From b535c6ca7b9e8c4bcf5637091ee5ad6d9c807c31 Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Sat, 30 Mar 2024 20:36:28 +0300 Subject: [PATCH 001/370] Remove jQuery class from the project page (#30183) - Switched from jQuery class functions to plain JavaScript `classList` - Tested the edit column modal functionality and it works as before Signed-off-by: Yarden Shoham <git@yardenshoham.com> --- web_src/js/features/repo-projects.js | 45 ++++++++++++++-------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/web_src/js/features/repo-projects.js b/web_src/js/features/repo-projects.js index d9ae85a8d2..80e945a0f2 100644 --- a/web_src/js/features/repo-projects.js +++ b/web_src/js/features/repo-projects.js @@ -94,47 +94,46 @@ async function initRepoProjectSortable() { } export function initRepoProject() { - if (!$('.repository.projects').length) { + if (!document.querySelector('.repository.projects')) { return; } const _promise = initRepoProjectSortable(); - $('.edit-project-column-modal').each(function () { - const $projectHeader = $(this).closest('.project-column-header'); - const $projectTitleLabel = $projectHeader.find('.project-column-title'); - const $projectTitleInput = $(this).find('.project-column-title-input'); - const $projectColorInput = $(this).find('#new_project_column_color'); - const $boardColumn = $(this).closest('.project-column'); + for (const modal of document.getElementsByClassName('edit-project-column-modal')) { + const projectHeader = modal.closest('.project-column-header'); + const projectTitleLabel = projectHeader?.querySelector('.project-column-title'); + const projectTitleInput = modal.querySelector('.project-column-title-input'); + const projectColorInput = modal.querySelector('#new_project_column_color'); + const boardColumn = modal.closest('.project-column'); + const bgColor = boardColumn?.style.backgroundColor; - const bgColor = $boardColumn[0].style.backgroundColor; if (bgColor) { - setLabelColor($projectHeader, rgbToHex(bgColor)); + setLabelColor(projectHeader, rgbToHex(bgColor)); } - $(this).find('.edit-project-column-button').on('click', async function (e) { + modal.querySelector('.edit-project-column-button')?.addEventListener('click', async function (e) { e.preventDefault(); - try { - await PUT($(this).data('url'), { + await PUT(this.getAttribute('data-url'), { data: { - title: $projectTitleInput.val(), - color: $projectColorInput.val(), + title: projectTitleInput?.value, + color: projectColorInput?.value, }, }); } catch (error) { console.error(error); } finally { - $projectTitleLabel.text($projectTitleInput.val()); - $projectTitleInput.closest('form').removeClass('dirty'); - if ($projectColorInput.val()) { - setLabelColor($projectHeader, $projectColorInput.val()); + projectTitleLabel.textContent = projectTitleInput?.value; + projectTitleInput.closest('form')?.classList.remove('dirty'); + if (projectColorInput?.value) { + setLabelColor(projectHeader, projectColorInput.value); } - $boardColumn[0].style = `background: ${$projectColorInput.val()} !important`; + boardColumn.style = `background: ${projectColorInput.value} !important`; $('.ui.modal').modal('hide'); } }); - }); + } $('.default-project-column-modal').each(function () { const $boardColumn = $(this).closest('.project-column'); @@ -187,9 +186,11 @@ export function initRepoProject() { function setLabelColor(label, color) { const {r, g, b} = tinycolor(color).toRgb(); if (useLightTextOnBackground(r, g, b)) { - label.removeClass('dark-label').addClass('light-label'); + label.classList.remove('dark-label'); + label.classList.add('light-label'); } else { - label.removeClass('light-label').addClass('dark-label'); + label.classList.remove('light-label'); + label.classList.add('dark-label'); } } From f32ce753f6518caa815d7b6bc44bc03806e8d049 Mon Sep 17 00:00:00 2001 From: Denys Konovalov <kontakt@denyskon.de> Date: Sat, 30 Mar 2024 19:11:50 +0100 Subject: [PATCH 002/370] Use Crowdin action for translation sync (#30054) Switch from the old self-built action to the official one. We get: - config managed inside the repo - automatic upload when source file changes - automatic invalidation if source string changes (tested) - automatic download of new translation files Tested both upload and download. --- .github/workflows/cron-translations.yml | 33 +++++++++---------------- crowdin.yml | 12 +++++++++ 2 files changed, 23 insertions(+), 22 deletions(-) create mode 100644 crowdin.yml diff --git a/.github/workflows/cron-translations.yml b/.github/workflows/cron-translations.yml index 390aae7c07..f1b51debf1 100644 --- a/.github/workflows/cron-translations.yml +++ b/.github/workflows/cron-translations.yml @@ -11,14 +11,19 @@ jobs: if: github.repository == 'go-gitea/gitea' steps: - uses: actions/checkout@v4 - - name: download from crowdin - uses: docker://jonasfranz/crowdin + - uses: crowdin/github-action@v1 + with: + upload_sources: true + upload_translations: false + download_sources: false + download_translations: true + push_translations: false + push_sources: false + create_pull_request: false + config: crowdin.yml env: + CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} CROWDIN_KEY: ${{ secrets.CROWDIN_KEY }} - PLUGIN_DOWNLOAD: true - PLUGIN_EXPORT_DIR: options/locale/ - PLUGIN_IGNORE_BRANCH: true - PLUGIN_PROJECT_IDENTIFIER: gitea - name: update locales run: ./build/update-locales.sh - name: push translations to repo @@ -31,19 +36,3 @@ jobs: commit_message: "[skip ci] Updated translations via Crowdin" remote: "git@github.com:go-gitea/gitea.git" ssh_key: ${{ secrets.DEPLOY_KEY }} - crowdin-push: - runs-on: ubuntu-latest - if: github.repository == 'go-gitea/gitea' - steps: - - uses: actions/checkout@v4 - - name: push translations to crowdin - uses: docker://jonasfranz/crowdin - env: - CROWDIN_KEY: ${{ secrets.CROWDIN_KEY }} - PLUGIN_UPLOAD: true - PLUGIN_EXPORT_DIR: options/locale/ - PLUGIN_IGNORE_BRANCH: true - PLUGIN_PROJECT_IDENTIFIER: gitea - PLUGIN_FILES: | - locale_en-US.ini: options/locale/locale_en-US.ini - PLUGIN_BRANCH: main diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 0000000000..35a38d768c --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,12 @@ +project_id_env: CROWDIN_PROJECT_ID +api_token_env: CROWDIN_KEY +base_path: "." +base_url: "https://api.crowdin.com" +preserve_hierarchy: true +files: + - source: "/options/locale/locale_en-US.ini" + translation: "/options/locale/locale_%locale%.ini" + type: "ini" + skip_untranslated_strings: true + export_only_approved: true + update_option: "update_as_unapproved" From bcf3be3a6c2794f7a3841f9d110b14be29327e1a Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Sat, 30 Mar 2024 18:47:50 +0000 Subject: [PATCH 003/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_cs-CZ.ini | 411 +++++++++++++++++++------------- options/locale/locale_de-DE.ini | 206 ++++++++++++---- options/locale/locale_el-GR.ini | 58 +---- options/locale/locale_es-ES.ini | 58 +---- options/locale/locale_fa-IR.ini | 43 +--- options/locale/locale_fi-FI.ini | 34 +-- options/locale/locale_fr-FR.ini | 61 ++--- options/locale/locale_hu-HU.ini | 32 +-- options/locale/locale_id-ID.ini | 27 +-- options/locale/locale_is-IS.ini | 29 +-- options/locale/locale_it-IT.ini | 45 +--- options/locale/locale_ja-JP.ini | 93 ++++---- options/locale/locale_ko-KR.ini | 31 +-- options/locale/locale_lv-LV.ini | 58 +---- options/locale/locale_nl-NL.ini | 45 +--- options/locale/locale_pl-PL.ini | 42 +--- options/locale/locale_pt-BR.ini | 116 +++++---- options/locale/locale_pt-PT.ini | 144 +++++++---- options/locale/locale_ru-RU.ini | 58 +---- options/locale/locale_si-LK.ini | 42 +--- options/locale/locale_sk-SK.ini | 35 +-- options/locale/locale_sv-SE.ini | 35 +-- options/locale/locale_tr-TR.ini | 62 ++--- options/locale/locale_uk-UA.ini | 43 +--- options/locale/locale_zh-CN.ini | 58 +---- options/locale/locale_zh-HK.ini | 17 +- options/locale/locale_zh-TW.ini | 54 +---- 27 files changed, 888 insertions(+), 1049 deletions(-) diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index 2a421b1172..4abf813725 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -25,6 +25,7 @@ enable_javascript=Tato stránka vyžaduje JavaScript. toc=Obsah licenses=Licence return_to_gitea=Vrátit se do Gitea +more_items=Více položek username=Uživatelské jméno email=E-mailová adresa @@ -75,7 +76,7 @@ collaborative=Spolupráce forks=Rozštěpení activities=Aktivity -pull_requests=Požadavky na natažení +pull_requests=Pull requesty issues=Úkoly milestones=Milníky @@ -113,6 +114,7 @@ loading=Načítá se… error=Chyba error404=Stránka, kterou se snažíte zobrazit, buď <strong>neexistuje</strong>, nebo <strong>nemáte oprávnění</strong> ji zobrazit. go_back=Zpět +invalid_data=Neplatná data: %v never=Nikdy unknown=Neznámý @@ -142,6 +144,43 @@ confirm_delete_selected=Potvrdit odstranění všech vybraných položek? name=Název value=Hodnota +filter=Filtr +filter.clear=Vymazat filtr +filter.is_archived=Archivováno +filter.not_archived=Nearchivované +filter.is_fork=Rozštěpený +filter.not_fork=Není rozštěpený +filter.is_mirror=Zrcadlen +filter.not_mirror=Není zrcadleno +filter.is_template=Šablona +filter.not_template=Není šablona +filter.public=Veřejná +filter.private=Soukromý + +no_results_found=Nebyly nalezeny žádné výsledky. + +[search] +search=Hledat... +type_tooltip=Druh vyhledávání +fuzzy=Fuzzy +fuzzy_tooltip=Zahrnout výsledky, které také úzce odpovídají hledanému výrazu +match=Shoda +match_tooltip=Zahrnout pouze výsledky, které odpovídají přesnému hledanému výrazu +repo_kind=Hledat repozitáře... +user_kind=Hledat uživatele... +org_kind=Hledat organizace... +team_kind=Hledat týmy... +code_kind=Hledat kód... +code_search_unavailable=Vyhledávání kódu není momentálně dostupné. Obraťte se na správce webu. +code_search_by_git_grep=Aktuální výsledky vyhledávání kódu jsou poskytovány pomocí „git grep“. Pokud správce webu povolí index repozitáře, mohou být výsledky lepší. +package_kind=Hledat balíčky... +project_kind=Hledat projekty... +branch_kind=Hledat větve... +commit_kind=Hledat commity... +runner_kind=Hledat runnery... +no_results=Nebyly nalezeny žádné odpovídající výsledky. +keyword_search_unavailable=Hledání podle klíčového slova není momentálně dostupné. Obraťte se na správce webu. + [aria] navbar=Navigační lišta footer=Patička @@ -247,6 +286,7 @@ email_title=Nastavení e-mailu smtp_addr=Server SMTP smtp_port=Port SMTP smtp_from=Odeslat e-mail jako +smtp_from_invalid=Adresa "Odeslat e-mail jako" je neplatná smtp_from_helper=E-mailová adresa, kterou bude Gitea používat. Zadejte běžnou e-mailovou adresu, nebo použijte formát "Jméno"<email@example.com>. mailer_user=Uživatelské jméno SMTP mailer_password=Heslo pro SMTP @@ -306,6 +346,7 @@ env_config_keys=Konfigurace prostředí env_config_keys_prompt=Následující proměnné prostředí budou také použity pro váš konfigurační soubor: [home] +nav_menu=Navigační menu uname_holder=Uživatelské jméno nebo e-mailová adresa password_holder=Heslo switch_dashboard_context=Přepnout kontext přehledu @@ -315,7 +356,6 @@ collaborative_repos=Společné repozitáře my_orgs=Mé organizace my_mirrors=Má zrcadla view_home=Zobrazit %s -search_repos=Nalézt repozitář… filter=Ostatní filtry filter_by_team_repositories=Filtrovat podle repozitářů týmu feed_of=Kanál z „%s“ @@ -336,20 +376,8 @@ issues.in_your_repos=Ve vašich repozitářích repos=Repozitáře users=Uživatelé organizations=Organizace -search=Vyhledat go_to=Přejít na code=Kód -search.type.tooltip=Druh vyhledávání -search.fuzzy=Fuzzy -search.fuzzy.tooltip=Zahrnout výsledky, které také úzce odpovídají hledanému výrazu -search.match=Shoda -search.match.tooltip=Zahrnout pouze výsledky, které odpovídají přesnému hledanému výrazu -code_search_unavailable=V současné době není vyhledávání kódu dostupné. Obraťte se na správce webu. -repo_no_results=Nebyly nalezeny žádné odpovídající repozitáře. -user_no_results=Nebyly nalezeni žádní odpovídající uživatelé. -org_no_results=Nebyly nalezeny žádné odpovídající organizace. -code_no_results=Nebyl nalezen žádný zdrojový kód odpovídající hledanému výrazu. -code_search_results=Výsledky hledání pro „%s“ code_last_indexed_at=Naposledy indexováno %s relevant_repositories_tooltip=Repozitáře, které jsou rozštěpení nebo nemají žádné téma, ikonu a žádný popis jsou skryty. relevant_repositories=Zobrazují se pouze relevantní repositáře, <a href="%s">zobrazit nefiltrované výsledky</a>. @@ -367,7 +395,7 @@ forgot_password_title=Zapomenuté heslo forgot_password=Zapomenuté heslo? sign_up_now=Potřebujete účet? Zaregistrujte se. sign_up_successful=Účet byl úspěšně vytvořen. Vítejte! -confirmation_mail_sent_prompt=Na adresu <b>%s</b> byl zaslán nový potvrzovací e-mail. Zkontrolujte prosím vaši doručenou poštu během následujících %s, abyste dokončili proces registrace. +confirmation_mail_sent_prompt_ex=Nový potvrzovací e-mail byl odeslán na <b>%s</b>. Zkontrolujte prosím svou doručenou poštu během následujících %s a dokončete proces registrace. Pokud je Vaše registrační e-mailová adresa nesprávná, můžete se znovu přihlásit a změnit ji. must_change_password=Aktualizujte své heslo allow_password_change=Vyžádat od uživatele změnu hesla (doporučeno) reset_password_mail_sent_prompt=Na adresu <b>%s</b> byl zaslán potvrzovací e-mail. Zkontrolujte prosím vaši doručenou poštu během následujících %s, abyste dokončili proces obnovení účtu. @@ -377,6 +405,7 @@ prohibit_login=Přihlášení zakázáno prohibit_login_desc=Vašemu účtu je zakázáno se přihlásit, kontaktujte prosím správce webu. resent_limit_prompt=Omlouváme se, ale před chvílí jste požádal o zaslání aktivačního e-mailu. Počkejte prosím 3 minuty a pak to zkuste znovu. has_unconfirmed_mail=Zdravím, %s, máte nepotvrzenou e-mailovou adresu (<b>%s</b>). Pokud jste nedostali e-mail pro potvrzení nebo potřebujete zaslat nový, klikněte prosím na tlačítku níže. +change_unconfirmed_mail_address=Pokud je Vaše registrační e-mailová adresa nesprávná, můžete ji zde změnit a znovu odeslat nový potvrzovací e-mail. resend_mail=Klikněte zde pro odeslání aktivačního e-mailu email_not_associate=Tato e-mailová adresa není spojena s žádným účtem. send_reset_mail=Zaslat e-mail pro obnovení účtu @@ -453,7 +482,7 @@ reset_password.text=Klikněte prosím na následující odkaz pro obnovení vaš register_success=Registrace byla úspěšná -issue_assigned.pull=@%[1]s vás přiřadil/a k požadavku na natažení %[2]s repozitáři %[3]s. +issue_assigned.pull=@%[1]s vás přiřadil/a k pull requestu %[2]s v repozitáři %[3]s. issue_assigned.issue=@%[1]s vás přiřadil/a k úkolu %[2]s repozitáři %[3]s. issue.x_mentioned_you=<b>@%s</b> vás zmínil/a: @@ -463,11 +492,11 @@ issue.action.push_n=<b>@%[1]s</b> nahrál/a %[3]d commity do %[2]s issue.action.close=<b>@%[1]s</b> uzavřel/a #%[2]d. issue.action.reopen=<b>@%[1]s</b> znovu otevřel/a #%[2]d. issue.action.merge=<b>@%[1]s</b> sloučil/a #%[2]d do %[3]s. -issue.action.approve=<b>@%[1]s</b> schválil/a tento požadavek na natažení. -issue.action.reject=<b>@%[1]s</b> požadoval/a změny v tomto požadavku na natažení. -issue.action.review=<b>@%[1]s</b> okomentoval/a tento požadavek na natažení. -issue.action.review_dismissed=<b>@%[1]s</b> odmítl/a poslední kontrolu z %[2]s pro tento požadavek na natažení. -issue.action.ready_for_review=<b>@%[1]s</b> označil/a tento požadavek na natažení jako připravený ke kontrole. +issue.action.approve=<b>@%[1]s</b> schválil/a tento pull request. +issue.action.reject=<b>@%[1]s</b> požadoval/a změny v tomto pull requestu. +issue.action.review=<b>@%[1]s</b> okomentoval/a tento pull request. +issue.action.review_dismissed=<b>@%[1]s</b> odmítl/a poslední kontrolu z %[2]s pro tento pull request. +issue.action.ready_for_review=<b>@%[1]s</b> označil/a tento pull request jako připravený ke kontrole. issue.action.new=<b>@%[1]s</b> vytvořil/a #%[2]d. issue.in_tree_path=V %s: @@ -557,6 +586,7 @@ team_name_been_taken=Název týmu je již použit. team_no_units_error=Povolit přístup alespoň do jedné sekce repozitáře. email_been_used=Tato e-mailová adresa je již používána. email_invalid=Emailová adresa je neplatná. +email_domain_is_not_allowed=Doména uživatelského e-mailu <b>%s</b> je v rozporu s EMAIL_DOMAIN_ALLOWLIST nebo EMAIL_DOMAIN_BLOCKLIST. Ujistěte se, že je Vaše operace očekávána. openid_been_used=OpenID addresa „%s“ je již použita. username_password_incorrect=Uživatelské jméno nebo heslo není správné. password_complexity=Heslo nesplňuje požadavky na složitost: @@ -568,6 +598,8 @@ enterred_invalid_repo_name=Zadaný název repozitáře není správný. enterred_invalid_org_name=Zadaný název organizace není správný. enterred_invalid_owner_name=Nové jméno vlastníka není správné. enterred_invalid_password=Zadané heslo není správné. +unset_password=Přihlášený uživatel nenastavil heslo. +unsupported_login_type=Typ přihlášení není podporován pro odstranění účtu. user_not_exist=Tento uživatel neexistuje. team_not_exist=Tento tým neexistuje. last_org_owner=Nemůžete odstranit posledního uživatele z týmu „vlastníci“. Musí existovat alespoň jeden vlastník pro organizaci. @@ -617,6 +649,30 @@ form.name_reserved=Uživatelské jméno „%s“ je rezervováno. form.name_pattern_not_allowed=Vzor „%s“ není povolen v uživatelském jméně. form.name_chars_not_allowed=Uživatelské jméno „%s“ obsahuje neplatné znaky. +block.block=Blokovat +block.block.user=Zablokovat Uživatele +block.block.org=Blokovat uživatele pro organizaci +block.block.failure=Nepodařilo se zablokovat uživatele: %s +block.unblock=Odblokovat +block.unblock.failure=Nepodařilo se odblokovat uživatele: %s +block.blocked=Zablokovali jste tohoto uživatele. +block.title=Zablokovat Uživatele +block.info=Blokování uživatele brání v interakci s repozitáři, jako je otevírání nebo komentování pull requestů nebo úkolů. Další informace o blokování uživatele. +block.info_1=Zablokování uživatele zabrání následujícím akcím na vašem účtu a repozirářích: +block.info_2=sledují váš účet +block.info_3=pošle vám oznámení pomocí @zmínění vašeho uživatelského jména +block.info_4=pozváním vás jako spolupracovníka do jejich repozitářů +block.info_5=oblíbení, rozštěpení nebo sledování repozitářů +block.info_6=otevření a komentování úkolů nebo pull requestů +block.info_7=reagovat na své komentáře v úkolech nebo pull requestů +block.user_to_block=Uživatel k blokování +block.note=Poznámka +block.note.title=Volitelná poznámka: +block.note.info=Poznámka není pro blokovaného uživatele viditelná. +block.note.edit=Upravit poznámku +block.list=Blokovaní uživatelé +block.list.none=Nemáte blokované žádné uživatele. + [settings] profile=Profil account=Účet @@ -761,7 +817,6 @@ gpg_invalid_token_signature=Zadaný GPG klíč, podpis a token se neshodují neb gpg_token_required=Musíte zadat podpis pro níže uvedený token gpg_token=Token gpg_token_help=Podpis můžete vygenerovat pomocí: -gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig gpg_token_signature=Zakódovaný podpis GPG key_signature_gpg_placeholder=Začíná s „-----BEGIN PGP SIGNATURE-----“ verify_gpg_key_success=GPG klíč „%s“ byl ověřen. @@ -833,6 +888,7 @@ select_permissions=Vyberte oprávnění permission_no_access=Bez přístupu permission_read=Přečtené permission_write=čtení i zápis +access_token_desc=Vybraná oprávnění tokenu omezují autorizaci pouze na odpovídající trasy <a %s>API</a>. Přečtěte si <a %s>dokumentaci</a> pro více informací. at_least_one_permission=Musíte vybrat alespoň jedno oprávnění pro vytvoření tokenu permissions_list=Oprávnění: @@ -953,8 +1009,9 @@ fork_visibility_helper=Viditelnost rozštěpeného repozitáře nemůže být zm fork_branch=Větev, která má být klonována pro fork all_branches=Všechny větve fork_no_valid_owners=Tento repozitář nemůže být rozštěpen, protože neexistují žádní platní vlastníci. +fork.blocked_user=Nelze rozštěpit repozitář, protože jste blokováni majitelem repozitáře. use_template=Použít tuto šablonu -clone_in_vsc=Klonovat ve VS Code +open_with_editor=Otevřít pomocí %s download_zip=Stáhnout ZIP download_tar=Stáhnout TAR.GZ download_bundle=Stáhnout BUNDLE @@ -984,11 +1041,12 @@ trust_model_helper_default=Výchozí: Použít výchozí model důvěry pro tuto create_repo=Vytvořit repozitář default_branch=Výchozí větev default_branch_label=výchozí -default_branch_helper=Výchozí větev je základní větev pro požadavky na natažení a commity kódu. +default_branch_helper=Výchozí větev je základní větev pro pull requesty a commity kódu. mirror_prune=Vyčistit mirror_prune_desc=Odstranit zastaralé reference na vzdálené sledování mirror_interval=Interval zrcadlení (platné časové jednotky jsou „h“, „m“ a „s“). 0 zakáže periodickou synchronizaci. (Minimální interval: %s) mirror_interval_invalid=Interval zrcadlení není platný. +mirror_sync=synchronizováno mirror_sync_on_commit=Synchronizovat při nahrávání revizí mirror_address=Klonovat z URL mirror_address_desc=Zadejte požadované přístupové údaje do sekce Ověření. @@ -1019,6 +1077,7 @@ delete_preexisting=Odstranit již existující soubory delete_preexisting_content=Odstranit soubory v %s delete_preexisting_success=Smazány nepřijaté soubory v %s blame_prior=Zobrazit blame před touto změnou +blame.ignore_revs=Ignorování revizí v <a href="%s">.git-blame-ignorerevs</a>. Klikněte zde <a href="%s">pro obejití</a> a zobrazení normálního pohledu blame. blame.ignore_revs.failed=Nepodařilo se ignorovat revize v <a href="%s">.git-blame-ignore-revs</a>. author_search_tooltip=Zobrazí maximálně 30 uživatelů @@ -1051,10 +1110,10 @@ template.issue_labels=Štítky úkolů template.one_item=Musíte vybrat alespoň jednu položku šablony template.invalid=Musíte vybrat repositář šablony -archive.title=Tento repozitář je archivovaný. Můžete prohlížet soubory, klonovat, ale nemůžete nahrávat a vytvářet nové úkoly nebo požadavky na natažení. -archive.title_date=Tento repositář byl archivován %s. Můžete zobrazit soubory a klonovat je, ale nemůžete nahrávat ani otevírat problémy nebo požadavky na natažení. +archive.title=Tento repozitář je archivovaný. Můžete prohlížet soubory, klonovat, ale nemůžete nahrávat a vytvářet nové úkoly nebo pull requesty. +archive.title_date=Tento repositář byl archivován %s. Můžete zobrazit soubory a klonovat je, ale nemůžete nahrávat ani otevírat problémy nebo pull requesty. archive.issue.nocomment=Tento repozitář je archivovaný. Nemůžete komentovat úkoly. -archive.pull.nocomment=Tento repozitář je archivovaný. Nemůžete komentovat požadavky na natažení. +archive.pull.nocomment=Tento repozitář je archivovaný. Nemůžete komentovat pull requesty. form.reach_limit_of_creation_1=Již jste dosáhli svůj limit %d repozitář. form.reach_limit_of_creation_n=Již jste dosáhli svůj limit %d repozitářů. @@ -1075,7 +1134,7 @@ migrate_items_wiki=Wiki migrate_items_milestones=Milníky migrate_items_labels=Štítky migrate_items_issues=Úkoly -migrate_items_pullrequests=Požadavky na natažení +migrate_items_pullrequests=Pull requesty migrate_items_merge_requests=Sloučit požadavky migrate_items_releases=Vydání migrate_repo=Migrovat repozitář @@ -1110,7 +1169,7 @@ migrate.migrating_milestones=Migrování milnků migrate.migrating_labels=Migrování štítků migrate.migrating_releases=Migrování vydání migrate.migrating_issues=Migrování úkolů -migrate.migrating_pulls=Migrování požadavků na natažení +migrate.migrating_pulls=Migrování pull requestů migrate.cancel_migrating_title=Zrušit migraci migrate.cancel_migrating_confirm=Chcete zrušit tuto migraci? @@ -1126,6 +1185,7 @@ watch=Sledovat unstar=Odoblíbit star=Oblíbit fork=Rozštěpit +action.blocked_user=Nelze provést akci, protože jste zablokování vlastníkem repozitáře. download_archive=Stáhnout repozitář more_operations=Další operace @@ -1148,7 +1208,7 @@ find_tag=Najít značku branches=Větve tags=Značky issues=Úkoly -pulls=Požadavky na natažení +pulls=Pull requesty project_board=Projekty packages=Balíčky actions=Akce @@ -1193,7 +1253,7 @@ vendored=Vendorováno generated=Generováno commit_graph=Graf commitů commit_graph.select=Vybrat větve -commit_graph.hide_pr_refs=Skrýt požadavky na natažení +commit_graph.hide_pr_refs=Skrýt pull requesty commit_graph.monochrome=Černobílé commit_graph.color=Barva commit.contained_in=Tento commit je obsažen v: @@ -1237,7 +1297,7 @@ editor.new_patch=Nová záplata editor.commit_message_desc=Přidat volitelný rozšířený popis… editor.signoff_desc=Přidat Signed-off-by podpis přispěvatele na konec zprávy o commitu. editor.commit_directly_to_this_branch=Odevzdat přímo do větve <strong class="branch-name">%s</strong>. -editor.create_new_branch=Vytvořit <strong>novou větev</strong> pro tento commit a spustit požadavek na natažení. +editor.create_new_branch=Vytvořit <strong>novou větev</strong> pro tento commit a začít pull request. editor.create_new_branch_np=Vytvořte <strong>novou větev</strong> z tohoto commitu. editor.propose_file_change=Navrhnout změnu souboru editor.new_branch_name=Pojmenujte novou větev pro tento commit @@ -1254,6 +1314,7 @@ editor.file_editing_no_longer_exists=Upravovaný soubor „%s“ již není sou editor.file_deleting_no_longer_exists=Odstraňovaný soubor „%s“ již není součástí tohoto repozitáře. editor.file_changed_while_editing=Obsah souboru byl změněn od doby, kdy jste začaly s úpravou. <a target="_blank" rel="noopener noreferrer" href="%s">Klikněte zde</a>, abyste je zobrazili, nebo <strong>potvrďte změny ještě jednou</strong> pro jejich přepsání. editor.file_already_exists=Soubor „%s“ již existuje v tomto repozitáři. +editor.commit_id_not_matching=ID commitu se neshoduje s ID, když jsi začal/a s úpravami. Odevzdat do záplatové větve a poté sloučit. editor.commit_empty_file_header=Odevzdat prázdný soubor editor.commit_empty_file_text=Soubor, který se chystáte odevzdat, je prázdný. Pokračovat? editor.no_changes_to_show=Žádné změny k zobrazení. @@ -1277,9 +1338,8 @@ commits.desc=Procházet historii změn zdrojového kódu. commits.commits=Commity commits.no_commits=Žádné společné commity. „%s“ a „%s“ mají zcela odlišnou historii. commits.nothing_to_compare=Tyto větve jsou stejné. -commits.search=Hledání commitů… commits.search.tooltip=Můžete předřadit klíčová slova s „author:“, „committer:“, „after:“ nebo „before:“, např. „revert author:Alice before:2019-01-03“. -commits.find=Vyhledat +commits.search_branch=Tato větev commits.search_all=Všechny větve commits.author=Autor commits.message=Zpráva @@ -1330,7 +1390,6 @@ projects.type.basic_kanban=Základní Kanban projects.type.bug_triage=Třídění chyb projects.template.desc=Šablona projektu projects.template.desc_helper=Vyberte šablonu projektu pro začátek -projects.type.uncategorized=Nezařazené projects.column.edit=Upravit sloupec projects.column.edit_title=Název projects.column.new_title=Název @@ -1338,10 +1397,7 @@ projects.column.new_submit=Vytvořit sloupec projects.column.new=Nový sloupec projects.column.set_default=Nastavit jako výchozí projects.column.set_default_desc=Nastavit tento sloupec jako výchozí pro nekategorizované úkoly a požadavky na natažení -projects.column.unset_default=Zrušit nastavení jako výchozí -projects.column.unset_default_desc=Zrušit nastavení tohoto sloupce jako výchozí projects.column.delete=Smazat sloupec -projects.column.deletion_desc=Smazání projektového sloupce přesune všechny související problémy do kategorie „Nezařazené“. Pokračovat? projects.column.color=Barva projects.open=Otevřít projects.close=Zavřít @@ -1376,6 +1432,8 @@ issues.new.assignees=Zpracovatelé issues.new.clear_assignees=Smazat zpracovatele issues.new.no_assignees=Bez zpracovatelů issues.new.no_reviewers=Žádní posuzovatelé +issues.new.blocked_user=Nemůžete vytvořit úkol, protože jste zablokováni zadavatelem příspěvku nebo vlastníkem repozitáře. +issues.edit.blocked_user=Nemůžete upravovat obsah, protože jste zablokováni zadavatelem příspěvku nebo vlastníkem repozitáře. issues.choose.get_started=Začínáme issues.choose.open_external_link=Otevřít issues.choose.blank=Výchozí @@ -1453,7 +1511,6 @@ issues.filter_sort.moststars=Nejvíce hvězdiček issues.filter_sort.feweststars=Nejméně hvězdiček issues.filter_sort.mostforks=Nejvíce rozštěpení issues.filter_sort.fewestforks=Nejméně rozštěpení -issues.keyword_search_unavailable=Hledání podle klíčového slova není momentálně dostupné. Obraťte se na správce webu. issues.action_open=Otevřít issues.action_close=Zavřít issues.action_label=Štítek @@ -1491,13 +1548,14 @@ issues.close_comment_issue=Okomentovat a zavřít issues.reopen_issue=Znovuotevřít issues.reopen_comment_issue=Okomentovat a znovuotevřít issues.create_comment=Okomentovat +issues.comment.blocked_user=Nemůžete vytvořit nebo upravovat komentář, protože jste zablokováni zadavatelem příspěvku nebo vlastníkem repozitáře. issues.closed_at=`uzavřel/a tento úkol <a id="%[1]s" href="#%[1]s">%[2]s</a>` issues.reopened_at=`znovuotevřel/a tento úkol <a id="%[1]s" href="#%[1]s">%[2]s</a>` issues.commit_ref_at=`odkázal na tento úkol z commitu <a id="%[1]s" href="#%[1]s">%[2]s</a>` issues.ref_issue_from=`<a href="%[3]s">odkazoval/a na tento úkol %[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>` -issues.ref_pull_from=`<a href="%[3]s">odkazoval/a na tento požadavek na natažení %[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>` -issues.ref_closing_from=`<a href="%[3]s">odkazoval/a na požadavek na natažení %[4]s, který uzavře tento úkol</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>` -issues.ref_reopening_from=`<a href="%[3]s">odkazoval/a na požadavek na natažení %[4]s, který znovu otevře tento úkol</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>` +issues.ref_pull_from=`<a href="%[3]s">odkazoval/a na tento pull request %[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>` +issues.ref_closing_from=`<a href="%[3]s">odkazoval/a na pull request %[4]s, který uzavře tento úkol</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>` +issues.ref_reopening_from=`<a href="%[3]s">odkazoval/a na pull request %[4]s, který znovu otevře tento úkol</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>` issues.ref_closed_from=`<a href="%[3]s">uzavřel/a tento úkol %[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>` issues.ref_reopened_from=`<a href="%[3]s">znovu otevřel/a tento úkol %[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>` issues.ref_from=`z %[1]s` @@ -1509,6 +1567,7 @@ issues.role.member=Člen issues.role.member_helper=Tento uživatel je členem organizace vlastnící tento repositář. issues.role.collaborator=Spolupracovník issues.role.collaborator_helper=Tento uživatel byl pozván ke spolupráci v repozitáři. +issues.role.first_time_contributor=Přispěvatel, který přispívá poprvé issues.role.first_time_contributor_helper=Toto je první příspěvek tohoto uživatele do repozitáře. issues.role.contributor=Přispěvatel issues.role.contributor_helper=Tento uživatel již dříve přispíval do repozitáře. @@ -1530,7 +1589,7 @@ issues.label_archive=Archivovat štítek issues.label_archived_filter=Zobrazit archivované popisky issues.label_archive_tooltip=Archivované štítky jsou ve výchozím nastavení vyloučeny z návrhů při hledání podle popisku. issues.label_exclusive_desc=Pojmenujte štítek <code>rozsah/položka</code>, aby se stal vzájemně exkluzivním s jinými štítky <code>rozsah/</code>. -issues.label_exclusive_warning=Jakékoliv protichůdné rozsahy štítků budou odstraněny při úpravě štítků u úkolů nebo u požadavku na natažení. +issues.label_exclusive_warning=Jakékoliv protichůdné rozsahy štítků budou odstraněny při úpravě štítků u úkolů nebo u pull requestů. issues.label_count=%d štítků issues.label_open_issues=%d otevřených úkolů issues.label_edit=Upravit @@ -1626,27 +1685,27 @@ issues.dependency.remove=Odstranit issues.dependency.remove_info=Odstranit tuto závislost issues.dependency.added_dependency=`přidal/a novou závislost %s` issues.dependency.removed_dependency=`odstranil/a závislost %s` -issues.dependency.pr_closing_blockedby=Uzavření tohoto požadavku na natažení je blokováno následujícími úkoly +issues.dependency.pr_closing_blockedby=Uzavření tohoto pull requestu je blokováno následujícími úkoly issues.dependency.issue_closing_blockedby=Uzavření tohoto úkolu je blokováno následujícími úkoly issues.dependency.issue_close_blocks=Tento úkol blokuje uzavření následujících úkolů -issues.dependency.pr_close_blocks=Tento požadavek na natažení blokuje uzavření následujících úkolů +issues.dependency.pr_close_blocks=Tento pull request blokuje uzavření následujících úkolů issues.dependency.issue_close_blocked=Musíte zavřít všechny úkoly, které blokují tento úkol, aby jej bylo možné zavřít. issues.dependency.issue_batch_close_blocked=Nelze uzavřít úkoly, které jste vybrali, protože úkol #%d má stále otevřené závislosti -issues.dependency.pr_close_blocked=Musíte zavřít všechny úkoly, které blokují tento požadavek na natažení, aby jej bylo možné sloučit. +issues.dependency.pr_close_blocked=Musíte zavřít všechny úkoly, které blokují tento pull request, aby jej bylo možné sloučit. issues.dependency.blocks_short=Blokuje issues.dependency.blocked_by_short=Závisí na issues.dependency.remove_header=Odstranit závislost issues.dependency.issue_remove_text=Tímto krokem odeberete závislost z úkolu. Pokračovat? -issues.dependency.pr_remove_text=Tímto krokem odeberete závislost z požadavku na natažení. Pokračovat? -issues.dependency.setting=Povolit závislosti pro úkoly a požadavky na natažení +issues.dependency.pr_remove_text=Tímto krokem odeberete závislost z pull requestu. Pokračovat? +issues.dependency.setting=Povolit závislosti pro úkoly a pull requesty issues.dependency.add_error_same_issue=Úkol nemůže záviset sám na sobě. issues.dependency.add_error_dep_issue_not_exist=Související úkol neexistuje. issues.dependency.add_error_dep_not_exist=Závislost neexistuje. issues.dependency.add_error_dep_exists=Závislost již existuje. issues.dependency.add_error_cannot_create_circular=Nemůžete vytvořit závislost dvou úkolů, které se vzájemně blokují. issues.dependency.add_error_dep_not_same_repo=Oba úkoly musí být ve stejném repozitáři. -issues.review.self.approval=Nemůžete schválit svůj požadavek na natažení. -issues.review.self.rejection=Nemůžete požadovat změny ve svém vlastním požadavku na natažení. +issues.review.self.approval=Nemůžete schválit svůj pull request. +issues.review.self.rejection=Nemůžete požadovat změny ve svém vlastním pull requestu. issues.review.approve=schválil tyto změny %s issues.review.comment=posoudil %s issues.review.dismissed=zamítl/a posouzení od %s %s @@ -1686,10 +1745,11 @@ issues.reference_link=Reference: %s compare.compare_base=základní compare.compare_head=porovnat -pulls.desc=Povolit požadavky na natažení a posuzování kódu. -pulls.new=Nový požadavek na natažení -pulls.view=Zobrazit požadavek na natažení -pulls.compare_changes=Nový požadavek na natažení +pulls.desc=Povolit pull requesty a posuzování kódu. +pulls.new=Nový pull request +pulls.new.blocked_user=Nemůžete vytvořit pull request, protože jste zablokování vlastníkem repozitáře. +pulls.view=Zobrazit pull request +pulls.compare_changes=Nový pull request pulls.allow_edits_from_maintainers=Povolit úpravy od správců pulls.allow_edits_from_maintainers_desc=Uživatelé s přístupem k zápisu do základní větve mohou také nahrávat do této větve pulls.allow_edits_from_maintainers_err=Aktualizace se nezdařila @@ -1704,7 +1764,6 @@ pulls.compare_compare=natáhnout z pulls.switch_comparison_type=Přepnout typ porovnání pulls.switch_head_and_base=Prohodit hlavní a základní větev pulls.filter_branch=Filtrovat větev -pulls.no_results=Nebyly nalezeny žádné výsledky. pulls.show_all_commits=Zobrazit všechny commity pulls.show_changes_since_your_last_review=Zobrazit změny od vašeho posledního posouzení pulls.showing_only_single_commit=Zobrazuji pouze změny commitu %[1]s @@ -1712,46 +1771,46 @@ pulls.showing_specified_commit_range=Zobrazují se pouze změny mezi %[1]s..%[2] pulls.select_commit_hold_shift_for_range=Vyberte commit. Podržte klávesu shift + klepněte pro výběr rozsahu pulls.review_only_possible_for_full_diff=Posouzení je možné pouze při zobrazení plného rozlišení pulls.filter_changes_by_commit=Filtrovat podle commitu -pulls.nothing_to_compare=Tyto větve jsou stejné. Není potřeba vytvářet požadavek na natažení. +pulls.nothing_to_compare=Tyto větve jsou stejné. Není potřeba vytvářet pull request. pulls.nothing_to_compare_have_tag=Vybraná větev/značka je stejná. -pulls.nothing_to_compare_and_allow_empty_pr=Tyto větve jsou stejné. Tento požadavek na natažení bude prázdný. -pulls.has_pull_request=`Požadavek na natažení mezi těmito větvemi již existuje: <a href="%[1]s">%[2]s#%[3]d</a>` -pulls.create=Vytvořit požadavek na natažení +pulls.nothing_to_compare_and_allow_empty_pr=Tyto větve jsou stejné. Tento pull request bude prázdný. +pulls.has_pull_request=`Pull request mezi těmito větvemi již existuje: <a href="%[1]s">%[2]s#%[3]d</a>` +pulls.create=Vytvořit pull request pulls.title_desc=chce sloučit %[1]d commity z větve <code>%[2]s</code> do <code id="branch_target">%[3]s</code> pulls.merged_title_desc=sloučil %[1]d commity z větve <code>%[2]s</code> do větve <code>%[3]s</code> před %[4]s pulls.change_target_branch_at=`změnil/a cílovou větev z <b>%s</b> na <b>%s</b> %s` pulls.tab_conversation=Konverzace pulls.tab_commits=Commity pulls.tab_files=Změněné soubory -pulls.reopen_to_merge=Prosíme, otevřete znovu tento požadavek na natažení, aby se provedlo sloučení. -pulls.cant_reopen_deleted_branch=Tento požadavek na natažení nemůže být znovu otevřen protože větev byla smazána. +pulls.reopen_to_merge=Prosíme, otevřete znovu tento pull request, aby se provedlo sloučení. +pulls.cant_reopen_deleted_branch=Tento pull request nemůže být znovu otevřen protože větev byla smazána. pulls.merged=Sloučený -pulls.merged_success=Požadavek na natažení byl úspěšně sloučen a uzavřen -pulls.closed=Požadavek na natažení uzavřen +pulls.merged_success=Pull request byl úspěšně sloučen a uzavřen +pulls.closed=Pull request uzavřen pulls.manually_merged=Sloučeno ručně pulls.merged_info_text=Větev %s může být nyní odstraněna. -pulls.is_closed=Požadavek na natažení byl uzavřen. -pulls.title_wip_desc=`<a href="#">Začněte název s <strong>%s</strong></a> a zamezíte tak nechtěnému sloučení požadavku na natažení.` -pulls.cannot_merge_work_in_progress=Tento požadavek na natažení je označen jako probíhající práce. +pulls.is_closed=Pull request byl uzavřen. +pulls.title_wip_desc=`<a href="#">Začněte název s <strong>%s</strong></a> a zamezíte tak nechtěnému sloučení pull requestu.` +pulls.cannot_merge_work_in_progress=Tento pull request je označen jako probíhající práce. pulls.still_in_progress=Stále probíhá? pulls.add_prefix=Přidat prefix <strong>%s</strong> pulls.remove_prefix=Odstranit prefix <strong>%s</strong> -pulls.data_broken=Tento požadavek na natažení je rozbitý kvůli chybějícím informacím o rozštěpení. -pulls.files_conflicted=Tento požadavek na natažení obsahuje změny, které kolidují s cílovou větví. +pulls.data_broken=Tento pull request je rozbitý kvůli chybějícím informacím o rozštěpení. +pulls.files_conflicted=Tento pull request obsahuje změny, které kolidují s cílovou větví. pulls.is_checking=Právě probíhá kontrola konfliktů při sloučení. Zkuste to za chvíli. pulls.is_ancestor=Tato větev je již součástí cílové větve. Není co sloučit. pulls.is_empty=Změny na této větvi jsou již na cílové větvi. Toto bude prázdný commit. pulls.required_status_check_failed=Některé požadované kontroly nebyly úspěšné. pulls.required_status_check_missing=Některé požadované kontroly chybí. -pulls.required_status_check_administrator=Jako administrátor stále můžete sloučit tento požadavek na natažení. -pulls.blocked_by_approvals=Tento požadavek na natažení ještě nemá dostatek schválení. Uděleno %d z %d schválení. -pulls.blocked_by_rejection=Tento požadavek na natažení obsahuje změny požadované oficiálním posuzovatelem. -pulls.blocked_by_official_review_requests=Tento požadavek na natažení obsahuje oficiální žádosti o posouzení. -pulls.blocked_by_outdated_branch=Tento požadavek na natažení je zablokován, protože je zastaralý. -pulls.blocked_by_changed_protected_files_1=Tento požadavek na natažení je zablokován, protože mění chráněný soubor: -pulls.blocked_by_changed_protected_files_n=Tento požadavek na natažení je zablokován, protože mění chráněné soubory: -pulls.can_auto_merge_desc=Tento požadavek na natažení může být automaticky sloučen. -pulls.cannot_auto_merge_desc=Tento požadavek na natažení nemůže být automaticky sloučen, neboť se v něm nachází konflikty. +pulls.required_status_check_administrator=Jako administrátor stále můžete sloučit tento pull request. +pulls.blocked_by_approvals=Tento pull request ještě nemá dostatek schválení. Uděleno %d z %d schválení. +pulls.blocked_by_rejection=Tento pull request obsahuje změny požadované oficiálním posuzovatelem. +pulls.blocked_by_official_review_requests=Tento pull request obsahuje oficiální žádosti o posouzení. +pulls.blocked_by_outdated_branch=Tento pull request je zablokován, protože je zastaralý. +pulls.blocked_by_changed_protected_files_1=Tento pull request je zablokován, protože mění chráněný soubor: +pulls.blocked_by_changed_protected_files_n=Tento pull request je zablokován, protože mění chráněné soubory: +pulls.can_auto_merge_desc=Tento pull request může být automaticky sloučen. +pulls.cannot_auto_merge_desc=Tento pull request nemůže být automaticky sloučen, neboť se v něm nachází konflikty. pulls.cannot_auto_merge_helper=Pro vyřešení konfliktů proveďte ruční sloučení. pulls.num_conflicting_files_1=%d konfliktní soubor pulls.num_conflicting_files_n=%d konfliktních souborů @@ -1763,20 +1822,21 @@ pulls.waiting_count_1=%d čekající posouzení pulls.waiting_count_n=%d čekající posouzení pulls.wrong_commit_id=ID commitu musí být ID commitu v cílové větvi -pulls.no_merge_desc=Tento požadavek na natažení nemůže být sloučen, protože všechny možnosti repozitáře na sloučení jsou zakázány. -pulls.no_merge_helper=Povolte možnosti sloučení v nastavení repozitáře nebo proveďte sloučení požadavku na natažení ručně. -pulls.no_merge_wip=Požadavek na natažení nemůže být sloučen protože je označen jako nedokončený. -pulls.no_merge_not_ready=Tento požadavek na natažení není připraven na sloučení, zkontrolujte stav posouzení a kontrolu stavu. -pulls.no_merge_access=Nemáte oprávnění sloučit tento požadavek na natažení. +pulls.no_merge_desc=Tento pull request nemůže být sloučen, protože všechny možnosti repozitáře na sloučení jsou zakázány. +pulls.no_merge_helper=Povolte možnosti sloučení v nastavení repozitáře nebo proveďte sloučení pull requestu ručně. +pulls.no_merge_wip=Pull request nemůže být sloučen protože je označen jako nedokončený. +pulls.no_merge_not_ready=Tento pull request není připraven na sloučení, zkontrolujte stav posouzení a kontrolu stavu. +pulls.no_merge_access=Nemáte oprávnění sloučit tento pull request. pulls.merge_pull_request=Vytvořit slučovací commit pulls.rebase_merge_pull_request=Rebase pak fast-forward pulls.rebase_merge_commit_pull_request=Rebase a poté vytvořit slučovací commit pulls.squash_merge_pull_request=Vytvořit squash commit +pulls.fast_forward_only_merge_pull_request=Pouze fast-forward pulls.merge_manually=Sloučeno ručně pulls.merge_commit_id=ID slučovacího commitu pulls.require_signed_wont_sign=Větev vyžaduje podepsané commity, ale toto sloučení nebude podepsáno -pulls.invalid_merge_option=Nemůžete použít tuto možnost sloučení pro tento požadavek na natažení. +pulls.invalid_merge_option=Nemůžete použít tuto možnost sloučení pro tento pull request. pulls.merge_conflict=Sloučení selhalo: Došlo ke konfliktu při sloučení. Tip: Zkuste jinou strategii pulls.merge_conflict_summary=Chybové hlášení pulls.rebase_conflict=Sloučení selhalo: Došlo ke konfliktu při rebase commitu: %[1]s. Tip: Zkuste jinou strategii @@ -1784,11 +1844,11 @@ pulls.rebase_conflict_summary=Chybové hlášení pulls.unrelated_histories=Sloučení selhalo: Hlavní a základní revize nesdílí společnou historii. Tip: Zkuste jinou strategii pulls.merge_out_of_date=Sloučení selhalo: Základ byl aktualizován při generování sloučení. Tip: Zkuste to znovu. pulls.head_out_of_date=Sloučení selhalo: Hlavní revize byla aktualizován při generování sloučení. Tip: Zkuste to znovu. -pulls.has_merged=Chyba: Požadavek na natažení byl sloučen, nelze znovu sloučit nebo změnit cílovou větev. +pulls.has_merged=Chyba: Pull request byl sloučen, nelze znovu sloučit nebo změnit cílovou větev. pulls.push_rejected=Sloučení selhalo: Nahrání bylo zamítnuto. Zkontrolujte háčky Gitu pro tento repozitář. pulls.push_rejected_summary=Úplná zpráva o odmítnutí pulls.push_rejected_no_message=Sloučení se nezdařilo: Nahrání bylo odmítnuto, ale nebyla nalezena žádná vzdálená zpráva.<br>Zkontrolujte háčky gitu pro tento repozitář -pulls.open_unmerged_pull_exists=`Nemůžete provést operaci znovuotevření protože je tu čekající požadavek na natažení (#%d) s identickými vlastnostmi.` +pulls.open_unmerged_pull_exists=`Nemůžete provést operaci znovuotevření protože je tu čekající pull request (#%d) s identickými vlastnostmi.` pulls.status_checking=Některé kontroly jsou nedořešeny pulls.status_checks_success=Všechny kontroly byly úspěšné pulls.status_checks_warning=Některé kontroly nahlásily varování @@ -1803,30 +1863,32 @@ pulls.update_branch_rebase=Aktualizovat větev pomocí rebase pulls.update_branch_success=Aktualizace větve byla úspěšná pulls.update_not_allowed=Nemáte oprávnění aktualizovat větev pulls.outdated_with_base_branch=Tato větev je zastaralá oproti základní větvi -pulls.close=Zavřít požadavek na natažení -pulls.closed_at=`uzavřel/a tento požadavek na natažení <a id="%[1]s" href="#%[1]s">%[2]s</a>` -pulls.reopened_at=`znovuotevřel/a tento požadavek na natažení <a id="%[1]s" href="#%[1]s">%[2]s</a>` +pulls.close=Zavřít pull request +pulls.closed_at=`uzavřel/a tento pull request <a id="%[1]s" href="#%[1]s">%[2]s</a>` +pulls.reopened_at=`znovuotevřel/a tento pull request <a id="%[1]s" href="#%[1]s">%[2]s</a>` pulls.cmd_instruction_hint=`Zobrazit <a class="show-instruction">instrukce příkazové řádky</a>.` pulls.cmd_instruction_checkout_desc=Z vašeho repositáře projektu se podívejte na novou větev a vyzkoušejte změny. pulls.cmd_instruction_merge_title=Sloučit pulls.cmd_instruction_merge_desc=Slučte změny a aktualizujte je na Gitea. pulls.clear_merge_message=Vymazat zprávu o sloučení +pulls.clear_merge_message_hint=Vymazání zprávy o sloučení odstraní pouze obsah zprávy a ponechá generované přídavky gitu jako "Co-AuthoreBy …". pulls.auto_merge_button_when_succeed=(Když kontroly uspějí) pulls.auto_merge_when_succeed=Automaticky sloučit, když všechny kontroly uspějí -pulls.auto_merge_newly_scheduled=Požadavek na natažení byl naplánován na sloučení, jakmile všechny kontroly uspějí. -pulls.auto_merge_has_pending_schedule=%[1]s naplánoval/a tento požadavek na natažení pro automatické sloučení, když všechny kontroly uspějí v %[2]s. +pulls.auto_merge_newly_scheduled=Pull request byl naplánován na sloučení, jakmile všechny kontroly uspějí. +pulls.auto_merge_has_pending_schedule=%[1]s naplánoval/a tento pull request pro automatické sloučení, když všechny kontroly uspějí v %[2]s. pulls.auto_merge_cancel_schedule=Zrušit automatické sloučení -pulls.auto_merge_not_scheduled=Tento požadavek na natažení není naplánován na automatické sloučení. -pulls.auto_merge_canceled_schedule=Automatické sloučení bylo zrušeno pro tento požadavek na natažení. +pulls.auto_merge_not_scheduled=Tento pull request není naplánován na automatické sloučení. +pulls.auto_merge_canceled_schedule=Automatické sloučení bylo zrušeno pro tento pull request. -pulls.auto_merge_newly_scheduled_comment=`požadavek na automatické sloučení tohoto požadavku na natažení je naplánován, když všechny kontroly uspějí %[1]s` -pulls.auto_merge_canceled_schedule_comment=`zrušil/a automatické sloučení tohoto požadavku na natažení, když všechny kontroly uspějí %[1]s` +pulls.auto_merge_newly_scheduled_comment=`požadavek na automatické sloučení tohoto pull requestu je naplánován, když všechny kontroly uspějí %[1]s` +pulls.auto_merge_canceled_schedule_comment=`zrušil/a automatické sloučení tohoto pull requestu, když všechny kontroly uspějí %[1]s` -pulls.delete.title=Odstranit tento požadavek na natažení? -pulls.delete.text=Opravdu chcete tento požadavek na natažení smazat? (Tím se trvale odstraní veškerý obsah. Pokud jej hodláte archivovat, zvažte raději jeho uzavření.) +pulls.delete.title=Odstranit tento pull request? +pulls.delete.text=Opravdu chcete tento pull request smazat? (Tím se trvale odstraní veškerý obsah. Pokud jej hodláte archivovat, zvažte raději jeho uzavření.) +pulls.recently_pushed_new_branches=Nahráli jste větev <strong>%[1]s</strong> %[2]s pull.deleted_branch=(odstraněno):%s @@ -1871,7 +1933,7 @@ signing.wont_sign.parentsigned=Commit nebude podepsán, protože nadřazený com signing.wont_sign.basesigned=Sloučení nebude podepsáno, protože základní commit není podepsaný. signing.wont_sign.headsigned=Sloučení nebude podepsáno, protože hlavní revize není podepsána. signing.wont_sign.commitssigned=Sloučení nebude podepsáno, protože všechny přidružené revize nejsou podepsány. -signing.wont_sign.approved=Sloučení nebude podepsáno, protože požadavek na natažení není schválen. +signing.wont_sign.approved=Sloučení nebude podepsáno, protože pull request není schválen. signing.wont_sign.not_signed_in=Nejste přihlášeni. ext_wiki=Přístup k externí Wiki @@ -1905,6 +1967,9 @@ wiki.page_name_desc=Zadejte název této Wiki stránky. Některé speciální n wiki.original_git_entry_tooltip=Zobrazit originální Git soubor namísto použití přátelského odkazu. activity=Aktivita +activity.navbar.code_frequency=Frekvence kódu +activity.navbar.contributors=Přispěvatelé +activity.navbar.recent_commits=Nedávné commity activity.period.filter_label=Období: activity.period.daily=1 den activity.period.halfweekly=3 dny @@ -1914,16 +1979,16 @@ activity.period.quarterly=3 měsíce activity.period.semiyearly=6 měsíců activity.period.yearly=1 rok activity.overview=Přehled -activity.active_prs_count_1=<strong>%d</strong> aktivní požadavek na natažení -activity.active_prs_count_n=<strong>%d</strong> aktivní požadavky na natažení -activity.merged_prs_count_1=Sloučený požadavek na natažení -activity.merged_prs_count_n=Sloučené požadavky na natažení -activity.opened_prs_count_1=Navrhovaný požadavek na natažení -activity.opened_prs_count_n=Navrhované požadavky na natažení +activity.active_prs_count_1=<strong>%d</strong> aktivní pull request +activity.active_prs_count_n=<strong>%d</strong> aktivních pull requestů +activity.merged_prs_count_1=Sloučený pull request +activity.merged_prs_count_n=Sloučené pull requesty +activity.opened_prs_count_1=Navrhovaný pull request +activity.opened_prs_count_n=Navrhované pull requesty activity.title.user_1=%d uživatel activity.title.user_n=%d uživatelů -activity.title.prs_1=%d Požadavek na natažení -activity.title.prs_n=%d Požadavků na natažení +activity.title.prs_1=%d pull request +activity.title.prs_n=%d pull requestů activity.title.prs_merged_by=%s sloučil %s activity.title.prs_opened_by=%s navrhl %s activity.merged_prs_label=Sloučený @@ -1942,7 +2007,7 @@ activity.new_issues_count_n=Nové úkoly activity.new_issue_label=Otevřený activity.title.unresolved_conv_1=%d nevyřešená konverzace activity.title.unresolved_conv_n=%d nevyřešených konverzací -activity.unresolved_conv_desc=Tyto nedávno změněné úkolu a požadavky na natažení ještě nebyly vyřešeny. +activity.unresolved_conv_desc=Tyto nedávno změněné úkolu a pull requestu ještě nebyly vyřešeny. activity.unresolved_conv_label=Otevřít activity.title.releases_1=%d Vydání activity.title.releases_n=%d Vydání @@ -1972,17 +2037,8 @@ activity.git_stats_deletion_n=%d odebrání contributors.contribution_type.filter_label=Typ příspěvku: contributors.contribution_type.commits=Commity - -search=Vyhledat -search.search_repo=Hledat repozitář -search.type.tooltip=Druh vyhledávání -search.fuzzy=Fuzzy -search.fuzzy.tooltip=Zahrnout výsledky, které také úzce odpovídají hledanému výrazu -search.match=Shoda -search.match.tooltip=Zahrnout pouze výsledky, které odpovídají přesnému hledanému výrazu -search.results=Výsledky hledání „%s“ v <a href="%s">%s</a> -search.code_no_results=Nebyl nalezen žádný zdrojový kód odpovídající hledanému výrazu. -search.code_search_unavailable=V současné době není vyhledávání kódu dostupné. Obraťte se na správce webu. +contributors.contribution_type.additions=Přidání +contributors.contribution_type.deletions=Odstranění settings=Nastavení settings.desc=Nastavení je místo, kde můžete měnit nastavení repozitáře @@ -2000,10 +2056,13 @@ settings.mirror_settings=Nastavení zrcadla settings.mirror_settings.docs=Nastavte repozitář pro automatickou synchronizaci commitů, značek a větví s jiným repozitářem. settings.mirror_settings.docs.disabled_pull_mirror.instructions=Nastavte váš projekt pro automatické nahrávání commitů, značek a větví do jiného repozitáře. Správce webu zakázal zrcadla pro natažení. settings.mirror_settings.docs.disabled_push_mirror.instructions=Nastavte svůj projekt pro automatické natažení commitů, značek a větví z jiného repozitáře. +settings.mirror_settings.docs.disabled_push_mirror.pull_mirror_warning=Právě teď to lze provést pouze v menu "Nová migrace". Pro více informací prosím konzultujte: +settings.mirror_settings.docs.disabled_push_mirror.info=Push zrcadla byla zakázána administrátorem vašeho webu. settings.mirror_settings.docs.no_new_mirrors=Váš repozitář zrcadlí změny do nebo z jiného repozitáře. Mějte prosím na paměti, že v tuto chvíli nemůžete vytvořit žádná nová zrcadla. settings.mirror_settings.docs.can_still_use=I když nemůžete upravit stávající zrcadla nebo vytvořit nová, stále můžete použít své stávající zrcadlo. settings.mirror_settings.docs.more_information_if_disabled=Více informací o zrcadlech pro nahrání a natažení naleznete zde: settings.mirror_settings.docs.doc_link_title=Jak mohu zrcadlit repozitáře? +settings.mirror_settings.docs.doc_link_pull_section=sekci "stahovat ze vzdáleného úložiště" v dokumentaci. settings.mirror_settings.docs.pulling_remote_title=Stažení ze vzdáleného úložiště settings.mirror_settings.mirrored_repository=Zrcadlený repozitář settings.mirror_settings.direction=Směr @@ -2016,6 +2075,8 @@ settings.mirror_settings.push_mirror.add=Přidat zrcadlo pro nahrání settings.mirror_settings.push_mirror.edit_sync_time=Upravit interval synchronizace zrcadla settings.sync_mirror=Synchronizovat nyní +settings.pull_mirror_sync_in_progress=V tuto chvíli probíhá nahrávání změn ze vzdáleného %s. +settings.push_mirror_sync_in_progress=Probíhá nahrávání změn do vzdáleného %s. settings.site=Webová stránka settings.update_settings=Aktualizovat nastavení settings.update_mirror_settings=Aktualizovat nastavení zrcadla @@ -2025,6 +2086,8 @@ settings.branches.add_new_rule=Přidat nové pravidlo settings.advanced_settings=Pokročilá nastavení settings.wiki_desc=Povolit Wiki repozitáře settings.use_internal_wiki=Používat vestavěnou Wiki +settings.default_wiki_branch_name=Výchozí název větve Wiki +settings.failed_to_change_default_wiki_branch=Změna výchozí větve wiki se nezdařila. settings.use_external_wiki=Používat externí Wiki settings.external_wiki_url=URL externí Wiki settings.external_wiki_url_error=URL externí wiki platné URL. @@ -2046,15 +2109,19 @@ settings.tracker_issue_style.regexp_pattern_desc=První zachycená skupina bude settings.tracker_url_format_desc=Použijte zástupné symboly <code>{user}</code>, <code>{repo}</code> a <code>{index}</code> pro uživatelské jméno, jméno repozitáře a číslo úkolu. settings.enable_timetracker=Povolit sledování času settings.allow_only_contributors_to_track_time=Povolit sledování času pouze přispěvatelům -settings.pulls_desc=Povolit požadavky na natažení +settings.pulls_desc=Povolit pull requesty repozitáře settings.pulls.ignore_whitespace=Ignorovat bílé znaky při konfliktech settings.pulls.enable_autodetect_manual_merge=Povolit autodetekci ručních sloučení (Poznámka: V některých zvláštních případech může dojít k nesprávnému rozhodnutí) -settings.pulls.allow_rebase_update=Povolit aktualizaci větve požadavku na natažení pomocí rebase -settings.pulls.default_delete_branch_after_merge=Ve výchozím nastavení mazat větev požadavku na natažení po jeho sloučení +settings.pulls.allow_rebase_update=Povolit aktualizaci větve pull requestu pomocí rebase +settings.pulls.default_delete_branch_after_merge=Ve výchozím nastavení mazat větev pull requestu po jeho sloučení settings.pulls.default_allow_edits_from_maintainers=Ve výchozím nastavení povolit úpravy od správců settings.releases_desc=Povolit vydání v repozitáři settings.packages_desc=Povolit registr balíčků repozitáře settings.projects_desc=Povolit projekty v repozitáři +settings.projects_mode_desc=Režim projektů (druhy projektů k zobrazení) +settings.projects_mode_repo=Pouze projekty repozitáře +settings.projects_mode_owner=Pouze projekty uživatele nebo organizace +settings.projects_mode_all=Všechny projekty settings.actions_desc=Povolit akce repozitáře settings.admin_settings=Nastavení správce settings.admin_enable_health_check=Povolit kontrolu stavu repozitáře (git fsck) @@ -2080,6 +2147,7 @@ settings.convert_fork_succeed=Rozštěpení bylo překonvertován na běžný re settings.transfer=Předat vlastnictví settings.transfer.rejected=Převod repozitáře byl zamítnut. settings.transfer.success=Převod repozitáře byl úspěšný. +settings.transfer.blocked_user=Nelze převést repozitář, protože jste blokování novým vlastníkem. settings.transfer_abort=Zrušit převod settings.transfer_abort_invalid=Nemůžete zrušit neexistující převod repozitáře. settings.transfer_abort_success=Převod repozitáře do %s byl úspěšně zrušen. @@ -2125,11 +2193,11 @@ settings.add_collaborator_success=Spolupracovník byl přidán. settings.add_collaborator_inactive_user=Nelze přidat neaktivního uživatele jako spolupracovníka. settings.add_collaborator_owner=Vlastníka nelze přidat jako spolupracovníka. settings.add_collaborator_duplicate=Spolupracovník je již přidán k tomuto repozitáři. +settings.add_collaborator.blocked_user=Spolupracovník je zablokován vlastníkem repozitáře nebo naopak. settings.delete_collaborator=Odstranit settings.collaborator_deletion=Odstranit spolupracovníka settings.collaborator_deletion_desc=Odstranění spolupracovníka zruší jeho přístup do tohoto repozitáře. Pokračovat? settings.remove_collaborator_success=Spolupracovník byl smazán. -settings.search_user_placeholder=Hledat uživatele… settings.org_not_allowed_to_be_collaborator=Organizace nemůže být přidána jako spolupracovník. settings.change_team_access_not_allowed=Změna přístupu týmu k repozitáře se omezuje na vlastníka organizace settings.team_not_in_organization=Tým není ve stejné organizaci jako repozitář @@ -2137,7 +2205,6 @@ settings.teams=Týmy settings.add_team=Přidat tým settings.add_team_duplicate=Tým již má repozitář settings.add_team_success=Tým má nyní přístup k repozitáři. -settings.search_team=Vyhledat tým… settings.change_team_permission_tip=Oprávnění týmu je nastaveno na stránce nastavení týmu a nelze je změnit pro každý repozitář settings.delete_team_tip=Tento tým má přístup ke všem repositářům a nemůže být odstraněn settings.remove_team_success=Přístup týmu k repozitáři byl odstraněn. @@ -2203,22 +2270,25 @@ settings.event_issue_milestone=Úkolu přidán milník settings.event_issue_milestone_desc=Úkolu přidán nebo odebrán milník. settings.event_issue_comment=Komentář k úkolu settings.event_issue_comment_desc=Komentář úkolu přidán, upraven nebo smazán. -settings.event_header_pull_request=Události požadavku na natažení -settings.event_pull_request=Požadavek na stažení -settings.event_pull_request_desc=Požadavek na natažení otevřen, uzavřen, znovu otevřen nebo upraven. -settings.event_pull_request_assign=Požadavek na natažení přiřazen -settings.event_pull_request_assign_desc=Požadavek na natažení přiřazen nebo nepřiřazen. -settings.event_pull_request_label=Požadavek na natažení oštítkován -settings.event_pull_request_label_desc=Štítky požadavku na natažení aktualizovány nebo vymazány. -settings.event_pull_request_milestone=Požadavku na natažení přidán milník -settings.event_pull_request_milestone_desc=Požadavku na natažení přidán nebo odebrán milník. -settings.event_pull_request_comment=Požadavek na natažení okomentován -settings.event_pull_request_comment_desc=Komentář požadavku na natažení vytvořen, upraven nebo odstraněn. -settings.event_pull_request_review=Požadavek na natažení přezkoumán -settings.event_pull_request_review_desc=Požadavek na natažení schválen, odmítnut nebo zkontrolován. -settings.event_pull_request_sync=Požadavek na natažení synchronizován -settings.event_pull_request_sync_desc=Požadavek na natažení synchronizován. -settings.event_pull_request_review_request=Vyžádán požadavek na natažení +settings.event_header_pull_request=Události pull requestu +settings.event_pull_request=Pull request +settings.event_pull_request_desc=Pull request otevřen, uzavřen, znovu otevřen nebo upraven. +settings.event_pull_request_assign=Pull request přiřazen +settings.event_pull_request_assign_desc=Pull request přiřazen nebo nepřiřazen. +settings.event_pull_request_label=Pull request oštítkován +settings.event_pull_request_label_desc=Štítky pull requestu aktualizovány nebo vymazány. +settings.event_pull_request_milestone=Přidán milník pull requestu +settings.event_pull_request_milestone_desc=Přidán nebo odebrán milník pull requestu. +settings.event_pull_request_comment=Pull request okomentován +settings.event_pull_request_comment_desc=Komentář pull requestu vytvořen, upraven nebo odstraněn. +settings.event_pull_request_review=Pull request posouzen +settings.event_pull_request_review_desc=Pull request schválen, odmítnut nebo zkontrolován. +settings.event_pull_request_sync=Pull request synchronizován +settings.event_pull_request_sync_desc=Pull request synchronizován. +settings.event_pull_request_review_request=Požádáno o posouzení pull requestu +settings.event_pull_request_review_request_desc=Přidána nebo ostraněna žádnost o kontrolu pull requestu. +settings.event_pull_request_approvals=Schválení pull requestu +settings.event_pull_request_merge=Sloučení pull requestu settings.event_package=Balíček settings.event_package_desc=Balíček vytvořen nebo odstraněn v repozitáři. settings.branch_filter=Filtr větví @@ -2282,32 +2352,34 @@ settings.protect_disable_push_desc=Žádné nahrávání do této větve nebude settings.protect_enable_push=Povolit nahrávání settings.protect_enable_push_desc=Každý, kdo má přístup k zápisu, bude moci nahrávat do této větve (ale ne vynucená nahrávání). settings.protect_enable_merge=Povolit sloučení +settings.protect_enable_merge_desc=Každému, kdo má přístup k zápisu, bude povoleno sloučit pull requesty do této větve. settings.protect_whitelist_committers=Povolit nahrání jen vyjmenovaným settings.protect_whitelist_committers_desc=Pouze povolení uživatelé budou moci nahrávat do této větve (ale ne vynucení nahrávání). settings.protect_whitelist_deploy_keys=Povolit nahrání klíčům pro nasazení s přístupem pro zápis. settings.protect_whitelist_users=Povolení uživatelé pro nahrávání: -settings.protect_whitelist_search_users=Hledat uživatele… settings.protect_whitelist_teams=Povolené týmy pro nahrávání: -settings.protect_whitelist_search_teams=Vyhledat týmy… settings.protect_merge_whitelist_committers=Povolit vyjmenovaným slučování -settings.protect_merge_whitelist_committers_desc=Povolit pouze vyjmenovaným uživatelům nebo týmům slučovat požadavky na natažení do této větve. +settings.protect_merge_whitelist_committers_desc=Povolit pouze vyjmenovaným uživatelům nebo týmům slučovat pull requesty do této větve. settings.protect_merge_whitelist_users=Povolení uživatelé pro slučování: settings.protect_merge_whitelist_teams=Povolené týmy pro slučování: settings.protect_check_status_contexts=Povolit kontrolu stavu settings.protect_status_check_patterns=Vzorce kontroly stavu: +settings.protect_status_check_patterns_desc=Zadejte vzory pro určení, které kontroly stavu musí projít před sloučením větví do větve, která odpovídá tomuto pravidlu. Každý řádek určuje vzor. Vzory nemohou být prázdné. settings.protect_check_status_contexts_desc=Požadovat kontrolu stavu před sloučením. Vyberte, jaké kontroly stavu musí projít před tím, než je možné větev sloučit do větve, která vyhovuje tomuto pravidlu. Pokud je povoleno, revize musí být nejprve nahrány do jiné větve, projít kontrolou stavu, a následné sloučeny nebo přímo nahrány do větve, která vyhovuje tomuto pravidlu. Pokud nejsou vybrány žádné kontexty, musí být poslední potvrzení úspěšné bez ohledu na kontext. settings.protect_check_status_contexts_list=Kontroly stavu pro tento repozitář zjištěné během posledního týdne settings.protect_status_check_matched=Odpovídá settings.protect_invalid_status_check_pattern=Neplatný vzor kontroly stavu: „%s“. settings.protect_no_valid_status_check_patterns=Žádné platné vzory kontroly stavu. settings.protect_required_approvals=Požadovaná schválení: -settings.protect_required_approvals_desc=Umožnit sloučení pouze požadavkům na natažení s dostatečným pozitivním hodnocením. +settings.protect_required_approvals_desc=Umožnit sloučení pouze pull requestů s dostatečným pozitivním hodnocením. settings.protect_approvals_whitelist_enabled=Omezit schválení na povolené uživatele nebo týmy settings.protect_approvals_whitelist_enabled_desc=Do požadovaných schválení se započítají pouze posouzení od povolených uživatelů nebo týmů. Bez seznamu povolených se započítává schválení od kohokoli s právem zápisu. settings.protect_approvals_whitelist_users=Povolení posuzovatelé: settings.protect_approvals_whitelist_teams=Povolené týmy pro posuzování: settings.dismiss_stale_approvals=Odmítnout nekvalitní schválení -settings.dismiss_stale_approvals_desc=Pokud budou do větve nahrány nové revize, které mění obsah tohoto požadavku na natažení, všechna stará schválení budou zamítnuta. +settings.dismiss_stale_approvals_desc=Pokud budou do větve nahrány nové revize, které mění obsah tohoto pull requestu, všechna stará schválení budou zamítnuta. +settings.ignore_stale_approvals=Ignorovat zastaralá schválení +settings.ignore_stale_approvals_desc=Nezapočítávejte schválení, která byla provedena u starších commitů (zastaralých recenzí), do počtu schválení, která má PR. Pokud jsou zastaralá hodnocení již zamítnuta, je to irelevantní. settings.require_signed_commits=Vyžadovat podepsané revize settings.require_signed_commits_desc=Odmítnout nahrání do této větve pokud nejsou podepsaná nebo jsou neověřitelná. settings.protect_branch_name_pattern=Vzor jména chráněných větví @@ -2328,9 +2400,9 @@ settings.block_rejected_reviews=Blokovat sloučení při zamítavých posouzení settings.block_rejected_reviews_desc=Slučování nebude možné, pokud o změny požádají oficiální posuzovatelé, i když je k dispozici dostatek schválení. settings.block_on_official_review_requests=Blokovat sloučení při oficiální žádosti o posouzení settings.block_on_official_review_requests_desc=Slučování nebude možné, pokud mají oficiální požadavek na posouzení, i když mají k dispozici dostatek schválení. -settings.block_outdated_branch=Blokovat sloučení, pokud je požadavek na natažení zastaralý +settings.block_outdated_branch=Blokovat sloučení, pokud je pull request zastaralý settings.block_outdated_branch_desc=Slučování nebude možné, pokud je hlavní větev za základní větví. -settings.default_branch_desc=Vybrat výchozí větev repozitáře pro požadavky na natažení a revize kódu: +settings.default_branch_desc=Vybrat výchozí větev repozitáře pro pull requesty a revize kódu: settings.merge_style_desc=Sloučit styly settings.default_merge_style_desc=Výchozí styl sloučení pro požadavky na natažení: settings.choose_branch=Vyberte větev… @@ -2357,15 +2429,16 @@ settings.matrix.room_id=ID místnosti settings.matrix.message_type=Typ zprávy settings.archive.button=Archivovat repozitář settings.archive.header=Archivovat tento repozitář -settings.archive.text=Archivace repozitáře způsobí, že bude zcela určen pouze pro čtení. Bude skryt z ovládacího panelu. Nikdo (ani vy!) nebude moci vytvářet nové revize ani otevírat nové úkoly nebo žádosti o natažení. +settings.archive.text=Archivace repozitáře způsobí, že bude zcela určen pouze pro čtení. Bude skryt z ovládacího panelu. Nikdo (ani vy!) nebude moci vytvářet nové revize ani otevírat nové úkoly nebo pull requesty. settings.archive.success=Repozitář byl úspěšně archivován. settings.archive.error=Nastala chyba při archivování repozitáře. Prohlédněte si záznam pro více detailů. settings.archive.error_ismirror=Nemůžete archivovat zrcadlený repozitář. settings.archive.branchsettings_unavailable=Nastavení větví není dostupné, pokud je repozitář archivovaný. settings.archive.tagsettings_unavailable=Nastavení značek není k dispozici, pokud je repozitář archivován. +settings.archive.mirrors_unavailable=Zrcadla nejsou k dispozici, pokud je repozitář archivován. settings.unarchive.button=Obnovit repozitář settings.unarchive.header=Obnovit tento repozitář -settings.unarchive.text=Obnovení repozitáře vrátí možnost přijímání commitů a nahrávání. Stejně tak se obnoví i možnost zadávání nových úkolů a požadavků na natažení. +settings.unarchive.text=Obnovení repozitáře vrátí možnost přijímání commitů a nahrávání. Stejně tak se obnoví i možnost zadávání nových úkolů a pull requestů. settings.unarchive.success=Repozitář byl úspěšně obnoven. settings.unarchive.error=Nastala chyba při obnovování repozitáře. Prohlédněte si záznam pro více detailů. settings.update_avatar_success=Avatar repozitáře byl aktualizován. @@ -2446,9 +2519,9 @@ diff.review.header=Odeslat posouzení diff.review.placeholder=Posoudit komentář diff.review.comment=Okomentovat diff.review.approve=Schválit -diff.review.self_reject=Autoři požadavků na natažení nemohou požadovat změny na svém vlastním požadavku na natažení +diff.review.self_reject=Autoři pull requestu nemohou požadovat změny na svém vlastním pull requestu diff.review.reject=Požadovat změny -diff.review.self_approve=Autoři požadavku na natažení nemohou schválit svůj vlastní požadavek na natažení +diff.review.self_approve=Autoři pull requestu nemohou schválit svůj vlastní pull request diff.committed_by=odevzdal diff.protected=Chráněno diff.image.side_by_side=Vedle sebe @@ -2529,7 +2602,6 @@ branch.default_deletion_failed=Větev „%s“ je výchozí větev. Nelze ji ods branch.restore=Obnovit větev „%s“ branch.download=Stáhnout větev „%s“ branch.rename=Přejmenovat větev „%s“ -branch.search=Hledat větev branch.included_desc=Tato větev je součástí výchozí větve branch.included=Zahrnuje branch.create_new_branch=Vytvořit větev z větve: @@ -2560,13 +2632,16 @@ find_file.no_matching=Nebyl nalezen žádný odpovídající soubor error.csv.too_large=Tento soubor nelze vykreslit, protože je příliš velký. error.csv.unexpected=Tento soubor nelze vykreslit, protože obsahuje neočekávaný znak na řádku %d ve sloupci %d. error.csv.invalid_field_count=Soubor nelze vykreslit, protože má nesprávný počet polí na řádku %d. +error.broken_git_hook=Git háčky tohoto repozitáře se zdají být rozbité. Postupujte prosím podle <a target="_blank" rel="noreferrer" href="%s">dokumentace</a>, abyste je opravili, a poté nahrajte nějaké commity pro obnovení stavu. [graphs] component_loading=Načítání %s... component_loading_failed=Nelze načíst %s component_loading_info=Může to chvíli trvat… component_failed_to_load=Došlo k neočekávané chybě. +code_frequency.what=frekvence kódu contributors.what=příspěvky +recent_commits.what=nedávné commity [org] org_name_holder=Název organizace @@ -2672,7 +2747,6 @@ teams.write_permission_desc=Členství v tom týmu poskytuje právo <strong>záp teams.admin_permission_desc=Členství v tom týmu poskytuje právo <strong>správce</strong>: členové mohou číst z, nahrávat do a přidávat spolupracovníky do repozitářů týmu. teams.create_repo_permission_desc=Navíc tento tým uděluje oprávnění <strong>vytvořit repozitář</strong>: členové mohou vytvářet nové repozitáře v organizaci. teams.repositories=Repozitáře týmu -teams.search_repo_placeholder=Hledat repozitář… teams.remove_all_repos_title=Odstranit všechny repozitáře týmu teams.remove_all_repos_desc=Tímto odeberete všechny repozitáře z týmu. teams.add_all_repos_title=Přidat všechny repozitáře @@ -2681,6 +2755,7 @@ teams.add_nonexistent_repo=Repositář, který se snažíte přidat, neexistuje. teams.add_duplicate_users=Uživatel je již členem týmu. teams.repos.none=Tento tým nemůže přistoupit k žádným repozitářům. teams.members.none=Žádní členové v tomto týmu. +teams.members.blocked_user=Nelze přidat uživatele, protože je zablokován organizací. teams.specific_repositories=Konkrétní repozitáře teams.specific_repositories_helper=Členové budou mít přístup pouze do repozitářů výslovně přidaných do týmu. Výběrem tohoto <strong>nebudou</strong> automaticky odstraněny již přidané repozitáře pomocí <i>Všechny repozitáře</i>. teams.all_repositories=Všechny repozitáře @@ -2694,6 +2769,7 @@ teams.invite.description=Pro připojení k týmu klikněte na tlačítko níže. [admin] dashboard=Přehled +self_check=Samokontrola identity_access=Identita a přístup users=Uživatelské účty organizations=Organizace @@ -2703,6 +2779,8 @@ integrations=Integrace authentication=Zdroje ověření emails=Uživatelské e-maily config=Nastavení +config_summary=Souhrn +config_settings=Nastavení notices=Systémová oznámení monitor=Sledování first_page=První @@ -2737,6 +2815,7 @@ dashboard.delete_repo_archives.started=Spuštěna úloha smazání všech archiv dashboard.delete_missing_repos=Smazat všechny repozitáře, které nemají Git soubory dashboard.delete_missing_repos.started=Spuštěna úloha mazání všech repozitářů, které nemají Git soubory. dashboard.delete_generated_repository_avatars=Odstranit vygenerované avatary repozitářů +dashboard.sync_repo_branches=Synchronizovat chybějící větve z git dat do databází dashboard.sync_repo_tags=Synchronizovat značky z git dat do databáze dashboard.update_mirrors=Aktualizovat zrcadla dashboard.repo_health_check=Kontrola stavu všech repozitářů @@ -2752,6 +2831,7 @@ dashboard.reinit_missing_repos=Znovu inicializovat všechny chybějící repozit dashboard.sync_external_users=Synchronizovat externí uživatelská data dashboard.cleanup_hook_task_table=Vyčistit tabulku hook_task dashboard.cleanup_packages=Vyčistit prošlé balíčky +dashboard.cleanup_actions=Vyčištění prošlých záznamů a artefaktů z akcí dashboard.server_uptime=Doba provozu serveru dashboard.current_goroutine=Aktuální Goroutines dashboard.current_memory_usage=Aktuální využití paměti @@ -2877,9 +2957,6 @@ repos.unadopted.no_more=Nebyly nalezeny žádné další nepřijaté repositář repos.owner=Vlastník repos.name=Název repos.private=Soukromý -repos.watches=Sledovače -repos.stars=Oblíbení -repos.forks=Rozštěpení repos.issues=Úkoly repos.size=Velikost repos.lfs_size=Velikost LFS @@ -2888,6 +2965,7 @@ packages.package_manage_panel=Správa balíčků packages.total_size=Celková velikost: %s packages.unreferenced_size=Neodkazovaná velikost: %s packages.cleanup=Vyčistit prošlá data +packages.cleanup.success=Úspěšné vyčištění dat, jejichž platnost vypršela packages.owner=Vlastník packages.creator=Tvůrce packages.name=Název @@ -2898,10 +2976,12 @@ packages.size=Velikost packages.published=Publikováno defaulthooks=Výchozí webové háčky +defaulthooks.desc=Webové háčky automaticky vytvářejí HTTP POST dotazy na server při určitých Gitea událostech. Webové háčky definované zde jsou výchozí a budou zkopírovány do všech nových repozitářů. Přečtěte si více v <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/webhooks/">průvodci webovými háčky</a>. defaulthooks.add_webhook=Přidat výchozí webový háček defaulthooks.update_webhook=Aktualizovat výchozí webový háček systemhooks=Systémové webové háčky +systemhooks.desc=Webové háčky automaticky vytvářejí HTTP POST dotazy na server při určitých Gitea událostech. Webové háčky definované zde budou vykonány na všech repozitářích systému, proto prosím zvažte jakékoli důsledky, které to může mít na výkon. Přečtěte si více v <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/webhooks/">průvodci webovými háčky</a>. systemhooks.add_webhook=Přidat systémový webový háček systemhooks.update_webhook=Aktualizovat systémový webový háček @@ -2979,6 +3059,7 @@ auths.oauth2_required_claim_value_helper=Nastavte tuto hodnotu pro omezení při auths.oauth2_group_claim_name=Název tvrzení poskytující názvy skupin pro tento zdroj. (nepovinné) auths.oauth2_admin_group=Hodnota tvrzení pro skupinu uživatelů administrátorů. (Volitelné - vyžaduje název tvrzení výše) auths.oauth2_restricted_group=Hodnota tvrzení pro skupinu omezených uživatelů. (Volitelné - vyžaduje název tvrzení výše) +auths.oauth2_map_group_to_team=Mapa uváděných skupin do organizačních týmů. (Volitelné - vyžaduje výše uvedené jméno) auths.oauth2_map_group_to_team_removal=Odebrat uživatele z synchronizovaných týmů, pokud uživatel nepatří do odpovídající skupiny. auths.enable_auto_register=Povolit zaregistrování se auths.sspi_auto_create_users=Automaticky vytvářet uživatele @@ -3000,7 +3081,7 @@ auths.tip.nextcloud=Zaregistrujte nového OAuth konzumenta na vaší instanci po auths.tip.dropbox=Vytvořte novou aplikaci na https://www.dropbox.com/developers/apps auths.tip.facebook=Registrujte novou aplikaci na https://developers.facebook.com/apps a přidejte produkt „Facebook Login“ auths.tip.github=Registrujte novou OAuth aplikaci na https://github.com/settings/applications/new -auths.tip.gitlab=Registrujte novou aplikaci na https://gitlab.com/profile/applications +auths.tip.gitlab_new=Zaregistrujte novou aplikaci na https://gitlab.com/-/profile/applications auths.tip.google_plus=Získejte klientské pověření OAuth2 z Google API konzole na https://console.developers.google.com/ auths.tip.openid_connect=Použijte OpenID URL pro objevování spojení (<server>/.well-known/openid-configuration) k nastavení koncových bodů auths.tip.twitter=Jděte na https://dev.twitter.com/apps, vytvořte aplikaci a ujistěte se, že volba „Allow this application to be used to Sign in with Twitter“ je povolená @@ -3136,6 +3217,7 @@ config.picture_config=Nastavení obrázku a avataru config.picture_service=Služba ikon uživatelů config.disable_gravatar=Zakázat službu Gravatar config.enable_federated_avatar=Povolit avatary z veřejných zdrojů +config.open_with_editor_app_help=Editory "Otevřít" v nabídce klon. Ponecháte-li prázdné, bude použito výchozí. Pro zobrazení výchozího nastavení rozbalte. config.git_config=Konfigurace Gitu config.git_disable_diff_highlight=Zakázat zvýraznění syntaxe v rozdílovém zobrazení @@ -3150,6 +3232,7 @@ config.git_pull_timeout=Časový limit operace stažení config.git_gc_timeout=Časový limit operace GC config.log_config=Nastavení logů +config.logger_name_fmt=Logger: %s config.disabled_logger=Zakázané config.access_log_mode=Režim logování přístupu config.access_log_template=Šablona záznamu přístupu @@ -3168,6 +3251,7 @@ monitor.execute_times=Vykonání monitor.process=Spuštěné procesy monitor.stacktrace=Výpisy zásobníku monitor.processes_count=%d procesů +monitor.download_diagnosis_report=Stáhnout diagnosttickou zprávu monitor.desc=Popis monitor.start=Čas zahájení monitor.execute_time=Doba provádění @@ -3187,6 +3271,7 @@ monitor.queue.maxnumberworkers=Maximální počet workerů monitor.queue.numberinqueue=Číslo ve frontě monitor.queue.review_add=Posoudit / přidat workery monitor.queue.settings.title=Nastavení fondu +monitor.queue.settings.desc=Fondy se dynamicky zvětšují v závislosti na blokování jejich pracovních front. monitor.queue.settings.maxnumberworkers=Maximální počet workerů monitor.queue.settings.maxnumberworkers.placeholder=V současné době %[1]d monitor.queue.settings.maxnumberworkers.error=Maximální počet workerů musí být číslo @@ -3224,13 +3309,13 @@ commit_repo=nahrál/a do <a href="%[2]s">%[3]s</a> v <a href="%[1]s">%[4]s</a> create_issue=`otevřel/a úkol <a href="%[1]s">%[3]s#%[2]s</a>` close_issue=`uzavřel/a úkol <a href="%[1]s">%[3]s#%[2]s</a>` reopen_issue=`znovuotevřel/a úkol <a href="%[1]s">%[3]s#%[2]s</a>` -create_pull_request=`vytvořil/a požadavek na natažení <a href="%[1]s">%[3]s#%[2]s</a>` -close_pull_request=`uzavřel/a požadavek na natažení <a href="%[1]s">%[3]s#%[2]s</a>` -reopen_pull_request=`znovuotevřel/a požadavek na natažení <a href="%[1]s">%[3]s#%[2]s</a>` +create_pull_request=`vytvořil/a pull request <a href="%[1]s">%[3]s#%[2]s</a>` +close_pull_request=`uzavřel/a pull request <a href="%[1]s">%[3]s#%[2]s</a>` +reopen_pull_request=`znovuotevřel/a pull request <a href="%[1]s">%[3]s#%[2]s</a>` comment_issue=`okomentoval/a problém <a href="%[1]s">%[3]s#%[2]s</a>` -comment_pull=`okomentoval/a požadavek na natažení <a href="%[1]s">%[3]s#%[2]s</a>` -merge_pull_request=`sloučil/a požadavek na natažení <a href="%[1]s">%[3]s#%[2]s</a>` -auto_merge_pull_request=`automaticky sloučen požadavek na natažení <a href="%[1]s">%[3]s#%[2]s</a>` +comment_pull=`okomentoval/a pull request <a href="%[1]s">%[3]s#%[2]s</a>` +merge_pull_request=`sloučil/a pull request <a href="%[1]s">%[3]s#%[2]s</a>` +auto_merge_pull_request=`automaticky sloučen pull request <a href="%[1]s">%[3]s#%[2]s</a>` transfer_repo=předal/a repozitář <code>%s</code> uživateli/organizaci <a href="%s">%s</a> push_tag=nahrál/a značku <a href="%[2]s">%[3]s</a> do <a href="%[1]s">%[4]s</a> delete_tag=smazal/a značku %[2]s z <a href="%[1]s">%[3]s</a> @@ -3431,6 +3516,7 @@ owner.settings.cargo.initialize.description=Pro použití Cargo registru je zapo owner.settings.cargo.initialize.error=Nepodařilo se inicializovat Cargo index: %v owner.settings.cargo.initialize.success=Index Cargo byl úspěšně vytvořen. owner.settings.cargo.rebuild=Znovu vytvořit Index +owner.settings.cargo.rebuild.description=Obnova může být užitečná, pokud index není synchronizován s uloženými balíčky Cargo. owner.settings.cargo.rebuild.error=Obnovení Cargo indexu se nezdařilo: %v owner.settings.cargo.rebuild.success=Cargo Index byl úspěšně obnoven. owner.settings.cleanuprules.title=Spravovat pravidla pro čištění @@ -3523,8 +3609,10 @@ runners.reset_registration_token_success=Registrační token runneru byl úspě runs.all_workflows=Všechny pracovní postupy runs.commit=Commit runs.scheduled=Naplánováno +runs.pushed_by=náhrán runs.invalid_workflow_helper=Konfigurační soubor pracovního postupu je neplatný. Zkontrolujte prosím konfigurační soubor: %s runs.no_matching_online_runner_helper=Žádný odpovídající online runner s popiskem: %s +runs.no_job_without_needs=Pracovní postup musí obsahovat alespoň jednu úlohu bez závislostí. runs.actor=Aktér runs.status=Status runs.actors_no_select=Všichni aktéři @@ -3542,6 +3630,7 @@ workflow.enable=Povolit pracovní postup workflow.enable_success=Pracovní postup „%s“ byl úspěšně aktivován. workflow.disabled=Pracovní postup je zakázán. +need_approval_desc=Potřebujete schválení pro spuštění pracovních postupů pro rozštěpený pull request. variables=Proměnné variables.management=Správa proměnných diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index fa10bfcb11..1dacb0e0ee 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -17,6 +17,7 @@ template=Template language=Sprache notifications=Benachrichtigungen active_stopwatch=Aktive Zeiterfassung +tracked_time_summary=Zusammenfassung der erfassten Zeit basierend auf Filtern der Issue-Liste create_new=Erstellen… user_profile_and_more=Profil und Einstellungen… signed_in_as=Angemeldet als @@ -24,6 +25,7 @@ enable_javascript=Diese Website benötigt JavaScript. toc=Inhaltsverzeichnis licenses=Lizenzen return_to_gitea=Zurück zu Gitea +more_items=Weitere Einträge username=Benutzername email=E-Mail-Adresse @@ -90,6 +92,7 @@ remove=Löschen remove_all=Alle entfernen remove_label_str=Element "%s " entfernen edit=Bearbeiten +view=Anzeigen enabled=Aktiviert disabled=Deaktiviert @@ -99,7 +102,7 @@ copy=Kopieren copy_url=URL kopieren copy_hash=Hash kopieren copy_content=Inhalt kopieren -copy_branch=Branchenname kopieren +copy_branch=Branchennamen kopieren copy_success=Kopiert! copy_error=Kopieren fehlgeschlagen copy_type_unsupported=Dieser Dateityp kann nicht kopiert werden @@ -111,6 +114,7 @@ loading=Laden… error=Fehler error404=Die Seite, die Du versuchst aufzurufen, <strong>existiert nicht</strong> oder <strong>Du bist nicht berechtigt</strong>, diese anzusehen. go_back=Zurück +invalid_data=Ungültige Daten: %v never=Niemals unknown=Unbekannt @@ -121,6 +125,7 @@ pin=Anheften unpin=Loslösen artifacts=Artefakte +confirm_delete_artifact=Bist du sicher, dass du das Artefakt '%s' löschen möchtest? archived=Archiviert @@ -139,6 +144,43 @@ confirm_delete_selected=Alle ausgewählten Elemente löschen? name=Name value=Wert +filter=Filter +filter.clear=Filter leeren +filter.is_archived=Archiviert +filter.not_archived=Nicht archiviert +filter.is_fork=Fork +filter.not_fork=Kein Fork +filter.is_mirror=Gespiegelt +filter.not_mirror=Nicht gespiegelt +filter.is_template=Template +filter.not_template=Kein Template +filter.public=Öffentlich +filter.private=Privat + +no_results_found=Es wurden keine Ergebnisse gefunden. + +[search] +search=Suche ... +type_tooltip=Suchmodus +fuzzy=Ähnlich +fuzzy_tooltip=Ergebnisse einbeziehen, die dem Suchbegriff ähnlich sind +match=Genau +match_tooltip=Nur genau zum Suchbegriff passende Ergebnisse einbeziehen +repo_kind=Repositories durchsuchen ... +user_kind=Benutzer durchsuchen ... +org_kind=Organisationen durchsuchen ... +team_kind=Teams durchsuchen ... +code_kind=Code durchsuchen ... +code_search_unavailable=Zurzeit ist die Code-Suche nicht verfügbar. Bitte wende dich an den Website-Administrator. +code_search_by_git_grep=Aktuelle Code-Suchergebnisse werden von "git grep" bereitgestellt. Es könnte bessere Ergebnisse geben, wenn der Website-Administrator den Repository-Indexer aktiviert. +package_kind=Pakete durchsuchen ... +project_kind=Projekte durchsuchen ... +branch_kind=Branches durchsuchen ... +commit_kind=Commits durchsuchen ... +runner_kind=Runner durchsuchen ... +no_results=Es wurden keine passenden Ergebnisse gefunden. +keyword_search_unavailable=Zurzeit ist die Stichwort-Suche nicht verfügbar. Bitte wende dich an den Website-Administrator. + [aria] navbar=Navigationsleiste footer=Fußzeile @@ -244,6 +286,7 @@ email_title=E-Mail-Einstellungen smtp_addr=SMTP-Host smtp_port=SMTP-Port smtp_from=E-Mail senden als +smtp_from_invalid=Die „E-Mail senden als“ Adresse ist ungültig smtp_from_helper=E-Mail-Adresse, die von Gitea genutzt werden soll. Bitte gib die E-Mail-Adresse im Format „"Name" <email@example.com>“ ein. mailer_user=SMTP-Benutzername mailer_password=SMTP-Passwort @@ -303,6 +346,7 @@ env_config_keys=Umgebungskonfiguration env_config_keys_prompt=Die folgenden Umgebungsvariablen werden auch auf Ihre Konfigurationsdatei angewendet: [home] +nav_menu=Navigationsmenü uname_holder=E-Mail-Adresse oder Benutzername password_holder=Passwort switch_dashboard_context=Kontext der Übersichtsseite wechseln @@ -312,7 +356,6 @@ collaborative_repos=Gemeinschaftliche Repositories my_orgs=Meine Organisationen my_mirrors=Meine Mirrors view_home=%s ansehen -search_repos=Finde ein Repository… filter=Andere Filter filter_by_team_repositories=Nach Team-Repositories filtern feed_of=`Feed von "%s"` @@ -333,20 +376,8 @@ issues.in_your_repos=Eigene Repositories repos=Repositories users=Benutzer organizations=Organisationen -search=Suche go_to=Gehe zu code=Code -search.type.tooltip=Suchmodus -search.fuzzy=Ähnlich -search.fuzzy.tooltip=Zeige auch Ergebnisse, die dem Suchbegriff ähneln -search.match=Genau -search.match.tooltip=Zeige nur Ergebnisse, die exakt mit dem Suchbegriff übereinstimmen -code_search_unavailable=Derzeit ist die Code-Suche nicht verfügbar. Bitte wende dich an den Website-Administrator. -repo_no_results=Keine passenden Repositories gefunden. -user_no_results=Keine passenden Benutzer gefunden. -org_no_results=Keine passenden Organisationen gefunden. -code_no_results=Es konnte kein passender Code für deinen Suchbegriff gefunden werden. -code_search_results=`Suchergebnisse für "%s"` code_last_indexed_at=Zuletzt indexiert %s relevant_repositories_tooltip=Repositories, die Forks sind oder die kein Thema, kein Symbol und keine Beschreibung haben, werden ausgeblendet. relevant_repositories=Es werden nur relevante Repositories angezeigt, <a href="%s">ungefilterte Ergebnisse anzeigen</a>. @@ -359,11 +390,12 @@ disable_register_prompt=Die Registrierung ist deaktiviert. Bitte wende dich an d disable_register_mail=E-Mail-Bestätigung bei der Registrierung ist deaktiviert. manual_activation_only=Kontaktiere den Website-Administrator, um die Aktivierung abzuschließen. remember_me=Dieses Gerät speichern +remember_me.compromised=Das Login-Token ist nicht mehr gültig, was auf ein kompromittiertes Konto hindeuten kann. Bitte überprüfe dein Konto auf ungewöhnliche Aktivitäten. forgot_password_title=Passwort vergessen forgot_password=Passwort vergessen? sign_up_now=Noch kein Konto? Jetzt registrieren. sign_up_successful=Konto wurde erfolgreich erstellt. Willkommen! -confirmation_mail_sent_prompt=Eine neue Bestätigungs-E-Mail wurde an <b>%s</b> gesendet. Bitte überprüfe dein Postfach innerhalb der nächsten %s, um die Registrierung abzuschließen. +confirmation_mail_sent_prompt_ex=Eine neue Bestätigungs-E-Mail wurde an <b>%s</b>gesendet. Bitte überprüfe deinen Posteingang innerhalb der nächsten %s, um den Registrierungsprozess abzuschließen. Wenn deine Registrierungs-E-Mail-Adresse falsch ist, kannst du dich erneut anmelden und diese ändern. must_change_password=Aktualisiere dein Passwort allow_password_change=Verlange vom Benutzer das Passwort zu ändern (empfohlen) reset_password_mail_sent_prompt=Eine Bestätigungs-E-Mail wurde an <b>%s</b> gesendet. Bitte überprüfe dein Postfach innerhalb von %s, um den Wiederherstellungsprozess abzuschließen. @@ -373,6 +405,7 @@ prohibit_login=Anmelden verboten prohibit_login_desc=Die Anmeldung mit diesem Konto ist nicht gestattet. Bitte kontaktiere den Administrator. 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. +change_unconfirmed_mail_address=Wenn deine Registrierungs-E-Mail-Adresse falsch ist, kannst du sie hier ändern und eine neue Bestätigungs-E-Mail senden. resend_mail=Aktivierungs-E-Mail erneut verschicken email_not_associate=Diese E-Mail-Adresse ist mit keinem Konto verknüpft. send_reset_mail=Wiederherstellungs-E-Mail senden @@ -420,6 +453,7 @@ authorization_failed_desc=Die Autorisierung ist fehlgeschlagen, da wir eine ung sspi_auth_failed=SSPI-Authentifizierung fehlgeschlagen password_pwned=Das von dir gewählte Passwort befindet sich auf einer <a target="_blank" rel="noopener noreferrer" href="https://haveibeenpwned.com/Passwords">List gestohlener Passwörter</a>, die öffentlich verfügbar sind. Bitte versuche es erneut mit einem anderen Passwort und ziehe in Erwägung, auch anderswo deine Passwörter zu ändern. password_pwned_err=Anfrage an HaveIBeenPwned konnte nicht abgeschlossen werden +last_admin=Du kannst den letzten Admin nicht entfernen. Es muss mindestens einen Administrator geben. [mail] view_it_on=Auf %s ansehen @@ -552,6 +586,7 @@ team_name_been_taken=Der Teamname ist bereits vergeben. team_no_units_error=Das Team muss auf mindestens einen Bereich Zugriff haben. email_been_used=Die E-Mail-Adresse wird bereits verwendet. email_invalid=Die E-Mail-Adresse ist ungültig. +email_domain_is_not_allowed=Die Domain der Benutzer-E-Mail <b>%s</b> steht im Widerspruch zu EMAIL_DOMAIN_ALLOWLIST oder EMAIL_DOMAIN_BLOCKLIST. Bitte stelle sicher, dass deine Operation erwartet ist. openid_been_used=Die OpenID-Adresse "%s" wird bereits verwendet. username_password_incorrect=Benutzername oder Passwort ist falsch. password_complexity=Das Passwort erfüllt nicht die Komplexitätsanforderungen: @@ -563,6 +598,8 @@ enterred_invalid_repo_name=Der eingegebenen Repository-Name ist falsch. enterred_invalid_org_name=Der eingegebene Organisation-Name ist falsch. enterred_invalid_owner_name=Der Name des neuen Besitzers ist ungültig. enterred_invalid_password=Das eingegebene Passwort ist falsch. +unset_password=Der Login-Benutzer hat das Passwort nicht gesetzt. +unsupported_login_type=Der Anmeldetyp wird zum Löschen des Kontos nicht unterstützt. user_not_exist=Dieser Benutzer ist nicht vorhanden. team_not_exist=Dieses Team existiert nicht. last_org_owner=Du kannst den letzten Benutzer nicht aus dem 'Besitzer'-Team entfernen. Es muss mindestens einen Besitzer in einer Organisation geben. @@ -585,6 +622,7 @@ org_still_own_packages=Diese Organisation besitzt noch ein oder mehrere Pakete, target_branch_not_exist=Der Ziel-Branch existiert nicht. +admin_cannot_delete_self=Du kannst dich nicht selbst löschen, wenn du ein Administrator bist. Bitte entferne zuerst deine Administratorrechte. [user] change_avatar=Profilbild ändern… @@ -611,6 +649,30 @@ form.name_reserved=Der Benutzername "%s" ist reserviert. form.name_pattern_not_allowed=Das Muster "%s" ist nicht in einem Benutzernamen erlaubt. form.name_chars_not_allowed=Benutzername "%s" enthält ungültige Zeichen. +block.block=Sperren +block.block.user=Benutzer sperren +block.block.org=Benutzer für Organisation sperren +block.block.failure=Fehler beim Sperren des Benutzers: %s +block.unblock=Entsperren +block.unblock.failure=Fehler beim Entsperren des Benutzers: %s +block.blocked=Du hast diesen Benutzer gesperrt. +block.title=Einen Benutzer sperren +block.info=Das Blockieren eines Benutzers hindert ihn daran, mit Repositories zu interagieren, wie zum Beispiel das Öffnen oder Kommentieren von Pull Requests oder Issues. Erfahre mehr über das Blockieren eines Benutzers. +block.info_1=Das Blockieren eines Benutzers verhindert folgende Aktionen auf deinem Konto und deinen Repositories: +block.info_2=deinem Konto folgen +block.info_3=dir Benachrichtigungen durch @Erwähnung deines Benutzernamens senden +block.info_4=dich als Mitarbeiter in deren Repositories einladen +block.info_5=Repositories favorisieren, forken oder beobachten +block.info_6=Issues oder Pull Requests öffnen und kommentieren +block.info_7=auf deine Kommentare in Issues oder Pull Requests reagieren +block.user_to_block=Zu sperrender Benutzer +block.note=Anmerkung +block.note.title=Optionale Anmerkung: +block.note.info=Die Anmerkung ist für den blockierten Benutzer nicht sichtbar. +block.note.edit=Anmerkung bearbeiten +block.list=Gesperrte Benutzer +block.list.none=Du hast noch keine Benutzer gesperrt. + [settings] profile=Profil account=Account @@ -755,7 +817,6 @@ gpg_invalid_token_signature=Der GPG Key, die Signatur, und das Token stimmen nic gpg_token_required=Du musst eine Signatur für das folgende Token angeben gpg_token=Token gpg_token_help=Du kannst eine Signatur wie folgt generieren: -gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig gpg_token_signature=GPG Textsignatur (armored signature) key_signature_gpg_placeholder=Beginnt mit '-----BEGIN PGP SIGNATURE-----' verify_gpg_key_success=GPG-Schlüssel "%s" wurde verifiziert. @@ -863,6 +924,7 @@ revoke_oauth2_grant_description=Wenn du die Autorisierung widerrufst, kann die A revoke_oauth2_grant_success=Zugriff erfolgreich widerrufen. twofa_desc=Zwei-Faktor-Authentifizierung trägt zu einer höheren Accountsicherheit bei. +twofa_recovery_tip=Wenn du dein Gerät verlierst, kannst du einen einmalig verwendbaren Wiederherstellungsschlüssel nutzen, um den Zugriff auf dein Konto wiederherzustellen. 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_disable=Zwei-Faktor-Authentifizierung deaktivieren @@ -885,6 +947,8 @@ webauthn_register_key=Sicherheitsschlüssel hinzufügen webauthn_nickname=Nickname webauthn_delete_key=Sicherheitsschlüssel entfernen webauthn_delete_key_desc=Wenn du einen Sicherheitsschlüssel entfernst, kannst du dich nicht mehr mit ihm anmelden. Fortfahren? +webauthn_key_loss_warning=Wenn du deine Sicherheitsschlüssel verlierst, verlierst du den Zugriff auf dein Konto. +webauthn_alternative_tip=Möglicherweise möchtest du eine zusätzliche Authentifizierungsmethode konfigurieren. manage_account_links=Verknüpfte Accounts verwalten manage_account_links_desc=Diese externen Accounts sind mit deinem Gitea-Account verknüpft. @@ -921,6 +985,7 @@ visibility.private=Privat visibility.private_tooltip=Sichtbar nur für Mitglieder von Organisationen, denen du beigetreten bist [repo] +new_repo_helper=Ein Repository enthält alle Projektdateien, einschließlich des Änderungsverlaufs. Schon woanders vorhanden? <a href="%s">Migration eines Repositorys.</a> owner=Besitzer owner_helper=Einige Organisationen könnten in der Dropdown-Liste nicht angezeigt werden, da die Anzahl an Repositories begrenzt ist. repo_name=Repository-Name @@ -944,8 +1009,9 @@ fork_visibility_helper=Die Sichtbarkeit eines geforkten Repositories kann nicht fork_branch=Branch, der zum Fork geklont werden soll all_branches=Alle Branches fork_no_valid_owners=Dieses Repository kann nicht geforkt werden, da keine gültigen Besitzer vorhanden sind. +fork.blocked_user=Das Repository kann nicht geforkt werden, da du vom Repository-Eigentümer blockiert wurdest. use_template=Dieses Template verwenden -clone_in_vsc=In VS Code klonen +open_with_editor=Mit %s öffnen download_zip=ZIP herunterladen download_tar=TAR.GZ herunterladen download_bundle=BUNDLE herunterladen @@ -961,6 +1027,8 @@ issue_labels_helper=Wähle ein Issue-Label-Set. license=Lizenz license_helper=Wähle eine Lizenz aus. license_helper_desc=Eine Lizenz regelt, was Andere mit deinem Code (nicht) tun können. Unsicher, welches für dein Projekt die Richtige ist? Siehe <a target="_blank" rel="noopener noreferrer" href="%s">eine Lizenz wählen</a>. +object_format=Objektformat +object_format_helper=Objektformat des Repositories. Es kann später nicht geändert werden. SHA1 ist am meisten kompatibel. readme=README readme_helper=Wähle eine README-Vorlage aus. readme_helper_desc=Hier kannst du eine komplette Beschreibung für dein Projekt schreiben. @@ -978,6 +1046,7 @@ mirror_prune=Entfernen mirror_prune_desc=Entferne veraltete remote-tracking Referenzen mirror_interval=Mirror-Intervall (gültige Zeiteinheiten sind 'h', 'm', 's'). 0 deaktiviert die regelmäßige Synchronisation. (Minimales Intervall: %s) mirror_interval_invalid=Das Spiegel-Intervall ist ungültig. +mirror_sync=synchronisiert mirror_sync_on_commit=Synchronisieren, wenn Commits gepusht wurden mirror_address=Klonen via URL mirror_address_desc=Gib alle erforderlichen Anmeldedaten im Abschnitt "Authentifizierung" ein. @@ -995,6 +1064,7 @@ watchers=Beobachter stargazers=Favorisiert von stars_remove_warning=Dies wird alle Sterne aus diesem Repository entfernen. forks=Forks +stars=Favoriten reactions_more=und %d weitere unit_disabled=Der Administrator hat diesen Repository-Bereich deaktiviert. language_other=Andere @@ -1028,6 +1098,7 @@ desc.public=Öffentlich desc.template=Template desc.internal=Intern desc.archived=Archiviert +desc.sha256=SHA256 template.items=Template-Elemente template.git_content=Git Inhalt (Standardbranch) @@ -1115,6 +1186,7 @@ watch=Beobachten unstar=Favorit entfernen star=Favorisieren fork=Fork +action.blocked_user=Die Aktion kann nicht ausgeführt werden, da du vom Repository-Eigentümer blockiert wurdest. download_archive=Repository herunterladen more_operations=Weitere Operationen @@ -1178,6 +1250,8 @@ audio_not_supported_in_browser=Dein Browser unterstützt den HTML5 'audio'-Tag n stored_lfs=Gespeichert mit Git LFS symbolic_link=Softlink executable_file=Ausführbare Datei +vendored=Vendor +generated=Generiert commit_graph=Commit graph commit_graph.select=Branches auswählen commit_graph.hide_pr_refs=Pull-Requests ausblenden @@ -1241,6 +1315,8 @@ editor.file_editing_no_longer_exists=Die bearbeitete Datei "%s" existiert nicht editor.file_deleting_no_longer_exists=Die zu löschende 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 noreferrer" 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' existiert bereits in diesem Repository. +editor.commit_id_not_matching=Die Commit-ID stimmt nicht mit der ID überein, bei welcher du mit der Bearbeitung begonnen hast. Commite in einen Patch-Branch und merge daraufhin. +editor.push_out_of_date=Der Push scheint veraltet zu sein. editor.commit_empty_file_header=Leere Datei committen editor.commit_empty_file_text=Die Datei, die du commiten willst, ist leer. Fortfahren? editor.no_changes_to_show=Keine Änderungen vorhanden. @@ -1264,9 +1340,8 @@ commits.desc=Durchsuche die Quellcode-Änderungshistorie. commits.commits=Commits commits.no_commits=Keine gemeinsamen Commits. "%s" und "%s" haben vollständig unterschiedliche Historien. commits.nothing_to_compare=Diese Branches sind auf demselben Stand. -commits.search=Commits durchsuchen… commits.search.tooltip=Du kannst Suchbegriffen "author:", " committer:", "after:", oder " before:" voranstellen, z.B. "revert author:Alice before:2019-04-01". -commits.find=Suchen +commits.search_branch=Dieser Branch commits.search_all=Alle Branches commits.author=Autor commits.message=Nachricht @@ -1317,7 +1392,6 @@ projects.type.basic_kanban=Einfaches Kanban projects.type.bug_triage=Bug Triage projects.template.desc=Projektvorlage projects.template.desc_helper=Wähle eine Projektvorlage aus, um loszulegen -projects.type.uncategorized=Nicht kategorisiert projects.column.edit=Spalte bearbeiten projects.column.edit_title=Name projects.column.new_title=Name @@ -1325,10 +1399,8 @@ projects.column.new_submit=Spalte erstellen projects.column.new=Neue Spalte projects.column.set_default=Als Standard verwenden projects.column.set_default_desc=Diese Spalte als Standard für unkategorisierte Issues und Pull Requests festlegen -projects.column.unset_default=Standard entfernen -projects.column.unset_default_desc=Diese Spalte als Standard entfernen projects.column.delete=Spalte löschen -projects.column.deletion_desc=Beim Löschen einer Projektspalte werden alle dazugehörigen Issues nach 'Nicht kategorisiert' verschoben. Fortfahren? +projects.column.deletion_desc=Beim Löschen einer Projektspalte werden alle Einträge in die Standard-Spalte verschoben. Fortfahren? projects.column.color=Farbe projects.open=Öffnen projects.close=Schließen @@ -1363,6 +1435,8 @@ issues.new.assignees=Zuständig issues.new.clear_assignees=Zuständige entfernen issues.new.no_assignees=Niemand zuständig issues.new.no_reviewers=Keine Reviewer +issues.new.blocked_user=Das Issue kann nicht erstellt werden, da du vom Repository-Eigentümer blockiert wurdest. +issues.edit.blocked_user=Der Inhalt kann nicht bearbeitet werden, da du vom Repository-Eigentümer blockiert wurdest. issues.choose.get_started=Los geht's issues.choose.open_external_link=Öffnen issues.choose.blank=Standard @@ -1440,7 +1514,6 @@ issues.filter_sort.moststars=Meiste Favoriten issues.filter_sort.feweststars=Wenigste Favoriten issues.filter_sort.mostforks=Meiste Forks issues.filter_sort.fewestforks=Wenigste Forks -issues.keyword_search_unavailable=Zurzeit ist die Stichwort-Suche nicht verfügbar. Bitte wende dich an den Website-Administrator. issues.action_open=Öffnen issues.action_close=Schließen issues.action_label=Label @@ -1478,6 +1551,7 @@ issues.close_comment_issue=Kommentieren und schließen issues.reopen_issue=Wieder öffnen issues.reopen_comment_issue=Kommentieren und wieder öffnen issues.create_comment=Kommentieren +issues.comment.blocked_user=Der Kommentar kann nicht erstellt oder bearbeitet werden, da du vom Repository-Eigentümer blockiert wurdest. issues.closed_at=`hat diesen Issue <a id="%[1]s" href="#%[1]s">%[2]s</a> geschlossen` issues.reopened_at=`hat diesen Issue <a id="%[1]s" href="#%[1]s">%[2]s</a> wieder geöffnet` issues.commit_ref_at=`hat dieses Issue <a id="%[1]s" href="#%[1]s">%[2]s</a> aus einem Commit referenziert` @@ -1676,6 +1750,7 @@ compare.compare_head=vergleichen pulls.desc=Pull-Requests und Code-Reviews aktivieren. pulls.new=Neuer Pull-Request +pulls.new.blocked_user=Der Pull Request kann nicht erstellt werden, da du vom Repository-Eigentümer blockiert wurdest. pulls.view=Pull-Request ansehen pulls.compare_changes=Neuer Pull-Request pulls.allow_edits_from_maintainers=Änderungen von Maintainern erlauben @@ -1692,7 +1767,6 @@ pulls.compare_compare=pullen von pulls.switch_comparison_type=Vergleichstyp wechseln pulls.switch_head_and_base=Head und Base vertauschen pulls.filter_branch=Branch filtern -pulls.no_results=Keine Ergebnisse verfügbar. pulls.show_all_commits=Alle Commits anzeigen pulls.show_changes_since_your_last_review=Zeige Änderungen seit deinem letzten Review pulls.showing_only_single_commit=Nur Änderungen aus Commit %[1]s werden angezeigt @@ -1701,6 +1775,7 @@ pulls.select_commit_hold_shift_for_range=Commit auswählen. Halte Shift + klicke pulls.review_only_possible_for_full_diff=Ein Review ist nur möglich, wenn das vollständige Diff angezeigt wird pulls.filter_changes_by_commit=Nach Commit filtern pulls.nothing_to_compare=Diese Branches sind identisch. Es muss kein Pull-Request erstellt werden. +pulls.nothing_to_compare_have_tag=Der ausgewählte Branch und Tag sind gleich. pulls.nothing_to_compare_and_allow_empty_pr=Diese Branches sind gleich. Der Pull-Request wird leer sein. pulls.has_pull_request=`Es existiert bereits ein Pull-Request zwischen diesen beiden Branches: <a href="%[1]s">%[2]s#%[3]d</a>` pulls.create=Pull-Request erstellen @@ -1759,6 +1834,7 @@ pulls.merge_pull_request=Merge Commit erstellen pulls.rebase_merge_pull_request=Rebasen und dann fast-forwarden pulls.rebase_merge_commit_pull_request=Rebasen und dann mergen pulls.squash_merge_pull_request=Squash Commit erstellen +pulls.fast_forward_only_merge_pull_request=Nur Fast-forward pulls.merge_manually=Manuell mergen pulls.merge_commit_id=Der Mergecommit ID pulls.require_signed_wont_sign=Der Branch erfordert einen signierten Commit, aber dieser Merge wird nicht signiert @@ -1783,6 +1859,8 @@ pulls.status_checks_failure=Einige Prüfungen sind fehlgeschlagen pulls.status_checks_error=Einige Checks meldeten Fehler pulls.status_checks_requested=Erforderlich pulls.status_checks_details=Details +pulls.status_checks_hide_all=Alle Prüfungen ausblenden +pulls.status_checks_show_all=Alle Prüfungen anzeigen pulls.update_branch=Branch durch Mergen aktualisieren pulls.update_branch_rebase=Branch durch Rebase aktualisieren pulls.update_branch_success=Branch-Aktualisierung erfolgreich @@ -1791,6 +1869,11 @@ pulls.outdated_with_base_branch=Dieser Branch enthält nicht die neusten Commits pulls.close=Pull-Request schließen pulls.closed_at=`hat diesen Pull-Request <a id="%[1]s" href="#%[1]s">%[2]s</a> geschlossen` pulls.reopened_at=`hat diesen Pull-Request <a id="%[1]s" href="#%[1]s">%[2]s</a> wieder geöffnet` +pulls.cmd_instruction_hint=`Zeige <a class="show-instruction">Kommandozeilenanweisungen</a>.` +pulls.cmd_instruction_checkout_title=Checkout +pulls.cmd_instruction_checkout_desc=Wechsle auf einen neuen Branch in deinem lokalen Repository und teste die Änderungen. +pulls.cmd_instruction_merge_title=Mergen +pulls.cmd_instruction_merge_desc=Die Änderungen mergen und auf Gitea aktualisieren. pulls.clear_merge_message=Merge-Nachricht löschen pulls.clear_merge_message_hint=Das Löschen der Merge-Nachricht wird nur den Inhalt der Commit-Nachricht entfernen und generierte Git-Trailer wie "Co-Authored-By …" erhalten. @@ -1888,6 +1971,10 @@ wiki.page_name_desc=Gib einen Namen für diese Wiki-Seite ein. Spezielle Namen s wiki.original_git_entry_tooltip=Originale Git-Datei anstatt eines benutzerfreundlichen Links anzeigen. activity=Aktivität +activity.navbar.pulse=Puls +activity.navbar.code_frequency=Code-Frequenz +activity.navbar.contributors=Mitwirkende +activity.navbar.recent_commits=Neueste Commits activity.period.filter_label=Zeitraum: activity.period.daily=1 Tag activity.period.halfweekly=3 Tage @@ -1953,18 +2040,10 @@ activity.git_stats_and_deletions=und activity.git_stats_deletion_1=%d Löschung activity.git_stats_deletion_n=%d Löschungen +contributors.contribution_type.filter_label=Beitragstyp: contributors.contribution_type.commits=Commits - -search=Suchen -search.search_repo=Repository durchsuchen -search.type.tooltip=Suchmodus -search.fuzzy=Ähnlich -search.fuzzy.tooltip=Zeige auch Ergebnisse, die dem Suchbegriff ähneln -search.match=Genau -search.match.tooltip=Zeige nur Ergebnisse, die exakt mit dem Suchbegriff übereinstimmen -search.results=Suchergebnisse für „%s“ in <a href="%s"> %s</a> -search.code_no_results=Es konnte kein passender Code für deinen Suchbegriff gefunden werden. -search.code_search_unavailable=Derzeit ist die Code-Suche nicht verfügbar. Bitte wende dich an den Website-Administrator. +contributors.contribution_type.additions=Ergänzungen +contributors.contribution_type.deletions=Löschungen settings=Einstellungen settings.desc=In den Einstellungen kannst du die Einstellungen des Repositories anpassen @@ -1992,6 +2071,7 @@ settings.mirror_settings.docs.doc_link_title=Wie spiegele ich Repositories? settings.mirror_settings.docs.doc_link_pull_section=den Abschnitt "Von einem entfernten Repository pullen" in der Dokumentation. settings.mirror_settings.docs.pulling_remote_title=Aus einem Remote-Repository pullen settings.mirror_settings.mirrored_repository=Gespiegeltes Repository +settings.mirror_settings.pushed_repository=Gepushtes Repository settings.mirror_settings.direction=Richtung settings.mirror_settings.direction.pull=Pull settings.mirror_settings.direction.push=Push @@ -2013,6 +2093,8 @@ settings.branches.add_new_rule=Neue Regel hinzufügen settings.advanced_settings=Erweiterte Einstellungen settings.wiki_desc=Repository-Wiki aktivieren settings.use_internal_wiki=Eingebautes Wiki verwenden +settings.default_wiki_branch_name=Standardbezeichnung für Wiki-Branch +settings.failed_to_change_default_wiki_branch=Das Ändern des Standard-Wiki-Branches ist fehlgeschlagen. settings.use_external_wiki=Externes Wiki verwenden settings.external_wiki_url=Externe Wiki-URL settings.external_wiki_url_error=Die externe Wiki-URL ist ungültig. @@ -2043,6 +2125,10 @@ settings.pulls.default_allow_edits_from_maintainers=Änderungen von Maintainern settings.releases_desc=Repository-Releases aktivieren settings.packages_desc=Repository Packages Registry aktivieren settings.projects_desc=Repository-Projekte aktivieren +settings.projects_mode_desc=Projekte-Modus (welche Art Projekte angezeigt werden sollen) +settings.projects_mode_repo=Nur Repo-Projekte +settings.projects_mode_owner=Nur Benutzer- oder Organisations-Projekte +settings.projects_mode_all=Alle Projekte settings.actions_desc=Repository-Actions aktivieren settings.admin_settings=Administratoreinstellungen settings.admin_enable_health_check=Repository-Health-Checks aktivieren (git fsck) @@ -2068,6 +2154,7 @@ settings.convert_fork_succeed=Der Fork wurde in ein normales Repository konverti settings.transfer=Besitz übertragen settings.transfer.rejected=Repository-Übertragung wurde abgelehnt. settings.transfer.success=Repository-Übertragung war erfolgreich. +settings.transfer.blocked_user=Das Repository kann nicht übertragen werden, da du vom Repository-Eigentümer blockiert wurdest. settings.transfer_abort=Übertragung abbrechen settings.transfer_abort_invalid=Du kannst nur eingeleitete Repository-Übertragung abbrechen. settings.transfer_abort_success=Die Repository-Übertragung zu %s wurde abgebrochen. @@ -2113,11 +2200,11 @@ settings.add_collaborator_success=Der Mitarbeiter wurde hinzugefügt. settings.add_collaborator_inactive_user=Inaktive Benutzer können nicht als Mitarbeiter hinzufügt werden. settings.add_collaborator_owner=Besitzer können nicht als Mitarbeiter hinzugefügt werden. settings.add_collaborator_duplicate=Der Mitarbeiter ist bereits zu diesem Repository hinzugefügt. +settings.add_collaborator.blocked_user=Der Mitwirkende wurde vom Eigentümer des Repositories blockiert oder umgekehrt. settings.delete_collaborator=Entfernen settings.collaborator_deletion=Mitarbeiter entfernen settings.collaborator_deletion_desc=Nach dem Löschen wird dieser Mitarbeiter keinen Zugriff mehr auf dieses Repository haben. Fortfahren? settings.remove_collaborator_success=Der Mitarbeiter wurde entfernt. -settings.search_user_placeholder=Benutzer suchen… settings.org_not_allowed_to_be_collaborator=Organisationen können nicht als Mitarbeiter hinzugefügt werden. settings.change_team_access_not_allowed=Nur der Besitzer der Organisation kann die Zugangsrechte des Teams ändern settings.team_not_in_organization=Das Team ist nicht in der gleichen Organisation wie das Repository @@ -2125,7 +2212,6 @@ settings.teams=Teams settings.add_team=Team hinzufügen settings.add_team_duplicate=Das Team ist dem Repository schon zugeordnet settings.add_team_success=Das Team hat nun Zugriff auf das Repository. -settings.search_team=Team suchen… settings.change_team_permission_tip=Die Team-Berechtigung ist auf der Team-Einstellungsseite festgelegt und kann nicht für ein Repository geändert werden settings.delete_team_tip=Dieses Team hat Zugriff auf alle Repositories und kann nicht entfernt werden settings.remove_team_success=Der Zugriff des Teams auf das Repository wurde zurückgezogen. @@ -2278,9 +2364,7 @@ settings.protect_whitelist_committers=Schütze gewhitelistete Commiter settings.protect_whitelist_committers_desc=Jeder, der auf der Whitelist steht, darf in diesen Branch pushen (aber kein Force-Push). settings.protect_whitelist_deploy_keys=Deploy-Schlüssel mit Schreibzugriff zum Pushen whitelisten. settings.protect_whitelist_users=Nutzer, die pushen dürfen: -settings.protect_whitelist_search_users=Benutzer suchen… settings.protect_whitelist_teams=Teams, die pushen dürfen: -settings.protect_whitelist_search_teams=Teams suchen… settings.protect_merge_whitelist_committers=Merge-Whitelist aktivieren settings.protect_merge_whitelist_committers_desc=Erlaube Nutzern oder Teams auf der Whitelist Pull-Requests in diesen Branch zu mergen. settings.protect_merge_whitelist_users=Nutzer, die mergen dürfen: @@ -2301,9 +2385,12 @@ settings.protect_approvals_whitelist_users=Freigeschaltete Reviewer: settings.protect_approvals_whitelist_teams=Freigeschaltete Teams: settings.dismiss_stale_approvals=Entferne alte Genehmigungen settings.dismiss_stale_approvals_desc=Wenn neue Commits gepusht werden, die den Inhalt des Pull-Requests ändern, werden alte Genehmigungen entfernt. +settings.ignore_stale_approvals=Veraltete Genehmigungen ignorieren +settings.ignore_stale_approvals_desc=Genehmigungen, die für ältere Commits erteilt wurden (veraltete Genehmigungen), nicht bei der Anzahl an Genehmigungen mitzählen. Irrelevant, falls veraltete Genehmigungen bereits verworfen wurden. settings.require_signed_commits=Signierte Commits erforderlich settings.require_signed_commits_desc=Pushes auf diesen Branch ablehnen, wenn Commits nicht signiert oder nicht überprüfbar sind. settings.protect_branch_name_pattern=Muster für geschützte Branchnamen +settings.protect_branch_name_pattern_desc=Geschützte Branch-Namensmuster. Siehe <a href="https://github.com/gobwas/glob">die Dokumentation</a> für die Muster-Syntax. Beispiele: main, release/** settings.protect_patterns=Muster settings.protect_protected_file_patterns=Geschützte Dateimuster (durch Semikolon ';' getrennt): settings.protect_protected_file_patterns_desc=Geschützte Dateien dürfen nicht direkt geändert werden, auch wenn der Benutzer Rechte hat, Dateien in diesem Branch hinzuzufügen, zu bearbeiten oder zu löschen. Mehrere Muster können mit Semikolon (';') getrennt werden. Siehe <a href='https://pkg.go.dev/github.com/gobwas/glob#Compile'>github.com/gobwas/glob</a> Dokumentation zur Mustersyntax. Beispiele: <code>.drone.yml</code>, <code>/docs/**/*.txt</code>. @@ -2355,6 +2442,7 @@ settings.archive.error=Beim Versuch, das Repository zu archivieren, ist ein Fehl settings.archive.error_ismirror=Du kannst keinen Repo-Mirror archivieren. settings.archive.branchsettings_unavailable=Branch-Einstellungen sind nicht verfügbar wenn das Repo archiviert ist. settings.archive.tagsettings_unavailable=Tag Einstellungen sind nicht verfügbar, wenn das Repo archiviert wurde. +settings.archive.mirrors_unavailable=Mirrors sind nicht verfügbar, wenn das Repository archiviert ist. settings.unarchive.button=Archivieren rückgängig machen settings.unarchive.header=Archivieren dieses Repositories rückgängig machen settings.unarchive.text=Durch das Aufheben der Archivierung kann das Repo wieder Commits und Pushes sowie neue Issues und Pull-Requests empfangen. @@ -2521,7 +2609,6 @@ branch.default_deletion_failed=Branch "%s" kann nicht gelöscht werden, da diese branch.restore=Branch "%s" wiederherstellen branch.download=Branch "%s" herunterladen branch.rename=Branch "%s" umbenennen -branch.search=Branch suchen branch.included_desc=Dieser Branch ist im Standard-Branch enthalten branch.included=Enthalten branch.create_new_branch=Branch aus Branch erstellen: @@ -2552,8 +2639,16 @@ find_file.no_matching=Keine passende Datei gefunden error.csv.too_large=Diese Datei kann nicht gerendert werden, da sie zu groß ist. error.csv.unexpected=Diese Datei kann nicht gerendert werden, da sie ein unerwartetes Zeichen in Zeile %d und Spalte %d enthält. error.csv.invalid_field_count=Diese Datei kann nicht gerendert werden, da sie eine falsche Anzahl an Feldern in Zeile %d hat. +error.broken_git_hook=Git-Hooks dieses Repositories scheinen defekt zu sein. Bitte folge der <a target="_blank" rel="noreferrer" href="%s">Dokumentation</a>, um dies zu beheben, pushe dann ein paar Commits und den Status zu aktualisieren. [graphs] +component_loading=%s werden geladen ... +component_loading_failed=%s konnten nicht geladen werden +component_loading_info=Dies kann ein wenig dauern … +component_failed_to_load=Ein unerwarteter Fehler ist aufgetreten. +code_frequency.what=Code-Frequenz +contributors.what=Beiträge +recent_commits.what=Neueste Commits [org] org_name_holder=Name der Organisation @@ -2659,7 +2754,6 @@ teams.write_permission_desc=Dieses Team hat <strong>Schreibzugriff</strong>: Mit teams.admin_permission_desc=Dieses Team hat <strong>Adminzugriff</strong>: Mitglieder dieses Teams können Team-Repositories ansehen, auf sie pushen und Mitarbeiter hinzufügen. teams.create_repo_permission_desc=Zusätzlich erteilt dieses Team die Berechtigung <strong>Repository erstellen</strong>: Mitglieder können neue Repositories in der Organisation erstellen. teams.repositories=Team-Repositories -teams.search_repo_placeholder=Repository durchsuchen… teams.remove_all_repos_title=Alle Team-Repositories entfernen teams.remove_all_repos_desc=Dies entfernt alle Repositories von dem Team. teams.add_all_repos_title=Alle Repositories hinzufügen @@ -2668,6 +2762,7 @@ teams.add_nonexistent_repo=Das Repository, das du hinzufügen möchtest, existie teams.add_duplicate_users=Dieser Benutzer ist bereits ein Teammitglied. teams.repos.none=Dieses Team hat Zugang zu keinem Repository. teams.members.none=Keine Mitglieder in diesem Team. +teams.members.blocked_user=Der Benutzer kann nicht hinzugefügt werden, da er von der Organisation blockiert wurde. teams.specific_repositories=Bestimmte Repositories teams.specific_repositories_helper=Mitglieder haben nur Zugriff auf Repositories, die explizit dem Team hinzugefügt wurden. Wenn Du diese Option wählst, werden Repositories, die bereits mit <i>Alle Repositories</i> hinzugefügt wurden, <strong>nicht</strong> automatisch entfernt. teams.all_repositories=Alle Repositories @@ -2681,6 +2776,7 @@ teams.invite.description=Bitte klicke auf die folgende Schaltfläche, um dem Tea [admin] dashboard=Dashboard +self_check=Selbstprüfung identity_access=Identität & Zugriff users=Benutzerkonten organizations=Organisationen @@ -2691,6 +2787,8 @@ integrations=Integrationen authentication=Authentifizierungsquellen emails=Benutzer E-Mails config=Konfiguration +config_summary=Übersicht +config_settings=Einstellungen notices=Systemmitteilungen monitor=Monitoring first_page=Erste @@ -2726,6 +2824,7 @@ dashboard.delete_missing_repos=Alle Repository-Datensätze mit verloren gegangen dashboard.delete_missing_repos.started=Alle Repositories löschen, die den Git-File-Task nicht gestartet haben. dashboard.delete_generated_repository_avatars=Generierte Repository-Avatare löschen dashboard.sync_repo_branches=Fehlende Branches aus den Git-Daten in die Datenbank synchronisieren +dashboard.sync_repo_tags=Tags von Git-Daten in die Datenbank synchronisieren dashboard.update_mirrors=Mirrors aktualisieren dashboard.repo_health_check=Healthchecks für alle Repositories ausführen dashboard.check_repo_stats=Überprüfe alle Repository-Statistiken @@ -2780,6 +2879,7 @@ dashboard.stop_endless_tasks=Endlose Aufgaben stoppen dashboard.cancel_abandoned_jobs=Aufgegebene Jobs abbrechen dashboard.start_schedule_tasks=Terminierte Aufgaben starten dashboard.sync_branch.started=Synchronisierung der Branches gestartet +dashboard.sync_tag.started=Tag-Synchronisierung gestartet dashboard.rebuild_issue_indexer=Issue-Indexer neu bauen users.user_manage_panel=Benutzerkontenverwaltung @@ -2851,6 +2951,7 @@ emails.updated=E-Mail aktualisiert emails.not_updated=Fehler beim Aktualisieren der angeforderten E-Mail-Adresse: %v emails.duplicate_active=Diese E-Mail-Adresse wird bereits von einem Nutzer verwendet. emails.change_email_header=E-Mail-Eigenschaften aktualisieren +emails.change_email_text=Bist du dir sicher, dass du diese E-Mail-Adresse aktualisieren möchtest? orgs.org_manage_panel=Organisationsverwaltung orgs.name=Name @@ -2864,9 +2965,6 @@ repos.unadopted.no_more=Keine weiteren nicht übernommenen Repositories gefunden repos.owner=Besitzer repos.name=Name repos.private=Privat -repos.watches=Beobachtungen -repos.stars=Favoriten -repos.forks=Forks repos.issues=Issues repos.size=Größe repos.lfs_size=LFS-Größe @@ -2875,6 +2973,7 @@ packages.package_manage_panel=Paketverwaltung packages.total_size=Gesamtgröße: %s packages.unreferenced_size=Nicht referenzierte Größe: %s packages.cleanup=Veraltete Daten löschen +packages.cleanup.success=Abgelaufene Daten erfolgreich bereinigt packages.owner=Besitzer packages.creator=Ersteller packages.name=Name @@ -2990,7 +3089,7 @@ auths.tip.nextcloud=Registriere über das "Settings -> Security -> OAuth 2.0 cli auths.tip.dropbox=Erstelle eine neue App auf https://www.dropbox.com/developers/apps. auths.tip.facebook=Erstelle eine neue Anwendung auf https://developers.facebook.com/apps und füge das Produkt „Facebook Login“ hinzu. 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_new=Erstelle eine neue Anwendung unter https://gitlab.com/-/profile/applications auths.tip.google_plus=Du erhältst die OAuth2-Client-Zugangsdaten in der Google-API-Konsole unter https://console.developers.google.com/ auths.tip.openid_connect=Benutze die OpenID-Connect-Discovery-URL (<server>/.well-known/openid-configuration), um die Endpunkte zu spezifizieren auths.tip.twitter=Gehe auf https://dev.twitter.com/apps, erstelle eine Anwendung und stelle sicher, dass die Option „Allow this application to be used to Sign in with Twitter“ aktiviert ist @@ -3126,6 +3225,7 @@ config.picture_config=Bild-und-Profilbild-Konfiguration config.picture_service=Bilderservice config.disable_gravatar=Gravatar deaktivieren config.enable_federated_avatar=Föderierte Profilbilder einschalten +config.open_with_editor_app_help=Die „Öffnen mit“-Editoren für das Klon-Menü. Falls leer, wird die Standardeinstellung verwendet. Erweitern, um die Standardeinstellung zu sehen. config.git_config=Git-Konfiguration config.git_disable_diff_highlight=Diff-Syntaxhervorhebung ausschalten @@ -3204,6 +3304,12 @@ notices.desc=Beschreibung notices.op=Aktion notices.delete_success=Diese Systemmeldung wurde gelöscht. +self_check.no_problem_found=Bisher wurde kein Problem festgestellt. +self_check.database_collation_mismatch=Erwarte Datenbank-Kollation: %s +self_check.database_collation_case_insensitive=Die Datenbank verwendet die Kollation %s, was eine unsensible Kollation ist. Obwohl Gitea damit arbeiten könnte, gibt es vielleicht einige seltene Fälle, die nicht wie erwartet funktionieren. +self_check.database_inconsistent_collation_columns=Die Datenbank verwendet die Kollation %s, aber diese Spalten verwenden unzutreffende Kollationen. Dies könnte zu unerwarteten Problemen führen. +self_check.database_fix_mysql=Für MySQL/MariaDB-Benutzer kann man den Befehl "gitea doctor convert" oder manuell auch "ALTER ... COLLATE ..."-SQLs verwenden, um die Sortierprobleme zu beheben. +self_check.database_fix_mssql=Für MSSQL-Benutzer kann das Problem im Moment nur durch "ALTER ... COLLATE ..." SQLs manuell behoben werden. [action] create_repo=hat das Repository <a href="%s">%s</a> erstellt @@ -3391,6 +3497,7 @@ rpm.distros.suse=auf SUSE-basierten Distributionen rpm.install=Nutze folgenden Befehl, um das Paket zu installieren: rpm.repository=Repository-Informationen rpm.repository.architectures=Architekturen +rpm.repository.multiple_groups=Dieses Paket ist in mehreren Gruppen verfügbar. rubygems.install=Um das Paket mit gem zu installieren, führe den folgenden Befehl aus: rubygems.install2=oder füg es zum Gemfile hinzu: rubygems.dependencies.runtime=Laufzeitabhängigkeiten @@ -3516,12 +3623,18 @@ runs.commit=Commit runs.scheduled=Geplant runs.pushed_by=gepusht von runs.invalid_workflow_helper=Die Workflow-Konfigurationsdatei ist ungültig. Bitte überprüfe Deine Konfigurationsdatei: %s +runs.no_matching_online_runner_helper=Kein passender Runner online mit Label: %s +runs.no_job_without_needs=Der Workflow muss mindestens einen Job ohne Abhängigkeiten enthalten. runs.actor=Initiator runs.status=Status runs.actors_no_select=Alle Initiatoren runs.status_no_select=Alle Status runs.no_results=Keine passenden Ergebnisse gefunden. +runs.no_workflows=Es gibt noch keine Workflows. +runs.no_workflows.quick_start=Du weißt nicht, wie du mit Gitea Actions loslegst? Siehe <a target="_blank" rel="noopener noreferrer" href="%s">die Schnellstart-Anleitung</a>. +runs.no_workflows.documentation=Weitere Informationen zu Gitea Actions findest du in der <a target="_blank" rel="noopener noreferrer" href="%s"> Dokumentation</a>. runs.no_runs=Der Workflow hat noch keine Ausführungen. +runs.empty_commit_message=(leere Commit-Nachricht) workflow.disable=Workflow deaktivieren workflow.disable_success=Workflow '%s' erfolgreich deaktiviert. @@ -3538,6 +3651,7 @@ variables.none=Es gibt noch keine Variablen. variables.deletion=Variable entfernen variables.deletion.description=Das Entfernen einer Variable ist dauerhaft und kann nicht rückgängig gemacht werden. Fortfahren? variables.description=Variablen werden an bestimmte Aktionen übergeben und können nicht anderweitig gelesen werden. +variables.id_not_exist=Eine Variable mit ID %d existiert nicht. variables.edit=Variable bearbeiten variables.deletion.failed=Fehler beim Entfernen der Variable. variables.deletion.success=Die Variable wurde entfernt. diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini index 2662a49cea..1199d84581 100644 --- a/options/locale/locale_el-GR.ini +++ b/options/locale/locale_el-GR.ini @@ -141,6 +141,15 @@ confirm_delete_selected=Επιβεβαιώνετε τη διαγραφή όλω name=Όνομα value=Τιμή +filter=Φίλτρο +filter.is_archived=Αρχειοθετήθηκε +filter.is_template=Πρότυπο +filter.public=Δημόσιος +filter.private=Ιδιωτικό + + +[search] + [aria] navbar=Γραμμή Πλοήγησης footer=Υποσέλιδο @@ -314,7 +323,6 @@ collaborative_repos=Συνεργατικά Αποθετήρια my_orgs=Οι Οργανισμοί Μου my_mirrors=Τα Αντίγραφα Μου view_home=Προβολή %s -search_repos=Βρείτε ένα αποθετήριο… filter=Άλλα Φίλτρα filter_by_team_repositories=Φιλτράρισμα ανά αποθετήρια ομάδας feed_of=`Τροφοδοσία του "%s"` @@ -335,20 +343,8 @@ issues.in_your_repos=Στα αποθετήρια σας repos=Αποθετήρια users=Χρήστες organizations=Οργανισμοί -search=Αναζήτηση go_to=Μετάβαση σε code=Κώδικας -search.type.tooltip=Τύπος αναζήτησης -search.fuzzy=Fuzzy -search.fuzzy.tooltip=Συμπερίληψη και των αποτελεσμάτων που είναι πλησιέστερα με τον όρο αναζήτησης -search.match=Ταίριασμα -search.match.tooltip=Συμπερίληψη μόνο των αποτελεσμάτων που ταιριάζουν ακριβώς με τον όρο αναζήτησης -code_search_unavailable=Η αναζήτηση κώδικα δεν είναι διαθέσιμη αυτή τη στιγμή. Παρακαλώ επικοινωνήστε με το διαχειριστή. -repo_no_results=Δεν βρέθηκαν αποθετήρια που να ταιρίαζουν με τα κριτήρια. -user_no_results=Δεν βρέθηκαν χρήστες που να ταιριάζουν με τα κριτήρια. -org_no_results=Δεν βρέθηκαν οργανισμοί που να ταιριάζουν με τα κριτήρια. -code_no_results=Δεν βρέθηκε πηγαίος κώδικας που να ταιριάζει με τον όρο αναζήτησης. -code_search_results=`Αποτελέσματα αναζήτησης για "%s"` code_last_indexed_at=Τελευταίο δημιουργία ευρετηρίου στις %s relevant_repositories_tooltip=Τα αποθετήρια που είναι forks ή που δεν έχουν θέμα, εικονίδιο και περιγραφή είναι κρυμμένα. relevant_repositories=Εμφανίζονται μόνο τα σχετικά αποθετήρια, <a href="%s">εμφάνιση χωρίς φίλτρο</a>. @@ -366,7 +362,6 @@ forgot_password_title=Ξέχασα Τον Κωδικό Πρόσβασης forgot_password=Ξεχάσατε τον κωδικό πρόσβασης; sign_up_now=Χρειάζεστε λογαριασμό; Εγγραφείτε τώρα. sign_up_successful=Ο λογαριασμός δημιουργήθηκε επιτυχώς. Καλώς ορίσατε! -confirmation_mail_sent_prompt=Ένα νέο email επιβεβαίωσης έχει σταλεί στο <b>%s</b>. Παρακαλώ ελέγξτε τα εισερχόμενα σας μέσα στις επόμενες %s για να ολοκληρώσετε τη διαδικασία εγγραφής. must_change_password=Ενημερώστε τον κωδικό πρόσβασης σας allow_password_change=Απαιτείται από το χρήστη να αλλάξει τον κωδικό πρόσβασης (συνιστόμενο) reset_password_mail_sent_prompt=Ένα email επιβεβαίωσης έχει σταλεί στο <b>%s</b>. Παρακαλώ ελέγξτε τα εισερχόμενα σας στις επόμενες %s για να ολοκληρώσετε τη διαδικασία ανάκτησης λογαριασμού. @@ -614,6 +609,7 @@ form.name_reserved=Το όνομα χρήστη "%s" είναι δεσμευμέ form.name_pattern_not_allowed=Το μοτίβο "%s" δεν επιτρέπεται μέσα σε ένα όνομα χρήστη. form.name_chars_not_allowed=Το όνομα χρήστη "%s" περιέχει μη έγκυρους χαρακτήρες. + [settings] profile=Προφίλ account=Λογαριασμός @@ -758,7 +754,6 @@ gpg_invalid_token_signature=Το κλειδί GPG, η υπογραφή και τ gpg_token_required=Πρέπει να δώσετε μια υπογραφή για το παρακάτω διακριτικό gpg_token=Διακριτικό gpg_token_help=Μπορείτε να δημιουργήσετε μια υπογραφή χρησιμοποιώντας: -gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig gpg_token_signature=Θωρακισμένη υπογραφή GPG key_signature_gpg_placeholder=Ξεκινά με '-----BEGIN PGP SIGNATURE-----' verify_gpg_key_success=Το κλειδί GPG "%s" επαληθεύτηκε. @@ -952,7 +947,6 @@ fork_branch=Κλάδος που θα κλωνοποιηθεί στο fork all_branches=Όλοι οι κλάδοι fork_no_valid_owners=Αυτό το αποθετήριο δεν μπορεί να γίνει fork επειδή δεν υπάρχουν έγκυροι ιδιοκτήτες. use_template=Χρήση αυτού του πρότυπου -clone_in_vsc=Κλωνοποίηση στο VS Code download_zip=Λήψη ZIP download_tar=Λήψη TAR.GZ download_bundle=Κατεβάστε Το ΔΕΜΑ @@ -1271,9 +1265,7 @@ commits.desc=Δείτε το ιστορικό αλλαγών του πηγαίο commits.commits=Υποβολές commits.no_commits=Δεν υπάρχουν κοινές υποβολές. Τα "%s" και "%s" έχουν εντελώς διαφορετικές ιστορίες. commits.nothing_to_compare=Αυτοί οι κλάδοι είναι όμοιοι. -commits.search=Αναζήτηση υποβολών… commits.search.tooltip=Μπορείτε να προθέτετε τις λέξεις-κλειδιά με "author:", "committer:", "after:", ή "before:", π.χ. "επαναφορά author:Alice before:2019-01-13". -commits.find=Αναζήτηση commits.search_all=Όλοι Οι Κλάδοι commits.author=Συγγραφέας commits.message=Μήνυμα @@ -1324,7 +1316,6 @@ projects.type.basic_kanban=Βασικό Kanban projects.type.bug_triage=Διαλογή Σφαλμάτων projects.template.desc=Πρότυπο έργου projects.template.desc_helper=Επιλέξτε ένα πρότυπο έργου για να ξεκινήσετε -projects.type.uncategorized=Χωρίς Κατηγορία projects.column.edit=Επεξεργασία Στήλης projects.column.edit_title=Όνομα projects.column.new_title=Όνομα @@ -1332,10 +1323,7 @@ projects.column.new_submit=Δημιουργία Στήλης projects.column.new=Νέα Στήλη projects.column.set_default=Ορισμός Προεπιλογής projects.column.set_default_desc=Ορίστε αυτή τη στήλη ως προεπιλογή για ζητήματα και pull requests χωρίς κατηγορία -projects.column.unset_default=Αφαίρεση Προεπιλογής -projects.column.unset_default_desc=Αφαίρεση της προεπιλογής αυτής της στήλης projects.column.delete=Διαγραφή Στήλης -projects.column.deletion_desc=Η διαγραφή μιας στήλης έργου μετακινεί όλα τα συναφή ζητήματα σε 'Χωρίς Κατηγορία'. Συνέχεια; projects.column.color=Έγχρωμο projects.open=Άνοιγμα projects.close=Κλείσιμο @@ -1447,7 +1435,6 @@ issues.filter_sort.moststars=Περισσότερα αστέρια issues.filter_sort.feweststars=Λιγότερα αστέρια issues.filter_sort.mostforks=Περισσότερα forks issues.filter_sort.fewestforks=Λιγότερα forks -issues.keyword_search_unavailable=Η αναζήτηση μέσω λέξεων κλειδιών δεν είναι διαθέσιμη. Παρακαλώ επικοινωνήστε με το διαχειριστή. issues.action_open=Άνοιγμα issues.action_close=Κλείσιμο issues.action_label=Σήμα @@ -1699,7 +1686,6 @@ pulls.compare_compare=τράβηγμα από pulls.switch_comparison_type=Αλλαγή τύπου σύγκρισης pulls.switch_head_and_base=Αλλαγή κεφαλής και βάσης pulls.filter_branch=Φιλτράρισμα κλάδου -pulls.no_results=Δεν βρέθηκαν αποτελέσματα. pulls.show_all_commits=Εμφάνιση όλων των υποβολών pulls.show_changes_since_your_last_review=Εμφάνιση αλλαγών από την τελευταία αξιολόγηση pulls.showing_only_single_commit=Εμφάνιση μόνο αλλαγών της υποβολής %[1]s @@ -1969,17 +1955,6 @@ activity.git_stats_deletion_n=%d διαγραφές contributors.contribution_type.commits=Υποβολές -search=Αναζήτηση -search.search_repo=Αναζήτηση αποθετηρίου -search.type.tooltip=Τύπος αναζήτησης -search.fuzzy=Fuzzy -search.fuzzy.tooltip=Συμπερίληψη και των αποτελεσμάτων που είναι πλησιέστερα με τον όρο αναζήτησης -search.match=Ταίριασμα -search.match.tooltip=Συμπερίληψη μόνο των αποτελεσμάτων που ταιριάζουν ακριβώς με τον όρο αναζήτησης -search.results=Αποτελέσματα αναζήτησης για "%s" σε <a href="%s">%s</a> -search.code_no_results=Δεν βρέθηκε πηγαίος κώδικας που να ταιριάζει με τον όρο αναζήτησης. -search.code_search_unavailable=Η αναζήτηση κώδικα δεν είναι διαθέσιμη αυτή τη στιγμή. Παρακαλώ επικοινωνήστε με το διαχειριστή. - settings=Ρυθμίσεις settings.desc=Στις Ρυθμίσεις μπορείτε να διαχειριστείτε τις ρυθμίσεις για το αποθετήριο settings.options=Αποθετήριο @@ -2057,6 +2032,7 @@ settings.pulls.default_allow_edits_from_maintainers=Να επιτρέποντα settings.releases_desc=Ενεργοποίηση Κυκλοφοριών Αποθετηρίου settings.packages_desc=Ενεργοποίηση Μητρώου Πακέτων Αποθετηρίου settings.projects_desc=Ενεργοποίηση Έργων Αποθετηρίου +settings.projects_mode_all=Όλα τα έργα settings.actions_desc=Ενεργοποίηση Δράσεων Αποθετηρίου settings.admin_settings=Ρυθμίσεις Διαχειριστή settings.admin_enable_health_check=Ενεργοποίηση Ελέγχων Υγείας του Αποθετηρίου (git fsck) @@ -2131,7 +2107,6 @@ settings.delete_collaborator=Αφαίρεση settings.collaborator_deletion=Αφαίρεση Συνεργάτη settings.collaborator_deletion_desc=Η κατάργηση ενός συνεργάτη θα ανακαλέσει την πρόσβασή τους σε αυτό το αποθετήριο. Συνέχεια; settings.remove_collaborator_success=Ο συνεργάτης έχει αφαιρεθεί. -settings.search_user_placeholder=Αναζήτηση χρήστη… settings.org_not_allowed_to_be_collaborator=Οι οργανισμοί δεν μπορούν να προστεθούν ως συνεργάτης. settings.change_team_access_not_allowed=Η αλλαγή της πρόσβασης ομάδας για το αποθετήριο έχει περιοριστεί στον ιδιοκτήτη του οργανισμού settings.team_not_in_organization=Η ομάδα δεν είναι στον ίδιο οργανισμό με το αποθετήριο @@ -2139,7 +2114,6 @@ settings.teams=Ομάδες settings.add_team=Προσθήκη Ομάδας settings.add_team_duplicate=Η ομάδα έχει ήδη το αποθετήριο settings.add_team_success=Η ομάδα έχει πλέον πρόσβαση στο αποθετήριο. -settings.search_team=Αναζήτηση Ομάδας… settings.change_team_permission_tip=Τα δικαιώματα της ομάδας έχουν οριστεί στη σελίδα ρυθμίσεων της ομάδας και δεν μπορούν να αλλάξουν ανά αποθετήριο settings.delete_team_tip=Αυτή η ομάδα έχει πρόσβαση σε όλα τα αποθετήρια και δεν μπορεί να αφαιρεθεί settings.remove_team_success=Έχει αφαιρεθεί η πρόσβαση της ομάδας στο αποθετήριο. @@ -2292,9 +2266,7 @@ settings.protect_whitelist_committers=Περιορισμός του Push στη settings.protect_whitelist_committers_desc=Μόνο χρήστες ή ομάδες στη λίστα θα επιτρέπεται να κάνουν push σε αυτόν τον κλάδο (αλλά όχι να κάνουν force push). settings.protect_whitelist_deploy_keys=Έγκριση κλειδιών διάθεσης με πρόσβαση εγγραφής για ώθηση. settings.protect_whitelist_users=Λίστα χρηστών που επιτρέπεται να κάνουν push: -settings.protect_whitelist_search_users=Αναζήτηση χρηστών… settings.protect_whitelist_teams=Λίστα ομάδων που επιτρέπεται να κάνουν push: -settings.protect_whitelist_search_teams=Αναζήτηση ομάδων… settings.protect_merge_whitelist_committers=Ενεργοποίηση Λίστας Συγχώνευσης settings.protect_merge_whitelist_committers_desc=Επιτρέψτε μόνο σε χρήστες ή ομάδες στη λίστα να συγχωνεύσουν pull requests σε αυτό το κλάδο. settings.protect_merge_whitelist_users=Λίστα επιτρεπόμενων χρηστών για συγχώνευση: @@ -2536,7 +2508,6 @@ branch.default_deletion_failed=Ο κλάδος "%s" είναι ο προεπιλ branch.restore=`Επαναφορά του Κλάδου "%s"` branch.download=`Λήψη του Κλάδου "%s"` branch.rename=`Μετονομασία Κλάδου "%s"` -branch.search=Αναζήτηση Κλάδου branch.included_desc=Αυτός ο κλάδος είναι μέρος του προεπιλεγμένου κλάδου branch.included=Περιλαμβάνεται branch.create_new_branch=Δημιουργία κλάδου από κλάδο: @@ -2674,7 +2645,6 @@ teams.write_permission_desc=Αυτή η ομάδα χορηγεί πρόσβασ teams.admin_permission_desc=Αυτή η ομάδα παρέχει πρόσβαση <strong>Διαχειριστή</strong>: τα μέλη μπορούν να διαβάσουν, να κάνουν push και να προσθέσουν συνεργάτες στα αποθετήρια της ομάδας. teams.create_repo_permission_desc=Επιπλέον, αυτή η ομάδα χορηγεί άδεια <strong>Δημιουργία αποθετηρίου</strong>: τα μέλη μπορούν να δημιουργήσουν νέα αποθετήρια στον οργανισμό. teams.repositories=Αποθετήρια Ομάδας -teams.search_repo_placeholder=Αναζήτηση αποθετηρίου… teams.remove_all_repos_title=Αφαίρεση όλων των αποθετηρίων της ομάδας teams.remove_all_repos_desc=Αυτό θα αφαιρέσει όλα τα αποθετήρια από την ομάδα. teams.add_all_repos_title=Προσθήκη όλων των αποθετηρίων @@ -2706,6 +2676,8 @@ integrations=Ενσωματώσεις authentication=Πηγές Ταυτοποίησης emails=Email Χρήστη config=Διαμόρφωση +config_summary=Περίληψη +config_settings=Ρυθμίσεις notices=Ειδοποιήσεις Συστήματος monitor=Παρακολούθηση first_page=Πρώτο @@ -2880,9 +2852,6 @@ repos.unadopted.no_more=Δεν βρέθηκαν μη υιοθετημένα απ repos.owner=Ιδιοκτήτης repos.name=Όνομα repos.private=Ιδιωτικό -repos.watches=Παρακολουθήσεις -repos.stars=Αστέρια -repos.forks=Forks repos.issues=Ζητήματα repos.size=Μέγεθος repos.lfs_size=Μέγεθος LFS @@ -3007,7 +2976,6 @@ auths.tip.nextcloud=`Καταχωρήστε ένα νέο καταναλωτή O 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.google_plus=Αποκτήστε τα διαπιστευτήρια πελάτη OAuth2 από την κονσόλα API της Google στο https://console.developers.google.com/ auths.tip.openid_connect=Χρησιμοποιήστε το OpenID Connect Discovery URL (<server>/.well known/openid-configuration) για να καθορίσετε τα τελικά σημεία auths.tip.twitter=Πηγαίνετε στο https://dev.twitter.com/apps, δημιουργήστε μια εφαρμογή και βεβαιωθείτε ότι η επιλογή “Allow this application to be used to Sign in with Twitter” είναι ενεργοποιημένη diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index c013927157..ce50b71ec4 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -139,6 +139,15 @@ confirm_delete_selected=¿Borrar todos los elementos seleccionados? name=Nombre value=Valor +filter=Filtro +filter.is_archived=Archivado +filter.is_template=Plantilla +filter.public=Público +filter.private=Privado + + +[search] + [aria] navbar=Barra de navegación footer=Pie @@ -312,7 +321,6 @@ collaborative_repos=Repositorios colaborativos my_orgs=Mis organizaciones my_mirrors=Mis réplicas view_home=Ver %s -search_repos=Buscar un repositorio… filter=Otros filtros filter_by_team_repositories=Filtrar por repositorios de equipo feed_of=`Suministro de noticias de "%s"` @@ -333,20 +341,8 @@ issues.in_your_repos=En tus repositorios repos=Repositorios users=Usuarios organizations=Organizaciones -search=Buscar go_to=Ir a code=Código -search.type.tooltip=Tipo de búsqueda -search.fuzzy=Parcial -search.fuzzy.tooltip=Incluye los resultados que también coincidan con el término de búsqueda -search.match=Coincidir -search.match.tooltip=Incluye sólo los resultados que coincidan con el término de búsqueda exacto -code_search_unavailable=Actualmente la búsqueda de código no está disponible. Póngase en contacto con el administrador de su sitio. -repo_no_results=No se ha encontrado ningún repositorio coincidente. -user_no_results=No se ha encontrado ningún usuario coincidente. -org_no_results=No se ha encontrado ninguna organización coincidente. -code_no_results=No se ha encontrado código de fuente que coincida con su término de búsqueda. -code_search_results=Resultados de búsqueda para «%s» code_last_indexed_at=Indexado por última vez %s relevant_repositories_tooltip=Repositorios que son bifurcaciones o que no tienen ningún tema, ningún icono, y ninguna descripción están ocultos. relevant_repositories=Solo se muestran repositorios relevantes, <a href="%s">mostrar resultados sin filtrar</a>. @@ -363,7 +359,6 @@ forgot_password_title=He olvidado mi contraseña forgot_password=¿Has olvidado tu contraseña? sign_up_now=¿Necesitas una cuenta? Regístrate ahora. sign_up_successful=La cuenta se ha creado correctamente. ¡Bienvenido! -confirmation_mail_sent_prompt=Un nuevo correo de confirmación se ha enviado a <b>%s</b>. Comprueba tu bandeja de entrada en las siguientes %s para completar el registro. must_change_password=Actualizar su contraseña allow_password_change=Obligar al usuario a cambiar la contraseña (recomendado) reset_password_mail_sent_prompt=Un correo de confirmación se ha enviado a <b>%s</b>. Compruebe su bandeja de entrada en las siguientes %s para completar el proceso de recuperación de la cuenta. @@ -611,6 +606,7 @@ form.name_reserved=El nombre de usuario "%s" está reservado. form.name_pattern_not_allowed=El patrón "%s" no está permitido en un nombre de usuario. form.name_chars_not_allowed=El nombre de usuario "%s" contiene caracteres no válidos. + [settings] profile=Perfil account=Cuenta @@ -755,7 +751,6 @@ gpg_invalid_token_signature=La clave GPG proporcionada, la firma y el token no c gpg_token_required=Debe proporcionar una firma para el token de abajo gpg_token=Token gpg_token_help=Puede generar una firma de la siguiente manera: -gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig gpg_token_signature=Firma GPG armadura key_signature_gpg_placeholder=Comienza con '-----BEGIN PGP SIGNATURE-----' verify_gpg_key_success=La clave GPG "%s" ha sido verificada. @@ -945,7 +940,6 @@ fork_branch=Rama a clonar en la bifurcación all_branches=Todas las ramas fork_no_valid_owners=Este repositorio no puede ser bifurcado porque no hay propietarios válidos. use_template=Utilizar esta plantilla -clone_in_vsc=Clonar en VS Code download_zip=Descargar ZIP download_tar=Descargar TAR.GZ download_bundle=Descargar BUNDLE @@ -1264,9 +1258,7 @@ commits.desc=Ver el historial de cambios de código fuente. commits.commits=Commits commits.no_commits=No hay commits en común. "%s" y "%s" tienen historias totalmente diferentes. commits.nothing_to_compare=Estas ramas son iguales. -commits.search=Buscar commits… commits.search.tooltip=Puede prefijar palabras clave con "author:", "committer:", "after:", o "before:", p. ej., "revertir author:Alice before:2019-01-13". -commits.find=Buscar commits.search_all=Todas las Ramas commits.author=Autor commits.message=Mensaje @@ -1317,7 +1309,6 @@ projects.type.basic_kanban=Kanban básico projects.type.bug_triage=Prueba de error projects.template.desc=Plantilla del proyecto projects.template.desc_helper=Seleccione una plantilla de proyecto para empezar -projects.type.uncategorized=Sin categorizar projects.column.edit=Editar columna projects.column.edit_title=Nombre projects.column.new_title=Nombre @@ -1325,10 +1316,7 @@ projects.column.new_submit=Crear columna projects.column.new=Nueva columna projects.column.set_default=Establecer como predeterminado projects.column.set_default_desc=Establecer esta columna como predeterminada para incidencias no categorizadas y pulls -projects.column.unset_default=Anular valor predeterminado -projects.column.unset_default_desc=Anular esta columna como la predeterminada projects.column.delete=Borrar columna -projects.column.deletion_desc=Eliminar una columna del proyecto mueve todos los problemas relacionados a 'Sin categorizar'. ¿Continuar? projects.column.color=Color projects.open=Abrir projects.close=Cerrar @@ -1440,7 +1428,6 @@ issues.filter_sort.moststars=Mas estrellas issues.filter_sort.feweststars=Menor número de estrellas issues.filter_sort.mostforks=La mayoría de forks issues.filter_sort.fewestforks=Menor número de forks -issues.keyword_search_unavailable=La búsqueda por palabra clave no está disponible actualmente. Por favor, contacte con el administrador de su sitio. issues.action_open=Abrir issues.action_close=Cerrar issues.action_label=Etiqueta @@ -1692,7 +1679,6 @@ pulls.compare_compare=recuperar de pulls.switch_comparison_type=Cambiar tipo de comparación pulls.switch_head_and_base=Intercambiar cabeza y base pulls.filter_branch=Filtrar rama -pulls.no_results=Sin resultados. pulls.show_all_commits=Mostrar todos los commits pulls.show_changes_since_your_last_review=Mostrar cambios desde tu última revisión pulls.showing_only_single_commit=Mostrando solo los cambios del commit %[1]s @@ -1955,17 +1941,6 @@ activity.git_stats_deletion_n=%d eliminaciones contributors.contribution_type.commits=Commits -search=Buscar -search.search_repo=Buscar repositorio -search.type.tooltip=Tipo de búsqueda -search.fuzzy=Parcial -search.fuzzy.tooltip=Incluye los resultados que también coinciden aproximadamente con el término de búsqueda -search.match=Coincidir -search.match.tooltip=Incluye sólo los resultados que coincidan con el término de búsqueda exacto -search.results=Resultados de la búsqueda para "%s" en <a href="%s">%s</a> -search.code_no_results=No se ha encontrado código de fuente que coincida con su término de búsqueda. -search.code_search_unavailable=Actualmente la búsqueda de código no está disponible. Póngase en contacto con el administrador de su sitio. - settings=Configuración settings.desc=La configuración es donde puede administrar la configuración del repositorio settings.options=Repositorio @@ -2043,6 +2018,7 @@ settings.pulls.default_allow_edits_from_maintainers=Permitir ediciones de manten settings.releases_desc=Activar lanzamientos del repositorio settings.packages_desc=Habilitar registro de paquetes de repositorio settings.projects_desc=Activar Proyectos de Repositorio +settings.projects_mode_all=Todos los proyectos settings.actions_desc=Activar Acciones del repositorio settings.admin_settings=Ajustes de administrador settings.admin_enable_health_check=Activar cheques de estado de salud del repositorio (git fsck) @@ -2117,7 +2093,6 @@ settings.delete_collaborator=Eliminar settings.collaborator_deletion=Eliminar colaborador settings.collaborator_deletion_desc=Eliminar un colaborador revocará su acceso a este repositorio. ¿Continuar? settings.remove_collaborator_success=El colaborador ha sido eliminado. -settings.search_user_placeholder=Buscar usuario… settings.org_not_allowed_to_be_collaborator=Las organizaciones no pueden ser añadidas como colaboradoras. settings.change_team_access_not_allowed=Cambiar el acceso del equipo al repositorio se ha restringido al propietario de la organización settings.team_not_in_organization=El equipo no pertenece a la misma organización que el repositorio @@ -2125,7 +2100,6 @@ settings.teams=Equipos settings.add_team=Añadir equipo settings.add_team_duplicate=El equipo ya tiene acceso al repositorio settings.add_team_success=Ahora el equipo ya tiene acceso al repositorio. -settings.search_team=Buscar equipos… settings.change_team_permission_tip=El permiso del equipo está establecido en la página de configuración del equipo y no puede ser cambiado por repositorio settings.delete_team_tip=Este equipo tiene acceso a todos los repositorios y no puede ser eliminado settings.remove_team_success=Se ha eliminado el acceso del equipo al repositorio. @@ -2278,9 +2252,7 @@ settings.protect_whitelist_committers=Hacer push restringido a la lista blanca settings.protect_whitelist_committers_desc=Sólo se permitirá a los usuarios o equipos de la lista blanca hacer push a esta rama (pero no forzar push). settings.protect_whitelist_deploy_keys=Lista blanca de claves de despliegue con acceso de escritura a push. settings.protect_whitelist_users=Usuarios en la lista blanca para hacer push: -settings.protect_whitelist_search_users=Buscar usuarios… settings.protect_whitelist_teams=Equipos en la lista blanca para hacer push: -settings.protect_whitelist_search_teams=Buscar equipos… settings.protect_merge_whitelist_committers=Activar lista blanca para fusionar settings.protect_merge_whitelist_committers_desc=Permitir a los usuarios o equipos de la lista a fusionar peticiones pull dentro de esta rama. settings.protect_merge_whitelist_users=Usuarios en la lista blanca para fusionar: @@ -2521,7 +2493,6 @@ branch.default_deletion_failed=La rama "%s" es la rama por defecto. No se puede branch.restore=`Restaurar rama "%s"` branch.download=`Descargar rama "%s"` branch.rename=`Renombrar rama "%s"` -branch.search=Buscar rama branch.included_desc=Esta rama forma parte de la predeterminada branch.included=Incluida branch.create_new_branch=Crear rama desde la rama: @@ -2659,7 +2630,6 @@ teams.write_permission_desc=Este equipo tiene permisos de <strong>Escritura</str teams.admin_permission_desc=Este equipo tiene permisos de <strong>Administración</strong>: los miembros pueden ver, hacer push y añadir colaboradores a los repositorios del equipo. teams.create_repo_permission_desc=Adicionalmente, este equipo concede permiso <strong>Crear repositorio</strong>: los miembros pueden crear nuevos repositorios en la organización. teams.repositories=Repositorios del equipo -teams.search_repo_placeholder=Buscar repositorio… teams.remove_all_repos_title=Eliminar todos los repositorios del equipo teams.remove_all_repos_desc=Esto eliminará todos los repositorios del equipo. teams.add_all_repos_title=Añadir todos los repositorios @@ -2691,6 +2661,8 @@ integrations=Integraciones authentication=Orígenes de autenticación emails=Correos de usuario config=Configuración +config_summary=Resumen +config_settings=Configuración notices=Notificaciones del sistema monitor=Monitorización first_page=Primera @@ -2864,9 +2836,6 @@ repos.unadopted.no_more=No se encontraron más repositorios no adoptados repos.owner=Propietario repos.name=Nombre repos.private=Privado -repos.watches=Vigilantes -repos.stars=Estrellas -repos.forks=Forks repos.issues=Incidencias repos.size=Tamaño repos.lfs_size=Tamaño LFS @@ -2990,7 +2959,6 @@ auths.tip.nextcloud=`Registre un nuevo consumidor OAuth en su instancia usando e auths.tip.dropbox=Crear nueva aplicación en https://www.dropbox.com/developers/apps auths.tip.facebook=`Registre una nueva aplicación en https://developers.facebook.com/apps y agregue el producto "Facebook Login"` auths.tip.github=Registre una nueva aplicación OAuth en https://github.com/settings/applications/new -auths.tip.gitlab=Registrar nueva solicitud en https://gitlab.com/profile/applications auths.tip.google_plus=Obtener credenciales de cliente OAuth2 desde la consola API de Google en https://console.developers.google.com/ auths.tip.openid_connect=Use el OpenID Connect Discovery URL (<server>/.well-known/openid-configuration) para especificar los puntos finales auths.tip.twitter=Ir a https://dev.twitter.com/apps, crear una aplicación y asegurarse de que la opción "Permitir que esta aplicación sea usada para iniciar sesión con Twitter" está activada diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini index d2db7a20e9..31122841a7 100644 --- a/options/locale/locale_fa-IR.ini +++ b/options/locale/locale_fa-IR.ini @@ -100,6 +100,15 @@ concept_user_organization=سازمان name=نام +filter=فیلتر +filter.is_archived=بایگانی شده +filter.is_template=قالب +filter.public=عمومی +filter.private=خصوصی + + +[search] + [aria] [heatmap] @@ -233,7 +242,6 @@ collaborative_repos=مخازن همکاری my_orgs=سازمان های من my_mirrors=قرینههای من view_home=نمایش %s -search_repos=یافتن مخزن… filter=فیلترهای دیگر filter_by_team_repositories=فیلتر کردن با مخازن تیمها feed_of=`خوراک از "%s"` @@ -254,14 +262,7 @@ issues.in_your_repos=در مخازن شما repos=مخازن users=کاربران organizations=سازمان ها -search=جستجو code=کد -search.fuzzy=نادقیق -search.match=تطابق -repo_no_results=مخزنی مطابق با این مورد یافت نشد. -user_no_results=کاربری مطابق با این مورد یافت نشد. -org_no_results=سازمانی مطابق با این مورد یافت نشد. -code_no_results=کد منبعی مطابق با جستجوی شما یافت نشد. code_last_indexed_at=آخرین به روزرسانی در %s [auth] @@ -274,7 +275,6 @@ remember_me=این دستگاه را بخاطر بسپار forgot_password_title=گذرواژه خود را فراموش کرده ام forgot_password=گذرواژه خود را فراموش کردهاید؟ sign_up_now=نیاز به یک حساب دارید؟ هماکنون ثبت نام کنید. -confirmation_mail_sent_prompt=ایمیل تاییدیه جدیدی به <b>%s</b> ارسال شد. لطفا صندوق ورودی خود را در %d ساعت آینده برای تکمیل فرایند ثبت نام بررسی کنید. must_change_password=گذرواژه خود را به روز کنید allow_password_change=نیاز به کاربر برای تغییرگذرواژه (توصیه می شود) reset_password_mail_sent_prompt=ایمیل تاییدیه جدیدی به <b>%s</b> ارسال شد. لطفا صندوق ورودی خود را در %s آینده برای فرآیند بازیابی حساب کاربری خود بررسی کنید. @@ -480,6 +480,7 @@ user_bio=زندگینامه disabled_public_activity=این کاربر نمایش عمومی فعالیت های خود را غیرفعال کرده است. + [settings] profile=نمایه account=حساب کاربری @@ -591,7 +592,6 @@ gpg_invalid_token_signature=کلید GPG ارائه شده، امضا و ژتو gpg_token_required=باید یک امضا برای ژتون زیر ارائه کنید gpg_token=توکن gpg_token_help=با این میتوانید یک امضاء بسازید: -gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig gpg_token_signature=امضای GPG زرهپوش key_signature_gpg_placeholder=با '-----BEGIN PGP SIGNATURE-----' شروع میشود ssh_key_verified=کلید تأیید شده @@ -730,7 +730,6 @@ fork_repo=انشعاب از مخزن fork_from=انشعاب از fork_visibility_helper=نمایان بودن مخزن منشعب شده غیر قابل تغییر است. use_template=استفاده از این الگو -clone_in_vsc=کلون کردن در VS Code download_zip=دانلود ZIP download_tar=دانلود TAR.GZ download_bundle=بارگیری باندل @@ -972,8 +971,6 @@ editor.require_signed_commit=شاخه یک کامیت امضا شده لازم commits.desc=تاریخچه تغییرات کد منبع را مرور کنید. commits.commits=کامیتها commits.nothing_to_compare=این شاخه ها برابرند. -commits.search=جستوجو کامیتها… -commits.find=جستجو commits.search_all=همه شاخه ها commits.author=مولف commits.message=پیام @@ -1010,7 +1007,6 @@ projects.type.basic_kanban=پایه بر اساس سیستم کانبان (یک projects.type.bug_triage=اشکال Triage projects.template.desc=قالب پروژه projects.template.desc_helper=برای شروع یک قالب پروژه را انتخاب کنید -projects.type.uncategorized=دستهبندی نشده projects.column.edit_title=نام projects.column.new_title=نام projects.column.color=رنگ @@ -1301,7 +1297,6 @@ pulls.compare_compare=واکشی از pulls.switch_comparison_type=سوئیچ نوع مقایسه pulls.switch_head_and_base=سر و پایه سوئیچ pulls.filter_branch=صافی شاخه -pulls.no_results=هیچ نتیجهای یافت نشد. pulls.nothing_to_compare=این شاخهها یکی هستند. نیازی به تقاضای واکشی نیست. pulls.nothing_to_compare_and_allow_empty_pr=این شاخه ها برابر هستند. این PR خالی خواهد بود. pulls.has_pull_request=`A درخواست pull بین این شاخه ها از قبل وجود دارد: <a href="%[1]s">%[2]s#%[3]d</a>` @@ -1501,13 +1496,6 @@ activity.git_stats_deletion_n=%d مذحوف contributors.contribution_type.commits=کامیتها -search=جستجو -search.search_repo=جستجوی مخزن -search.fuzzy=درهم -search.match=مطابق -search.results=نتیجه جستجو برای "%s" در <a href="%s">%s</a> -search.code_no_results=کد منبعی مطابق با جستجوی شما یافت نشد. - settings=تنظيمات settings.desc=تنظیمات جایی است که شما میتوانید تنظیمات مخزن خود را مدیریت کنید settings.options=مخزن @@ -1623,7 +1611,6 @@ settings.delete_collaborator=حذف settings.collaborator_deletion=حذفکردن همکار settings.collaborator_deletion_desc=حذف یک همکار از مخزن دسترسیهای آنها را را مجدد لغو میکند. آیا ادامه میدهید؟ settings.remove_collaborator_success=همكار حذف شد. -settings.search_user_placeholder=جستجوی کاربر… settings.org_not_allowed_to_be_collaborator=سازمان ها را نمیتوان به عنوان همکار افزود. settings.change_team_access_not_allowed=تغییر دسترسی های تیم برای این مخزن توسط مالک ارگان محدود شده است settings.team_not_in_organization=تیم همانند ارگان برای این مخزن نیست @@ -1631,7 +1618,6 @@ settings.teams=تیم ها settings.add_team=افزودن تیم settings.add_team_duplicate=تیم پیش از این مخزن داشته settings.add_team_success=تیم هماکنون به مخزن دسترسی دارد. -settings.search_team=جستجوی تیم… settings.change_team_permission_tip=دسترسی تیم در صفحه تنظیمات تیم انجام شده و برای هر مخزن نمی تواند تغییر یابد settings.delete_team_tip=این تیم به تمامی مخازن دسترسی دارد و نمی تواند حذف شود settings.remove_team_success=دسترسی تیم به مخزن حذف شد. @@ -1748,9 +1734,7 @@ settings.protect_whitelist_committers=لیست سفید برای درج محدو settings.protect_whitelist_committers_desc=فقط به کاربران یا تیمهای موجود لیست سفید برای درج در این شاخه اجازه خواهند داشت (اما نه درج اجباری). settings.protect_whitelist_deploy_keys=فهرست سفید کلیدهای استقرار با دسترسی نوشتن برای push کردن. settings.protect_whitelist_users=کاربران لیست سفید برای درج در مخزن: -settings.protect_whitelist_search_users=جستجوی کاربر… settings.protect_whitelist_teams=تیمهای لیست سفید برای درج در مخزن: -settings.protect_whitelist_search_teams=جستجوی تیم ها… settings.protect_merge_whitelist_committers=فعال کردن لیست سفید ادغام settings.protect_merge_whitelist_committers_desc=اجازه به کاربران یا تیمهای موجود لیست سفید برای تقاضا ادغام واکشی در این شاخه. settings.protect_merge_whitelist_users=کاربران لیست سفید برای ادغام: @@ -2047,7 +2031,6 @@ teams.write_permission_desc=این تیم دسترسی <strong>نوشتن</stron teams.admin_permission_desc=این تیم دسترسی <strong>نوشتن</strong> خواهد داشت: اعضا خواهند توانست مخازن تیم را خوانده ، تغییراتی در آنها اعمال کرده و یا همکارانشان را به مخازن اضافه نمایند. teams.create_repo_permission_desc=علاوه بر این ، این تیم اجازه <strong> ساخت مخزن </strong> دسترسی : اعضا می توانند مخازن جدیدی را در سازمان ایجاد کنند. teams.repositories=مخازن تیم -teams.search_repo_placeholder=جستجوی مخزن... teams.remove_all_repos_title=حذف تمام مخازن تیم teams.remove_all_repos_desc=با این کار همه مخازن از تیم حذف می شوند. teams.add_all_repos_title=افزودن همه مخازن @@ -2072,6 +2055,8 @@ hooks=وب هوک ها authentication=منابع احراز هویت emails=ایمیل های کاربر config=پیکربندی +config_summary=چکیده +config_settings=تنظيمات notices=هشدارهای سامانه monitor=نظارت first_page=نخستین @@ -2220,9 +2205,6 @@ repos.unadopted.no_more=هیچ مخزن تایید نشده دیگری یافت repos.owner=مالک repos.name=نام repos.private=خصوصی -repos.watches=تماشا شده -repos.stars=ستاره ها -repos.forks=انشعابها repos.issues=مسائل repos.size=اندازه @@ -2321,7 +2303,6 @@ auths.tip.nextcloud=با استفاده از منوی زیر "تنظیمات -> 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.google_plus=اطلاعات مربوط به مشتری OAuth2 را از کلاینت API Google در https://console.developers.google.com/ auths.tip.openid_connect=برای مشخص کردن نقاط پایانی از آدرس OpenID Connect Discovery URL (<server> /.well-known/openid-configuration) استفاده کنید. auths.tip.twitter=به https://dev.twitter.com/apps بروید ، برنامه ای ایجاد کنید و اطمینان حاصل کنید که گزینه "اجازه استفاده از این برنامه برای ورود به سیستم با Twitter" را فعال کنید diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini index ab0dcc443d..00581f49fc 100644 --- a/options/locale/locale_fi-FI.ini +++ b/options/locale/locale_fi-FI.ini @@ -114,6 +114,15 @@ concept_user_organization=Organisaatio name=Nimi +filter=Suodata +filter.is_archived=Arkistoidut +filter.is_template=Malli +filter.public=Julkinen +filter.private=Yksityinen + + +[search] + [aria] [heatmap] @@ -243,7 +252,6 @@ collaborative_repos=Yhteistyö repot my_orgs=Organisaationi my_mirrors=Peilini view_home=Näytä %s -search_repos=Etsi repo… filter=Muut suodattimet filter_by_team_repositories=Suodata tiimin repojen mukaan feed_of=`Syöte "%s"` @@ -264,13 +272,7 @@ issues.in_your_repos=Repoissasi repos=Repot users=Käyttäjät organizations=Organisaatiot -search=Hae code=Koodi -search.match=Osuma -repo_no_results=Vastaavia repoja ei löydy. -user_no_results=Vastaavia käyttäjiä ei löytynyt. -org_no_results=Ei löytynyt vastaavia organisaatioita. -code_no_results=Hakuehtoasi vastaavaa lähdekoodia ei löytynyt. code_last_indexed_at=Viimeksi indeksoitu %s [auth] @@ -283,7 +285,6 @@ remember_me=Muista tämä laite forgot_password_title=Unohtuiko salasana forgot_password=Unohtuiko salasana? sign_up_now=Tarvitsetko tilin? Rekisteröidy nyt. -confirmation_mail_sent_prompt=Uusi varmistussähköposti on lähetetty osoitteeseen <b>%s</b>, ole hyvä ja tarkista saapuneet seuraavan %s tunnin sisällä saadaksesi rekisteröintiprosessin valmiiksi. must_change_password=Vaihda salasanasi allow_password_change=Vaadi käyttäjää vaihtamaan salasanansa (suositeltava) reset_password_mail_sent_prompt=Varmistussähköposti on lähetetty osoitteeseen <b>%s</b>. Tarkista saapuneet seuraavan %s tunnin sisällä saadaksesi tilin palauttamisen valmiiksi. @@ -440,6 +441,7 @@ unfollow=Lopeta seuraaminen user_bio=Elämäkerta + [settings] profile=Profiili account=Tili @@ -555,7 +557,6 @@ gpg_key_verify=Vahvista gpg_token_required=Sinun täytyy antaa allekirjoitus alla olevalle pääsymerkille gpg_token=Pääsymerkki gpg_token_help=Voit luoda allekirjoituksen käyttäen: -gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig gpg_token_signature=Panssaroitu GPG-allekirjoitus key_signature_gpg_placeholder=Alkaa sanoilla '-----BEGIN PGP SIGNATURE-----' ssh_key_verified=Vahvistettu avain @@ -657,7 +658,6 @@ visibility_helper_forced=Sivuston ylläpitäjä pakottaa uudet repot olemaan yks fork_repo=Forkkaa repo fork_from=Forkkaa lähteestä fork_visibility_helper=Forkatun repon näkyvyyttä ei voi muuttaa. -clone_in_vsc=Kloonaa VS Codessa download_zip=Lataa ZIP download_tar=Lataa TAR.GZ repo_desc=Kuvaus @@ -779,7 +779,6 @@ editor.require_signed_commit=Haara vaatii vahvistetun commitin commits.commits=Commitit commits.nothing_to_compare=Nämä haarat vastaavat toisiaan. -commits.find=Haku commits.search_all=Kaikki haarat commits.author=Tekijä commits.message=Viesti @@ -806,7 +805,6 @@ projects.edit=Muokkaa projektia projects.modify=Päivitä projekti projects.type.basic_kanban=Yksinkertainen Kanban projects.template.desc=Malli -projects.type.uncategorized=Luokittelematon projects.column.edit_title=Nimi projects.column.new_title=Nimi projects.open=Avaa @@ -983,7 +981,6 @@ pulls.has_viewed_file=Katsottu pulls.viewed_files_label=%[1]d / %[2]d tiedostoa katsottu pulls.compare_compare=vedä kohteesta pulls.filter_branch=Suodata branch -pulls.no_results=Tuloksia ei löytynyt. pulls.nothing_to_compare=Nämä haarat vastaavat toisiaan. Ei ole tarvetta luoda vetopyyntöä. pulls.nothing_to_compare_and_allow_empty_pr=Nämä haarat vastaavat toisiaan. Vetopyyntö tulee olemaan tyhjä. pulls.has_pull_request=`Vetopyyntö haarojen välillä on jo olemassa: <a href="%[1]s">%[2]s#%[3]d</a>` @@ -1077,10 +1074,6 @@ activity.git_stats_deletion_n=%d poistoa contributors.contribution_type.commits=Commitit -search=Haku -search.match=Osuma -search.code_no_results=Hakuehtoasi vastaavaa lähdekoodia ei löytynyt. - settings=Asetukset settings.options=Repo settings.collaboration.admin=Ylläpitäjä @@ -1119,7 +1112,6 @@ settings.delete_desc=Repon poistaminen on pysyvä eikä voi peruuttaa. settings.delete_notices_1=- Tätä toimintoa <strong>EI VOI</strong> peruuttaa myöhemmin. settings.update_settings_success=Repon asetukset on päivitetty. settings.delete_collaborator=Poista -settings.search_user_placeholder=Etsi käyttäjä… settings.teams=Tiimit settings.add_team=Lisää tiimi settings.add_webhook=Lisää webkoukku @@ -1203,7 +1195,6 @@ settings.branch_protection=Haaran '<b>%s</b>' suojaus settings.protect_this_branch=Ota haaran suojaus käyttöön settings.protect_whitelist_deploy_keys=Lisää julkaisuavaimet sallittujen listalle mahdollistaaksesi repohin kirjoituksen. settings.protect_whitelist_users=Lista käyttäjistä joilla työntö oikeus: -settings.protect_whitelist_search_users=Etsi käyttäjiä… settings.protect_merge_whitelist_committers_desc=Salli vain listaan merkittyjen käyttäjien ja tiimien yhdistää vetopyynnöt tähän haaraan. settings.protect_merge_whitelist_users=Lista käyttäjistä joilla yhdistämis-oikeus: settings.protect_required_approvals=Vaadittavat hyväksynnät: @@ -1407,6 +1398,8 @@ repositories=Repot authentication=Todennuslähteet emails=Käyttäjien sähköpostit config=Asetukset +config_summary=Yhteenveto +config_settings=Asetukset notices=Järjestelmän ilmoitukset monitor=Valvonta first_page=Ensimmäinen @@ -1508,9 +1501,6 @@ repos.repo_manage_panel=Repojen hallinta repos.owner=Omistaja repos.name=Nimi repos.private=Yksityinen -repos.watches=Tarkkailijat -repos.stars=Tähdet -repos.forks=Haarat repos.issues=Ongelmat repos.size=Koko diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index 20ef954cd2..062c818bd4 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -142,6 +142,15 @@ confirm_delete_selected=Êtes-vous sûr de vouloir supprimer tous les éléments name=Nom value=Valeur +filter=Filtrer +filter.is_archived=Archivé +filter.is_template=Modèle +filter.public=Public +filter.private=Privé + + +[search] + [aria] navbar=Barre de navigation footer=Pied de page @@ -315,7 +324,6 @@ collaborative_repos=Dépôts collaboratifs my_orgs=Mes organisations my_mirrors=Mes miroirs view_home=Voir %s -search_repos=Trouver un dépôt … filter=Autres filtres filter_by_team_repositories=Dépôts filtrés par équipe feed_of=Flux de « %s » @@ -336,20 +344,8 @@ issues.in_your_repos=Dans vos dépôts repos=Dépôts users=Utilisateurs organizations=Organisations -search=Rechercher go_to=Atteindre code=Code -search.type.tooltip=Type de recherche -search.fuzzy=Approximative -search.fuzzy.tooltip=Inclure également les résultats proches de la recherche -search.match=Exacte -search.match.tooltip=Inclure uniquement les résultats exacts -code_search_unavailable=Actuellement, la recherche de code n'est pas disponible. Veuillez contacter l'administrateur de votre site. -repo_no_results=Aucun dépôt correspondant n'a été trouvé. -user_no_results=Aucun utilisateur correspondant n'a été trouvé. -org_no_results=Aucune organisation correspondante n'a été trouvée. -code_no_results=Aucun code source correspondant à votre terme de recherche n'a été trouvé. -code_search_results=Résultats de la recherche pour « %s » code_last_indexed_at=Dernière indexation %s relevant_repositories_tooltip=Les dépôts qui sont des forks ou qui n'ont aucun sujet, aucune icône et aucune description sont cachés. relevant_repositories=Seuls les dépôts pertinents sont affichés, <a href="%s">afficher les résultats non filtrés</a>. @@ -367,7 +363,6 @@ forgot_password_title=Mot de passe oublié forgot_password=Mot de passe oublié ? sign_up_now=Pas de compte ? Inscrivez-vous maintenant. sign_up_successful=Le compte a été créé avec succès. Bienvenue ! -confirmation_mail_sent_prompt=Un nouveau mail de confirmation a été envoyé à <b>%s</b>. Veuillez vérifier votre boîte de réception dans les prochaines %s pour valider votre enregistrement. must_change_password=Réinitialisez votre mot de passe allow_password_change=Demande à l'utilisateur de changer son mot de passe (recommandé) reset_password_mail_sent_prompt=Un mail de confirmation a été envoyé à <b>%s</b>. Veuillez vérifier votre boîte de réception dans les prochaines %s pour terminer la procédure de récupération du compte. @@ -617,6 +612,7 @@ form.name_reserved=Le nom d’utilisateur "%s" est réservé. form.name_pattern_not_allowed=Le motif « %s » n’est pas autorisé dans un nom de d'utilisateur. form.name_chars_not_allowed=Le nom d'utilisateur "%s" contient des caractères non valides. + [settings] profile=Profil account=Compte @@ -761,7 +757,6 @@ gpg_invalid_token_signature=La clé GPG, la signature et le jeton fournis ne cor gpg_token_required=Vous devez fournir une signature pour le jeton ci-dessous gpg_token=Jeton gpg_token_help=Vous pouvez générer une signature en utilisant : -gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig gpg_token_signature=Signature GPG renforcée key_signature_gpg_placeholder=Commence par '-----BEGIN PGP SIGNATURE-----' verify_gpg_key_success=La clé GPG "%s" a été vérifiée. @@ -955,7 +950,6 @@ fork_branch=Branche à cloner sur la bifurcation all_branches=Toutes les branches fork_no_valid_owners=Ce dépôt ne peut pas être bifurqué car il n’a pas de propriétaire valide. use_template=Utiliser ce modèle -clone_in_vsc=Cloner dans VS Code download_zip=Télécharger le ZIP download_tar=Télécharger le TAR.GZ download_bundle=Télécharger le BUNDLE @@ -971,6 +965,8 @@ issue_labels_helper=Sélectionner un jeu de label. license=Licence license_helper=Sélectionner une licence license_helper_desc=Une licence réglemente ce que les autres peuvent ou ne peuvent pas faire avec votre code. Vous ne savez pas laquelle est la bonne pour votre projet ? Comment <a target="_blank" rel="noopener noreferrer" href="%s">choisir une licence</a>. +object_format=Format d'objet +object_format_helper=Format d’objet pour ce dépôt. Ne peut être modifié plus tard. SHA1 est le plus compatible. readme=LISEZMOI readme_helper=Choisissez un modèle de fichier LISEZMOI. readme_helper_desc=Le README est l'endroit idéal pour décrire votre projet et accueillir des contributeurs. @@ -1278,9 +1274,7 @@ commits.desc=Naviguer dans l'historique des modifications. commits.commits=Révisions commits.no_commits=Pas de révisions en commun. "%s" et "%s" ont des historiques entièrement différents. commits.nothing_to_compare=Ces branches sont égales. -commits.search=Rechercher des révisions… commits.search.tooltip=Vous pouvez utiliser les mots-clés "author:", "committer:", "after:", ou "before:" pour filtrer votre recherche, ex.: "revert author:Alice before:2019-01-13". -commits.find=Chercher commits.search_all=Toutes les branches commits.author=Auteur commits.message=Message @@ -1331,7 +1325,6 @@ projects.type.basic_kanban=Kanban basique projects.type.bug_triage=Bug à trier projects.template.desc=Modèle de projet projects.template.desc_helper=Sélectionnez un modèle de projet pour débuter -projects.type.uncategorized=Non catégorisé projects.column.edit=Modifier la colonne projects.column.edit_title=Nom projects.column.new_title=Nom @@ -1339,10 +1332,7 @@ projects.column.new_submit=Créer une colonne projects.column.new=Nouvelle colonne projects.column.set_default=Définir par défaut projects.column.set_default_desc=Les tickets et demandes d’ajout non-catégorisés seront placés dans cette colonne. -projects.column.unset_default=Défaire par défaut -projects.column.unset_default_desc=Les tickets et demandes d'ajouts non-catégorisés seront placés dans une colonne idoine. projects.column.delete=Supprimer la colonne -projects.column.deletion_desc=La suppression d'une colonne de projet déplace tous les tickets liés à 'Non catégorisé'. Continuer ? projects.column.color=Couleur projects.open=Ouvrir projects.close=Fermer @@ -1454,7 +1444,6 @@ issues.filter_sort.moststars=Favoris (décroissant) issues.filter_sort.feweststars=Favoris (croissant) issues.filter_sort.mostforks=Bifurcations (décroissant) issues.filter_sort.fewestforks=Bifurcations (croissant) -issues.keyword_search_unavailable=La recherche par mot clé n'est pas disponible. Veuillez contacter l'administrateur de votre instance Gitea. issues.action_open=Ouvrir issues.action_close=Fermer issues.action_label=Label @@ -1706,7 +1695,6 @@ pulls.compare_compare=tirer les modifications depuis pulls.switch_comparison_type=Changer le type de comparaison pulls.switch_head_and_base=Passez de head à base pulls.filter_branch=Filtre de branche -pulls.no_results=Aucun résultat trouvé. pulls.show_all_commits=Afficher toutes les révisions pulls.show_changes_since_your_last_review=Affiche les modifications depuis votre dernière évaluation. pulls.showing_only_single_commit=Affiche uniquement les changements de la révision %[1]s @@ -1982,17 +1970,6 @@ contributors.contribution_type.commits=Révisions contributors.contribution_type.additions=Ajouts contributors.contribution_type.deletions=Suppressions -search=Chercher -search.search_repo=Rechercher dans le dépôt -search.type.tooltip=Type de recherche -search.fuzzy=Approximative -search.fuzzy.tooltip=Inclure également les résultats proches de la recherche -search.match=Exacte -search.match.tooltip=Inclure uniquement les résultats exacts -search.results=Résultats de la recherche « %s » dans <a href="%s"> %s</a> -search.code_no_results=Aucun code source correspondant à votre terme de recherche n'a été trouvé. -search.code_search_unavailable=Actuellement, la recherche de code n'est pas disponible. Veuillez contacter l'administrateur de votre site. - settings=Paramètres settings.desc=Les paramètres sont l'endroit où gérer les options du dépôt settings.options=Dépôt @@ -2019,6 +1996,7 @@ settings.mirror_settings.docs.doc_link_title=Comment mettre en miroir les dépô settings.mirror_settings.docs.doc_link_pull_section=la section « Pulling from a remote repository » de la documentation. settings.mirror_settings.docs.pulling_remote_title=Tirer depuis un dépôt distant settings.mirror_settings.mirrored_repository=Dépôt en miroir +settings.mirror_settings.pushed_repository=Dépôt sortant settings.mirror_settings.direction=Direction settings.mirror_settings.direction.pull=Tirer settings.mirror_settings.direction.push=Soumission @@ -2070,6 +2048,7 @@ settings.pulls.default_allow_edits_from_maintainers=Autoriser les modifications settings.releases_desc=Activer les publications du dépôt settings.packages_desc=Activer le registre des paquets du dépôt settings.projects_desc=Activer les projets de dépôt +settings.projects_mode_all=Tous les projets settings.actions_desc=Activer les actions du dépôt settings.admin_settings=Paramètres administrateur settings.admin_enable_health_check=Activer les vérifications de santé du dépôt (git fsck) @@ -2144,7 +2123,6 @@ settings.delete_collaborator=Supprimer settings.collaborator_deletion=Supprimer le collaborateur settings.collaborator_deletion_desc=La suppression d'un collaborateur révoque son accès à ce dépôt. Continuer ? settings.remove_collaborator_success=Le collaborateur a été retiré. -settings.search_user_placeholder=Rechercher un utilisateur… settings.org_not_allowed_to_be_collaborator=Les organisations ne peuvent être ajoutées en tant que collaborateur. settings.change_team_access_not_allowed=La modification de l'accès de l'équipe au dépôt a été limitée au propriétaire de l'organisation settings.team_not_in_organization=L'équipe n'est pas dans la même organisation que le dépôt @@ -2152,7 +2130,6 @@ settings.teams=Équipes settings.add_team=Ajouter une équipe settings.add_team_duplicate=L'équipe a déjà le dépôt settings.add_team_success=L'équipe a maintenant accès au dépôt. -settings.search_team=Rechercher une équipe… settings.change_team_permission_tip=La permission de l'équipe est définie sur la page de configuration de l'équipe et ne peut pas être modifiée par dépôt settings.delete_team_tip=Cette équipe a accès à tous les dépôts et ne peut pas être supprimée settings.remove_team_success=L'accès de l'équipe au dépôt a été supprimé. @@ -2305,9 +2282,7 @@ settings.protect_whitelist_committers=Liste blanche des soumissions settings.protect_whitelist_committers_desc=Seuls les utilisateurs ou les équipes autorisés pourront soumettre sur cette branche (sans forcer). settings.protect_whitelist_deploy_keys=Mettez les clés de déploiement sur liste blanche avec accès en écriture pour soumettre. settings.protect_whitelist_users=Utilisateurs sur liste blanche : -settings.protect_whitelist_search_users=Rechercher des utilisateurs… settings.protect_whitelist_teams=Équipes sur liste blanche : -settings.protect_whitelist_search_teams=Rechercher des équipes… settings.protect_merge_whitelist_committers=Activer la liste blanche pour la fusion settings.protect_merge_whitelist_committers_desc=N'autoriser que les utilisateurs et les équipes en liste blanche d'appliquer les demandes de fusion sur cette branche. settings.protect_merge_whitelist_users=Utilisateurs en liste blanche de fusion : @@ -2552,7 +2527,6 @@ branch.default_deletion_failed=La branche "%s" est la branche par défaut. Elle branch.restore=`Restaurer la branche "%s"` branch.download=`Télécharger la branche "%s"` branch.rename=`Renommer la branche "%s"` -branch.search=Rechercher une branche branch.included_desc=Cette branche fait partie de la branche par défaut branch.included=Incluses branch.create_new_branch=Créer une branche à partir de la branche : @@ -2695,7 +2669,6 @@ teams.write_permission_desc=Cette équipe permet l'accès en <strong>écriture</ teams.admin_permission_desc=Cette équipe permet l'accès <strong>administrateur</strong> : les membres peuvent voir, participer et ajouter des collaborateurs à ses dépôts. teams.create_repo_permission_desc=De plus, cette équipe accorde la permission <strong>Créer un dépôt</strong> : les membres peuvent créer de nouveaux dépôts dans l'organisation. teams.repositories=Dépôts de l'Équipe -teams.search_repo_placeholder=Rechercher dans le dépôt… teams.remove_all_repos_title=Supprimer tous les dépôts de l'équipe teams.remove_all_repos_desc=Ceci supprimera tous les dépôts de l'équipe. teams.add_all_repos_title=Ajouter tous les dépôts @@ -2728,6 +2701,8 @@ integrations=Intégrations authentication=Sources d'authentification emails=Emails de l'utilisateur config=Configuration +config_summary=Résumé +config_settings=Paramètres notices=Informations monitor=Surveillance first_page=Première @@ -2904,9 +2879,6 @@ repos.unadopted.no_more=Aucun dépôt dépossédé trouvé. repos.owner=Propriétaire repos.name=Nom repos.private=Privé -repos.watches=Suivi par -repos.stars=Votes -repos.forks=Bifurcations repos.issues=Tickets repos.size=Taille repos.lfs_size=Taille LFS @@ -3031,7 +3003,6 @@ auths.tip.nextcloud=`Enregistrez un nouveau consommateur OAuth sur votre instanc auths.tip.dropbox=Créez une nouvelle application sur https://www.dropbox.com/developers/apps auths.tip.facebook=`Enregistrez une nouvelle application sur https://developers.facebook.com/apps et ajoutez le produit "Facebook Login"` auths.tip.github=Créez une nouvelle application OAuth sur https://github.com/settings/applications/new -auths.tip.gitlab=Créez une nouvelle application sur https://gitlab.com/profile/applications auths.tip.google_plus=Obtenez des identifiants OAuth2 sur la console API de Google (https://console.developers.google.com/) auths.tip.openid_connect=Utilisez l'URL de découvert OpenID (<server>/.well-known/openid-configuration) pour spécifier les points d'accès auths.tip.twitter=Rendez-vous sur https://dev.twitter.com/apps, créez une application et assurez-vous que l'option "Autoriser l'application à être utilisée avec Twitter Connect" est activée diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini index 901690d9a0..93e3b42115 100644 --- a/options/locale/locale_hu-HU.ini +++ b/options/locale/locale_hu-HU.ini @@ -90,6 +90,14 @@ concept_user_organization=Szervezet name=Név +filter.is_archived=Archivált +filter.is_template=Sablon +filter.public=Nyilvános +filter.private=Privát + + +[search] + [aria] [heatmap] @@ -207,7 +215,6 @@ collaborative_repos=Együttműködési tárolók my_orgs=Szervezeteim my_mirrors=Tükreim view_home=Nézet %s -search_repos=Tároló keresés… show_archived=Archivált @@ -222,12 +229,7 @@ issues.in_your_repos=A tárolóidban repos=Tárolók users=Felhasználók organizations=Szervezetek -search=Keresés code=Kód -repo_no_results=Nincs ilyen tároló. -user_no_results=Nincs ilyen felhasználó. -org_no_results=Nincs ilyen szervezet. -code_no_results=Nincs találat a keresési kifejezésedre. code_last_indexed_at=Utoljára indexelve: %s [auth] @@ -240,7 +242,6 @@ remember_me=Eszköz megjegyzése forgot_password_title=Elfelejtett jelszó forgot_password=Elfelejtette a jelszavát? sign_up_now=Szeretne bejelentkezni? Regisztráljon most. -confirmation_mail_sent_prompt=Új megerősítő email lett küldve ide: <b>%s</b>. Ellenőrizze postafiókját az elkövetkező %s a regisztrációs folyamat befejezéséhez. must_change_password=Jelszó módosítása allow_password_change=A felhasználóknak meg kell változtatniuk a jelszavukat(ajánlott) reset_password_mail_sent_prompt=Megerősítő email lett küldve ide: <b>%s</b>. Ellenőrizze postafiókját az elkövetkező %s a jelszó visszaállítási folyamat befejezéséhez. @@ -384,6 +385,7 @@ unfollow=Követés törlése user_bio=Életrajz + [settings] profile=Profil account=Fiók @@ -722,8 +724,6 @@ editor.no_changes_to_show=Nincsen megjeleníthető változás. editor.add_subdir=Mappa hozzáadása… commits.commits=Commit-ok -commits.search=Commit-ok keresése… -commits.find=Keresés commits.search_all=Minden ág commits.author=Szerző commits.message=Üzenet @@ -929,7 +929,6 @@ pulls.compare_changes=Új egyesítési kérés pulls.compare_base=egyesítés ide pulls.compare_compare=egyesítés innen pulls.filter_branch=Ágra szűrés -pulls.no_results=Nincs találat. pulls.nothing_to_compare=Ezek az ágak egyenlőek. Nincs szükség egyesítési kérésre. pulls.create=Egyesítési kérés létrehozása pulls.title_desc=egyesíteni szeretné %[1]d változás(oka)t a(z) <code>%[2]s</code>-ból <code id="branch_target">%[3]s</code>-ba @@ -1056,11 +1055,6 @@ activity.git_stats_deletion_n=%d törlés contributors.contribution_type.commits=Commit-ok -search=Keresés -search.search_repo=Tároló keresés -search.results=`"%s" találatok keresése itt: <a href="%s">%s</a>` -search.code_no_results=Nincs találat a keresési kifejezésedre. - settings=Beállítások settings.options=Tároló settings.collaboration.read=Olvasott @@ -1102,8 +1096,6 @@ settings.branches=Ágak settings.protected_branch=Ág védeleme settings.protected_branch_can_push=Push engedélyezése? settings.protected_branch_can_push_yes=Most már push-olhatja -settings.protect_whitelist_search_users=Felhasználó keresése… -settings.protect_whitelist_search_teams=Csoportok keresése… settings.protect_check_status_contexts=Állapotellenőrzés engedélyezése settings.add_protected_branch=Védelem engedélyezése settings.delete_protected_branch=Védelem letiltása @@ -1248,7 +1240,6 @@ teams.delete_team_desc=Egy csapat törlése visszavonja a tagjai hozzáférésé teams.delete_team_success=A csoport törölve lett. teams.read_permission_desc=Ez a csoport <strong>Olvasási</strong> jogosultságot biztosít: a tagok megtekinthetik és klónozhatják a csoport tárolóit. teams.repositories=Csoport tárolói -teams.search_repo_placeholder=Tároló keresése… teams.remove_all_repos_title=Összes csapattároló eltávolítása teams.remove_all_repos_desc=Ez el fogja távolítani az összes tárolót a csoportból. teams.add_all_repos_title=Minden tároló hozzáadása @@ -1266,6 +1257,8 @@ organizations=Szervezetek repositories=Tárolók authentication=Hitelesítési források config=Konfiguráció +config_summary=Összefoglaló +config_settings=Beállítások notices=Rendszer-értesítések monitor=Figyelés first_page=Első @@ -1352,8 +1345,6 @@ repos.repo_manage_panel=Tárolók Kezelése repos.owner=Tulajdonos repos.name=Név repos.private=Privát -repos.watches=Figyelők -repos.stars=Csillagok repos.issues=Hibajegyek repos.size=Méret @@ -1415,7 +1406,6 @@ auths.tip.bitbucket=Igényeljen egy új OAuth jogosultságot itt: https://bitbuc auths.tip.dropbox=Vegyen fel új alkalmazást itt: https://www.dropbox.com/developers/apps auths.tip.facebook=Vegyen fel új alkalmazást itt: https://developers.facebook.com/apps majd adja hozzá a "Facebook Login"-t auths.tip.github=Vegyen fel új OAuth alkalmazást itt: https://github.com/settings/applications/new -auths.tip.gitlab=Vegyen fel új alkalmazást itt: https://gitlab.com/profile/applications auths.tip.google_plus=Szerezzen OAuth2 kliens hitelesítési adatokat a Google API konzolban (https://console.developers.google.com/) auths.tip.openid_connect=Használja az OpenID kapcsolódás felfedező URL-t (<kiszolgáló>/.well-known/openid-configuration) a végpontok beállításához auths.tip.twitter=Menyjen ide: https://dev.twitter.com/apps, hozzon létre egy alkalmazást és győződjön meg róla, hogy az “Allow this application to be used to Sign in with Twitter” opció be van kapcsolva diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini index 1aee871b67..ad7e0f4062 100644 --- a/options/locale/locale_id-ID.ini +++ b/options/locale/locale_id-ID.ini @@ -83,6 +83,12 @@ concept_code_repository=Repositori name=Nama +filter.is_template=Contoh +filter.private=Pribadi + + +[search] + [aria] [heatmap] @@ -134,7 +140,6 @@ collaborative_repos=Repositori Kolaboratif my_orgs=Organisasi Saya my_mirrors=Duplikat Saya view_home=Lihat %s -search_repos=Cari repositori… show_private=Pribadi @@ -145,12 +150,7 @@ issues.in_your_repos=Dalam repositori anda repos=Repositori users=Pengguna organizations=Organisasi -search=Cari code=Kode -repo_no_results=Tidak ditemukan repositori yang cocok. -user_no_results=Tidak ditemukan pengguna yang cocok. -org_no_results=Tidak ada organisasi yang cocok ditemukan. -code_no_results=Tidak ada kode sumber yang cocok dengan istilah yang anda cari. [auth] create_new_account=Daftar Akun @@ -161,7 +161,6 @@ disable_register_mail=Konfirmasi lewat email untuk pengguna baru dimatikan. forgot_password_title=Lupa Kata Sandi forgot_password=Lupa kata sandi? sign_up_now=Butuh akun? Daftar sekarang. -confirmation_mail_sent_prompt=Surel konfirmasi baru telah dikirim ke <b>%s</b>. Silakan periksa kotak masuk anda dalam %s ke depan untuk menyelesaikan proses pendaftaran. must_change_password=Perbarui kata sandi Anda allow_password_change=Wajibkan pengguna untuk mengganti kata sandi (disarankan) reset_password_mail_sent_prompt=Surel konfirmasi berhasil dikirim ke <b>%s</b>. Silahkan cek akun email Anda dalam %s jam untuk menyelesaikan proses pemulihan akun. @@ -307,6 +306,7 @@ unfollow=Berhenti Mengikuti user_bio=Biografi + [settings] profile=Profil account=Akun @@ -631,7 +631,6 @@ editor.cancel=Membatalkan editor.no_changes_to_show=Tidak ada perubahan untuk ditampilkan. commits.commits=Melakukan -commits.find=Telusuri commits.author=Penulis commits.message=Pesan commits.date=Tanggal @@ -749,7 +748,6 @@ issues.dependency.remove=Menghapus pulls.new=Permintaan Tarik Baru pulls.compare_changes=Permintaan Tarik Baru pulls.filter_branch=Penyaringan cabang -pulls.no_results=Hasil tidak ditemukan. pulls.create=Buat Permintaan Tarik pulls.title_desc=ingin menggabungkan komit %[1]d dari <code>%[2]s</code> menuju <code id="branch_target">%[3]s</code> pulls.merged_title_desc=commit %[1]d telah digabungkan dari <code>%[2]s</code> menjadi <code>%[3]s</code> %[4]s @@ -841,11 +839,6 @@ activity.published_release_label=Dikeluarkan contributors.contribution_type.commits=Melakukan -search=Cari -search.search_repo=Cari repositori -search.results=Cari hasil untuk "%s" dalam <a href="%s">%s</a> -search.code_no_results=Tidak ada kode sumber yang cocok dengan istilah yang anda cari. - settings=Pengaturan settings.desc=Pengaturan dimana anda dapat mengelola pengaturan untuk repositori settings.options=Repositori @@ -873,7 +866,6 @@ settings.transfer_owner=Pemilik Baru settings.delete=Menghapus Repositori Ini settings.delete_notices_1=- Operasi ini <strong>TIDAK BISA</strong> dibatalkan. settings.delete_collaborator=Menghapus -settings.search_user_placeholder=Cari pengguna… settings.teams=Tim settings.add_webhook=Tambahkan Webhook settings.webhook.test_delivery=Percobaan Pengiriman @@ -1008,13 +1000,13 @@ teams.update_settings=Memperbarui pengaturan teams.add_team_member=Tambahkan Anggota Tim teams.delete_team_success=Tim sudah di hapus. teams.repositories=Tim repositori -teams.search_repo_placeholder=Cari repositori… [admin] dashboard=Dasbor organizations=Organisasi repositories=Repositori config=Konfigurasi +config_settings=Pengaturan notices=Pemberitahuan Sistem monitor=Memantau first_page=Pertama @@ -1077,8 +1069,6 @@ repos.repo_manage_panel=Manajemen Repositori repos.owner=Pemilik repos.name=Nama repos.private=Pribadi -repos.watches=Jam tangan -repos.stars=Bintang repos.issues=Masalah repos.size=Ukuran @@ -1128,7 +1118,6 @@ auths.tip.oauth2_provider=Penyediaan OAuth2 auths.tip.dropbox=Membuat aplikasi baru di https://www.dropbox.com/developers/apps auths.tip.facebook=`Daftarkan sebuah aplikasi baru di https://developers.facebook.com/apps dan tambakan produk "Facebook Masuk"` auths.tip.github=Mendaftar aplikasi OAuth baru di https://github.com/settings/applications/new -auths.tip.gitlab=Mendaftar aplikasi baru di https://gitlab.com/profile/applications auths.tip.openid_connect=Gunakan membuka ID yang terhubung ke jelajah URL (<server>/.well-known/openid-configuration) untuk menentukan titik akhir auths.delete=Menghapus Otentikasi Sumber auths.delete_auth_title=Menghapus Otentikasi Sumber diff --git a/options/locale/locale_is-IS.ini b/options/locale/locale_is-IS.ini index f67541fe73..3165c4185b 100644 --- a/options/locale/locale_is-IS.ini +++ b/options/locale/locale_is-IS.ini @@ -111,6 +111,14 @@ concept_code_repository=Hugbúnaðarsafn name=Heiti value=Gildi +filter=Sía +filter.is_archived=Safnvistað +filter.is_template=Sniðmát +filter.public=Opinbert + + +[search] + [aria] [heatmap] @@ -224,7 +232,6 @@ show_more_repos=Sýna fleiri hugbúnaðarsöfn… my_orgs=Stofnanir Mínar my_mirrors=Speglanir Mínar view_home=Skoða %s -search_repos=Finna hugbúnaðarsafn… filter=Aðrar Síur show_archived=Safnvistað @@ -239,14 +246,7 @@ issues.in_your_repos=Í hugbúnaðarsöfnum þínum repos=Hugbúnaðarsöfn users=Notendur organizations=Stofnanir -search=Leita code=Kóði -search.fuzzy=Óljóst -code_search_unavailable=Sem stendur er kóðaleit ekki í boði. Vinsamlegast hafðu samband við síðustjórann þinn. -repo_no_results=Engin samsvarandi hugbúnaðarsöfn fundust. -user_no_results=Engir samsvarandi notendur fundust. -org_no_results=Engar samsvarandi stofnanir fundust. -code_no_results=Enginn samsvarandi frumkóði fannst eftur þínum leitarorðum. [auth] create_new_account=Skrá Notanda @@ -418,6 +418,7 @@ user_bio=Lífssaga disabled_public_activity=Þessi notandi hefur slökkt á opinberum sýnileika virkninnar. + [settings] profile=Notandasíða account=Reikningur @@ -704,7 +705,6 @@ editor.cancel=Hætta við editor.fail_to_update_file_summary=Villuskilaboð: commits.commits=Framlög -commits.find=Leita commits.author=Höfundur commits.message=Skilaboð commits.date=Dagsetning @@ -728,7 +728,6 @@ projects.edit=Breyta Verkefnum projects.modify=Uppfæra Verkefni projects.type.none=Ekkert projects.template.desc=Sniðmát -projects.type.uncategorized=Óflokkuð projects.column.edit_title=Heiti projects.column.new_title=Heiti projects.column.color=Litað @@ -992,11 +991,6 @@ activity.git_stats_deletion_n=%d eyðingar contributors.contribution_type.commits=Framlög -search=Leita -search.fuzzy=Óljóst -search.code_no_results=Enginn samsvarandi frumkóði fannst eftur þínum leitarorðum. -search.code_search_unavailable=Sem stendur er kóðaleit ekki í boði. Vinsamlegast hafðu samband við síðustjórann þinn. - settings=Stillingar settings.options=Hugbúnaðarsafn settings.collaboration.write=Skrifa @@ -1163,6 +1157,8 @@ teams.all_repositories=Öll hugbúnaðarsöfn [admin] repositories=Hugbúnaðarsöfn config=Stilling +config_summary=Yfirlit +config_settings=Stillingar first_page=Byrjun last_page=Síðasta total=Samtals: %d @@ -1201,9 +1197,6 @@ orgs.members=Meðlimar repos.owner=Eigandi repos.name=Heiti -repos.watches=Fylgist með -repos.stars=Eftirlæti -repos.forks=Skiptingar repos.issues=Vandamál repos.size=Stærð diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index 0e38c1ffb9..cc379e8109 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -116,6 +116,15 @@ concept_user_organization=Organizzazione name=Nome value=Valore +filter=Filtro +filter.is_archived=Archiviato +filter.is_template=Template +filter.public=Pubblico +filter.private=Privati + + +[search] + [aria] [heatmap] @@ -254,7 +263,6 @@ collaborative_repos=Repository Condivisi my_orgs=Le mie Organizzazioni my_mirrors=I miei Mirror view_home=Vedi %s -search_repos=Trova un repository… filter=Altro filtri filter_by_team_repositories=Filtra per repository del team feed_of=`Feed di "%s"` @@ -275,15 +283,7 @@ issues.in_your_repos=Nei tuoi repository repos=Repository users=Utenti organizations=Organizzazioni -search=Cerca code=Codice -search.fuzzy=Fuzzy -search.match=Corrispondenze -code_search_unavailable=Attualmente la ricerca di codice non è disponibile. Contatta l'amministratore del sito. -repo_no_results=Nessuna repository corrispondente. -user_no_results=Nessun utente corrispondente. -org_no_results=Nessun'organizzazione corrispondente trovata. -code_no_results=Nessun codice sorgente corrispondente ai termini di ricerca. code_last_indexed_at=Ultimo indicizzato %s [auth] @@ -297,7 +297,6 @@ remember_me=Ricorda questo dispositivo forgot_password_title=Password Dimenticata forgot_password=Password dimenticata? sign_up_now=Hai bisogno di un account? Registrati adesso. -confirmation_mail_sent_prompt=Una nuova email di conferma è stata inviata a <b>%s</b>. Per favore controlla la tua posta in arrivo nelle prossime %s per completare il processo di registrazione. must_change_password=Aggiorna la tua password allow_password_change=Richiede all'utente di cambiare la password (scelta consigliata) reset_password_mail_sent_prompt=Una email di conferma è stata inviata a <b>%s</b>. Per favore controlla la tua posta in arrivo nelle prossime %s per completare il processo di reset della password. @@ -507,6 +506,7 @@ user_bio=Biografia disabled_public_activity=L'utente ha disabilitato la vista pubblica dell'attività. + [settings] profile=Profilo account=Account @@ -634,7 +634,6 @@ gpg_invalid_token_signature=La chiave GPG fornita, la firma e il token non corri gpg_token_required=Devi fornire una firma per il token sottostante gpg_token=Token gpg_token_help=È possibile generare una firma utilizzando: -gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig gpg_token_signature=Firma GPG corazzata key_signature_gpg_placeholder=Comincia con '-----BEGIN PGP SIGNATURE-----' ssh_key_verified=Chiave Verificata @@ -787,7 +786,6 @@ already_forked=Hai già fatto il fork di %s fork_to_different_account=Fai Fork a un account diverso fork_visibility_helper=La visibilità di un repository forkato non può essere modificata. use_template=Usa questo modello -clone_in_vsc=Clona nel codice VS download_zip=Scarica ZIP download_tar=Scarica TAR.GZ download_bundle=Scarica BUNDLE @@ -1051,8 +1049,6 @@ editor.revert=Ripristina %s su: commits.desc=Sfoglia la cronologia di modifiche del codice rogente. commits.commits=Commit commits.nothing_to_compare=Questi rami sono uguali. -commits.search=Ricerca commits… -commits.find=Cerca commits.search_all=Tutti i branch commits.author=Autore commits.message=Messaggio @@ -1097,7 +1093,6 @@ projects.type.basic_kanban=Basic Kanban projects.type.bug_triage=Bug Triage projects.template.desc=Template di progetto projects.template.desc_helper=Seleziona un modello di progetto per iniziare -projects.type.uncategorized=Senza categoria projects.column.edit_title=Nome projects.column.new_title=Nome projects.column.color=Colore @@ -1409,7 +1404,6 @@ pulls.compare_compare=esegui un pull da pulls.switch_comparison_type=Cambia tipo di confronto pulls.switch_head_and_base=Testa e base di commutazione pulls.filter_branch=Filtra branch -pulls.no_results=Nessun risultato trovato. pulls.nothing_to_compare=Questi rami sono uguali. Non c'è alcuna necessità di creare una pull request. pulls.nothing_to_compare_and_allow_empty_pr=Questi rami sono uguali. Questa PR sarà vuota. pulls.has_pull_request=`Una pull request tra questi rami esiste già: <a href="%[1]s">%[2]s#%[3]d</a>` @@ -1626,14 +1620,6 @@ activity.git_stats_deletion_n=%d cancellazioni contributors.contribution_type.commits=Commit -search=Ricerca -search.search_repo=Ricerca repository -search.fuzzy=Fuzzy -search.match=Corrispondenze -search.results=Risultati della ricerca per "%s" in <a href="%s">%s</a> -search.code_no_results=Nessun codice sorgente corrispondente al termine di ricerca trovato. -search.code_search_unavailable=Attualmente la ricerca di codice non è disponibile. Contatta l'amministratore del sito. - settings=Impostazioni settings.desc=Impostazioni ti permette di gestire le impostazioni del repository settings.options=Repository @@ -1760,7 +1746,6 @@ settings.delete_collaborator=Rimuovi settings.collaborator_deletion=Rimuovi collaboratore settings.collaborator_deletion_desc=Rimuovere un collaboratore revocherà l'accesso a questo repository. Continuare? settings.remove_collaborator_success=Il collaboratore è stato rimosso. -settings.search_user_placeholder=Ricerca utente… settings.org_not_allowed_to_be_collaborator=Le organizzazioni non possono essere aggiunte come un collaboratore. settings.change_team_access_not_allowed=La modifica dell'accesso al team per il repository è stato limitato al solo proprietario dell'organizzazione settings.team_not_in_organization=Il team non è nella stessa organizzazione del repository @@ -1768,7 +1753,6 @@ settings.teams=Gruppi settings.add_team=Aggiungi Squadra settings.add_team_duplicate=Il team ha già il repository settings.add_team_success=Il team ha ora accesso al repository. -settings.search_team=Cerca Squadra… settings.change_team_permission_tip=Il permesso del team è impostato sulla pagina delle impostazioni del team e non può essere modificato per repository settings.delete_team_tip=Questo team ha accesso a tutte le repository e non può essere rimosso settings.remove_team_success=L'accesso del team al repository è stato rimosso. @@ -1907,9 +1891,7 @@ settings.protect_whitelist_committers=Lista bianch push ristretti settings.protect_whitelist_committers_desc=Solo gli utenti o i team nella whitelist potranno pushare su questo ramo (ma non forzare il push). settings.protect_whitelist_deploy_keys=Chiavi di deploy in whitelist con permessi di scrittura per il push. settings.protect_whitelist_users=Utenti nella whitelist per pushare: -settings.protect_whitelist_search_users=Cerca utenti… settings.protect_whitelist_teams=Team nella whitelist per pushare: -settings.protect_whitelist_search_teams=Ricerca team… settings.protect_merge_whitelist_committers=Attiva la whitelist per i merge settings.protect_merge_whitelist_committers_desc=Consentire soltanto agli utenti o ai team in whitelist il permesso di unire le pull request di questo branch. settings.protect_merge_whitelist_users=Utenti nella whitelist per il merging: @@ -2218,7 +2200,6 @@ teams.write_permission_desc=Questo team concede l'accesso di <strong>Scrittura</ teams.admin_permission_desc=Questo team concede l'accesso di <strong>Amministratore</strong>: i membri possono leggere da, pushare su e aggiungere collaboratori ai repository del team. teams.create_repo_permission_desc=Inoltre, questo team concede il permesso di <strong>Creare repository</strong>: i membri possono creare nuove repository nell'organizzazione. teams.repositories=Repository di Squadra -teams.search_repo_placeholder=Ricerca repository… teams.remove_all_repos_title=Rimuovi tutti i repository del team teams.remove_all_repos_desc=Questo rimuoverà tutte le repository dal team. teams.add_all_repos_title=Aggiungi tutti i repository @@ -2243,6 +2224,8 @@ hooks=Webhooks authentication=Fonti di autenticazione emails=Email Utente config=Configurazione +config_summary=Riepilogo +config_settings=Impostazioni notices=Avvisi di sistema monitor=Monitoraggio first_page=Prima @@ -2397,9 +2380,6 @@ repos.unadopted.no_more=Nessun repository non adottato trovato repos.owner=Proprietario repos.name=Nome repos.private=Privati -repos.watches=Segue -repos.stars=Voti -repos.forks=Fork repos.issues=Problemi repos.size=Dimensione @@ -2515,7 +2495,6 @@ auths.tip.nextcloud=`Registra un nuovo OAuth sulla tua istanza utilizzando il se auths.tip.dropbox=Crea una nuova applicazione su https://www.dropbox.com/developers/apps auths.tip.facebook=`Registra una nuova applicazione su https://developers.facebook.com/apps e aggiungi il prodotto "Facebook Login"` auths.tip.github=Registra una nuova applicazione OAuth su https://github.com/settings/applications/new -auths.tip.gitlab=Registra una nuova applicazione su https://gitlab.com/profile/applications auths.tip.google_plus=Ottieni le credenziali del client OAuth2 dalla console API di Google su https://console.developers.google.com/ auths.tip.openid_connect=Utilizza l'OpenID Connect Discovery URL (<server>/.well-known/openid-configuration) per specificare gli endpoint auths.tip.twitter=Vai su https://dev.twitter.com/apps, crea una applicazione e assicurati che l'opzione "Allow this application to be used to Sign In with Twitter" sia abilitata diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index af06a78642..d5c2885f00 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -142,6 +142,15 @@ confirm_delete_selected=選択したすべてのアイテムを削除してよ name=名称 value=値 +filter=フィルター +filter.is_archived=アーカイブ +filter.is_template=テンプレート +filter.public=公開 +filter.private=プライベート + + +[search] + [aria] navbar=ナビゲーションバー footer=フッター @@ -315,7 +324,6 @@ collaborative_repos=共同リポジトリ my_orgs=自分の組織 my_mirrors=自分のミラー view_home=%s を表示 -search_repos=リポジトリを探す… filter=その他のフィルター filter_by_team_repositories=チームリポジトリで絞り込み feed_of=`"%s" のフィード` @@ -336,20 +344,8 @@ issues.in_your_repos=あなたのリポジトリ repos=リポジトリ users=ユーザー organizations=組織 -search=検索 go_to=開く code=コード -search.type.tooltip=検索タイプ -search.fuzzy=あいまい -search.fuzzy.tooltip=検索ワードにおおよそ一致している結果も含めます -search.match=一致 -search.match.tooltip=検索ワードに一致する結果だけを含めます -code_search_unavailable=現在コード検索は利用できません。 サイト管理者にお問い合わせください。 -repo_no_results=一致するリポジトリが見つかりません。 -user_no_results=一致するユーザーが見つかりません。 -org_no_results=一致する組織が見つかりません。 -code_no_results=検索ワードに一致するソースコードが見つかりません。 -code_search_results=`"%s" の検索結果` code_last_indexed_at=最終取得 %s relevant_repositories_tooltip=フォークリポジトリや、トピック、アイコン、説明のいずれも無いリポジトリは表示されません。 relevant_repositories=妥当と思われるリポジトリのみを表示しています。 <a href="%s">フィルタリングしない結果を表示</a>。 @@ -367,7 +363,6 @@ forgot_password_title=パスワードを忘れた forgot_password=パスワードをお忘れですか? sign_up_now=アカウントが必要ですか? 今すぐ登録しましょう。 sign_up_successful=アカウントは無事に作成されました。ようこそ! -confirmation_mail_sent_prompt=<b>%s</b> に確認メールを送信しました。 %s以内に受信トレイを確認し、登録手続きを完了してください。 must_change_password=パスワードの更新 allow_password_change=ユーザーはパスワードの変更が必要 (推奨) reset_password_mail_sent_prompt=<b>%s</b> に確認メールを送信しました。 %s以内に受信トレイを確認し、アカウント回復手続きを完了してください。 @@ -617,6 +612,13 @@ form.name_reserved=ユーザー名 "%s" は予約されています。 form.name_pattern_not_allowed=`"%s" の形式はユーザー名に使用できません。` form.name_chars_not_allowed=ユーザー名 "%s" には無効な文字が含まれています。 +block.block=ブロック +block.block.user=ユーザーをブロック +block.block.org=組織向けにユーザーをブロック +block.block.failure=ユーザーのブロックに失敗しました: %s +block.unblock=ブロックを解除 +block.unblock.failure=ユーザーのブロック解除に失敗しました: %s + [settings] profile=プロフィール account=アカウント @@ -761,7 +763,6 @@ gpg_invalid_token_signature=入力されたGPG鍵、署名、トークンが合 gpg_token_required=以下のトークンの署名を入力する必要があります gpg_token=トークン gpg_token_help=署名はこの方法で生成できます: -gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig gpg_token_signature=Armor形式のGPG署名 key_signature_gpg_placeholder=先頭は '-----BEGIN PGP SIGNATURE-----' verify_gpg_key_success=GPG鍵 "%s" を確認しました。 @@ -955,7 +956,6 @@ fork_branch=フォークにクローンされるブランチ all_branches=すべてのブランチ fork_no_valid_owners=このリポジトリには有効なオーナーがいないため、フォークできません。 use_template=このテンプレートを使用 -clone_in_vsc=VSCodeでクローン download_zip=ZIPファイルをダウンロード download_tar=TAR.GZファイルをダウンロード download_bundle=バンドルをダウンロード @@ -990,6 +990,7 @@ mirror_prune=Prune mirror_prune_desc=不要になった古いリモートトラッキング参照を削除 mirror_interval=ミラー間隔 (有効な時間の単位は'h'、'm'、's')。 定期的な同期を無効にする場合は0。(最小間隔: %s) mirror_interval_invalid=ミラー間隔が不正です。 +mirror_sync=前回の同期 mirror_sync_on_commit=コミットがプッシュされたときに同期 mirror_address=クローンするURL mirror_address_desc=必要な資格情報は「認証」セクションに設定してください。 @@ -1191,6 +1192,8 @@ audio_not_supported_in_browser=このブラウザーはHTML5のaudioタグをサ stored_lfs=Git LFSで保管されています symbolic_link=シンボリック リンク executable_file=実行ファイル +vendored=ベンダーファイル +generated=生成ファイル commit_graph=コミットグラフ commit_graph.select=ブランチを選択 commit_graph.hide_pr_refs=プルリクエストを非表示 @@ -1277,9 +1280,7 @@ commits.desc=ソースコードの変更履歴を参照します。 commits.commits=コミット commits.no_commits=共通のコミットはありません。 "%s" と "%s" の履歴はすべて異なっています。 commits.nothing_to_compare=二つのブランチは同じ内容です。 -commits.search=コミットの検索… commits.search.tooltip=`キーワード "author:"、"committer:"、"after:"、"before:" を付けて指定できます。 例 "revert author:Alice before:2019-01-13"` -commits.find=検索 commits.search_all=すべてのブランチ commits.author=作成者 commits.message=メッセージ @@ -1330,7 +1331,6 @@ projects.type.basic_kanban=基本的なカンバン projects.type.bug_triage=バグ トリアージ projects.template.desc=テンプレート projects.template.desc_helper=開始するプロジェクトテンプレートを選択 -projects.type.uncategorized=未分類 projects.column.edit=列を編集 projects.column.edit_title=名称 projects.column.new_title=名称 @@ -1338,10 +1338,7 @@ projects.column.new_submit=列を作成 projects.column.new=新しい列 projects.column.set_default=デフォルトに設定 projects.column.set_default_desc=この列を未分類のイシューやプルリクエストが入るデフォルトの列にします -projects.column.unset_default=デフォルトを解除 -projects.column.unset_default_desc=この列からデフォルト列の設定を解除します projects.column.delete=列を削除 -projects.column.deletion_desc=プロジェクト列を削除すると、関連するすべてのイシューが '未分類' に移動します。 続行しますか? projects.column.color=カラー projects.open=オープン projects.close=クローズ @@ -1453,7 +1450,6 @@ issues.filter_sort.moststars=スターが多い順 issues.filter_sort.feweststars=スターが少ない順 issues.filter_sort.mostforks=フォークが多い順 issues.filter_sort.fewestforks=フォークが少ない順 -issues.keyword_search_unavailable=現在キーワード検索は利用できません。 サイト管理者にお問い合わせください。 issues.action_open=オープン issues.action_close=クローズ issues.action_label=ラベル @@ -1705,7 +1701,6 @@ pulls.compare_compare=プル元 pulls.switch_comparison_type=比較の種類を切り替える pulls.switch_head_and_base=ヘッドとベースを切り替える pulls.filter_branch=ブランチの絞り込み -pulls.no_results=結果が見つかりませんでした。 pulls.show_all_commits=すべてのコミットを表示 pulls.show_changes_since_your_last_review=前回の自分のレビューからの変更を表示 pulls.showing_only_single_commit=コミット %[1]s の変更だけを表示しています @@ -1714,6 +1709,7 @@ pulls.select_commit_hold_shift_for_range=コミットを選択。シフトを押 pulls.review_only_possible_for_full_diff=すべての差分を表示しているときだけレビューが可能です pulls.filter_changes_by_commit=コミットで絞り込み pulls.nothing_to_compare=同じブランチ同士のため、 プルリクエストを作成する必要がありません。 +pulls.nothing_to_compare_have_tag=選択したブランチ/タグは同一のものです。 pulls.nothing_to_compare_and_allow_empty_pr=これらのブランチは内容が同じです。 空のプルリクエストになります。 pulls.has_pull_request=`同じブランチのプルリクエストはすでに存在します: <a href="%[1]s">%[2]s#%[3]d</a>` pulls.create=プルリクエストを作成 @@ -1772,6 +1768,7 @@ pulls.merge_pull_request=マージコミットを作成 pulls.rebase_merge_pull_request=リベース後にファストフォワード pulls.rebase_merge_commit_pull_request=リベース後にマージコミット作成 pulls.squash_merge_pull_request=スカッシュコミットを作成 +pulls.fast_forward_only_merge_pull_request=ファストフォワードのみ pulls.merge_manually=手動マージ済みにする pulls.merge_commit_id=マージコミットID pulls.require_signed_wont_sign=ブランチでは署名されたコミットが必須ですが、このマージでは署名がされません @@ -1908,6 +1905,8 @@ wiki.page_name_desc=この Wiki ページの名前を入力してください。 wiki.original_git_entry_tooltip=フレンドリーリンクを使用する代わりにオリジナルのGitファイルを表示します。 activity=アクティビティ +activity.navbar.pulse=Pulse +activity.navbar.contributors=貢献者 activity.period.filter_label=期間: activity.period.daily=1日 activity.period.halfweekly=3日 @@ -1973,18 +1972,10 @@ activity.git_stats_and_deletions=、 activity.git_stats_deletion_1=%d行削除 activity.git_stats_deletion_n=%d行削除 +contributors.contribution_type.filter_label=実績タイプ: contributors.contribution_type.commits=コミット - -search=検索 -search.search_repo=リポジトリを検索 -search.type.tooltip=検索タイプ -search.fuzzy=あいまい -search.fuzzy.tooltip=検索ワードにおおよそ一致している結果も含めます -search.match=一致 -search.match.tooltip=検索ワードに一致する結果だけを含めます -search.results=<a href="%[2]s">%[3]s</a> 内での "%[1]s" の検索結果 -search.code_no_results=検索ワードに一致するソースコードが見つかりません。 -search.code_search_unavailable=現在コード検索は利用できません。 サイト管理者にお問い合わせください。 +contributors.contribution_type.additions=追加 +contributors.contribution_type.deletions=削除 settings=設定 settings.desc=設定では、リポジトリの設定を管理することができます。 @@ -2064,6 +2055,7 @@ settings.pulls.default_allow_edits_from_maintainers=デフォルトでメンテ settings.releases_desc=リリースを有効にする settings.packages_desc=リポジトリパッケージレジストリを有効にする settings.projects_desc=リポジトリプロジェクトを有効にする +settings.projects_mode_all=すべてのプロジェクト settings.actions_desc=Actionsを有効にする settings.admin_settings=管理者用設定 settings.admin_enable_health_check=リポジトリのヘルスチェックを有効にする (git fsck) @@ -2138,7 +2130,6 @@ settings.delete_collaborator=削除 settings.collaborator_deletion=共同作業者の削除 settings.collaborator_deletion_desc=共同作業者を削除し、このリポジトリへのアクセス権を取り消します。 続行しますか? settings.remove_collaborator_success=共同作業者を削除しました。 -settings.search_user_placeholder=ユーザーを検索… settings.org_not_allowed_to_be_collaborator=組織を共同作業者として追加することはできません。 settings.change_team_access_not_allowed=リポジトリに対するチームアクセス権の変更は、組織のオーナーのみに制限されています。 settings.team_not_in_organization=チームがリポジトリと同じ組織に属していません。 @@ -2146,7 +2137,6 @@ settings.teams=チーム settings.add_team=チームを追加 settings.add_team_duplicate=チームにはすでにこのリポジトリが登録されています。 settings.add_team_success=チームがこのリポジトリにアクセスできるようになりました。 -settings.search_team=チームを検索… settings.change_team_permission_tip=チームの権限はチーム設定ページで設定されており、リポジトリごとに変更することはできません settings.delete_team_tip=このチームはすべてのリポジトリにアクセスでき、削除できません settings.remove_team_success=チームのこのリポジトリへのアクセス権を削除しました。 @@ -2299,9 +2289,7 @@ settings.protect_whitelist_committers=ホワイトリストでプッシュを制 settings.protect_whitelist_committers_desc=ホワイトリストに登録したユーザーまたはチームにのみ、このブランチへのプッシュが許可されます。(強制プッシュ以外) settings.protect_whitelist_deploy_keys=プッシュ可能な書き込み権限を持つデプロイキーをホワイトリストに含める。 settings.protect_whitelist_users=プッシュ・ホワイトリストに含むユーザー: -settings.protect_whitelist_search_users=ユーザーを検索… settings.protect_whitelist_teams=プッシュ・ホワイトリストに含むチーム: -settings.protect_whitelist_search_teams=チームを検索… settings.protect_merge_whitelist_committers=マージ・ホワイトリストを有効にする settings.protect_merge_whitelist_committers_desc=ホワイトリストに登録したユーザーまたはチームにだけ、このブランチに対するプルリクエストのマージを許可します。 settings.protect_merge_whitelist_users=マージ・ホワイトリストに含むユーザー: @@ -2322,6 +2310,8 @@ settings.protect_approvals_whitelist_users=ホワイトリストに含めるレ settings.protect_approvals_whitelist_teams=ホワイトリストに含めるレビューチーム: settings.dismiss_stale_approvals=古くなった承認を取り消す settings.dismiss_stale_approvals_desc=プルリクエストの内容を変える新たなコミットがブランチにプッシュされた場合、以前の承認を取り消します。 +settings.ignore_stale_approvals=古くなった承認を無視する +settings.ignore_stale_approvals_desc=古いコミットに対して行われた承認 (古いレビュー) を、PRの承認数にカウントしません。 古いレビューが取り消される場合は関係ありません。 settings.require_signed_commits=コミット署名必須 settings.require_signed_commits_desc=署名されていない場合、または署名が検証できなかった場合は、このブランチへのプッシュを拒否します。 settings.protect_branch_name_pattern=保護ブランチ名のパターン @@ -2377,6 +2367,7 @@ settings.archive.error=リポジトリのアーカイブ設定でエラーが発 settings.archive.error_ismirror=ミラーのリポジトリはアーカイブできません。 settings.archive.branchsettings_unavailable=ブランチ設定は、アーカイブリポジトリでは使用できません。 settings.archive.tagsettings_unavailable=タグ設定は、アーカイブリポジトリでは使用できません。 +settings.archive.mirrors_unavailable=リポジトリがアーカイブされている場合、ミラーは利用できません。 settings.unarchive.button=アーカイブ解除 settings.unarchive.header=このリポジトリをアーカイブ解除 settings.unarchive.text=リポジトリのアーカイブを解除すると、コミット、プッシュ、新規のイシューやプルリクエストを受け付ける機能が復活します。 @@ -2543,7 +2534,6 @@ branch.default_deletion_failed=ブランチ "%s" はデフォルトブランチ branch.restore=ブランチ "%s" の復元 branch.download=ブランチ "%s" をダウンロード branch.rename=ブランチ名 "%s" を変更 -branch.search=ブランチを検索 branch.included_desc=このブランチはデフォルトブランチに含まれています branch.included=埋没 branch.create_new_branch=このブランチをもとに作成します: @@ -2576,6 +2566,11 @@ error.csv.unexpected=このファイルは %d 行目の %d 文字目に予期し error.csv.invalid_field_count=このファイルは %d 行目のフィールドの数が正しくないため表示できません。 [graphs] +component_loading=%sを読み込み中... +component_loading_failed=%sを読み込めませんでした +component_loading_info=少し時間がかかるかもしれません… +component_failed_to_load=予期しないエラーが発生しました。 +contributors.what=実績 [org] org_name_holder=組織名 @@ -2681,7 +2676,6 @@ teams.write_permission_desc=このチームは<strong>書き込み</strong>ア teams.admin_permission_desc=このチームは<strong>管理者</strong>アクセス権を持ちます: メンバーはチームリポジトリの読み取り、プッシュ、共同作業者の追加が可能です。 teams.create_repo_permission_desc=さらに、このチームには<strong>リポジトリの作成</strong>権限が与えられています: メンバーは組織のリポジトリを新たに作成できます。 teams.repositories=チームのリポジトリ -teams.search_repo_placeholder=リポジトリを検索… teams.remove_all_repos_title=チームリポジトリをすべて除去 teams.remove_all_repos_desc=チームからすべてのリポジトリを除去します。 teams.add_all_repos_title=すべてのリポジトリを追加 @@ -2703,6 +2697,7 @@ teams.invite.description=下のボタンをクリックしてチームに参加 [admin] dashboard=ダッシュボード +self_check=セルフチェック identity_access=アイデンティティとアクセス users=ユーザーアカウント organizations=組織 @@ -2713,6 +2708,8 @@ integrations=連携 authentication=認証ソース emails=ユーザーメールアドレス config=設定 +config_summary=サマリー +config_settings=設定 notices=システム通知 monitor=モニタリング first_page=最初 @@ -2748,6 +2745,7 @@ dashboard.delete_missing_repos=Gitファイルが存在しないリポジトリ dashboard.delete_missing_repos.started=Gitファイルが存在しないリポジトリをすべて削除するタスクを開始しました。 dashboard.delete_generated_repository_avatars=自動生成したリポジトリアバターを削除 dashboard.sync_repo_branches=Gitデータからデータベースへ不足しているブランチを同期 +dashboard.sync_repo_tags=Gitデータからデータベースへタグを同期 dashboard.update_mirrors=ミラーの更新 dashboard.repo_health_check=全リポジトリのヘルスチェック dashboard.check_repo_stats=全リポジトリの統計情報を更新 @@ -2802,6 +2800,7 @@ dashboard.stop_endless_tasks=終わらないタスクを停止 dashboard.cancel_abandoned_jobs=放置されたままのジョブをキャンセル dashboard.start_schedule_tasks=スケジュールタスクを開始 dashboard.sync_branch.started=ブランチの同期を開始しました +dashboard.sync_tag.started=タグの同期を開始しました dashboard.rebuild_issue_indexer=イシューインデクサーの再構築 users.user_manage_panel=ユーザーアカウント管理 @@ -2887,9 +2886,6 @@ repos.unadopted.no_more=未登録のリポジトリはありません repos.owner=オーナー repos.name=名称 repos.private=プライベート -repos.watches=ウォッチ -repos.stars=スター -repos.forks=フォーク repos.issues=イシュー repos.size=サイズ repos.lfs_size=LFSサイズ @@ -3014,7 +3010,6 @@ auths.tip.nextcloud=新しいOAuthコンシューマーを、インスタンス 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.google_plus=OAuth2クライアント資格情報を、Google APIコンソール https://console.developers.google.com/ から取得してください。 auths.tip.openid_connect=OpenID Connect DiscoveryのURL (<server>/.well-known/openid-configuration) をエンドポイントとして指定してください auths.tip.twitter=https://dev.twitter.com/apps へアクセスしてアプリケーションを作成し、“Allow this application to be used to Sign in with Twitter”オプションを有効にしてください。 @@ -3228,6 +3223,12 @@ notices.desc=説明 notices.op=操作 notices.delete_success=システム通知を削除しました。 +self_check.no_problem_found=今のところ問題は見つかっていません。 +self_check.database_collation_mismatch=データベースに想定される照合順序: %s +self_check.database_collation_case_insensitive=データベースは照合順序 %s を使用しており、大文字小文字を区別しません。 Giteaはその照合順序でも動作するかもしれませんが、まれに期待どおり動作しないケースがあるかもしれません。 +self_check.database_inconsistent_collation_columns=データベースは照合順序 %s を使用していますが、以下のカラムはそれと一致しない照合順序を使用しており、予期せぬ問題を引き起こす可能性があります。 +self_check.database_fix_mysql=MySQL/MariaDBユーザーの方は、"gitea doctor convert" コマンドを使用することで、照合順序の問題を修正できます。 また、"ALTER ... COLLATE ..." のSQLを手で実行しても修正することができます。 +self_check.database_fix_mssql=MSSQLユーザーの方は、問題を修正するには今のところ "ALTER ... COLLATE ..." のSQLを手で実行するしかありません。 [action] create_repo=がリポジトリ <a href="%s">%s</a> を作成しました @@ -3415,6 +3416,7 @@ rpm.distros.suse=SUSE系ディストリビューションの場合 rpm.install=パッケージをインストールするには、次のコマンドを実行します: rpm.repository=リポジトリ情報 rpm.repository.architectures=Architectures +rpm.repository.multiple_groups=このパッケージは複数のグループで利用可能です。 rubygems.install=gem を使用してパッケージをインストールするには、次のコマンドを実行します: rubygems.install2=または Gemfile に追加します: rubygems.dependencies.runtime=実行用依存関係 @@ -3567,6 +3569,7 @@ variables.none=変数はまだありません。 variables.deletion=変数を削除 variables.deletion.description=変数の削除は恒久的で元に戻すことはできません。 続行しますか? variables.description=変数は特定のActionsに渡されます。 それ以外で読み出されることはありません。 +variables.id_not_exist=IDが%dの変数は存在しません。 variables.edit=変数の編集 variables.deletion.failed=変数を削除できませんでした。 variables.deletion.success=変数を削除しました。 diff --git a/options/locale/locale_ko-KR.ini b/options/locale/locale_ko-KR.ini index ed0bb897c4..3e9679575c 100644 --- a/options/locale/locale_ko-KR.ini +++ b/options/locale/locale_ko-KR.ini @@ -84,6 +84,12 @@ concept_user_organization=조직 name=이름 +filter.is_template=템플릿 +filter.private=비공개 + + +[search] + [aria] [heatmap] @@ -199,7 +205,6 @@ collaborative_repos=협업 저장소 my_orgs=내 조직 my_mirrors=내 미러 저장소들 view_home=%s 보기 -search_repos=저장소 찾기.. show_private=비공개 @@ -210,12 +215,7 @@ issues.in_your_repos=당신의 저장소에 repos=저장소 users=유저 organizations=조직 -search=검색 code=코드 -repo_no_results=일치하는 레포지토리가 없습니다. -user_no_results=일치하는 사용자가 없습니다. -org_no_results=일치하는 조직이 없습니다. -code_no_results=검색어와 일치하는 소스코드가 없습니다. [auth] create_new_account=계정 등록 @@ -226,7 +226,6 @@ disable_register_mail=계정 등록을 위한 이메일 검증이 비활성화 forgot_password_title=비밀번호 찾기 forgot_password=비밀번호를 잊으셨나요? sign_up_now=계정이 필요하신가요? 지금 가입하세요. -confirmation_mail_sent_prompt=새로운 확인 메일이 <b>%s</b>로 전송되었습니다. 받은 편지함으로 도착한 메일을 %s 안에 확인해서 등록 절차를 완료하십시오. must_change_password=비밀번호를 변경하세요. allow_password_change=사용자에게 비밀번호 변경을 요청 (권장됨) reset_password_mail_sent_prompt=확인 메일이 <b>%s</b>로 전송되었습니다. 받은 편지함으로 도착한 메일을 %s 안에 확인해서 비밀번호 찾기 절차를 완료하십시오. @@ -363,6 +362,7 @@ unfollow=추적해제 user_bio=소개 + [settings] profile=프로필 account=계정 @@ -661,8 +661,6 @@ editor.add_subdir=경로 추가... commits.desc=소스 코드 변경 내역 탐색 commits.commits=커밋 -commits.search=커밋 찾기... -commits.find=검색 commits.search_all=모든 브랜치 commits.author=작성자 commits.message=메시지 @@ -844,7 +842,6 @@ pulls.compare_changes=새 풀 리퀘스트 pulls.compare_base=병합하기 pulls.compare_compare=다음으로부터 풀 pulls.filter_branch=Filter Branch -pulls.no_results=결과 없음 pulls.create=풀 리퀘스트 생성 pulls.title_desc="<code>%[2]s</code> 에서 <code id=\"branch_target\">%[3]s</code> 로 %[1]d commits 를 머지하려 합니다" pulls.merged_title_desc=<code>%[2]s</code> 에서 <code>%[3]s</code> 로 %[1]d commits 를 머지했습니다 %[4]s @@ -952,11 +949,6 @@ activity.published_release_label=배포됨 contributors.contribution_type.commits=커밋 -search=검색 -search.search_repo=저장소 검색 -search.results="<a href=\"%s\">%s</a> 에서 \"%s\" 에 대한 검색 결과" -search.code_no_results=검색어와 일치하는 소스코드가 없습니다. - settings=설정 settings.desc=설정은 저장소 설정을 관리할 수 있습니다. settings.options=저장소 @@ -1016,7 +1008,6 @@ settings.add_collaborator=새 공동작업자 추가 settings.add_collaborator_success=공동작업자가 추가 되었습니다. settings.delete_collaborator=제거 settings.collaborator_deletion=공동작업자 삭제 -settings.search_user_placeholder=사용자 검색... settings.teams=팀 settings.add_webhook=Webhook 추가 settings.webhook_deletion=Webhook 삭제 @@ -1090,8 +1081,6 @@ settings.branch_protection='<b>%s</b>' 브랜치 보호 settings.protect_this_branch=브랜치 보호 활성화 settings.protect_disable_push=푸시 끄기 settings.protect_enable_push=푸시 켜기 -settings.protect_whitelist_search_users=사용자 찾기... -settings.protect_whitelist_search_teams=팀 찾기... settings.protect_merge_whitelist_committers=머지 화이트리스트 활성화 settings.protect_required_approvals=필요한 승인: settings.protect_approvals_whitelist_users=화이트리스트된 리뷰어: @@ -1226,7 +1215,6 @@ teams.add_team_member=팀 구성원 추가 teams.delete_team_title=팀 삭제 teams.delete_team_success=팀이 삭제되었습니다. teams.repositories=팀 저장소 -teams.search_repo_placeholder=저장소 찾기... teams.add_duplicate_users=사용자가 이미 팀 멤버입니다. teams.members.none=이 팀에 멤버가 없습니다. @@ -1237,6 +1225,8 @@ organizations=조직 repositories=저장소 authentication=인증 소스 config=설정 +config_summary=요약 +config_settings=설정 notices=시스템 공지 monitor=모니터링 first_page=처음 @@ -1323,9 +1313,6 @@ repos.repo_manage_panel=저장소 관리 repos.owner=소유자 repos.name=이름 repos.private=비공개 -repos.watches=지켜보기 -repos.stars=별 -repos.forks=포크 repos.issues=이슈 repos.size=크기 diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 3c3513ad48..0a2729980b 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -141,6 +141,15 @@ confirm_delete_selected=Apstiprināt, lai izdzēstu visus atlasītos vienumus? name=Nosaukums value=Vērtība +filter=Filtrs +filter.is_archived=Arhivētie +filter.is_template=Sagatave +filter.public=Publiska +filter.private=Privāts + + +[search] + [aria] navbar=Navigācijas josla footer=Kājene @@ -314,7 +323,6 @@ collaborative_repos=Sadarbības repozitoriji my_orgs=Manas organizācijas my_mirrors=Mani spoguļi view_home=Skatīties %s -search_repos=Meklēt repozitoriju… filter=Citi filtri filter_by_team_repositories=Filtrēt pēc komandas repozitorijiem feed_of=`"%s" plūsma` @@ -335,20 +343,8 @@ issues.in_your_repos=Jūsu repozitorijos repos=Repozitoriji users=Lietotāji organizations=Organizācijas -search=Meklēt go_to=Iet uz code=Kods -search.type.tooltip=Meklēšanas veids -search.fuzzy=Aptuveni -search.fuzzy.tooltip=Iekļaut meklēšanas rezultātos arī aptuvenas sakritības -search.match=Precīzi -search.match.tooltip=Iekļaut meklēšanas rezultātos tikai precīzas sakritības -code_search_unavailable=Pašlaik koda meklēšana nav pieejama. Sazinieties ar lapas administratoru. -repo_no_results=Netika atrasts neviens repozitorijs, kas atbilstu kritērijiem. -user_no_results=Netika atrasts neviens lietotājs, kas atbilstu kritērijiem. -org_no_results=Netika atrasta neviena organizācija, kas atbilstu kritērijiem. -code_no_results=Netika atrasts pirmkods, kas atbilstu kritērijiem. -code_search_results=`Meklēšanas rezultāti "%s"` code_last_indexed_at=Pēdējo reizi indeksēts %s relevant_repositories_tooltip=Repozitoriju, kas ir atdalīti vai kuriem nav tēmas, ikonas un apraksta ir paslēpti. relevant_repositories=Tikai būtiskie repozitoriji tiek rādīti, <a href="%s">pārādīt nefiltrētus rezultātus</a>. @@ -366,7 +362,6 @@ forgot_password_title=Aizmirsu paroli forgot_password=Aizmirsi paroli? sign_up_now=Nepieciešams konts? Reģistrējies tagad. sign_up_successful=Konts tika veiksmīgi izveidots. Laipni lūdzam! -confirmation_mail_sent_prompt=Jauns apstiprināšanas e-pasts ir nosūtīts uz <b>%s</b>, pārbaudies savu e-pasta kontu tuvāko %s laikā, lai pabeigtu reģistrācijas procesu. must_change_password=Mainīt paroli allow_password_change=Pieprasīt lietotājam mainīt paroli (ieteicams) reset_password_mail_sent_prompt=Apstiprināšanas e-pasts tika nosūtīts uz <b>%s</b>. Pārbaudiet savu e-pasta kontu tuvāko %s laikā, lai pabeigtu paroles atjaunošanas procesu. @@ -614,6 +609,7 @@ form.name_reserved=Lietotājvārdu "%s" nedrīkst izmantot. form.name_pattern_not_allowed=Lietotājvārds "%s" nav atļauts. form.name_chars_not_allowed=Lietotāja vārds "%s" satur neatļautus simbolus. + [settings] profile=Profils account=Konts @@ -758,7 +754,6 @@ gpg_invalid_token_signature=Norādītā GPG atslēga, paraksts un pilnvara neatb gpg_token_required=Jānorāda paraksts zemāk esošajai pilnvarai gpg_token=Pilnvara gpg_token_help=Parakstu ir iespējams uzģenerēt izmantojot komandu: -gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig gpg_token_signature=Tekstuāls GPG paraksts key_signature_gpg_placeholder=Sākas ar '-----BEGIN PGP SIGNATURE-----' verify_gpg_key_success=GPG atslēga "%s" veiksmīgi pārbaudīta. @@ -952,7 +947,6 @@ fork_branch=Atzars, ko klonēt atdalītajā repozitorijā all_branches=Visi atzari fork_no_valid_owners=Šim repozitorijam nevar izveidot atdalītu repozitoriju, jo tam nav spēkā esošu īpašnieku. use_template=Izmantot šo sagatavi -clone_in_vsc=Atvērt VS Code download_zip=Lejupielādēt ZIP download_tar=Lejupielādēt TAR.GZ download_bundle=Lejupielādēt BUNDLE @@ -1272,9 +1266,7 @@ commits.desc=Pārlūkot pirmkoda izmaiņu vēsturi. commits.commits=Revīzijas commits.no_commits=Nav kopīgu revīziju. Atzariem "%s" un "%s" ir pilnībā atšķirīga izmaiņu vēsture. commits.nothing_to_compare=Atzari ir vienādi. -commits.search=Meklēt revīzijas… commits.search.tooltip=Jūs varat izmantot atslēgas vārdus "author:", "committer:", "after:" vai "before:", piemēram, "revert author:Alice before:2019-01-13". -commits.find=Meklēt commits.search_all=Visi atzari commits.author=Autors commits.message=Ziņojums @@ -1325,7 +1317,6 @@ projects.type.basic_kanban=`Vienkāršots "Kanban"` projects.type.bug_triage=Kļūdu šķirošana projects.template.desc=Projekta sagatave projects.template.desc_helper=Izvēlieties projekta sagatavi, lai sāktu darbu -projects.type.uncategorized=Bez kategorijas projects.column.edit=Rediģēt kolonnas projects.column.edit_title=Nosaukums projects.column.new_title=Nosaukums @@ -1333,10 +1324,7 @@ projects.column.new_submit=Izveidot kolonnu projects.column.new=Jauna kolonna projects.column.set_default=Izvēlēties kā noklusēto projects.column.set_default_desc=Izvēlēties šo kolonnu kā noklusēto nekategorizētām problēmām un izmaiņu pieteikumiem -projects.column.unset_default=Atiestatīt noklusēto -projects.column.unset_default_desc=Noņemt šo kolonnu kā noklusēto projects.column.delete=Dzēst kolonnu -projects.column.deletion_desc=Dzēšot projekta kolonnu visas tam piesaistītās problēmas tiks pārliktas kā nekategorizētas. Vai turpināt? projects.column.color=Krāsa projects.open=Aktīvie projects.close=Pabeigtie @@ -1448,7 +1436,6 @@ issues.filter_sort.moststars=Visvairāk atzīmētie issues.filter_sort.feweststars=Vismazāk atzīmētie issues.filter_sort.mostforks=Visvairāk atdalītie issues.filter_sort.fewestforks=Vismazāk atdalītie -issues.keyword_search_unavailable=Meklēšana pēc atslēgvārda pašreiz nav pieejama. Lūgums sazināties ar vietnes administratoru. issues.action_open=Atvērt issues.action_close=Aizvērt issues.action_label=Etiķete @@ -1700,7 +1687,6 @@ pulls.compare_compare=salīdzināmais pulls.switch_comparison_type=Mainīt salīdzināšanas tipu pulls.switch_head_and_base=Mainīt galvas un pamata atzarus pulls.filter_branch=Filtrēt atzarus -pulls.no_results=Nekas netika atrasts. pulls.show_all_commits=Rādīt visas revīzijas pulls.show_changes_since_your_last_review=Rādīt izmaiņas kopš Tavas pēdējās recenzijas pulls.showing_only_single_commit=Rāda tikai revīzijas %[1]s izmaiņas @@ -1970,17 +1956,6 @@ activity.git_stats_deletion_n=%d dzēšanas contributors.contribution_type.commits=Revīzijas -search=Meklēt -search.search_repo=Meklēšana repozitorijā -search.type.tooltip=Meklēšanas veids -search.fuzzy=Aptuveni -search.fuzzy.tooltip=Iekļaut meklēšanas rezultātos arī aptuvenas sakritības -search.match=Precīzi -search.match.tooltip=Iekļaut meklēšanas rezultātos tikai precīzas sakritības -search.results=Meklēšanas rezultāti nosacījumam "%s" repozitorijā <a href="%s">%s</a> -search.code_no_results=Netika atrasts pirmkods, kas atbilstu kritērijiem. -search.code_search_unavailable=Pašlaik koda meklēšana nav pieejama. Sazinieties ar lapas administratoru. - settings=Iestatījumi settings.desc=Iestatījumi ir vieta, kur varat pārvaldīt repozitorija iestatījumus settings.options=Repozitorijs @@ -2058,6 +2033,7 @@ settings.pulls.default_allow_edits_from_maintainers=Atļaut uzturētājiem labot settings.releases_desc=Iespējot repozitorija laidienus settings.packages_desc=Iespējot repozitorija pakotņu reģistru settings.projects_desc=Iespējot repozitorija projektus +settings.projects_mode_all=Visi projekti settings.actions_desc=Iespējot repozitorija darbības settings.admin_settings=Administratora iestatījumi settings.admin_enable_health_check=Iespējot veselības pārbaudi (git fsck) šim repozitorijam @@ -2132,7 +2108,6 @@ settings.delete_collaborator=Noņemt settings.collaborator_deletion=Noņemt līdzstrādnieku settings.collaborator_deletion_desc=Noņemot līdzstrādnieku, tam tiks liegta piekļuve šim repozitorijam. Vai turpināt? settings.remove_collaborator_success=Līdzstrādnieks tika noņemts. -settings.search_user_placeholder=Meklēt lietotāju… settings.org_not_allowed_to_be_collaborator=Organizācijas nevar tikt pievienotas kā līdzstrādnieki. settings.change_team_access_not_allowed=Iespēja mainīt komandu piekļuvi repozitorijam ir organizācijas īpašniekam settings.team_not_in_organization=Komanda nav tajā pašā organizācijā kā repozitorijs @@ -2140,7 +2115,6 @@ settings.teams=Komandas settings.add_team=Pievienot komandu settings.add_team_duplicate=Komandai jau ir piekļuve šim repozitorijam settings.add_team_success=Komandai tagad ir piekļuve šim repozitorijam. -settings.search_team=Meklēt komandu… settings.change_team_permission_tip=Komandas tiesības tiek uzstādītas komandas iestatījumu lapā un nevar tikt individuāli mainītas katram repozitorijam atsevišķi settings.delete_team_tip=Komandai ir piekļuve visiem repozitorijiem un tā nevar tikt noņemta individuāli settings.remove_team_success=Komandas piekļuve šim repozitorijam ir noņemta. @@ -2293,9 +2267,7 @@ settings.protect_whitelist_committers=Atļaut iesūtīt izmaiņas norādītajiem settings.protect_whitelist_committers_desc=Tikai norādītiem lietotāji vai komandas varēs iesūtīt izmaiņas šajā atzarā (piespiedu izmaiņu iesūtīšanas netiks atļauta). settings.protect_whitelist_deploy_keys=Atļaut izvietošanas atslēgām ar rakstīšanas tiesībām nosūtīt izmaiņas. settings.protect_whitelist_users=Lietotāji, kas var veikt izmaiņu nosūtīšanu: -settings.protect_whitelist_search_users=Meklēt lietotājus… settings.protect_whitelist_teams=Komandas, kas var veikt izmaiņu nosūtīšanu: -settings.protect_whitelist_search_teams=Meklēt komandas… settings.protect_merge_whitelist_committers=Iespējot sapludināšanas ierobežošanu settings.protect_merge_whitelist_committers_desc=Atļaut tikai noteiktiem lietotājiem vai komandām sapludināt izmaiņu pieprasījumus šajā atzarā. settings.protect_merge_whitelist_users=Lietotāji, kas var veikt izmaiņu sapludināšanu: @@ -2537,7 +2509,6 @@ branch.default_deletion_failed=Atzars "%s" ir noklusētais atzars un to nevar dz branch.restore=`Atjaunot atzaru "%s"` branch.download=`Lejupielādēt atzaru "%s"` branch.rename=`Pārsaukt atzaru "%s"` -branch.search=Meklēt atzarā branch.included_desc=Šis atzars ir daļa no noklusēta atzara branch.included=Iekļauts branch.create_new_branch=Izveidot jaunu atzaru no atzara: @@ -2679,7 +2650,6 @@ teams.write_permission_desc=Šai komandai ir <strong>rakstīšanas</strong> ties teams.admin_permission_desc=Šai komandai ir <strong>administratora</strong> tiesības: dalībnieki var lasīt, rakstīt un pievienot citus dalībniekus komandas repozitorijiem. teams.create_repo_permission_desc=Papildus šī komanda piešķirt <strong>Veidot repozitorijus</strong> tiesības: komandas biedri var veidot jaunus repozitorijus šajā organizācijā. teams.repositories=Komandas repozitoriji -teams.search_repo_placeholder=Meklēt repozitorijā… teams.remove_all_repos_title=Noņemt visus komandas repozitorijus teams.remove_all_repos_desc=Šī darbība noņems visus repozitorijus no komandas. teams.add_all_repos_title=Pievienot visus repozitorijus @@ -2712,6 +2682,8 @@ integrations=Integrācijas authentication=Autentificēšanas avoti emails=Lietotāja e-pasts config=Konfigurācija +config_summary=Kopsavilkums +config_settings=Iestatījumi notices=Sistēmas paziņojumi monitor=Uzraudzība first_page=Pirmā @@ -2886,9 +2858,6 @@ repos.unadopted.no_more=Netika atrasts neviens nepārņemtais repozitorijs repos.owner=Īpašnieks repos.name=Nosaukums repos.private=Privāts -repos.watches=Vērošana -repos.stars=Zvaigznes -repos.forks=Atdalītie repos.issues=Problēmas repos.size=Izmērs repos.lfs_size=LFS izmērs @@ -3013,7 +2982,6 @@ auths.tip.nextcloud=`Reģistrējiet jaunu OAuth klientu jūsu instances sadāļ auths.tip.dropbox=Izveidojiet jaunu aplikāciju adresē https://www.dropbox.com/developers/apps auths.tip.facebook=`Reģistrējiet jaunu aplikāciju adresē https://developers.facebook.com/apps un pievienojiet produktu "Facebook Login"` auths.tip.github=Reģistrējiet jaunu aplikāciju adresē https://github.com/settings/applications/new -auths.tip.gitlab=Reģistrējiet jaunu aplikāciju adresē https://gitlab.com/profile/applications auths.tip.google_plus=Iegūstiet OAuth2 klienta pilnvaru no Google API konsoles adresē https://console.developers.google.com/ auths.tip.openid_connect=Izmantojiet OpenID pieslēgšanās atklāšanas URL (<serveris>/.well-known/openid-configuration), lai norādītu galapunktus auths.tip.twitter=Dodieties uz adresi https://dev.twitter.com/apps, izveidojiet lietotni un pārliecinieties, ka ir atzīmēts “Allow this application to be used to Sign in with Twitter” diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini index fc1da2b992..255a3db9fa 100644 --- a/options/locale/locale_nl-NL.ini +++ b/options/locale/locale_nl-NL.ini @@ -115,6 +115,15 @@ concept_user_organization=Organisatie name=Naam +filter=Filter +filter.is_archived=Gearchiveerd +filter.is_template=Sjabloon +filter.public=Publiek +filter.private=Prive + + +[search] + [aria] [heatmap] @@ -253,7 +262,6 @@ collaborative_repos=Gedeelde repositories my_orgs=Mijn organisaties my_mirrors=Mijn spiegels view_home=Bekijk %s -search_repos=Zoek een repository… filter=Andere filters filter_by_team_repositories=Filter op team repositories feed_of=`Feed van "%s"` @@ -274,15 +282,7 @@ issues.in_your_repos=In uw repositories repos=Repositories users=Gebruikers organizations=Organisaties -search=Zoeken code=Code -search.fuzzy=Vergelijkbaar -search.match=Overeenkomst -code_search_unavailable=Er is momenteel geen code zoekfunctie beschikbaar. Neem contact op met uw sitebeheerder. -repo_no_results=Er zijn geen overeenkomende repositories gevonden. -user_no_results=Er zijn geen overeenkomende gebruikers gevonden. -org_no_results=Er zijn geen overeenkomende organisaties gevonden. -code_no_results=Geen broncode gevonden in overeenstemming met uw zoekterm. code_last_indexed_at=Laatst geïndexeerd %s [auth] @@ -296,7 +296,6 @@ remember_me=Onthoud dit apparaat forgot_password_title=Wachtwoord vergeten forgot_password=Wachtwoord vergeten? sign_up_now=Een account nodig? Meld u nu aan. -confirmation_mail_sent_prompt=Een nieuwe bevestigingsmail is gestuurd naar <b>%s</b>. De mail moet binnen %s worden bevestigd om je registratie te voltooien. must_change_password=Uw wachtwoord wijzigen allow_password_change=Verplicht de gebruiker om zijn/haar wachtwoord te wijzigen (aanbevolen) reset_password_mail_sent_prompt=Een bevestigingsmail is verstuurd naar <b>%s</b>. Controleer uw inbox in de volgende %s om het herstel van uw account te voltooien. @@ -506,6 +505,7 @@ user_bio=Biografie disabled_public_activity=Deze gebruiker heeft de publieke zichtbaarheid van de activiteit uitgeschakeld. + [settings] profile=Profiel account=Account @@ -633,7 +633,6 @@ gpg_invalid_token_signature=De opgegeven GPG-sleutel, handtekening en token kome gpg_token_required=U moet een handtekening opgeven voor de onderstaande token gpg_token=Token gpg_token_help=U kunt een handtekening genereren met: -gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig gpg_token_signature=Gepantserde GPG-handtekening key_signature_gpg_placeholder=Begint met '-----BEGIN PGP SIGNATURE-----' ssh_key_verified=Geverifieerde sleutel @@ -785,7 +784,6 @@ already_forked=Je hebt %s al geforked fork_to_different_account=Fork naar een ander account fork_visibility_helper=De zichtbaarheid van een geforkte repository kan niet worden veranderd. use_template=Gebruik dit sjabloon -clone_in_vsc=Kloon in VS Code download_zip=ZIP downloaden download_tar=TAR.GZ downloaden download_bundle=BUNDLE downloaden @@ -1049,8 +1047,6 @@ editor.revert=%s ongedaan maken op: commits.desc=Bekijk de broncode-wijzigingsgeschiedenis. commits.commits=Commits commits.nothing_to_compare=Deze branches zijn gelijk. -commits.search=Zoek commits… -commits.find=Zoek commits.search_all=Alle branches commits.author=Auteur commits.message=Bericht @@ -1095,7 +1091,6 @@ projects.type.basic_kanban=Basis Kanban projects.type.bug_triage=Bug Triage projects.template.desc=Project sjabloon projects.template.desc_helper=Selecteer een projecttemplate om aan de slag te gaan -projects.type.uncategorized=Ongecategoriseerd projects.column.edit_title=Naam projects.column.new_title=Naam projects.column.color=Kleur @@ -1406,7 +1401,6 @@ pulls.compare_compare=trekken van pulls.switch_comparison_type=Wissel vergelijking type pulls.switch_head_and_base=Verwissel hoofd en basis pulls.filter_branch=Filter branch -pulls.no_results=Geen resultaten gevonden. pulls.nothing_to_compare=Deze branches zijn gelijk. Er is geen pull-aanvraag nodig. pulls.nothing_to_compare_and_allow_empty_pr=Deze branches zijn gelijk. Deze pull verzoek zal leeg zijn. pulls.has_pull_request=`Een pull-verzoek tussen deze branches bestaat al: <a href="%[1]s">%[2]s#%[3]d</a>` @@ -1621,14 +1615,6 @@ activity.git_stats_deletion_n=%d verwijderingen contributors.contribution_type.commits=Commits -search=Zoek -search.search_repo=Zoek repository -search.fuzzy=Vergelijkbaar -search.match=Overeenkomst -search.results=Zoek resultaat voor "%s" in <a href="%s">%s</a> -search.code_no_results=Geen broncode gevonden die aan uw zoekterm voldoet. -search.code_search_unavailable=Er is momenteel geen code zoekfunctie beschikbaar. Neem contact op met uw sitebeheerder. - settings=Instellingen settings.desc=In de instellingen kan je de instellingen van de repository aanpassen settings.options=Repository @@ -1705,7 +1691,6 @@ settings.delete_collaborator=Verwijder settings.collaborator_deletion=Verwijder medewerker settings.collaborator_deletion_desc=Het verwijderen van een collaborator zal hun toegang tot deze repository intrekken. Doorgaan? settings.remove_collaborator_success=De medewerker is verwijderd. -settings.search_user_placeholder=Zoek gebruiker… settings.org_not_allowed_to_be_collaborator=Organisaties kunnen niet worden toegevoegd als een medewerker. settings.change_team_access_not_allowed=Het veranderen van team toegang voor de repository is beperkt tot de organisatie eigenaar settings.team_not_in_organization=Het team zit niet in dezelfde organisatie als de repository @@ -1713,7 +1698,6 @@ settings.teams=Teams settings.add_team=Team toevoegen settings.add_team_duplicate=Team heeft al de repository settings.add_team_success=Het team heeft nu toegang tot de repository. -settings.search_team=Zoek team… settings.change_team_permission_tip=Teammachtiging is ingesteld op de team-instellingspagina en kan niet per repository worden gewijzigd settings.delete_team_tip=Dit team heeft toegang tot alle repositories en kan niet verwijderd worden settings.remove_team_success=De toegang van het team tot de repository is verwijderd. @@ -1845,9 +1829,7 @@ settings.protect_whitelist_committers=Whitelist Beperkte Push settings.protect_whitelist_committers_desc=Alleen gewhiteliste gebruikers of teams mogen pushen naar deze branch (maar geen force push). settings.protect_whitelist_deploy_keys=Whitelist deploy sleutels met schrijftoegang om te pushen. settings.protect_whitelist_users=Toegestane gebruikers voor push: -settings.protect_whitelist_search_users=Zoek gebruiker… settings.protect_whitelist_teams=Toegestane teams voor push: -settings.protect_whitelist_search_teams=Zoek teams… settings.protect_merge_whitelist_committers=Samenvoegen whitelist inschakelen settings.protect_merge_whitelist_committers_desc=Sta alleen gebruikers of teams van de whitelist toe om pull requests samen te voegen met deze branch. settings.protect_merge_whitelist_users=Toegestane gebruikers voor samenvoegen: @@ -2123,7 +2105,6 @@ teams.write_permission_desc=Dit team heeft <strong>Schrijf</strong> rechten: led teams.admin_permission_desc=Dit team heeft <strong>beheersrechten</strong>: leden kunnen van en naar teamrepositories pullen, pushen, en er medewerkers aan toevoegen. teams.create_repo_permission_desc=Daarnaast verleent dit team <strong>Maak repository</strong> permissie: leden kunnen nieuwe repositories maken in de organisatie. teams.repositories=Teamrepositories -teams.search_repo_placeholder=Repository zoeken… teams.remove_all_repos_title=Verwijder alle team repositories teams.remove_all_repos_desc=Dit zal alle repositories uit het team verwijderen. teams.add_all_repos_title=Voeg alle repositories toe @@ -2145,6 +2126,8 @@ repositories=Repositories authentication=Authenticatie bronnen emails=Gebruikeremails config=Configuratie +config_summary=Overzicht +config_settings=Instellingen notices=Systeem aankondigingen monitor=Bijhouden first_page=Eerste @@ -2282,9 +2265,6 @@ repos.unadopted.no_more=Geen niet-geadopteerde repositories meer gevonden repos.owner=Eigenaar repos.name=Naam repos.private=Prive -repos.watches=Volgers -repos.stars=Sterren -repos.forks=Forks repos.issues=Kwesties repos.size=Grootte @@ -2365,7 +2345,6 @@ auths.tip.nextcloud=`Registreer een nieuwe OAuth consument op je installatie met auths.tip.dropbox=Maak een nieuwe applicatie aan op https://www.dropbox.com/developers/apps auths.tip.facebook=Registreer een nieuwe applicatie op https://developers.facebook.com/apps en voeg het product "Facebook Login" toe auths.tip.github=Registreer een nieuwe OAuth toepassing op https://github.com/settings/applications/new -auths.tip.gitlab=Registreer een nieuwe applicatie op https://gitlab.com/profile/applicaties auths.tip.google_plus=Verkrijg OAuth2 client referenties van de Google API console op https://console.developers.google.com/ auths.tip.openid_connect=Gebruik de OpenID Connect Discovery URL (<server>/.well-known/openid-configuration) om de eindpunten op te geven auths.tip.yandex=`Maak een nieuwe applicatie aan op https://oauth.yandex.com/client/new. Selecteer de volgende machtigingen van de "Yandex". assport API sectie: "Toegang tot e-mailadres", "Toegang tot avatar" en "Toegang tot gebruikersnaam, voornaam en achternaam, geslacht"` diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini index 2af3ce1a11..1496877fd5 100644 --- a/options/locale/locale_pl-PL.ini +++ b/options/locale/locale_pl-PL.ini @@ -113,6 +113,14 @@ concept_user_organization=Organizacja name=Nazwa +filter.is_archived=Zarchiwizowane +filter.is_template=Szablon +filter.public=Publiczne +filter.private=Prywatne + + +[search] + [aria] [heatmap] @@ -251,7 +259,6 @@ collaborative_repos=Wspólne repozytoria my_orgs=Moje organizacje my_mirrors=Moje kopie lustrzane view_home=Zobacz %s -search_repos=Znajdź repozytorium… filter=Inne filtry filter_by_team_repositories=Filtruj według repozytoriów zespołu feed_of=`Kanał "%s"` @@ -272,14 +279,7 @@ issues.in_your_repos=W Twoich repozytoriach repos=Repozytoria users=Użytkownicy organizations=Organizacje -search=Szukaj code=Kod -search.fuzzy=Fuzzy -search.match=Dopasuj -repo_no_results=Nie znaleziono pasujących repozytoriów. -user_no_results=Nie znaleziono pasującego użytkowników. -org_no_results=Nie znaleziono pasujących organizacji. -code_no_results=Nie znaleziono kodu źródłowego odpowiadającego Twojej frazie wyszukiwania. code_last_indexed_at=Ostatnio indeksowane %s [auth] @@ -292,7 +292,6 @@ remember_me=Zapamiętaj to urządzenie forgot_password_title=Zapomniałem hasła forgot_password=Zapomniałeś hasła? sign_up_now=Potrzebujesz konta? Zarejestruj się teraz. -confirmation_mail_sent_prompt=Nowy email aktywacyjny został wysłany na adres <b>%s</b>. Sprawdź swoją skrzynkę odbiorczą w ciągu %s aby dokończyć proces rejestracji. must_change_password=Zaktualizuj swoje hasło allow_password_change=Użytkownik musi zmienić hasło (zalecane) reset_password_mail_sent_prompt=E-mail potwierdzający został wysłany na adres <b>%s</b>. Sprawdź swoją skrzynkę odbiorczą w przeciągu %s, aby ukończyć proces odzyskiwania konta. @@ -491,6 +490,7 @@ user_bio=Biografia disabled_public_activity=Ten użytkownik wyłączył publiczne wyświetlanie jego aktywności. + [settings] profile=Profil account=Konto @@ -597,7 +597,6 @@ gpg_invalid_token_signature=Podany klucz GPG, podpis i token nie pasują lub tok gpg_token_required=Musisz podać podpis poniższego tokenu gpg_token=Token gpg_token_help=Możesz wygenerować podpis za pomocą: -gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig gpg_token_signature=Wzmocniony podpis GPG key_signature_gpg_placeholder=Zaczyna się od '-----BEGIN PGP SIGNATURE-----' ssh_key_verified=Zweryfikowany klucz @@ -741,7 +740,6 @@ fork_repo=Forkuj repozytorium fork_from=Forkuj z fork_visibility_helper=Widoczność sforkowanego repozytorium nie może być zmieniona. use_template=Użyj tego szablonu -clone_in_vsc=Klonuj w VS Code download_zip=Pobierz ZIP download_tar=Pobierz TAR.GZ download_bundle=Pobierz BUNDLE @@ -974,8 +972,6 @@ editor.require_signed_commit=Gałąź wymaga podpisanych commitów commits.desc=Przeglądaj historię zmian kodu źródłowego. commits.commits=Commity -commits.search=Przeszukaj commity… -commits.find=Szukaj commits.search_all=Wszystkie gałęzie commits.author=Autor commits.message=Wiadomość @@ -1011,7 +1007,6 @@ projects.type.basic_kanban=Basic Kanban projects.type.bug_triage=Bug Triage projects.template.desc=Szablon projektu projects.template.desc_helper=Wybierz szablon projektu do rozpoczęcia -projects.type.uncategorized=Bez kategorii projects.column.edit_title=Nazwa projects.column.new_title=Nazwa projects.column.color=Kolor @@ -1280,7 +1275,6 @@ pulls.compare_changes_desc=Wybierz gałąź, do której chcesz scalić oraz gał pulls.compare_base=scal do pulls.compare_compare=ściągnij z pulls.filter_branch=Filtruj branch -pulls.no_results=Nie znaleziono wyników. pulls.nothing_to_compare=Te gałęzie są sobie równe. Nie ma potrzeby tworzyć Pull Requesta. pulls.nothing_to_compare_and_allow_empty_pr=Te gałęzie są równe. Ten PR będzie pusty. pulls.create=Utwórz Pull Request @@ -1470,13 +1464,6 @@ activity.git_stats_deletion_n=%d usunięć contributors.contribution_type.commits=Commity -search=Szukaj -search.search_repo=Przeszukaj repozytorium -search.fuzzy=Fuzzy -search.match=Dopasuj -search.results=Wyniki wyszukiwania dla "%s" w <a href="%s">%s</a> -search.code_no_results=Nie znaleziono kodu źródłowego odpowiadającego Twojej frazie wyszukiwania. - settings=Ustawienia settings.desc=Ustawienia to miejsce, w którym możesz zmieniać parametry repozytorium settings.options=Repozytorium @@ -1586,7 +1573,6 @@ settings.delete_collaborator=Usuń settings.collaborator_deletion=Usuń współpracownika settings.collaborator_deletion_desc=Usunięcie współpracownika odbierze mu dostęp do tego repozytorium. Kontynuować? settings.remove_collaborator_success=Usunięto użytkownika. -settings.search_user_placeholder=Szukaj użytkownika… settings.org_not_allowed_to_be_collaborator=Organizacji nie można dodać jako współpracownika. settings.change_team_access_not_allowed=Zmiana dostępu zespołu do repozytorium zostało zastrzeżone do właściciela organizacji settings.team_not_in_organization=Zespół nie jest w tej samej organizacji co repozytorium @@ -1594,7 +1580,6 @@ settings.teams=Zespoły settings.add_team=Dodaj zespół settings.add_team_duplicate=Zespół już posiada repozytorium settings.add_team_success=Zespół ma teraz dostęp do repozytorium. -settings.search_team=Szukaj zespołu… settings.change_team_permission_tip=Uprawnienia zespołu ustawione są konfigurowane na stronie ustawień zespołu i nie mogą być zmieniane dla pojedynczych repozytoriów settings.delete_team_tip=Ten zespół ma dostęp do wszystkich repozytoriów i nie może zostać usunięty settings.remove_team_success=Dostęp zespołu do repozytorium został usunięty. @@ -1710,9 +1695,7 @@ settings.protect_whitelist_committers=Wypychanie ograniczone białą listą settings.protect_whitelist_committers_desc=Tylko dopuszczeni użytkownicy oraz zespoły będą miały możliwość wypychania zmian do tej gałęzi (oprócz wymuszenia wypchnięcia). settings.protect_whitelist_deploy_keys=Dozwolona lista kluczy wdrożeniowych z uprawnieniem zapisu do push'a. settings.protect_whitelist_users=Użytkownicy dopuszczeni do wypychania: -settings.protect_whitelist_search_users=Szukaj użytkowników… settings.protect_whitelist_teams=Zespoły dopuszczone do wypychania: -settings.protect_whitelist_search_teams=Szukaj zespołów… settings.protect_merge_whitelist_committers=Włącz dopuszczenie scalania settings.protect_merge_whitelist_committers_desc=Zezwól jedynie dopuszczonym użytkownikom lub zespołom na scalanie Pull Requestów w tej gałęzi. settings.protect_merge_whitelist_users=Użytkownicy dopuszczeni do scalania: @@ -1994,7 +1977,6 @@ teams.write_permission_desc=Ten zespół udziela dostępu <strong>z zapisem</str teams.admin_permission_desc=Ten zespół udziela dostępu <strong>administratora</strong>: członkowie mogą wyświetlać i wypychać zmiany oraz dodawać współpracowników do repozytoriów zespołu. teams.create_repo_permission_desc=Dodatkowo, ten zespół otrzyma uprawnienie <strong>Tworzenie repozytoriów</strong>: jego członkowie mogą tworzyć nowe repozytoria w organizacji. teams.repositories=Repozytoria zespołu -teams.search_repo_placeholder=Szukaj repozytorium… teams.remove_all_repos_title=Usuń wszystkie repozytoria zespołu teams.remove_all_repos_desc=Usunie to wszystkie repozytoria przypisane do zespołu. teams.add_all_repos_title=Dodaj wszystkie repozytoria @@ -2019,6 +2001,8 @@ hooks=Weebhook'i authentication=Źródła uwierzytelniania emails=Emaile użytkowników config=Konfiguracja +config_summary=Podsumowanie +config_settings=Ustawienia notices=Powiadomienia systemu monitor=Monitorowanie first_page=Pierwsza @@ -2157,9 +2141,6 @@ repos.unadopted.no_more=Nie znaleziono więcej nieprzyjętych repozytoriów repos.owner=Właściciel repos.name=Nazwa repos.private=Prywatne -repos.watches=Obserwujących -repos.stars=Polubienia -repos.forks=Forki repos.issues=Zgłoszenia repos.size=Rozmiar @@ -2248,7 +2229,6 @@ auths.tip.nextcloud=`Zarejestruj nowego klienta OAuth w swojej instancji za pomo auths.tip.dropbox=Stwórz nową aplikację na https://www.dropbox.com/developers/apps auths.tip.facebook=`Zarejestruj nową aplikację na https://developers.facebook.com/apps i dodaj produkt "Facebook Login"` auths.tip.github=Zarejestruj nową aplikację OAuth na https://github.com/settings/applications/new -auths.tip.gitlab=Zarejestruj nową aplikację na https://gitlab.com/profile/applications auths.tip.google_plus=Uzyskaj dane uwierzytelniające klienta OAuth2 z konsoli Google API na https://console.developers.google.com/ auths.tip.openid_connect=Użyj adresu URL OpenID Connect Discovery (<server>/.well-known/openid-configuration), aby określić punkty końcowe auths.tip.twitter=Przejdź na https://dev.twitter.com/apps, stwórz aplikację i upewnij się, że opcja “Allow this application to be used to Sign in with Twitter” jest włączona diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 11743f29a5..0d1614df3f 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -90,6 +90,7 @@ remove=Remover remove_all=Excluir todos remove_label_str=`Remover item "%s"` edit=Editar +view=Visualizar enabled=Habilitado disabled=Desabilitado @@ -97,6 +98,7 @@ locked=Bloqueado copy=Copiar copy_url=Copiar URL +copy_hash=Copiar hash copy_content=Copiar conteúdo copy_branch=Copiar nome do branch copy_success=Copiado! @@ -109,6 +111,7 @@ loading=Carregando… error=Erro error404=A página que você está tentando acessar <strong>não existe</strong> ou <strong>você não está autorizado</strong> a visualizá-la. +go_back=Voltar never=Nunca unknown=Desconhecido @@ -119,6 +122,7 @@ pin=Fixar unpin=Desfixar artifacts=Artefatos +confirm_delete_artifact=Tem certeza que deseja excluir o artefato '%s' ? archived=Arquivado @@ -137,6 +141,15 @@ confirm_delete_selected=Confirma a exclusão de todos os itens selecionados? name=Nome value=Valor +filter=Filtro +filter.is_archived=Arquivado +filter.is_template=Template +filter.public=Pública +filter.private=Privado + + +[search] + [aria] navbar=Barra de navegação footer=Rodapé @@ -309,7 +322,6 @@ collaborative_repos=Repositórios colaborativos my_orgs=Minhas organizações my_mirrors=Meus espelhos view_home=Ver %s -search_repos=Encontre um repositório… filter=Outros filtros filter_by_team_repositories=Filtrar por repositórios da equipe feed_of=`Feed de "%s"` @@ -330,20 +342,8 @@ issues.in_your_repos=Em seus repositórios repos=Repositórios users=Usuários organizations=Organizações -search=Pesquisar go_to=Ir para code=Código -search.type.tooltip=Tipo de pesquisa -search.fuzzy=Similar -search.fuzzy.tooltip=Incluir resultados que sejam próximos ao termo de busca -search.match=Correspondência -search.match.tooltip=Incluir somente resultados que correspondam exatamente ao termo de busca -code_search_unavailable=A pesquisa por código não está disponível no momento. Entre em contato com o administrador do site. -repo_no_results=Nenhum repositório correspondente foi encontrado. -user_no_results=Nenhum usuário correspondente foi encontrado. -org_no_results=Nenhuma organização correspondente foi encontrada. -code_no_results=Nenhum código-fonte correspondente ao seu termo de pesquisa foi encontrado. -code_search_results=`Resultados da pesquisa por: "%s"` code_last_indexed_at=Última indexação %s relevant_repositories_tooltip=Repositórios que são forks ou que não possuem tópico, nem ícone e nem descrição estão ocultos. relevant_repositories=Apenas repositórios relevantes estão sendo mostrados, <a href="%s">mostrar resultados não filtrados</a>. @@ -356,11 +356,11 @@ disable_register_prompt=Cadastro está desabilitado. Entre em contato com o admi disable_register_mail=E-mail de confirmação de cadastro está desabilitado. manual_activation_only=Entre em contato com o administrador do site para concluir a ativação. remember_me=Lembrar deste Dispositivo +remember_me.compromised=O token de login não é mais válido, o que pode indicar uma conta comprometida. Por favor, verifique a sua conta por atividades incomuns. forgot_password_title=Esqueci minha senha forgot_password=Esqueceu sua senha? sign_up_now=Precisa de uma conta? Cadastre-se agora. sign_up_successful=A conta foi criada com sucesso. Bem-vindo! -confirmation_mail_sent_prompt=Um novo e-mail de confirmação foi enviado para <b>%s</b>. Por favor, verifique sua caixa de e-mail nas próximas %s horas para finalizar o processo de cadastro. must_change_password=Redefina sua senha allow_password_change=Exigir que o usuário redefina a senha (recomendado) reset_password_mail_sent_prompt=Um e-mail de confirmação foi enviado para <b>%s</b>. Por favor, verifique sua caixa de entrada dentro do(s) próximo(s) %s para concluir o processo de recuperação de conta. @@ -417,6 +417,7 @@ authorization_failed_desc=A autorização falhou porque detectamos uma solicita sspi_auth_failed=Falha de autenticação SSPI password_pwned=A senha que você escolheu faz parte de uma <a target="_blank" rel="noopener noreferrer" href="https://haveibeenpwned.com/Passwords">lista de senhas roubadas</a> expostas anteriormente em violações de dados. Tente novamente com uma senha diferente e considere alterar essa senha em outro lugar também. password_pwned_err=Não foi possível concluir a requisição ao HaveIBeenPwned +last_admin=Você não pode remover o último administrador. Deve haver pelo menos um administrador. [mail] view_it_on=Veja em %s @@ -582,6 +583,7 @@ org_still_own_packages=Esta organização ainda possui pacotes, exclua-os primei target_branch_not_exist=O branch de destino não existe. +admin_cannot_delete_self=Você não pode excluir você mesmo quando você é um administrador. Por favor, remova seus privilégios de administrador primeiro. [user] change_avatar=Altere seu avatar... @@ -608,6 +610,7 @@ form.name_reserved=O nome de usuário "%s" está reservado. form.name_pattern_not_allowed=O padrão de "%s" não é permitido em um nome de usuário. form.name_chars_not_allowed=Nome de usuário "%s" contém caracteres inválidos. + [settings] profile=Perfil account=Conta @@ -752,7 +755,6 @@ gpg_invalid_token_signature=A chave GPG fornecida, a assinatura ou o token não gpg_token_required=Você tem que fornecer uma assinatura para o token abaixo gpg_token=Token gpg_token_help=Você pode gerar uma assinatura usando: -gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig gpg_token_signature=Assinatura GPG blindada key_signature_gpg_placeholder=Começa com '-----BEGIN PGP SIGNATURE-----' verify_gpg_key_success=A chave GPG "%s" foi validada. @@ -859,6 +861,7 @@ revoke_oauth2_grant_description=Revogando o acesso para este aplicativo de terce revoke_oauth2_grant_success=Acesso revogado com sucesso. twofa_desc=Autenticação de dois fatores melhora a segurança de sua conta. +twofa_recovery_tip=Se você perder o seu dispositivo, você será capaz de usar uma chave de recuperação de uso único para recuperar o acesso à sua conta. twofa_is_enrolled=Sua conta está atualmente <strong>habilitada</strong> com autenticação de dois fatores. twofa_not_enrolled=Sua conta não está atualmente inscrita para a autenticação em duas etapas. twofa_disable=Desabilitar a autenticação de dois fatores @@ -881,6 +884,8 @@ webauthn_register_key=Adicionar chave de segurança webauthn_nickname=Apelido webauthn_delete_key=Remover chave de segurança webauthn_delete_key_desc=Se você remover uma chave de segurança, não poderá mais entrar com ela. Continuar? +webauthn_key_loss_warning=Se você perder suas chaves de segurança, perderá o acesso à sua conta. +webauthn_alternative_tip=Você pode querer configurar um método de autenticação adicional. manage_account_links=Gerenciar contas vinculadas manage_account_links_desc=Estas contas externas estão vinculadas a sua conta de Gitea. @@ -917,6 +922,7 @@ visibility.private=Privada visibility.private_tooltip=Visível apenas para membros das organizações às quais você se associou [repo] +new_repo_helper=Um repositório contém todos os arquivos do projeto, inclusive o histórico de revisões. Já está hospedando um em outro lugar? <a href="%s">Migre o repositório.</a> owner=Proprietário owner_helper=Algumas organizações podem não aparecer no menu devido a um limite de contagem dos repositórios. repo_name=Nome do repositório @@ -937,9 +943,10 @@ fork_from=Fork de already_forked=Você já fez o fork de %s fork_to_different_account=Faça um fork para uma conta diferente fork_visibility_helper=A visibilidade do fork de um repositório não pode ser alterada. +fork_branch=Branch a ser clonado para o fork +all_branches=Todos os branches fork_no_valid_owners=Não é possível fazer um fork desse repositório porque não há proprietários validos. use_template=Usar este modelo -clone_in_vsc=Clonar no VS Code download_zip=Baixar ZIP download_tar=Baixar TAR.GZ download_bundle=Baixar PACOTE @@ -972,6 +979,7 @@ mirror_prune=Varrer mirror_prune_desc=Remover referências obsoletas de controle remoto mirror_interval=Intervalo de espelhamento (unidades válidas são 'h', 'm', ou 's'). O desabilita a sincronização automática. (Intervalo mínimo: %s) mirror_interval_invalid=O intervalo do espelhamento não é válido. +mirror_sync=sincronizado mirror_sync_on_commit=Sincronizar quando commits forem enviados mirror_address=Clonar de URL mirror_address_desc=Coloque todas as credenciais necessárias na seção de autorização. @@ -1017,6 +1025,7 @@ desc.public=Público desc.template=Template desc.internal=Interno desc.archived=Arquivado +desc.sha256=SHA256 template.items=Itens do modelo template.git_content=Conteúdo Git (Branch padrão) @@ -1167,6 +1176,7 @@ audio_not_supported_in_browser=Seu navegador não suporta a tag 'audio' do HTML5 stored_lfs=Armazenado com Git LFS symbolic_link=Link simbólico executable_file=Arquivo executável +generated=Gerado commit_graph=Gráfico de commits commit_graph.select=Selecionar branches commit_graph.hide_pr_refs=Esconder Pull Requests @@ -1253,9 +1263,7 @@ commits.desc=Veja o histórico de alterações do código de fonte. commits.commits=Commits commits.no_commits=Nenhum commit em comum. "%s" e "%s" tem históricos completamente diferentes. commits.nothing_to_compare=Estes branches são iguais. -commits.search=Pesquisar commits... commits.search.tooltip=Você pode prefixar as palavras-chave com "author:" (autor da mudança), "committer:" (autor do commit), "after:" (depois) ou "before:" (antes). Por exemplo: "revert author:Ana before:2019-01-13".\ -commits.find=Pesquisar commits.search_all=Todos os branches commits.author=Autor commits.message=Mensagem @@ -1267,6 +1275,7 @@ commits.signed_by_untrusted_user=Assinado por usuário não confiável commits.signed_by_untrusted_user_unmatched=Assinado por usuário não confiável que não corresponde ao autor da submissão commits.gpg_key_id=ID da chave GPG commits.ssh_key_fingerprint=Impressão Digital da Chave SSH +commits.view_path=Visualizar neste ponto do histórico commit.operations=Operações commit.revert=Reverter @@ -1305,7 +1314,6 @@ projects.type.basic_kanban=Kanban básico projects.type.bug_triage=Triagem de Bugs projects.template.desc=Modelo de projeto projects.template.desc_helper=Selecione um modelo de projeto para começar -projects.type.uncategorized=Sem categoria projects.column.edit=Editar coluna projects.column.edit_title=Nome projects.column.new_title=Nome @@ -1313,10 +1321,7 @@ projects.column.new_submit=Criar coluna projects.column.new=Nova Coluna projects.column.set_default=Atribuir como padrão projects.column.set_default_desc=Definir esta coluna como padrão para pull e issues sem categoria -projects.column.unset_default=Desatribuir padrão -projects.column.unset_default_desc=Desatribuir esta coluna como padrão projects.column.delete=Excluir coluna -projects.column.deletion_desc=Excluir uma coluna do projeto move todas as issues relacionadas para 'Sem categoria'. Continuar? projects.column.color=Cor projects.open=Abrir projects.close=Fechar @@ -1357,6 +1362,7 @@ issues.choose.blank=Padrão issues.choose.blank_about=Criar uma issue a partir do modelo padrão. issues.choose.ignore_invalid_templates=Modelos inválidos foram ignorados issues.choose.invalid_templates=%v modelo(s) inválido(s) encontrado(s) +issues.choose.invalid_config=A configuração da issue contém erros: issues.no_ref=Nenhum branch/tag especificado issues.create=Criar issue issues.new_label=Nova etiqueta @@ -1427,7 +1433,6 @@ issues.filter_sort.moststars=Mais estrelas issues.filter_sort.feweststars=Menos estrelas issues.filter_sort.mostforks=Mais forks issues.filter_sort.fewestforks=Menos forks -issues.keyword_search_unavailable=A pesquisa por palavra-chave não está disponível no momento. Entre em contato com o administrador do site. issues.action_open=Abrir issues.action_close=Fechar issues.action_label=Etiqueta @@ -1480,6 +1485,11 @@ issues.author_helper=Este usuário é o autor. issues.role.owner=Proprietário issues.role.owner_helper=Este usuário é o dono deste repositório. issues.role.member=Membro +issues.role.collaborator=Colaborador +issues.role.collaborator_helper=Este usuário foi convidado para colaborar no repositório. +issues.role.first_time_contributor=Primeira vez contribuindo +issues.role.first_time_contributor_helper=Esta é a primeira contribuição deste usuário para o repositório. +issues.role.contributor=Contribuidor issues.re_request_review=Re-solicitar revisão issues.is_stale=Houve alterações nessa PR desde essa revisão issues.remove_request_review=Remover solicitação de revisão @@ -1495,6 +1505,8 @@ issues.label_description=Descrição da etiqueta issues.label_color=Cor da etiqueta issues.label_exclusive=Exclusivo issues.label_archive=Arquivar etiqueta +issues.label_archived_filter=Mostrar etiquetas arquivadas +issues.label_archive_tooltip=Etiquetas arquivadas são excluídas, por padrão, das sugestões ao pesquisar por etiqueta. issues.label_exclusive_desc=Nomeie o rótulo <code>escopo/item</code> para torná-lo mutuamente exclusivo com outros rótulos do <code>escopo/</code>. issues.label_exclusive_warning=Quaisquer rótulos com escopo conflitantes serão removidos ao editar os rótulos de uma issue ou pull request. issues.label_count=%d etiquetas @@ -1573,6 +1585,7 @@ issues.due_date_form=dd/mm/aaaa issues.due_date_form_add=Adicionar data limite issues.due_date_form_edit=Editar issues.due_date_form_remove=Remover +issues.due_date_not_writer=Você precisa de acesso de gravação a esse repositório para atualizar a data limite de uma issue. issues.due_date_not_set=Data limite não informada. issues.due_date_added=adicionou a data limite %s %s issues.due_date_modified=modificou a data limite de %[2]s para %[1]s %[3]s @@ -1669,7 +1682,6 @@ pulls.compare_compare=pull de pulls.switch_comparison_type=Mudar tipo de comparação pulls.switch_head_and_base=Trocar cabeça e base pulls.filter_branch=Filtrar branch -pulls.no_results=Nada encontrado. pulls.show_all_commits=Mostrar todos os commits pulls.show_changes_since_your_last_review=Mostrar alterações desde sua última revisão pulls.showing_only_single_commit=Mostrando apenas as alterações do commit %[1]s @@ -1736,6 +1748,7 @@ pulls.merge_pull_request=Criar commit de merge pulls.rebase_merge_pull_request=Rebase e fast-forward pulls.rebase_merge_commit_pull_request=Rebase e criar commit de merge pulls.squash_merge_pull_request=Criar commit de squash +pulls.fast_forward_only_merge_pull_request=Apenas Fast-forward pulls.merge_manually=Merge feito manualmente pulls.merge_commit_id=A ID de merge commit pulls.require_signed_wont_sign=O branch requer commits assinados, mas este merge não será assinado @@ -1759,6 +1772,8 @@ pulls.status_checks_failure=Algumas verificações falharam pulls.status_checks_error=Algumas verificações reportaram erros pulls.status_checks_requested=Obrigatário pulls.status_checks_details=Detalhes +pulls.status_checks_hide_all=Ocultar todas as verificações +pulls.status_checks_show_all=Mostrar todas as verificações pulls.update_branch=Atualizar branch por merge pulls.update_branch_rebase=Atualizar branch por rebase pulls.update_branch_success=Atualização do branch foi bem-sucedida @@ -1767,6 +1782,9 @@ pulls.outdated_with_base_branch=Este branch está desatualizado com o branch bas pulls.close=Fechar pull request pulls.closed_at=`fechou este pull request <a id="%[1]s" href="#%[1]s">%[2]s</a>` pulls.reopened_at=`reabriu este pull request <a id="%[1]s" href="#%[1]s">%[2]s</a>` +pulls.cmd_instruction_checkout_title=Checkout +pulls.cmd_instruction_merge_title=Merge +pulls.cmd_instruction_merge_desc=Faça merge das alterações e atualize no Gitea. pulls.clear_merge_message=Limpar mensagem do merge pulls.clear_merge_message_hint=Limpar a mensagem de merge só irá remover o conteúdo da mensagem de commit e manter trailers git gerados, como "Co-Authored-By …". @@ -1863,6 +1881,8 @@ wiki.page_name_desc=Digite um nome para esta página Wiki. Alguns nomes especiai wiki.original_git_entry_tooltip=Ver o arquivo Git original em vez de usar o link amigável. activity=Atividade +activity.navbar.pulse=Pulso +activity.navbar.contributors=Contribuidores activity.period.filter_label=Período: activity.period.daily=1 dia activity.period.halfweekly=3 dias @@ -1928,18 +1948,10 @@ activity.git_stats_and_deletions=e activity.git_stats_deletion_1=%d exclusão activity.git_stats_deletion_n=%d exclusões +contributors.contribution_type.filter_label=Tipo de contribuição: contributors.contribution_type.commits=Commits - -search=Pesquisar -search.search_repo=Pesquisar no repositório... -search.type.tooltip=Tipo de pesquisa -search.fuzzy=Aproximada -search.fuzzy.tooltip=Incluir resultados que sejam próximos ao termo de busca -search.match=Corresponde -search.match.tooltip=Incluir somente resultados que correspondam exatamente ao termo de busca -search.results=Resultados da pesquisa para "%s" em <a href="%s">%s</a> -search.code_no_results=Nenhum código-fonte correspondente ao seu termo de pesquisa foi encontrado. -search.code_search_unavailable=A pesquisa por código não está disponível no momento. Entre em contato com o administrador do site. +contributors.contribution_type.additions=Adições +contributors.contribution_type.deletions=Exclusões settings=Configurações settings.desc=Opções é onde você pode gerenciar as configurações para o repositório @@ -2008,6 +2020,7 @@ settings.pulls.default_allow_edits_from_maintainers=Permitir edições de manten settings.releases_desc=Habilitar versões do Repositório settings.packages_desc=Habilitar Registro de Pacotes de Repositório settings.projects_desc=Habilitar Projetos do Repositório +settings.projects_mode_all=Todos os projetos settings.actions_desc=Habilitar ações do repositório settings.admin_settings=Configurações do administrador settings.admin_enable_health_check=Habilitar verificações de integridade (git fsck) no repositório @@ -2079,7 +2092,6 @@ settings.delete_collaborator=Remover settings.collaborator_deletion=Remover colaborador settings.collaborator_deletion_desc=A exclusão de um colaborador irá revogar o acesso a este repositório. Continuar? settings.remove_collaborator_success=O colaborador foi removido. -settings.search_user_placeholder=Pesquisar usuário... settings.org_not_allowed_to_be_collaborator=Organizações não podem ser adicionadas como um colaborador. settings.change_team_access_not_allowed=Alteração do acesso da equipe para o repositório está restrito ao proprietário da organização settings.team_not_in_organization=A equipe não está na mesma organização que o repositório @@ -2087,7 +2099,6 @@ settings.teams=Equipes settings.add_team=Adicionar Equipe settings.add_team_duplicate=A equipe já tem o repositório settings.add_team_success=A equipe agora tem acesso ao repositório. -settings.search_team=Pesquisar Equipe… settings.change_team_permission_tip=A permissão da equipe está definida na página de configurações da equipe e não pode ser alterada por repositório settings.delete_team_tip=Esta equipe tem acesso a todos os repositórios e não pode ser removida settings.remove_team_success=O acesso da equipe ao repositório foi removido. @@ -2232,9 +2243,7 @@ settings.protect_whitelist_committers=Lista permitida para push settings.protect_whitelist_committers_desc=Somente usuários ou equipes da lista permitida serão autorizados realizar push neste branch (mas não forçar o push). settings.protect_whitelist_deploy_keys=Dar permissão às chaves de deploy com acesso de gravação para push. settings.protect_whitelist_users=Usuários com permissão para realizar push: -settings.protect_whitelist_search_users=Pesquisar usuários... settings.protect_whitelist_teams=Equipes com permissão para realizar push: -settings.protect_whitelist_search_teams=Pesquisar equipes... settings.protect_merge_whitelist_committers=Habilitar controle de permissão de merge settings.protect_merge_whitelist_committers_desc=Permitir que determinados usuários ou equipes possam aplicar merge de pull requests neste branch. settings.protect_merge_whitelist_users=Usuários com permissão para aplicar merge: @@ -2301,6 +2310,9 @@ settings.archive.error=Um erro ocorreu enquanto estava sendo arquivado o reposit settings.archive.error_ismirror=Você não pode arquivar um repositório espelhado. settings.archive.branchsettings_unavailable=Configurações do branch não estão disponíveis quando o repositório está arquivado. settings.archive.tagsettings_unavailable=As configurações de tag não estão disponíveis se o repositório estiver arquivado. +settings.unarchive.button=Desarquivar o repositório +settings.unarchive.header=Desarquivar este repositório +settings.unarchive.success=O repositório foi desarquivado com sucesso. settings.update_avatar_success=O avatar do repositório foi atualizado. settings.lfs=LFS settings.lfs_filelist=Arquivos LFS armazenados neste repositório @@ -2423,6 +2435,7 @@ release.edit_release=Atualizar versão release.delete_release=Excluir versão release.delete_tag=Apagar Tag release.deletion=Excluir versão +release.deletion_desc=A exclusão de uma versão apenas a remove do Gitea. Isso não afetará a tag do Git, o conteúdo do seu repositório ou seu histórico. Continuar? release.deletion_success=A versão foi excluída. release.deletion_tag_desc=A tag será excluída do repositório. Conteúdo do repositório e histórico permanecerão inalterados. Continuar? release.deletion_tag_success=A tag foi excluída. @@ -2488,6 +2501,9 @@ error.csv.unexpected=Não é possível renderizar este arquivo porque ele conté error.csv.invalid_field_count=Não é possível renderizar este arquivo porque ele tem um número errado de campos na linha %d. [graphs] +component_loading=Carregando %s... +component_loading_failed=Não foi possível carregar %s +component_loading_info=Isto pode demorar um pouco… [org] org_name_holder=Nome da organização @@ -2518,6 +2534,7 @@ form.create_org_not_allowed=Você não tem permissão para criar uma organizaç settings=Configurações settings.options=Organização settings.full_name=Nome completo +settings.email=E-mail de contato settings.website=Site settings.location=Localização settings.permission=Permissões @@ -2590,7 +2607,6 @@ teams.write_permission_desc=Esta equipe concede acesso para <strong>escrita</str teams.admin_permission_desc=Esta equipe concede acesso de <strong>Administrador</strong>: Membros podem ler, fazer push e adicionar outros colaboradores para os repositórios da equipe. teams.create_repo_permission_desc=Além disso, esta equipe concede permissão de <strong>Criar repositório</strong>: membros podem criar novos repositórios na organização. teams.repositories=Repositórios da equipe -teams.search_repo_placeholder=Pesquisar repositório... teams.remove_all_repos_title=Remover todos os repositórios da equipe teams.remove_all_repos_desc=Isto irá remover todos os repositórios da equipe. teams.add_all_repos_title=Adicionar todos os repositórios @@ -2606,11 +2622,13 @@ teams.all_repositories_helper=A equipe tem acesso a todos os repositórios. Sele teams.all_repositories_read_permission_desc=Esta equipe concede acesso <strong>Leitura</strong> a <strong>todos os repositórios</strong>: membros podem ver e clonar repositórios. teams.all_repositories_write_permission_desc=Esta equipe concede acesso <strong>Escrita</strong> a <strong>todos os repositórios</strong>: os membros podem ler de e fazer push para os repositórios. teams.all_repositories_admin_permission_desc=Esta equipe concede acesso <strong>Administrativo</strong> a <strong>todos os repositórios</strong>: os membros podem ler, fazer push e adicionar colaboradores aos repositórios. +teams.invite.title=Você foi convidado para fazer parte da equipe <strong>%s</strong> na organização <strong>%s</strong>. teams.invite.by=Convidado por %s teams.invite.description=Por favor, clique no botão abaixo para se juntar à equipe. [admin] dashboard=Painel +identity_access=Identidade e acesso users=Contas de usuário organizations=Organizações repositories=Repositórios @@ -2619,11 +2637,14 @@ integrations=Integrações authentication=Fontes de autenticação emails=E-mails do Usuário config=Configuração +config_summary=Resumo +config_settings=Configurações notices=Avisos do sistema monitor=Monitoramento first_page=Primeira last_page=Última total=Total: %d +settings=Configurações de Administrador dashboard.new_version_hint=Uma nova versão está disponível: %s. Versão atual: %s. Visite <a target="_blank" rel="noreferrer" href="https://blog.gitea.io">o blog</a> para mais informações. dashboard.statistic=Resumo @@ -2782,9 +2803,6 @@ repos.unadopted.no_more=Não foram encontrados mais repositórios não adotados repos.owner=Proprietário repos.name=Nome repos.private=Privado -repos.watches=Observadores -repos.stars=Favoritos -repos.forks=Forks repos.issues=Issues repos.size=Tamanho repos.lfs_size=Tamanho do LFS @@ -2906,7 +2924,6 @@ auths.tip.nextcloud=`Registre um novo consumidor OAuth em sua instância usando auths.tip.dropbox=Criar um novo aplicativo em https://www.dropbox.com/developers/apps auths.tip.facebook=`Cadastrar um novo aplicativo em https://developers.facebook.com/apps e adicionar o produto "Facebook Login"` auths.tip.github=Cadastrar um novo aplicativo de OAuth na https://github.com/settings/applications/new -auths.tip.gitlab=Cadastrar um novo aplicativo em https://gitlab.com/profile/applications auths.tip.google_plus=Obter credenciais de cliente OAuth2 do console de API do Google em https://console.developers.google.com/ auths.tip.openid_connect=Use o OpenID Connect Discovery URL (<servidor>/.well-known/openid-configuration) para especificar os endpoints auths.tip.twitter=Vá em https://dev.twitter.com/apps, crie um aplicativo e certifique-se de que está habilitada a opção “Allow this application to be used to Sign in with Twitter“ @@ -3414,13 +3431,20 @@ runners.status.idle=Inativo runners.status.active=Ativo runners.status.offline=Offiline runners.version=Versão +runners.reset_registration_token=Redefinir token de registro runners.reset_registration_token_success=Token de registro de runner redefinido com sucesso runs.all_workflows=Todos os Workflows runs.commit=Commit +runs.scheduled=Agendado runs.pushed_by=push feito por runs.invalid_workflow_helper=O arquivo de configuração do workflow é inválido. Por favor, verifique seu arquivo de configuração: %s +runs.actor=Ator runs.status=Status +runs.actors_no_select=Todos os atores +runs.status_no_select=Todos os Status +runs.no_results=Não houve correspondência de resultados. +runs.empty_commit_message=(mensagem de commit vazia) need_approval_desc=Precisa de aprovação para executar workflows para pull request do fork. @@ -3433,5 +3457,9 @@ type-3.display_name=Projeto da organização [git.filemode] ; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", … +directory=Diretório +normal_file=Arquivo normal +executable_file=Arquivo executável symbolic_link=Link simbólico +submodule=Submódulo diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 99165ed332..ea80cd7abb 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -25,6 +25,7 @@ enable_javascript=Este sítio Web requer JavaScript. toc=Índice licenses=Licenças return_to_gitea=Retornar ao Gitea +more_items=Mais itens username=Nome de utilizador email=Endereço de email @@ -113,6 +114,7 @@ loading=Carregando… error=Erro error404=A página que pretende aceder <strong>não existe</strong> ou <strong>não tem autorização</strong> para a ver. go_back=Voltar +invalid_data=Dados inválidos: %v never=Nunca unknown=Desconhecido @@ -142,6 +144,43 @@ confirm_delete_selected=Confirma a exclusão de todos os itens marcados? name=Nome value=Valor +filter=Filtro +filter.clear=Retirar filtro +filter.is_archived=Arquivado +filter.not_archived=Não arquivado +filter.is_fork=Derivado +filter.not_fork=Não derivado +filter.is_mirror=Replicado +filter.not_mirror=Não replicado +filter.is_template=Modelo +filter.not_template=Não é modelo +filter.public=Público +filter.private=Privado + +no_results_found=Não foram encontrados quaisquer resultados. + +[search] +search=Pesquisar... +type_tooltip=Tipo de pesquisa +fuzzy=Aproximada +fuzzy_tooltip=Incluir também os resultados que estejam próximos do termo de pesquisa +match=Fiel +match_tooltip=Incluir somente os resultados que correspondam rigorosamente ao termo de pesquisa +repo_kind=Pesquisar repositórios... +user_kind=Pesquisar utilizadores... +org_kind=Pesquisar organizações... +team_kind=Pesquisar equipas... +code_kind=Pesquisar código... +code_search_unavailable=A pesquisa de código não está disponível, neste momento. Entre em contacto com o administrador. +code_search_by_git_grep=Os resultados da pesquisa no código-fonte neste momento são fornecidos pelo "git grep". Esses resultados podem ser melhores se o administrador habilitar o indexador do repositório. +package_kind=Pesquisar pacotes... +project_kind=Pesquisar planeamentos... +branch_kind=Pesquisar ramos... +commit_kind=Pesquisar cometimentos... +runner_kind=Pesquisar executores... +no_results=Não foram encontrados resultados correspondentes. +keyword_search_unavailable=Pesquisar por palavra-chave não está disponível, neste momento. Entre em contacto com o administrador. + [aria] navbar=Barra de navegação footer=Rodapé @@ -247,6 +286,7 @@ email_title=Configurações de email smtp_addr=Servidor SMTP smtp_port=Porto do SMTP smtp_from=Email do remetente +smtp_from_invalid=O endereço para "Enviar email como" é inválido smtp_from_helper=Endereço de email que o Gitea vai usar. Insira um endereço de email simples ou use o formato "Nome" <email@exemplo.com>. mailer_user=Nome de utilizador do SMTP mailer_password=Senha do SMTP @@ -306,6 +346,7 @@ env_config_keys=Configuração do ambiente env_config_keys_prompt=As seguintes variáveis de ambiente também serão aplicadas ao seu ficheiro de configuração: [home] +nav_menu=Menu de navegação uname_holder=Nome de utilizador ou endereço de email password_holder=Senha switch_dashboard_context=Trocar contexto do painel @@ -315,7 +356,6 @@ collaborative_repos=Repositórios colaborativos my_orgs=As minhas organizações my_mirrors=As minhas réplicas view_home=Ver %s -search_repos=Procurar um repositório… filter=Outros filtros filter_by_team_repositories=Filtrar por repositórios da equipa feed_of=`Fonte de "%s"` @@ -336,20 +376,8 @@ issues.in_your_repos=Nos seus repositórios repos=Repositórios users=Utilizadores organizations=Organizações -search=Procurar go_to=Ir para code=Código -search.type.tooltip=Tipo de pesquisa -search.fuzzy=Aproximada -search.fuzzy.tooltip=Incluir também os resultados que estejam próximos do termo de pesquisa -search.match=Fiel -search.match.tooltip=Incluir somente os resultados que correspondam rigorosamente ao termo de pesquisa -code_search_unavailable=A pesquisa por código-fonte não está disponível, neste momento. Entre em contacto com o administrador. -repo_no_results=Não foram encontrados quaisquer repositórios correspondentes. -user_no_results=Não foram encontrados quaisquer utilizadores correspondentes. -org_no_results=Não foram encontradas quaisquer organizações correspondentes. -code_no_results=Não foi encontrado qualquer código-fonte correspondente à sua pesquisa. -code_search_results=`Resultados da pesquisa para "%s"` code_last_indexed_at=Última indexação %s relevant_repositories_tooltip=Repositórios que são derivações ou que não têm tópico, nem ícone, nem descrição, estão escondidos. relevant_repositories=Apenas estão a ser mostrados os repositórios relevantes. <a href="%s">Mostrar resultados não filtrados</a>. @@ -367,7 +395,7 @@ forgot_password_title=Esqueci-me da senha forgot_password=Esqueceu a sua senha? sign_up_now=Precisa de uma conta? Inscreva-se agora. sign_up_successful=A conta foi criada com sucesso. Bem-vindo/a! -confirmation_mail_sent_prompt=Foi enviado um novo email de confirmação para <b>%s</b>. Verifique a sua caixa de entrada dentro de %s para completar o processo de inscrição. +confirmation_mail_sent_prompt_ex=Foi enviado um email de confirmação para <b>%s</b>. Verifique a sua caixa de entrada dentro de %s para completar o processo de registo. Se o seu endereço de email de registo estiver errado, pode iniciar a sessão novamente e mudá-lo. must_change_password=Mude a sua senha allow_password_change=Exigir que o utilizador mude a senha (recomendado) reset_password_mail_sent_prompt=Foi enviado um email de confirmação para <b>%s</b>. Verifique a sua caixa de entrada dentro de %s para completar o processo de recuperação. @@ -377,6 +405,7 @@ prohibit_login=Início de sessão proibido prohibit_login_desc=A sua conta está proibida de iniciar sessão. Contacte o administrador. resent_limit_prompt=Já fez um pedido recentemente para enviar um email para pôr a conta em funcionamento. Espere 3 minutos e tente novamente. has_unconfirmed_mail=Olá %s, tem um endereço de email não confirmado (<b>%s</b>). Se não recebeu um email de confirmação ou precisa de o voltar a enviar, clique no botão abaixo. +change_unconfirmed_mail_address=Se o seu endereço de email estiver errado, pode mudá-lo aqui e enviar um novo email de confirmação. resend_mail=Clique aqui para voltar a enviar um email para pôr a conta em funcionamento email_not_associate=O endereço de email não está associado a qualquer conta. send_reset_mail=Enviar email de recuperação da conta @@ -557,6 +586,7 @@ team_name_been_taken=O nome da equipa já foi tomado. team_no_units_error=Permitir acesso a pelo menos uma secção do repositório. email_been_used=O endereço de email já está em uso. email_invalid=O endereço de email é inválido. +email_domain_is_not_allowed=O domínio do email de utilizador <b>%s</b> entra en conflito com o EMAIL_DOMAIN_ALLOWLIST ou com o EMAIL_DOMAIN_BLOCKLIST. Verifique se a operação estava prevista. openid_been_used=O endereço OpenID "%s" já está em uso. username_password_incorrect=O nome de utilizador ou a senha estão errados. password_complexity=A senha não passa nos requisitos de complexidade: @@ -568,6 +598,8 @@ enterred_invalid_repo_name=O nome do repositório que inseriu está errado. enterred_invalid_org_name=O nome da organização que inseriu está errado. enterred_invalid_owner_name=O novo nome de proprietário não é válido. enterred_invalid_password=A senha que inseriu está errada. +unset_password=O utilizador não definiu a senha. +unsupported_login_type=O tipo de início de sessão não é suportado para eliminar a conta. user_not_exist=O utilizador não existe. team_not_exist=A equipa não existe. last_org_owner=Não pode remover o último utilizador da equipa 'proprietários'. Tem que haver pelo menos um proprietário numa organização. @@ -617,6 +649,30 @@ form.name_reserved=O nome de utilizador "%s" está reservado. form.name_pattern_not_allowed=O padrão "%s" não é permitido no nome de utilizador. form.name_chars_not_allowed=O nome de utilizador "%s" contém caracteres inválidos. +block.block=Bloquear +block.block.user=Bloquear utilizador +block.block.org=Bloquear utilizador para a organização +block.block.failure=Falhou o bloqueio do utilizador: %s +block.unblock=Desbloquear +block.unblock.failure=Falhou o desbloqueio do utilizador: %s +block.blocked=Bloqueou este utilizador. +block.title=Bloquear um utilizador +block.info=Bloquear um utilizador evita que este interaja com repositórios, tal como abrir ou comentar em pedidos de integração ou questões. Saiba mais sobre como bloquear um utilizador. +block.info_1=Bloquear um utilizador impede as seguintes operações na sua conta e nos seus repositórios: +block.info_2=seguir a sua conta +block.info_3=enviar-lhe notificações ao @mencionar o seu nome de utilizador +block.info_4=convidá-lo/a para ser colaborador/a nos repositórios dele/dela +block.info_5=juntar aos favoritos, derivar ou vigiar repositórios +block.info_6=abrir e comentar questões ou pedidos de integração +block.info_7=reagir aos seus comentários em questões ou pedidos de integração +block.user_to_block=Utilizador a bloquear +block.note=Nota +block.note.title=Nota opcional: +block.note.info=A nota não é visível para o utilizador bloqueado. +block.note.edit=Editar nota +block.list=Utilizadores bloqueados +block.list.none=Você ainda não bloqueou quaisquer utilizadores. + [settings] profile=Perfil account=Conta @@ -761,7 +817,6 @@ gpg_invalid_token_signature=A chave GPG, assinatura ou código fornecidos não c gpg_token_required=Tem que fornecer uma assinatura para o código abaixo gpg_token=Código gpg_token_help=Pode gerar uma assinatura usando o seguinte comando: -gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig gpg_token_signature=Assinatura GPG blindada (com armadura ASCII) key_signature_gpg_placeholder=Começa com '-----BEGIN PGP SIGNATURE-----' verify_gpg_key_success=A chave GPG "%s" foi validada. @@ -954,8 +1009,9 @@ fork_visibility_helper=A visibilidade de um repositório derivado não poderá s fork_branch=Ramo a ser clonado para a derivação all_branches=Todos os ramos fork_no_valid_owners=Não pode fazer uma derivação deste repositório porque não existem proprietários válidos. +fork.blocked_user=Não pode derivar o repositório porque foi bloqueado/a pelo/a proprietário/a do repositório. use_template=Usar este modelo -clone_in_vsc=Clonar no VS Code +open_with_editor=Abrir com %s download_zip=Descarregar ZIP download_tar=Descarregar TAR.GZ download_bundle=Descarregar PACOTE @@ -1008,6 +1064,7 @@ watchers=Vigilantes stargazers=Fãs stars_remove_warning=Isto irá remover todas as marcas de favoritos deste repositório. forks=Derivações +stars=Favoritos reactions_more=e mais %d unit_disabled=O administrador desabilitou esta secção do repositório. language_other=Outros @@ -1129,6 +1186,7 @@ watch=Vigiar unstar=Tirar dos favoritos star=Juntar aos favoritos fork=Derivar +action.blocked_user=Não pode realizar a operação porque foi bloqueado/a pelo/a proprietário/a do repositório. download_archive=Descarregar repositório more_operations=Mais operações @@ -1257,6 +1315,8 @@ editor.file_editing_no_longer_exists=O ficheiro que está a ser editado, "%s", j editor.file_deleting_no_longer_exists=O ficheiro que está a ser eliminado, "%s", já não existe neste repositório. editor.file_changed_while_editing=O conteúdo do ficheiro mudou desde que começou a editar. <a target="_blank" rel="noopener noreferrer" href="%s">Clique aqui</a> para ver as modificações ou clique em <strong>Cometer novamente</strong> para escrever por cima. editor.file_already_exists=Já existe um ficheiro com o nome "%s" neste repositório. +editor.commit_id_not_matching=O ID do cometimento não corresponde ao ID de quando começou a editar. Faça o cometimento para um ramo de remendo (patch) e depois faça a integração. +editor.push_out_of_date=O envio parece estar obsoleto. editor.commit_empty_file_header=Cometer um ficheiro vazio editor.commit_empty_file_text=O ficheiro que está prestes a cometer está vazio. Quer continuar? editor.no_changes_to_show=Não existem modificações para mostrar. @@ -1280,9 +1340,8 @@ commits.desc=Navegar pelo histórico de modificações no código fonte. commits.commits=Cometimentos commits.no_commits=Não há cometimentos em comum. "%s" e "%s" têm históricos completamente diferentes. commits.nothing_to_compare=Estes ramos são iguais. -commits.search=Procurar cometimentos… commits.search.tooltip=Pode prefixar palavras-chave com "author:", "committer:", "after:", ou "before:". Por exemplo: "revert author:Alice before:2019-01-13". -commits.find=Procurar +commits.search_branch=Este ramo commits.search_all=Todos os ramos commits.author=Autor(a) commits.message=Mensagem @@ -1333,7 +1392,6 @@ projects.type.basic_kanban=Kanban básico projects.type.bug_triage=Triagem de erros projects.template.desc=Modelo de planeamento projects.template.desc_helper=Escolha um modelo de planeamento para começar -projects.type.uncategorized=Sem categoria projects.column.edit=Editar coluna projects.column.edit_title=Nome projects.column.new_title=Nome @@ -1341,8 +1399,6 @@ projects.column.new_submit=Criar coluna projects.column.new=Nova coluna projects.column.set_default=Tornar predefinida projects.column.set_default_desc=Definir esta coluna como a predefinida para questões e pedidos de integração não categorizados -projects.column.unset_default=Deixar de ser a predefinida -projects.column.unset_default_desc=Faz com que esta coluna deixe de ser a predefinida projects.column.delete=Eliminar coluna projects.column.deletion_desc=Eliminar uma coluna de um planeamento faz com que todas as questões que nela constam sejam movidas para a coluna 'Sem categoria'. Continuar? projects.column.color=Colorido @@ -1379,6 +1435,8 @@ issues.new.assignees=Encarregados issues.new.clear_assignees=Retirar todos os encarregados issues.new.no_assignees=Sem encarregados issues.new.no_reviewers=Sem revisores +issues.new.blocked_user=Não pode criar a questão porque foi bloqueado/a pelo/a proprietário/a do repositório. +issues.edit.blocked_user=Não pode editar o conteúdo porque foi bloqueado/a pelo/a remetente ou pelo/a proprietário/a do repositório. issues.choose.get_started=Começar issues.choose.open_external_link=Abrir issues.choose.blank=Padrão @@ -1456,7 +1514,6 @@ issues.filter_sort.moststars=Favorito (decrescente) issues.filter_sort.feweststars=Favorito (crescente) issues.filter_sort.mostforks=Mais derivações issues.filter_sort.fewestforks=Menos derivações -issues.keyword_search_unavailable=A pesquisa por palavra-chave não está disponível, neste momento. Entre em contacto com o administrador. issues.action_open=Abrir issues.action_close=Fechar issues.action_label=Rótulo @@ -1494,6 +1551,7 @@ issues.close_comment_issue=Comentar e fechar issues.reopen_issue=Reabrir issues.reopen_comment_issue=Comentar e reabrir issues.create_comment=Comentar +issues.comment.blocked_user=Não pode criar ou editar o comentário porque foi bloqueado/a pelo remetente ou pelo/a proprietário/a do repositório. issues.closed_at=`encerrou esta questão <a id="%[1]s" href="#%[1]s">%[2]s</a>` issues.reopened_at=`reabriu esta questão <a id="%[1]s" href="#%[1]s">%[2]s</a>` issues.commit_ref_at=`referenciou esta questão num cometimento <a id="%[1]s" href="#%[1]s">%[2]s</a>` @@ -1692,6 +1750,7 @@ compare.compare_head=comparar pulls.desc=Habilitar pedidos de integração e revisão de código. pulls.new=Novo pedido de integração +pulls.new.blocked_user=Não pode criar o pedido de integração porque foi bloqueado/a pelo/a proprietário/a do repositório. pulls.view=Ver pedido de integração pulls.compare_changes=Novo pedido de integração pulls.allow_edits_from_maintainers=Permitir edições por parte dos responsáveis @@ -1708,7 +1767,6 @@ pulls.compare_compare=puxar de pulls.switch_comparison_type=Trocar o tipo de comparação pulls.switch_head_and_base=Trocar o topo com a base pulls.filter_branch=Filtrar ramo -pulls.no_results=Não foram encontrados quaisquer resultados. pulls.show_all_commits=Mostrar todos os cometimentos pulls.show_changes_since_your_last_review=Mostrar modificações desde a sua última revisão pulls.showing_only_single_commit=Mostrando apenas as modificações do comentimento %[1]s @@ -1914,7 +1972,9 @@ wiki.original_git_entry_tooltip=Ver o ficheiro Git original, ao invés de usar u activity=Trabalho activity.navbar.pulse=Pulso +activity.navbar.code_frequency=Frequência de programação activity.navbar.contributors=Contribuidores +activity.navbar.recent_commits=Cometimentos recentes activity.period.filter_label=Período: activity.period.daily=1 dia activity.period.halfweekly=3 dias @@ -1985,17 +2045,6 @@ contributors.contribution_type.commits=Cometimentos contributors.contribution_type.additions=Adições contributors.contribution_type.deletions=Eliminações -search=Procurar -search.search_repo=Procurar repositório -search.type.tooltip=Tipo de pesquisa -search.fuzzy=Aproximada -search.fuzzy.tooltip=Incluir também os resultados que estejam próximos do termo de pesquisa -search.match=Fiel -search.match.tooltip=Incluir somente os resultados que correspondam rigorosamente ao termo de pesquisa -search.results=Resultados da procura de "%s" em <a href="%s">%s</a> -search.code_no_results=Não foi encontrado qualquer código-fonte correspondente à sua pesquisa. -search.code_search_unavailable=A pesquisa por código-fonte não está disponível, neste momento. Entre em contacto com o administrador. - settings=Configurações settings.desc=Configurações é onde pode gerir as configurações do repositório settings.options=Repositório @@ -2044,6 +2093,8 @@ settings.branches.add_new_rule=Adicionar nova regra settings.advanced_settings=Configurações avançadas settings.wiki_desc=Habilitar wiki do repositório settings.use_internal_wiki=Usar o wiki nativo +settings.default_wiki_branch_name=Nome do ramo predefinido do wiki +settings.failed_to_change_default_wiki_branch=Falhou ao mudar o nome do ramo predefinido do wiki. settings.use_external_wiki=Usar um wiki externo settings.external_wiki_url=URL do wiki externo settings.external_wiki_url_error=O URL do wiki externo não é um URL válido. @@ -2074,6 +2125,10 @@ settings.pulls.default_allow_edits_from_maintainers=Permitir, por norma, que os settings.releases_desc=Habilitar lançamentos no repositório settings.packages_desc=Habilitar o registo de pacotes do repositório settings.projects_desc=Habilitar planeamentos no repositório +settings.projects_mode_desc=Modo de planeamentos (tipos de planeamentos a mostrar) +settings.projects_mode_repo=Apenas planeamentos de repositórios +settings.projects_mode_owner=Apenas planeamentos de utilizadores ou de organizações +settings.projects_mode_all=Todos os planeamentos settings.actions_desc=Habilitar operações no repositório (Gitea Actions) settings.admin_settings=Configurações do administrador settings.admin_enable_health_check=Habilitar verificações de integridade (git fsck) no repositório @@ -2099,6 +2154,7 @@ settings.convert_fork_succeed=A derivação foi convertida num repositório norm settings.transfer=Transferir a propriedade settings.transfer.rejected=A transferência do repositório foi rejeitada. settings.transfer.success=A transferência do repositório foi bem sucedida. +settings.transfer.blocked_user=Não foi possível transferir o repositório porque foi bloqueado/a pelo/a novo/a proprietário/a. settings.transfer_abort=Cancelar a transferência settings.transfer_abort_invalid=Não pode cancelar a transferência de um repositório inexistente. settings.transfer_abort_success=A transferência de repositório para %s foi cancelada com sucesso. @@ -2144,11 +2200,11 @@ settings.add_collaborator_success=O colaborador foi adicionado. settings.add_collaborator_inactive_user=Não é possível adicionar um utilizador desabilitado como colaborador. settings.add_collaborator_owner=Não é possível adicionar um proprietário como um colaborador. settings.add_collaborator_duplicate=O colaborador já tinha sido adicionado a este repositório. +settings.add_collaborator.blocked_user=O/A colaborador/a foi bloqueado/a pelo/a proprietário/a do repositório ou vice-versa. settings.delete_collaborator=Remover settings.collaborator_deletion=Remover colaborador settings.collaborator_deletion_desc=Remover um colaborador irá revogar o seu acesso a este repositório. Quer continuar? settings.remove_collaborator_success=O colaborador foi removido. -settings.search_user_placeholder=Procurar utilizador… settings.org_not_allowed_to_be_collaborator=As organizações não podem ser adicionadas como colaborador. settings.change_team_access_not_allowed=Alterar o acesso da equipa ao repositório foi restrito ao proprietário da organização settings.team_not_in_organization=A equipa não está na mesma organização que o repositório @@ -2156,7 +2212,6 @@ settings.teams=Equipas settings.add_team=Adicionar equipa settings.add_team_duplicate=A equipa já tem o repositório settings.add_team_success=A equipa agora tem acesso ao repositório. -settings.search_team=Procurar equipa… settings.change_team_permission_tip=A permissão da equipa é definida na página de configurações da equipa e não pode ter modificações específicas de cada repositório settings.delete_team_tip=Esta equipa tem acesso a todos os repositórios e não pode ser removida settings.remove_team_success=O acesso da equipa ao repositório foi removido. @@ -2309,9 +2364,7 @@ settings.protect_whitelist_committers=Lista de permissões para restringir os en settings.protect_whitelist_committers_desc=Apenas os utilizadores ou equipas constantes na lista terão permissão para enviar para este ramo (mas não poderão fazer envios forçados). settings.protect_whitelist_deploy_keys=Dar permissão às chaves de instalação para terem acesso de escrita para enviar. settings.protect_whitelist_users=Utilizadores com permissão para enviar: -settings.protect_whitelist_search_users=Procurar utilizadores… settings.protect_whitelist_teams=Equipas com permissão para enviar: -settings.protect_whitelist_search_teams=Procurar equipas… settings.protect_merge_whitelist_committers=Habilitar lista de permissão para integrar settings.protect_merge_whitelist_committers_desc=Permitir que somente utilizadores ou equipas constantes na lista de permissão possam executar, neste ramo, integrações constantes em pedidos de integração. settings.protect_merge_whitelist_users=Utilizadores com permissão para executar integrações: @@ -2556,7 +2609,6 @@ branch.default_deletion_failed=O ramo "%s" é o ramo principal, não pode ser el branch.restore=`Restaurar o ramo "%s"` branch.download=`Descarregar o ramo "%s"` branch.rename=`Renomear ramo "%s"` -branch.search=Pesquisar ramo branch.included_desc=Este ramo faz parte do ramo principal branch.included=Incluído branch.create_new_branch=Criar ramo a partir do ramo: @@ -2587,13 +2639,16 @@ find_file.no_matching=Não foi encontrado qualquer ficheiro correspondente error.csv.too_large=Não é possível apresentar este ficheiro por ser demasiado grande. error.csv.unexpected=Não é possível apresentar este ficheiro porque contém um caractere inesperado na linha %d e coluna %d. error.csv.invalid_field_count=Não é possível apresentar este ficheiro porque tem um número errado de campos na linha %d. +error.broken_git_hook=Os automatismos git deste repositório parecem estar danificados. Consulte a <a target="_blank" rel="noreferrer" href="%s">documentação</a> sobre como os consertar e depois envie alguns cometimentos para refrescar o estado. [graphs] component_loading=A carregar %s... component_loading_failed=Não foi possível carregar %s component_loading_info=Isto pode demorar um pouco… component_failed_to_load=Ocorreu um erro inesperado. +code_frequency.what=frequência de programação contributors.what=contribuições +recent_commits.what=cometimentos recentes [org] org_name_holder=Nome da organização @@ -2699,7 +2754,6 @@ teams.write_permission_desc=Esta equipa atribui acesso de <strong>escrita</stron teams.admin_permission_desc=Esta equipa atribui o acesso de <strong>administração</strong>: os seus membros podem ler de, enviar para, e adicionar colaboradores aos repositórios da equipa. teams.create_repo_permission_desc=Adicionalmente, esta equipa atribui a permissão de <strong>criar repositórios</strong>: os seus membros podem criar novos repositórios na organização. teams.repositories=Repositórios da equipa -teams.search_repo_placeholder=Procurar repositório… teams.remove_all_repos_title=Remover todos os repositórios da equipa teams.remove_all_repos_desc=Isto irá remover todos os repositórios da equipa. teams.add_all_repos_title=Adicionar todos os repositórios @@ -2708,6 +2762,7 @@ teams.add_nonexistent_repo=O repositório que está a tentar adicionar não exis teams.add_duplicate_users=O utilizador já é um membro da equipa. teams.repos.none=Não há repositórios que possam ser acedidos por esta equipa. teams.members.none=Não há membros nesta equipa. +teams.members.blocked_user=Não foi possível adicionar o/a utilizador/a porque essa operação foi bloqueada pela organização. teams.specific_repositories=Repositórios específicos teams.specific_repositories_helper=Os membros só terão acesso a repositórios explicitamente adicionados à equipa. Escolher isto <strong>não irá</strong> remover automaticamente os repositórios já adicionados com <i>Todos os repositórios</i>. teams.all_repositories=Todos os repositórios @@ -2732,6 +2787,8 @@ integrations=Integrações authentication=Fontes de autenticação emails=Emails do utilizador config=Configuração +config_summary=Resumo +config_settings=Configurações notices=Notificações do sistema monitor=Monitorização first_page=Primeira @@ -2908,9 +2965,6 @@ repos.unadopted.no_more=Não foram encontrados mais repositórios não adoptados repos.owner=Proprietário(a) repos.name=Nome repos.private=Privado -repos.watches=Vigilâncias -repos.stars=Favoritos -repos.forks=Derivações repos.issues=Questões repos.size=Tamanho repos.lfs_size=Tamanho do LFS @@ -3035,7 +3089,7 @@ auths.tip.nextcloud=`Registe um novo consumidor OAuth na sua instância usando o auths.tip.dropbox=Crie uma nova aplicação em https://www.dropbox.com/developers/apps auths.tip.facebook=`Registe uma nova aplicação em https://developers.facebook.com/apps e adicione o produto "Facebook Login"` auths.tip.github=Registe uma nova aplicação OAuth em https://github.com/settings/applications/new -auths.tip.gitlab=Registe uma nova aplicação em https://gitlab.com/profile/applications +auths.tip.gitlab_new=Registe uma nova aplicação em https://gitlab.com/-/profile/applications auths.tip.google_plus=Obtenha credenciais de cliente OAuth2 a partir da consola do Google API em https://console.developers.google.com/ auths.tip.openid_connect=Use o URL da descoberta de conexão OpenID (<server>/.well-known/openid-configuration) para especificar os extremos auths.tip.twitter=`Vá a https://dev.twitter.com/apps, 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"` @@ -3171,6 +3225,7 @@ config.picture_config=Configuração da imagem e do avatar config.picture_service=Serviço de imagem config.disable_gravatar=Desabilitar o Gravatar config.enable_federated_avatar=Habilitar avatares federados +config.open_with_editor_app_help=Os editores de "Abrir com" do menu de clonagem. Se for deixado em branco, será usado o predefinido. Expanda para ver o predefinido. config.git_config=Configuração Git config.git_disable_diff_highlight=Desabilitar o realce de sintaxe no diff @@ -3569,6 +3624,7 @@ runs.scheduled=Agendadas runs.pushed_by=enviado por runs.invalid_workflow_helper=O ficheiro de configuração da sequência de trabalho é inválido. Verifique o seu ficheiro de configuração: %s runs.no_matching_online_runner_helper=Não existem executores ligados que tenham o rótulo %s +runs.no_job_without_needs=A sequência de trabalho tem que conter pelo menos um trabalho sem dependências. runs.actor=Interveniente runs.status=Estado runs.actors_no_select=Todos os intervenientes diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index 36b9d0e39e..74c4c9c935 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -139,6 +139,15 @@ confirm_delete_selected=Вы уверены, что хотите удалить name=Название value=Значение +filter=Фильтр +filter.is_archived=Архивировано +filter.is_template=Шаблон +filter.public=Публичный +filter.private=Личный + + +[search] + [aria] navbar=Панель навигации footer=Подвал @@ -312,7 +321,6 @@ collaborative_repos=Совместные репозитории my_orgs=Мои организации my_mirrors=Мои зеркала view_home=Показать %s -search_repos=Поиск репозитория… filter=Другие фильтры filter_by_team_repositories=Фильтровать по репозиториям команды feed_of=Лента «%s» @@ -333,20 +341,8 @@ issues.in_your_repos=В ваших репозиториях repos=Репозитории users=Пользователи organizations=Организации -search=Поиск go_to=Перейти к code=Код -search.type.tooltip=Тип поиска -search.fuzzy=Неточный -search.fuzzy.tooltip=Включать результаты, которые не полностью соответствуют поисковому запросу -search.match=Соответствие -search.match.tooltip=Включать только результаты, которые точно соответствуют поисковому запросу -code_search_unavailable=В настоящее время поиск по коду недоступен. Обратитесь к администратору сайта. -repo_no_results=Подходящие репозитории не найдены. -user_no_results=Подходящие пользователи не найдены. -org_no_results=Подходящие организации не найдены. -code_no_results=Соответствующий поисковому запросу исходный код не найден. -code_search_results=Результаты поиска «%s» code_last_indexed_at=Последний проиндексированный %s relevant_repositories_tooltip=Репозитории, являющиеся ответвлениями или не имеющие ни темы, ни значка, ни описания, скрыты. relevant_repositories=Показаны только релевантные репозитории, <a href="%s">показать результаты без фильтрации</a>. @@ -364,7 +360,6 @@ forgot_password_title=Восстановить пароль forgot_password=Забыли пароль? sign_up_now=Нужен аккаунт? Зарегистрируйтесь. sign_up_successful=Учётная запись успешно создана. Добро пожаловать! -confirmation_mail_sent_prompt=Новое письмо для подтверждения направлено на <b>%s</b>. Пожалуйста, проверьте ваш почтовый ящик в течение %s для завершения регистрации. must_change_password=Обновить пароль allow_password_change=Требовать смену пароля пользователем (рекомендуется) reset_password_mail_sent_prompt=Письмо с подтверждением отправлено на <b>%s</b>. Пожалуйста, проверьте входящую почту в течение %s, чтобы завершить процесс восстановления аккаунта. @@ -612,6 +607,7 @@ form.name_reserved=Имя пользователя «%s» зарезервиро form.name_pattern_not_allowed=Шаблон «%s» не допускается в имени пользователя. form.name_chars_not_allowed=Имя пользователя «%s» содержит недопустимые символы. + [settings] profile=Профиль account=Аккаунт @@ -755,7 +751,6 @@ gpg_invalid_token_signature=Предоставленный ключ GPG, под gpg_token_required=Вы должны предоставить подпись для токена ниже gpg_token=Токен gpg_token_help=Вы можете сгенерировать подпись с помощью: -gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig gpg_token_signature=Текстовая подпись GPG key_signature_gpg_placeholder=Начинается с '-----BEGIN PGP SIGNATURE-----' verify_gpg_key_success=Ключ GPG «%s» верифицирован. @@ -942,7 +937,6 @@ fork_visibility_helper=Видимость форкнутого репозито fork_branch=Ветка для клонирования в форк all_branches=Все ветки use_template=Использовать этот шаблон -clone_in_vsc=Клонировать в VS Code download_zip=Скачать ZIP download_tar=Скачать TAR.GZ download_bundle=Скачать BUNDLE @@ -1249,9 +1243,7 @@ commits.desc=Просмотр истории изменений исходног commits.commits=Коммитов commits.no_commits=Нет общих коммитов. «%s» и «%s» имеют совершенно разные истории. commits.nothing_to_compare=Эти ветки одинаковы. -commits.search=Поиск коммитов… commits.search.tooltip=Можно предварять ключевые слова префиксами "author:", "committer:", "after:", или "before:", например "revert author:Alice before:2019-01-13". -commits.find=Поиск commits.search_all=Все ветки commits.author=Автор commits.message=Сообщение @@ -1301,7 +1293,6 @@ projects.type.basic_kanban=Обычный Канбан projects.type.bug_triage=Планирование работы с багами projects.template.desc=Шаблон проекта projects.template.desc_helper=Выберите шаблон проекта для начала -projects.type.uncategorized=Без категории projects.column.edit=Изменить столбец projects.column.edit_title=Название projects.column.new_title=Название @@ -1309,10 +1300,7 @@ projects.column.new_submit=Создать столбец projects.column.new=Новый столбец projects.column.set_default=Установить по умолчанию projects.column.set_default_desc=Назначить этот столбец по умолчанию для неклассифицированных задач и запросов на слияние -projects.column.unset_default=Снять установку по умолчанию -projects.column.unset_default_desc=Снять установку этого столбца по умолчанию projects.column.delete=Удалить столбец -projects.column.deletion_desc=При удалении столбца проекта все связанные задачи перемещаются в 'Без категории'. Продолжить? projects.column.color=Цвет projects.open=Открыть projects.close=Закрыть @@ -1424,7 +1412,6 @@ issues.filter_sort.moststars=Больше звезд issues.filter_sort.feweststars=Меньше звезд issues.filter_sort.mostforks=Больше форков issues.filter_sort.fewestforks=Меньше форков -issues.keyword_search_unavailable=В настоящее время поиск по ключевым словам недоступен. Обратитесь к администратору сайта. issues.action_open=Открыть issues.action_close=Закрыть issues.action_label=Метка @@ -1673,7 +1660,6 @@ pulls.compare_compare=взять из pulls.switch_comparison_type=Переключить тип сравнения pulls.switch_head_and_base=Поменять исходную и целевую ветки местами pulls.filter_branch=Фильтр по ветке -pulls.no_results=Результатов не найдено. pulls.show_all_commits=Показать все коммиты pulls.show_changes_since_your_last_review=Показать изменения с момента вашего последнего отзыва pulls.showing_only_single_commit=Показать только изменения коммита %[1]s @@ -1929,17 +1915,6 @@ activity.git_stats_deletion_n=%d удалений contributors.contribution_type.commits=коммитов -search=Поиск -search.search_repo=Поиск по репозиторию -search.type.tooltip=Тип поиска -search.fuzzy=Неточный -search.fuzzy.tooltip=Включать результаты, которые не полностью соответствуют поисковому запросу -search.match=Соответствие -search.match.tooltip=Включать только результаты, которые точно соответствуют поисковому запросу -search.results=Результаты поиска "%s" в <a href="%s">%s</a> -search.code_no_results=Не найдено исходного кода, соответствующего поисковому запросу. -search.code_search_unavailable=В настоящее время поиск по коду недоступен. Обратитесь к администратору сайта. - settings=Настройки settings.desc=В настройках вы можете менять различные параметры этого репозитория settings.options=Репозиторий @@ -2015,6 +1990,7 @@ settings.pulls.default_allow_edits_from_maintainers=По умолчанию ра settings.releases_desc=Включить релизы settings.packages_desc=Включить реестр пакетов settings.projects_desc=Включить проекты репозитория +settings.projects_mode_all=Все проекты settings.actions_desc=Включить действия репозитория settings.admin_settings=Настройки администратора settings.admin_enable_health_check=Выполнять проверки целостности этого репозитория (git fsck) @@ -2089,7 +2065,6 @@ settings.delete_collaborator=Удалить settings.collaborator_deletion=Удалить соавтора settings.collaborator_deletion_desc=Этот пользователь больше не будет иметь доступа для совместной работы в этом репозитории после удаления. Вы хотите продолжить? settings.remove_collaborator_success=Соавтор удалён. -settings.search_user_placeholder=Поиск пользователя… settings.org_not_allowed_to_be_collaborator=Организации не могут быть добавлены как соавторы. settings.change_team_access_not_allowed=Доступ к репозиторию команде ограничен владельцем организации settings.team_not_in_organization=Команда не в той же организации, что и репозиторий @@ -2097,7 +2072,6 @@ settings.teams=Команды settings.add_team=Добавить команду settings.add_team_duplicate=Команда уже имеет репозиторий settings.add_team_success=Команда теперь имеет доступ к репозиторию. -settings.search_team=Поиск команды… settings.change_team_permission_tip=Разрешение команды установлено на странице настройки команды и не может быть изменено для каждого репозитория settings.delete_team_tip=Эта команда имеет доступ ко всем репозиториям и не может быть удалена settings.remove_team_success=Доступ команды к репозиторию удалён. @@ -2248,9 +2222,7 @@ settings.protect_whitelist_committers=Ограничение отправки п settings.protect_whitelist_committers_desc=Только пользователям или командам из белого списка будет разрешена отправка изменений в эту ветку (но не принудительная отправка). settings.protect_whitelist_deploy_keys=Белый список развёртываемых ключей с доступом на запись в push. settings.protect_whitelist_users=Пользователи, которые могут отправлять изменения в эту ветку: -settings.protect_whitelist_search_users=Поиск пользователей… settings.protect_whitelist_teams=Команды, члены которых могут отправлять изменения в эту ветку: -settings.protect_whitelist_search_teams=Поиск команд… settings.protect_merge_whitelist_committers=Ограничить право на слияние белым списком settings.protect_merge_whitelist_committers_desc=Разрешить принимать запросы на слияние в эту ветку только пользователям и командам из «белого списка». settings.protect_merge_whitelist_users=Пользователи с правом на слияние: @@ -2486,7 +2458,6 @@ branch.default_deletion_failed=Ветка «%s» является веткой branch.restore=Восстановить ветку «%s» branch.download=Скачать ветку «%s» branch.rename=Переименовать ветку «%s» -branch.search=Поиск ветки branch.included_desc=Эта ветка является частью ветки по умолчанию branch.included=Включено branch.create_new_branch=Создать ветку из ветви: @@ -2623,7 +2594,6 @@ teams.write_permission_desc=Эта команда предоставляет д teams.admin_permission_desc=Эта команда даёт <strong>административный</strong> доступ: участники могут читать, отправлять изменения и добавлять соавторов к её репозиториям. teams.create_repo_permission_desc=Кроме того, эта команда предоставляет право <strong>Создание репозитория</strong>: члены команды могут создавать новые репозитории в организации. teams.repositories=Репозитории группы разработки -teams.search_repo_placeholder=Поиск репозитория… teams.remove_all_repos_title=Удалить все репозитории команды teams.remove_all_repos_desc=Удаляет все репозитории из команды. teams.add_all_repos_title=Добавить все репозитории @@ -2654,6 +2624,8 @@ integrations=Интеграции authentication=Аутентификация emails=Адреса эл. почты пользователей config=Конфигурация +config_summary=Статистика +config_settings=Настройки notices=Системные уведомления monitor=Мониторинг first_page=Первая @@ -2822,9 +2794,6 @@ repos.unadopted.no_more=Больше непринятых репозиторие repos.owner=Владелец repos.name=Название repos.private=Личный -repos.watches=Следят -repos.stars=Звезды -repos.forks=Форки repos.issues=Задачи repos.size=Размер repos.lfs_size=Размер LFS @@ -2946,7 +2915,6 @@ auths.tip.nextcloud=`Зарегистрируйте нового потреби 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.google_plus=Получите учётные данные клиента OAuth2 в консоли Google API на странице https://console.developers.google.com/ auths.tip.openid_connect=Используйте OpenID Connect Discovery URL (<server>/.well-known/openid-configuration) для автоматической настройки входа OAuth auths.tip.twitter=Перейдите на https://dev.twitter.com/apps, создайте приложение и убедитесь, что включена опция «Разрешить это приложение для входа в систему с помощью Twitter» diff --git a/options/locale/locale_si-LK.ini b/options/locale/locale_si-LK.ini index fb97daf5e0..7e82cfe3d6 100644 --- a/options/locale/locale_si-LK.ini +++ b/options/locale/locale_si-LK.ini @@ -100,6 +100,15 @@ concept_user_organization=සංවිධානය name=නම +filter=පෙරහන +filter.is_archived=සංරක්ෂිත +filter.is_template=සැකිලි +filter.public=ප්රසිද්ධ +filter.private=පෞද්ගලික + + +[search] + [aria] [heatmap] @@ -223,7 +232,6 @@ collaborative_repos=සහයෝගී ගබඩාවලදී my_orgs=මාගේ සංවිධාන my_mirrors=මගේ දර්පණ view_home=%s දකින්න -search_repos=ගබඩාවක් සොයා ගන්න… filter=වෙනත් පෙරහන් filter_by_team_repositories=කණ්ඩායම් කෝෂ්ඨ අනුව පෙරන්න @@ -243,13 +251,7 @@ issues.in_your_repos=ඔබගේ කෝෂ්ඨවල repos=කෝෂ්ඨ users=පරිශීලකයින් organizations=සංවිධාන -search=සොයන්න code=කේතය -search.match=තරගය -repo_no_results=ගැලපෙන ගබඩාවක් හමු නොවීය. -user_no_results=ගැලපෙන පරිශීලකයින් හමු නොවීය. -org_no_results=ගැලපෙන සංවිධාන හමු නොවීය. -code_no_results=ඔබගේ සෙවුම් පදය ගැලපෙන ප්රභව කේතයක් නොමැත. code_last_indexed_at=අවසන් සුචිගත %s [auth] @@ -262,7 +264,6 @@ remember_me=උපාංගය මතක තබාගන්න forgot_password_title=මුරපදය අමතක වුණා forgot_password=මුරපදය අමතක වුණා ද? sign_up_now=ගිණුමක් ඇවැසිද? දැන් ලියාපදිංචි වන්න. -confirmation_mail_sent_prompt=නව තහවුරු කිරීමේ විද්යුත් තැපෑලක් <b>%s</b>වෙත යවා ඇත. ලියාපදිංචි කිරීමේ ක්රියාවලිය සම්පූර්ණ කිරීම සඳහා කරුණාකර ඊළඟ %s තුළ ඔබගේ එන ලිපි පරීක්ෂා කරන්න. must_change_password=මුරපදය යාවත්කාල කරන්න allow_password_change=මුරපදය වෙනස් කිරීමට පරිශීලකයාට අවශ්ය වේ (නිර්දේශිත) reset_password_mail_sent_prompt=තහවුරු කිරීමේ විද්යුත් තැපෑලක් <b>%s</b>වෙත යවා ඇත. ඊළඟ තුළ ඔබගේ එන ලිපි පරීක්ෂා කරන්න %s ගිණුම යථා ක්රියාවලිය සම්පූර්ණ කිරීම සඳහා. @@ -467,6 +468,7 @@ user_bio=චරිතාපදානය disabled_public_activity=මෙම පරිශීලකයා ක්රියාකාරකම්වල මහජන දෘශ්යතාව අක්රීය කර ඇත. + [settings] profile=පැතිකඩ account=ගිණුම @@ -578,7 +580,6 @@ gpg_invalid_token_signature=සපයන ලද GPG යතුර, අත්ස gpg_token_required=පහත ටෝකනය සඳහා ඔබ අත්සනක් ලබා දිය යුතුය gpg_token=ටෝකනය gpg_token_help=ඔබට අත්සනක් ජනනය කළ හැකිය: -gpg_token_code=දෝංකාරය "%s" | gpg -a -පැහැර හැරීම-යතුර %s —වෙන්ච-සිග් gpg_token_signature=සන්නද්ධ GPG අත්සන key_signature_gpg_placeholder=ආරම්භ වන්නේ '—ආරම්භ කරන්න PGP සිග්නේටුර්—' ssh_key_verified=සත්යාපිත යතුර @@ -717,7 +718,6 @@ fork_repo=දෙබලක ගබඩාව fork_from=සිට දෙබලක fork_visibility_helper=ව්යාජ ගබඩාවේ දෘශ්යතාව වෙනස් කළ නොහැක. use_template=මෙම අච්චුව භාවිතා කරන්න -clone_in_vsc=VS කේතය පරිගණක ක්රිඩාවට සමාන download_zip=ZIP බාගන්න download_tar=TAR.GZ බාගන්න download_bundle=බණ්ඩලය බාගත කරන්න @@ -943,8 +943,6 @@ editor.require_signed_commit=ශාඛාවට අත්සන් කළ කැ commits.desc=මූලාශ්ර කේත වෙනස් කිරීමේ ඉතිහාසය පිරික්සන්න. commits.commits=විවරයන් commits.nothing_to_compare=මෙම ශාඛා සමාන වේ. -commits.search=සෙවුම් වාර… -commits.find=සොයන්න commits.search_all=සියළුම ශාඛා commits.author=කතෘ commits.message=පණිවිඩය @@ -981,7 +979,6 @@ projects.type.basic_kanban=මූලික කන්ෙවනි projects.type.bug_triage=දෝෂ ට්රයිජ් projects.template.desc=ව්යාපෘති සැකිල්ල projects.template.desc_helper=ආරම්භ කිරීම සඳහා ව්යාපෘති සැකිල්ලක් තෝරන්න -projects.type.uncategorized=ප්රවර්ග ගත නැති projects.column.edit_title=නම projects.column.new_title=නම projects.column.color=වර්ණය @@ -1263,7 +1260,6 @@ pulls.compare_compare=සිට අදින්න pulls.switch_comparison_type=ස්විච් සංසන්දනය වර්ගය pulls.switch_head_and_base=හිස සහ පාදය මාරු කරන්න pulls.filter_branch=ශාඛාව පෙරන්න -pulls.no_results=ප්රතිඵල සොයාගත නොහැකි විය. pulls.nothing_to_compare=මෙම ශාඛා සමාන වේ. අදින්න ඉල්ලීමක් නිර්මාණය කිරීමට අවශ්ය නැත. pulls.nothing_to_compare_and_allow_empty_pr=මෙම ශාඛා සමාන වේ. මෙම මහජන සම්බන්ධතා හිස් වනු ඇත. pulls.has_pull_request=`මෙම ශාඛා අතර අදින්න ඉල්ලීම දැනටමත් පවතී: <a href="%[1]s">%[2]s #%[3]d</a>` @@ -1462,13 +1458,6 @@ activity.git_stats_deletion_n=%d මකාදැමීම් contributors.contribution_type.commits=විවරයන් -search=සොයන්න -search.search_repo=කෝෂ්ඨය සොයන්න -search.fuzzy=සිනිඳු -search.match=තරගය -search.results=<a href="%s">%s</a> හි "%s" සඳහා සෙවුම් ප්රතිඵල -search.code_no_results=ඔබගේ සෙවුම් පදය ගැලපෙන ප්රභව කේතයක් නොමැත. - settings=සැකසුම් settings.desc=සැකසුම් යනු ගබඩාව සඳහා සැකසුම් කළමනාකරණය කළ හැකි ස්ථානයයි settings.options=කෝෂ්ඨය @@ -1584,7 +1573,6 @@ settings.delete_collaborator=ඉවත් කරන්න settings.collaborator_deletion=සහයෝගිතාකරු ඉවත් කරන්න settings.collaborator_deletion_desc=සහයෝගිතාකරුවෙකු ඉවත් කිරීම මෙම ගබඩාවට ඔවුන්ගේ ප්රවේශය අවලංගු කරනු ඇත. දිගටම? settings.remove_collaborator_success=සහයෝගිතාකරු ඉවත් කර ඇත. -settings.search_user_placeholder=පරිශීලක සොයන්න… settings.org_not_allowed_to_be_collaborator=සහයෝගීකයෙකු ලෙස සංවිධාන එකතු කළ නොහැක. settings.change_team_access_not_allowed=ගබඩාව සඳහා කණ්ඩායම් ප්රවේශය වෙනස් කිරීම සංවිධාන හිමිකරුට සීමා කර ඇත settings.team_not_in_organization=මෙම කණ්ඩායම ගබඩාවේ එකම සංවිධානයේ නොමැත @@ -1592,7 +1580,6 @@ settings.teams=කණ්ඩායම් settings.add_team=කණ්ඩායම එකතු කරන්න settings.add_team_duplicate=කණ්ඩායම දැනටමත් ගබඩාවක් ඇත settings.add_team_success=කණ්ඩායමට දැන් කෝෂ්ඨයට ප්රවේශය ඇත. -settings.search_team=කණ්ඩායම සොයන්න… settings.change_team_permission_tip=කණ්ඩායමේ අවසරය කණ්ඩායම් සැකසුම් පිටුවේ සකසන අතර කෝෂ්ඨය අනුව වෙනස් කළ නොහැකිය settings.delete_team_tip=මෙම කණ්ඩායම සියළුම කෝෂ්ඨවලට ප්රවේශය ඇති අතර ඉවත් කළ නොහැකිය settings.remove_team_success=කෝෂ්ඨය වෙත කණ්ඩායමේ ප්රවේශය ඉවත් කර ඇත. @@ -1709,9 +1696,7 @@ settings.protect_whitelist_committers=වයිට්ලිස්ට් සී settings.protect_whitelist_committers_desc=මෙම ශාඛාව වෙත තල්ලු කිරීමට අවසර ඇත්තේ වයිට්ලිස්ට් පරිශීලකයින්ට හෝ කණ්ඩායම්වලට පමණි (නමුත් බල තල්ලුව නොවේ). settings.protect_whitelist_deploy_keys=වයිට්ලිස්ට් තල්ලු කිරීමට ලිවීමේ ප්රවේශය සහිත යතුරු යොදවන්න. settings.protect_whitelist_users=තල්ලු කිරීම සඳහා වයිට්ලිස්ට් පරිශීලකයින්: -settings.protect_whitelist_search_users=පරිශීලකයින් සොයන්න… settings.protect_whitelist_teams=තල්ලු කිරීම සඳහා වයිට්ලිස්ට් කණ්ඩායම්: -settings.protect_whitelist_search_teams=කණ්ඩායම් සොයන්න… settings.protect_merge_whitelist_committers=ඒකාබද්ධ වයිට්ලිස්ට් සක්රීය කරන්න settings.protect_merge_whitelist_committers_desc=මෙම ශාඛාවට ඇද ගැනීමේ ඉල්ලීම් ඒකාබද්ධ කිරීමට සුදු පැහැති පරිශීලකයින්ට හෝ කණ්ඩායම්වලට පමණක් ඉඩ දෙන්න. settings.protect_merge_whitelist_users=ඒකාබද්ධ කිරීම සඳහා Whitelisted පරිශීලකයන්: @@ -2006,7 +1991,6 @@ teams.write_permission_desc=මෙම කණ්ඩායම ප්රදාන teams.admin_permission_desc=මෙම කණ්ඩායම <strong>පරිපාලක</strong> ප්රවේශය ලබා දෙයි: සාමාජිකයින්ට කියවීමට, කණ්ඩායම් ගබඩාවන්ට සහයෝගීකයින් වෙත තල්ලු කිරීමට සහ එකතු කිරීමට හැකිය. teams.create_repo_permission_desc=මීට අමතරව, මෙම කණ්ඩායම <strong>ලබා දෙයි ගබඩාව සාදන්න</strong> අවසරය: සාමාජිකයින්ට සංවිධානයේ නව ගබඩාවක් නිර්මාණය කළ හැකිය. teams.repositories=කණ්ඩායම් කෝෂ්ඨ -teams.search_repo_placeholder=කෝෂ්ඨය සොයන්න… teams.remove_all_repos_title=සියළුම කණ්ඩායම් කෝෂ්ඨ ඉවත් කරන්න teams.remove_all_repos_desc=මෙය කණ්ඩායමෙන් සියළුම කෝෂ්ඨ ඉවත් කෙරෙනු ඇත. teams.add_all_repos_title=සියළුම කෝෂ්ඨ එක්කරන්න @@ -2031,6 +2015,8 @@ hooks=වෙබ්කොකු authentication=සත්යාපන ප්රභවයන් emails=පරිශීලක වි-තැපැල් config=වින්යාසය +config_summary=සාරාංශය +config_settings=සැකසුම් notices=පද්ධතියේ දැන්වීම් monitor=අධීක්ෂණය first_page=පළමු @@ -2178,9 +2164,6 @@ repos.unadopted.no_more=තවත් සම්මත නොකළ ගබඩා repos.owner=හිමිකරු repos.name=නම repos.private=පෞද්ගලික -repos.watches=අත් ඔරලෝසු -repos.stars=තරු -repos.forks=දෙබලක repos.issues=ගැටළු repos.size=ප්රමාණය @@ -2278,7 +2261,6 @@ auths.tip.nextcloud=පහත සඳහන් මෙනුව භාවිතා auths.tip.dropbox=https://www.dropbox.com/developers/apps හි නව යෙදුමක් සාදන්න auths.tip.facebook=https://developers.facebook.com/apps හි නව යෙදුමක් ලියාපදිංචි කර නිෂ්පාදනය එකතු කරන්න “ෆේස්බුක් ලොගින් වන්න” auths.tip.github=https://github.com/settings/applications/new හි නව OAUTH අයදුම්පතක් ලියාපදිංචි කරන්න -auths.tip.gitlab=https://gitlab.com/profile/applications හි නව අයදුම්පතක් ලියාපදිංචි කරන්න auths.tip.google_plus=ගූගල් API කොන්සෝලය වෙතින් OUT2 සේවාදායක අක්තපත්ර ලබා ගන්න https://console.developers.google.com/ auths.tip.openid_connect=අන්ත ලක්ෂ්ය නියම කිරීම සඳහා OpenID Connect ඩිස්කවරි URL (<server>/.හොඳින් දැන /openid-වින්යාසය) භාවිතා කරන්න auths.tip.twitter=https://dev.twitter.com/apps වෙත යන්න, යෙදුමක් සාදන්න සහ “මෙම යෙදුම ට්විටර් සමඟ පුරනය වීමට භාවිතා කිරීමට ඉඩ දෙන්න” විකල්පය සක්රීය කර ඇති බවට සහතික වන්න diff --git a/options/locale/locale_sk-SK.ini b/options/locale/locale_sk-SK.ini index 4a223ee90d..b468b55283 100644 --- a/options/locale/locale_sk-SK.ini +++ b/options/locale/locale_sk-SK.ini @@ -140,6 +140,13 @@ confirm_delete_selected=Potvrdzujete zmazanie všetkých vybraných položiek? name=Meno value=Hodnota +filter.is_archived=Archivované +filter.is_template=Šablóna +filter.private=Súkromný + + +[search] + [aria] navbar=Navigačná lišta footer=Päta @@ -309,7 +316,6 @@ collaborative_repos=Kolaboratívne repozitáre my_orgs=Moje organizácie my_mirrors=Moje zrkadlá view_home=Zobraziť %s -search_repos=Nájsť repozitár… filter=Ostatné filtre filter_by_team_repositories=Filtrovať podľa tímových repozitárov feed_of=Informačný kanál „%s“ @@ -330,20 +336,8 @@ issues.in_your_repos=Vo vašich repozitároch repos=Repozitáre users=Používatelia organizations=Organizácie -search=Hľadať go_to=Ísť na code=Zdrojový kód -search.type.tooltip=Typ vyhľadávania -search.fuzzy=Fuzzy -search.fuzzy.tooltip=Zahrnúť iba výsledky, ktoré sa takmer zhodujú s hľadaným výrazom -search.match=Zhoda -search.match.tooltip=Zahrnúť iba výsledky, ktoré sa presne zhodujú s hľadaným výrazom -code_search_unavailable=Vyhľadávanie kódu momentálne nie je dostupné. Kontaktujte, prosím, správcu. -repo_no_results=Nenašli sa zodpovedajúce repozitáre. -user_no_results=Nenašli sa zodpovedajúci používatelia. -org_no_results=Nenašli sa zodpovedajúce organizácie. -code_no_results=Nenašiel sa žiaden zdrojový kód zodpovedajúci hľadanému výrazu. -code_search_results=`Výsledky hľadania pre "%s"` code_last_indexed_at=Naposledy indexované %s relevant_repositories_tooltip=Repozitáre, ktoré sú forkami alebo ktoré nemajú tému, žiadnu ikonu ani popis, sú skryté. relevant_repositories=Zobrazujú sa iba relevantné repozitáre, <a href="%s">zobraziť nefiltrované výsledky</a>. @@ -359,7 +353,6 @@ remember_me=Zapamätať si toto zariadenie forgot_password_title=Zabudnuté heslo forgot_password=Zabudli ste heslo? sign_up_now=Potrebujete účet? Zaregistrujte sa teraz. -confirmation_mail_sent_prompt=Na adresu <b>%s</b> bol odoslaný nový potvrdzovací e-mail. Skontrolujte si, prosím, vašu doručenú poštu počas najbližších %s pre dokončenie procesu registrácie. allow_password_change=Vyžiadať od používateľa zmenu hesla (doporučuje sa) reset_password_mail_sent_prompt=Na adresu <b>%s</b> bol odoslaný potvrdzovací e-mail. Skontrolujte si, prosím, vašu doručenú poštu počas najbližších %s pre dokončenie procesu obnovenia účtu. active_your_account=Aktivovať účet @@ -582,6 +575,7 @@ user_bio=Životopis disabled_public_activity=Tento používateľ zákázal verejnú viditeľnosť aktivity. + [settings] profile=Profil account=Účet @@ -707,7 +701,6 @@ gpg_invalid_token_signature=Zadaný GPG kľúč, podpis a token sa nezhodujú al gpg_token_required=Musíte zadať podpis pre nižšie uvedený token gpg_token=Token gpg_token_help=Podpis môžete vygenerovať pomocou: -gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig gpg_token_signature=Zakódovaný (ASCII) podpis GPG key_signature_gpg_placeholder=Začína s '-----BEGIN PGP SIGNATURE-----' ssh_key_verified=Overený kľúč @@ -853,7 +846,6 @@ visibility_helper_forced=Váš správca vynucuje že nové repozitáre musia by visibility_fork_helper=(Zmena ovplyvní všetky forky.) clone_helper=Potrebujete pomoc s klonovaním? Navštívte <a target="_blank" rel="noopener noreferrer" href="%s">Pomocníka</a>. use_template=Použiť túto šablónu -clone_in_vsc=Klonovať vo VS Code generate_repo=Generovať repozitár generate_from=Generovať z repo_desc=Popis @@ -1037,7 +1029,6 @@ editor.no_commit_to_branch=Nedá sa odoslať priamo do vetvy, pretože: editor.require_signed_commit=Vetva vyžaduje podpísaný commit commits.commits=Commity -commits.find=Hľadať commits.search_all=Všetky vetvy commits.author=Autor commits.message=Správa @@ -1147,15 +1138,6 @@ activity.git_stats_commit_n=%d commity contributors.contribution_type.commits=Commitov -search=Hľadať -search.type.tooltip=Typ vyhľadávania -search.fuzzy=Fuzzy -search.fuzzy.tooltip=Zahrnúť iba výsledky, ktoré sa takmer zhodujú s hľadaným výrazom -search.match=Zhoda -search.match.tooltip=Zahrnúť iba výsledky, ktoré sa presne zhodujú s hľadaným výrazom -search.code_no_results=Nenašiel sa žiaden zdrojový kód zodpovedajúci hľadanému výrazu. -search.code_search_unavailable=Vyhľadávanie kódu momentálne nie je dostupné. Kontaktujte, prosím, správcu. - settings.collaboration.owner=Vlastník settings.hooks=Webhooky settings.githooks=Git hooky @@ -1287,7 +1269,6 @@ dashboard.delete_generated_repository_avatars=Odstrániť vygenerované avatary repos.owner=Vlastník repos.private=Súkromný -repos.forks=Forky packages.owner=Vlastník packages.repository=Repozitár diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini index 0a484c9b79..e48d84ff78 100644 --- a/options/locale/locale_sv-SE.ini +++ b/options/locale/locale_sv-SE.ini @@ -91,6 +91,14 @@ concept_user_organization=Organisation name=Namn +filter.is_archived=Arkiverade +filter.is_template=Mall +filter.public=Offentlig +filter.private=Privat + + +[search] + [aria] [heatmap] @@ -212,7 +220,6 @@ collaborative_repos=Kollaborativa Utvecklingskataloger my_orgs=Mina organisationer my_mirrors=Mina speglar view_home=Visa %s -search_repos=Hitta en utvecklingskatalog… filter=Övriga Filter show_archived=Arkiverade @@ -231,12 +238,7 @@ issues.in_your_repos=I dina utvecklingskataloger repos=Utvecklingskataloger users=Användare organizations=Organisationer -search=Sök code=Kod -repo_no_results=Inga matchande utvecklingskataloger hittades. -user_no_results=Inga matchande användare hittades. -org_no_results=Inga matchande organisationer hittades. -code_no_results=Ingen källkod hittades som matchar din sökterm. code_last_indexed_at=Indexerades senast %s [auth] @@ -249,7 +251,6 @@ remember_me=Kom ihåg denna enhet forgot_password_title=Glömt lösenord forgot_password=Glömt lösenord? sign_up_now=Behöver du ett konto? Registrera nu. -confirmation_mail_sent_prompt=Ett nytt bekräftelsemail has skickats till <b>%s</b>. Vänligen kolla din inkorg inom dom kommande %s för att slutföra registreringsprocessen. must_change_password=Ändra ditt lösenord allow_password_change=Kräv att användaren byter lösenord (rekommenderas) reset_password_mail_sent_prompt=Ett nytt bekräftelsemail has skickats till <b>%s</b>. Vänligen kontrollera din inkorg inom de kommande %s för att slutföra återställning av ditt konto. @@ -406,6 +407,7 @@ user_bio=Biografi disabled_public_activity=Den här användaren har inaktiverat den publika synligheten av aktiviteten. + [settings] profile=Profil account=Konto @@ -798,8 +800,6 @@ editor.require_signed_commit=Branchen kräver en signerad commit commits.desc=Bläddra i källkodens förändringshistorik. commits.commits=Incheckningar -commits.search=Sök commits… -commits.find=Sök commits.search_all=Alla brancher commits.author=Upphovsman commits.message=Meddelande @@ -827,7 +827,6 @@ projects.edit=Redigera projekt projects.modify=Uppdatera projekt projects.type.none=Ingen projects.template.desc=Projektmall -projects.type.uncategorized=Okatergoriserad projects.column.edit_title=Namn projects.column.new_title=Namn projects.open=Öppna @@ -1084,7 +1083,6 @@ pulls.compare_changes_desc=Välj branchen att merga in i, och ifrån. pulls.compare_base=merga in i pulls.compare_compare=pulla från pulls.filter_branch=Filtrera gren -pulls.no_results=Inga resultat hittades. pulls.nothing_to_compare=Dessa brancher är ekvivalenta. Det finns ingen anledning att skapa en pull-request. pulls.create=Skapa Pullförfrågan pulls.title_desc=vill sammanfoga %[1]d incheckningar från <code>s[2]s</code> in i <code id="branch_target">%[3]s</code> @@ -1230,11 +1228,6 @@ activity.git_stats_deletion_n=%d borttagningar contributors.contribution_type.commits=Incheckningar -search=Sök -search.search_repo=Sök utvecklingskatalog -search.results=Sökresultat för ”%s” i <a href="%s"> %s</a> -search.code_no_results=Ingen källkod hittades som matchar din sökterm. - settings=Inställningar settings.desc=Inställningarna är där du kan hantera inställningar för utvecklingskatalogen settings.options=Utvecklingskatalog @@ -1315,7 +1308,6 @@ settings.delete_collaborator=Ta bort settings.collaborator_deletion=Ta bort medarbetare settings.collaborator_deletion_desc=Borttagning av en medarbetare kommer att återkalla deras åtkomst till utvecklingskatalogen. Vill du fortsätta? settings.remove_collaborator_success=Medarbetaren har blivit borttagen. -settings.search_user_placeholder=Sök användare… settings.org_not_allowed_to_be_collaborator=Organisationer kan inte läggas till som en medarbetare. settings.change_team_access_not_allowed=Att ändra teamåtkomst för utvecklingskatalogen har begränsats till organisationsägaren settings.team_not_in_organization=Teamet är inte i samma organisation som utvecklingskatalogen @@ -1407,9 +1399,7 @@ settings.protect_enable_push=Aktivera Push settings.protect_enable_push_desc=Alla med skrivrättigheter kommer att kunna pusha till denna branch (men inte force-pusha). settings.protect_whitelist_deploy_keys=Vitlista deploy-nyckar med skrivåtkomst till push. settings.protect_whitelist_users=Vitlistade användare för pushning: -settings.protect_whitelist_search_users=Sök användare… settings.protect_whitelist_teams=Vitlistade team för pushning: -settings.protect_whitelist_search_teams=Sök team… settings.protect_merge_whitelist_committers=Aktivera vitlista för sammanfogning settings.protect_merge_whitelist_committers_desc=Tillåt endast vitlistade användare eller team att sammanfoga pull requests i denna branch. settings.protect_merge_whitelist_users=Vitlistade användare för sammanfogning: @@ -1626,7 +1616,6 @@ teams.write_permission_desc=Medlemskap i detta team ger <strong>skrivrättighete teams.admin_permission_desc=Medlemskap i detta team ger <strong>administratörsrättigheter</strong>: medlemmar kan läsa, pusha och lägga till medarbetare till teamets utvecklingskataloger. teams.create_repo_permission_desc=Vidare så ger detta team <strong>Skapa utvecklingskatalog</strong> rättigheten: medlemmar can skapa nya utvecklingskataloger i organisationen. teams.repositories=Teamförråd -teams.search_repo_placeholder=Sök utvecklingskatalog… teams.remove_all_repos_title=Ta bort alla utvecklingskataloger för teamet teams.remove_all_repos_desc=Detta kommer att ta bort alla utvecklingskataloger från teamet. teams.add_all_repos_title=Lägg till alla utvecklingskataloger @@ -1649,6 +1638,8 @@ organizations=Organisationer repositories=Utvecklingskataloger authentication=Autentiseringskälla config=Konfiguration +config_summary=Översikt +config_settings=Inställningar notices=Systemaviseringar monitor=Övervakning first_page=Första @@ -1750,9 +1741,6 @@ repos.repo_manage_panel=Utvecklingskatalogshantering repos.owner=Ägare repos.name=Namn repos.private=Privat -repos.watches=Vakter -repos.stars=Stjärnor -repos.forks=Forkar repos.issues=Ärenden repos.size=Storlek @@ -1818,7 +1806,6 @@ auths.tip.bitbucket=Registrera en ny OAuth konsument på https://bitbucket.org/a auths.tip.dropbox=Skapa en ny applikation på https://www.dropbox.com/developers/apps auths.tip.facebook=Registrera en ny appliaktion på https://developers.facebook.com/apps och lägg till produkten ”Facebook-inloggning” auths.tip.github=Registrera en ny OAuth applikation på https://github.com/settings/applications/new -auths.tip.gitlab=Registrera en ny applikation på https://gitlab.com/profile/applications auths.tip.google_plus=Erhåll inloggningsuppgifter för OAuth2 från Google API-konsolen på https://console.developers.google.com/ auths.tip.openid_connect=Använd OpenID Connect Discovery länken (<server>/.well-known/openid-configuration) för att ange slutpunkterna auths.tip.twitter=Gå till https://dev.twitter.com/app, skapa en applikation och försäkra att alternativet "Allow this application to be used to Sign in with Twitter" är aktiverat diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index 3c8cb08726..5a5036f87d 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -141,6 +141,15 @@ confirm_delete_selected=Tüm seçili öğeleri gerçekten silmek istiyor musunuz name=İsim value=Değer +filter=Filtre +filter.is_archived=Arşivlenmiş +filter.is_template=Şablon +filter.public=Genel +filter.private=Özel + + +[search] + [aria] navbar=Gezinti Çubuğu footer=Alt Bilgi @@ -314,7 +323,6 @@ collaborative_repos=Katkıya Açık Depolar my_orgs=Organizasyonlarım my_mirrors=Yansılarım view_home=%s Görüntüle -search_repos=Depo bul… filter=Diğer Süzgeçler filter_by_team_repositories=Takım depolarına göre süz feed_of=`"%s" beslemesi` @@ -335,20 +343,8 @@ issues.in_your_repos=Depolarınızda repos=Depolar users=Kullanıcılar organizations=Organizasyonlar -search=Ara go_to=Git code=Kod -search.type.tooltip=Arama türü -search.fuzzy=Bulanık -search.fuzzy.tooltip=Arama terimine benzeyen sonuçları da içer -search.match=Eşleştir -search.match.tooltip=Sadece arama terimiyle tamamen eşleşen sonuçları içer -code_search_unavailable=Kod arama şu an mevcut değil. Lütfen site yöneticinizle bağlantıya geçin. -repo_no_results=Eşleşen depo bulunamadı. -user_no_results=Eşleşen kullanıcı bulunamadı. -org_no_results=Eşleşen organizasyon bulunamadı. -code_no_results=Arama teriminizi içeren kaynak kod bulunamadı. -code_search_results=`"%s" için sonuçları ara` code_last_indexed_at=Son dizinlenen %s relevant_repositories_tooltip=Çatal olan veya konusu, simgesi veya açıklaması olmayan depolar gizlenmiştir. relevant_repositories=Sadece ilişkili depolar gösteriliyor, <a href="%s">süzülmemiş sonuçları göster</a>. @@ -366,7 +362,6 @@ forgot_password_title=Şifremi unuttum forgot_password=Şifrenizi mi unuttunuz? sign_up_now=Bir hesaba mı ihtiyacınız var? Hemen kaydolun. sign_up_successful=Hesap başarılı bir şekilde oluşturuldu. Hoşgeldiniz! -confirmation_mail_sent_prompt=Yeni onay e-postası <b>%s</b> adresine gönderildi. Lütfen gelen kutunuzu bir sonraki %s e kadar kontrol edip kayıt işlemini tamamlayın. must_change_password=Parolanızı güncelleyin allow_password_change=Kullanıcıyı parola değiştirmeye zorla (önerilen) reset_password_mail_sent_prompt=<b>%s</b> adresine bir onay e-postası gönderildi. Hesap kurtarma işlemini tamamlamak için lütfen gelen kutunuzu sonraki %s içinde kontrol edin. @@ -614,6 +609,7 @@ form.name_reserved=`"%s" kullanıcı adı rezerve edilmiş.` form.name_pattern_not_allowed=Kullanıcı adında "%s" deseni kullanılamaz. form.name_chars_not_allowed=`"%s" kullanıcı adı geçersiz karakterler içeriyor.` + [settings] profile=Profil account=Hesap @@ -758,7 +754,6 @@ gpg_invalid_token_signature=Verilen GPG anahtarı, imza ve anahtar uyuşmuyor ve gpg_token_required=Aşağıdaki anahtar için bir imza sağlamalısınız gpg_token=Anahtar gpg_token_help=Şunu kullanarak bir imza oluşturabilirsiniz: -gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig gpg_token_signature=Korumalı GPG imzası key_signature_gpg_placeholder='-----PGP İMZA BAŞLAT -----' ile başlar verify_gpg_key_success=GPG anahtarı "%s" doğrulandı. @@ -952,7 +947,6 @@ fork_branch=Çatala klonlanacak dal all_branches=Tüm dallar fork_no_valid_owners=Geçerli bir sahibi olmadığı için bu depo çatallanamaz. use_template=Bu şablonu kullan -clone_in_vsc=VS Code'ta klonla download_zip=ZIP indir download_tar=TAR.GZ indir download_bundle=BUNDLE indir @@ -973,9 +967,9 @@ readme_helper=Bir README dosyası şablonu seçin. readme_helper_desc=Projeniz için eksiksiz bir açıklama yazabileceğiniz yer burasıdır. auto_init=Depoyu başlat (.gitignore, Lisans ve README dosyalarını ekler) trust_model_helper=İmza doğrulaması için güven modelini seçin. Olası seçenekler şunlardır: -trust_model_helper_collaborator=Ortak çalışan: Ortak çalışanların imzalarına güven +trust_model_helper_collaborator=Katkıcı: Katkıcıların imzalarına güven trust_model_helper_committer=İşleyen: İşleyenlerle eşleşen imzalara güven -trust_model_helper_collaborator_committer=Ortak çalışan+İşleyen: İşleyenle eşleşen ortak çalışanların imzalarına güven +trust_model_helper_collaborator_committer=Katkıcı+İşleyen: İşleyenle eşleşen ortak çalışanların imzalarına güven trust_model_helper_default=Varsayılan: Bu kurulum için varsayılan güven modelini kullan create_repo=Depo Oluştur default_branch=Varsayılan Dal @@ -1271,9 +1265,7 @@ commits.desc=Kaynak kodu değişiklik geçmişine göz atın. commits.commits=İşleme commits.no_commits=Ortak bir işleme yok. "%s" ve "%s" tamamen farklı geçmişlere sahip. commits.nothing_to_compare=Bu dallar eşit. -commits.search=İşlemeleri ara… commits.search.tooltip=Anahtar kelimeleri "author:", "committer:", "after:" veya "before:" ile kullanabilirsiniz, örneğin "revert author:Alice before:2019-01-13". -commits.find=Ara commits.search_all=Tüm Dallar commits.author=Yazar commits.message=Mesaj @@ -1324,7 +1316,6 @@ projects.type.basic_kanban=Kanban Tabanı projects.type.bug_triage=Hata Triyajı projects.template.desc=Proje şablonu projects.template.desc_helper=Başlamak için bir proje şablonu seçin -projects.type.uncategorized=Kategorize edilmemiş projects.column.edit=Sütun Düzenle projects.column.edit_title=İsim projects.column.new_title=İsim @@ -1332,10 +1323,7 @@ projects.column.new_submit=Sütun Oluştur projects.column.new=Yeni Sütun projects.column.set_default=Varsayılanı Ayarla projects.column.set_default_desc=Bu sütunu kategorize edilmemiş konular ve değişiklik istekleri için varsayılan olarak ayarlayın -projects.column.unset_default=Varsayılanları Geri Al -projects.column.unset_default_desc=Bu sütunu varsayılan olarak geri al projects.column.delete=Sutün Sil -projects.column.deletion_desc=Bir proje sütununun silinmesi, ilgili tüm konuları 'Kategorize edilmemiş'e taşır. Devam edilsin mi? projects.column.color=Renk projects.open=Aç projects.close=Kapat @@ -1447,7 +1435,6 @@ issues.filter_sort.moststars=En çok yıldızlılar issues.filter_sort.feweststars=En az yıldızlılar issues.filter_sort.mostforks=En çok çatallananlar issues.filter_sort.fewestforks=En az çatallananlar -issues.keyword_search_unavailable=Anahtar kelime ile arama şu an mevcut değil. Lütfen site yöneticisiyle iletişime geçin. issues.action_open=Açık issues.action_close=Kapat issues.action_label=Etiket @@ -1699,7 +1686,6 @@ pulls.compare_compare=şuradan çek pulls.switch_comparison_type=Karşılaştırma türünü değiştir pulls.switch_head_and_base=Ana ve temeli değiştir pulls.filter_branch=Dal filtrele -pulls.no_results=Sonuç bulunamadı. pulls.show_all_commits=Tüm işlemeleri göster pulls.show_changes_since_your_last_review=Son incelemenizden sonraki değişiklikleri göster pulls.showing_only_single_commit=Sadece %[1]s işlemesindeki değişiklikler gösteriliyor @@ -1969,17 +1955,6 @@ activity.git_stats_deletion_n=%d silme oldu contributors.contribution_type.commits=İşleme -search=Ara -search.search_repo=Depo ara -search.type.tooltip=Arama türü -search.fuzzy=Belirsiz -search.fuzzy.tooltip=Arama terimine benzeyen sonuçları da içer -search.match=Eşleştir -search.match.tooltip=Sadece arama terimiyle tamamen eşleşen sonuçları içer -search.results=`"%s" için <a href="%s">%s</a> içinde sonuçları ara` -search.code_no_results=Arama teriminizi içeren kaynak kod bulunamadı. -search.code_search_unavailable=Kod arama şu an mevcut değil. Lütfen site yöneticinizle bağlantıya geçin. - settings=Ayarlar settings.desc=Ayarlar, deponun ayarlarını yönetebileceğiniz yerdir settings.options=Depo @@ -2057,6 +2032,7 @@ settings.pulls.default_allow_edits_from_maintainers=Bakımcıların düzenlemele settings.releases_desc=Depo Sürümlerini Etkinleştir settings.packages_desc=Depo Paket Kütüğünü Etkinleştir settings.projects_desc=Depo Projelerini Etkinleştir +settings.projects_mode_all=Tüm projeler settings.actions_desc=Depo İşlemlerini Etkinleştir settings.admin_settings=Yönetici Ayarları settings.admin_enable_health_check=Depo Sağlık Kontrollerini Etkinleştir (git fsck) @@ -2131,7 +2107,6 @@ settings.delete_collaborator=Sil settings.collaborator_deletion=Katkıcıyı Sil settings.collaborator_deletion_desc=Bir katkıcıyı silmek, bu depoya erişimini iptal edecektir. Devam et? settings.remove_collaborator_success=Katkıcı silindi. -settings.search_user_placeholder=Kullanıcı ara… settings.org_not_allowed_to_be_collaborator=Organizasyonlar katkıcı olarak eklenemez. settings.change_team_access_not_allowed=Depo için takım erişimini değiştirmek, organizasyon sahibiyle sınırlandırıldı settings.team_not_in_organization=Takım, depo ile aynı organizasyonda değil @@ -2139,7 +2114,6 @@ settings.teams=Takımlar settings.add_team=Takım Ekle settings.add_team_duplicate=Takım zaten bu depoya sahip settings.add_team_success=Takım artık bu depoya erişebilir. -settings.search_team=Takım Ara… settings.change_team_permission_tip=Takımın izni takım ayarı sayfasında ayarlanır ve depo başına değiştirilemez settings.delete_team_tip=Bu takımın tüm depolara erişimi var ve kaldırılamıyor settings.remove_team_success=Takımın depoya erişimi kaldırıldı. @@ -2292,9 +2266,7 @@ settings.protect_whitelist_committers=Beyaz Liste Kısıtlı Gönderme settings.protect_whitelist_committers_desc=Sadece beyaz listeye alınmış kullanıcıların veya takımların bu dala göndermesine izin verilir (ancak zorla gönderim yapmayın). settings.protect_whitelist_deploy_keys=Beyaz liste göndermek için yazma erişimi olan anahtarları dağıtır. settings.protect_whitelist_users=İtme için beyaz listedeki kullanıcılar: -settings.protect_whitelist_search_users=Kullanıcı ara… settings.protect_whitelist_teams=İtme için beyaz listedeki takımlar: -settings.protect_whitelist_search_teams=Takımları ara… settings.protect_merge_whitelist_committers=Birleştirme Beyaz Listesini Etkinleştir settings.protect_merge_whitelist_committers_desc=Yalnızca beyaz listedeki kullanıcıların veya takımların bu daldaki değişiklik isteklerini birleştirmesine izin verin. settings.protect_merge_whitelist_users=Birleştirme için beyaz listedeki kullanıcılar: @@ -2536,7 +2508,6 @@ branch.default_deletion_failed=`"%s" dalı varsayılan daldır. Silinemez.` branch.restore=`"%s" Dalını Geri Yükle` branch.download=`"%s" Dalını İndir` branch.rename=`"%s" Dalının Adını Değiştir` -branch.search=Dal Ara branch.included_desc=Bu dal varsayılan dalın bir parçasıdır branch.included=Dahil branch.create_new_branch=Şu daldan dal oluştur: @@ -2674,7 +2645,6 @@ teams.write_permission_desc=Bu takım <strong>Yazma</strong> erişimi veriyor. teams.admin_permission_desc=Bu takım <strong>Yönetici</strong> erişimi veriyor. Üyeler takım depolarını okuyabilir, itebilir ve katkıcı ekleyebilir. teams.create_repo_permission_desc=Ayrıca, bu takım <strong>Depo oluşturma</strong> izni verir: üyeler organizasyonda yeni depolar oluşturabilir. teams.repositories=Takım Depoları -teams.search_repo_placeholder=Depo ara… teams.remove_all_repos_title=Tüm takım depolarını kaldır teams.remove_all_repos_desc=Bu, tüm depoları takımdan kaldıracaktır. teams.add_all_repos_title=Tüm depoları ekle @@ -2706,6 +2676,8 @@ integrations=Bütünleştirmeler authentication=Yetkilendirme Kaynakları emails=Kullanıcı E-postaları config=Yapılandırma +config_summary=Özet +config_settings=Ayarlar notices=Sistem Bildirimler monitor=İzleme first_page=İlk @@ -2880,9 +2852,6 @@ repos.unadopted.no_more=Kabul edilmemiş başka depo bulunamadı repos.owner=Sahibi repos.name=İsim repos.private=Özel -repos.watches=İzlemeler -repos.stars=Yıldızlar -repos.forks=Çatallar repos.issues=Konular repos.size=Boyut repos.lfs_size=LFS Boyutu @@ -3007,7 +2976,6 @@ auths.tip.nextcloud=Aşağıdaki "Ayarlar -> Güvenlik -> OAuth 2.0 istemcisi" m auths.tip.dropbox=https://www.dropbox.com/developers/apps adresinde yeni bir uygulama oluştur auths.tip.facebook=https://developers.facebook.com/apps adresinde yeni bir uygulama kaydedin ve "Facebook Giriş" ürününü ekleyin auths.tip.github=https://github.com/settings/applications/new adresinde yeni bir OAuth uygulaması kaydedin -auths.tip.gitlab=https://gitlab.com/profile/applications adresinde yeni bir uygulama kaydedin auths.tip.google_plus=OAuth2 istemci kimlik bilgilerini https://console.developers.google.com/ adresindeki Google API konsolundan edinin auths.tip.openid_connect=Bitiş noktalarını belirlemek için OpenID Connect Discovery URL'sini kullanın (<server>/.well-known/openid-configuration) auths.tip.twitter=https://dev.twitter.com/apps adresine gidin, bir uygulama oluşturun ve “Bu uygulamanın Twitter ile oturum açmak için kullanılmasına izin ver” seçeneğinin etkin olduğundan emin olun diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini index 9aa6d6a16e..09561a7902 100644 --- a/options/locale/locale_uk-UA.ini +++ b/options/locale/locale_uk-UA.ini @@ -101,6 +101,15 @@ concept_user_organization=Організація name=Назва +filter=Фільтр +filter.is_archived=Архівовані +filter.is_template=Шаблон +filter.public=Публічний +filter.private=Приватний + + +[search] + [aria] [heatmap] @@ -236,7 +245,6 @@ collaborative_repos=Спільні репозиторії my_orgs=Мої організації my_mirrors=Мої дзеркала view_home=Переглянути %s -search_repos=Шукати репозиторій… filter=Інші фільтри filter_by_team_repositories=Фільтрувати за репозиторіями команд feed_of=`Стрічка "%s"` @@ -257,14 +265,7 @@ issues.in_your_repos=В ваших репозиторіях repos=Репозиторії users=Користувачі organizations=Організації -search=Пошук code=Код -search.fuzzy=Неточний -search.match=Відповідність -repo_no_results=Відповідних репозиторіїв не знайдено. -user_no_results=Відповідних користувачів не знайдено. -org_no_results=Відповідних організацій не знайдено. -code_no_results=Відповідний пошуковому запитанню код не знайдено. code_last_indexed_at=Останні індексовані %s [auth] @@ -277,7 +278,6 @@ remember_me=Запам’ятати цей пристрій forgot_password_title=Забув пароль forgot_password=Забули пароль? sign_up_now=Потрібен обліковий запис? Зареєструйтеся зараз. -confirmation_mail_sent_prompt=Новий лист для підтвердження було відправлено на <b>%s</b>, будь ласка, перевірте вашу поштову скриньку протягом %s для завершення реєстрації. must_change_password=Оновіть свій пароль allow_password_change=Вимагати в користувача змінити пароль (рекомендується) reset_password_mail_sent_prompt=Електронний лист із підтвердженням надіслано <b>%s</b>. Перевірте папку 'Вхідні' в межах наступних %s, щоб завершити процес відновлення облікового запису. @@ -483,6 +483,7 @@ user_bio=Біографія disabled_public_activity=Цей користувач вимкнув публічний показ діяльності. + [settings] profile=Профіль account=Обліковий запис @@ -599,7 +600,6 @@ gpg_invalid_token_signature=Наданий ключ GPG, підпис і ток gpg_token_required=Вам потрібно надати підпис для нижчевказаного токена gpg_token=Токен gpg_token_help=Ви можете створити підпис за допомогою: -gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig gpg_token_signature=Текстовий (armored) підпис GPG key_signature_gpg_placeholder=`Починається з "-----BEGIN PGP SIGNATURE-----"` ssh_key_verified=Перевірений ключ @@ -738,7 +738,6 @@ fork_repo=Форкнути репозиторій fork_from=Форк з fork_visibility_helper=Неможливо змінити видимість форкнутого репозиторію. use_template=Застосувати цей шаблон -clone_in_vsc=Клонувати у VS Code download_zip=Завантажити ZIP download_tar=Завантажити TAR.GZ download_bundle=Завантажити BUNDLE @@ -980,8 +979,6 @@ editor.require_signed_commit=Гілка вимагає підписаного к commits.desc=Переглянути історію зміни коду. commits.commits=Коміти commits.nothing_to_compare=Ці гілки однакові. -commits.search=Знайти коміт… -commits.find=Пошук commits.search_all=Усі гілки commits.author=Автор commits.message=Повідомлення @@ -1019,7 +1016,6 @@ projects.type.basic_kanban=Спрощений канбан projects.type.bug_triage=Сортування помилок projects.template.desc=Шаблон проєкту projects.template.desc_helper=Оберіть шаблон проєкту, аби почати -projects.type.uncategorized=Без категорії projects.column.edit_title=Назва projects.column.new_title=Назва projects.column.color=Колір @@ -1311,7 +1307,6 @@ pulls.compare_compare=pull з pulls.switch_comparison_type=Перемкнути вигляд порівняння pulls.switch_head_and_base=Поміняти місцями основну та базову гілку pulls.filter_branch=Фільтр по гілці -pulls.no_results=Результатів не знайдено. pulls.nothing_to_compare=Ці гілки однакові. Немає необхідності створювати запитів на злиття. pulls.nothing_to_compare_and_allow_empty_pr=Одинакові гілки. Цей PR буде порожнім. pulls.has_pull_request=`Запит злиття для цих гілок вже існує: <a href="%[1]s">%[2]s#%[3]d</a>` @@ -1511,13 +1506,6 @@ activity.git_stats_deletion_n=%d видалені contributors.contribution_type.commits=Коміти -search=Пошук -search.search_repo=Пошук репозиторію -search.fuzzy=Неточний -search.match=Збігається -search.results=Результати пошуку для "%s" в <a href="%s">%s</a> -search.code_no_results=Відповідний пошуковому запитанню код не знайдено. - settings=Налаштування settings.desc=У налаштуваннях ви можете змінювати різні параметри цього репозиторія settings.options=Репозиторій @@ -1633,7 +1621,6 @@ settings.delete_collaborator=Видалити settings.collaborator_deletion=Видалити співавтора settings.collaborator_deletion_desc=Цей користувач більше не матиме доступу для спільної роботи в цьому репозиторії після видалення. Ви хочете продовжити? settings.remove_collaborator_success=Співавтор видалений. -settings.search_user_placeholder=Пошук користувача… settings.org_not_allowed_to_be_collaborator=Організації не можуть бути додані як співавтори. settings.change_team_access_not_allowed=Зміна доступу команди до репозитарію обмежена власником організації settings.team_not_in_organization=Команда та репозитарій мають привязки до різних організацій @@ -1641,7 +1628,6 @@ settings.teams=Команди settings.add_team=Додати Команду settings.add_team_duplicate=Команда вже має привязку до репозитарію settings.add_team_success=Команда отримала доступ до репозиторію. -settings.search_team=Знайти команду… settings.change_team_permission_tip=Дозволи команди встановлюються на сторінці налаштувань команди та не можуть бути заданими для кожного з репозиторіїв окремо settings.delete_team_tip=Ця команда має доступ до всіх репозиторіїв та не може бути видалена settings.remove_team_success=Доступ команди до репозиторію видалений. @@ -1758,9 +1744,7 @@ settings.protect_whitelist_committers=Білий список обмеження settings.protect_whitelist_committers_desc=Лише користувачі та команди з білого списку зможуть виконувати push в цій гілці (за виключеням force push). settings.protect_whitelist_deploy_keys=Білий список ключів розгортання з правом на запис. settings.protect_whitelist_users=Користувачі, які можуть робити push в цю гілку: -settings.protect_whitelist_search_users=Пошук користувачів… settings.protect_whitelist_teams=Команди, учасники яких можуть робити push в цю гілку: -settings.protect_whitelist_search_teams=Пошук команд… settings.protect_merge_whitelist_committers=Обмежити право на прийняття Pull Request'ів в цю гілку списком settings.protect_merge_whitelist_committers_desc=Ви можете додавати користувачів або цілі команди в 'білий' список цієї гілки. Тільки присутні в списку зможуть приймати запити на злиття. В іншому випадку будь-хто з правами запису до головного репозиторію буде володіти такою можливістю. settings.protect_merge_whitelist_users=Користувачі з правом на прийняття Pull Request'ів в цю гілку: @@ -2057,7 +2041,6 @@ teams.write_permission_desc=Ця команда надає доступ на <st teams.admin_permission_desc=Ця команда надає <strong>адміністраторський</strong> доступ: учасники можуть читати, виконувати push команди та додавати співробітників до репозиторію. teams.create_repo_permission_desc=Крім того, ця команда надає дозвіл <strong>Створити репозиторій</strong>: учасники можуть створювати нові репозиторії в організації. teams.repositories=Репозиторії команди -teams.search_repo_placeholder=Пошук репозиторію… teams.remove_all_repos_title=Видалити всі репозиторії команди teams.remove_all_repos_desc=Це видалить усі репозиторії команди. teams.add_all_repos_title=Додати всі репозиторії @@ -2082,6 +2065,8 @@ hooks=Веб-хуки authentication=Джерела автентифікації emails=Електронні адреси Користувача config=Конфігурація +config_summary=Підсумок +config_settings=Налаштування notices=Сповіщення системи monitor=Моніторинг first_page=Перша @@ -2230,9 +2215,6 @@ repos.unadopted.no_more=Не знайдено більше неприйняти repos.owner=Власник repos.name=Назва repos.private=Приватний -repos.watches=Стежать -repos.stars=В обраному -repos.forks=Форки repos.issues=Задачі repos.size=Розмір @@ -2330,7 +2312,6 @@ auths.tip.nextcloud=`Зареєструйте нового споживача OA 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.google_plus=Отримайте облікові дані клієнта OAuth2 в консолі Google API на сторінці https://console.developers.google.com/ auths.tip.openid_connect=Використовуйте OpenID Connect Discovery URL (<server>/.well-known/openid-configuration) для автоматичної настройки входу OAuth auths.tip.twitter=Перейдіть на https://dev.twitter.com/apps, створіть програму і переконайтеся, що включена опція «Дозволити цю програму для входу в систему за допомогою Twitter» diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 89f237a117..406e9ac8f2 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -142,6 +142,15 @@ confirm_delete_selected=确认删除所有选中项目? name=名称 value=值 +filter=过滤 +filter.is_archived=已归档 +filter.is_template=模板 +filter.public=公开 +filter.private=私有库 + + +[search] + [aria] navbar=导航栏 footer=页脚 @@ -315,7 +324,6 @@ collaborative_repos=参与协作的仓库 my_orgs=我的组织 my_mirrors=我的镜像 view_home=访问 %s -search_repos=查找仓库… filter=其他过滤器 filter_by_team_repositories=按团队仓库筛选 feed_of=`"%s"的源` @@ -336,20 +344,8 @@ issues.in_your_repos=在您的仓库中 repos=仓库 users=用户 organizations=组织 -search=搜索 go_to=转到 code=代码 -search.type.tooltip=搜索类型 -search.fuzzy=模糊 -search.fuzzy.tooltip=包含近似匹配搜索词的结果 -search.match=匹配 -search.match.tooltip=仅包含精确匹配搜索词的结果 -code_search_unavailable=目前代码搜索不可用。请与网站管理员联系。 -repo_no_results=未找到匹配的仓库。 -user_no_results=未找到匹配的用户。 -org_no_results=未找到匹配的组织。 -code_no_results=未找到与搜索字词匹配的源代码。 -code_search_results=“%s” 的搜索结果是 code_last_indexed_at=最后索引于 %s relevant_repositories_tooltip=派生的仓库,以及缺少主题、图标和描述的仓库将被隐藏。 relevant_repositories=只显示相关的仓库, <a href="%s">显示未过滤结果</a>。 @@ -367,7 +363,6 @@ forgot_password_title=忘记密码 forgot_password=忘记密码? sign_up_now=还没帐户?马上注册。 sign_up_successful=帐户创建成功。欢迎! -confirmation_mail_sent_prompt=一封新的确认邮件已经被发送至 <b>%s</b>,请检查您的收件箱并在 %s 内完成确认注册操作。 must_change_password=更新您的密码 allow_password_change=要求用户更改密码(推荐) reset_password_mail_sent_prompt=确认电子邮件已被发送到 <b>%s</b>。请您在 %s 内检查您的收件箱 ,完成密码重置过程。 @@ -617,6 +612,7 @@ form.name_reserved=用户名 "%s" 被保留。 form.name_pattern_not_allowed=用户名中不允许使用 "%s" 格式。 form.name_chars_not_allowed=用户名 "%s" 包含无效字符。 + [settings] profile=个人信息 account=账号 @@ -761,7 +757,6 @@ gpg_invalid_token_signature=提供的 GPG 密钥、签名和令牌不匹配或 gpg_token_required=您必须为下面的令牌提供签名 gpg_token=令牌 gpg_token_help=您可以使用以下方式生成签名: -gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig gpg_token_signature=GPG 增强签名 key_signature_gpg_placeholder=以 '-----BEGIN PGP PUBLIC KEY BLOCK-----' 开头 verify_gpg_key_success=GPG 密钥 %s 已被验证。 @@ -955,7 +950,6 @@ fork_branch=要克隆到 Fork 的分支 all_branches=所有分支 fork_no_valid_owners=这个代码仓库无法被派生,因为没有有效的所有者。 use_template=使用此模板 -clone_in_vsc=在 VS Code 中克隆 download_zip=下载 ZIP download_tar=下载 TAR.GZ download_bundle=下载 BUNDLE @@ -1280,9 +1274,7 @@ commits.desc=浏览代码修改历史 commits.commits=次代码提交 commits.no_commits=没有共同的提交。%s 和 %s 的历史完全不同。 commits.nothing_to_compare=这些分支是相同的。 -commits.search=搜索提交历史 commits.search.tooltip=`您可以在关键词前加上前缀,如"author:", "committer:", "after:", 或"before:", 例如 "retrin author:Alice before:2019-01-13"` -commits.find=搜索 commits.search_all=所有分支 commits.author=作者 commits.message=备注 @@ -1333,7 +1325,6 @@ projects.type.basic_kanban=基础看板 projects.type.bug_triage=Bug分类看板 projects.template.desc=项目模板 projects.template.desc_helper=选择一个项目模板以开始 -projects.type.uncategorized=未分类 projects.column.edit=编辑列 projects.column.edit_title=名称 projects.column.new_title=名称 @@ -1341,10 +1332,7 @@ projects.column.new_submit=创建列 projects.column.new=创建列 projects.column.set_default=设为默认 projects.column.set_default_desc=设置此列为未分类问题和合并请求的默认值 -projects.column.unset_default=取消设为默认 -projects.column.unset_default_desc=取消此列为默认值 projects.column.delete=删除列 -projects.column.deletion_desc=删除项目列会将所有相关问题移到“未分类”。是否继续? projects.column.color=彩色 projects.open=开启 projects.close=关闭 @@ -1456,7 +1444,6 @@ issues.filter_sort.moststars=点赞由多到少 issues.filter_sort.feweststars=点赞由少到多 issues.filter_sort.mostforks=派生由多到少 issues.filter_sort.fewestforks=派生由少到多 -issues.keyword_search_unavailable=关键词搜索目前不可用。请联系网站管理员。 issues.action_open=开启 issues.action_close=关闭 issues.action_label=标签 @@ -1708,7 +1695,6 @@ pulls.compare_compare=拉取从 pulls.switch_comparison_type=切换比较类型 pulls.switch_head_and_base=切换 head 和 base pulls.filter_branch=过滤分支 -pulls.no_results=未找到结果 pulls.show_all_commits=显示所有提交 pulls.show_changes_since_your_last_review=显示自您上次审核以来的更改 pulls.showing_only_single_commit=仅显示提交 %[1]s 的更改 @@ -1983,17 +1969,6 @@ contributors.contribution_type.commits=提交 contributors.contribution_type.additions=更多 contributors.contribution_type.deletions=删除 -search=搜索 -search.search_repo=搜索仓库... -search.type.tooltip=搜索类型 -search.fuzzy=模糊 -search.fuzzy.tooltip=包含近似匹配搜索词的结果 -search.match=匹配 -search.match.tooltip=仅包含精确匹配搜索词的结果 -search.results=在 <a href="%[2]s"> %[3]s </a> 中搜索 "%[1]s" 的结果 -search.code_no_results=未找到与搜索字词匹配的源代码。 -search.code_search_unavailable=当前代码搜索不可用。请与网站管理员联系。 - settings=设置 settings.desc=设置是你可以管理仓库设置的地方 settings.options=仓库 @@ -2072,6 +2047,7 @@ settings.pulls.default_allow_edits_from_maintainers=默认开启允许维护者 settings.releases_desc=启用发布 settings.packages_desc=启用仓库软件包注册中心 settings.projects_desc=启用仓库项目 +settings.projects_mode_all=所有项目 settings.actions_desc=启用 Actions settings.admin_settings=管理员设置 settings.admin_enable_health_check=启用仓库健康检查 (git fsck) @@ -2146,7 +2122,6 @@ settings.delete_collaborator=删除 settings.collaborator_deletion=删除协作者 settings.collaborator_deletion_desc=删除协作者后他将无法再对此仓库的访问。继续? settings.remove_collaborator_success=协作者删除成功! -settings.search_user_placeholder=搜索用户... settings.org_not_allowed_to_be_collaborator=组织不允许被添加为仓库协作者! settings.change_team_access_not_allowed=更改仓库的团队访问权限仅限于组织所有者 settings.team_not_in_organization=团队不在与仓库相同的组织中 @@ -2154,7 +2129,6 @@ settings.teams=团队 settings.add_team=添加团队 settings.add_team_duplicate=团队已经拥有仓库 settings.add_team_success=团队现在可以访问仓库。 -settings.search_team=搜索团队... settings.change_team_permission_tip=团队权限设置于团队设置页面,不能根据仓库更改 settings.delete_team_tip=该团队仍有仓库, 无法删除 settings.remove_team_success=团队访问仓库的权限已被删除。 @@ -2307,9 +2281,7 @@ settings.protect_whitelist_committers=受白名单限制的推送 settings.protect_whitelist_committers_desc=只有列入白名单的用户或团队才能被允许推送到此分支(但不能强行推送)。 settings.protect_whitelist_deploy_keys=具有推送权限的部署密钥白名单。 settings.protect_whitelist_users=推送白名单用户: -settings.protect_whitelist_search_users=搜索用户... settings.protect_whitelist_teams=推送白名单团队: -settings.protect_whitelist_search_teams=搜索团队... settings.protect_merge_whitelist_committers=启用合并白名单 settings.protect_merge_whitelist_committers_desc=仅允许白名单用户或团队合并合并请求到此分支。 settings.protect_merge_whitelist_users=合并白名单用户: @@ -2554,7 +2526,6 @@ branch.default_deletion_failed=不能删除默认分支"%s"。 branch.restore=`还原分支 "%s"` branch.download=`下载分支 "%s"` branch.rename=`重命名分支 "%s"` -branch.search=搜索分支 branch.included_desc=此分支是默认分支的一部分 branch.included=已包含 branch.create_new_branch=从下列分支创建分支: @@ -2697,7 +2668,6 @@ teams.write_permission_desc=该团队拥有对所属仓库的 <strong>读取</st teams.admin_permission_desc=该团队拥有一定的 <strong>管理</strong> 权限,团队成员可以读取、克隆、推送以及添加其它仓库协作者。 teams.create_repo_permission_desc=此外,该团队拥有了 <strong>创建仓库</strong> 的权限:成员可以在组织中创建新的仓库。 teams.repositories=团队仓库 -teams.search_repo_placeholder=搜索仓库... teams.remove_all_repos_title=移除所有团队仓库 teams.remove_all_repos_desc=这将从团队中移除所有仓库。 teams.add_all_repos_title=添加所有仓库 @@ -2730,6 +2700,8 @@ integrations=集成 authentication=认证源 emails=用户邮件 config=应用配置 +config_summary=摘要 +config_settings=组织设置 notices=系统提示 monitor=监控面板 first_page=首页 @@ -2906,9 +2878,6 @@ repos.unadopted.no_more=找不到更多未被收录的仓库 repos.owner=所有者 repos.name=名称 repos.private=私有库 -repos.watches=关注数 -repos.stars=点赞数 -repos.forks=派生数 repos.issues=工单数 repos.size=大小 repos.lfs_size=LFS 大小 @@ -3033,7 +3002,6 @@ auths.tip.nextcloud=使用下面的菜单“设置(Settings) -> 安全(Sec auths.tip.dropbox=在 https://www.dropbox.com/developers/apps 上创建一个新的应用程序 auths.tip.facebook=`在 https://developers.facebook.com/apps 注册一个新的应用,并添加产品"Facebook 登录"` auths.tip.github=在 https://github.com/settings/applications/new 注册一个 OAuth 应用程序 -auths.tip.gitlab=在 https://gitlab.com/profile/applications 上注册新应用程序 auths.tip.google_plus=从谷歌 API 控制台 (https://console.developers.google.com/) 获得 OAuth2 客户端凭据 auths.tip.openid_connect=使用 OpenID 连接发现 URL (<server>/.well-known/openid-configuration) 来指定终点 auths.tip.twitter=访问 https://dev.twitter.com/apps,创建应用并确保启用了"允许此应用程序用于登录 Twitter"的选项。 diff --git a/options/locale/locale_zh-HK.ini b/options/locale/locale_zh-HK.ini index 8c45e3157f..d4b65239a6 100644 --- a/options/locale/locale_zh-HK.ini +++ b/options/locale/locale_zh-HK.ini @@ -61,6 +61,12 @@ concept_code_repository=儲存庫 name=組織名稱 +filter.is_template=樣板 +filter.private=私有庫 + + +[search] + [aria] [heatmap] @@ -116,13 +122,11 @@ issues.in_your_repos=屬於該用戶儲存庫的 repos=儲存庫 users=使用者 organizations=組織 -search=搜尋 [auth] register_helper_msg=已經註冊?立即登錄! forgot_password_title=忘記密碼 forgot_password=忘記密碼? -confirmation_mail_sent_prompt=一封新的確認郵件已發送至 <b>%s</b>。請檢查您的收件箱並在 %s 小時內完成確認註冊操作。 active_your_account=啟用您的帳戶 has_unconfirmed_mail=%s 您好,您有一封發送至( <b>%s</b>) 但未被確認的郵件。如果您未收到啟用郵件,或需要重新發送,請單擊下方的按鈕。 resend_mail=單擊此處重新發送確認郵件 @@ -205,6 +209,7 @@ follow=關注 unfollow=取消關注 + [settings] profile=個人訊息 password=修改密碼 @@ -375,7 +380,6 @@ editor.cancel=取消 editor.no_changes_to_show=沒有可以顯示的變更。 commits.commits=次程式碼提交 -commits.find=搜尋 commits.author=作者 commits.message=備註 commits.date=提交日期 @@ -481,7 +485,6 @@ issues.dependency.remove=移除成員 pulls.new=建立合併請求 pulls.compare_changes=建立合併請求 pulls.filter_branch=過濾分支 -pulls.no_results=未找到結果 pulls.create=建立合併請求 pulls.merged_title_desc=於 %[4]s 將 %[1]d 次代碼提交從 <code>%[2]s</code>合併至 <code>%[3]s</code> pulls.tab_conversation=對話內容 @@ -540,8 +543,6 @@ activity.new_issues_count_1=建立問題 contributors.contribution_type.commits=提交歷史 -search=搜尋 - settings=儲存庫設定 settings.desc=設定是您可以管理儲存庫設定的地方 settings.options=儲存庫 @@ -698,6 +699,7 @@ dashboard=控制面版 organizations=組織管理 repositories=儲存庫管理 config=應用設定管理 +config_settings=組織設定 notices=系統提示管理 monitor=應用監控面版 first_page=首頁 @@ -760,8 +762,6 @@ repos.repo_manage_panel=儲存庫管理 repos.owner=所有者 repos.name=儲存庫名稱 repos.private=私有庫 -repos.watches=關註數 -repos.stars=讚好數 repos.issues=問題數 repos.size=大小 @@ -809,7 +809,6 @@ auths.tip.oauth2_provider=OAuth2 提供者 auths.tip.dropbox=建立新 App 在 https://www.dropbox.com/developers/apps auths.tip.facebook=`在 https://developers.facebook.com/apps 註冊一個新的應用,並且新增一個產品 "Facebook Login"` auths.tip.github=在 https://github.com/settings/applications/new 註冊一個新的 OAuth 應用程式 -auths.tip.gitlab=在 https://gitlab.com/profile/applications 註冊一個新的應用程式 auths.tip.openid_connect=使用 OpenID 連接探索 URL (<server>/.well-known/openid-configuration) 來指定節點 auths.delete=刪除認證來源 auths.delete_auth_title=刪除認證來源 diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini index 09eb262212..0511fa44ae 100644 --- a/options/locale/locale_zh-TW.ini +++ b/options/locale/locale_zh-TW.ini @@ -125,6 +125,15 @@ concept_user_organization=組織 name=名稱 value=值 +filter=篩選 +filter.is_archived=已封存 +filter.is_template=模板 +filter.public=公開 +filter.private=私有 + + +[search] + [aria] navbar=導航列 footer=頁尾 @@ -292,7 +301,6 @@ collaborative_repos=參與協作的儲存庫 my_orgs=我的組織 my_mirrors=我的鏡像 view_home=訪問 %s -search_repos=搜尋儲存庫... filter=其他篩選條件 filter_by_team_repositories=以團隊儲存庫篩選 feed_of=「%s」的訊息來源 @@ -313,19 +321,7 @@ issues.in_your_repos=在您的儲存庫中 repos=儲存庫 users=使用者 organizations=組織 -search=搜尋 code=程式碼 -search.type.tooltip=搜尋類型 -search.fuzzy=模糊 -search.fuzzy.tooltip=包含近似關鍵字的結果 -search.match=符合 -search.match.tooltip=只包含完全符合關鍵字的結果 -code_search_unavailable=現在無法使用程式碼搜尋。請與網站管理員聯絡。 -repo_no_results=沒有找到符合的儲存庫。 -user_no_results=沒有找到符合的使用者。 -org_no_results=沒有找到符合的組織。 -code_no_results=找不到符合您關鍵字的原始碼。 -code_search_results=「%s」的搜尋結果 code_last_indexed_at=最後索引 %s relevant_repositories_tooltip=已隱藏缺少主題、圖示、說明、Fork 的儲存庫。 relevant_repositories=只顯示相關的儲存庫,<a href="%s">顯示未篩選的結果</a>。 @@ -341,7 +337,6 @@ remember_me=記得這個裝置 forgot_password_title=忘記密碼 forgot_password=忘記密碼? sign_up_now=還沒有帳戶?馬上註冊。 -confirmation_mail_sent_prompt=新的確認信已發送至 <b>%s</b>。請在 %s內檢查您的收件匣並完成註冊作業。 must_change_password=更新您的密碼 allow_password_change=要求使用者更改密碼 (推薦) reset_password_mail_sent_prompt=確認信已發送至 <b>%s</b>。請在 %s內檢查您的收件匣並完成帳戶救援作業。 @@ -578,6 +573,7 @@ form.name_reserved=「%s」是保留的帳號。 form.name_pattern_not_allowed=帳號不可包含字元「%s」。 form.name_chars_not_allowed=帳號「%s」包含無效字元。 + [settings] profile=個人資料 account=帳戶 @@ -707,7 +703,6 @@ gpg_invalid_token_signature=提供的 GPG 金鑰、簽署、Token 不符合或 T gpg_token_required=您必須為下列的 Token 提供簽署 gpg_token=Token gpg_token_help=您可以使用以下方法產生簽署: -gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig gpg_token_signature=Armored GPG 簽署 key_signature_gpg_placeholder=以「-----BEGIN PGP SIGNATURE-----」開頭 verify_gpg_key_success=已驗證 GPG 金鑰「%s」。 @@ -867,7 +862,6 @@ already_forked=您已經 fork 過 %s fork_to_different_account=Fork 到其他帳戶 fork_visibility_helper=無法更改 fork 儲存庫的瀏覽權限。 use_template=使用此範本 -clone_in_vsc=在 VS Code 中 Clone download_zip=下載 ZIP download_tar=下載 TAR.GZ download_bundle=下載 BUNDLE @@ -1155,9 +1149,7 @@ commits.desc=瀏覽原始碼修改歷程。 commits.commits=次程式碼提交 commits.no_commits=沒有共同的提交。「%s」和「%s」的歷史完全不同。 commits.nothing_to_compare=這些分支是相同的。 -commits.search=搜尋提交歷史... commits.search.tooltip=你可以用「author:」、「committer:」、「after:」、「before:」等作為關鍵字的前綴,例如: 「revert author:Alice before:2019-01-13」。 -commits.find=搜尋 commits.search_all=所有分支 commits.author=作者 commits.message=備註 @@ -1207,7 +1199,6 @@ projects.type.basic_kanban=基本看板 projects.type.bug_triage=Bug 檢傷分類 projects.template.desc=範本 projects.template.desc_helper=選擇專案範本以開始 -projects.type.uncategorized=未分類 projects.column.edit=編輯欄位 projects.column.edit_title=名稱 projects.column.new_title=名稱 @@ -1216,7 +1207,6 @@ projects.column.new=新增欄位 projects.column.set_default=設為預設 projects.column.set_default_desc=將此欄位設定為未分類問題及合併請求的預設預設值 projects.column.delete=刪除欄位 -projects.column.deletion_desc=刪除專案欄位會將所有相關的問題移動到「未分類」,是否繼續? projects.column.color=顏色 projects.open=開啟 projects.close=關閉 @@ -1552,7 +1542,6 @@ pulls.compare_compare=拉取自 pulls.switch_comparison_type=切換比較類型 pulls.switch_head_and_base=切換 head 和 base pulls.filter_branch=過濾分支 -pulls.no_results=未找到結果 pulls.nothing_to_compare=這些分支的內容相同,無需建立合併請求。 pulls.nothing_to_compare_and_allow_empty_pr=這些分支的內容相同,此合併請求將會是空白的。 pulls.has_pull_request=`已有介於這些分支間的合併請求:<a href="%[1]s">%[2]s#%[3]d</a>` @@ -1779,17 +1768,6 @@ activity.git_stats_deletion_n=刪除 %d 行 contributors.contribution_type.commits=提交歷史 -search=搜尋 -search.search_repo=搜尋儲存庫 -search.type.tooltip=搜尋類型 -search.fuzzy=模糊 -search.fuzzy.tooltip=包含近似關鍵字的結果 -search.match=符合 -search.match.tooltip=只包含完全符合關鍵字的結果 -search.results=在 <a href="%s"> %s </a> 中搜尋 "%s" 的结果 -search.code_no_results=找不到符合您關鍵字的原始碼。 -search.code_search_unavailable=現在無法使用程式碼搜尋。請與網站管理員聯絡。 - settings=設定 settings.desc=設定是您可以管理儲存庫設定的地方 settings.options=儲存庫 @@ -1850,6 +1828,7 @@ settings.pulls.default_allow_edits_from_maintainers=預設允許維護者進行 settings.releases_desc=啟用儲存庫版本發佈 settings.packages_desc=啟用儲存庫套件註冊中心 settings.projects_desc=啟用儲存庫專案 +settings.projects_mode_all=所有專案 settings.actions_desc=啟用儲存庫 Actions settings.admin_settings=管理員設定 settings.admin_enable_health_check=啟用儲存庫的健康檢查 (git fsck) @@ -1922,7 +1901,6 @@ settings.delete_collaborator=移除 settings.collaborator_deletion=移除協作者 settings.collaborator_deletion_desc=移除協作者將拒絕他存取此儲存庫。是否繼續? settings.remove_collaborator_success=已移除協作者。 -settings.search_user_placeholder=搜尋使用者... settings.org_not_allowed_to_be_collaborator=不可加入組織為協作者。 settings.change_team_access_not_allowed=只有組織擁有者可修改團隊的儲存庫存取權限 settings.team_not_in_organization=團隊和儲存庫不在相同的組織內 @@ -1930,7 +1908,6 @@ settings.teams=團隊 settings.add_team=增加團隊 settings.add_team_duplicate=團隊已擁有該儲存庫 settings.add_team_success=團隊現在可存取該儲存庫了。 -settings.search_team=搜尋團隊... settings.change_team_permission_tip=團隊權限可於團隊設定頁面修改,不能針對儲存庫分別調整。 settings.delete_team_tip=此團隊可存取所有儲存庫,無法移除 settings.remove_team_success=已移除團隊存取儲存庫的權限。 @@ -2077,9 +2054,7 @@ settings.protect_whitelist_committers=使用白名單控管推送 settings.protect_whitelist_committers_desc=僅允許白名單內的使用者或團隊推送至該分支(但不可使用force push)。 settings.protect_whitelist_deploy_keys=將擁有寫入權限的部署金鑰加入白名單。 settings.protect_whitelist_users=允許推送的使用者: -settings.protect_whitelist_search_users=搜尋使用者... settings.protect_whitelist_teams=允許推送的團隊: -settings.protect_whitelist_search_teams=搜尋團隊... settings.protect_merge_whitelist_committers=啟用合併白名單 settings.protect_merge_whitelist_committers_desc=僅允許白名單內的使用者或團隊將合併請求合併至該分支。 settings.protect_merge_whitelist_users=允許合併的使用者: @@ -2427,7 +2402,6 @@ teams.write_permission_desc=這個團隊擁有<strong>寫入</strong> 權限: teams.admin_permission_desc=這個團隊擁有<strong>管理員</strong> 權限:成員可以讀取、推送和增加協作者到儲存庫。 teams.create_repo_permission_desc=此外,這個團隊還擁有<strong>建立儲存庫</strong>的權限:成員可以在組織中新增儲存庫。 teams.repositories=團隊儲存庫 -teams.search_repo_placeholder=搜尋儲存庫... teams.remove_all_repos_title=移除所有團隊儲存庫 teams.remove_all_repos_desc=這將從團隊中移除所有儲存庫。 teams.add_all_repos_title=增加所有儲存庫 @@ -2455,6 +2429,8 @@ hooks=Webhook authentication=認證來源 emails=使用者電子信箱 config=組態 +config_summary=摘要 +config_settings=設定 notices=系統提示 monitor=應用監控面版 first_page=首頁 @@ -2616,9 +2592,6 @@ repos.unadopted.no_more=找不到其他未接管的儲存庫 repos.owner=擁有者 repos.name=名稱 repos.private=私有 -repos.watches=關注數 -repos.stars=星號數 -repos.forks=Fork 數 repos.issues=問題數 repos.size=大小 @@ -2737,7 +2710,6 @@ auths.tip.nextcloud=在您的執行個體中,於選單「設定 -> 安全性 - auths.tip.dropbox=建立新的 App。網址:https://www.dropbox.com/developers/apps auths.tip.facebook=註冊新的應用程式並新增產品「Facebook 登入」。網址:https://developers.facebook.com/apps auths.tip.github=註冊新的 OAuth 應用程式。網址:https://github.com/settings/applications/new -auths.tip.gitlab=註冊新的應用程式。網址:https://gitlab.com/profile/applications auths.tip.google_plus=從 Google API 控制台取得 OAuth2 用戶端憑證。網址:https://console.developers.google.com/ auths.tip.openid_connect=使用 OpenID 連接探索 URL (<server>/.well-known/openid-configuration) 來指定節點 auths.tip.twitter=建立應用程式並確保有啟用「Allow this application to be used to Sign in with Twitter」。網址:https://dev.twitter.com/apps From 2b3f7d3e966ab60cb147115303d1992e8b50d4df Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Sun, 31 Mar 2024 00:30:00 +0300 Subject: [PATCH 004/370] Remove jQuery class from the repository branch settings (#30184) - Switched from jQuery class functions to plain JavaScript `classList` - Tested the repository branch settings functionality and it works as before Signed-off-by: Yarden Shoham <git@yardenshoham.com> --- web_src/js/features/repo-settings.js | 31 ++++++++++++++++------------ 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/web_src/js/features/repo-settings.js b/web_src/js/features/repo-settings.js index 0ea44130d0..52c5de2bfa 100644 --- a/web_src/js/features/repo-settings.js +++ b/web_src/js/features/repo-settings.js @@ -77,18 +77,24 @@ export function initRepoSettingGitHook() { } export function initRepoSettingBranches() { - if (!$('.repository.settings.branches').length) return; - $('.toggle-target-enabled').on('change', function () { - const $target = $(this.getAttribute('data-target')); - $target.toggleClass('disabled', !this.checked); - }); - $('.toggle-target-disabled').on('change', function () { - const $target = $(this.getAttribute('data-target')); - if (this.checked) $target.addClass('disabled'); // only disable, do not auto enable - }); - $('#dismiss_stale_approvals').on('change', function () { - const $target = $('#ignore_stale_approvals_box'); - $target.toggleClass('disabled', this.checked); + if (!document.querySelector('.repository.settings.branches')) return; + + for (const el of document.getElementsByClassName('toggle-target-enabled')) { + el.addEventListener('change', function () { + const target = document.querySelector(this.getAttribute('data-target')); + target?.classList.toggle('disabled', !this.checked); + }); + } + + for (const el of document.getElementsByClassName('toggle-target-disabled')) { + el.addEventListener('change', function () { + const target = document.querySelector(this.getAttribute('data-target')); + if (this.checked) target?.classList.add('disabled'); // only disable, do not auto enable + }); + } + + document.getElementById('dismiss_stale_approvals')?.addEventListener('change', function () { + document.getElementById('ignore_stale_approvals_box')?.classList.toggle('disabled', this.checked); }); // show the `Matched` mark for the status checks that match the pattern @@ -106,7 +112,6 @@ export function initRepoSettingBranches() { break; } } - toggleElem(el, matched); } }; From 6aeff21b76fcbb10d5ce9009ed4243c14633d899 Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Sun, 31 Mar 2024 01:09:46 +0300 Subject: [PATCH 005/370] Remove jQuery class from the comment edit history (#30186) - Switched from jQuery class functions to plain JavaScript `classList` - Tested the comment edit history functionality and it works as before Signed-off-by: Yarden Shoham <git@yardenshoham.com> Co-authored-by: Giteabot <teabot@gitea.io> --- web_src/js/features/repo-issue-content.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/web_src/js/features/repo-issue-content.js b/web_src/js/features/repo-issue-content.js index 3c4efe0447..cef2f49008 100644 --- a/web_src/js/features/repo-issue-content.js +++ b/web_src/js/features/repo-issue-content.js @@ -2,6 +2,7 @@ import $ from 'jquery'; import {svg} from '../svg.js'; import {showErrorToast} from '../modules/toast.js'; import {GET, POST} from '../modules/fetch.js'; +import {showElem} from '../utils/dom.js'; const {appSubUrl} = window.config; let i18nTextEdited; @@ -73,10 +74,12 @@ function showContentHistoryDetail(issueBaseUrl, commentId, historyId, itemTitleH const response = await GET(url); const resp = await response.json(); - $dialog.find('.comment-diff-data').removeClass('is-loading').html(resp.diffHtml); + const commentDiffData = $dialog.find('.comment-diff-data')[0]; + commentDiffData?.classList.remove('is-loading'); + commentDiffData.innerHTML = resp.diffHtml; // there is only one option "item[data-option-item=delete]", so the dropdown can be entirely shown/hidden. if (resp.canSoftDelete) { - $dialog.find('.dialog-header-options').removeClass('tw-hidden'); + showElem($dialog.find('.dialog-header-options')); } } catch (error) { console.error('Error:', error); From 72a5d3faa8b65042a4fc7525d511d8942a47dafe Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Sun, 31 Mar 2024 01:14:57 +0300 Subject: [PATCH 006/370] Remove jQuery class from the issue author dropdown (#30188) - Switched from jQuery class functions to plain JavaScript `classList` - Tested the issue author dropdown functionality and it works as before Signed-off-by: Yarden Shoham <git@yardenshoham.com> Co-authored-by: Giteabot <teabot@gitea.io> --- web_src/js/features/repo-issue-list.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/web_src/js/features/repo-issue-list.js b/web_src/js/features/repo-issue-list.js index 4582f87425..ccd13bbcf5 100644 --- a/web_src/js/features/repo-issue-list.js +++ b/web_src/js/features/repo-issue-list.js @@ -6,6 +6,7 @@ import {confirmModal} from './comp/ConfirmModal.js'; import {showErrorToast} from '../modules/toast.js'; import {createSortable} from '../modules/sortable.js'; import {DELETE, POST} from '../modules/fetch.js'; +import {parseDom} from '../utils.js'; function initRepoIssueListCheckboxes() { const issueSelectAll = document.querySelector('.issue-checkbox-all'); @@ -129,22 +130,27 @@ function initRepoIssueListAuthorDropdown() { const dropdownTemplates = $searchDropdown.dropdown('setting', 'templates'); $searchDropdown.dropdown('internal', 'setup', dropdownSetup); dropdownSetup.menu = function (values) { - const $menu = $searchDropdown.find('> .menu'); - $menu.find('> .dynamic-item').remove(); // remove old dynamic items + const menu = $searchDropdown.find('> .menu')[0]; + // remove old dynamic items + for (const el of menu.querySelectorAll(':scope > .dynamic-item')) { + el.remove(); + } const newMenuHtml = dropdownTemplates.menu(values, $searchDropdown.dropdown('setting', 'fields'), true /* html */, $searchDropdown.dropdown('setting', 'className')); if (newMenuHtml) { - const $newMenuItems = $(newMenuHtml); - $newMenuItems.addClass('dynamic-item'); + const newMenuItems = parseDom(newMenuHtml, 'text/html').querySelectorAll('body > div'); + for (const newMenuItem of newMenuItems) { + newMenuItem.classList.add('dynamic-item'); + } const div = document.createElement('div'); div.classList.add('divider', 'dynamic-item'); - $menu[0].append(div, ...$newMenuItems); + menu.append(div, ...newMenuItems); } $searchDropdown.dropdown('refresh'); // defer our selection to the next tick, because dropdown will set the selection item after this `menu` function setTimeout(() => { - $menu.find('.item.active, .item.selected').removeClass('active selected'); - $menu.find(`.item[data-value="${selectedUserId}"]`).addClass('selected'); + menu.querySelector('.item.active, .item.selected')?.classList.remove('active', 'selected'); + menu.querySelector(`.item[data-value="${selectedUserId}"]`)?.classList.add('selected'); }, 0); }; } From 640850e15f56bbe01f5d8ea407f99c79dc38457e Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 31 Mar 2024 01:00:58 +0100 Subject: [PATCH 007/370] Fix unclickable checkboxes (#30195) Fix https://github.com/go-gitea/gitea/issues/30185, regression from https://github.com/go-gitea/gitea/pull/30162. The checkboxes were unclickable because the label was positioned over the checkbox with `padding`. Now it uses `margin` so the checkbox itself will be clickable in all cases. Secondly, I changed the for/id linking to also add missing `for` attributes when `id` is present. The other way around (only `for` present) is currently not handled and I think there are likey no occurences in the code and introducing new non-generated `id`s might cause problems elsewhere if we do, so I skipped on that. --- web_src/css/modules/checkbox.css | 2 +- web_src/js/modules/fomantic/checkbox.js | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/web_src/css/modules/checkbox.css b/web_src/css/modules/checkbox.css index fc44a7c115..9238e0b3f3 100644 --- a/web_src/css/modules/checkbox.css +++ b/web_src/css/modules/checkbox.css @@ -41,7 +41,7 @@ input[type="radio"] { .ui.checkbox label, .ui.radio.checkbox label { - padding-left: 1.85714em; + margin-left: 1.85714em; } .ui.checkbox + label { diff --git a/web_src/js/modules/fomantic/checkbox.js b/web_src/js/modules/fomantic/checkbox.js index ffe853b28f..7f2b340296 100644 --- a/web_src/js/modules/fomantic/checkbox.js +++ b/web_src/js/modules/fomantic/checkbox.js @@ -6,10 +6,19 @@ export function initAriaCheckboxPatch() { if (el.hasAttribute('data-checkbox-patched')) continue; const label = el.querySelector('label'); const input = el.querySelector('input'); - if (!label || !input || input.getAttribute('id') || label.getAttribute('for')) continue; - const id = generateAriaId(); - input.setAttribute('id', id); - label.setAttribute('for', id); + if (!label || !input) continue; + const inputId = input.getAttribute('id'); + const labelFor = label.getAttribute('for'); + + if (inputId && !labelFor) { // missing "for" + label.setAttribute('for', inputId); + } else if (!inputId && !labelFor) { // missing both "id" and "for" + const id = generateAriaId(); + input.setAttribute('id', id); + label.setAttribute('for', id); + } else { + continue; + } el.setAttribute('data-checkbox-patched', 'true'); } } From 7eb3ab076549f83fadf4034f77e7794e785725fa Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Sun, 31 Mar 2024 00:27:17 +0000 Subject: [PATCH 008/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_de-DE.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 1dacb0e0ee..4d446db86f 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -102,7 +102,7 @@ copy=Kopieren copy_url=URL kopieren copy_hash=Hash kopieren copy_content=Inhalt kopieren -copy_branch=Branchennamen kopieren +copy_branch=Branchnamen kopieren copy_success=Kopiert! copy_error=Kopieren fehlgeschlagen copy_type_unsupported=Dieser Dateityp kann nicht kopiert werden From 82ffd91607ba03907ebad31ec9a38555b153a331 Mon Sep 17 00:00:00 2001 From: KN4CK3R <admin@oldschoolhack.me> Date: Sun, 31 Mar 2024 04:35:19 +0200 Subject: [PATCH 009/370] Fix GPG subkey verify (#30193) Fixes #30189 Can't verify subkeys if they are not loaded. --- models/asymkey/gpg_key_verify.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/models/asymkey/gpg_key_verify.go b/models/asymkey/gpg_key_verify.go index 4cf46ab556..01812a2d54 100644 --- a/models/asymkey/gpg_key_verify.go +++ b/models/asymkey/gpg_key_verify.go @@ -46,6 +46,10 @@ func VerifyGPGKey(ctx context.Context, ownerID int64, keyID, token, signature st return "", ErrGPGKeyNotExist{} } + if err := key.LoadSubKeys(ctx); err != nil { + return "", err + } + sig, err := extractSignature(signature) if err != nil { return "", ErrGPGInvalidTokenSignature{ From 6d34ce25b16cdfd6e2e364aebe546e3c2fbb76c6 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sun, 31 Mar 2024 11:03:24 +0800 Subject: [PATCH 010/370] Do not allow different storage configurations to point to the same directory (#30169) Replace #29171 --- modules/setting/indexer.go | 2 +- modules/setting/path.go | 4 --- modules/setting/repository.go | 2 +- modules/setting/server.go | 3 +- modules/setting/session.go | 2 +- modules/setting/setting.go | 13 ++++--- modules/setting/storage.go | 2 +- options/locale/locale_en-US.ini | 4 ++- routers/web/admin/admin.go | 8 +++++ templates/admin/dashboard.tmpl | 2 +- templates/admin/navbar.tmpl | 18 ++++++---- templates/admin/self_check.tmpl | 62 ++++++++++++++++++++------------- 12 files changed, 75 insertions(+), 47 deletions(-) diff --git a/modules/setting/indexer.go b/modules/setting/indexer.go index 15f6150242..cec364d370 100644 --- a/modules/setting/indexer.go +++ b/modules/setting/indexer.go @@ -58,7 +58,7 @@ func loadIndexerFrom(rootCfg ConfigProvider) { if !filepath.IsAbs(Indexer.IssuePath) { Indexer.IssuePath = filepath.ToSlash(filepath.Join(AppWorkPath, Indexer.IssuePath)) } - fatalDuplicatedPath("issue_indexer", Indexer.IssuePath) + checkOverlappedPath("indexer.ISSUE_INDEXER_PATH", Indexer.IssuePath) } else { Indexer.IssueConnStr = sec.Key("ISSUE_INDEXER_CONN_STR").MustString(Indexer.IssueConnStr) if Indexer.IssueType == "meilisearch" { diff --git a/modules/setting/path.go b/modules/setting/path.go index b2cca0acbf..0fdc305aa1 100644 --- a/modules/setting/path.go +++ b/modules/setting/path.go @@ -66,12 +66,8 @@ func init() { AppWorkPath = filepath.Dir(AppPath) } - fatalDuplicatedPath("app_work_path", AppWorkPath) - appWorkPathBuiltin = AppWorkPath customPathBuiltin = CustomPath - - fatalDuplicatedPath("custom_path", CustomPath) customConfBuiltin = CustomConf } diff --git a/modules/setting/repository.go b/modules/setting/repository.go index 7990021aaa..a332d6adb3 100644 --- a/modules/setting/repository.go +++ b/modules/setting/repository.go @@ -286,7 +286,7 @@ func loadRepositoryFrom(rootCfg ConfigProvider) { RepoRootPath = filepath.Clean(RepoRootPath) } - fatalDuplicatedPath("repository.ROOT", RepoRootPath) + checkOverlappedPath("repository.ROOT", RepoRootPath) defaultDetectedCharsetsOrder := make([]string, 0, len(Repository.DetectedCharsetsOrder)) for _, charset := range Repository.DetectedCharsetsOrder { diff --git a/modules/setting/server.go b/modules/setting/server.go index 0dea4e1ac7..315faaeb21 100644 --- a/modules/setting/server.go +++ b/modules/setting/server.go @@ -324,7 +324,6 @@ func loadServerFrom(rootCfg ConfigProvider) { if !filepath.IsAbs(AppDataPath) { AppDataPath = filepath.ToSlash(filepath.Join(AppWorkPath, AppDataPath)) } - fatalDuplicatedPath("app_data_path", AppDataPath) EnableGzip = sec.Key("ENABLE_GZIP").MustBool() EnablePprof = sec.Key("ENABLE_PPROF").MustBool(false) @@ -332,7 +331,7 @@ func loadServerFrom(rootCfg ConfigProvider) { if !filepath.IsAbs(PprofDataPath) { PprofDataPath = filepath.Join(AppWorkPath, PprofDataPath) } - fatalDuplicatedPath("pprof_data_path", PprofDataPath) + checkOverlappedPath("server.PPROF_DATA_PATH", PprofDataPath) landingPage := sec.Key("LANDING_PAGE").MustString("home") switch landingPage { diff --git a/modules/setting/session.go b/modules/setting/session.go index 70497e5eaa..3cb1bfe7b5 100644 --- a/modules/setting/session.go +++ b/modules/setting/session.go @@ -46,7 +46,7 @@ func loadSessionFrom(rootCfg ConfigProvider) { SessionConfig.ProviderConfig = strings.Trim(sec.Key("PROVIDER_CONFIG").MustString(filepath.Join(AppDataPath, "sessions")), "\" ") if SessionConfig.Provider == "file" && !filepath.IsAbs(SessionConfig.ProviderConfig) { SessionConfig.ProviderConfig = filepath.Join(AppWorkPath, SessionConfig.ProviderConfig) - fatalDuplicatedPath("session", SessionConfig.ProviderConfig) + checkOverlappedPath("session.PROVIDER_CONFIG", SessionConfig.ProviderConfig) } SessionConfig.CookieName = sec.Key("COOKIE_NAME").MustString("i_like_gitea") SessionConfig.CookiePath = AppSubURL diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 13821da44d..6aca9ec6cf 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -230,11 +230,14 @@ func LoadSettingsForInstall() { loadMailerFrom(CfgProvider) } -var uniquePaths = make(map[string]string) +var configuredPaths = make(map[string]string) -func fatalDuplicatedPath(name, p string) { - if targetName, ok := uniquePaths[p]; ok && targetName != name { - log.Fatal("storage path %q is being used by %q and %q and all storage paths must be unique to prevent data loss.", p, targetName, name) +func checkOverlappedPath(name, path string) { + // TODO: some paths shouldn't overlap (storage.xxx.path), while some could (data path is the base path for storage path) + if targetName, ok := configuredPaths[path]; ok && targetName != name { + msg := fmt.Sprintf("Configured path %q is used by %q and %q at the same time. The paths must be unique to prevent data loss.", path, targetName, name) + log.Error("%s", msg) + DeprecatedWarnings = append(DeprecatedWarnings, msg) } - uniquePaths[p] = name + configuredPaths[path] = name } diff --git a/modules/setting/storage.go b/modules/setting/storage.go index 23b08df101..f4e33a53af 100644 --- a/modules/setting/storage.go +++ b/modules/setting/storage.go @@ -240,7 +240,7 @@ func getStorageForLocal(targetSec, overrideSec ConfigSection, tp targetSecType, } } - fatalDuplicatedPath("storage."+name, storage.Path) + checkOverlappedPath("storage."+name+".PATH", storage.Path) return &storage, nil } diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index b7bcf20d30..39b9855186 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2775,6 +2775,7 @@ teams.invite.by = Invited by %s teams.invite.description = Please click the button below to join the team. [admin] +maintenance = Maintenance dashboard = Dashboard self_check = Self Check identity_access = Identity & Access @@ -2798,7 +2799,7 @@ settings = Admin Settings dashboard.new_version_hint = Gitea %s is now available, you are running %s. Check <a target="_blank" rel="noreferrer" href="https://blog.gitea.io">the blog</a> for more details. dashboard.statistic = Summary -dashboard.operations = Maintenance Operations +dashboard.maintenance_operations = Maintenance Operations dashboard.system_status = System Status dashboard.operation_name = Operation Name dashboard.operation_switch = Switch @@ -3305,6 +3306,7 @@ notices.op = Op. notices.delete_success = The system notices have been deleted. self_check.no_problem_found = No problem found yet. +self_check.startup_warnings = Startup warnings: self_check.database_collation_mismatch = Expect database to use collation: %s self_check.database_collation_case_insensitive = Database is using a collation %s, which is an insensitive collation. Although Gitea could work with it, there might be some rare cases which don't work as expected. self_check.database_inconsistent_collation_columns = Database is using collation %s, but these columns are using mismatched collations. It might cause some unexpected problems. diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go index f3f10fd1b8..4dc0dfdef8 100644 --- a/routers/web/admin/admin.go +++ b/routers/web/admin/admin.go @@ -190,6 +190,14 @@ func DashboardPost(ctx *context.Context) { func SelfCheck(ctx *context.Context) { ctx.Data["PageIsAdminSelfCheck"] = true + + ctx.Data["DeprecatedWarnings"] = setting.DeprecatedWarnings + if len(setting.DeprecatedWarnings) == 0 && !setting.IsProd { + if time.Now().Unix()%2 == 0 { + ctx.Data["DeprecatedWarnings"] = []string{"This is a test warning message in dev mode"} + } + } + r, err := db.CheckCollationsDefaultEngine() if err != nil { ctx.Flash.Error(fmt.Sprintf("CheckCollationsDefaultEngine: %v", err), true) diff --git a/templates/admin/dashboard.tmpl b/templates/admin/dashboard.tmpl index bfd2ee6670..589fc5048a 100644 --- a/templates/admin/dashboard.tmpl +++ b/templates/admin/dashboard.tmpl @@ -6,7 +6,7 @@ </div> {{end}} <h4 class="ui top attached header"> - {{ctx.Locale.Tr "admin.dashboard.operations"}} + {{ctx.Locale.Tr "admin.dashboard.maintenance_operations"}} </h4> <div class="ui attached table segment"> <form method="post" action="{{AppSubUrl}}/admin"> diff --git a/templates/admin/navbar.tmpl b/templates/admin/navbar.tmpl index d01a6ab964..1b3b9d6efc 100644 --- a/templates/admin/navbar.tmpl +++ b/templates/admin/navbar.tmpl @@ -1,12 +1,18 @@ <div class="flex-container-nav"> <div class="ui fluid vertical menu"> <div class="header item">{{ctx.Locale.Tr "admin.settings"}}</div> - <a class="{{if .PageIsAdminDashboard}}active {{end}}item" href="{{AppSubUrl}}/admin"> - {{ctx.Locale.Tr "admin.dashboard"}} - </a> - <a class="{{if .PageIsAdminSelfCheck}}active {{end}}item" href="{{AppSubUrl}}/admin/self_check"> - {{ctx.Locale.Tr "admin.self_check"}} - </a> + + <details class="item toggleable-item" {{if or .PageIsAdminDashboard .PageIsAdminSelfCheck}}open{{end}}> + <summary>{{ctx.Locale.Tr "admin.maintenance"}}</summary> + <div class="menu"> + <a class="{{if .PageIsAdminDashboard}}active {{end}}item" href="{{AppSubUrl}}/admin"> + {{ctx.Locale.Tr "admin.dashboard"}} + </a> + <a class="{{if .PageIsAdminSelfCheck}}active {{end}}item" href="{{AppSubUrl}}/admin/self_check"> + {{ctx.Locale.Tr "admin.self_check"}} + </a> + </div> + </details> <details class="item toggleable-item" {{if or .PageIsAdminUsers .PageIsAdminEmails .PageIsAdminOrganizations .PageIsAdminAuthentications}}open{{end}}> <summary>{{ctx.Locale.Tr "admin.identity_access"}}</summary> <div class="menu"> diff --git a/templates/admin/self_check.tmpl b/templates/admin/self_check.tmpl index 94c4673a49..c100ffd504 100644 --- a/templates/admin/self_check.tmpl +++ b/templates/admin/self_check.tmpl @@ -4,33 +4,47 @@ <h4 class="ui top attached header"> {{ctx.Locale.Tr "admin.self_check"}} </h4> + + {{if .DeprecatedWarnings}} <div class="ui attached segment"> - {{if .DatabaseCheckHasProblems}} - {{if .DatabaseType.IsMySQL}} - <div class="tw-p-2">{{ctx.Locale.Tr "admin.self_check.database_fix_mysql"}}</div> - {{else if .DatabaseType.IsMSSQL}} - <div class="tw-p-2">{{ctx.Locale.Tr "admin.self_check.database_fix_mssql"}}</div> - {{end}} - {{if .DatabaseCheckCollationMismatch}} - <div class="ui red message">{{ctx.Locale.Tr "admin.self_check.database_collation_mismatch" .DatabaseCheckResult.ExpectedCollation}}</div> - {{end}} - {{if .DatabaseCheckCollationCaseInsensitive}} - <div class="ui warning message">{{ctx.Locale.Tr "admin.self_check.database_collation_case_insensitive" .DatabaseCheckResult.DatabaseCollation}}</div> - {{end}} - {{if .DatabaseCheckInconsistentCollationColumns}} - <div class="ui red message"> - {{ctx.Locale.Tr "admin.self_check.database_inconsistent_collation_columns" .DatabaseCheckResult.DatabaseCollation}} - <ul class="tw-w-full"> - {{range .DatabaseCheckInconsistentCollationColumns}} - <li>{{.}}</li> - {{end}} - </ul> - </div> - {{end}} - {{else}} - <div class="tw-p-2">{{ctx.Locale.Tr "admin.self_check.no_problem_found"}}</div> + <div class="ui warning message"> + <div>{{ctx.Locale.Tr "admin.self_check.startup_warnings"}}</div> + <ul class="tw-w-full">{{range .DeprecatedWarnings}}<li>{{.}}</li>{{end}}</ul> + </div> + </div> + {{end}} + + {{if .DatabaseCheckHasProblems}} + <div class="ui attached segment"> + {{if .DatabaseType.IsMySQL}} + <div class="tw-p-2">{{ctx.Locale.Tr "admin.self_check.database_fix_mysql"}}</div> + {{else if .DatabaseType.IsMSSQL}} + <div class="tw-p-2">{{ctx.Locale.Tr "admin.self_check.database_fix_mssql"}}</div> + {{end}} + {{if .DatabaseCheckCollationMismatch}} + <div class="ui red message">{{ctx.Locale.Tr "admin.self_check.database_collation_mismatch" .DatabaseCheckResult.ExpectedCollation}}</div> + {{end}} + {{if .DatabaseCheckCollationCaseInsensitive}} + <div class="ui warning message">{{ctx.Locale.Tr "admin.self_check.database_collation_case_insensitive" .DatabaseCheckResult.DatabaseCollation}}</div> + {{end}} + {{if .DatabaseCheckInconsistentCollationColumns}} + <div class="ui red message"> + {{ctx.Locale.Tr "admin.self_check.database_inconsistent_collation_columns" .DatabaseCheckResult.DatabaseCollation}} + <ul class="tw-w-full"> + {{range .DatabaseCheckInconsistentCollationColumns}} + <li>{{.}}</li> + {{end}} + </ul> + </div> {{end}} </div> + {{end}} + + {{if and (not .DeprecatedWarnings) (not .DatabaseCheckHasProblems)}} + <div class="ui attached segment"> + {{ctx.Locale.Tr "admin.self_check.no_problem_found"}} + </div> + {{end}} </div> {{template "admin/layout_footer" .}} From ab028356c7f4f29adb99505c078c162a317c7c37 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sun, 31 Mar 2024 19:17:34 +0800 Subject: [PATCH 011/370] Fix markdown color code detection (#30208) When reviewing PRs, some color names might be mentioned, the `transformCodeSpan` (which calls `css.ColorHandler`) considered it as a valid color, but actually it shouldn't be rendered as a color codespan. --- modules/markup/markdown/markdown_test.go | 8 +++++-- modules/markup/markdown/transform_codespan.go | 21 ++++++++++++++++++- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index ebac3fbe9e..c664758a27 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -436,6 +436,10 @@ func TestColorPreview(t *testing.T) { testcase string expected string }{ + { // do not render color names + "The CSS class `red` is there", + "<p>The CSS class <code>red</code> is there</p>\n", + }, { // hex "`#FF0000`", `<p><code>#FF0000<span class="color-preview" style="background-color: #FF0000"></span></code></p>` + nl, @@ -445,8 +449,8 @@ func TestColorPreview(t *testing.T) { `<p><code>rgb(16, 32, 64)<span class="color-preview" style="background-color: rgb(16, 32, 64)"></span></code></p>` + nl, }, { // short hex - "This is the color white `#000`", - `<p>This is the color white <code>#000<span class="color-preview" style="background-color: #000"></span></code></p>` + nl, + "This is the color white `#0a0`", + `<p>This is the color white <code>#0a0<span class="color-preview" style="background-color: #0a0"></span></code></p>` + nl, }, { // hsl "HSL stands for hue, saturation, and lightness. An example: `hsl(0, 100%, 50%)`.", diff --git a/modules/markup/markdown/transform_codespan.go b/modules/markup/markdown/transform_codespan.go index bfff2897b0..5b07d72999 100644 --- a/modules/markup/markdown/transform_codespan.go +++ b/modules/markup/markdown/transform_codespan.go @@ -49,9 +49,28 @@ func (r *HTMLRenderer) renderCodeSpan(w util.BufWriter, source []byte, n ast.Nod return ast.WalkContinue, nil } +// cssColorHandler checks if a string is a render-able CSS color value. +// The code is from "github.com/microcosm-cc/bluemonday/css.ColorHandler", except that it doesn't handle color words like "red". +func cssColorHandler(value string) bool { + value = strings.ToLower(value) + if css.HexRGB.MatchString(value) { + return true + } + if css.RGB.MatchString(value) { + return true + } + if css.RGBA.MatchString(value) { + return true + } + if css.HSL.MatchString(value) { + return true + } + return css.HSLA.MatchString(value) +} + func (g *ASTTransformer) transformCodeSpan(ctx *markup.RenderContext, v *ast.CodeSpan, reader text.Reader) { colorContent := v.Text(reader.Source()) - if css.ColorHandler(strings.ToLower(string(colorContent))) { + if cssColorHandler(string(colorContent)) { v.AppendChild(v, NewColorPreview(colorContent)) } } From 44dd6d6927180a4d36b3811fd2fb7557d0b44adb Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 31 Mar 2024 13:22:28 +0200 Subject: [PATCH 012/370] Move and simplify tab-size helpers (#30196) Tailwind does not support. Dropped the vendor-prefix. Co-authored-by: Giteabot <teabot@gitea.io> --- web_src/css/helpers.css | 17 +++++++++ web_src/css/repo.css | 80 ----------------------------------------- 2 files changed, 17 insertions(+), 80 deletions(-) diff --git a/web_src/css/helpers.css b/web_src/css/helpers.css index 13962f19d7..118c058b19 100644 --- a/web_src/css/helpers.css +++ b/web_src/css/helpers.css @@ -63,3 +63,20 @@ only use: display: none !important; } } + +.tab-size-1 { tab-size: 1 !important; } +.tab-size-2 { tab-size: 2 !important; } +.tab-size-3 { tab-size: 3 !important; } +.tab-size-4 { tab-size: 4 !important; } +.tab-size-5 { tab-size: 5 !important; } +.tab-size-6 { tab-size: 6 !important; } +.tab-size-7 { tab-size: 7 !important; } +.tab-size-8 { tab-size: 8 !important; } +.tab-size-9 { tab-size: 9 !important; } +.tab-size-10 { tab-size: 10 !important; } +.tab-size-11 { tab-size: 11 !important; } +.tab-size-12 { tab-size: 12 !important; } +.tab-size-13 { tab-size: 13 !important; } +.tab-size-14 { tab-size: 14 !important; } +.tab-size-15 { tab-size: 15 !important; } +.tab-size-16 { tab-size: 16 !important; } diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 780093fb7f..eab90c10d3 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -2260,86 +2260,6 @@ padding-top: 15px; } -.tab-size-1 { - tab-size: 1 !important; - -moz-tab-size: 1 !important; -} - -.tab-size-2 { - tab-size: 2 !important; - -moz-tab-size: 2 !important; -} - -.tab-size-3 { - tab-size: 3 !important; - -moz-tab-size: 3 !important; -} - -.tab-size-4 { - tab-size: 4 !important; - -moz-tab-size: 4 !important; -} - -.tab-size-5 { - tab-size: 5 !important; - -moz-tab-size: 5 !important; -} - -.tab-size-6 { - tab-size: 6 !important; - -moz-tab-size: 6 !important; -} - -.tab-size-7 { - tab-size: 7 !important; - -moz-tab-size: 7 !important; -} - -.tab-size-8 { - tab-size: 8 !important; - -moz-tab-size: 8 !important; -} - -.tab-size-9 { - tab-size: 9 !important; - -moz-tab-size: 9 !important; -} - -.tab-size-10 { - tab-size: 10 !important; - -moz-tab-size: 10 !important; -} - -.tab-size-11 { - tab-size: 11 !important; - -moz-tab-size: 11 !important; -} - -.tab-size-12 { - tab-size: 12 !important; - -moz-tab-size: 12 !important; -} - -.tab-size-13 { - tab-size: 13 !important; - -moz-tab-size: 13 !important; -} - -.tab-size-14 { - tab-size: 14 !important; - -moz-tab-size: 14 !important; -} - -.tab-size-15 { - tab-size: 15 !important; - -moz-tab-size: 15 !important; -} - -.tab-size-16 { - tab-size: 16 !important; - -moz-tab-size: 16 !important; -} - .stats-table { display: table; width: 100%; From f8fbaaf26fa7798fde690f4400910069fbccd40e Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Sun, 31 Mar 2024 14:27:39 +0300 Subject: [PATCH 013/370] Make a distinction between `active` and `selected` in the issue author dropdown (#30207) Signed-off-by: Yarden Shoham <git@yardenshoham.com> --- web_src/js/features/repo-issue-list.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web_src/js/features/repo-issue-list.js b/web_src/js/features/repo-issue-list.js index ccd13bbcf5..92f058c4d2 100644 --- a/web_src/js/features/repo-issue-list.js +++ b/web_src/js/features/repo-issue-list.js @@ -149,7 +149,9 @@ function initRepoIssueListAuthorDropdown() { $searchDropdown.dropdown('refresh'); // defer our selection to the next tick, because dropdown will set the selection item after this `menu` function setTimeout(() => { - menu.querySelector('.item.active, .item.selected')?.classList.remove('active', 'selected'); + for (const el of menu.querySelectorAll('.item.active, .item.selected')) { + el.classList.remove('active', 'selected'); + } menu.querySelector(`.item[data-value="${selectedUserId}"]`)?.classList.add('selected'); }, 0); }; From f691721714cba2a1a11e69c2b3da323b031620ff Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 31 Mar 2024 13:35:11 +0200 Subject: [PATCH 014/370] Remove `modifies/frontend` from labeler (#30198) Remove this label, I find it barely useful and we already have more useful labels like `modifies/js`. Backport so that we can eventually delete that label. Co-authored-by: Giteabot <teabot@gitea.io> --- .github/labeler.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/labeler.yml b/.github/labeler.yml index 4acdb6f6f5..d1b4d00d80 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -4,13 +4,6 @@ modifies/docs: - "**/*.md" - "docs/**" -modifies/frontend: - - changed-files: - - any-glob-to-any-file: - - "web_src/**" - - "tailwind.config.js" - - "webpack.config.js" - modifies/templates: - changed-files: - all-globs-to-any-file: From 38d56ca10600bdb867b363be717f7cf5d176297a Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 31 Mar 2024 13:41:28 +0200 Subject: [PATCH 015/370] Ignore fomantic folder in linters (#30200) We are not linting these files but editor integrations will still try to lint, disable that. --- .eslintrc.yaml | 1 + stylelint.config.js | 1 + 2 files changed, 2 insertions(+) diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 99ce2e97d6..43edd14cec 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -3,6 +3,7 @@ reportUnusedDisableDirectives: true ignorePatterns: - /web_src/js/vendor + - /web_src/fomantic parserOptions: sourceType: module diff --git a/stylelint.config.js b/stylelint.config.js index c34181233e..523b18841e 100644 --- a/stylelint.config.js +++ b/stylelint.config.js @@ -16,6 +16,7 @@ export default { ], ignoreFiles: [ '**/*.go', + '/web_src/fomantic', ], overrides: [ { From ef5892d988f71743c7f5446bc6ce69cb4384455b Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Sun, 31 Mar 2024 15:01:21 +0300 Subject: [PATCH 016/370] Remove jQuery class from the `repo-issue.js` file (#30192) Switched from jQuery class functions to plain JavaScript `classList`. Tested the following functionalities and they work as before: - delete issue comment - cancel code comment - update (merge or rebase) pull request - re-request review - reply to code comment - show/hide outdated comments - add code comment - edit issue title --------- Signed-off-by: Yarden Shoham <git@yardenshoham.com> Co-authored-by: silverwind <me@silverwind.io> --- web_src/js/features/repo-issue.js | 155 ++++++++++++++++-------------- 1 file changed, 85 insertions(+), 70 deletions(-) diff --git a/web_src/js/features/repo-issue.js b/web_src/js/features/repo-issue.js index bb45c6ae57..0d326aae58 100644 --- a/web_src/js/features/repo-issue.js +++ b/web_src/js/features/repo-issue.js @@ -158,17 +158,22 @@ export function initRepoIssueSidebarList() { export function initRepoIssueCommentDelete() { // Delete comment - $(document).on('click', '.delete-comment', async function () { - const $this = $(this); - if (window.confirm($this.data('locale'))) { + document.addEventListener('click', async (e) => { + if (!e.target.matches('.delete-comment')) return; + e.preventDefault(); + + const deleteButton = e.target; + if (window.confirm(deleteButton.getAttribute('data-locale'))) { try { - const response = await POST($this.data('url')); + const response = await POST(deleteButton.getAttribute('data-url')); if (!response.ok) throw new Error('Failed to delete comment'); - const $conversationHolder = $this.closest('.conversation-holder'); - const $parentTimelineItem = $this.closest('.timeline-item'); - const $parentTimelineGroup = $this.closest('.timeline-item-group'); + + const conversationHolder = deleteButton.closest('.conversation-holder'); + const parentTimelineItem = deleteButton.closest('.timeline-item'); + const parentTimelineGroup = deleteButton.closest('.timeline-item-group'); + // Check if this was a pending comment. - if ($conversationHolder.find('.pending-label').length) { + if (conversationHolder?.querySelector('.pending-label')) { const counter = document.querySelector('#review-box .review-comments-counter'); let num = parseInt(counter?.getAttribute('data-pending-comment-number')) - 1 || 0; num = Math.max(num, 0); @@ -176,29 +181,32 @@ export function initRepoIssueCommentDelete() { counter.textContent = String(num); } - $(`#${$this.data('comment-id')}`).remove(); - if ($conversationHolder.length && !$conversationHolder.find('.comment').length) { - const path = $conversationHolder.data('path'); - const side = $conversationHolder.data('side'); - const idx = $conversationHolder.data('idx'); - const lineType = $conversationHolder.closest('tr').data('line-type'); + document.getElementById(deleteButton.getAttribute('data-comment-id'))?.remove(); + + if (conversationHolder && !conversationHolder.querySelector('.comment')) { + const path = conversationHolder.getAttribute('data-path'); + const side = conversationHolder.getAttribute('data-side'); + const idx = conversationHolder.getAttribute('data-idx'); + const lineType = conversationHolder.closest('tr').getAttribute('data-line-type'); + if (lineType === 'same') { - $(`[data-path="${path}"] .add-code-comment[data-idx="${idx}"]`).removeClass('tw-invisible'); + document.querySelector(`[data-path="${path}"] .add-code-comment[data-idx="${idx}"]`).classList.remove('tw-invisible'); } else { - $(`[data-path="${path}"] .add-code-comment[data-side="${side}"][data-idx="${idx}"]`).removeClass('tw-invisible'); + document.querySelector(`[data-path="${path}"] .add-code-comment[data-side="${side}"][data-idx="${idx}"]`).classList.remove('tw-invisible'); } - $conversationHolder.remove(); + + conversationHolder.remove(); } + // Check if there is no review content, move the time avatar upward to avoid overlapping the content below. - if (!$parentTimelineGroup.find('.timeline-item.comment').length && !$parentTimelineItem.find('.conversation-holder').length) { - const $timelineAvatar = $parentTimelineGroup.find('.timeline-avatar'); - $timelineAvatar.removeClass('timeline-avatar-offset'); + if (!parentTimelineGroup?.querySelector('.timeline-item.comment') && !parentTimelineItem?.querySelector('.conversation-holder')) { + const timelineAvatar = parentTimelineGroup?.querySelector('.timeline-avatar'); + timelineAvatar?.classList.remove('timeline-avatar-offset'); } } catch (error) { console.error(error); } } - return false; }); } @@ -222,32 +230,35 @@ export function initRepoIssueDependencyDelete() { export function initRepoIssueCodeCommentCancel() { // Cancel inline code comment - $(document).on('click', '.cancel-code-comment', (e) => { - const $form = $(e.currentTarget).closest('form'); - if ($form.length > 0 && $form.hasClass('comment-form')) { - $form.addClass('tw-hidden'); - showElem($form.closest('.comment-code-cloud').find('button.comment-form-reply')); + document.addEventListener('click', (e) => { + if (!e.target.matches('.cancel-code-comment')) return; + + const form = e.target.closest('form'); + if (form?.classList.contains('comment-form')) { + hideElem(form); + showElem(form.closest('.comment-code-cloud')?.querySelectorAll('button.comment-form-reply')); } else { - $form.closest('.comment-code-cloud').remove(); + form.closest('.comment-code-cloud')?.remove(); } }); } export function initRepoPullRequestUpdate() { // Pull Request update button - const $pullUpdateButton = $('.update-button > button'); - $pullUpdateButton.on('click', async function (e) { + const pullUpdateButton = document.querySelector('.update-button > button'); + if (!pullUpdateButton) return; + + pullUpdateButton.addEventListener('click', async function (e) { e.preventDefault(); - const $this = $(this); - const redirect = $this.data('redirect'); - $this.addClass('is-loading'); + const redirect = this.getAttribute('data-redirect'); + this.classList.add('is-loading'); let response; try { - response = await POST($this.data('do')); + response = await POST(this.getAttribute('data-do')); } catch (error) { console.error(error); } finally { - $this.removeClass('is-loading'); + this.classList.remove('is-loading'); } let data; try { @@ -266,10 +277,13 @@ export function initRepoPullRequestUpdate() { $('.update-button > .dropdown').dropdown({ onChange(_text, _value, $choice) { - const $url = $choice.data('do'); - if ($url) { - $pullUpdateButton.find('.button-text').text($choice.text()); - $pullUpdateButton.data('do', $url); + const url = $choice[0].getAttribute('data-do'); + if (url) { + const buttonText = pullUpdateButton.querySelector('.button-text'); + if (buttonText) { + buttonText.textContent = $choice.text(); + } + pullUpdateButton.setAttribute('data-do', url); } }, }); @@ -367,10 +381,10 @@ export function initRepoIssueComments() { $('.re-request-review').on('click', async function (e) { e.preventDefault(); - const url = $(this).data('update-url'); - const issueId = $(this).data('issue-id'); - const id = $(this).data('id'); - const isChecked = $(this).hasClass('checked'); + const url = this.getAttribute('data-update-url'); + const issueId = this.getAttribute('data-issue-id'); + const id = this.getAttribute('data-id'); + const isChecked = this.classList.contains('checked'); await updateIssuesMeta(url, isChecked ? 'detach' : 'attach', issueId, id); window.location.reload(); @@ -397,7 +411,7 @@ export function initRepoIssueComments() { export async function handleReply($el) { hideElem($el); const $form = $el.closest('.comment-code-cloud').find('.comment-form'); - $form.removeClass('tw-hidden'); + showElem($form); const $textarea = $form.find('textarea'); let editor = getComboMarkdownEditor($textarea); @@ -454,20 +468,20 @@ export function initRepoPullRequestReview() { $(document).on('click', '.show-outdated', function (e) { e.preventDefault(); - const id = $(this).data('comment'); - $(this).addClass('tw-hidden'); - $(`#code-comments-${id}`).removeClass('tw-hidden'); - $(`#code-preview-${id}`).removeClass('tw-hidden'); - $(`#hide-outdated-${id}`).removeClass('tw-hidden'); + const id = this.getAttribute('data-comment'); + hideElem(this); + showElem(`#code-comments-${id}`); + showElem(`#code-preview-${id}`); + showElem(`#hide-outdated-${id}`); }); $(document).on('click', '.hide-outdated', function (e) { e.preventDefault(); - const id = $(this).data('comment'); - $(this).addClass('tw-hidden'); - $(`#code-comments-${id}`).addClass('tw-hidden'); - $(`#code-preview-${id}`).addClass('tw-hidden'); - $(`#show-outdated-${id}`).removeClass('tw-hidden'); + const id = this.getAttribute('data-comment'); + hideElem(this); + hideElem(`#code-comments-${id}`); + hideElem(`#code-preview-${id}`); + showElem(`#show-outdated-${id}`); }); $(document).on('click', 'button.comment-form-reply', async function (e) { @@ -504,18 +518,19 @@ export function initRepoPullRequestReview() { } $(document).on('click', '.add-code-comment', async function (e) { - if ($(e.target).hasClass('btn-add-single')) return; // https://github.com/go-gitea/gitea/issues/4745 + if (e.target.classList.contains('btn-add-single')) return; // https://github.com/go-gitea/gitea/issues/4745 e.preventDefault(); - const isSplit = $(this).closest('.code-diff').hasClass('code-diff-split'); - const side = $(this).data('side'); - const idx = $(this).data('idx'); - const path = $(this).closest('[data-path]').data('path'); - const $tr = $(this).closest('tr'); - const lineType = $tr.data('line-type'); + const isSplit = this.closest('.code-diff')?.classList.contains('code-diff-split'); + const side = this.getAttribute('data-side'); + const idx = this.getAttribute('data-idx'); + const path = this.closest('[data-path]')?.getAttribute('data-path'); + const tr = this.closest('tr'); + const lineType = tr.getAttribute('data-line-type'); - let $ntr = $tr.next(); - if (!$ntr.hasClass('add-comment')) { + const ntr = tr.nextElementSibling; + let $ntr = $(ntr); + if (!ntr?.classList.contains('add-comment')) { $ntr = $(` <tr class="add-comment" data-line-type="${lineType}"> ${isSplit ? ` @@ -525,7 +540,7 @@ export function initRepoPullRequestReview() { <td class="add-comment-left add-comment-right" colspan="5"></td> `} </tr>`); - $tr.after($ntr); + $(tr).after($ntr); } const $td = $ntr.find(`.add-comment-${side}`); @@ -611,13 +626,13 @@ export function initRepoIssueTitleEdit() { const editTitleToggle = function () { toggleElem($issueTitle); - toggleElem($('.not-in-edit')); - toggleElem($('#edit-title-input')); - toggleElem($('#pull-desc')); - toggleElem($('#pull-desc-edit')); - toggleElem($('.in-edit')); - toggleElem($('.new-issue-button')); - $('#issue-title-wrapper').toggleClass('edit-active'); + toggleElem('.not-in-edit'); + toggleElem('#edit-title-input'); + toggleElem('#pull-desc'); + toggleElem('#pull-desc-edit'); + toggleElem('.in-edit'); + toggleElem('.new-issue-button'); + document.getElementById('issue-title-wrapper')?.classList.toggle('edit-active'); $editInput[0].focus(); $editInput[0].select(); return false; From 8da9130c1ffe93e0e97290fddb908ae5b67432e2 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 31 Mar 2024 16:58:55 +0200 Subject: [PATCH 017/370] Prevent flash of dropdown menu on labels list (#30215) On the labels list, This `left` class caused the dropdown content to flash on page load until JS had hidden it. Remove it as I see no purpose to it. <img width="215" alt="image" src="https://github.com/go-gitea/gitea/assets/115237/9e1de97f-dd89-41e0-9229-5c4a786ba762"> --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> --- templates/repo/issue/labels/label_list.tmpl | 2 +- web_src/css/modules/header.css | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/templates/repo/issue/labels/label_list.tmpl b/templates/repo/issue/labels/label_list.tmpl index d84f14242a..8d7fc2c3db 100644 --- a/templates/repo/issue/labels/label_list.tmpl +++ b/templates/repo/issue/labels/label_list.tmpl @@ -8,7 +8,7 @@ {{ctx.Locale.Tr "repo.issues.filter_sort"}} </span> {{svg "octicon-triangle-down" 14 "dropdown icon"}} - <div class="left menu"> + <div class="menu"> <a class="{{if or (eq .SortType "alphabetically") (not .SortType)}}active {{end}}item" href="?sort=alphabetically&state={{$.State}}">{{ctx.Locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a> <a class="{{if eq .SortType "reversealphabetically"}}active {{end}}item" href="?sort=reversealphabetically&state={{$.State}}">{{ctx.Locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a> <a class="{{if eq .SortType "leastissues"}}active {{end}}item" href="?sort=leastissues&state={{$.State}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.least_issues"}}</a> diff --git a/web_src/css/modules/header.css b/web_src/css/modules/header.css index 091d536cfc..05381e1185 100644 --- a/web_src/css/modules/header.css +++ b/web_src/css/modules/header.css @@ -135,6 +135,12 @@ h4.ui.header .sub.header { font-weight: var(--font-weight-normal); } +/* open dropdown menus to the left in right-attached headers */ +.ui.attached.header > .ui.right .ui.dropdown .menu { + right: 0; + left: auto; +} + /* if a .top.attached.header is followed by a .segment, add some margin */ .ui.segments + .ui.top.attached.header, .ui.attached.segment + .ui.top.attached.header { From 0497b2607d1052e771af4017c2c4180adb7d86b2 Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Sun, 31 Mar 2024 18:39:50 +0300 Subject: [PATCH 018/370] Remove most jQuery function calls from the repository topic box (#30191) Remove most jQuery function calls --------- Signed-off-by: Yarden Shoham <git@yardenshoham.com> Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> --- templates/repo/home.tmpl | 23 ++++----- web_src/css/repo.css | 1 + web_src/js/features/repo-home.js | 86 ++++++++++---------------------- web_src/js/modules/toast.js | 1 + web_src/js/utils/dom.js | 18 ++++++- 5 files changed, 54 insertions(+), 75 deletions(-) diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 4241f77ead..ab37f7e318 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -18,22 +18,21 @@ </div> </form> </div> - <div class="tw-flex tw-items-center tw-flex-wrap tw-gap-1" id="repo-topics"> - {{range .Topics}}<a class="ui repo-topic large label topic tw-m-0" href="{{AppSubUrl}}/explore/repos?q={{.Name}}&topic=1">{{.Name}}</a>{{end}} + <div class="tw-flex tw-items-center tw-flex-wrap tw-gap-2 tw-my-2" id="repo-topics"> + {{/* it should match the code in issue-home.js */}} + {{range .Topics}}<a class="repo-topic ui large label" href="{{AppSubUrl}}/explore/repos?q={{.Name}}&topic=1">{{.Name}}</a>{{end}} {{if and .Permission.IsAdmin (not .Repository.IsArchived)}}<button id="manage_topic" class="btn interact-fg tw-text-12">{{ctx.Locale.Tr "repo.topic.manage_topics"}}</button>{{end}} </div> {{end}} {{if and .Permission.IsAdmin (not .Repository.IsArchived)}} - <div class="ui form tw-hidden tw-flex tw-flex-col tw-mt-4" id="topic_edit"> - <div class="field tw-flex-1 tw-mb-1"> - <div class="ui fluid multiple search selection dropdown tw-flex-wrap" data-text-count-prompt="{{ctx.Locale.Tr "repo.topic.count_prompt"}}" data-text-format-prompt="{{ctx.Locale.Tr "repo.topic.format_prompt"}}"> - <input type="hidden" name="topics" value="{{range $i, $v := .Topics}}{{.Name}}{{if Eval $i "+" 1 "<" (len $.Topics)}},{{end}}{{end}}"> - {{range .Topics}} - {{/* keey the same layout as Fomantic UI generated labels */}} - <a class="ui label transition visible tw-cursor-default tw-inline-block" data-value="{{.Name}}">{{.Name}}{{svg "octicon-x" 16 "delete icon"}}</a> - {{end}} - <div class="text"></div> - </div> + <div class="ui form tw-hidden tw-flex tw-gap-2 tw-my-2" id="topic_edit"> + <div class="ui fluid multiple search selection dropdown tw-flex-wrap tw-flex-1"> + <input type="hidden" name="topics" value="{{range $i, $v := .Topics}}{{.Name}}{{if Eval $i "+" 1 "<" (len $.Topics)}},{{end}}{{end}}"> + {{range .Topics}} + {{/* keep the same layout as Fomantic UI generated labels */}} + <a class="ui label transition visible tw-cursor-default tw-inline-block" data-value="{{.Name}}">{{.Name}}{{svg "octicon-x" 16 "delete icon"}}</a> + {{end}} + <div class="text"></div> </div> <div> <button class="ui basic button" id="cancel_topic_edit">{{ctx.Locale.Tr "cancel"}}</button> diff --git a/web_src/css/repo.css b/web_src/css/repo.css index eab90c10d3..705d652b54 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -2437,6 +2437,7 @@ tbody.commit-list { #repo-topics .repo-topic { font-weight: var(--font-weight-normal); cursor: pointer; + margin: 0; } #new-dependency-drop-list.ui.selection.dropdown { diff --git a/web_src/js/features/repo-home.js b/web_src/js/features/repo-home.js index e195c23c37..6a5bce8268 100644 --- a/web_src/js/features/repo-home.js +++ b/web_src/js/features/repo-home.js @@ -1,55 +1,53 @@ import $ from 'jquery'; import {stripTags} from '../utils.js'; -import {hideElem, showElem} from '../utils/dom.js'; +import {hideElem, queryElemChildren, showElem} from '../utils/dom.js'; import {POST} from '../modules/fetch.js'; +import {showErrorToast} from '../modules/toast.js'; const {appSubUrl} = window.config; export function initRepoTopicBar() { const mgrBtn = document.getElementById('manage_topic'); if (!mgrBtn) return; + const editDiv = document.getElementById('topic_edit'); const viewDiv = document.getElementById('repo-topics'); - const saveBtn = document.getElementById('save_topic'); - const topicDropdown = editDiv.querySelector('.dropdown'); - const $topicDropdown = $(topicDropdown); - const $topicForm = $(editDiv); - const $topicDropdownSearch = $topicDropdown.find('input.search'); - const topicPrompts = { - countPrompt: topicDropdown.getAttribute('data-text-count-prompt') ?? undefined, - formatPrompt: topicDropdown.getAttribute('data-text-format-prompt') ?? undefined, - }; + const topicDropdown = editDiv.querySelector('.ui.dropdown'); + let lastErrorToast; mgrBtn.addEventListener('click', () => { hideElem(viewDiv); showElem(editDiv); - $topicDropdownSearch.trigger('focus'); + topicDropdown.querySelector('input.search').focus(); }); - $('#cancel_topic_edit').on('click', () => { + document.querySelector('#cancel_topic_edit').addEventListener('click', () => { + lastErrorToast?.hideToast(); hideElem(editDiv); showElem(viewDiv); mgrBtn.focus(); }); - saveBtn.addEventListener('click', async () => { - const topics = $('input[name=topics]').val(); + document.getElementById('save_topic').addEventListener('click', async (e) => { + lastErrorToast?.hideToast(); + const topics = editDiv.querySelector('input[name=topics]').value; const data = new FormData(); data.append('topics', topics); - const response = await POST(saveBtn.getAttribute('data-link'), {data}); + const response = await POST(e.target.getAttribute('data-link'), {data}); if (response.ok) { const responseData = await response.json(); if (responseData.status === 'ok') { - $(viewDiv).children('.topic').remove(); + queryElemChildren(viewDiv, '.repo-topic', (el) => el.remove()); if (topics.length) { const topicArray = topics.split(','); topicArray.sort(); for (const topic of topicArray) { + // it should match the code in repo/home.tmpl const link = document.createElement('a'); - link.classList.add('ui', 'repo-topic', 'large', 'label', 'topic', 'tw-m-0'); + link.classList.add('repo-topic', 'ui', 'large', 'label'); link.href = `${appSubUrl}/explore/repos?q=${encodeURIComponent(topic)}&topic=1`; link.textContent = topic; mgrBtn.parentNode.insertBefore(link, mgrBtn); // insert all new topics before manage button @@ -59,27 +57,23 @@ export function initRepoTopicBar() { showElem(viewDiv); } } else if (response.status === 422) { + // how to test: input topic like " invalid topic " (with spaces), and select it from the list, then "Save" const responseData = await response.json(); + lastErrorToast = showErrorToast(responseData.message, {duration: 5000}); if (responseData.invalidTopics.length > 0) { - topicPrompts.formatPrompt = responseData.message; - const {invalidTopics} = responseData; - const $topicLabels = $topicDropdown.children('a.ui.label'); + const topicLabels = queryElemChildren(topicDropdown, 'a.ui.label'); for (const [index, value] of topics.split(',').entries()) { if (invalidTopics.includes(value)) { - $topicLabels.eq(index).removeClass('green').addClass('red'); + topicLabels[index].classList.remove('green'); + topicLabels[index].classList.add('red'); } } - } else { - topicPrompts.countPrompt = responseData.message; } } - - // Always validate the form - $topicForm.form('validate form'); }); - $topicDropdown.dropdown({ + $(topicDropdown).dropdown({ allowAdditions: true, forceSelection: false, fullTextSearch: 'exact', @@ -102,9 +96,9 @@ export function initRepoTopicBar() { const query = stripTags(this.urlData.query.trim()); let found_query = false; const current_topics = []; - $topicDropdown.find('a.label.visible').each((_, el) => { + for (const el of queryElemChildren(topicDropdown, 'a.ui.label.visible')) { current_topics.push(el.getAttribute('data-value')); - }); + } if (res.topics) { let found = false; @@ -146,38 +140,8 @@ export function initRepoTopicBar() { }, onAdd(addedValue, _addedText, $addedChoice) { addedValue = addedValue.toLowerCase().trim(); - $($addedChoice)[0].setAttribute('data-value', addedValue); - $($addedChoice)[0].setAttribute('data-text', addedValue); - }, - }); - - $.fn.form.settings.rules.validateTopic = function (_values, regExp) { - const $topics = $topicDropdown.children('a.ui.label'); - const status = !$topics.length || $topics.last()[0].getAttribute('data-value').match(regExp); - if (!status) { - $topics.last().removeClass('green').addClass('red'); - } - return status && !$topicDropdown.children('a.ui.label.red').length; - }; - - $topicForm.form({ - on: 'change', - inline: true, - fields: { - topics: { - identifier: 'topics', - rules: [ - { - type: 'validateTopic', - value: /^\s*[a-z0-9][-.a-z0-9]{0,35}\s*$/, - prompt: topicPrompts.formatPrompt, - }, - { - type: 'maxCount[25]', - prompt: topicPrompts.countPrompt, - }, - ], - }, + $addedChoice[0].setAttribute('data-value', addedValue); + $addedChoice[0].setAttribute('data-text', addedValue); }, }); } diff --git a/web_src/js/modules/toast.js b/web_src/js/modules/toast.js index d64359799c..d12d203718 100644 --- a/web_src/js/modules/toast.js +++ b/web_src/js/modules/toast.js @@ -39,6 +39,7 @@ function showToast(message, level, {gravity, position, duration, useHtmlBody, .. toast.showToast(); toast.toastElement.querySelector('.toast-close').addEventListener('click', () => toast.hideToast()); + return toast; } export function showInfoToast(message, opts) { diff --git a/web_src/js/utils/dom.js b/web_src/js/utils/dom.js index fffe9c6109..fb23a71725 100644 --- a/web_src/js/utils/dom.js +++ b/web_src/js/utils/dom.js @@ -51,8 +51,22 @@ export function isElemHidden(el) { return res[0]; } -export function queryElemSiblings(el, selector = '*') { - return Array.from(el.parentNode.children).filter((child) => child !== el && child.matches(selector)); +function applyElemsCallback(elems, fn) { + if (fn) { + for (const el of elems) { + fn(el); + } + } + return elems; +} + +export function queryElemSiblings(el, selector = '*', fn) { + return applyElemsCallback(Array.from(el.parentNode.children).filter((child) => child !== el && child.matches(selector)), fn); +} + +// it works like jQuery.children: only the direct children are selected +export function queryElemChildren(parent, selector = '*', fn) { + return applyElemsCallback(parent.querySelectorAll(`:scope > ${selector}`), fn); } export function onDomReady(cb) { From ff334749f58c71980ec19143bc21c0a799074b30 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 31 Mar 2024 18:06:06 +0200 Subject: [PATCH 019/370] Remove fomantic input module (#30194) Another pure CSS module. Some styling is part of the `form` module which will likely follow next. --- templates/devtest/gitea-ui.tmpl | 2 +- .../repo/issue/view_content/sidebar.tmpl | 2 +- web_src/css/base.css | 57 -- web_src/css/index.css | 1 + web_src/css/modules/animations.css | 8 +- web_src/css/modules/input.css | 192 +++++ web_src/fomantic/build/semantic.css | 744 ------------------ web_src/fomantic/semantic.json | 1 - web_src/js/components/DashboardRepoList.vue | 4 +- web_src/js/features/common-global.js | 4 +- web_src/js/features/copycontent.js | 4 +- 11 files changed, 207 insertions(+), 812 deletions(-) create mode 100644 web_src/css/modules/input.css diff --git a/templates/devtest/gitea-ui.tmpl b/templates/devtest/gitea-ui.tmpl index 76de4a93d7..bb4fc77a74 100644 --- a/templates/devtest/gitea-ui.tmpl +++ b/templates/devtest/gitea-ui.tmpl @@ -102,7 +102,7 @@ <div> <h1>Loading</h1> - <div class="is-loading small-loading-icon tw-border tw-border-secondary tw-py-1"><span>loading ...</span></div> + <div class="is-loading loading-icon-2px tw-border tw-border-secondary tw-py-1"><span>loading ...</span></div> <div class="is-loading tw-border tw-border-secondary tw-py-4"> <p>loading ...</p> <p>loading ...</p> diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index c917c78e68..7040c2849a 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -677,7 +677,7 @@ {{if and (not (eq .Issue.PullRequest.HeadRepo.FullName .Issue.PullRequest.BaseRepo.FullName)) .CanWriteToHeadRepo}} <div class="divider"></div> <div class="inline field"> - <div class="ui checkbox small-loading-icon" id="allow-edits-from-maintainers" + <div class="ui checkbox loading-icon-2px" id="allow-edits-from-maintainers" data-url="{{.Issue.Link}}" data-tooltip-content="{{ctx.Locale.Tr "repo.pulls.allow_edits_from_maintainers_desc"}}" data-prompt-error="{{ctx.Locale.Tr "repo.pulls.allow_edits_from_maintainers_err"}}" diff --git a/web_src/css/base.css b/web_src/css/base.css index cd0f883138..96c90ee692 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -305,12 +305,6 @@ a.label, background-color: var(--color-label-bg); } -/* fix Fomantic's line-height cutting off "g" on Windows Chrome with Segoe UI */ -.ui.input > input { - line-height: var(--line-height-default); - text-align: start; /* Override fomantic's `text-align: left` to make RTL work via HTML `dir="auto"` */ -} - /* fix Fomantic's line-height causing vertical scrollbars to appear */ ul.ui.list li, ol.ui.list li, @@ -319,47 +313,6 @@ ol.ui.list li, line-height: var(--line-height-default); } -.ui.input.focus > input, -.ui.input > input:focus { - border-color: var(--color-primary); -} - -.ui.action.input .ui.ui.button { - border-color: var(--color-input-border); - padding-top: 0; /* the ".action.input" is "flex + stretch", so let the buttons layout themselves */ - padding-bottom: 0; -} - -/* currently used for search bar dropdowns in repo search and explore code */ -.ui.action.input:not([class*="left action"]) > .ui.dropdown.selection { - min-width: 10em; -} -.ui.action.input:not([class*="left action"]) > .ui.dropdown.selection:not(:focus) { - border-right: none; -} -.ui.action.input:not([class*="left action"]) > .ui.dropdown.selection:not(.active):hover { - border-color: var(--color-input-border); -} -.ui.action.input:not([class*="left action"]) .ui.dropdown.selection.upward.visible { - border-bottom-left-radius: 0 !important; - border-bottom-right-radius: 0 !important; -} -.ui.action.input:not([class*="left action"]) > input, -.ui.action.input:not([class*="left action"]) > input:hover { - border-right: none; -} -.ui.action.input:not([class*="left action"]) > input:focus + .ui.dropdown.selection, -.ui.action.input:not([class*="left action"]) > input:focus + .ui.dropdown.selection:hover, -.ui.action.input:not([class*="left action"]) > input:focus + .button, -.ui.action.input:not([class*="left action"]) > input:focus + .button:hover, -.ui.action.input:not([class*="left action"]) > input:focus + .icon + .button, -.ui.action.input:not([class*="left action"]) > input:focus + .icon + .button:hover { - border-left-color: var(--color-primary); -} -.ui.action.input:not([class*="left action"]) > input:focus { - border-right-color: var(--color-primary); -} - .ui.menu { display: flex; } @@ -1599,16 +1552,6 @@ table th[data-sortt-desc] .svg { align-items: stretch; } -.ui.ui.icon.input .icon { - display: flex; - align-items: center; - justify-content: center; -} - -.ui.icon.input > i.icon { - transition: none; -} - .flex-items-block > .item, .flex-text-block { display: flex; diff --git a/web_src/css/index.css b/web_src/css/index.css index 373a84cf6a..40b1d3c881 100644 --- a/web_src/css/index.css +++ b/web_src/css/index.css @@ -6,6 +6,7 @@ @import "./modules/container.css"; @import "./modules/divider.css"; @import "./modules/header.css"; +@import "./modules/input.css"; @import "./modules/label.css"; @import "./modules/segment.css"; @import "./modules/grid.css"; diff --git a/web_src/css/modules/animations.css b/web_src/css/modules/animations.css index 0f78ad25cb..361618c449 100644 --- a/web_src/css/modules/animations.css +++ b/web_src/css/modules/animations.css @@ -34,10 +34,14 @@ border-radius: var(--border-radius-circle); } -.is-loading.small-loading-icon::after { +.is-loading.loading-icon-2px::after { border-width: 2px; } +.is-loading.loading-icon-3px::after { + border-width: 3px; +} + /* for single form button, the loading state should be on the button, but not go semi-transparent, just replace the text on the button with the loader. */ form.single-button-form.is-loading > * { opacity: 1; @@ -62,7 +66,7 @@ form.single-button-form.is-loading .button { background: transparent; } -/* TODO: not needed, use "is-loading small-loading-icon" instead */ +/* TODO: not needed, use "is-loading loading-icon-2px" instead */ code.language-math.is-loading::after { padding: 0; border-width: 2px; diff --git a/web_src/css/modules/input.css b/web_src/css/modules/input.css new file mode 100644 index 0000000000..48cd2fa9ff --- /dev/null +++ b/web_src/css/modules/input.css @@ -0,0 +1,192 @@ +/* based on Fomantic UI input module, with just the parts extracted that we use. If you find any + unused rules here after refactoring, please remove them. */ + +.ui.input { + position: relative; + font-weight: var(--font-weight-normal); + display: inline-flex; + color: var(--color-input-text); +} +.ui.input > input { + margin: 0; + max-width: 100%; + flex: 1 0 auto; + outline: none; + font-family: var(--fonts-regular); + padding: 0.67857143em 1em; + border: 1px solid var(--color-input-border); + color: var(--color-input-text); + border-radius: 0.28571429rem; + line-height: var(--line-height-default); + text-align: start; +} + +.ui.disabled.input, +.ui.input:not(.disabled) input[disabled] { + opacity: var(--opacity-disabled); +} +.ui.disabled.input > input, +.ui.input:not(.disabled) input[disabled] { + pointer-events: none; +} + +.ui.input.focus > input, +.ui.input > input:focus { + border-color: var(--color-primary); +} + +.ui.input.error > input { + background: var(--color-error-bg); + border-color: var(--color-error-border); + color: var(--color-error-text); +} + +.ui.icon.input > i.icon { + display: flex; + align-items: center; + justify-content: center; + cursor: default; + position: absolute; + text-align: center; + top: 50%; + transform: translateY(-50%); + opacity: 0.5; + border-radius: 0 0.28571429rem 0.28571429rem 0; + pointer-events: none; + padding: 4px; +} + +.ui.icon.input > i.icon.is-loading { + position: absolute !important; +} + +.ui.icon.input > i.icon.is-loading > * { + visibility: hidden; +} + +.ui.ui.ui.ui.icon.input > textarea, +.ui.ui.ui.ui.icon.input > input { + padding-right: 2.67142857em; +} +.ui.icon.input > i.link.icon { + cursor: pointer; +} +.ui.icon.input > i.circular.icon { + top: 0.35em; + right: 0.5em; +} + +.ui[class*="left icon"].input > i.icon { + right: auto; + left: 8px; + border-radius: 0.28571429rem 0 0 0.28571429rem; +} +.ui[class*="left icon"].input > i.circular.icon { + right: auto; + left: 0.5em; +} +.ui.ui.ui.ui[class*="left icon"].input > textarea, +.ui.ui.ui.ui[class*="left icon"].input > input { + padding-left: 2.67142857em; + padding-right: 1em; +} + +.ui.icon.input > textarea:focus ~ .icon, +.ui.icon.input > input:focus ~ .icon { + opacity: 1; +} + +.ui.icon.input > textarea ~ i.icon { + height: 3em; +} + +.ui.form .field.error > .ui.action.input > .ui.button, +.ui.action.input.error > .ui.button { + border-top: 1px solid var(--color-error-border); + border-bottom: 1px solid var(--color-error-border); +} + +.ui.action.input > .button, +.ui.action.input > .buttons { + display: flex; + align-items: center; + flex: 0 0 auto; +} +.ui.action.input > .button, +.ui.action.input > .buttons > .button { + padding-top: 0.78571429em; + padding-bottom: 0.78571429em; + margin: 0; +} + +.ui.action.input:not([class*="left action"]) > input { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-right-color: transparent; +} + +.ui.action.input > .dropdown:first-child, +.ui.action.input > .button:first-child, +.ui.action.input > .buttons:first-child > .button { + border-radius: 0.28571429rem 0 0 0.28571429rem; +} +.ui.action.input > .dropdown:not(:first-child), +.ui.action.input > .button:not(:first-child), +.ui.action.input > .buttons:not(:first-child) > .button { + border-radius: 0; +} +.ui.action.input > .dropdown:last-child, +.ui.action.input > .button:last-child, +.ui.action.input > .buttons:last-child > .button { + border-radius: 0 0.28571429rem 0.28571429rem 0; +} + +.ui.fluid.input { + display: flex; +} +.ui.fluid.input > input { + width: 0 !important; +} + +.ui.tiny.input { + font-size: 0.85714286em; +} +.ui.small.input { + font-size: 0.92857143em; +} + +.ui.action.input .ui.ui.button { + border-color: var(--color-input-border); + padding-top: 0; /* the ".action.input" is "flex + stretch", so let the buttons layout themselves */ + padding-bottom: 0; +} + +/* currently used for search bar dropdowns in repo search and explore code */ +.ui.action.input:not([class*="left action"]) > .ui.dropdown.selection { + min-width: 10em; +} +.ui.action.input:not([class*="left action"]) > .ui.dropdown.selection:not(:focus) { + border-right: none; +} +.ui.action.input:not([class*="left action"]) > .ui.dropdown.selection:not(.active):hover { + border-color: var(--color-input-border); +} +.ui.action.input:not([class*="left action"]) .ui.dropdown.selection.upward.visible { + border-bottom-left-radius: 0 !important; + border-bottom-right-radius: 0 !important; +} +.ui.action.input:not([class*="left action"]) > input, +.ui.action.input:not([class*="left action"]) > input:hover { + border-right: none; +} +.ui.action.input:not([class*="left action"]) > input:focus + .ui.dropdown.selection, +.ui.action.input:not([class*="left action"]) > input:focus + .ui.dropdown.selection:hover, +.ui.action.input:not([class*="left action"]) > input:focus + .button, +.ui.action.input:not([class*="left action"]) > input:focus + .button:hover, +.ui.action.input:not([class*="left action"]) > input:focus + .icon + .button, +.ui.action.input:not([class*="left action"]) > input:focus + .icon + .button:hover { + border-left-color: var(--color-primary); +} +.ui.action.input:not([class*="left action"]) > input:focus { + border-right-color: var(--color-primary); +} diff --git a/web_src/fomantic/build/semantic.css b/web_src/fomantic/build/semantic.css index 525a3af8c6..5cb6a371e5 100644 --- a/web_src/fomantic/build/semantic.css +++ b/web_src/fomantic/build/semantic.css @@ -6474,750 +6474,6 @@ select.ui.dropdown { Theme Overrides *******************************/ -/******************************* - Site Overrides -*******************************/ -/*! - * # Fomantic-UI - Input - * http://github.com/fomantic/Fomantic-UI/ - * - * - * Released under the MIT license - * http://opensource.org/licenses/MIT - * - */ - -/******************************* - Standard -*******************************/ - -/*-------------------- - Inputs ----------------------*/ - -.ui.input { - position: relative; - font-weight: normal; - font-style: normal; - display: inline-flex; - color: rgba(0, 0, 0, 0.87); -} - -.ui.input > input { - margin: 0; - max-width: 100%; - flex: 1 0 auto; - outline: none; - -webkit-tap-highlight-color: rgba(255, 255, 255, 0); - text-align: left; - line-height: 1.21428571em; - font-family: var(--fonts-regular); - padding: 0.67857143em 1em; - background: #FFFFFF; - border: 1px solid rgba(34, 36, 38, 0.15); - color: rgba(0, 0, 0, 0.87); - border-radius: 0.28571429rem; - transition: box-shadow 0.1s ease, border-color 0.1s ease; - box-shadow: none; -} - -/*-------------------- - Placeholder ----------------------*/ - -/* browsers require these rules separate */ - -.ui.input > input::-webkit-input-placeholder { - color: rgba(191, 191, 191, 0.87); -} - -.ui.input > input::-moz-placeholder { - color: rgba(191, 191, 191, 0.87); -} - -.ui.input > input:-ms-input-placeholder { - color: rgba(191, 191, 191, 0.87); -} - -/******************************* - States -*******************************/ - -/*-------------------- - Disabled - ---------------------*/ - -.ui.disabled.input, -.ui.input:not(.disabled) input[disabled] { - opacity: var(--opacity-disabled); -} - -.ui.disabled.input > input, -.ui.input:not(.disabled) input[disabled] { - pointer-events: none; -} - -/*-------------------- - Active ----------------------*/ - -.ui.input > input:active, -.ui.input.down input { - border-color: rgba(0, 0, 0, 0.3); - background: #FAFAFA; - color: rgba(0, 0, 0, 0.87); - box-shadow: none; -} - -/*-------------------- - Loading - ---------------------*/ - -.ui.loading.loading.input > i.icon:before { - position: absolute; - content: ''; - top: 50%; - left: 50%; - margin: -0.64285714em 0 0 -0.64285714em; - width: 1.28571429em; - height: 1.28571429em; - border-radius: 500rem; - border: 0.2em solid rgba(0, 0, 0, 0.1); -} - -.ui.loading.loading.input > i.icon:after { - position: absolute; - content: ''; - top: 50%; - left: 50%; - margin: -0.64285714em 0 0 -0.64285714em; - width: 1.28571429em; - height: 1.28571429em; - animation: loader 0.6s infinite linear; - border: 0.2em solid #767676; - border-radius: 500rem; - box-shadow: 0 0 0 1px transparent; -} - -/*-------------------- - Focus ----------------------*/ - -.ui.input.focus > input, -.ui.input > input:focus { - border-color: #85B7D9; - background: #FFFFFF; - color: rgba(0, 0, 0, 0.8); - box-shadow: none; -} - -.ui.input.focus > input::-webkit-input-placeholder, -.ui.input > input:focus::-webkit-input-placeholder { - color: rgba(115, 115, 115, 0.87); -} - -.ui.input.focus > input::-moz-placeholder, -.ui.input > input:focus::-moz-placeholder { - color: rgba(115, 115, 115, 0.87); -} - -.ui.input.focus > input:-ms-input-placeholder, -.ui.input > input:focus:-ms-input-placeholder { - color: rgba(115, 115, 115, 0.87); -} - -/*-------------------- - States - ---------------------*/ - -.ui.input.error > input { - background-color: #FFF6F6; - border-color: #E0B4B4; - color: #9F3A38; - box-shadow: none; -} - -/* Placeholder */ - -.ui.input.error > input::-webkit-input-placeholder { - color: #e7bdbc; -} - -.ui.input.error > input::-moz-placeholder { - color: #e7bdbc; -} - -.ui.input.error > input:-ms-input-placeholder { - color: #e7bdbc !important; -} - -/* Focused Placeholder */ - -.ui.input.error > input:focus::-webkit-input-placeholder { - color: #da9796; -} - -.ui.input.error > input:focus::-moz-placeholder { - color: #da9796; -} - -.ui.input.error > input:focus:-ms-input-placeholder { - color: #da9796 !important; -} - -.ui.input.info > input { - background-color: #F8FFFF; - border-color: #A9D5DE; - color: #276F86; - box-shadow: none; -} - -/* Placeholder */ - -.ui.input.info > input::-webkit-input-placeholder { - color: #98cfe1; -} - -.ui.input.info > input::-moz-placeholder { - color: #98cfe1; -} - -.ui.input.info > input:-ms-input-placeholder { - color: #98cfe1 !important; -} - -/* Focused Placeholder */ - -.ui.input.info > input:focus::-webkit-input-placeholder { - color: #70bdd6; -} - -.ui.input.info > input:focus::-moz-placeholder { - color: #70bdd6; -} - -.ui.input.info > input:focus:-ms-input-placeholder { - color: #70bdd6 !important; -} - -.ui.input.success > input { - background-color: #FCFFF5; - border-color: #A3C293; - color: #2C662D; - box-shadow: none; -} - -/* Placeholder */ - -.ui.input.success > input::-webkit-input-placeholder { - color: #8fcf90; -} - -.ui.input.success > input::-moz-placeholder { - color: #8fcf90; -} - -.ui.input.success > input:-ms-input-placeholder { - color: #8fcf90 !important; -} - -/* Focused Placeholder */ - -.ui.input.success > input:focus::-webkit-input-placeholder { - color: #6cbf6d; -} - -.ui.input.success > input:focus::-moz-placeholder { - color: #6cbf6d; -} - -.ui.input.success > input:focus:-ms-input-placeholder { - color: #6cbf6d !important; -} - -.ui.input.warning > input { - background-color: #FFFAF3; - border-color: #C9BA9B; - color: #573A08; - box-shadow: none; -} - -/* Placeholder */ - -.ui.input.warning > input::-webkit-input-placeholder { - color: #edad3e; -} - -.ui.input.warning > input::-moz-placeholder { - color: #edad3e; -} - -.ui.input.warning > input:-ms-input-placeholder { - color: #edad3e !important; -} - -/* Focused Placeholder */ - -.ui.input.warning > input:focus::-webkit-input-placeholder { - color: #e39715; -} - -.ui.input.warning > input:focus::-moz-placeholder { - color: #e39715; -} - -.ui.input.warning > input:focus:-ms-input-placeholder { - color: #e39715 !important; -} - -/******************************* - Variations -*******************************/ - -/*-------------------- - Transparent - ---------------------*/ - -.ui.transparent.input > textarea, -.ui.transparent.input > input { - border-color: transparent !important; - background-color: transparent !important; - padding: 0; - box-shadow: none !important; - border-radius: 0 !important; -} - -.field .ui.transparent.input > textarea { - padding: 0.67857143em 1em; -} - -/* Transparent Icon */ - -:not(.field) > .ui.transparent.icon.input > i.icon { - width: 1.1em; -} - -:not(.field) > .ui.ui.ui.transparent.icon.input > input { - padding-left: 0; - padding-right: 2em; -} - -:not(.field) > .ui.ui.ui.transparent[class*="left icon"].input > input { - padding-left: 2em; - padding-right: 0; -} - -/*-------------------- - Icon - ---------------------*/ - -.ui.icon.input > i.icon { - cursor: default; - position: absolute; - line-height: 1; - text-align: center; - top: 0; - right: 0; - margin: 0; - height: 100%; - width: 2.67142857em; - opacity: 0.5; - border-radius: 0 0.28571429rem 0.28571429rem 0; - transition: opacity 0.3s ease; -} - -.ui.icon.input > i.icon:not(.link) { - pointer-events: none; -} - -.ui.ui.ui.ui.icon.input > textarea, -.ui.ui.ui.ui.icon.input > input { - padding-right: 2.67142857em; -} - -.ui.icon.input > i.icon:before, -.ui.icon.input > i.icon:after { - left: 0; - position: absolute; - text-align: center; - top: 50%; - width: 100%; - margin-top: -0.5em; -} - -.ui.icon.input > i.link.icon { - cursor: pointer; -} - -.ui.icon.input > i.circular.icon { - top: 0.35em; - right: 0.5em; -} - -/* Left Icon Input */ - -.ui[class*="left icon"].input > i.icon { - right: auto; - left: 1px; - border-radius: 0.28571429rem 0 0 0.28571429rem; -} - -.ui[class*="left icon"].input > i.circular.icon { - right: auto; - left: 0.5em; -} - -.ui.ui.ui.ui[class*="left icon"].input > textarea, -.ui.ui.ui.ui[class*="left icon"].input > input { - padding-left: 2.67142857em; - padding-right: 1em; -} - -/* Focus */ - -.ui.icon.input > textarea:focus ~ i.icon, -.ui.icon.input > input:focus ~ i.icon { - opacity: 1; -} - -/*-------------------- - Labeled - ---------------------*/ - -/* Adjacent Label */ - -.ui.labeled.input > .label { - flex: 0 0 auto; - margin: 0; - font-size: 1em; -} - -.ui.labeled.input > .label:not(.corner) { - padding-top: 0.78571429em; - padding-bottom: 0.78571429em; -} - -/* Regular Label on Left */ - -.ui.labeled.input:not([class*="corner labeled"]) .label:first-child { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} - -.ui.labeled.input:not([class*="corner labeled"]) .label:first-child + input { - border-top-left-radius: 0; - border-bottom-left-radius: 0; - border-left-color: transparent; -} - -.ui.labeled.input:not([class*="corner labeled"]) .label:first-child + input:focus { - border-left-color: #85B7D9; -} - -/* Regular Label on Right */ - -.ui[class*="right labeled"].input > input { - border-top-right-radius: 0 !important; - border-bottom-right-radius: 0 !important; - border-right-color: transparent !important; -} - -.ui[class*="right labeled"].input > input + .label { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} - -.ui[class*="right labeled"].input > input:focus { - border-right-color: #85B7D9 !important; -} - -/* Corner Label */ - -.ui.labeled.input .corner.label { - top: 1px; - right: 1px; - font-size: 0.64285714em; - border-radius: 0 0.28571429rem 0 0; -} - -/* Spacing with corner label */ - -.ui[class*="corner labeled"]:not([class*="left corner labeled"]).labeled.input > textarea, -.ui[class*="corner labeled"]:not([class*="left corner labeled"]).labeled.input > input { - padding-right: 2.5em !important; -} - -.ui[class*="corner labeled"].icon.input:not([class*="left corner labeled"]) > textarea, -.ui[class*="corner labeled"].icon.input:not([class*="left corner labeled"]) > input { - padding-right: 3.25em !important; -} - -.ui[class*="corner labeled"].icon.input:not([class*="left corner labeled"]) > i.icon { - margin-right: 1.25em; -} - -/* Left Labeled */ - -.ui[class*="left corner labeled"].labeled.input > textarea, -.ui[class*="left corner labeled"].labeled.input > input { - padding-left: 2.5em !important; -} - -.ui[class*="left corner labeled"].icon.input > textarea, -.ui[class*="left corner labeled"].icon.input > input { - padding-left: 3.25em !important; -} - -.ui[class*="left corner labeled"].icon.input > i.icon { - margin-left: 1.25em; -} - -.ui.icon.input > textarea ~ i.icon { - height: 3em; -} - -:not(.field) > .ui.transparent.icon.input > textarea ~ i.icon { - height: 1.3em; -} - -/* Corner Label Position */ - -.ui.input > .ui.corner.label { - top: 1px; - right: 1px; -} - -.ui.input > .ui.left.corner.label { - right: auto; - left: 1px; -} - -/* Labeled and action input states */ - -.ui.form .field.error > .ui.action.input > .ui.button, -.ui.form .field.error > .ui.labeled.input:not([class*="corner labeled"]) > .ui.label, -.ui.action.input.error > .ui.button, -.ui.labeled.input.error:not([class*="corner labeled"]) > .ui.label { - border-top: 1px solid #E0B4B4; - border-bottom: 1px solid #E0B4B4; -} - -.ui.form .field.error > .ui[class*="left action"].input > .ui.button, -.ui.form .field.error > .ui.labeled.input:not(.right):not([class*="corner labeled"]) > .ui.label, -.ui[class*="left action"].input.error > .ui.button, -.ui.labeled.input.error:not(.right):not([class*="corner labeled"]) > .ui.label { - border-left: 1px solid #E0B4B4; -} - -.ui.form .field.error > .ui.action.input:not([class*="left action"]) > input + .ui.button, -.ui.form .field.error > .ui.right.labeled.input:not([class*="corner labeled"]) > input + .ui.label, -.ui.action.input.error:not([class*="left action"]) > input + .ui.button, -.ui.right.labeled.input.error:not([class*="corner labeled"]) > input + .ui.label { - border-right: 1px solid #E0B4B4; -} - -.ui.form .field.error > .ui.right.labeled.input:not([class*="corner labeled"]) > .ui.label:first-child, -.ui.right.labeled.input.error:not([class*="corner labeled"]) > .ui.label:first-child { - border-left: 1px solid #E0B4B4; -} - -.ui.form .field.info > .ui.action.input > .ui.button, -.ui.form .field.info > .ui.labeled.input:not([class*="corner labeled"]) > .ui.label, -.ui.action.input.info > .ui.button, -.ui.labeled.input.info:not([class*="corner labeled"]) > .ui.label { - border-top: 1px solid #A9D5DE; - border-bottom: 1px solid #A9D5DE; -} - -.ui.form .field.info > .ui[class*="left action"].input > .ui.button, -.ui.form .field.info > .ui.labeled.input:not(.right):not([class*="corner labeled"]) > .ui.label, -.ui[class*="left action"].input.info > .ui.button, -.ui.labeled.input.info:not(.right):not([class*="corner labeled"]) > .ui.label { - border-left: 1px solid #A9D5DE; -} - -.ui.form .field.info > .ui.action.input:not([class*="left action"]) > input + .ui.button, -.ui.form .field.info > .ui.right.labeled.input:not([class*="corner labeled"]) > input + .ui.label, -.ui.action.input.info:not([class*="left action"]) > input + .ui.button, -.ui.right.labeled.input.info:not([class*="corner labeled"]) > input + .ui.label { - border-right: 1px solid #A9D5DE; -} - -.ui.form .field.info > .ui.right.labeled.input:not([class*="corner labeled"]) > .ui.label:first-child, -.ui.right.labeled.input.info:not([class*="corner labeled"]) > .ui.label:first-child { - border-left: 1px solid #A9D5DE; -} - -.ui.form .field.success > .ui.action.input > .ui.button, -.ui.form .field.success > .ui.labeled.input:not([class*="corner labeled"]) > .ui.label, -.ui.action.input.success > .ui.button, -.ui.labeled.input.success:not([class*="corner labeled"]) > .ui.label { - border-top: 1px solid #A3C293; - border-bottom: 1px solid #A3C293; -} - -.ui.form .field.success > .ui[class*="left action"].input > .ui.button, -.ui.form .field.success > .ui.labeled.input:not(.right):not([class*="corner labeled"]) > .ui.label, -.ui[class*="left action"].input.success > .ui.button, -.ui.labeled.input.success:not(.right):not([class*="corner labeled"]) > .ui.label { - border-left: 1px solid #A3C293; -} - -.ui.form .field.success > .ui.action.input:not([class*="left action"]) > input + .ui.button, -.ui.form .field.success > .ui.right.labeled.input:not([class*="corner labeled"]) > input + .ui.label, -.ui.action.input.success:not([class*="left action"]) > input + .ui.button, -.ui.right.labeled.input.success:not([class*="corner labeled"]) > input + .ui.label { - border-right: 1px solid #A3C293; -} - -.ui.form .field.success > .ui.right.labeled.input:not([class*="corner labeled"]) > .ui.label:first-child, -.ui.right.labeled.input.success:not([class*="corner labeled"]) > .ui.label:first-child { - border-left: 1px solid #A3C293; -} - -.ui.form .field.warning > .ui.action.input > .ui.button, -.ui.form .field.warning > .ui.labeled.input:not([class*="corner labeled"]) > .ui.label, -.ui.action.input.warning > .ui.button, -.ui.labeled.input.warning:not([class*="corner labeled"]) > .ui.label { - border-top: 1px solid #C9BA9B; - border-bottom: 1px solid #C9BA9B; -} - -.ui.form .field.warning > .ui[class*="left action"].input > .ui.button, -.ui.form .field.warning > .ui.labeled.input:not(.right):not([class*="corner labeled"]) > .ui.label, -.ui[class*="left action"].input.warning > .ui.button, -.ui.labeled.input.warning:not(.right):not([class*="corner labeled"]) > .ui.label { - border-left: 1px solid #C9BA9B; -} - -.ui.form .field.warning > .ui.action.input:not([class*="left action"]) > input + .ui.button, -.ui.form .field.warning > .ui.right.labeled.input:not([class*="corner labeled"]) > input + .ui.label, -.ui.action.input.warning:not([class*="left action"]) > input + .ui.button, -.ui.right.labeled.input.warning:not([class*="corner labeled"]) > input + .ui.label { - border-right: 1px solid #C9BA9B; -} - -.ui.form .field.warning > .ui.right.labeled.input:not([class*="corner labeled"]) > .ui.label:first-child, -.ui.right.labeled.input.warning:not([class*="corner labeled"]) > .ui.label:first-child { - border-left: 1px solid #C9BA9B; -} - -/*-------------------- - Action - ---------------------*/ - -.ui.action.input > .button, -.ui.action.input > .buttons { - display: flex; - align-items: center; - flex: 0 0 auto; -} - -.ui.action.input > .button, -.ui.action.input > .buttons > .button { - padding-top: 0.78571429em; - padding-bottom: 0.78571429em; - margin: 0; -} - -/* Input when ui Left*/ - -.ui[class*="left action"].input > input { - border-top-left-radius: 0; - border-bottom-left-radius: 0; - border-left-color: transparent; -} - -/* Input when ui Right*/ - -.ui.action.input:not([class*="left action"]) > input { - border-top-right-radius: 0; - border-bottom-right-radius: 0; - border-right-color: transparent; -} - -/* Button and Dropdown */ - -.ui.action.input > .dropdown:first-child, -.ui.action.input > .button:first-child, -.ui.action.input > .buttons:first-child > .button { - border-radius: 0.28571429rem 0 0 0.28571429rem; -} - -.ui.action.input > .dropdown:not(:first-child), -.ui.action.input > .button:not(:first-child), -.ui.action.input > .buttons:not(:first-child) > .button { - border-radius: 0; -} - -.ui.action.input > .dropdown:last-child, -.ui.action.input > .button:last-child, -.ui.action.input > .buttons:last-child > .button { - border-radius: 0 0.28571429rem 0.28571429rem 0; -} - -/* Input Focus */ - -.ui.action.input:not([class*="left action"]) > input:focus { - border-right-color: #85B7D9; -} - -.ui.ui[class*="left action"].input > input:focus { - border-left-color: #85B7D9; -} - -/*-------------------- - Fluid - ---------------------*/ - -.ui.fluid.input { - display: flex; -} - -.ui.fluid.input > input { - width: 0 !important; -} - -/*-------------------- - Size ----------------------*/ - -.ui.input { - font-size: 1em; -} - -.ui.mini.input { - font-size: 0.78571429em; -} - -.ui.tiny.input { - font-size: 0.85714286em; -} - -.ui.small.input { - font-size: 0.92857143em; -} - -.ui.large.input { - font-size: 1.14285714em; -} - -.ui.big.input { - font-size: 1.28571429em; -} - -.ui.huge.input { - font-size: 1.42857143em; -} - -.ui.massive.input { - font-size: 1.71428571em; -} - -/******************************* - Theme Overrides -*******************************/ - /******************************* Site Overrides *******************************/ diff --git a/web_src/fomantic/semantic.json b/web_src/fomantic/semantic.json index 151273f3ca..7ec520f315 100644 --- a/web_src/fomantic/semantic.json +++ b/web_src/fomantic/semantic.json @@ -26,7 +26,6 @@ "dimmer", "dropdown", "form", - "input", "list", "menu", "modal", diff --git a/web_src/js/components/DashboardRepoList.vue b/web_src/js/components/DashboardRepoList.vue index ffdcef2bc8..2d980a1b18 100644 --- a/web_src/js/components/DashboardRepoList.vue +++ b/web_src/js/components/DashboardRepoList.vue @@ -355,9 +355,9 @@ export default sfc; // activate the IDE's Vue plugin </a> </h4> <div class="ui attached segment repos-search"> - <div class="ui small fluid action left icon input" :class="{loading: isLoading}"> + <div class="ui small fluid action left icon input"> <input type="search" spellcheck="false" maxlength="255" @input="changeReposFilter(reposFilter)" v-model="searchQuery" ref="search" @keydown="reposFilterKeyControl" :placeholder="textSearchRepos"> - <i class="icon"><svg-icon name="octicon-search" :size="16"/></i> + <i class="icon loading-icon-3px" :class="{'is-loading': isLoading}"><svg-icon name="octicon-search" :size="16"/></i> <div class="ui dropdown icon button" :title="textFilter"> <svg-icon name="octicon-filter" :size="16"/> <div class="menu"> diff --git a/web_src/js/features/common-global.js b/web_src/js/features/common-global.js index 009dbd9421..e7db9b2336 100644 --- a/web_src/js/features/common-global.js +++ b/web_src/js/features/common-global.js @@ -109,7 +109,7 @@ async function fetchActionDoRequest(actionElem, url, opt) { showErrorToast(`${i18n.network_error} ${e}`); } } - actionElem.classList.remove('is-loading', 'small-loading-icon'); + actionElem.classList.remove('is-loading', 'loading-icon-2px'); } async function formFetchAction(e) { @@ -121,7 +121,7 @@ async function formFetchAction(e) { formEl.classList.add('is-loading'); if (formEl.clientHeight < 50) { - formEl.classList.add('small-loading-icon'); + formEl.classList.add('loading-icon-2px'); } const formMethod = formEl.getAttribute('method') || 'get'; diff --git a/web_src/js/features/copycontent.js b/web_src/js/features/copycontent.js index 3d3b2a697e..03efe00701 100644 --- a/web_src/js/features/copycontent.js +++ b/web_src/js/features/copycontent.js @@ -19,7 +19,7 @@ export function initCopyContent() { // the text to copy is not in the DOM or it is an image which should be // fetched to copy in full resolution if (link) { - btn.classList.add('is-loading', 'small-loading-icon'); + btn.classList.add('is-loading', 'loading-icon-2px'); try { const res = await GET(link, {credentials: 'include', redirect: 'follow'}); const contentType = res.headers.get('content-type'); @@ -33,7 +33,7 @@ export function initCopyContent() { } catch { return showTemporaryTooltip(btn, i18n.copy_error); } finally { - btn.classList.remove('is-loading', 'small-loading-icon'); + btn.classList.remove('is-loading', 'loading-icon-2px'); } } else { // text, read from DOM const lineEls = document.querySelectorAll('.file-view .lines-code'); From 934fa46f769f0b90fc319054612d4f5c9a4c46ba Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 31 Mar 2024 22:22:29 +0200 Subject: [PATCH 020/370] Add `/options/license` and `/options/gitignore` to `.ignore` (#30219) Ignore this folder in tools like `rg` or `ag`. Also sorted the entries alphabetically. --- .ignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.ignore b/.ignore index 5c945ab981..5b96dabd38 100644 --- a/.ignore +++ b/.ignore @@ -4,6 +4,8 @@ /modules/options/bindata.go /modules/public/bindata.go /modules/templates/bindata.go -/vendor +/options/gitignore +/options/license /public/assets +/vendor node_modules From 3607f827fb432378dbe7d90bdedbff4fd4565e13 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Mon, 1 Apr 2024 00:27:21 +0000 Subject: [PATCH 021/370] [skip ci] Updated licenses and gitignores --- options/license/AMD-newlib | 11 +++++++++++ options/license/OAR | 12 ++++++++++++ options/license/xzoom | 12 ++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 options/license/AMD-newlib create mode 100644 options/license/OAR create mode 100644 options/license/xzoom diff --git a/options/license/AMD-newlib b/options/license/AMD-newlib new file mode 100644 index 0000000000..1b2f1abd6f --- /dev/null +++ b/options/license/AMD-newlib @@ -0,0 +1,11 @@ +Copyright 1989, 1990 Advanced Micro Devices, Inc. + +This software is the property of Advanced Micro Devices, Inc (AMD) which +specifically grants the user the right to modify, use and distribute this +software provided this notice is not removed or altered. All other rights +are reserved by AMD. + +AMD MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH REGARD TO THIS +SOFTWARE. IN NO EVENT SHALL AMD BE LIABLE FOR INCIDENTAL OR CONSEQUENTIAL +DAMAGES IN CONNECTION WITH OR ARISING FROM THE FURNISHING, PERFORMANCE, OR +USE OF THIS SOFTWARE. diff --git a/options/license/OAR b/options/license/OAR new file mode 100644 index 0000000000..ca5c4b9617 --- /dev/null +++ b/options/license/OAR @@ -0,0 +1,12 @@ +COPYRIGHT (c) 1989-2013, 2015. +On-Line Applications Research Corporation (OAR). + +Permission to use, copy, modify, and distribute this software for any +purpose without fee is hereby granted, provided that this entire notice +is included in all copies of any software which is or includes a copy +or modification of this software. + +THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED +WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION +OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS +SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. diff --git a/options/license/xzoom b/options/license/xzoom new file mode 100644 index 0000000000..f312dedbc2 --- /dev/null +++ b/options/license/xzoom @@ -0,0 +1,12 @@ +Copyright Itai Nahshon 1995, 1996. +This program is distributed with no warranty. + +Source files for this program may be distributed freely. +Modifications to this file are okay as long as: + a. This copyright notice and comment are preserved and + left at the top of the file. + b. The man page is fixed to reflect the change. + c. The author of this change adds his name and change + description to the list of changes below. +Executable files may be distributed with sources, or with +exact location where the source code can be obtained. From a008486f5c5acfe2d2acb009f41dc660ee8348eb Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Mon, 1 Apr 2024 10:06:35 +0800 Subject: [PATCH 022/370] Refactor DeleteInactiveUsers, fix bug and add tests (#30206) 1. check `IsActive` before calling `IsLastAdminUser`. 2. Fix some comments and error messages. 3. Don't `return err` if "removing file" fails in `DeleteUser`. 4. Remove incorrect `DeleteInactiveEmailAddresses`. Active users could also have inactive emails, and inactive emails do not support "olderThan" 5. Add tests --- models/user/email_address.go | 8 ------- services/user/user.go | 45 ++++++++++++++++-------------------- services/user/user_test.go | 25 ++++++++++++++++++++ 3 files changed, 45 insertions(+), 33 deletions(-) diff --git a/models/user/email_address.go b/models/user/email_address.go index d26549f383..08771efe99 100644 --- a/models/user/email_address.go +++ b/models/user/email_address.go @@ -256,14 +256,6 @@ func IsEmailUsed(ctx context.Context, email string) (bool, error) { return db.GetEngine(ctx).Where("lower_email=?", strings.ToLower(email)).Get(&EmailAddress{}) } -// DeleteInactiveEmailAddresses deletes inactive email addresses -func DeleteInactiveEmailAddresses(ctx context.Context) error { - _, err := db.GetEngine(ctx). - Where("is_activated = ?", false). - Delete(new(EmailAddress)) - return err -} - // ActivateEmail activates the email address to given user. func ActivateEmail(ctx context.Context, email *EmailAddress) error { ctx, committer, err := db.TxContext(ctx) diff --git a/services/user/user.go b/services/user/user.go index 4fcb81581d..2287e36c71 100644 --- a/services/user/user.go +++ b/services/user/user.go @@ -126,7 +126,7 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error { return fmt.Errorf("%s is an organization not a user", u.Name) } - if user_model.IsLastAdminUser(ctx, u) { + if u.IsActive && user_model.IsLastAdminUser(ctx, u) { return models.ErrDeleteLastAdminUser{UID: u.ID} } @@ -250,7 +250,7 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error { if err := committer.Commit(); err != nil { return err } - committer.Close() + _ = committer.Close() if err = asymkey_service.RewriteAllPublicKeys(ctx); err != nil { return err @@ -259,50 +259,45 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error { return err } - // Note: There are something just cannot be roll back, - // so just keep error logs of those operations. + // Note: There are something just cannot be roll back, so just keep error logs of those operations. path := user_model.UserPath(u.Name) - if err := util.RemoveAll(path); err != nil { - err = fmt.Errorf("Failed to RemoveAll %s: %w", path, err) + if err = util.RemoveAll(path); err != nil { + err = fmt.Errorf("failed to RemoveAll %s: %w", path, err) _ = system_model.CreateNotice(ctx, system_model.NoticeTask, fmt.Sprintf("delete user '%s': %v", u.Name, err)) - return err } if u.Avatar != "" { avatarPath := u.CustomAvatarRelativePath() - if err := storage.Avatars.Delete(avatarPath); err != nil { - err = fmt.Errorf("Failed to remove %s: %w", avatarPath, err) + if err = storage.Avatars.Delete(avatarPath); err != nil { + err = fmt.Errorf("failed to remove %s: %w", avatarPath, err) _ = system_model.CreateNotice(ctx, system_model.NoticeTask, fmt.Sprintf("delete user '%s': %v", u.Name, err)) - return err } } return nil } -// DeleteInactiveUsers deletes all inactive users and email addresses. +// DeleteInactiveUsers deletes all inactive users and their email addresses. func DeleteInactiveUsers(ctx context.Context, olderThan time.Duration) error { - users, err := user_model.GetInactiveUsers(ctx, olderThan) + inactiveUsers, err := user_model.GetInactiveUsers(ctx, olderThan) if err != nil { return err } // FIXME: should only update authorized_keys file once after all deletions. - for _, u := range users { - select { - case <-ctx.Done(): - return db.ErrCancelledf("Before delete inactive user %s", u.Name) - default: - } - if err := DeleteUser(ctx, u, false); err != nil { - // Ignore users that were set inactive by admin. - if models.IsErrUserOwnRepos(err) || models.IsErrUserHasOrgs(err) || - models.IsErrUserOwnPackages(err) || models.IsErrDeleteLastAdminUser(err) { + for _, u := range inactiveUsers { + if err = DeleteUser(ctx, u, false); err != nil { + // Ignore inactive users that were ever active but then were set inactive by admin + if models.IsErrUserOwnRepos(err) || models.IsErrUserHasOrgs(err) || models.IsErrUserOwnPackages(err) { continue } - return err + select { + case <-ctx.Done(): + return db.ErrCancelledf("when deleting inactive user %q", u.Name) + default: + return err + } } } - - return user_model.DeleteInactiveEmailAddresses(ctx) + return nil // TODO: there could be still inactive users left, and the number would increase gradually } diff --git a/services/user/user_test.go b/services/user/user_test.go index f110bd26d0..bd6019a14f 100644 --- a/services/user/user_test.go +++ b/services/user/user_test.go @@ -7,6 +7,7 @@ import ( "fmt" "strings" "testing" + "time" "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/auth" @@ -16,6 +17,7 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/timeutil" "github.com/stretchr/testify/assert" ) @@ -185,3 +187,26 @@ func TestCreateUser_Issue5882(t *testing.T) { assert.NoError(t, DeleteUser(db.DefaultContext, v.user, false)) } } + +func TestDeleteInactiveUsers(t *testing.T) { + addUser := func(name, email string, createdUnix timeutil.TimeStamp, active bool) { + inactiveUser := &user_model.User{Name: name, LowerName: strings.ToLower(name), Email: email, CreatedUnix: createdUnix, IsActive: active} + _, err := db.GetEngine(db.DefaultContext).NoAutoTime().Insert(inactiveUser) + assert.NoError(t, err) + inactiveUserEmail := &user_model.EmailAddress{UID: inactiveUser.ID, IsPrimary: true, Email: email, LowerEmail: strings.ToLower(email), IsActivated: active} + err = db.Insert(db.DefaultContext, inactiveUserEmail) + assert.NoError(t, err) + } + addUser("user-inactive-10", "user-inactive-10@test.com", timeutil.TimeStampNow().Add(-600), false) + addUser("user-inactive-5", "user-inactive-5@test.com", timeutil.TimeStampNow().Add(-300), false) + addUser("user-active-10", "user-active-10@test.com", timeutil.TimeStampNow().Add(-600), true) + addUser("user-active-5", "user-active-5@test.com", timeutil.TimeStampNow().Add(-300), true) + unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user-inactive-10"}) + unittest.AssertExistsAndLoadBean(t, &user_model.EmailAddress{Email: "user-inactive-10@test.com"}) + assert.NoError(t, DeleteInactiveUsers(db.DefaultContext, 8*time.Minute)) + unittest.AssertNotExistsBean(t, &user_model.User{Name: "user-inactive-10"}) + unittest.AssertNotExistsBean(t, &user_model.EmailAddress{Email: "user-inactive-10@test.com"}) + unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user-inactive-5"}) + unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user-active-10"}) + unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user-active-5"}) +} From 751997ad34fdd52b9f3956b14395560b059c9ac1 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Mon, 1 Apr 2024 21:11:30 +0800 Subject: [PATCH 023/370] Refactor file view & render (#30227) The old code is inconsistent and fragile, and the UI isn't right. --- routers/web/repo/blame.go | 10 +++++++++- routers/web/repo/setting/lfs.go | 17 ++++++++--------- routers/web/repo/view.go | 12 +++++++----- templates/repo/blame.tmpl | 4 ++++ templates/repo/settings/lfs_file.tmpl | 10 ++++------ templates/repo/view_file.tmpl | 16 ++++------------ templates/shared/filetoolarge.tmpl | 4 ++++ 7 files changed, 40 insertions(+), 33 deletions(-) create mode 100644 templates/shared/filetoolarge.tmpl diff --git a/routers/web/repo/blame.go b/routers/web/repo/blame.go index 935e6d78fc..1887e4d95d 100644 --- a/routers/web/repo/blame.go +++ b/routers/web/repo/blame.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/highlight" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" @@ -87,9 +88,16 @@ func RefBlame(ctx *context.Context) { ctx.Data["IsBlame"] = true - ctx.Data["FileSize"] = blob.Size() + fileSize := blob.Size() + ctx.Data["FileSize"] = fileSize ctx.Data["FileName"] = blob.Name() + if fileSize >= setting.UI.MaxDisplayFileSize { + ctx.Data["IsFileTooLarge"] = true + ctx.HTML(http.StatusOK, tplRepoHome) + return + } + ctx.Data["NumLines"], err = blob.GetBlobLineCount() ctx.Data["NumLinesSet"] = true diff --git a/routers/web/repo/setting/lfs.go b/routers/web/repo/setting/lfs.go index 32049cf0a4..6dddade066 100644 --- a/routers/web/repo/setting/lfs.go +++ b/routers/web/repo/setting/lfs.go @@ -287,22 +287,19 @@ func LFSFileGet(ctx *context.Context) { st := typesniffer.DetectContentType(buf) ctx.Data["IsTextFile"] = st.IsText() - isRepresentableAsText := st.IsRepresentableAsText() - - fileSize := meta.Size ctx.Data["FileSize"] = meta.Size ctx.Data["RawFileLink"] = fmt.Sprintf("%s%s/%s.git/info/lfs/objects/%s/%s", setting.AppURL, url.PathEscape(ctx.Repo.Repository.OwnerName), url.PathEscape(ctx.Repo.Repository.Name), url.PathEscape(meta.Oid), "direct") switch { - case isRepresentableAsText: - if st.IsSvgImage() { - ctx.Data["IsImageFile"] = true - } - - if fileSize >= setting.UI.MaxDisplayFileSize { + case st.IsRepresentableAsText(): + if meta.Size >= setting.UI.MaxDisplayFileSize { ctx.Data["IsFileTooLarge"] = true break } + if st.IsSvgImage() { + ctx.Data["IsImageFile"] = true + } + rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc), charset.ConvertOpts{}) // Building code view blocks with line number on server side. @@ -338,6 +335,8 @@ func LFSFileGet(ctx *context.Context) { ctx.Data["IsAudioFile"] = true case st.IsImage() && (setting.UI.SVG.Enabled || !st.IsSvgImage()): ctx.Data["IsImageFile"] = true + default: + // TODO: the logic is not the same as "renderFile" in "view.go" } ctx.HTML(http.StatusOK, tplSettingsLFSFile) } diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 93e0f5bcbd..8aa9dbb1be 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -482,17 +482,17 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry) { switch { case isRepresentableAsText: + if fInfo.fileSize >= setting.UI.MaxDisplayFileSize { + ctx.Data["IsFileTooLarge"] = true + break + } + if fInfo.st.IsSvgImage() { ctx.Data["IsImageFile"] = true ctx.Data["CanCopyContent"] = true ctx.Data["HasSourceRenderedToggle"] = true } - if fInfo.fileSize >= setting.UI.MaxDisplayFileSize { - ctx.Data["IsFileTooLarge"] = true - break - } - rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc), charset.ConvertOpts{}) shouldRenderSource := ctx.FormString("display") == "source" @@ -606,6 +606,8 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry) { break } + // TODO: this logic seems strange, it duplicates with "isRepresentableAsText=true", it is not the same as "LFSFileGet" in "lfs.go" + // maybe for this case, the file is a binary file, and shouldn't be rendered? if markupType := markup.Type(blob.Name()); markupType != "" { rd := io.MultiReader(bytes.NewReader(buf), dataRc) ctx.Data["IsMarkup"] = true diff --git a/templates/repo/blame.tmpl b/templates/repo/blame.tmpl index 1a148a2d1c..30d1a3d78d 100644 --- a/templates/repo/blame.tmpl +++ b/templates/repo/blame.tmpl @@ -30,6 +30,9 @@ </h4> <div class="ui attached table unstackable segment"> <div class="file-view code-view unicode-escaped"> + {{if .IsFileTooLarge}} + {{template "shared/filetoolarge" dict "RawFileLink" .RawFileLink}} + {{else}} <table> <tbody> {{range $row := .BlameRows}} @@ -75,6 +78,7 @@ {{end}} </tbody> </table> + {{end}}{{/* end if .IsFileTooLarge */}} <div class="code-line-menu tippy-target"> {{if $.Permission.CanRead $.UnitTypeIssues}} <a class="item ref-in-new-issue" role="menuitem" data-url-issue-new="{{.RepoLink}}/issues/new" data-url-param-body-link="{{.Repository.Link}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}{{if $.HasSourceRenderedToggle}}?display=source{{end}}" rel="nofollow noindex">{{ctx.Locale.Tr "repo.issues.context.reference_issue"}}</a> diff --git a/templates/repo/settings/lfs_file.tmpl b/templates/repo/settings/lfs_file.tmpl index 43afba96c3..cb65236f23 100644 --- a/templates/repo/settings/lfs_file.tmpl +++ b/templates/repo/settings/lfs_file.tmpl @@ -14,7 +14,9 @@ <div class="ui attached table unstackable segment"> {{template "repo/unicode_escape_prompt" dict "EscapeStatus" .EscapeStatus "root" $}} <div class="file-view{{if .IsMarkup}} markup {{.MarkupType}}{{else if .IsPlainText}} plain-text{{else if .IsTextFile}} code-view{{end}}"> - {{if .IsMarkup}} + {{if .IsFileTooLarge}} + {{template "shared/filetoolarge" dict "RawFileLink" .RawFileLink}} + {{else if .IsMarkup}} {{if .FileContent}}{{.FileContent | SafeHTML}}{{end}} {{else if .IsPlainText}} <pre>{{if .FileContent}}{{.FileContent | SafeHTML}}{{end}}</pre> @@ -33,19 +35,15 @@ {{else if .IsPDFFile}} <div class="pdf-content is-loading" data-src="{{$.RawFileLink}}" data-fallback-button-text="{{ctx.Locale.Tr "diff.view_file"}}"></div> {{else}} - <a href="{{$.RawFileLink}}" rel="nofollow">{{ctx.Locale.Tr "repo.file_view_raw"}}</a> + <a href="{{$.RawFileLink}}" rel="nofollow" class="tw-p-4">{{ctx.Locale.Tr "repo.file_view_raw"}}</a> {{end}} </div> {{else if .FileSize}} <table> <tbody> <tr> - {{if .IsFileTooLarge}} - <td><strong>{{ctx.Locale.Tr "repo.file_too_large"}}</strong></td> - {{else}} <td class="lines-num">{{.LineNums}}</td> <td class="lines-code"><pre><code class="{{.HighlightClass}}"><ol>{{.FileContent}}</ol></code></pre></td> - {{end}} </tr> </tbody> </table> diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl index b7c1b9eeae..9c5bd9094d 100644 --- a/templates/repo/view_file.tmpl +++ b/templates/repo/view_file.tmpl @@ -89,7 +89,9 @@ {{template "repo/unicode_escape_prompt" dict "EscapeStatus" .EscapeStatus "root" $}} {{end}} <div class="file-view{{if .IsMarkup}} markup {{.MarkupType}}{{else if .IsPlainText}} plain-text{{else if .IsTextSource}} code-view{{end}}"> - {{if .IsMarkup}} + {{if .IsFileTooLarge}} + {{template "shared/filetoolarge" dict "RawFileLink" .RawFileLink}} + {{else if .IsMarkup}} {{if .FileContent}}{{.FileContent}}{{end}} {{else if .IsPlainText}} <pre>{{if .FileContent}}{{.FileContent}}{{end}}</pre> @@ -108,19 +110,10 @@ {{else if .IsPDFFile}} <div class="pdf-content is-loading" data-src="{{$.RawFileLink}}" data-fallback-button-text="{{ctx.Locale.Tr "repo.diff.view_file"}}"></div> {{else}} - <a href="{{$.RawFileLink}}" rel="nofollow">{{ctx.Locale.Tr "repo.file_view_raw"}}</a> + <a href="{{$.RawFileLink}}" rel="nofollow" class="tw-p-4">{{ctx.Locale.Tr "repo.file_view_raw"}}</a> {{end}} </div> {{else if .FileSize}} - {{if .IsFileTooLarge}} - <table> - <tbody> - <tr> - <td><strong>{{ctx.Locale.Tr "repo.file_too_large"}}</strong></td> - </tr> - </tbody> - </table> - {{else}} <table> <tbody> {{range $idx, $code := .FileContent}} @@ -142,7 +135,6 @@ <a class="item view_git_blame" role="menuitem" href="{{.Repository.Link}}/blame/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}">{{ctx.Locale.Tr "repo.view_git_blame"}}</a> <a class="item copy-line-permalink" role="menuitem" data-url="{{.Repository.Link}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}{{if $.HasSourceRenderedToggle}}?display=source{{end}}">{{ctx.Locale.Tr "repo.file_copy_permalink"}}</a> </div> - {{end}} {{end}} </div> </div> diff --git a/templates/shared/filetoolarge.tmpl b/templates/shared/filetoolarge.tmpl new file mode 100644 index 0000000000..8842fb1b91 --- /dev/null +++ b/templates/shared/filetoolarge.tmpl @@ -0,0 +1,4 @@ +<div class="tw-p-4"> + {{ctx.Locale.Tr "repo.file_too_large"}} + {{if .RawFileLink}}<a href="{{.RawFileLink}}" rel="nofollow">{{ctx.Locale.Tr "repo.file_view_raw"}}</a>{{end}} +</div> From 1ef2eb50d82d07b1e4ff312ef58953d1bba2437a Mon Sep 17 00:00:00 2001 From: Zettat123 <zettat123@gmail.com> Date: Mon, 1 Apr 2024 21:48:14 +0800 Subject: [PATCH 024/370] Remove scheduled action tasks if the repo is archived (#30224) Fix #30220 --- routers/api/v1/repo/repo.go | 10 ++++++++++ routers/web/repo/setting/setting.go | 12 ++++++++++++ services/actions/notifier_helper.go | 4 ++-- services/actions/schedule_tasks.go | 5 +++++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 80504b9c33..822e368fa8 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -12,6 +12,7 @@ import ( "strings" "time" + actions_model "code.gitea.io/gitea/models/actions" activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" @@ -31,6 +32,7 @@ import ( "code.gitea.io/gitea/modules/validation" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + actions_service "code.gitea.io/gitea/services/actions" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/issue" @@ -1035,6 +1037,9 @@ func updateRepoArchivedState(ctx *context.APIContext, opts api.EditRepoOption) e ctx.Error(http.StatusInternalServerError, "ArchiveRepoState", err) return err } + if err := actions_model.CleanRepoScheduleTasks(ctx, repo); err != nil { + log.Error("CleanRepoScheduleTasks for archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err) + } log.Trace("Repository was archived: %s/%s", ctx.Repo.Owner.Name, repo.Name) } else { if err := repo_model.SetArchiveRepoState(ctx, repo, *opts.Archived); err != nil { @@ -1042,6 +1047,11 @@ func updateRepoArchivedState(ctx *context.APIContext, opts api.EditRepoOption) e ctx.Error(http.StatusInternalServerError, "ArchiveRepoState", err) return err } + if ctx.Repo.Repository.UnitEnabled(ctx, unit_model.TypeActions) { + if err := actions_service.DetectAndHandleSchedules(ctx, repo); err != nil { + log.Error("DetectAndHandleSchedules for un-archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err) + } + } log.Trace("Repository was un-archived: %s/%s", ctx.Repo.Owner.Name, repo.Name) } } diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go index e045e3b8dc..00a5282f34 100644 --- a/routers/web/repo/setting/setting.go +++ b/routers/web/repo/setting/setting.go @@ -13,6 +13,7 @@ import ( "time" "code.gitea.io/gitea/models" + actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" repo_model "code.gitea.io/gitea/models/repo" @@ -29,6 +30,7 @@ import ( "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/validation" "code.gitea.io/gitea/modules/web" + actions_service "code.gitea.io/gitea/services/actions" asymkey_service "code.gitea.io/gitea/services/asymkey" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" @@ -897,6 +899,10 @@ func SettingsPost(ctx *context.Context) { return } + if err := actions_model.CleanRepoScheduleTasks(ctx, repo); err != nil { + log.Error("CleanRepoScheduleTasks for archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err) + } + ctx.Flash.Success(ctx.Tr("repo.settings.archive.success")) log.Trace("Repository was archived: %s/%s", ctx.Repo.Owner.Name, repo.Name) @@ -915,6 +921,12 @@ func SettingsPost(ctx *context.Context) { return } + if ctx.Repo.Repository.UnitEnabled(ctx, unit_model.TypeActions) { + if err := actions_service.DetectAndHandleSchedules(ctx, repo); err != nil { + log.Error("DetectAndHandleSchedules for un-archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err) + } + } + ctx.Flash.Success(ctx.Tr("repo.settings.unarchive.success")) log.Trace("Repository was un-archived: %s/%s", ctx.Repo.Owner.Name, repo.Name) diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index 66a19844c2..8c98f56af5 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -117,7 +117,7 @@ func notify(ctx context.Context, input *notifyInput) error { log.Debug("ignore executing %v for event %v whose doer is %v", getMethod(ctx), input.Event, input.Doer.Name) return nil } - if input.Repo.IsEmpty { + if input.Repo.IsEmpty || input.Repo.IsArchived { return nil } if unit_model.TypeActions.UnitGlobalDisabled() { @@ -501,7 +501,7 @@ func handleSchedules( // DetectAndHandleSchedules detects the schedule workflows on the default branch and create schedule tasks func DetectAndHandleSchedules(ctx context.Context, repo *repo_model.Repository) error { - if repo.IsEmpty { + if repo.IsEmpty || repo.IsArchived { return nil } diff --git a/services/actions/schedule_tasks.go b/services/actions/schedule_tasks.go index 59862fd0d8..e4e56e5122 100644 --- a/services/actions/schedule_tasks.go +++ b/services/actions/schedule_tasks.go @@ -66,6 +66,11 @@ func startTasks(ctx context.Context) error { } } + if row.Repo.IsArchived { + // Skip if the repo is archived + continue + } + cfg, err := row.Repo.GetUnit(ctx, unit.TypeActions) if err != nil { if repo_model.IsErrUnitTypeNotExist(err) { From ca297a90fb1fec5b270fad1a3e575916510e7385 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Tue, 2 Apr 2024 02:16:38 +0800 Subject: [PATCH 025/370] Refactor dropzone (#30232) Simplify code and use `.files` elements --- web_src/js/features/repo-legacy.js | 50 +++++++++++++----------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index 34320de1de..4c7dd36920 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -358,11 +358,11 @@ async function onEditContent(event) { input.name = 'files'; input.type = 'hidden'; input.value = data.uuid; - dropzone.querySelector('.files').insertAdjacentHTML('beforeend', input.outerHTML); + dropzone.querySelector('.files').append(input); }); this.on('removedfile', async (file) => { - if (disableRemovedfileEvent) return; document.getElementById(file.uuid)?.remove(); + if (disableRemovedfileEvent) return; if (dropzone.getAttribute('data-remove-url') && !fileUuidDict[file.uuid].submitted) { try { await POST(dropzone.getAttribute('data-remove-url'), {data: new URLSearchParams({file: file.uuid})}); @@ -384,6 +384,7 @@ async function onEditContent(event) { disableRemovedfileEvent = true; dz.removeAllFiles(true); dropzone.querySelector('.files').innerHTML = ''; + for (const el of dropzone.querySelectorAll('.dz-preview')) el.remove(); fileUuidDict = {}; disableRemovedfileEvent = false; @@ -392,7 +393,6 @@ async function onEditContent(event) { dz.emit('addedfile', attachment); dz.emit('thumbnail', attachment, imgSrc); dz.emit('complete', attachment); - dz.files.push(attachment); fileUuidDict[attachment.uuid] = {submitted: true}; dropzone.querySelector(`img[src='${imgSrc}']`).style.maxWidth = '100%'; const input = document.createElement('input'); @@ -400,7 +400,10 @@ async function onEditContent(event) { input.name = 'files'; input.type = 'hidden'; input.value = attachment.uuid; - dropzone.querySelector('.files').insertAdjacentHTML('beforeend', input.outerHTML); + dropzone.querySelector('.files').append(input); + } + if (!dropzone.querySelector('.dz-preview')) { + dropzone.classList.remove('dz-started'); } } catch (error) { console.error(error); @@ -412,24 +415,24 @@ async function onEditContent(event) { return dz; }; - const cancelAndReset = (dz) => { + const cancelAndReset = (e) => { + e.preventDefault(); showElem(renderContent); hideElem(editContentZone); - if (dz) { - dz.emit('reload'); - } + comboMarkdownEditor.attachedDropzoneInst?.emit('reload'); }; - const saveAndRefresh = async (dz) => { + const saveAndRefresh = async (e) => { + e.preventDefault(); showElem(renderContent); hideElem(editContentZone); - + const dropzoneInst = comboMarkdownEditor.attachedDropzoneInst; try { const params = new URLSearchParams({ content: comboMarkdownEditor.value(), context: editContentZone.getAttribute('data-context'), }); - for (const file of dz.files) params.append('files[]', file.uuid); + for (const fileInput of dropzoneInst?.element.querySelectorAll('.files [name=files]')) params.append('files[]', fileInput.value); const response = await POST(editContentZone.getAttribute('data-update-url'), {data: params}); const data = await response.json(); @@ -452,10 +455,8 @@ async function onEditContent(event) { } else { content.querySelector('.dropzone-attachments').outerHTML = data.attachments; } - if (dz) { - dz.emit('submit'); - dz.emit('reload'); - } + dropzoneInst?.emit('submit'); + dropzoneInst?.emit('reload'); initMarkupContent(); initCommentContent(); } catch (error) { @@ -463,22 +464,13 @@ async function onEditContent(event) { } }; - if (!editContentZone.innerHTML) { + comboMarkdownEditor = getComboMarkdownEditor(editContentZone.querySelector('.combo-markdown-editor')); + if (!comboMarkdownEditor) { editContentZone.innerHTML = document.getElementById('issue-comment-editor-template').innerHTML; comboMarkdownEditor = await initComboMarkdownEditor(editContentZone.querySelector('.combo-markdown-editor')); - - const dropzone = editContentZone.querySelector('.dropzone'); - const dz = await setupDropzone(dropzone); - editContentZone.querySelector('.cancel.button').addEventListener('click', (e) => { - e.preventDefault(); - cancelAndReset(dz); - }); - editContentZone.querySelector('.save.button').addEventListener('click', (e) => { - e.preventDefault(); - saveAndRefresh(dz); - }); - } else { - comboMarkdownEditor = getComboMarkdownEditor(editContentZone.querySelector('.combo-markdown-editor')); + comboMarkdownEditor.attachedDropzoneInst = await setupDropzone(editContentZone.querySelector('.dropzone')); + editContentZone.querySelector('.cancel.button').addEventListener('click', cancelAndReset); + editContentZone.querySelector('.save.button').addEventListener('click', saveAndRefresh); } // Show write/preview tab and copy raw content as needed From 0db554fa634737af59613768b2e01bfe3e239e68 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Tue, 2 Apr 2024 04:23:17 +0800 Subject: [PATCH 026/370] Refactor commit signature parser (#30228) To make it more flexible and support SSH signature. The existing tests are not changed, there are also tests covering `parseTagRef` which also calls `parsePayloadSignature` now. Add some new tests to `Test_parseTagData` --- modules/git/commit.go | 6 +- modules/git/commit_convert_gogit.go | 4 +- modules/git/commit_reader.go | 2 +- modules/git/repo_tag.go | 10 ++- modules/git/repo_tag_test.go | 2 +- modules/git/tag.go | 104 +++++++++++++++------------ modules/git/tag_test.go | 106 +++++++++++++++++----------- 7 files changed, 135 insertions(+), 99 deletions(-) diff --git a/modules/git/commit.go b/modules/git/commit.go index ef2676762c..5f442b0e1a 100644 --- a/modules/git/commit.go +++ b/modules/git/commit.go @@ -26,14 +26,14 @@ type Commit struct { Author *Signature Committer *Signature CommitMessage string - Signature *CommitGPGSignature + Signature *CommitSignature Parents []ObjectID // ID strings submoduleCache *ObjectCache } -// CommitGPGSignature represents a git commit signature part. -type CommitGPGSignature struct { +// CommitSignature represents a git commit signature part. +type CommitSignature struct { Signature string Payload string // TODO check if can be reconstruct from the rest of commit information to not have duplicate data } diff --git a/modules/git/commit_convert_gogit.go b/modules/git/commit_convert_gogit.go index 33ef2f4487..d7b945ed6b 100644 --- a/modules/git/commit_convert_gogit.go +++ b/modules/git/commit_convert_gogit.go @@ -13,7 +13,7 @@ import ( "github.com/go-git/go-git/v5/plumbing/object" ) -func convertPGPSignature(c *object.Commit) *CommitGPGSignature { +func convertPGPSignature(c *object.Commit) *CommitSignature { if c.PGPSignature == "" { return nil } @@ -57,7 +57,7 @@ func convertPGPSignature(c *object.Commit) *CommitGPGSignature { return nil } - return &CommitGPGSignature{ + return &CommitSignature{ Signature: c.PGPSignature, Payload: w.String(), } diff --git a/modules/git/commit_reader.go b/modules/git/commit_reader.go index 56c41dc473..f1f4a0e588 100644 --- a/modules/git/commit_reader.go +++ b/modules/git/commit_reader.go @@ -99,7 +99,7 @@ readLoop: } } commit.CommitMessage = messageSB.String() - commit.Signature = &CommitGPGSignature{ + commit.Signature = &CommitSignature{ Signature: signatureSB.String(), Payload: payloadSB.String(), } diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index e8c5ce6fb8..2026a4c9f5 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -185,17 +185,15 @@ func parseTagRef(ref map[string]string) (tag *Tag, err error) { tag.Tagger = parseSignatureFromCommitLine(ref["creator"]) tag.Message = ref["contents"] - // strip PGP signature if present in contents field - pgpStart := strings.Index(tag.Message, beginpgp) - if pgpStart >= 0 { - tag.Message = tag.Message[0:pgpStart] - } + + // strip any signature if present in contents field + _, tag.Message, _ = parsePayloadSignature(util.UnsafeStringToBytes(tag.Message), 0) // annotated tag with GPG signature if tag.Type == "tag" && ref["contents:signature"] != "" { payload := fmt.Sprintf("object %s\ntype commit\ntag %s\ntagger %s\n\n%s\n", tag.Object, tag.Name, ref["creator"], strings.TrimSpace(tag.Message)) - tag.Signature = &CommitGPGSignature{ + tag.Signature = &CommitSignature{ Signature: ref["contents:signature"], Payload: payload, } diff --git a/modules/git/repo_tag_test.go b/modules/git/repo_tag_test.go index 785c3442a7..0117cb902d 100644 --- a/modules/git/repo_tag_test.go +++ b/modules/git/repo_tag_test.go @@ -315,7 +315,7 @@ qbHDASXl Type: "tag", Tagger: parseSignatureFromCommitLine("Foo Bar <foo@bar.com> 1565789218 +0300"), Message: "Add changelog of v1.9.1 (#7859)\n\n* add changelog of v1.9.1\n* Update CHANGELOG.md", - Signature: &CommitGPGSignature{ + Signature: &CommitSignature{ Signature: `-----BEGIN PGP SIGNATURE----- aBCGzBAABCgAdFiEEyWRwv/q1Q6IjSv+D4IPOwzt33PoFAmI8jbIACgkQ4IPOwzt3 diff --git a/modules/git/tag.go b/modules/git/tag.go index 94e5cd7c63..f7666aa89b 100644 --- a/modules/git/tag.go +++ b/modules/git/tag.go @@ -6,16 +6,10 @@ package git import ( "bytes" "sort" - "strings" "code.gitea.io/gitea/modules/util" ) -const ( - beginpgp = "\n-----BEGIN PGP SIGNATURE-----\n" - endpgp = "\n-----END PGP SIGNATURE-----" -) - // Tag represents a Git tag. type Tag struct { Name string @@ -24,7 +18,7 @@ type Tag struct { Type string Tagger *Signature Message string - Signature *CommitGPGSignature + Signature *CommitSignature } // Commit return the commit of the tag reference @@ -32,6 +26,36 @@ func (tag *Tag) Commit(gitRepo *Repository) (*Commit, error) { return gitRepo.getCommit(tag.Object) } +func parsePayloadSignature(data []byte, messageStart int) (payload, msg, sign string) { + pos := messageStart + signStart, signEnd := -1, -1 + for { + eol := bytes.IndexByte(data[pos:], '\n') + if eol < 0 { + break + } + line := data[pos : pos+eol] + signType, hasPrefix := bytes.CutPrefix(line, []byte("-----BEGIN ")) + signType, hasSuffix := bytes.CutSuffix(signType, []byte(" SIGNATURE-----")) + if hasPrefix && hasSuffix { + signEndBytes := append([]byte("\n-----END "), signType...) + signEndBytes = append(signEndBytes, []byte(" SIGNATURE-----")...) + signEnd = bytes.Index(data[pos:], signEndBytes) + if signEnd != -1 { + signStart = pos + signEnd = pos + signEnd + len(signEndBytes) + } + } + pos += eol + 1 + } + + if signStart != -1 && signEnd != -1 { + msgEnd := max(messageStart, signStart-1) + return string(data[:msgEnd]), string(data[messageStart:msgEnd]), string(data[signStart:signEnd]) + } + return string(data), string(data[messageStart:]), "" +} + // Parse commit information from the (uncompressed) raw // data from the commit object. // \n\n separate headers from message @@ -40,47 +64,37 @@ func parseTagData(objectFormat ObjectFormat, data []byte) (*Tag, error) { tag.ID = objectFormat.EmptyObjectID() tag.Object = objectFormat.EmptyObjectID() tag.Tagger = &Signature{} - // we now have the contents of the commit object. Let's investigate... - nextline := 0 -l: + + pos := 0 for { - eol := bytes.IndexByte(data[nextline:], '\n') - switch { - case eol > 0: - line := data[nextline : nextline+eol] - spacepos := bytes.IndexByte(line, ' ') - reftype := line[:spacepos] - switch string(reftype) { - case "object": - id, err := NewIDFromString(string(line[spacepos+1:])) - if err != nil { - return nil, err - } - tag.Object = id - case "type": - // A commit can have one or more parents - tag.Type = string(line[spacepos+1:]) - case "tagger": - tag.Tagger = parseSignatureFromCommitLine(util.UnsafeBytesToString(line[spacepos+1:])) - } - nextline += eol + 1 - case eol == 0: - tag.Message = string(data[nextline+1:]) - break l - default: - break l + eol := bytes.IndexByte(data[pos:], '\n') + if eol == -1 { + break // shouldn't happen, but could just tolerate it } + if eol == 0 { + pos++ + break // end of headers + } + line := data[pos : pos+eol] + key, val, _ := bytes.Cut(line, []byte(" ")) + switch string(key) { + case "object": + id, err := NewIDFromString(string(val)) + if err != nil { + return nil, err + } + tag.Object = id + case "type": + tag.Type = string(val) // A commit can have one or more parents + case "tagger": + tag.Tagger = parseSignatureFromCommitLine(util.UnsafeBytesToString(val)) + } + pos += eol + 1 } - idx := strings.LastIndex(tag.Message, beginpgp) - if idx > 0 { - endSigIdx := strings.Index(tag.Message[idx:], endpgp) - if endSigIdx > 0 { - tag.Signature = &CommitGPGSignature{ - Signature: tag.Message[idx+1 : idx+endSigIdx+len(endpgp)], - Payload: string(data[:bytes.LastIndex(data, []byte(beginpgp))+1]), - } - tag.Message = tag.Message[:idx+1] - } + payload, msg, sign := parsePayloadSignature(data, pos) + tag.Message = msg + if len(sign) > 0 { + tag.Signature = &CommitSignature{Signature: sign, Payload: payload} } return tag, nil } diff --git a/modules/git/tag_test.go b/modules/git/tag_test.go index f980b0c560..ba02c28946 100644 --- a/modules/git/tag_test.go +++ b/modules/git/tag_test.go @@ -12,24 +12,28 @@ import ( func Test_parseTagData(t *testing.T) { testData := []struct { - data []byte - tag Tag + data string + expected Tag }{ - {data: []byte(`object 3b114ab800c6432ad42387ccf6bc8d4388a2885a + { + data: `object 3b114ab800c6432ad42387ccf6bc8d4388a2885a type commit tag 1.22.0 tagger Lucas Michot <lucas@semalead.com> 1484491741 +0100 -`), tag: Tag{ - Name: "", - ID: Sha1ObjectFormat.EmptyObjectID(), - Object: &Sha1Hash{0x3b, 0x11, 0x4a, 0xb8, 0x0, 0xc6, 0x43, 0x2a, 0xd4, 0x23, 0x87, 0xcc, 0xf6, 0xbc, 0x8d, 0x43, 0x88, 0xa2, 0x88, 0x5a}, - Type: "commit", - Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484491741, 0)}, - Message: "", - Signature: nil, - }}, - {data: []byte(`object 7cdf42c0b1cc763ab7e4c33c47a24e27c66bfccc +`, + expected: Tag{ + Name: "", + ID: Sha1ObjectFormat.EmptyObjectID(), + Object: MustIDFromString("3b114ab800c6432ad42387ccf6bc8d4388a2885a"), + Type: "commit", + Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484491741, 0).In(time.FixedZone("", 3600))}, + Message: "", + Signature: nil, + }, + }, + { + data: `object 7cdf42c0b1cc763ab7e4c33c47a24e27c66bfccc type commit tag 1.22.1 tagger Lucas Michot <lucas@semalead.com> 1484553735 +0100 @@ -37,37 +41,57 @@ tagger Lucas Michot <lucas@semalead.com> 1484553735 +0100 test message o -ono`), tag: Tag{ - Name: "", - ID: Sha1ObjectFormat.EmptyObjectID(), - Object: &Sha1Hash{0x7c, 0xdf, 0x42, 0xc0, 0xb1, 0xcc, 0x76, 0x3a, 0xb7, 0xe4, 0xc3, 0x3c, 0x47, 0xa2, 0x4e, 0x27, 0xc6, 0x6b, 0xfc, 0xcc}, - Type: "commit", - Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484553735, 0)}, - Message: "test message\no\n\nono", - Signature: nil, - }}, +ono`, + expected: Tag{ + Name: "", + ID: Sha1ObjectFormat.EmptyObjectID(), + Object: MustIDFromString("7cdf42c0b1cc763ab7e4c33c47a24e27c66bfccc"), + Type: "commit", + Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484553735, 0).In(time.FixedZone("", 3600))}, + Message: "test message\no\n\nono", + Signature: nil, + }, + }, + { + data: `object 7cdf42c0b1cc763ab7e4c33c47a24e27c66bfaaa +type commit +tag v0 +tagger dummy user <dummy-email@example.com> 1484491741 +0100 + +dummy message +-----BEGIN SSH SIGNATURE----- +dummy signature +-----END SSH SIGNATURE----- +`, + expected: Tag{ + Name: "", + ID: Sha1ObjectFormat.EmptyObjectID(), + Object: MustIDFromString("7cdf42c0b1cc763ab7e4c33c47a24e27c66bfaaa"), + Type: "commit", + Tagger: &Signature{Name: "dummy user", Email: "dummy-email@example.com", When: time.Unix(1484491741, 0).In(time.FixedZone("", 3600))}, + Message: "dummy message", + Signature: &CommitSignature{ + Signature: `-----BEGIN SSH SIGNATURE----- +dummy signature +-----END SSH SIGNATURE-----`, + Payload: `object 7cdf42c0b1cc763ab7e4c33c47a24e27c66bfaaa +type commit +tag v0 +tagger dummy user <dummy-email@example.com> 1484491741 +0100 + +dummy message`, + }, + }, + }, } for _, test := range testData { - tag, err := parseTagData(Sha1ObjectFormat, test.data) + tag, err := parseTagData(Sha1ObjectFormat, []byte(test.data)) assert.NoError(t, err) - assert.EqualValues(t, test.tag.ID, tag.ID) - assert.EqualValues(t, test.tag.Object, tag.Object) - assert.EqualValues(t, test.tag.Name, tag.Name) - assert.EqualValues(t, test.tag.Message, tag.Message) - assert.EqualValues(t, test.tag.Type, tag.Type) - if test.tag.Signature != nil && assert.NotNil(t, tag.Signature) { - assert.EqualValues(t, test.tag.Signature.Signature, tag.Signature.Signature) - assert.EqualValues(t, test.tag.Signature.Payload, tag.Signature.Payload) - } else { - assert.Nil(t, tag.Signature) - } - if test.tag.Tagger != nil && assert.NotNil(t, tag.Tagger) { - assert.EqualValues(t, test.tag.Tagger.Name, tag.Tagger.Name) - assert.EqualValues(t, test.tag.Tagger.Email, tag.Tagger.Email) - assert.EqualValues(t, test.tag.Tagger.When.Unix(), tag.Tagger.When.Unix()) - } else { - assert.Nil(t, tag.Tagger) - } + assert.Equal(t, test.expected, *tag) } + + tag, err := parseTagData(Sha1ObjectFormat, []byte("type commit\n\nfoo\n-----BEGIN SSH SIGNATURE-----\ncorrupted...")) + assert.NoError(t, err) + assert.Equal(t, "foo\n-----BEGIN SSH SIGNATURE-----\ncorrupted...", tag.Message) } From 8a5c597c1d53e7652f1f3fc59e64b46a04c5e20b Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Tue, 2 Apr 2024 00:24:02 +0000 Subject: [PATCH 027/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_cs-CZ.ini | 1 - options/locale/locale_de-DE.ini | 1 - options/locale/locale_el-GR.ini | 1 - options/locale/locale_es-ES.ini | 1 - options/locale/locale_fa-IR.ini | 1 - options/locale/locale_fi-FI.ini | 1 - options/locale/locale_fr-FR.ini | 1 - options/locale/locale_hu-HU.ini | 1 - options/locale/locale_it-IT.ini | 1 - options/locale/locale_ja-JP.ini | 1 - options/locale/locale_lv-LV.ini | 1 - options/locale/locale_nl-NL.ini | 1 - options/locale/locale_pl-PL.ini | 1 - options/locale/locale_pt-BR.ini | 1 - options/locale/locale_pt-PT.ini | 4 +++- options/locale/locale_ru-RU.ini | 1 - options/locale/locale_si-LK.ini | 1 - options/locale/locale_sv-SE.ini | 1 - options/locale/locale_tr-TR.ini | 1 - options/locale/locale_uk-UA.ini | 1 - options/locale/locale_zh-CN.ini | 1 - options/locale/locale_zh-TW.ini | 1 - 22 files changed, 3 insertions(+), 22 deletions(-) diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index 4abf813725..82a8fe5d45 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -2790,7 +2790,6 @@ settings=Nastavení správce dashboard.new_version_hint=Gitea %s je nyní k dispozici, právě u vás běži %s. Podívej se na <a target="_blank" rel="noreferrer" href="https://blog.gitea.io">blogu</a> pro více informací. dashboard.statistic=Souhrn -dashboard.operations=Operace údržby dashboard.system_status=Status systému dashboard.operation_name=Název operace dashboard.operation_switch=Přepnout diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 4d446db86f..9a09c2922e 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -2798,7 +2798,6 @@ settings=Administratoreinstellungen dashboard.new_version_hint=Gitea %s ist jetzt verfügbar, deine derzeitige Version ist %s. Weitere Details findest du im <a target="_blank" rel="noreferrer" href="https://blog.gitea.io">Blog</a>. dashboard.statistic=Übersicht -dashboard.operations=Wartungsoperationen dashboard.system_status=System-Status dashboard.operation_name=Name der Operation dashboard.operation_switch=Wechseln diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini index 1199d84581..6ce5ae1ce9 100644 --- a/options/locale/locale_el-GR.ini +++ b/options/locale/locale_el-GR.ini @@ -2687,7 +2687,6 @@ settings=Ρυθμίσεις Διαχειριστή dashboard.new_version_hint=Το Gitea %s είναι διαθέσιμο, τώρα εκτελείτε το %s. Ανατρέξτε <a target="_blank" rel="noreferrer" href="https://blog.gitea.io">στο blog</a> για περισσότερες λεπτομέρειες. dashboard.statistic=Περίληψη -dashboard.operations=Λειτουργίες Συντήρησης dashboard.system_status=Κατάσταση Συστήματος dashboard.operation_name=Όνομα Λειτουργίας dashboard.operation_switch=Αλλαγή diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index ce50b71ec4..fc78e1d439 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -2672,7 +2672,6 @@ settings=Configuración de Admin dashboard.new_version_hint=Gitea %s ya está disponible, estás ejecutando %s. Revisa <a target="_blank" rel="noreferrer" href="https://blog.gitea.io">el blog</a> para más detalles. dashboard.statistic=Resumen -dashboard.operations=Operaciones de mantenimiento dashboard.system_status=Estado del sistema dashboard.operation_name=Nombre de la operación dashboard.operation_switch=Interruptor diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini index 31122841a7..d19eb356d2 100644 --- a/options/locale/locale_fa-IR.ini +++ b/options/locale/locale_fa-IR.ini @@ -2064,7 +2064,6 @@ last_page=واپسین total=مجموع: %d dashboard.statistic=چکیده -dashboard.operations=عملیاتهای نگهداری dashboard.system_status=وضعیت سامانه dashboard.operation_name=نام عملیات dashboard.operation_switch=تعویض diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini index 00581f49fc..f283209908 100644 --- a/options/locale/locale_fi-FI.ini +++ b/options/locale/locale_fi-FI.ini @@ -1407,7 +1407,6 @@ last_page=Viimeisin total=Yhteensä: %d dashboard.statistic=Yhteenveto -dashboard.operations=Huoltotoimet dashboard.system_status=Järjestelmän tila dashboard.operation_name=Toiminnon nimi dashboard.operation_switch=Vaihda diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index 062c818bd4..dc66402901 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -2712,7 +2712,6 @@ settings=Paramètres administrateur dashboard.new_version_hint=Gitea %s est maintenant disponible, vous utilisez %s. Consultez <a target="_blank" rel="noreferrer" href="https://blog.gitea.io">le blog</a> pour plus de détails. dashboard.statistic=Résumé -dashboard.operations=Opérations de maintenance dashboard.system_status=État du système dashboard.operation_name=Nom de l'Opération dashboard.operation_switch=Basculer diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini index 93e3b42115..fb229090d4 100644 --- a/options/locale/locale_hu-HU.ini +++ b/options/locale/locale_hu-HU.ini @@ -1266,7 +1266,6 @@ last_page=Utolsó total=Összesen: %d dashboard.statistic=Összefoglaló -dashboard.operations=Karbantartási műveletek dashboard.system_status=Rendszer Állapota dashboard.operation_name=Művelet Neve dashboard.operation_switch=Váltás diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index cc379e8109..9a22995dfb 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -2233,7 +2233,6 @@ last_page=Ultima total=Totale: %d dashboard.statistic=Riepilogo -dashboard.operations=Operazioni di manutenzione dashboard.system_status=Stato del sistema dashboard.operation_name=Nome Operazione dashboard.operation_switch=Cambia diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index d5c2885f00..eddad35073 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -2719,7 +2719,6 @@ settings=管理設定 dashboard.new_version_hint=Gitea %s が入手可能になりました。 現在実行しているのは %s です。 詳細は <a target="_blank" rel="noreferrer" href="https://blog.gitea.io">ブログ</a> を確認してください。 dashboard.statistic=サマリー -dashboard.operations=メンテナンス操作 dashboard.system_status=システム状況 dashboard.operation_name=操作の名称 dashboard.operation_switch=切り替え diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 0a2729980b..9a15090012 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -2693,7 +2693,6 @@ settings=Administratora iestatījumi dashboard.new_version_hint=Ir pieejama Gitea versija %s, pašreizējā versija %s. Papildus informācija par jauno versiju ir pieejama <a target="_blank" rel="noreferrer" href="https://blog.gitea.io">mājas lapā</a>. dashboard.statistic=Kopsavilkums -dashboard.operations=Uzturēšanas darbības dashboard.system_status=Sistēmas statuss dashboard.operation_name=Darbības nosaukums dashboard.operation_switch=Pārslēgt diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini index 255a3db9fa..6b5122a86f 100644 --- a/options/locale/locale_nl-NL.ini +++ b/options/locale/locale_nl-NL.ini @@ -2135,7 +2135,6 @@ last_page=Laatste total=Totaal: %d dashboard.statistic=Overzicht -dashboard.operations=Onderhoudswerkzaamheden dashboard.system_status=Systeemtatus dashboard.operation_name=Bewerking naam dashboard.operation_switch=Omschakelen diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini index 1496877fd5..a1d7e95842 100644 --- a/options/locale/locale_pl-PL.ini +++ b/options/locale/locale_pl-PL.ini @@ -2010,7 +2010,6 @@ last_page=Ostatnia total=Ogółem: %d dashboard.statistic=Podsumowanie -dashboard.operations=Operacje konserwacji dashboard.system_status=Status strony dashboard.operation_name=Nazwa operacji dashboard.operation_switch=Przełącz diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 0d1614df3f..45f1c3b3f8 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -2648,7 +2648,6 @@ settings=Configurações de Administrador dashboard.new_version_hint=Uma nova versão está disponível: %s. Versão atual: %s. Visite <a target="_blank" rel="noreferrer" href="https://blog.gitea.io">o blog</a> para mais informações. dashboard.statistic=Resumo -dashboard.operations=Operações de manutenção dashboard.system_status=Status do sistema dashboard.operation_name=Nome da operação dashboard.operation_switch=Trocar diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index ea80cd7abb..09b9d4e3ce 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -2775,6 +2775,7 @@ teams.invite.by=Convidado(a) por %s teams.invite.description=Clique no botão abaixo para se juntar à equipa. [admin] +maintenance=Manutenção dashboard=Painel de controlo self_check=Auto-verificação identity_access=Identidade e acesso @@ -2798,7 +2799,7 @@ 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 <a target="_blank" rel="noreferrer" href="https://blog.gitea.io">blog</a> para mais detalhes. dashboard.statistic=Resumo -dashboard.operations=Operações de manutenção +dashboard.maintenance_operations=Operações de manutenção dashboard.system_status=Estado do sistema dashboard.operation_name=Nome da operação dashboard.operation_switch=Comutar @@ -3305,6 +3306,7 @@ notices.op=Op. notices.delete_success=As notificações do sistema foram eliminadas. self_check.no_problem_found=Nenhum problema encontrado até agora. +self_check.startup_warnings=Alertas do arranque: self_check.database_collation_mismatch=Supor que a base de dados usa a colação: %s self_check.database_collation_case_insensitive=A base de dados está a usar a colação %s, que é insensível à diferença entre maiúsculas e minúsculas. Embora o Gitea possa trabalhar com ela, pode haver alguns casos raros que não funcionem como esperado. self_check.database_inconsistent_collation_columns=A base de dados está a usar a colação %s, mas estas colunas estão a usar colações diferentes. Isso poderá causar alguns problemas inesperados. diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index 74c4c9c935..818dad1147 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -2634,7 +2634,6 @@ total=Всего: %d dashboard.new_version_hint=Доступна новая версия Gitea %s, вы используете %s. Более подробную информацию читайте в <a target="_blank" rel="noreferrer" href="https://blog.gitea.io">блоге</a>. dashboard.statistic=Статистика -dashboard.operations=Операции dashboard.system_status=Состояние системы dashboard.operation_name=Имя операции dashboard.operation_switch=Переключить diff --git a/options/locale/locale_si-LK.ini b/options/locale/locale_si-LK.ini index 7e82cfe3d6..99559802c5 100644 --- a/options/locale/locale_si-LK.ini +++ b/options/locale/locale_si-LK.ini @@ -2024,7 +2024,6 @@ last_page=පසුගිය total=මුළු: %d dashboard.statistic=සාරාංශය -dashboard.operations=නඩත්තු මෙහෙයුම් dashboard.system_status=පද්ධතියේ තත්වය dashboard.operation_name=මෙහෙයුමේ නම dashboard.operation_switch=මාරුවන්න diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini index e48d84ff78..9234e9aa58 100644 --- a/options/locale/locale_sv-SE.ini +++ b/options/locale/locale_sv-SE.ini @@ -1647,7 +1647,6 @@ last_page=Sista total=Totalt: %d dashboard.statistic=Översikt -dashboard.operations=Operationer för underhåll dashboard.system_status=Status dashboard.operation_name=Operationsnamn dashboard.operation_switch=Byt till diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index 5a5036f87d..119e1ef150 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -2687,7 +2687,6 @@ settings=Yönetici Ayarları dashboard.new_version_hint=Gitea %s şimdi hazır, %s çalıştırıyorsunuz. Ayrıntılar için <a target="_blank" rel="noreferrer" href="https://blog.gitea.io">blog</a>'a bakabilirsiniz. dashboard.statistic=Özet -dashboard.operations=Bakım İşlemleri dashboard.system_status=Sistem Durumu dashboard.operation_name=İşlem Adı dashboard.operation_switch=Geç diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini index 09561a7902..e8a3acedda 100644 --- a/options/locale/locale_uk-UA.ini +++ b/options/locale/locale_uk-UA.ini @@ -2074,7 +2074,6 @@ last_page=Остання total=Разом: %d dashboard.statistic=Підсумок -dashboard.operations=Технічне обслуговування dashboard.system_status=Статус системи dashboard.operation_name=Назва операції dashboard.operation_switch=Перемкнути diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 406e9ac8f2..01058d48d2 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -2711,7 +2711,6 @@ settings=管理设置 dashboard.new_version_hint=Gitea %s 现已可用,您正在运行 %s。查看 <a target="_blank" rel="noreferrer" href="https://blog.gitea.io">博客</a> 了解详情。 dashboard.statistic=摘要 -dashboard.operations=维护操作 dashboard.system_status=系统状态 dashboard.operation_name=操作名称 dashboard.operation_switch=开关 diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini index 0511fa44ae..0447a7d8b7 100644 --- a/options/locale/locale_zh-TW.ini +++ b/options/locale/locale_zh-TW.ini @@ -2439,7 +2439,6 @@ total=總計:%d dashboard.new_version_hint=現已推出 Gitea %s,您正在執行 %s。詳情請參閱<a target="_blank" rel="noreferrer" href="https://blog.gitea.io">部落格</a>的說明。 dashboard.statistic=摘要 -dashboard.operations=維護作業 dashboard.system_status=系統狀態 dashboard.operation_name=作業名稱 dashboard.operation_switch=開關 From b4825670596fe745cebdcc63a8ead4388602d42c Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Tue, 2 Apr 2024 16:02:05 +0800 Subject: [PATCH 028/370] Add unique index for project_issue to prevent duplicate data (#30190) Fix #27639 --- .../project_issue.yml | 9 ++++ models/migrations/migrations.go | 5 ++ models/migrations/v1_23/main_test.go | 14 +++++ models/migrations/v1_23/v294.go | 53 +++++++++++++++++++ models/migrations/v1_23/v294_test.go | 52 ++++++++++++++++++ 5 files changed, 133 insertions(+) create mode 100644 models/migrations/fixtures/Test_AddUniqueIndexForProjectIssue/project_issue.yml create mode 100644 models/migrations/v1_23/main_test.go create mode 100644 models/migrations/v1_23/v294.go create mode 100644 models/migrations/v1_23/v294_test.go diff --git a/models/migrations/fixtures/Test_AddUniqueIndexForProjectIssue/project_issue.yml b/models/migrations/fixtures/Test_AddUniqueIndexForProjectIssue/project_issue.yml new file mode 100644 index 0000000000..6feaeb39f0 --- /dev/null +++ b/models/migrations/fixtures/Test_AddUniqueIndexForProjectIssue/project_issue.yml @@ -0,0 +1,9 @@ +- + id: 1 + project_id: 1 + issue_id: 1 + +- + id: 2 + project_id: 1 + issue_id: 1 diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 0daa799ff6..387cd96a53 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -21,6 +21,7 @@ import ( "code.gitea.io/gitea/models/migrations/v1_20" "code.gitea.io/gitea/models/migrations/v1_21" "code.gitea.io/gitea/models/migrations/v1_22" + "code.gitea.io/gitea/models/migrations/v1_23" "code.gitea.io/gitea/models/migrations/v1_6" "code.gitea.io/gitea/models/migrations/v1_7" "code.gitea.io/gitea/models/migrations/v1_8" @@ -572,6 +573,10 @@ var migrations = []Migration{ NewMigration("Ensure every project has exactly one default column - No Op", noopMigration), // v293 -> v294 NewMigration("Ensure every project has exactly one default column", v1_22.CheckProjectColumnsConsistency), + + // Gitea 1.22.0 ends at 294 + + NewMigration("Add unique index for project issue table", v1_23.AddUniqueIndexForProjectIssue), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v1_23/main_test.go b/models/migrations/v1_23/main_test.go new file mode 100644 index 0000000000..b7948bd4dd --- /dev/null +++ b/models/migrations/v1_23/main_test.go @@ -0,0 +1,14 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_23 //nolint + +import ( + "testing" + + "code.gitea.io/gitea/models/migrations/base" +) + +func TestMain(m *testing.M) { + base.MainTest(m) +} diff --git a/models/migrations/v1_23/v294.go b/models/migrations/v1_23/v294.go new file mode 100644 index 0000000000..f2a54f6d23 --- /dev/null +++ b/models/migrations/v1_23/v294.go @@ -0,0 +1,53 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_23 //nolint + +import ( + "fmt" + + "xorm.io/xorm" + "xorm.io/xorm/schemas" +) + +// AddUniqueIndexForProjectIssue adds unique indexes for project issue table +func AddUniqueIndexForProjectIssue(x *xorm.Engine) error { + // remove possible duplicated records in table project_issue + type result struct { + IssueID int64 + ProjectID int64 + Cnt int + } + var results []result + if err := x.Select("issue_id, project_id, count(*) as cnt"). + Table("project_issue"). + GroupBy("issue_id, project_id"). + Having("count(*) > 1"). + Find(&results); err != nil { + return err + } + for _, r := range results { + if x.Dialect().URI().DBType == schemas.MSSQL { + if _, err := x.Exec(fmt.Sprintf("delete from project_issue where id in (SELECT top %d id FROM project_issue WHERE issue_id = ? and project_id = ?)", r.Cnt-1), r.IssueID, r.ProjectID); err != nil { + return err + } + } else { + var ids []int64 + if err := x.SQL("SELECT id FROM project_issue WHERE issue_id = ? and project_id = ? limit ?", r.IssueID, r.ProjectID, r.Cnt-1).Find(&ids); err != nil { + return err + } + if _, err := x.Table("project_issue").In("id", ids).Delete(); err != nil { + return err + } + } + } + + // add unique index for project_issue table + type ProjectIssue struct { //revive:disable-line:exported + ID int64 `xorm:"pk autoincr"` + IssueID int64 `xorm:"INDEX unique(s)"` + ProjectID int64 `xorm:"INDEX unique(s)"` + } + + return x.Sync(new(ProjectIssue)) +} diff --git a/models/migrations/v1_23/v294_test.go b/models/migrations/v1_23/v294_test.go new file mode 100644 index 0000000000..d9a44ad866 --- /dev/null +++ b/models/migrations/v1_23/v294_test.go @@ -0,0 +1,52 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_23 //nolint + +import ( + "slices" + "testing" + + "code.gitea.io/gitea/models/migrations/base" + + "github.com/stretchr/testify/assert" + "xorm.io/xorm/schemas" +) + +func Test_AddUniqueIndexForProjectIssue(t *testing.T) { + type ProjectIssue struct { //revive:disable-line:exported + ID int64 `xorm:"pk autoincr"` + IssueID int64 `xorm:"INDEX"` + ProjectID int64 `xorm:"INDEX"` + } + + // Prepare and load the testing database + x, deferable := base.PrepareTestEnv(t, 0, new(ProjectIssue)) + defer deferable() + if x == nil || t.Failed() { + return + } + + cnt, err := x.Table("project_issue").Where("project_id=1 AND issue_id=1").Count() + assert.NoError(t, err) + assert.EqualValues(t, 2, cnt) + + assert.NoError(t, AddUniqueIndexForProjectIssue(x)) + + cnt, err = x.Table("project_issue").Where("project_id=1 AND issue_id=1").Count() + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + tables, err := x.DBMetas() + assert.NoError(t, err) + assert.EqualValues(t, 1, len(tables)) + found := false + for _, index := range tables[0].Indexes { + if index.Type == schemas.UniqueType { + found = true + slices.Equal(index.Cols, []string{"project_id", "issue_id"}) + break + } + } + assert.True(t, found) +} From 944c76e78423405a33450eb3d07cd2b772f4a81c Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Tue, 2 Apr 2024 13:48:07 +0200 Subject: [PATCH 029/370] Fix spacing in issue navbar (#30238) Create a new `issue-navbar` class specifically for this bar, previous class used in many places and I thought I had them all removed, but not this one. Fixes: https://github.com/go-gitea/gitea/issues/30226 --- templates/repo/issue/choose.tmpl | 2 +- templates/repo/issue/labels.tmpl | 2 +- templates/repo/issue/milestone_new.tmpl | 2 +- web_src/css/modules/navbar.css | 5 +++++ 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/templates/repo/issue/choose.tmpl b/templates/repo/issue/choose.tmpl index a8037482be..38cf9e485f 100644 --- a/templates/repo/issue/choose.tmpl +++ b/templates/repo/issue/choose.tmpl @@ -3,7 +3,7 @@ {{template "repo/header" .}} <div class="ui container"> {{template "base/alert" .}} - <div class="navbar"> + <div class="issue-navbar"> {{template "repo/issue/navbar" .}} </div> <div class="divider"></div> diff --git a/templates/repo/issue/labels.tmpl b/templates/repo/issue/labels.tmpl index 6dc7e4ef64..230777efcc 100644 --- a/templates/repo/issue/labels.tmpl +++ b/templates/repo/issue/labels.tmpl @@ -2,7 +2,7 @@ <div role="main" aria-label="{{.Title}}" class="page-content repository labels"> {{template "repo/header" .}} <div class="ui container"> - <div class="navbar tw-mb-4"> + <div class="issue-navbar tw-mb-4"> {{template "repo/issue/navbar" .}} {{if and (or .CanWriteIssues .CanWritePulls) (not .Repository.IsArchived)}} <button class="ui small primary new-label button">{{ctx.Locale.Tr "repo.issues.new_label"}}</button> diff --git a/templates/repo/issue/milestone_new.tmpl b/templates/repo/issue/milestone_new.tmpl index 7a56d73ac9..9f32df00e3 100644 --- a/templates/repo/issue/milestone_new.tmpl +++ b/templates/repo/issue/milestone_new.tmpl @@ -2,7 +2,7 @@ <div role="main" aria-label="{{.Title}}" class="page-content repository new milestone"> {{template "repo/header" .}} <div class="ui container"> - <div class="navbar"> + <div class="issue-navbar"> {{template "repo/issue/navbar" .}} {{if and (or .CanWriteIssues .CanWritePulls) .PageIsEditMilestone}} <div class="ui right floated secondary menu"> diff --git a/web_src/css/modules/navbar.css b/web_src/css/modules/navbar.css index f8553d7cf0..d7aa197e02 100644 --- a/web_src/css/modules/navbar.css +++ b/web_src/css/modules/navbar.css @@ -140,3 +140,8 @@ .secondary-nav { background: var(--color-secondary-nav-bg) !important; /* important because of .ui.secondary.menu */ } + +.issue-navbar { + display: flex; + justify-content: space-between; +} From eb505b128c7b9b2459f2a5d20b5740017125178b Mon Sep 17 00:00:00 2001 From: KN4CK3R <admin@oldschoolhack.me> Date: Tue, 2 Apr 2024 17:50:57 +0200 Subject: [PATCH 030/370] Fix missing 0 prefix of GPG key id (#30245) Fixes #30235 If the key id "front" byte has a single digit, `%X` is missing the 0 prefix. ` 38D1A3EADDBEA9C` instead of `038D1A3EADDBEA9C` When using the `IssuerFingerprint` slice `%X` is enough but I changed it to `%016X` too to be consistent. --- models/asymkey/gpg_key_commit_verification.go | 8 +------- models/asymkey/gpg_key_common.go | 10 ++++++++++ models/asymkey/gpg_key_test.go | 12 ++++++++++++ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/models/asymkey/gpg_key_commit_verification.go b/models/asymkey/gpg_key_commit_verification.go index 83fbab5d36..06ac31bc6f 100644 --- a/models/asymkey/gpg_key_commit_verification.go +++ b/models/asymkey/gpg_key_commit_verification.go @@ -139,13 +139,7 @@ func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerific } } - keyID := "" - if sig.IssuerKeyId != nil && (*sig.IssuerKeyId) != 0 { - keyID = fmt.Sprintf("%X", *sig.IssuerKeyId) - } - if keyID == "" && sig.IssuerFingerprint != nil && len(sig.IssuerFingerprint) > 0 { - keyID = fmt.Sprintf("%X", sig.IssuerFingerprint[12:20]) - } + keyID := tryGetKeyIDFromSignature(sig) defaultReason := NoKeyFound // First check if the sig has a keyID and if so just look at that diff --git a/models/asymkey/gpg_key_common.go b/models/asymkey/gpg_key_common.go index b02be2851a..9c015582f1 100644 --- a/models/asymkey/gpg_key_common.go +++ b/models/asymkey/gpg_key_common.go @@ -134,3 +134,13 @@ func extractSignature(s string) (*packet.Signature, error) { } return sig, nil } + +func tryGetKeyIDFromSignature(sig *packet.Signature) string { + if sig.IssuerKeyId != nil && (*sig.IssuerKeyId) != 0 { + return fmt.Sprintf("%016X", *sig.IssuerKeyId) + } + if sig.IssuerFingerprint != nil && len(sig.IssuerFingerprint) > 0 { + return fmt.Sprintf("%016X", sig.IssuerFingerprint[12:20]) + } + return "" +} diff --git a/models/asymkey/gpg_key_test.go b/models/asymkey/gpg_key_test.go index dee74bc281..d3fbb01d82 100644 --- a/models/asymkey/gpg_key_test.go +++ b/models/asymkey/gpg_key_test.go @@ -11,7 +11,9 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" + "github.com/keybase/go-crypto/openpgp/packet" "github.com/stretchr/testify/assert" ) @@ -391,3 +393,13 @@ epiDVQ== assert.Equal(t, time.Unix(1586105389, 0), expire) } } + +func TestTryGetKeyIDFromSignature(t *testing.T) { + assert.Empty(t, tryGetKeyIDFromSignature(&packet.Signature{})) + assert.Equal(t, "038D1A3EADDBEA9C", tryGetKeyIDFromSignature(&packet.Signature{ + IssuerKeyId: util.ToPointer(uint64(0x38D1A3EADDBEA9C)), + })) + assert.Equal(t, "038D1A3EADDBEA9C", tryGetKeyIDFromSignature(&packet.Signature{ + IssuerFingerprint: []uint8{0xb, 0x23, 0x24, 0xc7, 0xe6, 0xfe, 0x4f, 0x3a, 0x6, 0x26, 0xc1, 0x21, 0x3, 0x8d, 0x1a, 0x3e, 0xad, 0xdb, 0xea, 0x9c}, + })) +} From ca5c895efb91d2c2f17a83460e1753101c6f6bb1 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Wed, 3 Apr 2024 01:48:27 +0800 Subject: [PATCH 031/370] Render embedded code preview by permlink in markdown (#30234) The permlink in markdown will be rendered as a code preview block, like GitHub Co-authored-by: silverwind <me@silverwind.io> --- modules/charset/escape_test.go | 6 +- modules/csv/csv_test.go | 4 +- modules/indexer/code/search.go | 16 +-- modules/markup/html.go | 1 + modules/markup/html_codepreview.go | 92 ++++++++++++++ modules/markup/html_codepreview_test.go | 34 +++++ modules/markup/renderer.go | 3 + modules/markup/sanitizer.go | 15 +++ modules/translation/mock.go | 18 ++- options/locale/locale_en-US.ini | 2 + routers/web/repo/search.go | 2 +- routers/web/repo/wiki_test.go | 2 +- services/contexttest/context_tests.go | 1 + services/markup/main_test.go | 2 +- services/markup/processorhelper.go | 2 + .../markup/processorhelper_codepreview.go | 117 ++++++++++++++++++ .../processorhelper_codepreview_test.go | 83 +++++++++++++ templates/base/markup_codepreview.tmpl | 25 ++++ web_src/css/base.css | 5 +- web_src/css/index.css | 1 + web_src/css/markup/codepreview.css | 36 ++++++ web_src/css/markup/content.css | 4 +- 22 files changed, 450 insertions(+), 21 deletions(-) create mode 100644 modules/markup/html_codepreview.go create mode 100644 modules/markup/html_codepreview_test.go create mode 100644 services/markup/processorhelper_codepreview.go create mode 100644 services/markup/processorhelper_codepreview_test.go create mode 100644 templates/base/markup_codepreview.tmpl create mode 100644 web_src/css/markup/codepreview.css diff --git a/modules/charset/escape_test.go b/modules/charset/escape_test.go index a353ced631..9d796a0c18 100644 --- a/modules/charset/escape_test.go +++ b/modules/charset/escape_test.go @@ -4,6 +4,7 @@ package charset import ( + "regexp" "strings" "testing" @@ -156,13 +157,16 @@ func TestEscapeControlReader(t *testing.T) { tests = append(tests, test) } + re := regexp.MustCompile(`repo.ambiguous_character:\d+,\d+`) // simplify the output for the tests, remove the translation variants for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { output := &strings.Builder{} status, err := EscapeControlReader(strings.NewReader(tt.text), output, &translation.MockLocale{}) assert.NoError(t, err) assert.Equal(t, tt.status, *status) - assert.Equal(t, tt.result, output.String()) + outStr := output.String() + outStr = re.ReplaceAllString(outStr, "repo.ambiguous_character") + assert.Equal(t, tt.result, outStr) }) } } diff --git a/modules/csv/csv_test.go b/modules/csv/csv_test.go index f6e782a5a4..3ddb47acbb 100644 --- a/modules/csv/csv_test.go +++ b/modules/csv/csv_test.go @@ -561,14 +561,14 @@ func TestFormatError(t *testing.T) { err: &csv.ParseError{ Err: csv.ErrFieldCount, }, - expectedMessage: "repo.error.csv.invalid_field_count", + expectedMessage: "repo.error.csv.invalid_field_count:0", expectsError: false, }, { err: &csv.ParseError{ Err: csv.ErrBareQuote, }, - expectedMessage: "repo.error.csv.unexpected", + expectedMessage: "repo.error.csv.unexpected:0,0", expectsError: false, }, { diff --git a/modules/indexer/code/search.go b/modules/indexer/code/search.go index 5f35e8073b..74c957dde6 100644 --- a/modules/indexer/code/search.go +++ b/modules/indexer/code/search.go @@ -22,7 +22,7 @@ type Result struct { UpdatedUnix timeutil.TimeStamp Language string Color string - Lines []ResultLine + Lines []*ResultLine } type ResultLine struct { @@ -70,16 +70,18 @@ func writeStrings(buf *bytes.Buffer, strs ...string) error { return nil } -func HighlightSearchResultCode(filename string, lineNums []int, code string) []ResultLine { +func HighlightSearchResultCode(filename, language string, lineNums []int, code string) []*ResultLine { // we should highlight the whole code block first, otherwise it doesn't work well with multiple line highlighting - hl, _ := highlight.Code(filename, "", code) + hl, _ := highlight.Code(filename, language, code) highlightedLines := strings.Split(string(hl), "\n") // The lineNums outputted by highlight.Code might not match the original lineNums, because "highlight" removes the last `\n` - lines := make([]ResultLine, min(len(highlightedLines), len(lineNums))) + lines := make([]*ResultLine, min(len(highlightedLines), len(lineNums))) for i := 0; i < len(lines); i++ { - lines[i].Num = lineNums[i] - lines[i].FormattedContent = template.HTML(highlightedLines[i]) + lines[i] = &ResultLine{ + Num: lineNums[i], + FormattedContent: template.HTML(highlightedLines[i]), + } } return lines } @@ -122,7 +124,7 @@ func searchResult(result *internal.SearchResult, startIndex, endIndex int) (*Res UpdatedUnix: result.UpdatedUnix, Language: result.Language, Color: result.Color, - Lines: HighlightSearchResultCode(result.Filename, lineNums, formattedLinesBuffer.String()), + Lines: HighlightSearchResultCode(result.Filename, result.Language, lineNums, formattedLinesBuffer.String()), }, nil } diff --git a/modules/markup/html.go b/modules/markup/html.go index 21bd6206e0..56aa1cb49c 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -171,6 +171,7 @@ type processor func(ctx *RenderContext, node *html.Node) var defaultProcessors = []processor{ fullIssuePatternProcessor, comparePatternProcessor, + codePreviewPatternProcessor, fullHashPatternProcessor, shortLinkProcessor, linkProcessor, diff --git a/modules/markup/html_codepreview.go b/modules/markup/html_codepreview.go new file mode 100644 index 0000000000..d9da24ea34 --- /dev/null +++ b/modules/markup/html_codepreview.go @@ -0,0 +1,92 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package markup + +import ( + "html/template" + "net/url" + "regexp" + "strconv" + "strings" + + "code.gitea.io/gitea/modules/httplib" + "code.gitea.io/gitea/modules/log" + + "golang.org/x/net/html" +) + +// codePreviewPattern matches "http://domain/.../{owner}/{repo}/src/commit/{commit}/{filepath}#L10-L20" +var codePreviewPattern = regexp.MustCompile(`https?://\S+/([^\s/]+)/([^\s/]+)/src/commit/([0-9a-f]{7,64})(/\S+)#(L\d+(-L\d+)?)`) + +type RenderCodePreviewOptions struct { + FullURL string + OwnerName string + RepoName string + CommitID string + FilePath string + + LineStart, LineStop int +} + +func renderCodeBlock(ctx *RenderContext, node *html.Node) (urlPosStart, urlPosStop int, htm template.HTML, err error) { + m := codePreviewPattern.FindStringSubmatchIndex(node.Data) + if m == nil { + return 0, 0, "", nil + } + + opts := RenderCodePreviewOptions{ + FullURL: node.Data[m[0]:m[1]], + OwnerName: node.Data[m[2]:m[3]], + RepoName: node.Data[m[4]:m[5]], + CommitID: node.Data[m[6]:m[7]], + FilePath: node.Data[m[8]:m[9]], + } + if !httplib.IsCurrentGiteaSiteURL(opts.FullURL) { + return 0, 0, "", nil + } + u, err := url.Parse(opts.FilePath) + if err != nil { + return 0, 0, "", err + } + opts.FilePath = strings.TrimPrefix(u.Path, "/") + + lineStartStr, lineStopStr, _ := strings.Cut(node.Data[m[10]:m[11]], "-") + lineStart, _ := strconv.Atoi(strings.TrimPrefix(lineStartStr, "L")) + lineStop, _ := strconv.Atoi(strings.TrimPrefix(lineStopStr, "L")) + opts.LineStart, opts.LineStop = lineStart, lineStop + h, err := DefaultProcessorHelper.RenderRepoFileCodePreview(ctx.Ctx, opts) + return m[0], m[1], h, err +} + +func codePreviewPatternProcessor(ctx *RenderContext, node *html.Node) { + for node != nil { + if node.Type != html.TextNode { + node = node.NextSibling + continue + } + urlPosStart, urlPosEnd, h, err := renderCodeBlock(ctx, node) + if err != nil || h == "" { + if err != nil { + log.Error("Unable to render code preview: %v", err) + } + node = node.NextSibling + continue + } + next := node.NextSibling + textBefore := node.Data[:urlPosStart] + textAfter := node.Data[urlPosEnd:] + // "textBefore" could be empty if there is only a URL in the text node, then an empty node (p, or li) will be left here. + // However, the empty node can't be simply removed, because: + // 1. the following processors will still try to access it (need to double-check undefined behaviors) + // 2. the new node is inserted as "<p>{TextBefore}<div NewNode/>{TextAfter}</p>" (the parent could also be "li") + // then it is resolved as: "<p>{TextBefore}</p><div NewNode/><p>{TextAfter}</p>", + // so unless it could correctly replace the parent "p/li" node, it is very difficult to eliminate the "TextBefore" empty node. + node.Data = textBefore + node.Parent.InsertBefore(&html.Node{Type: html.RawNode, Data: string(h)}, next) + if textAfter != "" { + node.Parent.InsertBefore(&html.Node{Type: html.TextNode, Data: textAfter}, next) + } + node = next + } +} diff --git a/modules/markup/html_codepreview_test.go b/modules/markup/html_codepreview_test.go new file mode 100644 index 0000000000..d33630d040 --- /dev/null +++ b/modules/markup/html_codepreview_test.go @@ -0,0 +1,34 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package markup_test + +import ( + "context" + "html/template" + "strings" + "testing" + + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/markup" + + "github.com/stretchr/testify/assert" +) + +func TestRenderCodePreview(t *testing.T) { + markup.Init(&markup.ProcessorHelper{ + RenderRepoFileCodePreview: func(ctx context.Context, opts markup.RenderCodePreviewOptions) (template.HTML, error) { + return "<div>code preview</div>", nil + }, + }) + test := func(input, expected string) { + buffer, err := markup.RenderString(&markup.RenderContext{ + Ctx: git.DefaultContext, + Type: "markdown", + }, input) + assert.NoError(t, err) + assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) + } + test("http://localhost:3000/owner/repo/src/commit/0123456789/foo/bar.md#L10-L20", "<p><div>code preview</div></p>") + test("http://other/owner/repo/src/commit/0123456789/foo/bar.md#L10-L20", `<p><a href="http://other/owner/repo/src/commit/0123456789/foo/bar.md#L10-L20" rel="nofollow">http://other/owner/repo/src/commit/0123456789/foo/bar.md#L10-L20</a></p>`) +} diff --git a/modules/markup/renderer.go b/modules/markup/renderer.go index 0f0bf55740..005fcc278b 100644 --- a/modules/markup/renderer.go +++ b/modules/markup/renderer.go @@ -8,6 +8,7 @@ import ( "context" "errors" "fmt" + "html/template" "io" "net/url" "path/filepath" @@ -33,6 +34,8 @@ type ProcessorHelper struct { IsUsernameMentionable func(ctx context.Context, username string) bool ElementDir string // the direction of the elements, eg: "ltr", "rtl", "auto", default to no direction attribute + + RenderRepoFileCodePreview func(ctx context.Context, options RenderCodePreviewOptions) (template.HTML, error) } var DefaultProcessorHelper ProcessorHelper diff --git a/modules/markup/sanitizer.go b/modules/markup/sanitizer.go index 79a2ba0dfb..77fbdf4520 100644 --- a/modules/markup/sanitizer.go +++ b/modules/markup/sanitizer.go @@ -60,6 +60,21 @@ func createDefaultPolicy() *bluemonday.Policy { // For JS code copy and Mermaid loading state policy.AllowAttrs("class").Matching(regexp.MustCompile(`^code-block( is-loading)?$`)).OnElements("pre") + // For code preview + policy.AllowAttrs("class").Matching(regexp.MustCompile(`^code-preview-[-\w]+( file-content)?$`)).Globally() + policy.AllowAttrs("class").Matching(regexp.MustCompile(`^lines-num$`)).OnElements("td") + policy.AllowAttrs("data-line-number").OnElements("span") + policy.AllowAttrs("class").Matching(regexp.MustCompile(`^lines-code chroma$`)).OnElements("td") + policy.AllowAttrs("class").Matching(regexp.MustCompile(`^code-inner$`)).OnElements("code") + + // For code preview (unicode escape) + policy.AllowAttrs("class").Matching(regexp.MustCompile(`^file-view( unicode-escaped)?$`)).OnElements("table") + policy.AllowAttrs("class").Matching(regexp.MustCompile(`^lines-escape$`)).OnElements("td") + policy.AllowAttrs("class").Matching(regexp.MustCompile(`^toggle-escape-button btn interact-bg$`)).OnElements("a") // don't use button, button might submit a form + policy.AllowAttrs("class").Matching(regexp.MustCompile(`^(ambiguous-code-point|escaped-code-point|broken-code-point)$`)).OnElements("span") + policy.AllowAttrs("class").Matching(regexp.MustCompile(`^char$`)).OnElements("span") + policy.AllowAttrs("data-tooltip-content", "data-escaped").OnElements("span") + // For color preview policy.AllowAttrs("class").Matching(regexp.MustCompile(`^color-preview$`)).OnElements("span") diff --git a/modules/translation/mock.go b/modules/translation/mock.go index 18fbc1044a..f457271ea5 100644 --- a/modules/translation/mock.go +++ b/modules/translation/mock.go @@ -6,6 +6,7 @@ package translation import ( "fmt" "html/template" + "strings" ) // MockLocale provides a mocked locale without any translations @@ -19,18 +20,25 @@ func (l MockLocale) Language() string { return "en" } -func (l MockLocale) TrString(s string, _ ...any) string { - return s +func (l MockLocale) TrString(s string, args ...any) string { + return sprintAny(s, args...) } -func (l MockLocale) Tr(s string, a ...any) template.HTML { - return template.HTML(s) +func (l MockLocale) Tr(s string, args ...any) template.HTML { + return template.HTML(sprintAny(s, args...)) } func (l MockLocale) TrN(cnt any, key1, keyN string, args ...any) template.HTML { - return template.HTML(key1) + return template.HTML(sprintAny(key1, args...)) } func (l MockLocale) PrettyNumber(v any) string { return fmt.Sprint(v) } + +func sprintAny(s string, args ...any) string { + if len(args) == 0 { + return s + } + return s + ":" + fmt.Sprintf(strings.Repeat(",%v", len(args))[1:], args...) +} diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 39b9855186..0a3d12d7a4 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1233,6 +1233,8 @@ file_view_rendered = View Rendered file_view_raw = View Raw file_permalink = Permalink file_too_large = The file is too large to be shown. +code_preview_line_from_to = Lines %[1]d to %[2]d in %[3]s +code_preview_line_in = Line %[1]d in %[2]s invisible_runes_header = `This file contains invisible Unicode characters` invisible_runes_description = `This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.` ambiguous_runes_header = `This file contains ambiguous Unicode characters` diff --git a/routers/web/repo/search.go b/routers/web/repo/search.go index 9d65427b8f..46f0208453 100644 --- a/routers/web/repo/search.go +++ b/routers/web/repo/search.go @@ -81,7 +81,7 @@ func Search(ctx *context.Context) { // UpdatedUnix: not supported yet // Language: not supported yet // Color: not supported yet - Lines: code_indexer.HighlightSearchResultCode(r.Filename, r.LineNumbers, strings.Join(r.LineCodes, "\n")), + Lines: code_indexer.HighlightSearchResultCode(r.Filename, "", r.LineNumbers, strings.Join(r.LineCodes, "\n")), }) } } diff --git a/routers/web/repo/wiki_test.go b/routers/web/repo/wiki_test.go index 52e216e6a0..8b5207f9d9 100644 --- a/routers/web/repo/wiki_test.go +++ b/routers/web/repo/wiki_test.go @@ -145,7 +145,7 @@ func TestNewWikiPost_ReservedName(t *testing.T) { }) NewWikiPost(ctx) assert.EqualValues(t, http.StatusOK, ctx.Resp.Status()) - assert.EqualValues(t, ctx.Tr("repo.wiki.reserved_page"), ctx.Flash.ErrorMsg) + assert.EqualValues(t, ctx.Tr("repo.wiki.reserved_page", "_edit"), ctx.Flash.ErrorMsg) assertWikiNotExists(t, ctx.Repo.Repository, "_edit") } diff --git a/services/contexttest/context_tests.go b/services/contexttest/context_tests.go index d3e6de7efe..3064c56590 100644 --- a/services/contexttest/context_tests.go +++ b/services/contexttest/context_tests.go @@ -63,6 +63,7 @@ func MockContext(t *testing.T, reqPath string, opts ...MockContextOption) (*cont base.Locale = &translation.MockLocale{} ctx := context.NewWebContext(base, opt.Render, nil) + ctx.AppendContextValue(context.WebContextKey, ctx) ctx.PageData = map[string]any{} ctx.Data["PageStartTime"] = time.Now() chiCtx := chi.NewRouteContext() diff --git a/services/markup/main_test.go b/services/markup/main_test.go index 89fe3e7e34..5553ebc058 100644 --- a/services/markup/main_test.go +++ b/services/markup/main_test.go @@ -11,6 +11,6 @@ import ( func TestMain(m *testing.M) { unittest.MainTest(m, &unittest.TestOptions{ - FixtureFiles: []string{"user.yml"}, + FixtureFiles: []string{"user.yml", "repository.yml", "access.yml", "repo_unit.yml"}, }) } diff --git a/services/markup/processorhelper.go b/services/markup/processorhelper.go index a4378678a0..68487fb8db 100644 --- a/services/markup/processorhelper.go +++ b/services/markup/processorhelper.go @@ -14,6 +14,8 @@ import ( func ProcessorHelper() *markup.ProcessorHelper { return &markup.ProcessorHelper{ ElementDir: "auto", // set dir="auto" for necessary (eg: <p>, <h?>, etc) tags + + RenderRepoFileCodePreview: renderRepoFileCodePreview, IsUsernameMentionable: func(ctx context.Context, username string) bool { mentionedUser, err := user.GetUserByName(ctx, username) if err != nil { diff --git a/services/markup/processorhelper_codepreview.go b/services/markup/processorhelper_codepreview.go new file mode 100644 index 0000000000..ef95046128 --- /dev/null +++ b/services/markup/processorhelper_codepreview.go @@ -0,0 +1,117 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package markup + +import ( + "bufio" + "context" + "fmt" + "html/template" + "strings" + + "code.gitea.io/gitea/models/perm/access" + "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unit" + "code.gitea.io/gitea/modules/charset" + "code.gitea.io/gitea/modules/gitrepo" + "code.gitea.io/gitea/modules/indexer/code" + "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/setting" + gitea_context "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/repository/files" +) + +func renderRepoFileCodePreview(ctx context.Context, opts markup.RenderCodePreviewOptions) (template.HTML, error) { + opts.LineStop = max(opts.LineStop, opts.LineStart) + lineCount := opts.LineStop - opts.LineStart + 1 + if lineCount <= 0 || lineCount > 140 /* GitHub at most show 140 lines */ { + lineCount = 10 + opts.LineStop = opts.LineStart + lineCount + } + + dbRepo, err := repo.GetRepositoryByOwnerAndName(ctx, opts.OwnerName, opts.RepoName) + if err != nil { + return "", err + } + + webCtx, ok := ctx.Value(gitea_context.WebContextKey).(*gitea_context.Context) + if !ok { + return "", fmt.Errorf("context is not a web context") + } + doer := webCtx.Doer + + perms, err := access.GetUserRepoPermission(ctx, dbRepo, doer) + if err != nil { + return "", err + } + if !perms.CanRead(unit.TypeCode) { + return "", fmt.Errorf("no permission") + } + + gitRepo, err := gitrepo.OpenRepository(ctx, dbRepo) + if err != nil { + return "", err + } + defer gitRepo.Close() + + commit, err := gitRepo.GetCommit(opts.CommitID) + if err != nil { + return "", err + } + + language, _ := files.TryGetContentLanguage(gitRepo, opts.CommitID, opts.FilePath) + blob, err := commit.GetBlobByPath(opts.FilePath) + if err != nil { + return "", err + } + + if blob.Size() > setting.UI.MaxDisplayFileSize { + return "", fmt.Errorf("file is too large") + } + + dataRc, err := blob.DataAsync() + if err != nil { + return "", err + } + defer dataRc.Close() + + reader := bufio.NewReader(dataRc) + for i := 1; i < opts.LineStart; i++ { + if _, err = reader.ReadBytes('\n'); err != nil { + return "", err + } + } + + lineNums := make([]int, 0, lineCount) + lineCodes := make([]string, 0, lineCount) + for i := opts.LineStart; i <= opts.LineStop; i++ { + if line, err := reader.ReadString('\n'); err != nil && line == "" { + break + } else { + lineNums = append(lineNums, i) + lineCodes = append(lineCodes, line) + } + } + realLineStop := max(opts.LineStart, opts.LineStart+len(lineNums)-1) + highlightLines := code.HighlightSearchResultCode(opts.FilePath, language, lineNums, strings.Join(lineCodes, "")) + + escapeStatus := &charset.EscapeStatus{} + lineEscapeStatus := make([]*charset.EscapeStatus, len(highlightLines)) + for i, hl := range highlightLines { + lineEscapeStatus[i], hl.FormattedContent = charset.EscapeControlHTML(hl.FormattedContent, webCtx.Base.Locale, charset.RuneNBSP) + escapeStatus = escapeStatus.Or(lineEscapeStatus[i]) + } + + return webCtx.RenderToHTML("base/markup_codepreview", map[string]any{ + "FullURL": opts.FullURL, + "FilePath": opts.FilePath, + "LineStart": opts.LineStart, + "LineStop": realLineStop, + "RepoLink": dbRepo.Link(), + "CommitID": opts.CommitID, + "HighlightLines": highlightLines, + "EscapeStatus": escapeStatus, + "LineEscapeStatus": lineEscapeStatus, + }) +} diff --git a/services/markup/processorhelper_codepreview_test.go b/services/markup/processorhelper_codepreview_test.go new file mode 100644 index 0000000000..01db792925 --- /dev/null +++ b/services/markup/processorhelper_codepreview_test.go @@ -0,0 +1,83 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package markup + +import ( + "testing" + + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/templates" + "code.gitea.io/gitea/services/contexttest" + + "github.com/stretchr/testify/assert" +) + +func TestProcessorHelperCodePreview(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + ctx, _ := contexttest.MockContext(t, "/", contexttest.MockContextOption{Render: templates.HTMLRenderer()}) + htm, err := renderRepoFileCodePreview(ctx, markup.RenderCodePreviewOptions{ + FullURL: "http://full", + OwnerName: "user2", + RepoName: "repo1", + CommitID: "65f1bf27bc3bf70f64657658635e66094edbcb4d", + FilePath: "/README.md", + LineStart: 1, + LineStop: 2, + }) + assert.NoError(t, err) + assert.Equal(t, `<div class="code-preview-container file-content"> + <div class="code-preview-header"> + <a href="http://full" class="muted" rel="nofollow">/README.md</a> + repo.code_preview_line_from_to:1,2,<a href="/user2/repo1/src/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d" rel="nofollow">65f1bf27bc</a> + </div> + <table class="file-view"> + <tbody><tr> + <td class="lines-num"><span data-line-number="1"></span></td> + <td class="lines-code chroma"><code class="code-inner"><span class="gh"># repo1</code></td> + </tr><tr> + <td class="lines-num"><span data-line-number="2"></span></td> + <td class="lines-code chroma"><code class="code-inner"></span><span class="gh"></span></code></td> + </tr></tbody> + </table> +</div> +`, string(htm)) + + ctx, _ = contexttest.MockContext(t, "/", contexttest.MockContextOption{Render: templates.HTMLRenderer()}) + htm, err = renderRepoFileCodePreview(ctx, markup.RenderCodePreviewOptions{ + FullURL: "http://full", + OwnerName: "user2", + RepoName: "repo1", + CommitID: "65f1bf27bc3bf70f64657658635e66094edbcb4d", + FilePath: "/README.md", + LineStart: 1, + }) + assert.NoError(t, err) + assert.Equal(t, `<div class="code-preview-container file-content"> + <div class="code-preview-header"> + <a href="http://full" class="muted" rel="nofollow">/README.md</a> + repo.code_preview_line_in:1,<a href="/user2/repo1/src/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d" rel="nofollow">65f1bf27bc</a> + </div> + <table class="file-view"> + <tbody><tr> + <td class="lines-num"><span data-line-number="1"></span></td> + <td class="lines-code chroma"><code class="code-inner"><span class="gh"># repo1</code></td> + </tr></tbody> + </table> +</div> +`, string(htm)) + + ctx, _ = contexttest.MockContext(t, "/", contexttest.MockContextOption{Render: templates.HTMLRenderer()}) + _, err = renderRepoFileCodePreview(ctx, markup.RenderCodePreviewOptions{ + FullURL: "http://full", + OwnerName: "user15", + RepoName: "big_test_private_1", + CommitID: "65f1bf27bc3bf70f64657658635e66094edbcb4d", + FilePath: "/README.md", + LineStart: 1, + LineStop: 10, + }) + assert.ErrorContains(t, err, "no permission") +} diff --git a/templates/base/markup_codepreview.tmpl b/templates/base/markup_codepreview.tmpl new file mode 100644 index 0000000000..c65ab28406 --- /dev/null +++ b/templates/base/markup_codepreview.tmpl @@ -0,0 +1,25 @@ +<div class="code-preview-container file-content"> + <div class="code-preview-header"> + <a href="{{.FullURL}}" class="muted" rel="nofollow">{{.FilePath}}</a> + {{$link := HTMLFormat `<a href="%s/src/commit/%s" rel="nofollow">%s</a>` .RepoLink .CommitID (.CommitID | ShortSha) -}} + {{- if eq .LineStart .LineStop -}} + {{ctx.Locale.Tr "repo.code_preview_line_in" .LineStart $link}} + {{- else -}} + {{ctx.Locale.Tr "repo.code_preview_line_from_to" .LineStart .LineStop $link}} + {{- end}} + </div> + <table class="file-view"> + <tbody> + {{- range $idx, $line := .HighlightLines -}} + <tr> + <td class="lines-num"><span data-line-number="{{$line.Num}}"></span></td> + {{- if $.EscapeStatus.Escaped -}} + {{- $lineEscapeStatus := index $.LineEscapeStatus $idx -}} + <td class="lines-escape">{{if $lineEscapeStatus.Escaped}}<a href="#" class="toggle-escape-button btn interact-bg" title="{{if $lineEscapeStatus.HasInvisible}}{{ctx.Locale.Tr "repo.invisible_runes_line"}} {{end}}{{if $lineEscapeStatus.HasAmbiguous}}{{ctx.Locale.Tr "repo.ambiguous_runes_line"}}{{end}}"></a>{{end}}</td> + {{- end}} + <td class="lines-code chroma"><code class="code-inner">{{$line.FormattedContent}}</code></td> + </tr> + {{- end -}} + </tbody> + </table> +</div> diff --git a/web_src/css/base.css b/web_src/css/base.css index 96c90ee692..05ddba3223 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -1186,10 +1186,13 @@ overflow-menu .ui.label { content: attr(data-line-number); line-height: 20px !important; padding: 0 10px; - cursor: pointer; display: block; } +.code-view .lines-num span::after { + cursor: pointer; +} + .lines-type-marker { vertical-align: top; } diff --git a/web_src/css/index.css b/web_src/css/index.css index 40b1d3c881..7be8065dc7 100644 --- a/web_src/css/index.css +++ b/web_src/css/index.css @@ -41,6 +41,7 @@ @import "./markup/content.css"; @import "./markup/codecopy.css"; +@import "./markup/codepreview.css"; @import "./markup/asciicast.css"; @import "./chroma/base.css"; diff --git a/web_src/css/markup/codepreview.css b/web_src/css/markup/codepreview.css new file mode 100644 index 0000000000..9219544993 --- /dev/null +++ b/web_src/css/markup/codepreview.css @@ -0,0 +1,36 @@ +.markup .code-preview-container { + border: 1px solid var(--color-secondary); + border-radius: var(--border-radius); + margin: 0.25em 0; +} + +.markup .code-preview-container .code-preview-header { + border-bottom: 1px solid var(--color-secondary); + padding: 0.5em; + font-size: 12px; +} + +.markup .code-preview-container table { + width: 100%; + max-height: 100px; + overflow-y: auto; + margin: 0; /* override ".markup table {margin}" */ +} + +/* workaround to hide empty p before container - more details are in "html_codepreview.go" */ +.markup p:empty:has(+ .code-preview-container) { + display: none; +} + +/* override the polluted styles from the content.css: ".markup table ..." */ +.markup .code-preview-container table tr { + border: 0 !important; +} +.markup .code-preview-container table th, +.markup .code-preview-container table td { + border: 0 !important; + padding: 0 0 0 5px !important; +} +.markup .code-preview-container table tr:nth-child(2n) { + background: none !important; +} diff --git a/web_src/css/markup/content.css b/web_src/css/markup/content.css index 5eeef078a5..376d3030c7 100644 --- a/web_src/css/markup/content.css +++ b/web_src/css/markup/content.css @@ -382,7 +382,7 @@ text-align: center; } -.markup span.align-center span img +.markup span.align-center span img, .markup span.align-center span video { margin: 0 auto; text-align: center; @@ -432,7 +432,7 @@ text-align: right; } -.markup code, +.markup code:not(.code-inner), .markup tt { padding: 0.2em 0.4em; margin: 0; From e006451ab1509f8d6d43c5974387c05b26517392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Tiago?= <114936010+jmlt2002@users.noreply.github.com> Date: Tue, 2 Apr 2024 19:15:40 +0100 Subject: [PATCH 032/370] Fixes #27605: inline math blocks can't be preceeded/followed by alphanumerical characters (#30175) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Inline math blocks couldn't be preceeded or succeeded by alphanumerical characters due to changes introduced in PR #21171. Removed the condition that caused this (precedingCharacter condition) and added a new exit condition of the for-loop that checks if a specific '$' was escaped using '\' so that the math expression can be rendered as intended. - Additionally this PR fixes another bug where math blocks of the type '$xyz$abc$' where the dollar sign was not escaped by the user, generated an error (shown in the screenshots below) - Altered the tests to accomodate for the changes Former behaviour (from try.gitea.io):  Fixed behaviour (from my local build):  (Edit) Source code for the README.md file: ``` $x$ -$x$ $x$- a$xa$ $xa$a 1$xb$ $xb$1 $a a$b b$ a$b $a a$b b$ $a a\$b b$ ``` --------- Signed-off-by: João Tiago <joao.leal.tintas@tecnico.ulisboa.pt> Co-authored-by: Giteabot <teabot@gitea.io> --- modules/markup/markdown/markdown_test.go | 20 +++++++++++++++++-- modules/markup/markdown/math/inline_parser.go | 18 ++++++++++++----- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index c664758a27..a9c9024982 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -511,9 +511,17 @@ func TestMathBlock(t *testing.T) { `\(a\) \(b\)`, `<p><code class="language-math is-loading">a</code> <code class="language-math is-loading">b</code></p>` + nl, }, + { + `$a$.`, + `<p><code class="language-math is-loading">a</code>.</p>` + nl, + }, + { + `.$a$`, + `<p>.$a$</p>` + nl, + }, { `$a a$b b$`, - `<p><code class="language-math is-loading">a a$b b</code></p>` + nl, + `<p>$a a$b b$</p>` + nl, }, { `a a$b b`, @@ -521,7 +529,15 @@ func TestMathBlock(t *testing.T) { }, { `a$b $a a$b b$`, - `<p>a$b <code class="language-math is-loading">a a$b b</code></p>` + nl, + `<p>a$b $a a$b b$</p>` + nl, + }, + { + "a$x$", + `<p>a$x$</p>` + nl, + }, + { + "$x$a", + `<p>$x$a</p>` + nl, }, { "$$a$$", diff --git a/modules/markup/markdown/math/inline_parser.go b/modules/markup/markdown/math/inline_parser.go index 0ac25c2b2a..862234e69b 100644 --- a/modules/markup/markdown/math/inline_parser.go +++ b/modules/markup/markdown/math/inline_parser.go @@ -41,9 +41,12 @@ func (parser *inlineParser) Trigger() []byte { return parser.start[0:1] } +func isPunctuation(b byte) bool { + return b == '.' || b == '!' || b == '?' || b == ',' || b == ';' || b == ':' +} + func isAlphanumeric(b byte) bool { - // Github only cares about 0-9A-Za-z - return (b >= '0' && b <= '9') || (b >= 'A' && b <= 'Z') || (b >= 'a' && b <= 'z') + return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || (b >= '0' && b <= '9') } // Parse parses the current line and returns a result of parsing. @@ -56,7 +59,7 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser. } precedingCharacter := block.PrecendingCharacter() - if precedingCharacter < 256 && isAlphanumeric(byte(precedingCharacter)) { + if precedingCharacter < 256 && (isAlphanumeric(byte(precedingCharacter)) || isPunctuation(byte(precedingCharacter))) { // need to exclude things like `a$` from being considered a start return nil } @@ -75,14 +78,19 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser. ender += pos // Now we want to check the character at the end of our parser section - // that is ender + len(parser.end) + // that is ender + len(parser.end) and check if char before ender is '\' pos = ender + len(parser.end) if len(line) <= pos { break } - if !isAlphanumeric(line[pos]) { + suceedingCharacter := line[pos] + if !isPunctuation(suceedingCharacter) && !(suceedingCharacter == ' ') { + return nil + } + if line[ender-1] != '\\' { break } + // move the pointer onwards ender += len(parser.end) } From 6f4e2e79ffd1a244e9c266db19840a5bfda09119 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Wed, 3 Apr 2024 03:44:15 +0200 Subject: [PATCH 033/370] Show 12 lines in markup code preview (#30255) Show up to 12 lines instead of previous 5. --- web_src/css/markup/codepreview.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/css/markup/codepreview.css b/web_src/css/markup/codepreview.css index 9219544993..c9d19f5cc8 100644 --- a/web_src/css/markup/codepreview.css +++ b/web_src/css/markup/codepreview.css @@ -12,7 +12,7 @@ .markup .code-preview-container table { width: 100%; - max-height: 100px; + max-height: 240px; /* 12 lines at 20px per line */ overflow-y: auto; margin: 0; /* override ".markup table {margin}" */ } From b28d3a4218b1338ce6f683d11993081b722bae0a Mon Sep 17 00:00:00 2001 From: scribblemaniac <scribblemaniac@users.noreply.github.com> Date: Tue, 2 Apr 2024 19:47:13 -0600 Subject: [PATCH 034/370] Add -u git to docs when using docker exec with root installation (#29314) This fixes a minor issue in the documentation for SSH Container Passthrough for non-rootless installs. The non-rootless Dockerfile and docker-compose do not set `USER`/`user` instructions so `docker exec` will run as root by default. While running as root, gitea commands will refuse to execute, breaking these approaches. For containers built with the rootless instructions, `docker exec` will run as git by default so this is not necessary in that case. This issue was already discussed in #19065, but it does not appear this part of the issue was ever added to the documentation. --- docs/content/installation/with-docker.en-us.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/content/installation/with-docker.en-us.md b/docs/content/installation/with-docker.en-us.md index e67f5bccb2..e8a80f7c96 100644 --- a/docs/content/installation/with-docker.en-us.md +++ b/docs/content/installation/with-docker.en-us.md @@ -545,7 +545,7 @@ In this option, the idea is that the host SSH uses an `AuthorizedKeysCommand` in ```bash cat <<"EOF" | sudo tee /home/git/docker-shell #!/bin/sh - /usr/bin/docker exec -i --env SSH_ORIGINAL_COMMAND="$SSH_ORIGINAL_COMMAND" gitea sh "$@" + /usr/bin/docker exec -i -u git --env SSH_ORIGINAL_COMMAND="$SSH_ORIGINAL_COMMAND" gitea sh "$@" EOF sudo chmod +x /home/git/docker-shell sudo usermod -s /home/git/docker-shell git @@ -560,7 +560,7 @@ Add the following block to `/etc/ssh/sshd_config`, on the host: ```bash Match User git AuthorizedKeysCommandUser git - AuthorizedKeysCommand /usr/bin/docker exec -i gitea /usr/local/bin/gitea keys -c /data/gitea/conf/app.ini -e git -u %u -t %t -k %k + AuthorizedKeysCommand /usr/bin/docker exec -i -u git gitea /usr/local/bin/gitea keys -c /data/gitea/conf/app.ini -e git -u %u -t %t -k %k ``` (From 1.16.0 you will not need to set the `-c /data/gitea/conf/app.ini` option.) From 654cfd1dfbd3f3f1d94addee50b6fe2b018a49c3 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Wed, 3 Apr 2024 10:16:46 +0800 Subject: [PATCH 035/370] Refactor "dump" sub-command (#30240) Major changes: * Move some functions like "addReader" / "isSubDir" / "addRecursiveExclude" to a separate package, and add tests * Clarify the filename&dump type logic and add tests * Clarify the logger behavior and remove FIXME comments Co-authored-by: Giteabot <teabot@gitea.io> --- cmd/dump.go | 296 ++++++++-------------------------- modules/dump/dumper.go | 174 ++++++++++++++++++++ modules/dump/dumper_test.go | 113 +++++++++++++ modules/setting/log.go | 9 ++ modules/timeutil/timestamp.go | 3 +- modules/util/util.go | 8 + 6 files changed, 374 insertions(+), 229 deletions(-) create mode 100644 modules/dump/dumper.go create mode 100644 modules/dump/dumper_test.go diff --git a/cmd/dump.go b/cmd/dump.go index 69ecdcec12..da0a51d9ce 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -6,14 +6,13 @@ package cmd import ( "fmt" - "io" "os" "path" "path/filepath" "strings" - "time" "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/dump" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" @@ -25,89 +24,17 @@ import ( "github.com/urfave/cli/v2" ) -func addReader(w archiver.Writer, r io.ReadCloser, info os.FileInfo, customName string, verbose bool) error { - if verbose { - log.Info("Adding file %s", customName) - } - - return w.Write(archiver.File{ - FileInfo: archiver.FileInfo{ - FileInfo: info, - CustomName: customName, - }, - ReadCloser: r, - }) -} - -func addFile(w archiver.Writer, filePath, absPath string, verbose bool) error { - file, err := os.Open(absPath) - if err != nil { - return err - } - defer file.Close() - fileInfo, err := file.Stat() - if err != nil { - return err - } - - return addReader(w, file, fileInfo, filePath, verbose) -} - -func isSubdir(upper, lower string) (bool, error) { - if relPath, err := filepath.Rel(upper, lower); err != nil { - return false, err - } else if relPath == "." || !strings.HasPrefix(relPath, ".") { - return true, nil - } - return false, nil -} - -type outputType struct { - Enum []string - Default string - selected string -} - -func (o outputType) Join() string { - return strings.Join(o.Enum, ", ") -} - -func (o *outputType) Set(value string) error { - for _, enum := range o.Enum { - if enum == value { - o.selected = value - return nil - } - } - - return fmt.Errorf("allowed values are %s", o.Join()) -} - -func (o outputType) String() string { - if o.selected == "" { - return o.Default - } - return o.selected -} - -var outputTypeEnum = &outputType{ - Enum: []string{"zip", "tar", "tar.sz", "tar.gz", "tar.xz", "tar.bz2", "tar.br", "tar.lz4", "tar.zst"}, - Default: "zip", -} - // CmdDump represents the available dump sub-command. var CmdDump = &cli.Command{ - Name: "dump", - Usage: "Dump Gitea files and database", - Description: `Dump compresses all related files and database into zip file. -It can be used for backup and capture Gitea server image to send to maintainer`, - Action: runDump, + Name: "dump", + Usage: "Dump Gitea files and database", + Description: `Dump compresses all related files and database into zip file. It can be used for backup and capture Gitea server image to send to maintainer`, + Action: runDump, Flags: []cli.Flag{ &cli.StringFlag{ Name: "file", Aliases: []string{"f"}, - Value: fmt.Sprintf("gitea-dump-%d.zip", time.Now().Unix()), - Usage: "Name of the dump file which will be created. Supply '-' for stdout. See type for available types.", + Usage: `Name of the dump file which will be created, default to "gitea-dump-{time}.zip". Supply '-' for stdout. See type for available types.`, }, &cli.BoolFlag{ Name: "verbose", @@ -160,64 +87,52 @@ It can be used for backup and capture Gitea server image to send to maintainer`, Name: "skip-index", Usage: "Skip bleve index data", }, - &cli.GenericFlag{ + &cli.StringFlag{ Name: "type", - Value: outputTypeEnum, - Usage: fmt.Sprintf("Dump output format: %s", outputTypeEnum.Join()), + Usage: fmt.Sprintf(`Dump output format, default to "zip", supported types: %s`, strings.Join(dump.SupportedOutputTypes, ", ")), }, }, } func fatal(format string, args ...any) { - fmt.Fprintf(os.Stderr, format+"\n", args...) log.Fatal(format, args...) } func runDump(ctx *cli.Context) error { - var file *os.File - fileName := ctx.String("file") - outType := ctx.String("type") - if fileName == "-" { - file = os.Stdout - setupConsoleLogger(log.FATAL, log.CanColorStderr, os.Stderr) - } else { - for _, suffix := range outputTypeEnum.Enum { - if strings.HasSuffix(fileName, "."+suffix) { - fileName = strings.TrimSuffix(fileName, "."+suffix) - break - } - } - fileName += "." + outType - } setting.MustInstalled() - // make sure we are logging to the console no matter what the configuration tells us do to - // FIXME: don't use CfgProvider directly - if _, err := setting.CfgProvider.Section("log").NewKey("MODE", "console"); err != nil { - fatal("Setting logging mode to console failed: %v", err) - } - if _, err := setting.CfgProvider.Section("log.console").NewKey("STDERR", "true"); err != nil { - fatal("Setting console logger to stderr failed: %v", err) - } - - // Set loglevel to Warn if quiet-mode is requested - if ctx.Bool("quiet") { - if _, err := setting.CfgProvider.Section("log.console").NewKey("LEVEL", "Warn"); err != nil { - fatal("Setting console log-level failed: %v", err) - } - } - - if !setting.InstallLock { - log.Error("Is '%s' really the right config path?\n", setting.CustomConf) - return fmt.Errorf("gitea is not initialized") - } - setting.LoadSettings() // cannot access session settings otherwise - + quite := ctx.Bool("quiet") verbose := ctx.Bool("verbose") - if verbose && ctx.Bool("quiet") { - return fmt.Errorf("--quiet and --verbose cannot both be set") + if verbose && quite { + fatal("Option --quiet and --verbose cannot both be set") } + // outFileName is either "-" or a file name (will be made absolute) + outFileName, outType := dump.PrepareFileNameAndType(ctx.String("file"), ctx.String("type")) + if outType == "" { + fatal("Invalid output type") + } + + outFile := os.Stdout + if outFileName != "-" { + var err error + if outFileName, err = filepath.Abs(outFileName); err != nil { + fatal("Unable to get absolute path of dump file: %v", err) + } + if exist, _ := util.IsExist(outFileName); exist { + fatal("Dump file %q exists", outFileName) + } + if outFile, err = os.Create(outFileName); err != nil { + fatal("Unable to create dump file %q: %v", outFileName, err) + } + defer outFile.Close() + } + + setupConsoleLogger(util.Iif(quite, log.WARN, log.INFO), log.CanColorStderr, os.Stderr) + + setting.DisableLoggerInit() + setting.LoadSettings() // cannot access session settings otherwise + stdCtx, cancel := installSignals() defer cancel() @@ -226,44 +141,32 @@ func runDump(ctx *cli.Context) error { return err } - if err := storage.Init(); err != nil { + if err = storage.Init(); err != nil { return err } - if file == nil { - file, err = os.Create(fileName) - if err != nil { - fatal("Unable to open %s: %v", fileName, err) - } - } - defer file.Close() - - absFileName, err := filepath.Abs(fileName) - if err != nil { - return err - } - - var iface any - if fileName == "-" { - iface, err = archiver.ByExtension(fmt.Sprintf(".%s", outType)) - } else { - iface, err = archiver.ByExtension(fileName) - } + archiverGeneric, err := archiver.ByExtension("." + outType) if err != nil { fatal("Unable to get archiver for extension: %v", err) } - w, _ := iface.(archiver.Writer) - if err := w.Create(file); err != nil { + archiverWriter := archiverGeneric.(archiver.Writer) + if err := archiverWriter.Create(outFile); err != nil { fatal("Creating archiver.Writer failed: %v", err) } - defer w.Close() + defer archiverWriter.Close() + + dumper := &dump.Dumper{ + Writer: archiverWriter, + Verbose: verbose, + } + dumper.GlobalExcludeAbsPath(outFileName) if ctx.IsSet("skip-repository") && ctx.Bool("skip-repository") { log.Info("Skip dumping local repositories") } else { log.Info("Dumping local repositories... %s", setting.RepoRootPath) - if err := addRecursiveExclude(w, "repos", setting.RepoRootPath, []string{absFileName}, verbose); err != nil { + if err := dumper.AddRecursiveExclude("repos", setting.RepoRootPath, nil); err != nil { fatal("Failed to include repositories: %v", err) } @@ -276,8 +179,7 @@ func runDump(ctx *cli.Context) error { if err != nil { return err } - - return addReader(w, object, info, path.Join("data", "lfs", objPath), verbose) + return dumper.AddReader(object, info, path.Join("data", "lfs", objPath)) }); err != nil { fatal("Failed to dump LFS objects: %v", err) } @@ -310,15 +212,13 @@ func runDump(ctx *cli.Context) error { fatal("Failed to dump database: %v", err) } - if err := addFile(w, "gitea-db.sql", dbDump.Name(), verbose); err != nil { + if err = dumper.AddFile("gitea-db.sql", dbDump.Name()); err != nil { fatal("Failed to include gitea-db.sql: %v", err) } - if len(setting.CustomConf) > 0 { - log.Info("Adding custom configuration file from %s", setting.CustomConf) - if err := addFile(w, "app.ini", setting.CustomConf, verbose); err != nil { - fatal("Failed to include specified app.ini: %v", err) - } + log.Info("Adding custom configuration file from %s", setting.CustomConf) + if err = dumper.AddFile("app.ini", setting.CustomConf); err != nil { + fatal("Failed to include specified app.ini: %v", err) } if ctx.IsSet("skip-custom-dir") && ctx.Bool("skip-custom-dir") { @@ -326,8 +226,8 @@ func runDump(ctx *cli.Context) error { } else { customDir, err := os.Stat(setting.CustomPath) if err == nil && customDir.IsDir() { - if is, _ := isSubdir(setting.AppDataPath, setting.CustomPath); !is { - if err := addRecursiveExclude(w, "custom", setting.CustomPath, []string{absFileName}, verbose); err != nil { + if is, _ := dump.IsSubdir(setting.AppDataPath, setting.CustomPath); !is { + if err := dumper.AddRecursiveExclude("custom", setting.CustomPath, nil); err != nil { fatal("Failed to include custom: %v", err) } } else { @@ -364,8 +264,7 @@ func runDump(ctx *cli.Context) error { excludes = append(excludes, setting.Attachment.Storage.Path) excludes = append(excludes, setting.Packages.Storage.Path) excludes = append(excludes, setting.Log.RootPath) - excludes = append(excludes, absFileName) - if err := addRecursiveExclude(w, "data", setting.AppDataPath, excludes, verbose); err != nil { + if err := dumper.AddRecursiveExclude("data", setting.AppDataPath, excludes); err != nil { fatal("Failed to include data directory: %v", err) } } @@ -377,8 +276,7 @@ func runDump(ctx *cli.Context) error { if err != nil { return err } - - return addReader(w, object, info, path.Join("data", "attachments", objPath), verbose) + return dumper.AddReader(object, info, path.Join("data", "attachments", objPath)) }); err != nil { fatal("Failed to dump attachments: %v", err) } @@ -392,8 +290,7 @@ func runDump(ctx *cli.Context) error { if err != nil { return err } - - return addReader(w, object, info, path.Join("data", "packages", objPath), verbose) + return dumper.AddReader(object, info, path.Join("data", "packages", objPath)) }); err != nil { fatal("Failed to dump packages: %v", err) } @@ -409,80 +306,23 @@ func runDump(ctx *cli.Context) error { log.Error("Unable to check if %s exists. Error: %v", setting.Log.RootPath, err) } if isExist { - if err := addRecursiveExclude(w, "log", setting.Log.RootPath, []string{absFileName}, verbose); err != nil { + if err := dumper.AddRecursiveExclude("log", setting.Log.RootPath, nil); err != nil { fatal("Failed to include log: %v", err) } } } - if fileName != "-" { - if err = w.Close(); err != nil { - _ = util.Remove(fileName) - fatal("Failed to save %s: %v", fileName, err) + if outFileName == "-" { + log.Info("Finish dumping to stdout") + } else { + if err = archiverWriter.Close(); err != nil { + _ = os.Remove(outFileName) + fatal("Failed to save %q: %v", outFileName, err) } - - if err := os.Chmod(fileName, 0o600); err != nil { + if err = os.Chmod(outFileName, 0o600); err != nil { log.Info("Can't change file access permissions mask to 0600: %v", err) } - } - - if fileName != "-" { - log.Info("Finish dumping in file %s", fileName) - } else { - log.Info("Finish dumping to stdout") - } - - return nil -} - -// addRecursiveExclude zips absPath to specified insidePath inside writer excluding excludeAbsPath -func addRecursiveExclude(w archiver.Writer, insidePath, absPath string, excludeAbsPath []string, verbose bool) error { - absPath, err := filepath.Abs(absPath) - if err != nil { - return err - } - dir, err := os.Open(absPath) - if err != nil { - return err - } - defer dir.Close() - - files, err := dir.Readdir(0) - if err != nil { - return err - } - for _, file := range files { - currentAbsPath := filepath.Join(absPath, file.Name()) - currentInsidePath := path.Join(insidePath, file.Name()) - if file.IsDir() { - if !util.SliceContainsString(excludeAbsPath, currentAbsPath) { - if err := addFile(w, currentInsidePath, currentAbsPath, false); err != nil { - return err - } - if err = addRecursiveExclude(w, currentInsidePath, currentAbsPath, excludeAbsPath, verbose); err != nil { - return err - } - } - } else { - // only copy regular files and symlink regular files, skip non-regular files like socket/pipe/... - shouldAdd := file.Mode().IsRegular() - if !shouldAdd && file.Mode()&os.ModeSymlink == os.ModeSymlink { - target, err := filepath.EvalSymlinks(currentAbsPath) - if err != nil { - return err - } - targetStat, err := os.Stat(target) - if err != nil { - return err - } - shouldAdd = targetStat.Mode().IsRegular() - } - if shouldAdd { - if err = addFile(w, currentInsidePath, currentAbsPath, verbose); err != nil { - return err - } - } - } + log.Info("Finish dumping in file %s", outFileName) } return nil } diff --git a/modules/dump/dumper.go b/modules/dump/dumper.go new file mode 100644 index 0000000000..47730851fb --- /dev/null +++ b/modules/dump/dumper.go @@ -0,0 +1,174 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package dump + +import ( + "fmt" + "io" + "os" + "path" + "path/filepath" + "slices" + "strings" + + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/timeutil" + + "github.com/mholt/archiver/v3" +) + +var SupportedOutputTypes = []string{"zip", "tar", "tar.sz", "tar.gz", "tar.xz", "tar.bz2", "tar.br", "tar.lz4", "tar.zst"} + +// PrepareFileNameAndType prepares the output file name and type, if the type is not supported, it returns an empty "outType" +func PrepareFileNameAndType(argFile, argType string) (outFileName, outType string) { + if argFile == "" && argType == "" { + outType = SupportedOutputTypes[0] + outFileName = fmt.Sprintf("gitea-dump-%d.%s", timeutil.TimeStampNow(), outType) + } else if argFile == "" { + outType = argType + outFileName = fmt.Sprintf("gitea-dump-%d.%s", timeutil.TimeStampNow(), outType) + } else if argType == "" { + if filepath.Ext(outFileName) == "" { + outType = SupportedOutputTypes[0] + outFileName = argFile + } else { + for _, t := range SupportedOutputTypes { + if strings.HasSuffix(argFile, "."+t) { + outFileName = argFile + outType = t + } + } + } + } else { + outFileName, outType = argFile, argType + } + if !slices.Contains(SupportedOutputTypes, outType) { + return "", "" + } + return outFileName, outType +} + +func IsSubdir(upper, lower string) (bool, error) { + if relPath, err := filepath.Rel(upper, lower); err != nil { + return false, err + } else if relPath == "." || !strings.HasPrefix(relPath, ".") { + return true, nil + } + return false, nil +} + +type Dumper struct { + Writer archiver.Writer + Verbose bool + + globalExcludeAbsPaths []string +} + +func (dumper *Dumper) AddReader(r io.ReadCloser, info os.FileInfo, customName string) error { + if dumper.Verbose { + log.Info("Adding file %s", customName) + } + + return dumper.Writer.Write(archiver.File{ + FileInfo: archiver.FileInfo{ + FileInfo: info, + CustomName: customName, + }, + ReadCloser: r, + }) +} + +func (dumper *Dumper) AddFile(filePath, absPath string) error { + file, err := os.Open(absPath) + if err != nil { + return err + } + defer file.Close() + fileInfo, err := file.Stat() + if err != nil { + return err + } + return dumper.AddReader(file, fileInfo, filePath) +} + +func (dumper *Dumper) normalizeFilePath(absPath string) string { + absPath = filepath.Clean(absPath) + if setting.IsWindows { + absPath = strings.ToLower(absPath) + } + return absPath +} + +func (dumper *Dumper) GlobalExcludeAbsPath(absPaths ...string) { + for _, absPath := range absPaths { + dumper.globalExcludeAbsPaths = append(dumper.globalExcludeAbsPaths, dumper.normalizeFilePath(absPath)) + } +} + +func (dumper *Dumper) shouldExclude(absPath string, excludes []string) bool { + norm := dumper.normalizeFilePath(absPath) + return slices.Contains(dumper.globalExcludeAbsPaths, norm) || slices.Contains(excludes, norm) +} + +func (dumper *Dumper) AddRecursiveExclude(insidePath, absPath string, excludes []string) error { + excludes = slices.Clone(excludes) + for i := range excludes { + excludes[i] = dumper.normalizeFilePath(excludes[i]) + } + return dumper.addFileOrDir(insidePath, absPath, excludes) +} + +func (dumper *Dumper) addFileOrDir(insidePath, absPath string, excludes []string) error { + absPath, err := filepath.Abs(absPath) + if err != nil { + return err + } + dir, err := os.Open(absPath) + if err != nil { + return err + } + defer dir.Close() + + files, err := dir.Readdir(0) + if err != nil { + return err + } + for _, file := range files { + currentAbsPath := filepath.Join(absPath, file.Name()) + if dumper.shouldExclude(currentAbsPath, excludes) { + continue + } + + currentInsidePath := path.Join(insidePath, file.Name()) + if file.IsDir() { + if err := dumper.AddFile(currentInsidePath, currentAbsPath); err != nil { + return err + } + if err = dumper.addFileOrDir(currentInsidePath, currentAbsPath, excludes); err != nil { + return err + } + } else { + // only copy regular files and symlink regular files, skip non-regular files like socket/pipe/... + shouldAdd := file.Mode().IsRegular() + if !shouldAdd && file.Mode()&os.ModeSymlink == os.ModeSymlink { + target, err := filepath.EvalSymlinks(currentAbsPath) + if err != nil { + return err + } + targetStat, err := os.Stat(target) + if err != nil { + return err + } + shouldAdd = targetStat.Mode().IsRegular() + } + if shouldAdd { + if err = dumper.AddFile(currentInsidePath, currentAbsPath); err != nil { + return err + } + } + } + } + return nil +} diff --git a/modules/dump/dumper_test.go b/modules/dump/dumper_test.go new file mode 100644 index 0000000000..b444fa2de5 --- /dev/null +++ b/modules/dump/dumper_test.go @@ -0,0 +1,113 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package dump + +import ( + "fmt" + "io" + "os" + "path/filepath" + "sort" + "testing" + "time" + + "code.gitea.io/gitea/modules/timeutil" + + "github.com/mholt/archiver/v3" + "github.com/stretchr/testify/assert" +) + +func TestPrepareFileNameAndType(t *testing.T) { + defer timeutil.MockSet(time.Unix(1234, 0))() + test := func(argFile, argType, expFile, expType string) { + outFile, outType := PrepareFileNameAndType(argFile, argType) + assert.Equal(t, + fmt.Sprintf("outFile=%s, outType=%s", expFile, expType), + fmt.Sprintf("outFile=%s, outType=%s", outFile, outType), + fmt.Sprintf("argFile=%s, argType=%s", argFile, argType), + ) + } + + test("", "", "gitea-dump-1234.zip", "zip") + test("", "tar.gz", "gitea-dump-1234.tar.gz", "tar.gz") + test("", "no-such", "", "") + + test("-", "", "-", "zip") + test("-", "tar.gz", "-", "tar.gz") + test("-", "no-such", "", "") + + test("a", "", "a", "zip") + test("a", "tar.gz", "a", "tar.gz") + test("a", "no-such", "", "") + + test("a.zip", "", "a.zip", "zip") + test("a.zip", "tar.gz", "a.zip", "tar.gz") + test("a.zip", "no-such", "", "") + + test("a.tar.gz", "", "a.tar.gz", "zip") + test("a.tar.gz", "tar.gz", "a.tar.gz", "tar.gz") + test("a.tar.gz", "no-such", "", "") +} + +func TestIsSubDir(t *testing.T) { + tmpDir := t.TempDir() + _ = os.MkdirAll(filepath.Join(tmpDir, "include/sub"), 0o755) + + isSub, err := IsSubdir(filepath.Join(tmpDir, "include"), filepath.Join(tmpDir, "include")) + assert.NoError(t, err) + assert.True(t, isSub) + + isSub, err = IsSubdir(filepath.Join(tmpDir, "include"), filepath.Join(tmpDir, "include/sub")) + assert.NoError(t, err) + assert.True(t, isSub) + + isSub, err = IsSubdir(filepath.Join(tmpDir, "include/sub"), filepath.Join(tmpDir, "include")) + assert.NoError(t, err) + assert.False(t, isSub) +} + +type testWriter struct { + added []string +} + +func (t *testWriter) Create(out io.Writer) error { + return nil +} + +func (t *testWriter) Write(f archiver.File) error { + t.added = append(t.added, f.Name()) + return nil +} + +func (t *testWriter) Close() error { + return nil +} + +func TestDumper(t *testing.T) { + sortStrings := func(s []string) []string { + sort.Strings(s) + return s + } + tmpDir := t.TempDir() + _ = os.MkdirAll(filepath.Join(tmpDir, "include/exclude1"), 0o755) + _ = os.MkdirAll(filepath.Join(tmpDir, "include/exclude2"), 0o755) + _ = os.MkdirAll(filepath.Join(tmpDir, "include/sub"), 0o755) + _ = os.WriteFile(filepath.Join(tmpDir, "include/a"), nil, 0o644) + _ = os.WriteFile(filepath.Join(tmpDir, "include/sub/b"), nil, 0o644) + _ = os.WriteFile(filepath.Join(tmpDir, "include/exclude1/a-1"), nil, 0o644) + _ = os.WriteFile(filepath.Join(tmpDir, "include/exclude2/a-2"), nil, 0o644) + + tw := &testWriter{} + d := &Dumper{Writer: tw} + d.GlobalExcludeAbsPath(filepath.Join(tmpDir, "include/exclude1")) + err := d.AddRecursiveExclude("include", filepath.Join(tmpDir, "include"), []string{filepath.Join(tmpDir, "include/exclude2")}) + assert.NoError(t, err) + assert.EqualValues(t, sortStrings([]string{"include/a", "include/sub", "include/sub/b"}), sortStrings(tw.added)) + + tw = &testWriter{} + d = &Dumper{Writer: tw} + err = d.AddRecursiveExclude("include", filepath.Join(tmpDir, "include"), nil) + assert.NoError(t, err) + assert.EqualValues(t, sortStrings([]string{"include/exclude2", "include/exclude2/a-2", "include/a", "include/sub", "include/sub/b", "include/exclude1", "include/exclude1/a-1"}), sortStrings(tw.added)) +} diff --git a/modules/setting/log.go b/modules/setting/log.go index e404074b72..50c5779994 100644 --- a/modules/setting/log.go +++ b/modules/setting/log.go @@ -185,8 +185,13 @@ func InitLoggersForTest() { initAllLoggers() } +var initLoggerDisabled bool + // initAllLoggers creates all the log services func initAllLoggers() { + if initLoggerDisabled { + return + } initManagedLoggers(log.GetManager(), CfgProvider) golog.SetFlags(0) @@ -194,6 +199,10 @@ func initAllLoggers() { golog.SetOutput(log.LoggerToWriter(log.GetLogger(log.DEFAULT).Info)) } +func DisableLoggerInit() { + initLoggerDisabled = true +} + func initManagedLoggers(manager *log.LoggerManager, cfg ConfigProvider) { loadLogGlobalFrom(cfg) prepareLoggerConfig(cfg) diff --git a/modules/timeutil/timestamp.go b/modules/timeutil/timestamp.go index 27a80b6682..e77652b24f 100644 --- a/modules/timeutil/timestamp.go +++ b/modules/timeutil/timestamp.go @@ -21,8 +21,9 @@ var ( ) // MockSet sets the time to a mocked time.Time -func MockSet(now time.Time) { +func MockSet(now time.Time) func() { mockNow = now + return MockUnset } // MockUnset will unset the mocked time.Time diff --git a/modules/util/util.go b/modules/util/util.go index b6e730eb54..3921002e2a 100644 --- a/modules/util/util.go +++ b/modules/util/util.go @@ -213,6 +213,14 @@ func ToPointer[T any](val T) *T { return &val } +// Iif is an "inline-if", it returns "trueVal" if "condition" is true, otherwise "falseVal" +func Iif[T comparable](condition bool, trueVal, falseVal T) T { + if condition { + return trueVal + } + return falseVal +} + // IfZero returns "def" if "v" is a zero value, otherwise "v" func IfZero[T comparable](v, def T) T { var zero T From 1195be41a13d2198ab644c8558549edd74485510 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Wed, 3 Apr 2024 11:15:06 +0200 Subject: [PATCH 036/370] Replace coloris with vanilla-colorful (#30201) Found [a better color picker](https://github.com/web-padawan/vanilla-colorful) that [does not rely](https://github.com/mdbassit/Coloris/issues/139) on `querySelectorAll` or a global shared instance, and is also around a third of the size of the previous one. The popover is handled by tippy.js for which I introduced a new "bare" theme and it uses a new sibling-based mechanism which should prove useful later to create tippy popovers via HTML only. <img width="846" alt="Screenshot 2024-03-31 at 04 03 38" src="https://github.com/go-gitea/gitea/assets/115237/7639b911-a2d7-4f5c-bffd-a9d84561e747"> --- package-lock.json | 12 +-- package.json | 2 +- web_src/css/features/colorpicker.css | 141 +++------------------------ web_src/css/modules/tippy.css | 11 +++ web_src/js/features/colorpicker.js | 85 +++++++++++----- web_src/js/modules/tippy.js | 7 +- 6 files changed, 94 insertions(+), 164 deletions(-) diff --git a/package-lock.json b/package-lock.json index 21de79387f..a5f7a09ed0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,6 @@ "@github/relative-time-element": "4.4.0", "@github/text-expander-element": "2.6.1", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", - "@melloware/coloris": "0.23.0", "@primer/octicons": "19.9.0", "add-asset-webpack-plugin": "2.0.1", "ansi_up": "6.0.2", @@ -54,6 +53,7 @@ "toastify-js": "1.12.0", "tributejs": "5.1.3", "uint8-to-base64": "0.2.0", + "vanilla-colorful": "0.7.2", "vue": "3.4.21", "vue-bar-graph": "2.0.0", "vue-chartjs": "5.3.0", @@ -1290,11 +1290,6 @@ "@mcaptcha/core-glue": "^0.1.0-alpha-5" } }, - "node_modules/@melloware/coloris": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@melloware/coloris/-/coloris-0.23.0.tgz", - "integrity": "sha512-VGIjI9+IQwg6BHjIE10yl0K2ARYz5bsjn6BgFEs1y1ErPAQymgdoxwVcSVL4Ai5t9OVs8xaCB7JKHqFu2N96Ow==" - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -11853,6 +11848,11 @@ "builtins": "^1.0.3" } }, + "node_modules/vanilla-colorful": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/vanilla-colorful/-/vanilla-colorful-0.7.2.tgz", + "integrity": "sha512-z2YZusTFC6KnLERx1cgoIRX2CjPRP0W75N+3CC6gbvdX5Ch47rZkEMGO2Xnf+IEmi3RiFLxS18gayMA27iU7Kg==" + }, "node_modules/vite": { "version": "5.2.6", "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.6.tgz", diff --git a/package.json b/package.json index beea0e5d86..004ac9e2bf 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,6 @@ "@github/relative-time-element": "4.4.0", "@github/text-expander-element": "2.6.1", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", - "@melloware/coloris": "0.23.0", "@primer/octicons": "19.9.0", "add-asset-webpack-plugin": "2.0.1", "ansi_up": "6.0.2", @@ -53,6 +52,7 @@ "toastify-js": "1.12.0", "tributejs": "5.1.3", "uint8-to-base64": "0.2.0", + "vanilla-colorful": "0.7.2", "vue": "3.4.21", "vue-bar-graph": "2.0.0", "vue-chartjs": "5.3.0", diff --git a/web_src/css/features/colorpicker.css b/web_src/css/features/colorpicker.css index 0c651cfeb3..b7436783df 100644 --- a/web_src/css/features/colorpicker.css +++ b/web_src/css/features/colorpicker.css @@ -1,10 +1,6 @@ -/* This is a stripped-down version of coloris's CSS tailored to our needs. It does only include - opaqua colors, and if more features like opacity are needed, the CSS needs to be extended - based on upstream: https://github.com/mdbassit/Coloris/blob/main/src/coloris.css. */ - .js-color-picker-input { display: flex; - flex-wrap: wrap; + position: relative; } .js-color-picker-input input { @@ -13,152 +9,39 @@ padding-left: 32px !important; } -.clr-picker { - display: none; - flex-wrap: wrap; - position: absolute; - width: 200px; - z-index: 1002; /* above .ui.modal which has 1001 */ - border-radius: var(--border-radius); - background-color: var(--color-menu); - justify-content: flex-end; - direction: ltr; - box-shadow: 0 5px 20px var(--color-shadow); - user-select: none; -} - -.clr-picker.clr-open { - display: flex; -} - -.clr-gradient { - position: relative; - width: 100%; - height: 100px; - border-radius: 3px 3px 0 0; - background: linear-gradient(rgba(0,0,0,0), #000), linear-gradient(90deg, #fff, currentcolor); /* stylelint-disable-line scale-unlimited/declaration-strict-value */ - cursor: pointer; -} - -.clr-marker { - position: absolute; - width: 12px; - height: 12px; - margin: -6px 0 0 -6px; - border: 1px solid var(--color-white); - border-radius: 50%; - background-color: currentcolor; - cursor: pointer; -} - -.clr-picker input[type="range"]::-webkit-slider-runnable-track { - width: 100%; - height: 16px; -} - -.clr-picker input[type="range"]::-webkit-slider-thumb { - width: 16px; - height: 16px; - -webkit-appearance: none; -} - -.clr-picker input[type="range"]::-moz-range-track { - width: 100%; - height: 16px; - border: 0; -} - -.clr-picker input[type="range"]::-moz-range-thumb { - width: 16px; - height: 16px; - border: 0; -} - -.clr-hue { - background: linear-gradient(to right, #f00 0%, #ff0 16.66%, #0f0 33.33%, #0ff 50%, #00f 66.66%, #f0f 83.33%, #f00 100%); /* stylelint-disable-line scale-unlimited/declaration-strict-value */ - position: relative; - width: calc(100% - 40px); - height: 10px; - margin: 10px 20px; - border-radius: 4px; -} - -.clr-hue input[type="range"] { - position: absolute; - width: calc(100% + 32px); - margin: 0; - background-color: transparent; - opacity: 0; - cursor: pointer; - appearance: none; -} - -.clr-hue div { - position: absolute; - width: 16px; - height: 16px; - left: 0; - top: 50%; - transform: translate(-50%, -50%); - border: 2px solid var(--color-white); - border-radius: 50%; - background-color: currentcolor; - box-shadow: 0 0 1px var(--color-shadow); - pointer-events: none; -} - -.clr-field { - flex: 1; - position: relative; - color: transparent; -} - -.clr-field button { +.js-color-picker-input .preview-square { position: absolute; aspect-ratio: 1; height: 16px; left: 10px; top: 50%; transform: translateY(-50%); - margin: 0; - padding: 0; - border: 0; - color: inherit; - pointer-events: none; border-radius: 2px; background: repeating-linear-gradient(45deg, #aaa 25%, transparent 25%, transparent 75%, #aaa 75%, #aaa), repeating-linear-gradient(45deg, #aaa 25%, #fff 25%, #fff 75%, #aaa 75%, #aaa); /* stylelint-disable-line scale-unlimited/declaration-strict-value */ background-position: 0 0, 4px 4px; background-size: 8px 8px; } -.clr-field button::after { +.js-color-picker-input .preview-square::after { content: ""; - display: block; position: absolute; width: 100%; height: 100%; - left: 0; - top: 0; border-radius: inherit; background-color: currentcolor; } -.clr-marker:focus { - outline: none; +hex-color-picker { + width: 180px; + height: 120px; } -.clr-keyboard-nav .clr-marker:focus, -.clr-keyboard-nav .clr-hue input:focus + div, -.clr-keyboard-nav .clr-alpha input:focus + div { - outline: none; - box-shadow: 0 0 2px 2px var(--color-white); +hex-color-picker::part(hue-pointer), +hex-color-picker::part(saturation-pointer) { + width: 22px; + height: 22px; } -.clr-picker .clr-preview, -.clr-picker .clr-clear, -.clr-picker .clr-swatches, -.clr-picker .clr-format, -.clr-picker .clr-alpha, -.clr-picker .clr-color { - display: none; +hex-color-picker::part(hue) { + flex-basis: 16px; } diff --git a/web_src/css/modules/tippy.css b/web_src/css/modules/tippy.css index 76d36b4293..6ac7c37d93 100644 --- a/web_src/css/modules/tippy.css +++ b/web_src/css/modules/tippy.css @@ -29,6 +29,17 @@ z-index: 1; } +/* bare theme, no styling at all, except box-shadow */ +.tippy-box[data-theme="bare"] { + border: none; + box-shadow: 0 6px 18px var(--color-shadow); +} + +.tippy-box[data-theme="bare"] .tippy-content { + padding: 0; + background: transparent; +} + /* tooltip theme for text tooltips */ .tippy-box[data-theme="tooltip"] { diff --git a/web_src/js/features/colorpicker.js b/web_src/js/features/colorpicker.js index f342598e66..6d00d908c9 100644 --- a/web_src/js/features/colorpicker.js +++ b/web_src/js/features/colorpicker.js @@ -1,31 +1,66 @@ -export async function initColorPickers(selector = '.js-color-picker-input input', opts = {}) { - const inputEls = document.querySelectorAll(selector); - if (!inputEls.length) return; +import {createTippy} from '../modules/tippy.js'; - const [{coloris, init}] = await Promise.all([ - import(/* webpackChunkName: "colorpicker" */'@melloware/coloris'), +export async function initColorPickers() { + const els = document.getElementsByClassName('js-color-picker-input'); + if (!els.length) return; + + await Promise.all([ + import(/* webpackChunkName: "colorpicker" */'vanilla-colorful/hex-color-picker.js'), import(/* webpackChunkName: "colorpicker" */'../../css/features/colorpicker.css'), ]); - init(); - coloris({ - el: selector, - alpha: false, - focusInput: true, - selectInput: false, - ...opts, - }); - - for (const inputEl of inputEls) { - const parent = inputEl.closest('.js-color-picker-input'); - // prevent tabbing on the color preview `button` inside the input - parent.querySelector('button').tabIndex = -1; - // init precolors - for (const el of parent.querySelectorAll('.precolors .color')) { - el.addEventListener('click', (e) => { - inputEl.value = e.target.getAttribute('data-color-hex'); - inputEl.dispatchEvent(new Event('input', {bubbles: true})); - }); - } + for (const el of els) { + initPicker(el); + } +} + +function updateSquare(el, newValue) { + el.style.color = /#[0-9a-f]{6}/i.test(newValue) ? newValue : 'transparent'; +} + +function updatePicker(el, newValue) { + el.setAttribute('color', newValue); +} + +function initPicker(el) { + const input = el.querySelector('input'); + + const square = document.createElement('div'); + square.classList.add('preview-square'); + updateSquare(square, input.value); + el.append(square); + + const picker = document.createElement('hex-color-picker'); + picker.addEventListener('color-changed', (e) => { + input.value = e.detail.value; + input.focus(); + updateSquare(square, e.detail.value); + }); + + input.addEventListener('input', (e) => { + updateSquare(square, e.target.value); + updatePicker(picker, e.target.value); + }); + + createTippy(input, { + trigger: 'focus click', + theme: 'bare', + hideOnClick: true, + content: picker, + placement: 'bottom-start', + interactive: true, + onShow() { + updatePicker(picker, input.value); + }, + }); + + // init precolors + for (const colorEl of el.querySelectorAll('.precolors .color')) { + colorEl.addEventListener('click', (e) => { + const newValue = e.target.getAttribute('data-color-hex'); + input.value = newValue; + input.dispatchEvent(new Event('input', {bubbles: true})); + updateSquare(square, newValue); + }); } } diff --git a/web_src/js/modules/tippy.js b/web_src/js/modules/tippy.js index 220c9e5512..83b28e5745 100644 --- a/web_src/js/modules/tippy.js +++ b/web_src/js/modules/tippy.js @@ -3,11 +3,12 @@ import {isDocumentFragmentOrElementNode} from '../utils/dom.js'; import {formatDatetime} from '../utils/time.js'; const visibleInstances = new Set(); +const arrowSvg = `<svg width="16" height="7"><path d="m0 7 8-7 8 7Z" class="tippy-svg-arrow-outer"/><path d="m0 8 8-7 8 7Z" class="tippy-svg-arrow-inner"/></svg>`; export function createTippy(target, opts = {}) { // the callback functions should be destructured from opts, // because we should use our own wrapper functions to handle them, do not let the user override them - const {onHide, onShow, onDestroy, role, theme, ...other} = opts; + const {onHide, onShow, onDestroy, role, theme, arrow, ...other} = opts; const instance = tippy(target, { appendTo: document.body, @@ -35,9 +36,9 @@ export function createTippy(target, opts = {}) { visibleInstances.add(instance); return onShow?.(instance); }, - arrow: `<svg width="16" height="7"><path d="m0 7 8-7 8 7Z" class="tippy-svg-arrow-outer"/><path d="m0 8 8-7 8 7Z" class="tippy-svg-arrow-inner"/></svg>`, + arrow: arrow || (theme === 'bare' ? false : arrowSvg), role: role || 'menu', // HTML role attribute - theme: theme || role || 'menu', // CSS theme, either "tooltip", "menu" or "box-with-header" + theme: theme || role || 'menu', // CSS theme, either "tooltip", "menu", "box-with-header" or "bare" plugins: [followCursor], ...other, }); From 0ceecfc11ab4851863a5a6bc5e398d2baf7e86f6 Mon Sep 17 00:00:00 2001 From: guangwu <guoguangwu@magic-shield.com> Date: Wed, 3 Apr 2024 22:58:13 +0800 Subject: [PATCH 037/370] fix: close file in the Upload func (#30262) --- modules/lfs/filesystem_client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/lfs/filesystem_client.go b/modules/lfs/filesystem_client.go index 3503a9effc..71bef5c899 100644 --- a/modules/lfs/filesystem_client.go +++ b/modules/lfs/filesystem_client.go @@ -44,7 +44,7 @@ func (c *FilesystemClient) Download(ctx context.Context, objects []Pointer, call if err != nil { return err } - + defer f.Close() if err := callback(p, f, nil); err != nil { return err } @@ -75,7 +75,7 @@ func (c *FilesystemClient) Upload(ctx context.Context, objects []Pointer, callba if err != nil { return err } - + defer f.Close() _, err = io.Copy(f, content) return err From 609a627a44dbcb7b630ff51ce9f4b9f448b48ca8 Mon Sep 17 00:00:00 2001 From: Yakov <git@yakov.cloud> Date: Wed, 3 Apr 2024 09:01:50 -0700 Subject: [PATCH 038/370] Add `[other].SHOW_FOOTER_POWERED_BY` setting to hide `Powered by` (#30253) This allows you to hide the "Powered by" text in footer via `SHOW_FOOTER_POWERED_BY` flag in configuration. --------- Co-authored-by: silverwind <me@silverwind.io> --- custom/conf/app.example.ini | 2 ++ docs/content/administration/config-cheat-sheet.en-us.md | 1 + docs/content/administration/config-cheat-sheet.zh-cn.md | 1 + modules/setting/other.go | 2 ++ modules/templates/helper.go | 3 +++ templates/base/footer_content.tmpl | 4 +++- 6 files changed, 12 insertions(+), 1 deletion(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 1584b10301..918252044b 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -2315,6 +2315,8 @@ LEVEL = Info ;SHOW_FOOTER_VERSION = true ;; Show template execution time in the footer ;SHOW_FOOTER_TEMPLATE_LOAD_TIME = true +;; Show the "powered by" text in the footer +;SHOW_FOOTER_POWERED_BY = true ;; Generate sitemap. Defaults to `true`. ;ENABLE_SITEMAP = true ;; Enable/Disable RSS/Atom feed diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index f2209d269a..9de7511964 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -1429,5 +1429,6 @@ Like `uses: https://gitea.com/actions/checkout@v4` or `uses: http://your-git-ser - `SHOW_FOOTER_VERSION`: **true**: Show Gitea and Go version information in the footer. - `SHOW_FOOTER_TEMPLATE_LOAD_TIME`: **true**: Show time of template execution in the footer. +- `SHOW_FOOTER_POWERED_BY`: **true**: Show the "powered by" text in the footer. - `ENABLE_SITEMAP`: **true**: Generate sitemap. - `ENABLE_FEED`: **true**: Enable/Disable RSS/Atom feed. diff --git a/docs/content/administration/config-cheat-sheet.zh-cn.md b/docs/content/administration/config-cheat-sheet.zh-cn.md index 41c8844ae5..759f39b576 100644 --- a/docs/content/administration/config-cheat-sheet.zh-cn.md +++ b/docs/content/administration/config-cheat-sheet.zh-cn.md @@ -1353,5 +1353,6 @@ PROXY_HOSTS = *.github.com - `SHOW_FOOTER_VERSION`: **true**: 在页面底部显示Gitea的版本。 - `SHOW_FOOTER_TEMPLATE_LOAD_TIME`: **true**: 在页脚显示模板执行的时间。 +- `SHOW_FOOTER_POWERED_BY`: **true**: 在页脚显示“由...提供动力”的文本。 - `ENABLE_SITEMAP`: **true**: 生成sitemap. - `ENABLE_FEED`: **true**: 是否启用RSS/Atom diff --git a/modules/setting/other.go b/modules/setting/other.go index 706cb1e3d9..4ba494765b 100644 --- a/modules/setting/other.go +++ b/modules/setting/other.go @@ -8,6 +8,7 @@ import "code.gitea.io/gitea/modules/log" type OtherConfig struct { ShowFooterVersion bool ShowFooterTemplateLoadTime bool + ShowFooterPoweredBy bool EnableFeed bool EnableSitemap bool } @@ -15,6 +16,7 @@ type OtherConfig struct { var Other = OtherConfig{ ShowFooterVersion: true, ShowFooterTemplateLoadTime: true, + ShowFooterPoweredBy: true, EnableSitemap: true, EnableFeed: true, } diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 2452064749..9e770a2606 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -106,6 +106,9 @@ func NewFuncMap() template.FuncMap { "ShowFooterTemplateLoadTime": func() bool { return setting.Other.ShowFooterTemplateLoadTime }, + "ShowFooterPoweredBy": func() bool { + return setting.Other.ShowFooterPoweredBy + }, "AllowedReactions": func() []string { return setting.UI.Reactions }, diff --git a/templates/base/footer_content.tmpl b/templates/base/footer_content.tmpl index f0a7865602..8d0d8e669c 100644 --- a/templates/base/footer_content.tmpl +++ b/templates/base/footer_content.tmpl @@ -1,6 +1,8 @@ <footer class="page-footer" role="group" aria-label="{{ctx.Locale.Tr "aria.footer"}}"> <div class="left-links" role="contentinfo" aria-label="{{ctx.Locale.Tr "aria.footer.software"}}"> - <a target="_blank" rel="noopener noreferrer" href="https://about.gitea.com">{{ctx.Locale.Tr "powered_by" "Gitea"}}</a> + {{if ShowFooterPoweredBy}} + <a target="_blank" rel="noopener noreferrer" href="https://about.gitea.com">{{ctx.Locale.Tr "powered_by" "Gitea"}}</a> + {{end}} {{if (or .ShowFooterVersion .PageIsAdmin)}} {{ctx.Locale.Tr "version"}}: {{if .IsAdmin}} From 39e64e094f5b62401c3652983d8058df85ef744d Mon Sep 17 00:00:00 2001 From: Knud Hollander <26556793+KnudH@users.noreply.github.com> Date: Thu, 4 Apr 2024 01:16:02 +0200 Subject: [PATCH 039/370] update mailer example config, remove deprecated HOST (#30267) --- docs/content/installation/with-docker.en-us.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/content/installation/with-docker.en-us.md b/docs/content/installation/with-docker.en-us.md index e8a80f7c96..a16d4a8d60 100644 --- a/docs/content/installation/with-docker.en-us.md +++ b/docs/content/installation/with-docker.en-us.md @@ -304,7 +304,8 @@ services: - GITEA__mailer__ENABLED=true - GITEA__mailer__FROM=${GITEA__mailer__FROM:?GITEA__mailer__FROM not set} - GITEA__mailer__PROTOCOL=smtps - - GITEA__mailer__HOST=${GITEA__mailer__HOST:?GITEA__mailer__HOST not set} + - GITEA__mailer__SMTP_ADDR=${GITEA__mailer__SMTP_ADDR:?GITEA__mailer__SMTP_ADDR not set} + - GITEA__mailer__SMTP_PORT=${GITEA__mailer__SMTP_PORT:?GITEA__mailer__SMTP_PORT not set} - GITEA__mailer__USER=${GITEA__mailer__USER:-apikey} - GITEA__mailer__PASSWD="""${GITEA__mailer__PASSWD:?GITEA__mailer__PASSWD not set}""" ``` From 663acd0b4620a7a4e83f2d0699749af95126b0f5 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Thu, 4 Apr 2024 00:24:47 +0000 Subject: [PATCH 040/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_pt-PT.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 09b9d4e3ce..59b3d3df67 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -1233,6 +1233,8 @@ file_view_rendered=Ver resultado processado file_view_raw=Ver em bruto file_permalink=Ligação permanente file_too_large=O ficheiro é demasiado grande para ser apresentado. +code_preview_line_from_to=Linhas %[1]d até %[2]d em %[3]s +code_preview_line_in=Linha %[1]d em %[2]s invisible_runes_header=`Este ficheiro contém caracteres Unicode invisíveis` invisible_runes_description=`Este ficheiro contém caracteres Unicode indistinguíveis para humanos mas que podem ser processados de forma diferente por um computador. Se acha que é intencional, pode ignorar este aviso com segurança. Use o botão Revelar para os mostrar.` ambiguous_runes_header=`Este ficheiro contém caracteres Unicode ambíguos` From 83c5072077f34e6e108b12559b5aef2ae2de5a22 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Fri, 5 Apr 2024 00:24:29 +0000 Subject: [PATCH 041/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_ja-JP.ini | 64 +++++++++++++++++++++++++++++++-- options/locale/locale_zh-CN.ini | 54 ++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 2 deletions(-) diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index eddad35073..7e725b4647 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -113,6 +113,7 @@ loading=読み込み中… error=エラー error404=アクセスしようとしたページは<strong>存在しない</strong>か、閲覧が<strong>許可されていません</strong>。 go_back=戻る +invalid_data=無効なデータ: %v never=無し unknown=不明 @@ -143,13 +144,41 @@ name=名称 value=値 filter=フィルター +filter.clear=フィルターをクリア filter.is_archived=アーカイブ +filter.not_archived=非アーカイブ +filter.is_fork=フォーク +filter.not_fork=非フォーク +filter.is_mirror=ミラー +filter.not_mirror=非ミラー filter.is_template=テンプレート +filter.not_template=非テンプレート filter.public=公開 filter.private=プライベート +no_results_found=見つかりません。 [search] +search=検索… +type_tooltip=検索タイプ +fuzzy=あいまい +fuzzy_tooltip=検索ワードに近い結果も含めます +match=一致 +match_tooltip=検索ワードと完全に一致する結果のみ含めます +repo_kind=リポジトリを検索... +user_kind=ユーザーを検索... +org_kind=組織を検索... +team_kind=チームを検索… +code_kind=コードを検索... +code_search_unavailable=現在コード検索は利用できません。 サイト管理者にお問い合わせください。 +code_search_by_git_grep=現在のコード検索結果は "git grep" で提供されています。 サイト管理者がリポジトリインデクサーを有効にすると、より良い結果が得られるかもしれません。 +package_kind=パッケージを検索... +project_kind=プロジェクトを検索... +branch_kind=ブランチを検索... +commit_kind=コミットを検索... +runner_kind=ランナーを検索... +no_results=一致する結果が見つかりませんでした +keyword_search_unavailable=現在キーワード検索は利用できません。 サイト管理者にお問い合わせください。 [aria] navbar=ナビゲーションバー @@ -256,6 +285,7 @@ email_title=メール設定 smtp_addr=SMTPホスト smtp_port=SMTPポート smtp_from=メール送信者 +smtp_from_invalid=「メール送信者」のアドレスが無効です smtp_from_helper=Giteaが使用するメールアドレス。 メールアドレスのみ、または、 "名前" <email@example.com> の形式で入力してください。 mailer_user=SMTPユーザー名 mailer_password=SMTPパスワード @@ -315,6 +345,7 @@ env_config_keys=環境設定 env_config_keys_prompt=以下の環境変数も設定ファイルに適用されます: [home] +nav_menu=ナビゲーションメニュー uname_holder=ユーザー名またはメールアドレス password_holder=パスワード switch_dashboard_context=ダッシュボードのコンテキスト切替 @@ -618,6 +649,23 @@ block.block.org=組織向けにユーザーをブロック block.block.failure=ユーザーのブロックに失敗しました: %s block.unblock=ブロックを解除 block.unblock.failure=ユーザーのブロック解除に失敗しました: %s +block.blocked=あなたはこのユーザーをブロックしています。 +block.title=ユーザーをブロックする +block.info=ユーザーをブロックすると、そのユーザーは、プルリクエストやイシューの作成、コメントの投稿など、リポジトリに対する操作ができなくなります。 ユーザーのブロックについてはよく確認してください。 +block.info_1=ユーザーをブロックすることで、あなたのアカウントとリポジトリに対する以下の行為を防ぎます: +block.info_2=あなたのアカウントのフォロー +block.info_3=あなたのユーザー名で@メンションして通知を送ること +block.info_4=そのユーザーのリポジトリに、あなたを共同作業者として招待すること +block.info_5=リポジトリへの、スター、フォーク、ウォッチ +block.info_6=イシューやプルリクエストの作成、コメント投稿 +block.info_7=イシューやプルリクエストでの、あなたのコメントに対するリアクションの送信 +block.user_to_block=ブロックするユーザー +block.note=メモ +block.note.title=メモ(任意): +block.note.info=メモはブロックされるユーザーには表示されません。 +block.note.edit=メモを編集 +block.list=ブロックしたユーザー +block.list.none=ブロックしているユーザーはいません。 [settings] profile=プロフィール @@ -956,6 +1004,7 @@ fork_branch=フォークにクローンされるブランチ all_branches=すべてのブランチ fork_no_valid_owners=このリポジトリには有効なオーナーがいないため、フォークできません。 use_template=このテンプレートを使用 +open_with_editor=%s で開く download_zip=ZIPファイルをダウンロード download_tar=TAR.GZファイルをダウンロード download_bundle=バンドルをダウンロード @@ -1008,6 +1057,7 @@ watchers=ウォッチャー stargazers=スターゲイザー stars_remove_warning=これを指定すると、このリポジトリのスターはすべて削除されます。 forks=フォーク +stars=スター reactions_more=さらに %d 件 unit_disabled=サイト管理者がこのリポジトリセクションを無効にしています。 language_other=その他 @@ -1039,7 +1089,7 @@ transfer.no_permission_to_reject=この移転を拒否する権限がありま desc.private=プライベート desc.public=公開 desc.template=テンプレート -desc.internal=組織内 +desc.internal=内部 desc.archived=アーカイブ desc.sha256=SHA256 @@ -1257,6 +1307,8 @@ editor.file_editing_no_longer_exists=編集中のファイル "%s" が、もう editor.file_deleting_no_longer_exists=削除しようとしたファイル "%s" が、すでにリポジトリ内にありません。 editor.file_changed_while_editing=あなたが編集を開始したあと、ファイルの内容が変更されました。 <a target="_blank" rel="noopener noreferrer" href="%s">ここをクリック</a>して何が変更されたか確認するか、<strong>もう一度"変更をコミット"をクリック</strong>して上書きします。 editor.file_already_exists=ファイル "%s" は、このリポジトリに既に存在します。 +editor.commit_id_not_matching=コミットIDが編集を開始したときのIDと一致しません。 パッチ用のブランチにコミットしたあとマージしてください。 +editor.push_out_of_date=このプッシュは最新ではないようです。 editor.commit_empty_file_header=空ファイルのコミット editor.commit_empty_file_text=コミットしようとしているファイルは空です。 続行しますか? editor.no_changes_to_show=表示する変更箇所はありません。 @@ -1281,6 +1333,7 @@ commits.commits=コミット commits.no_commits=共通のコミットはありません。 "%s" と "%s" の履歴はすべて異なっています。 commits.nothing_to_compare=二つのブランチは同じ内容です。 commits.search.tooltip=`キーワード "author:"、"committer:"、"after:"、"before:" を付けて指定できます。 例 "revert author:Alice before:2019-01-13"` +commits.search_branch=このブランチ commits.search_all=すべてのブランチ commits.author=作成者 commits.message=メッセージ @@ -1339,6 +1392,7 @@ projects.column.new=新しい列 projects.column.set_default=デフォルトに設定 projects.column.set_default_desc=この列を未分類のイシューやプルリクエストが入るデフォルトの列にします projects.column.delete=列を削除 +projects.column.deletion_desc=プロジェクト列を削除すると、関連するすべてのイシューがデフォルトの列に移動します。 続行しますか? projects.column.color=カラー projects.open=オープン projects.close=クローズ @@ -1738,7 +1792,7 @@ pulls.is_checking=マージのコンフリクトを確認中です。 少し待 pulls.is_ancestor=このブランチは既にターゲットブランチに含まれています。マージするものはありません。 pulls.is_empty=このブランチの変更は既にターゲットブランチにあります。これは空のコミットになります。 pulls.required_status_check_failed=いくつかの必要なステータスチェックが成功していません。 -pulls.required_status_check_missing=必要なステータスチェックが見つかりません。 +pulls.required_status_check_missing=必要なチェックがいくつか抜けています。 pulls.required_status_check_administrator=管理者であるため、このプルリクエストをマージすることは可能です。 pulls.blocked_by_approvals=このプルリクエストはまだ承認数が足りません。 %[1]d/%[2]dの承認を得ています。 pulls.blocked_by_rejection=このプルリクエストは公式レビューアにより変更要請されています。 @@ -1907,6 +1961,7 @@ wiki.original_git_entry_tooltip=フレンドリーリンクを使用する代わ activity=アクティビティ activity.navbar.pulse=Pulse activity.navbar.contributors=貢献者 +activity.navbar.recent_commits=最近のコミット activity.period.filter_label=期間: activity.period.daily=1日 activity.period.halfweekly=3日 @@ -2571,6 +2626,7 @@ component_loading_failed=%sを読み込めませんでした component_loading_info=少し時間がかかるかもしれません… component_failed_to_load=予期しないエラーが発生しました。 contributors.what=実績 +recent_commits.what=最近のコミット [org] org_name_holder=組織名 @@ -2684,6 +2740,7 @@ teams.add_nonexistent_repo=追加しようとしているリポジトリは存 teams.add_duplicate_users=ユーザーは既にチームのメンバーです。 teams.repos.none=このチームがアクセスできるリポジトリはありません。 teams.members.none=このチームにはメンバーがいません。 +teams.members.blocked_user=組織によってブロックされているため、ユーザーを追加できません。 teams.specific_repositories=指定したリポジトリ teams.specific_repositories_helper=メンバーは、明示的にチームへ追加したリポジトリにのみアクセスできます。 これを選択しても、すでに<i>すべてのリポジトリ</i>で追加されたリポジトリは自動的に除去<strong>されません</strong>。 teams.all_repositories=すべてのリポジトリ @@ -3009,6 +3066,7 @@ auths.tip.nextcloud=新しいOAuthコンシューマーを、インスタンス 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_new=新しいアプリケーションを https://gitlab.com/-/profile/applications から登録してください。 auths.tip.google_plus=OAuth2クライアント資格情報を、Google APIコンソール https://console.developers.google.com/ から取得してください。 auths.tip.openid_connect=OpenID Connect DiscoveryのURL (<server>/.well-known/openid-configuration) をエンドポイントとして指定してください auths.tip.twitter=https://dev.twitter.com/apps へアクセスしてアプリケーションを作成し、“Allow this application to be used to Sign in with Twitter”オプションを有効にしてください。 @@ -3144,6 +3202,7 @@ config.picture_config=画像とアバターの設定 config.picture_service=画像サービス config.disable_gravatar=Gravatarが無効 config.enable_federated_avatar=フェデレーテッド・アバター有効 +config.open_with_editor_app_help=クローンメニューの「~で開く」に表示するエディタ。 空白のままにするとデフォルトが使用されます。 展開するとデフォルトを確認できます。 config.git_config=Git設定 config.git_disable_diff_highlight=Diffのシンタックスハイライトが無効 @@ -3542,6 +3601,7 @@ runs.scheduled=スケジュール済み runs.pushed_by=pushed by runs.invalid_workflow_helper=ワークフロー設定ファイルは無効です。あなたの設定ファイルを確認してください: %s runs.no_matching_online_runner_helper=ラベルに一致するオンラインのランナーが見つかりません: %s +runs.no_job_without_needs=ワークフローには依存関係のないジョブが少なくとも1つ含まれている必要があります。 runs.actor=アクター runs.status=ステータス runs.actors_no_select=すべてのアクター diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 01058d48d2..3e907eabfd 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -25,6 +25,7 @@ enable_javascript=此网站需要 JavaScript。 toc=目录 licenses=许可证 return_to_gitea=返回 Gitea +more_items=更多选项 username=用户名 email=电子邮件地址 @@ -113,6 +114,7 @@ loading=正在加载... error=错误 error404=您正尝试访问的页面 <strong>不存在</strong> 或 <strong>您尚未被授权</strong> 查看该页面。 go_back=返回 +invalid_data=无效数据: %v never=从不 unknown=未知 @@ -143,13 +145,36 @@ name=名称 value=值 filter=过滤 +filter.clear=清除筛选器 filter.is_archived=已归档 +filter.not_archived=非存档 +filter.is_fork=派生 +filter.not_fork=非派生 +filter.is_mirror=镜像 +filter.not_mirror=非镜像 filter.is_template=模板 +filter.not_template=非模板 filter.public=公开 filter.private=私有库 +no_results_found=未找到结果 [search] +search=搜索... +type_tooltip=搜索类型 +fuzzy=模糊 +match=匹配 +repo_kind=搜索仓库... +user_kind=搜索用户... +org_kind=搜索组织... +team_kind=搜索团队... +code_kind=搜索代码... +package_kind=搜索软件包... +project_kind=搜索项目... +branch_kind=搜索分支... +commit_kind=搜索提交记录... +runner_kind=搜索runners... +no_results=未找到匹配结果 [aria] navbar=导航栏 @@ -315,6 +340,7 @@ env_config_keys=环境配置 env_config_keys_prompt=以下环境变量也将应用于您的配置文件: [home] +nav_menu=导航菜单 uname_holder=用户名或邮箱 password_holder=密码 switch_dashboard_context=切换控制面板用户 @@ -612,6 +638,13 @@ form.name_reserved=用户名 "%s" 被保留。 form.name_pattern_not_allowed=用户名中不允许使用 "%s" 格式。 form.name_chars_not_allowed=用户名 "%s" 包含无效字符。 +block.block=屏蔽 +block.block.user=屏蔽用户 +block.block.org=屏蔽用户访问组织 +block.block.failure=屏蔽用户失败: %s +block.unblock=取消屏蔽 +block.title=屏蔽一个用户 +block.info_2=关注你的账号 [settings] profile=个人信息 @@ -1275,6 +1308,7 @@ commits.commits=次代码提交 commits.no_commits=没有共同的提交。%s 和 %s 的历史完全不同。 commits.nothing_to_compare=这些分支是相同的。 commits.search.tooltip=`您可以在关键词前加上前缀,如"author:", "committer:", "after:", 或"before:", 例如 "retrin author:Alice before:2019-01-13"` +commits.search_branch=此分支 commits.search_all=所有分支 commits.author=作者 commits.message=备注 @@ -1333,6 +1367,7 @@ projects.column.new=创建列 projects.column.set_default=设为默认 projects.column.set_default_desc=设置此列为未分类问题和合并请求的默认值 projects.column.delete=删除列 +projects.column.deletion_desc=删除项目列会将所有相关问题移到“未分类”。是否继续? projects.column.color=彩色 projects.open=开启 projects.close=关闭 @@ -1898,7 +1933,9 @@ wiki.page_name_desc=输入此 Wiki 页面的名称。特殊名称有:'Home', ' wiki.original_git_entry_tooltip=查看原始的 Git 文件而不是使用友好链接。 activity=动态 +activity.navbar.code_frequency=代码频率 activity.navbar.contributors=贡献者 +activity.navbar.recent_commits=最近的提交 activity.period.filter_label=周期: activity.period.daily=1 天 activity.period.halfweekly=3 天 @@ -2017,6 +2054,8 @@ settings.branches.add_new_rule=添加新规则 settings.advanced_settings=高级设置 settings.wiki_desc=启用仓库百科 settings.use_internal_wiki=使用内置百科 +settings.default_wiki_branch_name=默认百科分支名称 +settings.failed_to_change_default_wiki_branch=更改百科默认分支失败。 settings.use_external_wiki=使用外部百科 settings.external_wiki_url=外部 Wiki 链接 settings.external_wiki_url_error=外部百科链接无效 @@ -2047,6 +2086,9 @@ settings.pulls.default_allow_edits_from_maintainers=默认开启允许维护者 settings.releases_desc=启用发布 settings.packages_desc=启用仓库软件包注册中心 settings.projects_desc=启用仓库项目 +settings.projects_mode_desc=项目模式 (要显示的项目类型) +settings.projects_mode_repo=仅仓库项目 +settings.projects_mode_owner=仅限用户或组织项目 settings.projects_mode_all=所有项目 settings.actions_desc=启用 Actions settings.admin_settings=管理员设置 @@ -2073,6 +2115,7 @@ settings.convert_fork_succeed=此派生仓库已经转换为普通仓库。 settings.transfer=转移仓库所有权 settings.transfer.rejected=代码库转移被拒绝。 settings.transfer.success=代码库转移成功。 +settings.transfer.blocked_user=无法传输仓库,因为您被新的所有者屏蔽。 settings.transfer_abort=取消转移 settings.transfer_abort_invalid=你不能取消不存在的代码库转移。 settings.transfer_abort_success=成功取消了将代码库转让给 %s。 @@ -2118,6 +2161,7 @@ settings.add_collaborator_success=协作者添加成功! settings.add_collaborator_inactive_user=无法添加未激活的用户作为合作者。 settings.add_collaborator_owner=不能将所有者添加为协作者。 settings.add_collaborator_duplicate=合作者已经被添加到本仓库。 +settings.add_collaborator.blocked_user=此写作者被仓库所有者屏蔽,反之亦然。 settings.delete_collaborator=删除 settings.collaborator_deletion=删除协作者 settings.collaborator_deletion_desc=删除协作者后他将无法再对此仓库的访问。继续? @@ -2556,13 +2600,16 @@ find_file.no_matching=没有找到匹配的文件 error.csv.too_large=无法渲染此文件,因为它太大了。 error.csv.unexpected=无法渲染此文件,因为它包含了意外字符,其位于第 %d 行和第 %d 列。 error.csv.invalid_field_count=无法渲染此文件,因为它在第 %d 行中的字段数有误。 +error.broken_git_hook=此仓库的 Git 钩子似乎已损坏。 请按照 <a target="_blank" rel="noreferrer" href="%s">文档</a> 来修复它们,然后推送一些提交来刷新状态。 [graphs] component_loading=正在加载 %s... component_loading_failed=无法加载 %s component_loading_info=这可能需要一点… component_failed_to_load=意外的错误发生了。 +code_frequency.what=代码频率 contributors.what=贡献 +recent_commits.what=最近的提交 [org] org_name_holder=组织名称 @@ -2676,6 +2723,7 @@ teams.add_nonexistent_repo=您尝试添加的仓库不存在,请先创建它 teams.add_duplicate_users=用户已经是团队成员。 teams.repos.none=此团队无法访问任何仓库。 teams.members.none=团队中没有成员。 +teams.members.blocked_user=不能添加用户因为他已经被该组织屏蔽。 teams.specific_repositories=指定仓库 teams.specific_repositories_helper=团队成员将只能访问添加到团队的仓库。 选择此项 <strong>将不会</strong> 自动删除已经添加的仓库。 teams.all_repositories=所有仓库 @@ -2688,6 +2736,7 @@ teams.invite.by=邀请人 %s teams.invite.description=请点击下面的按钮加入团队。 [admin] +maintenance=维护 dashboard=管理面板 self_check=自我检查 identity_access=身份及认证 @@ -2711,6 +2760,7 @@ settings=管理设置 dashboard.new_version_hint=Gitea %s 现已可用,您正在运行 %s。查看 <a target="_blank" rel="noreferrer" href="https://blog.gitea.io">博客</a> 了解详情。 dashboard.statistic=摘要 +dashboard.maintenance_operations=运维 dashboard.system_status=系统状态 dashboard.operation_name=操作名称 dashboard.operation_switch=开关 @@ -3001,6 +3051,7 @@ auths.tip.nextcloud=使用下面的菜单“设置(Settings) -> 安全(Sec auths.tip.dropbox=在 https://www.dropbox.com/developers/apps 上创建一个新的应用程序 auths.tip.facebook=`在 https://developers.facebook.com/apps 注册一个新的应用,并添加产品"Facebook 登录"` auths.tip.github=在 https://github.com/settings/applications/new 注册一个 OAuth 应用程序 +auths.tip.gitlab_new=在 https://gitlab.com/-/profile/applications 注册一个新的应用 auths.tip.google_plus=从谷歌 API 控制台 (https://console.developers.google.com/) 获得 OAuth2 客户端凭据 auths.tip.openid_connect=使用 OpenID 连接发现 URL (<server>/.well-known/openid-configuration) 来指定终点 auths.tip.twitter=访问 https://dev.twitter.com/apps,创建应用并确保启用了"允许此应用程序用于登录 Twitter"的选项。 @@ -3136,6 +3187,7 @@ config.picture_config=图片和头像配置 config.picture_service=图片服务 config.disable_gravatar=禁用 Gravatar 头像 config.enable_federated_avatar=启用 Federated Avatars +config.open_with_editor_app_help=用于克隆菜单的编辑器。如果为空将使用默认值。展开可以查看默认值。 config.git_config=Git 配置 config.git_disable_diff_highlight=禁用差异对比语法高亮 @@ -3215,6 +3267,7 @@ notices.op=操作 notices.delete_success=系统通知已被删除。 self_check.no_problem_found=尚未发现问题。 +self_check.startup_warnings=启动警告: self_check.database_collation_mismatch=期望数据库使用的校验方式:%s self_check.database_collation_case_insensitive=数据库正在使用一个校验 %s, 这是一个不敏感的校验. 虽然Gitea可以与它合作,但可能有一些罕见的情况不如预期的那样起作用。 self_check.database_inconsistent_collation_columns=数据库正在使用%s的排序规则,但是这些列使用了不匹配的排序规则。这可能会造成一些意外问题。 @@ -3534,6 +3587,7 @@ runs.scheduled=已计划的 runs.pushed_by=推送者 runs.invalid_workflow_helper=工作流配置文件无效。请检查您的配置文件: %s runs.no_matching_online_runner_helper=没有匹配标签的在线 runner: %s +runs.no_job_without_needs=工作流必须包含至少一个没有依赖关系的作业。 runs.actor=操作者 runs.status=状态 runs.actors_no_select=所有操作者 From 07bcfc171bcccfe78a86c7b4b3f9b729ba7d60b6 Mon Sep 17 00:00:00 2001 From: sebastian-sauer <sauer.sebastian@gmail.com> Date: Fri, 5 Apr 2024 02:51:53 +0200 Subject: [PATCH 042/370] Commit-Dropdown: Show Author of commit if available (#30272) As in commits page we show the author of the commit in the commits dropdown and not the committer. Commits Page:  and the same contents in our dropdown:  fixes #29588 --- services/pull/pull.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/pull/pull.go b/services/pull/pull.go index c091b8608a..185a1895c9 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -989,12 +989,12 @@ func GetPullCommits(ctx *gitea_context.Context, issue *issues_model.Issue) ([]Co for _, commit := range prInfo.Commits { var committerOrAuthorName string var commitTime time.Time - if commit.Committer != nil { - committerOrAuthorName = commit.Committer.Name - commitTime = commit.Committer.When - } else { + if commit.Author != nil { committerOrAuthorName = commit.Author.Name commitTime = commit.Author.When + } else { + committerOrAuthorName = commit.Committer.Name + commitTime = commit.Committer.When } commits = append(commits, CommitInfo{ From 95504045cceee9d60ff5d2eeb32cd30213b52322 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Fri, 5 Apr 2024 04:45:59 +0200 Subject: [PATCH 043/370] Upgrade `golang.org/x/net` to v0.24.0 (#30283) Result of `go get -u golang.org/x/net; make tidy`. This is related to the following vulncheck warning: ``` There are 2 vulnerabilities in modules that you require that are neither imported nor called. You may not need to take any action. See https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck for details. Vulnerability #1: GO-2024-2687 HTTP/2 CONTINUATION flood in net/http More info: https://pkg.go.dev/vuln/GO-2024-2687 Module: golang.org/x/net Found in: golang.org/x/net@v0.22.0 Fixed in: golang.org/x/net@v0.23.0 Vulnerability #2: GO-2022-0470 No access control in github.com/blevesearch/bleve and bleve/v2 More info: https://pkg.go.dev/vuln/GO-2022-0470 Module: github.com/blevesearch/bleve/v2 Found in: github.com/blevesearch/bleve/v2@v2.3.10 Fixed in: N/A ``` --- go.mod | 6 +++--- go.sum | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index b76eb74876..27e1924806 100644 --- a/go.mod +++ b/go.mod @@ -105,11 +105,11 @@ require ( github.com/yuin/goldmark v1.7.0 github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc github.com/yuin/goldmark-meta v1.1.0 - golang.org/x/crypto v0.21.0 + golang.org/x/crypto v0.22.0 golang.org/x/image v0.15.0 - golang.org/x/net v0.22.0 + golang.org/x/net v0.24.0 golang.org/x/oauth2 v0.18.0 - golang.org/x/sys v0.18.0 + golang.org/x/sys v0.19.0 golang.org/x/text v0.14.0 golang.org/x/tools v0.19.0 google.golang.org/grpc v1.62.1 diff --git a/go.sum b/go.sum index d82110177c..55f24bf2e7 100644 --- a/go.sum +++ b/go.sum @@ -846,8 +846,8 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f h1:3CW0unweImhOzd5FmYuRsD4Y4oQFKZIjAnKbjV4WIrw= golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8= @@ -881,8 +881,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -932,8 +932,8 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -943,8 +943,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= From 5dabc679aa0a33bc1b997335a216acfe97e70ea5 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Fri, 5 Apr 2024 05:35:37 +0200 Subject: [PATCH 044/370] Update JS dependencies and add new eslint rules (#30279) - Run `make update-js` - Added new eslint rules - Tested webpack build and swagger ui --- .eslintrc.yaml | 5 +- package-lock.json | 633 ++++++++++++++++++++++++++++------------------ package.json | 24 +- 3 files changed, 396 insertions(+), 266 deletions(-) diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 43edd14cec..5fd0a245f2 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -537,7 +537,7 @@ rules: no-underscore-dangle: [0] no-unexpected-multiline: [2] no-unmodified-loop-condition: [2] - no-unneeded-ternary: [0] + no-unneeded-ternary: [2] no-unreachable-loop: [2] no-unreachable: [2] no-unsafe-finally: [2] @@ -716,12 +716,14 @@ rules: unicorn/import-style: [0] unicorn/new-for-builtins: [2] unicorn/no-abusive-eslint-disable: [0] + unicorn/no-anonymous-default-export: [0] unicorn/no-array-callback-reference: [0] unicorn/no-array-for-each: [2] unicorn/no-array-method-this-argument: [2] unicorn/no-array-push-push: [2] unicorn/no-array-reduce: [2] unicorn/no-await-expression-member: [0] + unicorn/no-await-in-promise-methods: [2] unicorn/no-console-spaces: [0] unicorn/no-document-cookie: [2] unicorn/no-empty-file: [2] @@ -738,6 +740,7 @@ rules: unicorn/no-null: [0] unicorn/no-object-as-default-parameter: [0] unicorn/no-process-exit: [0] + unicorn/no-single-promise-in-promise-methods: [2] unicorn/no-static-only-class: [2] unicorn/no-thenable: [2] unicorn/no-this-assignment: [2] diff --git a/package-lock.json b/package-lock.json index a5f7a09ed0..35bf886fc8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "chartjs-adapter-dayjs-4": "1.0.4", "chartjs-plugin-zoom": "2.0.1", "clippie": "4.0.7", - "css-loader": "6.10.0", + "css-loader": "7.0.0", "dayjs": "1.11.10", "dropzone": "6.0.0-beta.2", "easymde": "2.18.0", @@ -35,17 +35,17 @@ "license-checker-webpack-plugin": "0.2.1", "mermaid": "10.9.0", "mini-css-extract-plugin": "2.8.1", - "minimatch": "9.0.3", + "minimatch": "9.0.4", "monaco-editor": "0.47.0", "monaco-editor-webpack-plugin": "7.1.0", "pdfobject": "2.3.0", "postcss": "8.4.38", "postcss-loader": "8.1.1", - "postcss-nesting": "12.1.0", + "postcss-nesting": "12.1.1", "pretty-ms": "9.0.0", "sortablejs": "1.15.2", - "swagger-ui-dist": "5.12.0", - "tailwindcss": "3.4.1", + "swagger-ui-dist": "5.13.0", + "tailwindcss": "3.4.3", "temporal-polyfill": "0.2.3", "throttle-debounce": "5.0.0", "tinycolor2": "1.6.0", @@ -66,9 +66,9 @@ "devDependencies": { "@eslint-community/eslint-plugin-eslint-comments": "4.1.0", "@playwright/test": "1.42.1", - "@stoplight/spectral-cli": "6.11.0", + "@stoplight/spectral-cli": "6.11.1", "@stylistic/eslint-plugin-js": "1.7.0", - "@stylistic/stylelint-plugin": "2.1.0", + "@stylistic/stylelint-plugin": "2.1.1", "@vitejs/plugin-vue": "5.0.4", "eslint": "8.57.0", "eslint-plugin-array-func": "4.0.0", @@ -78,17 +78,17 @@ "eslint-plugin-no-jquery": "2.7.0", "eslint-plugin-no-use-extend-native": "0.5.0", "eslint-plugin-regexp": "2.4.0", - "eslint-plugin-sonarjs": "0.24.0", - "eslint-plugin-unicorn": "51.0.1", - "eslint-plugin-vitest": "0.4.0", + "eslint-plugin-sonarjs": "0.25.1", + "eslint-plugin-unicorn": "52.0.0", + "eslint-plugin-vitest": "0.4.1", "eslint-plugin-vitest-globals": "1.5.0", "eslint-plugin-vue": "9.24.0", "eslint-plugin-vue-scoped-css": "2.8.0", "eslint-plugin-wc": "2.0.4", - "happy-dom": "14.3.7", + "happy-dom": "14.5.0", "markdownlint-cli": "0.39.0", "postcss-html": "1.6.0", - "stylelint": "16.3.0", + "stylelint": "16.3.1", "stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-declaration-strict-value": "1.10.4", "stylelint-value-no-unknown-custom-properties": "6.0.1", @@ -234,9 +234,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", - "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", + "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", "bin": { "parser": "bin/babel-parser.js" }, @@ -245,9 +245,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz", - "integrity": "sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz", + "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -481,9 +481,9 @@ } }, "node_modules/@csstools/selector-specificity": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.0.2.tgz", - "integrity": "sha512-RpHaZ1h9LE7aALeQXmXrJkRG84ZxIsctEN2biEUmFyKpzFM3zZ35eUMcIzZFsw/2olQE6v69+esEqU2f1MKycg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.0.3.tgz", + "integrity": "sha512-KEPNw4+WW5AVEIyzC80rTbWEUatTW2lXpN8+8ILC8PiPeWPjwUzrPZDIOZ2wwqDmeqOYTdSGyL3+vE5GC3FB3Q==", "funding": [ { "type": "github", @@ -1059,9 +1059,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, "node_modules/@isaacs/cliui": { @@ -1420,9 +1420,9 @@ "dev": true }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz", - "integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.0.tgz", + "integrity": "sha512-jwXtxYbRt1V+CdQSy6Z+uZti7JF5irRKF8hlKfEnF/xJpcNGuuiZMBvuoYM+x9sr9iWGnzrlM0+9hvQ1kgkf1w==", "cpu": [ "arm" ], @@ -1433,9 +1433,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz", - "integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.0.tgz", + "integrity": "sha512-fI9nduZhCccjzlsA/OuAwtFGWocxA4gqXGTLvOyiF8d+8o0fZUeSztixkYjcGq1fGZY3Tkq4yRvHPFxU+jdZ9Q==", "cpu": [ "arm64" ], @@ -1446,9 +1446,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz", - "integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.0.tgz", + "integrity": "sha512-BcnSPRM76/cD2gQC+rQNGBN6GStBs2pl/FpweW8JYuz5J/IEa0Fr4AtrPv766DB/6b2MZ/AfSIOSGw3nEIP8SA==", "cpu": [ "arm64" ], @@ -1459,9 +1459,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz", - "integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.0.tgz", + "integrity": "sha512-LDyFB9GRolGN7XI6955aFeI3wCdCUszFWumWU0deHA8VpR3nWRrjG6GtGjBrQxQKFevnUTHKCfPR4IvrW3kCgQ==", "cpu": [ "x64" ], @@ -1472,9 +1472,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz", - "integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.0.tgz", + "integrity": "sha512-ygrGVhQP47mRh0AAD0zl6QqCbNsf0eTo+vgwkY6LunBcg0f2Jv365GXlDUECIyoXp1kKwL5WW6rsO429DBY/bA==", "cpu": [ "arm" ], @@ -1485,9 +1485,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz", - "integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.0.tgz", + "integrity": "sha512-x+uJ6MAYRlHGe9wi4HQjxpaKHPM3d3JjqqCkeC5gpnnI6OWovLdXTpfa8trjxPLnWKyBsSi5kne+146GAxFt4A==", "cpu": [ "arm64" ], @@ -1498,9 +1498,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz", - "integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.0.tgz", + "integrity": "sha512-nrRw8ZTQKg6+Lttwqo6a2VxR9tOroa2m91XbdQ2sUUzHoedXlsyvY1fN4xWdqz8PKmf4orDwejxXHjh7YBGUCA==", "cpu": [ "arm64" ], @@ -1510,10 +1510,23 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.0.tgz", + "integrity": "sha512-xV0d5jDb4aFu84XKr+lcUJ9y3qpIWhttO3Qev97z8DKLXR62LC3cXT/bMZXrjLF9X+P5oSmJTzAhqwUbY96PnA==", + "cpu": [ + "ppc64le" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz", - "integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.0.tgz", + "integrity": "sha512-SDDhBQwZX6LPRoPYjAZWyL27LbcBo7WdBFWJi5PI9RPCzU8ijzkQn7tt8NXiXRiFMJCVpkuMkBf4OxSxVMizAw==", "cpu": [ "riscv64" ], @@ -1523,10 +1536,23 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.0.tgz", + "integrity": "sha512-RxB/qez8zIDshNJDufYlTT0ZTVut5eCpAZ3bdXDU9yTxBzui3KhbGjROK2OYTTor7alM7XBhssgoO3CZ0XD3qA==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz", - "integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.0.tgz", + "integrity": "sha512-C6y6z2eCNCfhZxT9u+jAM2Fup89ZjiG5pIzZIDycs1IwESviLxwkQcFRGLjnDrP+PT+v5i4YFvlcfAs+LnreXg==", "cpu": [ "x64" ], @@ -1537,9 +1563,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz", - "integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.0.tgz", + "integrity": "sha512-i0QwbHYfnOMYsBEyjxcwGu5SMIi9sImDVjDg087hpzXqhBSosxkE7gyIYFHgfFl4mr7RrXksIBZ4DoLoP4FhJg==", "cpu": [ "x64" ], @@ -1550,9 +1576,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz", - "integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.0.tgz", + "integrity": "sha512-Fq52EYb0riNHLBTAcL0cun+rRwyZ10S9vKzhGKKgeD+XbwunszSY0rVMco5KbOsTlwovP2rTOkiII/fQ4ih/zQ==", "cpu": [ "arm64" ], @@ -1563,9 +1589,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz", - "integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.0.tgz", + "integrity": "sha512-e/PBHxPdJ00O9p5Ui43+vixSgVf4NlLsmV6QneGERJ3lnjIua/kim6PRFe3iDueT1rQcgSkYP8ZBBXa/h4iPvw==", "cpu": [ "ia32" ], @@ -1576,9 +1602,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz", - "integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.0.tgz", + "integrity": "sha512-aGg7iToJjdklmxlUlJh/PaPNa4PmqHfyRMLunbL3eaMO0gp656+q1zOKkpJ/CVe9CryJv6tAN1HDoR8cNGzkag==", "cpu": [ "x64" ], @@ -1686,9 +1712,9 @@ } }, "node_modules/@stoplight/spectral-cli": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-cli/-/spectral-cli-6.11.0.tgz", - "integrity": "sha512-IURDN47BPIf3q4ZyUPujGpBzuHWFE5yT34w9rTJ1GKA4SgdscEdQO9KoTjOPT4G4cvDlEV3bNxwQ3uRm7+wRlA==", + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-cli/-/spectral-cli-6.11.1.tgz", + "integrity": "sha512-1zqsQ0TOuVSnxxZ9mHBfC0IygV6ex7nAY6Mp59mLmw5fW103U9yPVK5ZcX9ZngCmr3PdteAnMDUIIaoDGso6nA==", "dev": true, "dependencies": { "@stoplight/json": "~3.21.0", @@ -1709,7 +1735,7 @@ "pony-cause": "^1.0.0", "stacktracey": "^2.1.7", "tslib": "^2.3.0", - "yargs": "17.3.1" + "yargs": "~17.7.2" }, "bin": { "spectral": "dist/index.js" @@ -1873,20 +1899,33 @@ } }, "node_modules/@stoplight/spectral-parsers": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-parsers/-/spectral-parsers-1.0.3.tgz", - "integrity": "sha512-J0KW5Rh5cHWnJQ3yN+cr/ijNFVirPSR0pkQbdrNX30VboEl083UEDrQ3yov9kjLVIWEk9t9kKE7Eo3QT/k4JLA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-parsers/-/spectral-parsers-1.0.4.tgz", + "integrity": "sha512-nCTVvtX6q71M8o5Uvv9kxU31Gk1TRmgD6/k8HBhdCmKG6FWcwgjiZouA/R3xHLn/VwTI/9k8SdG5Mkdy0RBqbQ==", "dev": true, "dependencies": { "@stoplight/json": "~3.21.0", - "@stoplight/types": "^13.6.0", - "@stoplight/yaml": "~4.2.3", + "@stoplight/types": "^14.1.1", + "@stoplight/yaml": "~4.3.0", "tslib": "^2.3.1" }, "engines": { "node": "^12.20 || >=14.13" } }, + "node_modules/@stoplight/spectral-parsers/node_modules/@stoplight/types": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-14.1.1.tgz", + "integrity": "sha512-/kjtr+0t0tjKr+heVfviO9FrU/uGLc+QNX3fHJc19xsCNYqU7lVhaXxDmEID9BZTjG+/r9pK9xP/xU02XGg65g==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.4", + "utility-types": "^3.10.0" + }, + "engines": { + "node": "^12.20 || >=14.13" + } + }, "node_modules/@stoplight/spectral-ref-resolver": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@stoplight/spectral-ref-resolver/-/spectral-ref-resolver-1.0.4.tgz", @@ -1955,6 +1994,27 @@ "node": ">=12" } }, + "node_modules/@stoplight/spectral-ruleset-migrator/node_modules/@stoplight/yaml": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@stoplight/yaml/-/yaml-4.2.3.tgz", + "integrity": "sha512-Mx01wjRAR9C7yLMUyYFTfbUf5DimEpHMkRDQ1PKLe9dfNILbgdxyrncsOXM3vCpsQ1Hfj4bPiGl+u4u6e9Akqw==", + "dev": true, + "dependencies": { + "@stoplight/ordered-object-literal": "^1.0.1", + "@stoplight/types": "^13.0.0", + "@stoplight/yaml-ast-parser": "0.0.48", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=10.8" + } + }, + "node_modules/@stoplight/spectral-ruleset-migrator/node_modules/@stoplight/yaml-ast-parser": { + "version": "0.0.48", + "resolved": "https://registry.npmjs.org/@stoplight/yaml-ast-parser/-/yaml-ast-parser-0.0.48.tgz", + "integrity": "sha512-sV+51I7WYnLJnKPn2EMWgS4EUfoP4iWEbrWwbXsj0MZCB/xOK8j6+C9fntIdOM50kpx45ZLC3s6kwKivWuqvyg==", + "dev": true + }, "node_modules/@stoplight/spectral-rulesets": { "version": "1.18.1", "resolved": "https://registry.npmjs.org/@stoplight/spectral-rulesets/-/spectral-rulesets-1.18.1.tgz", @@ -2025,14 +2085,14 @@ } }, "node_modules/@stoplight/yaml": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@stoplight/yaml/-/yaml-4.2.3.tgz", - "integrity": "sha512-Mx01wjRAR9C7yLMUyYFTfbUf5DimEpHMkRDQ1PKLe9dfNILbgdxyrncsOXM3vCpsQ1Hfj4bPiGl+u4u6e9Akqw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@stoplight/yaml/-/yaml-4.3.0.tgz", + "integrity": "sha512-JZlVFE6/dYpP9tQmV0/ADfn32L9uFarHWxfcRhReKUnljz1ZiUM5zpX+PH8h5CJs6lao3TuFqnPm9IJJCEkE2w==", "dev": true, "dependencies": { - "@stoplight/ordered-object-literal": "^1.0.1", - "@stoplight/types": "^13.0.0", - "@stoplight/yaml-ast-parser": "0.0.48", + "@stoplight/ordered-object-literal": "^1.0.5", + "@stoplight/types": "^14.1.1", + "@stoplight/yaml-ast-parser": "0.0.50", "tslib": "^2.2.0" }, "engines": { @@ -2040,11 +2100,24 @@ } }, "node_modules/@stoplight/yaml-ast-parser": { - "version": "0.0.48", - "resolved": "https://registry.npmjs.org/@stoplight/yaml-ast-parser/-/yaml-ast-parser-0.0.48.tgz", - "integrity": "sha512-sV+51I7WYnLJnKPn2EMWgS4EUfoP4iWEbrWwbXsj0MZCB/xOK8j6+C9fntIdOM50kpx45ZLC3s6kwKivWuqvyg==", + "version": "0.0.50", + "resolved": "https://registry.npmjs.org/@stoplight/yaml-ast-parser/-/yaml-ast-parser-0.0.50.tgz", + "integrity": "sha512-Pb6M8TDO9DtSVla9yXSTAxmo9GVEouq5P40DWXdOie69bXogZTkgvopCq+yEvTMA0F6PEvdJmbtTV3ccIp11VQ==", "dev": true }, + "node_modules/@stoplight/yaml/node_modules/@stoplight/types": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-14.1.1.tgz", + "integrity": "sha512-/kjtr+0t0tjKr+heVfviO9FrU/uGLc+QNX3fHJc19xsCNYqU7lVhaXxDmEID9BZTjG+/r9pK9xP/xU02XGg65g==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.4", + "utility-types": "^3.10.0" + }, + "engines": { + "node": "^12.20 || >=14.13" + } + }, "node_modules/@stylistic/eslint-plugin-js": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-1.7.0.tgz", @@ -2065,9 +2138,9 @@ } }, "node_modules/@stylistic/stylelint-plugin": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-2.1.0.tgz", - "integrity": "sha512-mUZEW9uImHSbXeyzbFmHb8WPBv56UTaEnWL/3dGdAiJ54C+8GTfDwDVdI6gbqT9wV7zynkPu7tCXc5746H9mZQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-2.1.1.tgz", + "integrity": "sha512-xqHTmQZN7EbnFDW7jw0rAsdFNO4IRqvXhrh3qhUlIwF/x09Zm7kgs/ADktHxsTJYcw346PpGihsB0t4pZhpeHw==", "dev": true, "dependencies": { "@csstools/css-parser-algorithms": "^2.5.0", @@ -2144,9 +2217,9 @@ } }, "node_modules/@types/eslint": { - "version": "8.56.6", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.6.tgz", - "integrity": "sha512-ymwc+qb1XkjT/gfoQwxIeHZ6ixH23A+tCT2ADSA/DPVKzAjwYkTXBMCQ/f6fe4wEa85Lhp26VPeUxI7wMhAi7A==", + "version": "8.56.7", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.7.tgz", + "integrity": "sha512-SjDvI/x3zsZnOkYZ3lCt9lOZWZLB2jIlNKz+LBgCtDurK0JZcwucxYHn1w2BJkD34dgX9Tjnak0txtq4WTggEA==", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -2196,9 +2269,9 @@ "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" }, "node_modules/@types/node": { - "version": "20.11.30", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.30.tgz", - "integrity": "sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==", + "version": "20.12.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.4.tgz", + "integrity": "sha512-E+Fa9z3wSQpzgYQdYmme5X3OTuejnnTx88A6p6vkkJosR3KBz+HpE3kqNm98VE6cfLFcISx7zW7MsJkH6KwbTw==", "dependencies": { "undici-types": "~5.26.4" } @@ -2241,16 +2314,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.4.0.tgz", - "integrity": "sha512-yHMQ/oFaM7HZdVrVm/M2WHaNPgyuJH4WelkSVEWSSsir34kxW2kDJCxlXRhhGWEsMN0WAW/vLpKfKVcm8k+MPw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.5.0.tgz", + "integrity": "sha512-HpqNTH8Du34nLxbKgVMGljZMG0rJd2O9ecvr2QLYp+7512ty1j42KnsFwspPXg1Vh8an9YImf6CokUBltisZFQ==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.4.0", - "@typescript-eslint/type-utils": "7.4.0", - "@typescript-eslint/utils": "7.4.0", - "@typescript-eslint/visitor-keys": "7.4.0", + "@typescript-eslint/scope-manager": "7.5.0", + "@typescript-eslint/type-utils": "7.5.0", + "@typescript-eslint/utils": "7.5.0", + "@typescript-eslint/visitor-keys": "7.5.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -2276,15 +2349,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.4.0.tgz", - "integrity": "sha512-ZvKHxHLusweEUVwrGRXXUVzFgnWhigo4JurEj0dGF1tbcGh6buL+ejDdjxOQxv6ytcY1uhun1p2sm8iWStlgLQ==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.5.0.tgz", + "integrity": "sha512-cj+XGhNujfD2/wzR1tabNsidnYRaFfEkcULdcIyVBYcXjBvBKOes+mpMBP7hMpOyk+gBcfXsrg4NBGAStQyxjQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.4.0", - "@typescript-eslint/types": "7.4.0", - "@typescript-eslint/typescript-estree": "7.4.0", - "@typescript-eslint/visitor-keys": "7.4.0", + "@typescript-eslint/scope-manager": "7.5.0", + "@typescript-eslint/types": "7.5.0", + "@typescript-eslint/typescript-estree": "7.5.0", + "@typescript-eslint/visitor-keys": "7.5.0", "debug": "^4.3.4" }, "engines": { @@ -2304,13 +2377,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.4.0.tgz", - "integrity": "sha512-68VqENG5HK27ypafqLVs8qO+RkNc7TezCduYrx8YJpXq2QGZ30vmNZGJJJC48+MVn4G2dCV8m5ZTVnzRexTVtw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.5.0.tgz", + "integrity": "sha512-Z1r7uJY0MDeUlql9XJ6kRVgk/sP11sr3HKXn268HZyqL7i4cEfrdFuSSY/0tUqT37l5zT0tJOsuDP16kio85iA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.4.0", - "@typescript-eslint/visitor-keys": "7.4.0" + "@typescript-eslint/types": "7.5.0", + "@typescript-eslint/visitor-keys": "7.5.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2321,13 +2394,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.4.0.tgz", - "integrity": "sha512-247ETeHgr9WTRMqHbbQdzwzhuyaJ8dPTuyuUEMANqzMRB1rj/9qFIuIXK7l0FX9i9FXbHeBQl/4uz6mYuCE7Aw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.5.0.tgz", + "integrity": "sha512-A021Rj33+G8mx2Dqh0nMO9GyjjIBK3MqgVgZ2qlKf6CJy51wY/lkkFqq3TqqnH34XyAHUkq27IjlUkWlQRpLHw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.4.0", - "@typescript-eslint/utils": "7.4.0", + "@typescript-eslint/typescript-estree": "7.5.0", + "@typescript-eslint/utils": "7.5.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -2348,9 +2421,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.4.0.tgz", - "integrity": "sha512-mjQopsbffzJskos5B4HmbsadSJQWaRK0UxqQ7GuNA9Ga4bEKeiO6b2DnB6cM6bpc8lemaPseh0H9B/wyg+J7rw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.5.0.tgz", + "integrity": "sha512-tv5B4IHeAdhR7uS4+bf8Ov3k793VEVHd45viRRkehIUZxm0WF82VPiLgHzA/Xl4TGPg1ZD49vfxBKFPecD5/mg==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2361,13 +2434,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.4.0.tgz", - "integrity": "sha512-A99j5AYoME/UBQ1ucEbbMEmGkN7SE0BvZFreSnTd1luq7yulcHdyGamZKizU7canpGDWGJ+Q6ZA9SyQobipePg==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.5.0.tgz", + "integrity": "sha512-YklQQfe0Rv2PZEueLTUffiQGKQneiIEKKnfIqPIOxgM9lKSZFCjT5Ad4VqRKj/U4+kQE3fa8YQpskViL7WjdPQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.4.0", - "@typescript-eslint/visitor-keys": "7.4.0", + "@typescript-eslint/types": "7.5.0", + "@typescript-eslint/visitor-keys": "7.5.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2388,18 +2461,33 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@typescript-eslint/utils": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.4.0.tgz", - "integrity": "sha512-NQt9QLM4Tt8qrlBVY9lkMYzfYtNz8/6qwZg8pI3cMGlPnj6mOpRxxAm7BMJN9K0AiY+1BwJ5lVC650YJqYOuNg==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.5.0.tgz", + "integrity": "sha512-3vZl9u0R+/FLQcpy2EHyRGNqAS/ofJ3Ji8aebilfJe+fobK8+LbIFmrHciLVDxjDoONmufDcnVSF38KwMEOjzw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.4.0", - "@typescript-eslint/types": "7.4.0", - "@typescript-eslint/typescript-estree": "7.4.0", + "@typescript-eslint/scope-manager": "7.5.0", + "@typescript-eslint/types": "7.5.0", + "@typescript-eslint/typescript-estree": "7.5.0", "semver": "^7.5.4" }, "engines": { @@ -2414,12 +2502,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.4.0.tgz", - "integrity": "sha512-0zkC7YM0iX5Y41homUUeW1CHtZR01K3ybjM1l6QczoMuay0XKtrb93kv95AxUGwdjGr64nNqnOCwmEl616N8CA==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.5.0.tgz", + "integrity": "sha512-mcuHM/QircmA6O7fy6nn2w/3ditQkj+SgtOc8DW3uQ10Yfj42amm2i+6F2K4YAOPNNTmE6iM1ynM6lrSwdendA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/types": "7.5.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -2519,9 +2607,9 @@ } }, "node_modules/@vitest/snapshot/node_modules/magic-string": { - "version": "0.30.8", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", - "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "version": "0.30.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.9.tgz", + "integrity": "sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw==", "dev": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" @@ -2610,9 +2698,9 @@ } }, "node_modules/@vue/compiler-sfc/node_modules/magic-string": { - "version": "0.30.8", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", - "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "version": "0.30.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.9.tgz", + "integrity": "sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw==", "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" }, @@ -3478,9 +3566,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001600", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz", - "integrity": "sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==", + "version": "1.0.30001605", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001605.tgz", + "integrity": "sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ==", "funding": [ { "type": "opencollective", @@ -3872,21 +3960,21 @@ } }, "node_modules/css-loader": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.10.0.tgz", - "integrity": "sha512-LTSA/jWbwdMlk+rhmElbDR2vbtQoTBPr7fkJE+mxrHj+7ru0hUmHafDRzWIjIHTwpitWVaqY2/UWGRca3yUgRw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.0.0.tgz", + "integrity": "sha512-WrO4FVoamxt5zY9CauZjoJgXRi/LZKIk+Ta7YvpSGr5r/eMYPNp5/T9ODlMe4/1rF5DYlycG1avhV4g3A/tiAw==", "dependencies": { "icss-utils": "^5.1.0", "postcss": "^8.4.33", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.4", - "postcss-modules-scope": "^3.1.1", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", "postcss-modules-values": "^4.0.0", "postcss-value-parser": "^4.2.0", "semver": "^7.5.4" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", @@ -3894,7 +3982,7 @@ }, "peerDependencies": { "@rspack/core": "0.x || 1.x", - "webpack": "^5.0.0" + "webpack": "^5.27.0" }, "peerDependenciesMeta": { "@rspack/core": { @@ -4769,9 +4857,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.716", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.716.tgz", - "integrity": "sha512-t/MXMzFKQC3UfMDpw7V5wdB/UAB8dWx4hEsy+fpPYJWW3gqh3u5T1uXp6vR+H6dGCPBxkRo+YBcapBLvbGQHRw==" + "version": "1.4.727", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.727.tgz", + "integrity": "sha512-brpv4KTeC4g0Fx2FeIKytLd4UGn1zBQq5Lauy7zEWT9oqkaj5mgsxblEZIAOf1HHLlXxzr6adGViiBy5Z39/CA==" }, "node_modules/elkjs": { "version": "0.9.2", @@ -4842,9 +4930,9 @@ } }, "node_modules/es-abstract": { - "version": "1.23.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.2.tgz", - "integrity": "sha512-60s3Xv2T2p1ICykc7c+DNDPLDMm9t4QxCOUU0K9JxiLjM3C1zB9YVdN7tjxrFd4+AkZ8CdX1ovUga4P2+1e+/w==", + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.1", @@ -4886,11 +4974,11 @@ "safe-regex-test": "^1.0.3", "string.prototype.trim": "^1.2.9", "string.prototype.trimend": "^1.0.8", - "string.prototype.trimstart": "^1.0.7", + "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.2", "typed-array-byte-length": "^1.0.1", "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.5", + "typed-array-length": "^1.0.6", "unbox-primitive": "^1.0.2", "which-typed-array": "^1.1.15" }, @@ -5622,9 +5710,9 @@ } }, "node_modules/eslint-plugin-sonarjs": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.24.0.tgz", - "integrity": "sha512-87zp50mbbNrSTuoEOebdRQBPa0mdejA5UEjyuScyIw8hEpEjfWP89Qhkq5xVZfVyVSRQKZc9alVm7yRKQvvUmg==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.25.1.tgz", + "integrity": "sha512-5IOKvj/GMBNqjxBdItfotfRHo7w48496GOu1hxdeXuD0mB1JBlDCViiLHETDTfA8pDAVSBimBEQoetRXYceQEw==", "dev": true, "engines": { "node": ">=16" @@ -5634,9 +5722,9 @@ } }, "node_modules/eslint-plugin-unicorn": { - "version": "51.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-51.0.1.tgz", - "integrity": "sha512-MuR/+9VuB0fydoI0nIn2RDA5WISRn4AsJyNSaNKLVwie9/ONvQhxOBbkfSICBPnzKrB77Fh6CZZXjgTt/4Latw==", + "version": "52.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-52.0.0.tgz", + "integrity": "sha512-1Yzm7/m+0R4djH0tjDjfVei/ju2w3AzUGjG6q8JnuNIL5xIwsflyCooW5sfBvQp2pMYQFSWWCFONsjCax1EHng==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", @@ -5667,12 +5755,12 @@ } }, "node_modules/eslint-plugin-vitest": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vitest/-/eslint-plugin-vitest-0.4.0.tgz", - "integrity": "sha512-3oWgZIwdWVBQ5plvkmOBjreIGLQRdYb7x54OP8uIRHeZyRVJIdOn9o/qWVb9292fDMC8jn7H7d9TSFBZqhrykQ==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-vitest/-/eslint-plugin-vitest-0.4.1.tgz", + "integrity": "sha512-+PnZ2u/BS+f5FiuHXz4zKsHPcMKHie+K+1Uvu/x91ovkCMEOJqEI8E9Tw1Wzx2QRz4MHOBHYf1ypO8N1K0aNAA==", "dev": true, "dependencies": { - "@typescript-eslint/utils": "^7.2.0" + "@typescript-eslint/utils": "^7.4.0" }, "engines": { "node": "^18.0.0 || >= 20.0.0" @@ -6506,9 +6594,9 @@ } }, "node_modules/happy-dom": { - "version": "14.3.7", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-14.3.7.tgz", - "integrity": "sha512-lUfDRGzjrVJF2pnvh13OL+qEJ9eDpcedVLm77a3aMg8gPGKXfG+xFMNk3cOWetjucU8FveJ4qcSC/EX55nJ4fQ==", + "version": "14.5.0", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-14.5.0.tgz", + "integrity": "sha512-KvOtCq7eamc7cjihM0F1wj6FptuXzooc3Typa7Vgu6ns2uKGXC4BIFlK80SdH2w8zcW0gtxpBVI/sUqbYtljDA==", "dev": true, "dependencies": { "entities": "^4.5.0", @@ -7956,16 +8044,16 @@ } }, "node_modules/markdownlint-cli/node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", + "jackspeak": "^2.3.6", "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -8608,9 +8696,9 @@ } }, "node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -9133,11 +9221,11 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-scurry": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", - "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", "dependencies": { - "lru-cache": "^9.1.1 || ^10.0.0", + "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { @@ -9456,9 +9544,9 @@ } }, "node_modules/postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -9467,9 +9555,9 @@ } }, "node_modules/postcss-modules-local-by-default": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.4.tgz", - "integrity": "sha512-L4QzMnOdVwRm1Qb8m4x8jsZzKAaPAgrUF1r/hjDR2Xj7R+8Zsf97jAlSQzWtKx5YNiNGN8QxmPFIc/sh+RQl+Q==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", + "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", "dependencies": { "icss-utils": "^5.0.0", "postcss-selector-parser": "^6.0.2", @@ -9483,9 +9571,9 @@ } }, "node_modules/postcss-modules-scope": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.1.1.tgz", - "integrity": "sha512-uZgqzdTleelWjzJY+Fhti6F3C9iF1JR/dODLs/JDefozYcKTBCdD8BIl6nNPbTbcLnGrk56hzwZC2DaGNvYjzA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", + "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", "dependencies": { "postcss-selector-parser": "^6.0.4" }, @@ -9529,9 +9617,9 @@ } }, "node_modules/postcss-nesting": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-12.1.0.tgz", - "integrity": "sha512-QOYnosaZ+mlP6plQrAxFw09UUp2Sgtxj1BVHN+rSVbtV0Yx48zRt9/9F/ZOoxOKBBEsaJk2MYhhVRjeRRw5yuw==", + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-12.1.1.tgz", + "integrity": "sha512-qc74KvIAQNa5ujZKG1UV286dhaDW6basbUy2i9AzNU/T8C9hpvGu9NZzm1SfePe2yP7sPYgpA8d4sPVopn2Hhw==", "funding": [ { "type": "github", @@ -9544,7 +9632,7 @@ ], "dependencies": { "@csstools/selector-resolve-nested": "^1.1.0", - "@csstools/selector-specificity": "^3.0.2", + "@csstools/selector-specificity": "^3.0.3", "postcss-selector-parser": "^6.0.13" }, "engines": { @@ -10765,17 +10853,23 @@ } }, "node_modules/strip-literal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.0.0.tgz", - "integrity": "sha512-f9vHgsCWBq2ugHAkGMiiYY+AYG0D/cbloKKg0nhaaaSNsujdGIpVXCNsrJpCKr5M0f4aI31mr13UjY6GAuXCKA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.0.tgz", + "integrity": "sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==", "dev": true, "dependencies": { - "js-tokens": "^8.0.2" + "js-tokens": "^9.0.0" }, "funding": { "url": "https://github.com/sponsors/antfu" } }, + "node_modules/strip-literal/node_modules/js-tokens": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.0.tgz", + "integrity": "sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==", + "dev": true + }, "node_modules/style-search": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", @@ -10783,9 +10877,9 @@ "dev": true }, "node_modules/stylelint": { - "version": "16.3.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.3.0.tgz", - "integrity": "sha512-hqC6xNTbQ5HRGQXfIW4HwXcx09raIFz4W4XFbraeqWqYRVVY/ibYvI0dsu0ORMQY8re2bpDdCAeIa2cm+QJ4Sw==", + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.3.1.tgz", + "integrity": "sha512-/JOwQnBvxEKOT2RtNgGpBVXnCSMBgKOL2k7w0K52htwCyJls4+cHvc4YZgXlVoAZS9QJd2DgYAiRnja96pTgxw==", "dev": true, "dependencies": { "@csstools/css-parser-algorithms": "^2.6.1", @@ -11036,15 +11130,15 @@ } }, "node_modules/sucrase/node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", + "jackspeak": "^2.3.6", "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -11147,9 +11241,9 @@ } }, "node_modules/swagger-ui-dist": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.12.0.tgz", - "integrity": "sha512-Rt1xUpbHulJVGbiQjq9yy9/r/0Pg6TmpcG+fXTaMePDc8z5WUw4LfaWts5qcNv/8ewPvBIbY7DKq7qReIKNCCQ==" + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.13.0.tgz", + "integrity": "sha512-uaWhh6j18IIs5tOX0arvIBnVINAzpTXaQXkr7qAk8zoupegJVg0UU/5+S/FgsgVCnzVsJ9d7QLjIxkswEeTg0Q==" }, "node_modules/sync-fetch": { "version": "0.4.5", @@ -11180,9 +11274,9 @@ } }, "node_modules/table": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", - "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz", + "integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==", "dev": true, "dependencies": { "ajv": "^8.0.1", @@ -11196,9 +11290,9 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz", - "integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz", + "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -11208,7 +11302,7 @@ "fast-glob": "^3.3.0", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jiti": "^1.19.1", + "jiti": "^1.21.0", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", @@ -11298,9 +11392,9 @@ "integrity": "sha512-r1AT0XdEp8TMQ13FLvOt8mOtAxDQsRt2QU5rSWCA7YfshddU651Y1NHVrceLANvixKdf9fYO8B/S9fXHodB7HQ==" }, "node_modules/terser": { - "version": "5.29.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.2.tgz", - "integrity": "sha512-ZiGkhUBIM+7LwkNjXYJq8svgkd+QK3UUr0wJqY4MieaezBSAIPgbSPZyIx0idM6XWK5CMzSWa8MJIzmRcB8Caw==", + "version": "5.30.3", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.3.tgz", + "integrity": "sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -11655,9 +11749,9 @@ } }, "node_modules/typescript": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", - "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz", + "integrity": "sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==", "devOptional": true, "peer": true, "bin": { @@ -11854,13 +11948,13 @@ "integrity": "sha512-z2YZusTFC6KnLERx1cgoIRX2CjPRP0W75N+3CC6gbvdX5Ch47rZkEMGO2Xnf+IEmi3RiFLxS18gayMA27iU7Kg==" }, "node_modules/vite": { - "version": "5.2.6", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.6.tgz", - "integrity": "sha512-FPtnxFlSIKYjZ2eosBQamz4CbyrTizbZ3hnGJlh/wMtCrlp1Hah6AzBLjGI5I2urTfNnpovpHdrL6YRuBOPnCA==", + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.8.tgz", + "integrity": "sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==", "dev": true, "dependencies": { "esbuild": "^0.20.1", - "postcss": "^8.4.36", + "postcss": "^8.4.38", "rollup": "^4.13.0" }, "bin": { @@ -11957,9 +12051,9 @@ } }, "node_modules/vite/node_modules/rollup": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz", - "integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.0.tgz", + "integrity": "sha512-Qe7w62TyawbDzB4yt32R0+AbIo6m1/sqO7UPzFS8Z/ksL5mrfhA0v4CavfdmFav3D+ub4QeAgsGEe84DoWe/nQ==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -11972,19 +12066,21 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.13.0", - "@rollup/rollup-android-arm64": "4.13.0", - "@rollup/rollup-darwin-arm64": "4.13.0", - "@rollup/rollup-darwin-x64": "4.13.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.13.0", - "@rollup/rollup-linux-arm64-gnu": "4.13.0", - "@rollup/rollup-linux-arm64-musl": "4.13.0", - "@rollup/rollup-linux-riscv64-gnu": "4.13.0", - "@rollup/rollup-linux-x64-gnu": "4.13.0", - "@rollup/rollup-linux-x64-musl": "4.13.0", - "@rollup/rollup-win32-arm64-msvc": "4.13.0", - "@rollup/rollup-win32-ia32-msvc": "4.13.0", - "@rollup/rollup-win32-x64-msvc": "4.13.0", + "@rollup/rollup-android-arm-eabi": "4.14.0", + "@rollup/rollup-android-arm64": "4.14.0", + "@rollup/rollup-darwin-arm64": "4.14.0", + "@rollup/rollup-darwin-x64": "4.14.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.14.0", + "@rollup/rollup-linux-arm64-gnu": "4.14.0", + "@rollup/rollup-linux-arm64-musl": "4.14.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.14.0", + "@rollup/rollup-linux-riscv64-gnu": "4.14.0", + "@rollup/rollup-linux-s390x-gnu": "4.14.0", + "@rollup/rollup-linux-x64-gnu": "4.14.0", + "@rollup/rollup-linux-x64-musl": "4.14.0", + "@rollup/rollup-win32-arm64-msvc": "4.14.0", + "@rollup/rollup-win32-ia32-msvc": "4.14.0", + "@rollup/rollup-win32-x64-msvc": "4.14.0", "fsevents": "~2.3.2" } }, @@ -12054,9 +12150,9 @@ } }, "node_modules/vitest/node_modules/magic-string": { - "version": "0.30.8", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", - "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "version": "0.30.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.9.tgz", + "integrity": "sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw==", "dev": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" @@ -12664,18 +12760,18 @@ } }, "node_modules/yargs": { - "version": "17.3.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", - "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" + "yargs-parser": "^21.1.1" }, "engines": { "node": ">=12" @@ -12690,6 +12786,37 @@ "node": ">=12" } }, + "node_modules/yargs/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 004ac9e2bf..f58c3b4d8f 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "chartjs-adapter-dayjs-4": "1.0.4", "chartjs-plugin-zoom": "2.0.1", "clippie": "4.0.7", - "css-loader": "6.10.0", + "css-loader": "7.0.0", "dayjs": "1.11.10", "dropzone": "6.0.0-beta.2", "easymde": "2.18.0", @@ -34,17 +34,17 @@ "license-checker-webpack-plugin": "0.2.1", "mermaid": "10.9.0", "mini-css-extract-plugin": "2.8.1", - "minimatch": "9.0.3", + "minimatch": "9.0.4", "monaco-editor": "0.47.0", "monaco-editor-webpack-plugin": "7.1.0", "pdfobject": "2.3.0", "postcss": "8.4.38", "postcss-loader": "8.1.1", - "postcss-nesting": "12.1.0", + "postcss-nesting": "12.1.1", "pretty-ms": "9.0.0", "sortablejs": "1.15.2", - "swagger-ui-dist": "5.12.0", - "tailwindcss": "3.4.1", + "swagger-ui-dist": "5.13.0", + "tailwindcss": "3.4.3", "temporal-polyfill": "0.2.3", "throttle-debounce": "5.0.0", "tinycolor2": "1.6.0", @@ -65,9 +65,9 @@ "devDependencies": { "@eslint-community/eslint-plugin-eslint-comments": "4.1.0", "@playwright/test": "1.42.1", - "@stoplight/spectral-cli": "6.11.0", + "@stoplight/spectral-cli": "6.11.1", "@stylistic/eslint-plugin-js": "1.7.0", - "@stylistic/stylelint-plugin": "2.1.0", + "@stylistic/stylelint-plugin": "2.1.1", "@vitejs/plugin-vue": "5.0.4", "eslint": "8.57.0", "eslint-plugin-array-func": "4.0.0", @@ -77,17 +77,17 @@ "eslint-plugin-no-jquery": "2.7.0", "eslint-plugin-no-use-extend-native": "0.5.0", "eslint-plugin-regexp": "2.4.0", - "eslint-plugin-sonarjs": "0.24.0", - "eslint-plugin-unicorn": "51.0.1", - "eslint-plugin-vitest": "0.4.0", + "eslint-plugin-sonarjs": "0.25.1", + "eslint-plugin-unicorn": "52.0.0", + "eslint-plugin-vitest": "0.4.1", "eslint-plugin-vitest-globals": "1.5.0", "eslint-plugin-vue": "9.24.0", "eslint-plugin-vue-scoped-css": "2.8.0", "eslint-plugin-wc": "2.0.4", - "happy-dom": "14.3.7", + "happy-dom": "14.5.0", "markdownlint-cli": "0.39.0", "postcss-html": "1.6.0", - "stylelint": "16.3.0", + "stylelint": "16.3.1", "stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-declaration-strict-value": "1.10.4", "stylelint-value-no-unknown-custom-properties": "6.0.1", From 556099fa72f6239aa9446d06265876bc72b021b8 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Fri, 5 Apr 2024 13:11:26 +0200 Subject: [PATCH 045/370] Add gap to commit status details (#30284) Before: <img width="162" alt="Screenshot 2024-04-05 at 02 25 27" src="https://github.com/go-gitea/gitea/assets/115237/9f786811-3e45-4b3c-aaf9-e1d2cad284d2"> After: <img width="172" alt="Screenshot 2024-04-05 at 02 27 25" src="https://github.com/go-gitea/gitea/assets/115237/f5254877-9e0d-44cb-9605-ba15c75872bb"> --- web_src/css/repo.css | 1 + 1 file changed, 1 insertion(+) diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 705d652b54..653af379d5 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -2855,6 +2855,7 @@ tbody.commit-list { display: flex; align-items: center; justify-content: flex-end; + gap: 8px; } @media (max-width: 767.98px) { From b2b49c9bde63b311f01d500ada9212c46b9602fe Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sat, 6 Apr 2024 02:03:07 +0800 Subject: [PATCH 046/370] Fix view commit link (#30297) Fix #30098 --- templates/repo/commits_list.tmpl | 173 +++++++++++++++---------------- 1 file changed, 86 insertions(+), 87 deletions(-) diff --git a/templates/repo/commits_list.tmpl b/templates/repo/commits_list.tmpl index 53052333fa..be73c4ca18 100644 --- a/templates/repo/commits_list.tmpl +++ b/templates/repo/commits_list.tmpl @@ -1,92 +1,91 @@ <div class="ui attached table segment commit-table"> - <table class="ui very basic striped table unstackable" id="commits-table"> - <thead> + <table class="ui very basic striped table unstackable" id="commits-table"> + <thead> + <tr> + <th class="three wide">{{ctx.Locale.Tr "repo.commits.author"}}</th> + <th class="two wide sha">{{StringUtils.ToUpper $.Repository.ObjectFormatName}}</th> + <th class="eight wide message">{{ctx.Locale.Tr "repo.commits.message"}}</th> + <th class="two wide right aligned">{{ctx.Locale.Tr "repo.commits.date"}}</th> + <th class="one wide"></th> + </tr> + </thead> + <tbody class="commit-list"> + {{$commitRepoLink := $.RepoLink}}{{if $.CommitRepoLink}}{{$commitRepoLink = $.CommitRepoLink}}{{end}} + {{range .Commits}} <tr> - <th class="three wide">{{ctx.Locale.Tr "repo.commits.author"}}</th> - <th class="two wide sha">{{StringUtils.ToUpper $.Repository.ObjectFormatName}}</th> - <th class="eight wide message">{{ctx.Locale.Tr "repo.commits.message"}}</th> - <th class="two wide right aligned">{{ctx.Locale.Tr "repo.commits.date"}}</th> - <th class="one wide"></th> - </tr> - </thead> - <tbody class="commit-list"> - {{$commitRepoLink := $.RepoLink}}{{if $.CommitRepoLink}}{{$commitRepoLink = $.CommitRepoLink}}{{end}} - {{range .Commits}} - <tr> - <td class="author tw-flex"> - {{$userName := .Author.Name}} - {{if .User}} - {{if and .User.FullName DefaultShowFullName}} - {{$userName = .User.FullName}} - {{end}} - {{ctx.AvatarUtils.Avatar .User 28 "tw-mr-2"}}<a class="muted author-wrapper" href="{{.User.HomeLink}}">{{$userName}}</a> - {{else}} - {{ctx.AvatarUtils.AvatarByEmail .Author.Email .Author.Name 28 "tw-mr-2"}} - <span class="author-wrapper">{{$userName}}</span> + <td class="author tw-flex"> + {{$userName := .Author.Name}} + {{if .User}} + {{if and .User.FullName DefaultShowFullName}} + {{$userName = .User.FullName}} {{end}} - </td> - <td class="sha"> - {{$class := "ui sha label"}} - {{if .Signature}} - {{$class = (print $class " isSigned")}} - {{if .Verification.Verified}} - {{if eq .Verification.TrustStatus "trusted"}} - {{$class = (print $class " isVerified")}} - {{else if eq .Verification.TrustStatus "untrusted"}} - {{$class = (print $class " isVerifiedUntrusted")}} - {{else}} - {{$class = (print $class " isVerifiedUnmatched")}} - {{end}} - {{else if .Verification.Warning}} - {{$class = (print $class " isWarning")}} - {{end}} - {{end}} - {{$commitShaLink := ""}} - {{if $.PageIsWiki}} - {{$commitShaLink = (printf "%s/wiki/commit/%s" $commitRepoLink (PathEscape .ID.String))}} - {{else if $.PageIsPullCommits}} - {{$commitShaLink = (printf "%s/pulls/%d/commits/%s" $commitRepoLink $.Issue.Index (PathEscape .ID.String))}} - {{else if $.Reponame}} - {{$commitShaLink = (printf "%s/commit/%s" $commitRepoLink (PathEscape .ID.String))}} - {{end}} - <a {{if $commitShaLink}}href="{{$commitShaLink}}"{{end}} class="{{$class}}"> - <span class="shortsha">{{ShortSha .ID.String}}</span> - {{if .Signature}}{{template "repo/shabox_badge" dict "root" $ "verification" .Verification}}{{end}} - </a> - </td> - <td class="message"> - <span class="message-wrapper"> - {{if $.PageIsWiki}} - <span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{.Summary | RenderEmoji $.Context}}</span> - {{else}} - {{$commitLink:= printf "%s/commit/%s" $commitRepoLink (PathEscape .ID.String)}} - <span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{RenderCommitMessageLinkSubject $.Context .Message $commitLink ($.Repository.ComposeMetas ctx)}}</span> - {{end}} - </span> - {{if IsMultilineCommitMessage .Message}} - <button class="ui button js-toggle-commit-body ellipsis-button" aria-expanded="false">...</button> - {{end}} - {{template "repo/commit_statuses" dict "Status" .Status "Statuses" .Statuses}} - {{if IsMultilineCommitMessage .Message}} - <pre class="commit-body tw-hidden">{{RenderCommitBody $.Context .Message ($.Repository.ComposeMetas ctx)}}</pre> - {{end}} - </td> - {{if .Committer}} - <td class="text right aligned">{{TimeSince .Committer.When ctx.Locale}}</td> + {{ctx.AvatarUtils.Avatar .User 28 "tw-mr-2"}}<a class="muted author-wrapper" href="{{.User.HomeLink}}">{{$userName}}</a> {{else}} - <td class="text right aligned">{{TimeSince .Author.When ctx.Locale}}</td> + {{ctx.AvatarUtils.AvatarByEmail .Author.Email .Author.Name 28 "tw-mr-2"}} + <span class="author-wrapper">{{$userName}}</span> {{end}} - <td class="text right aligned tw-py-0"> - <button class="btn interact-bg tw-p-2" data-tooltip-content="{{ctx.Locale.Tr "copy_hash"}}" data-clipboard-text="{{.ID}}">{{svg "octicon-copy"}}</button> - <a - class="btn interact-bg tw-p-2" - data-tooltip-content="{{ctx.Locale.Tr "repo.commits.view_path"}}" - href="{{if $.FileName}}{{printf "%s/src/commit/%s/%s" $commitRepoLink (PathEscape .ID.String) (PathEscapeSegments $.FileName)}}{{else}}{{printf "%s/src/commit/%s" $commitRepoLink (PathEscape .ID.String)}}{{end}}"> - {{svg "octicon-file-code"}} - </a> - </td> - </tr> - {{end}} - </tbody> - </table> - </div> + </td> + <td class="sha"> + {{$class := "ui sha label"}} + {{if .Signature}} + {{$class = (print $class " isSigned")}} + {{if .Verification.Verified}} + {{if eq .Verification.TrustStatus "trusted"}} + {{$class = (print $class " isVerified")}} + {{else if eq .Verification.TrustStatus "untrusted"}} + {{$class = (print $class " isVerifiedUntrusted")}} + {{else}} + {{$class = (print $class " isVerifiedUnmatched")}} + {{end}} + {{else if .Verification.Warning}} + {{$class = (print $class " isWarning")}} + {{end}} + {{end}} + {{$commitShaLink := ""}} + {{if $.PageIsWiki}} + {{$commitShaLink = (printf "%s/wiki/commit/%s" $commitRepoLink (PathEscape .ID.String))}} + {{else if $.PageIsPullCommits}} + {{$commitShaLink = (printf "%s/pulls/%d/commits/%s" $commitRepoLink $.Issue.Index (PathEscape .ID.String))}} + {{else if $.Reponame}} + {{$commitShaLink = (printf "%s/commit/%s" $commitRepoLink (PathEscape .ID.String))}} + {{end}} + <a {{if $commitShaLink}}href="{{$commitShaLink}}"{{end}} class="{{$class}}"> + <span class="shortsha">{{ShortSha .ID.String}}</span> + {{if .Signature}}{{template "repo/shabox_badge" dict "root" $ "verification" .Verification}}{{end}} + </a> + </td> + <td class="message"> + <span class="message-wrapper"> + {{if $.PageIsWiki}} + <span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{.Summary | RenderEmoji $.Context}}</span> + {{else}} + {{$commitLink:= printf "%s/commit/%s" $commitRepoLink (PathEscape .ID.String)}} + <span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{RenderCommitMessageLinkSubject $.Context .Message $commitLink ($.Repository.ComposeMetas ctx)}}</span> + {{end}} + </span> + {{if IsMultilineCommitMessage .Message}} + <button class="ui button js-toggle-commit-body ellipsis-button" aria-expanded="false">...</button> + {{end}} + {{template "repo/commit_statuses" dict "Status" .Status "Statuses" .Statuses}} + {{if IsMultilineCommitMessage .Message}} + <pre class="commit-body tw-hidden">{{RenderCommitBody $.Context .Message ($.Repository.ComposeMetas ctx)}}</pre> + {{end}} + </td> + {{if .Committer}} + <td class="text right aligned">{{TimeSince .Committer.When ctx.Locale}}</td> + {{else}} + <td class="text right aligned">{{TimeSince .Author.When ctx.Locale}}</td> + {{end}} + <td class="text right aligned tw-py-0"> + <button class="btn interact-bg tw-p-2" data-tooltip-content="{{ctx.Locale.Tr "copy_hash"}}" data-clipboard-text="{{.ID}}">{{svg "octicon-copy"}}</button> + {{if not $.PageIsWiki}}{{/* at the moment, wiki doesn't support "view at history point*/}} + {{$viewCommitLink := printf "%s/src/commit/%s" $commitRepoLink (PathEscape .ID.String)}} + {{if $.FileName}}{{$viewCommitLink = printf "%s/%s" $viewCommitLink (PathEscapeSegments $.FileName)}}{{end}} + <a class="btn interact-bg tw-p-2" data-tooltip-content="{{ctx.Locale.Tr "repo.commits.view_path"}}" href="{{$viewCommitLink}}">{{svg "octicon-file-code"}}</a> + {{end}} + </td> + </tr> + {{end}} + </tbody> + </table> +</div> From 9c1f4dae2ee85b748250ba7b161d70bd529088d3 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sat, 6 Apr 2024 10:25:39 +0200 Subject: [PATCH 047/370] Always use `octicon-eye` on watch button (#30288) This might appear odd but I think it's the right thing to do: On Github, the "Watch" button always has the open eye icon: <img width="177" alt="Screenshot 2024-04-05 at 08 26 48" src="https://github.com/go-gitea/gitea/assets/115237/0c1188d1-145b-4c6d-909f-2e1460499941"> <img width="179" alt="Screenshot 2024-04-05 at 08 26 40" src="https://github.com/go-gitea/gitea/assets/115237/e29d91fa-f122-4e10-9589-f79c1d612cf9"> On Gitea, while watching, the icon is this and this sometimes confuses me slightly, being used to above: <img width="158" alt="Screenshot 2024-04-05 at 08 29 08" src="https://github.com/go-gitea/gitea/assets/115237/3301021b-744e-409f-a9d8-887ec2772fdc"> After this PR, both states will use the same icon: <img width="145" alt="Screenshot 2024-04-05 at 08 26 27" src="https://github.com/go-gitea/gitea/assets/115237/8addfa5b-c009-4bdb-bfa1-4f3dfaffa4cd"> <img width="161" alt="Screenshot 2024-04-05 at 08 26 33" src="https://github.com/go-gitea/gitea/assets/115237/cef383e6-2cc0-460f-a4d3-83ebb321debe"> --- templates/repo/watch_unwatch.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/watch_unwatch.tmpl b/templates/repo/watch_unwatch.tmpl index 2bf2c7bd21..64be971416 100644 --- a/templates/repo/watch_unwatch.tmpl +++ b/templates/repo/watch_unwatch.tmpl @@ -3,7 +3,7 @@ {{$buttonText := ctx.Locale.Tr "repo.watch"}} {{if $.IsWatchingRepo}}{{$buttonText = ctx.Locale.Tr "repo.unwatch"}}{{end}} <button type="submit" class="ui compact small basic button"{{if not $.IsSigned}} disabled{{end}} aria-label="{{$buttonText}}"> - {{if $.IsWatchingRepo}}{{svg "octicon-eye-closed"}}{{else}}{{svg "octicon-eye"}}{{end}} + {{svg "octicon-eye"}} <span class="not-mobile" aria-hidden="true">{{$buttonText}}</span> </button> <a hx-boost="false" class="ui basic label" href="{{.RepoLink}}/watchers"> From 7396172a02a9ea8d80f9763469fd65a5a12ff3f7 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sat, 6 Apr 2024 20:07:08 +0800 Subject: [PATCH 048/370] Fix code block style for code preview (#30298) Fix #30292 To avoid unnecessary style overriding, use "div" instead of "code" --- modules/markup/sanitizer.go | 2 +- services/markup/processorhelper_codepreview_test.go | 6 +++--- templates/base/markup_codepreview.tmpl | 2 +- web_src/css/markup/content.css | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/markup/sanitizer.go b/modules/markup/sanitizer.go index 77fbdf4520..570a1da248 100644 --- a/modules/markup/sanitizer.go +++ b/modules/markup/sanitizer.go @@ -65,7 +65,7 @@ func createDefaultPolicy() *bluemonday.Policy { policy.AllowAttrs("class").Matching(regexp.MustCompile(`^lines-num$`)).OnElements("td") policy.AllowAttrs("data-line-number").OnElements("span") policy.AllowAttrs("class").Matching(regexp.MustCompile(`^lines-code chroma$`)).OnElements("td") - policy.AllowAttrs("class").Matching(regexp.MustCompile(`^code-inner$`)).OnElements("code") + policy.AllowAttrs("class").Matching(regexp.MustCompile(`^code-inner$`)).OnElements("div") // For code preview (unicode escape) policy.AllowAttrs("class").Matching(regexp.MustCompile(`^file-view( unicode-escaped)?$`)).OnElements("table") diff --git a/services/markup/processorhelper_codepreview_test.go b/services/markup/processorhelper_codepreview_test.go index 01db792925..154e4e8e44 100644 --- a/services/markup/processorhelper_codepreview_test.go +++ b/services/markup/processorhelper_codepreview_test.go @@ -36,10 +36,10 @@ func TestProcessorHelperCodePreview(t *testing.T) { <table class="file-view"> <tbody><tr> <td class="lines-num"><span data-line-number="1"></span></td> - <td class="lines-code chroma"><code class="code-inner"><span class="gh"># repo1</code></td> + <td class="lines-code chroma"><div class="code-inner"><span class="gh"># repo1</div></td> </tr><tr> <td class="lines-num"><span data-line-number="2"></span></td> - <td class="lines-code chroma"><code class="code-inner"></span><span class="gh"></span></code></td> + <td class="lines-code chroma"><div class="code-inner"></span><span class="gh"></span></div></td> </tr></tbody> </table> </div> @@ -63,7 +63,7 @@ func TestProcessorHelperCodePreview(t *testing.T) { <table class="file-view"> <tbody><tr> <td class="lines-num"><span data-line-number="1"></span></td> - <td class="lines-code chroma"><code class="code-inner"><span class="gh"># repo1</code></td> + <td class="lines-code chroma"><div class="code-inner"><span class="gh"># repo1</div></td> </tr></tbody> </table> </div> diff --git a/templates/base/markup_codepreview.tmpl b/templates/base/markup_codepreview.tmpl index c65ab28406..a1a4f26b47 100644 --- a/templates/base/markup_codepreview.tmpl +++ b/templates/base/markup_codepreview.tmpl @@ -17,7 +17,7 @@ {{- $lineEscapeStatus := index $.LineEscapeStatus $idx -}} <td class="lines-escape">{{if $lineEscapeStatus.Escaped}}<a href="#" class="toggle-escape-button btn interact-bg" title="{{if $lineEscapeStatus.HasInvisible}}{{ctx.Locale.Tr "repo.invisible_runes_line"}} {{end}}{{if $lineEscapeStatus.HasAmbiguous}}{{ctx.Locale.Tr "repo.ambiguous_runes_line"}}{{end}}"></a>{{end}}</td> {{- end}} - <td class="lines-code chroma"><code class="code-inner">{{$line.FormattedContent}}</code></td> + <td class="lines-code chroma"><div class="code-inner">{{$line.FormattedContent}}</div></td>{{/* only div works, span generates incorrect HTML structure */}} </tr> {{- end -}} </tbody> diff --git a/web_src/css/markup/content.css b/web_src/css/markup/content.css index 376d3030c7..d44e727a25 100644 --- a/web_src/css/markup/content.css +++ b/web_src/css/markup/content.css @@ -432,7 +432,7 @@ text-align: right; } -.markup code:not(.code-inner), +.markup code, .markup tt { padding: 0.2em 0.4em; margin: 0; From 662eb4b0852f9ce2c161e7fea5ac66bf912fc9f6 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sat, 6 Apr 2024 23:06:27 +0200 Subject: [PATCH 049/370] Markup color and font size fixes (#30282) 1. Distinguish inline an block code with new CSS variable `--color-markup-code-inline` 2. Various color tweaks, better contrast from background <img width="447" alt="Screenshot 2024-04-05 at 00 51 00" src="https://github.com/go-gitea/gitea/assets/115237/93e069f4-6807-4f2c-9331-2d69730919d4"> <img width="456" alt="Screenshot 2024-04-05 at 00 50 44" src="https://github.com/go-gitea/gitea/assets/115237/0dc9c745-c531-40fa-94ec-b0ba10bd7ccf"> --- web_src/css/markup/content.css | 4 ++-- web_src/css/themes/theme-gitea-dark.css | 5 +++-- web_src/css/themes/theme-gitea-light.css | 5 +++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/web_src/css/markup/content.css b/web_src/css/markup/content.css index d44e727a25..6ba4e40072 100644 --- a/web_src/css/markup/content.css +++ b/web_src/css/markup/content.css @@ -438,7 +438,7 @@ margin: 0; font-size: 85%; white-space: break-spaces; - background-color: var(--color-markup-code-block); + background-color: var(--color-markup-code-inline); border-radius: var(--border-radius); } @@ -508,7 +508,7 @@ line-height: 10px; color: var(--color-text-light); vertical-align: middle; - background-color: var(--color-markup-code-block); + background-color: var(--color-markup-code-inline); border: 1px solid var(--color-secondary); border-radius: var(--border-radius); box-shadow: inset 0 -1px 0 var(--color-secondary); diff --git a/web_src/css/themes/theme-gitea-dark.css b/web_src/css/themes/theme-gitea-dark.css index 626590ca54..07e217742d 100644 --- a/web_src/css/themes/theme-gitea-dark.css +++ b/web_src/css/themes/theme-gitea-dark.css @@ -204,8 +204,9 @@ --color-active: #e8e8ff24; --color-menu: #151a1e; --color-card: #151a1e; - --color-markup-table-row: #e8e8ff06; - --color-markup-code-block: #e8e8ff16; + --color-markup-table-row: #e8e8ff0f; + --color-markup-code-block: #e8e8ff12; + --color-markup-code-inline: #e8e8ff28; --color-button: #151a1e; --color-code-bg: #14171a; --color-shadow: #00001758; diff --git a/web_src/css/themes/theme-gitea-light.css b/web_src/css/themes/theme-gitea-light.css index f6913fbe22..2741e0e0bd 100644 --- a/web_src/css/themes/theme-gitea-light.css +++ b/web_src/css/themes/theme-gitea-light.css @@ -204,8 +204,9 @@ --color-active: #00001714; --color-menu: #f8f9fb; --color-card: #f8f9fb; - --color-markup-table-row: #00001708; - --color-markup-code-block: #00001710; + --color-markup-table-row: #0030600a; + --color-markup-code-block: #00306010; + --color-markup-code-inline: #00306012; --color-button: #f8f9fb; --color-code-bg: #fafdff; --color-shadow: #00001726; From 649aada3664f5adccdaecc7dd24b8252ae070220 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sat, 6 Apr 2024 23:33:45 +0200 Subject: [PATCH 050/370] Remove fomantic list module (#30281) Likely still some unnecessary CSS but any combinations with the `ui list` classes are covered. There was only on instance of `horizontal list` which I removed. It was this part of the commit page: <img width="396" alt="image" src="https://github.com/go-gitea/gitea/assets/115237/c49ec4f5-93c3-41d6-a907-cdbedf8abc44"> --- templates/repo/commit_page.tmpl | 4 +- templates/user/settings/repos.tmpl | 2 +- web_src/css/base.css | 29 +- web_src/css/index.css | 1 + web_src/css/modules/list.css | 187 ++++++ web_src/fomantic/build/semantic.css | 977 ---------------------------- web_src/fomantic/semantic.json | 1 - 7 files changed, 192 insertions(+), 1009 deletions(-) create mode 100644 web_src/css/modules/list.css diff --git a/templates/repo/commit_page.tmpl b/templates/repo/commit_page.tmpl index 3ae7fffa1c..49a0b445b1 100644 --- a/templates/repo/commit_page.tmpl +++ b/templates/repo/commit_page.tmpl @@ -164,9 +164,9 @@ {{end}} {{end}} </div> - <div class="ui horizontal list tw-flex tw-items-center"> + <div class="tw-flex tw-items-center"> {{if .Parents}} - <div class="item"> + <div> <span>{{ctx.Locale.Tr "repo.diff.parent"}}</span> {{range .Parents}} {{if $.PageIsWiki}} diff --git a/templates/user/settings/repos.tmpl b/templates/user/settings/repos.tmpl index c874ccd878..26b9dfeed9 100644 --- a/templates/user/settings/repos.tmpl +++ b/templates/user/settings/repos.tmpl @@ -6,7 +6,7 @@ <div class="ui attached segment"> {{if or .allowAdopt .allowDelete}} {{if .Dirs}} - <div class="ui middle aligned divided list"> + <div class="ui list"> {{range $dirI, $dir := .Dirs}} {{$repo := index $.ReposMap $dir}} <div class="item {{if not $repo}}tw-py-1{{end}}">{{/* if not repo, then there are "adapt" buttons, so the padding shouldn't be that default large*/}} diff --git a/web_src/css/base.css b/web_src/css/base.css index 05ddba3223..096b67058e 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -44,7 +44,7 @@ html, body { } body { - line-height: 1.4285rem; + line-height: 20px; font-family: var(--fonts-regular); color: var(--color-text); background-color: var(--color-body); @@ -305,14 +305,6 @@ a.label, background-color: var(--color-label-bg); } -/* fix Fomantic's line-height causing vertical scrollbars to appear */ -ul.ui.list li, -ol.ui.list li, -.ui.list > .item, -.ui.list .list > .item { - line-height: var(--line-height-default); -} - .ui.menu { display: flex; } @@ -456,21 +448,6 @@ ol.ui.list li, color: var(--color-text-light-2); } -.ui.list .list > .item .header, -.ui.list > .item .header { - color: var(--color-text-dark); -} - -.ui.list .list > .item > .content, -.ui.list > .item > .content { - color: var(--color-text); -} - -.ui.list .list > .item .description, -.ui.list > .item .description { - color: var(--color-text); -} - /* replace item margin on secondary menu items with gap and remove both the negative margins on the menu as well as margin on the items */ .ui.secondary.menu { @@ -589,10 +566,6 @@ img.ui.avatar, aspect-ratio: 1; } -.ui.divided.list > .item { - border-color: var(--color-secondary); -} - .ui.error.message .header, .ui.warning.message .header { color: inherit; diff --git a/web_src/css/index.css b/web_src/css/index.css index 7be8065dc7..ad59f32636 100644 --- a/web_src/css/index.css +++ b/web_src/css/index.css @@ -8,6 +8,7 @@ @import "./modules/header.css"; @import "./modules/input.css"; @import "./modules/label.css"; +@import "./modules/list.css"; @import "./modules/segment.css"; @import "./modules/grid.css"; @import "./modules/message.css"; diff --git a/web_src/css/modules/list.css b/web_src/css/modules/list.css new file mode 100644 index 0000000000..73760390de --- /dev/null +++ b/web_src/css/modules/list.css @@ -0,0 +1,187 @@ +/* based on Fomantic UI list module, with just the parts extracted that we use. If you find any + unused rules here after refactoring, please remove them. */ + +.ui.list { + list-style-type: none; + margin: 1em 0; + padding: 0; + font-size: 1em; +} + +.ui.list:first-child { + margin-top: 0; + padding-top: 0; +} + +.ui.list:last-child { + margin-bottom: 0; + padding-bottom: 0; +} + +.ui.list > .item, +.ui.list .list > .item { + display: list-item; + table-layout: fixed; + list-style-type: none; + list-style-position: outside; +} + +.ui.list > .list > .item::after, +.ui.list > .item::after { + content: ""; + display: block; + height: 0; + clear: both; + visibility: hidden; +} + +.ui.list .list:not(.icon) { + clear: both; + margin: 0; + padding: 0.75em 0 0.25em 0.5em; +} + +.ui.list .list > .item { + padding: 0.14285714em 0; +} + +.ui.list .list > .item > i.icon, +.ui.list > .item > i.icon { + display: table-cell; + min-width: 1.55em; + padding-top: 0; + transition: color 0.1s ease; + padding-right: 0.28571429em; + vertical-align: top; +} +.ui.list .list > .item > i.icon:only-child, +.ui.list > .item > i.icon:only-child { + display: inline-block; + min-width: auto; + vertical-align: top; +} + +.ui.list .list > .item > .image, +.ui.list > .item > .image { + display: table-cell; + background-color: transparent; + vertical-align: top; +} +.ui.list .list > .item > .image:not(:only-child):not(img), +.ui.list > .item > .image:not(:only-child):not(img) { + padding-right: 0.5em; +} +.ui.list .list > .item > .image img, +.ui.list > .item > .image img { + vertical-align: top; +} +.ui.list .list > .item > img.image, +.ui.list .list > .item > .image:only-child, +.ui.list > .item > img.image, +.ui.list > .item > .image:only-child { + display: inline-block; +} + +.ui.list .list > .item > .content, +.ui.list > .item > .content { + color: var(--color-text); +} +.ui.list .list > .item > .image + .content, +.ui.list .list > .item > i.icon + .content, +.ui.list > .item > .image + .content, +.ui.list > .item > i.icon + .content { + display: table-cell; + width: 100%; + padding: 0 0 0 0.5em; + vertical-align: top; +} +.ui.list .list > .item > img.image + .content, +.ui.list > .item > img.image + .content { + display: inline-block; + width: auto; +} +.ui.list .list > .item > .content > .list, +.ui.list > .item > .content > .list { + margin-left: 0; + padding-left: 0; +} + +.ui.list .list > .item .header, +.ui.list > .item .header { + display: block; + margin: 0; + font-family: var(--fonts-regular); + font-weight: var(--font-weight-medium); + color: var(--color-text-dark); +} + +.ui.list .list > .item .description, +.ui.list > .item .description { + display: block; + color: var(--color-text); +} + +.ui.list > .item a, +.ui.list .list > .item a { + cursor: pointer; +} + +.ui.menu .ui.list > .item, +.ui.menu .ui.list .list > .item { + display: list-item; + table-layout: fixed; + background-color: transparent; + list-style-type: none; + list-style-position: outside; + padding: 0.21428571em 0; +} +.ui.menu .ui.list .list > .item::before, +.ui.menu .ui.list > .item::before { + border: none; + background: none; +} +.ui.menu .ui.list .list > .item:first-child, +.ui.menu .ui.list > .item:first-child { + padding-top: 0; +} +.ui.menu .ui.list .list > .item:last-child, +.ui.menu .ui.list > .item:last-child { + padding-bottom: 0; +} + +.ui.list .list > .disabled.item, +.ui.list > .disabled.item { + pointer-events: none; + opacity: var(--opacity-disabled); +} + +.ui.list .list > a.item:hover > .icons, +.ui.list > a.item:hover > .icons, +.ui.list .list > a.item:hover > i.icon, +.ui.list > a.item:hover > i.icon { + color: var(--color-text-dark); +} + +.ui.divided.list > .item { + border-top: 1px solid var(--color-secondary); +} +.ui.divided.list .list > .item { + border-top: none; +} +.ui.divided.list .item .list > .item { + border-top: none; +} +.ui.divided.list .list > .item:first-child, +.ui.divided.list > .item:first-child { + border-top: none; +} +.ui.divided.list .list > .item:first-child { + border-top-width: 1px; +} + +.ui.relaxed.list > .item:not(:first-child) { + padding-top: 0.42857143em; +} +.ui.relaxed.list > .item:not(:last-child) { + padding-bottom: 0.42857143em; +} diff --git a/web_src/fomantic/build/semantic.css b/web_src/fomantic/build/semantic.css index 5cb6a371e5..49c00c4dad 100644 --- a/web_src/fomantic/build/semantic.css +++ b/web_src/fomantic/build/semantic.css @@ -6477,983 +6477,6 @@ select.ui.dropdown { /******************************* Site Overrides *******************************/ -/*! - * # Fomantic-UI - List - * http://github.com/fomantic/Fomantic-UI/ - * - * - * Released under the MIT license - * http://opensource.org/licenses/MIT - * - */ - -/******************************* - List -*******************************/ - -ul.ui.list, -ol.ui.list, -.ui.list { - list-style-type: none; - margin: 1em 0; - padding: 0 0; -} - -ul.ui.list:first-child, -ol.ui.list:first-child, -.ui.list:first-child { - margin-top: 0; - padding-top: 0; -} - -ul.ui.list:last-child, -ol.ui.list:last-child, -.ui.list:last-child { - margin-bottom: 0; - padding-bottom: 0; -} - -/******************************* - Content -*******************************/ - -/* List Item */ - -ul.ui.list li, -ol.ui.list li, -.ui.list > .item, -.ui.list .list > .item { - display: list-item; - table-layout: fixed; - list-style-type: none; - list-style-position: outside; - padding: 0.21428571em 0; - line-height: 1.14285714em; -} - -ul.ui.list > li:first-child:after, -ol.ui.list > li:first-child:after, -.ui.list > .list > .item:after, -.ui.list > .item:after { - content: ''; - display: block; - height: 0; - clear: both; - visibility: hidden; -} - -ul.ui.list li:first-child, -ol.ui.list li:first-child, -.ui.list .list > .item:first-child, -.ui.list > .item:first-child { - padding-top: 0; -} - -ul.ui.list li:last-child, -ol.ui.list li:last-child, -.ui.list .list > .item:last-child, -.ui.list > .item:last-child { - padding-bottom: 0; -} - -/* Child List */ - -ul.ui.list ul, -ol.ui.list ol, -.ui.list .list:not(.icon) { - clear: both; - margin: 0; - padding: 0.75em 0 0.25em 0.5em; -} - -/* Child Item */ - -ul.ui.list ul li, -ol.ui.list ol li, -.ui.list .list > .item { - padding: 0.14285714em 0; - line-height: inherit; -} - -/* Icon */ - -.ui.list .list > .item > i.icon, -.ui.list > .item > i.icon { - display: table-cell; - min-width: 1.55em; - margin: 0; - padding-top: 0; - transition: color 0.1s ease; -} - -.ui.list .list > .item > i.icon:not(.loading), -.ui.list > .item > i.icon:not(.loading) { - padding-right: 0.28571429em; - vertical-align: top; -} - -.ui.list .list > .item > i.icon:only-child, -.ui.list > .item > i.icon:only-child { - display: inline-block; - min-width: auto; - vertical-align: top; -} - -/* Image */ - -.ui.list .list > .item > .image, -.ui.list > .item > .image { - display: table-cell; - background-color: transparent; - margin: 0; - vertical-align: top; -} - -.ui.list .list > .item > .image:not(:only-child):not(img), -.ui.list > .item > .image:not(:only-child):not(img) { - padding-right: 0.5em; -} - -.ui.list .list > .item > .image img, -.ui.list > .item > .image img { - vertical-align: top; -} - -.ui.list .list > .item > img.image, -.ui.list .list > .item > .image:only-child, -.ui.list > .item > img.image, -.ui.list > .item > .image:only-child { - display: inline-block; -} - -/* Content */ - -.ui.list .list > .item > .content, -.ui.list > .item > .content { - line-height: 1.14285714em; - color: rgba(0, 0, 0, 0.87); -} - -.ui.list .list > .item > .image + .content, -.ui.list .list > .item > i.icon + .content, -.ui.list > .item > .image + .content, -.ui.list > .item > i.icon + .content { - display: table-cell; - width: 100%; - padding: 0 0 0 0.5em; - vertical-align: top; -} - -.ui.list .list > .item > i.loading.icon + .content, -.ui.list > .item > i.loading.icon + .content { - padding-left: calc(0.2857142857142857em + 0.5em); -} - -.ui.list .list > .item > img.image + .content, -.ui.list > .item > img.image + .content { - display: inline-block; - width: auto; -} - -.ui.list .list > .item > .content > .list, -.ui.list > .item > .content > .list { - margin-left: 0; - padding-left: 0; -} - -/* Header */ - -.ui.list .list > .item .header, -.ui.list > .item .header { - display: block; - margin: 0; - font-family: var(--fonts-regular); - font-weight: 500; - color: rgba(0, 0, 0, 0.87); -} - -/* Description */ - -.ui.list .list > .item .description, -.ui.list > .item .description { - display: block; - color: rgba(0, 0, 0, 0.7); -} - -/* Child Link */ - -.ui.list > .item a, -.ui.list .list > .item a { - cursor: pointer; -} - -/* Linking Item */ - -.ui.list .list > a.item, -.ui.list > a.item { - cursor: pointer; - color: #4183C4; -} - -.ui.list .list > a.item:hover, -.ui.list > a.item:hover { - color: #1e70bf; -} - -/* Linked Item Icons */ - -.ui.list .list > a.item > i.icons, -.ui.list > a.item > i.icons, -.ui.list .list > a.item > i.icon, -.ui.list > a.item > i.icon { - color: rgba(0, 0, 0, 0.4); -} - -/* Header Link */ - -.ui.list .list > .item a.header, -.ui.list > .item a.header { - cursor: pointer; - color: #4183C4 !important; -} - -.ui.list .list > .item > a.header:hover, -.ui.list > .item > a.header:hover { - color: #1e70bf !important; -} - -/* Floated Content */ - -.ui[class*="left floated"].list { - float: left; -} - -.ui[class*="right floated"].list { - float: right; -} - -.ui.list .list > .item [class*="left floated"], -.ui.list > .item [class*="left floated"] { - float: left; - margin: 0 1em 0 0; -} - -.ui.list .list > .item [class*="right floated"], -.ui.list > .item [class*="right floated"] { - float: right; - margin: 0 0 0 1em; -} - -/******************************* - Coupling -*******************************/ - -.ui.menu .ui.list > .item, -.ui.menu .ui.list .list > .item { - display: list-item; - table-layout: fixed; - background-color: transparent; - list-style-type: none; - list-style-position: outside; - padding: 0.21428571em 0; - line-height: 1.14285714em; -} - -.ui.menu .ui.list .list > .item:before, -.ui.menu .ui.list > .item:before { - border: none; - background: none; -} - -.ui.menu .ui.list .list > .item:first-child, -.ui.menu .ui.list > .item:first-child { - padding-top: 0; -} - -.ui.menu .ui.list .list > .item:last-child, -.ui.menu .ui.list > .item:last-child { - padding-bottom: 0; -} - -/******************************* - Types -*******************************/ - -/*------------------- - Horizontal - --------------------*/ - -.ui.horizontal.list { - display: inline-block; - font-size: 0; -} - -.ui.horizontal.list > .item { - display: inline-block; - margin-right: 1em; - font-size: 1rem; -} - -.ui.horizontal.list:not(.celled) > .item:last-child { - margin-right: 0; - padding-right: 0; -} - -.ui.horizontal.list .list:not(.icon) { - padding-left: 0; - padding-bottom: 0; -} - -.ui.horizontal.list > .item > .image, -.ui.horizontal.list .list > .item > .image, -.ui.horizontal.list > .item > i.icon, -.ui.horizontal.list .list > .item > i.icon, -.ui.horizontal.list > .item > .content, -.ui.horizontal.list .list > .item > .content { - vertical-align: middle; -} - -/* Padding on all elements */ - -.ui.horizontal.list > .item:first-child, -.ui.horizontal.list > .item:last-child { - padding-top: 0.21428571em; - padding-bottom: 0.21428571em; -} - -/* Horizontal List */ - -.ui.horizontal.list > .item > i.icon, -.ui.horizontal.list .item > i.icons > i.icon { - margin: 0; - padding: 0 0.25em 0 0; -} - -.ui.horizontal.list > .item > .image + .content, -.ui.horizontal.list > .item > i.icon, -.ui.horizontal.list > .item > i.icon + .content { - float: none; - display: inline-block; - width: auto; -} - -.ui.horizontal.list > .item > .image { - display: inline-block; -} - -/******************************* - States -*******************************/ - -/*------------------- - Disabled - --------------------*/ - -.ui.list .list > .disabled.item, -.ui.list > .disabled.item { - pointer-events: none; - color: rgba(40, 40, 40, 0.3) !important; -} - -/*------------------- - Hover ---------------------*/ - -.ui.list .list > a.item:hover > .icons, -.ui.list > a.item:hover > .icons, -.ui.list .list > a.item:hover > i.icon, -.ui.list > a.item:hover > i.icon { - color: rgba(0, 0, 0, 0.87); -} - -/******************************* - Variations -*******************************/ - -/*------------------- - Aligned - --------------------*/ - -.ui.list[class*="top aligned"] .image, -.ui.list[class*="top aligned"] .content, -.ui.list [class*="top aligned"] { - vertical-align: top !important; -} - -.ui.list[class*="middle aligned"] .image, -.ui.list[class*="middle aligned"] .content, -.ui.list [class*="middle aligned"] { - vertical-align: middle !important; -} - -.ui.list[class*="bottom aligned"] .image, -.ui.list[class*="bottom aligned"] .content, -.ui.list [class*="bottom aligned"] { - vertical-align: bottom !important; -} - -/*------------------- - Link - --------------------*/ - -.ui.link.list .item, -.ui.link.list a.item, -.ui.link.list .item a:not(.ui) { - color: rgba(0, 0, 0, 0.4); - transition: 0.1s color ease; -} - -.ui.link.list.list a.item:hover, -.ui.link.list.list .item a:not(.ui):hover { - color: rgba(0, 0, 0, 0.8); -} - -.ui.link.list.list a.item:active, -.ui.link.list.list .item a:not(.ui):active { - color: rgba(0, 0, 0, 0.9); -} - -.ui.link.list.list .active.item, -.ui.link.list.list .active.item a:not(.ui) { - color: rgba(0, 0, 0, 0.95); -} - -/*------------------- - Selection - --------------------*/ - -.ui.selection.list .list > .item, -.ui.selection.list > .item { - cursor: pointer; - background: transparent; - padding: 0.5em 0.5em; - margin: 0; - color: rgba(0, 0, 0, 0.4); - border-radius: 0.5em; - transition: 0.1s color ease, 0.1s padding-left ease, 0.1s background-color ease; -} - -.ui.selection.list .list > .item:last-child, -.ui.selection.list > .item:last-child { - margin-bottom: 0; -} - -.ui.selection.list .list > .item:hover, -.ui.selection.list > .item:hover { - background: rgba(0, 0, 0, 0.03); - color: rgba(0, 0, 0, 0.8); -} - -.ui.selection.list .list > .item:active, -.ui.selection.list > .item:active { - background: rgba(0, 0, 0, 0.05); - color: rgba(0, 0, 0, 0.9); -} - -.ui.selection.list .list > .item.active, -.ui.selection.list > .item.active { - background: rgba(0, 0, 0, 0.05); - color: rgba(0, 0, 0, 0.95); -} - -/* Celled / Divided Selection List */ - -.ui.celled.selection.list .list > .item, -.ui.divided.selection.list .list > .item, -.ui.celled.selection.list > .item, -.ui.divided.selection.list > .item { - border-radius: 0; -} - -/*------------------- - Animated - --------------------*/ - -.ui.animated.list > .item { - transition: 0.25s color ease 0.1s, 0.25s padding-left ease 0.1s, 0.25s background-color ease 0.1s; -} - -.ui.animated.list:not(.horizontal) > .item:hover { - padding-left: 1em; -} - -/*------------------- - Fitted - --------------------*/ - -.ui.fitted.list:not(.selection) .list > .item, -.ui.fitted.list:not(.selection) > .item { - padding-left: 0; - padding-right: 0; -} - -.ui.fitted.selection.list .list > .item, -.ui.fitted.selection.list > .item { - margin-left: -0.5em; - margin-right: -0.5em; -} - -/*------------------- - Bulleted - --------------------*/ - -ul.ui.list, -.ui.bulleted.list { - margin-left: 1.25rem; -} - -ul.ui.list li, -.ui.bulleted.list .list > .item, -.ui.bulleted.list > .item { - position: relative; -} - -ul.ui.list li:before, -.ui.bulleted.list .list > .item:before, -.ui.bulleted.list > .item:before { - -webkit-user-select: none; - -moz-user-select: none; - user-select: none; - pointer-events: none; - position: absolute; - top: auto; - left: auto; - font-weight: normal; - margin-left: -1.25rem; - content: '\2022'; - opacity: 1; - color: inherit; - vertical-align: top; -} - -ul.ui.list li:before, -.ui.bulleted.list .list > a.item:before, -.ui.bulleted.list > a.item:before { - color: rgba(0, 0, 0, 0.87); -} - -ul.ui.list ul, -.ui.bulleted.list .list:not(.icon) { - padding-left: 1.25rem; -} - -/* Horizontal Bulleted */ - -ul.ui.horizontal.bulleted.list, -.ui.horizontal.bulleted.list { - margin-left: 0; -} - -ul.ui.horizontal.bulleted.list li, -.ui.horizontal.bulleted.list > .item { - margin-left: 1.75rem; -} - -ul.ui.horizontal.bulleted.list li:first-child, -.ui.horizontal.bulleted.list > .item:first-child { - margin-left: 0; -} - -ul.ui.horizontal.bulleted.list li::before, -.ui.horizontal.bulleted.list > .item::before { - color: rgba(0, 0, 0, 0.87); -} - -ul.ui.horizontal.bulleted.list li:first-child::before, -.ui.horizontal.bulleted.list > .item:first-child::before { - display: none; -} - -/*------------------- - Ordered - --------------------*/ - -ol.ui.list, -.ui.ordered.list, -.ui.ordered.list .list:not(.icon), -ol.ui.list ol { - counter-reset: ordered; - margin-left: 1.25rem; - list-style-type: none; -} - -ol.ui.list li, -.ui.ordered.list .list > .item, -.ui.ordered.list > .item { - list-style-type: none; - position: relative; -} - -ol.ui.list li:before, -.ui.ordered.list .list > .item:before, -.ui.ordered.list > .item:before { - position: absolute; - top: auto; - left: auto; - -webkit-user-select: none; - -moz-user-select: none; - user-select: none; - pointer-events: none; - margin-left: -1.25rem; - counter-increment: ordered; - content: counters(ordered, ".") " "; - text-align: right; - color: rgba(0, 0, 0, 0.87); - vertical-align: middle; - opacity: 0.8; -} - -/* Value */ - -.ui.ordered.list .list > .item[data-value]:before, -.ui.ordered.list > .item[data-value]:before { - content: attr(data-value); -} - -ol.ui.list li[value]:before { - content: attr(value); -} - -/* Child Lists */ - -ol.ui.list ol, -.ui.ordered.list .list:not(.icon) { - margin-left: 1em; -} - -ol.ui.list ol li:before, -.ui.ordered.list .list > .item:before { - margin-left: -2em; -} - -/* Horizontal Ordered */ - -ol.ui.horizontal.list, -.ui.ordered.horizontal.list { - margin-left: 0; -} - -ol.ui.horizontal.list li:before, -.ui.ordered.horizontal.list .list > .item:before, -.ui.ordered.horizontal.list > .item:before { - position: static; - margin: 0 0.5em 0 0; -} - -/* Suffixed Ordered */ - -ol.ui.suffixed.list li:before, -.ui.suffixed.ordered.list .list > .item:before, -.ui.suffixed.ordered.list > .item:before { - content: counters(ordered, ".") "."; -} - -/*------------------- - Divided - --------------------*/ - -.ui.divided.list > .item { - border-top: 1px solid rgba(34, 36, 38, 0.15); -} - -.ui.divided.list .list > .item { - border-top: none; -} - -.ui.divided.list .item .list > .item { - border-top: none; -} - -.ui.divided.list .list > .item:first-child, -.ui.divided.list > .item:first-child { - border-top: none; -} - -/* Sub Menu */ - -.ui.divided.list:not(.horizontal) .list > .item:first-child { - border-top-width: 1px; -} - -/* Divided bulleted */ - -.ui.divided.bulleted.list:not(.horizontal), -.ui.divided.bulleted.list .list:not(.icon) { - margin-left: 0; - padding-left: 0; -} - -.ui.divided.bulleted.list > .item:not(.horizontal) { - padding-left: 1.25rem; -} - -/* Divided Ordered */ - -.ui.divided.ordered.list { - margin-left: 0; -} - -.ui.divided.ordered.list .list > .item, -.ui.divided.ordered.list > .item { - padding-left: 1.25rem; -} - -.ui.divided.ordered.list .item .list:not(.icon) { - margin-left: 0; - margin-right: 0; - padding-bottom: 0.21428571em; -} - -.ui.divided.ordered.list .item .list > .item { - padding-left: 1em; -} - -/* Divided Selection */ - -.ui.divided.selection.list .list > .item, -.ui.divided.selection.list > .item { - margin: 0; - border-radius: 0; -} - -/* Divided horizontal */ - -.ui.divided.horizontal.list { - margin-left: 0; -} - -.ui.divided.horizontal.list > .item { - padding-left: 0.5em; -} - -.ui.divided.horizontal.list > .item:not(:last-child) { - padding-right: 0.5em; -} - -.ui.divided.horizontal.list > .item { - border-top: none; - border-right: 1px solid rgba(34, 36, 38, 0.15); - margin: 0; - line-height: 0.6; -} - -.ui.horizontal.divided.list > .item:last-child { - border-right: none; -} - -/*------------------- - Celled - --------------------*/ - -.ui.celled.list > .item, -.ui.celled.list > .list { - border-top: 1px solid rgba(34, 36, 38, 0.15); - padding-left: 0.5em; - padding-right: 0.5em; -} - -.ui.celled.list > .item:last-child { - border-bottom: 1px solid rgba(34, 36, 38, 0.15); -} - -/* Padding on all elements */ - -.ui.celled.list > .item:first-child, -.ui.celled.list > .item:last-child { - padding-top: 0.21428571em; - padding-bottom: 0.21428571em; -} - -/* Sub Menu */ - -.ui.celled.list .item .list > .item { - border-width: 0; -} - -.ui.celled.list .list > .item:first-child { - border-top-width: 0; -} - -/* Celled Bulleted */ - -.ui.celled.bulleted.list { - margin-left: 0; -} - -.ui.celled.bulleted.list .list > .item, -.ui.celled.bulleted.list > .item { - padding-left: 1.25rem; -} - -.ui.celled.bulleted.list .item .list:not(.icon) { - margin-left: -1.25rem; - margin-right: -1.25rem; - padding-bottom: 0.21428571em; -} - -/* Celled Ordered */ - -.ui.celled.ordered.list { - margin-left: 0; -} - -.ui.celled.ordered.list .list > .item, -.ui.celled.ordered.list > .item { - padding-left: 1.25rem; -} - -.ui.celled.ordered.list .item .list:not(.icon) { - margin-left: 0; - margin-right: 0; - padding-bottom: 0.21428571em; -} - -.ui.celled.ordered.list .list > .item { - padding-left: 1em; -} - -/* Celled Horizontal */ - -.ui.horizontal.celled.list { - margin-left: 0; -} - -.ui.horizontal.celled.list .list > .item, -.ui.horizontal.celled.list > .item { - border-top: none; - border-left: 1px solid rgba(34, 36, 38, 0.15); - margin: 0; - padding-left: 0.5em; - padding-right: 0.5em; - line-height: 0.6; -} - -.ui.horizontal.celled.list .list > .item:last-child, -.ui.horizontal.celled.list > .item:last-child { - border-bottom: none; - border-right: 1px solid rgba(34, 36, 38, 0.15); -} - -/*------------------- - Relaxed - --------------------*/ - -.ui.relaxed.list:not(.horizontal) > .item:not(:first-child) { - padding-top: 0.42857143em; -} - -.ui.relaxed.list:not(.horizontal) > .item:not(:last-child) { - padding-bottom: 0.42857143em; -} - -.ui.horizontal.relaxed.list .list > .item:not(:first-child), -.ui.horizontal.relaxed.list > .item:not(:first-child) { - padding-left: 1rem; -} - -.ui.horizontal.relaxed.list .list > .item:not(:last-child), -.ui.horizontal.relaxed.list > .item:not(:last-child) { - padding-right: 1rem; -} - -/* Very Relaxed */ - -.ui[class*="very relaxed"].list:not(.horizontal) > .item:not(:first-child) { - padding-top: 0.85714286em; -} - -.ui[class*="very relaxed"].list:not(.horizontal) > .item:not(:last-child) { - padding-bottom: 0.85714286em; -} - -.ui.horizontal[class*="very relaxed"].list .list > .item:not(:first-child), -.ui.horizontal[class*="very relaxed"].list > .item:not(:first-child) { - padding-left: 1.5rem; -} - -.ui.horizontal[class*="very relaxed"].list .list > .item:not(:last-child), -.ui.horizontal[class*="very relaxed"].list > .item:not(:last-child) { - padding-right: 1.5rem; -} - -/*------------------- - Sizes ---------------------*/ - -.ui.list { - font-size: 1em; -} - -.ui.mini.list { - font-size: 0.78571429em; -} - -.ui.mini.horizontal.list .list > .item, -.ui.mini.horizontal.list > .item { - font-size: 0.78571429rem; -} - -.ui.tiny.list { - font-size: 0.85714286em; -} - -.ui.tiny.horizontal.list .list > .item, -.ui.tiny.horizontal.list > .item { - font-size: 0.85714286rem; -} - -.ui.small.list { - font-size: 0.92857143em; -} - -.ui.small.horizontal.list .list > .item, -.ui.small.horizontal.list > .item { - font-size: 0.92857143rem; -} - -.ui.large.list { - font-size: 1.14285714em; -} - -.ui.large.horizontal.list .list > .item, -.ui.large.horizontal.list > .item { - font-size: 1.14285714rem; -} - -.ui.big.list { - font-size: 1.28571429em; -} - -.ui.big.horizontal.list .list > .item, -.ui.big.horizontal.list > .item { - font-size: 1.28571429rem; -} - -.ui.huge.list { - font-size: 1.42857143em; -} - -.ui.huge.horizontal.list .list > .item, -.ui.huge.horizontal.list > .item { - font-size: 1.42857143rem; -} - -.ui.massive.list { - font-size: 1.71428571em; -} - -.ui.massive.horizontal.list .list > .item, -.ui.massive.horizontal.list > .item { - font-size: 1.71428571rem; -} - -/******************************* - Theme Overrides -*******************************/ - -/******************************* - User Variable Overrides -*******************************/ /* * # Fomantic - Menu * http://github.com/fomantic/Fomantic-UI/ diff --git a/web_src/fomantic/semantic.json b/web_src/fomantic/semantic.json index 7ec520f315..5db57bc8d4 100644 --- a/web_src/fomantic/semantic.json +++ b/web_src/fomantic/semantic.json @@ -26,7 +26,6 @@ "dimmer", "dropdown", "form", - "list", "menu", "modal", "search", From 48223909be0511bcd773bceea76918bfd7cc7d46 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Sun, 7 Apr 2024 00:27:31 +0000 Subject: [PATCH 051/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_ja-JP.ini | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 7e725b4647..57b2aff254 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -652,7 +652,7 @@ block.unblock.failure=ユーザーのブロック解除に失敗しました: %s block.blocked=あなたはこのユーザーをブロックしています。 block.title=ユーザーをブロックする block.info=ユーザーをブロックすると、そのユーザーは、プルリクエストやイシューの作成、コメントの投稿など、リポジトリに対する操作ができなくなります。 ユーザーのブロックについてはよく確認してください。 -block.info_1=ユーザーをブロックすることで、あなたのアカウントとリポジトリに対する以下の行為を防ぎます: +block.info_1=ユーザーをブロックすることで、あなたのアカウントとあなたのリポジトリに対する以下の行為を阻止します: block.info_2=あなたのアカウントのフォロー block.info_3=あなたのユーザー名で@メンションして通知を送ること block.info_4=そのユーザーのリポジトリに、あなたを共同作業者として招待すること @@ -709,8 +709,8 @@ language=言語 ui=テーマ hidden_comment_types=非表示にするコメントの種類 hidden_comment_types_description=ここでチェックを入れたコメントの種類は、イシューのページには表示されません。 たとえば「ラベル」にチェックを入れると、「<ユーザー> が <ラベル> を追加/削除」といったコメントはすべて除去されます。 -hidden_comment_types.ref_tooltip=このイシューが別のイシューやコミット等から参照されたというコメント -hidden_comment_types.issue_ref_tooltip=このイシューに関連付けるブランチやタグをユーザーが変更したというコメント +hidden_comment_types.ref_tooltip=このイシューが別のイシューやコミット等から参照された、というコメント +hidden_comment_types.issue_ref_tooltip=このイシューのブランチやタグへの関連付けをユーザーが変更した、というコメント comment_type_group_reference=参照 comment_type_group_label=ラベル comment_type_group_milestone=マイルストーン @@ -780,7 +780,7 @@ add_email_success=新しいメールアドレスを追加しました。 email_preference_set_success=メール設定を保存しました。 add_openid_success=新しいOpenIDアドレスを追加しました。 keep_email_private=メールアドレスを隠す -keep_email_private_popup=これによりプロフィールでメールアドレスが隠され、Webインターフェースでのプルリクエスト作成やファイル編集でもメールアドレスが隠されます。 プッシュ済みのコミットは変更されません。 +keep_email_private_popup=あなたのプロフィールからメールアドレスが隠され、Webインターフェースを使ったプルリクエスト作成やファイル編集でも、メールアドレスが隠されます。 プッシュ済みのコミットは変更されません。 コミットであなたのアカウントに関連付ける場合は %s を使用してください。 openid_desc=OpenIDを使うと外部プロバイダーに認証を委任することができます。 manage_ssh_keys=SSHキーの管理 @@ -2961,12 +2961,12 @@ packages.size=サイズ packages.published=配布 defaulthooks=デフォルトWebhook -defaulthooks.desc=Webhookは、特定のGiteaイベントのトリガーが発生した際に、自動的にHTTP POSTリクエストをサーバーへ送信するものです。 ここで定義されたWebhookはデフォルトとなり、全ての新規リポジトリにコピーされます。 詳しくは<a target="_blank" rel="noopener" href="https://docs.gitea.com/usage/webhooks">Webhooksガイド</a>をご覧下さい。 +defaulthooks.desc=Webhookは、特定のGiteaイベントが発生したときに、サーバーにHTTP POSTリクエストを自動的に送信するものです。 ここで定義したWebhookはデフォルトとなり、全ての新規リポジトリにコピーされます。 詳しくは<a target="_blank" rel="noopener" href="https://docs.gitea.com/usage/webhooks">Webhooksガイド</a>をご覧下さい。 defaulthooks.add_webhook=デフォルトWebhookの追加 defaulthooks.update_webhook=デフォルトWebhookの更新 systemhooks=システムWebhook -systemhooks.desc=Webhookは、特定のGiteaイベントのトリガーが発生した際に、自動的にHTTP POSTリクエストをサーバーへ送信するものです。 ここで定義したWebhookはシステム内のすべてのリポジトリで呼び出されます。 そのため、パフォーマンスに及ぼす影響を考慮したうえで設定してください。 詳しくは<a target="_blank" rel="noopener" href="https://docs.gitea.com/usage/webhooks">Webhooksガイド</a>をご覧下さい。 +systemhooks.desc=Webhookは、特定のGiteaイベントが発生したときに、サーバーにHTTP POSTリクエストを自動的に送信するものです。 ここで定義したWebhookは、システム内のすべてのリポジトリで呼び出されます。 そのため、パフォーマンスに及ぼす影響を考慮したうえで設定してください。 詳しくは<a target="_blank" rel="noopener" href="https://docs.gitea.com/usage/webhooks">Webhooksガイド</a>をご覧下さい。 systemhooks.add_webhook=システムWebhookを追加 systemhooks.update_webhook=システムWebhookを更新 @@ -3342,9 +3342,9 @@ raw_seconds=秒 raw_minutes=分 [dropzone] -default_message=ここにファイルをドロップまたはクリックしてアップロードします。 +default_message=ファイルをここにドロップ、またはここをクリックしてアップロード invalid_input_type=この種類のファイルはアップロードできません。 -file_too_big=アップロードされたファイルのサイズ ({{filesize}} MB) が最大サイズ ({{maxFilesize}} MB) を超えています。 +file_too_big=アップロードされたファイルのサイズ ({{filesize}} MB) は、最大サイズ ({{maxFilesize}} MB) を超えています。 remove_file=ファイル削除 [notification] @@ -3369,7 +3369,7 @@ error.no_committer_account=コミッターのメールアドレスに対応す error.no_gpg_keys_found=この署名に対応する既知のキーがデータベースに存在しません error.not_signed_commit=署名されたコミットではありません error.failed_retrieval_gpg_keys=コミッターのアカウントに登録されたキーを取得できませんでした -error.probable_bad_signature=警告! このIDの鍵はデータベースに登録されていますが、その鍵でコミットの検証が通りません! これは疑わしいコミットです。 +error.probable_bad_signature=警告! このIDに該当する鍵がデータベースにありますが、コミットの検証が通りません! これは疑わしいコミットです。 error.probable_bad_default_signature=警告! これはデフォルト鍵のIDですが、デフォルト鍵ではコミットの検証が通りません! これは疑わしいコミットです。 [units] @@ -3382,7 +3382,7 @@ title=パッケージ desc=リポジトリ パッケージを管理します。 empty=パッケージはまだありません。 empty.documentation=パッケージレジストリの詳細については、 <a target="_blank" rel="noopener noreferrer" href="%s">ドキュメント</a> を参照してください。 -empty.repo=パッケージはアップロードしたけども、ここに表示されない? <a href="%[1]s">パッケージ設定</a>を開いて、パッケージをこのリポジトリにリンクしてください。 +empty.repo=パッケージはアップロード済みで、ここに表示されていないですか? <a href="%[1]s">パッケージ設定</a>を開いて、パッケージをこのリポジトリにリンクしてください。 registry.documentation=%sレジストリの詳細については、 <a target="_blank" rel="noopener noreferrer" href="%s">ドキュメント</a> を参照してください。 filter.type=タイプ filter.type.all=すべて From bbe5cd7c92ccc3793473ae0163398cdbccdd4246 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sun, 7 Apr 2024 09:11:25 +0800 Subject: [PATCH 052/370] Refactor startup deprecation messages (#30305) It doesn't change logic, it only does: 1. Rename the variable and function names 2. Use more consistent format when mentioning config section&key 3. Improve some messages --- modules/setting/config_provider.go | 16 ++++++++++------ modules/setting/indexer.go | 2 +- modules/setting/oauth2.go | 2 +- modules/setting/repository.go | 2 +- modules/setting/server.go | 2 +- modules/setting/session.go | 2 +- modules/setting/setting.go | 4 +--- modules/setting/storage.go | 2 +- routers/web/admin/admin.go | 18 +++++++++--------- routers/web/admin/config.go | 2 +- templates/admin/self_check.tmpl | 6 +++--- 11 files changed, 30 insertions(+), 28 deletions(-) diff --git a/modules/setting/config_provider.go b/modules/setting/config_provider.go index 3fa3f3b50b..03f27ba203 100644 --- a/modules/setting/config_provider.go +++ b/modules/setting/config_provider.go @@ -315,21 +315,25 @@ func mustMapSetting(rootCfg ConfigProvider, sectionName string, setting any) { } } -// DeprecatedWarnings contains the warning message for various deprecations, including: setting option, file/folder, etc -var DeprecatedWarnings []string +// StartupProblems contains the messages for various startup problems, including: setting option, file/folder, etc +var StartupProblems []string + +func logStartupProblem(skip int, level log.Level, format string, args ...any) { + msg := fmt.Sprintf(format, args...) + log.Log(skip+1, level, "%s", msg) + StartupProblems = append(StartupProblems, msg) +} func deprecatedSetting(rootCfg ConfigProvider, oldSection, oldKey, newSection, newKey, version string) { if rootCfg.Section(oldSection).HasKey(oldKey) { - msg := fmt.Sprintf("Deprecated config option `[%s]` `%s` present. Use `[%s]` `%s` instead. This fallback will be/has been removed in %s", oldSection, oldKey, newSection, newKey, version) - log.Error("%v", msg) - DeprecatedWarnings = append(DeprecatedWarnings, msg) + logStartupProblem(1, log.ERROR, "Deprecation: config option `[%s].%s` presents, please use `[%s].%s` instead because this fallback will be/has been removed in %s", oldSection, oldKey, newSection, newKey, version) } } // deprecatedSettingDB add a hint that the configuration has been moved to database but still kept in app.ini func deprecatedSettingDB(rootCfg ConfigProvider, oldSection, oldKey string) { if rootCfg.Section(oldSection).HasKey(oldKey) { - log.Error("Deprecated `[%s]` `%s` present which has been copied to database table sys_setting", oldSection, oldKey) + logStartupProblem(1, log.ERROR, "Deprecation: config option `[%s].%s` presents but it won't take effect because it has been moved to admin panel -> config setting", oldSection, oldKey) } } diff --git a/modules/setting/indexer.go b/modules/setting/indexer.go index cec364d370..6877d70e3c 100644 --- a/modules/setting/indexer.go +++ b/modules/setting/indexer.go @@ -58,7 +58,7 @@ func loadIndexerFrom(rootCfg ConfigProvider) { if !filepath.IsAbs(Indexer.IssuePath) { Indexer.IssuePath = filepath.ToSlash(filepath.Join(AppWorkPath, Indexer.IssuePath)) } - checkOverlappedPath("indexer.ISSUE_INDEXER_PATH", Indexer.IssuePath) + checkOverlappedPath("[indexer].ISSUE_INDEXER_PATH", Indexer.IssuePath) } else { Indexer.IssueConnStr = sec.Key("ISSUE_INDEXER_CONN_STR").MustString(Indexer.IssueConnStr) if Indexer.IssueType == "meilisearch" { diff --git a/modules/setting/oauth2.go b/modules/setting/oauth2.go index 4d3bfd3eb6..1429a7585c 100644 --- a/modules/setting/oauth2.go +++ b/modules/setting/oauth2.go @@ -168,7 +168,7 @@ func GetGeneralTokenSigningSecret() []byte { } if generalSigningSecret.CompareAndSwap(old, &jwtSecret) { // FIXME: in main branch, the signing token should be refactored (eg: one unique for LFS/OAuth2/etc ...) - log.Warn("OAuth2 is not enabled, unable to use a persistent signing secret, a new one is generated, which is not persistent between restarts and cluster nodes") + logStartupProblem(1, log.WARN, "OAuth2 is not enabled, unable to use a persistent signing secret, a new one is generated, which is not persistent between restarts and cluster nodes") return jwtSecret } return *generalSigningSecret.Load() diff --git a/modules/setting/repository.go b/modules/setting/repository.go index a332d6adb3..8656ebc7ec 100644 --- a/modules/setting/repository.go +++ b/modules/setting/repository.go @@ -286,7 +286,7 @@ func loadRepositoryFrom(rootCfg ConfigProvider) { RepoRootPath = filepath.Clean(RepoRootPath) } - checkOverlappedPath("repository.ROOT", RepoRootPath) + checkOverlappedPath("[repository].ROOT", RepoRootPath) defaultDetectedCharsetsOrder := make([]string, 0, len(Repository.DetectedCharsetsOrder)) for _, charset := range Repository.DetectedCharsetsOrder { diff --git a/modules/setting/server.go b/modules/setting/server.go index 315faaeb21..7d6ece2727 100644 --- a/modules/setting/server.go +++ b/modules/setting/server.go @@ -331,7 +331,7 @@ func loadServerFrom(rootCfg ConfigProvider) { if !filepath.IsAbs(PprofDataPath) { PprofDataPath = filepath.Join(AppWorkPath, PprofDataPath) } - checkOverlappedPath("server.PPROF_DATA_PATH", PprofDataPath) + checkOverlappedPath("[server].PPROF_DATA_PATH", PprofDataPath) landingPage := sec.Key("LANDING_PAGE").MustString("home") switch landingPage { diff --git a/modules/setting/session.go b/modules/setting/session.go index 3cb1bfe7b5..afe63bfdb7 100644 --- a/modules/setting/session.go +++ b/modules/setting/session.go @@ -46,7 +46,7 @@ func loadSessionFrom(rootCfg ConfigProvider) { SessionConfig.ProviderConfig = strings.Trim(sec.Key("PROVIDER_CONFIG").MustString(filepath.Join(AppDataPath, "sessions")), "\" ") if SessionConfig.Provider == "file" && !filepath.IsAbs(SessionConfig.ProviderConfig) { SessionConfig.ProviderConfig = filepath.Join(AppWorkPath, SessionConfig.ProviderConfig) - checkOverlappedPath("session.PROVIDER_CONFIG", SessionConfig.ProviderConfig) + checkOverlappedPath("[session].PROVIDER_CONFIG", SessionConfig.ProviderConfig) } SessionConfig.CookieName = sec.Key("COOKIE_NAME").MustString("i_like_gitea") SessionConfig.CookiePath = AppSubURL diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 6aca9ec6cf..92bb0b6541 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -235,9 +235,7 @@ var configuredPaths = make(map[string]string) func checkOverlappedPath(name, path string) { // TODO: some paths shouldn't overlap (storage.xxx.path), while some could (data path is the base path for storage path) if targetName, ok := configuredPaths[path]; ok && targetName != name { - msg := fmt.Sprintf("Configured path %q is used by %q and %q at the same time. The paths must be unique to prevent data loss.", path, targetName, name) - log.Error("%s", msg) - DeprecatedWarnings = append(DeprecatedWarnings, msg) + logStartupProblem(1, log.ERROR, "Configured path %q is used by %q and %q at the same time. The paths must be unique to prevent data loss.", path, targetName, name) } configuredPaths[path] = name } diff --git a/modules/setting/storage.go b/modules/setting/storage.go index f4e33a53af..aeb61ac513 100644 --- a/modules/setting/storage.go +++ b/modules/setting/storage.go @@ -240,7 +240,7 @@ func getStorageForLocal(targetSec, overrideSec ConfigSection, tp targetSecType, } } - checkOverlappedPath("storage."+name+".PATH", storage.Path) + checkOverlappedPath("[storage."+name+"].PATH", storage.Path) return &storage, nil } diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go index 4dc0dfdef8..e6585d8833 100644 --- a/routers/web/admin/admin.go +++ b/routers/web/admin/admin.go @@ -117,11 +117,11 @@ func updateSystemStatus() { sysStatus.NumGC = m.NumGC } -func prepareDeprecatedWarningsAlert(ctx *context.Context) { - if len(setting.DeprecatedWarnings) > 0 { - content := setting.DeprecatedWarnings[0] - if len(setting.DeprecatedWarnings) > 1 { - content += fmt.Sprintf(" (and %d more)", len(setting.DeprecatedWarnings)-1) +func prepareStartupProblemsAlert(ctx *context.Context) { + if len(setting.StartupProblems) > 0 { + content := setting.StartupProblems[0] + if len(setting.StartupProblems) > 1 { + content += fmt.Sprintf(" (and %d more)", len(setting.StartupProblems)-1) } ctx.Flash.Error(content, true) } @@ -136,7 +136,7 @@ func Dashboard(ctx *context.Context) { updateSystemStatus() ctx.Data["SysStatus"] = sysStatus ctx.Data["SSH"] = setting.SSH - prepareDeprecatedWarningsAlert(ctx) + prepareStartupProblemsAlert(ctx) ctx.HTML(http.StatusOK, tplDashboard) } @@ -191,10 +191,10 @@ func DashboardPost(ctx *context.Context) { func SelfCheck(ctx *context.Context) { ctx.Data["PageIsAdminSelfCheck"] = true - ctx.Data["DeprecatedWarnings"] = setting.DeprecatedWarnings - if len(setting.DeprecatedWarnings) == 0 && !setting.IsProd { + ctx.Data["StartupProblems"] = setting.StartupProblems + if len(setting.StartupProblems) == 0 && !setting.IsProd { if time.Now().Unix()%2 == 0 { - ctx.Data["DeprecatedWarnings"] = []string{"This is a test warning message in dev mode"} + ctx.Data["StartupProblems"] = []string{"This is a test warning message in dev mode"} } } diff --git a/routers/web/admin/config.go b/routers/web/admin/config.go index 2f5f17e201..48f80dbbf1 100644 --- a/routers/web/admin/config.go +++ b/routers/web/admin/config.go @@ -165,7 +165,7 @@ func Config(ctx *context.Context) { ctx.Data["Loggers"] = log.GetManager().DumpLoggers() config.GetDynGetter().InvalidateCache() - prepareDeprecatedWarningsAlert(ctx) + prepareStartupProblemsAlert(ctx) ctx.HTML(http.StatusOK, tplConfig) } diff --git a/templates/admin/self_check.tmpl b/templates/admin/self_check.tmpl index c100ffd504..a6c2ac1ac9 100644 --- a/templates/admin/self_check.tmpl +++ b/templates/admin/self_check.tmpl @@ -5,11 +5,11 @@ {{ctx.Locale.Tr "admin.self_check"}} </h4> - {{if .DeprecatedWarnings}} + {{if .StartupProblems}} <div class="ui attached segment"> <div class="ui warning message"> <div>{{ctx.Locale.Tr "admin.self_check.startup_warnings"}}</div> - <ul class="tw-w-full">{{range .DeprecatedWarnings}}<li>{{.}}</li>{{end}}</ul> + <ul class="tw-w-full">{{range .StartupProblems}}<li>{{.}}</li>{{end}}</ul> </div> </div> {{end}} @@ -40,7 +40,7 @@ </div> {{end}} - {{if and (not .DeprecatedWarnings) (not .DatabaseCheckHasProblems)}} + {{if and (not .StartupProblems) (not .DatabaseCheckHasProblems)}} <div class="ui attached segment"> {{ctx.Locale.Tr "admin.self_check.no_problem_found"}} </div> From 94aad35a120b05897a0b6b97f0d9605a52ea9642 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 7 Apr 2024 10:53:28 +0200 Subject: [PATCH 053/370] Fix right-aligned input icons (#30301) Fix regression from https://github.com/go-gitea/gitea/pull/30194 where right-aligned items would not display correctly. Before and After: <img width="285" alt="Screenshot 2024-04-06 at 01 12 11" src="https://github.com/go-gitea/gitea/assets/115237/f9168db5-0f69-4b5d-ba17-b60145ac4a09"> <img width="285" alt="Screenshot 2024-04-06 at 01 11 49" src="https://github.com/go-gitea/gitea/assets/115237/639ab6ed-d018-4e3a-9980-1f079e4ebe9d"> Frontpage search tweaked to accommodate (which was the reason for the changes that broken above): <img width="445" alt="Screenshot 2024-04-06 at 01 11 34" src="https://github.com/go-gitea/gitea/assets/115237/1919220b-390e-463a-8e3d-33a3556bf111"> <img width="438" alt="Screenshot 2024-04-06 at 01 11 39" src="https://github.com/go-gitea/gitea/assets/115237/fd94f8e4-1d56-4b04-99e3-1cd240bd7ab4"> --- web_src/css/modules/input.css | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/web_src/css/modules/input.css b/web_src/css/modules/input.css index 48cd2fa9ff..18b785ac82 100644 --- a/web_src/css/modules/input.css +++ b/web_src/css/modules/input.css @@ -48,8 +48,11 @@ cursor: default; position: absolute; text-align: center; - top: 50%; - transform: translateY(-50%); + top: 0; + right: 0; + margin: 0; + height: 100%; + width: 2.67142857em; opacity: 0.5; border-radius: 0 0.28571429rem 0.28571429rem 0; pointer-events: none; @@ -58,6 +61,8 @@ .ui.icon.input > i.icon.is-loading { position: absolute !important; + height: 28px; + top: 4px; } .ui.icon.input > i.icon.is-loading > * { @@ -78,7 +83,7 @@ .ui[class*="left icon"].input > i.icon { right: auto; - left: 8px; + left: 1px; border-radius: 0.28571429rem 0 0 0.28571429rem; } .ui[class*="left icon"].input > i.circular.icon { From 83f83019ef3471b847a300f0821499b3896ec987 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sun, 7 Apr 2024 19:17:06 +0800 Subject: [PATCH 054/370] Clean up log messages (#30313) `log.Xxx("%v")` is not ideal, this PR adds necessary context messages. Remove some unnecessary logs. Co-authored-by: Giteabot <teabot@gitea.io> --- cmd/web.go | 2 +- models/asymkey/ssh_key_fingerprint.go | 17 ++++------------- models/repo/issue.go | 2 +- modules/util/util.go | 2 +- routers/api/v1/notify/repo.go | 2 -- routers/private/actions.go | 16 ++++++++-------- routers/private/hook_verification.go | 3 +-- routers/private/mail.go | 2 +- routers/web/admin/users.go | 1 - routers/web/auth/password.go | 2 -- routers/web/user/setting/account.go | 1 - services/context/captcha.go | 4 ++-- services/notify/notify.go | 4 ++-- services/repository/files/cherry_pick.go | 2 +- services/repository/files/patch.go | 2 +- services/repository/files/update.go | 2 +- services/wiki/wiki.go | 14 +++++++------- 17 files changed, 31 insertions(+), 47 deletions(-) diff --git a/cmd/web.go b/cmd/web.go index 01386251be..ef8a7426c1 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -114,7 +114,7 @@ func showWebStartupMessage(msg string) { log.Info("* WorkPath: %s", setting.AppWorkPath) log.Info("* CustomPath: %s", setting.CustomPath) log.Info("* ConfigFile: %s", setting.CustomConf) - log.Info("%s", msg) + log.Info("%s", msg) // show startup message } func serveInstall(ctx *cli.Context) error { diff --git a/models/asymkey/ssh_key_fingerprint.go b/models/asymkey/ssh_key_fingerprint.go index b9cfb1b251..1ed3b5df2a 100644 --- a/models/asymkey/ssh_key_fingerprint.go +++ b/models/asymkey/ssh_key_fingerprint.go @@ -76,23 +76,14 @@ func calcFingerprintNative(publicKeyContent string) (string, error) { // CalcFingerprint calculate public key's fingerprint func CalcFingerprint(publicKeyContent string) (string, error) { // Call the method based on configuration - var ( - fnName, fp string - err error - ) - if len(setting.SSH.KeygenPath) == 0 { - fnName = "calcFingerprintNative" - fp, err = calcFingerprintNative(publicKeyContent) - } else { - fnName = "calcFingerprintSSHKeygen" - fp, err = calcFingerprintSSHKeygen(publicKeyContent) - } + useNative := setting.SSH.KeygenPath == "" + calcFn := util.Iif(useNative, calcFingerprintNative, calcFingerprintSSHKeygen) + fp, err := calcFn(publicKeyContent) if err != nil { if IsErrKeyUnableVerify(err) { - log.Info("%s", publicKeyContent) return "", err } - return "", fmt.Errorf("%s: %w", fnName, err) + return "", fmt.Errorf("CalcFingerprint(%s): %w", util.Iif(useNative, "native", "ssh-keygen"), err) } return fp, nil } diff --git a/models/repo/issue.go b/models/repo/issue.go index 6f6b565a00..0dd4fd5ed4 100644 --- a/models/repo/issue.go +++ b/models/repo/issue.go @@ -53,7 +53,7 @@ func (repo *Repository) IsDependenciesEnabled(ctx context.Context) bool { var u *RepoUnit var err error if u, err = repo.GetUnit(ctx, unit.TypeIssues); err != nil { - log.Trace("%s", err) + log.Trace("IsDependenciesEnabled: %v", err) return setting.Service.DefaultEnableDependencies } return u.IssuesConfig().EnableDependencies diff --git a/modules/util/util.go b/modules/util/util.go index 3921002e2a..44b5a6ed81 100644 --- a/modules/util/util.go +++ b/modules/util/util.go @@ -214,7 +214,7 @@ func ToPointer[T any](val T) *T { } // Iif is an "inline-if", it returns "trueVal" if "condition" is true, otherwise "falseVal" -func Iif[T comparable](condition bool, trueVal, falseVal T) T { +func Iif[T any](condition bool, trueVal, falseVal T) T { if condition { return trueVal } diff --git a/routers/api/v1/notify/repo.go b/routers/api/v1/notify/repo.go index 8d97e8a3f8..1744426ee8 100644 --- a/routers/api/v1/notify/repo.go +++ b/routers/api/v1/notify/repo.go @@ -10,7 +10,6 @@ import ( activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" @@ -201,7 +200,6 @@ func ReadRepoNotifications(ctx *context.APIContext) { if !ctx.FormBool("all") { statuses := ctx.FormStrings("status-types") opts.Status = statusStringsToNotificationStatuses(statuses, []string{"unread"}) - log.Error("%v", opts.Status) } nl, err := db.Find[activities_model.Notification](ctx, opts) if err != nil { diff --git a/routers/private/actions.go b/routers/private/actions.go index 53c2412308..696634b5e7 100644 --- a/routers/private/actions.go +++ b/routers/private/actions.go @@ -26,7 +26,7 @@ func GenerateActionsRunnerToken(ctx *context.PrivateContext) { defer rd.Close() if err := json.NewDecoder(rd).Decode(&genRequest); err != nil { - log.Error("%v", err) + log.Error("JSON Decode failed: %v", err) ctx.JSON(http.StatusInternalServerError, private.Response{ Err: err.Error(), }) @@ -35,7 +35,7 @@ func GenerateActionsRunnerToken(ctx *context.PrivateContext) { owner, repo, err := parseScope(ctx, genRequest.Scope) if err != nil { - log.Error("%v", err) + log.Error("parseScope failed: %v", err) ctx.JSON(http.StatusInternalServerError, private.Response{ Err: err.Error(), }) @@ -45,18 +45,18 @@ func GenerateActionsRunnerToken(ctx *context.PrivateContext) { if errors.Is(err, util.ErrNotExist) || (token != nil && !token.IsActive) { token, err = actions_model.NewRunnerToken(ctx, owner, repo) if err != nil { - err := fmt.Sprintf("error while creating runner token: %v", err) - log.Error("%v", err) + errMsg := fmt.Sprintf("error while creating runner token: %v", err) + log.Error("NewRunnerToken failed: %v", errMsg) ctx.JSON(http.StatusInternalServerError, private.Response{ - Err: err, + Err: errMsg, }) return } } else if err != nil { - err := fmt.Sprintf("could not get unactivated runner token: %v", err) - log.Error("%v", err) + errMsg := fmt.Sprintf("could not get unactivated runner token: %v", err) + log.Error("GetLatestRunnerToken failed: %v", errMsg) ctx.JSON(http.StatusInternalServerError, private.Response{ - Err: err, + Err: errMsg, }) return } diff --git a/routers/private/hook_verification.go b/routers/private/hook_verification.go index 42b8e5abed..764c976fa9 100644 --- a/routers/private/hook_verification.go +++ b/routers/private/hook_verification.go @@ -47,7 +47,7 @@ func verifyCommits(oldCommitID, newCommitID string, repo *git.Repository, env [] _ = stdoutWriter.Close() err := readAndVerifyCommitsFromShaReader(stdoutReader, repo, env) if err != nil { - log.Error("%v", err) + log.Error("readAndVerifyCommitsFromShaReader failed: %v", err) cancel() } _ = stdoutReader.Close() @@ -66,7 +66,6 @@ func readAndVerifyCommitsFromShaReader(input io.ReadCloser, repo *git.Repository line := scanner.Text() err := readAndVerifyCommit(line, repo, env) if err != nil { - log.Error("%v", err) return err } } diff --git a/routers/private/mail.go b/routers/private/mail.go index c19ee67896..cf3abb31c6 100644 --- a/routers/private/mail.go +++ b/routers/private/mail.go @@ -35,7 +35,7 @@ func SendEmail(ctx *context.PrivateContext) { defer rd.Close() if err := json.NewDecoder(rd).Decode(&mail); err != nil { - log.Error("%v", err) + log.Error("JSON Decode failed: %v", err) ctx.JSON(http.StatusInternalServerError, private.Response{ Err: err.Error(), }) diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go index b93668c5a2..ea9d6f4c9c 100644 --- a/routers/web/admin/users.go +++ b/routers/web/admin/users.go @@ -403,7 +403,6 @@ func EditUserPost(ctx *context.Context) { ctx.Data["Err_Password"] = true ctx.RenderWithErr(ctx.Tr("auth.password_pwned"), tplUserEdit, &form) case password.IsErrIsPwnedRequest(err): - log.Error("%s", err.Error()) ctx.Data["Err_Password"] = true ctx.RenderWithErr(ctx.Tr("auth.password_pwned_err"), tplUserEdit, &form) default: diff --git a/routers/web/auth/password.go b/routers/web/auth/password.go index f6b76c1ffd..0e88fe68f9 100644 --- a/routers/web/auth/password.go +++ b/routers/web/auth/password.go @@ -214,7 +214,6 @@ func ResetPasswdPost(ctx *context.Context) { case errors.Is(err, password.ErrIsPwned): ctx.RenderWithErr(ctx.Tr("auth.password_pwned"), tplResetPassword, nil) case password.IsErrIsPwnedRequest(err): - log.Error("%s", err.Error()) ctx.RenderWithErr(ctx.Tr("auth.password_pwned_err"), tplResetPassword, nil) default: ctx.ServerError("UpdateAuth", err) @@ -298,7 +297,6 @@ func MustChangePasswordPost(ctx *context.Context) { ctx.Data["Err_Password"] = true ctx.RenderWithErr(ctx.Tr("auth.password_pwned"), tplMustChangePassword, &form) case password.IsErrIsPwnedRequest(err): - log.Error("%s", err.Error()) ctx.Data["Err_Password"] = true ctx.RenderWithErr(ctx.Tr("auth.password_pwned_err"), tplMustChangePassword, &form) default: diff --git a/routers/web/user/setting/account.go b/routers/web/user/setting/account.go index c93b70af76..8ea7548e51 100644 --- a/routers/web/user/setting/account.go +++ b/routers/web/user/setting/account.go @@ -74,7 +74,6 @@ func AccountPost(ctx *context.Context) { case errors.Is(err, password.ErrIsPwned): ctx.Flash.Error(ctx.Tr("auth.password_pwned")) case password.IsErrIsPwnedRequest(err): - log.Error("%s", err.Error()) ctx.Flash.Error(ctx.Tr("auth.password_pwned_err")) default: ctx.ServerError("UpdateAuth", err) diff --git a/services/context/captcha.go b/services/context/captcha.go index a1999900c9..fa8d779f56 100644 --- a/services/context/captcha.go +++ b/services/context/captcha.go @@ -79,11 +79,11 @@ func VerifyCaptcha(ctx *Context, tpl base.TplName, form any) { case setting.CfTurnstile: valid, err = turnstile.Verify(ctx, ctx.Req.Form.Get(cfTurnstileResponseField)) default: - ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType)) + ctx.ServerError("Unknown Captcha Type", fmt.Errorf("unknown Captcha Type: %s", setting.Service.CaptchaType)) return } if err != nil { - log.Debug("%v", err) + log.Debug("Captcha Verify failed: %v", err) } if !valid { diff --git a/services/notify/notify.go b/services/notify/notify.go index 16fbb6325d..0c8262ef7a 100644 --- a/services/notify/notify.go +++ b/services/notify/notify.go @@ -91,7 +91,7 @@ func AutoMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues // NewPullRequest notifies new pull request to notifiers func NewPullRequest(ctx context.Context, pr *issues_model.PullRequest, mentions []*user_model.User) { if err := pr.LoadIssue(ctx); err != nil { - log.Error("%v", err) + log.Error("LoadIssue failed: %v", err) return } if err := pr.Issue.LoadPoster(ctx); err != nil { @@ -112,7 +112,7 @@ func PullRequestSynchronized(ctx context.Context, doer *user_model.User, pr *iss // PullRequestReview notifies new pull request review func PullRequestReview(ctx context.Context, pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) { if err := review.LoadReviewer(ctx); err != nil { - log.Error("%v", err) + log.Error("LoadReviewer failed: %v", err) return } for _, notifier := range notifiers { diff --git a/services/repository/files/cherry_pick.go b/services/repository/files/cherry_pick.go index 613b46d8f6..451a182155 100644 --- a/services/repository/files/cherry_pick.go +++ b/services/repository/files/cherry_pick.go @@ -28,7 +28,7 @@ func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_mod t, err := NewTemporaryUploadRepository(ctx, repo) if err != nil { - log.Error("%v", err) + log.Error("NewTemporaryUploadRepository failed: %v", err) } defer t.Close() if err := t.Clone(opts.OldBranch, false); err != nil { diff --git a/services/repository/files/patch.go b/services/repository/files/patch.go index f6d5643dc9..e5f7e2af96 100644 --- a/services/repository/files/patch.go +++ b/services/repository/files/patch.go @@ -111,7 +111,7 @@ func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user t, err := NewTemporaryUploadRepository(ctx, repo) if err != nil { - log.Error("%v", err) + log.Error("NewTemporaryUploadRepository failed: %v", err) } defer t.Close() if err := t.Clone(opts.OldBranch, true); err != nil { diff --git a/services/repository/files/update.go b/services/repository/files/update.go index 4f7178184b..f029a9aefe 100644 --- a/services/repository/files/update.go +++ b/services/repository/files/update.go @@ -143,7 +143,7 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use t, err := NewTemporaryUploadRepository(ctx, repo) if err != nil { - log.Error("%v", err) + log.Error("NewTemporaryUploadRepository failed: %v", err) } defer t.Close() hasOldBranch := true diff --git a/services/wiki/wiki.go b/services/wiki/wiki.go index 1b921a44bd..f8387416c1 100644 --- a/services/wiki/wiki.go +++ b/services/wiki/wiki.go @@ -161,7 +161,7 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model if isOldWikiExist { err := gitRepo.RemoveFilesFromIndex(oldWikiPath) if err != nil { - log.Error("%v", err) + log.Error("RemoveFilesFromIndex failed: %v", err) return err } } @@ -171,18 +171,18 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model objectHash, err := gitRepo.HashObject(strings.NewReader(content)) if err != nil { - log.Error("%v", err) + log.Error("HashObject failed: %v", err) return err } if err := gitRepo.AddObjectToIndex("100644", objectHash, newWikiPath); err != nil { - log.Error("%v", err) + log.Error("AddObjectToIndex failed: %v", err) return err } tree, err := gitRepo.WriteTree() if err != nil { - log.Error("%v", err) + log.Error("WriteTree failed: %v", err) return err } @@ -207,7 +207,7 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model commitHash, err := gitRepo.CommitTree(doer.NewGitSig(), committer, tree, commitTreeOpts) if err != nil { - log.Error("%v", err) + log.Error("CommitTree failed: %v", err) return err } @@ -222,11 +222,11 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model 0, ), }); err != nil { - log.Error("%v", err) + log.Error("Push failed: %v", err) if git.IsErrPushOutOfDate(err) || git.IsErrPushRejected(err) { return err } - return fmt.Errorf("Push: %w", err) + return fmt.Errorf("failed to push: %w", err) } return nil From 644ade5ae6805a3db063b3f81a596febe49bacaf Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 7 Apr 2024 14:36:33 +0200 Subject: [PATCH 055/370] Fix checkboxes on mobile view, remove some dead css (#30308) Fix the checkbox issues in https://github.com/go-gitea/gitea/issues/30303 which were existing problems with these selectors, but made visible with https://github.com/go-gitea/gitea/pull/30162. There is a lot of dead/useless CSS in `form.css`, I only fixed the two problems and remove CSS that was definitely not in use or needed. <img width="369" alt="Screenshot 2024-04-06 at 18 00 08" src="https://github.com/go-gitea/gitea/assets/115237/720f178b-1b22-48d4-8704-becb8ce66129"> <img width="405" alt="Screenshot 2024-04-06 at 18 00 28" src="https://github.com/go-gitea/gitea/assets/115237/61c0f8ec-34af-46c5-a3fa-7c5c4d30c7d2"> Co-authored-by: Giteabot <teabot@gitea.io> --- web_src/css/form.css | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/web_src/css/form.css b/web_src/css/form.css index 2a976c056d..a8f73b6b66 100644 --- a/web_src/css/form.css +++ b/web_src/css/form.css @@ -249,21 +249,6 @@ textarea:focus, .user.signup form .optional .title { margin-left: 250px !important; } - .user.activate form .inline.field > input, - .user.forgot.password form .inline.field > input, - .user.reset.password form .inline.field > input, - .user.link-account form .inline.field > input, - .user.signin form .inline.field > input, - .user.signup form .inline.field > input, - .user.activate form .inline.field > textarea, - .user.forgot.password form .inline.field > textarea, - .user.reset.password form .inline.field > textarea, - .user.link-account form .inline.field > textarea, - .user.signin form .inline.field > textarea, - .user.signup form .inline.field > textarea, - .oauth-login-link { - width: 50%; - } } @media (max-width: 767.98px) { @@ -310,14 +295,7 @@ textarea:focus, .user.reset.password form .inline.field > label, .user.link-account form .inline.field > label, .user.signin form .inline.field > label, - .user.signup form .inline.field > label, - .user.activate form input, - .user.forgot.password form input, - .user.reset.password form input, - .user.link-account form input, - .user.signin form input, - .user.signup form input, - .oauth-login-link { + .user.signup form .inline.field > label { width: 100% !important; } } @@ -435,9 +413,9 @@ textarea:focus, .repository.new.repo form label, .repository.new.migrate form label, .repository.new.fork form label, - .repository.new.repo form input, - .repository.new.migrate form input, - .repository.new.fork form input, + .repository.new.repo form .inline.field > input, + .repository.new.migrate form .inline.field > input, + .repository.new.fork form .inline.field > input, .repository.new.fork form .field a, .repository.new.repo form .selection.dropdown, .repository.new.migrate form .selection.dropdown, From 0178eaec256a349371c75e582edd7fefca2085d0 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 7 Apr 2024 14:41:42 +0200 Subject: [PATCH 056/370] Action view mobile improvements and fixes (#30309) Fix the action issue in https://github.com/go-gitea/gitea/issues/30303, specifically: - Use opaque step header hover background to avoid transparency issue - Un-sticky the `action-view-left` on mobile, it would otherwise overlap into right view - Improve commit summary, let it wrap - Fix and comment z-indexes - Tweak width for run-list-item-right so it wastes less space on desktop - Synced latest changes to console colors from dark to light theme <img width="467" alt="Screenshot 2024-04-06 at 18 58 15" src="https://github.com/go-gitea/gitea/assets/115237/8ad26b72-6cd9-4522-8ad1-6fd86b2d0d53"> --- web_src/css/actions.css | 2 +- web_src/css/themes/theme-gitea-dark.css | 2 +- web_src/css/themes/theme-gitea-light.css | 12 +++++----- web_src/js/components/RepoActionView.vue | 28 +++++++++++++++++++----- 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/web_src/css/actions.css b/web_src/css/actions.css index e7b9a3855a..1d5bea2395 100644 --- a/web_src/css/actions.css +++ b/web_src/css/actions.css @@ -44,7 +44,7 @@ } .run-list-item-right { - flex: 0 0 15%; + flex: 0 0 min(20%, 130px); display: flex; flex-direction: column; gap: 3px; diff --git a/web_src/css/themes/theme-gitea-dark.css b/web_src/css/themes/theme-gitea-dark.css index 07e217742d..ed6718e40c 100644 --- a/web_src/css/themes/theme-gitea-dark.css +++ b/web_src/css/themes/theme-gitea-dark.css @@ -65,7 +65,7 @@ --color-console-fg-subtle: #bec4c8; --color-console-bg: #171b1e; --color-console-border: #2e353b; - --color-console-hover-bg: #e8e8ff16; + --color-console-hover-bg: #292d31; --color-console-active-bg: #2e353b; --color-console-menu-bg: #252b30; --color-console-menu-border: #424b51; diff --git a/web_src/css/themes/theme-gitea-light.css b/web_src/css/themes/theme-gitea-light.css index 2741e0e0bd..b10ad7d840 100644 --- a/web_src/css/themes/theme-gitea-light.css +++ b/web_src/css/themes/theme-gitea-light.css @@ -63,12 +63,12 @@ /* console colors - used for actions console and console files */ --color-console-fg: #f8f8f9; --color-console-fg-subtle: #bec4c8; - --color-console-bg: #181b1d; - --color-console-border: #313538; - --color-console-hover-bg: #ffffff16; - --color-console-active-bg: #313538; - --color-console-menu-bg: #272b2e; - --color-console-menu-border: #464a4d; + --color-console-bg: #171b1e; + --color-console-border: #2e353b; + --color-console-hover-bg: #292d31; + --color-console-active-bg: #2e353b; + --color-console-menu-bg: #252b30; + --color-console-menu-border: #424b51; /* named colors */ --color-red: #db2828; --color-orange: #f2711c; diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index 75cd1db70a..06c42f0b35 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -517,8 +517,16 @@ export function initRepositoryActionView() { .action-commit-summary { display: flex; + flex-wrap: wrap; gap: 5px; - margin: 0 0 0 28px; + margin-left: 28px; +} + +@media (max-width: 767.98px) { + .action-commit-summary { + margin-left: 0; + margin-top: 8px; + } } /* ================ */ @@ -531,6 +539,14 @@ export function initRepositoryActionView() { top: 12px; max-height: 100vh; overflow-y: auto; + background: var(--color-body); + z-index: 2; /* above .job-info-header */ +} + +@media (max-width: 767.98px) { + .action-view-left { + position: static; /* can not sticky because multiple jobs would overlap into right view */ + } } .job-artifacts-title { @@ -692,7 +708,9 @@ export function initRepositoryActionView() { position: sticky; top: 0; height: 60px; - z-index: 1; + z-index: 1; /* above .job-step-container */ + background: var(--color-console-bg); + border-radius: 3px; } .job-info-header:has(+ .job-step-container) { @@ -730,7 +748,7 @@ export function initRepositoryActionView() { .job-step-container .job-step-summary.step-expandable:hover { color: var(--color-console-fg); - background-color: var(--color-console-hover-bg); + background: var(--color-console-hover-bg); } .job-step-container .job-step-summary .step-summary-msg { @@ -748,17 +766,15 @@ export function initRepositoryActionView() { top: 60px; } -@media (max-width: 768px) { +@media (max-width: 767.98px) { .action-view-body { flex-direction: column; } .action-view-left, .action-view-right { width: 100%; } - .action-view-left { max-width: none; - overflow-y: hidden; } } </style> From 019857a7015cae32c12b5eac0b895c05f0264b77 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 7 Apr 2024 17:45:36 +0200 Subject: [PATCH 057/370] Add `--page-spacing` variable, fix admin dashboard notice (#30302) Fixes https://github.com/go-gitea/gitea/issues/30293 and introduce the `--page-spacing` variable which holds the spacing between the elements on the page. This is working vertically for all pages, including ones that have fomantic grid, and horizontally for all that use `flex-container`. The `.page-content > :first-child:not(.secondary-nav)` selector uses margin which in some cases enables to adjacent margins to overlap, which is nice. <img width="1320" alt="Screenshot 2024-04-06 at 01 35 19" src="https://github.com/go-gitea/gitea/assets/115237/3e81e707-e9ff-4b7f-a211-3d98f4f85353"> --- <img width="1327" alt="Screenshot 2024-04-06 at 01 35 45" src="https://github.com/go-gitea/gitea/assets/115237/aad196c0-9e21-4c06-ae59-7e33a76c61e1"> --- <img width="1321" alt="Screenshot 2024-04-06 at 01 35 31" src="https://github.com/go-gitea/gitea/assets/115237/785f6c5d-08b6-4e66-aa16-aeca7cfed3ad"> --- templates/user/notification/notification_div.tmpl | 2 +- web_src/css/base.css | 12 ++++++++---- web_src/css/modules/flexcontainer.css | 3 ++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/templates/user/notification/notification_div.tmpl b/templates/user/notification/notification_div.tmpl index 04e79ba749..bf3b51ee3b 100644 --- a/templates/user/notification/notification_div.tmpl +++ b/templates/user/notification/notification_div.tmpl @@ -1,7 +1,7 @@ <div role="main" aria-label="{{.Title}}" class="page-content user notification" id="notification_div" data-sequence-number="{{.SequenceNumber}}"> <div class="ui container"> {{$notificationUnreadCount := call .NotificationUnreadCount}} - <div class="tw-flex tw-items-center tw-justify-between tw-mb-4"> + <div class="tw-flex tw-items-center tw-justify-between tw-mb-[--page-spacing]"> <div class="small-menu-items ui compact tiny menu"> <a class="{{if eq .Status 1}}active {{end}}item" href="{{AppSubUrl}}/notifications?q=unread"> {{ctx.Locale.Tr "notification.unread"}} diff --git a/web_src/css/base.css b/web_src/css/base.css index 096b67058e..44dc83e6f3 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -24,6 +24,7 @@ --min-height-textarea: 132px; /* padding + 6 lines + border = calc(1.57142em + 6lh + 2px), but lh is not fully supported */ --tab-size: 4; --checkbox-size: 16px; /* height and width of checkbox and radio inputs */ + --page-spacing: 16px; /* space between page elements */ } :root * { @@ -582,11 +583,14 @@ img.ui.avatar, margin-bottom: 14px; } -/* add padding to all content when there is no .secondary.nav. this uses padding instead of - margin because with the negative margin on .ui.grid we would have to set margin-top: 0, - but that does not work universally for all pages */ +/* add margin to all pages when there is no .secondary.nav */ .page-content > :first-child:not(.secondary-nav) { - padding-top: 14px; + margin-top: var(--page-spacing); +} +/* if .ui.grid is the first child the first grid-column has 'padding-top: 1rem' which we need + to compensate here */ +.page-content > :first-child.ui.grid { + margin-top: calc(var(--page-spacing) - 1rem); } .ui.pagination.menu .active.item { diff --git a/web_src/css/modules/flexcontainer.css b/web_src/css/modules/flexcontainer.css index 0b559f1e7d..1ca513687f 100644 --- a/web_src/css/modules/flexcontainer.css +++ b/web_src/css/modules/flexcontainer.css @@ -2,7 +2,8 @@ .flex-container { display: flex !important; - gap: 16px; + gap: var(--page-spacing); + margin-top: var(--page-spacing); } .flex-container-nav { From 36887ed3921d03f1864360c95bd2ecf853bfbe72 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 7 Apr 2024 18:19:25 +0200 Subject: [PATCH 058/370] Fix and rewrite contrast color calculation, fix project-related bugs (#30237) 1. The previous color contrast calculation function was incorrect at least for the `#84b6eb` where it output low-contrast white instead of black. I've rewritten these functions now to accept hex colors and to match GitHub's calculation and to output pure white/black for maximum contrast. Before and after: <img width="94" alt="Screenshot 2024-04-02 at 01 53 46" src="https://github.com/go-gitea/gitea/assets/115237/00b39e15-a377-4458-95cf-ceec74b78228"><img width="90" alt="Screenshot 2024-04-02 at 01 51 30" src="https://github.com/go-gitea/gitea/assets/115237/1677067a-8d8f-47eb-82c0-76330deeb775"> 2. Fix project-related issues: - Expose the new `ContrastColor` function as template helper and use it for project cards, replacing the previous JS solution which eliminates a flash of wrong color on page load. - Fix a bug where if editing a project title, the counter would get lost. - Move `rgbToHex` function to color utils. @HesterG fyi --------- Co-authored-by: delvh <dev.lh@web.de> Co-authored-by: Giteabot <teabot@gitea.io> --- modules/templates/helper.go | 6 +-- modules/templates/util_render.go | 11 ++--- modules/util/color.go | 42 +++++++--------- modules/util/color_test.go | 46 +++++++++--------- templates/projects/view.tmpl | 8 ++-- web_src/css/features/projects.css | 27 +++++------ web_src/css/repo.css | 15 +++++- web_src/css/repo/issue-list.css | 17 ------- web_src/css/themes/theme-gitea-dark.css | 2 - web_src/css/themes/theme-gitea-light.css | 2 - web_src/js/components/ContextPopup.vue | 20 +++----- web_src/js/features/repo-projects.js | 61 ++++++++---------------- web_src/js/utils/color.js | 30 ++++++------ web_src/js/utils/color.test.js | 39 +++++++-------- 14 files changed, 135 insertions(+), 191 deletions(-) diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 9e770a2606..5d2fa79bc5 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -53,13 +53,13 @@ func NewFuncMap() template.FuncMap { "JsonUtils": NewJsonUtils, // ----------------------------------------------------------------- - // svg / avatar / icon + // svg / avatar / icon / color "svg": svg.RenderHTML, "EntryIcon": base.EntryIcon, "MigrationIcon": MigrationIcon, "ActionIcon": ActionIcon, - - "SortArrow": SortArrow, + "SortArrow": SortArrow, + "ContrastColor": util.ContrastColor, // ----------------------------------------------------------------- // time / number / format diff --git a/modules/templates/util_render.go b/modules/templates/util_render.go index d1c9b082fa..0b53965f25 100644 --- a/modules/templates/util_render.go +++ b/modules/templates/util_render.go @@ -123,16 +123,10 @@ func RenderIssueTitle(ctx context.Context, text string, metas map[string]string) func RenderLabel(ctx context.Context, locale translation.Locale, label *issues_model.Label) template.HTML { var ( archivedCSSClass string - textColor = "#111" + textColor = util.ContrastColor(label.Color) labelScope = label.ExclusiveScope() ) - r, g, b := util.HexToRBGColor(label.Color) - // Determine if label text should be light or dark to be readable on background color - if util.UseLightTextOnBackground(r, g, b) { - textColor = "#eee" - } - description := emoji.ReplaceAliases(template.HTMLEscapeString(label.Description)) if label.IsArchived() { @@ -153,7 +147,7 @@ func RenderLabel(ctx context.Context, locale translation.Locale, label *issues_m // Make scope and item background colors slightly darker and lighter respectively. // More contrast needed with higher luminance, empirically tweaked. - luminance := util.GetLuminance(r, g, b) + luminance := util.GetRelativeLuminance(label.Color) contrast := 0.01 + luminance*0.03 // Ensure we add the same amount of contrast also near 0 and 1. darken := contrast + math.Max(luminance+contrast-1.0, 0.0) @@ -162,6 +156,7 @@ func RenderLabel(ctx context.Context, locale translation.Locale, label *issues_m darkenFactor := math.Max(luminance-darken, 0.0) / math.Max(luminance, 1.0/255.0) lightenFactor := math.Min(luminance+lighten, 1.0) / math.Max(luminance, 1.0/255.0) + r, g, b := util.HexToRBGColor(label.Color) scopeBytes := []byte{ uint8(math.Min(math.Round(r*darkenFactor), 255)), uint8(math.Min(math.Round(g*darkenFactor), 255)), diff --git a/modules/util/color.go b/modules/util/color.go index 240b045c28..9c520dce78 100644 --- a/modules/util/color.go +++ b/modules/util/color.go @@ -4,22 +4,10 @@ package util import ( "fmt" - "math" "strconv" "strings" ) -// Check similar implementation in web_src/js/utils/color.js and keep synchronization - -// Return R, G, B values defined in reletive luminance -func getLuminanceRGB(channel float64) float64 { - sRGB := channel / 255 - if sRGB <= 0.03928 { - return sRGB / 12.92 - } - return math.Pow((sRGB+0.055)/1.055, 2.4) -} - // Get color as RGB values in 0..255 range from the hex color string (with or without #) func HexToRBGColor(colorString string) (float64, float64, float64) { hexString := colorString @@ -47,19 +35,23 @@ func HexToRBGColor(colorString string) (float64, float64, float64) { return r, g, b } -// return luminance given RGB channels -// Reference from: https://www.w3.org/WAI/GL/wiki/Relative_luminance -func GetLuminance(r, g, b float64) float64 { - R := getLuminanceRGB(r) - G := getLuminanceRGB(g) - B := getLuminanceRGB(b) - luminance := 0.2126*R + 0.7152*G + 0.0722*B - return luminance +// Returns relative luminance for a SRGB color - https://en.wikipedia.org/wiki/Relative_luminance +// Keep this in sync with web_src/js/utils/color.js +func GetRelativeLuminance(color string) float64 { + r, g, b := HexToRBGColor(color) + return (0.2126729*r + 0.7151522*g + 0.0721750*b) / 255 } -// Reference from: https://firsching.ch/github_labels.html -// In the future WCAG 3 APCA may be a better solution. -// Check if text should use light color based on RGB of background -func UseLightTextOnBackground(r, g, b float64) bool { - return GetLuminance(r, g, b) < 0.453 +func UseLightText(backgroundColor string) bool { + return GetRelativeLuminance(backgroundColor) < 0.453 +} + +// Given a background color, returns a black or white foreground color that the highest +// contrast ratio. In the future, the APCA contrast function, or CSS `contrast-color` will be better. +// https://github.com/color-js/color.js/blob/eb7b53f7a13bb716ec8b28c7a56f052cd599acd9/src/contrast/APCA.js#L42 +func ContrastColor(backgroundColor string) string { + if UseLightText(backgroundColor) { + return "#fff" + } + return "#000" } diff --git a/modules/util/color_test.go b/modules/util/color_test.go index d96ac36730..be6e6b122a 100644 --- a/modules/util/color_test.go +++ b/modules/util/color_test.go @@ -33,33 +33,31 @@ func Test_HexToRBGColor(t *testing.T) { } } -func Test_UseLightTextOnBackground(t *testing.T) { +func Test_UseLightText(t *testing.T) { cases := []struct { - r float64 - g float64 - b float64 - expected bool + color string + expected string }{ - {215, 58, 74, true}, - {0, 117, 202, true}, - {207, 211, 215, false}, - {162, 238, 239, false}, - {112, 87, 255, true}, - {0, 134, 114, true}, - {228, 230, 105, false}, - {216, 118, 227, true}, - {255, 255, 255, false}, - {43, 134, 133, true}, - {43, 135, 134, true}, - {44, 135, 134, true}, - {59, 182, 179, true}, - {124, 114, 104, true}, - {126, 113, 108, true}, - {129, 112, 109, true}, - {128, 112, 112, true}, + {"#d73a4a", "#fff"}, + {"#0075ca", "#fff"}, + {"#cfd3d7", "#000"}, + {"#a2eeef", "#000"}, + {"#7057ff", "#fff"}, + {"#008672", "#fff"}, + {"#e4e669", "#000"}, + {"#d876e3", "#000"}, + {"#ffffff", "#000"}, + {"#2b8684", "#fff"}, + {"#2b8786", "#fff"}, + {"#2c8786", "#000"}, + {"#3bb6b3", "#000"}, + {"#7c7268", "#fff"}, + {"#7e716c", "#fff"}, + {"#81706d", "#fff"}, + {"#807070", "#fff"}, + {"#84b6eb", "#000"}, } for n, c := range cases { - result := UseLightTextOnBackground(c.r, c.g, c.b) - assert.Equal(t, c.expected, result, "case %d: error should match", n) + assert.Equal(t, c.expected, ContrastColor(c.color), "case %d: error should match", n) } } diff --git a/templates/projects/view.tmpl b/templates/projects/view.tmpl index 33dd758c79..f9b85360e0 100644 --- a/templates/projects/view.tmpl +++ b/templates/projects/view.tmpl @@ -66,13 +66,13 @@ <div id="project-board"> <div class="board {{if .CanWriteProjects}}sortable{{end}}"> {{range .Columns}} - <div class="ui segment project-column" style="background: {{.Color}} !important;" data-id="{{.ID}}" data-sorting="{{.Sorting}}" data-url="{{$.Link}}/{{.ID}}"> + <div class="ui segment project-column"{{if .Color}} style="background: {{.Color}} !important; color: {{ContrastColor .Color}} !important"{{end}} data-id="{{.ID}}" data-sorting="{{.Sorting}}" data-url="{{$.Link}}/{{.ID}}"> <div class="project-column-header{{if $canWriteProject}} tw-cursor-grab{{end}}"> <div class="ui large label project-column-title tw-py-1"> <div class="ui small circular grey label project-column-issue-count"> {{.NumIssues ctx}} </div> - {{.Title}} + <span class="project-column-title-label">{{.Title}}</span> </div> {{if $canWriteProject}} <div class="ui dropdown jump item"> @@ -153,9 +153,7 @@ </div> {{end}} </div> - - <div class="divider"></div> - + <div class="divider"{{if .Color}} style="color: {{ContrastColor .Color}} !important"{{end}}></div> <div class="ui cards" data-url="{{$.Link}}/{{.ID}}" data-project="{{$.Project.ID}}" data-board="{{.ID}}" id="board_{{.ID}}"> {{range (index $.IssuesMap .ID)}} <div class="issue-card gt-word-break {{if $canWriteProject}}tw-cursor-grab{{end}}" data-issue="{{.ID}}"> diff --git a/web_src/css/features/projects.css b/web_src/css/features/projects.css index cec5e6fc64..e23c146748 100644 --- a/web_src/css/features/projects.css +++ b/web_src/css/features/projects.css @@ -22,34 +22,27 @@ cursor: default; } +.project-column .issue-card { + color: var(--color-text); +} + .project-column-header { display: flex; align-items: center; justify-content: space-between; } -.project-column-header.dark-label { - color: var(--color-project-board-dark-label) !important; -} - -.project-column-header.dark-label .project-column-title { - color: var(--color-project-board-dark-label) !important; -} - -.project-column-header.light-label { - color: var(--color-project-board-light-label) !important; -} - -.project-column-header.light-label .project-column-title { - color: var(--color-project-board-light-label) !important; -} - .project-column-title { background: none !important; line-height: 1.25 !important; cursor: inherit; } +.project-column-title, +.project-column-issue-count { + color: inherit !important; +} + .project-column > .cards { flex: 1; display: flex; @@ -64,6 +57,8 @@ .project-column > .divider { margin: 5px 0; + border-color: currentcolor; + opacity: .5; } .project-column:first-child { diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 653af379d5..c50d13a174 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -2273,8 +2273,21 @@ height: 0.5em; } +.labels-list { + display: flex; + flex-wrap: wrap; + gap: 0.25em; +} + +.labels-list a { + display: flex; + text-decoration: none; +} + .labels-list .label { - margin: 2px 0; + padding: 0 6px; + margin: 0 !important; + min-height: 20px; display: inline-flex !important; line-height: 1.3; /* there is a `font-size: 1.25em` for inside emoji, so here the line-height needs to be larger slightly */ } diff --git a/web_src/css/repo/issue-list.css b/web_src/css/repo/issue-list.css index fe8231d718..77905956f0 100644 --- a/web_src/css/repo/issue-list.css +++ b/web_src/css/repo/issue-list.css @@ -34,23 +34,6 @@ } } -#issue-list .flex-item-title .labels-list { - display: flex; - flex-wrap: wrap; - gap: 0.25em; -} - -#issue-list .flex-item-title .labels-list a { - display: flex; - text-decoration: none; -} - -#issue-list .flex-item-title .labels-list .label { - padding: 0 6px; - margin: 0; - min-height: 20px; -} - #issue-list .flex-item-body .branches { display: inline-flex; } diff --git a/web_src/css/themes/theme-gitea-dark.css b/web_src/css/themes/theme-gitea-dark.css index ed6718e40c..c74f334c2d 100644 --- a/web_src/css/themes/theme-gitea-dark.css +++ b/web_src/css/themes/theme-gitea-dark.css @@ -215,8 +215,6 @@ --color-placeholder-text: var(--color-text-light-3); --color-editor-line-highlight: var(--color-primary-light-5); --color-project-board-bg: var(--color-secondary-light-2); - --color-project-board-dark-label: #0e1011; - --color-project-board-light-label: #dde0e2; --color-caret: var(--color-text); /* should ideally be --color-text-dark, see #15651 */ --color-reaction-bg: #e8e8ff12; --color-reaction-hover-bg: var(--color-primary-light-4); diff --git a/web_src/css/themes/theme-gitea-light.css b/web_src/css/themes/theme-gitea-light.css index b10ad7d840..01dd8ba4f7 100644 --- a/web_src/css/themes/theme-gitea-light.css +++ b/web_src/css/themes/theme-gitea-light.css @@ -215,8 +215,6 @@ --color-placeholder-text: var(--color-text-light-3); --color-editor-line-highlight: var(--color-primary-light-6); --color-project-board-bg: var(--color-secondary-light-4); - --color-project-board-dark-label: #0e1114; - --color-project-board-light-label: #eaeef2; --color-caret: var(--color-text-dark); --color-reaction-bg: #0000170a; --color-reaction-hover-bg: var(--color-primary-light-5); diff --git a/web_src/js/components/ContextPopup.vue b/web_src/js/components/ContextPopup.vue index d87eb1a180..65a6089522 100644 --- a/web_src/js/components/ContextPopup.vue +++ b/web_src/js/components/ContextPopup.vue @@ -1,7 +1,6 @@ <script> import {SvgIcon} from '../svg.js'; -import {useLightTextOnBackground} from '../utils/color.js'; -import tinycolor from 'tinycolor2'; +import {contrastColor} from '../utils/color.js'; import {GET} from '../modules/fetch.js'; const {appSubUrl, i18n} = window.config; @@ -59,16 +58,11 @@ export default { }, labels() { - return this.issue.labels.map((label) => { - let textColor; - const {r, g, b} = tinycolor(label.color).toRgb(); - if (useLightTextOnBackground(r, g, b)) { - textColor = '#eeeeee'; - } else { - textColor = '#111111'; - } - return {name: label.name, color: `#${label.color}`, textColor}; - }); + return this.issue.labels.map((label) => ({ + name: label.name, + color: `#${label.color}`, + textColor: contrastColor(`#${label.color}`), + })); }, }, mounted() { @@ -108,7 +102,7 @@ export default { <p><small>{{ issue.repository.full_name }} on {{ createdAt }}</small></p> <p><svg-icon :name="icon" :class="['text', color]"/> <strong>{{ issue.title }}</strong> #{{ issue.number }}</p> <p>{{ body }}</p> - <div> + <div class="labels-list"> <div v-for="label in labels" :key="label.name" diff --git a/web_src/js/features/repo-projects.js b/web_src/js/features/repo-projects.js index 80e945a0f2..a869c24c82 100644 --- a/web_src/js/features/repo-projects.js +++ b/web_src/js/features/repo-projects.js @@ -1,8 +1,8 @@ import $ from 'jquery'; -import {useLightTextOnBackground} from '../utils/color.js'; -import tinycolor from 'tinycolor2'; +import {contrastColor} from '../utils/color.js'; import {createSortable} from '../modules/sortable.js'; import {POST, DELETE, PUT} from '../modules/fetch.js'; +import tinycolor from 'tinycolor2'; function updateIssueCount(cards) { const parent = cards.parentElement; @@ -65,14 +65,11 @@ async function initRepoProjectSortable() { boardColumns = mainBoard.getElementsByClassName('project-column'); for (let i = 0; i < boardColumns.length; i++) { const column = boardColumns[i]; - if (parseInt($(column).data('sorting')) !== i) { + if (parseInt(column.getAttribute('data-sorting')) !== i) { try { - await PUT($(column).data('url'), { - data: { - sorting: i, - color: rgbToHex(window.getComputedStyle($(column)[0]).backgroundColor), - }, - }); + const bgColor = column.style.backgroundColor; // will be rgb() string + const color = bgColor ? tinycolor(bgColor).toHexString() : ''; + await PUT(column.getAttribute('data-url'), {data: {sorting: i, color}}); } catch (error) { console.error(error); } @@ -102,16 +99,10 @@ export function initRepoProject() { for (const modal of document.getElementsByClassName('edit-project-column-modal')) { const projectHeader = modal.closest('.project-column-header'); - const projectTitleLabel = projectHeader?.querySelector('.project-column-title'); + const projectTitleLabel = projectHeader?.querySelector('.project-column-title-label'); const projectTitleInput = modal.querySelector('.project-column-title-input'); const projectColorInput = modal.querySelector('#new_project_column_color'); const boardColumn = modal.closest('.project-column'); - const bgColor = boardColumn?.style.backgroundColor; - - if (bgColor) { - setLabelColor(projectHeader, rgbToHex(bgColor)); - } - modal.querySelector('.edit-project-column-button')?.addEventListener('click', async function (e) { e.preventDefault(); try { @@ -126,10 +117,21 @@ export function initRepoProject() { } finally { projectTitleLabel.textContent = projectTitleInput?.value; projectTitleInput.closest('form')?.classList.remove('dirty'); - if (projectColorInput?.value) { - setLabelColor(projectHeader, projectColorInput.value); + const dividers = boardColumn.querySelectorAll(':scope > .divider'); + if (projectColorInput.value) { + const color = contrastColor(projectColorInput.value); + boardColumn.style.setProperty('background', projectColorInput.value, 'important'); + boardColumn.style.setProperty('color', color, 'important'); + for (const divider of dividers) { + divider.style.setProperty('color', color); + } + } else { + boardColumn.style.removeProperty('background'); + boardColumn.style.removeProperty('color'); + for (const divider of dividers) { + divider.style.removeProperty('color'); + } } - boardColumn.style = `background: ${projectColorInput.value} !important`; $('.ui.modal').modal('hide'); } }); @@ -182,24 +184,3 @@ export function initRepoProject() { createNewColumn(url, $columnTitle, $projectColorInput); }); } - -function setLabelColor(label, color) { - const {r, g, b} = tinycolor(color).toRgb(); - if (useLightTextOnBackground(r, g, b)) { - label.classList.remove('dark-label'); - label.classList.add('light-label'); - } else { - label.classList.remove('light-label'); - label.classList.add('dark-label'); - } -} - -function rgbToHex(rgb) { - rgb = rgb.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+).*\)$/); - return `#${hex(rgb[1])}${hex(rgb[2])}${hex(rgb[3])}`; -} - -function hex(x) { - const hexDigits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; - return Number.isNaN(x) ? '00' : hexDigits[(x - x % 16) / 16] + hexDigits[x % 16]; -} diff --git a/web_src/js/utils/color.js b/web_src/js/utils/color.js index 0ba6af49ee..198f97c454 100644 --- a/web_src/js/utils/color.js +++ b/web_src/js/utils/color.js @@ -1,23 +1,21 @@ -// Check similar implementation in modules/util/color.go and keep synchronization -// Return R, G, B values defined in reletive luminance -function getLuminanceRGB(channel) { - const sRGB = channel / 255; - return (sRGB <= 0.03928) ? sRGB / 12.92 : ((sRGB + 0.055) / 1.055) ** 2.4; +import tinycolor from 'tinycolor2'; + +// Returns relative luminance for a SRGB color - https://en.wikipedia.org/wiki/Relative_luminance +// Keep this in sync with modules/util/color.go +function getRelativeLuminance(color) { + const {r, g, b} = tinycolor(color).toRgb(); + return (0.2126729 * r + 0.7151522 * g + 0.072175 * b) / 255; } -// Reference from: https://www.w3.org/WAI/GL/wiki/Relative_luminance -function getLuminance(r, g, b) { - const R = getLuminanceRGB(r); - const G = getLuminanceRGB(g); - const B = getLuminanceRGB(b); - return 0.2126 * R + 0.7152 * G + 0.0722 * B; +function useLightText(backgroundColor) { + return getRelativeLuminance(backgroundColor) < 0.453; } -// Reference from: https://firsching.ch/github_labels.html -// In the future WCAG 3 APCA may be a better solution. -// Check if text should use light color based on RGB of background -export function useLightTextOnBackground(r, g, b) { - return getLuminance(r, g, b) < 0.453; +// Given a background color, returns a black or white foreground color that the highest +// contrast ratio. In the future, the APCA contrast function, or CSS `contrast-color` will be better. +// https://github.com/color-js/color.js/blob/eb7b53f7a13bb716ec8b28c7a56f052cd599acd9/src/contrast/APCA.js#L42 +export function contrastColor(backgroundColor) { + return useLightText(backgroundColor) ? '#fff' : '#000'; } function resolveColors(obj) { diff --git a/web_src/js/utils/color.test.js b/web_src/js/utils/color.test.js index e129109ef0..fee9afc776 100644 --- a/web_src/js/utils/color.test.js +++ b/web_src/js/utils/color.test.js @@ -1,21 +1,22 @@ -import {useLightTextOnBackground} from './color.js'; +import {contrastColor} from './color.js'; -test('useLightTextOnBackground', () => { - expect(useLightTextOnBackground(215, 58, 74)).toBe(true); - expect(useLightTextOnBackground(0, 117, 202)).toBe(true); - expect(useLightTextOnBackground(207, 211, 215)).toBe(false); - expect(useLightTextOnBackground(162, 238, 239)).toBe(false); - expect(useLightTextOnBackground(112, 87, 255)).toBe(true); - expect(useLightTextOnBackground(0, 134, 114)).toBe(true); - expect(useLightTextOnBackground(228, 230, 105)).toBe(false); - expect(useLightTextOnBackground(216, 118, 227)).toBe(true); - expect(useLightTextOnBackground(255, 255, 255)).toBe(false); - expect(useLightTextOnBackground(43, 134, 133)).toBe(true); - expect(useLightTextOnBackground(43, 135, 134)).toBe(true); - expect(useLightTextOnBackground(44, 135, 134)).toBe(true); - expect(useLightTextOnBackground(59, 182, 179)).toBe(true); - expect(useLightTextOnBackground(124, 114, 104)).toBe(true); - expect(useLightTextOnBackground(126, 113, 108)).toBe(true); - expect(useLightTextOnBackground(129, 112, 109)).toBe(true); - expect(useLightTextOnBackground(128, 112, 112)).toBe(true); +test('contrastColor', () => { + expect(contrastColor('#d73a4a')).toBe('#fff'); + expect(contrastColor('#0075ca')).toBe('#fff'); + expect(contrastColor('#cfd3d7')).toBe('#000'); + expect(contrastColor('#a2eeef')).toBe('#000'); + expect(contrastColor('#7057ff')).toBe('#fff'); + expect(contrastColor('#008672')).toBe('#fff'); + expect(contrastColor('#e4e669')).toBe('#000'); + expect(contrastColor('#d876e3')).toBe('#000'); + expect(contrastColor('#ffffff')).toBe('#000'); + expect(contrastColor('#2b8684')).toBe('#fff'); + expect(contrastColor('#2b8786')).toBe('#fff'); + expect(contrastColor('#2c8786')).toBe('#000'); + expect(contrastColor('#3bb6b3')).toBe('#000'); + expect(contrastColor('#7c7268')).toBe('#fff'); + expect(contrastColor('#7e716c')).toBe('#fff'); + expect(contrastColor('#81706d')).toBe('#fff'); + expect(contrastColor('#807070')).toBe('#fff'); + expect(contrastColor('#84b6eb')).toBe('#000'); }); From 8498e67309478bd0a65a7b1c6f3c8e6ce62c0956 Mon Sep 17 00:00:00 2001 From: KN4CK3R <admin@oldschoolhack.me> Date: Sun, 7 Apr 2024 18:46:59 +0200 Subject: [PATCH 059/370] Some NuGet package enhancements (#30280) Fixes #30265 1. Read second type of dependencies 2. Render `Description` and `ReleaseNotes` old:  new:  The NuGet spec does not specify what kind of text can be stored in the description but we can best guess markdown. The official NuGet registry just [converts the newlines to html lines](https://www.nuget.org/packages/rb.Firefox#readme-body-tab). 3. Extract and render the readme. This is the new and better place to store larger text than in the description. The content is markdown.  --------- Co-authored-by: Benjamin Heemann <benjamin.heemann@raith.de> --- modules/packages/nuget/metadata.go | 34 +++++++++++++- modules/packages/nuget/metadata_test.go | 62 +++++++++++++++---------- templates/package/content/nuget.tmpl | 9 ++-- 3 files changed, 73 insertions(+), 32 deletions(-) diff --git a/modules/packages/nuget/metadata.go b/modules/packages/nuget/metadata.go index 3c478b1c02..6769c514cc 100644 --- a/modules/packages/nuget/metadata.go +++ b/modules/packages/nuget/metadata.go @@ -58,6 +58,7 @@ type Package struct { type Metadata struct { Description string `json:"description,omitempty"` ReleaseNotes string `json:"release_notes,omitempty"` + Readme string `json:"readme,omitempty"` Authors string `json:"authors,omitempty"` ProjectURL string `json:"project_url,omitempty"` RepositoryURL string `json:"repository_url,omitempty"` @@ -71,6 +72,7 @@ type Dependency struct { Version string `json:"version"` } +// https://learn.microsoft.com/en-us/nuget/reference/nuspec type nuspecPackage struct { Metadata struct { ID string `xml:"id"` @@ -80,6 +82,7 @@ type nuspecPackage struct { ProjectURL string `xml:"projectUrl"` Description string `xml:"description"` ReleaseNotes string `xml:"releaseNotes"` + Readme string `xml:"readme"` PackageTypes struct { PackageType []struct { Name string `xml:"name,attr"` @@ -89,6 +92,11 @@ type nuspecPackage struct { URL string `xml:"url,attr"` } `xml:"repository"` Dependencies struct { + Dependency []struct { + ID string `xml:"id,attr"` + Version string `xml:"version,attr"` + Exclude string `xml:"exclude,attr"` + } `xml:"dependency"` Group []struct { TargetFramework string `xml:"targetFramework,attr"` Dependency []struct { @@ -122,14 +130,14 @@ func ParsePackageMetaData(r io.ReaderAt, size int64) (*Package, error) { } defer f.Close() - return ParseNuspecMetaData(f) + return ParseNuspecMetaData(archive, f) } } return nil, ErrMissingNuspecFile } // ParseNuspecMetaData parses a Nuspec file to retrieve the metadata of a Nuget package -func ParseNuspecMetaData(r io.Reader) (*Package, error) { +func ParseNuspecMetaData(archive *zip.Reader, r io.Reader) (*Package, error) { var p nuspecPackage if err := xml.NewDecoder(r).Decode(&p); err != nil { return nil, err @@ -166,6 +174,28 @@ func ParseNuspecMetaData(r io.Reader) (*Package, error) { Dependencies: make(map[string][]Dependency), } + if p.Metadata.Readme != "" { + f, err := archive.Open(p.Metadata.Readme) + if err == nil { + buf, _ := io.ReadAll(f) + m.Readme = string(buf) + _ = f.Close() + } + } + + if len(p.Metadata.Dependencies.Dependency) > 0 { + deps := make([]Dependency, 0, len(p.Metadata.Dependencies.Dependency)) + for _, dep := range p.Metadata.Dependencies.Dependency { + if dep.ID == "" || dep.Version == "" { + continue + } + deps = append(deps, Dependency{ + ID: dep.ID, + Version: dep.Version, + }) + } + m.Dependencies[""] = deps + } for _, group := range p.Metadata.Dependencies.Group { deps := make([]Dependency, 0, len(group.Dependency)) for _, dep := range group.Dependency { diff --git a/modules/packages/nuget/metadata_test.go b/modules/packages/nuget/metadata_test.go index bba2bff4a5..f466492f8a 100644 --- a/modules/packages/nuget/metadata_test.go +++ b/modules/packages/nuget/metadata_test.go @@ -6,7 +6,6 @@ package nuget import ( "archive/zip" "bytes" - "strings" "testing" "github.com/stretchr/testify/assert" @@ -19,6 +18,7 @@ const ( projectURL = "https://gitea.io" description = "Package Description" releaseNotes = "Package Release Notes" + readme = "Readme" repositoryURL = "https://gitea.io/gitea/gitea" targetFramework = ".NETStandard2.1" dependencyID = "System.Text.Json" @@ -36,6 +36,7 @@ const nuspecContent = `<?xml version="1.0" encoding="utf-8"?> <description>` + description + `</description> <releaseNotes>` + releaseNotes + `</releaseNotes> <repository url="` + repositoryURL + `" /> + <readme>README.md</readme> <dependencies> <group targetFramework="` + targetFramework + `"> <dependency id="` + dependencyID + `" version="` + dependencyVersion + `" exclude="Build,Analyzers" /> @@ -60,17 +61,19 @@ const symbolsNuspecContent = `<?xml version="1.0" encoding="utf-8"?> </package>` func TestParsePackageMetaData(t *testing.T) { - createArchive := func(name, content string) []byte { + createArchive := func(files map[string]string) []byte { var buf bytes.Buffer archive := zip.NewWriter(&buf) - w, _ := archive.Create(name) - w.Write([]byte(content)) + for name, content := range files { + w, _ := archive.Create(name) + w.Write([]byte(content)) + } archive.Close() return buf.Bytes() } t.Run("MissingNuspecFile", func(t *testing.T) { - data := createArchive("dummy.txt", "") + data := createArchive(map[string]string{"dummy.txt": ""}) np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.Nil(t, np) @@ -78,7 +81,7 @@ func TestParsePackageMetaData(t *testing.T) { }) t.Run("MissingNuspecFileInRoot", func(t *testing.T) { - data := createArchive("sub/package.nuspec", "") + data := createArchive(map[string]string{"sub/package.nuspec": ""}) np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.Nil(t, np) @@ -86,7 +89,7 @@ func TestParsePackageMetaData(t *testing.T) { }) t.Run("InvalidNuspecFile", func(t *testing.T) { - data := createArchive("package.nuspec", "") + data := createArchive(map[string]string{"package.nuspec": ""}) np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.Nil(t, np) @@ -94,10 +97,10 @@ func TestParsePackageMetaData(t *testing.T) { }) t.Run("InvalidPackageId", func(t *testing.T) { - data := createArchive("package.nuspec", `<?xml version="1.0" encoding="utf-8"?> + data := createArchive(map[string]string{"package.nuspec": `<?xml version="1.0" encoding="utf-8"?> <package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd"> <metadata></metadata> - </package>`) + </package>`}) np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.Nil(t, np) @@ -105,30 +108,34 @@ func TestParsePackageMetaData(t *testing.T) { }) t.Run("InvalidPackageVersion", func(t *testing.T) { - data := createArchive("package.nuspec", `<?xml version="1.0" encoding="utf-8"?> + data := createArchive(map[string]string{"package.nuspec": `<?xml version="1.0" encoding="utf-8"?> <package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd"> <metadata> - <id>`+id+`</id> + <id>` + id + `</id> </metadata> - </package>`) + </package>`}) np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.Nil(t, np) assert.ErrorIs(t, err, ErrNuspecInvalidVersion) }) - t.Run("Valid", func(t *testing.T) { - data := createArchive("package.nuspec", nuspecContent) + t.Run("MissingReadme", func(t *testing.T) { + data := createArchive(map[string]string{"package.nuspec": nuspecContent}) np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.NoError(t, err) assert.NotNil(t, np) + assert.Empty(t, np.Metadata.Readme) }) -} -func TestParseNuspecMetaData(t *testing.T) { t.Run("Dependency Package", func(t *testing.T) { - np, err := ParseNuspecMetaData(strings.NewReader(nuspecContent)) + data := createArchive(map[string]string{ + "package.nuspec": nuspecContent, + "README.md": readme, + }) + + np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.NoError(t, err) assert.NotNil(t, np) assert.Equal(t, DependencyPackage, np.PackageType) @@ -139,6 +146,7 @@ func TestParseNuspecMetaData(t *testing.T) { assert.Equal(t, projectURL, np.Metadata.ProjectURL) assert.Equal(t, description, np.Metadata.Description) assert.Equal(t, releaseNotes, np.Metadata.ReleaseNotes) + assert.Equal(t, readme, np.Metadata.Readme) assert.Equal(t, repositoryURL, np.Metadata.RepositoryURL) assert.Len(t, np.Metadata.Dependencies, 1) assert.Contains(t, np.Metadata.Dependencies, targetFramework) @@ -148,13 +156,15 @@ func TestParseNuspecMetaData(t *testing.T) { assert.Equal(t, dependencyVersion, deps[0].Version) t.Run("NormalizedVersion", func(t *testing.T) { - np, err := ParseNuspecMetaData(strings.NewReader(`<?xml version="1.0" encoding="utf-8"?> -<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd"> - <metadata> - <id>test</id> - <version>1.04.5.2.5-rc.1+metadata</version> - </metadata> -</package>`)) + data := createArchive(map[string]string{"package.nuspec": `<?xml version="1.0" encoding="utf-8"?> + <package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd"> + <metadata> + <id>test</id> + <version>1.04.5.2.5-rc.1+metadata</version> + </metadata> + </package>`}) + + np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.NoError(t, err) assert.NotNil(t, np) assert.Equal(t, "1.4.5.2-rc.1", np.Version) @@ -162,7 +172,9 @@ func TestParseNuspecMetaData(t *testing.T) { }) t.Run("Symbols Package", func(t *testing.T) { - np, err := ParseNuspecMetaData(strings.NewReader(symbolsNuspecContent)) + data := createArchive(map[string]string{"package.nuspec": symbolsNuspecContent}) + + np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.NoError(t, err) assert.NotNil(t, np) assert.Equal(t, SymbolsPackage, np.PackageType) diff --git a/templates/package/content/nuget.tmpl b/templates/package/content/nuget.tmpl index 0911260fba..f1fe420c0b 100644 --- a/templates/package/content/nuget.tmpl +++ b/templates/package/content/nuget.tmpl @@ -16,12 +16,11 @@ </div> </div> - {{if or .PackageDescriptor.Metadata.Description .PackageDescriptor.Metadata.ReleaseNotes}} + {{if or .PackageDescriptor.Metadata.Description .PackageDescriptor.Metadata.ReleaseNotes .PackageDescriptor.Metadata.Readme}} <h4 class="ui top attached header">{{ctx.Locale.Tr "packages.about"}}</h4> - <div class="ui attached segment"> - {{if .PackageDescriptor.Metadata.Description}}{{.PackageDescriptor.Metadata.Description}}{{end}} - {{if .PackageDescriptor.Metadata.ReleaseNotes}}{{.PackageDescriptor.Metadata.ReleaseNotes}}{{end}} - </div> + {{if .PackageDescriptor.Metadata.Description}}<div class="ui attached segment">{{RenderMarkdownToHtml $.Context .PackageDescriptor.Metadata.Description}}</div>{{end}} + {{if .PackageDescriptor.Metadata.Readme}}<div class="ui attached segment markup markdown">{{RenderMarkdownToHtml $.Context .PackageDescriptor.Metadata.Readme}}</div>{{end}} + {{if .PackageDescriptor.Metadata.ReleaseNotes}}<div class="ui attached segment">{{RenderMarkdownToHtml $.Context .PackageDescriptor.Metadata.ReleaseNotes}}</div>{{end}} {{end}} {{if .PackageDescriptor.Metadata.Dependencies}} From 0c7b0c5acaae911d3d3fefa1d8b394594c860620 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Mon, 8 Apr 2024 00:25:35 +0000 Subject: [PATCH 060/370] [skip ci] Updated licenses and gitignores --- options/license/APL-1.0 | 44 ++++++++++++++++++------------------ options/license/IBM-pibs | 4 ++-- options/license/NCGL-UK-2.0 | 6 ++--- options/license/NPL-1.1 | 8 +++---- options/license/OCCT-PL | 8 +++---- options/license/OGL-UK-1.0 | 22 +++++++++--------- options/license/OSET-PL-2.1 | 3 ++- options/license/SHL-2.0 | 18 +++++++-------- options/license/SHL-2.1 | 2 +- options/license/SISSL | 10 ++++---- options/license/W3C-19980720 | 2 +- 11 files changed, 64 insertions(+), 63 deletions(-) diff --git a/options/license/APL-1.0 b/options/license/APL-1.0 index 261f2d687c..0748f90cd9 100644 --- a/options/license/APL-1.0 +++ b/options/license/APL-1.0 @@ -210,21 +210,21 @@ PART 1: INITIAL CONTRIBUTOR AND DESIGNATED WEB SITE The Initial Contributor is: ____________________________________________________ - + [Enter full name of Initial Contributor] Address of Initial Contributor: ________________________________________________ - + ________________________________________________ - + ________________________________________________ - + [Enter address above] The Designated Web Site is: __________________________________________________ - + [Enter URL for Designated Web Site of Initial Contributor] NOTE: The Initial Contributor is to complete this Part 1, along with Parts 2, 3, and 5, and, if applicable, Parts 4 and 6. @@ -237,27 +237,27 @@ The date on which the Initial Work was first available under this License: _____ PART 3: GOVERNING JURISDICTION -For the purposes of this License, the Governing Jurisdiction is _________________________________________________. [Initial Contributor to Enter Governing Jurisdiction here] +For the purposes of this License, the Governing Jurisdiction is _________________________________________________. [Initial Contributor to Enter Governing Jurisdiction here] PART 4: THIRD PARTIES For the purposes of this License, "Third Party" has the definition set forth below in the ONE paragraph selected by the Initial Contributor from paragraphs A, B, C, D and E when the Initial Work is distributed or otherwise made available by the Initial Contributor. To select one of the following paragraphs, the Initial Contributor must place an "X" or "x" in the selection box alongside the one respective paragraph selected. SELECTION - + BOX PARAGRAPH -[ ] A. "THIRD PARTY" means any third party. - - -[ ] B. "THIRD PARTY" means any third party except for any of the following: (a) a wholly owned subsidiary of the Subsequent Contributor in question; (b) a legal entity (the "PARENT") that wholly owns the Subsequent Contributor in question; or (c) a wholly owned subsidiary of the wholly owned subsidiary in (a) or of the Parent in (b). - - -[ ] C. "THIRD PARTY" means any third party except for any of the following: (a) any Person directly or indirectly owning a majority of the voting interest in the Subsequent Contributor or (b) any Person in which the Subsequent Contributor directly or indirectly owns a majority voting interest. - - -[ ] D. "THIRD PARTY" means any third party except for any Person directly or indirectly controlled by the Subsequent Contributor. For purposes of this definition, "control" shall mean the power to direct or cause the direction of, the management and policies of such Person whether through the ownership of voting interests, by contract, or otherwise. - - -[ ] E. "THIRD PARTY" means any third party except for any Person directly or indirectly controlling, controlled by, or under common control with the Subsequent Contributor. For purposes of this definition, "control" shall mean the power to direct or cause the direction of, the management and policies of such Person whether through the ownership of voting interests, by contract, or otherwise. +[ ] A. "THIRD PARTY" means any third party. + + +[ ] B. "THIRD PARTY" means any third party except for any of the following: (a) a wholly owned subsidiary of the Subsequent Contributor in question; (b) a legal entity (the "PARENT") that wholly owns the Subsequent Contributor in question; or (c) a wholly owned subsidiary of the wholly owned subsidiary in (a) or of the Parent in (b). + + +[ ] C. "THIRD PARTY" means any third party except for any of the following: (a) any Person directly or indirectly owning a majority of the voting interest in the Subsequent Contributor or (b) any Person in which the Subsequent Contributor directly or indirectly owns a majority voting interest. + + +[ ] D. "THIRD PARTY" means any third party except for any Person directly or indirectly controlled by the Subsequent Contributor. For purposes of this definition, "control" shall mean the power to direct or cause the direction of, the management and policies of such Person whether through the ownership of voting interests, by contract, or otherwise. + + +[ ] E. "THIRD PARTY" means any third party except for any Person directly or indirectly controlling, controlled by, or under common control with the Subsequent Contributor. For purposes of this definition, "control" shall mean the power to direct or cause the direction of, the management and policies of such Person whether through the ownership of voting interests, by contract, or otherwise. The default definition of "THIRD PARTY" is the definition set forth in paragraph A, if NONE OR MORE THAN ONE of paragraphs A, B, C, D or E in this Part 4 are selected by the Initial Contributor. PART 5: NOTICE @@ -271,8 +271,8 @@ PART 6: PATENT LICENSING TERMS For the purposes of this License, paragraphs A, B, C, D and E of this Part 6 of Exhibit A are only incorporated and form part of the terms of the License if the Initial Contributor places an "X" or "x" in the selection box alongside the YES answer to the question immediately below. Is this a Patents-Included License pursuant to Section 2.2 of the License? -YES [ ] -NO [ ] +YES [ ] +NO [ ] By default, if YES is not selected by the Initial Contributor, the answer is NO. diff --git a/options/license/IBM-pibs b/options/license/IBM-pibs index 49454b8b1e..ee9c7be36d 100644 --- a/options/license/IBM-pibs +++ b/options/license/IBM-pibs @@ -4,5 +4,5 @@ Any user of this software should understand that IBM cannot provide technical su Any person who transfers this source code or any derivative work must include the IBM copyright notice, this paragraph, and the preceding two paragraphs in the transferred software. -COPYRIGHT I B M CORPORATION 2002 -LICENSED MATERIAL - PROGRAM PROPERTY OF I B M +COPYRIGHT I B M CORPORATION 2002 +LICENSED MATERIAL - PROGRAM PROPERTY OF I B M diff --git a/options/license/NCGL-UK-2.0 b/options/license/NCGL-UK-2.0 index 31fbad6f83..15c4f63c22 100644 --- a/options/license/NCGL-UK-2.0 +++ b/options/license/NCGL-UK-2.0 @@ -12,15 +12,15 @@ The Licensor grants you a worldwide, royalty-free, perpetual, non-exclusive lice This licence does not affect your freedom under fair dealing or fair use or any other copyright or database right exceptions and limitations. You are free to: - copy, publish, distribute and transmit the Information; + copy, publish, distribute and transmit the Information; adapt the Information; exploit the Information for Non-Commercial purposes for example, by combining it with other information in your own product or application. You are not permitted to: - exercise any of the rights granted to you by this licence in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation. + exercise any of the rights granted to you by this licence in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation. You must, where you do any of the above: - acknowledge the source of the Information by including any attribution statement specified by the Information Provider(s) and, where possible, provide a link to this licence; + acknowledge the source of the Information by including any attribution statement specified by the Information Provider(s) and, where possible, provide a link to this licence; If the Information Provider does not provide a specific attribution statement, you must use the following: Contains information licensed under the Non-Commercial Government Licence v2.0. diff --git a/options/license/NPL-1.1 b/options/license/NPL-1.1 index 62c5296400..0d5457ff04 100644 --- a/options/license/NPL-1.1 +++ b/options/license/NPL-1.1 @@ -2,7 +2,7 @@ Netscape Public LIcense version 1.1 AMENDMENTS -The Netscape Public License Version 1.1 ("NPL") consists of the Mozilla Public License Version 1.1 with the following Amendments, including Exhibit A-Netscape Public License. Files identified with "Exhibit A-Netscape Public License" are governed by the Netscape Public License Version 1.1. +The Netscape Public License Version 1.1 ("NPL") consists of the Mozilla Public License Version 1.1 with the following Amendments, including Exhibit A-Netscape Public License. Files identified with "Exhibit A-Netscape Public License" are governed by the Netscape Public License Version 1.1. Additional Terms applicable to the Netscape Public License. @@ -28,7 +28,7 @@ Additional Terms applicable to the Netscape Public License. Notwithstanding the limitations of Section 11 above, the provisions regarding litigation in Section 11(a), (b) and (c) of the License shall apply to all disputes relating to this License. EXHIBIT A-Netscape Public License. - + "The contents of this file are subject to the Netscape Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/NPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. @@ -37,8 +37,8 @@ The Original Code is Mozilla Communicator client code, released March 31, 1998. The Initial Developer of the Original Code is Netscape Communications Corporation. Portions created by Netscape are Copyright (C) 1998-1999 Netscape Communications Corporation. All Rights Reserved. Contributor(s): ______________________________________. - -Alternatively, the contents of this file may be used under the terms of the _____ license (the "[___] License"), in which case the provisions of [______] License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the [____] License and not to allow others to use your version of this file under the NPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the [___] License. If you do not delete the provisions above, a recipient may use your version of this file under either the NPL or the [___] License." + +Alternatively, the contents of this file may be used under the terms of the _____ license (the "[___] License"), in which case the provisions of [______] License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the [____] License and not to allow others to use your version of this file under the NPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the [___] License. If you do not delete the provisions above, a recipient may use your version of this file under either the NPL or the [___] License." Mozilla Public License Version 1.1 diff --git a/options/license/OCCT-PL b/options/license/OCCT-PL index 85df3c73c5..9b6fccc1c9 100644 --- a/options/license/OCCT-PL +++ b/options/license/OCCT-PL @@ -6,7 +6,7 @@ OPEN CASCADE releases and makes publicly available the source code of the softwa It is not the purpose of this license to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this license has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. Please read this license carefully and completely before downloading this software. By downloading, using, modifying, distributing and sublicensing this software, you indicate your acceptance to be bound by the terms and conditions of this license. If you do not want to accept or cannot accept for any reasons the terms and conditions of this license, please do not download or use in any manner this software. - + 1. Definitions Unless there is something in the subject matter or in the context inconsistent therewith, the capitalized terms used in this License shall have the following meaning. @@ -26,13 +26,13 @@ Unless there is something in the subject matter or in the context inconsistent t "Software": means the Original Code, the Modifications, the combination of Original Code and any Modifications or any respective portions thereof. "You" or "Your": means an individual or a legal entity exercising rights under this License - + 2. Acceptance of license By using, reproducing, modifying, distributing or sublicensing the Software or any portion thereof, You expressly indicate Your acceptance of the terms and conditions of this License and undertake to act in accordance with all the provisions of this License applicable to You. - + 3. Scope and purpose This License applies to the Software and You may not use, reproduce, modify, distribute, sublicense or circulate the Software, or any portion thereof, except as expressly provided under this License. Any attempt to otherwise use, reproduce, modify, distribute or sublicense the Software is void and will automatically terminate Your rights under this License. - + 4. Contributor license Subject to the terms and conditions of this License, the Initial Developer and each of the Contributors hereby grant You a world-wide, royalty-free, irrevocable and non-exclusive license under the Applicable Intellectual Property Rights they own or control, to use, reproduce, modify, distribute and sublicense the Software provided that: diff --git a/options/license/OGL-UK-1.0 b/options/license/OGL-UK-1.0 index a761c9916f..867c0e353b 100644 --- a/options/license/OGL-UK-1.0 +++ b/options/license/OGL-UK-1.0 @@ -10,20 +10,20 @@ The Licensor grants you a worldwide, royalty-free, perpetual, non-exclusive lice This licence does not affect your freedom under fair dealing or fair use or any other copyright or database right exceptions and limitations. You are free to: - copy, publish, distribute and transmit the Information; + copy, publish, distribute and transmit the Information; adapt the Information; exploit the Information commercially for example, by combining it with other Information, or by including it in your own product or application. You must, where you do any of the above: - acknowledge the source of the Information by including any attribution statement specified by the Information Provider(s) and, where possible, provide a link to this licence; - If the Information Provider does not provide a specific attribution statement, or if you are using Information from several Information Providers and multiple attributions are not practical in your product or application, you may consider using the following: Contains public sector information licensed under the Open Government Licence v1.0. + acknowledge the source of the Information by including any attribution statement specified by the Information Provider(s) and, where possible, provide a link to this licence; + If the Information Provider does not provide a specific attribution statement, or if you are using Information from several Information Providers and multiple attributions are not practical in your product or application, you may consider using the following: Contains public sector information licensed under the Open Government Licence v1.0. ensure that you do not use the Information in a way that suggests any official status or that the Information Provider endorses you or your use of the Information; ensure that you do not mislead others or misrepresent the Information or its source; ensure that your use of the Information does not breach the Data Protection Act 1998 or the Privacy and Electronic Communications (EC Directive) Regulations 2003. These are important conditions of this licence and if you fail to comply with them the rights granted to you under this licence, or any similar licence granted by the Licensor, will end automatically. - Exemptions + Exemptions This licence does not cover the use of: - personal data in the Information; @@ -48,22 +48,22 @@ Definitions In this licence, the terms below have the following meanings: -‘Information’ means information protected by copyright or by database right (for example, literary and artistic works, content, data and source code) offered for use under the terms of this licence. +‘Information’ means information protected by copyright or by database right (for example, literary and artistic works, content, data and source code) offered for use under the terms of this licence. -‘Information Provider’ means the person or organisation providing the Information under this licence. +‘Information Provider’ means the person or organisation providing the Information under this licence. -‘Licensor’ means any Information Provider which has the authority to offer Information under the terms of this licence or the Controller of Her Majesty’s Stationery Office, who has the authority to offer Information subject to Crown copyright and Crown database rights and Information subject to copyright and database right that has been assigned to or acquired by the Crown, under the terms of this licence. +‘Licensor’ means any Information Provider which has the authority to offer Information under the terms of this licence or the Controller of Her Majesty’s Stationery Office, who has the authority to offer Information subject to Crown copyright and Crown database rights and Information subject to copyright and database right that has been assigned to or acquired by the Crown, under the terms of this licence. -‘Use’ as a verb, means doing any act which is restricted by copyright or database right, whether in the original medium or in any other medium, and includes without limitation distributing, copying, adapting, modifying as may be technically necessary to use it in a different mode or format. +‘Use’ as a verb, means doing any act which is restricted by copyright or database right, whether in the original medium or in any other medium, and includes without limitation distributing, copying, adapting, modifying as may be technically necessary to use it in a different mode or format. -‘You’ means the natural or legal person, or body of persons corporate or incorporate, acquiring rights under this licence. +‘You’ means the natural or legal person, or body of persons corporate or incorporate, acquiring rights under this licence. About the Open Government Licence The Controller of Her Majesty’s Stationery Office (HMSO) has developed this licence as a tool to enable Information Providers in the public sector to license the use and re-use of their Information under a common open licence. The Controller invites public sector bodies owning their own copyright and database rights to permit the use of their Information under this licence. -The Controller of HMSO has authority to license Information subject to copyright and database right owned by the Crown. The extent of the Controller’s offer to license this Information under the terms of this licence is set out in the UK Government Licensing Framework. +The Controller of HMSO has authority to license Information subject to copyright and database right owned by the Crown. The extent of the Controller’s offer to license this Information under the terms of this licence is set out in the UK Government Licensing Framework. This is version 1.0 of the Open Government Licence. The Controller of HMSO may, from time to time, issue new versions of the Open Government Licence. However, you may continue to use Information licensed under this version should you wish to do so. These terms have been aligned to be interoperable with any Creative Commons Attribution Licence, which covers copyright, and Open Data Commons Attribution License, which covers database rights and applicable copyrights. -Further context, best practice and guidance can be found in the UK Government Licensing Framework section on The National Archives website. +Further context, best practice and guidance can be found in the UK Government Licensing Framework section on The National Archives website. diff --git a/options/license/OSET-PL-2.1 b/options/license/OSET-PL-2.1 index 15f0c7758c..e0ed2e1398 100644 --- a/options/license/OSET-PL-2.1 +++ b/options/license/OSET-PL-2.1 @@ -100,7 +100,8 @@ If it is impossible for You to comply with any of the terms of this License with 5.1 Failure to Comply The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60-days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30-days after Your receipt of the notice. - 5.2 Patent Infringement Claims If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. + 5.2 Patent Infringement Claims + If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3 Additional Compliance Terms Notwithstanding the foregoing in this Section 5, for purposes of this Section, if You breach Section 3.1 (Distribution of Source Form), Section 3.2 (Distribution of Executable Form), Section 3.3 (Distribution of a Larger Work), or Section 3.4 (Notices), then becoming compliant as described in Section 5.1 must also include, no later than 30 days after receipt by You of notice of such violation by a Contributor, making the Covered Software available in Source Code Form as required by this License on a publicly available computer network for a period of no less than three (3) years. diff --git a/options/license/SHL-2.0 b/options/license/SHL-2.0 index e522a396fe..9218b47a72 100644 --- a/options/license/SHL-2.0 +++ b/options/license/SHL-2.0 @@ -1,22 +1,22 @@ # Solderpad Hardware Licence Version 2.0 -This licence (the “Licence”) operates as a wraparound licence to the Apache License Version 2.0 (the “Apache License”) and grants to You the rights, and imposes the obligations, set out in the Apache License (which can be found here: http://apache.org/licenses/LICENSE-2.0), with the following extensions. It must be read in conjunction with the Apache License. Section 1 below modifies definitions in the Apache License, and section 2 below replaces sections 2 of the Apache License. You may, at your option, choose to treat any Work released under this License as released under the Apache License (thus ignoring all sections written below entirely). Words in italics indicate changes rom the Apache License, but are indicative and not to be taken into account in interpretation. +This licence (the “Licence”) operates as a wraparound licence to the Apache License Version 2.0 (the “Apache License”) and grants to You the rights, and imposes the obligations, set out in the Apache License (which can be found here: http://apache.org/licenses/LICENSE-2.0), with the following extensions. It must be read in conjunction with the Apache License. Section 1 below modifies definitions in the Apache License, and section 2 below replaces sections 2 of the Apache License. You may, at your option, choose to treat any Work released under this License as released under the Apache License (thus ignoring all sections written below entirely). Words in italics indicate changes rom the Apache License, but are indicative and not to be taken into account in interpretation. 1. The definitions set out in the Apache License are modified as follows: -Copyright any reference to ‘copyright’ (whether capitalised or not) includes ‘Rights’ (as defined below). +Copyright any reference to ‘copyright’ (whether capitalised or not) includes ‘Rights’ (as defined below). -Contribution also includes any design, as well as any work of authorship. +Contribution also includes any design, as well as any work of authorship. -Derivative Works shall not include works that remain reversibly separable from, or merely link (or bind by name) or physically connect to or interoperate with the interfaces of the Work and Derivative Works thereof. +Derivative Works shall not include works that remain reversibly separable from, or merely link (or bind by name) or physically connect to or interoperate with the interfaces of the Work and Derivative Works thereof. -Object form shall mean any form resulting from mechanical transformation or translation of a Source form or the application of a Source form to physical material, including but not limited to compiled object code, generated documentation, the instantiation of a hardware design or physical object and conversions to other media types, including intermediate forms such as bytecodes, FPGA bitstreams, moulds, artwork and semiconductor topographies (mask works). +Object form shall mean any form resulting from mechanical transformation or translation of a Source form or the application of a Source form to physical material, including but not limited to compiled object code, generated documentation, the instantiation of a hardware design or physical object and conversions to other media types, including intermediate forms such as bytecodes, FPGA bitstreams, moulds, artwork and semiconductor topographies (mask works). -Rights means copyright and any similar right including design right (whether registered or unregistered), semiconductor topography (mask) rights and database rights (but excluding Patents and Trademarks). +Rights means copyright and any similar right including design right (whether registered or unregistered), semiconductor topography (mask) rights and database rights (but excluding Patents and Trademarks). -Source form shall mean the preferred form for making modifications, including but not limited to source code, net lists, board layouts, CAD files, documentation source, and configuration files. -Work also includes a design or work of authorship, whether in Source form or other Object form. +Source form shall mean the preferred form for making modifications, including but not limited to source code, net lists, board layouts, CAD files, documentation source, and configuration files. +Work also includes a design or work of authorship, whether in Source form or other Object form. 2. Grant of Licence -2.1 Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license under the Rights to reproduce, prepare Derivative Works of, make, adapt, repair, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form and do anything in relation to the Work as if the Rights did not exist. +2.1 Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license under the Rights to reproduce, prepare Derivative Works of, make, adapt, repair, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form and do anything in relation to the Work as if the Rights did not exist. diff --git a/options/license/SHL-2.1 b/options/license/SHL-2.1 index 4815a9e5ed..c9ae53741f 100644 --- a/options/license/SHL-2.1 +++ b/options/license/SHL-2.1 @@ -19,7 +19,7 @@ The following definitions shall replace the corresponding definitions in the Apa "License" shall mean this Solderpad Hardware License version 2.1, being the terms and conditions for use, manufacture, instantiation, adaptation, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the Rights owner or entity authorized by the Rights owner that is granting the License. - + "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship or design. For the purposes of this License, Derivative Works shall not include works that remain reversibly separable from, or merely link (or bind by name) or physically connect to or interoperate with the Work and Derivative Works thereof. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form or the application of a Source form to physical material, including but not limited to compiled object code, generated documentation, the instantiation of a hardware design or physical object or material and conversions to other media types, including intermediate forms such as bytecodes, FPGA bitstreams, moulds, artwork and semiconductor topographies (mask works). diff --git a/options/license/SISSL b/options/license/SISSL index 7d6ad9d66c..af38d02d92 100644 --- a/options/license/SISSL +++ b/options/license/SISSL @@ -36,13 +36,13 @@ Sun Industry Standards Source License - Version 1.1 2.0 SOURCE CODE LICENSE - 2.1 The Initial Developer Grant The Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims: + 2.1 The Initial Developer Grant The Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims: (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer to use, reproduce, modify, display, perform, sublicense and distribute the Original Code (or portions thereof) with or without Modifications, and/or as part of a Larger Work; and (b) under Patents Claims infringed by the making, using or selling of Original Code, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Code (or portions thereof). (c) the licenses granted in this Section 2.1(a) and (b) are effective on the date Initial Developer first distributes Original Code under the terms of this License. - (d) Notwithstanding Section 2.1(b) above, no patent license is granted: 1) for code that You delete from the Original Code; 2) separate from the Original Code; or 3) for infringements caused by: i) the modification of the Original Code or ii) the combination of the Original Code with other software or devices, including but not limited to Modifications. + (d) Notwithstanding Section 2.1(b) above, no patent license is granted: 1) for code that You delete from the Original Code; 2) separate from the Original Code; or 3) for infringements caused by: i) the modification of the Original Code or ii) the combination of the Original Code with other software or devices, including but not limited to Modifications. 3.0 DISTRIBUTION OBLIGATIONS @@ -92,14 +92,14 @@ This License represents the complete agreement concerning subject matter hereof. EXHIBIT A - Sun Standards License -"The contents of this file are subject to the Sun Standards License Version 1.1 (the "License"); You may not use this file except in compliance with the License. You may obtain a copy of the License at _______________________________. +"The contents of this file are subject to the Sun Standards License Version 1.1 (the "License"); You may not use this file except in compliance with the License. You may obtain a copy of the License at _______________________________. -Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either +Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is ______________________________________. -The Initial Developer of the Original Code is: +The Initial Developer of the Original Code is: Sun Microsystems, Inc.. Portions created by: _______________________________________ diff --git a/options/license/W3C-19980720 b/options/license/W3C-19980720 index a8554039ef..134879044d 100644 --- a/options/license/W3C-19980720 +++ b/options/license/W3C-19980720 @@ -4,7 +4,7 @@ Copyright (c) 1994-2002 World Wide Web Consortium, (Massachusetts Institute of T This W3C work (including software, documents, or other related items) is being provided by the copyright holders under the following license. By obtaining, using and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions: -Permission to use, copy, modify, and distribute this software and its documentation, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the software and documentation or portions thereof, including modifications, that you make: +Permission to use, copy, modify, and distribute this software and its documentation, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the software and documentation or portions thereof, including modifications, that you make: 1. The full text of this NOTICE in a location viewable to users of the redistributed or derivative work. From 074a3e05f665ad8c635a314f49080f8846e6d315 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Mon, 8 Apr 2024 12:13:34 +0800 Subject: [PATCH 061/370] Fix oauth2 builtin application logic (#30304) Fix #29074 (allow to disable all builtin apps) and don't make the doctor command remove the builtin apps. By the way, rename refobject and joincond to camel case. --- models/db/consistency.go | 12 +++---- modules/setting/oauth2.go | 4 +++ modules/setting/oauth2_test.go | 18 ++++++++++ services/doctor/dbconsistency.go | 25 +++++++------ services/doctor/dbconsistency_test.go | 51 +++++++++++++++++++++++++++ services/doctor/main_test.go | 14 ++++++++ 6 files changed, 107 insertions(+), 17 deletions(-) create mode 100644 services/doctor/dbconsistency_test.go create mode 100644 services/doctor/main_test.go diff --git a/models/db/consistency.go b/models/db/consistency.go index d19732cf80..d0b0ab8315 100644 --- a/models/db/consistency.go +++ b/models/db/consistency.go @@ -10,21 +10,21 @@ import ( ) // CountOrphanedObjects count subjects with have no existing refobject anymore -func CountOrphanedObjects(ctx context.Context, subject, refobject, joinCond string) (int64, error) { +func CountOrphanedObjects(ctx context.Context, subject, refObject, joinCond string) (int64, error) { return GetEngine(ctx). Table("`"+subject+"`"). - Join("LEFT", "`"+refobject+"`", joinCond). - Where(builder.IsNull{"`" + refobject + "`.id"}). + Join("LEFT", "`"+refObject+"`", joinCond). + Where(builder.IsNull{"`" + refObject + "`.id"}). Select("COUNT(`" + subject + "`.`id`)"). Count() } // DeleteOrphanedObjects delete subjects with have no existing refobject anymore -func DeleteOrphanedObjects(ctx context.Context, subject, refobject, joinCond string) error { +func DeleteOrphanedObjects(ctx context.Context, subject, refObject, joinCond string) error { subQuery := builder.Select("`"+subject+"`.id"). From("`"+subject+"`"). - Join("LEFT", "`"+refobject+"`", joinCond). - Where(builder.IsNull{"`" + refobject + "`.id"}) + Join("LEFT", "`"+refObject+"`", joinCond). + Where(builder.IsNull{"`" + refObject + "`.id"}) b := builder.Delete(builder.In("id", subQuery)).From("`" + subject + "`") _, err := GetEngine(ctx).Exec(b) return err diff --git a/modules/setting/oauth2.go b/modules/setting/oauth2.go index 1429a7585c..830472db32 100644 --- a/modules/setting/oauth2.go +++ b/modules/setting/oauth2.go @@ -118,6 +118,10 @@ func loadOAuth2From(rootCfg ConfigProvider) { return } + if sec.HasKey("DEFAULT_APPLICATIONS") && sec.Key("DEFAULT_APPLICATIONS").String() == "" { + OAuth2.DefaultApplications = nil + } + // Handle the rename of ENABLE to ENABLED deprecatedSetting(rootCfg, "oauth2", "ENABLE", "oauth2", "ENABLED", "v1.23.0") if sec.HasKey("ENABLE") && !sec.HasKey("ENABLED") { diff --git a/modules/setting/oauth2_test.go b/modules/setting/oauth2_test.go index d822198619..4403f35892 100644 --- a/modules/setting/oauth2_test.go +++ b/modules/setting/oauth2_test.go @@ -32,3 +32,21 @@ JWT_SECRET = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB assert.Len(t, actual, 32) assert.EqualValues(t, expected, actual) } + +func TestOauth2DefaultApplications(t *testing.T) { + cfg, _ := NewConfigProviderFromData(``) + loadOAuth2From(cfg) + assert.Equal(t, []string{"git-credential-oauth", "git-credential-manager", "tea"}, OAuth2.DefaultApplications) + + cfg, _ = NewConfigProviderFromData(`[oauth2] +DEFAULT_APPLICATIONS = tea +`) + loadOAuth2From(cfg) + assert.Equal(t, []string{"tea"}, OAuth2.DefaultApplications) + + cfg, _ = NewConfigProviderFromData(`[oauth2] +DEFAULT_APPLICATIONS = +`) + loadOAuth2From(cfg) + assert.Nil(t, nil, OAuth2.DefaultApplications) +} diff --git a/services/doctor/dbconsistency.go b/services/doctor/dbconsistency.go index e2dcb63f33..dfdf7b547a 100644 --- a/services/doctor/dbconsistency.go +++ b/services/doctor/dbconsistency.go @@ -61,26 +61,20 @@ func asFixer(fn func(ctx context.Context) error) func(ctx context.Context) (int6 } } -func genericOrphanCheck(name, subject, refobject, joincond string) consistencyCheck { +func genericOrphanCheck(name, subject, refObject, joinCond string) consistencyCheck { return consistencyCheck{ Name: name, Counter: func(ctx context.Context) (int64, error) { - return db.CountOrphanedObjects(ctx, subject, refobject, joincond) + return db.CountOrphanedObjects(ctx, subject, refObject, joinCond) }, Fixer: func(ctx context.Context) (int64, error) { - err := db.DeleteOrphanedObjects(ctx, subject, refobject, joincond) + err := db.DeleteOrphanedObjects(ctx, subject, refObject, joinCond) return -1, err }, } } -func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) error { - // make sure DB version is uptodate - if err := db.InitEngineWithMigration(ctx, migrations.EnsureUpToDate); err != nil { - logger.Critical("Model version on the database does not match the current Gitea version. Model consistency will not be checked until the database is upgraded") - return err - } - +func prepareDBConsistencyChecks() []consistencyCheck { consistencyChecks := []consistencyCheck{ { // find labels without existing repo or org @@ -210,7 +204,7 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er "oauth2_grant", "user", "oauth2_grant.user_id=`user`.id"), // find OAuth2Application without existing user genericOrphanCheck("Orphaned OAuth2Application without existing User", - "oauth2_application", "user", "oauth2_application.uid=`user`.id"), + "oauth2_application", "user", "oauth2_application.uid=0 OR oauth2_application.uid=`user`.id"), // find OAuth2AuthorizationCode without existing OAuth2Grant genericOrphanCheck("Orphaned OAuth2AuthorizationCode without existing OAuth2Grant", "oauth2_authorization_code", "oauth2_grant", "oauth2_authorization_code.grant_id=oauth2_grant.id"), @@ -224,7 +218,16 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er genericOrphanCheck("Orphaned Redirects without existing redirect user", "user_redirect", "user", "user_redirect.redirect_user_id=`user`.id"), ) + return consistencyChecks +} +func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) error { + // make sure DB version is uptodate + if err := db.InitEngineWithMigration(ctx, migrations.EnsureUpToDate); err != nil { + logger.Critical("Model version on the database does not match the current Gitea version. Model consistency will not be checked until the database is upgraded") + return err + } + consistencyChecks := prepareDBConsistencyChecks() for _, c := range consistencyChecks { if err := c.Run(ctx, logger, autofix); err != nil { return err diff --git a/services/doctor/dbconsistency_test.go b/services/doctor/dbconsistency_test.go new file mode 100644 index 0000000000..4e4ac535b7 --- /dev/null +++ b/services/doctor/dbconsistency_test.go @@ -0,0 +1,51 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package doctor + +import ( + "slices" + "testing" + + "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/log" + + "github.com/stretchr/testify/assert" +) + +func TestConsistencyCheck(t *testing.T) { + checks := prepareDBConsistencyChecks() + idx := slices.IndexFunc(checks, func(check consistencyCheck) bool { + return check.Name == "Orphaned OAuth2Application without existing User" + }) + if !assert.NotEqual(t, -1, idx) { + return + } + + _ = db.TruncateBeans(db.DefaultContext, &auth.OAuth2Application{}, &user.User{}) + _ = db.TruncateBeans(db.DefaultContext, &auth.OAuth2Application{}, &auth.OAuth2Application{}) + + err := db.Insert(db.DefaultContext, &user.User{ID: 1}) + assert.NoError(t, err) + err = db.Insert(db.DefaultContext, &auth.OAuth2Application{Name: "test-oauth2-app-1", ClientID: "client-id-1"}) + assert.NoError(t, err) + err = db.Insert(db.DefaultContext, &auth.OAuth2Application{Name: "test-oauth2-app-2", ClientID: "client-id-2", UID: 1}) + assert.NoError(t, err) + err = db.Insert(db.DefaultContext, &auth.OAuth2Application{Name: "test-oauth2-app-3", ClientID: "client-id-3", UID: 99999999}) + assert.NoError(t, err) + + unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{ClientID: "client-id-1"}) + unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{ClientID: "client-id-2"}) + unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{ClientID: "client-id-3"}) + + oauth2AppCheck := checks[idx] + err = oauth2AppCheck.Run(db.DefaultContext, log.GetManager().GetLogger(log.DEFAULT), true) + assert.NoError(t, err) + + unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{ClientID: "client-id-1"}) + unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{ClientID: "client-id-2"}) + unittest.AssertNotExistsBean(t, &auth.OAuth2Application{ClientID: "client-id-3"}) +} diff --git a/services/doctor/main_test.go b/services/doctor/main_test.go new file mode 100644 index 0000000000..0f365e21d0 --- /dev/null +++ b/services/doctor/main_test.go @@ -0,0 +1,14 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package doctor + +import ( + "testing" + + "code.gitea.io/gitea/models/unittest" +) + +func TestMain(m *testing.M) { + unittest.MainTest(m) +} From 7d66b9ea65cc416046ec7075bc327932a4f2094f Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 8 Apr 2024 20:43:23 +0900 Subject: [PATCH 062/370] Avoid showing `Failed to change the default wiki branch` if repo has no wiki when saving repo settings (#30329) --- routers/web/repo/wiki_test.go | 6 ++++++ services/wiki/wiki.go | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/routers/web/repo/wiki_test.go b/routers/web/repo/wiki_test.go index 8b5207f9d9..2894c06fbd 100644 --- a/routers/web/repo/wiki_test.go +++ b/routers/web/repo/wiki_test.go @@ -226,6 +226,12 @@ func TestWikiRaw(t *testing.T) { func TestDefaultWikiBranch(t *testing.T) { unittest.PrepareTestEnv(t) + // repo with no wiki + repoWithNoWiki := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) + assert.False(t, repoWithNoWiki.HasWiki()) + assert.NoError(t, wiki_service.ChangeDefaultWikiBranch(db.DefaultContext, repoWithNoWiki, "main")) + + // repo with wiki assert.NoError(t, repo_model.UpdateRepositoryCols(db.DefaultContext, &repo_model.Repository{ID: 1, DefaultWikiBranch: "wrong-branch"})) ctx, _ := contexttest.MockContext(t, "user2/repo1/wiki") diff --git a/services/wiki/wiki.go b/services/wiki/wiki.go index f8387416c1..fdcc5feefa 100644 --- a/services/wiki/wiki.go +++ b/services/wiki/wiki.go @@ -370,6 +370,10 @@ func ChangeDefaultWikiBranch(ctx context.Context, repo *repo_model.Repository, n return fmt.Errorf("unable to update database: %w", err) } + if !repo.HasWiki() { + return nil + } + oldDefBranch, err := gitrepo.GetWikiDefaultBranch(ctx, repo) if err != nil { return fmt.Errorf("unable to get default branch: %w", err) From d872ce006c0400edb10a05f7555f9b08070442e3 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 8 Apr 2024 23:08:26 +0900 Subject: [PATCH 063/370] Avoid running action when action unit is disabled after workflows detected (#30331) Fix #30243 We only checking unit disabled when detecting workflows, but not in runner `FetchTask`. So if a workflow was detected when action unit is enabled, but disabled later, `FetchTask` will still return these detected actions. Global setting: repo.ENABLED and repository.`DISABLED_REPO_UNITS` will not effect this. --- models/actions/task.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/models/actions/task.go b/models/actions/task.go index 96a6d2e80c..1e279659c7 100644 --- a/models/actions/task.go +++ b/models/actions/task.go @@ -11,6 +11,7 @@ import ( auth_model "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" @@ -227,7 +228,9 @@ func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask if runner.RepoID != 0 { jobCond = builder.Eq{"repo_id": runner.RepoID} } else if runner.OwnerID != 0 { - jobCond = builder.In("repo_id", builder.Select("id").From("repository").Where(builder.Eq{"owner_id": runner.OwnerID})) + jobCond = builder.In("repo_id", builder.Select("id").From("repository"). + Join("INNER", "repo_unit", "`repository`.id = `repo_unit`.repo_id"). + Where(builder.Eq{"`repository`.owner_id": runner.OwnerID, "`repo_unit`.type": unit.TypeActions})) } if jobCond.IsValid() { jobCond = builder.In("run_id", builder.Select("id").From("action_run").Where(jobCond)) From ff7aab44032cbb22cb6696a1939d1f619621f067 Mon Sep 17 00:00:00 2001 From: Michael Kriese <michael.kriese@visualon.de> Date: Mon, 8 Apr 2024 22:59:09 +0200 Subject: [PATCH 064/370] Add optional doctor storage init (#30330) Add optional storage init to doctor --- services/doctor/doctor.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/services/doctor/doctor.go b/services/doctor/doctor.go index 559f8e06da..a4eb5e16b9 100644 --- a/services/doctor/doctor.go +++ b/services/doctor/doctor.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/storage" ) // Check represents a Doctor check @@ -25,6 +26,7 @@ type Check struct { AbortIfFailed bool SkipDatabaseInitialization bool Priority int + InitStorage bool } func initDBSkipLogger(ctx context.Context) error { @@ -84,6 +86,7 @@ func RunChecks(ctx context.Context, colorize, autofix bool, checks []*Check) err logger := log.BaseLoggerToGeneralLogger(&doctorCheckLogger{colorize: colorize}) loggerStep := log.BaseLoggerToGeneralLogger(&doctorCheckStepLogger{colorize: colorize}) dbIsInit := false + storageIsInit := false for i, check := range checks { if !dbIsInit && !check.SkipDatabaseInitialization { // Only open database after the most basic configuration check @@ -94,6 +97,14 @@ func RunChecks(ctx context.Context, colorize, autofix bool, checks []*Check) err } dbIsInit = true } + if !storageIsInit && check.InitStorage { + if err := storage.Init(); err != nil { + logger.Error("Error whilst initializing the storage: %v", err) + logger.Error("Check if you are using the right config file. You can use a --config directive to specify one.") + return nil + } + storageIsInit = true + } logger.Info("\n[%d] %s", i+1, check.Title) if err := check.Run(ctx, loggerStep, autofix); err != nil { if check.AbortIfFailed { From 908426aa0fcc58961c345994f0f66056f6cf5f48 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Tue, 9 Apr 2024 05:26:41 +0800 Subject: [PATCH 065/370] Fix missed doer (#30231) Fix #29879 Co-authored-by: Giteabot <teabot@gitea.io> --- routers/api/v1/repo/issue.go | 10 ++++---- routers/api/v1/repo/issue_attachment.go | 2 +- routers/api/v1/repo/issue_dependency.go | 12 +++++----- routers/api/v1/repo/issue_pin.go | 2 +- routers/api/v1/repo/issue_tracked_time.go | 10 ++++---- routers/web/repo/issue.go | 6 ++--- services/actions/notifier.go | 10 ++++---- services/convert/issue.go | 28 +++++++++++------------ services/convert/issue_comment.go | 6 ++--- services/convert/pull.go | 2 +- services/webhook/notifier.go | 22 +++++++++--------- 11 files changed, 55 insertions(+), 55 deletions(-) diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index 6934b34b24..5e173abf88 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -311,7 +311,7 @@ func SearchIssues(ctx *context.APIContext) { ctx.SetLinkHeader(int(total), limit) ctx.SetTotalCountHeader(total) - ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues)) + ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, ctx.Doer, issues)) } // ListIssues list the issues of a repository @@ -548,7 +548,7 @@ func ListIssues(ctx *context.APIContext) { ctx.SetLinkHeader(int(total), listOptions.PageSize) ctx.SetTotalCountHeader(total) - ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues)) + ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, ctx.Doer, issues)) } func getUserIDForFilter(ctx *context.APIContext, queryName string) int64 { @@ -614,7 +614,7 @@ func GetIssue(ctx *context.APIContext) { ctx.NotFound() return } - ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, issue)) + ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, ctx.Doer, issue)) } // CreateIssue create an issue of a repository @@ -737,7 +737,7 @@ func CreateIssue(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "GetIssueByID", err) return } - ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, issue)) + ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, issue)) } // EditIssue modify an issue of a repository @@ -911,7 +911,7 @@ func EditIssue(ctx *context.APIContext) { ctx.InternalServerError(err) return } - ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, issue)) + ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, issue)) } func DeleteIssue(ctx *context.APIContext) { diff --git a/routers/api/v1/repo/issue_attachment.go b/routers/api/v1/repo/issue_attachment.go index d62e23aa02..7a5c6d554d 100644 --- a/routers/api/v1/repo/issue_attachment.go +++ b/routers/api/v1/repo/issue_attachment.go @@ -107,7 +107,7 @@ func ListIssueAttachments(ctx *context.APIContext) { return } - ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, issue).Attachments) + ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, ctx.Doer, issue).Attachments) } // CreateIssueAttachment creates an attachment and saves the given file diff --git a/routers/api/v1/repo/issue_dependency.go b/routers/api/v1/repo/issue_dependency.go index a42920d4fd..c40e92c01b 100644 --- a/routers/api/v1/repo/issue_dependency.go +++ b/routers/api/v1/repo/issue_dependency.go @@ -153,7 +153,7 @@ func GetIssueDependencies(ctx *context.APIContext) { blockerIssues = append(blockerIssues, &blocker.Issue) } - ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, blockerIssues)) + ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, ctx.Doer, blockerIssues)) } // CreateIssueDependency create a new issue dependencies @@ -214,7 +214,7 @@ func CreateIssueDependency(ctx *context.APIContext) { return } - ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, target)) + ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, target)) } // RemoveIssueDependency remove an issue dependency @@ -275,7 +275,7 @@ func RemoveIssueDependency(ctx *context.APIContext) { return } - ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, target)) + ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, target)) } // GetIssueBlocks list issues that are blocked by this issue @@ -381,7 +381,7 @@ func GetIssueBlocks(ctx *context.APIContext) { issues = append(issues, &depMeta.Issue) } - ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues)) + ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, ctx.Doer, issues)) } // CreateIssueBlocking block the issue given in the body by the issue in path @@ -438,7 +438,7 @@ func CreateIssueBlocking(ctx *context.APIContext) { return } - ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, dependency)) + ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, dependency)) } // RemoveIssueBlocking unblock the issue given in the body by the issue in path @@ -495,7 +495,7 @@ func RemoveIssueBlocking(ctx *context.APIContext) { return } - ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, dependency)) + ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, dependency)) } func getParamsIssue(ctx *context.APIContext) *issues_model.Issue { diff --git a/routers/api/v1/repo/issue_pin.go b/routers/api/v1/repo/issue_pin.go index 8fcf670fd0..af3e06332a 100644 --- a/routers/api/v1/repo/issue_pin.go +++ b/routers/api/v1/repo/issue_pin.go @@ -207,7 +207,7 @@ func ListPinnedIssues(ctx *context.APIContext) { return } - ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues)) + ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, ctx.Doer, issues)) } // ListPinnedPullRequests returns a list of all pinned PRs diff --git a/routers/api/v1/repo/issue_tracked_time.go b/routers/api/v1/repo/issue_tracked_time.go index c640515881..f83855efac 100644 --- a/routers/api/v1/repo/issue_tracked_time.go +++ b/routers/api/v1/repo/issue_tracked_time.go @@ -138,7 +138,7 @@ func ListTrackedTimes(ctx *context.APIContext) { } ctx.SetTotalCountHeader(count) - ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, trackedTimes)) + ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, ctx.Doer, trackedTimes)) } // AddTime add time manual to the given issue @@ -225,7 +225,7 @@ func AddTime(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) return } - ctx.JSON(http.StatusOK, convert.ToTrackedTime(ctx, trackedTime)) + ctx.JSON(http.StatusOK, convert.ToTrackedTime(ctx, user, trackedTime)) } // ResetIssueTime reset time manual to the given issue @@ -455,7 +455,7 @@ func ListTrackedTimesByUser(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) return } - ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, trackedTimes)) + ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, ctx.Doer, trackedTimes)) } // ListTrackedTimesByRepository lists all tracked times of the repository @@ -567,7 +567,7 @@ func ListTrackedTimesByRepository(ctx *context.APIContext) { } ctx.SetTotalCountHeader(count) - ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, trackedTimes)) + ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, ctx.Doer, trackedTimes)) } // ListMyTrackedTimes lists all tracked times of the current user @@ -629,5 +629,5 @@ func ListMyTrackedTimes(ctx *context.APIContext) { } ctx.SetTotalCountHeader(count) - ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, trackedTimes)) + ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, ctx.Doer, trackedTimes)) } diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 6c2d4a7390..e4f2e9a2bc 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -2179,7 +2179,7 @@ func GetIssueInfo(ctx *context.Context) { } } - ctx.JSON(http.StatusOK, convert.ToIssue(ctx, issue)) + ctx.JSON(http.StatusOK, convert.ToIssue(ctx, ctx.Doer, issue)) } // UpdateIssueTitle change issue's title @@ -2709,7 +2709,7 @@ func SearchIssues(ctx *context.Context) { } ctx.SetTotalCountHeader(total) - ctx.JSON(http.StatusOK, convert.ToIssueList(ctx, issues)) + ctx.JSON(http.StatusOK, convert.ToIssueList(ctx, ctx.Doer, issues)) } func getUserIDForFilter(ctx *context.Context, queryName string) int64 { @@ -2879,7 +2879,7 @@ func ListIssues(ctx *context.Context) { } ctx.SetTotalCountHeader(total) - ctx.JSON(http.StatusOK, convert.ToIssueList(ctx, issues)) + ctx.JSON(http.StatusOK, convert.ToIssueList(ctx, ctx.Doer, issues)) } func BatchDeleteIssues(ctx *context.Context) { diff --git a/services/actions/notifier.go b/services/actions/notifier.go index eec5f814da..6551da39e7 100644 --- a/services/actions/notifier.go +++ b/services/actions/notifier.go @@ -49,7 +49,7 @@ func (n *actionsNotifier) NewIssue(ctx context.Context, issue *issues_model.Issu newNotifyInputFromIssue(issue, webhook_module.HookEventIssues).WithPayload(&api.IssuePayload{ Action: api.HookIssueOpened, Index: issue.Index, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, issue.Poster, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, issue.Poster, nil), }).Notify(withMethod(ctx, "NewIssue")) @@ -89,7 +89,7 @@ func (n *actionsNotifier) IssueChangeContent(ctx context.Context, doer *user_mod WithPayload(&api.IssuePayload{ Action: api.HookIssueEdited, Index: issue.Index, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, doer, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), }). @@ -127,7 +127,7 @@ func (n *actionsNotifier) IssueChangeStatus(ctx context.Context, doer *user_mode } apiIssue := &api.IssuePayload{ Index: issue.Index, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, doer, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), } @@ -229,7 +229,7 @@ func notifyIssueChange(ctx context.Context, doer *user_model.User, issue *issues WithPayload(&api.IssuePayload{ Action: action, Index: issue.Index, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, doer, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), }). @@ -293,7 +293,7 @@ func notifyIssueCommentChange(ctx context.Context, doer *user_model.User, commen payload := &api.IssueCommentPayload{ Action: action, - Issue: convert.ToAPIIssue(ctx, comment.Issue), + Issue: convert.ToAPIIssue(ctx, doer, comment.Issue), Comment: convert.ToAPIComment(ctx, comment.Issue.Repo, comment), Repository: convert.ToRepo(ctx, comment.Issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), diff --git a/services/convert/issue.go b/services/convert/issue.go index c6e06180c8..54b00cd88e 100644 --- a/services/convert/issue.go +++ b/services/convert/issue.go @@ -18,19 +18,19 @@ import ( api "code.gitea.io/gitea/modules/structs" ) -func ToIssue(ctx context.Context, issue *issues_model.Issue) *api.Issue { - return toIssue(ctx, issue, WebAssetDownloadURL) +func ToIssue(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) *api.Issue { + return toIssue(ctx, doer, issue, WebAssetDownloadURL) } // ToAPIIssue converts an Issue to API format // it assumes some fields assigned with values: // Required - Poster, Labels, // Optional - Milestone, Assignee, PullRequest -func ToAPIIssue(ctx context.Context, issue *issues_model.Issue) *api.Issue { - return toIssue(ctx, issue, APIAssetDownloadURL) +func ToAPIIssue(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) *api.Issue { + return toIssue(ctx, doer, issue, APIAssetDownloadURL) } -func toIssue(ctx context.Context, issue *issues_model.Issue, getDownloadURL func(repo *repo_model.Repository, attach *repo_model.Attachment) string) *api.Issue { +func toIssue(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, getDownloadURL func(repo *repo_model.Repository, attach *repo_model.Attachment) string) *api.Issue { if err := issue.LoadLabels(ctx); err != nil { return &api.Issue{} } @@ -44,7 +44,7 @@ func toIssue(ctx context.Context, issue *issues_model.Issue, getDownloadURL func apiIssue := &api.Issue{ ID: issue.ID, Index: issue.Index, - Poster: ToUser(ctx, issue.Poster, nil), + Poster: ToUser(ctx, issue.Poster, doer), Title: issue.Title, Body: issue.Content, Attachments: toAttachments(issue.Repo, issue.Attachments, getDownloadURL), @@ -114,25 +114,25 @@ func toIssue(ctx context.Context, issue *issues_model.Issue, getDownloadURL func } // ToIssueList converts an IssueList to API format -func ToIssueList(ctx context.Context, il issues_model.IssueList) []*api.Issue { +func ToIssueList(ctx context.Context, doer *user_model.User, il issues_model.IssueList) []*api.Issue { result := make([]*api.Issue, len(il)) for i := range il { - result[i] = ToIssue(ctx, il[i]) + result[i] = ToIssue(ctx, doer, il[i]) } return result } // ToAPIIssueList converts an IssueList to API format -func ToAPIIssueList(ctx context.Context, il issues_model.IssueList) []*api.Issue { +func ToAPIIssueList(ctx context.Context, doer *user_model.User, il issues_model.IssueList) []*api.Issue { result := make([]*api.Issue, len(il)) for i := range il { - result[i] = ToAPIIssue(ctx, il[i]) + result[i] = ToAPIIssue(ctx, doer, il[i]) } return result } // ToTrackedTime converts TrackedTime to API format -func ToTrackedTime(ctx context.Context, t *issues_model.TrackedTime) (apiT *api.TrackedTime) { +func ToTrackedTime(ctx context.Context, doer *user_model.User, t *issues_model.TrackedTime) (apiT *api.TrackedTime) { apiT = &api.TrackedTime{ ID: t.ID, IssueID: t.IssueID, @@ -141,7 +141,7 @@ func ToTrackedTime(ctx context.Context, t *issues_model.TrackedTime) (apiT *api. Created: t.Created, } if t.Issue != nil { - apiT.Issue = ToAPIIssue(ctx, t.Issue) + apiT.Issue = ToAPIIssue(ctx, doer, t.Issue) } if t.User != nil { apiT.UserName = t.User.Name @@ -192,10 +192,10 @@ func ToStopWatches(ctx context.Context, sws []*issues_model.Stopwatch) (api.Stop } // ToTrackedTimeList converts TrackedTimeList to API format -func ToTrackedTimeList(ctx context.Context, tl issues_model.TrackedTimeList) api.TrackedTimeList { +func ToTrackedTimeList(ctx context.Context, doer *user_model.User, tl issues_model.TrackedTimeList) api.TrackedTimeList { result := make([]*api.TrackedTime, 0, len(tl)) for _, t := range tl { - result = append(result, ToTrackedTime(ctx, t)) + result = append(result, ToTrackedTime(ctx, doer, t)) } return result } diff --git a/services/convert/issue_comment.go b/services/convert/issue_comment.go index b034a50897..9ffaf1e84c 100644 --- a/services/convert/issue_comment.go +++ b/services/convert/issue_comment.go @@ -120,7 +120,7 @@ func ToTimelineComment(ctx context.Context, repo *repo_model.Repository, c *issu return nil } - comment.TrackedTime = ToTrackedTime(ctx, c.Time) + comment.TrackedTime = ToTrackedTime(ctx, doer, c.Time) } if c.RefIssueID != 0 { @@ -129,7 +129,7 @@ func ToTimelineComment(ctx context.Context, repo *repo_model.Repository, c *issu log.Error("GetIssueByID(%d): %v", c.RefIssueID, err) return nil } - comment.RefIssue = ToAPIIssue(ctx, issue) + comment.RefIssue = ToAPIIssue(ctx, doer, issue) } if c.RefCommentID != 0 { @@ -180,7 +180,7 @@ func ToTimelineComment(ctx context.Context, repo *repo_model.Repository, c *issu } if c.DependentIssue != nil { - comment.DependentIssue = ToAPIIssue(ctx, c.DependentIssue) + comment.DependentIssue = ToAPIIssue(ctx, doer, c.DependentIssue) } return comment diff --git a/services/convert/pull.go b/services/convert/pull.go index 6d98121ed5..775bf3806d 100644 --- a/services/convert/pull.go +++ b/services/convert/pull.go @@ -33,7 +33,7 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u return nil } - apiIssue := ToAPIIssue(ctx, pr.Issue) + apiIssue := ToAPIIssue(ctx, doer, pr.Issue) if err := pr.LoadBaseRepo(ctx); err != nil { log.Error("GetRepositoryById[%d]: %v", pr.ID, err) return nil diff --git a/services/webhook/notifier.go b/services/webhook/notifier.go index 1ab14fd6a7..587caf62ff 100644 --- a/services/webhook/notifier.go +++ b/services/webhook/notifier.go @@ -67,7 +67,7 @@ func (m *webhookNotifier) IssueClearLabels(ctx context.Context, doer *user_model err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueLabel, &api.IssuePayload{ Action: api.HookIssueLabelCleared, Index: issue.Index, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, doer, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), }) @@ -168,7 +168,7 @@ func (m *webhookNotifier) IssueChangeAssignee(ctx context.Context, doer *user_mo permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, doer) apiIssue := &api.IssuePayload{ Index: issue.Index, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, doer, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), } @@ -214,7 +214,7 @@ func (m *webhookNotifier) IssueChangeTitle(ctx context.Context, doer *user_model From: oldTitle, }, }, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, doer, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), }) @@ -250,7 +250,7 @@ func (m *webhookNotifier) IssueChangeStatus(ctx context.Context, doer *user_mode } else { apiIssue := &api.IssuePayload{ Index: issue.Index, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, doer, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), CommitID: commitID, @@ -281,7 +281,7 @@ func (m *webhookNotifier) NewIssue(ctx context.Context, issue *issues_model.Issu if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssues, &api.IssuePayload{ Action: api.HookIssueOpened, Index: issue.Index, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, issue.Poster, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, issue.Poster, nil), }); err != nil { @@ -349,7 +349,7 @@ func (m *webhookNotifier) IssueChangeContent(ctx context.Context, doer *user_mod From: oldContent, }, }, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, doer, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), }) @@ -384,7 +384,7 @@ func (m *webhookNotifier) UpdateComment(ctx context.Context, doer *user_model.Us permission, _ := access_model.GetUserRepoPermission(ctx, c.Issue.Repo, doer) if err := PrepareWebhooks(ctx, EventSource{Repository: c.Issue.Repo}, eventType, &api.IssueCommentPayload{ Action: api.HookIssueCommentEdited, - Issue: convert.ToAPIIssue(ctx, c.Issue), + Issue: convert.ToAPIIssue(ctx, doer, c.Issue), Comment: convert.ToAPIComment(ctx, c.Issue.Repo, c), Changes: &api.ChangesPayload{ Body: &api.ChangesFromPayload{ @@ -412,7 +412,7 @@ func (m *webhookNotifier) CreateIssueComment(ctx context.Context, doer *user_mod permission, _ := access_model.GetUserRepoPermission(ctx, repo, doer) if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, eventType, &api.IssueCommentPayload{ Action: api.HookIssueCommentCreated, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, doer, issue), Comment: convert.ToAPIComment(ctx, repo, comment), Repository: convert.ToRepo(ctx, repo, permission), Sender: convert.ToUser(ctx, doer, nil), @@ -449,7 +449,7 @@ func (m *webhookNotifier) DeleteComment(ctx context.Context, doer *user_model.Us permission, _ := access_model.GetUserRepoPermission(ctx, comment.Issue.Repo, doer) if err := PrepareWebhooks(ctx, EventSource{Repository: comment.Issue.Repo}, eventType, &api.IssueCommentPayload{ Action: api.HookIssueCommentDeleted, - Issue: convert.ToAPIIssue(ctx, comment.Issue), + Issue: convert.ToAPIIssue(ctx, doer, comment.Issue), Comment: convert.ToAPIComment(ctx, comment.Issue.Repo, comment), Repository: convert.ToRepo(ctx, comment.Issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), @@ -533,7 +533,7 @@ func (m *webhookNotifier) IssueChangeLabels(ctx context.Context, doer *user_mode err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueLabel, &api.IssuePayload{ Action: api.HookIssueLabelUpdated, Index: issue.Index, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, doer, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), }) @@ -575,7 +575,7 @@ func (m *webhookNotifier) IssueChangeMilestone(ctx context.Context, doer *user_m err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueMilestone, &api.IssuePayload{ Action: hookAction, Index: issue.Index, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, doer, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), }) From d7013c26c8eadf1679efe14ea338a4f1b2295b07 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Tue, 9 Apr 2024 00:24:26 +0000 Subject: [PATCH 066/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_id-ID.ini | 41 +++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini index ad7e0f4062..96248cbc1d 100644 --- a/options/locale/locale_id-ID.ini +++ b/options/locale/locale_id-ID.ini @@ -1331,12 +1331,53 @@ runners.task_list.repository=Repositori runners.task_list.commit=Memperbuat runs.commit=Memperbuat +runs.no_matching_online_runner_helper=Tidak ada runner online yang cocok dengan label: %s +runs.actor=Aktor +runs.status=Status +runs.actors_no_select=Semua aktor +runs.status_no_select=Semua status +runs.no_results=Tidak ada hasil yang cocok. +runs.no_workflows=Belum ada alur kerja. +runs.no_workflows.quick_start=Tidak tahu cara memulai dengan Gitea Actions? Lihat <a target="_blank" rel="noopener noreferrer" href="%s">panduan cepat</a>. +runs.no_workflows.documentation=Untuk informasi lebih lanjut tentang Gitea Actions, lihat <a target="_blank" rel="noopener noreferrer" href="%s">dokumentasi</a>. +runs.no_runs=Alur kerja belum berjalan. +runs.empty_commit_message=(pesan commit kosong) +workflow.disable=Nonaktifkan Alur Kerja +workflow.disable_success=Alur kerja '%s' berhasil dinonaktifkan. +workflow.enable=Aktifkan Alur Kerja +workflow.enable_success=Alur kerja '%s' berhasil diaktifkan. +workflow.disabled=Alur kerja dinonaktifkan. +need_approval_desc=Butuh persetujuan untuk menjalankan alur kerja untuk pull request fork. +variables=Variabel +variables.management=Managemen Variabel +variables.creation=Tambah Variabel +variables.none=Belum ada variabel. +variables.deletion=Hapus variabel +variables.deletion.description=Menghapus variabel bersifat permanen dan tidak dapat dibatalkan. Lanjutkan? +variables.description=Variabel akan diteruskan ke beberapa tindakan dan tidak dapat dibaca sebaliknya. +variables.id_not_exist=Variabel dengan ID %d tidak ada. +variables.edit=Edit Variabel +variables.deletion.failed=Gagal menghapus variabel. +variables.deletion.success=Variabel telah dihapus. +variables.creation.failed=Gagal menambahkan variabel. +variables.creation.success=Variabel "%s" telah ditambahkan. +variables.update.failed=Gagal mengedit variabel. +variables.update.success=Variabel telah diedit. [projects] +type-1.display_name=Proyek Individu +type-2.display_name=Proyek Repositori +type-3.display_name=Proyek Organisasi [git.filemode] +changed_filemode=%[1]s → %[2]s ; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", … +directory=Directory +normal_file=Normal file +executable_file=Executable file +symbolic_link=Symbolic link +submodule=Submodule From 72dc75e594fb5227abfa1cb74cb652cc33bacc93 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Tue, 9 Apr 2024 05:09:43 +0200 Subject: [PATCH 067/370] Reduce checkbox size to 15px (#30346) 16 seems to big, 14 too small. Let's do 15. Alignment: <img width="181" alt="image" src="https://github.com/go-gitea/gitea/assets/115237/f2988611-dee2-492e-a18f-dc5ab3a1cd6c"> --- web_src/css/base.css | 2 +- web_src/css/modules/checkbox.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/web_src/css/base.css b/web_src/css/base.css index 44dc83e6f3..02bc1b7220 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -23,7 +23,7 @@ --height-loading: 16rem; --min-height-textarea: 132px; /* padding + 6 lines + border = calc(1.57142em + 6lh + 2px), but lh is not fully supported */ --tab-size: 4; - --checkbox-size: 16px; /* height and width of checkbox and radio inputs */ + --checkbox-size: 15px; /* height and width of checkbox and radio inputs */ --page-spacing: 16px; /* space between page elements */ } diff --git a/web_src/css/modules/checkbox.css b/web_src/css/modules/checkbox.css index 9238e0b3f3..d3e45714a4 100644 --- a/web_src/css/modules/checkbox.css +++ b/web_src/css/modules/checkbox.css @@ -20,7 +20,7 @@ input[type="radio"] { .ui.checkbox input[type="checkbox"], .ui.checkbox input[type="radio"] { position: absolute; - top: 0; + top: 1px; left: 0; width: var(--checkbox-size); height: var(--checkbox-size); From 263a716cb52037f3e7e51f014f6c8cdfad6ae03d Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Tue, 9 Apr 2024 11:43:17 +0800 Subject: [PATCH 068/370] Performance optimization for git push (#30104) Agit returned result should be from `ProcReceive` hook but not `PostReceive` hook. Then for all non-agit pull requests, it will not check the pull requests for every pushing `refs/pull/%d/head`. --- cmd/hook.go | 37 +++++++----- modules/private/hook.go | 25 ++++---- routers/private/hook_post_receive.go | 85 ++++++++++++++-------------- services/agit/agit.go | 26 ++++++--- tests/integration/git_push_test.go | 11 ++++ 5 files changed, 110 insertions(+), 74 deletions(-) diff --git a/cmd/hook.go b/cmd/hook.go index 6a3358853d..c04591d79e 100644 --- a/cmd/hook.go +++ b/cmd/hook.go @@ -448,23 +448,26 @@ Gitea or set your environment appropriately.`, "") func hookPrintResults(results []private.HookPostReceiveBranchResult) { for _, res := range results { - if !res.Message { - continue - } - - fmt.Fprintln(os.Stderr, "") - if res.Create { - fmt.Fprintf(os.Stderr, "Create a new pull request for '%s':\n", res.Branch) - fmt.Fprintf(os.Stderr, " %s\n", res.URL) - } else { - fmt.Fprint(os.Stderr, "Visit the existing pull request:\n") - fmt.Fprintf(os.Stderr, " %s\n", res.URL) - } - fmt.Fprintln(os.Stderr, "") - os.Stderr.Sync() + hookPrintResult(res.Message, res.Create, res.Branch, res.URL) } } +func hookPrintResult(output, isCreate bool, branch, url string) { + if !output { + return + } + fmt.Fprintln(os.Stderr, "") + if isCreate { + fmt.Fprintf(os.Stderr, "Create a new pull request for '%s':\n", branch) + fmt.Fprintf(os.Stderr, " %s\n", url) + } else { + fmt.Fprint(os.Stderr, "Visit the existing pull request:\n") + fmt.Fprintf(os.Stderr, " %s\n", url) + } + fmt.Fprintln(os.Stderr, "") + os.Stderr.Sync() +} + func pushOptions() map[string]string { opts := make(map[string]string) if pushCount, err := strconv.Atoi(os.Getenv(private.GitPushOptionCount)); err == nil { @@ -691,6 +694,12 @@ Gitea or set your environment appropriately.`, "") } err = writeFlushPktLine(ctx, os.Stdout) + if err == nil { + for _, res := range resp.Results { + hookPrintResult(res.ShouldShowMessage, res.IsCreatePR, res.HeadBranch, res.URL) + } + } + return err } diff --git a/modules/private/hook.go b/modules/private/hook.go index cab8c81224..79c3d48229 100644 --- a/modules/private/hook.go +++ b/modules/private/hook.go @@ -11,6 +11,7 @@ import ( "time" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" ) @@ -32,13 +33,13 @@ const ( ) // Bool checks for a key in the map and parses as a boolean -func (g GitPushOptions) Bool(key string, def bool) bool { +func (g GitPushOptions) Bool(key string) optional.Option[bool] { if val, ok := g[key]; ok { if b, err := strconv.ParseBool(val); err == nil { - return b + return optional.Some(b) } } - return def + return optional.None[bool]() } // HookOptions represents the options for the Hook calls @@ -87,13 +88,17 @@ type HookProcReceiveResult struct { // HookProcReceiveRefResult represents an individual result from ProcReceive type HookProcReceiveRefResult struct { - OldOID string - NewOID string - Ref string - OriginalRef git.RefName - IsForcePush bool - IsNotMatched bool - Err string + OldOID string + NewOID string + Ref string + OriginalRef git.RefName + IsForcePush bool + IsNotMatched bool + Err string + IsCreatePR bool + URL string + ShouldShowMessage bool + HeadBranch string } // HookPreReceive check whether the provided commits are allowed diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index 101ae92302..769a68970d 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -6,11 +6,12 @@ package private import ( "fmt" "net/http" - "strconv" git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" + 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/log" @@ -159,8 +160,10 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { } } + isPrivate := opts.GitPushOptions.Bool(private.GitPushOptionRepoPrivate) + isTemplate := opts.GitPushOptions.Bool(private.GitPushOptionRepoTemplate) // Handle Push Options - if len(opts.GitPushOptions) > 0 { + if isPrivate.Has() || isTemplate.Has() { // load the repository if repo == nil { repo = loadRepository(ctx, ownerName, repoName) @@ -171,13 +174,49 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { wasEmpty = repo.IsEmpty } - repo.IsPrivate = opts.GitPushOptions.Bool(private.GitPushOptionRepoPrivate, repo.IsPrivate) - repo.IsTemplate = opts.GitPushOptions.Bool(private.GitPushOptionRepoTemplate, repo.IsTemplate) - if err := repo_model.UpdateRepositoryCols(ctx, repo, "is_private", "is_template"); err != nil { + pusher, err := user_model.GetUserByID(ctx, opts.UserID) + if err != nil { log.Error("Failed to Update: %s/%s Error: %v", ownerName, repoName, err) ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{ Err: fmt.Sprintf("Failed to Update: %s/%s Error: %v", ownerName, repoName, err), }) + return + } + perm, err := access_model.GetUserRepoPermission(ctx, repo, pusher) + if err != nil { + log.Error("Failed to Update: %s/%s Error: %v", ownerName, repoName, err) + ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{ + Err: fmt.Sprintf("Failed to Update: %s/%s Error: %v", ownerName, repoName, err), + }) + return + } + if !perm.IsOwner() && !perm.IsAdmin() { + ctx.JSON(http.StatusNotFound, private.HookPostReceiveResult{ + Err: "Permissions denied", + }) + return + } + + cols := make([]string, 0, len(opts.GitPushOptions)) + + if isPrivate.Has() { + repo.IsPrivate = isPrivate.Value() + cols = append(cols, "is_private") + } + + if isTemplate.Has() { + repo.IsTemplate = isTemplate.Value() + cols = append(cols, "is_template") + } + + if len(cols) > 0 { + if err := repo_model.UpdateRepositoryCols(ctx, repo, cols...); err != nil { + log.Error("Failed to Update: %s/%s Error: %v", ownerName, repoName, err) + ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{ + Err: fmt.Sprintf("Failed to Update: %s/%s Error: %v", ownerName, repoName, err), + }) + return + } } } @@ -192,42 +231,6 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { refFullName := opts.RefFullNames[i] newCommitID := opts.NewCommitIDs[i] - // post update for agit pull request - // FIXME: use pr.Flow to test whether it's an Agit PR or a GH PR - if git.DefaultFeatures.SupportProcReceive && refFullName.IsPull() { - if repo == nil { - repo = loadRepository(ctx, ownerName, repoName) - if ctx.Written() { - return - } - } - - pullIndex, _ := strconv.ParseInt(refFullName.PullName(), 10, 64) - if pullIndex <= 0 { - continue - } - - pr, err := issues_model.GetPullRequestByIndex(ctx, repo.ID, pullIndex) - if err != nil && !issues_model.IsErrPullRequestNotExist(err) { - log.Error("Failed to get PR by index %v Error: %v", pullIndex, err) - ctx.JSON(http.StatusInternalServerError, private.Response{ - Err: fmt.Sprintf("Failed to get PR by index %v Error: %v", pullIndex, err), - }) - return - } - if pr == nil { - continue - } - - results = append(results, private.HookPostReceiveBranchResult{ - Message: setting.Git.PullRequestPushMessage && repo.AllowsPulls(ctx), - Create: false, - Branch: "", - URL: fmt.Sprintf("%s/pulls/%d", repo.HTMLURL(), pr.Index), - }) - continue - } - // If we've pushed a branch (and not deleted it) if !git.IsEmptyCommitID(newCommitID) && refFullName.IsBranch() { // First ensure we have the repository loaded, we're allowed pulls requests and we can get the base repo diff --git a/services/agit/agit.go b/services/agit/agit.go index eb3bafa906..52a70469e0 100644 --- a/services/agit/agit.go +++ b/services/agit/agit.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/private" + "code.gitea.io/gitea/modules/setting" notify_service "code.gitea.io/gitea/services/notify" pull_service "code.gitea.io/gitea/services/pull" ) @@ -145,10 +146,14 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git. log.Trace("Pull request created: %d/%d", repo.ID, prIssue.ID) results = append(results, private.HookProcReceiveRefResult{ - Ref: pr.GetGitRefName(), - OriginalRef: opts.RefFullNames[i], - OldOID: objectFormat.EmptyObjectID().String(), - NewOID: opts.NewCommitIDs[i], + Ref: pr.GetGitRefName(), + OriginalRef: opts.RefFullNames[i], + OldOID: objectFormat.EmptyObjectID().String(), + NewOID: opts.NewCommitIDs[i], + IsCreatePR: true, + URL: fmt.Sprintf("%s/pulls/%d", repo.HTMLURL(), pr.Index), + ShouldShowMessage: setting.Git.PullRequestPushMessage && repo.AllowsPulls(ctx), + HeadBranch: headBranch, }) continue } @@ -208,11 +213,14 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git. isForcePush := comment != nil && comment.IsForcePush results = append(results, private.HookProcReceiveRefResult{ - OldOID: oldCommitID, - NewOID: opts.NewCommitIDs[i], - Ref: pr.GetGitRefName(), - OriginalRef: opts.RefFullNames[i], - IsForcePush: isForcePush, + OldOID: oldCommitID, + NewOID: opts.NewCommitIDs[i], + Ref: pr.GetGitRefName(), + OriginalRef: opts.RefFullNames[i], + IsForcePush: isForcePush, + IsCreatePR: false, + URL: fmt.Sprintf("%s/pulls/%d", repo.HTMLURL(), pr.Index), + ShouldShowMessage: setting.Git.PullRequestPushMessage && repo.AllowsPulls(ctx), }) } diff --git a/tests/integration/git_push_test.go b/tests/integration/git_push_test.go index 0a35724807..b37fb02444 100644 --- a/tests/integration/git_push_test.go +++ b/tests/integration/git_push_test.go @@ -49,6 +49,17 @@ func testGitPush(t *testing.T, u *url.URL) { }) }) + t.Run("Push branch with options", func(t *testing.T) { + runTestGitPush(t, u, func(t *testing.T, gitPath string) (pushed, deleted []string) { + branchName := "branch-with-options" + doGitCreateBranch(gitPath, branchName)(t) + doGitPushTestRepository(gitPath, "origin", branchName, "-o", "repo.private=true", "-o", "repo.template=true")(t) + pushed = append(pushed, branchName) + + return pushed, deleted + }) + }) + t.Run("Delete branches", func(t *testing.T) { runTestGitPush(t, u, func(t *testing.T, gitPath string) (pushed, deleted []string) { doGitPushTestRepository(gitPath, "origin", "master")(t) // make sure master is the default branch instead of a branch we are going to delete From 8d14266269f1b4fd5e13d701830919c1a1613444 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Tue, 9 Apr 2024 08:30:21 +0200 Subject: [PATCH 069/370] Fix label-list rendering in timeline, decrease gap (#30342) Not sure exactly when this regressed, but has been a while I think. Before: <img width="895" alt="Screenshot 2024-04-08 at 22 46 50" src="https://github.com/go-gitea/gitea/assets/115237/9b1788f8-017e-4fe1-8ab9-938e0d76fb41"> After: <img width="689" alt="Screenshot 2024-04-08 at 23 00 58" src="https://github.com/go-gitea/gitea/assets/115237/90193df9-5c24-4a1a-96fe-3d4e8392063c"> Co-authored-by: Giteabot <teabot@gitea.io> --- web_src/css/repo.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web_src/css/repo.css b/web_src/css/repo.css index c50d13a174..8b91b599e7 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -2274,9 +2274,9 @@ } .labels-list { - display: flex; + display: inline-flex; flex-wrap: wrap; - gap: 0.25em; + gap: 2.5px; } .labels-list a { From d547b53cca8a9a7ac96449910bae5d811728c251 Mon Sep 17 00:00:00 2001 From: oliverpool <3864879+oliverpool@users.noreply.github.com> Date: Tue, 9 Apr 2024 14:27:30 +0200 Subject: [PATCH 070/370] Add container.FilterSlice function (#30339) Many places have the following logic: ```go func (jobs ActionJobList) GetRunIDs() []int64 { ids := make(container.Set[int64], len(jobs)) for _, j := range jobs { if j.RunID == 0 { continue } ids.Add(j.RunID) } return ids.Values() } ``` this introduces a `container.FilterMapUnique` function, which reduces the code above to: ```go func (jobs ActionJobList) GetRunIDs() []int64 { return container.FilterMapUnique(jobs, func(j *ActionRunJob) (int64, bool) { return j.RunID, j.RunID != 0 }) } ``` --- models/actions/run_job_list.go | 11 +--- models/actions/run_list.go | 16 ++--- models/actions/runner_list.go | 11 +--- models/actions/schedule_list.go | 16 ++--- models/actions/schedule_spec_list.go | 16 ++--- models/actions/task_list.go | 11 +--- models/activities/action_list.go | 30 ++++----- models/git/branch_list.go | 26 ++++---- models/issues/comment.go | 9 ++- models/issues/comment_list.go | 95 ++++++++-------------------- models/issues/issue_list.go | 16 ++--- models/issues/reaction.go | 10 ++- models/issues/review_list.go | 9 ++- models/repo/repo_list.go | 9 +-- modules/container/filter.go | 21 ++++++ modules/container/filter_test.go | 28 ++++++++ 16 files changed, 150 insertions(+), 184 deletions(-) create mode 100644 modules/container/filter.go create mode 100644 modules/container/filter_test.go diff --git a/models/actions/run_job_list.go b/models/actions/run_job_list.go index 6ea6cb9d3b..6c5d3b3252 100644 --- a/models/actions/run_job_list.go +++ b/models/actions/run_job_list.go @@ -16,14 +16,9 @@ import ( type ActionJobList []*ActionRunJob func (jobs ActionJobList) GetRunIDs() []int64 { - ids := make(container.Set[int64], len(jobs)) - for _, j := range jobs { - if j.RunID == 0 { - continue - } - ids.Add(j.RunID) - } - return ids.Values() + return container.FilterSlice(jobs, func(j *ActionRunJob) (int64, bool) { + return j.RunID, j.RunID != 0 + }) } func (jobs ActionJobList) LoadRuns(ctx context.Context, withRepo bool) error { diff --git a/models/actions/run_list.go b/models/actions/run_list.go index 388bfc4f86..4046c7d369 100644 --- a/models/actions/run_list.go +++ b/models/actions/run_list.go @@ -19,19 +19,15 @@ type RunList []*ActionRun // GetUserIDs returns a slice of user's id func (runs RunList) GetUserIDs() []int64 { - ids := make(container.Set[int64], len(runs)) - for _, run := range runs { - ids.Add(run.TriggerUserID) - } - return ids.Values() + return container.FilterSlice(runs, func(run *ActionRun) (int64, bool) { + return run.TriggerUserID, true + }) } func (runs RunList) GetRepoIDs() []int64 { - ids := make(container.Set[int64], len(runs)) - for _, run := range runs { - ids.Add(run.RepoID) - } - return ids.Values() + return container.FilterSlice(runs, func(run *ActionRun) (int64, bool) { + return run.RepoID, true + }) } func (runs RunList) LoadTriggerUser(ctx context.Context) error { diff --git a/models/actions/runner_list.go b/models/actions/runner_list.go index 87f0886b47..5ce69e07ac 100644 --- a/models/actions/runner_list.go +++ b/models/actions/runner_list.go @@ -16,14 +16,9 @@ type RunnerList []*ActionRunner // GetUserIDs returns a slice of user's id func (runners RunnerList) GetUserIDs() []int64 { - ids := make(container.Set[int64], len(runners)) - for _, runner := range runners { - if runner.OwnerID == 0 { - continue - } - ids.Add(runner.OwnerID) - } - return ids.Values() + return container.FilterSlice(runners, func(runner *ActionRunner) (int64, bool) { + return runner.OwnerID, runner.OwnerID != 0 + }) } func (runners RunnerList) LoadOwners(ctx context.Context) error { diff --git a/models/actions/schedule_list.go b/models/actions/schedule_list.go index b806550b87..1d35adc420 100644 --- a/models/actions/schedule_list.go +++ b/models/actions/schedule_list.go @@ -18,19 +18,15 @@ type ScheduleList []*ActionSchedule // GetUserIDs returns a slice of user's id func (schedules ScheduleList) GetUserIDs() []int64 { - ids := make(container.Set[int64], len(schedules)) - for _, schedule := range schedules { - ids.Add(schedule.TriggerUserID) - } - return ids.Values() + return container.FilterSlice(schedules, func(schedule *ActionSchedule) (int64, bool) { + return schedule.TriggerUserID, true + }) } func (schedules ScheduleList) GetRepoIDs() []int64 { - ids := make(container.Set[int64], len(schedules)) - for _, schedule := range schedules { - ids.Add(schedule.RepoID) - } - return ids.Values() + return container.FilterSlice(schedules, func(schedule *ActionSchedule) (int64, bool) { + return schedule.RepoID, true + }) } func (schedules ScheduleList) LoadTriggerUser(ctx context.Context) error { diff --git a/models/actions/schedule_spec_list.go b/models/actions/schedule_spec_list.go index e9ae268a6e..f7dac72f8b 100644 --- a/models/actions/schedule_spec_list.go +++ b/models/actions/schedule_spec_list.go @@ -16,11 +16,9 @@ import ( type SpecList []*ActionScheduleSpec func (specs SpecList) GetScheduleIDs() []int64 { - ids := make(container.Set[int64], len(specs)) - for _, spec := range specs { - ids.Add(spec.ScheduleID) - } - return ids.Values() + return container.FilterSlice(specs, func(spec *ActionScheduleSpec) (int64, bool) { + return spec.ScheduleID, true + }) } func (specs SpecList) LoadSchedules(ctx context.Context) error { @@ -46,11 +44,9 @@ func (specs SpecList) LoadSchedules(ctx context.Context) error { } func (specs SpecList) GetRepoIDs() []int64 { - ids := make(container.Set[int64], len(specs)) - for _, spec := range specs { - ids.Add(spec.RepoID) - } - return ids.Values() + return container.FilterSlice(specs, func(spec *ActionScheduleSpec) (int64, bool) { + return spec.RepoID, true + }) } func (specs SpecList) LoadRepos(ctx context.Context) error { diff --git a/models/actions/task_list.go b/models/actions/task_list.go index b07d00b8db..5e17f91441 100644 --- a/models/actions/task_list.go +++ b/models/actions/task_list.go @@ -16,14 +16,9 @@ import ( type TaskList []*ActionTask func (tasks TaskList) GetJobIDs() []int64 { - ids := make(container.Set[int64], len(tasks)) - for _, t := range tasks { - if t.JobID == 0 { - continue - } - ids.Add(t.JobID) - } - return ids.Values() + return container.FilterSlice(tasks, func(t *ActionTask) (int64, bool) { + return t.JobID, t.JobID != 0 + }) } func (tasks TaskList) LoadJobs(ctx context.Context) error { diff --git a/models/activities/action_list.go b/models/activities/action_list.go index fdf0f35d4f..6e23b173b5 100644 --- a/models/activities/action_list.go +++ b/models/activities/action_list.go @@ -22,11 +22,9 @@ import ( type ActionList []*Action func (actions ActionList) getUserIDs() []int64 { - userIDs := make(container.Set[int64], len(actions)) - for _, action := range actions { - userIDs.Add(action.ActUserID) - } - return userIDs.Values() + return container.FilterSlice(actions, func(action *Action) (int64, bool) { + return action.ActUserID, true + }) } func (actions ActionList) LoadActUsers(ctx context.Context) (map[int64]*user_model.User, error) { @@ -50,11 +48,9 @@ func (actions ActionList) LoadActUsers(ctx context.Context) (map[int64]*user_mod } func (actions ActionList) getRepoIDs() []int64 { - repoIDs := make(container.Set[int64], len(actions)) - for _, action := range actions { - repoIDs.Add(action.RepoID) - } - return repoIDs.Values() + return container.FilterSlice(actions, func(action *Action) (int64, bool) { + return action.RepoID, true + }) } func (actions ActionList) LoadRepositories(ctx context.Context) error { @@ -80,18 +76,16 @@ func (actions ActionList) loadRepoOwner(ctx context.Context, userMap map[int64]* userMap = make(map[int64]*user_model.User) } - userSet := make(container.Set[int64], len(actions)) - for _, action := range actions { + missingUserIDs := container.FilterSlice(actions, func(action *Action) (int64, bool) { if action.Repo == nil { - continue + return 0, false } - if _, ok := userMap[action.Repo.OwnerID]; !ok { - userSet.Add(action.Repo.OwnerID) - } - } + _, alreadyLoaded := userMap[action.Repo.OwnerID] + return action.Repo.OwnerID, !alreadyLoaded + }) if err := db.GetEngine(ctx). - In("id", userSet.Values()). + In("id", missingUserIDs). Find(&userMap); err != nil { return fmt.Errorf("find user: %w", err) } diff --git a/models/git/branch_list.go b/models/git/branch_list.go index 8319e5ecd0..980bd7b4c9 100644 --- a/models/git/branch_list.go +++ b/models/git/branch_list.go @@ -17,15 +17,12 @@ import ( type BranchList []*Branch func (branches BranchList) LoadDeletedBy(ctx context.Context) error { - ids := container.Set[int64]{} - for _, branch := range branches { - if !branch.IsDeleted { - continue - } - ids.Add(branch.DeletedByID) - } + ids := container.FilterSlice(branches, func(branch *Branch) (int64, bool) { + return branch.DeletedByID, branch.IsDeleted + }) + usersMap := make(map[int64]*user_model.User, len(ids)) - if err := db.GetEngine(ctx).In("id", ids.Values()).Find(&usersMap); err != nil { + if err := db.GetEngine(ctx).In("id", ids).Find(&usersMap); err != nil { return err } for _, branch := range branches { @@ -41,14 +38,13 @@ func (branches BranchList) LoadDeletedBy(ctx context.Context) error { } func (branches BranchList) LoadPusher(ctx context.Context) error { - ids := container.Set[int64]{} - for _, branch := range branches { - if branch.PusherID > 0 { // pusher_id maybe zero because some branches are sync by backend with no pusher - ids.Add(branch.PusherID) - } - } + ids := container.FilterSlice(branches, func(branch *Branch) (int64, bool) { + // pusher_id maybe zero because some branches are sync by backend with no pusher + return branch.PusherID, branch.PusherID > 0 + }) + usersMap := make(map[int64]*user_model.User, len(ids)) - if err := db.GetEngine(ctx).In("id", ids.Values()).Find(&usersMap); err != nil { + if err := db.GetEngine(ctx).In("id", ids).Find(&usersMap); err != nil { return err } for _, branch := range branches { diff --git a/models/issues/comment.go b/models/issues/comment.go index 6f65a5dbbc..353163ebd6 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -1272,10 +1272,9 @@ func InsertIssueComments(ctx context.Context, comments []*Comment) error { return nil } - issueIDs := make(container.Set[int64]) - for _, comment := range comments { - issueIDs.Add(comment.IssueID) - } + issueIDs := container.FilterSlice(comments, func(comment *Comment) (int64, bool) { + return comment.IssueID, true + }) ctx, committer, err := db.TxContext(ctx) if err != nil { @@ -1298,7 +1297,7 @@ func InsertIssueComments(ctx context.Context, comments []*Comment) error { } } - for issueID := range issueIDs { + for _, issueID := range issueIDs { if _, err := db.Exec(ctx, "UPDATE issue set num_comments = (SELECT count(*) FROM comment WHERE issue_id = ? AND `type`=?) WHERE id = ?", issueID, CommentTypeComment, issueID); err != nil { return err diff --git a/models/issues/comment_list.go b/models/issues/comment_list.go index 0047b054ba..370b5396e0 100644 --- a/models/issues/comment_list.go +++ b/models/issues/comment_list.go @@ -17,13 +17,9 @@ import ( type CommentList []*Comment func (comments CommentList) getPosterIDs() []int64 { - posterIDs := make(container.Set[int64], len(comments)) - for _, comment := range comments { - if comment.PosterID > 0 { - posterIDs.Add(comment.PosterID) - } - } - return posterIDs.Values() + return container.FilterSlice(comments, func(c *Comment) (int64, bool) { + return c.PosterID, c.PosterID > 0 + }) } // LoadPosters loads posters @@ -44,13 +40,9 @@ func (comments CommentList) LoadPosters(ctx context.Context) error { } func (comments CommentList) getLabelIDs() []int64 { - ids := make(container.Set[int64], len(comments)) - for _, comment := range comments { - if comment.LabelID > 0 { - ids.Add(comment.LabelID) - } - } - return ids.Values() + return container.FilterSlice(comments, func(comment *Comment) (int64, bool) { + return comment.LabelID, comment.LabelID > 0 + }) } func (comments CommentList) loadLabels(ctx context.Context) error { @@ -94,13 +86,9 @@ func (comments CommentList) loadLabels(ctx context.Context) error { } func (comments CommentList) getMilestoneIDs() []int64 { - ids := make(container.Set[int64], len(comments)) - for _, comment := range comments { - if comment.MilestoneID > 0 { - ids.Add(comment.MilestoneID) - } - } - return ids.Values() + return container.FilterSlice(comments, func(comment *Comment) (int64, bool) { + return comment.MilestoneID, comment.MilestoneID > 0 + }) } func (comments CommentList) loadMilestones(ctx context.Context) error { @@ -137,13 +125,9 @@ func (comments CommentList) loadMilestones(ctx context.Context) error { } func (comments CommentList) getOldMilestoneIDs() []int64 { - ids := make(container.Set[int64], len(comments)) - for _, comment := range comments { - if comment.OldMilestoneID > 0 { - ids.Add(comment.OldMilestoneID) - } - } - return ids.Values() + return container.FilterSlice(comments, func(comment *Comment) (int64, bool) { + return comment.OldMilestoneID, comment.OldMilestoneID > 0 + }) } func (comments CommentList) loadOldMilestones(ctx context.Context) error { @@ -180,13 +164,9 @@ func (comments CommentList) loadOldMilestones(ctx context.Context) error { } func (comments CommentList) getAssigneeIDs() []int64 { - ids := make(container.Set[int64], len(comments)) - for _, comment := range comments { - if comment.AssigneeID > 0 { - ids.Add(comment.AssigneeID) - } - } - return ids.Values() + return container.FilterSlice(comments, func(comment *Comment) (int64, bool) { + return comment.AssigneeID, comment.AssigneeID > 0 + }) } func (comments CommentList) loadAssignees(ctx context.Context) error { @@ -237,14 +217,9 @@ func (comments CommentList) loadAssignees(ctx context.Context) error { // getIssueIDs returns all the issue ids on this comment list which issue hasn't been loaded func (comments CommentList) getIssueIDs() []int64 { - ids := make(container.Set[int64], len(comments)) - for _, comment := range comments { - if comment.Issue != nil { - continue - } - ids.Add(comment.IssueID) - } - return ids.Values() + return container.FilterSlice(comments, func(comment *Comment) (int64, bool) { + return comment.IssueID, comment.Issue == nil + }) } // Issues returns all the issues of comments @@ -311,16 +286,12 @@ func (comments CommentList) LoadIssues(ctx context.Context) error { } func (comments CommentList) getDependentIssueIDs() []int64 { - ids := make(container.Set[int64], len(comments)) - for _, comment := range comments { + return container.FilterSlice(comments, func(comment *Comment) (int64, bool) { if comment.DependentIssue != nil { - continue + return 0, false } - if comment.DependentIssueID > 0 { - ids.Add(comment.DependentIssueID) - } - } - return ids.Values() + return comment.DependentIssueID, comment.DependentIssueID > 0 + }) } func (comments CommentList) loadDependentIssues(ctx context.Context) error { @@ -375,15 +346,9 @@ func (comments CommentList) loadDependentIssues(ctx context.Context) error { // getAttachmentCommentIDs only return the comment ids which possibly has attachments func (comments CommentList) getAttachmentCommentIDs() []int64 { - ids := make(container.Set[int64], len(comments)) - for _, comment := range comments { - if comment.Type == CommentTypeComment || - comment.Type == CommentTypeReview || - comment.Type == CommentTypeCode { - ids.Add(comment.ID) - } - } - return ids.Values() + return container.FilterSlice(comments, func(comment *Comment) (int64, bool) { + return comment.ID, comment.Type.HasAttachmentSupport() + }) } // LoadAttachmentsByIssue loads attachments by issue id @@ -451,13 +416,9 @@ func (comments CommentList) LoadAttachments(ctx context.Context) (err error) { } func (comments CommentList) getReviewIDs() []int64 { - ids := make(container.Set[int64], len(comments)) - for _, comment := range comments { - if comment.ReviewID > 0 { - ids.Add(comment.ReviewID) - } - } - return ids.Values() + return container.FilterSlice(comments, func(comment *Comment) (int64, bool) { + return comment.ReviewID, comment.ReviewID > 0 + }) } func (comments CommentList) loadReviews(ctx context.Context) error { diff --git a/models/issues/issue_list.go b/models/issues/issue_list.go index 218891ad35..1b05f0aa35 100644 --- a/models/issues/issue_list.go +++ b/models/issues/issue_list.go @@ -74,11 +74,9 @@ func (issues IssueList) LoadRepositories(ctx context.Context) (repo_model.Reposi } func (issues IssueList) getPosterIDs() []int64 { - posterIDs := make(container.Set[int64], len(issues)) - for _, issue := range issues { - posterIDs.Add(issue.PosterID) - } - return posterIDs.Values() + return container.FilterSlice(issues, func(issue *Issue) (int64, bool) { + return issue.PosterID, true + }) } func (issues IssueList) loadPosters(ctx context.Context) error { @@ -193,11 +191,9 @@ func (issues IssueList) loadLabels(ctx context.Context) error { } func (issues IssueList) getMilestoneIDs() []int64 { - ids := make(container.Set[int64], len(issues)) - for _, issue := range issues { - ids.Add(issue.MilestoneID) - } - return ids.Values() + return container.FilterSlice(issues, func(issue *Issue) (int64, bool) { + return issue.MilestoneID, true + }) } func (issues IssueList) loadMilestones(ctx context.Context) error { diff --git a/models/issues/reaction.go b/models/issues/reaction.go index d5448636fe..eb7faefc79 100644 --- a/models/issues/reaction.go +++ b/models/issues/reaction.go @@ -305,14 +305,12 @@ func (list ReactionList) GroupByType() map[string]ReactionList { } func (list ReactionList) getUserIDs() []int64 { - userIDs := make(container.Set[int64], len(list)) - for _, reaction := range list { + return container.FilterSlice(list, func(reaction *Reaction) (int64, bool) { if reaction.OriginalAuthor != "" { - continue + return 0, false } - userIDs.Add(reaction.UserID) - } - return userIDs.Values() + return reaction.UserID, true + }) } func valuesUser(m map[int64]*user_model.User) []*user_model.User { diff --git a/models/issues/review_list.go b/models/issues/review_list.go index ec6cb07988..7b8c3d319c 100644 --- a/models/issues/review_list.go +++ b/models/issues/review_list.go @@ -38,12 +38,11 @@ func (reviews ReviewList) LoadReviewers(ctx context.Context) error { } func (reviews ReviewList) LoadIssues(ctx context.Context) error { - issueIDs := container.Set[int64]{} - for i := 0; i < len(reviews); i++ { - issueIDs.Add(reviews[i].IssueID) - } + issueIDs := container.FilterSlice(reviews, func(review *Review) (int64, bool) { + return review.IssueID, true + }) - issues, err := GetIssuesByIDs(ctx, issueIDs.Values()) + issues, err := GetIssuesByIDs(ctx, issueIDs) if err != nil { return err } diff --git a/models/repo/repo_list.go b/models/repo/repo_list.go index cb7cd47a8d..987c7df9b0 100644 --- a/models/repo/repo_list.go +++ b/models/repo/repo_list.go @@ -104,18 +104,19 @@ func (repos RepositoryList) LoadAttributes(ctx context.Context) error { return nil } - set := make(container.Set[int64]) + userIDs := container.FilterSlice(repos, func(repo *Repository) (int64, bool) { + return repo.OwnerID, true + }) repoIDs := make([]int64, len(repos)) for i := range repos { - set.Add(repos[i].OwnerID) repoIDs[i] = repos[i].ID } // Load owners. - users := make(map[int64]*user_model.User, len(set)) + users := make(map[int64]*user_model.User, len(userIDs)) if err := db.GetEngine(ctx). Where("id > 0"). - In("id", set.Values()). + In("id", userIDs). Find(&users); err != nil { return fmt.Errorf("find users: %w", err) } diff --git a/modules/container/filter.go b/modules/container/filter.go new file mode 100644 index 0000000000..37ec7c3d56 --- /dev/null +++ b/modules/container/filter.go @@ -0,0 +1,21 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package container + +import "slices" + +// FilterSlice ranges over the slice and calls include() for each element. +// If the second returned value is true, the first returned value will be included in the resulting +// slice (after deduplication). +func FilterSlice[E any, T comparable](s []E, include func(E) (T, bool)) []T { + filtered := make([]T, 0, len(s)) // slice will be clipped before returning + seen := make(map[T]bool, len(s)) + for i := range s { + if v, ok := include(s[i]); ok && !seen[v] { + filtered = append(filtered, v) + seen[v] = true + } + } + return slices.Clip(filtered) +} diff --git a/modules/container/filter_test.go b/modules/container/filter_test.go new file mode 100644 index 0000000000..ad304e5abb --- /dev/null +++ b/modules/container/filter_test.go @@ -0,0 +1,28 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package container + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestFilterMapUnique(t *testing.T) { + result := FilterSlice([]int{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + }, func(i int) (int, bool) { + switch i { + case 0: + return 0, true // included later + case 1: + return 0, true // duplicate of previous (should be ignored) + case 2: + return 2, false // not included + default: + return i, true + } + }) + assert.Equal(t, []int{0, 3, 4, 5, 6, 7, 8, 9}, result) +} From 63c80aeb29efa2bc0ffa0ed46ea7cd86e634ef8a Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Wed, 10 Apr 2024 00:39:38 +0800 Subject: [PATCH 071/370] Fix actions design about default actions download url (#30360) Fix #30359 --- docs/content/usage/actions/design.en-us.md | 2 +- docs/content/usage/actions/design.zh-cn.md | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/content/usage/actions/design.en-us.md b/docs/content/usage/actions/design.en-us.md index 29fa433e59..0d72c19dce 100644 --- a/docs/content/usage/actions/design.en-us.md +++ b/docs/content/usage/actions/design.en-us.md @@ -104,7 +104,7 @@ However, if a job container tries to fetch code from localhost, it will fail bec ### Connection 3, act runner to internet When you use some actions like `actions/checkout@v4`, the act runner downloads the scripts, not the job containers. -By default, it downloads from [gitea.com](http://gitea.com/), so it requires access to the internet. +By default, it downloads from [github.com](http://github.com/), so it requires access to the internet. If you configure the `DEFAULT_ACTIONS_URL` to `self`, then it will download from your Gitea instance by default. Then it will not connect to internet when downloading the action itself. It also downloads some docker images from Docker Hub by default, which also requires internet access. However, internet access is not strictly necessary. diff --git a/docs/content/usage/actions/design.zh-cn.md b/docs/content/usage/actions/design.zh-cn.md index 8add1cf7c5..f48576477f 100644 --- a/docs/content/usage/actions/design.zh-cn.md +++ b/docs/content/usage/actions/design.zh-cn.md @@ -105,7 +105,8 @@ act runner 必须能够连接到Gitea以接收任务并发送执行结果回来 ### 连接 3,act runner到互联网 当您使用诸如 `actions/checkout@v4` 的一些Actions时,act runner下载的是脚本,而不是Job容器。 -默认情况下,它从[gitea.com](http://gitea.com/)下载,因此需要访问互联网。 +默认情况下,它从[github.com](http://github.com/)下载,因此需要访问互联网。如果您设置的是 self, +那么默认将从您的当前Gitea实例下载,那么此步骤不需要连接到互联网。 它还默认从Docker Hub下载一些Docker镜像,这也需要互联网访问。 然而,互联网访问并不是绝对必需的。 From fec754258cce7f82ce9263f2dd0fad3f0b078d8a Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Wed, 10 Apr 2024 04:16:55 +0200 Subject: [PATCH 072/370] Fix floated list items (#30377) Fixes https://github.com/go-gitea/gitea/issues/30365, regression from https://github.com/go-gitea/gitea/pull/30281 --- web_src/css/modules/list.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/web_src/css/modules/list.css b/web_src/css/modules/list.css index 73760390de..32c71e802b 100644 --- a/web_src/css/modules/list.css +++ b/web_src/css/modules/list.css @@ -126,6 +126,12 @@ cursor: pointer; } +.ui.list .list > .item [class*="right floated"], +.ui.list > .item [class*="right floated"] { + float: right; + margin: 0 0 0 1em; +} + .ui.menu .ui.list > .item, .ui.menu .ui.list .list > .item { display: list-item; From 310e2517e5d55a037f612a8561fb1850b517b37f Mon Sep 17 00:00:00 2001 From: Jason Song <i@wolfogre.com> Date: Wed, 10 Apr 2024 10:57:43 +0800 Subject: [PATCH 073/370] Fix ambiguous id when fetch Actions tasks (#30382) Fix regression of #30331. ```txt time="2024-04-10T02:23:49Z" level=error msg="failed to fetch task" func="[fetchTask]" file="[poller.go:91]" error="unknown: rpc error: code = Internal desc = pick task: CreateTaskForRunner: Error 1052 (23000): Column 'id' in field list is ambiguous" ``` --- models/actions/task.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/actions/task.go b/models/actions/task.go index 1e279659c7..9946cf5233 100644 --- a/models/actions/task.go +++ b/models/actions/task.go @@ -228,7 +228,7 @@ func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask if runner.RepoID != 0 { jobCond = builder.Eq{"repo_id": runner.RepoID} } else if runner.OwnerID != 0 { - jobCond = builder.In("repo_id", builder.Select("id").From("repository"). + jobCond = builder.In("repo_id", builder.Select("`repository`.id").From("repository"). Join("INNER", "repo_unit", "`repository`.id = `repo_unit`.repo_id"). Where(builder.Eq{"`repository`.owner_id": runner.OwnerID, "`repo_unit`.type": unit.TypeActions})) } From b09687f1d18e1489d82dd481a1cce50203f2da94 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Wed, 10 Apr 2024 12:18:41 +0800 Subject: [PATCH 074/370] Refactor more filterslice (#30370) --- models/actions/runner_list.go | 13 +++---------- models/activities/notification_list.go | 12 +++++------- models/issues/issue_list.go | 11 +++++------ 3 files changed, 13 insertions(+), 23 deletions(-) diff --git a/models/actions/runner_list.go b/models/actions/runner_list.go index 5ce69e07ac..3ef8ebb254 100644 --- a/models/actions/runner_list.go +++ b/models/actions/runner_list.go @@ -36,16 +36,9 @@ func (runners RunnerList) LoadOwners(ctx context.Context) error { } func (runners RunnerList) getRepoIDs() []int64 { - repoIDs := make(container.Set[int64], len(runners)) - for _, runner := range runners { - if runner.RepoID == 0 { - continue - } - if _, ok := repoIDs[runner.RepoID]; !ok { - repoIDs[runner.RepoID] = struct{}{} - } - } - return repoIDs.Values() + return container.FilterSlice(runners, func(runner *ActionRunner) (int64, bool) { + return runner.RepoID, runner.RepoID > 0 + }) } func (runners RunnerList) LoadRepos(ctx context.Context) error { diff --git a/models/activities/notification_list.go b/models/activities/notification_list.go index 5858933391..0cbb91df3c 100644 --- a/models/activities/notification_list.go +++ b/models/activities/notification_list.go @@ -190,14 +190,12 @@ func (nl NotificationList) LoadAttributes(ctx context.Context) error { } func (nl NotificationList) getPendingRepoIDs() []int64 { - ids := make(container.Set[int64], len(nl)) - for _, notification := range nl { - if notification.Repository != nil { - continue + return container.FilterSlice(nl, func(n *Notification) (int64, bool) { + if n.Repository != nil { + return 0, false } - ids.Add(notification.RepoID) - } - return ids.Values() + return n.RepoID, true + }) } // LoadRepos loads repositories from database diff --git a/models/issues/issue_list.go b/models/issues/issue_list.go index 1b05f0aa35..f8ee271a6b 100644 --- a/models/issues/issue_list.go +++ b/models/issues/issue_list.go @@ -21,16 +21,15 @@ type IssueList []*Issue // get the repo IDs to be loaded later, these IDs are for issue.Repo and issue.PullRequest.HeadRepo func (issues IssueList) getRepoIDs() []int64 { - repoIDs := make(container.Set[int64], len(issues)) - for _, issue := range issues { + return container.FilterSlice(issues, func(issue *Issue) (int64, bool) { if issue.Repo == nil { - repoIDs.Add(issue.RepoID) + return issue.RepoID, true } if issue.PullRequest != nil && issue.PullRequest.HeadRepo == nil { - repoIDs.Add(issue.PullRequest.HeadRepoID) + return issue.PullRequest.HeadRepoID, true } - } - return repoIDs.Values() + return 0, false + }) } // LoadRepositories loads issues' all repositories From 6cac11cb1bc4b42bc7851a59b1f3a94700c5eb84 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Wed, 10 Apr 2024 07:44:48 +0200 Subject: [PATCH 075/370] Fix line height on inline code preview (#30372) Fixes https://github.com/go-gitea/gitea/issues/30353. I don't know what causes `code-inner` to not inherit `line-height` from its direct parent `.lines-code` but instead from grandparent `.markup` even thought MDN tells me it's [inherited](https://developer.mozilla.org/en-US/docs/Web/CSS/line-height#formal_definition). This causes no negative impact on other code views, so I think it's the best solution. --- web_src/css/base.css | 1 + 1 file changed, 1 insertion(+) diff --git a/web_src/css/base.css b/web_src/css/base.css index 02bc1b7220..d188bf6f3e 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -1242,6 +1242,7 @@ overflow-menu .ui.label { white-space: pre-wrap; word-break: break-all; overflow-wrap: anywhere; + line-height: inherit; /* needed for inline code preview in markup */ } .blame .code-inner { From 50099d7af436785daf66a3a9f27bd5c009f90684 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Wed, 10 Apr 2024 08:13:22 +0200 Subject: [PATCH 076/370] Various improvements for long file and commit names (#30374) Fixes: https://github.com/go-gitea/gitea/issues/29438 This contains numerous enhancements for how large commit messages and large filenames render. Another notable change is that the file path is no longer cut off by backend at 30 chars, but rendered in full with wrapping. <img width="1329" alt="Screenshot 2024-04-09 at 21 53 57" src="https://github.com/go-gitea/gitea/assets/115237/5ccbb3d6-643a-4f60-ba79-3572b36d5182"> <hr> <img width="711" alt="Screenshot 2024-04-09 at 21 44 24" src="https://github.com/go-gitea/gitea/assets/115237/6ffe8fbb-407c-4aa7-b591-3d80daea7d57"> <hr> <img width="439" alt="Screenshot 2024-04-09 at 21 19 03" src="https://github.com/go-gitea/gitea/assets/115237/1ec7f6e9-2fd8-4841-87eb-6ca02ab9cd61"> <hr> <img width="444" alt="Screenshot 2024-04-09 at 21 18 52" src="https://github.com/go-gitea/gitea/assets/115237/70931b9e-5841-477e-b3bc-98f8d2662964"> --------- Co-authored-by: Giteabot <teabot@gitea.io> --- templates/repo/commit_page.tmpl | 4 +- templates/repo/diff/box.tmpl | 34 +++++++------- templates/repo/home.tmpl | 21 +++++---- templates/repo/view_file.tmpl | 6 +-- templates/repo/view_list.tmpl | 8 +++- web_src/css/base.css | 13 ++++++ web_src/css/modules/container.css | 23 +--------- web_src/css/repo.css | 76 +++++++++++++++++++++---------- 8 files changed, 107 insertions(+), 78 deletions(-) diff --git a/templates/repo/commit_page.tmpl b/templates/repo/commit_page.tmpl index 49a0b445b1..7fec88cb79 100644 --- a/templates/repo/commit_page.tmpl +++ b/templates/repo/commit_page.tmpl @@ -18,10 +18,10 @@ {{end}} {{end}} <div class="ui top attached header clearing segment tw-relative commit-header {{$class}}"> - <div class="tw-flex tw-mb-4 tw-flex-wrap"> + <div class="tw-flex tw-mb-4 tw-gap-1"> <h3 class="tw-mb-0 tw-flex-1"><span class="commit-summary" title="{{.Commit.Summary}}">{{RenderCommitMessage $.Context .Commit.Message ($.Repository.ComposeMetas ctx)}}</span>{{template "repo/commit_statuses" dict "Status" .CommitStatus "Statuses" .CommitStatuses}}</h3> {{if not $.PageIsWiki}} - <div> + <div class="commit-header-buttons"> <a class="ui primary tiny button" href="{{.SourcePath}}"> {{ctx.Locale.Tr "repo.diff.browse_source"}} </a> diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl index 5327b7f02c..92a3163642 100644 --- a/templates/repo/diff/box.tmpl +++ b/templates/repo/diff/box.tmpl @@ -111,7 +111,7 @@ {{$isReviewFile := and $.IsSigned $.PageIsPullFiles (not $.IsArchived) $.IsShowingAllCommits}} <div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}} tw-mt-0" id="diff-{{$file.NameHash}}" data-old-filename="{{$file.OldName}}" data-new-filename="{{$file.Name}}" {{if or ($file.ShouldBeHidden) (not $isExpandable)}}data-folded="true"{{end}}> <h4 class="diff-file-header sticky-2nd-row ui top attached header tw-font-normal tw-flex tw-items-center tw-justify-between tw-flex-wrap"> - <div class="diff-file-name tw-flex tw-items-center tw-gap-1 tw-flex-wrap"> + <div class="diff-file-name tw-flex tw-flex-1 tw-items-center tw-gap-1 tw-flex-wrap"> <button class="fold-file btn interact-bg tw-p-1{{if not $isExpandable}} tw-invisible{{end}}"> {{if $file.ShouldBeHidden}} {{svg "octicon-chevron-right" 18}} @@ -128,21 +128,23 @@ {{template "repo/diff/stats" dict "file" . "root" $}} {{end}} </div> - <span class="file tw-font-mono"><a class="muted file-link" title="{{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}}" href="#diff-{{$file.NameHash}}">{{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}}</a>{{if .IsLFSFile}} ({{ctx.Locale.Tr "repo.stored_lfs"}}){{end}}</span> - <button class="btn interact-fg tw-p-2" data-clipboard-text="{{$file.Name}}">{{svg "octicon-copy" 14}}</button> - {{if $file.IsGenerated}} - <span class="ui label">{{ctx.Locale.Tr "repo.diff.generated"}}</span> - {{end}} - {{if $file.IsVendored}} - <span class="ui label">{{ctx.Locale.Tr "repo.diff.vendored"}}</span> - {{end}} - {{if and $file.Mode $file.OldMode}} - {{$old := ctx.Locale.Tr ($file.ModeTranslationKey $file.OldMode)}} - {{$new := ctx.Locale.Tr ($file.ModeTranslationKey $file.Mode)}} - <span class="tw-ml-4 tw-font-mono">{{ctx.Locale.Tr "git.filemode.changed_filemode" $old $new}}</span> - {{else if $file.Mode}} - <span class="tw-ml-4 tw-font-mono">{{ctx.Locale.Tr ($file.ModeTranslationKey $file.Mode)}}</span> - {{end}} + <span class="file tw-flex tw-items-center tw-font-mono tw-flex-1"><a class="muted file-link" title="{{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}}" href="#diff-{{$file.NameHash}}">{{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}}</a> + {{if .IsLFSFile}} ({{ctx.Locale.Tr "repo.stored_lfs"}}){{end}} + <button class="btn interact-fg tw-p-2" data-clipboard-text="{{$file.Name}}">{{svg "octicon-copy" 14}}</button> + {{if $file.IsGenerated}} + <span class="ui label">{{ctx.Locale.Tr "repo.diff.generated"}}</span> + {{end}} + {{if $file.IsVendored}} + <span class="ui label">{{ctx.Locale.Tr "repo.diff.vendored"}}</span> + {{end}} + {{if and $file.Mode $file.OldMode}} + {{$old := ctx.Locale.Tr ($file.ModeTranslationKey $file.OldMode)}} + {{$new := ctx.Locale.Tr ($file.ModeTranslationKey $file.Mode)}} + <span class="tw-mx-2 tw-font-mono tw-whitespace-nowrap">{{ctx.Locale.Tr "git.filemode.changed_filemode" $old $new}}</span> + {{else if $file.Mode}} + <span class="tw-mx-2 tw-font-mono tw-whitespace-nowrap">{{ctx.Locale.Tr ($file.ModeTranslationKey $file.Mode)}}</span> + {{end}} + </span> </div> <div class="diff-file-header-actions tw-flex tw-items-center tw-gap-1 tw-flex-wrap"> {{if $showFileViewToggle}} diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index ab37f7e318..e18a0aec17 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -50,8 +50,11 @@ </div> {{end}} {{template "repo/sub_menu" .}} + {{$n := len .TreeNames}} + {{$l := Eval $n "-" 1}} + {{$isHomepage := (eq $n 0)}} <div class="repo-button-row"> - <div class="tw-flex tw-items-center tw-flex-wrap tw-gap-y-2"> + <div class="tw-flex tw-items-center tw-gap-y-2"> {{template "repo/branch_dropdown" dict "root" . "ContainerClasses" "tw-mr-1"}} {{if and .CanCompareOrPull .IsViewBranch (not .Repository.IsArchived)}} {{$cmpBranch := ""}} @@ -66,9 +69,7 @@ </a> {{end}} <!-- Show go to file and breadcrumbs if not on home page --> - {{$n := len .TreeNames}} - {{$l := Eval $n "-" 1}} - {{if eq $n 0}} + {{if $isHomepage}} <a href="{{.Repository.Link}}/find/{{.BranchNameSubURL}}" class="ui compact basic button">{{ctx.Locale.Tr "repo.find_file.go_to_file"}}</a> {{end}} @@ -92,20 +93,20 @@ </button> {{end}} - {{if and (eq $n 0) (.Repository.IsTemplate)}} + {{if and $isHomepage (.Repository.IsTemplate)}} <a role="button" class="ui primary compact button" href="{{AppSubUrl}}/repo/create?template_id={{.Repository.ID}}"> {{ctx.Locale.Tr "repo.use_template"}} </a> {{end}} - {{if ne $n 0}} + {{if (not $isHomepage)}} <span class="breadcrumb repo-path tw-ml-1"> <a class="section" href="{{.RepoLink}}/src/{{.BranchNameSubURL}}" title="{{.Repository.Name}}">{{StringUtils.EllipsisString .Repository.Name 30}}</a> {{- range $i, $v := .TreeNames -}} <span class="breadcrumb-divider">/</span> {{- if eq $i $l -}} - <span class="active section" title="{{$v}}">{{StringUtils.EllipsisString $v 30}}</span> + <span class="active section" title="{{$v}}">{{$v}}</span> {{- else -}} - {{$p := index $.Paths $i}}<span class="section"><a href="{{$.BranchLink}}/{{PathEscapeSegments $p}}" title="{{$v}}">{{StringUtils.EllipsisString $v 30}}</a></span> + {{$p := index $.Paths $i}}<span class="section"><a href="{{$.BranchLink}}/{{PathEscapeSegments $p}}" title="{{$v}}">{{$v}}</a></span> {{- end -}} {{- end -}} </span> @@ -113,7 +114,7 @@ </div> <div class="tw-flex tw-items-center"> <!-- Only show clone panel in repository home page --> - {{if eq $n 0}} + {{if $isHomepage}} <div class="clone-panel ui action tiny input"> {{template "repo/clone_buttons" .}} <button class="ui small jump dropdown icon button" data-tooltip-content="{{ctx.Locale.Tr "repo.more_operations"}}"> @@ -136,7 +137,7 @@ </div> {{template "repo/cite/cite_modal" .}} {{end}} - {{if and (ne $n 0) (not .IsViewFile) (not .IsBlame)}} + {{if and (not $isHomepage) (not .IsViewFile) (not .IsBlame)}} <a class="ui button" href="{{.RepoLink}}/commits/{{.BranchNameSubURL}}/{{.TreePath | PathEscapeSegments}}"> {{svg "octicon-history" 16 "tw-mr-2"}}{{ctx.Locale.Tr "repo.file_history"}} </a> diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl index 9c5bd9094d..0683004718 100644 --- a/templates/repo/view_file.tmpl +++ b/templates/repo/view_file.tmpl @@ -11,13 +11,13 @@ {{end}} {{if not .ReadmeInList}} - <div id="repo-file-commit-box" class="ui top attached header list-header tw-mb-4"> - <div> + <div id="repo-file-commit-box" class="ui top attached header list-header tw-mb-4 tw-flex tw-justify-between"> + <div class="latest-commit"> {{template "repo/latest_commit" .}} </div> {{if .LatestCommit}} {{if .LatestCommit.Committer}} - <div class="ui text grey right age"> + <div class="text grey age"> {{TimeSince .LatestCommit.Committer.When ctx.Locale}} </div> {{end}} diff --git a/templates/repo/view_list.tmpl b/templates/repo/view_list.tmpl index 7c463c50a6..fb257bd474 100644 --- a/templates/repo/view_list.tmpl +++ b/templates/repo/view_list.tmpl @@ -1,8 +1,12 @@ <table id="repo-files-table" class="ui single line table tw-mt-0" {{if .HasFilesWithoutLatestCommit}}hx-indicator="tr.notready td.message span" hx-trigger="load" hx-swap="morph" hx-post="{{.LastCommitLoaderURL}}"{{end}}> <thead> <tr class="commit-list"> - <th colspan="2"> - {{template "repo/latest_commit" .}} + <th class="tw-overflow-hidden" colspan="2"> + <div class="tw-flex"> + <div class="latest-commit"> + {{template "repo/latest_commit" .}} + </div> + </div> </th> <th class="text grey right age">{{if .LatestCommit}}{{if .LatestCommit.Committer}}{{TimeSince .LatestCommit.Committer.When ctx.Locale}}{{end}}{{end}}</th> </tr> diff --git a/web_src/css/base.css b/web_src/css/base.css index d188bf6f3e..c6a22a5dc4 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -25,6 +25,19 @@ --tab-size: 4; --checkbox-size: 15px; /* height and width of checkbox and radio inputs */ --page-spacing: 16px; /* space between page elements */ + --page-margin-x: 32px; /* minimum space on left and right side of page */ +} + +@media (min-width: 768px) and (max-width: 1200px) { + :root { + --page-margin-x: 16px; + } +} + +@media (max-width: 767.98px) { + :root { + --page-margin-x: 8px; + } } :root * { diff --git a/web_src/css/modules/container.css b/web_src/css/modules/container.css index dc854f89d0..f394d6c06d 100644 --- a/web_src/css/modules/container.css +++ b/web_src/css/modules/container.css @@ -49,30 +49,11 @@ /* overwrite width of containers inside the main page content div (div with class "page-content") */ .page-content .ui.ui.ui.container:not(.fluid) { width: 1280px; - max-width: calc(100% - 64px); + max-width: calc(100% - calc(2 * var(--page-margin-x))); margin-left: auto; margin-right: auto; } .ui.container.fluid.padded { - padding: 0 32px; -} - -/* enable fluid page widths for medium size viewports */ -@media (min-width: 768px) and (max-width: 1200px) { - .page-content .ui.ui.ui.container:not(.fluid) { - max-width: calc(100% - 32px); - } - .ui.container.fluid.padded { - padding: 0 16px; - } -} - -@media (max-width: 767.98px) { - .page-content .ui.ui.ui.container:not(.fluid) { - max-width: calc(100% - 16px); - } - .ui.container.fluid.padded { - padding: 0 8px; - } + padding: 0 var(--page-margin-x); } diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 8b91b599e7..c579745238 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -177,12 +177,44 @@ } } -.repository.file.list .repo-path { - word-break: break-word; +.commit-summary { + flex: 1; + overflow-wrap: anywhere; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; } -.repository.file.list #repo-files-table { - table-layout: fixed; +.commit-header .commit-summary, +td .commit-summary { + white-space: normal; +} + +.latest-commit { + display: flex; + flex: 1; + align-items: center; + overflow: hidden; + text-overflow: ellipsis; +} + +@media (max-width: 767.98px) { + .latest-commit .sha { + display: none; + } + .latest-commit .commit-summary { + margin-left: 8px; + } +} + +.repo-path { + display: flex; + overflow-wrap: anywhere; +} + +/* this is what limits the commit table width to a value that works on all viewport sizes */ +#repo-files-table th:first-of-type { + max-width: calc(calc(min(100vw, 1280px)) - 145px - calc(2 * var(--page-margin-x))); } .repository.file.list #repo-files-table thead th { @@ -262,7 +294,6 @@ } .repository.file.list #repo-files-table td.age { - width: 120px; color: var(--color-text-light-1); } @@ -1219,10 +1250,6 @@ margin: 0; } -.repository #commits-table td.message { - text-overflow: unset; -} - .repository #commits-table.ui.basic.striped.table tbody tr:nth-child(2n) { background-color: var(--color-light) !important; } @@ -2114,6 +2141,20 @@ padding-bottom: 0 !important; } +.commit-header-buttons { + display: flex; + gap: 4px; + align-items: flex-start; + white-space: nowrap; +} + +@media (max-width: 767.98px) { + .commit-header-buttons { + flex-direction: column; + align-items: stretch; + } +} + .settings.webhooks .list > .item:not(:first-child), .settings.githooks .list > .item:not(:first-child), .settings.actions .list > .item:not(:first-child) { @@ -2346,7 +2387,7 @@ tbody.commit-list { .author-wrapper { overflow: hidden; text-overflow: ellipsis; - max-width: calc(100% - 50px); + max-width: 100%; display: inline-block; vertical-align: middle; } @@ -2371,10 +2412,6 @@ tbody.commit-list { tr.commit-list { width: 100%; } - th .message-wrapper { - display: block; - max-width: calc(100vw - 70px); - } .author-wrapper { max-width: 80px; } @@ -2384,27 +2421,18 @@ tbody.commit-list { tr.commit-list { width: 723px; } - th .message-wrapper { - max-width: 120px; - } } @media (min-width: 992px) and (max-width: 1200px) { tr.commit-list { width: 933px; } - th .message-wrapper { - max-width: 350px; - } } @media (min-width: 1201px) { tr.commit-list { width: 1127px; } - th .message-wrapper { - max-width: 525px; - } } .commit-list .commit-status-link { @@ -2732,7 +2760,7 @@ tbody.commit-list { .repository.file.list #repo-files-table .entry td.message, .repository.file.list #repo-files-table .commit-list td.message, .repository.file.list #repo-files-table .entry span.commit-summary, - .repository.file.list #repo-files-table .commit-list span.commit-summary { + .repository.file.list #repo-files-table .commit-list tr span.commit-summary { display: none !important; } .repository.view.issue .comment-list .timeline, From c1f76aea45f11e1d5ae22c047cf3bda9c681de8d Mon Sep 17 00:00:00 2001 From: Rafael <git@rafael.ovh> Date: Wed, 10 Apr 2024 18:49:57 +0100 Subject: [PATCH 077/370] Use raw Wiki links for non-renderable Wiki files (#30273) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In Wiki pages, short-links created to local Wiki files were always expanded as regular Wiki Links. In particular, if a link wanted to point to a file that Gitea doesn't know how to render (e.g, a .zip file), a user following the link would be silently redirected to the Wiki's home page. This change makes short-links* in Wiki pages be expanded to raw wiki links, so these local wiki files may be accessed without manually accessing their URL. * only short-links ending in a file extension that isn't renderable are affected. Closes #27121. Signed-off-by: Rafael Girão <rafael.s.girao@tecnico.ulisboa.pt> Co-authored-by: silverwind <me@silverwind.io> --- modules/markup/html.go | 22 +++++++++++++--- modules/markup/html_test.go | 12 +++++++++ modules/markup/markdown/markdown_test.go | 24 +++++++++--------- modules/markup/markdown/transform_link.go | 13 +++++++++- routers/web/repo/wiki_test.go | 13 +++++----- .../81/a1c039774e337621609336c0e44ed9f92278f7 | Bin 0 -> 68 bytes .../91/dc55f9de16a558e859123f2b99668469b1a1dc | Bin 0 -> 234 bytes .../a5/bbc0fd39a696feabed2d4cccaf05abbcaf3b02 | 1 + .../cf/19952a40b92eb2f86689146a65ac2d87c0818a | Bin 0 -> 255 bytes .../e1/6da91326b845f1ba86a7df0a67db352f96dcb0 | Bin 0 -> 149 bytes .../user2/repo1.wiki.git/refs/heads/master | 2 +- tests/integration/git_clone_wiki_test.go | 1 + 12 files changed, 65 insertions(+), 23 deletions(-) create mode 100644 tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/81/a1c039774e337621609336c0e44ed9f92278f7 create mode 100644 tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/91/dc55f9de16a558e859123f2b99668469b1a1dc create mode 100644 tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/a5/bbc0fd39a696feabed2d4cccaf05abbcaf3b02 create mode 100644 tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/cf/19952a40b92eb2f86689146a65ac2d87c0818a create mode 100644 tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/e1/6da91326b845f1ba86a7df0a67db352f96dcb0 diff --git a/modules/markup/html.go b/modules/markup/html.go index 56aa1cb49c..cef643bf18 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -709,7 +709,8 @@ func shortLinkProcessor(ctx *RenderContext, node *html.Node) { name += tail image := false - switch ext := filepath.Ext(link); ext { + ext := filepath.Ext(link) + switch ext { // fast path: empty string, ignore case "": // leave image as false @@ -767,11 +768,26 @@ func shortLinkProcessor(ctx *RenderContext, node *html.Node) { } } else { if !absoluteLink { + var base string if ctx.IsWiki { - link = util.URLJoin(ctx.Links.WikiLink(), link) + switch ext { + case "": + // no file extension, create a regular wiki link + base = ctx.Links.WikiLink() + default: + // we have a file extension: + // return a regular wiki link if it's a renderable file (extension), + // raw link otherwise + if Type(link) != "" { + base = ctx.Links.WikiLink() + } else { + base = ctx.Links.WikiRawLink() + } + } } else { - link = util.URLJoin(ctx.Links.SrcLink(), link) + base = ctx.Links.SrcLink() } + link = util.URLJoin(base, link) } childNode.Type = html.TextNode childNode.Data = name diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go index 55de65d196..916e74fb62 100644 --- a/modules/markup/html_test.go +++ b/modules/markup/html_test.go @@ -427,6 +427,10 @@ func TestRender_ShortLinks(t *testing.T) { otherImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "Link+Other.jpg") encodedImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "Link+%23.jpg") notencodedImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "some", "path", "Link+#.jpg") + renderableFileURL := util.URLJoin(tree, "markdown_file.md") + renderableFileURLWiki := util.URLJoin(markup.TestRepoURL, "wiki", "markdown_file.md") + unrenderableFileURL := util.URLJoin(tree, "file.zip") + unrenderableFileURLWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "file.zip") favicon := "http://google.com/favicon.ico" test( @@ -481,6 +485,14 @@ func TestRender_ShortLinks(t *testing.T) { "[[Link]] [[Other Link]] [[Link?]]", `<p><a href="`+url+`" rel="nofollow">Link</a> <a href="`+otherURL+`" rel="nofollow">Other Link</a> <a href="`+encodedURL+`" rel="nofollow">Link?</a></p>`, `<p><a href="`+urlWiki+`" rel="nofollow">Link</a> <a href="`+otherURLWiki+`" rel="nofollow">Other Link</a> <a href="`+encodedURLWiki+`" rel="nofollow">Link?</a></p>`) + test( + "[[markdown_file.md]]", + `<p><a href="`+renderableFileURL+`" rel="nofollow">markdown_file.md</a></p>`, + `<p><a href="`+renderableFileURLWiki+`" rel="nofollow">markdown_file.md</a></p>`) + test( + "[[file.zip]]", + `<p><a href="`+unrenderableFileURL+`" rel="nofollow">file.zip</a></p>`, + `<p><a href="`+unrenderableFileURLWiki+`" rel="nofollow">file.zip</a></p>`) test( "[[Link #.jpg]]", `<p><a href="`+encodedImgurl+`" rel="nofollow"><img src="`+encodedImgurl+`" title="Link #.jpg" alt="Link #.jpg"/></a></p>`, diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index a9c9024982..d9b67e43af 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -653,9 +653,9 @@ space</p> Expected: `<p>space @mention-user<br/> /just/a/path.bin<br/> <a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/> -<a href="/wiki/file.bin" rel="nofollow">local link</a><br/> +<a href="/wiki/raw/file.bin" rel="nofollow">local link</a><br/> <a href="https://example.com" rel="nofollow">remote link</a><br/> -<a href="/wiki/file.bin" rel="nofollow">local link</a><br/> +<a href="/wiki/raw/file.bin" rel="nofollow">local link</a><br/> <a href="https://example.com" rel="nofollow">remote link</a><br/> <a href="/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="/wiki/raw/image.jpg" alt="local image"/></a><br/> <a href="/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/wiki/raw/path/file" alt="local image"/></a><br/> @@ -711,9 +711,9 @@ space</p> Expected: `<p>space @mention-user<br/> /just/a/path.bin<br/> <a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/> -<a href="https://gitea.io/wiki/file.bin" rel="nofollow">local link</a><br/> +<a href="https://gitea.io/wiki/raw/file.bin" rel="nofollow">local link</a><br/> <a href="https://example.com" rel="nofollow">remote link</a><br/> -<a href="https://gitea.io/wiki/file.bin" rel="nofollow">local link</a><br/> +<a href="https://gitea.io/wiki/raw/file.bin" rel="nofollow">local link</a><br/> <a href="https://example.com" rel="nofollow">remote link</a><br/> <a href="https://gitea.io/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="https://gitea.io/wiki/raw/image.jpg" alt="local image"/></a><br/> <a href="https://gitea.io/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="https://gitea.io/wiki/raw/path/file" alt="local image"/></a><br/> @@ -769,9 +769,9 @@ space</p> Expected: `<p>space @mention-user<br/> /just/a/path.bin<br/> <a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/> -<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/> +<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/> <a href="https://example.com" rel="nofollow">remote link</a><br/> -<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/> +<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/> <a href="https://example.com" rel="nofollow">remote link</a><br/> <a href="/relative/path/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/image.jpg" alt="local image"/></a><br/> <a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/> @@ -829,9 +829,9 @@ space</p> Expected: `<p>space @mention-user<br/> /just/a/path.bin<br/> <a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/> -<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/> +<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/> <a href="https://example.com" rel="nofollow">remote link</a><br/> -<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/> +<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/> <a href="https://example.com" rel="nofollow">remote link</a><br/> <a href="/relative/path/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/image.jpg" alt="local image"/></a><br/> <a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/> @@ -889,9 +889,9 @@ space</p> Expected: `<p>space @mention-user<br/> /just/a/path.bin<br/> <a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/> -<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/> +<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/> <a href="https://example.com" rel="nofollow">remote link</a><br/> -<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/> +<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/> <a href="https://example.com" rel="nofollow">remote link</a><br/> <a href="/relative/path/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/image.jpg" alt="local image"/></a><br/> <a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/> @@ -951,9 +951,9 @@ space</p> Expected: `<p>space @mention-user<br/> /just/a/path.bin<br/> <a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/> -<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/> +<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/> <a href="https://example.com" rel="nofollow">remote link</a><br/> -<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/> +<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/> <a href="https://example.com" rel="nofollow">remote link</a><br/> <a href="/relative/path/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/image.jpg" alt="local image"/></a><br/> <a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/> diff --git a/modules/markup/markdown/transform_link.go b/modules/markup/markdown/transform_link.go index 8bf19ea4ce..7e305b74bc 100644 --- a/modules/markup/markdown/transform_link.go +++ b/modules/markup/markdown/transform_link.go @@ -4,6 +4,8 @@ package markdown import ( + "path/filepath" + "code.gitea.io/gitea/modules/markup" giteautil "code.gitea.io/gitea/modules/util" @@ -18,7 +20,16 @@ func (g *ASTTransformer) transformLink(ctx *markup.RenderContext, v *ast.Link, r if !isAnchorFragment && !markup.IsFullURLBytes(link) { base := ctx.Links.Base if ctx.IsWiki { - base = ctx.Links.WikiLink() + if filepath.Ext(string(link)) == "" { + // This link doesn't have a file extension - assume a regular wiki link + base = ctx.Links.WikiLink() + } else if markup.Type(string(link)) != "" { + // If it's a file type we can render, use a regular wiki link + base = ctx.Links.WikiLink() + } else { + // Otherwise, use a raw link instead + base = ctx.Links.WikiRawLink() + } } else if ctx.Links.HasBranchInfo() { base = ctx.Links.SrcLink() } diff --git a/routers/web/repo/wiki_test.go b/routers/web/repo/wiki_test.go index 2894c06fbd..4602dcfeb4 100644 --- a/routers/web/repo/wiki_test.go +++ b/routers/web/repo/wiki_test.go @@ -200,12 +200,13 @@ func TestDeleteWikiPagePost(t *testing.T) { func TestWikiRaw(t *testing.T) { for filepath, filetype := range map[string]string{ - "jpeg.jpg": "image/jpeg", - "images/jpeg.jpg": "image/jpeg", - "Page With Spaced Name": "text/plain; charset=utf-8", - "Page-With-Spaced-Name": "text/plain; charset=utf-8", - "Page With Spaced Name.md": "", // there is no "Page With Spaced Name.md" in repo - "Page-With-Spaced-Name.md": "text/plain; charset=utf-8", + "jpeg.jpg": "image/jpeg", + "images/jpeg.jpg": "image/jpeg", + "files/Non-Renderable-File.zip": "application/octet-stream", + "Page With Spaced Name": "text/plain; charset=utf-8", + "Page-With-Spaced-Name": "text/plain; charset=utf-8", + "Page With Spaced Name.md": "", // there is no "Page With Spaced Name.md" in repo + "Page-With-Spaced-Name.md": "text/plain; charset=utf-8", } { unittest.PrepareTestEnv(t) diff --git a/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/81/a1c039774e337621609336c0e44ed9f92278f7 b/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/81/a1c039774e337621609336c0e44ed9f92278f7 new file mode 100644 index 0000000000000000000000000000000000000000..17a5547da8286e051f08cb79be1169efacb59654 GIT binary patch literal 68 zcmV-K0K5Nq0V^p=O;s>8WH2-^Ff%bx@XOEB4NA>RNi9lD%1PCA%gjmDtI8~3c$m9V aSZ#;v$6am9?{lT!Hr1bYX9EC2Q5Lqqq8?@d literal 0 HcmV?d00001 diff --git a/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/91/dc55f9de16a558e859123f2b99668469b1a1dc b/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/91/dc55f9de16a558e859123f2b99668469b1a1dc new file mode 100644 index 0000000000000000000000000000000000000000..8390a40c0805716854172c1d6c26de3e3845cbf6 GIT binary patch literal 234 zcmV<G02Tju0V^p=O;s>5w`4FhFfcPQQSivmP1VayVR+T_r@efUH~XP%EAKClN_3cu z?N&pT1SF=X>V{{QWaxV40+}GyMzKeJyfpDk%lIT}wrp;^tlw3e#TcrC3lfu4Q*`|j zAvP5KNeVoZ(l^mZfMKqov;3mR-Ln*+dP4J3i<1)zQd1P%GIMY`$HV{#6w-hyiWwRg z9<VI;GcHq1m~3|7iQmniN)_KB@|hqv7BiGwU2xrY=g#+4E2sBuUodk+f5??MsBKvV ksp)!I1?dch6Q#ejryZ9Nl{m=GDabf~H^at102VQB$tL$~r2qf` literal 0 HcmV?d00001 diff --git a/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/a5/bbc0fd39a696feabed2d4cccaf05abbcaf3b02 b/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/a5/bbc0fd39a696feabed2d4cccaf05abbcaf3b02 new file mode 100644 index 0000000000..94312d3db6 --- /dev/null +++ b/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/a5/bbc0fd39a696feabed2d4cccaf05abbcaf3b02 @@ -0,0 +1 @@ +x��Kn� D��죱�v�EQ��~n�@3F���r�\,d��^�T��S�ϏGj|��K+D���� $2`�4��Y��Y�u{�Xho\���u4E;k- P4�Q^H�84��lk.��i�_��|g�V�v��=����|�-U�q8�;�ZJ��,��Nn�_����0�a�3���ҿ T�mķ�q�1m�؍b�^���z��/����_�5�zR'-'�~�tl� \ No newline at end of file diff --git a/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/cf/19952a40b92eb2f86689146a65ac2d87c0818a b/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/cf/19952a40b92eb2f86689146a65ac2d87c0818a new file mode 100644 index 0000000000000000000000000000000000000000..b384e5c72edc4f93a1c15a2ab088e39f7d12176b GIT binary patch literal 255 zcmV<b0094Z0cDOsZp0uAMZ4w{UUgGV5|RL6R8`Ye_j3aSCPB)C2*_NhN9n~%r`^>H z%ir?<em352p}^4Vr;><3b7zI{+7Xv1#6*+OydQjTw3c!jr8XSv4cjr%R-khhg>l*l zr^xF;Dc(^hq!&uiByGp1(cmN)9%YFMuIQ0g_z3CiGs0_n$R;;)NEk1L>=tZnjx}Tx zvDwQTaK*VC)hIN)bhVg$AQ$=<HivTg3yk;W*Qr&d?yHkmCwq4ewz!=tx}$_<C0L`y z6?~}UGbGA8*%IyqJI=(|m3%(KQp%psZCf8KhiNK6JI7O1gg?95L(T`~wpYC8>>Ccm FYv@Vae2V}8 literal 0 HcmV?d00001 diff --git a/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/e1/6da91326b845f1ba86a7df0a67db352f96dcb0 b/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/e1/6da91326b845f1ba86a7df0a67db352f96dcb0 new file mode 100644 index 0000000000000000000000000000000000000000..da281ff7916dcb6dac5154f4d87bab9af4428b29 GIT binary patch literal 149 zcmV;G0BZku0ZYosPf{?nG+_wvW@Zs#U|`^2_|;Mq!FtVSryP){0>tbLG7KL1xv6@& zDWM^p49pR8S<^tcw1S&~k>v$50|QG6P+4%;hZE<0Lp3~n{GUGJI(b4TjA7BFo{(0a z85@+ufyOg3$uZ-yKmw?rfq@Z-mo$P{aO+qh)}dJy;LXYgQpN~`zCb!2#9;scqk${9 Dp4URN literal 0 HcmV?d00001 diff --git a/tests/gitea-repositories-meta/user2/repo1.wiki.git/refs/heads/master b/tests/gitea-repositories-meta/user2/repo1.wiki.git/refs/heads/master index 38984b12b7..b352f15003 100644 --- a/tests/gitea-repositories-meta/user2/repo1.wiki.git/refs/heads/master +++ b/tests/gitea-repositories-meta/user2/repo1.wiki.git/refs/heads/master @@ -1 +1 @@ -0dca5bd9b5d7ef937710e056f575e86c0184ba85 +a5bbc0fd39a696feabed2d4cccaf05abbcaf3b02 diff --git a/tests/integration/git_clone_wiki_test.go b/tests/integration/git_clone_wiki_test.go index d7949dfe25..ef662300f3 100644 --- a/tests/integration/git_clone_wiki_test.go +++ b/tests/integration/git_clone_wiki_test.go @@ -45,6 +45,7 @@ func TestRepoCloneWiki(t *testing.T) { assertFileExist(t, filepath.Join(dstPath, "Page-With-Image.md")) assertFileExist(t, filepath.Join(dstPath, "Page-With-Spaced-Name.md")) assertFileExist(t, filepath.Join(dstPath, "images")) + assertFileExist(t, filepath.Join(dstPath, "files/Non-Renderable-File.zip")) assertFileExist(t, filepath.Join(dstPath, "jpeg.jpg")) }) }) From e7ecdba4933f4ff5e6e2b24cdcea8b76f486966a Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Wed, 10 Apr 2024 22:29:05 +0200 Subject: [PATCH 078/370] Minor color tweaks (#30397) New approach to color shades: Stem all colors off the body color `#1b1f23` using [this](https://pinetools.com/darken-color) and [this](https://pinetools.com/lighten-color) tool. The differences are very subtle, but it will give a more consistent color scheme until https://github.com/go-gitea/gitea/issues/30160. <img width="1342" alt="Screenshot 2024-04-10 at 20 44 16" src="https://github.com/go-gitea/gitea/assets/115237/75b65797-2521-46ea-91d8-d76f77b591b1"> --- web_src/css/themes/theme-gitea-dark.css | 128 +++++++++++------------ web_src/css/themes/theme-gitea-light.css | 18 ++-- 2 files changed, 73 insertions(+), 73 deletions(-) diff --git a/web_src/css/themes/theme-gitea-dark.css b/web_src/css/themes/theme-gitea-dark.css index c74f334c2d..7bf2c982c6 100644 --- a/web_src/css/themes/theme-gitea-dark.css +++ b/web_src/css/themes/theme-gitea-dark.css @@ -30,45 +30,45 @@ --color-primary-alpha-90: #4183c4e1; --color-primary-hover: var(--color-primary-light-1); --color-primary-active: var(--color-primary-light-2); - --color-secondary: #3b444a; - --color-secondary-dark-1: #424b51; - --color-secondary-dark-2: #4a545b; - --color-secondary-dark-3: #59646c; - --color-secondary-dark-4: #6b7681; - --color-secondary-dark-5: #78858f; - --color-secondary-dark-6: #87929d; - --color-secondary-dark-7: #939ea9; - --color-secondary-dark-8: #a1acb4; - --color-secondary-dark-9: #aab3bc; - --color-secondary-dark-10: #b6bfc8; - --color-secondary-dark-11: #c2cbd3; - --color-secondary-dark-12: #ccd4dc; - --color-secondary-dark-13: #cfd7df; - --color-secondary-light-1: #2e353b; - --color-secondary-light-2: #2b353e; - --color-secondary-light-3: #1c2227; - --color-secondary-light-4: #161b1f; - --color-secondary-alpha-10: #3b444a19; - --color-secondary-alpha-20: #3b444a33; - --color-secondary-alpha-30: #3b444a4b; - --color-secondary-alpha-40: #3b444a66; - --color-secondary-alpha-50: #3b444a80; - --color-secondary-alpha-60: #3b444a99; - --color-secondary-alpha-70: #3b444ab3; - --color-secondary-alpha-80: #3b444acc; - --color-secondary-alpha-90: #3b444ae1; + --color-secondary: #3b444c; + --color-secondary-dark-1: #414b54; + --color-secondary-dark-2: #49545f; + --color-secondary-dark-3: #576471; + --color-secondary-dark-4: #677685; + --color-secondary-dark-5: #758594; + --color-secondary-dark-6: #8392a0; + --color-secondary-dark-7: #929eab; + --color-secondary-dark-8: #a2acb7; + --color-secondary-dark-9: #a9b3bd; + --color-secondary-dark-10: #b7bfc7; + --color-secondary-dark-11: #c5cbd2; + --color-secondary-dark-12: #cfd4da; + --color-secondary-dark-13: #d2d7dc; + --color-secondary-light-1: #313940; + --color-secondary-light-2: #292f35; + --color-secondary-light-3: #1d2226; + --color-secondary-light-4: #171b1e; + --color-secondary-alpha-10: #3b444c19; + --color-secondary-alpha-20: #3b444c33; + --color-secondary-alpha-30: #3b444c4b; + --color-secondary-alpha-40: #3b444c66; + --color-secondary-alpha-50: #3b444c80; + --color-secondary-alpha-60: #3b444c99; + --color-secondary-alpha-70: #3b444cb3; + --color-secondary-alpha-80: #3b444ccc; + --color-secondary-alpha-90: #3b444ce1; --color-secondary-button: var(--color-secondary-dark-4); --color-secondary-hover: var(--color-secondary-dark-3); --color-secondary-active: var(--color-secondary-dark-2); /* console colors - used for actions console and console files */ - --color-console-fg: #f8f8f9; - --color-console-fg-subtle: #bec4c8; + --color-console-fg: #f7f8f9; + --color-console-fg-subtle: #bdc4cc; --color-console-bg: #171b1e; --color-console-border: #2e353b; - --color-console-hover-bg: #292d31; + --color-console-hover-bg: #272d33; --color-console-active-bg: #2e353b; - --color-console-menu-bg: #252b30; - --color-console-menu-border: #424b51; + --color-console-menu-bg: #262b31; + --color-console-menu-border: #414b55; /* named colors */ --color-red: #cc4848; --color-orange: #cc580c; @@ -122,7 +122,7 @@ --color-brown-dark-2: #835b42; --color-black-dark-2: #272930; /* ansi colors used for actions console and console files */ - --color-ansi-black: #1d2328; + --color-ansi-black: #1e2327; --color-ansi-red: #cc4848; --color-ansi-green: #87ab63; --color-ansi-yellow: #cc9903; @@ -139,8 +139,8 @@ --color-ansi-bright-cyan: #00b6ad; --color-ansi-bright-white: var(--color-console-fg); /* other colors */ - --color-grey: #384147; - --color-grey-light: #828f99; + --color-grey: #384149; + --color-grey-light: #818f9e; --color-gold: #b1983b; --color-white: #ffffff; --color-diff-removed-word-bg: #6f3333; @@ -180,55 +180,55 @@ --color-orange-badge-hover-bg: #f2711c4d; --color-git: #f05133; /* target-based colors */ - --color-body: #1c1f25; + --color-body: #1b1f23; --color-box-header: #1a1d1f; --color-box-body: #14171a; - --color-box-body-highlight: #1c2227; - --color-text-dark: #f8f8f9; - --color-text: #d1d5d8; - --color-text-light: #bdc3c7; - --color-text-light-1: #a8afb5; - --color-text-light-2: #929ba2; - --color-text-light-3: #7c8790; + --color-box-body-highlight: #1e2226; + --color-text-dark: #f7f8f9; + --color-text: #d0d5da; + --color-text-light: #bcc3cb; + --color-text-light-1: #a5afb9; + --color-text-light-2: #8f9ba8; + --color-text-light-3: #788797; --color-footer: var(--color-nav-bg); - --color-timeline: #353c42; + --color-timeline: #343c44; --color-input-text: var(--color-text-dark); - --color-input-background: #151a1e; - --color-input-toggle-background: #2e353b; + --color-input-background: #171a1e; + --color-input-toggle-background: #2e353c; --color-input-border: var(--color-secondary); --color-input-border-hover: var(--color-secondary-dark-1); --color-light: #00001728; --color-light-mimic-enabled: rgba(0, 0, 0, calc(40 / 255 * 222 / 255 / var(--opacity-disabled))); - --color-light-border: #e8e8ff28; - --color-hover: #e8e8ff19; - --color-active: #e8e8ff24; - --color-menu: #151a1e; - --color-card: #151a1e; - --color-markup-table-row: #e8e8ff0f; - --color-markup-code-block: #e8e8ff12; - --color-markup-code-inline: #e8e8ff28; - --color-button: #151a1e; + --color-light-border: #e8f3ff28; + --color-hover: #e8f3ff19; + --color-active: #e8f3ff24; + --color-menu: #171a1e; + --color-card: #171a1e; + --color-markup-table-row: #e8f3ff0f; + --color-markup-code-block: #e8f3ff12; + --color-markup-code-inline: #e8f3ff28; + --color-button: #171a1e; --color-code-bg: #14171a; --color-shadow: #00001758; - --color-secondary-bg: #2f3138; - --color-expand-button: #2b353e; + --color-secondary-bg: #2a3137; + --color-expand-button: #2f363d; --color-placeholder-text: var(--color-text-light-3); --color-editor-line-highlight: var(--color-primary-light-5); --color-project-board-bg: var(--color-secondary-light-2); --color-caret: var(--color-text); /* should ideally be --color-text-dark, see #15651 */ - --color-reaction-bg: #e8e8ff12; + --color-reaction-bg: #e8f3ff12; --color-reaction-hover-bg: var(--color-primary-light-4); --color-reaction-active-bg: var(--color-primary-light-5); - --color-tooltip-text: #fafafb; - --color-tooltip-bg: #000017f0; - --color-nav-bg: #16191c; + --color-tooltip-text: #f9fafb; + --color-tooltip-bg: #000b17f0; + --color-nav-bg: #16191d; --color-nav-hover-bg: var(--color-secondary-light-1); --color-nav-text: var(--color-text); --color-secondary-nav-bg: #181c20; --color-label-text: var(--color-text); - --color-label-bg: #73828e4b; - --color-label-hover-bg: #73828ea0; - --color-label-active-bg: #73828eff; + --color-label-bg: #7282924b; + --color-label-hover-bg: #728292a0; + --color-label-active-bg: #728292ff; --color-accent: var(--color-primary-light-1); --color-small-accent: var(--color-primary-light-5); --color-highlight-fg: #87651e; diff --git a/web_src/css/themes/theme-gitea-light.css b/web_src/css/themes/theme-gitea-light.css index 01dd8ba4f7..dfccd37647 100644 --- a/web_src/css/themes/theme-gitea-light.css +++ b/web_src/css/themes/theme-gitea-light.css @@ -61,14 +61,14 @@ --color-secondary-hover: var(--color-secondary-dark-5); --color-secondary-active: var(--color-secondary-dark-6); /* console colors - used for actions console and console files */ - --color-console-fg: #f8f8f9; - --color-console-fg-subtle: #bec4c8; + --color-console-fg: #f7f8f9; + --color-console-fg-subtle: #bdc4cc; --color-console-bg: #171b1e; --color-console-border: #2e353b; - --color-console-hover-bg: #292d31; + --color-console-hover-bg: #272d33; --color-console-active-bg: #2e353b; - --color-console-menu-bg: #252b30; - --color-console-menu-border: #424b51; + --color-console-menu-bg: #262b31; + --color-console-menu-border: #414b55; /* named colors */ --color-red: #db2828; --color-orange: #f2711c; @@ -81,7 +81,7 @@ --color-purple: #a333c8; --color-pink: #e03997; --color-brown: #a5673f; - --color-black: #191c1d; + --color-black: #1d2328; /* light variants - produced via Sass scale-color(color, $lightness: +25%) */ --color-red-light: #e45e5e; --color-orange-light: #f59555; @@ -94,7 +94,7 @@ --color-purple-light: #bb64d8; --color-pink-light: #e86bb1; --color-brown-light: #c58b66; - --color-black-light: #525558; + --color-black-light: #4b5b68; /* dark 1 variants - produced via Sass scale-color(color, $lightness: -10%) */ --color-red-dark-1: #c82121; --color-orange-dark-1: #e6630d; @@ -107,7 +107,7 @@ --color-purple-dark-1: #932eb4; --color-pink-dark-1: #db228a; --color-brown-dark-1: #955d39; - --color-black-dark-1: #16191c; + --color-black-dark-1: #2c3339; /* dark 2 variants - produced via Sass scale-color(color, $lightness: -20%) */ --color-red-dark-2: #b11e1e; --color-orange-dark-2: #cc580c; @@ -122,7 +122,7 @@ --color-brown-dark-2: #845232; --color-black-dark-2: #131619; /* ansi colors used for actions console and console files */ - --color-ansi-black: #1f2326; + --color-ansi-black: #1e2327; --color-ansi-red: #cc4848; --color-ansi-green: #87ab63; --color-ansi-yellow: #cc9903; From 17c7ebb327faf6f8b6d659a0adb451b553405116 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Thu, 11 Apr 2024 00:24:56 +0000 Subject: [PATCH 079/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_ja-JP.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 57b2aff254..0edd6c5dd7 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -2109,7 +2109,7 @@ settings.pulls.default_delete_branch_after_merge=デフォルトでプルリク settings.pulls.default_allow_edits_from_maintainers=デフォルトでメンテナからの編集を許可する settings.releases_desc=リリースを有効にする settings.packages_desc=リポジトリパッケージレジストリを有効にする -settings.projects_desc=リポジトリプロジェクトを有効にする +settings.projects_desc=プロジェクトを有効にする settings.projects_mode_all=すべてのプロジェクト settings.actions_desc=Actionsを有効にする settings.admin_settings=管理者用設定 From f0bfad29ea00eea7fd421d51352825aaa931aba8 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Thu, 11 Apr 2024 09:12:40 +0800 Subject: [PATCH 080/370] Replace MSSQL driver with a better maintained version (#30390) As the latest tag of `github.com/denisenkom/go-mssqldb` is in 2022, but as a fork of it, `github.com/microsoft/go-mssqldb` has more activities than the original repository. We can convert the driver to the fork. Since the interface of Go database driver are the same, it should have no any affect for the end users. --- assets/go-licenses.json | 15 ++++++++++----- go.mod | 2 +- go.sum | 28 ++++++++++++++++++---------- models/db/engine.go | 6 +++--- 4 files changed, 32 insertions(+), 19 deletions(-) diff --git a/assets/go-licenses.json b/assets/go-licenses.json index be9022b694..ea73182a83 100644 --- a/assets/go-licenses.json +++ b/assets/go-licenses.json @@ -304,11 +304,6 @@ "path": "github.com/davecgh/go-spew/spew/LICENSE", "licenseText": "ISC License\n\nCopyright (c) 2012-2016 Dave Collins \u003cdave@davec.name\u003e\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n" }, - { - "name": "github.com/denisenkom/go-mssqldb", - "path": "github.com/denisenkom/go-mssqldb/LICENSE.txt", - "licenseText": "Copyright (c) 2012 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" - }, { "name": "github.com/dgryski/go-rendezvous", "path": "github.com/dgryski/go-rendezvous/LICENSE", @@ -759,6 +754,16 @@ "path": "github.com/microcosm-cc/bluemonday/LICENSE.md", "licenseText": "SPDX short identifier: BSD-3-Clause\nhttps://opensource.org/licenses/BSD-3-Clause\n\nCopyright (c) 2014, David Kitchen \u003cdavid@buro9.com\u003e\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n* Neither the name of the organisation (Microcosm) nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, + { + "name": "github.com/microsoft/go-mssqldb", + "path": "github.com/microsoft/go-mssqldb/LICENSE.txt", + "licenseText": "Copyright (c) 2012 The Go Authors. All rights reserved.\nCopyright (c) Microsoft Corporation.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + }, + { + "name": "github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg", + "path": "github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/LICENSE.txt", + "licenseText": "Copyright (c) 2021 Swisscom (Switzerland) Ltd\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n" + }, { "name": "github.com/miekg/dns", "path": "github.com/miekg/dns/LICENSE", diff --git a/go.mod b/go.mod index 27e1924806..1e0f1ea8f8 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,6 @@ require ( github.com/buildkite/terminal-to-html/v3 v3.11.0 github.com/caddyserver/certmagic v0.20.0 github.com/chi-middleware/proxy v1.1.1 - github.com/denisenkom/go-mssqldb v0.12.3 github.com/dimiro1/reply v0.0.0-20200315094148-d0136a4c9e21 github.com/djherbis/buffer v1.2.0 github.com/djherbis/nio/v3 v3.0.1 @@ -77,6 +76,7 @@ require ( github.com/meilisearch/meilisearch-go v0.26.2 github.com/mholt/archiver/v3 v3.5.1 github.com/microcosm-cc/bluemonday v1.0.26 + github.com/microsoft/go-mssqldb v1.7.0 github.com/minio/minio-go/v7 v7.0.69 github.com/msteinert/pam v1.2.0 github.com/nektos/act v0.2.52 diff --git a/go.sum b/go.sum index 55f24bf2e7..864bed6677 100644 --- a/go.sum +++ b/go.sum @@ -38,11 +38,20 @@ github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121 h1:r3qt8PCHnfjOv9PN3H github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121/go.mod h1:Ock8XgA7pvULhIaHGAk/cDnRfNrF9Jey81nPcc403iU= github.com/6543/go-version v1.3.1 h1:HvOp+Telns7HWJ2Xo/05YXQSB2bE0WmVgbHqwMPZT4U= github.com/6543/go-version v1.3.1/go.mod h1:oqFAHCwtLVUTLdhQmVZWYvaHXTdsbB4SY85at64SQEo= -github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0= -github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 h1:lGlwhPtrX6EVml1hO0ivjkUxsSyl4dsiw9qcA1k/3IQ= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1/go.mod h1:RKUqNu35KJYcVG/fqTRqmuXJZYNhYkBrnC/hX7yGbTA= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 h1:6oNBlSdi1QqM1PNW7FPA6xOGA5UNsXnkaYZz9vdPGhA= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 h1:MyVTgWR8qd/Jw1Le0NZebGBUCLbtak3bJ3z1OlqZBpw= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1/go.mod h1:GpPjLhVR9dnUoJMyHWSPy71xY9/lcmpzIPZXmF0FCVY= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/ClickHouse/ch-go v0.61.5 h1:zwR8QbYI0tsMiEcze/uIMK+Tz1D3XZXLdNrlaOpeEI4= github.com/ClickHouse/ch-go v0.61.5/go.mod h1:s1LJW/F/LcFs5HJnuogFMta50kKDO0lf9zzfrbl0RQg= @@ -220,7 +229,6 @@ github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55k github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY= github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= @@ -355,7 +363,6 @@ github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOW github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= @@ -513,6 +520,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= @@ -551,6 +560,8 @@ github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Cl github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58= github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs= +github.com/microsoft/go-mssqldb v1.7.0 h1:sgMPW0HA6Ihd37Yx0MzHyKD726C2kY/8KJsQtXHNaAs= +github.com/microsoft/go-mssqldb v1.7.0/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA= github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= @@ -574,7 +585,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 h1:j2kD3MT1z4PXCiUllUJF9mWUESr9TWKS7iEKsQ/IipM= github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM= @@ -627,7 +637,8 @@ github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= -github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -836,7 +847,6 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= @@ -871,7 +881,6 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -1022,7 +1031,6 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= diff --git a/models/db/engine.go b/models/db/engine.go index 2a2743e927..8684c4e2f1 100755 --- a/models/db/engine.go +++ b/models/db/engine.go @@ -21,9 +21,9 @@ import ( "xorm.io/xorm/names" "xorm.io/xorm/schemas" - _ "github.com/denisenkom/go-mssqldb" // Needed for the MSSQL driver - _ "github.com/go-sql-driver/mysql" // Needed for the MySQL driver - _ "github.com/lib/pq" // Needed for the Postgresql driver + _ "github.com/go-sql-driver/mysql" // Needed for the MySQL driver + _ "github.com/lib/pq" // Needed for the Postgresql driver + _ "github.com/microsoft/go-mssqldb" // Needed for the MSSQL driver ) var ( From e6d3f9fc07d193ce95cf0964f0d12da87156fac9 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Thu, 11 Apr 2024 04:40:03 +0200 Subject: [PATCH 081/370] Upgrade golangci-lint to v1.57.2 (#30401) Update and adapt to one setting [deprecation](https://github.com/golangci/golangci-lint/pull/4509). --- .golangci.yml | 5 +---- Makefile | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index d6ce37f49a..5be2cefe44 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -30,10 +30,6 @@ linters: run: timeout: 10m - skip-dirs: - - node_modules - - public - - web_src linters-settings: stylecheck: @@ -94,6 +90,7 @@ linters-settings: issues: max-issues-per-linter: 0 max-same-issues: 0 + exclude-dirs: [node_modules, public, web_src] exclude-rules: # Exclude some linters from running on tests files. - path: _test\.go diff --git a/Makefile b/Makefile index 8489520920..ee9c90e8d9 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ XGO_VERSION := go-1.22.x AIR_PACKAGE ?= github.com/cosmtrek/air@v1.49.0 EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.7.0 GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.6.0 -GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.56.1 +GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.57.2 GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11 MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.4.1 SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@db51e79a0e37c572d8b59ae0c58bf2bbbbe53285 From 50dbed652738182eb42af51967ec7bd10e84ede9 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Thu, 11 Apr 2024 05:16:44 +0200 Subject: [PATCH 082/370] Fix author name alignment in commits table (#30396) Fixes https://github.com/go-gitea/gitea/issues/30129 by introducing a wrapper div with flexbox that collapses any inter-tag whitespace within. View diff with whitespace hidden. Author names aligned: <img width="172" alt="Screenshot 2024-04-10 at 19 41 27" src="https://github.com/go-gitea/gitea/assets/115237/d761e8f2-0e67-4f84-8d37-9ed73850470a"> Vertically centered on expand: <img width="466" alt="Screenshot 2024-04-10 at 19 43 02" src="https://github.com/go-gitea/gitea/assets/115237/decd68b3-19b5-4cfa-a505-b358e4a0715b"> Ellipsis works: <img width="344" alt="image" src="https://github.com/go-gitea/gitea/assets/115237/6f8624a2-f8b6-4f3e-ac98-c44dd0cdfca5"> --- templates/repo/commits_list.tmpl | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/templates/repo/commits_list.tmpl b/templates/repo/commits_list.tmpl index be73c4ca18..bb5d2a0394 100644 --- a/templates/repo/commits_list.tmpl +++ b/templates/repo/commits_list.tmpl @@ -13,17 +13,19 @@ {{$commitRepoLink := $.RepoLink}}{{if $.CommitRepoLink}}{{$commitRepoLink = $.CommitRepoLink}}{{end}} {{range .Commits}} <tr> - <td class="author tw-flex"> - {{$userName := .Author.Name}} - {{if .User}} - {{if and .User.FullName DefaultShowFullName}} - {{$userName = .User.FullName}} + <td class="author"> + <div class="tw-flex"> + {{$userName := .Author.Name}} + {{if .User}} + {{if and .User.FullName DefaultShowFullName}} + {{$userName = .User.FullName}} + {{end}} + {{ctx.AvatarUtils.Avatar .User 28 "tw-mr-2"}}<a class="muted author-wrapper" href="{{.User.HomeLink}}">{{$userName}}</a> + {{else}} + {{ctx.AvatarUtils.AvatarByEmail .Author.Email .Author.Name 28 "tw-mr-2"}} + <span class="author-wrapper">{{$userName}}</span> {{end}} - {{ctx.AvatarUtils.Avatar .User 28 "tw-mr-2"}}<a class="muted author-wrapper" href="{{.User.HomeLink}}">{{$userName}}</a> - {{else}} - {{ctx.AvatarUtils.AvatarByEmail .Author.Email .Author.Name 28 "tw-mr-2"}} - <span class="author-wrapper">{{$userName}}</span> - {{end}} + </div> </td> <td class="sha"> {{$class := "ui sha label"}} From f3cc00626b5a170e193961b885d4e60088ef7d9b Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Thu, 11 Apr 2024 11:57:03 +0800 Subject: [PATCH 083/370] Update actions variables documents (#30394) Fix #30393 --------- Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: Zettat123 <zettat123@gmail.com> --- .../content/usage/actions/act-runner.en-us.md | 31 -------------- .../content/usage/actions/act-runner.zh-cn.md | 29 ------------- docs/content/usage/actions/variables.en-us.md | 41 +++++++++++++++++++ docs/content/usage/actions/variables.zh-cn.md | 39 ++++++++++++++++++ 4 files changed, 80 insertions(+), 60 deletions(-) create mode 100644 docs/content/usage/actions/variables.en-us.md create mode 100644 docs/content/usage/actions/variables.zh-cn.md diff --git a/docs/content/usage/actions/act-runner.en-us.md b/docs/content/usage/actions/act-runner.en-us.md index b2806bf5dd..942d126919 100644 --- a/docs/content/usage/actions/act-runner.en-us.md +++ b/docs/content/usage/actions/act-runner.en-us.md @@ -303,34 +303,3 @@ sudo systemctl enable act_runner --now ``` If using Docker, the `act_runner` user should also be added to the `docker` group before starting the service. Keep in mind that this effectively gives `act_runner` root access to the system [[1]](https://docs.docker.com/engine/security/#docker-daemon-attack-surface). - -## Configuration variable - -You can create configuration variables on the user, organization and repository level. -The level of the variable depends on where you created it. - -### Naming conventions - -The following rules apply to variable names: - -- Variable names can only contain alphanumeric characters (`[a-z]`, `[A-Z]`, `[0-9]`) or underscores (`_`). Spaces are not allowed. - -- Variable names must not start with the `GITHUB_` and `GITEA_` prefix. - -- Variable names must not start with a number. - -- Variable names are case-insensitive. - -- Variable names must be unique at the level they are created at. - -- Variable names must not be `CI`. - -### Using variable - -After creating configuration variables, they will be automatically filled in the `vars` context. -They can be accessed through expressions like `{{ vars.VARIABLE_NAME }}` in the workflow. - -### Precedence - -If a variable with the same name exists at multiple levels, the variable at the lowest level takes precedence: -A repository variable will always be chosen over an organization/user variable. diff --git a/docs/content/usage/actions/act-runner.zh-cn.md b/docs/content/usage/actions/act-runner.zh-cn.md index 274b0f0692..e5ebff976d 100644 --- a/docs/content/usage/actions/act-runner.zh-cn.md +++ b/docs/content/usage/actions/act-runner.zh-cn.md @@ -258,32 +258,3 @@ Runner的标签用于确定Runner可以运行哪些Job以及如何运行它们 Runner将从Gitea实例获取Job并自动运行它们。 由于Act Runner仍处于开发中,建议定期检查最新版本并进行升级。 - -## 变量 - -您可以创建用户、组织和仓库级别的变量。变量的级别取决于创建它的位置。 - -### 命名规则 - -以下规则适用于变量名: - -- 变量名称只能包含字母数字字符 (`[a-z]`, `[A-Z]`, `[0-9]`) 或下划线 (`_`)。不允许使用空格。 - -- 变量名称不能以 `GITHUB_` 和 `GITEA_` 前缀开头。 - -- 变量名称不能以数字开头。 - -- 变量名称不区分大小写。 - -- 变量名称在创建它们的级别上必须是唯一的。 - -- 变量名称不能为 “CI”。 - -### 使用 - -创建配置变量后,它们将自动填充到 `vars` 上下文中。您可以在工作流中使用类似 `{{ vars.VARIABLE_NAME }}` 这样的表达式来使用它们。 - -### 优先级 - -如果同名变量存在于多个级别,则级别最低的变量优先。 -仓库级别的变量总是比组织或者用户级别的变量优先被选中。 diff --git a/docs/content/usage/actions/variables.en-us.md b/docs/content/usage/actions/variables.en-us.md new file mode 100644 index 0000000000..dee2e74234 --- /dev/null +++ b/docs/content/usage/actions/variables.en-us.md @@ -0,0 +1,41 @@ +--- +date: "2024-04-10T22:21:00+08:00" +title: "Variables" +slug: "actions-variables" +sidebar_position: 25 +draft: false +toc: false +menu: + sidebar: + parent: "actions" + name: "Variables" + sidebar_position: 25 + identifier: "actions-variables" +--- + +## Variables + +You can create configuration variables on the user, organization and repository level. +The level of the variable depends on where you created it. When creating a variable, the +key will be converted to uppercase. You need use uppercase on the yaml file. + +### Naming conventions + +The following rules apply to variable names: + +- Variable names can only contain alphanumeric characters (`[a-z]`, `[A-Z]`, `[0-9]`) or underscores (`_`). Spaces are not allowed. +- Variable names must not start with the `GITHUB_` and `GITEA_` prefix. +- Variable names must not start with a number. +- Variable names are case-insensitive. +- Variable names must be unique at the level they are created at. +- Variable names must not be `CI`. + +### Using variable + +After creating configuration variables, they will be automatically filled in the `vars` context. +They can be accessed through expressions like `${{ vars.VARIABLE_NAME }}` in the workflow. + +### Precedence + +If a variable with the same name exists at multiple levels, the variable at the lowest level takes precedence: +A repository variable will always be chosen over an organization/user variable. diff --git a/docs/content/usage/actions/variables.zh-cn.md b/docs/content/usage/actions/variables.zh-cn.md new file mode 100644 index 0000000000..77643408a1 --- /dev/null +++ b/docs/content/usage/actions/variables.zh-cn.md @@ -0,0 +1,39 @@ +--- +date: "2024-04-10T22:21:00+08:00" +title: "变量" +slug: "actions-variables" +sidebar_position: 25 +draft: false +toc: false +menu: + sidebar: + parent: "actions" + name: "变量" + sidebar_position: 25 + identifier: "actions-variables" +--- + +## 变量 + +您可以创建用户、组织和仓库级别的变量。变量的级别取决于创建它的位置。当创建变量时,变量的名称会被 +转换为大写,在yaml文件中引用时需要使用大写。 + +### 命名规则 + +以下规则适用于变量名: + +- 变量名称只能包含字母数字字符 (`[a-z]`, `[A-Z]`, `[0-9]`) 或下划线 (`_`)。不允许使用空格。 +- 变量名称不能以 `GITHUB_` 和 `GITEA_` 前缀开头。 +- 变量名称不能以数字开头。 +- 变量名称不区分大小写。 +- 变量名称在创建它们的级别上必须是唯一的。 +- 变量名称不能为 `CI`。 + +### 使用 + +创建配置变量后,它们将自动填充到 `vars` 上下文中。您可以在工作流中使用类似 `${{ vars.VARIABLE_NAME }}` 这样的表达式来使用它们。 + +### 优先级 + +如果同名变量存在于多个级别,则级别最低的变量优先。 +仓库级别的变量总是比组织或者用户级别的变量优先被选中。 From 96d31fe0a8b88c09488989cd5459d4124dcb7983 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 11 Apr 2024 16:11:32 +0900 Subject: [PATCH 084/370] Avoid user does not exist error when detecting schedule actions when the commit author is an external user (#30357)  When repo is a mirror, and commit author is an external user, then `GetUserByEmail` will return error. reproduce/test: - mirror Gitea to your instance - disable action and enable it again, this will trigger `DetectAndHandleSchedules` ps: also follow #24706, it only fixed normal runs, not scheduled runs. --- models/actions/schedule_list.go | 3 +++ services/actions/notifier_helper.go | 9 +++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/models/actions/schedule_list.go b/models/actions/schedule_list.go index 1d35adc420..5361b94801 100644 --- a/models/actions/schedule_list.go +++ b/models/actions/schedule_list.go @@ -40,6 +40,9 @@ func (schedules ScheduleList) LoadTriggerUser(ctx context.Context) error { schedule.TriggerUser = user_model.NewActionsUser() } else { schedule.TriggerUser = users[schedule.TriggerUserID] + if schedule.TriggerUser == nil { + schedule.TriggerUser = user_model.NewGhostUser() + } } } return nil diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index 8c98f56af5..c48886a824 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -525,12 +525,9 @@ func DetectAndHandleSchedules(ctx context.Context, repo *repo_model.Repository) } // We need a notifyInput to call handleSchedules - // Here we use the commit author as the Doer of the notifyInput - commitUser, err := user_model.GetUserByEmail(ctx, commit.Author.Email) - if err != nil { - return fmt.Errorf("get user by email: %w", err) - } - notifyInput := newNotifyInput(repo, commitUser, webhook_module.HookEventSchedule) + // if repo is a mirror, commit author maybe an external user, + // so we use action user as the Doer of the notifyInput + notifyInput := newNotifyInput(repo, user_model.NewActionsUser(), webhook_module.HookEventSchedule) return handleSchedules(ctx, scheduleWorkflows, commit, notifyInput, repo.DefaultBranch) } From 0fe9f93eb4c94d55e43b18b9c3cc6d513a34c0b5 Mon Sep 17 00:00:00 2001 From: Zettat123 <zettat123@gmail.com> Date: Thu, 11 Apr 2024 16:01:44 +0800 Subject: [PATCH 085/370] Check the token's owner and repository when registering a runner (#30406) Fix #30378 --- models/organization/org.go | 3 +++ routers/api/actions/runner/runner.go | 14 ++++++++++++++ services/repository/delete.go | 1 + services/user/delete.go | 1 + 4 files changed, 19 insertions(+) diff --git a/models/organization/org.go b/models/organization/org.go index ba0fd756e3..b33d15d29c 100644 --- a/models/organization/org.go +++ b/models/organization/org.go @@ -9,6 +9,7 @@ import ( "fmt" "strings" + actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" repo_model "code.gitea.io/gitea/models/repo" @@ -402,6 +403,8 @@ func DeleteOrganization(ctx context.Context, org *Organization) error { &TeamInvite{OrgID: org.ID}, &secret_model.Secret{OwnerID: org.ID}, &user_model.Blocking{BlockerID: org.ID}, + &actions_model.ActionRunner{OwnerID: org.ID}, + &actions_model.ActionRunnerToken{OwnerID: org.ID}, ); err != nil { return fmt.Errorf("DeleteBeans: %w", err) } diff --git a/routers/api/actions/runner/runner.go b/routers/api/actions/runner/runner.go index 1d07be3aec..b2f3e7af78 100644 --- a/routers/api/actions/runner/runner.go +++ b/routers/api/actions/runner/runner.go @@ -9,6 +9,8 @@ import ( "net/http" actions_model "code.gitea.io/gitea/models/actions" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/actions" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/util" @@ -52,6 +54,18 @@ func (s *Service) Register( return nil, errors.New("runner registration token has been invalidated, please use the latest one") } + if runnerToken.OwnerID > 0 { + if _, err := user_model.GetUserByID(ctx, runnerToken.OwnerID); err != nil { + return nil, errors.New("owner of the token not found") + } + } + + if runnerToken.RepoID > 0 { + if _, err := repo_model.GetRepositoryByID(ctx, runnerToken.RepoID); err != nil { + return nil, errors.New("repository of the token not found") + } + } + labels := req.Msg.Labels // TODO: agent_labels should be removed from pb after Gitea 1.20 released. // Old version runner's agent_labels slice is not empty and labels slice is empty. diff --git a/services/repository/delete.go b/services/repository/delete.go index 8d6729f31b..7c7dfe2ddd 100644 --- a/services/repository/delete.go +++ b/services/repository/delete.go @@ -163,6 +163,7 @@ func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, repoID &actions_model.ActionScheduleSpec{RepoID: repoID}, &actions_model.ActionSchedule{RepoID: repoID}, &actions_model.ActionArtifact{RepoID: repoID}, + &actions_model.ActionRunnerToken{RepoID: repoID}, ); err != nil { return fmt.Errorf("deleteBeans: %w", err) } diff --git a/services/user/delete.go b/services/user/delete.go index 212cb83e03..889da3eb67 100644 --- a/services/user/delete.go +++ b/services/user/delete.go @@ -94,6 +94,7 @@ func deleteUser(ctx context.Context, u *user_model.User, purge bool) (err error) &actions_model.ActionRunner{OwnerID: u.ID}, &user_model.Blocking{BlockerID: u.ID}, &user_model.Blocking{BlockeeID: u.ID}, + &actions_model.ActionRunnerToken{OwnerID: u.ID}, ); err != nil { return fmt.Errorf("deleteBeans: %w", err) } From 26ee66327fecf2f1755a47f9193bc6305132def1 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Fri, 12 Apr 2024 02:22:59 +0800 Subject: [PATCH 086/370] Split `issue edit` code from `repo-legacy.js` into its own file (#30419) Follow Split `index.js` to separate files (#17315) It's time to move some code away from the messy "legacy" file. --- web_src/js/features/repo-issue-edit.js | 206 ++++++++++++++++++++++++ web_src/js/features/repo-legacy.js | 207 +------------------------ 2 files changed, 209 insertions(+), 204 deletions(-) create mode 100644 web_src/js/features/repo-issue-edit.js diff --git a/web_src/js/features/repo-issue-edit.js b/web_src/js/features/repo-issue-edit.js new file mode 100644 index 0000000000..4c03325c7a --- /dev/null +++ b/web_src/js/features/repo-issue-edit.js @@ -0,0 +1,206 @@ +import $ from 'jquery'; +import {handleReply} from './repo-issue.js'; +import {getComboMarkdownEditor, initComboMarkdownEditor} from './comp/ComboMarkdownEditor.js'; +import {createDropzone} from './dropzone.js'; +import {GET, POST} from '../modules/fetch.js'; +import {hideElem, showElem} from '../utils/dom.js'; +import {attachRefIssueContextPopup} from './contextpopup.js'; +import {initCommentContent, initMarkupContent} from '../markup/content.js'; + +const {csrfToken} = window.config; + +async function onEditContent(event) { + event.preventDefault(); + + const segment = this.closest('.header').nextElementSibling; + const editContentZone = segment.querySelector('.edit-content-zone'); + const renderContent = segment.querySelector('.render-content'); + const rawContent = segment.querySelector('.raw-content'); + + let comboMarkdownEditor; + + /** + * @param {HTMLElement} dropzone + */ + const setupDropzone = async (dropzone) => { + if (!dropzone) return null; + + let disableRemovedfileEvent = false; // when resetting the dropzone (removeAllFiles), disable the "removedfile" event + let fileUuidDict = {}; // to record: if a comment has been saved, then the uploaded files won't be deleted from server when clicking the Remove in the dropzone + const dz = await createDropzone(dropzone, { + url: dropzone.getAttribute('data-upload-url'), + headers: {'X-Csrf-Token': csrfToken}, + maxFiles: dropzone.getAttribute('data-max-file'), + maxFilesize: dropzone.getAttribute('data-max-size'), + acceptedFiles: ['*/*', ''].includes(dropzone.getAttribute('data-accepts')) ? null : dropzone.getAttribute('data-accepts'), + addRemoveLinks: true, + dictDefaultMessage: dropzone.getAttribute('data-default-message'), + dictInvalidFileType: dropzone.getAttribute('data-invalid-input-type'), + dictFileTooBig: dropzone.getAttribute('data-file-too-big'), + dictRemoveFile: dropzone.getAttribute('data-remove-file'), + timeout: 0, + thumbnailMethod: 'contain', + thumbnailWidth: 480, + thumbnailHeight: 480, + init() { + this.on('success', (file, data) => { + file.uuid = data.uuid; + fileUuidDict[file.uuid] = {submitted: false}; + const input = document.createElement('input'); + input.id = data.uuid; + input.name = 'files'; + input.type = 'hidden'; + input.value = data.uuid; + dropzone.querySelector('.files').append(input); + }); + this.on('removedfile', async (file) => { + document.getElementById(file.uuid)?.remove(); + if (disableRemovedfileEvent) return; + if (dropzone.getAttribute('data-remove-url') && !fileUuidDict[file.uuid].submitted) { + try { + await POST(dropzone.getAttribute('data-remove-url'), {data: new URLSearchParams({file: file.uuid})}); + } catch (error) { + console.error(error); + } + } + }); + this.on('submit', () => { + for (const fileUuid of Object.keys(fileUuidDict)) { + fileUuidDict[fileUuid].submitted = true; + } + }); + this.on('reload', async () => { + try { + const response = await GET(editContentZone.getAttribute('data-attachment-url')); + const data = await response.json(); + // do not trigger the "removedfile" event, otherwise the attachments would be deleted from server + disableRemovedfileEvent = true; + dz.removeAllFiles(true); + dropzone.querySelector('.files').innerHTML = ''; + for (const el of dropzone.querySelectorAll('.dz-preview')) el.remove(); + fileUuidDict = {}; + disableRemovedfileEvent = false; + + for (const attachment of data) { + const imgSrc = `${dropzone.getAttribute('data-link-url')}/${attachment.uuid}`; + dz.emit('addedfile', attachment); + dz.emit('thumbnail', attachment, imgSrc); + dz.emit('complete', attachment); + fileUuidDict[attachment.uuid] = {submitted: true}; + dropzone.querySelector(`img[src='${imgSrc}']`).style.maxWidth = '100%'; + const input = document.createElement('input'); + input.id = attachment.uuid; + input.name = 'files'; + input.type = 'hidden'; + input.value = attachment.uuid; + dropzone.querySelector('.files').append(input); + } + if (!dropzone.querySelector('.dz-preview')) { + dropzone.classList.remove('dz-started'); + } + } catch (error) { + console.error(error); + } + }); + }, + }); + dz.emit('reload'); + return dz; + }; + + const cancelAndReset = (e) => { + e.preventDefault(); + showElem(renderContent); + hideElem(editContentZone); + comboMarkdownEditor.attachedDropzoneInst?.emit('reload'); + }; + + const saveAndRefresh = async (e) => { + e.preventDefault(); + showElem(renderContent); + hideElem(editContentZone); + const dropzoneInst = comboMarkdownEditor.attachedDropzoneInst; + try { + const params = new URLSearchParams({ + content: comboMarkdownEditor.value(), + context: editContentZone.getAttribute('data-context'), + }); + for (const fileInput of dropzoneInst?.element.querySelectorAll('.files [name=files]')) params.append('files[]', fileInput.value); + + const response = await POST(editContentZone.getAttribute('data-update-url'), {data: params}); + const data = await response.json(); + if (!data.content) { + renderContent.innerHTML = document.getElementById('no-content').innerHTML; + rawContent.textContent = ''; + } else { + renderContent.innerHTML = data.content; + rawContent.textContent = comboMarkdownEditor.value(); + const refIssues = renderContent.querySelectorAll('p .ref-issue'); + attachRefIssueContextPopup(refIssues); + } + const content = segment; + if (!content.querySelector('.dropzone-attachments')) { + if (data.attachments !== '') { + content.insertAdjacentHTML('beforeend', data.attachments); + } + } else if (data.attachments === '') { + content.querySelector('.dropzone-attachments').remove(); + } else { + content.querySelector('.dropzone-attachments').outerHTML = data.attachments; + } + dropzoneInst?.emit('submit'); + dropzoneInst?.emit('reload'); + initMarkupContent(); + initCommentContent(); + } catch (error) { + console.error(error); + } + }; + + comboMarkdownEditor = getComboMarkdownEditor(editContentZone.querySelector('.combo-markdown-editor')); + if (!comboMarkdownEditor) { + editContentZone.innerHTML = document.getElementById('issue-comment-editor-template').innerHTML; + comboMarkdownEditor = await initComboMarkdownEditor(editContentZone.querySelector('.combo-markdown-editor')); + comboMarkdownEditor.attachedDropzoneInst = await setupDropzone(editContentZone.querySelector('.dropzone')); + editContentZone.querySelector('.cancel.button').addEventListener('click', cancelAndReset); + editContentZone.querySelector('.save.button').addEventListener('click', saveAndRefresh); + } + + // Show write/preview tab and copy raw content as needed + showElem(editContentZone); + hideElem(renderContent); + if (!comboMarkdownEditor.value()) { + comboMarkdownEditor.value(rawContent.textContent); + } + comboMarkdownEditor.focus(); +} + +export function initRepoIssueCommentEdit() { + // Edit issue or comment content + $(document).on('click', '.edit-content', onEditContent); + + // Quote reply + $(document).on('click', '.quote-reply', async function (event) { + event.preventDefault(); + const target = $(this).data('target'); + const quote = $(`#${target}`).text().replace(/\n/g, '\n> '); + const content = `> ${quote}\n\n`; + let editor; + if ($(this).hasClass('quote-reply-diff')) { + const $replyBtn = $(this).closest('.comment-code-cloud').find('button.comment-form-reply'); + editor = await handleReply($replyBtn); + } else { + // for normal issue/comment page + editor = getComboMarkdownEditor($('#comment-form .combo-markdown-editor')); + } + if (editor) { + if (editor.value()) { + editor.value(`${editor.value()}\n\n${content}`); + } else { + editor.value(content); + } + editor.focus(); + editor.moveCursorToEnd(); + } + }); +} diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index 4c7dd36920..e83de27e4c 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -3,7 +3,7 @@ import { initRepoIssueBranchSelect, initRepoIssueCodeCommentCancel, initRepoIssueCommentDelete, initRepoIssueComments, initRepoIssueDependencyDelete, initRepoIssueReferenceIssue, initRepoIssueTitleEdit, initRepoIssueWipToggle, - initRepoPullRequestUpdate, updateIssuesMeta, handleReply, initIssueTemplateCommentEditors, initSingleCommentEditor, + initRepoPullRequestUpdate, updateIssuesMeta, initIssueTemplateCommentEditors, initSingleCommentEditor, } from './repo-issue.js'; import {initUnicodeEscapeButton} from './repo-unicode-escape.js'; import {svg} from '../svg.js'; @@ -15,18 +15,13 @@ import { import {initCitationFileCopyContent} from './citation.js'; import {initCompLabelEdit} from './comp/LabelEdit.js'; import {initRepoDiffConversationNav} from './repo-diff.js'; -import {createDropzone} from './dropzone.js'; -import {initCommentContent, initMarkupContent} from '../markup/content.js'; import {initCompReactionSelector} from './comp/ReactionSelector.js'; import {initRepoSettingBranches} from './repo-settings.js'; import {initRepoPullRequestMergeForm} from './repo-issue-pr-form.js'; import {initRepoPullRequestCommitStatus} from './repo-issue-pr-status.js'; import {hideElem, showElem} from '../utils/dom.js'; -import {getComboMarkdownEditor, initComboMarkdownEditor} from './comp/ComboMarkdownEditor.js'; -import {attachRefIssueContextPopup} from './contextpopup.js'; -import {POST, GET} from '../modules/fetch.js'; - -const {csrfToken} = window.config; +import {POST} from '../modules/fetch.js'; +import {initRepoIssueCommentEdit} from './repo-issue-edit.js'; // if there are draft comments, confirm before reloading, to avoid losing comments function reloadConfirmDraftComment() { @@ -316,172 +311,6 @@ export function initRepoCommentForm() { selectItem('.select-assignee', '#assignee_id'); } -async function onEditContent(event) { - event.preventDefault(); - - const segment = this.closest('.header').nextElementSibling; - const editContentZone = segment.querySelector('.edit-content-zone'); - const renderContent = segment.querySelector('.render-content'); - const rawContent = segment.querySelector('.raw-content'); - - let comboMarkdownEditor; - - /** - * @param {HTMLElement} dropzone - */ - const setupDropzone = async (dropzone) => { - if (!dropzone) return null; - - let disableRemovedfileEvent = false; // when resetting the dropzone (removeAllFiles), disable the "removedfile" event - let fileUuidDict = {}; // to record: if a comment has been saved, then the uploaded files won't be deleted from server when clicking the Remove in the dropzone - const dz = await createDropzone(dropzone, { - url: dropzone.getAttribute('data-upload-url'), - headers: {'X-Csrf-Token': csrfToken}, - maxFiles: dropzone.getAttribute('data-max-file'), - maxFilesize: dropzone.getAttribute('data-max-size'), - acceptedFiles: ['*/*', ''].includes(dropzone.getAttribute('data-accepts')) ? null : dropzone.getAttribute('data-accepts'), - addRemoveLinks: true, - dictDefaultMessage: dropzone.getAttribute('data-default-message'), - dictInvalidFileType: dropzone.getAttribute('data-invalid-input-type'), - dictFileTooBig: dropzone.getAttribute('data-file-too-big'), - dictRemoveFile: dropzone.getAttribute('data-remove-file'), - timeout: 0, - thumbnailMethod: 'contain', - thumbnailWidth: 480, - thumbnailHeight: 480, - init() { - this.on('success', (file, data) => { - file.uuid = data.uuid; - fileUuidDict[file.uuid] = {submitted: false}; - const input = document.createElement('input'); - input.id = data.uuid; - input.name = 'files'; - input.type = 'hidden'; - input.value = data.uuid; - dropzone.querySelector('.files').append(input); - }); - this.on('removedfile', async (file) => { - document.getElementById(file.uuid)?.remove(); - if (disableRemovedfileEvent) return; - if (dropzone.getAttribute('data-remove-url') && !fileUuidDict[file.uuid].submitted) { - try { - await POST(dropzone.getAttribute('data-remove-url'), {data: new URLSearchParams({file: file.uuid})}); - } catch (error) { - console.error(error); - } - } - }); - this.on('submit', () => { - for (const fileUuid of Object.keys(fileUuidDict)) { - fileUuidDict[fileUuid].submitted = true; - } - }); - this.on('reload', async () => { - try { - const response = await GET(editContentZone.getAttribute('data-attachment-url')); - const data = await response.json(); - // do not trigger the "removedfile" event, otherwise the attachments would be deleted from server - disableRemovedfileEvent = true; - dz.removeAllFiles(true); - dropzone.querySelector('.files').innerHTML = ''; - for (const el of dropzone.querySelectorAll('.dz-preview')) el.remove(); - fileUuidDict = {}; - disableRemovedfileEvent = false; - - for (const attachment of data) { - const imgSrc = `${dropzone.getAttribute('data-link-url')}/${attachment.uuid}`; - dz.emit('addedfile', attachment); - dz.emit('thumbnail', attachment, imgSrc); - dz.emit('complete', attachment); - fileUuidDict[attachment.uuid] = {submitted: true}; - dropzone.querySelector(`img[src='${imgSrc}']`).style.maxWidth = '100%'; - const input = document.createElement('input'); - input.id = attachment.uuid; - input.name = 'files'; - input.type = 'hidden'; - input.value = attachment.uuid; - dropzone.querySelector('.files').append(input); - } - if (!dropzone.querySelector('.dz-preview')) { - dropzone.classList.remove('dz-started'); - } - } catch (error) { - console.error(error); - } - }); - }, - }); - dz.emit('reload'); - return dz; - }; - - const cancelAndReset = (e) => { - e.preventDefault(); - showElem(renderContent); - hideElem(editContentZone); - comboMarkdownEditor.attachedDropzoneInst?.emit('reload'); - }; - - const saveAndRefresh = async (e) => { - e.preventDefault(); - showElem(renderContent); - hideElem(editContentZone); - const dropzoneInst = comboMarkdownEditor.attachedDropzoneInst; - try { - const params = new URLSearchParams({ - content: comboMarkdownEditor.value(), - context: editContentZone.getAttribute('data-context'), - }); - for (const fileInput of dropzoneInst?.element.querySelectorAll('.files [name=files]')) params.append('files[]', fileInput.value); - - const response = await POST(editContentZone.getAttribute('data-update-url'), {data: params}); - const data = await response.json(); - if (!data.content) { - renderContent.innerHTML = document.getElementById('no-content').innerHTML; - rawContent.textContent = ''; - } else { - renderContent.innerHTML = data.content; - rawContent.textContent = comboMarkdownEditor.value(); - const refIssues = renderContent.querySelectorAll('p .ref-issue'); - attachRefIssueContextPopup(refIssues); - } - const content = segment; - if (!content.querySelector('.dropzone-attachments')) { - if (data.attachments !== '') { - content.insertAdjacentHTML('beforeend', data.attachments); - } - } else if (data.attachments === '') { - content.querySelector('.dropzone-attachments').remove(); - } else { - content.querySelector('.dropzone-attachments').outerHTML = data.attachments; - } - dropzoneInst?.emit('submit'); - dropzoneInst?.emit('reload'); - initMarkupContent(); - initCommentContent(); - } catch (error) { - console.error(error); - } - }; - - comboMarkdownEditor = getComboMarkdownEditor(editContentZone.querySelector('.combo-markdown-editor')); - if (!comboMarkdownEditor) { - editContentZone.innerHTML = document.getElementById('issue-comment-editor-template').innerHTML; - comboMarkdownEditor = await initComboMarkdownEditor(editContentZone.querySelector('.combo-markdown-editor')); - comboMarkdownEditor.attachedDropzoneInst = await setupDropzone(editContentZone.querySelector('.dropzone')); - editContentZone.querySelector('.cancel.button').addEventListener('click', cancelAndReset); - editContentZone.querySelector('.save.button').addEventListener('click', saveAndRefresh); - } - - // Show write/preview tab and copy raw content as needed - showElem(editContentZone); - hideElem(renderContent); - if (!comboMarkdownEditor.value()) { - comboMarkdownEditor.value(rawContent.textContent); - } - comboMarkdownEditor.focus(); -} - export function initRepository() { if (!$('.page-content.repository').length) return; @@ -585,33 +414,3 @@ export function initRepository() { initUnicodeEscapeButton(); } - -function initRepoIssueCommentEdit() { - // Edit issue or comment content - $(document).on('click', '.edit-content', onEditContent); - - // Quote reply - $(document).on('click', '.quote-reply', async function (event) { - event.preventDefault(); - const target = $(this).data('target'); - const quote = $(`#${target}`).text().replace(/\n/g, '\n> '); - const content = `> ${quote}\n\n`; - let editor; - if ($(this).hasClass('quote-reply-diff')) { - const $replyBtn = $(this).closest('.comment-code-cloud').find('button.comment-form-reply'); - editor = await handleReply($replyBtn); - } else { - // for normal issue/comment page - editor = getComboMarkdownEditor($('#comment-form .combo-markdown-editor')); - } - if (editor) { - if (editor.value()) { - editor.value(`${editor.value()}\n\n${content}`); - } else { - editor.value(content); - } - editor.focus(); - editor.moveCursorToEnd(); - } - }); -} From fc34481d054a9324ea4654dc721e54e2f608ac17 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Fri, 12 Apr 2024 09:41:50 +0800 Subject: [PATCH 087/370] Add commit status summary table to reduce query from commit status table (#30223) This PR adds a new table named commit status summary to reduce queries from the commit status table. After this change, commit status summary table will be used for the final result, commit status table will be for details. --------- Co-authored-by: Jason Song <i@wolfogre.com> --- models/git/commit_status.go | 21 ++--- models/git/commit_status_summary.go | 84 +++++++++++++++++++ models/migrations/migrations.go | 3 + models/migrations/v1_23/v295.go | 18 ++++ services/actions/commit_status.go | 20 ++--- .../repository/commitstatus/commitstatus.go | 48 +++++++++-- tests/integration/pull_status_test.go | 7 ++ 7 files changed, 170 insertions(+), 31 deletions(-) create mode 100644 models/git/commit_status_summary.go create mode 100644 models/migrations/v1_23/v295.go diff --git a/models/git/commit_status.go b/models/git/commit_status.go index bb75dcca26..c3cda7b73d 100644 --- a/models/git/commit_status.go +++ b/models/git/commit_status.go @@ -292,30 +292,27 @@ func GetLatestCommitStatus(ctx context.Context, repoID int64, sha string, listOp } // GetLatestCommitStatusForPairs returns all statuses with a unique context for a given list of repo-sha pairs -func GetLatestCommitStatusForPairs(ctx context.Context, repoIDsToLatestCommitSHAs map[int64]string, listOptions db.ListOptions) (map[int64][]*CommitStatus, error) { +func GetLatestCommitStatusForPairs(ctx context.Context, repoSHAs []RepoSHA) (map[int64][]*CommitStatus, error) { type result struct { Index int64 RepoID int64 + SHA string } - results := make([]result, 0, len(repoIDsToLatestCommitSHAs)) + results := make([]result, 0, len(repoSHAs)) getBase := func() *xorm.Session { return db.GetEngine(ctx).Table(&CommitStatus{}) } // Create a disjunction of conditions for each repoID and SHA pair - conds := make([]builder.Cond, 0, len(repoIDsToLatestCommitSHAs)) - for repoID, sha := range repoIDsToLatestCommitSHAs { - conds = append(conds, builder.Eq{"repo_id": repoID, "sha": sha}) + conds := make([]builder.Cond, 0, len(repoSHAs)) + for _, repoSHA := range repoSHAs { + conds = append(conds, builder.Eq{"repo_id": repoSHA.RepoID, "sha": repoSHA.SHA}) } sess := getBase().Where(builder.Or(conds...)). - Select("max( `index` ) as `index`, repo_id"). - GroupBy("context_hash, repo_id").OrderBy("max( `index` ) desc") - - if !listOptions.IsListAll() { - sess = db.SetSessionPagination(sess, &listOptions) - } + Select("max( `index` ) as `index`, repo_id, sha"). + GroupBy("context_hash, repo_id, sha").OrderBy("max( `index` ) desc") err := sess.Find(&results) if err != nil { @@ -332,7 +329,7 @@ func GetLatestCommitStatusForPairs(ctx context.Context, repoIDsToLatestCommitSHA cond := builder.Eq{ "`index`": result.Index, "repo_id": result.RepoID, - "sha": repoIDsToLatestCommitSHAs[result.RepoID], + "sha": result.SHA, } conds = append(conds, cond) } diff --git a/models/git/commit_status_summary.go b/models/git/commit_status_summary.go new file mode 100644 index 0000000000..01674e943d --- /dev/null +++ b/models/git/commit_status_summary.go @@ -0,0 +1,84 @@ +// Copyright 2024 Gitea. All rights reserved. +// SPDX-License-Identifier: MIT + +package git + +import ( + "context" + + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/setting" + api "code.gitea.io/gitea/modules/structs" + + "xorm.io/builder" +) + +// CommitStatusSummary holds the latest commit Status of a single Commit +type CommitStatusSummary struct { + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX UNIQUE(repo_id_sha)"` + SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_id_sha)"` + State api.CommitStatusState `xorm:"VARCHAR(7) NOT NULL"` +} + +func init() { + db.RegisterModel(new(CommitStatusSummary)) +} + +type RepoSHA struct { + RepoID int64 + SHA string +} + +func GetLatestCommitStatusForRepoAndSHAs(ctx context.Context, repoSHAs []RepoSHA) ([]*CommitStatus, error) { + cond := builder.NewCond() + for _, rs := range repoSHAs { + cond = cond.Or(builder.Eq{"repo_id": rs.RepoID, "sha": rs.SHA}) + } + + var summaries []CommitStatusSummary + if err := db.GetEngine(ctx).Where(cond).Find(&summaries); err != nil { + return nil, err + } + + commitStatuses := make([]*CommitStatus, 0, len(repoSHAs)) + for _, summary := range summaries { + commitStatuses = append(commitStatuses, &CommitStatus{ + RepoID: summary.RepoID, + SHA: summary.SHA, + State: summary.State, + }) + } + return commitStatuses, nil +} + +func UpdateCommitStatusSummary(ctx context.Context, repoID int64, sha string) error { + commitStatuses, _, err := GetLatestCommitStatus(ctx, repoID, sha, db.ListOptionsAll) + if err != nil { + return err + } + state := CalcCommitStatus(commitStatuses) + // mysql will return 0 when update a record which state hasn't been changed which behaviour is different from other database, + // so we need to use insert in on duplicate + if setting.Database.Type.IsMySQL() { + _, err := db.GetEngine(ctx).Exec("INSERT INTO commit_status_summary (repo_id,sha,state) VALUES (?,?,?) ON DUPLICATE KEY UPDATE state=?", + repoID, sha, state.State, state.State) + return err + } + + if cnt, err := db.GetEngine(ctx).Where("repo_id=? AND sha=?", repoID, sha). + Cols("state"). + Update(&CommitStatusSummary{ + State: state.State, + }); err != nil { + return err + } else if cnt == 0 { + _, err = db.GetEngine(ctx).Insert(&CommitStatusSummary{ + RepoID: repoID, + SHA: sha, + State: state.State, + }) + return err + } + return nil +} diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 387cd96a53..3ea8f2acbf 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -576,7 +576,10 @@ var migrations = []Migration{ // Gitea 1.22.0 ends at 294 + // v294 -> v295 NewMigration("Add unique index for project issue table", v1_23.AddUniqueIndexForProjectIssue), + // v295 -> v296 + NewMigration("Add commit status summary table", v1_23.AddCommitStatusSummary), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v1_23/v295.go b/models/migrations/v1_23/v295.go new file mode 100644 index 0000000000..9a2003cfc1 --- /dev/null +++ b/models/migrations/v1_23/v295.go @@ -0,0 +1,18 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_23 //nolint + +import "xorm.io/xorm" + +func AddCommitStatusSummary(x *xorm.Engine) error { + type CommitStatusSummary struct { + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX UNIQUE(repo_id_sha)"` + SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_id_sha)"` + State string `xorm:"VARCHAR(7) NOT NULL"` + } + // there is no migrations because if there is no data on this table, it will fall back to get data + // from commit status + return x.Sync2(new(CommitStatusSummary)) +} diff --git a/services/actions/commit_status.go b/services/actions/commit_status.go index 4236553927..eb031511f6 100644 --- a/services/actions/commit_status.go +++ b/services/actions/commit_status.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/log" api "code.gitea.io/gitea/modules/structs" webhook_module "code.gitea.io/gitea/modules/webhook" + commitstatus_service "code.gitea.io/gitea/services/repository/commitstatus" "github.com/nektos/act/pkg/jobparser" ) @@ -122,18 +123,13 @@ func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er if err != nil { return fmt.Errorf("HashTypeInterfaceFromHashString: %w", err) } - if err := git_model.NewCommitStatus(ctx, git_model.NewCommitStatusOptions{ - Repo: repo, - SHA: commitID, - Creator: creator, - CommitStatus: &git_model.CommitStatus{ - SHA: sha, - TargetURL: fmt.Sprintf("%s/jobs/%d", run.Link(), index), - Description: description, - Context: ctxname, - CreatorID: creator.ID, - State: state, - }, + if err := commitstatus_service.CreateCommitStatus(ctx, repo, creator, commitID.String(), &git_model.CommitStatus{ + SHA: sha, + TargetURL: fmt.Sprintf("%s/jobs/%d", run.Link(), index), + Description: description, + Context: ctxname, + CreatorID: creator.ID, + State: state, }); err != nil { return fmt.Errorf("NewCommitStatus: %w", err) } diff --git a/services/repository/commitstatus/commitstatus.go b/services/repository/commitstatus/commitstatus.go index 145fc7d53c..167a5330dd 100644 --- a/services/repository/commitstatus/commitstatus.go +++ b/services/repository/commitstatus/commitstatus.go @@ -7,6 +7,7 @@ import ( "context" "crypto/sha256" "fmt" + "slices" "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" @@ -59,13 +60,19 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato sha = commit.ID.String() } - if err := git_model.NewCommitStatus(ctx, git_model.NewCommitStatusOptions{ - Repo: repo, - Creator: creator, - SHA: commit.ID, - CommitStatus: status, + if err := db.WithTx(ctx, func(ctx context.Context) error { + if err := git_model.NewCommitStatus(ctx, git_model.NewCommitStatusOptions{ + Repo: repo, + Creator: creator, + SHA: commit.ID, + CommitStatus: status, + }); err != nil { + return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %w", repo.ID, creator.ID, sha, err) + } + + return git_model.UpdateCommitStatusSummary(ctx, repo.ID, commit.ID.String()) }); err != nil { - return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %w", repo.ID, creator.ID, sha, err) + return err } defaultBranchCommit, err := gitRepo.GetBranchCommit(repo.DefaultBranch) @@ -114,8 +121,35 @@ func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Rep return nil, fmt.Errorf("FindBranchesByRepoAndBranchName: %v", err) } + var repoSHAs []git_model.RepoSHA + for id, sha := range repoIDsToLatestCommitSHAs { + repoSHAs = append(repoSHAs, git_model.RepoSHA{RepoID: id, SHA: sha}) + } + + summaryResults, err := git_model.GetLatestCommitStatusForRepoAndSHAs(ctx, repoSHAs) + if err != nil { + return nil, fmt.Errorf("GetLatestCommitStatusForRepoAndSHAs: %v", err) + } + + for _, summary := range summaryResults { + for i, repo := range repos { + if repo.ID == summary.RepoID { + results[i] = summary + _ = slices.DeleteFunc(repoSHAs, func(repoSHA git_model.RepoSHA) bool { + return repoSHA.RepoID == repo.ID + }) + if results[i].State != "" { + if err := updateCommitStatusCache(ctx, repo.ID, repo.DefaultBranch, results[i].State); err != nil { + log.Error("updateCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err) + } + } + break + } + } + } + // call the database O(1) times to get the commit statuses for all repos - repoToItsLatestCommitStatuses, err := git_model.GetLatestCommitStatusForPairs(ctx, repoIDsToLatestCommitSHAs, db.ListOptionsAll) + repoToItsLatestCommitStatuses, err := git_model.GetLatestCommitStatusForPairs(ctx, repoSHAs) if err != nil { return nil, fmt.Errorf("GetLatestCommitStatusForPairs: %v", err) } diff --git a/tests/integration/pull_status_test.go b/tests/integration/pull_status_test.go index 26c99e6445..bb7098e424 100644 --- a/tests/integration/pull_status_test.go +++ b/tests/integration/pull_status_test.go @@ -12,6 +12,9 @@ import ( "testing" auth_model "code.gitea.io/gitea/models/auth" + git_model "code.gitea.io/gitea/models/git" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" api "code.gitea.io/gitea/modules/structs" "github.com/stretchr/testify/assert" @@ -90,6 +93,10 @@ func TestPullCreate_CommitStatus(t *testing.T) { assert.True(t, ok) assert.Contains(t, cls, statesIcons[status]) } + + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user1", Name: "repo1"}) + css := unittest.AssertExistsAndLoadBean(t, &git_model.CommitStatusSummary{RepoID: repo1.ID, SHA: commitID}) + assert.EqualValues(t, api.CommitStatusWarning, css.State) }) } From e8a99c8f92c5b36382abb38a1471c94245457560 Mon Sep 17 00:00:00 2001 From: HEREYUA <37935145+HEREYUA@users.noreply.github.com> Date: Fri, 12 Apr 2024 10:08:58 +0800 Subject: [PATCH 088/370] Fix the spacing issue in the Project view (#30415) **fix**: [#30388](https://github.com/go-gitea/gitea/issues/30388) **before**  **after**  --- templates/org/projects/list.tmpl | 6 ++---- templates/org/projects/view.tmpl | 2 +- templates/user/overview/package_versions.tmpl | 6 ++---- templates/user/overview/packages.tmpl | 6 ++---- templates/user/profile.tmpl | 7 ++----- 5 files changed, 9 insertions(+), 18 deletions(-) diff --git a/templates/org/projects/list.tmpl b/templates/org/projects/list.tmpl index ec9cfece9a..80dde1c4d2 100644 --- a/templates/org/projects/list.tmpl +++ b/templates/org/projects/list.tmpl @@ -13,11 +13,9 @@ <div class="ui four wide column"> {{template "shared/user/profile_big_avatar" .}} </div> - <div class="ui twelve wide column"> - <div class="tw-mb-4"> + <div class="ui twelve wide column tw-mb-4"> {{template "user/overview/header" .}} - </div> - {{template "projects/list" .}} + {{template "projects/list" .}} </div> </div> </div> diff --git a/templates/org/projects/view.tmpl b/templates/org/projects/view.tmpl index 495204b06d..e1ab81c4cd 100644 --- a/templates/org/projects/view.tmpl +++ b/templates/org/projects/view.tmpl @@ -1,7 +1,7 @@ {{template "base/head" .}} <div role="main" aria-label="{{.Title}}" class="page-content repository projects view-project"> {{template "shared/user/org_profile_avatar" .}} - <div class="ui container"> + <div class="ui container tw-mb-4"> {{template "user/overview/header" .}} </div> <div class="ui container fluid padded"> diff --git a/templates/user/overview/package_versions.tmpl b/templates/user/overview/package_versions.tmpl index b2cc814e13..0ac2db0d86 100644 --- a/templates/user/overview/package_versions.tmpl +++ b/templates/user/overview/package_versions.tmpl @@ -13,11 +13,9 @@ <div class="ui four wide column"> {{template "shared/user/profile_big_avatar" .}} </div> - <div class="ui twelve wide column"> - <div class="tw-mb-4"> + <div class="ui twelve wide column tw-mb-4"> {{template "user/overview/header" .}} - </div> - {{template "package/shared/versionlist" .}} + {{template "package/shared/versionlist" .}} </div> </div> </div> diff --git a/templates/user/overview/packages.tmpl b/templates/user/overview/packages.tmpl index 95cb506e57..bb2238b919 100644 --- a/templates/user/overview/packages.tmpl +++ b/templates/user/overview/packages.tmpl @@ -13,11 +13,9 @@ <div class="ui four wide column"> {{template "shared/user/profile_big_avatar" .}} </div> - <div class="ui twelve wide column"> - <div class="tw-mb-4"> + <div class="ui twelve wide column tw-mb-4"> {{template "user/overview/header" .}} - </div> - {{template "package/shared/list" .}} + {{template "package/shared/list" .}} </div> </div> </div> diff --git a/templates/user/profile.tmpl b/templates/user/profile.tmpl index e68f79fae6..cf61bb906a 100644 --- a/templates/user/profile.tmpl +++ b/templates/user/profile.tmpl @@ -5,11 +5,8 @@ <div class="ui four wide column"> {{template "shared/user/profile_big_avatar" .}} </div> - <div class="ui twelve wide column"> - <div class="tw-mb-4"> - {{template "user/overview/header" .}} - </div> - + <div class="ui twelve wide column tw-mb-4"> + {{template "user/overview/header" .}} {{if eq .TabName "activity"}} {{if .ContextUser.KeepActivityPrivate}} <div class="ui info message"> From 7af074dbeebc3c863618992b43f84ec9e5ab9657 Mon Sep 17 00:00:00 2001 From: "Kazushi (Jam) Marukawa" <jam@pobox.com> Date: Fri, 12 Apr 2024 11:51:40 +0900 Subject: [PATCH 089/370] Change the default maxPerPage for gitbucket (#30392) This patch improves the migration from gitbucket to gitea. The gitbucket uses it's own internal perPage value (= 25) for paging and ignore per_page arguments in the requested URL. This cause gitea to migrate only 25 issues and 25 PRs from gitbucket repository. This may not happens on old gitbucket. But recent gitbucket 4.40 or 4.38.4 has this problem. This patch change to use this internally hardcoded perPage of gitbucket as gitea's maxPerPage numer when migrating from gitbucket. There are several perPage values in gitbucket like 25 for Isseus/PRs and 10 for Releases. Some of those API doesn't support paging yet. It sounds difficult to implement, but using the minimum number among them worked out very well. So, I use 10 in this patch. Brief descriptions of problems and this patch are also available in https://github.com/go-gitea/gitea/issues/30316. In addition, I'm not sure what kind of test cases are possible to write here. It's a test for migration, so it requires testing gitbucket server and gitea server, I guess. Please let me know if it is possible to write such test cases here. Thanks! --- services/migrations/gitbucket.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/services/migrations/gitbucket.go b/services/migrations/gitbucket.go index 5f11555839..4fe9e30a39 100644 --- a/services/migrations/gitbucket.go +++ b/services/migrations/gitbucket.go @@ -72,6 +72,11 @@ func (g *GitBucketDownloader) LogString() string { // NewGitBucketDownloader creates a GitBucket downloader func NewGitBucketDownloader(ctx context.Context, baseURL, userName, password, token, repoOwner, repoName string) *GitBucketDownloader { githubDownloader := NewGithubDownloaderV3(ctx, baseURL, userName, password, token, repoOwner, repoName) + // Gitbucket 4.40 uses different internal hard-coded perPage values. + // Issues, PRs, and other major parts use 25. Release page uses 10. + // Some API doesn't support paging yet. Sounds difficult, but using + // minimum number among them worked out very well. + githubDownloader.maxPerPage = 10 githubDownloader.SkipReactions = true githubDownloader.SkipReviews = true return &GitBucketDownloader{ From f9fdac9809335729b2ac3227b2a5f71a62fc64ad Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Fri, 12 Apr 2024 11:36:34 +0800 Subject: [PATCH 090/370] Limit the max line length when parsing git grep output (#30418) --- modules/git/grep.go | 20 ++++++++++++++++---- modules/git/grep_test.go | 10 ++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/modules/git/grep.go b/modules/git/grep.go index a6c486112a..e7d238e586 100644 --- a/modules/git/grep.go +++ b/modules/git/grep.go @@ -10,6 +10,7 @@ import ( "errors" "fmt" "os" + "slices" "strconv" "strings" @@ -27,6 +28,7 @@ type GrepOptions struct { MaxResultLimit int ContextLineNumber int IsFuzzy bool + MaxLineLength int // the maximum length of a line to parse, exceeding chars will be truncated } func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepOptions) ([]*GrepResult, error) { @@ -71,10 +73,20 @@ func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepO defer stdoutReader.Close() isInBlock := false - scanner := bufio.NewScanner(stdoutReader) + rd := bufio.NewReaderSize(stdoutReader, util.IfZero(opts.MaxLineLength, 16*1024)) var res *GrepResult - for scanner.Scan() { - line := scanner.Text() + for { + lineBytes, isPrefix, err := rd.ReadLine() + if isPrefix { + lineBytes = slices.Clone(lineBytes) + for isPrefix && err == nil { + _, isPrefix, err = rd.ReadLine() + } + } + if len(lineBytes) == 0 && err != nil { + break + } + line := string(lineBytes) // the memory of lineBytes is mutable if !isInBlock { if _ /* ref */, filename, ok := strings.Cut(line, ":"); ok { isInBlock = true @@ -100,7 +112,7 @@ func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepO res.LineCodes = append(res.LineCodes, lineCode) } } - return scanner.Err() + return nil }, }) // git grep exits by cancel (killed), usually it is caused by the limit of results diff --git a/modules/git/grep_test.go b/modules/git/grep_test.go index b5fa437c53..7f4ded478f 100644 --- a/modules/git/grep_test.go +++ b/modules/git/grep_test.go @@ -41,6 +41,16 @@ func TestGrepSearch(t *testing.T) { }, }, res) + res, err = GrepSearch(context.Background(), repo, "void", GrepOptions{MaxResultLimit: 1, MaxLineLength: 39}) + assert.NoError(t, err) + assert.Equal(t, []*GrepResult{ + { + Filename: "java-hello/main.java", + LineNumbers: []int{3}, + LineCodes: []string{" public static void main(String[] arg"}, + }, + }, res) + res, err = GrepSearch(context.Background(), repo, "no-such-content", GrepOptions{}) assert.NoError(t, err) assert.Len(t, res, 0) From 9466fec879f4f2c88c7c1e7a5cffba319282ab66 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Fri, 12 Apr 2024 18:11:16 +0800 Subject: [PATCH 091/370] Fix rename branch 500 when the target branch is deleted but exist in database (#30430) Fix #30428 --- models/git/branch.go | 31 ++++++-- routers/web/repo/setting/protected_branch.go | 8 +- tests/integration/rename_branch_test.go | 80 ++++++++++++++++++-- 3 files changed, 107 insertions(+), 12 deletions(-) diff --git a/models/git/branch.go b/models/git/branch.go index fa0781fed1..2979dff3d2 100644 --- a/models/git/branch.go +++ b/models/git/branch.go @@ -297,6 +297,7 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str sess := db.GetEngine(ctx) + // check whether from branch exist var branch Branch exist, err := db.GetEngine(ctx).Where("repo_id=? AND name=?", repo.ID, from).Get(&branch) if err != nil { @@ -308,6 +309,24 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str } } + // check whether to branch exist or is_deleted + var dstBranch Branch + exist, err = db.GetEngine(ctx).Where("repo_id=? AND name=?", repo.ID, to).Get(&dstBranch) + if err != nil { + return err + } + if exist { + if !dstBranch.IsDeleted { + return ErrBranchAlreadyExists{ + BranchName: to, + } + } + + if _, err := db.GetEngine(ctx).ID(dstBranch.ID).NoAutoCondition().Delete(&dstBranch); err != nil { + return err + } + } + // 1. update branch in database if n, err := sess.Where("repo_id=? AND name=?", repo.ID, from).Update(&Branch{ Name: to, @@ -362,12 +381,7 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str return err } - // 5. do git action - if err = gitAction(ctx, isDefault); err != nil { - return err - } - - // 6. insert renamed branch record + // 5. insert renamed branch record renamedBranch := &RenamedBranch{ RepoID: repo.ID, From: from, @@ -378,6 +392,11 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str return err } + // 6. do git action + if err = gitAction(ctx, isDefault); err != nil { + return err + } + return committer.Commit() } diff --git a/routers/web/repo/setting/protected_branch.go b/routers/web/repo/setting/protected_branch.go index b30dc3b061..4bab3f897a 100644 --- a/routers/web/repo/setting/protected_branch.go +++ b/routers/web/repo/setting/protected_branch.go @@ -313,7 +313,13 @@ func RenameBranchPost(ctx *context.Context) { msg, err := repository.RenameBranch(ctx, ctx.Repo.Repository, ctx.Doer, ctx.Repo.GitRepo, form.From, form.To) if err != nil { - ctx.ServerError("RenameBranch", err) + switch { + case git_model.IsErrBranchAlreadyExists(err): + ctx.Flash.Error(ctx.Tr("repo.branch.branch_already_exists", form.To)) + ctx.Redirect(fmt.Sprintf("%s/branches", ctx.Repo.RepoLink)) + default: + ctx.ServerError("RenameBranch", err) + } return } diff --git a/tests/integration/rename_branch_test.go b/tests/integration/rename_branch_test.go index 703fc243a4..13f6cf204b 100644 --- a/tests/integration/rename_branch_test.go +++ b/tests/integration/rename_branch_test.go @@ -5,17 +5,23 @@ package integration import ( "net/http" + "net/url" "testing" git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" + gitea_context "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/tests" "github.com/stretchr/testify/assert" ) func TestRenameBranch(t *testing.T) { + onGiteaRun(t, testRenameBranch) +} + +func testRenameBranch(t *testing.T, u *url.URL) { defer tests.PrepareTestEnv(t)() unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: 1, Name: "master"}) @@ -26,20 +32,19 @@ func TestRenameBranch(t *testing.T) { resp := session.MakeRequest(t, req, http.StatusOK) htmlDoc := NewHTMLParser(t, resp.Body) - postData := map[string]string{ + req = NewRequestWithValues(t, "POST", "/user2/repo1/settings/rename_branch", map[string]string{ "_csrf": htmlDoc.GetCSRF(), "from": "master", "to": "main", - } - req = NewRequestWithValues(t, "POST", "/user2/repo1/settings/rename_branch", postData) + }) session.MakeRequest(t, req, http.StatusSeeOther) // check new branch link - req = NewRequestWithValues(t, "GET", "/user2/repo1/src/branch/main/README.md", postData) + req = NewRequestWithValues(t, "GET", "/user2/repo1/src/branch/main/README.md", nil) session.MakeRequest(t, req, http.StatusOK) // check old branch link - req = NewRequestWithValues(t, "GET", "/user2/repo1/src/branch/master/README.md", postData) + req = NewRequestWithValues(t, "GET", "/user2/repo1/src/branch/master/README.md", nil) resp = session.MakeRequest(t, req, http.StatusSeeOther) location := resp.Header().Get("Location") assert.Equal(t, "/user2/repo1/src/branch/main/README.md", location) @@ -47,4 +52,69 @@ func TestRenameBranch(t *testing.T) { // check db repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) assert.Equal(t, "main", repo1.DefaultBranch) + + // create branch1 + csrf := GetCSRF(t, session, "/user2/repo1/src/branch/main") + + req = NewRequestWithValues(t, "POST", "/user2/repo1/branches/_new/branch/main", map[string]string{ + "_csrf": csrf, + "new_branch_name": "branch1", + }) + session.MakeRequest(t, req, http.StatusSeeOther) + + branch1 := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo1.ID, Name: "branch1"}) + assert.Equal(t, "branch1", branch1.Name) + + // create branch2 + req = NewRequestWithValues(t, "POST", "/user2/repo1/branches/_new/branch/main", map[string]string{ + "_csrf": csrf, + "new_branch_name": "branch2", + }) + session.MakeRequest(t, req, http.StatusSeeOther) + + branch2 := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo1.ID, Name: "branch2"}) + assert.Equal(t, "branch2", branch2.Name) + + // rename branch2 to branch1 + req = NewRequestWithValues(t, "POST", "/user2/repo1/settings/rename_branch", map[string]string{ + "_csrf": htmlDoc.GetCSRF(), + "from": "branch2", + "to": "branch1", + }) + session.MakeRequest(t, req, http.StatusSeeOther) + flashCookie := session.GetCookie(gitea_context.CookieNameFlash) + assert.NotNil(t, flashCookie) + assert.Contains(t, flashCookie.Value, "error") + + branch2 = unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo1.ID, Name: "branch2"}) + assert.Equal(t, "branch2", branch2.Name) + branch1 = unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo1.ID, Name: "branch1"}) + assert.Equal(t, "branch1", branch1.Name) + + // delete branch1 + req = NewRequestWithValues(t, "POST", "/user2/repo1/branches/delete", map[string]string{ + "_csrf": htmlDoc.GetCSRF(), + "name": "branch1", + }) + session.MakeRequest(t, req, http.StatusOK) + branch2 = unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo1.ID, Name: "branch2"}) + assert.Equal(t, "branch2", branch2.Name) + branch1 = unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo1.ID, Name: "branch1"}) + assert.True(t, branch1.IsDeleted) // virtual deletion + + // rename branch2 to branch1 again + req = NewRequestWithValues(t, "POST", "/user2/repo1/settings/rename_branch", map[string]string{ + "_csrf": htmlDoc.GetCSRF(), + "from": "branch2", + "to": "branch1", + }) + session.MakeRequest(t, req, http.StatusSeeOther) + + flashCookie = session.GetCookie(gitea_context.CookieNameFlash) + assert.NotNil(t, flashCookie) + assert.Contains(t, flashCookie.Value, "success") + + unittest.AssertNotExistsBean(t, &git_model.Branch{RepoID: repo1.ID, Name: "branch2"}) + branch1 = unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo1.ID, Name: "branch1"}) + assert.Equal(t, "branch1", branch1.Name) } From 25427e0aee435cdedb9f8aae58767174d877767f Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Fri, 12 Apr 2024 13:34:12 +0300 Subject: [PATCH 092/370] Remove jQuery from the commit graph (except Fomantic) (#30395) - Switched to plain JavaScript - Tested the commit graph and it works as before # Demo using JavaScript without jQuery  --------- Signed-off-by: Yarden Shoham <git@yardenshoham.com> Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: delvh <dev.lh@web.de> Co-authored-by: Giteabot <teabot@gitea.io> --- web_src/js/features/repo-graph.js | 138 +++++++++++++++++------------- 1 file changed, 77 insertions(+), 61 deletions(-) diff --git a/web_src/js/features/repo-graph.js b/web_src/js/features/repo-graph.js index a5b61bff54..0086b92021 100644 --- a/web_src/js/features/repo-graph.js +++ b/web_src/js/features/repo-graph.js @@ -1,14 +1,16 @@ import $ from 'jquery'; +import {hideElem, showElem} from '../utils/dom.js'; import {GET} from '../modules/fetch.js'; export function initRepoGraphGit() { const graphContainer = document.getElementById('git-graph-container'); if (!graphContainer) return; - $('#flow-color-monochrome').on('click', () => { - $('#flow-color-monochrome').addClass('active'); - $('#flow-color-colored').removeClass('active'); - $('#git-graph-container').removeClass('colored').addClass('monochrome'); + document.getElementById('flow-color-monochrome')?.addEventListener('click', () => { + document.getElementById('flow-color-monochrome').classList.add('active'); + document.getElementById('flow-color-colored')?.classList.remove('active'); + graphContainer.classList.remove('colored'); + graphContainer.classList.add('monochrome'); const params = new URLSearchParams(window.location.search); params.set('mode', 'monochrome'); const queryString = params.toString(); @@ -17,29 +19,31 @@ export function initRepoGraphGit() { } else { window.history.replaceState({}, '', window.location.pathname); } - $('.pagination a').each((_, that) => { - const href = that.getAttribute('href'); - if (!href) return; + for (const link of document.querySelectorAll('.pagination a')) { + const href = link.getAttribute('href'); + if (!href) continue; const url = new URL(href, window.location); const params = url.searchParams; params.set('mode', 'monochrome'); url.search = `?${params.toString()}`; - that.setAttribute('href', url.href); - }); + link.setAttribute('href', url.href); + } }); - $('#flow-color-colored').on('click', () => { - $('#flow-color-colored').addClass('active'); - $('#flow-color-monochrome').removeClass('active'); - $('#git-graph-container').addClass('colored').removeClass('monochrome'); - $('.pagination a').each((_, that) => { - const href = that.getAttribute('href'); - if (!href) return; + + document.getElementById('flow-color-colored')?.addEventListener('click', () => { + document.getElementById('flow-color-colored').classList.add('active'); + document.getElementById('flow-color-monochrome')?.classList.remove('active'); + graphContainer.classList.add('colored'); + graphContainer.classList.remove('monochrome'); + for (const link of document.querySelectorAll('.pagination a')) { + const href = link.getAttribute('href'); + if (!href) continue; const url = new URL(href, window.location); const params = url.searchParams; params.delete('mode'); url.search = `?${params.toString()}`; - that.setAttribute('href', url.href); - }); + link.setAttribute('href', url.href); + } const params = new URLSearchParams(window.location.search); params.delete('mode'); const queryString = params.toString(); @@ -56,20 +60,21 @@ export function initRepoGraphGit() { const ajaxUrl = new URL(url); ajaxUrl.searchParams.set('div-only', 'true'); window.history.replaceState({}, '', queryString ? `?${queryString}` : window.location.pathname); - $('#pagination').empty(); - $('#rel-container').addClass('tw-hidden'); - $('#rev-container').addClass('tw-hidden'); - $('#loading-indicator').removeClass('tw-hidden'); + document.getElementById('pagination').innerHTML = ''; + hideElem('#rel-container'); + hideElem('#rev-container'); + showElem('#loading-indicator'); (async () => { const response = await GET(String(ajaxUrl)); const html = await response.text(); - const $div = $(html); - $('#pagination').html($div.find('#pagination').html()); - $('#rel-container').html($div.find('#rel-container').html()); - $('#rev-container').html($div.find('#rev-container').html()); - $('#loading-indicator').addClass('tw-hidden'); - $('#rel-container').removeClass('tw-hidden'); - $('#rev-container').removeClass('tw-hidden'); + const div = document.createElement('div'); + div.innerHTML = html; + document.getElementById('pagination').innerHTML = div.getElementById('pagination').innerHTML; + document.getElementById('rel-container').innerHTML = div.getElementById('rel-container').innerHTML; + document.getElementById('rev-container').innerHTML = div.getElementById('rev-container').innerHTML; + hideElem('#loading-indicator'); + showElem('#rel-container'); + showElem('#rev-container'); })(); }; const dropdownSelected = params.getAll('branch'); @@ -77,8 +82,9 @@ export function initRepoGraphGit() { dropdownSelected.splice(0, 0, '...flow-hide-pr-refs'); } - $('#flow-select-refs-dropdown').dropdown('set selected', dropdownSelected); - $('#flow-select-refs-dropdown').dropdown({ + const flowSelectRefsDropdown = document.getElementById('flow-select-refs-dropdown'); + $(flowSelectRefsDropdown).dropdown('set selected', dropdownSelected); + $(flowSelectRefsDropdown).dropdown({ clearable: true, fullTextSeach: 'exact', onRemove(toRemove) { @@ -104,36 +110,46 @@ export function initRepoGraphGit() { updateGraph(); }, }); - $('#git-graph-container').on('mouseenter', '#rev-list li', (e) => { - const flow = $(e.currentTarget).data('flow'); - if (flow === 0) return; - $(`#flow-${flow}`).addClass('highlight'); - $(e.currentTarget).addClass('hover'); - $(`#rev-list li[data-flow='${flow}']`).addClass('highlight'); + + graphContainer.addEventListener('mouseenter', (e) => { + if (e.target.matches('#rev-list li')) { + const flow = e.target.getAttribute('data-flow'); + if (flow === '0') return; + document.getElementById(`flow-${flow}`)?.classList.add('highlight'); + e.target.classList.add('hover'); + for (const item of document.querySelectorAll(`#rev-list li[data-flow='${flow}']`)) { + item.classList.add('highlight'); + } + } else if (e.target.matches('#rel-container .flow-group')) { + e.target.classList.add('highlight'); + const flow = e.target.getAttribute('data-flow'); + for (const item of document.querySelectorAll(`#rev-list li[data-flow='${flow}']`)) { + item.classList.add('highlight'); + } + } else if (e.target.matches('#rel-container .flow-commit')) { + const rev = e.target.getAttribute('data-rev'); + document.querySelector(`#rev-list li#commit-${rev}`)?.classList.add('hover'); + } }); - $('#git-graph-container').on('mouseleave', '#rev-list li', (e) => { - const flow = $(e.currentTarget).data('flow'); - if (flow === 0) return; - $(`#flow-${flow}`).removeClass('highlight'); - $(e.currentTarget).removeClass('hover'); - $(`#rev-list li[data-flow='${flow}']`).removeClass('highlight'); - }); - $('#git-graph-container').on('mouseenter', '#rel-container .flow-group', (e) => { - $(e.currentTarget).addClass('highlight'); - const flow = $(e.currentTarget).data('flow'); - $(`#rev-list li[data-flow='${flow}']`).addClass('highlight'); - }); - $('#git-graph-container').on('mouseleave', '#rel-container .flow-group', (e) => { - $(e.currentTarget).removeClass('highlight'); - const flow = $(e.currentTarget).data('flow'); - $(`#rev-list li[data-flow='${flow}']`).removeClass('highlight'); - }); - $('#git-graph-container').on('mouseenter', '#rel-container .flow-commit', (e) => { - const rev = $(e.currentTarget).data('rev'); - $(`#rev-list li#commit-${rev}`).addClass('hover'); - }); - $('#git-graph-container').on('mouseleave', '#rel-container .flow-commit', (e) => { - const rev = $(e.currentTarget).data('rev'); - $(`#rev-list li#commit-${rev}`).removeClass('hover'); + + graphContainer.addEventListener('mouseleave', (e) => { + if (e.target.matches('#rev-list li')) { + const flow = e.target.getAttribute('data-flow'); + if (flow === '0') return; + document.getElementById(`flow-${flow}`)?.classList.remove('highlight'); + e.target.classList.remove('hover'); + for (const item of document.querySelectorAll(`#rev-list li[data-flow='${flow}']`)) { + item.classList.remove('highlight'); + } + } else if (e.target.matches('#rel-container .flow-group')) { + e.target.classList.remove('highlight'); + const flow = e.target.getAttribute('data-flow'); + for (const item of document.querySelectorAll(`#rev-list li[data-flow='${flow}']`)) { + item.classList.remove('highlight'); + } + } else if (e.target.matches('#rel-container .flow-commit')) { + const rev = e.target.getAttribute('data-rev'); + document.querySelector(`#rev-list li#commit-${rev}`)?.classList.remove('hover'); + } }); } From f9c3e79abac9dc417cdbbddf24a9fb8dc49363c4 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Fri, 12 Apr 2024 19:02:42 +0800 Subject: [PATCH 093/370] Fix commit status cache which missed target_url (#30426) Fix #30421 --------- Co-authored-by: Jason Song <i@wolfogre.com> --- .../repository/commitstatus/commitstatus.go | 54 ++++++++++++++----- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/services/repository/commitstatus/commitstatus.go b/services/repository/commitstatus/commitstatus.go index 167a5330dd..7c1c6c2609 100644 --- a/services/repository/commitstatus/commitstatus.go +++ b/services/repository/commitstatus/commitstatus.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" + "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/services/automerge" @@ -26,12 +27,41 @@ func getCacheKey(repoID int64, brancheName string) string { return fmt.Sprintf("commit_status:%x", hashBytes) } -func updateCommitStatusCache(ctx context.Context, repoID int64, branchName string, status api.CommitStatusState) error { - c := cache.GetCache() - return c.Put(getCacheKey(repoID, branchName), string(status), 3*24*60) +type commitStatusCacheValue struct { + State string `json:"state"` + TargetURL string `json:"target_url"` } -func deleteCommitStatusCache(ctx context.Context, repoID int64, branchName string) error { +func getCommitStatusCache(repoID int64, branchName string) *commitStatusCacheValue { + c := cache.GetCache() + statusStr, ok := c.Get(getCacheKey(repoID, branchName)).(string) + if ok && statusStr != "" { + var cv commitStatusCacheValue + err := json.Unmarshal([]byte(statusStr), &cv) + if err == nil && cv.State != "" { + return &cv + } + if err != nil { + log.Warn("getCommitStatusCache: json.Unmarshal failed: %v", err) + } + } + return nil +} + +func updateCommitStatusCache(repoID int64, branchName string, state api.CommitStatusState, targetURL string) error { + c := cache.GetCache() + bs, err := json.Marshal(commitStatusCacheValue{ + State: state.String(), + TargetURL: targetURL, + }) + if err != nil { + log.Warn("updateCommitStatusCache: json.Marshal failed: %v", err) + return nil + } + return c.Put(getCacheKey(repoID, branchName), string(bs), 3*24*60) +} + +func deleteCommitStatusCache(repoID int64, branchName string) error { c := cache.GetCache() return c.Delete(getCacheKey(repoID, branchName)) } @@ -81,7 +111,7 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato } if commit.ID.String() == defaultBranchCommit.ID.String() { // since one commit status updated, the combined commit status should be invalid - if err := deleteCommitStatusCache(ctx, repo.ID, repo.DefaultBranch); err != nil { + if err := deleteCommitStatusCache(repo.ID, repo.DefaultBranch); err != nil { log.Error("deleteCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err) } } @@ -98,12 +128,12 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato // FindReposLastestCommitStatuses loading repository default branch latest combinded commit status with cache func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Repository) ([]*git_model.CommitStatus, error) { results := make([]*git_model.CommitStatus, len(repos)) - c := cache.GetCache() - for i, repo := range repos { - status, ok := c.Get(getCacheKey(repo.ID, repo.DefaultBranch)).(string) - if ok && status != "" { - results[i] = &git_model.CommitStatus{State: api.CommitStatusState(status)} + if cv := getCommitStatusCache(repo.ID, repo.DefaultBranch); cv != nil { + results[i] = &git_model.CommitStatus{ + State: api.CommitStatusState(cv.State), + TargetURL: cv.TargetURL, + } } } @@ -139,7 +169,7 @@ func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Rep return repoSHA.RepoID == repo.ID }) if results[i].State != "" { - if err := updateCommitStatusCache(ctx, repo.ID, repo.DefaultBranch, results[i].State); err != nil { + if err := updateCommitStatusCache(repo.ID, repo.DefaultBranch, results[i].State, results[i].TargetURL); err != nil { log.Error("updateCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err) } } @@ -158,7 +188,7 @@ func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Rep if results[i] == nil { results[i] = git_model.CalcCommitStatus(repoToItsLatestCommitStatuses[repo.ID]) if results[i].State != "" { - if err := updateCommitStatusCache(ctx, repo.ID, repo.DefaultBranch, results[i].State); err != nil { + if err := updateCommitStatusCache(repo.ID, repo.DefaultBranch, results[i].State, results[i].TargetURL); err != nil { log.Error("updateCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err) } } From 487b12783fb2dba7459a8aa739162cfe6bab3904 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Fri, 12 Apr 2024 14:52:39 +0200 Subject: [PATCH 094/370] Lock a few tool dependencies to major versions (#30439) It's better having to update these less often, so unlock a few dependencies that I trust enough to not break to their latest major versions. This excludes any tool still at major version 0 and golangci-lint can't really be unlocked either because new versions almost always break there. For the v0 packages, I've opened https://github.com/golangci/misspell/issues/14 and https://github.com/mvdan/gofumpt/issues/303. --- Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index ee9c90e8d9..f1acfbc81e 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ COMMA := , XGO_VERSION := go-1.22.x -AIR_PACKAGE ?= github.com/cosmtrek/air@v1.49.0 +AIR_PACKAGE ?= github.com/cosmtrek/air@v1 EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.7.0 GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.6.0 GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.57.2 @@ -33,9 +33,9 @@ GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11 MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.4.1 SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@db51e79a0e37c572d8b59ae0c58bf2bbbbe53285 XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest -GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.6.0 -GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1.0.3 -ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.6.26 +GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1 +GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 +ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1 DOCKER_IMAGE ?= gitea/gitea DOCKER_TAG ?= latest From 68271834d6ae6d397b5a2048f9e515ff53735994 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sat, 13 Apr 2024 04:28:20 +0200 Subject: [PATCH 095/370] Add `/public/assets/img/webpack` to ignore files again (#30451) Fixes https://github.com/go-gitea/gitea/issues/30442 It's inconvenient to have new untracked files show up in git when switching to older branches that had generated them. Introduce a list of such files and folders to gitignore and dockerignore. --- .dockerignore | 3 +++ .gitignore | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.dockerignore b/.dockerignore index b299c7313d..b696e1603c 100644 --- a/.dockerignore +++ b/.dockerignore @@ -95,6 +95,9 @@ cpu.out /.air /.go-licenses +# Files and folders that were previously generated +/public/assets/img/webpack + # Snapcraft snap/.snapcraft/ parts/ diff --git a/.gitignore b/.gitignore index 501fef7dcf..46c8b9b49c 100644 --- a/.gitignore +++ b/.gitignore @@ -94,6 +94,9 @@ cpu.out /.air /.go-licenses +# Files and folders that were previously generated +/public/assets/img/webpack + # Snapcraft /gitea_a*.txt snap/.snapcraft/ From b4d86912ef18c58e973ee10c4a3bc621e9bd6c52 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Sat, 13 Apr 2024 12:01:02 +0900 Subject: [PATCH 096/370] Fix mirror error when mirror repo is empty (#30432) Fix #30424 Co-authored-by: Giteabot <teabot@gitea.io> --- services/mirror/mirror_pull.go | 40 +++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index 2a38d4ba55..21d5f08205 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -449,19 +449,17 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { return false } - var gitRepo *git.Repository - if len(results) == 0 { - log.Trace("SyncMirrors [repo: %-v]: no branches updated", m.Repo) - } else { - log.Trace("SyncMirrors [repo: %-v]: %d branches updated", m.Repo, len(results)) - gitRepo, err = gitrepo.OpenRepository(ctx, m.Repo) - if err != nil { - log.Error("SyncMirrors [repo: %-v]: unable to OpenRepository: %v", m.Repo, err) - return false - } - defer gitRepo.Close() + gitRepo, err := gitrepo.OpenRepository(ctx, m.Repo) + if err != nil { + log.Error("SyncMirrors [repo: %-v]: unable to OpenRepository: %v", m.Repo, err) + return false + } + defer gitRepo.Close() + log.Trace("SyncMirrors [repo: %-v]: %d branches updated", m.Repo, len(results)) + if len(results) > 0 { if ok := checkAndUpdateEmptyRepository(ctx, m, gitRepo, results); !ok { + log.Error("SyncMirrors [repo: %-v]: checkAndUpdateEmptyRepository: %v", m.Repo, err) return false } } @@ -534,16 +532,24 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { } log.Trace("SyncMirrors [repo: %-v]: done notifying updated branches/tags - now updating last commit time", m.Repo) - // Get latest commit date and update to current repository updated time - commitDate, err := git.GetLatestCommitTime(ctx, m.Repo.RepoPath()) + isEmpty, err := gitRepo.IsEmpty() if err != nil { - log.Error("SyncMirrors [repo: %-v]: unable to GetLatestCommitDate: %v", m.Repo, err) + log.Error("SyncMirrors [repo: %-v]: unable to check empty git repo: %v", m.Repo, err) return false } + if !isEmpty { + // Get latest commit date and update to current repository updated time + commitDate, err := git.GetLatestCommitTime(ctx, m.Repo.RepoPath()) + if err != nil { + log.Error("SyncMirrors [repo: %-v]: unable to GetLatestCommitDate: %v", m.Repo, err) + return false + } + + if err = repo_model.UpdateRepositoryUpdatedTime(ctx, m.RepoID, commitDate); err != nil { + log.Error("SyncMirrors [repo: %-v]: unable to update repository 'updated_unix': %v", m.Repo, err) + return false + } - if err = repo_model.UpdateRepositoryUpdatedTime(ctx, m.RepoID, commitDate); err != nil { - log.Error("SyncMirrors [repo: %-v]: unable to update repository 'updated_unix': %v", m.Repo, err) - return false } log.Trace("SyncMirrors [repo: %-v]: Successfully updated", m.Repo) From 8fd8978b4934865c2b041216e84e923ad574a4c7 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sat, 13 Apr 2024 09:46:02 +0200 Subject: [PATCH 097/370] Fix admin notice view-detail (#30450) Fix https://github.com/go-gitea/gitea/issues/30434, regression from https://github.com/go-gitea/gitea/pull/30115. I also removed the date insertion into the modal which was also broken since that date was switched to `absolute-date` because I see no real purpose to putting that date into the modal. Result: <img width="1038" alt="image" src="https://github.com/go-gitea/gitea/assets/115237/aa2eb8b4-73dc-4d98-9b80-3f276f89d9e5"> --- templates/admin/notice.tmpl | 5 +---- web_src/js/features/admin/common.js | 8 ++++---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/templates/admin/notice.tmpl b/templates/admin/notice.tmpl index 5ea003e5ec..33d8a2f963 100644 --- a/templates/admin/notice.tmpl +++ b/templates/admin/notice.tmpl @@ -62,10 +62,7 @@ <div class="ui modal admin" id="detail-modal"> <div class="header">{{ctx.Locale.Tr "admin.notices.view_detail_header"}}</div> - <div class="content"> - <div class="sub header"></div> - <pre></pre> - </div> + <div class="content"><pre></pre></div> </div> {{template "admin/layout_footer" .}} diff --git a/web_src/js/features/admin/common.js b/web_src/js/features/admin/common.js index f388b1122e..b35502d52f 100644 --- a/web_src/js/features/admin/common.js +++ b/web_src/js/features/admin/common.js @@ -207,13 +207,13 @@ export function initAdminCommon() { // Notice if (document.querySelector('.admin.notice')) { - const $detailModal = document.getElementById('detail-modal'); + const detailModal = document.getElementById('detail-modal'); // Attach view detail modals $('.view-detail').on('click', function () { - $detailModal.find('.content pre').text($(this).parents('tr').find('.notice-description').text()); - $detailModal.find('.sub.header').text(this.closest('tr')?.querySelector('relative-time')?.getAttribute('title')); - $detailModal.modal('show'); + const description = this.closest('tr').querySelector('.notice-description').textContent; + detailModal.querySelector('.content pre').textContent = description; + $(detailModal).modal('show'); return false; }); From c248f010ad08a7017ba1d418e9b6a5b72aff0c88 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sat, 13 Apr 2024 16:38:44 +0800 Subject: [PATCH 098/370] Refactor cache and disable go-chi cache (#30417) use built-in cache package to wrap external go-chi cache package --- .golangci.yml | 2 + modules/cache/cache.go | 138 ++++-------------- modules/cache/cache_redis.go | 2 +- modules/cache/cache_test.go | 40 +---- modules/cache/cache_twoqueue.go | 2 +- modules/cache/string_cache.go | 120 +++++++++++++++ modules/git/last_commit_cache.go | 15 +- routers/api/v1/misc/nodeinfo.go | 6 +- services/context/api.go | 8 +- services/context/captcha.go | 2 +- services/context/context.go | 7 +- services/repository/branch.go | 11 +- .../repository/commitstatus/commitstatus.go | 2 +- services/repository/contributors_graph.go | 32 ++-- .../repository/contributors_graph_test.go | 20 ++- 15 files changed, 198 insertions(+), 209 deletions(-) create mode 100644 modules/cache/string_cache.go diff --git a/.golangci.yml b/.golangci.yml index 5be2cefe44..27fee20f75 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -86,6 +86,8 @@ linters-settings: desc: do not use the internal package, use AddXxx function instead - pkg: gopkg.in/ini.v1 desc: do not use the ini package, use gitea's config system instead + - pkg: gitea.com/go-chi/cache + desc: do not use the go-chi cache package, use gitea's cache system issues: max-issues-per-linter: 0 diff --git a/modules/cache/cache.go b/modules/cache/cache.go index 09afc8b7f7..2ca77bdb29 100644 --- a/modules/cache/cache.go +++ b/modules/cache/cache.go @@ -4,149 +4,75 @@ package cache import ( - "fmt" "strconv" + "time" "code.gitea.io/gitea/modules/setting" - - mc "gitea.com/go-chi/cache" - - _ "gitea.com/go-chi/cache/memcache" // memcache plugin for cache ) -var conn mc.Cache - -func newCache(cacheConfig setting.Cache) (mc.Cache, error) { - return mc.NewCacher(mc.Options{ - Adapter: cacheConfig.Adapter, - AdapterConfig: cacheConfig.Conn, - Interval: cacheConfig.Interval, - }) -} +var defaultCache StringCache // Init start cache service func Init() error { - var err error - - if conn == nil { - if conn, err = newCache(setting.CacheService.Cache); err != nil { + if defaultCache == nil { + c, err := NewStringCache(setting.CacheService.Cache) + if err != nil { return err } - if err = conn.Ping(); err != nil { + for i := 0; i < 10; i++ { + if err = c.Ping(); err == nil { + break + } + time.Sleep(time.Second) + } + if err != nil { return err } + defaultCache = c } - - return err + return nil } // GetCache returns the currently configured cache -func GetCache() mc.Cache { - return conn +func GetCache() StringCache { + return defaultCache } // GetString returns the key value from cache with callback when no key exists in cache func GetString(key string, getFunc func() (string, error)) (string, error) { - if conn == nil || setting.CacheService.TTL == 0 { + if defaultCache == nil || setting.CacheService.TTL == 0 { return getFunc() } - - cached := conn.Get(key) - - if cached == nil { + cached, exist := defaultCache.Get(key) + if !exist { value, err := getFunc() if err != nil { return value, err } - return value, conn.Put(key, value, setting.CacheService.TTLSeconds()) - } - - if value, ok := cached.(string); ok { - return value, nil - } - - if stringer, ok := cached.(fmt.Stringer); ok { - return stringer.String(), nil - } - - return fmt.Sprintf("%s", cached), nil -} - -// GetInt returns key value from cache with callback when no key exists in cache -func GetInt(key string, getFunc func() (int, error)) (int, error) { - if conn == nil || setting.CacheService.TTL == 0 { - return getFunc() - } - - cached := conn.Get(key) - - if cached == nil { - value, err := getFunc() - if err != nil { - return value, err - } - - return value, conn.Put(key, value, setting.CacheService.TTLSeconds()) - } - - switch v := cached.(type) { - case int: - return v, nil - case string: - value, err := strconv.Atoi(v) - if err != nil { - return 0, err - } - return value, nil - default: - value, err := getFunc() - if err != nil { - return value, err - } - return value, conn.Put(key, value, setting.CacheService.TTLSeconds()) + return value, defaultCache.Put(key, value, setting.CacheService.TTLSeconds()) } + return cached, nil } // GetInt64 returns key value from cache with callback when no key exists in cache func GetInt64(key string, getFunc func() (int64, error)) (int64, error) { - if conn == nil || setting.CacheService.TTL == 0 { - return getFunc() + s, err := GetString(key, func() (string, error) { + v, err := getFunc() + return strconv.FormatInt(v, 10), err + }) + if err != nil { + return 0, err } - - cached := conn.Get(key) - - if cached == nil { - value, err := getFunc() - if err != nil { - return value, err - } - - return value, conn.Put(key, value, setting.CacheService.TTLSeconds()) - } - - switch v := conn.Get(key).(type) { - case int64: - return v, nil - case string: - value, err := strconv.ParseInt(v, 10, 64) - if err != nil { - return 0, err - } - return value, nil - default: - value, err := getFunc() - if err != nil { - return value, err - } - - return value, conn.Put(key, value, setting.CacheService.TTLSeconds()) + if s == "" { + return 0, nil } + return strconv.ParseInt(s, 10, 64) } // Remove key from cache func Remove(key string) { - if conn == nil { + if defaultCache == nil { return } - _ = conn.Delete(key) + _ = defaultCache.Delete(key) } diff --git a/modules/cache/cache_redis.go b/modules/cache/cache_redis.go index 6c358b0a78..c5b52a2086 100644 --- a/modules/cache/cache_redis.go +++ b/modules/cache/cache_redis.go @@ -11,7 +11,7 @@ import ( "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/nosql" - "gitea.com/go-chi/cache" + "gitea.com/go-chi/cache" //nolint:depguard "github.com/redis/go-redis/v9" ) diff --git a/modules/cache/cache_test.go b/modules/cache/cache_test.go index 3f65040924..0c68cc26ee 100644 --- a/modules/cache/cache_test.go +++ b/modules/cache/cache_test.go @@ -14,7 +14,7 @@ import ( ) func createTestCache() { - conn, _ = newCache(setting.Cache{ + defaultCache, _ = NewStringCache(setting.Cache{ Adapter: "memory", TTL: time.Minute, }) @@ -25,7 +25,7 @@ func TestNewContext(t *testing.T) { assert.NoError(t, Init()) setting.CacheService.Cache = setting.Cache{Adapter: "redis", Conn: "some random string"} - con, err := newCache(setting.Cache{ + con, err := NewStringCache(setting.Cache{ Adapter: "rand", Conn: "false conf", Interval: 100, @@ -76,42 +76,6 @@ func TestGetString(t *testing.T) { Remove("key") } -func TestGetInt(t *testing.T) { - createTestCache() - - data, err := GetInt("key", func() (int, error) { - return 0, fmt.Errorf("some error") - }) - assert.Error(t, err) - assert.Equal(t, 0, data) - - data, err = GetInt("key", func() (int, error) { - return 0, nil - }) - assert.NoError(t, err) - assert.Equal(t, 0, data) - - data, err = GetInt("key", func() (int, error) { - return 100, nil - }) - assert.NoError(t, err) - assert.Equal(t, 0, data) - Remove("key") - - data, err = GetInt("key", func() (int, error) { - return 100, nil - }) - assert.NoError(t, err) - assert.Equal(t, 100, data) - - data, err = GetInt("key", func() (int, error) { - return 0, fmt.Errorf("some error") - }) - assert.NoError(t, err) - assert.Equal(t, 100, data) - Remove("key") -} - func TestGetInt64(t *testing.T) { createTestCache() diff --git a/modules/cache/cache_twoqueue.go b/modules/cache/cache_twoqueue.go index f9de2563ec..1eda2debc4 100644 --- a/modules/cache/cache_twoqueue.go +++ b/modules/cache/cache_twoqueue.go @@ -10,7 +10,7 @@ import ( "code.gitea.io/gitea/modules/json" - mc "gitea.com/go-chi/cache" + mc "gitea.com/go-chi/cache" //nolint:depguard lru "github.com/hashicorp/golang-lru/v2" ) diff --git a/modules/cache/string_cache.go b/modules/cache/string_cache.go new file mode 100644 index 0000000000..4f659616f5 --- /dev/null +++ b/modules/cache/string_cache.go @@ -0,0 +1,120 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package cache + +import ( + "errors" + "strings" + + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" + + chi_cache "gitea.com/go-chi/cache" //nolint:depguard +) + +type GetJSONError struct { + err error + cachedError string // Golang error can't be stored in cache, only the string message could be stored +} + +func (e *GetJSONError) ToError() error { + if e.err != nil { + return e.err + } + return errors.New("cached error: " + e.cachedError) +} + +type StringCache interface { + Ping() error + + Get(key string) (string, bool) + Put(key, value string, ttl int64) error + Delete(key string) error + IsExist(key string) bool + + PutJSON(key string, v any, ttl int64) error + GetJSON(key string, ptr any) (exist bool, err *GetJSONError) + + ChiCache() chi_cache.Cache +} + +type stringCache struct { + chiCache chi_cache.Cache +} + +func NewStringCache(cacheConfig setting.Cache) (StringCache, error) { + adapter := util.IfZero(cacheConfig.Adapter, "memory") + interval := util.IfZero(cacheConfig.Interval, 60) + cc, err := chi_cache.NewCacher(chi_cache.Options{ + Adapter: adapter, + AdapterConfig: cacheConfig.Conn, + Interval: interval, + }) + if err != nil { + return nil, err + } + return &stringCache{chiCache: cc}, nil +} + +func (sc *stringCache) Ping() error { + return sc.chiCache.Ping() +} + +func (sc *stringCache) Get(key string) (string, bool) { + v := sc.chiCache.Get(key) + if v == nil { + return "", false + } + s, ok := v.(string) + return s, ok +} + +func (sc *stringCache) Put(key, value string, ttl int64) error { + return sc.chiCache.Put(key, value, ttl) +} + +func (sc *stringCache) Delete(key string) error { + return sc.chiCache.Delete(key) +} + +func (sc *stringCache) IsExist(key string) bool { + return sc.chiCache.IsExist(key) +} + +const cachedErrorPrefix = "<CACHED-ERROR>:" + +func (sc *stringCache) PutJSON(key string, v any, ttl int64) error { + var s string + switch v := v.(type) { + case error: + s = cachedErrorPrefix + v.Error() + default: + b, err := json.Marshal(v) + if err != nil { + return err + } + s = util.UnsafeBytesToString(b) + } + return sc.chiCache.Put(key, s, ttl) +} + +func (sc *stringCache) GetJSON(key string, ptr any) (exist bool, getErr *GetJSONError) { + s, ok := sc.Get(key) + if !ok || s == "" { + return false, nil + } + s, isCachedError := strings.CutPrefix(s, cachedErrorPrefix) + if isCachedError { + return true, &GetJSONError{cachedError: s} + } + if err := json.Unmarshal(util.UnsafeStringToBytes(s), ptr); err != nil { + return false, &GetJSONError{err: err} + } + return true, nil +} + +func (sc *stringCache) ChiCache() chi_cache.Cache { + return sc.chiCache +} diff --git a/modules/git/last_commit_cache.go b/modules/git/last_commit_cache.go index 5b62b90b27..cf9c10d7b4 100644 --- a/modules/git/last_commit_cache.go +++ b/modules/git/last_commit_cache.go @@ -7,18 +7,11 @@ import ( "crypto/sha256" "fmt" + "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" ) -// Cache represents a caching interface -type Cache interface { - // Put puts value into cache with key and expire time. - Put(key string, val any, timeout int64) error - // Get gets cached value by given key. - Get(key string) any -} - func getCacheKey(repoPath, commitID, entryPath string) string { hashBytes := sha256.Sum256([]byte(fmt.Sprintf("%s:%s:%s", repoPath, commitID, entryPath))) return fmt.Sprintf("last_commit:%x", hashBytes) @@ -30,11 +23,11 @@ type LastCommitCache struct { ttl func() int64 repo *Repository commitCache map[string]*Commit - cache Cache + cache cache.StringCache } // NewLastCommitCache creates a new last commit cache for repo -func NewLastCommitCache(count int64, repoPath string, gitRepo *Repository, cache Cache) *LastCommitCache { +func NewLastCommitCache(count int64, repoPath string, gitRepo *Repository, cache cache.StringCache) *LastCommitCache { if cache == nil { return nil } @@ -65,7 +58,7 @@ func (c *LastCommitCache) Get(ref, entryPath string) (*Commit, error) { return nil, nil } - commitID, ok := c.cache.Get(getCacheKey(c.repoPath, ref, entryPath)).(string) + commitID, ok := c.cache.Get(getCacheKey(c.repoPath, ref, entryPath)) if !ok || commitID == "" { return nil, nil } diff --git a/routers/api/v1/misc/nodeinfo.go b/routers/api/v1/misc/nodeinfo.go index 3bd80de5c1..5973724782 100644 --- a/routers/api/v1/misc/nodeinfo.go +++ b/routers/api/v1/misc/nodeinfo.go @@ -29,9 +29,7 @@ func NodeInfo(ctx *context.APIContext) { nodeInfoUsage := structs.NodeInfoUsage{} if setting.Federation.ShareUserStatistics { - var cached bool - nodeInfoUsage, cached = ctx.Cache.Get(cacheKeyNodeInfoUsage).(structs.NodeInfoUsage) - + cached, _ := ctx.Cache.GetJSON(cacheKeyNodeInfoUsage, &nodeInfoUsage) if !cached { usersTotal := int(user_model.CountUsers(ctx, nil)) now := time.Now() @@ -53,7 +51,7 @@ func NodeInfo(ctx *context.APIContext) { LocalComments: int(allComments), } - if err := ctx.Cache.Put(cacheKeyNodeInfoUsage, nodeInfoUsage, 180); err != nil { + if err := ctx.Cache.PutJSON(cacheKeyNodeInfoUsage, nodeInfoUsage, 180); err != nil { ctx.InternalServerError(err) return } diff --git a/services/context/api.go b/services/context/api.go index b18a206b5e..c684add297 100644 --- a/services/context/api.go +++ b/services/context/api.go @@ -13,7 +13,7 @@ import ( "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" - mc "code.gitea.io/gitea/modules/cache" + "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/httpcache" @@ -21,15 +21,13 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" web_types "code.gitea.io/gitea/modules/web/types" - - "gitea.com/go-chi/cache" ) // APIContext is a specific context for API service type APIContext struct { *Base - Cache cache.Cache + Cache cache.StringCache Doer *user_model.User // current signed-in user IsSigned bool @@ -217,7 +215,7 @@ func APIContexter() func(http.Handler) http.Handler { base, baseCleanUp := NewBaseContext(w, req) ctx := &APIContext{ Base: base, - Cache: mc.GetCache(), + Cache: cache.GetCache(), Repo: &Repository{PullRequest: &PullRequest{}}, Org: &APIOrganization{}, } diff --git a/services/context/captcha.go b/services/context/captcha.go index fa8d779f56..41afe0e7d2 100644 --- a/services/context/captcha.go +++ b/services/context/captcha.go @@ -30,7 +30,7 @@ func GetImageCaptcha() *captcha.Captcha { cpt = captcha.NewCaptcha(captcha.Options{ SubURL: setting.AppSubURL, }) - cpt.Store = cache.GetCache() + cpt.Store = cache.GetCache().ChiCache() }) return cpt } diff --git a/services/context/context.go b/services/context/context.go index 4b318f7e33..7ab48afb73 100644 --- a/services/context/context.go +++ b/services/context/context.go @@ -17,7 +17,7 @@ import ( "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" - mc "code.gitea.io/gitea/modules/cache" + "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/httpcache" "code.gitea.io/gitea/modules/setting" @@ -27,7 +27,6 @@ import ( "code.gitea.io/gitea/modules/web/middleware" web_types "code.gitea.io/gitea/modules/web/types" - "gitea.com/go-chi/cache" "gitea.com/go-chi/session" ) @@ -46,7 +45,7 @@ type Context struct { Render Render PageData map[string]any // data used by JavaScript modules in one page, it's `window.config.pageData` - Cache cache.Cache + Cache cache.StringCache Csrf CSRFProtector Flash *middleware.Flash Session session.Store @@ -111,7 +110,7 @@ func NewWebContext(base *Base, render Render, session session.Store) *Context { Render: render, Session: session, - Cache: mc.GetCache(), + Cache: cache.GetCache(), Link: setting.AppSubURL + strings.TrimSuffix(base.Req.URL.EscapedPath(), "/"), Repo: &Repository{PullRequest: &PullRequest{}}, Org: &Organization{}, diff --git a/services/repository/branch.go b/services/repository/branch.go index 229ac54f30..d74e5819a1 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -26,6 +26,7 @@ import ( "code.gitea.io/gitea/modules/queue" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" webhook_module "code.gitea.io/gitea/modules/webhook" notify_service "code.gitea.io/gitea/services/notify" files_service "code.gitea.io/gitea/services/repository/files" @@ -119,17 +120,15 @@ func getDivergenceCacheKey(repoID int64, branchName string) string { // getDivergenceFromCache gets the divergence from cache func getDivergenceFromCache(repoID int64, branchName string) (*git.DivergeObject, bool) { - data := cache.GetCache().Get(getDivergenceCacheKey(repoID, branchName)) + data, ok := cache.GetCache().Get(getDivergenceCacheKey(repoID, branchName)) res := git.DivergeObject{ Ahead: -1, Behind: -1, } - s, ok := data.([]byte) - if !ok || len(s) == 0 { + if !ok || data == "" { return &res, false } - - if err := json.Unmarshal(s, &res); err != nil { + if err := json.Unmarshal(util.UnsafeStringToBytes(data), &res); err != nil { log.Error("json.UnMarshal failed: %v", err) return &res, false } @@ -141,7 +140,7 @@ func putDivergenceFromCache(repoID int64, branchName string, divergence *git.Div if err != nil { return err } - return cache.GetCache().Put(getDivergenceCacheKey(repoID, branchName), bs, 30*24*60*60) + return cache.GetCache().Put(getDivergenceCacheKey(repoID, branchName), util.UnsafeBytesToString(bs), 30*24*60*60) } func DelDivergenceFromCache(repoID int64, branchName string) error { diff --git a/services/repository/commitstatus/commitstatus.go b/services/repository/commitstatus/commitstatus.go index 7c1c6c2609..8a62a603d4 100644 --- a/services/repository/commitstatus/commitstatus.go +++ b/services/repository/commitstatus/commitstatus.go @@ -34,7 +34,7 @@ type commitStatusCacheValue struct { func getCommitStatusCache(repoID int64, branchName string) *commitStatusCacheValue { c := cache.GetCache() - statusStr, ok := c.Get(getCacheKey(repoID, branchName)).(string) + statusStr, ok := c.Get(getCacheKey(repoID, branchName)) if ok && statusStr != "" { var cv commitStatusCacheValue err := json.Unmarshal([]byte(statusStr), &cv) diff --git a/services/repository/contributors_graph.go b/services/repository/contributors_graph.go index 7c9f535ae0..b0d6de99ca 100644 --- a/services/repository/contributors_graph.go +++ b/services/repository/contributors_graph.go @@ -17,13 +17,12 @@ import ( "code.gitea.io/gitea/models/avatars" repo_model "code.gitea.io/gitea/models/repo" 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/gitrepo" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" api "code.gitea.io/gitea/modules/structs" - - "gitea.com/go-chi/cache" ) const ( @@ -79,13 +78,13 @@ func findLastSundayBeforeDate(dateStr string) (string, error) { } // GetContributorStats returns contributors stats for git commits for given revision or default branch -func GetContributorStats(ctx context.Context, cache cache.Cache, repo *repo_model.Repository, revision string) (map[string]*ContributorData, error) { +func GetContributorStats(ctx context.Context, cache cache.StringCache, repo *repo_model.Repository, revision string) (map[string]*ContributorData, error) { // as GetContributorStats is resource intensive we cache the result cacheKey := fmt.Sprintf(contributorStatsCacheKey, repo.FullName(), revision) if !cache.IsExist(cacheKey) { genReady := make(chan struct{}) - // dont start multible async generations + // dont start multiple async generations _, run := generateLock.Load(cacheKey) if run { return nil, ErrAwaitGeneration @@ -104,15 +103,11 @@ func GetContributorStats(ctx context.Context, cache cache.Cache, repo *repo_mode } } // TODO: renew timeout of cache cache.UpdateTimeout(cacheKey, contributorStatsCacheTimeout) - - switch v := cache.Get(cacheKey).(type) { - case error: - return nil, v - case map[string]*ContributorData: - return v, nil - default: - return nil, fmt.Errorf("unexpected type in cache detected") + var res map[string]*ContributorData + if _, cacheErr := cache.GetJSON(cacheKey, &res); cacheErr != nil { + return nil, fmt.Errorf("cached error: %w", cacheErr.ToError()) } + return res, nil } // getExtendedCommitStats return the list of *ExtendedCommitStats for the given revision @@ -205,13 +200,12 @@ func getExtendedCommitStats(repo *git.Repository, revision string /*, limit int return extendedCommitStats, nil } -func generateContributorStats(genDone chan struct{}, cache cache.Cache, cacheKey string, repo *repo_model.Repository, revision string) { +func generateContributorStats(genDone chan struct{}, cache cache.StringCache, cacheKey string, repo *repo_model.Repository, revision string) { ctx := graceful.GetManager().HammerContext() gitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, repo) if err != nil { - err := fmt.Errorf("OpenRepository: %w", err) - _ = cache.Put(cacheKey, err, contributorStatsCacheTimeout) + _ = cache.PutJSON(cacheKey, fmt.Errorf("OpenRepository: %w", err), contributorStatsCacheTimeout) return } defer closer.Close() @@ -221,13 +215,11 @@ func generateContributorStats(genDone chan struct{}, cache cache.Cache, cacheKey } extendedCommitStats, err := getExtendedCommitStats(gitRepo, revision) if err != nil { - err := fmt.Errorf("ExtendedCommitStats: %w", err) - _ = cache.Put(cacheKey, err, contributorStatsCacheTimeout) + _ = cache.PutJSON(cacheKey, fmt.Errorf("ExtendedCommitStats: %w", err), contributorStatsCacheTimeout) return } if len(extendedCommitStats) == 0 { - err := fmt.Errorf("no commit stats returned for revision '%s'", revision) - _ = cache.Put(cacheKey, err, contributorStatsCacheTimeout) + _ = cache.PutJSON(cacheKey, fmt.Errorf("no commit stats returned for revision '%s'", revision), contributorStatsCacheTimeout) return } @@ -309,7 +301,7 @@ func generateContributorStats(genDone chan struct{}, cache cache.Cache, cacheKey total.TotalCommits++ } - _ = cache.Put(cacheKey, contributorsCommitStats, contributorStatsCacheTimeout) + _ = cache.PutJSON(cacheKey, contributorsCommitStats, contributorStatsCacheTimeout) generateLock.Delete(cacheKey) if genDone != nil { genDone <- struct{}{} diff --git a/services/repository/contributors_graph_test.go b/services/repository/contributors_graph_test.go index 3801a5eee4..f22c115276 100644 --- a/services/repository/contributors_graph_test.go +++ b/services/repository/contributors_graph_test.go @@ -10,9 +10,9 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/cache" + "code.gitea.io/gitea/modules/setting" - "gitea.com/go-chi/cache" "github.com/stretchr/testify/assert" ) @@ -20,20 +20,18 @@ func TestRepository_ContributorsGraph(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) assert.NoError(t, repo.LoadOwner(db.DefaultContext)) - mockCache, err := cache.NewCacher(cache.Options{ - Adapter: "memory", - Interval: 24 * 60, - }) + mockCache, err := cache.NewStringCache(setting.Cache{}) assert.NoError(t, err) generateContributorStats(nil, mockCache, "key", repo, "404ref") - err, isErr := mockCache.Get("key").(error) - assert.True(t, isErr) - assert.ErrorAs(t, err, &git.ErrNotExist{}) + var data map[string]*ContributorData + _, getErr := mockCache.GetJSON("key", &data) + assert.NotNil(t, getErr) + assert.ErrorContains(t, getErr.ToError(), "object does not exist") generateContributorStats(nil, mockCache, "key2", repo, "master") - data, isData := mockCache.Get("key2").(map[string]*ContributorData) - assert.True(t, isData) + exist, _ := mockCache.GetJSON("key2", &data) + assert.True(t, exist) var keys []string for k := range data { keys = append(keys, k) From c28bed27af82b664df943e5fd3d9bd07fb2f2b77 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sat, 13 Apr 2024 10:54:36 +0200 Subject: [PATCH 099/370] Update JS and PY deps, lock eslint and related plugins (#30452) Update all JS dependencies and lock eslint and flat-only plugins. There is at least the blocker https://github.com/SonarSource/eslint-plugin-sonarjs/issues/454 preventing us from upgrading to eslint 9. Tested API spec, charts and absolute dates. --- package-lock.json | 477 ++++++++++++++++++++++------------------------ package.json | 24 +-- poetry.lock | 6 +- updates.config.js | 2 + 4 files changed, 248 insertions(+), 261 deletions(-) diff --git a/package-lock.json b/package-lock.json index 35bf886fc8..61d86f6b7c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "chartjs-adapter-dayjs-4": "1.0.4", "chartjs-plugin-zoom": "2.0.1", "clippie": "4.0.7", - "css-loader": "7.0.0", + "css-loader": "7.1.1", "dayjs": "1.11.10", "dropzone": "6.0.0-beta.2", "easymde": "2.18.0", @@ -44,9 +44,9 @@ "postcss-nesting": "12.1.1", "pretty-ms": "9.0.0", "sortablejs": "1.15.2", - "swagger-ui-dist": "5.13.0", + "swagger-ui-dist": "5.15.1", "tailwindcss": "3.4.3", - "temporal-polyfill": "0.2.3", + "temporal-polyfill": "0.2.4", "throttle-debounce": "5.0.0", "tinycolor2": "1.6.0", "tippy.js": "6.3.7", @@ -56,7 +56,7 @@ "vanilla-colorful": "0.7.2", "vue": "3.4.21", "vue-bar-graph": "2.0.0", - "vue-chartjs": "5.3.0", + "vue-chartjs": "5.3.1", "vue-loader": "17.4.2", "vue3-calendar-heatmap": "2.0.5", "webpack": "5.91.0", @@ -64,8 +64,8 @@ "wrap-ansi": "9.0.0" }, "devDependencies": { - "@eslint-community/eslint-plugin-eslint-comments": "4.1.0", - "@playwright/test": "1.42.1", + "@eslint-community/eslint-plugin-eslint-comments": "4.3.0", + "@playwright/test": "1.43.1", "@stoplight/spectral-cli": "6.11.1", "@stylistic/eslint-plugin-js": "1.7.0", "@stylistic/stylelint-plugin": "2.1.1", @@ -77,15 +77,15 @@ "eslint-plugin-jquery": "1.5.1", "eslint-plugin-no-jquery": "2.7.0", "eslint-plugin-no-use-extend-native": "0.5.0", - "eslint-plugin-regexp": "2.4.0", + "eslint-plugin-regexp": "2.5.0", "eslint-plugin-sonarjs": "0.25.1", "eslint-plugin-unicorn": "52.0.0", "eslint-plugin-vitest": "0.4.1", "eslint-plugin-vitest-globals": "1.5.0", - "eslint-plugin-vue": "9.24.0", + "eslint-plugin-vue": "9.24.1", "eslint-plugin-vue-scoped-css": "2.8.0", - "eslint-plugin-wc": "2.0.4", - "happy-dom": "14.5.0", + "eslint-plugin-wc": "2.1.0", + "happy-dom": "14.7.1", "markdownlint-cli": "0.39.0", "postcss-html": "1.6.0", "stylelint": "16.3.1", @@ -93,9 +93,9 @@ "stylelint-declaration-strict-value": "1.10.4", "stylelint-value-no-unknown-custom-properties": "6.0.1", "svgo": "3.2.0", - "updates": "16.0.0", + "updates": "16.0.1", "vite-string-plugin": "1.1.5", - "vitest": "1.4.0" + "vitest": "1.5.0" }, "engines": { "node": ">= 18.0.0" @@ -865,9 +865,9 @@ } }, "node_modules/@eslint-community/eslint-plugin-eslint-comments": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-4.1.0.tgz", - "integrity": "sha512-B2mwipifrBS5E00vN8vME68laPMZ0h3sNGOEDj5g9iUN9k5EU99Omq0Nc325eKNoFFDnDtiHp3DqIjO+1bstag==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-4.3.0.tgz", + "integrity": "sha512-6e93KtgsndNkvwCCa07LOQJSwzzLLxwrFll3+huyFoiiQXWG0KBcmo0Q1bVgYQQDLfWOOZl2VPBsXqZL6vHIBQ==", "dev": true, "dependencies": { "escape-string-regexp": "^4.0.0", @@ -877,7 +877,7 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" } }, "node_modules/@eslint-community/eslint-utils": { @@ -1344,12 +1344,12 @@ } }, "node_modules/@playwright/test": { - "version": "1.42.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.42.1.tgz", - "integrity": "sha512-Gq9rmS54mjBL/7/MvBaNOBwbfnh7beHvS6oS4srqXFcQHpQCV1+c8JXWE8VLPyRDhgS3H8x8A7hztqI9VnwrAQ==", + "version": "1.43.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.43.1.tgz", + "integrity": "sha512-HgtQzFgNEEo4TE22K/X7sYTYNqEMMTZmFS8kTq6m8hXj+m1D8TgwgIbumHddJa9h4yl4GkKb8/bgAl2+g7eDgA==", "dev": true, "dependencies": { - "playwright": "1.42.1" + "playwright": "1.43.1" }, "bin": { "playwright": "cli.js" @@ -1420,9 +1420,9 @@ "dev": true }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.0.tgz", - "integrity": "sha512-jwXtxYbRt1V+CdQSy6Z+uZti7JF5irRKF8hlKfEnF/xJpcNGuuiZMBvuoYM+x9sr9iWGnzrlM0+9hvQ1kgkf1w==", + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.2.tgz", + "integrity": "sha512-ahxSgCkAEk+P/AVO0vYr7DxOD3CwAQrT0Go9BJyGQ9Ef0QxVOfjDZMiF4Y2s3mLyPrjonchIMH/tbWHucJMykQ==", "cpu": [ "arm" ], @@ -1433,9 +1433,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.0.tgz", - "integrity": "sha512-fI9nduZhCccjzlsA/OuAwtFGWocxA4gqXGTLvOyiF8d+8o0fZUeSztixkYjcGq1fGZY3Tkq4yRvHPFxU+jdZ9Q==", + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.2.tgz", + "integrity": "sha512-lAarIdxZWbFSHFSDao9+I/F5jDaKyCqAPMq5HqnfpBw8dKDiCaaqM0lq5h1pQTLeIqueeay4PieGR5jGZMWprw==", "cpu": [ "arm64" ], @@ -1446,9 +1446,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.0.tgz", - "integrity": "sha512-BcnSPRM76/cD2gQC+rQNGBN6GStBs2pl/FpweW8JYuz5J/IEa0Fr4AtrPv766DB/6b2MZ/AfSIOSGw3nEIP8SA==", + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.2.tgz", + "integrity": "sha512-SWsr8zEUk82KSqquIMgZEg2GE5mCSfr9sE/thDROkX6pb3QQWPp8Vw8zOq2GyxZ2t0XoSIUlvHDkrf5Gmf7x3Q==", "cpu": [ "arm64" ], @@ -1459,9 +1459,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.0.tgz", - "integrity": "sha512-LDyFB9GRolGN7XI6955aFeI3wCdCUszFWumWU0deHA8VpR3nWRrjG6GtGjBrQxQKFevnUTHKCfPR4IvrW3kCgQ==", + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.2.tgz", + "integrity": "sha512-o/HAIrQq0jIxJAhgtIvV5FWviYK4WB0WwV91SLUnsliw1lSAoLsmgEEgRWzDguAFeUEUUoIWXiJrPqU7vGiVkA==", "cpu": [ "x64" ], @@ -1472,9 +1472,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.0.tgz", - "integrity": "sha512-ygrGVhQP47mRh0AAD0zl6QqCbNsf0eTo+vgwkY6LunBcg0f2Jv365GXlDUECIyoXp1kKwL5WW6rsO429DBY/bA==", + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.2.tgz", + "integrity": "sha512-nwlJ65UY9eGq91cBi6VyDfArUJSKOYt5dJQBq8xyLhvS23qO+4Nr/RreibFHjP6t+5ap2ohZrUJcHv5zk5ju/g==", "cpu": [ "arm" ], @@ -1485,9 +1485,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.0.tgz", - "integrity": "sha512-x+uJ6MAYRlHGe9wi4HQjxpaKHPM3d3JjqqCkeC5gpnnI6OWovLdXTpfa8trjxPLnWKyBsSi5kne+146GAxFt4A==", + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.2.tgz", + "integrity": "sha512-Pg5TxxO2IVlMj79+c/9G0LREC9SY3HM+pfAwX7zj5/cAuwrbfj2Wv9JbMHIdPCfQpYsI4g9mE+2Bw/3aeSs2rQ==", "cpu": [ "arm64" ], @@ -1498,9 +1498,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.0.tgz", - "integrity": "sha512-nrRw8ZTQKg6+Lttwqo6a2VxR9tOroa2m91XbdQ2sUUzHoedXlsyvY1fN4xWdqz8PKmf4orDwejxXHjh7YBGUCA==", + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.2.tgz", + "integrity": "sha512-cAOTjGNm84gc6tS02D1EXtG7tDRsVSDTBVXOLbj31DkwfZwgTPYZ6aafSU7rD/4R2a34JOwlF9fQayuTSkoclA==", "cpu": [ "arm64" ], @@ -1511,11 +1511,11 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.0.tgz", - "integrity": "sha512-xV0d5jDb4aFu84XKr+lcUJ9y3qpIWhttO3Qev97z8DKLXR62LC3cXT/bMZXrjLF9X+P5oSmJTzAhqwUbY96PnA==", + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.2.tgz", + "integrity": "sha512-4RyT6v1kXb7C0fn6zV33rvaX05P0zHoNzaXI/5oFHklfKm602j+N4mn2YvoezQViRLPnxP8M1NaY4s/5kXO5cw==", "cpu": [ - "ppc64le" + "ppc64" ], "dev": true, "optional": true, @@ -1524,9 +1524,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.0.tgz", - "integrity": "sha512-SDDhBQwZX6LPRoPYjAZWyL27LbcBo7WdBFWJi5PI9RPCzU8ijzkQn7tt8NXiXRiFMJCVpkuMkBf4OxSxVMizAw==", + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.2.tgz", + "integrity": "sha512-KNUH6jC/vRGAKSorySTyc/yRYlCwN/5pnMjXylfBniwtJx5O7X17KG/0efj8XM3TZU7raYRXJFFReOzNmL1n1w==", "cpu": [ "riscv64" ], @@ -1537,9 +1537,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.0.tgz", - "integrity": "sha512-RxB/qez8zIDshNJDufYlTT0ZTVut5eCpAZ3bdXDU9yTxBzui3KhbGjROK2OYTTor7alM7XBhssgoO3CZ0XD3qA==", + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.2.tgz", + "integrity": "sha512-xPV4y73IBEXToNPa3h5lbgXOi/v0NcvKxU0xejiFw6DtIYQqOTMhZ2DN18/HrrP0PmiL3rGtRG9gz1QE8vFKXQ==", "cpu": [ "s390x" ], @@ -1550,9 +1550,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.0.tgz", - "integrity": "sha512-C6y6z2eCNCfhZxT9u+jAM2Fup89ZjiG5pIzZIDycs1IwESviLxwkQcFRGLjnDrP+PT+v5i4YFvlcfAs+LnreXg==", + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.2.tgz", + "integrity": "sha512-QBhtr07iFGmF9egrPOWyO5wciwgtzKkYPNLVCFZTmr4TWmY0oY2Dm/bmhHjKRwZoGiaKdNcKhFtUMBKvlchH+Q==", "cpu": [ "x64" ], @@ -1563,9 +1563,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.0.tgz", - "integrity": "sha512-i0QwbHYfnOMYsBEyjxcwGu5SMIi9sImDVjDg087hpzXqhBSosxkE7gyIYFHgfFl4mr7RrXksIBZ4DoLoP4FhJg==", + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.2.tgz", + "integrity": "sha512-8zfsQRQGH23O6qazZSFY5jP5gt4cFvRuKTpuBsC1ZnSWxV8ZKQpPqOZIUtdfMOugCcBvFGRa1pDC/tkf19EgBw==", "cpu": [ "x64" ], @@ -1576,9 +1576,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.0.tgz", - "integrity": "sha512-Fq52EYb0riNHLBTAcL0cun+rRwyZ10S9vKzhGKKgeD+XbwunszSY0rVMco5KbOsTlwovP2rTOkiII/fQ4ih/zQ==", + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.2.tgz", + "integrity": "sha512-H4s8UjgkPnlChl6JF5empNvFHp77Jx+Wfy2EtmYPe9G22XV+PMuCinZVHurNe8ggtwoaohxARJZbaH/3xjB/FA==", "cpu": [ "arm64" ], @@ -1589,9 +1589,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.0.tgz", - "integrity": "sha512-e/PBHxPdJ00O9p5Ui43+vixSgVf4NlLsmV6QneGERJ3lnjIua/kim6PRFe3iDueT1rQcgSkYP8ZBBXa/h4iPvw==", + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.2.tgz", + "integrity": "sha512-djqpAjm/i8erWYF0K6UY4kRO3X5+T4TypIqw60Q8MTqSBaQNpNXDhxdjpZ3ikgb+wn99svA7jxcXpiyg9MUsdw==", "cpu": [ "ia32" ], @@ -1602,9 +1602,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.0.tgz", - "integrity": "sha512-aGg7iToJjdklmxlUlJh/PaPNa4PmqHfyRMLunbL3eaMO0gp656+q1zOKkpJ/CVe9CryJv6tAN1HDoR8cNGzkag==", + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.2.tgz", + "integrity": "sha512-teAqzLT0yTYZa8ZP7zhFKEx4cotS8Tkk5XiqNMJhD4CpaWB1BHARE4Qy+RzwnXvSAYv+Q3jAqCVBS+PS+Yee8Q==", "cpu": [ "x64" ], @@ -2217,9 +2217,9 @@ } }, "node_modules/@types/eslint": { - "version": "8.56.7", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.7.tgz", - "integrity": "sha512-SjDvI/x3zsZnOkYZ3lCt9lOZWZLB2jIlNKz+LBgCtDurK0JZcwucxYHn1w2BJkD34dgX9Tjnak0txtq4WTggEA==", + "version": "8.56.9", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.9.tgz", + "integrity": "sha512-W4W3KcqzjJ0sHg2vAq9vfml6OhsJ53TcUjUqfzzZf/EChUtwspszj/S0pzMxnfRcO55/iGq47dscXw71Fxc4Zg==", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -2269,9 +2269,9 @@ "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" }, "node_modules/@types/node": { - "version": "20.12.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.4.tgz", - "integrity": "sha512-E+Fa9z3wSQpzgYQdYmme5X3OTuejnnTx88A6p6vkkJosR3KBz+HpE3kqNm98VE6cfLFcISx7zW7MsJkH6KwbTw==", + "version": "20.12.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", + "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", "dependencies": { "undici-types": "~5.26.4" } @@ -2314,22 +2314,22 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.5.0.tgz", - "integrity": "sha512-HpqNTH8Du34nLxbKgVMGljZMG0rJd2O9ecvr2QLYp+7512ty1j42KnsFwspPXg1Vh8an9YImf6CokUBltisZFQ==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.6.0.tgz", + "integrity": "sha512-gKmTNwZnblUdnTIJu3e9kmeRRzV2j1a/LUO27KNNAnIC5zjy1aSvXSRp4rVNlmAoHlQ7HzX42NbKpcSr4jF80A==", "dev": true, "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.5.0", - "@typescript-eslint/type-utils": "7.5.0", - "@typescript-eslint/utils": "7.5.0", - "@typescript-eslint/visitor-keys": "7.5.0", + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.6.0", + "@typescript-eslint/type-utils": "7.6.0", + "@typescript-eslint/utils": "7.6.0", + "@typescript-eslint/visitor-keys": "7.6.0", "debug": "^4.3.4", "graphemer": "^1.4.0", - "ignore": "^5.2.4", + "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2349,15 +2349,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.5.0.tgz", - "integrity": "sha512-cj+XGhNujfD2/wzR1tabNsidnYRaFfEkcULdcIyVBYcXjBvBKOes+mpMBP7hMpOyk+gBcfXsrg4NBGAStQyxjQ==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.6.0.tgz", + "integrity": "sha512-usPMPHcwX3ZoPWnBnhhorc14NJw9J4HpSXQX4urF2TPKG0au0XhJoZyX62fmvdHONUkmyUe74Hzm1//XA+BoYg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.5.0", - "@typescript-eslint/types": "7.5.0", - "@typescript-eslint/typescript-estree": "7.5.0", - "@typescript-eslint/visitor-keys": "7.5.0", + "@typescript-eslint/scope-manager": "7.6.0", + "@typescript-eslint/types": "7.6.0", + "@typescript-eslint/typescript-estree": "7.6.0", + "@typescript-eslint/visitor-keys": "7.6.0", "debug": "^4.3.4" }, "engines": { @@ -2377,13 +2377,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.5.0.tgz", - "integrity": "sha512-Z1r7uJY0MDeUlql9XJ6kRVgk/sP11sr3HKXn268HZyqL7i4cEfrdFuSSY/0tUqT37l5zT0tJOsuDP16kio85iA==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.6.0.tgz", + "integrity": "sha512-ngttyfExA5PsHSx0rdFgnADMYQi+Zkeiv4/ZxGYUWd0nLs63Ha0ksmp8VMxAIC0wtCFxMos7Lt3PszJssG/E6w==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.5.0", - "@typescript-eslint/visitor-keys": "7.5.0" + "@typescript-eslint/types": "7.6.0", + "@typescript-eslint/visitor-keys": "7.6.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2394,15 +2394,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.5.0.tgz", - "integrity": "sha512-A021Rj33+G8mx2Dqh0nMO9GyjjIBK3MqgVgZ2qlKf6CJy51wY/lkkFqq3TqqnH34XyAHUkq27IjlUkWlQRpLHw==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.6.0.tgz", + "integrity": "sha512-NxAfqAPNLG6LTmy7uZgpK8KcuiS2NZD/HlThPXQRGwz6u7MDBWRVliEEl1Gj6U7++kVJTpehkhZzCJLMK66Scw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.5.0", - "@typescript-eslint/utils": "7.5.0", + "@typescript-eslint/typescript-estree": "7.6.0", + "@typescript-eslint/utils": "7.6.0", "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^1.3.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2421,9 +2421,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.5.0.tgz", - "integrity": "sha512-tv5B4IHeAdhR7uS4+bf8Ov3k793VEVHd45viRRkehIUZxm0WF82VPiLgHzA/Xl4TGPg1ZD49vfxBKFPecD5/mg==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.6.0.tgz", + "integrity": "sha512-h02rYQn8J+MureCvHVVzhl69/GAfQGPQZmOMjG1KfCl7o3HtMSlPaPUAPu6lLctXI5ySRGIYk94clD/AUMCUgQ==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2434,19 +2434,19 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.5.0.tgz", - "integrity": "sha512-YklQQfe0Rv2PZEueLTUffiQGKQneiIEKKnfIqPIOxgM9lKSZFCjT5Ad4VqRKj/U4+kQE3fa8YQpskViL7WjdPQ==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.6.0.tgz", + "integrity": "sha512-+7Y/GP9VuYibecrCQWSKgl3GvUM5cILRttpWtnAu8GNL9j11e4tbuGZmZjJ8ejnKYyBRb2ddGQ3rEFCq3QjMJw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.5.0", - "@typescript-eslint/visitor-keys": "7.5.0", + "@typescript-eslint/types": "7.6.0", + "@typescript-eslint/visitor-keys": "7.6.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2461,34 +2461,19 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@typescript-eslint/utils": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.5.0.tgz", - "integrity": "sha512-3vZl9u0R+/FLQcpy2EHyRGNqAS/ofJ3Ji8aebilfJe+fobK8+LbIFmrHciLVDxjDoONmufDcnVSF38KwMEOjzw==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.6.0.tgz", + "integrity": "sha512-x54gaSsRRI+Nwz59TXpCsr6harB98qjXYzsRxGqvA5Ue3kQH+FxS7FYU81g/omn22ML2pZJkisy6Q+ElK8pBCA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.5.0", - "@typescript-eslint/types": "7.5.0", - "@typescript-eslint/typescript-estree": "7.5.0", - "semver": "^7.5.4" + "@types/json-schema": "^7.0.15", + "@types/semver": "^7.5.8", + "@typescript-eslint/scope-manager": "7.6.0", + "@typescript-eslint/types": "7.6.0", + "@typescript-eslint/typescript-estree": "7.6.0", + "semver": "^7.6.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2502,13 +2487,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.5.0.tgz", - "integrity": "sha512-mcuHM/QircmA6O7fy6nn2w/3ditQkj+SgtOc8DW3uQ10Yfj42amm2i+6F2K4YAOPNNTmE6iM1ynM6lrSwdendA==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.6.0.tgz", + "integrity": "sha512-4eLB7t+LlNUmXzfOu1VAIAdkjbu5xNSerURS9X/S5TUKWFRpXRQZbmtPqgKmYx8bj3J0irtQXSiWAOY82v+cgw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.5.0", - "eslint-visitor-keys": "^3.4.1" + "@typescript-eslint/types": "7.6.0", + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2538,13 +2523,13 @@ } }, "node_modules/@vitest/expect": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.4.0.tgz", - "integrity": "sha512-Jths0sWCJZ8BxjKe+p+eKsoqev1/T8lYcrjavEaz8auEJ4jAVY0GwW3JKmdVU4mmNPLPHixh4GNXP7GFtAiDHA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.5.0.tgz", + "integrity": "sha512-0pzuCI6KYi2SIC3LQezmxujU9RK/vwC1U9R0rLuGlNGcOuDWxqWKu6nUdFsX9tH1WU0SXtAxToOsEjeUn1s3hA==", "dev": true, "dependencies": { - "@vitest/spy": "1.4.0", - "@vitest/utils": "1.4.0", + "@vitest/spy": "1.5.0", + "@vitest/utils": "1.5.0", "chai": "^4.3.10" }, "funding": { @@ -2552,12 +2537,12 @@ } }, "node_modules/@vitest/runner": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.4.0.tgz", - "integrity": "sha512-EDYVSmesqlQ4RD2VvWo3hQgTJ7ZrFQ2VSJdfiJiArkCerDAGeyF1i6dHkmySqk573jLp6d/cfqCN+7wUB5tLgg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.0.tgz", + "integrity": "sha512-7HWwdxXP5yDoe7DTpbif9l6ZmDwCzcSIK38kTSIt6CFEpMjX4EpCgT6wUmS0xTXqMI6E/ONmfgRKmaujpabjZQ==", "dev": true, "dependencies": { - "@vitest/utils": "1.4.0", + "@vitest/utils": "1.5.0", "p-limit": "^5.0.0", "pathe": "^1.1.1" }, @@ -2593,9 +2578,9 @@ } }, "node_modules/@vitest/snapshot": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.4.0.tgz", - "integrity": "sha512-saAFnt5pPIA5qDGxOHxJ/XxhMFKkUSBJmVt5VgDsAqPTX6JP326r5C/c9UuCMPoXNzuudTPsYDZCoJ5ilpqG2A==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.0.tgz", + "integrity": "sha512-qpv3fSEuNrhAO3FpH6YYRdaECnnRjg9VxbhdtPwPRnzSfHVXnNzzrpX4cJxqiwgRMo7uRMWDFBlsBq4Cr+rO3A==", "dev": true, "dependencies": { "magic-string": "^0.30.5", @@ -2619,9 +2604,9 @@ } }, "node_modules/@vitest/spy": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.4.0.tgz", - "integrity": "sha512-Ywau/Qs1DzM/8Uc+yA77CwSegizMlcgTJuYGAi0jujOteJOUf1ujunHThYo243KG9nAyWT3L9ifPYZ5+As/+6Q==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.5.0.tgz", + "integrity": "sha512-vu6vi6ew5N5MMHJjD5PoakMRKYdmIrNJmyfkhRpQt5d9Ewhw9nZ5Aqynbi3N61bvk9UvZ5UysMT6ayIrZ8GA9w==", "dev": true, "dependencies": { "tinyspy": "^2.2.0" @@ -2631,9 +2616,9 @@ } }, "node_modules/@vitest/utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.4.0.tgz", - "integrity": "sha512-mx3Yd1/6e2Vt/PUC98DcqTirtfxUyAZ32uK82r8rZzbtBeBo+nqgnjx/LvqQdWsrvNtm14VmurNgcf4nqY5gJg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.0.tgz", + "integrity": "sha512-BDU0GNL8MWkRkSRdNFvCUCAVOeHaUlVJ9Tx0TYBZyXaaOTmGtUFObzchCivIBrIwKzvZA7A9sCejVhXM2aY98A==", "dev": true, "dependencies": { "diff-sequences": "^29.6.3", @@ -3566,9 +3551,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001605", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001605.tgz", - "integrity": "sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ==", + "version": "1.0.30001609", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001609.tgz", + "integrity": "sha512-JFPQs34lHKx1B5t1EpQpWH4c+29zIyn/haGsbpfq3suuV9v56enjFt23zqijxGTMwy1p/4H2tjnQMY+p1WoAyA==", "funding": [ { "type": "opencollective", @@ -3960,9 +3945,9 @@ } }, "node_modules/css-loader": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.0.0.tgz", - "integrity": "sha512-WrO4FVoamxt5zY9CauZjoJgXRi/LZKIk+Ta7YvpSGr5r/eMYPNp5/T9ODlMe4/1rF5DYlycG1avhV4g3A/tiAw==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.1.tgz", + "integrity": "sha512-OxIR5P2mjO1PSXk44bWuQ8XtMK4dpEqpIyERCx3ewOo3I8EmbcxMPUc5ScLtQfgXtOojoMv57So4V/C02HQLsw==", "dependencies": { "icss-utils": "^5.1.0", "postcss": "^8.4.33", @@ -4812,9 +4797,9 @@ } }, "node_modules/dompurify": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.11.tgz", - "integrity": "sha512-Fan4uMuyB26gFV3ovPoEoQbxRRPfTu3CvImyZnhGq5fsIEO+gEFLp45ISFt+kQBWsK5ulDdT0oV28jS1UrwQLg==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.0.tgz", + "integrity": "sha512-yoU4rhgPKCo+p5UrWWWNKiIq+ToGqmVVhk0PmMYBK4kRsR3/qhemNFL8f6CFmBd4gMwm3F4T7HBoydP5uY07fA==" }, "node_modules/domutils": { "version": "3.1.0", @@ -4857,9 +4842,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.727", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.727.tgz", - "integrity": "sha512-brpv4KTeC4g0Fx2FeIKytLd4UGn1zBQq5Lauy7zEWT9oqkaj5mgsxblEZIAOf1HHLlXxzr6adGViiBy5Z39/CA==" + "version": "1.4.736", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.736.tgz", + "integrity": "sha512-Rer6wc3ynLelKNM4lOCg7/zPQj8tPOCB2hzD32PX9wd3hgRRi9MxEbmkFCokzcEhRVMiOVLjnL9ig9cefJ+6+Q==" }, "node_modules/elkjs": { "version": "0.9.2", @@ -4911,9 +4896,9 @@ } }, "node_modules/envinfo": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.1.tgz", - "integrity": "sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.12.0.tgz", + "integrity": "sha512-Iw9rQJBGpJRd3rwXm9ft/JiGoAZmLxxJZELYDQoPRZ4USVhkKtIcNBPw6U+/K2mBpaqM25JSV6Yl4Az9vO2wJg==", "bin": { "envinfo": "dist/cli.js" }, @@ -5689,9 +5674,9 @@ } }, "node_modules/eslint-plugin-regexp": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-2.4.0.tgz", - "integrity": "sha512-OL2S6VPjQhs9s/NclQ0qattVq1J0GU8ox70/HIVy5Dxw+qbbdd7KQkyucsez2clEQjvdtDe12DTnPphFFUyXFg==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-2.5.0.tgz", + "integrity": "sha512-I7vKcP0o75WS5SHiVNXN+Eshq49sbrweMQIuqSL3AId9AwDe9Dhbfug65vw64LxmOd4v+yf5l5Xt41y9puiq0g==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", @@ -5785,9 +5770,9 @@ "dev": true }, "node_modules/eslint-plugin-vue": { - "version": "9.24.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.24.0.tgz", - "integrity": "sha512-9SkJMvF8NGMT9aQCwFc5rj8Wo1XWSMSHk36i7ZwdI614BU7sIOR28ZjuFPKp8YGymZN12BSEbiSwa7qikp+PBw==", + "version": "9.24.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.24.1.tgz", + "integrity": "sha512-wk3SuwmS1pZdcuJlokGYEi/buDOwD6KltvhIZyOnpJ/378dcQ4zchu9PAMbbLAaydCz1iYc5AozszcOOgZIIOg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", @@ -5803,7 +5788,7 @@ "node": "^14.17.0 || >=16.0.0" }, "peerDependencies": { - "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0" + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" } }, "node_modules/eslint-plugin-vue-scoped-css": { @@ -5833,9 +5818,9 @@ } }, "node_modules/eslint-plugin-wc": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-wc/-/eslint-plugin-wc-2.0.4.tgz", - "integrity": "sha512-ORu7MBv0hXIvq894EJad70m+AvHGbmrDdKT6lcgtCVVhEbuIAyxg0ilfqqqHOmsh8PfcUBeEae3y7CElKvm1KQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-wc/-/eslint-plugin-wc-2.1.0.tgz", + "integrity": "sha512-s/BGOtmpgQ2yifR6EC1OM9t0DwYLgg4ZAL07Kw4eXvBb5TYaPafI+65tswvnZvhH8FqcjERLbBZPPvYsvinkfg==", "dev": true, "dependencies": { "is-valid-element-name": "^1.0.0", @@ -6594,9 +6579,9 @@ } }, "node_modules/happy-dom": { - "version": "14.5.0", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-14.5.0.tgz", - "integrity": "sha512-KvOtCq7eamc7cjihM0F1wj6FptuXzooc3Typa7Vgu6ns2uKGXC4BIFlK80SdH2w8zcW0gtxpBVI/sUqbYtljDA==", + "version": "14.7.1", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-14.7.1.tgz", + "integrity": "sha512-v60Q0evZ4clvMcrAh5/F8EdxDdfHdFrtffz/CNe10jKD+nFweZVxM91tW+UyY2L4AtpgIaXdZ7TQmiO1pfcwbg==", "dev": true, "dependencies": { "entities": "^4.5.0", @@ -9381,12 +9366,12 @@ "dev": true }, "node_modules/playwright": { - "version": "1.42.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.42.1.tgz", - "integrity": "sha512-PgwB03s2DZBcNRoW+1w9E+VkLBxweib6KTXM0M3tkiT4jVxKSi6PmVJ591J+0u10LUrgxB7dLRbiJqO5s2QPMg==", + "version": "1.43.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.1.tgz", + "integrity": "sha512-V7SoH0ai2kNt1Md9E3Gwas5B9m8KR2GVvwZnAI6Pg0m3sh7UvgiYhRrhsziCmqMJNouPckiOhk8T+9bSAK0VIA==", "dev": true, "dependencies": { - "playwright-core": "1.42.1" + "playwright-core": "1.43.1" }, "bin": { "playwright": "cli.js" @@ -9399,9 +9384,9 @@ } }, "node_modules/playwright-core": { - "version": "1.42.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.42.1.tgz", - "integrity": "sha512-mxz6zclokgrke9p1vtdy/COWBH+eOZgYUVVU34C73M+4j4HLlQJHtfcqiqqxpP0o8HhMkflvfbquLX5dg6wlfA==", + "version": "1.43.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.1.tgz", + "integrity": "sha512-EI36Mto2Vrx6VF7rm708qSnesVQKbxEWvPrfA1IPY6HgczBplDx7ENtx+K2n4kJ41sLLkuGfmb0ZLSSXlDhqPg==", "dev": true, "bin": { "playwright-core": "cli.js" @@ -11241,9 +11226,9 @@ } }, "node_modules/swagger-ui-dist": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.13.0.tgz", - "integrity": "sha512-uaWhh6j18IIs5tOX0arvIBnVINAzpTXaQXkr7qAk8zoupegJVg0UU/5+S/FgsgVCnzVsJ9d7QLjIxkswEeTg0Q==" + "version": "5.15.1", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.15.1.tgz", + "integrity": "sha512-Et/WY0NFdKj8sUBOyEx5P3VybsvGl7bo/y9JvgQ22TkH1a/KscQ0ZiQST2YeJ3cwCrIjYTbHbt165fkku0y1Ig==" }, "node_modules/sync-fetch": { "version": "0.4.5", @@ -11379,17 +11364,17 @@ } }, "node_modules/temporal-polyfill": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/temporal-polyfill/-/temporal-polyfill-0.2.3.tgz", - "integrity": "sha512-7ZJRc7wq/1XjrOQYkkNpgo2qfE9XLrUU8D/DS+LAC/T0bYqZ46rW6dow0sOTXTPZS4bwer8bD/0OyuKQBfA3yw==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/temporal-polyfill/-/temporal-polyfill-0.2.4.tgz", + "integrity": "sha512-WA5p0CjQTkMjF9m8sP4wSYgpqI8m2d4q7wPUyaJOWhy4bI9mReLb2yGvTV4qf/DPMTe6H6M/Dig5KmTMB7ev6Q==", "dependencies": { - "temporal-spec": "^0.2.0" + "temporal-spec": "^0.2.4" } }, "node_modules/temporal-spec": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/temporal-spec/-/temporal-spec-0.2.0.tgz", - "integrity": "sha512-r1AT0XdEp8TMQ13FLvOt8mOtAxDQsRt2QU5rSWCA7YfshddU651Y1NHVrceLANvixKdf9fYO8B/S9fXHodB7HQ==" + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/temporal-spec/-/temporal-spec-0.2.4.tgz", + "integrity": "sha512-lDMFv4nKQrSjlkHKAlHVqKrBG4DyFfa9F74cmBZ3Iy3ed8yvWnlWSIdi4IKfSqwmazAohBNwiN64qGx4y5Q3IQ==" }, "node_modules/terser": { "version": "5.30.3", @@ -11749,9 +11734,9 @@ } }, "node_modules/typescript": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz", - "integrity": "sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "devOptional": true, "peer": true, "bin": { @@ -11855,9 +11840,9 @@ } }, "node_modules/updates": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/updates/-/updates-16.0.0.tgz", - "integrity": "sha512-Ra3QUu/rfbSCsG83zNNvoRQt0FVT3qULBSALYTlwTDX6oyz7R5GQAYwqJoIG/RDjYAXpwr3usrInoyHHTP6cag==", + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/updates/-/updates-16.0.1.tgz", + "integrity": "sha512-If3NQKzGcA3aVgz2VyOXqQ+4uqYjPUPqh2PeZPtD+OKT4CTmxRYqoyFO+T3nwfccy4SiWy5AabWrBXXhVQ89Aw==", "dev": true, "bin": { "updates": "dist/updates.js" @@ -12003,9 +11988,9 @@ } }, "node_modules/vite-node": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.4.0.tgz", - "integrity": "sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.0.tgz", + "integrity": "sha512-tV8h6gMj6vPzVCa7l+VGq9lwoJjW8Y79vst8QZZGiuRAfijU+EEWuc0kFpmndQrWhMMhet1jdSF+40KSZUqIIw==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -12051,9 +12036,9 @@ } }, "node_modules/vite/node_modules/rollup": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.0.tgz", - "integrity": "sha512-Qe7w62TyawbDzB4yt32R0+AbIo6m1/sqO7UPzFS8Z/ksL5mrfhA0v4CavfdmFav3D+ub4QeAgsGEe84DoWe/nQ==", + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.2.tgz", + "integrity": "sha512-WkeoTWvuBoFjFAhsEOHKRoZ3r9GfTyhh7Vff1zwebEFLEFjT1lG3784xEgKiTa7E+e70vsC81roVL2MP4tgEEQ==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -12066,35 +12051,35 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.14.0", - "@rollup/rollup-android-arm64": "4.14.0", - "@rollup/rollup-darwin-arm64": "4.14.0", - "@rollup/rollup-darwin-x64": "4.14.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.14.0", - "@rollup/rollup-linux-arm64-gnu": "4.14.0", - "@rollup/rollup-linux-arm64-musl": "4.14.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.14.0", - "@rollup/rollup-linux-riscv64-gnu": "4.14.0", - "@rollup/rollup-linux-s390x-gnu": "4.14.0", - "@rollup/rollup-linux-x64-gnu": "4.14.0", - "@rollup/rollup-linux-x64-musl": "4.14.0", - "@rollup/rollup-win32-arm64-msvc": "4.14.0", - "@rollup/rollup-win32-ia32-msvc": "4.14.0", - "@rollup/rollup-win32-x64-msvc": "4.14.0", + "@rollup/rollup-android-arm-eabi": "4.14.2", + "@rollup/rollup-android-arm64": "4.14.2", + "@rollup/rollup-darwin-arm64": "4.14.2", + "@rollup/rollup-darwin-x64": "4.14.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.14.2", + "@rollup/rollup-linux-arm64-gnu": "4.14.2", + "@rollup/rollup-linux-arm64-musl": "4.14.2", + "@rollup/rollup-linux-powerpc64le-gnu": "4.14.2", + "@rollup/rollup-linux-riscv64-gnu": "4.14.2", + "@rollup/rollup-linux-s390x-gnu": "4.14.2", + "@rollup/rollup-linux-x64-gnu": "4.14.2", + "@rollup/rollup-linux-x64-musl": "4.14.2", + "@rollup/rollup-win32-arm64-msvc": "4.14.2", + "@rollup/rollup-win32-ia32-msvc": "4.14.2", + "@rollup/rollup-win32-x64-msvc": "4.14.2", "fsevents": "~2.3.2" } }, "node_modules/vitest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.4.0.tgz", - "integrity": "sha512-gujzn0g7fmwf83/WzrDTnncZt2UiXP41mHuFYFrdwaLRVQ6JYQEiME2IfEjU3vcFL3VKa75XhI3lFgn+hfVsQw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.0.tgz", + "integrity": "sha512-d8UKgR0m2kjdxDWX6911uwxout6GHS0XaGH1cksSIVVG8kRlE7G7aBw7myKQCvDI5dT4j7ZMa+l706BIORMDLw==", "dev": true, "dependencies": { - "@vitest/expect": "1.4.0", - "@vitest/runner": "1.4.0", - "@vitest/snapshot": "1.4.0", - "@vitest/spy": "1.4.0", - "@vitest/utils": "1.4.0", + "@vitest/expect": "1.5.0", + "@vitest/runner": "1.5.0", + "@vitest/snapshot": "1.5.0", + "@vitest/spy": "1.5.0", + "@vitest/utils": "1.5.0", "acorn-walk": "^8.3.2", "chai": "^4.3.10", "debug": "^4.3.4", @@ -12106,9 +12091,9 @@ "std-env": "^3.5.0", "strip-literal": "^2.0.0", "tinybench": "^2.5.1", - "tinypool": "^0.8.2", + "tinypool": "^0.8.3", "vite": "^5.0.0", - "vite-node": "1.4.0", + "vite-node": "1.5.0", "why-is-node-running": "^2.2.2" }, "bin": { @@ -12123,8 +12108,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.4.0", - "@vitest/ui": "1.4.0", + "@vitest/browser": "1.5.0", + "@vitest/ui": "1.5.0", "happy-dom": "*", "jsdom": "*" }, @@ -12191,9 +12176,9 @@ } }, "node_modules/vue-chartjs": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/vue-chartjs/-/vue-chartjs-5.3.0.tgz", - "integrity": "sha512-8XqX0JU8vFZ+WA2/knz4z3ThClduni2Nm0BMe2u0mXgTfd9pXrmJ07QBI+WAij5P/aPmPMX54HCE1seWL37ZdQ==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/vue-chartjs/-/vue-chartjs-5.3.1.tgz", + "integrity": "sha512-rZjqcHBxKiHrBl0CIvcOlVEBwRhpWAVf6rDU3vUfa7HuSRmGtCslc0Oc8m16oAVuk0erzc1FCtH1VCriHsrz+A==", "peerDependencies": { "chart.js": "^4.1.1", "vue": "^3.0.0-0 || ^2.7.0" diff --git a/package.json b/package.json index f58c3b4d8f..ff1ae4d49e 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "chartjs-adapter-dayjs-4": "1.0.4", "chartjs-plugin-zoom": "2.0.1", "clippie": "4.0.7", - "css-loader": "7.0.0", + "css-loader": "7.1.1", "dayjs": "1.11.10", "dropzone": "6.0.0-beta.2", "easymde": "2.18.0", @@ -43,9 +43,9 @@ "postcss-nesting": "12.1.1", "pretty-ms": "9.0.0", "sortablejs": "1.15.2", - "swagger-ui-dist": "5.13.0", + "swagger-ui-dist": "5.15.1", "tailwindcss": "3.4.3", - "temporal-polyfill": "0.2.3", + "temporal-polyfill": "0.2.4", "throttle-debounce": "5.0.0", "tinycolor2": "1.6.0", "tippy.js": "6.3.7", @@ -55,7 +55,7 @@ "vanilla-colorful": "0.7.2", "vue": "3.4.21", "vue-bar-graph": "2.0.0", - "vue-chartjs": "5.3.0", + "vue-chartjs": "5.3.1", "vue-loader": "17.4.2", "vue3-calendar-heatmap": "2.0.5", "webpack": "5.91.0", @@ -63,8 +63,8 @@ "wrap-ansi": "9.0.0" }, "devDependencies": { - "@eslint-community/eslint-plugin-eslint-comments": "4.1.0", - "@playwright/test": "1.42.1", + "@eslint-community/eslint-plugin-eslint-comments": "4.3.0", + "@playwright/test": "1.43.1", "@stoplight/spectral-cli": "6.11.1", "@stylistic/eslint-plugin-js": "1.7.0", "@stylistic/stylelint-plugin": "2.1.1", @@ -76,15 +76,15 @@ "eslint-plugin-jquery": "1.5.1", "eslint-plugin-no-jquery": "2.7.0", "eslint-plugin-no-use-extend-native": "0.5.0", - "eslint-plugin-regexp": "2.4.0", + "eslint-plugin-regexp": "2.5.0", "eslint-plugin-sonarjs": "0.25.1", "eslint-plugin-unicorn": "52.0.0", "eslint-plugin-vitest": "0.4.1", "eslint-plugin-vitest-globals": "1.5.0", - "eslint-plugin-vue": "9.24.0", + "eslint-plugin-vue": "9.24.1", "eslint-plugin-vue-scoped-css": "2.8.0", - "eslint-plugin-wc": "2.0.4", - "happy-dom": "14.5.0", + "eslint-plugin-wc": "2.1.0", + "happy-dom": "14.7.1", "markdownlint-cli": "0.39.0", "postcss-html": "1.6.0", "stylelint": "16.3.1", @@ -92,9 +92,9 @@ "stylelint-declaration-strict-value": "1.10.4", "stylelint-value-no-unknown-custom-properties": "6.0.1", "svgo": "3.2.0", - "updates": "16.0.0", + "updates": "16.0.1", "vite-string-plugin": "1.1.5", - "vitest": "1.4.0" + "vitest": "1.5.0" }, "browserslist": [ "defaults" diff --git a/poetry.lock b/poetry.lock index 951a0fa7a8..1533ddc5ec 100644 --- a/poetry.lock +++ b/poetry.lock @@ -113,13 +113,13 @@ six = ">=1.13.0" [[package]] name = "json5" -version = "0.9.24" +version = "0.9.25" description = "A Python implementation of the JSON5 data format." optional = false python-versions = ">=3.8" files = [ - {file = "json5-0.9.24-py3-none-any.whl", hash = "sha256:4ca101fd5c7cb47960c055ef8f4d0e31e15a7c6c48c3b6f1473fc83b6c462a13"}, - {file = "json5-0.9.24.tar.gz", hash = "sha256:0c638399421da959a20952782800e5c1a78c14e08e1dc9738fa10d8ec14d58c8"}, + {file = "json5-0.9.25-py3-none-any.whl", hash = "sha256:34ed7d834b1341a86987ed52f3f76cd8ee184394906b6e22a1e0deb9ab294e8f"}, + {file = "json5-0.9.25.tar.gz", hash = "sha256:548e41b9be043f9426776f05df8635a00fe06104ea51ed24b67f908856e151ae"}, ] [[package]] diff --git a/updates.config.js b/updates.config.js index 11908dea8e..bd072fe6cb 100644 --- a/updates.config.js +++ b/updates.config.js @@ -1,6 +1,8 @@ export default { exclude: [ '@mcaptcha/vanilla-glue', // breaking changes in rc versions need to be handled + 'eslint', // need to migrate to eslint flat config first 'eslint-plugin-array-func', // need to migrate to eslint flat config first + 'eslint-plugin-vitest', // need to migrate to eslint flat config first ], }; From 92e27e15c38b95be2309dae316b896ee1d80324b Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sat, 13 Apr 2024 17:31:40 +0800 Subject: [PATCH 100/370] Add comment for ContainsRedirectURI about the exact match (#30457) Close #26897 Replace #30336 --- models/auth/oauth2.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/models/auth/oauth2.go b/models/auth/oauth2.go index 9d53fffc78..bc1bcaef63 100644 --- a/models/auth/oauth2.go +++ b/models/auth/oauth2.go @@ -137,6 +137,11 @@ func (app *OAuth2Application) TableName() string { // ContainsRedirectURI checks if redirectURI is allowed for app func (app *OAuth2Application) ContainsRedirectURI(redirectURI string) bool { + // OAuth2 requires the redirect URI to be an exact match, no dynamic parts are allowed. + // https://stackoverflow.com/questions/55524480/should-dynamic-query-parameters-be-present-in-the-redirection-uri-for-an-oauth2 + // https://www.rfc-editor.org/rfc/rfc6819#section-5.2.3.3 + // https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest + // https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics-12#section-3.1 contains := func(s string) bool { s = strings.TrimSuffix(strings.ToLower(s), "/") for _, u := range app.RedirectURIs { From 18dd9f9a3f3ef68e3cb2c0b032f751b64ea0e6e8 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sat, 13 Apr 2024 18:05:33 +0800 Subject: [PATCH 101/370] Fix label rendering (#30456) 1. Check whether the label is for an issue or a pull request. 2. Don't use space to layout 3. Make sure the test strings have trailing spaces explicitly, to avoid some IDE removing the trailing spaces automatically. --- modules/templates/util_render.go | 7 ++-- modules/templates/util_render_test.go | 40 ++++++++++++++----- .../repo/issue/view_content/comments.tmpl | 6 +-- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/modules/templates/util_render.go b/modules/templates/util_render.go index 0b53965f25..659422aee7 100644 --- a/modules/templates/util_render.go +++ b/modules/templates/util_render.go @@ -216,15 +216,16 @@ func RenderMarkdownToHtml(ctx context.Context, input string) template.HTML { //n return output } -func RenderLabels(ctx context.Context, locale translation.Locale, labels []*issues_model.Label, repoLink string) template.HTML { +func RenderLabels(ctx context.Context, locale translation.Locale, labels []*issues_model.Label, repoLink string, issue *issues_model.Issue) template.HTML { + isPullRequest := issue != nil && issue.IsPull + baseLink := fmt.Sprintf("%s/%s", repoLink, util.Iif(isPullRequest, "pulls", "issues")) htmlCode := `<span class="labels-list">` for _, label := range labels { // Protect against nil value in labels - shouldn't happen but would cause a panic if so if label == nil { continue } - htmlCode += fmt.Sprintf("<a href='%s/issues?labels=%d'>%s</a> ", - repoLink, label.ID, RenderLabel(ctx, locale, label)) + htmlCode += fmt.Sprintf(`<a href="%s?labels=%d">%s</a>`, baseLink, label.ID, RenderLabel(ctx, locale, label)) } htmlCode += "</span>" return template.HTML(htmlCode) diff --git a/modules/templates/util_render_test.go b/modules/templates/util_render_test.go index 15aee8912d..47c5da6485 100644 --- a/modules/templates/util_render_test.go +++ b/modules/templates/util_render_test.go @@ -7,17 +7,21 @@ import ( "context" "html/template" "os" + "strings" "testing" + "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/translation" "github.com/stretchr/testify/assert" ) -const testInput = ` space @mention-user +func testInput() string { + s := ` space @mention-user<SPACE><SPACE> /just/a/path.bin https://example.com/file.bin [local link](file.bin) @@ -36,8 +40,10 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit mail@domain.com @mention-user test #123 - space + space<SPACE><SPACE> ` + return strings.ReplaceAll(s, "<SPACE>", " ") +} var testMetas = map[string]string{ "user": "user13", @@ -121,23 +127,23 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit <a href="/user13/repo11/issues/123" class="ref-issue">#123</a> space` - assert.EqualValues(t, expected, RenderCommitBody(context.Background(), testInput, testMetas)) + assert.EqualValues(t, expected, RenderCommitBody(context.Background(), testInput(), testMetas)) } func TestRenderCommitMessage(t *testing.T) { expected := `space <a href="/mention-user" class="mention">@mention-user</a> ` - assert.EqualValues(t, expected, RenderCommitMessage(context.Background(), testInput, testMetas)) + assert.EqualValues(t, expected, RenderCommitMessage(context.Background(), testInput(), testMetas)) } func TestRenderCommitMessageLinkSubject(t *testing.T) { expected := `<a href="https://example.com/link" class="default-link muted">space </a><a href="/mention-user" class="mention">@mention-user</a>` - assert.EqualValues(t, expected, RenderCommitMessageLinkSubject(context.Background(), testInput, "https://example.com/link", testMetas)) + assert.EqualValues(t, expected, RenderCommitMessageLinkSubject(context.Background(), testInput(), "https://example.com/link", testMetas)) } func TestRenderIssueTitle(t *testing.T) { - expected := ` space @mention-user + expected := ` space @mention-user<SPACE><SPACE> /just/a/path.bin https://example.com/file.bin [local link](file.bin) @@ -156,9 +162,10 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit mail@domain.com @mention-user test <a href="/user13/repo11/issues/123" class="ref-issue">#123</a> - space + space<SPACE><SPACE> ` - assert.EqualValues(t, expected, RenderIssueTitle(context.Background(), testInput, testMetas)) + expected = strings.ReplaceAll(expected, "<SPACE>", " ") + assert.EqualValues(t, expected, RenderIssueTitle(context.Background(), testInput(), testMetas)) } func TestRenderMarkdownToHtml(t *testing.T) { @@ -183,5 +190,20 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit #123 space</p> ` - assert.EqualValues(t, expected, RenderMarkdownToHtml(context.Background(), testInput)) + assert.EqualValues(t, expected, RenderMarkdownToHtml(context.Background(), testInput())) +} + +func TestRenderLabels(t *testing.T) { + ctx := context.Background() + locale := &translation.MockLocale{} + + label := &issues.Label{ID: 123, Name: "label-name", Color: "label-color"} + issue := &issues.Issue{} + expected := `/owner/repo/issues?labels=123` + assert.Contains(t, RenderLabels(ctx, locale, []*issues.Label{label}, "/owner/repo", issue), expected) + + label = &issues.Label{ID: 123, Name: "label-name", Color: "label-color"} + issue = &issues.Issue{IsPull: true} + expected = `/owner/repo/pulls?labels=123` + assert.Contains(t, RenderLabels(ctx, locale, []*issues.Label{label}, "/owner/repo", issue), expected) } diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index f65dc6ee90..d900d23c47 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -173,11 +173,11 @@ <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} {{if and .AddedLabels (not .RemovedLabels)}} - {{ctx.Locale.TrN (len .AddedLabels) "repo.issues.add_label" "repo.issues.add_labels" (RenderLabels $.Context ctx.Locale .AddedLabels $.RepoLink) $createdStr}} + {{ctx.Locale.TrN (len .AddedLabels) "repo.issues.add_label" "repo.issues.add_labels" (RenderLabels ctx ctx.Locale .AddedLabels $.RepoLink .Issue) $createdStr}} {{else if and (not .AddedLabels) .RemovedLabels}} - {{ctx.Locale.TrN (len .RemovedLabels) "repo.issues.remove_label" "repo.issues.remove_labels" (RenderLabels $.Context ctx.Locale .RemovedLabels $.RepoLink) $createdStr}} + {{ctx.Locale.TrN (len .RemovedLabels) "repo.issues.remove_label" "repo.issues.remove_labels" (RenderLabels ctx ctx.Locale .RemovedLabels $.RepoLink .Issue) $createdStr}} {{else}} - {{ctx.Locale.Tr "repo.issues.add_remove_labels" (RenderLabels $.Context ctx.Locale .AddedLabels $.RepoLink) (RenderLabels $.Context ctx.Locale .RemovedLabels $.RepoLink) $createdStr}} + {{ctx.Locale.Tr "repo.issues.add_remove_labels" (RenderLabels ctx ctx.Locale .AddedLabels $.RepoLink .Issue) (RenderLabels ctx ctx.Locale .RemovedLabels $.RepoLink .Issue) $createdStr}} {{end}} </span> </div> From fd59cd9450cbd511ad4a0790bf51f8d5d2c18aa3 Mon Sep 17 00:00:00 2001 From: Jason Song <i@wolfogre.com> Date: Sat, 13 Apr 2024 23:41:57 +0800 Subject: [PATCH 102/370] Avoid losing token when updating mirror settings (#30429) Fix #30416. Before (it shows as "Unset" while there's a token): <img width="980" alt="image" src="https://github.com/go-gitea/gitea/assets/9418365/d7148e3e-62c9-4d2e-942d-3d795b79515a"> After: <img width="977" alt="image" src="https://github.com/go-gitea/gitea/assets/9418365/24aaa1db-5baa-4204-9081-470b15ea72b5"> The username shows as "oauth2" because of https://github.com/go-gitea/gitea/blob/f9fdac9809335729b2ac3227b2a5f71a62fc64ad/services/migrations/dump.go#L99 I have checked that all usage of `MirrorRemoteAddress` has been updated. <img width="1806" alt="image" src="https://github.com/go-gitea/gitea/assets/9418365/2f042501-2824-4511-9203-c84a6731a02d"> However, it needs to be checked again when backporting. --------- Co-authored-by: Giteabot <teabot@gitea.io> --- modules/templates/util_misc.go | 38 +++++++++++++++------------- services/mirror/mirror_pull.go | 12 +++++++-- templates/repo/settings/options.tmpl | 2 +- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/modules/templates/util_misc.go b/modules/templates/util_misc.go index 6c1b4ab240..774385483b 100644 --- a/modules/templates/util_misc.go +++ b/modules/templates/util_misc.go @@ -142,35 +142,39 @@ type remoteAddress struct { Password string } -func mirrorRemoteAddress(ctx context.Context, m *repo_model.Repository, remoteName string, ignoreOriginalURL bool) remoteAddress { - a := remoteAddress{} - - remoteURL := m.OriginalURL - if ignoreOriginalURL || remoteURL == "" { - var err error - remoteURL, err = git.GetRemoteAddress(ctx, m.RepoPath(), remoteName) - if err != nil { - log.Error("GetRemoteURL %v", err) - return a - } +func mirrorRemoteAddress(ctx context.Context, m *repo_model.Repository, remoteName string) remoteAddress { + ret := remoteAddress{} + remoteURL, err := git.GetRemoteAddress(ctx, m.RepoPath(), remoteName) + if err != nil { + log.Error("GetRemoteURL %v", err) + return ret } u, err := giturl.Parse(remoteURL) if err != nil { log.Error("giturl.Parse %v", err) - return a + return ret } if u.Scheme != "ssh" && u.Scheme != "file" { if u.User != nil { - a.Username = u.User.Username() - a.Password, _ = u.User.Password() + ret.Username = u.User.Username() + ret.Password, _ = u.User.Password() } - u.User = nil } - a.Address = u.String() - return a + // The URL stored in the git repo could contain authentication, + // erase it, or it will be shown in the UI. + u.User = nil + ret.Address = u.String() + // Why not use m.OriginalURL to set ret.Address? + // It should be OK to use it, since m.OriginalURL should be the same as the authentication-erased URL from the Git repository. + // However, the old code has already stored authentication in m.OriginalURL when updating mirror settings. + // That means we need to use "giturl.Parse" for m.OriginalURL again to ensure authentication is erased. + // Instead of doing this, why not directly use the authentication-erased URL from the Git repository? + // It should be the same as long as there are no bugs. + + return ret } func FilenameIsImage(filename string) bool { diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index 21d5f08205..fa23986c54 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -13,6 +13,7 @@ import ( system_model "code.gitea.io/gitea/models/system" "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/git" + giturl "code.gitea.io/gitea/modules/git/url" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/log" @@ -30,10 +31,15 @@ const gitShortEmptySha = "0000000" // UpdateAddress writes new address to Git repository and database func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error { + u, err := giturl.Parse(addr) + if err != nil { + return fmt.Errorf("invalid addr: %v", err) + } + remoteName := m.GetRemoteName() repoPath := m.GetRepository(ctx).RepoPath() // Remove old remote - _, _, err := git.NewCommand(ctx, "remote", "rm").AddDynamicArguments(remoteName).RunStdString(&git.RunOpts{Dir: repoPath}) + _, _, err = git.NewCommand(ctx, "remote", "rm").AddDynamicArguments(remoteName).RunStdString(&git.RunOpts{Dir: repoPath}) if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { return err } @@ -70,7 +76,9 @@ func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error } } - m.Repo.OriginalURL = addr + // erase authentication before storing in database + u.User = nil + m.Repo.OriginalURL = u.String() return repo_model.UpdateRepositoryCols(ctx, m.Repo, "original_url") } diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index b8fa4759b1..df6ccbf6bc 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -156,7 +156,7 @@ <label for="interval">{{ctx.Locale.Tr "repo.mirror_interval" .MinimumMirrorInterval}}</label> <input id="interval" name="interval" value="{{.PullMirror.Interval}}"> </div> - {{$address := MirrorRemoteAddress $.Context .Repository .PullMirror.GetRemoteName false}} + {{$address := MirrorRemoteAddress $.Context .Repository .PullMirror.GetRemoteName}} <div class="field {{if .Err_MirrorAddress}}error{{end}}"> <label for="mirror_address">{{ctx.Locale.Tr "repo.mirror_address"}}</label> <input id="mirror_address" name="mirror_address" value="{{$address.Address}}" required> From af02b8a0e9b00a324fb92f1f73ea386dd9595c3d Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Sun, 14 Apr 2024 01:17:01 +0900 Subject: [PATCH 103/370] Fix network error when open/close organization/individual projects and redirect to project page (#30387) Follow #27734  Updated: Redirect to project page instead of project list page. --- routers/web/org/projects.go | 8 ++++---- routers/web/repo/projects.go | 9 ++------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go index 596a370d2e..d439b11cf9 100644 --- a/routers/web/org/projects.go +++ b/routers/web/org/projects.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "net/http" - "net/url" "strconv" "strings" @@ -195,14 +194,15 @@ func NewProjectPost(ctx *context.Context) { // ChangeProjectStatus updates the status of a project between "open" and "close" func ChangeProjectStatus(ctx *context.Context) { - toClose := false + var toClose bool switch ctx.Params(":action") { case "open": toClose = false case "close": toClose = true default: - ctx.Redirect(ctx.ContextUser.HomeLink() + "/-/projects") + ctx.JSONRedirect(ctx.ContextUser.HomeLink() + "/-/projects") + return } id := ctx.ParamsInt64(":id") @@ -210,7 +210,7 @@ func ChangeProjectStatus(ctx *context.Context) { ctx.NotFoundOrServerError("ChangeProjectStatusByRepoIDAndID", project_model.IsErrProjectNotExist, err) return } - ctx.Redirect(ctx.ContextUser.HomeLink() + "/-/projects?state=" + url.QueryEscape(ctx.Params(":action"))) + ctx.JSONRedirect(fmt.Sprintf("%s/-/projects/%d", ctx.ContextUser.HomeLink(), id)) } // DeleteProject delete a project diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go index a2db1fc770..9b765e89e8 100644 --- a/routers/web/repo/projects.go +++ b/routers/web/repo/projects.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "net/http" - "net/url" "strings" "code.gitea.io/gitea/models/db" @@ -181,14 +180,10 @@ func ChangeProjectStatus(ctx *context.Context) { id := ctx.ParamsInt64(":id") if err := project_model.ChangeProjectStatusByRepoIDAndID(ctx, ctx.Repo.Repository.ID, id, toClose); err != nil { - if project_model.IsErrProjectNotExist(err) { - ctx.NotFound("", err) - } else { - ctx.ServerError("ChangeProjectStatusByIDAndRepoID", err) - } + ctx.NotFoundOrServerError("ChangeProjectStatusByRepoIDAndID", project_model.IsErrProjectNotExist, err) return } - ctx.JSONRedirect(ctx.Repo.RepoLink + "/projects?state=" + url.QueryEscape(ctx.Params(":action"))) + ctx.JSONRedirect(fmt.Sprintf("%s/projects/%d", ctx.Repo.RepoLink, id)) } // DeleteProject delete a project From c77e8140bc2ac6521dbebfb77613dce2648bfcb8 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sat, 13 Apr 2024 19:32:15 +0200 Subject: [PATCH 104/370] Add `interface{}` to `any` replacement to `make fmt`, exclude `*.pb.go` (#30461) Since https://github.com/go-gitea/gitea/pull/25686, a few `interface{}` have sneaked into the codebase. Add this replacement to `make fmt` to prevent this from happening again. Ideally a linter would do this, but I haven't found any suitable. --- .gitattributes | 1 + Makefile | 2 +- build/code-batch-process.go | 15 +++------------ modules/optional/serialization.go | 2 +- services/actions/auth_test.go | 2 +- 5 files changed, 7 insertions(+), 15 deletions(-) diff --git a/.gitattributes b/.gitattributes index 467b8a47b5..9fb4a4e83d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,6 @@ * text=auto eol=lf *.tmpl linguist-language=Handlebars +*.pb.go linguist-generated /assets/*.json linguist-generated /public/assets/img/svg/*.svg linguist-generated /templates/swagger/v1_json.tmpl linguist-generated diff --git a/Makefile b/Makefile index f1acfbc81e..594f13ead8 100644 --- a/Makefile +++ b/Makefile @@ -295,7 +295,7 @@ clean: .PHONY: fmt fmt: - GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}' + @GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}' $(eval TEMPLATES := $(shell find templates -type f -name '*.tmpl')) @# strip whitespace after '{{' or '(' and before '}}' or ')' unless there is only @# whitespace before it diff --git a/build/code-batch-process.go b/build/code-batch-process.go index b3ee399420..cc2ab68026 100644 --- a/build/code-batch-process.go +++ b/build/code-batch-process.go @@ -69,6 +69,7 @@ func newFileCollector(fileFilter string, batchSize int) (*fileCollector, error) co.includePatterns = append(co.includePatterns, regexp.MustCompile(`.*\.go$`)) co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`.*\bbindata\.go$`)) + co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`\.pb\.go$`)) co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`tests/gitea-repositories-meta`)) co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`tests/integration/migration-test`)) co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`modules/git/tests`)) @@ -203,17 +204,6 @@ Example: `, "file-batch-exec") } -func getGoVersion() string { - goModFile, err := os.ReadFile("go.mod") - if err != nil { - log.Fatalf(`Faild to read "go.mod": %v`, err) - os.Exit(1) - } - goModVersionRegex := regexp.MustCompile(`go \d+\.\d+`) - goModVersionLine := goModVersionRegex.Find(goModFile) - return string(goModVersionLine[3:]) -} - func newFileCollectorFromMainOptions(mainOptions map[string]string) (fc *fileCollector, err error) { fileFilter := mainOptions["file-filter"] if fileFilter == "" { @@ -278,7 +268,8 @@ func main() { log.Print("the -d option is not supported by gitea-fmt") } cmdErrors = append(cmdErrors, giteaFormatGoImports(files, containsString(subArgs, "-w"))) - cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("GOFUMPT_PACKAGE"), "-extra", "-lang", getGoVersion()}, substArgs...))) + cmdErrors = append(cmdErrors, passThroughCmd("gofmt", append([]string{"-w", "-r", "interface{} -> any"}, substArgs...))) + cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("GOFUMPT_PACKAGE"), "-extra"}, substArgs...))) default: log.Fatalf("unknown cmd: %s %v", subCmd, subArgs) } diff --git a/modules/optional/serialization.go b/modules/optional/serialization.go index 6688e78cd1..b120a0edf6 100644 --- a/modules/optional/serialization.go +++ b/modules/optional/serialization.go @@ -35,7 +35,7 @@ func (o *Option[T]) UnmarshalYAML(value *yaml.Node) error { return nil } -func (o Option[T]) MarshalYAML() (interface{}, error) { +func (o Option[T]) MarshalYAML() (any, error) { if !o.Has() { return nil, nil } diff --git a/services/actions/auth_test.go b/services/actions/auth_test.go index f73ae8ae4c..12db2bae56 100644 --- a/services/actions/auth_test.go +++ b/services/actions/auth_test.go @@ -20,7 +20,7 @@ func TestCreateAuthorizationToken(t *testing.T) { assert.Nil(t, err) assert.NotEqual(t, "", token) claims := jwt.MapClaims{} - _, err = jwt.ParseWithClaims(token, claims, func(t *jwt.Token) (interface{}, error) { + _, err = jwt.ParseWithClaims(token, claims, func(t *jwt.Token) (any, error) { return setting.GetGeneralTokenSigningSecret(), nil }) assert.Nil(t, err) From b18c04ebde94e23d97da4958173faea843d5344f Mon Sep 17 00:00:00 2001 From: Jonathan Tran <jonnytran@gmail.com> Date: Sun, 14 Apr 2024 00:46:56 -0400 Subject: [PATCH 105/370] fix: Fix to delete cookie when AppSubURL is non-empty (#30375) Cookies may exist on "/subpath" and "/subpath/" for some legacy reasons (eg: changed CookiePath behavior in code). The legacy cookie should be removed correctly. --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: Kyle D <kdumontnu@gmail.com> --- modules/session/store.go | 7 ++++++ modules/web/middleware/cookie.go | 34 +++++++++++++++++++++++----- services/auth/source/oauth2/store.go | 3 ++- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/modules/session/store.go b/modules/session/store.go index 4fa4d2848f..2f7ab7760b 100644 --- a/modules/session/store.go +++ b/modules/session/store.go @@ -6,6 +6,9 @@ package session import ( "net/http" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/web/middleware" + "gitea.com/go-chi/session" ) @@ -18,6 +21,10 @@ type Store interface { // RegenerateSession regenerates the underlying session and returns the new store func RegenerateSession(resp http.ResponseWriter, req *http.Request) (Store, error) { + // Ensure that a cookie with a trailing slash does not take precedence over + // the cookie written by the middleware. + middleware.DeleteLegacySiteCookie(resp, setting.SessionConfig.CookieName) + s, err := session.RegenerateSession(resp, req) return s, err } diff --git a/modules/web/middleware/cookie.go b/modules/web/middleware/cookie.go index 621640895b..0bed726793 100644 --- a/modules/web/middleware/cookie.go +++ b/modules/web/middleware/cookie.go @@ -45,10 +45,32 @@ func SetSiteCookie(resp http.ResponseWriter, name, value string, maxAge int) { SameSite: setting.SessionConfig.SameSite, } resp.Header().Add("Set-Cookie", cookie.String()) - if maxAge < 0 { - // There was a bug in "setting.SessionConfig.CookiePath" code, the old default value of it was empty "". - // So we have to delete the cookie on path="" again, because some old code leaves cookies on path="". - cookie.Path = strings.TrimSuffix(setting.SessionConfig.CookiePath, "/") - resp.Header().Add("Set-Cookie", cookie.String()) - } + // Previous versions would use a cookie path with a trailing /. + // These are more specific than cookies without a trailing /, so + // we need to delete these if they exist. + DeleteLegacySiteCookie(resp, name) +} + +// DeleteLegacySiteCookie deletes the cookie with the given name at the cookie +// path with a trailing /, which would unintentionally override the cookie. +func DeleteLegacySiteCookie(resp http.ResponseWriter, name string) { + if setting.SessionConfig.CookiePath == "" || strings.HasSuffix(setting.SessionConfig.CookiePath, "/") { + // If the cookie path ends with /, no legacy cookies will take + // precedence, so do nothing. The exception is that cookies with no + // path could override other cookies, but it's complicated and we don't + // currently handle that. + return + } + + cookie := &http.Cookie{ + Name: name, + Value: "", + MaxAge: -1, + Path: setting.SessionConfig.CookiePath + "/", + Domain: setting.SessionConfig.Domain, + Secure: setting.SessionConfig.Secure, + HttpOnly: true, + SameSite: setting.SessionConfig.SameSite, + } + resp.Header().Add("Set-Cookie", cookie.String()) } diff --git a/services/auth/source/oauth2/store.go b/services/auth/source/oauth2/store.go index 394bf99463..90fa965602 100644 --- a/services/auth/source/oauth2/store.go +++ b/services/auth/source/oauth2/store.go @@ -9,6 +9,7 @@ import ( "net/http" "code.gitea.io/gitea/modules/log" + session_module "code.gitea.io/gitea/modules/session" chiSession "gitea.com/go-chi/session" "github.com/gorilla/sessions" @@ -65,7 +66,7 @@ func (st *SessionsStore) Save(r *http.Request, w http.ResponseWriter, session *s chiStore := chiSession.GetSession(r) if session.IsNew { - _, _ = chiSession.RegenerateSession(w, r) + _, _ = session_module.RegenerateSession(w, r) session.IsNew = false } From ce130ae8daa37c977443045390209e9095dc42b1 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 14 Apr 2024 09:16:03 +0200 Subject: [PATCH 106/370] Fix JS error when opening to expanded code comment (#30463) Fix regression from https://github.com/go-gitea/gitea/commit/e0b018706fa7703ef1759d9a75a1399383715808 where opening to a code comment via hash link would give this error: <img width="1247" alt="image" src="https://github.com/go-gitea/gitea/assets/115237/f9aaeded-8492-4416-9a73-afa0c56220a7"> --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> --- web_src/js/features/repo-issue.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/web_src/js/features/repo-issue.js b/web_src/js/features/repo-issue.js index 0d326aae58..2b2eed58bb 100644 --- a/web_src/js/features/repo-issue.js +++ b/web_src/js/features/repo-issue.js @@ -449,12 +449,10 @@ export function initRepoPullRequestReview() { offset += $('.diff-detail-box').outerHeight() + $(diffHeader).outerHeight(); } - document.getElementById(`show-outdated-${id}`).classList.add('tw-hidden'); - document.getElementById(`code-comments-${id}`).classList.remove('tw-hidden'); - document.getElementById(`code-preview-${id}`).classList.remove('tw-hidden'); - document.getElementById(`hide-outdated-${id}`).classList.remove('tw-hidden'); + hideElem(`#show-outdated-${id}`); + showElem(`#code-comments-${id}, #code-preview-${id}, #hide-outdated-${id}`); // if the comment box is folded, expand it - if (ancestorDiffBox.getAttribute('data-folded') === 'true') { + if (ancestorDiffBox?.getAttribute('data-folded') === 'true') { setFileFolding(ancestorDiffBox, ancestorDiffBox.querySelector('.fold-file'), false); } From 6999a88fd9bef6baa0a8cc5f63e419079611fc9b Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 14 Apr 2024 11:21:16 +0200 Subject: [PATCH 107/370] Pulse page improvements (#30149) 1. add border-radius and spacing to bars 2. use tailwind background classes 3. Add more space around activity list headers <img width="983" alt="Screenshot 2024-03-27 at 23 40 54" src="https://github.com/go-gitea/gitea/assets/115237/70f72c30-e69f-4ecb-882f-32b8bc94d638"> <img width="1020" alt="Screenshot 2024-03-27 at 23 41 02" src="https://github.com/go-gitea/gitea/assets/115237/a35dbbda-515c-40b0-938a-d759f9686b8e"> --- templates/repo/pulse.tmpl | 26 +++++++++++++++----------- web_src/css/dashboard.css | 1 - web_src/css/modules/divider.css | 6 +++++- web_src/css/modules/header.css | 1 - web_src/css/modules/label.css | 1 - web_src/css/repo.css | 14 +++++++++++++- 6 files changed, 33 insertions(+), 16 deletions(-) diff --git a/templates/repo/pulse.tmpl b/templates/repo/pulse.tmpl index cfb3ec1d3d..bc25563d48 100644 --- a/templates/repo/pulse.tmpl +++ b/templates/repo/pulse.tmpl @@ -25,12 +25,14 @@ <div class="column"> {{if gt .Activity.ActivePRCount 0}} <div class="stats-table"> - <a href="#merged-pull-requests" class="table-cell tiny background purple" style="width: {{.Activity.MergedPRPerc}}{{if ne .Activity.MergedPRPerc 0}}%{{end}}"></a> - <a href="#proposed-pull-requests" class="table-cell tiny background green"></a> + {{if gt .Activity.MergedPRPerc 0}} + <a href="#merged-pull-requests" class="table-cell tiny tw-bg-purple" style="width: {{.Activity.MergedPRPerc}}%"></a> + {{end}} + <a href="#proposed-pull-requests" class="table-cell tiny tw-bg-green"></a> </div> {{else}} <div class="stats-table"> - <a class="table-cell tiny background light grey"></a> + <a class="table-cell tiny tw-bg-grey"></a> </div> {{end}} {{ctx.Locale.TrN .Activity.ActivePRCount "repo.activity.active_prs_count_1" "repo.activity.active_prs_count_n" .Activity.ActivePRCount}} @@ -40,8 +42,10 @@ <div class="column"> {{if gt .Activity.ActiveIssueCount 0}} <div class="stats-table"> - <a href="#closed-issues" class="table-cell tiny background red" style="width: {{.Activity.ClosedIssuePerc}}{{if ne .Activity.ClosedIssuePerc 0}}%{{end}}"></a> - <a href="#new-issues" class="table-cell tiny background green"></a> + {{if gt .Activity.ClosedIssuePerc 0}} + <a href="#closed-issues" class="table-cell tiny tw-bg-red" style="width: {{.Activity.ClosedIssuePerc}}%"></a> + {{end}} + <a href="#new-issues" class="table-cell tiny tw-bg-green"></a> </div> {{else}} <div class="stats-table"> @@ -108,7 +112,7 @@ {{end}} {{if gt .Activity.PublishedReleaseCount 0}} - <h4 class="divider divider-text tw-normal-case" id="published-releases"> + <h4 class="divider divider-text" id="published-releases"> {{svg "octicon-tag" 16 "tw-mr-2"}} {{ctx.Locale.Tr "repo.activity.title.releases_published_by" (ctx.Locale.TrN .Activity.PublishedReleaseCount "repo.activity.title.releases_1" "repo.activity.title.releases_n" .Activity.PublishedReleaseCount) @@ -130,7 +134,7 @@ {{end}} {{if gt .Activity.MergedPRCount 0}} - <h4 class="divider divider-text tw-normal-case" id="merged-pull-requests"> + <h4 class="divider divider-text" id="merged-pull-requests"> {{svg "octicon-git-pull-request" 16 "tw-mr-2"}} {{ctx.Locale.Tr "repo.activity.title.prs_merged_by" (ctx.Locale.TrN .Activity.MergedPRCount "repo.activity.title.prs_1" "repo.activity.title.prs_n" .Activity.MergedPRCount) @@ -149,7 +153,7 @@ {{end}} {{if gt .Activity.OpenedPRCount 0}} - <h4 class="divider divider-text tw-normal-case" id="proposed-pull-requests"> + <h4 class="divider divider-text" id="proposed-pull-requests"> {{svg "octicon-git-branch" 16 "tw-mr-2"}} {{ctx.Locale.Tr "repo.activity.title.prs_opened_by" (ctx.Locale.TrN .Activity.OpenedPRCount "repo.activity.title.prs_1" "repo.activity.title.prs_n" .Activity.OpenedPRCount) @@ -168,7 +172,7 @@ {{end}} {{if gt .Activity.ClosedIssueCount 0}} - <h4 class="divider divider-text tw-normal-case" id="closed-issues"> + <h4 class="divider divider-text" id="closed-issues"> {{svg "octicon-issue-closed" 16 "tw-mr-2"}} {{ctx.Locale.Tr "repo.activity.title.issues_closed_from" (ctx.Locale.TrN .Activity.ClosedIssueCount "repo.activity.title.issues_1" "repo.activity.title.issues_n" .Activity.ClosedIssueCount) @@ -187,7 +191,7 @@ {{end}} {{if gt .Activity.OpenedIssueCount 0}} - <h4 class="divider divider-text tw-normal-case" id="new-issues"> + <h4 class="divider divider-text" id="new-issues"> {{svg "octicon-issue-opened" 16 "tw-mr-2"}} {{ctx.Locale.Tr "repo.activity.title.issues_created_by" (ctx.Locale.TrN .Activity.OpenedIssueCount "repo.activity.title.issues_1" "repo.activity.title.issues_n" .Activity.OpenedIssueCount) @@ -206,7 +210,7 @@ {{end}} {{if gt .Activity.UnresolvedIssueCount 0}} - <h4 class="divider divider-text tw-normal-case" id="unresolved-conversations" data-tooltip-content="{{ctx.Locale.Tr "repo.activity.unresolved_conv_desc"}}"> + <h4 class="divider divider-text" id="unresolved-conversations" data-tooltip-content="{{ctx.Locale.Tr "repo.activity.unresolved_conv_desc"}}"> {{svg "octicon-comment-discussion" 16 "tw-mr-2"}} {{ctx.Locale.TrN .Activity.UnresolvedIssueCount "repo.activity.title.unresolved_conv_1" "repo.activity.title.unresolved_conv_n" .Activity.UnresolvedIssueCount}} </h4> diff --git a/web_src/css/dashboard.css b/web_src/css/dashboard.css index d61e0c1cf2..0962215ac6 100644 --- a/web_src/css/dashboard.css +++ b/web_src/css/dashboard.css @@ -7,7 +7,6 @@ .dashboard.feeds .context.user.menu .ui.header, .dashboard.issues .context.user.menu .ui.header { font-size: 1rem; - text-transform: none; } .dashboard.feeds .filter.menu, diff --git a/web_src/css/modules/divider.css b/web_src/css/modules/divider.css index 48560bd3d9..acc8408f37 100644 --- a/web_src/css/modules/divider.css +++ b/web_src/css/modules/divider.css @@ -2,12 +2,16 @@ margin: 10px 0; height: 0; font-weight: var(--font-weight-medium); - text-transform: uppercase; color: var(--color-text); font-size: 1rem; width: 100%; } +h4.divider { + margin-top: 1.25rem; + margin-bottom: 1.25rem; +} + .divider:not(.divider-text) { border-top: 1px solid var(--color-secondary); } diff --git a/web_src/css/modules/header.css b/web_src/css/modules/header.css index 05381e1185..9cec5fcbe6 100644 --- a/web_src/css/modules/header.css +++ b/web_src/css/modules/header.css @@ -9,7 +9,6 @@ font-family: var(--fonts-regular); font-weight: var(--font-weight-medium); line-height: 1.28571429; - text-transform: none; } .ui.header:first-child { diff --git a/web_src/css/modules/label.css b/web_src/css/modules/label.css index 0512c5fddb..32e772ea5b 100644 --- a/web_src/css/modules/label.css +++ b/web_src/css/modules/label.css @@ -10,7 +10,6 @@ background: var(--color-label-bg); color: var(--color-label-text); padding: 0.3em 0.5em; - text-transform: none; font-size: 0.85714286rem; font-weight: var(--font-weight-medium); border: 0 solid transparent; diff --git a/web_src/css/repo.css b/web_src/css/repo.css index c579745238..edb3bc2e87 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -2304,6 +2304,8 @@ td .commit-summary { .stats-table { display: table; width: 100%; + margin: 6px 0; + border-spacing: 2px; } .stats-table .table-cell { @@ -2311,7 +2313,17 @@ td .commit-summary { } .stats-table .table-cell.tiny { - height: 0.5em; + height: 8px; +} + +.stats-table .table-cell:first-child { + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; +} + +.stats-table .table-cell:last-child { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; } .labels-list { From 4b1063f3dba6ef7a54c15f6e795409b504a62391 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 14 Apr 2024 12:44:11 +0200 Subject: [PATCH 108/370] Rewrite and restyle reaction selector and enable no-sizzle eslint rule (#30453) Enable `no-sizzle` lint rule, there was only one use in `initCompReactionSelector` and: - Remove all jQuery except the necessary fomantic dropdown init - Remove the recursion, instead bind event listeners to common parent container nodes --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: Giteabot <teabot@gitea.io> --- .eslintrc.yaml | 4 +- routers/web/repo/issue.go | 2 - services/context/context.go | 1 + templates/repo/diff/comments.tmpl | 4 +- templates/repo/issue/view_content.tmpl | 4 +- .../repo/issue/view_content/add_reaction.tmpl | 10 +- .../repo/issue/view_content/comments.tmpl | 8 +- .../repo/issue/view_content/conversation.tmpl | 8 +- .../repo/issue/view_content/reactions.tmpl | 8 +- web_src/css/base.css | 6 +- web_src/css/index.css | 1 + web_src/css/modules/comment.css | 2 +- web_src/css/repo.css | 124 ++---------------- web_src/css/repo/reactions.css | 70 ++++++++++ web_src/js/features/comp/ReactionSelector.js | 58 ++++---- web_src/js/features/repo-diff.js | 1 - web_src/js/features/repo-legacy.js | 2 +- 17 files changed, 134 insertions(+), 179 deletions(-) create mode 100644 web_src/css/repo/reactions.css diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 5fd0a245f2..3e4c6ea50b 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -318,7 +318,7 @@ rules: jquery/no-serialize: [2] jquery/no-show: [2] jquery/no-size: [2] - jquery/no-sizzle: [0] + jquery/no-sizzle: [2] jquery/no-slide: [0] jquery/no-submit: [0] jquery/no-text: [0] @@ -470,7 +470,7 @@ rules: no-jquery/no-selector-prop: [2] no-jquery/no-serialize: [2] no-jquery/no-size: [2] - no-jquery/no-sizzle: [0] + no-jquery/no-sizzle: [2] no-jquery/no-slide: [2] no-jquery/no-sub: [2] no-jquery/no-support: [2] diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index e4f2e9a2bc..1364d75676 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -3318,7 +3318,6 @@ func ChangeIssueReaction(ctx *context.Context) { } html, err := ctx.RenderToHTML(tplReactions, map[string]any{ - "ctxData": ctx.Data, "ActionURL": fmt.Sprintf("%s/issues/%d/reactions", ctx.Repo.RepoLink, issue.Index), "Reactions": issue.Reactions.GroupByType(), }) @@ -3425,7 +3424,6 @@ func ChangeCommentReaction(ctx *context.Context) { } html, err := ctx.RenderToHTML(tplReactions, map[string]any{ - "ctxData": ctx.Data, "ActionURL": fmt.Sprintf("%s/comments/%d/reactions", ctx.Repo.RepoLink, comment.ID), "Reactions": comment.Reactions.GroupByType(), }) diff --git a/services/context/context.go b/services/context/context.go index 7ab48afb73..9d7787bf4b 100644 --- a/services/context/context.go +++ b/services/context/context.go @@ -101,6 +101,7 @@ func NewTemplateContextForWeb(ctx *Context) TemplateContext { tmplCtx := NewTemplateContext(ctx) tmplCtx["Locale"] = ctx.Base.Locale tmplCtx["AvatarUtils"] = templates.NewAvatarUtils(ctx) + tmplCtx["RootData"] = ctx.Data return tmplCtx } diff --git a/templates/repo/diff/comments.tmpl b/templates/repo/diff/comments.tmpl index a9120465bd..c7f4337182 100644 --- a/templates/repo/diff/comments.tmpl +++ b/templates/repo/diff/comments.tmpl @@ -48,7 +48,7 @@ </div> {{end}} {{end}} - {{template "repo/issue/view_content/add_reaction" dict "ctxData" $.root "ActionURL" (printf "%s/comments/%d/reactions" $.root.RepoLink .ID)}} + {{template "repo/issue/view_content/add_reaction" dict "ActionURL" (printf "%s/comments/%d/reactions" $.root.RepoLink .ID)}} {{template "repo/issue/view_content/context_menu" dict "ctxData" $.root "item" . "delete" true "issue" false "diff" true "IsCommentPoster" (and $.root.IsSigned (eq $.root.SignedUserID .PosterID))}} </div> </div> @@ -68,7 +68,7 @@ </div> {{$reactions := .Reactions.GroupByType}} {{if $reactions}} - {{template "repo/issue/view_content/reactions" dict "ctxData" $.root "ActionURL" (printf "%s/comments/%d/reactions" $.root.RepoLink .ID) "Reactions" $reactions}} + {{template "repo/issue/view_content/reactions" dict "ActionURL" (printf "%s/comments/%d/reactions" $.root.RepoLink .ID) "Reactions" $reactions}} {{end}} </div> </div> diff --git a/templates/repo/issue/view_content.tmpl b/templates/repo/issue/view_content.tmpl index c65b79dea7..06d0586683 100644 --- a/templates/repo/issue/view_content.tmpl +++ b/templates/repo/issue/view_content.tmpl @@ -46,7 +46,7 @@ <div class="comment-header-right actions tw-flex tw-items-center"> {{template "repo/issue/view_content/show_role" dict "ShowRole" .Issue.ShowRole "IgnorePoster" true}} {{if not $.Repository.IsArchived}} - {{template "repo/issue/view_content/add_reaction" dict "ctxData" $ "ActionURL" (printf "%s/issues/%d/reactions" $.RepoLink .Issue.Index)}} + {{template "repo/issue/view_content/add_reaction" dict "ActionURL" (printf "%s/issues/%d/reactions" $.RepoLink .Issue.Index)}} {{end}} {{template "repo/issue/view_content/context_menu" dict "ctxData" $ "item" .Issue "delete" false "issue" true "diff" false "IsCommentPoster" $.IsIssuePoster}} </div> @@ -67,7 +67,7 @@ </div> {{$reactions := .Issue.Reactions.GroupByType}} {{if $reactions}} - {{template "repo/issue/view_content/reactions" dict "ctxData" $ "ActionURL" (printf "%s/issues/%d/reactions" $.RepoLink .Issue.Index) "Reactions" $reactions}} + {{template "repo/issue/view_content/reactions" dict "ActionURL" (printf "%s/issues/%d/reactions" $.RepoLink .Issue.Index) "Reactions" $reactions}} {{end}} </div> </div> diff --git a/templates/repo/issue/view_content/add_reaction.tmpl b/templates/repo/issue/view_content/add_reaction.tmpl index 37931f287e..6baded8fe9 100644 --- a/templates/repo/issue/view_content/add_reaction.tmpl +++ b/templates/repo/issue/view_content/add_reaction.tmpl @@ -1,11 +1,9 @@ -{{if .ctxData.IsSigned}} +{{if ctx.RootData.IsSigned}} <div class="item action ui dropdown jump pointing top right select-reaction" data-action-url="{{.ActionURL}}"> - <a class="add-reaction muted"> - {{svg "octicon-smiley"}} - </a> - <div class="menu reactions-menu"> + <a class="muted">{{svg "octicon-smiley"}}</a> + <div class="menu"> {{range $value := AllowedReactions}} - <a class="item reaction" data-tooltip-content="{{$value}}" aria-label="{{$value}}" data-reaction-content="{{$value}}">{{ReactionToEmoji $value}}</a> + <a class="item emoji comment-reaction-button" data-tooltip-content="{{$value}}" aria-label="{{$value}}" data-reaction-content="{{$value}}">{{ReactionToEmoji $value}}</a> {{end}} </div> </div> diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index d900d23c47..acc04e4c61 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -53,7 +53,7 @@ <div class="comment-header-right actions tw-flex tw-items-center"> {{template "repo/issue/view_content/show_role" dict "ShowRole" .ShowRole}} {{if not $.Repository.IsArchived}} - {{template "repo/issue/view_content/add_reaction" dict "ctxData" $ "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID)}} + {{template "repo/issue/view_content/add_reaction" dict "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID)}} {{end}} {{template "repo/issue/view_content/context_menu" dict "ctxData" $ "item" . "delete" true "issue" true "diff" false "IsCommentPoster" (and $.IsSigned (eq $.SignedUserID .PosterID))}} </div> @@ -74,7 +74,7 @@ </div> {{$reactions := .Reactions.GroupByType}} {{if $reactions}} - {{template "repo/issue/view_content/reactions" dict "ctxData" $ "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID) "Reactions" $reactions}} + {{template "repo/issue/view_content/reactions" dict "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID) "Reactions" $reactions}} {{end}} </div> </div> @@ -427,7 +427,7 @@ <div class="comment-header-right actions tw-flex tw-items-center"> {{template "repo/issue/view_content/show_role" dict "ShowRole" .ShowRole}} {{if not $.Repository.IsArchived}} - {{template "repo/issue/view_content/add_reaction" dict "ctxData" $ "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID)}} + {{template "repo/issue/view_content/add_reaction" dict "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID)}} {{template "repo/issue/view_content/context_menu" dict "ctxData" $ "item" . "delete" false "issue" true "diff" false "IsCommentPoster" (and $.IsSigned (eq $.SignedUserID .PosterID))}} {{end}} </div> @@ -448,7 +448,7 @@ </div> {{$reactions := .Reactions.GroupByType}} {{if $reactions}} - {{template "repo/issue/view_content/reactions" dict "ctxData" $ "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID) "Reactions" $reactions}} + {{template "repo/issue/view_content/reactions" dict "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID) "Reactions" $reactions}} {{end}} </div> </div> diff --git a/templates/repo/issue/view_content/conversation.tmpl b/templates/repo/issue/view_content/conversation.tmpl index 79e7cb498b..ac32a2db5d 100644 --- a/templates/repo/issue/view_content/conversation.tmpl +++ b/templates/repo/issue/view_content/conversation.tmpl @@ -55,8 +55,8 @@ <div class="ui comments tw-mb-0"> {{range .comments}} {{$createdSubStr:= TimeSinceUnix .CreatedUnix ctx.Locale}} - <div class="comment code-comment tw-pb-4" id="{{.HashTag}}"> - <div class="content"> + <div class="comment code-comment" id="{{.HashTag}}"> + <div class="content comment-container"> <div class="header comment-header"> <div class="comment-header-left tw-flex tw-items-center"> {{if not .OriginalAuthor}} @@ -82,7 +82,7 @@ <div class="comment-header-right actions tw-flex tw-items-center"> {{template "repo/issue/view_content/show_role" dict "ShowRole" .ShowRole}} {{if not $.Repository.IsArchived}} - {{template "repo/issue/view_content/add_reaction" dict "ctxData" $ "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID)}} + {{template "repo/issue/view_content/add_reaction" dict "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID)}} {{template "repo/issue/view_content/context_menu" dict "ctxData" $ "item" . "delete" true "issue" true "diff" true "IsCommentPoster" (and $.IsSigned (eq $.SignedUserID .PosterID))}} {{end}} </div> @@ -103,7 +103,7 @@ </div> {{$reactions := .Reactions.GroupByType}} {{if $reactions}} - {{template "repo/issue/view_content/reactions" dict "ctxData" $ "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID) "Reactions" $reactions}} + {{template "repo/issue/view_content/reactions" dict "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID) "Reactions" $reactions}} {{end}} </div> </div> diff --git a/templates/repo/issue/view_content/reactions.tmpl b/templates/repo/issue/view_content/reactions.tmpl index da6319667b..0011efe8b2 100644 --- a/templates/repo/issue/view_content/reactions.tmpl +++ b/templates/repo/issue/view_content/reactions.tmpl @@ -1,7 +1,7 @@ -<div class="ui attached segment reactions" data-action-url="{{$.ActionURL}}"> +<div class="bottom-reactions" data-action-url="{{$.ActionURL}}"> {{range $key, $value := .Reactions}} - {{$hasReacted := $value.HasUser $.ctxData.SignedUserID}} - <a role="button" class="ui label basic{{if $hasReacted}} primary{{end}}{{if not $.ctxData.IsSigned}} disabled{{end}} comment-reaction-button" + {{$hasReacted := $value.HasUser ctx.RootData.SignedUserID}} + <a role="button" class="ui label basic{{if $hasReacted}} primary{{end}}{{if not ctx.RootData.IsSigned}} disabled{{end}} comment-reaction-button" data-tooltip-content title="{{$value.GetFirstUsers}}{{if gt ($value.GetMoreUserCount) 0}} {{ctx.Locale.Tr "repo.reactions_more" $value.GetMoreUserCount}}{{end}}" aria-label="{{$value.GetFirstUsers}}{{if gt ($value.GetMoreUserCount) 0}} {{ctx.Locale.Tr "repo.reactions_more" $value.GetMoreUserCount}}{{end}}" @@ -12,6 +12,6 @@ </a> {{end}} {{if AllowedReactions}} - {{template "repo/issue/view_content/add_reaction" dict "ctxData" $.ctxData "ActionURL" .ActionURL}} + {{template "repo/issue/view_content/add_reaction" dict "ActionURL" .ActionURL}} {{end}} </div> diff --git a/web_src/css/base.css b/web_src/css/base.css index c6a22a5dc4..02067971a0 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -1366,8 +1366,7 @@ table th[data-sortt-desc] .svg { box-shadow: 0 0 0 1px var(--color-secondary) inset; } -.emoji, -.reaction { +.emoji { font-size: 1.25em; line-height: var(--line-height-default); font-style: normal !important; @@ -1375,8 +1374,7 @@ table th[data-sortt-desc] .svg { vertical-align: -0.075em; } -.emoji img, -.reaction img { +.emoji img { border-width: 0 !important; margin: 0 !important; width: 1em !important; diff --git a/web_src/css/index.css b/web_src/css/index.css index ad59f32636..73e10eedcb 100644 --- a/web_src/css/index.css +++ b/web_src/css/index.css @@ -62,6 +62,7 @@ @import "./repo/linebutton.css"; @import "./repo/wiki.css"; @import "./repo/header.css"; +@import "./repo/reactions.css"; @import "./editor/fileeditor.css"; @import "./editor/combomarkdowneditor.css"; diff --git a/web_src/css/modules/comment.css b/web_src/css/modules/comment.css index 799eeb8574..cf080db225 100644 --- a/web_src/css/modules/comment.css +++ b/web_src/css/modules/comment.css @@ -16,7 +16,7 @@ .ui.comments .comment { position: relative; background: none; - margin: 0.5em 0 0; + margin: 3px 0 0; padding: 0.5em 0 0; border: none; border-top: none; diff --git a/web_src/css/repo.css b/web_src/css/repo.css index edb3bc2e87..4b7ad49677 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -913,6 +913,9 @@ td .commit-summary { .repository.view.issue .comment-list .ui.comments { max-width: 100%; + display: flex; + flex-direction: column; + gap: 3px; } .repository.view.issue .comment-list .comment > .content > div:first-child { @@ -928,6 +931,11 @@ td .commit-summary { .repository.view.issue .comment-list .comment .comment-container { border: 1px solid var(--color-secondary); border-radius: var(--border-radius); + background: var(--color-box-body); +} + +.repository.view.issue .comment-list .conversation-holder .comment .comment-container { + border: none; } @media (max-width: 767.98px) { @@ -1042,30 +1050,6 @@ td .commit-summary { margin-left: 42px; } -.repository.view.issue .comment-list .comment-code-cloud .segment.reactions { - margin-top: 16px !important; - margin-bottom: -8px !important; - border-top: none !important; -} - -.repository.view.issue .comment-list .comment-code-cloud .segment.reactions .ui.label { - border: 1px solid; - padding: 5px 8px !important; - margin: 0 2px; - border-radius: var(--border-radius); - border-color: var(--color-secondary-dark-1) !important; -} - -.repository.view.issue .comment-list .comment-code-cloud .segment.reactions .ui.label.basic.primary { - background-color: var(--color-reaction-active-bg) !important; - border-color: var(--color-primary-alpha-80) !important; -} - -.repository.view.issue .comment-list .comment-code-cloud .segment.reactions .ui.label.basic.primary:hover { - background-color: var(--color-reaction-hover-bg) !important; - border-color: var(--color-primary-alpha-80) !important; -} - .repository.view.issue .comment-list .comment-code-cloud button.comment-form-reply { margin: 0; } @@ -1902,98 +1886,6 @@ td .commit-summary { border-bottom: 1px solid var(--color-warning-border); } -.repository .segment.reactions.dropdown .menu, -.repository .select-reaction.dropdown .menu { - right: 0 !important; - left: auto !important; - min-width: 170px; -} - -.repository .segment.reactions.dropdown .menu > .header, -.repository .select-reaction.dropdown .menu > .header { - margin: 0.75rem 0 0.5rem; -} - -.repository .segment.reactions.dropdown .menu > .item, -.repository .select-reaction.dropdown .menu > .item { - float: left; - margin: 4px; - font-size: 20px; - width: 34px; - height: 34px; - min-height: 0 !important; - border-radius: var(--border-radius); - display: flex !important; - align-items: center; - justify-content: center; -} - -.repository .segment.reactions { - padding: 0; - display: flex; - border: none !important; - border-top: 1px solid var(--color-secondary) !important; - width: 100% !important; - max-width: 100% !important; - margin: 0 !important; - border-radius: 0 0 var(--border-radius) var(--border-radius); -} - -.repository .segment.reactions .ui.label { - max-height: 40px; - padding: 8px 16px !important; - display: flex !important; - align-items: center; - border: 0; - border-right: 1px solid; - border-radius: 0; - margin: 0; - font-size: 12px; - font-weight: var(--font-weight-normal); - border-color: var(--color-secondary) !important; - background: var(--color-reaction-bg); -} - -.repository .segment.reactions .ui.label:first-of-type { - border-bottom-left-radius: 3px; -} - -.repository .segment.reactions .ui.label.disabled { - cursor: default; - opacity: 1; -} - -.repository .segment.reactions .ui.label.basic.primary { - color: var(--color-primary) !important; - background-color: var(--color-reaction-active-bg) !important; - border-color: var(--color-secondary-dark-1) !important; -} - -.repository .segment.reactions .ui.label.basic:hover { - background-color: var(--color-reaction-hover-bg) !important; -} - -.repository .segment.reactions .reaction-count { - margin-left: 0.5rem; -} - -.repository .segment.reactions .select-reaction { - display: flex; - align-items: center; -} - -.repository .segment.reactions .select-reaction a { - padding: 0 14px; -} - -.repository .segment.reactions .select-reaction:not(.active) a { - display: none; -} - -.repository .segment.reactions:hover .select-reaction a { - display: block; -} - .repository .ui.fluid.action.input .ui.search.action.input { flex: auto; } diff --git a/web_src/css/repo/reactions.css b/web_src/css/repo/reactions.css new file mode 100644 index 0000000000..8fe01af4f0 --- /dev/null +++ b/web_src/css/repo/reactions.css @@ -0,0 +1,70 @@ +.bottom-reactions { + display: flex; + gap: 6px; + margin: 0 1em 1em; +} + +.timeline-item .conversation-holder .bottom-reactions { + margin: 1em 0 0 36px; + padding-bottom: 8px; +} + +.bottom-reactions .ui.label { + padding: 5px 8px; + font-weight: var(--font-weight-normal); +} + +.bottom-reactions .ui.label.primary { + background-color: var(--color-reaction-active-bg) !important; +} + +.bottom-reactions .ui.label:hover { + background-color: var(--color-reaction-hover-bg) !important; +} + +.bottom-reactions .ui.label.disabled { + cursor: default; + opacity: 1; +} + +.bottom-reactions .ui.label .reaction { + font-size: 16px; + display: flex; +} + +.bottom-reactions .ui.label .reaction img { + height: 16px; + aspect-ratio: 1; +} + +.bottom-reactions .reaction-count { + margin-left: 4px; +} + +.ui.dropdown.select-reaction .menu { + min-width: 170px; /* item-outer-width * 4 */ +} + +.ui.dropdown.select-reaction .menu > .item { + float: left; + margin: 4px; + font-size: 20px; + width: 34px; + height: 34px; + border-radius: var(--border-radius); + display: flex; + align-items: center; + justify-content: center; +} + +.bottom-reactions .select-reaction { + padding: 0 10px; +} + +.bottom-reactions .select-reaction:not(.active) { + visibility: hidden; +} + +.bottom-reactions:hover .select-reaction { + visibility: visible; +} diff --git a/web_src/js/features/comp/ReactionSelector.js b/web_src/js/features/comp/ReactionSelector.js index 2def3db51a..e507b89632 100644 --- a/web_src/js/features/comp/ReactionSelector.js +++ b/web_src/js/features/comp/ReactionSelector.js @@ -1,38 +1,36 @@ import $ from 'jquery'; import {POST} from '../../modules/fetch.js'; -export function initCompReactionSelector($parent) { - $parent.find(`.select-reaction .item.reaction, .comment-reaction-button`).on('click', async function (e) { - e.preventDefault(); +export function initCompReactionSelector() { + for (const container of document.querySelectorAll('.issue-content, .diff-file-body')) { + container.addEventListener('click', async (e) => { + // there are 2 places for the "reaction" buttons, one is the top-right reaction menu, one is the bottom of the comment + const target = e.target.closest('.comment-reaction-button'); + if (!target) return; + e.preventDefault(); - if (this.classList.contains('disabled')) return; + if (target.classList.contains('disabled')) return; - const actionUrl = this.closest('[data-action-url]')?.getAttribute('data-action-url'); - const reactionContent = this.getAttribute('data-reaction-content'); - const hasReacted = this.closest('.ui.segment.reactions')?.querySelector(`a[data-reaction-content="${reactionContent}"]`)?.getAttribute('data-has-reacted') === 'true'; + const actionUrl = target.closest('[data-action-url]').getAttribute('data-action-url'); + const reactionContent = target.getAttribute('data-reaction-content'); - const res = await POST(`${actionUrl}/${hasReacted ? 'unreact' : 'react'}`, { - data: new URLSearchParams({content: reactionContent}), + const commentContainer = target.closest('.comment-container'); + + const bottomReactions = commentContainer.querySelector('.bottom-reactions'); // may not exist if there is no reaction + const bottomReactionBtn = bottomReactions?.querySelector(`a[data-reaction-content="${CSS.escape(reactionContent)}"]`); + const hasReacted = bottomReactionBtn?.getAttribute('data-has-reacted') === 'true'; + + const res = await POST(`${actionUrl}/${hasReacted ? 'unreact' : 'react'}`, { + data: new URLSearchParams({content: reactionContent}), + }); + + const data = await res.json(); + bottomReactions?.remove(); + if (data.html) { + commentContainer.insertAdjacentHTML('beforeend', data.html); + const bottomReactionsDropdowns = commentContainer.querySelectorAll('.bottom-reactions .dropdown.select-reaction'); + $(bottomReactionsDropdowns).dropdown(); // re-init the dropdown + } }); - - const data = await res.json(); - if (data && (data.html || data.empty)) { - const $content = $(this).closest('.content'); - let $react = $content.find('.segment.reactions'); - if ((!data.empty || data.html === '') && $react.length > 0) { - $react.remove(); - } - if (!data.empty) { - const $attachments = $content.find('.segment.bottom:first'); - $react = $(data.html); - if ($attachments.length > 0) { - $react.insertBefore($attachments); - } else { - $react.appendTo($content); - } - $react.find('.dropdown').dropdown(); - initCompReactionSelector($react); - } - } - }); + } } diff --git a/web_src/js/features/repo-diff.js b/web_src/js/features/repo-diff.js index b2e8ec4866..00f74515df 100644 --- a/web_src/js/features/repo-diff.js +++ b/web_src/js/features/repo-diff.js @@ -87,7 +87,6 @@ function initRepoDiffConversationForm() { el.classList.add('tw-invisible'); } $newConversationHolder.find('.dropdown').dropdown(); - initCompReactionSelector($newConversationHolder); } catch (error) { console.error('Error:', error); showErrorToast(i18n.network_error); diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index e83de27e4c..18d98c891d 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -393,7 +393,7 @@ export function initRepository() { initRepoIssueDependencyDelete(); initRepoIssueCodeCommentCancel(); initRepoPullRequestUpdate(); - initCompReactionSelector($(document)); + initCompReactionSelector(); initRepoPullRequestMergeForm(); initRepoPullRequestCommitStatus(); From 044cc169e75dccbf1d846f8774ef2feccd0da1fd Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 14 Apr 2024 13:39:11 +0200 Subject: [PATCH 109/370] Use `flex-container` for dashboard layout (#30214) Added new class `flex-container-sidebar` to cover the dashboard sidebar. Previously this was 37.5% with more padding. Now there is less empty space between the two columns and this matches other pages like repo or admin settings page. Desktop: <img width="1345" alt="Screenshot 2024-03-31 at 15 11 36" src="https://github.com/go-gitea/gitea/assets/115237/717389d9-d42c-466e-a8fe-e968f79447fd"> Mobile: <img width="444" alt="Screenshot 2024-03-31 at 15 11 44" src="https://github.com/go-gitea/gitea/assets/115237/7faa840b-513a-411b-bf2d-26d52b9b71a0"> --------- Co-authored-by: Giteabot <teabot@gitea.io> --- templates/user/dashboard/dashboard.tmpl | 12 +++++------- templates/user/dashboard/repolist.tmpl | 2 +- web_src/css/modules/flexcontainer.css | 10 +++++++++- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/templates/user/dashboard/dashboard.tmpl b/templates/user/dashboard/dashboard.tmpl index d4553ea61b..030fd49940 100644 --- a/templates/user/dashboard/dashboard.tmpl +++ b/templates/user/dashboard/dashboard.tmpl @@ -1,15 +1,13 @@ {{template "base/head" .}} <div role="main" aria-label="{{.Title}}" class="page-content dashboard feeds"> {{template "user/dashboard/navbar" .}} - <div class="ui container"> + <div class="ui container flex-container"> {{template "base/alert" .}} - <div class="ui mobile reversed stackable grid"> - <div class="ui container ten wide column"> - {{template "user/heatmap" .}} - {{template "user/dashboard/feeds" .}} - </div> - {{template "user/dashboard/repolist" .}} + <div class="flex-container-main"> + {{template "user/heatmap" .}} + {{template "user/dashboard/feeds" .}} </div> + {{template "user/dashboard/repolist" .}} </div> </div> {{template "base/footer" .}} diff --git a/templates/user/dashboard/repolist.tmpl b/templates/user/dashboard/repolist.tmpl index a879f1fb9d..be710675d5 100644 --- a/templates/user/dashboard/repolist.tmpl +++ b/templates/user/dashboard/repolist.tmpl @@ -56,4 +56,4 @@ data.organizationId = {{.ContextUser.ID}}; window.config.pageData.dashboardRepoList = data; </script> -<div id="dashboard-repo-list" class="six wide column"></div> +<div id="dashboard-repo-list" class="flex-container-sidebar"></div> diff --git a/web_src/css/modules/flexcontainer.css b/web_src/css/modules/flexcontainer.css index 1ca513687f..5d4e12cc12 100644 --- a/web_src/css/modules/flexcontainer.css +++ b/web_src/css/modules/flexcontainer.css @@ -6,10 +6,16 @@ margin-top: var(--page-spacing); } +/* small options menu on the left, used in settings/admin pages */ .flex-container-nav { width: 240px; } +/* wide sidebar on the right, used in frontpage */ +.flex-container-sidebar { + width: 35%; +} + .flex-container-main { flex: 1; min-width: 0; /* make the "text truncate" work, otherwise the flex axis is not limited and the text just overflows */ @@ -19,7 +25,9 @@ .flex-container { flex-direction: column; } - .flex-container-nav { + .flex-container-nav, + .flex-container-sidebar { + order: -1; width: auto; } } From f3267548abfd4deda1aaeb4b336df6cd4b0e1d70 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 14 Apr 2024 13:43:46 +0200 Subject: [PATCH 110/370] Remove fomantic menu module (#30325) A lot of variants are in use, so the diff stat isn't so great. Co-authored-by: Giteabot <teabot@gitea.io> --- web_src/css/base.css | 186 +-- web_src/css/index.css | 1 + web_src/css/modules/menu.css | 802 +++++++++++ web_src/css/repo.css | 5 - web_src/fomantic/build/semantic.css | 2010 --------------------------- web_src/fomantic/semantic.json | 1 - 6 files changed, 804 insertions(+), 2201 deletions(-) create mode 100644 web_src/css/modules/menu.css diff --git a/web_src/css/base.css b/web_src/css/base.css index 02067971a0..20f3616177 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -319,27 +319,6 @@ a.label, background-color: var(--color-label-bg); } -.ui.menu { - display: flex; -} - -.ui.menu, -.ui.vertical.menu { - background: var(--color-menu); - border-color: var(--color-secondary); - box-shadow: none; -} - -.ui.menu .item { - color: var(--color-text); - user-select: auto; - line-height: var(--line-height-default); /* fomantic uses "1" which causes overflow problems because "1" doesn't consider the descent part */ -} - -.ui.menu .item > .svg { - margin-right: 0.35em; -} - .ui.menu .dropdown.item:hover, .ui.menu a.item:hover, .ui.menu details.item summary:hover { @@ -347,42 +326,6 @@ a.label, background: var(--color-hover); } -.ui.menu .active.item, -.ui.menu .active.item:hover, -.ui.vertical.menu .active.item, -.ui.vertical.menu .active.item:hover { - color: var(--color-text); - background: var(--color-active); -} - -.ui.menu a.item:active { - color: var(--color-text); - background: none; -} - -.ui.ui.menu .item.disabled { - color: var(--color-text-light-3); -} - -.ui.menu .item::before, .ui.vertical.menu .item::before { - background: var(--color-secondary); -} - -/* sub menu of vertical menu */ -.ui.vertical.menu .item .menu .item { - color: var(--color-text-light-2); - text-indent: 16px; -} - -.ui.vertical.menu .item .menu .item:hover, -.ui.vertical.menu .item .menu a.item:hover { - color: var(--color-text-light-1); -} - -.ui.vertical.menu .item .menu .active.item { - color: var(--color-text); -} - /* slightly more contrast for filters on issue list */ .ui.ui.menu .dropdown.item.disabled { color: var(--color-text-light-2); @@ -441,11 +384,6 @@ a.label, background: var(--color-hover); } -.ui.menu .ui.dropdown .menu > .selected.item { - color: var(--color-text) !important; - background: var(--color-hover) !important; -} - .ui.dropdown .menu > .message:not(.ui) { color: var(--color-text-light-2); } @@ -462,58 +400,6 @@ a.label, color: var(--color-text-light-2); } -/* replace item margin on secondary menu items with gap and remove both the - negative margins on the menu as well as margin on the items */ -.ui.secondary.menu { - margin-left: 0; - margin-right: 0; - gap: .35714286em; -} -.ui.secondary.menu .item { - margin-left: 0; - margin-right: 0; -} - -.ui.secondary.menu .dropdown.item:hover, -.ui.secondary.menu a.item:hover { - color: var(--color-text); - background: var(--color-hover); -} - -.ui.secondary.menu .active.item, -.ui.secondary.menu .active.item:hover { - color: var(--color-text); - background: var(--color-active); -} - -.ui.secondary.menu.tight .item { - padding-left: 0.85714286em; - padding-right: 0.85714286em; -} - -/* remove the menu clearfix so that it won't add undesired gaps when using "gap" */ -.ui.menu::after { - content: normal; -} - -.ui.menu .dropdown.item .menu { - background: var(--color-body); -} - -.ui.menu .ui.dropdown .menu > .item { - color: var(--color-text) !important; -} - -.ui.menu .ui.dropdown .menu > .item:hover { - color: var(--color-text) !important; - background: var(--color-hover) !important; -} - -.ui.menu .ui.dropdown .menu > .active.item { - color: var(--color-text) !important; - background: var(--color-active) !important; -} - .ui.form textarea:not([rows]) { height: var(--min-height-textarea); /* override fomantic default 12em */ min-height: var(--min-height-textarea); /* override fomantic default 8em */ @@ -606,11 +492,6 @@ img.ui.avatar, margin-top: calc(var(--page-spacing) - 1rem); } -.ui.pagination.menu .active.item { - color: var(--color-text); - background: var(--color-active); -} - .ui.form .fields.error .field textarea, .ui.form .fields.error .field select, .ui.form .fields.error .field input:not([type]), @@ -786,7 +667,7 @@ input:-webkit-autofill:active, font-weight: var(--font-weight-normal); } -/* replace fomantic popover box shadows */ +/* popover box shadows */ .ui.dropdown .menu, .ui.upward.dropdown > .menu, .ui.menu .dropdown.item .menu, @@ -804,22 +685,6 @@ input:-webkit-autofill:active, background: var(--color-overlay-backdrop); } -/* Override semantic selector '.ui.menu:not(.vertical) .item > .button' */ -/* This fixes the commit graph button on the commits page */ -/* modal svg icons, copied from fomantic except width and height */ -/* center text in fomantic modal dialogs */ -.ui .menu:not(.vertical) .item > .button.compact { - padding: 0.58928571em 1.125em; -} - -.ui .menu:not(.vertical) .item > .button.small { - font-size: 0.92857143rem; -} - -.ui.menu .ui.dropdown.item .menu .item { - width: 100%; -} - .ui.dropdown .menu > .header { font-size: 0.8em; } @@ -1010,24 +875,6 @@ input:-webkit-autofill:active, border-color: var(--color-gold) !important; } -@media (max-width: 767.98px) { - .ui.pagination.menu .item:not(.active,.navigation), - .ui.pagination.menu .item.navigation span.navigation_label { - display: none; - } -} - -.ui.pagination.menu.narrow .item { - padding-left: 8px; - padding-right: 8px; - min-width: 1em; - text-align: center; -} - -.ui.pagination.menu.narrow .item .icon { - margin-right: 0; -} - .ui.floating.dropdown .overflow.menu .scrolling.menu.items { border-radius: 0 !important; box-shadow: none !important; @@ -1149,11 +996,6 @@ overflow-menu .ui.label { margin-top: 1px; } -.ui.menu .item > .label { - background: var(--color-label-bg); - color: var(--color-label-text); -} - .lines-blame-btn { padding: 0 0 0 5px; display: flex; @@ -1382,26 +1224,6 @@ table th[data-sortt-desc] .svg { vertical-align: -0.15em; } -.ui.tabular.menu { - border-color: var(--color-secondary); -} - -.ui.tabular.menu .active.item, -.ui.tabular.menu .active.item:hover { - background: var(--color-body); - border-color: var(--color-secondary); - color: var(--color-text); -} - -.ui.segment .ui.tabular.menu .active.item, -.ui.segment .ui.tabular.menu .active.item:hover { - background: var(--color-box-body); -} - -.ui.secondary.pointing.menu { - border-color: var(--color-secondary); -} - .ui.tabular.menu .item, .ui.secondary.pointing.menu .item { padding: 11.55px 12px !important; /* match .dashboard-navbar in height */ @@ -1413,12 +1235,6 @@ table th[data-sortt-desc] .svg { color: var(--color-text); } -.ui.secondary.pointing.menu .active.item, -.ui.secondary.pointing.menu .active.item:hover, -.ui.secondary.pointing.menu .dropdown.item:hover { - color: var(--color-text-dark); -} - .ui.tabular.menu .active.item, .ui.secondary.pointing.menu .active.item, .resize-for-semibold::before { diff --git a/web_src/css/index.css b/web_src/css/index.css index 73e10eedcb..edd6cdca8b 100644 --- a/web_src/css/index.css +++ b/web_src/css/index.css @@ -11,6 +11,7 @@ @import "./modules/list.css"; @import "./modules/segment.css"; @import "./modules/grid.css"; +@import "./modules/menu.css"; @import "./modules/message.css"; @import "./modules/table.css"; @import "./modules/card.css"; diff --git a/web_src/css/modules/menu.css b/web_src/css/modules/menu.css new file mode 100644 index 0000000000..2581d8fab2 --- /dev/null +++ b/web_src/css/modules/menu.css @@ -0,0 +1,802 @@ +.ui.menu { + display: flex; + margin: 1rem 0; + font-family: var(--fonts-regular); + font-weight: var(--font-weight-normal); + background: var(--color-menu); + border: 1px solid var(--color-secondary); + border-radius: 0.28571429rem; + min-height: 2.85714286em; + font-size: 1rem; +} +.ui.menu:first-child { + margin-top: 0; +} +.ui.menu:last-child { + margin-bottom: 0; +} + +.ui.menu .menu { + margin: 0; +} +.ui.menu:not(.vertical) > .menu { + display: flex; +} + +.ui.menu:not(.vertical) .item { + display: flex; + align-items: center; +} + +.ui.menu .item { + position: relative; + vertical-align: middle; + line-height: var(--line-height-default); + text-decoration: none; + flex: 0 0 auto; + background: none; + padding: 0.92857143em 1.14285714em; + color: var(--color-text); + font-weight: var(--font-weight-normal); +} +.ui.menu > .item:first-child { + border-radius: 0.28571429rem 0 0 0.28571429rem; +} + +.ui.menu .item::before { + position: absolute; + content: ""; + top: 0; + right: 0; + height: 100%; + width: 1px; + background: var(--color-secondary); +} + +.ui.menu .item > .svg { + margin-right: 0.35em; +} + +.ui.menu .item > a:not(.ui), +.ui.menu .item > p:only-child { + line-height: 1.3; +} +.ui.menu .item > p:first-child { + margin-top: 0; +} +.ui.menu .item > p:last-child { + margin-bottom: 0; +} + +.ui.menu .item > i.icon { + opacity: 0.9; + float: none; + margin: 0 0.35714286em 0 0; +} + +.ui.menu:not(.vertical) .item > .button { + position: relative; + top: 0; + margin: -0.5em 0; + padding: 0.58928571em 1.125em; + font-size: 1em; +} + +.ui.menu > .grid, +.ui.menu > .container { + display: flex; + align-items: inherit; + flex-direction: inherit; +} + +.ui.menu .item > .input { + width: 100%; +} +.ui.menu:not(.vertical) .item > .input { + position: relative; + top: 0; + margin: -0.5em 0; +} +.ui.menu .item > .input input { + font-size: 1em; + padding-top: 0.57142857em; + padding-bottom: 0.57142857em; +} + +.ui.menu .header.item, +.ui.vertical.menu .header.item { + margin: 0; + font-size: 1.1em; + background: var(--color-box-header); + font-weight: var(--font-weight-medium); +} +.ui.vertical.menu .item > .header:not(.ui) { + margin: 0 0 0.5em; + font-size: 1em; + font-weight: var(--font-weight-medium); +} + +.ui.menu .item > i.dropdown.icon { + padding: 0; + float: right; + margin: 0 0 0 1em; +} + +.ui.menu .dropdown.item .menu { + min-width: calc(100% - 1px); + border-radius: 0 0 0.28571429rem 0.28571429rem; + background: var(--color-body); + margin: 0; + flex-direction: column !important; +} + +.ui.menu .ui.dropdown .menu > .item { + margin: 0; + text-align: left; + font-size: 1em !important; + padding: 0.78571429em 1.14285714em !important; + background: transparent !important; + color: var(--color-text) !important; + font-weight: var(--font-weight-normal) !important; +} +.ui.menu .ui.dropdown .menu > .item:hover { + color: var(--color-text) !important; + background: var(--color-hover) !important; +} +.ui.menu .ui.dropdown .menu > .selected.item { + color: var(--color-text) !important; + background: var(--color-hover) !important; +} +.ui.menu .ui.dropdown .menu > .active.item { + color: var(--color-text) !important; + background: var(--color-active) !important; + font-weight: var(--font-weight-medium) !important; +} + +.ui.menu .ui.dropdown.item .menu .item { + width: 100%; +} + +.ui.menu .ui.dropdown.item .menu .item:not(.filtered) { + display: block; +} +.ui.menu .ui.dropdown .menu > .item > i.icon:not(.dropdown) { + display: inline-block; + font-size: 1em !important; + float: none; + margin: 0 0.75em 0 0 !important; +} + +.ui.secondary.menu .dropdown.item > .menu { + border-radius: 0.28571429rem; + margin-top: 0.35714286em; +} + +.ui.menu .pointing.dropdown.item .menu { + margin-top: 0.75em; +} + +.ui.menu .item > .label:not(.floating) { + margin-left: 1em; + padding: 0.3em 0.78571429em; +} +.ui.vertical.menu .item > .label { + margin-top: -0.15em; + margin-bottom: -0.15em; + padding: 0.3em 0.78571429em; + float: right; + text-align: center; +} +.ui.menu .item > .floating.label { + padding: 0.3em 0.78571429em; +} +.ui.menu .item > .label { + background: var(--color-label-bg); + color: var(--color-label-text); +} +.ui.menu .item > .image.label img { + margin: -0.2833em 0.8em -0.2833em -0.8em; + height: 1.5666em; +} + +.ui.menu .item > img:not(.ui) { + display: inline-block; + vertical-align: middle; + margin: -0.3em 0; + width: 2.5em; +} +.ui.vertical.menu .item > img:not(.ui):only-child { + display: block; + max-width: 100%; + width: auto; +} + +.ui.menu .list .item::before { + background: none !important; +} + +@media only screen and (max-width: 767.98px) { + .ui.menu > .ui.container { + width: 100% !important; + margin-left: 0 !important; + margin-right: 0 !important; + } +} + +.ui.menu .dropdown.item:hover, +.ui.menu a.item:hover { + cursor: pointer; +} + +.ui.menu a.item:active { + color: var(--color-text); + background: none; +} + +.ui.menu .active.item { + color: var(--color-text); + background: var(--color-active); + font-weight: var(--font-weight-normal); +} +.ui.menu .active.item > i.icon { + opacity: 1; +} + +.ui.ui.menu .item.disabled { + cursor: default; + background-color: transparent; + pointer-events: none; + opacity: var(--opacity-disabled); +} + +.ui.menu:not(.vertical) .left.item, +.ui.menu:not(.vertical) .left.menu { + display: flex; + margin-right: auto !important; +} + +.ui.menu:not(.vertical) .right.item, +.ui.menu:not(.vertical) .right.menu { + display: flex; + margin-left: auto !important; +} +.ui.menu:not(.vertical) :not(.dropdown) > .left.menu, +.ui.menu:not(.vertical) :not(.dropdown) > .right.menu { + display: inherit; +} + +.ui.menu:not(.vertical) .center.item { + display: flex; + margin-left: auto !important; + margin-right: auto !important; +} + +.ui.menu .right.item::before, +.ui.menu .right.menu > .item::before { + right: auto; + left: 0; +} + +.ui.menu .center.item:last-child::before { + display: none; +} + +.ui.vertical.menu { + display: block; + flex-direction: column; + background: var(--color-menu); + width: 15rem; +} + +.ui.vertical.menu .item { + display: block; + background: none; + border-top: none; + border-right: none; +} +.ui.vertical.menu > .item:first-child { + border-radius: 0.28571429rem 0.28571429rem 0 0; +} +.ui.vertical.menu > .item:last-child { + border-radius: 0 0 0.28571429rem 0.28571429rem; +} + +.ui.vertical.menu .item > i.icon { + width: 1.18em; + float: right; + margin: 0 0 0 0.5em; +} +.ui.vertical.menu .item > .label + i.icon { + float: none; + margin: 0 0.5em 0 0; +} + +.ui.vertical.menu .item::before { + position: absolute; + content: ""; + top: 0; + left: 0; + width: 100%; + height: 1px; + background: var(--color-secondary); +} +.ui.vertical.menu .item:first-child::before { + display: none !important; +} + +.ui.vertical.menu .item > .menu { + margin: 0.5em -1.14285714em 0; +} +.ui.vertical.menu .menu .item { + background: none; + padding: 0.5em 1.33333333em; + font-size: 0.85714286em; + color: var(--color-text-light-2); +} + +.ui.vertical.menu .item .menu .item { + color: var(--color-text-light-2); + text-indent: 16px; +} + +.ui.vertical.menu .item .menu .item:hover, +.ui.vertical.menu .item .menu a.item:hover { + color: var(--color-text-light-1); +} + +.ui.vertical.menu .item .menu .active.item { + background-color: transparent; + font-weight: var(--font-weight-medium); + color: var(--color-text); +} + +.ui.vertical.menu .item .menu a.item:hover { + color: var(--color-text); +} +.ui.vertical.menu .menu .item::before { + display: none; +} + +.ui.vertical.menu .active.item { + border-radius: 0; +} +.ui.vertical.menu > .active.item:first-child { + border-radius: 0.28571429rem 0.28571429rem 0 0; +} +.ui.vertical.menu > .active.item:last-child { + border-radius: 0 0 0.28571429rem 0.28571429rem; +} +.ui.vertical.menu > .active.item:only-child { + border-radius: 0.28571429rem; +} +.ui.vertical.menu .active.item .menu .active.item { + border-left: none; +} + +.ui.tabular.menu { + border-radius: 0; + border: none; + background: none transparent; + border-bottom: 1px solid var(--color-secondary); +} +.ui.tabular.fluid.menu { + width: calc(100% + 2px) !important; +} +.ui.tabular.menu .item { + background: transparent; + border-bottom: none; + border-left: 1px solid transparent; + border-right: 1px solid transparent; + border-top: 2px solid transparent; + color: var(--color-text-light-2); +} +.ui.tabular.menu .item::before { + display: none; +} + +.ui.tabular.menu .item:hover { + background-color: transparent; +} + +.ui.tabular.menu .active.item, +.ui.tabular.menu .active.item:hover { + background: var(--color-body); + border-top-width: 1px; + border-color: var(--color-secondary); + font-weight: var(--font-weight-medium); + margin-bottom: -1px; + border-radius: 0.28571429rem 0.28571429rem 0 0 !important; +} + +.ui.tabular.menu + .attached:not(.top).segment, +.ui.tabular.menu + .attached:not(.top).segment + .attached:not(.top).segment { + border-top: none; + margin-left: 0; + margin-top: 0; + margin-right: 0; + width: 100%; +} + +.ui.tabular.menu .active.dropdown.item { + margin-bottom: 0; + border-left: 1px solid transparent; + border-right: 1px solid transparent; + border-top: 2px solid transparent; + border-bottom: none; +} + +.ui.pagination.menu { + margin: 0; + display: inline-flex; + vertical-align: middle; +} +.ui.pagination.menu .item:last-child { + border-radius: 0 0.28571429rem 0.28571429rem 0; +} +.ui.compact.menu .item:last-child { + border-radius: 0 0.28571429rem 0.28571429rem 0; +} +.ui.pagination.menu .item:last-child::before { + display: none; +} +.ui.pagination.menu .item { + min-width: 3em; + text-align: center; +} +.ui.pagination.menu .icon.item i.icon { + vertical-align: top; +} + +.ui.pagination.menu .active.item, +.ui.pagination.menu .active.item:hover { + border-top: none; + padding-top: 0.92857143em; + color: var(--color-text); + background: var(--color-active); +} + +@media (max-width: 767.98px) { + .ui.pagination.menu .item:not(.active,.navigation), + .ui.pagination.menu .item.navigation span.navigation_label { + display: none; + } +} + +.ui.pagination.menu.narrow .item { + padding-left: 8px; + padding-right: 8px; + min-width: 1em; + text-align: center; +} + +.ui.pagination.menu.narrow .item .icon { + margin-right: 0; +} + +.ui.secondary.menu { + background: none; + margin-left: 0; + margin-right: 0; + gap: .35714286em; + border-radius: 0; + border: none; +} + +.ui.secondary.menu .item { + align-self: center; + border: none; + padding: 0.78571429em 0.92857143em; + margin: 0; + background: none; + border-radius: 0.28571429rem; +} + +.ui.secondary.menu .item::before { + display: none !important; +} + +.ui.secondary.menu .header.item { + border-radius: 0; + border-right: none; + background: none transparent; +} + +.ui.secondary.menu .item > img:not(.ui) { + margin: 0; +} + +.ui.secondary.menu .dropdown.item:hover, +.ui.secondary.menu a.item:hover { + color: var(--color-text); + background: var(--color-hover); +} + +.ui.secondary.menu .active.item, +.ui.secondary.menu .active.item:hover { + color: var(--color-text-dark); + background: var(--color-active); + border-radius: 0.28571429rem; +} + +.ui.secondary.item.menu { + margin-left: 0; + margin-right: 0; +} +.ui.secondary.item.menu .item:last-child { + margin-right: 0; +} + +.ui.vertical.secondary.menu .item:not(.dropdown) > .menu { + margin: 0 -0.92857143em; +} +.ui.vertical.secondary.menu .item:not(.dropdown) > .menu > .item { + margin: 0; + padding: 0.5em 1.33333333em; +} +.ui.secondary.vertical.menu > .item { + border: none; + margin: 0 0 0.35714286em; + border-radius: 0.28571429rem !important; +} +.ui.secondary.vertical.menu > .header.item { + border-radius: 0; +} + +.ui.vertical.secondary.menu .item > .menu .item { + background-color: transparent; +} + +.ui.secondary.pointing.menu { + margin-left: 0; + margin-right: 0; + border-bottom: 2px solid var(--color-secondary); +} +.ui.secondary.pointing.menu .item { + border-bottom-color: transparent; + border-bottom-style: solid; + border-radius: 0; + align-self: flex-end; + margin: 0 0 -2px; + padding: 0.85714286em 1.14285714em; + border-bottom-width: 2px; +} +.ui.secondary.pointing.menu .ui.dropdown .menu .item { + border-bottom-width: 0; +} +.ui.secondary.pointing.menu .item > .label:not(.floating) { + margin-top: -0.3em; + margin-bottom: -0.3em; +} +.ui.secondary.pointing.menu .item > .circular.label { + margin-top: -0.5em; + margin-bottom: -0.5em; +} + +.ui.secondary.pointing.menu .header.item { + color: var(--color-text) !important; +} +.ui.secondary.pointing.menu .item::after { + display: none; +} + +.ui.secondary.pointing.menu .dropdown.item:hover, +.ui.secondary.pointing.menu a.item:hover { + background-color: transparent; + color: var(--color-text); +} + +.ui.secondary.pointing.menu .dropdown.item:active, +.ui.secondary.pointing.menu a.item:active { + background-color: transparent; + border-color: var(--color-secondary); +} + +.ui.secondary.pointing.menu .active.item { + background-color: transparent; + border-color: currentcolor; + font-weight: var(--font-weight-medium); +} + +.ui.secondary.pointing.menu .active.item, +.ui.secondary.pointing.menu .active.item:hover, +.ui.secondary.pointing.menu .dropdown.item:hover { + color: var(--color-text-dark); +} + +.ui.secondary.pointing.menu .active.dropdown.item { + border-color: transparent; +} + +@media only screen and (max-width: 767.98px) { + .ui.stackable.menu { + flex-direction: column; + } + .ui.stackable.menu .item { + width: 100% !important; + } + .ui.stackable.menu .left.menu, + .ui.stackable.menu .left.item { + margin-right: 0 !important; + } + .ui.stackable.menu .right.menu, + .ui.stackable.menu .right.item { + margin-left: 0 !important; + } + .ui.stackable.menu .center.item { + margin-left: 0 !important; + margin-right: 0 !important; + } + .ui.stackable.menu .right.menu, + .ui.stackable.menu .left.menu { + flex-direction: column; + } +} + +.ui.floated.menu { + float: left; + margin: 0 0.5rem 0 0; +} +.ui.floated.menu .item:last-child::before { + display: none; +} +.ui.right.floated.menu { + float: right; + margin: 0 0 0 0.5rem; +} + +.ui.borderless.menu .item::before, +.ui.borderless.menu .item .menu .item::before, +.ui.menu .borderless.item::before { + background: none !important; +} + +.ui.compact.menu { + display: inline-flex; + margin: 0; + vertical-align: middle; +} +.ui.compact.vertical.menu { + display: inline-block; + width: auto !important; +} +.ui.compact.menu:not(.secondary) .item:last-child { + border-radius: 0 0.28571429rem 0.28571429rem 0; +} +.ui.compact.menu .item:last-child::before { + display: none; +} +.ui.compact.vertical.menu .item:last-child::before { + display: block; +} + +.ui.menu.fluid, +.ui.vertical.menu.fluid { + width: 100% !important; +} + +.ui.item.menu, +.ui.item.menu .item { + width: 100%; + padding-left: 0 !important; + padding-right: 0 !important; + margin-left: 0 !important; + margin-right: 0 !important; + text-align: center; + justify-content: center; +} +.ui.attached.item.menu:not(.tabular) { + margin: 0 -1px !important; +} +.ui.item.menu .item:last-child::before { + display: none; +} +.ui.menu.two.item .item { + width: 50%; +} + +.ui.pointing.menu .item::after { + visibility: hidden; + position: absolute; + content: ""; + top: 100%; + left: 50%; + transform: translateX(-50%) translateY(-50%) rotate(45deg); + background: none; + margin: 0.5px 0 0; + width: 0.57142857em; + height: 0.57142857em; + border: none; + border-bottom: 1px solid var(--color-secondary); + border-right: 1px solid var(--color-secondary); + z-index: 2; +} +.ui.pointing.menu .ui.dropdown .menu .item::after { + display: none; +} + +.ui.pointing.menu .active.item::after { + visibility: visible; +} +.ui.pointing.menu .active.dropdown.item::after { + visibility: hidden; +} + +.ui.pointing.menu .dropdown.active.item::after, +.ui.pointing.menu .active.item .menu .active.item::after { + display: none; +} + +.ui.pointing.menu .active.item::after, +.ui.pointing.menu .active.item:hover::after { + background-color: var(--color-active); +} + +.ui.attached.menu { + top: 0; + bottom: 0; + border-radius: 0; + margin: 0 -1px; + width: calc(100% + 2px); + max-width: calc(100% + 2px); +} +.ui.attached + .ui.attached.menu:not(.top) { + border-top: none; +} + +.ui[class*="top attached"].menu { + bottom: 0; + margin-bottom: 0; + top: 0; + margin-top: 1rem; + border-radius: 0.28571429rem 0.28571429rem 0 0; +} +.ui.menu[class*="top attached"]:first-child { + margin-top: 0; +} + +.ui.top.attached.menu > .item:first-child { + border-radius: 0.28571429rem 0 0; +} + +.ui.attached.menu:not(.tabular) { + border: 1px solid var(--color-secondary); +} +.ui.attached.tabular.menu { + margin-left: 0; + margin-right: 0; + width: 100%; +} + +.ui.mini.menu, +.ui.mini.menu .dropdown, +.ui.mini.menu .dropdown .menu > .item { + font-size: 0.78571429rem; +} +.ui.mini.vertical.menu:not(.icon) { + width: 9rem; +} +.ui.tiny.menu, +.ui.tiny.menu .dropdown, +.ui.tiny.menu .dropdown .menu > .item { + font-size: 0.85714286rem; +} +.ui.tiny.vertical.menu:not(.icon) { + width: 11rem; +} +.ui.small.menu, +.ui.small.menu .dropdown, +.ui.small.menu .dropdown .menu > .item { + font-size: 0.92857143rem; +} +.ui.small.vertical.menu:not(.icon) { + width: 13rem; +} + +.ui .menu:not(.vertical) .item > .button.small { + font-size: 0.92857143rem; +} + +.ui.segment .ui.tabular.menu .active.item, +.ui.segment .ui.tabular.menu .active.item:hover { + background: var(--color-box-body); +} diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 4b7ad49677..52f9d5a6ca 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -2079,11 +2079,6 @@ td .commit-summary { padding: 10px 0 0; } -.ui.vertical.menu .header.item { - font-size: 1.1em; - background: var(--color-box-header); -} - .comment:target .comment-container { border-color: var(--color-primary) !important; box-shadow: 0 0 0 3px var(--color-primary-alpha-30) !important; diff --git a/web_src/fomantic/build/semantic.css b/web_src/fomantic/build/semantic.css index 49c00c4dad..8ce9ee24ea 100644 --- a/web_src/fomantic/build/semantic.css +++ b/web_src/fomantic/build/semantic.css @@ -6474,2016 +6474,6 @@ select.ui.dropdown { Theme Overrides *******************************/ -/******************************* - Site Overrides -*******************************/ -/* - * # Fomantic - Menu - * http://github.com/fomantic/Fomantic-UI/ - * - * - * Copyright 2015 Contributor - * Released under the MIT license - * http://opensource.org/licenses/MIT - * - */ - -/******************************* - Standard -*******************************/ - -/*-------------- - Menu ----------------*/ - -.ui.menu { - display: flex; - margin: 1rem 0; - font-family: var(--fonts-regular); - background: #FFFFFF; - font-weight: normal; - border: 1px solid rgba(34, 36, 38, 0.15); - box-shadow: 0 1px 2px 0 rgba(34, 36, 38, 0.15); - border-radius: 0.28571429rem; - min-height: 2.85714286em; -} - -.ui.menu:after { - content: ''; - display: block; - height: 0; - clear: both; - visibility: hidden; -} - -.ui.menu:first-child { - margin-top: 0; -} - -.ui.menu:last-child { - margin-bottom: 0; -} - -/*-------------- - Sub-Menu ----------------*/ - -.ui.menu .menu { - margin: 0; -} - -.ui.menu:not(.vertical) > .menu { - display: flex; -} - -/*-------------- - Item ----------------*/ - -.ui.menu:not(.vertical) .item { - display: flex; - align-items: center; -} - -.ui.menu .item { - position: relative; - vertical-align: middle; - line-height: 1; - text-decoration: none; - -webkit-tap-highlight-color: transparent; - flex: 0 0 auto; - -webkit-user-select: none; - -moz-user-select: none; - user-select: none; - background: none; - padding: 0.92857143em 1.14285714em; - text-transform: none; - color: rgba(0, 0, 0, 0.87); - font-weight: normal; - transition: background 0.1s ease, box-shadow 0.1s ease, color 0.1s ease; -} - -.ui.menu > .item:first-child { - border-radius: 0.28571429rem 0 0 0.28571429rem; -} - -/* Border */ - -.ui.menu .item:before { - position: absolute; - content: ''; - top: 0; - right: 0; - height: 100%; - width: 1px; - background: rgba(34, 36, 38, 0.1); -} - -/*-------------- - Text Content ----------------*/ - -.ui.menu .text.item > *, -.ui.menu .item > a:not(.ui), -.ui.menu .item > p:only-child { - -webkit-user-select: text; - -moz-user-select: text; - user-select: text; - line-height: 1.3; -} - -.ui.menu .item > p:first-child { - margin-top: 0; -} - -.ui.menu .item > p:last-child { - margin-bottom: 0; -} - -/*-------------- - Icons ----------------*/ - -.ui.menu .item > i.icon { - opacity: 0.9; - float: none; - margin: 0 0.35714286em 0 0; -} - -/*-------------- - Button ----------------*/ - -.ui.menu:not(.vertical) .item > .button { - position: relative; - top: 0; - margin: -0.5em 0; - padding-bottom: 0.78571429em; - padding-top: 0.78571429em; - font-size: 1em; -} - -/*---------------- - Grid / Container ------------------*/ - -.ui.menu > .grid, -.ui.menu > .container { - display: flex; - align-items: inherit; - flex-direction: inherit; -} - -/*-------------- - Inputs ----------------*/ - -.ui.menu .item > .input { - width: 100%; -} - -.ui.menu:not(.vertical) .item > .input { - position: relative; - top: 0; - margin: -0.5em 0; -} - -.ui.menu .item > .input input { - font-size: 1em; - padding-top: 0.57142857em; - padding-bottom: 0.57142857em; -} - -/*-------------- - Header ----------------*/ - -.ui.menu .header.item, -.ui.vertical.menu .header.item { - margin: 0; - background: ''; - text-transform: normal; - font-weight: 500; -} - -.ui.vertical.menu .item > .header:not(.ui) { - margin: 0 0 0.5em; - font-size: 1em; - font-weight: 500; -} - -/*-------------- - Dropdowns ----------------*/ - -/* Dropdown Icon */ - -.ui.menu .item > i.dropdown.icon { - padding: 0; - float: right; - margin: 0 0 0 1em; -} - -/* Menu */ - -.ui.menu .dropdown.item .menu { - min-width: calc(100% - 1px); - border-radius: 0 0 0.28571429rem 0.28571429rem; - background: #FFFFFF; - margin: 0 0 0; - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.08); - flex-direction: column !important; -} - -/* Menu Items */ - -.ui.menu .ui.dropdown .menu > .item { - margin: 0; - text-align: left; - font-size: 1em !important; - padding: 0.78571429em 1.14285714em !important; - background: transparent !important; - color: rgba(0, 0, 0, 0.87) !important; - text-transform: none !important; - font-weight: normal !important; - box-shadow: none !important; - transition: none !important; -} - -.ui.menu .ui.dropdown .menu > .item:hover { - background: rgba(0, 0, 0, 0.05) !important; - color: rgba(0, 0, 0, 0.95) !important; -} - -.ui.menu .ui.dropdown .menu > .selected.item { - background: rgba(0, 0, 0, 0.05) !important; - color: rgba(0, 0, 0, 0.95) !important; -} - -.ui.menu .ui.dropdown .menu > .active.item { - background: rgba(0, 0, 0, 0.03) !important; - font-weight: 500 !important; - color: rgba(0, 0, 0, 0.95) !important; -} - -.ui.menu .ui.dropdown.item .menu .item:not(.filtered) { - display: block; -} - -.ui.menu .ui.dropdown .menu > .item > .icons, -.ui.menu .ui.dropdown .menu > .item > i.icon:not(.dropdown) { - display: inline-block; - font-size: 1em !important; - float: none; - margin: 0 0.75em 0 0 !important; -} - -/* Secondary */ - -.ui.secondary.menu .dropdown.item > .menu, -.ui.text.menu .dropdown.item > .menu { - border-radius: 0.28571429rem; - margin-top: 0.35714286em; -} - -/* Pointing */ - -.ui.menu .pointing.dropdown.item .menu { - margin-top: 0.75em; -} - -/* Vertical */ - -.ui.vertical.menu .dropdown.item > i.icon { - float: right; - content: "\f0da"; - margin-left: 1em; -} - -.ui.vertical.menu .dropdown.item .menu { - left: 100%; - /* IE needs 0, all others support max-content to show dropdown icon inline, so keep both settings! */ - min-width: 0; - min-width: -moz-max-content; - min-width: max-content; - margin: 0 0 0 0; - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.08); - border-radius: 0 0.28571429rem 0.28571429rem 0.28571429rem; -} - -.ui.vertical.menu .dropdown.item.upward .menu { - bottom: 0; -} - -.ui.vertical.menu .dropdown.item:not(.upward) .menu { - top: 0; -} - -.ui.vertical.menu .active.dropdown.item { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} - -.ui.vertical.menu .dropdown.active.item { - box-shadow: none; -} - -/* Evenly Divided */ - -.ui.item.menu .dropdown .menu .item { - width: 100%; -} - -/*-------------- - Labels ----------------*/ - -.ui.menu .item > .label:not(.floating) { - margin-left: 1em; - padding: 0.3em 0.78571429em; -} - -.ui.vertical.menu .item > .label { - margin-top: -0.15em; - margin-bottom: -0.15em; - padding: 0.3em 0.78571429em; -} - -.ui.menu .item > .floating.label { - padding: 0.3em 0.78571429em; -} - -.ui.menu .item > .label { - background: #999999; - color: #FFFFFF; -} - -.ui.menu .item > .image.label img { - margin: -0.2833em 0.8em -0.2833em -0.8em; - height: 1.5666em; -} - -/*-------------- - Images ----------------*/ - -.ui.menu .item > img:not(.ui) { - display: inline-block; - vertical-align: middle; - margin: -0.3em 0; - width: 2.5em; -} - -.ui.vertical.menu .item > img:not(.ui):only-child { - display: block; - max-width: 100%; - width: auto; -} - -/******************************* - Coupling -*******************************/ - -/*-------------- - List ----------------*/ - -/* Menu divider shouldnt apply */ - -.ui.menu .list .item:before { - background: none !important; -} - -/*-------------- - Sidebar - ---------------*/ - -/* Show vertical dividers below last */ - -.ui.vertical.sidebar.menu > .item:first-child:before { - display: block !important; -} - -.ui.vertical.sidebar.menu > .item::before { - top: auto; - bottom: 0; -} - -/*-------------- - Container ----------------*/ - -@media only screen and (max-width: 767.98px) { - .ui.menu > .ui.container { - width: 100% !important; - margin-left: 0 !important; - margin-right: 0 !important; - } -} - -@media only screen and (min-width: 768px) { - .ui.menu:not(.secondary):not(.text):not(.tabular):not(.borderless) > .container > .item:not(.right):not(.borderless):first-child { - border-left: 1px solid rgba(34, 36, 38, 0.1); - } - - .ui.menu:not(.secondary):not(.text):not(.tabular):not(.borderless) > .container > .right.item:not(.borderless):last-child, - .ui.menu:not(.secondary):not(.text):not(.tabular):not(.borderless) > .container > .right.menu > .item:not(.borderless):last-child { - border-right: 1px solid rgba(34, 36, 38, 0.1); - } -} - -/******************************* - States -*******************************/ - -/*-------------- - Hover ----------------*/ - -.ui.link.menu .item:hover, -.ui.menu .dropdown.item:hover, -.ui.menu .link.item:hover, -.ui.menu a.item:hover { - cursor: pointer; - background: rgba(0, 0, 0, 0.03); - color: rgba(0, 0, 0, 0.95); -} - -/*-------------- - Pressed ----------------*/ - -.ui.link.menu .item:active, -.ui.menu .link.item:active, -.ui.menu a.item:active { - background: rgba(0, 0, 0, 0.03); - color: rgba(0, 0, 0, 0.95); -} - -/*-------------- - Active ----------------*/ - -.ui.menu .active.item { - background: rgba(0, 0, 0, 0.05); - color: rgba(0, 0, 0, 0.95); - font-weight: normal; - box-shadow: none; -} - -.ui.menu .active.item > i.icon { - opacity: 1; -} - -/*-------------- - Active Hover ----------------*/ - -.ui.menu .active.item:hover, -.ui.vertical.menu .active.item:hover { - background-color: rgba(0, 0, 0, 0.05); - color: rgba(0, 0, 0, 0.95); -} - -/*-------------- - Disabled ----------------*/ - -.ui.ui.menu .item.disabled { - cursor: default; - background-color: transparent; - color: rgba(40, 40, 40, 0.3); - pointer-events: none; -} - -/******************************* - Types -*******************************/ - -/*------------------ -Floated Menu / Item --------------------*/ - -/* Left Floated */ - -.ui.menu:not(.vertical) .left.item, -.ui.menu:not(.vertical) .left.menu { - display: flex; - margin-right: auto !important; -} - -/* Right Floated */ - -.ui.menu:not(.vertical) .right.item, -.ui.menu:not(.vertical) .right.menu { - display: flex; - margin-left: auto !important; -} - -.ui.menu:not(.vertical) :not(.dropdown) > .left.menu, -.ui.menu:not(.vertical) :not(.dropdown) > .right.menu { - display: inherit; -} - -/* Center */ - -.ui.menu:not(.vertical) .center.item, -.ui.menu:not(.vertical) .center.menu { - display: flex; - margin-left: auto !important; - margin-right: auto !important; -} - -/* Swapped Borders */ - -.ui.menu .right.item::before, -.ui.menu .right.menu > .item::before { - right: auto; - left: 0; -} - -/* Remove Outer Borders */ - -.ui.menu .center.item:last-child::before, -.ui.menu .center.menu > .item:last-child::before { - display: none; -} - -/*-------------- - Vertical - ---------------*/ - -.ui.vertical.menu { - display: block; - flex-direction: column; - background: #FFFFFF; - box-shadow: 0 1px 2px 0 rgba(34, 36, 38, 0.15); -} - -/*--- Item ---*/ - -.ui.vertical.menu .item { - display: block; - background: none; - border-top: none; - border-right: none; -} - -.ui.vertical.menu > .item:first-child { - border-radius: 0.28571429rem 0.28571429rem 0 0; -} - -.ui.vertical.menu > .item:last-child { - border-radius: 0 0 0.28571429rem 0.28571429rem; -} - -/*--- Label ---*/ - -.ui.vertical.menu .item > .label { - float: right; - text-align: center; -} - -/*--- Icon ---*/ - -.ui.vertical.menu .item > i.icon, -.ui.vertical.menu .item > i.icons { - width: 1.18em; - float: right; - margin: 0 0 0 0.5em; -} - -.ui.vertical.menu .item > .label + i.icon { - float: none; - margin: 0 0.5em 0 0; -} - -/*--- Border ---*/ - -.ui.vertical.menu .item:before { - position: absolute; - content: ''; - top: 0; - left: 0; - width: 100%; - height: 1px; - background: rgba(34, 36, 38, 0.1); -} - -.ui.vertical.menu .item:first-child:before { - display: none !important; -} - -/*--- Sub Menu ---*/ - -.ui.vertical.menu .item > .menu { - margin: 0.5em -1.14285714em 0; -} - -.ui.vertical.menu .menu .item { - background: none; - padding: 0.5em 1.33333333em; - font-size: 0.85714286em; - color: rgba(0, 0, 0, 0.5); -} - -.ui.vertical.menu .item .menu a.item:hover, -.ui.vertical.menu .item .menu .link.item:hover { - color: rgba(0, 0, 0, 0.85); -} - -.ui.vertical.menu .menu .item:before { - display: none; -} - -/* Vertical Active */ - -.ui.vertical.menu .active.item { - background: rgba(0, 0, 0, 0.05); - border-radius: 0; - box-shadow: none; -} - -.ui.vertical.menu > .active.item:first-child { - border-radius: 0.28571429rem 0.28571429rem 0 0; -} - -.ui.vertical.menu > .active.item:last-child { - border-radius: 0 0 0.28571429rem 0.28571429rem; -} - -.ui.vertical.menu > .active.item:only-child { - border-radius: 0.28571429rem; -} - -.ui.vertical.menu .active.item .menu .active.item { - border-left: none; -} - -.ui.vertical.menu .item .menu .active.item { - background-color: transparent; - font-weight: 500; - color: rgba(0, 0, 0, 0.95); -} - -/*-------------- - Tabular - ---------------*/ - -.ui.tabular.menu { - border-radius: 0; - box-shadow: none !important; - border: none; - background: none transparent; - border-bottom: 1px solid #D4D4D5; -} - -.ui.tabular.fluid.menu { - width: calc(100% + 2px) !important; -} - -.ui.tabular.menu .item { - background: transparent; - border-bottom: none; - border-left: 1px solid transparent; - border-right: 1px solid transparent; - border-top: 2px solid transparent; - padding: 0.92857143em 1.42857143em; - color: rgba(0, 0, 0, 0.87); -} - -.ui.tabular.menu .item:before { - display: none; -} - -/* Hover */ - -.ui.tabular.menu .item:hover { - background-color: transparent; - color: rgba(0, 0, 0, 0.8); -} - -/* Active */ - -.ui.tabular.menu .active.item { - background: none #FFFFFF; - color: rgba(0, 0, 0, 0.95); - border-top-width: 1px; - border-color: #D4D4D5; - font-weight: 500; - margin-bottom: -1px; - box-shadow: none; - border-radius: 0.28571429rem 0.28571429rem 0 0 !important; -} - -/* Coupling with segment for attachment */ - -.ui.tabular.menu + .attached:not(.top).segment, -.ui.tabular.menu + .attached:not(.top).segment + .attached:not(.top).segment { - border-top: none; - margin-left: 0; - margin-top: 0; - margin-right: 0; - width: 100%; -} - -.top.attached.segment + .ui.bottom.tabular.menu { - position: relative; - width: calc(100% + 2px); - left: -1px; -} - -/* Bottom Vertical Tabular */ - -.ui.bottom.tabular.menu { - background: none transparent; - border-radius: 0; - box-shadow: none !important; - border-bottom: none; - border-top: 1px solid #D4D4D5; -} - -.ui.bottom.tabular.menu .item { - background: none; - border-left: 1px solid transparent; - border-right: 1px solid transparent; - border-bottom: 1px solid transparent; - border-top: none; -} - -.ui.bottom.tabular.menu .active.item { - background: none #FFFFFF; - color: rgba(0, 0, 0, 0.95); - border-color: #D4D4D5; - margin: -1px 0 0 0; - border-radius: 0 0 0.28571429rem 0.28571429rem !important; -} - -/* Vertical Tabular (Left) */ - -.ui.vertical.tabular.menu { - background: none transparent; - border-radius: 0; - box-shadow: none !important; - border-bottom: none; - border-right: 1px solid #D4D4D5; -} - -.ui.vertical.tabular.menu .item { - background: none; - border-left: 1px solid transparent; - border-bottom: 1px solid transparent; - border-top: 1px solid transparent; - border-right: none; -} - -.ui.vertical.tabular.menu .active.item { - background: none #FFFFFF; - color: rgba(0, 0, 0, 0.95); - border-color: #D4D4D5; - margin: 0 -1px 0 0; - border-radius: 0.28571429rem 0 0 0.28571429rem !important; -} - -/* Vertical Right Tabular */ - -.ui.vertical.right.tabular.menu { - background: none transparent; - border-radius: 0; - box-shadow: none !important; - border-bottom: none; - border-right: none; - border-left: 1px solid #D4D4D5; -} - -.ui.vertical.right.tabular.menu .item { - background: none; - border-right: 1px solid transparent; - border-bottom: 1px solid transparent; - border-top: 1px solid transparent; - border-left: none; -} - -.ui.vertical.right.tabular.menu .active.item { - background: none #FFFFFF; - color: rgba(0, 0, 0, 0.95); - border-color: #D4D4D5; - margin: 0 0 0 -1px; - border-radius: 0 0.28571429rem 0.28571429rem 0 !important; -} - -/* Dropdown */ - -.ui.tabular.menu .active.dropdown.item { - margin-bottom: 0; - border-left: 1px solid transparent; - border-right: 1px solid transparent; - border-top: 2px solid transparent; - border-bottom: none; -} - -/*-------------- - Pagination - ---------------*/ - -.ui.pagination.menu { - margin: 0; - display: inline-flex; - vertical-align: middle; -} - -.ui.pagination.menu .item:last-child { - border-radius: 0 0.28571429rem 0.28571429rem 0; -} - -.ui.compact.menu .item:last-child { - border-radius: 0 0.28571429rem 0.28571429rem 0; -} - -.ui.pagination.menu .item:last-child:before { - display: none; -} - -.ui.pagination.menu .item { - min-width: 3em; - text-align: center; -} - -.ui.pagination.menu .icon.item i.icon { - vertical-align: top; -} - -/* Active */ - -.ui.pagination.menu .active.item { - border-top: none; - padding-top: 0.92857143em; - background-color: rgba(0, 0, 0, 0.05); - color: rgba(0, 0, 0, 0.95); - box-shadow: none; -} - -/*-------------- - Secondary - ---------------*/ - -.ui.secondary.menu { - background: none; - margin-left: -0.35714286em; - margin-right: -0.35714286em; - border-radius: 0; - border: none; - box-shadow: none; -} - -/* Item */ - -.ui.secondary.menu .item { - align-self: center; - box-shadow: none; - border: none; - padding: 0.78571429em 0.92857143em; - margin: 0 0.35714286em; - background: none; - transition: color 0.1s ease; - border-radius: 0.28571429rem; -} - -/* No Divider */ - -.ui.secondary.menu .item:before { - display: none !important; -} - -/* Header */ - -.ui.secondary.menu .header.item { - border-radius: 0; - border-right: none; - background: none transparent; -} - -/* Image */ - -.ui.secondary.menu .item > img:not(.ui) { - margin: 0; -} - -/* Hover */ - -.ui.secondary.menu .dropdown.item:hover, -.ui.secondary.menu .link.item:hover, -.ui.secondary.menu a.item:hover { - background: rgba(0, 0, 0, 0.05); - color: rgba(0, 0, 0, 0.95); -} - -/* Active */ - -.ui.secondary.menu .active.item { - box-shadow: none; - background: rgba(0, 0, 0, 0.05); - color: rgba(0, 0, 0, 0.95); - border-radius: 0.28571429rem; -} - -/* Active Hover */ - -.ui.secondary.menu .active.item:hover { - box-shadow: none; - background: rgba(0, 0, 0, 0.05); - color: rgba(0, 0, 0, 0.95); -} - -/* Fix item margins */ - -.ui.secondary.item.menu { - margin-left: 0; - margin-right: 0; -} - -.ui.secondary.item.menu .item:last-child { - margin-right: 0; -} - -.ui.secondary.attached.menu { - box-shadow: none; -} - -/*--------------------- - Secondary Vertical - -----------------------*/ - -/* Sub Menu */ - -.ui.vertical.secondary.menu .item:not(.dropdown) > .menu { - margin: 0 -0.92857143em; -} - -.ui.vertical.secondary.menu .item:not(.dropdown) > .menu > .item { - margin: 0; - padding: 0.5em 1.33333333em; -} - -.ui.secondary.vertical.menu > .item { - border: none; - margin: 0 0 0.35714286em; - border-radius: 0.28571429rem !important; -} - -.ui.secondary.vertical.menu > .header.item { - border-radius: 0; -} - -/* Sub Menu */ - -.ui.vertical.secondary.menu .item > .menu .item { - background-color: transparent; -} - -/* Inverted */ - -.ui.secondary.inverted.menu { - background-color: transparent; -} - -/*--------------------- - Secondary Pointing - -----------------------*/ - -.ui.secondary.pointing.menu { - margin-left: 0; - margin-right: 0; - border-bottom: 2px solid rgba(34, 36, 38, 0.15); -} - -.ui.secondary.pointing.menu .item { - border-bottom-color: transparent; - border-bottom-style: solid; - border-radius: 0; - align-self: flex-end; - margin: 0 0 -2px; - padding: 0.85714286em 1.14285714em; - border-bottom-width: 2px; - transition: color 0.1s ease; -} - -.ui.secondary.pointing.menu .ui.dropdown .menu .item { - border-bottom-width: 0; -} - -.ui.secondary.pointing.menu .item > .label:not(.floating) { - margin-top: -0.3em; - margin-bottom: -0.3em; -} - -.ui.secondary.pointing.menu .item > .circular.label { - margin-top: -0.5em; - margin-bottom: -0.5em; -} - -/* Item Types */ - -.ui.secondary.pointing.menu .header.item { - color: rgba(0, 0, 0, 0.85) !important; -} - -.ui.secondary.pointing.menu .text.item { - box-shadow: none !important; -} - -.ui.secondary.pointing.menu .item:after { - display: none; -} - -/* Hover */ - -.ui.secondary.pointing.menu .dropdown.item:hover, -.ui.secondary.pointing.menu .link.item:hover, -.ui.secondary.pointing.menu a.item:hover { - background-color: transparent; - color: rgba(0, 0, 0, 0.87); -} - -/* Pressed */ - -.ui.secondary.pointing.menu .dropdown.item:active, -.ui.secondary.pointing.menu .link.item:active, -.ui.secondary.pointing.menu a.item:active { - background-color: transparent; - border-color: rgba(34, 36, 38, 0.15); -} - -/* Active */ - -.ui.secondary.pointing.menu .active.item { - background-color: transparent; - box-shadow: none; - border-color: currentColor; - font-weight: 500; - color: rgba(0, 0, 0, 0.95); -} - -/* Active Hover */ - -.ui.secondary.pointing.menu .active.item:hover { - border-color: currentColor; - color: rgba(0, 0, 0, 0.95); -} - -/* Active Dropdown */ - -.ui.secondary.pointing.menu .active.dropdown.item { - border-color: transparent; -} - -/* Vertical Pointing */ - -.ui.secondary.vertical.pointing.menu { - border-bottom-width: 0; - border-right-width: 2px; - border-right-style: solid; - border-right-color: rgba(34, 36, 38, 0.15); -} - -.ui.secondary.vertical.pointing.menu .item { - border-bottom: none; - border-right-style: solid; - border-right-color: transparent; - border-radius: 0 !important; - margin: 0 -2px 0 0; - border-right-width: 2px; -} - -/* Vertical Active */ - -.ui.secondary.vertical.pointing.menu .active.item { - border-color: currentColor; -} - -/*-------------- - Text Menu - ---------------*/ - -.ui.text.menu { - background: none transparent; - border-radius: 0; - box-shadow: none; - border: none; - margin: 1em -0.5em; -} - -.ui.text.menu .item { - border-radius: 0; - box-shadow: none; - align-self: center; - margin: 0 0; - padding: 0.35714286em 0.5em; - font-weight: normal; - color: rgba(0, 0, 0, 0.6); - transition: opacity 0.1s ease; -} - -/* Border */ - -.ui.text.menu .item:before, -.ui.text.menu .menu .item:before { - display: none !important; -} - -/* Header */ - -.ui.text.menu .header.item { - background-color: transparent; - opacity: 1; - color: rgba(0, 0, 0, 0.85); - font-size: 0.92857143em; - text-transform: uppercase; - font-weight: 500; -} - -/* Image */ - -.ui.text.menu .item > img:not(.ui) { - margin: 0; -} - -/*--- fluid text ---*/ - -.ui.text.item.menu .item { - margin: 0; -} - -/*--- vertical text ---*/ - -.ui.vertical.text.menu { - margin: 1em 0; -} - -.ui.vertical.text.menu:first-child { - margin-top: 0; -} - -.ui.vertical.text.menu:last-child { - margin-bottom: 0; -} - -.ui.vertical.text.menu .item { - margin: 0.57142857em 0; - padding-left: 0; - padding-right: 0; -} - -.ui.vertical.text.menu .item > i.icon { - float: none; - margin: 0 0.35714286em 0 0; -} - -.ui.vertical.text.menu .header.item { - margin: 0.57142857em 0 0.71428571em; -} - -/* Vertical Sub Menu */ - -.ui.vertical.text.menu .item:not(.dropdown) > .menu { - margin: 0; -} - -.ui.vertical.text.menu .item:not(.dropdown) > .menu > .item { - margin: 0; - padding: 0.5em 0; -} - -/*--- hover ---*/ - -.ui.text.menu .item:hover { - opacity: 1; - background-color: transparent; -} - -/*--- active ---*/ - -.ui.text.menu .active.item { - background-color: transparent; - border: none; - box-shadow: none; - font-weight: normal; - color: rgba(0, 0, 0, 0.95); -} - -/*--- active hover ---*/ - -.ui.text.menu .active.item:hover { - background-color: transparent; -} - -/* Disable Bariations */ - -.ui.text.pointing.menu .active.item:after { - box-shadow: none; -} - -.ui.text.attached.menu { - box-shadow: none; -} - -/* Fluid */ - -.ui.fluid.text.menu { - margin-left: 0; - margin-right: 0; -} - -/*-------------- - Icon Only ----------------*/ - -/* Vertical Menu */ - -.ui.vertical.icon.menu { - display: inline-block; - width: auto; -} - -/* Item */ - -.ui.icon.menu .item { - height: auto; - text-align: center; - color: #1B1C1D; -} - -/* Icon */ - -.ui.icon.menu .item > i.icon:not(.dropdown) { - margin: 0; - opacity: 1; -} - -/* Icon Gylph */ - -.ui.icon.menu i.icon:before { - opacity: 1; -} - -/* (x) Item Icon */ - -.ui.menu .icon.item > i.icon { - width: auto; - margin: 0 auto; -} - -/* Vertical Icon */ - -.ui.vertical.icon.menu .item > i.icon:not(.dropdown) { - display: block; - opacity: 1; - margin: 0 auto; - float: none; -} - -/* Inverted */ - -.ui.inverted.icon.menu .item { - color: #FFFFFF; -} - -/*-------------- - Labeled Icon - ---------------*/ - -/* Menu */ - -.ui.labeled.icon.menu { - text-align: center; -} - -/* Item */ - -.ui.labeled.icon.menu .item { - min-width: 6em; - flex-direction: column; -} - -/* Icon */ - -.ui.labeled.icon.menu > .item > i.icon:not(.dropdown) { - height: 1em; - display: block; - font-size: 1.71428571em !important; - margin: 0 auto 0.5rem !important; -} - -/* Fluid */ - -.ui.fluid.labeled.icon.menu > .item { - min-width: 0; -} - -/******************************* - Variations -*******************************/ - -/*-------------- - Stackable - ---------------*/ - -@media only screen and (max-width: 767.98px) { - .ui.stackable.menu { - flex-direction: column; - } - - .ui.stackable.menu .item { - width: 100% !important; - } - - .ui.stackable.menu .item:before { - position: absolute; - content: ''; - top: auto; - bottom: 0; - left: 0; - width: 100%; - height: 1px; - background: rgba(34, 36, 38, 0.1); - } - - .ui.stackable.menu .left.menu, - .ui.stackable.menu .left.item { - margin-right: 0 !important; - } - - .ui.stackable.menu .right.menu, - .ui.stackable.menu .right.item { - margin-left: 0 !important; - } - - .ui.stackable.menu .center.menu, - .ui.stackable.menu .center.item { - margin-left: 0 !important; - margin-right: 0 !important; - } - - .ui.stackable.menu .right.menu, - .ui.stackable.menu .center.menu, - .ui.stackable.menu .left.menu { - flex-direction: column; - } -} - -/*-------------- - Colors ----------------*/ - -.ui.ui.ui.menu .primary.active.item, -.ui.ui.primary.menu .active.item:hover, -.ui.ui.primary.menu .active.item { - color: #2185D0; -} - -.ui.ui.ui.menu .red.active.item, -.ui.ui.red.menu .active.item:hover, -.ui.ui.red.menu .active.item { - color: #DB2828; -} - -.ui.ui.ui.menu .orange.active.item, -.ui.ui.orange.menu .active.item:hover, -.ui.ui.orange.menu .active.item { - color: #F2711C; -} - -.ui.ui.ui.menu .yellow.active.item, -.ui.ui.yellow.menu .active.item:hover, -.ui.ui.yellow.menu .active.item { - color: #FBBD08; -} - -.ui.ui.ui.menu .olive.active.item, -.ui.ui.olive.menu .active.item:hover, -.ui.ui.olive.menu .active.item { - color: #B5CC18; -} - -.ui.ui.ui.menu .green.active.item, -.ui.ui.green.menu .active.item:hover, -.ui.ui.green.menu .active.item { - color: #21BA45; -} - -.ui.ui.ui.menu .teal.active.item, -.ui.ui.teal.menu .active.item:hover, -.ui.ui.teal.menu .active.item { - color: #00B5AD; -} - -.ui.ui.ui.menu .blue.active.item, -.ui.ui.blue.menu .active.item:hover, -.ui.ui.blue.menu .active.item { - color: #2185D0; -} - -.ui.ui.ui.menu .violet.active.item, -.ui.ui.violet.menu .active.item:hover, -.ui.ui.violet.menu .active.item { - color: #6435C9; -} - -.ui.ui.ui.menu .purple.active.item, -.ui.ui.purple.menu .active.item:hover, -.ui.ui.purple.menu .active.item { - color: #A333C8; -} - -.ui.ui.ui.menu .pink.active.item, -.ui.ui.pink.menu .active.item:hover, -.ui.ui.pink.menu .active.item { - color: #E03997; -} - -.ui.ui.ui.menu .brown.active.item, -.ui.ui.brown.menu .active.item:hover, -.ui.ui.brown.menu .active.item { - color: #A5673F; -} - -.ui.ui.ui.menu .grey.active.item, -.ui.ui.grey.menu .active.item:hover, -.ui.ui.grey.menu .active.item { - color: #767676; -} - -.ui.ui.ui.menu .black.active.item, -.ui.ui.black.menu .active.item:hover, -.ui.ui.black.menu .active.item { - color: #1B1C1D; -} - -/*-------------- - Floated - ---------------*/ - -.ui.floated.menu { - float: left; - margin: 0 0.5rem 0 0; -} - -.ui.floated.menu .item:last-child:before { - display: none; -} - -.ui.right.floated.menu { - float: right; - margin: 0 0 0 0.5rem; -} - -/*-------------- - Fitted - ---------------*/ - -.ui.fitted.menu .item, -.ui.fitted.menu .item .menu .item, -.ui.menu .fitted.item { - padding: 0; -} - -.ui.horizontally.fitted.menu .item, -.ui.horizontally.fitted.menu .item .menu .item, -.ui.menu .horizontally.fitted.item { - padding-top: 0.92857143em; - padding-bottom: 0.92857143em; -} - -.ui.vertically.fitted.menu .item, -.ui.vertically.fitted.menu .item .menu .item, -.ui.menu .vertically.fitted.item { - padding-left: 1.14285714em; - padding-right: 1.14285714em; -} - -/*-------------- - Borderless - ---------------*/ - -.ui.borderless.menu .item:before, -.ui.borderless.menu .item .menu .item:before, -.ui.menu .borderless.item:before { - background: none !important; -} - -/*------------------- - Compact - --------------------*/ - -.ui.compact.menu { - display: inline-flex; - margin: 0; - vertical-align: middle; -} - -.ui.compact.vertical.menu { - /* IE hack to make dropdown icons appear inline */ - display: -ms-inline-flexbox !important; - display: inline-block; -} - -.ui.compact.menu:not(.secondary) .item:last-child { - border-radius: 0 0.28571429rem 0.28571429rem 0; -} - -.ui.compact.menu .item:last-child:before { - display: none; -} - -.ui.compact.vertical.menu { - width: auto !important; -} - -.ui.compact.vertical.menu .item:last-child::before { - display: block; -} - -/*------------------- - Fluid - --------------------*/ - -.ui.menu.fluid, -.ui.vertical.menu.fluid { - width: 100% !important; -} - -/*------------------- - Evenly Sized ---------------------*/ - -.ui.item.menu, -.ui.item.menu .item { - width: 100%; - padding-left: 0 !important; - padding-right: 0 !important; - margin-left: 0 !important; - margin-right: 0 !important; - text-align: center; - justify-content: center; -} - -.ui.attached.item.menu:not(.tabular) { - margin: 0 -1px !important; -} - -.ui.item.menu .item:last-child:before { - display: none; -} - -.ui.menu.two.item .item { - width: 50%; -} - -.ui.menu.three.item .item { - width: 33.333%; -} - -.ui.menu.four.item .item { - width: 25%; -} - -.ui.menu.five.item .item { - width: 20%; -} - -.ui.menu.six.item .item { - width: 16.666%; -} - -.ui.menu.seven.item .item { - width: 14.285%; -} - -.ui.menu.eight.item .item { - width: 12.5%; -} - -.ui.menu.nine.item .item { - width: 11.11%; -} - -.ui.menu.ten.item .item { - width: 10%; -} - -.ui.menu.eleven.item .item { - width: 9.09%; -} - -.ui.menu.twelve.item .item { - width: 8.333%; -} - -/*-------------- - Fixed - ---------------*/ - -.ui.menu.fixed { - position: fixed; - z-index: 101; - margin: 0; - width: 100%; -} - -.ui.menu.fixed, -.ui.menu.fixed .item:first-child, -.ui.menu.fixed .item:last-child { - border-radius: 0 !important; -} - -.ui.fixed.menu, -.ui[class*="top fixed"].menu { - top: 0; - left: 0; - right: auto; - bottom: auto; -} - -.ui[class*="top fixed"].menu { - border-top: none; - border-left: none; - border-right: none; -} - -.ui[class*="right fixed"].menu { - border-top: none; - border-bottom: none; - border-right: none; - top: 0; - right: 0; - left: auto; - bottom: auto; - width: auto; - height: 100%; -} - -.ui[class*="bottom fixed"].menu { - border-bottom: none; - border-left: none; - border-right: none; - bottom: 0; - left: 0; - top: auto; - right: auto; -} - -.ui[class*="left fixed"].menu { - border-top: none; - border-bottom: none; - border-left: none; - top: 0; - left: 0; - right: auto; - bottom: auto; - width: auto; - height: 100%; -} - -/* Coupling with Grid */ - -.ui.fixed.menu + .ui.grid { - padding-top: 2.75rem; -} - -/*------------------- - Pointing - --------------------*/ - -.ui.pointing.menu .item:after { - visibility: hidden; - position: absolute; - content: ''; - top: 100%; - left: 50%; - transform: translateX(-50%) translateY(-50%) rotate(45deg); - background: none; - margin: 0.5px 0 0; - width: 0.57142857em; - height: 0.57142857em; - border: none; - border-bottom: 1px solid #D4D4D5; - border-right: 1px solid #D4D4D5; - z-index: 2; - transition: background 0.1s ease; -} - -.ui.vertical.pointing.menu .item:after { - position: absolute; - top: 50%; - right: 0; - bottom: auto; - left: auto; - transform: translateX(50%) translateY(-50%) rotate(45deg); - margin: 0 -0.5px 0 0; - border: none; - border-top: 1px solid #D4D4D5; - border-right: 1px solid #D4D4D5; -} - -.ui.pointing.menu .ui.dropdown .menu .item:after, -.ui.vertical.pointing.menu .ui.dropdown .menu .item:after { - display: none; -} - -/* Active */ - -.ui.pointing.menu .active.item:after { - visibility: visible; -} - -.ui.pointing.menu .active.dropdown.item:after { - visibility: hidden; -} - -/* Don't double up pointers */ - -.ui.pointing.menu .dropdown.active.item:after, -.ui.pointing.menu .active.item .menu .active.item:after { - display: none; -} - -/* Colors */ - -.ui.pointing.menu .active.item:hover:after { - background-color: #F2F2F2; -} - -.ui.pointing.menu .active.item:after { - background-color: #F2F2F2; -} - -.ui.pointing.menu .active.item:hover:after { - background-color: #F2F2F2; -} - -.ui.vertical.pointing.menu .active.item:hover:after { - background-color: #F2F2F2; -} - -.ui.vertical.pointing.menu .active.item:after { - background-color: #F2F2F2; -} - -.ui.vertical.pointing.menu .menu .active.item:after { - background-color: #FFFFFF; -} - -.ui.inverted.pointing.menu .primary.active.item:after { - background-color: #2185D0; -} - -.ui.inverted.pointing.menu .secondary.active.item:after { - background-color: #1B1C1D; -} - -.ui.inverted.pointing.menu .red.active.item:after { - background-color: #DB2828; -} - -.ui.inverted.pointing.menu .orange.active.item:after { - background-color: #F2711C; -} - -.ui.inverted.pointing.menu .yellow.active.item:after { - background-color: #FBBD08; -} - -.ui.inverted.pointing.menu .olive.active.item:after { - background-color: #B5CC18; -} - -.ui.inverted.pointing.menu .green.active.item:after { - background-color: #21BA45; -} - -.ui.inverted.pointing.menu .teal.active.item:after { - background-color: #00B5AD; -} - -.ui.inverted.pointing.menu .blue.active.item:after { - background-color: #2185D0; -} - -.ui.inverted.pointing.menu .violet.active.item:after { - background-color: #6435C9; -} - -.ui.inverted.pointing.menu .purple.active.item:after { - background-color: #A333C8; -} - -.ui.inverted.pointing.menu .pink.active.item:after { - background-color: #E03997; -} - -.ui.inverted.pointing.menu .brown.active.item:after { - background-color: #A5673F; -} - -.ui.inverted.pointing.menu .grey.active.item:after { - background-color: #767676; -} - -.ui.inverted.pointing.menu .black.active.item:after { - background-color: #1B1C1D; -} - -/*-------------- - Attached - ---------------*/ - -/* Middle */ - -.ui.attached.menu { - top: 0; - bottom: 0; - border-radius: 0; - margin: 0 -1px; - width: calc(100% + 2px); - max-width: calc(100% + 2px); - box-shadow: none; -} - -.ui.attached + .ui.attached.menu:not(.top) { - border-top: none; -} - -/* Top */ - -.ui[class*="top attached"].menu { - bottom: 0; - margin-bottom: 0; - top: 0; - margin-top: 1rem; - border-radius: 0.28571429rem 0.28571429rem 0 0; -} - -.ui.menu[class*="top attached"]:first-child { - margin-top: 0; -} - -/* Bottom */ - -.ui[class*="bottom attached"].menu { - bottom: 0; - margin-top: 0; - top: 0; - margin-bottom: 1rem; - box-shadow: 0 1px 2px 0 rgba(34, 36, 38, 0.15), none; - border-radius: 0 0 0.28571429rem 0.28571429rem; -} - -.ui[class*="bottom attached"].menu:last-child { - margin-bottom: 0; -} - -/* Attached Menu Item */ - -.ui.top.attached.menu > .item:first-child { - border-radius: 0.28571429rem 0 0 0; -} - -.ui.bottom.attached.menu > .item:first-child { - border-radius: 0 0 0 0.28571429rem; -} - -/* Tabular Attached */ - -.ui.attached.menu:not(.tabular) { - border: 1px solid #D4D4D5; -} - -.ui.attached.tabular.menu { - margin-left: 0; - margin-right: 0; - width: 100%; -} - -/*-------------- - Sizes ----------------*/ - -.ui.menu { - font-size: 1rem; -} - -.ui.vertical.menu { - width: 15rem; -} - -.ui.mini.menu, -.ui.mini.menu .dropdown, -.ui.mini.menu .dropdown .menu > .item { - font-size: 0.78571429rem; -} - -.ui.mini.vertical.menu:not(.icon) { - width: 9rem; -} - -.ui.tiny.menu, -.ui.tiny.menu .dropdown, -.ui.tiny.menu .dropdown .menu > .item { - font-size: 0.85714286rem; -} - -.ui.tiny.vertical.menu:not(.icon) { - width: 11rem; -} - -.ui.small.menu, -.ui.small.menu .dropdown, -.ui.small.menu .dropdown .menu > .item { - font-size: 0.92857143rem; -} - -.ui.small.vertical.menu:not(.icon) { - width: 13rem; -} - -.ui.large.menu, -.ui.large.menu .dropdown, -.ui.large.menu .dropdown .menu > .item { - font-size: 1.07142857rem; -} - -.ui.large.vertical.menu:not(.icon) { - width: 18rem; -} - -.ui.big.menu, -.ui.big.menu .dropdown, -.ui.big.menu .dropdown .menu > .item { - font-size: 1.14285714rem; -} - -.ui.big.vertical.menu:not(.icon) { - width: 20rem; -} - -.ui.huge.menu, -.ui.huge.menu .dropdown, -.ui.huge.menu .dropdown .menu > .item { - font-size: 1.21428571rem; -} - -.ui.huge.vertical.menu:not(.icon) { - width: 22rem; -} - -.ui.massive.menu, -.ui.massive.menu .dropdown, -.ui.massive.menu .dropdown .menu > .item { - font-size: 1.28571429rem; -} - -.ui.massive.vertical.menu:not(.icon) { - width: 25rem; -} - -/*------------------- - Inverted dropdowns ---------------------*/ - -.ui.menu .ui.inverted.inverted.dropdown.item .menu { - background: #1B1C1D; - box-shadow: none; -} - -.ui.menu .ui.inverted.dropdown .menu > .item { - color: rgba(255, 255, 255, 0.8) !important; -} - -.ui.menu .ui.inverted.dropdown .menu > .active.item { - background: transparent !important; - color: rgba(255, 255, 255, 0.8) !important; -} - -.ui.menu .ui.inverted.dropdown .menu > .item:hover { - background: rgba(255, 255, 255, 0.08) !important; - color: rgba(255, 255, 255, 0.8) !important; -} - -.ui.menu .ui.inverted.dropdown .menu > .selected.item { - background: rgba(255, 255, 255, 0.15) !important; - color: rgba(255, 255, 255, 0.8) !important; -} - -/* Vertical */ - -.ui.vertical.menu .inverted.dropdown.item .menu { - box-shadow: none; -} - -/******************************* - Theme Overrides -*******************************/ - /******************************* Site Overrides *******************************/ diff --git a/web_src/fomantic/semantic.json b/web_src/fomantic/semantic.json index 5db57bc8d4..5b3a480d53 100644 --- a/web_src/fomantic/semantic.json +++ b/web_src/fomantic/semantic.json @@ -26,7 +26,6 @@ "dimmer", "dropdown", "form", - "menu", "modal", "search", "tab" From e20428d8f64697d7c6418b42d0a8e57d1d3f588c Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Sun, 14 Apr 2024 20:16:54 +0800 Subject: [PATCH 111/370] Fix commitstatus summary (#30431) The target_url is necessary for the UI, but missed in commit_status_summary table. This PR fix it. --------- Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: delvh <dev.lh@web.de> Co-authored-by: Giteabot <teabot@gitea.io> --- models/git/commit_status_summary.go | 32 ++++++++++++++++------------- models/migrations/migrations.go | 2 ++ models/migrations/v1_23/v296.go | 16 +++++++++++++++ 3 files changed, 36 insertions(+), 14 deletions(-) create mode 100644 models/migrations/v1_23/v296.go diff --git a/models/git/commit_status_summary.go b/models/git/commit_status_summary.go index 01674e943d..7603e7aa65 100644 --- a/models/git/commit_status_summary.go +++ b/models/git/commit_status_summary.go @@ -15,10 +15,11 @@ import ( // CommitStatusSummary holds the latest commit Status of a single Commit type CommitStatusSummary struct { - ID int64 `xorm:"pk autoincr"` - RepoID int64 `xorm:"INDEX UNIQUE(repo_id_sha)"` - SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_id_sha)"` - State api.CommitStatusState `xorm:"VARCHAR(7) NOT NULL"` + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX UNIQUE(repo_id_sha)"` + SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_id_sha)"` + State api.CommitStatusState `xorm:"VARCHAR(7) NOT NULL"` + TargetURL string `xorm:"TEXT"` } func init() { @@ -44,9 +45,10 @@ func GetLatestCommitStatusForRepoAndSHAs(ctx context.Context, repoSHAs []RepoSHA commitStatuses := make([]*CommitStatus, 0, len(repoSHAs)) for _, summary := range summaries { commitStatuses = append(commitStatuses, &CommitStatus{ - RepoID: summary.RepoID, - SHA: summary.SHA, - State: summary.State, + RepoID: summary.RepoID, + SHA: summary.SHA, + State: summary.State, + TargetURL: summary.TargetURL, }) } return commitStatuses, nil @@ -61,22 +63,24 @@ func UpdateCommitStatusSummary(ctx context.Context, repoID int64, sha string) er // mysql will return 0 when update a record which state hasn't been changed which behaviour is different from other database, // so we need to use insert in on duplicate if setting.Database.Type.IsMySQL() { - _, err := db.GetEngine(ctx).Exec("INSERT INTO commit_status_summary (repo_id,sha,state) VALUES (?,?,?) ON DUPLICATE KEY UPDATE state=?", - repoID, sha, state.State, state.State) + _, err := db.GetEngine(ctx).Exec("INSERT INTO commit_status_summary (repo_id,sha,state,target_url) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE state=?", + repoID, sha, state.State, state.TargetURL, state.State) return err } if cnt, err := db.GetEngine(ctx).Where("repo_id=? AND sha=?", repoID, sha). - Cols("state"). + Cols("state, target_url"). Update(&CommitStatusSummary{ - State: state.State, + State: state.State, + TargetURL: state.TargetURL, }); err != nil { return err } else if cnt == 0 { _, err = db.GetEngine(ctx).Insert(&CommitStatusSummary{ - RepoID: repoID, - SHA: sha, - State: state.State, + RepoID: repoID, + SHA: sha, + State: state.State, + TargetURL: state.TargetURL, }) return err } diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 3ea8f2acbf..5326d48f90 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -580,6 +580,8 @@ var migrations = []Migration{ NewMigration("Add unique index for project issue table", v1_23.AddUniqueIndexForProjectIssue), // v295 -> v296 NewMigration("Add commit status summary table", v1_23.AddCommitStatusSummary), + // v296 -> v297 + NewMigration("Add missing field of commit status summary table", v1_23.AddCommitStatusSummary2), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v1_23/v296.go b/models/migrations/v1_23/v296.go new file mode 100644 index 0000000000..495ae2ab23 --- /dev/null +++ b/models/migrations/v1_23/v296.go @@ -0,0 +1,16 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_23 //nolint + +import "xorm.io/xorm" + +func AddCommitStatusSummary2(x *xorm.Engine) error { + type CommitStatusSummary struct { + ID int64 `xorm:"pk autoincr"` + TargetURL string `xorm:"TEXT"` + } + // there is no migrations because if there is no data on this table, it will fall back to get data + // from commit status + return x.Sync(new(CommitStatusSummary)) +} From 4c6e2da088cf092a9790df5c84b7b338508fede7 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Mon, 15 Apr 2024 01:22:14 +0800 Subject: [PATCH 112/370] Improve "must-change-password" logic and document (#30472) Unify the behaviors of "user create" and "user change-password". Co-authored-by: KN4CK3R <admin@oldschoolhack.me> --- cmd/admin_user_change_password.go | 14 +++---- cmd/admin_user_create.go | 38 +++++++++++-------- .../administration/command-line.en-us.md | 5 +-- models/db/engine.go | 4 +- 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/cmd/admin_user_change_password.go b/cmd/admin_user_change_password.go index 824d66d112..bd9063a8e4 100644 --- a/cmd/admin_user_change_password.go +++ b/cmd/admin_user_change_password.go @@ -36,6 +36,7 @@ var microcmdUserChangePassword = &cli.Command{ &cli.BoolFlag{ Name: "must-change-password", Usage: "User must change password", + Value: true, }, }, } @@ -57,23 +58,18 @@ func runChangePassword(c *cli.Context) error { return err } - var mustChangePassword optional.Option[bool] - if c.IsSet("must-change-password") { - mustChangePassword = optional.Some(c.Bool("must-change-password")) - } - opts := &user_service.UpdateAuthOptions{ Password: optional.Some(c.String("password")), - MustChangePassword: mustChangePassword, + MustChangePassword: optional.Some(c.Bool("must-change-password")), } if err := user_service.UpdateAuth(ctx, user, opts); err != nil { switch { case errors.Is(err, password.ErrMinLength): - return fmt.Errorf("Password is not long enough. Needs to be at least %d", setting.MinPasswordLength) + return fmt.Errorf("password is not long enough, needs to be at least %d characters", setting.MinPasswordLength) case errors.Is(err, password.ErrComplexity): - return errors.New("Password does not meet complexity requirements") + return errors.New("password does not meet complexity requirements") case errors.Is(err, password.ErrIsPwned): - return errors.New("The password you chose is on a list of stolen passwords previously exposed in public data breaches. Please try again with a different password.\nFor more details, see https://haveibeenpwned.com/Passwords") + return errors.New("the password is in a list of stolen passwords previously exposed in public data breaches, please try again with a different password, to see more details: https://haveibeenpwned.com/Passwords") default: return err } diff --git a/cmd/admin_user_create.go b/cmd/admin_user_create.go index a257ce21c8..403e3ee8d8 100644 --- a/cmd/admin_user_create.go +++ b/cmd/admin_user_create.go @@ -8,6 +8,7 @@ import ( "fmt" auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" pwd "code.gitea.io/gitea/modules/auth/password" "code.gitea.io/gitea/modules/optional" @@ -46,8 +47,9 @@ var microcmdUserCreate = &cli.Command{ Usage: "Generate a random password for the user", }, &cli.BoolFlag{ - Name: "must-change-password", - Usage: "Set this option to false to prevent forcing the user to change their password after initial login, (Default: true)", + Name: "must-change-password", + Usage: "Set to false to prevent forcing the user to change their password after initial login", + DisableDefaultText: true, }, &cli.IntFlag{ Name: "random-password-length", @@ -71,10 +73,10 @@ func runCreateUser(c *cli.Context) error { } if c.IsSet("name") && c.IsSet("username") { - return errors.New("Cannot set both --name and --username flags") + return errors.New("cannot set both --name and --username flags") } if !c.IsSet("name") && !c.IsSet("username") { - return errors.New("One of --name or --username flags must be set") + return errors.New("one of --name or --username flags must be set") } if c.IsSet("password") && c.IsSet("random-password") { @@ -110,17 +112,21 @@ func runCreateUser(c *cli.Context) error { return errors.New("must set either password or random-password flag") } - // always default to true - changePassword := true - - // If this is the first user being created. - // Take it as the admin and don't force a password update. - if n := user_model.CountUsers(ctx, nil); n == 0 { - changePassword = false - } - + isAdmin := c.Bool("admin") + mustChangePassword := true // always default to true if c.IsSet("must-change-password") { - changePassword = c.Bool("must-change-password") + // if the flag is set, use the value provided by the user + mustChangePassword = c.Bool("must-change-password") + } else { + // check whether there are users in the database + hasUserRecord, err := db.IsTableNotEmpty(&user_model.User{}) + if err != nil { + return fmt.Errorf("IsTableNotEmpty: %w", err) + } + if !hasUserRecord && isAdmin { + // if this is the first admin being created, don't force to change password (keep the old behavior) + mustChangePassword = false + } } restricted := optional.None[bool]() @@ -136,8 +142,8 @@ func runCreateUser(c *cli.Context) error { Name: username, Email: c.String("email"), Passwd: password, - IsAdmin: c.Bool("admin"), - MustChangePassword: changePassword, + IsAdmin: isAdmin, + MustChangePassword: mustChangePassword, Visibility: visibility, } diff --git a/docs/content/administration/command-line.en-us.md b/docs/content/administration/command-line.en-us.md index 5049df35e0..752a8d4c6f 100644 --- a/docs/content/administration/command-line.en-us.md +++ b/docs/content/administration/command-line.en-us.md @@ -83,8 +83,7 @@ Admin operations: - `--email value`: Email. Required. - `--admin`: If provided, this makes the user an admin. Optional. - `--access-token`: If provided, an access token will be created for the user. Optional. (default: false). - - `--must-change-password`: If provided, the created user will be required to choose a newer password after the - initial login. Optional. (default: true). + - `--must-change-password`: The created user will be required to set a new password after the initial login, default: true. It could be disabled by `--must-change-password=false`. - `--random-password`: If provided, a randomly generated password will be used as the password of the created user. The value of `--password` will be discarded. Optional. - `--random-password-length`: If provided, it will be used to configure the length of the randomly generated @@ -95,7 +94,7 @@ Admin operations: - Options: - `--username value`, `-u value`: Username. Required. - `--password value`, `-p value`: New password. Required. - - `--must-change-password`: If provided, the user is required to choose a new password after the login. Optional. + - `--must-change-password`: The user is required to set a new password after the login, default: true. It could be disabled by `--must-change-password=false`. - Examples: - `gitea admin user change-password --username myname --password asecurepassword` - `must-change-password`: diff --git a/models/db/engine.go b/models/db/engine.go index 8684c4e2f1..26abf0b96c 100755 --- a/models/db/engine.go +++ b/models/db/engine.go @@ -284,8 +284,8 @@ func MaxBatchInsertSize(bean any) int { } // IsTableNotEmpty returns true if table has at least one record -func IsTableNotEmpty(tableName string) (bool, error) { - return x.Table(tableName).Exist() +func IsTableNotEmpty(beanOrTableName any) (bool, error) { + return x.Table(beanOrTableName).Exist() } // DeleteAllRecords will delete all the records of this table From 99463532820d7a88cdea88e66e0606b996cc9fc7 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 14 Apr 2024 19:53:52 +0200 Subject: [PATCH 113/370] Remove fomantic button module (#30475) CSS-only module. Button colors are reduced to this: <img width="639" alt="Screenshot 2024-04-14 at 15 36 07" src="https://github.com/go-gitea/gitea/assets/115237/882d6c02-d1de-44f2-b707-db02a9f5070d"> --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> --- templates/admin/notice.tmpl | 2 +- templates/admin/repo/unadopted.tmpl | 2 +- templates/base/modal_actions_confirm.tmpl | 10 +- templates/devtest/fomantic-modal.tmpl | 31 +- templates/devtest/gitea-ui.tmpl | 42 +- templates/org/team/sidebar.tmpl | 2 +- .../code/recently_pushed_new_branches.tmpl | 2 +- templates/repo/diff/compare.tmpl | 24 +- .../repo/issue/view_content/sidebar.tmpl | 2 +- templates/repo/settings/lfs.tmpl | 2 +- templates/repo/settings/lfs_pointers.tmpl | 2 +- templates/repo/settings/webhook/history.tmpl | 2 +- templates/user/settings/applications.tmpl | 2 +- web_src/css/base.css | 8 - web_src/css/helpers.css | 3 + web_src/css/modules/button.css | 985 +++---- web_src/css/modules/modal.css | 4 + web_src/css/repo.css | 14 +- web_src/fomantic/build/semantic.css | 2318 ----------------- web_src/fomantic/semantic.json | 1 - .../js/components/PullRequestMergeForm.vue | 2 +- 21 files changed, 361 insertions(+), 3099 deletions(-) diff --git a/templates/admin/notice.tmpl b/templates/admin/notice.tmpl index 33d8a2f963..68703cc884 100644 --- a/templates/admin/notice.tmpl +++ b/templates/admin/notice.tmpl @@ -49,7 +49,7 @@ </div> </div> </div> - <button class="ui small teal button" id="delete-selection" data-link="{{.Link}}/delete" data-redirect="?page={{.Page.Paginater.Current}}"> + <button class="ui small button" id="delete-selection" data-link="{{.Link}}/delete" data-redirect="?page={{.Page.Paginater.Current}}"> <span class="text">{{ctx.Locale.Tr "admin.notices.delete_selected"}}</span> </button> </th> diff --git a/templates/admin/repo/unadopted.tmpl b/templates/admin/repo/unadopted.tmpl index 6a8e203694..a95f6b5120 100644 --- a/templates/admin/repo/unadopted.tmpl +++ b/templates/admin/repo/unadopted.tmpl @@ -54,7 +54,7 @@ <input type="hidden" name="action" value="delete"> <input type="hidden" name="q" value="{{$.Keyword}}"> <input type="hidden" name="page" value="{{$.CurrentPage}}"> - {{template "base/modal_actions_confirm" (dict "ModalButtonColors" "yellow")}} + {{template "base/modal_actions_confirm"}} </form> </div> </div> diff --git a/templates/base/modal_actions_confirm.tmpl b/templates/base/modal_actions_confirm.tmpl index c44320deff..9f7eb4adf2 100644 --- a/templates/base/modal_actions_confirm.tmpl +++ b/templates/base/modal_actions_confirm.tmpl @@ -1,7 +1,6 @@ {{/* Two buttons (negative, positive): * ModalButtonTypes: "yes" (default) or "confirm" -* ModalButtonColors: "primary" (default) / "blue" / "yellow" * ModalButtonCancelText * ModalButtonOkText @@ -22,14 +21,7 @@ The ".ok.button" and ".cancel.button" selectors are also used by Fomantic Modal {{end}} {{if .ModalButtonCancelText}}{{$textNegitive = .ModalButtonCancelText}}{{end}} {{if .ModalButtonOkText}}{{$textPositive = .ModalButtonOkText}}{{end}} - - {{$stylePositive := "primary"}} - {{if eq .ModalButtonColors "blue"}} - {{$stylePositive = "blue"}} - {{else if eq .ModalButtonColors "yellow"}} - {{$stylePositive = "yellow"}} - {{end}} <button class="ui cancel button">{{svg "octicon-x"}} {{$textNegitive}}</button> - <button class="ui {{$stylePositive}} ok button">{{svg "octicon-check"}} {{$textPositive}}</button> + <button class="ui primary ok button">{{svg "octicon-check"}} {{$textPositive}}</button> {{end}} </div> diff --git a/templates/devtest/fomantic-modal.tmpl b/templates/devtest/fomantic-modal.tmpl index 5cd36721a7..f31cdc1983 100644 --- a/templates/devtest/fomantic-modal.tmpl +++ b/templates/devtest/fomantic-modal.tmpl @@ -1,6 +1,15 @@ {{template "base/head" .}} <div class="page-content devtest ui container"> {{template "base/alert" .}} + <div class="modal-buttons flex-text-block tw-flex-wrap"></div> + <script type="module"> + for (const el of $('.ui.modal')) { + const $btn = $('<button class="ui button">').text(`${el.id}`).on('click', () => { + $(el).modal({onApprove() {alert('confirmed')}}).modal('show'); + }); + $('.modal-buttons').append($btn); + } + </script> <div id="test-modal-form-1" class="ui mini modal"> <div class="header">Form dialog (layout 1)</div> @@ -54,33 +63,11 @@ {{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}} </div> - <div class="ui g-modal-confirm modal" id="test-modal-blue"> - <div class="header">Blue dialog</div> - <div class="content">hello, this is the modal dialog content</div> - {{template "base/modal_actions_confirm" (dict "ModalButtonColors" "blue")}} - </div> - - <div class="ui g-modal-confirm modal" id="test-modal-yellow"> - <div class="header">yellow dialog</div> - <div class="content">hello, this is the modal dialog content</div> - {{template "base/modal_actions_confirm" (dict "ModalButtonColors" "yellow")}} - </div> - <div class="ui g-modal-confirm modal" id="test-modal-danger"> {{svg "octicon-x" 16 "inside close"}} <div class="header">dangerous action dialog</div> <div class="content">hello, this is the modal dialog content, this is a dangerous operation</div> {{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" "I know and must do this is dangerous operation")}} </div> - - <div class="modal-buttons flex-text-block tw-flex-wrap"></div> - <script type="module"> - for (const el of $('.ui.modal')) { - const $btn = $('<button>').text(`${el.id}`).on('click', () => { - $(el).modal({onApprove() {alert('confirmed')}}).modal('show'); - }); - $('.modal-buttons').append($btn); - } - </script> </div> {{template "base/footer" .}} diff --git a/templates/devtest/gitea-ui.tmpl b/templates/devtest/gitea-ui.tmpl index bb4fc77a74..3b13c13be8 100644 --- a/templates/devtest/gitea-ui.tmpl +++ b/templates/devtest/gitea-ui.tmpl @@ -29,41 +29,13 @@ <button class="ui basic button">Basic Unclassed</button> <button class="ui primary button">Primary</button> <button class="ui basic primary button">Basic Primary</button> - <button class="ui negative button">Negative</button> - <button class="ui basic negative button">Basic Negative</button> - <button class="ui positive button">Positive</button> - <button class="ui basic positive button">Basic Positive</button> </li> <li class="sample-group"> <h2>Recommended colors:</h2> <button class="ui red button">Red</button> <button class="ui basic red button">Basic Red</button> - <button class="ui primary button">Green</button> - <button class="ui basic primary button">Basic Green</button> - <button class="ui blue button">Blue</button> - <button class="ui basic blue button">Basic Blue</button> - <button class="ui orange button">Orange</button> - <button class="ui basic orange button">Basic Orange</button> - <button class="ui yellow button">Yellow</button> - <button class="ui basic yellow button">Basic Yellow</button> - </li> - <li class="sample-group"> - <h2>Supported but not recommended:</h2> - <p>Do not use if there is no strong requirement. Do not use grey/black buttons, they don't work well with dark theme.</p> - <button class="ui secondary button">Secondary</button> - <button class="ui basic secondary button">Basic Secondary</button> - <button class="ui olive button">Olive</button> - <button class="ui basic olive button">Basic Olive</button> - <button class="ui teal button">Teal</button> - <button class="ui basic teal button">Basic Teal</button> - <button class="ui violet button">Violet</button> - <button class="ui basic violet button">Basic Violet</button> - <button class="ui purple button">Purple</button> - <button class="ui basic purple button">Basic Purple</button> - <button class="ui pink button">Pink</button> - <button class="ui basic pink button">Basic Pink</button> - <button class="ui brown button">Brown</button> - <button class="ui basic brown button">Basic Brown</button> + <button class="ui green button">Green</button> + <button class="ui basic green button">Basic Green</button> </li> <li class="sample-group"> <h2>Inline / Plain:</h2> @@ -198,7 +170,7 @@ <button class="ui basic button">labeled button</button> <a class="ui basic label">123</a> </div> - <button class="ui yellow button">{{svg "octicon-x" 16}} button with very very very very very very very very long text</button> + <button class="ui button">{{svg "octicon-x" 16}} button with very very very very very very very very long text</button> </div> <h2>Input with SVG</h2> @@ -271,10 +243,6 @@ <span class="text">button dropdown</span> {{svg "octicon-triangle-down" 14 "dropdown icon"}} </div> - <div class="ui dropdown large button"> - <span class="text">large dropdown</span> - {{svg "octicon-triangle-down" 14 "dropdown icon"}} - </div> </div> <div> @@ -290,10 +258,6 @@ <span class="text">button compact</span> {{svg "octicon-triangle-down" 14 "dropdown icon"}} </div> - <div class="ui dropdown large compact button"> - <span class="text">large compact</span> - {{svg "octicon-triangle-down" 14 "dropdown icon"}} - </div> </div> <div> diff --git a/templates/org/team/sidebar.tmpl b/templates/org/team/sidebar.tmpl index 9311a46e38..b9e55dd587 100644 --- a/templates/org/team/sidebar.tmpl +++ b/templates/org/team/sidebar.tmpl @@ -79,7 +79,7 @@ </div> {{if .IsOrganizationOwner}} <div class="ui bottom attached segment"> - <a class="ui teal small button" href="{{.OrgLink}}/teams/{{.Team.LowerName | PathEscape}}/edit">{{svg "octicon-gear"}} {{ctx.Locale.Tr "org.teams.settings"}}</a> + <a class="ui small button" href="{{.OrgLink}}/teams/{{.Team.LowerName | PathEscape}}/edit">{{svg "octicon-gear"}} {{ctx.Locale.Tr "org.teams.settings"}}</a> </div> {{end}} </div> diff --git a/templates/repo/code/recently_pushed_new_branches.tmpl b/templates/repo/code/recently_pushed_new_branches.tmpl index 17ae7d119d..b808f413d3 100644 --- a/templates/repo/code/recently_pushed_new_branches.tmpl +++ b/templates/repo/code/recently_pushed_new_branches.tmpl @@ -5,7 +5,7 @@ {{$branchLink := HTMLFormat `<a href="%s/src/branch/%s">%s</a>` $.RepoLink (PathEscapeSegments .Name) .Name}} {{ctx.Locale.Tr "repo.pulls.recently_pushed_new_branches" $branchLink $timeSince}} </div> - <a role="button" class="ui compact positive button tw-m-0" href="{{$.Repository.ComposeBranchCompareURL $.Repository.BaseRepo .Name}}"> + <a role="button" class="ui compact green button tw-m-0" href="{{$.Repository.ComposeBranchCompareURL $.Repository.BaseRepo .Name}}"> {{ctx.Locale.Tr "repo.pulls.compare_changes"}} </a> </div> diff --git a/templates/repo/diff/compare.tmpl b/templates/repo/diff/compare.tmpl index d0472577d0..f927501197 100644 --- a/templates/repo/diff/compare.tmpl +++ b/templates/repo/diff/compare.tmpl @@ -184,23 +184,15 @@ {{end}} {{else if and .PageIsComparePull (gt .CommitCount 0)}} {{if .HasPullRequest}} - <div class="ui segment grid title"> - <div class="twelve wide column issue-title"> - {{ctx.Locale.Tr "repo.pulls.has_pull_request" (print $.RepoLink "/pulls/" .PullRequest.Issue.Index) $.RepoRelPath .PullRequest.Index}} - <h1> - <span id="issue-title">{{RenderIssueTitle $.Context .PullRequest.Issue.Title ($.Repository.ComposeMetas ctx)}}</span> - <span class="index">#{{.PullRequest.Issue.Index}}</span> - </h1> - </div> - <div class="four wide column middle aligned text right"> - {{- if .PullRequest.HasMerged -}} - <a href="{{$.RepoLink}}/pulls/{{.PullRequest.Issue.Index}}" class="ui button purple show-form">{{svg "octicon-git-merge" 16}} {{ctx.Locale.Tr "repo.pulls.view"}}</a> - {{else if .Issue.IsClosed}} - <a href="{{$.RepoLink}}/pulls/{{.PullRequest.Issue.Index}}" class="ui button red show-form">{{svg "octicon-issue-closed" 16}} {{ctx.Locale.Tr "repo.pulls.view"}}</a> - {{else}} - <a href="{{$.RepoLink}}/pulls/{{.PullRequest.Issue.Index}}" class="ui button primary show-form">{{svg "octicon-git-pull-request" 16}} {{ctx.Locale.Tr "repo.pulls.view"}}</a> - {{end}} + <div class="ui segment flex-text-block tw-gap-4"> + {{template "shared/issueicon" .}} + <div class="issue-title tw-break-anywhere"> + {{RenderIssueTitle $.Context .PullRequest.Issue.Title ($.Repository.ComposeMetas ctx) | RenderCodeBlock}} + <span class="index">#{{.PullRequest.Issue.Index}}</span> </div> + <a href="{{$.RepoLink}}/pulls/{{.PullRequest.Issue.Index}}" class="ui compact button primary"> + {{ctx.Locale.Tr "repo.pulls.view"}} + </a> </div> {{else}} {{if and $.IsSigned (not .Repository.IsArchived)}} diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index 7040c2849a..bb0bb2cff3 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -572,7 +572,7 @@ </form> {{end}} - <button class="tw-mt-1 fluid ui show-modal button {{if .Issue.IsLocked}} negative {{end}}" data-modal="#lock"> + <button class="tw-mt-1 fluid ui show-modal button{{if .Issue.IsLocked}} red{{end}}" data-modal="#lock"> {{if .Issue.IsLocked}} {{svg "octicon-key"}} {{ctx.Locale.Tr "repo.issues.unlock"}} diff --git a/templates/repo/settings/lfs.tmpl b/templates/repo/settings/lfs.tmpl index e0864ff221..bc92b4828b 100644 --- a/templates/repo/settings/lfs.tmpl +++ b/templates/repo/settings/lfs.tmpl @@ -44,7 +44,7 @@ </p> <form class="ui form" action="{{$.Link}}/delete/{{.Oid}}" method="post"> {{$.CsrfTokenHtml}} - {{template "base/modal_actions_confirm" (dict "ModalButtonColors" "yellow")}} + {{template "base/modal_actions_confirm"}} </form> </div> </div> diff --git a/templates/repo/settings/lfs_pointers.tmpl b/templates/repo/settings/lfs_pointers.tmpl index a0bb8c46f0..758aec6bb0 100644 --- a/templates/repo/settings/lfs_pointers.tmpl +++ b/templates/repo/settings/lfs_pointers.tmpl @@ -37,7 +37,7 @@ </a> </td> <td> - <a {{if and .Exists .InRepo}}href="{{$.LFSFilesLink}}/show/{{.Oid}}" rel="nofollow" target="_blank"{{end}} title="{{.Oid}}" class="ui brown button tw-font-mono"> + <a {{if and .Exists .InRepo}}href="{{$.LFSFilesLink}}/show/{{.Oid}}" rel="nofollow" target="_blank"{{end}} title="{{.Oid}}" class="ui button tw-font-mono"> {{ShortSha .Oid}} </a> </td> diff --git a/templates/repo/settings/webhook/history.tmpl b/templates/repo/settings/webhook/history.tmpl index 8ee1446a16..149840b0de 100644 --- a/templates/repo/settings/webhook/history.tmpl +++ b/templates/repo/settings/webhook/history.tmpl @@ -6,7 +6,7 @@ <div class="ui right"> <!-- the button is wrapped with a span because the tooltip doesn't show on hover if we put data-tooltip-content directly on the button --> <span data-tooltip-content="{{if or $isNew .Webhook.IsActive}}{{ctx.Locale.Tr "repo.settings.webhook.test_delivery_desc"}}{{else}}{{ctx.Locale.Tr "repo.settings.webhook.test_delivery_desc_disabled"}}{{end}}"> - <button class="ui teal tiny button{{if not (or $isNew .Webhook.IsActive)}} disabled{{end}}" id="test-delivery" data-link="{{.Link}}/test" data-redirect="{{.Link}}"> + <button class="ui tiny button{{if not (or $isNew .Webhook.IsActive)}} disabled{{end}}" id="test-delivery" data-link="{{.Link}}/test" data-redirect="{{.Link}}"> <span class="text">{{ctx.Locale.Tr "repo.settings.webhook.test_delivery"}}</span> </button> </span> diff --git a/templates/user/settings/applications.tmpl b/templates/user/settings/applications.tmpl index 5e2ffc3bb3..8baa07c90b 100644 --- a/templates/user/settings/applications.tmpl +++ b/templates/user/settings/applications.tmpl @@ -109,7 +109,7 @@ <div class="content"> <p>{{ctx.Locale.Tr "settings.access_token_deletion_desc"}}</p> </div> - {{template "base/modal_actions_confirm" (dict "ModalButtonColors" "yellow")}} + {{template "base/modal_actions_confirm"}} </div> {{template "user/settings/layout_footer" .}} diff --git a/web_src/css/base.css b/web_src/css/base.css index 20f3616177..b3f87044e0 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -663,10 +663,6 @@ input:-webkit-autofill:active, font-size: 0.75em; } -.ui.form .ui.button { - font-weight: var(--font-weight-normal); -} - /* popover box shadows */ .ui.dropdown .menu, .ui.upward.dropdown > .menu, @@ -1347,10 +1343,6 @@ table th[data-sortt-desc] .svg { vertical-align: middle; } -.ui.ui.button { - justify-content: center; -} - .ui.dropdown .ui.label .svg { vertical-align: middle; } diff --git a/web_src/css/helpers.css b/web_src/css/helpers.css index 118c058b19..cf2e73572c 100644 --- a/web_src/css/helpers.css +++ b/web_src/css/helpers.css @@ -52,6 +52,9 @@ only use: */ .tw-hidden.tw-hidden { display: none !important; } +/* proposed class from https://github.com/tailwindlabs/tailwindcss/pull/12128 */ +.tw-break-anywhere { overflow-wrap: anywhere !important; } + @media (max-width: 767.98px) { /* double selector so it wins over .tw-flex (old .gt-df) etc */ .not-mobile.not-mobile { diff --git a/web_src/css/modules/button.css b/web_src/css/modules/button.css index faeed8c9a1..47f55df7fa 100644 --- a/web_src/css/modules/button.css +++ b/web_src/css/modules/button.css @@ -1,11 +1,33 @@ -/* this contains override styles for buttons and related elements */ +/* based on Fomantic UI checkbox module, with just the parts extracted that we use. If you find any + unused rules here after refactoring, please remove them. */ -/* these styles changed the Fomantic UI's rules, Fomantic UI expects only "basic" buttons have borders */ -.ui.button, -.ui.button:focus { +.ui.button { + cursor: pointer; + display: inline-block; + min-height: 1em; + outline: none; + vertical-align: baseline; + font-family: var(--fonts-regular); + margin: 0 0.25em 0 0; + padding: 0.78571429em 1.5em; + font-weight: var(--font-weight-normal); + text-align: center; + text-decoration: none; + line-height: 1; + border-radius: 0.28571429rem; + user-select: none; + -webkit-tap-highlight-color: transparent; + justify-content: center; background: var(--color-button); border: 1px solid var(--color-light-border); color: var(--color-text); + white-space: nowrap; +} + +@media (max-width: 767.98px) { + .ui.button { + white-space: normal; + } } .ui.button:hover { @@ -13,10 +35,6 @@ color: var(--color-text); } -.page-content .ui.button { - box-shadow: none !important; -} - .ui.active.button, .ui.button:active, .ui.active.button:active, @@ -25,6 +43,286 @@ color: var(--color-text); } +.ui.buttons .disabled.button:not(.basic), +.ui.disabled.button, +.ui.button:disabled, +.ui.disabled.button:hover, +.ui.disabled.active.button { + cursor: default; + opacity: var(--opacity-disabled) !important; + background-image: none; + pointer-events: none !important; +} + +.ui.labeled.button:not(.icon) { + display: inline-flex; + flex-direction: row; + background: none; + padding: 0 !important; + border: none; +} +.ui.labeled.button > .button { + margin: 0; +} +.ui.labeled.button > .label { + display: flex; + align-items: center; + margin: 0 0 0 -1px !important; + font-size: 1em; + border-color: var(--color-light-border); +} + +.ui.button > .icon:not(.button) { + height: auto; + opacity: 0.8; +} +.ui.button:not(.icon) > .icon:not(.button):not(.dropdown), +.ui.button:not(.icon) > .icons:not(.button):not(.dropdown) { + margin: 0 0.42857143em 0 -0.21428571em; + vertical-align: baseline; +} +.ui.button:not(.icon) > .icons:not(.button):not(.dropdown) > .icon { + vertical-align: baseline; +} +.ui.button:not(.icon) > .right.icon:not(.button):not(.dropdown) { + margin: 0 -0.21428571em 0 0.42857143em; +} + +.ui.compact.buttons .button, +.ui.compact.button { + padding: 0.58928571em 1.125em; +} +.ui.compact.icon.buttons .button, +.ui.compact.icon.button { + padding: 0.58928571em; +} +.ui.compact.labeled.icon.button { + padding: 0.58928571em 3.69642857em; +} +.ui.compact.labeled.icon.button > .icon { + padding: 0.58928571em 0; +} + +.ui.buttons .button, +.ui.button { + font-size: 1rem; +} +.ui.mini.buttons .dropdown, +.ui.mini.buttons .dropdown .menu > .item, +.ui.mini.buttons .button, +.ui.ui.ui.ui.mini.button { + font-size: 0.78571429rem; +} +.ui.tiny.buttons .dropdown, +.ui.tiny.buttons .dropdown .menu > .item, +.ui.tiny.buttons .button, +.ui.ui.ui.ui.tiny.button { + font-size: 0.85714286rem; +} +.ui.small.buttons .dropdown, +.ui.small.buttons .dropdown .menu > .item, +.ui.small.buttons .button, +.ui.ui.ui.ui.small.button { + font-size: 0.92857143rem; +} + +.ui.icon.buttons .button, +.ui.icon.button:not(.compact) { + padding: 0.78571429em; +} +.ui.icon.buttons .button > .icon, +.ui.icon.button > .icon { + margin: 0 !important; + vertical-align: top; +} + +.ui.basic.buttons .button, +.ui.basic.button { + border-radius: 0.28571429rem; + background: none; +} +.ui.basic.buttons { + border: 1px solid var(--color-secondary); + border-radius: 0.28571429rem; +} +.ui.basic.buttons .button { + border-radius: 0; + border-left: 1px solid var(--color-secondary); +} + +.ui.labeled.button.disabled > .button, +.ui.basic.buttons .button, +.ui.basic.button { + color: var(--color-text-light); + background: var(--color-button); +} + +.ui.basic.buttons .button:hover, +.ui.basic.button:hover { + color: var(--color-text); + background: var(--color-hover); + border-color: var(--color-secondary-dark-2); +} + +.ui.basic.buttons .button:active, +.ui.basic.button:active, +.ui.basic.buttons .active.button, +.ui.basic.active.button, +.ui.basic.buttons .active.button:hover, +.ui.basic.active.button:hover { + color: var(--color-text); + background: var(--color-active); +} + +.ui.labeled.icon.button { + position: relative; + padding-left: 4.07142857em !important; + padding-right: 1.5em !important; +} + +.ui.labeled.icon.button > .icon { + position: absolute; + top: 0; + left: 0; + height: 100%; + line-height: 1; + border-radius: 0; + border-top-left-radius: inherit; + border-bottom-left-radius: inherit; + text-align: center; + animation: none; + padding: 0.78571429em 0; + margin: 0; + width: 2.57142857em; + background: var(--color-hover); +} + +.ui.button.toggle.active { + background-color: var(--color-green); + color: var(--color-white); +} +.ui.button.toggle.active:hover { + background-color: var(--color-green-dark-1); + color: var(--color-white); +} + +.ui.fluid.button { + width: 100%; + display: block; +} + +.ui.primary.button, +.ui.primary.buttons .button { + background: var(--color-primary); + color: var(--color-primary-contrast); +} + +.ui.primary.button:hover, +.ui.primary.buttons .button:hover { + background: var(--color-primary-hover); + color: var(--color-primary-contrast); +} + +.ui.primary.button:active, +.ui.primary.buttons .button:active { + background: var(--color-primary-active); +} + +.ui.basic.primary.buttons .button, +.ui.basic.primary.button { + color: var(--color-primary); + border-color: var(--color-primary); + background: none; +} + +.ui.basic.primary.buttons .button:hover, +.ui.basic.primary.button:hover { + color: var(--color-primary-hover); + border-color: var(--color-primary-hover); +} + +.ui.basic.primary.buttons .button:active, +.ui.basic.primary.button:active { + color: var(--color-primary-active); + border-color: var(--color-primary-active); +} + +.ui.red.button, +.ui.red.buttons .button { + background: var(--color-red); +} + +.ui.red.button:hover, +.ui.red.buttons .button:hover { + background: var(--color-red-dark-1); +} + +.ui.red.button:active, +.ui.red.buttons .button:active { + background: var(--color-red-dark-2); +} + +.ui.basic.red.buttons .button, +.ui.basic.red.button { + color: var(--color-red); + border-color: var(--color-red); + background: none; +} + +.ui.basic.red.buttons .button:hover, +.ui.basic.red.button:hover { + color: var(--color-red-dark-1); + border-color: var(--color-red-dark-1); +} + +.ui.basic.red.buttons .button:active, +.ui.basic.red.button:active { + color: var(--color-red-dark-2); + border-color: var(--color-red-dark-2); +} + +.ui.green.button, +.ui.green.buttons .button { + background: var(--color-green); +} + +.ui.green.button:hover, +.ui.green.buttons .button:hover { + background: var(--color-green-dark-1); +} + +.ui.green.button:active, +.ui.green.buttons .button:active { + background: var(--color-green-dark-2); +} + +.ui.basic.green.buttons .button, +.ui.basic.green.button { + color: var(--color-green); + border-color: var(--color-green); + background: none; +} + +.ui.basic.green.buttons .button:hover, +.ui.basic.green.button:hover { + color: var(--color-green-dark-1); + border-color: var(--color-green-dark-1); +} + +.ui.basic.green.buttons .button:active, +.ui.basic.green.button:active { + color: var(--color-green-dark-2); + border-color: var(--color-green-dark-2); +} + +.ui.buttons { + display: inline-flex; + flex-direction: row; + font-size: 0; + vertical-align: baseline; + margin: 0 0.25em 0 0; +} + .delete-button, .delete-button:hover { color: var(--color-red); @@ -42,8 +340,7 @@ } .btn:hover, -.btn:active, -.btn:focus { +.btn:active { background: none; border: none; } @@ -59,6 +356,19 @@ It needs some tricks to tweak the left/right borders with active state */ .ui.buttons .button { border-right: none; + flex: 1 0 auto; + border-radius: 0; + margin: 0; +} +.ui.buttons .button:first-child { + border-left: none; + margin-left: 0; + border-top-left-radius: 0.28571429rem; + border-bottom-left-radius: 0.28571429rem; +} +.ui.buttons .button:last-child { + border-top-right-radius: 0.28571429rem; + border-bottom-right-radius: 0.28571429rem; } .ui.buttons .button:hover { @@ -89,664 +399,9 @@ It needs some tricks to tweak the left/right borders with active state */ border-left: none; } -.ui.basic.buttons .button, -.ui.basic.button, -.ui.basic.buttons .button:hover, -.ui.basic.button:hover { - box-shadow: none; -} - /* apply the vertical padding of .compact to non-compact buttons when they contain a svg as they would otherwise appear too large. Seen on "RSS Feed" button on repo releases tab. */ .ui.small.button:not(.compact):has(.svg) { padding-top: 0.58928571em; padding-bottom: 0.58928571em; } - -.ui.labeled.button.disabled > .button, -.ui.basic.buttons .button, -.ui.basic.button, -.ui.basic.buttons .button:focus, -.ui.basic.button:focus { - color: var(--color-text-light); - background: var(--color-button); -} - -.ui.basic.buttons .button:hover, -.ui.basic.button:hover { - color: var(--color-text); - background: var(--color-hover); - border-color: var(--color-secondary-dark-2); -} - -.ui.basic.buttons .button:active, -.ui.basic.button:active, -.ui.basic.buttons .active.button, -.ui.basic.active.button, -.ui.basic.buttons .active.button:hover, -.ui.basic.active.button:hover { - color: var(--color-text); - background: var(--color-active); -} - -.ui.labeled.button > .label { - border-color: var(--color-light-border); -} - -.ui.labeled.icon.buttons > .button > .icon, -.ui.labeled.icon.button > .icon { - background: var(--color-hover); -} - -/* primary */ - -.ui.primary.labels .label, -.ui.ui.ui.primary.label, -.ui.primary.button, -.ui.primary.buttons .button, -.ui.primary.button:focus, -.ui.primary.buttons .button:focus { - background: var(--color-primary); - color: var(--color-primary-contrast); -} - -.ui.primary.button:hover, -.ui.primary.buttons .button:hover { - background: var(--color-primary-hover); - color: var(--color-primary-contrast); -} - -.ui.primary.button:active, -.ui.primary.buttons .button:active { - background: var(--color-primary-active); -} - -.ui.basic.primary.buttons .button, -.ui.basic.primary.button, -.ui.basic.primary.buttons .button:focus, -.ui.basic.primary.button:focus { - color: var(--color-primary); - border-color: var(--color-primary); -} - -.ui.basic.primary.buttons .button:hover, -.ui.basic.primary.button:hover { - color: var(--color-primary-hover); - border-color: var(--color-primary-hover); -} - -.ui.basic.primary.buttons .button:active, -.ui.basic.primary.button:active { - color: var(--color-primary-active); - border-color: var(--color-primary-active); -} - -/* secondary */ - -.ui.secondary.labels .label, -.ui.ui.ui.secondary.label, -.ui.secondary.button, -.ui.secondary.buttons .button, -.ui.secondary.button:focus, -.ui.secondary.buttons .button:focus { - background: var(--color-secondary-button); -} - -.ui.secondary.button:hover, -.ui.secondary.buttons .button:hover { - background: var(--color-secondary-hover); -} - -.ui.secondary.button:active, -.ui.secondary.buttons .button:active { - background: var(--color-secondary-active); -} - -.ui.basic.secondary.buttons .button, -.ui.basic.secondary.button, -.ui.basic.secondary.button:focus, -.ui.basic.secondary.buttons .button:focus { - color: var(--color-secondary-button); - border-color: var(--color-secondary-button); -} - -.ui.basic.secondary.buttons .button:hover, -.ui.basic.secondary.button:hover { - color: var(--color-secondary-hover); - border-color: var(--color-secondary-hover); -} - -.ui.basic.secondary.buttons .button:active, -.ui.basic.secondary.button:active { - color: var(--color-secondary-active); - border-color: var(--color-secondary-active); -} - -/* red */ - -.ui.red.labels .label, -.ui.ui.ui.red.label, -.ui.red.button, -.ui.red.buttons .button, -.ui.red.button:focus, -.ui.red.buttons .button:focus { - background: var(--color-red); -} - -.ui.red.button:hover, -.ui.red.buttons .button:hover { - background: var(--color-red-dark-1); -} - -.ui.red.button:active, -.ui.red.buttons .button:active { - background: var(--color-red-dark-2); -} - -.ui.basic.red.buttons .button, -.ui.basic.red.button, -.ui.basic.red.buttons .button:focus, -.ui.basic.red.button:focus { - color: var(--color-red); - border-color: var(--color-red); -} - -.ui.basic.red.buttons .button:hover, -.ui.basic.red.button:hover { - color: var(--color-red-dark-1); - border-color: var(--color-red-dark-1); -} - -.ui.basic.red.buttons .button:active, -.ui.basic.red.button:active { - color: var(--color-red-dark-2); - border-color: var(--color-red-dark-2); -} - -/* orange */ - -.ui.orange.labels .label, -.ui.ui.ui.orange.label, -.ui.orange.button, -.ui.orange.buttons .button, -.ui.orange.button:focus, -.ui.orange.buttons .button:focus { - background: var(--color-orange); -} - -.ui.orange.button:hover, -.ui.orange.buttons .button:hover { - background: var(--color-orange-dark-1); -} - -.ui.orange.button:active, -.ui.orange.buttons .button:active { - background: var(--color-orange-dark-2); -} - -.ui.basic.orange.buttons .button, -.ui.basic.orange.button, -.ui.basic.orange.buttons .button:focus, -.ui.basic.orange.button:focus { - color: var(--color-orange); - border-color: var(--color-orange); -} - -.ui.basic.orange.buttons .button:hover, -.ui.basic.orange.button:hover { - color: var(--color-orange-dark-1); - border-color: var(--color-orange-dark-1); -} - -.ui.basic.orange.buttons .button:active, -.ui.basic.orange.button:active { - color: var(--color-orange-dark-2); - border-color: var(--color-orange-dark-2); -} - -/* yellow */ - -.ui.yellow.labels .label, -.ui.ui.ui.yellow.label, -.ui.yellow.button, -.ui.yellow.buttons .button, -.ui.yellow.button:focus, -.ui.yellow.buttons .button:focus { - background: var(--color-yellow); -} - -.ui.yellow.button:hover, -.ui.yellow.buttons .button:hover { - background: var(--color-yellow-dark-1); -} - -.ui.yellow.button:active, -.ui.yellow.buttons .button:active { - background: var(--color-yellow-dark-2); -} - -.ui.basic.yellow.buttons .button, -.ui.basic.yellow.button, -.ui.basic.yellow.buttons .button:focus, -.ui.basic.yellow.button:focus { - color: var(--color-yellow); - border-color: var(--color-yellow); -} - -.ui.basic.yellow.buttons .button:hover, -.ui.basic.yellow.button:hover { - color: var(--color-yellow-dark-1); - border-color: var(--color-yellow-dark-1); -} - -.ui.basic.yellow.buttons .button:active, -.ui.basic.yellow.button:active { - color: var(--color-yellow-dark-2); - border-color: var(--color-yellow-dark-2); -} - -/* olive */ - -.ui.olive.labels .label, -.ui.ui.ui.olive.label, -.ui.olive.button, -.ui.olive.buttons .button, -.ui.olive.button:focus, -.ui.olive.buttons .button:focus { - background: var(--color-olive); -} - -.ui.olive.button:hover, -.ui.olive.buttons .button:hover { - background: var(--color-olive-dark-1); -} - -.ui.olive.button:active, -.ui.olive.buttons .button:active { - background: var(--color-olive-dark-2); -} - -.ui.basic.olive.buttons .button, -.ui.basic.olive.button, -.ui.basic.olive.buttons .button:focus, -.ui.basic.olive.button:focus { - color: var(--color-olive); - border-color: var(--color-olive); -} - -.ui.basic.olive.buttons .button:hover, -.ui.basic.olive.button:hover { - color: var(--color-olive-dark-1); - border-color: var(--color-olive-dark-1); -} - -.ui.basic.olive.buttons .button:active, -.ui.basic.olive.button:active { - color: var(--color-olive-dark-2); - border-color: var(--color-olive-dark-2); -} - -/* green */ - -.ui.green.labels .label, -.ui.ui.ui.green.label, -.ui.green.button, -.ui.green.buttons .button, -.ui.green.button:focus, -.ui.green.buttons .button:focus { - background: var(--color-green); -} - -.ui.green.button:hover, -.ui.green.buttons .button:hover { - background: var(--color-green-dark-1); -} - -.ui.green.button:active, -.ui.green.buttons .button:active { - background: var(--color-green-dark-2); -} - -.ui.basic.green.buttons .button, -.ui.basic.green.button, -.ui.basic.green.buttons .button:focus, -.ui.basic.green.button:focus { - color: var(--color-green); - border-color: var(--color-green); -} - -.ui.basic.green.buttons .button:hover, -.ui.basic.green.button:hover { - color: var(--color-green-dark-1); - border-color: var(--color-green-dark-1); -} - -.ui.basic.green.buttons .button:active, -.ui.basic.green.button:active { - color: var(--color-green-dark-2); - border-color: var(--color-green-dark-2); -} - -/* teal */ - -.ui.teal.labels .label, -.ui.ui.ui.teal.label, -.ui.teal.button, -.ui.teal.buttons .button, -.ui.teal.button:focus, -.ui.teal.buttons .button:focus { - background: var(--color-teal); -} - -.ui.teal.button:hover, -.ui.teal.buttons .button:hover { - background: var(--color-teal-dark-1); -} - -.ui.teal.button:active, -.ui.teal.buttons .button:active { - background: var(--color-teal-dark-2); -} - -.ui.basic.teal.buttons .button, -.ui.basic.teal.button, -.ui.basic.teal.buttons .button:focus, -.ui.basic.teal.button:focus { - color: var(--color-teal); - border-color: var(--color-teal); -} - -.ui.basic.teal.buttons .button:hover, -.ui.basic.teal.button:hover { - color: var(--color-teal-dark-1); - border-color: var(--color-teal-dark-1); -} - -.ui.basic.teal.buttons .button:active, -.ui.basic.teal.button:active { - color: var(--color-teal-dark-2); - border-color: var(--color-teal-dark-2); -} - -/* blue */ - -.ui.blue.labels .label, -.ui.ui.ui.blue.label, -.ui.blue.button, -.ui.blue.buttons .button, -.ui.blue.button:focus, -.ui.blue.buttons .button:focus { - background: var(--color-blue); -} - -.ui.blue.button:hover, -.ui.blue.buttons .button:hover { - background: var(--color-blue-dark-1); -} - -.ui.blue.button:active, -.ui.blue.buttons .button:active { - background: var(--color-blue-dark-2); -} - -.ui.basic.blue.buttons .button, -.ui.basic.blue.button, -.ui.basic.blue.buttons .button:focus, -.ui.basic.blue.button:focus { - color: var(--color-blue); - border-color: var(--color-blue); -} - -.ui.basic.blue.buttons .button:hover, -.ui.basic.blue.button:hover { - color: var(--color-blue-dark-1); - border-color: var(--color-blue-dark-1); -} - -.ui.basic.blue.buttons .button:active, -.ui.basic.blue.button:active { - color: var(--color-blue-dark-2); - border-color: var(--color-blue-dark-2); -} - -/* violet */ - -.ui.violet.labels .label, -.ui.ui.ui.violet.label, -.ui.violet.button, -.ui.violet.buttons .button, -.ui.violet.button:focus, -.ui.violet.buttons .button:focus { - background: var(--color-violet); -} - -.ui.violet.button:hover, -.ui.violet.buttons .button:hover { - background: var(--color-violet-dark-1); -} - -.ui.violet.button:active, -.ui.violet.buttons .button:active { - background: var(--color-violet-dark-2); -} - -.ui.basic.violet.buttons .button, -.ui.basic.violet.button, -.ui.basic.violet.buttons .button:focus, -.ui.basic.violet.button:focus { - color: var(--color-violet); - border-color: var(--color-violet); -} - -.ui.basic.violet.buttons .button:hover, -.ui.basic.violet.button:hover { - color: var(--color-violet-dark-1); - border-color: var(--color-violet-dark-1); -} - -.ui.basic.violet.buttons .button:active, -.ui.basic.violet.button:active { - color: var(--color-violet-dark-2); - border-color: var(--color-violet-dark-2); -} - -/* purple */ - -.ui.purple.labels .label, -.ui.ui.ui.purple.label, -.ui.purple.button, -.ui.purple.buttons .button, -.ui.purple.button:focus, -.ui.purple.buttons .button:focus { - background: var(--color-purple); -} - -.ui.purple.button:hover, -.ui.purple.buttons .button:hover { - background: var(--color-purple-dark-1); -} - -.ui.purple.button:active, -.ui.purple.buttons .button:active { - background: var(--color-purple-dark-2); -} - -.ui.basic.purple.buttons .button, -.ui.basic.purple.button, -.ui.basic.purple.buttons .button:focus, -.ui.basic.purple.button:focus { - color: var(--color-purple); - border-color: var(--color-purple); -} - -.ui.basic.purple.buttons .button:hover, -.ui.basic.purple.button:hover { - color: var(--color-purple-dark-1); - border-color: var(--color-purple-dark-1); -} - -.ui.basic.purple.buttons .button:active, -.ui.basic.purple.button:active { - color: var(--color-purple-dark-2); - border-color: var(--color-purple-dark-2); -} - -/* pink */ - -.ui.pink.labels .label, -.ui.ui.ui.pink.label, -.ui.pink.button, -.ui.pink.buttons .button, -.ui.pink.button:focus, -.ui.pink.buttons .button:focus { - background: var(--color-pink); -} - -.ui.pink.button:hover, -.ui.pink.buttons .button:hover { - background: var(--color-pink-dark-1); -} - -.ui.pink.button:active, -.ui.pink.buttons .button:active { - background: var(--color-pink-dark-2); -} - -.ui.basic.pink.buttons .button, -.ui.basic.pink.button, -.ui.basic.pink.buttons .button:focus, -.ui.basic.pink.button:focus { - color: var(--color-pink); - border-color: var(--color-pink); -} - -.ui.basic.pink.buttons .button:hover, -.ui.basic.pink.button:hover { - color: var(--color-pink-dark-1); - border-color: var(--color-pink-dark-1); -} - -.ui.basic.pink.buttons .button:active, -.ui.basic.pink.button:active { - color: var(--color-pink-dark-2); - border-color: var(--color-pink-dark-2); -} - -/* brown */ - -.ui.brown.labels .label, -.ui.ui.ui.brown.label, -.ui.brown.button, -.ui.brown.buttons .button, -.ui.brown.button:focus, -.ui.brown.buttons .button:focus { - background: var(--color-brown); -} - -.ui.brown.button:hover, -.ui.brown.buttons .button:hover { - background: var(--color-brown-dark-1); -} - -.ui.brown.button:active, -.ui.brown.buttons .button:active { - background: var(--color-brown-dark-2); -} - -.ui.basic.brown.buttons .button, -.ui.basic.brown.button, -.ui.basic.brown.buttons .button:focus, -.ui.basic.brown.button:focus { - color: var(--color-brown); - border-color: var(--color-brown); -} - -.ui.basic.brown.buttons .button:hover, -.ui.basic.brown.button:hover { - color: var(--color-brown-dark-1); - border-color: var(--color-brown-dark-1); -} - -.ui.basic.brown.buttons .button:active, -.ui.basic.brown.button:active { - color: var(--color-brown-dark-2); - border-color: var(--color-brown-dark-2); -} - -/* negative */ - -.ui.negative.buttons .button, -.ui.negative.button, -.ui.negative.buttons .button:focus, -.ui.negative.button:focus { - background: var(--color-red); -} - -.ui.negative.buttons .button:hover, -.ui.negative.button:hover { - background: var(--color-red-dark-1); -} - -.ui.negative.buttons .button:active, -.ui.negative.button:active { - background: var(--color-red-dark-2); -} - -.ui.basic.negative.buttons .button, -.ui.basic.negative.button, -.ui.basic.negative.buttons .button:focus, -.ui.basic.negative.button:focus { - color: var(--color-red); - border-color: var(--color-red); -} - -.ui.basic.negative.buttons .button:hover, -.ui.basic.negative.button:hover { - color: var(--color-red-dark-1); - border-color: var(--color-red-dark-1); -} - -.ui.basic.negative.buttons .button:active, -.ui.basic.negative.button:active { - color: var(--color-red-dark-2); - border-color: var(--color-red-dark-2); -} - -/* positive */ - -.ui.positive.buttons .button, -.ui.positive.button, -.ui.positive.buttons .button:focus, -.ui.positive.button:focus { - background: var(--color-green); -} - -.ui.positive.buttons .button:hover, -.ui.positive.button:hover { - background: var(--color-green-dark-1); -} - -.ui.positive.buttons .button:active, -.ui.positive.button:active { - background: var(--color-green-dark-2); -} - -.ui.basic.positive.buttons .button, -.ui.basic.positive.button, -.ui.basic.positive.buttons .button:focus, -.ui.basic.positive.button:focus { - color: var(--color-green); - border-color: var(--color-green); -} - -.ui.basic.positive.buttons .button:hover, -.ui.basic.positive.button:hover { - color: var(--color-green-dark-1); - border-color: var(--color-green-dark-1); -} - -.ui.basic.positive.buttons .button:active, -.ui.basic.positive.button:active { - color: var(--color-green-dark-2); - border-color: var(--color-green-dark-2); -} diff --git a/web_src/css/modules/modal.css b/web_src/css/modules/modal.css index 54a4ef81ca..a2acfeaa15 100644 --- a/web_src/css/modules/modal.css +++ b/web_src/css/modules/modal.css @@ -10,6 +10,10 @@ top: 1.2em; } +.ui.modal > .close.inside { + color: inherit; +} + .ui.modal > .close.icon[height="16"] { top: 0.7em; /* fomantic uses absolute layout, so if we have special icon size, it needs this trick to align vertically */ color: var(--color-text-dark); diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 52f9d5a6ca..887789115e 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -654,15 +654,15 @@ td .commit-summary { padding: 2px .5rem; } -.repository.view.issue .issue-title .index { +.issue-title .index { color: var(--color-text-light-2); } -.repository.view.issue .issue-title .label { +.issue-title .label { margin-right: 10px; } -.repository.view.issue .issue-title .edit-zone { +.issue-title .edit-zone { margin-top: 10px; } @@ -1164,14 +1164,6 @@ td .commit-summary { font-size: 14px; } -.repository.compare.pull .title .issue-title { - margin-bottom: 0.5rem; -} - -.repository.compare.pull .title .issue-title .index { - color: var(--color-text-light-2); -} - .repository .ui.dropdown.filter > .menu { margin-top: 1px; } diff --git a/web_src/fomantic/build/semantic.css b/web_src/fomantic/build/semantic.css index 8ce9ee24ea..7c404bdb30 100644 --- a/web_src/fomantic/build/semantic.css +++ b/web_src/fomantic/build/semantic.css @@ -8,2324 +8,6 @@ * http://opensource.org/licenses/MIT * */ -/*! - * # Fomantic-UI - Button - * http://github.com/fomantic/Fomantic-UI/ - * - * - * Released under the MIT license - * http://opensource.org/licenses/MIT - * - */ - -/******************************* - Button -*******************************/ - -.ui.button { - cursor: pointer; - display: inline-block; - min-height: 1em; - outline: none; - border: none; - vertical-align: baseline; - background: #E0E1E2 none; - color: rgba(0, 0, 0, 0.6); - font-family: var(--fonts-regular); - margin: 0 0.25em 0 0; - padding: 0.78571429em 1.5em 0.78571429em; - text-transform: none; - text-shadow: none; - font-weight: 500; - line-height: 1em; - font-style: normal; - text-align: center; - text-decoration: none; - border-radius: 0.28571429rem; - box-shadow: 0 0 0 1px transparent inset, 0 0 0 0 rgba(34, 36, 38, 0.15) inset; - -webkit-user-select: none; - -moz-user-select: none; - user-select: none; - transition: opacity 0.1s ease, background-color 0.1s ease, color 0.1s ease, box-shadow 0.1s ease, background 0.1s ease; - will-change: auto; - -webkit-tap-highlight-color: transparent; -} - -/******************************* - States -*******************************/ - -/*-------------- - Hover ----------------*/ - -.ui.button:hover { - background-color: #CACBCD; - background-image: none; - box-shadow: 0 0 0 1px transparent inset, 0 0 0 0 rgba(34, 36, 38, 0.15) inset; - color: rgba(0, 0, 0, 0.8); -} - -.ui.button:hover .icon { - opacity: 0.85; -} - -/*-------------- - Focus ----------------*/ - -.ui.button:focus { - background-color: #CACBCD; - color: rgba(0, 0, 0, 0.8); - background-image: none; - box-shadow: ''; -} - -.ui.button:focus .icon { - opacity: 0.85; -} - -/*-------------- - Down ----------------*/ - -.ui.button:active, -.ui.active.button:active { - background-color: #BABBBC; - background-image: ''; - color: rgba(0, 0, 0, 0.9); - box-shadow: 0 0 0 1px transparent inset, none; -} - -/*-------------- - Active ----------------*/ - -.ui.active.button { - background-color: #C0C1C2; - background-image: none; - box-shadow: 0 0 0 1px transparent inset; - color: rgba(0, 0, 0, 0.95); -} - -.ui.active.button:hover { - background-color: #C0C1C2; - background-image: none; - color: rgba(0, 0, 0, 0.95); -} - -.ui.active.button:active { - background-color: #C0C1C2; - background-image: none; -} - -/*-------------- - Loading ----------------*/ - -/* Specificity hack */ - -.ui.loading.loading.loading.loading.loading.loading.button { - position: relative; - cursor: default; - text-shadow: none !important; - color: transparent; - opacity: 1; - pointer-events: auto; - transition: all 0s linear, opacity 0.1s ease; -} - -.ui.loading.button:before { - position: absolute; - content: ''; - top: 50%; - left: 50%; - margin: -0.64285714em 0 0 -0.64285714em; - width: 1.28571429em; - height: 1.28571429em; - border-radius: 500rem; - border: 0.2em solid rgba(0, 0, 0, 0.15); -} - -.ui.loading.button:after { - position: absolute; - content: ''; - top: 50%; - left: 50%; - margin: -0.64285714em 0 0 -0.64285714em; - width: 1.28571429em; - height: 1.28571429em; - border-radius: 500rem; - animation: loader 0.6s infinite linear; - border: 0.2em solid currentColor; - color: #FFFFFF; - box-shadow: 0 0 0 1px transparent; -} - -.ui.labeled.icon.loading.button .icon { - background-color: transparent; - box-shadow: none; -} - -.ui.basic.loading.button:not(.inverted):before { - border-color: rgba(0, 0, 0, 0.1); -} - -.ui.basic.loading.button:not(.inverted):after { - border-color: #767676; -} - -/*------------------- - Disabled - --------------------*/ - -.ui.buttons .disabled.button:not(.basic), -.ui.disabled.button, -.ui.button:disabled, -.ui.disabled.button:hover, -.ui.disabled.active.button { - cursor: default; - opacity: var(--opacity-disabled) !important; - background-image: none; - box-shadow: none; - pointer-events: none !important; -} - -/* Basic Group With Disabled */ - -.ui.basic.buttons .ui.disabled.button { - border-color: rgba(34, 36, 38, 0.5); -} - -/******************************* - Types -*******************************/ - -/*------------------- - Labeled Button - --------------------*/ - -.ui.labeled.button:not(.icon) { - display: inline-flex; - flex-direction: row; - background: none; - padding: 0 !important; - border: none; - box-shadow: none; -} - -.ui.labeled.button > .button { - margin: 0; -} - -.ui.labeled.button > .label { - display: flex; - align-items: center; - margin: 0 0 0 -1px !important; - font-size: 1em; - padding: ''; - border-color: rgba(34, 36, 38, 0.15); -} - -/* Tag */ - -.ui.labeled.button > .tag.label:before { - width: 1.85em; - height: 1.85em; -} - -/* Right */ - -.ui.labeled.button:not([class*="left labeled"]) > .button { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} - -.ui.labeled.button:not([class*="left labeled"]) > .label { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} - -/* Left Side */ - -.ui[class*="left labeled"].button > .button { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} - -.ui[class*="left labeled"].button > .label { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} - -/*-------------- - Icon ----------------*/ - -.ui.button > .icon:not(.button) { - height: auto; - opacity: 0.8; - transition: opacity 0.1s ease; - color: ''; -} - -.ui.button:not(.icon) > .icon:not(.button):not(.dropdown), -.ui.button:not(.icon) > .icons:not(.button):not(.dropdown) { - margin: 0 0.42857143em 0 -0.21428571em; - vertical-align: baseline; -} - -.ui.button:not(.icon) > .icons:not(.button):not(.dropdown) > .icon { - vertical-align: baseline; -} - -.ui.button:not(.icon) > .right.icon:not(.button):not(.dropdown) { - margin: 0 -0.21428571em 0 0.42857143em; -} - -/******************************* - Variations -*******************************/ - -/*------------------- - Floated - --------------------*/ - -.ui[class*="left floated"].buttons, -.ui[class*="left floated"].button { - float: left; - margin-left: 0; - margin-right: 0.25em; -} - -.ui[class*="right floated"].buttons, -.ui[class*="right floated"].button { - float: right; - margin-right: 0; - margin-left: 0.25em; -} - -/*------------------- - Compact - --------------------*/ - -.ui.compact.buttons .button, -.ui.compact.button { - padding: 0.58928571em 1.125em 0.58928571em; -} - -.ui.compact.icon.buttons .button, -.ui.compact.icon.button { - padding: 0.58928571em 0.58928571em 0.58928571em; -} - -.ui.compact.labeled.icon.buttons .button, -.ui.compact.labeled.icon.button { - padding: 0.58928571em 3.69642857em 0.58928571em; -} - -.ui.compact.labeled.icon.buttons .button > .icon, -.ui.compact.labeled.icon.button > .icon { - padding: 0.58928571em 0 0.58928571em 0; -} - -/*------------------- - Sizes ---------------------*/ - -.ui.buttons .button, -.ui.buttons .or, -.ui.button { - font-size: 1rem; -} - -.ui.mini.buttons .dropdown, -.ui.mini.buttons .dropdown .menu > .item, -.ui.mini.buttons .button, -.ui.mini.buttons .or, -.ui.ui.ui.ui.mini.button { - font-size: 0.78571429rem; -} - -.ui.tiny.buttons .dropdown, -.ui.tiny.buttons .dropdown .menu > .item, -.ui.tiny.buttons .button, -.ui.tiny.buttons .or, -.ui.ui.ui.ui.tiny.button { - font-size: 0.85714286rem; -} - -.ui.small.buttons .dropdown, -.ui.small.buttons .dropdown .menu > .item, -.ui.small.buttons .button, -.ui.small.buttons .or, -.ui.ui.ui.ui.small.button { - font-size: 0.92857143rem; -} - -.ui.large.buttons .dropdown, -.ui.large.buttons .dropdown .menu > .item, -.ui.large.buttons .button, -.ui.large.buttons .or, -.ui.ui.ui.ui.large.button { - font-size: 1.14285714rem; -} - -.ui.big.buttons .dropdown, -.ui.big.buttons .dropdown .menu > .item, -.ui.big.buttons .button, -.ui.big.buttons .or, -.ui.ui.ui.ui.big.button { - font-size: 1.28571429rem; -} - -.ui.huge.buttons .dropdown, -.ui.huge.buttons .dropdown .menu > .item, -.ui.huge.buttons .button, -.ui.huge.buttons .or, -.ui.ui.ui.ui.huge.button { - font-size: 1.42857143rem; -} - -.ui.massive.buttons .dropdown, -.ui.massive.buttons .dropdown .menu > .item, -.ui.massive.buttons .button, -.ui.massive.buttons .or, -.ui.ui.ui.ui.massive.button { - font-size: 1.71428571rem; -} - -/*-------------- - Icon Only ----------------*/ - -.ui.icon.buttons .button, -.ui.icon.button:not(.animated):not(.compact) { - padding: 0.78571429em 0.78571429em 0.78571429em; -} - -.ui.animated.icon.button > .content > .icon, -.ui.icon.buttons .button > .icon, -.ui.icon.button > .icon { - opacity: 0.9; - margin: 0 !important; - vertical-align: top; -} - -.ui.animated.button > .content > .icon { - vertical-align: top; -} - -/*------------------- - Basic - --------------------*/ - -.ui.basic.buttons .button, -.ui.basic.button { - background: transparent none; - color: rgba(0, 0, 0, 0.6); - font-weight: normal; - border-radius: 0.28571429rem; - text-transform: none; - text-shadow: none !important; - box-shadow: 0 0 0 1px rgba(34, 36, 38, 0.15) inset; -} - -.ui.basic.buttons { - box-shadow: none; - border: 1px solid rgba(34, 36, 38, 0.15); - border-radius: 0.28571429rem; -} - -.ui.basic.buttons .button { - border-radius: 0; -} - -.ui.basic.buttons .button:hover, -.ui.basic.button:hover { - background: #FFFFFF; - color: rgba(0, 0, 0, 0.8); - box-shadow: 0 0 0 1px rgba(34, 36, 38, 0.35) inset, 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.basic.buttons .button:focus, -.ui.basic.button:focus { - background: #FFFFFF; - color: rgba(0, 0, 0, 0.8); - box-shadow: 0 0 0 1px rgba(34, 36, 38, 0.35) inset, 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.basic.buttons .button:active, -.ui.basic.button:active { - background: #F8F8F8; - color: rgba(0, 0, 0, 0.9); - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15) inset, 0 1px 4px 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.basic.buttons .active.button, -.ui.basic.active.button { - background: rgba(0, 0, 0, 0.05); - box-shadow: ''; - color: rgba(0, 0, 0, 0.95); -} - -.ui.basic.buttons .active.button:hover, -.ui.basic.active.button:hover { - background-color: rgba(0, 0, 0, 0.05); -} - -/* Vertical */ - -.ui.basic.buttons .button:hover { - box-shadow: 0 0 0 1px rgba(34, 36, 38, 0.35) inset, 0 0 0 0 rgba(34, 36, 38, 0.15) inset inset; -} - -.ui.basic.buttons .button:active { - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15) inset, 0 1px 4px 0 rgba(34, 36, 38, 0.15) inset inset; -} - -.ui.basic.buttons .active.button { - box-shadow: ''; -} - -/* Basic Group */ - -.ui.basic.buttons .button { - border-left: 1px solid rgba(34, 36, 38, 0.15); - box-shadow: none; -} - -.ui.basic.vertical.buttons .button { - border-left: none; - border-left-width: 0; - border-top: 1px solid rgba(34, 36, 38, 0.15); -} - -.ui.basic.vertical.buttons .button:first-child { - border-top-width: 0; -} - -/*-------------- - Labeled Icon - ---------------*/ - -.ui.labeled.icon.buttons .button, -.ui.labeled.icon.button { - position: relative; - padding-left: 4.07142857em !important; - padding-right: 1.5em !important; -} - -/* Left Labeled */ - -.ui.labeled.icon.buttons > .button > .icon, -.ui.labeled.icon.button > .icon { - position: absolute; - top: 0; - left: 0; - height: 100%; - line-height: 1; - border-radius: 0; - border-top-left-radius: inherit; - border-bottom-left-radius: inherit; - text-align: center; - animation: none; - padding: 0.78571429em 0 0.78571429em 0; - margin: 0; - width: 2.57142857em; - background-color: rgba(0, 0, 0, 0.05); - color: ''; - box-shadow: -1px 0 0 0 transparent inset; -} - -/* Right Labeled */ - -.ui[class*="right labeled"].icon.button { - padding-right: 4.07142857em !important; - padding-left: 1.5em !important; -} - -.ui[class*="right labeled"].icon.button > .icon { - left: auto; - right: 0; - border-radius: 0; - border-top-right-radius: inherit; - border-bottom-right-radius: inherit; - box-shadow: 1px 0 0 0 transparent inset; -} - -.ui.labeled.icon.buttons > .button > .icon:before, -.ui.labeled.icon.button > .icon:before, -.ui.labeled.icon.buttons > .button > .icon:after, -.ui.labeled.icon.button > .icon:after { - display: block; - position: relative; - width: 100%; - top: 0; - text-align: center; -} - -.ui.labeled.icon.buttons .button > .icon { - border-radius: 0; -} - -.ui.labeled.icon.buttons .button:first-child > .icon { - border-top-left-radius: 0.28571429rem; - border-bottom-left-radius: 0.28571429rem; -} - -.ui.labeled.icon.buttons .button:last-child > .icon { - border-top-right-radius: 0.28571429rem; - border-bottom-right-radius: 0.28571429rem; -} - -.ui.vertical.labeled.icon.buttons .button:first-child > .icon { - border-radius: 0; - border-top-left-radius: 0.28571429rem; -} - -.ui.vertical.labeled.icon.buttons .button:last-child > .icon { - border-radius: 0; - border-bottom-left-radius: 0.28571429rem; -} - -/* Loading Icon in Labeled Button */ - -.ui.labeled.icon.button > .loading.icon:before { - animation: loader 2s linear infinite; -} - -/*-------------- - Toggle - ---------------*/ - -/* Toggle (Modifies active state to give affordances) */ - -.ui.toggle.buttons .active.button, -.ui.buttons .button.toggle.active, -.ui.button.toggle.active { - background-color: #21BA45; - box-shadow: none; - text-shadow: none; - color: #FFFFFF; -} - -.ui.button.toggle.active:hover { - background-color: #16ab39; - text-shadow: none; - color: #FFFFFF; -} - -/*-------------- - Circular - ---------------*/ - -.ui.circular.button { - border-radius: 10em; -} - -.ui.circular.button > .icon { - width: 1em; - vertical-align: baseline; -} - -/*------------------- - Or Buttons - --------------------*/ - -.ui.buttons .or { - position: relative; - width: 0.3em; - height: 2.57142857em; - z-index: 3; -} - -.ui.buttons .or:before { - position: absolute; - text-align: center; - border-radius: 500rem; - content: 'or'; - top: 50%; - left: 50%; - background-color: #FFFFFF; - text-shadow: none; - margin-top: -0.89285714em; - margin-left: -0.89285714em; - width: 1.78571429em; - height: 1.78571429em; - line-height: 1.78571429em; - color: rgba(0, 0, 0, 0.4); - font-style: normal; - font-weight: 500; - box-shadow: 0 0 0 1px transparent inset; -} - -.ui.buttons .or[data-text]:before { - content: attr(data-text); -} - -/* Fluid Or */ - -.ui.fluid.buttons .or { - width: 0 !important; -} - -.ui.fluid.buttons .or:after { - display: none; -} - -/*------------------- - Fluid - --------------------*/ - -.ui.fluid.buttons, -.ui.fluid.button { - width: 100%; -} - -.ui.fluid.button { - display: block; -} - -.ui.two.buttons { - width: 100%; -} - -.ui.two.buttons > .button { - width: 50%; -} - -.ui.three.buttons { - width: 100%; -} - -.ui.three.buttons > .button { - width: 33.333%; -} - -.ui.four.buttons { - width: 100%; -} - -.ui.four.buttons > .button { - width: 25%; -} - -.ui.five.buttons { - width: 100%; -} - -.ui.five.buttons > .button { - width: 20%; -} - -.ui.six.buttons { - width: 100%; -} - -.ui.six.buttons > .button { - width: 16.666%; -} - -.ui.seven.buttons { - width: 100%; -} - -.ui.seven.buttons > .button { - width: 14.285%; -} - -.ui.eight.buttons { - width: 100%; -} - -.ui.eight.buttons > .button { - width: 12.5%; -} - -.ui.nine.buttons { - width: 100%; -} - -.ui.nine.buttons > .button { - width: 11.11%; -} - -.ui.ten.buttons { - width: 100%; -} - -.ui.ten.buttons > .button { - width: 10%; -} - -.ui.eleven.buttons { - width: 100%; -} - -.ui.eleven.buttons > .button { - width: 9.09%; -} - -.ui.twelve.buttons { - width: 100%; -} - -.ui.twelve.buttons > .button { - width: 8.3333%; -} - -/* Fluid Vertical Buttons */ - -.ui.fluid.vertical.buttons, -.ui.fluid.vertical.buttons > .button { - display: flex; - width: auto; - justify-content: center; -} - -.ui.two.vertical.buttons > .button { - height: 50%; -} - -.ui.three.vertical.buttons > .button { - height: 33.333%; -} - -.ui.four.vertical.buttons > .button { - height: 25%; -} - -.ui.five.vertical.buttons > .button { - height: 20%; -} - -.ui.six.vertical.buttons > .button { - height: 16.666%; -} - -.ui.seven.vertical.buttons > .button { - height: 14.285%; -} - -.ui.eight.vertical.buttons > .button { - height: 12.5%; -} - -.ui.nine.vertical.buttons > .button { - height: 11.11%; -} - -.ui.ten.vertical.buttons > .button { - height: 10%; -} - -.ui.eleven.vertical.buttons > .button { - height: 9.09%; -} - -.ui.twelve.vertical.buttons > .button { - height: 8.3333%; -} - -/*------------------- - Colors ---------------------*/ - -.ui.primary.buttons .button, -.ui.primary.button { - background-color: #2185D0; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.primary.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.primary.buttons .button:hover, -.ui.primary.button:hover { - background-color: #1678c2; - color: #FFFFFF; - text-shadow: none; -} - -.ui.primary.buttons .button:focus, -.ui.primary.button:focus { - background-color: #0d71bb; - color: #FFFFFF; - text-shadow: none; -} - -.ui.primary.buttons .button:active, -.ui.primary.button:active { - background-color: #1a69a4; - color: #FFFFFF; - text-shadow: none; -} - -.ui.primary.buttons .active.button, -.ui.primary.buttons .active.button:active, -.ui.primary.active.button, -.ui.primary.button .active.button:active { - background-color: #1279c6; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.primary.buttons .button, -.ui.basic.primary.button { - background: transparent; - box-shadow: 0 0 0 1px #2185D0 inset; - color: #2185D0; -} - -.ui.basic.primary.buttons .button:hover, -.ui.basic.primary.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #1678c2 inset; - color: #1678c2; -} - -.ui.basic.primary.buttons .button:focus, -.ui.basic.primary.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #0d71bb inset; - color: #1678c2; -} - -.ui.basic.primary.buttons .active.button, -.ui.basic.primary.active.button { - background: transparent; - box-shadow: 0 0 0 1px #1279c6 inset; - color: #1a69a4; -} - -.ui.basic.primary.buttons .button:active, -.ui.basic.primary.button:active { - box-shadow: 0 0 0 1px #1a69a4 inset; - color: #1a69a4; -} - -.ui.buttons:not(.vertical) > .basic.primary.button:not(:first-child) { - margin-left: -1px; -} - -.ui.secondary.buttons .button, -.ui.secondary.button { - background-color: #1B1C1D; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.secondary.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.secondary.buttons .button:hover, -.ui.secondary.button:hover { - background-color: #27292a; - color: #FFFFFF; - text-shadow: none; -} - -.ui.secondary.buttons .button:focus, -.ui.secondary.button:focus { - background-color: #2e3032; - color: #FFFFFF; - text-shadow: none; -} - -.ui.secondary.buttons .button:active, -.ui.secondary.button:active { - background-color: #343637; - color: #FFFFFF; - text-shadow: none; -} - -.ui.secondary.buttons .active.button, -.ui.secondary.buttons .active.button:active, -.ui.secondary.active.button, -.ui.secondary.button .active.button:active { - background-color: #27292a; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.secondary.buttons .button, -.ui.basic.secondary.button { - background: transparent; - box-shadow: 0 0 0 1px #1B1C1D inset; - color: #1B1C1D; -} - -.ui.basic.secondary.buttons .button:hover, -.ui.basic.secondary.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #27292a inset; - color: #27292a; -} - -.ui.basic.secondary.buttons .button:focus, -.ui.basic.secondary.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #2e3032 inset; - color: #27292a; -} - -.ui.basic.secondary.buttons .active.button, -.ui.basic.secondary.active.button { - background: transparent; - box-shadow: 0 0 0 1px #27292a inset; - color: #343637; -} - -.ui.basic.secondary.buttons .button:active, -.ui.basic.secondary.button:active { - box-shadow: 0 0 0 1px #343637 inset; - color: #343637; -} - -.ui.buttons:not(.vertical) > .basic.secondary.button:not(:first-child) { - margin-left: -1px; -} - -.ui.red.buttons .button, -.ui.red.button { - background-color: #DB2828; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.red.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.red.buttons .button:hover, -.ui.red.button:hover { - background-color: #d01919; - color: #FFFFFF; - text-shadow: none; -} - -.ui.red.buttons .button:focus, -.ui.red.button:focus { - background-color: #ca1010; - color: #FFFFFF; - text-shadow: none; -} - -.ui.red.buttons .button:active, -.ui.red.button:active { - background-color: #b21e1e; - color: #FFFFFF; - text-shadow: none; -} - -.ui.red.buttons .active.button, -.ui.red.buttons .active.button:active, -.ui.red.active.button, -.ui.red.button .active.button:active { - background-color: #d41515; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.red.buttons .button, -.ui.basic.red.button { - background: transparent; - box-shadow: 0 0 0 1px #DB2828 inset; - color: #DB2828; -} - -.ui.basic.red.buttons .button:hover, -.ui.basic.red.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #d01919 inset; - color: #d01919; -} - -.ui.basic.red.buttons .button:focus, -.ui.basic.red.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #ca1010 inset; - color: #d01919; -} - -.ui.basic.red.buttons .active.button, -.ui.basic.red.active.button { - background: transparent; - box-shadow: 0 0 0 1px #d41515 inset; - color: #b21e1e; -} - -.ui.basic.red.buttons .button:active, -.ui.basic.red.button:active { - box-shadow: 0 0 0 1px #b21e1e inset; - color: #b21e1e; -} - -.ui.buttons:not(.vertical) > .basic.red.button:not(:first-child) { - margin-left: -1px; -} - -.ui.orange.buttons .button, -.ui.orange.button { - background-color: #F2711C; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.orange.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.orange.buttons .button:hover, -.ui.orange.button:hover { - background-color: #f26202; - color: #FFFFFF; - text-shadow: none; -} - -.ui.orange.buttons .button:focus, -.ui.orange.button:focus { - background-color: #e55b00; - color: #FFFFFF; - text-shadow: none; -} - -.ui.orange.buttons .button:active, -.ui.orange.button:active { - background-color: #cf590c; - color: #FFFFFF; - text-shadow: none; -} - -.ui.orange.buttons .active.button, -.ui.orange.buttons .active.button:active, -.ui.orange.active.button, -.ui.orange.button .active.button:active { - background-color: #f56100; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.orange.buttons .button, -.ui.basic.orange.button { - background: transparent; - box-shadow: 0 0 0 1px #F2711C inset; - color: #F2711C; -} - -.ui.basic.orange.buttons .button:hover, -.ui.basic.orange.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #f26202 inset; - color: #f26202; -} - -.ui.basic.orange.buttons .button:focus, -.ui.basic.orange.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #e55b00 inset; - color: #f26202; -} - -.ui.basic.orange.buttons .active.button, -.ui.basic.orange.active.button { - background: transparent; - box-shadow: 0 0 0 1px #f56100 inset; - color: #cf590c; -} - -.ui.basic.orange.buttons .button:active, -.ui.basic.orange.button:active { - box-shadow: 0 0 0 1px #cf590c inset; - color: #cf590c; -} - -.ui.buttons:not(.vertical) > .basic.orange.button:not(:first-child) { - margin-left: -1px; -} - -.ui.yellow.buttons .button, -.ui.yellow.button { - background-color: #FBBD08; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.yellow.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.yellow.buttons .button:hover, -.ui.yellow.button:hover { - background-color: #eaae00; - color: #FFFFFF; - text-shadow: none; -} - -.ui.yellow.buttons .button:focus, -.ui.yellow.button:focus { - background-color: #daa300; - color: #FFFFFF; - text-shadow: none; -} - -.ui.yellow.buttons .button:active, -.ui.yellow.button:active { - background-color: #cd9903; - color: #FFFFFF; - text-shadow: none; -} - -.ui.yellow.buttons .active.button, -.ui.yellow.buttons .active.button:active, -.ui.yellow.active.button, -.ui.yellow.button .active.button:active { - background-color: #eaae00; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.yellow.buttons .button, -.ui.basic.yellow.button { - background: transparent; - box-shadow: 0 0 0 1px #FBBD08 inset; - color: #FBBD08; -} - -.ui.basic.yellow.buttons .button:hover, -.ui.basic.yellow.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #eaae00 inset; - color: #eaae00; -} - -.ui.basic.yellow.buttons .button:focus, -.ui.basic.yellow.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #daa300 inset; - color: #eaae00; -} - -.ui.basic.yellow.buttons .active.button, -.ui.basic.yellow.active.button { - background: transparent; - box-shadow: 0 0 0 1px #eaae00 inset; - color: #cd9903; -} - -.ui.basic.yellow.buttons .button:active, -.ui.basic.yellow.button:active { - box-shadow: 0 0 0 1px #cd9903 inset; - color: #cd9903; -} - -.ui.buttons:not(.vertical) > .basic.yellow.button:not(:first-child) { - margin-left: -1px; -} - -.ui.olive.buttons .button, -.ui.olive.button { - background-color: #B5CC18; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.olive.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.olive.buttons .button:hover, -.ui.olive.button:hover { - background-color: #a7bd0d; - color: #FFFFFF; - text-shadow: none; -} - -.ui.olive.buttons .button:focus, -.ui.olive.button:focus { - background-color: #a0b605; - color: #FFFFFF; - text-shadow: none; -} - -.ui.olive.buttons .button:active, -.ui.olive.button:active { - background-color: #8d9e13; - color: #FFFFFF; - text-shadow: none; -} - -.ui.olive.buttons .active.button, -.ui.olive.buttons .active.button:active, -.ui.olive.active.button, -.ui.olive.button .active.button:active { - background-color: #aac109; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.olive.buttons .button, -.ui.basic.olive.button { - background: transparent; - box-shadow: 0 0 0 1px #B5CC18 inset; - color: #B5CC18; -} - -.ui.basic.olive.buttons .button:hover, -.ui.basic.olive.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #a7bd0d inset; - color: #a7bd0d; -} - -.ui.basic.olive.buttons .button:focus, -.ui.basic.olive.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #a0b605 inset; - color: #a7bd0d; -} - -.ui.basic.olive.buttons .active.button, -.ui.basic.olive.active.button { - background: transparent; - box-shadow: 0 0 0 1px #aac109 inset; - color: #8d9e13; -} - -.ui.basic.olive.buttons .button:active, -.ui.basic.olive.button:active { - box-shadow: 0 0 0 1px #8d9e13 inset; - color: #8d9e13; -} - -.ui.buttons:not(.vertical) > .basic.olive.button:not(:first-child) { - margin-left: -1px; -} - -.ui.green.buttons .button, -.ui.green.button { - background-color: #21BA45; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.green.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.green.buttons .button:hover, -.ui.green.button:hover { - background-color: #16ab39; - color: #FFFFFF; - text-shadow: none; -} - -.ui.green.buttons .button:focus, -.ui.green.button:focus { - background-color: #0ea432; - color: #FFFFFF; - text-shadow: none; -} - -.ui.green.buttons .button:active, -.ui.green.button:active { - background-color: #198f35; - color: #FFFFFF; - text-shadow: none; -} - -.ui.green.buttons .active.button, -.ui.green.buttons .active.button:active, -.ui.green.active.button, -.ui.green.button .active.button:active { - background-color: #13ae38; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.green.buttons .button, -.ui.basic.green.button { - background: transparent; - box-shadow: 0 0 0 1px #21BA45 inset; - color: #21BA45; -} - -.ui.basic.green.buttons .button:hover, -.ui.basic.green.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #16ab39 inset; - color: #16ab39; -} - -.ui.basic.green.buttons .button:focus, -.ui.basic.green.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #0ea432 inset; - color: #16ab39; -} - -.ui.basic.green.buttons .active.button, -.ui.basic.green.active.button { - background: transparent; - box-shadow: 0 0 0 1px #13ae38 inset; - color: #198f35; -} - -.ui.basic.green.buttons .button:active, -.ui.basic.green.button:active { - box-shadow: 0 0 0 1px #198f35 inset; - color: #198f35; -} - -.ui.buttons:not(.vertical) > .basic.green.button:not(:first-child) { - margin-left: -1px; -} - -.ui.teal.buttons .button, -.ui.teal.button { - background-color: #00B5AD; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.teal.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.teal.buttons .button:hover, -.ui.teal.button:hover { - background-color: #009c95; - color: #FFFFFF; - text-shadow: none; -} - -.ui.teal.buttons .button:focus, -.ui.teal.button:focus { - background-color: #008c86; - color: #FFFFFF; - text-shadow: none; -} - -.ui.teal.buttons .button:active, -.ui.teal.button:active { - background-color: #00827c; - color: #FFFFFF; - text-shadow: none; -} - -.ui.teal.buttons .active.button, -.ui.teal.buttons .active.button:active, -.ui.teal.active.button, -.ui.teal.button .active.button:active { - background-color: #009c95; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.teal.buttons .button, -.ui.basic.teal.button { - background: transparent; - box-shadow: 0 0 0 1px #00B5AD inset; - color: #00B5AD; -} - -.ui.basic.teal.buttons .button:hover, -.ui.basic.teal.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #009c95 inset; - color: #009c95; -} - -.ui.basic.teal.buttons .button:focus, -.ui.basic.teal.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #008c86 inset; - color: #009c95; -} - -.ui.basic.teal.buttons .active.button, -.ui.basic.teal.active.button { - background: transparent; - box-shadow: 0 0 0 1px #009c95 inset; - color: #00827c; -} - -.ui.basic.teal.buttons .button:active, -.ui.basic.teal.button:active { - box-shadow: 0 0 0 1px #00827c inset; - color: #00827c; -} - -.ui.buttons:not(.vertical) > .basic.teal.button:not(:first-child) { - margin-left: -1px; -} - -.ui.blue.buttons .button, -.ui.blue.button { - background-color: #2185D0; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.blue.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.blue.buttons .button:hover, -.ui.blue.button:hover { - background-color: #1678c2; - color: #FFFFFF; - text-shadow: none; -} - -.ui.blue.buttons .button:focus, -.ui.blue.button:focus { - background-color: #0d71bb; - color: #FFFFFF; - text-shadow: none; -} - -.ui.blue.buttons .button:active, -.ui.blue.button:active { - background-color: #1a69a4; - color: #FFFFFF; - text-shadow: none; -} - -.ui.blue.buttons .active.button, -.ui.blue.buttons .active.button:active, -.ui.blue.active.button, -.ui.blue.button .active.button:active { - background-color: #1279c6; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.blue.buttons .button, -.ui.basic.blue.button { - background: transparent; - box-shadow: 0 0 0 1px #2185D0 inset; - color: #2185D0; -} - -.ui.basic.blue.buttons .button:hover, -.ui.basic.blue.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #1678c2 inset; - color: #1678c2; -} - -.ui.basic.blue.buttons .button:focus, -.ui.basic.blue.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #0d71bb inset; - color: #1678c2; -} - -.ui.basic.blue.buttons .active.button, -.ui.basic.blue.active.button { - background: transparent; - box-shadow: 0 0 0 1px #1279c6 inset; - color: #1a69a4; -} - -.ui.basic.blue.buttons .button:active, -.ui.basic.blue.button:active { - box-shadow: 0 0 0 1px #1a69a4 inset; - color: #1a69a4; -} - -.ui.buttons:not(.vertical) > .basic.blue.button:not(:first-child) { - margin-left: -1px; -} - -.ui.violet.buttons .button, -.ui.violet.button { - background-color: #6435C9; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.violet.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.violet.buttons .button:hover, -.ui.violet.button:hover { - background-color: #5829bb; - color: #FFFFFF; - text-shadow: none; -} - -.ui.violet.buttons .button:focus, -.ui.violet.button:focus { - background-color: #4f20b5; - color: #FFFFFF; - text-shadow: none; -} - -.ui.violet.buttons .button:active, -.ui.violet.button:active { - background-color: #502aa1; - color: #FFFFFF; - text-shadow: none; -} - -.ui.violet.buttons .active.button, -.ui.violet.buttons .active.button:active, -.ui.violet.active.button, -.ui.violet.button .active.button:active { - background-color: #5626bf; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.violet.buttons .button, -.ui.basic.violet.button { - background: transparent; - box-shadow: 0 0 0 1px #6435C9 inset; - color: #6435C9; -} - -.ui.basic.violet.buttons .button:hover, -.ui.basic.violet.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #5829bb inset; - color: #5829bb; -} - -.ui.basic.violet.buttons .button:focus, -.ui.basic.violet.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #4f20b5 inset; - color: #5829bb; -} - -.ui.basic.violet.buttons .active.button, -.ui.basic.violet.active.button { - background: transparent; - box-shadow: 0 0 0 1px #5626bf inset; - color: #502aa1; -} - -.ui.basic.violet.buttons .button:active, -.ui.basic.violet.button:active { - box-shadow: 0 0 0 1px #502aa1 inset; - color: #502aa1; -} - -.ui.buttons:not(.vertical) > .basic.violet.button:not(:first-child) { - margin-left: -1px; -} - -.ui.purple.buttons .button, -.ui.purple.button { - background-color: #A333C8; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.purple.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.purple.buttons .button:hover, -.ui.purple.button:hover { - background-color: #9627ba; - color: #FFFFFF; - text-shadow: none; -} - -.ui.purple.buttons .button:focus, -.ui.purple.button:focus { - background-color: #8f1eb4; - color: #FFFFFF; - text-shadow: none; -} - -.ui.purple.buttons .button:active, -.ui.purple.button:active { - background-color: #82299f; - color: #FFFFFF; - text-shadow: none; -} - -.ui.purple.buttons .active.button, -.ui.purple.buttons .active.button:active, -.ui.purple.active.button, -.ui.purple.button .active.button:active { - background-color: #9724be; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.purple.buttons .button, -.ui.basic.purple.button { - background: transparent; - box-shadow: 0 0 0 1px #A333C8 inset; - color: #A333C8; -} - -.ui.basic.purple.buttons .button:hover, -.ui.basic.purple.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #9627ba inset; - color: #9627ba; -} - -.ui.basic.purple.buttons .button:focus, -.ui.basic.purple.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #8f1eb4 inset; - color: #9627ba; -} - -.ui.basic.purple.buttons .active.button, -.ui.basic.purple.active.button { - background: transparent; - box-shadow: 0 0 0 1px #9724be inset; - color: #82299f; -} - -.ui.basic.purple.buttons .button:active, -.ui.basic.purple.button:active { - box-shadow: 0 0 0 1px #82299f inset; - color: #82299f; -} - -.ui.buttons:not(.vertical) > .basic.purple.button:not(:first-child) { - margin-left: -1px; -} - -.ui.pink.buttons .button, -.ui.pink.button { - background-color: #E03997; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.pink.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.pink.buttons .button:hover, -.ui.pink.button:hover { - background-color: #e61a8d; - color: #FFFFFF; - text-shadow: none; -} - -.ui.pink.buttons .button:focus, -.ui.pink.button:focus { - background-color: #e10f85; - color: #FFFFFF; - text-shadow: none; -} - -.ui.pink.buttons .button:active, -.ui.pink.button:active { - background-color: #c71f7e; - color: #FFFFFF; - text-shadow: none; -} - -.ui.pink.buttons .active.button, -.ui.pink.buttons .active.button:active, -.ui.pink.active.button, -.ui.pink.button .active.button:active { - background-color: #ea158d; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.pink.buttons .button, -.ui.basic.pink.button { - background: transparent; - box-shadow: 0 0 0 1px #E03997 inset; - color: #E03997; -} - -.ui.basic.pink.buttons .button:hover, -.ui.basic.pink.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #e61a8d inset; - color: #e61a8d; -} - -.ui.basic.pink.buttons .button:focus, -.ui.basic.pink.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #e10f85 inset; - color: #e61a8d; -} - -.ui.basic.pink.buttons .active.button, -.ui.basic.pink.active.button { - background: transparent; - box-shadow: 0 0 0 1px #ea158d inset; - color: #c71f7e; -} - -.ui.basic.pink.buttons .button:active, -.ui.basic.pink.button:active { - box-shadow: 0 0 0 1px #c71f7e inset; - color: #c71f7e; -} - -.ui.buttons:not(.vertical) > .basic.pink.button:not(:first-child) { - margin-left: -1px; -} - -.ui.brown.buttons .button, -.ui.brown.button { - background-color: #A5673F; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.brown.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.brown.buttons .button:hover, -.ui.brown.button:hover { - background-color: #975b33; - color: #FFFFFF; - text-shadow: none; -} - -.ui.brown.buttons .button:focus, -.ui.brown.button:focus { - background-color: #90532b; - color: #FFFFFF; - text-shadow: none; -} - -.ui.brown.buttons .button:active, -.ui.brown.button:active { - background-color: #805031; - color: #FFFFFF; - text-shadow: none; -} - -.ui.brown.buttons .active.button, -.ui.brown.buttons .active.button:active, -.ui.brown.active.button, -.ui.brown.button .active.button:active { - background-color: #995a31; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.brown.buttons .button, -.ui.basic.brown.button { - background: transparent; - box-shadow: 0 0 0 1px #A5673F inset; - color: #A5673F; -} - -.ui.basic.brown.buttons .button:hover, -.ui.basic.brown.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #975b33 inset; - color: #975b33; -} - -.ui.basic.brown.buttons .button:focus, -.ui.basic.brown.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #90532b inset; - color: #975b33; -} - -.ui.basic.brown.buttons .active.button, -.ui.basic.brown.active.button { - background: transparent; - box-shadow: 0 0 0 1px #995a31 inset; - color: #805031; -} - -.ui.basic.brown.buttons .button:active, -.ui.basic.brown.button:active { - box-shadow: 0 0 0 1px #805031 inset; - color: #805031; -} - -.ui.buttons:not(.vertical) > .basic.brown.button:not(:first-child) { - margin-left: -1px; -} - -.ui.grey.buttons .button, -.ui.grey.button { - background-color: #767676; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.grey.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.grey.buttons .button:hover, -.ui.grey.button:hover { - background-color: #838383; - color: #FFFFFF; - text-shadow: none; -} - -.ui.grey.buttons .button:focus, -.ui.grey.button:focus { - background-color: #8a8a8a; - color: #FFFFFF; - text-shadow: none; -} - -.ui.grey.buttons .button:active, -.ui.grey.button:active { - background-color: #909090; - color: #FFFFFF; - text-shadow: none; -} - -.ui.grey.buttons .active.button, -.ui.grey.buttons .active.button:active, -.ui.grey.active.button, -.ui.grey.button .active.button:active { - background-color: #696969; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.grey.buttons .button, -.ui.basic.grey.button { - background: transparent; - box-shadow: 0 0 0 1px #767676 inset; - color: #767676; -} - -.ui.basic.grey.buttons .button:hover, -.ui.basic.grey.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #838383 inset; - color: #838383; -} - -.ui.basic.grey.buttons .button:focus, -.ui.basic.grey.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #8a8a8a inset; - color: #838383; -} - -.ui.basic.grey.buttons .active.button, -.ui.basic.grey.active.button { - background: transparent; - box-shadow: 0 0 0 1px #696969 inset; - color: #909090; -} - -.ui.basic.grey.buttons .button:active, -.ui.basic.grey.button:active { - box-shadow: 0 0 0 1px #909090 inset; - color: #909090; -} - -.ui.buttons:not(.vertical) > .basic.grey.button:not(:first-child) { - margin-left: -1px; -} - -.ui.black.buttons .button, -.ui.black.button { - background-color: #1B1C1D; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.black.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.black.buttons .button:hover, -.ui.black.button:hover { - background-color: #27292a; - color: #FFFFFF; - text-shadow: none; -} - -.ui.black.buttons .button:focus, -.ui.black.button:focus { - background-color: #2f3032; - color: #FFFFFF; - text-shadow: none; -} - -.ui.black.buttons .button:active, -.ui.black.button:active { - background-color: #343637; - color: #FFFFFF; - text-shadow: none; -} - -.ui.black.buttons .active.button, -.ui.black.buttons .active.button:active, -.ui.black.active.button, -.ui.black.button .active.button:active { - background-color: #0f0f10; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.black.buttons .button, -.ui.basic.black.button { - background: transparent; - box-shadow: 0 0 0 1px #1B1C1D inset; - color: #1B1C1D; -} - -.ui.basic.black.buttons .button:hover, -.ui.basic.black.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #27292a inset; - color: #27292a; -} - -.ui.basic.black.buttons .button:focus, -.ui.basic.black.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #2f3032 inset; - color: #27292a; -} - -.ui.basic.black.buttons .active.button, -.ui.basic.black.active.button { - background: transparent; - box-shadow: 0 0 0 1px #0f0f10 inset; - color: #343637; -} - -.ui.basic.black.buttons .button:active, -.ui.basic.black.button:active { - box-shadow: 0 0 0 1px #343637 inset; - color: #343637; -} - -.ui.buttons:not(.vertical) > .basic.black.button:not(:first-child) { - margin-left: -1px; -} - -/*--------------- - Positive -----------------*/ - -/* Standard */ - -.ui.positive.buttons .button, -.ui.positive.button { - background-color: #21BA45; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.positive.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.positive.buttons .button:hover, -.ui.positive.button:hover { - background-color: #16ab39; - color: #FFFFFF; - text-shadow: none; -} - -.ui.positive.buttons .button:focus, -.ui.positive.button:focus { - background-color: #0ea432; - color: #FFFFFF; - text-shadow: none; -} - -.ui.positive.buttons .button:active, -.ui.positive.button:active { - background-color: #198f35; - color: #FFFFFF; - text-shadow: none; -} - -.ui.positive.buttons .active.button, -.ui.positive.buttons .active.button:active, -.ui.positive.active.button, -.ui.positive.button .active.button:active { - background-color: #13ae38; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.positive.buttons .button, -.ui.basic.positive.button { - background: transparent; - box-shadow: 0 0 0 1px #21BA45 inset; - color: #21BA45; -} - -.ui.basic.positive.buttons .button:hover, -.ui.basic.positive.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #16ab39 inset; - color: #16ab39; -} - -.ui.basic.positive.buttons .button:focus, -.ui.basic.positive.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #0ea432 inset; - color: #16ab39; -} - -.ui.basic.positive.buttons .active.button, -.ui.basic.positive.active.button { - background: transparent; - box-shadow: 0 0 0 1px #13ae38 inset; - color: #198f35; -} - -.ui.basic.positive.buttons .button:active, -.ui.basic.positive.button:active { - box-shadow: 0 0 0 1px #198f35 inset; - color: #198f35; -} - -.ui.buttons:not(.vertical) > .basic.positive.button:not(:first-child) { - margin-left: -1px; -} - -/*--------------- - Negative -----------------*/ - -/* Standard */ - -.ui.negative.buttons .button, -.ui.negative.button { - background-color: #DB2828; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.negative.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.negative.buttons .button:hover, -.ui.negative.button:hover { - background-color: #d01919; - color: #FFFFFF; - text-shadow: none; -} - -.ui.negative.buttons .button:focus, -.ui.negative.button:focus { - background-color: #ca1010; - color: #FFFFFF; - text-shadow: none; -} - -.ui.negative.buttons .button:active, -.ui.negative.button:active { - background-color: #b21e1e; - color: #FFFFFF; - text-shadow: none; -} - -.ui.negative.buttons .active.button, -.ui.negative.buttons .active.button:active, -.ui.negative.active.button, -.ui.negative.button .active.button:active { - background-color: #d41515; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.negative.buttons .button, -.ui.basic.negative.button { - background: transparent; - box-shadow: 0 0 0 1px #DB2828 inset; - color: #DB2828; -} - -.ui.basic.negative.buttons .button:hover, -.ui.basic.negative.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #d01919 inset; - color: #d01919; -} - -.ui.basic.negative.buttons .button:focus, -.ui.basic.negative.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #ca1010 inset; - color: #d01919; -} - -.ui.basic.negative.buttons .active.button, -.ui.basic.negative.active.button { - background: transparent; - box-shadow: 0 0 0 1px #d41515 inset; - color: #b21e1e; -} - -.ui.basic.negative.buttons .button:active, -.ui.basic.negative.button:active { - box-shadow: 0 0 0 1px #b21e1e inset; - color: #b21e1e; -} - -.ui.buttons:not(.vertical) > .basic.negative.button:not(:first-child) { - margin-left: -1px; -} - -/******************************* - Groups - *******************************/ - -.ui.buttons { - display: inline-flex; - flex-direction: row; - font-size: 0; - vertical-align: baseline; - margin: 0 0.25em 0 0; -} - -.ui.buttons:not(.basic):not(.inverted) { - box-shadow: none; -} - -/* Clearfix */ - -.ui.buttons:after { - content: "."; - display: block; - height: 0; - clear: both; - visibility: hidden; -} - -/* Standard Group */ - -.ui.buttons .button { - flex: 1 0 auto; - border-radius: 0; - margin: 0 0 0 0; -} - -.ui.buttons:not(.basic):not(.inverted) > .button:not(.basic):not(.inverted) { - box-shadow: 0 0 0 1px transparent inset, 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.buttons .button:first-child { - border-left: none; - margin-left: 0; - border-top-left-radius: 0.28571429rem; - border-bottom-left-radius: 0.28571429rem; -} - -.ui.buttons .button:last-child { - border-top-right-radius: 0.28571429rem; - border-bottom-right-radius: 0.28571429rem; -} - -/* Vertical Style */ - -.ui.vertical.buttons { - display: inline-flex; - flex-direction: column; -} - -.ui.vertical.buttons .button { - display: block; - float: none; - width: 100%; - margin: 0 0 0 0; - box-shadow: none; - border-radius: 0; -} - -.ui.vertical.buttons .button:first-child { - border-top-left-radius: 0.28571429rem; - border-top-right-radius: 0.28571429rem; -} - -.ui.vertical.buttons .button:last-child { - margin-bottom: 0; - border-bottom-left-radius: 0.28571429rem; - border-bottom-right-radius: 0.28571429rem; -} - -.ui.vertical.buttons .button:only-child { - border-radius: 0.28571429rem; -} - -/******************************* - Theme Overrides -*******************************/ - -/******************************* - Site Overrides -*******************************/ /*! * # Fomantic-UI - Dimmer * http://github.com/fomantic/Fomantic-UI/ diff --git a/web_src/fomantic/semantic.json b/web_src/fomantic/semantic.json index 5b3a480d53..489ca7b9b7 100644 --- a/web_src/fomantic/semantic.json +++ b/web_src/fomantic/semantic.json @@ -22,7 +22,6 @@ "admin": false, "components": [ "api", - "button", "dimmer", "dropdown", "form", diff --git a/web_src/js/components/PullRequestMergeForm.vue b/web_src/js/components/PullRequestMergeForm.vue index bd0901a7b5..9efa8840ac 100644 --- a/web_src/js/components/PullRequestMergeForm.vue +++ b/web_src/js/components/PullRequestMergeForm.vue @@ -138,7 +138,7 @@ export default { <div v-if="!showActionForm" class="tw-flex"> <!-- the merge button --> - <div class="ui buttons merge-button" :class="[mergeForm.emptyCommit ? 'grey' : mergeForm.allOverridableChecksOk ? 'primary' : 'red']" @click="toggleActionForm(true)"> + <div class="ui buttons merge-button" :class="[mergeForm.emptyCommit ? '' : mergeForm.allOverridableChecksOk ? 'primary' : 'red']" @click="toggleActionForm(true)"> <button class="ui button"> <svg-icon name="octicon-git-merge"/> <span class="button-text"> From b84baf21fa19521e1ab303a60918c74f85fcad1c Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Mon, 15 Apr 2024 03:43:30 +0800 Subject: [PATCH 114/370] Improve flex ellipsis (#30479)  --------- Co-authored-by: silverwind <me@silverwind.io> --- templates/devtest/label.tmpl | 27 +++++++++++++++++++++++++++ web_src/css/base.css | 3 +++ web_src/css/modules/label.css | 2 ++ 3 files changed, 32 insertions(+) create mode 100644 templates/devtest/label.tmpl diff --git a/templates/devtest/label.tmpl b/templates/devtest/label.tmpl new file mode 100644 index 0000000000..77590715a1 --- /dev/null +++ b/templates/devtest/label.tmpl @@ -0,0 +1,27 @@ +{{template "base/head" .}} +<link rel="stylesheet" href="{{AssetUrlPrefix}}/css/devtest.css?v={{AssetVersion}}"> +<div class="page-content devtest ui container"> + <div> + <h1>Label</h1> + <div class="flex-text-block tw-my-2"> + <span class="ui label">simple label</span> + <span class="ui red label">red label</span> + <span class="ui green label">green label</span> + </div> + <div class="flex-text-block tw-my-2"> + <span class="ui basic label">basic label</span> + <span class="ui basic red label">basic red label</span> + <span class="ui basic green label">basic green label</span> + </div> + <div class="flex-text-block tw-my-2"> + <span class="ui label">long content must be in a non-flex "gt-ellipsis" element, otherwise it won't get ellipsis. very looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong label</span> + </div> + <div class="flex-text-block tw-my-2"> + <span class="ui label"><span class="gt-ellipsis">very looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong label</span></span> + </div> + <div class="tw-my-2"> + <span class="ui label"><span class="gt-ellipsis">very looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong label</span></span> + </div> + </div> +</div> +{{template "base/footer" .}} diff --git a/web_src/css/base.css b/web_src/css/base.css index b3f87044e0..8ded4aa883 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -1341,6 +1341,7 @@ table th[data-sortt-desc] .svg { align-items: center; gap: .25rem; vertical-align: middle; + min-width: 0; } .ui.dropdown .ui.label .svg { @@ -1357,6 +1358,7 @@ table th[data-sortt-desc] .svg { display: flex; align-items: center; gap: .25rem; + min-width: 0; } /* to override Fomantic's default display: block for ".menu .item", and use a slightly larger gap for menu item content */ @@ -1364,4 +1366,5 @@ table th[data-sortt-desc] .svg { display: flex !important; align-items: center; gap: .5rem; + min-width: 0; } diff --git a/web_src/css/modules/label.css b/web_src/css/modules/label.css index 32e772ea5b..696080b667 100644 --- a/web_src/css/modules/label.css +++ b/web_src/css/modules/label.css @@ -5,6 +5,8 @@ display: inline-flex; align-items: center; gap: .25rem; + min-width: 0; + max-width: 100%; /* since we are using "flex" to align label contents, we also need to limit the x-axis, a label shouldn't be wider than 100% */ vertical-align: middle; line-height: 1; background: var(--color-label-bg); From ef3941f2ebe9d8353f9546e7df00b24092c71cb7 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Mon, 15 Apr 2024 03:04:02 +0200 Subject: [PATCH 115/370] Revert 100% label max-width (#30481) Partial revert of https://github.com/go-gitea/gitea/pull/30479 It's causing problems at least here: https://github.com/go-gitea/gitea/pull/30344#discussion_r1564895591 --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> --- templates/devtest/label.tmpl | 2 +- web_src/css/modules/label.css | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/templates/devtest/label.tmpl b/templates/devtest/label.tmpl index 77590715a1..c4b52a3e23 100644 --- a/templates/devtest/label.tmpl +++ b/templates/devtest/label.tmpl @@ -20,7 +20,7 @@ <span class="ui label"><span class="gt-ellipsis">very looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong label</span></span> </div> <div class="tw-my-2"> - <span class="ui label"><span class="gt-ellipsis">very looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong label</span></span> + <span class="ui label tw-max-w-full"><span class="gt-ellipsis">very looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong label</span></span> </div> </div> </div> diff --git a/web_src/css/modules/label.css b/web_src/css/modules/label.css index 696080b667..2032b2c84b 100644 --- a/web_src/css/modules/label.css +++ b/web_src/css/modules/label.css @@ -6,7 +6,6 @@ align-items: center; gap: .25rem; min-width: 0; - max-width: 100%; /* since we are using "flex" to align label contents, we also need to limit the x-axis, a label shouldn't be wider than 100% */ vertical-align: middle; line-height: 1; background: var(--color-label-bg); From 708e87e17df2b6a03eca3cac026a51beed296b5b Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Mon, 15 Apr 2024 02:40:53 +0000 Subject: [PATCH 116/370] [skip ci] Updated licenses and gitignores --- options/license/BSD-2-clause-first-lines | 27 ++++++++++++++++++++++++ options/license/Sun-PPP-2000 | 13 ++++++++++++ options/license/pkgconf | 7 ++++++ 3 files changed, 47 insertions(+) create mode 100644 options/license/BSD-2-clause-first-lines create mode 100644 options/license/Sun-PPP-2000 create mode 100644 options/license/pkgconf diff --git a/options/license/BSD-2-clause-first-lines b/options/license/BSD-2-clause-first-lines new file mode 100644 index 0000000000..3774caf24a --- /dev/null +++ b/options/license/BSD-2-clause-first-lines @@ -0,0 +1,27 @@ +Copyright (C) 2006,2007,2009 NTT (Nippon Telegraph and Telephone +Corporation). All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer as the first lines of this file unmodified. + +2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +THIS SOFTWARE IS PROVIDED BY NTT "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL NTT BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/options/license/Sun-PPP-2000 b/options/license/Sun-PPP-2000 new file mode 100644 index 0000000000..914c19544a --- /dev/null +++ b/options/license/Sun-PPP-2000 @@ -0,0 +1,13 @@ +Copyright (c) 2000 by Sun Microsystems, Inc. +All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation is hereby granted, provided that the above copyright +notice appears in all copies. + +SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF +THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR +ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR +DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES diff --git a/options/license/pkgconf b/options/license/pkgconf new file mode 100644 index 0000000000..b8b2ffd996 --- /dev/null +++ b/options/license/pkgconf @@ -0,0 +1,7 @@ +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +This software is provided 'as is' and without any warranty, express or +implied. In no event shall the authors be liable for any damages arising +from the use of this software. From 994920c677b04a720726d982e4d6212664b82a43 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Mon, 15 Apr 2024 10:24:36 +0200 Subject: [PATCH 117/370] Kill all gitea processes before air build (#30477) So it happened to me multiple times that air leaves zombie processes after termination. I think ultimately it's some kind of bug in air, but we can work around. The change in the delay is unrelated to the zombie processes but seems to help a bit with duplicate changes resulting in duplicate `make generate` as seen here: <img width="424" alt="Screenshot 2024-04-14 at 17 05 47" src="https://github.com/go-gitea/gitea/assets/115237/6dd1d787-6be3-4fb2-8b0b-cd711c281793"> --------- Co-authored-by: delvh <dev.lh@web.de> --- .air.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.air.toml b/.air.toml index de97bd8b29..3740c4d4aa 100644 --- a/.air.toml +++ b/.air.toml @@ -2,9 +2,10 @@ root = "." tmp_dir = ".air" [build] +pre_cmd = ["killall -9 gitea 2>/dev/null || true"] # kill off potential zombie processes from previous runs cmd = "make --no-print-directory backend" bin = "gitea" -delay = 1000 +delay = 2000 include_ext = ["go", "tmpl"] include_file = ["main.go"] include_dir = ["cmd", "models", "modules", "options", "routers", "services"] From 1508a85f6235814271ea927d651bcbcd8c9f5f18 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Mon, 15 Apr 2024 10:49:48 +0200 Subject: [PATCH 118/370] Fix overflow on issue dependency (#30484) Small tweak here to prevent this and likely other events from overflowing in the timeline: <img width="895" alt="Screenshot 2024-04-14 at 22 53 17" src="https://github.com/go-gitea/gitea/assets/115237/001b4f6b-f649-44ff-b2f0-c8e0dedeb384"> Co-authored-by: Giteabot <teabot@gitea.io> --- web_src/css/repo.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 887789115e..0f6bf482b5 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -1063,6 +1063,12 @@ td .commit-summary { margin-left: 15px; } +.repository.view.issue .comment-list .event .detail .text { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + .repository.view.issue .comment-list .event .segments { box-shadow: none; } From c63060b130d34e3f03f28f4dccbf04d381a95c17 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Mon, 15 Apr 2024 22:11:07 +0800 Subject: [PATCH 119/370] Fix code owners will not be mentioned when a pull request comes from a forked repository (#30476) Fix #30277 Caused by #29783 --- services/issue/pull.go | 8 ++++---- tests/integration/pull_create_test.go | 25 +++++++++++++++++++++++++ tests/integration/pull_review_test.go | 10 +++++++++- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/services/issue/pull.go b/services/issue/pull.go index b7b63a7024..4a0009e82f 100644 --- a/services/issue/pull.go +++ b/services/issue/pull.go @@ -51,14 +51,14 @@ func PullRequestCodeOwnersReview(ctx context.Context, issue *issues_model.Issue, return nil, err } - if pr.HeadRepo.IsFork { - return nil, nil - } - if err := pr.LoadBaseRepo(ctx); err != nil { return nil, err } + if pr.BaseRepo.IsFork { + return nil, nil + } + repo, err := gitrepo.OpenRepository(ctx, pr.BaseRepo) if err != nil { return nil, err diff --git a/tests/integration/pull_create_test.go b/tests/integration/pull_create_test.go index 029ea65d71..609bd73fd5 100644 --- a/tests/integration/pull_create_test.go +++ b/tests/integration/pull_create_test.go @@ -4,6 +4,7 @@ package integration import ( + "fmt" "net/http" "net/http/httptest" "net/url" @@ -57,6 +58,30 @@ func testPullCreate(t *testing.T, session *TestSession, user, repo string, toSel return resp } +func testPullCreateDirectly(t *testing.T, session *TestSession, baseRepoOwner, baseRepoName, baseBranch, headRepoOwner, headRepoName, headBranch, title string) *httptest.ResponseRecorder { + headCompare := headBranch + if headRepoOwner != "" { + if headRepoName != "" { + headCompare = fmt.Sprintf("%s/%s:%s", headRepoOwner, headRepoName, headBranch) + } else { + headCompare = fmt.Sprintf("%s:%s", headRepoOwner, headBranch) + } + } + req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/compare/%s...%s", baseRepoOwner, baseRepoName, baseBranch, headCompare)) + resp := session.MakeRequest(t, req, http.StatusOK) + + // Submit the form for creating the pull + htmlDoc := NewHTMLParser(t, resp.Body) + link, exists := htmlDoc.doc.Find("form.ui.form").Attr("action") + assert.True(t, exists, "The template has changed") + req = NewRequestWithValues(t, "POST", link, map[string]string{ + "_csrf": htmlDoc.GetCSRF(), + "title": title, + }) + resp = session.MakeRequest(t, req, http.StatusOK) + return resp +} + func TestPullCreate(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { session := loginUser(t, "user1") diff --git a/tests/integration/pull_review_test.go b/tests/integration/pull_review_test.go index 9a5877697c..2d8b3cb4ab 100644 --- a/tests/integration/pull_review_test.go +++ b/tests/integration/pull_review_test.go @@ -161,10 +161,18 @@ func TestPullView_CodeOwner(t *testing.T) { assert.NoError(t, err) session := loginUser(t, "user5") - testPullCreate(t, session, "user5", "test_codeowner", true, forkedRepo.DefaultBranch, "codeowner-basebranch-forked", "Test Pull Request2") + + // create a pull request on the forked repository, code reviewers should not be mentioned + testPullCreateDirectly(t, session, "user5", "test_codeowner", forkedRepo.DefaultBranch, "", "", "codeowner-basebranch-forked", "Test Pull Request on Forked Repository") pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{BaseRepoID: forkedRepo.ID, HeadBranch: "codeowner-basebranch-forked"}) unittest.AssertExistsIf(t, false, &issues_model.Review{IssueID: pr.IssueID, Type: issues_model.ReviewTypeRequest, ReviewerID: 8}) + + // create a pull request to base repository, code reviewers should be mentioned + testPullCreateDirectly(t, session, repo.OwnerName, repo.Name, repo.DefaultBranch, forkedRepo.OwnerName, forkedRepo.Name, "codeowner-basebranch-forked", "Test Pull Request3") + + pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{BaseRepoID: repo.ID, HeadRepoID: forkedRepo.ID, HeadBranch: "codeowner-basebranch-forked"}) + unittest.AssertExistsIf(t, true, &issues_model.Review{IssueID: pr.IssueID, Type: issues_model.ReviewTypeRequest, ReviewerID: 8}) }) }) } From 2dc7e9e5fe66a361021e41046f7a88e61a45300b Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Mon, 15 Apr 2024 19:20:32 +0200 Subject: [PATCH 120/370] Fix button color on red and green buttons (#30500) Previously these colors were provided by fomantic css. I missed them. Fixes: https://github.com/go-gitea/gitea/issues/30499 Regressed by: https://github.com/go-gitea/gitea/pull/30475 --- web_src/css/modules/button.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web_src/css/modules/button.css b/web_src/css/modules/button.css index 47f55df7fa..87b9ddf292 100644 --- a/web_src/css/modules/button.css +++ b/web_src/css/modules/button.css @@ -249,6 +249,7 @@ .ui.red.button, .ui.red.buttons .button { + color: var(--color-white); background: var(--color-red); } @@ -283,6 +284,7 @@ .ui.green.button, .ui.green.buttons .button { + color: var(--color-white); background: var(--color-green); } From 3b40ebf895307a705738df3c5aba31843f0be74d Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Mon, 15 Apr 2024 20:22:53 +0200 Subject: [PATCH 121/370] Remove active border on pointing menu (#30486) It looks better when these menus don't flash a border-bottom on click. --- web_src/css/modules/menu.css | 1 - 1 file changed, 1 deletion(-) diff --git a/web_src/css/modules/menu.css b/web_src/css/modules/menu.css index 2581d8fab2..a392ffb5e9 100644 --- a/web_src/css/modules/menu.css +++ b/web_src/css/modules/menu.css @@ -588,7 +588,6 @@ .ui.secondary.pointing.menu .dropdown.item:active, .ui.secondary.pointing.menu a.item:active { background-color: transparent; - border-color: var(--color-secondary); } .ui.secondary.pointing.menu .active.item { From 2c80421243ed1fd6f53c3e1a84c06648524f7c66 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 16 Apr 2024 04:08:31 +0900 Subject: [PATCH 122/370] Convert max file name length to 255 (#30489) Quick/Partly fix #29907 In Linux and MacOS, by default the max file name length is 255. In windows, it depends on the version and settings, and has no file name length limitation, but has path length limitation. By default it is 260, considering path length is longer than filename, so I think it is ok to do this. For Windows, see https://learn.microsoft.com/windows/win32/fileio/maximum-file-path-limitation?tabs=registry For Linux, see https://github.com/torvalds/linux/blob/master/include/uapi/linux/limits.h#L12-L13 For MacOS, see https://discussions.apple.com/thread/254788848?sortBy=best --- templates/repo/editor/edit.tmpl | 2 +- templates/repo/editor/upload.tmpl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/repo/editor/edit.tmpl b/templates/repo/editor/edit.tmpl index 46f82c47d4..d52e5a047a 100644 --- a/templates/repo/editor/edit.tmpl +++ b/templates/repo/editor/edit.tmpl @@ -15,7 +15,7 @@ {{range $i, $v := .TreeNames}} <div class="breadcrumb-divider">/</div> {{if eq $i $l}} - <input id="file-name" maxlength="500" value="{{$v}}" placeholder="{{ctx.Locale.Tr "repo.editor.name_your_file"}}" data-editorconfig="{{$.EditorconfigJson}}" required autofocus> + <input id="file-name" maxlength="255" value="{{$v}}" placeholder="{{ctx.Locale.Tr "repo.editor.name_your_file"}}" data-editorconfig="{{$.EditorconfigJson}}" required autofocus> <span data-tooltip-content="{{ctx.Locale.Tr "repo.editor.filename_help"}}">{{svg "octicon-info"}}</span> {{else}} <span class="section"><a href="{{$.BranchLink}}/{{index $.TreePaths $i | PathEscapeSegments}}">{{$v}}</a></span> diff --git a/templates/repo/editor/upload.tmpl b/templates/repo/editor/upload.tmpl index 0a7c49dae3..5725020406 100644 --- a/templates/repo/editor/upload.tmpl +++ b/templates/repo/editor/upload.tmpl @@ -13,7 +13,7 @@ {{range $i, $v := .TreeNames}} <div class="breadcrumb-divider">/</div> {{if eq $i $l}} - <input type="text" id="file-name" maxlength="500" value="{{$v}}" placeholder="{{ctx.Locale.Tr "repo.editor.add_subdir"}}" autofocus> + <input type="text" id="file-name" maxlength="255" value="{{$v}}" placeholder="{{ctx.Locale.Tr "repo.editor.add_subdir"}}" autofocus> <span data-tooltip-content="{{ctx.Locale.Tr "repo.editor.filename_help"}}">{{svg "octicon-info"}}</span> {{else}} <span class="section"><a href="{{$.BranchLink}}/{{index $.TreePaths $i | PathEscapeSegments}}">{{$v}}</a></span> From b9f69b4a4d1d6b5b1f94852f6dfcae41b30658ff Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Mon, 15 Apr 2024 21:46:52 +0200 Subject: [PATCH 123/370] Fix various overflows on actions view (#30344) Fix a number of text overflow issues in actions view and run list. Also improve mobile view of run list. Fixes: https://github.com/go-gitea/gitea/issues/30328 <img width="782" alt="Screenshot 2024-04-08 at 23 10 16" src="https://github.com/go-gitea/gitea/assets/115237/3d9f9f88-3eab-44a0-8144-30c2b58b24cb"> <img width="935" alt="Screenshot 2024-04-08 at 23 17 46" src="https://github.com/go-gitea/gitea/assets/115237/581d73ea-a31d-416b-be3a-47313b879b12"> <img width="1008" alt="Screenshot 2024-04-08 at 23 49 05" src="https://github.com/go-gitea/gitea/assets/115237/c5d10565-f285-477f-8659-1caf94797647"> <img width="397" alt="Screenshot 2024-04-08 at 23 55 30" src="https://github.com/go-gitea/gitea/assets/115237/368aaa75-1903-4058-9d75-d1fe91c564d6"> --- templates/repo/actions/runs_list.tmpl | 14 ++++++------- web_src/css/actions.css | 26 +++++++++++++++++++++++- web_src/js/components/RepoActionView.vue | 16 ++++++++++----- 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/templates/repo/actions/runs_list.tmpl b/templates/repo/actions/runs_list.tmpl index ac5049cf56..20330b5d62 100644 --- a/templates/repo/actions/runs_list.tmpl +++ b/templates/repo/actions/runs_list.tmpl @@ -1,4 +1,4 @@ -<div class="flex-list"> +<div class="flex-list run-list"> {{if not .Runs}} <div class="empty-placeholder"> {{svg "octicon-no-entry" 48}} @@ -28,14 +28,14 @@ </div> <div class="flex-item-trailing"> {{if .RefLink}} - <a class="ui label tw-px-1 tw-mx-0" href="{{.RefLink}}">{{.PrettyRef}}</a> + <a class="ui label run-list-ref gt-ellipsis" href="{{.RefLink}}">{{.PrettyRef}}</a> {{else}} - <span class="ui label tw-px-1 tw-mx-0">{{.PrettyRef}}</span> + <span class="ui label run-list-ref gt-ellipsis">{{.PrettyRef}}</span> {{end}} - </div> - <div class="run-list-item-right"> - <div class="run-list-meta">{{svg "octicon-calendar" 16}}{{TimeSinceUnix .Updated ctx.Locale}}</div> - <div class="run-list-meta">{{svg "octicon-stopwatch" 16}}{{.Duration}}</div> + <div class="run-list-item-right"> + <div class="run-list-meta">{{svg "octicon-calendar" 16}}{{TimeSinceUnix .Updated ctx.Locale}}</div> + <div class="run-list-meta">{{svg "octicon-stopwatch" 16}}{{.Duration}}</div> + </div> </div> </div> {{end}} diff --git a/web_src/css/actions.css b/web_src/css/actions.css index 1d5bea2395..0ab09f537a 100644 --- a/web_src/css/actions.css +++ b/web_src/css/actions.css @@ -44,9 +44,10 @@ } .run-list-item-right { - flex: 0 0 min(20%, 130px); + width: 130px; display: flex; flex-direction: column; + flex-shrink: 0; gap: 3px; color: var(--color-text-light); } @@ -57,3 +58,26 @@ gap: .25rem; align-items: center; } + +.run-list .flex-item-trailing { + flex-wrap: nowrap; + width: 280px; + flex: 0 0 280px; +} + +.run-list-ref { + display: inline-block !important; +} + +@media (max-width: 767.98px) { + .run-list .flex-item-trailing { + flex-direction: column; + align-items: flex-end; + width: auto; + flex-basis: auto; + } + .run-list-item-right, + .run-list-ref { + max-width: 110px; + } +} diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index 06c42f0b35..16ce3fc80d 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -377,7 +377,7 @@ export function initRepositoryActionView() { <button class="ui basic small compact button red" @click="cancelRun()" v-else-if="run.canCancel"> {{ locale.cancel }} </button> - <button class="ui basic small compact button tw-mr-0 link-action" :data-url="`${run.link}/rerun`" v-else-if="run.canRerun"> + <button class="ui basic small compact button tw-mr-0 tw-whitespace-nowrap link-action" :data-url="`${run.link}/rerun`" v-else-if="run.canRerun"> {{ locale.rerun_all }} </button> </div> @@ -386,8 +386,8 @@ export function initRepositoryActionView() { <a class="muted" :href="run.commit.link">{{ run.commit.shortSHA }}</a> {{ run.commit.localePushedBy }} <a class="muted" :href="run.commit.pusher.link">{{ run.commit.pusher.displayName }}</a> - <span class="ui label" v-if="run.commit.shortSHA"> - <a :href="run.commit.branch.link">{{ run.commit.branch.name }}</a> + <span class="ui label tw-max-w-full" v-if="run.commit.shortSHA"> + <a class="gt-ellipsis" :href="run.commit.branch.link">{{ run.commit.branch.name }}</a> </span> </div> </div> @@ -426,8 +426,8 @@ export function initRepositoryActionView() { <div class="action-view-right"> <div class="job-info-header"> - <div class="job-info-header-left"> - <h3 class="job-info-header-title"> + <div class="job-info-header-left gt-ellipsis"> + <h3 class="job-info-header-title gt-ellipsis"> {{ currentJob.title }} </h3> <p class="job-info-header-detail"> @@ -503,6 +503,7 @@ export function initRepositoryActionView() { display: flex; align-items: center; justify-content: space-between; + gap: 8px; } .action-info-summary-title { @@ -513,6 +514,7 @@ export function initRepositoryActionView() { font-size: 20px; margin: 0 0 0 8px; flex: 1; + overflow-wrap: anywhere; } .action-commit-summary { @@ -728,6 +730,10 @@ export function initRepositoryActionView() { font-size: 12px; } +.job-info-header-left { + flex: 1; +} + .job-step-container { max-height: 100%; border-radius: 0 0 var(--border-radius) var(--border-radius); From 3b045ee165c8ba06c99c28d57b849fb53a502e84 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Tue, 16 Apr 2024 00:23:51 +0000 Subject: [PATCH 124/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_ja-JP.ini | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 0edd6c5dd7..74ff775cc8 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -25,6 +25,7 @@ enable_javascript=このウェブサイトにはJavaScriptが必要です。 toc=目次 licenses=ライセンス return_to_gitea=Giteaに戻る +more_items=その他の項目 username=ユーザー名 email=メールアドレス @@ -1003,6 +1004,7 @@ fork_visibility_helper=フォークしたリポジトリの公開/非公開は fork_branch=フォークにクローンされるブランチ all_branches=すべてのブランチ fork_no_valid_owners=このリポジトリには有効なオーナーがいないため、フォークできません。 +fork.blocked_user=リポジトリのオーナーがあなたをブロックしているため、リポジトリをフォークできません。 use_template=このテンプレートを使用 open_with_editor=%s で開く download_zip=ZIPファイルをダウンロード @@ -1179,6 +1181,7 @@ watch=ウォッチ unstar=スター取消 star=スター fork=フォーク +action.blocked_user=リポジトリのオーナーがあなたをブロックしているため、アクションを実行できません。 download_archive=リポジトリをダウンロード more_operations=その他の操作 @@ -1427,6 +1430,8 @@ issues.new.assignees=担当者 issues.new.clear_assignees=担当者をクリア issues.new.no_assignees=担当者なし issues.new.no_reviewers=レビューアなし +issues.new.blocked_user=リポジトリのオーナーがあなたをブロックしているため、イシューを作成できません。 +issues.edit.blocked_user=投稿者またはリポジトリのオーナーがあなたをブロックしているため、内容を編集できません。 issues.choose.get_started=始める issues.choose.open_external_link=オープン issues.choose.blank=デフォルト @@ -1541,6 +1546,7 @@ issues.close_comment_issue=コメントしてクローズ issues.reopen_issue=再オープンする issues.reopen_comment_issue=コメントして再オープン issues.create_comment=コメントする +issues.comment.blocked_user=投稿者またはリポジトリのオーナーがあなたをブロックしているため、コメントの作成や編集はできません。 issues.closed_at=`がイシューをクローズ <a id="%[1]s" href="#%[1]s">%[2]s</a>` issues.reopened_at=`がイシューを再オープン <a id="%[1]s" href="#%[1]s">%[2]s</a>` issues.commit_ref_at=`がコミットでこのイシューを参照 <a id="%[1]s" href="#%[1]s">%[2]s</a>` @@ -1739,6 +1745,7 @@ compare.compare_head=比較 pulls.desc=プルリクエストとコードレビューの有効化。 pulls.new=新しいプルリクエスト +pulls.new.blocked_user=リポジトリのオーナーがあなたをブロックしているため、プルリクエストを作成できません。 pulls.view=プルリクエストを表示 pulls.compare_changes=新規プルリクエスト pulls.allow_edits_from_maintainers=メンテナーからの編集を許可する @@ -1960,6 +1967,7 @@ wiki.original_git_entry_tooltip=フレンドリーリンクを使用する代わ activity=アクティビティ activity.navbar.pulse=Pulse +activity.navbar.code_frequency=コード更新頻度 activity.navbar.contributors=貢献者 activity.navbar.recent_commits=最近のコミット activity.period.filter_label=期間: @@ -2080,6 +2088,8 @@ settings.branches.add_new_rule=新しいルールを追加 settings.advanced_settings=拡張設定 settings.wiki_desc=Wikiを有効にする settings.use_internal_wiki=ビルトインのWikiを使用する +settings.default_wiki_branch_name=デフォルトのWikiブランチ名 +settings.failed_to_change_default_wiki_branch=デフォルトのWikiブランチを変更できませんでした。 settings.use_external_wiki=外部のWikiを使用する settings.external_wiki_url=外部WikiのURL settings.external_wiki_url_error=外部WikiのURLが有効なURLではありません。 @@ -2110,6 +2120,9 @@ settings.pulls.default_allow_edits_from_maintainers=デフォルトでメンテ settings.releases_desc=リリースを有効にする settings.packages_desc=リポジトリパッケージレジストリを有効にする settings.projects_desc=プロジェクトを有効にする +settings.projects_mode_desc=プロジェクト モード (表示するプロジェクトの種類) +settings.projects_mode_repo=リポジトリのプロジェクトのみ +settings.projects_mode_owner=ユーザーや組織のプロジェクトのみ settings.projects_mode_all=すべてのプロジェクト settings.actions_desc=Actionsを有効にする settings.admin_settings=管理者用設定 @@ -2136,6 +2149,7 @@ settings.convert_fork_succeed=フォークを通常のリポジトリに変換 settings.transfer=オーナー移転 settings.transfer.rejected=リポジトリの移転は拒否されました。 settings.transfer.success=リポジトリの移転が成功しました。 +settings.transfer.blocked_user=新しいオーナーがあなたをブロックしているため、リポジトリを移転できません。 settings.transfer_abort=転送をキャンセル settings.transfer_abort_invalid=存在しないリポジトリの移転はキャンセルできません。 settings.transfer_abort_success=%s へのリポジトリ移転は正常にキャンセルされました。 @@ -2181,6 +2195,7 @@ settings.add_collaborator_success=共同作業者を追加しました。 settings.add_collaborator_inactive_user=アクティベートされていないユーザーを共同作業者として追加することはできません。 settings.add_collaborator_owner=共同作業者としてオーナーを追加することはできません。 settings.add_collaborator_duplicate=共同作業者として既にこのリポジトリに追加されています。 +settings.add_collaborator.blocked_user=共同作業者がリポジトリのオーナーによってブロックされているか、またはブロックしています。 settings.delete_collaborator=削除 settings.collaborator_deletion=共同作業者の削除 settings.collaborator_deletion_desc=共同作業者を削除し、このリポジトリへのアクセス権を取り消します。 続行しますか? @@ -2619,12 +2634,14 @@ find_file.no_matching=一致するファイルが見つかりません error.csv.too_large=このファイルは大きすぎるため表示できません。 error.csv.unexpected=このファイルは %d 行目の %d 文字目に予期しない文字が含まれているため表示できません。 error.csv.invalid_field_count=このファイルは %d 行目のフィールドの数が正しくないため表示できません。 +error.broken_git_hook=このリポジトリのGitフックが壊れているようです。 <a target="_blank" rel="noreferrer" href="%s">ドキュメント</a>に従って修正し、その後いくつかのコミットをプッシュして状態を最新にしてください。 [graphs] component_loading=%sを読み込み中... component_loading_failed=%sを読み込めませんでした component_loading_info=少し時間がかかるかもしれません… component_failed_to_load=予期しないエラーが発生しました。 +code_frequency.what=コード更新頻度 contributors.what=実績 recent_commits.what=最近のコミット @@ -2753,6 +2770,7 @@ teams.invite.by=%s からの招待 teams.invite.description=下のボタンをクリックしてチームに参加してください。 [admin] +maintenance=メンテナンス dashboard=ダッシュボード self_check=セルフチェック identity_access=アイデンティティとアクセス @@ -2776,6 +2794,7 @@ settings=管理設定 dashboard.new_version_hint=Gitea %s が入手可能になりました。 現在実行しているのは %s です。 詳細は <a target="_blank" rel="noreferrer" href="https://blog.gitea.io">ブログ</a> を確認してください。 dashboard.statistic=サマリー +dashboard.maintenance_operations=メンテナンス操作 dashboard.system_status=システム状況 dashboard.operation_name=操作の名称 dashboard.operation_switch=切り替え @@ -3282,6 +3301,7 @@ notices.op=操作 notices.delete_success=システム通知を削除しました。 self_check.no_problem_found=今のところ問題は見つかっていません。 +self_check.startup_warnings=起動時の警告: self_check.database_collation_mismatch=データベースに想定される照合順序: %s self_check.database_collation_case_insensitive=データベースは照合順序 %s を使用しており、大文字小文字を区別しません。 Giteaはその照合順序でも動作するかもしれませんが、まれに期待どおり動作しないケースがあるかもしれません。 self_check.database_inconsistent_collation_columns=データベースは照合順序 %s を使用していますが、以下のカラムはそれと一致しない照合順序を使用しており、予期せぬ問題を引き起こす可能性があります。 From c70e442ce4b99e2a1f1bf216afcfa1ad78d1925a Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu <appleboy.tw@gmail.com> Date: Tue, 16 Apr 2024 11:45:04 +0800 Subject: [PATCH 125/370] feat(api): implement branch/commit comparison API (#30349) - Add new `Compare` struct to represent comparison between two commits - Introduce new API endpoint `/compare/*` to get commit comparison information - Create new file `repo_compare.go` with the `Compare` struct definition - Add new file `compare.go` in `routers/api/v1/repo` to handle comparison logic - Add new file `compare.go` in `routers/common` to define `CompareInfo` struct - Refactor `ParseCompareInfo` function to use `common.CompareInfo` struct - Update Swagger documentation to include the new API endpoint for commit comparison - Remove duplicate `CompareInfo` struct from `routers/web/repo/compare.go` - Adjust base path in Swagger template to be relative (`/api/v1`) GitHub API https://docs.github.com/en/rest/commits/commits?apiVersion=2022-11-28#compare-two-commits --------- Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> --- modules/structs/repo_compare.go | 10 +++ routers/api/v1/api.go | 2 + routers/api/v1/repo/compare.go | 99 ++++++++++++++++++++++ routers/api/v1/swagger/repo.go | 6 ++ routers/common/compare.go | 21 +++++ routers/web/repo/compare.go | 18 +--- templates/swagger/v1_json.tmpl | 70 +++++++++++++++ tests/integration/api_repo_compare_test.go | 38 +++++++++ 8 files changed, 250 insertions(+), 14 deletions(-) create mode 100644 modules/structs/repo_compare.go create mode 100644 routers/api/v1/repo/compare.go create mode 100644 routers/common/compare.go create mode 100644 tests/integration/api_repo_compare_test.go diff --git a/modules/structs/repo_compare.go b/modules/structs/repo_compare.go new file mode 100644 index 0000000000..8a12498705 --- /dev/null +++ b/modules/structs/repo_compare.go @@ -0,0 +1,10 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package structs + +// Compare represents a comparison between two commits. +type Compare struct { + TotalCommits int `json:"total_commits"` // Total number of commits in the comparison. + Commits []*Commit `json:"commits"` // List of commits in the comparison. +} diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index e870378c4b..1fc7682966 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -1066,6 +1066,8 @@ func Routes() *web.Route { m.Post("/migrate", reqToken(), bind(api.MigrateRepoOptions{}), repo.Migrate) m.Group("/{username}/{reponame}", func() { + m.Get("/compare/*", reqRepoReader(unit.TypeCode), repo.CompareDiff) + m.Combo("").Get(reqAnyRepoReader(), repo.Get). Delete(reqToken(), reqOwner(), repo.Delete). Patch(reqToken(), reqAdmin(), bind(api.EditRepoOption{}), repo.Edit) diff --git a/routers/api/v1/repo/compare.go b/routers/api/v1/repo/compare.go new file mode 100644 index 0000000000..549b9b7fa9 --- /dev/null +++ b/routers/api/v1/repo/compare.go @@ -0,0 +1,99 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repo + +import ( + "net/http" + "strings" + + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/gitrepo" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/convert" +) + +// CompareDiff compare two branches or commits +func CompareDiff(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/compare/{basehead} Get commit comparison information + // --- + // summary: Get commit comparison information + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: basehead + // in: path + // description: compare two branches or commits + // type: string + // required: true + // responses: + // "200": + // "$ref": "#/responses/Compare" + // "404": + // "$ref": "#/responses/notFound" + + if ctx.Repo.GitRepo == nil { + gitRepo, err := gitrepo.OpenRepository(ctx, ctx.Repo.Repository) + if err != nil { + ctx.Error(http.StatusInternalServerError, "OpenRepository", err) + return + } + ctx.Repo.GitRepo = gitRepo + defer gitRepo.Close() + } + + infoPath := ctx.Params("*") + infos := []string{ctx.Repo.Repository.DefaultBranch, ctx.Repo.Repository.DefaultBranch} + if infoPath != "" { + infos = strings.SplitN(infoPath, "...", 2) + if len(infos) != 2 { + if infos = strings.SplitN(infoPath, "..", 2); len(infos) != 2 { + infos = []string{ctx.Repo.Repository.DefaultBranch, infoPath} + } + } + } + + _, _, headGitRepo, ci, _, _ := parseCompareInfo(ctx, api.CreatePullRequestOption{ + Base: infos[0], + Head: infos[1], + }) + if ctx.Written() { + return + } + defer headGitRepo.Close() + + verification := ctx.FormString("verification") == "" || ctx.FormBool("verification") + files := ctx.FormString("files") == "" || ctx.FormBool("files") + + apiCommits := make([]*api.Commit, 0, len(ci.Commits)) + userCache := make(map[string]*user_model.User) + for i := 0; i < len(ci.Commits); i++ { + apiCommit, err := convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, ci.Commits[i], userCache, + convert.ToCommitOptions{ + Stat: true, + Verification: verification, + Files: files, + }) + if err != nil { + ctx.ServerError("toCommit", err) + return + } + apiCommits = append(apiCommits, apiCommit) + } + + ctx.JSON(http.StatusOK, &api.Compare{ + TotalCommits: len(ci.Commits), + Commits: apiCommits, + }) +} diff --git a/routers/api/v1/swagger/repo.go b/routers/api/v1/swagger/repo.go index 3e23aa4d5a..c3219f28d6 100644 --- a/routers/api/v1/swagger/repo.go +++ b/routers/api/v1/swagger/repo.go @@ -414,3 +414,9 @@ type swaggerRepoNewIssuePinsAllowed struct { // in:body Body api.NewIssuePinsAllowed `json:"body"` } + +// swagger:response Compare +type swaggerCompare struct { + // in:body + Body api.Compare `json:"body"` +} diff --git a/routers/common/compare.go b/routers/common/compare.go new file mode 100644 index 0000000000..4d1cc2f0d8 --- /dev/null +++ b/routers/common/compare.go @@ -0,0 +1,21 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package common + +import ( + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" +) + +// CompareInfo represents the collected results from ParseCompareInfo +type CompareInfo struct { + HeadUser *user_model.User + HeadRepo *repo_model.Repository + HeadGitRepo *git.Repository + CompareInfo *git.CompareInfo + BaseBranch string + HeadBranch string + DirectComparison bool +} diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index cfb0e859bd..035a92f228 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -35,6 +35,7 @@ import ( api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/typesniffer" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/routers/common" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/context/upload" "code.gitea.io/gitea/services/gitdiff" @@ -185,21 +186,10 @@ func setCsvCompareContext(ctx *context.Context) { } } -// CompareInfo represents the collected results from ParseCompareInfo -type CompareInfo struct { - HeadUser *user_model.User - HeadRepo *repo_model.Repository - HeadGitRepo *git.Repository - CompareInfo *git.CompareInfo - BaseBranch string - HeadBranch string - DirectComparison bool -} - // ParseCompareInfo parse compare info between two commit for preparing comparing references -func ParseCompareInfo(ctx *context.Context) *CompareInfo { +func ParseCompareInfo(ctx *context.Context) *common.CompareInfo { baseRepo := ctx.Repo.Repository - ci := &CompareInfo{} + ci := &common.CompareInfo{} fileOnly := ctx.FormBool("file-only") @@ -576,7 +566,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { // PrepareCompareDiff renders compare diff page func PrepareCompareDiff( ctx *context.Context, - ci *CompareInfo, + ci *common.CompareInfo, whitespaceBehavior git.TrustedCmdArgs, ) bool { var ( diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index b5677c77e0..254b7daf17 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -5340,6 +5340,51 @@ } } }, + "/repos/{owner}/{repo}/compare/{basehead}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Get", + "commit", + "comparison" + ], + "summary": "Get commit comparison information", + "operationId": "information", + "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": "string", + "description": "compare two branches or commits", + "name": "basehead", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/Compare" + }, + "404": { + "$ref": "#/responses/notFound" + } + } + } + }, "/repos/{owner}/{repo}/contents": { "get": { "produces": [ @@ -18717,6 +18762,25 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "Compare": { + "type": "object", + "title": "Compare represents a comparison between two commits.", + "properties": { + "commits": { + "type": "array", + "items": { + "$ref": "#/definitions/Commit" + }, + "x-go-name": "Commits" + }, + "total_commits": { + "type": "integer", + "format": "int64", + "x-go-name": "TotalCommits" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "ContentsResponse": { "description": "ContentsResponse contains information about a repo's entry's (dir, file, symlink, submodule) metadata and content", "type": "object", @@ -24678,6 +24742,12 @@ } } }, + "Compare": { + "description": "", + "schema": { + "$ref": "#/definitions/Compare" + } + }, "ContentsListResponse": { "description": "ContentsListResponse", "schema": { diff --git a/tests/integration/api_repo_compare_test.go b/tests/integration/api_repo_compare_test.go new file mode 100644 index 0000000000..f3188eb49f --- /dev/null +++ b/tests/integration/api_repo_compare_test.go @@ -0,0 +1,38 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package integration + +import ( + "net/http" + "testing" + + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/tests" + + "github.com/stretchr/testify/assert" +) + +func TestAPICompareBranches(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + // Login as User2. + session := loginUser(t, user.Name) + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) + + repoName := "repo20" + + req := NewRequestf(t, "GET", "/api/v1/repos/user2/%s/compare/add-csv...remove-files-b", repoName). + AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusOK) + + var apiResp *api.Compare + DecodeJSON(t, resp, &apiResp) + + assert.Equal(t, 2, apiResp.TotalCommits) + assert.Len(t, apiResp.Commits, 2) +} From cf9061f44a439aa7775e301a7467dbda22a06eaa Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 16 Apr 2024 14:13:00 +0900 Subject: [PATCH 126/370] Fix empty field `login_name` in API response JSON when creating user (#30511) Fix #30508 ps: if `sourceID` is not set, `LoginName` will be ignored --- routers/api/v1/admin/user.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go index 87a5b28fad..be907805d6 100644 --- a/routers/api/v1/admin/user.go +++ b/routers/api/v1/admin/user.go @@ -30,7 +30,7 @@ import ( user_service "code.gitea.io/gitea/services/user" ) -func parseAuthSource(ctx *context.APIContext, u *user_model.User, sourceID int64, loginName string) { +func parseAuthSource(ctx *context.APIContext, u *user_model.User, sourceID int64) { if sourceID == 0 { return } @@ -47,7 +47,6 @@ func parseAuthSource(ctx *context.APIContext, u *user_model.User, sourceID int64 u.LoginType = source.Type u.LoginSource = source.ID - u.LoginName = loginName } // CreateUser create a user @@ -83,12 +82,13 @@ func CreateUser(ctx *context.APIContext) { Passwd: form.Password, MustChangePassword: true, LoginType: auth.Plain, + LoginName: form.LoginName, } if form.MustChangePassword != nil { u.MustChangePassword = *form.MustChangePassword } - parseAuthSource(ctx, u, form.SourceID, form.LoginName) + parseAuthSource(ctx, u, form.SourceID) if ctx.Written() { return } From 6ba0c371c21237376c292ee92ec067b4a1ef1218 Mon Sep 17 00:00:00 2001 From: SimonErm <33630884+SimonErm@users.noreply.github.com> Date: Tue, 16 Apr 2024 07:41:39 +0200 Subject: [PATCH 127/370] Allow `preferred_username` as username source for OIDC (#30454) This PR adds the preferred_username claim as a possible username source for the oauth2_client. Closes #21518 --- custom/conf/app.example.ini | 3 ++- docs/content/administration/config-cheat-sheet.en-us.md | 5 +++-- modules/setting/oauth2.go | 4 +++- routers/web/auth/auth.go | 7 +++++++ 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 918252044b..32b51fd7c6 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1553,8 +1553,9 @@ LEVEL = Info ;; The source of the username for new oauth2 accounts: ;; userid = use the userid / sub attribute ;; nickname = use the nickname attribute +;; preferred_username = use the preferred_username attribute ;; email = use the username part of the email attribute -;; Note: `nickname` and `email` options will normalize input strings using the following criteria: +;; Note: `nickname`, `preferred_username` and `email` options will normalize input strings using the following criteria: ;; - diacritics are removed ;; - the characters in the set `['´\x60]` are removed ;; - the characters in the set `[\s~+]` are replaced with `-` diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index 9de7511964..ff8bcb066c 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -608,9 +608,10 @@ And the following unique queues: - `ENABLE_AUTO_REGISTRATION`: **false**: Automatically create user accounts for new oauth2 users. - `USERNAME`: **nickname**: The source of the username for new oauth2 accounts: - `userid` - use the userid / sub attribute - - `nickname` - use the nickname attribute + - `nickname` - use the nickname + - `preferred_username` - use the preferred_username - `email` - use the username part of the email attribute - - Note: `nickname` and `email` options will normalize input strings using the following criteria: + - Note: `nickname`, `preferred_username` and `email` options will normalize input strings using the following criteria: - diacritics are removed - the characters in the set `['´\x60]` are removed - the characters in the set `[\s~+]` are replaced with `-` diff --git a/modules/setting/oauth2.go b/modules/setting/oauth2.go index 830472db32..6930197b22 100644 --- a/modules/setting/oauth2.go +++ b/modules/setting/oauth2.go @@ -22,11 +22,13 @@ const ( OAuth2UsernameNickname OAuth2UsernameType = "nickname" // OAuth2UsernameEmail username of oauth2 email field will be used as gitea name OAuth2UsernameEmail OAuth2UsernameType = "email" + // OAuth2UsernameEmail username of oauth2 preferred_username field will be used as gitea name + OAuth2UsernamePreferredUsername OAuth2UsernameType = "preferred_username" ) func (username OAuth2UsernameType) isValid() bool { switch username { - case OAuth2UsernameUserid, OAuth2UsernameNickname, OAuth2UsernameEmail: + case OAuth2UsernameUserid, OAuth2UsernameNickname, OAuth2UsernameEmail, OAuth2UsernamePreferredUsername: return true } return false diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 8b5cd986b8..9ef32ebdb1 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -386,6 +386,13 @@ func getUserName(gothUser *goth.User) (string, error) { switch setting.OAuth2Client.Username { case setting.OAuth2UsernameEmail: return user_model.NormalizeUserName(strings.Split(gothUser.Email, "@")[0]) + case setting.OAuth2UsernamePreferredUsername: + preferredUsername, exists := gothUser.RawData["preferred_username"] + if exists { + return user_model.NormalizeUserName(preferredUsername.(string)) + } else { + return "", fmt.Errorf("preferred_username is missing in received user data but configured as username source for user_id %q. Check if OPENID_CONNECT_SCOPES contains profile", gothUser.UserID) + } case setting.OAuth2UsernameNickname: return user_model.NormalizeUserName(gothUser.NickName) default: // OAuth2UsernameUserid From 58b204b813cd3a97db904d889d552e64a7e398ff Mon Sep 17 00:00:00 2001 From: Tobias Balle-Petersen <tobiasbp@gmail.com> Date: Tue, 16 Apr 2024 08:08:48 +0200 Subject: [PATCH 128/370] Update API to return 'source_id' for users (#29718) Using the API, a user's _source_id_ can be set in the _CreateUserOption_ model, but the field is not returned in the _User_ model. This PR updates the _User_ model to include the field _source_id_ (The ID of the Authentication Source). --- modules/structs/user.go | 2 ++ services/convert/user.go | 1 + templates/swagger/v1_json.tmpl | 6 ++++++ 3 files changed, 9 insertions(+) diff --git a/modules/structs/user.go b/modules/structs/user.go index 21ecc1479e..ca6ab79944 100644 --- a/modules/structs/user.go +++ b/modules/structs/user.go @@ -20,6 +20,8 @@ type User struct { // the user's authentication sign-in name. // default: empty LoginName string `json:"login_name"` + // The ID of the user's Authentication Source + SourceID int64 `json:"source_id"` // the user's full name FullName string `json:"full_name"` // swagger:strfmt email diff --git a/services/convert/user.go b/services/convert/user.go index 3521dd2f90..1a2733d91e 100644 --- a/services/convert/user.go +++ b/services/convert/user.go @@ -75,6 +75,7 @@ func toUser(ctx context.Context, user *user_model.User, signed, authed bool) *ap if authed { result.IsAdmin = user.IsAdmin result.LoginName = user.LoginName + result.SourceID = user.LoginSource result.LastLogin = user.LastLoginUnix.AsTime() result.Language = user.Language result.IsActive = user.IsActive diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 254b7daf17..532b8880bc 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -24260,6 +24260,12 @@ "type": "boolean", "x-go-name": "Restricted" }, + "source_id": { + "description": "The ID of the user's Authentication Source", + "type": "integer", + "format": "int64", + "x-go-name": "SourceID" + }, "starred_repos_count": { "type": "integer", "format": "int64", From a658e2f277af435517f022355af697bdf588708e Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Tue, 16 Apr 2024 10:52:45 +0200 Subject: [PATCH 129/370] Fix long branch name overflows (#30345) Fixes: https://github.com/go-gitea/gitea/issues/27971 Fixes: https://github.com/go-gitea/gitea/pull/28010 <img width="689" alt="Screenshot 2024-04-09 at 00 19 57" src="https://github.com/go-gitea/gitea/assets/115237/7c895a47-274f-40a6-a126-290658f1982d"> Also fixes a similar issue in issue list where CSS was there but not active because of missing `display: block`. <img width="372" alt="Screenshot 2024-04-09 at 00 18 25" src="https://github.com/go-gitea/gitea/assets/115237/cfbee7cd-2e15-4ac7-96ce-020816f48798"> --- templates/repo/branch_dropdown.tmpl | 4 ++-- .../repo/issue/branch_selector_field.tmpl | 6 +++--- templates/repo/issue/view_title.tmpl | 2 +- templates/shared/issuelist.tmpl | 15 ++++++++------ web_src/css/base.css | 2 ++ web_src/css/repo.css | 20 ++++++------------- web_src/css/repo/issue-list.css | 6 ++++-- .../js/components/RepoBranchTagSelector.vue | 4 ++-- 8 files changed, 29 insertions(+), 30 deletions(-) diff --git a/templates/repo/branch_dropdown.tmpl b/templates/repo/branch_dropdown.tmpl index 6c2e08a985..7b39830df8 100644 --- a/templates/repo/branch_dropdown.tmpl +++ b/templates/repo/branch_dropdown.tmpl @@ -71,7 +71,7 @@ {{/* show dummy elements before Vue componment is mounted, this code must match the code in BranchTagSelector.vue */}} <div class="ui dropdown custom"> <button class="branch-dropdown-button gt-ellipsis ui basic small compact button tw-flex tw-m-0"> - <span class="text tw-flex tw-items-center tw-mr-1"> + <span class="text tw-flex tw-items-center tw-mr-1 gt-ellipsis"> {{if .release}} {{ctx.Locale.Tr "repo.release.compare"}} {{else}} @@ -80,7 +80,7 @@ {{else}} {{svg "octicon-git-branch"}} {{end}} - <strong ref="dropdownRefName" class="tw-ml-2">{{if and .root.IsViewTag (not .noTag)}}{{.root.TagName}}{{else if .root.IsViewBranch}}{{.root.BranchName}}{{else}}{{ShortSha .root.CommitID}}{{end}}</strong> + <strong ref="dropdownRefName" class="tw-ml-2 tw-inline-block gt-ellipsis">{{if and .root.IsViewTag (not .noTag)}}{{.root.TagName}}{{else if .root.IsViewBranch}}{{.root.BranchName}}{{else}}{{ShortSha .root.CommitID}}{{end}}</strong> {{end}} </span> {{svg "octicon-triangle-down" 14 "dropdown icon"}} diff --git a/templates/repo/issue/branch_selector_field.tmpl b/templates/repo/issue/branch_selector_field.tmpl index b8ac9a6194..ed0d58cf27 100644 --- a/templates/repo/issue/branch_selector_field.tmpl +++ b/templates/repo/issue/branch_selector_field.tmpl @@ -5,9 +5,9 @@ {{$.CsrfTokenHtml}} </form> {{/* TODO: share this branch selector dropdown with the same in repo page */}} -<div class="ui {{if not .HasIssuesOrPullsWritePermission}}disabled{{end}} floating filter select-branch dropdown" data-no-results="{{ctx.Locale.Tr "no_results_found"}}"> +<div class="ui {{if not .HasIssuesOrPullsWritePermission}}disabled{{end}} floating filter select-branch dropdown tw-max-w-full" data-no-results="{{ctx.Locale.Tr "no_results_found"}}"> <div class="ui basic small button"> - <span class="text branch-name">{{if .Reference}}{{$.RefEndName}}{{else}}{{ctx.Locale.Tr "repo.issues.no_ref"}}{{end}}</span> + <span class="text branch-name gt-ellipsis">{{if .Reference}}{{$.RefEndName}}{{else}}{{ctx.Locale.Tr "repo.issues.no_ref"}}{{end}}</span> {{if .HasIssuesOrPullsWritePermission}}{{svg "octicon-triangle-down" 14 "dropdown icon"}}{{end}} </div> <div class="menu"> @@ -37,7 +37,7 @@ <div class="item text small" data-id="" data-id-selector="#ref_selector"><strong><a href="#">{{ctx.Locale.Tr "repo.clear_ref"}}</a></strong></div> {{end}} {{range .Branches}} - <div class="item" data-id="refs/heads/{{.}}" data-name="{{.}}" data-id-selector="#ref_selector">{{.}}</div> + <div class="item" data-id="refs/heads/{{.}}" data-name="{{.}}" data-id-selector="#ref_selector" title="{{.}}">{{.}}</div> {{else}} <div class="item">{{ctx.Locale.Tr "no_results_found"}}</div> {{end}} diff --git a/templates/repo/issue/view_title.tmpl b/templates/repo/issue/view_title.tmpl index b78ff55cda..fccf8cca91 100644 --- a/templates/repo/issue/view_title.tmpl +++ b/templates/repo/issue/view_title.tmpl @@ -41,7 +41,7 @@ {{else}} <div class="ui green label issue-state-label">{{svg "octicon-issue-opened"}} {{ctx.Locale.Tr "repo.issues.open_title"}}</div> {{end}} - <div class="tw-ml-2"> + <div class="tw-ml-2 tw-flex-1 tw-break-anywhere"> {{if .Issue.IsPull}} {{$headHref := .HeadTarget}} {{if .HeadBranchLink}} diff --git a/templates/shared/issuelist.tmpl b/templates/shared/issuelist.tmpl index 1c0dfcc551..16c650ee3e 100644 --- a/templates/shared/issuelist.tmpl +++ b/templates/shared/issuelist.tmpl @@ -88,18 +88,21 @@ </div> {{end}} {{if and .Milestone (ne $.listType "milestone")}} - <a class="milestone flex-text-inline" {{if $.RepoLink}}href="{{$.RepoLink}}/milestone/{{.Milestone.ID}}"{{else}}href="{{.Repo.Link}}/milestone/{{.Milestone.ID}}"{{end}}> - {{svg "octicon-milestone" 14}}{{.Milestone.Name}} + <a class="milestone flex-text-inline tw-max-w-[300px]" {{if $.RepoLink}}href="{{$.RepoLink}}/milestone/{{.Milestone.ID}}"{{else}}href="{{.Repo.Link}}/milestone/{{.Milestone.ID}}"{{end}}> + {{svg "octicon-milestone" 14}} + <span class="gt-ellipsis">{{.Milestone.Name}}</span> </a> {{end}} {{if .Project}} - <a class="project flex-text-inline" href="{{.Project.Link ctx}}"> - {{svg .Project.IconName 14}}{{.Project.Title}} + <a class="project flex-text-inline tw-max-w-[300px]" href="{{.Project.Link ctx}}"> + {{svg .Project.IconName 14}} + <span class="gt-ellipsis">{{.Project.Title}}</span> </a> {{end}} {{if .Ref}} - <a class="ref flex-text-inline" {{if $.RepoLink}}href="{{index $.IssueRefURLs .ID}}"{{else}}href="{{.Repo.Link}}{{index $.IssueRefURLs .ID}}"{{end}}> - {{svg "octicon-git-branch" 14}}{{index $.IssueRefEndNames .ID}} + <a class="ref flex-text-inline tw-max-w-[300px]" {{if $.RepoLink}}href="{{index $.IssueRefURLs .ID}}"{{else}}href="{{.Repo.Link}}{{index $.IssueRefURLs .ID}}"{{end}}> + {{svg "octicon-git-branch" 14}} + <span class="gt-ellipsis">{{index $.IssueRefEndNames .ID}}</span> </a> {{end}} {{$tasks := .GetTasks}} diff --git a/web_src/css/base.css b/web_src/css/base.css index 8ded4aa883..7e781aa97b 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -342,6 +342,8 @@ a.label, .ui.dropdown .menu > .item { color: var(--color-text); + overflow: hidden; + text-overflow: ellipsis; } .ui.dropdown .menu > .item:hover { diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 0f6bf482b5..8d1f60d158 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -50,6 +50,11 @@ width: 300px; } +.issue-content-right .dropdown > .menu { + max-width: 270px; + min-width: 0; +} + @media (max-width: 767.98px) { .issue-content-left, .issue-content-right { @@ -57,11 +62,6 @@ } } -.repository .issue-content-right .menu { - overflow-x: auto; - max-height: 500px; -} - .repository .issue-content-right .ui.list .dependency { padding: 0; white-space: nowrap; @@ -113,11 +113,6 @@ left: 0; } -.repository .filter.menu .ui.dropdown .menu .item { - overflow: hidden; - text-overflow: ellipsis; -} - .repository .select-label .desc { padding-left: 23px; } @@ -672,6 +667,7 @@ td .commit-summary { font-size: 14px !important; padding: 7px 10px !important; border-radius: var(--border-radius-medium) !important; + flex-shrink: 0; } .issue-state-label .svg { @@ -1170,10 +1166,6 @@ td .commit-summary { font-size: 14px; } -.repository .ui.dropdown.filter > .menu { - margin-top: 1px; -} - .repository.branches .commit-divergence .bar-group { position: relative; float: left; diff --git a/web_src/css/repo/issue-list.css b/web_src/css/repo/issue-list.css index 77905956f0..1e0f82ce27 100644 --- a/web_src/css/repo/issue-list.css +++ b/web_src/css/repo/issue-list.css @@ -39,7 +39,7 @@ } #issue-list .flex-item-body .branches .branch { - background-color: var(--color-secondary-alpha-40); + background-color: var(--color-secondary-alpha-50); border-radius: var(--border-radius); padding: 0 4px; } @@ -48,7 +48,9 @@ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - max-width: 10em; + max-width: 200px; + display: inline-block; + vertical-align: top; } #issue-list .flex-item-body .checklist progress { diff --git a/web_src/js/components/RepoBranchTagSelector.vue b/web_src/js/components/RepoBranchTagSelector.vue index 4e977ab185..c13af14dea 100644 --- a/web_src/js/components/RepoBranchTagSelector.vue +++ b/web_src/js/components/RepoBranchTagSelector.vue @@ -248,12 +248,12 @@ export default sfc; // activate IDE's Vue plugin <template> <div class="ui dropdown custom"> <button class="branch-dropdown-button gt-ellipsis ui basic small compact button tw-flex tw-m-0" @click="menuVisible = !menuVisible" @keyup.enter="menuVisible = !menuVisible"> - <span class="text tw-flex tw-items-center tw-mr-1"> + <span class="text tw-flex tw-items-center tw-mr-1 gt-ellipsis"> <template v-if="release">{{ textReleaseCompare }}</template> <template v-else> <svg-icon v-if="isViewTag" name="octicon-tag"/> <svg-icon v-else name="octicon-git-branch"/> - <strong ref="dropdownRefName" class="tw-ml-2">{{ refNameText }}</strong> + <strong ref="dropdownRefName" class="tw-ml-2 tw-inline-block gt-ellipsis">{{ refNameText }}</strong> </template> </span> <svg-icon name="octicon-triangle-down" :size="14" class-name="dropdown icon"/> From 3746a625f55d24fc48a0198c8108bdebfd4edeb3 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Tue, 16 Apr 2024 17:46:12 +0200 Subject: [PATCH 130/370] Tweak repo buttons on mobile and labeled button border-radius (#30503) Fixes: https://github.com/go-gitea/gitea/issues/30514 Fixes: https://github.com/go-gitea/gitea/pull/30288#issuecomment-2057466623 - Fix border-radius regression from https://github.com/go-gitea/gitea/pull/30475 - Fix and simplify hover state - Move the modal HTML so it does not interfere with the CSS - Make the star and unwatch text show on mobile. There is still plenty of space, below is iPhone 12 viewport size <img width="696" alt="Screenshot 2024-04-15 at 20 34 03" src="https://github.com/go-gitea/gitea/assets/115237/af90bb00-4671-4973-a255-8eb44ee6ba8d"> <img width="230" alt="Screenshot 2024-04-15 at 20 31 42" src="https://github.com/go-gitea/gitea/assets/115237/986ef533-7a01-4bb0-8dcd-fd19e4259e84"> <img width="233" alt="Screenshot 2024-04-15 at 20 31 47" src="https://github.com/go-gitea/gitea/assets/115237/5b825dd8-0ccc-4d56-9d8f-774abb935b68"> --------- Co-authored-by: Giteabot <teabot@gitea.io> --- templates/repo/header.tmpl | 36 +++++++++++++++---------------- templates/repo/star_unstar.tmpl | 2 +- templates/repo/watch_unwatch.tmpl | 2 +- web_src/css/modules/button.css | 10 +++++++++ web_src/css/modules/label.css | 2 +- web_src/css/repo/header.css | 14 +++++++----- 6 files changed, 40 insertions(+), 26 deletions(-) diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index 5e2774dfa1..bb344bf3d4 100644 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -91,28 +91,28 @@ > {{svg "octicon-repo-forked"}}<span class="text not-mobile">{{ctx.Locale.Tr "repo.fork"}}</span> </a> - <div class="ui small modal" id="fork-repo-modal"> - <div class="header"> - {{ctx.Locale.Tr "repo.already_forked" .Name}} - </div> - <div class="content tw-text-left"> - <div class="ui list"> - {{range $.UserAndOrgForks}} - <div class="ui item tw-py-2"> - <a href="{{.Link}}">{{svg "octicon-repo-forked" 16 "tw-mr-2"}}{{.FullName}}</a> - </div> - {{end}} - </div> - {{if $.CanSignedUserFork}} - <div class="divider"></div> - <a href="{{$.RepoLink}}/fork">{{ctx.Locale.Tr "repo.fork_to_different_account"}}</a> - {{end}} - </div> - </div> <a class="ui basic label" href="{{.Link}}/forks"> {{CountFmt .NumForks}} </a> </div> + <div class="ui small modal" id="fork-repo-modal"> + <div class="header"> + {{ctx.Locale.Tr "repo.already_forked" .Name}} + </div> + <div class="content tw-text-left"> + <div class="ui list"> + {{range $.UserAndOrgForks}} + <div class="ui item tw-py-2"> + <a href="{{.Link}}">{{svg "octicon-repo-forked" 16 "tw-mr-2"}}{{.FullName}}</a> + </div> + {{end}} + </div> + {{if $.CanSignedUserFork}} + <div class="divider"></div> + <a href="{{$.RepoLink}}/fork">{{ctx.Locale.Tr "repo.fork_to_different_account"}}</a> + {{end}} + </div> + </div> {{end}} </div> {{end}} diff --git a/templates/repo/star_unstar.tmpl b/templates/repo/star_unstar.tmpl index 1cdb98bf27..0f09d8b492 100644 --- a/templates/repo/star_unstar.tmpl +++ b/templates/repo/star_unstar.tmpl @@ -4,7 +4,7 @@ {{if $.IsStaringRepo}}{{$buttonText = ctx.Locale.Tr "repo.unstar"}}{{end}} <button type="submit" class="ui compact small basic button"{{if not $.IsSigned}} disabled{{end}} aria-label="{{$buttonText}}"> {{if $.IsStaringRepo}}{{svg "octicon-star-fill"}}{{else}}{{svg "octicon-star"}}{{end}} - <span class="not-mobile" aria-hidden="true">{{$buttonText}}</span> + <span aria-hidden="true">{{$buttonText}}</span> </button> <a hx-boost="false" class="ui basic label" href="{{$.RepoLink}}/stars"> {{CountFmt .Repository.NumStars}} diff --git a/templates/repo/watch_unwatch.tmpl b/templates/repo/watch_unwatch.tmpl index 64be971416..465cd91c2b 100644 --- a/templates/repo/watch_unwatch.tmpl +++ b/templates/repo/watch_unwatch.tmpl @@ -4,7 +4,7 @@ {{if $.IsWatchingRepo}}{{$buttonText = ctx.Locale.Tr "repo.unwatch"}}{{end}} <button type="submit" class="ui compact small basic button"{{if not $.IsSigned}} disabled{{end}} aria-label="{{$buttonText}}"> {{svg "octicon-eye"}} - <span class="not-mobile" aria-hidden="true">{{$buttonText}}</span> + <span aria-hidden="true">{{$buttonText}}</span> </button> <a hx-boost="false" class="ui basic label" href="{{.RepoLink}}/watchers"> {{CountFmt .Repository.NumWatches}} diff --git a/web_src/css/modules/button.css b/web_src/css/modules/button.css index 87b9ddf292..4e133852f1 100644 --- a/web_src/css/modules/button.css +++ b/web_src/css/modules/button.css @@ -63,6 +63,8 @@ } .ui.labeled.button > .button { margin: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 0; } .ui.labeled.button > .label { display: flex; @@ -70,6 +72,14 @@ margin: 0 0 0 -1px !important; font-size: 1em; border-color: var(--color-light-border); + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.ui.labeled.button > .label:hover { + background: var(--color-hover); +} +.ui.labeled.button > .button:hover + .label { + border-left-color: var(--color-secondary-dark-2); } .ui.button > .icon:not(.button) { diff --git a/web_src/css/modules/label.css b/web_src/css/modules/label.css index 2032b2c84b..1e42668aa1 100644 --- a/web_src/css/modules/label.css +++ b/web_src/css/modules/label.css @@ -107,7 +107,7 @@ a.ui.label:hover { a.ui.basic.label:hover { text-decoration: none; color: var(--color-text); - border-color: var(--color-light-border); + border-color: var(--color-secondary-dark-2); background: var(--color-hover); } diff --git a/web_src/css/repo/header.css b/web_src/css/repo/header.css index 55e704ed10..b70691435f 100644 --- a/web_src/css/repo/header.css +++ b/web_src/css/repo/header.css @@ -36,11 +36,6 @@ gap: 0.25em; } -.repo-buttons .ui.labeled.button > .label:hover { - color: var(--color-primary-light-2); - background: var(--color-light); -} - .repo-buttons button[disabled] ~ .label { opacity: var(--opacity-disabled); color: var(--color-text-dark); @@ -67,3 +62,12 @@ .repo-buttons .ui.labeled.button.disabled > .button { pointer-events: none !important; } + +@media (max-width: 767.98px) { + .repo-buttons .ui.button, + .repo-buttons .ui.label { + padding-left: 8px; + padding-right: 8px; + margin: 0; + } +} From 5ccd042f7080e1f4ef4b96591e1b1002a4826115 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Wed, 17 Apr 2024 00:39:19 +0200 Subject: [PATCH 131/370] Tweak and fix toggle checkboxes (#30527) Fixes: https://github.com/go-gitea/gitea/issues/30524. Slightly restyled them so that the "knob" is contained inside the background. <img width="179" alt="Screenshot 2024-04-16 at 21 58 09" src="https://github.com/go-gitea/gitea/assets/115237/be94517b-9cb7-46e2-ae96-fcf6767ce4ba"> <img width="187" alt="Screenshot 2024-04-16 at 21 58 50" src="https://github.com/go-gitea/gitea/assets/115237/c13a1959-5c5a-4e88-9225-e5f6fb72e3e0"> --- web_src/css/modules/checkbox.css | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/web_src/css/modules/checkbox.css b/web_src/css/modules/checkbox.css index d3e45714a4..8d73573bfa 100644 --- a/web_src/css/modules/checkbox.css +++ b/web_src/css/modules/checkbox.css @@ -66,7 +66,7 @@ input[type="radio"] { } .ui.toggle.checkbox input { width: 3.5rem; - height: 1.5rem; + height: 21px; opacity: 0; z-index: 3; } @@ -81,29 +81,30 @@ input[type="radio"] { content: ""; z-index: 1; top: 0; - width: 3.5rem; - height: 1.5rem; + width: 49px; + height: 21px; border-radius: 500rem; left: 0; } .ui.toggle.checkbox label::after { background: var(--color-white); + box-shadow: 1px 1px 4px 1px var(--color-shadow); position: absolute; content: ""; opacity: 1; z-index: 2; - width: 1.5rem; - height: 1.5rem; - top: 0; - left: 0; + width: 18px; + height: 18px; + top: 1.5px; + left: 1.5px; border-radius: 500rem; transition: background 0.3s ease, left 0.3s ease; } .ui.toggle.checkbox input ~ label::after { - left: -0.05rem; + left: 1.5px; } .ui.toggle.checkbox input:checked ~ label::after { - left: 2.15rem; + left: 29px; } .ui.toggle.checkbox input:focus ~ label::before, .ui.toggle.checkbox label::before { From 38147d020de1bc8909e61d65a39ebd184bd296d7 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Wed, 17 Apr 2024 00:24:47 +0000 Subject: [PATCH 132/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_zh-CN.ini | 41 +++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 3e907eabfd..78460ad2f8 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -163,18 +163,23 @@ no_results_found=未找到结果 search=搜索... type_tooltip=搜索类型 fuzzy=模糊 +fuzzy_tooltip=包含近似匹配搜索词的结果 match=匹配 +match_tooltip=仅包含精确匹配搜索词的结果 repo_kind=搜索仓库... user_kind=搜索用户... org_kind=搜索组织... team_kind=搜索团队... code_kind=搜索代码... +code_search_unavailable=代码搜索当前不可用。请与网站管理员联系。 +code_search_by_git_grep=当前代码搜索结果由“git grep”提供。如果站点管理员启用仓库索引器,可能会有更好的结果。 package_kind=搜索软件包... project_kind=搜索项目... branch_kind=搜索分支... commit_kind=搜索提交记录... runner_kind=搜索runners... no_results=未找到匹配结果 +keyword_search_unavailable=按关键字搜索当前不可用。请联系站点管理员。 [aria] navbar=导航栏 @@ -281,6 +286,7 @@ email_title=电子邮箱设置 smtp_addr=SMTP 主机地址 smtp_port=SMTP 端口 smtp_from=电子邮件发件人 +smtp_from_invalid=`"发送电子邮件为"地址无效` smtp_from_helper=请输入一个用于 Gitea 的电子邮件地址,或者使用完整格式:"名称" <email@example.com> mailer_user=SMTP 用户名 mailer_password=SMTP 密码 @@ -389,6 +395,7 @@ forgot_password_title=忘记密码 forgot_password=忘记密码? sign_up_now=还没帐户?马上注册。 sign_up_successful=帐户创建成功。欢迎! +confirmation_mail_sent_prompt_ex=一封新的确认邮件已经发送到 <b>%s</b>请在下一个 %s 中检查您的收件箱以完成注册过程。 如果您的注册电子邮件地址不正确,您可以重新登录并更改它。 must_change_password=更新您的密码 allow_password_change=要求用户更改密码(推荐) reset_password_mail_sent_prompt=确认电子邮件已被发送到 <b>%s</b>。请您在 %s 内检查您的收件箱 ,完成密码重置过程。 @@ -398,6 +405,7 @@ prohibit_login=禁止登录 prohibit_login_desc=您的帐户被禁止登录,请与网站管理员联系。 resent_limit_prompt=您请求发送激活邮件过于频繁,请等待 3 分钟后再试! has_unconfirmed_mail=%s 您好,系统检测到您有一封发送至 <b>%s</b> 但未被确认的邮件。如果您未收到激活邮件,或需要重新发送,请单击下方的按钮。 +change_unconfirmed_mail_address=如果您的注册电子邮件地址不正确,您可以在此更改并重新发送新的确认电子邮件。 resend_mail=单击此处重新发送确认邮件 email_not_associate=您输入的邮箱地址未被关联到任何帐号! send_reset_mail=发送账户恢复邮件 @@ -578,6 +586,7 @@ team_name_been_taken=团队名称已被使用。 team_no_units_error=至少选择一项仓库单元。 email_been_used=该电子邮件地址已在使用中。 email_invalid=此邮箱地址无效。 +email_domain_is_not_allowed=用户 <b>%s</b> 与EMAIL_DOMAIN_ALLOWLIT 或 EMAIL_DOMAIN_BLOCKLIT 冲突。请确保您的操作是预期的。 openid_been_used=OpenID 地址 "%s" 已被使用。 username_password_incorrect=用户名或密码不正确。 password_complexity=密码未达到复杂程度要求: @@ -589,6 +598,8 @@ enterred_invalid_repo_name=输入的仓库名称不正确 enterred_invalid_org_name=您输入的组织名称不正确。 enterred_invalid_owner_name=新的所有者名称无效。 enterred_invalid_password=输入的密码不正确 +unset_password=登录用户没有设置密码。 +unsupported_login_type=此登录类型不支持手动删除帐户。 user_not_exist=该用户不存在 team_not_exist=团队不存在 last_org_owner=您不能从 "所有者" 团队中删除最后一个用户。组织中必须至少有一个所有者。 @@ -643,8 +654,24 @@ block.block.user=屏蔽用户 block.block.org=屏蔽用户访问组织 block.block.failure=屏蔽用户失败: %s block.unblock=取消屏蔽 +block.unblock.failure=屏蔽用户失败: %s +block.blocked=您已屏蔽此用户。 block.title=屏蔽一个用户 +block.info=屏蔽用户会阻止他们与仓库进行交互,例如打开或评论合并请求或出现问题。了解更多关于屏蔽用户的信息。 +block.info_1=阻止用户在您的帐户和仓库中进行以下操作: block.info_2=关注你的账号 +block.info_3=通过@提及您的用户名向您发送通知 +block.info_4=邀请您作为协作者到他们的仓库中 +block.info_5=在仓库中点赞、派生或关注 +block.info_6=打开和评论工单或合并请求 +block.info_7=在问题或合并请求中对您的评论做出反应 +block.user_to_block=要屏蔽的用户 +block.note=备注 +block.note.title=可选备注: +block.note.info=该备注对被屏蔽的用户不可见。 +block.note.edit=编辑备注 +block.list=已屏蔽用户 +block.list.none=您没有已屏蔽的用户。 [settings] profile=个人信息 @@ -982,7 +1009,9 @@ fork_visibility_helper=无法更改派生仓库的可见性。 fork_branch=要克隆到 Fork 的分支 all_branches=所有分支 fork_no_valid_owners=这个代码仓库无法被派生,因为没有有效的所有者。 +fork.blocked_user=无法克隆仓库,因为您被仓库所有者屏蔽。 use_template=使用此模板 +open_with_editor=用 %s 打开 download_zip=下载 ZIP download_tar=下载 TAR.GZ download_bundle=下载 BUNDLE @@ -1035,6 +1064,7 @@ watchers=关注者 stargazers=称赞者 stars_remove_warning=这将清除此仓库的所有点赞数。 forks=派生仓库 +stars=点赞数 reactions_more=再加载 %d unit_disabled=站点管理员已禁用此仓库单元。 language_other=其它 @@ -1156,6 +1186,7 @@ watch=关注 unstar=取消点赞 star=点赞 fork=派生 +action.blocked_user=无法执行操作,因为您已被仓库所有者屏蔽。 download_archive=下载此仓库 more_operations=更多操作 @@ -1202,6 +1233,8 @@ file_view_rendered=渲染模式 file_view_raw=查看原始文件 file_permalink=永久链接 file_too_large=文件过大,无法显示。 +code_preview_line_from_to=在 %[3]s 的第 %[1]d 行到 %[2]d 行 +code_preview_line_in=在 %[2]s 的第 %[1]d 行 invisible_runes_header=`此文件含有不可见的 Unicode 字符` invisible_runes_description=`此文件含有人类无法区分的不可见的 Unicode 字符,但可以由计算机进行不同的处理。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。` ambiguous_runes_header=`此文件含有模棱两可的 Unicode 字符` @@ -1284,6 +1317,8 @@ editor.file_editing_no_longer_exists=正在编辑的文件 %s 已不存在。 editor.file_deleting_no_longer_exists=正在删除的文件 %s 已不存在。 editor.file_changed_while_editing=文件内容在您进行编辑时已经发生变动。<a target="_blank" rel="noopener noreferrer" href="%s">单击此处</a> 查看变动的具体内容,或者 <strong>再次提交</strong> 覆盖已发生的变动。 editor.file_already_exists=此仓库已经存在名为 %s 的文件。 +editor.commit_id_not_matching=提交ID与您开始编辑时的ID不匹配。请提交到补丁分支然后合并。 +editor.push_out_of_date=推送似乎已经过时。 editor.commit_empty_file_header=提交一个空文件 editor.commit_empty_file_text=您要提交的文件是空的,继续吗? editor.no_changes_to_show=没有可以显示的变更。 @@ -1402,6 +1437,8 @@ issues.new.assignees=指派成员 issues.new.clear_assignees=取消指派成员 issues.new.no_assignees=未指派成员 issues.new.no_reviewers=无审核者 +issues.new.blocked_user=无法创建工单,因为您已被仓库所有者屏蔽。 +issues.edit.blocked_user=无法编辑内容,因为您已被仓库所有者或工单创建者屏蔽。 issues.choose.get_started=开始 issues.choose.open_external_link=开启 issues.choose.blank=默认模板 @@ -1516,6 +1553,7 @@ issues.close_comment_issue=评论并关闭 issues.reopen_issue=重新开启 issues.reopen_comment_issue=评论并重新开启 issues.create_comment=评论 +issues.comment.blocked_user=无法创建或编辑评论,因为您已被仓库所有者或工单创建者屏蔽。 issues.closed_at=`于 <a id="%[1]s" href="#%[1]s">%[2]s</a> 关闭此工单` issues.reopened_at=`重新打开此问题 <a id="%[1]s" href="#%[1]s">%[2]s</a>` issues.commit_ref_at=`于 <a id="%[1]s" href="#%[1]s">%[2]s</a> 在代码提交中引用了该工单` @@ -1714,6 +1752,7 @@ compare.compare_head=比较 pulls.desc=启用合并请求和代码评审。 pulls.new=创建合并请求 +pulls.new.blocked_user=无法创建合并请求,因为您已被仓库所有者屏蔽。 pulls.view=查看拉取请求 pulls.compare_changes=创建合并请求 pulls.allow_edits_from_maintainers=允许维护者编辑 @@ -1797,6 +1836,7 @@ pulls.merge_pull_request=创建合并提交 pulls.rebase_merge_pull_request=变基后快进 pulls.rebase_merge_commit_pull_request=变基后创建合并提交 pulls.squash_merge_pull_request=创建压缩提交 +pulls.fast_forward_only_merge_pull_request=仅快进 pulls.merge_manually=手动合并 pulls.merge_commit_id=合并提交 ID pulls.require_signed_wont_sign=分支需要签名的提交,但这个合并将不会被签名 @@ -1933,6 +1973,7 @@ wiki.page_name_desc=输入此 Wiki 页面的名称。特殊名称有:'Home', ' wiki.original_git_entry_tooltip=查看原始的 Git 文件而不是使用友好链接。 activity=动态 +activity.navbar.pulse=活动 activity.navbar.code_frequency=代码频率 activity.navbar.contributors=贡献者 activity.navbar.recent_commits=最近的提交 From 6f7d70fb3d2624507c3ccd5640f6d1837259c27d Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Wed, 17 Apr 2024 09:25:03 +0800 Subject: [PATCH 133/370] Reduce unnecessary database queries on actions table (#30509) --- models/activities/action_list.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/models/activities/action_list.go b/models/activities/action_list.go index 6e23b173b5..aafb7f8a26 100644 --- a/models/activities/action_list.go +++ b/models/activities/action_list.go @@ -83,6 +83,9 @@ func (actions ActionList) loadRepoOwner(ctx context.Context, userMap map[int64]* _, alreadyLoaded := userMap[action.Repo.OwnerID] return action.Repo.OwnerID, !alreadyLoaded }) + if len(missingUserIDs) == 0 { + return nil + } if err := db.GetEngine(ctx). In("id", missingUserIDs). @@ -129,6 +132,9 @@ func (actions ActionList) LoadComments(ctx context.Context) error { commentIDs = append(commentIDs, action.CommentID) } } + if len(commentIDs) == 0 { + return nil + } commentsMap := make(map[int64]*issues_model.Comment, len(commentIDs)) if err := db.GetEngine(ctx).In("id", commentIDs).Find(&commentsMap); err != nil { From 4f276a336355c4bf999034fb79f0fe5c967ceb50 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Wed, 17 Apr 2024 09:30:46 +0200 Subject: [PATCH 134/370] Fix install page checkboxes and dropdown width (#30526) Fixes: https://github.com/go-gitea/gitea/issues/30523 1. Fix checkbox rendering 2. Fix width of selection dropdowns (was too small) --------- Co-authored-by: delvh <dev.lh@web.de> Co-authored-by: Giteabot <teabot@gitea.io> --- web_src/css/install.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web_src/css/install.css b/web_src/css/install.css index 4ac294e902..ee2395e6c5 100644 --- a/web_src/css/install.css +++ b/web_src/css/install.css @@ -18,7 +18,8 @@ width: auto; } -.page-content.install form.ui.form input { +.page-content.install form.ui.form input:not([type="checkbox"],[type="radio"]), +.page-content.install form.ui.form .ui.selection.dropdown { width: 60%; } From 3e2e76e2484c79715ab5d56f268ea3ad8e1c259b Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Wed, 17 Apr 2024 16:31:37 +0800 Subject: [PATCH 135/370] Refactor web routes (#30519) Re-organize the routes in web.go and use ctx constants instead of `context.UnitTypes()` --------- Co-authored-by: Giteabot <teabot@gitea.io> --- models/organization/team.go | 18 +- models/perm/access/repo_permission.go | 18 +- routers/web/repo/view.go | 6 +- routers/web/web.go | 540 ++++++++++---------- services/context/context.go | 12 + services/context/repo.go | 17 - templates/explore/navbar.tmpl | 2 +- templates/repo/blame.tmpl | 2 +- templates/repo/code_frequency.tmpl | 2 +- templates/repo/commit_page.tmpl | 2 +- templates/repo/contributors.tmpl | 2 +- templates/repo/graph/commits.tmpl | 2 +- templates/repo/header.tmpl | 28 +- templates/repo/issue/view_content/pull.tmpl | 2 +- templates/repo/pulse.tmpl | 12 +- templates/repo/recent_commits.tmpl | 2 +- templates/repo/release/list.tmpl | 10 +- templates/repo/release_tag_header.tmpl | 4 +- templates/repo/settings/navbar.tmpl | 4 +- templates/repo/settings/options.tmpl | 70 +-- templates/repo/sub_menu.tmpl | 6 +- templates/repo/tag/list.tmpl | 8 +- templates/repo/view_file.tmpl | 2 +- 23 files changed, 394 insertions(+), 377 deletions(-) diff --git a/models/organization/team.go b/models/organization/team.go index 17db11c42d..501a43d3a1 100644 --- a/models/organization/team.go +++ b/models/organization/team.go @@ -174,23 +174,27 @@ func (t *Team) LoadMembers(ctx context.Context) (err error) { return err } -// UnitEnabled returns if the team has the given unit type enabled +// UnitEnabled returns true if the team has the given unit type enabled func (t *Team) UnitEnabled(ctx context.Context, tp unit.Type) bool { return t.UnitAccessMode(ctx, tp) > perm.AccessModeNone } -// UnitAccessMode returns if the team has the given unit type enabled +// UnitAccessMode returns the access mode for the given unit type, "none" for non-existent units func (t *Team) UnitAccessMode(ctx context.Context, tp unit.Type) perm.AccessMode { + accessMode, _ := t.UnitAccessModeEx(ctx, tp) + return accessMode +} + +func (t *Team) UnitAccessModeEx(ctx context.Context, tp unit.Type) (accessMode perm.AccessMode, exist bool) { if err := t.LoadUnits(ctx); err != nil { log.Warn("Error loading team (ID: %d) units: %s", t.ID, err.Error()) } - - for _, unit := range t.Units { - if unit.Type == tp { - return unit.AccessMode + for _, u := range t.Units { + if u.Type == tp { + return u.AccessMode, true } } - return perm.AccessModeNone + return perm.AccessModeNone, false } // IsUsableTeamName tests if a name could be as team name diff --git a/models/perm/access/repo_permission.go b/models/perm/access/repo_permission.go index 4175cb9b92..e4e7579e62 100644 --- a/models/perm/access/repo_permission.go +++ b/models/perm/access/repo_permission.go @@ -102,6 +102,16 @@ func (p *Permission) CanWriteIssuesOrPulls(isPull bool) bool { return p.CanWrite(unit.TypeIssues) } +func (p *Permission) ReadableUnitTypes() []unit.Type { + types := make([]unit.Type, 0, len(p.Units)) + for _, u := range p.Units { + if p.CanRead(u.Type) { + types = append(types, u.Type) + } + } + return types +} + func (p *Permission) LogString() string { format := "<Permission AccessMode=%s, %d Units, %d UnitsMode(s): [ " args := []any{p.AccessMode.String(), len(p.Units), len(p.UnitsMode)} @@ -229,12 +239,8 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use for _, u := range repo.Units { var found bool for _, team := range teams { - teamMode := team.UnitAccessMode(ctx, u.Type) - if teamMode > perm_model.AccessModeNone { - m := perm.UnitsMode[u.Type] - if m < teamMode { - perm.UnitsMode[u.Type] = teamMode - } + if teamMode, exist := team.UnitAccessModeEx(ctx, u.Type); exist { + perm.UnitsMode[u.Type] = max(perm.UnitsMode[u.Type], teamMode) found = true } } diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 8aa9dbb1be..de35c6b3a2 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -721,12 +721,12 @@ func checkHomeCodeViewable(ctx *context.Context) { } var firstUnit *unit_model.Unit - for _, repoUnit := range ctx.Repo.Units { - if repoUnit.Type == unit_model.TypeCode { + for _, repoUnitType := range ctx.Repo.Permission.ReadableUnitTypes() { + if repoUnitType == unit_model.TypeCode { return } - unit, ok := unit_model.Units[repoUnit.Type] + unit, ok := unit_model.Units[repoUnitType] if ok && (firstUnit == nil || !firstUnit.IsLessThan(unit)) { firstUnit = &unit } diff --git a/routers/web/web.go b/routers/web/web.go index 4fff994e42..f9164568ed 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -493,6 +493,7 @@ func registerRoutes(m *web.Route) { }, explore.Code) m.Get("/topics/search", explore.TopicSearch) }, ignExploreSignIn) + m.Group("/issues", func() { m.Get("", user.Issues) m.Get("/search", repo.SearchIssues) @@ -802,6 +803,7 @@ func registerRoutes(m *web.Route) { reqRepoCodeReader := context.RequireRepoReader(unit.TypeCode) reqRepoReleaseWriter := context.RequireRepoWriter(unit.TypeReleases) reqRepoReleaseReader := context.RequireRepoReader(unit.TypeReleases) + reqRepoWikiReader := context.RequireRepoReader(unit.TypeWiki) reqRepoWikiWriter := context.RequireRepoWriter(unit.TypeWiki) reqRepoIssueReader := context.RequireRepoReader(unit.TypeIssues) reqRepoPullsReader := context.RequireRepoReader(unit.TypePullRequests) @@ -838,12 +840,12 @@ func registerRoutes(m *web.Route) { } } - // ***** START: Organization ***** m.Group("/org", func() { m.Group("/{org}", func() { m.Get("/members", org.Members) }, context.OrgAssignment()) }, ignSignIn) + // end "/org": members m.Group("/org", func() { m.Group("", func() { @@ -958,9 +960,8 @@ func registerRoutes(m *web.Route) { }, ctxDataSet("EnableOAuth2", setting.OAuth2.Enabled, "EnablePackages", setting.Packages.Enabled, "PageIsOrgSettings", true)) }, context.OrgAssignment(true, true)) }, reqSignIn) - // ***** END: Organization ***** + // end "/org": most org routes - // ***** START: Repository ***** m.Group("/repo", func() { m.Get("/create", repo.Create) m.Post("/create", web.Bind(forms.CreateRepoForm{}), repo.CreatePost) @@ -968,6 +969,7 @@ func registerRoutes(m *web.Route) { m.Post("/migrate", web.Bind(forms.MigrateRepoForm{}), repo.MigratePost) m.Get("/search", repo.SearchRepo) }, reqSignIn) + // end "/repo": create, migrate, search m.Group("/{username}/-", func() { if setting.Packages.Enabled { @@ -1008,7 +1010,6 @@ func registerRoutes(m *web.Route) { m.Put("", web.Bind(forms.EditProjectBoardForm{}), org.EditProjectBoard) m.Delete("", org.DeleteProjectBoard) m.Post("/default", org.SetDefaultProjectBoard) - m.Post("/move", org.MoveIssues) }) }) @@ -1023,125 +1024,152 @@ func registerRoutes(m *web.Route) { m.Group("", func() { m.Get("/code", user.CodeSearch) }, reqUnitAccess(unit.TypeCode, perm.AccessModeRead, false), individualPermsChecker) - }, ignSignIn, context.UserAssignmentWeb(), context.OrgAssignment()) // for "/{username}/-" (packages, projects, code) + }, ignSignIn, context.UserAssignmentWeb(), context.OrgAssignment()) + // end "/{username}/-": packages, projects, code + + m.Group("/{username}/{reponame}/settings", func() { + m.Group("", func() { + m.Combo("").Get(repo_setting.Settings). + Post(web.Bind(forms.RepoSettingForm{}), repo_setting.SettingsPost) + }, repo_setting.SettingsCtxData) + m.Post("/avatar", web.Bind(forms.AvatarForm{}), repo_setting.SettingsAvatar) + m.Post("/avatar/delete", repo_setting.SettingsDeleteAvatar) + + m.Group("/collaboration", func() { + m.Combo("").Get(repo_setting.Collaboration).Post(repo_setting.CollaborationPost) + m.Post("/access_mode", repo_setting.ChangeCollaborationAccessMode) + m.Post("/delete", repo_setting.DeleteCollaboration) + m.Group("/team", func() { + m.Post("", repo_setting.AddTeamPost) + m.Post("/delete", repo_setting.DeleteTeam) + }) + }) + + m.Group("/branches", func() { + m.Post("/", repo_setting.SetDefaultBranchPost) + }, repo.MustBeNotEmpty) + + m.Group("/branches", func() { + m.Get("/", repo_setting.ProtectedBranchRules) + m.Combo("/edit").Get(repo_setting.SettingsProtectedBranch). + Post(web.Bind(forms.ProtectBranchForm{}), context.RepoMustNotBeArchived(), repo_setting.SettingsProtectedBranchPost) + m.Post("/{id}/delete", repo_setting.DeleteProtectedBranchRulePost) + }, repo.MustBeNotEmpty) + + m.Post("/rename_branch", web.Bind(forms.RenameBranchForm{}), context.RepoMustNotBeArchived(), repo_setting.RenameBranchPost) + + m.Group("/tags", func() { + m.Get("", repo_setting.ProtectedTags) + m.Post("", web.Bind(forms.ProtectTagForm{}), context.RepoMustNotBeArchived(), repo_setting.NewProtectedTagPost) + m.Post("/delete", context.RepoMustNotBeArchived(), repo_setting.DeleteProtectedTagPost) + m.Get("/{id}", repo_setting.EditProtectedTag) + m.Post("/{id}", web.Bind(forms.ProtectTagForm{}), context.RepoMustNotBeArchived(), repo_setting.EditProtectedTagPost) + }) + + m.Group("/hooks/git", func() { + m.Get("", repo_setting.GitHooks) + m.Combo("/{name}").Get(repo_setting.GitHooksEdit). + Post(repo_setting.GitHooksEditPost) + }, context.GitHookService()) + + m.Group("/hooks", func() { + m.Get("", repo_setting.Webhooks) + m.Post("/delete", repo_setting.DeleteWebhook) + addWebhookAddRoutes() + m.Group("/{id}", func() { + m.Get("", repo_setting.WebHooksEdit) + m.Post("/test", repo_setting.TestWebhook) + m.Post("/replay/{uuid}", repo_setting.ReplayWebhook) + }) + addWebhookEditRoutes() + }, webhooksEnabled) + + m.Group("/keys", func() { + m.Combo("").Get(repo_setting.DeployKeys). + Post(web.Bind(forms.AddKeyForm{}), repo_setting.DeployKeysPost) + m.Post("/delete", repo_setting.DeleteDeployKey) + }) + + m.Group("/lfs", func() { + m.Get("/", repo_setting.LFSFiles) + m.Get("/show/{oid}", repo_setting.LFSFileGet) + m.Post("/delete/{oid}", repo_setting.LFSDelete) + m.Get("/pointers", repo_setting.LFSPointerFiles) + m.Post("/pointers/associate", repo_setting.LFSAutoAssociate) + m.Get("/find", repo_setting.LFSFileFind) + m.Group("/locks", func() { + m.Get("/", repo_setting.LFSLocks) + m.Post("/", repo_setting.LFSLockFile) + m.Post("/{lid}/unlock", repo_setting.LFSUnlock) + }) + }) + m.Group("/actions", func() { + m.Get("", repo_setting.RedirectToDefaultSetting) + addSettingsRunnersRoutes() + addSettingsSecretsRoutes() + addSettingsVariablesRoutes() + }, actions.MustEnableActions) + // the follow handler must be under "settings", otherwise this incomplete repo can't be accessed + m.Group("/migrate", func() { + m.Post("/retry", repo.MigrateRetryPost) + m.Post("/cancel", repo.MigrateCancelPost) + }) + }, + reqSignIn, context.RepoAssignment, context.RepoRef(), reqRepoAdmin, + ctxDataSet("PageIsRepoSettings", true, "LFSStartServer", setting.LFS.StartServer), + ) + // end "/{username}/{reponame}/settings" + + // user/org home, including rss feeds + m.Get("/{username}/{reponame}", ignSignIn, context.RepoAssignment, context.RepoRef(), repo.SetEditorconfigIfExists, repo.Home) m.Group("/{username}/{reponame}", func() { - m.Group("/settings", func() { - m.Group("", func() { - m.Combo("").Get(repo_setting.Settings). - Post(web.Bind(forms.RepoSettingForm{}), repo_setting.SettingsPost) - }, repo_setting.SettingsCtxData) - m.Post("/avatar", web.Bind(forms.AvatarForm{}), repo_setting.SettingsAvatar) - m.Post("/avatar/delete", repo_setting.SettingsDeleteAvatar) - - m.Group("/collaboration", func() { - m.Combo("").Get(repo_setting.Collaboration).Post(repo_setting.CollaborationPost) - m.Post("/access_mode", repo_setting.ChangeCollaborationAccessMode) - m.Post("/delete", repo_setting.DeleteCollaboration) - m.Group("/team", func() { - m.Post("", repo_setting.AddTeamPost) - m.Post("/delete", repo_setting.DeleteTeam) - }) - }) - - m.Group("/branches", func() { - m.Post("/", repo_setting.SetDefaultBranchPost) - }, repo.MustBeNotEmpty) - - m.Group("/branches", func() { - m.Get("/", repo_setting.ProtectedBranchRules) - m.Combo("/edit").Get(repo_setting.SettingsProtectedBranch). - Post(web.Bind(forms.ProtectBranchForm{}), context.RepoMustNotBeArchived(), repo_setting.SettingsProtectedBranchPost) - m.Post("/{id}/delete", repo_setting.DeleteProtectedBranchRulePost) - }, repo.MustBeNotEmpty) - - m.Post("/rename_branch", web.Bind(forms.RenameBranchForm{}), context.RepoMustNotBeArchived(), repo_setting.RenameBranchPost) - - m.Group("/tags", func() { - m.Get("", repo_setting.ProtectedTags) - m.Post("", web.Bind(forms.ProtectTagForm{}), context.RepoMustNotBeArchived(), repo_setting.NewProtectedTagPost) - m.Post("/delete", context.RepoMustNotBeArchived(), repo_setting.DeleteProtectedTagPost) - m.Get("/{id}", repo_setting.EditProtectedTag) - m.Post("/{id}", web.Bind(forms.ProtectTagForm{}), context.RepoMustNotBeArchived(), repo_setting.EditProtectedTagPost) - }) - - m.Group("/hooks/git", func() { - m.Get("", repo_setting.GitHooks) - m.Combo("/{name}").Get(repo_setting.GitHooksEdit). - Post(repo_setting.GitHooksEditPost) - }, context.GitHookService()) - - m.Group("/hooks", func() { - m.Get("", repo_setting.Webhooks) - m.Post("/delete", repo_setting.DeleteWebhook) - addWebhookAddRoutes() - m.Group("/{id}", func() { - m.Get("", repo_setting.WebHooksEdit) - m.Post("/test", repo_setting.TestWebhook) - m.Post("/replay/{uuid}", repo_setting.ReplayWebhook) - }) - addWebhookEditRoutes() - }, webhooksEnabled) - - m.Group("/keys", func() { - m.Combo("").Get(repo_setting.DeployKeys). - Post(web.Bind(forms.AddKeyForm{}), repo_setting.DeployKeysPost) - m.Post("/delete", repo_setting.DeleteDeployKey) - }) - - m.Group("/lfs", func() { - m.Get("/", repo_setting.LFSFiles) - m.Get("/show/{oid}", repo_setting.LFSFileGet) - m.Post("/delete/{oid}", repo_setting.LFSDelete) - m.Get("/pointers", repo_setting.LFSPointerFiles) - m.Post("/pointers/associate", repo_setting.LFSAutoAssociate) - m.Get("/find", repo_setting.LFSFileFind) - m.Group("/locks", func() { - m.Get("/", repo_setting.LFSLocks) - m.Post("/", repo_setting.LFSLockFile) - m.Post("/{lid}/unlock", repo_setting.LFSUnlock) - }) - }) - m.Group("/actions", func() { - m.Get("", repo_setting.RedirectToDefaultSetting) - addSettingsRunnersRoutes() - addSettingsSecretsRoutes() - addSettingsVariablesRoutes() - }, actions.MustEnableActions) - // the follow handler must be under "settings", otherwise this incomplete repo can't be accessed - m.Group("/migrate", func() { - m.Post("/retry", repo.MigrateRetryPost) - m.Post("/cancel", repo.MigrateCancelPost) - }) - }, ctxDataSet("PageIsRepoSettings", true, "LFSStartServer", setting.LFS.StartServer)) - }, reqSignIn, context.RepoAssignment, context.UnitTypes(), reqRepoAdmin, context.RepoRef()) - - m.Post("/{username}/{reponame}/action/{action}", reqSignIn, context.RepoAssignment, context.UnitTypes(), repo.Action) - - // Grouping for those endpoints not requiring authentication (but should respect ignSignIn) - m.Group("/{username}/{reponame}", func() { - m.Group("/milestone", func() { - m.Get("/{id}", repo.MilestoneIssuesAndPulls) - }, reqRepoIssuesOrPullsReader, context.RepoRef()) m.Get("/find/*", repo.FindFiles) m.Group("/tree-list", func() { m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.TreeList) m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.TreeList) m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.TreeList) }) - m.Get("/compare", repo.MustBeNotEmpty, reqRepoCodeReader, repo.SetEditorconfigIfExists, ignSignIn, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff) - m.Combo("/compare/*", repo.MustBeNotEmpty, reqRepoCodeReader, repo.SetEditorconfigIfExists). + m.Get("/compare", repo.MustBeNotEmpty, repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff) + m.Combo("/compare/*", repo.MustBeNotEmpty, repo.SetEditorconfigIfExists). Get(repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff). Post(reqSignIn, context.RepoMustNotBeArchived(), reqRepoPullsReader, repo.MustAllowPulls, web.Bind(forms.CreateIssueForm{}), repo.SetWhitespaceBehavior, repo.CompareAndPullRequestPost) + }, ignSignIn, context.RepoAssignment, reqRepoCodeReader) + // end "/{username}/{reponame}": find, compare, list (code related) + + m.Group("/{username}/{reponame}", func() { + m.Get("/issues/posters", repo.IssuePosters) // it can't use {type:issues|pulls} because it would conflict with other routes like "/pulls/{index}" + m.Get("/pulls/posters", repo.PullPosters) + m.Get("/comments/{id}/attachments", repo.GetCommentAttachments) + m.Get("/labels", repo.RetrieveLabels, repo.Labels) + m.Get("/milestones", repo.Milestones) + m.Get("/milestone/{id}", context.RepoRef(), repo.MilestoneIssuesAndPulls) m.Group("/{type:issues|pulls}", func() { m.Group("/{index}", func() { m.Get("/info", repo.GetIssueInfo) + m.Get("/attachments", repo.GetIssueAttachments) + m.Get("/attachments/{uuid}", repo.GetAttachment) + m.Group("/content-history", func() { + m.Get("/overview", repo.GetContentHistoryOverview) + m.Get("/list", repo.GetContentHistoryList) + m.Get("/detail", repo.GetContentHistoryDetail) + }) + }) + }, context.RepoRef()) + }, ignSignIn, context.RepoAssignment, reqRepoIssuesOrPullsReader) + // end "/{username}/{reponame}": view milestone, label, issue, pull, etc + + m.Group("/{username}/{reponame}", func() { + m.Group("/{type:issues|pulls}", func() { + m.Get("", repo.Issues) + m.Group("/{index}", func() { + m.Get("", repo.ViewIssue) }) }) - }, ignSignIn, context.RepoAssignment, context.UnitTypes()) // for "/{username}/{reponame}" which doesn't require authentication + }, ignSignIn, context.RepoAssignment, context.RequireRepoReaderOr(unit.TypeIssues, unit.TypePullRequests, unit.TypeExternalTracker)) + // end "/{username}/{reponame}": issue/pull list, issue/pull view, external tracker - // Grouping for those endpoints that do require authentication - m.Group("/{username}/{reponame}", func() { + m.Group("/{username}/{reponame}", func() { // edit issues, pulls, labels, milestones, etc m.Group("/issues", func() { m.Group("/new", func() { m.Combo("").Get(context.RepoRef(), repo.NewIssue). @@ -1150,6 +1178,7 @@ func registerRoutes(m *web.Route) { }) m.Get("/search", repo.ListIssues) }, context.RepoMustNotBeArchived(), reqRepoIssueReader) + // FIXME: should use different URLs but mostly same logic for comments of issue and pull request. // So they can apply their own enable/disable logic on routers. m.Group("/{type:issues|pulls}", func() { @@ -1179,10 +1208,7 @@ func registerRoutes(m *web.Route) { m.Post("/unlock", reqRepoIssuesOrPullsWriter, repo.UnlockIssue) m.Post("/delete", reqRepoAdmin, repo.DeleteIssue) }, context.RepoMustNotBeArchived()) - m.Group("/{index}", func() { - m.Get("/attachments", repo.GetIssueAttachments) - m.Get("/attachments/{uuid}", repo.GetAttachment) - }) + m.Group("/{index}", func() { m.Post("/content-history/soft-delete", repo.SoftDeleteContentHistory) }) @@ -1191,25 +1217,25 @@ func registerRoutes(m *web.Route) { m.Post("/milestone", reqRepoIssuesOrPullsWriter, repo.UpdateIssueMilestone) m.Post("/projects", reqRepoIssuesOrPullsWriter, reqRepoProjectsReader, repo.UpdateIssueProject) m.Post("/assignee", reqRepoIssuesOrPullsWriter, repo.UpdateIssueAssignee) - m.Post("/request_review", reqRepoIssuesOrPullsReader, repo.UpdatePullReviewRequest) + m.Post("/request_review", repo.UpdatePullReviewRequest) m.Post("/dismiss_review", reqRepoAdmin, web.Bind(forms.DismissReviewForm{}), repo.DismissReview) m.Post("/status", reqRepoIssuesOrPullsWriter, repo.UpdateIssueStatus) m.Post("/delete", reqRepoAdmin, repo.BatchDeleteIssues) - m.Post("/resolve_conversation", reqRepoIssuesOrPullsReader, repo.SetShowOutdatedComments, repo.UpdateResolveConversation) + m.Post("/resolve_conversation", repo.SetShowOutdatedComments, repo.UpdateResolveConversation) m.Post("/attachments", repo.UploadIssueAttachment) m.Post("/attachments/remove", repo.DeleteAttachment) m.Delete("/unpin/{index}", reqRepoAdmin, repo.IssueUnpin) m.Post("/move_pin", reqRepoAdmin, repo.IssuePinMove) }, context.RepoMustNotBeArchived()) + m.Group("/comments/{id}", func() { m.Post("", repo.UpdateCommentContent) m.Post("/delete", repo.DeleteComment) m.Post("/reactions/{action}", web.Bind(forms.ReactionForm{}), repo.ChangeCommentReaction) }, context.RepoMustNotBeArchived()) - m.Group("/comments/{id}", func() { - m.Get("/attachments", repo.GetCommentAttachments) - }) + m.Post("/markup", web.Bind(structs.MarkupOption{}), misc.Markup) + m.Group("/labels", func() { m.Post("/new", web.Bind(forms.CreateLabelForm{}), repo.NewLabel) m.Post("/edit", web.Bind(forms.CreateLabelForm{}), repo.UpdateLabel) @@ -1227,7 +1253,10 @@ func registerRoutes(m *web.Route) { m.Group("/pull", func() { m.Post("/{index}/target_branch", repo.UpdatePullRequestTarget) }, context.RepoMustNotBeArchived()) + }, reqSignIn, context.RepoAssignment, reqRepoIssuesOrPullsReader) + // end "/{username}/{reponame}": create or edit issues, pulls, labels, milestones + m.Group("/{username}/{reponame}", func() { // repo code m.Group("", func() { m.Group("", func() { m.Combo("/_edit/*").Get(repo.EditFile). @@ -1261,26 +1290,26 @@ func registerRoutes(m *web.Route) { m.Post("/restore", repo.RestoreBranchPost) }, context.RepoMustNotBeArchived(), reqRepoCodeWriter, repo.MustBeNotEmpty) - m.Combo("/fork", reqRepoCodeReader).Get(repo.Fork).Post(web.Bind(forms.CreateRepoForm{}), repo.ForkPost) - }, reqSignIn, context.RepoAssignment, context.UnitTypes()) + m.Combo("/fork").Get(repo.Fork).Post(web.Bind(forms.CreateRepoForm{}), repo.ForkPost) + }, reqSignIn, context.RepoAssignment, reqRepoCodeReader) + // end "/{username}/{reponame}": repo code - // Tags - m.Group("/{username}/{reponame}", func() { + m.Group("/{username}/{reponame}", func() { // repo tags m.Group("/tags", func() { m.Get("", repo.TagsList) m.Get("/list", repo.GetTagList) m.Get(".rss", feedEnabled, repo.TagsListFeedRSS) m.Get(".atom", feedEnabled, repo.TagsListFeedAtom) }, ctxDataSet("EnableFeed", setting.Other.EnableFeed), - repo.MustBeNotEmpty, reqRepoCodeReader, context.RepoRefByType(context.RepoRefTag, true)) + repo.MustBeNotEmpty, context.RepoRefByType(context.RepoRefTag, true)) m.Post("/tags/delete", repo.DeleteTag, reqSignIn, repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoCodeWriter, context.RepoRef()) - }, ignSignIn, context.RepoAssignment, context.UnitTypes()) + }, ignSignIn, context.RepoAssignment, reqRepoCodeReader) + // end "/{username}/{reponame}": repo tags - // Releases - m.Group("/{username}/{reponame}", func() { + m.Group("/{username}/{reponame}", func() { // repo releases m.Group("/releases", func() { - m.Get("/", repo.Releases) + m.Get("", repo.Releases) m.Get("/tag/*", repo.SingleRelease) m.Get("/latest", repo.LatestRelease) m.Get(".rss", feedEnabled, repo.ReleasesFeedRSS) @@ -1300,148 +1329,141 @@ func registerRoutes(m *web.Route) { m.Get("/edit/*", repo.EditRelease) m.Post("/edit/*", web.Bind(forms.EditReleaseForm{}), repo.EditReleasePost) }, reqSignIn, repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoReleaseWriter, repo.CommitInfoCache) - }, ignSignIn, context.RepoAssignment, context.UnitTypes(), reqRepoReleaseReader) + }, ignSignIn, context.RepoAssignment, reqRepoReleaseReader) + // end "/{username}/{reponame}": repo releases - // to maintain compatibility with old attachments - m.Group("/{username}/{reponame}", func() { + m.Group("/{username}/{reponame}", func() { // to maintain compatibility with old attachments m.Get("/attachments/{uuid}", repo.GetAttachment) - }, ignSignIn, context.RepoAssignment, context.UnitTypes()) + }, ignSignIn, context.RepoAssignment) + // end "/{username}/{reponame}": compatibility with old attachments m.Group("/{username}/{reponame}", func() { m.Post("/topics", repo.TopicsPost) - }, context.RepoAssignment, context.RepoMustNotBeArchived(), reqRepoAdmin) + }, context.RepoAssignment, reqRepoAdmin, context.RepoMustNotBeArchived()) m.Group("/{username}/{reponame}", func() { - m.Group("", func() { - m.Get("/issues/posters", repo.IssuePosters) // it can't use {type:issues|pulls} because other routes like "/pulls/{index}" has higher priority - m.Get("/{type:issues|pulls}", repo.Issues) - m.Get("/{type:issues|pulls}/{index}", repo.ViewIssue) - m.Group("/{type:issues|pulls}/{index}/content-history", func() { - m.Get("/overview", repo.GetContentHistoryOverview) - m.Get("/list", repo.GetContentHistoryList) - m.Get("/detail", repo.GetContentHistoryDetail) - }) - m.Get("/labels", reqRepoIssuesOrPullsReader, repo.RetrieveLabels, repo.Labels) - m.Get("/milestones", reqRepoIssuesOrPullsReader, repo.Milestones) - }, context.RepoRef()) - if setting.Packages.Enabled { m.Get("/packages", repo.Packages) } + }, ignSignIn, context.RepoAssignment) - m.Group("/projects", func() { - m.Get("", repo.Projects) - m.Get("/{id}", repo.ViewProject) - m.Group("", func() { //nolint:dupl - m.Get("/new", repo.RenderNewProject) - m.Post("/new", web.Bind(forms.CreateProjectForm{}), repo.NewProjectPost) - m.Group("/{id}", func() { - m.Post("", web.Bind(forms.EditProjectBoardForm{}), repo.AddBoardToProjectPost) - m.Post("/delete", repo.DeleteProject) + m.Group("/{username}/{reponame}/projects", func() { + m.Get("", repo.Projects) + m.Get("/{id}", repo.ViewProject) + m.Group("", func() { //nolint:dupl + m.Get("/new", repo.RenderNewProject) + m.Post("/new", web.Bind(forms.CreateProjectForm{}), repo.NewProjectPost) + m.Group("/{id}", func() { + m.Post("", web.Bind(forms.EditProjectBoardForm{}), repo.AddBoardToProjectPost) + m.Post("/delete", repo.DeleteProject) - m.Get("/edit", repo.RenderEditProject) - m.Post("/edit", web.Bind(forms.CreateProjectForm{}), repo.EditProjectPost) - m.Post("/{action:open|close}", repo.ChangeProjectStatus) + m.Get("/edit", repo.RenderEditProject) + m.Post("/edit", web.Bind(forms.CreateProjectForm{}), repo.EditProjectPost) + m.Post("/{action:open|close}", repo.ChangeProjectStatus) - m.Group("/{boardID}", func() { - m.Put("", web.Bind(forms.EditProjectBoardForm{}), repo.EditProjectBoard) - m.Delete("", repo.DeleteProjectBoard) - m.Post("/default", repo.SetDefaultProjectBoard) - - m.Post("/move", repo.MoveIssues) - }) + m.Group("/{boardID}", func() { + m.Put("", web.Bind(forms.EditProjectBoardForm{}), repo.EditProjectBoard) + m.Delete("", repo.DeleteProjectBoard) + m.Post("/default", repo.SetDefaultProjectBoard) + m.Post("/move", repo.MoveIssues) }) - }, reqRepoProjectsWriter, context.RepoMustNotBeArchived()) - }, reqRepoProjectsReader, repo.MustEnableRepoProjects) + }) + }, reqRepoProjectsWriter, context.RepoMustNotBeArchived()) + }, ignSignIn, context.RepoAssignment, reqRepoProjectsReader, repo.MustEnableRepoProjects) + // end "/{username}/{reponame}/projects" - m.Group("/actions", func() { - m.Get("", actions.List) - m.Post("/disable", reqRepoAdmin, actions.DisableWorkflowFile) - m.Post("/enable", reqRepoAdmin, actions.EnableWorkflowFile) + m.Group("/{username}/{reponame}/actions", func() { + m.Get("", actions.List) + m.Post("/disable", reqRepoAdmin, actions.DisableWorkflowFile) + m.Post("/enable", reqRepoAdmin, actions.EnableWorkflowFile) - m.Group("/runs/{run}", func() { + m.Group("/runs/{run}", func() { + m.Combo(""). + Get(actions.View). + Post(web.Bind(actions.ViewRequest{}), actions.ViewPost) + m.Group("/jobs/{job}", func() { m.Combo(""). Get(actions.View). Post(web.Bind(actions.ViewRequest{}), actions.ViewPost) - m.Group("/jobs/{job}", func() { - m.Combo(""). - Get(actions.View). - Post(web.Bind(actions.ViewRequest{}), actions.ViewPost) - m.Post("/rerun", reqRepoActionsWriter, actions.Rerun) - m.Get("/logs", actions.Logs) - }) - m.Post("/cancel", reqRepoActionsWriter, actions.Cancel) - m.Post("/approve", reqRepoActionsWriter, actions.Approve) - m.Get("/artifacts", actions.ArtifactsView) - m.Get("/artifacts/{artifact_name}", actions.ArtifactsDownloadView) - m.Delete("/artifacts/{artifact_name}", actions.ArtifactsDeleteView) m.Post("/rerun", reqRepoActionsWriter, actions.Rerun) + m.Get("/logs", actions.Logs) }) - m.Group("/workflows/{workflow_name}", func() { - m.Get("/badge.svg", actions.GetWorkflowBadge) - }) - }, reqRepoActionsReader, actions.MustEnableActions) - - m.Group("/wiki", func() { - m.Combo("/"). - Get(repo.Wiki). - Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost) - m.Combo("/*"). - Get(repo.Wiki). - Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost) - m.Get("/commit/{sha:[a-f0-9]{7,64}}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff) - m.Get("/commit/{sha:[a-f0-9]{7,64}}.{ext:patch|diff}", repo.RawDiff) - }, repo.MustEnableWiki, func(ctx *context.Context) { - ctx.Data["PageIsWiki"] = true - ctx.Data["CloneButtonOriginLink"] = ctx.Repo.Repository.WikiCloneLink() + m.Post("/cancel", reqRepoActionsWriter, actions.Cancel) + m.Post("/approve", reqRepoActionsWriter, actions.Approve) + m.Get("/artifacts", actions.ArtifactsView) + m.Get("/artifacts/{artifact_name}", actions.ArtifactsDownloadView) + m.Delete("/artifacts/{artifact_name}", actions.ArtifactsDeleteView) + m.Post("/rerun", reqRepoActionsWriter, actions.Rerun) }) + m.Group("/workflows/{workflow_name}", func() { + m.Get("/badge.svg", actions.GetWorkflowBadge) + }) + }, ignSignIn, context.RepoAssignment, reqRepoActionsReader, actions.MustEnableActions) + // end "/{username}/{reponame}/actions" - m.Group("/wiki", func() { - m.Get("/raw/*", repo.WikiRaw) - }, repo.MustEnableWiki) + m.Group("/{username}/{reponame}/wiki", func() { + m.Combo(""). + Get(repo.Wiki). + Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost) + m.Combo("/*"). + Get(repo.Wiki). + Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost) + m.Get("/commit/{sha:[a-f0-9]{7,64}}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff) + m.Get("/commit/{sha:[a-f0-9]{7,64}}.{ext:patch|diff}", repo.RawDiff) + m.Get("/raw/*", repo.WikiRaw) + }, ignSignIn, context.RepoAssignment, repo.MustEnableWiki, reqRepoWikiReader, func(ctx *context.Context) { + ctx.Data["PageIsWiki"] = true + ctx.Data["CloneButtonOriginLink"] = ctx.Repo.Repository.WikiCloneLink() + }) + // end "/{username}/{reponame}/wiki" - m.Group("/activity", func() { - m.Get("", repo.Activity) - m.Get("/{period}", repo.Activity) - m.Group("/contributors", func() { - m.Get("", repo.Contributors) - m.Get("/data", repo.ContributorsData) - }) - m.Group("/code-frequency", func() { - m.Get("", repo.CodeFrequency) - m.Get("/data", repo.CodeFrequencyData) - }) - m.Group("/recent-commits", func() { - m.Get("", repo.RecentCommits) - m.Get("/data", repo.RecentCommitsData) - }) - }, context.RepoRef(), repo.MustBeNotEmpty, context.RequireRepoReaderOr(unit.TypePullRequests, unit.TypeIssues, unit.TypeReleases)) + m.Group("/{username}/{reponame}/activity", func() { + m.Get("", repo.Activity) + m.Get("/{period}", repo.Activity) + m.Group("/contributors", func() { + m.Get("", repo.Contributors) + m.Get("/data", repo.ContributorsData) + }) + m.Group("/code-frequency", func() { + m.Get("", repo.CodeFrequency) + m.Get("/data", repo.CodeFrequencyData) + }) + m.Group("/recent-commits", func() { + m.Get("", repo.RecentCommits) + m.Get("/data", repo.RecentCommitsData) + }) + }, + ignSignIn, context.RepoAssignment, context.RequireRepoReaderOr(unit.TypePullRequests, unit.TypeIssues, unit.TypeReleases), + context.RepoRef(), repo.MustBeNotEmpty, + ) + // end "/{username}/{reponame}/activity" + m.Group("/{username}/{reponame}", func() { m.Group("/activity_author_data", func() { m.Get("", repo.ActivityAuthors) m.Get("/{period}", repo.ActivityAuthors) - }, context.RepoRef(), repo.MustBeNotEmpty, context.RequireRepoReaderOr(unit.TypeCode)) + }, context.RepoRef(), repo.MustBeNotEmpty) m.Group("/archive", func() { m.Get("/*", repo.Download) m.Post("/*", repo.InitiateDownload) - }, repo.MustBeNotEmpty, dlSourceEnabled, reqRepoCodeReader) + }, repo.MustBeNotEmpty, dlSourceEnabled) m.Group("/branches", func() { m.Get("/list", repo.GetBranchesList) m.Get("", repo.Branches) - }, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader) + }, repo.MustBeNotEmpty, context.RepoRef()) m.Group("/blob_excerpt", func() { m.Get("/{sha}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.ExcerptBlob) }, func(ctx *context.Context) gocontext.CancelFunc { + // FIXME: refactor this function, use separate routes for wiki/code if ctx.FormBool("wiki") { ctx.Data["PageIsWiki"] = true repo.MustEnableWiki(ctx) return nil } - reqRepoCodeReader(ctx) if ctx.Written() { return nil } @@ -1454,7 +1476,6 @@ func registerRoutes(m *web.Route) { return cancel }) - m.Get("/pulls/posters", repo.PullPosters) m.Group("/pulls/{index}", func() { m.Get("", repo.SetWhitespaceBehavior, repo.GetPullDiffStats, repo.ViewIssue) m.Get(".diff", repo.DownloadPullDiff) @@ -1488,7 +1509,7 @@ func registerRoutes(m *web.Route) { m.Get("/blob/{sha}", context.RepoRefByType(context.RepoRefBlob), repo.DownloadByIDOrLFS) // "/*" route is deprecated, and kept for backward compatibility m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.SingleDownloadOrLFS) - }, repo.MustBeNotEmpty, reqRepoCodeReader) + }, repo.MustBeNotEmpty) m.Group("/raw", func() { m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.SingleDownload) @@ -1497,14 +1518,14 @@ func registerRoutes(m *web.Route) { m.Get("/blob/{sha}", context.RepoRefByType(context.RepoRefBlob), repo.DownloadByID) // "/*" route is deprecated, and kept for backward compatibility m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.SingleDownload) - }, repo.MustBeNotEmpty, reqRepoCodeReader) + }, repo.MustBeNotEmpty) m.Group("/render", func() { m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.RenderFile) m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.RenderFile) m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.RenderFile) m.Get("/blob/{sha}", context.RepoRefByType(context.RepoRefBlob), repo.RenderFile) - }, repo.MustBeNotEmpty, reqRepoCodeReader) + }, repo.MustBeNotEmpty) m.Group("/commits", func() { m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.RefCommits) @@ -1512,20 +1533,20 @@ func registerRoutes(m *web.Route) { m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.RefCommits) // "/*" route is deprecated, and kept for backward compatibility m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.RefCommits) - }, repo.MustBeNotEmpty, reqRepoCodeReader) + }, repo.MustBeNotEmpty) m.Group("/blame", func() { m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.RefBlame) m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.RefBlame) m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.RefBlame) - }, repo.MustBeNotEmpty, reqRepoCodeReader) + }, repo.MustBeNotEmpty) m.Group("", func() { m.Get("/graph", repo.Graph) m.Get("/commit/{sha:([a-f0-9]{7,64})$}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff) m.Get("/commit/{sha:([a-f0-9]{7,64})$}/load-branches-and-tags", repo.LoadBranchesAndTags) m.Get("/cherry-pick/{sha:([a-f0-9]{7,64})$}", repo.SetEditorconfigIfExists, repo.CherryPick) - }, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader) + }, repo.MustBeNotEmpty, context.RepoRef()) m.Get("/rss/branch/*", context.RepoRefByType(context.RepoRefBranch), feedEnabled, feed.RenderBranchFeed) m.Get("/atom/branch/*", context.RepoRefByType(context.RepoRefBranch), feedEnabled, feed.RenderBranchFeed) @@ -1534,51 +1555,42 @@ func registerRoutes(m *web.Route) { m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.Home) m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.Home) m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.Home) - // "/*" route is deprecated, and kept for backward compatibility - m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.Home) + m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.Home) // "/*" route is deprecated, and kept for backward compatibility }, repo.SetEditorconfigIfExists) - m.Group("", func() { - m.Get("/forks", repo.Forks) - }, context.RepoRef(), reqRepoCodeReader) - m.Get("/commit/{sha:([a-f0-9]{7,64})}.{ext:patch|diff}", repo.MustBeNotEmpty, reqRepoCodeReader, repo.RawDiff) - }, ignSignIn, context.RepoAssignment, context.UnitTypes()) - - m.Post("/{username}/{reponame}/lastcommit/*", ignSignInAndCsrf, context.RepoAssignment, context.UnitTypes(), context.RepoRefByType(context.RepoRefCommit), reqRepoCodeReader, repo.LastCommit) + m.Get("/forks", context.RepoRef(), repo.Forks) + m.Get("/commit/{sha:([a-f0-9]{7,64})}.{ext:patch|diff}", repo.MustBeNotEmpty, repo.RawDiff) + m.Post("/lastcommit/*", context.RepoRefByType(context.RepoRefCommit), repo.LastCommit) + }, ignSignIn, context.RepoAssignment, reqRepoCodeReader) + // end "/{username}/{reponame}": repo code m.Group("/{username}/{reponame}", func() { m.Get("/stars", repo.Stars) m.Get("/watchers", repo.Watchers) m.Get("/search", reqRepoCodeReader, repo.Search) - }, ignSignIn, context.RepoAssignment, context.RepoRef(), context.UnitTypes()) + m.Post("/action/{action}", reqSignIn, repo.Action) + }, ignSignIn, context.RepoAssignment, context.RepoRef()) - m.Group("/{username}", func() { - m.Group("/{reponame}", func() { - m.Get("", repo.SetEditorconfigIfExists, repo.Home) - }, ignSignIn, context.RepoAssignment, context.RepoRef(), context.UnitTypes()) - - m.Group("/{reponame}", func() { - m.Group("/info/lfs", func() { - m.Post("/objects/batch", lfs.CheckAcceptMediaType, lfs.BatchHandler) - m.Put("/objects/{oid}/{size}", lfs.UploadHandler) - m.Get("/objects/{oid}/{filename}", lfs.DownloadHandler) - m.Get("/objects/{oid}", lfs.DownloadHandler) - m.Post("/verify", lfs.CheckAcceptMediaType, lfs.VerifyHandler) - m.Group("/locks", func() { - m.Get("/", lfs.GetListLockHandler) - m.Post("/", lfs.PostLockHandler) - m.Post("/verify", lfs.VerifyLockHandler) - m.Post("/{lid}/unlock", lfs.UnLockHandler) - }, lfs.CheckAcceptMediaType) - m.Any("/*", func(ctx *context.Context) { - ctx.NotFound("", nil) - }) - }, ignSignInAndCsrf, lfsServerEnabled) - - gitHTTPRouters(m) - }) + m.Group("/{username}/{reponame}", func() { + m.Group("/info/lfs", func() { + m.Post("/objects/batch", lfs.CheckAcceptMediaType, lfs.BatchHandler) + m.Put("/objects/{oid}/{size}", lfs.UploadHandler) + m.Get("/objects/{oid}/{filename}", lfs.DownloadHandler) + m.Get("/objects/{oid}", lfs.DownloadHandler) + m.Post("/verify", lfs.CheckAcceptMediaType, lfs.VerifyHandler) + m.Group("/locks", func() { + m.Get("/", lfs.GetListLockHandler) + m.Post("/", lfs.PostLockHandler) + m.Post("/verify", lfs.VerifyLockHandler) + m.Post("/{lid}/unlock", lfs.UnLockHandler) + }, lfs.CheckAcceptMediaType) + m.Any("/*", func(ctx *context.Context) { + ctx.NotFound("", nil) + }) + }, ignSignInAndCsrf, lfsServerEnabled) + gitHTTPRouters(m) }) - // ***** END: Repository ***** + // end "/{username}/{reponame}.git": git support m.Group("/notifications", func() { m.Get("", user.Notifications) diff --git a/services/context/context.go b/services/context/context.go index 9d7787bf4b..1641e995fb 100644 --- a/services/context/context.go +++ b/services/context/context.go @@ -102,6 +102,18 @@ func NewTemplateContextForWeb(ctx *Context) TemplateContext { tmplCtx["Locale"] = ctx.Base.Locale tmplCtx["AvatarUtils"] = templates.NewAvatarUtils(ctx) tmplCtx["RootData"] = ctx.Data + tmplCtx["Consts"] = map[string]any{ + "RepoUnitTypeCode": unit.TypeCode, + "RepoUnitTypeIssues": unit.TypeIssues, + "RepoUnitTypePullRequests": unit.TypePullRequests, + "RepoUnitTypeReleases": unit.TypeReleases, + "RepoUnitTypeWiki": unit.TypeWiki, + "RepoUnitTypeExternalWiki": unit.TypeExternalWiki, + "RepoUnitTypeExternalTracker": unit.TypeExternalTracker, + "RepoUnitTypeProjects": unit.TypeProjects, + "RepoUnitTypePackages": unit.TypePackages, + "RepoUnitTypeActions": unit.TypeActions, + } return tmplCtx } diff --git a/services/context/repo.go b/services/context/repo.go index 56e9fada0e..1f4c698afc 100644 --- a/services/context/repo.go +++ b/services/context/repo.go @@ -383,7 +383,6 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) { ctx.NotFound("no access right", nil) return } - ctx.Data["HasAccess"] = true ctx.Data["Permission"] = &ctx.Repo.Permission if repo.IsMirror { @@ -1052,19 +1051,3 @@ func GitHookService() func(ctx *Context) { } } } - -// UnitTypes returns a middleware to set unit types to context variables. -func UnitTypes() func(ctx *Context) { - return func(ctx *Context) { - ctx.Data["UnitTypeCode"] = unit_model.TypeCode - ctx.Data["UnitTypeIssues"] = unit_model.TypeIssues - ctx.Data["UnitTypePullRequests"] = unit_model.TypePullRequests - ctx.Data["UnitTypeReleases"] = unit_model.TypeReleases - ctx.Data["UnitTypeWiki"] = unit_model.TypeWiki - ctx.Data["UnitTypeExternalWiki"] = unit_model.TypeExternalWiki - ctx.Data["UnitTypeExternalTracker"] = unit_model.TypeExternalTracker - ctx.Data["UnitTypeProjects"] = unit_model.TypeProjects - ctx.Data["UnitTypePackages"] = unit_model.TypePackages - ctx.Data["UnitTypeActions"] = unit_model.TypeActions - } -} diff --git a/templates/explore/navbar.tmpl b/templates/explore/navbar.tmpl index 8e619fa66f..a157cd4b75 100644 --- a/templates/explore/navbar.tmpl +++ b/templates/explore/navbar.tmpl @@ -11,7 +11,7 @@ <a class="{{if .PageIsExploreOrganizations}}active {{end}}item" href="{{AppSubUrl}}/explore/organizations"> {{svg "octicon-organization"}} {{ctx.Locale.Tr "explore.organizations"}} </a> - {{if and (not $.UnitTypeCode.UnitGlobalDisabled) .IsRepoIndexerEnabled}} + {{if and (not ctx.Consts.RepoUnitTypeCode.UnitGlobalDisabled) .IsRepoIndexerEnabled}} <a class="{{if .PageIsExploreCode}}active {{end}}item" href="{{AppSubUrl}}/explore/code"> {{svg "octicon-code"}} {{ctx.Locale.Tr "explore.code"}} </a> diff --git a/templates/repo/blame.tmpl b/templates/repo/blame.tmpl index 30d1a3d78d..ccef8e4b38 100644 --- a/templates/repo/blame.tmpl +++ b/templates/repo/blame.tmpl @@ -80,7 +80,7 @@ </table> {{end}}{{/* end if .IsFileTooLarge */}} <div class="code-line-menu tippy-target"> - {{if $.Permission.CanRead $.UnitTypeIssues}} + {{if $.Permission.CanRead ctx.Consts.RepoUnitTypeIssues}} <a class="item ref-in-new-issue" role="menuitem" data-url-issue-new="{{.RepoLink}}/issues/new" data-url-param-body-link="{{.Repository.Link}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}{{if $.HasSourceRenderedToggle}}?display=source{{end}}" rel="nofollow noindex">{{ctx.Locale.Tr "repo.issues.context.reference_issue"}}</a> {{end}} <a class="item copy-line-permalink" role="menuitem" data-url="{{.Repository.Link}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}{{if $.HasSourceRenderedToggle}}?display=source{{end}}">{{ctx.Locale.Tr "repo.file_copy_permalink"}}</a> diff --git a/templates/repo/code_frequency.tmpl b/templates/repo/code_frequency.tmpl index 50ec1beb6b..79b45d4931 100644 --- a/templates/repo/code_frequency.tmpl +++ b/templates/repo/code_frequency.tmpl @@ -1,4 +1,4 @@ -{{if .Permission.CanRead $.UnitTypeCode}} +{{if .Permission.CanRead ctx.Consts.RepoUnitTypeCode}} <div id="repo-code-frequency-chart" data-locale-loading-title="{{ctx.Locale.Tr "graphs.component_loading" (ctx.Locale.Tr "graphs.code_frequency.what")}}" data-locale-loading-title-failed="{{ctx.Locale.Tr "graphs.component_loading_failed" (ctx.Locale.Tr "graphs.code_frequency.what")}}" diff --git a/templates/repo/commit_page.tmpl b/templates/repo/commit_page.tmpl index 7fec88cb79..938d93b323 100644 --- a/templates/repo/commit_page.tmpl +++ b/templates/repo/commit_page.tmpl @@ -25,7 +25,7 @@ <a class="ui primary tiny button" href="{{.SourcePath}}"> {{ctx.Locale.Tr "repo.diff.browse_source"}} </a> - {{if and ($.Permission.CanWrite $.UnitTypeCode) (not $.Repository.IsArchived) (not .IsDeleted)}}{{- /* */ -}} + {{if and ($.Permission.CanWrite ctx.Consts.RepoUnitTypeCode) (not $.Repository.IsArchived) (not .IsDeleted)}}{{- /* */ -}} <div class="ui dropdown primary tiny button"> {{ctx.Locale.Tr "repo.commit.operations"}} {{svg "octicon-triangle-down" 14 "dropdown icon"}} diff --git a/templates/repo/contributors.tmpl b/templates/repo/contributors.tmpl index 4a258e5b70..54e3e426a2 100644 --- a/templates/repo/contributors.tmpl +++ b/templates/repo/contributors.tmpl @@ -1,4 +1,4 @@ -{{if .Permission.CanRead $.UnitTypeCode}} +{{if .Permission.CanRead ctx.Consts.RepoUnitTypeCode}} <div id="repo-contributors-chart" data-locale-filter-label="{{ctx.Locale.Tr "repo.contributors.contribution_type.filter_label"}}" data-locale-contribution-type-commits="{{ctx.Locale.Tr "repo.contributors.contribution_type.commits"}}" diff --git a/templates/repo/graph/commits.tmpl b/templates/repo/graph/commits.tmpl index f141dbeada..a90c5309b0 100644 --- a/templates/repo/graph/commits.tmpl +++ b/templates/repo/graph/commits.tmpl @@ -37,7 +37,7 @@ {{if eq $refGroup "pull"}} {{if or (not $.HidePRRefs) (SliceUtils.Contains $.SelectedBranches .Name)}} <!-- it's intended to use issues not pulls, if it's a pull you will get redirected --> - <a class="ui labelled basic tiny button" href="{{$.RepoLink}}/{{if $.Repository.UnitEnabled $.Context $.UnitTypePullRequests}}pulls{{else}}issues{{end}}/{{.ShortName|PathEscape}}"> + <a class="ui labelled basic tiny button" href="{{$.RepoLink}}/{{if $.Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypePullRequests}}pulls{{else}}issues{{end}}/{{.ShortName|PathEscape}}"> {{svg "octicon-git-pull-request"}} #{{.ShortName}} </a> {{end}} diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index bb344bf3d4..775aa30063 100644 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -64,7 +64,7 @@ {{if not $.DisableStars}} {{template "repo/star_unstar" $}} {{end}} - {{if and (not .IsEmpty) ($.Permission.CanRead $.UnitTypeCode)}} + {{if and (not .IsEmpty) ($.Permission.CanRead ctx.Consts.RepoUnitTypeCode)}} <div class="ui labeled button {{if or (not $.IsSigned) (and (not $.CanSignedUserFork) (not $.UserAndOrgForks))}} disabled @@ -131,13 +131,13 @@ <overflow-menu class="ui container secondary pointing tabular top attached borderless menu tw-pt-0 tw-my-0"> {{if not (or .Repository.IsBeingCreated .Repository.IsBroken)}} <div class="overflow-menu-items"> - {{if .Permission.CanRead $.UnitTypeCode}} + {{if .Permission.CanRead ctx.Consts.RepoUnitTypeCode}} <a class="{{if .PageIsViewCode}}active {{end}}item" href="{{.RepoLink}}{{if and (ne .BranchName .Repository.DefaultBranch) (not $.PageIsWiki)}}/src/{{.BranchNameSubURL}}{{end}}"> {{svg "octicon-code"}} {{ctx.Locale.Tr "repo.code"}} </a> {{end}} - {{if .Permission.CanRead $.UnitTypeIssues}} + {{if .Permission.CanRead ctx.Consts.RepoUnitTypeIssues}} <a class="{{if .PageIsIssueList}}active {{end}}item" href="{{.RepoLink}}/issues"> {{svg "octicon-issue-opened"}} {{ctx.Locale.Tr "repo.issues"}} {{if .Repository.NumOpenIssues}} @@ -146,13 +146,13 @@ </a> {{end}} - {{if .Permission.CanRead $.UnitTypeExternalTracker}} + {{if .Permission.CanRead ctx.Consts.RepoUnitTypeExternalTracker}} <a class="{{if .PageIsIssueList}}active {{end}}item" href="{{.RepoExternalIssuesLink}}" target="_blank" rel="noopener noreferrer"> {{svg "octicon-link-external"}} {{ctx.Locale.Tr "repo.issues"}} </a> {{end}} - {{if and .Repository.CanEnablePulls (.Permission.CanRead $.UnitTypePullRequests)}} + {{if and .Repository.CanEnablePulls (.Permission.CanRead ctx.Consts.RepoUnitTypePullRequests)}} <a class="{{if .PageIsPullList}}active {{end}}item" href="{{.RepoLink}}/pulls"> {{svg "octicon-git-pull-request"}} {{ctx.Locale.Tr "repo.pulls"}} {{if .Repository.NumOpenPulls}} @@ -161,7 +161,7 @@ </a> {{end}} - {{if and .EnableActions (not .UnitActionsGlobalDisabled) (.Permission.CanRead $.UnitTypeActions)}} + {{if and .EnableActions (not .UnitActionsGlobalDisabled) (.Permission.CanRead ctx.Consts.RepoUnitTypeActions)}} <a class="{{if .PageIsActions}}active {{end}}item" href="{{.RepoLink}}/actions"> {{svg "octicon-play"}} {{ctx.Locale.Tr "actions.actions"}} {{if .Repository.NumOpenActionRuns}} @@ -170,14 +170,14 @@ </a> {{end}} - {{if .Permission.CanRead $.UnitTypePackages}} + {{if .Permission.CanRead ctx.Consts.RepoUnitTypePackages}} <a href="{{.RepoLink}}/packages" class="{{if .IsPackagesPage}}active {{end}}item"> {{svg "octicon-package"}} {{ctx.Locale.Tr "packages.title"}} </a> {{end}} - {{$projectsUnit := .Repository.MustGetUnit $.Context $.UnitTypeProjects}} - {{if and (not .UnitProjectsGlobalDisabled) (.Permission.CanRead $.UnitTypeProjects) ($projectsUnit.ProjectsConfig.IsProjectsAllowed "repo")}} + {{$projectsUnit := .Repository.MustGetUnit $.Context ctx.Consts.RepoUnitTypeProjects}} + {{if and (not .UnitProjectsGlobalDisabled) (.Permission.CanRead ctx.Consts.RepoUnitTypeProjects) ($projectsUnit.ProjectsConfig.IsProjectsAllowed "repo")}} <a href="{{.RepoLink}}/projects" class="{{if .IsProjectsPage}}active {{end}}item"> {{svg "octicon-project"}} {{ctx.Locale.Tr "repo.project_board"}} {{if .Repository.NumOpenProjects}} @@ -186,7 +186,7 @@ </a> {{end}} - {{if and (.Permission.CanRead $.UnitTypeReleases) (not .IsEmptyRepo)}} + {{if and (.Permission.CanRead ctx.Consts.RepoUnitTypeReleases) (not .IsEmptyRepo)}} <a class="{{if or .PageIsReleaseList .PageIsTagList}}active {{end}}item" href="{{.RepoLink}}/releases"> {{svg "octicon-tag"}} {{ctx.Locale.Tr "repo.releases"}} {{if .NumReleases}} @@ -195,19 +195,19 @@ </a> {{end}} - {{if .Permission.CanRead $.UnitTypeWiki}} + {{if .Permission.CanRead ctx.Consts.RepoUnitTypeWiki}} <a class="{{if .PageIsWiki}}active {{end}}item" href="{{.RepoLink}}/wiki"> {{svg "octicon-book"}} {{ctx.Locale.Tr "repo.wiki"}} </a> {{end}} - {{if .Permission.CanRead $.UnitTypeExternalWiki}} - <a class="item" href="{{(.Repository.MustGetUnit $.Context $.UnitTypeExternalWiki).ExternalWikiConfig.ExternalWikiURL}}" target="_blank" rel="noopener noreferrer"> + {{if .Permission.CanRead ctx.Consts.RepoUnitTypeExternalWiki}} + <a class="item" href="{{(.Repository.MustGetUnit $.Context ctx.Consts.RepoUnitTypeExternalWiki).ExternalWikiConfig.ExternalWikiURL}}" target="_blank" rel="noopener noreferrer"> {{svg "octicon-link-external"}} {{ctx.Locale.Tr "repo.wiki"}} </a> {{end}} - {{if and (.Permission.CanReadAny $.UnitTypePullRequests $.UnitTypeIssues $.UnitTypeReleases) (not .IsEmptyRepo)}} + {{if and (.Permission.CanReadAny ctx.Consts.RepoUnitTypePullRequests ctx.Consts.RepoUnitTypeIssues ctx.Consts.RepoUnitTypeReleases) (not .IsEmptyRepo)}} <a class="{{if .PageIsActivity}}active {{end}}item" href="{{.RepoLink}}/activity"> {{svg "octicon-pulse"}} {{ctx.Locale.Tr "repo.activity"}} </a> diff --git a/templates/repo/issue/view_content/pull.tmpl b/templates/repo/issue/view_content/pull.tmpl index 25e9bbcfc2..117cd7b7a3 100644 --- a/templates/repo/issue/view_content/pull.tmpl +++ b/templates/repo/issue/view_content/pull.tmpl @@ -196,7 +196,7 @@ {{end}} {{if .AllowMerge}} {{/* user is allowed to merge */}} - {{$prUnit := .Repository.MustGetUnit $.Context $.UnitTypePullRequests}} + {{$prUnit := .Repository.MustGetUnit $.Context ctx.Consts.RepoUnitTypePullRequests}} {{$approvers := (.Issue.PullRequest.GetApprovers ctx)}} {{if or $prUnit.PullRequestsConfig.AllowMerge $prUnit.PullRequestsConfig.AllowRebase $prUnit.PullRequestsConfig.AllowRebaseMerge $prUnit.PullRequestsConfig.AllowSquash $prUnit.PullRequestsConfig.AllowFastForwardOnly}} {{$hasPendingPullRequestMergeTip := ""}} diff --git a/templates/repo/pulse.tmpl b/templates/repo/pulse.tmpl index bc25563d48..e68109b755 100644 --- a/templates/repo/pulse.tmpl +++ b/templates/repo/pulse.tmpl @@ -18,10 +18,10 @@ </div> </h2> -{{if (or (.Permission.CanRead $.UnitTypeIssues) (.Permission.CanRead $.UnitTypePullRequests))}} +{{if (or (.Permission.CanRead ctx.Consts.RepoUnitTypeIssues) (.Permission.CanRead ctx.Consts.RepoUnitTypePullRequests))}} <h4 class="ui top attached header">{{ctx.Locale.Tr "repo.activity.overview"}}</h4> <div class="ui attached segment two column grid"> - {{if .Permission.CanRead $.UnitTypePullRequests}} + {{if .Permission.CanRead ctx.Consts.RepoUnitTypePullRequests}} <div class="column"> {{if gt .Activity.ActivePRCount 0}} <div class="stats-table"> @@ -38,7 +38,7 @@ {{ctx.Locale.TrN .Activity.ActivePRCount "repo.activity.active_prs_count_1" "repo.activity.active_prs_count_n" .Activity.ActivePRCount}} </div> {{end}} - {{if .Permission.CanRead $.UnitTypeIssues}} + {{if .Permission.CanRead ctx.Consts.RepoUnitTypeIssues}} <div class="column"> {{if gt .Activity.ActiveIssueCount 0}} <div class="stats-table"> @@ -57,7 +57,7 @@ {{end}} </div> <div class="ui attached segment horizontal segments"> - {{if .Permission.CanRead $.UnitTypePullRequests}} + {{if .Permission.CanRead ctx.Consts.RepoUnitTypePullRequests}} <a href="#merged-pull-requests" class="ui attached segment text center"> <span class="text purple">{{svg "octicon-git-pull-request"}}</span> <strong>{{.Activity.MergedPRCount}}</strong><br> {{ctx.Locale.TrN .Activity.MergedPRCount "repo.activity.merged_prs_count_1" "repo.activity.merged_prs_count_n"}} @@ -67,7 +67,7 @@ {{ctx.Locale.TrN .Activity.OpenedPRCount "repo.activity.opened_prs_count_1" "repo.activity.opened_prs_count_n"}} </a> {{end}} - {{if .Permission.CanRead $.UnitTypeIssues}} + {{if .Permission.CanRead ctx.Consts.RepoUnitTypeIssues}} <a href="#closed-issues" class="ui attached segment text center"> <span class="text red">{{svg "octicon-issue-closed"}}</span> <strong>{{.Activity.ClosedIssueCount}}</strong><br> {{ctx.Locale.TrN .Activity.ClosedIssueCount "repo.activity.closed_issues_count_1" "repo.activity.closed_issues_count_n"}} @@ -80,7 +80,7 @@ </div> {{end}} -{{if .Permission.CanRead $.UnitTypeCode}} +{{if .Permission.CanRead ctx.Consts.RepoUnitTypeCode}} {{if eq .Activity.Code.CommitCountInAllBranches 0}} <div class="ui center aligned segment"> <h4 class="ui header">{{ctx.Locale.Tr "repo.activity.no_git_activity"}}</h4> diff --git a/templates/repo/recent_commits.tmpl b/templates/repo/recent_commits.tmpl index 5c241d635c..cfa8fab11c 100644 --- a/templates/repo/recent_commits.tmpl +++ b/templates/repo/recent_commits.tmpl @@ -1,4 +1,4 @@ -{{if .Permission.CanRead $.UnitTypeCode}} +{{if .Permission.CanRead ctx.Consts.RepoUnitTypeCode}} <div id="repo-recent-commits-chart" data-locale-loading-title="{{ctx.Locale.Tr "graphs.component_loading" (ctx.Locale.Tr "graphs.recent_commits.what")}}" data-locale-loading-title-failed="{{ctx.Locale.Tr "graphs.component_loading_failed" (ctx.Locale.Tr "graphs.recent_commits.what")}}" diff --git a/templates/repo/release/list.tmpl b/templates/repo/release/list.tmpl index 3139022bb4..5a8668fbe1 100644 --- a/templates/repo/release/list.tmpl +++ b/templates/repo/release/list.tmpl @@ -9,8 +9,8 @@ {{$release := $info.Release}} <li class="ui grid"> <div class="ui four wide column meta"> - <a class="muted" href="{{if not (and $release.Sha1 ($.Permission.CanRead $.UnitTypeCode))}}#{{else}}{{$.RepoLink}}/src/tag/{{$release.TagName | PathEscapeSegments}}{{end}}" rel="nofollow">{{svg "octicon-tag" 16 "tw-mr-1"}}{{$release.TagName}}</a> - {{if and $release.Sha1 ($.Permission.CanRead $.UnitTypeCode)}} + <a class="muted" href="{{if not (and $release.Sha1 ($.Permission.CanRead ctx.Consts.RepoUnitTypeCode))}}#{{else}}{{$.RepoLink}}/src/tag/{{$release.TagName | PathEscapeSegments}}{{end}}" rel="nofollow">{{svg "octicon-tag" 16 "tw-mr-1"}}{{$release.TagName}}</a> + {{if and $release.Sha1 ($.Permission.CanRead ctx.Consts.RepoUnitTypeCode)}} <a class="muted tw-font-mono" href="{{$.RepoLink}}/src/commit/{{$release.Sha1}}" rel="nofollow">{{svg "octicon-git-commit" 16 "tw-mr-1"}}{{ShortSha $release.Sha1}}</a> {{template "repo/branch_dropdown" dict "root" $ "release" $release}} {{end}} @@ -53,7 +53,7 @@ {{if $release.CreatedUnix}} <span class="time">{{TimeSinceUnix $release.CreatedUnix ctx.Locale}}</span> {{end}} - {{if and (not $release.IsDraft) ($.Permission.CanRead $.UnitTypeCode)}} + {{if and (not $release.IsDraft) ($.Permission.CanRead ctx.Consts.RepoUnitTypeCode)}} | <span class="ahead"><a href="{{$.RepoLink}}/compare/{{$release.TagName | PathEscapeSegments}}...{{$release.TargetBehind | PathEscapeSegments}}">{{ctx.Locale.Tr "repo.release.ahead.commits" $release.NumCommitsBehind}}</a> {{ctx.Locale.Tr "repo.release.ahead.target" $release.TargetBehind}}</span> {{end}} </p> @@ -66,7 +66,7 @@ {{ctx.Locale.Tr "repo.release.downloads"}} </summary> <ul class="list"> - {{if and (not $.DisableDownloadSourceArchives) (not $release.IsDraft) ($.Permission.CanRead $.UnitTypeCode)}} + {{if and (not $.DisableDownloadSourceArchives) (not $release.IsDraft) ($.Permission.CanRead ctx.Consts.RepoUnitTypeCode)}} <li> <a class="archive-link" href="{{$.RepoLink}}/archive/{{$release.TagName | PathEscapeSegments}}.zip" rel="nofollow"><strong>{{svg "octicon-file-zip" 16 "tw-mr-1"}}{{ctx.Locale.Tr "repo.release.source_code"}} (ZIP)</strong></a> </li> @@ -99,7 +99,7 @@ </div> </div> -{{if (and ($.Permission.CanWrite $.UnitTypeCode) .PageIsTagList)}} +{{if (and ($.Permission.CanWrite ctx.Consts.RepoUnitTypeCode) .PageIsTagList)}} <div class="ui g-modal-confirm delete modal"> <div class="header"> {{svg "octicon-trash"}} diff --git a/templates/repo/release_tag_header.tmpl b/templates/repo/release_tag_header.tmpl index ab1e58620d..f96c76864f 100644 --- a/templates/repo/release_tag_header.tmpl +++ b/templates/repo/release_tag_header.tmpl @@ -1,5 +1,5 @@ -{{$canReadReleases := $.Permission.CanRead $.UnitTypeReleases}} -{{$canReadCode := $.Permission.CanRead $.UnitTypeCode}} +{{$canReadReleases := $.Permission.CanRead ctx.Consts.RepoUnitTypeReleases}} +{{$canReadCode := $.Permission.CanRead ctx.Consts.RepoUnitTypeCode}} {{if $canReadReleases}} <div class="tw-flex"> diff --git a/templates/repo/settings/navbar.tmpl b/templates/repo/settings/navbar.tmpl index 0b0ef0b6e8..414effbf2f 100644 --- a/templates/repo/settings/navbar.tmpl +++ b/templates/repo/settings/navbar.tmpl @@ -12,7 +12,7 @@ {{ctx.Locale.Tr "repo.settings.hooks"}} </a> {{end}} - {{if .Repository.UnitEnabled $.Context $.UnitTypeCode}} + {{if .Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeCode}} {{if not .Repository.IsEmpty}} <a class="{{if .PageIsSettingsBranches}}active {{end}}item" href="{{.RepoLink}}/settings/branches"> {{ctx.Locale.Tr "repo.settings.branches"}} @@ -35,7 +35,7 @@ </a> {{end}} {{end}} - {{if and .EnableActions (not .UnitActionsGlobalDisabled) (.Permission.CanRead $.UnitTypeActions)}} + {{if and .EnableActions (not .UnitActionsGlobalDisabled) (.Permission.CanRead ctx.Consts.RepoUnitTypeActions)}} <details class="item toggleable-item" {{if or .PageIsSharedSettingsRunners .PageIsSharedSettingsSecrets .PageIsSharedSettingsVariables}}open{{end}}> <summary>{{ctx.Locale.Tr "actions.actions"}}</summary> <div class="menu"> diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index df6ccbf6bc..251785d078 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -66,7 +66,7 @@ {{/* These variables exist to make the logic in the Settings window easier to comprehend and are not used later on. */}} {{$newMirrorsPartiallyEnabled := or (not .DisableNewPullMirrors) (not .DisableNewPushMirrors)}} {{/* .Repository.IsMirror is not always reliable if the repository is not actively acting as a mirror because of errors. */}} - {{$showMirrorSettings := and (.Repository.UnitEnabled $.Context $.UnitTypeCode) (or $newMirrorsPartiallyEnabled .Repository.IsMirror .PullMirror .PushMirrors)}} + {{$showMirrorSettings := and (.Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeCode) (or $newMirrorsPartiallyEnabled .Repository.IsMirror .PullMirror .PushMirrors)}} {{$newMirrorsEntirelyEnabled := and (not .DisableNewPullMirrors) (not .DisableNewPushMirrors)}} {{$onlyNewPushMirrorsEnabled := and (not .DisableNewPushMirrors) .DisableNewPullMirrors}} {{$onlyNewPullMirrorsEnabled := and .DisableNewPushMirrors (not .DisableNewPullMirrors)}} @@ -307,8 +307,8 @@ {{.CsrfTokenHtml}} <input type="hidden" name="action" value="advanced"> - {{$isCodeEnabled := .Repository.UnitEnabled $.Context $.UnitTypeCode}} - {{$isCodeGlobalDisabled := .UnitTypeCode.UnitGlobalDisabled}} + {{$isCodeEnabled := .Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeCode}} + {{$isCodeGlobalDisabled := ctx.Consts.RepoUnitTypeCode.UnitGlobalDisabled}} <div class="inline field"> <label>{{ctx.Locale.Tr "repo.code"}}</label> <div class="ui checkbox{{if $isCodeGlobalDisabled}} disabled{{end}}"{{if $isCodeGlobalDisabled}} data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{end}}> @@ -317,9 +317,9 @@ </div> </div> - {{$isWikiEnabled := or (.Repository.UnitEnabled $.Context $.UnitTypeWiki) (.Repository.UnitEnabled $.Context $.UnitTypeExternalWiki)}} - {{$isWikiGlobalDisabled := .UnitTypeWiki.UnitGlobalDisabled}} - {{$isExternalWikiGlobalDisabled := .UnitTypeExternalWiki.UnitGlobalDisabled}} + {{$isWikiEnabled := or (.Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeWiki) (.Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeExternalWiki)}} + {{$isWikiGlobalDisabled := ctx.Consts.RepoUnitTypeWiki.UnitGlobalDisabled}} + {{$isExternalWikiGlobalDisabled := ctx.Consts.RepoUnitTypeExternalWiki.UnitGlobalDisabled}} {{$isBothWikiGlobalDisabled := and $isWikiGlobalDisabled $isExternalWikiGlobalDisabled}} <div class="inline field"> <label>{{ctx.Locale.Tr "repo.wiki"}}</label> @@ -331,7 +331,7 @@ <div class="field{{if not $isWikiEnabled}} disabled{{end}}" id="wiki_box"> <div class="field"> <div class="ui radio checkbox{{if $isWikiGlobalDisabled}} disabled{{end}}"{{if $isWikiGlobalDisabled}} data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{end}}> - <input class="enable-system-radio" name="enable_external_wiki" type="radio" value="false" data-target="#external_wiki_box" {{if not (.Repository.UnitEnabled $.Context $.UnitTypeExternalWiki)}}checked{{end}}> + <input class="enable-system-radio" name="enable_external_wiki" type="radio" value="false" data-target="#external_wiki_box" {{if not (.Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeExternalWiki)}}checked{{end}}> <label>{{ctx.Locale.Tr "repo.settings.use_internal_wiki"}}</label> </div> </div> @@ -341,22 +341,22 @@ </div> <div class="field"> <div class="ui radio checkbox{{if $isExternalWikiGlobalDisabled}} disabled{{end}}"{{if $isExternalWikiGlobalDisabled}} data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{end}}> - <input class="enable-system-radio" name="enable_external_wiki" type="radio" value="true" data-target="#external_wiki_box" {{if .Repository.UnitEnabled $.Context $.UnitTypeExternalWiki}}checked{{end}}> + <input class="enable-system-radio" name="enable_external_wiki" type="radio" value="true" data-target="#external_wiki_box" {{if .Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeExternalWiki}}checked{{end}}> <label>{{ctx.Locale.Tr "repo.settings.use_external_wiki"}}</label> </div> </div> - <div class="field tw-pl-4 {{if not (.Repository.UnitEnabled $.Context $.UnitTypeExternalWiki)}}disabled{{end}}" id="external_wiki_box"> + <div class="field tw-pl-4 {{if not (.Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeExternalWiki)}}disabled{{end}}" id="external_wiki_box"> <label for="external_wiki_url">{{ctx.Locale.Tr "repo.settings.external_wiki_url"}}</label> - <input id="external_wiki_url" name="external_wiki_url" type="url" value="{{(.Repository.MustGetUnit $.Context $.UnitTypeExternalWiki).ExternalWikiConfig.ExternalWikiURL}}"> + <input id="external_wiki_url" name="external_wiki_url" type="url" value="{{(.Repository.MustGetUnit $.Context ctx.Consts.RepoUnitTypeExternalWiki).ExternalWikiConfig.ExternalWikiURL}}"> <p class="help">{{ctx.Locale.Tr "repo.settings.external_wiki_url_desc"}}</p> </div> </div> <div class="divider"></div> - {{$isIssuesEnabled := or (.Repository.UnitEnabled $.Context $.UnitTypeIssues) (.Repository.UnitEnabled $.Context $.UnitTypeExternalTracker)}} - {{$isIssuesGlobalDisabled := .UnitTypeIssues.UnitGlobalDisabled}} - {{$isExternalTrackerGlobalDisabled := .UnitTypeExternalTracker.UnitGlobalDisabled}} + {{$isIssuesEnabled := or (.Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeIssues) (.Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeExternalTracker)}} + {{$isIssuesGlobalDisabled := ctx.Consts.RepoUnitTypeIssues.UnitGlobalDisabled}} + {{$isExternalTrackerGlobalDisabled := ctx.Consts.RepoUnitTypeExternalTracker.UnitGlobalDisabled}} {{$isIssuesAndExternalGlobalDisabled := and $isIssuesGlobalDisabled $isExternalTrackerGlobalDisabled}} <div class="inline field"> <label>{{ctx.Locale.Tr "repo.issues"}}</label> @@ -368,11 +368,11 @@ <div class="field {{if not $isIssuesEnabled}}disabled{{end}}" id="issue_box"> <div class="field"> <div class="ui radio checkbox{{if $isIssuesGlobalDisabled}} disabled{{end}}"{{if $isIssuesGlobalDisabled}} data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{end}}> - <input class="enable-system-radio" name="enable_external_tracker" type="radio" value="false" data-context="#internal_issue_box" data-target="#external_issue_box" {{if not (.Repository.UnitEnabled $.Context $.UnitTypeExternalTracker)}}checked{{end}}> + <input class="enable-system-radio" name="enable_external_tracker" type="radio" value="false" data-context="#internal_issue_box" data-target="#external_issue_box" {{if not (.Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeExternalTracker)}}checked{{end}}> <label>{{ctx.Locale.Tr "repo.settings.use_internal_issue_tracker"}}</label> </div> </div> - <div class="field tw-pl-4 {{if (.Repository.UnitEnabled $.Context $.UnitTypeExternalTracker)}}disabled{{end}}" id="internal_issue_box"> + <div class="field tw-pl-4 {{if (.Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeExternalTracker)}}disabled{{end}}" id="internal_issue_box"> {{if .Repository.CanEnableTimetracker}} <div class="field"> <div class="ui checkbox"> @@ -400,26 +400,26 @@ </div> <div class="field"> <div class="ui radio checkbox{{if $isExternalTrackerGlobalDisabled}} disabled{{end}}"{{if $isExternalTrackerGlobalDisabled}} data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{end}}> - <input class="enable-system-radio" name="enable_external_tracker" type="radio" value="true" data-context="#internal_issue_box" data-target="#external_issue_box" {{if .Repository.UnitEnabled $.Context $.UnitTypeExternalTracker}}checked{{end}}> + <input class="enable-system-radio" name="enable_external_tracker" type="radio" value="true" data-context="#internal_issue_box" data-target="#external_issue_box" {{if .Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeExternalTracker}}checked{{end}}> <label>{{ctx.Locale.Tr "repo.settings.use_external_issue_tracker"}}</label> </div> </div> - <div class="field tw-pl-4 {{if not (.Repository.UnitEnabled $.Context $.UnitTypeExternalTracker)}}disabled{{end}}" id="external_issue_box"> + <div class="field tw-pl-4 {{if not (.Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeExternalTracker)}}disabled{{end}}" id="external_issue_box"> <div class="field"> <label for="external_tracker_url">{{ctx.Locale.Tr "repo.settings.external_tracker_url"}}</label> - <input id="external_tracker_url" name="external_tracker_url" type="url" value="{{(.Repository.MustGetUnit $.Context $.UnitTypeExternalTracker).ExternalTrackerConfig.ExternalTrackerURL}}"> + <input id="external_tracker_url" name="external_tracker_url" type="url" value="{{(.Repository.MustGetUnit $.Context ctx.Consts.RepoUnitTypeExternalTracker).ExternalTrackerConfig.ExternalTrackerURL}}"> <p class="help">{{ctx.Locale.Tr "repo.settings.external_tracker_url_desc"}}</p> </div> <div class="field"> <label for="tracker_url_format">{{ctx.Locale.Tr "repo.settings.tracker_url_format"}}</label> - <input id="tracker_url_format" name="tracker_url_format" type="url" value="{{(.Repository.MustGetUnit $.Context $.UnitTypeExternalTracker).ExternalTrackerConfig.ExternalTrackerFormat}}" placeholder="https://github.com/{user}/{repo}/issues/{index}"> + <input id="tracker_url_format" name="tracker_url_format" type="url" value="{{(.Repository.MustGetUnit $.Context ctx.Consts.RepoUnitTypeExternalTracker).ExternalTrackerConfig.ExternalTrackerFormat}}" placeholder="https://github.com/{user}/{repo}/issues/{index}"> <p class="help">{{ctx.Locale.Tr "repo.settings.tracker_url_format_desc"}}</p> </div> <div class="inline fields"> <label for="issue_style">{{ctx.Locale.Tr "repo.settings.tracker_issue_style"}}</label> <div class="field"> <div class="ui radio checkbox"> - {{$externalTracker := (.Repository.MustGetUnit $.Context $.UnitTypeExternalTracker)}} + {{$externalTracker := (.Repository.MustGetUnit $.Context ctx.Consts.RepoUnitTypeExternalTracker)}} {{$externalTrackerStyle := $externalTracker.ExternalTrackerConfig.ExternalTrackerStyle}} <input class="js-tracker-issue-style" name="tracker_issue_style" type="radio" value="numeric" {{if eq $externalTrackerStyle "numeric"}}checked{{end}}> <label>{{ctx.Locale.Tr "repo.settings.tracker_issue_style.numeric"}} <span class="ui light grey text">#1234</span></label> @@ -440,7 +440,7 @@ </div> <div class="field {{if ne $externalTrackerStyle "regexp"}}disabled{{end}}" id="tracker-issue-style-regex-box"> <label for="external_tracker_regexp_pattern">{{ctx.Locale.Tr "repo.settings.tracker_issue_style.regexp_pattern"}}</label> - <input id="external_tracker_regexp_pattern" name="external_tracker_regexp_pattern" value="{{(.Repository.MustGetUnit $.Context $.UnitTypeExternalTracker).ExternalTrackerConfig.ExternalTrackerRegexpPattern}}"> + <input id="external_tracker_regexp_pattern" name="external_tracker_regexp_pattern" value="{{(.Repository.MustGetUnit $.Context ctx.Consts.RepoUnitTypeExternalTracker).ExternalTrackerConfig.ExternalTrackerRegexpPattern}}"> <p class="help">{{ctx.Locale.Tr "repo.settings.tracker_issue_style.regexp_pattern_desc"}}</p> </div> </div> @@ -448,9 +448,9 @@ <div class="divider"></div> - {{$isProjectsEnabled := .Repository.UnitEnabled $.Context $.UnitTypeProjects}} - {{$isProjectsGlobalDisabled := .UnitTypeProjects.UnitGlobalDisabled}} - {{$projectsUnit := .Repository.MustGetUnit $.Context $.UnitTypeProjects}} + {{$isProjectsEnabled := .Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeProjects}} + {{$isProjectsGlobalDisabled := ctx.Consts.RepoUnitTypeProjects.UnitGlobalDisabled}} + {{$projectsUnit := .Repository.MustGetUnit $.Context ctx.Consts.RepoUnitTypeProjects}} <div class="inline field"> <label>{{ctx.Locale.Tr "repo.project_board"}}</label> <div class="ui checkbox{{if $isProjectsGlobalDisabled}} disabled{{end}}"{{if $isProjectsGlobalDisabled}} data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{end}}> @@ -490,8 +490,8 @@ <div class="divider"></div> - {{$isReleasesEnabled := .Repository.UnitEnabled $.Context $.UnitTypeReleases}} - {{$isReleasesGlobalDisabled := .UnitTypeReleases.UnitGlobalDisabled}} + {{$isReleasesEnabled := .Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeReleases}} + {{$isReleasesGlobalDisabled := ctx.Consts.RepoUnitTypeReleases.UnitGlobalDisabled}} <div class="inline field"> <label>{{ctx.Locale.Tr "repo.releases"}}</label> <div class="ui checkbox{{if $isReleasesGlobalDisabled}} disabled{{end}}"{{if $isReleasesGlobalDisabled}} data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{end}}> @@ -500,8 +500,8 @@ </div> </div> - {{$isPackagesEnabled := .Repository.UnitEnabled $.Context $.UnitTypePackages}} - {{$isPackagesGlobalDisabled := .UnitTypePackages.UnitGlobalDisabled}} + {{$isPackagesEnabled := .Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypePackages}} + {{$isPackagesGlobalDisabled := ctx.Consts.RepoUnitTypePackages.UnitGlobalDisabled}} <div class="inline field"> <label>{{ctx.Locale.Tr "repo.packages"}}</label> <div class="ui checkbox{{if $isPackagesGlobalDisabled}} disabled{{end}}"{{if $isPackagesGlobalDisabled}} data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{end}}> @@ -511,8 +511,8 @@ </div> {{if .EnableActions}} - {{$isActionsEnabled := .Repository.UnitEnabled $.Context $.UnitTypeActions}} - {{$isActionsGlobalDisabled := .UnitTypeActions.UnitGlobalDisabled}} + {{$isActionsEnabled := .Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeActions}} + {{$isActionsGlobalDisabled := ctx.Consts.RepoUnitTypeActions.UnitGlobalDisabled}} <div class="inline field"> <label>{{ctx.Locale.Tr "actions.actions"}}</label> <div class="ui checkbox{{if $isActionsGlobalDisabled}} disabled{{end}}"{{if $isActionsGlobalDisabled}} data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{end}}> @@ -524,9 +524,9 @@ {{if not .IsMirror}} <div class="divider"></div> - {{$pullRequestEnabled := .Repository.UnitEnabled $.Context $.UnitTypePullRequests}} - {{$pullRequestGlobalDisabled := .UnitTypePullRequests.UnitGlobalDisabled}} - {{$prUnit := .Repository.MustGetUnit $.Context $.UnitTypePullRequests}} + {{$pullRequestEnabled := .Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypePullRequests}} + {{$pullRequestGlobalDisabled := ctx.Consts.RepoUnitTypePullRequests.UnitGlobalDisabled}} + {{$prUnit := .Repository.MustGetUnit $.Context ctx.Consts.RepoUnitTypePullRequests}} <div class="inline field"> <label>{{ctx.Locale.Tr "repo.pulls"}}</label> <div class="ui checkbox{{if $pullRequestGlobalDisabled}} disabled{{end}}"{{if $pullRequestGlobalDisabled}} data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{end}}> @@ -816,7 +816,7 @@ {{end}} </div> </div> - {{if .Permission.CanRead $.UnitTypeWiki}} + {{if .Permission.CanRead ctx.Consts.RepoUnitTypeWiki}} <div class="flex-item"> <div class="flex-item-main"> <div class="flex-item-title">{{ctx.Locale.Tr "repo.settings.wiki_delete"}}</div> @@ -997,7 +997,7 @@ </div> </div> - {{if .Repository.UnitEnabled $.Context $.UnitTypeWiki}} + {{if .Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeWiki}} <div class="ui small modal" id="delete-wiki-modal"> <div class="header"> {{ctx.Locale.Tr "repo.settings.wiki_delete"}} diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl index 000e0a10c5..87d2110314 100644 --- a/templates/repo/sub_menu.tmpl +++ b/templates/repo/sub_menu.tmpl @@ -1,14 +1,14 @@ {{if and (not .HideRepoInfo) (not .IsBlame)}} <div class="ui segments repository-summary tw-mt-1 tw-mb-0"> <div class="ui segment sub-menu repository-menu"> - {{if and (.Permission.CanRead $.UnitTypeCode) (not .IsEmptyRepo)}} + {{if and (.Permission.CanRead ctx.Consts.RepoUnitTypeCode) (not .IsEmptyRepo)}} <a class="item muted {{if .PageIsCommits}}active{{end}}" href="{{.RepoLink}}/commits/{{.BranchNameSubURL}}"> {{svg "octicon-history"}} <b>{{ctx.Locale.PrettyNumber .CommitsCount}}</b> {{ctx.Locale.TrN .CommitsCount "repo.commit" "repo.commits"}} </a> <a class="item muted {{if .PageIsBranches}}active{{end}}" href="{{.RepoLink}}/branches"> {{svg "octicon-git-branch"}} <b>{{ctx.Locale.PrettyNumber .BranchesCount}}</b> {{ctx.Locale.TrN .BranchesCount "repo.branch" "repo.branches"}} </a> - {{if $.Permission.CanRead $.UnitTypeCode}} + {{if $.Permission.CanRead ctx.Consts.RepoUnitTypeCode}} <a class="item muted {{if .PageIsTagList}}active{{end}}" href="{{.RepoLink}}/tags"> {{svg "octicon-tag"}} <b>{{ctx.Locale.PrettyNumber .NumTags}}</b> {{ctx.Locale.TrN .NumTags "repo.tag" "repo.tags"}} </a> @@ -20,7 +20,7 @@ </span> {{end}} </div> - {{if and (.Permission.CanRead $.UnitTypeCode) (not .IsEmptyRepo) .LanguageStats}} + {{if and (.Permission.CanRead ctx.Consts.RepoUnitTypeCode) (not .IsEmptyRepo) .LanguageStats}} <div class="ui segment sub-menu language-stats-details tw-hidden"> {{range .LanguageStats}} <div class="item"> diff --git a/templates/repo/tag/list.tmpl b/templates/repo/tag/list.tmpl index 5378a8a322..a63c94cd8e 100644 --- a/templates/repo/tag/list.tmpl +++ b/templates/repo/tag/list.tmpl @@ -9,7 +9,7 @@ {{svg "octicon-tag" 16 "tw-mr-1"}}{{ctx.Locale.Tr "repo.release.tags"}} </div> </h4> - {{$canReadReleases := $.Permission.CanRead $.UnitTypeReleases}} + {{$canReadReleases := $.Permission.CanRead ctx.Consts.RepoUnitTypeReleases}} <div class="ui attached table segment"> <table class="ui very basic striped fixed table single line" id="tags-table"> <tbody class="tag-list"> @@ -24,7 +24,7 @@ {{end}} </h3> <div class="download tw-flex tw-items-center"> - {{if $.Permission.CanRead $.UnitTypeCode}} + {{if $.Permission.CanRead ctx.Consts.RepoUnitTypeCode}} {{if .CreatedUnix}} <span class="tw-mr-2">{{svg "octicon-clock" 16 "tw-mr-1"}}{{TimeSinceUnix .CreatedUnix ctx.Locale}}</span> {{end}} @@ -40,7 +40,7 @@ <a class="tw-mr-2 muted" href="{{$.RepoLink}}/releases/new?tag={{.TagName}}">{{svg "octicon-tag" 16 "tw-mr-1"}}{{ctx.Locale.Tr "repo.release.new_release"}}</a> {{end}} - {{if (and ($.Permission.CanWrite $.UnitTypeCode) $release.IsTag)}} + {{if (and ($.Permission.CanWrite ctx.Consts.RepoUnitTypeCode) $release.IsTag)}} <a class="ui delete-button tw-mr-2 muted" data-url="{{$.RepoLink}}/tags/delete" data-id="{{.ID}}"> {{svg "octicon-trash" 16 "tw-mr-1"}}{{ctx.Locale.Tr "repo.release.delete_tag"}} </a> @@ -62,7 +62,7 @@ </div> </div> -{{if $.Permission.CanWrite $.UnitTypeCode}} +{{if $.Permission.CanWrite ctx.Consts.RepoUnitTypeCode}} <div class="ui g-modal-confirm delete modal"> <div class="header"> {{svg "octicon-trash"}} diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl index 0683004718..da82332066 100644 --- a/templates/repo/view_file.tmpl +++ b/templates/repo/view_file.tmpl @@ -129,7 +129,7 @@ </tbody> </table> <div class="code-line-menu tippy-target"> - {{if $.Permission.CanRead $.UnitTypeIssues}} + {{if $.Permission.CanRead ctx.Consts.RepoUnitTypeIssues}} <a class="item ref-in-new-issue" role="menuitem" data-url-issue-new="{{.RepoLink}}/issues/new" data-url-param-body-link="{{.Repository.Link}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}{{if $.HasSourceRenderedToggle}}?display=source{{end}}" rel="nofollow noindex">{{ctx.Locale.Tr "repo.issues.context.reference_issue"}}</a> {{end}} <a class="item view_git_blame" role="menuitem" href="{{.Repository.Link}}/blame/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}">{{ctx.Locale.Tr "repo.view_git_blame"}}</a> From 311f5261cdb23b46d3f510e40fd4e2ac06e376c0 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Wed, 17 Apr 2024 10:58:08 +0200 Subject: [PATCH 136/370] Fix and tweak pull request commit list (#30528) Fixes https://github.com/go-gitea/gitea/issues/30493, regression from https://github.com/go-gitea/gitea/pull/30374. Also did the flexbox convertion as suggested by the existing comment. <img width="850" alt="Screenshot 2024-04-16 at 22 28 48" src="https://github.com/go-gitea/gitea/assets/115237/e8905944-620a-4211-b5c5-53ed3b3ee23e"> Co-authored-by: Giteabot <teabot@gitea.io> --- templates/repo/commits_list_small.tmpl | 23 ++++++++++---------- web_src/css/repo.css | 30 ++++++++++++-------------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/templates/repo/commits_list_small.tmpl b/templates/repo/commits_list_small.tmpl index d96b314d01..6ca6dd5cdc 100644 --- a/templates/repo/commits_list_small.tmpl +++ b/templates/repo/commits_list_small.tmpl @@ -6,14 +6,23 @@ <div class="singular-commit" id="{{$tag}}"> <span class="badge badge-commit">{{svg "octicon-git-commit"}}</span> {{if .User}} - <a class="avatar" href="{{.User.HomeLink}}">{{ctx.AvatarUtils.Avatar .User}}</a> + <a class="avatar" href="{{.User.HomeLink}}">{{ctx.AvatarUtils.Avatar .User 20}}</a> {{else}} - {{ctx.AvatarUtils.AvatarByEmail .Author.Email .Author.Name}} + {{ctx.AvatarUtils.AvatarByEmail .Author.Email .Author.Name 20}} {{end}} {{$commitLink:= printf "%s/commit/%s" $.comment.Issue.PullRequest.BaseRepo.Link (PathEscape .ID.String)}} - <span class="shabox tw-flex tw-items-center tw-float-right"> + <span class="tw-flex-1 gt-ellipsis tw-font-mono{{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{RenderCommitMessageLinkSubject $.root.Context .Message $commitLink ($.comment.Issue.PullRequest.BaseRepo.ComposeMetas ctx)}}</span> + + {{if IsMultilineCommitMessage .Message}} + <button class="ui button js-toggle-commit-body ellipsis-button" aria-expanded="false">...</button> + {{end}} + {{if IsMultilineCommitMessage .Message}} + <pre class="commit-body tw-hidden">{{RenderCommitBody $.root.Context .Message ($.comment.Issue.PullRequest.BaseRepo.ComposeMetas ctx)}}</pre> + {{end}} + + <span class="shabox tw-flex tw-items-center"> {{template "repo/commit_statuses" dict "Status" .Status "Statuses" .Statuses}} {{$class := "ui sha label"}} {{if .Signature}} @@ -37,14 +46,6 @@ {{end}} </a> </span> - - <span class="tw-font-mono commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{RenderCommitMessageLinkSubject $.root.Context .Message $commitLink ($.comment.Issue.PullRequest.BaseRepo.ComposeMetas ctx)}}</span> - {{if IsMultilineCommitMessage .Message}} - <button class="ui button js-toggle-commit-body ellipsis-button" aria-expanded="false">...</button> - {{end}} - {{if IsMultilineCommitMessage .Message}} - <pre class="commit-body tw-hidden">{{RenderCommitBody $.root.Context .Message ($.comment.Issue.PullRequest.BaseRepo.ComposeMetas ctx)}}</pre> - {{end}} </div> {{end}} </div> diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 8d1f60d158..882d86c4f6 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -832,55 +832,53 @@ td .commit-summary { margin-right: 0.25em; } -.repository.view.issue .comment-list .timeline-item.commits-list .singular-commit { - line-height: 34px; /* this must be same as .badge height, to avoid overflow */ - clear: both; /* reset the "float right shabox", in the future, use flexbox instead */ +.singular-commit { + display: flex; + align-items: center; } -.repository.view.issue .comment-list .timeline-item.commits-list .singular-commit > img.avatar, -.repository.view.issue .comment-list .timeline-item.commits-list .singular-commit > .avatar img { - position: relative; - top: -2px; +.singular-commit .badge { + height: 30px !important; } -.repository.view.issue .comment-list .timeline-item.commits-list .singular-commit .shabox .sha.label { +.singular-commit .shabox .sha.label { margin: 0; border: 1px solid var(--color-light-border); } -.repository.view.issue .comment-list .timeline-item.commits-list .singular-commit .shabox .sha.label.isSigned.isWarning { +.singular-commit .shabox .sha.label.isSigned.isWarning { border: 1px solid var(--color-red-badge); background: var(--color-red-badge-bg); } -.repository.view.issue .comment-list .timeline-item.commits-list .singular-commit .shabox .sha.label.isSigned.isWarning:hover { +.singular-commit .shabox .sha.label.isSigned.isWarning:hover { background: var(--color-red-badge-hover-bg) !important; } -.repository.view.issue .comment-list .timeline-item.commits-list .singular-commit .shabox .sha.label.isSigned.isVerified { +.singular-commit .shabox .sha.label.isSigned.isVerified { border: 1px solid var(--color-green-badge); background: var(--color-green-badge-bg); } -.repository.view.issue .comment-list .timeline-item.commits-list .singular-commit .shabox .sha.label.isSigned.isVerified:hover { +.singular-commit .shabox .sha.label.isSigned.isVerified:hover { background: var(--color-green-badge-hover-bg) !important; } -.repository.view.issue .comment-list .timeline-item.commits-list .singular-commit .shabox .sha.label.isSigned.isVerifiedUntrusted { +.singular-commit .shabox .sha.label.isSigned.isVerifiedUntrusted { border: 1px solid var(--color-yellow-badge); background: var(--color-yellow-badge-bg); } -.repository.view.issue .comment-list .timeline-item.commits-list .singular-commit .shabox .sha.label.isSigned.isVerifiedUntrusted:hover { +.singular-commit .shabox .sha.label.isSigned.isVerifiedUntrusted:hover { background: var(--color-yellow-badge-hover-bg) !important; } -.repository.view.issue .comment-list .timeline-item.commits-list .singular-commit .shabox .sha.label.isSigned.isVerifiedUnmatched { +.singular-commit .shabox .sha.label.isSigned.isVerifiedUnmatched { border: 1px solid var(--color-orange-badge); background: var(--color-orange-badge-bg); } -.repository.view.issue .comment-list .timeline-item.commits-list .singular-commit .shabox .sha.label.isSigned.isVerifiedUnmatched:hover { +.singular-commit .shabox .sha.label.isSigned.isVerifiedUnmatched:hover { background: var(--color-orange-badge-hover-bg) !important; } From 8e12ef911a1d10dedb03e3127c42ca76f9850aca Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Wed, 17 Apr 2024 11:40:35 +0200 Subject: [PATCH 137/370] Run `go generate` and `go vet` on all packages (#30529) Fixes: https://github.com/go-gitea/gitea/issues/30512 I think this does mean those tools would run on a potential `vendor` directory, but I'm not sure we really support vendoring of dependencies anymore. `release` has a `vendor` prerequisite so likely the source tarballs contain vendor files? --- Makefile | 5 ++--- tests/integration/api_comment_attachment_test.go | 3 +-- tests/integration/api_issue_attachment_test.go | 3 +-- tests/integration/api_packages_cargo_test.go | 3 +-- tests/integration/markup_external_test.go | 3 +-- tests/integration/repo_mergecommit_revert_test.go | 3 +++ 6 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 594f13ead8..1bb79e0337 100644 --- a/Makefile +++ b/Makefile @@ -110,7 +110,6 @@ LDFLAGS := $(LDFLAGS) -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(G LINUX_ARCHS ?= linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64 -GO_PACKAGES ?= $(filter-out code.gitea.io/gitea/tests/integration/migration-test code.gitea.io/gitea/tests code.gitea.io/gitea/tests/integration code.gitea.io/gitea/tests/e2e,$(shell $(GO) list ./... | grep -v /vendor/)) GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list code.gitea.io/gitea/models/migrations/...) code.gitea.io/gitea/tests/integration/migration-test code.gitea.io/gitea/tests code.gitea.io/gitea/tests/integration code.gitea.io/gitea/tests/e2e,$(shell $(GO) list ./... | grep -v /vendor/)) MIGRATE_TEST_PACKAGES ?= $(shell $(GO) list code.gitea.io/gitea/models/migrations/...) @@ -423,7 +422,7 @@ lint-go-windows: lint-go-vet: @echo "Running go vet..." @GOOS= GOARCH= $(GO) build code.gitea.io/gitea-vet - @$(GO) vet -vettool=gitea-vet $(GO_PACKAGES) + @$(GO) vet -vettool=gitea-vet ./... .PHONY: lint-editorconfig lint-editorconfig: @@ -779,7 +778,7 @@ generate-backend: $(TAGS_PREREQ) generate-go .PHONY: generate-go generate-go: $(TAGS_PREREQ) @echo "Running go generate..." - @CC= GOOS= GOARCH= $(GO) generate -tags '$(TAGS)' $(GO_PACKAGES) + @CC= GOOS= GOARCH= $(GO) generate -tags '$(TAGS)' ./... .PHONY: security-check security-check: diff --git a/tests/integration/api_comment_attachment_test.go b/tests/integration/api_comment_attachment_test.go index e5e62a86b7..2d7587bbde 100644 --- a/tests/integration/api_comment_attachment_test.go +++ b/tests/integration/api_comment_attachment_test.go @@ -1,6 +1,5 @@ // Copyright 2021 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. +// SPDX-License-Identifier: MIT package integration diff --git a/tests/integration/api_issue_attachment_test.go b/tests/integration/api_issue_attachment_test.go index 4b57d387d8..497dd0155e 100644 --- a/tests/integration/api_issue_attachment_test.go +++ b/tests/integration/api_issue_attachment_test.go @@ -1,6 +1,5 @@ // Copyright 2021 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. +// SPDX-License-Identifier: MIT package integration diff --git a/tests/integration/api_packages_cargo_test.go b/tests/integration/api_packages_cargo_test.go index c0705e0de5..3fb9687653 100644 --- a/tests/integration/api_packages_cargo_test.go +++ b/tests/integration/api_packages_cargo_test.go @@ -1,6 +1,5 @@ // Copyright 2021 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. +// SPDX-License-Identifier: MIT package integration diff --git a/tests/integration/markup_external_test.go b/tests/integration/markup_external_test.go index 5f102f8d62..e50f5c1356 100644 --- a/tests/integration/markup_external_test.go +++ b/tests/integration/markup_external_test.go @@ -1,6 +1,5 @@ // Copyright 2022 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. +// SPDX-License-Identifier: MIT package integration diff --git a/tests/integration/repo_mergecommit_revert_test.go b/tests/integration/repo_mergecommit_revert_test.go index 4d612bdcdb..103fb47e2b 100644 --- a/tests/integration/repo_mergecommit_revert_test.go +++ b/tests/integration/repo_mergecommit_revert_test.go @@ -1,3 +1,6 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + package integration import ( From 0798370f25ca3bd67933dd6d75c342aaded57095 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Wed, 17 Apr 2024 18:24:08 +0800 Subject: [PATCH 138/370] Correct locale string rendering (#30522) Since #29165, the translations are rendered as HTML in templates, so: 1. if the translation does contain `<>`, use `TrString` 2. use `{dummy}` instead of `<dummy>` as much as possible Co-authored-by: Giteabot <teabot@gitea.io> --- options/locale/locale_en-US.ini | 8 ++++---- templates/install.tmpl | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 0a3d12d7a4..ed274197c7 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -714,7 +714,7 @@ cancel = Cancel language = Language ui = Theme hidden_comment_types = Hidden comment types -hidden_comment_types_description = Comment types checked here will not be shown inside issue pages. Checking "Label" for example removes all "<user> added/removed <label>" comments. +hidden_comment_types_description = Comment types checked here will not be shown inside issue pages. Checking "Label" for example removes all "{user} added/removed {label}" comments. hidden_comment_types.ref_tooltip = Comments where this issue was referenced from another issue/commit/… hidden_comment_types.issue_ref_tooltip = Comments where the user changes the branch/tag associated with the issue comment_type_group_reference = Reference @@ -1289,7 +1289,7 @@ editor.or = or editor.cancel_lower = Cancel editor.commit_signed_changes = Commit Signed Changes editor.commit_changes = Commit Changes -editor.add_tmpl = Add '<filename>' +editor.add_tmpl = Add '{filename}' editor.add = Add %s editor.update = Update %s editor.delete = Delete %s @@ -3087,14 +3087,14 @@ auths.tips = Tips auths.tips.oauth2.general = OAuth2 Authentication auths.tips.oauth2.general.tip = When registering a new OAuth2 authentication, the callback/redirect URL should be: auths.tip.oauth2_provider = OAuth2 Provider -auths.tip.bitbucket = Register a new OAuth consumer on https://bitbucket.org/account/user/<your username>/oauth-consumers/new and add the permission 'Account' - 'Read' +auths.tip.bitbucket = Register a new OAuth consumer on https://bitbucket.org/account/user/{your-username}/oauth-consumers/new and add the permission 'Account' - 'Read' auths.tip.nextcloud = Register a new OAuth consumer on your instance using the following menu "Settings -> Security -> OAuth 2.0 client" auths.tip.dropbox = Create a new application at https://www.dropbox.com/developers/apps auths.tip.facebook = Register a new application at https://developers.facebook.com/apps and add the product "Facebook Login" auths.tip.github = Register a new OAuth application on https://github.com/settings/applications/new auths.tip.gitlab_new = Register a new application on https://gitlab.com/-/profile/applications auths.tip.google_plus = Obtain OAuth2 client credentials from the Google API console at https://console.developers.google.com/ -auths.tip.openid_connect = Use the OpenID Connect Discovery URL (<server>/.well-known/openid-configuration) to specify the endpoints +auths.tip.openid_connect = Use the OpenID Connect Discovery URL "https://{server}/.well-known/openid-configuration" to specify the endpoints auths.tip.twitter = Go to https://dev.twitter.com/apps, create an application and ensure that the “Allow this application to be used to Sign in with Twitter” option is enabled auths.tip.discord = Register a new application on https://discordapp.com/developers/applications/me auths.tip.gitea = Register a new OAuth2 application. Guide can be found at https://docs.gitea.com/development/oauth2-provider diff --git a/templates/install.tmpl b/templates/install.tmpl index 8a6956b546..f3117af547 100644 --- a/templates/install.tmpl +++ b/templates/install.tmpl @@ -174,7 +174,7 @@ <div class="inline field {{if .Err_SMTPFrom}}error{{end}}"> <label for="smtp_from">{{ctx.Locale.Tr "install.smtp_from"}}</label> <input id="smtp_from" name="smtp_from" value="{{.smtp_from}}"> - <span class="help">{{ctx.Locale.Tr "install.smtp_from_helper"}}</span> + <span class="help">{{ctx.Locale.TrString "install.smtp_from_helper"}}{{/* it contains lt/gt chars*/}}</span> </div> <div class="inline field {{if .Err_SMTPUser}}error{{end}}"> <label for="smtp_user">{{ctx.Locale.Tr "install.mailer_user"}}</label> From 02e183bf3fa502b7cef76e8dcdbf01b85ce641f0 Mon Sep 17 00:00:00 2001 From: Edward Zhang <45360012+edwardzhanged@users.noreply.github.com> Date: Wed, 17 Apr 2024 21:24:07 +0800 Subject: [PATCH 139/370] Fix branch_protection api shows users/teams who has no readAccess (#30291) Add some logic in `convert.ToBranchProtection` to return only the names associated with readAccess instead of returning all names. This will ensure consistency in behavior between the frontend and backend. Fixes: #27694 --------- Co-authored-by: techknowlogick <techknowlogick@gitea.com> Co-authored-by: wenzhuo.zhang <wenzhuo.zhang@geely.com> Co-authored-by: Giteabot <teabot@gitea.io> --- routers/api/v1/repo/branch.go | 8 ++--- services/convert/convert.go | 56 ++++++++++++++++++++++------------- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index 5e6b6a8658..baab486e52 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -437,7 +437,7 @@ func GetBranchProtection(ctx *context.APIContext) { return } - ctx.JSON(http.StatusOK, convert.ToBranchProtection(ctx, bp)) + ctx.JSON(http.StatusOK, convert.ToBranchProtection(ctx, bp, repo)) } // ListBranchProtections list branch protections for a repo @@ -470,7 +470,7 @@ func ListBranchProtections(ctx *context.APIContext) { } apiBps := make([]*api.BranchProtection, len(bps)) for i := range bps { - apiBps[i] = convert.ToBranchProtection(ctx, bps[i]) + apiBps[i] = convert.ToBranchProtection(ctx, bps[i], repo) } ctx.JSON(http.StatusOK, apiBps) @@ -681,7 +681,7 @@ func CreateBranchProtection(ctx *context.APIContext) { return } - ctx.JSON(http.StatusCreated, convert.ToBranchProtection(ctx, bp)) + ctx.JSON(http.StatusCreated, convert.ToBranchProtection(ctx, bp, repo)) } // EditBranchProtection edits a branch protection for a repo @@ -959,7 +959,7 @@ func EditBranchProtection(ctx *context.APIContext) { return } - ctx.JSON(http.StatusOK, convert.ToBranchProtection(ctx, bp)) + ctx.JSON(http.StatusOK, convert.ToBranchProtection(ctx, bp, repo)) } // DeleteBranchProtection deletes a branch protection for a repo diff --git a/services/convert/convert.go b/services/convert/convert.go index ca3ec32a40..5df0303646 100644 --- a/services/convert/convert.go +++ b/services/convert/convert.go @@ -21,6 +21,7 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" api "code.gitea.io/gitea/modules/structs" @@ -105,33 +106,46 @@ func ToBranch(ctx context.Context, repo *repo_model.Repository, branchName strin return branch, nil } +// getWhitelistEntities returns the names of the entities that are in the whitelist +func getWhitelistEntities[T *user_model.User | *organization.Team](entities []T, whitelistIDs []int64) []string { + whitelistUserIDsSet := container.SetOf(whitelistIDs...) + whitelistNames := make([]string, 0) + for _, entity := range entities { + switch v := any(entity).(type) { + case *user_model.User: + if whitelistUserIDsSet.Contains(v.ID) { + whitelistNames = append(whitelistNames, v.Name) + } + case *organization.Team: + if whitelistUserIDsSet.Contains(v.ID) { + whitelistNames = append(whitelistNames, v.Name) + } + } + } + + return whitelistNames +} + // ToBranchProtection convert a ProtectedBranch to api.BranchProtection -func ToBranchProtection(ctx context.Context, bp *git_model.ProtectedBranch) *api.BranchProtection { - pushWhitelistUsernames, err := user_model.GetUserNamesByIDs(ctx, bp.WhitelistUserIDs) +func ToBranchProtection(ctx context.Context, bp *git_model.ProtectedBranch, repo *repo_model.Repository) *api.BranchProtection { + readers, err := access_model.GetRepoReaders(ctx, repo) if err != nil { - log.Error("GetUserNamesByIDs (WhitelistUserIDs): %v", err) + log.Error("GetRepoReaders: %v", err) } - mergeWhitelistUsernames, err := user_model.GetUserNamesByIDs(ctx, bp.MergeWhitelistUserIDs) + + pushWhitelistUsernames := getWhitelistEntities(readers, bp.WhitelistUserIDs) + mergeWhitelistUsernames := getWhitelistEntities(readers, bp.MergeWhitelistUserIDs) + approvalsWhitelistUsernames := getWhitelistEntities(readers, bp.ApprovalsWhitelistUserIDs) + + teamReaders, err := organization.OrgFromUser(repo.Owner).TeamsWithAccessToRepo(ctx, repo.ID, perm.AccessModeRead) if err != nil { - log.Error("GetUserNamesByIDs (MergeWhitelistUserIDs): %v", err) - } - approvalsWhitelistUsernames, err := user_model.GetUserNamesByIDs(ctx, bp.ApprovalsWhitelistUserIDs) - if err != nil { - log.Error("GetUserNamesByIDs (ApprovalsWhitelistUserIDs): %v", err) - } - pushWhitelistTeams, err := organization.GetTeamNamesByID(ctx, bp.WhitelistTeamIDs) - if err != nil { - log.Error("GetTeamNamesByID (WhitelistTeamIDs): %v", err) - } - mergeWhitelistTeams, err := organization.GetTeamNamesByID(ctx, bp.MergeWhitelistTeamIDs) - if err != nil { - log.Error("GetTeamNamesByID (MergeWhitelistTeamIDs): %v", err) - } - approvalsWhitelistTeams, err := organization.GetTeamNamesByID(ctx, bp.ApprovalsWhitelistTeamIDs) - if err != nil { - log.Error("GetTeamNamesByID (ApprovalsWhitelistTeamIDs): %v", err) + log.Error("Repo.Owner.TeamsWithAccessToRepo: %v", err) } + pushWhitelistTeams := getWhitelistEntities(teamReaders, bp.WhitelistTeamIDs) + mergeWhitelistTeams := getWhitelistEntities(teamReaders, bp.MergeWhitelistTeamIDs) + approvalsWhitelistTeams := getWhitelistEntities(teamReaders, bp.ApprovalsWhitelistTeamIDs) + branchName := "" if !git_model.IsRuleNameSpecial(bp.RuleName) { branchName = bp.RuleName From bafb80f80d5505b03e5994d1ea6e2dab10052fe1 Mon Sep 17 00:00:00 2001 From: Michael Kriese <michael.kriese@visualon.de> Date: Wed, 17 Apr 2024 17:30:41 +0200 Subject: [PATCH 140/370] Support nuspec manifest download for nuget packages (#28921) Support downloading nuget nuspec manifest[^1]. This is useful for renovate because it uses this api to find the corresponding repository - Store nuspec along with nupkg on upload - allow downloading nuspec - add doctor command to add missing nuspec files [^1]: https://learn.microsoft.com/en-us/nuget/api/package-base-address-resource#download-package-manifest-nuspec --------- Co-authored-by: KN4CK3R <admin@oldschoolhack.me> --- modules/packages/nuget/metadata.go | 21 +++--- routers/api/packages/nuget/nuget.go | 32 +++++++- tests/integration/api_packages_nuget_test.go | 77 ++++++++++++++------ 3 files changed, 95 insertions(+), 35 deletions(-) diff --git a/modules/packages/nuget/metadata.go b/modules/packages/nuget/metadata.go index 6769c514cc..1e98ddffde 100644 --- a/modules/packages/nuget/metadata.go +++ b/modules/packages/nuget/metadata.go @@ -48,10 +48,11 @@ const maxNuspecFileSize = 3 * 1024 * 1024 // Package represents a Nuget package type Package struct { - PackageType PackageType - ID string - Version string - Metadata *Metadata + PackageType PackageType + ID string + Version string + Metadata *Metadata + NuspecContent *bytes.Buffer } // Metadata represents the metadata of a Nuget package @@ -138,8 +139,9 @@ func ParsePackageMetaData(r io.ReaderAt, size int64) (*Package, error) { // ParseNuspecMetaData parses a Nuspec file to retrieve the metadata of a Nuget package func ParseNuspecMetaData(archive *zip.Reader, r io.Reader) (*Package, error) { + var nuspecBuf bytes.Buffer var p nuspecPackage - if err := xml.NewDecoder(r).Decode(&p); err != nil { + if err := xml.NewDecoder(io.TeeReader(r, &nuspecBuf)).Decode(&p); err != nil { return nil, err } @@ -212,10 +214,11 @@ func ParseNuspecMetaData(archive *zip.Reader, r io.Reader) (*Package, error) { } } return &Package{ - PackageType: packageType, - ID: p.Metadata.ID, - Version: toNormalizedVersion(v), - Metadata: m, + PackageType: packageType, + ID: p.Metadata.ID, + Version: toNormalizedVersion(v), + Metadata: m, + NuspecContent: &nuspecBuf, }, nil } diff --git a/routers/api/packages/nuget/nuget.go b/routers/api/packages/nuget/nuget.go index c28bc6c9d9..09156ece6b 100644 --- a/routers/api/packages/nuget/nuget.go +++ b/routers/api/packages/nuget/nuget.go @@ -388,7 +388,8 @@ func EnumeratePackageVersionsV3(ctx *context.Context) { ctx.JSON(http.StatusOK, resp) } -// https://docs.microsoft.com/en-us/nuget/api/package-base-address-resource#download-package-content-nupkg +// https://learn.microsoft.com/en-us/nuget/api/package-base-address-resource#download-package-manifest-nuspec +// https://learn.microsoft.com/en-us/nuget/api/package-base-address-resource#download-package-content-nupkg func DownloadPackageFile(ctx *context.Context) { packageName := ctx.Params("id") packageVersion := ctx.Params("version") @@ -431,7 +432,7 @@ func UploadPackage(ctx *context.Context) { return } - _, _, err := packages_service.CreatePackageAndAddFile( + pv, _, err := packages_service.CreatePackageAndAddFile( ctx, &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ @@ -465,6 +466,33 @@ func UploadPackage(ctx *context.Context) { return } + nuspecBuf, err := packages_module.CreateHashedBufferFromReaderWithSize(np.NuspecContent, np.NuspecContent.Len()) + if err != nil { + apiError(ctx, http.StatusInternalServerError, err) + return + } + defer nuspecBuf.Close() + + _, err = packages_service.AddFileToPackageVersionInternal( + ctx, + pv, + &packages_service.PackageFileCreationInfo{ + PackageFileInfo: packages_service.PackageFileInfo{ + Filename: strings.ToLower(fmt.Sprintf("%s.nuspec", np.ID)), + }, + Data: nuspecBuf, + }, + ) + if err != nil { + switch err { + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) + } + return + } + ctx.Status(http.StatusCreated) } diff --git a/tests/integration/api_packages_nuget_test.go b/tests/integration/api_packages_nuget_test.go index 20dafd5cc7..83947ff967 100644 --- a/tests/integration/api_packages_nuget_test.go +++ b/tests/integration/api_packages_nuget_test.go @@ -90,29 +90,33 @@ func TestPackageNuGet(t *testing.T) { symbolFilename := "test.pdb" symbolID := "d910bb6948bd4c6cb40155bcf52c3c94" - createPackage := func(id, version string) io.Reader { + createNuspec := func(id, version string) string { + return `<?xml version="1.0" encoding="utf-8"?> +<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd"> + <metadata> + <id>` + id + `</id> + <version>` + version + `</version> + <authors>` + packageAuthors + `</authors> + <description>` + packageDescription + `</description> + <dependencies> + <group targetFramework=".NETStandard2.0"> + <dependency id="Microsoft.CSharp" version="4.5.0" /> + </group> + </dependencies> + </metadata> +</package>` + } + + createPackage := func(id, version string) *bytes.Buffer { var buf bytes.Buffer archive := zip.NewWriter(&buf) w, _ := archive.Create("package.nuspec") - w.Write([]byte(`<?xml version="1.0" encoding="utf-8"?> - <package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd"> - <metadata> - <id>` + id + `</id> - <version>` + version + `</version> - <authors>` + packageAuthors + `</authors> - <description>` + packageDescription + `</description> - <dependencies> - <group targetFramework=".NETStandard2.0"> - <dependency id="Microsoft.CSharp" version="4.5.0" /> - </group> - </dependencies> - </metadata> - </package>`)) + w.Write([]byte(createNuspec(id, version))) archive.Close() return &buf } - content, _ := io.ReadAll(createPackage(packageName, packageVersion)) + content := createPackage(packageName, packageVersion).Bytes() url := fmt.Sprintf("/api/packages/%s/nuget", user.Name) @@ -224,7 +228,7 @@ func TestPackageNuGet(t *testing.T) { pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNuGet) assert.NoError(t, err) - assert.Len(t, pvs, 1) + assert.Len(t, pvs, 1, "Should have one version") pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0]) assert.NoError(t, err) @@ -235,13 +239,21 @@ func TestPackageNuGet(t *testing.T) { pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID) assert.NoError(t, err) - assert.Len(t, pfs, 1) - assert.Equal(t, fmt.Sprintf("%s.%s.nupkg", packageName, packageVersion), pfs[0].Name) - assert.True(t, pfs[0].IsLead) + assert.Len(t, pfs, 2, "Should have 2 files: nuget and nuspec") + for _, pf := range pfs { + switch pf.Name { + case fmt.Sprintf("%s.%s.nupkg", packageName, packageVersion): + assert.True(t, pf.IsLead) - pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID) - assert.NoError(t, err) - assert.Equal(t, int64(len(content)), pb.Size) + pb, err := packages.GetBlobByID(db.DefaultContext, pf.BlobID) + assert.NoError(t, err) + assert.Equal(t, int64(len(content)), pb.Size) + case fmt.Sprintf("%s.nuspec", packageName): + assert.False(t, pf.IsLead) + default: + assert.Fail(t, "unexpected filename: %v", pf.Name) + } + } req = NewRequestWithBody(t, "PUT", url, bytes.NewReader(content)). AddBasicAuth(user.Name) @@ -302,16 +314,27 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`) pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID) assert.NoError(t, err) - assert.Len(t, pfs, 3) + assert.Len(t, pfs, 4, "Should have 4 files: nupkg, snupkg, nuspec and pdb") for _, pf := range pfs { switch pf.Name { case fmt.Sprintf("%s.%s.nupkg", packageName, packageVersion): + assert.True(t, pf.IsLead) + + pb, err := packages.GetBlobByID(db.DefaultContext, pf.BlobID) + assert.NoError(t, err) + assert.Equal(t, int64(412), pb.Size) case fmt.Sprintf("%s.%s.snupkg", packageName, packageVersion): assert.False(t, pf.IsLead) pb, err := packages.GetBlobByID(db.DefaultContext, pf.BlobID) assert.NoError(t, err) assert.Equal(t, int64(616), pb.Size) + case fmt.Sprintf("%s.nuspec", packageName): + assert.False(t, pf.IsLead) + + pb, err := packages.GetBlobByID(db.DefaultContext, pf.BlobID) + assert.NoError(t, err) + assert.Equal(t, int64(427), pb.Size) case symbolFilename: assert.False(t, pf.IsLead) @@ -353,6 +376,12 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`) assert.Equal(t, content, resp.Body.Bytes()) + req = NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s.nuspec", url, packageName, packageVersion, packageName)). + AddBasicAuth(user.Name) + resp = MakeRequest(t, req, http.StatusOK) + + assert.Equal(t, createNuspec(packageName, packageVersion), resp.Body.String()) + checkDownloadCount(1) req = NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s.%s.snupkg", url, packageName, packageVersion, packageName, packageVersion)). From 3feba9f1f44156c256a30d25ad1c25f751819c94 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Wed, 17 Apr 2024 23:58:37 +0800 Subject: [PATCH 141/370] Allow everyone to read or write a wiki by a repo unit setting (#30495) Replace #6312 Help #5833 Wiki solution for #639 --- models/issues/pull_list.go | 6 +- models/migrations/migrations.go | 2 + models/migrations/v1_11/v111.go | 2 +- models/migrations/v1_23/v297.go | 17 +++ models/organization/team.go | 4 +- models/perm/access/access.go | 8 +- models/perm/access/repo_permission.go | 145 ++++++++++++--------- models/perm/access/repo_permission_test.go | 98 ++++++++++++++ models/perm/access_mode.go | 39 +++--- models/perm/access_mode_test.go | 22 ++++ models/repo/repo_unit.go | 12 +- models/unit/unit.go | 11 +- modules/templates/helper.go | 12 ++ options/locale/locale_en-US.ini | 2 + routers/api/v1/api.go | 6 +- routers/private/hook_pre_receive.go | 6 +- routers/web/repo/setting/setting.go | 8 +- routers/web/repo/view.go | 3 +- services/convert/convert.go | 2 +- services/convert/repository.go | 11 +- services/convert/user.go | 4 +- services/forms/repo_form.go | 1 + templates/repo/settings/options.tmpl | 28 +++- tests/integration/api_team_test.go | 4 +- 24 files changed, 322 insertions(+), 131 deletions(-) create mode 100644 models/migrations/v1_23/v297.go create mode 100644 models/perm/access/repo_permission_test.go create mode 100644 models/perm/access_mode_test.go diff --git a/models/issues/pull_list.go b/models/issues/pull_list.go index de3eceed37..b5557cad06 100644 --- a/models/issues/pull_list.go +++ b/models/issues/pull_list.go @@ -62,11 +62,13 @@ func CanMaintainerWriteToBranch(ctx context.Context, p access_model.Permission, return true } - if len(p.Units) < 1 { + // the code below depends on units to get the repository ID, not ideal but just keep it for now + firstUnitRepoID := p.GetFirstUnitRepoID() + if firstUnitRepoID == 0 { return false } - prs, err := GetUnmergedPullRequestsByHeadInfo(ctx, p.Units[0].RepoID, branch) + prs, err := GetUnmergedPullRequestsByHeadInfo(ctx, firstUnitRepoID, branch) if err != nil { return false } diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 5326d48f90..cb3a64f48c 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -582,6 +582,8 @@ var migrations = []Migration{ NewMigration("Add commit status summary table", v1_23.AddCommitStatusSummary), // v296 -> v297 NewMigration("Add missing field of commit status summary table", v1_23.AddCommitStatusSummary2), + // v297 -> v298 + NewMigration("Add everyone_access_mode for repo_unit", v1_23.AddRepoUnitEveryoneAccessMode), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v1_11/v111.go b/models/migrations/v1_11/v111.go index d757acb7d2..1722792a38 100644 --- a/models/migrations/v1_11/v111.go +++ b/models/migrations/v1_11/v111.go @@ -336,7 +336,7 @@ func AddBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error { if err != nil { return false, err } - if perm.UnitsMode == nil { + if len(perm.UnitsMode) == 0 { for _, u := range perm.Units { if u.Type == UnitTypeCode { return AccessModeWrite <= perm.AccessMode, nil diff --git a/models/migrations/v1_23/v297.go b/models/migrations/v1_23/v297.go new file mode 100644 index 0000000000..e79f04cf9c --- /dev/null +++ b/models/migrations/v1_23/v297.go @@ -0,0 +1,17 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_23 //nolint + +import ( + "code.gitea.io/gitea/models/perm" + + "xorm.io/xorm" +) + +func AddRepoUnitEveryoneAccessMode(x *xorm.Engine) error { + type RepoUnit struct { //revive:disable-line:exported + EveryoneAccessMode perm.AccessMode `xorm:"NOT NULL DEFAULT 0"` + } + return x.Sync(&RepoUnit{}) +} diff --git a/models/organization/team.go b/models/organization/team.go index 501a43d3a1..e4e83fedee 100644 --- a/models/organization/team.go +++ b/models/organization/team.go @@ -130,11 +130,11 @@ func (t *Team) GetUnitsMap() map[string]string { m := make(map[string]string) if t.AccessMode >= perm.AccessModeAdmin { for _, u := range unit.Units { - m[u.NameKey] = t.AccessMode.String() + m[u.NameKey] = t.AccessMode.ToString() } } else { for _, u := range t.Units { - m[u.Unit().NameKey] = u.AccessMode.String() + m[u.Unit().NameKey] = u.AccessMode.ToString() } } return m diff --git a/models/perm/access/access.go b/models/perm/access/access.go index b422a08614..6a0a901f71 100644 --- a/models/perm/access/access.go +++ b/models/perm/access/access.go @@ -63,13 +63,11 @@ func accessLevel(ctx context.Context, user *user_model.User, repo *repo_model.Re } func maxAccessMode(modes ...perm.AccessMode) perm.AccessMode { - max := perm.AccessModeNone + maxMode := perm.AccessModeNone for _, mode := range modes { - if mode > max { - max = mode - } + maxMode = max(maxMode, mode) } - return max + return maxMode } type userAccess struct { diff --git a/models/perm/access/repo_permission.go b/models/perm/access/repo_permission.go index e4e7579e62..9cce95b776 100644 --- a/models/perm/access/repo_permission.go +++ b/models/perm/access/repo_permission.go @@ -6,6 +6,7 @@ package access import ( "context" "fmt" + "slices" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" @@ -14,13 +15,15 @@ import ( "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/util" ) // Permission contains all the permissions related variables to a repository for a user type Permission struct { AccessMode perm_model.AccessMode - Units []*repo_model.RepoUnit - UnitsMode map[unit.Type]perm_model.AccessMode + + units []*repo_model.RepoUnit + unitsMode map[unit.Type]perm_model.AccessMode } // IsOwner returns true if current user is the owner of repository. @@ -33,25 +36,44 @@ func (p *Permission) IsAdmin() bool { return p.AccessMode >= perm_model.AccessModeAdmin } -// HasAccess returns true if the current user has at least read access to any unit of this repository +// HasAccess returns true if the current user might have at least read access to any unit of this repository func (p *Permission) HasAccess() bool { - if p.UnitsMode == nil { - return p.AccessMode >= perm_model.AccessModeRead - } - return len(p.UnitsMode) > 0 + return len(p.unitsMode) > 0 || p.AccessMode >= perm_model.AccessModeRead } -// UnitAccessMode returns current user accessmode to the specify unit of the repository -func (p *Permission) UnitAccessMode(unitType unit.Type) perm_model.AccessMode { - if p.UnitsMode == nil { - for _, u := range p.Units { - if u.Type == unitType { - return p.AccessMode - } - } - return perm_model.AccessModeNone +// HasUnits returns true if the permission contains attached units +func (p *Permission) HasUnits() bool { + return len(p.units) > 0 +} + +// GetFirstUnitRepoID returns the repo ID of the first unit, it is a fragile design and should NOT be used anymore +// deprecated +func (p *Permission) GetFirstUnitRepoID() int64 { + if len(p.units) > 0 { + return p.units[0].RepoID + } + return 0 +} + +// UnitAccessMode returns current user access mode to the specify unit of the repository +func (p *Permission) UnitAccessMode(unitType unit.Type) perm_model.AccessMode { + if p.unitsMode != nil { + // if the units map contains the access mode, use it, but admin/owner mode could override it + if m, ok := p.unitsMode[unitType]; ok { + return util.Iif(p.AccessMode >= perm_model.AccessModeAdmin, p.AccessMode, m) + } + } + // if the units map does not contain the access mode, return the default access mode if the unit exists + hasUnit := slices.ContainsFunc(p.units, func(u *repo_model.RepoUnit) bool { return u.Type == unitType }) + return util.Iif(hasUnit, p.AccessMode, perm_model.AccessModeNone) +} + +func (p *Permission) SetUnitsWithDefaultAccessMode(units []*repo_model.RepoUnit, mode perm_model.AccessMode) { + p.units = units + p.unitsMode = make(map[unit.Type]perm_model.AccessMode) + for _, u := range p.units { + p.unitsMode[u.Type] = mode } - return p.UnitsMode[unitType] } // CanAccess returns true if user has mode access to the unit of the repository @@ -103,8 +125,8 @@ func (p *Permission) CanWriteIssuesOrPulls(isPull bool) bool { } func (p *Permission) ReadableUnitTypes() []unit.Type { - types := make([]unit.Type, 0, len(p.Units)) - for _, u := range p.Units { + types := make([]unit.Type, 0, len(p.units)) + for _, u := range p.units { if p.CanRead(u.Type) { types = append(types, u.Type) } @@ -114,21 +136,21 @@ func (p *Permission) ReadableUnitTypes() []unit.Type { func (p *Permission) LogString() string { format := "<Permission AccessMode=%s, %d Units, %d UnitsMode(s): [ " - args := []any{p.AccessMode.String(), len(p.Units), len(p.UnitsMode)} + args := []any{p.AccessMode.ToString(), len(p.units), len(p.unitsMode)} - for i, unit := range p.Units { + for i, u := range p.units { config := "" - if unit.Config != nil { - configBytes, err := unit.Config.ToDB() + if u.Config != nil { + configBytes, err := u.Config.ToDB() config = string(configBytes) if err != nil { config = err.Error() } } format += "\nUnits[%d]: ID: %d RepoID: %d Type: %s Config: %s" - args = append(args, i, unit.ID, unit.RepoID, unit.Type.LogString(), config) + args = append(args, i, u.ID, u.RepoID, u.Type.LogString(), config) } - for key, value := range p.UnitsMode { + for key, value := range p.unitsMode { format += "\nUnitMode[%-v]: %-v" args = append(args, key.LogString(), value.LogString()) } @@ -136,23 +158,34 @@ func (p *Permission) LogString() string { return fmt.Sprintf(format, args...) } -// GetUserRepoPermission returns the user permissions to the repository -func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, user *user_model.User) (Permission, error) { - var perm Permission - if log.IsTrace() { - defer func() { - if user == nil { - log.Trace("Permission Loaded for anonymous user in %-v:\nPermissions: %-+v", - repo, - perm) - return +func applyEveryoneRepoPermission(user *user_model.User, perm *Permission) { + if user != nil && user.ID > 0 { + for _, u := range perm.units { + if perm.unitsMode == nil { + perm.unitsMode = make(map[unit.Type]perm_model.AccessMode) } - log.Trace("Permission Loaded for %-v in %-v:\nPermissions: %-+v", - user, - repo, - perm) - }() + if u.EveryoneAccessMode >= perm_model.AccessModeRead && u.EveryoneAccessMode > perm.unitsMode[u.Type] { + perm.unitsMode[u.Type] = u.EveryoneAccessMode + } + } } +} + +// GetUserRepoPermission returns the user permissions to the repository +func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, user *user_model.User) (perm Permission, err error) { + defer func() { + if err == nil { + applyEveryoneRepoPermission(user, &perm) + } + if log.IsTrace() { + log.Trace("Permission Loaded for user %-v in repo %-v, permissions: %-+v", user, repo, perm) + } + }() + + if err = repo.LoadUnits(ctx); err != nil { + return perm, err + } + perm.units = repo.Units // anonymous user visit private repo. // TODO: anonymous user visit public unit of private repo??? @@ -162,7 +195,6 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use } var isCollaborator bool - var err error if user != nil { isCollaborator, err = repo_model.IsCollaborator(ctx, repo.ID, user.ID) if err != nil { @@ -170,7 +202,7 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use } } - if err := repo.LoadOwner(ctx); err != nil { + if err = repo.LoadOwner(ctx); err != nil { return perm, err } @@ -181,12 +213,6 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use return perm, nil } - if err := repo.LoadUnits(ctx); err != nil { - return perm, err - } - - perm.Units = repo.Units - // anonymous visit public repo if user == nil { perm.AccessMode = perm_model.AccessModeRead @@ -205,19 +231,16 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use return perm, err } - if err := repo.LoadOwner(ctx); err != nil { - return perm, err - } if !repo.Owner.IsOrganization() { return perm, nil } - perm.UnitsMode = make(map[unit.Type]perm_model.AccessMode) + perm.unitsMode = make(map[unit.Type]perm_model.AccessMode) // Collaborators on organization if isCollaborator { for _, u := range repo.Units { - perm.UnitsMode[u.Type] = perm.AccessMode + perm.unitsMode[u.Type] = perm.AccessMode } } @@ -231,7 +254,7 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use for _, team := range teams { if team.AccessMode >= perm_model.AccessModeAdmin { perm.AccessMode = perm_model.AccessModeOwner - perm.UnitsMode = nil + perm.unitsMode = nil return perm, nil } } @@ -240,25 +263,25 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use var found bool for _, team := range teams { if teamMode, exist := team.UnitAccessModeEx(ctx, u.Type); exist { - perm.UnitsMode[u.Type] = max(perm.UnitsMode[u.Type], teamMode) + perm.unitsMode[u.Type] = max(perm.unitsMode[u.Type], teamMode) found = true } } // for a public repo on an organization, a non-restricted user has read permission on non-team defined units. if !found && !repo.IsPrivate && !user.IsRestricted { - if _, ok := perm.UnitsMode[u.Type]; !ok { - perm.UnitsMode[u.Type] = perm_model.AccessModeRead + if _, ok := perm.unitsMode[u.Type]; !ok { + perm.unitsMode[u.Type] = perm_model.AccessModeRead } } } // remove no permission units - perm.Units = make([]*repo_model.RepoUnit, 0, len(repo.Units)) - for t := range perm.UnitsMode { + perm.units = make([]*repo_model.RepoUnit, 0, len(repo.Units)) + for t := range perm.unitsMode { for _, u := range repo.Units { if u.Type == t { - perm.Units = append(perm.Units, u) + perm.units = append(perm.units, u) } } } @@ -340,7 +363,7 @@ func HasAccessUnit(ctx context.Context, user *user_model.User, repo *repo_model. // Currently any write access (code, issues or pr's) is assignable, to match assignee list in user interface. func CanBeAssigned(ctx context.Context, user *user_model.User, repo *repo_model.Repository, _ bool) (bool, error) { if user.IsOrganization() { - return false, fmt.Errorf("Organization can't be added as assignee [user_id: %d, repo_id: %d]", user.ID, repo.ID) + return false, fmt.Errorf("organization can't be added as assignee [user_id: %d, repo_id: %d]", user.ID, repo.ID) } perm, err := GetUserRepoPermission(ctx, repo, user) if err != nil { diff --git a/models/perm/access/repo_permission_test.go b/models/perm/access/repo_permission_test.go new file mode 100644 index 0000000000..aaa53bb24f --- /dev/null +++ b/models/perm/access/repo_permission_test.go @@ -0,0 +1,98 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package access + +import ( + "testing" + + perm_model "code.gitea.io/gitea/models/perm" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unit" + user_model "code.gitea.io/gitea/models/user" + + "github.com/stretchr/testify/assert" +) + +func TestApplyEveryoneRepoPermission(t *testing.T) { + perm := Permission{ + AccessMode: perm_model.AccessModeNone, + units: []*repo_model.RepoUnit{ + {Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeNone}, + }, + } + applyEveryoneRepoPermission(nil, &perm) + assert.False(t, perm.CanRead(unit.TypeWiki)) + + perm = Permission{ + AccessMode: perm_model.AccessModeNone, + units: []*repo_model.RepoUnit{ + {Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead}, + }, + } + applyEveryoneRepoPermission(&user_model.User{ID: 1}, &perm) + assert.True(t, perm.CanRead(unit.TypeWiki)) + + perm = Permission{ + AccessMode: perm_model.AccessModeWrite, + units: []*repo_model.RepoUnit{ + {Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead}, + }, + } + applyEveryoneRepoPermission(&user_model.User{ID: 1}, &perm) + assert.True(t, perm.CanRead(unit.TypeWiki)) + assert.False(t, perm.CanWrite(unit.TypeWiki)) // because there is no unit mode, so the everyone-mode is used as the unit's access mode + + perm = Permission{ + units: []*repo_model.RepoUnit{ + {Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead}, + }, + unitsMode: map[unit.Type]perm_model.AccessMode{ + unit.TypeWiki: perm_model.AccessModeWrite, + }, + } + applyEveryoneRepoPermission(&user_model.User{ID: 1}, &perm) + assert.True(t, perm.CanWrite(unit.TypeWiki)) +} + +func TestUnitAccessMode(t *testing.T) { + perm := Permission{ + AccessMode: perm_model.AccessModeNone, + } + assert.Equal(t, perm_model.AccessModeNone, perm.UnitAccessMode(unit.TypeWiki), "no unit, no map, use AccessMode") + + perm = Permission{ + AccessMode: perm_model.AccessModeRead, + units: []*repo_model.RepoUnit{ + {Type: unit.TypeWiki}, + }, + } + assert.Equal(t, perm_model.AccessModeRead, perm.UnitAccessMode(unit.TypeWiki), "only unit, no map, use AccessMode") + + perm = Permission{ + AccessMode: perm_model.AccessModeAdmin, + unitsMode: map[unit.Type]perm_model.AccessMode{ + unit.TypeWiki: perm_model.AccessModeRead, + }, + } + assert.Equal(t, perm_model.AccessModeAdmin, perm.UnitAccessMode(unit.TypeWiki), "no unit, only map, admin overrides map") + + perm = Permission{ + AccessMode: perm_model.AccessModeNone, + unitsMode: map[unit.Type]perm_model.AccessMode{ + unit.TypeWiki: perm_model.AccessModeRead, + }, + } + assert.Equal(t, perm_model.AccessModeRead, perm.UnitAccessMode(unit.TypeWiki), "no unit, only map, use map") + + perm = Permission{ + AccessMode: perm_model.AccessModeNone, + units: []*repo_model.RepoUnit{ + {Type: unit.TypeWiki}, + }, + unitsMode: map[unit.Type]perm_model.AccessMode{ + unit.TypeWiki: perm_model.AccessModeRead, + }, + } + assert.Equal(t, perm_model.AccessModeRead, perm.UnitAccessMode(unit.TypeWiki), "has unit, and map, use map") +} diff --git a/models/perm/access_mode.go b/models/perm/access_mode.go index a37bc1f0e1..0364191e2e 100644 --- a/models/perm/access_mode.go +++ b/models/perm/access_mode.go @@ -5,25 +5,25 @@ package perm import ( "fmt" + "slices" + + "code.gitea.io/gitea/modules/util" ) // AccessMode specifies the users access mode type AccessMode int const ( - // AccessModeNone no access - AccessModeNone AccessMode = iota // 0 - // AccessModeRead read access - AccessModeRead // 1 - // AccessModeWrite write access - AccessModeWrite // 2 - // AccessModeAdmin admin access - AccessModeAdmin // 3 - // AccessModeOwner owner access - AccessModeOwner // 4 + AccessModeNone AccessMode = iota // 0: no access + + AccessModeRead // 1: read access + AccessModeWrite // 2: write access + AccessModeAdmin // 3: admin access + AccessModeOwner // 4: owner access ) -func (mode AccessMode) String() string { +// ToString returns the string representation of the access mode, do not make it a Stringer, otherwise it's difficult to render in templates +func (mode AccessMode) ToString() string { switch mode { case AccessModeRead: return "read" @@ -39,19 +39,24 @@ func (mode AccessMode) String() string { } func (mode AccessMode) LogString() string { - return fmt.Sprintf("<AccessMode:%d:%s>", mode, mode.String()) + return fmt.Sprintf("<AccessMode:%d:%s>", mode, mode.ToString()) } // ParseAccessMode returns corresponding access mode to given permission string. -func ParseAccessMode(permission string) AccessMode { +func ParseAccessMode(permission string, allowed ...AccessMode) AccessMode { + m := AccessModeNone switch permission { case "read": - return AccessModeRead + m = AccessModeRead case "write": - return AccessModeWrite + m = AccessModeWrite case "admin": - return AccessModeAdmin + m = AccessModeAdmin default: - return AccessModeNone + // the "owner" access is not really used for user input, it's mainly for checking access level in code, so don't parse it } + if len(allowed) == 0 { + return m + } + return util.Iif(slices.Contains(allowed, m), m, AccessModeNone) } diff --git a/models/perm/access_mode_test.go b/models/perm/access_mode_test.go new file mode 100644 index 0000000000..982fceee5a --- /dev/null +++ b/models/perm/access_mode_test.go @@ -0,0 +1,22 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package perm + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAccessMode(t *testing.T) { + names := []string{"none", "read", "write", "admin"} + for i, name := range names { + m := ParseAccessMode(name) + assert.Equal(t, AccessMode(i), m) + } + assert.Equal(t, AccessMode(4), AccessModeOwner) + assert.Equal(t, "owner", AccessModeOwner.ToString()) + assert.Equal(t, AccessModeNone, ParseAccessMode("owner")) + assert.Equal(t, AccessModeNone, ParseAccessMode("invalid")) +} diff --git a/models/repo/repo_unit.go b/models/repo/repo_unit.go index 5a841f4d31..fd5baa9488 100644 --- a/models/repo/repo_unit.go +++ b/models/repo/repo_unit.go @@ -10,6 +10,7 @@ import ( "strings" "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/setting" @@ -41,11 +42,12 @@ func (err ErrUnitTypeNotExist) Unwrap() error { // RepoUnit describes all units of a repository type RepoUnit struct { //revive:disable-line:exported - ID int64 - RepoID int64 `xorm:"INDEX(s)"` - Type unit.Type `xorm:"INDEX(s)"` - Config convert.Conversion `xorm:"TEXT"` - CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"` + ID int64 + RepoID int64 `xorm:"INDEX(s)"` + Type unit.Type `xorm:"INDEX(s)"` + Config convert.Conversion `xorm:"TEXT"` + CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"` + EveryoneAccessMode perm.AccessMode `xorm:"NOT NULL DEFAULT 0"` } func init() { diff --git a/models/unit/unit.go b/models/unit/unit.go index b216712d37..a78a2f1e47 100644 --- a/models/unit/unit.go +++ b/models/unit/unit.go @@ -191,16 +191,13 @@ type Unit struct { NameKey string URI string DescKey string - Idx int + Priority int MaxAccessMode perm.AccessMode // The max access mode of the unit. i.e. Read means this unit can only be read. } // IsLessThan compares order of two units func (u Unit) IsLessThan(unit Unit) bool { - if (u.Type == TypeExternalTracker || u.Type == TypeExternalWiki) && unit.Type != TypeExternalTracker && unit.Type != TypeExternalWiki { - return false - } - return u.Idx < unit.Idx + return u.Priority < unit.Priority } // MaxPerm returns the max perms of this unit @@ -236,7 +233,7 @@ var ( "repo.ext_issues", "/issues", "repo.ext_issues.desc", - 1, + 101, perm.AccessModeRead, } @@ -272,7 +269,7 @@ var ( "repo.ext_wiki", "/wiki", "repo.ext_wiki.desc", - 4, + 102, perm.AccessModeRead, } diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 5d2fa79bc5..360b48c594 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -34,6 +34,7 @@ func NewFuncMap() template.FuncMap { // ----------------------------------------------------------------- // html/template related functions "dict": dict, // it's lowercase because this name has been widely used. Our other functions should have uppercase names. + "Iif": Iif, "Eval": Eval, "SafeHTML": SafeHTML, "HTMLFormat": HTMLFormat, @@ -238,6 +239,17 @@ func DotEscape(raw string) string { return strings.ReplaceAll(raw, ".", "\u200d.\u200d") } +// Iif is an "inline-if", similar util.Iif[T] but templates need the non-generic version, +// and it could be simply used as "{{Iif expr trueVal}}" (omit the falseVal). +func Iif(condition bool, vals ...any) any { + if condition { + return vals[0] + } else if len(vals) > 1 { + return vals[1] + } + return nil +} + // Eval the expression and return the result, see the comment of eval.Expr for details. // To use this helper function in templates, pass each token as a separate parameter. // diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index ed274197c7..a7c1d91791 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -885,6 +885,7 @@ repo_and_org_access = Repository and Organization Access permissions_public_only = Public only permissions_access_all = All (public, private, and limited) select_permissions = Select permissions +permission_not_set = Not set permission_no_access = No Access permission_read = Read permission_write = Read and Write @@ -2096,6 +2097,7 @@ settings.advanced_settings = Advanced Settings settings.wiki_desc = Enable Repository Wiki settings.use_internal_wiki = Use Built-In Wiki settings.default_wiki_branch_name = Default Wiki Branch Name +settings.default_wiki_everyone_access = Default Access Permission for signed-in users: settings.failed_to_change_default_wiki_branch = Failed to change the default wiki branch. settings.use_external_wiki = Use External Wiki settings.external_wiki_url = External Wiki URL diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 1fc7682966..f60c5f21db 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -209,11 +209,7 @@ func repoAssignment() func(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "LoadUnits", err) return } - ctx.Repo.Permission.Units = ctx.Repo.Repository.Units - ctx.Repo.Permission.UnitsMode = make(map[unit.Type]perm.AccessMode) - for _, u := range ctx.Repo.Repository.Units { - ctx.Repo.Permission.UnitsMode[u.Type] = ctx.Repo.Permission.AccessMode - } + ctx.Repo.Permission.SetUnitsWithDefaultAccessMode(ctx.Repo.Repository.Units, ctx.Repo.Permission.AccessMode) } else { ctx.Repo.Permission, err = access_model.GetUserRepoPermission(ctx, repo, ctx.Doer) if err != nil { diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go index 32ec3003e2..4e59237ed3 100644 --- a/routers/private/hook_pre_receive.go +++ b/routers/private/hook_pre_receive.go @@ -481,11 +481,7 @@ func (ctx *preReceiveContext) loadPusherAndPermission() bool { }) return false } - ctx.userPerm.Units = ctx.Repo.Repository.Units - ctx.userPerm.UnitsMode = make(map[unit.Type]perm_model.AccessMode) - for _, u := range ctx.Repo.Repository.Units { - ctx.userPerm.UnitsMode[u.Type] = ctx.userPerm.AccessMode - } + ctx.userPerm.SetUnitsWithDefaultAccessMode(ctx.Repo.Repository.Units, ctx.userPerm.AccessMode) } else { user, err := user_model.GetUserByID(ctx, ctx.opts.UserID) if err != nil { diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go index 00a5282f34..b55e259e4b 100644 --- a/routers/web/repo/setting/setting.go +++ b/routers/web/repo/setting/setting.go @@ -16,6 +16,7 @@ import ( actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" + "code.gitea.io/gitea/models/perm" repo_model "code.gitea.io/gitea/models/repo" unit_model "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" @@ -476,9 +477,10 @@ func SettingsPost(ctx *context.Context) { deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeWiki) } else if form.EnableWiki && !form.EnableExternalWiki && !unit_model.TypeWiki.UnitGlobalDisabled() { units = append(units, repo_model.RepoUnit{ - RepoID: repo.ID, - Type: unit_model.TypeWiki, - Config: new(repo_model.UnitConfig), + RepoID: repo.ID, + Type: unit_model.TypeWiki, + Config: new(repo_model.UnitConfig), + EveryoneAccessMode: perm.ParseAccessMode(form.DefaultWikiEveryoneAccess, perm.AccessModeNone, perm.AccessModeRead, perm.AccessModeWrite), }) deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalWiki) } else { diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index de35c6b3a2..9c1f4faa5f 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -684,7 +684,7 @@ func markupRender(ctx *context.Context, renderCtx *markup.RenderContext, input i } func checkHomeCodeViewable(ctx *context.Context) { - if len(ctx.Repo.Units) > 0 { + if ctx.Repo.HasUnits() { if ctx.Repo.Repository.IsBeingCreated() { task, err := admin_model.GetMigratingTask(ctx, ctx.Repo.Repository.ID) if err != nil { @@ -723,6 +723,7 @@ func checkHomeCodeViewable(ctx *context.Context) { var firstUnit *unit_model.Unit for _, repoUnitType := range ctx.Repo.Permission.ReadableUnitTypes() { if repoUnitType == unit_model.TypeCode { + // we are doing this check in "code" unit related pages, so if the code unit is readable, no need to do any further redirection return } diff --git a/services/convert/convert.go b/services/convert/convert.go index 5df0303646..3b6139d2fe 100644 --- a/services/convert/convert.go +++ b/services/convert/convert.go @@ -336,7 +336,7 @@ func ToTeams(ctx context.Context, teams []*organization.Team, loadOrgs bool) ([] Description: t.Description, IncludesAllRepositories: t.IncludesAllRepositories, CanCreateOrgRepo: t.CanCreateOrgRepo, - Permission: t.AccessMode.String(), + Permission: t.AccessMode.ToString(), Units: t.GetUnitNames(), UnitsMap: t.GetUnitsMap(), } diff --git a/services/convert/repository.go b/services/convert/repository.go index 39efd304a9..3b293fe550 100644 --- a/services/convert/repository.go +++ b/services/convert/repository.go @@ -25,12 +25,13 @@ func ToRepo(ctx context.Context, repo *repo_model.Repository, permissionInRepo a func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInRepo access_model.Permission, isParent bool) *api.Repository { var parent *api.Repository - if permissionInRepo.Units == nil && permissionInRepo.UnitsMode == nil { - // If Units and UnitsMode are both nil, it means that it's a hard coded permission, - // like access_model.Permission{AccessMode: perm.AccessModeAdmin}. - // So we need to load units for the repo, or UnitAccessMode will always return perm.AccessModeNone. + if !permissionInRepo.HasUnits() && permissionInRepo.AccessMode > perm.AccessModeNone { + // If units is empty, it means that it's a hard-coded permission, like access_model.Permission{AccessMode: perm.AccessModeAdmin} + // So we need to load units for the repo, otherwise UnitAccessMode will just return perm.AccessModeNone. + // TODO: this logic is still not right (because unit modes are not correctly prepared) + // the caller should prepare a proper "permission" before calling this function. _ = repo.LoadUnits(ctx) // the error is not important, so ignore it - permissionInRepo.Units = repo.Units + permissionInRepo.SetUnitsWithDefaultAccessMode(repo.Units, permissionInRepo.AccessMode) } cloneLink := repo.CloneLink() diff --git a/services/convert/user.go b/services/convert/user.go index 1a2733d91e..2957c58b14 100644 --- a/services/convert/user.go +++ b/services/convert/user.go @@ -103,7 +103,7 @@ func User2UserSettings(user *user_model.User) api.UserSettings { func ToUserAndPermission(ctx context.Context, user, doer *user_model.User, accessMode perm.AccessMode) api.RepoCollaboratorPermission { return api.RepoCollaboratorPermission{ User: ToUser(ctx, user, doer), - Permission: accessMode.String(), - RoleName: accessMode.String(), + Permission: accessMode.ToString(), + RoleName: accessMode.ToString(), } } diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go index e45a2a1695..f49cc2e86b 100644 --- a/services/forms/repo_form.go +++ b/services/forms/repo_form.go @@ -134,6 +134,7 @@ type RepoSettingForm struct { EnableWiki bool EnableExternalWiki bool DefaultWikiBranch string + DefaultWikiEveryoneAccess string ExternalWikiURL string EnableIssues bool EnableExternalTracker bool diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index 251785d078..c0411cfc56 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -317,7 +317,9 @@ </div> </div> - {{$isWikiEnabled := or (.Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeWiki) (.Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeExternalWiki)}} + {{$isInternalWikiEnabled := .Repository.UnitEnabled ctx ctx.Consts.RepoUnitTypeWiki}} + {{$isExternalWikiEnabled := .Repository.UnitEnabled ctx ctx.Consts.RepoUnitTypeExternalWiki}} + {{$isWikiEnabled := or $isInternalWikiEnabled $isExternalWikiEnabled}} {{$isWikiGlobalDisabled := ctx.Consts.RepoUnitTypeWiki.UnitGlobalDisabled}} {{$isExternalWikiGlobalDisabled := ctx.Consts.RepoUnitTypeExternalWiki.UnitGlobalDisabled}} {{$isBothWikiGlobalDisabled := and $isWikiGlobalDisabled $isExternalWikiGlobalDisabled}} @@ -331,21 +333,33 @@ <div class="field{{if not $isWikiEnabled}} disabled{{end}}" id="wiki_box"> <div class="field"> <div class="ui radio checkbox{{if $isWikiGlobalDisabled}} disabled{{end}}"{{if $isWikiGlobalDisabled}} data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{end}}> - <input class="enable-system-radio" name="enable_external_wiki" type="radio" value="false" data-target="#external_wiki_box" {{if not (.Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeExternalWiki)}}checked{{end}}> + <input class="enable-system-radio" name="enable_external_wiki" type="radio" value="false" data-context="#internal_wiki_box" data-target="#external_wiki_box" {{if $isInternalWikiEnabled}}checked{{end}}> <label>{{ctx.Locale.Tr "repo.settings.use_internal_wiki"}}</label> </div> </div> - <div class="inline field tw-pl-4"> - <label>{{ctx.Locale.Tr "repo.settings.default_wiki_branch_name"}}</label> - <input name="default_wiki_branch" value="{{.Repository.DefaultWikiBranch}}"> + <div id="internal_wiki_box" class="field tw-pl-4 {{if not $isInternalWikiEnabled}}disabled{{end}}"> + <div class="inline field"> + <label>{{ctx.Locale.Tr "repo.settings.default_wiki_branch_name"}}</label> + <input name="default_wiki_branch" value="{{.Repository.DefaultWikiBranch}}"> + </div> + <div class="inline field"> + {{$unitInternalWiki := .Repository.MustGetUnit ctx ctx.Consts.RepoUnitTypeWiki}} + <label>{{ctx.Locale.Tr "repo.settings.default_wiki_everyone_access"}}</label> + <select name="default_wiki_everyone_access" class="ui dropdown"> + {{/* everyone access mode is different from others, none means it is unset and won't be applied */}} + <option value="none" {{Iif (eq $unitInternalWiki.EveryoneAccessMode 0) "selected"}}>{{ctx.Locale.Tr "settings.permission_not_set"}}</option> + <option value="read" {{Iif (eq $unitInternalWiki.EveryoneAccessMode 1) "selected"}}>{{ctx.Locale.Tr "settings.permission_read"}}</option> + <option value="write" {{Iif (eq $unitInternalWiki.EveryoneAccessMode 2) "selected"}}>{{ctx.Locale.Tr "settings.permission_write"}}</option> + </select> + </div> </div> <div class="field"> <div class="ui radio checkbox{{if $isExternalWikiGlobalDisabled}} disabled{{end}}"{{if $isExternalWikiGlobalDisabled}} data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{end}}> - <input class="enable-system-radio" name="enable_external_wiki" type="radio" value="true" data-target="#external_wiki_box" {{if .Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeExternalWiki}}checked{{end}}> + <input class="enable-system-radio" name="enable_external_wiki" type="radio" value="true" data-context="#internal_wiki_box" data-target="#external_wiki_box" {{if $isExternalWikiEnabled}}checked{{end}}> <label>{{ctx.Locale.Tr "repo.settings.use_external_wiki"}}</label> </div> </div> - <div class="field tw-pl-4 {{if not (.Repository.UnitEnabled $.Context ctx.Consts.RepoUnitTypeExternalWiki)}}disabled{{end}}" id="external_wiki_box"> + <div id="external_wiki_box" class="field tw-pl-4 {{if not $isExternalWikiEnabled}}disabled{{end}}"> <label for="external_wiki_url">{{ctx.Locale.Tr "repo.settings.external_wiki_url"}}</label> <input id="external_wiki_url" name="external_wiki_url" type="url" value="{{(.Repository.MustGetUnit $.Context ctx.Consts.RepoUnitTypeExternalWiki).ExternalWikiConfig.ExternalWikiURL}}"> <p class="help">{{ctx.Locale.Tr "repo.settings.external_wiki_url_desc"}}</p> diff --git a/tests/integration/api_team_test.go b/tests/integration/api_team_test.go index 4df545284e..d14c66ff2c 100644 --- a/tests/integration/api_team_test.go +++ b/tests/integration/api_team_test.go @@ -126,7 +126,7 @@ func TestAPITeam(t *testing.T) { apiTeam = api.Team{} DecodeJSON(t, resp, &apiTeam) checkTeamResponse(t, "ReadTeam1", &apiTeam, teamRead.Name, *teamToEditDesc.Description, teamRead.IncludesAllRepositories, - teamRead.AccessMode.String(), teamRead.GetUnitNames(), teamRead.GetUnitsMap()) + teamRead.AccessMode.ToString(), teamRead.GetUnitNames(), teamRead.GetUnitsMap()) // Delete team. req = NewRequestf(t, "DELETE", "/api/v1/teams/%d", teamID). @@ -197,7 +197,7 @@ func TestAPITeam(t *testing.T) { DecodeJSON(t, resp, &apiTeam) assert.NoError(t, teamRead.LoadUnits(db.DefaultContext)) checkTeamResponse(t, "ReadTeam2", &apiTeam, teamRead.Name, *teamToEditDesc.Description, teamRead.IncludesAllRepositories, - teamRead.AccessMode.String(), teamRead.GetUnitNames(), teamRead.GetUnitsMap()) + teamRead.AccessMode.ToString(), teamRead.GetUnitNames(), teamRead.GetUnitsMap()) // Delete team. req = NewRequestf(t, "DELETE", "/api/v1/teams/%d", teamID). From be5be0ac81ce50ad5adb079af6ca4e8c396aaece Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 18 Apr 2024 02:16:52 +0200 Subject: [PATCH 142/370] Expose fuzzy search for issues/pulls (#29701) close #29685 --------- Signed-off-by: 6543 <6543@obermui.de> Co-authored-by: silverwind <me@silverwind.io> --- options/locale/locale_en-US.ini | 6 +++-- routers/web/user/home.go | 12 +++++++-- templates/shared/search/fuzzy.tmpl | 4 +-- templates/user/dashboard/issues.tmpl | 40 +++++++++++++++------------- web_src/css/form.css | 2 +- 5 files changed, 38 insertions(+), 26 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index a7c1d91791..c602aba53d 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -164,8 +164,8 @@ search = Search... type_tooltip = Search type fuzzy = Fuzzy fuzzy_tooltip = Include results that also match the search term closely -match = Match -match_tooltip = Include only results that match the exact search term +exact = Exact +exact_tooltip = Include only results that match the exact search term repo_kind = Search repos... user_kind = Search users... org_kind = Search orgs... @@ -179,6 +179,8 @@ branch_kind = Search branches... commit_kind = Search commits... runner_kind = Search runners... no_results = No matching results found. +issue_kind = Search issues... +pull_kind = Search pulls... keyword_search_unavailable = Searching by keyword is currently not available. Please contact the site administrator. [aria] diff --git a/routers/web/user/home.go b/routers/web/user/home.go index ff6c2a6c36..c3f34039e9 100644 --- a/routers/web/user/home.go +++ b/routers/web/user/home.go @@ -447,6 +447,8 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { User: ctx.Doer, } + isFuzzy := ctx.FormBool("fuzzy") + // Search all repositories which // // As user: @@ -546,7 +548,9 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { // USING FINAL STATE OF opts FOR A QUERY. var issues issues_model.IssueList { - issueIDs, _, err := issue_indexer.SearchIssues(ctx, issue_indexer.ToSearchOptions(keyword, opts)) + issueIDs, _, err := issue_indexer.SearchIssues(ctx, issue_indexer.ToSearchOptions(keyword, opts).Copy( + func(o *issue_indexer.SearchOptions) { o.IsFuzzyKeyword = isFuzzy }, + )) if err != nil { ctx.ServerError("issueIDsFromSearch", err) return @@ -567,7 +571,9 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { // ------------------------------- // Fill stats to post to ctx.Data. // ------------------------------- - issueStats, err := getUserIssueStats(ctx, ctxUser, filterMode, issue_indexer.ToSearchOptions(keyword, opts)) + issueStats, err := getUserIssueStats(ctx, ctxUser, filterMode, issue_indexer.ToSearchOptions(keyword, opts).Copy( + func(o *issue_indexer.SearchOptions) { o.IsFuzzyKeyword = isFuzzy }, + )) if err != nil { ctx.ServerError("getUserIssueStats", err) return @@ -621,6 +627,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { ctx.Data["SortType"] = sortType ctx.Data["IsShowClosed"] = isShowClosed ctx.Data["SelectLabels"] = selectedLabels + ctx.Data["IsFuzzy"] = isFuzzy if isShowClosed { ctx.Data["State"] = "closed" @@ -634,6 +641,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { pager.AddParamString("sort", sortType) pager.AddParamString("state", fmt.Sprint(ctx.Data["State"])) pager.AddParamString("labels", selectedLabels) + pager.AddParamString("fuzzy", fmt.Sprintf("%v", isFuzzy)) ctx.Data["Page"] = pager ctx.HTML(http.StatusOK, tplIssues) diff --git a/templates/shared/search/fuzzy.tmpl b/templates/shared/search/fuzzy.tmpl index 6ddb03c004..5c09d3c150 100644 --- a/templates/shared/search/fuzzy.tmpl +++ b/templates/shared/search/fuzzy.tmpl @@ -2,9 +2,9 @@ {{/* IsFuzzy - state of the fuzzy search toggle */}} <div class="ui small dropdown selection {{if .Disabled}} disabled{{end}}" data-tooltip-content="{{ctx.Locale.Tr "search.type_tooltip"}}"> <input name="fuzzy" type="hidden"{{if .Disabled}} disabled{{end}} value="{{.IsFuzzy}}">{{svg "octicon-triangle-down" 14 "dropdown icon"}} - <div class="text">{{if .IsFuzzy}}{{ctx.Locale.Tr "search.fuzzy"}}{{else}}{{ctx.Locale.Tr "search.match"}}{{end}}</div> + <div class="text">{{if .IsFuzzy}}{{ctx.Locale.Tr "search.fuzzy"}}{{else}}{{ctx.Locale.Tr "search.exact"}}{{end}}</div> <div class="menu"> <div class="item" data-value="true" data-tooltip-content="{{ctx.Locale.Tr "search.fuzzy_tooltip"}}">{{ctx.Locale.Tr "search.fuzzy"}}</div> - <div class="item" data-value="false" data-tooltip-content="{{ctx.Locale.Tr "search.match_tooltip"}}">{{ctx.Locale.Tr "search.match"}}</div> + <div class="item" data-value="false" data-tooltip-content="{{ctx.Locale.Tr "search.exact_tooltip"}}">{{ctx.Locale.Tr "search.exact"}}</div> </div> </div> diff --git a/templates/user/dashboard/issues.tmpl b/templates/user/dashboard/issues.tmpl index 89f23163f7..278907e43f 100644 --- a/templates/user/dashboard/issues.tmpl +++ b/templates/user/dashboard/issues.tmpl @@ -6,29 +6,29 @@ <div class="flex-container"> <div class="flex-container-nav"> <div class="ui secondary vertical filter menu tw-bg-transparent"> - <a class="{{if eq .ViewType "your_repositories"}}active{{end}} item" href="?type=your_repositories&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}"> + <a class="{{if eq .ViewType "your_repositories"}}active{{end}} item" href="?type=your_repositories&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}"> {{ctx.Locale.Tr "home.issues.in_your_repos"}} <strong>{{CountFmt .IssueStats.YourRepositoriesCount}}</strong> </a> - <a class="{{if eq .ViewType "assigned"}}active{{end}} item" href="?type=assigned&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}"> + <a class="{{if eq .ViewType "assigned"}}active{{end}} item" href="?type=assigned&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}"> {{ctx.Locale.Tr "repo.issues.filter_type.assigned_to_you"}} <strong>{{CountFmt .IssueStats.AssignCount}}</strong> </a> - <a class="{{if eq .ViewType "created_by"}}active{{end}} item" href="?type=created_by&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}"> + <a class="{{if eq .ViewType "created_by"}}active{{end}} item" href="?type=created_by&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}"> {{ctx.Locale.Tr "repo.issues.filter_type.created_by_you"}} <strong>{{CountFmt .IssueStats.CreateCount}}</strong> </a> {{if .PageIsPulls}} - <a class="{{if eq .ViewType "review_requested"}}active{{end}} item" href="?type=review_requested&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}"> + <a class="{{if eq .ViewType "review_requested"}}active{{end}} item" href="?type=review_requested&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}"> {{ctx.Locale.Tr "repo.issues.filter_type.review_requested"}} <strong>{{CountFmt .IssueStats.ReviewRequestedCount}}</strong> </a> - <a class="{{if eq .ViewType "reviewed_by"}}active{{end}} item" href="?type=reviewed_by&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}"> + <a class="{{if eq .ViewType "reviewed_by"}}active{{end}} item" href="?type=reviewed_by&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}"> {{ctx.Locale.Tr "repo.issues.filter_type.reviewed_by_you"}} <strong>{{CountFmt .IssueStats.ReviewedCount}}</strong> </a> {{end}} - <a class="{{if eq .ViewType "mentioned"}}active{{end}} item" href="?type=mentioned&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}"> + <a class="{{if eq .ViewType "mentioned"}}active{{end}} item" href="?type=mentioned&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}"> {{ctx.Locale.Tr "repo.issues.filter_type.mentioning_you"}} <strong>{{CountFmt .IssueStats.MentionCount}}</strong> </a> @@ -37,11 +37,11 @@ <div class="flex-container-main content"> <div class="list-header"> <div class="small-menu-items ui compact tiny menu list-header-toggle"> - <a class="item{{if not .IsShowClosed}} active{{end}}" href="?type={{$.ViewType}}&sort={{$.SortType}}&state=open&q={{$.Keyword}}"> + <a class="item{{if not .IsShowClosed}} active{{end}}" href="?type={{$.ViewType}}&sort={{$.SortType}}&state=open&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}"> {{svg "octicon-issue-opened" 16 "tw-mr-2"}} {{ctx.Locale.PrettyNumber .IssueStats.OpenCount}} {{ctx.Locale.Tr "repo.issues.open_title"}} </a> - <a class="item{{if .IsShowClosed}} active{{end}}" href="?type={{$.ViewType}}&sort={{$.SortType}}&state=closed&q={{$.Keyword}}"> + <a class="item{{if .IsShowClosed}} active{{end}}" href="?type={{$.ViewType}}&sort={{$.SortType}}&state=closed&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}"> {{svg "octicon-issue-closed" 16 "tw-mr-2"}} {{ctx.Locale.PrettyNumber .IssueStats.ClosedCount}} {{ctx.Locale.Tr "repo.issues.closed_title"}} </a> @@ -51,9 +51,11 @@ <input type="hidden" name="type" value="{{$.ViewType}}"> <input type="hidden" name="sort" value="{{$.SortType}}"> <input type="hidden" name="state" value="{{$.State}}"> - {{template "shared/search/input" dict "Value" $.Keyword}} - <button id="issue-list-quick-goto" class="ui small icon button tw-hidden" data-tooltip-content="{{ctx.Locale.Tr "explore.go_to"}}">{{svg "octicon-hash"}}</button> - {{template "shared/search/button"}} + {{if .PageIsPulls}} + {{template "shared/search/combo_fuzzy" dict "Value" $.Keyword "IsFuzzy" $.IsFuzzy "Placeholder" (ctx.Locale.Tr "search.pull_kind") "Tooltip" (ctx.Locale.Tr "explorer.go")}} + {{else}} + {{template "shared/search/combo_fuzzy" dict "Value" $.Keyword "IsFuzzy" $.IsFuzzy "Placeholder" (ctx.Locale.Tr "search.issue_kind") "Tooltip" (ctx.Locale.Tr "explorer.go")}} + {{end}} </div> </form> <!-- Sort --> @@ -63,14 +65,14 @@ {{svg "octicon-triangle-down" 14 "dropdown icon"}} </span> <div class="menu"> - <a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="?type={{$.ViewType}}&sort=recentupdate&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.recentupdate"}}</a> - <a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="?type={{$.ViewType}}&sort=leastupdate&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastupdate"}}</a> - <a class="{{if or (eq .SortType "latest") (not .SortType)}}active {{end}}item" href="?type={{$.ViewType}}&sort=latest&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.latest"}}</a> - <a class="{{if eq .SortType "oldest"}}active {{end}}item" href="?type={{$.ViewType}}&sort=oldest&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.oldest"}}</a> - <a class="{{if eq .SortType "mostcomment"}}active {{end}}item" href="?type={{$.ViewType}}&sort=mostcomment&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.mostcomment"}}</a> - <a class="{{if eq .SortType "leastcomment"}}active {{end}}item" href="?type={{$.ViewType}}&sort=leastcomment&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastcomment"}}</a> - <a class="{{if eq .SortType "nearduedate"}}active {{end}}item" href="?type={{$.ViewType}}&sort=nearduedate&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.nearduedate"}}</a> - <a class="{{if eq .SortType "farduedate"}}active {{end}}item" href="?type={{$.ViewType}}&sort=farduedate&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.farduedate"}}</a> + <a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="?type={{$.ViewType}}&sort=recentupdate&state={{$.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">{{ctx.Locale.Tr "repo.issues.filter_sort.recentupdate"}}</a> + <a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="?type={{$.ViewType}}&sort=leastupdate&state={{$.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastupdate"}}</a> + <a class="{{if or (eq .SortType "latest") (not .SortType)}}active {{end}}item" href="?type={{$.ViewType}}&sort=latest&state={{$.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">{{ctx.Locale.Tr "repo.issues.filter_sort.latest"}}</a> + <a class="{{if eq .SortType "oldest"}}active {{end}}item" href="?type={{$.ViewType}}&sort=oldest&state={{$.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">{{ctx.Locale.Tr "repo.issues.filter_sort.oldest"}}</a> + <a class="{{if eq .SortType "mostcomment"}}active {{end}}item" href="?type={{$.ViewType}}&sort=mostcomment&state={{$.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">{{ctx.Locale.Tr "repo.issues.filter_sort.mostcomment"}}</a> + <a class="{{if eq .SortType "leastcomment"}}active {{end}}item" href="?type={{$.ViewType}}&sort=leastcomment&state={{$.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastcomment"}}</a> + <a class="{{if eq .SortType "nearduedate"}}active {{end}}item" href="?type={{$.ViewType}}&sort=nearduedate&state={{$.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">{{ctx.Locale.Tr "repo.issues.filter_sort.nearduedate"}}</a> + <a class="{{if eq .SortType "farduedate"}}active {{end}}item" href="?type={{$.ViewType}}&sort=farduedate&state={{$.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">{{ctx.Locale.Tr "repo.issues.filter_sort.farduedate"}}</a> </div> </div> </div> diff --git a/web_src/css/form.css b/web_src/css/form.css index a8f73b6b66..7479af0c4e 100644 --- a/web_src/css/form.css +++ b/web_src/css/form.css @@ -40,7 +40,7 @@ textarea, /* fix fomantic small dropdown having inconsistent padding with input */ .ui.small.selection.dropdown { - padding: .67857143em 3.2em .67857143em 1em; + padding: .67857143em 1.6em .67857143em 1em; } input:hover, From ffc98790703cdc41ed2327e613aa2f91a051b457 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Thu, 18 Apr 2024 00:26:04 +0000 Subject: [PATCH 143/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_cs-CZ.ini | 6 ------ options/locale/locale_de-DE.ini | 6 ------ options/locale/locale_el-GR.ini | 4 ---- options/locale/locale_es-ES.ini | 4 ---- options/locale/locale_fa-IR.ini | 3 --- options/locale/locale_fi-FI.ini | 1 - options/locale/locale_fr-FR.ini | 4 ---- options/locale/locale_hu-HU.ini | 3 --- options/locale/locale_id-ID.ini | 2 -- options/locale/locale_is-IS.ini | 1 - options/locale/locale_it-IT.ini | 3 --- options/locale/locale_ja-JP.ini | 6 ------ options/locale/locale_lv-LV.ini | 4 ---- options/locale/locale_nl-NL.ini | 2 -- options/locale/locale_pl-PL.ini | 3 --- options/locale/locale_pt-BR.ini | 4 ---- options/locale/locale_pt-PT.ini | 6 ------ options/locale/locale_ru-RU.ini | 4 ---- options/locale/locale_si-LK.ini | 2 -- options/locale/locale_sv-SE.ini | 3 --- options/locale/locale_tr-TR.ini | 4 ---- options/locale/locale_uk-UA.ini | 3 --- options/locale/locale_zh-CN.ini | 6 ------ options/locale/locale_zh-HK.ini | 1 - options/locale/locale_zh-TW.ini | 3 --- 25 files changed, 88 deletions(-) diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index 82a8fe5d45..57c44e4b26 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -164,8 +164,6 @@ search=Hledat... type_tooltip=Druh vyhledávání fuzzy=Fuzzy fuzzy_tooltip=Zahrnout výsledky, které také úzce odpovídají hledanému výrazu -match=Shoda -match_tooltip=Zahrnout pouze výsledky, které odpovídají přesnému hledanému výrazu repo_kind=Hledat repozitáře... user_kind=Hledat uživatele... org_kind=Hledat organizace... @@ -714,7 +712,6 @@ cancel=Zrušit language=Jazyk ui=Motiv vzhledu hidden_comment_types=Skryté typy komentářů -hidden_comment_types_description=Zde zkontrolované typy komentářů nebudou zobrazeny na stránkách problémů. Zaškrtnutí „Štítek“ například odstraní všechny komentáře „<user> přidal/odstranil <label>“. hidden_comment_types.ref_tooltip=Komentáře, na které se odkazovalo z jiného úkolu/commitu/… hidden_comment_types.issue_ref_tooltip=Komentáře, kde uživatel změní větev/značku spojenou s problémem comment_type_group_reference=Reference @@ -1286,7 +1283,6 @@ editor.or=nebo editor.cancel_lower=Zrušit editor.commit_signed_changes=Odevzdat podepsané změny editor.commit_changes=Odevzdat změny -editor.add_tmpl=Přidán „<nazev_souboru>“ editor.add=Přidat %s editor.update=Aktualizovat %s editor.delete=Odstranit %s @@ -3075,14 +3071,12 @@ auths.tips=Tipy auths.tips.oauth2.general=Ověřování OAuth2 auths.tips.oauth2.general.tip=Při registraci nové OAuth2 autentizace by URL callbacku/přesměrování měla být: auths.tip.oauth2_provider=Poskytovatel OAuth2 -auths.tip.bitbucket=Vytvořte nového OAuth konzumenta na https://bitbucket.org/account/user/<vase-uzivatelske-jmeno>/oauth-consumers/new a přidejte oprávnění „Account“ - „Read“ auths.tip.nextcloud=Zaregistrujte nového OAuth konzumenta na vaší instanci pomocí následujícího menu „Nastavení -> Zabezpečení -> OAuth 2.0 klient“ auths.tip.dropbox=Vytvořte novou aplikaci na https://www.dropbox.com/developers/apps auths.tip.facebook=Registrujte novou aplikaci na https://developers.facebook.com/apps a přidejte produkt „Facebook Login“ auths.tip.github=Registrujte novou OAuth aplikaci na https://github.com/settings/applications/new auths.tip.gitlab_new=Zaregistrujte novou aplikaci na https://gitlab.com/-/profile/applications auths.tip.google_plus=Získejte klientské pověření OAuth2 z Google API konzole na https://console.developers.google.com/ -auths.tip.openid_connect=Použijte OpenID URL pro objevování spojení (<server>/.well-known/openid-configuration) k nastavení koncových bodů auths.tip.twitter=Jděte na https://dev.twitter.com/apps, vytvořte aplikaci a ujistěte se, že volba „Allow this application to be used to Sign in with Twitter“ je povolená auths.tip.discord=Registrujte novou aplikaci na https://discordapp.com/developers/applications/me auths.tip.gitea=Registrovat novou Oauth2 aplikaci. Návod naleznete na https://docs.gitea.com/development/oauth2-provider diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 9a09c2922e..f591b75577 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -164,8 +164,6 @@ search=Suche ... type_tooltip=Suchmodus fuzzy=Ähnlich fuzzy_tooltip=Ergebnisse einbeziehen, die dem Suchbegriff ähnlich sind -match=Genau -match_tooltip=Nur genau zum Suchbegriff passende Ergebnisse einbeziehen repo_kind=Repositories durchsuchen ... user_kind=Benutzer durchsuchen ... org_kind=Organisationen durchsuchen ... @@ -714,7 +712,6 @@ cancel=Abbrechen language=Sprache ui=Theme hidden_comment_types=Ausgeblendeter Kommentartypen -hidden_comment_types_description=Die hier markierten Kommentartypen werden nicht innerhalb der Issue-Seiten angezeigt. Das Überprüfen von "Label" entfernt beispielsweise alle "<user> hinzugefügt/entfernt <label>" Kommentare. hidden_comment_types.ref_tooltip=Kommentare, in denen dieses Issue von einem anderen Issue/Commit referenziert wurde hidden_comment_types.issue_ref_tooltip=Kommentare, bei denen der Benutzer den Branch/Tag des Issues ändert comment_type_group_reference=Verweis auf Mitglieder @@ -1287,7 +1284,6 @@ editor.or=oder editor.cancel_lower=Abbrechen editor.commit_signed_changes=Committe signierte Änderungen editor.commit_changes=Änderungen committen -editor.add_tmpl='<filename>' hinzufügen editor.add=%s hinzugefügt editor.update=%s aktualisiert editor.delete=%s gelöscht @@ -3083,14 +3079,12 @@ auths.tips=Tipps auths.tips.oauth2.general=OAuth2-Authentifizierung auths.tips.oauth2.general.tip=Beim Registrieren einer OAuth2-Anwendung sollte die Callback-URL folgendermaßen lauten: auths.tip.oauth2_provider=OAuth2-Anbieter -auths.tip.bitbucket=Registriere einen neuen OAuth-Consumer unter https://bitbucket.org/account/user/<dein-benutzername>/oauth-consumers/new und füge die Berechtigung „Account“ – „Read“ hinzu. auths.tip.nextcloud=Registriere über das "Settings -> Security -> OAuth 2.0 client"-Menü einen neuen "OAuth consumer" auf der Nextcloud-Instanz auths.tip.dropbox=Erstelle eine neue App auf https://www.dropbox.com/developers/apps. auths.tip.facebook=Erstelle eine neue Anwendung auf https://developers.facebook.com/apps und füge das Produkt „Facebook Login“ hinzu. auths.tip.github=Erstelle unter https://github.com/settings/applications/new eine neue OAuth-Anwendung. auths.tip.gitlab_new=Erstelle eine neue Anwendung unter https://gitlab.com/-/profile/applications auths.tip.google_plus=Du erhältst die OAuth2-Client-Zugangsdaten in der Google-API-Konsole unter https://console.developers.google.com/ -auths.tip.openid_connect=Benutze die OpenID-Connect-Discovery-URL (<server>/.well-known/openid-configuration), um die Endpunkte zu spezifizieren auths.tip.twitter=Gehe auf https://dev.twitter.com/apps, erstelle eine Anwendung und stelle sicher, dass die Option „Allow this application to be used to Sign in with Twitter“ aktiviert ist auths.tip.discord=Erstelle unter https://discordapp.com/developers/applications/me eine neue Anwendung. auths.tip.gitea=Registriere eine neue OAuth2-Anwendung. Eine Anleitung findest du unter https://docs.gitea.com/development/oauth2-provider/ diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini index 6ce5ae1ce9..64db2348da 100644 --- a/options/locale/locale_el-GR.ini +++ b/options/locale/locale_el-GR.ini @@ -651,7 +651,6 @@ cancel=Ακύρωση language=Γλώσσα ui=Θέμα Διεπαφής hidden_comment_types=Κρυμμένοι τύποι σχολίων -hidden_comment_types_description=Οι τύποι σχολίων που επιλέγονται εδώ δε θα εμφανίζονται μέσα στις σελίδες ζητημάτων. Επιλέγοντας π.χ το "Σήματα", θα αφαιρεθούν όλα τα σχόλια σαν το "<user> πρόσθεσε/αφαίρεσε τα σήματα <label>". hidden_comment_types.ref_tooltip=Σχόλια όπου αυτό το ζήτημα αναφέρθηκε από άλλο ζήτημα/υποβολή/… hidden_comment_types.issue_ref_tooltip=Σχόλια όπου ο χρήστης αλλάζει τον κλάδο/ετικέτα που σχετίζεται με το ζήτημα comment_type_group_reference=Αναφορά @@ -1214,7 +1213,6 @@ editor.or=ή editor.cancel_lower=Ακύρωση editor.commit_signed_changes=Υποβολή Υπογεγραμμένων Αλλαγών editor.commit_changes=Υποβολή Αλλαγών -editor.add_tmpl=Προσθήκη '<filename>' editor.add=Προσθήκη %s editor.update=Ενημέρωση %s editor.delete=Διαγραφή %s @@ -2970,13 +2968,11 @@ auths.tips=Συμβουλές auths.tips.oauth2.general=Ταυτοποίηση OAuth2 auths.tips.oauth2.general.tip=Κατά την εγγραφή μιας νέας ταυτοποίησης OAuth2, το URL κλήσης/ανακατεύθυνσης πρέπει να είναι: auths.tip.oauth2_provider=Πάροχος OAuth2 -auths.tip.bitbucket=Καταχωρήστε ένα νέο καταναλωτή OAuth στο https://bitbucket.org/account/user/<your username>/oauth-consumers/new και προσθέστε το δικαίωμα 'Account' - 'Read' auths.tip.nextcloud=`Καταχωρήστε ένα νέο καταναλωτή OAuth στην υπηρεσία σας χρησιμοποιώντας το παρακάτω μενού "Settings -> Security -> OAuth 2.0 client"` 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.google_plus=Αποκτήστε τα διαπιστευτήρια πελάτη OAuth2 από την κονσόλα API της Google στο https://console.developers.google.com/ -auths.tip.openid_connect=Χρησιμοποιήστε το OpenID Connect Discovery URL (<server>/.well known/openid-configuration) για να καθορίσετε τα τελικά σημεία auths.tip.twitter=Πηγαίνετε στο https://dev.twitter.com/apps, δημιουργήστε μια εφαρμογή και βεβαιωθείτε ότι η επιλογή “Allow this application to be used to Sign in with Twitter” είναι ενεργοποιημένη auths.tip.discord=Καταχωρήστε μια νέα εφαρμογή στο https://discordapp.com/developers/applications/me auths.tip.gitea=Καταχωρήστε μια νέα εφαρμογή OAuth2. Μπορείτε να βρείτε τον οδηγό στο https://docs.gitea.com/development/oauth2-provider diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index fc78e1d439..d1d680c14c 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -648,7 +648,6 @@ cancel=Cancelar language=Idioma ui=Tema hidden_comment_types=Tipos de comentarios ocultos -hidden_comment_types_description=Los tipos de comentarios marcados aquí no se mostrarán dentro de las páginas de incidencia. Marcar "Etiqueta" por ejemplo elimina todos los comentarios "<user> añadidos/eliminados <label>". hidden_comment_types.ref_tooltip=Comentarios donde esta incidencia fue referenciada desde otra incidencia/commit/… hidden_comment_types.issue_ref_tooltip=Comentarios donde el usuario cambia la rama/etiqueta asociada a la incidencia comment_type_group_reference=Referencia @@ -1207,7 +1206,6 @@ editor.or=o editor.cancel_lower=Cancelar editor.commit_signed_changes=Crear commit firmado de los cambios editor.commit_changes=Crear commit de los cambios -editor.add_tmpl=Añadir '<filename>' editor.add=Añadir %s editor.update=Actualizar %s editor.delete=Eliminar %s @@ -2953,13 +2951,11 @@ auths.tips=Consejos auths.tips.oauth2.general=Autenticación OAuth2 auths.tips.oauth2.general.tip=Al registrar una nueva autenticación de OAuth2, la URL de devolución de llamada/redirección debe ser: auths.tip.oauth2_provider=Proveedor OAuth2 -auths.tip.bitbucket=Registrar un nuevo usuario de OAuth en https://bitbucket.org/account/user/<your username>/oauth-consumers/new y agregar el permiso 'Cuenta' - 'Lectura' auths.tip.nextcloud=`Registre un nuevo consumidor OAuth en su instancia usando el siguiente menú "Configuración-> Seguridad-> cliente OAuth 2.0"` auths.tip.dropbox=Crear nueva aplicación en https://www.dropbox.com/developers/apps auths.tip.facebook=`Registre una nueva aplicación en https://developers.facebook.com/apps y agregue el producto "Facebook Login"` auths.tip.github=Registre una nueva aplicación OAuth en https://github.com/settings/applications/new auths.tip.google_plus=Obtener credenciales de cliente OAuth2 desde la consola API de Google en https://console.developers.google.com/ -auths.tip.openid_connect=Use el OpenID Connect Discovery URL (<server>/.well-known/openid-configuration) para especificar los puntos finales auths.tip.twitter=Ir a https://dev.twitter.com/apps, crear una aplicación y asegurarse de que la opción "Permitir que esta aplicación sea usada para iniciar sesión con Twitter" está activada auths.tip.discord=Registrar una nueva aplicación en https://discordapp.com/developers/applications/me auths.tip.gitea=Registrar una nueva aplicación OAuth2. Puede encontrar la guía en https://docs.gitea.com/development/oauth2-provider diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini index d19eb356d2..54a4911e5c 100644 --- a/options/locale/locale_fa-IR.ini +++ b/options/locale/locale_fa-IR.ini @@ -947,7 +947,6 @@ editor.or=یا editor.cancel_lower=انصراف editor.commit_signed_changes=اعمال تغییرات امضا شده editor.commit_changes=تغییرات کامیت -editor.add_tmpl=افزودن '<filename>' editor.commit_message_desc=توضیحی تخصصی به دلخواه اضافه نمایید… editor.signoff_desc=یک تریلر Signed-off-by توسط committer در انتهای پیام گزارش commit اضافه کنید. editor.commit_directly_to_this_branch=ثبت کامیت به صورت مستقیم در انشعاب <strong class="branch-name">%s</strong>. @@ -2297,13 +2296,11 @@ auths.sspi_default_language_helper=زبان پیش فرض برای کاربرا auths.tips=ﻧﮑﺎﺕ auths.tips.oauth2.general=احراز هویت OAuth2 auths.tip.oauth2_provider=تامین کننده OAuth2 -auths.tip.bitbucket=ثبت یک OAuth جدید مصرف کننده بر https://bitbucket.org/account/user/<your username>/oauth-consumers/new و افزودن مجوز 'Account' - 'Read' auths.tip.nextcloud=با استفاده از منوی زیر "تنظیمات -> امنیت -> مشتری OAuth 2.0" مصرف کننده OAuth جدیدی را در نمونه خود ثبت کنید 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.google_plus=اطلاعات مربوط به مشتری OAuth2 را از کلاینت API Google در https://console.developers.google.com/ -auths.tip.openid_connect=برای مشخص کردن نقاط پایانی از آدرس OpenID Connect Discovery URL (<server> /.well-known/openid-configuration) استفاده کنید. auths.tip.twitter=به https://dev.twitter.com/apps بروید ، برنامه ای ایجاد کنید و اطمینان حاصل کنید که گزینه "اجازه استفاده از این برنامه برای ورود به سیستم با Twitter" را فعال کنید auths.tip.discord=یک برنامه جدید را در https://discordapp.com/developers/applications/me ثبت کنید auths.tip.yandex=`یک برنامه جدید در https://oauth.yandex.com/client/new ایجاد کنید. مجوزهای زیر را از بخش "Yandex.Passport API" انتخاب کنید: "دسترسی به آدرس ایمیل"، "دسترسی به آواتار کاربر" و "دسترسی به نام کاربری، نام و نام خانوادگی، جنسیت"` diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini index f283209908..ace676281f 100644 --- a/options/locale/locale_fi-FI.ini +++ b/options/locale/locale_fi-FI.ini @@ -767,7 +767,6 @@ editor.or=tai editor.cancel_lower=Peru editor.commit_signed_changes=Commitoi vahvistetut muutokset editor.commit_changes=Commitoi muutokset -editor.add_tmpl=Lisää '<filename>' editor.commit_directly_to_this_branch=Commitoi suoraan <strong class="branch-name">%s</strong> haaraan. editor.create_new_branch=Luo <strong>uusi haara</strong> tälle commitille ja aloita vetopyyntö. editor.create_new_branch_np=Luo <strong>uusi haara</strong> tälle commitille. diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index dc66402901..c57bae77c0 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -654,7 +654,6 @@ cancel=Annuler language=Langue ui=Thème hidden_comment_types=Catégories de commentaires masqués -hidden_comment_types_description=Cochez les catégories suivantes pour masquer les commentaires correspondants des fils d'activité. Par exemple, « Label » cache les commentaires du genre « Cerise a attribué le label Bug il y a 2 heures. » hidden_comment_types.ref_tooltip=Commentaires où ce ticket a été référencé sur un autre ticket, révision, etc. hidden_comment_types.issue_ref_tooltip=Commentaires où l’utilisateur change la branche/étiquette associée au ticket comment_type_group_reference=Référence @@ -1223,7 +1222,6 @@ editor.or=ou editor.cancel_lower=Annuler editor.commit_signed_changes=Réviser les changements (signé) editor.commit_changes=Réviser les changements -editor.add_tmpl=Ajouter '<filename>' editor.add=Ajouter %s editor.update=Actualiser %s editor.delete=Supprimer %s @@ -2997,13 +2995,11 @@ auths.tips=Conseils auths.tips.oauth2.general=Authentification OAuth2 auths.tips.oauth2.general.tip=Lors de l'enregistrement d'une nouvelle authentification OAuth2, l'URL de rappel/redirection doit être : auths.tip.oauth2_provider=Fournisseur OAuth2 -auths.tip.bitbucket=`Créez un nouveau jeton OAuth sur https://bitbucket.org/account/user/<your username>/oauth-consumers/new et ajoutez la permission "Compte"-"Lecture"` auths.tip.nextcloud=`Enregistrez un nouveau consommateur OAuth sur votre instance en utilisant le menu "Paramètres -> Sécurité -> Client OAuth 2.0"` auths.tip.dropbox=Créez une nouvelle application sur https://www.dropbox.com/developers/apps auths.tip.facebook=`Enregistrez une nouvelle application sur https://developers.facebook.com/apps et ajoutez le produit "Facebook Login"` auths.tip.github=Créez une nouvelle application OAuth sur https://github.com/settings/applications/new auths.tip.google_plus=Obtenez des identifiants OAuth2 sur la console API de Google (https://console.developers.google.com/) -auths.tip.openid_connect=Utilisez l'URL de découvert OpenID (<server>/.well-known/openid-configuration) pour spécifier les points d'accès auths.tip.twitter=Rendez-vous sur https://dev.twitter.com/apps, créez une application et assurez-vous que l'option "Autoriser l'application à être utilisée avec Twitter Connect" est activée auths.tip.discord=Enregistrer une nouvelle application sur https://discordapp.com/developers/applications/me auths.tip.gitea=Enregistrez une nouvelle application OAuth2. Le guide peut être trouvé sur https://docs.gitea.com/development/oauth2-provider diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini index fb229090d4..bddd6dd582 100644 --- a/options/locale/locale_hu-HU.ini +++ b/options/locale/locale_hu-HU.ini @@ -711,7 +711,6 @@ editor.name_your_file=Fájl elnevezése… editor.or=vagy editor.cancel_lower=Mégse editor.commit_changes=Változások Véglegesítése -editor.add_tmpl='<filename>' hozzáadása editor.commit_message_desc=Opcionális hosszabb leírás hozzáadása… editor.commit_directly_to_this_branch=Mentés egyenesen a(z) <strong class="branch-name">%s</strong> ágba. editor.create_new_branch=Hozzon létre egy <strong>új ágat</strong> ennek a commit-nak és indíts egy egyesítési kérést. @@ -1401,12 +1400,10 @@ auths.enable_auto_register=Automatikus regisztráció engedélyezése auths.tips=Tippek auths.tips.oauth2.general=OAuth2 hitelesítés auths.tip.oauth2_provider=OAuth2 szolgáltató -auths.tip.bitbucket=Igényeljen egy új OAuth jogosultságot itt: https://bitbucket.org/account/user/<felhasználóneved>/oauth-consumers/new és adja hozzá jogosultságot a "Fiókok"-"Olvasás" alá auths.tip.dropbox=Vegyen fel új alkalmazást itt: https://www.dropbox.com/developers/apps auths.tip.facebook=Vegyen fel új alkalmazást itt: https://developers.facebook.com/apps majd adja hozzá a "Facebook Login"-t auths.tip.github=Vegyen fel új OAuth alkalmazást itt: https://github.com/settings/applications/new auths.tip.google_plus=Szerezzen OAuth2 kliens hitelesítési adatokat a Google API konzolban (https://console.developers.google.com/) -auths.tip.openid_connect=Használja az OpenID kapcsolódás felfedező URL-t (<kiszolgáló>/.well-known/openid-configuration) a végpontok beállításához auths.tip.twitter=Menyjen ide: https://dev.twitter.com/apps, hozzon létre egy alkalmazást és győződjön meg róla, hogy az “Allow this application to be used to Sign in with Twitter” opció be van kapcsolva auths.tip.discord=Vegyen fel új alkalmazást itt: https://discordapp.com/developers/applications/me diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini index 96248cbc1d..9261077831 100644 --- a/options/locale/locale_id-ID.ini +++ b/options/locale/locale_id-ID.ini @@ -620,7 +620,6 @@ editor.filename_help=Tambahkan direktori dengan mengetikkan nama direktori diiku editor.or=atau editor.cancel_lower=Batalkan editor.commit_changes=Perubahan komitmen -editor.add_tmpl=Tambahkan '<filename>' editor.commit_message_desc=Tambahkan deskripsi opsional yang panjang… editor.commit_directly_to_this_branch=Komitmen langsung ke <strong class="branch-name">%s</strong> cabang. editor.create_new_branch=Membuat <strong>new branch</strong> untuk tarik komit ini mulai permintaan. @@ -1118,7 +1117,6 @@ auths.tip.oauth2_provider=Penyediaan OAuth2 auths.tip.dropbox=Membuat aplikasi baru di https://www.dropbox.com/developers/apps auths.tip.facebook=`Daftarkan sebuah aplikasi baru di https://developers.facebook.com/apps dan tambakan produk "Facebook Masuk"` auths.tip.github=Mendaftar aplikasi OAuth baru di https://github.com/settings/applications/new -auths.tip.openid_connect=Gunakan membuka ID yang terhubung ke jelajah URL (<server>/.well-known/openid-configuration) untuk menentukan titik akhir auths.delete=Menghapus Otentikasi Sumber auths.delete_auth_title=Menghapus Otentikasi Sumber diff --git a/options/locale/locale_is-IS.ini b/options/locale/locale_is-IS.ini index 3165c4185b..a1116eddbc 100644 --- a/options/locale/locale_is-IS.ini +++ b/options/locale/locale_is-IS.ini @@ -697,7 +697,6 @@ editor.delete_this_file=Eyða Skrá editor.name_your_file=Nefndu skrána þína… editor.or=eða editor.cancel_lower=Hætta við -editor.add_tmpl=Bæta við „<filename>“ editor.create_new_branch=Búðu til <strong>nýja grein</strong> og sameiningarbeiðni fyrir þetta framlag. editor.create_new_branch_np=Búðu til <strong>nýja grein</strong> fyrir þetta framlag. editor.new_branch_name_desc=Heiti nýjar greinar… diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index 9a22995dfb..b15a78ccf4 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -1018,7 +1018,6 @@ editor.or=o editor.cancel_lower=Annulla editor.commit_signed_changes=Conferma modifiche firmate editor.commit_changes=Apporta le modifiche -editor.add_tmpl=Aggiungi '<filename>' editor.patch=Applica Patch editor.patching=Patching: editor.new_patch=Nuova Patch @@ -2489,13 +2488,11 @@ auths.sspi_default_language_helper=Lingua predefinita per gli utenti creati auto auths.tips=Consigli auths.tips.oauth2.general=Autenticazione OAuth2 auths.tip.oauth2_provider=OAuth2 Provider -auths.tip.bitbucket=Registra un nuovo cliente OAuth su https://bitbucket.org/account/user/<your username>/oauth-consumers/new e aggiungi il permesso 'Account' - 'Read' auths.tip.nextcloud=`Registra un nuovo OAuth sulla tua istanza utilizzando il seguente menu "Impostazioni -> Sicurezza -> OAuth 2.0 client"` auths.tip.dropbox=Crea una nuova applicazione su https://www.dropbox.com/developers/apps auths.tip.facebook=`Registra una nuova applicazione su https://developers.facebook.com/apps e aggiungi il prodotto "Facebook Login"` auths.tip.github=Registra una nuova applicazione OAuth su https://github.com/settings/applications/new auths.tip.google_plus=Ottieni le credenziali del client OAuth2 dalla console API di Google su https://console.developers.google.com/ -auths.tip.openid_connect=Utilizza l'OpenID Connect Discovery URL (<server>/.well-known/openid-configuration) per specificare gli endpoint auths.tip.twitter=Vai su https://dev.twitter.com/apps, crea una applicazione e assicurati che l'opzione "Allow this application to be used to Sign In with Twitter" sia abilitata auths.tip.discord=Registra una nuova applicazione su https://discordapp.com/developers/applications/me auths.tip.yandex=`Crea una nuova applicazione su https://oauth.yandex.com/client/new. Seleziona i seguenti permessi da "Yandex. assport API": "Access to email address", "Access to user avatar" e "Access to username, name and surname, gender"` diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 74ff775cc8..dd5e58133e 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -164,8 +164,6 @@ search=検索… type_tooltip=検索タイプ fuzzy=あいまい fuzzy_tooltip=検索ワードに近い結果も含めます -match=一致 -match_tooltip=検索ワードと完全に一致する結果のみ含めます repo_kind=リポジトリを検索... user_kind=ユーザーを検索... org_kind=組織を検索... @@ -709,7 +707,6 @@ cancel=キャンセル language=言語 ui=テーマ hidden_comment_types=非表示にするコメントの種類 -hidden_comment_types_description=ここでチェックを入れたコメントの種類は、イシューのページには表示されません。 たとえば「ラベル」にチェックを入れると、「<ユーザー> が <ラベル> を追加/削除」といったコメントはすべて除去されます。 hidden_comment_types.ref_tooltip=このイシューが別のイシューやコミット等から参照された、というコメント hidden_comment_types.issue_ref_tooltip=このイシューのブランチやタグへの関連付けをユーザーが変更した、というコメント comment_type_group_reference=参照 @@ -1282,7 +1279,6 @@ editor.or=または editor.cancel_lower=キャンセル editor.commit_signed_changes=署名した変更をコミット editor.commit_changes=変更をコミット -editor.add_tmpl='<ファイル名>' を追加 editor.add=%s を追加 editor.update=%s を更新 editor.delete=%s を削除 @@ -3080,14 +3076,12 @@ auths.tips=ヒント auths.tips.oauth2.general=OAuth2認証 auths.tips.oauth2.general.tip=新しいOAuth2認証を登録するときは、コールバック/リダイレクトURLは以下になります: auths.tip.oauth2_provider=OAuth2プロバイダー -auths.tip.bitbucket=新しいOAuthコンシューマーを https://bitbucket.org/account/user/<あなたのユーザー名>/oauth-consumers/new から登録し、"アカウント" に "読み取り" 権限を追加してください。 auths.tip.nextcloud=新しいOAuthコンシューマーを、インスタンスのメニュー "Settings -> Security -> OAuth 2.0 client" から登録してください。 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_new=新しいアプリケーションを https://gitlab.com/-/profile/applications から登録してください。 auths.tip.google_plus=OAuth2クライアント資格情報を、Google APIコンソール https://console.developers.google.com/ から取得してください。 -auths.tip.openid_connect=OpenID Connect DiscoveryのURL (<server>/.well-known/openid-configuration) をエンドポイントとして指定してください auths.tip.twitter=https://dev.twitter.com/apps へアクセスしてアプリケーションを作成し、“Allow this application to be used to Sign in with Twitter”オプションを有効にしてください。 auths.tip.discord=新しいアプリケーションを https://discordapp.com/developers/applications/me から登録してください。 auths.tip.gitea=新しいOAuthアプリケーションを登録してください。 利用ガイドは https://docs.gitea.com/development/oauth2-provider にあります diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 9a15090012..6afb488414 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -651,7 +651,6 @@ cancel=Atcelt language=Valoda ui=Motīvs hidden_comment_types=Attēlojot paslēpt šauds komentārus: -hidden_comment_types_description=Komentāru veidi, kas atzīmēti, netiks rādīti problēmas lapā. Piemēram, atzīmējot "Etiķetes" netiks rādīti komentāri "<lietotājs> pievienoja/noņēma <etiķete>". hidden_comment_types.ref_tooltip=Komentāri, kad problēmai tiek pievienota atsauce uz citu probēmu, komentāru, … hidden_comment_types.issue_ref_tooltip=Komentāri par lietotāja izmaiņām ar problēmas saistīto atzaru/tagu comment_type_group_reference=Atsauces @@ -1215,7 +1214,6 @@ editor.or=vai editor.cancel_lower=Atcelt editor.commit_signed_changes=Apstiprināt parakstītu revīziju editor.commit_changes=Pabeigt revīziju -editor.add_tmpl=Pievienot '<fails>' editor.add=Pievienot %s editor.update=Atjaunot %s editor.delete=Dzēst %s @@ -2976,13 +2974,11 @@ auths.tips=Padomi auths.tips.oauth2.general=OAuth2 autentifikācija auths.tips.oauth2.general.tip=Kad tiek reģistrēta jauna OAuth2 autentifikācija, atzvanīšanas/pārvirzīšanas URL vajadzētu būt: auths.tip.oauth2_provider=OAuth2 pakalpojuma sniedzējs -auths.tip.bitbucket=Reģistrējiet jaunu OAuth klientu adresē https://bitbucket.org/account/user/<jūsu lietotājvārds>/oauth-consumers/new un piešķiriet tam "Account" - "Read" tiesības auths.tip.nextcloud=`Reģistrējiet jaunu OAuth klientu jūsu instances sadāļā "Settings -> Security -> OAuth 2.0 client"` auths.tip.dropbox=Izveidojiet jaunu aplikāciju adresē https://www.dropbox.com/developers/apps auths.tip.facebook=`Reģistrējiet jaunu aplikāciju adresē https://developers.facebook.com/apps un pievienojiet produktu "Facebook Login"` auths.tip.github=Reģistrējiet jaunu aplikāciju adresē https://github.com/settings/applications/new auths.tip.google_plus=Iegūstiet OAuth2 klienta pilnvaru no Google API konsoles adresē https://console.developers.google.com/ -auths.tip.openid_connect=Izmantojiet OpenID pieslēgšanās atklāšanas URL (<serveris>/.well-known/openid-configuration), lai norādītu galapunktus auths.tip.twitter=Dodieties uz adresi https://dev.twitter.com/apps, izveidojiet lietotni un pārliecinieties, ka ir atzīmēts “Allow this application to be used to Sign in with Twitter” auths.tip.discord=Reģistrējiet jaunu aplikāciju adresē https://discordapp.com/developers/applications/me auths.tip.gitea=Pievienot jaunu OAuth2 lietojumprogrammu. Dokumentācija ir pieejama https://docs.gitea.com/development/oauth2-provider diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini index 6b5122a86f..b0b081db5d 100644 --- a/options/locale/locale_nl-NL.ini +++ b/options/locale/locale_nl-NL.ini @@ -1016,7 +1016,6 @@ editor.or=of editor.cancel_lower=Annuleer editor.commit_signed_changes=Commit Ondertekende Wijzigingen editor.commit_changes=Wijzigingen doorvoeren -editor.add_tmpl='<filename>' toevoegen editor.patch=Patch toepassen editor.patching=Patchen: editor.new_patch=Nieuwe Patch @@ -2345,7 +2344,6 @@ auths.tip.dropbox=Maak een nieuwe applicatie aan op https://www.dropbox.com/deve auths.tip.facebook=Registreer een nieuwe applicatie op https://developers.facebook.com/apps en voeg het product "Facebook Login" toe auths.tip.github=Registreer een nieuwe OAuth toepassing op https://github.com/settings/applications/new auths.tip.google_plus=Verkrijg OAuth2 client referenties van de Google API console op https://console.developers.google.com/ -auths.tip.openid_connect=Gebruik de OpenID Connect Discovery URL (<server>/.well-known/openid-configuration) om de eindpunten op te geven auths.tip.yandex=`Maak een nieuwe applicatie aan op https://oauth.yandex.com/client/new. Selecteer de volgende machtigingen van de "Yandex". assport API sectie: "Toegang tot e-mailadres", "Toegang tot avatar" en "Toegang tot gebruikersnaam, voornaam en achternaam, geslacht"` auths.edit=Authenticatiebron bewerken auths.activated=Deze authenticatiebron is geactiveerd diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini index a1d7e95842..fd5db4109f 100644 --- a/options/locale/locale_pl-PL.ini +++ b/options/locale/locale_pl-PL.ini @@ -950,7 +950,6 @@ editor.or=lub editor.cancel_lower=Anuluj editor.commit_signed_changes=Zatwierdź podpisane zmiany editor.commit_changes=Zatwierdź zmiany -editor.add_tmpl=Dodanie '<filename>' editor.commit_message_desc=Dodaj dodatkowy rozszerzony opis… editor.commit_directly_to_this_branch=Zmieniaj bezpośrednio gałąź <strong class="branch-name">%s</strong>. editor.create_new_branch=Stwórz <strong>nową gałąź</strong> dla tego commita i rozpocznij Pull Request. @@ -2223,13 +2222,11 @@ auths.sspi_default_language_helper=Domyślny język dla użytkowników automatyc auths.tips=Wskazówki auths.tips.oauth2.general=Uwierzytelnianie OAuth2 auths.tip.oauth2_provider=Dostawca OAuth2 -auths.tip.bitbucket=`Zarejestruj nowego konsumenta OAuth na https://bitbucket.org/account/user/<twoja nazwa użytkownika>/oauth-consumers/new i dodaj uprawnienie "Account" - "Read"` auths.tip.nextcloud=`Zarejestruj nowego klienta OAuth w swojej instancji za pomocą menu "Ustawienia -> Bezpieczeństwo -> Klient OAuth 2.0"` auths.tip.dropbox=Stwórz nową aplikację na https://www.dropbox.com/developers/apps auths.tip.facebook=`Zarejestruj nową aplikację na https://developers.facebook.com/apps i dodaj produkt "Facebook Login"` auths.tip.github=Zarejestruj nową aplikację OAuth na https://github.com/settings/applications/new auths.tip.google_plus=Uzyskaj dane uwierzytelniające klienta OAuth2 z konsoli Google API na https://console.developers.google.com/ -auths.tip.openid_connect=Użyj adresu URL OpenID Connect Discovery (<server>/.well-known/openid-configuration), aby określić punkty końcowe auths.tip.twitter=Przejdź na https://dev.twitter.com/apps, stwórz aplikację i upewnij się, że opcja “Allow this application to be used to Sign in with Twitter” jest włączona auths.tip.discord=Zarejestruj nową aplikację na https://discordapp.com/developers/applications/me auths.tip.yandex=`Utwórz nową aplikację na https://oauth.yandex.com/client/new. Wybierz następujące uprawnienia z "Yandex.Passport API": "Access to email address", "Access to user avatar" and "Access to username, first name and surname, gender"` diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 45f1c3b3f8..5a058c807b 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -652,7 +652,6 @@ cancel=Cancelar language=Idioma ui=Tema hidden_comment_types=Tipos de comentários ocultos -hidden_comment_types_description=Os tipos de comentários marcados aqui não serão exibidos nas páginas de issues. Marcar "Rótulo", por exemplo, remove todos os comentários "<usuário> adicionou/removeu <rótulo>". hidden_comment_types.ref_tooltip=Comentários onde este issue foi referenciado de outro issue/commit/… hidden_comment_types.issue_ref_tooltip=Comentários onde o usuário altera o branch/tag associado ao issue comment_type_group_reference=Referência @@ -1212,7 +1211,6 @@ editor.or=ou editor.cancel_lower=Cancelar editor.commit_signed_changes=Commit de alteradores assinadas editor.commit_changes=Aplicar commit das alterações -editor.add_tmpl=Adicionar '<filename>' editor.add=Adicionar %s editor.update=Atualizar %s editor.delete=Excluir %s @@ -2918,13 +2916,11 @@ auths.tips=Dicas auths.tips.oauth2.general=Autenticação OAuth2 auths.tips.oauth2.general.tip=Ao registrar uma nova autenticação OAuth2, o URL de retorno de chamada/redirecionamento deve ser: auths.tip.oauth2_provider=Provedor OAuth2 -auths.tip.bitbucket=Cadastrar um novo consumidor de OAuth em https://bitbucket.org/account/user/<seu nome de usuário> e adicionar a permissão 'Account' - 'Read' auths.tip.nextcloud=`Registre um novo consumidor OAuth em sua instância usando o seguinte menu "Configurações -> Segurança -> Cliente OAuth 2.0"` auths.tip.dropbox=Criar um novo aplicativo em https://www.dropbox.com/developers/apps auths.tip.facebook=`Cadastrar um novo aplicativo em https://developers.facebook.com/apps e adicionar o produto "Facebook Login"` auths.tip.github=Cadastrar um novo aplicativo de OAuth na https://github.com/settings/applications/new auths.tip.google_plus=Obter credenciais de cliente OAuth2 do console de API do Google em https://console.developers.google.com/ -auths.tip.openid_connect=Use o OpenID Connect Discovery URL (<servidor>/.well-known/openid-configuration) para especificar os endpoints auths.tip.twitter=Vá em https://dev.twitter.com/apps, crie um aplicativo e certifique-se de que está habilitada a opção “Allow this application to be used to Sign in with Twitter“ auths.tip.discord=Cadastrar um novo aplicativo em https://discordapp.com/developers/applications/me auths.tip.yandex=`Crie um novo aplicativo em https://oauth.yandex.com/client/new. Selecione as seguintes permissões da seção "Yandex.Passport API": "Access to email address", "Access to user avatar" and "Access to username, first name and surname, gender"` diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 59b3d3df67..4f21b881c5 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -164,8 +164,6 @@ search=Pesquisar... type_tooltip=Tipo de pesquisa fuzzy=Aproximada fuzzy_tooltip=Incluir também os resultados que estejam próximos do termo de pesquisa -match=Fiel -match_tooltip=Incluir somente os resultados que correspondam rigorosamente ao termo de pesquisa repo_kind=Pesquisar repositórios... user_kind=Pesquisar utilizadores... org_kind=Pesquisar organizações... @@ -714,7 +712,6 @@ cancel=Cancelar language=Idioma ui=Tema hidden_comment_types=Tipos de comentários ocultos -hidden_comment_types_description=Os tipos de comentário marcados aqui não serão mostrados dentro das páginas das questões. Marcar "Rótulo", por exemplo, remove todos os comentários "<utilizador> adicionou/removeu <rótulo>". hidden_comment_types.ref_tooltip=Comentários onde esta questão foi referenciada a partir de outra questão/cometimento/… hidden_comment_types.issue_ref_tooltip=Comentários onde o utilizador altera o ramo/etiqueta associado à questão comment_type_group_reference=Referência @@ -1289,7 +1286,6 @@ editor.or=ou editor.cancel_lower=Cancelar editor.commit_signed_changes=Cometer modificações assinadas editor.commit_changes=Cometer modificações -editor.add_tmpl=Adicionar '<filename>' editor.add=Adicionar %s editor.update=Modificar %s editor.delete=Eliminar %s @@ -3087,14 +3083,12 @@ 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 https://bitbucket.org/account/user/<o_seu_nome_de_utilizador>/oauth-consumers/new 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 https://www.dropbox.com/developers/apps auths.tip.facebook=`Registe uma nova aplicação em https://developers.facebook.com/apps e adicione o produto "Facebook Login"` auths.tip.github=Registe uma nova aplicação OAuth em https://github.com/settings/applications/new auths.tip.gitlab_new=Registe uma nova aplicação em https://gitlab.com/-/profile/applications auths.tip.google_plus=Obtenha credenciais de cliente OAuth2 a partir da consola do Google API em https://console.developers.google.com/ -auths.tip.openid_connect=Use o URL da descoberta de conexão OpenID (<server>/.well-known/openid-configuration) para especificar os extremos auths.tip.twitter=`Vá a https://dev.twitter.com/apps, 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 https://discordapp.com/developers/applications/me auths.tip.gitea=Registe uma nova aplicação OAuth2. O guia pode ser encontrado em https://docs.gitea.com/development/oauth2-provider diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index 818dad1147..d4098aa952 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -649,7 +649,6 @@ cancel=Отмена language=Язык ui=Тема hidden_comment_types=Скрытые типы комментариев -hidden_comment_types_description=Отмеченные типы комментариев не будут отображаться на страницах задач. Например, если выбрать «Метки», не станет всех комментариев «<пользователь> добавил/удалил <метку>». hidden_comment_types.ref_tooltip=Комментарии об упоминании задачи в другой задаче/коммите/… hidden_comment_types.issue_ref_tooltip=Комментарии об изменении ветки/тега, связанных с этой задачей comment_type_group_reference=Упоминания @@ -1192,7 +1191,6 @@ editor.or=или editor.cancel_lower=Отменить editor.commit_signed_changes=Зафиксировать подписанные изменения editor.commit_changes=Сохранить правки -editor.add_tmpl=Добавить '<filename>' editor.add=Добавить %s editor.update=Обновить %s editor.delete=Удалить %s @@ -2909,13 +2907,11 @@ auths.sspi_default_language_helper=Язык по умолчанию для по auths.tips=Советы auths.tips.oauth2.general=Аутентификация OAuth2 auths.tip.oauth2_provider=Поставщик OAuth2 -auths.tip.bitbucket=`Создайте OAuth URI на странице https://bitbucket.org/account/user/<имя пользователя>/oauth-consumers/new и добавьте права "Account" - "Read"` auths.tip.nextcloud=`Зарегистрируйте нового потребителя OAuth в вашем экземпляре, используя меню "Settings -> Security -> OAuth 2.0 client"` 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.google_plus=Получите учётные данные клиента OAuth2 в консоли Google API на странице https://console.developers.google.com/ -auths.tip.openid_connect=Используйте OpenID Connect Discovery URL (<server>/.well-known/openid-configuration) для автоматической настройки входа OAuth auths.tip.twitter=Перейдите на https://dev.twitter.com/apps, создайте приложение и убедитесь, что включена опция «Разрешить это приложение для входа в систему с помощью Twitter» auths.tip.discord=Добавьте новое приложение на https://discordapp.com/developers/applications/me auths.tip.yandex=`Создайте новое приложение по адресу https://oauth.yandex.com/client/new. В разделе "API Яндекс.Паспорта" выберите следующие разрешения: "Доступ к адресу электронной почты", "Доступ к аватару пользователя" и "Доступ к имени пользователя, фамилии и полу"` diff --git a/options/locale/locale_si-LK.ini b/options/locale/locale_si-LK.ini index 99559802c5..05538af971 100644 --- a/options/locale/locale_si-LK.ini +++ b/options/locale/locale_si-LK.ini @@ -919,7 +919,6 @@ editor.or=හෝ editor.cancel_lower=අවලංගු කරන්න editor.commit_signed_changes=අත්සන් කළ වෙනස්කම් සිදු කරන්න editor.commit_changes=වෙනස්කම් සිදු කරන්න -editor.add_tmpl='<filename>' එකතු කරන්න editor.commit_message_desc=විකල්ප දීර්ඝ විස්තරයක් එක් කරන්න… editor.signoff_desc=කැපවූ ලොග් පණිවිඩය අවසානයේ දී කැපකරු විසින් සිග්නෙඩ්-ඕෆ්-විසින් ට්රේලරයක් එක් කරන්න. editor.commit_directly_to_this_branch=<strong class="branch-name">%s</strong> ශාඛාවට කෙලින්ම කැප කරන්න. @@ -2261,7 +2260,6 @@ auths.tip.dropbox=https://www.dropbox.com/developers/apps හි නව යෙ auths.tip.facebook=https://developers.facebook.com/apps හි නව යෙදුමක් ලියාපදිංචි කර නිෂ්පාදනය එකතු කරන්න “ෆේස්බුක් ලොගින් වන්න” auths.tip.github=https://github.com/settings/applications/new හි නව OAUTH අයදුම්පතක් ලියාපදිංචි කරන්න auths.tip.google_plus=ගූගල් API කොන්සෝලය වෙතින් OUT2 සේවාදායක අක්තපත්ර ලබා ගන්න https://console.developers.google.com/ -auths.tip.openid_connect=අන්ත ලක්ෂ්ය නියම කිරීම සඳහා OpenID Connect ඩිස්කවරි URL (<server>/.හොඳින් දැන /openid-වින්යාසය) භාවිතා කරන්න auths.tip.twitter=https://dev.twitter.com/apps වෙත යන්න, යෙදුමක් සාදන්න සහ “මෙම යෙදුම ට්විටර් සමඟ පුරනය වීමට භාවිතා කිරීමට ඉඩ දෙන්න” විකල්පය සක්රීය කර ඇති බවට සහතික වන්න auths.tip.discord=https://discordapp.com/developers/applications/me හි නව අයදුම්පතක් ලියාපදිංචි කරන්න auths.tip.yandex=https://oauth.yandex.com/client/new හි නව යෙදුමක් සාදන්න. “Yandex.Passport API” කොටසේ පහත සඳහන් අවසරයන් තෝරන්න: “විද්යුත් තැපැල් ලිපිනය වෙත ප්රවේශය”, “පරිශීලක අවතාර් වෙත ප්රවේශය” සහ “පරිශීලක නාමය, මුල් නම සහ වාසගම, ස්ත්රී පුරුෂ භාවය” diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini index 9234e9aa58..5fe6288ad6 100644 --- a/options/locale/locale_sv-SE.ini +++ b/options/locale/locale_sv-SE.ini @@ -779,7 +779,6 @@ editor.or=eller editor.cancel_lower=Avbryt editor.commit_signed_changes=Committa signerade ändringar editor.commit_changes=Checka in ändringar -editor.add_tmpl=Lägg till '<filename>' editor.commit_message_desc=Lägg till en valfri utökad beskrivning… editor.commit_directly_to_this_branch=Checka in direkt till grenen <strong class="branch-name">%s</strong>. editor.create_new_branch=Skapa en <strong>ny gren</strong> för denna incheckning och påbörja en hämtningsbegäran. @@ -1801,12 +1800,10 @@ auths.enable_auto_register=Aktivera Automatisk Registrering auths.tips=Tips auths.tips.oauth2.general=OAuth2 Autensiering auths.tip.oauth2_provider=OAuth2 leverantör -auths.tip.bitbucket=Registrera en ny OAuth konsument på https://bitbucket.org/account/user/<your username>/oauth-consumers/new och lägg till behörighet 'Account' - 'Read' auths.tip.dropbox=Skapa en ny applikation på https://www.dropbox.com/developers/apps auths.tip.facebook=Registrera en ny appliaktion på https://developers.facebook.com/apps och lägg till produkten ”Facebook-inloggning” auths.tip.github=Registrera en ny OAuth applikation på https://github.com/settings/applications/new auths.tip.google_plus=Erhåll inloggningsuppgifter för OAuth2 från Google API-konsolen på https://console.developers.google.com/ -auths.tip.openid_connect=Använd OpenID Connect Discovery länken (<server>/.well-known/openid-configuration) för att ange slutpunkterna auths.tip.twitter=Gå till https://dev.twitter.com/app, skapa en applikation och försäkra att alternativet "Allow this application to be used to Sign in with Twitter" är aktiverat auths.tip.discord=Registrera en ny applikation på https://discordapp.com/developers/applications/me auths.edit=Redigera autensieringskälla diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index 119e1ef150..acc21d24e1 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -651,7 +651,6 @@ cancel=İptal language=Dil ui=Tema hidden_comment_types=Gizli yorum türleri -hidden_comment_types_description=Burada işaretlenen yorum türleri konu sayfalarında görüntülenmeyecektir. Örneğin "Etiket" seçildiğinde tüm "<user>, <label> ekledi/çıkardı" yorumları kalkacaktır. hidden_comment_types.ref_tooltip=Bu konuya başka konu/işlem tarafından değinilen yorumlar… hidden_comment_types.issue_ref_tooltip=Kullanıcının konuyla ilişkili dalı/etiketi değiştirdiği yorumlar comment_type_group_reference=Referans @@ -1214,7 +1213,6 @@ editor.or=veya editor.cancel_lower=İptal editor.commit_signed_changes=İmzalı Değişiklikleri İşle editor.commit_changes=Değişiklikleri Uygula -editor.add_tmpl='<dosyaadi>' eklendi editor.add=%s Ekle editor.update=%s Güncelle editor.delete=%s Sil @@ -2970,13 +2968,11 @@ auths.tips=İpuçları auths.tips.oauth2.general=OAuth2 Kimlik Doğrulama auths.tips.oauth2.general.tip=Yeni bir OAuth2 kimlik doğrulama kaydederken, geri çağırma/yönlendirme URL'si şu olmalıdır: auths.tip.oauth2_provider=OAuth2 Sağlayıcısı -auths.tip.bitbucket=https://bitbucket.org/account/user/<kullanıcı adınız>/oauth-consumers/new adında yeni bir OAuth tüketicisi kaydedin ve 'Hesap' - 'Oku' iznini ekleyin auths.tip.nextcloud=Aşağıdaki "Ayarlar -> Güvenlik -> OAuth 2.0 istemcisi" menüsünü kullanarak örneğinize yeni bir OAuth tüketicisi kaydedin auths.tip.dropbox=https://www.dropbox.com/developers/apps adresinde yeni bir uygulama oluştur auths.tip.facebook=https://developers.facebook.com/apps adresinde yeni bir uygulama kaydedin ve "Facebook Giriş" ürününü ekleyin auths.tip.github=https://github.com/settings/applications/new adresinde yeni bir OAuth uygulaması kaydedin auths.tip.google_plus=OAuth2 istemci kimlik bilgilerini https://console.developers.google.com/ adresindeki Google API konsolundan edinin -auths.tip.openid_connect=Bitiş noktalarını belirlemek için OpenID Connect Discovery URL'sini kullanın (<server>/.well-known/openid-configuration) auths.tip.twitter=https://dev.twitter.com/apps adresine gidin, bir uygulama oluşturun ve “Bu uygulamanın Twitter ile oturum açmak için kullanılmasına izin ver” seçeneğinin etkin olduğundan emin olun auths.tip.discord=https://discordapp.com/developers/applications/me adresinde yeni bir uygulama kaydedin auths.tip.gitea=Yeni bir OAuth2 uygulaması kaydedin. Rehber https://docs.gitea.com/development/oauth2-provider adresinde bulunabilir diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini index e8a3acedda..613f39b3c9 100644 --- a/options/locale/locale_uk-UA.ini +++ b/options/locale/locale_uk-UA.ini @@ -955,7 +955,6 @@ editor.or=або editor.cancel_lower=Скасувати editor.commit_signed_changes=Внести підписані зміни editor.commit_changes=Закомітити зміни -editor.add_tmpl=Додати '<filename>' editor.commit_message_desc=Додати необов'язковий розширений опис… editor.signoff_desc=Додатиь Signed-off-by комітом в конці повідомлення журналу комітів. editor.commit_directly_to_this_branch=Зробіть коміт прямо в гілку <strong class="branch-name">%s</strong>. @@ -2306,13 +2305,11 @@ auths.sspi_default_language_helper=Типова мова для користув auths.tips=Поради auths.tips.oauth2.general=OAuth2 автентифікація auths.tip.oauth2_provider=Постачальник OAuth2 -auths.tip.bitbucket=Створіть OAuth URI на сторінці https://bitbucket.org/account/user/<your username>/oauth-consumers/new і додайте права 'Account' - 'Read' auths.tip.nextcloud=`Зареєструйте нового споживача OAuth у вашому екземплярі за допомогою наступного меню "Налаштування -> Безпека -> клієнт OAuth 2.0"` 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.google_plus=Отримайте облікові дані клієнта OAuth2 в консолі Google API на сторінці https://console.developers.google.com/ -auths.tip.openid_connect=Використовуйте OpenID Connect Discovery URL (<server>/.well-known/openid-configuration) для автоматичної настройки входу OAuth auths.tip.twitter=Перейдіть на https://dev.twitter.com/apps, створіть програму і переконайтеся, що включена опція «Дозволити цю програму для входу в систему за допомогою Twitter» auths.tip.discord=Зареєструйте новий додаток на https://discordapp.com/developers/applications/me auths.tip.yandex=`Створіть нову програму в https://oauth.yandex.com/client/new. Виберіть наступні дозволи з "Yandex. assport API": "Доступ до адреси електронної пошти", "Доступ до аватара" і "Доступ до імені користувача, імені та прізвища, статі"` diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 78460ad2f8..fcc34e9177 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -164,8 +164,6 @@ search=搜索... type_tooltip=搜索类型 fuzzy=模糊 fuzzy_tooltip=包含近似匹配搜索词的结果 -match=匹配 -match_tooltip=仅包含精确匹配搜索词的结果 repo_kind=搜索仓库... user_kind=搜索用户... org_kind=搜索组织... @@ -714,7 +712,6 @@ cancel=取消操作 language=界面语言 ui=主题 hidden_comment_types=隐藏的评论类型 -hidden_comment_types_description=此处选中的注释类型不会显示在问题页面中。比如,勾选”标签“删除所有 "<user> 添加/删除的 <label>" 注释。 hidden_comment_types.ref_tooltip=注释此问题在何处被提及过,如另一个问题、代码提交等 hidden_comment_types.issue_ref_tooltip=注释用户在何处更改了与此问题相关联的分支/标签 comment_type_group_reference=引用 @@ -1289,7 +1286,6 @@ editor.or=或 editor.cancel_lower=取消 editor.commit_signed_changes=提交已签名的更改 editor.commit_changes=提交变更 -editor.add_tmpl=添加 '<filename>' editor.add=添加 %s editor.update=更新 %s editor.delete=删除 %s @@ -3087,14 +3083,12 @@ auths.tips=帮助提示 auths.tips.oauth2.general=OAuth2 认证 auths.tips.oauth2.general.tip=当注册新的 OAuth2 身份验证时,回调/重定向 URL 应该是: auths.tip.oauth2_provider=OAuth2 提供程序 -auths.tip.bitbucket=`在 https://bitbucket.org/account/user/<your username>/oauth-consumers/new 注册新的 OAuth 消费者同时添加权限"帐户"-"读"` auths.tip.nextcloud=使用下面的菜单“设置(Settings) -> 安全(Security) -> OAuth 2.0 client”在您的实例上注册一个新的 OAuth 客户端。 auths.tip.dropbox=在 https://www.dropbox.com/developers/apps 上创建一个新的应用程序 auths.tip.facebook=`在 https://developers.facebook.com/apps 注册一个新的应用,并添加产品"Facebook 登录"` auths.tip.github=在 https://github.com/settings/applications/new 注册一个 OAuth 应用程序 auths.tip.gitlab_new=在 https://gitlab.com/-/profile/applications 注册一个新的应用 auths.tip.google_plus=从谷歌 API 控制台 (https://console.developers.google.com/) 获得 OAuth2 客户端凭据 -auths.tip.openid_connect=使用 OpenID 连接发现 URL (<server>/.well-known/openid-configuration) 来指定终点 auths.tip.twitter=访问 https://dev.twitter.com/apps,创建应用并确保启用了"允许此应用程序用于登录 Twitter"的选项。 auths.tip.discord=在 https://discordapp.com/developers/applications/me 上注册新应用程序 auths.tip.gitea=注册一个新的 OAuth2 应用程序。可以访问 https://docs.gitea.com/development/oauth2-provider 查看帮助 diff --git a/options/locale/locale_zh-HK.ini b/options/locale/locale_zh-HK.ini index d4b65239a6..2dbdeb2bae 100644 --- a/options/locale/locale_zh-HK.ini +++ b/options/locale/locale_zh-HK.ini @@ -809,7 +809,6 @@ auths.tip.oauth2_provider=OAuth2 提供者 auths.tip.dropbox=建立新 App 在 https://www.dropbox.com/developers/apps auths.tip.facebook=`在 https://developers.facebook.com/apps 註冊一個新的應用,並且新增一個產品 "Facebook Login"` auths.tip.github=在 https://github.com/settings/applications/new 註冊一個新的 OAuth 應用程式 -auths.tip.openid_connect=使用 OpenID 連接探索 URL (<server>/.well-known/openid-configuration) 來指定節點 auths.delete=刪除認證來源 auths.delete_auth_title=刪除認證來源 diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini index 0447a7d8b7..3e7bd4ae20 100644 --- a/options/locale/locale_zh-TW.ini +++ b/options/locale/locale_zh-TW.ini @@ -1103,7 +1103,6 @@ editor.or=或 editor.cancel_lower=取消 editor.commit_signed_changes=提交簽署過的變更 editor.commit_changes=提交變更 -editor.add_tmpl=新增「<filename>」 editor.add=新增 %s editor.update=更新 %s editor.delete=刪除 %s @@ -2704,13 +2703,11 @@ auths.sspi_default_language_helper=SSPI 認證方法自動建立之使用者的 auths.tips=幫助提示 auths.tips.oauth2.general=OAuth2 認證 auths.tip.oauth2_provider=OAuth2 提供者 -auths.tip.bitbucket=註冊新的 OAuth 客戶端並加入權限「Account - Read」。網址:https://bitbucket.org/account/user/<your username>/oauth-consumers/new auths.tip.nextcloud=在您的執行個體中,於選單「設定 -> 安全性 -> OAuth 2.0 客戶端」註冊新的 OAuth 客戶端 auths.tip.dropbox=建立新的 App。網址:https://www.dropbox.com/developers/apps auths.tip.facebook=註冊新的應用程式並新增產品「Facebook 登入」。網址:https://developers.facebook.com/apps auths.tip.github=註冊新的 OAuth 應用程式。網址:https://github.com/settings/applications/new auths.tip.google_plus=從 Google API 控制台取得 OAuth2 用戶端憑證。網址:https://console.developers.google.com/ -auths.tip.openid_connect=使用 OpenID 連接探索 URL (<server>/.well-known/openid-configuration) 來指定節點 auths.tip.twitter=建立應用程式並確保有啟用「Allow this application to be used to Sign in with Twitter」。網址:https://dev.twitter.com/apps auths.tip.discord=註冊新的應用程式。網址:https://discordapp.com/developers/applications/me auths.tip.yandex=建立新的應用程式,從「Yandex.Passport API」區塊選擇「Access to email address」、「Access to user avatar」和「Access to username, first name and surname, gender」。網址:https://oauth.yandex.com/client/new From 2da1dcfc21afe6f5373e4271e9ddcc7f31d6695b Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Thu, 18 Apr 2024 11:16:20 +0800 Subject: [PATCH 144/370] Add an api test for updating user (#30539) Fix #30518 --- tests/integration/api_user_update_test.go | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/integration/api_user_update_test.go diff --git a/tests/integration/api_user_update_test.go b/tests/integration/api_user_update_test.go new file mode 100644 index 0000000000..af5481cfd5 --- /dev/null +++ b/tests/integration/api_user_update_test.go @@ -0,0 +1,25 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package integration + +import ( + "net/http" + "testing" + + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/tests" +) + +func TestAPIUpdateUser(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + normalUsername := "user2" + session := loginUser(t, normalUsername) + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteUser) + + req := NewRequestWithJSON(t, "PATCH", "/api/v1/user/settings", map[string]string{ + "website": "https://gitea.com", + }).AddTokenAuth(token) + MakeRequest(t, req, http.StatusOK) +} From 49b80f8ac1cf9f0b56da0c73d0f34ef030f4c447 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Thu, 18 Apr 2024 10:06:56 +0200 Subject: [PATCH 145/370] Disable enter key for accepting code completion in Monaco (#30548) Fixes https://github.com/go-gitea/gitea/issues/28114 and behaviour matches vscode on desktop as well. Co-authored-by: Giteabot <teabot@gitea.io> --- web_src/js/features/codeeditor.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web_src/js/features/codeeditor.js b/web_src/js/features/codeeditor.js index 4fb8bb9e63..f5e4e74dc6 100644 --- a/web_src/js/features/codeeditor.js +++ b/web_src/js/features/codeeditor.js @@ -112,6 +112,10 @@ export async function createMonaco(textarea, filename, editorOpts) { ...other, }); + monaco.editor.addKeybindingRules([ + {keybinding: monaco.KeyCode.Enter, command: null}, // disable enter from accepting code completion + ]); + const model = editor.getModel(); model.onDidChangeContent(() => { textarea.value = editor.getValue({preserveBOM: true}); From 31538133c32009532897989ad623067bd224f924 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Thu, 18 Apr 2024 10:34:23 +0200 Subject: [PATCH 146/370] Fix border-radius on view, blame and code search (#30545) Fixes: https://github.com/go-gitea/gitea/issues/30540 1. Fix all these boxes by adding `bottom attached` and removing a problematic CSS rule: <img width="1319" alt="Screenshot 2024-04-17 at 22 25 31" src="https://github.com/go-gitea/gitea/assets/115237/346445a4-4944-4003-a1ef-6f5b0eda624e"> <img width="643" alt="Screenshot 2024-04-17 at 22 21 18" src="https://github.com/go-gitea/gitea/assets/115237/10f17ed3-9ad6-48de-92fa-bac6621815b9"> 2. Change the "last commit" box to `ui segment` which has correct border-radius. Also included is a tiny tweak to make author name ellipse instead of wrap. <img width="1331" alt="Screenshot 2024-04-17 at 22 23 23" src="https://github.com/go-gitea/gitea/assets/115237/285fbd45-ced0-4d33-abe3-7384ffa03188"> Co-authored-by: Giteabot <teabot@gitea.io> --- templates/repo/blame.tmpl | 2 +- templates/repo/settings/lfs_file.tmpl | 2 +- templates/repo/view_file.tmpl | 4 ++-- web_src/css/repo.css | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/templates/repo/blame.tmpl b/templates/repo/blame.tmpl index ccef8e4b38..4ad3ed85c9 100644 --- a/templates/repo/blame.tmpl +++ b/templates/repo/blame.tmpl @@ -28,7 +28,7 @@ </div> </div> </h4> - <div class="ui attached table unstackable segment"> + <div class="ui bottom attached table unstackable segment"> <div class="file-view code-view unicode-escaped"> {{if .IsFileTooLarge}} {{template "shared/filetoolarge" dict "RawFileLink" .RawFileLink}} diff --git a/templates/repo/settings/lfs_file.tmpl b/templates/repo/settings/lfs_file.tmpl index cb65236f23..a015cc8bd1 100644 --- a/templates/repo/settings/lfs_file.tmpl +++ b/templates/repo/settings/lfs_file.tmpl @@ -11,7 +11,7 @@ <a class="ui primary tiny button" href="{{.LFSFilesLink}}/find?oid={{.LFSFile.Oid}}&size={{.LFSFile.Size}}">{{ctx.Locale.Tr "repo.settings.lfs_findcommits"}}</a> </div> </h4> - <div class="ui attached table unstackable segment"> + <div class="ui bottom attached table unstackable segment"> {{template "repo/unicode_escape_prompt" dict "EscapeStatus" .EscapeStatus "root" $}} <div class="file-view{{if .IsMarkup}} markup {{.MarkupType}}{{else if .IsPlainText}} plain-text{{else if .IsTextFile}} code-view{{end}}"> {{if .IsFileTooLarge}} diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl index da82332066..0a34b6c325 100644 --- a/templates/repo/view_file.tmpl +++ b/templates/repo/view_file.tmpl @@ -11,7 +11,7 @@ {{end}} {{if not .ReadmeInList}} - <div id="repo-file-commit-box" class="ui top attached header list-header tw-mb-4 tw-flex tw-justify-between"> + <div id="repo-file-commit-box" class="ui segment list-header tw-mb-4 tw-flex tw-justify-between"> <div class="latest-commit"> {{template "repo/latest_commit" .}} </div> @@ -84,7 +84,7 @@ {{end}} </div> </h4> - <div class="ui attached table unstackable segment"> + <div class="ui bottom attached table unstackable segment"> {{if not (or .IsMarkup .IsRenderedHTML)}} {{template "repo/unicode_escape_prompt" dict "EscapeStatus" .EscapeStatus "root" $}} {{end}} diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 882d86c4f6..b7da9ce6e0 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -430,7 +430,6 @@ td .commit-summary { padding: 0 !important; } -.non-diff-file-content .attached.segment, .non-diff-file-content .pdfobject { border-radius: 0 0 var(--border-radius) var(--border-radius); } @@ -2282,6 +2281,7 @@ tbody.commit-list { .author-wrapper { max-width: 180px; align-self: center; + white-space: nowrap; } /* in the commit list, messages can wrap so we can use inline */ From d4ec6b3d16496ce3b479d5a08f79823122dc2b7b Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Thu, 18 Apr 2024 11:01:06 +0200 Subject: [PATCH 147/370] Add form field id generation, remove duplicated ids (#30546) Fixes: https://github.com/go-gitea/gitea/issues/30384 On repo settings page, there id `repo_name` was used 5 times on the same page, some in modal and such. I think we are better off just auto-generating these IDs in the future so that labels link up with their form element. Ideally this id generation would be done in backend in a subtemplate, but seeing that we already have similar JS patches for checkboxes, I took the easy path for now. I also checked that these `#repo_name` were not in use in JS and the only case where this id appears in JS is on the migration page where it's still there. --------- Co-authored-by: Giteabot <teabot@gitea.io> --- templates/repo/settings/options.tmpl | 20 ++++++++++---------- web_src/js/modules/fomantic.js | 2 ++ web_src/js/modules/fomantic/base.js | 13 +++++++++++++ web_src/js/modules/fomantic/checkbox.js | 15 ++------------- web_src/js/modules/fomantic/form.js | 13 +++++++++++++ 5 files changed, 40 insertions(+), 23 deletions(-) create mode 100644 web_src/js/modules/fomantic/form.js diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index c0411cfc56..0cd2201c4b 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -9,8 +9,8 @@ {{.CsrfTokenHtml}} <input type="hidden" name="action" value="update"> <div class="required field {{if .Err_RepoName}}error{{end}}"> - <label for="repo_name">{{ctx.Locale.Tr "repo.repo_name"}}</label> - <input id="repo_name" name="repo_name" value="{{.Repository.Name}}" data-repo-name="{{.Repository.Name}}" autofocus required> + <label>{{ctx.Locale.Tr "repo.repo_name"}}</label> + <input name="repo_name" value="{{.Repository.Name}}" data-repo-name="{{.Repository.Name}}" autofocus required> </div> <div class="inline field"> <label>{{ctx.Locale.Tr "repo.repo_size"}}</label> @@ -898,8 +898,8 @@ </label> </div> <div class="required field"> - <label for="repo_name">{{ctx.Locale.Tr "repo.repo_name"}}</label> - <input id="repo_name" name="repo_name" required maxlength="100"> + <label>{{ctx.Locale.Tr "repo.repo_name"}}</label> + <input name="repo_name" required maxlength="100"> </div> <div class="text right actions"> @@ -929,8 +929,8 @@ </label> </div> <div class="required field"> - <label for="repo_name">{{ctx.Locale.Tr "repo.repo_name"}}</label> - <input id="repo_name" name="repo_name" required> + <label>{{ctx.Locale.Tr "repo.repo_name"}}</label> + <input name="repo_name" required> </div> <div class="text right actions"> @@ -961,8 +961,8 @@ </label> </div> <div class="required field"> - <label for="repo_name">{{ctx.Locale.Tr "repo.repo_name"}}</label> - <input id="repo_name" name="repo_name" required> + <label>{{ctx.Locale.Tr "repo.repo_name"}}</label> + <input name="repo_name" required> </div> <div class="required field"> <label for="new_owner_name">{{ctx.Locale.Tr "repo.settings.transfer_owner"}}</label> @@ -1031,8 +1031,8 @@ </label> </div> <div class="required field"> - <label for="repo_name">{{ctx.Locale.Tr "repo.repo_name"}}</label> - <input id="repo_name" name="repo_name" required> + <label>{{ctx.Locale.Tr "repo.repo_name"}}</label> + <input name="repo_name" required> </div> <div class="text right actions"> diff --git a/web_src/js/modules/fomantic.js b/web_src/js/modules/fomantic.js index d205c2b2ee..c04bc6e863 100644 --- a/web_src/js/modules/fomantic.js +++ b/web_src/js/modules/fomantic.js @@ -1,6 +1,7 @@ import $ from 'jquery'; import {initFomanticApiPatch} from './fomantic/api.js'; import {initAriaCheckboxPatch} from './fomantic/checkbox.js'; +import {initAriaFormFieldPatch} from './fomantic/form.js'; import {initAriaDropdownPatch} from './fomantic/dropdown.js'; import {initAriaModalPatch} from './fomantic/modal.js'; import {initFomanticTransition} from './fomantic/transition.js'; @@ -27,6 +28,7 @@ export function initGiteaFomantic() { // Use the patches to improve accessibility, these patches are designed to be as independent as possible, make it easy to modify or remove in the future. initAriaCheckboxPatch(); + initAriaFormFieldPatch(); initAriaDropdownPatch(); initAriaModalPatch(); } diff --git a/web_src/js/modules/fomantic/base.js b/web_src/js/modules/fomantic/base.js index c4a01038ba..7574fdd25c 100644 --- a/web_src/js/modules/fomantic/base.js +++ b/web_src/js/modules/fomantic/base.js @@ -3,3 +3,16 @@ let ariaIdCounter = 0; export function generateAriaId() { return `_aria_auto_id_${ariaIdCounter++}`; } + +export function linkLabelAndInput(label, input) { + const labelFor = label.getAttribute('for'); + const inputId = input.getAttribute('id'); + + if (inputId && !labelFor) { // missing "for" + label.setAttribute('for', inputId); + } else if (!inputId && !labelFor) { // missing both "id" and "for" + const id = generateAriaId(); + input.setAttribute('id', id); + label.setAttribute('for', id); + } +} diff --git a/web_src/js/modules/fomantic/checkbox.js b/web_src/js/modules/fomantic/checkbox.js index 7f2b340296..ed77406cc3 100644 --- a/web_src/js/modules/fomantic/checkbox.js +++ b/web_src/js/modules/fomantic/checkbox.js @@ -1,4 +1,4 @@ -import {generateAriaId} from './base.js'; +import {linkLabelAndInput} from './base.js'; export function initAriaCheckboxPatch() { // link the label and the input element so it's clickable and accessible @@ -7,18 +7,7 @@ export function initAriaCheckboxPatch() { const label = el.querySelector('label'); const input = el.querySelector('input'); if (!label || !input) continue; - const inputId = input.getAttribute('id'); - const labelFor = label.getAttribute('for'); - - if (inputId && !labelFor) { // missing "for" - label.setAttribute('for', inputId); - } else if (!inputId && !labelFor) { // missing both "id" and "for" - const id = generateAriaId(); - input.setAttribute('id', id); - label.setAttribute('for', id); - } else { - continue; - } + linkLabelAndInput(label, input); el.setAttribute('data-checkbox-patched', 'true'); } } diff --git a/web_src/js/modules/fomantic/form.js b/web_src/js/modules/fomantic/form.js new file mode 100644 index 0000000000..3bb0058902 --- /dev/null +++ b/web_src/js/modules/fomantic/form.js @@ -0,0 +1,13 @@ +import {linkLabelAndInput} from './base.js'; + +export function initAriaFormFieldPatch() { + // link the label and the input element so it's clickable and accessible + for (const el of document.querySelectorAll('.ui.form .field')) { + if (el.hasAttribute('data-field-patched')) continue; + const label = el.querySelector(':scope > label'); + const input = el.querySelector(':scope > input'); + if (!label || !input) continue; + linkLabelAndInput(label, input); + el.setAttribute('data-field-patched', 'true'); + } +} From d1ba5f431b09cf2a1f814ce0b3feb4c1d4755844 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Thu, 18 Apr 2024 17:36:19 +0800 Subject: [PATCH 148/370] Some following up changes for routes (#30550) 1. Switch back to the old order for `reqRepoAdmin, context.RepoRef()` 2. Add a routing function info for global NotFound --- routers/web/web.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/routers/web/web.go b/routers/web/web.go index f9164568ed..a6a4c1d987 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -54,10 +54,7 @@ import ( "github.com/prometheus/client_golang/prometheus" ) -const ( - // GzipMinSize represents min size to compress for the body size of response - GzipMinSize = 1400 -) +const GzipMinSize = 1400 // min size to compress for the body size of response // optionsCorsHandler return a http handler which sets CORS options if enabled by config, it blocks non-CORS OPTIONS requests. func optionsCorsHandler() func(next http.Handler) http.Handler { @@ -1115,7 +1112,7 @@ func registerRoutes(m *web.Route) { m.Post("/cancel", repo.MigrateCancelPost) }) }, - reqSignIn, context.RepoAssignment, context.RepoRef(), reqRepoAdmin, + reqSignIn, context.RepoAssignment, reqRepoAdmin, context.RepoRef(), ctxDataSet("PageIsRepoSettings", true, "LFSStartServer", setting.LFS.StartServer), ) // end "/{username}/{reponame}/settings" @@ -1613,6 +1610,7 @@ func registerRoutes(m *web.Route) { m.NotFound(func(w http.ResponseWriter, req *http.Request) { ctx := context.GetWebContext(req) + routing.UpdateFuncInfo(ctx, routing.GetFuncInfo(ctx.NotFound, "GlobalNotFound")) ctx.NotFound("", nil) }) } From 86d4c8a4662e9ab49888569d77529d2d22292e6b Mon Sep 17 00:00:00 2001 From: Jerry Jacobs <xor-gate@users.noreply.github.com> Date: Thu, 18 Apr 2024 13:22:06 +0200 Subject: [PATCH 149/370] Fixup app.example.ini for task section, which is now queue.task (#30555) Config section `[task]` has been deprecated in favor of `[queue.task]` --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> --- custom/conf/app.example.ini | 16 ---------------- .../administration/config-cheat-sheet.en-us.md | 8 -------- .../administration/config-cheat-sheet.zh-cn.md | 9 --------- 3 files changed, 33 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 32b51fd7c6..b4e330184e 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -2377,22 +2377,6 @@ LEVEL = Info ;; Enable issue by repository metrics; default is false ;ENABLED_ISSUE_BY_REPOSITORY = false -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;[task] -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; Task queue type, could be `channel` or `redis`. -;QUEUE_TYPE = channel -;; -;; Task queue length, available only when `QUEUE_TYPE` is `channel`. -;QUEUE_LENGTH = 1000 -;; -;; Task queue connection string, available only when `QUEUE_TYPE` is `redis`. -;; If there is a password of redis, use `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` or `redis+cluster://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` for `redis-clsuter`. -;QUEUE_CONN_STR = "redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s" - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;[migrations] diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index ff8bcb066c..9328177f50 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -1198,14 +1198,6 @@ in this mapping or the filetype using heuristics. - `DEFAULT_UI_LOCATION`: Default location of time on the UI, so that we can display correct user's time on UI. i.e. Asia/Shanghai -## Task (`task`) - -Task queue configuration has been moved to `queue.task`. However, the below configuration values are kept for backwards compatibility: - -- `QUEUE_TYPE`: **channel**: Task queue type, could be `channel` or `redis`. -- `QUEUE_LENGTH`: **1000**: Task queue length, available only when `QUEUE_TYPE` is `channel`. -- `QUEUE_CONN_STR`: **redis://127.0.0.1:6379/0**: Task queue connection string, available only when `QUEUE_TYPE` is `redis`. If redis needs a password, use `redis://123@127.0.0.1:6379/0` or `redis+cluster://123@127.0.0.1:6379/0`. - ## Migrations (`migrations`) - `MAX_ATTEMPTS`: **3**: Max attempts per http/https request on migrations. diff --git a/docs/content/administration/config-cheat-sheet.zh-cn.md b/docs/content/administration/config-cheat-sheet.zh-cn.md index 759f39b576..e4945dd1c1 100644 --- a/docs/content/administration/config-cheat-sheet.zh-cn.md +++ b/docs/content/administration/config-cheat-sheet.zh-cn.md @@ -1128,15 +1128,6 @@ ALLOW_DATA_URI_IMAGES = true - `DEFAULT_UI_LOCATION`:在 UI 上的默认时间位置,以便我们可以在 UI 上显示正确的用户时间。例如:Asia/Shanghai -## 任务 (`task`) - -任务队列配置已移动到 `queue.task`。然而,以下配置值仍保留以确保向后兼容: - -- `QUEUE_TYPE`:**channel**:任务队列类型,可以是 `channel` 或 `redis`。 -- `QUEUE_LENGTH`:**1000**:任务队列长度,仅在 `QUEUE_TYPE` 为 `channel` 时可用。 -- `QUEUE_CONN_STR`:**redis://127.0.0.1:6379/0**:任务队列连接字符串,仅在 `QUEUE_TYPE` 为 `redis` 时可用。 - 如果 redis 需要密码,使用 `redis://123@127.0.0.1:6379/0` 或 `redis+cluster://123@127.0.0.1:6379/0`。 - ## 迁移 (`migrations`) - `MAX_ATTEMPTS`:**3**:每次 http/https 请求的最大尝试次数(用于迁移)。 From d0e07083559180b124a08359fcc72f9ef695e723 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Fri, 19 Apr 2024 00:45:50 +0800 Subject: [PATCH 150/370] Refactor and fix archive link bug (#30535) Regression of #29920 Fixes: #30569 Also this is a rewriting to eliminate the remaining jQuery usages from code. Co-authored-by: Giteabot <teabot@gitea.io> --- web_src/js/features/repo-common.js | 54 ++++++++++++------------------ web_src/js/utils/dom.js | 4 +++ 2 files changed, 26 insertions(+), 32 deletions(-) diff --git a/web_src/js/features/repo-common.js b/web_src/js/features/repo-common.js index b750addb07..88aa93d850 100644 --- a/web_src/js/features/repo-common.js +++ b/web_src/js/features/repo-common.js @@ -1,45 +1,35 @@ import $ from 'jquery'; -import {hideElem, showElem} from '../utils/dom.js'; +import {hideElem, queryElems, showElem} from '../utils/dom.js'; import {POST} from '../modules/fetch.js'; +import {showErrorToast} from '../modules/toast.js'; +import {sleep} from '../utils.js'; -async function getArchive($target, url, first) { - const dropdownBtn = $target[0].closest('.ui.dropdown.button') ?? $target[0].closest('.ui.dropdown.btn'); - +async function onDownloadArchive(e) { + e.preventDefault(); + // there are many places using the "archive-link", eg: the dropdown on the repo code page, the release list + const el = e.target.closest('a.archive-link[href]'); + const targetLoading = el.closest('.ui.dropdown') ?? el; + targetLoading.classList.add('is-loading', 'loading-icon-2px'); try { - dropdownBtn.classList.add('is-loading'); - const response = await POST(url); - if (response.status === 200) { - const data = await response.json(); - if (!data) { - // XXX Shouldn't happen? - dropdownBtn.classList.remove('is-loading'); - return; - } + for (let tryCount = 0; ;tryCount++) { + const response = await POST(el.href); + if (!response.ok) throw new Error(`Invalid server response: ${response.status}`); - if (!data.complete) { - // Wait for only three quarters of a second initially, in case it's - // quickly archived. - setTimeout(() => { - getArchive($target, url, false); - }, first ? 750 : 2000); - } else { - // We don't need to continue checking. - dropdownBtn.classList.remove('is-loading'); - window.location.href = url; - } + const data = await response.json(); + if (data.complete) break; + await sleep(Math.min((tryCount + 1) * 750, 2000)); } - } catch { - dropdownBtn.classList.remove('is-loading'); + window.location.href = el.href; // the archive is ready, start real downloading + } catch (e) { + console.error(e); + showErrorToast(`Failed to download the archive: ${e}`, {duration: 2500}); + } finally { + targetLoading.classList.remove('is-loading', 'loading-icon-2px'); } } export function initRepoArchiveLinks() { - $('.archive-link').on('click', function (event) { - event.preventDefault(); - const url = this.getAttribute('href'); - if (!url) return; - getArchive($(event.target), url, true); - }); + queryElems('a.archive-link[href]', (el) => el.addEventListener('click', onDownloadArchive)); } export function initRepoCloneLink() { diff --git a/web_src/js/utils/dom.js b/web_src/js/utils/dom.js index fb23a71725..a48510b191 100644 --- a/web_src/js/utils/dom.js +++ b/web_src/js/utils/dom.js @@ -69,6 +69,10 @@ export function queryElemChildren(parent, selector = '*', fn) { return applyElemsCallback(parent.querySelectorAll(`:scope > ${selector}`), fn); } +export function queryElems(selector, fn) { + return applyElemsCallback(document.querySelectorAll(selector), fn); +} + export function onDomReady(cb) { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', cb); From 354705450a410329d253023d2c66ef6d68ecc046 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Thu, 18 Apr 2024 20:54:40 +0200 Subject: [PATCH 151/370] Add a few root files to lint-spell (#30530) Files in root were not linted, add them. No new violations. --- CHANGELOG.md | 72 ++++++++++++++++++++++++++-------------------------- Makefile | 4 +-- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e119d0bec0..1c11ad4a7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -159,11 +159,11 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Fix the issue ref rendering for wiki (#28556) (#28559) * Fix duplicate ID when deleting repo (#28520) (#28528) * Only check online runner when detecting matching runners in workflows (#28286) (#28512) - * Initalize stroage for orphaned repository doctor (#28487) (#28490) + * Initialize stroage for orphaned repository doctor (#28487) (#28490) * Fix possible nil pointer access (#28428) (#28440) * Don't show unnecessary citation JS error on UI (#28433) (#28437) * DOCS - * Update actions document about comparsion as Github Actions (#28560) (#28564) + * Update actions document about comparison as Github Actions (#28560) (#28564) * Fix documents for "custom/public/assets/" (#28465) (#28467) * MISC * Fix inperformant query on retrifing review from database. (#28552) (#28562) @@ -673,7 +673,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Docs: template variables (#26547) * Update index doc (#26455) * Update zh-cn documentation (#26406) - * Fix typos and grammer problems for actions documentation (#26328) + * Fix typos and grammar problems for actions documentation (#26328) * Update documentation for 1.21 actions (#26317) * Doc update swagger doc for POST /orgs/{org}/teams (#26155) * Doc sync authentication.md to zh-cn (#26117) @@ -762,7 +762,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Fix incorrect color of selected assignees when create issue (#26324) (#26372) * Display human-readable text instead of cryptic filemodes (#26352) (#26358) * Hide `last indexed SHA` when a repo could not be indexed yet (#26340) (#26345) - * Fix the topic validation rule and suport dots (#26286) (#26303) + * Fix the topic validation rule and support dots (#26286) (#26303) * Fix due date rendering the wrong date in issue (#26268) (#26274) * Don't autosize textarea in diff view (#26233) (#26244) * Fix commit compare style (#26209) (#26226) @@ -989,7 +989,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Add dark mode to API Docs (#24971) * Display file mode for new file and file mode changes (#24966) * Make the 500 page load themes (#24953) - * Show `bot` label next to username when rendering autor link if the user is a bot (#24943) + * Show `bot` label next to username when rendering author link if the user is a bot (#24943) * Repo list improvements, fix bold helper classes (#24935) * Improve queue and logger context (#24924) * Improve RunMode / dev mode (#24886) @@ -1384,7 +1384,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Replace `drone exec` to `act_runner exec` in test README.md (#24791) * Update packages overview page (#24730) * Docs for creating a user to run Gitea on Fedora/RHEL/CentOS (#24725) - * Move actions as usage's subdirectory and update comparsion zh-cn version (#24719) + * Move actions as usage's subdirectory and update comparison zh-cn version (#24719) * Document `redis-cluster` explicitly in config (#24717) * Improve reverse-proxy document and fix nginx config bug (#24616) * Fix broken `README` link (#24546) @@ -1462,7 +1462,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Show visibility status of email in own profile (#23900) * Refactor authors dropdown (send get request from frontend to avoid long wait time) (#23890) * Add self to maintainers (#23644) - * Upgrade to npm lockfile v3 and explicitely set it (#23561) + * Upgrade to npm lockfile v3 and explicitly set it (#23561) * Improve indices for `action` table (#23532) * Update JS dependencies, Require Node.js 16 (#23528) * Add init file for Ubuntu (#23362) @@ -1503,7 +1503,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Fix issues list page multiple selection update milestones (#24660) (#24663) * Fix: release page for empty or non-existing target (#24659) * Fix close org projects (#24588) (#24591) - * Refresh the refernce of the closed PR when reopening (#24231) (#24587) + * Refresh the references of the closed PR when reopening (#24231) (#24587) * Fix the permission of team's `Actions` unit issue (#24536) (#24545) * Bump go.etcd.io/bbolt and blevesearch deps (#23062) (#24519) * Fix new wiki page mirror (#24518) @@ -2644,7 +2644,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Feeds: render markdown to html (#19058) * Allow users to self-request a PR review (#19030) * Allow render HTML with css/js external links (#19017) - * Fix script compatiable with OpenWrt (#19000) + * Fix script compatible with OpenWrt (#19000) * Support ignore all santize for external renderer (#18984) * Add note to GPG key response if user has no keys (#18961) * Improve Stopwatch behavior (#18930) @@ -2975,7 +2975,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Update go-org to v1.6.1 (#18932) (#18933) * Fix `<strong>` html in translation (#18929) (#18931) * Fix page and missing return on unadopted repos API (#18848) (#18927) - * Allow adminstrator teams members to see other teams (#18918) (#18919) + * Allow administrator teams members to see other teams (#18918) (#18919) * Don't treat BOM escape sequence as hidden character. (#18909) (#18910) * Correctly link URLs to users/repos with dashes, dots or underscores (… (#18908) * Fix redirect when using lowercase repo name (#18775) (#18902) @@ -3323,7 +3323,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Fixed issue merged/closed wording (#17973) * Return nicer error for ForcePrivate (#17971) * Fix overflow in commit graph (#17947) - * Prevent services/mailer/mailer_test.go tests from deleteing data directory (#17941) + * Prevent services/mailer/mailer_test.go tests from deleting data directory (#17941) * Use disable_form_autofill on Codebase and Gitbucket (#17936) * Fix a panic in NotifyCreateIssueComment (caused by string truncation) (#17928) * Fix markdown URL parsing (#17924) @@ -3362,7 +3362,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Fixed emoji alias not parsed in links (#16221) * Calculate label URL on API (#16186) * TRANSLATION - * Fix mispelling of starred as stared (#17465) + * Fix misspelling of starred as stared (#17465) * Re-separate the color translation strings (#17390) * Enable Malayalam, Greek, Persian, Hungarian & Indonesian by default (#16998) * BUILD @@ -3554,7 +3554,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Correctly return the number of Repositories for Organizations (#16807) (#16911) * Test if LFS object is accessible (#16865) (#16904) * Fix git.Blob.DataAsync(): close pipe since we return a NopCloser (#16899) (#16900) - * Fix dump and restore respository (#16698) (#16898) + * Fix dump and restore repository (#16698) (#16898) * Repare and Improve GetDiffRangeWithWhitespaceBehavior (#16894) (#16895) * Fix wiki raw commit diff/patch view (#16891) (#16892) * Ensure wiki repos are all closed (#16886) (#16888) @@ -4164,7 +4164,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Improve Description in new/ edit Project template (#14429) * Allow ssh-keygen on Windows to detect ssh key type (#14413) * Display error if twofaSecret cannot be retrieved (#14372) - * Sort issue search results by revelance (#14353) + * Sort issue search results by relevance (#14353) * Implement ghost comment mitigation (#14349) * Upgrade blevesearch dependency to v2.0.1 (#14346) * Add edit, delete and reaction support to code review comments on issue page (#14339) @@ -4337,7 +4337,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * BUGFIXES * Fix race in LFS ContentStore.Put(...) (#14895) (#14913) * Fix a couple of issues with a feeds (#14897) (#14903) - * When transfering repository and database transaction failed, rollback the renames (#14864) (#14902) + * When transferring repository and database transaction failed, rollback the renames (#14864) (#14902) * Fix race in local storage (#14888) (#14901) * Fix 500 on pull view page if user is not loged in (#14885) (#14886) * DOCS @@ -4668,7 +4668,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Render the git graph on the server (#12333) * Fix clone panel in wiki position not always align right (#12326) * Rework 'make generate-images' (#12316) - * Refactor webhook payload convertion (#12310) + * Refactor webhook payload conversion (#12310) * Move jquery-minicolors to npm/webpack (#12305) * Support use nvarchar for all varchar columns when using mssql (#12269) * Update Octicons to v10 (#12240) @@ -4744,7 +4744,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Add debug option to hooks (#11624) * Log slow tests (#11487) * TRANSLATION - * Translate two small lables on commit statuse list (#12821) + * Translate two small lables on commit statutes list (#12821) * Make issues.force_push_codes message shorter (#11575) * BUILD * Bump min required golang to 1.13 (#12717) @@ -5123,7 +5123,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Add restricted user filter to LDAP authentication (#10600) * Add Yandex OAuth2 provider (#8335) (#10564) * Make avatar lookup occur at image request (#10540) - * Prevent accidential selection of language stats bar (#10537) + * Prevent accidental selection of language stats bar (#10537) * Add fluid-icon (#10491) * Inform participants on UI too (#10473) * Build with go 1.14 (and raise minimum go version to 1.12) (#10467) @@ -5515,7 +5515,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Don't link wiki revision to commit (#9244) * Change review content column to type text in db (#9229) * Fixed topic regex pattern and added search by topic links after save (#9219) - * Add language to user API responce (#9215) + * Add language to user API response (#9215) * Correct tooltip message blocked by dependencies (#9211) * Add SimpleMDE and Fix Image Paste for Issue/Comment Editor (#9197) * Fix panic when diff (#9187) @@ -6136,7 +6136,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be * Display original author and URL information when showing migrated issues/comments (#7352) * Refactor filetype is not allowed errors (#7309) * switch to use gliderlabs/ssh for builtin server (#7250) - * Remove settting dependency on modules/session (#7237) + * Remove setting dependency on modules/session (#7237) * Move all mail related codes from models to services/mailer (#7200) * Support git.PATH entry in app.ini (#6772) * Support setting cookie domain (#6288) @@ -6311,7 +6311,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be * Fix markdown invoke sequence (#7513) (#7560) * Reserve .well-known username (#7638) * Do not leak secrets via timing side channel (#7364) - * Ensure that decryption of cookie actually suceeds (#7363) + * Ensure that decryption of cookie actually succeeds (#7363) * FEATURES * Content API for Creating, Updating, Deleting Files (#6314) * Enable tls-alpn-01: Use certmanager provided TLSConfig for LetsEncrypt (#7229) @@ -6533,7 +6533,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be * Change UpdateRepoIndex api to include watchers (#7012) * Move serv hook functionality & drop GitLogger (#6993) * Add support of utf8mb4 for mysql (#6992) - * Make webhook http connections resuable (#6976) + * Make webhook http connections reusable (#6976) * Move xorm logger bridge from log to models so that log module could be a standalone package (#6944) * Refactor models.NewRepoContext to extract git related codes to modules/git (#6941) * Remove macaron dependent on models (#6940) @@ -7104,7 +7104,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be * Fix data race on migrate repository (#5224) * Fix sqlite and mssql lock (#5214) * Fix sqlite lock (#5210) - * Fix: Accept web-command cli flags if web-command is commited (#5200) + * Fix: Accept web-command cli flags if web-command is committed (#5200) * Fix: Add secret to all webhook's payload where it has been missing (#5199) * Fix race on updatesize (#5190) * Fix create team, update team missing units (#5188) @@ -7255,7 +7255,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be * Enforce token on api routes [fixed critical security issue #4357] (#4840) * Update legacy branch and tag URLs in dashboard to new format (#4812) * Slack webhook channel name cannot be empty or just contain an hashtag (#4786) - * Add whitespace handling to PR-comparsion (#4683) + * Add whitespace handling to PR-comparison (#4683) * Make reverse proxy auth optional (#4643) * MySQL TLS (#4642) * Make sure to set PR split view when creating/previewing a pull request (#4617) @@ -7309,7 +7309,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be * Fix markdown image with link (#4675) * Remove maxlines option for file logger (#5282) * Fix wrong api request url for instances running in subfolders (#5261) (#5247) - * Accept web-command cli flags if web-command is commited (#5245) (#5200) + * Accept web-command cli flags if web-command is committed (#5245) (#5200) * Reduce join star, repo_topic, topic tables on repo search, to resolve extra columns problem on MSSQL (#5136) (#5229) * Fix data race on migrate repository (#5224) (#5230) * Add secret to all webhook's payload where it has been missing (#5208) (#5199) @@ -7342,7 +7342,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be * Fix missing release title in webhook (#4783) (#4796) * User shouldn't be able to approve or reject his/her own PR (#4729) * Make sure to reset commit count in the cache on mirror syncing (#4720) - * Fixed bug where team with admin privelege type doesn't get any unit (#4719) + * Fixed bug where team with admin privilege type doesn't get any unit (#4719) * Fix incorrect caption of webhook setting (#4701) (#4717) * Allow WIP marker to contains < or > (#4709) * Hide org/create menu item in Dashboard if user has no rights (#4678) (#4680) @@ -7408,7 +7408,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be * BUGFIXES * Fix missing release title in webhook (#4783) (#4800) * Make sure to reset commit count in the cache on mirror syncing (#4770) - * Fixed bug where team with admin privelege type doesn't get any unit (#4759) + * Fixed bug where team with admin privilege type doesn't get any unit (#4759) * Fix failure on creating pull request with assignees (#4583) (#4727) * Hide org/create menu item in Dashboard if user has no rights (#4678) (#4686) * TRANSLATION @@ -7759,7 +7759,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be * Fix inconsistencies in user settings UI (#2901) * Fix attachments icon size on zoom in/out (#2853) * Fix ignored errors in API route (#2850) - * Fix activity css conflit with semantic ui (#2758) + * Fix activity css conflict with semantic ui (#2758) * Fix notifications tabs according to semantic-ui docs (#2733) * Fix typos in app.ini (#2732) * Fix duplicated rel attribute (#2549) @@ -7957,7 +7957,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be * LFS: Return 404 for unimplemented endpoints (#1330) * Show a link to password reset from user settings requiring a password (#862) * Reserve the "explore" user/org name (#1222) - * Send notifications to partecipants in issue comments (#1217) + * Send notifications to participants in issue comments (#1217) * Improve style of user OpenID setting page (#1324) * Use font-awesome OpenID icon more (#1320) * Use readonly input form to show the validated OpenID URI (#1308) @@ -8155,7 +8155,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be * fix #1501 ssh hangs caused by #1461 (#1513) * Fix empty file download (#1506) * Fix broken v27 migration - change mirror interval from int to bigint (#1504) - * Do not allow commiting to protected branch from online editor (#1502) + * Do not allow committing to protected branch from online editor (#1502) * Add internal routes for ssh hook comands (#1471) * Fix races within code.gitea.io/git.(*Command).RunInDirTimeoutPipeline (#1465) * Simple quick fix for #1418 (#1456) @@ -8183,7 +8183,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be * Make sure both scripts/ can live side by side (#1264) * Fix nil-dereference bug (#1258) * rewrite pre-commit, post-commit and options hooks (fixes #1250) (#1257) - * Commit search appearence fixes (#1254) + * Commit search appearance fixes (#1254) * Fix forget migration for wiki hooks (#1227) * Fix repo settings external tracker failed and check external urls (#1215) * Fix 500 caused by branches settings introduced by #1198 (#1214) @@ -8267,7 +8267,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be * Only run coverage on merges/pushes to master (#1783) * Remove stale rule from Makefile (#1782) * feat: upgrade drone docker image to support multi-stage build. (#1732) - * Realy don't cache apk index (#1694) + * Really don't cache apk index (#1694) * Limit clone depth when drone-building (#1644) * Refactor Dockerfile (#1632) * Check if missing/modified/unused deps in vendor and fix errors (#1468) @@ -8331,7 +8331,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be * Remove unused files (#2124) * Improve org error handling (#2117) * Absolute path for setting.CustomConf (#2085) - * remove deprecated code for Gogs compitable (#2041) + * remove deprecated code for Gogs compatible (#2041) * Refactor session close as xorm already does everything needed internally (#2020) * SQLite has a query timeout. Hopefully fixes most 'database locked' errors (#1961) * Use monospace font in githook editor (#1958) @@ -8339,7 +8339,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be * Gracefully handle bare repositories on API operations. (#1932) * Fix errors caused by force push (#1927) * Display URLs in integration test logs (#1924) - * Set TMPDIR enviroment variable for dump command (#1915) + * Set TMPDIR environment variable for dump command (#1915) * Cache ctx.User in retrieveFeeds (#1902) * Make `LocalCopyPath` a setting instead of a hard-coded path (#1881) * Add check misspelling (#1877) @@ -8348,7 +8348,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be * Rename misnamed migration (#1867) * Support CRLF when splitting code lines for display (#1862) * Add convert less css file step. (#1861) - * Prevent accidential selection of line numbers in code view (#1860) + * Prevent accidental selection of line numbers in code view (#1860) * Delete Public SSH Key tmp file after calculating fingerprint (#1855) * Remove annoying difference in button heights. (#1853) * Only run test coverage on master branch. (#1838) @@ -8358,7 +8358,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be * Rename RepoCreationNum -> MaxCreationLimit (#1766) * Add button to admin ui (#1738) * Correct spelling mistakes (#1703) - * Make openid support default false for compitable with v1.1 (#1650) + * Make openid support default false for compatible with v1.1 (#1650) * Send mails as HTML as default. Setting for send as plain text. (#1648) * fix potential lock when sqlite (#1647) * Optimize png images via Google zopflipng [ci skip] (#1639) diff --git a/Makefile b/Makefile index 1bb79e0337..2a78c907c0 100644 --- a/Makefile +++ b/Makefile @@ -143,9 +143,9 @@ TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(FOMAN GO_DIRS := build cmd models modules routers services tests WEB_DIRS := web_src/js web_src/css -ESLINT_FILES := web_src/js tools *.config.js tests/e2e +ESLINT_FILES := web_src/js tools *.js tests/e2e STYLELINT_FILES := web_src/css web_src/js/components/*.vue -SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) docs/content templates options/locale/locale_en-US.ini .github +SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) docs/content templates options/locale/locale_en-US.ini .github $(filter-out CHANGELOG.md, $(wildcard *.go *.js *.md *.yml *.yaml *.toml)) EDITORCONFIG_FILES := templates .github/workflows options/locale/locale_en-US.ini GO_SOURCES := $(wildcard *.go) From dd8e6ae270b4b5e91a152a145978029dacb938ff Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Thu, 18 Apr 2024 21:31:53 +0200 Subject: [PATCH 152/370] Improve "Reference in new issue" modal (#30547) Fixes: https://github.com/go-gitea/gitea/issues/29994 Also some misc enhancements done to the form in the modal. <img width="840" alt="Screenshot 2024-04-17 at 23 02 55" src="https://github.com/go-gitea/gitea/assets/115237/e71fba55-55cd-4e48-a497-6b1025c36a43"> --- .../view_content/reference_issue_dialog.tmpl | 34 +++++++++---------- web_src/css/base.css | 7 ++++ 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/templates/repo/issue/view_content/reference_issue_dialog.tmpl b/templates/repo/issue/view_content/reference_issue_dialog.tmpl index 5f338f6768..f6ac4192ab 100644 --- a/templates/repo/issue/view_content/reference_issue_dialog.tmpl +++ b/templates/repo/issue/view_content/reference_issue_dialog.tmpl @@ -5,26 +5,24 @@ <div class="content tw-text-left"> <form class="ui form form-fetch-action" action="{{printf "%s/issues/new" .Repository.Link}}" method="post"> {{.CsrfTokenHtml}} - <div class="ui segment content"> - <div class="field"> - <span class="text"><strong>{{ctx.Locale.Tr "repository"}}</strong></span> - <div class="ui search normal selection dropdown issue_reference_repository_search"> - <div class="default text">{{.Repository.FullName}}</div> - <div class="menu"></div> - </div> - </div> - <div class="field"> - <span class="text"><strong>{{ctx.Locale.Tr "repo.milestones.title"}}</strong></span> - <input name="title" value="" autofocus required maxlength="255" autocomplete="off"> - </div> - <div class="field"> - <span class="text"><strong>{{ctx.Locale.Tr "repo.issues.reference_issue.body"}}</strong></span> - <textarea name="content" class="form-control"></textarea> - </div> - <div class="text right"> - <button class="ui primary button">{{ctx.Locale.Tr "repo.issues.create"}}</button> + <div class="field"> + <label><strong>{{ctx.Locale.Tr "repository"}}</strong></label> + <div class="ui search selection dropdown issue_reference_repository_search"> + <div class="default text">{{.Repository.FullName}}</div> + <div class="menu"></div> </div> </div> + <div class="field"> + <label><strong>{{ctx.Locale.Tr "repo.milestones.title"}}</strong></label> + <input name="title" value="" autofocus required maxlength="255" autocomplete="off"> + </div> + <div class="field"> + <label><strong>{{ctx.Locale.Tr "repo.issues.reference_issue.body"}}</strong></label> + <textarea name="content" class="form-control"></textarea> + </div> + <div class="text right"> + <button class="ui primary button">{{ctx.Locale.Tr "repo.issues.create"}}</button> + </div> </form> </div> </div> diff --git a/web_src/css/base.css b/web_src/css/base.css index 7e781aa97b..831044756f 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -374,6 +374,7 @@ a.label, .ui.selection.dropdown .menu > .item { border-color: var(--color-secondary); + white-space: nowrap; } .ui.selection.visible.dropdown > .text:not(.default) { @@ -390,6 +391,12 @@ a.label, color: var(--color-text-light-2); } +.ui.dropdown > .text { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + /* extend fomantic style '.ui.dropdown > .text > img' to include svg.img */ .ui.dropdown > .text > .img { margin-left: 0; From bcbeb24dbaaafd79c45792a2fe020c98a246b0a7 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Fri, 19 Apr 2024 04:00:59 +0800 Subject: [PATCH 153/370] Mock queue backoff duration (#30553) During testing, the backoff duration shouldn't be longer than other durations --- modules/queue/backoff.go | 10 +++++++++- modules/queue/workerqueue_test.go | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/queue/backoff.go b/modules/queue/backoff.go index cda7233567..02fc88574a 100644 --- a/modules/queue/backoff.go +++ b/modules/queue/backoff.go @@ -8,7 +8,7 @@ import ( "time" ) -const ( +var ( backoffBegin = 50 * time.Millisecond backoffUpper = 2 * time.Second ) @@ -18,6 +18,14 @@ type ( backoffFuncErr func() (retry bool, err error) ) +func mockBackoffDuration(d time.Duration) func() { + oldBegin, oldUpper := backoffBegin, backoffUpper + backoffBegin, backoffUpper = d, d + return func() { + backoffBegin, backoffUpper = oldBegin, oldUpper + } +} + func backoffRetErr[T any](ctx context.Context, begin, upper time.Duration, end <-chan time.Time, fn backoffFuncRetErr[T]) (ret T, err error) { d := begin for { diff --git a/modules/queue/workerqueue_test.go b/modules/queue/workerqueue_test.go index e09669c542..a08b02a123 100644 --- a/modules/queue/workerqueue_test.go +++ b/modules/queue/workerqueue_test.go @@ -250,6 +250,7 @@ func TestWorkerPoolQueueShutdown(t *testing.T) { func TestWorkerPoolQueueWorkerIdleReset(t *testing.T) { defer test.MockVariableValue(&workerIdleDuration, 10*time.Millisecond)() + defer mockBackoffDuration(10 * time.Millisecond)() handler := func(items ...int) (unhandled []int) { time.Sleep(50 * time.Millisecond) From ba9b124c34ff9a30945530f1f3cc7949ec2c8675 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Fri, 19 Apr 2024 00:24:35 +0000 Subject: [PATCH 154/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_fr-FR.ini | 6 ++ options/locale/locale_pt-PT.ini | 10 +++ options/locale/locale_tr-TR.ini | 139 ++++++++++++++++++++++++++++++++ options/locale/locale_zh-CN.ini | 10 +++ 4 files changed, 165 insertions(+) diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index c57bae77c0..61a6a98379 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -150,6 +150,10 @@ filter.private=Privé [search] +exact=Exact +exact_tooltip=Inclure uniquement les résultats qui correspondent exactement au terme de recherche +issue_kind=Recherche de tickets… +pull_kind=Recherche de demandes d’ajouts… [aria] navbar=Barre de navigation @@ -824,6 +828,7 @@ repo_and_org_access=Accès aux Organisations et Dépôts permissions_public_only=Publique uniquement permissions_access_all=Tout (public, privé et limité) select_permissions=Sélectionner les autorisations +permission_not_set=Non défini permission_no_access=Aucun accès permission_read=Lecture permission_write=Lecture et écriture @@ -2016,6 +2021,7 @@ settings.branches.add_new_rule=Ajouter une nouvelle règle settings.advanced_settings=Paramètres avancés settings.wiki_desc=Activer le wiki du dépôt settings.use_internal_wiki=Utiliser le wiki interne +settings.default_wiki_everyone_access=Autorisation d’accès par défaut pour les utilisateurs connectés : settings.use_external_wiki=Utiliser un wiki externe settings.external_wiki_url=URL Wiki externe settings.external_wiki_url_error=L’URL du wiki externe n’est pas une URL valide. diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 4f21b881c5..a90927a255 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -164,6 +164,8 @@ search=Pesquisar... type_tooltip=Tipo de pesquisa fuzzy=Aproximada fuzzy_tooltip=Incluir também os resultados que estejam próximos do termo de pesquisa +exact=Fiel +exact_tooltip=Incluir somente os resultados que correspondam rigorosamente ao termo de pesquisa repo_kind=Pesquisar repositórios... user_kind=Pesquisar utilizadores... org_kind=Pesquisar organizações... @@ -177,6 +179,8 @@ branch_kind=Pesquisar ramos... commit_kind=Pesquisar cometimentos... runner_kind=Pesquisar executores... no_results=Não foram encontrados resultados correspondentes. +issue_kind=Pesquisar questões... +pull_kind=Pesquisar puxadas... keyword_search_unavailable=Pesquisar por palavra-chave não está disponível, neste momento. Entre em contacto com o administrador. [aria] @@ -712,6 +716,7 @@ cancel=Cancelar language=Idioma ui=Tema hidden_comment_types=Tipos de comentários ocultos +hidden_comment_types_description=Os tipos de comentário marcados aqui não serão mostrados dentro das páginas das questões. Marcar "Rótulo", por exemplo, remove todos os comentários "{user} adicionou/removeu {label}". hidden_comment_types.ref_tooltip=Comentários onde esta questão foi referenciada a partir de outra questão/cometimento/… hidden_comment_types.issue_ref_tooltip=Comentários onde o utilizador altera o ramo/etiqueta associado à questão comment_type_group_reference=Referência @@ -882,6 +887,7 @@ repo_and_org_access=Acesso aos repositórios e às organizações permissions_public_only=Apenas público permissions_access_all=Tudo (público, privado e limitado) select_permissions=Escolher permissões +permission_not_set=Não definido permission_no_access=Sem acesso permission_read=Lidas permission_write=Leitura e escrita @@ -1286,6 +1292,7 @@ editor.or=ou editor.cancel_lower=Cancelar editor.commit_signed_changes=Cometer modificações assinadas editor.commit_changes=Cometer modificações +editor.add_tmpl=Adicionar '{filename}' editor.add=Adicionar %s editor.update=Modificar %s editor.delete=Eliminar %s @@ -2092,6 +2099,7 @@ settings.advanced_settings=Configurações avançadas settings.wiki_desc=Habilitar wiki do repositório settings.use_internal_wiki=Usar o wiki nativo settings.default_wiki_branch_name=Nome do ramo predefinido do wiki +settings.default_wiki_everyone_access=Permissão de acesso predefinida para utilizadores registados: settings.failed_to_change_default_wiki_branch=Falhou ao mudar o nome do ramo predefinido do wiki. settings.use_external_wiki=Usar um wiki externo settings.external_wiki_url=URL do wiki externo @@ -3083,12 +3091,14 @@ 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 https://bitbucket.org/account/user/{your-username}/oauth-consumers/new 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 https://www.dropbox.com/developers/apps auths.tip.facebook=`Registe uma nova aplicação em https://developers.facebook.com/apps e adicione o produto "Facebook Login"` auths.tip.github=Registe uma nova aplicação OAuth em https://github.com/settings/applications/new auths.tip.gitlab_new=Registe uma nova aplicação em https://gitlab.com/-/profile/applications auths.tip.google_plus=Obtenha credenciais de cliente OAuth2 a partir da consola do Google API em https://console.developers.google.com/ +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 https://dev.twitter.com/apps, 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 https://discordapp.com/developers/applications/me auths.tip.gitea=Registe uma nova aplicação OAuth2. O guia pode ser encontrado em https://docs.gitea.com/development/oauth2-provider diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index acc21d24e1..59c931afd2 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -25,6 +25,7 @@ enable_javascript=Bu web sitesinin çalışması için JavaScript gereklidir. toc=İçindekiler Tablosu licenses=Lisanslar return_to_gitea=Gitea'ya Dön +more_items=Daha fazla öğe username=Kullanıcı Adı email=E-posta Adresi @@ -113,6 +114,7 @@ loading=Yükleniyor… error=Hata error404=Ulaşmaya çalıştığınız sayfa <strong>mevcut değil</strong> veya <strong>görüntüleme yetkiniz yok</strong>. go_back=Geri Git +invalid_data=Geçersiz veri: %v never=Asla unknown=Bilinmiyor @@ -123,6 +125,7 @@ pin=Sabitle unpin=Sabitlemeyi kaldır artifacts=Yapılar +confirm_delete_artifact=%s yapısını silmek istediğinizden emin misiniz? archived=Arşivlenmiş @@ -142,13 +145,43 @@ name=İsim value=Değer filter=Filtre +filter.clear=Filtreyi Temizle filter.is_archived=Arşivlenmiş +filter.not_archived=Arşivlenmemiş +filter.is_fork=Çatallanmış +filter.not_fork=Çatallanmamış +filter.is_mirror=Yansılanmış +filter.not_mirror=Yansılanmamış filter.is_template=Şablon +filter.not_template=Şablon değil filter.public=Genel filter.private=Özel +no_results_found=Sonuç bulunamadı. [search] +search=Ara... +type_tooltip=Arama türü +fuzzy=Bulanık +fuzzy_tooltip=Arama terimine benzeyen sonuçları da içer +exact=Tam +exact_tooltip=Sadece arama terimiyle tamamen eşleşen sonuçları içer +repo_kind=Depoları ara... +user_kind=Kullanıcıları ara... +org_kind=Organizasyonları ara... +team_kind=Takımları ara... +code_kind=Kod ara... +code_search_unavailable=Kod arama şu an mevcut değil. Lütfen site yöneticisiyle iletişime geçin. +code_search_by_git_grep=Mevcut kod arama sonuçları "git grep" ile sağlanıyor. Eğer yönetici Depo Dizinleyici'yi etkinleştirirse daha iyi sonuçlar çıkabilir. +package_kind=Paketleri ara... +project_kind=Projeleri ara... +branch_kind=Dalları ara... +commit_kind=İşlemeleri ara... +runner_kind=Çalıştırıcıları ara... +no_results=Eşleşen sonuç bulunamadı. +issue_kind=Konuları ara... +pull_kind=Değişiklikleri ara... +keyword_search_unavailable=Anahtar kelime ile arama şu an mevcut değil. Lütfen site yöneticinizle iletişime geçin. [aria] navbar=Gezinti Çubuğu @@ -255,6 +288,7 @@ email_title=E-posta Ayarları smtp_addr=SMTP Sunucusu smtp_port=SMTP Portu smtp_from=E-posta Gönderen +smtp_from_invalid=`"E-posta Olarak Gönder" adresi geçersiz` smtp_from_helper=Gitea'nın kullanacağı e-posta adresi. Yalın bir e-posta adresi girin veya "İsim" <eposta@ornek.com> biçimini kullanın. mailer_user=SMTP Kullanıcı Adı mailer_password=SMTP Parolası @@ -314,6 +348,7 @@ env_config_keys=Ortam Yapılandırma env_config_keys_prompt=Aşağıdaki ortam değişkenleri de yapılandırma dosyanıza eklenecektir: [home] +nav_menu=Gezinti Menüsü uname_holder=Kullanıcı Adı veya E-Posta Adresi password_holder=Parola switch_dashboard_context=Panoya Geçiş Yap @@ -362,6 +397,7 @@ forgot_password_title=Şifremi unuttum forgot_password=Şifrenizi mi unuttunuz? sign_up_now=Bir hesaba mı ihtiyacınız var? Hemen kaydolun. sign_up_successful=Hesap başarılı bir şekilde oluşturuldu. Hoşgeldiniz! +confirmation_mail_sent_prompt_ex=Yeni bir doğrulama e-postası <b>%s</b> adresine gönderildi. Lütfen kayıt sürecini tamamlamak için %s içinde gelen kutunuzu denetleyin. Eğer kayıt e-posta adresiniz hatalı ise, tekrar oturum açıp değiştirebilirsiniz. must_change_password=Parolanızı güncelleyin allow_password_change=Kullanıcıyı parola değiştirmeye zorla (önerilen) reset_password_mail_sent_prompt=<b>%s</b> adresine bir onay e-postası gönderildi. Hesap kurtarma işlemini tamamlamak için lütfen gelen kutunuzu sonraki %s içinde kontrol edin. @@ -371,6 +407,7 @@ prohibit_login=Oturum Açma Yasağı prohibit_login_desc=Hesabınız ile oturum açmanız yasaklanmış, lütfen site yöneticinizle iletişime geçin. resent_limit_prompt=Zaten bir etkinleştirme e-postası talep ettiniz. Lütfen 3 dakika bekleyip tekrar deneyin. has_unconfirmed_mail=Merhaba %s, doğrulanmamış bir e-posta adresin var (<b>%s</b>). Bir doğrulama e-postası almadıysanız ya da yenisine ihtiyacınız varsa lütfen aşağıdaki düğmeye tıklayın. +change_unconfirmed_mail_address=Eğer kayıt e-posta adresiniz hatalı ise, burada değiştirebilir ve yeni bir doğrulama e-postası gönderebilirsiniz. resend_mail=Etkinleştirme e-postasını tekrar almak için buraya tıklayın email_not_associate=Bu e-posta adresi hiçbir hesap ile ilişkilendirilmemiştir. send_reset_mail=Hesap Kurtarma E-postası Gönder @@ -418,6 +455,7 @@ authorization_failed_desc=Geçersiz bir istek tespit ettiğimiz için yetkilendi sspi_auth_failed=SSPI kimlik doğrulaması başarısız oldu password_pwned=Seçtiğiniz parola, daha önce herkese açık veri ihlallerinde açığa çıkan bir <a target="_blank" rel="noopener noreferrer" href="https://haveibeenpwned.com/Passwords">çalınan parola listesindedir</a>. Lütfen farklı bir parola ile tekrar deneyin ve başka yerlerde de bu parolayı değiştirmeyi düşünün. password_pwned_err=HaveIBeenPwned'e yapılan istek tamamlanamadı +last_admin=Son yöneticiyi silemezsiniz. En azından bir yönetici olmalıdır. [mail] view_it_on=%s üzerinde görüntüle @@ -550,6 +588,7 @@ team_name_been_taken=Takım adı zaten alınmış. team_no_units_error=En az bir depo bölümüne erişimine izin ver. email_been_used=E-posta adresi zaten kullanılıyor. email_invalid=E-posta adresi geçersiz. +email_domain_is_not_allowed=Kullanıcı e-posta adresi <b>%s</b> alan adı EMAIL_DOMAIN_ALLOWLIST veya EMAIL_DOMAIN_BLOCKLIST ile çelişiyor. Lütfen işleminizin beklendiğinden emin olun. openid_been_used=OpenID adresi "%s" zaten kullanılıyor. username_password_incorrect=Kullanıcı adı veya parola hatalı. password_complexity=Parola, karmaşıklık gereksinimlerini karşılamıyor: @@ -561,6 +600,8 @@ enterred_invalid_repo_name=Girdiğiniz depo adı hatalı. enterred_invalid_org_name=Girdiğiniz organizsyon adı hatalı. enterred_invalid_owner_name=Yeni sahip ismi hatalı. enterred_invalid_password=Girdiğiniz parola hatalı. +unset_password=Oturum açma kullanıcısı parola belirlemedi. +unsupported_login_type=Oturum açma türü hesap silmeyi desteklemiyor. user_not_exist=Böyle bir kullanıcı yok. team_not_exist=Böyle bir takım bulunmuyor. last_org_owner=Son kullanıcıyı 'sahipler' takımından çıkaramazsınız. Bir organizasyonun en az bir sahibi olmalıdır. @@ -583,6 +624,7 @@ org_still_own_packages=Bu organizasyon hala bir veya daha fazla pakete sahip, ö target_branch_not_exist=Hedef dal mevcut değil. +admin_cannot_delete_self=Yöneticiyken kendinizi silemezsiniz. Lütfen önce yönetici haklarınızı kaldırın. [user] change_avatar=Profil resmini değiştir… @@ -609,6 +651,29 @@ form.name_reserved=`"%s" kullanıcı adı rezerve edilmiş.` form.name_pattern_not_allowed=Kullanıcı adında "%s" deseni kullanılamaz. form.name_chars_not_allowed=`"%s" kullanıcı adı geçersiz karakterler içeriyor.` +block.block=Engelle +block.block.user=Kullanıcıyı engelle +block.block.org=Kullanıcıyı organizasyonda engelle +block.block.failure=Kullanıcı engellenemedi: %s +block.unblock=Engeli kaldır +block.unblock.failure=Kullanıcının engeli kaldırılamadı: %s +block.blocked=Bu kullanıcıyı engelledin. +block.title=Bir kullanıcı engelle +block.info=Bir kullanıcıyı engellemek depoarla, değişiklik isteği veya konu açmak veya yorumlamak gibi, etkileşim kurmasını önler. Bir kullanıcı engelleme hakkında daha fazlasını öğrenin. +block.info_1=Bir kullanıcıyı engellemek, hesabınızda ve depolarınızda şu eylemleri önler: +block.info_2=hesabınızı takip etmek +block.info_3=kullanıcı adınızdan @bahsederek size bildirim göndermek +block.info_4=kendi depolarına sizi katkıcı olarak davet etmek +block.info_5=depolara yıldız koymak, çatallamak veya izlemek +block.info_6=konu veya değişiklik isteği açmak ve yorum eklemek +block.info_7=konularda veya değişiklik isteklerinde yorumlarınıza tepki vermek +block.user_to_block=Engellenecek kullanıcı +block.note=Not +block.note.title=İsteğe bağlı not: +block.note.info=Not engellenen kullanıcıya gösterilmez. +block.note.edit=Notu düzenle +block.list=Engellenmiş kullanıcılar +block.list.none=Engellediğiniz kullanıcı yok. [settings] profile=Profil @@ -651,6 +716,7 @@ cancel=İptal language=Dil ui=Tema hidden_comment_types=Gizli yorum türleri +hidden_comment_types_description=Burada işaretlenen yorum türleri konu sayfalarında görüntülenmeyecektir. Örneğin "Etiket" seçildiğinde tüm "{user}, {label} ekledi/çıkardı" yorumları kalkacaktır. hidden_comment_types.ref_tooltip=Bu konuya başka konu/işlem tarafından değinilen yorumlar… hidden_comment_types.issue_ref_tooltip=Kullanıcının konuyla ilişkili dalı/etiketi değiştirdiği yorumlar comment_type_group_reference=Referans @@ -821,6 +887,7 @@ repo_and_org_access=Depo ve Organizasyon Erişimi permissions_public_only=Yalnızca herkese açık permissions_access_all=Tümü (herkese açık, özel ve sınırlı) select_permissions=İzinleri seçin +permission_not_set=Ayarlanmadı permission_no_access=Erişim Yok permission_read=Okunmuş permission_write=Okuma ve Yazma @@ -945,7 +1012,9 @@ fork_visibility_helper=Çatallanmış bir deponun görünürlüğü değiştiril fork_branch=Çatala klonlanacak dal all_branches=Tüm dallar fork_no_valid_owners=Geçerli bir sahibi olmadığı için bu depo çatallanamaz. +fork.blocked_user=Depo çatallanamıyor, depo sahibi tarafından engellenmişsiniz. use_template=Bu şablonu kullan +open_with_editor=%s ile aç download_zip=ZIP indir download_tar=TAR.GZ indir download_bundle=BUNDLE indir @@ -961,6 +1030,8 @@ issue_labels_helper=Bir konu etiket seti seçin. license=Lisans license_helper=Bir lisans dosyası seçin. license_helper_desc=Bir lisans, başkalarının kodunuzla neler yapıp yapamayacağını yönetir. Projeniz için hangisinin doğru olduğundan emin değil misiniz? <a target="_blank" rel="noopener noreferrer" href="%s">Lisans seçme</a> konusuna bakın +object_format=Nesne Biçimi +object_format_helper=Deponun nesne biçimi. Daha sonra değiştirilemez. SHA1 en uyumlu olandır. readme=README readme_helper=Bir README dosyası şablonu seçin. readme_helper_desc=Projeniz için eksiksiz bir açıklama yazabileceğiniz yer burasıdır. @@ -978,6 +1049,7 @@ mirror_prune=Buda mirror_prune_desc=Kullanılmayan uzak depoları izleyen referansları kaldır mirror_interval=Yansı Aralığı (geçerli zaman birimleri 'h', 'm', 's'). Periyodik senkronizasyonu devre dışı bırakmak için 0 kullanın. (Asgari aralık: %s) mirror_interval_invalid=Yansı süre aralığı geçerli değil. +mirror_sync=eşitlendi mirror_sync_on_commit=İşlemeler gönderildiğinde senkronize et mirror_address=URL'den Klonla mirror_address_desc=Yetkilendirme bölümüne gerekli tüm kimlik bilgilerini girin. @@ -995,6 +1067,7 @@ watchers=İzleyenler stargazers=Yıldızlayanlar stars_remove_warning=Bu depodan tüm yıldızları kaldıracaktır. forks=Çatallamalar +stars=Yıldızlar reactions_more=ve %d daha fazla unit_disabled=Site yöneticisi bu depo bölümünü devre dışı bıraktı. language_other=Diğer @@ -1028,6 +1101,7 @@ desc.public=Genel desc.template=Şablon desc.internal=Dahili desc.archived=Arşivlenmiş +desc.sha256=SHA256 template.items=Şablon Öğeleri template.git_content=Git İçeriği (Varsayılan Dal) @@ -1115,6 +1189,7 @@ watch=İzle unstar=Yıldızı Kaldır star=Yıldızla fork=Çatalla +action.blocked_user=İşlem gerçekleştirilemiyor, depo sahibi tarafından engellenmişsiniz. download_archive=Depoyu İndir more_operations=Daha Fazla İşlem @@ -1161,6 +1236,8 @@ file_view_rendered=Oluşturulanları Görüntüle file_view_raw=Ham Görünüm file_permalink=Kalıcı Bağlantı file_too_large=Bu dosya görüntülemek için çok büyük. +code_preview_line_from_to=%[3]s içinde %[1]d ve %[2]d arasındaki satırlar +code_preview_line_in=%[2]s içinde %[1]d satırı invisible_runes_header=`Bu dosya görünmez Evrensel Kodlu karakter içeriyor` invisible_runes_description=`Bu dosya, insanlar tarafından ayırt edilemeyen ama bir bilgisayar tarafından farklı bir şekilde işlenebilecek görünmez evrensel kodlu karakter içeriyor. Eğer bunu kasıtlı olarak yaptıysanız bu uyarıyı yok sayabilirsiniz. Gizli karakterleri göstermek için Kaçış Karakterli düğmesine tıklayın.` ambiguous_runes_header=`Bu dosya muğlak Evrensel Kodlu karakter içeriyor` @@ -1178,6 +1255,8 @@ audio_not_supported_in_browser=Tarayıcınız HTML5 'audio' etiketini desteklemi stored_lfs=Git LFS ile depolandı symbolic_link=Sembolik Bağlantı executable_file=Çalıştırılabilir Dosya +vendored=Sağlanmış +generated=Üretilmiş commit_graph=İşleme Grafiği commit_graph.select=Dalları seç commit_graph.hide_pr_refs=Değişiklik İsteklerini Gizle @@ -1213,6 +1292,7 @@ editor.or=veya editor.cancel_lower=İptal editor.commit_signed_changes=İmzalı Değişiklikleri İşle editor.commit_changes=Değişiklikleri Uygula +editor.add_tmpl='{filename}' ekle editor.add=%s Ekle editor.update=%s Güncelle editor.delete=%s Sil @@ -1240,6 +1320,8 @@ editor.file_editing_no_longer_exists=Düzenlenmekte olan "%s" dosyası artık bu editor.file_deleting_no_longer_exists=Silinen "%s" dosyası artık bu depoda yer almıyor. editor.file_changed_while_editing=Düzenlemeye başladığınızdan beri dosya içeriği değişti. Görmek için <a target="_blank" rel="noopener noreferrer" href="%s">burayı tıklayın</a> veya üzerine yazmak için <strong>değişiklikleri yine de işleyin</strong>. editor.file_already_exists=Bu depoda "%s" isimli bir dosya zaten var. +editor.commit_id_not_matching=İşleme ID'si, düzenlemeye başladığınız ID ile uyuşmuyor, bir yama dalına işleme yapın ve sonra birleştirin. +editor.push_out_of_date=İtme eskimiş. editor.commit_empty_file_header=Boş bir dosya işle editor.commit_empty_file_text=İşlemek üzere olduğunuz dosya boş. Devam edilsin mi? editor.no_changes_to_show=Gösterilecek değişiklik yok. @@ -1264,6 +1346,7 @@ commits.commits=İşleme commits.no_commits=Ortak bir işleme yok. "%s" ve "%s" tamamen farklı geçmişlere sahip. commits.nothing_to_compare=Bu dallar eşit. commits.search.tooltip=Anahtar kelimeleri "author:", "committer:", "after:" veya "before:" ile kullanabilirsiniz, örneğin "revert author:Alice before:2019-01-13". +commits.search_branch=Bu Dal commits.search_all=Tüm Dallar commits.author=Yazar commits.message=Mesaj @@ -1322,6 +1405,7 @@ projects.column.new=Yeni Sütun projects.column.set_default=Varsayılanı Ayarla projects.column.set_default_desc=Bu sütunu kategorize edilmemiş konular ve değişiklik istekleri için varsayılan olarak ayarlayın projects.column.delete=Sutün Sil +projects.column.deletion_desc=Bir proje sütununun silinmesi, ilgili tüm konuları varsayılan sütuna taşır. Devam edilsin mi? projects.column.color=Renk projects.open=Aç projects.close=Kapat @@ -1356,6 +1440,8 @@ issues.new.assignees=Atananlar issues.new.clear_assignees=Atamaları Temizle issues.new.no_assignees=Atanan Kişi Yok issues.new.no_reviewers=Değerlendirici yok +issues.new.blocked_user=Konu oluşturulamıyor, depo sahibi tarafından engellenmişsiniz. +issues.edit.blocked_user=İçerik düzenlenemiyor, gönderen veya depo sahibi tarafından engellenmişsiniz. issues.choose.get_started=Başla issues.choose.open_external_link=Aç issues.choose.blank=Varsayılan @@ -1470,6 +1556,7 @@ issues.close_comment_issue=Yorum Yap ve Kapat issues.reopen_issue=Yeniden aç issues.reopen_comment_issue=Yorum Yap ve Yeniden Aç issues.create_comment=Yorum yap +issues.comment.blocked_user=Yorum oluşturulamıyor veya düzenlenemiyor, gönderen veya depo sahibi tarafından engellenmişsiniz. issues.closed_at=`<a id="%[1]s" href="#%[1]s">%[2]s</a> konusunu kapattı` issues.reopened_at=`<a id="%[1]s" href="#%[1]s">%[2]s</a> konusunu yeniden açtı` issues.commit_ref_at=`<a id="%[1]s" href="#%[1]s">%[2]s</a> işlemesinde bu konuyu işaret etti` @@ -1668,6 +1755,7 @@ compare.compare_head=karşılaştır pulls.desc=Değişiklik isteklerini ve kod incelemelerini etkinleştir. pulls.new=Yeni Değişiklik İsteği +pulls.new.blocked_user=Değişiklik isteği oluşturulamıyor, depo sahibi tarafından engellenmişsiniz. pulls.view=Değişiklik İsteği Görüntüle pulls.compare_changes=Yeni Değişiklik İsteği pulls.allow_edits_from_maintainers=Bakımcıların düzenlemelerine izin ver @@ -1692,6 +1780,7 @@ pulls.select_commit_hold_shift_for_range=İşleme seç. Bir aralık seçmek içi pulls.review_only_possible_for_full_diff=İnceleme sadece tam fark görüntülemede mümkündür pulls.filter_changes_by_commit=İşleme ile süz pulls.nothing_to_compare=Bu dallar eşit. Değişiklik isteği oluşturmaya gerek yok. +pulls.nothing_to_compare_have_tag=Seçili dal/etiket aynı. pulls.nothing_to_compare_and_allow_empty_pr=Bu dallar eşittir. Bu Dİ boş olacak. pulls.has_pull_request=`Bu dallar arasında zaten bir değişiklik isteği var: <a href="%[1]s">%[2]s#%[3]d</a>` pulls.create=Değişiklik İsteği Oluştur @@ -1750,6 +1839,7 @@ pulls.merge_pull_request=Birleştirme işlemi oluştur pulls.rebase_merge_pull_request=Yeniden yapılandır ve ileri sar pulls.rebase_merge_commit_pull_request=Yeniden yapılandır ve birleştirme işlemi oluştur pulls.squash_merge_pull_request=Ezme işlemi oluştur +pulls.fast_forward_only_merge_pull_request=Sadece ileri sarma pulls.merge_manually=Elle birleştirildi pulls.merge_commit_id=Birleştirme işlemesi kimliği pulls.require_signed_wont_sign=Dal imzalı işlemeler gerektiriyor, ancak bu birleştirme imzalanmayacak @@ -1886,6 +1976,10 @@ wiki.page_name_desc=Bu Viki sayfası için bir ad girin. Bazı özel isimler 'Ho wiki.original_git_entry_tooltip=Kolay bağlantı kullanmak yerine özgün Git dosyasını görüntüle. activity=Aktivite +activity.navbar.pulse=Eğilim +activity.navbar.code_frequency=Kod Frekansı +activity.navbar.contributors=Katkıda Bulunanlar +activity.navbar.recent_commits=Son İşlemeler activity.period.filter_label=Dönem: activity.period.daily=1 gün activity.period.halfweekly=3 gün @@ -1951,7 +2045,10 @@ activity.git_stats_and_deletions=ve activity.git_stats_deletion_1=%d silme oldu activity.git_stats_deletion_n=%d silme oldu +contributors.contribution_type.filter_label=Katkı türü: contributors.contribution_type.commits=İşleme +contributors.contribution_type.additions=Eklemeler +contributors.contribution_type.deletions=Silmeler settings=Ayarlar settings.desc=Ayarlar, deponun ayarlarını yönetebileceğiniz yerdir @@ -1979,6 +2076,7 @@ settings.mirror_settings.docs.doc_link_title=Depoların yansısını nasıl olu settings.mirror_settings.docs.doc_link_pull_section=belgelerin "uzak bir depodan çekmek" bölümü. settings.mirror_settings.docs.pulling_remote_title=Uzak bir depodan çekmek settings.mirror_settings.mirrored_repository=Yansıtılmış depo +settings.mirror_settings.pushed_repository=İtilmiş depo settings.mirror_settings.direction=Yön settings.mirror_settings.direction.pull=Çek settings.mirror_settings.direction.push=Gönder @@ -2000,6 +2098,9 @@ settings.branches.add_new_rule=Yeni Kural Ekle settings.advanced_settings=Gelişmiş Ayarlar settings.wiki_desc=Depo Wiki'sini Etkinkleştir settings.use_internal_wiki=Dahili Wiki Kullan +settings.default_wiki_branch_name=Varsayılan Viki Dal Adı +settings.default_wiki_everyone_access=Oturum açmış kullanıcılar için Varsayılan Erişim İzinleri: +settings.failed_to_change_default_wiki_branch=Varsayılan viki dalı değiştirilemedi. settings.use_external_wiki=Harici Wiki Kullan settings.external_wiki_url=Harici Wiki bağlantısı settings.external_wiki_url_error=Harici wiki URL'si geçerli bir URL değil. @@ -2030,6 +2131,9 @@ settings.pulls.default_allow_edits_from_maintainers=Bakımcıların düzenlemele settings.releases_desc=Depo Sürümlerini Etkinleştir settings.packages_desc=Depo Paket Kütüğünü Etkinleştir settings.projects_desc=Depo Projelerini Etkinleştir +settings.projects_mode_desc=Proje Modu (ne tür projeler görüntülensin) +settings.projects_mode_repo=Sadece depo projeleri +settings.projects_mode_owner=Sadece kullanıcı veya organizasyon projeleri settings.projects_mode_all=Tüm projeler settings.actions_desc=Depo İşlemlerini Etkinleştir settings.admin_settings=Yönetici Ayarları @@ -2056,6 +2160,7 @@ settings.convert_fork_succeed=Çatal normal bir depoya dönüştürüldü. settings.transfer=Sahipliği Aktar settings.transfer.rejected=Depo aktarımı reddedildi. settings.transfer.success=Depo aktarımı başarıyla tamamlandı. +settings.transfer.blocked_user=Depo transfer edilemiyor, yeni sahibi tarafından engellenmişsiniz. settings.transfer_abort=Aktarımı iptal et settings.transfer_abort_invalid=Var olmayan bir depo aktarımını iptal edemezsiniz. settings.transfer_abort_success=%s tarafına yapılan depo aktarımı başarıyla iptal edildi. @@ -2101,6 +2206,7 @@ settings.add_collaborator_success=Katkıcı eklendi. settings.add_collaborator_inactive_user=Etkin olmayan bir kullanıcı katkıcı olarak eklenemez. settings.add_collaborator_owner=Bir sahip katkıcı olarak eklenemez. settings.add_collaborator_duplicate=Katkıcı bu depoya zaten eklenmiş. +settings.add_collaborator.blocked_user=Katkıcı depo sahibi tarafından engellenmiş veya depo sahibini engellemiş. settings.delete_collaborator=Sil settings.collaborator_deletion=Katkıcıyı Sil settings.collaborator_deletion_desc=Bir katkıcıyı silmek, bu depoya erişimini iptal edecektir. Devam et? @@ -2285,6 +2391,8 @@ settings.protect_approvals_whitelist_users=Beyaz listedeki incelemeciler: settings.protect_approvals_whitelist_teams=Gözden geçirme için beyaz listedeki takımlar: settings.dismiss_stale_approvals=Eski onayları reddet settings.dismiss_stale_approvals_desc=Değişiklik isteğinin içeriğini değiştiren yeni işlemeler dala itildiğinde, eski onaylar reddedilir. +settings.ignore_stale_approvals=Eskimiş onayları yoksay +settings.ignore_stale_approvals_desc=Daha eski işlemelere (eski incelemelere) yapılmış olan onayları, Dİ'nin kaç onayı olduğunu belirlerken sayma. Eskimiş incelemeler atıldıysa bu ilgisizdir. settings.require_signed_commits=İmzalı İşleme Gerekli settings.require_signed_commits_desc=Reddetme, onlar imzasızsa veya doğrulanamazsa bu dala gönderir. settings.protect_branch_name_pattern=Korunmuş Dal Adı Deseni @@ -2340,6 +2448,7 @@ settings.archive.error=Depoyu arşivlemeye çalışırken bir hata oluştu. Daha settings.archive.error_ismirror=Yansılanmış bir depoyu arşivleyemezsiniz. settings.archive.branchsettings_unavailable=Depo arşivlenirse dal ayarları kullanılamaz. settings.archive.tagsettings_unavailable=Depo arşivlenmişse etiket ayarları kullanılamaz. +settings.archive.mirrors_unavailable=Depo arşivlenmişse yansılar kullanılamaz. settings.unarchive.button=Depoyu Arşivden Çıkar settings.unarchive.header=Bu Depoyu Arşivden Çıkar settings.unarchive.text=Depoyu arşivden çıkarmak, yeni sorunların ve değişiklik isteklerinin yanı sıra işleme ve itme yeteneğini de geri kazandıracaktır. @@ -2536,8 +2645,16 @@ find_file.no_matching=Eşleşen dosya bulunamadı error.csv.too_large=Bu dosya çok büyük olduğu için işlenemiyor. error.csv.unexpected=%d satırı ve %d sütununda beklenmeyen bir karakter içerdiğinden bu dosya işlenemiyor. error.csv.invalid_field_count=%d satırında yanlış sayıda alan olduğundan bu dosya işlenemiyor. +error.broken_git_hook=Bu deponun Git İstemcileri bozuk gibi gözüküyor. Onarmak için lütfen <a target="_blank" rel="noreferrer" href="%s">belgelere</a> bakın, daha sonra durumu yenilemek için bazı işlemeler itin. [graphs] +component_loading=%s yükleniyor... +component_loading_failed=%s yüklenemedi +component_loading_info=Bu biraz sürebilir… +component_failed_to_load=Beklenmedik bir hata oluştu. +code_frequency.what=kod frekansı +contributors.what=katkılar +recent_commits.what=son işlemeler [org] org_name_holder=Organizasyon Adı @@ -2651,6 +2768,7 @@ teams.add_nonexistent_repo=Eklemeye çalıştığınz depo mevcut değil. Lütfe teams.add_duplicate_users=Kullanıcı zaten takımın üyesi. teams.repos.none=Bu takım tarafından hiçbir depoya erişilemedi. teams.members.none=Bu takımda üye yok. +teams.members.blocked_user=Kullanıcı eklenemiyor, çünkü organizasyon tarafından engellenmiş. teams.specific_repositories=Belirli depolar teams.specific_repositories_helper=Üyeler, yalnızca takıma açıkça eklenen depolara erişebilir. Bunu seçmek, <i>Tüm depolarla</i> zaten eklenmiş olan depoları otomatik olarak <strong>kaldırmaz</strong>. teams.all_repositories=Tüm depolar @@ -2663,7 +2781,9 @@ teams.invite.by=%s tarafından davet edildi teams.invite.description=Takıma katılmak için aşağıdaki düğmeye tıklayın. [admin] +maintenance=Bakım dashboard=Pano +self_check=Öz Denetim identity_access=Kimlik ve Erişim users=Kullanıcı Hesapları organizations=Organizasyonlar @@ -2685,6 +2805,7 @@ settings=Yönetici Ayarları dashboard.new_version_hint=Gitea %s şimdi hazır, %s çalıştırıyorsunuz. Ayrıntılar için <a target="_blank" rel="noreferrer" href="https://blog.gitea.io">blog</a>'a bakabilirsiniz. dashboard.statistic=Özet +dashboard.maintenance_operations=Bakım İşlemleri dashboard.system_status=Sistem Durumu dashboard.operation_name=İşlem Adı dashboard.operation_switch=Geç @@ -2710,6 +2831,7 @@ dashboard.delete_missing_repos=Git dosyaları eksik olan tüm depoları sil dashboard.delete_missing_repos.started=Git dosyaları eksik olan tüm depoları silme görevi başladı. dashboard.delete_generated_repository_avatars=Oluşturulan depo resimlerini sil dashboard.sync_repo_branches=Eşzamanlama git verisinden veritabanlarına dalları kaçırdı +dashboard.sync_repo_tags=Etiketleri git verisinden veritabanına eşitle dashboard.update_mirrors=Yansıları Güncelle dashboard.repo_health_check=Tüm depoların sağlığını denetle dashboard.check_repo_stats=Tüm depo istatistiklerini denetle @@ -2764,6 +2886,7 @@ dashboard.stop_endless_tasks=Daimi görevleri durdur dashboard.cancel_abandoned_jobs=Terkedilmiş görevleri iptal et dashboard.start_schedule_tasks=Zamanlanmış görevleri başlat dashboard.sync_branch.started=Dal Eşzamanlaması başladı +dashboard.sync_tag.started=Etiket eşitlemesi başladı dashboard.rebuild_issue_indexer=Konu indeksini yeniden oluştur users.user_manage_panel=Kullanıcı Hesap Yönetimi @@ -2968,11 +3091,14 @@ auths.tips=İpuçları auths.tips.oauth2.general=OAuth2 Kimlik Doğrulama auths.tips.oauth2.general.tip=Yeni bir OAuth2 kimlik doğrulama kaydederken, geri çağırma/yönlendirme URL'si şu olmalıdır: auths.tip.oauth2_provider=OAuth2 Sağlayıcısı +auths.tip.bitbucket=https://bitbucket.org/account/user/{your-username}/oauth-consumers/new sayfasında yeni bir OAuth tüketicisi kaydedin ve 'Hesap' - 'Oku' iznini ekleyin auths.tip.nextcloud=Aşağıdaki "Ayarlar -> Güvenlik -> OAuth 2.0 istemcisi" menüsünü kullanarak örneğinize yeni bir OAuth tüketicisi kaydedin auths.tip.dropbox=https://www.dropbox.com/developers/apps adresinde yeni bir uygulama oluştur auths.tip.facebook=https://developers.facebook.com/apps adresinde yeni bir uygulama kaydedin ve "Facebook Giriş" ürününü ekleyin auths.tip.github=https://github.com/settings/applications/new adresinde yeni bir OAuth uygulaması kaydedin +auths.tip.gitlab_new=https://gitlab.com/-/profile/applications adresinde yeni bir uygulama kaydedin auths.tip.google_plus=OAuth2 istemci kimlik bilgilerini https://console.developers.google.com/ adresindeki Google API konsolundan edinin +auths.tip.openid_connect=Bitiş noktalarını belirlemek için OpenID Connect Discovery URL'sini (https://{server}/.well-known/openid-configuration) kullanın auths.tip.twitter=https://dev.twitter.com/apps adresine gidin, bir uygulama oluşturun ve “Bu uygulamanın Twitter ile oturum açmak için kullanılmasına izin ver” seçeneğinin etkin olduğundan emin olun auths.tip.discord=https://discordapp.com/developers/applications/me adresinde yeni bir uygulama kaydedin auths.tip.gitea=Yeni bir OAuth2 uygulaması kaydedin. Rehber https://docs.gitea.com/development/oauth2-provider adresinde bulunabilir @@ -3106,6 +3232,7 @@ config.picture_config=Resim ve Avatar Yapılandırması config.picture_service=Resim Servisi config.disable_gravatar=Gravatar Hizmet Dışı config.enable_federated_avatar=Birleştirilmiş Avatarları Etkinleştir +config.open_with_editor_app_help=Klon menüsü için "Birlikte aç" düzenleyicileri. Boş bırakılırsa, varsayılan kullanılacaktır. Varsayılanı görmek için genişletin. config.git_config=Git Yapılandırması config.git_disable_diff_highlight=Değişiklik Sözdizimi Vurgusunu Devre Dışı Bırak @@ -3184,6 +3311,13 @@ notices.desc=Açıklama notices.op=İşlem notices.delete_success=Sistem bildirimleri silindi. +self_check.no_problem_found=Henüz bir sorun bulunmadı. +self_check.startup_warnings=Başlangıç uyarıları: +self_check.database_collation_mismatch=Veritabanının şu harmanlamayı kullanmasını bekle: %s +self_check.database_collation_case_insensitive=Veritabanı %s harmanlamasını kullanıyor, bu duyarsız bir harmanlamadır. Her ne kadar Gitea bununla çalışabilse de, beklendiği gibi çalışmadığı nadir durumlar ortaya çıkabilir. +self_check.database_inconsistent_collation_columns=Veritabanı %s harmanlamasını kullanıyor, ancak bu sütunlar uyumsuz harmanlamalar kullanıyor. Bu beklenmedik sorunlar oluşturabilir. +self_check.database_fix_mysql=MySQL/MariaDB kullanıcıları "gitea doctor convert" komutunu harmanlama sorunlarını çözmek için kullanabilir veya "ALTER ... COLLATE ..." SQL'lerini şahsen çalıştırarak sorunu çözebilirler. +self_check.database_fix_mssql=MSSQL kullanıcıları sorunu şu an sadece "ALTER ... COLLATE ..." SQL'lerini şahsen çalıştırarak çözebilirler. [action] create_repo=depo <a href="%s">%s</a> oluşturuldu @@ -3371,6 +3505,7 @@ rpm.distros.suse=SUSE tabanlı dağıtımlarda rpm.install=Paketi kurmak için, aşağıdaki komutu çalıştırın: rpm.repository=Depo Bilgisi rpm.repository.architectures=Mimariler +rpm.repository.multiple_groups=Bu paket birçok grupta mevcut. rubygems.install=Paketi gem ile kurmak için, şu komutu çalıştırın: rubygems.install2=veya paketi Gemfile dosyasına ekleyin: rubygems.dependencies.runtime=Çalışma Zamanı Bağımlılıkları @@ -3497,12 +3632,15 @@ runs.scheduled=Zamanlanmış runs.pushed_by=iten runs.invalid_workflow_helper=İş akışı yapılandırma dosyası geçersiz. Lütfen yapılandırma dosyanızı denetleyin: %s runs.no_matching_online_runner_helper=Şu etiket ile eşleşen çevrimiçi çalıştırıcı bulunamadı: %s +runs.no_job_without_needs=İş akışı en azından bağımlılığı olmayan bir görev içermelidir. runs.actor=Aktör runs.status=Durum runs.actors_no_select=Tüm aktörler runs.status_no_select=Tüm durumlar runs.no_results=Eşleşen sonuç yok. runs.no_workflows=Henüz hiç bir iş akışı yok. +runs.no_workflows.quick_start=Gitea İşlemlerini nasıl başlatacağınızı bilmiyor musunuz? <a target="_blank" rel="noopener noreferrer" href="%s">Hızlı başlangıç kılavuzuna</a> bakabilirsiniz. +runs.no_workflows.documentation=Gitea İşlemleri hakkında daha fazla bilgi için, <a target="_blank" rel="noopener noreferrer" href="%s">belgelere</a> bakabilirsiniz. runs.no_runs=İş akışı henüz hiç çalıştırılmadı. runs.empty_commit_message=(boş işleme iletisi) @@ -3521,6 +3659,7 @@ variables.none=Henüz hiçbir değişken yok. variables.deletion=Değişkeni kaldır variables.deletion.description=Bir değişkeni kaldırma kalıcıdır ve geri alınamaz. Devam edilsin mi? variables.description=Değişkenler belirli işlemlere aktarılacaktır, bunun dışında okunamaz. +variables.id_not_exist=%d kimlikli değişken mevcut değil. variables.edit=Değişkeni Düzenle variables.deletion.failed=Değişken kaldırılamadı. variables.deletion.success=Değişken kaldırıldı. diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index fcc34e9177..aeba11fb9a 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -164,6 +164,8 @@ search=搜索... type_tooltip=搜索类型 fuzzy=模糊 fuzzy_tooltip=包含近似匹配搜索词的结果 +exact=精确 +exact_tooltip=仅包含精确匹配搜索词的结果 repo_kind=搜索仓库... user_kind=搜索用户... org_kind=搜索组织... @@ -177,6 +179,8 @@ branch_kind=搜索分支... commit_kind=搜索提交记录... runner_kind=搜索runners... no_results=未找到匹配结果 +issue_kind=搜索工单... +pull_kind=搜索合并请求... keyword_search_unavailable=按关键字搜索当前不可用。请联系站点管理员。 [aria] @@ -712,6 +716,7 @@ cancel=取消操作 language=界面语言 ui=主题 hidden_comment_types=隐藏的评论类型 +hidden_comment_types_description=此处选中的注释类型不会显示在问题页面中。比如,勾选”标签“删除所有 "<user> 添加/删除的 <label>" 注释。 hidden_comment_types.ref_tooltip=注释此问题在何处被提及过,如另一个问题、代码提交等 hidden_comment_types.issue_ref_tooltip=注释用户在何处更改了与此问题相关联的分支/标签 comment_type_group_reference=引用 @@ -882,6 +887,7 @@ repo_and_org_access=仓库和组织访问权限 permissions_public_only=仅公开 permissions_access_all=全部(公开、私有和受限) select_permissions=选择权限 +permission_not_set=未设置 permission_no_access=无访问权限 permission_read=可读 permission_write=读写 @@ -1286,6 +1292,7 @@ editor.or=或 editor.cancel_lower=取消 editor.commit_signed_changes=提交已签名的更改 editor.commit_changes=提交变更 +editor.add_tmpl=添加 '{filename}' editor.add=添加 %s editor.update=更新 %s editor.delete=删除 %s @@ -2092,6 +2099,7 @@ settings.advanced_settings=高级设置 settings.wiki_desc=启用仓库百科 settings.use_internal_wiki=使用内置百科 settings.default_wiki_branch_name=默认百科分支名称 +settings.default_wiki_everyone_access=登录用户的默认访问权限: settings.failed_to_change_default_wiki_branch=更改百科默认分支失败。 settings.use_external_wiki=使用外部百科 settings.external_wiki_url=外部 Wiki 链接 @@ -3083,12 +3091,14 @@ auths.tips=帮助提示 auths.tips.oauth2.general=OAuth2 认证 auths.tips.oauth2.general.tip=当注册新的 OAuth2 身份验证时,回调/重定向 URL 应该是: auths.tip.oauth2_provider=OAuth2 提供程序 +auths.tip.bitbucket=在 https://bitbucket.org/account/user/{your username}/oauth-consumers/new 注册新的 OAuth 使用者同时添加权限“账号”-“读取” auths.tip.nextcloud=使用下面的菜单“设置(Settings) -> 安全(Security) -> OAuth 2.0 client”在您的实例上注册一个新的 OAuth 客户端。 auths.tip.dropbox=在 https://www.dropbox.com/developers/apps 上创建一个新的应用程序 auths.tip.facebook=`在 https://developers.facebook.com/apps 注册一个新的应用,并添加产品"Facebook 登录"` auths.tip.github=在 https://github.com/settings/applications/new 注册一个 OAuth 应用程序 auths.tip.gitlab_new=在 https://gitlab.com/-/profile/applications 注册一个新的应用 auths.tip.google_plus=从谷歌 API 控制台 (https://console.developers.google.com/) 获得 OAuth2 客户端凭据 +auths.tip.openid_connect=使用 OpenID 连接发现 URL ({server}/.well-known/openid-configuration) 来指定终点 auths.tip.twitter=访问 https://dev.twitter.com/apps,创建应用并确保启用了"允许此应用程序用于登录 Twitter"的选项。 auths.tip.discord=在 https://discordapp.com/developers/applications/me 上注册新应用程序 auths.tip.gitea=注册一个新的 OAuth2 应用程序。可以访问 https://docs.gitea.com/development/oauth2-provider 查看帮助 From acfe29fc2bcc5261676868c8fdd6dc0def178d1e Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Fri, 19 Apr 2024 05:29:08 +0200 Subject: [PATCH 155/370] Enable npm cache on `setup-node` action (#30577) Enable npm dependency cache in [setup-node](https://github.com/actions/setup-node). This should work reliably and across branches as well. --- .github/workflows/pull-compliance.yml | 8 ++++++++ .github/workflows/pull-e2e-tests.yml | 2 ++ .github/workflows/release-nightly.yml | 2 ++ .github/workflows/release-tag-rc.yml | 2 ++ .github/workflows/release-tag-version.yml | 2 ++ 5 files changed, 16 insertions(+) diff --git a/.github/workflows/pull-compliance.yml b/.github/workflows/pull-compliance.yml index 99a69ab174..f89276fe82 100644 --- a/.github/workflows/pull-compliance.yml +++ b/.github/workflows/pull-compliance.yml @@ -38,6 +38,8 @@ jobs: - uses: actions/setup-node@v4 with: node-version: 20 + cache: npm + cache-dependency-path: package-lock.json - run: pip install poetry - run: make deps-py - run: make deps-frontend @@ -65,6 +67,8 @@ jobs: - uses: actions/setup-node@v4 with: node-version: 20 + cache: npm + cache-dependency-path: package-lock.json - run: make deps-frontend - run: make lint-swagger @@ -134,6 +138,8 @@ jobs: - uses: actions/setup-node@v4 with: node-version: 20 + cache: npm + cache-dependency-path: package-lock.json - run: make deps-frontend - run: make lint-frontend - run: make checks-frontend @@ -181,6 +187,8 @@ jobs: - uses: actions/setup-node@v4 with: node-version: 20 + cache: npm + cache-dependency-path: package-lock.json - run: make deps-frontend - run: make lint-md - run: make docs diff --git a/.github/workflows/pull-e2e-tests.yml b/.github/workflows/pull-e2e-tests.yml index 5a249db9f8..35ac7598f6 100644 --- a/.github/workflows/pull-e2e-tests.yml +++ b/.github/workflows/pull-e2e-tests.yml @@ -24,6 +24,8 @@ jobs: - uses: actions/setup-node@v4 with: node-version: 20 + cache: npm + cache-dependency-path: package-lock.json - run: make deps-frontend frontend deps-backend - run: npx playwright install --with-deps - run: make test-e2e-sqlite diff --git a/.github/workflows/release-nightly.yml b/.github/workflows/release-nightly.yml index 80e6683919..990f3c8e07 100644 --- a/.github/workflows/release-nightly.yml +++ b/.github/workflows/release-nightly.yml @@ -25,6 +25,8 @@ jobs: - uses: actions/setup-node@v4 with: node-version: 20 + cache: npm + cache-dependency-path: package-lock.json - run: make deps-frontend deps-backend # xgo build - run: make release diff --git a/.github/workflows/release-tag-rc.yml b/.github/workflows/release-tag-rc.yml index 12d1e1e4be..55908d3657 100644 --- a/.github/workflows/release-tag-rc.yml +++ b/.github/workflows/release-tag-rc.yml @@ -24,6 +24,8 @@ jobs: - uses: actions/setup-node@v4 with: node-version: 20 + cache: npm + cache-dependency-path: package-lock.json - run: make deps-frontend deps-backend # xgo build - run: make release diff --git a/.github/workflows/release-tag-version.yml b/.github/workflows/release-tag-version.yml index e0e93633e8..edf7ea1270 100644 --- a/.github/workflows/release-tag-version.yml +++ b/.github/workflows/release-tag-version.yml @@ -26,6 +26,8 @@ jobs: - uses: actions/setup-node@v4 with: node-version: 20 + cache: npm + cache-dependency-path: package-lock.json - run: make deps-frontend deps-backend # xgo build - run: make release From 61457cdf6b49225ae831fd9fb084deadd8bdb0fb Mon Sep 17 00:00:00 2001 From: Jason Song <i@wolfogre.com> Date: Fri, 19 Apr 2024 12:03:53 +0800 Subject: [PATCH 156/370] Avoid importing `modules/web/middleware` in `modules/session` (#30584) Related to #30375. It doesn't make sense to import `modules/web/middleware` and `modules/setting` in `modules/web/session` since the last one is more low-level. And it looks like a workaround to call `DeleteLegacySiteCookie` in `RegenerateSession`, so maybe we could reverse the importing by registering hook functions. --- modules/session/store.go | 13 ++++++------- modules/web/middleware/cookie.go | 15 ++++++++++++--- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/modules/session/store.go b/modules/session/store.go index 2f7ab7760b..70988fcdc5 100644 --- a/modules/session/store.go +++ b/modules/session/store.go @@ -6,9 +6,6 @@ package session import ( "net/http" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/web/middleware" - "gitea.com/go-chi/session" ) @@ -21,10 +18,12 @@ type Store interface { // RegenerateSession regenerates the underlying session and returns the new store func RegenerateSession(resp http.ResponseWriter, req *http.Request) (Store, error) { - // Ensure that a cookie with a trailing slash does not take precedence over - // the cookie written by the middleware. - middleware.DeleteLegacySiteCookie(resp, setting.SessionConfig.CookieName) - + for _, f := range BeforeRegenerateSession { + f(resp, req) + } s, err := session.RegenerateSession(resp, req) return s, err } + +// BeforeRegenerateSession is a list of functions that are called before a session is regenerated. +var BeforeRegenerateSession []func(http.ResponseWriter, *http.Request) diff --git a/modules/web/middleware/cookie.go b/modules/web/middleware/cookie.go index 0bed726793..ec6b06f993 100644 --- a/modules/web/middleware/cookie.go +++ b/modules/web/middleware/cookie.go @@ -9,6 +9,7 @@ import ( "net/url" "strings" + "code.gitea.io/gitea/modules/session" "code.gitea.io/gitea/modules/setting" ) @@ -48,12 +49,12 @@ func SetSiteCookie(resp http.ResponseWriter, name, value string, maxAge int) { // Previous versions would use a cookie path with a trailing /. // These are more specific than cookies without a trailing /, so // we need to delete these if they exist. - DeleteLegacySiteCookie(resp, name) + deleteLegacySiteCookie(resp, name) } -// DeleteLegacySiteCookie deletes the cookie with the given name at the cookie +// deleteLegacySiteCookie deletes the cookie with the given name at the cookie // path with a trailing /, which would unintentionally override the cookie. -func DeleteLegacySiteCookie(resp http.ResponseWriter, name string) { +func deleteLegacySiteCookie(resp http.ResponseWriter, name string) { if setting.SessionConfig.CookiePath == "" || strings.HasSuffix(setting.SessionConfig.CookiePath, "/") { // If the cookie path ends with /, no legacy cookies will take // precedence, so do nothing. The exception is that cookies with no @@ -74,3 +75,11 @@ func DeleteLegacySiteCookie(resp http.ResponseWriter, name string) { } resp.Header().Add("Set-Cookie", cookie.String()) } + +func init() { + session.BeforeRegenerateSession = append(session.BeforeRegenerateSession, func(resp http.ResponseWriter, _ *http.Request) { + // Ensure that a cookie with a trailing slash does not take precedence over + // the cookie written by the middleware. + deleteLegacySiteCookie(resp, setting.SessionConfig.CookieName) + }) +} From fe829915475cadd0f6285a30d629772920e8bf32 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Fri, 19 Apr 2024 14:08:30 +0800 Subject: [PATCH 157/370] Fix changelog (main) (#30582) 1. The 1.21.11 changelog is missing 2. Split the old content to CHANGELOG-archived.md, to reduce the size of CHANGELOG.md --- CHANGELOG-archived.md | 5223 +++++++++++++++++++++++++++++++++++++++ CHANGELOG.md | 5358 ++--------------------------------------- 2 files changed, 5365 insertions(+), 5216 deletions(-) create mode 100644 CHANGELOG-archived.md diff --git a/CHANGELOG-archived.md b/CHANGELOG-archived.md new file mode 100644 index 0000000000..e0551d39a6 --- /dev/null +++ b/CHANGELOG-archived.md @@ -0,0 +1,5223 @@ +# Changelog (archived) + +This changelog (archived) contains changes for old releases. + +* Recent changelogs: [CHANGELOG.md](CHANGELOG.md) +* Release blogs with highlights: [blog.gitea.com](https://blog.gitea.com). + +## [1.15.11](https://github.com/go-gitea/gitea/releases/tag/v1.15.11) - 2022-01-29 + +* SECURITY + * Only view milestones from current repo (#18414) (#18418) +* BUGFIXES + * Fix broken when no commits and default branch is not master (#18422) (#18424) + * Fix commit's time (#18375) (#18409) + * Fix restore without topic failure (#18387) (#18401) + * Fix mermaid import in 1.15 (it uses ESModule now) (#18382) + * Update to go/text 0.3.7 (#18336) +* MISC + * Upgrade EasyMDE to 2.16.1 (#18278) (#18279) + +## [1.15.10](https://github.com/go-gitea/gitea/releases/tag/v1.15.10) - 2022-01-14 + +* BUGFIXES + * Fix inconsistent PR comment counts (#18260) (#18261) + * Fix release link broken (#18252) (#18253) + * Fix update user from site administration page bug (#18250) (#18251) + * Set HeadCommit when creating tags (#18116) (#18173) + * Use correct translation key for error messages due to max repo limits (#18135 & #18153) (#18152) + * Fix purple color in suggested label colors (#18241) (#18242) +* SECURITY + * Bump mermaid from 8.10.1 to 8.13.8 (#18198) (#18206) + +## [1.15.9](https://github.com/go-gitea/gitea/releases/tag/v1.15.9) - 2021-12-30 + +* BUGFIXES + * Fix wrong redirect on org labels (#18128) (#18134) + * Fix: unstable sort skips/duplicates issues across pages (#18094) (#18095) + * Revert "Fix delete u2f keys bug (#18042)" (#18107) + * Migrating wiki don't require token, so we should move it out of the require form (#17645) (#18104) + * Prevent NPE if gitea uploader fails to open url (#18080) (#18101) + * Reset locale on login (#17734) (#18100) + * Correctly handle failed migrations (#17575) (#18099) + * Instead of using routerCtx just escape the url before routing (#18086) (#18098) + * Quote references to the user table in consistency checks (#18072) (#18073) + * Add NotFound handler (#18062) (#18067) + * Ensure that git repository is closed before transfer (#18049) (#18057) + * Use common sessioner for API and web routes (#18114) +* TRANSLATION + * Fix code search result hint on zh-CN (#18053) + +## [1.15.8](https://github.com/go-gitea/gitea/releases/tag/v1.15.8) - 2021-12-20 + +* BUGFIXES + * Move POST /{username}/action/{action} to simply POST /{username} (#18045) (#18046) + * Fix delete u2f keys bug (#18040) (#18042) + * Reset Session ID on login (#18018) (#18041) + * Prevent off-by-one error on comments on newly appended lines (#18029) (#18035) + * Stop printing 03d after escaped characters in logs (#18030) (#18034) + * Reset locale on login (#18023) (#18025) + * Fix reset password email template (#17025) (#18022) + * Fix outType on gitea dump (#18000) (#18016) + * Ensure complexity, minlength and isPwned are checked on password setting (#18005) (#18015) + * Fix rename notification bug (#18011) + * Prevent double decoding of % in url params (#17997) (#18001) + * Prevent hang in git cat-file if the repository is not a valid repository (Partial #17991) (#17992) + * Prevent deadlock in create issue (#17970) (#17982) +* TESTING + * Use non-expiring key. (#17984) (#17985) + +## [1.15.7](https://github.com/go-gitea/gitea/releases/tag/v1.15.7) - 2021-12-01 + +* ENHANCEMENTS + * Only allow webhook to send requests to allowed hosts (#17482) (#17510) + * Fix login redirection links (#17451) (#17473) +* BUGFIXES + * Fix database inconsistent when admin change user email (#17549) (#17840) + * Use correct user on releases (#17806) (#17818) + * Fix commit count in tag view (#17698) (#17790) + * Fix close issue but time watcher still running (#17643) (#17761) + * Fix Migrate Description (#17692) (#17727) + * Fix bug when project board get open issue number (#17703) (#17726) + * Return 400 but not 500 when request archive with wrong format (#17691) (#17700) + * Fix bug when read mysql database max lifetime (#17682) (#17690) + * Fix database deadlock when update issue labels (#17649) (#17665) + * Fix bug on detect issue/comment writer (#17592) + * Remove appSubUrl from pasted images (#17572) (#17588) + * Make `ParsePatch` more robust (#17573) (#17580) + * Fix stats upon searching issues (#17566) (#17578) + * Escape issue titles in comments list (#17555) (#17556) + * Fix zero created time bug on commit api (#17546) (#17547) + * Fix database keyword quote problem on migration v161 (#17522) (#17523) + * Fix email with + when active (#17518) (#17520) + * Stop double encoding blame commit messages (#17498) (#17500) + * Quote the table name in CountOrphanedObjects (#17487) (#17488) + * Run Migrate in Install rather than just SyncTables (#17475) (#17486) +* BUILD + * Fix golangci-lint warnings (#17598 et al) (#17668) +* MISC + * Preserve color when inverting emojis (#17797) (#17799) + +## [1.15.6](https://github.com/go-gitea/gitea/releases/tag/v1.15.6) - 2021-10-28 + +* BUGFIXES + * Prevent panic in serv.go with Deploy Keys (#17434) (#17435) + * Fix CSV render error (#17406) (#17431) + * Read expected buffer size (#17409) (#17430) + * Ensure that restricted users can access repos for which they are members (#17460) (#17464) + * Make commit-statuses popup show correctly (#17447) (#17466) +* TESTING + * Add integration tests for private.NoServCommand and private.ServCommand (#17456) (#17463) + +## [1.15.5](https://github.com/go-gitea/gitea/releases/tag/v1.15.5) - 2021-10-21 + +* SECURITY + * Upgrade Bluemonday to v1.0.16 (#17372) (#17374) + * Ensure correct SSH permissions check for private and restricted users (#17370) (#17373) +* BUGFIXES + * Prevent NPE in CSV diff rendering when column removed (#17018) (#17377) + * Offer rsa-sha2-512 and rsa-sha2-256 algorithms in internal SSH (#17281) (#17376) + * Don't panic if we fail to parse U2FRegistration data (#17304) (#17371) + * Ensure popup text is aligned left (backport for 1.15) (#17343) + * Ensure that git daemon export ok is created for mirrors (#17243) (#17306) + * Disable core.protectNTFS (#17300) (#17302) + * Use pointer for wrappedConn methods (#17295) (#17296) + * AutoRegistration is supposed to be working with disabled registration (backport) (#17292) + * Handle duplicate keys on GPG key ring (#17242) (#17284) + * Fix SVG side by side comparison link (#17375) (#17391) + +## [1.15.4](https://github.com/go-gitea/gitea/releases/tag/v1.15.4) - 2021-10-08 + +* BUGFIXES + * Raw file API: don't try to interpret 40char filenames as commit SHA (#17185) (#17272) + * Don't allow merged PRs to be reopened (#17192) (#17271) + * Fix incorrect repository count on organization tab of dashboard (#17256) (#17266) + * Fix unwanted team review request deletion (#17257) (#17264) + * Fix broken Activities link in team dashboard (#17255) (#17258) + * API pull's head/base have correct permission(#17214) (#17245) + * Fix strange behavior of DownloadPullDiffOrPatch in incorrect index (#17223) (#17227) + * Upgrade xorm to v1.2.5 (#17177) (#17188) + * Fix missing repo link in issue/pull assigned emails (#17183) (#17184) + * Fix bug of get context user (#17169) (#17172) + * Nicely handle missing user in collaborations (#17049) (#17166) + * Add Horizontal scrollbar to inner menu on Chrome (#17086) (#17164) + * Fix wrong i18n keys (#17150) (#17153) + * Fix Archive Creation: correct transaction ending (#17151) + * Prevent panic in Org mode HighlightCodeBlock (#17140) (#17141) + * Create doctor command to fix repo_units broken by dumps from 1.14.3-1.14.6 (#17136) (#17137) +* ENHANCEMENT + * Check user instead of organization when creating a repo from a template via API (#16346) (#17195) +* TRANSLATION + * v1.15 fix Sprintf format 'verbs' in locale files (#17187) + +## [1.15.3](https://github.com/go-gitea/gitea/releases/tag/v1.15.3) - 2021-09-19 + +* ENHANCEMENTS + * Add fluid to ui container class to remove margin (#16396) (#16976) + * Add caller to cat-file batch calls (#17082) (#17089) +* BUGFIXES + * Render full plain readme. (#17083) (#17090) + * Upgrade xorm to v1.2.4 (#17059) + * Fix bug of migrate comments which only fetch one page (#17055) (#17058) + * Do not show issue context popup on external issues (#17050) (#17054) + * Decrement Fork Num when converting from Fork (#17035) (#17046) + * Correctly rollback in ForkRepository (#17034) (#17045) + * Fix missing close in WalkGitLog (#17008) (#17009) + * Add prefix to SVG id/class attributes (#16997) (#17000) + * Fix bug of migrated repository not index (#16991) (#16996) + * Skip AllowedUserVisibilityModes validation on update user if it is an organisation (#16988) (#16990) + * Fix storage Iterate bug and Add storage doctor to delete garbage attachments (#16971) (#16977) + * Fix issue with issue default mail template (#16956) (#16975) + * Ensure that rebase conflicts are handled in updates (#16952) (#16960) + * Prevent panic on diff generation (#16950) (#16951) + +## [1.15.2](https://github.com/go-gitea/gitea/releases/tag/v1.15.2) - 2021-09-03 + +* BUGFIXES + * Add unique constraint back into issue_index (#16938) + * Close storage objects before cleaning (#16934) (#16942) + +## [1.15.1](https://github.com/go-gitea/gitea/releases/tag/v1.15.1) - 2021-09-02 + +* BUGFIXES + * Allow BASIC authentication access to /:owner/:repo/releases/download/* (#16916) (#16923) + * Prevent leave changes dialogs due to autofill fields (#16912) (#16920) + * Ignore review comment when ref commit is missed (#16905) (#16919) + * Fix wrong attachment removal (#16915) (#16917) + * Gitlab Migrator: dont ignore reactions of last request (#16903) (#16913) + * Correctly return the number of Repositories for Organizations (#16807) (#16911) + * Test if LFS object is accessible (#16865) (#16904) + * Fix git.Blob.DataAsync(): close pipe since we return a NopCloser (#16899) (#16900) + * Fix dump and restore repository (#16698) (#16898) + * Repare and Improve GetDiffRangeWithWhitespaceBehavior (#16894) (#16895) + * Fix wiki raw commit diff/patch view (#16891) (#16892) + * Ensure wiki repos are all closed (#16886) (#16888) + * List limited and private orgs if authenticated on API (#16866) (#16879) + * Simplify split diff view generation and remove JS dependency (#16775) (#16863) + * Ensure that the default visibility is set on the user create page (#16845) (#16862) + * In Render tolerate not being passed a context (#16842) (#16858) + * Upgrade xorm to v1.2.2 (#16663) & Add test to ensure that dumping of login sources remains correct (#16847) (#16848) + * Report the correct number of pushes on the feeds (#16811) (#16822) + * Add primary_key to issue_index (#16813) (#16820) + * Prevent NPE on empty commit (#16812) (#16819) + * Fix branch pagination error (#16805) (#16816) + * Add missing return to handleSettingRemoteAddrError (#16794) (#16795) + * Remove spurious / from issues.opened_by (#16793) + * Ensure that template compilation panics are sent to the logs (#16788) (#16792) + * Update caddyserver/certmagic (#16789) (#16790) + +## [1.15.0](https://github.com/go-gitea/gitea/releases/tag/v1.15.0) - 2021-08-21 + +* BREAKING + * Make app.ini permissions more restrictive (#16266) + * Refactor Webhook + Add X-Hub-Signature (#16176) + * Add asymmetric JWT signing (#16010) + * Clean-up the settings hierarchy for issue_indexer queue (#16001) + * Change default queue settings to be low go-routines (#15964) + * Improve assets handler middleware (#15961) + * Rename StaticUrlPrefix to AssetUrlPrefix (#15779) + * Use a generic markup class to display externally rendered files and diffs (#15735) + * Add frontend testing, require node 12 (#15315) + * Move (custom) assets into subpath `/assets` (#15219) + * Use level config in log section when sub log section not set level (#15176) + * Links in markdown should be absolute to the repository not the server (#15088) + * Upgrade to the latest version of golang-jwt (#16590) (#16606) + * Set minimum supported version of go to 1.16 (#16710) +* SECURITY + * Encrypt LDAP bind password in db with SECRET_KEY (#15547) + * Remove random password in Dockerfiles (#15362) + * Upgrade to the latest version of golang-jwt and increase minimum go to 1.15 (#16590) (#16606) + * Correctly create of git-daemon-export-ok files (#16508) (#16514) + * Don't show private user's repo in explore view (#16550) (#16554) + * Update node tar dependency to 6.1.6 (#16622) (#16623) +* FEATURES + * Update Go-Git to take advantage of LargeObjectThreshold (#16316) + * Support custom mime type mapping for text files (#16304) + * Link to previous blames in file blame page (#16259) + * Add LRU mem cache implementation (#16226) + * Localize Email Templates (#16200) + * Make command in authorized keys a template (#16003) + * Add possibility to make branch in branch page (#15960) + * Add email headers (#15939) + * Make tasklist checkboxes clickable (#15791) + * Add selecting tags on the compare page (#15723) + * Add cron job to delete old actions from database (#15688) + * On open repository open common cat file batch and batch-check (#15667) + * Add tag protection (#15629) + * Add push to remote mirror repository (#15157) + * Add Image Diff for SVG files (#14867) + * Add dashboard milestone search and repo milestone search by name. (#14866) + * Add LFS Migration and Mirror (#14726) + * Improve notifications for WIP draft PR's (#14663) + * Disable Stars config option (#14653) + * GPG Key Ownership verification with Signed Token (#14054) + * OAuth2 auto-register (#5123) +* API + * Return updated repository when changing repository using API (#16420) + * Let branch/tag name be a valid ref to get CI status (#16400) + * Add endpoint to get commits of PR (#16300) + * Allow COMMENT reviews to not specify a body (#16229) + * Add subject-type filter to list notification API endpoints (#16177) + * ListReleases add filter for draft and pre-releases (#16175) + * ListIssues add more filters (#16174) + * Issue Search Add filter for MilestoneNames (#16173) + * GET / SET User Settings (#16169) + * Expose repo.GetReviewers() & repo.GetAssignees() (#16168) + * User expose counters (#16167) + * Add repoGetTag (#16166) + * Add repoCreateTag (#16165) + * Creating a repo from a template repo via API (#15958) + * Add Active and ProhibitLogin to API (#15689) + * Add Location, Website and Description to API (#15675) + * Expose resolver via API (#15167) + * Swagger AccessToken fixes (#16574) (#16597) + * Set AllowedHeaders on API CORS handler (#16524) (#16618) +* ENHANCEMENTS + * Support HTTP/2 in Let's Encrypt (#16371) + * Introduce NotifySubjectType (#16320) + * Add forge emojies (#16296) + * Implemented head_commit for webhooks (#16282) + * Upgrade Gliderlabs SSH to 0.3.3 and add FailedConnectionCallback (#16278) + * Add previous/next buttons to review comments (#16273) + * Review comments: break-word for long file names (#16272) + * Add configuration to restrict allowed user visibility modes (#16271) + * Add scroll-margin-top to account for sticky header (#16269) + * Add --quiet and --verbose to gitea web to control initial logging (#16260) + * Use gitea logging module for git module (#16243) + * Add tests for all webhooks (#16214) + * Add button to delete undeleted repositories from failed migrations (#16197) + * Speed up git diff highlight generation (#16180) + * Add OpenID claims "profile" and "email". (#16141) + * Reintroduce squash merge default comment as a config setting (#16134) + * Add sanitizer rules per renderer (#16110) + * Improve performance of dashboard list orgs (#16099) + * Refactor assert statements in tests (#16089) + * Add sso.Group, context.Auth, context.APIAuth to allow auth special routes (#16086) + * Remove unnecessary goroutine (#16080) + * Add attachments for PR reviews (#16075) + * Make the github migration less rate limit waiting to get comment per page from repository but not per issue (#16070) + * Add Visible modes function from Organisation to Users too (#16069) + * Add checkbox to delete pull branch after successful merge (#16049) + * Make commit info cancelable (#16032) + * Make modules/context.Context a context.Context (#16031) + * Unified custom config creation (#16012) + * Make sshd_config more flexible regarding connections (#16009) + * Append to existing trailers in generated squash commit message (#15980) + * Always store primary email address into email_address table and also the state (#15956) + * Load issue/PR context popup data only when needed (#15955) + * Remove remaining fontawesome usage in templates (#15952) + * Remove fomantic accordion module (#15951) + * Small refactoring of modules/private (#15947) + * Double the avatar size factor (#15941) + * Add curl to rootless docker image (#15908) + * Replace clipboard.js with async clipboard api (#15899) + * Allow custom highlight mapping beyond file extensions (#15808) + * Add trace logging to SSO methods (#15803) + * Refactor routers directory (#15800) + * Allow only internal registration (#15795) + * Add a new internal hook to save ssh log (#15787) + * Respect default merge message syntax when parsing item references (#15772) + * OAuth2 login: Set account link to "login" as default behavior (#15768) + * Use single shared random string generation function (#15741) + * Hold the event source when there are no listeners (#15725) + * Code comments improvements (#15722) + * Provide OIDC compliant user info endpoint (#15721) + * Fix webkit calendar icon color on arc-green (#15713) + * Improve Light Chroma style (#15699) + * Only use boost workers for leveldb shadow queues (#15696) + * Add compare tag dropdown to releases page (#15695) + * Add caret styling CSS (#15651) + * Remove x-ua-compatible meta tag (#15640) + * Refactor of link creation (#15619) + * Add a new table issue_index to store the max issue index so that issue could be deleted with no duplicated index (#15599) + * Rewrite of the LFS server (#15523) + * Display more repository type on admin repository management (#15440) + * Remove usage of some JS globals (#15378) + * SHA in merged commit comment should be rendered ui sha (#15376) + * Add well-known config for OIDC (#15355) + * Use route rather than use thus reducing the number of stack frames (#15301) + * Code Formats, Nits & Unused Func/Var deletions (#15286) + * Let package git depend on setting but not opposite (#15241) + * Fixed sanitize errors (#15240) + * response simple text message for not html request when 404 (#15229) + * Remove file-loader dependency (#15196) + * Refactor renders (#15175) + * Add mimetype mapping settings (#15133) + * Add Status Updates whilst Gitea migrations are occurring (#15076) + * Reload locales in initialisation if needed by utilizing i18n.Reset (#15073) + * Counterwork seemingly unclickable repo button labels (#15064) + * Add DefaultMergeStyle option to repository (#14789) + * Added support for gopher URLs. (#14749) + * Rework repository archive (#14723) + * Add links to toggle WIP status (#14677) + * Add Tabular Diff for CSV files (#14661) + * Use milestone deadline when sorting issues (#14551) +* BUGFIXES + * Fix invalid params and typo of email templates (#16394) + * Fix activation of primary email addresses (#16385) + * Fix calculation for finalPage in repo-search component (#16382) + * Specify user in rootless container numerically (#16361) + * Detect encoding changes while parsing diff (#16330) + * Fix U2F error reasons always hidden (#16327) + * Prevent zombie processes (#16314) + * Escape reference to `user` table in models.SearchEmails (#16313) + * Fix default push instructions on empty repos (#16302) + * Fix modified files list in webhooks when there is a space (#16288) + * Fix webhook commits wrong hash on HEAD reset (#16283) + * Fuzzer finds an NPE due to incorrect URLPrefix (#16249) + * Don't WARN log UserNotExist errors on ExternalUserLogin failure (#16238) + * Do not show No match found for tribute (#16231) + * Fix "Copy Link" for pull requests (#16230) + * Fix diff expansion is missing final line in a file (#16222) + * Fix private repo permission problem (#16142) + * Fix not able to update local created non-urlencoded wiki pages (#16139) + * More efficiently parse shas for shaPostProcessor (#16101) + * Fix `doctor --run check-db-consistency --fix` with label fix (#16094) + * Prevent webhook action buttons from shifting (#16087) + * Change default TMPDIR path in rootless containers (#16077) + * Fix typo and add TODO notice (#16064) + * Use git log name-status in get last commit (#16059) + * Fix 500 Error with branch and tag sharing the same name (#16040) + * Fix get tag when migration (#16014) + * Add custom emoji support (#16004) + * Use filepath.ToSlash and Join in indexer defaults and queues (#15971) + * Add permission check for ``GenerateRepository`` (#15946) + * Ensure settings for Service and Mailer are read on the install page (#15943) + * Fix layout of milestone view (#15927) + * Unregister non-matching serviceworkers (#15834) + * Multiple Queue improvements: LevelDB Wait on empty, shutdown empty shadow level queue, reduce goroutines etc (#15693) + * Attachment support repository route (#15580) + * Fix missing icons and colorpicker when mounted on suburl (#15501) + * Create a session on ReverseProxy and ensure that ReverseProxy users cannot change username (#15304) + * Prevent double-login for Git HTTP and LFS and simplify login (#15303) + * Resolve Object { type: "error", data: undefined } in stopwatch.js (#15278) + * Fix heatmap activity (#15252) + * Remove vendored copy of fomantic-dropdown (#15193) + * Update repository size on cron gc task (#15177) + * Add NeedPostProcess for Parser interface to improve performance of csv parser and some external parser (#15153) + * Add code block highlight to orgmode back (#14222) + * Remove User.GetOrganizations() (#14032) + * Restore Accessibility for Dropdown (#16576) (#16617) + * Pass down SignedUserName down to AccessLogger context (#16605) (#16616) + * Fix table alignment in markdown (#16596) (#16602) + * Fix 500 on first wiki page (#16586) (#16598) + * Lock goth/gothic and Re-attempt OAuth2 registration on login if registration failed at startup (#16564) (#16570) + * Upgrade levelqueue to v0.4.0 (#16560) (#16561) + * Handle too long PR titles correctly (#16517) (#16549) + * Fix data race in bleve indexer (#16474) (#16509) + * Restore CORS on git smart http protocol (#16496) (#16506) + * Fix race in log (#16490) (#16505) + * Fix prepareWikiFileName to respect existing unescaped files (#16487) (#16498) + * Make cancel from CatFileBatch and CatFileBatchCheck wait for the command to end (#16479) (#16480) + * Update notification table with only latest data (#16445) (#16469) + * Fix crash following ldap authentication update (#16447) (#16448) + * Fix direct creation of external users on admin page (partial #16612) (#16613) + * Prevent 500 on draft releases without tag (#16634) (#16636) + * Restore creation of git-daemon-export-ok files (#16508) (#16514) + * Fix data race in bleve indexer (#16474) (#16509) + * Restore CORS on git smart http protocol (#16496) (#16506) + * Fix race in log (#16490) (#16505) + * Fix prepareWikiFileName to respect existing unescaped files (#16487) (#16498) + * Make cancel from CatFileBatch and CatFileBatchCheck wait for the command to end (#16479) (#16480) + * Update notification table with only latest data (#16445) (#16469) + * Fix crash following ldap authentication update (#16447) (#16448) + * Restore compatibility with SQLServer 2008 R2 in migrations (#16638) + * Fix direct creation of external users on admin page (#16613) + * Fix go-git implementation of GetNote when passed a non-existent commit (#16658) (#16659) + * Fix NPE in fuzzer (#16680) (#16682) + * Set issue_index when finishing migration (#16685) (#16687) + * Skip patch download when no patch file exists (#16356) (#16681) + * Ensure empty lines are copiable and final new line too (#16678) (#16692) + * Fix wrong user in OpenID response (#16736) (#16741) + * Do not use thin scrollbars on Firefox (#16738) (#16745) + * Recreate Tables should Recreate indexes on MySQL (#16718) (#16739) + * Keep attachments on tasklist update (#16750) (#16757) +* TESTING + * Bump `postgres` and `mysql` versions (#15710) + * Add tests for clone from wiki (#15513) + * Fix Benchmark tests, remove a broken one & add two new (#15250) + * Create Proper Migration tests (#15116) +* TRANSLATION + * Use a special name for update default branch on repository setting (#15893) + * Fix mirror_lfs source string in en-US locale (#15369) +* BUILD + * Upgrade xorm to v1.1.1 (#16339) + * Disable legal comments in esbuild (#15929) + * Switch to Node 16 to build fronted (#15804) + * Use esbuild to minify CSS (#15756) + * Use binary version of revive linter (#15739) + * Fix: npx webpack make: *** [Makefile:699: public/js/index.js] Error -… (#15465) + * Stop packaging node_modules in release tarballs (#15273) + * Introduce esbuild on webpack (#14578) +* DOCS + * Update queue workers documentation (#15999) + * Comment out app.example.ini (#15807) + * Improve logo customization docs (#15754) + * Add some response status on api docs (#15399) + * Rework Token API comments (#15162) + * Add better errors for disabled account recovery (#15117) +* MISC + * Remove utf8 option from installation page (#16126) + * Use Wants= over Requires= in systemd file (#15897) + +## [1.14.7](https://github.com/go-gitea/gitea/releases/tag/v1.14.7) - 2021-09-02 + +* BUGFIXES + * Add missing gitRepo close at GetDiffRangeWithWhitespaceBehavior (Partial #16894) (#16896) + * Fix wiki raw commit diff/patch view (#16891) (#16893) + * Ensure wiki repos are all closed (#16886) (#16889) + * Upgrade xorm to v1.2.2 (#16663) & Add test to ensure that dumping of login sources remains correct (#16847) (#16849) + * Recreate Tables should Recreate indexes on MySQL (#16718) (#16740) + +## [1.14.6](https://github.com/go-gitea/gitea/releases/tag/v1.14.6) - 2021-08-04 + +* SECURITY + * Bump github.com/markbates/goth from v1.67.1 to v1.68.0 (#16538) (#16540) + * Switch to maintained JWT lib (#16532) (#16535) + * Upgrade to latest version of golang-jwt (as forked for 1.14) (#16590) (#16607) +* BUGFIXES + * Add basic edit ldap auth test & actually fix #16252 (#16465) (#16495) + * Make cancel from CatFileBatch and CatFileBatchCheck wait for the command to end (#16479) (#16481) + +## [1.14.5](https://github.com/go-gitea/gitea/releases/tag/v1.14.5) - 2021-07-16 + +* SECURITY + * Hide mirror passwords on repo settings page (#16022) (#16355) + * Update bluemonday to v1.0.15 (#16379) (#16380) +* BUGFIXES + * Retry rename on lock induced failures (#16435) (#16439) + * Validate issue index before querying DB (#16406) (#16410) + * Fix crash following ldap authentication update (#16447) (#16449) +* ENHANCEMENTS + * Redirect on bad CSRF instead of presenting bad page (#14937) (#16378) + +## [1.14.4](https://github.com/go-gitea/gitea/releases/tag/v1.14.4) - 2021-07-06 + +* BUGFIXES + * Fix relative links in postprocessed images (#16334) (#16340) + * Fix list_options GetStartEnd (#16303) (#16305) + * Fix API to use author for commits instead of committer (#16276) (#16277) + * Handle misencoding of login_source cfg in mssql (#16268) (#16275) + * Fixed issues not updated by commits (#16254) (#16261) + * Improve efficiency in FindRenderizableReferenceNumeric and getReference (#16251) (#16255) + * Use html.Parse rather than html.ParseFragment (#16223) (#16225) + * Fix milestone counters on new issue (#16183) (#16224) + * reqOrgMembership calls need to be preceded by reqToken (#16198) (#16219) + +## [1.14.3](https://github.com/go-gitea/gitea/releases/tag/v1.14.3) - 2021-06-18 + +* SECURITY + * Encrypt migration credentials at rest (#15895) (#16187) + * Only check access tokens if they are likely to be tokens (#16164) (#16171) + * Add missing SameSite settings for the i_like_gitea cookie (#16037) (#16039) + * Fix setting of SameSite on cookies (#15989) (#15991) +* API + * Repository object only count releases as releases (#16184) (#16190) + * EditOrg respect RepoAdminChangeTeamAccess option (#16184) (#16190) + * Fix overly strict edit pr permissions (#15900) (#16081) +* BUGFIXES + * Run processors on whole of text (#16155) (#16185) + * Class `issue-keyword` is being incorrectly stripped off spans (#16163) (#16172) + * Fix language switch for install page (#16043) (#16128) + * Fix bug on getIssueIDsByRepoID (#16119) (#16124) + * Set self-adjusting deadline for connection writing (#16068) (#16123) + * Fix http path bug (#16117) (#16120) + * Fix data URI scramble (#16098) (#16118) + * Merge all deleteBranch as one function and also fix bug when delete branch don't close related PRs (#16067) (#16097) + * git migration: don't prompt interactively for clone credentials (#15902) (#16082) + * Fix case change in ownernames (#16045) (#16050) + * Don't manipulate input params in email notification (#16011) (#16033) + * Remove branch URL before IssueRefURL (#15968) (#15970) + * Fix layout of milestone view (#15927) (#15940) + * GitHub Migration, migrate draft releases too (#15884) (#15888) + * Close the gitrepo when deleting the repository (#15876) (#15887) + * Upgrade xorm to v1.1.0 (#15869) (#15885) + * Fix blame row height alignment (#15863) (#15883) + * Fix error message when saving generated LOCAL_ROOT_URL config (#15880) (#15882) + * Backport Fix LFS commit finder not working (#15856) (#15874) + * Stop calling WriteHeader in Write (#15862) (#15873) + * Add timeout to writing to responses (#15831) (#15872) + * Return go-get info on subdirs (#15642) (#15871) + * Restore PAM user autocreation functionality (#15825) (#15867) + * Fix truncate utf8 string (#15828) (#15854) + * Fix bound address/port for caddy's certmagic library (#15758) (#15848) + * Upgrade unrolled/render to v1.1.1 (#15845) (#15846) + * Queue manager FlushAll can loop rapidly - add delay (#15733) (#15840) + * Tagger can be empty, as can Commit and Author - tolerate this (#15835) (#15839) + * Set autocomplete off on branches selector (#15809) (#15833) + * Add missing error to Doctor log (#15813) (#15824) + * Move restore repo to internal router and invoke from command to avoid open the same db file or queues files (#15790) (#15816) +* ENHANCEMENTS + * Removable media support to snap package (#16136) (#16138) + * Move sans-serif fallback font higher than emoji fonts (#15855) (#15892) +* DOCKER + * Only write config in environment-to-ini if there are changes (#15861) (#15868) + * Only offer hostcertificates if they exist (#15849) (#15853) + +## [1.14.2](https://github.com/go-gitea/gitea/releases/tag/v1.14.2) - 2021-05-09 + +* API + * Make change repo settings work on empty repos (#15778) (#15789) + * Add pull "merged" notification subject status to API (#15344) (#15654) +* BUGFIXES + * Ensure that ctx.Written is checked after issues(...) calls (#15797) (#15798) + * Use pulls in commit graph unless pulls are disabled (#15734 & #15740 & #15774) (#15775) + * Set GIT_DIR correctly if it is not set (#15751) (#15769) + * Fix bug where repositories appear unadopted (#15757) (#15767) + * Not show `ref-in-new-issue` pop when issue was disabled (#15761) (#15765) + * Drop back to use IsAnInteractiveSession for SVC (#15749) (#15762) + * Fix setting version table in dump (#15753) (#15759) + * Fix close button change on delete in simplemde area (#15737) (#15747) + * Defer closing the gitrepo until the end of the wrapped context functions (#15653) (#15746) + * Fix some ui bug about draft release (#15137) (#15745) + * Only log Error on getLastCommitStatus error to let pull list still be visible (#15716) (#15715) + * Move tooltip down to allow selection of Remove File on error (#15672) (#15714) + * Fix setting redis db path (#15698) (#15708) + * Fix DB session cleanup (#15697) (#15700) + * Fixed several activation bugs (#15473) (#15685) + * Delete references if repository gets deleted (#15681) (#15684) + * Fix orphaned objects deletion bug (#15657) (#15683) + * Delete protected branch if repository gets removed (#15658) (#15676) + * Remove spurious set name from eventsource.sharedworker.js (#15643) (#15652) + * Not update updated uinx for `git gc` (#15637) (#15641) + * Fix commit graph author link (#15627) (#15630) + * Fix webhook timeout bug (#15613) (#15621) + * Resolve panic on failed interface conversion in migration v156 (#15604) (#15610) + * Fix missing storage init (#15589) (#15598) + * If the default branch is not present do not report error on stats indexing (#15546 & #15583) (#15594) + * Fix lfs management find (#15537) (#15578) + * Fix NPE on view commit with notes (#15561) (#15573) + * Fix bug on commit graph (#15517) (#15530) + * Send size to /avatars if requested (#15459) (#15528) + * Prevent migration 156 failure if tag commit missing (#15519) (#15527) +* ENHANCEMENTS + * Display conflict-free merge messages for pull requests (#15773) (#15796) + * Exponential Backoff for ByteFIFO (#15724) (#15793) + * Issue list alignment tweaks (#15483) (#15766) + * Implement delete release attachments and update release attachments' name (#14130) (#15666) + * Add placeholder text to deploy key textarea (#15575) (#15576) + * Project board improvements (#15429) (#15560) + * Repo branch page: label size, PR ref, new PR button alignment (#15363) (#15365) +* MISC + * Fix webkit calendar icon color on arc-green (#15713) (#15728) + * Performance improvement for last commit cache and show-ref (#15455) (#15701) + * Bump unrolled/render to v1.1.0 (#15581) (#15608) + * Add ETag header (#15370) (#15552) + +## [1.14.1](https://github.com/go-gitea/gitea/releases/tag/v1.14.1) - 2021-04-15 + +* BUGFIXES + * Fix bug clone wiki (#15499) (#15502) + * Github Migration ignore rate limit, if not enabled (#15490) (#15495) + * Use subdir for URL (#15446) (#15493) + * Query the DB for the hash before inserting in to email_hash (#15457) (#15491) + * Ensure review dismissal only dismisses the correct review (#15477) (#15489) + * Use index of the supported tags to choose user lang (#15452) (#15488) + * Fix wrong file link in code search page (#15466) (#15486) + * Quick template fix for built-in SSH server in admin config (#15464) (#15481) + * Prevent superfluous response.WriteHeader (#15456) (#15476) + * Fix ambiguous argument error on tags (#15432) (#15474) + * Add created_unix instead of expiry to migration (#15458) (#15463) + * Fix repository search (#15428) (#15442) + * Prevent NPE on avatar direct rendering if federated avatars disabled (#15434) (#15439) + * Fix wiki clone urls (#15430) (#15431) + * Fix dingtalk icon url at webhook (#15417) (#15426) + * Standardise icon on projects PR page (#15387) (#15408) +* ENHANCEMENTS + * Add option to skip LFS/attachment files for `dump` (#15407) (#15492) + * Clone panel fixes (#15436) + * Use semantic dropdown for code search query type (#15276) (#15364) +* BUILD + * Build go-git variants for windows (#15482) (#15487) + * Lock down build-images dependencies (Partial #15479) (#15480) +* MISC + * Performance improvement for list pull requests (#15447) (#15500) + * Fix potential copy lfs records failure when fork a repository (#15441) (#15485) + +## [1.14.0](https://github.com/go-gitea/gitea/releases/tag/v1.14.0) - 2021-04-11 + +* SECURITY + * Respect approved email domain list for externally validated user registration (#15014) + * Add reverse proxy configuration support for remote IP address detection (#14959) + * Ensure validation occurs on clone addresses too (#14994) + * Fix several render issues highlighted during fuzzing (#14986) +* BREAKING + * Fix double 'push tag' action feed (#15078) (#15083) + * Remove possible resource leak (#15067) (#15082) + * Handle unauthorized user events gracefully (#15071) (#15074) + * Restore Access.log following migration to Chi framework (Stops access logging of /api/internal routes) (#14475) + * Migrate from Macaron to Chi framework (#14293) + * Deprecate building for mips (#14174) + * Consolidate Logos and update README header (#14136) + * Inline manifest.json (#14038) + * Store repository data in data path if not previously set (#13991) + * Rename "gitea" png to "logo" (#13974) + * Standardise logging of failed authentication attempts in internal SSH (#13962) + * Add markdown support in organization description (#13549) + * Improve users management through the CLI (#6001) (#10492) +* FEATURES + * Create a new issue with reference to lines of code from file view (#14863) + * Repository transfer has to be confirmed, if user can not create repo for new owner (#14792) + * Allow blocking some email domains from registering an account (#14667) + * Create a new issue based on reference to an issue comment (#14366) + * Add support to migrate from gogs (#14342) + * Add pager to the branches page (#14202) + * Minimal OpenID Connect implementation (#14139) + * Display current stopwatch in navbar (#14122) + * Display SVG files as images instead of text (#14101) + * Disable SSH key deletion of externally managed Keys (#13985) + * Add support for ed25519_sk and ecdsa_sk SSH keys (#13462) + * Add support for Mastodon OAuth2 provider (#13293) + * Add gitea sendmail command (#13079) + * Create DB session provider(based on xorm) (#13031) + * Add dismiss review feature (#12674) + * Make manual merge autodetection optional and add manual merge as merge method (#12543) + * Dump github/gitlab/gitea repository data to a local directory and restore to gitea (#12244) + * Create Rootless Docker image (#10154) +* API + * Speedup issue search (#15179) (#15192) + * Get pull, return head branch sha, even if deleted (#14931) + * Export LFS & TimeTracking function status (#14753) + * Show Gitea version in swagger (#14654) + * Fix PATCH /repos/{owner}/{repo} panic (#14637) + * Add Restricted Field to User (#14630) + * Add support for ref parameter to get raw file API (#14602) + * Add affected files of commits to commit struct (#14579) + * Fix CJK fonts again and misc. font issues (#14575) + * Add delete release by tag & delete tag (#14563) & (#13358) + * Add pagination to ListBranches (#14524) + * Add signoff option in commit form (#14516) + * GetRelease by tag only return release (#14397) + * Add MirrorInterval to the API (#14163) + * Make BasicAuth Prefix case insensitive (#14106) + * Add user filter to issueTrackedTimes, enable usage for issue managers (#14081) + * Add ref to create/edit issue options & deprecated assignee (#13992) + * Add Ref to Issue (#13946) + * Expose default theme in meta and API (#13809) + * Send error message when CSRF token is missing (#13676) + * List, Check, Add & delete endpoints for repository teams (#13630) + * Admin EditUser: Make FullName, Email, Website & Location optional (#13562) + * Add more filters to issues search (#13514) + * Add review request api (#11355) +* BUGFIXES + * Fix delete nonexist oauth application 500 and prevent deadlock (#15384) (#15396) + * Always set the merge base used to merge the commit (#15352) (#15385) + * Upgrade to bluemonday 1.0.7 (#15379) (#15380) + * Turn RepoRef and RepoAssignment back into func(*Context) (#15372) (#15377) + * Move FCGI req.URL.Path fix-up to the FCGI listener (#15292) (#15361) + * Show diff on rename with diff changes (#15338) (#15339) + * Fix handling of logout event (#15323) (#15337) + * Fix CanCreateRepo check (#15311) (#15321) + * Fix xorm log stack level (#15285) (#15316) + * Fix bug in Wrap (#15302) (#15309) + * Drop the event source if we are unauthorized (#15275) (#15280) + * Backport Fix graph pagination (#15225) (#15249) + * Prevent NPE in CommentMustAsDiff if no hunk header (#15199) (#15200) + * should run RetrieveRepoMetas() for empty pr (#15187) (#15190) + * Move setting to enable closing issue via commit in non default branch to repo settings (#14965) + * Show correct issues for team dashboard (#14952) + * Ensure that new pull request button works on forked forks owned by owner of the root and reduce ambiguity (#14932) + * Only allow issue labels from owner repository or organization (#14928) + * Fix alignment of People and Teams right arrow on org homepage (#14924) + * Fix overdue marking of closed issues and milestones (#14923) + * Prevent panic when empty MilestoneID in repo/issue/list (#14911) + * Fix migration context data (#14910) + * Handle URLs with trailing slash (#14852) + * Add CORS config on to /login/oauth/access_token endpoint (#14850) + * Make searching issues by keyword case insensitive on DB (#14848) + * Prevent use of double sub-path and incorrect asset path in manifest (#14827) + * Fix link account ui (#14763) + * Fix preview status switch button on wiki editor (#14742) + * Fix github download on migration (#14703) + * Fix svg spacing (#14638) + * Prevent adding nil label to .AddedLabels or .RemovedLabels (#14623) + * Truncated organizations name (#14615) + * Exclude the current dump file from the dump (#14606) + * Use OldRef instead of CommitSHA for DeleteBranch comments (#14604) + * Ensure memcache caching works when TTL greater than 30 days (#14592) + * Remove NULs byte arrays passed to PostProcess (#14587) + * Restore detection of branches are equal on compare page (#14586) + * Fix incorrect key name so registerManualConfirm works (#14455) + * Fix close/reopen with comment (#14436) + * Allow passcode invalid error to appear (#14371) + * Escape branch names in compare url (#14364) + * Label and milestone webhooks on issue/pull creation (#14363) + * Handle NotifyCreateRef as create branch in feeds (#14245) + * Prevent clipping input text in Chrome + Segoe UI Font (#14179) + * Fix UI on edit auth source page (#14137) + * Fix git.parseTagData (#14105) + * Refactor get tag to remove unnecessary steps (#14058) + * Fix integrations test error with space in CURDIR path (#14056) + * Dropdown triangle fixes (#14028) + * Fix label of --id in admin delete user (#14005) + * Cause NotifyMigrateRepository to emit a repo create webhook (#14004) + * Update HEAD to match defaultBranch in template generation (#13948) + * Fix action avatar loading (#13909) + * Fix issue participants (#13893) + * Fix avatar template error (#13833) + * Fix review request notification email links when external issue tracker is enabled (#13723) + * Fix blame line alignment (#13542) + * Include OriginalAuthor in Reaction constraint (#13505) + * Comments on review should have the same sha (#13448) + * Fix whitespace rendering in diff (#13415) + * Fixed git args duplication (#13411) + * Fix bug on release publisherid migrations (#13410) + * Fix --port setting (#13288) + * Keep database transactions not too big (#13254) + * Git version check, ignore pre-releases constraints (#13234) + * Handle and propagate errors when checking if paths are Dirs, Files or Exist (#13186) + * Update Mirror IsEmpty status on synchronize (#13185) + * Use GO variable in go-check target (#13146) (#13147) +* ENHANCEMENTS + * UI style improvements + * Dropzone styling improvements (#15291) (#15374) + * Add size to Save function (#15264) (#15270) + * Monaco improvements (#15333) (#15345) + * Support .mailmap in code activity stats (#15009) + * Sort release attachments by name (#15008) + * Add ui.explore settings to control view of explore pages (#14094) + * Make internal SSH server host key path configurable (#14918) + * Hide resync all ssh principals when using internal ssh server (#14904) + * Add SameSite setting for cookies (#14900) + * Move Bleve and Elastic code indexers to use a common cat-file --batch (#14781) + * Add environment-to-ini to docker image (#14762) + * Add preview support for wiki editor when disable simpleMDE (#14757) + * Add easyMDE(simpleMDE) support for release content editor (#14744) + * Organization removal confirmation using name not password (#14738) + * Make branch names in PR description clickable (#14716) + * Add Password Algorithm option to install page (#14701) + * Add fullTextSearch to dropdowns by default (#14694) + * Fix truncated organization names (#14655) + * Whitespace in commits (#14650) + * Sort / move project boards (#14634) + * Make fileheader sticky in diffs (#14616) + * Add helper descriptions on new repo page (#14591) + * Move the stopwatches to the eventsource stream (#14588) + * Add Content-Length header to HEAD requests (#14542) + * Add Image Diff options in Diff view (#14450) + * Improve Description in new/ edit Project template (#14429) + * Allow ssh-keygen on Windows to detect ssh key type (#14413) + * Display error if twofaSecret cannot be retrieved (#14372) + * Sort issue search results by relevance (#14353) + * Implement ghost comment mitigation (#14349) + * Upgrade blevesearch dependency to v2.0.1 (#14346) + * Add edit, delete and reaction support to code review comments on issue page (#14339) + * Merge default and system webhooks under one menu (#14244) + * Add option for administrator to reset user 2FA (#14243) + * Add option to change username to the admin panel (#14229) + * Check for 'main' as potential default branch name (#14193) + * Project: show referenced PRs in issue cards (#14183) + * Use caddy's certmagic library for extensible/robust ACME handling (#14177) + * CLI support for OAuth sources custom icons (#14166) + * Custom icons for OAuth sources (#14161) + * Team dashboards (#14159) + * KanBan: be able to set default board (#14147) + * Disable Fomantic's custom scrollbars (#14109) + * Add UI to delete tracked times (#14100) + * Rework heatmap permissions (#14080) + * Issue and pull request filters on organization dashboard (#14072) + * Fix webhook list styling (#14001) + * Show dropdown with all statuses for commit (#13977) + * Show status check for merged PRs (#13975) + * Diff stat improvements (#13954) + * Report permissions denied in internal SSH (#13953) + * Markdown task list improvements (#13952) + * Heatmap days clickable (#13935) + * chore: use octicon-mirror for feeds display (#13928) + * Move diff split code into own template file (#13919) + * Markdown: Enable wrapping in code blocks and a color tweak (#13894) + * Do not reload page after adding comments in Pull Request reviews (#13877) + * Add pull request manually merge instruction (#13840) + * add thumbnail preview section to issue attachments (#13826) + * Move Repo APIFormat to convert package (#13787) + * Move notification APIFormat (#13783) + * Swap swagger-ui with swagger-ui-dist (#13777) + * User Settings: Ignore empty language codes & validate (#13755) + * Improve migrate page and add card CSS (#13751) + * Add block on official review requests branch protection (#13705) + * Add review requested filter on pull request overview (#13701) + * Use chronological commit order in default squash message (#13696) + * Clickable links in pull request (and issue) titles (#13695) + * Support shortened commit SHAs in URLs (#13686) + * Use native git variants by default with go-git variants as build tag (#13673) + * Don't render dropdown when only 1 merge style is available (#13670) + * Move webhook type from int to string (#13664) + * Direct avatar rendering (#13649) + * Verify password for local-account activation (#13631) + * Prevent clone protocol button flash on page load (#13626) + * Remove fetch request from heatmap (#13623) + * Refactor combine label comments with tests (#13619) + * Move metrics from macaron to chi (#13601) + * Issue and Pulls lists rework (#13594) + * HTTP cache rework and enable caching for storage assets (#13569) + * Use mount but not register for chi routes (#13555) + * Use monaco for the git hook editor (#13552) + * Make heatmap colors more distinct (#13533) + * Lazy-load issue reviewers and assignees avatars (#13526) + * Change search and filter icons to SVG (#13473) + * Create tag on ui (#13467) + * updateSize when create a repo with init commit (#13441) + * Added title and action buttons to Project view page (#13437) + * Override fomantic monospace fonts and set size (#13435) + * Rework focused comment styling (#13434) + * Tags cleanup (#13428) + * Various style tweaks (#13418) + * Refactor push update (#13381) + * Comment box tweaks and SVG dropdown triangles (#13376) + * Various style fixes (#13372) + * Change repo home page icons to SVG (#13364) + * Use CSS Vars for primary color (#13361) + * Refactor image paste code (#13354) + * Switch from SimpleMDE to EasyMDE (#13333) + * Group Label Changed Comments in timeline (#13304) + * Make the logger an interface (#13294) + * Fix PR/Issue titles on mobile (#13292) + * Rearrange the order of the merged by etc. in locale (#13284) + * Replace footer and modal icons with SVG (#13245) + * Issues overview should not show issues from archived repos (#13220) + * Show stale label for stale code comment which is marked as resolved (#13213) + * Use CSS Variables for fonts, remove postcss-loader (#13204) + * Add mentionable teams to tributeValues and change team mention rules to gh's style (#13198) + * Move install pages out of main macaron routes (#13195) + * Update outdated label to use Fomantic UI style (#13181) + * Added option to disable webhooks (#13176) + * Change order of possible-owner organizations to alphabetical (#13160) + * Log IP on SSH authentication failure for Built-in SSH server (#13150) + * Added option to disable migrations (#13114) + * New "Add Mirror" Button in the Organization view (#13105) + * Manually approve new registration (#13083) + * Cron job to cleanup hook_task table (#13080) + * Use the headline comment of pull-request as the squash commit's message (#13071) + * Clarify the suffices and prefixes of setting.AppSubURL and setting.AppURL (#12999) + * Slightly simplify the queue settings code to help reduce the risk of problems (#12976) + * Add precise search type for Elastic Search (#12869) + * Move APIFormat functions into convert package (#12856) + * Multiple GitGraph improvements: Exclude PR heads, Add branch/PR links, Show only certain branches, (#12766) + * Add TrN for repository limit (#12492) + * Refactor doctor (#12264) + * Add the tag list page to the release page (#12096) + * Redirect on changed user and org name (#11649) + * load U2F js only on pages which need it (#11585) + * Make archival asynchronous (#11296) + * Introduce go chi web framework as frontend of macaron, so that we can move routes from macaron to chi step by step (#7420) + * Improve vfsgen to not unzip bindata files but send to browser directly (#7109) + * Enhance release list (#6025) +* DOCS + * Swagger show models by default (#14880) + * Add missing repo.projects unit into swagger (#14876) + * Update docs and comments to remove macaron (#14491) + * Issue template addition: Are you using Gitea behind CloudFlare? (#14098) + * Generate man pages (#13901) + * Reformat/fine-tune docs (#13897) + * Added Table of Contents to long documentation pages (#13890) + * Add docs command (#13429) + * Update external-renderers.en-us.md (#13165) +* MISC + * Add builds for apple M1 (darwin arm64) (#14951) + * Migrate to use jsoniter instead of encoding/json (#14841) + * Reduce make verbosity (#13803) + * Add git command error directory on log (#13194) + +## [1.13.7](https://github.com/go-gitea/gitea/releases/tag/v1.13.7) - 2021-04-07 + +* SECURITY + * Update to bluemonday-1.0.6 (#15294) (#15298) + * Clusterfuzz found another way (#15160) (#15169) +* API + * Fix wrong user returned in API (#15139) (#15150) +* BUGFIXES + * Add 'fonts' into 'KnownPublicEntries' (#15188) (#15317) + * Speed up `enry.IsVendor` (#15213) (#15246) + * Response 404 for diff/patch of a commit that not exist (#15221) (#15238) + * Prevent NPE in CommentMustAsDiff if no hunk header (#15199) (#15201) +* MISC + * Add size to Save function (#15264) (#15271) + +## [1.13.6](https://github.com/go-gitea/gitea/releases/tag/v1.13.6) - 2021-03-23 + +* SECURITY + * Fix bug on avatar middleware (#15124) (#15125) + * Fix another clusterfuzz identified issue (#15096) (#15114) +* API + * Fix nil exeption for get pull reviews API #15104 (#15106) +* BUGFIXES + * Fix markdown rendering in milestone content (#15056) (#15092) + +## [1.13.5](https://github.com/go-gitea/gitea/releases/tag/v1.13.5) - 2021-03-21 + +* SECURITY + * Update to goldmark 1.3.3 (#15059) (#15061) + * Another clusterfuzz spotted issue (#15032) (#15034) +* API + * Fix set milestone on PR creation (#14981) (#15001) + * Prevent panic when editing forked repos by API (#14960) (#14963) +* BUGFIXES + * Fix bug when upload on web (#15042) (#15055) + * Delete Labels & IssueLabels on Repo Delete too (#15039) (#15051) + * Fix postgres ID sequences broken by recreate-table (#15015) (#15029) + * Fix several render issues (#14986) (#15013) + * Make sure sibling images get a link too (#14979) (#14995) + * Fix Anchor jumping with escaped query components (#14969) (#14977) + * Fix release mail html template (#14976) + * Fix excluding more than two labels on issues list (#14962) (#14973) + * Don't mark each comment poster as OP (#14971) (#14972) + * Add "captcha" to list of reserved usernames (#14930) + * Re-enable import local paths after reversion from #13610 (#14925) (#14927) + +## [1.13.4](https://github.com/go-gitea/gitea/releases/tag/v1.13.4) - 2021-03-07 + +* SECURITY + * Fix issue popups (#14898) (#14899) +* BUGFIXES + * Fix race in LFS ContentStore.Put(...) (#14895) (#14913) + * Fix a couple of issues with a feeds (#14897) (#14903) + * When transferring repository and database transaction failed, rollback the renames (#14864) (#14902) + * Fix race in local storage (#14888) (#14901) + * Fix 500 on pull view page if user is not loged in (#14885) (#14886) +* DOCS + * Fix how lfs data path is set (#14855) (#14884) + +## [1.13.3](https://github.com/go-gitea/gitea/releases/tag/v1.13.3) - 2021-03-04 + +* BREAKING + * Turn default hash password algorithm back to pbkdf2 from argon2 until we find a better one (#14673) (#14675) +* BUGFIXES + * Fix paging of file commit logs (#14831) (#14879) + * Print useful error if SQLite is used in settings but not supported (#14476) (#14874) + * Fix display since time round (#14226) (#14873) + * When Deleting Repository only explicitly close PRs whose base is not this repository (#14823) (#14842) + * Set HCaptchaSiteKey on Link Account pages (#14834) (#14839) + * Fix a couple of CommentAsPatch issues. (#14804) (#14820) + * Disable broken OAuth2 providers at startup (#14802) (#14811) + * Repo Transfer permission checks (#14792) (#14794) + * Fix double alert in oauth2 application edit view (#14764) (#14768) + * Fix broken spans in diffs (#14678) (#14683) + * Prevent race in PersistableChannelUniqueQueue.Has (#14651) (#14676) + * HasPreviousCommit causes recursive load of commits unnecessarily (#14598) (#14649) + * Do not assume all 40 char strings are SHA1s (#14624) (#14648) + * Allow org labels to be set with issue templates (#14593) (#14647) + * Accept multiple SSH keys in single LDAP SSHPublicKey attribute (#13989) (#14607) + * Fix bug about ListOptions and stars/watchers pagnation (#14556) (#14573) + * Fix GPG key deletion during account deletion (#14561) (#14569) + +## [1.13.2](https://github.com/go-gitea/gitea/releases/tag/v1.13.2) - 2021-01-31 + +* SECURITY + * Prevent panic on fuzzer provided string (#14405) (#14409) + * Add secure/httpOnly attributes to the lang cookie (#14279) (#14280) +* API + * If release publisher is deleted use ghost user (#14375) +* BUGFIXES + * Internal ssh server respect Ciphers, MACs and KeyExchanges settings (#14523) (#14530) + * Set the name Mapper in migrations (#14526) (#14529) + * Fix wiki preview (#14515) + * Update code.gitea.io/sdk/gitea v0.13.1 -> v0.13.2 (#14497) + * ChangeUserName: rename user files back on DB issue (#14447) + * Fix lfs preview bug (#14428) (#14433) + * Ensure timeout error is shown on u2f timeout (#14417) (#14431) + * Fix Deadlock & Delete affected reactions on comment deletion (#14392) (#14425) + * Use path not filepath in routers/editor (#14390) (#14396) + * Check if label template exist first (#14384) (#14389) + * Fix migration v141 (#14387) (#14388) + * Use Request.URL.RequestURI() for fcgi (#14347) + * Use ServerError provided by Context (#14333) (#14345) + * Fix edit-label form init (#14337) + * Fix mailIssueCommentBatch for pull request (#14252) (#14296) + * Render links for commit hashes followed by comma (#14224) (#14227) + * Send notifications for mentions in pulls, issues, (code-)comments (#14218) (#14221) + * Fix avatar bugs (#14217) (#14220) + * Ensure that schema search path is set with every connection on postgres (#14131) (#14216) + * Fix dashboard issues labels filter bug (#14210) (#14214) + * When visit /favicon.ico but the static file is not exist return 404 but not continue to handle the route (#14211) (#14213) + * Fix branch selector on new issue page (#14194) (#14207) + * Check for notExist on profile repository page (#14197) (#14203) + +## [1.13.1](https://github.com/go-gitea/gitea/releases/tag/v1.13.1) - 2020-12-29 + +* SECURITY + * Hide private participation in Orgs (#13994) (#14031) + * Fix escaping issue in diff (#14153) (#14154) +* BUGFIXES + * Fix bug of link query order on markdown render (#14156) (#14171) + * Drop long repo topics during migration (#14152) (#14155) + * Ensure that search term and page are not lost on adoption page-turn (#14133) (#14143) + * Fix storage config implementation (#14091) (#14095) + * Fix panic in BasicAuthDecode (#14046) (#14048) + * Always wait for the cmd to finish (#14006) (#14039) + * Don't use simpleMDE editor on mobile devices for 1.13 (#14029) + * Fix incorrect review comment diffs (#14002) (#14011) + * Trim the branch prefix from action.GetBranch (#13981) (#13986) + * Ensure template renderer is available before storage handler (#13164) (#13982) + * Whenever the password is updated ensure that the hash algorithm is too (#13966) (#13967) + * Enforce setting HEAD in wiki to master (#13950) (#13961) + * Fix feishu webhook caused by API changed (#13938) + * Fix Quote Reply button on review diff (#13830) (#13898) + * Fix Pull Merge when tag with same name as base branch exist (#13882) (#13896) + * Fix mermaid chart size (#13865) + * Fix branch/tag notifications in mirror sync (#13855) (#13862) + * Fix crash in short link processor (#13839) (#13841) + * Update font stack to bootstrap's latest (#13834) (#13837) + * Make sure email recipients can see issue (#13820) (#13827) + * Reply button is not removed when deleting a code review comment (#13824) + * When reinitialising DBConfig reset the database use flags (#13796) (#13811) +* ENHANCEMENTS + * Add emoji in label to project boards (#13978) (#14021) + * Send webhook when tag is removed via Web UI (#14015) (#14019) + * Use Process Manager to create own Context (#13792) (#13793) +* API + * GetCombinedCommitStatusByRef always return json & swagger doc fixes (#14047) + * Return original URL of Repositories (#13885) (#13886) + +## [1.13.0](https://github.com/go-gitea/gitea/releases/tag/v1.13.0) - 2020-12-01 + +* SECURITY + * Add Allow-/Block-List for Migrate & Mirrors (#13610) (#13776) + * Prevent git operations for inactive users (#13527) (#13536) + * Disallow urlencoded new lines in git protocol paths if there is a port (#13521) (#13524) + * Mitigate Security vulnerability in the git hook feature (#13058) + * Disable DSA ssh keys by default (#13056) + * Set TLS minimum version to 1.2 (#12689) + * Use argon as default password hash algorithm (#12688) +* BREAKING + * Set RUN_MODE prod by default (#13765) (#13767) + * Don't replace underscores in auto-generated IDs in goldmark (#12805) + * Add Primary Key to Topic and RepoTopic tables (#12639) + * Disable password complexity check default (#12557) + * Change PIDFile default from /var/run/gitea.pid to /run/gitea.pid (#12500) + * Add extension Support to Attachments (allow all types for releases) (#12465) + * Remove IE11 Support (#11470) +* FEATURES + * Adopt repositories (#12920) + * Check passwords against HaveIBeenPwned (#12716) + * Gitea 2 Gitea migration (#12657) + * Support storing Avatars in minio (#12516) + * Allow addition of gpg keyring with multiple keys (#12487) + * Add email notify for new release (#12463) + * Add Access-Control-Expose-Headers (#12446) + * UserProfile Page: Render Description (#12415) + * Add command to recreate tables (#12407) + * Add mermaid JS renderer (#12334) + * Add ssh certificate support (#12281) + * Add spent time to referenced issue in commit message (#12220) + * Initial support for push options (#12169) + * Provide option to unlink a fork (#11858) + * Show exact tag for commit on diff view (#11846) + * Pause, Resume, Release&Reopen, Add and Remove Logging from command line (#11777) + * Issue templates directory (#11450) + * Add a storage layer for attachments (#11387) + * Add hide activity option (#11353) + * Add push commits history comment on PR time-line (#11167) + * Support elastic search for code search (#10273) + * Kanban board (#8346) +* API + * If User is Admin, show 500 error message on PROD mode too (#13115) + * Add Timestamp to Tag list API (#13026) + * Return sample message for login error in api context (#12994) + * Add IsTemplate option in create repo ui and api (#12942) + * GetReleaseByID return 404 if not found (#12933) + * Get release by tags endpoint (#12932) + * NotificationSubject show Issue/Pull State (#12901) + * Expose its limitation settings (#12714) + * Add Created & Updated to Milestone (#12662) + * Milestone endpoints accept names too (#12649) + * Expose Attachment Settings in the API (#12514) + * Add Issue and Repo info to StopWatch (#12458) + * Add cron running API (#12421) + * Add Update Pull HeadBranch Function (#12419) + * Add TOTP header to Swagger Documentation (#12402) + * Delete Token accept names too (#12366) + * Add name filter for GetMilestoneList (#12336) + * Fixed count of filtered issues when api request. (#12275) + * Do not override API issue pagination with UI settings (#12068) + * Expose useful General Repo settings settings (#11758) + * Return error when trying to create Mirrors but Mirrors are globally disabled (#11757) + * Provide diff and patch API endpoints (#11751) + * Allow to create closed milestones (#11745) + * Add language Statistics endpoint (#11737) + * Add Endpoint to get GetGeneralUI Settings (#11735) & (#11854) + * Issue/Pull expose IsLocked Property on API (#11708) + * Add endpoint for Branch Creation (#11607) + * Add pagination headers on endpoints that support total count from database (#11145) +* BUGFIXES + * Fix bogus http requests on diffs (#13760) (#13761) + * Show 'owner' tag for real owner (#13689) (#13743) + * Validate email before inserting/updating (#13475) (#13666) + * Fix issue/pull request list assignee filter (#13647) (#13651) + * Gitlab migration support for subdirectories (#13563) (#13591) + * Fix logic for preferred license setting (#13550) (#13557) + * Add missed sync branch/tag webhook (#13538) (#13556) + * Migration won't fail on non-migrated reactions (#13507) + * Fix Italian language file parsing error (#13156) + * Show outdated comments in pull request (#13148) (#13162) + * Fix parsing of pre-release git version (#13169) (#13172) + * Fix diff skipping lines (#13154) (#13155) + * When handling errors in storageHandler check underlying error (#13178) (#13193) + * Fix size and clickable area on file table back link (#13205) (#13207) + * Add better error checking for inline html diff code (#13251) + * Fix initial commit page & binary munching problem (#13249) (#13258) + * Fix migrations from remote Gitea instances when configuration not set (#13229) (#13273) + * Store task errors following migrations and display them (#13246) (#13287) + * Fix bug isEnd detection on getIssues/getPullRequests (#13299) (#13301) + * When the git ref is unable to be found return broken pr (#13218) (#13303) + * Ensure topics added using the API are added to the repository (#13285) (#13302) + * Fix avatar autogeneration (#13233) (#13282) + * Add migrated pulls to pull request task queue (#13331) (#13334) + * Issue comment reactions should also check pull type on API (#13349) (#13350) + * Fix links to repositories in /user/setting/repos (#13360) (#13362) + * Remove obsolete change of email on profile page (#13341) (#13347) + * Fix scrolling to resolved comment anchors (#13343) (#13371) + * Storage configuration support `[storage]` (#13314) (#13379) + * When creating line diffs do not split within an html entity (#13357) (#13375) (#13425) (#13427) + * Fix reactions on code comments (#13390) (#13401) + * Add missing full names when DEFAULT_SHOW_FULL_NAME is enabled (#13424) + * Replies to outdated code comments should also be outdated (#13217) (#13433) + * Fix panic bug in handling multiple references in commit (#13486) (#13487) + * Prevent panic on git blame by limiting lines to 4096 bytes at most (#13470) (#13491) + * Show original author's reviews on pull summary box (#13127) + * Update golangci-lint to version 1.31.0 (#13102) + * Fix line break for MS teams webhook (#13081) + * Fix Issue & Pull Request comment headers on mobile (#13039) + * Avoid setting the CONN_STR in queues unless it is meant to be set (#13025) + * Remove code-view class from diff view (#13011) + * Fix the color of PR comment hyperlinks. (#13009) + * (Re)Load issue labels when changing them (#13007) + * Fix Media links in org files not liked to media files (#12997) + * Always return a list from GetCommitsFromIDs (#12981) + * Only set the user password if the password field would have been shown (#12980) + * Fix admin/config page (#12979) + * Changed width of commit signature avatar (#12961) + * Completely quote AppPath and CustomConf paths (#12955) + * Fix handling of migration errors (#12928) + * Fix anonymous GL migration (#12862) + * Fix git open close bug (#12834) + * Fix markdown meta parsing (#12817) + * Add default storage configurations (#12813) + * Show PR settings on empty repos (#12808) + * Disable watch and star if not signed in (#12807) + * Whilst changing the character set to utf8mb4 we should set ROW_FORMAT=dynamic too (#12804) + * Set opengraph attributes on org pages (#12803) + * Return error when creating gitlabdownloader failed (#12790) + * Add migration for password algorithm change (#12784) + * Compare SSH_DOMAIN when parsing submodule URLs (#12753) + * Fix editor.commit_empty_file_text locale string (#12744) + * Fix wrong poster message for code comment on Pull view (#11721) + * Escape failed highlighted files (#12685) + * Ensure that all migration requests are cancellable (#12669) + * Ensure RepoPath is lowercased in gitea serv (#12668) + * Do not disable commit changes button on repost (#12644) + * Dark theme for line numbers in blame view (#12632) + * Fix message when deleting last owner from an organization (#12628) + * Use shellquote to unpack arguments to gitea serv (#12624) + * Fix signing.wont_sign.%!s(<nil>) if Require Signing commits but not signed in. (#12581) + * Set utf8mb4 as the default charset on MySQL if CHARSET is unset (#12563) + * Set context for running CreateArchive to that of the request (#12555) + * Prevent redirect back to /user/events (#12462) + * Re-attempt to delete temporary upload if the file is locked by another process (#12447) + * Mirror System Notice reports are too frequent (#12438) + * Do not show arrows on comment diffs on pull comment pages (#12434) + * Fix milestone links (#12405) + * Increase size of the language column in language_stat (#12396) + * Use transaction in V102 migration (#12395) + * Only use --exclude on name-rev with git >= 2.13 (#12347) + * Add action feed for new release (#12324) + * Set NoAutoTime when updating is_archived (#12266) + * Support Force-update in Mirror and improve Tracing in mirror (#12242) + * Avoid sending "0 new commits" webhooks (#12212) + * Fix U2F button icon (#12167) + * models/repo_sign.go: break out of loops (#12159) + * Ensure that git commit tree continues properly over the page (#12142) + * Rewrite GitGraph.js (#12137) + * Fix repo API listing stability (#12057) + * Add team support for review request (#12039) + * Fix 500 error on repos with no tags (#11870) + * Fix nil pointer in default issue mail template (#11862) + * Fix commit search in all branches (#11849) + * Don't consider tag refs as valid for branch name (#11847) + * Don't add same line code comment box twice (#11837) + * Fix visibility of forked public repos from private orgs (#11717) + * Fix chardet test and add ordering option (#11621) + * Fix number of files, total additions, and deletions on Diff pages (#11614) + * Properly handle and return empty string for dangling commits in GetBranchName (#11587) + * Include query in sign in redirect (#11579) + * Fix Enter not working in SimpleMDE (#11564) + * Fix bug about can't skip commits base on base branch (#11555) +* ENHANCEMENTS + * Only Return JSON for responses (#13511) (#13565) + * Use existing analyzer module for language detection for highlighting (#13522) (#13551) + * Return the full rejection message and errors in flash errors (#13221) (#13237) + * Remove PAM from auth dropdown when unavailable (#13276) (#13281) + * Add HostCertificate to sshd_config in Docker image (#13143) + * Save TimeStamps for Star, Label, Follow, Watch and Collaboration to Database (#13124) + * Improve error feedback for duplicate deploy keys (#13112) + * Set appropriate `autocomplete` attributes on password fields (#13078) + * Adding visual cue for "Limited" & "Private" organizations. (#13040) + * Fix Pull Request merge buttons on mobile (#13035) + * Gitea serv, hooks, manager and the like should always display Fatals (#13032) + * CSS tweaks to warning/error segments and misc fixes (#13024) + * Fix formatting of branches ahead-behind on narrow windows (#12989) + * Add config option to make create-on-push repositories public by default (#12936) + * Disable migration items when mirror is selected (#12918) + * Add the checkbox quick button to the comment tool bar also (#12885) + * Support GH enterprise (#12863) + * Simplify CheckUnitUser logic (#12854) + * Fix background of signed-commits on arc-green of timeline commits (#12837) + * Move git update-server-info to hooks (#12826) + * Add ui style for "Open a blank issue" button (#12824) + * Use a simple format for the big number on ui (#12822) + * Make SVG size argument optional (#12814) + * Add placeholder text for bio profile text form (#12792) + * Set language via AJAX (#12785) + * Show git-pull-request icon for closed pull request (#12742) + * Migrate version parsing library to hashicorp/go-version (#12719) + * Only use async pre-empt hack if go < 1.15 (#12718) + * Inform user about meaning of an hourglass on reviews (#12713) + * Add a migrate service type switch page (#12697) + * Migrations: Gitlab Add Reactions Support for Issues & MergeRequests (#12695) + * Remove duplicate logic in initListSubmits (#12660) + * Set avatar image dimensions (#12654) + * Rename models.ProtectedBranchRepoID/PRID to models.EnvRepoID/PRID and ensure EnvPusherEmail is set (#12646) + * Set setting.AppURL as GITEA_ROOT_URL environment variable during pushes (#12752) + * Add postgres schema to the search_path on database connection (#12634) + * Git migration UX improvements (#12619) + * Add link to home page on swagger ui (#12601) + * hCaptcha Support (#12594) + * OpenGraph: use repo avatar if exist (#12586) + * Reaction picker display improvements (#12576) + * Fix emoji replacements, make emoji images consistent (#12567) + * Increase clickable area on files table links (#12553) + * Set z-index for sticky diff box lower (#12537) + * Report error if API merge is not allowed (#12528) + * LFS support to be stored on minio (#12518) + * Show 2FA info on Admin Pannel: Users List (#12515) + * Milestone Issue/Pull List: Add octicons type (#12499) + * Make dashboard newsfeed list length a configurable item (#12469) + * Add placeholder text for send testing email button in admin/config (#12452) + * Add SVG favicon (#12437) + * In issue comments, put issue participants also in completion list when hitting @ (#12433) + * Collapse Swagger UI tags by default (#12428) + * Detect full references to issues and pulls in commit messages (#12399) + * Allow common redis and leveldb connections (#12385) + * Don't use legacy method to send Matrix Webhook (#12348) + * Remove padding/border-radius on image diffs (#12346) + * Render the git graph on the server (#12333) + * Fix clone panel in wiki position not always align right (#12326) + * Rework 'make generate-images' (#12316) + * Refactor webhook payload conversion (#12310) + * Move jquery-minicolors to npm/webpack (#12305) + * Support use nvarchar for all varchar columns when using mssql (#12269) + * Update Octicons to v10 (#12240) + * Disable search box autofocus (#12229) + * Replace code fold icons with octicons (#12222) + * Ensure syntax highlighting is the same inside diffs (#12205) + * Auto-init repo on license, .gitignore select (#12202) + * Default to showing closed Issues/PR list when there are only closed issues/PRs (#12200) + * Enable cloning via Git Wire Protocol v2 over HTTP (#12170) + * Direct SVG rendering (#12157) + * Improve arc-green code colors (#12111) + * Allow admin to merge pr with protected file changes (#12078) + * Show description on individual milestone view (#12055) + * Update the wiki repository remote origin while update the mirror repository's Clone From URL (#12053) + * Server-side syntax highlighting for all code (#12047) + * Use Fomantic's fluid padded for blame full width (#12023) + * Use custom SVGs for commit signing lock icon (#12017) + * Make tabs smaller (#12003) + * Fix sticky diff stats container (#12002) + * Move fomantic and jQuery to main webpack bundle (#11997) + * Use enry language type to detect special languages (#11974) + * Use only first line of commit when creating referenced comment (#11960) + * Rename custom/conf/app.ini.sample to custom/conf/app.example.ini for better syntax light on editor (#11926) + * Fix double divider on issue sidebar (#11919) + * Shorten markdown heading anchors links (#11903) + * Add org avatar on top of internal repo icon (#11895) + * Use label to describe repository type (#11891) + * Make repository size unclickable on repo summary bar (#11887) + * Rework blame template and styling (#11885) + * Fix icon alignment for show/hide outdated link on resolved conversation (#11881) + * Vertically align review icons on repository sidebar (#11880) + * Better align items using flex within review request box (#11879) + * Only write to global gitconfig if necessary (#11876) + * Disable all typographic replacements in markdown renderer (#11871) + * Improve label edit buttons labels (#11841) + * Use crispEdges rendering for octicon-internal-repo (#11801) + * Show update branch item in merge box when it's necessary (#11761) + * Add compare link to releases (#11752) + * Allow site admin to disable mirrors (#11740) + * Export monaco editor on window.codeEditors (#11739) + * Add configurable Trust Models (#11712) + * Show full GPG commit status on PR commit history (#11702) + * Fix align issues and decrease avatar size on PR timeline (#11689) + * Replace jquery-datetimepicker with native date input (#11684) + * Change Style of Tags on Comments (#11668) + * Fix missing styling for shabox on PR commit history (#11625) + * Apply padding to approval icons on PR list (#11622) + * Fix message wrapping on PR commit list (#11616) + * Right-align status icon on pull request commit history (#11594) + * Add missing padding for multi-commit list on PR view (#11593) + * Do not show avatar for "{{user}} added X commits" (#11591) + * Fix styling and padding for commit list on PR view (#11588) + * Style code review comment for arc-green (#11572) + * Use default commit message for wiki edits (#11550) + * Add internal-repo octicon for public repos of private org (#11529) + * Fix dropzone color on arc-green (#11514) + * Insert ui divider directly in templates instead of from inside heatmap vue component (#11508) + * Move tributejs to npm/webpack (#11497) + * Fix text-transform on wiki revisions page (#11486) + * Do not show lock icon on repo list for public repos in private org (#11445) + * Include LFS when calculating repo size (#11060) + * Add check for LDAP group membership (#10869) + * When starting new stopwatch stop previous if it is still running (#10533) + * Add queue for code indexer (#10332) + * Move all push update operations to a queue (#10133) + * Cache last commit when pushing for big repository (#10109) + * Change/remove a branch of an open issue (#9080) + * Sortable Tables Header By Click (#7980) +* TESTING + * Use community codecov drone plugin (#12468) + * Add more tests for diff highlighting (#12467) + * Don't put integration test data outside of test folder (#11746) + * Add debug option to hooks (#11624) + * Log slow tests (#11487) +* TRANSLATION + * Translate two small lables on commit statutes list (#12821) + * Make issues.force_push_codes message shorter (#11575) +* BUILD + * Bump min required golang to 1.13 (#12717) + * Add 'make watch' (#12636) + * Extract Swagger CSS to its own file (#12616) + * Update eslint config (#12609) + * Avoid unnecessary system-ui expansion (#12522) + * Make the default PID file compile-time settable (#12485) + * Add 'watch-backend' (#12330) + * Detect version of sed in Makefile (#12319) + * Update gitea-vet to v0.2.1 (#12282) + * Add logic to build stable and edge builds for gitea snap (#12052) + * Fix missing CGO_EXTRA_FLAGS build arg for docker (#11782) + * Alpine 3.12 (#11720) + * Enable stylelint's shorthand-property-no-redundant-values (#11436) +* DOCS + * Change default log configuration (#13088) + * Add automatic JS license generation (#11810) + * Remove page size limit comment from swagger (#11806) + * Narrow down Edge version in browser support docs (#11640) + +## [1.12.5](https://github.com/go-gitea/gitea/releases/tag/v1.12.5) - 2020-10-01 + +* BUGFIXES + * Allow U2F with default settings for gitea in subpath (#12990) (#13001) + * Prevent empty div when editing comment (#12404) (#12991) + * On mirror update also update address in DB (#12964) (#12967) + * Allow extended config on cron settings (#12939) (#12943) + * Open transaction when adding Avatar email-hash pairs to the DB (#12577) (#12940) + * Fix internal server error from ListUserOrgs API (#12910) (#12915) + * Update only the repository columns that need updating (#12900) (#12912) + * Fix panic when adding long comment (#12892) (#12894) + * Add size limit for content of comment on action ui (#12881) (#12890) + * Convert User expose ID each time (#12855) (#12883) + * Support slashes in release tags (#12864) (#12882) + * Add missing information to CreateRepo API endpoint (#12848) (#12867) + * On Migration respect old DefaultBranch (#12843) (#12858) + * Fix notifications page links (#12838) (#12853) + * Stop cloning unnecessarily on PR update (#12839) (#12852) + * Escape more things that are passed through str2html (#12622) (#12850) + * Remove double escape on labels addition in comments (#12809) (#12810) + * Fix "only mail on mention" bug (#12775) (#12789) + * Fix yet another bug with diff file names (#12771) (#12776) + * RepoInit Respect AlternateDefaultBranch (#12746) (#12751) + * Fix Avatar Resize (resize algo NearestNeighbor -> Bilinear) (#12745) (#12750) +* ENHANCEMENTS + * gitea dump: include version & Check InstallLock (#12760) (#12762) + +## [1.12.4](https://github.com/go-gitea/gitea/releases/tag/v1.12.4) - 2020-09-02 + +* SECURITY + * Escape provider name in oauth2 provider redirect (#12648) (#12650) + * Escape Email on password reset page (#12610) (#12612) + * When reading expired sessions - expire them (#12686) (#12690) +* ENHANCEMENTS + * StaticRootPath configurable at compile time (#12371) (#12652) +* BUGFIXES + * Fix to show an issue that is related to a deleted issue (#12651) (#12692) + * Expire time acknowledged for cache (#12605) (#12611) + * Fix diff path unquoting (#12554) (#12575) + * Improve HTML escaping helper (#12562) + * models: break out of loop (#12386) (#12561) + * Default empty merger list to those with write permissions (#12535) (#12560) + * Skip SSPI authentication attempts for /api/internal (#12556) (#12559) + * Prevent NPE on commenting on lines with invalidated comments (#12549) (#12550) + * Remove hardcoded ES indexername (#12521) (#12526) + * Fix bug preventing transfer to private organization (#12497) (#12501) + * Keys should not verify revoked email addresses (#12486) (#12495) + * Do not add prefix on http/https submodule links (#12477) (#12479) + * Fix ignored login on compare (#12476) (#12478) + * Fix incorrect error logging in Stats indexer and OAuth2 (#12387) (#12422) + * Upgrade google/go-github to v32.1.0 (#12361) (#12390) + * Render emoji's of Commit message on feed-page (#12373) + * Fix handling of diff on unrelated branches when Git 2.28 used (#12370) + +## [1.12.3](https://github.com/go-gitea/gitea/releases/tag/v1.12.3) - 2020-07-28 + +* BUGFIXES + * Don't change creation date when updating Release (#12343) (#12351) + * Show 404 page when release not found (#12328) (#12332) + * Fix emoji detection in certain cases (#12320) (#12327) + * Reduce emoji size (#12317) (#12327) + * Fix double-indirection bug in logging IDs (#12294) (#12308) + * Link to pull list page on sidebar when view pr (#12256) (#12263) + * Extend Notifications API and return pinned notifications by default (#12164) (#12232) + +## [1.12.2](https://github.com/go-gitea/gitea/releases/tag/v1.12.2) - 2020-07-11 + +* BUGFIXES + * When deleting repository decrese user repository count in cache (#11954) (#12188) + * Return full commit message instead of summary in commits API (#12186) (#12187) + * Properly set HEAD when a repo is created with a default branch that is not named 'master' (#12135) (#12182) + * Ensure GPG Subkeys are verified (#12155) (#12168) + * Fix failing to cache last commit with key being to long (#12151) (#12161) + * Multiple small admin dashboard fixes (#12153) (#12156) + * Remove spurious logging of " Delete all repository archives" at startup (#12139) (#12148) + * Fix repository setup instructions when default branch is not named 'master' (#12122) (#12147) + * Move EventSource to SharedWorker (#12095) (#12130) + * Fix ui bug in wiki commit page (#12089) (#12125) + * Fix gitgraph branch continues after merge (#12044) (#12105) + * Set the base url when migrating from Gitlab using access token or username without password (#11852) (#12104) + * Ensure BlameReaders close at end of request (#12102) (#12103) + * Fix panic when adding review comment (#12058) +* ENHANCEMENTS + * Disable dropzone's timeout for file uploads (#12024) (#12032) + +## [1.12.1](https://github.com/go-gitea/gitea/releases/tag/v1.12.1) - 2020-06-21 + +* BUGFIXES + * Handle multiple merges in gitgraph.js (#11996) (#12000) + * Add serviceworker.js to KnownPublicEntries (#11992) (#11994) + * For language detection do not try to analyze big files by content (#11971) (#11975) +* ENHANCEMENTS + * Fix scrollable header on dropdowns (#11893) (#11965) + +## [1.11.8](https://github.com/go-gitea/gitea/releases/tag/v1.11.8) - 2020-06-21 + +* BUGFIXES + * Really fix __webpack_public_path__ for 1.11 (#11961) + +## [1.12.0](https://github.com/go-gitea/gitea/releases/tag/v1.12.0) - 2020-06-17 + +* BREAKING + * When using API CreateRelease set created_unix to the tag commit time (#11218) + * Enable ENABLE_HARD_LINE_BREAK by default for rendering markdown (#11162) + * Fix sanitizer config - multiple rules (#11133) + * Remove check on username when using AccessToken authentication for the API (#11015) + * Return 404 from Contents API when items don't exist (#10323) + * Notification API should always return a JSON object with the current count of notifications (#10059) + * Remove migration support from versions earlier than 1.6.0 (#10026) +* SECURITY + * Use -1 to disable key algorithm type in ssh.minimum_key_sizes (#11635) (#11662) +* FEATURES + * Improve config logging when WrappedQueue times out (#11174) + * Add branch delete to API (#11112) + * Use markdown frontmatter to provide Table of contents, language and frontmatter rendering (#11047) + * Add a way to mark Conversation (code comment) resolved (#11037) + * Handle yaml frontmatter in markdown (#11016) + * Cache PullRequest Divergence (#10914) + * Make `gitea admin auth list` formatting configurable (#10844) + * Add Matrix webhook (#10831) + * Add Organization Wide Labels (#10814) + * Allow to set protected file patterns for files that can not be changed under no conditions (#10806) + * Option to set default branch at repository creation (#10803) + * Add request review from specific reviewers feature in pull request (#10756) + * Add NextCloud oauth (#10562) + * System-wide webhooks (#10546) + * Relax sanitization as per https://github.com/jch/html-pipeline (#10527) + * Use media links for img in post-process (#10515) + * Add API endpoints to manage OAuth2 Application (list/create/delete) (#10437) + * Render READMEs in docs/ .gitea or .github from root (#10361) + * Add feishu webhook support (#10229) + * Cache last commit to accelerate the repository directory page visit (#10069) + * Implement basic app.ini and path checks to doctor cmd (#10064) + * Make WorkerPools and Queues flushable (#10001) + * Implement "embedded" command to extract static resources (#9982) + * Add API endpoint for repo transfer (#9947) + * Make archive prefixing configurable with a global setting (#9943) + * Add Unique Queue infrastructure and move TestPullRequests to this (#9856) + * Issue/PR Context Popups (#9822) + * Add "Update Branch" button to Pull Requests (#9784) + * Add require signed commit for protected branch (#9708) + * Mark PR reviews as stale at push and allow to dismiss stale approvals (#9532) + * Add API notification endpoints (#9488) + * Issue search support elasticsearch (#9428) + * Add API branch protection endpoint (#9311) + * Add a new command doctor to check if some wrong configurations on gitea instance (#9095) + * Add support for migrating from Gitlab (#9084) + * Add support for database schema in PostgreSQL (#8819) + * Add setting to set default and global disabled repository units. (#8788) + * Language statistics bar for repositories (#8037) + * Restricted users (#6274) +* BUGFIXES + * Fix commenting on non-utf8 encoded files (#11916) (#11950) + * Use google/uuid to instead satori/go.uuid (#11943) (#11946) + * Align show/hide outdated button on code review block (#11932) (#11944) + * Update to go-git v5.1.0 (#11936) (#11941) + * Use ID or Where to instead directly use Get when load object from database (#11925) (#11934) + * Update CommitsAhead CommitsBehind on Pull BaseBranch Change too (#11912) (#11915) + * Invalidate comments when file is shortened (#11882) (#11884) + * Rework api/user/repos for pagination (#11827) (#11877) + * Handle more pathological branch and tag names (#11843) (#11863) + * Add doctor check to set IsArchived false if it is null (partial #11853) (#11859) + * Prevent panic on empty HOST for mysql (#11850) (#11856) + * Use DEFAULT_PAGING_NUM instead of MAX_RESPONSE_ITEMS in ListOptions (#11831) (#11836) + * Fix reply octicon (#11821) (#11822) + * Honor DEFAULT_PAGING_NUM for API (#11805) (#11813) + * Ensure rejected push to refs/pull/index/head fails nicely (#11724) (#11809) + * In File Create/Update API return 404 if Branch does not exist (#11791) (#11795) + * Fix doer of rename repo (#11789) (#11794) + * Initialize SimpleMDE when making a code comment (#11749) (#11785) + * Fix timezone on issue deadline (#11697) (#11784) + * Fix to allow comment poster to edit or delete his own comments (#11671) (#11774) + * Show full 500 error in API when Gitea in dev mode (#11641) (#11753) + * Add missing templates for Matrix system webhooks (#11729) (#11748) + * Fix verification of subkeys of default gpg key (#11713) (#11747) + * Fix styling for commiter on diff view (#11715) (#11744) + * Properly truncate system notices (#11714) (#11742) + * Handle expected errors in FileCreate & FileUpdate API (#11643) (#11718) + * Fix missing authorization check on pull for public repos of private/limited org (#11656) (#11682) + * Doctor check & fix db consistency (#11111) (#11676) + * Exclude generated files from language statistics (#11653) (#11670) + * Return json on 500 error from API (#11574) (#11659) + * When must change password only show Signout (#11600) (#11637) + * Backport various styling fixes (#11619) + * Fix wrong milestone in webhook message (#11596) (#11611) + * Fix serviceworker output file and misc improvements (#11562) (#11610) + * When initialising repositories ensure that the user doing the creation is the initializer (#11601) (#11608) + * Prevent empty query parameter being set on dashboard (#11561) (#11604) + * Fix images in wiki edit preview (#11546) (#11602) + * Prevent (caught) panic on login (#11590) (#11597) + * Prevent transferring repos to invisible orgs (#11517) (#11549) + * Move serviceworker to workbox and fix SSE interference (#11538) (#11547) + * API PullReviewComment HTMLPullURL should return the HTMLURL (#11501) (#11533) + * Fix repo-list private and total count bugs (#11500) (#11532) + * Fix form action template substitutions on admin pages (backport #11519) (#11531) + * Fix a bug where the reaction emoji doesn't disappear. (#11489) (#11530) + * TrimSpace when reading InternalToken from a file (#11502) (#11524) + * Fix selected line color in arc-green (#11492) (#11520) + * Make localstorage read ssh or https correctly (#11483) (#11490) + * Check branch protection on IsUserAllowedToUpdate (#11448) + * Fix margin on attached segment headers when they are separated by other element (#11425) + * Fix webhook template when validation errors occur (#11421) + * Fix NPE in template due to missing signing key on commit page (#11392) + * Restore active background to Register button on Register page (#11390) + * Fix hook failure due to relative LFS_CONTENT_PATH (#11362) + * Correctly set the organization num repos (#11339) + * Prevent 500 with badly formed task list (#11328) + * Allow compare page to look up base, head, own-fork, forkbase-of-head (#11327) + * Handle panics that percolate up to the graceful module (#11291) + * Don't allow registration via the web form, when AllowOnlyExternalRegistration is True (#11248) + * Patch fomantic-ui to workaround build issue (#11244) + * Prevent panic during wrappedConn close at hammertime (#11219) + * On logout force redirect to start page (#11202) + * Fix creation of Organization repos by Users with max created personal repos (#11183) + * Add option to increase provided OAuth2 token maximum size (#11180) + * Log the indexer path on failure (#11172) + * Ensure that relative paths in edit preview work (#11143) + * Make API EditIssue and EditPullRequest issue notifications (#11123) + * Send 404 immediately for known public requests (#11117) + * Remove nil inserts in models (#11096) + * Add GetReviews() to RetryDownloader (#11093) + * Remove nonexistent serviceworker entries (#11091) + * Simplify and fix GetApprovalCounts (#11086) + * Fix wiki revision template and simplify some tmpl conditions (#11080) + * Make branch parameter optional for /api/v1/repos/{owner}/{repo}/contents/{filepath} (#11067) + * Align review-item svg octicons (#11065) + * Automatically remove Watches, Assignments, etc if user loses access due to being removed as collaborator or from a team (#10997) + * Users should not be able to prohibit their own login (#10970) + * Fix scrollbar issues in dropdowns (#10897) + * Change the order of issues.closed_by to list opening user first (#10876) + * Allow site admin to check /api/v1/orgs endpoints (#10867) + * Avoid logging []byte in queue failures - convert to string first (#10865) + * Use ErrKeyUnableToVerify if fail to calc fingerprint in ssh-keygen (#10863) + * Fix assignees double load bug (#10856) + * Handle push rejection in branch and upload (#10854) + * In authorized_keys use double-quote for windows compatibility (#10841) + * Fix milestone template (#10824) + * log.Fatal on failure to listen to SSH port (#10795) + * Fix forked repo has no icon and language stat. (#10791) + * Fix tag/release deletion (#10663) + * Fix webhook migration (#10641) + * Migration for deleting orphaned dependencies (#10617) + * Add migration to fix the old broken merge-bases (#10604) + * Update templates for Go 1.14 (#10596) + * Remove unnecessary parentheses in wiki/view template (#10583) + * Change default value of DefaultCommandExecutionTimeout to match docs (#10581) + * Handle panic in indexer initialisation better (#10534) + * Set correct content_type value for Gogs/Gitea webhooks (#9504) (#10456) + * Fixed wrong AppSubUrl in multiple templates (#10447) + * Fix profile page CSS (#10406) + * Inject SVG sprite via ajax (#10320) + * Fix migration information update bug when linked github account (#10310) + * Allow admin to check org membership by API for other users (#10201) + * Fix topics dropdown (#10167) + * Ensure DeleteUser is not allowed to Delete Orgs and visa versa (#10134) + * Fix IsErrPullClosed (#10093) + * Accept punctuation after simple+cross repository issue references (#10091) + * On merge of already closed PR redirect back to the pulls page (#10010) + * Fix crowdin update script (#9969) + * Fix pull view when head repository or head branch missed and close related pull requests when delete head repository or head branch (#9927) + * Add option to prevent LDAP from deactivating everything on empty search (#9879) + * Fix admin handling at merge of PR (#9749) + * err_admin_name_pattern_not_allowed String Clarification (#9731) + * Fix wrong original git service type on a migrated repository (#9693) + * Fix ref links in issue overviews for tags (#8742) +* ENHANCEMENTS + * Fix search form button overlap (#11840) (#11864) + * Make tabular menu styling consistent for arc-green (#11570) (#11798) + * Add option to API to update PullRequest base branch (#11666) (#11796) + * Increase maximum SQLite variables count to 32766 (#11696) (#11783) + * Update emoji dataset with skin tone variants (#11678) (#11763) + * Add logging to long migrations (#11647) (#11691) + * Change language statistics to save size instead of percentage (#11681) (#11690) + * Allow different HardBreaks settings for documents and comments (#11515) (#11599) + * Fix alignment for commits on dashboard (#11595) (#11680) + * Default MSSQL port 0 to allow automatic detection by default (#11642) (#11673) + * Handle expected errors in AddGPGkey API (#11644) (#11661) + * Close EventSource before unloading the page (#11539) (#11557) + * Ensure emoji render with regular font-weight (#11541) (#11545) + * Fix webpack chunk loading with STATIC_URL_PREFIX (#11526) (#11542) + * Tweak reaction buttons (#11516) + * Use more toned colors for selected line (#11493) (#11511) + * Increase width for authors on commit view (#11441) + * Hide archived repos by default in repo-list (#11440) + * Better styling for code review comment textarea (#11428) + * Support view individual commit for wiki pages (#11415) + * Fix yellow background on active elements in code review (#11414) + * Better styling for code review comment form (#11413) + * Change install description on homepage (#11395) + * Ensure search action button is coalesced to adjacent input (#11385) + * Switch code editor to Monaco (#11366) + * Add paging and archive/private repository filtering to dashboard list (#11321) + * Changed image of openid-connect logo for better look on arc-green theme (#11312) + * Load Repo Topics on blame view too (#11307) + * Change the style in admin notice content view from `<p>` to `<pre>` (#11301) + * Allow log.xxx.default to set logging settings for the default logger only (#11292) + * Automatically attempt auto recovery of broken disk queues (Update lunny/levelqueue to 0.3.0) (#11285) + * Make sendmail a Process and have default timeout (#11256) + * Check value of skip-repository flag in dump command (#11254) + * Fix submit review form (#11252) + * Allow unauthenticated users to compare (#11240) + * Add EventSource support (#11235) + * Refactor Milestone related (#11225) + * Add pull review API endpoints (#11224) + * Add a 'this' to issue close/reopened messages (#11204) + * When migrating from Gitlab map Approvals to approving Reviews (#11147) + * Improve representation of attachments in issues (#11141) + * Protect default branch against deletion (#11115) + * Add X-Total-Count on /repos/{owner]/{repo}/pulls API endpoint (#11113) + * Fix status label on branches list vertical alignment (#11109) + * Add single release page and latest redirect (#11102) + * Add missing commit states to PR checks template (#11085) + * Change icon on title for merged PR to git-merge (#11064) + * Add MergePull comment type instead of close for merge PR (#11058) + * Upgrade jQuery to 3.5.0, remove jQuery-Migrate, fix deprecations (#11055) + * Consolidate author name across timeline (#11053) + * Refactor UpdateOAuth2Application (#11034) + * Support unicode emojis and remove emojify.js (#11032) + * Add git hook "warning" to admin panel (#11030) + * Add flash notify for email preference setting success (#11027) + * Remove package code.gitea.io/gitea/modules/git import out of models (#11025) + * Match arc-green code tag color to code blocks (#11023) + * Move syntax highlighting to web worker (#11017) + * Prevent merge of outdated PRs on protected branches (#11012) + * Add Get/Update for api/v1/user/applications/oauth2 (#11008) + * Upgrade to most recent bluemonday (#11007) + * Tweak code tags in markdown (#11000) + * Reject duplicate AccessToken names (#10994) + * Fix Ctrl-Enter shortcut for issues (#10986) + * Provide `OwnerName` field for README template (#10981) + * Prettify Timeline (#10972) + * Add issue subscription check to API (#10967) + * Use AJAX for notifications table (#10961) + * Adjust label padding (#10957) + * Avoiding directory execution on hook (#10954) (#10955) + * Migrate ActivityHeatmap to Vue SFC (#10953) + * Change merge strategy: do not check write access if user in merge white list (#10951) + * Enable GO111MODULE=on globally in Makefile (#10939) + * API endpoint to get single commit via SHA and Ref (#10915) + * Add accordion to release list and hide non-latest (#10910) + * Split dashboard elements into separate template files (#10885) + * Add more message on sidebar menus (#10872) + * Set MySQL rowtype to dynamic for new tables (#10833) + * Completely fix task-list checkbox styling (#10798) + * Hide gear icon for user who can't use them on sidebar (#10750) + * Refactor Cron and merge dashboard tasks (#10745) + * Change review status icons on pr view style to github style (#10737) + * Make pagination optional for API list notification endpoints (#10714) + * Fix tab indentation in code view (#10671) + * Fix task-list checkbox styling (#10668) + * Multiple LFS improvements (#10667) + * Make PR message on pushes configurable (#10664) + * Move dropzone.js to npm/webpack (#10645) + * Ensure Update button is enabled even when CI has failed (#10640) + * Add restricted user filter to LDAP authentication (#10600) + * Add Yandex OAuth2 provider (#8335) (#10564) + * Make avatar lookup occur at image request (#10540) + * Prevent accidental selection of language stats bar (#10537) + * Add fluid-icon (#10491) + * Inform participants on UI too (#10473) + * Build with go 1.14 (and raise minimum go version to 1.12) (#10467) + * Add max-file-size to LFS (#10463) + * Enable paggination for ListRepoTags API (#10454) + * Update JS dependencies (#10450) + * Show the username as a fallback on feeds if full name is blank (#10438) + * Various dark theme fixes (#10416) + * Display pull request head branch even the branch deleted or repository deleted (#10413) + * Prevent Firefox from using apple-touch-icon (#10402) + * Fix input[type=file] on dark theme (#10382) + * Improve mobile review-box sizing (#10297) + * Notification: queue ui.go notification-service (#10281) + * Add detected file language to code search (#10256) + * Index code and stats only for non-empty repositories (#10251) + * Add Approval Counts to pulls list (#10238) + * Limit label list height on edit issue page (#10216) + * Improve 404 error message (#10214) + * Tweak locale to respect singular conflicting file message in PR list (#10177) + * Fix commit view (#10169) + * Reorganize frontend files and tooling (#10168) + * Allow emoji on popup label (#10166) + * ListIssues add filter for milestones API (#10148) + * Show if a PR has conflicting files on the PR lists (#10130) + * Fix inconsistent label color format in API (#10129) + * Show download count info in release list (#10124) + * Add Octicon SVG spritemap (#10107) + * Update aria-fixed semantic-dropdown to fomantic master (#10096) + * Fix apple-touch-icon, regenerate images (#10065)(#10006) + * Style blockquote for default issue mail template (#10024) + * More expansions in template repositories (#10021) + * Allow list collaborators for users with Read access to repo (#9995) + * Add explicit dimensions to navbar avatar (#9986) + * Remove loadCSS and preload woff2 icon fonts (#9976) + * Fix commit view JS features, reimplement folding (#9968) + * Fix review avatar image (#9962) + * Improve notification pager (#9821) + * Move jquery and jquery-migrate to npm/webpack (#9813) + * Change font to Roboto to support more charsets (#9803) + * Move mailer to use a queue (#9789) + * Issue search on my related repositories (#9758) + * Add "before" query to ListIssueComments and ListRepoIssueComments API (#9685) + * Move tracked time api convert to convert package (#9665) + * Improve PR info in default merge message (#9635) + * Granular webhook events (#9626) + * Add Reviewed-on in commit message (#9623) + * Add top author stats to activity page (#9615) + * Allow repo admin to merge PR regardless of review status (#9611) + * Migrate reactions when migrating repository from github (#9599) + * API orgEditTeam make Fields optional (#9556) + * Move create/fork repository from models to modules/repository (#9489) + * Migrate reviews when migrating repository from github (#9463) + * Times API add filters (#9373) + * Move push commits from models to modules/repository (#9370) + * Add API endpoint to check notifications [Extend #9488] (#9595) + * Add GET /orgs API endpoint (#9560) + * API add/generalize pagination (#9452) + * Make create org repo API call same as github (#9186) +* BUILD + * Turn off go modules for xgo and gxz (#10963) + * Add gitea-vet (#10948) + * Rename scripts to build and add revive command as a new build tool command (#10942) + * Add 'make lint', restructure 'compliance' pipeline (#10861) + * Move JS build dependencies to 'dependencies' (#10763) + * Use whitelist to find go files, run find only once (#10594) + * Move vue and vue-calendar-heatmap to npm/webpack (#10188) + * Move jquery.are-you-sure to npm/webpack (#10063) + * Move highlight.js to npm/webpack (#10011) + * Generate Bindata if TAGS="bindata" and not up-to-date (#10004) + * Move CSS build to webpack (#9983) + * Move fomantic target, update 'make help' (#9945) + * Add css extraction and minification to webpack (#9944) + * Misc webpack tweaks (#9924) + * Make node_modules a order-only prerequisite (#9923) + * Update documentation for the go module era (#9751) + * Move swagger-ui to webpack/npm and update it to 3.24.3 (#9714) + * Use npm to manage fomantic and only build needed components (#9561) +* MISC + * Add gnupg to Dockerfile (#11365) + * Update snapcraft.yaml for core18 and latest features (#11300) + * Update JS dependencies, min Node.js version 10.13 (#11246) + * Change default charset for MySQL on install to utf8mb4 (#10989) + * Return issue subscription status from API subscribe (#10966) + * Fix queue log param (#10733) + * Add warning when using relative path to app.ini (#10104) + +## [1.11.7](https://github.com/go-gitea/gitea/releases/tag/v1.11.7) - 2020-06-18 + +* BUGFIXES + * Use ID or Where to instead directly use Get when load object from database (#11925) (#11935) + * Fix __webpack_public_path__ for 1.11 (#11907) + * Fix verification of subkeys of default gpg key (#11713) (#11902) + * Remove unnecessary parentheses in wiki/view template (#11781) + * Doctor fix xorm.Count nil on sqlite error (#11741) + +## [1.11.6](https://github.com/go-gitea/gitea/releases/tag/v1.11.6) - 2020-05-30 + +* SECURITY + * Fix missing authorization check on pull for public repos of private/limited org (#11656) (#11683) + * Use session for retrieving org teams (#11438) (#11439) +* BUGFIXES + * Return json on 500 error from API (#11574) (#11660) + * Fix wrong milestone in webhook message (#11596) (#11612) + * Prevent (caught) panic on login (#11590) (#11598) + * Fix commit page js error (#11527) + * Use media links for img in post-process (#10515) (#11504) + * Ensure public repositories in private organizations are visible and fix admin organizations list (#11465) (#11475) + * Set correct Content-Type value for Gogs/Gitea webhooks (#9504) (#10456) (#11461) + * Allow all members of private orgs to see public repos (#11442) (#11459) + * Whenever the ctx.Session is updated, release it to save it before sending the redirect (#11456) (#11457) + * Forcibly clean and destroy the session on logout (#11447) (#11451) + * Fix /api/v1/orgs/* endpoints by changing parameter to :org from :orgname (#11381) + * Add tracked time fix to doctor (part of #11111) (#11138) + * Fix webpack chunk loading with STATIC_URL_PREFIX (#11526) (#11544) + * Remove unnecessary parentheses in wiki/revision.tmpl to allow 1.11 to build on go1.14 (#11481) + +## [1.11.5](https://github.com/go-gitea/gitea/releases/tag/v1.11.5) - 2020-05-09 + +* BUGFIXES + * Prevent timer leaks in Workerpool and others (#11333) (#11340) + * Fix tracked time issues (#11349) (#11354) + * Add NotifySyncPushCommits to indexer notifier (#11309) (#11338) + * Allow X in addition to x in tasks (#10979) (#11335) + * When delete tracked time through the API return 404 not 500 (#11319) (#11326) + * Prevent duplicate records in organizations list when creating a repository (#11303) (#11325) + * Manage port in submodule refurl (#11305) (#11323) + * api.Context.NotFound(...) should tolerate nil (#11288) (#11306) + * Show pull request selection even when unrelated branches (#11239) (#11283) + * Repo: milestone: make /milestone/:id endpoint accessible (#11264) (#11282) + * Fix GetContents(): Dont't ignore Executables (#11192) (#11209) + * Fix submodule paths when AppSubUrl is not root (#11098) (#11176) + * Prevent clones and pushes to disabled wiki (#11131) (#11134) + * Remove errant third closing curly-bracket from account.tmpl and send account ID in account.tmpl (#11130) + * On Repo Deletion: Delete related TrackedTimes too (#11110) (#11125) + * Refresh codemirror on show pull comment tab (#11100) (#11122) + * Fix merge dialog on protected branch with missing required statuses (#11074) (#11084) + * Load pr Issue Poster on API too (#11033) (#11039) + * Fix release counter on API repository info (#10968) (#10996) + * Generate Diff and Patch direct from Pull head (#10936) (#10938) + * Fix rebase conflict detection in git 2.26 (#10929) (#10930) +* ENHANCEMENT + * Fix 404 and 500 image size in small size screen (#11043) (#11049) + * Multiple Gitea Doctor improvements (#10943) (#10990) (#10064) (#9095) (#10991) + +## [1.11.4](https://github.com/go-gitea/gitea/releases/tag/v1.11.4) - 2020-04-01 + +* BUGFIXES + * Only update merge_base if not already merged (#10909) + * Fix milestones too many SQL variables bug (#10880) (#10904) + * Protect against NPEs in notifications list (#10879) (#10883) + * Convert plumbing.ErrObjectNotFound to git.ErrNotExist in getCommit (#10862) (#10868) + * Convert plumbing.ErrReferenceNotFound to git.ErrNotExist in GetRefCommitID (#10676) (#10797) + * Account for empty lines in receive-hook message (#10773) (#10784) + * Fix bug on branch API (#10767) (#10775) + * Migrate to go-git/go-git v5.0.0 (#10735) (#10753) + * Fix hiding of fields in authorization source page (#10734) (#10752) + * Prevent default for linkAction (#10742) (#10743) + +## [1.11.3](https://github.com/go-gitea/gitea/releases/tag/v1.11.3) - 2020-03-10 + +* BUGFIXES + * Prevent panic in stopwatch (#10670) (#10673) + * Fix bug on pull view when required status check no ci result (#10648) (#10651) + * Build explicitly with Go 1.13 (#10684) + +## [1.11.2](https://github.com/go-gitea/gitea/releases/tag/v1.11.2) - 2020-03-06 + +* BREAKING + * Various fixes in login sources (#10428) (#10429) +* SECURITY + * Ensure only own addresses are updated (#10397) (#10399) + * Logout POST action (#10582) (#10585) + * Org action fixes and form cleanup (#10512) (#10514) + * Change action GETs to POST (#10462) (#10464) + * Fix admin notices (#10480) (#10483) + * Change admin dashboard to POST (#10465) (#10466) + * Update markbates/goth (#10444) (#10445) + * Update crypto vendors (#10385) (#10398) +* BUGFIXES + * Allow users with write permissions to modify issue descriptions and comments. (#10623) (#10626) + * Handle deleted base branch in PR (#10618) (#10619) + * Delete dependencies when deleting a repository (#10608) (#10616) + * Ensure executable bit is kept on the web editor (#10607) (#10614) + * Update mergebase in pr checker (#10586) (#10605) + * Fix release attachments being deleted while upgrading (#10572) (#10573) + * Fix redirection path if Slack webhook channel is invalid (#10566) + * Fix head.tmpl og:image picture location (#10531) (#10556) + * Fix 404 after activating secondary email (#10547) (#10553) + * Show Signer in commit lists and add basic trust (#10425 & #10511) (#10524) + * Fix potential bugs (#10513) (#10518) + * Use \[:space:\] instead of \\s (#10508) (#10509) + * Avoid mailing users that have explicitly unwatched an issue (#10475) (#10500) + * Handle push rejection message in Merge & Web Editor (#10373) (#10497) + * Fix SQLite concurrency problems by using BEGIN IMMEDIATE (#10368) (#10493) + * Fix double PR notification from API (#10482) (#10486) + * Show the username as a fallback on feeds if full name is blank (#10461) + * Trigger webhooks on issue label-change via API too (#10421) (#10439) + * Fix git reference type in webhooks (#10427) (#10432) + * Prevent panic on merge to PR (#10403) (#10408) + * Fix wrong num closed issues on repository when close issue via commit… (#10364) (#10380) + * Reading pull attachments should depend on read UnitTypePullRequests (#10346) (#10354) + * Set max-width on review-box comment box (#10348) (#10353) + * Prevent nil pointer in GetPullRequestCommitStatusState (#10342) (#10344) + * Fix protected branch status check settings (#10341) (#10343) + * Truncate long commit message header (#10301) (#10319) + * Set the initial commit status to Success otherwise it will always be Pending (#10317) (#10318) + * Don't manually replace whitespace during render (#10291) (#10315) +* ENHANCEMENT + * Admin page for managing user e-mail activation (#10557) (#10579) + +## [1.11.1](https://github.com/go-gitea/gitea/releases/tag/v1.11.1) - 2020-02-15 + +* BUGFIXES + * Repo name added to automatically generated commit message when merging (#9997) (#10285) + * Fix Workerpool deadlock (#10283) (#10284) + * Divide GetIssueStats query in smaller chunks (#10176) (#10282) + * Fix reply on code review (#10257) + * Stop hanging issue indexer initialisation from preventing shutdown (#10243) (#10249) + * Fix filter label emoji width (#10241) (#10244) + * Fix issue sidebar menus having an infinite height (#10239) (#10240) + * Fix commit between two commits calculation if there is only last commit (#10225) (#10226) + * Only check for conflicts/merging if the PR has not been merged in the interim (#10132) (#10206) + * Blacklist manifest.json & milestones user (#10292) (#10293) + +## [1.11.0](https://github.com/go-gitea/gitea/releases/tag/v1.11.0) - 2020-02-10 + +* BREAKING + * Fix followers and following tabs in profile (#10202) (#10203) + * Make CertFile and KeyFile relative to CustomPath (#9868) (#9874) + * Remove unused endpoints (#9538) + * Prefix all user-generated IDs in markup (#9477) + * Enforce Gitea environment for pushes (#8982) + * Hide some user information via API if user have not enough permissions (#8655) + * Move startpage/homepage translation to crowdin (#8596) +* SECURITY + * Never allow an empty password to validate (#9682) (#9683) + * Prevent redirect to Host (#9678) (#9679) + * Swagger hide search field (#9554) + * Add "search" to reserved usernames (#9063) + * Switch to fomantic-ui (#9374) + * Only serve attachments when linked to issue/release and if accessible by user (#9340) +* FEATURES + * Webhooks should only show sender if it makes sense (#9601) + * Provide Default messages for merges (#9393) + * Add description to labels on create issue (#9392) + * Graceful Queues: Issue Indexing and Tasks (#9363) + * Default NO_REPLY_ADDRESS to DOMAIN (#9325) + * Allow FCGI over unix sockets (#9298) + * Graceful: Xorm, RepoIndexer, Cron and Others (#9282) + * Add API for Reactions (#9220) + * Graceful: Cancel Process on monitor pages & HammerTime (#9213) + * Graceful: Allow graceful restart for unix sockets (#9113) + * Graceful: Allow graceful restart for fcgi (#9112) + * Sign protected branches (#8993) + * Add Graceful shutdown for Windows and hooks for shutdown of goroutines (#8964) + * Add Gitea icon to Emojis (#8950) + * Expand/Collapse Files and Blob Excerpt while Reviewing/Comparing code (#8924) + * Allow Custom Reactions (#8886) + * Close/reopen issues by keywords in titles and comments (#8866) + * Allow incompletely specified Time Formats (#8816) + * Prevent upload (overwrite) of lfs locked file (#8769) + * Template Repositories (#8768) + * Add /milestones endpoint (#8733) + * Make repository management section handle lfs locks (#8726) + * Respect LFS File Lock on UI (#8719) + * Add team option to grant rights for all organization repositories (#8688) + * Enabling and disabling the commit button to prevent empty commits (web editor) (#8590) + * Add setting to disable BASIC authentication (#8586) + * Expose db.SetMaxOpenConns and allow non MySQL dbs to set conn pool params (#8528) + * Allow Protected Branches to Whitelist Deploy Keys (#8483) + * Push to create repo (#8419) + * Sign merges, CRUD, Wiki and Repository initialisation with gpg key (#7631) + * Add basic repository lfs management (#7199) +* BUGFIXES + * Fix code-expansion arc-green theme bug (#10180) (#10185) + * Prevent double wait-group decrement (#10170) (#10175) + * Allow emoji on review head comments (#10159) (#10174) + * Fix issue/pull link (#10158) (#10173) + * Fix push-create SSH bugs (#10145) (#10151) + * Prevent DeleteUser API abuse (#10125) (#10128) + * Fix issues/pulls dashboard paging error (#10114) (#10115) + * Add button to revert SimpleMDE to plain textarea (#10099) (#10102) + * Fix branch page pull request title and link error (#10092) (#10097) + * Fix PR API: Only try to get HeadBranch if HeadRepo exist (#10029) (#10088) + * Update topics repo count when deleting repository (#10051) (#10081) + * Show pull icon on pull requests (#10061) (#10062) + * Fix milestone API state parameter unhandled (#10049) (#10052) + * Move to using a temporary repo for pushing new PRs (#10009) (#10042) + * Fix wiki raw view on sub path (#10002) (#10040) + * Ensure that feeds are appropriately restricted (#10018) (#10019) + * Sanitize credentials in mirror form (#9975) (#9991) + * Close related pull requests when deleting head repository or head branch (#9927) (#9974) + * Switch to use -f instead of -F for sendmail (#9961) (#9970) + * Fix file rename/copy not supported by indexer (#9965) (#9967) + * Fix repo indexer not updating upon push (#9957) (#9963) + * Don't convert ellipsis in markdown (#9905) (#9937) + * Fixed repo link in generated comment for cross repository dependency (#9863) (#9935) + * Check if diff actually contains sections when rendering (#9926) (#9933) + * Fix wrong hint when status checking is running on pull request view (#9886) (#9928) + * Fix RocketChat (#9908) (#9921) + * Do not try to recreate ldap user if they are already created (#9900) (#9919) + * Create terminated channel in queue_redis (#9910) (#9911) + * Prevent empty LDAP search result from deactivating all users (#9879) (#9896) + * Fix wrong permissions check when issues/prs shared operations (#9885) (#9889) + * Check user != nil before checking values (#9881) (#9883) + * Allow hyphen in language name (#9873) (#9880) + * Ensure that 2fa is checked on reset-password (#9857) (#9876) + * Fix issues/pulls dependencies problems (#9842) (#9864) + * Fix markdown anchor links (#9673) (#9840) + * Allow assignee on Pull Creation when Issue Unit is deactivated (#9836) (#9837) + * Fix download file wrong content-type (#9825) (#9834) + * Fix wrong poster identity on a migrated pull request when submit review (#9827) (#9830) + * Fix database dump when log directory is missing (#9818) (#9819) + * Fix compare (#9808) (#9814) + * Fix push-to-create (#9772) (#9797) + * Fix missing msteam webhook on organization (#9781) (#9794) + * Fix missing unlock in uniquequeue (#9790) (#9791) + * Fix add team on collaborator page when same name as organization (#9778) + * DeleteRepoFile incorrectly handles Delete to new branch (#9769) (#9775) + * Fix milestones page (#9771) + * Fix SimpleMDE quote reply (#9757) (#9768) + * Fix missing updated time on migrated issues and comments (#9744) (#9764) + * Move Errored PRs out of StatusChecking (#9675) (#9726) + * Make hook status printing configurable with delay (#9641) (#9725) + * Fix /repos/issues/search (#9698) (#9724) + * Silence fomantic error regarding tabs (#9713) (#9718) + * Remove unused lock (#9709) (#9710) + * Remove q.lock.Unlock() in setInternal to prevent panic (#9705) (#9706) + * Load milestone in API PR list (#9671) (#9700) + * Don't attempt to close issue if already closed (#9696) (#9699) + * Remove google font call (#9668) (#9681) + * Eliminate horizontal scroll caused by footer (#9674) + * Fix nil reference in repo generation (#9660) (#9666) + * Add HTML URL to API Issues (#9654) (#9661) + * Add PR review webhook to Telegram (#9653) (#9655) + * Use filepath.IsAbs instead of path.IsAbs (#9651) (#9652) + * Disable remove button on repository teams when have access to all (#9640) + * Clean up old references on branch delete (#9614) + * Hide public repos owned by private orgs (#9609) + * Fix access issues on milestone and issue overview pages. (#9603) + * Fix error logged when repos qs is empty (#9591) + * Dont trigger notification twice on issue assignee change (#9582) + * Fix mirror pushed commit actions (#9572) + * Allow only specific columns to be updated on issue via API (#9189) (#9539) + * Fix default avatar for ghost user (#9536) + * Fix download of release attachments with same name (#9529) + * Resolve deprecated INI conversion (#9525) + * Ignore empty avatars during database migration (#9520) + * Fix deleted branch isn't removed when push the branch again (#9516) + * Fix repository issues pagination bug when there are more than one label filter (#9512) + * Fix SetExpr failed (#9506) + * Remove obsolete file private/push_update.go (#9503) + * When recreating hooks, delete them first so they are recreated with the umask (#9502) + * Properly enforce gitea environment for pushes (#9501) + * Fix datarace on repo indexer queue (#9490) + * Add call to load repo prior to redirect in add/remove dependency code (#9484) + * Wrap the code indexer (#9476) + * Use Req.URL.RequestURI() to cope with FCGI urls (#9473) + * Set default ssh.minimum_key_sizes (#9466) + * Fixed issue with paging in /repos/{owner}/{repo}/git/trees/{sha} api (#9459) + * Fix wrong notification on merge (#9450) + * Issue with Migration rule v111 (#9449) + * Trigger webhook when deleting a branch after merging a PR (#9424) + * Add migration to sanitize repository original_url (#9423) + * Use OriginalURL instead of CloneAddr in migration logging (#9418) + * Push update after branch is restored (#9416) + * Fix wrong migration (#9381) + * Fix show repositories filter (#9234) (#9379) + * Fix Slack webhook payload title generation to work with Mattermost (#9378) + * Fix double webhook for new PR (#9375) + * AuthorizedKeysCommand should not query db directly (#9371) + * Fix missed change to GetManager() (#9361) + * Fix cache problem on dashboard (#9358) + * RepoIndexer: DefaultBranch needs to be prefixed by BranchPrefix (#9356) + * Fix protected branch using IssueID (#9348) + * Fix nondeterministic behavior (#9341) + * Fix PR/issue redirects when having external tracker (#9339) + * Remove release attachments which repository has been deleted (#9334) + * Fix issue indexer not triggered when migrating a repository (#9332) + * Add SyncTags to uploader interface (#9326) + * Fix bug that release attachment files not deleted when deleting repository (#9322) + * Only sync tags after all migration release batches are completed (#9319) + * File Edit: Author/Committer interchanged (#9297) + * prebuild CSS/JS before xgo release binaries (#9293) + * Log: Ensure FLAGS=none shows no flags (#9287) + * Make Diff Detail on Pull Request Changed File UI always on Top (#9280) + * Switch CSS minifier to cssnano (#9260) + * Fix latest docker image haven't include static files. (#9252) + * Don't link wiki revision to commit (#9244) + * Change review content column to type text in db (#9229) + * Fixed topic regex pattern and added search by topic links after save (#9219) + * Add language to user API response (#9215) + * Correct tooltip message blocked by dependencies (#9211) + * Add SimpleMDE and Fix Image Paste for Issue/Comment Editor (#9197) + * Fix panic when diff (#9187) + * Fix #9151 - smtp logger configuration sendTos should be an array (#9154) + * Fix max length check and limit in multiple repo forms (#9148) + * Always Show Password Field on Link Account Sign-in Page (#9147) + * Properly fix displaying virtual session provider in admin panel (#9137) + * Fix race condition on indexer (#9136) + * Fix team links in HTML rendering (#9127) + * Fix race condition in ReplaceSanitizer (#9123) + * Fix what information is shown about user in API (#9115) + * Fix nil context user for template repositories (#9099) + * Hide given credentials for migrated repos. (#9097) + * Fix reCAPTCHA API URL (#9083) + * Fix password checks on admin create/edit user (#9076) + * Update golang.org/x/crypto vendor to use acme v2 (#9056) + * Ensure Written is set in GZIP ProxyResponseWriter (#9018) + * Fix wrong system notice when repository is empty (#9010) + * Fix broken link to branch from issue list (#9003) + * Fix bug when pack js (#8992) + * New review approvals shouldn't require a message (#8991) + * Shadow password correctly for session config (#8984) + * Don't send notification on pending reviews (#8943) + * Fix Notify Create Ref Error on tag creation (#8936) + * Convert EOL to UNIX-style to render MD properly (#8925) + * Migrate temp_repo.go to use git.NewCommand (#8918) + * Fix issue with user.fullname (#8902) + * Add Close() method to gogitRepository (#8901) + * Enable punctuations ending mentions (#8889) + * Fix password complexity check on registration (#8887) + * Fix require external registration password (#8885) + * Fix edit content button on migrated issue content (#8877) + * Fix permission checks for close/reopen from commit (#8875) + * Fix API Bug (fail on empty assignees) (#8873) + * Stop using git count-objects and use raw directory size for repository (#8848) + * Fix count for commit graph last page (#8843) + * Fix to close opened io resources as soon as not needed (#8839) + * Improve notification (#8835) + * Fix new user form for non-local users (#8826) + * Fix: remove duplicated signed commit icons (#8820) + * Fix (open/closed) issue count when label excluded (#8815) + * Fix SSH2 conditional in key parsing code (#8806) + * Fix 500 when edit hook (#8782) + * On windows set core.longpaths true (#8776) + * Fix commit expand button to not go to commit link (#8745) + * Avoid re-issuing redundant cross-references. (#8734) + * Fix milestone close timestamp function (#8728) + * Move webhook codes from service to webhook notification (#8712) + * Show zero lines on the line counter if the file empty (#8700) + * Fix deadline on update issue or PR via API (#8696) + * make call createMilestoneComment on newIssue func (#8678) + * Send tag create and push webhook when release created on UI (#8671) + * Prevent chrome download page as html with alt + click (#8669) + * Fix 500 when getting user as unauthenticated user (#8653) + * Graceful fixes (#8645) + * Add SubURL to redirect path (#8632) (#8634) + * Fix extra columns from `label` table (#8633) + * Add SubURL to redirect path for transferred/renamed repos (#8632) + * Fix bug when migrate from API (#8631) + * Allow to merge if file path contains " or \ (#8629) + * Prevent removal of non-empty emoji panel following selection of duplicate (#8609) + * Ensure default gpg settings not nil and found commits have reference to repo (#8604) + * Set webhook Content-Type for application/x-www-form-urlencoded (#8599) + * Fix #8582 by handling empty repos (#8587) + * Fix of the diff statistics view on pull request's (#8581) + * Fix bug on pull requests when transfer head repository (#8564) + * Fix template error on account page (#8562) + * Allow externalID to be UUID (#8551) + * Fix ignored error on editorconfig api (#8550) + * Fix user avatar name (#8547) + * Ensure that GitRepo is set on Empty repositories (#8539) + * Add missed close in ServeBlobLFS (#8527) + * Fix migrate mirror 500 bug (#8526) + * Fix password complexity regex for special characters (on master) (#8525) +* ENHANCEMENTS + * Explicitly refer to PR in squash-merge commit message in case of external tracker (#9844) (#9855) + * Add a /user/login landing page option (#9622) + * Some more e-mail notification fixes (#9596) + * Add branch protection option to block merge on requested changes. (#9592) + * Add footer extra links template (#9576) + * Fix for a wrong URL in activity page of repository. (#9571) + * Update default issue template (#9568) + * Change markdown rendering from blackfriday to goldmark (#9533) + * Extend file create api with dates (#9464) + * Add ActionCommentPull action (#9456) + * Response for context on retry database connection (#9444) + * Refactor webhooks to reduce code duplication (#9422) + * update couchbase deps for new license (#9419) + * Add .ignore file for search tools (#9417) + * Remove unsued struct (#9405) + * Hide not allowed Reactions (#9387) + * Remove text from action-only webhooks (#9377) + * Move PushToBaseRepo from models to services/pull (#9352) + * Site admin could view org's members (#9346) + * Sleep longer if request speed is over github limitation (#9335) + * Refactor comment (#9330) + * Refactor code indexer (#9313) + * Remove SavePatch and generate patches on the fly (#9302) + * Move some pull request functions from models to services (#9266) + * Update JS dependencies (#9255) + * Show label list on label set (#9251) + * Redirect issue if repo has configured external tracker. (#9247) + * Allow kbd tags (#9245) + * Remove unused comment actions (#9222) + * Fixed errors logging in dump.go (#9218) + * Expose release counter to repo API response (#9214) + * Make consistent links to repository in the Slack/Mattermost notificiations (#9205) + * Expose pull request counter to repo API response (#9202) + * Extend TrackedTimes API (#9200) + * Extend StopWatch API (#9196) + * Move code indexer related code to a new package (#9191) + * Docker: ask s6 to stop all service when gitea stop (#9171) + * Variable expansion in repository templates (#9163) + * Add avatar and issue labels to template repositories (#9149) + * Show single review comments in the PR conversation tab (#9143) + * Extract createComment (#9125) + * Move PushUpdateOptions from models to repofiles (#9124) + * Alternate syntax for cross references (#9116) + * Add USE_SERVICE_WORKER setting (#9110) + * Only show part of members on orgnization dashboard and add paging for orgnization members page (#9092) + * Explore page: Add topic param to pagination (#9077) (#9078) + * Markdown: Sanitizier Configuration (#9075) + * Add password requirement info on error (#9074) + * Allow authors to use act keywords in PR content (#9059) + * Move modules/gzip to gitea.com/macaron/gzip (#9058) + * Branch protection: Possibility to not use whitelist but allow anyone with write access (#9055) + * Context menus for comments, add quote reply (#9043) + * Update branch API endpoint to show effective branch protection. (#9031) + * Move git graph from models to modules/graph (#9027) + * Move merge actions to notification (#9024) + * Move mirror sync actions to notification (#9022) + * Add retry for migration http/https requests (#9019) + * Rewrite delivery of issue and comment mails (#9009) + * Add review comments to mail notifications (#8996) + * Refactor pull request review (#8954) + * Githook highlighter (#8932) + * Add git hooks and webhooks to template repositories; move to services (#8926) + * Only view branch or tag if it match refType requested. (#8899) + * Drop Admin attribute based on LDAP when login (continue #1743) (#8849) + * Add additional periods to activity page (#8829) + * Update go-org to optimize code (#8824) + * Move some actions to notification/action (#8779) + * Webhook support custom proxy (#8760) + * Fix API deadline removal (#8759) + * Mark review comment as invalidated when file is deleted (#8751) + * Move pull list code to a separate file (#8748) + * Move webhook to a standalone package under modules (#8747) + * Multi repo select on issue page (#8741) + * apply exclude label on milestone issue list (#8739) + * Move issue notifications and assignee man (#8713) + * Move issue change content from models to service (#8711) + * Move issue change status from models to service (#8691) + * Move more issue assignee code from models to issue service (#8690) + * Create PR on Current Repository by Default (#8670) + * Improve Open Graph Protocol (#8637) + * Batch hook pre- and post-receive calls (#8602) + * Improve webhooks (#8583) + * Move transfer repository and rename repository on a service package and start action notification (#8573) + * Implement/Fix PR review webhooks (#8570) + * Rewrite markdown rendering to blackfriday v2 and rewrite orgmode rendering to go-org (#8560) + * Move some repositories' operations to a standalone service package (#8557) + * Allow more than 255 characters for tokens in external_login_user table (#8554) + * Move issue label operations to issue service package (#8553) + * Adjust error reporting from merge failures and use LC_ALL=C for git (#8548) + * Mail assignee when issue/pull request is assigned (#8546) + * Allow committing / adding empty files using the web ui (#8420) (#8532) + * Move sync mirror actions to mirror service package (#8518) + * Remove arrows on numeric inputs (#8516) + * Support inline rendering of CUSTOM_URL_SCHEMES (#8496) + * Recalculate repository access only for specific user (#8481) + * Add download button for rull request diff- and patch-file (#8470) + * Add single sign-on support via SSPI on Windows (#8463) + * Move change issue title from models to issue service package (#8456) + * Add included tag on branch view (#8449) + * Make static resouces web browser cache time customized on app.ini (#8442) + * Enable Uploading/Removing Attachments When Editing an Issue/Comment (#8426) + * Add pagination to commit graph page (#8360) + * Use templates for issue e-mail subject and body (#8329) + * Move clearlabels from models to issue service (#8326) + * Move AddTestPullRequestTask to pull service package from models (#8324) + * Team permission to create repository in organization (#8312) + * Allows external rendering of other filetypes (#8300) + * Add 'Alt + click' feature to exclude labels (#8199) + * Configurable close and reopen keywords for PRs (#8120) + * Configurable URL for static resources (#7911) + * Unifies commit list in repository commit table and wiki revision page (#7907) + * Allow cross-repository dependencies on issues (#7901) + * Auto-subscribe user to repository when they commit/tag to it (#7657) + * Restore Graceful Restarting & Socket Activation (#7274) + * wiki - add 'write' 'preview' buttons to wiki edit like in issues (#7241) + * Change target branch for pull request (#6488) + * Display PR commits and diffs using base repo rather than forked (#3648) +* TESTING + * Add debug option to serv to help debug problems (#9492) + * Fix the intermittent TestGPGGit failures (#9360) + * Testing: Update postgres sequences (#9304) + * Missed defer prepareTestEnv (#9285) + * Fix "data race" in testlogger (#9159) + * Yet another attempt to fix the intermittent failure of gpg git test (#9146) + * integrations: Fix Dropped Test Errors (#9040) + * services/mirror: fix dropped test errors (#9007) + * Fix intermittent GPG Git test failure (#8968) + * Update Github Migration Tests (#8893) (#8938) + * Update heatmap fixtures to restore tests (#8615) +* TRANSLATION + * Fix Korean locales (#9761) (#9780) + * Fix placeholders in the error message (#9060) + * Fix spelling of admin.users.max_repo_creation (#8934) + * Improve german translation of homepage (#8549) +* BUILD + * Fix webpack polyfills (#9735) (#9738) + * Update gitea.com/macaron to 1.4.0 (#9608) + * Upgrade lato fonts to v16. (#9498) + * Update alpine to 3.11 (#9440) + * Upgrade blevesearch (#9177) + * Remove built js/css files from git (#9114) + * Move semantic.dropdown.custom.js to webpack (#9064) + * Check compiled files during build (#9042) + * Enable lazy-loading of gitgraph.js (#9036) + * Pack web_src/js/draw.js to public/js/index.js (#8975) + * Modernize js and use babel (#8973) + * Move index.js to web_src and use webpack to pack them (#8598) + * Restrict modules/graceful to non-windows build and shim IsChild (#8537) + * Upgrade gopkg.in/editorconfig/editorconfig-core-go.v1 (#8501) +* DOCS + * Swagger info corrections (#9441) (#9558) + * Add ALLOW_ONLY_EXTERNAL_REGISTRATION to config cheat sheet (#8986) + * Rephrase comment about RuntimeDirectory option in systemd config (#8912) + * Explicitly indicate the socket unit to use the service unit "gitea.service" (#8804) + * Adjust the must-change-password help (#8755) + * Add notice to docs for migrating from more recent versions of Gogs (#8724) + * Add explicit info about customization of homepage (#8694) + * Change external asciidoctor tool to embedded mode (#8677) + * Add Docker fail2ban configuration (#8642) + * Correct some outdated statements in the contributing guidelines (#8612) + * Basic Design guidelines (describing different parts of the code) (#8601) + * Display Gitea logo in Readme (#8592) + * Fix building from source docs to ref AppWorkPath (#8567) + * Update the provided gitea.service to mention socket activation (#8531) + * Doc added how to setup email (#8520) +* MISC + * Backport Locales [2020-01-14] (#9773) + * Add translatable Powered by Gitea text in footer (#9600) + * Add contrib/environment-to-ini (#9519) + * Remove unnecessary loading of settings in update hook (#9496) + * Update gitignore list (#9437) + * Update license list (#9436) + * Fix background reactions in the arc-green theme (#9421) + * Update and fix chardet import (#9351) + * Ensure LF on checkouts and in editors (#9259) + * Fixed topics margin (#9248) + * Add comment to exported function WindowsServiceName (make revive) (#9241) + * Remove empty lines on issues/pulls page (#9232) + * Fix Add Comment Button's "+" Position (#9140) + * Add first issue comment hashtag (#9052) + * Change some label colors (#9051) + * Fix double scroll in branch dropdown (#9048) + * Add comment highlight when target from url (#9047) + * Update display of reactions to issues and comments (#9038) + * Button tooltip formatting under Branches (#9034) + * Allow setting default branch via API (#9030) + * Update dashboard context for PR reviews (#8995) + * Show repository size in repo home page and settings (#8940) + * Allow to add and remove all repositories to/from team. (#8867) + * Show due date in dashboard issues list (#8860) + * Theme arc-green: reverse heatmap colors (#8840) + * Project files table style update (#8757) + * gitignore debugging file from vscode (#8740) + * Add API for Issue set Subscription (#8729) + * Make 100% width search bar (#8710) + * Update color theme for heatmap (#8709) + * Add margin to title_wip_desc (#8705) + * Improve visibility of "Pending" indicator (#8685) + * Improve accessibility of dropdown menus (#8638) + * Make /users/{username}/repos list private repos the current user has access to (#8621) + * Prevent .code-view from overriding font on icon fonts (#8614) + * Add id references on all issue events to allow internal linking (#8608) + * Upgrade xorm to v0.8.0 (#8536) + * Upgrade gopkg.in/ini.v1 (#8500) + * Update CodeMirror to version 5.49.0 (#8381) + * Wiki editor: enable side-by-side button (#7242) + +## [1.10.6](https://github.com/go-gitea/gitea/releases/tag/v1.10.6) - 2020-03-10 + +This is a re-tag version of v1.10.5 and also explicitly built with Go 1.13. + +WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be used. + +## [1.10.5](https://github.com/go-gitea/gitea/releases/tag/v1.10.5) - 2020-03-06 + +* BUGFIXES + * Fix release attachments being deleted while upgrading (#10572) (#10574) + +## [1.10.4](https://github.com/go-gitea/gitea/releases/tag/v1.10.4) - 2020-02-16 + +* FEATURE + * Prevent empty LDAP search from deactivating all users (#9879) (#9890) +* BUGFIXES + * Fix reply on code review (#10261) (#10227) + * Fix branch page pull request title and link error (#10092) (#10098) + * Fix milestone API state parameter unhandled (#10049) (#10053) + * Fix wiki raw view on sub path (#10002) (#10041) + * Fix RocketChat Webhook (#9908) (#9921) (#9925) + * Fix bug about wrong dependencies permissions check and other wrong permissions check (#9884) (Partial backport #9842) + * Ensure that 2fa is checked on reset-password (#9857) (#9877) + +## [1.10.3](https://github.com/go-gitea/gitea/releases/tag/v1.10.3) - 2020-01-17 + +* SECURITY + * Hide credentials when submitting migration (#9102) (#9704) + * Never allow an empty password to validate (#9682) (#9684) + * Prevent redirect to Host (#9678) (#9680) + * Hide public repos owned by private orgs (#9609) (#9616) +* BUGFIXES + * Allow assignee on Pull Creation when Issue Unit is deactivated (#9836) (#9838) + * Fix download file wrong content-type (#9825) (#9835) + * Fix wrong identify poster on a migrated pull request when submit review (#9827) (#9831) + * Fix dump non-exist log directory (#9818) (#9820) + * Fix compare (#9808) (#9815) + * Fix missing msteam webhook on organization (#9781) (#9795) + * Fix add team on collaborator page when same name as organization (#9783) + * Fix cache problem on dashboard (#9358) (#9703) + * Send tag create and push webhook when release created on UI (#8671) (#9702) + * Branches not at ref commit ID should not be listed as Merged (#9614) (#9639) + +## [1.10.2](https://github.com/go-gitea/gitea/releases/tag/v1.10.2) - 2020-01-02 + +* BUGFIXES + * Allow only specific Columns to be updated on Issue via API (#9539) (#9580) + * Add ErrReactionAlreadyExist error (#9550) (#9564) + * Fix bug when migrate from API (#8631) (#9563) + * Use default avatar for ghost user (#9536) (#9537) + * Fix repository issues pagination bug when there are more than one label filter (#9512) (#9528) + * Fix deleted branch not removed when push the branch again (#9516) (#9524) + * Fix missing repository status when migrating repository via API (#9511) + * Trigger webhook when deleting a branch after merging a PR (#9510) + * Fix paging on /repos/{owner}/{repo}/git/trees/{sha} API endpoint (#9482) + * Fix NewCommitStatus (#9434) (#9435) + * Use OriginalURL instead of CloneAddr in migration logging (#9418) (#9420) + * Fix Slack webhook payload title generation to work with Mattermost (#9404) + * DefaultBranch needs to be prefixed by BranchPrefix (#9356) (#9359) + * Fix issue indexer not triggered when migrating a repository (#9333) + * Fix bug that release attachment files not deleted when deleting repository (#9322) (#9329) + * Fix migration releases (#9319) (#9326) (#9328) + * Fix File Edit: Author/Committer interchanged (#9297) (#9300) + +## [1.10.1](https://github.com/go-gitea/gitea/releases/tag/v1.10.1) - 2019-12-05 + +* BUGFIXES + * Fix max length check and limit in multiple repo forms (#9148) (#9204) + * Properly fix displaying virtual session provider in admin panel (#9137) (#9203) + * Upgrade levelqueue to 0.1.0 (#9192) (#9199) + * Fix panic when diff (#9187) (#9193) + * Smtp logger configuration sendTos should be an array (#9154) (#9157) + * Always Show Password Field on Link Account Sign-in Page (#9150) + * Create PR on Current Repository by Default (#8670) (#9141) + * Fix race on indexer (#9136) (#9139) + * Fix reCAPTCHA URL (#9119) + * Hide migrated credentials (#9098) + * Update golang.org/x/crypto vendor to use acme v2 (#9056) (#9085) + * Fix password checks on admin create/edit user (#9076) (#9081) + * Fix add search as a reserved username (#9063) (#9065) + * Fix permission checks for close/reopen from commit (#8875) (#9033) + * Ensure Written is set in GZIP ProxyResponseWriter (#9018) (#9025) + * Fix broken link to branch from issue list (#9003) (#9021) + * Fix wrong system notice when repository is empty (#9020) + * Shadow password correctly for session config (#8984) (#9002) + +## [1.10.0](https://github.com/go-gitea/gitea/releases/tag/v1.10.0) - 2019-11-13 + +* BREAKING + * Fix deadline on update issue or PR via API (#8698) + * Hide some user information via API if user doesn't have enough permission (#8655) (#8657) + * Remove legacy handling of drone token (#8191) + * Change repo search to use exact match for topic search. (#7941) + * Add pagination for admin api get orgs and fix only list public orgs bug (#7742) + * Implement the ability to change the ssh port to match what is in the gitea config (#7286) +* SECURITY + * Fix issue with user.fullname (#8903) + * Ignore mentions for users with no access (#8395) + * Be more strict with git arguments (#7715) + * Extract the username and password from the mirror url (#7651) + * reserve .well-known username (#7637) +* FEATURES + * Org/Members: display 2FA members states + optimize sql requests (#7621) + * SetDefaultBranch on pushing to empty repository (#7610) + * Adds side-by-side diff for images (#6784) + * API method to list all commits of a repository (#6408) + * Password Complexity Checks (#6230) + * Add option to initialize repository with labels (#6061) + * Add additional password hash algorithms (#6023) +* BUGFIXES + * Allow to merge if file path contains " or \ (#8629) (#8771) + * On windows set core.longpaths true (#8776) (#8786) + * Fix 500 when edit hook (#8782) (#8789) + * Fix Checkbox at RepoSettings Protected Branch (#8799) (#8801) + * Fix SSH2 conditional in key parsing code (#8806) (#8810) + * Fix commit expand button to not go to commit link (#8745) (#8825) + * Fix new user form for non-local users (#8826) (#8828) + * Fix to close opened io resources as soon as not needed (#8839) (#8846) + * Fix edit content button on migrated issue content (#8877) (#8884) + * Fix require external registration password (#8885) (#8890) + * Fix password complexity check on registration (#8887) (#8888) + * Update Github Migration Tests (#8896) (#8938) (#8945) + * Enable punctuations ending mentions (#8889) (#8894) + * Add Close() method to gogitRepository (#8901) (#8956) + * Hotfix for review actions and notifications (#8965) + * Expose db.SetMaxOpenConns and allow non MySQL dbs to set conn pool params (#8528) (#8618) + * Fix milestone close timestamp (#8728) (#8730) + * Fix 500 when getting user as unauthenticated user (#8653) (#8663) + * Fix 'New Issue Missing Milestone Comment' (#8678) (#8681) + * Use AppSubUrl for more redirections (#8647) (#8651) + * Add SubURL to redirect path (#8632) (#8634) + * Fix template error on account page (#8562) (#8622) + * Allow externalID to be UUID (#8551) (#8624) + * Prevent removal of non-empty emoji panel following selection of duplicate (#8609) (#8623) + * Update heatmap fixtures to restore tests (#8615) (#8616) + * Ensure that diff stats can scroll independently of the diff (#8581) (#8621) + * Webhook: set Content-Type for application/x-www-form-urlencoded (#8600) + * Fix #8582 by handling empty repos (#8587) (#8594) + * Fix bug on pull requests when transfer head repository (#8564) (#8569) + * Add missed close in ServeBlobLFS (#8527) (#8542) + * Ensure that GitRepo is set on Empty repositories (#8539) (#8541) + * Fix migrate mirror 500 bug (#8526) (#8530) + * Fix password complexity regex for special characters (#8524) + * Prevent .code-view from overriding font on icon fonts (#8614) (#8627) + * Allow more than 255 characters for tokens in external_login_user table (#8554) + * Fix errors in create org UI regarding team access permission (#8506) + * Fix bug on FindExternalUsersByProvider (#8504) + * Create .ssh dir as necessary (#8486) + * IsBranchExist: return false if provided name is empty (#8485) + * Making openssh listen on SSH_LISTEN_PORT not SSH_PORT (#8477) + * Add check for empty set when dropping indexes during migration (#8471) + * LFS files are relative to LFS content path, ensure that when deleting they are made relative to this (#8455) + * Ensure Request Body Readers are closed in LFS server (#8454) + * Fix template bug on mirror repository setting page (#8438) + * Fix migration v96 to keep issue attachments (#8435) + * Update strk.kbt.io/projects/go/libravatar to latest (#8429) + * Singular form for files that has only one line (#8416) + * Check for either escaped or unescaped wiki filenames (#8408) + * Allow users with explicit read access to give approvals (#8382) + * Fix editor commit to new branch if PR disabled (#8375) + * readd .markdown class to all markup renderers (#8357) + * Upgrade xorm to v0.7.9 to fix some bugs (#8354) + * Fix column name ambiguity in GetUserIssueStats() (#8347) + * Change general form binding to gogs form (#8334) + * Fix pull request commit status in user dashboard list (#8321) + * Fix repo_admin_change_team_access always checked in org settings (#8319) + * Update to github.com/lafriks/xormstore@v1.3.0 (#8317) + * Show correct commit status in PR list (#8316) + * Bugfix for image compare and minor improvements to image compare (#8289) + * Update xorm (#8286) + * Fix API for edit and delete release attachment (#8285) + * Fix nil object access in some conditions when parsing cross references (#8281) + * Fix label count (#8267) + * Only show teams access for organization repositories on collaboration setting page (#8265) + * Test more reserved usernames (#8263) + * Rewrite reference processing code in preparation for opening/closing from comment references (#8261) + * Fix assets key on release webhook (#8253) + * Allow registration when button is hidden (#8237) + * Fix release API URL generation (#8234) + * Fix milestone num_issues (#8221) + * MS Teams webhook misses commit messages (#8209) + * Fix data race (#8204) + * Fix team user api (#8172) + * Fix pull merge 500 error caused by git-fetch breaking behaviors (#8161) + * Make show private icon when repo avatar set (#8144) + * Add reviewers as participants (#8121) + * Fix Go 1.13 private repository go get issue (#8112) + * feat: highlight issue references with : (#8101) + * Make AllowedUsers configurable in sshd_config (#8094) + * Strict name matching for Repository.GetTagID() (#8074) + * Avoid ambiguity of branch/directory names for the git-diff-tree command (#8066) + * Add change title notification for issues (#8061) + * [ssh] fix the config specification in the authorized_keys template (#8031) + * Fix reading git notes from nested trees (#8026) + * Fixes synchronize tags to releases for repository - makes sure we are only getting tag refs (#7990) + * Fix adding default Telegram webhook (#7972) + * Run CORS handler first for /api routes (#7967) + * Abort synchronization from LDAP source if there is some error. (#7960) + * Fix wrong sender when send slack webhook (#7918) + * Fix bug when migrating a private repository (#7917) + * Evaluate emojis in commit messages in list view (#7906) + * Fix upload file type check (#7890) + * lfs/lock: round locked_at timestamp to second (#7872) + * fix non existent milestone with 500 error instead of 404 (#7867) + * gpg/bugfix: Use .ExpiredUnix.IsZero to display green color of forever valid gpg key (#7846) + * Fix duplicate call of webhook (#7821) + * Enable switching to a different source branch when PR already exists (#7819) + * Convert files to utf-8 for indexing (#7814) + * Do not fetch all refs in pull-request compare (#7797) + * Fix multiple bugs with statuses endpoints at API (#7785) + * Restore functionality for early gits (#7775) + * Fix Slack webhook fork message (#7774) + * Rewrite existing repo units if setting is not included in api body (#7763) + * Fix rename failed when rewrite public keys (#7761) + * Fix approvals counting (#7757) + * Add migration step to remove old repo_indexer_status orphaned records (#7746) + * Fix repo_index_status lingering when deleting a repository (#7734) + * Remove camel case tokenization from repo indexer (#7733) + * Fix milestone completness calculation when migrating (#7725) + * Regression: Include "executable" files in the index, as they are not necessarily … (#7718) + * Fixes indexed repos keeping outdated indexes when files grow too large (#7712) + * Skip non-regular files (e.g. submodules) on repo indexing (#7711) + * Fix dropTableColumns sqlite implementation (#7710) + * Update gopkg.in/src-d/go-git.v4 to v4.13.1 (#7705) + * improve branches list performance and fix protected branch icon when no-login (#7695) + * Correct wrong datetime format for git (#7689) + * Move add to hook queue for created repo to outside xorm session. (#7675) + * sugestion to use range .Branches (#7674) + * Fix bug on migrating milestone from github (#7665) + * hide delete/restore button on archived repos (#7658) + * css: use flex to fix floating paginate (#7656) + * Fix syntax highlight initialization (#7617) + * Fix panic on push at - Merging pull request causes 500 error (#7615) + * Make PKCS8, PEM and SSH2 keys work (#7600) + * Fix mistake in arc-green.less split-diff css code. (#7587) + * Handle ErrUserProhibitLogin in http git (#7586) + * Fix bug create/edit wiki pages when code master branch protected (#7580) + * Fixes Malformed URLs in API git/commits response (#7565) + * Fix file header overflow in file and blame views (#7562) + * Improve SSH key parser to handle newlines in keys (#7522) + * Fix empty commits now showing in repo overview (#7521) + * Fix repository's pull request count error (#7518) + * Fix markdown invoke sequence (#7513) + * Remove duplicated webhook trigger (#7511) + * Update User.NumRepos atomically in createRepository (#7493) + * Fix settings page of repo you aren't admin print error - Settings pages giving UnitType error message (#7482) + * Fix redirection after file edit - Handles all redirects for Web UI File CRUD (#7478) + * cmd/serv: actually exit after fatal errors (#7458) + * Fix an issue with some pages throwing 'not defined' js exceptions (#7450) + * fix Dropzone.js integration (#7445) + * Fix regex for issues in commit messages (#7444) + * Diff: Fix indentation on unhighlighted code (#7435) + * Only show "New Pull Request" button if repo allows pulls (#7426) + * Upgrade macaron/captcha to fix random error problem (#7407) + * create class for inline positioned lists (#7393) + * Fetch refs for successful testing for tag (#7388) + * add missing template variable on organisation settings (#7385) + * fix post parameter - on issue list - unset assignee (#7380) + * fix/define autochecked checkboxes on issue list in firefox (#7320) + * only return head: null if source branch was deleted (#6705) +* ENHANCEMENTS + * Add nofollow to sign in links (#8509) + * vendor: update mvdan.cc/xurls/v2 to v2.1.0 (#8495) + * Update milestone issues numbers when save milestone and other code improvements (#8411) + * Add extra user information when migrating release (#8331) + * Require overall success if no context is given for status check (#8318) + * Transaction-aware retry create issue to cope with duplicate keys (#8307) + * Change link on issue milestone (#8246) + * Alwaywas return local url for users avatar (#8245) + * Move some milestone functions to a standalone package (#8213) + * Move create issue comment to comments package (#8212) + * Disable max height property of comment textarea (#8203) + * Add 'Mentioning you' group to /issues page (#8201) + * oauth2 with remote Gitea (#8149) + * Reference issues from pull requests and other issues (#8137) + * Fix webhooks to use proxy from environment (#8116) + * Add merged commit id on pull view when it's merged (#8062) + * Add teams to repo on collaboration page. (#8045) + * Update swagger to 0.20.1 (#8010) + * Make link last commit massages in repository home page and commit tables (#8006) + * Add API endpoint for accessing repo topics (#7963) + * Include description in repository search (#7942) + * Use gitea forked macaron (#7933) + * Fix pull creation with empty changes (#7920) + * Allow token as authorization for accessing attachments (#7909) + * Retry create issue to cope with duplicate keys (#7898) + * Move git diff codes from models to services/gitdiff (#7889) + * migrate gplus to google oauth2 provider (#7885) + * Remove unique filter from repo indexer analyzer. (#7878) + * Detect delimiter in CSV rendering (#7869) + * Import topics during migration (#7851) + * Move CreateReview to modules/pull (#7841) + * vendor: update pdf.js to v2.1.266 (#7834) + * Support SSH_LISTEN_PORT env var in docker app.ini template (#7829) + * Add Ability for User to Customize Email Notification Frequency (#7813) + * Move database settings from models to setting (#7806) + * Display ui time with customize time location (#7792) + * Implement webhook branch filter (#7791) + * Restrict repository indexing by glob match (#7767) + * Api: advanced settings for repository (external wiki, issue tracker etc.) (#7756) + * Update migrated repositories' issues/comments/prs poster id if user has a github external user saved (#7751) + * deps: Upgrade gopkg.in/editorconfig/editorconfig-core-go.v1 (#7749) + * Apply emoji on commit graph page (#7743) + * Add a lot of extension to language mappings for syntax highlights (#7741) + * Add SQL execution on log and indexes on table repository and comment (#7740) + * Set DB connection error level to error (#7724) + * Check commit message hashes before making links (#7713) + * remove unnecessary fmt on generate bindata (#7706) + * Fix specific highlighting (CMakeLists.txt ...) (#7686) + * Add file status on API (#7671) + * Add support for DEFAULT_ORG_MEMBER_VISIBLE (#7669) + * Provide links in commit summaries in commits table/view list (#7659) + * Change length of some repository's columns (#7652) + * Move commit repo action from models to repofiles package (#7645) + * fix wrong email when use gitea as OAuth2 provider (#7640) + * [Branch View] add download button (#7604) + * Update to xorm@v0.7.4 (#7596) + * use 403 instead of 401 for ErrUserProhibitLogin (#7591) + * Removed unnecessary conversions (#7557) + * Un-lambda base.FileSize (#7556) + * Added missing error checks in tests (#7554) + * Move create release from models to a standalone package (#7539) + * Make default branch name link to default branch (#7519) + * Added total count of contributions to heatmap (#7517) + * Move mirror to a standalone package from models (#7486) + * Move models.PushUpdate to repofiles.PushUpdate (#7485) + * Include thread related headers in issue/coment mail (#7484) + * Refuse merge until all required status checks success (#7481) + * convert all js var to let/const (#7464) + * Only create branches for opened pull requestes when migrating from github (#7463) + * jQuery 3 (#7425) + * Add notification placeholder (#7409) + * Search Commits via Commit Hash (#7400) + * Move status table to cron package (#7370) + * wiki - page revisions list (#7369) + * Display original author and URL information when showing migrated issues/comments (#7352) + * Refactor filetype is not allowed errors (#7309) + * switch to use gliderlabs/ssh for builtin server (#7250) + * Remove setting dependency on modules/session (#7237) + * Move all mail related codes from models to services/mailer (#7200) + * Support git.PATH entry in app.ini (#6772) + * Support setting cookie domain (#6288) + * Move migrating repository from frontend to backend (#6200) + * Delete releases attachments if release is deleted (#6068) +* TRANSLATION + * Latvian translation for home page (#8468) + * Add home template italian translation (#8352) + * fix misprint (#7452) +* BUILD + * use go 1.13 (#8088) +* MISC + * add file line count info on UI (#8396) + * Make issues page left menu 100% width and add reponame as title attribute (#8359) + * [arc-green] white on hover for active menu items (#8344) + * Move ref (branch or tag) location on issue list page (#8157) + * apply emoji on dashboard issue list labels (#8156) + * 1148: Take up the full width when viewing the diff in split view. (#8114) + * Display description of 'make this repo private' as help text, not as tooltip (#8097) + * Fixes deformed emoji in pull request reviews (#8047) + * Add strike to old header on comment (#8046) + * Add tooltip for the visibility checkbox in /repo/create (#8025) + * Update github.com/lafriks/xormstore and tidy up mod.go (#8020) + * keep blame view buttons sequence consistent with normal view when view a file (#8007) + * Use "Pull Request" instead of "Merge Request" (#8003) + * Move line number to :before attr to hide from search on browser (#8002) + * Changed black color to white for (read) number label on issue list page (#8000) + * [Branch View] show "New Pull Request" Button only if posible (#7977) + * Fix hook problem by only setting the git environment variables if we are passed them (#7854) + * Prevent Commit Status and Message From Overflowing On Branch Page (#7800) + * Fix global search result CSS, misc CSS tweaks (#7789) + * Tweak label border CSS (#7739) + * Fix create menu item widths (#7708) + * [Branch View] Delete duplicate protection symbol (#7624) + * [Branch View] Delete Table Header (#7622) + * [Branch View] icons to buttons (#7602) + * update js dependencies (#7462) + * Add Extra Info to Branches Page (#7461) + * Bump lodash from 4.17.11 to 4.17.14 (#7459) + * wiki history improvements (#7391) + * ui fixes - compare view and archieved repo issues (#7345) + * dark theme scrollbars (#7269) + * wiki - editor - add buttons 'inline code', 'empty checkbox', 'checked checkbox' (#7243) + * Fix Statuses API only shows first 10 statuses: Add paging and extend API GetCommitStatuses (#7141) + +## [1.9.6](https://github.com/go-gitea/gitea/releases/tag/v1.9.6) - 2019-11-13 + +* BUGFIXES + * Allow to merge if file path contains " or \ (#8629) (#8772) + * Fix 500 when edit hook (#8782) (#8790) + * Fix issue with user.fullname (#8904) + * Update Github Migration Test (#8897) (#8946) + * Add Close() method to gogitRepository (#8901) (#8958) + +## [1.9.5](https://github.com/go-gitea/gitea/releases/tag/v1.9.5) - 2019-10-30 + +* BREAKING + * Hide some user information via API if user doesn't have enough permission (#8655) (#8658) +* BUGFIXES + * Fix milestone close timestamp (#8728) (#8731) + * Fix deadline on update issue or PR via API (#8699) + * Fix 'New Issue Missing Milestone Comment' (#8678) (#8682) + * Fix 500 when getting user as unauthenticated user (#8653) (#8662) + * Use AppSubUrl for more redirections (#8647) (#8652) + * Add SubURL to redirect path (#8632) (#8634) (#8640) + * Fix #8582 by handling empty repos (#8587) (#8593) + * Fix bug on pull requests when transfer head repository (#8571) + * Add missed close in ServeBlobLFS (#8527) (#8543) + * Return false if provided branch name is empty for IsBranchExist (#8485) (#8492) + * Create .ssh dir as necessary (#8369) (#8486) (#8489) + * Restore functionality for early gits (#7775) (#8476) + * Add check for empty set when dropping indexes during migration (#8475) + * Ensure Request Body Readers are closed in LFS server (#8454) (#8459) + * Ensure that LFS files are relative to the LFS content path (#8455) (#8458) +* SECURITY + * Ignore mentions for users with no access (#8395) (#8484) +* TESTING + * Update heatmap fixtures to restore tests (#8615) (#8617) + +## [1.9.4](https://github.com/go-gitea/gitea/releases/tag/v1.9.4) - 2019-10-08 + +* BUGFIXES + * Highlight issue references (#8101) (#8404) + * Fix bug when migrating a private repository #7917 (#8403) + * Change general form binding to gogs form (#8334) (#8402) + * Fix editor commit to new branch if PR disabled (#8375) (#8401) + * Fix milestone num_issues (#8221) (#8400) + * Allow users with explicit read access to give approvals (#8398) + * Fix commit status in PR #8316 and PR #8321 (#8339) + * Fix API for edit and delete release attachment (#8290) + * Fix assets on release webhook (#8283) + * Fix release API URL generation (#8239) + * Allow registration when button is hidden (#8238) + * MS Teams webhook misses commit messages (backport v1.9) (#8225) + * Fix data race (#8206) + * Fix pull merge 500 error caused by git-fetch breaking behaviors (#8194) + * Fix the SSH config specification in the authorized_keys template (#8193) + * Fix reading git notes from nested trees (#8189) + * Fix team user api (#8172) (#8188) + * Add reviewers as participants (#8124) +* BUILD + * Use vendored go-swagger (#8087) (#8165) + * Fix version-validation for GO 1.13 (go-macaron/cors) (#8389) +* MISC + * Make show private icon when repo avatar set (#8144) (#8175) + +## [1.9.3](https://github.com/go-gitea/gitea/releases/tag/v1.9.3) - 2019-09-06 + +* BUGFIXES + * Fix go get from a private repository with Go 1.13 (#8100) + * Strict name matching for Repository.GetTagID() (#8082) + * Avoid ambiguity of branch/directory names for the git-diff-tree command (#8070) + * Add change title notification for issues (#8064) + * Run CORS handler first for /api routes (#7967) (#8053) + * Evaluate emojis in commit messages in list view (#8044) + * Fix failed to synchronize tags to releases for repository (#7990) (#7994) + * Fix adding default Telegram webhook (#7972) (#7992) + * Abort synchronization from LDAP source if there is some error (#7965) + * Fix deformed emoji in commit message (#8071) +* ENHANCEMENTS + * Keep blame view buttons sequence consistent with normal view when viewing a file (#8007) (#8009) + +## [1.9.2](https://github.com/go-gitea/gitea/releases/tag/v1.9.2) - 2019-08-22 + +* BUGFIXES + * Fix wrong sender when send slack webhook (#7918) (#7924) + * Upload support text/plain; charset=utf8 (#7899) + * Lfs/lock: round locked_at timestamp to second (#7872) (#7875) + * Fix non existent milestone with 500 error (#7867) (#7873) +* SECURITY + * Fix No PGP signature on 1.9.1 tag (#7874) + * Release built with go 1.12.9 to fix security fixes in golang std lib, ref: https://groups.google.com/forum/#!msg/golang-announce/oeMaeUnkvVE/a49yvTLqAAAJ +* ENHANCEMENTS + * Fix pull creation with empty changes (#7920) (#7926) +* BUILD + * Drone/docker: prepare multi-arch release + provide arm64 image (#7571) (#7884) + +## [1.9.1](https://github.com/go-gitea/gitea/releases/tag/v1.9.1) - 2019-08-14 + +* BREAKING + * Add pagination for admin api get orgs and fix only list public orgs bug (#7742) (#7752) +* SECURITY + * Be more strict with git arguments (#7715) (#7762) + * Release built with go 1.12.8 to fix security fixes in golang std lib, ref: https://groups.google.com/forum/#!topic/golang-nuts/fCQWxqxP8aA +* BUGFIXES + * Fix local runs of ssh-requiring integration tests (#7855) (#7857) + * Fix hook problem (#7856) (#7754) + * Use .ExpiredUnix.IsZero to display green color of forever valid gpg key (#7850) (#7846) + * Do not fetch all refs (#7797) (#7837) + * Fix duplicate call of webhook (#7824) (#7821) + * Enable switching to a different source branch when PR already exists (#7823) + * Rewrite existing repo units if setting is not included in api body (#7811) + * Prevent Commit Status and Message From Overflowing On Branch Page (#7800) (#7808) + * API: fix multiple bugs with statuses endpoints (Backport #7785) (#7807) + * Fix Slack webhook fork message (1.9 release backport) (#7783) + * Fix approvals counting (#7757) (#7777) + * Fix rename failed when rewrite public keys (#7761) (#7769) + * Fix dropTableColumns sqlite implementation (#7710) (#7765) + * Fix repo_index_status lingering when deleting a repository (#7738) + * Fix milestone completness calculation when migrating (#7725) (#7732) + * Fixes indexed repos keeping outdated indexes when files grow too large (#7731) + * Skip non-regular files (e.g. submodules) on repo indexing (#7717) + * Improve branches list performance and fix protected branch icon when no-login (#7695) (#7704) + * Correct wrong datetime format for git (#7689) (#7690) + +## [1.9.0](https://github.com/go-gitea/gitea/releases/tag/v1.9.0) - 2019-07-30 + +* BREAKING + * Better logging (#6038) (#6095) +* SECURITY + * Shadow the password on cache and session config on admin panel (#7300) + * Fix markdown invoke sequence (#7513) (#7560) + * Reserve .well-known username (#7638) + * Do not leak secrets via timing side channel (#7364) + * Ensure that decryption of cookie actually succeeds (#7363) +* FEATURES + * Content API for Creating, Updating, Deleting Files (#6314) + * Enable tls-alpn-01: Use certmanager provided TLSConfig for LetsEncrypt (#7229) + * Add command to convert mysql database from utf8 to utf8mb4 (#7144) + * Fixes #2738 - Adds the /git/tags API endpoint (#7138) + * Compare branches, commits and tags with each other (#6991) + * Show Pull Request button or status of latest PR in branch list (#6990) + * Repository avatars (#6986) + * Show git-notes (#6984) + * Add commit statuses reports on pull request view (#6845) + * Number of commits ahead/behind in branch overview (#6695) + * Add CLI commands to manage LDAP authentication source (#6681) + * Add support for MS Teams webhooks (#6632) + * OAuth2 Grant UI (#6625) + * Add SUBJECT_PREFIX mailer config option (#6605) + * Include custom configuration file in dump (#6516) + * Add API for manipulating Git hooks (#6436) + * Improve migrations to support migrating milestones/labels/issues/comments/pullrequests (#6290) + * Add option to blame files (#5721) + * Implement Default Webhooks (#4299) + * Telegram webhook (#4227) +* BUGFIXES + * Send webhook after commit when creating issue with assignees (#7681) (#7684) + * Upgrade macaron/captcha to fix random error problem (#7407) (#7683) + * Move add to hook queue for created repo to outside xorm session. (#7682) (#7675) + * Show protection symbol if needed on default branch (#7660) (#7668) + * Hide delete/restore button on archived repos (#7660) + * Fix bug on migrating milestone from github (#7665) (#7666) + * Use flex to fix floating paginate (#7656) (#7662) + * Change length of some repository's columns (#7652) (#7655) + * Fix wrong email when use gitea as OAuth2 provider (#7640) (#7647) + * Fix syntax highlight initialization (#7617) (#7626) + * Fix bug create/edit wiki pages when code master branch protected (#7580) (#7623) + * Fix panic on push at #7611 (#7615) (#7618) + * Handle ErrUserProhibitLogin in http git (#7586, #7591) (#7590) + * Fix color of split-diff view in dark theme (#7587) (#7589) + * Fix file header overflow in file and blame views (#7562) (#7579) + * Malformed URLs in API git/commits response (#7565) (#7567) + * Fix empty commits now showing in repo overview (#7521) (#7563) + * Fix repository's pull request count error (#7518) (#7524) + * Remove duplicated webhook trigger (#7511) (#7516) + * Handles all redirects for Web UI File CRUD (#7478) (#7507) + * Fix regex for issues in commit messages (#7444) (#7466) + * cmd/serv: actually exit after fatal errors (#7458) (#7460) + * Fix an issue with some pages throwing 'not defined' js exceptions #7450 (#7453) + * Fix Dropzone.js integration (#7445) (#7448) + * Create class for inline positioned lists (#7439) (#7393) + * Diff: Fix indentation on unhighlighted code (#7435) (#7443) + * jQuery 3 (#7442) (#7425) + * Only show "New Pull Request" button if repo allows pulls (#7426) (#7432) + * Fix vendor references (#7394) (#7396) + * Only return head: null if source branch was deleted (#6705) (#7376) + * Add missing template variable on organisation settings (#7386) (#7385) + * Fix post parameter on issue list which had unset assignee (#7380) (#7383) + * Fix migration tests due to issue 7 being resolved (#7375) (#7381) + * Correctly adjust mirror url (#6593) + * Handle early git version's lack of get-url (#7065) + * Fix icon position in issue view (#7354) + * Cut timeline length with last element on issue view (#7355) + * Fix mirror repository webhooks (#7366) + * Fix api route for hooks (#7346) + * Fix bug conflict between SyncReleasesWithTags and InsertReleases (#7337) + * Fix pull view ui merge section (#7335) + * Fix 7303 - remove unnessesary buttons on archived repos (#7326) + * Fix topic bar to allow prefixes (#7325) + * Fixes #7152 - Allow create/update/delete message to be empty, use default message (#7324) + * Fixes #7238 - Annotated tag commit ID incorrect (#7321) + * Dark theme fixes (#7319) + * Gitea own dark codemirror theme (#7317) + * Fixes #7292 - API File Contents bug (#7301) + * Fix API link header (#7298) + * Fix extra newlines when copying from diff in Firefox (#7288) + * Make diff line-marker non-selectable (#7279) + * Fix Submodule dection in subdir (#7275) + * Fix error log when loading issues caused by a xorm bug (#7271) + * Add .fa icon margin like .octicon (#7258) + * Fix hljs unintenionally highlighting commit links (#7244) + * Only check and config git on web subcommand but not others (#7236) + * Fix migration panic when Head.User is not exist (#7226) + * Only warn on errors in deleting LFS orphaned files during repo deletion (#7213) + * Fix duplicated file on pull request conflicted files (#7211) + * Allow colon between fixing word and issue (#7207) + * Fix overflow issues in repo (#7190) + * API error cleanup (#7186) + * Add error for fork already existing (#7185) + * Fixes diff on merged pull requests (#7171) + * If milestone id is zero don't get it from database (#7169) + * Fix pusher name via ssh push (#7167) + * Fix database lock when use random repository fallback image (#7166) + * Various fixes for issue mail notifications (#7165) + * Allow archived repos to be (un)starred and (un)watched (#7163) + * Fix GCArgs load from ini (#7156) + * Detect noreply email address as user (#7133) + * Avoid arbitrary format strings upon calling fail() function (#7112) + * Validate External Tracker URL Format (#7089) + * Repository avatar fallback configuration (#7087) + * Fix #732: Add LFS objects to base repository on merging (#7082) + * Install page - Handle invalid administrator username better (#7060) + * Workaround for posting single comments in split diff view (#7052) + * Fix possbile mysql invalid connnection error (#7051) + * Fix charset was not saved after installation finished (#7048) + * Handle insecure and ports in go get (#7041) + * Avoid bad database state after failed migration (#7040) + * Fix wrong init dependency on markup extensions (#7038) + * Fix default for allowing new organization creation for new users (#7017) + * Fix content download and /verify LFS handler expecting wrong content-type (#7015) + * Fix missing repo description when migrating (#7000) + * Fix LFS Locks over SSH (#6999) + * Do not attempt to return blob on submodule (#6996) + * Fix U2F for Chrome >= 74 (#6980) + * Fix index produces problem when issues/pulls deleted (#6973) + * Allow collaborators to view repo owned by private org (#6965) + * Stop running hooks on pr merge (#6963) + * Run hooks on merge/edit and cope with protected branches (#6961) + * Webhook Logs show proper HTTP Method, and allow change HTTP method in form (#6953) + * Stop colorizing log files by default (#6949) + * Rotate serv.log, http.log and hook logs and stop stacktracing in these (#6935) + * Fix plain text overflow line wrap (#6915) + * Fix input size for dependency select (#6913) + * Change drone token name to let users know to use oauth2 (#6912) + * Fix syntax highlight in blame view #6895 (#6909) + * Use AppURL for Oauth user link (#6894) + * Fixes #6881 - API users search fix (#6882) + * Fix 404 when send pull request some situation (#6871) + * Enforce osusergo build tag for releases (#6862) + * Fix 500 when reviewer is deleted with integration tests (#6856) + * Fix v85.go (#6851) + * Make dropTableColumns drop columns on sqlite and constraints on all (#6849) + * Fix double-generation of scratch token (#6832) (#6833) + * When mirroring we should set the remote to mirror (#6824) + * Fix the v78 migration "Drop is_bare" on MSSQL #6707 (#6823) + * Change verbose flag in dump command to avoid colliding with global version flag (#6822) + * Fix #6813: Allow git.GetTree to take both commit and tree names (#6816) + * Remove `seen` map from `getLastCommitForPaths` (#6807) + * Show scrollbar only when needed (#6802) + * Restore IsWindows variable assignment (#6722) (#6790) + * Service worker js is a missing comma (#6788) + * Fix team edit API panic (#6780) + * Set user search base field optional in LDAP (simple auth) edit page (#6779) + * Ignore already existing public keys after ldap sync (#6766) + * Fix pulls broken when fork repository deleted (#6754) + * Fix missing return (#6751) + * Fix new team 500 (#6749) + * OAuth2 token can be used in basic auth (#6747) + * Fix org visibility bug when git cloning (#6743) + * Fix bug when sort repos on org home page login with non-admin (#6741) + * Stricter domain name pattern in email regex (#6739) + * Fix admin template error (#6737) + * Drop is_bare IDX only when it exists for MySQL and MariaDB (#6736) + * UI: Detect and restore encoding and BOM in content (#6727) + * Load issue attributes when editing an issue with API (#6723) + * Fix team members API (#6714) + * Unfortunately MemProvider Init does not actually Init properly (#6692) + * Fix partial reversion of #6657 caused by #6314 (#6685) + * Prevent creating empty sessions (#6677) + * Fixes #6659 - Swagger schemes selection default to page's protocol (#6660) + * Update highlight.js to 9.15.6 (#6658) + * Properly escape on the redirect from the web editor (#6657) + * Fix #6655 - Don't EscapePound .Link as it is already escaped (#6656) + * Use ctx.metas for SHA hash links (#6645) + * Fix wrong GPG expire date (#6643) + * upgrade version of lib/pq to v1.1.0 (#6640) + * Fix forking an empty repository (#6637) + * Fix issuer of OTP URI should be URI-encoded. (#6634) + * Return a UserList from /api/v1/admin/users (#6629) + * Add json tags for oauth2 form (#6627) + * Remove extra slash from twitter card (#6619) + * remove bash requirement in makefile (#6617) + * Fix Open Graph og:image link (#6612) + * Fix cross-compile builds (#6609) + * Change commit summary to full message in API (#6591) + * Fix bug user search API pagesize didn't obey ExplorePagingNum (#6579) + * Prevent server 500 on compare branches with no common history (#6555) + * Properly escape release attachment URL (#6512) + * Delete local branch when repo branch is deleted (#6497) + * Fix bug when user login and want to resend register confirmation email (#6482) + * Fix upload attachments (#6481) + * Avoid multi-clicks in oauth2 login (#6467) + * Hacky fix for alignment of the create-organization dialog (#6455) + * Change order that PostProcess Processors are run (#6445) + * Clean up ref name rules (#6437) + * Fix Hook & HookList in Swagger (#6432) + * Fixed unitTypeCode not being used in accessLevelUnit (#6419) + * Display correct error for invalid mirror interval (#6414) + * Don't Unescape redirect_to cookie value (#6399) + * Fix dump table name error and add some test for dump database (#6394) + * Fix migrations 82 to ignore unsynced tags between database and git data and missing is_archived on repository table (#6387) + * Make sure units of a team are returned (#6379) + * Fix bug manifest.json will not request with cookie so that session will created every request (#6372) + * Disable benchmarking during tag events on DroneIO (#6365) + * Comments list performance optimization (#5305) +* ENHANCEMENTS + * Update Drone docker generation to standard format (#7480) (#7496) (#7504) + * Add API Endpoint for Repo Edit (#7006) + * Add state param to milestone listing API (#7131) + * Make captcha and password optional for external accounts (#6606) + * Detect migrating batch size (#7353) + * Fix 7255 - wrap long texts on user profile info (#7333) + * Use commit graph files for listing pages (#7314) + * Add git command line commitgraph support global default true when git version >= 2.18 (#7313) + * Add LFS_START_SERVER option to control git-lfs support (#7281) + * Dark theme markdown fixes (#7260) + * Update go-git to v4.12.0 (#7249) + * Show lfs config on admin panel (#7220) + * Disable same user check for internal SSH (#7215) + * Add LastLogin to the User API (#7196) + * Add missing description of label on API (#7159) + * Use go method to calculate ssh key fingerprint (#7128) + * Enable Rust highlighting (#7125) + * Refactor submodule URL parsing (#7100) + * Change issue mail title. (#7064) + * Use batch insert on migrating repository to make the process faster (#7050) + * Improve github downloader on migrations (#7049) + * When git version >= 2.18, git command could run with git wire protocol version 2 param if enabled (#7047) + * Fix Erlang and Elixir highlight mappings (#7044) + * API Org Visibility (#7028) + * Improve handling of non-square avatars (#7025) + * Bugfix: Align comment label and actions to the right (#7024) + * Change UpdateRepoIndex api to include watchers (#7012) + * Move serv hook functionality & drop GitLogger (#6993) + * Add support of utf8mb4 for mysql (#6992) + * Make webhook http connections reusable (#6976) + * Move xorm logger bridge from log to models so that log module could be a standalone package (#6944) + * Refactor models.NewRepoContext to extract git related codes to modules/git (#6941) + * Remove macaron dependent on models (#6940) + * Add less linter via npx (#6936) + * Remove macaron dependent on modules/log (#6933) + * Remove macaron dependent on models/mail.go (#6931) + * Clean less files (#6921) + * Fix code overflow (#6914) + * Style orgs list in user profile (#6911) + * Improve description of branch protection (fix #6886) (#6906) + * Move sdk structs to modules/structs (#6905) + * update sdk to latest (#6903) + * Escape the commit message on issues update and title in telegram hook (#6901) + * SearchRepositoryByName improvements and unification (#6897) + * Change the color of issues/pulls list, merged is purple and closed is red (#6874) + * Refactor table width to have more info shown in file list (#6867) + * Monitor all git commands; move blame to git package and replace git as a variable (#6864) + * Fix config ui error about cache ttl (#6861) + * Improve localization of git activity stats (#6848) + * Generate access token in admin cli (#6847) + * Update github.com/urfave/cli to version 1.2.0 (#6838) + * Rename LFS_JWT_SECRET cli option to include OAUTH2 as well (#6826) + * internal/ssh: ignore env command totally (#6825) + * Allow Recaptcha service url to be configured (#6820) + * update github.com/mcuadros/go-version to v0.0.0-20190308113854-92cdf37c5b75 (#6815) + * Use modules/git for git commands (#6775) + * Add GET requests to webhook (#6771) + * Move PushUpdate dependency from models to repofiles (#6763) + * Tweak tab text and icon colors (#6760) + * Ignore non-standard refs in git push (#6758) + * Disable web preview for telegram webhook (#6719) + * Show full name if DEFAULT_SHOW_FULL_NAME setting enabled (#6710) + * Reorder file actions (#6706) + * README WordPress the code is overflowing #6679 (#6696) + * Improve issue reference on commit (#6694) + * Handle redirects for git clone commands (#6688) + * Fix one performance/correctness regression in #6478 found on Rails repository. (#6686) + * API OTP Context (#6674) + * Remove local clones & make hooks run on merge/edit/upload (#6672) + * Bump github.com/stretchr/testify from 1.2.2 to 1.3.0 (#6663) + * Bump gopkg.in/src-d/go-git.v4 from 4.8.0 to 4.10.0 (#6662) + * Fix dropdown icon padding (#6651) + * Add more title attributes on shortened names (#6647) + * Update UI for topics labels on projects (#6639) + * Trace Logging on Permission Denied & ColorFormat (#6618) + * Add .gpg url (match github behaviour) (#6610) + * Support for custom GITEA_CUSTOM env var in docker(#6608) + * Show "delete branch" button on closed pull requests (#6570) (#6601) + * Add option to disable refresh token invalidation (#6584) + * Fix new repo dropdown alignment (#6583) + * Fix mail notification when close/reopen issue (#6581) + * Pre-calculate the absolute path of git (#6575) + * Minor CSS cleanup for the navbar (#6553) + * Render SHA1 links as code blocks (#6546) + * Add username flag in create-user command (#6534) + * Unifies pagination template usage (#6531) (#6533) + * Fixes pagination width on mobile view (#5711) (#6532) + * Improve SHA1 link detection (#6526) + * Fixes #6446 - Sort team members and team's repositories (#6525) + * Use stricter boundaries for auto-link detection (#6522) + * Use regular line-height on frontpage entries (#6518) + * Fixes #6514 - New Pull Request on files and pulls pages the same (#6515) + * Make distinction between DisplayName and Username in email templates (#6495) + * Add X-Auto-Response-Suppress header to outgoing messages (#6492) + * Cleaned permission checks for API -> site admin can now do anything (#6483) + * Support search operators for commits search (#6479) + * Improve listing performance by using go-git (#6478) + * Fix repo sub_menu font color in arc-green (#6477) + * Show last commit status in pull request lists (#6465) + * Add signatures to webhooks (#6428) + * Optimize all images in public/img (#6427) + * Add golangci (#6418) + * Make "Ghost" not link to 404 page (#6410) + * Include more variables on admin/config page (#6378) + * Markdown: enable some more extensions (#6362) + * Include repo name in page title tag (#6343) + * Show locale string on timestamp (#6324) + * Handle CORS requests (#6289) + * Improve issue autolinks (#6273) + * Migration Tweaks (#6260) + * Add title attributes to all items in the repo list viewer (#6258) + * Issue indexer queue redis support (#6218) + * Add bio field for user (#6113) + * Make the version within makefile overwriteable (#6080) + * Updates to API 404 responses (#6077) + * Use Go1.11 module (#5743) + * UX + Security current user password reset (#5042) + * Refactor: append, build variable and type switch (#4940) + * Git statistics in Activity tab (#4724) + * Drop the bits argument when generating an ed25519 key (#6504) +* TESTING + * Exclude pull_request from fetch-tags step, fixes #7108 (#7120) + * Refactor and improve git test (#7086) + * Fix TestSearchRepo by waiting till indexing is done (#7004) + * Add mssql migration tests (needs #6823) (#6852) + * Add tests for Org API (#6731) + * Context.ServerError and NotFound should log from their caller (#6550) +* TRANSLATION + * Add french specific rule for translating plural texts (#6846) +* BUILD + * Update mssql driver to last working version 20180314172330-6a30f4e59a44 (#7306) + * Alpine 3.10 (#7256) + * Use vfsgen instead of go-bindata (#7080) + * remove and disable package-lock (#6969) + * add make targets for js and css, add js linter (#6952) + * Added tags pull step to drone config to show correct version hashes i… (#6836) + * Make CustomPath, CustomConf and AppWorkPath configurable at build (#6631) + * chore: update drone format to 1.0 (#6602) + * Fix race in integration testlogger (#6556) + * Quieter Integration Tests (#6513) + * Drop the docker Makefile from the image (#6507) + * Add make version on gitea version (#6485) + * Fix #6468 - Uses space match and adds newline for all sed flavors (#6473) + * Move code.gitea.io/git to code.gitea.io/gitea/modules/git (#6364) + * Update npm dependencies and various tweaks (#7344) + * Fix updated drone file (#7336) + * Add 'npm' and 'npm-update' make targets and lockfile (#7246) +* DOCS + * Add work path CLI option (#6922) + * Fix logging documentation (#6904) + * Some logging documentation (#6498) + * Fix link to Hacking on Gitea on From-Source doc page (#6471) + * Fix typos in docs command-line examples (#6466) + * Added docker example for backup (#5846) + +## [1.8.3](https://github.com/go-gitea/gitea/releases/tag/v1.8.3) - 2019-06-17 + +* BUGFIXES + * Always set userID on LFS authentication (#7224) (Part of #6993) + * Fix LFS Locks over SSH (#6999) (#7223) + * Fix duplicated file on pull request conflicted files (#7211) (#7214) + * Detect noreply email address as user (#7133) (#7195) + * Don't get milestone from DB if ID is zero (#7169) (#7174) + * Allow archived repos to be (un)starred and (un)watched (#7163) (#7168) + * Fix GCArgs load from ini (#7156) (#7157) + +## [1.8.2](https://github.com/go-gitea/gitea/releases/tag/v1.8.2) - 2019-05-29 + +* BUGFIXES + * Fix possbile mysql invalid connnection error (#7051) (#7071) + * Handle invalid administrator username on install page (#7060) (#7063) + * Disable arm7 builds (#7037) (#7042) + * Fix default for allowing new organization creation for new users (#7017) (#7034) + * SearchRepositoryByName improvements and unification (#6897) (#7002) + * Fix u2f registrationlist ToRegistrations() method (#6980) (#6982) + * Allow collaborators to view repo owned by private org (#6965) (#6968) + * Use AppURL for Oauth user link (#6894) (#6925) + * Escape the commit message on issues update (#6901) (#6902) + * Fix regression for API users search (#6882) (#6885) + * Handle early git version's lack of get-url (#7065) (#7076) + * Fix wrong init dependency on markup extensions (#7038) (#7074) + +## [1.8.1](https://github.com/go-gitea/gitea/releases/tag/v1.8.1) - 2019-05-08 + +* BUGFIXES + * Fix 404 when sending pull requests in some situations (#6871) (#6873) + * Enforce osusergo build tag for releases (#6862) (#6869) + * Don't post process commit summary in templates (#6842) (#6868) + * Fix 500 when reviewer is deleted (#6856) (#6860) + * Fix v78 migration for MSSQL (#6823) (#6854) + * Added tags pull step to drone config to show correct version hashes (#6836) (#6839) + * Fix double-generation of scratch token (#6833) (#6835) + * When mirroring we should set the remote to mirror (#6824) (#6834) + * Show scrollbar only when needed (#6802) (#6803) + * Service worker js is missing a comma (#6788) (#6795) + * Set user search base field optional in LDAP (simple auth) edit page (#6779) (#6789) + * Fix team edit API panic (#6780) (#6785) + * Minor CSS cleanup for the navbar (#6553) (#6781) + * Stricter domain name pattern in email regex (#6739) (#6768) + * Detect and restore encoding and BOM in content (#6727) (#6765) + * Fix org visibility bug when git cloning (#6743) (#6762) + * OAuth2 token can be used in basic auth (#6747) (#6761) + * Fix missing return (#6751) (#6756) + * Fix sorting repos on org home page with non-admin login (#6741) (#6746) + * Drop is_bare IDX only when it exists for MySQL and MariaDB (#6736) (#6744) + * Fix team members API (#6714) (#6729) + * Load issue attributes when editing an issue with API (#6723) (#6725) + * Fix config ui error about cache ttl (#6861) (#6865) + +## [1.8.0](https://github.com/go-gitea/gitea/releases/tag/v1.8.0) - 2019-04-20 + +* SECURITY + * Prevent remote code execution vulnerability with mirror repo URL settings (#6593) (#6594) + * Resolve 2FA bypass on API (#6676) (#6674) + * Prevent the creation of empty sessions for non-logged in users (#6690) (#6677) +* BREAKING + * Add "ghost" and "notifications" to list of reserved user names. (#6208) + * Change sqlite DB path default to data directory (#6198) + * Adds MustChangePassword to user create/edit API (#6193) + * Disable redirect for i18n (#5910) + * Releases API paging (#5831) + * Allow Macaron to be set to log through to gitea.log (#5667) + * Don't close issues via commits on non-default branch (#5622) +* FEATURES + * Add regenerate secret feature for oauth2 (#6291) + * Expose issue stopwatch toggling via API (#5970) + * Add other session providers (#5963) + * Pull request conflict files detection (#5951) + * Integrate OAuth2 Provider (#5378) + * Implement "conversation lock" for issue comments (#5073) + * Feature: Archive repos (#5009) + * Discord Oauth2 support (#4476) + * Allow to set organization visibility (public, internal, private) (#1763) + * Added URL mapping for Release attachments like on github.com (#1707) +* ENHANCEMENTS + * Add support for client basic auth for exchanging access tokens (#6293) + * Add ability to sort issues by due date (#6206) (#6244) + * Style tweaks to issue selection (#6196) + * Increase Username and Orgname MaxSize 35 -> 40 (#6178) + * Coverage profile with multiple packages (#6167) + * Split setting.go to multiple files (#6154) + * Allow labels to contain emoji (#6063) + * Disable git fsck for mirrored repos by default (#6018) + * Add default time out for git operations (#6015) + * Split setting.go as multiple files (#6014) + * Make dashboard navbar and footer full-width (#6013) + * Add lang specific font stacks for CJK (#6007) + * Fix header menu misalignment (#6002) + * Enhance closed PR and Issue status in the list (#6000) + * Make navbar full width (#5998) + * Add option to close issues via commit on a non master branch (#5992) + * Support n as a line highlight prefix (#5987) + * Search for org repos (#3031) (#5986) + * Minor UI tweaks (#5980) + * Use native golang SSH library but ssh-keygen when enable built-in SSH server to remove dependent on that command lines (#5976) + * Dashboard tweaks (#5974) + * Fixes for repo topic editor (#5971) + * Display the branch name in the commit view (#5950) + * handle milestone events for issues and PR (#5947) + * Add label names as filter in issue search api (#5946) + * Repo header tweaks (#5945) + * Better support for long repo names (#5932) + * Fix wrapping long code lines (#5927) + * Change GPG Validation colors and remove inline CSS (#5404) (#5896) + * Fix "pulls.blocked_by_approvals" text (#5879) + * Rename reject to 'request changes' (#5858) + * Move input fields to add members to a team and repos to a team (#5853) + * Config option to disable automatic repo watching (#5852) + * New Issue ?body= query (#5851) + * Add API to list tags (#5850) + * Pagination for git tree API (#5838) + * Add InternalTokenURI to load InternalToken from an external file (#5812) + * Allow markdown files to read from the LFS (#5787) + * Add the ability to use multiple labels as filters (#5786) + * Adjust log settings when a user is not found. (#5771) + * Log IP of failed ssh connection (#5766) + * Moved defaults in defaults.go to setting.go (#5764) + * Make DB connect more robust (#5738) + * Add Default Pull Request Title (#5735) + * Refactor repo.isBare to repo.isEmpty #5629 (#5714) + * Add flag to skip repository dumping (#5695) + * Prioritize "readme.md" (#5691) + * Improve "Fork button" for guests by showing a pop up asking them to log in before forking (#5690) + * Allow for user specific themes (#5668) + * Display branch name in delete branch confirmation modal. (#5654) + * New API routes added (#5594) + * Refactor notification for indexer (#5111) + * Refactor mail notification (#5110) + * Show email if the authenticated user owns the profile page being requested for (#4981) + * Optimize pulls merging (#4921) + * Sort Repositories widget by most recently updated (#3963) (#4599) + * Allow markdown table to scroll (#4401) + * Automatically clear stopwatch on merging a PR (#4327) + * Add the Owner Name to differentiate when merging (#3807) + * Add title attributes to all items in the repo list viewer (#6258) (#6650) +* BUGFIXES + * Fix dropdown icon padding (#6651) (#6654) + * Fix wrong GPG expire date (#6643) (#6644) + * Fix forking an empty repository (#6637) (#6653) + * Remove call to EscapePound .Link as it is already escaped (#6656) (#6666) + * Properly escape on the redirect from the web editor (#6657) (#6667) + * Allow resend of confirmation email when logged in (#6482) (#6486) + * Fix mail notification when close/reopen issue (#6581) (#6588) + * Change API commit summary to full message (#6591) (#6592) + * Add option to disable refresh token invalidation (#6584) (#6587) + * Fix bug user search API pagesize didn't obey ExplorePagingNum (#6579) (#6586) + * Fix new repo alignment (#6583) (#6585) + * Prevent server 500 on compare branches with no common history (#6555) (#6558) + * Properly escape release attachment URL (#6512) (#6523) + * Hacky fix for alignment of the create-organization dialog (#6455) (#6462) + * Disable benchmarking during tag events on DroneIO (#6365) (#6366) + * Make sure units of a team are returned (#6379) (#6381) + * Don't Unescape redirect_to cookie value (#6399) (#6401) + * Fix dump table name error and add some test for dump database (#6394) (#6402) + * Fix migration v82 to ignore unsynced tags between database and git data; Add missing is_archived column on repository table (#6387) (#6403) + * Display correct error for invalid mirror interval (#6414) (#6429) + * Clean up ref name rules (#6437) (#6439) + * Fix Hook & HookList in Swagger (#6432) (#6440) + * Change order that PostProcess Processors are run (#6445) (#6447) + * Clean up various use of escape/unescape functions for URL generation (#6334) + * Return 409 when creating repo if it already exists. (#6330) + * Add same changes from issues page to milestone->issues page (#6328) + * Fix ParsePatch function to work with quoted diff --git strings (#6323) + * Fix reported issue in repo description (#6306) + * Use url.PathEscape to escape the branchname (#6304) + * Add robots.txt as reserved username (#6272) + * Replace linkRegex with xurls library (#6261) + * Remove visitLinksForShortLinks features (#6257) + * Add unit types to repo action URL to correctly show 404 when archived (#6247) + * Check organization visibility before everything else (#6234) (#6235) + * Prevent double-close of issues (#6233) + * Override xorm type mapping for U2F counter (#6232) + * Add isAdmin to user API response (#6231) + * Update git vendor to fix wrong release commit id and add migrations (#6224) + * Fix fork button (#6223) + * Fix renames over redirects (#6216) + * Fix display dashboard even if require to change password (#6214) + * Create a repo redirect when transferring ownership (#6210) (#6211) + * Fix issue update race condition (#6194) + * Fix bug when migrate repository 500 when repo is existed (#6188) + * Fix scrollbar always present on page body (#6177) + * Fix bug when set indexer as db and add tests (#6173) + * Modify linkRegex to require http|https (#6171) + * Fix bug user could change private repository to public when force private enabled. (#6156) + * Fix admin list user/org API (#6143) + * Make repo creation for API similar to UI (#6142) + * Make document body a flexbox (#6139) + * Refactor issue indexer, add some testing and fix a bug (#6131) + * Load Issue attributes for API call (#6122) + * Fix bug when update owner team then visit team's repo return 404 (#6119) + * Fix heatmap and repository menu display in Internet Explorer 9+ (#6117) + * Show private organization for admin, fix #6111 (#6112) + * Fix prohibit login check on authorization (#6106) + * Move to ldap.v3 to fix #5928 (#6105) + * Remove use MakeAssigneeList in webhooks to fix deadlock (#6102) + * Allow display of LFS stored Readme.md on directory page (#6073) (#6099) + * Make sure labels are actually returned (#6053) + * Fix panic: template: repo/issue/list:210: unexpected "=" in operand (#6041) + * After deleting a repo on admin panel, UI should remember the last sort type (#6033) + * Default create repository on organisation on its dashboard (#6026) + * Swagger: Remove spaces in MergePullRequestOption enum (#6016) + * Fix metrics auth token detection (#6006) + * Fix repo header issues (#5995) + * Fix bug when deleting a linked account will removed all (#5989) + * Make organization dropdown scrollable when using mouse wheel (#5988) + * Fix empty ssh key importing in ldap (#5984) + * Admin config page mailertype setting option update (#5973) + * Fix redirect loop during forced password change (#5965) + * Show user who created the repository instead of the organisation in action feed (#5948) + * Remove all CommitStatus when a repo is deleted (#5940) + * Fix ssh deploy and user key constraints (#1357) (#5939) + * Fix log output (#5938) + * Set PusherName and PusherID to owner on deploy key to fix pushing with deploy keys (#5935) + * Fix compare button (#5929) + * Fix bug when read public repo lfs file (#5912) + * Only allow local login if password is non-empty (#5906) + * Recover panic in orgmode.Render if bad orgfile (#4982) (#5903) + * Provide better panic handling (#5902) + * Respect value of REQUIRE_SIGNIN_VIEW (#5901) + * Show a 404 not a 500 if a repo does not exist (#5900) + * Ensure repo is loaded in mailer (Completely fix #5891) (#5895) + * Ensure issue.Poster is loaded in mailIssueCommentToParticipants (#5891) + * Correct footer height if screen-width is to small (fixes #5878) (#5889) + * In gitea serv switch off console logger to fix #5866 (#5887) + * Don't allow pull requests to be created on an archived repository (#5883) + * Support reviews on a deleted file path (#5880) + * Fix compare button on upstream repo leading to 404 (#5877) + * Fix null pointer on not logged in attempt to Sudo (#5872) + * Fix new release creation API to allow empty target (#5870) + * Fix an error while adding a dependency via UI. (#5862) + * Fix failing migration v67 (#5849) + * Fix delete correct temp directory (#5839) + * Make sure .git/info is created before generating .git/info/sparse-che… (#5825) + * Fix topics saving internal error and disable for archived repos (#5821) + * Fix TLS errors when using acme/autocert for local connections (#5820) + * When creating new repository fsck option should be enabled (#5817) + * Request for public keys only if LDAP attribute is set (#5816) + * Fix serving of raw wiki files other than .md (#5814) + * Fix migration 78 error mssql (#5791) + * Disallow empty titles (#5785) + * Fix the v78 migration script (#5776) + * Ensure valid git author names passed in signatures (#5774) + * Fix wrong assumption where a user is always said to have unassigned (her)himself (#5769) + * Upgrade go-sql-driver/mysql to fix invalid connection error (#5748) + * Fixing PostgreSQL dump creation (#5747) + * Add proper CORS preflight origin validation (#5740) + * Disable auto-migrate in docker container (#5730) + * In basic auth check for tokens before call UserSignIn (#5725) + * Pooled and buffered gzip implementation (#5722) + * Ensure that sessions are passed into queries that could use the database to prevent deadlocks (#5718) + * Keep file permissions during database migration (#5707) + * Use correct value for "MSpan Structures Obtained" #4742 (#5706) + * Refactor editor upload, update and delete to use git plumbing and add LFS support (#5702) + * Update xorm to fix issue #5659 and #5651 (#5680) + * Fix public will not be reused as public key after deleting as deploy key (#5671) + * When redirecting, clean the path (#5669) + * Don't list an issue on its own dependency list UI. (#5658) + * Fix commit page showing status for current default branch (#5649) (#5650) + * Only count users own actions for heatmap contributions (#5647) + * Fix sqlite deadlock when assigning to a PR (#5640) + * Refactor issue indexer (#5363) +* TESTING + * Run benchmark at tag to track performances (#6035) + * Add test environment for MySQL8 (#5234) +* BUILD + * Use go 1.12 for tests and deprecate go 1.9 (#6186) + * Makefile changes for Windows and easier development (#6103) + * Update bleve dependency to latest master revision (#6100) + * Switch to more recent build of xgo (#6070) + * Add autoprefixer to css build (#6029) + * Update the version of less (#6010) + * Make log mailer for testing (#5893) +* DOCS + * Add more tests and docs for issue indexer, add db indexer type for searching from database (#6144) + * update default value of `--must-change-password` cli flag (#6032) + * Update and expand information about building Gitea (#6019) + * Update U2F Section of app.ini.sample (#5994) + * Update swagger for release API pagination (#5841) + * Added docs for the tree api (#5834) +* MISC + * Add single commit API support (#5843) + * Add missing GET teams endpoints (#5382) + * Migrate database if app.ini found (#5290) + +## [1.7.6](https://github.com/go-gitea/gitea/releases/tag/v1.7.6) - 2019-04-12 + +* SECURITY + * Prevent remote code execution vulnerability with mirror repo URL settings (#6593) (#6595) +* BUGFIXES + * Allow resend of confirmation email when logged in (#6482) (#6487) + +## [1.7.5](https://github.com/go-gitea/gitea/releases/tag/v1.7.5) - 2019-03-27 + +* BUGFIXES + * Fix unitTypeCode not being used in accessLevelUnit (#6419) (#6423) + * Fix bug where manifest.json was being requested without cookies and continuously creating new sessions (#6372) (#6383) + * Fix ParsePatch function to work with quoted diff --git strings (#6323) (#6332) + +## [1.7.4](https://github.com/go-gitea/gitea/releases/tag/v1.7.4) - 2019-03-12 + +* SECURITY + * Fix potential XSS vulnerability in repository description. (#6306) (#6308) +* BUGFIXES + * Fix wrong release commit id (#6224) (#6300) + * Fix panic on empty signed commits (#6292) (#6300) + * Fix organization dropdown not being scrollable when using mouse wheel (#5988) (#6246) + * Fix displaying dashboard even if required to change password (#6214) (#6215) + +## [1.7.3](https://github.com/go-gitea/gitea/releases/tag/v1.7.3) - 2019-02-27 + +* BUGFIXES + * Fix server 500 when trying to migrate to an already existing repository (#6188) (#6197) + * Load Issue attributes for API /repos/{owner}/{repo}/issues/{index} (#6122) (#6185) + * Fix bug whereby user could change private repository to public when force private enabled. (#6156) (#6165) + * Fix bug when update owner team then visit team's repo return 404 (#6119) (#6166) + * Fix heatmap and repository menu display in Internet Explorer 9+ (#6117) (#6137) + * Fix prohibit login check on authorization (#6106) (#6115) + * Fix LDAP protocol error regression by moving to ldap.v3 (#6105) (#6107) + * Fix deadlock in webhook PullRequest (#6102) (#6104) + * Fix redirect loop when password change is required and Gitea is installed as a suburl (#5965) (#6101) + * Fix compare button regression (#5929) (#6098) + * Recover panic in orgmode.Render if bad orgfile (#4982) (#5903) (#6097) + +## [1.7.2](https://github.com/go-gitea/gitea/releases/tag/v1.7.2) - 2019-02-14 + +* BUGFIXES + * Remove all CommitStatus when a repo is deleted (#5940) (#5941) + * Fix notifications on pushing with deploy keys by setting hook environment variables (#5935) (#5944) + * Silence console logger in gitea serv (#5887) (#5943) + * Handle milestone webhook events for issues and PR (#5947) (#5955) + * Show user who created the repository instead of the organization in action feed (#5948) (#5956) + * Fix ssh deploy and user key constraints (#1357) (#5939) (#5966) + * Fix bug when deleting a linked account will removed all (#5989) (#5990) + * Fix empty ssh key importing in ldap (#5984) (#6009) + * Fix metrics auth token detection (#6006) (#6017) + * Create repository on organisation by default on its dashboard (#6026) (#6048) + * Make sure labels are actually returned in API (#6053) (#6059) + * Switch to more recent build of xgo (#6070) (#6072) + * In basic auth check for tokens before call UserSignIn (#5725) (#6083) + +## [1.7.1](https://github.com/go-gitea/gitea/releases/tag/v1.7.1) - 2019-01-31 + +* SECURITY + * Disable redirect for i18n (#5910) (#5916) + * Only allow local login if password is non-empty (#5906) (#5908) + * Fix go-get URL generation (#5905) (#5907) +* BUGFIXES + * Fix TLS errors when using acme/autocert for local connections (#5820) (#5826) + * Request for public keys only if LDAP attribute is set (#5816) (#5819) + * Fix delete correct temp directory (#5840) (#5839) + * Fix an error while adding a dependency via UI (#5862) (#5876) + * Fix null pointer in attempt to Sudo if not logged in (#5872) (#5884) + * When creating new repository fsck option should be enabled (#5817) (#5885) + * Prevent nil dereference in mailIssueCommentToParticipants (#5891) (#5895) (#5894) + * Fix bug when read public repo lfs file (#5913) (#5912) + * Respect value of REQUIRE_SIGNIN_VIEW (#5901) (#5915) + * Fix compare button on upstream repo leading to 404 (#5877) (#5914) +* DOCS + * Added docs for the tree api (#5835) +* MISC + * Include Go toolchain to --version (#5832) (#5830) + +## [1.7.0](https://github.com/go-gitea/gitea/releases/tag/v1.7.0) - 2019-01-22 + +* SECURITY + * Do not display the raw OpenID error in the UI (#5705) (#5712) + * When redirecting clean the path to avoid redirecting to external site (#5669) (#5679) + * Prevent DeleteFilePost doing arbitrary deletion (#5631) +* BREAKING + * Restrict permission check on repositories and fix some problems (#5314) + * Show only opened milestones on issues page milestone filter (#5051) +* FEATURES + * Implement git refs API for listing references (branches, tags and other) (#5354) + * Approvals at Branch Protection (#5350) + * Add raw blob endpoint to get objects by SHA ID (#5334) + * Add api for user to create org (#5268) + * Create AuthorizedKeysCommand (#5236) + * User action heatmap (#5131) + * Refactor heatmap to vue component (#5401) + * Webhook for Pull Request approval/rejection (#5027) + * Add command for migrating database (#4954) + * Search keyword by splitting provided values by , (#4939) + * Create Progressive Web App (#4730) + * Give user a link to create PR after push (#4716) + * Add rebase with merge commit merge style (#3844) (#4052) +* BUGFIXES + * Disallow empty titles (#5785) (#5794) + * Fix sqlite deadlock when assigning to a PR (#5640) (#5642) + * Don't close issues via commits on non-default branch. (#5622) (#5643) + * Fix commit page showing status for current default branch (#5650) (#5653) + * Only count users own actions for heatmap contributions (#5647) (#5655) + * Update xorm to fix issue postgresql dumping issues (#5680) (#5692) + * Use correct value for "MSpan Structures Obtained" (#5706) (#5716) + * Fix bug on modifying sshd username (#5624) + * Delete tags in mirror which are removed for original repo. (#5609) + * Fix wrong text getting saved on editing second comment on an issue. (#5608) + * Fix nil pointer when adding a due date (#5587) + * Fix type mismatch of format string (#5574) + * Fix bug on upload file name (#5571) + * Issue is not overdue when it is on the same date #5566 (#5568) + * Fix indexer reindex bug when gitea restart (#5563) + * Fix table name typo on SQL (#5562) + * Synchronize SSH keys on login with LDAP + Fix SQLite deadlock on ldap ssh key deletion (#5557) + * Fix makefile generate buildstep (#5556) + * Fix nil pointer base branch bug (#5555) + * Fix permission check on api create org (#5523) + * Fix detect force push failure on deletion of protected branches (#5522) + * Fix approvals limitation (#5521) + * Fix bug when a read perm user to edit his issue (#5516) + * Fix adding reaction fail for read permission user (#5515) + * Fixing MSSQL timestamp type (#5511) + * Fix forgot deletion of notification when delete repository (#5506) + * Fix empty wiki (#5504) + * Fix clone wiki failed via ssh (#5503) + * Fix code review on mssql (#5502) + * Fix lfs version check warning log when using ssh protocol (#5501) + * Fix topic name length on database (#5493) + * Ensure that the `closed_at` is set for closed issues (#5449) + * Admin should be able to delete repos via the API even if he is not a member of the organization (#5443) + * Word-Break the WebHook url to prevent a ui-break (#5432) + * Fix forgot removed records when deleting user (#5429) + * Fix repository deletion when there is large number of issues in it (#5426) + * Fix heatmap colors for Chrome/Safari (#5421) + * Fix password variable shadowing (#5405) + * Fix dependent issue searching when gitea is run in subpath (#5392) + * Don't force a password change for the admin user when creating an account via cli (#5391) + * API: '/orgs/:org/repos': return private repos with read access (#5383) + * Don't send assign webhooks when creating issue (#5365) + * Removing Labels via EditPullRequest API (#5348) + * Migration fixes for gogs (0.11.66) to gitea (1.6.0) #5318 (#5341) + * Fix bug when users have serval teams with different units on different repositories (#5307) + * Fix U2F if gitea is configured in subpath (#5302) + * Fix file edit change preview functionality (#5300) + * Update gitignore list (#5258) + * Fixed heatmap not working in mssql (#5248) + * Fixed wrong api request url for instances running in subfolders (#5247) + * Fix compatibility heatmap with mysql 8 (#5232) + * Fix data race on migrate repository (#5224) + * Fix sqlite and mssql lock (#5214) + * Fix sqlite lock (#5210) + * Fix: Accept web-command cli flags if web-command is committed (#5200) + * Fix: Add secret to all webhook's payload where it has been missing (#5199) + * Fix race on updatesize (#5190) + * Fix create team, update team missing units (#5188) + * Fix sqlite lock (#5184 & #5176) + * Fix showing pull request link when delete a branch (#5166) + * Fix JSON result of empty array in heatmap data array (#5154) + * Update build tags for sqlite_unlock notify (#5144) + * This commit will reduce join star, repo_topic, topic tables on repo search, so that fix extra columns problem on mssql (#5136) + * Fix deadlock when sqlite (#5118) + * Add comment replies (#5104) + * Fix home page template regression (#5102) + * Fix regex to support optional end line of old section in diff hunk (#5096) + * LDAP via simple auth separate bind user and search base (#5055) + * Fix markdown image with link (#4675) + * Fix to 3819 - Filtering issues by tags on main screen issues (#3824) +* ENHANCEMENTS + * Delete organization endpoint added (#5601) + * Update Licenses (#5558) + * Support reverse proxy providing email (#5554) + * Add git protocol v2 support via SSH on Docker image (#5520) + * Add tests for api user orgs (#5494) + * Allow link verification for services like Mastodon (#5481) + * Improve team members and repositories settings UI (#5457) + * Remove the required class from optional ssh port in installation page (#5428) + * Explicitly disable Git credential helper (#5367) + * Setting Labels via EditPullRequest API (#5347) + * Implement pasting image from clipboard for browsers that supports that (#5317) + * Milestone issues and pull requests (#5293) + * Support envs on external render commands (#5278) + * Add option to disable automatic mirror syncing. (#5242) + * Remove unused db init on commands serv, update, hooks (#5225) + * Serve audio files using HTML5 audio tag (#5221) + * Pass link prefixes to external markup parsers (#5201) + * Add AutoHead functionality. (#5186) + * Fix emojis not showing in commit messages (#5168) + * Block registration based on email domain (#5157) + * Update vendor/go-sqlite3 (#5133 & #5162) + * Update x/net lib (#5169) + * Show review summary in pull requests (#5132) + * Use type switch (#5122) + * Remove duplicated if bodies (#5121) + * Remove check for negative length (#5120) + * Make switch more clear (#5119) + * Use named const instead of a raw string (#5115) + * Fix issue where ecdsa and other key types are not synced from LDAP (#5092) (#5094) + * Refactor: err != nil check, just return error instead (#5093) + * Add notification interface and refactor UI notifications (#5085) + * Use APP_NAME on home page (#5048) + * Explicitly decide whether to use TLS in mailer's configuration (#5024) + * Generate random password (#5023) + * UX of link account (Step 1) (#5006) + * Make sure argsSet verifies string isn't empty too (#4980) + * Improve performance of dashboard (#4977) + * Keys API changes (#4960) + * Add must-change-password flag to cli for creating a user (#4955) + * Use native go method to get current user rather than environment variable (#4930) + * Make gitea serv use api/internal (#4886) + * Add support for search by uid (#4876) + * Allow to add organization members as collaborators on organization owned repositories (#4748) +* TESTING + * Kill testing processes if the test takes too long (#5174) + * Update outdated Go toolchain version for .drone.yml (#5146) + * Increase the retry limit to 20 times and the interval to 200ms (#5134) + * Retry test-fixtures loading in case of transaction rollback (#5125) + * Added test environment for mssql (#4282) +* BUILD + * Replace lint to revive (#5422) + * Update golang version in Dockerfile (#5246) +* DOCS + * Typo in routers/api/v1/org/org.go fixed. (#5598) + * Update the docs for sqlite_unlock_notify (#5145) + * CN translation of docs part (#5049) + * Kubernetes deployment file (#5046) +* MISC + * Upgrade alpine to 3.8 (#5423) + * Git-Trees API (#5403) + * Only chown directories during docker setup if necessary. Fix #4425 (#5064) + +## [1.6.4](https://github.com/go-gitea/gitea/releases/tag/v1.6.4) - 2019-01-15 + +* BUGFIX + * Fix SSH key now can be reused as public key after deleting as deploy key (#5671) (#5685) + * When redirecting clean the path to avoid redirecting to external site (#5669) (#5703) + * Fix to use correct value for "MSpan Structures Obtained" (#5706) (#5715) + +## [1.6.3](https://github.com/go-gitea/gitea/releases/tag/v1.6.3) - 2019-01-04 + +* SECURITY + * Prevent DeleteFilePost doing arbitrary deletion (#5631) +* BUGFIX + * Fix wrong text getting saved on editing second comment on an issue (#5608) + +## [1.6.2](https://github.com/go-gitea/gitea/releases/tag/v1.6.2) - 2018-12-21 + +* SECURITY + * Sanitize uploaded file names (#5571) (#5573) + * HTMLEncode user added text (#5570) (#5575) +* BUGFIXES + * Fix indexer reindex bug when gitea restart (#5563) (#5564) + * Remove a double slash in the HTTPS redirect with Let's Encrypt (#5537) (#5539) + * Fix bug when a read perm user to edit his issue (#5516) (#5534) + * Detect force push failure on deletion of protected branches (#5522) (#5531) + * Let's Encrypt handler listens on correct port for certificate validation (#5525) (#5527) + * Fix forgot deletion of notification when delete repository (#5506) (#5514) + * Fix undeleted content when deleting user (#5429) (#5509) + * Fix empty wiki (#5504) (#5508) + +## [1.6.1](https://github.com/go-gitea/gitea/releases/tag/v1.6.1) - 2018-12-08 + +* BUGFIXES + * Fix dependent issue searching when gitea is run in subpath (#5392) (#5400) + * API: '/orgs/:org/repos': return private repos with read access (#5393) + * Fix repository deletion when there is large number of issues in it (#5426) (#5434) + * Word-break the WebHook url to prevent a ui-break (#5445) + * Admin should be able to delete repos via the API even if they are not a member of the organization (#5443) (#5447) + * Ensure that the `closed_at` is set for closed (#5450) + * Fix topic name length on database (#5493) (#5495) + +## [1.6.0](https://github.com/go-gitea/gitea/releases/tag/v1.6.0) - 2018-11-22 + +* BREAKING + * Respect email privacy option in user search via API (#4512) + * Simply remove tidb and deps (#3993) + * Swagger.v1.json template (#3572) +* SECURITY + * Add CSRF checking to reqToken and add reqToken to admin API routes (#5272) (#5250) + * Improve URL validation for external wiki and external issues (#4710) + * Make cookies HttpOnly and obey COOKIE_SECURE flag (#4706) + * Don't disclose emails of all users when sending out emails (#4664) + * Check that repositories can only be migrated to own user or organizations (#4366) +* FEATURES + * Add comment replies (#5147) (#5104) + * Pull request review/approval and comment on code (#3748) + * Added dependencies for issues (#2196) (#2531) + * Add the ability to have built in themes in Gitea and provide dark theme arc-green (#4198) + * Add sudo functionality to the API (#4809) + * Add oauth providers via cli (#4591) + * Disable merging a WIP Pull request (#4529) + * Force user to change password (#4489) + * Add letsencrypt to Gitea (#4189) + * Add push webhook support for mirrored repositories (#4127) + * Add csv file render support defaultly (#4105) + * Add Recaptcha functionality to Gitea (#4044) +* ENHANCEMENTS + * Fix milestones sorted wrongly (#4987) + * Allow api to create tags for releases if they don't exist (#4890) + * Fix #4877 to follow the OpenID Connect Audiences spec (#4878) + * Enforce token on api routes [fixed critical security issue #4357] (#4840) + * Update legacy branch and tag URLs in dashboard to new format (#4812) + * Slack webhook channel name cannot be empty or just contain an hashtag (#4786) + * Add whitespace handling to PR-comparison (#4683) + * Make reverse proxy auth optional (#4643) + * MySQL TLS (#4642) + * Make sure to set PR split view when creating/previewing a pull request (#4617) + * Log user in after a successful sign up (#4615) + * Fix typo IsPullReuqestBroken -> IsPullRequestBroken (#4578) + * Allow admin toggle forcing a password change for newly created users (#4563) + * Update jQuery to v1.12.4 (#4551) + * Env var GITEA_PUSHER_EMAIL (#4516) + * Feat(repo): support search repository by topic name (#4505) + * Small improvements to dependency UI (#4503) + * Make max commits in graph configurable (#4498) + * Add valid for lfs oid (#4461) + * Add shortcut to save wiki page (#4452) + * Allow administrator to create repository for any organization (#4368) + * Fix repository last updated time update when delete a user who watched the repo (#4363) + * Switch plaintext scratch tokens to use hash instead (#4331) + * Increase default TOTP secret size to 320 bits (#4287) + * Keep preseeded database password (#4284) + * Implemented hover text showing user FullName (#4261) + * Add ability to delete a token (#4235) + * Fix typos in i18n variable names. (#4080) + * Api: repos/search: add parameters to control the sort order (#3964) + * Add missing path in the Docker app.ini template (#2181) + * Add file name and branch to page title (#4902) + * Offline use of google fonts (#4872) + * Add missing History link to directory listings v2 (#4829) + * Locale for Edit and Remove due date issue (#4802) + * Disable 'May Import Local Repository' when is disabled by setting (Is… (#4780) + * API /admin/users/{username} missing parameter (#4775) + * Display error when adding a user to a team twice (#4746) + * Remove UsePrivilegeSeparation from the Docker sshd_config, see #2876 (#4722) + * Focus title input when clicking helper link (#4696) + * Add vendor to user reserved words and format words list according alphabet (#4685) + * Add gitea/issues link to 500 page (#4654) + * Hide home button when landing page is not set to home (#4651) + * Remove link to GitHub issues in 404 template (#4639) + * Cmd/serve: pprof cpu and memory profile dumps to disk (#4560) + * Add flash message after an account has been successfully activated (#4510) + * Prevent html entity escaping on delete branch (#4471) + * Locale for button Edit on protected branch (#4442) + * Update notification icon (#4343) + * Added front-end topics validation (#4316) + * Don't display buttons if there are no system notifications (#4280) + * Issue due date api (#3890) +* BUGFIXES + * dont' send assign webhooks when creating issue (#5365) + * Fix create team, update team missing units (#5188) + * Fix file edit change preview functionality (#5300) + * *ix bug when users have serval teams with different units on different repositories (#5307) + * Fix U2F if gitea is configured in subpath (#5302) + * Fix markdown image with link (#4675) + * Remove maxlines option for file logger (#5282) + * Fix wrong api request url for instances running in subfolders (#5261) (#5247) + * Accept web-command cli flags if web-command is committed (#5245) (#5200) + * Reduce join star, repo_topic, topic tables on repo search, to resolve extra columns problem on MSSQL (#5136) (#5229) + * Fix data race on migrate repository (#5224) (#5230) + * Add secret to all webhook's payload where it has been missing (#5208) (#5199) + * Fix sqlite and MSSQL lock (#5210) (#5223) (#5214) (#5218) (#5176) (#5179) + * Fix race on updatesize (#5190) (#5215) + * Fix filtering issues by tags on main screen issues (#5219) (#3824) + * Fix SQL quoting (#5137) (#5117) + * Fix regex to support optional end line of old section in diff hunk (#5097) (#5096) + * Fix release creation via API (#5076) + * Remove links from topics in edit mode (#5026) + * Fix missing AppSubUrl in few more templates (fixup) (#5021) + * Fix missing AppSubUrl in some templates (#5020) + * Hide outdated comments in file view (#5017) + * Upgrade gopkg.in/testfixtures.v2 (#4999) + * Disable debug routes unless PPROF is enabled in configuration (#4995) + * Fix user menu item styling (#4985) + * Fix layout of the topics editing form (#4971) + * Fix null pointer dereference in ParseCommitWithSignature (#4962) + * Fix url in discord webhook (#4953) + * Detect charset and convert non UTF-8 files for display (#4950) + * Make sure to catch the right error so it is displayed on the UI (#4945) + * Fix(topics): don't redirect to explore page. (#4938) + * Fix bug forget to remove Stopwatch when remove repository (#4928) + * Fix bug when repo remained bare if multiple branches pushed in single push (#4923) + * Fix: Crippled diff (#4726) (#4900) + * Fix trimming of markup section names (#4863) + * Issues api allow pulls and fix #4832 (#4852) + * Do not autocreate directory for new users/orgs (#4828) (#4849) + * Fix redirect with non-ascii branch names (#4764) (#4810) + * Fix missing release title in webhook (#4783) (#4796) + * User shouldn't be able to approve or reject his/her own PR (#4729) + * Make sure to reset commit count in the cache on mirror syncing (#4720) + * Fixed bug where team with admin privilege type doesn't get any unit (#4719) + * Fix incorrect caption of webhook setting (#4701) (#4717) + * Allow WIP marker to contains < or > (#4709) + * Hide org/create menu item in Dashboard if user has no rights (#4678) (#4680) + * Site admin could create repos even MAX_CREATION_LIMIT=0 (#4645) + * Fix custom templates being ignored (#4638) + * Fix starring icon after semantic ui update (#4628) + * Fix Split-View line adjustment (#4622) + * Fix integer constant overflows in tests (#4616) + * Push whitelist now doesn't apply to branch deletion (#4601) (#4607) + * Fix bugs when too many IN variables (#4594) + * Fix failure on creating pull request with assignees (#4419) (#4583) + * Fix panic issue on update avatar email (#4580) (#4581) + * Fix status code label for a successful webhook (#4540) + * An inactive user shouldn't be able to be added as a collaborator (#4535) + * Don't fail silently if trying to add a collaborator twice (#4533) + * Fix incorrect MergeWhitelistTeamIDs check in CanUserMerge function (#4519) (#4525) + * Fix out-of-transaction query in removeOrgUser (#4521) (#4522) + * Fix migration from older releases (#4495) + * Accept 'Data:' in commit graph (#4487) + * Update xorm to latest version and fix correct `user` table referencing in sql (#4473) + * Relative URLs for LibreJS page (#4460) + * Redirect to correct page after using scratch token (#4458) + * Fix column droping for MSSQL that need new transaction for that (#4440) + * Replace src with raw to fix image paths (#4377) + * Add default merge options when creating new repository (#4369) + * Fix docker build (#4358) + * Fixes repo membership check in API (#4341) + * Dep upgrade mysql lib (#4161) + * Fix some issues with special chars in branch names (#3767) + * Responsive design fixes (#4508) +* TRANSLATION + * Fix punctuation in English translation (#4958) + * Fix translation (#4355) + +## [1.5.3](https://github.com/go-gitea/gitea/releases/tag/v1.5.3) - 2018-10-31 + +* SECURITY + * Fix remote command execution vulnerability in upstream library (#5177) (#5196) + +## [1.5.2](https://github.com/go-gitea/gitea/releases/tag/v1.5.2) - 2018-10-09 + +* SECURITY + * Enforce token on api routes (#4840) (#4905) +* BUGFIXES + * Remove links from topics in edit mode (#5030) + * Detect charset and convert non UTF-8 files for display (#4950) (#4994) + * Fix layout of the topics editing form (#4971) (#4993) + * Fix null pointer dereference in ParseCommitWithSignature (#4964) + * Fix url in discord webhook (#4951) + * Fix font-cropping UI bug in diff (#4726) (#4929) + * Fix bug forget to remove Stopwatch when remove repository (#4933) + * Fix bug when repo remained bare if multiple branches pushed (#4927) + * Fix redirect with non-ascii branch names (#4764) (#4887) + * Fix issues api allow pulls (#4852) (#4862) + * Fix trimming of markup section names (#4864) + +## [1.5.1](https://github.com/go-gitea/gitea/releases/tag/v1.5.1) - 2018-09-03 + +* SECURITY + * Don't disclose emails of all users when sending out emails (#4784) + * Improve URL validation for external wiki and external issues (#4710) (#4740) + * Make cookies HttpOnly and obey COOKIE_SECURE flag (#4706) (#4707) +* BUGFIXES + * Fix missing release title in webhook (#4783) (#4800) + * Make sure to reset commit count in the cache on mirror syncing (#4770) + * Fixed bug where team with admin privilege type doesn't get any unit (#4759) + * Fix failure on creating pull request with assignees (#4583) (#4727) + * Hide org/create menu item in Dashboard if user has no rights (#4678) (#4686) +* TRANSLATION + * Fix incorrect caption of webhook setting (#4701) (#4718) + +## [1.5.0](https://github.com/go-gitea/gitea/releases/tag/v1.5.0) - 2018-08-10 + +* SECURITY + * Check that repositories can only be migrated to own user or organizations (#4366) (#4370) + * Limit uploaded avatar image-size to 4096px x 3072px by default (#4353) + * Do not allow to reuse TOTP passcode (#3878) +* BUGFIXES + * Fix column droping for MSSQL that need new transaction for that (#4440) (#4484) + * Redirect to correct page after using scratch token (#4458) (#4472) + * Replace src with raw to fix image paths (#4377) (#4386) + * Fixes repo membership check in API (#4341) (#4379) + * Add default merge options when adding new repository (#4369) (#4373) + * Fix repository last updated time update when delete a user who watched the repo (#4363) (#4371) + * Fix html entity escaping in branch deletion message (#4471) (#4485) + * Fix out-of-transaction query in removeOrgUser (#4521) (#4524) + * Fix incorrect MergeWhitelistTeamIDs check in CanUserMerge function (#4519) + * Fix panic issue on update avatar email (#4580) (#4590) + * Fix bugs when too many IN variables (#4594) (#4597) + * Push whitelist now doesn't apply to branch deletion (#4601) (#4640) + * Site admin could create repos even MAX_CREATION_LIMIT=0 (#4645) (#4650) +* FEATURES + * Add cli commands to regen hooks & keys (#3979) + * Add support for FIDO U2F (#3971) + * Added user language setting (#3875) + * LDAP Public SSH Keys synchronization (#1844) + * Add topic support (#3711) + * Multiple assignees (#3705) + * Add protected branch whitelists for merging (#3689) + * Global code search support (#3664) + * Add label descriptions (#3662) + * Add issue search via API (#3612) + * Add repository setting to enable/disable health checks (#3607) + * Emoji Autocomplete (#3433) + * Implements generator cli for secrets (#3531) +* ENHANCEMENTS + * Add more webhooks support and refactor webhook templates directory (#3929) + * Add new option to allow only OAuth2/OpenID user registration (#3910) + * Add option to use paged LDAP search when synchronizing users (#3895) + * Symlink icons (#1416) + * Improve release page UI (#3693) + * Add admin dashboard option to run health checks (#3606) + * Add branch link in branch list (#3576) + * Reduce sql query times in retrieveFeeds (#3547) + * Option to enable or disable swagger endpoints (#3502) + * Add missing licenses (#3497) + * Reduce repo indexer disk usage (#3452) + * Enable caching on assets and avatars (#3376) + * Add repository search ordered by stars/forks. Forks column in admin repo list (#3969) + * Add Environment Variables to Docker template (#4012) + * LFS: make HTTP auth period configurable (#4035) + * Add config path as an optionial flag when changing pass via CLI (#4184) + * Refactor User Settings sections (#3900) + * Allow square brackets in external issue patterns (#3408) + * Add Attachment API (#3478) + * Add EnableTimetracking option to app settings (#3719) + * Add config option to enable or disable log executed SQL (#3726) + * Shows total tracked time in issue and milestone list (#3341) +* TRANSLATION + * Improve English grammar and consistency (#3614) +* DEPLOYMENT + * Allow Gitea to run as different USER in Docker (#3961) + * Provide compressed release binaries (#3991) + * Sign release binaries (#4188) + +## [1.4.3](https://github.com/go-gitea/gitea/releases/tag/v1.4.3) - 2018-06-26 + +* SECURITY + * HTML-escape plain-text READMEs (#4192) (#4214) + * Fix open redirect vulnerability on login screen (#4312) (#4312) +* BUGFIXES + * Fix broken monitoring page when running processes are shown (#4203) (#4208) + * Fix delete comment bug (#4216) (#4228) + * Delete reactions added to issues and comments when deleting repository (#4232) (#4237) + * Fix wiki URL encoding bug (#4091) (#4254) + * Fix code tab link when viewing tags (#3908) (#4263) + * Fix webhook type conflation (#4285) (#4285) + +## [1.4.2](https://github.com/go-gitea/gitea/releases/tag/v1.4.2) - 2018-06-04 + +* BUGFIXES + * Adjust z-index for floating labels (#3939) (#3950) + * Add missing token validation on application settings page (#3976) #3978 + * Webhook and hook_task clean up (#4006) + * Fix webhook bug of response info is not displayed in UI (#4023) + * Fix writer cannot read bare repo guide (#4033) (#4039) + * Don't force due date to current time (#3830) (#4057) + * Fix wiki redirects (#3919) (#4065) + * Fix attachment ENABLED (#4064) (#4066) + * Added deletion of an empty line at the end of file (#4054) (#4074) + * Use ResolveReference instead of path.Join (#4073) + * Fix #4081 Check for leading / in base before removing it (#4083) + * Respository's home page not updated after first push (#4075) + +## [1.4.1](https://github.com/go-gitea/gitea/releases/tag/v1.4.1) - 2018-05-03 + +* BREAKING + * Add "error" as reserved username (#3882) (#3886) +* SECURITY + * Do not allow inactive users to access repositories using private key (#3887) (#3889) + * Fix path cleanup in file editor, when initilizing new repository and LFS oids (#3871) (#3873) + * Remove unnecessary allowed safe HTML (#3778) (#3779) + * Correctly check http git access rights for reverse proxy authorized users (#3721) (#3743) +* BUGFIXES + * Fix to use only needed columns from tables to get repository git paths (#3870) (#3883) + * Fix GPG expire time display when time is zero (#3584) (#3884) + * Fix to update only issue last update time when adding a comment (#3855) (#3860) + * Fix repository star count after deleting user (#3781) (#3783) + * Use the active branch for the code tab (#3720) (#3776) + * Set default branch name on first push (#3715) (#3723) + * Show clipboard button if disable HTTP of git protocol (#3773) (#3774) + +## [1.4.0](https://github.com/go-gitea/gitea/releases/tag/v1.4.0) - 2018-03-25 + +* BREAKING + * Drop deprecated GOGS\_WORK\_DIR use (#2946) + * Fix API status code for hook creation (#2814) +* SECURITY + * Escape branch name in dropdown menu (#3691) (#3692) + * Refactor and simplify to correctly validate redirect to URL (#3674) (#3676) + * Fix escaping changed title in comments (#3530) (#3534) + * Escape search query (#3486) (#3488) + * Sanitize logs for mirror sync (#3057) +* FEATURES + * Serve .patch and .diff for pull requests (#3305, #3293) + * Add repo-sync-releases admin command (#3254) + * Support default private when creating or migrating repository (#3239) + * Writable deploy keys (closes #671) (#3225) + * Add Pull Request merge options - Ignore white-space for conflict checking, Rebase, Squash merge (#3188) + * Added progressbar for issues with checkboxes (#1146). (#3171) + * Mention completion for issue editor. (#3136) + * Add 'mark all read' option to notifications (#3097) + * Git LFS lock api (#2938) + * Add reactions to issues/PR and comments (#2856) + * Add dingtalk webhook (#2777) + * Responsive view (#2750) +* BUGFIXES + * Fix wiki inter-links with spaces (#3560) (#3632) + * Fix query protected branch bug (#3563) (#3571) + * Fix remove team member issue (#3566) (#3570) + * Fix the protected branch panic issue (#3567) (#3569) + * If Mirrors repository no content is fetched, updated time should not be changed (#3551) (#3565) + * Bug fix for mirrored repository releases sorted (#3522) (#3555) + * Add issue closed time column to fix activity closed issues list (#3537) (#3540) + * Update markbates/goth library to support OAuth2 with new dropbox API (#3533) (#3539) + * Fixes missing avatars in offline mode (#3471) (#3477) + * Fix synchronization bug in repo indexer (#3455) (#3461) + * Fix rendering of wiki page list if wiki repo contains other files (#3454) (#3463) + * Fix webhook X-GitHub-* headers casing for better compatibility (#3429) + * Add content type and doctype to requests made with go-get (#3426, #3423) + * Fix SQL type error for webhooks (#3424) + * Fix PR merge error (#3421) + * Recognize more characters in crossreferenced repo name (#3413) + * Fix MSSQL bug on org (#3405) + * HTML escape all lines of the search result (#3402) + * Change local copy origin url after repository rename (#3399) + * Force-push to base repo's ref/pull/#/head (#3393) + * Fix bug when a user delete but assigned on issue (#3318) + * Use issue number/index instead of id for API URL. Fix #3297 (#3298) + * Fix repo-transfer-and-team-repo-count bug (#3241) + * Fix always-on SSL Mode checkbox in admin page (#3208) + * Fix source download link when no code unit allowed (#3166) + * Fix org owner cannot be removed if he is not in owner team (#3164) + * Fix run web with -p push failed (#3154) + * Fix gpg tmpl (#3153) + * Fix SSH auth lfs locks (#3152) + * Improvements for supporting UI Location (#3146) + * Fix new pull request link (#3133) + * Fix missing branch in release bug (#3108) + * Allow adding collaborators with (fullname) (#3103) + * Fix repo links (#3093) + * fix lfs url refs + keep path upper/lowercase in db. (#3092) + * Fix redis session failed (#3086) + * Fix bugs in issue dashboard stats (#3073) + * Fix avatar URLs (#3069) + * Fix ref parsing in commit messages (#3067) + * Fix issue list branch link broken (#3061) + * sendmail: correct option to set envelope-sender (#3044) + * Fix missing password length check when change password (#3039) + * Fix git lfs path (#3016) + * Fix API-Endpoint release (#3005) (#3012) + * Set OpenID support on by default when installing new instance (#3010) + * Various wiki bug fixes (#2996) + * Fix go-get, src and raw urls to new scheme (#2978) + * Fix error when add user has full name to team (#2973) + * Fix memcache support when value is returned as string always (#2924) +* ENHANCEMENTS + * Use GiteaServer as the user agent for http requests (#3404) + * Delete indexer DB entries when (re)creating index (#3385) + * Change how merged PR commit info are prepared (#3368) + * Asynchronously populate the repo indexer (#3366) + * Make the default action for the gitea executable that of running the webserver (#3331) + * Templates for extra links in top navbar and repo tool tabs. (#3308) + * Fixed asterisk based tasklist items #3295 (#3296) + * Add more additional template snippets (#3286) + * Open external tracker in blank window, consistently with wiki (#3227) + * Fix repo links on user profile (#3197) + * Enable emoji for wiki view (#3158) + * Small improve on deleting attachements (#3145) + * Reduce overhead of upgrades for users with custom stylesheets/JS (#3051) + * Default log level to Info without hardcoding it in installer (#3041) + * Memory usage improvements (#3013) + * Add fingerprint to ssh key endpoints. (#3009) + * Improve memory usage when reaching diff limits (#2990) + * Expandable commit bodies (#2980) + * Update gitgraph.js to fix blurry commit graph on HiDPI screens (#2957) + * Fix language names (#2955) + * Remove render issue link (#2954) + * Page parameter for repo search API (#2915) + * Apply LANDING\_PAGE config options for logged in users (#2894) + * Enable admin to search by email (#2888) + * Hide add key button if SSH is disabled (#2873) + * Fix comment API paths (#2813) + * Add an option to allow redirect of http port 80 to https. (#1928) +* MISC + * Fix organization profile on mobile devices (#3332) + * Fix guide link for webhooks in repository settings (#3291) (#3292) + * Enable Libravatar by default in new installations (#3287) + * Improve suppressed diff boxes (#3193) + * fix button heights on commits page (#3091) + * Minor copy changes (#3074) + * Sort repos in issues dashboard sidebar (#3072) + * Remove box-shadow from UI, fix dashboard issue (#3065) + * Adjust branch button size (#3063) + * Fix misalignment issue in repo header (#3062) + * Delete a user's public key via admin api (closes #3014) (#3059) + * Dashboard: Fix line height problem in issue titles (#3054) + * Remove duplicate "Max Diff Lines" from config view (#2987) + * Drop unmaintained gogs migration script (#2947) + * App restarts to quickly if it fails to start. (#2945) + * Add owner to delete repo message (#2886) + +## [1.3.1](https://github.com/go-gitea/gitea/releases/tag/v1.3.1) - 2017-12-08 + +* BUGFIXES + * Sanitize logs for mirror sync (#3057, #3082) (#3078) + * Fix missing branch in release bug (#3108) (#3117) + * Fix repo indexer and submodule bug (#3107) (#3110) + * Fix legacy URL redirects (#3100) (#3106) + * Fix redis session failed (#3086) (#3089) + * Fix issue list branch link broken (#3061) (#3070) + * Fix missing password length check when change password (#3039) (#3071) + +## [1.3.0](https://github.com/go-gitea/gitea/releases/tag/v1.3.0) - 2017-11-29 + +* BREAKING + * Make URL scheme unambiguous (#2408) +* FEATURES + * Add branch overiew page (#2108) + * Code/repo search (#2582) + * Add Activity page to repository (#2674) + * Issue Timetracking (#2211) + * Add orgmode document type on file view and readme (#2525) + * Add external markup render support (#2570) + * Implementation of discord webhook (#2402) + * Webhooks for repo creation/deletion (#1663) + * Complete push webhooks (#2530) + * Add possibility to record branch information in an issue (#780) + * Create new branch from branch selection dropdown (#2130) + * Implementation of all repositories of a user from user->settings (#1740) + * Add LFS object verification step after upload (#2868) + * Configurable SSH cipher suite (#913) + * Disable custom Git Hooks globally via configuration file (#2450) + * Sync releases table with tags on push and for mirrors (#2459) +* BUGFIXES + * Fix label comments for French locale (#3017) + * Remove duplicate "Max Diff Lines" from config view (#3001) + * Fix over-escaped characters (#2992) + * Fix go-get, src and raw urls to new scheme (#2986) + * Fix error when add user has full name to team (#2975) + * Fix files/commits of merged PRs (#2970) + * Update golang x/crypto dependencies - Fix SSH transport fail (#2951) + * Fix memcache support when value is returned as string always (#2950) + * Fix issue link rendering in commit messages (#2897) + * Fix adding a new authentication source after selecting OAuth (#2889) + * Fix new branch creation to new url scheme (#2884) + * Allow spaces in username for LDAP users (#2880) + * Fix LFS not returning correct content length when requesting a range … (#2864) + * Fix fork repository cycle to self (#2860) + * Fix click create pull request button 404 (#2859) + * Fix API raw file content access for default branch (#2849) + * Clean repository ROOT directory name with filepath.Clean (#2846) + * Fix API raw requests for commits and tags (#2841) + * Fix order of comments (#2835) + * Issue content should not be updated when closing with comment (#2833) + * Fix ordering in app.ini and fix run mode option (#2829) + * Fix redirect url of legacy commits route (#2825) + * Fix commits page url (#2823) + * Fix wrong translations (#2818) + * Fix dropdown menu position when explore repos (#2808) + * Fix Git LFS object/repo link storage in database and small refactoring (#2803) + * Use relative URLs for avatars on the dashboard (#2800) + * Add checks for commits with missing author and time (#2771) + * Fix emojify image URL (#2769) + * Hide unactive on explore users and some refactors (#2741) + * Fix IE unsupported javascript construction in branch dropdown (#2736) + * Only update mirror last update after successful sync (#2730) + * Fix semantic-ui style conflict with v-cloak (#2722) + * Fixing wrong translation on sort type oldest/latest (#2720) + * Fix PR, milestone and label functionality if issue unit is disabled (#2710) + * Fix plain readme didn't render correctly on repo home page (#2705) + * Fix organization removal from watch table migration (#2703) + * Fix repository search function (#2689) + * fix panic on gogs webhook creation (#2675) + * Fix orgnization user watch repository (#2670) + * GPG key email verification no longer case sensitive (#2661) (#2663) + * Fix index column deletion (#2651) + * table `pull_request` wasn't updated correctly (#2649) + * Fix go get response if only app URL is custom in configuration (#2634) + * Fix doubled issue tab introduced in migration v16 (#2611) + * Rewrite migrations to not depend on future code changes (#2604) + * Fix implementation of repo Home func (#2601) + * Fix translation upload to crowdin (#2599) + * Reduce usage of allcols on update (#2596) + * fix go get subpackage bug (#2584) + * Fix broken migration to add can_push field back to table (#2574) + * fix readme view bug (#2566) + * Fix sending mail with a non-latin display name. #2102 (#2559) + * Restricting access to fork functioanlity to users with Code access (#2534) + * fix updated update on public key (#2514) + * Added bucket name to s3 drone plugin (#2505) + * fixes 500 error on dashboard when using MSSQL (#2504) + * fix wrong rendering of commit detail page (#2503) + * Hotfix: Add time manually adds time in nanoseconds (#2499) + * Remove repository mirrors from "collaborative" list (#2497) + * fix release failed since the wrong token name (#2496) + * Fix slice out of bounds error in mailer (#2479) + * Fix #2470 (#2477) + * fix orgnization webhooks (#2422) + * fix webhook test (#2415) + * fix missing orgnization discord webhook (#2414) + * Fix route handler order (#2409) + * Prevent sending emails and notifications to inactive users (#2384) + * Move themes to plugin directory. Fixes #2372 (#2375) + * fix duplicated feed (#2370) + * Fix missing collabrative repos (#2367) + * Only check at least one email gpg key (#2266) + * don't check minimum key size when disabled (#1754) + * Fix run command race (#1470) + * fix .netrc authentication (#2700) + * Fix so that user can still fork his own repository to his organizations (#2699) + * Fix can_push value to false in protected_branch (#2560) + * Fix copy in email templates (#2801) + * Fix inconsistencies in user settings UI (#2901) + * Fix attachments icon size on zoom in/out (#2853) + * Fix ignored errors in API route (#2850) + * Fix activity css conflict with semantic ui (#2758) + * Fix notifications tabs according to semantic-ui docs (#2733) + * Fix typos in app.ini (#2732) + * Fix duplicated rel attribute (#2549) + * Fix tests code to prevent some runtime errors (#2381) +* ENHANCEMENTS + * Memory usage improvements and lower minimal git requirement to 1.7.2 (#3013) (#3028) + * Set OpenID support on by default when installing new instance (#3010) (#3027) + * Use api.TrackedTime in API (#2807) + * Configurable SSH key exchange algorithm and MAC suite (#2806) + * Add Safari pinned tab icon (#2799) + * Improve force push detect when push (#2798) + * Add wrapping to long diff lines (#2789) + * Link members and repositories count to each page on org home. (#2787) + * Show Sendmail settings on admin config page (#2782) + * Add commit count caching (#2774) + * Use identicon image for default gravatar. (#2767) + * Add default ssh ciphers (#2761) + * Remove manual of unsupported option (#2757) + * Add search mode option to /api/repo/search (#2756) + * Move swagger-ui under /api/v1 (#2746) + * Add support for extra sendmail arguments (#2731) + * Use buffersize to reduce database connection when iterate (#2724) + * Render plain text README.txt monospaced (#2721) + * Integration test for activity page (#2704) + * Merge password and 2fa page on user settings (#2695) + * Allow custom SSH user in UI for built-in SSH server (#2617) (#2678) + * Refactor duplicated code in repo handlers (#2657) + * Replace deprecated Id method with ID (#2655) + * Remove redudant functions and code (#2652) + * hide navbar when only 1 sign-in method is available (#2444) (#2648) + * Change default sort order (#2647) + * Change pull description text (#2075) (#2646) + * Remove direct user adding to organization members (#2641) + * Use session when creating user (#2638) + * Use Semantic UI's Search component for user and repo search (#2636) + * Use AfterLoad instead of AfterSet on Structs (#2628) + * Remove redudant CheckUnit calls in router (#2627) + * Remove repo unit index (#2621) + * Remove redudant issue LoadAttributes() calls (#2614) + * Make indexer code more reusable (#2590) + * Use custom type and constants to hold available order by options (#2572) + * Use named ActionType constants in template helper (#2545) + * Make basic functionality work without JavaScript (#2541) + * Ctrl + Enter to submit forms (#2540) + * Automatically regenerate indexer for incompatible versions (#2524) + * Set default lfs content path to data/lfs (#2521) + * Convert spaces to tabs in footer.tmpl (#2520) + * Sort repository tree entries in natural way (#2506) + * Open external wiki in new window (#2489) + * Use created & updated instead BeforeInsert & BeforeUpdate (#2482) + * Hide branch on pull request view or create UI (#2454) + * improve protected branch to add whitelist support (#2451) + * some refactors for issue and comments (#2419) + * Restructure markup & markdown to prepare for multiple markup language… (#2411) + * Improve issue search (#2387) + * Add UseCompatSSHURI setting (#2356) + * Use custom search for each filter type in dashboard (#2343) + * Failed authentication are now properly logged (#2334) + * Add environment variable support for Docker image (#2201) + * Set session and indexers' data files rel to AppDataPath (#2192) + * Display commit status on landing page of repo (#1784) +* TESTING + * Add integration test for logging out (#2892) + * Integration test for user deleting account (#2891) + * Use different directories for session files in integration tests (#2834) + * Add deleted_branch table fixture (#2832) + * Include HTTP method in test error message (#2815) + * Add repository search unit and integration tests (#2575) + * Expand fixtures (#2571) + * Fix /api/repo/search integration tests (#2550) + * Make integration tests more user-friendly (#2536) + * Fix unit test race condition (#2516) + * Add missing fixture to clean gpg_key table (#2494) + * Hotfix for integration testing (#2473) + * Make repo private to not interfere with other tests (#2467) + * Error message for integration test (#2410) + * Fix "index out of range" runtime error in repo_list tests (#2376) + * Add git clone test on integration test (#1682) +* TRANSLATION + * Fix localization texts that contain semicolon (#2900) + * Fix activity locale (#2709) + * Update translation from crowdin (#2368) +* BUILD + * change the email and name to GitBot account. (#2848) + * Fix removing backslash before quotes in translations (#2831) + * add gitea remote in drone. (#2817) + * add remote name for git push. (#2816) + * Launch Gitea with custom UID/GID for 'git' user (fixes #2286) (#2791) + * Download and pushing translations (#2727) + * Automatic update of translations (#2585) + * Add pre-build step for nodejs stuff (#2581) + * Compress css with nodejs (#2580) + * Remove go version check for make fmt (#2558) + * Fix lint errors (#2547) + * Always run fmt check in CI (#2546) + * Fix fmt errors (#2544) + * add codecov.io service. (#2493) + * Fix some tests : make coverage -> test (#2492) + * Fix fmt error in mailer (#2490) + * Allow changing integration test database connection using env variables (#2484) + * Add changelog config file for generate changelog (#2461) + * Changes for latest DroneCI (#2362) + * Use standard lessc and minify CSS using Node.js (#2337) +* DOCS + * Update screenshots on README (#2910) + * Gogs -> Gitea (#2909) + * Update swagger documentation (#2899) + * Fix typo (#2810) + * Fix Polish language name spelling (#2766) + * Fix Various Grammar Issues and Adjust Unnatural Wording (#2737) + * Add maintainer label for docker file (#2658) + * Link to gitea-specific Vagrant example (#2624) + * add release notes of v1.1.4 (#2463) + * Wrap most paragraphs to 80 columns (#2396) + * Update CONTRIBUTING following #2329 discussion (#2394) + * Update hard-coded version to 1.3.0+dev (#2390) + * Clarify Translation Process. Also fix branch names (#2378) + * Admin grammar fixes and improvements (#2056) +* MISC + * Sync MaxGitDiffLineCharacters with conf/app.ini (#2779) + * Dockerfile: Updated alpine image to 3.6. (#2486) + * Basic VSCode configuration for building and debugging (#2483) + * Added vendor dir for js/css libs; Documented sources (#1484) (#2241) + +## [1.2.3](https://github.com/go-gitea/gitea/releases/tag/v1.2.3) - 2017-11-03 + +* BUGFIXES + * Only require one email when validating GPG key (#2266, #2467, #2663) (#2788) + * Fix order of comments (#2835) (#2839) + +## [1.2.2](https://github.com/go-gitea/gitea/releases/tag/v1.2.2) - 2017-10-26 + +* BUGFIXES + * Add checks for commits with missing author and time (#2771) (#2785) + * Fix sending mail with a non-latin display name (#2559) (#2783) + * Sync MaxGitDiffLineCharacters with conf/app.ini (#2779) (#2780) + * Update vendor git (#2765) (#2772) + * Fix emojify image URL (#2769) (#2773) + +## [1.2.1](https://github.com/go-gitea/gitea/releases/tag/v1.2.1) - 2017-10-16 + +* BUGFIXES + * Fix PR, milestone and label functionality if issue unit is disabled (#2710) (#2714) + * Fix plain readme didn't render correctly on repo home page (#2705) (#2712) + * Fix so that user can still fork his own repository to his organizations (#2699) (#2707) + * Fix .netrc authentication (#2700) (#2708) + * Fix slice out of bounds error in mailer (#2479) (#2696) + +## [1.2.0](https://github.com/go-gitea/gitea/releases/tag/v1.2.0) - 2017-10-10 + +* SECURITY + * Sanitation fix from Gogs (#1461) +* BREAKING + * Rename /forget_password url to /forgot_password (#1219) +* FEATURES + * Logo: Add task to generate images from SVG and change to new logo (#2194) + * Status-API (#1332) + * Show commit status icon in commits table (#1688) + * Additional OAuth2 providers (#1010) + * GPG commit validation (#1150) + * Rework SSH key management UI to add GPG (#1293) + * Implement GPG api (#710) + * Login via OpenID-2.0 (#618) + * Add units to team (#947) + * Batch updates for issues (#926) + * Add Gitea Webhook (#1755) + * API: support '/orgs/:org/repos' (#2047) + * Display all organization from user settings (#1739) + * LDAP user synchronization (#1478) + * Adding #issuecomment to the URL in E-Mail notifications (#1674) + * Add download count field and unit testing for attachment. (#1512) + * Add repo mirror sync API endpoint (#1508) + * Add markup package to prepare for org markup format (#1493) + * Support for custom html meta (#1423) + * Per issue/PR watch/unwatch (#1410) + * Allow ENABLE_OPENID_SIGNUP to depend on DISABLE_REGISTRATION (#1369) + * Repo size in admin panel (#1482) + * Show user OpenID URIs in their profile (#1314) + * Add change-password admin command (#1304) + * Only use issue and wiki on repo. (#1297) + * Allow push to init a wiki repo (#1279) +* ENHANCEMENTS + * Make time diff translatable (#2057) + * Smaller watch, star, and fork buttons (#2052) + * Display config file path on admin panel (#2030) + * Only show SSH clone URL if signed in (#2169) (#2170) + * Only show "No Description" to repo admins (#2167) + * Always return valid go-get meta, even if unauthorized (#2010) + * Enable assignee e-mail notification (#2003) + * Let not-logged-in users view releases (#1999) + * No highlighting for .txt files (#1922) + * Make side nav on dashboard stackable (#1778) + * Setting to disable authorized_keys backup (#1856) + * Hide the create organization button (in dashboard/organization section) (#1705) + * LFS: Return 404 for unimplemented endpoints (#1330) + * Show a link to password reset from user settings requiring a password (#862) + * Reserve the "explore" user/org name (#1222) + * Send notifications to participants in issue comments (#1217) + * Improve style of user OpenID setting page (#1324) + * Use font-awesome OpenID icon more (#1320) + * Use readonly input form to show the validated OpenID URI (#1308) + * Add captcha support to OpenID based signup (#1307) + * Minor improvements on commit graph UI (#1380) + * Mirror sync interval specified as duration string (#1407) + * Make issue in commit graph "clickable" (#1392) + * Use whole button (commit graph) as link (#1390) + * Autofocus on 2fa passcode fields (#1460) + * Sort on repo size in admin panel (#1654) + * Improve dashboard repo search (#1652) + * Use a better default MAX_GIT_DIFF_LINE_CHARACTERS (#1845) + * Adds Parent property to the repo API (#1687) + * Add configuration option for default permission to create Organizations (#1686) + * Remove sha1 hash display in repository table (#1678) + * Download files to their original filename (#1676) + * Exposes in API the Repo entity's Size and IsBare property (#1668) + * Change two factor code entry box from text to number (#1733) + * Directly show error if user hit repository limit (#1767) + * Generate small and large logos at 4x resolution (#2233) + * Tags listed in releases tab (#2389) (#2424) +* BUGFIXES + * Fix adding branch as protected to not allow pushing to it (#2556) + * Orgs: fix org page title when full name is not defined (#1495) + * Fix double borders on edit page (#1152) (#1153) + * Search bar fixes for #1187 and #1205 (#1207) + * Fix upgrade failed after ever rollback (#1194) + * Fix FCGI (over TCP) support (#1368) + * Backport of migration fixes (#2604) (#2677) + * fix panic on gogs webhook creation (#2675) (#2676) + * Backport: Fixes 500 error on dashboard when using MSSQL (#2504) (#2662) + * Fix go get response if only app URL is custom in configuration (#2634) (#2640) + * Fix deletion of unprotected branches (#2630) + * Backport of 2611 / Fix doubled issue tab introduced in migration v16 (#2622) + * v38 migration used an outdated version of RepoUnit model (#2602) + * fix go get subpackage bug (#2584) (#2589) + * Backport: Sync releases table with tags on push and for mirrors (#2459) (#2554) + * Backport: Restricting access to fork functioanlity to users with Code access (#2542) + * Fix migration from pre-v15 to 1.2.0 (#2460) (#2465) + * Fix migration from pre-v15 to 1.2.0 (#2460) + * fix duplicated feed (#2370) (#2413) + * Fix releases to be counted from database not tags (#2389) + * Fix missing collabrative repos (#2367) (#2382) + * Add more test for login links and fix a bug on action retrieve (#2361) + * Fix SQL condition bug in GetFeeds(..) (#2360) + * fix bug on create repo link on dashboard (#2359) + * Fix order of elements in dashboard html (#2344) + * Fix repo-search template errors for go1.7 (#2336) + * Add missing forks key for dashboard repository component (#2325) + * fix template error on explore repos (#2319) + * Trigger sync webhooks on UI commit (#2302) + * fix 500 error when view an issue which's milestone deleted (#2297) + * Only update needed columns when update user (#2296) + * Fix rendering of external links (#2292) + * Fix and improve dashboard repo UI (#2285) + * Make short link pattern greedy (#2259) + * Temporarily patch go-ini/ini with fork (#2255) + * Convert xorm literal queries to method calls (#2253) + * update code.gitea.io/git in vendor to fix delete branch fails (#2250) + * Replace calls to xorm UseBool with Where (#2237) + * rhel7 has a git version with four digits (1.8.3.1) (#2236) + * Fix internal requests when gitea listens to unix socket or only external IP (#2234) + * Check for access in /repositories/:id (#2227) + * Fixed robots.txt 404 error (#2226) + * Fix counts on issues dashboard (#2215) + * Fix unclosed session bug (#2214) + * Add collaborative repositories to the dashboard (#2205) + * Fix issue updated_unix bug (#2204) + * Fix Commits nil pointer dereference (#2203) + * Fix bare-repo bugs (#2199) + * Fix PR nil-dereference bug (#2195) + * Allow only single fork per user/organization (#2193) + * Fix key usage time update if the key is used in parallel for multiple operations (#2185) + * Only allow token authentication with 2FA enabled (#2184) + * Fix profile update for non-local users (#2178) + * Fix compiling without sqlite and gcc (#2177) + * Make compare button URL aware if current repo is a fork (#2162) (#2163) + * Remove unit types commits and settings (#2161) + * Fix OpenID registration route (#2160) + * Fix repository settings collobration list display (#2151) + * Ignore invalid issue numbers in commit messages. Fixes #2022 (#2150) + * Fix SHA1 hash linking (#2143) + * Fix repo API bug (#2133) + * Use POSIX complaint ! operator in find (#2132) + * Fix GET /users/:username/repos endpoint (#2125) + * Fix username rendering bug (#2122) + * Fix wiki preview links (#2119) + * vendor: update sqlite to fix "database is locked" errors (#2116) + * Fix unchecked error bug (#2110) + * Fix missing-return bug (#2109) + * Fix API for branches with slashes (#2096) + * Fix git hooks update to receive required arguments (#2095) + * upgrade git source code. (#2094) + * Fix SQL bug in models.PullRequests (#2092) + * Don't ignore gravatar error (#2083) + * Fix release display and correct paging (#2080) + * remove unnecessary blank lines and wrong error log (#2079) + * Check for valid renamed usernames (#2077) + * Update git module (#2074) + * Fix org hooks UI (#2072) + * Fix #1271: Call location.reload after XHR finishes (#2071) + * Fix default ghost assignee bug (#2069) + * Fix bug in issue labels API (#2048) + * Load label ID in NewLabels (#2045) + * Fix: `http: multiple response.WriteHeader calls` (#2038) + * Pagination on releases page (#2035) + * repo/editor: fix breadcrumb path cuts parent dirs (#3859) (#2032) + * Fix displaying commits and files of PR created from now deleted fork (#2023) + * Fix #2001 and fix issue comments hidden (#2016) + * Update code.gitea.io/git (#2014) + * Keep sort when switching page (#2013) + * Important: wrong PR merge commit ID saved (#2007) + * Don't show non-comments in comments API (#2001) + * Fix "Dashboard shows deleted comments" (#1995) + * Make branch deletion URL more like GitHub's, fixes #1397 (#1994) + * Fix fast-forward PR bug (#1989) + * Fix GPG email checking to be case insensitive (#1988) + * fix bug for normal user visit public repo (#1984) + * fix collborators lack of units on orgnization repositories (#1968) + * Fix diff of renamed and modified file (#1967) + * Fix uppercase default branch bug (#1965) + * Fix bug in Action.loadRepo() (#1959) + * Fix deleted milestone bug (#1942) + * Fix engine bug in getIssueByID (#1934) + * Switch to keybase go-crypto (for some elliptic curve key) + test (#1925) + * Fix setting.AppPath for integration tests (#1923) + * Fix search by issue type (#1914) + * Fix ghost user bug (#1913) + * Require token before checking membership/ownership (#1905) + * Bug fixes for org member API (#1904) + * A missing / to provide a correct endpoint (#1903) + * Fix 500 in public activity page (#1901) + * Center-aligned login topbar (#1880) + * Migration to fix existing owner team units (#1873) + * Fix paginater length (#1866) + * Fix bug in removeOrgRepo (#1858) + * Display draft releases (#1854) + * Fix 404 for external tracking issues (#1852) + * Update code.gitea.io/git (#1849) + * Fix user profile activity feed (#1848) + * Don't ignore error in getMergeCommit (#1843) + * Fix locking bug in removeOrgRepo (#1842) + * Fix status table race condition (#1835) + * Fix PR template error (#1834) + * Fix pull request compare link (#1832) + * Use ghost users in issues/PRs (#1831) + * Commitless repos should be bare (#1829) + * Update code.gitea.io/git (#1824) + * Fix invalid reference in feeds template (#1820) + * fix bug to deny to add orgnization as a member of an orgnization or team (#1815) + * xxx_active_code_live setting in printed in hours and minutes instead … (#1814) + * Fix deadlock in updateRepository (#1813) + * Give all units to owner team (#1812) + * Fix 500 for GET /teams/:id endpoints (#1811) + * fix bug not to trim space of login username (#1796) + * Fix renaming bug (#1786) + * Fix activity feed (#1779) + * Make navbar scroll on overflow (#1777) + * Delete repo redirects on repo deletion (#1776) + * Fix unloaded owner bug (#1770) + * Admin should always be allowed to create repositories even if hit limit (#1765) + * Update HighlightJS and fix YAML files highlighting (#1764) + * fix: #1757 fix set MAX_CREATION_LIMIT as zero. (#1762) + * fix admin lost permission caused by #947 (#1753) + * More fixes for dashboard search (#1750) + * fixes wrong after field in webhook payload (#1746) + * fix avatar update bug (#1729) + * Fix FOUC on Firefox (#1728) + * Fix changes introduce by update of go-swagger. (#1727) + * Fix #1719 (#1722) + * Correct flash after sending password reset email (#1718) + * Fix and test for delete user (#1713) + * Fix rendering of issue checkboxes (#1709) + * Enforce netgo build tag while cross-compilation (#1690) + * fix bug when push a branch name with / & fix an integration test bug (#1689) + * fix potential sqlite lock (#1680) + * Fix commit sha1 URL rendering in markdown (#1677) + * Fix static files permission under public/ (#1675) + * fix: tag contain character ) will http 500 on release page (#1670) + * Fix CSS for code in wiki markdown (#1660) + * fix multiple readme file rendering and fix #1657 (#1658) + * Add primary key and index to external login user table (#1656) + * fix #1643 and improve integration test (#1645) + * Fix version in Makefile (#1636) + * Handle display of GPG key without end date (#1628) + * fix bug on issue view when not login (#1624) + * bug fixed for API to get user's repos (#1622) + * fix lost text color on button on set as primary email (#1621) + * Add create_at and updated_at in PR json (#1616) + * update git and fix #1133 (#1614) + * fix bug on status API (#1533) + * Do not show empty collaborators segment (#1531) + * Fix markdown rendering (#1530) + * fix go get sub package and add domain on installation to let go get work defaultly (#1518) + * fix #1501 ssh hangs caused by #1461 (#1513) + * Fix empty file download (#1506) + * Fix broken v27 migration - change mirror interval from int to bigint (#1504) + * Do not allow committing to protected branch from online editor (#1502) + * Add internal routes for ssh hook comands (#1471) + * Fix races within code.gitea.io/git.(*Command).RunInDirTimeoutPipeline (#1465) + * Simple quick fix for #1418 (#1456) + * fix gpg API panic when no verification (#1451) + * fix migrate failed and org dashboard failed on MSSQL database (#1448) + * Optimize and fix autolink function (#1442) (#1444) + * Fix and simplify repo branches (settings) UI (#1435) + * Fix disabled fields in repo settings UI (#1431) + * fixes pull request hanging when it contains normal and LFS files (#1425) + * Fix races in the log module by using syncmap (#1421) + * Add length check for the return string (#1420) + * Fix "Error: No issue number specified" when pushing (#1393) + * Corrected Mirror.NextUpdate not set (#1388) + * fix: remove `str2html` from org full name (#1360) + * Correct broken unaligned load/store in armv5 (#1355) + * Remove href on first/last link when on first/last page (#1345) + * Fix broken table layout (#1344) + * LFS: Fix SSH authentication for trailing arguments (#1328) + * Remove empty file (#1326) + * Fix delete user failed on sqlite (#1321) + * Fix inconsistency in layout (#1316) + * Fix gpg wrong column types (#1303) + * Fix wiki bugs (#1294) + * Fix missing less sources for oauth (#1288) + * Make sure both scripts/ can live side by side (#1264) + * Fix nil-dereference bug (#1258) + * rewrite pre-commit, post-commit and options hooks (fixes #1250) (#1257) + * Commit search appearance fixes (#1254) + * Fix forget migration for wiki hooks (#1227) + * Fix repo settings external tracker failed and check external urls (#1215) + * Fix 500 caused by branches settings introduced by #1198 (#1214) + * fix #1189, commit messages containing a pipe (#1203) + * Bug fixed for delete repo failed (#1193) + * Fix migration failed when authorized_keys is not exist (#1180) + * Fix ini format incomiptable with crowdin (#1177) +* TESTING + * Integration tests for issues API (#2059) + * Add integration tests for signin (#2363) + * Add INTERNAL_TOKEN to integration .ini file (#2346) + * Add public links check (#2323) + * Fix hooks for integration repo (#2216) + * More integration tests for comment API (#2156) + * Cache session cookies in tests (#2128) + * Less verbose integration tests (#2123) + * Fix improper setup for integration tests (#2050) + * Improve integration test helper functions (#2049) + * Add integration test for issue creating (#2002) + * Use testing/benchmark interface (#1993) + * Add integration test for repository migration (#1983) + * Consolidate boilerplate in integration tests (#1979) + * Set console to debug for integration tests (#1976) + * Add pull-create integration test (#1972) + * Coverage reports for integration tests (#1960) + * Add integration test for pull-request merge (#1912) + * Add integration test for file editing (#1907) + * Add integration test for repository forking (#1896) + * Run unused test (#1875) + * Don't recreate database in integration tests (#1697) + * remove sqlite tag when integration test with mysql/postgres and recreate database when init integration test (#1693) + * MySQL, Postgres integration tests in drone (#1638) + * improve integration test to resue models/fixtures and store git repos with tests (#1627) + * Improve govendor testing (#1623) + * Integration test framework (#1290) + * Unit tests for issue_list (#1209) + * Add integration test for signup (#1135) +* TRANSLATION + * update translation from crowdin (#2368) (#2380) + * Small fixes (#2144) + * Missing signed commit display translations (#2134) + * Sync latest translations from crowdin (#2104) + * Add make command update-translations for update translations from crodwin (#2097) + * Fix some mistakes (#1833) + * Improve clarity between is_activated and prohibit_login (#1788) + * Improve grammar (#1775) + * Fix bad grammar and wordiness (#1741) + * Make strings translatable (#1188) (#1198) +* BUILD + * Dockerfile for aarch64 (#1128) (#1130) + * backport from v1.2 branch: add secrets for github release (#2588) (#2598) + * Add secrets for github release to fix drone failed (#2588) + * Backport changes for latest drone (#2586) + * Removing .drone.yml.sig (#2579) + * Fix drone for tags (#2573) (#2576) + * Backport: Remove go version check for make fmt (#2558) (#2561) + * Backport: Fix lint, fmt and integration testing errors (#2553) + * update latest xorm version to vendor (#2353) + * Remove integration test executables on `make clean` (#2340) + * refactor(Makefile): allow overriding default go program (#2310) + * Revert to upstream ini dependency (#2304) + * Use /dev/urandom to create random password (#2298) + * update drone sig file. (#2262) + * go get github.com/wadey/gocovmerge when needed (#2235) + * fix typo (#2145) + * Revert "Reduce number of layer" (#2086) + * Reduce number of layer (#2078) + * Skip sqlite integration in CI (#2058) + * fix golint error and rename func for suggestion. (#1997) + * fix misspell (#1996) + * update drone sig file (#1981) + * send notification if status changed (#1973) + * switch gitter to discord for drone. (#1971) + * Fix missing backslash in Dockerfile.rpi (#1952) + * Don't run 'make release' on PRs (#1908) + * Update code.gitea.io/git (#1892) + * Use production version of vuejs (#1869) + * Add a variable for docker tag (#1825) + * resign drone and fix #1816 (#1819) + * Separate generate swagger + fix sed os specific (#1791) + * Only run coverage on merges/pushes to master (#1783) + * Remove stale rule from Makefile (#1782) + * feat: upgrade drone docker image to support multi-stage build. (#1732) + * Really don't cache apk index (#1694) + * Limit clone depth when drone-building (#1644) + * Refactor Dockerfile (#1632) + * Check if missing/modified/unused deps in vendor and fix errors (#1468) + * Add GOFLAGS and EXTRA_GOFLAGS (#1438) + * Include formatting check to the `make test` (and thus also `check`) rule (#1366) +* DOCS + * fix wrong changelog title (#2395) + * fix webhook link (#2289) + * Improve swagger doc (#2274) + * Add link to forum in issue template (#2070) + * add missing lfs config on example file (#2039) + * Add discourse link (#2027) + * Fix wording (#2024) + * Fix typo (#1974) + * Swagger docs for list/create forks (#1941) + * Update links to Discord server (#1940) + * [ci skip] update discord badge. (#1930) + * Change join chat from gitter to discord (#1929) + * Update changelog with v1.1.1 (#1926) + * Correct grammar in APIEmpty documentation (#1748) + * Add swagger comment for MirrorSync (#1747) + * Add "Table of Contents" in CONTRIBUTING.md (#1634) + * Fix service description in Debian init file (#1538) + * Use MAINTAINERS file in repository in CONTRIBUTING (#1489) + * Generate swagger json (#1402) + * Changed text when password reset disabled. (#1364) + * Removed email copyright year (#1348) + * Specify that time interval units are seconds (#1311) + * Gitea OpenID-2.0 login has been tested with livejournal.com too (#1306) + * Make wording of commit search more clear (#1291) + * Add notice that LFS mirroring is not supported (#1251) + * Fix typos in models/ and modules/ (#1248) + * Refactor and fix incorrect comment (#1247) + * Fix migration comment (#1241) + * Update locale_en-US.ini (#1235) + * Add LibreJS support (#1201) + * rename OSX to macOS (#1176) + * add mssql to app.ini db config comment (#1172) + * Add MSSQL to issues template (#1171) +* MISC + * Add badge and link to the Matrix room (#2348) + * ignore coverage steps. (#2257) + * Use sqlite3 database as default for Docker image (#2182) + * update drone discord plugin to 0.0.4 version (#1992) + * fix typo (#1990) + * Move 3rd party js/css into `public/vendor` and document sources (#2383) + * Prevent conflicting TOTP accounts by adding AppURL to issuer parameter (#2335) + * Fix variable name typo (#2327) + * Make use of Vue more universal (#2318) + * Remove (almost) server side data rendering from repo-search component (#2317) + * Add OpenID configuration in install page (#2276) + * More tweaks to repo top panel (#2267) + * File path tweaks in UI (#2264) + * Make SHOW_USER_EMAIL also apply to profiles (#2258) + * EnableUnit() -> UnitEnabled() (#2242) + * Prevent selection of diff line numbers (#2240) + * Remove unused variable on makefile (#2225) + * No error log entries for repo 404 (#2200) + * Refactor vue delimeters to use es6 template delimeters (#2171) + * Replace tmp with TMPDIR. (#2152) + * Remove unused files (#2124) + * Improve org error handling (#2117) + * Absolute path for setting.CustomConf (#2085) + * remove deprecated code for Gogs compatible (#2041) + * Refactor session close as xorm already does everything needed internally (#2020) + * SQLite has a query timeout. Hopefully fixes most 'database locked' errors (#1961) + * Use monospace font in githook editor (#1958) + * Fix import order (#1951) + * Gracefully handle bare repositories on API operations. (#1932) + * Fix errors caused by force push (#1927) + * Display URLs in integration test logs (#1924) + * Set TMPDIR environment variable for dump command (#1915) + * Cache ctx.User in retrieveFeeds (#1902) + * Make `LocalCopyPath` a setting instead of a hard-coded path (#1881) + * Add check misspelling (#1877) + * Fix misspelled variables (#1874) + * Gofmt (#1868, #1710, #1662) + * Rename misnamed migration (#1867) + * Support CRLF when splitting code lines for display (#1862) + * Add convert less css file step. (#1861) + * Prevent accidental selection of line numbers in code view (#1860) + * Delete Public SSH Key tmp file after calculating fingerprint (#1855) + * Remove annoying difference in button heights. (#1853) + * Only run test coverage on master branch. (#1838) + * Error from mktemp command in MacOS. (#1837) + * Use writeTmpKeyFile in calcFingerprint (#1828) + * ROOT_URL setting use the default as shown in conf/app.ini (#1823) + * Rename RepoCreationNum -> MaxCreationLimit (#1766) + * Add button to admin ui (#1738) + * Correct spelling mistakes (#1703) + * Make openid support default false for compatible with v1.1 (#1650) + * Send mails as HTML as default. Setting for send as plain text. (#1648) + * fix potential lock when sqlite (#1647) + * Optimize png images via Google zopflipng [ci skip] (#1639) + * Upgrade alpine to v3.5 in Dockerfile (#1633) + * remove unused vendor packages (#1620) + * markup: microoptimise for many short filenames in directory (#1534) + * support health check via / and fix #969 (#1520) + * Remove env user salt since no need to use (#1515) + * Drop db operations from hook commands (#1514) + * Better URL validation (#1507) + * Migrate WatchInfo struct to api (#1492) + * refactor: show command help message. (#1486) + * refactor update ssh key use time (#1466) + * Set VERSION from git once, in a variable (#1447) + * Remove unused mutex field (#1440) + * Simplify settings pages with item list (#1389) + * Clean-up PostgreSQL Tests (#1361) + * refactor: remove workaround after the golang 1.7 release. (#1349) + * Delete the useless code (#1335) + * Run "make fmt" with go-1.6 (#1333) + * Refactor admin/auth/new.tmpl (#1277) + * Refactor repo/issue/view_content.tmpl (#1276) + * Cleaner ui for admin, repo settings, and user settings page (#1269) (#1270) + * Cleaner UI for explore page (#1253) (#1255) + * Synced licenses with github repo (#1246) + * Synced gitignores with github repo (#1245) + * Simplify RepositoryList.loadAttributes() (#1211) + * Move user_follow to separate file (#1210) + * Reduce conditionals in signin/signup inner forms (#1138) + +## [1.1.4](https://github.com/go-gitea/gitea/releases/tag/v1.1.4) - 2017-09-04 + +* BUGFIXES + * Fix rendering of external links (#2292) (#2315) + * Fix deleted milestone bug (#1942) (#2300) + * fix 500 error when view an issue which's milestone deleted (#2297) (#2299) + * Fix SHA1 hash linking (#2143) (#2293) + * back port from #1709 (#2291) + +## [1.1.3](https://github.com/go-gitea/gitea/releases/tag/v1.1.3) - 2017-08-03 + +* BUGFIXES + * Fix PR template error (#2008) + * Fix markdown rendering (fix #1530) (#2043) + * Fix missing less sources for oauth (backport #1288) (#2135) + * Don't ignore gravatar error (#2138) + * Fix diff of renamed and modified file (#2136) + * Fix fast-forward PR bug (#2137) + * Fix some security bugs + +## [1.1.2](https://github.com/go-gitea/gitea/releases/tag/v1.1.2) - 2017-06-13 + +* BUGFIXES + * Enforce netgo build tag while cross-compilation (Backport of #1690) (#1731) + * fix update avatar + * fix delete user failed on sqlite (#1321) + * fix bug not to trim space of login username (#1806) + * Backport bugfixes #1220 and #1393 to v1.1 (#1758) + +## [1.1.1](https://github.com/go-gitea/gitea/releases/tag/v1.1.1) - 2017-05-04 + +* BUGFIXES + * Markdown Sanitation Fix [#1646](https://github.com/go-gitea/gitea/pull/1646) + * Fix broken hooks [#1376](https://github.com/go-gitea/gitea/pull/1376) + * Fix migration issue [#1375](https://github.com/go-gitea/gitea/pull/1375) + * Fix Wiki Issues [#1338](https://github.com/go-gitea/gitea/pull/1338) + * Forgotten migration for wiki githooks [#1237](https://github.com/go-gitea/gitea/pull/1237) + * Commit messages can contain pipes [#1218](https://github.com/go-gitea/gitea/pull/1218) + * Verify external tracker URLs [#1236](https://github.com/go-gitea/gitea/pull/1236) + * Allow upgrade after downgrade [#1197](https://github.com/go-gitea/gitea/pull/1197) + * 500 on delete repo with issue [#1195](https://github.com/go-gitea/gitea/pull/1195) + * INI compat with CrowdIn [#1192](https://github.com/go-gitea/gitea/pull/1192) + +## [1.1.0](https://github.com/go-gitea/gitea/releases/tag/v1.1.0) - 2017-03-09 + +* BREAKING + * The SSH keys can potentially break, make sure to regenerate the authorized keys +* FEATURES + * Git LFSv2 support [#122](https://github.com/go-gitea/gitea/pull/122) + * API endpoints for repo watching [#191](https://github.com/go-gitea/gitea/pull/191) + * Search within private repos [#222](https://github.com/go-gitea/gitea/pull/222) + * Hide user email address on explore page [#336](https://github.com/go-gitea/gitea/pull/336) + * Protected branch system [#339](https://github.com/go-gitea/gitea/pull/339) + * Sendmail for mail delivery [#355](https://github.com/go-gitea/gitea/pull/355) + * API endpoints for org webhooks [#372](https://github.com/go-gitea/gitea/pull/372) + * Enabled MSSQL support [#383](https://github.com/go-gitea/gitea/pull/383) + * API endpoints for org teams [#370](https://github.com/go-gitea/gitea/pull/370) + * API endpoints for collaborators [#375](https://github.com/go-gitea/gitea/pull/375) + * Graceful server restart [#416](https://github.com/go-gitea/gitea/pull/416) + * Commitgraph / timeline on commits page [#428](https://github.com/go-gitea/gitea/pull/428) + * API endpoints for repo forks [#509](https://github.com/go-gitea/gitea/pull/509) + * API endpoints for releases [#510](https://github.com/go-gitea/gitea/pull/510) + * Folder jumping [#511](https://github.com/go-gitea/gitea/pull/511) + * Stars tab on profile page [#519](https://github.com/go-gitea/gitea/pull/519) + * Notification system [#523](https://github.com/go-gitea/gitea/pull/523) + * Push and pull through reverse proxy basic auth [#524](https://github.com/go-gitea/gitea/pull/524) + * Search for issues and pull requests [#530](https://github.com/go-gitea/gitea/pull/530) + * API endpoint for stargazers [#597](https://github.com/go-gitea/gitea/pull/597) + * API endpoints for subscribers [#598](https://github.com/go-gitea/gitea/pull/598) + * PID file support [#610](https://github.com/go-gitea/gitea/pull/610) + * Two factor authentication (2FA) [#630](https://github.com/go-gitea/gitea/pull/630) + * API endpoints for org users [#645](https://github.com/go-gitea/gitea/pull/645) + * Release attachments [#673](https://github.com/go-gitea/gitea/pull/673) + * OAuth2 consumer [#679](https://github.com/go-gitea/gitea/pull/679) + * Add ability to fork your own repos [#761](https://github.com/go-gitea/gitea/pull/761) + * Search repository on dashboard [#773](https://github.com/go-gitea/gitea/pull/773) + * Search bar on user profile [#787](https://github.com/go-gitea/gitea/pull/787) + * Track label changes on issue view [#788](https://github.com/go-gitea/gitea/pull/788) + * Allow using custom time format [#798](https://github.com/go-gitea/gitea/pull/798) + * Redirects for renamed repos [#807](https://github.com/go-gitea/gitea/pull/807) + * Track assignee changes on issue view [#808](https://github.com/go-gitea/gitea/pull/808) + * Track title changes on issue view [#841](https://github.com/go-gitea/gitea/pull/841) + * Archive cleanup action [#885](https://github.com/go-gitea/gitea/pull/885) + * Basic Open Graph support [#901](https://github.com/go-gitea/gitea/pull/901) + * Take back control of Git hooks [#1006](https://github.com/go-gitea/gitea/pull/1006) + * API endpoints for user repos [#1059](https://github.com/go-gitea/gitea/pull/1059) +* BUGFIXES + * Fixed counting issues for issue filters [#413](https://github.com/go-gitea/gitea/pull/413) + * Added back default settings for SSH [#500](https://github.com/go-gitea/gitea/pull/500) + * Fixed repo permissions [#513](https://github.com/go-gitea/gitea/pull/513) + * Issues cannot be created with labels [#622](https://github.com/go-gitea/gitea/pull/622) + * Add a reserved wiki paths check to the wiki [#720](https://github.com/go-gitea/gitea/pull/720) + * Update website binding MaxSize to 255 [#722](https://github.com/go-gitea/gitea/pull/722) + * User can see the private activity on public history [#818](https://github.com/go-gitea/gitea/pull/818) + * Wrong pages number which includes private repositories [#844](https://github.com/go-gitea/gitea/pull/844) + * Trim whitespaces for search keyword [#893](https://github.com/go-gitea/gitea/pull/893) + * Don't rewrite non-gitea public keys [#906](https://github.com/go-gitea/gitea/pull/906) + * Use fingerprint to check instead content for public key [#911](https://github.com/go-gitea/gitea/pull/911) + * Fix random avatars [#1147](https://github.com/go-gitea/gitea/pull/1147) +* ENHANCEMENTS + * Refactored process manager [#75](https://github.com/go-gitea/gitea/pull/75) + * Restrict rights to create new orgs [#193](https://github.com/go-gitea/gitea/pull/193) + * Added label and milestone sorting [#199](https://github.com/go-gitea/gitea/pull/199) + * Make minimum password length configurable [#223](https://github.com/go-gitea/gitea/pull/223) + * Speedup conflict checking on pull requests [#276](https://github.com/go-gitea/gitea/pull/276) + * Added button to delete merged pull request branches [#441](https://github.com/go-gitea/gitea/pull/441) + * Improved issue references within markdown [#471](https://github.com/go-gitea/gitea/pull/471) + * Dutch translation for the landingpage [#487](https://github.com/go-gitea/gitea/pull/487) + * Added Gogs migration script [#532](https://github.com/go-gitea/gitea/pull/532) + * Support a .gitea folder for issue templates [#582](https://github.com/go-gitea/gitea/pull/582) + * Enhanced diff-view coloring [#584](https://github.com/go-gitea/gitea/pull/584) + * Added ETag header to avatars [#721](https://github.com/go-gitea/gitea/pull/721) + * Added option to config to disable local path imports [#724](https://github.com/go-gitea/gitea/pull/724) + * Allow custom public files [#782](https://github.com/go-gitea/gitea/pull/782) + * Added pprof endpoint for debugging [#801](https://github.com/go-gitea/gitea/pull/801) + * Added `X-GitHub-*` headers [#809](https://github.com/go-gitea/gitea/pull/809) + * Fill SSH key title automatically [#863](https://github.com/go-gitea/gitea/pull/863) + * Display Git version on admin panel [#921](https://github.com/go-gitea/gitea/pull/921) + * Expose URL field on issue API [#982](https://github.com/go-gitea/gitea/pull/982) + * Statically compile the binaries [#985](https://github.com/go-gitea/gitea/pull/985) + * Embed build tags into version string [#1051](https://github.com/go-gitea/gitea/pull/1051) + * Gitignore support for FSharp and Clojure [#1072](https://github.com/go-gitea/gitea/pull/1072) + * Custom templates for static builds [#1087](https://github.com/go-gitea/gitea/pull/1087) + * Add ProxyFromEnvironment if none set [#1096](https://github.com/go-gitea/gitea/pull/1096) +* MISC + * Replaced remaining Gogs references + * Added more tests on various packages + * Use Crowdin for translations again + * Resolved some XSS attack vectors + * Optimized and reduced number of database queries + +## [1.0.2](https://github.com/go-gitea/gitea/releases/tag/v1.0.2) - 2017-02-21 + +* BUGFIXES + * Fixed issue counter [#882](https://github.com/go-gitea/gitea/pull/882) + * Fixed XSS vulnerability on wiki page [#955](https://github.com/go-gitea/gitea/pull/955) + * Add data dir without session to dump [#587](https://github.com/go-gitea/gitea/pull/587) + * Fixed wiki page renaming [#958](https://github.com/go-gitea/gitea/pull/958) + * Drop default console logger if not required [#960](https://github.com/go-gitea/gitea/pull/960) + * Fixed docker docs link on install page [#972](https://github.com/go-gitea/gitea/pull/972) + * Handle SetModel errors [#957](https://github.com/go-gitea/gitea/pull/957) + * Fixed XSS vulnerability on milestones [#977](https://github.com/go-gitea/gitea/pull/977) + * Fixed XSS vulnerability on alerts [#981](https://github.com/go-gitea/gitea/pull/981) + +## [1.0.1](https://github.com/go-gitea/gitea/releases/tag/v1.0.1) - 2017-01-05 + +* BUGFIXES + * Fixed localized `MIN_PASSWORD_LENGTH` [#501](https://github.com/go-gitea/gitea/pull/501) + * Fixed 500 error on organization delete [#507](https://github.com/go-gitea/gitea/pull/507) + * Ignore empty wiki repo on migrate [#544](https://github.com/go-gitea/gitea/pull/544) + * Proper check access for forking [#563](https://github.com/go-gitea/gitea/pull/563) + * Fix SSH domain on installer [#506](https://github.com/go-gitea/gitea/pull/506) + * Fix missing data rows on admin UI [#580](https://github.com/go-gitea/gitea/pull/580) + * Do not delete tags with releases by default [#579](https://github.com/go-gitea/gitea/pull/579) + * Fix missing session config data on admin UI [#578](https://github.com/go-gitea/gitea/pull/578) + * Properly show the version within footer on the UI [#593](https://github.com/go-gitea/gitea/pull/593) + +## [1.0.0](https://github.com/go-gitea/gitea/releases/tag/v1.0.0) - 2016-12-23 + +* BREAKING + * We have various changes on the API, scripting against API must be updated +* FEATURES + * Show last login for admins [#121](https://github.com/go-gitea/gitea/pull/121) +* BUGFIXES + * Fixed sender of notifications [#2](https://github.com/go-gitea/gitea/pull/2) + * Fixed keyword hijacking vulnerability [#20](https://github.com/go-gitea/gitea/pull/20) + * Fixed non-markdown readme rendering [#95](https://github.com/go-gitea/gitea/pull/95) + * Allow updating draft releases [#169](https://github.com/go-gitea/gitea/pull/169) + * GitHub API compliance [#227](https://github.com/go-gitea/gitea/pull/227) + * Added commit SHA to tag webhook [#286](https://github.com/go-gitea/gitea/issues/286) + * Secured links via noopener [#315](https://github.com/go-gitea/gitea/issues/315) + * Replace tabs with spaces on wiki title [#371](https://github.com/go-gitea/gitea/pull/371) + * Fixed vulnerability on labels and releases [#409](https://github.com/go-gitea/gitea/pull/409) + * Fixed issue comment API [#449](https://github.com/go-gitea/gitea/pull/449) +* ENHANCEMENTS + * Use proper import path for libravatar [#3](https://github.com/go-gitea/gitea/pull/3) + * Integrated DroneCI for tests and builds [#24](https://github.com/go-gitea/gitea/issues/24) + * Integrated dependency manager [#29](https://github.com/go-gitea/gitea/issues/29) + * Embedded bindata optionally [#30](https://github.com/go-gitea/gitea/issues/30) + * Integrated pagination for releases [#73](https://github.com/go-gitea/gitea/pull/73) + * Autogenerate version on every build [#91](https://github.com/go-gitea/gitea/issues/91) + * Refactored Docker container [#104](https://github.com/go-gitea/gitea/issues/104) + * Added short-hash support for downloads [#211](https://github.com/go-gitea/gitea/issues/211) + * Display tooltip for downloads [#221](https://github.com/go-gitea/gitea/issues/221) + * Improved HTTP headers for issue attachments [#270](https://github.com/go-gitea/gitea/pull/270) + * Integrate public as bindata optionally [#293](https://github.com/go-gitea/gitea/pull/293) + * Integrate templates as bindata optionally [#314](https://github.com/go-gitea/gitea/pull/314) + * Inject more ENV variables into custom hooks [#316](https://github.com/go-gitea/gitea/issues/316) + * Correct LDAP login validation [#342](https://github.com/go-gitea/gitea/pull/342) + * Integrate conf as bindata optionally [#354](https://github.com/go-gitea/gitea/pull/354) + * Serve video files in browser [#418](https://github.com/go-gitea/gitea/pull/418) + * Configurable SSH host binding [#431](https://github.com/go-gitea/gitea/issues/431) +* MISC + * Forked from Gogs and renamed to Gitea + * Catching more errors with logs + * Fixed all linting errors + * Made the go linter entirely happy + * Really integrated vendoring diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c11ad4a7a..04fffd4a4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,148 @@ # Changelog -This changelog goes through all the changes that have been made in each release +This changelog goes through the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.com). +## [1.21.11](https://github.com/go-gitea/gitea/releases/tag/v1.21.11) - 2024-04-07 + +* SECURITY + * Use go1.21.9 to include Golang security fix + * Fix possible renderer security problem (#30136) (#30315) + * Performance optimization for git push and check permissions for push options (#30104) (#30354) +* BUGFIXES + * Fix close file in the Upload func (#30262) (#30269) + * Fix inline math blocks can't be preceeded/followed by alphanumerical characters (#30175) (#30250) + * Fix missing 0 prefix of GPG key id (#30245) (#30247) + * Include encoding in signature payload (#30174) (#30181) + * Move from `max( id )` to `max( index )` for latest commit statuses (#30076) (#30155) + * Load attachments for code comments (#30124) (#30126) + * Fix gitea doctor will remove repo-avatar files when executing command storage-archives (#30094) (#30120) + * Fix possible data race on tests (#30093) (#30108) + * Fix duplicate migrated milestones (#30102) (#30105) + * Fix panic for fixBrokenRepoUnits16961 (#30068) (#30100) + * Fix incorrect SVGs (#30086) (#30087) + * Fix create commit status (#30225) (#30340) + * Fix misuse of unsupported global variables (#30402) + * Fix to delete the cookie when AppSubURL is non-empty (#30375) (#30468) + * Avoid user does not exist error when detecting schedule actions when the commit author is an external user (#30357) (#30408) + * Change the default maxPerPage for gitbucket (#30392) (#30471) + * Check the token's owner and repository when registering a runner (#30406) (#30412) + * Avoid losing token when updating mirror settings (#30429) (#30466) + * Fix commit status cache which missed target_url (#30426) (#30445) + * Fix rename branch 500 when the target branch is deleted but exist in database (#30430) (#30437) + * Fix mirror error when mirror repo is empty (#30432) (#30467) + * Use db.ListOptions directly instead of Paginator interface to make it easier to use and fix performance of /pulls and /issues (#29990) (#30447) + * Fix code owners will not be mentioned when a pull request comes from a forked repository (#30476) (#30497) +* DOCS + * Update actions variables documents (#30394) (#30405) +* MISC + * Update katex to 0.16.10 (#30089) + * Upgrade go-sqlite to v1.14.22 (#30462) + +## [1.21.10](https://github.com/go-gitea/gitea/releases/tag/v1.21.10) - 2024-03-25 + +* BUGFIXES + * Fix Add/Remove WIP on pull request title failure (#29999) (#30066) + * Fix misuse of `TxContext` (#30061) (#30062) + * Respect DEFAULT_ORG_MEMBER_VISIBLE setting when adding creator to org (#30013) (#30035) + * Escape paths for find file correctly (#30026) (#30031) + * Remove duplicate option in admin screen and now-unused translation keys (#28492) (#30024) + * Fix manual merge form and 404 page templates (#30000) + +## [1.21.9](https://github.com/go-gitea/gitea/releases/tag/v1.21.9) - 2024-03-21 + +* PERFORMANCE + * Only do counting when count_only=true for repo dashboard (#29884) (#29905) + * Add cache for dashboard commit status (#29932) +* ENHANCEMENT + * Make runs-on support variable expression (#29468) (#29782) + * Show Actions post step when it's running (#29926) (#29928) +* BUGFIXES + * Fix PR creation via API between branches of the same repo with head field namespaced (#26986) (#29857) + * Fix and rewrite markup anchor processing (#29931) (#29946) + * Notify reviewers added via CODEOWNERS (#29842) (#29902) + * Fix template error when comment review doesn't exist (#29888) (#29889) + * Fix user id column case (#29863) (#29867) + * Make meilisearch do exact search for issues (#29740 & #29671) (#29846) + * Fix the `for` attribute not pointing to the ID of the color picker (#29813) (#29815) + * Fix codeowner detected diff base branch to mergebase (#29783) (#29807) + * Fix Safari spinner rendering (#29801) (#29802) + * Fix missing translation on milestones (#29785) (#29789) + * Fix user router possible panic (#29751) (#29786) + * Fix possible NPE in ToPullReviewList (#29759) (#29775) + * Fix the wrong default value of ENABLE_OPENID_SIGNIN on docs (#29925) (#29927) + * Solving the issue of UI disruption when the review is deleted without refreshing (#29951) (#29968) + * Fix loadOneBranch panic (#29938) (#29939) + * Fix invalid link of the commit status when ref is tagged (#29752) (#29908) + * Editor error message misleading due to re-used key. (#29859) (#29876) + * Fix double border and border-radius on empty action steps (#29845) (#29850) + * Use `Temporal.PlainDate` for absolute dates (#29804) (#29808) + * Fix incorrect package link method calls in templates (#29580) (#29764) + * Fix the bug that the user may log out if GetUserByID returns unknown error (#29962) (#29964) + * Performance improvements for pull request list page (#29900) (#29972) + * Fix bugs in rerunning jobs (#29983) (#29955) + +## [1.21.8](https://github.com/go-gitea/gitea/releases/tag/v1.21.8) - 2024-03-12 + +* SECURITY + * Only use supported sort orders for "/explore/users" page (#29430) (#29443) +* ENHANCEMENTS + * Fix wrong line number in code search result (#29260) (#29623) +* BUGFIXES + * Use Get but not Post to get actions artifacts (#29734) (#29737) + * Fix inconsistent rendering of block mathematical expressions (#29677) (#29711) + * Fix rendering internal file links in org (#29669) (#29705) + * Don't show AbortErrors on logout (#29639) (#29667) + * Fix user-defined markup links targets (#29305) (#29666) + * Fix incorrect rendering csv file when file size is larger than UI.CSV.MaxFileSize (#29653) (#29663) + * Fix hidden test's failure (#29254) (#29662) + * Add empty repo check-in DetectAndHandleSchedules (#29606) (#29659) + * Fix 500 when deleting an account with an incorrect password or unsupported login type (#29579) (#29656) + * Use strict protocol check when redirect (#29642) (#29644) + * Avoid issue info panic (#29625) (#29632) + * Avoid unexpected panic in graceful manager (#29629) (#29630) + * Make "/user/login" page redirect if the current user has signed in (#29583) (#29599) + * Fix workflow trigger event IssueChangeXXX bug (#29559) (#29565) + * Fix incorrect cookie path for AppSubURL (#29534) (#29552) + * Fix queue worker incorrectly stopped when there are still more items in the queue (#29532) (#29546) + * Fix incorrect redirection when creating a PR fails (#29537) (#29543) + * Fix incorrect subpath in links (#29535) (#29541) + * Fix issue link does not support quotes (#29484) (#29487) (#29536) + * Fix issue & comment history bugs (#29525) (#29527) + * Set pre-step status to `skipped` if the job is skipped (#29489) (#29523) + * Fix/Improve `processWindowErrorEvent` (#29407) (#29480) + * Fix counter display number incorrectly displayed on the page (#29448) (#29478) + * Fix workflow trigger event bugs (#29467) (#29475) + * Fix URL calculation in the clone input box (#29470) (#29473) + * The job should always run when `if` is `always()` (#29464) (#29469) + * Fix template bug (#27581) (#29446) + * Not trigger all jobs anymore when re-running the first job (#29439) (#29441) + * Ignore empty repo for CreateRepository in action notifier (#29416) (#29424) + * Fix incorrect tree path value for patch editor (#29377) (#29421) + * Add missing database transaction for new issues (#29490) (#29607) + * Fix 500 when pushing release to an empty repo (#29554) (#29564) + * Fix incorrect relative/absolute URL usages (#29531) (#29547) + * Fix wrong test usage of `AppSubURL` (#29459) (#29488) + * Fix missed return (#29450) (#29453) + * Fixing the issue when status checks per rule matches multiple actions (#29631) (#29655) + * Improve contrast on blame timestamp, fix double border (#29482) (#29485) + +## [1.21.7](https://github.com/go-gitea/gitea/releases/tag/v1.21.7) - 2024-02-26 + +* ENHANCEMENTS + * Users with `read` permission of pull requests can be assigned too (#27263) (#29372) +* BUGFIXES + * Do not double close reader (#29354) (#29370) + * Display friendly error message (#29105) (#29363) + * Fix project counter in organization/individual profile (#28068) (#29361) + * Fix validity of the FROM email address not being checked (#29347) (#29360) + * Fix tarball/zipball download bug (#29342) (#29352) +* DOCS + * Docker Tag Information in Docs (#29047) (#29362) +* MISC + * Enforce maxlength in frontend (#29389) (#29396) + ## [1.21.6](https://github.com/go-gitea/gitea/releases/tag/v1.21.6) - 2024-02-22 * SECURITY @@ -3371,5219 +3510,6 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * MISC * Update JS dependencies (#17611) -## [1.15.11](https://github.com/go-gitea/gitea/releases/tag/v1.15.11) - 2022-01-29 +## Archived releases -* SECURITY - * Only view milestones from current repo (#18414) (#18418) -* BUGFIXES - * Fix broken when no commits and default branch is not master (#18422) (#18424) - * Fix commit's time (#18375) (#18409) - * Fix restore without topic failure (#18387) (#18401) - * Fix mermaid import in 1.15 (it uses ESModule now) (#18382) - * Update to go/text 0.3.7 (#18336) -* MISC - * Upgrade EasyMDE to 2.16.1 (#18278) (#18279) - -## [1.15.10](https://github.com/go-gitea/gitea/releases/tag/v1.15.10) - 2022-01-14 - -* BUGFIXES - * Fix inconsistent PR comment counts (#18260) (#18261) - * Fix release link broken (#18252) (#18253) - * Fix update user from site administration page bug (#18250) (#18251) - * Set HeadCommit when creating tags (#18116) (#18173) - * Use correct translation key for error messages due to max repo limits (#18135 & #18153) (#18152) - * Fix purple color in suggested label colors (#18241) (#18242) -* SECURITY - * Bump mermaid from 8.10.1 to 8.13.8 (#18198) (#18206) - -## [1.15.9](https://github.com/go-gitea/gitea/releases/tag/v1.15.9) - 2021-12-30 - -* BUGFIXES - * Fix wrong redirect on org labels (#18128) (#18134) - * Fix: unstable sort skips/duplicates issues across pages (#18094) (#18095) - * Revert "Fix delete u2f keys bug (#18042)" (#18107) - * Migrating wiki don't require token, so we should move it out of the require form (#17645) (#18104) - * Prevent NPE if gitea uploader fails to open url (#18080) (#18101) - * Reset locale on login (#17734) (#18100) - * Correctly handle failed migrations (#17575) (#18099) - * Instead of using routerCtx just escape the url before routing (#18086) (#18098) - * Quote references to the user table in consistency checks (#18072) (#18073) - * Add NotFound handler (#18062) (#18067) - * Ensure that git repository is closed before transfer (#18049) (#18057) - * Use common sessioner for API and web routes (#18114) -* TRANSLATION - * Fix code search result hint on zh-CN (#18053) - -## [1.15.8](https://github.com/go-gitea/gitea/releases/tag/v1.15.8) - 2021-12-20 - -* BUGFIXES - * Move POST /{username}/action/{action} to simply POST /{username} (#18045) (#18046) - * Fix delete u2f keys bug (#18040) (#18042) - * Reset Session ID on login (#18018) (#18041) - * Prevent off-by-one error on comments on newly appended lines (#18029) (#18035) - * Stop printing 03d after escaped characters in logs (#18030) (#18034) - * Reset locale on login (#18023) (#18025) - * Fix reset password email template (#17025) (#18022) - * Fix outType on gitea dump (#18000) (#18016) - * Ensure complexity, minlength and isPwned are checked on password setting (#18005) (#18015) - * Fix rename notification bug (#18011) - * Prevent double decoding of % in url params (#17997) (#18001) - * Prevent hang in git cat-file if the repository is not a valid repository (Partial #17991) (#17992) - * Prevent deadlock in create issue (#17970) (#17982) -* TESTING - * Use non-expiring key. (#17984) (#17985) - -## [1.15.7](https://github.com/go-gitea/gitea/releases/tag/v1.15.7) - 2021-12-01 - -* ENHANCEMENTS - * Only allow webhook to send requests to allowed hosts (#17482) (#17510) - * Fix login redirection links (#17451) (#17473) -* BUGFIXES - * Fix database inconsistent when admin change user email (#17549) (#17840) - * Use correct user on releases (#17806) (#17818) - * Fix commit count in tag view (#17698) (#17790) - * Fix close issue but time watcher still running (#17643) (#17761) - * Fix Migrate Description (#17692) (#17727) - * Fix bug when project board get open issue number (#17703) (#17726) - * Return 400 but not 500 when request archive with wrong format (#17691) (#17700) - * Fix bug when read mysql database max lifetime (#17682) (#17690) - * Fix database deadlock when update issue labels (#17649) (#17665) - * Fix bug on detect issue/comment writer (#17592) - * Remove appSubUrl from pasted images (#17572) (#17588) - * Make `ParsePatch` more robust (#17573) (#17580) - * Fix stats upon searching issues (#17566) (#17578) - * Escape issue titles in comments list (#17555) (#17556) - * Fix zero created time bug on commit api (#17546) (#17547) - * Fix database keyword quote problem on migration v161 (#17522) (#17523) - * Fix email with + when active (#17518) (#17520) - * Stop double encoding blame commit messages (#17498) (#17500) - * Quote the table name in CountOrphanedObjects (#17487) (#17488) - * Run Migrate in Install rather than just SyncTables (#17475) (#17486) -* BUILD - * Fix golangci-lint warnings (#17598 et al) (#17668) -* MISC - * Preserve color when inverting emojis (#17797) (#17799) - -## [1.15.6](https://github.com/go-gitea/gitea/releases/tag/v1.15.6) - 2021-10-28 - -* BUGFIXES - * Prevent panic in serv.go with Deploy Keys (#17434) (#17435) - * Fix CSV render error (#17406) (#17431) - * Read expected buffer size (#17409) (#17430) - * Ensure that restricted users can access repos for which they are members (#17460) (#17464) - * Make commit-statuses popup show correctly (#17447) (#17466) -* TESTING - * Add integration tests for private.NoServCommand and private.ServCommand (#17456) (#17463) - -## [1.15.5](https://github.com/go-gitea/gitea/releases/tag/v1.15.5) - 2021-10-21 - -* SECURITY - * Upgrade Bluemonday to v1.0.16 (#17372) (#17374) - * Ensure correct SSH permissions check for private and restricted users (#17370) (#17373) -* BUGFIXES - * Prevent NPE in CSV diff rendering when column removed (#17018) (#17377) - * Offer rsa-sha2-512 and rsa-sha2-256 algorithms in internal SSH (#17281) (#17376) - * Don't panic if we fail to parse U2FRegistration data (#17304) (#17371) - * Ensure popup text is aligned left (backport for 1.15) (#17343) - * Ensure that git daemon export ok is created for mirrors (#17243) (#17306) - * Disable core.protectNTFS (#17300) (#17302) - * Use pointer for wrappedConn methods (#17295) (#17296) - * AutoRegistration is supposed to be working with disabled registration (backport) (#17292) - * Handle duplicate keys on GPG key ring (#17242) (#17284) - * Fix SVG side by side comparison link (#17375) (#17391) - -## [1.15.4](https://github.com/go-gitea/gitea/releases/tag/v1.15.4) - 2021-10-08 - -* BUGFIXES - * Raw file API: don't try to interpret 40char filenames as commit SHA (#17185) (#17272) - * Don't allow merged PRs to be reopened (#17192) (#17271) - * Fix incorrect repository count on organization tab of dashboard (#17256) (#17266) - * Fix unwanted team review request deletion (#17257) (#17264) - * Fix broken Activities link in team dashboard (#17255) (#17258) - * API pull's head/base have correct permission(#17214) (#17245) - * Fix strange behavior of DownloadPullDiffOrPatch in incorrect index (#17223) (#17227) - * Upgrade xorm to v1.2.5 (#17177) (#17188) - * Fix missing repo link in issue/pull assigned emails (#17183) (#17184) - * Fix bug of get context user (#17169) (#17172) - * Nicely handle missing user in collaborations (#17049) (#17166) - * Add Horizontal scrollbar to inner menu on Chrome (#17086) (#17164) - * Fix wrong i18n keys (#17150) (#17153) - * Fix Archive Creation: correct transaction ending (#17151) - * Prevent panic in Org mode HighlightCodeBlock (#17140) (#17141) - * Create doctor command to fix repo_units broken by dumps from 1.14.3-1.14.6 (#17136) (#17137) -* ENHANCEMENT - * Check user instead of organization when creating a repo from a template via API (#16346) (#17195) -* TRANSLATION - * v1.15 fix Sprintf format 'verbs' in locale files (#17187) - -## [1.15.3](https://github.com/go-gitea/gitea/releases/tag/v1.15.3) - 2021-09-19 - -* ENHANCEMENTS - * Add fluid to ui container class to remove margin (#16396) (#16976) - * Add caller to cat-file batch calls (#17082) (#17089) -* BUGFIXES - * Render full plain readme. (#17083) (#17090) - * Upgrade xorm to v1.2.4 (#17059) - * Fix bug of migrate comments which only fetch one page (#17055) (#17058) - * Do not show issue context popup on external issues (#17050) (#17054) - * Decrement Fork Num when converting from Fork (#17035) (#17046) - * Correctly rollback in ForkRepository (#17034) (#17045) - * Fix missing close in WalkGitLog (#17008) (#17009) - * Add prefix to SVG id/class attributes (#16997) (#17000) - * Fix bug of migrated repository not index (#16991) (#16996) - * Skip AllowedUserVisibilityModes validation on update user if it is an organisation (#16988) (#16990) - * Fix storage Iterate bug and Add storage doctor to delete garbage attachments (#16971) (#16977) - * Fix issue with issue default mail template (#16956) (#16975) - * Ensure that rebase conflicts are handled in updates (#16952) (#16960) - * Prevent panic on diff generation (#16950) (#16951) - -## [1.15.2](https://github.com/go-gitea/gitea/releases/tag/v1.15.2) - 2021-09-03 - -* BUGFIXES - * Add unique constraint back into issue_index (#16938) - * Close storage objects before cleaning (#16934) (#16942) - -## [1.15.1](https://github.com/go-gitea/gitea/releases/tag/v1.15.1) - 2021-09-02 - -* BUGFIXES - * Allow BASIC authentication access to /:owner/:repo/releases/download/* (#16916) (#16923) - * Prevent leave changes dialogs due to autofill fields (#16912) (#16920) - * Ignore review comment when ref commit is missed (#16905) (#16919) - * Fix wrong attachment removal (#16915) (#16917) - * Gitlab Migrator: dont ignore reactions of last request (#16903) (#16913) - * Correctly return the number of Repositories for Organizations (#16807) (#16911) - * Test if LFS object is accessible (#16865) (#16904) - * Fix git.Blob.DataAsync(): close pipe since we return a NopCloser (#16899) (#16900) - * Fix dump and restore repository (#16698) (#16898) - * Repare and Improve GetDiffRangeWithWhitespaceBehavior (#16894) (#16895) - * Fix wiki raw commit diff/patch view (#16891) (#16892) - * Ensure wiki repos are all closed (#16886) (#16888) - * List limited and private orgs if authenticated on API (#16866) (#16879) - * Simplify split diff view generation and remove JS dependency (#16775) (#16863) - * Ensure that the default visibility is set on the user create page (#16845) (#16862) - * In Render tolerate not being passed a context (#16842) (#16858) - * Upgrade xorm to v1.2.2 (#16663) & Add test to ensure that dumping of login sources remains correct (#16847) (#16848) - * Report the correct number of pushes on the feeds (#16811) (#16822) - * Add primary_key to issue_index (#16813) (#16820) - * Prevent NPE on empty commit (#16812) (#16819) - * Fix branch pagination error (#16805) (#16816) - * Add missing return to handleSettingRemoteAddrError (#16794) (#16795) - * Remove spurious / from issues.opened_by (#16793) - * Ensure that template compilation panics are sent to the logs (#16788) (#16792) - * Update caddyserver/certmagic (#16789) (#16790) - -## [1.15.0](https://github.com/go-gitea/gitea/releases/tag/v1.15.0) - 2021-08-21 - -* BREAKING - * Make app.ini permissions more restrictive (#16266) - * Refactor Webhook + Add X-Hub-Signature (#16176) - * Add asymmetric JWT signing (#16010) - * Clean-up the settings hierarchy for issue_indexer queue (#16001) - * Change default queue settings to be low go-routines (#15964) - * Improve assets handler middleware (#15961) - * Rename StaticUrlPrefix to AssetUrlPrefix (#15779) - * Use a generic markup class to display externally rendered files and diffs (#15735) - * Add frontend testing, require node 12 (#15315) - * Move (custom) assets into subpath `/assets` (#15219) - * Use level config in log section when sub log section not set level (#15176) - * Links in markdown should be absolute to the repository not the server (#15088) - * Upgrade to the latest version of golang-jwt (#16590) (#16606) - * Set minimum supported version of go to 1.16 (#16710) -* SECURITY - * Encrypt LDAP bind password in db with SECRET_KEY (#15547) - * Remove random password in Dockerfiles (#15362) - * Upgrade to the latest version of golang-jwt and increase minimum go to 1.15 (#16590) (#16606) - * Correctly create of git-daemon-export-ok files (#16508) (#16514) - * Don't show private user's repo in explore view (#16550) (#16554) - * Update node tar dependency to 6.1.6 (#16622) (#16623) -* FEATURES - * Update Go-Git to take advantage of LargeObjectThreshold (#16316) - * Support custom mime type mapping for text files (#16304) - * Link to previous blames in file blame page (#16259) - * Add LRU mem cache implementation (#16226) - * Localize Email Templates (#16200) - * Make command in authorized keys a template (#16003) - * Add possibility to make branch in branch page (#15960) - * Add email headers (#15939) - * Make tasklist checkboxes clickable (#15791) - * Add selecting tags on the compare page (#15723) - * Add cron job to delete old actions from database (#15688) - * On open repository open common cat file batch and batch-check (#15667) - * Add tag protection (#15629) - * Add push to remote mirror repository (#15157) - * Add Image Diff for SVG files (#14867) - * Add dashboard milestone search and repo milestone search by name. (#14866) - * Add LFS Migration and Mirror (#14726) - * Improve notifications for WIP draft PR's (#14663) - * Disable Stars config option (#14653) - * GPG Key Ownership verification with Signed Token (#14054) - * OAuth2 auto-register (#5123) -* API - * Return updated repository when changing repository using API (#16420) - * Let branch/tag name be a valid ref to get CI status (#16400) - * Add endpoint to get commits of PR (#16300) - * Allow COMMENT reviews to not specify a body (#16229) - * Add subject-type filter to list notification API endpoints (#16177) - * ListReleases add filter for draft and pre-releases (#16175) - * ListIssues add more filters (#16174) - * Issue Search Add filter for MilestoneNames (#16173) - * GET / SET User Settings (#16169) - * Expose repo.GetReviewers() & repo.GetAssignees() (#16168) - * User expose counters (#16167) - * Add repoGetTag (#16166) - * Add repoCreateTag (#16165) - * Creating a repo from a template repo via API (#15958) - * Add Active and ProhibitLogin to API (#15689) - * Add Location, Website and Description to API (#15675) - * Expose resolver via API (#15167) - * Swagger AccessToken fixes (#16574) (#16597) - * Set AllowedHeaders on API CORS handler (#16524) (#16618) -* ENHANCEMENTS - * Support HTTP/2 in Let's Encrypt (#16371) - * Introduce NotifySubjectType (#16320) - * Add forge emojies (#16296) - * Implemented head_commit for webhooks (#16282) - * Upgrade Gliderlabs SSH to 0.3.3 and add FailedConnectionCallback (#16278) - * Add previous/next buttons to review comments (#16273) - * Review comments: break-word for long file names (#16272) - * Add configuration to restrict allowed user visibility modes (#16271) - * Add scroll-margin-top to account for sticky header (#16269) - * Add --quiet and --verbose to gitea web to control initial logging (#16260) - * Use gitea logging module for git module (#16243) - * Add tests for all webhooks (#16214) - * Add button to delete undeleted repositories from failed migrations (#16197) - * Speed up git diff highlight generation (#16180) - * Add OpenID claims "profile" and "email". (#16141) - * Reintroduce squash merge default comment as a config setting (#16134) - * Add sanitizer rules per renderer (#16110) - * Improve performance of dashboard list orgs (#16099) - * Refactor assert statements in tests (#16089) - * Add sso.Group, context.Auth, context.APIAuth to allow auth special routes (#16086) - * Remove unnecessary goroutine (#16080) - * Add attachments for PR reviews (#16075) - * Make the github migration less rate limit waiting to get comment per page from repository but not per issue (#16070) - * Add Visible modes function from Organisation to Users too (#16069) - * Add checkbox to delete pull branch after successful merge (#16049) - * Make commit info cancelable (#16032) - * Make modules/context.Context a context.Context (#16031) - * Unified custom config creation (#16012) - * Make sshd_config more flexible regarding connections (#16009) - * Append to existing trailers in generated squash commit message (#15980) - * Always store primary email address into email_address table and also the state (#15956) - * Load issue/PR context popup data only when needed (#15955) - * Remove remaining fontawesome usage in templates (#15952) - * Remove fomantic accordion module (#15951) - * Small refactoring of modules/private (#15947) - * Double the avatar size factor (#15941) - * Add curl to rootless docker image (#15908) - * Replace clipboard.js with async clipboard api (#15899) - * Allow custom highlight mapping beyond file extensions (#15808) - * Add trace logging to SSO methods (#15803) - * Refactor routers directory (#15800) - * Allow only internal registration (#15795) - * Add a new internal hook to save ssh log (#15787) - * Respect default merge message syntax when parsing item references (#15772) - * OAuth2 login: Set account link to "login" as default behavior (#15768) - * Use single shared random string generation function (#15741) - * Hold the event source when there are no listeners (#15725) - * Code comments improvements (#15722) - * Provide OIDC compliant user info endpoint (#15721) - * Fix webkit calendar icon color on arc-green (#15713) - * Improve Light Chroma style (#15699) - * Only use boost workers for leveldb shadow queues (#15696) - * Add compare tag dropdown to releases page (#15695) - * Add caret styling CSS (#15651) - * Remove x-ua-compatible meta tag (#15640) - * Refactor of link creation (#15619) - * Add a new table issue_index to store the max issue index so that issue could be deleted with no duplicated index (#15599) - * Rewrite of the LFS server (#15523) - * Display more repository type on admin repository management (#15440) - * Remove usage of some JS globals (#15378) - * SHA in merged commit comment should be rendered ui sha (#15376) - * Add well-known config for OIDC (#15355) - * Use route rather than use thus reducing the number of stack frames (#15301) - * Code Formats, Nits & Unused Func/Var deletions (#15286) - * Let package git depend on setting but not opposite (#15241) - * Fixed sanitize errors (#15240) - * response simple text message for not html request when 404 (#15229) - * Remove file-loader dependency (#15196) - * Refactor renders (#15175) - * Add mimetype mapping settings (#15133) - * Add Status Updates whilst Gitea migrations are occurring (#15076) - * Reload locales in initialisation if needed by utilizing i18n.Reset (#15073) - * Counterwork seemingly unclickable repo button labels (#15064) - * Add DefaultMergeStyle option to repository (#14789) - * Added support for gopher URLs. (#14749) - * Rework repository archive (#14723) - * Add links to toggle WIP status (#14677) - * Add Tabular Diff for CSV files (#14661) - * Use milestone deadline when sorting issues (#14551) -* BUGFIXES - * Fix invalid params and typo of email templates (#16394) - * Fix activation of primary email addresses (#16385) - * Fix calculation for finalPage in repo-search component (#16382) - * Specify user in rootless container numerically (#16361) - * Detect encoding changes while parsing diff (#16330) - * Fix U2F error reasons always hidden (#16327) - * Prevent zombie processes (#16314) - * Escape reference to `user` table in models.SearchEmails (#16313) - * Fix default push instructions on empty repos (#16302) - * Fix modified files list in webhooks when there is a space (#16288) - * Fix webhook commits wrong hash on HEAD reset (#16283) - * Fuzzer finds an NPE due to incorrect URLPrefix (#16249) - * Don't WARN log UserNotExist errors on ExternalUserLogin failure (#16238) - * Do not show No match found for tribute (#16231) - * Fix "Copy Link" for pull requests (#16230) - * Fix diff expansion is missing final line in a file (#16222) - * Fix private repo permission problem (#16142) - * Fix not able to update local created non-urlencoded wiki pages (#16139) - * More efficiently parse shas for shaPostProcessor (#16101) - * Fix `doctor --run check-db-consistency --fix` with label fix (#16094) - * Prevent webhook action buttons from shifting (#16087) - * Change default TMPDIR path in rootless containers (#16077) - * Fix typo and add TODO notice (#16064) - * Use git log name-status in get last commit (#16059) - * Fix 500 Error with branch and tag sharing the same name (#16040) - * Fix get tag when migration (#16014) - * Add custom emoji support (#16004) - * Use filepath.ToSlash and Join in indexer defaults and queues (#15971) - * Add permission check for ``GenerateRepository`` (#15946) - * Ensure settings for Service and Mailer are read on the install page (#15943) - * Fix layout of milestone view (#15927) - * Unregister non-matching serviceworkers (#15834) - * Multiple Queue improvements: LevelDB Wait on empty, shutdown empty shadow level queue, reduce goroutines etc (#15693) - * Attachment support repository route (#15580) - * Fix missing icons and colorpicker when mounted on suburl (#15501) - * Create a session on ReverseProxy and ensure that ReverseProxy users cannot change username (#15304) - * Prevent double-login for Git HTTP and LFS and simplify login (#15303) - * Resolve Object { type: "error", data: undefined } in stopwatch.js (#15278) - * Fix heatmap activity (#15252) - * Remove vendored copy of fomantic-dropdown (#15193) - * Update repository size on cron gc task (#15177) - * Add NeedPostProcess for Parser interface to improve performance of csv parser and some external parser (#15153) - * Add code block highlight to orgmode back (#14222) - * Remove User.GetOrganizations() (#14032) - * Restore Accessibility for Dropdown (#16576) (#16617) - * Pass down SignedUserName down to AccessLogger context (#16605) (#16616) - * Fix table alignment in markdown (#16596) (#16602) - * Fix 500 on first wiki page (#16586) (#16598) - * Lock goth/gothic and Re-attempt OAuth2 registration on login if registration failed at startup (#16564) (#16570) - * Upgrade levelqueue to v0.4.0 (#16560) (#16561) - * Handle too long PR titles correctly (#16517) (#16549) - * Fix data race in bleve indexer (#16474) (#16509) - * Restore CORS on git smart http protocol (#16496) (#16506) - * Fix race in log (#16490) (#16505) - * Fix prepareWikiFileName to respect existing unescaped files (#16487) (#16498) - * Make cancel from CatFileBatch and CatFileBatchCheck wait for the command to end (#16479) (#16480) - * Update notification table with only latest data (#16445) (#16469) - * Fix crash following ldap authentication update (#16447) (#16448) - * Fix direct creation of external users on admin page (partial #16612) (#16613) - * Prevent 500 on draft releases without tag (#16634) (#16636) - * Restore creation of git-daemon-export-ok files (#16508) (#16514) - * Fix data race in bleve indexer (#16474) (#16509) - * Restore CORS on git smart http protocol (#16496) (#16506) - * Fix race in log (#16490) (#16505) - * Fix prepareWikiFileName to respect existing unescaped files (#16487) (#16498) - * Make cancel from CatFileBatch and CatFileBatchCheck wait for the command to end (#16479) (#16480) - * Update notification table with only latest data (#16445) (#16469) - * Fix crash following ldap authentication update (#16447) (#16448) - * Restore compatibility with SQLServer 2008 R2 in migrations (#16638) - * Fix direct creation of external users on admin page (#16613) - * Fix go-git implementation of GetNote when passed a non-existent commit (#16658) (#16659) - * Fix NPE in fuzzer (#16680) (#16682) - * Set issue_index when finishing migration (#16685) (#16687) - * Skip patch download when no patch file exists (#16356) (#16681) - * Ensure empty lines are copiable and final new line too (#16678) (#16692) - * Fix wrong user in OpenID response (#16736) (#16741) - * Do not use thin scrollbars on Firefox (#16738) (#16745) - * Recreate Tables should Recreate indexes on MySQL (#16718) (#16739) - * Keep attachments on tasklist update (#16750) (#16757) -* TESTING - * Bump `postgres` and `mysql` versions (#15710) - * Add tests for clone from wiki (#15513) - * Fix Benchmark tests, remove a broken one & add two new (#15250) - * Create Proper Migration tests (#15116) -* TRANSLATION - * Use a special name for update default branch on repository setting (#15893) - * Fix mirror_lfs source string in en-US locale (#15369) -* BUILD - * Upgrade xorm to v1.1.1 (#16339) - * Disable legal comments in esbuild (#15929) - * Switch to Node 16 to build fronted (#15804) - * Use esbuild to minify CSS (#15756) - * Use binary version of revive linter (#15739) - * Fix: npx webpack make: *** [Makefile:699: public/js/index.js] Error -… (#15465) - * Stop packaging node_modules in release tarballs (#15273) - * Introduce esbuild on webpack (#14578) -* DOCS - * Update queue workers documentation (#15999) - * Comment out app.example.ini (#15807) - * Improve logo customization docs (#15754) - * Add some response status on api docs (#15399) - * Rework Token API comments (#15162) - * Add better errors for disabled account recovery (#15117) -* MISC - * Remove utf8 option from installation page (#16126) - * Use Wants= over Requires= in systemd file (#15897) - -## [1.14.7](https://github.com/go-gitea/gitea/releases/tag/v1.14.7) - 2021-09-02 - -* BUGFIXES - * Add missing gitRepo close at GetDiffRangeWithWhitespaceBehavior (Partial #16894) (#16896) - * Fix wiki raw commit diff/patch view (#16891) (#16893) - * Ensure wiki repos are all closed (#16886) (#16889) - * Upgrade xorm to v1.2.2 (#16663) & Add test to ensure that dumping of login sources remains correct (#16847) (#16849) - * Recreate Tables should Recreate indexes on MySQL (#16718) (#16740) - -## [1.14.6](https://github.com/go-gitea/gitea/releases/tag/v1.14.6) - 2021-08-04 - -* SECURITY - * Bump github.com/markbates/goth from v1.67.1 to v1.68.0 (#16538) (#16540) - * Switch to maintained JWT lib (#16532) (#16535) - * Upgrade to latest version of golang-jwt (as forked for 1.14) (#16590) (#16607) -* BUGFIXES - * Add basic edit ldap auth test & actually fix #16252 (#16465) (#16495) - * Make cancel from CatFileBatch and CatFileBatchCheck wait for the command to end (#16479) (#16481) - -## [1.14.5](https://github.com/go-gitea/gitea/releases/tag/v1.14.5) - 2021-07-16 - -* SECURITY - * Hide mirror passwords on repo settings page (#16022) (#16355) - * Update bluemonday to v1.0.15 (#16379) (#16380) -* BUGFIXES - * Retry rename on lock induced failures (#16435) (#16439) - * Validate issue index before querying DB (#16406) (#16410) - * Fix crash following ldap authentication update (#16447) (#16449) -* ENHANCEMENTS - * Redirect on bad CSRF instead of presenting bad page (#14937) (#16378) - -## [1.14.4](https://github.com/go-gitea/gitea/releases/tag/v1.14.4) - 2021-07-06 - -* BUGFIXES - * Fix relative links in postprocessed images (#16334) (#16340) - * Fix list_options GetStartEnd (#16303) (#16305) - * Fix API to use author for commits instead of committer (#16276) (#16277) - * Handle misencoding of login_source cfg in mssql (#16268) (#16275) - * Fixed issues not updated by commits (#16254) (#16261) - * Improve efficiency in FindRenderizableReferenceNumeric and getReference (#16251) (#16255) - * Use html.Parse rather than html.ParseFragment (#16223) (#16225) - * Fix milestone counters on new issue (#16183) (#16224) - * reqOrgMembership calls need to be preceded by reqToken (#16198) (#16219) - -## [1.14.3](https://github.com/go-gitea/gitea/releases/tag/v1.14.3) - 2021-06-18 - -* SECURITY - * Encrypt migration credentials at rest (#15895) (#16187) - * Only check access tokens if they are likely to be tokens (#16164) (#16171) - * Add missing SameSite settings for the i_like_gitea cookie (#16037) (#16039) - * Fix setting of SameSite on cookies (#15989) (#15991) -* API - * Repository object only count releases as releases (#16184) (#16190) - * EditOrg respect RepoAdminChangeTeamAccess option (#16184) (#16190) - * Fix overly strict edit pr permissions (#15900) (#16081) -* BUGFIXES - * Run processors on whole of text (#16155) (#16185) - * Class `issue-keyword` is being incorrectly stripped off spans (#16163) (#16172) - * Fix language switch for install page (#16043) (#16128) - * Fix bug on getIssueIDsByRepoID (#16119) (#16124) - * Set self-adjusting deadline for connection writing (#16068) (#16123) - * Fix http path bug (#16117) (#16120) - * Fix data URI scramble (#16098) (#16118) - * Merge all deleteBranch as one function and also fix bug when delete branch don't close related PRs (#16067) (#16097) - * git migration: don't prompt interactively for clone credentials (#15902) (#16082) - * Fix case change in ownernames (#16045) (#16050) - * Don't manipulate input params in email notification (#16011) (#16033) - * Remove branch URL before IssueRefURL (#15968) (#15970) - * Fix layout of milestone view (#15927) (#15940) - * GitHub Migration, migrate draft releases too (#15884) (#15888) - * Close the gitrepo when deleting the repository (#15876) (#15887) - * Upgrade xorm to v1.1.0 (#15869) (#15885) - * Fix blame row height alignment (#15863) (#15883) - * Fix error message when saving generated LOCAL_ROOT_URL config (#15880) (#15882) - * Backport Fix LFS commit finder not working (#15856) (#15874) - * Stop calling WriteHeader in Write (#15862) (#15873) - * Add timeout to writing to responses (#15831) (#15872) - * Return go-get info on subdirs (#15642) (#15871) - * Restore PAM user autocreation functionality (#15825) (#15867) - * Fix truncate utf8 string (#15828) (#15854) - * Fix bound address/port for caddy's certmagic library (#15758) (#15848) - * Upgrade unrolled/render to v1.1.1 (#15845) (#15846) - * Queue manager FlushAll can loop rapidly - add delay (#15733) (#15840) - * Tagger can be empty, as can Commit and Author - tolerate this (#15835) (#15839) - * Set autocomplete off on branches selector (#15809) (#15833) - * Add missing error to Doctor log (#15813) (#15824) - * Move restore repo to internal router and invoke from command to avoid open the same db file or queues files (#15790) (#15816) -* ENHANCEMENTS - * Removable media support to snap package (#16136) (#16138) - * Move sans-serif fallback font higher than emoji fonts (#15855) (#15892) -* DOCKER - * Only write config in environment-to-ini if there are changes (#15861) (#15868) - * Only offer hostcertificates if they exist (#15849) (#15853) - -## [1.14.2](https://github.com/go-gitea/gitea/releases/tag/v1.14.2) - 2021-05-09 - -* API - * Make change repo settings work on empty repos (#15778) (#15789) - * Add pull "merged" notification subject status to API (#15344) (#15654) -* BUGFIXES - * Ensure that ctx.Written is checked after issues(...) calls (#15797) (#15798) - * Use pulls in commit graph unless pulls are disabled (#15734 & #15740 & #15774) (#15775) - * Set GIT_DIR correctly if it is not set (#15751) (#15769) - * Fix bug where repositories appear unadopted (#15757) (#15767) - * Not show `ref-in-new-issue` pop when issue was disabled (#15761) (#15765) - * Drop back to use IsAnInteractiveSession for SVC (#15749) (#15762) - * Fix setting version table in dump (#15753) (#15759) - * Fix close button change on delete in simplemde area (#15737) (#15747) - * Defer closing the gitrepo until the end of the wrapped context functions (#15653) (#15746) - * Fix some ui bug about draft release (#15137) (#15745) - * Only log Error on getLastCommitStatus error to let pull list still be visible (#15716) (#15715) - * Move tooltip down to allow selection of Remove File on error (#15672) (#15714) - * Fix setting redis db path (#15698) (#15708) - * Fix DB session cleanup (#15697) (#15700) - * Fixed several activation bugs (#15473) (#15685) - * Delete references if repository gets deleted (#15681) (#15684) - * Fix orphaned objects deletion bug (#15657) (#15683) - * Delete protected branch if repository gets removed (#15658) (#15676) - * Remove spurious set name from eventsource.sharedworker.js (#15643) (#15652) - * Not update updated uinx for `git gc` (#15637) (#15641) - * Fix commit graph author link (#15627) (#15630) - * Fix webhook timeout bug (#15613) (#15621) - * Resolve panic on failed interface conversion in migration v156 (#15604) (#15610) - * Fix missing storage init (#15589) (#15598) - * If the default branch is not present do not report error on stats indexing (#15546 & #15583) (#15594) - * Fix lfs management find (#15537) (#15578) - * Fix NPE on view commit with notes (#15561) (#15573) - * Fix bug on commit graph (#15517) (#15530) - * Send size to /avatars if requested (#15459) (#15528) - * Prevent migration 156 failure if tag commit missing (#15519) (#15527) -* ENHANCEMENTS - * Display conflict-free merge messages for pull requests (#15773) (#15796) - * Exponential Backoff for ByteFIFO (#15724) (#15793) - * Issue list alignment tweaks (#15483) (#15766) - * Implement delete release attachments and update release attachments' name (#14130) (#15666) - * Add placeholder text to deploy key textarea (#15575) (#15576) - * Project board improvements (#15429) (#15560) - * Repo branch page: label size, PR ref, new PR button alignment (#15363) (#15365) -* MISC - * Fix webkit calendar icon color on arc-green (#15713) (#15728) - * Performance improvement for last commit cache and show-ref (#15455) (#15701) - * Bump unrolled/render to v1.1.0 (#15581) (#15608) - * Add ETag header (#15370) (#15552) - -## [1.14.1](https://github.com/go-gitea/gitea/releases/tag/v1.14.1) - 2021-04-15 - -* BUGFIXES - * Fix bug clone wiki (#15499) (#15502) - * Github Migration ignore rate limit, if not enabled (#15490) (#15495) - * Use subdir for URL (#15446) (#15493) - * Query the DB for the hash before inserting in to email_hash (#15457) (#15491) - * Ensure review dismissal only dismisses the correct review (#15477) (#15489) - * Use index of the supported tags to choose user lang (#15452) (#15488) - * Fix wrong file link in code search page (#15466) (#15486) - * Quick template fix for built-in SSH server in admin config (#15464) (#15481) - * Prevent superfluous response.WriteHeader (#15456) (#15476) - * Fix ambiguous argument error on tags (#15432) (#15474) - * Add created_unix instead of expiry to migration (#15458) (#15463) - * Fix repository search (#15428) (#15442) - * Prevent NPE on avatar direct rendering if federated avatars disabled (#15434) (#15439) - * Fix wiki clone urls (#15430) (#15431) - * Fix dingtalk icon url at webhook (#15417) (#15426) - * Standardise icon on projects PR page (#15387) (#15408) -* ENHANCEMENTS - * Add option to skip LFS/attachment files for `dump` (#15407) (#15492) - * Clone panel fixes (#15436) - * Use semantic dropdown for code search query type (#15276) (#15364) -* BUILD - * Build go-git variants for windows (#15482) (#15487) - * Lock down build-images dependencies (Partial #15479) (#15480) -* MISC - * Performance improvement for list pull requests (#15447) (#15500) - * Fix potential copy lfs records failure when fork a repository (#15441) (#15485) - -## [1.14.0](https://github.com/go-gitea/gitea/releases/tag/v1.14.0) - 2021-04-11 - -* SECURITY - * Respect approved email domain list for externally validated user registration (#15014) - * Add reverse proxy configuration support for remote IP address detection (#14959) - * Ensure validation occurs on clone addresses too (#14994) - * Fix several render issues highlighted during fuzzing (#14986) -* BREAKING - * Fix double 'push tag' action feed (#15078) (#15083) - * Remove possible resource leak (#15067) (#15082) - * Handle unauthorized user events gracefully (#15071) (#15074) - * Restore Access.log following migration to Chi framework (Stops access logging of /api/internal routes) (#14475) - * Migrate from Macaron to Chi framework (#14293) - * Deprecate building for mips (#14174) - * Consolidate Logos and update README header (#14136) - * Inline manifest.json (#14038) - * Store repository data in data path if not previously set (#13991) - * Rename "gitea" png to "logo" (#13974) - * Standardise logging of failed authentication attempts in internal SSH (#13962) - * Add markdown support in organization description (#13549) - * Improve users management through the CLI (#6001) (#10492) -* FEATURES - * Create a new issue with reference to lines of code from file view (#14863) - * Repository transfer has to be confirmed, if user can not create repo for new owner (#14792) - * Allow blocking some email domains from registering an account (#14667) - * Create a new issue based on reference to an issue comment (#14366) - * Add support to migrate from gogs (#14342) - * Add pager to the branches page (#14202) - * Minimal OpenID Connect implementation (#14139) - * Display current stopwatch in navbar (#14122) - * Display SVG files as images instead of text (#14101) - * Disable SSH key deletion of externally managed Keys (#13985) - * Add support for ed25519_sk and ecdsa_sk SSH keys (#13462) - * Add support for Mastodon OAuth2 provider (#13293) - * Add gitea sendmail command (#13079) - * Create DB session provider(based on xorm) (#13031) - * Add dismiss review feature (#12674) - * Make manual merge autodetection optional and add manual merge as merge method (#12543) - * Dump github/gitlab/gitea repository data to a local directory and restore to gitea (#12244) - * Create Rootless Docker image (#10154) -* API - * Speedup issue search (#15179) (#15192) - * Get pull, return head branch sha, even if deleted (#14931) - * Export LFS & TimeTracking function status (#14753) - * Show Gitea version in swagger (#14654) - * Fix PATCH /repos/{owner}/{repo} panic (#14637) - * Add Restricted Field to User (#14630) - * Add support for ref parameter to get raw file API (#14602) - * Add affected files of commits to commit struct (#14579) - * Fix CJK fonts again and misc. font issues (#14575) - * Add delete release by tag & delete tag (#14563) & (#13358) - * Add pagination to ListBranches (#14524) - * Add signoff option in commit form (#14516) - * GetRelease by tag only return release (#14397) - * Add MirrorInterval to the API (#14163) - * Make BasicAuth Prefix case insensitive (#14106) - * Add user filter to issueTrackedTimes, enable usage for issue managers (#14081) - * Add ref to create/edit issue options & deprecated assignee (#13992) - * Add Ref to Issue (#13946) - * Expose default theme in meta and API (#13809) - * Send error message when CSRF token is missing (#13676) - * List, Check, Add & delete endpoints for repository teams (#13630) - * Admin EditUser: Make FullName, Email, Website & Location optional (#13562) - * Add more filters to issues search (#13514) - * Add review request api (#11355) -* BUGFIXES - * Fix delete nonexist oauth application 500 and prevent deadlock (#15384) (#15396) - * Always set the merge base used to merge the commit (#15352) (#15385) - * Upgrade to bluemonday 1.0.7 (#15379) (#15380) - * Turn RepoRef and RepoAssignment back into func(*Context) (#15372) (#15377) - * Move FCGI req.URL.Path fix-up to the FCGI listener (#15292) (#15361) - * Show diff on rename with diff changes (#15338) (#15339) - * Fix handling of logout event (#15323) (#15337) - * Fix CanCreateRepo check (#15311) (#15321) - * Fix xorm log stack level (#15285) (#15316) - * Fix bug in Wrap (#15302) (#15309) - * Drop the event source if we are unauthorized (#15275) (#15280) - * Backport Fix graph pagination (#15225) (#15249) - * Prevent NPE in CommentMustAsDiff if no hunk header (#15199) (#15200) - * should run RetrieveRepoMetas() for empty pr (#15187) (#15190) - * Move setting to enable closing issue via commit in non default branch to repo settings (#14965) - * Show correct issues for team dashboard (#14952) - * Ensure that new pull request button works on forked forks owned by owner of the root and reduce ambiguity (#14932) - * Only allow issue labels from owner repository or organization (#14928) - * Fix alignment of People and Teams right arrow on org homepage (#14924) - * Fix overdue marking of closed issues and milestones (#14923) - * Prevent panic when empty MilestoneID in repo/issue/list (#14911) - * Fix migration context data (#14910) - * Handle URLs with trailing slash (#14852) - * Add CORS config on to /login/oauth/access_token endpoint (#14850) - * Make searching issues by keyword case insensitive on DB (#14848) - * Prevent use of double sub-path and incorrect asset path in manifest (#14827) - * Fix link account ui (#14763) - * Fix preview status switch button on wiki editor (#14742) - * Fix github download on migration (#14703) - * Fix svg spacing (#14638) - * Prevent adding nil label to .AddedLabels or .RemovedLabels (#14623) - * Truncated organizations name (#14615) - * Exclude the current dump file from the dump (#14606) - * Use OldRef instead of CommitSHA for DeleteBranch comments (#14604) - * Ensure memcache caching works when TTL greater than 30 days (#14592) - * Remove NULs byte arrays passed to PostProcess (#14587) - * Restore detection of branches are equal on compare page (#14586) - * Fix incorrect key name so registerManualConfirm works (#14455) - * Fix close/reopen with comment (#14436) - * Allow passcode invalid error to appear (#14371) - * Escape branch names in compare url (#14364) - * Label and milestone webhooks on issue/pull creation (#14363) - * Handle NotifyCreateRef as create branch in feeds (#14245) - * Prevent clipping input text in Chrome + Segoe UI Font (#14179) - * Fix UI on edit auth source page (#14137) - * Fix git.parseTagData (#14105) - * Refactor get tag to remove unnecessary steps (#14058) - * Fix integrations test error with space in CURDIR path (#14056) - * Dropdown triangle fixes (#14028) - * Fix label of --id in admin delete user (#14005) - * Cause NotifyMigrateRepository to emit a repo create webhook (#14004) - * Update HEAD to match defaultBranch in template generation (#13948) - * Fix action avatar loading (#13909) - * Fix issue participants (#13893) - * Fix avatar template error (#13833) - * Fix review request notification email links when external issue tracker is enabled (#13723) - * Fix blame line alignment (#13542) - * Include OriginalAuthor in Reaction constraint (#13505) - * Comments on review should have the same sha (#13448) - * Fix whitespace rendering in diff (#13415) - * Fixed git args duplication (#13411) - * Fix bug on release publisherid migrations (#13410) - * Fix --port setting (#13288) - * Keep database transactions not too big (#13254) - * Git version check, ignore pre-releases constraints (#13234) - * Handle and propagate errors when checking if paths are Dirs, Files or Exist (#13186) - * Update Mirror IsEmpty status on synchronize (#13185) - * Use GO variable in go-check target (#13146) (#13147) -* ENHANCEMENTS - * UI style improvements - * Dropzone styling improvements (#15291) (#15374) - * Add size to Save function (#15264) (#15270) - * Monaco improvements (#15333) (#15345) - * Support .mailmap in code activity stats (#15009) - * Sort release attachments by name (#15008) - * Add ui.explore settings to control view of explore pages (#14094) - * Make internal SSH server host key path configurable (#14918) - * Hide resync all ssh principals when using internal ssh server (#14904) - * Add SameSite setting for cookies (#14900) - * Move Bleve and Elastic code indexers to use a common cat-file --batch (#14781) - * Add environment-to-ini to docker image (#14762) - * Add preview support for wiki editor when disable simpleMDE (#14757) - * Add easyMDE(simpleMDE) support for release content editor (#14744) - * Organization removal confirmation using name not password (#14738) - * Make branch names in PR description clickable (#14716) - * Add Password Algorithm option to install page (#14701) - * Add fullTextSearch to dropdowns by default (#14694) - * Fix truncated organization names (#14655) - * Whitespace in commits (#14650) - * Sort / move project boards (#14634) - * Make fileheader sticky in diffs (#14616) - * Add helper descriptions on new repo page (#14591) - * Move the stopwatches to the eventsource stream (#14588) - * Add Content-Length header to HEAD requests (#14542) - * Add Image Diff options in Diff view (#14450) - * Improve Description in new/ edit Project template (#14429) - * Allow ssh-keygen on Windows to detect ssh key type (#14413) - * Display error if twofaSecret cannot be retrieved (#14372) - * Sort issue search results by relevance (#14353) - * Implement ghost comment mitigation (#14349) - * Upgrade blevesearch dependency to v2.0.1 (#14346) - * Add edit, delete and reaction support to code review comments on issue page (#14339) - * Merge default and system webhooks under one menu (#14244) - * Add option for administrator to reset user 2FA (#14243) - * Add option to change username to the admin panel (#14229) - * Check for 'main' as potential default branch name (#14193) - * Project: show referenced PRs in issue cards (#14183) - * Use caddy's certmagic library for extensible/robust ACME handling (#14177) - * CLI support for OAuth sources custom icons (#14166) - * Custom icons for OAuth sources (#14161) - * Team dashboards (#14159) - * KanBan: be able to set default board (#14147) - * Disable Fomantic's custom scrollbars (#14109) - * Add UI to delete tracked times (#14100) - * Rework heatmap permissions (#14080) - * Issue and pull request filters on organization dashboard (#14072) - * Fix webhook list styling (#14001) - * Show dropdown with all statuses for commit (#13977) - * Show status check for merged PRs (#13975) - * Diff stat improvements (#13954) - * Report permissions denied in internal SSH (#13953) - * Markdown task list improvements (#13952) - * Heatmap days clickable (#13935) - * chore: use octicon-mirror for feeds display (#13928) - * Move diff split code into own template file (#13919) - * Markdown: Enable wrapping in code blocks and a color tweak (#13894) - * Do not reload page after adding comments in Pull Request reviews (#13877) - * Add pull request manually merge instruction (#13840) - * add thumbnail preview section to issue attachments (#13826) - * Move Repo APIFormat to convert package (#13787) - * Move notification APIFormat (#13783) - * Swap swagger-ui with swagger-ui-dist (#13777) - * User Settings: Ignore empty language codes & validate (#13755) - * Improve migrate page and add card CSS (#13751) - * Add block on official review requests branch protection (#13705) - * Add review requested filter on pull request overview (#13701) - * Use chronological commit order in default squash message (#13696) - * Clickable links in pull request (and issue) titles (#13695) - * Support shortened commit SHAs in URLs (#13686) - * Use native git variants by default with go-git variants as build tag (#13673) - * Don't render dropdown when only 1 merge style is available (#13670) - * Move webhook type from int to string (#13664) - * Direct avatar rendering (#13649) - * Verify password for local-account activation (#13631) - * Prevent clone protocol button flash on page load (#13626) - * Remove fetch request from heatmap (#13623) - * Refactor combine label comments with tests (#13619) - * Move metrics from macaron to chi (#13601) - * Issue and Pulls lists rework (#13594) - * HTTP cache rework and enable caching for storage assets (#13569) - * Use mount but not register for chi routes (#13555) - * Use monaco for the git hook editor (#13552) - * Make heatmap colors more distinct (#13533) - * Lazy-load issue reviewers and assignees avatars (#13526) - * Change search and filter icons to SVG (#13473) - * Create tag on ui (#13467) - * updateSize when create a repo with init commit (#13441) - * Added title and action buttons to Project view page (#13437) - * Override fomantic monospace fonts and set size (#13435) - * Rework focused comment styling (#13434) - * Tags cleanup (#13428) - * Various style tweaks (#13418) - * Refactor push update (#13381) - * Comment box tweaks and SVG dropdown triangles (#13376) - * Various style fixes (#13372) - * Change repo home page icons to SVG (#13364) - * Use CSS Vars for primary color (#13361) - * Refactor image paste code (#13354) - * Switch from SimpleMDE to EasyMDE (#13333) - * Group Label Changed Comments in timeline (#13304) - * Make the logger an interface (#13294) - * Fix PR/Issue titles on mobile (#13292) - * Rearrange the order of the merged by etc. in locale (#13284) - * Replace footer and modal icons with SVG (#13245) - * Issues overview should not show issues from archived repos (#13220) - * Show stale label for stale code comment which is marked as resolved (#13213) - * Use CSS Variables for fonts, remove postcss-loader (#13204) - * Add mentionable teams to tributeValues and change team mention rules to gh's style (#13198) - * Move install pages out of main macaron routes (#13195) - * Update outdated label to use Fomantic UI style (#13181) - * Added option to disable webhooks (#13176) - * Change order of possible-owner organizations to alphabetical (#13160) - * Log IP on SSH authentication failure for Built-in SSH server (#13150) - * Added option to disable migrations (#13114) - * New "Add Mirror" Button in the Organization view (#13105) - * Manually approve new registration (#13083) - * Cron job to cleanup hook_task table (#13080) - * Use the headline comment of pull-request as the squash commit's message (#13071) - * Clarify the suffices and prefixes of setting.AppSubURL and setting.AppURL (#12999) - * Slightly simplify the queue settings code to help reduce the risk of problems (#12976) - * Add precise search type for Elastic Search (#12869) - * Move APIFormat functions into convert package (#12856) - * Multiple GitGraph improvements: Exclude PR heads, Add branch/PR links, Show only certain branches, (#12766) - * Add TrN for repository limit (#12492) - * Refactor doctor (#12264) - * Add the tag list page to the release page (#12096) - * Redirect on changed user and org name (#11649) - * load U2F js only on pages which need it (#11585) - * Make archival asynchronous (#11296) - * Introduce go chi web framework as frontend of macaron, so that we can move routes from macaron to chi step by step (#7420) - * Improve vfsgen to not unzip bindata files but send to browser directly (#7109) - * Enhance release list (#6025) -* DOCS - * Swagger show models by default (#14880) - * Add missing repo.projects unit into swagger (#14876) - * Update docs and comments to remove macaron (#14491) - * Issue template addition: Are you using Gitea behind CloudFlare? (#14098) - * Generate man pages (#13901) - * Reformat/fine-tune docs (#13897) - * Added Table of Contents to long documentation pages (#13890) - * Add docs command (#13429) - * Update external-renderers.en-us.md (#13165) -* MISC - * Add builds for apple M1 (darwin arm64) (#14951) - * Migrate to use jsoniter instead of encoding/json (#14841) - * Reduce make verbosity (#13803) - * Add git command error directory on log (#13194) - -## [1.13.7](https://github.com/go-gitea/gitea/releases/tag/v1.13.7) - 2021-04-07 - -* SECURITY - * Update to bluemonday-1.0.6 (#15294) (#15298) - * Clusterfuzz found another way (#15160) (#15169) -* API - * Fix wrong user returned in API (#15139) (#15150) -* BUGFIXES - * Add 'fonts' into 'KnownPublicEntries' (#15188) (#15317) - * Speed up `enry.IsVendor` (#15213) (#15246) - * Response 404 for diff/patch of a commit that not exist (#15221) (#15238) - * Prevent NPE in CommentMustAsDiff if no hunk header (#15199) (#15201) -* MISC - * Add size to Save function (#15264) (#15271) - -## [1.13.6](https://github.com/go-gitea/gitea/releases/tag/v1.13.6) - 2021-03-23 - -* SECURITY - * Fix bug on avatar middleware (#15124) (#15125) - * Fix another clusterfuzz identified issue (#15096) (#15114) -* API - * Fix nil exeption for get pull reviews API #15104 (#15106) -* BUGFIXES - * Fix markdown rendering in milestone content (#15056) (#15092) - -## [1.13.5](https://github.com/go-gitea/gitea/releases/tag/v1.13.5) - 2021-03-21 - -* SECURITY - * Update to goldmark 1.3.3 (#15059) (#15061) - * Another clusterfuzz spotted issue (#15032) (#15034) -* API - * Fix set milestone on PR creation (#14981) (#15001) - * Prevent panic when editing forked repos by API (#14960) (#14963) -* BUGFIXES - * Fix bug when upload on web (#15042) (#15055) - * Delete Labels & IssueLabels on Repo Delete too (#15039) (#15051) - * Fix postgres ID sequences broken by recreate-table (#15015) (#15029) - * Fix several render issues (#14986) (#15013) - * Make sure sibling images get a link too (#14979) (#14995) - * Fix Anchor jumping with escaped query components (#14969) (#14977) - * Fix release mail html template (#14976) - * Fix excluding more than two labels on issues list (#14962) (#14973) - * Don't mark each comment poster as OP (#14971) (#14972) - * Add "captcha" to list of reserved usernames (#14930) - * Re-enable import local paths after reversion from #13610 (#14925) (#14927) - -## [1.13.4](https://github.com/go-gitea/gitea/releases/tag/v1.13.4) - 2021-03-07 - -* SECURITY - * Fix issue popups (#14898) (#14899) -* BUGFIXES - * Fix race in LFS ContentStore.Put(...) (#14895) (#14913) - * Fix a couple of issues with a feeds (#14897) (#14903) - * When transferring repository and database transaction failed, rollback the renames (#14864) (#14902) - * Fix race in local storage (#14888) (#14901) - * Fix 500 on pull view page if user is not loged in (#14885) (#14886) -* DOCS - * Fix how lfs data path is set (#14855) (#14884) - -## [1.13.3](https://github.com/go-gitea/gitea/releases/tag/v1.13.3) - 2021-03-04 - -* BREAKING - * Turn default hash password algorithm back to pbkdf2 from argon2 until we find a better one (#14673) (#14675) -* BUGFIXES - * Fix paging of file commit logs (#14831) (#14879) - * Print useful error if SQLite is used in settings but not supported (#14476) (#14874) - * Fix display since time round (#14226) (#14873) - * When Deleting Repository only explicitly close PRs whose base is not this repository (#14823) (#14842) - * Set HCaptchaSiteKey on Link Account pages (#14834) (#14839) - * Fix a couple of CommentAsPatch issues. (#14804) (#14820) - * Disable broken OAuth2 providers at startup (#14802) (#14811) - * Repo Transfer permission checks (#14792) (#14794) - * Fix double alert in oauth2 application edit view (#14764) (#14768) - * Fix broken spans in diffs (#14678) (#14683) - * Prevent race in PersistableChannelUniqueQueue.Has (#14651) (#14676) - * HasPreviousCommit causes recursive load of commits unnecessarily (#14598) (#14649) - * Do not assume all 40 char strings are SHA1s (#14624) (#14648) - * Allow org labels to be set with issue templates (#14593) (#14647) - * Accept multiple SSH keys in single LDAP SSHPublicKey attribute (#13989) (#14607) - * Fix bug about ListOptions and stars/watchers pagnation (#14556) (#14573) - * Fix GPG key deletion during account deletion (#14561) (#14569) - -## [1.13.2](https://github.com/go-gitea/gitea/releases/tag/v1.13.2) - 2021-01-31 - -* SECURITY - * Prevent panic on fuzzer provided string (#14405) (#14409) - * Add secure/httpOnly attributes to the lang cookie (#14279) (#14280) -* API - * If release publisher is deleted use ghost user (#14375) -* BUGFIXES - * Internal ssh server respect Ciphers, MACs and KeyExchanges settings (#14523) (#14530) - * Set the name Mapper in migrations (#14526) (#14529) - * Fix wiki preview (#14515) - * Update code.gitea.io/sdk/gitea v0.13.1 -> v0.13.2 (#14497) - * ChangeUserName: rename user files back on DB issue (#14447) - * Fix lfs preview bug (#14428) (#14433) - * Ensure timeout error is shown on u2f timeout (#14417) (#14431) - * Fix Deadlock & Delete affected reactions on comment deletion (#14392) (#14425) - * Use path not filepath in routers/editor (#14390) (#14396) - * Check if label template exist first (#14384) (#14389) - * Fix migration v141 (#14387) (#14388) - * Use Request.URL.RequestURI() for fcgi (#14347) - * Use ServerError provided by Context (#14333) (#14345) - * Fix edit-label form init (#14337) - * Fix mailIssueCommentBatch for pull request (#14252) (#14296) - * Render links for commit hashes followed by comma (#14224) (#14227) - * Send notifications for mentions in pulls, issues, (code-)comments (#14218) (#14221) - * Fix avatar bugs (#14217) (#14220) - * Ensure that schema search path is set with every connection on postgres (#14131) (#14216) - * Fix dashboard issues labels filter bug (#14210) (#14214) - * When visit /favicon.ico but the static file is not exist return 404 but not continue to handle the route (#14211) (#14213) - * Fix branch selector on new issue page (#14194) (#14207) - * Check for notExist on profile repository page (#14197) (#14203) - -## [1.13.1](https://github.com/go-gitea/gitea/releases/tag/v1.13.1) - 2020-12-29 - -* SECURITY - * Hide private participation in Orgs (#13994) (#14031) - * Fix escaping issue in diff (#14153) (#14154) -* BUGFIXES - * Fix bug of link query order on markdown render (#14156) (#14171) - * Drop long repo topics during migration (#14152) (#14155) - * Ensure that search term and page are not lost on adoption page-turn (#14133) (#14143) - * Fix storage config implementation (#14091) (#14095) - * Fix panic in BasicAuthDecode (#14046) (#14048) - * Always wait for the cmd to finish (#14006) (#14039) - * Don't use simpleMDE editor on mobile devices for 1.13 (#14029) - * Fix incorrect review comment diffs (#14002) (#14011) - * Trim the branch prefix from action.GetBranch (#13981) (#13986) - * Ensure template renderer is available before storage handler (#13164) (#13982) - * Whenever the password is updated ensure that the hash algorithm is too (#13966) (#13967) - * Enforce setting HEAD in wiki to master (#13950) (#13961) - * Fix feishu webhook caused by API changed (#13938) - * Fix Quote Reply button on review diff (#13830) (#13898) - * Fix Pull Merge when tag with same name as base branch exist (#13882) (#13896) - * Fix mermaid chart size (#13865) - * Fix branch/tag notifications in mirror sync (#13855) (#13862) - * Fix crash in short link processor (#13839) (#13841) - * Update font stack to bootstrap's latest (#13834) (#13837) - * Make sure email recipients can see issue (#13820) (#13827) - * Reply button is not removed when deleting a code review comment (#13824) - * When reinitialising DBConfig reset the database use flags (#13796) (#13811) -* ENHANCEMENTS - * Add emoji in label to project boards (#13978) (#14021) - * Send webhook when tag is removed via Web UI (#14015) (#14019) - * Use Process Manager to create own Context (#13792) (#13793) -* API - * GetCombinedCommitStatusByRef always return json & swagger doc fixes (#14047) - * Return original URL of Repositories (#13885) (#13886) - -## [1.13.0](https://github.com/go-gitea/gitea/releases/tag/v1.13.0) - 2020-12-01 - -* SECURITY - * Add Allow-/Block-List for Migrate & Mirrors (#13610) (#13776) - * Prevent git operations for inactive users (#13527) (#13536) - * Disallow urlencoded new lines in git protocol paths if there is a port (#13521) (#13524) - * Mitigate Security vulnerability in the git hook feature (#13058) - * Disable DSA ssh keys by default (#13056) - * Set TLS minimum version to 1.2 (#12689) - * Use argon as default password hash algorithm (#12688) -* BREAKING - * Set RUN_MODE prod by default (#13765) (#13767) - * Don't replace underscores in auto-generated IDs in goldmark (#12805) - * Add Primary Key to Topic and RepoTopic tables (#12639) - * Disable password complexity check default (#12557) - * Change PIDFile default from /var/run/gitea.pid to /run/gitea.pid (#12500) - * Add extension Support to Attachments (allow all types for releases) (#12465) - * Remove IE11 Support (#11470) -* FEATURES - * Adopt repositories (#12920) - * Check passwords against HaveIBeenPwned (#12716) - * Gitea 2 Gitea migration (#12657) - * Support storing Avatars in minio (#12516) - * Allow addition of gpg keyring with multiple keys (#12487) - * Add email notify for new release (#12463) - * Add Access-Control-Expose-Headers (#12446) - * UserProfile Page: Render Description (#12415) - * Add command to recreate tables (#12407) - * Add mermaid JS renderer (#12334) - * Add ssh certificate support (#12281) - * Add spent time to referenced issue in commit message (#12220) - * Initial support for push options (#12169) - * Provide option to unlink a fork (#11858) - * Show exact tag for commit on diff view (#11846) - * Pause, Resume, Release&Reopen, Add and Remove Logging from command line (#11777) - * Issue templates directory (#11450) - * Add a storage layer for attachments (#11387) - * Add hide activity option (#11353) - * Add push commits history comment on PR time-line (#11167) - * Support elastic search for code search (#10273) - * Kanban board (#8346) -* API - * If User is Admin, show 500 error message on PROD mode too (#13115) - * Add Timestamp to Tag list API (#13026) - * Return sample message for login error in api context (#12994) - * Add IsTemplate option in create repo ui and api (#12942) - * GetReleaseByID return 404 if not found (#12933) - * Get release by tags endpoint (#12932) - * NotificationSubject show Issue/Pull State (#12901) - * Expose its limitation settings (#12714) - * Add Created & Updated to Milestone (#12662) - * Milestone endpoints accept names too (#12649) - * Expose Attachment Settings in the API (#12514) - * Add Issue and Repo info to StopWatch (#12458) - * Add cron running API (#12421) - * Add Update Pull HeadBranch Function (#12419) - * Add TOTP header to Swagger Documentation (#12402) - * Delete Token accept names too (#12366) - * Add name filter for GetMilestoneList (#12336) - * Fixed count of filtered issues when api request. (#12275) - * Do not override API issue pagination with UI settings (#12068) - * Expose useful General Repo settings settings (#11758) - * Return error when trying to create Mirrors but Mirrors are globally disabled (#11757) - * Provide diff and patch API endpoints (#11751) - * Allow to create closed milestones (#11745) - * Add language Statistics endpoint (#11737) - * Add Endpoint to get GetGeneralUI Settings (#11735) & (#11854) - * Issue/Pull expose IsLocked Property on API (#11708) - * Add endpoint for Branch Creation (#11607) - * Add pagination headers on endpoints that support total count from database (#11145) -* BUGFIXES - * Fix bogus http requests on diffs (#13760) (#13761) - * Show 'owner' tag for real owner (#13689) (#13743) - * Validate email before inserting/updating (#13475) (#13666) - * Fix issue/pull request list assignee filter (#13647) (#13651) - * Gitlab migration support for subdirectories (#13563) (#13591) - * Fix logic for preferred license setting (#13550) (#13557) - * Add missed sync branch/tag webhook (#13538) (#13556) - * Migration won't fail on non-migrated reactions (#13507) - * Fix Italian language file parsing error (#13156) - * Show outdated comments in pull request (#13148) (#13162) - * Fix parsing of pre-release git version (#13169) (#13172) - * Fix diff skipping lines (#13154) (#13155) - * When handling errors in storageHandler check underlying error (#13178) (#13193) - * Fix size and clickable area on file table back link (#13205) (#13207) - * Add better error checking for inline html diff code (#13251) - * Fix initial commit page & binary munching problem (#13249) (#13258) - * Fix migrations from remote Gitea instances when configuration not set (#13229) (#13273) - * Store task errors following migrations and display them (#13246) (#13287) - * Fix bug isEnd detection on getIssues/getPullRequests (#13299) (#13301) - * When the git ref is unable to be found return broken pr (#13218) (#13303) - * Ensure topics added using the API are added to the repository (#13285) (#13302) - * Fix avatar autogeneration (#13233) (#13282) - * Add migrated pulls to pull request task queue (#13331) (#13334) - * Issue comment reactions should also check pull type on API (#13349) (#13350) - * Fix links to repositories in /user/setting/repos (#13360) (#13362) - * Remove obsolete change of email on profile page (#13341) (#13347) - * Fix scrolling to resolved comment anchors (#13343) (#13371) - * Storage configuration support `[storage]` (#13314) (#13379) - * When creating line diffs do not split within an html entity (#13357) (#13375) (#13425) (#13427) - * Fix reactions on code comments (#13390) (#13401) - * Add missing full names when DEFAULT_SHOW_FULL_NAME is enabled (#13424) - * Replies to outdated code comments should also be outdated (#13217) (#13433) - * Fix panic bug in handling multiple references in commit (#13486) (#13487) - * Prevent panic on git blame by limiting lines to 4096 bytes at most (#13470) (#13491) - * Show original author's reviews on pull summary box (#13127) - * Update golangci-lint to version 1.31.0 (#13102) - * Fix line break for MS teams webhook (#13081) - * Fix Issue & Pull Request comment headers on mobile (#13039) - * Avoid setting the CONN_STR in queues unless it is meant to be set (#13025) - * Remove code-view class from diff view (#13011) - * Fix the color of PR comment hyperlinks. (#13009) - * (Re)Load issue labels when changing them (#13007) - * Fix Media links in org files not liked to media files (#12997) - * Always return a list from GetCommitsFromIDs (#12981) - * Only set the user password if the password field would have been shown (#12980) - * Fix admin/config page (#12979) - * Changed width of commit signature avatar (#12961) - * Completely quote AppPath and CustomConf paths (#12955) - * Fix handling of migration errors (#12928) - * Fix anonymous GL migration (#12862) - * Fix git open close bug (#12834) - * Fix markdown meta parsing (#12817) - * Add default storage configurations (#12813) - * Show PR settings on empty repos (#12808) - * Disable watch and star if not signed in (#12807) - * Whilst changing the character set to utf8mb4 we should set ROW_FORMAT=dynamic too (#12804) - * Set opengraph attributes on org pages (#12803) - * Return error when creating gitlabdownloader failed (#12790) - * Add migration for password algorithm change (#12784) - * Compare SSH_DOMAIN when parsing submodule URLs (#12753) - * Fix editor.commit_empty_file_text locale string (#12744) - * Fix wrong poster message for code comment on Pull view (#11721) - * Escape failed highlighted files (#12685) - * Ensure that all migration requests are cancellable (#12669) - * Ensure RepoPath is lowercased in gitea serv (#12668) - * Do not disable commit changes button on repost (#12644) - * Dark theme for line numbers in blame view (#12632) - * Fix message when deleting last owner from an organization (#12628) - * Use shellquote to unpack arguments to gitea serv (#12624) - * Fix signing.wont_sign.%!s(<nil>) if Require Signing commits but not signed in. (#12581) - * Set utf8mb4 as the default charset on MySQL if CHARSET is unset (#12563) - * Set context for running CreateArchive to that of the request (#12555) - * Prevent redirect back to /user/events (#12462) - * Re-attempt to delete temporary upload if the file is locked by another process (#12447) - * Mirror System Notice reports are too frequent (#12438) - * Do not show arrows on comment diffs on pull comment pages (#12434) - * Fix milestone links (#12405) - * Increase size of the language column in language_stat (#12396) - * Use transaction in V102 migration (#12395) - * Only use --exclude on name-rev with git >= 2.13 (#12347) - * Add action feed for new release (#12324) - * Set NoAutoTime when updating is_archived (#12266) - * Support Force-update in Mirror and improve Tracing in mirror (#12242) - * Avoid sending "0 new commits" webhooks (#12212) - * Fix U2F button icon (#12167) - * models/repo_sign.go: break out of loops (#12159) - * Ensure that git commit tree continues properly over the page (#12142) - * Rewrite GitGraph.js (#12137) - * Fix repo API listing stability (#12057) - * Add team support for review request (#12039) - * Fix 500 error on repos with no tags (#11870) - * Fix nil pointer in default issue mail template (#11862) - * Fix commit search in all branches (#11849) - * Don't consider tag refs as valid for branch name (#11847) - * Don't add same line code comment box twice (#11837) - * Fix visibility of forked public repos from private orgs (#11717) - * Fix chardet test and add ordering option (#11621) - * Fix number of files, total additions, and deletions on Diff pages (#11614) - * Properly handle and return empty string for dangling commits in GetBranchName (#11587) - * Include query in sign in redirect (#11579) - * Fix Enter not working in SimpleMDE (#11564) - * Fix bug about can't skip commits base on base branch (#11555) -* ENHANCEMENTS - * Only Return JSON for responses (#13511) (#13565) - * Use existing analyzer module for language detection for highlighting (#13522) (#13551) - * Return the full rejection message and errors in flash errors (#13221) (#13237) - * Remove PAM from auth dropdown when unavailable (#13276) (#13281) - * Add HostCertificate to sshd_config in Docker image (#13143) - * Save TimeStamps for Star, Label, Follow, Watch and Collaboration to Database (#13124) - * Improve error feedback for duplicate deploy keys (#13112) - * Set appropriate `autocomplete` attributes on password fields (#13078) - * Adding visual cue for "Limited" & "Private" organizations. (#13040) - * Fix Pull Request merge buttons on mobile (#13035) - * Gitea serv, hooks, manager and the like should always display Fatals (#13032) - * CSS tweaks to warning/error segments and misc fixes (#13024) - * Fix formatting of branches ahead-behind on narrow windows (#12989) - * Add config option to make create-on-push repositories public by default (#12936) - * Disable migration items when mirror is selected (#12918) - * Add the checkbox quick button to the comment tool bar also (#12885) - * Support GH enterprise (#12863) - * Simplify CheckUnitUser logic (#12854) - * Fix background of signed-commits on arc-green of timeline commits (#12837) - * Move git update-server-info to hooks (#12826) - * Add ui style for "Open a blank issue" button (#12824) - * Use a simple format for the big number on ui (#12822) - * Make SVG size argument optional (#12814) - * Add placeholder text for bio profile text form (#12792) - * Set language via AJAX (#12785) - * Show git-pull-request icon for closed pull request (#12742) - * Migrate version parsing library to hashicorp/go-version (#12719) - * Only use async pre-empt hack if go < 1.15 (#12718) - * Inform user about meaning of an hourglass on reviews (#12713) - * Add a migrate service type switch page (#12697) - * Migrations: Gitlab Add Reactions Support for Issues & MergeRequests (#12695) - * Remove duplicate logic in initListSubmits (#12660) - * Set avatar image dimensions (#12654) - * Rename models.ProtectedBranchRepoID/PRID to models.EnvRepoID/PRID and ensure EnvPusherEmail is set (#12646) - * Set setting.AppURL as GITEA_ROOT_URL environment variable during pushes (#12752) - * Add postgres schema to the search_path on database connection (#12634) - * Git migration UX improvements (#12619) - * Add link to home page on swagger ui (#12601) - * hCaptcha Support (#12594) - * OpenGraph: use repo avatar if exist (#12586) - * Reaction picker display improvements (#12576) - * Fix emoji replacements, make emoji images consistent (#12567) - * Increase clickable area on files table links (#12553) - * Set z-index for sticky diff box lower (#12537) - * Report error if API merge is not allowed (#12528) - * LFS support to be stored on minio (#12518) - * Show 2FA info on Admin Pannel: Users List (#12515) - * Milestone Issue/Pull List: Add octicons type (#12499) - * Make dashboard newsfeed list length a configurable item (#12469) - * Add placeholder text for send testing email button in admin/config (#12452) - * Add SVG favicon (#12437) - * In issue comments, put issue participants also in completion list when hitting @ (#12433) - * Collapse Swagger UI tags by default (#12428) - * Detect full references to issues and pulls in commit messages (#12399) - * Allow common redis and leveldb connections (#12385) - * Don't use legacy method to send Matrix Webhook (#12348) - * Remove padding/border-radius on image diffs (#12346) - * Render the git graph on the server (#12333) - * Fix clone panel in wiki position not always align right (#12326) - * Rework 'make generate-images' (#12316) - * Refactor webhook payload conversion (#12310) - * Move jquery-minicolors to npm/webpack (#12305) - * Support use nvarchar for all varchar columns when using mssql (#12269) - * Update Octicons to v10 (#12240) - * Disable search box autofocus (#12229) - * Replace code fold icons with octicons (#12222) - * Ensure syntax highlighting is the same inside diffs (#12205) - * Auto-init repo on license, .gitignore select (#12202) - * Default to showing closed Issues/PR list when there are only closed issues/PRs (#12200) - * Enable cloning via Git Wire Protocol v2 over HTTP (#12170) - * Direct SVG rendering (#12157) - * Improve arc-green code colors (#12111) - * Allow admin to merge pr with protected file changes (#12078) - * Show description on individual milestone view (#12055) - * Update the wiki repository remote origin while update the mirror repository's Clone From URL (#12053) - * Server-side syntax highlighting for all code (#12047) - * Use Fomantic's fluid padded for blame full width (#12023) - * Use custom SVGs for commit signing lock icon (#12017) - * Make tabs smaller (#12003) - * Fix sticky diff stats container (#12002) - * Move fomantic and jQuery to main webpack bundle (#11997) - * Use enry language type to detect special languages (#11974) - * Use only first line of commit when creating referenced comment (#11960) - * Rename custom/conf/app.ini.sample to custom/conf/app.example.ini for better syntax light on editor (#11926) - * Fix double divider on issue sidebar (#11919) - * Shorten markdown heading anchors links (#11903) - * Add org avatar on top of internal repo icon (#11895) - * Use label to describe repository type (#11891) - * Make repository size unclickable on repo summary bar (#11887) - * Rework blame template and styling (#11885) - * Fix icon alignment for show/hide outdated link on resolved conversation (#11881) - * Vertically align review icons on repository sidebar (#11880) - * Better align items using flex within review request box (#11879) - * Only write to global gitconfig if necessary (#11876) - * Disable all typographic replacements in markdown renderer (#11871) - * Improve label edit buttons labels (#11841) - * Use crispEdges rendering for octicon-internal-repo (#11801) - * Show update branch item in merge box when it's necessary (#11761) - * Add compare link to releases (#11752) - * Allow site admin to disable mirrors (#11740) - * Export monaco editor on window.codeEditors (#11739) - * Add configurable Trust Models (#11712) - * Show full GPG commit status on PR commit history (#11702) - * Fix align issues and decrease avatar size on PR timeline (#11689) - * Replace jquery-datetimepicker with native date input (#11684) - * Change Style of Tags on Comments (#11668) - * Fix missing styling for shabox on PR commit history (#11625) - * Apply padding to approval icons on PR list (#11622) - * Fix message wrapping on PR commit list (#11616) - * Right-align status icon on pull request commit history (#11594) - * Add missing padding for multi-commit list on PR view (#11593) - * Do not show avatar for "{{user}} added X commits" (#11591) - * Fix styling and padding for commit list on PR view (#11588) - * Style code review comment for arc-green (#11572) - * Use default commit message for wiki edits (#11550) - * Add internal-repo octicon for public repos of private org (#11529) - * Fix dropzone color on arc-green (#11514) - * Insert ui divider directly in templates instead of from inside heatmap vue component (#11508) - * Move tributejs to npm/webpack (#11497) - * Fix text-transform on wiki revisions page (#11486) - * Do not show lock icon on repo list for public repos in private org (#11445) - * Include LFS when calculating repo size (#11060) - * Add check for LDAP group membership (#10869) - * When starting new stopwatch stop previous if it is still running (#10533) - * Add queue for code indexer (#10332) - * Move all push update operations to a queue (#10133) - * Cache last commit when pushing for big repository (#10109) - * Change/remove a branch of an open issue (#9080) - * Sortable Tables Header By Click (#7980) -* TESTING - * Use community codecov drone plugin (#12468) - * Add more tests for diff highlighting (#12467) - * Don't put integration test data outside of test folder (#11746) - * Add debug option to hooks (#11624) - * Log slow tests (#11487) -* TRANSLATION - * Translate two small lables on commit statutes list (#12821) - * Make issues.force_push_codes message shorter (#11575) -* BUILD - * Bump min required golang to 1.13 (#12717) - * Add 'make watch' (#12636) - * Extract Swagger CSS to its own file (#12616) - * Update eslint config (#12609) - * Avoid unnecessary system-ui expansion (#12522) - * Make the default PID file compile-time settable (#12485) - * Add 'watch-backend' (#12330) - * Detect version of sed in Makefile (#12319) - * Update gitea-vet to v0.2.1 (#12282) - * Add logic to build stable and edge builds for gitea snap (#12052) - * Fix missing CGO_EXTRA_FLAGS build arg for docker (#11782) - * Alpine 3.12 (#11720) - * Enable stylelint's shorthand-property-no-redundant-values (#11436) -* DOCS - * Change default log configuration (#13088) - * Add automatic JS license generation (#11810) - * Remove page size limit comment from swagger (#11806) - * Narrow down Edge version in browser support docs (#11640) - -## [1.12.5](https://github.com/go-gitea/gitea/releases/tag/v1.12.5) - 2020-10-01 - -* BUGFIXES - * Allow U2F with default settings for gitea in subpath (#12990) (#13001) - * Prevent empty div when editing comment (#12404) (#12991) - * On mirror update also update address in DB (#12964) (#12967) - * Allow extended config on cron settings (#12939) (#12943) - * Open transaction when adding Avatar email-hash pairs to the DB (#12577) (#12940) - * Fix internal server error from ListUserOrgs API (#12910) (#12915) - * Update only the repository columns that need updating (#12900) (#12912) - * Fix panic when adding long comment (#12892) (#12894) - * Add size limit for content of comment on action ui (#12881) (#12890) - * Convert User expose ID each time (#12855) (#12883) - * Support slashes in release tags (#12864) (#12882) - * Add missing information to CreateRepo API endpoint (#12848) (#12867) - * On Migration respect old DefaultBranch (#12843) (#12858) - * Fix notifications page links (#12838) (#12853) - * Stop cloning unnecessarily on PR update (#12839) (#12852) - * Escape more things that are passed through str2html (#12622) (#12850) - * Remove double escape on labels addition in comments (#12809) (#12810) - * Fix "only mail on mention" bug (#12775) (#12789) - * Fix yet another bug with diff file names (#12771) (#12776) - * RepoInit Respect AlternateDefaultBranch (#12746) (#12751) - * Fix Avatar Resize (resize algo NearestNeighbor -> Bilinear) (#12745) (#12750) -* ENHANCEMENTS - * gitea dump: include version & Check InstallLock (#12760) (#12762) - -## [1.12.4](https://github.com/go-gitea/gitea/releases/tag/v1.12.4) - 2020-09-02 - -* SECURITY - * Escape provider name in oauth2 provider redirect (#12648) (#12650) - * Escape Email on password reset page (#12610) (#12612) - * When reading expired sessions - expire them (#12686) (#12690) -* ENHANCEMENTS - * StaticRootPath configurable at compile time (#12371) (#12652) -* BUGFIXES - * Fix to show an issue that is related to a deleted issue (#12651) (#12692) - * Expire time acknowledged for cache (#12605) (#12611) - * Fix diff path unquoting (#12554) (#12575) - * Improve HTML escaping helper (#12562) - * models: break out of loop (#12386) (#12561) - * Default empty merger list to those with write permissions (#12535) (#12560) - * Skip SSPI authentication attempts for /api/internal (#12556) (#12559) - * Prevent NPE on commenting on lines with invalidated comments (#12549) (#12550) - * Remove hardcoded ES indexername (#12521) (#12526) - * Fix bug preventing transfer to private organization (#12497) (#12501) - * Keys should not verify revoked email addresses (#12486) (#12495) - * Do not add prefix on http/https submodule links (#12477) (#12479) - * Fix ignored login on compare (#12476) (#12478) - * Fix incorrect error logging in Stats indexer and OAuth2 (#12387) (#12422) - * Upgrade google/go-github to v32.1.0 (#12361) (#12390) - * Render emoji's of Commit message on feed-page (#12373) - * Fix handling of diff on unrelated branches when Git 2.28 used (#12370) - -## [1.12.3](https://github.com/go-gitea/gitea/releases/tag/v1.12.3) - 2020-07-28 - -* BUGFIXES - * Don't change creation date when updating Release (#12343) (#12351) - * Show 404 page when release not found (#12328) (#12332) - * Fix emoji detection in certain cases (#12320) (#12327) - * Reduce emoji size (#12317) (#12327) - * Fix double-indirection bug in logging IDs (#12294) (#12308) - * Link to pull list page on sidebar when view pr (#12256) (#12263) - * Extend Notifications API and return pinned notifications by default (#12164) (#12232) - -## [1.12.2](https://github.com/go-gitea/gitea/releases/tag/v1.12.2) - 2020-07-11 - -* BUGFIXES - * When deleting repository decrese user repository count in cache (#11954) (#12188) - * Return full commit message instead of summary in commits API (#12186) (#12187) - * Properly set HEAD when a repo is created with a default branch that is not named 'master' (#12135) (#12182) - * Ensure GPG Subkeys are verified (#12155) (#12168) - * Fix failing to cache last commit with key being to long (#12151) (#12161) - * Multiple small admin dashboard fixes (#12153) (#12156) - * Remove spurious logging of " Delete all repository archives" at startup (#12139) (#12148) - * Fix repository setup instructions when default branch is not named 'master' (#12122) (#12147) - * Move EventSource to SharedWorker (#12095) (#12130) - * Fix ui bug in wiki commit page (#12089) (#12125) - * Fix gitgraph branch continues after merge (#12044) (#12105) - * Set the base url when migrating from Gitlab using access token or username without password (#11852) (#12104) - * Ensure BlameReaders close at end of request (#12102) (#12103) - * Fix panic when adding review comment (#12058) -* ENHANCEMENTS - * Disable dropzone's timeout for file uploads (#12024) (#12032) - -## [1.12.1](https://github.com/go-gitea/gitea/releases/tag/v1.12.1) - 2020-06-21 - -* BUGFIXES - * Handle multiple merges in gitgraph.js (#11996) (#12000) - * Add serviceworker.js to KnownPublicEntries (#11992) (#11994) - * For language detection do not try to analyze big files by content (#11971) (#11975) -* ENHANCEMENTS - * Fix scrollable header on dropdowns (#11893) (#11965) - -## [1.11.8](https://github.com/go-gitea/gitea/releases/tag/v1.11.8) - 2020-06-21 - -* BUGFIXES - * Really fix __webpack_public_path__ for 1.11 (#11961) - -## [1.12.0](https://github.com/go-gitea/gitea/releases/tag/v1.12.0) - 2020-06-17 - -* BREAKING - * When using API CreateRelease set created_unix to the tag commit time (#11218) - * Enable ENABLE_HARD_LINE_BREAK by default for rendering markdown (#11162) - * Fix sanitizer config - multiple rules (#11133) - * Remove check on username when using AccessToken authentication for the API (#11015) - * Return 404 from Contents API when items don't exist (#10323) - * Notification API should always return a JSON object with the current count of notifications (#10059) - * Remove migration support from versions earlier than 1.6.0 (#10026) -* SECURITY - * Use -1 to disable key algorithm type in ssh.minimum_key_sizes (#11635) (#11662) -* FEATURES - * Improve config logging when WrappedQueue times out (#11174) - * Add branch delete to API (#11112) - * Use markdown frontmatter to provide Table of contents, language and frontmatter rendering (#11047) - * Add a way to mark Conversation (code comment) resolved (#11037) - * Handle yaml frontmatter in markdown (#11016) - * Cache PullRequest Divergence (#10914) - * Make `gitea admin auth list` formatting configurable (#10844) - * Add Matrix webhook (#10831) - * Add Organization Wide Labels (#10814) - * Allow to set protected file patterns for files that can not be changed under no conditions (#10806) - * Option to set default branch at repository creation (#10803) - * Add request review from specific reviewers feature in pull request (#10756) - * Add NextCloud oauth (#10562) - * System-wide webhooks (#10546) - * Relax sanitization as per https://github.com/jch/html-pipeline (#10527) - * Use media links for img in post-process (#10515) - * Add API endpoints to manage OAuth2 Application (list/create/delete) (#10437) - * Render READMEs in docs/ .gitea or .github from root (#10361) - * Add feishu webhook support (#10229) - * Cache last commit to accelerate the repository directory page visit (#10069) - * Implement basic app.ini and path checks to doctor cmd (#10064) - * Make WorkerPools and Queues flushable (#10001) - * Implement "embedded" command to extract static resources (#9982) - * Add API endpoint for repo transfer (#9947) - * Make archive prefixing configurable with a global setting (#9943) - * Add Unique Queue infrastructure and move TestPullRequests to this (#9856) - * Issue/PR Context Popups (#9822) - * Add "Update Branch" button to Pull Requests (#9784) - * Add require signed commit for protected branch (#9708) - * Mark PR reviews as stale at push and allow to dismiss stale approvals (#9532) - * Add API notification endpoints (#9488) - * Issue search support elasticsearch (#9428) - * Add API branch protection endpoint (#9311) - * Add a new command doctor to check if some wrong configurations on gitea instance (#9095) - * Add support for migrating from Gitlab (#9084) - * Add support for database schema in PostgreSQL (#8819) - * Add setting to set default and global disabled repository units. (#8788) - * Language statistics bar for repositories (#8037) - * Restricted users (#6274) -* BUGFIXES - * Fix commenting on non-utf8 encoded files (#11916) (#11950) - * Use google/uuid to instead satori/go.uuid (#11943) (#11946) - * Align show/hide outdated button on code review block (#11932) (#11944) - * Update to go-git v5.1.0 (#11936) (#11941) - * Use ID or Where to instead directly use Get when load object from database (#11925) (#11934) - * Update CommitsAhead CommitsBehind on Pull BaseBranch Change too (#11912) (#11915) - * Invalidate comments when file is shortened (#11882) (#11884) - * Rework api/user/repos for pagination (#11827) (#11877) - * Handle more pathological branch and tag names (#11843) (#11863) - * Add doctor check to set IsArchived false if it is null (partial #11853) (#11859) - * Prevent panic on empty HOST for mysql (#11850) (#11856) - * Use DEFAULT_PAGING_NUM instead of MAX_RESPONSE_ITEMS in ListOptions (#11831) (#11836) - * Fix reply octicon (#11821) (#11822) - * Honor DEFAULT_PAGING_NUM for API (#11805) (#11813) - * Ensure rejected push to refs/pull/index/head fails nicely (#11724) (#11809) - * In File Create/Update API return 404 if Branch does not exist (#11791) (#11795) - * Fix doer of rename repo (#11789) (#11794) - * Initialize SimpleMDE when making a code comment (#11749) (#11785) - * Fix timezone on issue deadline (#11697) (#11784) - * Fix to allow comment poster to edit or delete his own comments (#11671) (#11774) - * Show full 500 error in API when Gitea in dev mode (#11641) (#11753) - * Add missing templates for Matrix system webhooks (#11729) (#11748) - * Fix verification of subkeys of default gpg key (#11713) (#11747) - * Fix styling for commiter on diff view (#11715) (#11744) - * Properly truncate system notices (#11714) (#11742) - * Handle expected errors in FileCreate & FileUpdate API (#11643) (#11718) - * Fix missing authorization check on pull for public repos of private/limited org (#11656) (#11682) - * Doctor check & fix db consistency (#11111) (#11676) - * Exclude generated files from language statistics (#11653) (#11670) - * Return json on 500 error from API (#11574) (#11659) - * When must change password only show Signout (#11600) (#11637) - * Backport various styling fixes (#11619) - * Fix wrong milestone in webhook message (#11596) (#11611) - * Fix serviceworker output file and misc improvements (#11562) (#11610) - * When initialising repositories ensure that the user doing the creation is the initializer (#11601) (#11608) - * Prevent empty query parameter being set on dashboard (#11561) (#11604) - * Fix images in wiki edit preview (#11546) (#11602) - * Prevent (caught) panic on login (#11590) (#11597) - * Prevent transferring repos to invisible orgs (#11517) (#11549) - * Move serviceworker to workbox and fix SSE interference (#11538) (#11547) - * API PullReviewComment HTMLPullURL should return the HTMLURL (#11501) (#11533) - * Fix repo-list private and total count bugs (#11500) (#11532) - * Fix form action template substitutions on admin pages (backport #11519) (#11531) - * Fix a bug where the reaction emoji doesn't disappear. (#11489) (#11530) - * TrimSpace when reading InternalToken from a file (#11502) (#11524) - * Fix selected line color in arc-green (#11492) (#11520) - * Make localstorage read ssh or https correctly (#11483) (#11490) - * Check branch protection on IsUserAllowedToUpdate (#11448) - * Fix margin on attached segment headers when they are separated by other element (#11425) - * Fix webhook template when validation errors occur (#11421) - * Fix NPE in template due to missing signing key on commit page (#11392) - * Restore active background to Register button on Register page (#11390) - * Fix hook failure due to relative LFS_CONTENT_PATH (#11362) - * Correctly set the organization num repos (#11339) - * Prevent 500 with badly formed task list (#11328) - * Allow compare page to look up base, head, own-fork, forkbase-of-head (#11327) - * Handle panics that percolate up to the graceful module (#11291) - * Don't allow registration via the web form, when AllowOnlyExternalRegistration is True (#11248) - * Patch fomantic-ui to workaround build issue (#11244) - * Prevent panic during wrappedConn close at hammertime (#11219) - * On logout force redirect to start page (#11202) - * Fix creation of Organization repos by Users with max created personal repos (#11183) - * Add option to increase provided OAuth2 token maximum size (#11180) - * Log the indexer path on failure (#11172) - * Ensure that relative paths in edit preview work (#11143) - * Make API EditIssue and EditPullRequest issue notifications (#11123) - * Send 404 immediately for known public requests (#11117) - * Remove nil inserts in models (#11096) - * Add GetReviews() to RetryDownloader (#11093) - * Remove nonexistent serviceworker entries (#11091) - * Simplify and fix GetApprovalCounts (#11086) - * Fix wiki revision template and simplify some tmpl conditions (#11080) - * Make branch parameter optional for /api/v1/repos/{owner}/{repo}/contents/{filepath} (#11067) - * Align review-item svg octicons (#11065) - * Automatically remove Watches, Assignments, etc if user loses access due to being removed as collaborator or from a team (#10997) - * Users should not be able to prohibit their own login (#10970) - * Fix scrollbar issues in dropdowns (#10897) - * Change the order of issues.closed_by to list opening user first (#10876) - * Allow site admin to check /api/v1/orgs endpoints (#10867) - * Avoid logging []byte in queue failures - convert to string first (#10865) - * Use ErrKeyUnableToVerify if fail to calc fingerprint in ssh-keygen (#10863) - * Fix assignees double load bug (#10856) - * Handle push rejection in branch and upload (#10854) - * In authorized_keys use double-quote for windows compatibility (#10841) - * Fix milestone template (#10824) - * log.Fatal on failure to listen to SSH port (#10795) - * Fix forked repo has no icon and language stat. (#10791) - * Fix tag/release deletion (#10663) - * Fix webhook migration (#10641) - * Migration for deleting orphaned dependencies (#10617) - * Add migration to fix the old broken merge-bases (#10604) - * Update templates for Go 1.14 (#10596) - * Remove unnecessary parentheses in wiki/view template (#10583) - * Change default value of DefaultCommandExecutionTimeout to match docs (#10581) - * Handle panic in indexer initialisation better (#10534) - * Set correct content_type value for Gogs/Gitea webhooks (#9504) (#10456) - * Fixed wrong AppSubUrl in multiple templates (#10447) - * Fix profile page CSS (#10406) - * Inject SVG sprite via ajax (#10320) - * Fix migration information update bug when linked github account (#10310) - * Allow admin to check org membership by API for other users (#10201) - * Fix topics dropdown (#10167) - * Ensure DeleteUser is not allowed to Delete Orgs and visa versa (#10134) - * Fix IsErrPullClosed (#10093) - * Accept punctuation after simple+cross repository issue references (#10091) - * On merge of already closed PR redirect back to the pulls page (#10010) - * Fix crowdin update script (#9969) - * Fix pull view when head repository or head branch missed and close related pull requests when delete head repository or head branch (#9927) - * Add option to prevent LDAP from deactivating everything on empty search (#9879) - * Fix admin handling at merge of PR (#9749) - * err_admin_name_pattern_not_allowed String Clarification (#9731) - * Fix wrong original git service type on a migrated repository (#9693) - * Fix ref links in issue overviews for tags (#8742) -* ENHANCEMENTS - * Fix search form button overlap (#11840) (#11864) - * Make tabular menu styling consistent for arc-green (#11570) (#11798) - * Add option to API to update PullRequest base branch (#11666) (#11796) - * Increase maximum SQLite variables count to 32766 (#11696) (#11783) - * Update emoji dataset with skin tone variants (#11678) (#11763) - * Add logging to long migrations (#11647) (#11691) - * Change language statistics to save size instead of percentage (#11681) (#11690) - * Allow different HardBreaks settings for documents and comments (#11515) (#11599) - * Fix alignment for commits on dashboard (#11595) (#11680) - * Default MSSQL port 0 to allow automatic detection by default (#11642) (#11673) - * Handle expected errors in AddGPGkey API (#11644) (#11661) - * Close EventSource before unloading the page (#11539) (#11557) - * Ensure emoji render with regular font-weight (#11541) (#11545) - * Fix webpack chunk loading with STATIC_URL_PREFIX (#11526) (#11542) - * Tweak reaction buttons (#11516) - * Use more toned colors for selected line (#11493) (#11511) - * Increase width for authors on commit view (#11441) - * Hide archived repos by default in repo-list (#11440) - * Better styling for code review comment textarea (#11428) - * Support view individual commit for wiki pages (#11415) - * Fix yellow background on active elements in code review (#11414) - * Better styling for code review comment form (#11413) - * Change install description on homepage (#11395) - * Ensure search action button is coalesced to adjacent input (#11385) - * Switch code editor to Monaco (#11366) - * Add paging and archive/private repository filtering to dashboard list (#11321) - * Changed image of openid-connect logo for better look on arc-green theme (#11312) - * Load Repo Topics on blame view too (#11307) - * Change the style in admin notice content view from `<p>` to `<pre>` (#11301) - * Allow log.xxx.default to set logging settings for the default logger only (#11292) - * Automatically attempt auto recovery of broken disk queues (Update lunny/levelqueue to 0.3.0) (#11285) - * Make sendmail a Process and have default timeout (#11256) - * Check value of skip-repository flag in dump command (#11254) - * Fix submit review form (#11252) - * Allow unauthenticated users to compare (#11240) - * Add EventSource support (#11235) - * Refactor Milestone related (#11225) - * Add pull review API endpoints (#11224) - * Add a 'this' to issue close/reopened messages (#11204) - * When migrating from Gitlab map Approvals to approving Reviews (#11147) - * Improve representation of attachments in issues (#11141) - * Protect default branch against deletion (#11115) - * Add X-Total-Count on /repos/{owner]/{repo}/pulls API endpoint (#11113) - * Fix status label on branches list vertical alignment (#11109) - * Add single release page and latest redirect (#11102) - * Add missing commit states to PR checks template (#11085) - * Change icon on title for merged PR to git-merge (#11064) - * Add MergePull comment type instead of close for merge PR (#11058) - * Upgrade jQuery to 3.5.0, remove jQuery-Migrate, fix deprecations (#11055) - * Consolidate author name across timeline (#11053) - * Refactor UpdateOAuth2Application (#11034) - * Support unicode emojis and remove emojify.js (#11032) - * Add git hook "warning" to admin panel (#11030) - * Add flash notify for email preference setting success (#11027) - * Remove package code.gitea.io/gitea/modules/git import out of models (#11025) - * Match arc-green code tag color to code blocks (#11023) - * Move syntax highlighting to web worker (#11017) - * Prevent merge of outdated PRs on protected branches (#11012) - * Add Get/Update for api/v1/user/applications/oauth2 (#11008) - * Upgrade to most recent bluemonday (#11007) - * Tweak code tags in markdown (#11000) - * Reject duplicate AccessToken names (#10994) - * Fix Ctrl-Enter shortcut for issues (#10986) - * Provide `OwnerName` field for README template (#10981) - * Prettify Timeline (#10972) - * Add issue subscription check to API (#10967) - * Use AJAX for notifications table (#10961) - * Adjust label padding (#10957) - * Avoiding directory execution on hook (#10954) (#10955) - * Migrate ActivityHeatmap to Vue SFC (#10953) - * Change merge strategy: do not check write access if user in merge white list (#10951) - * Enable GO111MODULE=on globally in Makefile (#10939) - * API endpoint to get single commit via SHA and Ref (#10915) - * Add accordion to release list and hide non-latest (#10910) - * Split dashboard elements into separate template files (#10885) - * Add more message on sidebar menus (#10872) - * Set MySQL rowtype to dynamic for new tables (#10833) - * Completely fix task-list checkbox styling (#10798) - * Hide gear icon for user who can't use them on sidebar (#10750) - * Refactor Cron and merge dashboard tasks (#10745) - * Change review status icons on pr view style to github style (#10737) - * Make pagination optional for API list notification endpoints (#10714) - * Fix tab indentation in code view (#10671) - * Fix task-list checkbox styling (#10668) - * Multiple LFS improvements (#10667) - * Make PR message on pushes configurable (#10664) - * Move dropzone.js to npm/webpack (#10645) - * Ensure Update button is enabled even when CI has failed (#10640) - * Add restricted user filter to LDAP authentication (#10600) - * Add Yandex OAuth2 provider (#8335) (#10564) - * Make avatar lookup occur at image request (#10540) - * Prevent accidental selection of language stats bar (#10537) - * Add fluid-icon (#10491) - * Inform participants on UI too (#10473) - * Build with go 1.14 (and raise minimum go version to 1.12) (#10467) - * Add max-file-size to LFS (#10463) - * Enable paggination for ListRepoTags API (#10454) - * Update JS dependencies (#10450) - * Show the username as a fallback on feeds if full name is blank (#10438) - * Various dark theme fixes (#10416) - * Display pull request head branch even the branch deleted or repository deleted (#10413) - * Prevent Firefox from using apple-touch-icon (#10402) - * Fix input[type=file] on dark theme (#10382) - * Improve mobile review-box sizing (#10297) - * Notification: queue ui.go notification-service (#10281) - * Add detected file language to code search (#10256) - * Index code and stats only for non-empty repositories (#10251) - * Add Approval Counts to pulls list (#10238) - * Limit label list height on edit issue page (#10216) - * Improve 404 error message (#10214) - * Tweak locale to respect singular conflicting file message in PR list (#10177) - * Fix commit view (#10169) - * Reorganize frontend files and tooling (#10168) - * Allow emoji on popup label (#10166) - * ListIssues add filter for milestones API (#10148) - * Show if a PR has conflicting files on the PR lists (#10130) - * Fix inconsistent label color format in API (#10129) - * Show download count info in release list (#10124) - * Add Octicon SVG spritemap (#10107) - * Update aria-fixed semantic-dropdown to fomantic master (#10096) - * Fix apple-touch-icon, regenerate images (#10065)(#10006) - * Style blockquote for default issue mail template (#10024) - * More expansions in template repositories (#10021) - * Allow list collaborators for users with Read access to repo (#9995) - * Add explicit dimensions to navbar avatar (#9986) - * Remove loadCSS and preload woff2 icon fonts (#9976) - * Fix commit view JS features, reimplement folding (#9968) - * Fix review avatar image (#9962) - * Improve notification pager (#9821) - * Move jquery and jquery-migrate to npm/webpack (#9813) - * Change font to Roboto to support more charsets (#9803) - * Move mailer to use a queue (#9789) - * Issue search on my related repositories (#9758) - * Add "before" query to ListIssueComments and ListRepoIssueComments API (#9685) - * Move tracked time api convert to convert package (#9665) - * Improve PR info in default merge message (#9635) - * Granular webhook events (#9626) - * Add Reviewed-on in commit message (#9623) - * Add top author stats to activity page (#9615) - * Allow repo admin to merge PR regardless of review status (#9611) - * Migrate reactions when migrating repository from github (#9599) - * API orgEditTeam make Fields optional (#9556) - * Move create/fork repository from models to modules/repository (#9489) - * Migrate reviews when migrating repository from github (#9463) - * Times API add filters (#9373) - * Move push commits from models to modules/repository (#9370) - * Add API endpoint to check notifications [Extend #9488] (#9595) - * Add GET /orgs API endpoint (#9560) - * API add/generalize pagination (#9452) - * Make create org repo API call same as github (#9186) -* BUILD - * Turn off go modules for xgo and gxz (#10963) - * Add gitea-vet (#10948) - * Rename scripts to build and add revive command as a new build tool command (#10942) - * Add 'make lint', restructure 'compliance' pipeline (#10861) - * Move JS build dependencies to 'dependencies' (#10763) - * Use whitelist to find go files, run find only once (#10594) - * Move vue and vue-calendar-heatmap to npm/webpack (#10188) - * Move jquery.are-you-sure to npm/webpack (#10063) - * Move highlight.js to npm/webpack (#10011) - * Generate Bindata if TAGS="bindata" and not up-to-date (#10004) - * Move CSS build to webpack (#9983) - * Move fomantic target, update 'make help' (#9945) - * Add css extraction and minification to webpack (#9944) - * Misc webpack tweaks (#9924) - * Make node_modules a order-only prerequisite (#9923) - * Update documentation for the go module era (#9751) - * Move swagger-ui to webpack/npm and update it to 3.24.3 (#9714) - * Use npm to manage fomantic and only build needed components (#9561) -* MISC - * Add gnupg to Dockerfile (#11365) - * Update snapcraft.yaml for core18 and latest features (#11300) - * Update JS dependencies, min Node.js version 10.13 (#11246) - * Change default charset for MySQL on install to utf8mb4 (#10989) - * Return issue subscription status from API subscribe (#10966) - * Fix queue log param (#10733) - * Add warning when using relative path to app.ini (#10104) - -## [1.11.7](https://github.com/go-gitea/gitea/releases/tag/v1.11.7) - 2020-06-18 - -* BUGFIXES - * Use ID or Where to instead directly use Get when load object from database (#11925) (#11935) - * Fix __webpack_public_path__ for 1.11 (#11907) - * Fix verification of subkeys of default gpg key (#11713) (#11902) - * Remove unnecessary parentheses in wiki/view template (#11781) - * Doctor fix xorm.Count nil on sqlite error (#11741) - -## [1.11.6](https://github.com/go-gitea/gitea/releases/tag/v1.11.6) - 2020-05-30 - -* SECURITY - * Fix missing authorization check on pull for public repos of private/limited org (#11656) (#11683) - * Use session for retrieving org teams (#11438) (#11439) -* BUGFIXES - * Return json on 500 error from API (#11574) (#11660) - * Fix wrong milestone in webhook message (#11596) (#11612) - * Prevent (caught) panic on login (#11590) (#11598) - * Fix commit page js error (#11527) - * Use media links for img in post-process (#10515) (#11504) - * Ensure public repositories in private organizations are visible and fix admin organizations list (#11465) (#11475) - * Set correct Content-Type value for Gogs/Gitea webhooks (#9504) (#10456) (#11461) - * Allow all members of private orgs to see public repos (#11442) (#11459) - * Whenever the ctx.Session is updated, release it to save it before sending the redirect (#11456) (#11457) - * Forcibly clean and destroy the session on logout (#11447) (#11451) - * Fix /api/v1/orgs/* endpoints by changing parameter to :org from :orgname (#11381) - * Add tracked time fix to doctor (part of #11111) (#11138) - * Fix webpack chunk loading with STATIC_URL_PREFIX (#11526) (#11544) - * Remove unnecessary parentheses in wiki/revision.tmpl to allow 1.11 to build on go1.14 (#11481) - -## [1.11.5](https://github.com/go-gitea/gitea/releases/tag/v1.11.5) - 2020-05-09 - -* BUGFIXES - * Prevent timer leaks in Workerpool and others (#11333) (#11340) - * Fix tracked time issues (#11349) (#11354) - * Add NotifySyncPushCommits to indexer notifier (#11309) (#11338) - * Allow X in addition to x in tasks (#10979) (#11335) - * When delete tracked time through the API return 404 not 500 (#11319) (#11326) - * Prevent duplicate records in organizations list when creating a repository (#11303) (#11325) - * Manage port in submodule refurl (#11305) (#11323) - * api.Context.NotFound(...) should tolerate nil (#11288) (#11306) - * Show pull request selection even when unrelated branches (#11239) (#11283) - * Repo: milestone: make /milestone/:id endpoint accessible (#11264) (#11282) - * Fix GetContents(): Dont't ignore Executables (#11192) (#11209) - * Fix submodule paths when AppSubUrl is not root (#11098) (#11176) - * Prevent clones and pushes to disabled wiki (#11131) (#11134) - * Remove errant third closing curly-bracket from account.tmpl and send account ID in account.tmpl (#11130) - * On Repo Deletion: Delete related TrackedTimes too (#11110) (#11125) - * Refresh codemirror on show pull comment tab (#11100) (#11122) - * Fix merge dialog on protected branch with missing required statuses (#11074) (#11084) - * Load pr Issue Poster on API too (#11033) (#11039) - * Fix release counter on API repository info (#10968) (#10996) - * Generate Diff and Patch direct from Pull head (#10936) (#10938) - * Fix rebase conflict detection in git 2.26 (#10929) (#10930) -* ENHANCEMENT - * Fix 404 and 500 image size in small size screen (#11043) (#11049) - * Multiple Gitea Doctor improvements (#10943) (#10990) (#10064) (#9095) (#10991) - -## [1.11.4](https://github.com/go-gitea/gitea/releases/tag/v1.11.4) - 2020-04-01 - -* BUGFIXES - * Only update merge_base if not already merged (#10909) - * Fix milestones too many SQL variables bug (#10880) (#10904) - * Protect against NPEs in notifications list (#10879) (#10883) - * Convert plumbing.ErrObjectNotFound to git.ErrNotExist in getCommit (#10862) (#10868) - * Convert plumbing.ErrReferenceNotFound to git.ErrNotExist in GetRefCommitID (#10676) (#10797) - * Account for empty lines in receive-hook message (#10773) (#10784) - * Fix bug on branch API (#10767) (#10775) - * Migrate to go-git/go-git v5.0.0 (#10735) (#10753) - * Fix hiding of fields in authorization source page (#10734) (#10752) - * Prevent default for linkAction (#10742) (#10743) - -## [1.11.3](https://github.com/go-gitea/gitea/releases/tag/v1.11.3) - 2020-03-10 - -* BUGFIXES - * Prevent panic in stopwatch (#10670) (#10673) - * Fix bug on pull view when required status check no ci result (#10648) (#10651) - * Build explicitly with Go 1.13 (#10684) - -## [1.11.2](https://github.com/go-gitea/gitea/releases/tag/v1.11.2) - 2020-03-06 - -* BREAKING - * Various fixes in login sources (#10428) (#10429) -* SECURITY - * Ensure only own addresses are updated (#10397) (#10399) - * Logout POST action (#10582) (#10585) - * Org action fixes and form cleanup (#10512) (#10514) - * Change action GETs to POST (#10462) (#10464) - * Fix admin notices (#10480) (#10483) - * Change admin dashboard to POST (#10465) (#10466) - * Update markbates/goth (#10444) (#10445) - * Update crypto vendors (#10385) (#10398) -* BUGFIXES - * Allow users with write permissions to modify issue descriptions and comments. (#10623) (#10626) - * Handle deleted base branch in PR (#10618) (#10619) - * Delete dependencies when deleting a repository (#10608) (#10616) - * Ensure executable bit is kept on the web editor (#10607) (#10614) - * Update mergebase in pr checker (#10586) (#10605) - * Fix release attachments being deleted while upgrading (#10572) (#10573) - * Fix redirection path if Slack webhook channel is invalid (#10566) - * Fix head.tmpl og:image picture location (#10531) (#10556) - * Fix 404 after activating secondary email (#10547) (#10553) - * Show Signer in commit lists and add basic trust (#10425 & #10511) (#10524) - * Fix potential bugs (#10513) (#10518) - * Use \[:space:\] instead of \\s (#10508) (#10509) - * Avoid mailing users that have explicitly unwatched an issue (#10475) (#10500) - * Handle push rejection message in Merge & Web Editor (#10373) (#10497) - * Fix SQLite concurrency problems by using BEGIN IMMEDIATE (#10368) (#10493) - * Fix double PR notification from API (#10482) (#10486) - * Show the username as a fallback on feeds if full name is blank (#10461) - * Trigger webhooks on issue label-change via API too (#10421) (#10439) - * Fix git reference type in webhooks (#10427) (#10432) - * Prevent panic on merge to PR (#10403) (#10408) - * Fix wrong num closed issues on repository when close issue via commit… (#10364) (#10380) - * Reading pull attachments should depend on read UnitTypePullRequests (#10346) (#10354) - * Set max-width on review-box comment box (#10348) (#10353) - * Prevent nil pointer in GetPullRequestCommitStatusState (#10342) (#10344) - * Fix protected branch status check settings (#10341) (#10343) - * Truncate long commit message header (#10301) (#10319) - * Set the initial commit status to Success otherwise it will always be Pending (#10317) (#10318) - * Don't manually replace whitespace during render (#10291) (#10315) -* ENHANCEMENT - * Admin page for managing user e-mail activation (#10557) (#10579) - -## [1.11.1](https://github.com/go-gitea/gitea/releases/tag/v1.11.1) - 2020-02-15 - -* BUGFIXES - * Repo name added to automatically generated commit message when merging (#9997) (#10285) - * Fix Workerpool deadlock (#10283) (#10284) - * Divide GetIssueStats query in smaller chunks (#10176) (#10282) - * Fix reply on code review (#10257) - * Stop hanging issue indexer initialisation from preventing shutdown (#10243) (#10249) - * Fix filter label emoji width (#10241) (#10244) - * Fix issue sidebar menus having an infinite height (#10239) (#10240) - * Fix commit between two commits calculation if there is only last commit (#10225) (#10226) - * Only check for conflicts/merging if the PR has not been merged in the interim (#10132) (#10206) - * Blacklist manifest.json & milestones user (#10292) (#10293) - -## [1.11.0](https://github.com/go-gitea/gitea/releases/tag/v1.11.0) - 2020-02-10 - -* BREAKING - * Fix followers and following tabs in profile (#10202) (#10203) - * Make CertFile and KeyFile relative to CustomPath (#9868) (#9874) - * Remove unused endpoints (#9538) - * Prefix all user-generated IDs in markup (#9477) - * Enforce Gitea environment for pushes (#8982) - * Hide some user information via API if user have not enough permissions (#8655) - * Move startpage/homepage translation to crowdin (#8596) -* SECURITY - * Never allow an empty password to validate (#9682) (#9683) - * Prevent redirect to Host (#9678) (#9679) - * Swagger hide search field (#9554) - * Add "search" to reserved usernames (#9063) - * Switch to fomantic-ui (#9374) - * Only serve attachments when linked to issue/release and if accessible by user (#9340) -* FEATURES - * Webhooks should only show sender if it makes sense (#9601) - * Provide Default messages for merges (#9393) - * Add description to labels on create issue (#9392) - * Graceful Queues: Issue Indexing and Tasks (#9363) - * Default NO_REPLY_ADDRESS to DOMAIN (#9325) - * Allow FCGI over unix sockets (#9298) - * Graceful: Xorm, RepoIndexer, Cron and Others (#9282) - * Add API for Reactions (#9220) - * Graceful: Cancel Process on monitor pages & HammerTime (#9213) - * Graceful: Allow graceful restart for unix sockets (#9113) - * Graceful: Allow graceful restart for fcgi (#9112) - * Sign protected branches (#8993) - * Add Graceful shutdown for Windows and hooks for shutdown of goroutines (#8964) - * Add Gitea icon to Emojis (#8950) - * Expand/Collapse Files and Blob Excerpt while Reviewing/Comparing code (#8924) - * Allow Custom Reactions (#8886) - * Close/reopen issues by keywords in titles and comments (#8866) - * Allow incompletely specified Time Formats (#8816) - * Prevent upload (overwrite) of lfs locked file (#8769) - * Template Repositories (#8768) - * Add /milestones endpoint (#8733) - * Make repository management section handle lfs locks (#8726) - * Respect LFS File Lock on UI (#8719) - * Add team option to grant rights for all organization repositories (#8688) - * Enabling and disabling the commit button to prevent empty commits (web editor) (#8590) - * Add setting to disable BASIC authentication (#8586) - * Expose db.SetMaxOpenConns and allow non MySQL dbs to set conn pool params (#8528) - * Allow Protected Branches to Whitelist Deploy Keys (#8483) - * Push to create repo (#8419) - * Sign merges, CRUD, Wiki and Repository initialisation with gpg key (#7631) - * Add basic repository lfs management (#7199) -* BUGFIXES - * Fix code-expansion arc-green theme bug (#10180) (#10185) - * Prevent double wait-group decrement (#10170) (#10175) - * Allow emoji on review head comments (#10159) (#10174) - * Fix issue/pull link (#10158) (#10173) - * Fix push-create SSH bugs (#10145) (#10151) - * Prevent DeleteUser API abuse (#10125) (#10128) - * Fix issues/pulls dashboard paging error (#10114) (#10115) - * Add button to revert SimpleMDE to plain textarea (#10099) (#10102) - * Fix branch page pull request title and link error (#10092) (#10097) - * Fix PR API: Only try to get HeadBranch if HeadRepo exist (#10029) (#10088) - * Update topics repo count when deleting repository (#10051) (#10081) - * Show pull icon on pull requests (#10061) (#10062) - * Fix milestone API state parameter unhandled (#10049) (#10052) - * Move to using a temporary repo for pushing new PRs (#10009) (#10042) - * Fix wiki raw view on sub path (#10002) (#10040) - * Ensure that feeds are appropriately restricted (#10018) (#10019) - * Sanitize credentials in mirror form (#9975) (#9991) - * Close related pull requests when deleting head repository or head branch (#9927) (#9974) - * Switch to use -f instead of -F for sendmail (#9961) (#9970) - * Fix file rename/copy not supported by indexer (#9965) (#9967) - * Fix repo indexer not updating upon push (#9957) (#9963) - * Don't convert ellipsis in markdown (#9905) (#9937) - * Fixed repo link in generated comment for cross repository dependency (#9863) (#9935) - * Check if diff actually contains sections when rendering (#9926) (#9933) - * Fix wrong hint when status checking is running on pull request view (#9886) (#9928) - * Fix RocketChat (#9908) (#9921) - * Do not try to recreate ldap user if they are already created (#9900) (#9919) - * Create terminated channel in queue_redis (#9910) (#9911) - * Prevent empty LDAP search result from deactivating all users (#9879) (#9896) - * Fix wrong permissions check when issues/prs shared operations (#9885) (#9889) - * Check user != nil before checking values (#9881) (#9883) - * Allow hyphen in language name (#9873) (#9880) - * Ensure that 2fa is checked on reset-password (#9857) (#9876) - * Fix issues/pulls dependencies problems (#9842) (#9864) - * Fix markdown anchor links (#9673) (#9840) - * Allow assignee on Pull Creation when Issue Unit is deactivated (#9836) (#9837) - * Fix download file wrong content-type (#9825) (#9834) - * Fix wrong poster identity on a migrated pull request when submit review (#9827) (#9830) - * Fix database dump when log directory is missing (#9818) (#9819) - * Fix compare (#9808) (#9814) - * Fix push-to-create (#9772) (#9797) - * Fix missing msteam webhook on organization (#9781) (#9794) - * Fix missing unlock in uniquequeue (#9790) (#9791) - * Fix add team on collaborator page when same name as organization (#9778) - * DeleteRepoFile incorrectly handles Delete to new branch (#9769) (#9775) - * Fix milestones page (#9771) - * Fix SimpleMDE quote reply (#9757) (#9768) - * Fix missing updated time on migrated issues and comments (#9744) (#9764) - * Move Errored PRs out of StatusChecking (#9675) (#9726) - * Make hook status printing configurable with delay (#9641) (#9725) - * Fix /repos/issues/search (#9698) (#9724) - * Silence fomantic error regarding tabs (#9713) (#9718) - * Remove unused lock (#9709) (#9710) - * Remove q.lock.Unlock() in setInternal to prevent panic (#9705) (#9706) - * Load milestone in API PR list (#9671) (#9700) - * Don't attempt to close issue if already closed (#9696) (#9699) - * Remove google font call (#9668) (#9681) - * Eliminate horizontal scroll caused by footer (#9674) - * Fix nil reference in repo generation (#9660) (#9666) - * Add HTML URL to API Issues (#9654) (#9661) - * Add PR review webhook to Telegram (#9653) (#9655) - * Use filepath.IsAbs instead of path.IsAbs (#9651) (#9652) - * Disable remove button on repository teams when have access to all (#9640) - * Clean up old references on branch delete (#9614) - * Hide public repos owned by private orgs (#9609) - * Fix access issues on milestone and issue overview pages. (#9603) - * Fix error logged when repos qs is empty (#9591) - * Dont trigger notification twice on issue assignee change (#9582) - * Fix mirror pushed commit actions (#9572) - * Allow only specific columns to be updated on issue via API (#9189) (#9539) - * Fix default avatar for ghost user (#9536) - * Fix download of release attachments with same name (#9529) - * Resolve deprecated INI conversion (#9525) - * Ignore empty avatars during database migration (#9520) - * Fix deleted branch isn't removed when push the branch again (#9516) - * Fix repository issues pagination bug when there are more than one label filter (#9512) - * Fix SetExpr failed (#9506) - * Remove obsolete file private/push_update.go (#9503) - * When recreating hooks, delete them first so they are recreated with the umask (#9502) - * Properly enforce gitea environment for pushes (#9501) - * Fix datarace on repo indexer queue (#9490) - * Add call to load repo prior to redirect in add/remove dependency code (#9484) - * Wrap the code indexer (#9476) - * Use Req.URL.RequestURI() to cope with FCGI urls (#9473) - * Set default ssh.minimum_key_sizes (#9466) - * Fixed issue with paging in /repos/{owner}/{repo}/git/trees/{sha} api (#9459) - * Fix wrong notification on merge (#9450) - * Issue with Migration rule v111 (#9449) - * Trigger webhook when deleting a branch after merging a PR (#9424) - * Add migration to sanitize repository original_url (#9423) - * Use OriginalURL instead of CloneAddr in migration logging (#9418) - * Push update after branch is restored (#9416) - * Fix wrong migration (#9381) - * Fix show repositories filter (#9234) (#9379) - * Fix Slack webhook payload title generation to work with Mattermost (#9378) - * Fix double webhook for new PR (#9375) - * AuthorizedKeysCommand should not query db directly (#9371) - * Fix missed change to GetManager() (#9361) - * Fix cache problem on dashboard (#9358) - * RepoIndexer: DefaultBranch needs to be prefixed by BranchPrefix (#9356) - * Fix protected branch using IssueID (#9348) - * Fix nondeterministic behavior (#9341) - * Fix PR/issue redirects when having external tracker (#9339) - * Remove release attachments which repository has been deleted (#9334) - * Fix issue indexer not triggered when migrating a repository (#9332) - * Add SyncTags to uploader interface (#9326) - * Fix bug that release attachment files not deleted when deleting repository (#9322) - * Only sync tags after all migration release batches are completed (#9319) - * File Edit: Author/Committer interchanged (#9297) - * prebuild CSS/JS before xgo release binaries (#9293) - * Log: Ensure FLAGS=none shows no flags (#9287) - * Make Diff Detail on Pull Request Changed File UI always on Top (#9280) - * Switch CSS minifier to cssnano (#9260) - * Fix latest docker image haven't include static files. (#9252) - * Don't link wiki revision to commit (#9244) - * Change review content column to type text in db (#9229) - * Fixed topic regex pattern and added search by topic links after save (#9219) - * Add language to user API response (#9215) - * Correct tooltip message blocked by dependencies (#9211) - * Add SimpleMDE and Fix Image Paste for Issue/Comment Editor (#9197) - * Fix panic when diff (#9187) - * Fix #9151 - smtp logger configuration sendTos should be an array (#9154) - * Fix max length check and limit in multiple repo forms (#9148) - * Always Show Password Field on Link Account Sign-in Page (#9147) - * Properly fix displaying virtual session provider in admin panel (#9137) - * Fix race condition on indexer (#9136) - * Fix team links in HTML rendering (#9127) - * Fix race condition in ReplaceSanitizer (#9123) - * Fix what information is shown about user in API (#9115) - * Fix nil context user for template repositories (#9099) - * Hide given credentials for migrated repos. (#9097) - * Fix reCAPTCHA API URL (#9083) - * Fix password checks on admin create/edit user (#9076) - * Update golang.org/x/crypto vendor to use acme v2 (#9056) - * Ensure Written is set in GZIP ProxyResponseWriter (#9018) - * Fix wrong system notice when repository is empty (#9010) - * Fix broken link to branch from issue list (#9003) - * Fix bug when pack js (#8992) - * New review approvals shouldn't require a message (#8991) - * Shadow password correctly for session config (#8984) - * Don't send notification on pending reviews (#8943) - * Fix Notify Create Ref Error on tag creation (#8936) - * Convert EOL to UNIX-style to render MD properly (#8925) - * Migrate temp_repo.go to use git.NewCommand (#8918) - * Fix issue with user.fullname (#8902) - * Add Close() method to gogitRepository (#8901) - * Enable punctuations ending mentions (#8889) - * Fix password complexity check on registration (#8887) - * Fix require external registration password (#8885) - * Fix edit content button on migrated issue content (#8877) - * Fix permission checks for close/reopen from commit (#8875) - * Fix API Bug (fail on empty assignees) (#8873) - * Stop using git count-objects and use raw directory size for repository (#8848) - * Fix count for commit graph last page (#8843) - * Fix to close opened io resources as soon as not needed (#8839) - * Improve notification (#8835) - * Fix new user form for non-local users (#8826) - * Fix: remove duplicated signed commit icons (#8820) - * Fix (open/closed) issue count when label excluded (#8815) - * Fix SSH2 conditional in key parsing code (#8806) - * Fix 500 when edit hook (#8782) - * On windows set core.longpaths true (#8776) - * Fix commit expand button to not go to commit link (#8745) - * Avoid re-issuing redundant cross-references. (#8734) - * Fix milestone close timestamp function (#8728) - * Move webhook codes from service to webhook notification (#8712) - * Show zero lines on the line counter if the file empty (#8700) - * Fix deadline on update issue or PR via API (#8696) - * make call createMilestoneComment on newIssue func (#8678) - * Send tag create and push webhook when release created on UI (#8671) - * Prevent chrome download page as html with alt + click (#8669) - * Fix 500 when getting user as unauthenticated user (#8653) - * Graceful fixes (#8645) - * Add SubURL to redirect path (#8632) (#8634) - * Fix extra columns from `label` table (#8633) - * Add SubURL to redirect path for transferred/renamed repos (#8632) - * Fix bug when migrate from API (#8631) - * Allow to merge if file path contains " or \ (#8629) - * Prevent removal of non-empty emoji panel following selection of duplicate (#8609) - * Ensure default gpg settings not nil and found commits have reference to repo (#8604) - * Set webhook Content-Type for application/x-www-form-urlencoded (#8599) - * Fix #8582 by handling empty repos (#8587) - * Fix of the diff statistics view on pull request's (#8581) - * Fix bug on pull requests when transfer head repository (#8564) - * Fix template error on account page (#8562) - * Allow externalID to be UUID (#8551) - * Fix ignored error on editorconfig api (#8550) - * Fix user avatar name (#8547) - * Ensure that GitRepo is set on Empty repositories (#8539) - * Add missed close in ServeBlobLFS (#8527) - * Fix migrate mirror 500 bug (#8526) - * Fix password complexity regex for special characters (on master) (#8525) -* ENHANCEMENTS - * Explicitly refer to PR in squash-merge commit message in case of external tracker (#9844) (#9855) - * Add a /user/login landing page option (#9622) - * Some more e-mail notification fixes (#9596) - * Add branch protection option to block merge on requested changes. (#9592) - * Add footer extra links template (#9576) - * Fix for a wrong URL in activity page of repository. (#9571) - * Update default issue template (#9568) - * Change markdown rendering from blackfriday to goldmark (#9533) - * Extend file create api with dates (#9464) - * Add ActionCommentPull action (#9456) - * Response for context on retry database connection (#9444) - * Refactor webhooks to reduce code duplication (#9422) - * update couchbase deps for new license (#9419) - * Add .ignore file for search tools (#9417) - * Remove unsued struct (#9405) - * Hide not allowed Reactions (#9387) - * Remove text from action-only webhooks (#9377) - * Move PushToBaseRepo from models to services/pull (#9352) - * Site admin could view org's members (#9346) - * Sleep longer if request speed is over github limitation (#9335) - * Refactor comment (#9330) - * Refactor code indexer (#9313) - * Remove SavePatch and generate patches on the fly (#9302) - * Move some pull request functions from models to services (#9266) - * Update JS dependencies (#9255) - * Show label list on label set (#9251) - * Redirect issue if repo has configured external tracker. (#9247) - * Allow kbd tags (#9245) - * Remove unused comment actions (#9222) - * Fixed errors logging in dump.go (#9218) - * Expose release counter to repo API response (#9214) - * Make consistent links to repository in the Slack/Mattermost notificiations (#9205) - * Expose pull request counter to repo API response (#9202) - * Extend TrackedTimes API (#9200) - * Extend StopWatch API (#9196) - * Move code indexer related code to a new package (#9191) - * Docker: ask s6 to stop all service when gitea stop (#9171) - * Variable expansion in repository templates (#9163) - * Add avatar and issue labels to template repositories (#9149) - * Show single review comments in the PR conversation tab (#9143) - * Extract createComment (#9125) - * Move PushUpdateOptions from models to repofiles (#9124) - * Alternate syntax for cross references (#9116) - * Add USE_SERVICE_WORKER setting (#9110) - * Only show part of members on orgnization dashboard and add paging for orgnization members page (#9092) - * Explore page: Add topic param to pagination (#9077) (#9078) - * Markdown: Sanitizier Configuration (#9075) - * Add password requirement info on error (#9074) - * Allow authors to use act keywords in PR content (#9059) - * Move modules/gzip to gitea.com/macaron/gzip (#9058) - * Branch protection: Possibility to not use whitelist but allow anyone with write access (#9055) - * Context menus for comments, add quote reply (#9043) - * Update branch API endpoint to show effective branch protection. (#9031) - * Move git graph from models to modules/graph (#9027) - * Move merge actions to notification (#9024) - * Move mirror sync actions to notification (#9022) - * Add retry for migration http/https requests (#9019) - * Rewrite delivery of issue and comment mails (#9009) - * Add review comments to mail notifications (#8996) - * Refactor pull request review (#8954) - * Githook highlighter (#8932) - * Add git hooks and webhooks to template repositories; move to services (#8926) - * Only view branch or tag if it match refType requested. (#8899) - * Drop Admin attribute based on LDAP when login (continue #1743) (#8849) - * Add additional periods to activity page (#8829) - * Update go-org to optimize code (#8824) - * Move some actions to notification/action (#8779) - * Webhook support custom proxy (#8760) - * Fix API deadline removal (#8759) - * Mark review comment as invalidated when file is deleted (#8751) - * Move pull list code to a separate file (#8748) - * Move webhook to a standalone package under modules (#8747) - * Multi repo select on issue page (#8741) - * apply exclude label on milestone issue list (#8739) - * Move issue notifications and assignee man (#8713) - * Move issue change content from models to service (#8711) - * Move issue change status from models to service (#8691) - * Move more issue assignee code from models to issue service (#8690) - * Create PR on Current Repository by Default (#8670) - * Improve Open Graph Protocol (#8637) - * Batch hook pre- and post-receive calls (#8602) - * Improve webhooks (#8583) - * Move transfer repository and rename repository on a service package and start action notification (#8573) - * Implement/Fix PR review webhooks (#8570) - * Rewrite markdown rendering to blackfriday v2 and rewrite orgmode rendering to go-org (#8560) - * Move some repositories' operations to a standalone service package (#8557) - * Allow more than 255 characters for tokens in external_login_user table (#8554) - * Move issue label operations to issue service package (#8553) - * Adjust error reporting from merge failures and use LC_ALL=C for git (#8548) - * Mail assignee when issue/pull request is assigned (#8546) - * Allow committing / adding empty files using the web ui (#8420) (#8532) - * Move sync mirror actions to mirror service package (#8518) - * Remove arrows on numeric inputs (#8516) - * Support inline rendering of CUSTOM_URL_SCHEMES (#8496) - * Recalculate repository access only for specific user (#8481) - * Add download button for rull request diff- and patch-file (#8470) - * Add single sign-on support via SSPI on Windows (#8463) - * Move change issue title from models to issue service package (#8456) - * Add included tag on branch view (#8449) - * Make static resouces web browser cache time customized on app.ini (#8442) - * Enable Uploading/Removing Attachments When Editing an Issue/Comment (#8426) - * Add pagination to commit graph page (#8360) - * Use templates for issue e-mail subject and body (#8329) - * Move clearlabels from models to issue service (#8326) - * Move AddTestPullRequestTask to pull service package from models (#8324) - * Team permission to create repository in organization (#8312) - * Allows external rendering of other filetypes (#8300) - * Add 'Alt + click' feature to exclude labels (#8199) - * Configurable close and reopen keywords for PRs (#8120) - * Configurable URL for static resources (#7911) - * Unifies commit list in repository commit table and wiki revision page (#7907) - * Allow cross-repository dependencies on issues (#7901) - * Auto-subscribe user to repository when they commit/tag to it (#7657) - * Restore Graceful Restarting & Socket Activation (#7274) - * wiki - add 'write' 'preview' buttons to wiki edit like in issues (#7241) - * Change target branch for pull request (#6488) - * Display PR commits and diffs using base repo rather than forked (#3648) -* TESTING - * Add debug option to serv to help debug problems (#9492) - * Fix the intermittent TestGPGGit failures (#9360) - * Testing: Update postgres sequences (#9304) - * Missed defer prepareTestEnv (#9285) - * Fix "data race" in testlogger (#9159) - * Yet another attempt to fix the intermittent failure of gpg git test (#9146) - * integrations: Fix Dropped Test Errors (#9040) - * services/mirror: fix dropped test errors (#9007) - * Fix intermittent GPG Git test failure (#8968) - * Update Github Migration Tests (#8893) (#8938) - * Update heatmap fixtures to restore tests (#8615) -* TRANSLATION - * Fix Korean locales (#9761) (#9780) - * Fix placeholders in the error message (#9060) - * Fix spelling of admin.users.max_repo_creation (#8934) - * Improve german translation of homepage (#8549) -* BUILD - * Fix webpack polyfills (#9735) (#9738) - * Update gitea.com/macaron to 1.4.0 (#9608) - * Upgrade lato fonts to v16. (#9498) - * Update alpine to 3.11 (#9440) - * Upgrade blevesearch (#9177) - * Remove built js/css files from git (#9114) - * Move semantic.dropdown.custom.js to webpack (#9064) - * Check compiled files during build (#9042) - * Enable lazy-loading of gitgraph.js (#9036) - * Pack web_src/js/draw.js to public/js/index.js (#8975) - * Modernize js and use babel (#8973) - * Move index.js to web_src and use webpack to pack them (#8598) - * Restrict modules/graceful to non-windows build and shim IsChild (#8537) - * Upgrade gopkg.in/editorconfig/editorconfig-core-go.v1 (#8501) -* DOCS - * Swagger info corrections (#9441) (#9558) - * Add ALLOW_ONLY_EXTERNAL_REGISTRATION to config cheat sheet (#8986) - * Rephrase comment about RuntimeDirectory option in systemd config (#8912) - * Explicitly indicate the socket unit to use the service unit "gitea.service" (#8804) - * Adjust the must-change-password help (#8755) - * Add notice to docs for migrating from more recent versions of Gogs (#8724) - * Add explicit info about customization of homepage (#8694) - * Change external asciidoctor tool to embedded mode (#8677) - * Add Docker fail2ban configuration (#8642) - * Correct some outdated statements in the contributing guidelines (#8612) - * Basic Design guidelines (describing different parts of the code) (#8601) - * Display Gitea logo in Readme (#8592) - * Fix building from source docs to ref AppWorkPath (#8567) - * Update the provided gitea.service to mention socket activation (#8531) - * Doc added how to setup email (#8520) -* MISC - * Backport Locales [2020-01-14] (#9773) - * Add translatable Powered by Gitea text in footer (#9600) - * Add contrib/environment-to-ini (#9519) - * Remove unnecessary loading of settings in update hook (#9496) - * Update gitignore list (#9437) - * Update license list (#9436) - * Fix background reactions in the arc-green theme (#9421) - * Update and fix chardet import (#9351) - * Ensure LF on checkouts and in editors (#9259) - * Fixed topics margin (#9248) - * Add comment to exported function WindowsServiceName (make revive) (#9241) - * Remove empty lines on issues/pulls page (#9232) - * Fix Add Comment Button's "+" Position (#9140) - * Add first issue comment hashtag (#9052) - * Change some label colors (#9051) - * Fix double scroll in branch dropdown (#9048) - * Add comment highlight when target from url (#9047) - * Update display of reactions to issues and comments (#9038) - * Button tooltip formatting under Branches (#9034) - * Allow setting default branch via API (#9030) - * Update dashboard context for PR reviews (#8995) - * Show repository size in repo home page and settings (#8940) - * Allow to add and remove all repositories to/from team. (#8867) - * Show due date in dashboard issues list (#8860) - * Theme arc-green: reverse heatmap colors (#8840) - * Project files table style update (#8757) - * gitignore debugging file from vscode (#8740) - * Add API for Issue set Subscription (#8729) - * Make 100% width search bar (#8710) - * Update color theme for heatmap (#8709) - * Add margin to title_wip_desc (#8705) - * Improve visibility of "Pending" indicator (#8685) - * Improve accessibility of dropdown menus (#8638) - * Make /users/{username}/repos list private repos the current user has access to (#8621) - * Prevent .code-view from overriding font on icon fonts (#8614) - * Add id references on all issue events to allow internal linking (#8608) - * Upgrade xorm to v0.8.0 (#8536) - * Upgrade gopkg.in/ini.v1 (#8500) - * Update CodeMirror to version 5.49.0 (#8381) - * Wiki editor: enable side-by-side button (#7242) - -## [1.10.6](https://github.com/go-gitea/gitea/releases/tag/v1.10.6) - 2020-03-10 - -This is a re-tag version of v1.10.5 and also explicitly built with Go 1.13. - -WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be used. - -## [1.10.5](https://github.com/go-gitea/gitea/releases/tag/v1.10.5) - 2020-03-06 - -* BUGFIXES - * Fix release attachments being deleted while upgrading (#10572) (#10574) - -## [1.10.4](https://github.com/go-gitea/gitea/releases/tag/v1.10.4) - 2020-02-16 - -* FEATURE - * Prevent empty LDAP search from deactivating all users (#9879) (#9890) -* BUGFIXES - * Fix reply on code review (#10261) (#10227) - * Fix branch page pull request title and link error (#10092) (#10098) - * Fix milestone API state parameter unhandled (#10049) (#10053) - * Fix wiki raw view on sub path (#10002) (#10041) - * Fix RocketChat Webhook (#9908) (#9921) (#9925) - * Fix bug about wrong dependencies permissions check and other wrong permissions check (#9884) (Partial backport #9842) - * Ensure that 2fa is checked on reset-password (#9857) (#9877) - -## [1.10.3](https://github.com/go-gitea/gitea/releases/tag/v1.10.3) - 2020-01-17 - -* SECURITY - * Hide credentials when submitting migration (#9102) (#9704) - * Never allow an empty password to validate (#9682) (#9684) - * Prevent redirect to Host (#9678) (#9680) - * Hide public repos owned by private orgs (#9609) (#9616) -* BUGFIXES - * Allow assignee on Pull Creation when Issue Unit is deactivated (#9836) (#9838) - * Fix download file wrong content-type (#9825) (#9835) - * Fix wrong identify poster on a migrated pull request when submit review (#9827) (#9831) - * Fix dump non-exist log directory (#9818) (#9820) - * Fix compare (#9808) (#9815) - * Fix missing msteam webhook on organization (#9781) (#9795) - * Fix add team on collaborator page when same name as organization (#9783) - * Fix cache problem on dashboard (#9358) (#9703) - * Send tag create and push webhook when release created on UI (#8671) (#9702) - * Branches not at ref commit ID should not be listed as Merged (#9614) (#9639) - -## [1.10.2](https://github.com/go-gitea/gitea/releases/tag/v1.10.2) - 2020-01-02 - -* BUGFIXES - * Allow only specific Columns to be updated on Issue via API (#9539) (#9580) - * Add ErrReactionAlreadyExist error (#9550) (#9564) - * Fix bug when migrate from API (#8631) (#9563) - * Use default avatar for ghost user (#9536) (#9537) - * Fix repository issues pagination bug when there are more than one label filter (#9512) (#9528) - * Fix deleted branch not removed when push the branch again (#9516) (#9524) - * Fix missing repository status when migrating repository via API (#9511) - * Trigger webhook when deleting a branch after merging a PR (#9510) - * Fix paging on /repos/{owner}/{repo}/git/trees/{sha} API endpoint (#9482) - * Fix NewCommitStatus (#9434) (#9435) - * Use OriginalURL instead of CloneAddr in migration logging (#9418) (#9420) - * Fix Slack webhook payload title generation to work with Mattermost (#9404) - * DefaultBranch needs to be prefixed by BranchPrefix (#9356) (#9359) - * Fix issue indexer not triggered when migrating a repository (#9333) - * Fix bug that release attachment files not deleted when deleting repository (#9322) (#9329) - * Fix migration releases (#9319) (#9326) (#9328) - * Fix File Edit: Author/Committer interchanged (#9297) (#9300) - -## [1.10.1](https://github.com/go-gitea/gitea/releases/tag/v1.10.1) - 2019-12-05 - -* BUGFIXES - * Fix max length check and limit in multiple repo forms (#9148) (#9204) - * Properly fix displaying virtual session provider in admin panel (#9137) (#9203) - * Upgrade levelqueue to 0.1.0 (#9192) (#9199) - * Fix panic when diff (#9187) (#9193) - * Smtp logger configuration sendTos should be an array (#9154) (#9157) - * Always Show Password Field on Link Account Sign-in Page (#9150) - * Create PR on Current Repository by Default (#8670) (#9141) - * Fix race on indexer (#9136) (#9139) - * Fix reCAPTCHA URL (#9119) - * Hide migrated credentials (#9098) - * Update golang.org/x/crypto vendor to use acme v2 (#9056) (#9085) - * Fix password checks on admin create/edit user (#9076) (#9081) - * Fix add search as a reserved username (#9063) (#9065) - * Fix permission checks for close/reopen from commit (#8875) (#9033) - * Ensure Written is set in GZIP ProxyResponseWriter (#9018) (#9025) - * Fix broken link to branch from issue list (#9003) (#9021) - * Fix wrong system notice when repository is empty (#9020) - * Shadow password correctly for session config (#8984) (#9002) - -## [1.10.0](https://github.com/go-gitea/gitea/releases/tag/v1.10.0) - 2019-11-13 - -* BREAKING - * Fix deadline on update issue or PR via API (#8698) - * Hide some user information via API if user doesn't have enough permission (#8655) (#8657) - * Remove legacy handling of drone token (#8191) - * Change repo search to use exact match for topic search. (#7941) - * Add pagination for admin api get orgs and fix only list public orgs bug (#7742) - * Implement the ability to change the ssh port to match what is in the gitea config (#7286) -* SECURITY - * Fix issue with user.fullname (#8903) - * Ignore mentions for users with no access (#8395) - * Be more strict with git arguments (#7715) - * Extract the username and password from the mirror url (#7651) - * reserve .well-known username (#7637) -* FEATURES - * Org/Members: display 2FA members states + optimize sql requests (#7621) - * SetDefaultBranch on pushing to empty repository (#7610) - * Adds side-by-side diff for images (#6784) - * API method to list all commits of a repository (#6408) - * Password Complexity Checks (#6230) - * Add option to initialize repository with labels (#6061) - * Add additional password hash algorithms (#6023) -* BUGFIXES - * Allow to merge if file path contains " or \ (#8629) (#8771) - * On windows set core.longpaths true (#8776) (#8786) - * Fix 500 when edit hook (#8782) (#8789) - * Fix Checkbox at RepoSettings Protected Branch (#8799) (#8801) - * Fix SSH2 conditional in key parsing code (#8806) (#8810) - * Fix commit expand button to not go to commit link (#8745) (#8825) - * Fix new user form for non-local users (#8826) (#8828) - * Fix to close opened io resources as soon as not needed (#8839) (#8846) - * Fix edit content button on migrated issue content (#8877) (#8884) - * Fix require external registration password (#8885) (#8890) - * Fix password complexity check on registration (#8887) (#8888) - * Update Github Migration Tests (#8896) (#8938) (#8945) - * Enable punctuations ending mentions (#8889) (#8894) - * Add Close() method to gogitRepository (#8901) (#8956) - * Hotfix for review actions and notifications (#8965) - * Expose db.SetMaxOpenConns and allow non MySQL dbs to set conn pool params (#8528) (#8618) - * Fix milestone close timestamp (#8728) (#8730) - * Fix 500 when getting user as unauthenticated user (#8653) (#8663) - * Fix 'New Issue Missing Milestone Comment' (#8678) (#8681) - * Use AppSubUrl for more redirections (#8647) (#8651) - * Add SubURL to redirect path (#8632) (#8634) - * Fix template error on account page (#8562) (#8622) - * Allow externalID to be UUID (#8551) (#8624) - * Prevent removal of non-empty emoji panel following selection of duplicate (#8609) (#8623) - * Update heatmap fixtures to restore tests (#8615) (#8616) - * Ensure that diff stats can scroll independently of the diff (#8581) (#8621) - * Webhook: set Content-Type for application/x-www-form-urlencoded (#8600) - * Fix #8582 by handling empty repos (#8587) (#8594) - * Fix bug on pull requests when transfer head repository (#8564) (#8569) - * Add missed close in ServeBlobLFS (#8527) (#8542) - * Ensure that GitRepo is set on Empty repositories (#8539) (#8541) - * Fix migrate mirror 500 bug (#8526) (#8530) - * Fix password complexity regex for special characters (#8524) - * Prevent .code-view from overriding font on icon fonts (#8614) (#8627) - * Allow more than 255 characters for tokens in external_login_user table (#8554) - * Fix errors in create org UI regarding team access permission (#8506) - * Fix bug on FindExternalUsersByProvider (#8504) - * Create .ssh dir as necessary (#8486) - * IsBranchExist: return false if provided name is empty (#8485) - * Making openssh listen on SSH_LISTEN_PORT not SSH_PORT (#8477) - * Add check for empty set when dropping indexes during migration (#8471) - * LFS files are relative to LFS content path, ensure that when deleting they are made relative to this (#8455) - * Ensure Request Body Readers are closed in LFS server (#8454) - * Fix template bug on mirror repository setting page (#8438) - * Fix migration v96 to keep issue attachments (#8435) - * Update strk.kbt.io/projects/go/libravatar to latest (#8429) - * Singular form for files that has only one line (#8416) - * Check for either escaped or unescaped wiki filenames (#8408) - * Allow users with explicit read access to give approvals (#8382) - * Fix editor commit to new branch if PR disabled (#8375) - * readd .markdown class to all markup renderers (#8357) - * Upgrade xorm to v0.7.9 to fix some bugs (#8354) - * Fix column name ambiguity in GetUserIssueStats() (#8347) - * Change general form binding to gogs form (#8334) - * Fix pull request commit status in user dashboard list (#8321) - * Fix repo_admin_change_team_access always checked in org settings (#8319) - * Update to github.com/lafriks/xormstore@v1.3.0 (#8317) - * Show correct commit status in PR list (#8316) - * Bugfix for image compare and minor improvements to image compare (#8289) - * Update xorm (#8286) - * Fix API for edit and delete release attachment (#8285) - * Fix nil object access in some conditions when parsing cross references (#8281) - * Fix label count (#8267) - * Only show teams access for organization repositories on collaboration setting page (#8265) - * Test more reserved usernames (#8263) - * Rewrite reference processing code in preparation for opening/closing from comment references (#8261) - * Fix assets key on release webhook (#8253) - * Allow registration when button is hidden (#8237) - * Fix release API URL generation (#8234) - * Fix milestone num_issues (#8221) - * MS Teams webhook misses commit messages (#8209) - * Fix data race (#8204) - * Fix team user api (#8172) - * Fix pull merge 500 error caused by git-fetch breaking behaviors (#8161) - * Make show private icon when repo avatar set (#8144) - * Add reviewers as participants (#8121) - * Fix Go 1.13 private repository go get issue (#8112) - * feat: highlight issue references with : (#8101) - * Make AllowedUsers configurable in sshd_config (#8094) - * Strict name matching for Repository.GetTagID() (#8074) - * Avoid ambiguity of branch/directory names for the git-diff-tree command (#8066) - * Add change title notification for issues (#8061) - * [ssh] fix the config specification in the authorized_keys template (#8031) - * Fix reading git notes from nested trees (#8026) - * Fixes synchronize tags to releases for repository - makes sure we are only getting tag refs (#7990) - * Fix adding default Telegram webhook (#7972) - * Run CORS handler first for /api routes (#7967) - * Abort synchronization from LDAP source if there is some error. (#7960) - * Fix wrong sender when send slack webhook (#7918) - * Fix bug when migrating a private repository (#7917) - * Evaluate emojis in commit messages in list view (#7906) - * Fix upload file type check (#7890) - * lfs/lock: round locked_at timestamp to second (#7872) - * fix non existent milestone with 500 error instead of 404 (#7867) - * gpg/bugfix: Use .ExpiredUnix.IsZero to display green color of forever valid gpg key (#7846) - * Fix duplicate call of webhook (#7821) - * Enable switching to a different source branch when PR already exists (#7819) - * Convert files to utf-8 for indexing (#7814) - * Do not fetch all refs in pull-request compare (#7797) - * Fix multiple bugs with statuses endpoints at API (#7785) - * Restore functionality for early gits (#7775) - * Fix Slack webhook fork message (#7774) - * Rewrite existing repo units if setting is not included in api body (#7763) - * Fix rename failed when rewrite public keys (#7761) - * Fix approvals counting (#7757) - * Add migration step to remove old repo_indexer_status orphaned records (#7746) - * Fix repo_index_status lingering when deleting a repository (#7734) - * Remove camel case tokenization from repo indexer (#7733) - * Fix milestone completness calculation when migrating (#7725) - * Regression: Include "executable" files in the index, as they are not necessarily … (#7718) - * Fixes indexed repos keeping outdated indexes when files grow too large (#7712) - * Skip non-regular files (e.g. submodules) on repo indexing (#7711) - * Fix dropTableColumns sqlite implementation (#7710) - * Update gopkg.in/src-d/go-git.v4 to v4.13.1 (#7705) - * improve branches list performance and fix protected branch icon when no-login (#7695) - * Correct wrong datetime format for git (#7689) - * Move add to hook queue for created repo to outside xorm session. (#7675) - * sugestion to use range .Branches (#7674) - * Fix bug on migrating milestone from github (#7665) - * hide delete/restore button on archived repos (#7658) - * css: use flex to fix floating paginate (#7656) - * Fix syntax highlight initialization (#7617) - * Fix panic on push at - Merging pull request causes 500 error (#7615) - * Make PKCS8, PEM and SSH2 keys work (#7600) - * Fix mistake in arc-green.less split-diff css code. (#7587) - * Handle ErrUserProhibitLogin in http git (#7586) - * Fix bug create/edit wiki pages when code master branch protected (#7580) - * Fixes Malformed URLs in API git/commits response (#7565) - * Fix file header overflow in file and blame views (#7562) - * Improve SSH key parser to handle newlines in keys (#7522) - * Fix empty commits now showing in repo overview (#7521) - * Fix repository's pull request count error (#7518) - * Fix markdown invoke sequence (#7513) - * Remove duplicated webhook trigger (#7511) - * Update User.NumRepos atomically in createRepository (#7493) - * Fix settings page of repo you aren't admin print error - Settings pages giving UnitType error message (#7482) - * Fix redirection after file edit - Handles all redirects for Web UI File CRUD (#7478) - * cmd/serv: actually exit after fatal errors (#7458) - * Fix an issue with some pages throwing 'not defined' js exceptions (#7450) - * fix Dropzone.js integration (#7445) - * Fix regex for issues in commit messages (#7444) - * Diff: Fix indentation on unhighlighted code (#7435) - * Only show "New Pull Request" button if repo allows pulls (#7426) - * Upgrade macaron/captcha to fix random error problem (#7407) - * create class for inline positioned lists (#7393) - * Fetch refs for successful testing for tag (#7388) - * add missing template variable on organisation settings (#7385) - * fix post parameter - on issue list - unset assignee (#7380) - * fix/define autochecked checkboxes on issue list in firefox (#7320) - * only return head: null if source branch was deleted (#6705) -* ENHANCEMENTS - * Add nofollow to sign in links (#8509) - * vendor: update mvdan.cc/xurls/v2 to v2.1.0 (#8495) - * Update milestone issues numbers when save milestone and other code improvements (#8411) - * Add extra user information when migrating release (#8331) - * Require overall success if no context is given for status check (#8318) - * Transaction-aware retry create issue to cope with duplicate keys (#8307) - * Change link on issue milestone (#8246) - * Alwaywas return local url for users avatar (#8245) - * Move some milestone functions to a standalone package (#8213) - * Move create issue comment to comments package (#8212) - * Disable max height property of comment textarea (#8203) - * Add 'Mentioning you' group to /issues page (#8201) - * oauth2 with remote Gitea (#8149) - * Reference issues from pull requests and other issues (#8137) - * Fix webhooks to use proxy from environment (#8116) - * Add merged commit id on pull view when it's merged (#8062) - * Add teams to repo on collaboration page. (#8045) - * Update swagger to 0.20.1 (#8010) - * Make link last commit massages in repository home page and commit tables (#8006) - * Add API endpoint for accessing repo topics (#7963) - * Include description in repository search (#7942) - * Use gitea forked macaron (#7933) - * Fix pull creation with empty changes (#7920) - * Allow token as authorization for accessing attachments (#7909) - * Retry create issue to cope with duplicate keys (#7898) - * Move git diff codes from models to services/gitdiff (#7889) - * migrate gplus to google oauth2 provider (#7885) - * Remove unique filter from repo indexer analyzer. (#7878) - * Detect delimiter in CSV rendering (#7869) - * Import topics during migration (#7851) - * Move CreateReview to modules/pull (#7841) - * vendor: update pdf.js to v2.1.266 (#7834) - * Support SSH_LISTEN_PORT env var in docker app.ini template (#7829) - * Add Ability for User to Customize Email Notification Frequency (#7813) - * Move database settings from models to setting (#7806) - * Display ui time with customize time location (#7792) - * Implement webhook branch filter (#7791) - * Restrict repository indexing by glob match (#7767) - * Api: advanced settings for repository (external wiki, issue tracker etc.) (#7756) - * Update migrated repositories' issues/comments/prs poster id if user has a github external user saved (#7751) - * deps: Upgrade gopkg.in/editorconfig/editorconfig-core-go.v1 (#7749) - * Apply emoji on commit graph page (#7743) - * Add a lot of extension to language mappings for syntax highlights (#7741) - * Add SQL execution on log and indexes on table repository and comment (#7740) - * Set DB connection error level to error (#7724) - * Check commit message hashes before making links (#7713) - * remove unnecessary fmt on generate bindata (#7706) - * Fix specific highlighting (CMakeLists.txt ...) (#7686) - * Add file status on API (#7671) - * Add support for DEFAULT_ORG_MEMBER_VISIBLE (#7669) - * Provide links in commit summaries in commits table/view list (#7659) - * Change length of some repository's columns (#7652) - * Move commit repo action from models to repofiles package (#7645) - * fix wrong email when use gitea as OAuth2 provider (#7640) - * [Branch View] add download button (#7604) - * Update to xorm@v0.7.4 (#7596) - * use 403 instead of 401 for ErrUserProhibitLogin (#7591) - * Removed unnecessary conversions (#7557) - * Un-lambda base.FileSize (#7556) - * Added missing error checks in tests (#7554) - * Move create release from models to a standalone package (#7539) - * Make default branch name link to default branch (#7519) - * Added total count of contributions to heatmap (#7517) - * Move mirror to a standalone package from models (#7486) - * Move models.PushUpdate to repofiles.PushUpdate (#7485) - * Include thread related headers in issue/coment mail (#7484) - * Refuse merge until all required status checks success (#7481) - * convert all js var to let/const (#7464) - * Only create branches for opened pull requestes when migrating from github (#7463) - * jQuery 3 (#7425) - * Add notification placeholder (#7409) - * Search Commits via Commit Hash (#7400) - * Move status table to cron package (#7370) - * wiki - page revisions list (#7369) - * Display original author and URL information when showing migrated issues/comments (#7352) - * Refactor filetype is not allowed errors (#7309) - * switch to use gliderlabs/ssh for builtin server (#7250) - * Remove setting dependency on modules/session (#7237) - * Move all mail related codes from models to services/mailer (#7200) - * Support git.PATH entry in app.ini (#6772) - * Support setting cookie domain (#6288) - * Move migrating repository from frontend to backend (#6200) - * Delete releases attachments if release is deleted (#6068) -* TRANSLATION - * Latvian translation for home page (#8468) - * Add home template italian translation (#8352) - * fix misprint (#7452) -* BUILD - * use go 1.13 (#8088) -* MISC - * add file line count info on UI (#8396) - * Make issues page left menu 100% width and add reponame as title attribute (#8359) - * [arc-green] white on hover for active menu items (#8344) - * Move ref (branch or tag) location on issue list page (#8157) - * apply emoji on dashboard issue list labels (#8156) - * 1148: Take up the full width when viewing the diff in split view. (#8114) - * Display description of 'make this repo private' as help text, not as tooltip (#8097) - * Fixes deformed emoji in pull request reviews (#8047) - * Add strike to old header on comment (#8046) - * Add tooltip for the visibility checkbox in /repo/create (#8025) - * Update github.com/lafriks/xormstore and tidy up mod.go (#8020) - * keep blame view buttons sequence consistent with normal view when view a file (#8007) - * Use "Pull Request" instead of "Merge Request" (#8003) - * Move line number to :before attr to hide from search on browser (#8002) - * Changed black color to white for (read) number label on issue list page (#8000) - * [Branch View] show "New Pull Request" Button only if posible (#7977) - * Fix hook problem by only setting the git environment variables if we are passed them (#7854) - * Prevent Commit Status and Message From Overflowing On Branch Page (#7800) - * Fix global search result CSS, misc CSS tweaks (#7789) - * Tweak label border CSS (#7739) - * Fix create menu item widths (#7708) - * [Branch View] Delete duplicate protection symbol (#7624) - * [Branch View] Delete Table Header (#7622) - * [Branch View] icons to buttons (#7602) - * update js dependencies (#7462) - * Add Extra Info to Branches Page (#7461) - * Bump lodash from 4.17.11 to 4.17.14 (#7459) - * wiki history improvements (#7391) - * ui fixes - compare view and archieved repo issues (#7345) - * dark theme scrollbars (#7269) - * wiki - editor - add buttons 'inline code', 'empty checkbox', 'checked checkbox' (#7243) - * Fix Statuses API only shows first 10 statuses: Add paging and extend API GetCommitStatuses (#7141) - -## [1.9.6](https://github.com/go-gitea/gitea/releases/tag/v1.9.6) - 2019-11-13 - -* BUGFIXES - * Allow to merge if file path contains " or \ (#8629) (#8772) - * Fix 500 when edit hook (#8782) (#8790) - * Fix issue with user.fullname (#8904) - * Update Github Migration Test (#8897) (#8946) - * Add Close() method to gogitRepository (#8901) (#8958) - -## [1.9.5](https://github.com/go-gitea/gitea/releases/tag/v1.9.5) - 2019-10-30 - -* BREAKING - * Hide some user information via API if user doesn't have enough permission (#8655) (#8658) -* BUGFIXES - * Fix milestone close timestamp (#8728) (#8731) - * Fix deadline on update issue or PR via API (#8699) - * Fix 'New Issue Missing Milestone Comment' (#8678) (#8682) - * Fix 500 when getting user as unauthenticated user (#8653) (#8662) - * Use AppSubUrl for more redirections (#8647) (#8652) - * Add SubURL to redirect path (#8632) (#8634) (#8640) - * Fix #8582 by handling empty repos (#8587) (#8593) - * Fix bug on pull requests when transfer head repository (#8571) - * Add missed close in ServeBlobLFS (#8527) (#8543) - * Return false if provided branch name is empty for IsBranchExist (#8485) (#8492) - * Create .ssh dir as necessary (#8369) (#8486) (#8489) - * Restore functionality for early gits (#7775) (#8476) - * Add check for empty set when dropping indexes during migration (#8475) - * Ensure Request Body Readers are closed in LFS server (#8454) (#8459) - * Ensure that LFS files are relative to the LFS content path (#8455) (#8458) -* SECURITY - * Ignore mentions for users with no access (#8395) (#8484) -* TESTING - * Update heatmap fixtures to restore tests (#8615) (#8617) - -## [1.9.4](https://github.com/go-gitea/gitea/releases/tag/v1.9.4) - 2019-10-08 - -* BUGFIXES - * Highlight issue references (#8101) (#8404) - * Fix bug when migrating a private repository #7917 (#8403) - * Change general form binding to gogs form (#8334) (#8402) - * Fix editor commit to new branch if PR disabled (#8375) (#8401) - * Fix milestone num_issues (#8221) (#8400) - * Allow users with explicit read access to give approvals (#8398) - * Fix commit status in PR #8316 and PR #8321 (#8339) - * Fix API for edit and delete release attachment (#8290) - * Fix assets on release webhook (#8283) - * Fix release API URL generation (#8239) - * Allow registration when button is hidden (#8238) - * MS Teams webhook misses commit messages (backport v1.9) (#8225) - * Fix data race (#8206) - * Fix pull merge 500 error caused by git-fetch breaking behaviors (#8194) - * Fix the SSH config specification in the authorized_keys template (#8193) - * Fix reading git notes from nested trees (#8189) - * Fix team user api (#8172) (#8188) - * Add reviewers as participants (#8124) -* BUILD - * Use vendored go-swagger (#8087) (#8165) - * Fix version-validation for GO 1.13 (go-macaron/cors) (#8389) -* MISC - * Make show private icon when repo avatar set (#8144) (#8175) - -## [1.9.3](https://github.com/go-gitea/gitea/releases/tag/v1.9.3) - 2019-09-06 - -* BUGFIXES - * Fix go get from a private repository with Go 1.13 (#8100) - * Strict name matching for Repository.GetTagID() (#8082) - * Avoid ambiguity of branch/directory names for the git-diff-tree command (#8070) - * Add change title notification for issues (#8064) - * Run CORS handler first for /api routes (#7967) (#8053) - * Evaluate emojis in commit messages in list view (#8044) - * Fix failed to synchronize tags to releases for repository (#7990) (#7994) - * Fix adding default Telegram webhook (#7972) (#7992) - * Abort synchronization from LDAP source if there is some error (#7965) - * Fix deformed emoji in commit message (#8071) -* ENHANCEMENTS - * Keep blame view buttons sequence consistent with normal view when viewing a file (#8007) (#8009) - -## [1.9.2](https://github.com/go-gitea/gitea/releases/tag/v1.9.2) - 2019-08-22 - -* BUGFIXES - * Fix wrong sender when send slack webhook (#7918) (#7924) - * Upload support text/plain; charset=utf8 (#7899) - * Lfs/lock: round locked_at timestamp to second (#7872) (#7875) - * Fix non existent milestone with 500 error (#7867) (#7873) -* SECURITY - * Fix No PGP signature on 1.9.1 tag (#7874) - * Release built with go 1.12.9 to fix security fixes in golang std lib, ref: https://groups.google.com/forum/#!msg/golang-announce/oeMaeUnkvVE/a49yvTLqAAAJ -* ENHANCEMENTS - * Fix pull creation with empty changes (#7920) (#7926) -* BUILD - * Drone/docker: prepare multi-arch release + provide arm64 image (#7571) (#7884) - -## [1.9.1](https://github.com/go-gitea/gitea/releases/tag/v1.9.1) - 2019-08-14 - -* BREAKING - * Add pagination for admin api get orgs and fix only list public orgs bug (#7742) (#7752) -* SECURITY - * Be more strict with git arguments (#7715) (#7762) - * Release built with go 1.12.8 to fix security fixes in golang std lib, ref: https://groups.google.com/forum/#!topic/golang-nuts/fCQWxqxP8aA -* BUGFIXES - * Fix local runs of ssh-requiring integration tests (#7855) (#7857) - * Fix hook problem (#7856) (#7754) - * Use .ExpiredUnix.IsZero to display green color of forever valid gpg key (#7850) (#7846) - * Do not fetch all refs (#7797) (#7837) - * Fix duplicate call of webhook (#7824) (#7821) - * Enable switching to a different source branch when PR already exists (#7823) - * Rewrite existing repo units if setting is not included in api body (#7811) - * Prevent Commit Status and Message From Overflowing On Branch Page (#7800) (#7808) - * API: fix multiple bugs with statuses endpoints (Backport #7785) (#7807) - * Fix Slack webhook fork message (1.9 release backport) (#7783) - * Fix approvals counting (#7757) (#7777) - * Fix rename failed when rewrite public keys (#7761) (#7769) - * Fix dropTableColumns sqlite implementation (#7710) (#7765) - * Fix repo_index_status lingering when deleting a repository (#7738) - * Fix milestone completness calculation when migrating (#7725) (#7732) - * Fixes indexed repos keeping outdated indexes when files grow too large (#7731) - * Skip non-regular files (e.g. submodules) on repo indexing (#7717) - * Improve branches list performance and fix protected branch icon when no-login (#7695) (#7704) - * Correct wrong datetime format for git (#7689) (#7690) - -## [1.9.0](https://github.com/go-gitea/gitea/releases/tag/v1.9.0) - 2019-07-30 - -* BREAKING - * Better logging (#6038) (#6095) -* SECURITY - * Shadow the password on cache and session config on admin panel (#7300) - * Fix markdown invoke sequence (#7513) (#7560) - * Reserve .well-known username (#7638) - * Do not leak secrets via timing side channel (#7364) - * Ensure that decryption of cookie actually succeeds (#7363) -* FEATURES - * Content API for Creating, Updating, Deleting Files (#6314) - * Enable tls-alpn-01: Use certmanager provided TLSConfig for LetsEncrypt (#7229) - * Add command to convert mysql database from utf8 to utf8mb4 (#7144) - * Fixes #2738 - Adds the /git/tags API endpoint (#7138) - * Compare branches, commits and tags with each other (#6991) - * Show Pull Request button or status of latest PR in branch list (#6990) - * Repository avatars (#6986) - * Show git-notes (#6984) - * Add commit statuses reports on pull request view (#6845) - * Number of commits ahead/behind in branch overview (#6695) - * Add CLI commands to manage LDAP authentication source (#6681) - * Add support for MS Teams webhooks (#6632) - * OAuth2 Grant UI (#6625) - * Add SUBJECT_PREFIX mailer config option (#6605) - * Include custom configuration file in dump (#6516) - * Add API for manipulating Git hooks (#6436) - * Improve migrations to support migrating milestones/labels/issues/comments/pullrequests (#6290) - * Add option to blame files (#5721) - * Implement Default Webhooks (#4299) - * Telegram webhook (#4227) -* BUGFIXES - * Send webhook after commit when creating issue with assignees (#7681) (#7684) - * Upgrade macaron/captcha to fix random error problem (#7407) (#7683) - * Move add to hook queue for created repo to outside xorm session. (#7682) (#7675) - * Show protection symbol if needed on default branch (#7660) (#7668) - * Hide delete/restore button on archived repos (#7660) - * Fix bug on migrating milestone from github (#7665) (#7666) - * Use flex to fix floating paginate (#7656) (#7662) - * Change length of some repository's columns (#7652) (#7655) - * Fix wrong email when use gitea as OAuth2 provider (#7640) (#7647) - * Fix syntax highlight initialization (#7617) (#7626) - * Fix bug create/edit wiki pages when code master branch protected (#7580) (#7623) - * Fix panic on push at #7611 (#7615) (#7618) - * Handle ErrUserProhibitLogin in http git (#7586, #7591) (#7590) - * Fix color of split-diff view in dark theme (#7587) (#7589) - * Fix file header overflow in file and blame views (#7562) (#7579) - * Malformed URLs in API git/commits response (#7565) (#7567) - * Fix empty commits now showing in repo overview (#7521) (#7563) - * Fix repository's pull request count error (#7518) (#7524) - * Remove duplicated webhook trigger (#7511) (#7516) - * Handles all redirects for Web UI File CRUD (#7478) (#7507) - * Fix regex for issues in commit messages (#7444) (#7466) - * cmd/serv: actually exit after fatal errors (#7458) (#7460) - * Fix an issue with some pages throwing 'not defined' js exceptions #7450 (#7453) - * Fix Dropzone.js integration (#7445) (#7448) - * Create class for inline positioned lists (#7439) (#7393) - * Diff: Fix indentation on unhighlighted code (#7435) (#7443) - * jQuery 3 (#7442) (#7425) - * Only show "New Pull Request" button if repo allows pulls (#7426) (#7432) - * Fix vendor references (#7394) (#7396) - * Only return head: null if source branch was deleted (#6705) (#7376) - * Add missing template variable on organisation settings (#7386) (#7385) - * Fix post parameter on issue list which had unset assignee (#7380) (#7383) - * Fix migration tests due to issue 7 being resolved (#7375) (#7381) - * Correctly adjust mirror url (#6593) - * Handle early git version's lack of get-url (#7065) - * Fix icon position in issue view (#7354) - * Cut timeline length with last element on issue view (#7355) - * Fix mirror repository webhooks (#7366) - * Fix api route for hooks (#7346) - * Fix bug conflict between SyncReleasesWithTags and InsertReleases (#7337) - * Fix pull view ui merge section (#7335) - * Fix 7303 - remove unnessesary buttons on archived repos (#7326) - * Fix topic bar to allow prefixes (#7325) - * Fixes #7152 - Allow create/update/delete message to be empty, use default message (#7324) - * Fixes #7238 - Annotated tag commit ID incorrect (#7321) - * Dark theme fixes (#7319) - * Gitea own dark codemirror theme (#7317) - * Fixes #7292 - API File Contents bug (#7301) - * Fix API link header (#7298) - * Fix extra newlines when copying from diff in Firefox (#7288) - * Make diff line-marker non-selectable (#7279) - * Fix Submodule dection in subdir (#7275) - * Fix error log when loading issues caused by a xorm bug (#7271) - * Add .fa icon margin like .octicon (#7258) - * Fix hljs unintenionally highlighting commit links (#7244) - * Only check and config git on web subcommand but not others (#7236) - * Fix migration panic when Head.User is not exist (#7226) - * Only warn on errors in deleting LFS orphaned files during repo deletion (#7213) - * Fix duplicated file on pull request conflicted files (#7211) - * Allow colon between fixing word and issue (#7207) - * Fix overflow issues in repo (#7190) - * API error cleanup (#7186) - * Add error for fork already existing (#7185) - * Fixes diff on merged pull requests (#7171) - * If milestone id is zero don't get it from database (#7169) - * Fix pusher name via ssh push (#7167) - * Fix database lock when use random repository fallback image (#7166) - * Various fixes for issue mail notifications (#7165) - * Allow archived repos to be (un)starred and (un)watched (#7163) - * Fix GCArgs load from ini (#7156) - * Detect noreply email address as user (#7133) - * Avoid arbitrary format strings upon calling fail() function (#7112) - * Validate External Tracker URL Format (#7089) - * Repository avatar fallback configuration (#7087) - * Fix #732: Add LFS objects to base repository on merging (#7082) - * Install page - Handle invalid administrator username better (#7060) - * Workaround for posting single comments in split diff view (#7052) - * Fix possbile mysql invalid connnection error (#7051) - * Fix charset was not saved after installation finished (#7048) - * Handle insecure and ports in go get (#7041) - * Avoid bad database state after failed migration (#7040) - * Fix wrong init dependency on markup extensions (#7038) - * Fix default for allowing new organization creation for new users (#7017) - * Fix content download and /verify LFS handler expecting wrong content-type (#7015) - * Fix missing repo description when migrating (#7000) - * Fix LFS Locks over SSH (#6999) - * Do not attempt to return blob on submodule (#6996) - * Fix U2F for Chrome >= 74 (#6980) - * Fix index produces problem when issues/pulls deleted (#6973) - * Allow collaborators to view repo owned by private org (#6965) - * Stop running hooks on pr merge (#6963) - * Run hooks on merge/edit and cope with protected branches (#6961) - * Webhook Logs show proper HTTP Method, and allow change HTTP method in form (#6953) - * Stop colorizing log files by default (#6949) - * Rotate serv.log, http.log and hook logs and stop stacktracing in these (#6935) - * Fix plain text overflow line wrap (#6915) - * Fix input size for dependency select (#6913) - * Change drone token name to let users know to use oauth2 (#6912) - * Fix syntax highlight in blame view #6895 (#6909) - * Use AppURL for Oauth user link (#6894) - * Fixes #6881 - API users search fix (#6882) - * Fix 404 when send pull request some situation (#6871) - * Enforce osusergo build tag for releases (#6862) - * Fix 500 when reviewer is deleted with integration tests (#6856) - * Fix v85.go (#6851) - * Make dropTableColumns drop columns on sqlite and constraints on all (#6849) - * Fix double-generation of scratch token (#6832) (#6833) - * When mirroring we should set the remote to mirror (#6824) - * Fix the v78 migration "Drop is_bare" on MSSQL #6707 (#6823) - * Change verbose flag in dump command to avoid colliding with global version flag (#6822) - * Fix #6813: Allow git.GetTree to take both commit and tree names (#6816) - * Remove `seen` map from `getLastCommitForPaths` (#6807) - * Show scrollbar only when needed (#6802) - * Restore IsWindows variable assignment (#6722) (#6790) - * Service worker js is a missing comma (#6788) - * Fix team edit API panic (#6780) - * Set user search base field optional in LDAP (simple auth) edit page (#6779) - * Ignore already existing public keys after ldap sync (#6766) - * Fix pulls broken when fork repository deleted (#6754) - * Fix missing return (#6751) - * Fix new team 500 (#6749) - * OAuth2 token can be used in basic auth (#6747) - * Fix org visibility bug when git cloning (#6743) - * Fix bug when sort repos on org home page login with non-admin (#6741) - * Stricter domain name pattern in email regex (#6739) - * Fix admin template error (#6737) - * Drop is_bare IDX only when it exists for MySQL and MariaDB (#6736) - * UI: Detect and restore encoding and BOM in content (#6727) - * Load issue attributes when editing an issue with API (#6723) - * Fix team members API (#6714) - * Unfortunately MemProvider Init does not actually Init properly (#6692) - * Fix partial reversion of #6657 caused by #6314 (#6685) - * Prevent creating empty sessions (#6677) - * Fixes #6659 - Swagger schemes selection default to page's protocol (#6660) - * Update highlight.js to 9.15.6 (#6658) - * Properly escape on the redirect from the web editor (#6657) - * Fix #6655 - Don't EscapePound .Link as it is already escaped (#6656) - * Use ctx.metas for SHA hash links (#6645) - * Fix wrong GPG expire date (#6643) - * upgrade version of lib/pq to v1.1.0 (#6640) - * Fix forking an empty repository (#6637) - * Fix issuer of OTP URI should be URI-encoded. (#6634) - * Return a UserList from /api/v1/admin/users (#6629) - * Add json tags for oauth2 form (#6627) - * Remove extra slash from twitter card (#6619) - * remove bash requirement in makefile (#6617) - * Fix Open Graph og:image link (#6612) - * Fix cross-compile builds (#6609) - * Change commit summary to full message in API (#6591) - * Fix bug user search API pagesize didn't obey ExplorePagingNum (#6579) - * Prevent server 500 on compare branches with no common history (#6555) - * Properly escape release attachment URL (#6512) - * Delete local branch when repo branch is deleted (#6497) - * Fix bug when user login and want to resend register confirmation email (#6482) - * Fix upload attachments (#6481) - * Avoid multi-clicks in oauth2 login (#6467) - * Hacky fix for alignment of the create-organization dialog (#6455) - * Change order that PostProcess Processors are run (#6445) - * Clean up ref name rules (#6437) - * Fix Hook & HookList in Swagger (#6432) - * Fixed unitTypeCode not being used in accessLevelUnit (#6419) - * Display correct error for invalid mirror interval (#6414) - * Don't Unescape redirect_to cookie value (#6399) - * Fix dump table name error and add some test for dump database (#6394) - * Fix migrations 82 to ignore unsynced tags between database and git data and missing is_archived on repository table (#6387) - * Make sure units of a team are returned (#6379) - * Fix bug manifest.json will not request with cookie so that session will created every request (#6372) - * Disable benchmarking during tag events on DroneIO (#6365) - * Comments list performance optimization (#5305) -* ENHANCEMENTS - * Update Drone docker generation to standard format (#7480) (#7496) (#7504) - * Add API Endpoint for Repo Edit (#7006) - * Add state param to milestone listing API (#7131) - * Make captcha and password optional for external accounts (#6606) - * Detect migrating batch size (#7353) - * Fix 7255 - wrap long texts on user profile info (#7333) - * Use commit graph files for listing pages (#7314) - * Add git command line commitgraph support global default true when git version >= 2.18 (#7313) - * Add LFS_START_SERVER option to control git-lfs support (#7281) - * Dark theme markdown fixes (#7260) - * Update go-git to v4.12.0 (#7249) - * Show lfs config on admin panel (#7220) - * Disable same user check for internal SSH (#7215) - * Add LastLogin to the User API (#7196) - * Add missing description of label on API (#7159) - * Use go method to calculate ssh key fingerprint (#7128) - * Enable Rust highlighting (#7125) - * Refactor submodule URL parsing (#7100) - * Change issue mail title. (#7064) - * Use batch insert on migrating repository to make the process faster (#7050) - * Improve github downloader on migrations (#7049) - * When git version >= 2.18, git command could run with git wire protocol version 2 param if enabled (#7047) - * Fix Erlang and Elixir highlight mappings (#7044) - * API Org Visibility (#7028) - * Improve handling of non-square avatars (#7025) - * Bugfix: Align comment label and actions to the right (#7024) - * Change UpdateRepoIndex api to include watchers (#7012) - * Move serv hook functionality & drop GitLogger (#6993) - * Add support of utf8mb4 for mysql (#6992) - * Make webhook http connections reusable (#6976) - * Move xorm logger bridge from log to models so that log module could be a standalone package (#6944) - * Refactor models.NewRepoContext to extract git related codes to modules/git (#6941) - * Remove macaron dependent on models (#6940) - * Add less linter via npx (#6936) - * Remove macaron dependent on modules/log (#6933) - * Remove macaron dependent on models/mail.go (#6931) - * Clean less files (#6921) - * Fix code overflow (#6914) - * Style orgs list in user profile (#6911) - * Improve description of branch protection (fix #6886) (#6906) - * Move sdk structs to modules/structs (#6905) - * update sdk to latest (#6903) - * Escape the commit message on issues update and title in telegram hook (#6901) - * SearchRepositoryByName improvements and unification (#6897) - * Change the color of issues/pulls list, merged is purple and closed is red (#6874) - * Refactor table width to have more info shown in file list (#6867) - * Monitor all git commands; move blame to git package and replace git as a variable (#6864) - * Fix config ui error about cache ttl (#6861) - * Improve localization of git activity stats (#6848) - * Generate access token in admin cli (#6847) - * Update github.com/urfave/cli to version 1.2.0 (#6838) - * Rename LFS_JWT_SECRET cli option to include OAUTH2 as well (#6826) - * internal/ssh: ignore env command totally (#6825) - * Allow Recaptcha service url to be configured (#6820) - * update github.com/mcuadros/go-version to v0.0.0-20190308113854-92cdf37c5b75 (#6815) - * Use modules/git for git commands (#6775) - * Add GET requests to webhook (#6771) - * Move PushUpdate dependency from models to repofiles (#6763) - * Tweak tab text and icon colors (#6760) - * Ignore non-standard refs in git push (#6758) - * Disable web preview for telegram webhook (#6719) - * Show full name if DEFAULT_SHOW_FULL_NAME setting enabled (#6710) - * Reorder file actions (#6706) - * README WordPress the code is overflowing #6679 (#6696) - * Improve issue reference on commit (#6694) - * Handle redirects for git clone commands (#6688) - * Fix one performance/correctness regression in #6478 found on Rails repository. (#6686) - * API OTP Context (#6674) - * Remove local clones & make hooks run on merge/edit/upload (#6672) - * Bump github.com/stretchr/testify from 1.2.2 to 1.3.0 (#6663) - * Bump gopkg.in/src-d/go-git.v4 from 4.8.0 to 4.10.0 (#6662) - * Fix dropdown icon padding (#6651) - * Add more title attributes on shortened names (#6647) - * Update UI for topics labels on projects (#6639) - * Trace Logging on Permission Denied & ColorFormat (#6618) - * Add .gpg url (match github behaviour) (#6610) - * Support for custom GITEA_CUSTOM env var in docker(#6608) - * Show "delete branch" button on closed pull requests (#6570) (#6601) - * Add option to disable refresh token invalidation (#6584) - * Fix new repo dropdown alignment (#6583) - * Fix mail notification when close/reopen issue (#6581) - * Pre-calculate the absolute path of git (#6575) - * Minor CSS cleanup for the navbar (#6553) - * Render SHA1 links as code blocks (#6546) - * Add username flag in create-user command (#6534) - * Unifies pagination template usage (#6531) (#6533) - * Fixes pagination width on mobile view (#5711) (#6532) - * Improve SHA1 link detection (#6526) - * Fixes #6446 - Sort team members and team's repositories (#6525) - * Use stricter boundaries for auto-link detection (#6522) - * Use regular line-height on frontpage entries (#6518) - * Fixes #6514 - New Pull Request on files and pulls pages the same (#6515) - * Make distinction between DisplayName and Username in email templates (#6495) - * Add X-Auto-Response-Suppress header to outgoing messages (#6492) - * Cleaned permission checks for API -> site admin can now do anything (#6483) - * Support search operators for commits search (#6479) - * Improve listing performance by using go-git (#6478) - * Fix repo sub_menu font color in arc-green (#6477) - * Show last commit status in pull request lists (#6465) - * Add signatures to webhooks (#6428) - * Optimize all images in public/img (#6427) - * Add golangci (#6418) - * Make "Ghost" not link to 404 page (#6410) - * Include more variables on admin/config page (#6378) - * Markdown: enable some more extensions (#6362) - * Include repo name in page title tag (#6343) - * Show locale string on timestamp (#6324) - * Handle CORS requests (#6289) - * Improve issue autolinks (#6273) - * Migration Tweaks (#6260) - * Add title attributes to all items in the repo list viewer (#6258) - * Issue indexer queue redis support (#6218) - * Add bio field for user (#6113) - * Make the version within makefile overwriteable (#6080) - * Updates to API 404 responses (#6077) - * Use Go1.11 module (#5743) - * UX + Security current user password reset (#5042) - * Refactor: append, build variable and type switch (#4940) - * Git statistics in Activity tab (#4724) - * Drop the bits argument when generating an ed25519 key (#6504) -* TESTING - * Exclude pull_request from fetch-tags step, fixes #7108 (#7120) - * Refactor and improve git test (#7086) - * Fix TestSearchRepo by waiting till indexing is done (#7004) - * Add mssql migration tests (needs #6823) (#6852) - * Add tests for Org API (#6731) - * Context.ServerError and NotFound should log from their caller (#6550) -* TRANSLATION - * Add french specific rule for translating plural texts (#6846) -* BUILD - * Update mssql driver to last working version 20180314172330-6a30f4e59a44 (#7306) - * Alpine 3.10 (#7256) - * Use vfsgen instead of go-bindata (#7080) - * remove and disable package-lock (#6969) - * add make targets for js and css, add js linter (#6952) - * Added tags pull step to drone config to show correct version hashes i… (#6836) - * Make CustomPath, CustomConf and AppWorkPath configurable at build (#6631) - * chore: update drone format to 1.0 (#6602) - * Fix race in integration testlogger (#6556) - * Quieter Integration Tests (#6513) - * Drop the docker Makefile from the image (#6507) - * Add make version on gitea version (#6485) - * Fix #6468 - Uses space match and adds newline for all sed flavors (#6473) - * Move code.gitea.io/git to code.gitea.io/gitea/modules/git (#6364) - * Update npm dependencies and various tweaks (#7344) - * Fix updated drone file (#7336) - * Add 'npm' and 'npm-update' make targets and lockfile (#7246) -* DOCS - * Add work path CLI option (#6922) - * Fix logging documentation (#6904) - * Some logging documentation (#6498) - * Fix link to Hacking on Gitea on From-Source doc page (#6471) - * Fix typos in docs command-line examples (#6466) - * Added docker example for backup (#5846) - -## [1.8.3](https://github.com/go-gitea/gitea/releases/tag/v1.8.3) - 2019-06-17 - -* BUGFIXES - * Always set userID on LFS authentication (#7224) (Part of #6993) - * Fix LFS Locks over SSH (#6999) (#7223) - * Fix duplicated file on pull request conflicted files (#7211) (#7214) - * Detect noreply email address as user (#7133) (#7195) - * Don't get milestone from DB if ID is zero (#7169) (#7174) - * Allow archived repos to be (un)starred and (un)watched (#7163) (#7168) - * Fix GCArgs load from ini (#7156) (#7157) - -## [1.8.2](https://github.com/go-gitea/gitea/releases/tag/v1.8.2) - 2019-05-29 - -* BUGFIXES - * Fix possbile mysql invalid connnection error (#7051) (#7071) - * Handle invalid administrator username on install page (#7060) (#7063) - * Disable arm7 builds (#7037) (#7042) - * Fix default for allowing new organization creation for new users (#7017) (#7034) - * SearchRepositoryByName improvements and unification (#6897) (#7002) - * Fix u2f registrationlist ToRegistrations() method (#6980) (#6982) - * Allow collaborators to view repo owned by private org (#6965) (#6968) - * Use AppURL for Oauth user link (#6894) (#6925) - * Escape the commit message on issues update (#6901) (#6902) - * Fix regression for API users search (#6882) (#6885) - * Handle early git version's lack of get-url (#7065) (#7076) - * Fix wrong init dependency on markup extensions (#7038) (#7074) - -## [1.8.1](https://github.com/go-gitea/gitea/releases/tag/v1.8.1) - 2019-05-08 - -* BUGFIXES - * Fix 404 when sending pull requests in some situations (#6871) (#6873) - * Enforce osusergo build tag for releases (#6862) (#6869) - * Don't post process commit summary in templates (#6842) (#6868) - * Fix 500 when reviewer is deleted (#6856) (#6860) - * Fix v78 migration for MSSQL (#6823) (#6854) - * Added tags pull step to drone config to show correct version hashes (#6836) (#6839) - * Fix double-generation of scratch token (#6833) (#6835) - * When mirroring we should set the remote to mirror (#6824) (#6834) - * Show scrollbar only when needed (#6802) (#6803) - * Service worker js is missing a comma (#6788) (#6795) - * Set user search base field optional in LDAP (simple auth) edit page (#6779) (#6789) - * Fix team edit API panic (#6780) (#6785) - * Minor CSS cleanup for the navbar (#6553) (#6781) - * Stricter domain name pattern in email regex (#6739) (#6768) - * Detect and restore encoding and BOM in content (#6727) (#6765) - * Fix org visibility bug when git cloning (#6743) (#6762) - * OAuth2 token can be used in basic auth (#6747) (#6761) - * Fix missing return (#6751) (#6756) - * Fix sorting repos on org home page with non-admin login (#6741) (#6746) - * Drop is_bare IDX only when it exists for MySQL and MariaDB (#6736) (#6744) - * Fix team members API (#6714) (#6729) - * Load issue attributes when editing an issue with API (#6723) (#6725) - * Fix config ui error about cache ttl (#6861) (#6865) - -## [1.8.0](https://github.com/go-gitea/gitea/releases/tag/v1.8.0) - 2019-04-20 - -* SECURITY - * Prevent remote code execution vulnerability with mirror repo URL settings (#6593) (#6594) - * Resolve 2FA bypass on API (#6676) (#6674) - * Prevent the creation of empty sessions for non-logged in users (#6690) (#6677) -* BREAKING - * Add "ghost" and "notifications" to list of reserved user names. (#6208) - * Change sqlite DB path default to data directory (#6198) - * Adds MustChangePassword to user create/edit API (#6193) - * Disable redirect for i18n (#5910) - * Releases API paging (#5831) - * Allow Macaron to be set to log through to gitea.log (#5667) - * Don't close issues via commits on non-default branch (#5622) -* FEATURES - * Add regenerate secret feature for oauth2 (#6291) - * Expose issue stopwatch toggling via API (#5970) - * Add other session providers (#5963) - * Pull request conflict files detection (#5951) - * Integrate OAuth2 Provider (#5378) - * Implement "conversation lock" for issue comments (#5073) - * Feature: Archive repos (#5009) - * Discord Oauth2 support (#4476) - * Allow to set organization visibility (public, internal, private) (#1763) - * Added URL mapping for Release attachments like on github.com (#1707) -* ENHANCEMENTS - * Add support for client basic auth for exchanging access tokens (#6293) - * Add ability to sort issues by due date (#6206) (#6244) - * Style tweaks to issue selection (#6196) - * Increase Username and Orgname MaxSize 35 -> 40 (#6178) - * Coverage profile with multiple packages (#6167) - * Split setting.go to multiple files (#6154) - * Allow labels to contain emoji (#6063) - * Disable git fsck for mirrored repos by default (#6018) - * Add default time out for git operations (#6015) - * Split setting.go as multiple files (#6014) - * Make dashboard navbar and footer full-width (#6013) - * Add lang specific font stacks for CJK (#6007) - * Fix header menu misalignment (#6002) - * Enhance closed PR and Issue status in the list (#6000) - * Make navbar full width (#5998) - * Add option to close issues via commit on a non master branch (#5992) - * Support n as a line highlight prefix (#5987) - * Search for org repos (#3031) (#5986) - * Minor UI tweaks (#5980) - * Use native golang SSH library but ssh-keygen when enable built-in SSH server to remove dependent on that command lines (#5976) - * Dashboard tweaks (#5974) - * Fixes for repo topic editor (#5971) - * Display the branch name in the commit view (#5950) - * handle milestone events for issues and PR (#5947) - * Add label names as filter in issue search api (#5946) - * Repo header tweaks (#5945) - * Better support for long repo names (#5932) - * Fix wrapping long code lines (#5927) - * Change GPG Validation colors and remove inline CSS (#5404) (#5896) - * Fix "pulls.blocked_by_approvals" text (#5879) - * Rename reject to 'request changes' (#5858) - * Move input fields to add members to a team and repos to a team (#5853) - * Config option to disable automatic repo watching (#5852) - * New Issue ?body= query (#5851) - * Add API to list tags (#5850) - * Pagination for git tree API (#5838) - * Add InternalTokenURI to load InternalToken from an external file (#5812) - * Allow markdown files to read from the LFS (#5787) - * Add the ability to use multiple labels as filters (#5786) - * Adjust log settings when a user is not found. (#5771) - * Log IP of failed ssh connection (#5766) - * Moved defaults in defaults.go to setting.go (#5764) - * Make DB connect more robust (#5738) - * Add Default Pull Request Title (#5735) - * Refactor repo.isBare to repo.isEmpty #5629 (#5714) - * Add flag to skip repository dumping (#5695) - * Prioritize "readme.md" (#5691) - * Improve "Fork button" for guests by showing a pop up asking them to log in before forking (#5690) - * Allow for user specific themes (#5668) - * Display branch name in delete branch confirmation modal. (#5654) - * New API routes added (#5594) - * Refactor notification for indexer (#5111) - * Refactor mail notification (#5110) - * Show email if the authenticated user owns the profile page being requested for (#4981) - * Optimize pulls merging (#4921) - * Sort Repositories widget by most recently updated (#3963) (#4599) - * Allow markdown table to scroll (#4401) - * Automatically clear stopwatch on merging a PR (#4327) - * Add the Owner Name to differentiate when merging (#3807) - * Add title attributes to all items in the repo list viewer (#6258) (#6650) -* BUGFIXES - * Fix dropdown icon padding (#6651) (#6654) - * Fix wrong GPG expire date (#6643) (#6644) - * Fix forking an empty repository (#6637) (#6653) - * Remove call to EscapePound .Link as it is already escaped (#6656) (#6666) - * Properly escape on the redirect from the web editor (#6657) (#6667) - * Allow resend of confirmation email when logged in (#6482) (#6486) - * Fix mail notification when close/reopen issue (#6581) (#6588) - * Change API commit summary to full message (#6591) (#6592) - * Add option to disable refresh token invalidation (#6584) (#6587) - * Fix bug user search API pagesize didn't obey ExplorePagingNum (#6579) (#6586) - * Fix new repo alignment (#6583) (#6585) - * Prevent server 500 on compare branches with no common history (#6555) (#6558) - * Properly escape release attachment URL (#6512) (#6523) - * Hacky fix for alignment of the create-organization dialog (#6455) (#6462) - * Disable benchmarking during tag events on DroneIO (#6365) (#6366) - * Make sure units of a team are returned (#6379) (#6381) - * Don't Unescape redirect_to cookie value (#6399) (#6401) - * Fix dump table name error and add some test for dump database (#6394) (#6402) - * Fix migration v82 to ignore unsynced tags between database and git data; Add missing is_archived column on repository table (#6387) (#6403) - * Display correct error for invalid mirror interval (#6414) (#6429) - * Clean up ref name rules (#6437) (#6439) - * Fix Hook & HookList in Swagger (#6432) (#6440) - * Change order that PostProcess Processors are run (#6445) (#6447) - * Clean up various use of escape/unescape functions for URL generation (#6334) - * Return 409 when creating repo if it already exists. (#6330) - * Add same changes from issues page to milestone->issues page (#6328) - * Fix ParsePatch function to work with quoted diff --git strings (#6323) - * Fix reported issue in repo description (#6306) - * Use url.PathEscape to escape the branchname (#6304) - * Add robots.txt as reserved username (#6272) - * Replace linkRegex with xurls library (#6261) - * Remove visitLinksForShortLinks features (#6257) - * Add unit types to repo action URL to correctly show 404 when archived (#6247) - * Check organization visibility before everything else (#6234) (#6235) - * Prevent double-close of issues (#6233) - * Override xorm type mapping for U2F counter (#6232) - * Add isAdmin to user API response (#6231) - * Update git vendor to fix wrong release commit id and add migrations (#6224) - * Fix fork button (#6223) - * Fix renames over redirects (#6216) - * Fix display dashboard even if require to change password (#6214) - * Create a repo redirect when transferring ownership (#6210) (#6211) - * Fix issue update race condition (#6194) - * Fix bug when migrate repository 500 when repo is existed (#6188) - * Fix scrollbar always present on page body (#6177) - * Fix bug when set indexer as db and add tests (#6173) - * Modify linkRegex to require http|https (#6171) - * Fix bug user could change private repository to public when force private enabled. (#6156) - * Fix admin list user/org API (#6143) - * Make repo creation for API similar to UI (#6142) - * Make document body a flexbox (#6139) - * Refactor issue indexer, add some testing and fix a bug (#6131) - * Load Issue attributes for API call (#6122) - * Fix bug when update owner team then visit team's repo return 404 (#6119) - * Fix heatmap and repository menu display in Internet Explorer 9+ (#6117) - * Show private organization for admin, fix #6111 (#6112) - * Fix prohibit login check on authorization (#6106) - * Move to ldap.v3 to fix #5928 (#6105) - * Remove use MakeAssigneeList in webhooks to fix deadlock (#6102) - * Allow display of LFS stored Readme.md on directory page (#6073) (#6099) - * Make sure labels are actually returned (#6053) - * Fix panic: template: repo/issue/list:210: unexpected "=" in operand (#6041) - * After deleting a repo on admin panel, UI should remember the last sort type (#6033) - * Default create repository on organisation on its dashboard (#6026) - * Swagger: Remove spaces in MergePullRequestOption enum (#6016) - * Fix metrics auth token detection (#6006) - * Fix repo header issues (#5995) - * Fix bug when deleting a linked account will removed all (#5989) - * Make organization dropdown scrollable when using mouse wheel (#5988) - * Fix empty ssh key importing in ldap (#5984) - * Admin config page mailertype setting option update (#5973) - * Fix redirect loop during forced password change (#5965) - * Show user who created the repository instead of the organisation in action feed (#5948) - * Remove all CommitStatus when a repo is deleted (#5940) - * Fix ssh deploy and user key constraints (#1357) (#5939) - * Fix log output (#5938) - * Set PusherName and PusherID to owner on deploy key to fix pushing with deploy keys (#5935) - * Fix compare button (#5929) - * Fix bug when read public repo lfs file (#5912) - * Only allow local login if password is non-empty (#5906) - * Recover panic in orgmode.Render if bad orgfile (#4982) (#5903) - * Provide better panic handling (#5902) - * Respect value of REQUIRE_SIGNIN_VIEW (#5901) - * Show a 404 not a 500 if a repo does not exist (#5900) - * Ensure repo is loaded in mailer (Completely fix #5891) (#5895) - * Ensure issue.Poster is loaded in mailIssueCommentToParticipants (#5891) - * Correct footer height if screen-width is to small (fixes #5878) (#5889) - * In gitea serv switch off console logger to fix #5866 (#5887) - * Don't allow pull requests to be created on an archived repository (#5883) - * Support reviews on a deleted file path (#5880) - * Fix compare button on upstream repo leading to 404 (#5877) - * Fix null pointer on not logged in attempt to Sudo (#5872) - * Fix new release creation API to allow empty target (#5870) - * Fix an error while adding a dependency via UI. (#5862) - * Fix failing migration v67 (#5849) - * Fix delete correct temp directory (#5839) - * Make sure .git/info is created before generating .git/info/sparse-che… (#5825) - * Fix topics saving internal error and disable for archived repos (#5821) - * Fix TLS errors when using acme/autocert for local connections (#5820) - * When creating new repository fsck option should be enabled (#5817) - * Request for public keys only if LDAP attribute is set (#5816) - * Fix serving of raw wiki files other than .md (#5814) - * Fix migration 78 error mssql (#5791) - * Disallow empty titles (#5785) - * Fix the v78 migration script (#5776) - * Ensure valid git author names passed in signatures (#5774) - * Fix wrong assumption where a user is always said to have unassigned (her)himself (#5769) - * Upgrade go-sql-driver/mysql to fix invalid connection error (#5748) - * Fixing PostgreSQL dump creation (#5747) - * Add proper CORS preflight origin validation (#5740) - * Disable auto-migrate in docker container (#5730) - * In basic auth check for tokens before call UserSignIn (#5725) - * Pooled and buffered gzip implementation (#5722) - * Ensure that sessions are passed into queries that could use the database to prevent deadlocks (#5718) - * Keep file permissions during database migration (#5707) - * Use correct value for "MSpan Structures Obtained" #4742 (#5706) - * Refactor editor upload, update and delete to use git plumbing and add LFS support (#5702) - * Update xorm to fix issue #5659 and #5651 (#5680) - * Fix public will not be reused as public key after deleting as deploy key (#5671) - * When redirecting, clean the path (#5669) - * Don't list an issue on its own dependency list UI. (#5658) - * Fix commit page showing status for current default branch (#5649) (#5650) - * Only count users own actions for heatmap contributions (#5647) - * Fix sqlite deadlock when assigning to a PR (#5640) - * Refactor issue indexer (#5363) -* TESTING - * Run benchmark at tag to track performances (#6035) - * Add test environment for MySQL8 (#5234) -* BUILD - * Use go 1.12 for tests and deprecate go 1.9 (#6186) - * Makefile changes for Windows and easier development (#6103) - * Update bleve dependency to latest master revision (#6100) - * Switch to more recent build of xgo (#6070) - * Add autoprefixer to css build (#6029) - * Update the version of less (#6010) - * Make log mailer for testing (#5893) -* DOCS - * Add more tests and docs for issue indexer, add db indexer type for searching from database (#6144) - * update default value of `--must-change-password` cli flag (#6032) - * Update and expand information about building Gitea (#6019) - * Update U2F Section of app.ini.sample (#5994) - * Update swagger for release API pagination (#5841) - * Added docs for the tree api (#5834) -* MISC - * Add single commit API support (#5843) - * Add missing GET teams endpoints (#5382) - * Migrate database if app.ini found (#5290) - -## [1.7.6](https://github.com/go-gitea/gitea/releases/tag/v1.7.6) - 2019-04-12 - -* SECURITY - * Prevent remote code execution vulnerability with mirror repo URL settings (#6593) (#6595) -* BUGFIXES - * Allow resend of confirmation email when logged in (#6482) (#6487) - -## [1.7.5](https://github.com/go-gitea/gitea/releases/tag/v1.7.5) - 2019-03-27 - -* BUGFIXES - * Fix unitTypeCode not being used in accessLevelUnit (#6419) (#6423) - * Fix bug where manifest.json was being requested without cookies and continuously creating new sessions (#6372) (#6383) - * Fix ParsePatch function to work with quoted diff --git strings (#6323) (#6332) - -## [1.7.4](https://github.com/go-gitea/gitea/releases/tag/v1.7.4) - 2019-03-12 - -* SECURITY - * Fix potential XSS vulnerability in repository description. (#6306) (#6308) -* BUGFIXES - * Fix wrong release commit id (#6224) (#6300) - * Fix panic on empty signed commits (#6292) (#6300) - * Fix organization dropdown not being scrollable when using mouse wheel (#5988) (#6246) - * Fix displaying dashboard even if required to change password (#6214) (#6215) - -## [1.7.3](https://github.com/go-gitea/gitea/releases/tag/v1.7.3) - 2019-02-27 - -* BUGFIXES - * Fix server 500 when trying to migrate to an already existing repository (#6188) (#6197) - * Load Issue attributes for API /repos/{owner}/{repo}/issues/{index} (#6122) (#6185) - * Fix bug whereby user could change private repository to public when force private enabled. (#6156) (#6165) - * Fix bug when update owner team then visit team's repo return 404 (#6119) (#6166) - * Fix heatmap and repository menu display in Internet Explorer 9+ (#6117) (#6137) - * Fix prohibit login check on authorization (#6106) (#6115) - * Fix LDAP protocol error regression by moving to ldap.v3 (#6105) (#6107) - * Fix deadlock in webhook PullRequest (#6102) (#6104) - * Fix redirect loop when password change is required and Gitea is installed as a suburl (#5965) (#6101) - * Fix compare button regression (#5929) (#6098) - * Recover panic in orgmode.Render if bad orgfile (#4982) (#5903) (#6097) - -## [1.7.2](https://github.com/go-gitea/gitea/releases/tag/v1.7.2) - 2019-02-14 - -* BUGFIXES - * Remove all CommitStatus when a repo is deleted (#5940) (#5941) - * Fix notifications on pushing with deploy keys by setting hook environment variables (#5935) (#5944) - * Silence console logger in gitea serv (#5887) (#5943) - * Handle milestone webhook events for issues and PR (#5947) (#5955) - * Show user who created the repository instead of the organization in action feed (#5948) (#5956) - * Fix ssh deploy and user key constraints (#1357) (#5939) (#5966) - * Fix bug when deleting a linked account will removed all (#5989) (#5990) - * Fix empty ssh key importing in ldap (#5984) (#6009) - * Fix metrics auth token detection (#6006) (#6017) - * Create repository on organisation by default on its dashboard (#6026) (#6048) - * Make sure labels are actually returned in API (#6053) (#6059) - * Switch to more recent build of xgo (#6070) (#6072) - * In basic auth check for tokens before call UserSignIn (#5725) (#6083) - -## [1.7.1](https://github.com/go-gitea/gitea/releases/tag/v1.7.1) - 2019-01-31 - -* SECURITY - * Disable redirect for i18n (#5910) (#5916) - * Only allow local login if password is non-empty (#5906) (#5908) - * Fix go-get URL generation (#5905) (#5907) -* BUGFIXES - * Fix TLS errors when using acme/autocert for local connections (#5820) (#5826) - * Request for public keys only if LDAP attribute is set (#5816) (#5819) - * Fix delete correct temp directory (#5840) (#5839) - * Fix an error while adding a dependency via UI (#5862) (#5876) - * Fix null pointer in attempt to Sudo if not logged in (#5872) (#5884) - * When creating new repository fsck option should be enabled (#5817) (#5885) - * Prevent nil dereference in mailIssueCommentToParticipants (#5891) (#5895) (#5894) - * Fix bug when read public repo lfs file (#5913) (#5912) - * Respect value of REQUIRE_SIGNIN_VIEW (#5901) (#5915) - * Fix compare button on upstream repo leading to 404 (#5877) (#5914) -* DOCS - * Added docs for the tree api (#5835) -* MISC - * Include Go toolchain to --version (#5832) (#5830) - -## [1.7.0](https://github.com/go-gitea/gitea/releases/tag/v1.7.0) - 2019-01-22 - -* SECURITY - * Do not display the raw OpenID error in the UI (#5705) (#5712) - * When redirecting clean the path to avoid redirecting to external site (#5669) (#5679) - * Prevent DeleteFilePost doing arbitrary deletion (#5631) -* BREAKING - * Restrict permission check on repositories and fix some problems (#5314) - * Show only opened milestones on issues page milestone filter (#5051) -* FEATURES - * Implement git refs API for listing references (branches, tags and other) (#5354) - * Approvals at Branch Protection (#5350) - * Add raw blob endpoint to get objects by SHA ID (#5334) - * Add api for user to create org (#5268) - * Create AuthorizedKeysCommand (#5236) - * User action heatmap (#5131) - * Refactor heatmap to vue component (#5401) - * Webhook for Pull Request approval/rejection (#5027) - * Add command for migrating database (#4954) - * Search keyword by splitting provided values by , (#4939) - * Create Progressive Web App (#4730) - * Give user a link to create PR after push (#4716) - * Add rebase with merge commit merge style (#3844) (#4052) -* BUGFIXES - * Disallow empty titles (#5785) (#5794) - * Fix sqlite deadlock when assigning to a PR (#5640) (#5642) - * Don't close issues via commits on non-default branch. (#5622) (#5643) - * Fix commit page showing status for current default branch (#5650) (#5653) - * Only count users own actions for heatmap contributions (#5647) (#5655) - * Update xorm to fix issue postgresql dumping issues (#5680) (#5692) - * Use correct value for "MSpan Structures Obtained" (#5706) (#5716) - * Fix bug on modifying sshd username (#5624) - * Delete tags in mirror which are removed for original repo. (#5609) - * Fix wrong text getting saved on editing second comment on an issue. (#5608) - * Fix nil pointer when adding a due date (#5587) - * Fix type mismatch of format string (#5574) - * Fix bug on upload file name (#5571) - * Issue is not overdue when it is on the same date #5566 (#5568) - * Fix indexer reindex bug when gitea restart (#5563) - * Fix table name typo on SQL (#5562) - * Synchronize SSH keys on login with LDAP + Fix SQLite deadlock on ldap ssh key deletion (#5557) - * Fix makefile generate buildstep (#5556) - * Fix nil pointer base branch bug (#5555) - * Fix permission check on api create org (#5523) - * Fix detect force push failure on deletion of protected branches (#5522) - * Fix approvals limitation (#5521) - * Fix bug when a read perm user to edit his issue (#5516) - * Fix adding reaction fail for read permission user (#5515) - * Fixing MSSQL timestamp type (#5511) - * Fix forgot deletion of notification when delete repository (#5506) - * Fix empty wiki (#5504) - * Fix clone wiki failed via ssh (#5503) - * Fix code review on mssql (#5502) - * Fix lfs version check warning log when using ssh protocol (#5501) - * Fix topic name length on database (#5493) - * Ensure that the `closed_at` is set for closed issues (#5449) - * Admin should be able to delete repos via the API even if he is not a member of the organization (#5443) - * Word-Break the WebHook url to prevent a ui-break (#5432) - * Fix forgot removed records when deleting user (#5429) - * Fix repository deletion when there is large number of issues in it (#5426) - * Fix heatmap colors for Chrome/Safari (#5421) - * Fix password variable shadowing (#5405) - * Fix dependent issue searching when gitea is run in subpath (#5392) - * Don't force a password change for the admin user when creating an account via cli (#5391) - * API: '/orgs/:org/repos': return private repos with read access (#5383) - * Don't send assign webhooks when creating issue (#5365) - * Removing Labels via EditPullRequest API (#5348) - * Migration fixes for gogs (0.11.66) to gitea (1.6.0) #5318 (#5341) - * Fix bug when users have serval teams with different units on different repositories (#5307) - * Fix U2F if gitea is configured in subpath (#5302) - * Fix file edit change preview functionality (#5300) - * Update gitignore list (#5258) - * Fixed heatmap not working in mssql (#5248) - * Fixed wrong api request url for instances running in subfolders (#5247) - * Fix compatibility heatmap with mysql 8 (#5232) - * Fix data race on migrate repository (#5224) - * Fix sqlite and mssql lock (#5214) - * Fix sqlite lock (#5210) - * Fix: Accept web-command cli flags if web-command is committed (#5200) - * Fix: Add secret to all webhook's payload where it has been missing (#5199) - * Fix race on updatesize (#5190) - * Fix create team, update team missing units (#5188) - * Fix sqlite lock (#5184 & #5176) - * Fix showing pull request link when delete a branch (#5166) - * Fix JSON result of empty array in heatmap data array (#5154) - * Update build tags for sqlite_unlock notify (#5144) - * This commit will reduce join star, repo_topic, topic tables on repo search, so that fix extra columns problem on mssql (#5136) - * Fix deadlock when sqlite (#5118) - * Add comment replies (#5104) - * Fix home page template regression (#5102) - * Fix regex to support optional end line of old section in diff hunk (#5096) - * LDAP via simple auth separate bind user and search base (#5055) - * Fix markdown image with link (#4675) - * Fix to 3819 - Filtering issues by tags on main screen issues (#3824) -* ENHANCEMENTS - * Delete organization endpoint added (#5601) - * Update Licenses (#5558) - * Support reverse proxy providing email (#5554) - * Add git protocol v2 support via SSH on Docker image (#5520) - * Add tests for api user orgs (#5494) - * Allow link verification for services like Mastodon (#5481) - * Improve team members and repositories settings UI (#5457) - * Remove the required class from optional ssh port in installation page (#5428) - * Explicitly disable Git credential helper (#5367) - * Setting Labels via EditPullRequest API (#5347) - * Implement pasting image from clipboard for browsers that supports that (#5317) - * Milestone issues and pull requests (#5293) - * Support envs on external render commands (#5278) - * Add option to disable automatic mirror syncing. (#5242) - * Remove unused db init on commands serv, update, hooks (#5225) - * Serve audio files using HTML5 audio tag (#5221) - * Pass link prefixes to external markup parsers (#5201) - * Add AutoHead functionality. (#5186) - * Fix emojis not showing in commit messages (#5168) - * Block registration based on email domain (#5157) - * Update vendor/go-sqlite3 (#5133 & #5162) - * Update x/net lib (#5169) - * Show review summary in pull requests (#5132) - * Use type switch (#5122) - * Remove duplicated if bodies (#5121) - * Remove check for negative length (#5120) - * Make switch more clear (#5119) - * Use named const instead of a raw string (#5115) - * Fix issue where ecdsa and other key types are not synced from LDAP (#5092) (#5094) - * Refactor: err != nil check, just return error instead (#5093) - * Add notification interface and refactor UI notifications (#5085) - * Use APP_NAME on home page (#5048) - * Explicitly decide whether to use TLS in mailer's configuration (#5024) - * Generate random password (#5023) - * UX of link account (Step 1) (#5006) - * Make sure argsSet verifies string isn't empty too (#4980) - * Improve performance of dashboard (#4977) - * Keys API changes (#4960) - * Add must-change-password flag to cli for creating a user (#4955) - * Use native go method to get current user rather than environment variable (#4930) - * Make gitea serv use api/internal (#4886) - * Add support for search by uid (#4876) - * Allow to add organization members as collaborators on organization owned repositories (#4748) -* TESTING - * Kill testing processes if the test takes too long (#5174) - * Update outdated Go toolchain version for .drone.yml (#5146) - * Increase the retry limit to 20 times and the interval to 200ms (#5134) - * Retry test-fixtures loading in case of transaction rollback (#5125) - * Added test environment for mssql (#4282) -* BUILD - * Replace lint to revive (#5422) - * Update golang version in Dockerfile (#5246) -* DOCS - * Typo in routers/api/v1/org/org.go fixed. (#5598) - * Update the docs for sqlite_unlock_notify (#5145) - * CN translation of docs part (#5049) - * Kubernetes deployment file (#5046) -* MISC - * Upgrade alpine to 3.8 (#5423) - * Git-Trees API (#5403) - * Only chown directories during docker setup if necessary. Fix #4425 (#5064) - -## [1.6.4](https://github.com/go-gitea/gitea/releases/tag/v1.6.4) - 2019-01-15 - -* BUGFIX - * Fix SSH key now can be reused as public key after deleting as deploy key (#5671) (#5685) - * When redirecting clean the path to avoid redirecting to external site (#5669) (#5703) - * Fix to use correct value for "MSpan Structures Obtained" (#5706) (#5715) - -## [1.6.3](https://github.com/go-gitea/gitea/releases/tag/v1.6.3) - 2019-01-04 - -* SECURITY - * Prevent DeleteFilePost doing arbitrary deletion (#5631) -* BUGFIX - * Fix wrong text getting saved on editing second comment on an issue (#5608) - -## [1.6.2](https://github.com/go-gitea/gitea/releases/tag/v1.6.2) - 2018-12-21 - -* SECURITY - * Sanitize uploaded file names (#5571) (#5573) - * HTMLEncode user added text (#5570) (#5575) -* BUGFIXES - * Fix indexer reindex bug when gitea restart (#5563) (#5564) - * Remove a double slash in the HTTPS redirect with Let's Encrypt (#5537) (#5539) - * Fix bug when a read perm user to edit his issue (#5516) (#5534) - * Detect force push failure on deletion of protected branches (#5522) (#5531) - * Let's Encrypt handler listens on correct port for certificate validation (#5525) (#5527) - * Fix forgot deletion of notification when delete repository (#5506) (#5514) - * Fix undeleted content when deleting user (#5429) (#5509) - * Fix empty wiki (#5504) (#5508) - -## [1.6.1](https://github.com/go-gitea/gitea/releases/tag/v1.6.1) - 2018-12-08 - -* BUGFIXES - * Fix dependent issue searching when gitea is run in subpath (#5392) (#5400) - * API: '/orgs/:org/repos': return private repos with read access (#5393) - * Fix repository deletion when there is large number of issues in it (#5426) (#5434) - * Word-break the WebHook url to prevent a ui-break (#5445) - * Admin should be able to delete repos via the API even if they are not a member of the organization (#5443) (#5447) - * Ensure that the `closed_at` is set for closed (#5450) - * Fix topic name length on database (#5493) (#5495) - -## [1.6.0](https://github.com/go-gitea/gitea/releases/tag/v1.6.0) - 2018-11-22 - -* BREAKING - * Respect email privacy option in user search via API (#4512) - * Simply remove tidb and deps (#3993) - * Swagger.v1.json template (#3572) -* SECURITY - * Add CSRF checking to reqToken and add reqToken to admin API routes (#5272) (#5250) - * Improve URL validation for external wiki and external issues (#4710) - * Make cookies HttpOnly and obey COOKIE_SECURE flag (#4706) - * Don't disclose emails of all users when sending out emails (#4664) - * Check that repositories can only be migrated to own user or organizations (#4366) -* FEATURES - * Add comment replies (#5147) (#5104) - * Pull request review/approval and comment on code (#3748) - * Added dependencies for issues (#2196) (#2531) - * Add the ability to have built in themes in Gitea and provide dark theme arc-green (#4198) - * Add sudo functionality to the API (#4809) - * Add oauth providers via cli (#4591) - * Disable merging a WIP Pull request (#4529) - * Force user to change password (#4489) - * Add letsencrypt to Gitea (#4189) - * Add push webhook support for mirrored repositories (#4127) - * Add csv file render support defaultly (#4105) - * Add Recaptcha functionality to Gitea (#4044) -* ENHANCEMENTS - * Fix milestones sorted wrongly (#4987) - * Allow api to create tags for releases if they don't exist (#4890) - * Fix #4877 to follow the OpenID Connect Audiences spec (#4878) - * Enforce token on api routes [fixed critical security issue #4357] (#4840) - * Update legacy branch and tag URLs in dashboard to new format (#4812) - * Slack webhook channel name cannot be empty or just contain an hashtag (#4786) - * Add whitespace handling to PR-comparison (#4683) - * Make reverse proxy auth optional (#4643) - * MySQL TLS (#4642) - * Make sure to set PR split view when creating/previewing a pull request (#4617) - * Log user in after a successful sign up (#4615) - * Fix typo IsPullReuqestBroken -> IsPullRequestBroken (#4578) - * Allow admin toggle forcing a password change for newly created users (#4563) - * Update jQuery to v1.12.4 (#4551) - * Env var GITEA_PUSHER_EMAIL (#4516) - * Feat(repo): support search repository by topic name (#4505) - * Small improvements to dependency UI (#4503) - * Make max commits in graph configurable (#4498) - * Add valid for lfs oid (#4461) - * Add shortcut to save wiki page (#4452) - * Allow administrator to create repository for any organization (#4368) - * Fix repository last updated time update when delete a user who watched the repo (#4363) - * Switch plaintext scratch tokens to use hash instead (#4331) - * Increase default TOTP secret size to 320 bits (#4287) - * Keep preseeded database password (#4284) - * Implemented hover text showing user FullName (#4261) - * Add ability to delete a token (#4235) - * Fix typos in i18n variable names. (#4080) - * Api: repos/search: add parameters to control the sort order (#3964) - * Add missing path in the Docker app.ini template (#2181) - * Add file name and branch to page title (#4902) - * Offline use of google fonts (#4872) - * Add missing History link to directory listings v2 (#4829) - * Locale for Edit and Remove due date issue (#4802) - * Disable 'May Import Local Repository' when is disabled by setting (Is… (#4780) - * API /admin/users/{username} missing parameter (#4775) - * Display error when adding a user to a team twice (#4746) - * Remove UsePrivilegeSeparation from the Docker sshd_config, see #2876 (#4722) - * Focus title input when clicking helper link (#4696) - * Add vendor to user reserved words and format words list according alphabet (#4685) - * Add gitea/issues link to 500 page (#4654) - * Hide home button when landing page is not set to home (#4651) - * Remove link to GitHub issues in 404 template (#4639) - * Cmd/serve: pprof cpu and memory profile dumps to disk (#4560) - * Add flash message after an account has been successfully activated (#4510) - * Prevent html entity escaping on delete branch (#4471) - * Locale for button Edit on protected branch (#4442) - * Update notification icon (#4343) - * Added front-end topics validation (#4316) - * Don't display buttons if there are no system notifications (#4280) - * Issue due date api (#3890) -* BUGFIXES - * dont' send assign webhooks when creating issue (#5365) - * Fix create team, update team missing units (#5188) - * Fix file edit change preview functionality (#5300) - * *ix bug when users have serval teams with different units on different repositories (#5307) - * Fix U2F if gitea is configured in subpath (#5302) - * Fix markdown image with link (#4675) - * Remove maxlines option for file logger (#5282) - * Fix wrong api request url for instances running in subfolders (#5261) (#5247) - * Accept web-command cli flags if web-command is committed (#5245) (#5200) - * Reduce join star, repo_topic, topic tables on repo search, to resolve extra columns problem on MSSQL (#5136) (#5229) - * Fix data race on migrate repository (#5224) (#5230) - * Add secret to all webhook's payload where it has been missing (#5208) (#5199) - * Fix sqlite and MSSQL lock (#5210) (#5223) (#5214) (#5218) (#5176) (#5179) - * Fix race on updatesize (#5190) (#5215) - * Fix filtering issues by tags on main screen issues (#5219) (#3824) - * Fix SQL quoting (#5137) (#5117) - * Fix regex to support optional end line of old section in diff hunk (#5097) (#5096) - * Fix release creation via API (#5076) - * Remove links from topics in edit mode (#5026) - * Fix missing AppSubUrl in few more templates (fixup) (#5021) - * Fix missing AppSubUrl in some templates (#5020) - * Hide outdated comments in file view (#5017) - * Upgrade gopkg.in/testfixtures.v2 (#4999) - * Disable debug routes unless PPROF is enabled in configuration (#4995) - * Fix user menu item styling (#4985) - * Fix layout of the topics editing form (#4971) - * Fix null pointer dereference in ParseCommitWithSignature (#4962) - * Fix url in discord webhook (#4953) - * Detect charset and convert non UTF-8 files for display (#4950) - * Make sure to catch the right error so it is displayed on the UI (#4945) - * Fix(topics): don't redirect to explore page. (#4938) - * Fix bug forget to remove Stopwatch when remove repository (#4928) - * Fix bug when repo remained bare if multiple branches pushed in single push (#4923) - * Fix: Crippled diff (#4726) (#4900) - * Fix trimming of markup section names (#4863) - * Issues api allow pulls and fix #4832 (#4852) - * Do not autocreate directory for new users/orgs (#4828) (#4849) - * Fix redirect with non-ascii branch names (#4764) (#4810) - * Fix missing release title in webhook (#4783) (#4796) - * User shouldn't be able to approve or reject his/her own PR (#4729) - * Make sure to reset commit count in the cache on mirror syncing (#4720) - * Fixed bug where team with admin privilege type doesn't get any unit (#4719) - * Fix incorrect caption of webhook setting (#4701) (#4717) - * Allow WIP marker to contains < or > (#4709) - * Hide org/create menu item in Dashboard if user has no rights (#4678) (#4680) - * Site admin could create repos even MAX_CREATION_LIMIT=0 (#4645) - * Fix custom templates being ignored (#4638) - * Fix starring icon after semantic ui update (#4628) - * Fix Split-View line adjustment (#4622) - * Fix integer constant overflows in tests (#4616) - * Push whitelist now doesn't apply to branch deletion (#4601) (#4607) - * Fix bugs when too many IN variables (#4594) - * Fix failure on creating pull request with assignees (#4419) (#4583) - * Fix panic issue on update avatar email (#4580) (#4581) - * Fix status code label for a successful webhook (#4540) - * An inactive user shouldn't be able to be added as a collaborator (#4535) - * Don't fail silently if trying to add a collaborator twice (#4533) - * Fix incorrect MergeWhitelistTeamIDs check in CanUserMerge function (#4519) (#4525) - * Fix out-of-transaction query in removeOrgUser (#4521) (#4522) - * Fix migration from older releases (#4495) - * Accept 'Data:' in commit graph (#4487) - * Update xorm to latest version and fix correct `user` table referencing in sql (#4473) - * Relative URLs for LibreJS page (#4460) - * Redirect to correct page after using scratch token (#4458) - * Fix column droping for MSSQL that need new transaction for that (#4440) - * Replace src with raw to fix image paths (#4377) - * Add default merge options when creating new repository (#4369) - * Fix docker build (#4358) - * Fixes repo membership check in API (#4341) - * Dep upgrade mysql lib (#4161) - * Fix some issues with special chars in branch names (#3767) - * Responsive design fixes (#4508) -* TRANSLATION - * Fix punctuation in English translation (#4958) - * Fix translation (#4355) - -## [1.5.3](https://github.com/go-gitea/gitea/releases/tag/v1.5.3) - 2018-10-31 - -* SECURITY - * Fix remote command execution vulnerability in upstream library (#5177) (#5196) - -## [1.5.2](https://github.com/go-gitea/gitea/releases/tag/v1.5.2) - 2018-10-09 - -* SECURITY - * Enforce token on api routes (#4840) (#4905) -* BUGFIXES - * Remove links from topics in edit mode (#5030) - * Detect charset and convert non UTF-8 files for display (#4950) (#4994) - * Fix layout of the topics editing form (#4971) (#4993) - * Fix null pointer dereference in ParseCommitWithSignature (#4964) - * Fix url in discord webhook (#4951) - * Fix font-cropping UI bug in diff (#4726) (#4929) - * Fix bug forget to remove Stopwatch when remove repository (#4933) - * Fix bug when repo remained bare if multiple branches pushed (#4927) - * Fix redirect with non-ascii branch names (#4764) (#4887) - * Fix issues api allow pulls (#4852) (#4862) - * Fix trimming of markup section names (#4864) - -## [1.5.1](https://github.com/go-gitea/gitea/releases/tag/v1.5.1) - 2018-09-03 - -* SECURITY - * Don't disclose emails of all users when sending out emails (#4784) - * Improve URL validation for external wiki and external issues (#4710) (#4740) - * Make cookies HttpOnly and obey COOKIE_SECURE flag (#4706) (#4707) -* BUGFIXES - * Fix missing release title in webhook (#4783) (#4800) - * Make sure to reset commit count in the cache on mirror syncing (#4770) - * Fixed bug where team with admin privilege type doesn't get any unit (#4759) - * Fix failure on creating pull request with assignees (#4583) (#4727) - * Hide org/create menu item in Dashboard if user has no rights (#4678) (#4686) -* TRANSLATION - * Fix incorrect caption of webhook setting (#4701) (#4718) - -## [1.5.0](https://github.com/go-gitea/gitea/releases/tag/v1.5.0) - 2018-08-10 - -* SECURITY - * Check that repositories can only be migrated to own user or organizations (#4366) (#4370) - * Limit uploaded avatar image-size to 4096px x 3072px by default (#4353) - * Do not allow to reuse TOTP passcode (#3878) -* BUGFIXES - * Fix column droping for MSSQL that need new transaction for that (#4440) (#4484) - * Redirect to correct page after using scratch token (#4458) (#4472) - * Replace src with raw to fix image paths (#4377) (#4386) - * Fixes repo membership check in API (#4341) (#4379) - * Add default merge options when adding new repository (#4369) (#4373) - * Fix repository last updated time update when delete a user who watched the repo (#4363) (#4371) - * Fix html entity escaping in branch deletion message (#4471) (#4485) - * Fix out-of-transaction query in removeOrgUser (#4521) (#4524) - * Fix incorrect MergeWhitelistTeamIDs check in CanUserMerge function (#4519) - * Fix panic issue on update avatar email (#4580) (#4590) - * Fix bugs when too many IN variables (#4594) (#4597) - * Push whitelist now doesn't apply to branch deletion (#4601) (#4640) - * Site admin could create repos even MAX_CREATION_LIMIT=0 (#4645) (#4650) -* FEATURES - * Add cli commands to regen hooks & keys (#3979) - * Add support for FIDO U2F (#3971) - * Added user language setting (#3875) - * LDAP Public SSH Keys synchronization (#1844) - * Add topic support (#3711) - * Multiple assignees (#3705) - * Add protected branch whitelists for merging (#3689) - * Global code search support (#3664) - * Add label descriptions (#3662) - * Add issue search via API (#3612) - * Add repository setting to enable/disable health checks (#3607) - * Emoji Autocomplete (#3433) - * Implements generator cli for secrets (#3531) -* ENHANCEMENTS - * Add more webhooks support and refactor webhook templates directory (#3929) - * Add new option to allow only OAuth2/OpenID user registration (#3910) - * Add option to use paged LDAP search when synchronizing users (#3895) - * Symlink icons (#1416) - * Improve release page UI (#3693) - * Add admin dashboard option to run health checks (#3606) - * Add branch link in branch list (#3576) - * Reduce sql query times in retrieveFeeds (#3547) - * Option to enable or disable swagger endpoints (#3502) - * Add missing licenses (#3497) - * Reduce repo indexer disk usage (#3452) - * Enable caching on assets and avatars (#3376) - * Add repository search ordered by stars/forks. Forks column in admin repo list (#3969) - * Add Environment Variables to Docker template (#4012) - * LFS: make HTTP auth period configurable (#4035) - * Add config path as an optionial flag when changing pass via CLI (#4184) - * Refactor User Settings sections (#3900) - * Allow square brackets in external issue patterns (#3408) - * Add Attachment API (#3478) - * Add EnableTimetracking option to app settings (#3719) - * Add config option to enable or disable log executed SQL (#3726) - * Shows total tracked time in issue and milestone list (#3341) -* TRANSLATION - * Improve English grammar and consistency (#3614) -* DEPLOYMENT - * Allow Gitea to run as different USER in Docker (#3961) - * Provide compressed release binaries (#3991) - * Sign release binaries (#4188) - -## [1.4.3](https://github.com/go-gitea/gitea/releases/tag/v1.4.3) - 2018-06-26 - -* SECURITY - * HTML-escape plain-text READMEs (#4192) (#4214) - * Fix open redirect vulnerability on login screen (#4312) (#4312) -* BUGFIXES - * Fix broken monitoring page when running processes are shown (#4203) (#4208) - * Fix delete comment bug (#4216) (#4228) - * Delete reactions added to issues and comments when deleting repository (#4232) (#4237) - * Fix wiki URL encoding bug (#4091) (#4254) - * Fix code tab link when viewing tags (#3908) (#4263) - * Fix webhook type conflation (#4285) (#4285) - -## [1.4.2](https://github.com/go-gitea/gitea/releases/tag/v1.4.2) - 2018-06-04 - -* BUGFIXES - * Adjust z-index for floating labels (#3939) (#3950) - * Add missing token validation on application settings page (#3976) #3978 - * Webhook and hook_task clean up (#4006) - * Fix webhook bug of response info is not displayed in UI (#4023) - * Fix writer cannot read bare repo guide (#4033) (#4039) - * Don't force due date to current time (#3830) (#4057) - * Fix wiki redirects (#3919) (#4065) - * Fix attachment ENABLED (#4064) (#4066) - * Added deletion of an empty line at the end of file (#4054) (#4074) - * Use ResolveReference instead of path.Join (#4073) - * Fix #4081 Check for leading / in base before removing it (#4083) - * Respository's home page not updated after first push (#4075) - -## [1.4.1](https://github.com/go-gitea/gitea/releases/tag/v1.4.1) - 2018-05-03 - -* BREAKING - * Add "error" as reserved username (#3882) (#3886) -* SECURITY - * Do not allow inactive users to access repositories using private key (#3887) (#3889) - * Fix path cleanup in file editor, when initilizing new repository and LFS oids (#3871) (#3873) - * Remove unnecessary allowed safe HTML (#3778) (#3779) - * Correctly check http git access rights for reverse proxy authorized users (#3721) (#3743) -* BUGFIXES - * Fix to use only needed columns from tables to get repository git paths (#3870) (#3883) - * Fix GPG expire time display when time is zero (#3584) (#3884) - * Fix to update only issue last update time when adding a comment (#3855) (#3860) - * Fix repository star count after deleting user (#3781) (#3783) - * Use the active branch for the code tab (#3720) (#3776) - * Set default branch name on first push (#3715) (#3723) - * Show clipboard button if disable HTTP of git protocol (#3773) (#3774) - -## [1.4.0](https://github.com/go-gitea/gitea/releases/tag/v1.4.0) - 2018-03-25 - -* BREAKING - * Drop deprecated GOGS\_WORK\_DIR use (#2946) - * Fix API status code for hook creation (#2814) -* SECURITY - * Escape branch name in dropdown menu (#3691) (#3692) - * Refactor and simplify to correctly validate redirect to URL (#3674) (#3676) - * Fix escaping changed title in comments (#3530) (#3534) - * Escape search query (#3486) (#3488) - * Sanitize logs for mirror sync (#3057) -* FEATURES - * Serve .patch and .diff for pull requests (#3305, #3293) - * Add repo-sync-releases admin command (#3254) - * Support default private when creating or migrating repository (#3239) - * Writable deploy keys (closes #671) (#3225) - * Add Pull Request merge options - Ignore white-space for conflict checking, Rebase, Squash merge (#3188) - * Added progressbar for issues with checkboxes (#1146). (#3171) - * Mention completion for issue editor. (#3136) - * Add 'mark all read' option to notifications (#3097) - * Git LFS lock api (#2938) - * Add reactions to issues/PR and comments (#2856) - * Add dingtalk webhook (#2777) - * Responsive view (#2750) -* BUGFIXES - * Fix wiki inter-links with spaces (#3560) (#3632) - * Fix query protected branch bug (#3563) (#3571) - * Fix remove team member issue (#3566) (#3570) - * Fix the protected branch panic issue (#3567) (#3569) - * If Mirrors repository no content is fetched, updated time should not be changed (#3551) (#3565) - * Bug fix for mirrored repository releases sorted (#3522) (#3555) - * Add issue closed time column to fix activity closed issues list (#3537) (#3540) - * Update markbates/goth library to support OAuth2 with new dropbox API (#3533) (#3539) - * Fixes missing avatars in offline mode (#3471) (#3477) - * Fix synchronization bug in repo indexer (#3455) (#3461) - * Fix rendering of wiki page list if wiki repo contains other files (#3454) (#3463) - * Fix webhook X-GitHub-* headers casing for better compatibility (#3429) - * Add content type and doctype to requests made with go-get (#3426, #3423) - * Fix SQL type error for webhooks (#3424) - * Fix PR merge error (#3421) - * Recognize more characters in crossreferenced repo name (#3413) - * Fix MSSQL bug on org (#3405) - * HTML escape all lines of the search result (#3402) - * Change local copy origin url after repository rename (#3399) - * Force-push to base repo's ref/pull/#/head (#3393) - * Fix bug when a user delete but assigned on issue (#3318) - * Use issue number/index instead of id for API URL. Fix #3297 (#3298) - * Fix repo-transfer-and-team-repo-count bug (#3241) - * Fix always-on SSL Mode checkbox in admin page (#3208) - * Fix source download link when no code unit allowed (#3166) - * Fix org owner cannot be removed if he is not in owner team (#3164) - * Fix run web with -p push failed (#3154) - * Fix gpg tmpl (#3153) - * Fix SSH auth lfs locks (#3152) - * Improvements for supporting UI Location (#3146) - * Fix new pull request link (#3133) - * Fix missing branch in release bug (#3108) - * Allow adding collaborators with (fullname) (#3103) - * Fix repo links (#3093) - * fix lfs url refs + keep path upper/lowercase in db. (#3092) - * Fix redis session failed (#3086) - * Fix bugs in issue dashboard stats (#3073) - * Fix avatar URLs (#3069) - * Fix ref parsing in commit messages (#3067) - * Fix issue list branch link broken (#3061) - * sendmail: correct option to set envelope-sender (#3044) - * Fix missing password length check when change password (#3039) - * Fix git lfs path (#3016) - * Fix API-Endpoint release (#3005) (#3012) - * Set OpenID support on by default when installing new instance (#3010) - * Various wiki bug fixes (#2996) - * Fix go-get, src and raw urls to new scheme (#2978) - * Fix error when add user has full name to team (#2973) - * Fix memcache support when value is returned as string always (#2924) -* ENHANCEMENTS - * Use GiteaServer as the user agent for http requests (#3404) - * Delete indexer DB entries when (re)creating index (#3385) - * Change how merged PR commit info are prepared (#3368) - * Asynchronously populate the repo indexer (#3366) - * Make the default action for the gitea executable that of running the webserver (#3331) - * Templates for extra links in top navbar and repo tool tabs. (#3308) - * Fixed asterisk based tasklist items #3295 (#3296) - * Add more additional template snippets (#3286) - * Open external tracker in blank window, consistently with wiki (#3227) - * Fix repo links on user profile (#3197) - * Enable emoji for wiki view (#3158) - * Small improve on deleting attachements (#3145) - * Reduce overhead of upgrades for users with custom stylesheets/JS (#3051) - * Default log level to Info without hardcoding it in installer (#3041) - * Memory usage improvements (#3013) - * Add fingerprint to ssh key endpoints. (#3009) - * Improve memory usage when reaching diff limits (#2990) - * Expandable commit bodies (#2980) - * Update gitgraph.js to fix blurry commit graph on HiDPI screens (#2957) - * Fix language names (#2955) - * Remove render issue link (#2954) - * Page parameter for repo search API (#2915) - * Apply LANDING\_PAGE config options for logged in users (#2894) - * Enable admin to search by email (#2888) - * Hide add key button if SSH is disabled (#2873) - * Fix comment API paths (#2813) - * Add an option to allow redirect of http port 80 to https. (#1928) -* MISC - * Fix organization profile on mobile devices (#3332) - * Fix guide link for webhooks in repository settings (#3291) (#3292) - * Enable Libravatar by default in new installations (#3287) - * Improve suppressed diff boxes (#3193) - * fix button heights on commits page (#3091) - * Minor copy changes (#3074) - * Sort repos in issues dashboard sidebar (#3072) - * Remove box-shadow from UI, fix dashboard issue (#3065) - * Adjust branch button size (#3063) - * Fix misalignment issue in repo header (#3062) - * Delete a user's public key via admin api (closes #3014) (#3059) - * Dashboard: Fix line height problem in issue titles (#3054) - * Remove duplicate "Max Diff Lines" from config view (#2987) - * Drop unmaintained gogs migration script (#2947) - * App restarts to quickly if it fails to start. (#2945) - * Add owner to delete repo message (#2886) - -## [1.3.1](https://github.com/go-gitea/gitea/releases/tag/v1.3.1) - 2017-12-08 - -* BUGFIXES - * Sanitize logs for mirror sync (#3057, #3082) (#3078) - * Fix missing branch in release bug (#3108) (#3117) - * Fix repo indexer and submodule bug (#3107) (#3110) - * Fix legacy URL redirects (#3100) (#3106) - * Fix redis session failed (#3086) (#3089) - * Fix issue list branch link broken (#3061) (#3070) - * Fix missing password length check when change password (#3039) (#3071) - -## [1.3.0](https://github.com/go-gitea/gitea/releases/tag/v1.3.0) - 2017-11-29 - -* BREAKING - * Make URL scheme unambiguous (#2408) -* FEATURES - * Add branch overiew page (#2108) - * Code/repo search (#2582) - * Add Activity page to repository (#2674) - * Issue Timetracking (#2211) - * Add orgmode document type on file view and readme (#2525) - * Add external markup render support (#2570) - * Implementation of discord webhook (#2402) - * Webhooks for repo creation/deletion (#1663) - * Complete push webhooks (#2530) - * Add possibility to record branch information in an issue (#780) - * Create new branch from branch selection dropdown (#2130) - * Implementation of all repositories of a user from user->settings (#1740) - * Add LFS object verification step after upload (#2868) - * Configurable SSH cipher suite (#913) - * Disable custom Git Hooks globally via configuration file (#2450) - * Sync releases table with tags on push and for mirrors (#2459) -* BUGFIXES - * Fix label comments for French locale (#3017) - * Remove duplicate "Max Diff Lines" from config view (#3001) - * Fix over-escaped characters (#2992) - * Fix go-get, src and raw urls to new scheme (#2986) - * Fix error when add user has full name to team (#2975) - * Fix files/commits of merged PRs (#2970) - * Update golang x/crypto dependencies - Fix SSH transport fail (#2951) - * Fix memcache support when value is returned as string always (#2950) - * Fix issue link rendering in commit messages (#2897) - * Fix adding a new authentication source after selecting OAuth (#2889) - * Fix new branch creation to new url scheme (#2884) - * Allow spaces in username for LDAP users (#2880) - * Fix LFS not returning correct content length when requesting a range … (#2864) - * Fix fork repository cycle to self (#2860) - * Fix click create pull request button 404 (#2859) - * Fix API raw file content access for default branch (#2849) - * Clean repository ROOT directory name with filepath.Clean (#2846) - * Fix API raw requests for commits and tags (#2841) - * Fix order of comments (#2835) - * Issue content should not be updated when closing with comment (#2833) - * Fix ordering in app.ini and fix run mode option (#2829) - * Fix redirect url of legacy commits route (#2825) - * Fix commits page url (#2823) - * Fix wrong translations (#2818) - * Fix dropdown menu position when explore repos (#2808) - * Fix Git LFS object/repo link storage in database and small refactoring (#2803) - * Use relative URLs for avatars on the dashboard (#2800) - * Add checks for commits with missing author and time (#2771) - * Fix emojify image URL (#2769) - * Hide unactive on explore users and some refactors (#2741) - * Fix IE unsupported javascript construction in branch dropdown (#2736) - * Only update mirror last update after successful sync (#2730) - * Fix semantic-ui style conflict with v-cloak (#2722) - * Fixing wrong translation on sort type oldest/latest (#2720) - * Fix PR, milestone and label functionality if issue unit is disabled (#2710) - * Fix plain readme didn't render correctly on repo home page (#2705) - * Fix organization removal from watch table migration (#2703) - * Fix repository search function (#2689) - * fix panic on gogs webhook creation (#2675) - * Fix orgnization user watch repository (#2670) - * GPG key email verification no longer case sensitive (#2661) (#2663) - * Fix index column deletion (#2651) - * table `pull_request` wasn't updated correctly (#2649) - * Fix go get response if only app URL is custom in configuration (#2634) - * Fix doubled issue tab introduced in migration v16 (#2611) - * Rewrite migrations to not depend on future code changes (#2604) - * Fix implementation of repo Home func (#2601) - * Fix translation upload to crowdin (#2599) - * Reduce usage of allcols on update (#2596) - * fix go get subpackage bug (#2584) - * Fix broken migration to add can_push field back to table (#2574) - * fix readme view bug (#2566) - * Fix sending mail with a non-latin display name. #2102 (#2559) - * Restricting access to fork functioanlity to users with Code access (#2534) - * fix updated update on public key (#2514) - * Added bucket name to s3 drone plugin (#2505) - * fixes 500 error on dashboard when using MSSQL (#2504) - * fix wrong rendering of commit detail page (#2503) - * Hotfix: Add time manually adds time in nanoseconds (#2499) - * Remove repository mirrors from "collaborative" list (#2497) - * fix release failed since the wrong token name (#2496) - * Fix slice out of bounds error in mailer (#2479) - * Fix #2470 (#2477) - * fix orgnization webhooks (#2422) - * fix webhook test (#2415) - * fix missing orgnization discord webhook (#2414) - * Fix route handler order (#2409) - * Prevent sending emails and notifications to inactive users (#2384) - * Move themes to plugin directory. Fixes #2372 (#2375) - * fix duplicated feed (#2370) - * Fix missing collabrative repos (#2367) - * Only check at least one email gpg key (#2266) - * don't check minimum key size when disabled (#1754) - * Fix run command race (#1470) - * fix .netrc authentication (#2700) - * Fix so that user can still fork his own repository to his organizations (#2699) - * Fix can_push value to false in protected_branch (#2560) - * Fix copy in email templates (#2801) - * Fix inconsistencies in user settings UI (#2901) - * Fix attachments icon size on zoom in/out (#2853) - * Fix ignored errors in API route (#2850) - * Fix activity css conflict with semantic ui (#2758) - * Fix notifications tabs according to semantic-ui docs (#2733) - * Fix typos in app.ini (#2732) - * Fix duplicated rel attribute (#2549) - * Fix tests code to prevent some runtime errors (#2381) -* ENHANCEMENTS - * Memory usage improvements and lower minimal git requirement to 1.7.2 (#3013) (#3028) - * Set OpenID support on by default when installing new instance (#3010) (#3027) - * Use api.TrackedTime in API (#2807) - * Configurable SSH key exchange algorithm and MAC suite (#2806) - * Add Safari pinned tab icon (#2799) - * Improve force push detect when push (#2798) - * Add wrapping to long diff lines (#2789) - * Link members and repositories count to each page on org home. (#2787) - * Show Sendmail settings on admin config page (#2782) - * Add commit count caching (#2774) - * Use identicon image for default gravatar. (#2767) - * Add default ssh ciphers (#2761) - * Remove manual of unsupported option (#2757) - * Add search mode option to /api/repo/search (#2756) - * Move swagger-ui under /api/v1 (#2746) - * Add support for extra sendmail arguments (#2731) - * Use buffersize to reduce database connection when iterate (#2724) - * Render plain text README.txt monospaced (#2721) - * Integration test for activity page (#2704) - * Merge password and 2fa page on user settings (#2695) - * Allow custom SSH user in UI for built-in SSH server (#2617) (#2678) - * Refactor duplicated code in repo handlers (#2657) - * Replace deprecated Id method with ID (#2655) - * Remove redudant functions and code (#2652) - * hide navbar when only 1 sign-in method is available (#2444) (#2648) - * Change default sort order (#2647) - * Change pull description text (#2075) (#2646) - * Remove direct user adding to organization members (#2641) - * Use session when creating user (#2638) - * Use Semantic UI's Search component for user and repo search (#2636) - * Use AfterLoad instead of AfterSet on Structs (#2628) - * Remove redudant CheckUnit calls in router (#2627) - * Remove repo unit index (#2621) - * Remove redudant issue LoadAttributes() calls (#2614) - * Make indexer code more reusable (#2590) - * Use custom type and constants to hold available order by options (#2572) - * Use named ActionType constants in template helper (#2545) - * Make basic functionality work without JavaScript (#2541) - * Ctrl + Enter to submit forms (#2540) - * Automatically regenerate indexer for incompatible versions (#2524) - * Set default lfs content path to data/lfs (#2521) - * Convert spaces to tabs in footer.tmpl (#2520) - * Sort repository tree entries in natural way (#2506) - * Open external wiki in new window (#2489) - * Use created & updated instead BeforeInsert & BeforeUpdate (#2482) - * Hide branch on pull request view or create UI (#2454) - * improve protected branch to add whitelist support (#2451) - * some refactors for issue and comments (#2419) - * Restructure markup & markdown to prepare for multiple markup language… (#2411) - * Improve issue search (#2387) - * Add UseCompatSSHURI setting (#2356) - * Use custom search for each filter type in dashboard (#2343) - * Failed authentication are now properly logged (#2334) - * Add environment variable support for Docker image (#2201) - * Set session and indexers' data files rel to AppDataPath (#2192) - * Display commit status on landing page of repo (#1784) -* TESTING - * Add integration test for logging out (#2892) - * Integration test for user deleting account (#2891) - * Use different directories for session files in integration tests (#2834) - * Add deleted_branch table fixture (#2832) - * Include HTTP method in test error message (#2815) - * Add repository search unit and integration tests (#2575) - * Expand fixtures (#2571) - * Fix /api/repo/search integration tests (#2550) - * Make integration tests more user-friendly (#2536) - * Fix unit test race condition (#2516) - * Add missing fixture to clean gpg_key table (#2494) - * Hotfix for integration testing (#2473) - * Make repo private to not interfere with other tests (#2467) - * Error message for integration test (#2410) - * Fix "index out of range" runtime error in repo_list tests (#2376) - * Add git clone test on integration test (#1682) -* TRANSLATION - * Fix localization texts that contain semicolon (#2900) - * Fix activity locale (#2709) - * Update translation from crowdin (#2368) -* BUILD - * change the email and name to GitBot account. (#2848) - * Fix removing backslash before quotes in translations (#2831) - * add gitea remote in drone. (#2817) - * add remote name for git push. (#2816) - * Launch Gitea with custom UID/GID for 'git' user (fixes #2286) (#2791) - * Download and pushing translations (#2727) - * Automatic update of translations (#2585) - * Add pre-build step for nodejs stuff (#2581) - * Compress css with nodejs (#2580) - * Remove go version check for make fmt (#2558) - * Fix lint errors (#2547) - * Always run fmt check in CI (#2546) - * Fix fmt errors (#2544) - * add codecov.io service. (#2493) - * Fix some tests : make coverage -> test (#2492) - * Fix fmt error in mailer (#2490) - * Allow changing integration test database connection using env variables (#2484) - * Add changelog config file for generate changelog (#2461) - * Changes for latest DroneCI (#2362) - * Use standard lessc and minify CSS using Node.js (#2337) -* DOCS - * Update screenshots on README (#2910) - * Gogs -> Gitea (#2909) - * Update swagger documentation (#2899) - * Fix typo (#2810) - * Fix Polish language name spelling (#2766) - * Fix Various Grammar Issues and Adjust Unnatural Wording (#2737) - * Add maintainer label for docker file (#2658) - * Link to gitea-specific Vagrant example (#2624) - * add release notes of v1.1.4 (#2463) - * Wrap most paragraphs to 80 columns (#2396) - * Update CONTRIBUTING following #2329 discussion (#2394) - * Update hard-coded version to 1.3.0+dev (#2390) - * Clarify Translation Process. Also fix branch names (#2378) - * Admin grammar fixes and improvements (#2056) -* MISC - * Sync MaxGitDiffLineCharacters with conf/app.ini (#2779) - * Dockerfile: Updated alpine image to 3.6. (#2486) - * Basic VSCode configuration for building and debugging (#2483) - * Added vendor dir for js/css libs; Documented sources (#1484) (#2241) - -## [1.2.3](https://github.com/go-gitea/gitea/releases/tag/v1.2.3) - 2017-11-03 - -* BUGFIXES - * Only require one email when validating GPG key (#2266, #2467, #2663) (#2788) - * Fix order of comments (#2835) (#2839) - -## [1.2.2](https://github.com/go-gitea/gitea/releases/tag/v1.2.2) - 2017-10-26 - -* BUGFIXES - * Add checks for commits with missing author and time (#2771) (#2785) - * Fix sending mail with a non-latin display name (#2559) (#2783) - * Sync MaxGitDiffLineCharacters with conf/app.ini (#2779) (#2780) - * Update vendor git (#2765) (#2772) - * Fix emojify image URL (#2769) (#2773) - -## [1.2.1](https://github.com/go-gitea/gitea/releases/tag/v1.2.1) - 2017-10-16 - -* BUGFIXES - * Fix PR, milestone and label functionality if issue unit is disabled (#2710) (#2714) - * Fix plain readme didn't render correctly on repo home page (#2705) (#2712) - * Fix so that user can still fork his own repository to his organizations (#2699) (#2707) - * Fix .netrc authentication (#2700) (#2708) - * Fix slice out of bounds error in mailer (#2479) (#2696) - -## [1.2.0](https://github.com/go-gitea/gitea/releases/tag/v1.2.0) - 2017-10-10 - -* SECURITY - * Sanitation fix from Gogs (#1461) -* BREAKING - * Rename /forget_password url to /forgot_password (#1219) -* FEATURES - * Logo: Add task to generate images from SVG and change to new logo (#2194) - * Status-API (#1332) - * Show commit status icon in commits table (#1688) - * Additional OAuth2 providers (#1010) - * GPG commit validation (#1150) - * Rework SSH key management UI to add GPG (#1293) - * Implement GPG api (#710) - * Login via OpenID-2.0 (#618) - * Add units to team (#947) - * Batch updates for issues (#926) - * Add Gitea Webhook (#1755) - * API: support '/orgs/:org/repos' (#2047) - * Display all organization from user settings (#1739) - * LDAP user synchronization (#1478) - * Adding #issuecomment to the URL in E-Mail notifications (#1674) - * Add download count field and unit testing for attachment. (#1512) - * Add repo mirror sync API endpoint (#1508) - * Add markup package to prepare for org markup format (#1493) - * Support for custom html meta (#1423) - * Per issue/PR watch/unwatch (#1410) - * Allow ENABLE_OPENID_SIGNUP to depend on DISABLE_REGISTRATION (#1369) - * Repo size in admin panel (#1482) - * Show user OpenID URIs in their profile (#1314) - * Add change-password admin command (#1304) - * Only use issue and wiki on repo. (#1297) - * Allow push to init a wiki repo (#1279) -* ENHANCEMENTS - * Make time diff translatable (#2057) - * Smaller watch, star, and fork buttons (#2052) - * Display config file path on admin panel (#2030) - * Only show SSH clone URL if signed in (#2169) (#2170) - * Only show "No Description" to repo admins (#2167) - * Always return valid go-get meta, even if unauthorized (#2010) - * Enable assignee e-mail notification (#2003) - * Let not-logged-in users view releases (#1999) - * No highlighting for .txt files (#1922) - * Make side nav on dashboard stackable (#1778) - * Setting to disable authorized_keys backup (#1856) - * Hide the create organization button (in dashboard/organization section) (#1705) - * LFS: Return 404 for unimplemented endpoints (#1330) - * Show a link to password reset from user settings requiring a password (#862) - * Reserve the "explore" user/org name (#1222) - * Send notifications to participants in issue comments (#1217) - * Improve style of user OpenID setting page (#1324) - * Use font-awesome OpenID icon more (#1320) - * Use readonly input form to show the validated OpenID URI (#1308) - * Add captcha support to OpenID based signup (#1307) - * Minor improvements on commit graph UI (#1380) - * Mirror sync interval specified as duration string (#1407) - * Make issue in commit graph "clickable" (#1392) - * Use whole button (commit graph) as link (#1390) - * Autofocus on 2fa passcode fields (#1460) - * Sort on repo size in admin panel (#1654) - * Improve dashboard repo search (#1652) - * Use a better default MAX_GIT_DIFF_LINE_CHARACTERS (#1845) - * Adds Parent property to the repo API (#1687) - * Add configuration option for default permission to create Organizations (#1686) - * Remove sha1 hash display in repository table (#1678) - * Download files to their original filename (#1676) - * Exposes in API the Repo entity's Size and IsBare property (#1668) - * Change two factor code entry box from text to number (#1733) - * Directly show error if user hit repository limit (#1767) - * Generate small and large logos at 4x resolution (#2233) - * Tags listed in releases tab (#2389) (#2424) -* BUGFIXES - * Fix adding branch as protected to not allow pushing to it (#2556) - * Orgs: fix org page title when full name is not defined (#1495) - * Fix double borders on edit page (#1152) (#1153) - * Search bar fixes for #1187 and #1205 (#1207) - * Fix upgrade failed after ever rollback (#1194) - * Fix FCGI (over TCP) support (#1368) - * Backport of migration fixes (#2604) (#2677) - * fix panic on gogs webhook creation (#2675) (#2676) - * Backport: Fixes 500 error on dashboard when using MSSQL (#2504) (#2662) - * Fix go get response if only app URL is custom in configuration (#2634) (#2640) - * Fix deletion of unprotected branches (#2630) - * Backport of 2611 / Fix doubled issue tab introduced in migration v16 (#2622) - * v38 migration used an outdated version of RepoUnit model (#2602) - * fix go get subpackage bug (#2584) (#2589) - * Backport: Sync releases table with tags on push and for mirrors (#2459) (#2554) - * Backport: Restricting access to fork functioanlity to users with Code access (#2542) - * Fix migration from pre-v15 to 1.2.0 (#2460) (#2465) - * Fix migration from pre-v15 to 1.2.0 (#2460) - * fix duplicated feed (#2370) (#2413) - * Fix releases to be counted from database not tags (#2389) - * Fix missing collabrative repos (#2367) (#2382) - * Add more test for login links and fix a bug on action retrieve (#2361) - * Fix SQL condition bug in GetFeeds(..) (#2360) - * fix bug on create repo link on dashboard (#2359) - * Fix order of elements in dashboard html (#2344) - * Fix repo-search template errors for go1.7 (#2336) - * Add missing forks key for dashboard repository component (#2325) - * fix template error on explore repos (#2319) - * Trigger sync webhooks on UI commit (#2302) - * fix 500 error when view an issue which's milestone deleted (#2297) - * Only update needed columns when update user (#2296) - * Fix rendering of external links (#2292) - * Fix and improve dashboard repo UI (#2285) - * Make short link pattern greedy (#2259) - * Temporarily patch go-ini/ini with fork (#2255) - * Convert xorm literal queries to method calls (#2253) - * update code.gitea.io/git in vendor to fix delete branch fails (#2250) - * Replace calls to xorm UseBool with Where (#2237) - * rhel7 has a git version with four digits (1.8.3.1) (#2236) - * Fix internal requests when gitea listens to unix socket or only external IP (#2234) - * Check for access in /repositories/:id (#2227) - * Fixed robots.txt 404 error (#2226) - * Fix counts on issues dashboard (#2215) - * Fix unclosed session bug (#2214) - * Add collaborative repositories to the dashboard (#2205) - * Fix issue updated_unix bug (#2204) - * Fix Commits nil pointer dereference (#2203) - * Fix bare-repo bugs (#2199) - * Fix PR nil-dereference bug (#2195) - * Allow only single fork per user/organization (#2193) - * Fix key usage time update if the key is used in parallel for multiple operations (#2185) - * Only allow token authentication with 2FA enabled (#2184) - * Fix profile update for non-local users (#2178) - * Fix compiling without sqlite and gcc (#2177) - * Make compare button URL aware if current repo is a fork (#2162) (#2163) - * Remove unit types commits and settings (#2161) - * Fix OpenID registration route (#2160) - * Fix repository settings collobration list display (#2151) - * Ignore invalid issue numbers in commit messages. Fixes #2022 (#2150) - * Fix SHA1 hash linking (#2143) - * Fix repo API bug (#2133) - * Use POSIX complaint ! operator in find (#2132) - * Fix GET /users/:username/repos endpoint (#2125) - * Fix username rendering bug (#2122) - * Fix wiki preview links (#2119) - * vendor: update sqlite to fix "database is locked" errors (#2116) - * Fix unchecked error bug (#2110) - * Fix missing-return bug (#2109) - * Fix API for branches with slashes (#2096) - * Fix git hooks update to receive required arguments (#2095) - * upgrade git source code. (#2094) - * Fix SQL bug in models.PullRequests (#2092) - * Don't ignore gravatar error (#2083) - * Fix release display and correct paging (#2080) - * remove unnecessary blank lines and wrong error log (#2079) - * Check for valid renamed usernames (#2077) - * Update git module (#2074) - * Fix org hooks UI (#2072) - * Fix #1271: Call location.reload after XHR finishes (#2071) - * Fix default ghost assignee bug (#2069) - * Fix bug in issue labels API (#2048) - * Load label ID in NewLabels (#2045) - * Fix: `http: multiple response.WriteHeader calls` (#2038) - * Pagination on releases page (#2035) - * repo/editor: fix breadcrumb path cuts parent dirs (#3859) (#2032) - * Fix displaying commits and files of PR created from now deleted fork (#2023) - * Fix #2001 and fix issue comments hidden (#2016) - * Update code.gitea.io/git (#2014) - * Keep sort when switching page (#2013) - * Important: wrong PR merge commit ID saved (#2007) - * Don't show non-comments in comments API (#2001) - * Fix "Dashboard shows deleted comments" (#1995) - * Make branch deletion URL more like GitHub's, fixes #1397 (#1994) - * Fix fast-forward PR bug (#1989) - * Fix GPG email checking to be case insensitive (#1988) - * fix bug for normal user visit public repo (#1984) - * fix collborators lack of units on orgnization repositories (#1968) - * Fix diff of renamed and modified file (#1967) - * Fix uppercase default branch bug (#1965) - * Fix bug in Action.loadRepo() (#1959) - * Fix deleted milestone bug (#1942) - * Fix engine bug in getIssueByID (#1934) - * Switch to keybase go-crypto (for some elliptic curve key) + test (#1925) - * Fix setting.AppPath for integration tests (#1923) - * Fix search by issue type (#1914) - * Fix ghost user bug (#1913) - * Require token before checking membership/ownership (#1905) - * Bug fixes for org member API (#1904) - * A missing / to provide a correct endpoint (#1903) - * Fix 500 in public activity page (#1901) - * Center-aligned login topbar (#1880) - * Migration to fix existing owner team units (#1873) - * Fix paginater length (#1866) - * Fix bug in removeOrgRepo (#1858) - * Display draft releases (#1854) - * Fix 404 for external tracking issues (#1852) - * Update code.gitea.io/git (#1849) - * Fix user profile activity feed (#1848) - * Don't ignore error in getMergeCommit (#1843) - * Fix locking bug in removeOrgRepo (#1842) - * Fix status table race condition (#1835) - * Fix PR template error (#1834) - * Fix pull request compare link (#1832) - * Use ghost users in issues/PRs (#1831) - * Commitless repos should be bare (#1829) - * Update code.gitea.io/git (#1824) - * Fix invalid reference in feeds template (#1820) - * fix bug to deny to add orgnization as a member of an orgnization or team (#1815) - * xxx_active_code_live setting in printed in hours and minutes instead … (#1814) - * Fix deadlock in updateRepository (#1813) - * Give all units to owner team (#1812) - * Fix 500 for GET /teams/:id endpoints (#1811) - * fix bug not to trim space of login username (#1796) - * Fix renaming bug (#1786) - * Fix activity feed (#1779) - * Make navbar scroll on overflow (#1777) - * Delete repo redirects on repo deletion (#1776) - * Fix unloaded owner bug (#1770) - * Admin should always be allowed to create repositories even if hit limit (#1765) - * Update HighlightJS and fix YAML files highlighting (#1764) - * fix: #1757 fix set MAX_CREATION_LIMIT as zero. (#1762) - * fix admin lost permission caused by #947 (#1753) - * More fixes for dashboard search (#1750) - * fixes wrong after field in webhook payload (#1746) - * fix avatar update bug (#1729) - * Fix FOUC on Firefox (#1728) - * Fix changes introduce by update of go-swagger. (#1727) - * Fix #1719 (#1722) - * Correct flash after sending password reset email (#1718) - * Fix and test for delete user (#1713) - * Fix rendering of issue checkboxes (#1709) - * Enforce netgo build tag while cross-compilation (#1690) - * fix bug when push a branch name with / & fix an integration test bug (#1689) - * fix potential sqlite lock (#1680) - * Fix commit sha1 URL rendering in markdown (#1677) - * Fix static files permission under public/ (#1675) - * fix: tag contain character ) will http 500 on release page (#1670) - * Fix CSS for code in wiki markdown (#1660) - * fix multiple readme file rendering and fix #1657 (#1658) - * Add primary key and index to external login user table (#1656) - * fix #1643 and improve integration test (#1645) - * Fix version in Makefile (#1636) - * Handle display of GPG key without end date (#1628) - * fix bug on issue view when not login (#1624) - * bug fixed for API to get user's repos (#1622) - * fix lost text color on button on set as primary email (#1621) - * Add create_at and updated_at in PR json (#1616) - * update git and fix #1133 (#1614) - * fix bug on status API (#1533) - * Do not show empty collaborators segment (#1531) - * Fix markdown rendering (#1530) - * fix go get sub package and add domain on installation to let go get work defaultly (#1518) - * fix #1501 ssh hangs caused by #1461 (#1513) - * Fix empty file download (#1506) - * Fix broken v27 migration - change mirror interval from int to bigint (#1504) - * Do not allow committing to protected branch from online editor (#1502) - * Add internal routes for ssh hook comands (#1471) - * Fix races within code.gitea.io/git.(*Command).RunInDirTimeoutPipeline (#1465) - * Simple quick fix for #1418 (#1456) - * fix gpg API panic when no verification (#1451) - * fix migrate failed and org dashboard failed on MSSQL database (#1448) - * Optimize and fix autolink function (#1442) (#1444) - * Fix and simplify repo branches (settings) UI (#1435) - * Fix disabled fields in repo settings UI (#1431) - * fixes pull request hanging when it contains normal and LFS files (#1425) - * Fix races in the log module by using syncmap (#1421) - * Add length check for the return string (#1420) - * Fix "Error: No issue number specified" when pushing (#1393) - * Corrected Mirror.NextUpdate not set (#1388) - * fix: remove `str2html` from org full name (#1360) - * Correct broken unaligned load/store in armv5 (#1355) - * Remove href on first/last link when on first/last page (#1345) - * Fix broken table layout (#1344) - * LFS: Fix SSH authentication for trailing arguments (#1328) - * Remove empty file (#1326) - * Fix delete user failed on sqlite (#1321) - * Fix inconsistency in layout (#1316) - * Fix gpg wrong column types (#1303) - * Fix wiki bugs (#1294) - * Fix missing less sources for oauth (#1288) - * Make sure both scripts/ can live side by side (#1264) - * Fix nil-dereference bug (#1258) - * rewrite pre-commit, post-commit and options hooks (fixes #1250) (#1257) - * Commit search appearance fixes (#1254) - * Fix forget migration for wiki hooks (#1227) - * Fix repo settings external tracker failed and check external urls (#1215) - * Fix 500 caused by branches settings introduced by #1198 (#1214) - * fix #1189, commit messages containing a pipe (#1203) - * Bug fixed for delete repo failed (#1193) - * Fix migration failed when authorized_keys is not exist (#1180) - * Fix ini format incomiptable with crowdin (#1177) -* TESTING - * Integration tests for issues API (#2059) - * Add integration tests for signin (#2363) - * Add INTERNAL_TOKEN to integration .ini file (#2346) - * Add public links check (#2323) - * Fix hooks for integration repo (#2216) - * More integration tests for comment API (#2156) - * Cache session cookies in tests (#2128) - * Less verbose integration tests (#2123) - * Fix improper setup for integration tests (#2050) - * Improve integration test helper functions (#2049) - * Add integration test for issue creating (#2002) - * Use testing/benchmark interface (#1993) - * Add integration test for repository migration (#1983) - * Consolidate boilerplate in integration tests (#1979) - * Set console to debug for integration tests (#1976) - * Add pull-create integration test (#1972) - * Coverage reports for integration tests (#1960) - * Add integration test for pull-request merge (#1912) - * Add integration test for file editing (#1907) - * Add integration test for repository forking (#1896) - * Run unused test (#1875) - * Don't recreate database in integration tests (#1697) - * remove sqlite tag when integration test with mysql/postgres and recreate database when init integration test (#1693) - * MySQL, Postgres integration tests in drone (#1638) - * improve integration test to resue models/fixtures and store git repos with tests (#1627) - * Improve govendor testing (#1623) - * Integration test framework (#1290) - * Unit tests for issue_list (#1209) - * Add integration test for signup (#1135) -* TRANSLATION - * update translation from crowdin (#2368) (#2380) - * Small fixes (#2144) - * Missing signed commit display translations (#2134) - * Sync latest translations from crowdin (#2104) - * Add make command update-translations for update translations from crodwin (#2097) - * Fix some mistakes (#1833) - * Improve clarity between is_activated and prohibit_login (#1788) - * Improve grammar (#1775) - * Fix bad grammar and wordiness (#1741) - * Make strings translatable (#1188) (#1198) -* BUILD - * Dockerfile for aarch64 (#1128) (#1130) - * backport from v1.2 branch: add secrets for github release (#2588) (#2598) - * Add secrets for github release to fix drone failed (#2588) - * Backport changes for latest drone (#2586) - * Removing .drone.yml.sig (#2579) - * Fix drone for tags (#2573) (#2576) - * Backport: Remove go version check for make fmt (#2558) (#2561) - * Backport: Fix lint, fmt and integration testing errors (#2553) - * update latest xorm version to vendor (#2353) - * Remove integration test executables on `make clean` (#2340) - * refactor(Makefile): allow overriding default go program (#2310) - * Revert to upstream ini dependency (#2304) - * Use /dev/urandom to create random password (#2298) - * update drone sig file. (#2262) - * go get github.com/wadey/gocovmerge when needed (#2235) - * fix typo (#2145) - * Revert "Reduce number of layer" (#2086) - * Reduce number of layer (#2078) - * Skip sqlite integration in CI (#2058) - * fix golint error and rename func for suggestion. (#1997) - * fix misspell (#1996) - * update drone sig file (#1981) - * send notification if status changed (#1973) - * switch gitter to discord for drone. (#1971) - * Fix missing backslash in Dockerfile.rpi (#1952) - * Don't run 'make release' on PRs (#1908) - * Update code.gitea.io/git (#1892) - * Use production version of vuejs (#1869) - * Add a variable for docker tag (#1825) - * resign drone and fix #1816 (#1819) - * Separate generate swagger + fix sed os specific (#1791) - * Only run coverage on merges/pushes to master (#1783) - * Remove stale rule from Makefile (#1782) - * feat: upgrade drone docker image to support multi-stage build. (#1732) - * Really don't cache apk index (#1694) - * Limit clone depth when drone-building (#1644) - * Refactor Dockerfile (#1632) - * Check if missing/modified/unused deps in vendor and fix errors (#1468) - * Add GOFLAGS and EXTRA_GOFLAGS (#1438) - * Include formatting check to the `make test` (and thus also `check`) rule (#1366) -* DOCS - * fix wrong changelog title (#2395) - * fix webhook link (#2289) - * Improve swagger doc (#2274) - * Add link to forum in issue template (#2070) - * add missing lfs config on example file (#2039) - * Add discourse link (#2027) - * Fix wording (#2024) - * Fix typo (#1974) - * Swagger docs for list/create forks (#1941) - * Update links to Discord server (#1940) - * [ci skip] update discord badge. (#1930) - * Change join chat from gitter to discord (#1929) - * Update changelog with v1.1.1 (#1926) - * Correct grammar in APIEmpty documentation (#1748) - * Add swagger comment for MirrorSync (#1747) - * Add "Table of Contents" in CONTRIBUTING.md (#1634) - * Fix service description in Debian init file (#1538) - * Use MAINTAINERS file in repository in CONTRIBUTING (#1489) - * Generate swagger json (#1402) - * Changed text when password reset disabled. (#1364) - * Removed email copyright year (#1348) - * Specify that time interval units are seconds (#1311) - * Gitea OpenID-2.0 login has been tested with livejournal.com too (#1306) - * Make wording of commit search more clear (#1291) - * Add notice that LFS mirroring is not supported (#1251) - * Fix typos in models/ and modules/ (#1248) - * Refactor and fix incorrect comment (#1247) - * Fix migration comment (#1241) - * Update locale_en-US.ini (#1235) - * Add LibreJS support (#1201) - * rename OSX to macOS (#1176) - * add mssql to app.ini db config comment (#1172) - * Add MSSQL to issues template (#1171) -* MISC - * Add badge and link to the Matrix room (#2348) - * ignore coverage steps. (#2257) - * Use sqlite3 database as default for Docker image (#2182) - * update drone discord plugin to 0.0.4 version (#1992) - * fix typo (#1990) - * Move 3rd party js/css into `public/vendor` and document sources (#2383) - * Prevent conflicting TOTP accounts by adding AppURL to issuer parameter (#2335) - * Fix variable name typo (#2327) - * Make use of Vue more universal (#2318) - * Remove (almost) server side data rendering from repo-search component (#2317) - * Add OpenID configuration in install page (#2276) - * More tweaks to repo top panel (#2267) - * File path tweaks in UI (#2264) - * Make SHOW_USER_EMAIL also apply to profiles (#2258) - * EnableUnit() -> UnitEnabled() (#2242) - * Prevent selection of diff line numbers (#2240) - * Remove unused variable on makefile (#2225) - * No error log entries for repo 404 (#2200) - * Refactor vue delimeters to use es6 template delimeters (#2171) - * Replace tmp with TMPDIR. (#2152) - * Remove unused files (#2124) - * Improve org error handling (#2117) - * Absolute path for setting.CustomConf (#2085) - * remove deprecated code for Gogs compatible (#2041) - * Refactor session close as xorm already does everything needed internally (#2020) - * SQLite has a query timeout. Hopefully fixes most 'database locked' errors (#1961) - * Use monospace font in githook editor (#1958) - * Fix import order (#1951) - * Gracefully handle bare repositories on API operations. (#1932) - * Fix errors caused by force push (#1927) - * Display URLs in integration test logs (#1924) - * Set TMPDIR environment variable for dump command (#1915) - * Cache ctx.User in retrieveFeeds (#1902) - * Make `LocalCopyPath` a setting instead of a hard-coded path (#1881) - * Add check misspelling (#1877) - * Fix misspelled variables (#1874) - * Gofmt (#1868, #1710, #1662) - * Rename misnamed migration (#1867) - * Support CRLF when splitting code lines for display (#1862) - * Add convert less css file step. (#1861) - * Prevent accidental selection of line numbers in code view (#1860) - * Delete Public SSH Key tmp file after calculating fingerprint (#1855) - * Remove annoying difference in button heights. (#1853) - * Only run test coverage on master branch. (#1838) - * Error from mktemp command in MacOS. (#1837) - * Use writeTmpKeyFile in calcFingerprint (#1828) - * ROOT_URL setting use the default as shown in conf/app.ini (#1823) - * Rename RepoCreationNum -> MaxCreationLimit (#1766) - * Add button to admin ui (#1738) - * Correct spelling mistakes (#1703) - * Make openid support default false for compatible with v1.1 (#1650) - * Send mails as HTML as default. Setting for send as plain text. (#1648) - * fix potential lock when sqlite (#1647) - * Optimize png images via Google zopflipng [ci skip] (#1639) - * Upgrade alpine to v3.5 in Dockerfile (#1633) - * remove unused vendor packages (#1620) - * markup: microoptimise for many short filenames in directory (#1534) - * support health check via / and fix #969 (#1520) - * Remove env user salt since no need to use (#1515) - * Drop db operations from hook commands (#1514) - * Better URL validation (#1507) - * Migrate WatchInfo struct to api (#1492) - * refactor: show command help message. (#1486) - * refactor update ssh key use time (#1466) - * Set VERSION from git once, in a variable (#1447) - * Remove unused mutex field (#1440) - * Simplify settings pages with item list (#1389) - * Clean-up PostgreSQL Tests (#1361) - * refactor: remove workaround after the golang 1.7 release. (#1349) - * Delete the useless code (#1335) - * Run "make fmt" with go-1.6 (#1333) - * Refactor admin/auth/new.tmpl (#1277) - * Refactor repo/issue/view_content.tmpl (#1276) - * Cleaner ui for admin, repo settings, and user settings page (#1269) (#1270) - * Cleaner UI for explore page (#1253) (#1255) - * Synced licenses with github repo (#1246) - * Synced gitignores with github repo (#1245) - * Simplify RepositoryList.loadAttributes() (#1211) - * Move user_follow to separate file (#1210) - * Reduce conditionals in signin/signup inner forms (#1138) - -## [1.1.4](https://github.com/go-gitea/gitea/releases/tag/v1.1.4) - 2017-09-04 - -* BUGFIXES - * Fix rendering of external links (#2292) (#2315) - * Fix deleted milestone bug (#1942) (#2300) - * fix 500 error when view an issue which's milestone deleted (#2297) (#2299) - * Fix SHA1 hash linking (#2143) (#2293) - * back port from #1709 (#2291) - -## [1.1.3](https://github.com/go-gitea/gitea/releases/tag/v1.1.3) - 2017-08-03 - -* BUGFIXES - * Fix PR template error (#2008) - * Fix markdown rendering (fix #1530) (#2043) - * Fix missing less sources for oauth (backport #1288) (#2135) - * Don't ignore gravatar error (#2138) - * Fix diff of renamed and modified file (#2136) - * Fix fast-forward PR bug (#2137) - * Fix some security bugs - -## [1.1.2](https://github.com/go-gitea/gitea/releases/tag/v1.1.2) - 2017-06-13 - -* BUGFIXES - * Enforce netgo build tag while cross-compilation (Backport of #1690) (#1731) - * fix update avatar - * fix delete user failed on sqlite (#1321) - * fix bug not to trim space of login username (#1806) - * Backport bugfixes #1220 and #1393 to v1.1 (#1758) - -## [1.1.1](https://github.com/go-gitea/gitea/releases/tag/v1.1.1) - 2017-05-04 - -* BUGFIXES - * Markdown Sanitation Fix [#1646](https://github.com/go-gitea/gitea/pull/1646) - * Fix broken hooks [#1376](https://github.com/go-gitea/gitea/pull/1376) - * Fix migration issue [#1375](https://github.com/go-gitea/gitea/pull/1375) - * Fix Wiki Issues [#1338](https://github.com/go-gitea/gitea/pull/1338) - * Forgotten migration for wiki githooks [#1237](https://github.com/go-gitea/gitea/pull/1237) - * Commit messages can contain pipes [#1218](https://github.com/go-gitea/gitea/pull/1218) - * Verify external tracker URLs [#1236](https://github.com/go-gitea/gitea/pull/1236) - * Allow upgrade after downgrade [#1197](https://github.com/go-gitea/gitea/pull/1197) - * 500 on delete repo with issue [#1195](https://github.com/go-gitea/gitea/pull/1195) - * INI compat with CrowdIn [#1192](https://github.com/go-gitea/gitea/pull/1192) - -## [1.1.0](https://github.com/go-gitea/gitea/releases/tag/v1.1.0) - 2017-03-09 - -* BREAKING - * The SSH keys can potentially break, make sure to regenerate the authorized keys -* FEATURES - * Git LFSv2 support [#122](https://github.com/go-gitea/gitea/pull/122) - * API endpoints for repo watching [#191](https://github.com/go-gitea/gitea/pull/191) - * Search within private repos [#222](https://github.com/go-gitea/gitea/pull/222) - * Hide user email address on explore page [#336](https://github.com/go-gitea/gitea/pull/336) - * Protected branch system [#339](https://github.com/go-gitea/gitea/pull/339) - * Sendmail for mail delivery [#355](https://github.com/go-gitea/gitea/pull/355) - * API endpoints for org webhooks [#372](https://github.com/go-gitea/gitea/pull/372) - * Enabled MSSQL support [#383](https://github.com/go-gitea/gitea/pull/383) - * API endpoints for org teams [#370](https://github.com/go-gitea/gitea/pull/370) - * API endpoints for collaborators [#375](https://github.com/go-gitea/gitea/pull/375) - * Graceful server restart [#416](https://github.com/go-gitea/gitea/pull/416) - * Commitgraph / timeline on commits page [#428](https://github.com/go-gitea/gitea/pull/428) - * API endpoints for repo forks [#509](https://github.com/go-gitea/gitea/pull/509) - * API endpoints for releases [#510](https://github.com/go-gitea/gitea/pull/510) - * Folder jumping [#511](https://github.com/go-gitea/gitea/pull/511) - * Stars tab on profile page [#519](https://github.com/go-gitea/gitea/pull/519) - * Notification system [#523](https://github.com/go-gitea/gitea/pull/523) - * Push and pull through reverse proxy basic auth [#524](https://github.com/go-gitea/gitea/pull/524) - * Search for issues and pull requests [#530](https://github.com/go-gitea/gitea/pull/530) - * API endpoint for stargazers [#597](https://github.com/go-gitea/gitea/pull/597) - * API endpoints for subscribers [#598](https://github.com/go-gitea/gitea/pull/598) - * PID file support [#610](https://github.com/go-gitea/gitea/pull/610) - * Two factor authentication (2FA) [#630](https://github.com/go-gitea/gitea/pull/630) - * API endpoints for org users [#645](https://github.com/go-gitea/gitea/pull/645) - * Release attachments [#673](https://github.com/go-gitea/gitea/pull/673) - * OAuth2 consumer [#679](https://github.com/go-gitea/gitea/pull/679) - * Add ability to fork your own repos [#761](https://github.com/go-gitea/gitea/pull/761) - * Search repository on dashboard [#773](https://github.com/go-gitea/gitea/pull/773) - * Search bar on user profile [#787](https://github.com/go-gitea/gitea/pull/787) - * Track label changes on issue view [#788](https://github.com/go-gitea/gitea/pull/788) - * Allow using custom time format [#798](https://github.com/go-gitea/gitea/pull/798) - * Redirects for renamed repos [#807](https://github.com/go-gitea/gitea/pull/807) - * Track assignee changes on issue view [#808](https://github.com/go-gitea/gitea/pull/808) - * Track title changes on issue view [#841](https://github.com/go-gitea/gitea/pull/841) - * Archive cleanup action [#885](https://github.com/go-gitea/gitea/pull/885) - * Basic Open Graph support [#901](https://github.com/go-gitea/gitea/pull/901) - * Take back control of Git hooks [#1006](https://github.com/go-gitea/gitea/pull/1006) - * API endpoints for user repos [#1059](https://github.com/go-gitea/gitea/pull/1059) -* BUGFIXES - * Fixed counting issues for issue filters [#413](https://github.com/go-gitea/gitea/pull/413) - * Added back default settings for SSH [#500](https://github.com/go-gitea/gitea/pull/500) - * Fixed repo permissions [#513](https://github.com/go-gitea/gitea/pull/513) - * Issues cannot be created with labels [#622](https://github.com/go-gitea/gitea/pull/622) - * Add a reserved wiki paths check to the wiki [#720](https://github.com/go-gitea/gitea/pull/720) - * Update website binding MaxSize to 255 [#722](https://github.com/go-gitea/gitea/pull/722) - * User can see the private activity on public history [#818](https://github.com/go-gitea/gitea/pull/818) - * Wrong pages number which includes private repositories [#844](https://github.com/go-gitea/gitea/pull/844) - * Trim whitespaces for search keyword [#893](https://github.com/go-gitea/gitea/pull/893) - * Don't rewrite non-gitea public keys [#906](https://github.com/go-gitea/gitea/pull/906) - * Use fingerprint to check instead content for public key [#911](https://github.com/go-gitea/gitea/pull/911) - * Fix random avatars [#1147](https://github.com/go-gitea/gitea/pull/1147) -* ENHANCEMENTS - * Refactored process manager [#75](https://github.com/go-gitea/gitea/pull/75) - * Restrict rights to create new orgs [#193](https://github.com/go-gitea/gitea/pull/193) - * Added label and milestone sorting [#199](https://github.com/go-gitea/gitea/pull/199) - * Make minimum password length configurable [#223](https://github.com/go-gitea/gitea/pull/223) - * Speedup conflict checking on pull requests [#276](https://github.com/go-gitea/gitea/pull/276) - * Added button to delete merged pull request branches [#441](https://github.com/go-gitea/gitea/pull/441) - * Improved issue references within markdown [#471](https://github.com/go-gitea/gitea/pull/471) - * Dutch translation for the landingpage [#487](https://github.com/go-gitea/gitea/pull/487) - * Added Gogs migration script [#532](https://github.com/go-gitea/gitea/pull/532) - * Support a .gitea folder for issue templates [#582](https://github.com/go-gitea/gitea/pull/582) - * Enhanced diff-view coloring [#584](https://github.com/go-gitea/gitea/pull/584) - * Added ETag header to avatars [#721](https://github.com/go-gitea/gitea/pull/721) - * Added option to config to disable local path imports [#724](https://github.com/go-gitea/gitea/pull/724) - * Allow custom public files [#782](https://github.com/go-gitea/gitea/pull/782) - * Added pprof endpoint for debugging [#801](https://github.com/go-gitea/gitea/pull/801) - * Added `X-GitHub-*` headers [#809](https://github.com/go-gitea/gitea/pull/809) - * Fill SSH key title automatically [#863](https://github.com/go-gitea/gitea/pull/863) - * Display Git version on admin panel [#921](https://github.com/go-gitea/gitea/pull/921) - * Expose URL field on issue API [#982](https://github.com/go-gitea/gitea/pull/982) - * Statically compile the binaries [#985](https://github.com/go-gitea/gitea/pull/985) - * Embed build tags into version string [#1051](https://github.com/go-gitea/gitea/pull/1051) - * Gitignore support for FSharp and Clojure [#1072](https://github.com/go-gitea/gitea/pull/1072) - * Custom templates for static builds [#1087](https://github.com/go-gitea/gitea/pull/1087) - * Add ProxyFromEnvironment if none set [#1096](https://github.com/go-gitea/gitea/pull/1096) -* MISC - * Replaced remaining Gogs references - * Added more tests on various packages - * Use Crowdin for translations again - * Resolved some XSS attack vectors - * Optimized and reduced number of database queries - -## [1.0.2](https://github.com/go-gitea/gitea/releases/tag/v1.0.2) - 2017-02-21 - -* BUGFIXES - * Fixed issue counter [#882](https://github.com/go-gitea/gitea/pull/882) - * Fixed XSS vulnerability on wiki page [#955](https://github.com/go-gitea/gitea/pull/955) - * Add data dir without session to dump [#587](https://github.com/go-gitea/gitea/pull/587) - * Fixed wiki page renaming [#958](https://github.com/go-gitea/gitea/pull/958) - * Drop default console logger if not required [#960](https://github.com/go-gitea/gitea/pull/960) - * Fixed docker docs link on install page [#972](https://github.com/go-gitea/gitea/pull/972) - * Handle SetModel errors [#957](https://github.com/go-gitea/gitea/pull/957) - * Fixed XSS vulnerability on milestones [#977](https://github.com/go-gitea/gitea/pull/977) - * Fixed XSS vulnerability on alerts [#981](https://github.com/go-gitea/gitea/pull/981) - -## [1.0.1](https://github.com/go-gitea/gitea/releases/tag/v1.0.1) - 2017-01-05 - -* BUGFIXES - * Fixed localized `MIN_PASSWORD_LENGTH` [#501](https://github.com/go-gitea/gitea/pull/501) - * Fixed 500 error on organization delete [#507](https://github.com/go-gitea/gitea/pull/507) - * Ignore empty wiki repo on migrate [#544](https://github.com/go-gitea/gitea/pull/544) - * Proper check access for forking [#563](https://github.com/go-gitea/gitea/pull/563) - * Fix SSH domain on installer [#506](https://github.com/go-gitea/gitea/pull/506) - * Fix missing data rows on admin UI [#580](https://github.com/go-gitea/gitea/pull/580) - * Do not delete tags with releases by default [#579](https://github.com/go-gitea/gitea/pull/579) - * Fix missing session config data on admin UI [#578](https://github.com/go-gitea/gitea/pull/578) - * Properly show the version within footer on the UI [#593](https://github.com/go-gitea/gitea/pull/593) - -## [1.0.0](https://github.com/go-gitea/gitea/releases/tag/v1.0.0) - 2016-12-23 - -* BREAKING - * We have various changes on the API, scripting against API must be updated -* FEATURES - * Show last login for admins [#121](https://github.com/go-gitea/gitea/pull/121) -* BUGFIXES - * Fixed sender of notifications [#2](https://github.com/go-gitea/gitea/pull/2) - * Fixed keyword hijacking vulnerability [#20](https://github.com/go-gitea/gitea/pull/20) - * Fixed non-markdown readme rendering [#95](https://github.com/go-gitea/gitea/pull/95) - * Allow updating draft releases [#169](https://github.com/go-gitea/gitea/pull/169) - * GitHub API compliance [#227](https://github.com/go-gitea/gitea/pull/227) - * Added commit SHA to tag webhook [#286](https://github.com/go-gitea/gitea/issues/286) - * Secured links via noopener [#315](https://github.com/go-gitea/gitea/issues/315) - * Replace tabs with spaces on wiki title [#371](https://github.com/go-gitea/gitea/pull/371) - * Fixed vulnerability on labels and releases [#409](https://github.com/go-gitea/gitea/pull/409) - * Fixed issue comment API [#449](https://github.com/go-gitea/gitea/pull/449) -* ENHANCEMENTS - * Use proper import path for libravatar [#3](https://github.com/go-gitea/gitea/pull/3) - * Integrated DroneCI for tests and builds [#24](https://github.com/go-gitea/gitea/issues/24) - * Integrated dependency manager [#29](https://github.com/go-gitea/gitea/issues/29) - * Embedded bindata optionally [#30](https://github.com/go-gitea/gitea/issues/30) - * Integrated pagination for releases [#73](https://github.com/go-gitea/gitea/pull/73) - * Autogenerate version on every build [#91](https://github.com/go-gitea/gitea/issues/91) - * Refactored Docker container [#104](https://github.com/go-gitea/gitea/issues/104) - * Added short-hash support for downloads [#211](https://github.com/go-gitea/gitea/issues/211) - * Display tooltip for downloads [#221](https://github.com/go-gitea/gitea/issues/221) - * Improved HTTP headers for issue attachments [#270](https://github.com/go-gitea/gitea/pull/270) - * Integrate public as bindata optionally [#293](https://github.com/go-gitea/gitea/pull/293) - * Integrate templates as bindata optionally [#314](https://github.com/go-gitea/gitea/pull/314) - * Inject more ENV variables into custom hooks [#316](https://github.com/go-gitea/gitea/issues/316) - * Correct LDAP login validation [#342](https://github.com/go-gitea/gitea/pull/342) - * Integrate conf as bindata optionally [#354](https://github.com/go-gitea/gitea/pull/354) - * Serve video files in browser [#418](https://github.com/go-gitea/gitea/pull/418) - * Configurable SSH host binding [#431](https://github.com/go-gitea/gitea/issues/431) -* MISC - * Forked from Gogs and renamed to Gitea - * Catching more errors with logs - * Fixed all linting errors - * Made the go linter entirely happy - * Really integrated vendoring +* [CHANGELOG-archived.md](CHANGELOG-archived.md) From eb24d973b036e4dddf505d8c12e905ecb1a688f9 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Fri, 19 Apr 2024 15:58:56 +0800 Subject: [PATCH 158/370] Fix project description rendering for org (#30587) Fix #30263  Co-authored-by: Giteabot <teabot@gitea.io> --- routers/web/org/projects.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go index d439b11cf9..7f78d1c830 100644 --- a/routers/web/org/projects.go +++ b/routers/web/org/projects.go @@ -104,7 +104,7 @@ func Projects(ctx *context.Context) { } for _, project := range projects { - project.RenderedContent = templates.SanitizeHTML(project.Description) // FIXME: is it right? why not render? + project.RenderedContent = templates.RenderMarkdownToHtml(ctx, project.Description) } err = shared_user.LoadHeaderCount(ctx) @@ -372,7 +372,7 @@ func ViewProject(ctx *context.Context) { } } - project.RenderedContent = templates.SanitizeHTML(project.Description) // FIXME: is it right? why not render? + project.RenderedContent = templates.RenderMarkdownToHtml(ctx, project.Description) ctx.Data["LinkedPRs"] = linkedPrsMap ctx.Data["PageIsViewProjects"] = true ctx.Data["CanWriteProjects"] = canWriteProjects(ctx) From f60e1a1af25154160f08b85eb159c930b340df8b Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Fri, 19 Apr 2024 21:43:56 +0800 Subject: [PATCH 159/370] Fix HEAD method for robots.txt (#30603) Fix #30601 --- routers/web/web.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/web/web.go b/routers/web/web.go index a6a4c1d987..8fa24a2824 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -258,7 +258,7 @@ func Routes() *web.Route { routes.Get("/metrics", append(mid, Metrics)...) } - routes.Get("/robots.txt", append(mid, misc.RobotsTxt)...) + routes.Methods("GET,HEAD", "/robots.txt", append(mid, misc.RobotsTxt)...) routes.Get("/ssh_info", misc.SSHInfo) routes.Get("/api/healthz", healthcheck.Check) From 53cf46cae7475befa2dde554bbd9147e436072b9 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Fri, 19 Apr 2024 22:41:03 +0800 Subject: [PATCH 160/370] Fix commit file status parser (#30602) Try to fix #30492 --- modules/git/commit.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/git/commit.go b/modules/git/commit.go index 5f442b0e1a..d96cef37c8 100644 --- a/modules/git/commit.go +++ b/modules/git/commit.go @@ -468,7 +468,7 @@ func parseCommitFileStatus(fileStatus *CommitFileStatus, stdout io.Reader) { _, _ = rd.Discard(1) } for { - modifier, err := rd.ReadSlice('\x00') + modifier, err := rd.ReadString('\x00') if err != nil { if err != io.EOF { log.Error("Unexpected error whilst reading from git log --name-status. Error: %v", err) From cb6814adad4dc81a683b50826a211ce7bce731d7 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Sat, 20 Apr 2024 09:35:29 +0900 Subject: [PATCH 161/370] Use action user as the trigger user of schedules (#30581) Follow https://github.com/go-gitea/gitea/pull/30357 When user push to default branch, the schedule trigger user will be the user. When disable then enable action units in settings, the schedule trigger user will be action user. When repo is a mirror, the schedule trigger user will be action user. ( before it will return error, fixed by #30357) As scheduled job is a cron, the trigger user should be action user from Gitea, not a real user. --------- Co-authored-by: Giteabot <teabot@gitea.io> --- services/actions/notifier_helper.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index c48886a824..6fb6421887 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -78,6 +78,11 @@ func newNotifyInput(repo *repo_model.Repository, doer *user_model.User, event we } } +func newNotifyInputForSchedules(repo *repo_model.Repository) *notifyInput { + // the doer here will be ignored as we force using action user when handling schedules + return newNotifyInput(repo, user_model.NewActionsUser(), webhook_module.HookEventSchedule) +} + func (input *notifyInput) WithDoer(doer *user_model.User) *notifyInput { input.Doer = doer return input @@ -485,7 +490,7 @@ func handleSchedules( RepoID: input.Repo.ID, OwnerID: input.Repo.OwnerID, WorkflowID: dwf.EntryName, - TriggerUserID: input.Doer.ID, + TriggerUserID: user_model.ActionsUserID, Ref: ref, CommitSHA: commit.ID.String(), Event: input.Event, @@ -527,7 +532,7 @@ func DetectAndHandleSchedules(ctx context.Context, repo *repo_model.Repository) // We need a notifyInput to call handleSchedules // if repo is a mirror, commit author maybe an external user, // so we use action user as the Doer of the notifyInput - notifyInput := newNotifyInput(repo, user_model.NewActionsUser(), webhook_module.HookEventSchedule) + notifyInput := newNotifyInputForSchedules(repo) return handleSchedules(ctx, scheduleWorkflows, commit, notifyInput, repo.DefaultBranch) } From 89e39872fff39797107acafb984dc2dc3ec3dd6a Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sat, 20 Apr 2024 09:15:14 +0800 Subject: [PATCH 162/370] Fix links in PyPI Simple Repository API page (#30594) Thanks to @Zottelchen for looking into problem and proposing the fix. Ref: https://github.com/astral-sh/uv/issues/3017 , https://peps.python.org/pep-0503/ This PR's change is from Zottelchen's work. And I by the way rename the `$p` to `$pd` because `p` is used as "package" in code, while `pd` is used as "package description". ---- Co-authored-by: Zottelchen --- templates/api/packages/pypi/simple.tmpl | 5 +++-- tests/integration/api_packages_pypi_test.go | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/templates/api/packages/pypi/simple.tmpl b/templates/api/packages/pypi/simple.tmpl index 77cb035600..85aa730c72 100644 --- a/templates/api/packages/pypi/simple.tmpl +++ b/templates/api/packages/pypi/simple.tmpl @@ -4,11 +4,12 @@ <title>Links for {{.PackageDescriptor.Package.Name}}</title> </head> <body> + {{- /* PEP 503 – Simple Repository API: https://peps.python.org/pep-0503/ */ -}} <h1>Links for {{.PackageDescriptor.Package.Name}}</h1> {{range .PackageDescriptors}} - {{$p := .}} + {{$pd := .}} {{range .Files}} - <a href="{{$.RegistryURL}}/files/{{$p.Package.LowerName}}/{{$p.Version.Version}}/{{.File.Name}}#sha256-{{.Blob.HashSHA256}}"{{if $p.Metadata.RequiresPython}} data-requires-python="{{$p.Metadata.RequiresPython}}"{{end}}>{{.File.Name}}</a><br> + <a href="{{$.RegistryURL}}/files/{{$pd.Package.LowerName}}/{{$pd.Version.Version}}/{{.File.Name}}#sha256={{.Blob.HashSHA256}}"{{if $pd.Metadata.RequiresPython}} data-requires-python="{{$pd.Metadata.RequiresPython}}"{{end}}>{{.File.Name}}</a><br> {{end}} {{end}} </body> diff --git a/tests/integration/api_packages_pypi_test.go b/tests/integration/api_packages_pypi_test.go index a090b31e20..e973f6a52a 100644 --- a/tests/integration/api_packages_pypi_test.go +++ b/tests/integration/api_packages_pypi_test.go @@ -164,7 +164,7 @@ func TestPackagePyPI(t *testing.T) { nodes := htmlDoc.doc.Find("a").Nodes assert.Len(t, nodes, 2) - hrefMatcher := regexp.MustCompile(fmt.Sprintf(`%s/files/%s/%s/test\..+#sha256-%s`, root, regexp.QuoteMeta(packageName), regexp.QuoteMeta(packageVersion), hashSHA256)) + hrefMatcher := regexp.MustCompile(fmt.Sprintf(`%s/files/%s/%s/test\..+#sha256=%s`, root, regexp.QuoteMeta(packageName), regexp.QuoteMeta(packageVersion), hashSHA256)) for _, a := range nodes { for _, att := range a.Attr { From 48d4580dd5e975de2e8207bb9b9a2f258711d38c Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sat, 20 Apr 2024 11:15:04 +0800 Subject: [PATCH 163/370] Clarify permission "HasAccess" behavior (#30585) Follow #30495 "HasAccess" behavior wasn't clear, to make it clear: * Use a new name `HasAnyUnitAccess`, it will be easier to review related code and permission problems. * Separate everyone access mode to a separate field, then all calls to HasAccess are reverted to old behavior before #30495. * Add new tests. --------- Co-authored-by: Giteabot <teabot@gitea.io> --- models/org_team.go | 4 +- models/perm/access/access_test.go | 8 ++-- models/perm/access/repo_permission.go | 56 ++++++++++++++-------- models/perm/access/repo_permission_test.go | 44 +++++++++++++++-- routers/api/v1/api.go | 4 +- routers/api/v1/repo/repo.go | 2 +- routers/web/user/package.go | 4 +- services/context/repo.go | 3 +- services/convert/package.go | 2 +- services/repository/delete.go | 2 +- services/repository/transfer.go | 2 +- services/repository/transfer_test.go | 4 +- tests/integration/api_repo_test.go | 2 +- 13 files changed, 96 insertions(+), 41 deletions(-) diff --git a/models/org_team.go b/models/org_team.go index aecf0d80fd..b6908478c7 100644 --- a/models/org_team.go +++ b/models/org_team.go @@ -118,7 +118,7 @@ func removeAllRepositories(ctx context.Context, t *organization.Team) (err error // Remove watches from all users and now unaccessible repos for _, user := range t.Members { - has, err := access_model.HasAccess(ctx, user.ID, repo) + has, err := access_model.HasAnyUnitAccess(ctx, user.ID, repo) if err != nil { return err } else if has { @@ -544,7 +544,7 @@ func ReconsiderRepoIssuesAssignee(ctx context.Context, repo *repo_model.Reposito } func ReconsiderWatches(ctx context.Context, repo *repo_model.Repository, user *user_model.User) error { - if has, err := access_model.HasAccess(ctx, user.ID, repo); err != nil || has { + if has, err := access_model.HasAnyUnitAccess(ctx, user.ID, repo); err != nil || has { return err } if err := repo_model.WatchRepo(ctx, user, repo, false); err != nil { diff --git a/models/perm/access/access_test.go b/models/perm/access/access_test.go index 79b131fe89..51d625707c 100644 --- a/models/perm/access/access_test.go +++ b/models/perm/access/access_test.go @@ -79,17 +79,17 @@ func TestHasAccess(t *testing.T) { repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) assert.True(t, repo2.IsPrivate) - has, err := access_model.HasAccess(db.DefaultContext, user1.ID, repo1) + has, err := access_model.HasAnyUnitAccess(db.DefaultContext, user1.ID, repo1) assert.NoError(t, err) assert.True(t, has) - _, err = access_model.HasAccess(db.DefaultContext, user1.ID, repo2) + _, err = access_model.HasAnyUnitAccess(db.DefaultContext, user1.ID, repo2) assert.NoError(t, err) - _, err = access_model.HasAccess(db.DefaultContext, user2.ID, repo1) + _, err = access_model.HasAnyUnitAccess(db.DefaultContext, user2.ID, repo1) assert.NoError(t, err) - _, err = access_model.HasAccess(db.DefaultContext, user2.ID, repo2) + _, err = access_model.HasAnyUnitAccess(db.DefaultContext, user2.ID, repo2) assert.NoError(t, err) } diff --git a/models/perm/access/repo_permission.go b/models/perm/access/repo_permission.go index 9cce95b776..0ed116a132 100644 --- a/models/perm/access/repo_permission.go +++ b/models/perm/access/repo_permission.go @@ -24,6 +24,8 @@ type Permission struct { units []*repo_model.RepoUnit unitsMode map[unit.Type]perm_model.AccessMode + + everyoneAccessMode map[unit.Type]perm_model.AccessMode } // IsOwner returns true if current user is the owner of repository. @@ -36,9 +38,24 @@ func (p *Permission) IsAdmin() bool { return p.AccessMode >= perm_model.AccessModeAdmin } -// HasAccess returns true if the current user might have at least read access to any unit of this repository -func (p *Permission) HasAccess() bool { - return len(p.unitsMode) > 0 || p.AccessMode >= perm_model.AccessModeRead +// HasAnyUnitAccess returns true if the user might have at least one access mode to any unit of this repository. +// It doesn't count the "everyone access mode". +func (p *Permission) HasAnyUnitAccess() bool { + for _, v := range p.unitsMode { + if v >= perm_model.AccessModeRead { + return true + } + } + return p.AccessMode >= perm_model.AccessModeRead +} + +func (p *Permission) HasAnyUnitAccessOrEveryoneAccess() bool { + for _, v := range p.everyoneAccessMode { + if v >= perm_model.AccessModeRead { + return true + } + } + return p.HasAnyUnitAccess() } // HasUnits returns true if the permission contains attached units @@ -56,16 +73,16 @@ func (p *Permission) GetFirstUnitRepoID() int64 { } // UnitAccessMode returns current user access mode to the specify unit of the repository +// It also considers "everyone access mode" func (p *Permission) UnitAccessMode(unitType unit.Type) perm_model.AccessMode { - if p.unitsMode != nil { - // if the units map contains the access mode, use it, but admin/owner mode could override it - if m, ok := p.unitsMode[unitType]; ok { - return util.Iif(p.AccessMode >= perm_model.AccessModeAdmin, p.AccessMode, m) - } + // if the units map contains the access mode, use it, but admin/owner mode could override it + if m, ok := p.unitsMode[unitType]; ok { + return util.Iif(p.AccessMode >= perm_model.AccessModeAdmin, p.AccessMode, m) } // if the units map does not contain the access mode, return the default access mode if the unit exists + unitDefaultAccessMode := max(p.AccessMode, p.everyoneAccessMode[unitType]) hasUnit := slices.ContainsFunc(p.units, func(u *repo_model.RepoUnit) bool { return u.Type == unitType }) - return util.Iif(hasUnit, p.AccessMode, perm_model.AccessModeNone) + return util.Iif(hasUnit, unitDefaultAccessMode, perm_model.AccessModeNone) } func (p *Permission) SetUnitsWithDefaultAccessMode(units []*repo_model.RepoUnit, mode perm_model.AccessMode) { @@ -159,14 +176,15 @@ func (p *Permission) LogString() string { } func applyEveryoneRepoPermission(user *user_model.User, perm *Permission) { - if user != nil && user.ID > 0 { - for _, u := range perm.units { - if perm.unitsMode == nil { - perm.unitsMode = make(map[unit.Type]perm_model.AccessMode) - } - if u.EveryoneAccessMode >= perm_model.AccessModeRead && u.EveryoneAccessMode > perm.unitsMode[u.Type] { - perm.unitsMode[u.Type] = u.EveryoneAccessMode + if user == nil || user.ID <= 0 { + return + } + for _, u := range perm.units { + if u.EveryoneAccessMode >= perm_model.AccessModeRead && u.EveryoneAccessMode > perm.everyoneAccessMode[u.Type] { + if perm.everyoneAccessMode == nil { + perm.everyoneAccessMode = make(map[unit.Type]perm_model.AccessMode) } + perm.everyoneAccessMode[u.Type] = u.EveryoneAccessMode } } } @@ -373,8 +391,8 @@ func CanBeAssigned(ctx context.Context, user *user_model.User, repo *repo_model. perm.CanAccessAny(perm_model.AccessModeRead, unit.TypePullRequests), nil } -// HasAccess returns true if user has access to repo -func HasAccess(ctx context.Context, userID int64, repo *repo_model.Repository) (bool, error) { +// HasAnyUnitAccess see the comment of "perm.HasAnyUnitAccess" +func HasAnyUnitAccess(ctx context.Context, userID int64, repo *repo_model.Repository) (bool, error) { var user *user_model.User var err error if userID > 0 { @@ -387,7 +405,7 @@ func HasAccess(ctx context.Context, userID int64, repo *repo_model.Repository) ( if err != nil { return false, err } - return perm.HasAccess(), nil + return perm.HasAnyUnitAccess(), nil } // getUsersWithAccessMode returns users that have at least given access mode to the repository. diff --git a/models/perm/access/repo_permission_test.go b/models/perm/access/repo_permission_test.go index aaa53bb24f..50070c4368 100644 --- a/models/perm/access/repo_permission_test.go +++ b/models/perm/access/repo_permission_test.go @@ -14,16 +14,54 @@ import ( "github.com/stretchr/testify/assert" ) +func TestHasAnyUnitAccess(t *testing.T) { + perm := Permission{} + assert.False(t, perm.HasAnyUnitAccess()) + + perm = Permission{ + units: []*repo_model.RepoUnit{{Type: unit.TypeWiki}}, + } + assert.False(t, perm.HasAnyUnitAccess()) + assert.False(t, perm.HasAnyUnitAccessOrEveryoneAccess()) + + perm = Permission{ + units: []*repo_model.RepoUnit{{Type: unit.TypeWiki}}, + everyoneAccessMode: map[unit.Type]perm_model.AccessMode{unit.TypeIssues: perm_model.AccessModeRead}, + } + assert.False(t, perm.HasAnyUnitAccess()) + assert.True(t, perm.HasAnyUnitAccessOrEveryoneAccess()) + + perm = Permission{ + AccessMode: perm_model.AccessModeRead, + units: []*repo_model.RepoUnit{{Type: unit.TypeWiki}}, + } + assert.True(t, perm.HasAnyUnitAccess()) + + perm = Permission{ + unitsMode: map[unit.Type]perm_model.AccessMode{unit.TypeWiki: perm_model.AccessModeRead}, + } + assert.True(t, perm.HasAnyUnitAccess()) +} + func TestApplyEveryoneRepoPermission(t *testing.T) { perm := Permission{ AccessMode: perm_model.AccessModeNone, units: []*repo_model.RepoUnit{ - {Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeNone}, + {Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead}, }, } applyEveryoneRepoPermission(nil, &perm) assert.False(t, perm.CanRead(unit.TypeWiki)) + perm = Permission{ + AccessMode: perm_model.AccessModeNone, + units: []*repo_model.RepoUnit{ + {Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead}, + }, + } + applyEveryoneRepoPermission(&user_model.User{ID: 0}, &perm) + assert.False(t, perm.CanRead(unit.TypeWiki)) + perm = Permission{ AccessMode: perm_model.AccessModeNone, units: []*repo_model.RepoUnit{ @@ -40,8 +78,8 @@ func TestApplyEveryoneRepoPermission(t *testing.T) { }, } applyEveryoneRepoPermission(&user_model.User{ID: 1}, &perm) - assert.True(t, perm.CanRead(unit.TypeWiki)) - assert.False(t, perm.CanWrite(unit.TypeWiki)) // because there is no unit mode, so the everyone-mode is used as the unit's access mode + // it should work the same as "EveryoneAccessMode: none" because the default AccessMode should be applied to units + assert.True(t, perm.CanWrite(unit.TypeWiki)) perm = Permission{ units: []*repo_model.RepoUnit{ diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index f60c5f21db..5358906f27 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -218,7 +218,7 @@ func repoAssignment() func(ctx *context.APIContext) { } } - if !ctx.Repo.HasAccess() { + if !ctx.Repo.Permission.HasAnyUnitAccess() { ctx.NotFound() return } @@ -412,7 +412,7 @@ func reqRepoReader(unitType unit.Type) func(ctx *context.APIContext) { // reqAnyRepoReader user should have any permission to read repository or permissions of site admin func reqAnyRepoReader() func(ctx *context.APIContext) { return func(ctx *context.APIContext) { - if !ctx.Repo.HasAccess() && !ctx.IsUserSiteAdmin() { + if !ctx.Repo.Permission.HasAnyUnitAccess() && !ctx.IsUserSiteAdmin() { ctx.Error(http.StatusForbidden, "reqAnyRepoReader", "user should have any permission to read repository or permissions of site admin") return } diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 822e368fa8..2ac0b7ebd1 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -585,7 +585,7 @@ func GetByID(ctx *context.APIContext) { if err != nil { ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err) return - } else if !permission.HasAccess() { + } else if !permission.HasAnyUnitAccess() { ctx.NotFound() return } diff --git a/routers/web/user/package.go b/routers/web/user/package.go index 9af49406c4..2a18796687 100644 --- a/routers/web/user/package.go +++ b/routers/web/user/package.go @@ -82,7 +82,7 @@ func ListPackages(ctx *context.Context) { ctx.ServerError("GetUserRepoPermission", err) return } - repositoryAccessMap[pd.Repository.ID] = permission.HasAccess() + repositoryAccessMap[pd.Repository.ID] = permission.HasAnyUnitAccess() } hasPackages, err := packages_model.HasOwnerPackages(ctx, ctx.ContextUser.ID) @@ -276,7 +276,7 @@ func ViewPackageVersion(ctx *context.Context) { ctx.ServerError("GetUserRepoPermission", err) return } - hasRepositoryAccess = permission.HasAccess() + hasRepositoryAccess = permission.HasAnyUnitAccess() } ctx.Data["HasRepositoryAccess"] = hasRepositoryAccess diff --git a/services/context/repo.go b/services/context/repo.go index 1f4c698afc..b17f99eb17 100644 --- a/services/context/repo.go +++ b/services/context/repo.go @@ -374,8 +374,7 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) { return } - // Check access. - if !ctx.Repo.Permission.HasAccess() { + if !ctx.Repo.Permission.HasAnyUnitAccessOrEveryoneAccess() { if ctx.FormString("go-get") == "1" { EarlyResponseForGoGetMeta(ctx) return diff --git a/services/convert/package.go b/services/convert/package.go index b5fca21a3c..b27992bea9 100644 --- a/services/convert/package.go +++ b/services/convert/package.go @@ -21,7 +21,7 @@ func ToPackage(ctx context.Context, pd *packages.PackageDescriptor, doer *user_m return nil, err } - if permission.HasAccess() { + if permission.HasAnyUnitAccess() { repo = ToRepo(ctx, pd.Repository, permission) } } diff --git a/services/repository/delete.go b/services/repository/delete.go index 7c7dfe2ddd..cd779b05c3 100644 --- a/services/repository/delete.go +++ b/services/repository/delete.go @@ -374,7 +374,7 @@ func removeRepositoryFromTeam(ctx context.Context, t *organization.Team, repo *r return fmt.Errorf("GetTeamMembers: %w", err) } for _, member := range teamMembers { - has, err := access_model.HasAccess(ctx, member.ID, repo) + has, err := access_model.HasAnyUnitAccess(ctx, member.ID, repo) if err != nil { return err } else if has { diff --git a/services/repository/transfer.go b/services/repository/transfer.go index 83d3032188..3d0bce18d0 100644 --- a/services/repository/transfer.go +++ b/services/repository/transfer.go @@ -387,7 +387,7 @@ func StartRepositoryTransfer(ctx context.Context, doer, newOwner *user_model.Use } // In case the new owner would not have sufficient access to the repo, give access rights for read - hasAccess, err := access_model.HasAccess(ctx, newOwner.ID, repo) + hasAccess, err := access_model.HasAnyUnitAccess(ctx, newOwner.ID, repo) if err != nil { return err } diff --git a/services/repository/transfer_test.go b/services/repository/transfer_test.go index c3f03d6638..67799eddcc 100644 --- a/services/repository/transfer_test.go +++ b/services/repository/transfer_test.go @@ -67,13 +67,13 @@ func TestStartRepositoryTransferSetPermission(t *testing.T) { repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) repo.Owner = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) - hasAccess, err := access_model.HasAccess(db.DefaultContext, recipient.ID, repo) + hasAccess, err := access_model.HasAnyUnitAccess(db.DefaultContext, recipient.ID, repo) assert.NoError(t, err) assert.False(t, hasAccess) assert.NoError(t, StartRepositoryTransfer(db.DefaultContext, doer, recipient, repo, nil)) - hasAccess, err = access_model.HasAccess(db.DefaultContext, recipient.ID, repo) + hasAccess, err = access_model.HasAnyUnitAccess(db.DefaultContext, recipient.ID, repo) assert.NoError(t, err) assert.True(t, hasAccess) diff --git a/tests/integration/api_repo_test.go b/tests/integration/api_repo_test.go index 481732f8df..bc2720d51e 100644 --- a/tests/integration/api_repo_test.go +++ b/tests/integration/api_repo_test.go @@ -222,7 +222,7 @@ func TestAPISearchRepo(t *testing.T) { assert.Len(t, repoNames, expected.count) for _, repo := range body.Data { r := getRepo(t, repo.ID) - hasAccess, err := access_model.HasAccess(db.DefaultContext, userID, r) + hasAccess, err := access_model.HasAnyUnitAccess(db.DefaultContext, userID, r) assert.NoError(t, err, "Error when checking if User: %d has access to %s: %v", userID, repo.FullName, err) assert.True(t, hasAccess, "User: %d does not have access to %s", userID, repo.FullName) From b06aac40e6552b0ce1f7b8a92c977fcc27566f68 Mon Sep 17 00:00:00 2001 From: KN4CK3R <admin@oldschoolhack.me> Date: Sat, 20 Apr 2024 13:07:00 +0200 Subject: [PATCH 164/370] Fix package list performance (#30520) Fixes #28255 The new query uses the id field to sort by "newer". This most not be correct (usually it is) but it's faster (see #28255). If someone has a better idea, please propose changes. Co-authored-by: Giteabot <teabot@gitea.io> --- models/packages/package_version.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/models/packages/package_version.go b/models/packages/package_version.go index 505dbaa0a5..278e8e3a86 100644 --- a/models/packages/package_version.go +++ b/models/packages/package_version.go @@ -287,9 +287,10 @@ func (opts *PackageSearchOptions) configureOrderBy(e db.Engine) { // SearchVersions gets all versions of packages matching the search options func SearchVersions(ctx context.Context, opts *PackageSearchOptions) ([]*PackageVersion, int64, error) { sess := db.GetEngine(ctx). - Where(opts.ToConds()). + Select("package_version.*"). Table("package_version"). - Join("INNER", "package", "package.id = package_version.package_id") + Join("INNER", "package", "package.id = package_version.package_id"). + Where(opts.ToConds()) opts.configureOrderBy(sess) @@ -304,19 +305,18 @@ func SearchVersions(ctx context.Context, opts *PackageSearchOptions) ([]*Package // SearchLatestVersions gets the latest version of every package matching the search options func SearchLatestVersions(ctx context.Context, opts *PackageSearchOptions) ([]*PackageVersion, int64, error) { - cond := opts.ToConds(). - And(builder.Expr("pv2.id IS NULL")) - - joinCond := builder.Expr("package_version.package_id = pv2.package_id AND (package_version.created_unix < pv2.created_unix OR (package_version.created_unix = pv2.created_unix AND package_version.id < pv2.id))") - if opts.IsInternal.Has() { - joinCond = joinCond.And(builder.Eq{"pv2.is_internal": opts.IsInternal.Value()}) - } + in := builder. + Select("MAX(package_version.id)"). + From("package_version"). + InnerJoin("package", "package.id = package_version.package_id"). + Where(opts.ToConds()). + GroupBy("package_version.package_id") sess := db.GetEngine(ctx). + Select("package_version.*"). Table("package_version"). - Join("LEFT", "package_version pv2", joinCond). Join("INNER", "package", "package.id = package_version.package_id"). - Where(cond) + Where(builder.In("package_version.id", in)) opts.configureOrderBy(sess) From 99d789e8cdccd20779d1d4d05011f0797afbe292 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Sun, 21 Apr 2024 00:26:57 +0000 Subject: [PATCH 165/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_ja-JP.ini | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index dd5e58133e..707b37170a 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -44,7 +44,7 @@ webauthn_use_twofa=携帯電話から2要素認証コードを使用する webauthn_error=セキュリティキーを読み取ることができません。 webauthn_unsupported_browser=お使いのブラウザは現在 WebAuthn をサポートしていません。 webauthn_error_unknown=不明なエラーが発生しました。 もう一度やり直してください。 -webauthn_error_insecure=WebAuthn はセキュアな接続のみをサポートしています。HTTP 経由でテストする場合は、"localhost" または "127.0.0.1" のオリジンが使用できます。 +webauthn_error_insecure=WebAuthn は安全な接続でのみ使用できます。 HTTPでのテストには "localhost" または "127.0.0.1" のオリジンが使用できます。 webauthn_error_unable_to_process=サーバーがリクエストを処理できませんでした。 webauthn_error_duplicated=このリクエストに対しては、許可されていないセキュリティキーです。 キーが未登録であることを確認してください。 webauthn_error_empty=このキーに名前を設定する必要があります。 @@ -163,21 +163,21 @@ no_results_found=見つかりません。 search=検索… type_tooltip=検索タイプ fuzzy=あいまい -fuzzy_tooltip=検索ワードに近い結果も含めます +fuzzy_tooltip=検索語におおよそ一致する結果も含めます repo_kind=リポジトリを検索... user_kind=ユーザーを検索... org_kind=組織を検索... team_kind=チームを検索… code_kind=コードを検索... -code_search_unavailable=現在コード検索は利用できません。 サイト管理者にお問い合わせください。 -code_search_by_git_grep=現在のコード検索結果は "git grep" で提供されています。 サイト管理者がリポジトリインデクサーを有効にすると、より良い結果が得られるかもしれません。 +code_search_unavailable=コード検索は現在利用できません。 サイト管理者にお問い合わせください。 +code_search_by_git_grep=現在のコード検索は "git grep" によって行われています。 サイト管理者がリポジトリインデクサーを有効にすれば、より優れた結果が得られる可能性があります。 package_kind=パッケージを検索... project_kind=プロジェクトを検索... branch_kind=ブランチを検索... commit_kind=コミットを検索... runner_kind=ランナーを検索... no_results=一致する結果が見つかりませんでした -keyword_search_unavailable=現在キーワード検索は利用できません。 サイト管理者にお問い合わせください。 +keyword_search_unavailable=キーワード検索は現在利用できません。 サイト管理者にお問い合わせください。 [aria] navbar=ナビゲーションバー @@ -212,9 +212,9 @@ string.asc=A - Z string.desc=Z - A [error] -occurred=エラーが発生しました. +occurred=エラーが発生しました report_message=Gitea のバグが疑われる場合は、<a href="https://github.com/go-gitea/gitea/issues" target="_blank">GitHub</a>でIssueを検索して、見つからなければ新しいIssueを作成してください。 -missing_csrf=不正なリクエスト: CSRFトークンが不明です +missing_csrf=不正なリクエスト: CSRFトークンがありません invalid_csrf=不正なリクエスト: CSRFトークンが無効です not_found=ターゲットが見つかりませんでした。 network_error=ネットワークエラー @@ -224,11 +224,11 @@ app_desc=自分で立てる、超簡単 Git サービス install=簡単インストール install_desc=シンプルに、プラットフォームに応じて<a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.com/installation/install-from-binary">バイナリを実行</a>したり、<a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a>で動かしたり、<a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.com/installation/install-from-package">パッケージ</a>を使うだけ。 platform=クロスプラットフォーム -platform_desc=Giteaは<a target="_blank" rel="noopener noreferrer" href="http://golang.org/">Go</a>でコンパイルできる環境ならどこでも動きます: Windows、macOS、Linux、ARM等々、好きなものを選んでください! +platform_desc=Giteaは<a target="_blank" rel="noopener noreferrer" href="http://golang.org/">Go</a>がコンパイル可能なあらゆる環境で動きます: Windows、macOS、Linux、ARMなど。 あなたの好きなものを選んでください! lightweight=軽量 -lightweight_desc=Gitea の最小動作要件は小さくて、安価な Raspberry Pi でも動きます。エネルギー消費を節約しましょう! +lightweight_desc=Gitea の最小動作要件は小さいため、安価な Raspberry Pi でも動きます。エネルギーを節約しましょう! license=オープンソース -license_desc=Go get <a target="_blank" rel="noopener noreferrer" href="https://code.gitea.io/gitea">code.gitea.io/gitea</a>! 私たちと一緒にこのプロジェクトをより良くしていくために、何か<a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea">貢献</a>してみませんか。 些細なことでも大丈夫! 積極的にお願いします! +license_desc=Go get <a target="_blank" rel="noopener noreferrer" href="https://code.gitea.io/gitea">code.gitea.io/gitea</a>! このプロジェクトをさらに向上させるため、ぜひ<a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea">貢献</a>して参加してください。 貢献者になることを恥ずかしがらないで! [install] install=インストール @@ -393,6 +393,7 @@ forgot_password_title=パスワードを忘れた forgot_password=パスワードをお忘れですか? sign_up_now=アカウントが必要ですか? 今すぐ登録しましょう。 sign_up_successful=アカウントは無事に作成されました。ようこそ! +confirmation_mail_sent_prompt_ex=新しい確認メールを <b>%s</b> に送信しました。 %s以内にメールボックスを確認し、登録手続きを完了してください。 登録メールアドレスが間違っている場合は、もういちどサインインすると変更することができます。 must_change_password=パスワードの更新 allow_password_change=ユーザーはパスワードの変更が必要 (推奨) reset_password_mail_sent_prompt=<b>%s</b> に確認メールを送信しました。 %s以内に受信トレイを確認し、アカウント回復手続きを完了してください。 @@ -402,6 +403,7 @@ prohibit_login=サインイン禁止 prohibit_login_desc=あなたのアカウントはサインインを禁止されています。 サイト管理者にお問い合わせください。 resent_limit_prompt=少し前に、あなたからアクティベーションメールが要求されています。 3分待ったのち、もう一度試してください。 has_unconfirmed_mail=こんにちは %s さん、あなたのメール アドレス (<b>%s</b>) は確認がとれていません。 確認メールを受け取っていない場合や、改めて送信したい場合は、下のボタンをクリックしてください。 +change_unconfirmed_mail_address=登録のメールアドレスが間違っている場合は、こちらで変更して新しい確認メールを再送信することができます。 resend_mail=アクティベーションメールを再送信するにはここをクリック email_not_associate=このメールアドレスは、どのアカウントにも関連付けられていません。 send_reset_mail=アカウント回復メールを送信 @@ -582,6 +584,7 @@ team_name_been_taken=チーム名が既に使用されています。 team_no_units_error=リポジトリセクションは、少なくともひとつはアクセスを許可してください。 email_been_used=メールアドレスが既に使用されています。 email_invalid=メールアドレスが不正です。 +email_domain_is_not_allowed=ユーザーのメールアドレス <b>%s</b> のドメインが、EMAIL_DOMAIN_ALLOWLIST または EMAIL_DOMAIN_BLOCKLIST に違反しています。 あなたの操作が適切なものであるか確認してください。 openid_been_used=OpenIDのアドレス "%s" は既に使用されています。 username_password_incorrect=ユーザー名またはパスワードが間違っています。 password_complexity=パスワードが複雑性の要件を満たしていません: @@ -593,6 +596,8 @@ enterred_invalid_repo_name=入力したリポジトリ名が間違っていま enterred_invalid_org_name=入力した Organization の名前が間違っています。 enterred_invalid_owner_name=新しいオーナーの名前が正しくありません。 enterred_invalid_password=入力されたパスワードが間違っています。 +unset_password=ログインユーザーはパスワードを設定していません。 +unsupported_login_type=ログインの種類がアカウントの削除に対応していません。 user_not_exist=指定されたユーザーは存在しません。 team_not_exist=チームが存在していません。 last_org_owner='Owners'チームから最後のユーザーを削除することはできません。ひとつの組織には少なくとも一人のオーナーが必要です。 @@ -707,6 +712,7 @@ cancel=キャンセル language=言語 ui=テーマ hidden_comment_types=非表示にするコメントの種類 +hidden_comment_types_description=ここでチェックを入れたコメントの種類は、イシューのページには表示されません。 たとえば「ラベル」にチェックを入れると、「{ユーザー} が {ラベル} を追加/削除」といったコメントはすべて除外されます。 hidden_comment_types.ref_tooltip=このイシューが別のイシューやコミット等から参照された、というコメント hidden_comment_types.issue_ref_tooltip=このイシューのブランチやタグへの関連付けをユーザーが変更した、というコメント comment_type_group_reference=参照 @@ -1225,6 +1231,8 @@ file_view_rendered=レンダリング表示 file_view_raw=Rawデータを見る file_permalink=パーマリンク file_too_large=このファイルは大きすぎるため、表示できません。 +code_preview_line_from_to=%[1]d 行目から %[2]d 行目 in %[3]s +code_preview_line_in=%[1]d 行目 in %[2]s invisible_runes_header=このファイルには不可視のUnicode文字が含まれています invisible_runes_description=このファイルには人間が識別できない不可視のUnicode文字が含まれており、コンピューターによって特殊な処理が行われる可能性があります。 それが意図的なものと考えられる場合は、この警告を無視して構いません。 不可視文字を表示するにはエスケープボタンを使用します。 ambiguous_runes_header=このファイルには曖昧(ambiguous)なUnicode文字が含まれています @@ -1279,6 +1287,7 @@ editor.or=または editor.cancel_lower=キャンセル editor.commit_signed_changes=署名した変更をコミット editor.commit_changes=変更をコミット +editor.add_tmpl='{ファイル名}' を追加 editor.add=%s を追加 editor.update=%s を更新 editor.delete=%s を削除 @@ -3076,12 +3085,14 @@ auths.tips=ヒント auths.tips.oauth2.general=OAuth2認証 auths.tips.oauth2.general.tip=新しいOAuth2認証を登録するときは、コールバック/リダイレクトURLは以下になります: auths.tip.oauth2_provider=OAuth2プロバイダー +auths.tip.bitbucket=新しいOAuthコンシューマーを https://bitbucket.org/account/user/{あなたのユーザー名}/oauth-consumers/new から登録し、"アカウント" に "読み取り" 権限を追加してください。 auths.tip.nextcloud=新しいOAuthコンシューマーを、インスタンスのメニュー "Settings -> Security -> OAuth 2.0 client" から登録してください。 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_new=新しいアプリケーションを https://gitlab.com/-/profile/applications から登録してください。 auths.tip.google_plus=OAuth2クライアント資格情報を、Google APIコンソール https://console.developers.google.com/ から取得してください。 +auths.tip.openid_connect=OpenID Connect DiscoveryのURL "https://{server}/.well-known/openid-configuration" をエンドポイントとして指定してください auths.tip.twitter=https://dev.twitter.com/apps へアクセスしてアプリケーションを作成し、“Allow this application to be used to Sign in with Twitter”オプションを有効にしてください。 auths.tip.discord=新しいアプリケーションを https://discordapp.com/developers/applications/me から登録してください。 auths.tip.gitea=新しいOAuthアプリケーションを登録してください。 利用ガイドは https://docs.gitea.com/development/oauth2-provider にあります From e865de1e9d65dc09797d165a51c8e705d2a86030 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Sun, 21 Apr 2024 08:53:45 +0800 Subject: [PATCH 166/370] Use maintained gziphandler (#30592) Replace #27894 --------- Co-authored-by: delvh <dev.lh@web.de> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> --- assets/go-licenses.json | 10 +++++----- go.mod | 3 +-- go.sum | 6 ++---- modules/web/handler.go | 20 +++++++++++++------- routers/web/web.go | 10 ++++++---- 5 files changed, 27 insertions(+), 22 deletions(-) diff --git a/assets/go-licenses.json b/assets/go-licenses.json index ea73182a83..db94ea0d7d 100644 --- a/assets/go-licenses.json +++ b/assets/go-licenses.json @@ -99,11 +99,6 @@ "path": "github.com/DataDog/zstd/LICENSE", "licenseText": "Simplified BSD License\n\nCopyright (c) 2016, Datadog \u003cinfo@datadoghq.com\u003e\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n * Redistributions of source code must retain the above copyright notice,\n this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n * Neither the name of the copyright holder nor the names of its contributors\n may be used to endorse or promote products derived from this software\n without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, - { - "name": "github.com/NYTimes/gziphandler", - "path": "github.com/NYTimes/gziphandler/LICENSE", - "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2016-2017 The New York Times Company\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" - }, { "name": "github.com/ProtonMail/go-crypto", "path": "github.com/ProtonMail/go-crypto/LICENSE", @@ -669,6 +664,11 @@ "path": "github.com/klauspost/compress/LICENSE", "licenseText": "Copyright (c) 2012 The Go Authors. All rights reserved.\nCopyright (c) 2019 Klaus Post. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n------------------\n\nFiles: gzhttp/*\n\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2016-2017 The New York Times Company\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n------------------\n\nFiles: s2/cmd/internal/readahead/*\n\nThe MIT License (MIT)\n\nCopyright (c) 2015 Klaus Post\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n---------------------\nFiles: snappy/*\nFiles: internal/snapref/*\n\nCopyright (c) 2011 The Snappy-Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n-----------------\n\nFiles: s2/cmd/internal/filepathx/*\n\nCopyright 2016 The filepathx Authors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" }, + { + "name": "github.com/klauspost/compress/gzhttp", + "path": "github.com/klauspost/compress/gzhttp/LICENSE", + "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2016-2017 The New York Times Company\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" + }, { "name": "github.com/klauspost/compress/internal/snapref", "path": "github.com/klauspost/compress/internal/snapref/LICENSE", diff --git a/go.mod b/go.mod index 1e0f1ea8f8..1e88de3011 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,6 @@ require ( gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4 github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121 github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 - github.com/NYTimes/gziphandler v1.1.1 github.com/PuerkitoBio/goquery v1.9.1 github.com/alecthomas/chroma/v2 v2.13.0 github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb @@ -67,7 +66,7 @@ require ( github.com/json-iterator/go v1.1.12 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 - github.com/klauspost/compress v1.17.7 + github.com/klauspost/compress v1.17.8 github.com/klauspost/cpuid/v2 v2.2.7 github.com/lib/pq v1.10.9 github.com/markbates/goth v1.79.0 diff --git a/go.sum b/go.sum index 864bed6677..cbf397b95c 100644 --- a/go.sum +++ b/go.sum @@ -70,8 +70,6 @@ github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBa github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= -github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/PuerkitoBio/goquery v1.9.1 h1:mTL6XjbJTZdpfL+Gwl5U2h1l9yEkJjhmlTeV9VPW7UI= @@ -500,8 +498,8 @@ github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.6/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= -github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= diff --git a/modules/web/handler.go b/modules/web/handler.go index 26b7428016..1812c664b3 100644 --- a/modules/web/handler.go +++ b/modules/web/handler.go @@ -128,6 +128,16 @@ func hasResponseBeenWritten(argsIn []reflect.Value) bool { return false } +func wrapHandlerProvider[T http.Handler](hp func(next http.Handler) T, funcInfo *routing.FuncInfo) func(next http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + h := hp(next) // this handle could be dynamically generated, so we can't use it for debug info + return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + routing.UpdateFuncInfo(req.Context(), funcInfo) + h.ServeHTTP(resp, req) + }) + } +} + // toHandlerProvider converts a handler to a handler provider // A handler provider is a function that takes a "next" http.Handler, it can be used as a middleware func toHandlerProvider(handler any) func(next http.Handler) http.Handler { @@ -138,13 +148,9 @@ func toHandlerProvider(handler any) func(next http.Handler) http.Handler { } if hp, ok := handler.(func(next http.Handler) http.Handler); ok { - return func(next http.Handler) http.Handler { - h := hp(next) // this handle could be dynamically generated, so we can't use it for debug info - return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { - routing.UpdateFuncInfo(req.Context(), funcInfo) - h.ServeHTTP(resp, req) - }) - } + return wrapHandlerProvider(hp, funcInfo) + } else if hp, ok := handler.(func(http.Handler) http.HandlerFunc); ok { + return wrapHandlerProvider(hp, funcInfo) } provider := func(next http.Handler) http.Handler { diff --git a/routers/web/web.go b/routers/web/web.go index 8fa24a2824..994e639e20 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -48,9 +48,9 @@ import ( _ "code.gitea.io/gitea/modules/session" // to registers all internal adapters "gitea.com/go-chi/captcha" - "github.com/NYTimes/gziphandler" chi_middleware "github.com/go-chi/chi/v5/middleware" "github.com/go-chi/cors" + "github.com/klauspost/compress/gzhttp" "github.com/prometheus/client_golang/prometheus" ) @@ -241,11 +241,13 @@ func Routes() *web.Route { var mid []any if setting.EnableGzip { - h, err := gziphandler.GzipHandlerWithOpts(gziphandler.MinSize(GzipMinSize)) + // random jitter is recommended by: https://pkg.go.dev/github.com/klauspost/compress/gzhttp#readme-breach-mitigation + // compression level 6 is the gzip default and a good general tradeoff between speed, CPU usage, and compression + wrapper, err := gzhttp.NewWrapper(gzhttp.RandomJitter(32, 0, false), gzhttp.MinSize(GzipMinSize), gzhttp.CompressionLevel(6)) if err != nil { - log.Fatal("GzipHandlerWithOpts failed: %v", err) + log.Fatal("gzhttp.NewWrapper failed: %v", err) } - mid = append(mid, h) + mid = append(mid, wrapper) } if setting.Service.EnableCaptcha { From f95622cddc8db24719d10794e50ae6b125e6b96e Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Mon, 22 Apr 2024 01:00:04 +0800 Subject: [PATCH 167/370] Fix issue comment form and quick-submit (#30623) 1. Rewrite initGlobalEnterQuickSubmit (by the way, remove jQuery) 2. Fix issue comment form layout --- templates/devtest/fetch-action.tmpl | 2 +- templates/repo/issue/view_content.tmpl | 48 ++++++++++++----------- templates/shared/combomarkdowneditor.tmpl | 2 +- templates/user/settings/keys_ssh.tmpl | 4 +- web_src/css/repo.css | 8 ++-- web_src/js/features/common-global.js | 7 ++-- web_src/js/features/comp/QuickSubmit.js | 4 -- 7 files changed, 37 insertions(+), 38 deletions(-) diff --git a/templates/devtest/fetch-action.tmpl b/templates/devtest/fetch-action.tmpl index 7b0bbba554..2b25e6c9c4 100644 --- a/templates/devtest/fetch-action.tmpl +++ b/templates/devtest/fetch-action.tmpl @@ -21,7 +21,7 @@ <button name="btn">submit get</button> </form> <form method="post" action="fetch-action-test?k=1" class="form-fetch-action"> - <div><textarea name="text" rows="3" class="js-quick-submit"></textarea></div> + <div><textarea name="text" rows="3"></textarea></div> <div><label><input name="check" type="checkbox"> check</label></div> <div><button name="btn">submit post</button></div> </form> diff --git a/templates/repo/issue/view_content.tmpl b/templates/repo/issue/view_content.tmpl index 06d0586683..8316df2ee1 100644 --- a/templates/repo/issue/view_content.tmpl +++ b/templates/repo/issue/view_content.tmpl @@ -85,32 +85,34 @@ {{ctx.AvatarUtils.Avatar .SignedUser 40}} </a> <div class="content"> - <form class="ui segment form form-fetch-action" id="comment-form" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/comments" method="post"> - {{template "repo/issue/comment_tab" .}} - {{.CsrfTokenHtml}} - <div class="field footer"> - <div class="text right"> - {{if and (or .HasIssuesOrPullsWritePermission .IsIssuePoster) (not .DisableStatusChange)}} - {{if .Issue.IsClosed}} - <button id="status-button" class="ui primary basic button" data-status="{{ctx.Locale.Tr "repo.issues.reopen_issue"}}" data-status-and-comment="{{ctx.Locale.Tr "repo.issues.reopen_comment_issue"}}" name="status" value="reopen"> - {{ctx.Locale.Tr "repo.issues.reopen_issue"}} - </button> - {{else}} - {{$closeTranslationKey := "repo.issues.close"}} - {{if .Issue.IsPull}} - {{$closeTranslationKey = "repo.pulls.close"}} + <div class="ui segment"> + <form class="ui form form-fetch-action" id="comment-form" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/comments" method="post"> + {{template "repo/issue/comment_tab" .}} + {{.CsrfTokenHtml}} + <div class="field footer"> + <div class="text right"> + {{if and (or .HasIssuesOrPullsWritePermission .IsIssuePoster) (not .DisableStatusChange)}} + {{if .Issue.IsClosed}} + <button id="status-button" class="ui primary basic button" data-status="{{ctx.Locale.Tr "repo.issues.reopen_issue"}}" data-status-and-comment="{{ctx.Locale.Tr "repo.issues.reopen_comment_issue"}}" name="status" value="reopen"> + {{ctx.Locale.Tr "repo.issues.reopen_issue"}} + </button> + {{else}} + {{$closeTranslationKey := "repo.issues.close"}} + {{if .Issue.IsPull}} + {{$closeTranslationKey = "repo.pulls.close"}} + {{end}} + <button id="status-button" class="ui red basic button" data-status="{{ctx.Locale.Tr $closeTranslationKey}}" data-status-and-comment="{{ctx.Locale.Tr "repo.issues.close_comment_issue"}}" name="status" value="close"> + {{ctx.Locale.Tr $closeTranslationKey}} + </button> {{end}} - <button id="status-button" class="ui red basic button" data-status="{{ctx.Locale.Tr $closeTranslationKey}}" data-status-and-comment="{{ctx.Locale.Tr "repo.issues.close_comment_issue"}}" name="status" value="close"> - {{ctx.Locale.Tr $closeTranslationKey}} - </button> {{end}} - {{end}} - <button class="ui primary button"> - {{ctx.Locale.Tr "repo.issues.create_comment"}} - </button> + <button class="ui primary button"> + {{ctx.Locale.Tr "repo.issues.create_comment"}} + </button> + </div> </div> - </div> - </form> + </form> + </div> </div> </div> {{else if .Repository.IsArchived}} diff --git a/templates/shared/combomarkdowneditor.tmpl b/templates/shared/combomarkdowneditor.tmpl index 96fcf04cef..5bb71e7cd4 100644 --- a/templates/shared/combomarkdowneditor.tmpl +++ b/templates/shared/combomarkdowneditor.tmpl @@ -45,7 +45,7 @@ Template Attributes: </div> </markdown-toolbar> <text-expander keys=": @" suffix=""> - <textarea class="markdown-text-editor js-quick-submit"{{if .TextareaName}} name="{{.TextareaName}}"{{end}}{{if .TextareaPlaceholder}} placeholder="{{.TextareaPlaceholder}}"{{end}}{{if .TextareaAriaLabel}} aria-label="{{.TextareaAriaLabel}}"{{end}}{{if .DisableAutosize}} data-disable-autosize="{{.DisableAutosize}}"{{end}}>{{.TextareaContent}}</textarea> + <textarea class="markdown-text-editor"{{if .TextareaName}} name="{{.TextareaName}}"{{end}}{{if .TextareaPlaceholder}} placeholder="{{.TextareaPlaceholder}}"{{end}}{{if .TextareaAriaLabel}} aria-label="{{.TextareaAriaLabel}}"{{end}}{{if .DisableAutosize}} data-disable-autosize="{{.DisableAutosize}}"{{end}}>{{.TextareaContent}}</textarea> </text-expander> <script> if (localStorage?.getItem('markdown-editor-monospace') === 'true') { diff --git a/templates/user/settings/keys_ssh.tmpl b/templates/user/settings/keys_ssh.tmpl index d31cc81b66..a2af1b7f82 100644 --- a/templates/user/settings/keys_ssh.tmpl +++ b/templates/user/settings/keys_ssh.tmpl @@ -16,7 +16,7 @@ </div> <div class="field {{if .Err_Content}}error{{end}}"> <label for="ssh-key-content">{{ctx.Locale.Tr "settings.key_content"}}</label> - <textarea id="ssh-key-content" name="content" class="js-quick-submit" placeholder="{{ctx.Locale.Tr "settings.key_content_ssh_placeholder"}}" required>{{.content}}</textarea> + <textarea id="ssh-key-content" name="content" placeholder="{{ctx.Locale.Tr "settings.key_content_ssh_placeholder"}}" required>{{.content}}</textarea> </div> <input name="type" type="hidden" value="ssh"> <button class="ui primary button"> @@ -84,7 +84,7 @@ </div> <div class="field"> <label for="signature">{{ctx.Locale.Tr "settings.ssh_token_signature"}}</label> - <textarea id="ssh-key-signature" name="signature" class="js-quick-submit" placeholder="{{ctx.Locale.Tr "settings.key_signature_ssh_placeholder"}}" required>{{$.signature}}</textarea> + <textarea id="ssh-key-signature" name="signature" placeholder="{{ctx.Locale.Tr "settings.key_signature_ssh_placeholder"}}" required>{{$.signature}}</textarea> </div> <input name="type" type="hidden" value="verify_ssh"> <button class="ui primary button"> diff --git a/web_src/css/repo.css b/web_src/css/repo.css index b7da9ce6e0..6884bc5b16 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -1080,8 +1080,8 @@ td .commit-summary { clear: none; } -.repository .comment.form .content .form::before, -.repository .comment.form .content .form::after { +.repository .comment.form .content .segment::before, +.repository .comment.form .content .segment::after { right: 100%; top: 20px; border: solid transparent; @@ -1092,13 +1092,13 @@ td .commit-summary { pointer-events: none; } -.repository .comment.form .content .form::before { +.repository .comment.form .content .segment::before { border-right-color: var(--color-secondary); border-width: 9px; margin-top: -9px; } -.repository .comment.form .content .form::after { +.repository .comment.form .content .segment::after { border-right-color: var(--color-box-body); border-width: 8px; margin-top: -8px; diff --git a/web_src/js/features/common-global.js b/web_src/js/features/common-global.js index e7db9b2336..a821e1b921 100644 --- a/web_src/js/features/common-global.js +++ b/web_src/js/features/common-global.js @@ -46,10 +46,11 @@ export function initFootLanguageMenu() { } export function initGlobalEnterQuickSubmit() { - $(document).on('keydown', '.js-quick-submit', (e) => { - if (((e.ctrlKey && !e.altKey) || e.metaKey) && (e.key === 'Enter')) { + document.addEventListener('keydown', (e) => { + const isQuickSubmitEnter = ((e.ctrlKey && !e.altKey) || e.metaKey) && (e.key === 'Enter'); + if (isQuickSubmitEnter && e.target.matches('textarea')) { + e.preventDefault(); handleGlobalEnterQuickSubmit(e.target); - return false; } }); } diff --git a/web_src/js/features/comp/QuickSubmit.js b/web_src/js/features/comp/QuickSubmit.js index e6d7080bcf..477b3b9e2a 100644 --- a/web_src/js/features/comp/QuickSubmit.js +++ b/web_src/js/features/comp/QuickSubmit.js @@ -9,9 +9,5 @@ export function handleGlobalEnterQuickSubmit(target) { // here use the event to trigger the submit event (instead of calling `submit()` method directly) // otherwise the `areYouSure` handler won't be executed, then there will be an annoying "confirm to leave" dialog form.dispatchEvent(new SubmitEvent('submit', {bubbles: true, cancelable: true})); - } else { - // if no form, then the editor is for an AJAX request, dispatch an event to the target, let the target's event handler to do the AJAX request. - // the 'ce-' prefix means this is a CustomEvent - target.dispatchEvent(new CustomEvent('ce-quick-submit', {bubbles: true})); } } From 9de443ced2c328d9b58a5e144a765f402aab859d Mon Sep 17 00:00:00 2001 From: Cheng <36215014+ChengenH@users.noreply.github.com> Date: Mon, 22 Apr 2024 03:44:03 +0800 Subject: [PATCH 168/370] chore: use errors.New to replace fmt.Errorf with no parameters will much better (#30621) use errors.New to replace fmt.Errorf with no parameters will much better --- cmd/admin_auth.go | 3 ++- cmd/admin_auth_oauth.go | 3 ++- cmd/admin_auth_stmp.go | 3 +-- cmd/admin_user_delete.go | 3 ++- cmd/admin_user_generate_access_token.go | 5 +++-- cmd/embedded.go | 6 +++--- cmd/manager_logging.go | 3 ++- models/auth/oauth2.go | 3 ++- models/git/lfs_lock.go | 4 ++-- models/repo_transfer.go | 3 ++- 10 files changed, 21 insertions(+), 15 deletions(-) diff --git a/cmd/admin_auth.go b/cmd/admin_auth.go index ec92e342d4..4777a92908 100644 --- a/cmd/admin_auth.go +++ b/cmd/admin_auth.go @@ -4,6 +4,7 @@ package cmd import ( + "errors" "fmt" "os" "text/tabwriter" @@ -91,7 +92,7 @@ func runListAuth(c *cli.Context) error { func runDeleteAuth(c *cli.Context) error { if !c.IsSet("id") { - return fmt.Errorf("--id flag is missing") + return errors.New("--id flag is missing") } ctx, cancel := installSignals() diff --git a/cmd/admin_auth_oauth.go b/cmd/admin_auth_oauth.go index c151c0af27..8e6239ac33 100644 --- a/cmd/admin_auth_oauth.go +++ b/cmd/admin_auth_oauth.go @@ -4,6 +4,7 @@ package cmd import ( + "errors" "fmt" "net/url" @@ -193,7 +194,7 @@ func runAddOauth(c *cli.Context) error { func runUpdateOauth(c *cli.Context) error { if !c.IsSet("id") { - return fmt.Errorf("--id flag is missing") + return errors.New("--id flag is missing") } ctx, cancel := installSignals() diff --git a/cmd/admin_auth_stmp.go b/cmd/admin_auth_stmp.go index 58a6e2ac22..d724746905 100644 --- a/cmd/admin_auth_stmp.go +++ b/cmd/admin_auth_stmp.go @@ -5,7 +5,6 @@ package cmd import ( "errors" - "fmt" "strings" auth_model "code.gitea.io/gitea/models/auth" @@ -166,7 +165,7 @@ func runAddSMTP(c *cli.Context) error { func runUpdateSMTP(c *cli.Context) error { if !c.IsSet("id") { - return fmt.Errorf("--id flag is missing") + return errors.New("--id flag is missing") } ctx, cancel := installSignals() diff --git a/cmd/admin_user_delete.go b/cmd/admin_user_delete.go index 1cbc6f7527..520557554a 100644 --- a/cmd/admin_user_delete.go +++ b/cmd/admin_user_delete.go @@ -4,6 +4,7 @@ package cmd import ( + "errors" "fmt" "strings" @@ -42,7 +43,7 @@ var microcmdUserDelete = &cli.Command{ func runDeleteUser(c *cli.Context) error { if !c.IsSet("id") && !c.IsSet("username") && !c.IsSet("email") { - return fmt.Errorf("You must provide the id, username or email of a user to delete") + return errors.New("You must provide the id, username or email of a user to delete") } ctx, cancel := installSignals() diff --git a/cmd/admin_user_generate_access_token.go b/cmd/admin_user_generate_access_token.go index 6e78939680..6c2c10494e 100644 --- a/cmd/admin_user_generate_access_token.go +++ b/cmd/admin_user_generate_access_token.go @@ -4,6 +4,7 @@ package cmd import ( + "errors" "fmt" auth_model "code.gitea.io/gitea/models/auth" @@ -42,7 +43,7 @@ var microcmdUserGenerateAccessToken = &cli.Command{ func runGenerateAccessToken(c *cli.Context) error { if !c.IsSet("username") { - return fmt.Errorf("You must provide a username to generate a token for") + return errors.New("You must provide a username to generate a token for") } ctx, cancel := installSignals() @@ -68,7 +69,7 @@ func runGenerateAccessToken(c *cli.Context) error { return err } if exist { - return fmt.Errorf("access token name has been used already") + return errors.New("access token name has been used already") } // make sure the scopes are valid diff --git a/cmd/embedded.go b/cmd/embedded.go index 71d483d11c..9f03f7be7c 100644 --- a/cmd/embedded.go +++ b/cmd/embedded.go @@ -157,9 +157,9 @@ func runViewDo(c *cli.Context) error { } if len(matchedAssetFiles) == 0 { - return fmt.Errorf("no files matched the given pattern") + return errors.New("no files matched the given pattern") } else if len(matchedAssetFiles) > 1 { - return fmt.Errorf("too many files matched the given pattern, try to be more specific") + return errors.New("too many files matched the given pattern, try to be more specific") } data, err := matchedAssetFiles[0].fs.ReadFile(matchedAssetFiles[0].name) @@ -180,7 +180,7 @@ func runExtractDo(c *cli.Context) error { } if c.NArg() == 0 { - return fmt.Errorf("a list of pattern of files to extract is mandatory (e.g. '**' for all)") + return errors.New("a list of pattern of files to extract is mandatory (e.g. '**' for all)") } destdir := "." diff --git a/cmd/manager_logging.go b/cmd/manager_logging.go index 7d34fc9ac2..c2ae25ec57 100644 --- a/cmd/manager_logging.go +++ b/cmd/manager_logging.go @@ -4,6 +4,7 @@ package cmd import ( + "errors" "fmt" "os" @@ -249,7 +250,7 @@ func runAddFileLogger(c *cli.Context) error { if c.IsSet("filename") { vals["filename"] = c.String("filename") } else { - return fmt.Errorf("filename must be set when creating a file logger") + return errors.New("filename must be set when creating a file logger") } if c.IsSet("rotate") { vals["rotate"] = c.Bool("rotate") diff --git a/models/auth/oauth2.go b/models/auth/oauth2.go index bc1bcaef63..7dca378e5d 100644 --- a/models/auth/oauth2.go +++ b/models/auth/oauth2.go @@ -8,6 +8,7 @@ import ( "crypto/sha256" "encoding/base32" "encoding/base64" + "errors" "fmt" "net" "net/url" @@ -294,7 +295,7 @@ func UpdateOAuth2Application(ctx context.Context, opts UpdateOAuth2ApplicationOp return nil, err } if app.UID != opts.UserID { - return nil, fmt.Errorf("UID mismatch") + return nil, errors.New("UID mismatch") } builtinApps := BuiltinApplications() if _, builtin := builtinApps[app.ClientID]; builtin { diff --git a/models/git/lfs_lock.go b/models/git/lfs_lock.go index 261c73032a..2f65833fe3 100644 --- a/models/git/lfs_lock.go +++ b/models/git/lfs_lock.go @@ -5,7 +5,7 @@ package git import ( "context" - "fmt" + "errors" "strings" "time" @@ -148,7 +148,7 @@ func DeleteLFSLockByID(ctx context.Context, id int64, repo *repo_model.Repositor } if !force && u.ID != lock.OwnerID { - return nil, fmt.Errorf("user doesn't own lock and force flag is not set") + return nil, errors.New("user doesn't own lock and force flag is not set") } if _, err := db.GetEngine(dbCtx).ID(id).Delete(new(LFSLock)); err != nil { diff --git a/models/repo_transfer.go b/models/repo_transfer.go index 747ec2f248..37f591f65d 100644 --- a/models/repo_transfer.go +++ b/models/repo_transfer.go @@ -5,6 +5,7 @@ package models import ( "context" + "errors" "fmt" "code.gitea.io/gitea/models/db" @@ -147,7 +148,7 @@ func DeleteRepositoryTransfer(ctx context.Context, repoID int64) error { func TestRepositoryReadyForTransfer(status repo_model.RepositoryStatus) error { switch status { case repo_model.RepositoryBeingMigrated: - return fmt.Errorf("repo is not ready, currently migrating") + return errors.New("repo is not ready, currently migrating") case repo_model.RepositoryPendingTransfer: return ErrRepoTransferInProgress{} } From 1b1b8500aea0a17e999093e65b573ce54ae080ae Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 21 Apr 2024 22:24:56 +0200 Subject: [PATCH 169/370] Fix flash on dashboard (#30572) Fixes https://github.com/go-gitea/gitea/issues/30566, regression from https://github.com/go-gitea/gitea/pull/30214. --- templates/user/dashboard/dashboard.tmpl | 2 +- web_src/css/base.css | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/templates/user/dashboard/dashboard.tmpl b/templates/user/dashboard/dashboard.tmpl index 030fd49940..415423d436 100644 --- a/templates/user/dashboard/dashboard.tmpl +++ b/templates/user/dashboard/dashboard.tmpl @@ -1,8 +1,8 @@ {{template "base/head" .}} <div role="main" aria-label="{{.Title}}" class="page-content dashboard feeds"> {{template "user/dashboard/navbar" .}} + {{template "base/alert" .}} <div class="ui container flex-container"> - {{template "base/alert" .}} <div class="flex-container-main"> {{template "user/heatmap" .}} {{template "user/dashboard/feeds" .}} diff --git a/web_src/css/base.css b/web_src/css/base.css index 831044756f..0dae25506a 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -501,6 +501,12 @@ img.ui.avatar, margin-top: calc(var(--page-spacing) - 1rem); } +/* add horizontal margin to elements that are outside top-level of .flex-container or .ui.container */ +.page-content > .flash-message { + margin-left: var(--page-margin-x); + margin-right: var(--page-margin-x); +} + .ui.form .fields.error .field textarea, .ui.form .fields.error .field select, .ui.form .fields.error .field input:not([type]), From 0606284fcfce8c98fe6f42c47c0ddf42e90ffdd1 Mon Sep 17 00:00:00 2001 From: Kemal Zebari <60799661+kemzeb@users.noreply.github.com> Date: Sun, 21 Apr 2024 14:32:12 -0700 Subject: [PATCH 170/370] Add --skip-db option to dump command (#30613) Attempts to resolve #28720. --- Note that I am not a Gitea administrator so I don't normally use the gitea CLI. Just saw this issue and wanted an opportunity to understand how this subcommand works and see if I can add this feature :^) I tested both with `--skip-db` and without and it appears to not add any database-specific files to the generated archive i.e. I don't see a `gitea-db.sql` or `gitea.db` file: ```console $ TAGS="bindata sqlite sqlite_unlock_notify" make backend Running go generate... bindata for migration already up-to-date bindata for options already up-to-date bindata for public already up-to-date bindata for templates already up-to-date $ ./gitea dump --skip-db 2024/04/20 01:16:11 ...s/setting/session.go:77:loadSessionFrom() [I] Session Service Enabled 2024/04/20 01:16:11 ...s/storage/storage.go:176:initAttachments() [I] Initialising Attachment storage with type: local 2024/04/20 01:16:11 ...les/storage/local.go:33:NewLocalStorage() [I] Creating new Local Storage at /workspaces/gitea/data/attachments 2024/04/20 01:16:11 ...s/storage/storage.go:166:initAvatars() [I] Initialising Avatar storage with type: local 2024/04/20 01:16:11 ...les/storage/local.go:33:NewLocalStorage() [I] Creating new Local Storage at /workspaces/gitea/data/avatars 2024/04/20 01:16:11 ...s/storage/storage.go:192:initRepoAvatars() [I] Initialising Repository Avatar storage with type: local 2024/04/20 01:16:11 ...les/storage/local.go:33:NewLocalStorage() [I] Creating new Local Storage at /workspaces/gitea/data/repo-avatars 2024/04/20 01:16:11 ...s/storage/storage.go:186:initLFS() [I] Initialising LFS storage with type: local 2024/04/20 01:16:11 ...les/storage/local.go:33:NewLocalStorage() [I] Creating new Local Storage at /workspaces/gitea/data/lfs 2024/04/20 01:16:11 ...s/storage/storage.go:198:initRepoArchives() [I] Initialising Repository Archive storage with type: local 2024/04/20 01:16:11 ...les/storage/local.go:33:NewLocalStorage() [I] Creating new Local Storage at /workspaces/gitea/data/repo-archive 2024/04/20 01:16:11 ...s/storage/storage.go:208:initPackages() [I] Initialising Packages storage with type: local 2024/04/20 01:16:11 ...les/storage/local.go:33:NewLocalStorage() [I] Creating new Local Storage at /workspaces/gitea/data/packages 2024/04/20 01:16:11 ...s/storage/storage.go:219:initActions() [I] Initialising Actions storage with type: local 2024/04/20 01:16:11 ...les/storage/local.go:33:NewLocalStorage() [I] Creating new Local Storage at /workspaces/gitea/data/actions_log 2024/04/20 01:16:11 ...s/storage/storage.go:223:initActions() [I] Initialising ActionsArtifacts storage with type: local 2024/04/20 01:16:11 ...les/storage/local.go:33:NewLocalStorage() [I] Creating new Local Storage at /workspaces/gitea/data/actions_artifacts 2024/04/20 01:16:11 cmd/dump.go:172:runDump() [I] Dumping local repositories... /workspaces/gitea/data/gitea-repositories 2024/04/20 01:16:11 cmd/dump.go:195:runDump() [I] Skipping database 2024/04/20 01:16:11 cmd/dump.go:229:runDump() [I] Adding custom configuration file from /workspaces/gitea/custom/conf/app.ini 2024/04/20 01:16:11 cmd/dump.go:256:runDump() [I] Packing data directory.../workspaces/gitea/data 2024/04/20 01:16:11 cmd/dump.go:335:runDump() [I] Finish dumping in file /workspaces/gitea/gitea-dump-1713575771.zip $ unzip /workspaces/gitea/gitea-dump-1713575771.zip -d example Archive: /workspaces/gitea/gitea-dump-1713575771.zip . . . $ ls example/ app.ini custom data repos $ ls example/data/ actions_artifacts actions_log avatars home indexers jwt queues repo-archive repo-avatars tmp ``` Co-authored-by: Giteabot <teabot@gitea.io> --- cmd/dump.go | 62 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/cmd/dump.go b/cmd/dump.go index da0a51d9ce..ececc80f72 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -87,6 +87,10 @@ var CmdDump = &cli.Command{ Name: "skip-index", Usage: "Skip bleve index data", }, + &cli.BoolFlag{ + Name: "skip-db", + Usage: "Skip database", + }, &cli.StringFlag{ Name: "type", Usage: fmt.Sprintf(`Dump output format, default to "zip", supported types: %s`, strings.Join(dump.SupportedOutputTypes, ", ")), @@ -185,35 +189,41 @@ func runDump(ctx *cli.Context) error { } } - tmpDir := ctx.String("tempdir") - if _, err := os.Stat(tmpDir); os.IsNotExist(err) { - fatal("Path does not exist: %s", tmpDir) - } - - dbDump, err := os.CreateTemp(tmpDir, "gitea-db.sql") - if err != nil { - fatal("Failed to create tmp file: %v", err) - } - defer func() { - _ = dbDump.Close() - if err := util.Remove(dbDump.Name()); err != nil { - log.Warn("Unable to remove temporary file: %s: Error: %v", dbDump.Name(), err) - } - }() - - targetDBType := ctx.String("database") - if len(targetDBType) > 0 && targetDBType != setting.Database.Type.String() { - log.Info("Dumping database %s => %s...", setting.Database.Type, targetDBType) + if ctx.Bool("skip-db") { + // Ensure that we don't dump the database file that may reside in setting.AppDataPath or elsewhere. + dumper.GlobalExcludeAbsPath(setting.Database.Path) + log.Info("Skipping database") } else { - log.Info("Dumping database...") - } + tmpDir := ctx.String("tempdir") + if _, err := os.Stat(tmpDir); os.IsNotExist(err) { + fatal("Path does not exist: %s", tmpDir) + } - if err := db.DumpDatabase(dbDump.Name(), targetDBType); err != nil { - fatal("Failed to dump database: %v", err) - } + dbDump, err := os.CreateTemp(tmpDir, "gitea-db.sql") + if err != nil { + fatal("Failed to create tmp file: %v", err) + } + defer func() { + _ = dbDump.Close() + if err := util.Remove(dbDump.Name()); err != nil { + log.Warn("Unable to remove temporary file: %s: Error: %v", dbDump.Name(), err) + } + }() - if err = dumper.AddFile("gitea-db.sql", dbDump.Name()); err != nil { - fatal("Failed to include gitea-db.sql: %v", err) + targetDBType := ctx.String("database") + if len(targetDBType) > 0 && targetDBType != setting.Database.Type.String() { + log.Info("Dumping database %s => %s...", setting.Database.Type, targetDBType) + } else { + log.Info("Dumping database...") + } + + if err := db.DumpDatabase(dbDump.Name(), targetDBType); err != nil { + fatal("Failed to dump database: %v", err) + } + + if err = dumper.AddFile("gitea-db.sql", dbDump.Name()); err != nil { + fatal("Failed to include gitea-db.sql: %v", err) + } } log.Info("Adding custom configuration file from %s", setting.CustomConf) From 6459c50278906893f3cbc2bf3e52eff65e739b37 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu <appleboy.tw@gmail.com> Date: Mon, 22 Apr 2024 06:19:59 +0800 Subject: [PATCH 171/370] fix(api): refactor branch and tag existence checks (#30618) - Update branch existence check to also include tag existence check - Adjust error message for branch/tag existence check ref: https://github.com/go-gitea/gitea/pull/30349 --------- Signed-off-by: appleboy <appleboy.tw@gmail.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: Giteabot <teabot@gitea.io> --- routers/api/v1/repo/pull.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index e43366ff14..dfe34f23d0 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -1082,11 +1082,10 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) } ctx.Repo.PullRequest.SameRepo = isSameRepo - log.Info("Base branch: %s", baseBranch) - log.Info("Repo path: %s", ctx.Repo.GitRepo.Path) + log.Trace("Repo path: %q, base branch: %q, head branch: %q", ctx.Repo.GitRepo.Path, baseBranch, headBranch) // Check if base branch is valid. - if !ctx.Repo.GitRepo.IsBranchExist(baseBranch) { - ctx.NotFound("IsBranchExist") + if !ctx.Repo.GitRepo.IsBranchExist(baseBranch) && !ctx.Repo.GitRepo.IsTagExist(baseBranch) { + ctx.NotFound("BaseNotExist") return nil, nil, nil, nil, "", "" } @@ -1149,7 +1148,7 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) } // Check if head branch is valid. - if !headGitRepo.IsBranchExist(headBranch) { + if !headGitRepo.IsBranchExist(headBranch) && !headGitRepo.IsTagExist(headBranch) { headGitRepo.Close() ctx.NotFound() return nil, nil, nil, nil, "", "" From 1e4867730b261352d63098b85cf53ca05867c8c2 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Mon, 22 Apr 2024 07:14:33 +0800 Subject: [PATCH 172/370] Fix dropdown text ellipsis (#30628) Follow https://github.com/go-gitea/gitea/pull/30547#discussion_r1573866519 Fix #30624 The Fomantic UI Dropdown wasn't designed to work that way, its "text" element might contain images. So the "overflow" shouldn't be added to any general dropdown text.  --- .../repo/issue/view_content/reference_issue_dialog.tmpl | 8 ++++---- web_src/css/base.css | 6 ------ 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/templates/repo/issue/view_content/reference_issue_dialog.tmpl b/templates/repo/issue/view_content/reference_issue_dialog.tmpl index f6ac4192ab..c7a471f55e 100644 --- a/templates/repo/issue/view_content/reference_issue_dialog.tmpl +++ b/templates/repo/issue/view_content/reference_issue_dialog.tmpl @@ -2,13 +2,13 @@ <div class="header"> {{ctx.Locale.Tr "repo.issues.context.reference_issue"}} </div> - <div class="content tw-text-left"> - <form class="ui form form-fetch-action" action="{{printf "%s/issues/new" .Repository.Link}}" method="post"> + <div class="content"> + <form class="ui form form-fetch-action" action="{{.Repository.Link}}/issues/new" method="post"> {{.CsrfTokenHtml}} <div class="field"> <label><strong>{{ctx.Locale.Tr "repository"}}</strong></label> <div class="ui search selection dropdown issue_reference_repository_search"> - <div class="default text">{{.Repository.FullName}}</div> + <div class="default text gt-ellipsis">{{.Repository.FullName}}</div> <div class="menu"></div> </div> </div> @@ -18,7 +18,7 @@ </div> <div class="field"> <label><strong>{{ctx.Locale.Tr "repo.issues.reference_issue.body"}}</strong></label> - <textarea name="content" class="form-control"></textarea> + <textarea name="content"></textarea> </div> <div class="text right"> <button class="ui primary button">{{ctx.Locale.Tr "repo.issues.create"}}</button> diff --git a/web_src/css/base.css b/web_src/css/base.css index 0dae25506a..ef403cd2ad 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -391,12 +391,6 @@ a.label, color: var(--color-text-light-2); } -.ui.dropdown > .text { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - /* extend fomantic style '.ui.dropdown > .text > img' to include svg.img */ .ui.dropdown > .text > .img { margin-left: 0; From f4a1cf7eab674e3c1589a7ecef015ff64e441946 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Mon, 22 Apr 2024 07:47:31 +0800 Subject: [PATCH 173/370] Fix repo home UI when there is no repo description (#30552) Fix #30502 by a new approach.  --- options/locale/locale_en-US.ini | 1 - templates/repo/home.tmpl | 25 ++++++++++++------------- tests/integration/repo_test.go | 32 +++----------------------------- web_src/css/repo.css | 14 ++------------ 4 files changed, 17 insertions(+), 55 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index c602aba53d..c7d99a85b1 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1193,7 +1193,6 @@ action.blocked_user = Cannot perform action because you are blocked by the repos download_archive = Download Repository more_operations = More Operations -no_desc = No Description quick_guide = Quick Guide clone_this_repo = Clone this repository cite_this_repo = Cite this repository diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index e18a0aec17..7b37ac1011 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -5,18 +5,10 @@ {{template "base/alert" .}} {{template "repo/code/recently_pushed_new_branches" .}} {{if and (not .HideRepoInfo) (not .IsBlame)}} - <div class="repo-description"> - <div id="repo-desc" class="gt-word-break tw-text-16"> - {{$description := .Repository.DescriptionHTML $.Context}} - {{if $description}}<span class="description">{{$description | RenderCodeBlock}}</span>{{else if .IsRepositoryAdmin}}<span class="no-description text-italic">{{ctx.Locale.Tr "repo.no_desc"}}</span>{{end}} - <a class="link" href="{{.Repository.Website}}">{{.Repository.Website}}</a> - </div> - <form class="ignore-dirty" action="{{.RepoLink}}/search" method="get"> - <div class="ui small action input"> - <input name="q" value="{{.Keyword}}" placeholder="{{ctx.Locale.Tr "search.code_kind"}}"> - {{template "shared/search/button"}} - </div> - </form> + <div class="repo-description gt-word-break"> + {{- $description := .Repository.DescriptionHTML ctx -}} + {{if $description}}{{$description | RenderCodeBlock}}{{end}} + {{if .Repository.Website}}<a href="{{.Repository.Website}}">{{.Repository.Website}}</a>{{end}} </div> <div class="tw-flex tw-items-center tw-flex-wrap tw-gap-2 tw-my-2" id="repo-topics"> {{/* it should match the code in issue-home.js */}} @@ -54,7 +46,7 @@ {{$l := Eval $n "-" 1}} {{$isHomepage := (eq $n 0)}} <div class="repo-button-row"> - <div class="tw-flex tw-items-center tw-gap-y-2"> + <div class="tw-flex tw-items-center tw-flex-wrap tw-gap-y-2"> {{template "repo/branch_dropdown" dict "root" . "ContainerClasses" "tw-mr-1"}} {{if and .CanCompareOrPull .IsViewBranch (not .Repository.IsArchived)}} {{$cmpBranch := ""}} @@ -111,6 +103,13 @@ {{- end -}} </span> {{end}} + + <form class="ignore-dirty" action="{{.RepoLink}}/search" method="get"> + <div class="ui small action input"> + <input name="q" value="{{.Keyword}}" placeholder="{{ctx.Locale.Tr "search.code_kind"}}"> + {{template "shared/search/button"}} + </div> + </form> </div> <div class="tw-flex tw-items-center"> <!-- Only show clone panel in repository home page --> diff --git a/tests/integration/repo_test.go b/tests/integration/repo_test.go index 06c55b1e8a..b967ccad1e 100644 --- a/tests/integration/repo_test.go +++ b/tests/integration/repo_test.go @@ -28,11 +28,9 @@ func TestViewRepo(t *testing.T) { resp := session.MakeRequest(t, req, http.StatusOK) htmlDoc := NewHTMLParser(t, resp.Body) - noDescription := htmlDoc.doc.Find("#repo-desc").Children() repoTopics := htmlDoc.doc.Find("#repo-topics").Children() repoSummary := htmlDoc.doc.Find(".repository-summary").Children() - assert.True(t, noDescription.HasClass("no-description")) assert.True(t, repoTopics.HasClass("repo-topic")) assert.True(t, repoSummary.HasClass("repository-menu")) @@ -177,30 +175,6 @@ func TestViewRepoWithSymlinks(t *testing.T) { assert.Equal(t, "link_link: svg octicon-file-symlink-file", items[4]) } -// TestViewAsRepoAdmin tests PR #2167 -func TestViewAsRepoAdmin(t *testing.T) { - for user, expectedNoDescription := range map[string]bool{ - "user2": true, - "user4": false, - } { - defer tests.PrepareTestEnv(t)() - - session := loginUser(t, user) - - req := NewRequest(t, "GET", "/user2/repo1.git") - resp := session.MakeRequest(t, req, http.StatusOK) - - htmlDoc := NewHTMLParser(t, resp.Body) - noDescription := htmlDoc.doc.Find("#repo-desc").Children() - repoTopics := htmlDoc.doc.Find("#repo-topics").Children() - repoSummary := htmlDoc.doc.Find(".repository-summary").Children() - - assert.Equal(t, expectedNoDescription, noDescription.HasClass("no-description")) - assert.True(t, repoTopics.HasClass("repo-topic")) - assert.True(t, repoSummary.HasClass("repository-menu")) - } -} - // TestViewFileInRepo repo description, topics and summary should not be displayed when viewing a file func TestViewFileInRepo(t *testing.T) { defer tests.PrepareTestEnv(t)() @@ -211,7 +185,7 @@ func TestViewFileInRepo(t *testing.T) { resp := session.MakeRequest(t, req, http.StatusOK) htmlDoc := NewHTMLParser(t, resp.Body) - description := htmlDoc.doc.Find("#repo-desc") + description := htmlDoc.doc.Find(".repo-description") repoTopics := htmlDoc.doc.Find("#repo-topics") repoSummary := htmlDoc.doc.Find(".repository-summary") @@ -230,7 +204,7 @@ func TestBlameFileInRepo(t *testing.T) { resp := session.MakeRequest(t, req, http.StatusOK) htmlDoc := NewHTMLParser(t, resp.Body) - description := htmlDoc.doc.Find("#repo-desc") + description := htmlDoc.doc.Find(".repo-description") repoTopics := htmlDoc.doc.Find("#repo-topics") repoSummary := htmlDoc.doc.Find(".repository-summary") @@ -249,7 +223,7 @@ func TestViewRepoDirectory(t *testing.T) { resp := session.MakeRequest(t, req, http.StatusOK) htmlDoc := NewHTMLParser(t, resp.Body) - description := htmlDoc.doc.Find("#repo-desc") + description := htmlDoc.doc.Find(".repo-description") repoTopics := htmlDoc.doc.Find("#repo-topics") repoSummary := htmlDoc.doc.Find(".repository-summary") diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 6884bc5b16..62a72abaf9 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -157,21 +157,11 @@ left: auto !important; } -.repository.file.list .repo-description { - display: flex; - justify-content: space-between; - align-items: center; - gap: 5px; +.repository .repo-description { + font-size: 16px; margin-bottom: 5px; } -@media (max-width: 767.98px) { - .repository.file.list .repo-description { - flex-direction: column; - align-items: stretch; - } -} - .commit-summary { flex: 1; overflow-wrap: anywhere; From 7cb88e9c18995f194a0db153bbe43c5c029eb23e Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Mon, 22 Apr 2024 08:13:44 +0800 Subject: [PATCH 174/370] Use correct hash for "git update-index" (#30626) --- services/repository/files/temp_repo.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/services/repository/files/temp_repo.go b/services/repository/files/temp_repo.go index 9fcd335c55..d70b1e8d54 100644 --- a/services/repository/files/temp_repo.go +++ b/services/repository/files/temp_repo.go @@ -136,14 +136,18 @@ func (t *TemporaryUploadRepository) LsFiles(filenames ...string) ([]string, erro // RemoveFilesFromIndex removes the given files from the index func (t *TemporaryUploadRepository) RemoveFilesFromIndex(filenames ...string) error { + objFmt, err := t.gitRepo.GetObjectFormat() + if err != nil { + return fmt.Errorf("unable to get object format for temporary repo: %q, error: %w", t.repo.FullName(), err) + } stdOut := new(bytes.Buffer) stdErr := new(bytes.Buffer) stdIn := new(bytes.Buffer) for _, file := range filenames { if file != "" { - stdIn.WriteString("0 0000000000000000000000000000000000000000\t") - stdIn.WriteString(file) - stdIn.WriteByte('\000') + // man git-update-index: input syntax (1): mode SP sha1 TAB path + // mode=0 means "remove from index", then hash part "does not matter as long as it is well formatted." + _, _ = fmt.Fprintf(stdIn, "0 %s\t%s\x00", objFmt.EmptyObjectID(), file) } } @@ -154,8 +158,7 @@ func (t *TemporaryUploadRepository) RemoveFilesFromIndex(filenames ...string) er Stdout: stdOut, Stderr: stdErr, }); err != nil { - log.Error("Unable to update-index for temporary repo: %s (%s) Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), t.basePath, err, stdOut.String(), stdErr.String()) - return fmt.Errorf("Unable to update-index for temporary repo: %s Error: %w\nstdout: %s\nstderr: %s", t.repo.FullName(), err, stdOut.String(), stdErr.String()) + return fmt.Errorf("unable to update-index for temporary repo: %q, error: %w\nstdout: %s\nstderr: %s", t.repo.FullName(), err, stdOut.String(), stdErr.String()) } return nil } From 31386dc2bb94346b5a1039f009021a4e2f5eb166 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Mon, 22 Apr 2024 00:25:56 +0000 Subject: [PATCH 175/370] [skip ci] Updated licenses and gitignores --- options/license/HPND-UC-export-US | 10 ++++++++++ options/license/NCL | 32 +++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 options/license/HPND-UC-export-US create mode 100644 options/license/NCL diff --git a/options/license/HPND-UC-export-US b/options/license/HPND-UC-export-US new file mode 100644 index 0000000000..015556c5f9 --- /dev/null +++ b/options/license/HPND-UC-export-US @@ -0,0 +1,10 @@ +Copyright (C) 1985, 1990 Regents of the University of California. + +Permission to use, copy, modify, and distribute this +software and its documentation for any purpose and without +fee is hereby granted, provided that the above copyright +notice appear in all copies. The University of California +makes no representations about the suitability of this +software for any purpose. It is provided "as is" without +express or implied warranty. Export of this software outside +of the United States of America may require an export license. diff --git a/options/license/NCL b/options/license/NCL new file mode 100644 index 0000000000..3bfb658c26 --- /dev/null +++ b/options/license/NCL @@ -0,0 +1,32 @@ +Copyright (c) 2004 the University Corporation for Atmospheric +Research ("UCAR"). All rights reserved. Developed by NCAR's +Computational and Information Systems Laboratory, UCAR, +www.cisl.ucar.edu. + +Redistribution and use of the Software in source and binary forms, +with or without modification, is permitted provided that the +following conditions are met: + +- Neither the names of NCAR's Computational and Information Systems +Laboratory, the University Corporation for Atmospheric Research, +nor the names of its sponsors or contributors may be used to +endorse or promote products derived from this Software without +specific prior written permission. + +- Redistributions of source code must retain the above copyright +notices, this list of conditions, and the disclaimer below. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions, and the disclaimer below in the +documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. From 0386a42f70d1026c50697b12378f5026a63182b9 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Mon, 22 Apr 2024 12:48:14 +0200 Subject: [PATCH 176/370] Hide diff stats on empty PRs (#30629) When a PR is empty, e.g. has neither additions nor deletions, we don't need to show this: <img width="125" alt="Screenshot 2024-04-21 at 23 25 38" src="https://github.com/go-gitea/gitea/assets/115237/0b987eb5-66f5-4b9b-b5aa-7e9e267e9b52"> --- templates/repo/pulls/tab_menu.tmpl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/templates/repo/pulls/tab_menu.tmpl b/templates/repo/pulls/tab_menu.tmpl index c0e48928f9..a6d058f160 100644 --- a/templates/repo/pulls/tab_menu.tmpl +++ b/templates/repo/pulls/tab_menu.tmpl @@ -15,12 +15,14 @@ {{ctx.Locale.Tr "repo.pulls.tab_files"}} <span class="ui small label">{{if .NumFiles}}{{.NumFiles}}{{else}}-{{end}}</span> </a> + {{if or .Diff.TotalAddition .Diff.TotalDeletion}} <span class="item tw-ml-auto tw-pr-0 tw-font-bold tw-flex tw-items-center tw-gap-2"> <span><span class="text green">{{if .Diff.TotalAddition}}+{{.Diff.TotalAddition}}{{end}}</span> <span class="text red">{{if .Diff.TotalDeletion}}-{{.Diff.TotalDeletion}}{{end}}</span></span> <span class="diff-stats-bar"> <div class="diff-stats-add-bar" style="width: {{Eval 100 "*" .Diff.TotalAddition "/" "(" .Diff.TotalAddition "+" .Diff.TotalDeletion "+" 0.0 ")"}}%"></div> </span> </span> + {{end}} </div> <div class="ui tabs divider"></div> </div> From aff7b7bdd285cc1fcabea774f153886e11ae9f5d Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Mon, 22 Apr 2024 13:21:06 +0200 Subject: [PATCH 177/370] Remove obsolete CSS text classes (#30576) - `.text-thin` and `.text-italic` are not present in CSS so were doing nothing and I removed them. - `.text.middle` was unused so I removed it. - `.text.italic` is replaced with `tw-italic`. - `.text.normal` had exactly one use and it wasn't even needed. - add a `muted` class to the link to `org_profile_avatar.tmpl`. --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> --- templates/org/team/members.tmpl | 2 +- templates/org/team/repositories.tmpl | 2 +- templates/org/team/sidebar.tmpl | 2 +- templates/repo/create.tmpl | 6 +++--- templates/repo/file_info.tmpl | 2 +- templates/repo/settings/collaboration.tmpl | 4 ++-- templates/repo/settings/options.tmpl | 2 +- templates/shared/user/org_profile_avatar.tmpl | 2 +- web_src/css/base.css | 16 ---------------- 9 files changed, 11 insertions(+), 27 deletions(-) diff --git a/templates/org/team/members.tmpl b/templates/org/team/members.tmpl index 5719328a27..7e9a59a6bf 100644 --- a/templates/org/team/members.tmpl +++ b/templates/org/team/members.tmpl @@ -46,7 +46,7 @@ </div> {{else}} <div class="flex-item"> - <span class="text grey italic">{{ctx.Locale.Tr "org.teams.members.none"}}</span> + <span class="text grey tw-italic">{{ctx.Locale.Tr "org.teams.members.none"}}</span> </div> {{end}} </div> diff --git a/templates/org/team/repositories.tmpl b/templates/org/team/repositories.tmpl index 98b4854eb8..f5d68ce416 100644 --- a/templates/org/team/repositories.tmpl +++ b/templates/org/team/repositories.tmpl @@ -48,7 +48,7 @@ </div> {{else}} <div class="flex-item"> - <span class="text grey italic">{{ctx.Locale.Tr "org.teams.repos.none"}}</span> + <span class="text grey tw-italic">{{ctx.Locale.Tr "org.teams.repos.none"}}</span> </div> {{end}} </div> diff --git a/templates/org/team/sidebar.tmpl b/templates/org/team/sidebar.tmpl index b9e55dd587..ac41cda716 100644 --- a/templates/org/team/sidebar.tmpl +++ b/templates/org/team/sidebar.tmpl @@ -22,7 +22,7 @@ {{if .Team.Description}} {{.Team.Description}} {{else}} - <span class="text grey italic">{{ctx.Locale.Tr "org.teams.no_desc"}}</span> + <span class="text grey tw-italic">{{ctx.Locale.Tr "org.teams.no_desc"}}</span> {{end}} </div> {{if eq .Team.LowerName "owners"}} diff --git a/templates/repo/create.tmpl b/templates/repo/create.tmpl index bcd3c16b6a..c1c8c2185e 100644 --- a/templates/repo/create.tmpl +++ b/templates/repo/create.tmpl @@ -65,7 +65,7 @@ </div> <div class="inline field"> <label>{{ctx.Locale.Tr "repo.template"}}</label> - <div id="repo_template_search" class="ui search normal selection dropdown"> + <div id="repo_template_search" class="ui search selection dropdown"> <input type="hidden" id="repo_template" name="repo_template" value="{{.repo_template}}"> <div class="default text">{{.repo_template_name}}</div> <div class="menu"> @@ -119,7 +119,7 @@ <div id="non_template"> <div class="inline field"> <label>{{ctx.Locale.Tr "repo.issue_labels"}}</label> - <div class="ui search normal selection dropdown"> + <div class="ui search selection dropdown"> <input type="hidden" name="issue_labels" value="{{.issueLabels}}"> <div class="default text">{{ctx.Locale.Tr "repo.issue_labels_helper"}}</div> <div class="menu"> @@ -135,7 +135,7 @@ <div class="inline field"> <label>.gitignore</label> - <div class="ui multiple search normal selection dropdown"> + <div class="ui multiple search selection dropdown"> <input type="hidden" name="gitignores" value="{{.gitignores}}"> <div class="default text">{{ctx.Locale.Tr "repo.repo_gitignore_helper"}}</div> <div class="menu"> diff --git a/templates/repo/file_info.tmpl b/templates/repo/file_info.tmpl index 86c613e3a1..823cf1b7d8 100644 --- a/templates/repo/file_info.tmpl +++ b/templates/repo/file_info.tmpl @@ -1,4 +1,4 @@ -<div class="file-info text grey normal tw-font-mono"> +<div class="file-info tw-font-mono"> {{if .FileIsSymlink}} <div class="file-info-entry"> {{ctx.Locale.Tr "repo.symbolic_link"}} diff --git a/templates/repo/settings/collaboration.tmpl b/templates/repo/settings/collaboration.tmpl index 2a4ec577e7..ed4d5e7eb3 100644 --- a/templates/repo/settings/collaboration.tmpl +++ b/templates/repo/settings/collaboration.tmpl @@ -29,7 +29,7 @@ </div> </div> </div> - <button class="ui red tiny button inline text-thin delete-button" data-url="{{$.Link}}/delete" data-id="{{.ID}}"> + <button class="ui red tiny button inline delete-button" data-url="{{$.Link}}/delete" data-id="{{.ID}}"> {{ctx.Locale.Tr "repo.settings.delete_collaborator"}} </button> </div> @@ -75,7 +75,7 @@ </div> {{if $allowedToChangeTeams}} <div class="flex-item-trailing" {{if .IncludesAllRepositories}} data-tooltip-content="{{ctx.Locale.Tr "repo.settings.delete_team_tip"}}"{{end}}> - <button class="ui red tiny button inline text-thin delete-button {{if .IncludesAllRepositories}}disabled{{end}}" data-url="{{$.Link}}/team/delete" data-id="{{.ID}}"> + <button class="ui red tiny button inline delete-button {{if .IncludesAllRepositories}}disabled{{end}}" data-url="{{$.Link}}/team/delete" data-id="{{.ID}}"> {{ctx.Locale.Tr "repo.settings.delete_collaborator"}} </button> </div> diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index 0cd2201c4b..390351723b 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -135,7 +135,7 @@ <form method="post" class="tw-inline-block"> {{.CsrfTokenHtml}} <input type="hidden" name="action" value="mirror-sync"> - <button class="ui primary tiny button inline text-thin">{{ctx.Locale.Tr "repo.settings.sync_mirror"}}</button> + <button class="ui primary tiny button inline">{{ctx.Locale.Tr "repo.settings.sync_mirror"}}</button> </form> </td> </tr> diff --git a/templates/shared/user/org_profile_avatar.tmpl b/templates/shared/user/org_profile_avatar.tmpl index 2ff1e40ca8..d67f133abf 100644 --- a/templates/shared/user/org_profile_avatar.tmpl +++ b/templates/shared/user/org_profile_avatar.tmpl @@ -4,7 +4,7 @@ <div class="column"> <div class="ui header tw-flex tw-items-center gt-word-break"> {{ctx.AvatarUtils.Avatar . 100}} - <span class="text thin grey"><a href="{{.HomeLink}}">{{.DisplayName}}</a></span> + <span class="text grey"><a class="muted" href="{{.HomeLink}}">{{.DisplayName}}</a></span> <span class="org-visibility"> {{if .Visibility.IsLimited}}<div class="ui medium basic horizontal label">{{ctx.Locale.Tr "org.settings.visibility.limited_shortname"}}</div>{{end}} {{if .Visibility.IsPrivate}}<div class="ui medium basic horizontal label">{{ctx.Locale.Tr "org.settings.visibility.private_shortname"}}</div>{{end}} diff --git a/web_src/css/base.css b/web_src/css/base.css index ef403cd2ad..35f1781866 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -702,14 +702,6 @@ input:-webkit-autofill:active, text-align: right !important; } -.ui .text.normal { - font-weight: var(--font-weight-normal); -} - -.ui .text.italic { - font-style: italic; -} - .ui .text.truncate { overflow-x: hidden; text-overflow: ellipsis; @@ -717,14 +709,6 @@ input:-webkit-autofill:active, display: inline-block; } -.ui .text.thin { - font-weight: var(--font-weight-normal); -} - -.ui .text.middle { - vertical-align: middle; -} - .ui .message.flash-message { text-align: center; } From 74f0c84fa4245a20ce6fb87dac1faf2aeeded2a2 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Mon, 22 Apr 2024 13:48:42 +0200 Subject: [PATCH 178/370] Enable more `revive` linter rules (#30608) Noteable additions: - `redefines-builtin-id` forbid variable names that shadow go builtins - `empty-lines` remove unnecessary empty lines that `gofumpt` does not remove for some reason - `superfluous-else` eliminate more superfluous `else` branches Rules are also sorted alphabetically and I cleaned up various parts of `.golangci.yml`. --- .golangci.yml | 55 +++++++++++-------- cmd/hook.go | 2 +- models/asymkey/gpg_key_commit_verification.go | 1 - models/db/engine.go | 1 - models/issues/review.go | 2 - models/migrations/base/db.go | 5 -- models/migrations/v1_11/v111.go | 2 - models/migrations/v1_20/v250.go | 4 +- models/migrations/v1_6/v71.go | 1 - models/migrations/v1_9/v85.go | 1 - models/organization/team.go | 3 +- models/project/board.go | 2 - models/repo/user_repo.go | 1 - models/user/user.go | 3 +- modules/auth/password/password.go | 12 ++-- modules/git/batch_reader.go | 6 +- modules/git/commit_reader.go | 3 +- modules/git/pipeline/lfs_nogogit.go | 1 - modules/git/repo_commit.go | 8 +-- modules/git/submodule.go | 1 - modules/indexer/code/bleve/bleve.go | 2 - .../issues/elasticsearch/elasticsearch.go | 1 - modules/log/event_format.go | 1 - modules/markup/markdown/markdown_test.go | 2 - modules/packages/rubygems/marshal.go | 32 +++++------ modules/process/manager_stacktraces.go | 1 - modules/repository/temp.go | 1 - modules/setting/time.go | 3 +- modules/templates/htmlrenderer.go | 5 +- modules/templates/mailer.go | 3 +- modules/util/util_test.go | 6 +- routers/api/actions/artifacts.go | 1 - routers/api/packages/alpine/alpine.go | 4 +- routers/api/packages/conan/conan.go | 4 +- routers/api/packages/conda/conda.go | 4 +- routers/api/packages/container/container.go | 6 +- routers/api/packages/cran/cran.go | 4 +- routers/api/packages/debian/debian.go | 4 +- routers/api/packages/generic/generic.go | 4 +- routers/api/packages/goproxy/goproxy.go | 4 +- routers/api/packages/nuget/nuget.go | 4 +- routers/api/packages/rpm/rpm.go | 4 +- routers/api/packages/rubygems/rubygems.go | 4 +- routers/api/v1/repo/issue.go | 1 - routers/api/v1/repo/mirror.go | 1 - routers/api/v1/repo/pull.go | 2 - routers/api/v1/repo/pull_review.go | 1 - routers/api/v1/repo/repo.go | 1 - routers/api/v1/repo/wiki.go | 1 - routers/private/hook_pre_receive.go | 1 - routers/web/repo/actions/view.go | 1 - routers/web/repo/issue.go | 4 -- routers/web/repo/pull.go | 3 - routers/web/repo/pull_review.go | 1 - routers/web/repo/view.go | 1 - services/actions/notifier_helper.go | 8 ++- services/auth/source/ldap/source_sync.go | 1 - services/context/repo.go | 2 - services/gitdiff/gitdiff.go | 9 ++- services/issue/commit.go | 9 ++- .../markup/processorhelper_codepreview.go | 9 +-- services/migrations/gitea_downloader.go | 1 - services/migrations/gitlab.go | 1 - services/mirror/mirror_pull.go | 7 +-- services/pull/merge.go | 6 +- services/pull/pull.go | 1 - services/repository/adopt.go | 1 - services/repository/contributors_graph.go | 1 - services/repository/files/update.go | 2 - services/user/delete.go | 1 - services/user/update_test.go | 6 +- services/webhook/discord.go | 2 - services/webhook/matrix.go | 1 - tests/e2e/e2e_test.go | 6 +- tests/integration/api_notification_test.go | 10 ++-- tests/integration/pull_status_test.go | 1 - 76 files changed, 133 insertions(+), 188 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 27fee20f75..238f6cb837 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,13 +1,14 @@ linters: + enable-all: false + disable-all: true + fast: false enable: - bidichk - # - deadcode # deprecated - https://github.com/golangci/golangci-lint/issues/1841 - depguard - dupl - errcheck - forbidigo - gocritic - # - gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time. - gofmt - gofumpt - gosimple @@ -17,20 +18,18 @@ linters: - nolintlint - revive - staticcheck - # - structcheck # deprecated - https://github.com/golangci/golangci-lint/issues/1841 - stylecheck - typecheck - unconvert - unused - # - varcheck # deprecated - https://github.com/golangci/golangci-lint/issues/1841 - wastedassign - enable-all: false - disable-all: true - fast: false run: timeout: 10m +output: + sort-results: true + linters-settings: stylecheck: checks: ["all", "-ST1005", "-ST1003"] @@ -47,27 +46,37 @@ linters-settings: errorCode: 1 warningCode: 1 rules: + - name: atomic + - name: bare-return - name: blank-imports + - name: constant-logical-expr - name: context-as-argument - name: context-keys-type - name: dot-imports + - name: duplicated-imports + - name: empty-lines + - name: error-naming - name: error-return - name: error-strings - - name: error-naming + - name: errorf - name: exported + - name: identical-branches - name: if-return - name: increment-decrement - - name: var-naming - - name: var-declaration + - name: indent-error-flow + - name: modifies-value-receiver - name: package-comments - name: range - name: receiver-naming + - name: redefines-builtin-id + - name: string-of-int + - name: superfluous-else - name: time-naming + - name: unconditional-recursion - name: unexported-return - - name: indent-error-flow - - name: errorf - - name: duplicated-imports - - name: modifies-value-receiver + - name: unreachable-code + - name: var-declaration + - name: var-naming gofumpt: extra-rules: true depguard: @@ -93,8 +102,8 @@ issues: max-issues-per-linter: 0 max-same-issues: 0 exclude-dirs: [node_modules, public, web_src] + exclude-case-sensitive: true exclude-rules: - # Exclude some linters from running on tests files. - path: _test\.go linters: - gocyclo @@ -112,19 +121,19 @@ issues: - path: cmd linters: - forbidigo - - linters: + - text: "webhook" + linters: - dupl - text: "webhook" - - linters: + - text: "`ID' should not be capitalized" + linters: - gocritic - text: "`ID' should not be capitalized" - - linters: + - text: "swagger" + linters: - unused - deadcode - text: "swagger" - - linters: + - text: "argument x is overwritten before first use" + linters: - staticcheck - text: "argument x is overwritten before first use" - text: "commentFormatting: put a space between `//` and comment text" linters: - gocritic diff --git a/cmd/hook.go b/cmd/hook.go index c04591d79e..2a9c25add5 100644 --- a/cmd/hook.go +++ b/cmd/hook.go @@ -465,7 +465,7 @@ func hookPrintResult(output, isCreate bool, branch, url string) { fmt.Fprintf(os.Stderr, " %s\n", url) } fmt.Fprintln(os.Stderr, "") - os.Stderr.Sync() + _ = os.Stderr.Sync() } func pushOptions() map[string]string { diff --git a/models/asymkey/gpg_key_commit_verification.go b/models/asymkey/gpg_key_commit_verification.go index 06ac31bc6f..26fad3bb3f 100644 --- a/models/asymkey/gpg_key_commit_verification.go +++ b/models/asymkey/gpg_key_commit_verification.go @@ -110,7 +110,6 @@ func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerific Reason: "gpg.error.no_committer_account", } } - } } diff --git a/models/db/engine.go b/models/db/engine.go index 26abf0b96c..25f4066ea1 100755 --- a/models/db/engine.go +++ b/models/db/engine.go @@ -227,7 +227,6 @@ func NamesToBean(names ...string) ([]any, error) { // Need to map provided names to beans... beanMap := make(map[string]any) for _, bean := range tables { - beanMap[strings.ToLower(reflect.Indirect(reflect.ValueOf(bean)).Type().Name())] = bean beanMap[strings.ToLower(x.TableName(bean))] = bean beanMap[strings.ToLower(x.TableName(bean, true))] = bean diff --git a/models/issues/review.go b/models/issues/review.go index 92764db4d1..3c6934b060 100644 --- a/models/issues/review.go +++ b/models/issues/review.go @@ -345,11 +345,9 @@ func CreateReview(ctx context.Context, opts CreateReviewOptions) (*Review, error return nil, err } } - } else if opts.ReviewerTeam != nil { review.Type = ReviewTypeRequest review.ReviewerTeamID = opts.ReviewerTeam.ID - } else { return nil, fmt.Errorf("provide either reviewer or reviewer team") } diff --git a/models/migrations/base/db.go b/models/migrations/base/db.go index 51351cc7d3..eb1c44a79e 100644 --- a/models/migrations/base/db.go +++ b/models/migrations/base/db.go @@ -177,7 +177,6 @@ func RecreateTable(sess *xorm.Session, bean any) error { log.Error("Unable to recreate uniques on table %s. Error: %v", tableName, err) return err } - case setting.Database.Type.IsMySQL(): // MySQL will drop all the constraints on the old table if _, err := sess.Exec(fmt.Sprintf("DROP TABLE `%s`", tableName)); err != nil { @@ -228,7 +227,6 @@ func RecreateTable(sess *xorm.Session, bean any) error { return err } sequenceMap[sequence] = sequenceData - } // CASCADE causes postgres to drop all the constraints on the old table @@ -293,9 +291,7 @@ func RecreateTable(sess *xorm.Session, bean any) error { return err } } - } - case setting.Database.Type.IsMSSQL(): // MSSQL will drop all the constraints on the old table if _, err := sess.Exec(fmt.Sprintf("DROP TABLE `%s`", tableName)); err != nil { @@ -308,7 +304,6 @@ func RecreateTable(sess *xorm.Session, bean any) error { log.Error("Unable to rename %s to %s. Error: %v", tempTableName, tableName, err) return err } - default: log.Fatal("Unrecognized DB") } diff --git a/models/migrations/v1_11/v111.go b/models/migrations/v1_11/v111.go index 1722792a38..ff108479a9 100644 --- a/models/migrations/v1_11/v111.go +++ b/models/migrations/v1_11/v111.go @@ -262,7 +262,6 @@ func AddBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error { for _, u := range units { var found bool for _, team := range teams { - var teamU []*TeamUnit var unitEnabled bool err = sess.Where("team_id = ?", team.ID).Find(&teamU) @@ -331,7 +330,6 @@ func AddBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error { } if !protectedBranch.EnableApprovalsWhitelist { - perm, err := getUserRepoPermission(sess, baseRepo, reviewer) if err != nil { return false, err diff --git a/models/migrations/v1_20/v250.go b/models/migrations/v1_20/v250.go index a09957b291..86388ef0b8 100644 --- a/models/migrations/v1_20/v250.go +++ b/models/migrations/v1_20/v250.go @@ -104,7 +104,7 @@ func ChangeContainerMetadataMultiArch(x *xorm.Engine) error { // Convert to new metadata format - new := &MetadataNew{ + newMetadata := &MetadataNew{ Type: old.Type, IsTagged: old.IsTagged, Platform: old.Platform, @@ -119,7 +119,7 @@ func ChangeContainerMetadataMultiArch(x *xorm.Engine) error { Manifests: manifests, } - metadataJSON, err := json.Marshal(new) + metadataJSON, err := json.Marshal(newMetadata) if err != nil { return err } diff --git a/models/migrations/v1_6/v71.go b/models/migrations/v1_6/v71.go index 4e50ca9219..586187228b 100644 --- a/models/migrations/v1_6/v71.go +++ b/models/migrations/v1_6/v71.go @@ -61,7 +61,6 @@ func AddScratchHash(x *xorm.Engine) error { if _, err := sess.ID(tfa.ID).Cols("scratch_salt, scratch_hash").Update(tfa); err != nil { return fmt.Errorf("couldn't add in scratch_hash and scratch_salt: %w", err) } - } } diff --git a/models/migrations/v1_9/v85.go b/models/migrations/v1_9/v85.go index 9419ee1aae..a23d7c5d6e 100644 --- a/models/migrations/v1_9/v85.go +++ b/models/migrations/v1_9/v85.go @@ -81,7 +81,6 @@ func HashAppToken(x *xorm.Engine) error { if _, err := sess.ID(token.ID).Cols("token_hash, token_salt, token_last_eight, sha1").Update(token); err != nil { return fmt.Errorf("couldn't add in sha1, token_hash, token_salt and token_last_eight: %w", err) } - } } diff --git a/models/organization/team.go b/models/organization/team.go index e4e83fedee..fb7f0c0493 100644 --- a/models/organization/team.go +++ b/models/organization/team.go @@ -226,9 +226,8 @@ func GetTeamIDsByNames(ctx context.Context, orgID int64, names []string, ignoreN if err != nil { if ignoreNonExistent { continue - } else { - return nil, err } + return nil, err } ids = append(ids, u.ID) } diff --git a/models/project/board.go b/models/project/board.go index 5f142a356c..7faabc52c5 100644 --- a/models/project/board.go +++ b/models/project/board.go @@ -110,13 +110,11 @@ func createBoardsForProjectsType(ctx context.Context, project *Project) error { var items []string switch project.BoardType { - case BoardTypeBugTriage: items = setting.Project.ProjectBoardBugTriageType case BoardTypeBasicKanban: items = setting.Project.ProjectBoardBasicKanbanType - case BoardTypeNone: fallthrough default: diff --git a/models/repo/user_repo.go b/models/repo/user_repo.go index 6862247657..1c5412fe7d 100644 --- a/models/repo/user_repo.go +++ b/models/repo/user_repo.go @@ -170,7 +170,6 @@ func GetReviewers(ctx context.Context, repo *Repository, doerID, posterID int64) // the owner of a private repo needs to be explicitly added. cond = cond.Or(builder.Eq{"`user`.id": repo.Owner.ID}) } - } else { // This is a "public" repository: // Any user that has read access, is a watcher or organization member can be requested to review diff --git a/models/user/user.go b/models/user/user.go index d459ec239e..7056aecab0 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -988,9 +988,8 @@ func GetUserIDsByNames(ctx context.Context, names []string, ignoreNonExistent bo if err != nil { if ignoreNonExistent { continue - } else { - return nil, err } + return nil, err } ids = append(ids, u.ID) } diff --git a/modules/auth/password/password.go b/modules/auth/password/password.go index 27074358a9..85f9780709 100644 --- a/modules/auth/password/password.go +++ b/modules/auth/password/password.go @@ -63,16 +63,16 @@ func NewComplexity() { func setupComplexity(values []string) { if len(values) != 1 || values[0] != "off" { for _, val := range values { - if complex, ok := charComplexities[val]; ok { - validChars += complex.ValidChars - requiredList = append(requiredList, complex) + if complexity, ok := charComplexities[val]; ok { + validChars += complexity.ValidChars + requiredList = append(requiredList, complexity) } } if len(requiredList) == 0 { // No valid character classes found; use all classes as default - for _, complex := range charComplexities { - validChars += complex.ValidChars - requiredList = append(requiredList, complex) + for _, complexity := range charComplexities { + validChars += complexity.ValidChars + requiredList = append(requiredList, complexity) } } } diff --git a/modules/git/batch_reader.go b/modules/git/batch_reader.go index 043dbb44bd..c988d6ab86 100644 --- a/modules/git/batch_reader.go +++ b/modules/git/batch_reader.go @@ -307,10 +307,10 @@ func ParseTreeLine(objectFormat ObjectFormat, rd *bufio.Reader, modeBuf, fnameBu // Deal with the binary hash idx = 0 - len := objectFormat.FullLength() / 2 - for idx < len { + length := objectFormat.FullLength() / 2 + for idx < length { var read int - read, err = rd.Read(shaBuf[idx:len]) + read, err = rd.Read(shaBuf[idx:length]) n += read if err != nil { return mode, fname, sha, n, err diff --git a/modules/git/commit_reader.go b/modules/git/commit_reader.go index f1f4a0e588..228bbaf314 100644 --- a/modules/git/commit_reader.go +++ b/modules/git/commit_reader.go @@ -49,9 +49,8 @@ readLoop: if len(line) > 0 && line[0] == ' ' { _, _ = signatureSB.Write(line[1:]) continue - } else { - pgpsig = false } + pgpsig = false } if !message { diff --git a/modules/git/pipeline/lfs_nogogit.go b/modules/git/pipeline/lfs_nogogit.go index 4c65249089..fe320f39f3 100644 --- a/modules/git/pipeline/lfs_nogogit.go +++ b/modules/git/pipeline/lfs_nogogit.go @@ -232,7 +232,6 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err errChan <- err break } - } }() diff --git a/modules/git/repo_commit.go b/modules/git/repo_commit.go index 44273d2253..f9168bef7e 100644 --- a/modules/git/repo_commit.go +++ b/modules/git/repo_commit.go @@ -251,18 +251,18 @@ func (repo *Repository) CommitsByFileAndRange(opts CommitsByFileAndRangeOptions) return nil, err } - len := objectFormat.FullLength() + length := objectFormat.FullLength() commits := []*Commit{} - shaline := make([]byte, len+1) + shaline := make([]byte, length+1) for { n, err := io.ReadFull(stdoutReader, shaline) - if err != nil || n < len { + if err != nil || n < length { if err == io.EOF { err = nil } return commits, err } - objectID, err := NewIDFromString(string(shaline[0:len])) + objectID, err := NewIDFromString(string(shaline[0:length])) if err != nil { return nil, err } diff --git a/modules/git/submodule.go b/modules/git/submodule.go index 37813ea4c7..b99c81582b 100644 --- a/modules/git/submodule.go +++ b/modules/git/submodule.go @@ -64,7 +64,6 @@ func getRefURL(refURL, urlPrefix, repoFullName, sshDomain string) string { // ex: git@try.gitea.io:go-gitea/gitea match := scpSyntax.FindAllStringSubmatch(refURI, -1) if len(match) > 0 { - m := match[0] refHostname := m[2] pth := m[3] diff --git a/modules/indexer/code/bleve/bleve.go b/modules/indexer/code/bleve/bleve.go index c607d780ef..bd844205a6 100644 --- a/modules/indexer/code/bleve/bleve.go +++ b/modules/indexer/code/bleve/bleve.go @@ -191,7 +191,6 @@ func (b *Indexer) addDelete(filename string, repo *repo_model.Repository, batch func (b *Indexer) Index(ctx context.Context, repo *repo_model.Repository, sha string, changes *internal.RepoChanges) error { batch := inner_bleve.NewFlushingBatch(b.inner.Indexer, maxBatchSize) if len(changes.Updates) > 0 { - // Now because of some insanity with git cat-file not immediately failing if not run in a valid git directory we need to run git rev-parse first! if err := git.EnsureValidGitRepository(ctx, repo.RepoPath()); err != nil { log.Error("Unable to open git repo: %s for %-v: %v", repo.RepoPath(), repo, err) @@ -335,7 +334,6 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int if result, err = b.inner.Indexer.Search(facetRequest); err != nil { return 0, nil, nil, err } - } languagesFacet := result.Facets["languages"] for _, term := range languagesFacet.Terms.Terms() { diff --git a/modules/indexer/issues/elasticsearch/elasticsearch.go b/modules/indexer/issues/elasticsearch/elasticsearch.go index 53b383c8d5..c7cb59f2cf 100644 --- a/modules/indexer/issues/elasticsearch/elasticsearch.go +++ b/modules/indexer/issues/elasticsearch/elasticsearch.go @@ -145,7 +145,6 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( query := elastic.NewBoolQuery() if options.Keyword != "" { - searchType := esMultiMatchTypePhrasePrefix if options.IsFuzzyKeyword { searchType = esMultiMatchTypeBestFields diff --git a/modules/log/event_format.go b/modules/log/event_format.go index 524ca3dd87..d9dbebf831 100644 --- a/modules/log/event_format.go +++ b/modules/log/event_format.go @@ -125,7 +125,6 @@ func EventFormatTextMessage(mode *WriterMode, event *Event, msgFormat string, ms if mode.Colorize { buf = append(buf, resetBytes...) } - } if flags&(Lshortfile|Llongfile) != 0 { if mode.Colorize { diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index d9b67e43af..bc6ad7fb3c 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -466,7 +466,6 @@ func TestColorPreview(t *testing.T) { res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase) assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase) assert.Equal(t, template.HTML(test.expected), res, "Unexpected result in testcase %q", test.testcase) - } negativeTests := []string{ @@ -549,7 +548,6 @@ func TestMathBlock(t *testing.T) { res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase) assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase) assert.Equal(t, template.HTML(test.expected), res, "Unexpected result in testcase %q", test.testcase) - } } diff --git a/modules/packages/rubygems/marshal.go b/modules/packages/rubygems/marshal.go index 8878dcf973..4e6a5fc5f8 100644 --- a/modules/packages/rubygems/marshal.go +++ b/modules/packages/rubygems/marshal.go @@ -147,35 +147,35 @@ func (e *MarshalEncoder) marshalIntInternal(i int64) error { return e.w.WriteByte(byte(i - 5)) } - var len int + var length int if 122 < i && i <= 0xff { - len = 1 + length = 1 } else if 0xff < i && i <= 0xffff { - len = 2 + length = 2 } else if 0xffff < i && i <= 0xffffff { - len = 3 + length = 3 } else if 0xffffff < i && i <= 0x3fffffff { - len = 4 + length = 4 } else if -0x100 <= i && i < -123 { - len = -1 + length = -1 } else if -0x10000 <= i && i < -0x100 { - len = -2 + length = -2 } else if -0x1000000 <= i && i < -0x100000 { - len = -3 + length = -3 } else if -0x40000000 <= i && i < -0x1000000 { - len = -4 + length = -4 } else { return ErrInvalidIntRange } - if err := e.w.WriteByte(byte(len)); err != nil { + if err := e.w.WriteByte(byte(length)); err != nil { return err } - if len < 0 { - len = -len + if length < 0 { + length = -length } - for c := 0; c < len; c++ { + for c := 0; c < length; c++ { if err := e.w.WriteByte(byte(i >> uint(8*c) & 0xff)); err != nil { return err } @@ -244,13 +244,13 @@ func (e *MarshalEncoder) marshalArray(arr reflect.Value) error { return err } - len := arr.Len() + length := arr.Len() - if err := e.marshalIntInternal(int64(len)); err != nil { + if err := e.marshalIntInternal(int64(length)); err != nil { return err } - for i := 0; i < len; i++ { + for i := 0; i < length; i++ { if err := e.marshal(arr.Index(i).Interface()); err != nil { return err } diff --git a/modules/process/manager_stacktraces.go b/modules/process/manager_stacktraces.go index 49bd5071f6..e260893113 100644 --- a/modules/process/manager_stacktraces.go +++ b/modules/process/manager_stacktraces.go @@ -339,7 +339,6 @@ func (pm *Manager) ProcessStacktraces(flat, noSystem bool) ([]*Process, int, int } sort.Slice(processes, after(processes)) if !flat { - var sortChildren func(process *Process) sortChildren = func(process *Process) { diff --git a/modules/repository/temp.go b/modules/repository/temp.go index 53646718e0..04faa9db3d 100644 --- a/modules/repository/temp.go +++ b/modules/repository/temp.go @@ -32,7 +32,6 @@ func CreateTemporaryPath(prefix string) (string, error) { if err != nil { log.Error("Unable to create temporary directory: %s-*.git (%v)", prefix, err) return "", fmt.Errorf("Failed to create dir %s-*.git: %w", prefix, err) - } return basePath, nil } diff --git a/modules/setting/time.go b/modules/setting/time.go index 6d2aa80f5b..39acba12ef 100644 --- a/modules/setting/time.go +++ b/modules/setting/time.go @@ -19,9 +19,8 @@ func loadTimeFrom(rootCfg ConfigProvider) { DefaultUILocation, err = time.LoadLocation(zone) if err != nil { log.Fatal("Load time zone failed: %v", err) - } else { - log.Info("Default UI Location is %v", zone) } + log.Info("Default UI Location is %v", zone) } if DefaultUILocation == nil { DefaultUILocation = time.Local diff --git a/modules/templates/htmlrenderer.go b/modules/templates/htmlrenderer.go index 40941285aa..e7e805ed30 100644 --- a/modules/templates/htmlrenderer.go +++ b/modules/templates/htmlrenderer.go @@ -138,10 +138,9 @@ func wrapTmplErrMsg(msg string) { if setting.IsProd { // in prod mode, Gitea must have correct templates to run log.Fatal("Gitea can't run with template errors: %s", msg) - } else { - // in dev mode, do not need to really exit, because the template errors could be fixed by developer soon and the templates get reloaded - log.Error("There are template errors but Gitea continues to run in dev mode: %s", msg) } + // in dev mode, do not need to really exit, because the template errors could be fixed by developer soon and the templates get reloaded + log.Error("There are template errors but Gitea continues to run in dev mode: %s", msg) } type templateErrorPrettier struct { diff --git a/modules/templates/mailer.go b/modules/templates/mailer.go index f1832cba0e..7c97e1ea89 100644 --- a/modules/templates/mailer.go +++ b/modules/templates/mailer.go @@ -84,9 +84,8 @@ func Mailer(ctx context.Context) (*texttmpl.Template, *template.Template) { if err = buildSubjectBodyTemplate(subjectTemplates, bodyTemplates, tmplName, content); err != nil { if firstRun { log.Fatal("Failed to parse mail template, err: %v", err) - } else { - log.Error("Failed to parse mail template, err: %v", err) } + log.Error("Failed to parse mail template, err: %v", err) } } } diff --git a/modules/util/util_test.go b/modules/util/util_test.go index 5c5b13d04b..de8f065cad 100644 --- a/modules/util/util_test.go +++ b/modules/util/util_test.go @@ -121,9 +121,9 @@ func Test_NormalizeEOL(t *testing.T) { } func Test_RandomInt(t *testing.T) { - int, err := CryptoRandomInt(255) - assert.True(t, int >= 0) - assert.True(t, int <= 255) + randInt, err := CryptoRandomInt(255) + assert.True(t, randInt >= 0) + assert.True(t, randInt <= 255) assert.NoError(t, err) } diff --git a/routers/api/actions/artifacts.go b/routers/api/actions/artifacts.go index d530e9cee5..8198abb8a0 100644 --- a/routers/api/actions/artifacts.go +++ b/routers/api/actions/artifacts.go @@ -144,7 +144,6 @@ func ArtifactContexter() func(next http.Handler) http.Handler { var task *actions.ActionTask if err == nil { - task, err = actions.GetTaskByID(req.Context(), tID) if err != nil { log.Error("Error runner api getting task by ID: %v", err) diff --git a/routers/api/packages/alpine/alpine.go b/routers/api/packages/alpine/alpine.go index dae9c3dfcb..5127319807 100644 --- a/routers/api/packages/alpine/alpine.go +++ b/routers/api/packages/alpine/alpine.go @@ -96,12 +96,12 @@ func UploadPackageFile(ctx *context.Context) { return } - upload, close, err := ctx.UploadStream() + upload, needToClose, err := ctx.UploadStream() if err != nil { apiError(ctx, http.StatusInternalServerError, err) return } - if close { + if needToClose { defer upload.Close() } diff --git a/routers/api/packages/conan/conan.go b/routers/api/packages/conan/conan.go index c45e085a4d..07ea3eda34 100644 --- a/routers/api/packages/conan/conan.go +++ b/routers/api/packages/conan/conan.go @@ -310,12 +310,12 @@ func uploadFile(ctx *context.Context, fileFilter container.Set[string], fileKey return } - upload, close, err := ctx.UploadStream() + upload, needToClose, err := ctx.UploadStream() if err != nil { apiError(ctx, http.StatusBadRequest, err) return } - if close { + if needToClose { defer upload.Close() } diff --git a/routers/api/packages/conda/conda.go b/routers/api/packages/conda/conda.go index 30c80fc15e..c7e4544d52 100644 --- a/routers/api/packages/conda/conda.go +++ b/routers/api/packages/conda/conda.go @@ -174,12 +174,12 @@ func EnumeratePackages(ctx *context.Context) { } func UploadPackageFile(ctx *context.Context) { - upload, close, err := ctx.UploadStream() + upload, needToClose, err := ctx.UploadStream() if err != nil { apiError(ctx, http.StatusInternalServerError, err) return } - if close { + if needToClose { defer upload.Close() } diff --git a/routers/api/packages/container/container.go b/routers/api/packages/container/container.go index e519766142..2cb16daebc 100644 --- a/routers/api/packages/container/container.go +++ b/routers/api/packages/container/container.go @@ -385,9 +385,9 @@ func EndUploadBlob(ctx *context.Context) { } return } - close := true + doClose := true defer func() { - if close { + if doClose { uploader.Close() } }() @@ -427,7 +427,7 @@ func EndUploadBlob(ctx *context.Context) { apiError(ctx, http.StatusInternalServerError, err) return } - close = false + doClose = false if err := container_service.RemoveBlobUploadByID(ctx, uploader.ID); err != nil { apiError(ctx, http.StatusInternalServerError, err) diff --git a/routers/api/packages/cran/cran.go b/routers/api/packages/cran/cran.go index 2cec75294f..f1d616724a 100644 --- a/routers/api/packages/cran/cran.go +++ b/routers/api/packages/cran/cran.go @@ -151,12 +151,12 @@ func UploadBinaryPackageFile(ctx *context.Context) { } func uploadPackageFile(ctx *context.Context, compositeKey string, properties map[string]string) { - upload, close, err := ctx.UploadStream() + upload, needToClose, err := ctx.UploadStream() if err != nil { apiError(ctx, http.StatusBadRequest, err) return } - if close { + if needToClose { defer upload.Close() } diff --git a/routers/api/packages/debian/debian.go b/routers/api/packages/debian/debian.go index 241de3ac5d..8c05476cbc 100644 --- a/routers/api/packages/debian/debian.go +++ b/routers/api/packages/debian/debian.go @@ -127,12 +127,12 @@ func UploadPackageFile(ctx *context.Context) { return } - upload, close, err := ctx.UploadStream() + upload, needToClose, err := ctx.UploadStream() if err != nil { apiError(ctx, http.StatusInternalServerError, err) return } - if close { + if needToClose { defer upload.Close() } diff --git a/routers/api/packages/generic/generic.go b/routers/api/packages/generic/generic.go index 8232931134..e66f3ee676 100644 --- a/routers/api/packages/generic/generic.go +++ b/routers/api/packages/generic/generic.go @@ -90,12 +90,12 @@ func UploadPackage(ctx *context.Context) { return } - upload, close, err := ctx.UploadStream() + upload, needToClose, err := ctx.UploadStream() if err != nil { apiError(ctx, http.StatusInternalServerError, err) return } - if close { + if needToClose { defer upload.Close() } diff --git a/routers/api/packages/goproxy/goproxy.go b/routers/api/packages/goproxy/goproxy.go index d658066bb4..56a07dbd43 100644 --- a/routers/api/packages/goproxy/goproxy.go +++ b/routers/api/packages/goproxy/goproxy.go @@ -154,12 +154,12 @@ func resolvePackage(ctx *context.Context, ownerID int64, name, version string) ( } func UploadPackage(ctx *context.Context) { - upload, close, err := ctx.UploadStream() + upload, needToClose, err := ctx.UploadStream() if err != nil { apiError(ctx, http.StatusInternalServerError, err) return } - if close { + if needToClose { defer upload.Close() } diff --git a/routers/api/packages/nuget/nuget.go b/routers/api/packages/nuget/nuget.go index 09156ece6b..26b0ae226e 100644 --- a/routers/api/packages/nuget/nuget.go +++ b/routers/api/packages/nuget/nuget.go @@ -594,13 +594,13 @@ func UploadSymbolPackage(ctx *context.Context) { func processUploadedFile(ctx *context.Context, expectedType nuget_module.PackageType) (*nuget_module.Package, *packages_module.HashedBuffer, []io.Closer) { closables := make([]io.Closer, 0, 2) - upload, close, err := ctx.UploadStream() + upload, needToClose, err := ctx.UploadStream() if err != nil { apiError(ctx, http.StatusBadRequest, err) return nil, nil, closables } - if close { + if needToClose { closables = append(closables, upload) } diff --git a/routers/api/packages/rpm/rpm.go b/routers/api/packages/rpm/rpm.go index 4de361c214..c59366992c 100644 --- a/routers/api/packages/rpm/rpm.go +++ b/routers/api/packages/rpm/rpm.go @@ -117,12 +117,12 @@ func GetRepositoryFile(ctx *context.Context) { } func UploadPackageFile(ctx *context.Context) { - upload, close, err := ctx.UploadStream() + upload, needToClose, err := ctx.UploadStream() if err != nil { apiError(ctx, http.StatusInternalServerError, err) return } - if close { + if needToClose { defer upload.Close() } diff --git a/routers/api/packages/rubygems/rubygems.go b/routers/api/packages/rubygems/rubygems.go index d2fbcd01f0..ba5f4de080 100644 --- a/routers/api/packages/rubygems/rubygems.go +++ b/routers/api/packages/rubygems/rubygems.go @@ -197,12 +197,12 @@ func DownloadPackageFile(ctx *context.Context) { // UploadPackageFile adds a file to the package. If the package does not exist, it gets created. func UploadPackageFile(ctx *context.Context) { - upload, close, err := ctx.UploadStream() + upload, needToClose, err := ctx.UploadStream() if err != nil { apiError(ctx, http.StatusBadRequest, err) return } - if close { + if needToClose { defer upload.Close() } diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index 5e173abf88..dfe6d31f74 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -217,7 +217,6 @@ func SearchIssues(ctx *context.APIContext) { var includedAnyLabels []int64 { - labels := ctx.FormTrim("labels") var includedLabelNames []string if len(labels) > 0 { diff --git a/routers/api/v1/repo/mirror.go b/routers/api/v1/repo/mirror.go index 864644e1ef..2a896de4fe 100644 --- a/routers/api/v1/repo/mirror.go +++ b/routers/api/v1/repo/mirror.go @@ -180,7 +180,6 @@ func ListPushMirrors(ctx *context.APIContext) { if err == nil { responsePushMirrors = append(responsePushMirrors, m) } - } ctx.SetLinkHeader(len(responsePushMirrors), utils.GetListOptions(ctx).PageSize) ctx.SetTotalCountHeader(count) diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index dfe34f23d0..4129f94ac3 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -1061,7 +1061,6 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) isSameRepo = true headUser = ctx.Repo.Owner headBranch = headInfos[0] - } else if len(headInfos) == 2 { headUser, err = user_model.GetUserByName(ctx, headInfos[0]) if err != nil { @@ -1075,7 +1074,6 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) headBranch = headInfos[1] // The head repository can also point to the same repo isSameRepo = ctx.Repo.Owner.ID == headUser.ID - } else { ctx.NotFound() return nil, nil, nil, nil, "", "" diff --git a/routers/api/v1/repo/pull_review.go b/routers/api/v1/repo/pull_review.go index 17bb2085b6..b527e90f10 100644 --- a/routers/api/v1/repo/pull_review.go +++ b/routers/api/v1/repo/pull_review.go @@ -728,7 +728,6 @@ func apiReviewRequest(ctx *context.APIContext, opts api.PullReviewRequestOptions } if ctx.Repo.Repository.Owner.IsOrganization() && len(opts.TeamReviewers) > 0 { - teamReviewers := make([]*organization.Team, 0, len(opts.TeamReviewers)) for _, t := range opts.TeamReviewers { var teamReviewer *organization.Team diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 2ac0b7ebd1..7f35a7fe41 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -1084,7 +1084,6 @@ func updateMirror(ctx *context.APIContext, opts api.EditRepoOption) error { // update MirrorInterval if opts.MirrorInterval != nil { - // MirrorInterval should be a duration interval, err := time.ParseDuration(*opts.MirrorInterval) if err != nil { diff --git a/routers/api/v1/repo/wiki.go b/routers/api/v1/repo/wiki.go index f18ea087c4..c7065c1d9d 100644 --- a/routers/api/v1/repo/wiki.go +++ b/routers/api/v1/repo/wiki.go @@ -478,7 +478,6 @@ func findEntryForFile(commit *git.Commit, target string) (*git.TreeEntry, error) func findWikiRepoCommit(ctx *context.APIContext) (*git.Repository, *git.Commit) { wikiRepo, err := gitrepo.OpenWikiRepository(ctx, ctx.Repo.Repository) if err != nil { - if git.IsErrNotExist(err) || err.Error() == "no such file or directory" { ctx.NotFound(err) } else { diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go index 4e59237ed3..caab6b4c81 100644 --- a/routers/private/hook_pre_receive.go +++ b/routers/private/hook_pre_receive.go @@ -198,7 +198,6 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r UserMsg: fmt.Sprintf("branch %s is protected from force push", branchName), }) return - } } diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go index 41989589be..db2b11a7ed 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -644,7 +644,6 @@ func ArtifactsDownloadView(ctx *context_module.Context) { writer := zip.NewWriter(ctx.Resp) defer writer.Close() for _, art := range artifacts { - f, err := storage.ActionsArtifacts.Open(art.StoragePath) if err != nil { ctx.Error(http.StatusInternalServerError, err.Error()) diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 1364d75676..95f0cf3d71 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -933,7 +933,6 @@ func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleFiles } } } - } if template.Ref != "" && !strings.HasPrefix(template.Ref, "refs/") { // Assume that the ref intended is always a branch - for tags users should use refs/tags/<ref> @@ -1681,7 +1680,6 @@ func ViewIssue(ctx *context.Context) { if comment.ProjectID > 0 && comment.Project == nil { comment.Project = ghostProject } - } else if comment.Type == issues_model.CommentTypeAssignees || comment.Type == issues_model.CommentTypeReviewRequest { if err = comment.LoadAssigneeUserAndTeam(ctx); err != nil { ctx.ServerError("LoadAssigneeUserAndTeam", err) @@ -2610,7 +2608,6 @@ func SearchIssues(ctx *context.Context) { var includedAnyLabels []int64 { - labels := ctx.FormTrim("labels") var includedLabelNames []string if len(labels) > 0 { @@ -2994,7 +2991,6 @@ func NewComment(ctx *context.Context) { if (ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) || (ctx.IsSigned && issue.IsPoster(ctx.Doer.ID))) && (form.Status == "reopen" || form.Status == "close") && !(issue.IsPull && issue.PullRequest.HasMerged) { - // Duplication and conflict check should apply to reopen pull request. var pr *issues_model.PullRequest diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index a0a8e5410c..71f25db11b 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -443,7 +443,6 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C } if pb != nil && pb.EnableStatusCheck { - var missingRequiredChecks []string for _, requiredContext := range pb.StatusCheckContexts { contextFound := false @@ -646,7 +645,6 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi // Validate the given commit sha to show (if any passed) if willShowSpecifiedCommit || willShowSpecifiedCommitRange { - foundStartCommit := len(specifiedStartCommit) == 0 foundEndCommit := len(specifiedEndCommit) == 0 @@ -974,7 +972,6 @@ func UpdatePullRequest(ctx *context.Context) { ctx.Flash.Error(flashError) ctx.Redirect(issue.Link()) return - } ctx.Flash.Error(err.Error()) ctx.Redirect(issue.Link()) diff --git a/routers/web/repo/pull_review.go b/routers/web/repo/pull_review.go index c8d149a482..a65d4866d0 100644 --- a/routers/web/repo/pull_review.go +++ b/routers/web/repo/pull_review.go @@ -318,7 +318,6 @@ func UpdateViewedFiles(ctx *context.Context) { updatedFiles := make(map[string]pull_model.ViewedState, len(data.Files)) for file, viewed := range data.Files { - // Only unviewed and viewed are possible, has-changed can not be set from the outside state := pull_model.Unviewed if viewed { diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 9c1f4faa5f..e4e6201c24 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -347,7 +347,6 @@ func loadLatestCommitData(ctx *context.Context, latestCommit *git.Commit) bool { // or of directory if not in root directory. ctx.Data["LatestCommit"] = latestCommit if latestCommit != nil { - verification := asymkey_model.ParseCommitWithSignature(ctx, latestCommit) if err := asymkey_model.CalculateTrustStatus(verification, ctx.Repo.Repository.GetTrustModel(), func(user *user_model.User) (bool, error) { diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index 6fb6421887..1d09a222c0 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -298,13 +298,15 @@ func handleWorkflows( TriggerEvent: dwf.TriggerEvent.Name, Status: actions_model.StatusWaiting, } - if need, err := ifNeedApproval(ctx, run, input.Repo, input.Doer); err != nil { + + need, err := ifNeedApproval(ctx, run, input.Repo, input.Doer) + if err != nil { log.Error("check if need approval for repo %d with user %d: %v", input.Repo.ID, input.Doer.ID, err) continue - } else { - run.NeedApproval = need } + run.NeedApproval = need + if err := run.LoadAttributes(ctx); err != nil { log.Error("LoadAttributes: %v", err) continue diff --git a/services/auth/source/ldap/source_sync.go b/services/auth/source/ldap/source_sync.go index 0c9491cd09..2a95326b9e 100644 --- a/services/auth/source/ldap/source_sync.go +++ b/services/auth/source/ldap/source_sync.go @@ -156,7 +156,6 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error { !strings.EqualFold(usr.Email, su.Mail) || usr.FullName != fullName || !usr.IsActive { - log.Trace("SyncExternalUsers[%s]: Updating user %s", source.authSource.Name, usr.Name) opts := &user_service.UpdateOptions{ diff --git a/services/context/repo.go b/services/context/repo.go index b17f99eb17..4836c1456c 100644 --- a/services/context/repo.go +++ b/services/context/repo.go @@ -825,7 +825,6 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string { case RepoRefBranch: ref := getRefNameFromPath(ctx, repo, path, repo.GitRepo.IsBranchExist) if len(ref) == 0 { - // check if ref is HEAD parts := strings.Split(path, "/") if parts[0] == headRefName { @@ -968,7 +967,6 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context return cancel } ctx.Repo.CommitID = ctx.Repo.Commit.ID.String() - } else if refType.RefTypeIncludesTags() && ctx.Repo.GitRepo.IsTagExist(refName) { ctx.Repo.IsViewTag = true ctx.Repo.TagName = refName diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index b05c210a0c..d115686491 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -1044,10 +1044,10 @@ func createDiffFile(diff *Diff, line string) *DiffFile { // diff --git a/b b/b b/b b/b b/b b/b // midpoint := (len(line) + len(cmdDiffHead) - 1) / 2 - new, old := line[len(cmdDiffHead):midpoint], line[midpoint+1:] - if len(new) > 2 && len(old) > 2 && new[2:] == old[2:] { - curFile.OldName = old[2:] - curFile.Name = old[2:] + newPart, oldPart := line[len(cmdDiffHead):midpoint], line[midpoint+1:] + if len(newPart) > 2 && len(oldPart) > 2 && newPart[2:] == oldPart[2:] { + curFile.OldName = oldPart[2:] + curFile.Name = oldPart[2:] } } } @@ -1181,7 +1181,6 @@ func GetDiff(ctx context.Context, gitRepo *git.Repository, opts *DiffOptions, fi defer deferable() for _, diffFile := range diff.Files { - isVendored := optional.None[bool]() isGenerated := optional.None[bool]() if checker != nil { diff --git a/services/issue/commit.go b/services/issue/commit.go index 0a59088d12..0579e0f5c5 100644 --- a/services/issue/commit.go +++ b/services/issue/commit.go @@ -118,7 +118,6 @@ func UpdateIssuesCommit(ctx context.Context, doer *user_model.User, repo *repo_m var refIssue *issues_model.Issue var err error for _, ref := range references.FindAllIssueReferences(c.Message) { - // issue is from another repo if len(ref.Owner) > 0 && len(ref.Name) > 0 { refRepo, err = repo_model.GetRepositoryByOwnerAndName(ctx, ref.Owner, ref.Name) @@ -189,15 +188,15 @@ func UpdateIssuesCommit(ctx context.Context, doer *user_model.User, repo *repo_m continue } } - close := ref.Action == references.XRefActionCloses - if close && len(ref.TimeLog) > 0 { + isClosed := ref.Action == references.XRefActionCloses + if isClosed && len(ref.TimeLog) > 0 { if err := issueAddTime(ctx, refIssue, doer, c.Timestamp, ref.TimeLog); err != nil { return err } } - if close != refIssue.IsClosed { + if isClosed != refIssue.IsClosed { refIssue.Repo = refRepo - if err := ChangeStatus(ctx, refIssue, doer, c.Sha1, close); err != nil { + if err := ChangeStatus(ctx, refIssue, doer, c.Sha1, isClosed); err != nil { return err } } diff --git a/services/markup/processorhelper_codepreview.go b/services/markup/processorhelper_codepreview.go index ef95046128..0500e57e46 100644 --- a/services/markup/processorhelper_codepreview.go +++ b/services/markup/processorhelper_codepreview.go @@ -86,12 +86,13 @@ func renderRepoFileCodePreview(ctx context.Context, opts markup.RenderCodePrevie lineNums := make([]int, 0, lineCount) lineCodes := make([]string, 0, lineCount) for i := opts.LineStart; i <= opts.LineStop; i++ { - if line, err := reader.ReadString('\n'); err != nil && line == "" { + line, err := reader.ReadString('\n') + if err != nil && line == "" { break - } else { - lineNums = append(lineNums, i) - lineCodes = append(lineCodes, line) } + + lineNums = append(lineNums, i) + lineCodes = append(lineCodes, line) } realLineStop := max(opts.LineStart, opts.LineStart+len(lineNums)-1) highlightLines := code.HighlightSearchResultCode(opts.FilePath, language, lineNums, strings.Join(lineCodes, "")) diff --git a/services/migrations/gitea_downloader.go b/services/migrations/gitea_downloader.go index d402a238f2..272bf02e11 100644 --- a/services/migrations/gitea_downloader.go +++ b/services/migrations/gitea_downloader.go @@ -410,7 +410,6 @@ func (g *GiteaDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, err return nil, false, fmt.Errorf("error while listing issues: %w", err) } for _, issue := range issues { - labels := make([]*base.Label, 0, len(issue.Labels)) for i := range issue.Labels { labels = append(labels, g.convertGiteaLabel(issue.Labels[i])) diff --git a/services/migrations/gitlab.go b/services/migrations/gitlab.go index bbc44e958a..065b687fa6 100644 --- a/services/migrations/gitlab.go +++ b/services/migrations/gitlab.go @@ -421,7 +421,6 @@ func (g *GitlabDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, er return nil, false, fmt.Errorf("error while listing issues: %w", err) } for _, issue := range issues { - labels := make([]*base.Label, 0, len(issue.Labels)) for _, l := range issue.Labels { labels = append(labels, &base.Label{ diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index fa23986c54..f5eaeaf091 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -523,13 +523,13 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { theCommits.Commits = theCommits.Commits[:setting.UI.FeedMaxCommitNum] } - if newCommit, err := gitRepo.GetCommit(newCommitID); err != nil { + newCommit, err := gitRepo.GetCommit(newCommitID) + if err != nil { log.Error("SyncMirrors [repo: %-v]: unable to get commit %s: %v", m.Repo, newCommitID, err) continue - } else { - theCommits.HeadCommit = repo_module.CommitToPushCommit(newCommit) } + theCommits.HeadCommit = repo_module.CommitToPushCommit(newCommit) theCommits.CompareURL = m.Repo.ComposeCompareURL(oldCommitID, newCommitID) notify_service.SyncPushCommits(ctx, m.Repo.MustOwner(ctx), m.Repo, &repo_module.PushUpdateOptions{ @@ -557,7 +557,6 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { log.Error("SyncMirrors [repo: %-v]: unable to update repository 'updated_unix': %v", m.Repo, err) return false } - } log.Trace("SyncMirrors [repo: %-v]: Successfully updated", m.Repo) diff --git a/services/pull/merge.go b/services/pull/merge.go index e37540a96f..00f23e1e3a 100644 --- a/services/pull/merge.go +++ b/services/pull/merge.go @@ -231,9 +231,9 @@ func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.U if err = ref.Issue.LoadRepo(ctx); err != nil { return err } - close := ref.RefAction == references.XRefActionCloses - if close != ref.Issue.IsClosed { - if err = issue_service.ChangeStatus(ctx, ref.Issue, doer, pr.MergedCommitID, close); err != nil { + isClosed := ref.RefAction == references.XRefActionCloses + if isClosed != ref.Issue.IsClosed { + if err = issue_service.ChangeStatus(ctx, ref.Issue, doer, pr.MergedCommitID, isClosed); err != nil { // Allow ErrDependenciesLeft if !issues_model.IsErrDependenciesLeft(err) { return err diff --git a/services/pull/pull.go b/services/pull/pull.go index 185a1895c9..764be5c6e3 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -807,7 +807,6 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ if err != nil { log.Error("Unable to get commits between: %s %s Error: %v", pr.HeadBranch, pr.MergeBase, err) return "" - } if len(commits) == 0 { break diff --git a/services/repository/adopt.go b/services/repository/adopt.go index b337eac38a..31e3e581b3 100644 --- a/services/repository/adopt.go +++ b/services/repository/adopt.go @@ -357,7 +357,6 @@ func ListUnadoptedRepositories(ctx context.Context, query string, opts *db.ListO return err } repoNamesToCheck = repoNamesToCheck[:0] - } return filepath.SkipDir }); err != nil { diff --git a/services/repository/contributors_graph.go b/services/repository/contributors_graph.go index b0d6de99ca..b0748f8ee3 100644 --- a/services/repository/contributors_graph.go +++ b/services/repository/contributors_graph.go @@ -187,7 +187,6 @@ func getExtendedCommitStats(repo *git.Repository, revision string /*, limit int Stats: &commitStats, } extendedCommitStats = append(extendedCommitStats, res) - } _ = stdoutReader.Close() return nil diff --git a/services/repository/files/update.go b/services/repository/files/update.go index f029a9aefe..d0e3075eae 100644 --- a/services/repository/files/update.go +++ b/services/repository/files/update.go @@ -208,7 +208,6 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use return nil, fmt.Errorf("ConvertToSHA1: Invalid last commit ID: %w", err) } opts.LastCommitID = lastCommitID.String() - } for _, file := range opts.Files { @@ -360,7 +359,6 @@ func handleCheckErrors(file *ChangeRepoFile, commit *git.Commit, opts *ChangeRep Path: file.Options.treePath, } } - } } diff --git a/services/user/delete.go b/services/user/delete.go index 889da3eb67..39c6ef052d 100644 --- a/services/user/delete.go +++ b/services/user/delete.go @@ -105,7 +105,6 @@ func deleteUser(ctx context.Context, u *user_model.User, purge bool) (err error) if purge || (setting.Service.UserDeleteWithCommentsMaxTime != 0 && u.CreatedUnix.AsTime().Add(setting.Service.UserDeleteWithCommentsMaxTime).After(time.Now())) { - // Delete Comments const batchSize = 50 for { diff --git a/services/user/update_test.go b/services/user/update_test.go index 7ed764b539..c2ff26a140 100644 --- a/services/user/update_test.go +++ b/services/user/update_test.go @@ -94,7 +94,7 @@ func TestUpdateAuth(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 28}) - copy := *user + userCopy := *user assert.NoError(t, UpdateAuth(db.DefaultContext, user, &UpdateAuthOptions{ LoginName: optional.Some("new-login"), @@ -106,8 +106,8 @@ func TestUpdateAuth(t *testing.T) { MustChangePassword: optional.Some(true), })) assert.True(t, user.MustChangePassword) - assert.NotEqual(t, copy.Passwd, user.Passwd) - assert.NotEqual(t, copy.Salt, user.Salt) + assert.NotEqual(t, userCopy.Passwd, user.Passwd) + assert.NotEqual(t, userCopy.Salt, user.Salt) assert.NoError(t, UpdateAuth(db.DefaultContext, user, &UpdateAuthOptions{ ProhibitLogin: optional.Some(true), diff --git a/services/webhook/discord.go b/services/webhook/discord.go index 659754d5e0..3883ac9eb8 100644 --- a/services/webhook/discord.go +++ b/services/webhook/discord.go @@ -274,14 +274,12 @@ func newDiscordRequest(ctx context.Context, w *webhook_model.Webhook, t *webhook func parseHookPullRequestEventType(event webhook_module.HookEventType) (string, error) { switch event { - case webhook_module.HookEventPullRequestReviewApproved: return "approved", nil case webhook_module.HookEventPullRequestReviewRejected: return "rejected", nil case webhook_module.HookEventPullRequestReviewComment: return "comment", nil - default: return "", errors.New("unknown event type") } diff --git a/services/webhook/matrix.go b/services/webhook/matrix.go index 0329804a8b..5dcfdcb0dd 100644 --- a/services/webhook/matrix.go +++ b/services/webhook/matrix.go @@ -179,7 +179,6 @@ func (m matrixConvertor) Push(p *api.PushPayload) (MatrixPayload, error) { if i < len(p.Commits)-1 { text += "<br>" } - } return m.newPayload(text, p.Commits...) diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go index d15aa9a027..c8a792d6a3 100644 --- a/tests/e2e/e2e_test.go +++ b/tests/e2e/e2e_test.go @@ -102,18 +102,20 @@ func TestE2e(t *testing.T) { cmd := exec.Command(runArgs[0], runArgs...) cmd.Env = os.Environ() cmd.Env = append(cmd.Env, fmt.Sprintf("GITEA_URL=%s", setting.AppURL)) + var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr + err := cmd.Run() if err != nil { // Currently colored output is conflicting. Using Printf until that is resolved. fmt.Printf("%v", stdout.String()) fmt.Printf("%v", stderr.String()) log.Fatal("Playwright Failed: %s", err) - } else { - fmt.Printf("%v", stdout.String()) } + + fmt.Printf("%v", stdout.String()) }) }) } diff --git a/tests/integration/api_notification_test.go b/tests/integration/api_notification_test.go index 528890ca22..abb9852eef 100644 --- a/tests/integration/api_notification_test.go +++ b/tests/integration/api_notification_test.go @@ -111,7 +111,7 @@ func TestAPINotification(t *testing.T) { MakeRequest(t, NewRequest(t, "GET", "/api/v1/notifications/new"), http.StatusUnauthorized) - new := struct { + newStruct := struct { New int64 `json:"new"` }{} @@ -119,8 +119,8 @@ func TestAPINotification(t *testing.T) { req = NewRequest(t, "GET", "/api/v1/notifications/new"). AddTokenAuth(token) resp = MakeRequest(t, req, http.StatusOK) - DecodeJSON(t, resp, &new) - assert.True(t, new.New > 0) + DecodeJSON(t, resp, &newStruct) + assert.True(t, newStruct.New > 0) // -- mark notifications as read -- req = NewRequest(t, "GET", "/api/v1/notifications?status-types=unread"). @@ -153,8 +153,8 @@ func TestAPINotification(t *testing.T) { req = NewRequest(t, "GET", "/api/v1/notifications/new"). AddTokenAuth(token) resp = MakeRequest(t, req, http.StatusOK) - DecodeJSON(t, resp, &new) - assert.True(t, new.New == 0) + DecodeJSON(t, resp, &newStruct) + assert.True(t, newStruct.New == 0) } func TestAPINotificationPUT(t *testing.T) { diff --git a/tests/integration/pull_status_test.go b/tests/integration/pull_status_test.go index bb7098e424..80eea34513 100644 --- a/tests/integration/pull_status_test.go +++ b/tests/integration/pull_status_test.go @@ -71,7 +71,6 @@ func TestPullCreate_CommitStatus(t *testing.T) { // Update commit status, and check if icon is updated as well for _, status := range statusList { - // Call API to add status for commit t.Run("CreateStatus", doAPICreateCommitStatus(testCtx, commitID, api.CreateStatusOption{ State: status, From 99c5683da5e5c50154dcf9c07229a455a5095058 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Mon, 22 Apr 2024 16:24:47 +0200 Subject: [PATCH 179/370] Enable jquery-related eslint rules that have no violations (#30632) All these have no violations, so enable them. --- .eslintrc.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 3e4c6ea50b..cd5a0735b4 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -310,7 +310,7 @@ rules: jquery/no-merge: [2] jquery/no-param: [2] jquery/no-parent: [0] - jquery/no-parents: [0] + jquery/no-parents: [2] jquery/no-parse-html: [2] jquery/no-prop: [2] jquery/no-proxy: [2] @@ -319,8 +319,8 @@ rules: jquery/no-show: [2] jquery/no-size: [2] jquery/no-sizzle: [2] - jquery/no-slide: [0] - jquery/no-submit: [0] + jquery/no-slide: [2] + jquery/no-submit: [2] jquery/no-text: [0] jquery/no-toggle: [2] jquery/no-trigger: [0] @@ -458,7 +458,7 @@ rules: no-jquery/no-other-utils: [2] no-jquery/no-param: [2] no-jquery/no-parent: [0] - no-jquery/no-parents: [0] + no-jquery/no-parents: [2] no-jquery/no-parse-html-literal: [0] no-jquery/no-parse-html: [2] no-jquery/no-parse-json: [2] From e6103955ccc48e19f42dd7b70ad27d0e17205d77 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Tue, 23 Apr 2024 07:55:43 +0800 Subject: [PATCH 180/370] Fix queue test (#30646) Fix #30643 The old test code is not stable due to the data-race described in the TODO added at that time. Make it stable, and remove a debug-only field from old test code. --- modules/queue/workergroup.go | 18 ++++++++++------- modules/queue/workerqueue.go | 2 -- modules/queue/workerqueue_test.go | 33 +++++++++++++++++++++---------- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/modules/queue/workergroup.go b/modules/queue/workergroup.go index e3801ef2b2..153123f883 100644 --- a/modules/queue/workergroup.go +++ b/modules/queue/workergroup.go @@ -63,6 +63,8 @@ func (q *WorkerPoolQueue[T]) doDispatchBatchToWorker(wg *workerGroup[T], flushCh // TODO: the logic could be improved in the future, to avoid a data-race between "doStartNewWorker" and "workerNum" // The root problem is that if we skip "doStartNewWorker" here, the "workerNum" might be decreased by other workers later // So ideally, it should check whether there are enough workers by some approaches, and start new workers if necessary. + // This data-race is not serious, as long as a new worker will be started soon to make sure there are enough workers, + // so no need to hugely refactor at the moment. q.workerNumMu.Lock() noWorker := q.workerNum == 0 if full || noWorker { @@ -136,6 +138,14 @@ func (q *WorkerPoolQueue[T]) basePushForShutdown(items ...T) bool { return true } +func resetIdleTicker(t *time.Ticker, dur time.Duration) { + t.Reset(dur) + select { + case <-t.C: + default: + } +} + // doStartNewWorker starts a new worker for the queue, the worker reads from worker's channel and handles the items. func (q *WorkerPoolQueue[T]) doStartNewWorker(wp *workerGroup[T]) { wp.wg.Add(1) @@ -146,8 +156,6 @@ func (q *WorkerPoolQueue[T]) doStartNewWorker(wp *workerGroup[T]) { log.Debug("Queue %q starts new worker", q.GetName()) defer log.Debug("Queue %q stops idle worker", q.GetName()) - atomic.AddInt32(&q.workerStartedCounter, 1) // Only increase counter, used for debugging - t := time.NewTicker(workerIdleDuration) defer t.Stop() @@ -169,11 +177,7 @@ func (q *WorkerPoolQueue[T]) doStartNewWorker(wp *workerGroup[T]) { } q.doWorkerHandle(batch) // reset the idle ticker, and drain the tick after reset in case a tick is already triggered - t.Reset(workerIdleDuration) - select { - case <-t.C: - default: - } + resetIdleTicker(t, workerIdleDuration) // key code for TestWorkerPoolQueueWorkerIdleReset case <-t.C: q.workerNumMu.Lock() keepWorking = q.workerNum <= 1 // keep the last worker running diff --git a/modules/queue/workerqueue.go b/modules/queue/workerqueue.go index 4160622d81..b28fd88027 100644 --- a/modules/queue/workerqueue.go +++ b/modules/queue/workerqueue.go @@ -40,8 +40,6 @@ type WorkerPoolQueue[T any] struct { workerMaxNum int workerActiveNum int workerNumMu sync.Mutex - - workerStartedCounter int32 } type flushType chan struct{} diff --git a/modules/queue/workerqueue_test.go b/modules/queue/workerqueue_test.go index a08b02a123..d66253ff66 100644 --- a/modules/queue/workerqueue_test.go +++ b/modules/queue/workerqueue_test.go @@ -5,8 +5,10 @@ package queue import ( "context" + "slices" "strconv" "sync" + "sync/atomic" "testing" "time" @@ -250,23 +252,34 @@ func TestWorkerPoolQueueShutdown(t *testing.T) { func TestWorkerPoolQueueWorkerIdleReset(t *testing.T) { defer test.MockVariableValue(&workerIdleDuration, 10*time.Millisecond)() - defer mockBackoffDuration(10 * time.Millisecond)() + defer mockBackoffDuration(5 * time.Millisecond)() + var q *WorkerPoolQueue[int] + var handledCount atomic.Int32 + var hasOnlyOneWorkerRunning atomic.Bool handler := func(items ...int) (unhandled []int) { - time.Sleep(50 * time.Millisecond) + handledCount.Add(int32(len(items))) + // make each work have different duration, and check the active worker number periodically + var activeNums []int + for i := 0; i < 5-items[0]%2; i++ { + time.Sleep(workerIdleDuration * 2) + activeNums = append(activeNums, q.GetWorkerActiveNumber()) + } + // When the queue never becomes empty, the existing workers should keep working + // It is not 100% true at the moment because the data-race in workergroup.go is not resolved, see that TODO */ + // If the "active worker numbers" is like [2 2 ... 1 1], it means that an existing worker exited and the no new worker is started. + if slices.Equal([]int{1, 1}, activeNums[len(activeNums)-2:]) { + hasOnlyOneWorkerRunning.Store(true) + } return nil } - - q, _ := newWorkerPoolQueueForTest("test-workpoolqueue", setting.QueueSettings{Type: "channel", BatchLength: 1, MaxWorkers: 2, Length: 100}, handler, false) + q, _ = newWorkerPoolQueueForTest("test-workpoolqueue", setting.QueueSettings{Type: "channel", BatchLength: 1, MaxWorkers: 2, Length: 100}, handler, false) stop := runWorkerPoolQueue(q) - for i := 0; i < 20; i++ { + for i := 0; i < 100; i++ { assert.NoError(t, q.Push(i)) } - time.Sleep(500 * time.Millisecond) - assert.EqualValues(t, 2, q.GetWorkerNumber()) - assert.EqualValues(t, 2, q.GetWorkerActiveNumber()) - // when the queue never becomes empty, the existing workers should keep working - assert.EqualValues(t, 2, q.workerStartedCounter) + assert.Greater(t, int(handledCount.Load()), 4) // make sure there are enough items handled during the test + assert.False(t, hasOnlyOneWorkerRunning.Load(), "a slow handler should not block other workers from starting") stop() } From 7d5a03fda2089d088ce544011f93799ca0a1d193 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Tue, 23 Apr 2024 00:24:55 +0000 Subject: [PATCH 181/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_cs-CZ.ini | 1 - options/locale/locale_de-DE.ini | 1 - options/locale/locale_el-GR.ini | 1 - options/locale/locale_es-ES.ini | 1 - options/locale/locale_fa-IR.ini | 1 - options/locale/locale_fi-FI.ini | 1 - options/locale/locale_fr-FR.ini | 1 - options/locale/locale_hu-HU.ini | 1 - options/locale/locale_id-ID.ini | 1 - options/locale/locale_is-IS.ini | 1 - options/locale/locale_it-IT.ini | 1 - options/locale/locale_ja-JP.ini | 1 - options/locale/locale_ko-KR.ini | 1 - options/locale/locale_lv-LV.ini | 1 - options/locale/locale_nl-NL.ini | 1 - options/locale/locale_pl-PL.ini | 1 - options/locale/locale_pt-BR.ini | 1 - options/locale/locale_pt-PT.ini | 1 - options/locale/locale_ru-RU.ini | 1 - options/locale/locale_si-LK.ini | 1 - options/locale/locale_sk-SK.ini | 1 - options/locale/locale_sv-SE.ini | 1 - options/locale/locale_tr-TR.ini | 1 - options/locale/locale_uk-UA.ini | 1 - options/locale/locale_zh-CN.ini | 1 - options/locale/locale_zh-HK.ini | 1 - options/locale/locale_zh-TW.ini | 1 - 27 files changed, 27 deletions(-) diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index 57c44e4b26..82d7867168 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -1186,7 +1186,6 @@ action.blocked_user=Nelze provést akci, protože jste zablokování vlastníkem download_archive=Stáhnout repozitář more_operations=Další operace -no_desc=Bez popisu quick_guide=Krátká příručka clone_this_repo=Naklonovat tento repozitář cite_this_repo=Citovat tento repozitář diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index f591b75577..dd2b34a6f4 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -1187,7 +1187,6 @@ action.blocked_user=Die Aktion kann nicht ausgeführt werden, da du vom Reposito download_archive=Repository herunterladen more_operations=Weitere Operationen -no_desc=Keine Beschreibung quick_guide=Kurzanleitung clone_this_repo=Dieses Repository klonen cite_this_repo=Dieses Repository zitieren diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini index 64db2348da..9553ba2f3a 100644 --- a/options/locale/locale_el-GR.ini +++ b/options/locale/locale_el-GR.ini @@ -1118,7 +1118,6 @@ fork=Fork download_archive=Λήψη Αποθετηρίου more_operations=Περισσότερες Λειτουργίες -no_desc=Χωρίς Περιγραφή quick_guide=Γρήγορος Οδηγός clone_this_repo=Κλωνοποίηση αυτού του αποθετηρίου cite_this_repo=Αναφορά σε αυτό το αποθετήριο diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index d1d680c14c..f3e2d93e80 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -1111,7 +1111,6 @@ fork=Fork download_archive=Descargar repositorio more_operations=Más operaciones -no_desc=Sin descripción quick_guide=Guía rápida clone_this_repo=Clonar este repositorio cite_this_repo=Citar este repositorio diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini index 54a4911e5c..25a3361b3f 100644 --- a/options/locale/locale_fa-IR.ini +++ b/options/locale/locale_fa-IR.ini @@ -874,7 +874,6 @@ star=ستاره دار کن fork=انشعاب download_archive=دانلود مخزن -no_desc=بدون توضیح quick_guide=راهنمای سریع clone_this_repo=همسانسازی این مخزن create_new_repo_command=ایجاد یک مخزن جدید در خط فرمان diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini index ace676281f..f29ad8c6cd 100644 --- a/options/locale/locale_fi-FI.ini +++ b/options/locale/locale_fi-FI.ini @@ -718,7 +718,6 @@ unstar=Poista tähti star=Tähti download_archive=Lataa repo -no_desc=Ei kuvausta quick_guide=Pikaopas clone_this_repo=Kloonaa tämä repo diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index 61a6a98379..b90039c003 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -1130,7 +1130,6 @@ fork=Bifurcation download_archive=Télécharger ce dépôt more_operations=Plus d'opérations -no_desc=Aucune description quick_guide=Introduction rapide clone_this_repo=Cloner ce dépôt cite_this_repo=Citer ce dépôt diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini index bddd6dd582..4e46227fea 100644 --- a/options/locale/locale_hu-HU.ini +++ b/options/locale/locale_hu-HU.ini @@ -656,7 +656,6 @@ star=Csillagozás fork=Tükrözés download_archive=Tároló letöltése -no_desc=Nincs leírás quick_guide=Gyors útmutató clone_this_repo=Tároló klónozása create_new_repo_command=Egy új tároló létrehozása a parancssorból diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini index 9261077831..fe3a6d0b08 100644 --- a/options/locale/locale_id-ID.ini +++ b/options/locale/locale_id-ID.ini @@ -570,7 +570,6 @@ star=Bintang fork=Garpu download_archive=Unduh Repositori -no_desc=Tidak ada Deskripsi quick_guide=Panduan Cepat clone_this_repo=Klon repositori ini create_new_repo_command=Membuat repositori baru pada baris perintah diff --git a/options/locale/locale_is-IS.ini b/options/locale/locale_is-IS.ini index a1116eddbc..f2fcfb7eda 100644 --- a/options/locale/locale_is-IS.ini +++ b/options/locale/locale_is-IS.ini @@ -647,7 +647,6 @@ star=Bæta við eftirlæti fork=Tvískipta download_archive=Hlaða Miður Geymslu -no_desc=Engin Lýsing quick_guide=Stuttar Leiðbeiningar clone_this_repo=Afrita þetta hugbúnaðarsafn create_new_repo_command=Að búa til nýja geymslu með skipanalínu diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index b15a78ccf4..eceda0faad 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -936,7 +936,6 @@ star=Vota fork=Forka download_archive=Scarica Repository -no_desc=Nessuna descrizione quick_guide=Guida rapida clone_this_repo=Clona questo repository create_new_repo_command=Creazione di un nuovo repository da riga di comando diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 707b37170a..e33a1ae173 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -1188,7 +1188,6 @@ action.blocked_user=リポジトリのオーナーがあなたをブロックし download_archive=リポジトリをダウンロード more_operations=その他の操作 -no_desc=説明なし quick_guide=クイック ガイド clone_this_repo=このリポジトリのクローンを作成 cite_this_repo=このリポジトリを引用 diff --git a/options/locale/locale_ko-KR.ini b/options/locale/locale_ko-KR.ini index 3e9679575c..cf3188e9c0 100644 --- a/options/locale/locale_ko-KR.ini +++ b/options/locale/locale_ko-KR.ini @@ -606,7 +606,6 @@ star=좋아요 fork=포크 download_archive=저장소 다운로드 -no_desc=설명 없음 quick_guide=퀵 가이드 clone_this_repo=이 저장소 복제 create_new_repo_command=커맨드 라인에서 새 레포리지터리 생성 diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 6afb488414..3aed4bd6c5 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -1119,7 +1119,6 @@ fork=Atdalīts download_archive=Lejupielādēt repozitoriju more_operations=Vairāk darbību -no_desc=Nav apraksta quick_guide=Īsa pamācība clone_this_repo=Klonēt šo repozitoriju cite_this_repo=Citēt šo repozitoriju diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini index b0b081db5d..f511bc5d23 100644 --- a/options/locale/locale_nl-NL.ini +++ b/options/locale/locale_nl-NL.ini @@ -934,7 +934,6 @@ star=Ster fork=Vork download_archive=Download repository -no_desc=Geen omschrijving quick_guide=Snelstart gids clone_this_repo=Kloon deze repository create_new_repo_command=Maak een nieuwe repository aan vanaf de console diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini index fd5db4109f..b5a758514e 100644 --- a/options/locale/locale_pl-PL.ini +++ b/options/locale/locale_pl-PL.ini @@ -877,7 +877,6 @@ star=Polub fork=Forkuj download_archive=Pobierz repozytorium -no_desc=Brak opisu quick_guide=Skrócona instrukcja clone_this_repo=Klonuj repozytorium create_new_repo_command=Tworzenie nowego repozytorium z linii poleceń diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 5a058c807b..2e23cde801 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -1115,7 +1115,6 @@ fork=Fork download_archive=Baixar repositório more_operations=Mais Operações -no_desc=Nenhuma descrição quick_guide=Guia Rápido clone_this_repo=Clonar este repositório cite_this_repo=Citar este repositório diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index a90927a255..64798d6d65 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -1193,7 +1193,6 @@ action.blocked_user=Não pode realizar a operação porque foi bloqueado/a pelo/ download_archive=Descarregar repositório more_operations=Mais operações -no_desc=Sem descrição quick_guide=Guia rápido clone_this_repo=Clonar este repositório cite_this_repo=Citar este repositório diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index d4098aa952..df6df4cf95 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -1098,7 +1098,6 @@ fork=Форкнуть download_archive=Скачать репозиторий more_operations=Ещё действия -no_desc=Нет описания quick_guide=Краткое руководство clone_this_repo=Клонировать репозиторий cite_this_repo=Сослаться на этот репозиторий diff --git a/options/locale/locale_si-LK.ini b/options/locale/locale_si-LK.ini index 05538af971..15bbcfebb2 100644 --- a/options/locale/locale_si-LK.ini +++ b/options/locale/locale_si-LK.ini @@ -846,7 +846,6 @@ star=ස්ටාර් fork=දෙබලක download_archive=කෝෂ්ඨය බාගන්න -no_desc=සවිස්තරයක් නැත quick_guide=ඉක්මන් මාර්ගෝපදේශය clone_this_repo=මෙම ගබඩාව පරිගණක ක්රිඩාවට සමාන create_new_repo_command=විධාන රේඛාවේ නව ගබඩාවක් නිර්මාණය කිරීම diff --git a/options/locale/locale_sk-SK.ini b/options/locale/locale_sk-SK.ini index b468b55283..be1efa22bc 100644 --- a/options/locale/locale_sk-SK.ini +++ b/options/locale/locale_sk-SK.ini @@ -964,7 +964,6 @@ star=Hviezdička download_archive=Stiahnuť repozitár more_operations=Viac operácií -no_desc=Bez popisu quick_guide=Rýchly sprievodca clone_this_repo=Klonovať tento repozitár create_new_repo_command=Vytvoriť nový repozitár v príkazovom riadku diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini index 5fe6288ad6..b975636cb8 100644 --- a/options/locale/locale_sv-SE.ini +++ b/options/locale/locale_sv-SE.ini @@ -718,7 +718,6 @@ star=Stjärnmärk fork=Förgrening download_archive=Ladda Ned Utvecklingskatalogen -no_desc=Ingen beskrivning quick_guide=Snabbguide clone_this_repo=Klona detta repo create_new_repo_command=Skapa en ny utvecklingskatalog på kommandoraden diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index 59c931afd2..be89113f0d 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -1193,7 +1193,6 @@ action.blocked_user=İşlem gerçekleştirilemiyor, depo sahibi tarafından enge download_archive=Depoyu İndir more_operations=Daha Fazla İşlem -no_desc=Açıklama Yok quick_guide=Hızlı Başlangıç Kılavuzu clone_this_repo=Bu depoyu klonla cite_this_repo=Bu depoya atıf ver diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini index 613f39b3c9..3e38973e02 100644 --- a/options/locale/locale_uk-UA.ini +++ b/options/locale/locale_uk-UA.ini @@ -882,7 +882,6 @@ star=В обрані fork=Форк download_archive=Скачати репозиторій -no_desc=Без опису quick_guide=Короткий посібник clone_this_repo=Кнонувати цей репозиторій create_new_repo_command=Створити новий репозиторій з командного рядка diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index aeba11fb9a..a76ecafd62 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -1193,7 +1193,6 @@ action.blocked_user=无法执行操作,因为您已被仓库所有者屏蔽。 download_archive=下载此仓库 more_operations=更多操作 -no_desc=暂无描述 quick_guide=快速帮助 clone_this_repo=克隆当前仓库 cite_this_repo=引用此仓库 diff --git a/options/locale/locale_zh-HK.ini b/options/locale/locale_zh-HK.ini index 2dbdeb2bae..fb16b82fc5 100644 --- a/options/locale/locale_zh-HK.ini +++ b/options/locale/locale_zh-HK.ini @@ -344,7 +344,6 @@ unstar=取消收藏 star=收藏 fork=複製 -no_desc=暫無描述 quick_guide=快速幫助 clone_this_repo=複製當前儲存庫 create_new_repo_command=從命令列建立新儲存庫。 diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini index 3e7bd4ae20..7823426990 100644 --- a/options/locale/locale_zh-TW.ini +++ b/options/locale/locale_zh-TW.ini @@ -1016,7 +1016,6 @@ fork=Fork download_archive=下載此儲存庫 more_operations=更多操作 -no_desc=暫無描述 quick_guide=快速幫助 clone_this_repo=Clone 此儲存庫 cite_this_repo=引用此儲存庫 From 8924d9b2efd52132876fcd106c625a2a2db7a295 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Tue, 23 Apr 2024 10:22:43 +0800 Subject: [PATCH 182/370] Fix compare api swagger (#30648) The swagger format on #30349 is not right. This PR will fix it. --- routers/api/v1/repo/compare.go | 2 +- templates/swagger/v1_json.tmpl | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/routers/api/v1/repo/compare.go b/routers/api/v1/repo/compare.go index 549b9b7fa9..cfd61d768c 100644 --- a/routers/api/v1/repo/compare.go +++ b/routers/api/v1/repo/compare.go @@ -16,7 +16,7 @@ import ( // CompareDiff compare two branches or commits func CompareDiff(ctx *context.APIContext) { - // swagger:operation GET /repos/{owner}/{repo}/compare/{basehead} Get commit comparison information + // swagger:operation GET /repos/{owner}/{repo}/compare/{basehead} repository repoCompareDiff // --- // summary: Get commit comparison information // produces: diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 532b8880bc..faf57454d7 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -5346,12 +5346,10 @@ "application/json" ], "tags": [ - "Get", - "commit", - "comparison" + "repository" ], "summary": "Get commit comparison information", - "operationId": "information", + "operationId": "repoCompareDiff", "parameters": [ { "type": "string", From e94864e86c43f435af7e1fc3c4831a4cc0a3e981 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Tue, 23 Apr 2024 11:00:57 +0800 Subject: [PATCH 183/370] Fix wrong table name (#30557) The table name should be `oauth2_application` but `o_auth2_application` Caused by https://github.com/go-gitea/gitea/pull/21316/files#diff-9610efbc608a41f1f2eaff5790423f0a187906f6ff0beb23a5e8d18366cc2ccfR38 --- models/auth/oauth2_test.go | 2 -- ...{o_auth2_application.yml => oauth2_application.yml} | 0 models/migrations/migrations.go | 2 ++ models/migrations/v1_18/v230.go | 6 +++--- models/migrations/v1_18/v230_test.go | 6 +++--- models/migrations/v1_23/v298.go | 10 ++++++++++ 6 files changed, 18 insertions(+), 8 deletions(-) rename models/migrations/fixtures/Test_AddConfidentialClientColumnToOAuth2ApplicationTable/{o_auth2_application.yml => oauth2_application.yml} (100%) create mode 100644 models/migrations/v1_23/v298.go diff --git a/models/auth/oauth2_test.go b/models/auth/oauth2_test.go index 122d43098c..0829d31d51 100644 --- a/models/auth/oauth2_test.go +++ b/models/auth/oauth2_test.go @@ -13,8 +13,6 @@ import ( "github.com/stretchr/testify/assert" ) -//////////////////// Application - func TestOAuth2Application_GenerateClientSecret(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1}) diff --git a/models/migrations/fixtures/Test_AddConfidentialClientColumnToOAuth2ApplicationTable/o_auth2_application.yml b/models/migrations/fixtures/Test_AddConfidentialClientColumnToOAuth2ApplicationTable/oauth2_application.yml similarity index 100% rename from models/migrations/fixtures/Test_AddConfidentialClientColumnToOAuth2ApplicationTable/o_auth2_application.yml rename to models/migrations/fixtures/Test_AddConfidentialClientColumnToOAuth2ApplicationTable/oauth2_application.yml diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index cb3a64f48c..220d8c2331 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -584,6 +584,8 @@ var migrations = []Migration{ NewMigration("Add missing field of commit status summary table", v1_23.AddCommitStatusSummary2), // v297 -> v298 NewMigration("Add everyone_access_mode for repo_unit", v1_23.AddRepoUnitEveryoneAccessMode), + // v298 -> v299 + NewMigration("Drop wrongly created table o_auth2_application", v1_23.DropWronglyCreatedTable), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v1_18/v230.go b/models/migrations/v1_18/v230.go index cf94926be1..ea5b4d02e1 100644 --- a/models/migrations/v1_18/v230.go +++ b/models/migrations/v1_18/v230.go @@ -9,9 +9,9 @@ import ( // AddConfidentialColumnToOAuth2ApplicationTable: add ConfidentialClient column, setting existing rows to true func AddConfidentialClientColumnToOAuth2ApplicationTable(x *xorm.Engine) error { - type OAuth2Application struct { + type oauth2Application struct { + ID int64 ConfidentialClient bool `xorm:"NOT NULL DEFAULT TRUE"` } - - return x.Sync(new(OAuth2Application)) + return x.Sync(new(oauth2Application)) } diff --git a/models/migrations/v1_18/v230_test.go b/models/migrations/v1_18/v230_test.go index 308f3a5023..40db4c2ffe 100644 --- a/models/migrations/v1_18/v230_test.go +++ b/models/migrations/v1_18/v230_test.go @@ -13,12 +13,12 @@ import ( func Test_AddConfidentialClientColumnToOAuth2ApplicationTable(t *testing.T) { // premigration - type OAuth2Application struct { + type oauth2Application struct { ID int64 } // Prepare and load the testing database - x, deferable := base.PrepareTestEnv(t, 0, new(OAuth2Application)) + x, deferable := base.PrepareTestEnv(t, 0, new(oauth2Application)) defer deferable() if x == nil || t.Failed() { return @@ -36,7 +36,7 @@ func Test_AddConfidentialClientColumnToOAuth2ApplicationTable(t *testing.T) { } got := []ExpectedOAuth2Application{} - if err := x.Table("o_auth2_application").Select("id, confidential_client").Find(&got); !assert.NoError(t, err) { + if err := x.Table("oauth2_application").Select("id, confidential_client").Find(&got); !assert.NoError(t, err) { return } diff --git a/models/migrations/v1_23/v298.go b/models/migrations/v1_23/v298.go new file mode 100644 index 0000000000..8761a05d3d --- /dev/null +++ b/models/migrations/v1_23/v298.go @@ -0,0 +1,10 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_23 //nolint + +import "xorm.io/xorm" + +func DropWronglyCreatedTable(x *xorm.Engine) error { + return x.DropTables("o_auth2_application") +} From 30dd4beeee631860c7dd393c341e9955997095a4 Mon Sep 17 00:00:00 2001 From: Zettat123 <zettat123@gmail.com> Date: Tue, 23 Apr 2024 11:51:52 +0800 Subject: [PATCH 184/370] Add a db consistency check to remove runners that do not belong to a repository (#30614) Follow #30406 --- models/actions/runner.go | 26 ++++++++++++++++++++++++-- services/doctor/dbconsistency.go | 6 ++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/models/actions/runner.go b/models/actions/runner.go index 67f003387b..9192925d5a 100644 --- a/models/actions/runner.go +++ b/models/actions/runner.go @@ -270,7 +270,7 @@ func CountRunnersWithoutBelongingOwner(ctx context.Context) (int64, error) { // Only affect action runners were a owner ID is set, as actions runners // could also be created on a repository. return db.GetEngine(ctx).Table("action_runner"). - Join("LEFT", "user", "`action_runner`.owner_id = `user`.id"). + Join("LEFT", "`user`", "`action_runner`.owner_id = `user`.id"). Where("`action_runner`.owner_id != ?", 0). And(builder.IsNull{"`user`.id"}). Count(new(ActionRunner)) @@ -279,7 +279,7 @@ func CountRunnersWithoutBelongingOwner(ctx context.Context) (int64, error) { func FixRunnersWithoutBelongingOwner(ctx context.Context) (int64, error) { subQuery := builder.Select("`action_runner`.id"). From("`action_runner`"). - Join("LEFT", "user", "`action_runner`.owner_id = `user`.id"). + Join("LEFT", "`user`", "`action_runner`.owner_id = `user`.id"). Where(builder.Neq{"`action_runner`.owner_id": 0}). And(builder.IsNull{"`user`.id"}) b := builder.Delete(builder.In("id", subQuery)).From("`action_runner`") @@ -289,3 +289,25 @@ func FixRunnersWithoutBelongingOwner(ctx context.Context) (int64, error) { } return res.RowsAffected() } + +func CountRunnersWithoutBelongingRepo(ctx context.Context) (int64, error) { + return db.GetEngine(ctx).Table("action_runner"). + Join("LEFT", "`repository`", "`action_runner`.repo_id = `repository`.id"). + Where("`action_runner`.repo_id != ?", 0). + And(builder.IsNull{"`repository`.id"}). + Count(new(ActionRunner)) +} + +func FixRunnersWithoutBelongingRepo(ctx context.Context) (int64, error) { + subQuery := builder.Select("`action_runner`.id"). + From("`action_runner`"). + Join("LEFT", "`repository`", "`action_runner`.repo_id = `repository`.id"). + Where(builder.Neq{"`action_runner`.repo_id": 0}). + And(builder.IsNull{"`repository`.id"}) + b := builder.Delete(builder.In("id", subQuery)).From("`action_runner`") + res, err := db.GetEngine(ctx).Exec(b) + if err != nil { + return 0, err + } + return res.RowsAffected() +} diff --git a/services/doctor/dbconsistency.go b/services/doctor/dbconsistency.go index dfdf7b547a..7cb7445148 100644 --- a/services/doctor/dbconsistency.go +++ b/services/doctor/dbconsistency.go @@ -152,6 +152,12 @@ func prepareDBConsistencyChecks() []consistencyCheck { Fixer: actions_model.FixRunnersWithoutBelongingOwner, FixedMessage: "Removed", }, + { + Name: "Action Runners without existing repository", + Counter: actions_model.CountRunnersWithoutBelongingRepo, + Fixer: actions_model.FixRunnersWithoutBelongingRepo, + FixedMessage: "Removed", + }, { Name: "Topics with empty repository count", Counter: repo_model.CountOrphanedTopics, From 370b1bdb3757e91c59303b0ce6ec49c56eca795b Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Tue, 23 Apr 2024 06:17:51 +0200 Subject: [PATCH 185/370] Fix project name wrapping, remove horizontal margin on header (#30631) Enable wrapping of unbroken lines: <img width="1308" alt="Screenshot 2024-04-22 at 00 31 33" src="https://github.com/go-gitea/gitea/assets/115237/1a28ade1-d708-4260-96a3-cf508b6dcb79"> Remove extra margin added by nested `.ui.container` on certain viewports: Before: <img width="1305" alt="Screenshot 2024-04-22 at 00 40 23" src="https://github.com/go-gitea/gitea/assets/115237/d3d8c0d1-380c-4867-b95c-4d53d70d4a93"> After: <img width="1310" alt="Screenshot 2024-04-22 at 00 40 33" src="https://github.com/go-gitea/gitea/assets/115237/2ba7b9f2-db2f-4bcc-8cce-5c415625ddea"> --- templates/projects/list.tmpl | 4 ++-- templates/projects/view.tmpl | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/templates/projects/list.tmpl b/templates/projects/list.tmpl index ec02e9a6fc..b2f48fe2c9 100644 --- a/templates/projects/list.tmpl +++ b/templates/projects/list.tmpl @@ -41,9 +41,9 @@ <div class="milestone-list"> {{range .Projects}} <li class="milestone-card"> - <h3 class="flex-text-block tw-m-0"> + <h3 class="flex-text-block tw-m-0 tw-gap-3"> {{svg .IconName 16}} - <a class="muted" href="{{.Link ctx}}">{{.Title}}</a> + <a class="muted tw-break-anywhere" href="{{.Link ctx}}">{{.Title}}</a> </h3> <div class="milestone-toolbar"> <div class="group"> diff --git a/templates/projects/view.tmpl b/templates/projects/view.tmpl index f9b85360e0..3e000660e2 100644 --- a/templates/projects/view.tmpl +++ b/templates/projects/view.tmpl @@ -1,8 +1,8 @@ {{$canWriteProject := and .CanWriteProjects (or (not .Repository) (not .Repository.IsArchived))}} -<div class="ui container"> - <div class="tw-flex tw-justify-between tw-items-center tw-mb-4"> - <h2 class="tw-mb-0">{{.Project.Title}}</h2> +<div class="ui container tw-max-w-full"> + <div class="tw-flex tw-justify-between tw-items-center tw-mb-4 tw-gap-3"> + <h2 class="tw-mb-0 tw-flex-1 tw-break-anywhere">{{.Project.Title}}</h2> {{if $canWriteProject}} <div class="ui compact mini menu"> <a class="item" href="{{.Link}}/edit?redirect=project"> From 9b7af4340c36d3e1888788499d16f83feeb1601b Mon Sep 17 00:00:00 2001 From: Kemal Zebari <60799661+kemzeb@users.noreply.github.com> Date: Tue, 23 Apr 2024 00:10:01 -0700 Subject: [PATCH 186/370] Perform Newest sort type correctly when sorting issues (#30644) Should resolve #30642. Before this commit, we were treating an empty `?sort=` query parameter as the correct sorting type (which is to sort issues in descending order by their created UNIX time). But when we perform `sort=latest`, we did not include this as a type so we would sort by the most recently updated when reaching the `default` switch statement block. This commit fixes this by considering the empty string, "latest", and just any other string that is not mentioned in the switch statement as sorting by newest. --- modules/indexer/issues/dboptions.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/indexer/issues/dboptions.go b/modules/indexer/issues/dboptions.go index 4a98b4588a..8f94088742 100644 --- a/modules/indexer/issues/dboptions.go +++ b/modules/indexer/issues/dboptions.go @@ -68,7 +68,7 @@ func ToSearchOptions(keyword string, opts *issues_model.IssuesOptions) *SearchOp searchOpt.Paginator = opts.Paginator switch opts.SortType { - case "": + case "", "latest": searchOpt.SortBy = SortByCreatedDesc case "oldest": searchOpt.SortBy = SortByCreatedAsc @@ -86,7 +86,7 @@ func ToSearchOptions(keyword string, opts *issues_model.IssuesOptions) *SearchOp searchOpt.SortBy = SortByDeadlineDesc case "priority", "priorityrepo", "project-column-sorting": // Unsupported sort type for search - searchOpt.SortBy = SortByUpdatedDesc + fallthrough default: searchOpt.SortBy = SortByUpdatedDesc } From dd2aaadce3ecd3134a1ba0c82c5aaa05d6c11b2b Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Tue, 23 Apr 2024 16:31:51 +0800 Subject: [PATCH 187/370] Fix flash message for flex-container (#30657) --- templates/admin/layout_head.tmpl | 4 +--- templates/user/dashboard/dashboard.tmpl | 2 +- web_src/css/base.css | 6 ------ 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/templates/admin/layout_head.tmpl b/templates/admin/layout_head.tmpl index c1f5fb3314..7cc6624d50 100644 --- a/templates/admin/layout_head.tmpl +++ b/templates/admin/layout_head.tmpl @@ -1,11 +1,9 @@ {{template "base/head" .ctxData}} <div role="main" aria-label="{{.ctxData.Title}}" class="page-content {{.pageClass}}"> - <div class="ui container"> - {{template "base/alert" .ctxData}} - </div> <div class="ui container fluid padded flex-container"> {{template "admin/navbar" .ctxData}} <div class="flex-container-main"> + {{template "base/alert" .ctxData}} {{/* block: admin-setting-content */}} {{if false}}{{/* to make html structure "likely" complete to prevent IDE warnings */}} diff --git a/templates/user/dashboard/dashboard.tmpl b/templates/user/dashboard/dashboard.tmpl index 415423d436..5dc46dc0a5 100644 --- a/templates/user/dashboard/dashboard.tmpl +++ b/templates/user/dashboard/dashboard.tmpl @@ -1,9 +1,9 @@ {{template "base/head" .}} <div role="main" aria-label="{{.Title}}" class="page-content dashboard feeds"> {{template "user/dashboard/navbar" .}} - {{template "base/alert" .}} <div class="ui container flex-container"> <div class="flex-container-main"> + {{template "base/alert" .}} {{template "user/heatmap" .}} {{template "user/dashboard/feeds" .}} </div> diff --git a/web_src/css/base.css b/web_src/css/base.css index 35f1781866..58a5723cb5 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -495,12 +495,6 @@ img.ui.avatar, margin-top: calc(var(--page-spacing) - 1rem); } -/* add horizontal margin to elements that are outside top-level of .flex-container or .ui.container */ -.page-content > .flash-message { - margin-left: var(--page-margin-x); - margin-right: var(--page-margin-x); -} - .ui.form .fields.error .field textarea, .ui.form .fields.error .field select, .ui.form .fields.error .field input:not([type]), From b79e3db264e5734d8cc038be898d45186b3afcbd Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Wed, 24 Apr 2024 00:18:41 +0800 Subject: [PATCH 188/370] Initial support for colorblindness-friendly themes (#30625) Initial support for #25680 This PR only adds some simple styles from GitHub, it is big enough and it focuses on adding the necessary framework-level supports. More styles could be fine-tuned later. --- custom/conf/app.example.ini | 3 +- .../config-cheat-sheet.en-us.md | 5 +- .../config-cheat-sheet.zh-cn.md | 5 +- .../administration/customizing-gitea.en-us.md | 2 +- docs/content/help/faq.en-us.md | 11 --- docs/content/help/faq.zh-cn.md | 11 --- modules/setting/config_provider.go | 6 +- modules/setting/oauth2.go | 2 +- modules/setting/setting.go | 2 +- modules/setting/ui.go | 1 - modules/templates/helper.go | 18 +++-- options/locale/locale_en-US.ini | 2 + routers/web/user/setting/profile.go | 11 ++- routers/web/web.go | 2 +- services/context/context.go | 1 + services/forms/user_form.go | 17 +---- services/webtheme/webtheme.go | 74 +++++++++++++++++++ templates/base/head.tmpl | 2 +- templates/base/head_style.tmpl | 2 +- templates/status/500.tmpl | 4 +- templates/user/settings/appearance.tmpl | 43 ++++------- ...eme-gitea-dark-protanopia-deuteranopia.css | 11 +++ ...me-gitea-light-protanopia-deuteranopia.css | 11 +++ 23 files changed, 154 insertions(+), 92 deletions(-) create mode 100644 services/webtheme/webtheme.go create mode 100644 web_src/css/themes/theme-gitea-dark-protanopia-deuteranopia.css create mode 100644 web_src/css/themes/theme-gitea-light-protanopia-deuteranopia.css diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index b4e330184e..12588c1387 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1231,7 +1231,8 @@ LEVEL = Info ;DEFAULT_THEME = gitea-auto ;; ;; All available themes. Allow users select personalized themes regardless of the value of `DEFAULT_THEME`. -;THEMES = gitea-auto,gitea-light,gitea-dark +;; Leave it empty to allow users to select any theme from "{CustomPath}/public/assets/css/theme-*.css" +;THEMES = ;; ;; All available reactions users can choose on issues/prs and comments. ;; Values can be emoji alias (:smile:) or a unicode emoji. diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index 9328177f50..b295ddf53a 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -214,10 +214,9 @@ The following configuration set `Content-Type: application/vnd.android.package-a - `SITEMAP_PAGING_NUM`: **20**: Number of items that are displayed in a single subsitemap. - `GRAPH_MAX_COMMIT_NUM`: **100**: Number of maximum commits shown in the commit graph. - `CODE_COMMENT_LINES`: **4**: Number of line of codes shown for a code comment. -- `DEFAULT_THEME`: **gitea-auto**: \[gitea-auto, gitea-light, gitea-dark\]: Set the default theme for the Gitea installation. +- `DEFAULT_THEME`: **gitea-auto**: Set the default theme for the Gitea installation, custom themes could be provided by "{CustomPath}/public/assets/css/theme-*.css". - `SHOW_USER_EMAIL`: **true**: Whether the email of the user should be shown in the Explore Users page. -- `THEMES`: **gitea-auto,gitea-light,gitea-dark**: All available themes. Allow users select personalized themes. - regardless of the value of `DEFAULT_THEME`. +- `THEMES`: **_empty_**: All available themes by "{CustomPath}/public/assets/css/theme-*.css". Allow users select personalized themes. - `MAX_DISPLAY_FILE_SIZE`: **8388608**: Max size of files to be displayed (default is 8MiB) - `AMBIGUOUS_UNICODE_DETECTION`: **true**: Detect ambiguous unicode characters in file contents and show warnings on the UI - `REACTIONS`: All available reactions users can choose on issues/prs and comments diff --git a/docs/content/administration/config-cheat-sheet.zh-cn.md b/docs/content/administration/config-cheat-sheet.zh-cn.md index e4945dd1c1..0d08a5e51b 100644 --- a/docs/content/administration/config-cheat-sheet.zh-cn.md +++ b/docs/content/administration/config-cheat-sheet.zh-cn.md @@ -212,10 +212,9 @@ menu: - `SITEMAP_PAGING_NUM`: **20**: 在单个子SiteMap中显示的项数。 - `GRAPH_MAX_COMMIT_NUM`: **100**: 提交图中显示的最大commit数量。 - `CODE_COMMENT_LINES`: **4**: 在代码评论中能够显示的最大代码行数。 -- `DEFAULT_THEME`: **gitea-auto**: \[gitea-auto, gitea-light, gitea-dark\]: 在Gitea安装时候设置的默认主题。 +- `DEFAULT_THEME`: **gitea-auto**: 在Gitea安装时候设置的默认主题,自定义的主题可以通过 "{CustomPath}/public/assets/css/theme-*.css" 提供。 - `SHOW_USER_EMAIL`: **true**: 用户的电子邮件是否应该显示在`Explore Users`页面中。 -- `THEMES`: **gitea-auto,gitea-light,gitea-dark**: 所有可用的主题。允许用户选择个性化的主题, - 而不受DEFAULT_THEME 值的影响。 +- `THEMES`: **_empty_**: 所有可用的主题(由 "{CustomPath}/public/assets/css/theme-*.css" 提供)。允许用户选择个性化的主题, - `MAX_DISPLAY_FILE_SIZE`: **8388608**: 能够显示文件的最大大小(默认为8MiB)。 - `REACTIONS`: 用户可以在问题(Issue)、Pull Request(PR)以及评论中选择的所有可选的反应。 这些值可以是表情符号别名(例如::smile:)或Unicode表情符号。 diff --git a/docs/content/administration/customizing-gitea.en-us.md b/docs/content/administration/customizing-gitea.en-us.md index 7efddb2824..8475f6d131 100644 --- a/docs/content/administration/customizing-gitea.en-us.md +++ b/docs/content/administration/customizing-gitea.en-us.md @@ -381,7 +381,7 @@ To make a custom theme available to all users: 1. Add a CSS file to `$GITEA_CUSTOM/public/assets/css/theme-<theme-name>.css`. The value of `$GITEA_CUSTOM` of your instance can be queried by calling `gitea help` and looking up the value of "CustomPath". -2. Add `<theme-name>` to the comma-separated list of setting `THEMES` in `app.ini` +2. Add `<theme-name>` to the comma-separated list of setting `THEMES` in `app.ini`, or leave `THEMES` empty to allow all themes. Community themes are listed in [gitea/awesome-gitea#themes](https://gitea.com/gitea/awesome-gitea#themes). diff --git a/docs/content/help/faq.en-us.md b/docs/content/help/faq.en-us.md index b3b0980125..ba39ec83b0 100644 --- a/docs/content/help/faq.en-us.md +++ b/docs/content/help/faq.en-us.md @@ -178,17 +178,6 @@ At some point, a customer or third party needs access to a specific repo and onl Use [Fail2Ban](administration/fail2ban-setup.md) to monitor and stop automated login attempts or other malicious behavior based on log patterns -## How to add/use custom themes - -Gitea supports three official themes right now, `gitea-light`, `gitea-dark`, and `gitea-auto` (automatically switches between the previous two depending on operating system settings). -To add your own theme, currently the only way is to provide a complete theme (not just color overrides) - -As an example, let's say our theme is `arc-blue` (this is a real theme, and can be found [in this issue](https://github.com/go-gitea/gitea/issues/6011)) - -Name the `.css` file `theme-arc-blue.css` and add it to your custom folder in `custom/public/assets/css` - -Allow users to use it by adding `arc-blue` to the list of `THEMES` in your `app.ini` - ## SSHD vs built-in SSH SSHD is the built-in SSH server on most Unix systems. diff --git a/docs/content/help/faq.zh-cn.md b/docs/content/help/faq.zh-cn.md index 25230df70b..ef8a149ae2 100644 --- a/docs/content/help/faq.zh-cn.md +++ b/docs/content/help/faq.zh-cn.md @@ -182,17 +182,6 @@ Gitea不提供内置的Pages服务器。您需要一个专用的域名来提供 使用 [Fail2Ban](administration/fail2ban-setup.md) 监视并阻止基于日志模式的自动登录尝试或其他恶意行为。 -## 如何添加/使用自定义主题 - -Gitea 目前支持三个官方主题,分别是 `gitea-light`、`gitea-dark` 和 `gitea-auto`(根据操作系统设置自动切换前两个主题)。 -要添加自己的主题,目前唯一的方法是提供一个完整的主题(不仅仅是颜色覆盖)。 - -假设我们的主题是 `arc-blue`(这是一个真实的主题,可以在[此问题](https://github.com/go-gitea/gitea/issues/6011)中找到) - -将`.css`文件命名为`theme-arc-blue.css`并将其添加到`custom/public/assets/css`文件夹中 - -通过将`arc-blue`添加到`app.ini`中的`THEMES`列表中,允许用户使用该主题 - ## SSHD vs 内建SSH SSHD是大多数Unix系统上内建的SSH服务器。 diff --git a/modules/setting/config_provider.go b/modules/setting/config_provider.go index 03f27ba203..3138f8a63e 100644 --- a/modules/setting/config_provider.go +++ b/modules/setting/config_provider.go @@ -318,7 +318,7 @@ func mustMapSetting(rootCfg ConfigProvider, sectionName string, setting any) { // StartupProblems contains the messages for various startup problems, including: setting option, file/folder, etc var StartupProblems []string -func logStartupProblem(skip int, level log.Level, format string, args ...any) { +func LogStartupProblem(skip int, level log.Level, format string, args ...any) { msg := fmt.Sprintf(format, args...) log.Log(skip+1, level, "%s", msg) StartupProblems = append(StartupProblems, msg) @@ -326,14 +326,14 @@ func logStartupProblem(skip int, level log.Level, format string, args ...any) { func deprecatedSetting(rootCfg ConfigProvider, oldSection, oldKey, newSection, newKey, version string) { if rootCfg.Section(oldSection).HasKey(oldKey) { - logStartupProblem(1, log.ERROR, "Deprecation: config option `[%s].%s` presents, please use `[%s].%s` instead because this fallback will be/has been removed in %s", oldSection, oldKey, newSection, newKey, version) + LogStartupProblem(1, log.ERROR, "Deprecation: config option `[%s].%s` presents, please use `[%s].%s` instead because this fallback will be/has been removed in %s", oldSection, oldKey, newSection, newKey, version) } } // deprecatedSettingDB add a hint that the configuration has been moved to database but still kept in app.ini func deprecatedSettingDB(rootCfg ConfigProvider, oldSection, oldKey string) { if rootCfg.Section(oldSection).HasKey(oldKey) { - logStartupProblem(1, log.ERROR, "Deprecation: config option `[%s].%s` presents but it won't take effect because it has been moved to admin panel -> config setting", oldSection, oldKey) + LogStartupProblem(1, log.ERROR, "Deprecation: config option `[%s].%s` presents but it won't take effect because it has been moved to admin panel -> config setting", oldSection, oldKey) } } diff --git a/modules/setting/oauth2.go b/modules/setting/oauth2.go index 6930197b22..34e1a336dc 100644 --- a/modules/setting/oauth2.go +++ b/modules/setting/oauth2.go @@ -174,7 +174,7 @@ func GetGeneralTokenSigningSecret() []byte { } if generalSigningSecret.CompareAndSwap(old, &jwtSecret) { // FIXME: in main branch, the signing token should be refactored (eg: one unique for LFS/OAuth2/etc ...) - logStartupProblem(1, log.WARN, "OAuth2 is not enabled, unable to use a persistent signing secret, a new one is generated, which is not persistent between restarts and cluster nodes") + LogStartupProblem(1, log.WARN, "OAuth2 is not enabled, unable to use a persistent signing secret, a new one is generated, which is not persistent between restarts and cluster nodes") return jwtSecret } return *generalSigningSecret.Load() diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 92bb0b6541..f056fbfc6c 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -235,7 +235,7 @@ var configuredPaths = make(map[string]string) func checkOverlappedPath(name, path string) { // TODO: some paths shouldn't overlap (storage.xxx.path), while some could (data path is the base path for storage path) if targetName, ok := configuredPaths[path]; ok && targetName != name { - logStartupProblem(1, log.ERROR, "Configured path %q is used by %q and %q at the same time. The paths must be unique to prevent data loss.", path, targetName, name) + LogStartupProblem(1, log.ERROR, "Configured path %q is used by %q and %q at the same time. The paths must be unique to prevent data loss.", path, targetName, name) } configuredPaths[path] = name } diff --git a/modules/setting/ui.go b/modules/setting/ui.go index 2f9eef93c3..93855bca07 100644 --- a/modules/setting/ui.go +++ b/modules/setting/ui.go @@ -82,7 +82,6 @@ var UI = struct { ReactionMaxUserNum: 10, MaxDisplayFileSize: 8388608, DefaultTheme: `gitea-auto`, - Themes: []string{`gitea-auto`, `gitea-light`, `gitea-dark`}, Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`}, CustomEmojis: []string{`git`, `gitea`, `codeberg`, `gitlab`, `github`, `gogs`}, CustomEmojisMap: map[string]string{"git": ":git:", "gitea": ":gitea:", "codeberg": ":codeberg:", "gitlab": ":gitlab:", "github": ":github:", "gogs": ":gogs:"}, diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 360b48c594..94464fe628 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -22,6 +22,7 @@ import ( "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/gitdiff" + "code.gitea.io/gitea/services/webtheme" ) // NewFuncMap returns functions for injecting to templates @@ -137,12 +138,7 @@ func NewFuncMap() template.FuncMap { "DisableImportLocal": func() bool { return !setting.ImportLocalPaths }, - "ThemeName": func(user *user_model.User) string { - if user == nil || user.Theme == "" { - return setting.UI.DefaultTheme - } - return user.Theme - }, + "UserThemeName": UserThemeName, "NotificationSettings": func() map[string]any { return map[string]any{ "MinTimeout": int(setting.UI.Notification.MinTimeout / time.Millisecond), @@ -261,3 +257,13 @@ func Eval(tokens ...any) (any, error) { n, err := eval.Expr(tokens...) return n.Value, err } + +func UserThemeName(user *user_model.User) string { + if user == nil || user.Theme == "" { + return setting.UI.DefaultTheme + } + if webtheme.IsThemeAvailable(user.Theme) { + return user.Theme + } + return setting.UI.DefaultTheme +} diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index c7d99a85b1..4f17b1a6db 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -763,6 +763,8 @@ manage_themes = Select default theme manage_openid = Manage OpenID Addresses email_desc = Your primary email address will be used for notifications, password recovery and, provided that it is not hidden, web-based Git operations. theme_desc = This will be your default theme across the site. +theme_colorblindness_help = Colorblindness Theme Support +theme_colorblindness_prompt = Gitea just gets some themes with basic colorblindness support, which only have a few colors defined. The work is still in progress. More improvements could be done by defining more colors in the theme CSS files. primary = Primary activated = Activated requires_activation = Requires activation diff --git a/routers/web/user/setting/profile.go b/routers/web/user/setting/profile.go index 49eb050dcb..e5ff8570cf 100644 --- a/routers/web/user/setting/profile.go +++ b/routers/web/user/setting/profile.go @@ -31,6 +31,7 @@ import ( "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" user_service "code.gitea.io/gitea/services/user" + "code.gitea.io/gitea/services/webtheme" ) const ( @@ -319,6 +320,13 @@ func Appearance(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("settings.appearance") ctx.Data["PageIsSettingsAppearance"] = true + allThemes := webtheme.GetAvailableThemes() + if webtheme.IsThemeAvailable(setting.UI.DefaultTheme) { + allThemes = util.SliceRemoveAll(allThemes, setting.UI.DefaultTheme) + allThemes = append([]string{setting.UI.DefaultTheme}, allThemes...) // move the default theme to the top + } + ctx.Data["AllThemes"] = allThemes + var hiddenCommentTypes *big.Int val, err := user_model.GetUserSetting(ctx, ctx.Doer.ID, user_model.SettingsKeyHiddenCommentTypes) if err != nil { @@ -341,11 +349,12 @@ func UpdateUIThemePost(ctx *context.Context) { ctx.Data["PageIsSettingsAppearance"] = true if ctx.HasError() { + ctx.Flash.Error(ctx.GetErrMsg()) ctx.Redirect(setting.AppSubURL + "/user/settings/appearance") return } - if !form.IsThemeExists() { + if !webtheme.IsThemeAvailable(form.Theme) { ctx.Flash.Error(ctx.Tr("settings.theme_update_error")) ctx.Redirect(setting.AppSubURL + "/user/settings/appearance") return diff --git a/routers/web/web.go b/routers/web/web.go index 994e639e20..c6132f0d61 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -652,7 +652,7 @@ func registerRoutes(m *web.Route) { m.Get("", user_setting.BlockedUsers) m.Post("", web.Bind(forms.BlockUserForm{}), user_setting.BlockedUsersPost) }) - }, reqSignIn, ctxDataSet("PageIsUserSettings", true, "AllThemes", setting.UI.Themes, "EnablePackages", setting.Packages.Enabled)) + }, reqSignIn, ctxDataSet("PageIsUserSettings", true, "EnablePackages", setting.Packages.Enabled)) m.Group("/user", func() { m.Get("/activate", auth.Activate) diff --git a/services/context/context.go b/services/context/context.go index 1641e995fb..88ab5cae0e 100644 --- a/services/context/context.go +++ b/services/context/context.go @@ -230,6 +230,7 @@ func Contexter() func(next http.Handler) http.Handler { // HasError returns true if error occurs in form validation. // Attention: this function changes ctx.Data and ctx.Flash +// If HasError is called, then before Redirect, the error message should be stored by ctx.Flash.Error(ctx.GetErrMsg()) again. func (ctx *Context) HasError() bool { hasErr, ok := ctx.Data["HasError"] if !ok { diff --git a/services/forms/user_form.go b/services/forms/user_form.go index e2e6c208f7..418a87b863 100644 --- a/services/forms/user_form.go +++ b/services/forms/user_form.go @@ -11,7 +11,6 @@ import ( auth_model "code.gitea.io/gitea/models/auth" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web/middleware" "code.gitea.io/gitea/services/context" @@ -273,7 +272,7 @@ func (f *AddEmailForm) Validate(req *http.Request, errs binding.Errors) binding. // UpdateThemeForm form for updating a users' theme type UpdateThemeForm struct { - Theme string `binding:"Required;MaxSize(30)"` + Theme string `binding:"Required;MaxSize(255)"` } // Validate validates the field @@ -282,20 +281,6 @@ func (f *UpdateThemeForm) Validate(req *http.Request, errs binding.Errors) bindi return middleware.Validate(errs, ctx.Data, f, ctx.Locale) } -// IsThemeExists checks if the theme is a theme available in the config. -func (f UpdateThemeForm) IsThemeExists() bool { - var exists bool - - for _, v := range setting.UI.Themes { - if strings.EqualFold(v, f.Theme) { - exists = true - break - } - } - - return exists -} - // ChangePasswordForm form for changing password type ChangePasswordForm struct { OldPassword string `form:"old_password" binding:"MaxSize(255)"` diff --git a/services/webtheme/webtheme.go b/services/webtheme/webtheme.go new file mode 100644 index 0000000000..dc801e1ff7 --- /dev/null +++ b/services/webtheme/webtheme.go @@ -0,0 +1,74 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package webtheme + +import ( + "sort" + "strings" + "sync" + + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/public" + "code.gitea.io/gitea/modules/setting" +) + +var ( + availableThemes []string + availableThemesSet container.Set[string] + themeOnce sync.Once +) + +func initThemes() { + availableThemes = nil + defer func() { + availableThemesSet = container.SetOf(availableThemes...) + if !availableThemesSet.Contains(setting.UI.DefaultTheme) { + setting.LogStartupProblem(1, log.ERROR, "Default theme %q is not available, please correct the '[ui].DEFAULT_THEME' setting in the config file", setting.UI.DefaultTheme) + } + }() + cssFiles, err := public.AssetFS().ListFiles("/assets/css") + if err != nil { + log.Error("Failed to list themes: %v", err) + availableThemes = []string{setting.UI.DefaultTheme} + return + } + var foundThemes []string + for _, name := range cssFiles { + name, ok := strings.CutPrefix(name, "theme-") + if !ok { + continue + } + name, ok = strings.CutSuffix(name, ".css") + if !ok { + continue + } + foundThemes = append(foundThemes, name) + } + if len(setting.UI.Themes) > 0 { + allowedThemes := container.SetOf(setting.UI.Themes...) + for _, theme := range foundThemes { + if allowedThemes.Contains(theme) { + availableThemes = append(availableThemes, theme) + } + } + } else { + availableThemes = foundThemes + } + sort.Strings(availableThemes) + if len(availableThemes) == 0 { + setting.LogStartupProblem(1, log.ERROR, "No theme candidate in asset files, but Gitea requires there should be at least one usable theme") + availableThemes = []string{setting.UI.DefaultTheme} + } +} + +func GetAvailableThemes() []string { + themeOnce.Do(initThemes) + return availableThemes +} + +func IsThemeAvailable(name string) bool { + themeOnce.Do(initThemes) + return availableThemesSet.Contains(name) +} diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl index 2de8f58235..174267fd2f 100644 --- a/templates/base/head.tmpl +++ b/templates/base/head.tmpl @@ -1,5 +1,5 @@ <!DOCTYPE html> -<html lang="{{ctx.Locale.Lang}}" data-theme="{{ThemeName .SignedUser}}"> +<html lang="{{ctx.Locale.Lang}}" data-theme="{{UserThemeName .SignedUser}}"> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{{if .Title}}{{.Title}} - {{end}}{{if .Repository.Name}}{{.Repository.Name}} - {{end}}{{AppName}}</title> diff --git a/templates/base/head_style.tmpl b/templates/base/head_style.tmpl index 0793eaca20..f97e1880ce 100644 --- a/templates/base/head_style.tmpl +++ b/templates/base/head_style.tmpl @@ -1,2 +1,2 @@ <link rel="stylesheet" href="{{AssetUrlPrefix}}/css/index.css?v={{AssetVersion}}"> -<link rel="stylesheet" href="{{AssetUrlPrefix}}/css/theme-{{ThemeName .SignedUser | PathEscape}}.css?v={{AssetVersion}}"> +<link rel="stylesheet" href="{{AssetUrlPrefix}}/css/theme-{{UserThemeName .SignedUser | PathEscape}}.css?v={{AssetVersion}}"> diff --git a/templates/status/500.tmpl b/templates/status/500.tmpl index 576b6eebbb..566fddcec1 100644 --- a/templates/status/500.tmpl +++ b/templates/status/500.tmpl @@ -1,12 +1,12 @@ {{/* This page should only depend the minimal template functions/variables, to avoid triggering new panics. -* base template functions: AppName, AssetUrlPrefix, AssetVersion, AppSubUrl, ThemeName +* base template functions: AppName, AssetUrlPrefix, AssetVersion, AppSubUrl, UserThemeName * ctx.Locale * .Flash * .ErrorMsg * .SignedUser (optional) */}} <!DOCTYPE html> -<html lang="{{ctx.Locale.Lang}}" data-theme="{{ThemeName .SignedUser}}"> +<html lang="{{ctx.Locale.Lang}}" data-theme="{{UserThemeName .SignedUser}}"> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Internal Server Error - {{AppName}}</title> diff --git a/templates/user/settings/appearance.tmpl b/templates/user/settings/appearance.tmpl index 0997d721e1..4fa248910a 100644 --- a/templates/user/settings/appearance.tmpl +++ b/templates/user/settings/appearance.tmpl @@ -1,4 +1,4 @@ -{{template "user/settings/layout_head" (dict "ctxData" . "pageClass" "user settings sshkeys")}} +{{template "user/settings/layout_head" (dict "ctxData" . "pageClass" "user settings")}} <div class="user-setting-content"> <!-- Theme --> @@ -6,39 +6,26 @@ {{ctx.Locale.Tr "settings.manage_themes"}} </h4> <div class="ui attached segment"> - <div class="ui email list"> - <div class="item"> - {{ctx.Locale.Tr "settings.theme_desc"}} - </div> - <form class="ui form" action="{{.Link}}/theme" method="post"> {{.CsrfTokenHtml}} - <div class="field"> - <label for="ui">{{ctx.Locale.Tr "settings.ui"}}</label> - <div class="ui selection dropdown" id="ui"> - <input name="theme" type="hidden" value="{{.SignedUser.Theme}}"> - {{svg "octicon-triangle-down" 14 "dropdown icon"}} - <div class="text"> - {{range $i,$a := .AllThemes}} - {{if eq $.SignedUser.Theme $a}}{{$a}}{{end}} - {{end}} - </div> - - <div class="menu"> - {{range $i,$a := .AllThemes}} - <div class="item{{if eq $.SignedUser.Theme $a}} active selected{{end}}" data-value="{{$a}}"> - {{$a}} - </div> - {{end}} - </div> - </div> - </div> - + <div class="field"> + {{ctx.Locale.Tr "settings.theme_desc"}} + <a class="muted" target="_blank" href="https://github.com/go-gitea/gitea/blob/main/web_src/css/themes/" data-tooltip-content="{{ctx.Locale.Tr "settings.theme_colorblindness_prompt"}}"> + {{svg "octicon-question"}} {{ctx.Locale.Tr "settings.theme_colorblindness_help"}} + </a> + </div> + <div class="field"> + <label>{{ctx.Locale.Tr "settings.ui"}}</label> + <select name="theme" class="ui dropdown"> + {{range $theme := .AllThemes}} + <option value="{{$theme}}" {{Iif (eq $.SignedUser.Theme $theme) "selected"}}>{{$theme}}</option> + {{end}} + </select> + </div> <div class="field"> <button class="ui primary button">{{ctx.Locale.Tr "settings.update_theme"}}</button> </div> </form> - </div> </div> <!-- Language --> diff --git a/web_src/css/themes/theme-gitea-dark-protanopia-deuteranopia.css b/web_src/css/themes/theme-gitea-dark-protanopia-deuteranopia.css new file mode 100644 index 0000000000..681aa3b539 --- /dev/null +++ b/web_src/css/themes/theme-gitea-dark-protanopia-deuteranopia.css @@ -0,0 +1,11 @@ +@import "./theme-gitea-dark.css"; + +/* red/green colorblind-friendly colors */ +/* from GitHub: --diffBlob-addition-*, --diffBlob-deletion-*, etc */ +:root { + --color-diff-added-word-bg: #388bfd66; + --color-diff-added-row-bg: #388bfd26; + + --color-diff-removed-word-bg: #db6d2866; + --color-diff-removed-row-bg: #db6d2826; +} diff --git a/web_src/css/themes/theme-gitea-light-protanopia-deuteranopia.css b/web_src/css/themes/theme-gitea-light-protanopia-deuteranopia.css new file mode 100644 index 0000000000..7e03d90f5c --- /dev/null +++ b/web_src/css/themes/theme-gitea-light-protanopia-deuteranopia.css @@ -0,0 +1,11 @@ +@import "./theme-gitea-light.css"; + +/* red/green colorblind-friendly colors */ +/* from GitHub: --diffBlob-addition-*, --diffBlob-deletion-*, etc */ +:root { + --color-diff-added-word-bg: #54aeff66; + --color-diff-added-row-bg: #ddf4ff80; + + --color-diff-removed-word-bg: #ffb77c80; + --color-diff-removed-row-bg: #fff1e580; +} From 2f6b1c46a1a4a90f56ca0f3ad7840e8e70daeab5 Mon Sep 17 00:00:00 2001 From: sillyguodong <33891828+sillyguodong@users.noreply.github.com> Date: Wed, 24 Apr 2024 02:55:25 +0800 Subject: [PATCH 189/370] Interpolate runs-on with variables when scheduling tasks (#30640) Follow #29468 1. Interpolate runs-on with variables when scheduling tasks. 2. The `GetVariablesOfRun` function will check if the `Repo` of the run is nil. --------- Co-authored-by: Giteabot <teabot@gitea.io> --- models/actions/run.go | 22 ++++++++++++++++------ models/actions/variable.go | 5 +++++ services/actions/schedule_tasks.go | 8 +++++++- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/models/actions/run.go b/models/actions/run.go index fa9db0b554..b75fa49f3c 100644 --- a/models/actions/run.go +++ b/models/actions/run.go @@ -98,13 +98,10 @@ func (run *ActionRun) LoadAttributes(ctx context.Context) error { return nil } - if run.Repo == nil { - repo, err := repo_model.GetRepositoryByID(ctx, run.RepoID) - if err != nil { - return err - } - run.Repo = repo + if err := run.LoadRepo(ctx); err != nil { + return err } + if err := run.Repo.LoadAttributes(ctx); err != nil { return err } @@ -120,6 +117,19 @@ func (run *ActionRun) LoadAttributes(ctx context.Context) error { return nil } +func (run *ActionRun) LoadRepo(ctx context.Context) error { + if run == nil || run.Repo != nil { + return nil + } + + repo, err := repo_model.GetRepositoryByID(ctx, run.RepoID) + if err != nil { + return err + } + run.Repo = repo + return nil +} + func (run *ActionRun) Duration() time.Duration { return calculateDuration(run.Started, run.Stopped, run.Status) + run.PreviousDuration } diff --git a/models/actions/variable.go b/models/actions/variable.go index b0a455e675..8aff844659 100644 --- a/models/actions/variable.go +++ b/models/actions/variable.go @@ -92,6 +92,11 @@ func DeleteVariable(ctx context.Context, id int64) error { func GetVariablesOfRun(ctx context.Context, run *ActionRun) (map[string]string, error) { variables := map[string]string{} + if err := run.LoadRepo(ctx); err != nil { + log.Error("LoadRepo: %v", err) + return nil, err + } + // Global globalVariables, err := db.Find[ActionVariable](ctx, FindVariablesOpts{}) if err != nil { diff --git a/services/actions/schedule_tasks.go b/services/actions/schedule_tasks.go index e4e56e5122..18f3324fd2 100644 --- a/services/actions/schedule_tasks.go +++ b/services/actions/schedule_tasks.go @@ -132,8 +132,14 @@ func CreateScheduleTask(ctx context.Context, cron *actions_model.ActionSchedule) Status: actions_model.StatusWaiting, } + vars, err := actions_model.GetVariablesOfRun(ctx, run) + if err != nil { + log.Error("GetVariablesOfRun: %v", err) + return err + } + // Parse the workflow specification from the cron schedule - workflows, err := jobparser.Parse(cron.Content) + workflows, err := jobparser.Parse(cron.Content, jobparser.WithVars(vars)) if err != nil { return err } From 2ee93ea17869de8fe24c6965fa3416ff30d55c5a Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Wed, 24 Apr 2024 03:24:10 +0800 Subject: [PATCH 190/370] Avoid doubled border for the PR info segment (#30663) --- templates/repo/issue/view_content/pull.tmpl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/templates/repo/issue/view_content/pull.tmpl b/templates/repo/issue/view_content/pull.tmpl index 117cd7b7a3..77378ef1bd 100644 --- a/templates/repo/issue/view_content/pull.tmpl +++ b/templates/repo/issue/view_content/pull.tmpl @@ -20,6 +20,7 @@ {{- else if .Issue.PullRequest.CanAutoMerge}}green {{- else}}red{{end}}">{{svg "octicon-git-merge" 40}}</div> <div class="content"> + {{if .LatestCommitStatus}} <div class="ui attached segment fitted"> {{template "repo/pulls/status" (dict "CommitStatus" .LatestCommitStatus @@ -29,8 +30,9 @@ "is_context_required" .is_context_required )}} </div> + {{end}} {{$showGeneralMergeForm := false}} - <div class="ui attached merge-section segment {{if not $.LatestCommitStatus}}no-header{{end}} flex-items-block"> + <div class="ui attached segment merge-section {{if not $.LatestCommitStatus}}no-header{{end}} flex-items-block"> {{if .Issue.PullRequest.HasMerged}} {{if .IsPullBranchDeletable}} <div class="item item-section text tw-flex-1"> From 1a2ae64b16f10b8d1e17197d18b9eb373faf58db Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Tue, 23 Apr 2024 23:53:57 +0200 Subject: [PATCH 191/370] Fix checkbox field markup (#30666) Fixes https://github.com/go-gitea/gitea/issues/30664. Previous use was not a supported way by fomantic and the misuse only became visible after the checkbox migration. --- .../user/settings/applications_oauth2_edit_form.tmpl | 8 +++++--- templates/user/settings/applications_oauth2_list.tmpl | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/templates/user/settings/applications_oauth2_edit_form.tmpl b/templates/user/settings/applications_oauth2_edit_form.tmpl index f7ef115693..199d43a65c 100644 --- a/templates/user/settings/applications_oauth2_edit_form.tmpl +++ b/templates/user/settings/applications_oauth2_edit_form.tmpl @@ -41,9 +41,11 @@ <label for="redirect-uris">{{ctx.Locale.Tr "settings.oauth2_redirect_uris"}}</label> <textarea name="redirect_uris" id="redirect-uris" required>{{StringUtils.Join .App.RedirectURIs "\n"}}</textarea> </div> - <div class="field ui checkbox {{if .Err_ConfidentialClient}}error{{end}}"> - <label>{{ctx.Locale.Tr "settings.oauth2_confidential_client"}}</label> - <input type="checkbox" name="confidential_client" {{if .App.ConfidentialClient}}checked{{end}}> + <div class="field {{if .Err_ConfidentialClient}}error{{end}}"> + <div class="ui checkbox"> + <label>{{ctx.Locale.Tr "settings.oauth2_confidential_client"}}</label> + <input type="checkbox" name="confidential_client" {{if .App.ConfidentialClient}}checked{{end}}> + </div> </div> <button class="ui primary button"> {{ctx.Locale.Tr "settings.save_application"}} diff --git a/templates/user/settings/applications_oauth2_list.tmpl b/templates/user/settings/applications_oauth2_list.tmpl index cfcb6d053d..c75cbd532e 100644 --- a/templates/user/settings/applications_oauth2_list.tmpl +++ b/templates/user/settings/applications_oauth2_list.tmpl @@ -61,9 +61,11 @@ <label for="redirect-uris">{{ctx.Locale.Tr "settings.oauth2_redirect_uris"}}</label> <textarea name="redirect_uris" id="redirect-uris"></textarea> </div> - <div class="field ui checkbox {{if .Err_ConfidentialClient}}error{{end}}"> - <label>{{ctx.Locale.Tr "settings.oauth2_confidential_client"}}</label> - <input type="checkbox" name="confidential_client" checked> + <div class="field {{if .Err_ConfidentialClient}}error{{end}}"> + <div class="ui checkbox"> + <label>{{ctx.Locale.Tr "settings.oauth2_confidential_client"}}</label> + <input type="checkbox" name="confidential_client" checked> + </div> </div> <button class="ui primary button"> {{ctx.Locale.Tr "settings.create_oauth2_application_button"}} From 2ad9ef4984f0b68ef38241fd6b557d8427d851d8 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Wed, 24 Apr 2024 09:58:24 +0800 Subject: [PATCH 192/370] Fix some bug on migrations (#30647) Fix https://github.com/go-gitea/gitea/pull/23894#discussion_r1573718690 --- models/migrations/v1_16/v210.go | 5 ----- models/migrations/v1_22/v286.go | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/models/migrations/v1_16/v210.go b/models/migrations/v1_16/v210.go index 533bb4bf80..51b7d81e99 100644 --- a/models/migrations/v1_16/v210.go +++ b/models/migrations/v1_16/v210.go @@ -43,11 +43,6 @@ func RemigrateU2FCredentials(x *xorm.Engine) error { if err != nil { return err } - case schemas.ORACLE: - _, err := x.Exec("ALTER TABLE webauthn_credential MODIFY credential_id VARCHAR(410)") - if err != nil { - return err - } case schemas.MSSQL: // This column has an index on it. I could write all of the code to attempt to change the index OR // I could just use recreate table. diff --git a/models/migrations/v1_22/v286.go b/models/migrations/v1_22/v286.go index fbbd87344f..f46d494dfe 100644 --- a/models/migrations/v1_22/v286.go +++ b/models/migrations/v1_22/v286.go @@ -53,7 +53,7 @@ func expandHashReferencesToSha256(x *xorm.Engine) error { if setting.Database.Type.IsMySQL() { _, err = db.Exec(fmt.Sprintf("ALTER TABLE `%s` MODIFY COLUMN `%s` VARCHAR(64)", alts[0], alts[1])) } else if setting.Database.Type.IsMSSQL() { - _, err = db.Exec(fmt.Sprintf("ALTER TABLE [%s] ALTER COLUMN [%s] VARCHAR(64)", alts[0], alts[1])) + _, err = db.Exec(fmt.Sprintf("ALTER TABLE [%s] ALTER COLUMN [%s] NVARCHAR(64)", alts[0], alts[1])) } else { _, err = db.Exec(fmt.Sprintf("ALTER TABLE `%s` ALTER COLUMN `%s` TYPE VARCHAR(64)", alts[0], alts[1])) } From 8b3632435ef72c351af34a154b13511b34323471 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Wed, 24 Apr 2024 13:26:50 +0800 Subject: [PATCH 193/370] Fix a panic bug when head repository deleting (#30674) When visiting a pull request files which head repository has been deleted, it will panic because headrepo is nil. --- routers/web/repo/pull.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 71f25db11b..acdba4bcdc 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -863,21 +863,21 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi if pull.HeadRepo != nil { ctx.Data["SourcePath"] = pull.HeadRepo.Link() + "/src/branch/" + util.PathEscapeSegments(pull.HeadBranch) - } - if !pull.HasMerged && ctx.Doer != nil { - perm, err := access_model.GetUserRepoPermission(ctx, pull.HeadRepo, ctx.Doer) - if err != nil { - ctx.ServerError("GetUserRepoPermission", err) - return - } + if !pull.HasMerged && ctx.Doer != nil { + perm, err := access_model.GetUserRepoPermission(ctx, pull.HeadRepo, ctx.Doer) + if err != nil { + ctx.ServerError("GetUserRepoPermission", err) + return + } - if perm.CanWrite(unit.TypeCode) || issues_model.CanMaintainerWriteToBranch(ctx, perm, pull.HeadBranch, ctx.Doer) { - ctx.Data["CanEditFile"] = true - ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.edit_this_file") - ctx.Data["HeadRepoLink"] = pull.HeadRepo.Link() - ctx.Data["HeadBranchName"] = pull.HeadBranch - ctx.Data["BackToLink"] = setting.AppSubURL + ctx.Req.URL.RequestURI() + if perm.CanWrite(unit.TypeCode) || issues_model.CanMaintainerWriteToBranch(ctx, perm, pull.HeadBranch, ctx.Doer) { + ctx.Data["CanEditFile"] = true + ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.edit_this_file") + ctx.Data["HeadRepoLink"] = pull.HeadRepo.Link() + ctx.Data["HeadBranchName"] = pull.HeadBranch + ctx.Data["BackToLink"] = setting.AppSubURL + ctx.Req.URL.RequestURI() + } } } } From 3f19a6334575e1d2849999e8339f1b515cefaf1a Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Wed, 24 Apr 2024 15:11:52 +0200 Subject: [PATCH 194/370] Fix border-radius of header+segment boxes (#30667) This is a very old bug with the bottom border-radiuses not being there and the `:has` selector now makes it possible to cleanly solve it. It affects all header+segment boxes, which there are many throughout the UI: <img width="1017" alt="Screenshot 2024-04-23 at 20 47 21" src="https://github.com/go-gitea/gitea/assets/115237/870fe352-cc38-4bd6-bfe6-9fe8c3066f92"> --- web_src/css/modules/segment.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/web_src/css/modules/segment.css b/web_src/css/modules/segment.css index bbd39c385f..994ac1779a 100644 --- a/web_src/css/modules/segment.css +++ b/web_src/css/modules/segment.css @@ -151,6 +151,11 @@ border-top: none; } +.ui.attached.segment:has(+ .ui[class*="top attached"].header), +.ui.attached.segment:last-child { + border-radius: 0 0 0.28571429rem 0.28571429rem; +} + .ui[class*="top attached"].segment { bottom: 0; margin-bottom: 0; From a19d2bbd90dd22a897220425a1221af8ed065ba7 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Wed, 24 Apr 2024 22:11:49 +0800 Subject: [PATCH 195/370] Add test for #30674 (#30679) --- tests/integration/pull_compare_test.go | 35 ++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/integration/pull_compare_test.go b/tests/integration/pull_compare_test.go index 5ce8ea3031..b814207b2f 100644 --- a/tests/integration/pull_compare_test.go +++ b/tests/integration/pull_compare_test.go @@ -5,8 +5,14 @@ package integration import ( "net/http" + "net/url" "testing" + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + repo_service "code.gitea.io/gitea/services/repository" "code.gitea.io/gitea/tests" "github.com/stretchr/testify/assert" @@ -32,4 +38,33 @@ func TestPullCompare(t *testing.T) { doc := NewHTMLParser(t, resp.Body) editButtonCount := doc.doc.Find(".diff-file-header-actions a[href*='/_edit/']").Length() assert.Greater(t, editButtonCount, 0, "Expected to find a button to edit a file in the PR diff view but there were none") + + onGiteaRun(t, func(t *testing.T, u *url.URL) { + defer tests.PrepareTestEnv(t)() + + session := loginUser(t, "user1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testCreateBranch(t, session, "user1", "repo1", "branch/master", "master1", http.StatusSeeOther) + testEditFile(t, session, "user1", "repo1", "master1", "README.md", "Hello, World (Edited)\n") + resp = testPullCreate(t, session, "user1", "repo1", false, "master", "master1", "This is a pull title") + + // the max value on issue_index.yml for repo_id=1 is 5 + req = NewRequest(t, "GET", "/user2/repo1/pulls/6/files") + resp = session.MakeRequest(t, req, http.StatusOK) + doc := NewHTMLParser(t, resp.Body) + editButtonCount := doc.doc.Find(".diff-file-header-actions a[href*='/_edit/']").Length() + assert.Greater(t, editButtonCount, 0, "Expected to find a button to edit a file in the PR diff view but there were none") + + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repoForked := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user1", Name: "repo1"}) + // delete the head repository and revisit the PR diff view + err := repo_service.DeleteRepositoryDirectly(db.DefaultContext, user2, repoForked.ID) + assert.NoError(t, err) + + req = NewRequest(t, "GET", "/user2/repo1/pulls/6/files") + resp = session.MakeRequest(t, req, http.StatusOK) + doc = NewHTMLParser(t, resp.Body) + editButtonCount = doc.doc.Find(".diff-file-header-actions a[href*='/_edit/']").Length() + assert.EqualValues(t, editButtonCount, 0, "Expected not to find a button to edit a file in the PR diff view because head repository has been deleted") + }) } From a63f14b90839821a480fb56fd9b45a27864b77d1 Mon Sep 17 00:00:00 2001 From: Jiaxin Zhu <shin00pku@gmail.com> Date: Thu, 25 Apr 2024 08:07:38 +0800 Subject: [PATCH 196/370] Fix view of readme file in the home code page. (#30564) Gitea attempts to display image file, pdf file, etc. named readme in the home code page (but it cannot). I think only the markdown and plain-text file should be displayed, which is also the behavior of GitHub. Co-authored-by: jxshin <zhujiaxinabc@gmail.com> --- templates/repo/view_list.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/view_list.tmpl b/templates/repo/view_list.tmpl index fb257bd474..7ec9acc84e 100644 --- a/templates/repo/view_list.tmpl +++ b/templates/repo/view_list.tmpl @@ -68,6 +68,6 @@ {{end}} </tbody> </table> -{{if .ReadmeExist}} +{{if and .ReadmeExist (or .IsMarkup .IsPlainText)}} {{template "repo/view_file" .}} {{end}} From 4ff54933f8093f1c1d84797d687ccb640739ec32 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Thu, 25 Apr 2024 00:26:13 +0000 Subject: [PATCH 197/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_pt-PT.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 64798d6d65..4b7604a5cb 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -763,6 +763,8 @@ manage_themes=Escolher o tema padrão manage_openid=Gerir endereços OpenID email_desc=O seu endereço de email principal irá ser usado para notificações, recuperação de senha e, desde que não esteja oculto, operações Git baseados na web. theme_desc=Este será o seu tema padrão em todo o sítio. +theme_colorblindness_help=Suporte a temas para daltónicos +theme_colorblindness_prompt=O Gitea acabou de obter alguns temas com suporte básico para daltónicos que têm apenas algumas cores definidas. O trabalho ainda está em andamento. Poderiam ser feitos mais melhoramentos se fossem definidas mais cores nos ficheiros CSS do tema. primary=Principal activated=Em uso requires_activation=Tem que ser habilitado From c685eefe4a8ff6e32bc859a3457a5090f58ea8c5 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Thu, 25 Apr 2024 17:14:23 +0800 Subject: [PATCH 198/370] If a repository return no commitstatus, then still cache it but not query it from database (#30700) The previous repository default branch commit status cache will only store if the commit status has value. So the repository which have no any commit status will always be fetched from database. This PR will store the empty state of commit status of a repository into cache because the cache will be updated once there is a commit status stored. --- .../repository/commitstatus/commitstatus.go | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/services/repository/commitstatus/commitstatus.go b/services/repository/commitstatus/commitstatus.go index 8a62a603d4..444ae04d0c 100644 --- a/services/repository/commitstatus/commitstatus.go +++ b/services/repository/commitstatus/commitstatus.go @@ -38,12 +38,10 @@ func getCommitStatusCache(repoID int64, branchName string) *commitStatusCacheVal if ok && statusStr != "" { var cv commitStatusCacheValue err := json.Unmarshal([]byte(statusStr), &cv) - if err == nil && cv.State != "" { + if err == nil { return &cv } - if err != nil { - log.Warn("getCommitStatusCache: json.Unmarshal failed: %v", err) - } + log.Warn("getCommitStatusCache: json.Unmarshal failed: %v", err) } return nil } @@ -128,15 +126,22 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato // FindReposLastestCommitStatuses loading repository default branch latest combinded commit status with cache func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Repository) ([]*git_model.CommitStatus, error) { results := make([]*git_model.CommitStatus, len(repos)) + allCached := true for i, repo := range repos { if cv := getCommitStatusCache(repo.ID, repo.DefaultBranch); cv != nil { results[i] = &git_model.CommitStatus{ State: api.CommitStatusState(cv.State), TargetURL: cv.TargetURL, } + } else { + allCached = false } } + if allCached { + return results, nil + } + // collect the latest commit of each repo // at most there are dozens of repos (limited by MaxResponseItems), so it's not a big problem at the moment repoBranchNames := make(map[int64]string, len(repos)) @@ -165,10 +170,10 @@ func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Rep for i, repo := range repos { if repo.ID == summary.RepoID { results[i] = summary - _ = slices.DeleteFunc(repoSHAs, func(repoSHA git_model.RepoSHA) bool { + repoSHAs = slices.DeleteFunc(repoSHAs, func(repoSHA git_model.RepoSHA) bool { return repoSHA.RepoID == repo.ID }) - if results[i].State != "" { + if results[i] != nil { if err := updateCommitStatusCache(repo.ID, repo.DefaultBranch, results[i].State, results[i].TargetURL); err != nil { log.Error("updateCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err) } @@ -177,6 +182,9 @@ func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Rep } } } + if len(repoSHAs) == 0 { + return results, nil + } // call the database O(1) times to get the commit statuses for all repos repoToItsLatestCommitStatuses, err := git_model.GetLatestCommitStatusForPairs(ctx, repoSHAs) @@ -187,7 +195,7 @@ func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Rep for i, repo := range repos { if results[i] == nil { results[i] = git_model.CalcCommitStatus(repoToItsLatestCommitStatuses[repo.ID]) - if results[i].State != "" { + if results[i] != nil { if err := updateCommitStatusCache(repo.ID, repo.DefaultBranch, results[i].State, results[i].TargetURL); err != nil { log.Error("updateCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err) } From d0bfc978de802683b9a44720b7f5a8a8394d38be Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Thu, 25 Apr 2024 12:53:39 +0200 Subject: [PATCH 199/370] Fix active item in tab menu (#30690) Before, item would also resize on hover because of font weight: <img width="381" alt="Screenshot 2024-04-25 at 01 28 53" src="https://github.com/go-gitea/gitea/assets/115237/4f3291fc-90be-4d66-ae8b-3c2f763cb956"> After: <img width="381" alt="Screenshot 2024-04-25 at 01 28 40" src="https://github.com/go-gitea/gitea/assets/115237/06145bf2-1ddd-4171-9217-d92c100ea405"> Co-authored-by: Giteabot <teabot@gitea.io> --- web_src/css/modules/menu.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/css/modules/menu.css b/web_src/css/modules/menu.css index a392ffb5e9..e393ec5186 100644 --- a/web_src/css/modules/menu.css +++ b/web_src/css/modules/menu.css @@ -403,7 +403,7 @@ background: var(--color-body); border-top-width: 1px; border-color: var(--color-secondary); - font-weight: var(--font-weight-medium); + color: var(--color-text-dark); margin-bottom: -1px; border-radius: 0.28571429rem 0.28571429rem 0 0 !important; } From bffbbf547063fa170cc52ae2e757d5badb336632 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Thu, 25 Apr 2024 19:22:32 +0800 Subject: [PATCH 200/370] Improve oauth2 client "preferred username field" logic and the error handling (#30622) Follow #30454 And fix #24957 When using "preferred_username", if no such field, `extractUserNameFromOAuth2` (old `getUserName`) shouldn't return an error. All other USERNAME options do not return such error. And fine tune some logic and error messages, make code more stable and more friendly to end users. --- custom/conf/app.example.ini | 4 +- .../config-cheat-sheet.en-us.md | 2 +- models/unittest/testdb.go | 5 +++ models/user/user.go | 18 ++++----- models/user/user_test.go | 7 ++-- modules/session/mock.go | 26 ++++++++++++ modules/session/store.go | 23 ++++++++++- modules/setting/oauth2.go | 14 +++---- options/locale/locale_en-US.ini | 1 + routers/web/auth/auth.go | 14 +++---- routers/web/auth/auth_test.go | 40 +++++++++++++++++++ routers/web/auth/linkaccount.go | 20 ++++++---- routers/web/auth/oauth.go | 37 ++++++++++------- services/context/context.go | 5 +-- services/contexttest/context_tests.go | 14 +++++-- templates/user/auth/link_account.tmpl | 11 ++--- 16 files changed, 173 insertions(+), 68 deletions(-) create mode 100644 modules/session/mock.go diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 12588c1387..62db26fb02 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1558,8 +1558,8 @@ LEVEL = Info ;; email = use the username part of the email attribute ;; Note: `nickname`, `preferred_username` and `email` options will normalize input strings using the following criteria: ;; - diacritics are removed -;; - the characters in the set `['´\x60]` are removed -;; - the characters in the set `[\s~+]` are replaced with `-` +;; - the characters in the set ['´`] are removed +;; - the characters in the set [\s~+] are replaced with "-" ;USERNAME = nickname ;; ;; Update avatar if available from oauth2 provider. diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index b295ddf53a..14f562fc21 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -612,7 +612,7 @@ And the following unique queues: - `email` - use the username part of the email attribute - Note: `nickname`, `preferred_username` and `email` options will normalize input strings using the following criteria: - diacritics are removed - - the characters in the set `['´\x60]` are removed + - the characters in the set ```['´`]``` are removed - the characters in the set `[\s~+]` are replaced with `-` - `UPDATE_AVATAR`: **false**: Update avatar if available from oauth2 provider. Update will be performed on each login. - `ACCOUNT_LINKING`: **login**: How to handle if an account / email already exists: diff --git a/models/unittest/testdb.go b/models/unittest/testdb.go index cb90c12f2b..51de18fa9b 100644 --- a/models/unittest/testdb.go +++ b/models/unittest/testdb.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/models/system" "code.gitea.io/gitea/modules/auth/password/hash" "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting/config" @@ -106,6 +107,7 @@ func MainTest(m *testing.M, testOpts ...*TestOptions) { fatalTestError("Error creating test engine: %v\n", err) } + setting.IsInTesting = true setting.AppURL = "https://try.gitea.io/" setting.RunUser = "runuser" setting.SSH.User = "sshuser" @@ -148,6 +150,9 @@ func MainTest(m *testing.M, testOpts ...*TestOptions) { config.SetDynGetter(system.NewDatabaseDynKeyGetter()) + if err = cache.Init(); err != nil { + fatalTestError("cache.Init: %v\n", err) + } if err = storage.Init(); err != nil { fatalTestError("storage.Init: %v\n", err) } diff --git a/models/user/user.go b/models/user/user.go index 7056aecab0..a5a5b5bdf6 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -501,19 +501,19 @@ func GetUserSalt() (string, error) { // Note: The set of characters here can safely expand without a breaking change, // but characters removed from this set can cause user account linking to break var ( - customCharsReplacement = strings.NewReplacer("Æ", "AE") - removeCharsRE = regexp.MustCompile(`['´\x60]`) - removeDiacriticsTransform = transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC) - replaceCharsHyphenRE = regexp.MustCompile(`[\s~+]`) + customCharsReplacement = strings.NewReplacer("Æ", "AE") + removeCharsRE = regexp.MustCompile("['`´]") + transformDiacritics = transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC) + replaceCharsHyphenRE = regexp.MustCompile(`[\s~+]`) ) -// normalizeUserName returns a string with single-quotes and diacritics -// removed, and any other non-supported username characters replaced with -// a `-` character +// NormalizeUserName only takes the name part if it is an email address, transforms it diacritics to ASCII characters. +// It returns a string with the single-quotes removed, and any other non-supported username characters are replaced with a `-` character func NormalizeUserName(s string) (string, error) { - strDiacriticsRemoved, n, err := transform.String(removeDiacriticsTransform, customCharsReplacement.Replace(s)) + s, _, _ = strings.Cut(s, "@") + strDiacriticsRemoved, n, err := transform.String(transformDiacritics, customCharsReplacement.Replace(s)) if err != nil { - return "", fmt.Errorf("Failed to normalize character `%v` in provided username `%v`", s[n], s) + return "", fmt.Errorf("failed to normalize the string of provided username %q at position %d", s, n) } return replaceCharsHyphenRE.ReplaceAllLiteralString(removeCharsRE.ReplaceAllLiteralString(strDiacriticsRemoved, ""), "-"), nil } diff --git a/models/user/user_test.go b/models/user/user_test.go index a4550fa655..b4ffa1f322 100644 --- a/models/user/user_test.go +++ b/models/user/user_test.go @@ -506,15 +506,16 @@ func Test_NormalizeUserFromEmail(t *testing.T) { Expected string IsNormalizedValid bool }{ - {"test", "test", true}, + {"name@example.com", "name", true}, + {"test'`´name", "testname", true}, {"Sinéad.O'Connor", "Sinead.OConnor", true}, {"Æsir", "AEsir", true}, - // \u00e9\u0065\u0301 - {"éé", "ee", true}, + {"éé", "ee", true}, // \u00e9\u0065\u0301 {"Awareness Hub", "Awareness-Hub", true}, {"double__underscore", "double__underscore", false}, // We should consider squashing double non-alpha characters {".bad.", ".bad.", false}, {"new😀user", "new😀user", false}, // No plans to support + {`"quoted"`, `"quoted"`, false}, // No plans to support } for _, testCase := range testCases { normalizedName, err := user_model.NormalizeUserName(testCase.Input) diff --git a/modules/session/mock.go b/modules/session/mock.go new file mode 100644 index 0000000000..95231a3655 --- /dev/null +++ b/modules/session/mock.go @@ -0,0 +1,26 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package session + +import ( + "net/http" + + "gitea.com/go-chi/session" +) + +type MockStore struct { + *session.MemStore +} + +func (m *MockStore) Destroy(writer http.ResponseWriter, request *http.Request) error { + return nil +} + +type mockStoreContextKeyStruct struct{} + +var MockStoreContextKey = mockStoreContextKeyStruct{} + +func NewMockStore(sid string) *MockStore { + return &MockStore{session.NewMemStore(sid)} +} diff --git a/modules/session/store.go b/modules/session/store.go index 70988fcdc5..09d1ef44dd 100644 --- a/modules/session/store.go +++ b/modules/session/store.go @@ -6,6 +6,8 @@ package session import ( "net/http" + "code.gitea.io/gitea/modules/setting" + "gitea.com/go-chi/session" ) @@ -14,6 +16,10 @@ type Store interface { Get(any) any Set(any, any) error Delete(any) error + ID() string + Release() error + Flush() error + Destroy(http.ResponseWriter, *http.Request) error } // RegenerateSession regenerates the underlying session and returns the new store @@ -21,8 +27,21 @@ func RegenerateSession(resp http.ResponseWriter, req *http.Request) (Store, erro for _, f := range BeforeRegenerateSession { f(resp, req) } - s, err := session.RegenerateSession(resp, req) - return s, err + if setting.IsInTesting { + if store, ok := req.Context().Value(MockStoreContextKey).(*MockStore); ok { + return store, nil + } + } + return session.RegenerateSession(resp, req) +} + +func GetContextSession(req *http.Request) Store { + if setting.IsInTesting { + if store, ok := req.Context().Value(MockStoreContextKey).(*MockStore); ok { + return store + } + } + return session.GetSession(req) } // BeforeRegenerateSession is a list of functions that are called before a session is regenerated. diff --git a/modules/setting/oauth2.go b/modules/setting/oauth2.go index 34e1a336dc..e59f54420b 100644 --- a/modules/setting/oauth2.go +++ b/modules/setting/oauth2.go @@ -16,14 +16,10 @@ import ( type OAuth2UsernameType string const ( - // OAuth2UsernameUserid oauth2 userid field will be used as gitea name - OAuth2UsernameUserid OAuth2UsernameType = "userid" - // OAuth2UsernameNickname oauth2 nickname field will be used as gitea name - OAuth2UsernameNickname OAuth2UsernameType = "nickname" - // OAuth2UsernameEmail username of oauth2 email field will be used as gitea name - OAuth2UsernameEmail OAuth2UsernameType = "email" - // OAuth2UsernameEmail username of oauth2 preferred_username field will be used as gitea name - OAuth2UsernamePreferredUsername OAuth2UsernameType = "preferred_username" + OAuth2UsernameUserid OAuth2UsernameType = "userid" // use user id (sub) field as gitea's username + OAuth2UsernameNickname OAuth2UsernameType = "nickname" // use nickname field + OAuth2UsernameEmail OAuth2UsernameType = "email" // use email field + OAuth2UsernamePreferredUsername OAuth2UsernameType = "preferred_username" // use preferred_username field ) func (username OAuth2UsernameType) isValid() bool { @@ -71,8 +67,8 @@ func loadOAuth2ClientFrom(rootCfg ConfigProvider) { OAuth2Client.EnableAutoRegistration = sec.Key("ENABLE_AUTO_REGISTRATION").MustBool() OAuth2Client.Username = OAuth2UsernameType(sec.Key("USERNAME").MustString(string(OAuth2UsernameNickname))) if !OAuth2Client.Username.isValid() { - log.Warn("Username setting is not valid: '%s', will fallback to '%s'", OAuth2Client.Username, OAuth2UsernameNickname) OAuth2Client.Username = OAuth2UsernameNickname + log.Warn("[oauth2_client].USERNAME setting is invalid, falls back to %q", OAuth2Client.Username) } OAuth2Client.UpdateAvatar = sec.Key("UPDATE_AVATAR").MustBool() OAuth2Client.AccountLinking = OAuth2AccountLinkingType(sec.Key("ACCOUNT_LINKING").MustString(string(OAuth2AccountLinkingLogin))) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 4f17b1a6db..fb591be393 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -436,6 +436,7 @@ oauth_signin_submit = Link Account oauth.signin.error = There was an error processing the authorization request. If this error persists, please contact the site administrator. oauth.signin.error.access_denied = The authorization request was denied. oauth.signin.error.temporarily_unavailable = Authorization failed because the authentication server is temporarily unavailable. Please try again later. +oauth_callback_unable_auto_reg = Auto Registration is enabled, but OAuth2 Provider %[1]s returned missing fields: %[2]s, unable to create an account automatically, please create or link to an account, or contact the site administrator. openid_connect_submit = Connect openid_connect_title = Connect to an existing account openid_connect_desc = The chosen OpenID URI is unknown. Associate it with a new account here. diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 9ef32ebdb1..7c873796fe 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -382,17 +382,17 @@ func handleSignInFull(ctx *context.Context, u *user_model.User, remember, obeyRe return setting.AppSubURL + "/" } -func getUserName(gothUser *goth.User) (string, error) { +// extractUserNameFromOAuth2 tries to extract a normalized username from the given OAuth2 user. +// It returns ("", nil) if the required field doesn't exist. +func extractUserNameFromOAuth2(gothUser *goth.User) (string, error) { switch setting.OAuth2Client.Username { case setting.OAuth2UsernameEmail: - return user_model.NormalizeUserName(strings.Split(gothUser.Email, "@")[0]) + return user_model.NormalizeUserName(gothUser.Email) case setting.OAuth2UsernamePreferredUsername: - preferredUsername, exists := gothUser.RawData["preferred_username"] - if exists { - return user_model.NormalizeUserName(preferredUsername.(string)) - } else { - return "", fmt.Errorf("preferred_username is missing in received user data but configured as username source for user_id %q. Check if OPENID_CONNECT_SCOPES contains profile", gothUser.UserID) + if preferredUsername, ok := gothUser.RawData["preferred_username"].(string); ok { + return user_model.NormalizeUserName(preferredUsername) } + return "", nil case setting.OAuth2UsernameNickname: return user_model.NormalizeUserName(gothUser.NickName) default: // OAuth2UsernameUserid diff --git a/routers/web/auth/auth_test.go b/routers/web/auth/auth_test.go index c6afbf877c..45525a5c6f 100644 --- a/routers/web/auth/auth_test.go +++ b/routers/web/auth/auth_test.go @@ -8,12 +8,31 @@ import ( "net/url" "testing" + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/session" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/test" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/auth/source/oauth2" "code.gitea.io/gitea/services/contexttest" + "github.com/markbates/goth" + "github.com/markbates/goth/gothic" "github.com/stretchr/testify/assert" ) +func addOAuth2Source(t *testing.T, authName string, cfg oauth2.Source) { + cfg.Provider = util.IfZero(cfg.Provider, "gitea") + err := auth_model.CreateSource(db.DefaultContext, &auth_model.Source{ + Type: auth_model.OAuth2, + Name: authName, + IsActive: true, + Cfg: &cfg, + }) + assert.NoError(t, err) +} + func TestUserLogin(t *testing.T) { ctx, resp := contexttest.MockContext(t, "/user/login") SignIn(ctx) @@ -41,3 +60,24 @@ func TestUserLogin(t *testing.T) { SignIn(ctx) assert.Equal(t, "/", test.RedirectURL(resp)) } + +func TestSignUpOAuth2ButMissingFields(t *testing.T) { + defer test.MockVariableValue(&setting.OAuth2Client.EnableAutoRegistration, true)() + defer test.MockVariableValue(&gothic.CompleteUserAuth, func(res http.ResponseWriter, req *http.Request) (goth.User, error) { + return goth.User{Provider: "dummy-auth-source", UserID: "dummy-user"}, nil + })() + + addOAuth2Source(t, "dummy-auth-source", oauth2.Source{}) + + mockOpt := contexttest.MockContextOption{SessionStore: session.NewMockStore("dummy-sid")} + ctx, resp := contexttest.MockContext(t, "/user/oauth2/dummy-auth-source/callback?code=dummy-code", mockOpt) + ctx.SetParams("provider", "dummy-auth-source") + SignInOAuthCallback(ctx) + assert.Equal(t, http.StatusSeeOther, resp.Code) + assert.Equal(t, "/user/link_account", test.RedirectURL(resp)) + + // then the user will be redirected to the link account page, and see a message about the missing fields + ctx, _ = contexttest.MockContext(t, "/user/link_account", mockOpt) + LinkAccount(ctx) + assert.EqualValues(t, "auth.oauth_callback_unable_auto_reg:dummy-auth-source,email", ctx.Data["AutoRegistrationFailedPrompt"]) +} diff --git a/routers/web/auth/linkaccount.go b/routers/web/auth/linkaccount.go index f744a57a43..24130df634 100644 --- a/routers/web/auth/linkaccount.go +++ b/routers/web/auth/linkaccount.go @@ -48,23 +48,27 @@ func LinkAccount(ctx *context.Context) { ctx.Data["SignInLink"] = setting.AppSubURL + "/user/link_account_signin" ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/link_account_signup" - gothUser := ctx.Session.Get("linkAccountGothUser") - if gothUser == nil { - ctx.ServerError("UserSignIn", errors.New("not in LinkAccount session")) + gothUser, ok := ctx.Session.Get("linkAccountGothUser").(goth.User) + if !ok { + // no account in session, so just redirect to the login page, then the user could restart the process + ctx.Redirect(setting.AppSubURL + "/user/login") return } - gu, _ := gothUser.(goth.User) - uname, err := getUserName(&gu) + if missingFields, ok := gothUser.RawData["__giteaAutoRegMissingFields"].([]string); ok { + ctx.Data["AutoRegistrationFailedPrompt"] = ctx.Tr("auth.oauth_callback_unable_auto_reg", gothUser.Provider, strings.Join(missingFields, ",")) + } + + uname, err := extractUserNameFromOAuth2(&gothUser) if err != nil { ctx.ServerError("UserSignIn", err) return } - email := gu.Email + email := gothUser.Email ctx.Data["user_name"] = uname ctx.Data["email"] = email - if len(email) != 0 { + if email != "" { u, err := user_model.GetUserByEmail(ctx, email) if err != nil && !user_model.IsErrUserNotExist(err) { ctx.ServerError("UserSignIn", err) @@ -73,7 +77,7 @@ func LinkAccount(ctx *context.Context) { if u != nil { ctx.Data["user_exists"] = true } - } else if len(uname) != 0 { + } else if uname != "" { u, err := user_model.GetUserByName(ctx, uname) if err != nil && !user_model.IsErrUserNotExist(err) { ctx.ServerError("UserSignIn", err) diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 3189d1372e..c9cb7859cd 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -934,7 +934,7 @@ func SignInOAuthCallback(ctx *context.Context) { if u == nil { if ctx.Doer != nil { - // attach user to already logged in user + // attach user to the current signed-in user err = externalaccount.LinkAccountToUser(ctx, ctx.Doer, gothUser) if err != nil { ctx.ServerError("UserLinkAccount", err) @@ -952,23 +952,32 @@ func SignInOAuthCallback(ctx *context.Context) { if gothUser.Email == "" { missingFields = append(missingFields, "email") } - if setting.OAuth2Client.Username == setting.OAuth2UsernameNickname && gothUser.NickName == "" { - missingFields = append(missingFields, "nickname") - } - if len(missingFields) > 0 { - log.Error("OAuth2 Provider %s returned empty or missing fields: %s", authSource.Name, missingFields) - if authSource.IsOAuth2() && authSource.Cfg.(*oauth2.Source).Provider == "openidConnect" { - log.Error("You may need to change the 'OPENID_CONNECT_SCOPES' setting to request all required fields") - } - err = fmt.Errorf("OAuth2 Provider %s returned empty or missing fields: %s", authSource.Name, missingFields) - ctx.ServerError("CreateUser", err) - return - } - uname, err := getUserName(&gothUser) + uname, err := extractUserNameFromOAuth2(&gothUser) if err != nil { ctx.ServerError("UserSignIn", err) return } + if uname == "" { + if setting.OAuth2Client.Username == setting.OAuth2UsernameNickname { + missingFields = append(missingFields, "nickname") + } else if setting.OAuth2Client.Username == setting.OAuth2UsernamePreferredUsername { + missingFields = append(missingFields, "preferred_username") + } // else: "UserID" and "Email" have been handled above separately + } + if len(missingFields) > 0 { + log.Error(`OAuth2 auto registration (ENABLE_AUTO_REGISTRATION) is enabled but OAuth2 provider %q doesn't return required fields: %s. `+ + `Suggest to: disable auto registration, or make OPENID_CONNECT_SCOPES (for OpenIDConnect) / Authentication Source Scopes (for Admin panel) to request all required fields, and the fields shouldn't be empty.`, + authSource.Name, strings.Join(missingFields, ",")) + // The RawData is the only way to pass the missing fields to the another page at the moment, other ways all have various problems: + // by session or cookie: difficult to clean or reset; by URL: could be injected with uncontrollable content; by ctx.Flash: the link_account page is a mess ... + // Since the RawData is for the provider's data, so we need to use our own prefix here to avoid conflict. + if gothUser.RawData == nil { + gothUser.RawData = make(map[string]any) + } + gothUser.RawData["__giteaAutoRegMissingFields"] = missingFields + showLinkingLogin(ctx, gothUser) + return + } u = &user_model.User{ Name: uname, FullName: gothUser.Name, diff --git a/services/context/context.go b/services/context/context.go index 88ab5cae0e..aab0485f1a 100644 --- a/services/context/context.go +++ b/services/context/context.go @@ -20,14 +20,13 @@ import ( "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/httpcache" + "code.gitea.io/gitea/modules/session" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web/middleware" web_types "code.gitea.io/gitea/modules/web/types" - - "gitea.com/go-chi/session" ) // Render represents a template render @@ -154,7 +153,7 @@ func Contexter() func(next http.Handler) http.Handler { return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { base, baseCleanUp := NewBaseContext(resp, req) defer baseCleanUp() - ctx := NewWebContext(base, rnd, session.GetSession(req)) + ctx := NewWebContext(base, rnd, session.GetContextSession(req)) ctx.Data.MergeFrom(middleware.CommonTemplateContextData()) ctx.Data["Context"] = ctx // TODO: use "ctx" in template and remove this diff --git a/services/contexttest/context_tests.go b/services/contexttest/context_tests.go index 3064c56590..0c1e5ee54f 100644 --- a/services/contexttest/context_tests.go +++ b/services/contexttest/context_tests.go @@ -19,7 +19,9 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/gitrepo" + "code.gitea.io/gitea/modules/session" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/web/middleware" @@ -43,7 +45,8 @@ func mockRequest(t *testing.T, reqPath string) *http.Request { } type MockContextOption struct { - Render context.Render + Render context.Render + SessionStore *session.MockStore } // MockContext mock context for unit tests @@ -62,12 +65,17 @@ func MockContext(t *testing.T, reqPath string, opts ...MockContextOption) (*cont base.Data = middleware.GetContextData(req.Context()) base.Locale = &translation.MockLocale{} + chiCtx := chi.NewRouteContext() ctx := context.NewWebContext(base, opt.Render, nil) ctx.AppendContextValue(context.WebContextKey, ctx) + ctx.AppendContextValue(chi.RouteCtxKey, chiCtx) + if opt.SessionStore != nil { + ctx.AppendContextValue(session.MockStoreContextKey, opt.SessionStore) + ctx.Session = opt.SessionStore + } + ctx.Cache = cache.GetCache() ctx.PageData = map[string]any{} ctx.Data["PageStartTime"] = time.Now() - chiCtx := chi.NewRouteContext() - ctx.Base.AppendContextValue(chi.RouteCtxKey, chiCtx) return ctx, resp } diff --git a/templates/user/auth/link_account.tmpl b/templates/user/auth/link_account.tmpl index 8dd49ccd60..a99e172d05 100644 --- a/templates/user/auth/link_account.tmpl +++ b/templates/user/auth/link_account.tmpl @@ -17,15 +17,12 @@ </overflow-menu> <div class="ui middle very relaxed page grid"> <div class="column"> - <div class="ui tab {{if not .user_exists}}active{{end}}" - data-tab="auth-link-signup-tab"> + <div class="ui tab {{if not .user_exists}}active{{end}}" data-tab="auth-link-signup-tab"> + {{if .AutoRegistrationFailedPrompt}}<div class="ui message">{{.AutoRegistrationFailedPrompt}}</div>{{end}} {{template "user/auth/signup_inner" .}} </div> - <div class="ui tab {{if .user_exists}}active{{end}}" - data-tab="auth-link-signin-tab"> - <div class="ui user signin container icon"> - {{template "user/auth/signin_inner" .}} - </div> + <div class="ui tab {{if .user_exists}}active{{end}}" data-tab="auth-link-signin-tab"> + {{template "user/auth/signin_inner" .}} </div> </div> </div> From fd63b96f6a4c5b3ea9e53d37af85e0d2d09715b9 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Thu, 25 Apr 2024 21:01:38 +0800 Subject: [PATCH 201/370] Refactor imagediff and fix regression bug (#30694) Fix #30683 --- web_src/js/features/imagediff.js | 204 +++++++++++++++---------------- 1 file changed, 102 insertions(+), 102 deletions(-) diff --git a/web_src/js/features/imagediff.js b/web_src/js/features/imagediff.js index 192a642834..d1b139ffde 100644 --- a/web_src/js/features/imagediff.js +++ b/web_src/js/features/imagediff.js @@ -1,6 +1,6 @@ import $ from 'jquery'; import {GET} from '../modules/fetch.js'; -import {hideElem, loadElem} from '../utils/dom.js'; +import {hideElem, loadElem, queryElemChildren} from '../utils/dom.js'; import {parseDom} from '../utils.js'; function getDefaultSvgBoundsIfUndefined(text, src) { @@ -38,36 +38,36 @@ function getDefaultSvgBoundsIfUndefined(text, src) { return null; } +function createContext(imageAfter, imageBefore) { + const sizeAfter = { + width: imageAfter?.width || 0, + height: imageAfter?.height || 0, + }; + const sizeBefore = { + width: imageBefore?.width || 0, + height: imageBefore?.height || 0, + }; + const maxSize = { + width: Math.max(sizeBefore.width, sizeAfter.width), + height: Math.max(sizeBefore.height, sizeAfter.height), + }; + + return { + imageAfter, + imageBefore, + sizeAfter, + sizeBefore, + maxSize, + ratio: [ + Math.floor(maxSize.width - sizeAfter.width) / 2, + Math.floor(maxSize.height - sizeAfter.height) / 2, + Math.floor(maxSize.width - sizeBefore.width) / 2, + Math.floor(maxSize.height - sizeBefore.height) / 2, + ], + }; +} + export function initImageDiff() { - function createContext(image1, image2) { - const size1 = { - width: image1 && image1.width || 0, - height: image1 && image1.height || 0, - }; - const size2 = { - width: image2 && image2.width || 0, - height: image2 && image2.height || 0, - }; - const max = { - width: Math.max(size2.width, size1.width), - height: Math.max(size2.height, size1.height), - }; - - return { - $image1: $(image1), - $image2: $(image2), - size1, - size2, - max, - ratio: [ - Math.floor(max.width - size1.width) / 2, - Math.floor(max.height - size1.height) / 2, - Math.floor(max.width - size2.width) / 2, - Math.floor(max.height - size2.height) / 2, - ], - }; - } - $('.image-diff:not([data-image-diff-loaded])').each(async function() { const $container = $(this); this.setAttribute('data-image-diff-loaded', 'true'); @@ -116,94 +116,96 @@ export function initImageDiff() { initOverlay(createContext($imagesAfter[2], $imagesBefore[2])); } - this.querySelector(':scope > .image-diff-tabs')?.classList.remove('is-loading'); + queryElemChildren(this, '.image-diff-tabs', (el) => el.classList.remove('is-loading')); function initSideBySide(container, sizes) { let factor = 1; - if (sizes.max.width > (diffContainerWidth - 24) / 2) { - factor = (diffContainerWidth - 24) / 2 / sizes.max.width; + if (sizes.maxSize.width > (diffContainerWidth - 24) / 2) { + factor = (diffContainerWidth - 24) / 2 / sizes.maxSize.width; } - const widthChanged = sizes.$image1.length !== 0 && sizes.$image2.length !== 0 && sizes.$image1[0].naturalWidth !== sizes.$image2[0].naturalWidth; - const heightChanged = sizes.$image1.length !== 0 && sizes.$image2.length !== 0 && sizes.$image1[0].naturalHeight !== sizes.$image2[0].naturalHeight; - if (sizes.$image1?.length) { + const widthChanged = sizes.imageAfter && sizes.imageBefore && sizes.imageAfter.naturalWidth !== sizes.imageBefore.naturalWidth; + const heightChanged = sizes.imageAfter && sizes.imageBefore && sizes.imageAfter.naturalHeight !== sizes.imageBefore.naturalHeight; + if (sizes.imageAfter) { const boundsInfoAfterWidth = container.querySelector('.bounds-info-after .bounds-info-width'); - boundsInfoAfterWidth.textContent = `${sizes.$image1[0].naturalWidth}px`; - if (widthChanged) boundsInfoAfterWidth.classList.add('green'); - + if (boundsInfoAfterWidth) { + boundsInfoAfterWidth.textContent = `${sizes.imageAfter.naturalWidth}px`; + boundsInfoAfterWidth.classList.toggle('green', widthChanged); + } const boundsInfoAfterHeight = container.querySelector('.bounds-info-after .bounds-info-height'); - boundsInfoAfterHeight.textContent = `${sizes.$image1[0].naturalHeight}px`; - if (heightChanged) boundsInfoAfterHeight.classList.add('green'); + if (boundsInfoAfterHeight) { + boundsInfoAfterHeight.textContent = `${sizes.imageAfter.naturalHeight}px`; + boundsInfoAfterHeight.classList.toggle('green', heightChanged); + } } - if (sizes.$image2?.length) { + if (sizes.imageBefore) { const boundsInfoBeforeWidth = container.querySelector('.bounds-info-before .bounds-info-width'); - boundsInfoBeforeWidth.textContent = `${sizes.$image2[0].naturalWidth}px`; - if (widthChanged) boundsInfoBeforeWidth.classList.add('red'); - + if (boundsInfoBeforeWidth) { + boundsInfoBeforeWidth.textContent = `${sizes.imageBefore.naturalWidth}px`; + boundsInfoBeforeWidth.classList.toggle('red', widthChanged); + } const boundsInfoBeforeHeight = container.querySelector('.bounds-info-before .bounds-info-height'); - boundsInfoBeforeHeight.textContent = `${sizes.$image2[0].naturalHeight}px`; - if (heightChanged) boundsInfoBeforeHeight.classList.add('red'); + if (boundsInfoBeforeHeight) { + boundsInfoBeforeHeight.textContent = `${sizes.imageBefore.naturalHeight}px`; + boundsInfoBeforeHeight.classList.add('red', heightChanged); + } } - const image1 = sizes.$image1[0]; - if (image1) { - const container = image1.parentNode; - image1.style.width = `${sizes.size1.width * factor}px`; - image1.style.height = `${sizes.size1.height * factor}px`; + if (sizes.imageAfter) { + const container = sizes.imageAfter.parentNode; + sizes.imageAfter.style.width = `${sizes.sizeAfter.width * factor}px`; + sizes.imageAfter.style.height = `${sizes.sizeAfter.height * factor}px`; container.style.margin = '10px auto'; - container.style.width = `${sizes.size1.width * factor + 2}px`; - container.style.height = `${sizes.size1.height * factor + 2}px`; + container.style.width = `${sizes.sizeAfter.width * factor + 2}px`; + container.style.height = `${sizes.sizeAfter.height * factor + 2}px`; } - const image2 = sizes.$image2[0]; - if (image2) { - const container = image2.parentNode; - image2.style.width = `${sizes.size2.width * factor}px`; - image2.style.height = `${sizes.size2.height * factor}px`; + if (sizes.imageBefore) { + const container = sizes.imageBefore.parentNode; + sizes.imageBefore.style.width = `${sizes.sizeBefore.width * factor}px`; + sizes.imageBefore.style.height = `${sizes.sizeBefore.height * factor}px`; container.style.margin = '10px auto'; - container.style.width = `${sizes.size2.width * factor + 2}px`; - container.style.height = `${sizes.size2.height * factor + 2}px`; + container.style.width = `${sizes.sizeBefore.width * factor + 2}px`; + container.style.height = `${sizes.sizeBefore.height * factor + 2}px`; } } function initSwipe(sizes) { let factor = 1; - if (sizes.max.width > diffContainerWidth - 12) { - factor = (diffContainerWidth - 12) / sizes.max.width; + if (sizes.maxSize.width > diffContainerWidth - 12) { + factor = (diffContainerWidth - 12) / sizes.maxSize.width; } - const image1 = sizes.$image1[0]; - if (image1) { - const container = image1.parentNode; + if (sizes.imageAfter) { + const container = sizes.imageAfter.parentNode; const swipeFrame = container.parentNode; - image1.style.width = `${sizes.size1.width * factor}px`; - image1.style.height = `${sizes.size1.height * factor}px`; + sizes.imageAfter.style.width = `${sizes.sizeAfter.width * factor}px`; + sizes.imageAfter.style.height = `${sizes.sizeAfter.height * factor}px`; container.style.margin = `0px ${sizes.ratio[0] * factor}px`; - container.style.width = `${sizes.size1.width * factor + 2}px`; - container.style.height = `${sizes.size1.height * factor + 2}px`; + container.style.width = `${sizes.sizeAfter.width * factor + 2}px`; + container.style.height = `${sizes.sizeAfter.height * factor + 2}px`; swipeFrame.style.padding = `${sizes.ratio[1] * factor}px 0 0 0`; - swipeFrame.style.width = `${sizes.max.width * factor + 2}px`; + swipeFrame.style.width = `${sizes.maxSize.width * factor + 2}px`; } - const image2 = sizes.$image2[0]; - if (image2) { - const container = image2.parentNode; + if (sizes.imageBefore) { + const container = sizes.imageBefore.parentNode; const swipeFrame = container.parentNode; - image2.style.width = `${sizes.size2.width * factor}px`; - image2.style.height = `${sizes.size2.height * factor}px`; + sizes.imageBefore.style.width = `${sizes.sizeBefore.width * factor}px`; + sizes.imageBefore.style.height = `${sizes.sizeBefore.height * factor}px`; container.style.margin = `${sizes.ratio[3] * factor}px ${sizes.ratio[2] * factor}px`; - container.style.width = `${sizes.size2.width * factor + 2}px`; - container.style.height = `${sizes.size2.height * factor + 2}px`; - swipeFrame.style.width = `${sizes.max.width * factor + 2}px`; - swipeFrame.style.height = `${sizes.max.height * factor + 2}px`; + container.style.width = `${sizes.sizeBefore.width * factor + 2}px`; + container.style.height = `${sizes.sizeBefore.height * factor + 2}px`; + swipeFrame.style.width = `${sizes.maxSize.width * factor + 2}px`; + swipeFrame.style.height = `${sizes.maxSize.height * factor + 2}px`; } // extra height for inner "position: absolute" elements const swipe = $container.find('.diff-swipe')[0]; if (swipe) { - swipe.style.width = `${sizes.max.width * factor + 2}px`; - swipe.style.height = `${sizes.max.height * factor + 30}px`; + swipe.style.width = `${sizes.maxSize.width * factor + 2}px`; + swipe.style.height = `${sizes.maxSize.height * factor + 30}px`; } $container.find('.swipe-bar').on('mousedown', function(e) { @@ -229,39 +231,37 @@ export function initImageDiff() { function initOverlay(sizes) { let factor = 1; - if (sizes.max.width > diffContainerWidth - 12) { - factor = (diffContainerWidth - 12) / sizes.max.width; + if (sizes.maxSize.width > diffContainerWidth - 12) { + factor = (diffContainerWidth - 12) / sizes.maxSize.width; } - const image1 = sizes.$image1[0]; - if (image1) { - const container = image1.parentNode; - image1.style.width = `${sizes.size1.width * factor}px`; - image1.style.height = `${sizes.size1.height * factor}px`; + if (sizes.imageAfter) { + const container = sizes.imageAfter.parentNode; + sizes.imageAfter.style.width = `${sizes.sizeAfter.width * factor}px`; + sizes.imageAfter.style.height = `${sizes.sizeAfter.height * factor}px`; container.style.margin = `${sizes.ratio[1] * factor}px ${sizes.ratio[0] * factor}px`; - container.style.width = `${sizes.size1.width * factor + 2}px`; - container.style.height = `${sizes.size1.height * factor + 2}px`; + container.style.width = `${sizes.sizeAfter.width * factor + 2}px`; + container.style.height = `${sizes.sizeAfter.height * factor + 2}px`; } - const image2 = sizes.$image2[0]; - if (image2) { - const container = image2.parentNode; + if (sizes.imageBefore) { + const container = sizes.imageBefore.parentNode; const overlayFrame = container.parentNode; - image2.style.width = `${sizes.size2.width * factor}px`; - image2.style.height = `${sizes.size2.height * factor}px`; + sizes.imageBefore.style.width = `${sizes.sizeBefore.width * factor}px`; + sizes.imageBefore.style.height = `${sizes.sizeBefore.height * factor}px`; container.style.margin = `${sizes.ratio[3] * factor}px ${sizes.ratio[2] * factor}px`; - container.style.width = `${sizes.size2.width * factor + 2}px`; - container.style.height = `${sizes.size2.height * factor + 2}px`; + container.style.width = `${sizes.sizeBefore.width * factor + 2}px`; + container.style.height = `${sizes.sizeBefore.height * factor + 2}px`; // some inner elements are `position: absolute`, so the container's height must be large enough - overlayFrame.style.width = `${sizes.max.width * factor + 2}px`; - overlayFrame.style.height = `${sizes.max.height * factor + 2}px`; + overlayFrame.style.width = `${sizes.maxSize.width * factor + 2}px`; + overlayFrame.style.height = `${sizes.maxSize.height * factor + 2}px`; } const rangeInput = $container[0].querySelector('input[type="range"]'); function updateOpacity() { - if (sizes?.$image1?.[0]) { - sizes.$image1[0].parentNode.style.opacity = `${rangeInput.value / 100}`; + if (sizes.imageAfter) { + sizes.imageAfter.parentNode.style.opacity = `${rangeInput.value / 100}`; } } rangeInput?.addEventListener('input', updateOpacity); From 935330b1b98a232f2928d55e96dc425e09bda593 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Fri, 26 Apr 2024 00:26:00 +0000 Subject: [PATCH 202/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_pt-PT.ini | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 4b7604a5cb..444f784af9 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -2358,7 +2358,7 @@ 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=Salvaguarda do ramo '<b>%s</b>' +settings.branch_protection=Regras de salvaguarda do ramo '<b>%s</b>' 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. settings.protect_disable_push=Desabilitar envios @@ -2402,7 +2402,7 @@ 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 em <a href='https://pkg.go.dev/github.com/gobwas/glob#Compile'>github.com/gobwas/glob</a> para ver a sintaxe. Exemplos: <code>.drone.yml</code>, <code>/docs/**/*.txt</code>. 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. Múltiplos padrões podem ser separados com ponto e vírgula (';'). Veja a documentação em <a href='https://pkg.go.dev/github.com/gobwas/glob#Compile'>github.com/gobwas/glob</a> para ver a sintaxe. Exemplos: <code>.drone.yml</code>, <code>/docs/**/*.txt</code>. +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 em <a href='https://pkg.go.dev/github.com/gobwas/glob#Compile'>github.com/gobwas/glob</a> para ver a sintaxe. Exemplos: <code>.drone.yml</code>, <code>/docs/**/*.txt</code>. settings.add_protected_branch=Habilitar salvaguarda settings.delete_protected_branch=Desabilitar salvaguarda settings.update_protect_branch_success=A salvaguarda do ramo "%s" foi modificada. @@ -2418,7 +2418,7 @@ settings.block_outdated_branch=Bloquear integração se o pedido de integração settings.block_outdated_branch_desc=A integração não será possível quando o ramo de topo estiver abaixo do ramo base. settings.default_branch_desc=Escolha um ramo do repositório como sendo o predefinido para pedidos de integração e cometimentos: settings.merge_style_desc=Estilos de integração -settings.default_merge_style_desc=Tipo de integração predefinido para pedidos de integração: +settings.default_merge_style_desc=Tipo de integração predefinido settings.choose_branch=Escolha um ramo… settings.no_protected_branch=Não existem ramos protegidos. settings.edit_protected_branch=Editar @@ -2788,7 +2788,7 @@ self_check=Auto-verificação identity_access=Identidade e acesso users=Contas de utilizador organizations=Organizações -assets=Recursos de código +assets=Recursos do código-fonte repositories=Repositórios hooks=Automatismos web integrations=Integrações @@ -2869,14 +2869,14 @@ dashboard.mspan_structures_obtained=Estruturas MSpan obtidas dashboard.mcache_structures_usage=Uso das estruturas MCache dashboard.mcache_structures_obtained=Estruturas MCache obtidas dashboard.profiling_bucket_hash_table_obtained=Perfil obtido da tabela de hash do balde -dashboard.gc_metadata_obtained=Metadados da recolha de lixo obtidos +dashboard.gc_metadata_obtained=Metadados obtidos da recolha de lixo dashboard.other_system_allocation_obtained=Outras alocações de sistema obtidas dashboard.next_gc_recycle=Próxima reciclagem da recolha de lixo dashboard.last_gc_time=Tempo decorrido desde a última recolha de lixo dashboard.total_gc_time=Pausa total da recolha de lixo dashboard.total_gc_pause=Pausa total da recolha de lixo dashboard.last_gc_pause=Última pausa da recolha de lixo -dashboard.gc_times=Tempos da recolha de lixo +dashboard.gc_times=N.º de recolhas de lixo dashboard.delete_old_actions=Eliminar todas as operações antigas da base de dados dashboard.delete_old_actions.started=Foi iniciado o processo de eliminação de todas as operações antigas da base de dados. dashboard.update_checker=Verificador de novas versões @@ -3025,7 +3025,7 @@ auths.attribute_surname=Atributo do Sobrenome auths.attribute_mail=Atributo do email auths.attribute_ssh_public_key=Atributo da chave pública SSH auths.attribute_avatar=Atributo do avatar -auths.attributes_in_bind=Buscar os atributos no contexto de Bind DN +auths.attributes_in_bind=Buscar atributos no contexto do Bind DN auths.allow_deactivate_all=Permitir que um resultado de pesquisa vazio desabilite todos os utilizadores auths.use_paged_search=Usar pesquisa paginada auths.search_page_size=Tamanho da página @@ -3224,7 +3224,7 @@ config.session_config=Configuração de sessão config.session_provider=Fornecedor da sessão config.provider_config=Configuração do fornecedor config.cookie_name=Nome do cookie -config.gc_interval_time=Intervalo da recolha do lixo +config.gc_interval_time=Intervalo de tempo entre recolhas do lixo config.session_life_time=Tempo de vida da sessão config.https_only=Apenas HTTPS config.cookie_life_time=Tempo de vida do cookie From 6a0750177fe4c494f828463bc146ea11df08a422 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Fri, 26 Apr 2024 09:17:43 +0800 Subject: [PATCH 203/370] Allow to save empty comment (#30706) Fix #29986 --- routers/web/repo/issue.go | 41 +++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 95f0cf3d71..1bc5f343e7 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -3149,13 +3149,10 @@ func UpdateCommentContent(ctx *context.Context) { } oldContent := comment.Content - comment.Content = ctx.FormString("content") - if len(comment.Content) == 0 { - ctx.JSON(http.StatusOK, map[string]any{ - "content": "", - }) - return - } + newContent := ctx.FormString("content") + + // allow to save empty content + comment.Content = newContent if err = issue_service.UpdateComment(ctx, comment, ctx.Doer, oldContent); err != nil { if errors.Is(err, user_model.ErrBlockedUser) { ctx.JSONError(ctx.Tr("repo.issues.comment.blocked_user")) @@ -3178,21 +3175,27 @@ func UpdateCommentContent(ctx *context.Context) { } } - content, err := markdown.RenderString(&markup.RenderContext{ - Links: markup.Links{ - Base: ctx.FormString("context"), // FIXME: <- IS THIS SAFE ? - }, - Metas: ctx.Repo.Repository.ComposeMetas(ctx), - GitRepo: ctx.Repo.GitRepo, - Ctx: ctx, - }, comment.Content) - if err != nil { - ctx.ServerError("RenderString", err) - return + var renderedContent template.HTML + if comment.Content != "" { + renderedContent, err = markdown.RenderString(&markup.RenderContext{ + Links: markup.Links{ + Base: ctx.FormString("context"), // FIXME: <- IS THIS SAFE ? + }, + Metas: ctx.Repo.Repository.ComposeMetas(ctx), + GitRepo: ctx.Repo.GitRepo, + Ctx: ctx, + }, comment.Content) + if err != nil { + ctx.ServerError("RenderString", err) + return + } + } else { + contentEmpty := fmt.Sprintf(`<span class="no-content">%s</span>`, ctx.Tr("repo.issues.no_content")) + renderedContent = template.HTML(contentEmpty) } ctx.JSON(http.StatusOK, map[string]any{ - "content": content, + "content": renderedContent, "attachments": attachmentsHTML(ctx, comment.Attachments, comment.Content), }) } From 2a6418abb1e227f7d0401761a5f68d59a1cea9b2 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Fri, 26 Apr 2024 09:52:28 +0800 Subject: [PATCH 204/370] Improve test for TestPullCompare (#30699) --- tests/integration/pull_compare_test.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/integration/pull_compare_test.go b/tests/integration/pull_compare_test.go index b814207b2f..39d9103dfd 100644 --- a/tests/integration/pull_compare_test.go +++ b/tests/integration/pull_compare_test.go @@ -4,11 +4,13 @@ package integration import ( + "fmt" "net/http" "net/url" "testing" "code.gitea.io/gitea/models/db" + issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -46,22 +48,25 @@ func TestPullCompare(t *testing.T) { testRepoFork(t, session, "user2", "repo1", "user1", "repo1") testCreateBranch(t, session, "user1", "repo1", "branch/master", "master1", http.StatusSeeOther) testEditFile(t, session, "user1", "repo1", "master1", "README.md", "Hello, World (Edited)\n") - resp = testPullCreate(t, session, "user1", "repo1", false, "master", "master1", "This is a pull title") + testPullCreate(t, session, "user1", "repo1", false, "master", "master1", "This is a pull title") - // the max value on issue_index.yml for repo_id=1 is 5 - req = NewRequest(t, "GET", "/user2/repo1/pulls/6/files") + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"}) + issueIndex := unittest.AssertExistsAndLoadBean(t, &issues_model.IssueIndex{GroupID: repo1.ID}, unittest.OrderBy("group_id ASC")) + prFilesURL := fmt.Sprintf("/user2/repo1/pulls/%d/files", issueIndex.MaxIndex) + req = NewRequest(t, "GET", prFilesURL) resp = session.MakeRequest(t, req, http.StatusOK) doc := NewHTMLParser(t, resp.Body) editButtonCount := doc.doc.Find(".diff-file-header-actions a[href*='/_edit/']").Length() assert.Greater(t, editButtonCount, 0, "Expected to find a button to edit a file in the PR diff view but there were none") - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) repoForked := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user1", Name: "repo1"}) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + // delete the head repository and revisit the PR diff view err := repo_service.DeleteRepositoryDirectly(db.DefaultContext, user2, repoForked.ID) assert.NoError(t, err) - req = NewRequest(t, "GET", "/user2/repo1/pulls/6/files") + req = NewRequest(t, "GET", prFilesURL) resp = session.MakeRequest(t, req, http.StatusOK) doc = NewHTMLParser(t, resp.Body) editButtonCount = doc.doc.Find(".diff-file-header-actions a[href*='/_edit/']").Length() From 2a3906d75532ba8689338247d794f21dceb4d359 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 26 Apr 2024 11:22:45 +0900 Subject: [PATCH 205/370] Improve job commit description (#30579) Fix https://github.com/go-gitea/gitea/issues/30567 When job is a schedule:  When it is a normal one:  also add a 'space' behind `:`   --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> --- models/actions/run.go | 11 ++++++++++ routers/web/repo/actions/view.go | 26 +++++++++++++----------- templates/repo/actions/runs_list.tmpl | 2 +- templates/repo/actions/view.tmpl | 3 +++ web_src/js/components/RepoActionView.vue | 22 +++++++++++++++----- 5 files changed, 46 insertions(+), 18 deletions(-) diff --git a/models/actions/run.go b/models/actions/run.go index b75fa49f3c..d68710f46d 100644 --- a/models/actions/run.go +++ b/models/actions/run.go @@ -74,6 +74,13 @@ func (run *ActionRun) Link() string { return fmt.Sprintf("%s/actions/runs/%d", run.Repo.Link(), run.Index) } +func (run *ActionRun) WorkflowLink() string { + if run.Repo == nil { + return "" + } + return fmt.Sprintf("%s/actions/?workflow=%s", run.Repo.Link(), run.WorkflowID) +} + // RefLink return the url of run's ref func (run *ActionRun) RefLink() string { refName := git.RefName(run.Ref) @@ -156,6 +163,10 @@ func (run *ActionRun) GetPullRequestEventPayload() (*api.PullRequestPayload, err return nil, fmt.Errorf("event %s is not a pull request event", run.Event) } +func (run *ActionRun) IsSchedule() bool { + return run.ScheduleID > 0 +} + func updateRepoRunsNumbers(ctx context.Context, repo *repo_model.Repository) error { _, err := db.GetEngine(ctx).ID(repo.ID). SetExpr("num_action_runs", diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go index db2b11a7ed..3909a64be6 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -67,6 +67,9 @@ type ViewResponse struct { CanRerun bool `json:"canRerun"` CanDeleteArtifact bool `json:"canDeleteArtifact"` Done bool `json:"done"` + WorkflowID string `json:"workflowID"` + WorkflowLink string `json:"workflowLink"` + IsSchedule bool `json:"isSchedule"` Jobs []*ViewJob `json:"jobs"` Commit ViewCommit `json:"commit"` } `json:"run"` @@ -90,12 +93,10 @@ type ViewJob struct { } type ViewCommit struct { - LocaleCommit string `json:"localeCommit"` - LocalePushedBy string `json:"localePushedBy"` - ShortSha string `json:"shortSHA"` - Link string `json:"link"` - Pusher ViewUser `json:"pusher"` - Branch ViewBranch `json:"branch"` + ShortSha string `json:"shortSHA"` + Link string `json:"link"` + Pusher ViewUser `json:"pusher"` + Branch ViewBranch `json:"branch"` } type ViewUser struct { @@ -151,6 +152,9 @@ func ViewPost(ctx *context_module.Context) { resp.State.Run.CanRerun = run.Status.IsDone() && ctx.Repo.CanWrite(unit.TypeActions) resp.State.Run.CanDeleteArtifact = run.Status.IsDone() && ctx.Repo.CanWrite(unit.TypeActions) resp.State.Run.Done = run.Status.IsDone() + resp.State.Run.WorkflowID = run.WorkflowID + resp.State.Run.WorkflowLink = run.WorkflowLink() + resp.State.Run.IsSchedule = run.IsSchedule() resp.State.Run.Jobs = make([]*ViewJob, 0, len(jobs)) // marshal to '[]' instead fo 'null' in json resp.State.Run.Status = run.Status.String() for _, v := range jobs { @@ -172,12 +176,10 @@ func ViewPost(ctx *context_module.Context) { Link: run.RefLink(), } resp.State.Run.Commit = ViewCommit{ - LocaleCommit: ctx.Locale.TrString("actions.runs.commit"), - LocalePushedBy: ctx.Locale.TrString("actions.runs.pushed_by"), - ShortSha: base.ShortSha(run.CommitSHA), - Link: fmt.Sprintf("%s/commit/%s", run.Repo.Link(), run.CommitSHA), - Pusher: pusher, - Branch: branch, + ShortSha: base.ShortSha(run.CommitSHA), + Link: fmt.Sprintf("%s/commit/%s", run.Repo.Link(), run.CommitSHA), + Pusher: pusher, + Branch: branch, } var task *actions_model.ActionTask diff --git a/templates/repo/actions/runs_list.tmpl b/templates/repo/actions/runs_list.tmpl index 20330b5d62..09a25ce8bd 100644 --- a/templates/repo/actions/runs_list.tmpl +++ b/templates/repo/actions/runs_list.tmpl @@ -15,7 +15,7 @@ {{if .Title}}{{.Title}}{{else}}{{ctx.Locale.Tr "actions.runs.empty_commit_message"}}{{end}} </a> <div class="flex-item-body"> - <b>{{if not $.CurWorkflow}}{{.WorkflowID}} {{end}}#{{.Index}}</b>: + <span><b>{{if not $.CurWorkflow}}{{.WorkflowID}} {{end}}#{{.Index}}</b>:</span> {{- if .ScheduleID -}} {{ctx.Locale.Tr "actions.runs.scheduled"}} {{- else -}} diff --git a/templates/repo/actions/view.tmpl b/templates/repo/actions/view.tmpl index f8b106147b..f7b03608ee 100644 --- a/templates/repo/actions/view.tmpl +++ b/templates/repo/actions/view.tmpl @@ -10,6 +10,9 @@ data-locale-cancel="{{ctx.Locale.Tr "cancel"}}" data-locale-rerun="{{ctx.Locale.Tr "rerun"}}" data-locale-rerun-all="{{ctx.Locale.Tr "rerun_all"}}" + data-locale-runs-scheduled="{{ctx.Locale.Tr "actions.runs.scheduled"}}" + data-locale-runs-commit="{{ctx.Locale.Tr "actions.runs.commit"}}" + data-locale-runs-pushed-by="{{ctx.Locale.Tr "actions.runs.pushed_by"}}" data-locale-status-unknown="{{ctx.Locale.Tr "actions.status.unknown"}}" data-locale-status-waiting="{{ctx.Locale.Tr "actions.status.waiting"}}" data-locale-status-running="{{ctx.Locale.Tr "actions.status.running"}}" diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index 16ce3fc80d..8b39d0504b 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -44,6 +44,9 @@ const sfc = { canApprove: false, canRerun: false, done: false, + workflowID: '', + workflowLink: '', + isSchedule: false, jobs: [ // { // id: 0, @@ -338,10 +341,13 @@ export function initRepositoryActionView() { approve: el.getAttribute('data-locale-approve'), cancel: el.getAttribute('data-locale-cancel'), rerun: el.getAttribute('data-locale-rerun'), + rerun_all: el.getAttribute('data-locale-rerun-all'), + scheduled: el.getAttribute('data-locale-runs-scheduled'), + commit: el.getAttribute('data-locale-runs-commit'), + pushedBy: el.getAttribute('data-locale-runs-pushed-by'), artifactsTitle: el.getAttribute('data-locale-artifacts-title'), areYouSure: el.getAttribute('data-locale-are-you-sure'), confirmDeleteArtifact: el.getAttribute('data-locale-confirm-delete-artifact'), - rerun_all: el.getAttribute('data-locale-rerun-all'), showTimeStamps: el.getAttribute('data-locale-show-timestamps'), showLogSeconds: el.getAttribute('data-locale-show-log-seconds'), showFullScreen: el.getAttribute('data-locale-show-full-screen'), @@ -382,10 +388,16 @@ export function initRepositoryActionView() { </button> </div> <div class="action-commit-summary"> - {{ run.commit.localeCommit }} - <a class="muted" :href="run.commit.link">{{ run.commit.shortSHA }}</a> - {{ run.commit.localePushedBy }} - <a class="muted" :href="run.commit.pusher.link">{{ run.commit.pusher.displayName }}</a> + <span><a class="muted" :href="run.workflowLink"><b>{{ run.workflowID }}</b></a>:</span> + <template v-if="run.isSchedule"> + {{ locale.scheduled }} + </template> + <template v-else> + {{ locale.commit }} + <a class="muted" :href="run.commit.link">{{ run.commit.shortSHA }}</a> + {{ locale.pushedBy }} + <a class="muted" :href="run.commit.pusher.link">{{ run.commit.pusher.displayName }}</a> + </template> <span class="ui label tw-max-w-full" v-if="run.commit.shortSHA"> <a class="gt-ellipsis" :href="run.commit.branch.link">{{ run.commit.branch.name }}</a> </span> From ed8c63cea3da0d0ba3cdec58f6c6d61c73205afe Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Fri, 26 Apr 2024 10:53:30 +0800 Subject: [PATCH 206/370] Deduplicate lfs common code (#30704) --- modules/git/pipeline/lfs_common.go | 32 ++++++++++++++++++ modules/git/pipeline/{lfs.go => lfs_gogit.go} | 25 ++------------ modules/git/pipeline/lfs_nogogit.go | 33 ++++--------------- 3 files changed, 42 insertions(+), 48 deletions(-) create mode 100644 modules/git/pipeline/lfs_common.go rename modules/git/pipeline/{lfs.go => lfs_gogit.go} (80%) diff --git a/modules/git/pipeline/lfs_common.go b/modules/git/pipeline/lfs_common.go new file mode 100644 index 0000000000..188e7d4d65 --- /dev/null +++ b/modules/git/pipeline/lfs_common.go @@ -0,0 +1,32 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package pipeline + +import ( + "fmt" + "time" + + "code.gitea.io/gitea/modules/git" +) + +// LFSResult represents commits found using a provided pointer file hash +type LFSResult struct { + Name string + SHA string + Summary string + When time.Time + ParentHashes []git.ObjectID + BranchName string + FullCommitName string +} + +type lfsResultSlice []*LFSResult + +func (a lfsResultSlice) Len() int { return len(a) } +func (a lfsResultSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a lfsResultSlice) Less(i, j int) bool { return a[j].When.After(a[i].When) } + +func lfsError(msg string, err error) error { + return fmt.Errorf("LFS error occurred, %s: err: %w", msg, err) +} diff --git a/modules/git/pipeline/lfs.go b/modules/git/pipeline/lfs_gogit.go similarity index 80% rename from modules/git/pipeline/lfs.go rename to modules/git/pipeline/lfs_gogit.go index 6dfca24f29..adcf8ed09c 100644 --- a/modules/git/pipeline/lfs.go +++ b/modules/git/pipeline/lfs_gogit.go @@ -7,12 +7,10 @@ package pipeline import ( "bufio" - "fmt" "io" "sort" "strings" "sync" - "time" "code.gitea.io/gitea/modules/git" @@ -21,23 +19,6 @@ import ( "github.com/go-git/go-git/v5/plumbing/object" ) -// LFSResult represents commits found using a provided pointer file hash -type LFSResult struct { - Name string - SHA string - Summary string - When time.Time - ParentHashes []git.ObjectID - BranchName string - FullCommitName string -} - -type lfsResultSlice []*LFSResult - -func (a lfsResultSlice) Len() int { return len(a) } -func (a lfsResultSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a lfsResultSlice) Less(i, j int) bool { return a[j].When.After(a[i].When) } - // FindLFSFile finds commits that contain a provided pointer file hash func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, error) { resultsMap := map[string]*LFSResult{} @@ -51,7 +32,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err All: true, }) if err != nil { - return nil, fmt.Errorf("Failed to get GoGit CommitsIter. Error: %w", err) + return nil, lfsError("failed to get GoGit CommitsIter", err) } err = commitsIter.ForEach(func(gitCommit *object.Commit) error { @@ -85,7 +66,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err return nil }) if err != nil && err != io.EOF { - return nil, fmt.Errorf("Failure in CommitIter.ForEach: %w", err) + return nil, lfsError("failure in CommitIter.ForEach", err) } for _, result := range resultsMap { @@ -156,7 +137,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err select { case err, has := <-errChan: if has { - return nil, fmt.Errorf("Unable to obtain name for LFS files. Error: %w", err) + return nil, lfsError("unable to obtain name for LFS files", err) } default: } diff --git a/modules/git/pipeline/lfs_nogogit.go b/modules/git/pipeline/lfs_nogogit.go index fe320f39f3..349cfbd9ce 100644 --- a/modules/git/pipeline/lfs_nogogit.go +++ b/modules/git/pipeline/lfs_nogogit.go @@ -8,33 +8,14 @@ package pipeline import ( "bufio" "bytes" - "fmt" "io" "sort" "strings" "sync" - "time" "code.gitea.io/gitea/modules/git" ) -// LFSResult represents commits found using a provided pointer file hash -type LFSResult struct { - Name string - SHA string - Summary string - When time.Time - ParentIDs []git.ObjectID - BranchName string - FullCommitName string -} - -type lfsResultSlice []*LFSResult - -func (a lfsResultSlice) Len() int { return len(a) } -func (a lfsResultSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a lfsResultSlice) Less(i, j int) bool { return a[j].When.After(a[i].When) } - // FindLFSFile finds commits that contain a provided pointer file hash func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, error) { resultsMap := map[string]*LFSResult{} @@ -137,11 +118,11 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err n += int64(count) if bytes.Equal(binObjectID, objectID.RawValue()) { result := LFSResult{ - Name: curPath + string(fname), - SHA: curCommit.ID.String(), - Summary: strings.Split(strings.TrimSpace(curCommit.CommitMessage), "\n")[0], - When: curCommit.Author.When, - ParentIDs: curCommit.Parents, + Name: curPath + string(fname), + SHA: curCommit.ID.String(), + Summary: strings.Split(strings.TrimSpace(curCommit.CommitMessage), "\n")[0], + When: curCommit.Author.When, + ParentHashes: curCommit.Parents, } resultsMap[curCommit.ID.String()+":"+curPath+string(fname)] = &result } else if string(mode) == git.EntryModeTree.String() { @@ -183,7 +164,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err for _, result := range resultsMap { hasParent := false - for _, parentID := range result.ParentIDs { + for _, parentID := range result.ParentHashes { if _, hasParent = resultsMap[parentID.String()+":"+result.Name]; hasParent { break } @@ -240,7 +221,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err select { case err, has := <-errChan: if has { - return nil, fmt.Errorf("Unable to obtain name for LFS files. Error: %w", err) + return nil, lfsError("unable to obtain name for LFS files", err) } default: } From 68a3e6b5e64b4035aa0659cb6daa1c4d1eec892a Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Fri, 26 Apr 2024 10:27:34 +0300 Subject: [PATCH 207/370] Bump htmx version to 1.9.12 (#30711) There are no breaking changes. I tested and everything works as before. Signed-off-by: Yarden Shoham <git@yardenshoham.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 61d86f6b7c..780689a0a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "esbuild-loader": "4.1.0", "escape-goat": "4.0.0", "fast-glob": "3.3.2", - "htmx.org": "1.9.11", + "htmx.org": "1.9.12", "idiomorph": "0.3.0", "jquery": "3.7.1", "katex": "0.16.10", @@ -6728,9 +6728,9 @@ } }, "node_modules/htmx.org": { - "version": "1.9.11", - "resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-1.9.11.tgz", - "integrity": "sha512-WlVuICn8dfNOOgYmdYzYG8zSnP3++AdHkMHooQAzGZObWpVXYathpz/I37ycF4zikR6YduzfCvEcxk20JkIUsw==" + "version": "1.9.12", + "resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-1.9.12.tgz", + "integrity": "sha512-VZAohXyF7xPGS52IM8d1T1283y+X4D+Owf3qY1NZ9RuBypyu9l8cGsxUMAG5fEAb/DhT7rDoJ9Hpu5/HxFD3cw==" }, "node_modules/human-signals": { "version": "5.0.0", diff --git a/package.json b/package.json index ff1ae4d49e..b0cb67ed4a 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "esbuild-loader": "4.1.0", "escape-goat": "4.0.0", "fast-glob": "3.3.2", - "htmx.org": "1.9.11", + "htmx.org": "1.9.12", "idiomorph": "0.3.0", "jquery": "3.7.1", "katex": "0.16.10", From 1e749b80d741c3a5c7eff6087d820e4d0d1ba3a2 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Fri, 26 Apr 2024 17:09:49 +0800 Subject: [PATCH 208/370] Add route handler info for debugging purpose (#30705) Follow #30519 --- routers/init.go | 6 ++++++ routers/web/web.go | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/routers/init.go b/routers/init.go index aaf95920c2..030ef3c740 100644 --- a/routers/init.go +++ b/routers/init.go @@ -5,6 +5,7 @@ package routers import ( "context" + "net/http" "reflect" "runtime" @@ -25,6 +26,7 @@ import ( "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/modules/web/routing" actions_router "code.gitea.io/gitea/routers/api/actions" packages_router "code.gitea.io/gitea/routers/api/packages" apiv1 "code.gitea.io/gitea/routers/api/v1" @@ -202,5 +204,9 @@ func NormalRoutes() *web.Route { r.Mount(prefix, actions_router.ArtifactsV4Routes(prefix)) } + r.NotFound(func(w http.ResponseWriter, req *http.Request) { + routing.UpdateFuncInfo(req.Context(), routing.GetFuncInfo(http.NotFound, "GlobalNotFound")) + http.NotFound(w, req) + }) return r } diff --git a/routers/web/web.go b/routers/web/web.go index c6132f0d61..9a6687059b 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1612,7 +1612,7 @@ func registerRoutes(m *web.Route) { m.NotFound(func(w http.ResponseWriter, req *http.Request) { ctx := context.GetWebContext(req) - routing.UpdateFuncInfo(ctx, routing.GetFuncInfo(ctx.NotFound, "GlobalNotFound")) + routing.UpdateFuncInfo(ctx, routing.GetFuncInfo(ctx.NotFound, "WebNotFound")) ctx.NotFound("", nil) }) } From cd70ab31cdee8116055819bf67bcf374e2aa6172 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Fri, 26 Apr 2024 17:49:48 +0800 Subject: [PATCH 209/370] Fix incorrect object id hash function (#30708) Great thanks to @oliverpool for figuring out the problem and proposing a fix. Regression of #28138 Incorrect hash causes the user's LFS files get all deleted when running `doctor fix all` (by the way, remove unused/non-standard comments) Co-authored-by: Giteabot <teabot@gitea.io> --- modules/git/object_format.go | 16 ++++------------ modules/git/object_id.go | 3 --- modules/git/object_id_test.go | 4 ++++ 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/modules/git/object_format.go b/modules/git/object_format.go index a056b20e8a..3de9ff8cf4 100644 --- a/modules/git/object_format.go +++ b/modules/git/object_format.go @@ -33,7 +33,6 @@ type ObjectFormat interface { ComputeHash(t ObjectType, content []byte) ObjectID } -/* SHA1 Type */ type Sha1ObjectFormatImpl struct{} var ( @@ -70,14 +69,10 @@ func (h Sha1ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) ObjectID _, _ = hasher.Write([]byte(" ")) _, _ = hasher.Write([]byte(strconv.FormatInt(int64(len(content)), 10))) _, _ = hasher.Write([]byte{0}) - - // HashSum generates a SHA1 for the provided hash - var sha1 Sha1Hash - copy(sha1[:], hasher.Sum(nil)) - return &sha1 + _, _ = hasher.Write(content) + return h.MustID(hasher.Sum(nil)) } -/* SHA256 Type */ type Sha256ObjectFormatImpl struct{} var ( @@ -116,11 +111,8 @@ func (h Sha256ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) Object _, _ = hasher.Write([]byte(" ")) _, _ = hasher.Write([]byte(strconv.FormatInt(int64(len(content)), 10))) _, _ = hasher.Write([]byte{0}) - - // HashSum generates a SHA256 for the provided hash - var sha256 Sha1Hash - copy(sha256[:], hasher.Sum(nil)) - return &sha256 + _, _ = hasher.Write(content) + return h.MustID(hasher.Sum(nil)) } var ( diff --git a/modules/git/object_id.go b/modules/git/object_id.go index 4f8c39ee1d..33e5085005 100644 --- a/modules/git/object_id.go +++ b/modules/git/object_id.go @@ -16,7 +16,6 @@ type ObjectID interface { Type() ObjectFormat } -/* SHA1 */ type Sha1Hash [20]byte func (h *Sha1Hash) String() string { @@ -40,7 +39,6 @@ func MustIDFromString(hexHash string) ObjectID { return id } -/* SHA256 */ type Sha256Hash [32]byte func (h *Sha256Hash) String() string { @@ -54,7 +52,6 @@ func (h *Sha256Hash) IsZero() bool { func (h *Sha256Hash) RawValue() []byte { return h[:] } func (*Sha256Hash) Type() ObjectFormat { return Sha256ObjectFormat } -/* utility */ func NewIDFromString(hexHash string) (ObjectID, error) { var theObjectFormat ObjectFormat for _, objectFormat := range SupportedObjectFormats { diff --git a/modules/git/object_id_test.go b/modules/git/object_id_test.go index 1ad40096a0..03d0c85d87 100644 --- a/modules/git/object_id_test.go +++ b/modules/git/object_id_test.go @@ -18,4 +18,8 @@ func TestIsValidSHAPattern(t *testing.T) { assert.False(t, h.IsValid("abc")) assert.False(t, h.IsValid("123g")) assert.False(t, h.IsValid("some random text")) + assert.Equal(t, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", ComputeBlobHash(Sha1ObjectFormat, nil).String()) + assert.Equal(t, "2e65efe2a145dda7ee51d1741299f848e5bf752e", ComputeBlobHash(Sha1ObjectFormat, []byte("a")).String()) + assert.Equal(t, "473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813", ComputeBlobHash(Sha256ObjectFormat, nil).String()) + assert.Equal(t, "eb337bcee2061c5313c9a1392116b6c76039e9e30d71467ae359b36277e17dc7", ComputeBlobHash(Sha256ObjectFormat, []byte("a")).String()) } From 993736d838c36e26951b6cfea9c6a549958addd1 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Fri, 26 Apr 2024 19:21:04 +0800 Subject: [PATCH 210/370] Fix code search input for different views (#30678) Now only show the "code search" on the repo home page, because it only does global search. So do not show it when viewing file or directory to avoid misleading users (it doesn't search in a directory) --- routers/web/repo/commit.go | 2 -- routers/web/repo/compare.go | 1 - routers/web/repo/pull.go | 1 - templates/repo/home.tmpl | 22 ++++++++++++---------- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index 8543fa44cc..a2c6ac33e8 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -212,8 +212,6 @@ func SearchCommits(ctx *context.Context) { // FileHistory show a file's reversions func FileHistory(ctx *context.Context) { - ctx.Data["IsRepoToolbarCommits"] = true - fileName := ctx.Repo.TreePath if len(fileName) == 0 { Commits(ctx) diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 035a92f228..a55426dab5 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -800,7 +800,6 @@ func CompareDiff(ctx *context.Context) { } ctx.Data["Title"] = "Comparing " + base.ShortSha(beforeCommitID) + separator + base.ShortSha(afterCommitID) - ctx.Data["IsRepoToolbarCommits"] = true ctx.Data["IsDiffCompare"] = true _, templateErrs := setTemplateIfExists(ctx, pullRequestTemplateKey, pullRequestTemplateCandidates) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index acdba4bcdc..7f131f2e98 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -1225,7 +1225,6 @@ func CompareAndPullRequestPost(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("repo.pulls.compare_changes") ctx.Data["PageIsComparePull"] = true ctx.Data["IsDiffCompare"] = true - ctx.Data["IsRepoToolbarCommits"] = true ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled upload.AddUploadContext(ctx, "comment") diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 7b37ac1011..eb9eb9c149 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -90,7 +90,16 @@ {{ctx.Locale.Tr "repo.use_template"}} </a> {{end}} - {{if (not $isHomepage)}} + {{if $isHomepage}} + {{/* only show the "code search" on the repo home page, it only does global search, + so do not show it when viewing file or directory to avoid misleading users (it doesn't search in a directory) */}} + <form class="ignore-dirty" action="{{.RepoLink}}/search" method="get"> + <div class="ui small action input"> + <input name="q" placeholder="{{ctx.Locale.Tr "search.code_kind"}}"> + {{template "shared/search/button"}} + </div> + </form> + {{else}} <span class="breadcrumb repo-path tw-ml-1"> <a class="section" href="{{.RepoLink}}/src/{{.BranchNameSubURL}}" title="{{.Repository.Name}}">{{StringUtils.EllipsisString .Repository.Name 30}}</a> {{- range $i, $v := .TreeNames -}} @@ -103,13 +112,6 @@ {{- end -}} </span> {{end}} - - <form class="ignore-dirty" action="{{.RepoLink}}/search" method="get"> - <div class="ui small action input"> - <input name="q" value="{{.Keyword}}" placeholder="{{ctx.Locale.Tr "search.code_kind"}}"> - {{template "shared/search/button"}} - </div> - </form> </div> <div class="tw-flex tw-items-center"> <!-- Only show clone panel in repository home page --> @@ -136,7 +138,7 @@ </div> {{template "repo/cite/cite_modal" .}} {{end}} - {{if and (not $isHomepage) (not .IsViewFile) (not .IsBlame)}} + {{if and (not $isHomepage) (not .IsViewFile) (not .IsBlame)}}{{/* IsViewDirectory (not home), TODO: split the templates, avoid using "if" tricks */}} <a class="ui button" href="{{.RepoLink}}/commits/{{.BranchNameSubURL}}/{{.TreePath | PathEscapeSegments}}"> {{svg "octicon-history" 16 "tw-mr-2"}}{{ctx.Locale.Tr "repo.file_history"}} </a> @@ -147,7 +149,7 @@ {{template "repo/view_file" .}} {{else if .IsBlame}} {{template "repo/blame" .}} - {{else}} + {{else}}{{/* IsViewDirectory */}} {{template "repo/view_list" .}} {{end}} </div> From 852547d0dc70299589c7bf8d00ea462ed709b8e5 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu <appleboy.tw@gmail.com> Date: Fri, 26 Apr 2024 21:11:49 +0800 Subject: [PATCH 211/370] feat(api): enhance Actions Secrets Management API for repository (#30656) - Add endpoint to list repository action secrets in API routes - Implement `ListActionsSecrets` function to retrieve action secrets from the database - Update Swagger documentation to include the new `/repos/{owner}/{repo}/actions/secrets` endpoint - Add `actions` package import and define new routes for actions, secrets, variables, and runners in `api.go`. - Refactor action-related API functions into `Action` struct methods in `org/action.go` and `repo/action.go`. - Remove `actionAPI` struct and related functions, replacing them with `NewAction()` calls. - Rename `variables.go` to `action.go` in `org` directory. - Delete `runners.go` and `secrets.go` in both `org` and `repo` directories, consolidating their content into `action.go`. - Update copyright year and add new imports in `org/action.go`. - Implement `API` interface in `services/actions/interface.go` for action-related methods. - Remove individual action-related functions and replace them with methods on the `Action` struct in `repo/action.go`. --------- Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com> Signed-off-by: appleboy <appleboy.tw@gmail.com> --- routers/api/v1/api.go | 80 ++++---- .../api/v1/org/{variables.go => action.go} | 192 +++++++++++++++++- routers/api/v1/org/runners.go | 31 --- routers/api/v1/org/secrets.go | 166 --------------- routers/api/v1/repo/action.go | 108 +++++++++- routers/api/v1/repo/runners.go | 34 ---- services/actions/interface.go | 28 +++ templates/swagger/v1_json.tmpl | 48 +++++ tests/integration/api_repo_secrets_test.go | 8 +- 9 files changed, 410 insertions(+), 285 deletions(-) rename routers/api/v1/org/{variables.go => action.go} (58%) delete mode 100644 routers/api/v1/org/runners.go delete mode 100644 routers/api/v1/org/secrets.go delete mode 100644 routers/api/v1/repo/runners.go create mode 100644 services/actions/interface.go diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 5358906f27..73071aa8df 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -93,6 +93,7 @@ import ( "code.gitea.io/gitea/routers/api/v1/settings" "code.gitea.io/gitea/routers/api/v1/user" "code.gitea.io/gitea/routers/common" + "code.gitea.io/gitea/services/actions" "code.gitea.io/gitea/services/auth" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" @@ -835,6 +836,34 @@ func Routes() *web.Route { SignInRequired: setting.Service.RequireSignInView, })) + addActionsRoutes := func( + m *web.Route, + reqChecker func(ctx *context.APIContext), + act actions.API, + ) { + m.Group("/actions", func() { + m.Group("/secrets", func() { + m.Get("", reqToken(), reqChecker, act.ListActionsSecrets) + m.Combo("/{secretname}"). + Put(reqToken(), reqChecker, bind(api.CreateOrUpdateSecretOption{}), act.CreateOrUpdateSecret). + Delete(reqToken(), reqChecker, act.DeleteSecret) + }) + + m.Group("/variables", func() { + m.Get("", reqToken(), reqChecker, act.ListVariables) + m.Combo("/{variablename}"). + Get(reqToken(), reqChecker, act.GetVariable). + Delete(reqToken(), reqChecker, act.DeleteVariable). + Post(reqToken(), reqChecker, bind(api.CreateVariableOption{}), act.CreateVariable). + Put(reqToken(), reqChecker, bind(api.UpdateVariableOption{}), act.UpdateVariable) + }) + + m.Group("/runners", func() { + m.Get("/registration-token", reqToken(), reqChecker, act.GetRegistrationToken) + }) + }) + } + m.Group("", func() { // Miscellaneous (no scope required) if setting.API.EnableSwagger { @@ -1073,26 +1102,11 @@ func Routes() *web.Route { m.Post("/accept", repo.AcceptTransfer) m.Post("/reject", repo.RejectTransfer) }, reqToken()) - m.Group("/actions", func() { - m.Group("/secrets", func() { - m.Combo("/{secretname}"). - Put(reqToken(), reqOwner(), bind(api.CreateOrUpdateSecretOption{}), repo.CreateOrUpdateSecret). - Delete(reqToken(), reqOwner(), repo.DeleteSecret) - }) - - m.Group("/variables", func() { - m.Get("", reqToken(), reqOwner(), repo.ListVariables) - m.Combo("/{variablename}"). - Get(reqToken(), reqOwner(), repo.GetVariable). - Delete(reqToken(), reqOwner(), repo.DeleteVariable). - Post(reqToken(), reqOwner(), bind(api.CreateVariableOption{}), repo.CreateVariable). - Put(reqToken(), reqOwner(), bind(api.UpdateVariableOption{}), repo.UpdateVariable) - }) - - m.Group("/runners", func() { - m.Get("/registration-token", reqToken(), reqOwner(), repo.GetRegistrationToken) - }) - }) + addActionsRoutes( + m, + reqOwner(), + repo.NewAction(), + ) m.Group("/hooks/git", func() { m.Combo("").Get(repo.ListGitHooks) m.Group("/{id}", func() { @@ -1460,27 +1474,11 @@ func Routes() *web.Route { m.Combo("/{username}").Get(reqToken(), org.IsMember). Delete(reqToken(), reqOrgOwnership(), org.DeleteMember) }) - m.Group("/actions", func() { - m.Group("/secrets", func() { - m.Get("", reqToken(), reqOrgOwnership(), org.ListActionsSecrets) - m.Combo("/{secretname}"). - Put(reqToken(), reqOrgOwnership(), bind(api.CreateOrUpdateSecretOption{}), org.CreateOrUpdateSecret). - Delete(reqToken(), reqOrgOwnership(), org.DeleteSecret) - }) - - m.Group("/variables", func() { - m.Get("", reqToken(), reqOrgOwnership(), org.ListVariables) - m.Combo("/{variablename}"). - Get(reqToken(), reqOrgOwnership(), org.GetVariable). - Delete(reqToken(), reqOrgOwnership(), org.DeleteVariable). - Post(reqToken(), reqOrgOwnership(), bind(api.CreateVariableOption{}), org.CreateVariable). - Put(reqToken(), reqOrgOwnership(), bind(api.UpdateVariableOption{}), org.UpdateVariable) - }) - - m.Group("/runners", func() { - m.Get("/registration-token", reqToken(), reqOrgOwnership(), org.GetRegistrationToken) - }) - }) + addActionsRoutes( + m, + reqOrgOwnership(), + org.NewAction(), + ) m.Group("/public_members", func() { m.Get("", org.ListPublicMembers) m.Combo("/{username}").Get(org.IsPublicMember). diff --git a/routers/api/v1/org/variables.go b/routers/api/v1/org/action.go similarity index 58% rename from routers/api/v1/org/variables.go rename to routers/api/v1/org/action.go index eaf7bdc45b..03a1fa8ccc 100644 --- a/routers/api/v1/org/variables.go +++ b/routers/api/v1/org/action.go @@ -9,16 +9,188 @@ import ( actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" + secret_model "code.gitea.io/gitea/models/secret" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/routers/api/v1/shared" "code.gitea.io/gitea/routers/api/v1/utils" actions_service "code.gitea.io/gitea/services/actions" "code.gitea.io/gitea/services/context" + secret_service "code.gitea.io/gitea/services/secrets" ) +// ListActionsSecrets list an organization's actions secrets +func (Action) ListActionsSecrets(ctx *context.APIContext) { + // swagger:operation GET /orgs/{org}/actions/secrets organization orgListActionsSecrets + // --- + // summary: List an organization's actions secrets + // produces: + // - application/json + // parameters: + // - name: org + // in: path + // description: name of the organization + // type: string + // required: true + // - name: page + // in: query + // description: page number of results to return (1-based) + // type: integer + // - name: limit + // in: query + // description: page size of results + // type: integer + // responses: + // "200": + // "$ref": "#/responses/SecretList" + // "404": + // "$ref": "#/responses/notFound" + + opts := &secret_model.FindSecretsOptions{ + OwnerID: ctx.Org.Organization.ID, + ListOptions: utils.GetListOptions(ctx), + } + + secrets, count, err := db.FindAndCount[secret_model.Secret](ctx, opts) + if err != nil { + ctx.InternalServerError(err) + return + } + + apiSecrets := make([]*api.Secret, len(secrets)) + for k, v := range secrets { + apiSecrets[k] = &api.Secret{ + Name: v.Name, + Created: v.CreatedUnix.AsTime(), + } + } + + ctx.SetTotalCountHeader(count) + ctx.JSON(http.StatusOK, apiSecrets) +} + +// create or update one secret of the organization +func (Action) CreateOrUpdateSecret(ctx *context.APIContext) { + // swagger:operation PUT /orgs/{org}/actions/secrets/{secretname} organization updateOrgSecret + // --- + // summary: Create or Update a secret value in an organization + // consumes: + // - application/json + // produces: + // - application/json + // parameters: + // - name: org + // in: path + // description: name of organization + // type: string + // required: true + // - name: secretname + // in: path + // description: name of the secret + // type: string + // required: true + // - name: body + // in: body + // schema: + // "$ref": "#/definitions/CreateOrUpdateSecretOption" + // responses: + // "201": + // description: response when creating a secret + // "204": + // description: response when updating a secret + // "400": + // "$ref": "#/responses/error" + // "404": + // "$ref": "#/responses/notFound" + + opt := web.GetForm(ctx).(*api.CreateOrUpdateSecretOption) + + _, created, err := secret_service.CreateOrUpdateSecret(ctx, ctx.Org.Organization.ID, 0, ctx.Params("secretname"), opt.Data) + if err != nil { + if errors.Is(err, util.ErrInvalidArgument) { + ctx.Error(http.StatusBadRequest, "CreateOrUpdateSecret", err) + } else if errors.Is(err, util.ErrNotExist) { + ctx.Error(http.StatusNotFound, "CreateOrUpdateSecret", err) + } else { + ctx.Error(http.StatusInternalServerError, "CreateOrUpdateSecret", err) + } + return + } + + if created { + ctx.Status(http.StatusCreated) + } else { + ctx.Status(http.StatusNoContent) + } +} + +// DeleteSecret delete one secret of the organization +func (Action) DeleteSecret(ctx *context.APIContext) { + // swagger:operation DELETE /orgs/{org}/actions/secrets/{secretname} organization deleteOrgSecret + // --- + // summary: Delete a secret in an organization + // consumes: + // - application/json + // produces: + // - application/json + // parameters: + // - name: org + // in: path + // description: name of organization + // type: string + // required: true + // - name: secretname + // in: path + // description: name of the secret + // type: string + // required: true + // responses: + // "204": + // description: delete one secret of the organization + // "400": + // "$ref": "#/responses/error" + // "404": + // "$ref": "#/responses/notFound" + + err := secret_service.DeleteSecretByName(ctx, ctx.Org.Organization.ID, 0, ctx.Params("secretname")) + if err != nil { + if errors.Is(err, util.ErrInvalidArgument) { + ctx.Error(http.StatusBadRequest, "DeleteSecret", err) + } else if errors.Is(err, util.ErrNotExist) { + ctx.Error(http.StatusNotFound, "DeleteSecret", err) + } else { + ctx.Error(http.StatusInternalServerError, "DeleteSecret", err) + } + return + } + + ctx.Status(http.StatusNoContent) +} + +// https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization +// GetRegistrationToken returns the token to register org runners +func (Action) GetRegistrationToken(ctx *context.APIContext) { + // swagger:operation GET /orgs/{org}/actions/runners/registration-token organization orgGetRunnerRegistrationToken + // --- + // summary: Get an organization's actions runner registration token + // produces: + // - application/json + // parameters: + // - name: org + // in: path + // description: name of the organization + // type: string + // required: true + // responses: + // "200": + // "$ref": "#/responses/RegistrationToken" + + shared.GetRegistrationToken(ctx, ctx.Org.Organization.ID, 0) +} + // ListVariables list org-level variables -func ListVariables(ctx *context.APIContext) { +func (Action) ListVariables(ctx *context.APIContext) { // swagger:operation GET /orgs/{org}/actions/variables organization getOrgVariablesList // --- // summary: Get an org-level variables list @@ -70,7 +242,7 @@ func ListVariables(ctx *context.APIContext) { } // GetVariable get an org-level variable -func GetVariable(ctx *context.APIContext) { +func (Action) GetVariable(ctx *context.APIContext) { // swagger:operation GET /orgs/{org}/actions/variables/{variablename} organization getOrgVariable // --- // summary: Get an org-level variable @@ -119,7 +291,7 @@ func GetVariable(ctx *context.APIContext) { } // DeleteVariable delete an org-level variable -func DeleteVariable(ctx *context.APIContext) { +func (Action) DeleteVariable(ctx *context.APIContext) { // swagger:operation DELETE /orgs/{org}/actions/variables/{variablename} organization deleteOrgVariable // --- // summary: Delete an org-level variable @@ -163,7 +335,7 @@ func DeleteVariable(ctx *context.APIContext) { } // CreateVariable create an org-level variable -func CreateVariable(ctx *context.APIContext) { +func (Action) CreateVariable(ctx *context.APIContext) { // swagger:operation POST /orgs/{org}/actions/variables/{variablename} organization createOrgVariable // --- // summary: Create an org-level variable @@ -227,7 +399,7 @@ func CreateVariable(ctx *context.APIContext) { } // UpdateVariable update an org-level variable -func UpdateVariable(ctx *context.APIContext) { +func (Action) UpdateVariable(ctx *context.APIContext) { // swagger:operation PUT /orgs/{org}/actions/variables/{variablename} organization updateOrgVariable // --- // summary: Update an org-level variable @@ -289,3 +461,13 @@ func UpdateVariable(ctx *context.APIContext) { ctx.Status(http.StatusNoContent) } + +var _ actions_service.API = new(Action) + +// Action implements actions_service.API +type Action struct{} + +// NewAction creates a new Action service +func NewAction() actions_service.API { + return Action{} +} diff --git a/routers/api/v1/org/runners.go b/routers/api/v1/org/runners.go deleted file mode 100644 index 2a52bd8778..0000000000 --- a/routers/api/v1/org/runners.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package org - -import ( - "code.gitea.io/gitea/routers/api/v1/shared" - "code.gitea.io/gitea/services/context" -) - -// https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization - -// GetRegistrationToken returns the token to register org runners -func GetRegistrationToken(ctx *context.APIContext) { - // swagger:operation GET /orgs/{org}/actions/runners/registration-token organization orgGetRunnerRegistrationToken - // --- - // summary: Get an organization's actions runner registration token - // produces: - // - application/json - // parameters: - // - name: org - // in: path - // description: name of the organization - // type: string - // required: true - // responses: - // "200": - // "$ref": "#/responses/RegistrationToken" - - shared.GetRegistrationToken(ctx, ctx.Org.Organization.ID, 0) -} diff --git a/routers/api/v1/org/secrets.go b/routers/api/v1/org/secrets.go deleted file mode 100644 index abb6bb26c4..0000000000 --- a/routers/api/v1/org/secrets.go +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package org - -import ( - "errors" - "net/http" - - "code.gitea.io/gitea/models/db" - secret_model "code.gitea.io/gitea/models/secret" - api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/modules/web" - "code.gitea.io/gitea/routers/api/v1/utils" - "code.gitea.io/gitea/services/context" - secret_service "code.gitea.io/gitea/services/secrets" -) - -// ListActionsSecrets list an organization's actions secrets -func ListActionsSecrets(ctx *context.APIContext) { - // swagger:operation GET /orgs/{org}/actions/secrets organization orgListActionsSecrets - // --- - // summary: List an organization's actions secrets - // produces: - // - application/json - // parameters: - // - name: org - // in: path - // description: name of the organization - // type: string - // required: true - // - name: page - // in: query - // description: page number of results to return (1-based) - // type: integer - // - name: limit - // in: query - // description: page size of results - // type: integer - // responses: - // "200": - // "$ref": "#/responses/SecretList" - // "404": - // "$ref": "#/responses/notFound" - - opts := &secret_model.FindSecretsOptions{ - OwnerID: ctx.Org.Organization.ID, - ListOptions: utils.GetListOptions(ctx), - } - - secrets, count, err := db.FindAndCount[secret_model.Secret](ctx, opts) - if err != nil { - ctx.InternalServerError(err) - return - } - - apiSecrets := make([]*api.Secret, len(secrets)) - for k, v := range secrets { - apiSecrets[k] = &api.Secret{ - Name: v.Name, - Created: v.CreatedUnix.AsTime(), - } - } - - ctx.SetTotalCountHeader(count) - ctx.JSON(http.StatusOK, apiSecrets) -} - -// create or update one secret of the organization -func CreateOrUpdateSecret(ctx *context.APIContext) { - // swagger:operation PUT /orgs/{org}/actions/secrets/{secretname} organization updateOrgSecret - // --- - // summary: Create or Update a secret value in an organization - // consumes: - // - application/json - // produces: - // - application/json - // parameters: - // - name: org - // in: path - // description: name of organization - // type: string - // required: true - // - name: secretname - // in: path - // description: name of the secret - // type: string - // required: true - // - name: body - // in: body - // schema: - // "$ref": "#/definitions/CreateOrUpdateSecretOption" - // responses: - // "201": - // description: response when creating a secret - // "204": - // description: response when updating a secret - // "400": - // "$ref": "#/responses/error" - // "404": - // "$ref": "#/responses/notFound" - - opt := web.GetForm(ctx).(*api.CreateOrUpdateSecretOption) - - _, created, err := secret_service.CreateOrUpdateSecret(ctx, ctx.Org.Organization.ID, 0, ctx.Params("secretname"), opt.Data) - if err != nil { - if errors.Is(err, util.ErrInvalidArgument) { - ctx.Error(http.StatusBadRequest, "CreateOrUpdateSecret", err) - } else if errors.Is(err, util.ErrNotExist) { - ctx.Error(http.StatusNotFound, "CreateOrUpdateSecret", err) - } else { - ctx.Error(http.StatusInternalServerError, "CreateOrUpdateSecret", err) - } - return - } - - if created { - ctx.Status(http.StatusCreated) - } else { - ctx.Status(http.StatusNoContent) - } -} - -// DeleteSecret delete one secret of the organization -func DeleteSecret(ctx *context.APIContext) { - // swagger:operation DELETE /orgs/{org}/actions/secrets/{secretname} organization deleteOrgSecret - // --- - // summary: Delete a secret in an organization - // consumes: - // - application/json - // produces: - // - application/json - // parameters: - // - name: org - // in: path - // description: name of organization - // type: string - // required: true - // - name: secretname - // in: path - // description: name of the secret - // type: string - // required: true - // responses: - // "204": - // description: delete one secret of the organization - // "400": - // "$ref": "#/responses/error" - // "404": - // "$ref": "#/responses/notFound" - - err := secret_service.DeleteSecretByName(ctx, ctx.Org.Organization.ID, 0, ctx.Params("secretname")) - if err != nil { - if errors.Is(err, util.ErrInvalidArgument) { - ctx.Error(http.StatusBadRequest, "DeleteSecret", err) - } else if errors.Is(err, util.ErrNotExist) { - ctx.Error(http.StatusNotFound, "DeleteSecret", err) - } else { - ctx.Error(http.StatusInternalServerError, "DeleteSecret", err) - } - return - } - - ctx.Status(http.StatusNoContent) -} diff --git a/routers/api/v1/repo/action.go b/routers/api/v1/repo/action.go index 03321d956d..311cfca6e9 100644 --- a/routers/api/v1/repo/action.go +++ b/routers/api/v1/repo/action.go @@ -9,17 +9,76 @@ import ( actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" + secret_model "code.gitea.io/gitea/models/secret" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/routers/api/v1/shared" "code.gitea.io/gitea/routers/api/v1/utils" actions_service "code.gitea.io/gitea/services/actions" "code.gitea.io/gitea/services/context" secret_service "code.gitea.io/gitea/services/secrets" ) +// ListActionsSecrets list an repo's actions secrets +func (Action) ListActionsSecrets(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/actions/secrets repository repoListActionsSecrets + // --- + // summary: List an repo's actions secrets + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repository + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repository + // type: string + // required: true + // - name: page + // in: query + // description: page number of results to return (1-based) + // type: integer + // - name: limit + // in: query + // description: page size of results + // type: integer + // responses: + // "200": + // "$ref": "#/responses/SecretList" + // "404": + // "$ref": "#/responses/notFound" + + repo := ctx.Repo.Repository + + opts := &secret_model.FindSecretsOptions{ + RepoID: repo.ID, + ListOptions: utils.GetListOptions(ctx), + } + + secrets, count, err := db.FindAndCount[secret_model.Secret](ctx, opts) + if err != nil { + ctx.InternalServerError(err) + return + } + + apiSecrets := make([]*api.Secret, len(secrets)) + for k, v := range secrets { + apiSecrets[k] = &api.Secret{ + Name: v.Name, + Created: v.CreatedUnix.AsTime(), + } + } + + ctx.SetTotalCountHeader(count) + ctx.JSON(http.StatusOK, apiSecrets) +} + // create or update one secret of the repository -func CreateOrUpdateSecret(ctx *context.APIContext) { +func (Action) CreateOrUpdateSecret(ctx *context.APIContext) { // swagger:operation PUT /repos/{owner}/{repo}/actions/secrets/{secretname} repository updateRepoSecret // --- // summary: Create or Update a secret value in a repository @@ -82,7 +141,7 @@ func CreateOrUpdateSecret(ctx *context.APIContext) { } // DeleteSecret delete one secret of the repository -func DeleteSecret(ctx *context.APIContext) { +func (Action) DeleteSecret(ctx *context.APIContext) { // swagger:operation DELETE /repos/{owner}/{repo}/actions/secrets/{secretname} repository deleteRepoSecret // --- // summary: Delete a secret in a repository @@ -133,7 +192,7 @@ func DeleteSecret(ctx *context.APIContext) { } // GetVariable get a repo-level variable -func GetVariable(ctx *context.APIContext) { +func (Action) GetVariable(ctx *context.APIContext) { // swagger:operation GET /repos/{owner}/{repo}/actions/variables/{variablename} repository getRepoVariable // --- // summary: Get a repo-level variable @@ -186,7 +245,7 @@ func GetVariable(ctx *context.APIContext) { } // DeleteVariable delete a repo-level variable -func DeleteVariable(ctx *context.APIContext) { +func (Action) DeleteVariable(ctx *context.APIContext) { // swagger:operation DELETE /repos/{owner}/{repo}/actions/variables/{variablename} repository deleteRepoVariable // --- // summary: Delete a repo-level variable @@ -235,7 +294,7 @@ func DeleteVariable(ctx *context.APIContext) { } // CreateVariable create a repo-level variable -func CreateVariable(ctx *context.APIContext) { +func (Action) CreateVariable(ctx *context.APIContext) { // swagger:operation POST /repos/{owner}/{repo}/actions/variables/{variablename} repository createRepoVariable // --- // summary: Create a repo-level variable @@ -302,7 +361,7 @@ func CreateVariable(ctx *context.APIContext) { } // UpdateVariable update a repo-level variable -func UpdateVariable(ctx *context.APIContext) { +func (Action) UpdateVariable(ctx *context.APIContext) { // swagger:operation PUT /repos/{owner}/{repo}/actions/variables/{variablename} repository updateRepoVariable // --- // summary: Update a repo-level variable @@ -369,7 +428,7 @@ func UpdateVariable(ctx *context.APIContext) { } // ListVariables list repo-level variables -func ListVariables(ctx *context.APIContext) { +func (Action) ListVariables(ctx *context.APIContext) { // swagger:operation GET /repos/{owner}/{repo}/actions/variables repository getRepoVariablesList // --- // summary: Get repo-level variables list @@ -423,3 +482,38 @@ func ListVariables(ctx *context.APIContext) { ctx.SetTotalCountHeader(count) ctx.JSON(http.StatusOK, variables) } + +// GetRegistrationToken returns the token to register repo runners +func (Action) GetRegistrationToken(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/runners/registration-token repository repoGetRunnerRegistrationToken + // --- + // summary: Get a repository's actions runner registration token + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // responses: + // "200": + // "$ref": "#/responses/RegistrationToken" + + shared.GetRegistrationToken(ctx, ctx.Repo.Repository.OwnerID, ctx.Repo.Repository.ID) +} + +var _ actions_service.API = new(Action) + +// Action implements actions_service.API +type Action struct{} + +// NewAction creates a new Action service +func NewAction() actions_service.API { + return Action{} +} diff --git a/routers/api/v1/repo/runners.go b/routers/api/v1/repo/runners.go deleted file mode 100644 index fe133b311d..0000000000 --- a/routers/api/v1/repo/runners.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package repo - -import ( - "code.gitea.io/gitea/routers/api/v1/shared" - "code.gitea.io/gitea/services/context" -) - -// GetRegistrationToken returns the token to register repo runners -func GetRegistrationToken(ctx *context.APIContext) { - // swagger:operation GET /repos/{owner}/{repo}/runners/registration-token repository repoGetRunnerRegistrationToken - // --- - // summary: Get a repository's actions runner registration token - // produces: - // - application/json - // parameters: - // - name: owner - // in: path - // description: owner of the repo - // type: string - // required: true - // - name: repo - // in: path - // description: name of the repo - // type: string - // required: true - // responses: - // "200": - // "$ref": "#/responses/RegistrationToken" - - shared.GetRegistrationToken(ctx, ctx.Repo.Repository.OwnerID, ctx.Repo.Repository.ID) -} diff --git a/services/actions/interface.go b/services/actions/interface.go new file mode 100644 index 0000000000..d4fa782fec --- /dev/null +++ b/services/actions/interface.go @@ -0,0 +1,28 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package actions + +import "code.gitea.io/gitea/services/context" + +// API for actions of a repository or organization +type API interface { + // ListActionsSecrets list secrets + ListActionsSecrets(*context.APIContext) + // CreateOrUpdateSecret create or update a secret + CreateOrUpdateSecret(*context.APIContext) + // DeleteSecret delete a secret + DeleteSecret(*context.APIContext) + // ListVariables list variables + ListVariables(*context.APIContext) + // GetVariable get a variable + GetVariable(*context.APIContext) + // DeleteVariable delete a variable + DeleteVariable(*context.APIContext) + // CreateVariable create a variable + CreateVariable(*context.APIContext) + // UpdateVariable update a variable + UpdateVariable(*context.APIContext) + // GetRegistrationToken get registration token + GetRegistrationToken(*context.APIContext) +} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index faf57454d7..3ed4e43e6d 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -3843,6 +3843,54 @@ } } }, + "/repos/{owner}/{repo}/actions/secrets": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "repository" + ], + "summary": "List an repo's actions secrets", + "operationId": "repoListActionsSecrets", + "parameters": [ + { + "type": "string", + "description": "owner of the repository", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repository", + "name": "repo", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "page number of results to return (1-based)", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "page size of results", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "$ref": "#/responses/SecretList" + }, + "404": { + "$ref": "#/responses/notFound" + } + } + } + }, "/repos/{owner}/{repo}/actions/secrets/{secretname}": { "put": { "consumes": [ diff --git a/tests/integration/api_repo_secrets_test.go b/tests/integration/api_repo_secrets_test.go index feb9bae2b2..c3074d9ece 100644 --- a/tests/integration/api_repo_secrets_test.go +++ b/tests/integration/api_repo_secrets_test.go @@ -24,6 +24,12 @@ func TestAPIRepoSecrets(t *testing.T) { session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) + t.Run("List", func(t *testing.T) { + req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/secrets", repo.FullName())). + AddTokenAuth(token) + MakeRequest(t, req, http.StatusOK) + }) + t.Run("Create", func(t *testing.T) { cases := []struct { Name string @@ -31,7 +37,7 @@ func TestAPIRepoSecrets(t *testing.T) { }{ { Name: "", - ExpectedStatus: http.StatusNotFound, + ExpectedStatus: http.StatusMethodNotAllowed, }, { Name: "-", From c93eefb42b535f7a3917149a183f05a8b551ce26 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Fri, 26 Apr 2024 21:37:21 +0200 Subject: [PATCH 212/370] Diff color enhancements, add line number background (#30670) 1. Bring back the background on line numbers. This feature was lost a long time ago. <img width="457" alt="Screenshot 2024-04-24 at 01 36 09" src="https://github.com/go-gitea/gitea/assets/115237/76a7f5a9-c22a-4c72-9f0a-ebf16a66513e"> <img width="473" alt="Screenshot 2024-04-24 at 01 22 47" src="https://github.com/go-gitea/gitea/assets/115237/eef06cf2-f1b9-40e3-947d-dd5852ec12a3"> <img width="457" alt="Screenshot 2024-04-24 at 02 13 18" src="https://github.com/go-gitea/gitea/assets/115237/59e317d4-76a7-468c-8a19-10d88c675cc3"> <img width="459" alt="Screenshot 2024-04-24 at 01 23 21" src="https://github.com/go-gitea/gitea/assets/115237/f1a46f8d-8846-4d78-a9d7-8b7dc18ac6e4"> 2. Expanded lines background is now full-line, including line numbers: <img width="1303" alt="Screenshot 2024-04-24 at 01 37 12" src="https://github.com/go-gitea/gitea/assets/115237/271eefe2-0869-424e-93fb-ccd8adc87806"> 3. Sort affected colors alphabetically in the CSS Fixes #14603 --- templates/repo/diff/blob_excerpt.tmpl | 22 +++++++-------- web_src/css/repo.css | 28 ++++++++++++++----- ...eme-gitea-dark-protanopia-deuteranopia.css | 11 ++++---- web_src/css/themes/theme-gitea-dark.css | 16 ++++++----- ...me-gitea-light-protanopia-deuteranopia.css | 7 +++-- web_src/css/themes/theme-gitea-light.css | 14 ++++++---- 6 files changed, 59 insertions(+), 39 deletions(-) diff --git a/templates/repo/diff/blob_excerpt.tmpl b/templates/repo/diff/blob_excerpt.tmpl index 8312b5d913..a80abe263f 100644 --- a/templates/repo/diff/blob_excerpt.tmpl +++ b/templates/repo/diff/blob_excerpt.tmpl @@ -1,6 +1,6 @@ {{if $.IsSplitStyle}} {{range $k, $line := $.section.Lines}} - <tr class="{{.GetHTMLDiffLineType}}-code nl-{{$k}} ol-{{$k}}"> + <tr class="{{.GetHTMLDiffLineType}}-code nl-{{$k}} ol-{{$k}} line-expanded"> {{if eq .GetType 4}} <td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"> <div class="tw-flex"> @@ -26,17 +26,17 @@ {{else}} {{$inlineDiff := $.section.GetComputedInlineDiffFor $line ctx.Locale}} <td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{$.FileNameHash}}L{{$line.LeftIdx}}{{end}}"></span></td> - <td class="blob-excerpt lines-escape lines-escape-old">{{if and $line.LeftIdx $inlineDiff.EscapeStatus.Escaped}}<button class="toggle-escape-button btn interact-bg" title="{{template "repo/diff/escape_title" dict "diff" $inlineDiff}}"></button>{{end}}</td> - <td class="blob-excerpt lines-type-marker lines-type-marker-old">{{if $line.LeftIdx}}<span class="tw-font-mono" data-type-marker=""></span>{{end}}</td> - <td class="blob-excerpt lines-code lines-code-old">{{/* + <td class="lines-escape lines-escape-old">{{if and $line.LeftIdx $inlineDiff.EscapeStatus.Escaped}}<button class="toggle-escape-button btn interact-bg" title="{{template "repo/diff/escape_title" dict "diff" $inlineDiff}}"></button>{{end}}</td> + <td class="lines-type-marker lines-type-marker-old">{{if $line.LeftIdx}}<span class="tw-font-mono" data-type-marker=""></span>{{end}}</td> + <td class="lines-code lines-code-old">{{/* */}}{{if $line.LeftIdx}}{{template "repo/diff/section_code" dict "diff" $inlineDiff}}{{else}}{{/* */}}<code class="code-inner"></code>{{/* */}}{{end}}{{/* */}}</td> <td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{$.FileNameHash}}R{{$line.RightIdx}}{{end}}"></span></td> - <td class="blob-excerpt lines-escape lines-escape-new">{{if and $line.RightIdx $inlineDiff.EscapeStatus.Escaped}}<button class="toggle-escape-button btn interact-bg" title="{{template "repo/diff/escape_title" dict "diff" $inlineDiff}}"></button>{{end}}</td> - <td class="blob-excerpt lines-type-marker lines-type-marker-new">{{if $line.RightIdx}}<span class="tw-font-mono" data-type-marker=""></span>{{end}}</td> - <td class="blob-excerpt lines-code lines-code-new">{{/* + <td class="lines-escape lines-escape-new">{{if and $line.RightIdx $inlineDiff.EscapeStatus.Escaped}}<button class="toggle-escape-button btn interact-bg" title="{{template "repo/diff/escape_title" dict "diff" $inlineDiff}}"></button>{{end}}</td> + <td class="lines-type-marker lines-type-marker-new">{{if $line.RightIdx}}<span class="tw-font-mono" data-type-marker=""></span>{{end}}</td> + <td class="lines-code lines-code-new">{{/* */}}{{if $line.RightIdx}}{{template "repo/diff/section_code" dict "diff" $inlineDiff}}{{else}}{{/* */}}<code class="code-inner"></code>{{/* */}}{{end}}{{/* @@ -46,7 +46,7 @@ {{end}} {{else}} {{range $k, $line := $.section.Lines}} - <tr class="{{.GetHTMLDiffLineType}}-code nl-{{$k}} ol-{{$k}}"> + <tr class="{{.GetHTMLDiffLineType}}-code nl-{{$k}} ol-{{$k}} line-expanded"> {{if eq .GetType 4}} <td colspan="2" class="lines-num"> <div class="tw-flex"> @@ -72,9 +72,9 @@ <td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{$.FileNameHash}}R{{$line.RightIdx}}{{end}}"></span></td> {{end}} {{$inlineDiff := $.section.GetComputedInlineDiffFor $line ctx.Locale}} - <td class="blob-excerpt lines-escape">{{if $inlineDiff.EscapeStatus.Escaped}}<button class="toggle-escape-button btn interact-bg" title="{{template "repo/diff/escape_title" dict "diff" $inlineDiff}}"></button>{{end}}</td> - <td class="blob-excerpt lines-type-marker"><span class="tw-font-mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span></td> - <td class="blob-excerpt lines-code{{if (not $line.RightIdx)}} lines-code-old{{end}}"><code {{if $inlineDiff.EscapeStatus.Escaped}}class="code-inner has-escaped" title="{{template "repo/diff/escape_title" dict "diff" $inlineDiff}}"{{else}}class="code-inner"{{end}}>{{$inlineDiff.Content}}</code></td> + <td class="lines-escape">{{if $inlineDiff.EscapeStatus.Escaped}}<button class="toggle-escape-button btn interact-bg" title="{{template "repo/diff/escape_title" dict "diff" $inlineDiff}}"></button>{{end}}</td> + <td class="lines-type-marker"><span class="tw-font-mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span></td> + <td class="lines-code{{if (not $line.RightIdx)}} lines-code-old{{end}}"><code {{if $inlineDiff.EscapeStatus.Escaped}}class="code-inner has-escaped" title="{{template "repo/diff/escape_title" dict "diff" $inlineDiff}}"{{else}}class="code-inner"{{end}}>{{$inlineDiff.Content}}</code></td> </tr> {{end}} {{end}} diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 62a72abaf9..4de994112f 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -2377,7 +2377,7 @@ tbody.commit-list { .tag-code, .tag-code td, -.tag-code .blob-excerpt { +.tag-code.line-expanded { background-color: var(--color-box-body-highlight); vertical-align: middle; } @@ -2393,8 +2393,8 @@ tbody.commit-list { padding-top: 0 !important; } -.blob-excerpt { - background-color: var(--color-secondary-alpha-30); +.line-expanded { + background-color: var(--color-secondary-alpha-20); } .issue-keyword { @@ -2553,11 +2553,9 @@ tbody.commit-list { .code-diff-unified .add-code, .code-diff-unified .add-code td, -.code-diff-split .add-code .lines-num-new, .code-diff-split .add-code .lines-type-marker-new, .code-diff-split .add-code .lines-escape-new, .code-diff-split .add-code .lines-code-new, -.code-diff-split .del-code .add-code.lines-num-new, .code-diff-split .del-code .add-code.lines-type-marker-new, .code-diff-split .del-code .add-code.lines-escape-new, .code-diff-split .del-code .add-code.lines-code-new { @@ -2565,17 +2563,33 @@ tbody.commit-list { border-color: var(--color-diff-added-row-border); } -.code-diff-split .del-code .lines-num-new, .code-diff-split .del-code .lines-type-marker-new, .code-diff-split .del-code .lines-code-new, .code-diff-split .del-code .lines-escape-new, -.code-diff-split .add-code .lines-num-old, .code-diff-split .add-code .lines-escape-old, .code-diff-split .add-code .lines-type-marker-old, .code-diff-split .add-code .lines-code-old { background: var(--color-diff-inactive); } +.code-diff-split .add-code .lines-num.lines-num-old, +.code-diff-split .del-code .lines-num.lines-num-new { + background: var(--color-diff-inactive); +} + +.code-diff-unified .del-code .lines-num, +.code-diff-split .del-code .lines-num { + background: var(--color-diff-removed-linenum-bg); + color: var(--color-text); +} + +.code-diff-unified .add-code .lines-num, +.code-diff-split .add-code .lines-num, +.code-diff-split .del-code .add-code.lines-num { + background: var(--color-diff-added-linenum-bg); + color: var(--color-text); +} + .code-diff-split tbody tr td:nth-child(5), .code-diff-split tbody tr td.add-comment-right { border-left: 1px solid var(--color-secondary); diff --git a/web_src/css/themes/theme-gitea-dark-protanopia-deuteranopia.css b/web_src/css/themes/theme-gitea-dark-protanopia-deuteranopia.css index 681aa3b539..c1a6edaf35 100644 --- a/web_src/css/themes/theme-gitea-dark-protanopia-deuteranopia.css +++ b/web_src/css/themes/theme-gitea-dark-protanopia-deuteranopia.css @@ -3,9 +3,10 @@ /* red/green colorblind-friendly colors */ /* from GitHub: --diffBlob-addition-*, --diffBlob-deletion-*, etc */ :root { - --color-diff-added-word-bg: #388bfd66; - --color-diff-added-row-bg: #388bfd26; - - --color-diff-removed-word-bg: #db6d2866; - --color-diff-removed-row-bg: #db6d2826; + --color-diff-added-linenum-bg: #1979fd46; + --color-diff-added-row-bg: #1979fd20; + --color-diff-added-word-bg: #1979fd66; + --color-diff-removed-linenum-bg: #c8622146; + --color-diff-removed-row-bg: #c8622120; + --color-diff-removed-word-bg: #c8622166; } diff --git a/web_src/css/themes/theme-gitea-dark.css b/web_src/css/themes/theme-gitea-dark.css index 7bf2c982c6..ad9ab5a8c2 100644 --- a/web_src/css/themes/theme-gitea-dark.css +++ b/web_src/css/themes/theme-gitea-dark.css @@ -143,14 +143,16 @@ --color-grey-light: #818f9e; --color-gold: #b1983b; --color-white: #ffffff; - --color-diff-removed-word-bg: #6f3333; - --color-diff-added-word-bg: #3c653c; - --color-diff-removed-row-bg: #3c2626; - --color-diff-moved-row-bg: #818044; - --color-diff-added-row-bg: #283e2d; - --color-diff-removed-row-border: #634343; - --color-diff-moved-row-border: #bcca6f; + --color-diff-added-linenum-bg: #274227; + --color-diff-added-row-bg: #203224; --color-diff-added-row-border: #314a37; + --color-diff-added-word-bg: #3c653c; + --color-diff-moved-row-bg: #818044; + --color-diff-moved-row-border: #bcca6f; + --color-diff-removed-linenum-bg: #482121; + --color-diff-removed-row-bg: #301e1e; + --color-diff-removed-row-border: #634343; + --color-diff-removed-word-bg: #6f3333; --color-diff-inactive: #22282d; --color-error-border: #a04141; --color-error-bg: #522; diff --git a/web_src/css/themes/theme-gitea-light-protanopia-deuteranopia.css b/web_src/css/themes/theme-gitea-light-protanopia-deuteranopia.css index 7e03d90f5c..f42fa1db2c 100644 --- a/web_src/css/themes/theme-gitea-light-protanopia-deuteranopia.css +++ b/web_src/css/themes/theme-gitea-light-protanopia-deuteranopia.css @@ -3,9 +3,10 @@ /* red/green colorblind-friendly colors */ /* from GitHub: --diffBlob-addition-*, --diffBlob-deletion-*, etc */ :root { - --color-diff-added-word-bg: #54aeff66; + --color-diff-added-linenum-bg: #54aeff4d; --color-diff-added-row-bg: #ddf4ff80; - - --color-diff-removed-word-bg: #ffb77c80; + --color-diff-added-word-bg: #54aeff66; + --color-diff-removed-linenum-bg: #ffb77c4d; --color-diff-removed-row-bg: #fff1e580; + --color-diff-removed-word-bg: #ffb77c80; } diff --git a/web_src/css/themes/theme-gitea-light.css b/web_src/css/themes/theme-gitea-light.css index dfccd37647..8d4aa6df93 100644 --- a/web_src/css/themes/theme-gitea-light.css +++ b/web_src/css/themes/theme-gitea-light.css @@ -143,14 +143,16 @@ --color-grey-light: #7c838a; --color-gold: #a1882b; --color-white: #ffffff; - --color-diff-removed-word-bg: #fdb8c0; - --color-diff-added-word-bg: #acf2bd; - --color-diff-removed-row-bg: #ffeef0; - --color-diff-moved-row-bg: #f1f8d1; + --color-diff-added-linenum-bg: #d1f8d9; --color-diff-added-row-bg: #e6ffed; - --color-diff-removed-row-border: #f1c0c0; - --color-diff-moved-row-border: #d0e27f; --color-diff-added-row-border: #e6ffed; + --color-diff-added-word-bg: #acf2bd; + --color-diff-moved-row-bg: #f1f8d1; + --color-diff-moved-row-border: #d0e27f; + --color-diff-removed-linenum-bg: #ffcecb; + --color-diff-removed-row-bg: #ffeef0; + --color-diff-removed-row-border: #f1c0c0; + --color-diff-removed-word-bg: #fdb8c0; --color-diff-inactive: #f0f2f4; --color-error-border: #e0b4b4; --color-error-bg: #fff6f6; From 27861d711b6284ccc774f974d8a5813ca2c488eb Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Sat, 27 Apr 2024 00:24:31 +0000 Subject: [PATCH 213/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_pt-PT.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 444f784af9..c711c72045 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -436,6 +436,7 @@ oauth_signin_submit=Vincular conta oauth.signin.error=Ocorreu um erro durante o processamento do pedido de autorização. Se este erro persistir, contacte o administrador. oauth.signin.error.access_denied=O pedido de autorização foi negado. oauth.signin.error.temporarily_unavailable=A autorização falhou porque o servidor de autenticação está temporariamente indisponível. Tente mais tarde. +oauth_callback_unable_auto_reg=O registo automático está habilitado, mas o fornecedor OAuth2 %[1]s sinalizou campos em falta: %[2]s, por isso não foi possível criar uma conta automaticamente. Crie ou vincule uma conta ou contacte o administrador do sítio. openid_connect_submit=Estabelecer ligação openid_connect_title=Estabelecer ligação a uma conta existente openid_connect_desc=O URI do OpenID escolhido é desconhecido. Associe-o a uma nova conta aqui. From dcc3c17e5c41ad446b71215b095617e066a2e8e1 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sat, 27 Apr 2024 09:21:07 +0200 Subject: [PATCH 214/370] Suppress browserslist warning in webpack target (#30571) 1. Set [`BROWSERSLIST_IGNORE_OLD_DATA`](https://github.com/browserslist/browserslist/blob/c6ddf7b3870a4585822d06ec77e8dd2401b8e1ed/node.js#L400) to avoid warning on outdated browserslist data which the end user can likely not do anything about and which is currently visible in the v1.21 branch. 2. Suppress all command echoing and add a "Running webpack..." message in place. Warning in question was this: ``` Browserslist: caniuse-lite is outdated. Please run: npx update-browserslist-db@latest Why you should do it regularly: https://github.com/browserslist/update-db#readme ``` --- Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 2a78c907c0..6477b26664 100644 --- a/Makefile +++ b/Makefile @@ -908,8 +908,9 @@ webpack: $(WEBPACK_DEST) $(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) package-lock.json @$(MAKE) -s node-check node_modules - rm -rf $(WEBPACK_DEST_ENTRIES) - npx webpack + @rm -rf $(WEBPACK_DEST_ENTRIES) + @echo "Running webpack..." + @BROWSERSLIST_IGNORE_OLD_DATA=true npx webpack @touch $(WEBPACK_DEST) .PHONY: svg From 9b2536b78fdcd3cf444a2f54857d9871e153858f Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sat, 27 Apr 2024 10:03:49 +0200 Subject: [PATCH 215/370] Update misspell to 0.5.1 and add `misspellings.csv` (#30573) Misspell 0.5.0 supports passing a csv file to extend the list of misspellings, so I added some common ones from the codebase. There is at least one typo in a API response so we need to decided whether to revert that and then likely remove the dict entry. --- Makefile | 6 +++--- .../config-cheat-sheet.en-us.md | 2 +- models/actions/run.go | 6 +++--- models/actions/task.go | 12 +++++------ models/actions/tasks_version.go | 8 +++---- models/fixtures/pull_request.yml | 20 +++++++++--------- models/issues/pull.go | 2 +- models/issues/tracked_time.go | 12 +++++------ models/migrations/v1_17/v216.go | 2 +- modules/git/ref.go | 2 +- modules/process/manager.go | 6 +++--- modules/templates/helper_test.go | 4 ++-- routers/api/actions/artifacts.go | 2 +- routers/api/actions/runner/interceptor.go | 4 ++-- routers/api/packages/README.md | 2 +- routers/api/v1/shared/runners.go | 2 +- routers/private/hook_pre_receive.go | 2 +- routers/web/admin/orgs.go | 2 +- routers/web/admin/users.go | 2 +- routers/web/repo/compare.go | 2 +- routers/web/repo/issue.go | 4 ++-- services/convert/issue_comment.go | 4 ++-- services/issue/assignee.go | 12 +++++------ services/issue/issue.go | 6 +++--- services/issue/pull.go | 8 +++---- services/org/org.go | 6 +++--- services/pull/check.go | 2 +- services/pull/comment.go | 2 +- services/pull/pull.go | 6 +++--- templates/swagger/v1_json.tmpl | 2 +- tests/integration/api_issue_config_test.go | 4 ++-- tests/integration/compare_test.go | 6 +++--- tools/misspellings.csv | 21 +++++++++++++++++++ web_src/js/bootstrap.js | 2 +- 34 files changed, 103 insertions(+), 82 deletions(-) create mode 100644 tools/misspellings.csv diff --git a/Makefile b/Makefile index 6477b26664..0cd6abb81e 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-che GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.6.0 GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.57.2 GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11 -MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.4.1 +MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.5.1 SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@db51e79a0e37c572d8b59ae0c58bf2bbbbe53285 XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1 @@ -397,11 +397,11 @@ lint-md: node_modules .PHONY: lint-spell lint-spell: - @go run $(MISSPELL_PACKAGE) -error $(SPELLCHECK_FILES) + @go run $(MISSPELL_PACKAGE) -dict tools/misspellings.csv -error $(SPELLCHECK_FILES) .PHONY: lint-spell-fix lint-spell-fix: - @go run $(MISSPELL_PACKAGE) -w $(SPELLCHECK_FILES) + @go run $(MISSPELL_PACKAGE) -dict tools/misspellings.csv -w $(SPELLCHECK_FILES) .PHONY: lint-go lint-go: diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index 14f562fc21..7bf23c9b99 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -1322,7 +1322,7 @@ Defaultly every storage has their default base path like below | actions_log | actions_log/ | | actions_artifacts | actions_artifacts/ | -And bucket, basepath or `SERVE_DIRECT` could be special or overrided, if you want to use a different you can: +And bucket, basepath or `SERVE_DIRECT` could be special or overridden, if you want to use a different you can: ```ini [storage.actions_log] diff --git a/models/actions/run.go b/models/actions/run.go index d68710f46d..4f886999e9 100644 --- a/models/actions/run.go +++ b/models/actions/run.go @@ -262,11 +262,11 @@ func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID strin // InsertRun inserts a run func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWorkflow) error { - ctx, commiter, err := db.TxContext(ctx) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } - defer commiter.Close() + defer committer.Close() index, err := db.GetNextResourceIndex(ctx, "action_run_index", run.RepoID) if err != nil { @@ -331,7 +331,7 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork } } - return commiter.Commit() + return committer.Commit() } func GetRunByID(ctx context.Context, id int64) (*ActionRun, error) { diff --git a/models/actions/task.go b/models/actions/task.go index 9946cf5233..f2f796a626 100644 --- a/models/actions/task.go +++ b/models/actions/task.go @@ -216,11 +216,11 @@ func GetRunningTaskByToken(ctx context.Context, token string) (*ActionTask, erro } func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask, bool, error) { - ctx, commiter, err := db.TxContext(ctx) + ctx, committer, err := db.TxContext(ctx) if err != nil { return nil, false, err } - defer commiter.Close() + defer committer.Close() e := db.GetEngine(ctx) @@ -322,7 +322,7 @@ func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask task.Job = job - if err := commiter.Commit(); err != nil { + if err := committer.Commit(); err != nil { return nil, false, err } @@ -347,11 +347,11 @@ func UpdateTaskByState(ctx context.Context, state *runnerv1.TaskState) (*ActionT stepStates[v.Id] = v } - ctx, commiter, err := db.TxContext(ctx) + ctx, committer, err := db.TxContext(ctx) if err != nil { return nil, err } - defer commiter.Close() + defer committer.Close() e := db.GetEngine(ctx) @@ -412,7 +412,7 @@ func UpdateTaskByState(ctx context.Context, state *runnerv1.TaskState) (*ActionT } } - if err := commiter.Commit(); err != nil { + if err := committer.Commit(); err != nil { return nil, err } diff --git a/models/actions/tasks_version.go b/models/actions/tasks_version.go index 5c0a86538d..96c5468c1a 100644 --- a/models/actions/tasks_version.go +++ b/models/actions/tasks_version.go @@ -13,7 +13,7 @@ import ( // ActionTasksVersion // If both ownerID and repoID is zero, its scope is global. -// If ownerID is not zero and repoID is zero, its scope is org (there is no user-level runner currrently). +// If ownerID is not zero and repoID is zero, its scope is org (there is no user-level runner currently). // If ownerID is zero and repoID is not zero, its scope is repo. type ActionTasksVersion struct { ID int64 `xorm:"pk autoincr"` @@ -73,11 +73,11 @@ func increaseTasksVersionByScope(ctx context.Context, ownerID, repoID int64) err } func IncreaseTaskVersion(ctx context.Context, ownerID, repoID int64) error { - ctx, commiter, err := db.TxContext(ctx) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } - defer commiter.Close() + defer committer.Close() // 1. increase global if err := increaseTasksVersionByScope(ctx, 0, 0); err != nil { @@ -101,5 +101,5 @@ func IncreaseTaskVersion(ctx context.Context, ownerID, repoID int64) error { } } - return commiter.Commit() + return committer.Commit() } diff --git a/models/fixtures/pull_request.yml b/models/fixtures/pull_request.yml index 3fc8ce630d..9a16316e5a 100644 --- a/models/fixtures/pull_request.yml +++ b/models/fixtures/pull_request.yml @@ -1,7 +1,7 @@ - id: 1 type: 0 # gitea pull request - status: 2 # mergable + status: 2 # mergeable issue_id: 2 index: 2 head_repo_id: 1 @@ -16,7 +16,7 @@ - id: 2 type: 0 # gitea pull request - status: 2 # mergable + status: 2 # mergeable issue_id: 3 index: 3 head_repo_id: 1 @@ -29,7 +29,7 @@ - id: 3 type: 0 # gitea pull request - status: 2 # mergable + status: 2 # mergeable issue_id: 8 index: 1 head_repo_id: 11 @@ -42,7 +42,7 @@ - id: 4 type: 0 # gitea pull request - status: 2 # mergable + status: 2 # mergeable issue_id: 9 index: 1 head_repo_id: 48 @@ -55,7 +55,7 @@ - id: 5 # this PR is outdated (one commit behind branch1 ) type: 0 # gitea pull request - status: 2 # mergable + status: 2 # mergeable issue_id: 11 index: 5 head_repo_id: 1 @@ -68,7 +68,7 @@ - id: 6 type: 0 # gitea pull request - status: 2 # mergable + status: 2 # mergeable issue_id: 12 index: 2 head_repo_id: 3 @@ -81,7 +81,7 @@ - id: 7 type: 0 # gitea pull request - status: 2 # mergable + status: 2 # mergeable issue_id: 19 index: 1 head_repo_id: 58 @@ -94,7 +94,7 @@ - id: 8 type: 0 # gitea pull request - status: 2 # mergable + status: 2 # mergeable issue_id: 20 index: 1 head_repo_id: 23 @@ -103,7 +103,7 @@ - id: 9 type: 0 # gitea pull request - status: 2 # mergable + status: 2 # mergeable issue_id: 21 index: 1 head_repo_id: 60 @@ -112,7 +112,7 @@ - id: 10 type: 0 # gitea pull request - status: 2 # mergable + status: 2 # mergeable issue_id: 22 index: 1 head_repo_id: 61 diff --git a/models/issues/pull.go b/models/issues/pull.go index dc1b1b956a..4194df2e3d 100644 --- a/models/issues/pull.go +++ b/models/issues/pull.go @@ -807,7 +807,7 @@ func UpdateAllowEdits(ctx context.Context, pr *PullRequest) error { // Mergeable returns if the pullrequest is mergeable. func (pr *PullRequest) Mergeable(ctx context.Context) bool { - // If a pull request isn't mergable if it's: + // If a pull request isn't mergeable if it's: // - Being conflict checked. // - Has a conflict. // - Received a error while being conflict checked. diff --git a/models/issues/tracked_time.go b/models/issues/tracked_time.go index 4063ca043b..caa582a9fc 100644 --- a/models/issues/tracked_time.go +++ b/models/issues/tracked_time.go @@ -187,8 +187,8 @@ func AddTime(ctx context.Context, user *user_model.User, issue *Issue, amount in Issue: issue, Repo: issue.Repo, Doer: user, - // Content before v1.21 did store the formated string instead of seconds, - // so use "|" as delimeter to mark the new format + // Content before v1.21 did store the formatted string instead of seconds, + // so use "|" as delimiter to mark the new format Content: fmt.Sprintf("|%d", amount), Type: CommentTypeAddTimeManual, TimeID: t.ID, @@ -267,8 +267,8 @@ func DeleteIssueUserTimes(ctx context.Context, issue *Issue, user *user_model.Us Issue: issue, Repo: issue.Repo, Doer: user, - // Content before v1.21 did store the formated string instead of seconds, - // so use "|" as delimeter to mark the new format + // Content before v1.21 did store the formatted string instead of seconds, + // so use "|" as delimiter to mark the new format Content: fmt.Sprintf("|%d", removedTime), Type: CommentTypeDeleteTimeManual, }); err != nil { @@ -298,8 +298,8 @@ func DeleteTime(ctx context.Context, t *TrackedTime) error { Issue: t.Issue, Repo: t.Issue.Repo, Doer: t.User, - // Content before v1.21 did store the formated string instead of seconds, - // so use "|" as delimeter to mark the new format + // Content before v1.21 did store the formatted string instead of seconds, + // so use "|" as delimiter to mark the new format Content: fmt.Sprintf("|%d", t.Time), Type: CommentTypeDeleteTimeManual, }); err != nil { diff --git a/models/migrations/v1_17/v216.go b/models/migrations/v1_17/v216.go index 59b21d9b2c..268f472a42 100644 --- a/models/migrations/v1_17/v216.go +++ b/models/migrations/v1_17/v216.go @@ -4,4 +4,4 @@ package v1_17 //nolint // This migration added non-ideal indices to the action table which on larger datasets slowed things down -// it has been superceded by v218.go +// it has been superseded by v218.go diff --git a/modules/git/ref.go b/modules/git/ref.go index ed801f20d5..2db630e2ea 100644 --- a/modules/git/ref.go +++ b/modules/git/ref.go @@ -184,7 +184,7 @@ func (ref RefName) RefGroup() string { } // RefType returns the simple ref type of the reference, e.g. branch, tag -// It's differrent from RefGroup, which is using the name of the directory under .git/refs +// It's different from RefGroup, which is using the name of the directory under .git/refs // Here we using branch but not heads, using tag but not tags func (ref RefName) RefType() string { var refType string diff --git a/modules/process/manager.go b/modules/process/manager.go index 9c21f62152..bdc4931810 100644 --- a/modules/process/manager.go +++ b/modules/process/manager.go @@ -134,7 +134,7 @@ func (pm *Manager) AddTypedContext(parent context.Context, description, processT // // Most processes will not need to use the cancel function but there will be cases whereby you want to cancel the process but not immediately remove it from the // process table. -func (pm *Manager) AddContextTimeout(parent context.Context, timeout time.Duration, description string) (ctx context.Context, cancel context.CancelFunc, finshed FinishedFunc) { +func (pm *Manager) AddContextTimeout(parent context.Context, timeout time.Duration, description string) (ctx context.Context, cancel context.CancelFunc, finished FinishedFunc) { if timeout <= 0 { // it's meaningless to use timeout <= 0, and it must be a bug! so we must panic here to tell developers to make the timeout correct panic("the timeout must be greater than zero, otherwise the context will be cancelled immediately") @@ -142,9 +142,9 @@ func (pm *Manager) AddContextTimeout(parent context.Context, timeout time.Durati ctx, cancel = context.WithTimeout(parent, timeout) - ctx, _, finshed = pm.Add(ctx, description, cancel, NormalProcessType, true) + ctx, _, finished = pm.Add(ctx, description, cancel, NormalProcessType, true) - return ctx, cancel, finshed + return ctx, cancel, finished } // Add create a new process diff --git a/modules/templates/helper_test.go b/modules/templates/helper_test.go index 64f29d033e..0cefb7a6b2 100644 --- a/modules/templates/helper_test.go +++ b/modules/templates/helper_test.go @@ -49,9 +49,9 @@ func TestSubjectBodySeparator(t *testing.T) { test("Multiple\n---\n-------\n---\nSeparators", "Multiple\n", "\n-------\n---\nSeparators") - test("Insuficient\n--\nSeparators", + test("Insufficient\n--\nSeparators", "", - "Insuficient\n--\nSeparators") + "Insufficient\n--\nSeparators") } func TestJSEscapeSafe(t *testing.T) { diff --git a/routers/api/actions/artifacts.go b/routers/api/actions/artifacts.go index 8198abb8a0..3e717b8d8f 100644 --- a/routers/api/actions/artifacts.go +++ b/routers/api/actions/artifacts.go @@ -301,7 +301,7 @@ func (ar artifactRoutes) uploadArtifact(ctx *ArtifactContext) { }) } -// comfirmUploadArtifact comfirm upload artifact. +// comfirmUploadArtifact confirm upload artifact. // if all chunks are uploaded, merge them to one file. func (ar artifactRoutes) comfirmUploadArtifact(ctx *ArtifactContext) { _, runID, ok := validateRunID(ctx) diff --git a/routers/api/actions/runner/interceptor.go b/routers/api/actions/runner/interceptor.go index c2f4ade174..0e99f3deda 100644 --- a/routers/api/actions/runner/interceptor.go +++ b/routers/api/actions/runner/interceptor.go @@ -36,7 +36,7 @@ var withRunner = connect.WithInterceptors(connect.UnaryInterceptorFunc(func(unar uuid := request.Header().Get(uuidHeaderKey) token := request.Header().Get(tokenHeaderKey) // TODO: version will be removed from request header after Gitea 1.20 released. - // And Gitea will not try to read version from reuqest header + // And Gitea will not try to read version from request header version := request.Header().Get(versionHeaderKey) runner, err := actions_model.GetRunnerByUUID(ctx, uuid) @@ -53,7 +53,7 @@ var withRunner = connect.WithInterceptors(connect.UnaryInterceptorFunc(func(unar cols := []string{"last_online"} // TODO: version will be removed from request header after Gitea 1.20 released. - // And Gitea will not try to read version from reuqest header + // And Gitea will not try to read version from request header version, _ = util.SplitStringAtByteN(version, 64) if !util.IsEmptyString(version) && runner.Version != version { runner.Version = version diff --git a/routers/api/packages/README.md b/routers/api/packages/README.md index 533a0d32f0..74d14922cb 100644 --- a/routers/api/packages/README.md +++ b/routers/api/packages/README.md @@ -19,7 +19,7 @@ The package registry code is divided into multiple modules to split the function ## Models -Every package registry implementation uses the same underlaying models: +Every package registry implementation uses the same underlying models: | Model | Description | | - | - | diff --git a/routers/api/v1/shared/runners.go b/routers/api/v1/shared/runners.go index c850ad7866..f088e9a2d4 100644 --- a/routers/api/v1/shared/runners.go +++ b/routers/api/v1/shared/runners.go @@ -12,7 +12,7 @@ import ( "code.gitea.io/gitea/services/context" ) -// RegistrationToken is response related to registeration token +// RegistrationToken is response related to registration token // swagger:response RegistrationToken type RegistrationToken struct { Token string `json:"token"` diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go index caab6b4c81..f35eb77d42 100644 --- a/routers/private/hook_pre_receive.go +++ b/routers/private/hook_pre_receive.go @@ -359,7 +359,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r }) return } - log.Error("Unable to check if mergable: protected branch %s in %-v and pr #%d. Error: %v", ctx.opts.UserID, branchName, repo, pr.Index, err) + log.Error("Unable to check if mergeable: protected branch %s in %-v and pr #%d. Error: %v", ctx.opts.UserID, branchName, repo, pr.Index, err) ctx.JSON(http.StatusInternalServerError, private.Response{ Err: fmt.Sprintf("Unable to get status of pull request %d. Error: %v", ctx.opts.PullRequestID, err), }) diff --git a/routers/web/admin/orgs.go b/routers/web/admin/orgs.go index c5454db71e..cea28f8220 100644 --- a/routers/web/admin/orgs.go +++ b/routers/web/admin/orgs.go @@ -30,7 +30,7 @@ func Organizations(ctx *context.Context) { explore.RenderUserSearch(ctx, &user_model.SearchUserOptions{ Actor: ctx.Doer, Type: user_model.UserTypeOrganization, - IncludeReserved: true, // administrator needs to list all acounts include reserved + IncludeReserved: true, // administrator needs to list all accounts include reserved ListOptions: db.ListOptions{ PageSize: setting.UI.Admin.OrgPagingNum, }, diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go index ea9d6f4c9c..d2330d5fa1 100644 --- a/routers/web/admin/users.go +++ b/routers/web/admin/users.go @@ -81,7 +81,7 @@ func Users(ctx *context.Context) { IsRestricted: util.OptionalBoolParse(statusFilterMap["is_restricted"]), IsTwoFactorEnabled: util.OptionalBoolParse(statusFilterMap["is_2fa_enabled"]), IsProhibitLogin: util.OptionalBoolParse(statusFilterMap["is_prohibit_login"]), - IncludeReserved: true, // administrator needs to list all acounts include reserved, bot, remote ones + IncludeReserved: true, // administrator needs to list all accounts include reserved, bot, remote ones ExtraParamStrings: extraParamStrings, }, tplUsers) } diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index a55426dab5..8c0fee71a0 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -812,7 +812,7 @@ func CompareDiff(ctx *context.Context) { // applicable if you have one commit to compare and that commit has a message. // In that case the commit message will be prepend to the template body. if templateContent, ok := ctx.Data[pullRequestTemplateKey].(string); ok && templateContent != "" { - // Re-use the same key as that's priortized over the "content" key. + // Re-use the same key as that's prioritized over the "content" key. // Add two new lines between the content to ensure there's always at least // one empty line between them. ctx.Data[pullRequestTemplateKey] = content + "\n\n" + templateContent diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 1bc5f343e7..de6ef9e93b 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -1760,8 +1760,8 @@ func ViewIssue(ctx *context.Context) { // drop error since times could be pruned from DB.. _ = comment.LoadTime(ctx) if comment.Content != "" { - // Content before v1.21 did store the formated string instead of seconds, - // so "|" is used as delimeter to mark the new format + // Content before v1.21 did store the formatted string instead of seconds, + // so "|" is used as delimiter to mark the new format if comment.Content[0] != '|' { // handle old time comments that have formatted text stored comment.RenderedContent = templates.SanitizeHTML(comment.Content) diff --git a/services/convert/issue_comment.go b/services/convert/issue_comment.go index 9ffaf1e84c..9ec9ac7684 100644 --- a/services/convert/issue_comment.go +++ b/services/convert/issue_comment.go @@ -72,8 +72,8 @@ func ToTimelineComment(ctx context.Context, repo *repo_model.Repository, c *issu c.Type == issues_model.CommentTypeStopTracking || c.Type == issues_model.CommentTypeDeleteTimeManual) && c.Content[0] == '|' { - // TimeTracking Comments from v1.21 on store the seconds instead of an formated string - // so we check for the "|" delimeter and convert new to legacy format on demand + // TimeTracking Comments from v1.21 on store the seconds instead of an formatted string + // so we check for the "|" delimiter and convert new to legacy format on demand c.Content = util.SecToTime(c.Content[1:]) } } diff --git a/services/issue/assignee.go b/services/issue/assignee.go index 8740a6664a..a0aa5a339b 100644 --- a/services/issue/assignee.go +++ b/services/issue/assignee.go @@ -229,12 +229,12 @@ func TeamReviewRequest(ctx context.Context, issue *issues_model.Issue, doer *use return comment, teamReviewRequestNotify(ctx, issue, doer, reviewer, isAdd, comment) } -func ReviewRequestNotify(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, reviewNotifers []*ReviewRequestNotifier) { - for _, reviewNotifer := range reviewNotifers { - if reviewNotifer.Reviwer != nil { - notify_service.PullRequestReviewRequest(ctx, issue.Poster, issue, reviewNotifer.Reviwer, reviewNotifer.IsAdd, reviewNotifer.Comment) - } else if reviewNotifer.ReviewTeam != nil { - if err := teamReviewRequestNotify(ctx, issue, issue.Poster, reviewNotifer.ReviewTeam, reviewNotifer.IsAdd, reviewNotifer.Comment); err != nil { +func ReviewRequestNotify(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, reviewNotifiers []*ReviewRequestNotifier) { + for _, reviewNotifier := range reviewNotifiers { + if reviewNotifier.Reviewer != nil { + notify_service.PullRequestReviewRequest(ctx, issue.Poster, issue, reviewNotifier.Reviewer, reviewNotifier.IsAdd, reviewNotifier.Comment) + } else if reviewNotifier.ReviewTeam != nil { + if err := teamReviewRequestNotify(ctx, issue, issue.Poster, reviewNotifier.ReviewTeam, reviewNotifier.IsAdd, reviewNotifier.Comment); err != nil { log.Error("teamReviewRequestNotify: %v", err) } } diff --git a/services/issue/issue.go b/services/issue/issue.go index c7fa9f3300..b0e50f2b89 100644 --- a/services/issue/issue.go +++ b/services/issue/issue.go @@ -90,17 +90,17 @@ func ChangeTitle(ctx context.Context, issue *issues_model.Issue, doer *user_mode return err } - var reviewNotifers []*ReviewRequestNotifier + var reviewNotifiers []*ReviewRequestNotifier if issue.IsPull && issues_model.HasWorkInProgressPrefix(oldTitle) && !issues_model.HasWorkInProgressPrefix(title) { var err error - reviewNotifers, err = PullRequestCodeOwnersReview(ctx, issue, issue.PullRequest) + reviewNotifiers, err = PullRequestCodeOwnersReview(ctx, issue, issue.PullRequest) if err != nil { log.Error("PullRequestCodeOwnersReview: %v", err) } } notify_service.IssueChangeTitle(ctx, doer, issue, oldTitle) - ReviewRequestNotify(ctx, issue, issue.Poster, reviewNotifers) + ReviewRequestNotify(ctx, issue, issue.Poster, reviewNotifiers) return nil } diff --git a/services/issue/pull.go b/services/issue/pull.go index 4a0009e82f..896802108d 100644 --- a/services/issue/pull.go +++ b/services/issue/pull.go @@ -36,7 +36,7 @@ func getMergeBase(repo *git.Repository, pr *issues_model.PullRequest, baseBranch type ReviewRequestNotifier struct { Comment *issues_model.Comment IsAdd bool - Reviwer *user_model.User + Reviewer *user_model.User ReviewTeam *org_model.Team } @@ -124,9 +124,9 @@ func PullRequestCodeOwnersReview(ctx context.Context, issue *issues_model.Issue, return nil, err } notifiers = append(notifiers, &ReviewRequestNotifier{ - Comment: comment, - IsAdd: true, - Reviwer: u, + Comment: comment, + IsAdd: true, + Reviewer: u, }) } } diff --git a/services/org/org.go b/services/org/org.go index dca7794b47..c19572a123 100644 --- a/services/org/org.go +++ b/services/org/org.go @@ -20,11 +20,11 @@ import ( // DeleteOrganization completely and permanently deletes everything of organization. func DeleteOrganization(ctx context.Context, org *org_model.Organization, purge bool) error { - ctx, commiter, err := db.TxContext(ctx) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } - defer commiter.Close() + defer committer.Close() if purge { err := repo_service.DeleteOwnerRepositoriesDirectly(ctx, org.AsUser()) @@ -52,7 +52,7 @@ func DeleteOrganization(ctx context.Context, org *org_model.Organization, purge return fmt.Errorf("DeleteOrganization: %w", err) } - if err := commiter.Commit(); err != nil { + if err := committer.Commit(); err != nil { return err } diff --git a/services/pull/check.go b/services/pull/check.go index f4dd332b14..9495e8ad5f 100644 --- a/services/pull/check.go +++ b/services/pull/check.go @@ -66,7 +66,7 @@ const ( MergeCheckTypeAuto // Auto Merge (Scheduled Merge) After Checks Succeed ) -// CheckPullMergable check if the pull mergable based on all conditions (branch protection, merge options, ...) +// CheckPullMergable check if the pull mergeable based on all conditions (branch protection, merge options, ...) func CheckPullMergable(stdCtx context.Context, doer *user_model.User, perm *access_model.Permission, pr *issues_model.PullRequest, mergeCheckType MergeCheckType, adminSkipProtectionCheck bool) error { return db.WithTx(stdCtx, func(ctx context.Context) error { if pr.HasMerged { diff --git a/services/pull/comment.go b/services/pull/comment.go index d538b118d5..53587d4f54 100644 --- a/services/pull/comment.go +++ b/services/pull/comment.go @@ -46,7 +46,7 @@ func getCommitIDsFromRepo(ctx context.Context, repo *repo_model.Repository, oldC return commitIDs, isForcePush, err } - // Find commits between new and old commit exclusing base branch commits + // Find commits between new and old commit excluding base branch commits commits, err := gitRepo.CommitsBetweenNotBase(newCommit, oldCommit, baseBranch) if err != nil { return nil, false, err diff --git a/services/pull/pull.go b/services/pull/pull.go index 764be5c6e3..5c0ea42d77 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -77,7 +77,7 @@ func NewPullRequest(ctx context.Context, repo *repo_model.Repository, issue *iss } defer baseGitRepo.Close() - var reviewNotifers []*issue_service.ReviewRequestNotifier + var reviewNotifiers []*issue_service.ReviewRequestNotifier if err := db.WithTx(ctx, func(ctx context.Context) error { if err := issues_model.NewPullRequest(ctx, repo, issue, labelIDs, uuids, pr); err != nil { return err @@ -137,7 +137,7 @@ func NewPullRequest(ctx context.Context, repo *repo_model.Repository, issue *iss } if !pr.IsWorkInProgress(ctx) { - reviewNotifers, err = issue_service.PullRequestCodeOwnersReview(ctx, issue, pr) + reviewNotifiers, err = issue_service.PullRequestCodeOwnersReview(ctx, issue, pr) if err != nil { return err } @@ -152,7 +152,7 @@ func NewPullRequest(ctx context.Context, repo *repo_model.Repository, issue *iss } baseGitRepo.Close() // close immediately to avoid notifications will open the repository again - issue_service.ReviewRequestNotify(ctx, issue, issue.Poster, reviewNotifers) + issue_service.ReviewRequestNotify(ctx, issue, issue.Poster, reviewNotifiers) mentions, err := issues_model.FindAndUpdateIssueMentions(ctx, issue, issue.Poster, issue.Content) if err != nil { diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 3ed4e43e6d..362a847332 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -25282,7 +25282,7 @@ } }, "RegistrationToken": { - "description": "RegistrationToken is response related to registeration token", + "description": "RegistrationToken is response related to registration token", "headers": { "token": { "type": "string" diff --git a/tests/integration/api_issue_config_test.go b/tests/integration/api_issue_config_test.go index b9125438b6..745d0cb2a2 100644 --- a/tests/integration/api_issue_config_test.go +++ b/tests/integration/api_issue_config_test.go @@ -119,9 +119,9 @@ func TestAPIRepoIssueConfigPaths(t *testing.T) { ".github/issue_template/config", } - for _, canidate := range templateConfigCandidates { + for _, candidate := range templateConfigCandidates { for _, extension := range []string{".yaml", ".yml"} { - fullPath := canidate + extension + fullPath := candidate + extension t.Run(fullPath, func(t *testing.T) { configMap := make(map[string]any) configMap["blank_issues_enabled"] = false diff --git a/tests/integration/compare_test.go b/tests/integration/compare_test.go index 509524ca56..27b2920cc1 100644 --- a/tests/integration/compare_test.go +++ b/tests/integration/compare_test.go @@ -67,7 +67,7 @@ func TestCompareBranches(t *testing.T) { session := loginUser(t, "user2") - // Inderect compare remove-files-b (head) with add-csv (base) branch + // Indirect compare remove-files-b (head) with add-csv (base) branch // // 'link_hi' and 'test.csv' are deleted, 'test.txt' is added req := NewRequest(t, "GET", "/user2/repo20/compare/add-csv...remove-files-b") @@ -79,7 +79,7 @@ func TestCompareBranches(t *testing.T) { inspectCompare(t, htmlDoc, diffCount, diffChanges) - // Inderect compare remove-files-b (head) with remove-files-a (base) branch + // Indirect compare remove-files-b (head) with remove-files-a (base) branch // // 'link_hi' and 'test.csv' are deleted, 'test.txt' is added @@ -92,7 +92,7 @@ func TestCompareBranches(t *testing.T) { inspectCompare(t, htmlDoc, diffCount, diffChanges) - // Inderect compare remove-files-a (head) with remove-files-b (base) branch + // Indirect compare remove-files-a (head) with remove-files-b (base) branch // // 'link_hi' and 'test.csv' are deleted diff --git a/tools/misspellings.csv b/tools/misspellings.csv new file mode 100644 index 0000000000..645fb7853b --- /dev/null +++ b/tools/misspellings.csv @@ -0,0 +1,21 @@ +acounts,accounts +canidate,candidate +comfirm,confirm +converage,coverage +currrently,currently +delimeter,delimiter +differrent,different +exclusing,excluding +finshed,finished +formated,formatted +inderect,indirect +insuficient,insufficient +likly,likely +mergable,mergeable +overrided,overridden +priortized,prioritized +registeration,registration +reuqest,request +reviwer,reviewer +superceded,superseded +underlaying,underlying diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index 3034478190..6cca37f7ca 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -50,7 +50,7 @@ function processWindowErrorEvent({error, reason, message, type, filename, lineno const assetBaseUrl = String(new URL(__webpack_public_path__, window.location.origin)); const {runModeIsProd} = window.config ?? {}; - // `error` and `reason` are not guaranteed to be errors. If the value is falsy, it is likly a + // `error` and `reason` are not guaranteed to be errors. If the value is falsy, it is likely a // non-critical event from the browser. We log them but don't show them to users. Examples: // - https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver#observation_errors // - https://github.com/mozilla-mobile/firefox-ios/issues/10817 From 4ae6b1a5534e4cc85602e990054c66a08b11852e Mon Sep 17 00:00:00 2001 From: Chongyi Zheng <git@zcy.dev> Date: Sat, 27 Apr 2024 06:44:49 -0400 Subject: [PATCH 216/370] Remove unused parameter for some functions in `services/mirror` (#30724) Suggested by gopls `unusedparams` --- services/mirror/mirror.go | 6 +++--- services/mirror/mirror_pull.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/services/mirror/mirror.go b/services/mirror/mirror.go index 72e545581a..0270f87039 100644 --- a/services/mirror/mirror.go +++ b/services/mirror/mirror.go @@ -40,7 +40,7 @@ func Update(ctx context.Context, pullLimit, pushLimit int) error { } log.Trace("Doing: Update") - handler := func(idx int, bean any) error { + handler := func(bean any) error { var repo *repo_model.Repository var mirrorType SyncType var referenceID int64 @@ -91,7 +91,7 @@ func Update(ctx context.Context, pullLimit, pushLimit int) error { pullMirrorsRequested := 0 if pullLimit != 0 { if err := repo_model.MirrorsIterate(ctx, pullLimit, func(idx int, bean any) error { - if err := handler(idx, bean); err != nil { + if err := handler(bean); err != nil { return err } pullMirrorsRequested++ @@ -105,7 +105,7 @@ func Update(ctx context.Context, pullLimit, pushLimit int) error { pushMirrorsRequested := 0 if pushLimit != 0 { if err := repo_model.PushMirrorsIterate(ctx, pushLimit, func(idx int, bean any) error { - if err := handler(idx, bean); err != nil { + if err := handler(bean); err != nil { return err } pushMirrorsRequested++ diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index f5eaeaf091..9f7ffb29c9 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -466,7 +466,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { log.Trace("SyncMirrors [repo: %-v]: %d branches updated", m.Repo, len(results)) if len(results) > 0 { - if ok := checkAndUpdateEmptyRepository(ctx, m, gitRepo, results); !ok { + if ok := checkAndUpdateEmptyRepository(ctx, m, results); !ok { log.Error("SyncMirrors [repo: %-v]: checkAndUpdateEmptyRepository: %v", m.Repo, err) return false } @@ -564,7 +564,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { return true } -func checkAndUpdateEmptyRepository(ctx context.Context, m *repo_model.Mirror, gitRepo *git.Repository, results []*mirrorSyncResult) bool { +func checkAndUpdateEmptyRepository(ctx context.Context, m *repo_model.Mirror, results []*mirrorSyncResult) bool { if !m.Repo.IsEmpty { return true } From b2abac5e5ff05362e2d200c99cf792e7c3ba1330 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sat, 27 Apr 2024 13:22:55 +0200 Subject: [PATCH 217/370] Improve diff stats bar (#30669) Minor tweaks: - Remove unnecessary `item` class which was causing unwanted padding to be added. - Add some padding and prevent wrapping so it looks better on mobile. - Increase width by 4px. <img width="116" alt="Screenshot 2024-04-24 at 00 15 07" src="https://github.com/go-gitea/gitea/assets/115237/1f1cf54c-8053-4297-b309-71d9c2ceb9ee"> <img width="441" alt="Screenshot 2024-04-24 at 00 14 57" src="https://github.com/go-gitea/gitea/assets/115237/2f3a33dc-edad-4b97-b64c-6812aae513cb"> --- templates/repo/pulls/tab_menu.tmpl | 2 +- web_src/css/repo.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/repo/pulls/tab_menu.tmpl b/templates/repo/pulls/tab_menu.tmpl index a6d058f160..d5a8d6ed21 100644 --- a/templates/repo/pulls/tab_menu.tmpl +++ b/templates/repo/pulls/tab_menu.tmpl @@ -16,7 +16,7 @@ <span class="ui small label">{{if .NumFiles}}{{.NumFiles}}{{else}}-{{end}}</span> </a> {{if or .Diff.TotalAddition .Diff.TotalDeletion}} - <span class="item tw-ml-auto tw-pr-0 tw-font-bold tw-flex tw-items-center tw-gap-2"> + <span class="tw-ml-auto tw-pl-3 tw-whitespace-nowrap tw-pr-0 tw-font-bold tw-flex tw-items-center tw-gap-2"> <span><span class="text green">{{if .Diff.TotalAddition}}+{{.Diff.TotalAddition}}{{end}}</span> <span class="text red">{{if .Diff.TotalDeletion}}-{{.Diff.TotalDeletion}}{{end}}</span></span> <span class="diff-stats-bar"> <div class="diff-stats-add-bar" style="width: {{Eval 100 "*" .Diff.TotalAddition "/" "(" .Diff.TotalAddition "+" .Diff.TotalDeletion "+" 0.0 ")"}}%"></div> diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 4de994112f..dacb98ddb8 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -2520,7 +2520,7 @@ tbody.commit-list { display: inline-block; background-color: var(--color-red); height: 12px; - width: 40px; + width: 44px; } .diff-stats-bar .diff-stats-add-bar { From 238eb3ff9f36bcf7b4637957ae2dd98446105894 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sat, 27 Apr 2024 13:28:28 +0200 Subject: [PATCH 218/370] Update JS dependencies (#30713) - Update all JS dependencies - Remove [now-unnecessary](https://github.com/microsoft/monaco-editor/issues/4325) monaco workaround - Update stylelint config for new rule - Tested Monaco, Swagger UI, Mermaid --- package-lock.json | 665 ++++++++++++++++++++-------------------- package.json | 26 +- stylelint.config.js | 5 +- web_src/js/bootstrap.js | 8 - 4 files changed, 347 insertions(+), 357 deletions(-) diff --git a/package-lock.json b/package-lock.json index 780689a0a3..8e4eeb7fb8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,9 @@ "packages": { "": { "dependencies": { - "@citation-js/core": "0.7.9", - "@citation-js/plugin-bibtex": "0.7.9", - "@citation-js/plugin-csl": "0.7.9", + "@citation-js/core": "0.7.11", + "@citation-js/plugin-bibtex": "0.7.11", + "@citation-js/plugin-csl": "0.7.11", "@citation-js/plugin-software-formats": "0.6.1", "@github/markdown-toolbar-element": "2.2.3", "@github/relative-time-element": "4.4.0", @@ -34,17 +34,17 @@ "katex": "0.16.10", "license-checker-webpack-plugin": "0.2.1", "mermaid": "10.9.0", - "mini-css-extract-plugin": "2.8.1", + "mini-css-extract-plugin": "2.9.0", "minimatch": "9.0.4", - "monaco-editor": "0.47.0", + "monaco-editor": "0.48.0", "monaco-editor-webpack-plugin": "7.1.0", "pdfobject": "2.3.0", "postcss": "8.4.38", "postcss-loader": "8.1.1", - "postcss-nesting": "12.1.1", + "postcss-nesting": "12.1.2", "pretty-ms": "9.0.0", "sortablejs": "1.15.2", - "swagger-ui-dist": "5.15.1", + "swagger-ui-dist": "5.17.2", "tailwindcss": "3.4.3", "temporal-polyfill": "0.2.4", "throttle-debounce": "5.0.0", @@ -54,7 +54,7 @@ "tributejs": "5.1.3", "uint8-to-base64": "0.2.0", "vanilla-colorful": "0.7.2", - "vue": "3.4.21", + "vue": "3.4.25", "vue-bar-graph": "2.0.0", "vue-chartjs": "5.3.1", "vue-loader": "17.4.2", @@ -67,7 +67,7 @@ "@eslint-community/eslint-plugin-eslint-comments": "4.3.0", "@playwright/test": "1.43.1", "@stoplight/spectral-cli": "6.11.1", - "@stylistic/eslint-plugin-js": "1.7.0", + "@stylistic/eslint-plugin-js": "1.7.2", "@stylistic/stylelint-plugin": "2.1.1", "@vitejs/plugin-vue": "5.0.4", "eslint": "8.57.0", @@ -82,20 +82,20 @@ "eslint-plugin-unicorn": "52.0.0", "eslint-plugin-vitest": "0.4.1", "eslint-plugin-vitest-globals": "1.5.0", - "eslint-plugin-vue": "9.24.1", + "eslint-plugin-vue": "9.25.0", "eslint-plugin-vue-scoped-css": "2.8.0", "eslint-plugin-wc": "2.1.0", "happy-dom": "14.7.1", "markdownlint-cli": "0.39.0", "postcss-html": "1.6.0", - "stylelint": "16.3.1", + "stylelint": "16.4.0", "stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-declaration-strict-value": "1.10.4", "stylelint-value-no-unknown-custom-properties": "6.0.1", "svgo": "3.2.0", "updates": "16.0.1", - "vite-string-plugin": "1.1.5", - "vitest": "1.5.0" + "vite-string-plugin": "1.2.0", + "vitest": "1.5.2" }, "engines": { "node": ">= 18.0.0" @@ -261,9 +261,9 @@ "integrity": "sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==" }, "node_modules/@citation-js/core": { - "version": "0.7.9", - "resolved": "https://registry.npmjs.org/@citation-js/core/-/core-0.7.9.tgz", - "integrity": "sha512-fSbkB32JayDChZnAYC/kB+sWHRvxxL7ibVetyBOyzOc+5aCnjb6UVsbcfhnkOIEyAMoRRvWDyFmakEoTtA5ttQ==", + "version": "0.7.11", + "resolved": "https://registry.npmjs.org/@citation-js/core/-/core-0.7.11.tgz", + "integrity": "sha512-evQtyzeW+Gbmq+xWciIq9sbcvXXDbm8q32orD/HDd5ay6RQFKoW/BKxBLp+Nmpxgspb9sxTJn3iFK7+jxOTNTw==", "dependencies": { "@citation-js/date": "^0.5.0", "@citation-js/name": "^0.4.2", @@ -291,9 +291,9 @@ } }, "node_modules/@citation-js/plugin-bibtex": { - "version": "0.7.9", - "resolved": "https://registry.npmjs.org/@citation-js/plugin-bibtex/-/plugin-bibtex-0.7.9.tgz", - "integrity": "sha512-gIJpCd6vmmTOcRfDrSOjtoNhw2Mi94UwFxmgJ7GwkXyTYcNheW5VlMMo1tlqjakJGARQ0eOsKcI57gSPqJSS2g==", + "version": "0.7.11", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-bibtex/-/plugin-bibtex-0.7.11.tgz", + "integrity": "sha512-G4vEmLjrQUxgBIp3ffWN5dDOlwjPsrRSi/uTyxDJuFgKBD8GR1eO7Y/ZcePNAOHMqUxG7lxhhBbZJwcJZNVHYw==", "dependencies": { "@citation-js/date": "^0.5.0", "@citation-js/name": "^0.4.2", @@ -319,9 +319,9 @@ } }, "node_modules/@citation-js/plugin-csl": { - "version": "0.7.9", - "resolved": "https://registry.npmjs.org/@citation-js/plugin-csl/-/plugin-csl-0.7.9.tgz", - "integrity": "sha512-mbD7CnUiPOuVnjeJwo+d0RGUcY0PE8n01gHyjq0qpTeS42EGmQ9+LzqfsTUVWWBndTwc6zLRuIF1qFAUHKE4oA==", + "version": "0.7.11", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-csl/-/plugin-csl-0.7.11.tgz", + "integrity": "sha512-4OGZ9wHZDfpgiPU2cOXWGuKt7P+ndGWAeLG95nOG+DXe5U+f9EEZTXfaM4C99x8Ri+g6JklR96A3kuYZxYLllg==", "dependencies": { "@citation-js/date": "^0.5.0", "citeproc": "^2.4.6" @@ -1420,9 +1420,9 @@ "dev": true }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.2.tgz", - "integrity": "sha512-ahxSgCkAEk+P/AVO0vYr7DxOD3CwAQrT0Go9BJyGQ9Ef0QxVOfjDZMiF4Y2s3mLyPrjonchIMH/tbWHucJMykQ==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.16.4.tgz", + "integrity": "sha512-GkhjAaQ8oUTOKE4g4gsZ0u8K/IHU1+2WQSgS1TwTcYvL+sjbaQjNHFXbOJ6kgqGHIO1DfUhI/Sphi9GkRT9K+Q==", "cpu": [ "arm" ], @@ -1433,9 +1433,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.2.tgz", - "integrity": "sha512-lAarIdxZWbFSHFSDao9+I/F5jDaKyCqAPMq5HqnfpBw8dKDiCaaqM0lq5h1pQTLeIqueeay4PieGR5jGZMWprw==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.16.4.tgz", + "integrity": "sha512-Bvm6D+NPbGMQOcxvS1zUl8H7DWlywSXsphAeOnVeiZLQ+0J6Is8T7SrjGTH29KtYkiY9vld8ZnpV3G2EPbom+w==", "cpu": [ "arm64" ], @@ -1446,9 +1446,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.2.tgz", - "integrity": "sha512-SWsr8zEUk82KSqquIMgZEg2GE5mCSfr9sE/thDROkX6pb3QQWPp8Vw8zOq2GyxZ2t0XoSIUlvHDkrf5Gmf7x3Q==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.16.4.tgz", + "integrity": "sha512-i5d64MlnYBO9EkCOGe5vPR/EeDwjnKOGGdd7zKFhU5y8haKhQZTN2DgVtpODDMxUr4t2K90wTUJg7ilgND6bXw==", "cpu": [ "arm64" ], @@ -1459,9 +1459,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.2.tgz", - "integrity": "sha512-o/HAIrQq0jIxJAhgtIvV5FWviYK4WB0WwV91SLUnsliw1lSAoLsmgEEgRWzDguAFeUEUUoIWXiJrPqU7vGiVkA==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.16.4.tgz", + "integrity": "sha512-WZupV1+CdUYehaZqjaFTClJI72fjJEgTXdf4NbW69I9XyvdmztUExBtcI2yIIU6hJtYvtwS6pkTkHJz+k08mAQ==", "cpu": [ "x64" ], @@ -1472,9 +1472,22 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.2.tgz", - "integrity": "sha512-nwlJ65UY9eGq91cBi6VyDfArUJSKOYt5dJQBq8xyLhvS23qO+4Nr/RreibFHjP6t+5ap2ohZrUJcHv5zk5ju/g==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.16.4.tgz", + "integrity": "sha512-ADm/xt86JUnmAfA9mBqFcRp//RVRt1ohGOYF6yL+IFCYqOBNwy5lbEK05xTsEoJq+/tJzg8ICUtS82WinJRuIw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.16.4.tgz", + "integrity": "sha512-tJfJaXPiFAG+Jn3cutp7mCs1ePltuAgRqdDZrzb1aeE3TktWWJ+g7xK9SNlaSUFw6IU4QgOxAY4rA+wZUT5Wfg==", "cpu": [ "arm" ], @@ -1485,9 +1498,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.2.tgz", - "integrity": "sha512-Pg5TxxO2IVlMj79+c/9G0LREC9SY3HM+pfAwX7zj5/cAuwrbfj2Wv9JbMHIdPCfQpYsI4g9mE+2Bw/3aeSs2rQ==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.16.4.tgz", + "integrity": "sha512-7dy1BzQkgYlUTapDTvK997cgi0Orh5Iu7JlZVBy1MBURk7/HSbHkzRnXZa19ozy+wwD8/SlpJnOOckuNZtJR9w==", "cpu": [ "arm64" ], @@ -1498,9 +1511,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.2.tgz", - "integrity": "sha512-cAOTjGNm84gc6tS02D1EXtG7tDRsVSDTBVXOLbj31DkwfZwgTPYZ6aafSU7rD/4R2a34JOwlF9fQayuTSkoclA==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.16.4.tgz", + "integrity": "sha512-zsFwdUw5XLD1gQe0aoU2HVceI6NEW7q7m05wA46eUAyrkeNYExObfRFQcvA6zw8lfRc5BHtan3tBpo+kqEOxmg==", "cpu": [ "arm64" ], @@ -1511,9 +1524,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.2.tgz", - "integrity": "sha512-4RyT6v1kXb7C0fn6zV33rvaX05P0zHoNzaXI/5oFHklfKm602j+N4mn2YvoezQViRLPnxP8M1NaY4s/5kXO5cw==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.16.4.tgz", + "integrity": "sha512-p8C3NnxXooRdNrdv6dBmRTddEapfESEUflpICDNKXpHvTjRRq1J82CbU5G3XfebIZyI3B0s074JHMWD36qOW6w==", "cpu": [ "ppc64" ], @@ -1524,9 +1537,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.2.tgz", - "integrity": "sha512-KNUH6jC/vRGAKSorySTyc/yRYlCwN/5pnMjXylfBniwtJx5O7X17KG/0efj8XM3TZU7raYRXJFFReOzNmL1n1w==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.16.4.tgz", + "integrity": "sha512-Lh/8ckoar4s4Id2foY7jNgitTOUQczwMWNYi+Mjt0eQ9LKhr6sK477REqQkmy8YHY3Ca3A2JJVdXnfb3Rrwkng==", "cpu": [ "riscv64" ], @@ -1537,9 +1550,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.2.tgz", - "integrity": "sha512-xPV4y73IBEXToNPa3h5lbgXOi/v0NcvKxU0xejiFw6DtIYQqOTMhZ2DN18/HrrP0PmiL3rGtRG9gz1QE8vFKXQ==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.16.4.tgz", + "integrity": "sha512-1xwwn9ZCQYuqGmulGsTZoKrrn0z2fAur2ujE60QgyDpHmBbXbxLaQiEvzJWDrscRq43c8DnuHx3QorhMTZgisQ==", "cpu": [ "s390x" ], @@ -1550,9 +1563,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.2.tgz", - "integrity": "sha512-QBhtr07iFGmF9egrPOWyO5wciwgtzKkYPNLVCFZTmr4TWmY0oY2Dm/bmhHjKRwZoGiaKdNcKhFtUMBKvlchH+Q==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.16.4.tgz", + "integrity": "sha512-LuOGGKAJ7dfRtxVnO1i3qWc6N9sh0Em/8aZ3CezixSTM+E9Oq3OvTsvC4sm6wWjzpsIlOCnZjdluINKESflJLA==", "cpu": [ "x64" ], @@ -1563,9 +1576,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.2.tgz", - "integrity": "sha512-8zfsQRQGH23O6qazZSFY5jP5gt4cFvRuKTpuBsC1ZnSWxV8ZKQpPqOZIUtdfMOugCcBvFGRa1pDC/tkf19EgBw==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.16.4.tgz", + "integrity": "sha512-ch86i7KkJKkLybDP2AtySFTRi5fM3KXp0PnHocHuJMdZwu7BuyIKi35BE9guMlmTpwwBTB3ljHj9IQXnTCD0vA==", "cpu": [ "x64" ], @@ -1576,9 +1589,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.2.tgz", - "integrity": "sha512-H4s8UjgkPnlChl6JF5empNvFHp77Jx+Wfy2EtmYPe9G22XV+PMuCinZVHurNe8ggtwoaohxARJZbaH/3xjB/FA==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.16.4.tgz", + "integrity": "sha512-Ma4PwyLfOWZWayfEsNQzTDBVW8PZ6TUUN1uFTBQbF2Chv/+sjenE86lpiEwj2FiviSmSZ4Ap4MaAfl1ciF4aSA==", "cpu": [ "arm64" ], @@ -1589,9 +1602,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.2.tgz", - "integrity": "sha512-djqpAjm/i8erWYF0K6UY4kRO3X5+T4TypIqw60Q8MTqSBaQNpNXDhxdjpZ3ikgb+wn99svA7jxcXpiyg9MUsdw==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.16.4.tgz", + "integrity": "sha512-9m/ZDrQsdo/c06uOlP3W9G2ENRVzgzbSXmXHT4hwVaDQhYcRpi9bgBT0FTG9OhESxwK0WjQxYOSfv40cU+T69w==", "cpu": [ "ia32" ], @@ -1602,9 +1615,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.2.tgz", - "integrity": "sha512-teAqzLT0yTYZa8ZP7zhFKEx4cotS8Tkk5XiqNMJhD4CpaWB1BHARE4Qy+RzwnXvSAYv+Q3jAqCVBS+PS+Yee8Q==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.16.4.tgz", + "integrity": "sha512-YunpoOAyGLDseanENHmbFvQSfVL5BxW3k7hhy0eN4rb3gS/ct75dVD0EXOWIqFT/nE8XYW6LP6vz6ctKRi0k9A==", "cpu": [ "x64" ], @@ -2119,12 +2132,12 @@ } }, "node_modules/@stylistic/eslint-plugin-js": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-1.7.0.tgz", - "integrity": "sha512-PN6On/+or63FGnhhMKSQfYcWutRlzOiYlVdLM6yN7lquoBTqUJHYnl4TA4MHwiAt46X5gRxDr1+xPZ1lOLcL+Q==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-1.7.2.tgz", + "integrity": "sha512-ZYX7C5p7zlHbACwFLU+lISVh6tdcRP/++PWegh2Sy0UgMT5kU0XkPa2tKWEtJYzZmPhJxu9LxbnWcnE/tTwSDQ==", "dev": true, "dependencies": { - "@types/eslint": "^8.56.2", + "@types/eslint": "^8.56.8", "acorn": "^8.11.3", "escape-string-regexp": "^4.0.0", "eslint-visitor-keys": "^3.4.3", @@ -2217,9 +2230,9 @@ } }, "node_modules/@types/eslint": { - "version": "8.56.9", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.9.tgz", - "integrity": "sha512-W4W3KcqzjJ0sHg2vAq9vfml6OhsJ53TcUjUqfzzZf/EChUtwspszj/S0pzMxnfRcO55/iGq47dscXw71Fxc4Zg==", + "version": "8.56.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", + "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -2314,16 +2327,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.6.0.tgz", - "integrity": "sha512-gKmTNwZnblUdnTIJu3e9kmeRRzV2j1a/LUO27KNNAnIC5zjy1aSvXSRp4rVNlmAoHlQ7HzX42NbKpcSr4jF80A==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.1.tgz", + "integrity": "sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.6.0", - "@typescript-eslint/type-utils": "7.6.0", - "@typescript-eslint/utils": "7.6.0", - "@typescript-eslint/visitor-keys": "7.6.0", + "@typescript-eslint/scope-manager": "7.7.1", + "@typescript-eslint/type-utils": "7.7.1", + "@typescript-eslint/utils": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.3.1", @@ -2349,15 +2362,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.6.0.tgz", - "integrity": "sha512-usPMPHcwX3ZoPWnBnhhorc14NJw9J4HpSXQX4urF2TPKG0au0XhJoZyX62fmvdHONUkmyUe74Hzm1//XA+BoYg==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.1.tgz", + "integrity": "sha512-vmPzBOOtz48F6JAGVS/kZYk4EkXao6iGrD838sp1w3NQQC0W8ry/q641KU4PrG7AKNAf56NOcR8GOpH8l9FPCw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.6.0", - "@typescript-eslint/types": "7.6.0", - "@typescript-eslint/typescript-estree": "7.6.0", - "@typescript-eslint/visitor-keys": "7.6.0", + "@typescript-eslint/scope-manager": "7.7.1", + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/typescript-estree": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1", "debug": "^4.3.4" }, "engines": { @@ -2377,13 +2390,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.6.0.tgz", - "integrity": "sha512-ngttyfExA5PsHSx0rdFgnADMYQi+Zkeiv4/ZxGYUWd0nLs63Ha0ksmp8VMxAIC0wtCFxMos7Lt3PszJssG/E6w==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.1.tgz", + "integrity": "sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.6.0", - "@typescript-eslint/visitor-keys": "7.6.0" + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2394,13 +2407,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.6.0.tgz", - "integrity": "sha512-NxAfqAPNLG6LTmy7uZgpK8KcuiS2NZD/HlThPXQRGwz6u7MDBWRVliEEl1Gj6U7++kVJTpehkhZzCJLMK66Scw==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.1.tgz", + "integrity": "sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.6.0", - "@typescript-eslint/utils": "7.6.0", + "@typescript-eslint/typescript-estree": "7.7.1", + "@typescript-eslint/utils": "7.7.1", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -2421,9 +2434,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.6.0.tgz", - "integrity": "sha512-h02rYQn8J+MureCvHVVzhl69/GAfQGPQZmOMjG1KfCl7o3HtMSlPaPUAPu6lLctXI5ySRGIYk94clD/AUMCUgQ==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.1.tgz", + "integrity": "sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2434,13 +2447,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.6.0.tgz", - "integrity": "sha512-+7Y/GP9VuYibecrCQWSKgl3GvUM5cILRttpWtnAu8GNL9j11e4tbuGZmZjJ8ejnKYyBRb2ddGQ3rEFCq3QjMJw==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.1.tgz", + "integrity": "sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.6.0", - "@typescript-eslint/visitor-keys": "7.6.0", + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2462,17 +2475,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.6.0.tgz", - "integrity": "sha512-x54gaSsRRI+Nwz59TXpCsr6harB98qjXYzsRxGqvA5Ue3kQH+FxS7FYU81g/omn22ML2pZJkisy6Q+ElK8pBCA==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.1.tgz", + "integrity": "sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.15", "@types/semver": "^7.5.8", - "@typescript-eslint/scope-manager": "7.6.0", - "@typescript-eslint/types": "7.6.0", - "@typescript-eslint/typescript-estree": "7.6.0", + "@typescript-eslint/scope-manager": "7.7.1", + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/typescript-estree": "7.7.1", "semver": "^7.6.0" }, "engines": { @@ -2487,12 +2500,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.6.0.tgz", - "integrity": "sha512-4eLB7t+LlNUmXzfOu1VAIAdkjbu5xNSerURS9X/S5TUKWFRpXRQZbmtPqgKmYx8bj3J0irtQXSiWAOY82v+cgw==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.1.tgz", + "integrity": "sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.6.0", + "@typescript-eslint/types": "7.7.1", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -2523,13 +2536,13 @@ } }, "node_modules/@vitest/expect": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.5.0.tgz", - "integrity": "sha512-0pzuCI6KYi2SIC3LQezmxujU9RK/vwC1U9R0rLuGlNGcOuDWxqWKu6nUdFsX9tH1WU0SXtAxToOsEjeUn1s3hA==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.5.2.tgz", + "integrity": "sha512-rf7MTD1WCoDlN3FfYJ9Llfp0PbdtOMZ3FIF0AVkDnKbp3oiMW1c8AmvRZBcqbAhDUAvF52e9zx4WQM1r3oraVA==", "dev": true, "dependencies": { - "@vitest/spy": "1.5.0", - "@vitest/utils": "1.5.0", + "@vitest/spy": "1.5.2", + "@vitest/utils": "1.5.2", "chai": "^4.3.10" }, "funding": { @@ -2537,12 +2550,12 @@ } }, "node_modules/@vitest/runner": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.0.tgz", - "integrity": "sha512-7HWwdxXP5yDoe7DTpbif9l6ZmDwCzcSIK38kTSIt6CFEpMjX4EpCgT6wUmS0xTXqMI6E/ONmfgRKmaujpabjZQ==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.2.tgz", + "integrity": "sha512-7IJ7sJhMZrqx7HIEpv3WrMYcq8ZNz9L6alo81Y6f8hV5mIE6yVZsFoivLZmr0D777klm1ReqonE9LyChdcmw6g==", "dev": true, "dependencies": { - "@vitest/utils": "1.5.0", + "@vitest/utils": "1.5.2", "p-limit": "^5.0.0", "pathe": "^1.1.1" }, @@ -2578,9 +2591,9 @@ } }, "node_modules/@vitest/snapshot": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.0.tgz", - "integrity": "sha512-qpv3fSEuNrhAO3FpH6YYRdaECnnRjg9VxbhdtPwPRnzSfHVXnNzzrpX4cJxqiwgRMo7uRMWDFBlsBq4Cr+rO3A==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.2.tgz", + "integrity": "sha512-CTEp/lTYos8fuCc9+Z55Ga5NVPKUgExritjF5VY7heRFUfheoAqBneUlvXSUJHUZPjnPmyZA96yLRJDP1QATFQ==", "dev": true, "dependencies": { "magic-string": "^0.30.5", @@ -2592,21 +2605,18 @@ } }, "node_modules/@vitest/snapshot/node_modules/magic-string": { - "version": "0.30.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.9.tgz", - "integrity": "sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw==", + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", "dev": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" } }, "node_modules/@vitest/spy": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.5.0.tgz", - "integrity": "sha512-vu6vi6ew5N5MMHJjD5PoakMRKYdmIrNJmyfkhRpQt5d9Ewhw9nZ5Aqynbi3N61bvk9UvZ5UysMT6ayIrZ8GA9w==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.5.2.tgz", + "integrity": "sha512-xCcPvI8JpCtgikT9nLpHPL1/81AYqZy1GCy4+MCHBE7xi8jgsYkULpW5hrx5PGLgOQjUpb6fd15lqcriJ40tfQ==", "dev": true, "dependencies": { "tinyspy": "^2.2.0" @@ -2616,9 +2626,9 @@ } }, "node_modules/@vitest/utils": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.0.tgz", - "integrity": "sha512-BDU0GNL8MWkRkSRdNFvCUCAVOeHaUlVJ9Tx0TYBZyXaaOTmGtUFObzchCivIBrIwKzvZA7A9sCejVhXM2aY98A==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.2.tgz", + "integrity": "sha512-sWOmyofuXLJ85VvXNsroZur7mOJGiQeM0JN3/0D1uU8U9bGFM69X1iqHaRXl6R8BwaLY6yPCogP257zxTzkUdA==", "dev": true, "dependencies": { "diff-sequences": "^29.6.3", @@ -2646,105 +2656,102 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.4.21", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.21.tgz", - "integrity": "sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==", + "version": "3.4.25", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.25.tgz", + "integrity": "sha512-Y2pLLopaElgWnMNolgG8w3C5nNUVev80L7hdQ5iIKPtMJvhVpG0zhnBG/g3UajJmZdvW0fktyZTotEHD1Srhbg==", "dependencies": { - "@babel/parser": "^7.23.9", - "@vue/shared": "3.4.21", + "@babel/parser": "^7.24.4", + "@vue/shared": "3.4.25", "entities": "^4.5.0", "estree-walker": "^2.0.2", - "source-map-js": "^1.0.2" + "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-dom": { - "version": "3.4.21", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.21.tgz", - "integrity": "sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==", + "version": "3.4.25", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.25.tgz", + "integrity": "sha512-Ugz5DusW57+HjllAugLci19NsDK+VyjGvmbB2TXaTcSlQxwL++2PETHx/+Qv6qFwNLzSt7HKepPe4DcTE3pBWg==", "dependencies": { - "@vue/compiler-core": "3.4.21", - "@vue/shared": "3.4.21" + "@vue/compiler-core": "3.4.25", + "@vue/shared": "3.4.25" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.4.21", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.21.tgz", - "integrity": "sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==", + "version": "3.4.25", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.25.tgz", + "integrity": "sha512-m7rryuqzIoQpOBZ18wKyq05IwL6qEpZxFZfRxlNYuIPDqywrXQxgUwLXIvoU72gs6cRdY6wHD0WVZIFE4OEaAQ==", "dependencies": { - "@babel/parser": "^7.23.9", - "@vue/compiler-core": "3.4.21", - "@vue/compiler-dom": "3.4.21", - "@vue/compiler-ssr": "3.4.21", - "@vue/shared": "3.4.21", + "@babel/parser": "^7.24.4", + "@vue/compiler-core": "3.4.25", + "@vue/compiler-dom": "3.4.25", + "@vue/compiler-ssr": "3.4.25", + "@vue/shared": "3.4.25", "estree-walker": "^2.0.2", - "magic-string": "^0.30.7", - "postcss": "^8.4.35", - "source-map-js": "^1.0.2" + "magic-string": "^0.30.10", + "postcss": "^8.4.38", + "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-sfc/node_modules/magic-string": { - "version": "0.30.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.9.tgz", - "integrity": "sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw==", + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.4.21", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.21.tgz", - "integrity": "sha512-M5+9nI2lPpAsgXOGQobnIueVqc9sisBFexh5yMIMRAPYLa7+5wEJs8iqOZc1WAa9WQbx9GR2twgznU8LTIiZ4Q==", + "version": "3.4.25", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.25.tgz", + "integrity": "sha512-H2ohvM/Pf6LelGxDBnfbbXFPyM4NE3hrw0e/EpwuSiYu8c819wx+SVGdJ65p/sFrYDd6OnSDxN1MB2mN07hRSQ==", "dependencies": { - "@vue/compiler-dom": "3.4.21", - "@vue/shared": "3.4.21" + "@vue/compiler-dom": "3.4.25", + "@vue/shared": "3.4.25" } }, "node_modules/@vue/reactivity": { - "version": "3.4.21", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.21.tgz", - "integrity": "sha512-UhenImdc0L0/4ahGCyEzc/pZNwVgcglGy9HVzJ1Bq2Mm9qXOpP8RyNTjookw/gOCUlXSEtuZ2fUg5nrHcoqJcw==", + "version": "3.4.25", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.25.tgz", + "integrity": "sha512-mKbEtKr1iTxZkAG3vm3BtKHAOhuI4zzsVcN0epDldU/THsrvfXRKzq+lZnjczZGnTdh3ojd86/WrP+u9M51pWQ==", "dependencies": { - "@vue/shared": "3.4.21" + "@vue/shared": "3.4.25" } }, "node_modules/@vue/runtime-core": { - "version": "3.4.21", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.21.tgz", - "integrity": "sha512-pQthsuYzE1XcGZznTKn73G0s14eCJcjaLvp3/DKeYWoFacD9glJoqlNBxt3W2c5S40t6CCcpPf+jG01N3ULyrA==", + "version": "3.4.25", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.25.tgz", + "integrity": "sha512-3qhsTqbEh8BMH3pXf009epCI5E7bKu28fJLi9O6W+ZGt/6xgSfMuGPqa5HRbUxLoehTNp5uWvzCr60KuiRIL0Q==", "dependencies": { - "@vue/reactivity": "3.4.21", - "@vue/shared": "3.4.21" + "@vue/reactivity": "3.4.25", + "@vue/shared": "3.4.25" } }, "node_modules/@vue/runtime-dom": { - "version": "3.4.21", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.21.tgz", - "integrity": "sha512-gvf+C9cFpevsQxbkRBS1NpU8CqxKw0ebqMvLwcGQrNpx6gqRDodqKqA+A2VZZpQ9RpK2f9yfg8VbW/EpdFUOJw==", + "version": "3.4.25", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.25.tgz", + "integrity": "sha512-ode0sj77kuwXwSc+2Yhk8JMHZh1sZp9F/51wdBiz3KGaWltbKtdihlJFhQG4H6AY+A06zzeMLkq6qu8uDSsaoA==", "dependencies": { - "@vue/runtime-core": "3.4.21", - "@vue/shared": "3.4.21", + "@vue/runtime-core": "3.4.25", + "@vue/shared": "3.4.25", "csstype": "^3.1.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.4.21", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.21.tgz", - "integrity": "sha512-aV1gXyKSN6Rz+6kZ6kr5+Ll14YzmIbeuWe7ryJl5muJ4uwSwY/aStXTixx76TwkZFJLm1aAlA/HSWEJ4EyiMkg==", + "version": "3.4.25", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.25.tgz", + "integrity": "sha512-8VTwq0Zcu3K4dWV0jOwIVINESE/gha3ifYCOKEhxOj6MEl5K5y8J8clQncTcDhKF+9U765nRw4UdUEXvrGhyVQ==", "dependencies": { - "@vue/compiler-ssr": "3.4.21", - "@vue/shared": "3.4.21" + "@vue/compiler-ssr": "3.4.25", + "@vue/shared": "3.4.25" }, "peerDependencies": { - "vue": "3.4.21" + "vue": "3.4.25" } }, "node_modules/@vue/shared": { - "version": "3.4.21", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.21.tgz", - "integrity": "sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g==" + "version": "3.4.25", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.25.tgz", + "integrity": "sha512-k0yappJ77g2+KNrIaF0FFnzwLvUBLUYr8VOwz+/6vLsmItFp51AcxLL7Ey3iPd7BIRyWPOcqUjMnm7OkahXllA==" }, "node_modules/@webassemblyjs/ast": { "version": "1.12.1", @@ -3551,9 +3558,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001609", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001609.tgz", - "integrity": "sha512-JFPQs34lHKx1B5t1EpQpWH4c+29zIyn/haGsbpfq3suuV9v56enjFt23zqijxGTMwy1p/4H2tjnQMY+p1WoAyA==", + "version": "1.0.30001612", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz", + "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==", "funding": [ { "type": "opencollective", @@ -3865,10 +3872,16 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, + "node_modules/confbox": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz", + "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==", + "dev": true + }, "node_modules/core-js-compat": { - "version": "3.36.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz", - "integrity": "sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==", + "version": "3.37.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.0.tgz", + "integrity": "sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA==", "dev": true, "dependencies": { "browserslist": "^4.23.0" @@ -3936,9 +3949,9 @@ } }, "node_modules/css-functions-list": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.1.tgz", - "integrity": "sha512-Nj5YcaGgBtuUmn1D7oHqPW0c9iui7xsTsj5lIX8ZgevdfhmjFfKB3r8moHJtNJnctnYXJyYX5I1pp90HM4TPgQ==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.2.tgz", + "integrity": "sha512-c+N0v6wbKVxTu5gOBBFkr9BEdBWaqqjQeiJ8QvSRIJOf+UxlJh930m8e6/WNeODIK0mYLFkoONrnj16i2EcvfQ==", "dev": true, "engines": { "node": ">=12 || >=16" @@ -4069,13 +4082,9 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/cytoscape": { - "version": "3.28.1", - "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.28.1.tgz", - "integrity": "sha512-xyItz4O/4zp9/239wCcH8ZcFuuZooEeF8KHRmzjDfGdXsj3OG9MFSMA0pJE0uX3uCN/ygof6hHf4L7lst+JaDg==", - "dependencies": { - "heap": "^0.2.6", - "lodash": "^4.17.21" - }, + "version": "3.29.2", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.29.2.tgz", + "integrity": "sha512-2G1ycU28Nh7OHT9rkXRLpCDP30MKH1dXJORZuBhtEhEW7pKwgPi77ImqlCWinouyE1PNepIOGZBOrE84DG7LyQ==", "engines": { "node": ">=0.10" } @@ -4842,14 +4851,14 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.736", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.736.tgz", - "integrity": "sha512-Rer6wc3ynLelKNM4lOCg7/zPQj8tPOCB2hzD32PX9wd3hgRRi9MxEbmkFCokzcEhRVMiOVLjnL9ig9cefJ+6+Q==" + "version": "1.4.749", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.749.tgz", + "integrity": "sha512-LRMMrM9ITOvue0PoBrvNIraVmuDbJV5QC9ierz/z5VilMdPOVMjOtpICNld3PuXuTZ3CHH/UPxX9gHhAPwi+0Q==" }, "node_modules/elkjs": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.9.2.tgz", - "integrity": "sha512-2Y/RaA1pdgSHpY0YG4TYuYCD2wh97CRvu22eLG3Kz0pgQ/6KbIFTxsTnDc4MH/6hFlg2L/9qXrDMG0nMjP63iw==" + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.9.3.tgz", + "integrity": "sha512-f/ZeWvW/BCXbhGEf1Ujp29EASo/lk1FDnETgNKwJrsVvGZhUWCZyg3xLJjAsxfOmt8KjswHmI5EwCQcPMpOYhQ==" }, "node_modules/emoji-regex": { "version": "9.2.2", @@ -5018,14 +5027,14 @@ } }, "node_modules/es-iterator-helpers": { - "version": "1.0.18", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.18.tgz", - "integrity": "sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==", + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", + "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", "dev": true, "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.23.0", + "es-abstract": "^1.23.3", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", @@ -5770,9 +5779,9 @@ "dev": true }, "node_modules/eslint-plugin-vue": { - "version": "9.24.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.24.1.tgz", - "integrity": "sha512-wk3SuwmS1pZdcuJlokGYEi/buDOwD6KltvhIZyOnpJ/378dcQ4zchu9PAMbbLAaydCz1iYc5AozszcOOgZIIOg==", + "version": "9.25.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.25.0.tgz", + "integrity": "sha512-tDWlx14bVe6Bs+Nnh3IGrD+hb11kf2nukfm6jLsmJIhmiRQ1SUaksvwY9U5MvPB0pcrg0QK0xapQkfITs3RKOA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", @@ -6676,11 +6685,6 @@ "node": ">= 0.4" } }, - "node_modules/heap": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", - "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==" - }, "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -7848,7 +7852,8 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true }, "node_modules/lodash-es": { "version": "4.17.21", @@ -8662,9 +8667,9 @@ } }, "node_modules/mini-css-extract-plugin": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.8.1.tgz", - "integrity": "sha512-/1HDlyFRxWIZPI1ZpgqlZ8jMw/1Dp/dl3P0L1jtZ+zVcHqwPhGwaJwKL00WVgfnBy6PWCde9W65or7IIETImuA==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.0.tgz", + "integrity": "sha512-Zs1YsZVfemekSZG+44vBsYTLQORkPMwnlv+aehcxK/NLKC+EGhDB39/YePYYqx/sTk6NnYpuqikhSn7+JIevTA==", "dependencies": { "schema-utils": "^4.0.0", "tapable": "^2.2.1" @@ -8724,9 +8729,9 @@ } }, "node_modules/monaco-editor": { - "version": "0.47.0", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.47.0.tgz", - "integrity": "sha512-VabVvHvQ9QmMwXu4du008ZDuyLnHs9j7ThVFsiJoXSOQk18+LF89N4ADzPbFenm0W4V2bGHnFBztIRQTgBfxzw==" + "version": "0.48.0", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.48.0.tgz", + "integrity": "sha512-goSDElNqFfw7iDHMg8WDATkfcyeLTNpBHQpO8incK6p5qZt5G/1j41X0xdGzpIkGojGXM+QiRQyLjnfDVvrpwA==" }, "node_modules/monaco-editor-webpack-plugin": { "version": "7.1.0", @@ -9221,9 +9226,9 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.1.tgz", + "integrity": "sha512-tS24spDe/zXhWbNPErCHs/AGOzbKGHT+ybSBqmdLm8WZ1xXLWvH8Qn71QPAlqVhd0qUTWjy+Kl9JmISgDdEjsA==", "engines": { "node": "14 || >=16.14" } @@ -9349,22 +9354,16 @@ } }, "node_modules/pkg-types": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", - "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.0.tgz", + "integrity": "sha512-/RpmvKdxKf8uILTtoOhAgf30wYbP2Qw+L9p3Rvshx1JZVX+XQNZQFjlbmGHEGIm4CkVPlSn+NXmIM8+9oWQaSA==", "dev": true, "dependencies": { - "jsonc-parser": "^3.2.0", - "mlly": "^1.2.0", - "pathe": "^1.1.0" + "confbox": "^0.1.7", + "mlly": "^1.6.1", + "pathe": "^1.1.2" } }, - "node_modules/pkg-types/node_modules/jsonc-parser": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", - "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", - "dev": true - }, "node_modules/playwright": { "version": "1.43.1", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.1.tgz", @@ -9602,9 +9601,9 @@ } }, "node_modules/postcss-nesting": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-12.1.1.tgz", - "integrity": "sha512-qc74KvIAQNa5ujZKG1UV286dhaDW6basbUy2i9AzNU/T8C9hpvGu9NZzm1SfePe2yP7sPYgpA8d4sPVopn2Hhw==", + "version": "12.1.2", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-12.1.2.tgz", + "integrity": "sha512-FUmTHGDNundodutB4PUBxt/EPuhgtpk8FJGRsBhOuy+6FnkR2A8RZWIsyyy6XmhvX2DZQQWIkvu+HB4IbJm+Ew==", "funding": [ { "type": "github", @@ -9847,9 +9846,9 @@ } }, "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.0.tgz", + "integrity": "sha512-wRiUsea88TjKDc4FBEn+sLvIDesp6brMbGWnJGjew2waAc9evdhja/2LvePc898HJbHw0L+MTWy7NhpnELAvLQ==", "dev": true }, "node_modules/read-cache": { @@ -10537,9 +10536,9 @@ } }, "node_modules/solid-js": { - "version": "1.8.16", - "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.8.16.tgz", - "integrity": "sha512-rja94MNU9flF3qQRLNsu60QHKBDKBkVE1DldJZPIfn2ypIn3NV2WpSbGTQIvsyGPBo+9E2IMjwqnqpbgfWuzeg==", + "version": "1.8.17", + "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.8.17.tgz", + "integrity": "sha512-E0FkUgv9sG/gEBWkHr/2XkBluHb1fkrHywUgA6o6XolPDCJ4g1HaLmQufcBBhiF36ee40q+HpG/vCZu7fLpI3Q==", "dependencies": { "csstype": "^3.1.0", "seroval": "^1.0.4", @@ -10862,20 +10861,20 @@ "dev": true }, "node_modules/stylelint": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.3.1.tgz", - "integrity": "sha512-/JOwQnBvxEKOT2RtNgGpBVXnCSMBgKOL2k7w0K52htwCyJls4+cHvc4YZgXlVoAZS9QJd2DgYAiRnja96pTgxw==", + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.4.0.tgz", + "integrity": "sha512-uSx7VMuXwLuYcNSIg+0/fFNv0WinsfLAqsVVy7h7p80clKOHiGE8pfY6UjqwylTHiJrRIahTl6a8FPxGezhWoA==", "dev": true, "dependencies": { "@csstools/css-parser-algorithms": "^2.6.1", "@csstools/css-tokenizer": "^2.2.4", "@csstools/media-query-list-parser": "^2.1.9", - "@csstools/selector-specificity": "^3.0.2", + "@csstools/selector-specificity": "^3.0.3", "@dual-bundle/import-meta-resolve": "^4.0.0", "balanced-match": "^2.0.0", "colord": "^2.9.3", "cosmiconfig": "^9.0.0", - "css-functions-list": "^3.2.1", + "css-functions-list": "^3.2.2", "css-tree": "^2.3.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", @@ -10904,7 +10903,7 @@ "strip-ansi": "^7.1.0", "supports-hyperlinks": "^3.0.0", "svg-tags": "^1.0.0", - "table": "^6.8.1", + "table": "^6.8.2", "write-file-atomic": "^5.0.1" }, "bin": { @@ -11052,9 +11051,9 @@ } }, "node_modules/stylis": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.1.tgz", - "integrity": "sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ==" + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.2.tgz", + "integrity": "sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==" }, "node_modules/stylus": { "version": "0.57.0", @@ -11226,9 +11225,9 @@ } }, "node_modules/swagger-ui-dist": { - "version": "5.15.1", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.15.1.tgz", - "integrity": "sha512-Et/WY0NFdKj8sUBOyEx5P3VybsvGl7bo/y9JvgQ22TkH1a/KscQ0ZiQST2YeJ3cwCrIjYTbHbt165fkku0y1Ig==" + "version": "5.17.2", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.17.2.tgz", + "integrity": "sha512-V/NqUw6QoTrjSpctp2oLQvxrl3vW29UsUtZyq7B1CF0v870KOFbYGDQw8rpKaKm0JxTwHpWnW1SN9YuKZdiCyw==" }, "node_modules/sync-fetch": { "version": "0.4.5", @@ -11377,9 +11376,9 @@ "integrity": "sha512-lDMFv4nKQrSjlkHKAlHVqKrBG4DyFfa9F74cmBZ3Iy3ed8yvWnlWSIdi4IKfSqwmazAohBNwiN64qGx4y5Q3IQ==" }, "node_modules/terser": { - "version": "5.30.3", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.3.tgz", - "integrity": "sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==", + "version": "5.30.4", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.4.tgz", + "integrity": "sha512-xRdd0v64a8mFK9bnsKVdoNP9GQIKUAaJPTaqEQDL4w/J8WaW4sWXXoMZ+6SimPkfT5bElreXf8m9HnmPc3E1BQ==", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -11510,9 +11509,9 @@ } }, "node_modules/tinybench": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.6.0.tgz", - "integrity": "sha512-N8hW3PG/3aOoZAN5V/NSAEDz0ZixDSSt5b/a05iqtpgfLWMSVuCo7w0k2vVvEjdrIoeGqZzweX2WlyioNIHchA==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.8.0.tgz", + "integrity": "sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==", "dev": true }, "node_modules/tinycolor2": { @@ -11521,9 +11520,9 @@ "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==" }, "node_modules/tinypool": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.3.tgz", - "integrity": "sha512-Ud7uepAklqRH1bvwy22ynrliC7Dljz7Tm8M/0RBUW+YRa4YHhZ6e4PpgE+fu1zr/WqB1kbeuVrdfeuyIBpy4tw==", + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz", + "integrity": "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==", "dev": true, "engines": { "node": ">=14.0.0" @@ -11933,9 +11932,9 @@ "integrity": "sha512-z2YZusTFC6KnLERx1cgoIRX2CjPRP0W75N+3CC6gbvdX5Ch47rZkEMGO2Xnf+IEmi3RiFLxS18gayMA27iU7Kg==" }, "node_modules/vite": { - "version": "5.2.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.8.tgz", - "integrity": "sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==", + "version": "5.2.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.10.tgz", + "integrity": "sha512-PAzgUZbP7msvQvqdSD+ErD5qGnSFiGOoWmV5yAKUEI0kdhjbH6nMWVyZQC/hSc4aXwc0oJ9aEdIiF9Oje0JFCw==", "dev": true, "dependencies": { "esbuild": "^0.20.1", @@ -11988,9 +11987,9 @@ } }, "node_modules/vite-node": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.0.tgz", - "integrity": "sha512-tV8h6gMj6vPzVCa7l+VGq9lwoJjW8Y79vst8QZZGiuRAfijU+EEWuc0kFpmndQrWhMMhet1jdSF+40KSZUqIIw==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.2.tgz", + "integrity": "sha512-Y8p91kz9zU+bWtF7HGt6DVw2JbhyuB2RlZix3FPYAYmUyZ3n7iTp8eSyLyY6sxtPegvxQtmlTMhfPhUfCUF93A==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -12010,9 +12009,9 @@ } }, "node_modules/vite-string-plugin": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/vite-string-plugin/-/vite-string-plugin-1.1.5.tgz", - "integrity": "sha512-KRCIFX3PWVUuEjpi9O7EKLT9E27OqOA3RimIvVx6cziLAUxvnk2VvHQfMrP+mKkqyqqSmnnYyTig3OyDnK/zlA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vite-string-plugin/-/vite-string-plugin-1.2.0.tgz", + "integrity": "sha512-IijlLgTxUDUwOpLoBLZCZO2us4fZWPRpj8XWoD9OAYjjUEge8enV4gaDTOs7uEsC8EJ9+NmusdLwmgWajFO45Q==", "dev": true }, "node_modules/vite/node_modules/@types/estree": { @@ -12036,9 +12035,9 @@ } }, "node_modules/vite/node_modules/rollup": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.2.tgz", - "integrity": "sha512-WkeoTWvuBoFjFAhsEOHKRoZ3r9GfTyhh7Vff1zwebEFLEFjT1lG3784xEgKiTa7E+e70vsC81roVL2MP4tgEEQ==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.16.4.tgz", + "integrity": "sha512-kuaTJSUbz+Wsb2ATGvEknkI12XV40vIiHmLuFlejoo7HtDok/O5eDDD0UpCVY5bBX5U5RYo8wWP83H7ZsqVEnA==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -12051,35 +12050,36 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.14.2", - "@rollup/rollup-android-arm64": "4.14.2", - "@rollup/rollup-darwin-arm64": "4.14.2", - "@rollup/rollup-darwin-x64": "4.14.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.14.2", - "@rollup/rollup-linux-arm64-gnu": "4.14.2", - "@rollup/rollup-linux-arm64-musl": "4.14.2", - "@rollup/rollup-linux-powerpc64le-gnu": "4.14.2", - "@rollup/rollup-linux-riscv64-gnu": "4.14.2", - "@rollup/rollup-linux-s390x-gnu": "4.14.2", - "@rollup/rollup-linux-x64-gnu": "4.14.2", - "@rollup/rollup-linux-x64-musl": "4.14.2", - "@rollup/rollup-win32-arm64-msvc": "4.14.2", - "@rollup/rollup-win32-ia32-msvc": "4.14.2", - "@rollup/rollup-win32-x64-msvc": "4.14.2", + "@rollup/rollup-android-arm-eabi": "4.16.4", + "@rollup/rollup-android-arm64": "4.16.4", + "@rollup/rollup-darwin-arm64": "4.16.4", + "@rollup/rollup-darwin-x64": "4.16.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.16.4", + "@rollup/rollup-linux-arm-musleabihf": "4.16.4", + "@rollup/rollup-linux-arm64-gnu": "4.16.4", + "@rollup/rollup-linux-arm64-musl": "4.16.4", + "@rollup/rollup-linux-powerpc64le-gnu": "4.16.4", + "@rollup/rollup-linux-riscv64-gnu": "4.16.4", + "@rollup/rollup-linux-s390x-gnu": "4.16.4", + "@rollup/rollup-linux-x64-gnu": "4.16.4", + "@rollup/rollup-linux-x64-musl": "4.16.4", + "@rollup/rollup-win32-arm64-msvc": "4.16.4", + "@rollup/rollup-win32-ia32-msvc": "4.16.4", + "@rollup/rollup-win32-x64-msvc": "4.16.4", "fsevents": "~2.3.2" } }, "node_modules/vitest": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.0.tgz", - "integrity": "sha512-d8UKgR0m2kjdxDWX6911uwxout6GHS0XaGH1cksSIVVG8kRlE7G7aBw7myKQCvDI5dT4j7ZMa+l706BIORMDLw==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.2.tgz", + "integrity": "sha512-l9gwIkq16ug3xY7BxHwcBQovLZG75zZL0PlsiYQbf76Rz6QGs54416UWMtC0jXeihvHvcHrf2ROEjkQRVpoZYw==", "dev": true, "dependencies": { - "@vitest/expect": "1.5.0", - "@vitest/runner": "1.5.0", - "@vitest/snapshot": "1.5.0", - "@vitest/spy": "1.5.0", - "@vitest/utils": "1.5.0", + "@vitest/expect": "1.5.2", + "@vitest/runner": "1.5.2", + "@vitest/snapshot": "1.5.2", + "@vitest/spy": "1.5.2", + "@vitest/utils": "1.5.2", "acorn-walk": "^8.3.2", "chai": "^4.3.10", "debug": "^4.3.4", @@ -12093,7 +12093,7 @@ "tinybench": "^2.5.1", "tinypool": "^0.8.3", "vite": "^5.0.0", - "vite-node": "1.5.0", + "vite-node": "1.5.2", "why-is-node-running": "^2.2.2" }, "bin": { @@ -12108,8 +12108,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.5.0", - "@vitest/ui": "1.5.0", + "@vitest/browser": "1.5.2", + "@vitest/ui": "1.5.2", "happy-dom": "*", "jsdom": "*" }, @@ -12135,27 +12135,24 @@ } }, "node_modules/vitest/node_modules/magic-string": { - "version": "0.30.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.9.tgz", - "integrity": "sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw==", + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", "dev": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" } }, "node_modules/vue": { - "version": "3.4.21", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.21.tgz", - "integrity": "sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA==", + "version": "3.4.25", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.25.tgz", + "integrity": "sha512-HWyDqoBHMgav/OKiYA2ZQg+kjfMgLt/T0vg4cbIF7JbXAjDexRf5JRg+PWAfrAkSmTd2I8aPSXtooBFWHB98cg==", "dependencies": { - "@vue/compiler-dom": "3.4.21", - "@vue/compiler-sfc": "3.4.21", - "@vue/runtime-dom": "3.4.21", - "@vue/server-renderer": "3.4.21", - "@vue/shared": "3.4.21" + "@vue/compiler-dom": "3.4.25", + "@vue/compiler-sfc": "3.4.25", + "@vue/runtime-dom": "3.4.25", + "@vue/server-renderer": "3.4.25", + "@vue/shared": "3.4.25" }, "peerDependencies": { "typescript": "*" diff --git a/package.json b/package.json index b0cb67ed4a..142b9bb3ee 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,9 @@ "node": ">= 18.0.0" }, "dependencies": { - "@citation-js/core": "0.7.9", - "@citation-js/plugin-bibtex": "0.7.9", - "@citation-js/plugin-csl": "0.7.9", + "@citation-js/core": "0.7.11", + "@citation-js/plugin-bibtex": "0.7.11", + "@citation-js/plugin-csl": "0.7.11", "@citation-js/plugin-software-formats": "0.6.1", "@github/markdown-toolbar-element": "2.2.3", "@github/relative-time-element": "4.4.0", @@ -33,17 +33,17 @@ "katex": "0.16.10", "license-checker-webpack-plugin": "0.2.1", "mermaid": "10.9.0", - "mini-css-extract-plugin": "2.8.1", + "mini-css-extract-plugin": "2.9.0", "minimatch": "9.0.4", - "monaco-editor": "0.47.0", + "monaco-editor": "0.48.0", "monaco-editor-webpack-plugin": "7.1.0", "pdfobject": "2.3.0", "postcss": "8.4.38", "postcss-loader": "8.1.1", - "postcss-nesting": "12.1.1", + "postcss-nesting": "12.1.2", "pretty-ms": "9.0.0", "sortablejs": "1.15.2", - "swagger-ui-dist": "5.15.1", + "swagger-ui-dist": "5.17.2", "tailwindcss": "3.4.3", "temporal-polyfill": "0.2.4", "throttle-debounce": "5.0.0", @@ -53,7 +53,7 @@ "tributejs": "5.1.3", "uint8-to-base64": "0.2.0", "vanilla-colorful": "0.7.2", - "vue": "3.4.21", + "vue": "3.4.25", "vue-bar-graph": "2.0.0", "vue-chartjs": "5.3.1", "vue-loader": "17.4.2", @@ -66,7 +66,7 @@ "@eslint-community/eslint-plugin-eslint-comments": "4.3.0", "@playwright/test": "1.43.1", "@stoplight/spectral-cli": "6.11.1", - "@stylistic/eslint-plugin-js": "1.7.0", + "@stylistic/eslint-plugin-js": "1.7.2", "@stylistic/stylelint-plugin": "2.1.1", "@vitejs/plugin-vue": "5.0.4", "eslint": "8.57.0", @@ -81,20 +81,20 @@ "eslint-plugin-unicorn": "52.0.0", "eslint-plugin-vitest": "0.4.1", "eslint-plugin-vitest-globals": "1.5.0", - "eslint-plugin-vue": "9.24.1", + "eslint-plugin-vue": "9.25.0", "eslint-plugin-vue-scoped-css": "2.8.0", "eslint-plugin-wc": "2.1.0", "happy-dom": "14.7.1", "markdownlint-cli": "0.39.0", "postcss-html": "1.6.0", - "stylelint": "16.3.1", + "stylelint": "16.4.0", "stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-declaration-strict-value": "1.10.4", "stylelint-value-no-unknown-custom-properties": "6.0.1", "svgo": "3.2.0", "updates": "16.0.1", - "vite-string-plugin": "1.1.5", - "vitest": "1.5.0" + "vite-string-plugin": "1.2.0", + "vitest": "1.5.2" }, "browserslist": [ "defaults" diff --git a/stylelint.config.js b/stylelint.config.js index 523b18841e..9247eb3c33 100644 --- a/stylelint.config.js +++ b/stylelint.config.js @@ -191,8 +191,9 @@ export default { 'no-invalid-double-slash-comments': true, 'no-invalid-position-at-import-rule': [true, {ignoreAtRules: ['tailwind']}], 'no-irregular-whitespace': true, - 'no-unknown-animations': null, - 'no-unknown-custom-properties': null, + 'no-unknown-animations': null, // disabled until stylelint supports multi-file linting + 'no-unknown-custom-media': null, // disabled until stylelint supports multi-file linting + 'no-unknown-custom-properties': null, // disabled until stylelint supports multi-file linting 'number-max-precision': null, 'plugin/declaration-block-no-ignored-properties': true, 'property-allowed-list': null, diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index 6cca37f7ca..e466d0b169 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -6,18 +6,10 @@ // This file must be imported before any lazy-loading is being attempted. __webpack_public_path__ = `${window.config?.assetUrlPrefix ?? '/assets'}/`; -const filteredErrors = new Set([ - 'getModifierState is not a function', // https://github.com/microsoft/monaco-editor/issues/4325 -]); - export function showGlobalErrorMessage(msg) { const pageContent = document.querySelector('.page-content'); if (!pageContent) return; - for (const filteredError of filteredErrors) { - if (msg.includes(filteredError)) return; - } - // compact the message to a data attribute to avoid too many duplicated messages const msgCompact = msg.replace(/\W/g, '').trim(); let msgDiv = pageContent.querySelector(`.js-global-error[data-global-error-msg-compact="${msgCompact}"]`); From dd301cae1c40c9ef2805bd13af6b09a81ff4f5d7 Mon Sep 17 00:00:00 2001 From: Kemal Zebari <60799661+kemzeb@users.noreply.github.com> Date: Sat, 27 Apr 2024 04:55:03 -0700 Subject: [PATCH 219/370] Prevent allow/reject reviews on merged/closed PRs (#30686) Resolves #30675. --- routers/api/v1/repo/pull_review.go | 13 ++++- routers/web/repo/pull_review.go | 2 + services/pull/review.go | 8 +++ templates/repo/diff/new_review.tmpl | 28 +++++---- tests/integration/pull_review_test.go | 82 +++++++++++++++++++++++++++ 5 files changed, 119 insertions(+), 14 deletions(-) diff --git a/routers/api/v1/repo/pull_review.go b/routers/api/v1/repo/pull_review.go index b527e90f10..4b481790fb 100644 --- a/routers/api/v1/repo/pull_review.go +++ b/routers/api/v1/repo/pull_review.go @@ -4,6 +4,7 @@ package repo import ( + "errors" "fmt" "net/http" "strings" @@ -372,7 +373,11 @@ func CreatePullReview(ctx *context.APIContext) { // create review and associate all pending review comments review, _, err := pull_service.SubmitReview(ctx, ctx.Doer, ctx.Repo.GitRepo, pr.Issue, reviewType, opts.Body, opts.CommitID, nil) if err != nil { - ctx.Error(http.StatusInternalServerError, "SubmitReview", err) + if errors.Is(err, pull_service.ErrSubmitReviewOnClosedPR) { + ctx.Error(http.StatusUnprocessableEntity, "", err) + } else { + ctx.Error(http.StatusInternalServerError, "SubmitReview", err) + } return } @@ -460,7 +465,11 @@ func SubmitPullReview(ctx *context.APIContext) { // create review and associate all pending review comments review, _, err = pull_service.SubmitReview(ctx, ctx.Doer, ctx.Repo.GitRepo, pr.Issue, reviewType, opts.Body, headCommitID, nil) if err != nil { - ctx.Error(http.StatusInternalServerError, "SubmitReview", err) + if errors.Is(err, pull_service.ErrSubmitReviewOnClosedPR) { + ctx.Error(http.StatusUnprocessableEntity, "", err) + } else { + ctx.Error(http.StatusInternalServerError, "SubmitReview", err) + } return } diff --git a/routers/web/repo/pull_review.go b/routers/web/repo/pull_review.go index a65d4866d0..62f6d71c5e 100644 --- a/routers/web/repo/pull_review.go +++ b/routers/web/repo/pull_review.go @@ -264,6 +264,8 @@ func SubmitReview(ctx *context.Context) { if issues_model.IsContentEmptyErr(err) { ctx.Flash.Error(ctx.Tr("repo.issues.review.content.empty")) ctx.JSONRedirect(fmt.Sprintf("%s/pulls/%d/files", ctx.Repo.RepoLink, issue.Index)) + } else if errors.Is(err, pull_service.ErrSubmitReviewOnClosedPR) { + ctx.Status(http.StatusUnprocessableEntity) } else { ctx.ServerError("SubmitReview", err) } diff --git a/services/pull/review.go b/services/pull/review.go index 5bf1991d13..e303cd9a9d 100644 --- a/services/pull/review.go +++ b/services/pull/review.go @@ -6,6 +6,7 @@ package pull import ( "context" + "errors" "fmt" "io" "regexp" @@ -43,6 +44,9 @@ func (err ErrDismissRequestOnClosedPR) Unwrap() error { return util.ErrPermissionDenied } +// ErrSubmitReviewOnClosedPR represents an error when an user tries to submit an approve or reject review associated to a closed or merged PR. +var ErrSubmitReviewOnClosedPR = errors.New("can't submit review for a closed or merged PR") + // checkInvalidation checks if the line of code comment got changed by another commit. // If the line got changed the comment is going to be invalidated. func checkInvalidation(ctx context.Context, c *issues_model.Comment, doer *user_model.User, repo *git.Repository, branch string) error { @@ -293,6 +297,10 @@ func SubmitReview(ctx context.Context, doer *user_model.User, gitRepo *git.Repos if reviewType != issues_model.ReviewTypeApprove && reviewType != issues_model.ReviewTypeReject { stale = false } else { + if issue.IsClosed { + return nil, nil, ErrSubmitReviewOnClosedPR + } + headCommitID, err := gitRepo.GetRefCommitID(pr.GetGitRefName()) if err != nil { return nil, nil, err diff --git a/templates/repo/diff/new_review.tmpl b/templates/repo/diff/new_review.tmpl index a2eae007a5..1b74a230f4 100644 --- a/templates/repo/diff/new_review.tmpl +++ b/templates/repo/diff/new_review.tmpl @@ -30,20 +30,24 @@ {{end}} <div class="divider"></div> {{$showSelfTooltip := (and $.IsSigned ($.Issue.IsPoster $.SignedUser.ID))}} - {{if $showSelfTooltip}} - <span class="tw-inline-block" data-tooltip-content="{{ctx.Locale.Tr "repo.diff.review.self_approve"}}"> - <button type="submit" name="type" value="approve" disabled class="ui submit primary tiny button btn-submit">{{ctx.Locale.Tr "repo.diff.review.approve"}}</button> - </span> - {{else}} - <button type="submit" name="type" value="approve" class="ui submit primary tiny button btn-submit">{{ctx.Locale.Tr "repo.diff.review.approve"}}</button> + {{if not $.Issue.IsClosed}} + {{if $showSelfTooltip}} + <span class="tw-inline-block" data-tooltip-content="{{ctx.Locale.Tr "repo.diff.review.self_approve"}}"> + <button type="submit" name="type" value="approve" disabled class="ui submit primary tiny button btn-submit">{{ctx.Locale.Tr "repo.diff.review.approve"}}</button> + </span> + {{else}} + <button type="submit" name="type" value="approve" class="ui submit primary tiny button btn-submit">{{ctx.Locale.Tr "repo.diff.review.approve"}}</button> + {{end}} {{end}} <button type="submit" name="type" value="comment" class="ui submit tiny basic button btn-submit">{{ctx.Locale.Tr "repo.diff.review.comment"}}</button> - {{if $showSelfTooltip}} - <span class="tw-inline-block" data-tooltip-content="{{ctx.Locale.Tr "repo.diff.review.self_reject"}}"> - <button type="submit" name="type" value="reject" disabled class="ui submit red tiny button btn-submit">{{ctx.Locale.Tr "repo.diff.review.reject"}}</button> - </span> - {{else}} - <button type="submit" name="type" value="reject" class="ui submit red tiny button btn-submit">{{ctx.Locale.Tr "repo.diff.review.reject"}}</button> + {{if not $.Issue.IsClosed}} + {{if $showSelfTooltip}} + <span class="tw-inline-block" data-tooltip-content="{{ctx.Locale.Tr "repo.diff.review.self_reject"}}"> + <button type="submit" name="type" value="reject" disabled class="ui submit red tiny button btn-submit">{{ctx.Locale.Tr "repo.diff.review.reject"}}</button> + </span> + {{else}} + <button type="submit" name="type" value="reject" class="ui submit red tiny button btn-submit">{{ctx.Locale.Tr "repo.diff.review.reject"}}</button> + {{end}} {{end}} </form> </div> diff --git a/tests/integration/pull_review_test.go b/tests/integration/pull_review_test.go index 2d8b3cb4ab..273332a36b 100644 --- a/tests/integration/pull_review_test.go +++ b/tests/integration/pull_review_test.go @@ -5,12 +5,15 @@ package integration import ( "net/http" + "net/http/httptest" "net/url" + "path" "strings" "testing" "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" @@ -176,3 +179,82 @@ func TestPullView_CodeOwner(t *testing.T) { }) }) } + +func TestPullView_GivenApproveOrRejectReviewOnClosedPR(t *testing.T) { + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + user1Session := loginUser(t, "user1") + user2Session := loginUser(t, "user2") + + // Have user1 create a fork of repo1. + testRepoFork(t, user1Session, "user2", "repo1", "user1", "repo1") + + t.Run("Submit approve/reject review on merged PR", func(t *testing.T) { + // Create a merged PR (made by user1) in the upstream repo1. + testEditFile(t, user1Session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") + resp := testPullCreate(t, user1Session, "user1", "repo1", false, "master", "master", "This is a pull title") + elem := strings.Split(test.RedirectURL(resp), "/") + assert.EqualValues(t, "pulls", elem[3]) + testPullMerge(t, user1Session, elem[1], elem[2], elem[4], repo_model.MergeStyleMerge, false) + + // Grab the CSRF token. + req := NewRequest(t, "GET", path.Join(elem[1], elem[2], "pulls", elem[4])) + resp = user2Session.MakeRequest(t, req, http.StatusOK) + htmlDoc := NewHTMLParser(t, resp.Body) + + // Submit an approve review on the PR. + testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "approve", http.StatusUnprocessableEntity) + + // Submit a reject review on the PR. + testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "reject", http.StatusUnprocessableEntity) + }) + + t.Run("Submit approve/reject review on closed PR", func(t *testing.T) { + // Created a closed PR (made by user1) in the upstream repo1. + testEditFileToNewBranch(t, user1Session, "user1", "repo1", "master", "a-test-branch", "README.md", "Hello, World (Editied...again)\n") + resp := testPullCreate(t, user1Session, "user1", "repo1", false, "master", "a-test-branch", "This is a pull title") + elem := strings.Split(test.RedirectURL(resp), "/") + assert.EqualValues(t, "pulls", elem[3]) + testIssueClose(t, user1Session, elem[1], elem[2], elem[4]) + + // Grab the CSRF token. + req := NewRequest(t, "GET", path.Join(elem[1], elem[2], "pulls", elem[4])) + resp = user2Session.MakeRequest(t, req, http.StatusOK) + htmlDoc := NewHTMLParser(t, resp.Body) + + // Submit an approve review on the PR. + testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "approve", http.StatusUnprocessableEntity) + + // Submit a reject review on the PR. + testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "reject", http.StatusUnprocessableEntity) + }) + }) +} + +func testSubmitReview(t *testing.T, session *TestSession, csrf, owner, repo, pullNumber, reviewType string, expectedSubmitStatus int) *httptest.ResponseRecorder { + options := map[string]string{ + "_csrf": csrf, + "commit_id": "", + "content": "test", + "type": reviewType, + } + + submitURL := path.Join(owner, repo, "pulls", pullNumber, "files", "reviews", "submit") + req := NewRequestWithValues(t, "POST", submitURL, options) + return session.MakeRequest(t, req, expectedSubmitStatus) +} + +func testIssueClose(t *testing.T, session *TestSession, owner, repo, issueNumber string) *httptest.ResponseRecorder { + req := NewRequest(t, "GET", path.Join(owner, repo, "pulls", issueNumber)) + resp := session.MakeRequest(t, req, http.StatusOK) + + htmlDoc := NewHTMLParser(t, resp.Body) + closeURL := path.Join(owner, repo, "issues", issueNumber, "comments") + + options := map[string]string{ + "_csrf": htmlDoc.GetCSRF(), + "status": "close", + } + + req = NewRequestWithValues(t, "POST", closeURL, options) + return session.MakeRequest(t, req, http.StatusOK) +} From d3cdef88ad4784c19afcf24fbf62fccb03f456ba Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sat, 27 Apr 2024 20:23:37 +0800 Subject: [PATCH 220/370] Add some tests to clarify the "must-change-password" behavior (#30693) Follow #30472: When a user is created by command line `./gitea admin user create`: Old behavior before #30472: the first user (admin or non-admin) doesn't need to change password. Revert to the old behavior before #30472 --- cmd/admin_user_change_password.go | 2 +- cmd/admin_user_create.go | 22 ++++++++++------ cmd/admin_user_create_test.go | 44 +++++++++++++++++++++++++++++++ cmd/main.go | 9 +++++-- cmd/main_test.go | 2 +- main.go | 2 +- models/unittest/testdb.go | 12 +++++++-- modules/log/logger_global.go | 4 ++- tests/test_utils.go | 1 - 9 files changed, 81 insertions(+), 17 deletions(-) create mode 100644 cmd/admin_user_create_test.go diff --git a/cmd/admin_user_change_password.go b/cmd/admin_user_change_password.go index bd9063a8e4..f1ed46e70b 100644 --- a/cmd/admin_user_change_password.go +++ b/cmd/admin_user_change_password.go @@ -35,7 +35,7 @@ var microcmdUserChangePassword = &cli.Command{ }, &cli.BoolFlag{ Name: "must-change-password", - Usage: "User must change password", + Usage: "User must change password (can be disabled by --must-change-password=false)", Value: true, }, }, diff --git a/cmd/admin_user_create.go b/cmd/admin_user_create.go index 403e3ee8d8..f328b753d8 100644 --- a/cmd/admin_user_create.go +++ b/cmd/admin_user_create.go @@ -4,6 +4,7 @@ package cmd import ( + "context" "errors" "fmt" @@ -48,7 +49,7 @@ var microcmdUserCreate = &cli.Command{ }, &cli.BoolFlag{ Name: "must-change-password", - Usage: "Set to false to prevent forcing the user to change their password after initial login", + Usage: "User must change password after initial login, defaults to true for all users except the first one (can be disabled by --must-change-password=false)", DisableDefaultText: true, }, &cli.IntFlag{ @@ -91,11 +92,16 @@ func runCreateUser(c *cli.Context) error { _, _ = fmt.Fprintf(c.App.ErrWriter, "--name flag is deprecated. Use --username instead.\n") } - ctx, cancel := installSignals() - defer cancel() - - if err := initDB(ctx); err != nil { - return err + ctx := c.Context + if !setting.IsInTesting { + // FIXME: need to refactor the "installSignals/initDB" related code later + // it doesn't make sense to call it in (almost) every command action function + var cancel context.CancelFunc + ctx, cancel = installSignals() + defer cancel() + if err := initDB(ctx); err != nil { + return err + } } var password string @@ -123,8 +129,8 @@ func runCreateUser(c *cli.Context) error { if err != nil { return fmt.Errorf("IsTableNotEmpty: %w", err) } - if !hasUserRecord && isAdmin { - // if this is the first admin being created, don't force to change password (keep the old behavior) + if !hasUserRecord { + // if this is the first one being created, don't force to change password (keep the old behavior) mustChangePassword = false } } diff --git a/cmd/admin_user_create_test.go b/cmd/admin_user_create_test.go new file mode 100644 index 0000000000..83754e97b1 --- /dev/null +++ b/cmd/admin_user_create_test.go @@ -0,0 +1,44 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package cmd + +import ( + "fmt" + "strings" + "testing" + + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + + "github.com/stretchr/testify/assert" +) + +func TestAdminUserCreate(t *testing.T) { + app := NewMainApp(AppVersion{}) + + reset := func() { + assert.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.User{})) + assert.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.EmailAddress{})) + } + + type createCheck struct{ IsAdmin, MustChangePassword bool } + createUser := func(name, args string) createCheck { + assert.NoError(t, app.Run(strings.Fields(fmt.Sprintf("./gitea admin user create --username %s --email %s@gitea.local %s --password foobar", name, name, args)))) + u := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: name}) + return createCheck{u.IsAdmin, u.MustChangePassword} + } + reset() + assert.Equal(t, createCheck{IsAdmin: false, MustChangePassword: false}, createUser("u", ""), "first non-admin user doesn't need to change password") + + reset() + assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: false}, createUser("u", "--admin"), "first admin user doesn't need to change password") + + reset() + assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: true}, createUser("u", "--admin --must-change-password")) + assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: true}, createUser("u2", "--admin")) + assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: false}, createUser("u3", "--admin --must-change-password=false")) + assert.Equal(t, createCheck{IsAdmin: false, MustChangePassword: true}, createUser("u4", "")) + assert.Equal(t, createCheck{IsAdmin: false, MustChangePassword: false}, createUser("u5", "--must-change-password=false")) +} diff --git a/cmd/main.go b/cmd/main.go index 02dd660e9e..fd648946ef 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -112,13 +112,18 @@ func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(ctx *cli.Context) } } -func NewMainApp(version, versionExtra string) *cli.App { +type AppVersion struct { + Version string + Extra string +} + +func NewMainApp(appVer AppVersion) *cli.App { app := cli.NewApp() app.Name = "Gitea" app.HelpName = "gitea" app.Usage = "A painless self-hosted Git service" app.Description = `Gitea program contains "web" and other subcommands. If no subcommand is given, it starts the web server by default. Use "web" subcommand for more web server arguments, use other subcommands for other purposes.` - app.Version = version + versionExtra + app.Version = appVer.Version + appVer.Extra app.EnableBashCompletion = true // these sub-commands need to use config file diff --git a/cmd/main_test.go b/cmd/main_test.go index a916c61f85..c182b44019 100644 --- a/cmd/main_test.go +++ b/cmd/main_test.go @@ -28,7 +28,7 @@ func makePathOutput(workPath, customPath, customConf string) string { } func newTestApp(testCmdAction func(ctx *cli.Context) error) *cli.App { - app := NewMainApp("version", "version-extra") + app := NewMainApp(AppVersion{}) testCmd := &cli.Command{Name: "test-cmd", Action: testCmdAction} prepareSubcommandWithConfig(testCmd, appGlobalFlags()) app.Commands = append(app.Commands, testCmd) diff --git a/main.go b/main.go index 775c729c56..756c3e0f9b 100644 --- a/main.go +++ b/main.go @@ -42,7 +42,7 @@ func main() { log.GetManager().Close() os.Exit(code) } - app := cmd.NewMainApp(Version, formatBuiltWith()) + app := cmd.NewMainApp(cmd.AppVersion{Version: Version, Extra: formatBuiltWith()}) _ = cmd.RunMainApp(app, os.Args...) // all errors should have been handled by the RunMainApp log.GetManager().Close() } diff --git a/models/unittest/testdb.go b/models/unittest/testdb.go index 51de18fa9b..53c9dbdd77 100644 --- a/models/unittest/testdb.go +++ b/models/unittest/testdb.go @@ -6,7 +6,6 @@ package unittest import ( "context" "fmt" - "log" "os" "path/filepath" "strings" @@ -18,6 +17,7 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting/config" "code.gitea.io/gitea/modules/storage" @@ -46,6 +46,14 @@ func fatalTestError(fmtStr string, args ...any) { // InitSettings initializes config provider and load common settings for tests func InitSettings() { + setting.IsInTesting = true + log.OsExiter = func(code int) { + if code != 0 { + // non-zero exit code (log.Fatal) shouldn't occur during testing, if it happens, show a full stacktrace for more details + panic(fmt.Errorf("non-zero exit code during testing: %d", code)) + } + os.Exit(0) + } if setting.CustomConf == "" { setting.CustomConf = filepath.Join(setting.CustomPath, "conf/app-unittest-tmp.ini") _ = os.Remove(setting.CustomConf) @@ -54,7 +62,7 @@ func InitSettings() { setting.LoadCommonSettings() if err := setting.PrepareAppDataPath(); err != nil { - log.Fatalf("Can not prepare APP_DATA_PATH: %v", err) + log.Fatal("Can not prepare APP_DATA_PATH: %v", err) } // register the dummy hash algorithm function used in the test fixtures _ = hash.Register("dummy", hash.NewDummyHasher) diff --git a/modules/log/logger_global.go b/modules/log/logger_global.go index 994acfedbb..6ce8b70fed 100644 --- a/modules/log/logger_global.go +++ b/modules/log/logger_global.go @@ -57,11 +57,13 @@ func Critical(format string, v ...any) { Log(1, ERROR, format, v...) } +var OsExiter = os.Exit + // Fatal records fatal log and exit process func Fatal(format string, v ...any) { Log(1, FATAL, format, v...) GetManager().Close() - os.Exit(1) + OsExiter(1) } func GetLogger(name string) Logger { diff --git a/tests/test_utils.go b/tests/test_utils.go index 50049e73f0..66a287ecad 100644 --- a/tests/test_utils.go +++ b/tests/test_utils.go @@ -46,7 +46,6 @@ func InitTest(requireGitea bool) { // TODO: Speedup tests that rely on the event source ticker, confirm whether there is any bug or failure. // setting.UI.Notification.EventSourceUpdateTime = time.Second - setting.IsInTesting = true setting.AppWorkPath = giteaRoot setting.CustomPath = filepath.Join(setting.AppWorkPath, "custom") if requireGitea { From 51c28d96838a743d2ba4fd679d92e8e15b536a19 Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Sat, 27 Apr 2024 16:05:06 +0300 Subject: [PATCH 221/370] Don't show loading indicators when refreshing the system status (#30712) Signed-off-by: Yarden Shoham <git@yardenshoham.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: silverwind <me@silverwind.io> --- templates/admin/dashboard.tmpl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/templates/admin/dashboard.tmpl b/templates/admin/dashboard.tmpl index 589fc5048a..3445433d53 100644 --- a/templates/admin/dashboard.tmpl +++ b/templates/admin/dashboard.tmpl @@ -76,7 +76,8 @@ {{ctx.Locale.Tr "admin.dashboard.system_status"}} </h4> {{/* TODO: make these stats work in multi-server deployments, likely needs per-server stats in DB */}} - <div hx-get="{{$.Link}}/system_status" hx-swap="morph:innerHTML" hx-trigger="every 5s" hx-indicator=".divider" class="ui attached table segment"> + <div class="no-loading-indicator tw-hidden"></div> + <div hx-get="{{$.Link}}/system_status" hx-swap="morph:innerHTML" hx-trigger="every 5s" hx-indicator=".no-loading-indicator" class="ui attached table segment"> {{template "admin/system_status" .}} </div> </div> From b93c87b6fe025408777d9f2091d29941e439e58c Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sat, 27 Apr 2024 15:35:26 +0200 Subject: [PATCH 222/370] Issue card improvements (#30687) Fixes https://github.com/go-gitea/gitea/issues/30682 and does a few improvements: - Use gap instead of margin/padding - Don't render empty image div - Remove `right floated` class that did nothing <img width="406" alt="Screenshot 2024-04-24 at 20 21 20" src="https://github.com/go-gitea/gitea/assets/115237/2fa88707-c2c4-40df-aee7-a684c3097ed0"> --------- Co-authored-by: KN4CK3R <admin@oldschoolhack.me> --- templates/repo/issue/card.tmpl | 25 +++++++++++++++---------- web_src/css/repo/issue-card.css | 2 +- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/templates/repo/issue/card.tmpl b/templates/repo/issue/card.tmpl index bb9340bb2e..4a0ac050aa 100644 --- a/templates/repo/issue/card.tmpl +++ b/templates/repo/issue/card.tmpl @@ -1,13 +1,16 @@ {{with .Issue}} {{if eq $.Page.Project.CardType 1}}{{/* Images and Text*/}} + {{$attachments := index $.Page.issuesAttachmentMap .ID}} + {{if $attachments}} <div class="card-attachment-images"> - {{range (index $.Page.issuesAttachmentMap .ID)}} + {{range $attachments}} <img src="{{.DownloadURL}}" alt="{{.Name}}" /> {{end}} </div> + {{end}} {{end}} - <div class="content tw-p-0 tw-w-full"> - <div class="tw-flex tw-items-start"> + <div class="content tw-w-full"> + <div class="tw-flex tw-items-start tw-gap-[5px]"> <div class="issue-card-icon"> {{template "shared/issueicon" .}} </div> @@ -18,7 +21,7 @@ </a> {{end}} </div> - <div class="meta tw-my-1"> + <div class="meta"> <span class="text light grey muted-links"> {{if not $.Page.Repository}}{{.Repo.FullName}}{{end}}#{{.Index}} {{$timeStr := TimeSinceUnix .GetLastEventTimestamp ctx.Locale}} @@ -59,13 +62,15 @@ </div> {{if or .Labels .Assignees}} - <div class="extra content labels-list tw-p-0 tw-pt-1"> - {{range .Labels}} - <a target="_blank" href="{{$.Issue.Repo.Link}}/issues?labels={{.ID}}">{{RenderLabel ctx ctx.Locale .}}</a> - {{end}} - <div class="right floated"> + <div class="tw-flex tw-justify-between"> + <div class="labels-list tw-flex-1"> + {{range .Labels}} + <a target="_blank" href="{{$.Issue.Repo.Link}}/issues?labels={{.ID}}">{{RenderLabel ctx ctx.Locale .}}</a> + {{end}} + </div> + <div class="tw-flex tw-flex-wrap tw-content-start tw-gap-1"> {{range .Assignees}} - <a target="_blank" href="{{.HomeLink}}" data-tooltip-content="{{ctx.Locale.Tr "repo.projects.column.assigned_to"}} {{.Name}}">{{ctx.AvatarUtils.Avatar . 28 "mini tw-mr-2"}}</a> + <a target="_blank" href="{{.HomeLink}}" data-tooltip-content="{{ctx.Locale.Tr "repo.projects.column.assigned_to"}} {{.Name}}">{{ctx.AvatarUtils.Avatar . 28}}</a> {{end}} </div> </div> diff --git a/web_src/css/repo/issue-card.css b/web_src/css/repo/issue-card.css index b9368df4f6..609b1b3dbd 100644 --- a/web_src/css/repo/issue-card.css +++ b/web_src/css/repo/issue-card.css @@ -1,6 +1,7 @@ .issue-card { display: flex; flex-direction: column; + gap: 4px; align-items: start; border-radius: var(--border-radius); padding: 8px 10px; @@ -17,7 +18,6 @@ .issue-card-title { flex: 1; font-size: 14px; - margin-left: 4px; } .issue-card.sortable-chosen .issue-card-title { From 6d2a307ad8af7d686f1c3a3706ff0f2df895658a Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sat, 27 Apr 2024 22:02:07 +0800 Subject: [PATCH 223/370] Rename migration package name for 1.22-rc1 (#30730) Ref: Propose to restart 1.22 release #30501 --- models/migrations/migrations.go | 15 ++++++++------- models/migrations/{v1_23 => v1_22}/v294.go | 2 +- models/migrations/{v1_23 => v1_22}/v294_test.go | 2 +- models/migrations/{v1_23 => v1_22}/v295.go | 2 +- models/migrations/{v1_23 => v1_22}/v296.go | 2 +- models/migrations/{v1_23 => v1_22}/v297.go | 2 +- models/migrations/{v1_23 => v1_22}/v298.go | 2 +- 7 files changed, 14 insertions(+), 13 deletions(-) rename models/migrations/{v1_23 => v1_22}/v294.go (98%) rename models/migrations/{v1_23 => v1_22}/v294_test.go (98%) rename models/migrations/{v1_23 => v1_22}/v295.go (96%) rename models/migrations/{v1_23 => v1_22}/v296.go (95%) rename models/migrations/{v1_23 => v1_22}/v297.go (94%) rename models/migrations/{v1_23 => v1_22}/v298.go (90%) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 220d8c2331..4501585250 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -21,7 +21,6 @@ import ( "code.gitea.io/gitea/models/migrations/v1_20" "code.gitea.io/gitea/models/migrations/v1_21" "code.gitea.io/gitea/models/migrations/v1_22" - "code.gitea.io/gitea/models/migrations/v1_23" "code.gitea.io/gitea/models/migrations/v1_6" "code.gitea.io/gitea/models/migrations/v1_7" "code.gitea.io/gitea/models/migrations/v1_8" @@ -574,18 +573,20 @@ var migrations = []Migration{ // v293 -> v294 NewMigration("Ensure every project has exactly one default column", v1_22.CheckProjectColumnsConsistency), - // Gitea 1.22.0 ends at 294 + // Gitea 1.22.0-rc0 ends at 294 // v294 -> v295 - NewMigration("Add unique index for project issue table", v1_23.AddUniqueIndexForProjectIssue), + NewMigration("Add unique index for project issue table", v1_22.AddUniqueIndexForProjectIssue), // v295 -> v296 - NewMigration("Add commit status summary table", v1_23.AddCommitStatusSummary), + NewMigration("Add commit status summary table", v1_22.AddCommitStatusSummary), // v296 -> v297 - NewMigration("Add missing field of commit status summary table", v1_23.AddCommitStatusSummary2), + NewMigration("Add missing field of commit status summary table", v1_22.AddCommitStatusSummary2), // v297 -> v298 - NewMigration("Add everyone_access_mode for repo_unit", v1_23.AddRepoUnitEveryoneAccessMode), + NewMigration("Add everyone_access_mode for repo_unit", v1_22.AddRepoUnitEveryoneAccessMode), // v298 -> v299 - NewMigration("Drop wrongly created table o_auth2_application", v1_23.DropWronglyCreatedTable), + NewMigration("Drop wrongly created table o_auth2_application", v1_22.DropWronglyCreatedTable), + + // Gitea 1.22.0-rc1 ends at 299 } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v1_23/v294.go b/models/migrations/v1_22/v294.go similarity index 98% rename from models/migrations/v1_23/v294.go rename to models/migrations/v1_22/v294.go index f2a54f6d23..20e261fb1b 100644 --- a/models/migrations/v1_23/v294.go +++ b/models/migrations/v1_22/v294.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_23 //nolint +package v1_22 //nolint import ( "fmt" diff --git a/models/migrations/v1_23/v294_test.go b/models/migrations/v1_22/v294_test.go similarity index 98% rename from models/migrations/v1_23/v294_test.go rename to models/migrations/v1_22/v294_test.go index d9a44ad866..82a3bcd602 100644 --- a/models/migrations/v1_23/v294_test.go +++ b/models/migrations/v1_22/v294_test.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_23 //nolint +package v1_22 //nolint import ( "slices" diff --git a/models/migrations/v1_23/v295.go b/models/migrations/v1_22/v295.go similarity index 96% rename from models/migrations/v1_23/v295.go rename to models/migrations/v1_22/v295.go index 9a2003cfc1..17bdadb4ad 100644 --- a/models/migrations/v1_23/v295.go +++ b/models/migrations/v1_22/v295.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_23 //nolint +package v1_22 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_23/v296.go b/models/migrations/v1_22/v296.go similarity index 95% rename from models/migrations/v1_23/v296.go rename to models/migrations/v1_22/v296.go index 495ae2ab23..1ecacab95f 100644 --- a/models/migrations/v1_23/v296.go +++ b/models/migrations/v1_22/v296.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_23 //nolint +package v1_22 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_23/v297.go b/models/migrations/v1_22/v297.go similarity index 94% rename from models/migrations/v1_23/v297.go rename to models/migrations/v1_22/v297.go index e79f04cf9c..7d4b506925 100644 --- a/models/migrations/v1_23/v297.go +++ b/models/migrations/v1_22/v297.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_23 //nolint +package v1_22 //nolint import ( "code.gitea.io/gitea/models/perm" diff --git a/models/migrations/v1_23/v298.go b/models/migrations/v1_22/v298.go similarity index 90% rename from models/migrations/v1_23/v298.go rename to models/migrations/v1_22/v298.go index 8761a05d3d..b9f3b95ade 100644 --- a/models/migrations/v1_23/v298.go +++ b/models/migrations/v1_22/v298.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_23 //nolint +package v1_22 //nolint import "xorm.io/xorm" From 8de2992ffba8cc627757ecea1e002a55581113d2 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sat, 27 Apr 2024 22:32:00 +0800 Subject: [PATCH 224/370] Make Ctrl+Enter work for issue/comment edit (#30720) Fix #30710 --- templates/repo/diff/box.tmpl | 4 ++-- templates/repo/issue/view_content.tmpl | 6 +++--- web_src/js/features/comp/QuickSubmit.js | 7 ++++++- web_src/js/features/repo-issue-edit.js | 4 ++-- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl index 92a3163642..641de294fd 100644 --- a/templates/repo/diff/box.tmpl +++ b/templates/repo/diff/box.tmpl @@ -235,7 +235,7 @@ {{if and (not $.Repository.IsArchived) (not .DiffNotAvailable)}} <template id="issue-comment-editor-template"> - <div class="ui comment form"> + <div class="ui form comment"> {{template "shared/combomarkdowneditor" (dict "MarkdownPreviewUrl" (print $.Repository.Link "/markup") "MarkdownPreviewContext" $.RepoLink @@ -249,7 +249,7 @@ {{end}} <div class="text right edit buttons"> <button class="ui cancel button">{{ctx.Locale.Tr "repo.issues.cancel"}}</button> - <button class="ui primary save button">{{ctx.Locale.Tr "repo.issues.save"}}</button> + <button class="ui primary button">{{ctx.Locale.Tr "repo.issues.save"}}</button> </div> </div> </template> diff --git a/templates/repo/issue/view_content.tmpl b/templates/repo/issue/view_content.tmpl index 8316df2ee1..d40134ed08 100644 --- a/templates/repo/issue/view_content.tmpl +++ b/templates/repo/issue/view_content.tmpl @@ -146,7 +146,7 @@ </div> <template id="issue-comment-editor-template"> - <div class="ui comment form"> + <div class="ui form comment"> <div class="field"> {{template "shared/combomarkdowneditor" (dict "MarkdownPreviewUrl" (print .Repository.Link "/markup") @@ -164,8 +164,8 @@ <div class="field"> <div class="text right edit"> - <button class="ui basic cancel button">{{ctx.Locale.Tr "repo.issues.cancel"}}</button> - <button class="ui primary save button">{{ctx.Locale.Tr "repo.issues.save"}}</button> + <button class="ui cancel button">{{ctx.Locale.Tr "repo.issues.cancel"}}</button> + <button class="ui primary button">{{ctx.Locale.Tr "repo.issues.save"}}</button> </div> </div> </div> diff --git a/web_src/js/features/comp/QuickSubmit.js b/web_src/js/features/comp/QuickSubmit.js index 477b3b9e2a..6bd5f6644d 100644 --- a/web_src/js/features/comp/QuickSubmit.js +++ b/web_src/js/features/comp/QuickSubmit.js @@ -1,5 +1,5 @@ export function handleGlobalEnterQuickSubmit(target) { - const form = target.closest('form'); + let form = target.closest('form'); if (form) { if (!form.checkValidity()) { form.reportValidity(); @@ -9,5 +9,10 @@ export function handleGlobalEnterQuickSubmit(target) { // here use the event to trigger the submit event (instead of calling `submit()` method directly) // otherwise the `areYouSure` handler won't be executed, then there will be an annoying "confirm to leave" dialog form.dispatchEvent(new SubmitEvent('submit', {bubbles: true, cancelable: true})); + return; + } + form = target.closest('.ui.form'); + if (form) { + form.querySelector('.ui.primary.button')?.click(); } } diff --git a/web_src/js/features/repo-issue-edit.js b/web_src/js/features/repo-issue-edit.js index 4c03325c7a..abf2d31221 100644 --- a/web_src/js/features/repo-issue-edit.js +++ b/web_src/js/features/repo-issue-edit.js @@ -162,8 +162,8 @@ async function onEditContent(event) { editContentZone.innerHTML = document.getElementById('issue-comment-editor-template').innerHTML; comboMarkdownEditor = await initComboMarkdownEditor(editContentZone.querySelector('.combo-markdown-editor')); comboMarkdownEditor.attachedDropzoneInst = await setupDropzone(editContentZone.querySelector('.dropzone')); - editContentZone.querySelector('.cancel.button').addEventListener('click', cancelAndReset); - editContentZone.querySelector('.save.button').addEventListener('click', saveAndRefresh); + editContentZone.querySelector('.ui.cancel.button').addEventListener('click', cancelAndReset); + editContentZone.querySelector('.ui.primary.button').addEventListener('click', saveAndRefresh); } // Show write/preview tab and copy raw content as needed From 7b8e418da1e082786b844562a05864ec1177ce97 Mon Sep 17 00:00:00 2001 From: Chongyi Zheng <git@zcy.dev> Date: Sat, 27 Apr 2024 12:50:35 -0400 Subject: [PATCH 225/370] Replace deprecated `math/rand` functions (#30733) Suggested by logs in #30729 - Remove `math/rand.Seed` `rand.Seed is deprecated: As of Go 1.20 there is no reason to call Seed with a random value.` - Replace `math/rand.Read` `rand.Read is deprecated: For almost all use cases, [crypto/rand.Read] is more appropriate.` - Replace `math/rand` with `math/rand/v2`, which is available since Go 1.22 --- models/user/user_test.go | 2 +- modules/auth/password/pwn/pwn_test.go | 16 +++++----------- tests/integration/benchmarks_test.go | 6 +++--- tests/integration/git_test.go | 2 +- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/models/user/user_test.go b/models/user/user_test.go index b4ffa1f322..c4e278caab 100644 --- a/models/user/user_test.go +++ b/models/user/user_test.go @@ -5,8 +5,8 @@ package user_test import ( "context" + "crypto/rand" "fmt" - "math/rand" "strings" "testing" "time" diff --git a/modules/auth/password/pwn/pwn_test.go b/modules/auth/password/pwn/pwn_test.go index f9deadc8d7..a2a6b3a174 100644 --- a/modules/auth/password/pwn/pwn_test.go +++ b/modules/auth/password/pwn/pwn_test.go @@ -4,9 +4,8 @@ package pwn import ( - "math/rand" + "math/rand/v2" "net/http" - "os" "strings" "testing" "time" @@ -18,11 +17,6 @@ var client = New(WithHTTP(&http.Client{ Timeout: time.Second * 2, })) -func TestMain(m *testing.M) { - rand.Seed(time.Now().Unix()) - os.Exit(m.Run()) -} - func TestPassword(t *testing.T) { // Check input error _, err := client.CheckPassword("", false) @@ -81,24 +75,24 @@ func testPassword() string { // Set special character for i := 0; i < 5; i++ { - random := rand.Intn(len(specialCharSet)) + random := rand.IntN(len(specialCharSet)) password.WriteString(string(specialCharSet[random])) } // Set numeric for i := 0; i < 5; i++ { - random := rand.Intn(len(numberSet)) + random := rand.IntN(len(numberSet)) password.WriteString(string(numberSet[random])) } // Set uppercase for i := 0; i < 5; i++ { - random := rand.Intn(len(upperCharSet)) + random := rand.IntN(len(upperCharSet)) password.WriteString(string(upperCharSet[random])) } for i := 0; i < 5; i++ { - random := rand.Intn(len(allCharSet)) + random := rand.IntN(len(allCharSet)) password.WriteString(string(allCharSet[random])) } inRune := []rune(password.String()) diff --git a/tests/integration/benchmarks_test.go b/tests/integration/benchmarks_test.go index 7a882fe836..62da761d2d 100644 --- a/tests/integration/benchmarks_test.go +++ b/tests/integration/benchmarks_test.go @@ -4,7 +4,7 @@ package integration import ( - "math/rand" + "math/rand/v2" "net/http" "net/url" "testing" @@ -18,7 +18,7 @@ import ( func StringWithCharset(length int, charset string) string { b := make([]byte, length) for i := range b { - b[i] = charset[rand.Intn(len(charset))] + b[i] = charset[rand.IntN(len(charset))] } return string(b) } @@ -37,7 +37,7 @@ func BenchmarkRepoBranchCommit(b *testing.B) { b.ResetTimer() b.Run("CreateBranch", func(b *testing.B) { b.StopTimer() - branchName := StringWithCharset(5+rand.Intn(10), "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") + branchName := StringWithCharset(5+rand.IntN(10), "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") b.StartTimer() for i := 0; i < b.N; i++ { b.Run("new_"+branchName, func(b *testing.B) { diff --git a/tests/integration/git_test.go b/tests/integration/git_test.go index 818e1fa653..74c511fd7e 100644 --- a/tests/integration/git_test.go +++ b/tests/integration/git_test.go @@ -5,9 +5,9 @@ package integration import ( "bytes" + "crypto/rand" "encoding/hex" "fmt" - "math/rand" "net/http" "net/url" "os" From 8b8b48ef5fb1c5c164d5534ea4b8049f1db26ce9 Mon Sep 17 00:00:00 2001 From: Chongyi Zheng <git@zcy.dev> Date: Sat, 27 Apr 2024 19:21:33 -0400 Subject: [PATCH 226/370] Use `ProtonMail/go-crypto` for `opengpg` in tests (#30736) --- go.mod | 2 +- tests/integration/gpg_git_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 1e88de3011..183ece6b1a 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4 github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121 github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 + github.com/ProtonMail/go-crypto v1.0.0 github.com/PuerkitoBio/goquery v1.9.1 github.com/alecthomas/chroma/v2 v2.13.0 github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb @@ -135,7 +136,6 @@ require ( github.com/Masterminds/semver/v3 v3.2.1 // indirect github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/ProtonMail/go-crypto v1.0.0 // indirect github.com/RoaringBitmap/roaring v1.9.0 // indirect github.com/andybalholm/brotli v1.1.0 // indirect github.com/andybalholm/cascadia v1.3.2 // indirect diff --git a/tests/integration/gpg_git_test.go b/tests/integration/gpg_git_test.go index 00890cfb38..3ba4a5882c 100644 --- a/tests/integration/gpg_git_test.go +++ b/tests/integration/gpg_git_test.go @@ -19,9 +19,9 @@ import ( "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/tests" + "github.com/ProtonMail/go-crypto/openpgp" + "github.com/ProtonMail/go-crypto/openpgp/armor" "github.com/stretchr/testify/assert" - "golang.org/x/crypto/openpgp" - "golang.org/x/crypto/openpgp/armor" ) func TestGPGGit(t *testing.T) { From 970965f6d8fb4e68613ca445d2414c6c796b5231 Mon Sep 17 00:00:00 2001 From: Chongyi Zheng <git@zcy.dev> Date: Sun, 28 Apr 2024 00:13:57 -0400 Subject: [PATCH 227/370] Fix nil dereference on error (#30740) In both cases, the `err` is nil because of `if` checks before Reference: #30729 --- routers/api/actions/artifacts.go | 7 ++++--- routers/web/repo/actions/view.go | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/routers/api/actions/artifacts.go b/routers/api/actions/artifacts.go index 3e717b8d8f..5bd004bd37 100644 --- a/routers/api/actions/artifacts.go +++ b/routers/api/actions/artifacts.go @@ -466,14 +466,15 @@ func (ar artifactRoutes) downloadArtifact(ctx *ArtifactContext) { log.Error("Error getting artifact: %v", err) ctx.Error(http.StatusInternalServerError, err.Error()) return - } else if !exist { + } + if !exist { log.Error("artifact with ID %d does not exist", artifactID) ctx.Error(http.StatusNotFound, fmt.Sprintf("artifact with ID %d does not exist", artifactID)) return } if artifact.RunID != runID { - log.Error("Error dismatch runID and artifactID, task: %v, artifact: %v", runID, artifactID) - ctx.Error(http.StatusBadRequest, err.Error()) + log.Error("Error mismatch runID and artifactID, task: %v, artifact: %v", runID, artifactID) + ctx.Error(http.StatusBadRequest) return } diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go index 3909a64be6..12909bddd5 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -504,7 +504,7 @@ func getRunJobs(ctx *context_module.Context, runIndex, jobIndex int64) (*actions return nil, nil } if len(jobs) == 0 { - ctx.Error(http.StatusNotFound, err.Error()) + ctx.Error(http.StatusNotFound) return nil, nil } From b2013be9105bdbfa1e5926a6da13eac347df25e2 Mon Sep 17 00:00:00 2001 From: Chongyi Zheng <git@zcy.dev> Date: Sun, 28 Apr 2024 01:20:23 -0400 Subject: [PATCH 228/370] Bump `github.com/google/go-github` to v61 (#30738) --- assets/go-licenses.json | 4 ++-- contrib/backport/backport.go | 2 +- go.mod | 2 +- go.sum | 4 ++-- services/migrations/error.go | 2 +- services/migrations/github.go | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/assets/go-licenses.json b/assets/go-licenses.json index db94ea0d7d..b8905da284 100644 --- a/assets/go-licenses.json +++ b/assets/go-licenses.json @@ -540,8 +540,8 @@ "licenseText": "Copyright (c) 2011 The Snappy-Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, { - "name": "github.com/google/go-github/v57/github", - "path": "github.com/google/go-github/v57/github/LICENSE", + "name": "github.com/google/go-github/v61/github", + "path": "github.com/google/go-github/v61/github/LICENSE", "licenseText": "Copyright (c) 2013 The go-github AUTHORS. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" }, { diff --git a/contrib/backport/backport.go b/contrib/backport/backport.go index 820c0702b7..9ae4483d8b 100644 --- a/contrib/backport/backport.go +++ b/contrib/backport/backport.go @@ -17,7 +17,7 @@ import ( "strings" "syscall" - "github.com/google/go-github/v57/github" + "github.com/google/go-github/v61/github" "github.com/urfave/cli/v2" "gopkg.in/yaml.v3" ) diff --git a/go.mod b/go.mod index 183ece6b1a..2c1fc5d6f2 100644 --- a/go.mod +++ b/go.mod @@ -54,7 +54,7 @@ require ( github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 github.com/golang-jwt/jwt/v5 v5.2.1 - github.com/google/go-github/v57 v57.0.0 + github.com/google/go-github/v61 v61.0.0 github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 github.com/google/uuid v1.6.0 github.com/gorilla/feeds v1.1.2 diff --git a/go.sum b/go.sum index cbf397b95c..8c26b4a7a6 100644 --- a/go.sum +++ b/go.sum @@ -394,8 +394,8 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v57 v57.0.0 h1:L+Y3UPTY8ALM8x+TV0lg+IEBI+upibemtBD8Q9u7zHs= -github.com/google/go-github/v57 v57.0.0/go.mod h1:s0omdnye0hvK/ecLvpsGfJMiRt85PimQh4oygmLIxHw= +github.com/google/go-github/v61 v61.0.0 h1:VwQCBwhyE9JclCI+22/7mLB1PuU9eowCXKY5pNlu1go= +github.com/google/go-github/v61 v61.0.0/go.mod h1:0WR+KmsWX75G2EbpyGsGmradjo3IiciuI4BmdVCobQY= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= diff --git a/services/migrations/error.go b/services/migrations/error.go index 5e0e0742c9..c7d912f50b 100644 --- a/services/migrations/error.go +++ b/services/migrations/error.go @@ -7,7 +7,7 @@ package migrations import ( "errors" - "github.com/google/go-github/v57/github" + "github.com/google/go-github/v61/github" ) // ErrRepoNotCreated returns the error that repository not created diff --git a/services/migrations/github.go b/services/migrations/github.go index be573b33b3..a36b02ca8b 100644 --- a/services/migrations/github.go +++ b/services/migrations/github.go @@ -20,7 +20,7 @@ import ( "code.gitea.io/gitea/modules/proxy" "code.gitea.io/gitea/modules/structs" - "github.com/google/go-github/v57/github" + "github.com/google/go-github/v61/github" "golang.org/x/oauth2" ) From 9a0b449c4f428422b62c658ec1f6d2875ff41151 Mon Sep 17 00:00:00 2001 From: Chongyi Zheng <git@zcy.dev> Date: Sun, 28 Apr 2024 01:47:48 -0400 Subject: [PATCH 229/370] Remove disk-clean workflow (#30741) The jobs in the workflow runs in parallel. The `disk-clean` job actually does nothing, i.e. it will not clean the disk for `nightly-binary`, `nightly-docker-rootful`, `nightly-docker-rootless` --- .github/workflows/disk-clean.yml | 25 ------------------------- .github/workflows/release-nightly.yml | 2 -- 2 files changed, 27 deletions(-) delete mode 100644 .github/workflows/disk-clean.yml diff --git a/.github/workflows/disk-clean.yml b/.github/workflows/disk-clean.yml deleted file mode 100644 index 8abe8891c7..0000000000 --- a/.github/workflows/disk-clean.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: disk-clean - -on: - workflow_call: - -jobs: - triage: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Free Disk Space (Ubuntu) - uses: jlumbroso/free-disk-space@main - with: - # this might remove tools that are actually needed, - # if set to "true" but frees about 6 GB - tool-cache: false - - # all of these default to true, but feel free to set to - # "false" if necessary for your workflow - android: true - dotnet: true - haskell: true - large-packages: false - docker-images: false - swap-storage: true diff --git a/.github/workflows/release-nightly.yml b/.github/workflows/release-nightly.yml index 990f3c8e07..fbaa27102c 100644 --- a/.github/workflows/release-nightly.yml +++ b/.github/workflows/release-nightly.yml @@ -9,8 +9,6 @@ concurrency: cancel-in-progress: true jobs: - disk-clean: - uses: ./.github/workflows/disk-clean.yml nightly-binary: runs-on: nscloud steps: From daf841fe14a03d6a543afa1356f59aab96f31932 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Sun, 28 Apr 2024 20:36:14 +0800 Subject: [PATCH 230/370] Fix documentation build problems because of MDX syntax conflicts (#30744) Documentation building has encountered a problem like below. This is because MDX syntax doesn't allow `{customPath}`, we have to use \`{customPath}\` ``` Error: Can't render static file for pathname "/next/administration/config-cheat-sheet" at generateStaticFile (/workspace/gitea/gitea-docusaurus/node_modules/@docusaurus/core/lib/ssg.js:119:15) at runNextTicks (node:internal/process/task_queues:60:5) at process.processImmediate (node:internal/timers:449:9) at async /workspace/gitea/gitea-docusaurus/node_modules/p-map/index.js:57:22 { [cause]: ReferenceError: CustomPath is not defined at _createMdxContent (server.bundle.js:4406:106) at MDXContent (server.bundle.js:10745:8) at Uc (server.bundle.js:264171:44) at Xc (server.bundle.js:264173:253) at Z (server.bundle.js:264179:89) at Yc (server.bundle.js:264182:98) at $c (server.bundle.js:264181:140) at Z (server.bundle.js:264179:345) at Xc (server.bundle.js:264177:231) at Z (server.bundle.js:264179:89) ``` --- docs/content/administration/config-cheat-sheet.en-us.md | 4 ++-- docs/content/administration/config-cheat-sheet.zh-cn.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index 7bf23c9b99..5066e0f879 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -214,9 +214,9 @@ The following configuration set `Content-Type: application/vnd.android.package-a - `SITEMAP_PAGING_NUM`: **20**: Number of items that are displayed in a single subsitemap. - `GRAPH_MAX_COMMIT_NUM`: **100**: Number of maximum commits shown in the commit graph. - `CODE_COMMENT_LINES`: **4**: Number of line of codes shown for a code comment. -- `DEFAULT_THEME`: **gitea-auto**: Set the default theme for the Gitea installation, custom themes could be provided by "{CustomPath}/public/assets/css/theme-*.css". +- `DEFAULT_THEME`: **gitea-auto**: Set the default theme for the Gitea installation, custom themes could be provided by `{CustomPath}/public/assets/css/theme-*.css`. - `SHOW_USER_EMAIL`: **true**: Whether the email of the user should be shown in the Explore Users page. -- `THEMES`: **_empty_**: All available themes by "{CustomPath}/public/assets/css/theme-*.css". Allow users select personalized themes. +- `THEMES`: **_empty_**: All available themes by `{CustomPath}/public/assets/css/theme-*.css`. Allow users select personalized themes. - `MAX_DISPLAY_FILE_SIZE`: **8388608**: Max size of files to be displayed (default is 8MiB) - `AMBIGUOUS_UNICODE_DETECTION`: **true**: Detect ambiguous unicode characters in file contents and show warnings on the UI - `REACTIONS`: All available reactions users can choose on issues/prs and comments diff --git a/docs/content/administration/config-cheat-sheet.zh-cn.md b/docs/content/administration/config-cheat-sheet.zh-cn.md index 0d08a5e51b..3bb31d3d71 100644 --- a/docs/content/administration/config-cheat-sheet.zh-cn.md +++ b/docs/content/administration/config-cheat-sheet.zh-cn.md @@ -212,9 +212,9 @@ menu: - `SITEMAP_PAGING_NUM`: **20**: 在单个子SiteMap中显示的项数。 - `GRAPH_MAX_COMMIT_NUM`: **100**: 提交图中显示的最大commit数量。 - `CODE_COMMENT_LINES`: **4**: 在代码评论中能够显示的最大代码行数。 -- `DEFAULT_THEME`: **gitea-auto**: 在Gitea安装时候设置的默认主题,自定义的主题可以通过 "{CustomPath}/public/assets/css/theme-*.css" 提供。 +- `DEFAULT_THEME`: **gitea-auto**: 在Gitea安装时候设置的默认主题,自定义的主题可以通过 `{CustomPath}/public/assets/css/theme-*.css` 提供。 - `SHOW_USER_EMAIL`: **true**: 用户的电子邮件是否应该显示在`Explore Users`页面中。 -- `THEMES`: **_empty_**: 所有可用的主题(由 "{CustomPath}/public/assets/css/theme-*.css" 提供)。允许用户选择个性化的主题, +- `THEMES`: **_empty_**: 所有可用的主题(由 `{CustomPath}/public/assets/css/theme-*.css` 提供)。允许用户选择个性化的主题, - `MAX_DISPLAY_FILE_SIZE`: **8388608**: 能够显示文件的最大大小(默认为8MiB)。 - `REACTIONS`: 用户可以在问题(Issue)、Pull Request(PR)以及评论中选择的所有可选的反应。 这些值可以是表情符号别名(例如::smile:)或Unicode表情符号。 From 81a0a031f5df3504564634e6050fbb2a45cd40c1 Mon Sep 17 00:00:00 2001 From: mainboarder <git@mainboarder.de> Date: Sun, 28 Apr 2024 15:01:22 +0200 Subject: [PATCH 231/370] Gitea with first upper case + typos (#30739) * Corrected gitea to Gitea * fixed some typos --- docs/content/usage/repo-mirror.en-us.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/content/usage/repo-mirror.en-us.md b/docs/content/usage/repo-mirror.en-us.md index 8804a8885a..9d23159890 100644 --- a/docs/content/usage/repo-mirror.en-us.md +++ b/docs/content/usage/repo-mirror.en-us.md @@ -58,7 +58,7 @@ The repository now gets mirrored periodically to the remote repository. You can To set up a mirror from Gitea to GitHub, you need to follow these steps: -1. Create a [GitHub personal access token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) with the *public_repo* box checked. Also check the **workflow** checkbox in case your repo using act for continuous integration. +1. Create a [GitHub personal access token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) with the *public_repo* box checked. Also check the **workflow** checkbox in case your repo uses GitHub Actions for continuous integration. 2. Create a repository with that name on GitHub. Unlike Gitea, GitHub does not support creating repositories by pushing to the remote. You can also use an existing remote repo if it has the same commit history as your Gitea repo. 3. In the settings of your Gitea repo, fill in the **Git Remote Repository URL**: `https://github.com/<your_github_group>/<your_github_project>.git`. 4. Fill in the **Authorization** fields with your GitHub username and the personal access token as **Password**. @@ -91,10 +91,10 @@ The repository pushes shortly thereafter. To force a push, select the **Synchron ### Mirror an existing ssh repository -Currently gitea supports no ssh push mirrors. You can work around this by adding a `post-receive` hook to your gitea repository that pushes manually. +Currently Gitea supports no ssh push mirrors. You can work around this by adding a `post-receive` hook to your Gitea repository that pushes manually. -1. Make sure the user running gitea has access to the git repo you are trying to mirror to from shell. -2. On the Webinterface at the repository settings > git hooks add a post-receive hook for the mirror. I.e. +1. Make sure the user running Gitea has access to the git repo you are trying to mirror to from shell. +2. On the web interface at the repository settings > git hooks add a post-receive hook for the mirror. I.e. ``` #!/usr/bin/env bash From d89bf3d3ec933c11f4ee7e4e714804d5815afa75 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 28 Apr 2024 16:27:14 +0200 Subject: [PATCH 232/370] add built js files to eslint ignore (#30737) For the rare case that some overzealous tooling wants to lint our output files. --- .eslintrc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintrc.yaml b/.eslintrc.yaml index cd5a0735b4..d9cbefd124 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -4,6 +4,7 @@ reportUnusedDisableDirectives: true ignorePatterns: - /web_src/js/vendor - /web_src/fomantic + - /public/assets/js parserOptions: sourceType: module From e67141756d058045cf64a441255a2042425eda3b Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Mon, 29 Apr 2024 00:25:01 +0000 Subject: [PATCH 233/370] [skip ci] Updated licenses and gitignores --- options/license/Catharon | 121 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 options/license/Catharon diff --git a/options/license/Catharon b/options/license/Catharon new file mode 100644 index 0000000000..8d0ac128bc --- /dev/null +++ b/options/license/Catharon @@ -0,0 +1,121 @@ + The Catharon Open Source LICENSE + ---------------------------- + + 2000-Jul-04 + + Copyright (C) 2000 by Catharon Productions, Inc. + + + +Introduction +============ + + This license applies to source files distributed by Catharon + Productions, Inc. in several archive packages. This license + applies to all files found in such packages which do not fall + under their own explicit license. + + This license was inspired by the BSD, Artistic, and IJG + (Independent JPEG Group) licenses, which all encourage inclusion + and use of free software in commercial and freeware products + alike. As a consequence, its main points are that: + + o We don't promise that this software works. However, we are + interested in any kind of bug reports. (`as is' distribution) + + o You can use this software for whatever you want, in parts or + full form, without having to pay us. (`royalty-free' usage) + + o You may not pretend that you wrote this software. If you use + it, or only parts of it, in a program, you must acknowledge + somewhere in your documentation that you have used the + Catharon Code. (`credits') + + We specifically permit and encourage the inclusion of this + software, with or without modifications, in commercial products. + We disclaim all warranties covering the packages distributed by + Catharon Productions, Inc. and assume no liability related to + their use. + + +Legal Terms +=========== + +0. Definitions +-------------- + + Throughout this license, the terms `Catharon Package', `package', + and `Catharon Code' refer to the set of files originally + distributed by Catharon Productions, Inc. + + `You' refers to the licensee, or person using the project, where + `using' is a generic term including compiling the project's source + code as well as linking it to form a `program' or `executable'. + This program is referred to as `a program using one of the + Catharon Packages'. + + This license applies to all files distributed in the original + Catharon Package(s), including all source code, binaries and + documentation, unless otherwise stated in the file in its + original, unmodified form as distributed in the original archive. + If you are unsure whether or not a particular file is covered by + this license, you must contact us to verify this. + + The Catharon Packages are copyright (C) 2000 by Catharon + Productions, Inc. All rights reserved except as specified below. + +1. No Warranty +-------------- + + THE CATHARON PACKAGES ARE PROVIDED `AS IS' WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY DAMAGES CAUSED BY THE USE OF OR THE INABILITY TO + USE THE CATHARON PACKAGE. + +2. Redistribution +----------------- + + This license grants a worldwide, royalty-free, perpetual and + irrevocable right and license to use, execute, perform, compile, + display, copy, create derivative works of, distribute and + sublicense the Catharon Packages (in both source and object code + forms) and derivative works thereof for any purpose; and to + authorize others to exercise some or all of the rights granted + herein, subject to the following conditions: + + o Redistribution of source code must retain this license file + (`license.txt') unaltered; any additions, deletions or changes + to the original files must be clearly indicated in + accompanying documentation. The copyright notices of the + unaltered, original files must be preserved in all copies of + source files. + + o Redistribution in binary form must provide a disclaimer that + states that the software is based in part on the work of + Catharon Productions, Inc. in the distribution documentation. + + These conditions apply to any software derived from or based on + the Catharon Packages, not just the unmodified files. If you use + our work, you must acknowledge us. However, no fee need be paid + to us. + +3. Advertising +-------------- + + Neither Catharon Productions, Inc. and contributors nor you shall + use the name of the other for commercial, advertising, or + promotional purposes without specific prior written permission. + + We suggest, but do not require, that you use the following phrase + to refer to this software in your documentation: 'this software is + based in part on the Catharon Typography Project'. + + As you have not signed this license, you are not required to + accept it. However, as the Catharon Packages are copyrighted + material, only this license, or another one contracted with the + authors, grants you the right to use, distribute, and modify it. + Therefore, by using, distributing, or modifying the Catharon + Packages, you indicate that you understand and accept all the + terms of this license. From d11133b83652238023b52576e0d3e57a4f4b21c9 Mon Sep 17 00:00:00 2001 From: Sergey Zolotarev <4525736+sryze@users.noreply.github.com> Date: Mon, 29 Apr 2024 09:45:53 +0600 Subject: [PATCH 234/370] Fix cross-compilation errors when CGO_CFLAGS/CGO_LDFLAGS is set (#30749) When you cross-compile Gitea and you specify one of the envrionment variables related to C flags, cgo will fail to build the generator programs (e.g. generate-bindata) because GOOS and GOARCH are unset, but those additional flags variables are not unset together with those. To solve this issue, the simplest way that I've found is to disable cgo in the `go generate` command as it's not really used there. For example, I've had this problem with cross-compiling Gitea on FreeBSD x86_64 to ARMv7 where it's necessary to pass `--target` to `clang` via `CGO_CFLAGS`: ``` GOOS=freebsd \ GOARCH=arm \ GGOARM=7 \ CGO_ENABLED=1 \ SYSROOT=/usr/local/freebsd-sysroot/armv7 \ CC=clang \ CGO_CFLAGS="--target=armv7-unknown-freebsd13.2-gnueabihf" \ TAGS="bindata sqlite sqlite_unlock_notify" \ make SHELL='sh -x' build ``` ``` Running go generate... # runtime/cgo In file included from gcc_freebsd_amd64.c:9: In file included from /usr/include/signal.h:42: /usr/include/sys/_ucontext.h:44:2: error: unknown type name 'mcontext_t' modules/migration/schemas_bindata.go:8: running "go": exit status 1 # runtime/cgo In file included from gcc_freebsd_amd64.c:9: In file included from /usr/include/signal.h:42: /usr/include/sys/_ucontext.h:44:2: error: unknown type name 'mcontext_t' modules/options/options_bindata.go:8: running "go": exit status 1 # runtime/cgo In file included from gcc_freebsd_amd64.c:9: In file included from /usr/include/signal.h:42: /usr/include/sys/_ucontext.h:44:2: error: unknown type name 'mcontext_t' modules/public/public_bindata.go:8: running "go": exit status 1 # runtime/cgo In file included from gcc_freebsd_amd64.c:9: In file included from /usr/include/signal.h:42: /usr/include/sys/_ucontext.h:44:2: error: unknown type name 'mcontext_t' modules/templates/templates_bindata.go:8: running "go": exit status 1 gmake[1]: *** [Makefile:781: generate-go] Error 1 *** Error code 2 Stop. ``` But with this fix Gitea compiles successfully. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0cd6abb81e..e8006e4031 100644 --- a/Makefile +++ b/Makefile @@ -778,7 +778,7 @@ generate-backend: $(TAGS_PREREQ) generate-go .PHONY: generate-go generate-go: $(TAGS_PREREQ) @echo "Running go generate..." - @CC= GOOS= GOARCH= $(GO) generate -tags '$(TAGS)' ./... + @CC= GOOS= GOARCH= CGO_ENABLED=0 $(GO) generate -tags '$(TAGS)' ./... .PHONY: security-check security-check: From ad4e902d5a1430c0c1df18bf404537df5ded1dba Mon Sep 17 00:00:00 2001 From: Micash <70768913+micash545@users.noreply.github.com> Date: Mon, 29 Apr 2024 10:19:06 +0200 Subject: [PATCH 235/370] Add support for npm bundleDependencies (#30751) --- modules/packages/npm/creator.go | 2 ++ modules/packages/npm/metadata.go | 1 + options/locale/locale_en-US.ini | 1 + routers/api/packages/npm/api.go | 1 + templates/package/content/npm.tmpl | 9 +++++++++ 5 files changed, 14 insertions(+) diff --git a/modules/packages/npm/creator.go b/modules/packages/npm/creator.go index 9e636757af..7d3d7cd6b5 100644 --- a/modules/packages/npm/creator.go +++ b/modules/packages/npm/creator.go @@ -78,6 +78,7 @@ type PackageMetadataVersion struct { Repository Repository `json:"repository,omitempty"` Keywords []string `json:"keywords,omitempty"` Dependencies map[string]string `json:"dependencies,omitempty"` + BundleDependencies []string `json:"bundleDependencies,omitempty"` DevDependencies map[string]string `json:"devDependencies,omitempty"` PeerDependencies map[string]string `json:"peerDependencies,omitempty"` Bin map[string]string `json:"bin,omitempty"` @@ -218,6 +219,7 @@ func ParsePackage(r io.Reader) (*Package, error) { ProjectURL: meta.Homepage, Keywords: meta.Keywords, Dependencies: meta.Dependencies, + BundleDependencies: meta.BundleDependencies, DevelopmentDependencies: meta.DevDependencies, PeerDependencies: meta.PeerDependencies, OptionalDependencies: meta.OptionalDependencies, diff --git a/modules/packages/npm/metadata.go b/modules/packages/npm/metadata.go index 77b77472a7..6bb77f302b 100644 --- a/modules/packages/npm/metadata.go +++ b/modules/packages/npm/metadata.go @@ -16,6 +16,7 @@ type Metadata struct { ProjectURL string `json:"project_url,omitempty"` Keywords []string `json:"keywords,omitempty"` Dependencies map[string]string `json:"dependencies,omitempty"` + BundleDependencies []string `json:"bundleDependencies,omitempty"` DevelopmentDependencies map[string]string `json:"development_dependencies,omitempty"` PeerDependencies map[string]string `json:"peer_dependencies,omitempty"` OptionalDependencies map[string]string `json:"optional_dependencies,omitempty"` diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index fb591be393..eef4f5696a 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -3495,6 +3495,7 @@ npm.install = To install the package using npm, run the following command: npm.install2 = or add it to the package.json file: npm.dependencies = Dependencies npm.dependencies.development = Development Dependencies +npm.dependencies.bundle = Bundled Dependencies npm.dependencies.peer = Peer Dependencies npm.dependencies.optional = Optional Dependencies npm.details.tag = Tag diff --git a/routers/api/packages/npm/api.go b/routers/api/packages/npm/api.go index f8e839c424..b4379f3f49 100644 --- a/routers/api/packages/npm/api.go +++ b/routers/api/packages/npm/api.go @@ -64,6 +64,7 @@ func createPackageMetadataVersion(registryURL string, pd *packages_model.Package Homepage: metadata.ProjectURL, License: metadata.License, Dependencies: metadata.Dependencies, + BundleDependencies: metadata.BundleDependencies, DevDependencies: metadata.DevelopmentDependencies, PeerDependencies: metadata.PeerDependencies, OptionalDependencies: metadata.OptionalDependencies, diff --git a/templates/package/content/npm.tmpl b/templates/package/content/npm.tmpl index a78a07d874..01298a664c 100644 --- a/templates/package/content/npm.tmpl +++ b/templates/package/content/npm.tmpl @@ -45,6 +45,15 @@ </div> {{end}} + {{if .PackageDescriptor.Metadata.BundleDependencies}} + <h4 class="ui top attached header">{{ctx.Locale.Tr "packages.npm.dependencies.bundle"}}</h4> + <div class="ui attached segment"> + {{range .PackageDescriptor.Metadata.BundleDependencies}} + {{.}} + {{end}} + </div> + {{end}} + {{if .PackageDescriptor.Metadata.Keywords}} <h4 class="ui top attached header">{{ctx.Locale.Tr "packages.keywords"}}</h4> <div class="ui attached segment"> From e80466f7349164ce4cf3c07bdac30d736d20f035 Mon Sep 17 00:00:00 2001 From: Chongyi Zheng <git@zcy.dev> Date: Mon, 29 Apr 2024 04:47:56 -0400 Subject: [PATCH 236/370] Resolve lint for unused parameter and unnecessary type arguments (#30750) Resolve all cases for `unused parameter` and `unnecessary type arguments` Related: #30729 --------- Co-authored-by: Giteabot <teabot@gitea.io> --- models/issues/issue_xref_test.go | 12 +++++----- models/organization/org_test.go | 6 ++--- modules/actions/workflows.go | 24 +++++++++---------- modules/git/commit_info_nogogit.go | 4 ++-- modules/git/parse_gogit.go | 2 +- modules/git/parse_gogit_test.go | 2 +- modules/git/parse_nogogit.go | 6 ++--- modules/git/parse_nogogit_test.go | 10 +++----- modules/git/tree_nogogit.go | 14 ++++------- modules/indexer/code/git.go | 12 ++++------ modules/markup/markdown/goldmark.go | 6 ++--- modules/markup/markdown/transform_codespan.go | 2 +- modules/markup/markdown/transform_heading.go | 2 +- modules/markup/markdown/transform_image.go | 3 +-- modules/markup/markdown/transform_link.go | 3 +-- modules/markup/markdown/transform_list.go | 3 +-- modules/markup/mdstripper/mdstripper.go | 4 ++-- modules/optional/option_test.go | 2 +- modules/setting/incoming_email.go | 4 ++-- modules/setting/storage.go | 4 ++-- routers/api/v1/admin/user_badge.go | 6 ++--- routers/api/v1/repo/migrate.go | 6 ++--- routers/private/hook_pre_receive.go | 8 +++---- routers/web/admin/admin.go | 2 +- routers/web/feed/convert.go | 2 +- routers/web/feed/release.go | 2 +- services/context/repo.go | 8 +++---- services/doctor/storage.go | 14 +++++------ services/migrations/gitea_uploader.go | 15 ++++++------ services/mirror/mirror.go | 2 +- services/pull/review.go | 4 ++-- services/pull/update.go | 2 +- services/pull/update_rebase.go | 2 +- services/repository/adopt.go | 4 ++-- services/repository/branch.go | 6 ++--- services/repository/files/update.go | 4 ++-- services/user/update_test.go | 2 +- tests/integration/api_packages_chef_test.go | 4 ++-- tests/integration/api_releases_test.go | 12 +++++----- tests/integration/api_repo_git_tags_test.go | 2 +- tests/integration/repo_search_test.go | 4 ++-- tests/integration/repofiles_change_test.go | 6 ++--- 42 files changed, 112 insertions(+), 130 deletions(-) diff --git a/models/issues/issue_xref_test.go b/models/issues/issue_xref_test.go index 5bcaf75518..f1b1bb2a6b 100644 --- a/models/issues/issue_xref_test.go +++ b/models/issues/issue_xref_test.go @@ -34,7 +34,7 @@ func TestXRef_AddCrossReferences(t *testing.T) { // Comment on PR to reopen issue #1 content = fmt.Sprintf("content2, reopens #%d", itarget.Index) - c := testCreateComment(t, 1, 2, pr.ID, content) + c := testCreateComment(t, 2, pr.ID, content) ref = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: pr.ID, RefCommentID: c.ID}) assert.Equal(t, issues_model.CommentTypeCommentRef, ref.Type) assert.Equal(t, pr.RepoID, ref.RefRepoID) @@ -104,18 +104,18 @@ func TestXRef_ResolveCrossReferences(t *testing.T) { pr := testCreatePR(t, 1, 2, "titlepr", fmt.Sprintf("closes #%d", i1.Index)) rp := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i1.ID, RefIssueID: pr.Issue.ID, RefCommentID: 0}) - c1 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("closes #%d", i2.Index)) + c1 := testCreateComment(t, 2, pr.Issue.ID, fmt.Sprintf("closes #%d", i2.Index)) r1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i2.ID, RefIssueID: pr.Issue.ID, RefCommentID: c1.ID}) // Must be ignored - c2 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("mentions #%d", i2.Index)) + c2 := testCreateComment(t, 2, pr.Issue.ID, fmt.Sprintf("mentions #%d", i2.Index)) unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i2.ID, RefIssueID: pr.Issue.ID, RefCommentID: c2.ID}) // Must be superseded by c4/r4 - c3 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("reopens #%d", i3.Index)) + c3 := testCreateComment(t, 2, pr.Issue.ID, fmt.Sprintf("reopens #%d", i3.Index)) unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i3.ID, RefIssueID: pr.Issue.ID, RefCommentID: c3.ID}) - c4 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("closes #%d", i3.Index)) + c4 := testCreateComment(t, 2, pr.Issue.ID, fmt.Sprintf("closes #%d", i3.Index)) r4 := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i3.ID, RefIssueID: pr.Issue.ID, RefCommentID: c4.ID}) refs, err := pr.ResolveCrossReferences(db.DefaultContext) @@ -168,7 +168,7 @@ func testCreatePR(t *testing.T, repo, doer int64, title, content string) *issues return pr } -func testCreateComment(t *testing.T, repo, doer, issue int64, content string) *issues_model.Comment { +func testCreateComment(t *testing.T, doer, issue int64, content string) *issues_model.Comment { d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer}) i := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issue}) c := &issues_model.Comment{Type: issues_model.CommentTypeComment, PosterID: doer, Poster: d, IssueID: issue, Issue: i, Content: content} diff --git a/models/organization/org_test.go b/models/organization/org_test.go index 5e40dd4190..23ef22e2fb 100644 --- a/models/organization/org_test.go +++ b/models/organization/org_test.go @@ -291,15 +291,15 @@ func TestAccessibleReposEnv_CountRepos(t *testing.T) { func TestAccessibleReposEnv_RepoIDs(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) - testSuccess := func(userID, _, pageSize int64, expectedRepoIDs []int64) { + testSuccess := func(userID int64, expectedRepoIDs []int64) { env, err := organization.AccessibleReposEnv(db.DefaultContext, org, userID) assert.NoError(t, err) repoIDs, err := env.RepoIDs(1, 100) assert.NoError(t, err) assert.Equal(t, expectedRepoIDs, repoIDs) } - testSuccess(2, 1, 100, []int64{3, 5, 32}) - testSuccess(4, 0, 100, []int64{3, 32}) + testSuccess(2, []int64{3, 5, 32}) + testSuccess(4, []int64{3, 32}) } func TestAccessibleReposEnv_Repos(t *testing.T) { diff --git a/modules/actions/workflows.go b/modules/actions/workflows.go index 595fd8bbb0..0d2b0dd919 100644 --- a/modules/actions/workflows.go +++ b/modules/actions/workflows.go @@ -208,14 +208,14 @@ func detectMatched(gitRepo *git.Repository, commit *git.Commit, triggedEvent web webhook_module.HookEventIssueAssign, webhook_module.HookEventIssueLabel, webhook_module.HookEventIssueMilestone: - return matchIssuesEvent(commit, payload.(*api.IssuePayload), evt) + return matchIssuesEvent(payload.(*api.IssuePayload), evt) case // issue_comment webhook_module.HookEventIssueComment, // `pull_request_comment` is same as `issue_comment` // See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_comment-use-issue_comment webhook_module.HookEventPullRequestComment: - return matchIssueCommentEvent(commit, payload.(*api.IssueCommentPayload), evt) + return matchIssueCommentEvent(payload.(*api.IssueCommentPayload), evt) case // pull_request webhook_module.HookEventPullRequest, @@ -229,19 +229,19 @@ func detectMatched(gitRepo *git.Repository, commit *git.Commit, triggedEvent web case // pull_request_review webhook_module.HookEventPullRequestReviewApproved, webhook_module.HookEventPullRequestReviewRejected: - return matchPullRequestReviewEvent(commit, payload.(*api.PullRequestPayload), evt) + return matchPullRequestReviewEvent(payload.(*api.PullRequestPayload), evt) case // pull_request_review_comment webhook_module.HookEventPullRequestReviewComment: - return matchPullRequestReviewCommentEvent(commit, payload.(*api.PullRequestPayload), evt) + return matchPullRequestReviewCommentEvent(payload.(*api.PullRequestPayload), evt) case // release webhook_module.HookEventRelease: - return matchReleaseEvent(commit, payload.(*api.ReleasePayload), evt) + return matchReleaseEvent(payload.(*api.ReleasePayload), evt) case // registry_package webhook_module.HookEventPackage: - return matchPackageEvent(commit, payload.(*api.PackagePayload), evt) + return matchPackageEvent(payload.(*api.PackagePayload), evt) default: log.Warn("unsupported event %q", triggedEvent) @@ -347,7 +347,7 @@ func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobpa return matchTimes == len(evt.Acts()) } -func matchIssuesEvent(commit *git.Commit, issuePayload *api.IssuePayload, evt *jobparser.Event) bool { +func matchIssuesEvent(issuePayload *api.IssuePayload, evt *jobparser.Event) bool { // with no special filter parameters if len(evt.Acts()) == 0 { return true @@ -495,7 +495,7 @@ func matchPullRequestEvent(gitRepo *git.Repository, commit *git.Commit, prPayloa return activityTypeMatched && matchTimes == len(evt.Acts()) } -func matchIssueCommentEvent(commit *git.Commit, issueCommentPayload *api.IssueCommentPayload, evt *jobparser.Event) bool { +func matchIssueCommentEvent(issueCommentPayload *api.IssueCommentPayload, evt *jobparser.Event) bool { // with no special filter parameters if len(evt.Acts()) == 0 { return true @@ -527,7 +527,7 @@ func matchIssueCommentEvent(commit *git.Commit, issueCommentPayload *api.IssueCo return matchTimes == len(evt.Acts()) } -func matchPullRequestReviewEvent(commit *git.Commit, prPayload *api.PullRequestPayload, evt *jobparser.Event) bool { +func matchPullRequestReviewEvent(prPayload *api.PullRequestPayload, evt *jobparser.Event) bool { // with no special filter parameters if len(evt.Acts()) == 0 { return true @@ -576,7 +576,7 @@ func matchPullRequestReviewEvent(commit *git.Commit, prPayload *api.PullRequestP return matchTimes == len(evt.Acts()) } -func matchPullRequestReviewCommentEvent(commit *git.Commit, prPayload *api.PullRequestPayload, evt *jobparser.Event) bool { +func matchPullRequestReviewCommentEvent(prPayload *api.PullRequestPayload, evt *jobparser.Event) bool { // with no special filter parameters if len(evt.Acts()) == 0 { return true @@ -625,7 +625,7 @@ func matchPullRequestReviewCommentEvent(commit *git.Commit, prPayload *api.PullR return matchTimes == len(evt.Acts()) } -func matchReleaseEvent(commit *git.Commit, payload *api.ReleasePayload, evt *jobparser.Event) bool { +func matchReleaseEvent(payload *api.ReleasePayload, evt *jobparser.Event) bool { // with no special filter parameters if len(evt.Acts()) == 0 { return true @@ -662,7 +662,7 @@ func matchReleaseEvent(commit *git.Commit, payload *api.ReleasePayload, evt *job return matchTimes == len(evt.Acts()) } -func matchPackageEvent(commit *git.Commit, payload *api.PackagePayload, evt *jobparser.Event) bool { +func matchPackageEvent(payload *api.PackagePayload, evt *jobparser.Event) bool { // with no special filter parameters if len(evt.Acts()) == 0 { return true diff --git a/modules/git/commit_info_nogogit.go b/modules/git/commit_info_nogogit.go index a5d18694f7..7c369b07f9 100644 --- a/modules/git/commit_info_nogogit.go +++ b/modules/git/commit_info_nogogit.go @@ -29,7 +29,7 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath var revs map[string]*Commit if commit.repo.LastCommitCache != nil { var unHitPaths []string - revs, unHitPaths, err = getLastCommitForPathsByCache(ctx, commit.ID.String(), treePath, entryPaths, commit.repo.LastCommitCache) + revs, unHitPaths, err = getLastCommitForPathsByCache(commit.ID.String(), treePath, entryPaths, commit.repo.LastCommitCache) if err != nil { return nil, nil, err } @@ -97,7 +97,7 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath return commitsInfo, treeCommit, nil } -func getLastCommitForPathsByCache(ctx context.Context, commitID, treePath string, paths []string, cache *LastCommitCache) (map[string]*Commit, []string, error) { +func getLastCommitForPathsByCache(commitID, treePath string, paths []string, cache *LastCommitCache) (map[string]*Commit, []string, error) { var unHitEntryPaths []string results := make(map[string]*Commit) for _, p := range paths { diff --git a/modules/git/parse_gogit.go b/modules/git/parse_gogit.go index d1fdd346e4..74d258de8e 100644 --- a/modules/git/parse_gogit.go +++ b/modules/git/parse_gogit.go @@ -18,7 +18,7 @@ import ( ) // ParseTreeEntries parses the output of a `git ls-tree -l` command. -func ParseTreeEntries(h ObjectFormat, data []byte) ([]*TreeEntry, error) { +func ParseTreeEntries(data []byte) ([]*TreeEntry, error) { return parseTreeEntries(data, nil) } diff --git a/modules/git/parse_gogit_test.go b/modules/git/parse_gogit_test.go index d9e5b4441f..3e171d7e56 100644 --- a/modules/git/parse_gogit_test.go +++ b/modules/git/parse_gogit_test.go @@ -67,7 +67,7 @@ func TestParseTreeEntries(t *testing.T) { } for _, testCase := range testCases { - entries, err := ParseTreeEntries(Sha1ObjectFormat, []byte(testCase.Input)) + entries, err := ParseTreeEntries([]byte(testCase.Input)) assert.NoError(t, err) if len(entries) > 1 { fmt.Println(testCase.Expected[0].ID) diff --git a/modules/git/parse_nogogit.go b/modules/git/parse_nogogit.go index 225342cc5a..546b38be37 100644 --- a/modules/git/parse_nogogit.go +++ b/modules/git/parse_nogogit.go @@ -17,13 +17,13 @@ import ( ) // ParseTreeEntries parses the output of a `git ls-tree -l` command. -func ParseTreeEntries(objectFormat ObjectFormat, data []byte) ([]*TreeEntry, error) { - return parseTreeEntries(objectFormat, data, nil) +func ParseTreeEntries(data []byte) ([]*TreeEntry, error) { + return parseTreeEntries(data, nil) } var sepSpace = []byte{' '} -func parseTreeEntries(objectFormat ObjectFormat, data []byte, ptree *Tree) ([]*TreeEntry, error) { +func parseTreeEntries(data []byte, ptree *Tree) ([]*TreeEntry, error) { var err error entries := make([]*TreeEntry, 0, bytes.Count(data, []byte{'\n'})+1) for pos := 0; pos < len(data); { diff --git a/modules/git/parse_nogogit_test.go b/modules/git/parse_nogogit_test.go index f037fd7a2e..23fddb014c 100644 --- a/modules/git/parse_nogogit_test.go +++ b/modules/git/parse_nogogit_test.go @@ -12,8 +12,6 @@ import ( ) func TestParseTreeEntriesLong(t *testing.T) { - objectFormat := Sha1ObjectFormat - testCases := []struct { Input string Expected []*TreeEntry @@ -56,7 +54,7 @@ func TestParseTreeEntriesLong(t *testing.T) { }, } for _, testCase := range testCases { - entries, err := ParseTreeEntries(objectFormat, []byte(testCase.Input)) + entries, err := ParseTreeEntries([]byte(testCase.Input)) assert.NoError(t, err) assert.Len(t, entries, len(testCase.Expected)) for i, entry := range entries { @@ -66,8 +64,6 @@ func TestParseTreeEntriesLong(t *testing.T) { } func TestParseTreeEntriesShort(t *testing.T) { - objectFormat := Sha1ObjectFormat - testCases := []struct { Input string Expected []*TreeEntry @@ -91,7 +87,7 @@ func TestParseTreeEntriesShort(t *testing.T) { }, } for _, testCase := range testCases { - entries, err := ParseTreeEntries(objectFormat, []byte(testCase.Input)) + entries, err := ParseTreeEntries([]byte(testCase.Input)) assert.NoError(t, err) assert.Len(t, entries, len(testCase.Expected)) for i, entry := range entries { @@ -102,7 +98,7 @@ func TestParseTreeEntriesShort(t *testing.T) { func TestParseTreeEntriesInvalid(t *testing.T) { // there was a panic: "runtime error: slice bounds out of range" when the input was invalid: #20315 - entries, err := ParseTreeEntries(Sha1ObjectFormat, []byte("100644 blob ea0d83c9081af9500ac9f804101b3fd0a5c293af")) + entries, err := ParseTreeEntries([]byte("100644 blob ea0d83c9081af9500ac9f804101b3fd0a5c293af")) assert.Error(t, err) assert.Len(t, entries, 0) } diff --git a/modules/git/tree_nogogit.go b/modules/git/tree_nogogit.go index a591485082..e0a72de5b8 100644 --- a/modules/git/tree_nogogit.go +++ b/modules/git/tree_nogogit.go @@ -77,11 +77,8 @@ func (t *Tree) ListEntries() (Entries, error) { return nil, runErr } - objectFormat, err := t.repo.GetObjectFormat() - if err != nil { - return nil, err - } - t.entries, err = parseTreeEntries(objectFormat, stdout, t) + var err error + t.entries, err = parseTreeEntries(stdout, t) if err == nil { t.entriesParsed = true } @@ -104,11 +101,8 @@ func (t *Tree) listEntriesRecursive(extraArgs TrustedCmdArgs) (Entries, error) { return nil, runErr } - objectFormat, err := t.repo.GetObjectFormat() - if err != nil { - return nil, err - } - t.entriesRecursive, err = parseTreeEntries(objectFormat, stdout, t) + var err error + t.entriesRecursive, err = parseTreeEntries(stdout, t) if err == nil { t.entriesRecursiveParsed = true } diff --git a/modules/indexer/code/git.go b/modules/indexer/code/git.go index 2905a540e5..bc345f2325 100644 --- a/modules/indexer/code/git.go +++ b/modules/indexer/code/git.go @@ -62,8 +62,8 @@ func isIndexable(entry *git.TreeEntry) bool { } // parseGitLsTreeOutput parses the output of a `git ls-tree -r --full-name` command -func parseGitLsTreeOutput(objectFormat git.ObjectFormat, stdout []byte) ([]internal.FileUpdate, error) { - entries, err := git.ParseTreeEntries(objectFormat, stdout) +func parseGitLsTreeOutput(stdout []byte) ([]internal.FileUpdate, error) { + entries, err := git.ParseTreeEntries(stdout) if err != nil { return nil, err } @@ -91,10 +91,8 @@ func genesisChanges(ctx context.Context, repo *repo_model.Repository, revision s return nil, runErr } - objectFormat := git.ObjectFormatFromName(repo.ObjectFormatName) - var err error - changes.Updates, err = parseGitLsTreeOutput(objectFormat, stdout) + changes.Updates, err = parseGitLsTreeOutput(stdout) return &changes, err } @@ -172,8 +170,6 @@ func nonGenesisChanges(ctx context.Context, repo *repo_model.Repository, revisio return nil, err } - objectFormat := git.ObjectFormatFromName(repo.ObjectFormatName) - - changes.Updates, err = parseGitLsTreeOutput(objectFormat, lsTreeStdout) + changes.Updates, err = parseGitLsTreeOutput(lsTreeStdout) return &changes, err } diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go index b8b3aeaab0..a89670eeef 100644 --- a/modules/markup/markdown/goldmark.go +++ b/modules/markup/markdown/goldmark.go @@ -65,11 +65,11 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa case *ast.Paragraph: g.applyElementDir(v) case *ast.Image: - g.transformImage(ctx, v, reader) + g.transformImage(ctx, v) case *ast.Link: - g.transformLink(ctx, v, reader) + g.transformLink(ctx, v) case *ast.List: - g.transformList(ctx, v, reader, rc) + g.transformList(ctx, v, rc) case *ast.Text: if v.SoftLineBreak() && !v.HardLineBreak() { if ctx.Metas["mode"] != "document" { diff --git a/modules/markup/markdown/transform_codespan.go b/modules/markup/markdown/transform_codespan.go index 5b07d72999..7aae1757e0 100644 --- a/modules/markup/markdown/transform_codespan.go +++ b/modules/markup/markdown/transform_codespan.go @@ -68,7 +68,7 @@ func cssColorHandler(value string) bool { return css.HSLA.MatchString(value) } -func (g *ASTTransformer) transformCodeSpan(ctx *markup.RenderContext, v *ast.CodeSpan, reader text.Reader) { +func (g *ASTTransformer) transformCodeSpan(_ *markup.RenderContext, v *ast.CodeSpan, reader text.Reader) { colorContent := v.Text(reader.Source()) if cssColorHandler(string(colorContent)) { v.AppendChild(v, NewColorPreview(colorContent)) diff --git a/modules/markup/markdown/transform_heading.go b/modules/markup/markdown/transform_heading.go index ce585a37de..6f38abfad9 100644 --- a/modules/markup/markdown/transform_heading.go +++ b/modules/markup/markdown/transform_heading.go @@ -13,7 +13,7 @@ import ( "github.com/yuin/goldmark/util" ) -func (g *ASTTransformer) transformHeading(ctx *markup.RenderContext, v *ast.Heading, reader text.Reader, tocList *[]markup.Header) { +func (g *ASTTransformer) transformHeading(_ *markup.RenderContext, v *ast.Heading, reader text.Reader, tocList *[]markup.Header) { for _, attr := range v.Attributes() { if _, ok := attr.Value.([]byte); !ok { v.SetAttribute(attr.Name, []byte(fmt.Sprintf("%v", attr.Value))) diff --git a/modules/markup/markdown/transform_image.go b/modules/markup/markdown/transform_image.go index f290dc3721..812e24f0a2 100644 --- a/modules/markup/markdown/transform_image.go +++ b/modules/markup/markdown/transform_image.go @@ -10,10 +10,9 @@ import ( giteautil "code.gitea.io/gitea/modules/util" "github.com/yuin/goldmark/ast" - "github.com/yuin/goldmark/text" ) -func (g *ASTTransformer) transformImage(ctx *markup.RenderContext, v *ast.Image, reader text.Reader) { +func (g *ASTTransformer) transformImage(ctx *markup.RenderContext, v *ast.Image) { // Images need two things: // // 1. Their src needs to munged to be a real value diff --git a/modules/markup/markdown/transform_link.go b/modules/markup/markdown/transform_link.go index 7e305b74bc..527a5dfc44 100644 --- a/modules/markup/markdown/transform_link.go +++ b/modules/markup/markdown/transform_link.go @@ -10,10 +10,9 @@ import ( giteautil "code.gitea.io/gitea/modules/util" "github.com/yuin/goldmark/ast" - "github.com/yuin/goldmark/text" ) -func (g *ASTTransformer) transformLink(ctx *markup.RenderContext, v *ast.Link, reader text.Reader) { +func (g *ASTTransformer) transformLink(ctx *markup.RenderContext, v *ast.Link) { // Links need their href to munged to be a real value link := v.Destination isAnchorFragment := len(link) > 0 && link[0] == '#' diff --git a/modules/markup/markdown/transform_list.go b/modules/markup/markdown/transform_list.go index 6563e2dd64..b982fd4a83 100644 --- a/modules/markup/markdown/transform_list.go +++ b/modules/markup/markdown/transform_list.go @@ -11,7 +11,6 @@ import ( "github.com/yuin/goldmark/ast" east "github.com/yuin/goldmark/extension/ast" "github.com/yuin/goldmark/renderer/html" - "github.com/yuin/goldmark/text" "github.com/yuin/goldmark/util" ) @@ -50,7 +49,7 @@ func (r *HTMLRenderer) renderTaskCheckBox(w util.BufWriter, source []byte, node return ast.WalkContinue, nil } -func (g *ASTTransformer) transformList(ctx *markup.RenderContext, v *ast.List, reader text.Reader, rc *RenderConfig) { +func (g *ASTTransformer) transformList(_ *markup.RenderContext, v *ast.List, rc *RenderConfig) { if v.HasChildren() { children := make([]ast.Node, 0, v.ChildCount()) child := v.FirstChild() diff --git a/modules/markup/mdstripper/mdstripper.go b/modules/markup/mdstripper/mdstripper.go index e19f8f6419..2a69d95224 100644 --- a/modules/markup/mdstripper/mdstripper.go +++ b/modules/markup/mdstripper/mdstripper.go @@ -54,7 +54,7 @@ func (r *stripRenderer) Render(w io.Writer, source []byte, doc ast.Node) error { } return ast.WalkContinue, nil case *ast.Link: - r.processLink(w, v.Destination) + r.processLink(v.Destination) return ast.WalkSkipChildren, nil case *ast.AutoLink: // This could be a reference to an issue or pull - if so convert it @@ -124,7 +124,7 @@ func (r *stripRenderer) processAutoLink(w io.Writer, link []byte) { _, _ = w.Write([]byte(parts[4])) } -func (r *stripRenderer) processLink(w io.Writer, link []byte) { +func (r *stripRenderer) processLink(link []byte) { // Links are processed out of band r.links = append(r.links, string(link)) } diff --git a/modules/optional/option_test.go b/modules/optional/option_test.go index 4f55608004..203e9221e3 100644 --- a/modules/optional/option_test.go +++ b/modules/optional/option_test.go @@ -22,7 +22,7 @@ func TestOption(t *testing.T) { assert.Equal(t, int(0), none.Value()) assert.Equal(t, int(1), none.ValueOrDefault(1)) - some := optional.Some[int](1) + some := optional.Some(1) assert.True(t, some.Has()) assert.Equal(t, int(1), some.Value()) assert.Equal(t, int(1), some.ValueOrDefault(2)) diff --git a/modules/setting/incoming_email.go b/modules/setting/incoming_email.go index 75337a312f..bf81f292a2 100644 --- a/modules/setting/incoming_email.go +++ b/modules/setting/incoming_email.go @@ -38,12 +38,12 @@ func loadIncomingEmailFrom(rootCfg ConfigProvider) { return } - if err := checkReplyToAddress(IncomingEmail.ReplyToAddress); err != nil { + if err := checkReplyToAddress(); err != nil { log.Fatal("Invalid incoming_mail.REPLY_TO_ADDRESS (%s): %v", IncomingEmail.ReplyToAddress, err) } } -func checkReplyToAddress(address string) error { +func checkReplyToAddress() error { parsed, err := mail.ParseAddress(IncomingEmail.ReplyToAddress) if err != nil { return err diff --git a/modules/setting/storage.go b/modules/setting/storage.go index aeb61ac513..0bd52acc0f 100644 --- a/modules/setting/storage.go +++ b/modules/setting/storage.go @@ -97,7 +97,7 @@ func getStorage(rootCfg ConfigProvider, name, typ string, sec ConfigSection) (*S return nil, err } - overrideSec := getStorageOverrideSection(rootCfg, targetSec, sec, tp, name) + overrideSec := getStorageOverrideSection(rootCfg, sec, tp, name) targetType := targetSec.Key("STORAGE_TYPE").String() switch targetType { @@ -189,7 +189,7 @@ func getStorageTargetSection(rootCfg ConfigProvider, name, typ string, sec Confi } // getStorageOverrideSection override section will be read SERVE_DIRECT, PATH, MINIO_BASE_PATH, MINIO_BUCKET to override the targetsec when possible -func getStorageOverrideSection(rootConfig ConfigProvider, targetSec, sec ConfigSection, targetSecType targetSecType, name string) ConfigSection { +func getStorageOverrideSection(rootConfig ConfigProvider, sec ConfigSection, targetSecType targetSecType, name string) ConfigSection { if targetSecType == targetSecIsSec { return nil } diff --git a/routers/api/v1/admin/user_badge.go b/routers/api/v1/admin/user_badge.go index bacd1f809b..99e20877fd 100644 --- a/routers/api/v1/admin/user_badge.go +++ b/routers/api/v1/admin/user_badge.go @@ -67,7 +67,7 @@ func AddUserBadges(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" form := web.GetForm(ctx).(*api.UserBadgeOption) - badges := prepareBadgesForReplaceOrAdd(ctx, *form) + badges := prepareBadgesForReplaceOrAdd(*form) if err := user_model.AddUserBadges(ctx, ctx.ContextUser, badges); err != nil { ctx.Error(http.StatusInternalServerError, "ReplaceUserBadges", err) @@ -103,7 +103,7 @@ func DeleteUserBadges(ctx *context.APIContext) { // "$ref": "#/responses/validationError" form := web.GetForm(ctx).(*api.UserBadgeOption) - badges := prepareBadgesForReplaceOrAdd(ctx, *form) + badges := prepareBadgesForReplaceOrAdd(*form) if err := user_model.RemoveUserBadges(ctx, ctx.ContextUser, badges); err != nil { ctx.Error(http.StatusInternalServerError, "ReplaceUserBadges", err) @@ -113,7 +113,7 @@ func DeleteUserBadges(ctx *context.APIContext) { ctx.Status(http.StatusNoContent) } -func prepareBadgesForReplaceOrAdd(ctx *context.APIContext, form api.UserBadgeOption) []*user_model.Badge { +func prepareBadgesForReplaceOrAdd(form api.UserBadgeOption) []*user_model.Badge { badges := make([]*user_model.Badge, len(form.BadgeSlugs)) for i, badge := range form.BadgeSlugs { badges[i] = &user_model.Badge{ diff --git a/routers/api/v1/repo/migrate.go b/routers/api/v1/repo/migrate.go index 2caaa130e8..f246b08c0a 100644 --- a/routers/api/v1/repo/migrate.go +++ b/routers/api/v1/repo/migrate.go @@ -180,7 +180,7 @@ func Migrate(ctx *context.APIContext) { Status: repo_model.RepositoryBeingMigrated, }) if err != nil { - handleMigrateError(ctx, repoOwner, remoteAddr, err) + handleMigrateError(ctx, repoOwner, err) return } @@ -207,7 +207,7 @@ func Migrate(ctx *context.APIContext) { }() if repo, err = migrations.MigrateRepository(graceful.GetManager().HammerContext(), ctx.Doer, repoOwner.Name, opts, nil); err != nil { - handleMigrateError(ctx, repoOwner, remoteAddr, err) + handleMigrateError(ctx, repoOwner, err) return } @@ -215,7 +215,7 @@ func Migrate(ctx *context.APIContext) { ctx.JSON(http.StatusCreated, convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeAdmin})) } -func handleMigrateError(ctx *context.APIContext, repoOwner *user_model.User, remoteAddr string, err error) { +func handleMigrateError(ctx *context.APIContext, repoOwner *user_model.User, err error) { switch { case repo_model.IsErrRepoAlreadyExist(err): ctx.Error(http.StatusConflict, "", "The repository with the same name already exists.") diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go index f35eb77d42..7189fd715c 100644 --- a/routers/private/hook_pre_receive.go +++ b/routers/private/hook_pre_receive.go @@ -121,9 +121,9 @@ func HookPreReceive(ctx *gitea_context.PrivateContext) { case refFullName.IsBranch(): preReceiveBranch(ourCtx, oldCommitID, newCommitID, refFullName) case refFullName.IsTag(): - preReceiveTag(ourCtx, oldCommitID, newCommitID, refFullName) + preReceiveTag(ourCtx, refFullName) case git.DefaultFeatures.SupportProcReceive && refFullName.IsFor(): - preReceiveFor(ourCtx, oldCommitID, newCommitID, refFullName) + preReceiveFor(ourCtx, refFullName) default: ourCtx.AssertCanWriteCode() } @@ -368,7 +368,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r } } -func preReceiveTag(ctx *preReceiveContext, oldCommitID, newCommitID string, refFullName git.RefName) { +func preReceiveTag(ctx *preReceiveContext, refFullName git.RefName) { if !ctx.AssertCanWriteCode() { return } @@ -404,7 +404,7 @@ func preReceiveTag(ctx *preReceiveContext, oldCommitID, newCommitID string, refF } } -func preReceiveFor(ctx *preReceiveContext, oldCommitID, newCommitID string, refFullName git.RefName) { +func preReceiveFor(ctx *preReceiveContext, refFullName git.RefName) { if !ctx.AssertCreatePullRequest() { return } diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go index e6585d8833..3dd3c9670f 100644 --- a/routers/web/admin/admin.go +++ b/routers/web/admin/admin.go @@ -159,7 +159,7 @@ func DashboardPost(ctx *context.Context) { switch form.Op { case "sync_repo_branches": go func() { - if err := repo_service.AddAllRepoBranchesToSyncQueue(graceful.GetManager().ShutdownContext(), ctx.Doer.ID); err != nil { + if err := repo_service.AddAllRepoBranchesToSyncQueue(graceful.GetManager().ShutdownContext()); err != nil { log.Error("AddAllRepoBranchesToSyncQueue: %v: %v", ctx.Doer.ID, err) } }() diff --git a/routers/web/feed/convert.go b/routers/web/feed/convert.go index 3defa436a7..20fcda6664 100644 --- a/routers/web/feed/convert.go +++ b/routers/web/feed/convert.go @@ -279,7 +279,7 @@ func GetFeedType(name string, req *http.Request) (bool, string, string) { } // feedActionsToFeedItems convert gitea's Repo's Releases to feeds Item -func releasesToFeedItems(ctx *context.Context, releases []*repo_model.Release, isReleasesOnly bool) (items []*feeds.Item, err error) { +func releasesToFeedItems(ctx *context.Context, releases []*repo_model.Release) (items []*feeds.Item, err error) { for _, rel := range releases { err := rel.LoadAttributes(ctx) if err != nil { diff --git a/routers/web/feed/release.go b/routers/web/feed/release.go index 273f47e3b4..fb6e3add65 100644 --- a/routers/web/feed/release.go +++ b/routers/web/feed/release.go @@ -42,7 +42,7 @@ func ShowReleaseFeed(ctx *context.Context, repo *repo_model.Repository, isReleas Created: time.Now(), } - feed.Items, err = releasesToFeedItems(ctx, releases, isReleasesOnly) + feed.Items, err = releasesToFeedItems(ctx, releases) if err != nil { ctx.ServerError("releasesToFeedItems", err) return diff --git a/services/context/repo.go b/services/context/repo.go index 4836c1456c..d9a3feaf27 100644 --- a/services/context/repo.go +++ b/services/context/repo.go @@ -787,7 +787,7 @@ func (rt RepoRefType) RefTypeIncludesTags() bool { return false } -func getRefNameFromPath(ctx *Base, repo *Repository, path string, isExist func(string) bool) string { +func getRefNameFromPath(repo *Repository, path string, isExist func(string) bool) string { refName := "" parts := strings.Split(path, "/") for i, part := range parts { @@ -823,7 +823,7 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string { repo.TreePath = path return repo.Repository.DefaultBranch case RepoRefBranch: - ref := getRefNameFromPath(ctx, repo, path, repo.GitRepo.IsBranchExist) + ref := getRefNameFromPath(repo, path, repo.GitRepo.IsBranchExist) if len(ref) == 0 { // check if ref is HEAD parts := strings.Split(path, "/") @@ -833,7 +833,7 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string { } // maybe it's a renamed branch - return getRefNameFromPath(ctx, repo, path, func(s string) bool { + return getRefNameFromPath(repo, path, func(s string) bool { b, exist, err := git_model.FindRenamedBranch(ctx, repo.Repository.ID, s) if err != nil { log.Error("FindRenamedBranch: %v", err) @@ -853,7 +853,7 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string { return ref case RepoRefTag: - return getRefNameFromPath(ctx, repo, path, repo.GitRepo.IsTagExist) + return getRefNameFromPath(repo, path, repo.GitRepo.IsTagExist) case RepoRefCommit: parts := strings.Split(path, "/") diff --git a/services/doctor/storage.go b/services/doctor/storage.go index 787df27549..3f3b562c37 100644 --- a/services/doctor/storage.go +++ b/services/doctor/storage.go @@ -27,7 +27,7 @@ type commonStorageCheckOptions struct { name string } -func commonCheckStorage(ctx context.Context, logger log.Logger, autofix bool, opts *commonStorageCheckOptions) error { +func commonCheckStorage(logger log.Logger, autofix bool, opts *commonStorageCheckOptions) error { totalCount, orphanedCount := 0, 0 totalSize, orphanedSize := int64(0), int64(0) @@ -98,7 +98,7 @@ func checkStorage(opts *checkStorageOptions) func(ctx context.Context, logger lo } if opts.Attachments || opts.All { - if err := commonCheckStorage(ctx, logger, autofix, + if err := commonCheckStorage(logger, autofix, &commonStorageCheckOptions{ storer: storage.Attachments, isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) { @@ -116,7 +116,7 @@ func checkStorage(opts *checkStorageOptions) func(ctx context.Context, logger lo logger.Info("LFS isn't enabled (skipped)") return nil } - if err := commonCheckStorage(ctx, logger, autofix, + if err := commonCheckStorage(logger, autofix, &commonStorageCheckOptions{ storer: storage.LFS, isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) { @@ -132,7 +132,7 @@ func checkStorage(opts *checkStorageOptions) func(ctx context.Context, logger lo } if opts.Avatars || opts.All { - if err := commonCheckStorage(ctx, logger, autofix, + if err := commonCheckStorage(logger, autofix, &commonStorageCheckOptions{ storer: storage.Avatars, isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) { @@ -146,7 +146,7 @@ func checkStorage(opts *checkStorageOptions) func(ctx context.Context, logger lo } if opts.RepoAvatars || opts.All { - if err := commonCheckStorage(ctx, logger, autofix, + if err := commonCheckStorage(logger, autofix, &commonStorageCheckOptions{ storer: storage.RepoAvatars, isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) { @@ -160,7 +160,7 @@ func checkStorage(opts *checkStorageOptions) func(ctx context.Context, logger lo } if opts.RepoArchives || opts.All { - if err := commonCheckStorage(ctx, logger, autofix, + if err := commonCheckStorage(logger, autofix, &commonStorageCheckOptions{ storer: storage.RepoArchives, isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) { @@ -182,7 +182,7 @@ func checkStorage(opts *checkStorageOptions) func(ctx context.Context, logger lo logger.Info("Packages isn't enabled (skipped)") return nil } - if err := commonCheckStorage(ctx, logger, autofix, + if err := commonCheckStorage(logger, autofix, &commonStorageCheckOptions{ storer: storage.Packages, isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) { diff --git a/services/migrations/gitea_uploader.go b/services/migrations/gitea_uploader.go index 87691bf729..c63383f5ca 100644 --- a/services/migrations/gitea_uploader.go +++ b/services/migrations/gitea_uploader.go @@ -977,25 +977,24 @@ func (g *GiteaLocalUploader) Finish() error { } func (g *GiteaLocalUploader) remapUser(source user_model.ExternalUserMigrated, target user_model.ExternalUserRemappable) error { - var userid int64 + var userID int64 var err error if g.sameApp { - userid, err = g.remapLocalUser(source, target) + userID, err = g.remapLocalUser(source) } else { - userid, err = g.remapExternalUser(source, target) + userID, err = g.remapExternalUser(source) } - if err != nil { return err } - if userid > 0 { - return target.RemapExternalUser("", 0, userid) + if userID > 0 { + return target.RemapExternalUser("", 0, userID) } return target.RemapExternalUser(source.GetExternalName(), source.GetExternalID(), g.doer.ID) } -func (g *GiteaLocalUploader) remapLocalUser(source user_model.ExternalUserMigrated, target user_model.ExternalUserRemappable) (int64, error) { +func (g *GiteaLocalUploader) remapLocalUser(source user_model.ExternalUserMigrated) (int64, error) { userid, ok := g.userMap[source.GetExternalID()] if !ok { name, err := user_model.GetUserNameByID(g.ctx, source.GetExternalID()) @@ -1013,7 +1012,7 @@ func (g *GiteaLocalUploader) remapLocalUser(source user_model.ExternalUserMigrat return userid, nil } -func (g *GiteaLocalUploader) remapExternalUser(source user_model.ExternalUserMigrated, target user_model.ExternalUserRemappable) (userid int64, err error) { +func (g *GiteaLocalUploader) remapExternalUser(source user_model.ExternalUserMigrated) (userid int64, err error) { userid, ok := g.userMap[source.GetExternalID()] if !ok { userid, err = user_model.GetUserIDByExternalUserID(g.ctx, g.gitServiceType.Name(), fmt.Sprintf("%d", source.GetExternalID())) diff --git a/services/mirror/mirror.go b/services/mirror/mirror.go index 0270f87039..44218d6fb3 100644 --- a/services/mirror/mirror.go +++ b/services/mirror/mirror.go @@ -90,7 +90,7 @@ func Update(ctx context.Context, pullLimit, pushLimit int) error { pullMirrorsRequested := 0 if pullLimit != 0 { - if err := repo_model.MirrorsIterate(ctx, pullLimit, func(idx int, bean any) error { + if err := repo_model.MirrorsIterate(ctx, pullLimit, func(_ int, bean any) error { if err := handler(bean); err != nil { return err } diff --git a/services/pull/review.go b/services/pull/review.go index e303cd9a9d..3d5eca779f 100644 --- a/services/pull/review.go +++ b/services/pull/review.go @@ -49,7 +49,7 @@ var ErrSubmitReviewOnClosedPR = errors.New("can't submit review for a closed or // checkInvalidation checks if the line of code comment got changed by another commit. // If the line got changed the comment is going to be invalidated. -func checkInvalidation(ctx context.Context, c *issues_model.Comment, doer *user_model.User, repo *git.Repository, branch string) error { +func checkInvalidation(ctx context.Context, c *issues_model.Comment, repo *git.Repository, branch string) error { // FIXME differentiate between previous and proposed line commit, err := repo.LineBlame(branch, repo.Path, c.TreePath, uint(c.UnsignedLine())) if err != nil && (strings.Contains(err.Error(), "fatal: no such path") || notEnoughLines.MatchString(err.Error())) { @@ -83,7 +83,7 @@ func InvalidateCodeComments(ctx context.Context, prs issues_model.PullRequestLis return fmt.Errorf("find code comments: %v", err) } for _, comment := range codeComments { - if err := checkInvalidation(ctx, comment, doer, repo, branch); err != nil { + if err := checkInvalidation(ctx, comment, repo, branch); err != nil { return err } } diff --git a/services/pull/update.go b/services/pull/update.go index bc8c4a25e5..9b676e13ef 100644 --- a/services/pull/update.go +++ b/services/pull/update.go @@ -39,7 +39,7 @@ func Update(ctx context.Context, pr *issues_model.PullRequest, doer *user_model. go AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false, "", "") }() - return updateHeadByRebaseOnToBase(ctx, pr, doer, message) + return updateHeadByRebaseOnToBase(ctx, pr, doer) } if err := pr.LoadBaseRepo(ctx); err != nil { diff --git a/services/pull/update_rebase.go b/services/pull/update_rebase.go index 8e7bfa0ffd..3e2a7be132 100644 --- a/services/pull/update_rebase.go +++ b/services/pull/update_rebase.go @@ -18,7 +18,7 @@ import ( ) // updateHeadByRebaseOnToBase handles updating a PR's head branch by rebasing it on the PR current base branch -func updateHeadByRebaseOnToBase(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User, message string) error { +func updateHeadByRebaseOnToBase(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User) error { // "Clone" base repo and add the cache headers for the head repo and branch mergeCtx, cancel, err := createTemporaryRepoForMerge(ctx, pr, doer, "") if err != nil { diff --git a/services/repository/adopt.go b/services/repository/adopt.go index 31e3e581b3..914cd9047b 100644 --- a/services/repository/adopt.go +++ b/services/repository/adopt.go @@ -80,7 +80,7 @@ func AdoptRepository(ctx context.Context, doer, u *user_model.User, opts CreateR return fmt.Errorf("getRepositoryByID: %w", err) } - if err := adoptRepository(ctx, repoPath, doer, repo, opts.DefaultBranch); err != nil { + if err := adoptRepository(ctx, repoPath, repo, opts.DefaultBranch); err != nil { return fmt.Errorf("createDelegateHooks: %w", err) } @@ -111,7 +111,7 @@ func AdoptRepository(ctx context.Context, doer, u *user_model.User, opts CreateR return repo, nil } -func adoptRepository(ctx context.Context, repoPath string, u *user_model.User, repo *repo_model.Repository, defaultBranch string) (err error) { +func adoptRepository(ctx context.Context, repoPath string, repo *repo_model.Repository, defaultBranch string) (err error) { isExist, err := util.IsExist(repoPath) if err != nil { log.Error("Unable to check if %s exists. Error: %v", repoPath, err) diff --git a/services/repository/branch.go b/services/repository/branch.go index d74e5819a1..e1d036a97c 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -527,7 +527,7 @@ func handlerBranchSync(items ...*BranchSyncOptions) []*BranchSyncOptions { return nil } -func addRepoToBranchSyncQueue(repoID, doerID int64) error { +func addRepoToBranchSyncQueue(repoID int64) error { return branchSyncQueue.Push(&BranchSyncOptions{ RepoID: repoID, }) @@ -543,9 +543,9 @@ func initBranchSyncQueue(ctx context.Context) error { return nil } -func AddAllRepoBranchesToSyncQueue(ctx context.Context, doerID int64) error { +func AddAllRepoBranchesToSyncQueue(ctx context.Context) error { if err := db.Iterate(ctx, builder.Eq{"is_empty": false}, func(ctx context.Context, repo *repo_model.Repository) error { - return addRepoToBranchSyncQueue(repo.ID, doerID) + return addRepoToBranchSyncQueue(repo.ID) }); err != nil { return fmt.Errorf("run sync all branches failed: %v", err) } diff --git a/services/repository/files/update.go b/services/repository/files/update.go index d0e3075eae..b1b64bacd9 100644 --- a/services/repository/files/update.go +++ b/services/repository/files/update.go @@ -211,7 +211,7 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use } for _, file := range opts.Files { - if err := handleCheckErrors(file, commit, opts, repo); err != nil { + if err := handleCheckErrors(file, commit, opts); err != nil { return nil, err } } @@ -277,7 +277,7 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use } // handles the check for various issues for ChangeRepoFiles -func handleCheckErrors(file *ChangeRepoFile, commit *git.Commit, opts *ChangeRepoFilesOptions, repo *repo_model.Repository) error { +func handleCheckErrors(file *ChangeRepoFile, commit *git.Commit, opts *ChangeRepoFilesOptions) error { if file.Operation == "update" || file.Operation == "delete" { fromEntry, err := commit.GetTreeEntryByPath(file.Options.fromTreePath) if err != nil { diff --git a/services/user/update_test.go b/services/user/update_test.go index c2ff26a140..fc24a6c212 100644 --- a/services/user/update_test.go +++ b/services/user/update_test.go @@ -35,7 +35,7 @@ func TestUpdateUser(t *testing.T) { Description: optional.Some("description"), AllowGitHook: optional.Some(true), AllowImportLocal: optional.Some(true), - MaxRepoCreation: optional.Some[int](10), + MaxRepoCreation: optional.Some(10), IsRestricted: optional.Some(true), IsActive: optional.Some(false), IsAdmin: optional.Some(true), diff --git a/tests/integration/api_packages_chef_test.go b/tests/integration/api_packages_chef_test.go index 05545f11a6..6efb2708af 100644 --- a/tests/integration/api_packages_chef_test.go +++ b/tests/integration/api_packages_chef_test.go @@ -169,7 +169,7 @@ nwIDAQAB assert.Nil(t, u) assert.Error(t, err) - signRequest := func(t *testing.T, rw *RequestWrapper, version string) { + signRequest := func(rw *RequestWrapper, version string) { req := rw.Request username := req.Header.Get("X-Ops-Userid") if version != "1.0" && version != "1.3" { @@ -255,7 +255,7 @@ nwIDAQAB t.Run(v, func(t *testing.T) { defer tests.PrintCurrentTest(t)() - signRequest(t, req, v) + signRequest(req, v) u, err = auth.Verify(req.Request, nil, nil, nil) assert.NotNil(t, u) assert.NoError(t, err) diff --git a/tests/integration/api_releases_test.go b/tests/integration/api_releases_test.go index 49aa4c4e1b..73b371b2cb 100644 --- a/tests/integration/api_releases_test.go +++ b/tests/integration/api_releases_test.go @@ -77,7 +77,7 @@ func TestAPIListReleases(t *testing.T) { testFilterByLen(true, url.Values{"draft": {"true"}, "pre-release": {"true"}}, 0, "there is no pre-release draft") } -func createNewReleaseUsingAPI(t *testing.T, session *TestSession, token string, owner *user_model.User, repo *repo_model.Repository, name, target, title, desc string) *api.Release { +func createNewReleaseUsingAPI(t *testing.T, token string, owner *user_model.User, repo *repo_model.Repository, name, target, title, desc string) *api.Release { urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases", owner.Name, repo.Name) req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateReleaseOption{ TagName: name, @@ -120,7 +120,7 @@ func TestAPICreateAndUpdateRelease(t *testing.T) { target, err := gitRepo.GetTagCommitID("v0.0.1") assert.NoError(t, err) - newRelease := createNewReleaseUsingAPI(t, session, token, owner, repo, "v0.0.1", target, "v0.0.1", "test") + newRelease := createNewReleaseUsingAPI(t, token, owner, repo, "v0.0.1", target, "v0.0.1", "test") urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases/%d", owner.Name, repo.Name, newRelease.ID) req := NewRequest(t, "GET", urlStr). @@ -162,7 +162,7 @@ func TestAPICreateReleaseToDefaultBranch(t *testing.T) { session := loginUser(t, owner.LowerName) token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) - createNewReleaseUsingAPI(t, session, token, owner, repo, "v0.0.1", "", "v0.0.1", "test") + createNewReleaseUsingAPI(t, token, owner, repo, "v0.0.1", "", "v0.0.1", "test") } func TestAPICreateReleaseToDefaultBranchOnExistingTag(t *testing.T) { @@ -180,7 +180,7 @@ func TestAPICreateReleaseToDefaultBranchOnExistingTag(t *testing.T) { err = gitRepo.CreateTag("v0.0.1", "master") assert.NoError(t, err) - createNewReleaseUsingAPI(t, session, token, owner, repo, "v0.0.1", "", "v0.0.1", "test") + createNewReleaseUsingAPI(t, token, owner, repo, "v0.0.1", "", "v0.0.1", "test") } func TestAPIGetLatestRelease(t *testing.T) { @@ -232,7 +232,7 @@ func TestAPIDeleteReleaseByTagName(t *testing.T) { session := loginUser(t, owner.LowerName) token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) - createNewReleaseUsingAPI(t, session, token, owner, repo, "release-tag", "", "Release Tag", "test") + createNewReleaseUsingAPI(t, token, owner, repo, "release-tag", "", "Release Tag", "test") // delete release req := NewRequestf(t, http.MethodDelete, fmt.Sprintf("/api/v1/repos/%s/%s/releases/tags/release-tag", owner.Name, repo.Name)). @@ -258,7 +258,7 @@ func TestAPIUploadAssetRelease(t *testing.T) { session := loginUser(t, owner.LowerName) token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) - r := createNewReleaseUsingAPI(t, session, token, owner, repo, "release-tag", "", "Release Tag", "test") + r := createNewReleaseUsingAPI(t, token, owner, repo, "release-tag", "", "Release Tag", "test") filename := "image.png" buff := generateImg() diff --git a/tests/integration/api_repo_git_tags_test.go b/tests/integration/api_repo_git_tags_test.go index 937f6a829c..c5883a8058 100644 --- a/tests/integration/api_repo_git_tags_test.go +++ b/tests/integration/api_repo_git_tags_test.go @@ -80,7 +80,7 @@ func TestAPIDeleteTagByName(t *testing.T) { _ = MakeRequest(t, req, http.StatusNoContent) // Make sure that actual releases can't be deleted outright - createNewReleaseUsingAPI(t, session, token, owner, repo, "release-tag", "", "Release Tag", "test") + createNewReleaseUsingAPI(t, token, owner, repo, "release-tag", "", "Release Tag", "test") req = NewRequest(t, http.MethodDelete, fmt.Sprintf("/api/v1/repos/%s/%s/tags/release-tag", owner.Name, repo.Name)). AddTokenAuth(token) diff --git a/tests/integration/repo_search_test.go b/tests/integration/repo_search_test.go index 56cc45d901..29d1517f4e 100644 --- a/tests/integration/repo_search_test.go +++ b/tests/integration/repo_search_test.go @@ -17,7 +17,7 @@ import ( "github.com/stretchr/testify/assert" ) -func resultFilenames(t testing.TB, doc *HTMLDoc) []string { +func resultFilenames(doc *HTMLDoc) []string { filenameSelections := doc.doc.Find(".repository.search").Find(".repo-search-result").Find(".header").Find("span.file") result := make([]string, filenameSelections.Length()) filenameSelections.Each(func(i int, selection *goquery.Selection) { @@ -56,6 +56,6 @@ func testSearch(t *testing.T, url string, expected []string) { req := NewRequest(t, "GET", url) resp := MakeRequest(t, req, http.StatusOK) - filenames := resultFilenames(t, NewHTMLParser(t, resp.Body)) + filenames := resultFilenames(NewHTMLParser(t, resp.Body)) assert.EqualValues(t, expected, filenames) } diff --git a/tests/integration/repofiles_change_test.go b/tests/integration/repofiles_change_test.go index 49abeb83fb..7633d6915f 100644 --- a/tests/integration/repofiles_change_test.go +++ b/tests/integration/repofiles_change_test.go @@ -78,7 +78,7 @@ func getDeleteRepoFilesOptions(repo *repo_model.Repository) *files_service.Chang } } -func getExpectedFileResponseForRepofilesDelete(u *url.URL) *api.FileResponse { +func getExpectedFileResponseForRepofilesDelete() *api.FileResponse { // Just returns fields that don't change, i.e. fields with commit SHAs and dates can't be determined return &api.FileResponse{ Content: nil, @@ -418,7 +418,7 @@ func testDeleteRepoFiles(t *testing.T, u *url.URL) { t.Run("Delete README.md file", func(t *testing.T) { filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts) assert.NoError(t, err) - expectedFileResponse := getExpectedFileResponseForRepofilesDelete(u) + expectedFileResponse := getExpectedFileResponseForRepofilesDelete() assert.NotNil(t, filesResponse) assert.Nil(t, filesResponse.Files[0]) assert.EqualValues(t, expectedFileResponse.Commit.Message, filesResponse.Commit.Message) @@ -460,7 +460,7 @@ func testDeleteRepoFilesWithoutBranchNames(t *testing.T, u *url.URL) { t.Run("Delete README.md without Branch Name", func(t *testing.T) { filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts) assert.NoError(t, err) - expectedFileResponse := getExpectedFileResponseForRepofilesDelete(u) + expectedFileResponse := getExpectedFileResponseForRepofilesDelete() assert.NotNil(t, filesResponse) assert.Nil(t, filesResponse.Files[0]) assert.EqualValues(t, expectedFileResponse.Commit.Message, filesResponse.Commit.Message) From a21ca9b5a5e85d2734bd4cd9e308800eda41a524 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Mon, 29 Apr 2024 16:49:50 +0200 Subject: [PATCH 237/370] Remove fomantic dimmer module (#30723) Tested extensively using modal which is the only dependant. --- web_src/css/base.css | 4 - web_src/css/index.css | 1 + web_src/css/modules/dimmer.css | 30 + web_src/fomantic/build/semantic.css | 357 ------------ web_src/fomantic/build/semantic.js | 754 -------------------------- web_src/fomantic/semantic.json | 1 - web_src/js/modules/fomantic.js | 2 + web_src/js/modules/fomantic/dimmer.js | 29 + 8 files changed, 62 insertions(+), 1116 deletions(-) create mode 100644 web_src/css/modules/dimmer.css create mode 100644 web_src/js/modules/fomantic/dimmer.js diff --git a/web_src/css/base.css b/web_src/css/base.css index 58a5723cb5..df9028b50a 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -680,10 +680,6 @@ input:-webkit-autofill:active, box-shadow: 0 6px 18px var(--color-shadow) !important; } -.ui.dimmer { - background: var(--color-overlay-backdrop); -} - .ui.dropdown .menu > .header { font-size: 0.8em; } diff --git a/web_src/css/index.css b/web_src/css/index.css index edd6cdca8b..817f6997da 100644 --- a/web_src/css/index.css +++ b/web_src/css/index.css @@ -16,6 +16,7 @@ @import "./modules/table.css"; @import "./modules/card.css"; @import "./modules/checkbox.css"; +@import "./modules/dimmer.css"; @import "./modules/modal.css"; @import "./modules/select.css"; diff --git a/web_src/css/modules/dimmer.css b/web_src/css/modules/dimmer.css new file mode 100644 index 0000000000..a552d103e5 --- /dev/null +++ b/web_src/css/modules/dimmer.css @@ -0,0 +1,30 @@ +/* These are the remnants of the fomantic dimmer module */ + +.ui.dimmer { + position: fixed; + display: none; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: var(--color-overlay-backdrop); + opacity: 0; + z-index: 1000; + overflow-y: auto; + justify-content: center; + padding: 8px 0; + animation-name: fadein; + animation-duration: .2s; + user-select: none; +} + +.ui.active.dimmer { + display: flex; + opacity: 1; +} + +.ui.dimmer > * { + position: static; + margin-top: auto !important; + margin-bottom: auto !important; +} diff --git a/web_src/fomantic/build/semantic.css b/web_src/fomantic/build/semantic.css index 7c404bdb30..aef7a6bdbe 100644 --- a/web_src/fomantic/build/semantic.css +++ b/web_src/fomantic/build/semantic.css @@ -8,363 +8,6 @@ * http://opensource.org/licenses/MIT * */ -/*! - * # Fomantic-UI - Dimmer - * http://github.com/fomantic/Fomantic-UI/ - * - * - * Released under the MIT license - * http://opensource.org/licenses/MIT - * - */ - -/******************************* - Dimmer -*******************************/ - -.dimmable:not(body) { - position: relative; -} - -.ui.dimmer { - display: none; - position: absolute; - top: 0 !important; - left: 0 !important; - width: 100%; - height: 100%; - text-align: center; - vertical-align: middle; - padding: 1em; - background: rgba(0, 0, 0, 0.85); - opacity: 0; - line-height: 1; - animation-fill-mode: both; - animation-duration: 0.5s; - transition: background-color 0.5s linear; - flex-direction: column; - align-items: center; - justify-content: center; - -webkit-user-select: none; - -moz-user-select: none; - user-select: none; - will-change: opacity; - z-index: 1000; -} - -/* Dimmer Content */ - -.ui.dimmer > .content { - -webkit-user-select: text; - -moz-user-select: text; - user-select: text; - color: #FFFFFF; -} - -/* Loose Coupling */ - -.ui.segment > .ui.dimmer:not(.page) { - border-radius: inherit; -} - -/* Scrollbars */ - -/******************************* - States -*******************************/ - -/* Animating */ - -.animating.dimmable:not(body), -.dimmed.dimmable:not(body) { - overflow: hidden; -} - -/* Animating / Active / Visible */ - -.dimmed.dimmable > .ui.animating.dimmer, -.dimmed.dimmable > .ui.visible.dimmer, -.ui.active.dimmer { - display: flex; - opacity: 1; -} - -/* Disabled */ - -.ui.disabled.dimmer { - width: 0 !important; - height: 0 !important; -} - -/******************************* - Variations -*******************************/ - -/*-------------- - Legacy - ---------------*/ - -/* Animating / Active / Visible */ - -.dimmed.dimmable > .ui.animating.legacy.dimmer, -.dimmed.dimmable > .ui.visible.legacy.dimmer, -.ui.active.legacy.dimmer { - display: block; -} - -/*-------------- - Alignment - ---------------*/ - -.ui[class*="top aligned"].dimmer { - justify-content: flex-start; -} - -.ui[class*="bottom aligned"].dimmer { - justify-content: flex-end; -} - -/*-------------- - Page - ---------------*/ - -.ui.page.dimmer { - position: fixed; - transform-style: ''; - perspective: 2000px; - transform-origin: center center; -} - -.ui.page.dimmer.modals { - -moz-perspective: none; -} - -body.animating.in.dimmable, -body.dimmed.dimmable { - overflow: hidden; -} - -body.dimmable > .dimmer { - position: fixed; -} - -/*-------------- - Blurring - ---------------*/ - -.blurring.dimmable > :not(.dimmer) { - filter: initial; - transition: 800ms filter ease; -} - -.blurring.dimmed.dimmable > :not(.dimmer):not(.popup) { - filter: blur(5px) grayscale(0.7); -} - -/* Dimmer Color */ - -.blurring.dimmable > .dimmer { - background: rgba(0, 0, 0, 0.6); -} - -.blurring.dimmable > .inverted.dimmer { - background: rgba(255, 255, 255, 0.6); -} - -/*-------------- - Aligned - ---------------*/ - -.ui.dimmer > .top.aligned.content > * { - vertical-align: top; -} - -.ui.dimmer > .bottom.aligned.content > * { - vertical-align: bottom; -} - -/*-------------- - Shades - ---------------*/ - -.medium.medium.medium.medium.medium.dimmer { - background: rgba(0, 0, 0, 0.65); -} - -.light.light.light.light.light.dimmer { - background: rgba(0, 0, 0, 0.45); -} - -.very.light.light.light.light.dimmer { - background: rgba(0, 0, 0, 0.25); -} - -/*-------------- - Simple - ---------------*/ - -/* Displays without javascript */ - -.ui.simple.dimmer { - display: block; - overflow: hidden; - opacity: 0; - width: 0; - height: 0; - z-index: -100; - background: rgba(0, 0, 0, 0); -} - -.dimmed.dimmable > .ui.simple.dimmer { - overflow: visible; - opacity: 1; - width: 100%; - height: 100%; - background: rgba(0, 0, 0, 0.85); - z-index: 1; -} - -.ui.simple.inverted.dimmer { - background: rgba(255, 255, 255, 0); -} - -.dimmed.dimmable > .ui.simple.inverted.dimmer { - background: rgba(255, 255, 255, 0.85); -} - -/*-------------- - Partially - ----------------*/ - -.ui[class*="top dimmer"], -.ui[class*="center dimmer"], -.ui[class*="bottom dimmer"] { - height: auto; -} - -.ui[class*="bottom dimmer"] { - top: auto !important; - bottom: 0; -} - -.ui[class*="center dimmer"] { - top: 50% !important; - transform: translateY(-50%); - -webkit-transform: translateY(calc(-50% - 0.5px)); -} - -.ui.segment > .ui.ui[class*="top dimmer"] { - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; -} - -.ui.segment > .ui.ui[class*="center dimmer"] { - border-radius: 0; -} - -.ui.segment > .ui.ui[class*="bottom dimmer"] { - border-top-left-radius: 0; - border-top-right-radius: 0; -} - -.ui[class*="center dimmer"].transition[class*="fade up"].in { - animation-name: fadeInUpCenter; -} - -.ui[class*="center dimmer"].transition[class*="fade down"].in { - animation-name: fadeInDownCenter; -} - -.ui[class*="center dimmer"].transition[class*="fade up"].out { - animation-name: fadeOutUpCenter; -} - -.ui[class*="center dimmer"].transition[class*="fade down"].out { - animation-name: fadeOutDownCenter; -} - -.ui[class*="center dimmer"].bounce.transition { - animation-name: bounceCenter; -} - -@keyframes fadeInUpCenter { - 0% { - opacity: 0; - transform: translateY(-40%); - -webkit-transform: translateY(calc(-40% - 0.5px)); - } - - 100% { - opacity: 1; - transform: translateY(-50%); - -webkit-transform: translateY(calc(-50% - 0.5px)); - } -} - -@keyframes fadeInDownCenter { - 0% { - opacity: 0; - transform: translateY(-60%); - -webkit-transform: translateY(calc(-60% - 0.5px)); - } - - 100% { - opacity: 1; - transform: translateY(-50%); - -webkit-transform: translateY(calc(-50% - 0.5px)); - } -} - -@keyframes fadeOutUpCenter { - 0% { - opacity: 1; - transform: translateY(-50%); - -webkit-transform: translateY(calc(-50% - 0.5px)); - } - - 100% { - opacity: 0; - transform: translateY(-45%); - -webkit-transform: translateY(calc(-45% - 0.5px)); - } -} - -@keyframes fadeOutDownCenter { - 0% { - opacity: 1; - transform: translateY(-50%); - -webkit-transform: translateY(calc(-50% - 0.5px)); - } - - 100% { - opacity: 0; - transform: translateY(-55%); - -webkit-transform: translateY(calc(-55% - 0.5px)); - } -} - -@keyframes bounceCenter { - 0%, 20%, 50%, 80%, 100% { - transform: translateY(-50%); - -webkit-transform: translateY(calc(-50% - 0.5px)); - } - - 40% { - transform: translateY(calc(-50% - 30px)); - } - - 60% { - transform: translateY(calc(-50% - 15px)); - } -} - -/******************************* - Theme Overrides -*******************************/ - -/******************************* - User Overrides -*******************************/ /*! * # Fomantic-UI - Dropdown * http://github.com/fomantic/Fomantic-UI/ diff --git a/web_src/fomantic/build/semantic.js b/web_src/fomantic/build/semantic.js index c150c8d9db..1297216a31 100644 --- a/web_src/fomantic/build/semantic.js +++ b/web_src/fomantic/build/semantic.js @@ -1184,760 +1184,6 @@ $.api.settings = { -})( jQuery, window, document ); - -/*! - * # Fomantic-UI - Dimmer - * http://github.com/fomantic/Fomantic-UI/ - * - * - * Released under the MIT license - * http://opensource.org/licenses/MIT - * - */ - -;(function ($, window, document, undefined) { - -'use strict'; - -$.isFunction = $.isFunction || function(obj) { - return typeof obj === "function" && typeof obj.nodeType !== "number"; -}; - -window = (typeof window != 'undefined' && window.Math == Math) - ? window - : (typeof self != 'undefined' && self.Math == Math) - ? self - : Function('return this')() -; - -$.fn.dimmer = function(parameters) { - var - $allModules = $(this), - - time = new Date().getTime(), - performance = [], - - query = arguments[0], - methodInvoked = (typeof query == 'string'), - queryArguments = [].slice.call(arguments, 1), - - returnedValue - ; - - $allModules - .each(function() { - var - settings = ( $.isPlainObject(parameters) ) - ? $.extend(true, {}, $.fn.dimmer.settings, parameters) - : $.extend({}, $.fn.dimmer.settings), - - selector = settings.selector, - namespace = settings.namespace, - className = settings.className, - error = settings.error, - - eventNamespace = '.' + namespace, - moduleNamespace = 'module-' + namespace, - moduleSelector = $allModules.selector || '', - - clickEvent = "click", unstableClickEvent = ('ontouchstart' in document.documentElement) - ? 'touchstart' - : 'click', - - $module = $(this), - $dimmer, - $dimmable, - - element = this, - instance = $module.data(moduleNamespace), - module - ; - - module = { - - preinitialize: function() { - if( module.is.dimmer() ) { - - $dimmable = $module.parent(); - $dimmer = $module; - } - else { - $dimmable = $module; - if( module.has.dimmer() ) { - if(settings.dimmerName) { - $dimmer = $dimmable.find(selector.dimmer).filter('.' + settings.dimmerName); - } - else { - $dimmer = $dimmable.find(selector.dimmer); - } - } - else { - $dimmer = module.create(); - } - } - }, - - initialize: function() { - module.debug('Initializing dimmer', settings); - - module.bind.events(); - module.set.dimmable(); - module.instantiate(); - }, - - instantiate: function() { - module.verbose('Storing instance of module', module); - instance = module; - $module - .data(moduleNamespace, instance) - ; - }, - - destroy: function() { - module.verbose('Destroying previous module', $dimmer); - module.unbind.events(); - module.remove.variation(); - $dimmable - .off(eventNamespace) - ; - }, - - bind: { - events: function() { - if(settings.on == 'hover') { - $dimmable - .on('mouseenter' + eventNamespace, module.show) - .on('mouseleave' + eventNamespace, module.hide) - ; - } - else if(settings.on == 'click') { - $dimmable - .on(clickEvent + eventNamespace, module.toggle) - ; - } - if( module.is.page() ) { - module.debug('Setting as a page dimmer', $dimmable); - module.set.pageDimmer(); - } - - if( module.is.closable() ) { - module.verbose('Adding dimmer close event', $dimmer); - $dimmable - .on(clickEvent + eventNamespace, selector.dimmer, module.event.click) - ; - } - } - }, - - unbind: { - events: function() { - $module - .removeData(moduleNamespace) - ; - $dimmable - .off(eventNamespace) - ; - } - }, - - event: { - click: function(event) { - module.verbose('Determining if event occured on dimmer', event); - if( $dimmer.find(event.target).length === 0 || $(event.target).is(selector.content) ) { - module.hide(); - event.stopImmediatePropagation(); - } - } - }, - - addContent: function(element) { - var - $content = $(element) - ; - module.debug('Add content to dimmer', $content); - if($content.parent()[0] !== $dimmer[0]) { - $content.detach().appendTo($dimmer); - } - }, - - create: function() { - var - $element = $( settings.template.dimmer(settings) ) - ; - if(settings.dimmerName) { - module.debug('Creating named dimmer', settings.dimmerName); - $element.addClass(settings.dimmerName); - } - $element - .appendTo($dimmable) - ; - return $element; - }, - - show: function(callback) { - callback = $.isFunction(callback) - ? callback - : function(){} - ; - module.debug('Showing dimmer', $dimmer, settings); - module.set.variation(); - if( (!module.is.dimmed() || module.is.animating()) && module.is.enabled() ) { - module.animate.show(callback); - settings.onShow.call(element); - settings.onChange.call(element); - } - else { - module.debug('Dimmer is already shown or disabled'); - } - }, - - hide: function(callback) { - callback = $.isFunction(callback) - ? callback - : function(){} - ; - if( module.is.dimmed() || module.is.animating() ) { - module.debug('Hiding dimmer', $dimmer); - module.animate.hide(callback); - settings.onHide.call(element); - settings.onChange.call(element); - } - else { - module.debug('Dimmer is not visible'); - } - }, - - toggle: function() { - module.verbose('Toggling dimmer visibility', $dimmer); - if( !module.is.dimmed() ) { - module.show(); - } - else { - if ( module.is.closable() ) { - module.hide(); - } - } - }, - - animate: { - show: function(callback) { - callback = $.isFunction(callback) - ? callback - : function(){} - ; - if(settings.useCSS && $.fn.transition !== undefined && $dimmer.transition('is supported')) { - if(settings.useFlex) { - module.debug('Using flex dimmer'); - module.remove.legacy(); - } - else { - module.debug('Using legacy non-flex dimmer'); - module.set.legacy(); - } - if(settings.opacity !== 'auto') { - module.set.opacity(); - } - $dimmer - .transition({ - displayType : settings.useFlex - ? 'flex' - : 'block', - animation : settings.transition + ' in', - queue : false, - duration : module.get.duration(), - useFailSafe : true, - onStart : function() { - module.set.dimmed(); - }, - onComplete : function() { - module.set.active(); - callback(); - } - }) - ; - } - else { - module.verbose('Showing dimmer animation with javascript'); - module.set.dimmed(); - if(settings.opacity == 'auto') { - settings.opacity = 0.8; - } - $dimmer - .stop() - .css({ - opacity : 0, - width : '100%', - height : '100%' - }) - .fadeTo(module.get.duration(), settings.opacity, function() { - $dimmer.removeAttr('style'); - module.set.active(); - callback(); - }) - ; - } - }, - hide: function(callback) { - callback = $.isFunction(callback) - ? callback - : function(){} - ; - if(settings.useCSS && $.fn.transition !== undefined && $dimmer.transition('is supported')) { - module.verbose('Hiding dimmer with css'); - $dimmer - .transition({ - displayType : settings.useFlex - ? 'flex' - : 'block', - animation : settings.transition + ' out', - queue : false, - duration : module.get.duration(), - useFailSafe : true, - onComplete : function() { - module.remove.dimmed(); - module.remove.variation(); - module.remove.active(); - callback(); - } - }) - ; - } - else { - module.verbose('Hiding dimmer with javascript'); - $dimmer - .stop() - .fadeOut(module.get.duration(), function() { - module.remove.dimmed(); - module.remove.active(); - $dimmer.removeAttr('style'); - callback(); - }) - ; - } - } - }, - - get: { - dimmer: function() { - return $dimmer; - }, - duration: function() { - if(typeof settings.duration == 'object') { - if( module.is.active() ) { - return settings.duration.hide; - } - else { - return settings.duration.show; - } - } - return settings.duration; - } - }, - - has: { - dimmer: function() { - if(settings.dimmerName) { - return ($module.find(selector.dimmer).filter('.' + settings.dimmerName).length > 0); - } - else { - return ( $module.find(selector.dimmer).length > 0 ); - } - } - }, - - is: { - active: function() { - return $dimmer.hasClass(className.active); - }, - animating: function() { - return ( $dimmer.is(':animated') || $dimmer.hasClass(className.animating) ); - }, - closable: function() { - if(settings.closable == 'auto') { - if(settings.on == 'hover') { - return false; - } - return true; - } - return settings.closable; - }, - dimmer: function() { - return $module.hasClass(className.dimmer); - }, - dimmable: function() { - return $module.hasClass(className.dimmable); - }, - dimmed: function() { - return $dimmable.hasClass(className.dimmed); - }, - disabled: function() { - return $dimmable.hasClass(className.disabled); - }, - enabled: function() { - return !module.is.disabled(); - }, - page: function () { - return $dimmable.is('body'); - }, - pageDimmer: function() { - return $dimmer.hasClass(className.pageDimmer); - } - }, - - can: { - show: function() { - return !$dimmer.hasClass(className.disabled); - } - }, - - set: { - opacity: function(opacity) { - var - color = $dimmer.css('background-color'), - colorArray = color.split(','), - isRGB = (colorArray && colorArray.length >= 3) - ; - opacity = settings.opacity === 0 ? 0 : settings.opacity || opacity; - if(isRGB) { - colorArray[2] = colorArray[2].replace(')',''); - colorArray[3] = opacity + ')'; - color = colorArray.join(','); - } - else { - color = 'rgba(0, 0, 0, ' + opacity + ')'; - } - module.debug('Setting opacity to', opacity); - $dimmer.css('background-color', color); - }, - legacy: function() { - $dimmer.addClass(className.legacy); - }, - active: function() { - $dimmer.addClass(className.active); - }, - dimmable: function() { - $dimmable.addClass(className.dimmable); - }, - dimmed: function() { - $dimmable.addClass(className.dimmed); - }, - pageDimmer: function() { - $dimmer.addClass(className.pageDimmer); - }, - disabled: function() { - $dimmer.addClass(className.disabled); - }, - variation: function(variation) { - variation = variation || settings.variation; - if(variation) { - $dimmer.addClass(variation); - } - } - }, - - remove: { - active: function() { - $dimmer - .removeClass(className.active) - ; - }, - legacy: function() { - $dimmer.removeClass(className.legacy); - }, - dimmed: function() { - $dimmable.removeClass(className.dimmed); - }, - disabled: function() { - $dimmer.removeClass(className.disabled); - }, - variation: function(variation) { - variation = variation || settings.variation; - if(variation) { - $dimmer.removeClass(variation); - } - } - }, - - setting: function(name, value) { - module.debug('Changing setting', name, value); - if( $.isPlainObject(name) ) { - $.extend(true, settings, name); - } - else if(value !== undefined) { - if($.isPlainObject(settings[name])) { - $.extend(true, settings[name], value); - } - else { - settings[name] = value; - } - } - else { - return settings[name]; - } - }, - internal: function(name, value) { - if( $.isPlainObject(name) ) { - $.extend(true, module, name); - } - else if(value !== undefined) { - module[name] = value; - } - else { - return module[name]; - } - }, - debug: function() { - if(!settings.silent && settings.debug) { - if(settings.performance) { - module.performance.log(arguments); - } - else { - module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':'); - module.debug.apply(console, arguments); - } - } - }, - verbose: function() { - if(!settings.silent && settings.verbose && settings.debug) { - if(settings.performance) { - module.performance.log(arguments); - } - else { - module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':'); - module.verbose.apply(console, arguments); - } - } - }, - error: function() { - if(!settings.silent) { - module.error = Function.prototype.bind.call(console.error, console, settings.name + ':'); - module.error.apply(console, arguments); - } - }, - performance: { - log: function(message) { - var - currentTime, - executionTime, - previousTime - ; - if(settings.performance) { - currentTime = new Date().getTime(); - previousTime = time || currentTime; - executionTime = currentTime - previousTime; - time = currentTime; - performance.push({ - 'Name' : message[0], - 'Arguments' : [].slice.call(message, 1) || '', - 'Element' : element, - 'Execution Time' : executionTime - }); - } - clearTimeout(module.performance.timer); - module.performance.timer = setTimeout(module.performance.display, 500); - }, - display: function() { - var - title = settings.name + ':', - totalTime = 0 - ; - time = false; - clearTimeout(module.performance.timer); - $.each(performance, function(index, data) { - totalTime += data['Execution Time']; - }); - title += ' ' + totalTime + 'ms'; - if(moduleSelector) { - title += ' \'' + moduleSelector + '\''; - } - if($allModules.length > 1) { - title += ' ' + '(' + $allModules.length + ')'; - } - if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) { - console.groupCollapsed(title); - if(console.table) { - console.table(performance); - } - else { - $.each(performance, function(index, data) { - console.log(data['Name'] + ': ' + data['Execution Time']+'ms'); - }); - } - console.groupEnd(); - } - performance = []; - } - }, - invoke: function(query, passedArguments, context) { - var - object = instance, - maxDepth, - found, - response - ; - passedArguments = passedArguments || queryArguments; - context = element || context; - if(typeof query == 'string' && object !== undefined) { - query = query.split(/[\. ]/); - maxDepth = query.length - 1; - $.each(query, function(depth, value) { - var camelCaseValue = (depth != maxDepth) - ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1) - : query - ; - if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) { - object = object[camelCaseValue]; - } - else if( object[camelCaseValue] !== undefined ) { - found = object[camelCaseValue]; - return false; - } - else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) { - object = object[value]; - } - else if( object[value] !== undefined ) { - found = object[value]; - return false; - } - else { - module.error(error.method, query); - return false; - } - }); - } - if ( $.isFunction( found ) ) { - response = found.apply(context, passedArguments); - } - else if(found !== undefined) { - response = found; - } - if(Array.isArray(returnedValue)) { - returnedValue.push(response); - } - else if(returnedValue !== undefined) { - returnedValue = [returnedValue, response]; - } - else if(response !== undefined) { - returnedValue = response; - } - return found; - } - }; - - module.preinitialize(); - - if(methodInvoked) { - if(instance === undefined) { - module.initialize(); - } - module.invoke(query); - } - else { - if(instance !== undefined) { - instance.invoke('destroy'); - } - module.initialize(); - } - }) - ; - - return (returnedValue !== undefined) - ? returnedValue - : this - ; -}; - -$.fn.dimmer.settings = { - - name : 'Dimmer', - namespace : 'dimmer', - - silent : false, - debug : false, - verbose : false, - performance : true, - - // whether should use flex layout - useFlex : true, - - // name to distinguish between multiple dimmers in context - dimmerName : false, - - // whether to add a variation type - variation : false, - - // whether to bind close events - closable : 'auto', - - // whether to use css animations - useCSS : true, - - // css animation to use - transition : 'fade', - - // event to bind to - on : false, - - // overriding opacity value - opacity : 'auto', - - // transition durations - duration : { - show : 500, - hide : 500 - }, -// whether the dynamically created dimmer should have a loader - displayLoader: false, - loaderText : false, - loaderVariation : '', - - onChange : function(){}, - onShow : function(){}, - onHide : function(){}, - - error : { - method : 'The method you called is not defined.' - }, - - className : { - active : 'active', - animating : 'animating', - dimmable : 'dimmable', - dimmed : 'dimmed', - dimmer : 'dimmer', - disabled : 'disabled', - hide : 'hide', - legacy : 'legacy', - pageDimmer : 'page', - show : 'show', - loader : 'ui loader' - }, - - selector: { - dimmer : '> .ui.dimmer', - content : '.ui.dimmer > .content, .ui.dimmer > .content > .center' - }, - - template: { - dimmer: function(settings) { - var d = $('<div/>').addClass('ui dimmer'),l; - if(settings.displayLoader) { - l = $('<div/>') - .addClass(settings.className.loader) - .addClass(settings.loaderVariation); - if(!!settings.loaderText){ - l.text(settings.loaderText); - l.addClass('text'); - } - d.append(l); - } - return d; - } - } - -}; - })( jQuery, window, document ); /*! diff --git a/web_src/fomantic/semantic.json b/web_src/fomantic/semantic.json index 489ca7b9b7..63d0b30218 100644 --- a/web_src/fomantic/semantic.json +++ b/web_src/fomantic/semantic.json @@ -22,7 +22,6 @@ "admin": false, "components": [ "api", - "dimmer", "dropdown", "form", "modal", diff --git a/web_src/js/modules/fomantic.js b/web_src/js/modules/fomantic.js index c04bc6e863..06e4e97c48 100644 --- a/web_src/js/modules/fomantic.js +++ b/web_src/js/modules/fomantic.js @@ -5,6 +5,7 @@ import {initAriaFormFieldPatch} from './fomantic/form.js'; import {initAriaDropdownPatch} from './fomantic/dropdown.js'; import {initAriaModalPatch} from './fomantic/modal.js'; import {initFomanticTransition} from './fomantic/transition.js'; +import {initFomanticDimmer} from './fomantic/dimmer.js'; import {svg} from '../svg.js'; export const fomanticMobileScreen = window.matchMedia('only screen and (max-width: 767.98px)'); @@ -24,6 +25,7 @@ export function initGiteaFomantic() { }; initFomanticTransition(); + initFomanticDimmer(); initFomanticApiPatch(); // Use the patches to improve accessibility, these patches are designed to be as independent as possible, make it easy to modify or remove in the future. diff --git a/web_src/js/modules/fomantic/dimmer.js b/web_src/js/modules/fomantic/dimmer.js new file mode 100644 index 0000000000..f434e1ca59 --- /dev/null +++ b/web_src/js/modules/fomantic/dimmer.js @@ -0,0 +1,29 @@ +import $ from 'jquery'; +import {queryElemChildren} from '../../utils/dom.js'; + +export function initFomanticDimmer() { + // stand-in for removed dimmer module + $.fn.dimmer = function (arg0, $el) { + if (arg0 === 'add content') { + const existingDimmer = document.querySelector('body > .ui.dimmer'); + if (existingDimmer) { + queryElemChildren(existingDimmer, '*', (el) => el.remove()); + this._dimmer = existingDimmer; + } else { + this._dimmer = document.createElement('div'); + this._dimmer.classList.add('ui', 'dimmer'); + document.body.append(this._dimmer); + } + this._dimmer.append($el[0]); + } else if (arg0 === 'get dimmer') { + return $(this._dimmer); + } else if (arg0 === 'show') { + this._dimmer.classList.add('active'); + document.body.classList.add('tw-overflow-hidden'); + } else if (arg0 === 'hide') { + this._dimmer.classList.remove('active'); + document.body.classList.remove('tw-overflow-hidden'); + } + return this; + }; +} From 4daea7c603c085eeda7017ac7188de7828824ed4 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Tue, 30 Apr 2024 04:15:35 +0800 Subject: [PATCH 238/370] Rename CodeIndexerEnabled to IsRepoIndexerEnabled (#30762) Fix #30761 Most places use `IsRepoIndexerEnabled` but not `CodeIndexerEnabled`, so it should always use `IsRepoIndexerEnabled` for consistency. --- routers/web/repo/search.go | 2 +- routers/web/repo/setting/setting.go | 4 ++-- templates/repo/settings/options.tmpl | 2 +- templates/shared/search/code/search.tmpl | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/routers/web/repo/search.go b/routers/web/repo/search.go index 46f0208453..23cf898630 100644 --- a/routers/web/repo/search.go +++ b/routers/web/repo/search.go @@ -86,7 +86,7 @@ func Search(ctx *context.Context) { } } - ctx.Data["CodeIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled + ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled ctx.Data["Repo"] = ctx.Repo.Repository ctx.Data["SearchResults"] = searchResults ctx.Data["SearchResultLanguages"] = searchResultLanguages diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go index b55e259e4b..17a400e360 100644 --- a/routers/web/repo/setting/setting.go +++ b/routers/web/repo/setting/setting.go @@ -65,7 +65,7 @@ func SettingsCtxData(ctx *context.Context) { signing, _ := asymkey_service.SigningKey(ctx, ctx.Repo.Repository.RepoPath()) ctx.Data["SigningKeyAvailable"] = len(signing) > 0 ctx.Data["SigningSettings"] = setting.Repository.Signing - ctx.Data["CodeIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled + ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled if ctx.Doer.IsAdmin { if setting.Indexer.RepoIndexerEnabled { @@ -110,7 +110,7 @@ func SettingsPost(ctx *context.Context) { signing, _ := asymkey_service.SigningKey(ctx, ctx.Repo.Repository.RepoPath()) ctx.Data["SigningKeyAvailable"] = len(signing) > 0 ctx.Data["SigningSettings"] = setting.Repository.Signing - ctx.Data["CodeIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled + ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled repo := ctx.Repo.Repository diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index 390351723b..40617021d9 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -739,7 +739,7 @@ <form class="ui form" method="post"> {{.CsrfTokenHtml}} <input type="hidden" name="action" value="admin_index"> - {{if .CodeIndexerEnabled}} + {{if .IsRepoIndexerEnabled}} <h4 class="ui header">{{ctx.Locale.Tr "repo.settings.admin_code_indexer"}}</h4> <div class="inline fields"> <label>{{ctx.Locale.Tr "repo.settings.admin_indexer_commit_sha"}}</label> diff --git a/templates/shared/search/code/search.tmpl b/templates/shared/search/code/search.tmpl index cb873f5a92..e49ea47e03 100644 --- a/templates/shared/search/code/search.tmpl +++ b/templates/shared/search/code/search.tmpl @@ -8,7 +8,7 @@ <p>{{ctx.Locale.Tr "search.code_search_unavailable"}}</p> </div> {{else}} - {{if not .CodeIndexerEnabled}} + {{if not .IsRepoIndexerEnabled}} <div class="ui message"> <p>{{ctx.Locale.Tr "search.code_search_by_git_grep"}}</p> </div> From a3d9f0d9151dbdcd77bf68f70b8e9497da5f2d3f Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Mon, 29 Apr 2024 22:53:15 +0200 Subject: [PATCH 239/370] Fix all rounded borders, change affected tab menus to pills (#30707) Fixes https://github.com/go-gitea/gitea/issues/30673, all 23 issues. Notes: - Tab bar menus had to change to pills because of unsolvable issue with the border-radius as tab bar renders a overlapping border onto the box below. And I think pills look better. - Added padding to code editor empty preview message - Hide monaco's built-in blue focus border, we don't need it and it never showed before either. - Label add menu is simplified, removing the nested segment. <img width="1322" alt="Screenshot 2024-04-25 at 22 26 19" src="https://github.com/go-gitea/gitea/assets/115237/7e394e0c-b7ad-417d-8e9f-12f1dea93ed1"> <img width="1326" alt="Screenshot 2024-04-25 at 22 28 00" src="https://github.com/go-gitea/gitea/assets/115237/66c8499f-aa9f-4d95-8cca-ef13dfa82c65"> <img width="997" alt="Screenshot 2024-04-25 at 22 36 53" src="https://github.com/go-gitea/gitea/assets/115237/07896102-c71d-4246-8173-c2bc2e1d3cae"> <img width="832" alt="Screenshot 2024-04-25 at 22 56 09" src="https://github.com/go-gitea/gitea/assets/115237/d83afc96-08ca-4adc-baf4-3d02804be57c"> <img width="361" alt="Screenshot 2024-04-25 at 22 57 12" src="https://github.com/go-gitea/gitea/assets/115237/c7371a68-00b5-47d8-84d0-ddc5268b2b2c"> --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: Giteabot <teabot@gitea.io> --- routers/web/repo/editor.go | 6 ++-- templates/org/team/members.tmpl | 4 +-- templates/org/team/navbar.tmpl | 2 +- templates/org/team/repositories.tmpl | 2 +- templates/repo/commit_page.tmpl | 2 +- templates/repo/editor/diff_preview.tmpl | 6 ++++ templates/repo/editor/edit.tmpl | 8 ++--- templates/repo/editor/patch.tmpl | 4 +-- .../issue/labels/label_load_template.tmpl | 33 +++++++++---------- templates/repo/tag/list.tmpl | 2 ++ .../notification_subscriptions.tmpl | 4 +-- templates/user/settings/account.tmpl | 2 +- templates/user/settings/applications.tmpl | 2 +- .../applications_oauth2_edit_form.tmpl | 2 +- .../settings/applications_oauth2_list.tmpl | 2 +- templates/user/settings/security/openid.tmpl | 2 +- web_src/css/features/codeeditor.css | 5 +++ web_src/css/modules/card.css | 1 + web_src/css/modules/menu.css | 20 +++++++++++ web_src/css/modules/modal.css | 2 ++ web_src/css/modules/segment.css | 8 ++++- web_src/css/repo.css | 18 ++++++++++ web_src/css/repo/list-header.css | 19 ----------- web_src/js/features/codeeditor.js | 1 + web_src/js/features/repo-editor.js | 18 +++++----- 25 files changed, 107 insertions(+), 68 deletions(-) diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go index 474f7ff1da..474d7503e4 100644 --- a/routers/web/repo/editor.go +++ b/routers/web/repo/editor.go @@ -419,11 +419,9 @@ func DiffPreviewPost(ctx *context.Context) { return } - if diff.NumFiles == 0 { - ctx.PlainText(http.StatusOK, ctx.Locale.TrString("repo.editor.no_changes_to_show")) - return + if diff.NumFiles != 0 { + ctx.Data["File"] = diff.Files[0] } - ctx.Data["File"] = diff.Files[0] ctx.HTML(http.StatusOK, tplEditDiffPreview) } diff --git a/templates/org/team/members.tmpl b/templates/org/team/members.tmpl index 7e9a59a6bf..5433f01530 100644 --- a/templates/org/team/members.tmpl +++ b/templates/org/team/members.tmpl @@ -8,7 +8,7 @@ <div class="ui ten wide column"> {{template "org/team/navbar" .}} {{if .IsOrganizationOwner}} - <div class="ui attached segment"> + <div class="ui top attached segment"> <form class="ui form ignore-dirty tw-flex tw-flex-wrap tw-gap-2" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/add" method="post"> {{.CsrfTokenHtml}} <input type="hidden" name="uid" value="{{.SignedUser.ID}}"> @@ -21,7 +21,7 @@ </form> </div> {{end}} - <div class="ui attached segment"> + <div class="ui{{if not .IsOrganizationOwner}} top{{end}} attached segment"> <div class="flex-list"> {{range .Team.Members}} <div class="flex-item tw-items-center"> diff --git a/templates/org/team/navbar.tmpl b/templates/org/team/navbar.tmpl index 8f2571e1f6..9704f63f6f 100644 --- a/templates/org/team/navbar.tmpl +++ b/templates/org/team/navbar.tmpl @@ -1,4 +1,4 @@ -<div class="ui top attached tabular menu org-team-navbar"> +<div class="ui compact small menu small-menu-items org-team-navbar"> <a class="item{{if .PageIsOrgTeamMembers}} active{{end}}" href="{{.OrgLink}}/teams/{{.Team.LowerName | PathEscape}}">{{svg "octicon-person"}} <strong>{{.Team.NumMembers}}</strong> {{ctx.Locale.Tr "org.lower_members"}}</a> <a class="item{{if .PageIsOrgTeamRepos}} active{{end}}" href="{{.OrgLink}}/teams/{{.Team.LowerName | PathEscape}}/repositories">{{svg "octicon-repo"}} <strong>{{.Team.NumRepos}}</strong> {{ctx.Locale.Tr "org.lower_repositories"}}</a> </div> diff --git a/templates/org/team/repositories.tmpl b/templates/org/team/repositories.tmpl index f5d68ce416..502cf97992 100644 --- a/templates/org/team/repositories.tmpl +++ b/templates/org/team/repositories.tmpl @@ -25,7 +25,7 @@ </div> </div> {{end}} - <div class="ui attached segment"> + <div class="ui{{if not $canAddRemove}} top{{end}} attached segment"> <div class="flex-list"> {{range .Team.Repos}} <div class="flex-item tw-items-center"> diff --git a/templates/repo/commit_page.tmpl b/templates/repo/commit_page.tmpl index 938d93b323..b8195ac544 100644 --- a/templates/repo/commit_page.tmpl +++ b/templates/repo/commit_page.tmpl @@ -139,7 +139,7 @@ {{end}} {{template "repo/commit_load_branches_and_tags" .}} </div> - <div class="ui attached segment tw-flex tw-items-center tw-justify-between tw-py-1 commit-header-row tw-flex-wrap {{$class}}"> + <div class="ui{{if not .Commit.Signature}} bottom{{end}} attached segment tw-flex tw-items-center tw-justify-between tw-py-1 commit-header-row tw-flex-wrap {{$class}}"> <div class="tw-flex tw-items-center author"> {{if .Author}} {{ctx.AvatarUtils.Avatar .Author 28 "tw-mr-2"}} diff --git a/templates/repo/editor/diff_preview.tmpl b/templates/repo/editor/diff_preview.tmpl index e2e922be34..fd543a5ab9 100644 --- a/templates/repo/editor/diff_preview.tmpl +++ b/templates/repo/editor/diff_preview.tmpl @@ -1,3 +1,4 @@ +{{if .File}} <div class="diff-file-box"> <div class="ui attached table segment"> <div class="file-body file-code code-diff code-diff-unified unicode-escaped"> @@ -9,3 +10,8 @@ </div> </div> </div> +{{else}} +<div class="tw-p-6 tw-text-center"> + {{ctx.Locale.Tr "repo.editor.no_changes_to_show"}} +</div> +{{end}} diff --git a/templates/repo/editor/edit.tmpl b/templates/repo/editor/edit.tmpl index d52e5a047a..ae3f12669c 100644 --- a/templates/repo/editor/edit.tmpl +++ b/templates/repo/editor/edit.tmpl @@ -26,14 +26,14 @@ </div> </div> <div class="field"> - <div class="ui top attached tabular menu" data-write="write" data-preview="preview" data-diff="diff"> + <div class="ui compact small menu small-menu-items repo-editor-menu"> <a class="active item" data-tab="write">{{svg "octicon-code"}} {{if .IsNewFile}}{{ctx.Locale.Tr "repo.editor.new_file"}}{{else}}{{ctx.Locale.Tr "repo.editor.edit_file"}}{{end}}</a> <a class="item" data-tab="preview" data-url="{{.Repository.Link}}/markup" data-context="{{.RepoLink}}/src/{{.BranchNameSubURL}}" data-markup-mode="file">{{svg "octicon-eye"}} {{ctx.Locale.Tr "preview"}}</a> {{if not .IsNewFile}} <a class="item" data-tab="diff" hx-params="context,content" hx-vals='{"context":"{{.BranchLink}}"}' hx-include="#edit_area" hx-swap="innerHTML" hx-target=".tab[data-tab='diff']" hx-indicator=".tab[data-tab='diff']" hx-post="{{.RepoLink}}/_preview/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">{{svg "octicon-diff"}} {{ctx.Locale.Tr "repo.editor.preview_changes"}}</a> {{end}} </div> - <div class="ui bottom attached active tab segment" data-tab="write"> + <div class="ui active tab segment tw-rounded" data-tab="write"> <textarea id="edit_area" name="content" class="tw-hidden" data-id="repo-{{.Repository.Name}}-{{.TreePath}}" data-url="{{.Repository.Link}}/markup" data-context="{{.RepoLink}}" @@ -41,10 +41,10 @@ data-line-wrap-extensions="{{.LineWrapExtensions}}">{{.FileContent}}</textarea> <div class="editor-loading is-loading"></div> </div> - <div class="ui bottom attached tab segment markup" data-tab="preview"> + <div class="ui tab segment markup tw-rounded" data-tab="preview"> {{ctx.Locale.Tr "loading"}} </div> - <div class="ui bottom attached tab segment diff edit-diff" data-tab="diff"> + <div class="ui tab segment diff edit-diff" data-tab="diff"> <div class="tw-p-16"></div> </div> </div> diff --git a/templates/repo/editor/patch.tmpl b/templates/repo/editor/patch.tmpl index ff5c09667f..a29021fa47 100644 --- a/templates/repo/editor/patch.tmpl +++ b/templates/repo/editor/patch.tmpl @@ -19,10 +19,10 @@ </div> </div> <div class="field"> - <div class="ui top attached tabular menu" data-write="write"> + <div class="ui compact small menu small-menu-items repo-editor-menu"> <a class="active item" data-tab="write">{{svg "octicon-code" 16 "tw-mr-1"}}{{ctx.Locale.Tr "repo.editor.new_patch"}}</a> </div> - <div class="ui bottom attached active tab segment" data-tab="write"> + <div class="ui active tab segment tw-rounded tw-p-0" data-tab="write"> <textarea id="edit_area" name="content" class="tw-hidden" data-id="repo-{{.Repository.Name}}-patch" data-context="{{.RepoLink}}" data-line-wrap-extensions="{{.LineWrapExtensions}}"> diff --git a/templates/repo/issue/labels/label_load_template.tmpl b/templates/repo/issue/labels/label_load_template.tmpl index 0499afea19..3cb2442a1d 100644 --- a/templates/repo/issue/labels/label_load_template.tmpl +++ b/templates/repo/issue/labels/label_load_template.tmpl @@ -1,24 +1,21 @@ <div class="ui centered grid"> <div class="twelve wide computer column"> - <div class="ui attached left aligned segment"> - <p>{{ctx.Locale.Tr "repo.issues.label_templates.info"}}</p> - <br> - <form class="ui form center" action="{{.Link}}/initialize" method="post"> - {{.CsrfTokenHtml}} - <div class="field"> - <div class="ui selection dropdown"> - <input type="hidden" name="template_name" value="Default"> - <div class="default text">{{ctx.Locale.Tr "repo.issues.label_templates.helper"}}</div> - <div class="menu"> - {{range .LabelTemplateFiles}} - <div class="item" data-value="{{.DisplayName}}">{{.DisplayName}}<br><i>({{.Description}})</i></div> - {{end}} - </div> - {{svg "octicon-triangle-down" 18 "dropdown icon"}} + <p>{{ctx.Locale.Tr "repo.issues.label_templates.info"}}</p> + <form class="ui form center" action="{{.Link}}/initialize" method="post"> + {{.CsrfTokenHtml}} + <div class="field"> + <div class="ui selection dropdown"> + <input type="hidden" name="template_name" value="Default"> + <div class="default text">{{ctx.Locale.Tr "repo.issues.label_templates.helper"}}</div> + <div class="menu"> + {{range .LabelTemplateFiles}} + <div class="item" data-value="{{.DisplayName}}">{{.DisplayName}}<br><i>({{.Description}})</i></div> + {{end}} </div> + {{svg "octicon-triangle-down" 18 "dropdown icon"}} </div> - <button type="submit" class="ui primary button">{{ctx.Locale.Tr "repo.issues.label_templates.use"}}</button> - </form> - </div> + </div> + <button type="submit" class="ui primary button">{{ctx.Locale.Tr "repo.issues.label_templates.use"}}</button> + </form> </div> </div> diff --git a/templates/repo/tag/list.tmpl b/templates/repo/tag/list.tmpl index a63c94cd8e..b3ad3a7c47 100644 --- a/templates/repo/tag/list.tmpl +++ b/templates/repo/tag/list.tmpl @@ -4,6 +4,7 @@ <div class="ui container"> {{template "base/alert" .}} {{template "repo/release_tag_header" .}} + {{if .Releases}} <h4 class="ui top attached header"> <div class="five wide column tw-flex tw-items-center"> {{svg "octicon-tag" 16 "tw-mr-1"}}{{ctx.Locale.Tr "repo.release.tags"}} @@ -57,6 +58,7 @@ </tbody> </table> </div> + {{end}} {{template "base/paginate" .}} </div> diff --git a/templates/user/notification/notification_subscriptions.tmpl b/templates/user/notification/notification_subscriptions.tmpl index a5a965ca52..b92a32a957 100644 --- a/templates/user/notification/notification_subscriptions.tmpl +++ b/templates/user/notification/notification_subscriptions.tmpl @@ -1,7 +1,7 @@ {{template "base/head" .}} <div role="main" aria-label="{{.Title}}" class="page-content user notification"> <div class="ui container"> - <div class="ui top attached tabular menu"> + <div class="ui compact small menu small-menu-items"> <a href="{{AppSubUrl}}/notifications/subscriptions" class="{{if eq .Status 1}}active {{end}}item"> {{ctx.Locale.Tr "notification.subscriptions"}} </a> @@ -9,7 +9,7 @@ {{ctx.Locale.Tr "notification.watching"}} </a> </div> - <div class="ui bottom attached active tab segment"> + <div class="ui top attached segment"> {{if eq .Status 1}} <div class="tw-flex tw-justify-between"> <div class="tw-flex"> diff --git a/templates/user/settings/account.tmpl b/templates/user/settings/account.tmpl index 040f46e48b..2aaf8535d1 100644 --- a/templates/user/settings/account.tmpl +++ b/templates/user/settings/account.tmpl @@ -111,7 +111,7 @@ {{end}} </div> </div> - <div class="ui attached bottom segment"> + <div class="ui bottom attached segment"> <form class="ui form" action="{{AppSubUrl}}/user/settings/account/email" method="post"> {{.CsrfTokenHtml}} <div class="required field {{if .Err_Email}}error{{end}}"> diff --git a/templates/user/settings/applications.tmpl b/templates/user/settings/applications.tmpl index 8baa07c90b..8c67653e58 100644 --- a/templates/user/settings/applications.tmpl +++ b/templates/user/settings/applications.tmpl @@ -49,7 +49,7 @@ {{end}} </div> </div> - <div class="ui attached bottom segment"> + <div class="ui bottom attached segment"> <h5 class="ui top header"> {{ctx.Locale.Tr "settings.generate_new_token"}} </h5> diff --git a/templates/user/settings/applications_oauth2_edit_form.tmpl b/templates/user/settings/applications_oauth2_edit_form.tmpl index 199d43a65c..e62115d226 100644 --- a/templates/user/settings/applications_oauth2_edit_form.tmpl +++ b/templates/user/settings/applications_oauth2_edit_form.tmpl @@ -30,7 +30,7 @@ </form> </div> </div> -<div class="ui attached bottom segment"> +<div class="ui bottom attached segment"> <form class="ui form ignore-dirty" action="{{.FormActionPath}}" method="post"> {{.CsrfTokenHtml}} <div class="field {{if .Err_AppName}}error{{end}}"> diff --git a/templates/user/settings/applications_oauth2_list.tmpl b/templates/user/settings/applications_oauth2_list.tmpl index c75cbd532e..e9e02179f5 100644 --- a/templates/user/settings/applications_oauth2_list.tmpl +++ b/templates/user/settings/applications_oauth2_list.tmpl @@ -47,7 +47,7 @@ </div> </div> -<div class="ui attached bottom segment"> +<div class="ui bottom attached segment"> <h5 class="ui top header"> {{ctx.Locale.Tr "settings.create_oauth2_application"}} </h5> diff --git a/templates/user/settings/security/openid.tmpl b/templates/user/settings/security/openid.tmpl index b0473c9df5..87ba953e79 100644 --- a/templates/user/settings/security/openid.tmpl +++ b/templates/user/settings/security/openid.tmpl @@ -38,7 +38,7 @@ {{end}} </div> </div> -<div class="ui attached bottom segment"> +<div class="ui bottom attached segment"> <form class="ui form" action="{{AppSubUrl}}/user/settings/security/openid" method="post"> {{.CsrfTokenHtml}} <div class="required field {{if .Err_OpenID}}error{{end}}"> diff --git a/web_src/css/features/codeeditor.css b/web_src/css/features/codeeditor.css index 34a104c833..2a8accbcc8 100644 --- a/web_src/css/features/codeeditor.css +++ b/web_src/css/features/codeeditor.css @@ -21,6 +21,11 @@ background-color: transparent !important; } +.monaco-editor, +.monaco-editor .overflow-guard { + border-radius: var(--border-radius); +} + /* these seem unthemeable */ .monaco-scrollable-element > .scrollbar > .slider { background: var(--color-primary) !important; diff --git a/web_src/css/modules/card.css b/web_src/css/modules/card.css index 2406def681..d5d5e757d6 100644 --- a/web_src/css/modules/card.css +++ b/web_src/css/modules/card.css @@ -21,6 +21,7 @@ border: 1px solid var(--color-secondary); box-shadow: none; word-wrap: break-word; + border-radius: var(--border-radius); } .ui.card { diff --git a/web_src/css/modules/menu.css b/web_src/css/modules/menu.css index e393ec5186..830e4cdbc3 100644 --- a/web_src/css/modules/menu.css +++ b/web_src/css/modules/menu.css @@ -799,3 +799,23 @@ .ui.segment .ui.tabular.menu .active.item:hover { background: var(--color-box-body); } + +.small-menu-items { + min-height: 35.4px !important; /* match .small.button in height */ + background: none !important; /* fomantic sets a color here which does not play well with active transparent color on the item, so unset and set the colors on the item */ + user-select: none; +} + +.small-menu-items .item { + background: var(--color-menu) !important; + padding-top: 6px !important; + padding-bottom: 6px !important; +} + +.small-menu-items .item:hover { + background: var(--color-hover) !important; +} + +.small-menu-items .item.active { + background: var(--color-active) !important; +} diff --git a/web_src/css/modules/modal.css b/web_src/css/modules/modal.css index a2acfeaa15..427d2529c8 100644 --- a/web_src/css/modules/modal.css +++ b/web_src/css/modules/modal.css @@ -54,6 +54,7 @@ These inconsistent layouts should be refactored to simple ones. .ui.modal form > .content { padding: 1.5em; background: var(--color-body); + border-radius: 0 0 var(--border-radius) var(--border-radius); } .ui.modal > .actions, @@ -63,6 +64,7 @@ These inconsistent layouts should be refactored to simple ones. border-color: var(--color-secondary); padding: 1rem; text-align: right; + border-radius: 0 0 var(--border-radius) var(--border-radius); } .ui.modal .content > .actions { diff --git a/web_src/css/modules/segment.css b/web_src/css/modules/segment.css index 994ac1779a..cb307dc1a3 100644 --- a/web_src/css/modules/segment.css +++ b/web_src/css/modules/segment.css @@ -152,7 +152,9 @@ } .ui.attached.segment:has(+ .ui[class*="top attached"].header), -.ui.attached.segment:last-child { +.ui.attached.segment:last-child, +.ui.segment:has(+ .ui.segment:not(.attached)), +.ui.attached.segment:has(+ .ui.modal) { border-radius: 0 0 0.28571429rem 0.28571429rem; } @@ -166,6 +168,10 @@ .ui.segment[class*="top attached"]:first-child { margin-top: 0; } +.ui[class*="top attached"].segment:last-child { + border-top-left-radius: 0.28571429rem; + border-top-right-radius: 0.28571429rem; +} .ui.segment[class*="bottom attached"] { bottom: 0; diff --git a/web_src/css/repo.css b/web_src/css/repo.css index dacb98ddb8..0b46f6b69f 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -1586,6 +1586,7 @@ td .commit-summary { .repository .diff-file-box .file-body.file-code { background: var(--color-code-bg); + border-radius: var(--border-radius); } .repository .diff-file-box .file-body.file-code .lines-num { @@ -2382,6 +2383,22 @@ tbody.commit-list { vertical-align: middle; } +/* fix bottom border radius on diff files */ +.diff-file-body tr.tag-code:last-child { + background: none; +} +.diff-file-body tr.tag-code:last-child > td { + background: var(--color-box-body-highlight); +} +.diff-file-body tr.tag-code:last-child td:first-child, +.diff-file-body tr.tag-code:last-child td:first-child * { + border-bottom-left-radius: 3px; +} +.diff-file-body tr.tag-code:last-child td:last-child, +.diff-file-body tr.tag-code:last-child td:last-child * { + border-bottom-right-radius: 3px; +} + .resolved-placeholder { font-weight: var(--font-weight-normal) !important; border: 1px solid var(--color-secondary) !important; @@ -2491,6 +2508,7 @@ tbody.commit-list { .diff-file-header { padding: 5px 8px !important; + box-shadow: 0 -1px 0 1px var(--color-body); /* prevent borders being visible behind top corners when sticky and scrolled */ } .diff-file-box[data-folded="true"] .diff-file-body { diff --git a/web_src/css/repo/list-header.css b/web_src/css/repo/list-header.css index 304cfbc13c..4440bba8df 100644 --- a/web_src/css/repo/list-header.css +++ b/web_src/css/repo/list-header.css @@ -25,25 +25,6 @@ flex: 1; } -.small-menu-items { - min-height: 35.4px !important; /* match .small.button in height */ - background: none !important; /* fomantic sets a color here which does not play well with active transparent color on the item, so unset and set the colors on the item */ -} - -.small-menu-items .item { - background: var(--color-menu) !important; - padding-top: 6px !important; - padding-bottom: 6px !important; -} - -.small-menu-items .item:hover { - background: var(--color-hover) !important; -} - -.small-menu-items .item.active { - background: var(--color-active) !important; -} - @media (max-width: 767.98px) { .list-header-search { order: 0; diff --git a/web_src/js/features/codeeditor.js b/web_src/js/features/codeeditor.js index f5e4e74dc6..4dfef8c2b2 100644 --- a/web_src/js/features/codeeditor.js +++ b/web_src/js/features/codeeditor.js @@ -98,6 +98,7 @@ export async function createMonaco(textarea, filename, editorOpts) { 'input.foreground': getColor('--color-input-text'), 'scrollbar.shadow': getColor('--color-shadow'), 'progressBar.background': getColor('--color-primary'), + 'focusBorder': '#0000', // prevent blue border }, }); diff --git a/web_src/js/features/repo-editor.js b/web_src/js/features/repo-editor.js index 01dc4b95aa..a5232cb4b6 100644 --- a/web_src/js/features/repo-editor.js +++ b/web_src/js/features/repo-editor.js @@ -7,9 +7,9 @@ import {attachRefIssueContextPopup} from './contextpopup.js'; import {POST} from '../modules/fetch.js'; function initEditPreviewTab($form) { - const $tabMenu = $form.find('.tabular.menu'); + const $tabMenu = $form.find('.repo-editor-menu'); $tabMenu.find('.item').tab(); - const $previewTab = $tabMenu.find(`.item[data-tab="${$tabMenu.data('preview')}"]`); + const $previewTab = $tabMenu.find('a[data-tab="preview"]'); if ($previewTab.length) { $previewTab.on('click', async function () { const $this = $(this); @@ -24,13 +24,15 @@ function initEditPreviewTab($form) { const formData = new FormData(); formData.append('mode', mode); formData.append('context', context); - formData.append('text', $form.find(`.tab[data-tab="${$tabMenu.data('write')}"] textarea`).val()); + formData.append('text', $form.find('.tab[data-tab="write"] textarea').val()); formData.append('file_path', $treePathEl.val()); try { const response = await POST($this.data('url'), {data: formData}); const data = await response.text(); - const $previewPanel = $form.find(`.tab[data-tab="${$tabMenu.data('preview')}"]`); - renderPreviewPanelContent($previewPanel, data); + const $previewPanel = $form.find('.tab[data-tab="preview"]'); + if ($previewPanel.length) { + renderPreviewPanelContent($previewPanel, data); + } } catch (error) { console.error('Error:', error); } @@ -175,10 +177,10 @@ export function initRepoEditor() { })(); } -export function renderPreviewPanelContent($panelPreviewer, data) { - $panelPreviewer.html(data); +export function renderPreviewPanelContent($previewPanel, data) { + $previewPanel.html(data); initMarkupContent(); - const $refIssues = $panelPreviewer.find('p .ref-issue'); + const $refIssues = $previewPanel.find('p .ref-issue'); attachRefIssueContextPopup($refIssues); } From 61b495e5ab604a26c867433e5c5ae5b07267e30f Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Tue, 30 Apr 2024 10:36:32 +0800 Subject: [PATCH 240/370] Fix issue label rendering in the issue popup (#30763) --- modules/templates/util_render.go | 39 +++++++++++------------- routers/web/repo/issue.go | 5 ++- tests/integration/issue_test.go | 11 +++++-- web_src/js/components/ContextPopup.vue | 27 ++++------------ web_src/js/features/common-issue-list.js | 2 +- 5 files changed, 36 insertions(+), 48 deletions(-) diff --git a/modules/templates/util_render.go b/modules/templates/util_render.go index 659422aee7..b15de6521d 100644 --- a/modules/templates/util_render.go +++ b/modules/templates/util_render.go @@ -121,29 +121,25 @@ func RenderIssueTitle(ctx context.Context, text string, metas map[string]string) // RenderLabel renders a label // locale is needed due to an import cycle with our context providing the `Tr` function func RenderLabel(ctx context.Context, locale translation.Locale, label *issues_model.Label) template.HTML { - var ( - archivedCSSClass string - textColor = util.ContrastColor(label.Color) - labelScope = label.ExclusiveScope() - ) - - description := emoji.ReplaceAliases(template.HTMLEscapeString(label.Description)) + var extraCSSClasses string + textColor := util.ContrastColor(label.Color) + labelScope := label.ExclusiveScope() + descriptionText := emoji.ReplaceAliases(label.Description) if label.IsArchived() { - archivedCSSClass = "archived-label" - description = fmt.Sprintf("(%s) %s", locale.TrString("archived"), description) + extraCSSClasses = "archived-label" + descriptionText = fmt.Sprintf("(%s) %s", locale.TrString("archived"), descriptionText) } if labelScope == "" { // Regular label - s := fmt.Sprintf("<div class='ui label %s' style='color: %s !important; background-color: %s !important;' data-tooltip-content title='%s'>%s</div>", - archivedCSSClass, textColor, label.Color, description, RenderEmoji(ctx, label.Name)) - return template.HTML(s) + return HTMLFormat(`<div class="ui label %s" style="color: %s !important; background-color: %s !important;" data-tooltip-content title="%s">%s</div>`, + extraCSSClasses, textColor, label.Color, descriptionText, RenderEmoji(ctx, label.Name)) } // Scoped label - scopeText := RenderEmoji(ctx, labelScope) - itemText := RenderEmoji(ctx, label.Name[len(labelScope)+1:]) + scopeHTML := RenderEmoji(ctx, labelScope) + itemHTML := RenderEmoji(ctx, label.Name[len(labelScope)+1:]) // Make scope and item background colors slightly darker and lighter respectively. // More contrast needed with higher luminance, empirically tweaked. @@ -171,14 +167,13 @@ func RenderLabel(ctx context.Context, locale translation.Locale, label *issues_m itemColor := "#" + hex.EncodeToString(itemBytes) scopeColor := "#" + hex.EncodeToString(scopeBytes) - s := fmt.Sprintf("<span class='ui label %s scope-parent' data-tooltip-content title='%s'>"+ - "<div class='ui label scope-left' style='color: %s !important; background-color: %s !important'>%s</div>"+ - "<div class='ui label scope-right' style='color: %s !important; background-color: %s !important'>%s</div>"+ - "</span>", - archivedCSSClass, description, - textColor, scopeColor, scopeText, - textColor, itemColor, itemText) - return template.HTML(s) + return HTMLFormat(`<span class="ui label %s scope-parent" data-tooltip-content title="%s">`+ + `<div class="ui label scope-left" style="color: %s !important; background-color: %s !important">%s</div>`+ + `<div class="ui label scope-right" style="color: %s !important; background-color: %s !important">%s</div>`+ + `</span>`, + extraCSSClasses, descriptionText, + textColor, scopeColor, scopeHTML, + textColor, itemColor, itemHTML) } // RenderEmoji renders html text with emoji post processors diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index de6ef9e93b..0c8363a168 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -2177,7 +2177,10 @@ func GetIssueInfo(ctx *context.Context) { } } - ctx.JSON(http.StatusOK, convert.ToIssue(ctx, ctx.Doer, issue)) + ctx.JSON(http.StatusOK, map[string]any{ + "convertedIssue": convert.ToIssue(ctx, ctx.Doer, issue), + "renderedLabels": templates.RenderLabels(ctx, ctx.Locale, issue.Labels, ctx.Repo.RepoLink, issue), + }) } // UpdateIssueTitle change issue's title diff --git a/tests/integration/issue_test.go b/tests/integration/issue_test.go index 44d362d9c7..b7952b0879 100644 --- a/tests/integration/issue_test.go +++ b/tests/integration/issue_test.go @@ -6,6 +6,7 @@ package integration import ( "context" "fmt" + "html/template" "net/http" "net/url" "path" @@ -573,10 +574,14 @@ func TestGetIssueInfo(t *testing.T) { urlStr := fmt.Sprintf("/%s/%s/issues/%d/info", owner.Name, repo.Name, issue.Index) req := NewRequest(t, "GET", urlStr) resp := session.MakeRequest(t, req, http.StatusOK) - var apiIssue api.Issue - DecodeJSON(t, resp, &apiIssue) + var respStruct struct { + ConvertedIssue api.Issue + RenderedLabels template.HTML + } + DecodeJSON(t, resp, &respStruct) - assert.EqualValues(t, issue.ID, apiIssue.ID) + assert.EqualValues(t, issue.ID, respStruct.ConvertedIssue.ID) + assert.Contains(t, string(respStruct.RenderedLabels), `"labels-list"`) } func TestUpdateIssueDeadline(t *testing.T) { diff --git a/web_src/js/components/ContextPopup.vue b/web_src/js/components/ContextPopup.vue index 65a6089522..e4e8bce184 100644 --- a/web_src/js/components/ContextPopup.vue +++ b/web_src/js/components/ContextPopup.vue @@ -1,6 +1,5 @@ <script> import {SvgIcon} from '../svg.js'; -import {contrastColor} from '../utils/color.js'; import {GET} from '../modules/fetch.js'; const {appSubUrl, i18n} = window.config; @@ -10,6 +9,7 @@ export default { data: () => ({ loading: false, issue: null, + renderedLabels: '', i18nErrorOccurred: i18n.error_occurred, i18nErrorMessage: null, }), @@ -56,14 +56,6 @@ export default { } return 'red'; // Closed Issue }, - - labels() { - return this.issue.labels.map((label) => ({ - name: label.name, - color: `#${label.color}`, - textColor: contrastColor(`#${label.color}`), - })); - }, }, mounted() { this.$refs.root.addEventListener('ce-load-context-popup', (e) => { @@ -79,13 +71,14 @@ export default { this.i18nErrorMessage = null; try { - const response = await GET(`${appSubUrl}/${data.owner}/${data.repo}/issues/${data.index}/info`); + const response = await GET(`${appSubUrl}/${data.owner}/${data.repo}/issues/${data.index}/info`); // backend: GetIssueInfo const respJson = await response.json(); if (!response.ok) { this.i18nErrorMessage = respJson.message ?? i18n.network_error; return; } - this.issue = respJson; + this.issue = respJson.convertedIssue; + this.renderedLabels = respJson.renderedLabels; } catch { this.i18nErrorMessage = i18n.network_error; } finally { @@ -102,16 +95,8 @@ export default { <p><small>{{ issue.repository.full_name }} on {{ createdAt }}</small></p> <p><svg-icon :name="icon" :class="['text', color]"/> <strong>{{ issue.title }}</strong> #{{ issue.number }}</p> <p>{{ body }}</p> - <div class="labels-list"> - <div - v-for="label in labels" - :key="label.name" - class="ui label" - :style="{ color: label.textColor, backgroundColor: label.color }" - > - {{ label.name }} - </div> - </div> + <!-- eslint-disable-next-line vue/no-v-html --> + <div v-html="renderedLabels"/> </div> <div v-if="!loading && issue === null"> <p><small>{{ i18nErrorOccurred }}</small></p> diff --git a/web_src/js/features/common-issue-list.js b/web_src/js/features/common-issue-list.js index 0c0f6c563d..219a8a9c9a 100644 --- a/web_src/js/features/common-issue-list.js +++ b/web_src/js/features/common-issue-list.js @@ -53,7 +53,7 @@ export function initCommonIssueListQuickGoto() { // try to check whether the parsed goto link is valid let targetUrl = parseIssueListQuickGotoLink(repoLink, searchText); if (targetUrl) { - const res = await GET(`${targetUrl}/info`); + const res = await GET(`${targetUrl}/info`); // backend: GetIssueInfo, it only checks whether the issue exists by status code if (res.status !== 200) targetUrl = ''; } // if the input value has changed, then ignore the result From 7ad50313284db7eec565ad1750108de1444c5a84 Mon Sep 17 00:00:00 2001 From: Zettat123 <zettat123@gmail.com> Date: Tue, 30 Apr 2024 11:53:16 +0800 Subject: [PATCH 241/370] Fix duplicate status check contexts (#30660) Caused by #30076. There may be some duplicate status check contexts when setting status checks for a branch protection rule. The duplicate contexts should be removed. Before: <img src="https://github.com/go-gitea/gitea/assets/15528715/97f4de2d-4868-47a3-8a99-5a180f9ac0a3" width="600px" /> After: <img src="https://github.com/go-gitea/gitea/assets/15528715/ff7289c5-9793-4090-ba31-e8cb3c85f8a3" width="600px" /> --- models/git/commit_status.go | 30 +++-------------- models/git/commit_status_test.go | 56 ++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 25 deletions(-) diff --git a/models/git/commit_status.go b/models/git/commit_status.go index c3cda7b73d..d12afc42c5 100644 --- a/models/git/commit_status.go +++ b/models/git/commit_status.go @@ -397,36 +397,16 @@ func GetLatestCommitStatusForRepoCommitIDs(ctx context.Context, repoID int64, co // FindRepoRecentCommitStatusContexts returns repository's recent commit status contexts func FindRepoRecentCommitStatusContexts(ctx context.Context, repoID int64, before time.Duration) ([]string, error) { - type result struct { - Index int64 - SHA string - } - getBase := func() *xorm.Session { - return db.GetEngine(ctx).Table(&CommitStatus{}).Where("repo_id = ?", repoID) - } - start := timeutil.TimeStampNow().AddDuration(-before) - results := make([]result, 0, 10) - sess := getBase().And("updated_unix >= ?", start). - Select("max( `index` ) as `index`, sha"). - GroupBy("context_hash, sha").OrderBy("max( `index` ) desc") - - err := sess.Find(&results) - if err != nil { + var contexts []string + if err := db.GetEngine(ctx).Table("commit_status"). + Where("repo_id = ?", repoID).And("updated_unix >= ?", start). + Cols("context").Distinct().Find(&contexts); err != nil { return nil, err } - contexts := make([]string, 0, len(results)) - if len(results) == 0 { - return contexts, nil - } - - conds := make([]builder.Cond, 0, len(results)) - for _, result := range results { - conds = append(conds, builder.Eq{"`index`": result.Index, "sha": result.SHA}) - } - return contexts, getBase().And(builder.Or(conds...)).Select("context").Find(&contexts) + return contexts, nil } // NewCommitStatusOptions holds options for creating a CommitStatus diff --git a/models/git/commit_status_test.go b/models/git/commit_status_test.go index 74ba4a1006..08eba6e293 100644 --- a/models/git/commit_status_test.go +++ b/models/git/commit_status_test.go @@ -5,11 +5,15 @@ package git_test import ( "testing" + "time" "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" + 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/structs" "github.com/stretchr/testify/assert" @@ -175,3 +179,55 @@ func Test_CalcCommitStatus(t *testing.T) { assert.Equal(t, kase.expected, git_model.CalcCommitStatus(kase.statuses)) } } + +func TestFindRepoRecentCommitStatusContexts(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo2) + assert.NoError(t, err) + defer gitRepo.Close() + + commit, err := gitRepo.GetBranchCommit(repo2.DefaultBranch) + assert.NoError(t, err) + + defer func() { + _, err := db.DeleteByBean(db.DefaultContext, &git_model.CommitStatus{ + RepoID: repo2.ID, + CreatorID: user2.ID, + SHA: commit.ID.String(), + }) + assert.NoError(t, err) + }() + + err = git_model.NewCommitStatus(db.DefaultContext, git_model.NewCommitStatusOptions{ + Repo: repo2, + Creator: user2, + SHA: commit.ID, + CommitStatus: &git_model.CommitStatus{ + State: structs.CommitStatusFailure, + TargetURL: "https://example.com/tests/", + Context: "compliance/lint-backend", + }, + }) + assert.NoError(t, err) + + err = git_model.NewCommitStatus(db.DefaultContext, git_model.NewCommitStatusOptions{ + Repo: repo2, + Creator: user2, + SHA: commit.ID, + CommitStatus: &git_model.CommitStatus{ + State: structs.CommitStatusSuccess, + TargetURL: "https://example.com/tests/", + Context: "compliance/lint-backend", + }, + }) + assert.NoError(t, err) + + contexts, err := git_model.FindRepoRecentCommitStatusContexts(db.DefaultContext, repo2.ID, time.Hour) + assert.NoError(t, err) + if assert.Len(t, contexts, 1) { + assert.Equal(t, "compliance/lint-backend", contexts[0]) + } +} From 059b2718a5615c01b897283f6ae53c9702f11239 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Tue, 30 Apr 2024 12:26:13 +0800 Subject: [PATCH 242/370] Right align the "Settings" menu item in overflow-menu (#30764) I guess there could be enough people liking to make the Settings menu item right aligned. As a site admin, I found it's easier to find the right-aligned Settings menu item. Tested with various sizes:    --- templates/org/menu.tmpl | 3 ++- templates/repo/header.tmpl | 1 + web_src/css/base.css | 17 ++++++++++++ web_src/css/modules/container.css | 32 ----------------------- web_src/js/webcomponents/overflow-menu.js | 24 +++++++++++++---- 5 files changed, 39 insertions(+), 38 deletions(-) diff --git a/templates/org/menu.tmpl b/templates/org/menu.tmpl index c519606d1f..698a9559c5 100644 --- a/templates/org/menu.tmpl +++ b/templates/org/menu.tmpl @@ -40,8 +40,9 @@ </a> {{end}} {{if .IsOrganizationOwner}} + <span class="item-flex-space"></span> <a class="{{if .PageIsOrgSettings}}active {{end}}item" href="{{.OrgLink}}/settings"> - {{svg "octicon-tools"}} {{ctx.Locale.Tr "repo.settings"}} + {{svg "octicon-tools"}} {{ctx.Locale.Tr "repo.settings"}} </a> {{end}} </div> diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index 775aa30063..c0d833a187 100644 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -216,6 +216,7 @@ {{template "custom/extra_tabs" .}} {{if .Permission.IsAdmin}} + <span class="item-flex-space"></span> <a class="{{if .PageIsRepoSettings}}active {{end}} item" href="{{.RepoLink}}/settings"> {{svg "octicon-tools"}} {{ctx.Locale.Tr "repo.settings"}} </a> diff --git a/web_src/css/base.css b/web_src/css/base.css index df9028b50a..1d65bb37e7 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -938,6 +938,23 @@ overflow-menu .overflow-menu-items .item { margin-bottom: 0 !important; /* reset fomantic's margin, because the active menu has special bottom border */ } +overflow-menu .overflow-menu-items .item-flex-space { + flex: 1; +} + +overflow-menu .overflow-menu-button { + background: transparent; + border: none; + color: inherit; + text-align: center; + width: 32px; + padding: 0; +} + +overflow-menu .overflow-menu-button:hover { + color: var(--color-text-dark); +} + overflow-menu .ui.label { margin-left: 7px !important; /* save some space */ } diff --git a/web_src/css/modules/container.css b/web_src/css/modules/container.css index f394d6c06d..9f67ceb8d5 100644 --- a/web_src/css/modules/container.css +++ b/web_src/css/modules/container.css @@ -6,38 +6,6 @@ max-width: 100%; } -@media (max-width: 767.98px) { - .ui.ui.ui.container:not(.fluid) { - width: auto; - margin-left: 1em; - margin-right: 1em; - } -} - -@media (min-width: 768px) and (max-width: 991.98px) { - .ui.ui.ui.container:not(.fluid) { - width: 723px; - margin-left: auto; - margin-right: auto; - } -} - -@media (min-width: 992px) and (max-width: 1199.98px) { - .ui.ui.ui.container:not(.fluid) { - width: 933px; - margin-left: auto; - margin-right: auto; - } -} - -@media (min-width: 1200px) { - .ui.ui.ui.container:not(.fluid) { - width: 1127px; - margin-left: auto; - margin-right: auto; - } -} - .ui.fluid.container { width: 100%; } diff --git a/web_src/js/webcomponents/overflow-menu.js b/web_src/js/webcomponents/overflow-menu.js index 604fce7d4b..0778c5990f 100644 --- a/web_src/js/webcomponents/overflow-menu.js +++ b/web_src/js/webcomponents/overflow-menu.js @@ -8,7 +8,7 @@ window.customElements.define('overflow-menu', class extends HTMLElement { if (!this.tippyContent) { const div = document.createElement('div'); div.classList.add('tippy-target'); - div.tabIndex = '-1'; // for initial focus, programmatic focus only + div.tabIndex = -1; // for initial focus, programmatic focus only div.addEventListener('keydown', (e) => { if (e.key === 'Tab') { const items = this.tippyContent.querySelectorAll('[role="menuitem"]'); @@ -60,21 +60,35 @@ window.customElements.define('overflow-menu', class extends HTMLElement { this.tippyContent = div; } + const itemFlexSpace = this.menuItemsEl.querySelector('.item-flex-space'); + // move items in tippy back into the menu items for subsequent measurement for (const item of this.tippyItems || []) { - this.menuItemsEl.append(item); + if (!itemFlexSpace || item.getAttribute('data-after-flex-space')) { + this.menuItemsEl.append(item); + } else { + itemFlexSpace.insertAdjacentElement('beforebegin', item); + } } // measure which items are partially outside the element and move them into the button menu + itemFlexSpace?.style.setProperty('display', 'none', 'important'); this.tippyItems = []; const menuRight = this.offsetLeft + this.offsetWidth; - const menuItems = this.menuItemsEl.querySelectorAll('.item'); + const menuItems = this.menuItemsEl.querySelectorAll('.item, .item-flex-space'); + let afterFlexSpace = false; for (const item of menuItems) { + if (item.classList.contains('item-flex-space')) { + afterFlexSpace = true; + continue; + } + if (afterFlexSpace) item.setAttribute('data-after-flex-space', 'true'); const itemRight = item.offsetLeft + item.offsetWidth; - if (menuRight - itemRight < 38) { // roughly the width of .overflow-menu-button + if (menuRight - itemRight < 38) { // roughly the width of .overflow-menu-button with some extra space this.tippyItems.push(item); } } + itemFlexSpace?.style.removeProperty('display'); // if there are no overflown items, remove any previously created button if (!this.tippyItems?.length) { @@ -105,7 +119,7 @@ window.customElements.define('overflow-menu', class extends HTMLElement { // create button initially const btn = document.createElement('button'); - btn.classList.add('overflow-menu-button', 'btn', 'tw-px-2', 'hover:tw-text-text-dark'); + btn.classList.add('overflow-menu-button'); btn.setAttribute('aria-label', window.config.i18n.more_items); btn.innerHTML = octiconKebabHorizontal; this.append(btn); From f2d8ccc5bb2df25557cc0d4d23f2cdd029358274 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 30 Apr 2024 10:43:08 +0200 Subject: [PATCH 243/370] Get repo assignees and reviewers should ignore deactivated users (#30770) If an user is deactivated, it should not be in the list of users who are suggested to be assigned or review-requested. old assignees or reviewers are not affected. --- *Sponsored by Kithara Software GmbH* --- models/repo/user_repo.go | 8 ++++++-- models/repo/user_repo_test.go | 22 +++++++++++++++++----- tests/integration/api_repo_test.go | 4 +++- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/models/repo/user_repo.go b/models/repo/user_repo.go index 1c5412fe7d..c305603e02 100644 --- a/models/repo/user_repo.go +++ b/models/repo/user_repo.go @@ -130,7 +130,10 @@ func GetRepoAssignees(ctx context.Context, repo *Repository) (_ []*user_model.Us // and just waste 1 unit is cheaper than re-allocate memory once. users := make([]*user_model.User, 0, len(uniqueUserIDs)+1) if len(userIDs) > 0 { - if err = e.In("id", uniqueUserIDs.Values()).OrderBy(user_model.GetOrderByName()).Find(&users); err != nil { + if err = e.In("id", uniqueUserIDs.Values()). + Where(builder.Eq{"`user`.is_active": true}). + OrderBy(user_model.GetOrderByName()). + Find(&users); err != nil { return nil, err } } @@ -152,7 +155,8 @@ func GetReviewers(ctx context.Context, repo *Repository, doerID, posterID int64) return nil, err } - cond := builder.And(builder.Neq{"`user`.id": posterID}) + cond := builder.And(builder.Neq{"`user`.id": posterID}). + And(builder.Eq{"`user`.is_active": true}) if repo.IsPrivate || repo.Owner.Visibility == api.VisibleTypePrivate { // This a private repository: diff --git a/models/repo/user_repo_test.go b/models/repo/user_repo_test.go index 591dcea5b5..d2bf6dc912 100644 --- a/models/repo/user_repo_test.go +++ b/models/repo/user_repo_test.go @@ -9,6 +9,7 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" "github.com/stretchr/testify/assert" ) @@ -25,8 +26,17 @@ func TestRepoAssignees(t *testing.T) { repo21 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 21}) users, err = repo_model.GetRepoAssignees(db.DefaultContext, repo21) assert.NoError(t, err) - assert.Len(t, users, 4) - assert.ElementsMatch(t, []int64{10, 15, 16, 18}, []int64{users[0].ID, users[1].ID, users[2].ID, users[3].ID}) + if assert.Len(t, users, 4) { + assert.ElementsMatch(t, []int64{10, 15, 16, 18}, []int64{users[0].ID, users[1].ID, users[2].ID, users[3].ID}) + } + + // do not return deactivated users + assert.NoError(t, user_model.UpdateUserCols(db.DefaultContext, &user_model.User{ID: 15, IsActive: false}, "is_active")) + users, err = repo_model.GetRepoAssignees(db.DefaultContext, repo21) + assert.NoError(t, err) + if assert.Len(t, users, 3) { + assert.NotContains(t, []int64{users[0].ID, users[1].ID, users[2].ID}, 15) + } } func TestRepoGetReviewers(t *testing.T) { @@ -38,17 +48,19 @@ func TestRepoGetReviewers(t *testing.T) { ctx := db.DefaultContext reviewers, err := repo_model.GetReviewers(ctx, repo1, 2, 2) assert.NoError(t, err) - assert.Len(t, reviewers, 4) + if assert.Len(t, reviewers, 3) { + assert.ElementsMatch(t, []int64{1, 4, 11}, []int64{reviewers[0].ID, reviewers[1].ID, reviewers[2].ID}) + } // should include doer if doer is not PR poster. reviewers, err = repo_model.GetReviewers(ctx, repo1, 11, 2) assert.NoError(t, err) - assert.Len(t, reviewers, 4) + assert.Len(t, reviewers, 3) // should not include PR poster, if PR poster would be otherwise eligible reviewers, err = repo_model.GetReviewers(ctx, repo1, 11, 4) assert.NoError(t, err) - assert.Len(t, reviewers, 3) + assert.Len(t, reviewers, 2) // test private user repo repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) diff --git a/tests/integration/api_repo_test.go b/tests/integration/api_repo_test.go index bc2720d51e..f33827e58b 100644 --- a/tests/integration/api_repo_test.go +++ b/tests/integration/api_repo_test.go @@ -684,7 +684,9 @@ func TestAPIRepoGetReviewers(t *testing.T) { resp := MakeRequest(t, req, http.StatusOK) var reviewers []*api.User DecodeJSON(t, resp, &reviewers) - assert.Len(t, reviewers, 4) + if assert.Len(t, reviewers, 3) { + assert.ElementsMatch(t, []int64{1, 4, 11}, []int64{reviewers[0].ID, reviewers[1].ID, reviewers[2].ID}) + } } func TestAPIRepoGetAssignees(t *testing.T) { From 610802df85933e7a190a705bc3f7800da87ce868 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Tue, 30 Apr 2024 14:34:40 +0200 Subject: [PATCH 244/370] Fix tautological conditions (#30735) As discovered by https://github.com/go-gitea/gitea/pull/30729. --------- Co-authored-by: Giteabot <teabot@gitea.io> --- modules/indexer/code/indexer.go | 6 ------ routers/private/hook_post_receive.go | 18 ++++++++---------- services/auth/source/oauth2/providers.go | 2 +- services/convert/issue.go | 14 ++++++++------ tests/integration/git_test.go | 9 +++------ 5 files changed, 20 insertions(+), 29 deletions(-) diff --git a/modules/indexer/code/indexer.go b/modules/indexer/code/indexer.go index ebebf6ba8a..c1ab26569c 100644 --- a/modules/indexer/code/indexer.go +++ b/modules/indexer/code/indexer.go @@ -178,12 +178,6 @@ func Init() { }() rIndexer = elasticsearch.NewIndexer(setting.Indexer.RepoConnStr, setting.Indexer.RepoIndexerName) - if err != nil { - cancel() - (*globalIndexer.Load()).Close() - close(waitChannel) - log.Fatal("PID: %d Unable to create the elasticsearch Repository Indexer connstr: %s Error: %v", os.Getpid(), setting.Indexer.RepoConnStr, err) - } existed, err = rIndexer.Init(ctx) if err != nil { cancel() diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index 769a68970d..adc435b42c 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -117,16 +117,14 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { } } if len(branchesToSync) > 0 { - if gitRepo == nil { - var err error - gitRepo, err = gitrepo.OpenRepository(ctx, repo) - if err != nil { - log.Error("Failed to open repository: %s/%s Error: %v", ownerName, repoName, err) - ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{ - Err: fmt.Sprintf("Failed to open repository: %s/%s Error: %v", ownerName, repoName, err), - }) - return - } + var err error + gitRepo, err = gitrepo.OpenRepository(ctx, repo) + if err != nil { + log.Error("Failed to open repository: %s/%s Error: %v", ownerName, repoName, err) + ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{ + Err: fmt.Sprintf("Failed to open repository: %s/%s Error: %v", ownerName, repoName, err), + }) + return } var ( diff --git a/services/auth/source/oauth2/providers.go b/services/auth/source/oauth2/providers.go index 6ed6c184eb..f2c1bb4894 100644 --- a/services/auth/source/oauth2/providers.go +++ b/services/auth/source/oauth2/providers.go @@ -182,7 +182,7 @@ func createProvider(providerName string, source *Source) (goth.Provider, error) } // always set the name if provider is created so we can support multiple setups of 1 provider - if err == nil && provider != nil { + if provider != nil { provider.SetName(providerName) } diff --git a/services/convert/issue.go b/services/convert/issue.go index 54b00cd88e..668affe09a 100644 --- a/services/convert/issue.go +++ b/services/convert/issue.go @@ -211,13 +211,11 @@ func ToLabel(label *issues_model.Label, repo *repo_model.Repository, org *user_m IsArchived: label.IsArchived(), } + labelBelongsToRepo := label.BelongsToRepo() + // calculate URL - if label.BelongsToRepo() && repo != nil { - if repo != nil { - result.URL = fmt.Sprintf("%s/labels/%d", repo.APIURL(), label.ID) - } else { - log.Error("ToLabel did not get repo to calculate url for label with id '%d'", label.ID) - } + if labelBelongsToRepo && repo != nil { + result.URL = fmt.Sprintf("%s/labels/%d", repo.APIURL(), label.ID) } else { // BelongsToOrg if org != nil { result.URL = fmt.Sprintf("%sapi/v1/orgs/%s/labels/%d", setting.AppURL, url.PathEscape(org.Name), label.ID) @@ -226,6 +224,10 @@ func ToLabel(label *issues_model.Label, repo *repo_model.Repository, org *user_m } } + if labelBelongsToRepo && repo == nil { + log.Error("ToLabel did not get repo to calculate url for label with id '%d'", label.ID) + } + return result } diff --git a/tests/integration/git_test.go b/tests/integration/git_test.go index 74c511fd7e..8a091ecab7 100644 --- a/tests/integration/git_test.go +++ b/tests/integration/git_test.go @@ -81,7 +81,7 @@ func testGit(t *testing.T, u *url.URL) { rawTest(t, &httpContext, little, big, littleLFS, bigLFS) mediaTest(t, &httpContext, little, big, littleLFS, bigLFS) - t.Run("CreateAgitFlowPull", doCreateAgitFlowPull(dstPath, &httpContext, "master", "test/head")) + t.Run("CreateAgitFlowPull", doCreateAgitFlowPull(dstPath, &httpContext, "test/head")) t.Run("BranchProtectMerge", doBranchProtectPRMerge(&httpContext, dstPath)) t.Run("AutoMerge", doAutoPRMerge(&httpContext, dstPath)) t.Run("CreatePRAndSetManuallyMerged", doCreatePRAndSetManuallyMerged(httpContext, httpContext, dstPath, "master", "test-manually-merge")) @@ -122,7 +122,7 @@ func testGit(t *testing.T, u *url.URL) { rawTest(t, &sshContext, little, big, littleLFS, bigLFS) mediaTest(t, &sshContext, little, big, littleLFS, bigLFS) - t.Run("CreateAgitFlowPull", doCreateAgitFlowPull(dstPath, &sshContext, "master", "test/head2")) + t.Run("CreateAgitFlowPull", doCreateAgitFlowPull(dstPath, &sshContext, "test/head2")) t.Run("BranchProtectMerge", doBranchProtectPRMerge(&sshContext, dstPath)) t.Run("MergeFork", func(t *testing.T) { defer tests.PrintCurrentTest(t)() @@ -329,9 +329,6 @@ func generateCommitWithNewData(size int, repoPath, email, fullName, prefix strin } written += n } - if err != nil { - return "", err - } // Commit // Now here we should explicitly allow lfs filters to run @@ -693,7 +690,7 @@ func doAutoPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) { } } -func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headBranch string) func(t *testing.T) { +func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, headBranch string) func(t *testing.T) { return func(t *testing.T) { defer tests.PrintCurrentTest(t)() From 5f05e7b41a57972cc418a125d9263173b7b9838f Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Tue, 30 Apr 2024 20:39:36 +0800 Subject: [PATCH 245/370] Fix dashboard commit status null access (#30771) Fix #30768 --- web_src/js/components/DashboardRepoList.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web_src/js/components/DashboardRepoList.vue b/web_src/js/components/DashboardRepoList.vue index 2d980a1b18..8bce40ee79 100644 --- a/web_src/js/components/DashboardRepoList.vue +++ b/web_src/js/components/DashboardRepoList.vue @@ -251,9 +251,9 @@ const sfc = { this.repos = json.data.map((webSearchRepo) => { return { ...webSearchRepo.repository, - latest_commit_status_state: webSearchRepo.latest_commit_status.State, + latest_commit_status_state: webSearchRepo.latest_commit_status?.State, // if latest_commit_status is null, it means there is no commit status + latest_commit_status_state_link: webSearchRepo.latest_commit_status?.TargetURL, locale_latest_commit_status_state: webSearchRepo.locale_latest_commit_status, - latest_commit_status_state_link: webSearchRepo.latest_commit_status.TargetURL, }; }); const count = response.headers.get('X-Total-Count'); From 564102ce89f53d6bd2fdbaa33416e4287d6fe9a8 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Tue, 30 Apr 2024 16:52:46 +0200 Subject: [PATCH 246/370] Rework and fix stopwatch (#30732) Fixes https://github.com/go-gitea/gitea/issues/30721 and overhauls the stopwatch. Time is now shown inside the "dot" icon and on both mobile and desktop. All rendering is now done by `<relative-time>`, the `pretty-ms` dependency is dropped. Desktop: <img width="557" alt="Screenshot 2024-04-29 at 22 33 27" src="https://github.com/go-gitea/gitea/assets/115237/3a46cdbf-6af2-4bf9-b07f-021348badaac"> Mobile: <img width="640" alt="Screenshot 2024-04-29 at 22 34 19" src="https://github.com/go-gitea/gitea/assets/115237/8a2beea7-bd5d-473f-8fff-66f63fd50877"> Note for tippy: Previously, tippy instances defaulted to "menu" theme, but that theme is really only meant for `.ui.menu`, so it was not optimal for the stopwatch popover. This introduces a unopinionated `default` theme that has no padding and should be suitable for all content. I reviewed all existing uses and explicitely set the desired `theme` on all of them. --- package-lock.json | 26 ------- package.json | 1 - templates/base/head_navbar.tmpl | 69 ++++++++++--------- web_src/css/modules/navbar.css | 16 ++--- web_src/css/modules/tippy.css | 7 +- web_src/js/features/contextpopup.js | 2 + web_src/js/features/repo-code.js | 1 + web_src/js/features/repo-issue.js | 1 + web_src/js/features/stopwatch.js | 82 +++++++++++------------ web_src/js/modules/tippy.js | 6 +- web_src/js/webcomponents/overflow-menu.js | 1 + 11 files changed, 99 insertions(+), 113 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8e4eeb7fb8..917ff1029b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,7 +42,6 @@ "postcss": "8.4.38", "postcss-loader": "8.1.1", "postcss-nesting": "12.1.2", - "pretty-ms": "9.0.0", "sortablejs": "1.15.2", "swagger-ui-dist": "5.17.2", "tailwindcss": "3.4.3", @@ -9170,17 +9169,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parse-ms": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", - "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -9772,20 +9760,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/pretty-ms": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.0.0.tgz", - "integrity": "sha512-E9e9HJ9R9NasGOgPaPE8VMeiPKAyWR5jcFpNnwIejslIhWqdqOrb2wShBsncMPUb+BcCd2OPYfh7p2W6oemTng==", - "dependencies": { - "parse-ms": "^4.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/printable-characters": { "version": "1.0.42", "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz", diff --git a/package.json b/package.json index 142b9bb3ee..5f9b810320 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,6 @@ "postcss": "8.4.38", "postcss-loader": "8.1.1", "postcss-nesting": "12.1.2", - "pretty-ms": "9.0.0", "sortablejs": "1.15.2", "swagger-ui-dist": "5.17.2", "tailwindcss": "3.4.3", diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl index addff22c49..7a3e663c49 100644 --- a/templates/base/head_navbar.tmpl +++ b/templates/base/head_navbar.tmpl @@ -12,6 +12,14 @@ <!-- mobile right menu, it must be here because in mobile view, each item is a flex column, the first item is a full row column --> <div class="ui secondary menu item navbar-mobile-right only-mobile"> + {{if and .IsSigned EnableTimetracking .ActiveStopwatch}} + <a id="mobile-stopwatch-icon" class="active-stopwatch item tw-mx-0" href="{{.ActiveStopwatch.IssueLink}}" title="{{ctx.Locale.Tr "active_stopwatch"}}" data-seconds="{{.ActiveStopwatch.Seconds}}"> + <div class="tw-relative"> + {{svg "octicon-stopwatch"}} + <span class="header-stopwatch-dot"></span> + </div> + </a> + {{end}} {{if .IsSigned}} <a id="mobile-notifications-icon" class="item tw-w-auto tw-p-2" href="{{AppSubUrl}}/notifications" data-tooltip-content="{{ctx.Locale.Tr "notifications"}}" aria-label="{{ctx.Locale.Tr "notifications"}}"> <div class="tw-relative"> @@ -74,41 +82,13 @@ </div><!-- end content avatar menu --> </div><!-- end dropdown avatar menu --> {{else if .IsSigned}} - {{if EnableTimetracking}} - <a class="active-stopwatch-trigger item tw-mx-0{{if not .ActiveStopwatch}} tw-hidden{{end}}" href="{{.ActiveStopwatch.IssueLink}}" title="{{ctx.Locale.Tr "active_stopwatch"}}"> + {{if and EnableTimetracking .ActiveStopwatch}} + <a class="item not-mobile active-stopwatch tw-mx-0" href="{{.ActiveStopwatch.IssueLink}}" title="{{ctx.Locale.Tr "active_stopwatch"}}" data-seconds="{{.ActiveStopwatch.Seconds}}"> <div class="tw-relative"> {{svg "octicon-stopwatch"}} <span class="header-stopwatch-dot"></span> </div> - <span class="only-mobile tw-ml-2">{{ctx.Locale.Tr "active_stopwatch"}}</span> </a> - <div class="active-stopwatch-popup item tippy-target tw-p-2"> - <div class="tw-flex tw-items-center"> - <a class="stopwatch-link tw-flex tw-items-center" href="{{.ActiveStopwatch.IssueLink}}"> - {{svg "octicon-issue-opened" 16 "tw-mr-2"}} - <span class="stopwatch-issue">{{.ActiveStopwatch.RepoSlug}}#{{.ActiveStopwatch.IssueIndex}}</span> - <span class="ui primary label stopwatch-time tw-my-0 tw-mx-4" data-seconds="{{.ActiveStopwatch.Seconds}}"> - {{if .ActiveStopwatch}}{{Sec2Time .ActiveStopwatch.Seconds}}{{end}} - </span> - </a> - <form class="stopwatch-commit" method="post" action="{{.ActiveStopwatch.IssueLink}}/times/stopwatch/toggle"> - {{.CsrfTokenHtml}} - <button - type="submit" - class="ui button mini compact basic icon" - data-tooltip-content="{{ctx.Locale.Tr "repo.issues.stop_tracking"}}" - >{{svg "octicon-square-fill"}}</button> - </form> - <form class="stopwatch-cancel" method="post" action="{{.ActiveStopwatch.IssueLink}}/times/stopwatch/cancel"> - {{.CsrfTokenHtml}} - <button - type="submit" - class="ui button mini compact basic icon" - data-tooltip-content="{{ctx.Locale.Tr "repo.issues.cancel_tracking"}}" - >{{svg "octicon-trash"}}</button> - </form> - </div> - </div> {{end}} <a class="item not-mobile tw-mx-0" href="{{AppSubUrl}}/notifications" data-tooltip-content="{{ctx.Locale.Tr "notifications"}}" aria-label="{{ctx.Locale.Tr "notifications"}}"> @@ -202,4 +182,33 @@ </a> {{end}} </div><!-- end full right menu --> + + {{if and .IsSigned EnableTimetracking .ActiveStopwatch}} + <div class="active-stopwatch-popup tippy-target"> + <div class="tw-flex tw-items-center tw-gap-2 tw-p-3"> + <a class="stopwatch-link tw-flex tw-items-center tw-gap-2 muted" href="{{.ActiveStopwatch.IssueLink}}"> + {{svg "octicon-issue-opened" 16}} + <span class="stopwatch-issue">{{.ActiveStopwatch.RepoSlug}}#{{.ActiveStopwatch.IssueIndex}}</span> + </a> + <div class="tw-flex tw-gap-1"> + <form class="stopwatch-commit" method="post" action="{{.ActiveStopwatch.IssueLink}}/times/stopwatch/toggle"> + {{.CsrfTokenHtml}} + <button + type="submit" + class="ui button mini compact basic icon tw-mr-0" + data-tooltip-content="{{ctx.Locale.Tr "repo.issues.stop_tracking"}}" + >{{svg "octicon-square-fill"}}</button> + </form> + <form class="stopwatch-cancel" method="post" action="{{.ActiveStopwatch.IssueLink}}/times/stopwatch/cancel"> + {{.CsrfTokenHtml}} + <button + type="submit" + class="ui button mini compact basic icon tw-mr-0" + data-tooltip-content="{{ctx.Locale.Tr "repo.issues.cancel_tracking"}}" + >{{svg "octicon-trash"}}</button> + </form> + </div> + </div> + </div> + {{end}} </nav> diff --git a/web_src/css/modules/navbar.css b/web_src/css/modules/navbar.css index d7aa197e02..848f9331d0 100644 --- a/web_src/css/modules/navbar.css +++ b/web_src/css/modules/navbar.css @@ -103,19 +103,12 @@ width: 50%; min-height: 48px; } + #navbar #mobile-stopwatch-icon, #navbar #mobile-notifications-icon { margin-right: 6px !important; } } -#navbar a.item .notification_count { - color: var(--color-nav-bg); - padding: 0 3.75px; - font-size: 12px; - line-height: 12px; - font-weight: var(--font-weight-bold); -} - #navbar a.item:hover .notification_count, #navbar a.item:hover .header-stopwatch-dot { border-color: var(--color-nav-hover-bg); @@ -123,6 +116,11 @@ #navbar a.item .notification_count, #navbar a.item .header-stopwatch-dot { + color: var(--color-nav-bg); + padding: 0 3.75px; + font-size: 12px; + line-height: 12px; + font-weight: var(--font-weight-bold); background: var(--color-primary); border: 2px solid var(--color-nav-bg); position: absolute; @@ -135,6 +133,8 @@ align-items: center; justify-content: center; z-index: 1; /* prevent menu button background from overlaying icon */ + user-select: none; + white-space: nowrap; } .secondary-nav { diff --git a/web_src/css/modules/tippy.css b/web_src/css/modules/tippy.css index 6ac7c37d93..53c3d5aaea 100644 --- a/web_src/css/modules/tippy.css +++ b/web_src/css/modules/tippy.css @@ -16,8 +16,8 @@ .tippy-box { position: relative; - background-color: var(--color-body); - color: var(--color-secondary-dark-6); + background-color: var(--color-menu); + color: var(--color-text); border: 1px solid var(--color-secondary); border-radius: var(--border-radius); font-size: 1rem; @@ -25,7 +25,6 @@ .tippy-content { position: relative; - padding: 1rem; /* if you need different padding, use different data-theme */ z-index: 1; } @@ -166,5 +165,5 @@ } .tippy-svg-arrow-inner { - fill: var(--color-body); + fill: var(--color-menu); } diff --git a/web_src/js/features/contextpopup.js b/web_src/js/features/contextpopup.js index ce90f3e505..6a9325ed1c 100644 --- a/web_src/js/features/contextpopup.js +++ b/web_src/js/features/contextpopup.js @@ -18,6 +18,7 @@ export function attachRefIssueContextPopup(refIssues) { if (!owner) return; const el = document.createElement('div'); + el.classList.add('tw-p-3'); refIssue.parentNode.insertBefore(el, refIssue.nextSibling); const view = createApp(ContextPopup); @@ -30,6 +31,7 @@ export function attachRefIssueContextPopup(refIssues) { } createTippy(refIssue, { + theme: 'default', content: el, placement: 'top-start', interactive: true, diff --git a/web_src/js/features/repo-code.js b/web_src/js/features/repo-code.js index 63da5f2039..7c74c253a2 100644 --- a/web_src/js/features/repo-code.js +++ b/web_src/js/features/repo-code.js @@ -113,6 +113,7 @@ function showLineButton() { btn.closest('.code-view').append(menu.cloneNode(true)); createTippy(btn, { + theme: 'menu', trigger: 'click', hideOnClick: true, content: menu, diff --git a/web_src/js/features/repo-issue.js b/web_src/js/features/repo-issue.js index 2b2eed58bb..c4e14c62c4 100644 --- a/web_src/js/features/repo-issue.js +++ b/web_src/js/features/repo-issue.js @@ -502,6 +502,7 @@ export function initRepoPullRequestReview() { if ($reviewBtn.length && $panel.length) { const tippy = createTippy($reviewBtn[0], { content: $panel[0], + theme: 'default', placement: 'bottom', trigger: 'click', maxWidth: 'none', diff --git a/web_src/js/features/stopwatch.js b/web_src/js/features/stopwatch.js index 2ec74344fc..bcea26bd6e 100644 --- a/web_src/js/features/stopwatch.js +++ b/web_src/js/features/stopwatch.js @@ -1,4 +1,3 @@ -import prettyMilliseconds from 'pretty-ms'; import {createTippy} from '../modules/tippy.js'; import {GET} from '../modules/fetch.js'; import {hideElem, showElem} from '../utils/dom.js'; @@ -10,28 +9,31 @@ export function initStopwatch() { return; } - const stopwatchEl = document.querySelector('.active-stopwatch-trigger'); + const stopwatchEls = document.querySelectorAll('.active-stopwatch'); const stopwatchPopup = document.querySelector('.active-stopwatch-popup'); - if (!stopwatchEl || !stopwatchPopup) { + if (!stopwatchEls.length || !stopwatchPopup) { return; } - stopwatchEl.removeAttribute('href'); // intended for noscript mode only - - createTippy(stopwatchEl, { - content: stopwatchPopup, - placement: 'bottom-end', - trigger: 'click', - maxWidth: 'none', - interactive: true, - hideOnClick: true, - }); - // global stop watch (in the head_navbar), it should always work in any case either the EventSource or the PeriodicPoller is used. - const currSeconds = document.querySelector('.stopwatch-time')?.getAttribute('data-seconds'); - if (currSeconds) { - updateStopwatchTime(currSeconds); + const seconds = stopwatchEls[0]?.getAttribute('data-seconds'); + if (seconds) { + updateStopwatchTime(parseInt(seconds)); + } + + for (const stopwatchEl of stopwatchEls) { + stopwatchEl.removeAttribute('href'); // intended for noscript mode only + + createTippy(stopwatchEl, { + content: stopwatchPopup.cloneNode(true), + placement: 'bottom-end', + trigger: 'click', + maxWidth: 'none', + interactive: true, + hideOnClick: true, + theme: 'default', + }); } let usingPeriodicPoller = false; @@ -124,10 +126,9 @@ async function updateStopwatch() { function updateStopwatchData(data) { const watch = data[0]; - const btnEl = document.querySelector('.active-stopwatch-trigger'); + const btnEls = document.querySelectorAll('.active-stopwatch'); if (!watch) { - clearStopwatchTimer(); - hideElem(btnEl); + hideElem(btnEls); } else { const {repo_owner_name, repo_name, issue_index, seconds} = watch; const issueUrl = `${appSubUrl}/${repo_owner_name}/${repo_name}/issues/${issue_index}`; @@ -137,31 +138,28 @@ function updateStopwatchData(data) { const stopwatchIssue = document.querySelector('.stopwatch-issue'); if (stopwatchIssue) stopwatchIssue.textContent = `${repo_owner_name}/${repo_name}#${issue_index}`; updateStopwatchTime(seconds); - showElem(btnEl); + showElem(btnEls); } return Boolean(data.length); } -let updateTimeIntervalId = null; // holds setInterval id when active -function clearStopwatchTimer() { - if (updateTimeIntervalId !== null) { - clearInterval(updateTimeIntervalId); - updateTimeIntervalId = null; +// TODO: This flickers on page load, we could avoid this by making a custom +// element to render time periods. Feeding a datetime in backend does not work +// when time zone between server and client differs. +function updateStopwatchTime(seconds) { + if (!Number.isFinite(seconds)) return; + const datetime = (new Date(Date.now() - seconds * 1000)).toISOString(); + for (const parent of document.querySelectorAll('.header-stopwatch-dot')) { + const existing = parent.querySelector(':scope > relative-time'); + if (existing) { + existing.setAttribute('datetime', datetime); + } else { + const el = document.createElement('relative-time'); + el.setAttribute('format', 'micro'); + el.setAttribute('datetime', datetime); + el.setAttribute('lang', 'en-US'); + el.setAttribute('title', ''); // make <relative-time> show no title and therefor no tooltip + parent.append(el); + } } } -function updateStopwatchTime(seconds) { - const secs = parseInt(seconds); - if (!Number.isFinite(secs)) return; - - clearStopwatchTimer(); - const stopwatch = document.querySelector('.stopwatch-time'); - // TODO: replace with <relative-time> similar to how system status up time is shown - const start = Date.now(); - const updateUi = () => { - const delta = Date.now() - start; - const dur = prettyMilliseconds(secs * 1000 + delta, {compact: true}); - if (stopwatch) stopwatch.textContent = dur; - }; - updateUi(); - updateTimeIntervalId = setInterval(updateUi, 1000); -} diff --git a/web_src/js/modules/tippy.js b/web_src/js/modules/tippy.js index 83b28e5745..a18c94cafb 100644 --- a/web_src/js/modules/tippy.js +++ b/web_src/js/modules/tippy.js @@ -37,8 +37,10 @@ export function createTippy(target, opts = {}) { return onShow?.(instance); }, arrow: arrow || (theme === 'bare' ? false : arrowSvg), - role: role || 'menu', // HTML role attribute - theme: theme || role || 'menu', // CSS theme, either "tooltip", "menu", "box-with-header" or "bare" + // HTML role attribute, ideally the default role would be "popover" but it does not exist + role: role || 'menu', + // CSS theme, either "default", "tooltip", "menu", "box-with-header" or "bare" + theme: theme || role || 'default', plugins: [followCursor], ...other, }); diff --git a/web_src/js/webcomponents/overflow-menu.js b/web_src/js/webcomponents/overflow-menu.js index 0778c5990f..80dd1a545b 100644 --- a/web_src/js/webcomponents/overflow-menu.js +++ b/web_src/js/webcomponents/overflow-menu.js @@ -131,6 +131,7 @@ window.customElements.define('overflow-menu', class extends HTMLElement { interactive: true, placement: 'bottom-end', role: 'menu', + theme: 'menu', content: this.tippyContent, onShow: () => { // FIXME: onShown doesn't work (never be called) setTimeout(() => { From a988237eb43fe0b68465c4c965f869b51d0c60ea Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Tue, 30 Apr 2024 23:35:42 +0800 Subject: [PATCH 247/370] Improve logout from worker (#30775) A quick fix for #30756 --- web_src/js/features/notification.js | 3 ++- web_src/js/features/stopwatch.js | 3 ++- web_src/js/modules/worker.js | 9 +++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 web_src/js/modules/worker.js diff --git a/web_src/js/features/notification.js b/web_src/js/features/notification.js index 2de640e674..8e5a1f83db 100644 --- a/web_src/js/features/notification.js +++ b/web_src/js/features/notification.js @@ -1,6 +1,7 @@ import $ from 'jquery'; import {GET} from '../modules/fetch.js'; import {toggleElem} from '../utils/dom.js'; +import {logoutFromWorker} from '../modules/worker.js'; const {appSubUrl, notificationSettings, assetVersionEncoded} = window.config; let notificationSequenceNumber = 0; @@ -95,7 +96,7 @@ export function initNotificationCount() { type: 'close', }); worker.port.close(); - window.location.href = `${appSubUrl}/`; + logoutFromWorker(); } else if (event.data.type === 'close') { worker.port.postMessage({ type: 'close', diff --git a/web_src/js/features/stopwatch.js b/web_src/js/features/stopwatch.js index bcea26bd6e..79d9892b74 100644 --- a/web_src/js/features/stopwatch.js +++ b/web_src/js/features/stopwatch.js @@ -1,6 +1,7 @@ import {createTippy} from '../modules/tippy.js'; import {GET} from '../modules/fetch.js'; import {hideElem, showElem} from '../utils/dom.js'; +import {logoutFromWorker} from '../modules/worker.js'; const {appSubUrl, notificationSettings, enableTimeTracking, assetVersionEncoded} = window.config; @@ -77,7 +78,7 @@ export function initStopwatch() { type: 'close', }); worker.port.close(); - window.location.href = `${appSubUrl}/`; + logoutFromWorker(); } else if (event.data.type === 'close') { worker.port.postMessage({ type: 'close', diff --git a/web_src/js/modules/worker.js b/web_src/js/modules/worker.js new file mode 100644 index 0000000000..ef3f1dea48 --- /dev/null +++ b/web_src/js/modules/worker.js @@ -0,0 +1,9 @@ +import {sleep} from '../utils.js'; + +const {appSubUrl} = window.config; + +export async function logoutFromWorker() { + // wait for a while because other requests (eg: logout) may be in the flight + await sleep(5000); + window.location.href = `${appSubUrl}/`; +} From d8d46d1c483390da746d7a60edd2ace18a66c933 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Wed, 1 May 2024 00:26:38 +0000 Subject: [PATCH 248/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_pt-PT.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index c711c72045..7d799a20ba 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -3495,6 +3495,7 @@ npm.install=Para instalar o pacote usando o npm, execute o seguinte comando: npm.install2=ou adicione-o ao ficheiro <code>package.json</code>: npm.dependencies=Dependências npm.dependencies.development=Dependências de desenvolvimento +npm.dependencies.bundle=Dependências agregadas npm.dependencies.peer=Dependências de pares npm.dependencies.optional=Dependências opcionais npm.details.tag=Etiqueta From 6709e28da78a0ea7e63f9fe4e32f620abdc88d14 Mon Sep 17 00:00:00 2001 From: Chester <chesterip0510@gmail.com> Date: Wed, 1 May 2024 09:40:23 +0800 Subject: [PATCH 249/370] Add API endpoints for getting action jobs status (#26673) Sample of response, it is similar to Github actions ref https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#list-workflow-runs-for-a-repository ``` json { "workflow_runs": [ { "id": 3, "name": "Explore-Gitea-Actions", "head_branch": "main", "head_sha": "6d8d29a9f7a01ded8f8aeb64341cb31ee1ab5f19", "run_number": 3, "event": "push", "display_title": "More job", "status": "success", "workflow_id": "demo2.yaml", "url": "/chester/test/actions/runs/3", "created_at": "2023-08-22T13:41:33-04:00", "updated_at": "2023-08-22T13:41:37-04:00", "run_started_at": "2023-08-22T13:41:33-04:00" }, { "id": 2, "name": "Explore-Gitea-Actions", "head_branch": "main", "head_sha": "6d8d29a9f7a01ded8f8aeb64341cb31ee1ab5f19", "run_number": 2, "event": "push", "display_title": "More job", "status": "success", "workflow_id": "demo.yaml", "url": "/chester/test/actions/runs/2", "created_at": "2023-08-22T13:41:30-04:00", "updated_at": "2023-08-22T13:41:33-04:00", "run_started_at": "2023-08-22T13:41:30-04:00" }, { "id": 1, "name": "Explore-Gitea-Actions", "head_branch": "main", "head_sha": "e5369ab054cae79899ba36e45ee82811a6e0acd5", "run_number": 1, "event": "push", "display_title": "Add job", "status": "failure", "workflow_id": "demo.yaml", "url": "/chester/test/actions/runs/1", "created_at": "2023-08-22T13:15:21-04:00", "updated_at": "2023-08-22T13:18:10-04:00", "run_started_at": "2023-08-22T13:15:21-04:00" } ], "total_count": 3 } ``` --------- Co-authored-by: yp05327 <576951401@qq.com> Co-authored-by: puni9869 <80308335+puni9869@users.noreply.github.com> --- modules/structs/repo_actions.go | 34 ++++++++ routers/api/v1/api.go | 3 + routers/api/v1/repo/actions.go | 80 +++++++++++++++++ routers/api/v1/swagger/repo.go | 7 ++ services/convert/convert.go | 27 ++++++ templates/swagger/v1_json.tmpl | 149 ++++++++++++++++++++++++++++++++ 6 files changed, 300 insertions(+) create mode 100644 modules/structs/repo_actions.go create mode 100644 routers/api/v1/repo/actions.go diff --git a/modules/structs/repo_actions.go b/modules/structs/repo_actions.go new file mode 100644 index 0000000000..b13f344738 --- /dev/null +++ b/modules/structs/repo_actions.go @@ -0,0 +1,34 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package structs + +import ( + "time" +) + +// ActionTask represents a ActionTask +type ActionTask struct { + ID int64 `json:"id"` + Name string `json:"name"` + HeadBranch string `json:"head_branch"` + HeadSHA string `json:"head_sha"` + RunNumber int64 `json:"run_number"` + Event string `json:"event"` + DisplayTitle string `json:"display_title"` + Status string `json:"status"` + WorkflowID string `json:"workflow_id"` + URL string `json:"url"` + // swagger:strfmt date-time + CreatedAt time.Time `json:"created_at"` + // swagger:strfmt date-time + UpdatedAt time.Time `json:"updated_at"` + // swagger:strfmt date-time + RunStartedAt time.Time `json:"run_started_at"` +} + +// ActionTaskResponse returns a ActionTask +type ActionTaskResponse struct { + Entries []*ActionTask `json:"workflow_runs"` + TotalCount int64 `json:"total_count"` +} diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 73071aa8df..74062c44ac 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -1168,6 +1168,9 @@ func Routes() *web.Route { m.Post("", reqToken(), reqRepoWriter(unit.TypeCode), mustNotBeArchived, bind(api.CreateTagOption{}), repo.CreateTag) m.Delete("/*", reqToken(), reqRepoWriter(unit.TypeCode), mustNotBeArchived, repo.DeleteTag) }, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo(true)) + m.Group("/actions", func() { + m.Get("/tasks", repo.ListActionTasks) + }, reqRepoReader(unit.TypeActions), context.ReferencesGitRepo(true)) m.Group("/keys", func() { m.Combo("").Get(repo.ListDeployKeys). Post(bind(api.CreateKeyOption{}), repo.CreateDeployKey) diff --git a/routers/api/v1/repo/actions.go b/routers/api/v1/repo/actions.go new file mode 100644 index 0000000000..635cb4e138 --- /dev/null +++ b/routers/api/v1/repo/actions.go @@ -0,0 +1,80 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repo + +import ( + "net/http" + + actions_model "code.gitea.io/gitea/models/actions" + "code.gitea.io/gitea/models/db" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/convert" +) + +// ListActionTasks list all the actions of a repository +func ListActionTasks(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/actions/tasks repository ListActionTasks + // --- + // summary: List a repository's action tasks + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: page + // in: query + // description: page number of results to return (1-based) + // type: integer + // - name: limit + // in: query + // description: page size of results, default maximum page size is 50 + // type: integer + // responses: + // "200": + // "$ref": "#/responses/TasksList" + // "400": + // "$ref": "#/responses/error" + // "403": + // "$ref": "#/responses/forbidden" + // "404": + // "$ref": "#/responses/notFound" + // "409": + // "$ref": "#/responses/conflict" + // "422": + // "$ref": "#/responses/validationError" + + tasks, total, err := db.FindAndCount[actions_model.ActionTask](ctx, &actions_model.FindTaskOptions{ + ListOptions: utils.GetListOptions(ctx), + RepoID: ctx.Repo.Repository.ID, + }) + if err != nil { + ctx.Error(http.StatusInternalServerError, "ListActionTasks", err) + return + } + + res := new(api.ActionTaskResponse) + res.TotalCount = total + + res.Entries = make([]*api.ActionTask, len(tasks)) + for i := range tasks { + convertedTask, err := convert.ToActionTask(ctx, tasks[i]) + if err != nil { + ctx.Error(http.StatusInternalServerError, "ToActionTask", err) + return + } + res.Entries[i] = convertedTask + } + + ctx.JSON(http.StatusOK, &res) +} diff --git a/routers/api/v1/swagger/repo.go b/routers/api/v1/swagger/repo.go index c3219f28d6..fcd34a63a9 100644 --- a/routers/api/v1/swagger/repo.go +++ b/routers/api/v1/swagger/repo.go @@ -415,6 +415,13 @@ type swaggerRepoNewIssuePinsAllowed struct { Body api.NewIssuePinsAllowed `json:"body"` } +// TasksList +// swagger:response TasksList +type swaggerRepoTasksList struct { + // in:body + Body api.ActionTaskResponse `json:"body"` +} + // swagger:response Compare type swaggerCompare struct { // in:body diff --git a/services/convert/convert.go b/services/convert/convert.go index 3b6139d2fe..c44179632e 100644 --- a/services/convert/convert.go +++ b/services/convert/convert.go @@ -11,6 +11,7 @@ import ( "strings" "time" + actions_model "code.gitea.io/gitea/models/actions" asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/auth" git_model "code.gitea.io/gitea/models/git" @@ -24,6 +25,7 @@ import ( "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/gitdiff" @@ -193,6 +195,31 @@ func ToTag(repo *repo_model.Repository, t *git.Tag) *api.Tag { } } +// ToActionTask convert a actions_model.ActionTask to an api.ActionTask +func ToActionTask(ctx context.Context, t *actions_model.ActionTask) (*api.ActionTask, error) { + if err := t.LoadAttributes(ctx); err != nil { + return nil, err + } + + url := strings.TrimSuffix(setting.AppURL, "/") + t.GetRunLink() + + return &api.ActionTask{ + ID: t.ID, + Name: t.Job.Name, + HeadBranch: t.Job.Run.PrettyRef(), + HeadSHA: t.Job.CommitSHA, + RunNumber: t.Job.Run.Index, + Event: t.Job.Run.TriggerEvent, + DisplayTitle: t.Job.Run.Title, + Status: t.Status.String(), + WorkflowID: t.Job.Run.WorkflowID, + URL: url, + CreatedAt: t.Created.AsLocalTime(), + UpdatedAt: t.Updated.AsLocalTime(), + RunStartedAt: t.Started.AsLocalTime(), + }, nil +} + // ToVerification convert a git.Commit.Signature to an api.PayloadCommitVerification func ToVerification(ctx context.Context, c *git.Commit) *api.PayloadCommitVerification { verif := asymkey_model.ParseCommitWithSignature(ctx, c) diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 362a847332..0c5e5c974d 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -3997,6 +3997,66 @@ } } }, + "/repos/{owner}/{repo}/actions/tasks": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "repository" + ], + "summary": "List a repository's action tasks", + "operationId": "ListActionTasks", + "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": "page number of results to return (1-based)", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "page size of results, default maximum page size is 50", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "$ref": "#/responses/TasksList" + }, + "400": { + "$ref": "#/responses/error" + }, + "403": { + "$ref": "#/responses/forbidden" + }, + "404": { + "$ref": "#/responses/notFound" + }, + "409": { + "$ref": "#/responses/conflict" + }, + "422": { + "$ref": "#/responses/validationError" + } + } + } + }, "/repos/{owner}/{repo}/actions/variables": { "get": { "produces": [ @@ -17953,6 +18013,89 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "ActionTask": { + "description": "ActionTask represents a ActionTask", + "type": "object", + "properties": { + "created_at": { + "type": "string", + "format": "date-time", + "x-go-name": "CreatedAt" + }, + "display_title": { + "type": "string", + "x-go-name": "DisplayTitle" + }, + "event": { + "type": "string", + "x-go-name": "Event" + }, + "head_branch": { + "type": "string", + "x-go-name": "HeadBranch" + }, + "head_sha": { + "type": "string", + "x-go-name": "HeadSHA" + }, + "id": { + "type": "integer", + "format": "int64", + "x-go-name": "ID" + }, + "name": { + "type": "string", + "x-go-name": "Name" + }, + "run_number": { + "type": "integer", + "format": "int64", + "x-go-name": "RunNumber" + }, + "run_started_at": { + "type": "string", + "format": "date-time", + "x-go-name": "RunStartedAt" + }, + "status": { + "type": "string", + "x-go-name": "Status" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "x-go-name": "UpdatedAt" + }, + "url": { + "type": "string", + "x-go-name": "URL" + }, + "workflow_id": { + "type": "string", + "x-go-name": "WorkflowID" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, + "ActionTaskResponse": { + "description": "ActionTaskResponse returns a ActionTask", + "type": "object", + "properties": { + "total_count": { + "type": "integer", + "format": "int64", + "x-go-name": "TotalCount" + }, + "workflow_runs": { + "type": "array", + "items": { + "$ref": "#/definitions/ActionTask" + }, + "x-go-name": "Entries" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "ActionVariable": { "description": "ActionVariable return value of the query API", "type": "object", @@ -25409,6 +25552,12 @@ } } }, + "TasksList": { + "description": "TasksList", + "schema": { + "$ref": "#/definitions/ActionTaskResponse" + } + }, "Team": { "description": "Team", "schema": { From f135cb7c9457f7b9bdc43601f44757834573950f Mon Sep 17 00:00:00 2001 From: Kemal Zebari <60799661+kemzeb@users.noreply.github.com> Date: Tue, 30 Apr 2024 22:33:40 -0700 Subject: [PATCH 250/370] Don't have `redis-cluster` as possible cache/session adapter in docs (#30794) This is because it doesn't exist as an adapter. The `redis` adapter already handles Redis cluster configurations. Fixes #30534. --- custom/conf/app.example.ini | 12 +++++------- .../administration/config-cheat-sheet.en-us.md | 10 +++++----- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 62db26fb02..577479e39f 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1456,7 +1456,7 @@ LEVEL = Info ;; Batch size to send for batched queues ;BATCH_LENGTH = 20 ;; -;; Connection string for redis queues this will store the redis or redis-cluster connection string. +;; Connection string for redis queues this will store the redis (or Redis cluster) connection string. ;; When `TYPE` is `persistable-channel`, this provides a directory for the underlying leveldb ;; or additional options of the form `leveldb://path/to/db?option=value&....`, and will override `DATADIR`. ;CONN_STR = "redis://127.0.0.1:6379/0" @@ -1740,9 +1740,8 @@ LEVEL = Info ;; For "memory" only, GC interval in seconds, default is 60 ;INTERVAL = 60 ;; -;; For "redis", "redis-cluster" and "memcache", connection host address -;; redis: `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` -;; redis-cluster: `redis+cluster://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` +;; For "redis" and "memcache", connection host address +;; redis: `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` (or `redis+cluster://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` for a Redis cluster) ;; memcache: `127.0.0.1:11211` ;; twoqueue: `{"size":50000,"recent_ratio":0.25,"ghost_ratio":0.5}` or `50000` ;HOST = @@ -1772,15 +1771,14 @@ LEVEL = Info ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; -;; Either "memory", "file", "redis", "redis-cluster", "db", "mysql", "couchbase", "memcache" or "postgres" +;; Either "memory", "file", "redis", "db", "mysql", "couchbase", "memcache" or "postgres" ;; Default is "memory". "db" will reuse the configuration in [database] ;PROVIDER = memory ;; ;; Provider config options ;; memory: doesn't have any config yet ;; file: session file path, e.g. `data/sessions` -;; redis: `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` -;; redis-cluster: `redis+cluster://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` +;; redis: `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` (or `redis+cluster://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` for a Redis cluster) ;; mysql: go-sql-driver/mysql dsn config string, e.g. `root:password@/session_table` ;PROVIDER_CONFIG = data/sessions ; Relative paths will be made absolute against _`AppWorkPath`_. ;; diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index 5066e0f879..07712c1110 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -492,7 +492,7 @@ Configuration at `[queue]` will set defaults for queues with overrides for indiv - `DATADIR`: **queues/common**: Base DataDir for storing level queues. `DATADIR` for individual queues can be set in `queue.name` sections. Relative paths will be made absolute against `%(APP_DATA_PATH)s`. - `LENGTH`: **100000**: Maximal queue size before channel queues block - `BATCH_LENGTH`: **20**: Batch data before passing to the handler -- `CONN_STR`: **redis://127.0.0.1:6379/0**: Connection string for the redis queue type. For `redis-cluster` use `redis+cluster://127.0.0.1:6379/0`. Options can be set using query params. Similarly, LevelDB options can also be set using: **leveldb://relative/path?option=value** or **leveldb:///absolute/path?option=value**, and will override `DATADIR` +- `CONN_STR`: **redis://127.0.0.1:6379/0**: Connection string for the redis queue type. If you're running a Redis cluster, use `redis+cluster://127.0.0.1:6379/0`. Options can be set using query params. Similarly, LevelDB options can also be set using: **leveldb://relative/path?option=value** or **leveldb:///absolute/path?option=value**, and will override `DATADIR` - `QUEUE_NAME`: **_queue**: The suffix for default redis and disk queue name. Individual queues will default to **`name`**`QUEUE_NAME` but can be overridden in the specific `queue.name` section. - `SET_NAME`: **_unique**: The suffix that will be added to the default redis and disk queue `set` name for unique queues. Individual queues will default to **`name`**`QUEUE_NAME`_`SET_NAME`_ but can be overridden in the specific `queue.name` section. - `MAX_WORKERS`: **(dynamic)**: Maximum number of worker go-routines for the queue. Default value is "CpuNum/2" clipped to between 1 and 10. @@ -777,11 +777,11 @@ and ## Cache (`cache`) -- `ADAPTER`: **memory**: Cache engine adapter, either `memory`, `redis`, `redis-cluster`, `twoqueue` or `memcache`. (`twoqueue` represents a size limited LRU cache.) +- `ADAPTER`: **memory**: Cache engine adapter, either `memory`, `redis`, `twoqueue` or `memcache`. (`twoqueue` represents a size limited LRU cache.) - `INTERVAL`: **60**: Garbage Collection interval (sec), for memory and twoqueue cache only. -- `HOST`: **_empty_**: Connection string for `redis`, `redis-cluster` and `memcache`. For `twoqueue` sets configuration for the queue. +- `HOST`: **_empty_**: Connection string for `redis` and `memcache`. For `twoqueue` sets configuration for the queue. - Redis: `redis://:macaron@127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` - - Redis-cluster `redis+cluster://:macaron@127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` + - For a Redis cluster: `redis+cluster://:macaron@127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` - Memcache: `127.0.0.1:9090;127.0.0.1:9091` - TwoQueue LRU cache: `{"size":50000,"recent_ratio":0.25,"ghost_ratio":0.5}` or `50000` representing the maximum number of objects stored in the cache. - `ITEM_TTL`: **16h**: Time to keep items in cache if not used, Setting it to -1 disables caching. @@ -793,7 +793,7 @@ and ## Session (`session`) -- `PROVIDER`: **memory**: Session engine provider \[memory, file, redis, redis-cluster, db, mysql, couchbase, memcache, postgres\]. Setting `db` will reuse the configuration in `[database]` +- `PROVIDER`: **memory**: Session engine provider \[memory, file, redis, db, mysql, couchbase, memcache, postgres\]. Setting `db` will reuse the configuration in `[database]` - `PROVIDER_CONFIG`: **data/sessions**: For file, the root path; for db, empty (database config will be used); for others, the connection string. Relative paths will be made absolute against _`AppWorkPath`_. - `COOKIE_SECURE`:**_empty_**: `true` or `false`. Enable this to force using HTTPS for all session access. If not set, it defaults to `true` if the ROOT_URL is an HTTPS URL. - `COOKIE_NAME`: **i\_like\_gitea**: The name of the cookie used for the session ID. From 6f7cd94a02aaf14bf2e2a6219bbc4379c4995b5d Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Wed, 1 May 2024 20:32:52 +0800 Subject: [PATCH 251/370] Fix bleve fuzziness (#30799) Fix #30797 Fix #30317 --- modules/indexer/code/bleve/bleve.go | 4 +--- modules/indexer/internal/bleve/util.go | 12 ++++++++++++ modules/indexer/issues/bleve/bleve.go | 8 ++------ routers/web/repo/search.go | 2 +- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/modules/indexer/code/bleve/bleve.go b/modules/indexer/code/bleve/bleve.go index bd844205a6..8056b58ec2 100644 --- a/modules/indexer/code/bleve/bleve.go +++ b/modules/indexer/code/bleve/bleve.go @@ -39,8 +39,6 @@ import ( const ( unicodeNormalizeName = "unicodeNormalize" maxBatchSize = 16 - // fuzzyDenominator determines the levenshtein distance per each character of a keyword - fuzzyDenominator = 4 ) func addUnicodeNormalizeTokenFilter(m *mapping.IndexMappingImpl) error { @@ -245,7 +243,7 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int phraseQuery.Analyzer = repoIndexerAnalyzer keywordQuery = phraseQuery if opts.IsKeywordFuzzy { - phraseQuery.Fuzziness = len(opts.Keyword) / fuzzyDenominator + phraseQuery.Fuzziness = inner_bleve.GuessFuzzinessByKeyword(opts.Keyword) } if len(opts.RepoIDs) > 0 { diff --git a/modules/indexer/internal/bleve/util.go b/modules/indexer/internal/bleve/util.go index 43a7c3c5ec..a2265f86e6 100644 --- a/modules/indexer/internal/bleve/util.go +++ b/modules/indexer/internal/bleve/util.go @@ -47,3 +47,15 @@ func openIndexer(path string, latestVersion int) (bleve.Index, int, error) { return index, 0, nil } + +func GuessFuzzinessByKeyword(s string) int { + // according to https://github.com/blevesearch/bleve/issues/1563, the supported max fuzziness is 2 + // magic number 4 was chosen to determine the levenshtein distance per each character of a keyword + // BUT, when using CJK (eg: `갃갃갃` `啊啊啊`), it mismatches a lot. + for _, r := range s { + if r >= 128 { + return 0 + } + } + return min(2, len(s)/4) +} diff --git a/modules/indexer/issues/bleve/bleve.go b/modules/indexer/issues/bleve/bleve.go index 1f54be721b..d7957b266a 100644 --- a/modules/indexer/issues/bleve/bleve.go +++ b/modules/indexer/issues/bleve/bleve.go @@ -35,11 +35,7 @@ func addUnicodeNormalizeTokenFilter(m *mapping.IndexMappingImpl) error { }) } -const ( - maxBatchSize = 16 - // fuzzyDenominator determines the levenshtein distance per each character of a keyword - fuzzyDenominator = 4 -) +const maxBatchSize = 16 // IndexerData an update to the issue indexer type IndexerData internal.IndexerData @@ -162,7 +158,7 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( if options.Keyword != "" { fuzziness := 0 if options.IsFuzzyKeyword { - fuzziness = len(options.Keyword) / fuzzyDenominator + fuzziness = inner_bleve.GuessFuzzinessByKeyword(options.Keyword) } queries = append(queries, bleve.NewDisjunctionQuery([]query.Query{ diff --git a/routers/web/repo/search.go b/routers/web/repo/search.go index 23cf898630..d7854b2499 100644 --- a/routers/web/repo/search.go +++ b/routers/web/repo/search.go @@ -28,6 +28,7 @@ func Search(ctx *context.Context) { ctx.Data["Language"] = language ctx.Data["IsFuzzy"] = isFuzzy ctx.Data["PageIsViewCode"] = true + ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled if keyword == "" { ctx.HTML(http.StatusOK, tplSearch) @@ -86,7 +87,6 @@ func Search(ctx *context.Context) { } } - ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled ctx.Data["Repo"] = ctx.Repo.Repository ctx.Data["SearchResults"] = searchResults ctx.Data["SearchResultLanguages"] = searchResultLanguages From ce08a9fe2f7c9ae6390f1ad3d619524010a4e787 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Thu, 2 May 2024 09:00:46 +0800 Subject: [PATCH 252/370] Fix markdown rendering when mentioning users (#30795) --- modules/markup/html.go | 15 +++++++-------- modules/references/references.go | 2 +- modules/references/references_test.go | 2 +- modules/templates/util_render_test.go | 5 +++++ 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/modules/markup/html.go b/modules/markup/html.go index cef643bf18..5ae0cc8755 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -591,17 +591,16 @@ func replaceContentList(node *html.Node, i, j int, newNodes []*html.Node) { func mentionProcessor(ctx *RenderContext, node *html.Node) { start := 0 - next := node.NextSibling - for node != nil && node != next && start < len(node.Data) { - // We replace only the first mention; other mentions will be addressed later - found, loc := references.FindFirstMentionBytes([]byte(node.Data[start:])) + for node != nil { + found, loc := references.FindFirstMentionBytes(util.UnsafeStringToBytes(node.Data[start:])) if !found { - return + node = node.NextSibling + start = 0 + continue } loc.Start += start loc.End += start mention := node.Data[loc.Start:loc.End] - var teams string teams, ok := ctx.Metas["teams"] // FIXME: util.URLJoin may not be necessary here: // - setting.AppURL is defined to have a terminal '/' so unless mention[1:] @@ -623,10 +622,10 @@ func mentionProcessor(ctx *RenderContext, node *html.Node) { if DefaultProcessorHelper.IsUsernameMentionable != nil && DefaultProcessorHelper.IsUsernameMentionable(ctx.Ctx, mentionedUsername) { replaceContent(node, loc.Start, loc.End, createLink(util.URLJoin(ctx.Links.Prefix(), mentionedUsername), mention, "mention")) node = node.NextSibling.NextSibling + start = 0 } else { - node = node.NextSibling + start = loc.End } - start = 0 } } diff --git a/modules/references/references.go b/modules/references/references.go index 761d6ee3d1..1b656ed4cb 100644 --- a/modules/references/references.go +++ b/modules/references/references.go @@ -29,7 +29,7 @@ var ( // TODO: fix invalid linking issue // mentionPattern matches all mentions in the form of "@user" or "@org/team" - mentionPattern = regexp.MustCompile(`(?:\s|^|\(|\[)(@[0-9a-zA-Z-_]+|@[0-9a-zA-Z-_]+\/?[0-9a-zA-Z-_]+|@[0-9a-zA-Z-_][0-9a-zA-Z-_.]+\/?[0-9a-zA-Z-_.]+[0-9a-zA-Z-_])(?:\s|[:,;.?!]\s|[:,;.?!]?$|\)|\])`) + mentionPattern = regexp.MustCompile(`(?:\s|^|\(|\[)(@[-\w][-.\w]*?|@[-\w][-.\w]*?/[-\w][-.\w]*?)(?:\s|$|[:,;.?!](\s|$)|'|\)|\])`) // issueNumericPattern matches string that references to a numeric issue, e.g. #1287 issueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\'|\")([#!][0-9]+)(?:\s|$|\)|\]|\'|\"|[:;,.?!]\s|[:;,.?!]$)`) // issueAlphanumericPattern matches string that references to an alphanumeric issue, e.g. ABC-1234 diff --git a/modules/references/references_test.go b/modules/references/references_test.go index 0c32933619..e5a0d60fe3 100644 --- a/modules/references/references_test.go +++ b/modules/references/references_test.go @@ -392,6 +392,7 @@ func TestRegExp_mentionPattern(t *testing.T) { {"@gitea,", "@gitea"}, {"@gitea;", "@gitea"}, {"@gitea/team1;", "@gitea/team1"}, + {"@user's idea", "@user"}, } falseTestCases := []string{ "@ 0", @@ -412,7 +413,6 @@ func TestRegExp_mentionPattern(t *testing.T) { for _, testCase := range trueTestCases { found := mentionPattern.FindStringSubmatch(testCase.pat) - assert.Len(t, found, 2) assert.Equal(t, testCase.exp, found[1]) } for _, testCase := range falseTestCases { diff --git a/modules/templates/util_render_test.go b/modules/templates/util_render_test.go index 47c5da6485..f493b899e3 100644 --- a/modules/templates/util_render_test.go +++ b/modules/templates/util_render_test.go @@ -207,3 +207,8 @@ func TestRenderLabels(t *testing.T) { expected = `/owner/repo/pulls?labels=123` assert.Contains(t, RenderLabels(ctx, locale, []*issues.Label{label}, "/owner/repo", issue), expected) } + +func TestUserMention(t *testing.T) { + rendered := RenderMarkdownToHtml(context.Background(), "@no-such-user @mention-user @mention-user") + assert.EqualValues(t, `<p>@no-such-user <a href="/mention-user" rel="nofollow">@mention-user</a> <a href="/mention-user" rel="nofollow">@mention-user</a></p>`, strings.TrimSpace(string(rendered))) +} From be112c1fc30f87a248b30f48e891d1c8c18e8280 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Thu, 2 May 2024 10:27:25 +0800 Subject: [PATCH 253/370] Skip gzip for some well-known compressed file types (#30796) Co-authored-by: silverwind <me@silverwind.io> --- modules/httplib/serve.go | 8 +++++++ routers/web/web.go | 2 +- tests/integration/repo_archive_test.go | 33 ++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 tests/integration/repo_archive_test.go diff --git a/modules/httplib/serve.go b/modules/httplib/serve.go index a193ed901c..6e147d76f5 100644 --- a/modules/httplib/serve.go +++ b/modules/httplib/serve.go @@ -17,11 +17,14 @@ import ( "time" charsetModule "code.gitea.io/gitea/modules/charset" + "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/httpcache" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/typesniffer" "code.gitea.io/gitea/modules/util" + + "github.com/klauspost/compress/gzhttp" ) type ServeHeaderOptions struct { @@ -38,6 +41,11 @@ type ServeHeaderOptions struct { func ServeSetHeaders(w http.ResponseWriter, opts *ServeHeaderOptions) { header := w.Header() + skipCompressionExts := container.SetOf(".gz", ".bz2", ".zip", ".xz", ".zst", ".deb", ".apk", ".jar", ".png", ".jpg", ".webp") + if skipCompressionExts.Contains(strings.ToLower(path.Ext(opts.Filename))) { + w.Header().Add(gzhttp.HeaderNoCompression, "1") + } + contentType := typesniffer.ApplicationOctetStream if opts.ContentType != "" { if opts.ContentTypeCharset != "" { diff --git a/routers/web/web.go b/routers/web/web.go index 9a6687059b..91ab378d97 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -54,7 +54,7 @@ import ( "github.com/prometheus/client_golang/prometheus" ) -const GzipMinSize = 1400 // min size to compress for the body size of response +var GzipMinSize = 1400 // min size to compress for the body size of response // optionsCorsHandler return a http handler which sets CORS options if enabled by config, it blocks non-CORS OPTIONS requests. func optionsCorsHandler() func(next http.Handler) http.Handler { diff --git a/tests/integration/repo_archive_test.go b/tests/integration/repo_archive_test.go new file mode 100644 index 0000000000..664b04baf7 --- /dev/null +++ b/tests/integration/repo_archive_test.go @@ -0,0 +1,33 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package integration + +import ( + "io" + "net/http" + "testing" + + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" + "code.gitea.io/gitea/routers" + "code.gitea.io/gitea/routers/web" + "code.gitea.io/gitea/tests" + + "github.com/stretchr/testify/assert" +) + +func TestRepoDownloadArchive(t *testing.T) { + defer tests.PrepareTestEnv(t)() + defer test.MockVariableValue(&setting.EnableGzip, true)() + defer test.MockVariableValue(&web.GzipMinSize, 10)() + defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())() + + req := NewRequest(t, "GET", "/user2/repo1/archive/master.zip") + req.Header.Set("Accept-Encoding", "gzip") + resp := MakeRequest(t, req, http.StatusOK) + bs, err := io.ReadAll(resp.Body) + assert.NoError(t, err) + assert.Empty(t, resp.Header().Get("Content-Encoding")) + assert.Equal(t, 320, len(bs)) +} From 82eca44581100d96e11097db743804bc398d1742 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Thu, 2 May 2024 11:25:55 +0200 Subject: [PATCH 254/370] Fix rounded border for segment followed by pagination (#30809) Fixes https://github.com/go-gitea/gitea/issues/30673, specifically https://github.com/go-gitea/gitea/issues/30673#issuecomment-2085329812. --- web_src/css/modules/segment.css | 1 + 1 file changed, 1 insertion(+) diff --git a/web_src/css/modules/segment.css b/web_src/css/modules/segment.css index cb307dc1a3..48dc5c4488 100644 --- a/web_src/css/modules/segment.css +++ b/web_src/css/modules/segment.css @@ -152,6 +152,7 @@ } .ui.attached.segment:has(+ .ui[class*="top attached"].header), +.ui.attached.segment:has(+ .page.buttons), .ui.attached.segment:last-child, .ui.segment:has(+ .ui.segment:not(.attached)), .ui.attached.segment:has(+ .ui.modal) { From ebe6f4cad775a82d11c916c9af716beec394768b Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Thu, 2 May 2024 18:45:23 +0800 Subject: [PATCH 255/370] Fix branch selector UI (#30803) Fix #30802 --- templates/repo/branch_dropdown.tmpl | 8 +- .../repo/issue/branch_selector_field.tmpl | 44 +++++----- .../repo/issue/labels/labels_sidebar.tmpl | 2 +- web_src/css/base.css | 1 + web_src/css/repo.css | 85 ++++++++++++------- .../js/components/RepoBranchTagSelector.vue | 48 +---------- web_src/js/features/repo-legacy.js | 25 +++--- 7 files changed, 96 insertions(+), 117 deletions(-) diff --git a/templates/repo/branch_dropdown.tmpl b/templates/repo/branch_dropdown.tmpl index 7b39830df8..8f58826c6a 100644 --- a/templates/repo/branch_dropdown.tmpl +++ b/templates/repo/branch_dropdown.tmpl @@ -69,9 +69,9 @@ <div class="js-branch-tag-selector {{if .ContainerClasses}}{{.ContainerClasses}}{{end}}"> {{/* show dummy elements before Vue componment is mounted, this code must match the code in BranchTagSelector.vue */}} - <div class="ui dropdown custom"> - <button class="branch-dropdown-button gt-ellipsis ui basic small compact button tw-flex tw-m-0"> - <span class="text tw-flex tw-items-center tw-mr-1 gt-ellipsis"> + <div class="ui dropdown custom branch-selector-dropdown"> + <div class="ui button branch-dropdown-button"> + <span class="flex-text-block gt-ellipsis"> {{if .release}} {{ctx.Locale.Tr "repo.release.compare"}} {{else}} @@ -84,6 +84,6 @@ {{end}} </span> {{svg "octicon-triangle-down" 14 "dropdown icon"}} - </button> + </div> </div> </div> diff --git a/templates/repo/issue/branch_selector_field.tmpl b/templates/repo/issue/branch_selector_field.tmpl index ed0d58cf27..e9e5574cd7 100644 --- a/templates/repo/issue/branch_selector_field.tmpl +++ b/templates/repo/issue/branch_selector_field.tmpl @@ -4,10 +4,12 @@ <form method="post" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/ref" id="update_issueref_form"> {{$.CsrfTokenHtml}} </form> -{{/* TODO: share this branch selector dropdown with the same in repo page */}} -<div class="ui {{if not .HasIssuesOrPullsWritePermission}}disabled{{end}} floating filter select-branch dropdown tw-max-w-full" data-no-results="{{ctx.Locale.Tr "no_results_found"}}"> - <div class="ui basic small button"> - <span class="text branch-name gt-ellipsis">{{if .Reference}}{{$.RefEndName}}{{else}}{{ctx.Locale.Tr "repo.issues.no_ref"}}{{end}}</span> +<div class="ui dropdown select-branch branch-selector-dropdown {{if not .HasIssuesOrPullsWritePermission}}disabled{{end}}" + data-no-results="{{ctx.Locale.Tr "no_results_found"}}" + {{if not .Issue}}data-for-new-issue="true"{{end}} +> + <div class="ui button branch-dropdown-button"> + <span class="text-branch-name gt-ellipsis">{{if .Reference}}{{$.RefEndName}}{{else}}{{ctx.Locale.Tr "repo.issues.no_ref"}}{{end}}</span> {{if .HasIssuesOrPullsWritePermission}}{{svg "octicon-triangle-down" 14 "dropdown icon"}}{{end}} </div> <div class="menu"> @@ -15,26 +17,18 @@ <i class="icon">{{svg "octicon-filter" 16}}</i> <input name="search" placeholder="{{ctx.Locale.Tr "repo.filter_branch_and_tag"}}..."> </div> - <div class="header"> - <div class="ui grid"> - <div class="two column row"> - <a class="reference column muted" href="#" data-target="#branch-list"> - <span class="text black"> - {{svg "octicon-git-branch" 16 "tw-mr-1"}}{{ctx.Locale.Tr "repo.branches"}} - </span> - </a> - <a class="reference column muted" href="#" data-target="#tag-list"> - <span class="text"> - {{svg "octicon-tag" 16 "tw-mr-1"}}{{ctx.Locale.Tr "repo.tags"}} - </span> - </a> - </div> - </div> + <div class="branch-tag-tab"> + <a class="branch-tag-item reference column muted active" href="#" data-target="#branch-list"> + {{svg "octicon-git-branch" 16 "tw-mr-1"}} {{ctx.Locale.Tr "repo.branches"}} + </a> + <a class="branch-tag-item reference column muted" href="#" data-target="#tag-list"> + {{svg "octicon-tag" 16 "tw-mr-1"}} {{ctx.Locale.Tr "repo.tags"}} + </a> </div> <div class="branch-tag-divider"></div> - <div id="branch-list" class="scrolling menu reference-list-menu {{if not .Issue}}new-issue{{end}}"> - {{if .Reference}} - <div class="item text small" data-id="" data-id-selector="#ref_selector"><strong><a href="#">{{ctx.Locale.Tr "repo.clear_ref"}}</a></strong></div> + <div id="branch-list" class="scrolling menu reference-list-menu"> + {{if or .Reference (not .Issue)}} + <div class="item text small" data-id="" data-name="{{ctx.Locale.Tr "repo.issues.no_ref"}}" data-id-selector="#ref_selector"><strong><a href="#">{{ctx.Locale.Tr "repo.clear_ref"}}</a></strong></div> {{end}} {{range .Branches}} <div class="item" data-id="refs/heads/{{.}}" data-name="{{.}}" data-id-selector="#ref_selector" title="{{.}}">{{.}}</div> @@ -42,9 +36,9 @@ <div class="item">{{ctx.Locale.Tr "no_results_found"}}</div> {{end}} </div> - <div id="tag-list" class="scrolling menu reference-list-menu {{if not .Issue}}new-issue{{end}} tw-hidden"> - {{if .Reference}} - <div class="item text small" data-id="" data-id-selector="#ref_selector"><strong><a href="#">{{ctx.Locale.Tr "repo.clear_ref"}}</a></strong></div> + <div id="tag-list" class="scrolling menu reference-list-menu tw-hidden"> + {{if or .Reference (not .Issue)}} + <div class="item text small" data-id="" data-name="{{ctx.Locale.Tr "repo.issues.no_ref"}}" data-id-selector="#ref_selector"><strong><a href="#">{{ctx.Locale.Tr "repo.clear_ref"}}</a></strong></div> {{end}} {{range .Tags}} <div class="item" data-id="refs/tags/{{.}}" data-name="tags/{{.}}" data-id-selector="#ref_selector">{{.}}</div> diff --git a/templates/repo/issue/labels/labels_sidebar.tmpl b/templates/repo/issue/labels/labels_sidebar.tmpl index be30baba92..0b7b9b8969 100644 --- a/templates/repo/issue/labels/labels_sidebar.tmpl +++ b/templates/repo/issue/labels/labels_sidebar.tmpl @@ -1,6 +1,6 @@ <div class="ui labels list"> - <span class="no-select item {{if .root.HasSelectedLabel}}tw-hidden{{end}}">{{ctx.Locale.Tr "repo.issues.new.no_label"}}</span> <span class="labels-list"> + <span class="no-select {{if .root.HasSelectedLabel}}tw-hidden{{end}}">{{ctx.Locale.Tr "repo.issues.new.no_label"}}</span> {{range .root.Labels}} {{template "repo/issue/labels/label" dict "root" $.root "label" .}} {{end}} diff --git a/web_src/css/base.css b/web_src/css/base.css index 1d65bb37e7..c0ced2955c 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -871,6 +871,7 @@ input:-webkit-autofill:active, .ui.dropdown .scrolling.menu { border-color: var(--color-secondary); + border-radius: 0 0 var(--border-radius) var(--border-radius) !important; } .color-preview { diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 0b46f6b69f..cc09ec94e2 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -2748,23 +2748,6 @@ tbody.commit-list { } } -.branch-dropdown-button { - max-width: 340px; - vertical-align: bottom !important; -} - -@media (min-width: 768px) and (max-width: 991.98px) { - .branch-dropdown-button { - max-width: 185px; - } -} - -@media (max-width: 767.98px) { - .branch-dropdown-button { - max-width: 165px; - } -} - .commit-status-header { /* reset the default ".ui.attached.header" styles, to use the outer border */ border: none !important; @@ -2841,32 +2824,70 @@ tbody.commit-list { max-height: 200px; } -/* Branch tag selector - TODO: Merge this into the same selector on repo page */ -.repository .issue-content .issue-content-right .ui.grid .column.row { - padding: 10px; - padding-bottom: 0; +.branch-selector-dropdown { + max-width: 100%; } -.repository .issue-content .issue-content-right .ui.grid .column.muted { - padding: 0; + +.ui.dropdown.branch-selector-dropdown > .menu { + margin-top: 4px; } -.repository .issue-content .issue-content-right .ui.grid .column.muted .text { + +.branch-selector-dropdown .branch-dropdown-button { + margin: 0; + max-width: 340px; + line-height: var(--line-height-default); +} + +/* FIXME: These media selectors are not ideal (just keep them from old code). + There are many different pages, some need the max-width while some others don't, + they should be tested and improved in the future. */ +@media (min-width: 768px) and (max-width: 991.98px) { + .branch-selector-dropdown .branch-dropdown-button { + max-width: 185px; + } +} + +@media (max-width: 767.98px) { + .branch-selector-dropdown .branch-dropdown-button { + max-width: 165px; + } +} + +.branch-selector-dropdown .branch-tag-tab { + padding: 0 10px; +} + +.branch-selector-dropdown .branch-tag-item { display: inline-block; padding: 10px; - width: 100%; - text-align: center; border: 1px solid transparent; border-bottom: none; } -.repository .issue-content .issue-content-right .ui.grid .column.muted .text.black { + +.branch-selector-dropdown .branch-tag-item.active { border-color: var(--color-secondary); background: var(--color-menu); border-top-left-radius: var(--border-radius); border-top-right-radius: var(--border-radius); } -.repository .issue-content .issue-content-right .ui.dropdown .scrolling.menu { - border-top: none; -} -.repository .issue-content .issue-content-right .branch-tag-divider { - margin-top: -1px; + +.branch-selector-dropdown .branch-tag-divider { + margin-top: -1px !important; border-top: 1px solid var(--color-secondary); } + +.branch-selector-dropdown .scrolling.menu { + border-top: none !important; +} + +.branch-selector-dropdown .menu .item .rss-icon { + visibility: hidden; /* only show RSS icon on hover */ +} + +.branch-selector-dropdown .menu .item:hover .rss-icon { + visibility: visible; +} + +.branch-selector-dropdown .scrolling.menu .loading-indicator { + height: 4em; +} diff --git a/web_src/js/components/RepoBranchTagSelector.vue b/web_src/js/components/RepoBranchTagSelector.vue index c13af14dea..8a741b68da 100644 --- a/web_src/js/components/RepoBranchTagSelector.vue +++ b/web_src/js/components/RepoBranchTagSelector.vue @@ -246,9 +246,9 @@ export function initRepoBranchTagSelector(selector) { export default sfc; // activate IDE's Vue plugin </script> <template> - <div class="ui dropdown custom"> - <button class="branch-dropdown-button gt-ellipsis ui basic small compact button tw-flex tw-m-0" @click="menuVisible = !menuVisible" @keyup.enter="menuVisible = !menuVisible"> - <span class="text tw-flex tw-items-center tw-mr-1 gt-ellipsis"> + <div class="ui dropdown custom branch-selector-dropdown"> + <div class="ui button branch-dropdown-button" @click="menuVisible = !menuVisible" @keyup.enter="menuVisible = !menuVisible"> + <span class="flex-text-block gt-ellipsis"> <template v-if="release">{{ textReleaseCompare }}</template> <template v-else> <svg-icon v-if="isViewTag" name="octicon-tag"/> @@ -257,7 +257,7 @@ export default sfc; // activate IDE's Vue plugin </template> </span> <svg-icon name="octicon-triangle-down" :size="14" class-name="dropdown icon"/> - </button> + </div> <div class="menu transition" :class="{visible: menuVisible}" v-show="menuVisible" v-cloak> <div class="ui icon search input"> <i class="icon"><svg-icon name="octicon-filter" :size="16"/></i> @@ -317,43 +317,3 @@ export default sfc; // activate IDE's Vue plugin </div> </div> </template> -<style scoped> -.branch-tag-tab { - padding: 0 10px; -} - -.branch-tag-item { - display: inline-block; - padding: 10px; - border: 1px solid transparent; - border-bottom: none; -} - -.branch-tag-item.active { - border-color: var(--color-secondary); - background: var(--color-menu); - border-top-left-radius: var(--border-radius); - border-top-right-radius: var(--border-radius); -} - -.branch-tag-divider { - margin-top: -1px !important; - border-top: 1px solid var(--color-secondary); -} - -.scrolling.menu { - border-top: none !important; -} - -.menu .item .rss-icon { - display: none; /* only show RSS icon on hover */ -} - -.menu .item:hover .rss-icon { - display: inline-block; -} - -.scrolling.menu .loading-indicator { - height: 4em; -} -</style> diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index 18d98c891d..670e60def0 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -19,7 +19,7 @@ import {initCompReactionSelector} from './comp/ReactionSelector.js'; import {initRepoSettingBranches} from './repo-settings.js'; import {initRepoPullRequestMergeForm} from './repo-issue-pr-form.js'; import {initRepoPullRequestCommitStatus} from './repo-issue-pr-status.js'; -import {hideElem, showElem} from '../utils/dom.js'; +import {hideElem, queryElemChildren, showElem} from '../utils/dom.js'; import {POST} from '../modules/fetch.js'; import {initRepoIssueCommentEdit} from './repo-issue-edit.js'; @@ -56,16 +56,19 @@ export function initRepoCommentForm() { } function initBranchSelector() { - const $selectBranch = $('.ui.select-branch'); + const elSelectBranch = document.querySelector('.ui.dropdown.select-branch'); + const isForNewIssue = elSelectBranch.getAttribute('data-for-new-issue') === 'true'; + + const $selectBranch = $(elSelectBranch); const $branchMenu = $selectBranch.find('.reference-list-menu'); - const $isNewIssue = $branchMenu.hasClass('new-issue'); - $branchMenu.find('.item:not(.no-select)').on('click', async function () { - const selectedValue = $(this).data('id'); + $branchMenu.find('.item:not(.no-select)').on('click', async function (e) { + e.preventDefault(); + const selectedValue = $(this).data('id'); // eg: "refs/heads/my-branch" const editMode = $('#editing_mode').val(); $($(this).data('id-selector')).val(selectedValue); - if ($isNewIssue) { - $selectBranch.find('.ui .branch-name').text($(this).data('name')); - return; + if (isForNewIssue) { + elSelectBranch.querySelector('.text-branch-name').textContent = this.getAttribute('data-name'); + return; // only update UI&form, do not send request/reload } if (editMode === 'true') { @@ -84,9 +87,9 @@ export function initRepoCommentForm() { }); $selectBranch.find('.reference.column').on('click', function () { hideElem($selectBranch.find('.scrolling.reference-list-menu')); - $selectBranch.find('.reference .text').removeClass('black'); - showElem($($(this).data('target'))); - $(this).find('.text').addClass('black'); + showElem(this.getAttribute('data-target')); + queryElemChildren(this.parentNode, '.branch-tag-item', (el) => el.classList.remove('active')); + this.classList.add('active'); return false; }); } From 6ff2acc52c976e9d7bb6a5693f8a2365d12400f5 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Thu, 2 May 2024 19:19:44 +0800 Subject: [PATCH 256/370] Fix issue card layout (#30800) Fix #30788 --- templates/repo/issue/card.tmpl | 6 +++--- web_src/css/repo.css | 8 +------- web_src/css/repo/issue-card.css | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/templates/repo/issue/card.tmpl b/templates/repo/issue/card.tmpl index 4a0ac050aa..526f6dd5db 100644 --- a/templates/repo/issue/card.tmpl +++ b/templates/repo/issue/card.tmpl @@ -62,13 +62,13 @@ </div> {{if or .Labels .Assignees}} - <div class="tw-flex tw-justify-between"> - <div class="labels-list tw-flex-1"> + <div class="issue-card-bottom"> + <div class="labels-list"> {{range .Labels}} <a target="_blank" href="{{$.Issue.Repo.Link}}/issues?labels={{.ID}}">{{RenderLabel ctx ctx.Locale .}}</a> {{end}} </div> - <div class="tw-flex tw-flex-wrap tw-content-start tw-gap-1"> + <div class="issue-card-assignees"> {{range .Assignees}} <a target="_blank" href="{{.HomeLink}}" data-tooltip-content="{{ctx.Locale.Tr "repo.projects.column.assigned_to"}} {{.Name}}">{{ctx.AvatarUtils.Avatar . 28}}</a> {{end}} diff --git a/web_src/css/repo.css b/web_src/css/repo.css index cc09ec94e2..a930e130f8 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -2195,18 +2195,12 @@ td .commit-summary { display: inline-flex; flex-wrap: wrap; gap: 2.5px; -} - -.labels-list a { - display: flex; - text-decoration: none; + align-items: center; } .labels-list .label { padding: 0 6px; - margin: 0 !important; min-height: 20px; - display: inline-flex !important; line-height: 1.3; /* there is a `font-size: 1.25em` for inside emoji, so here the line-height needs to be larger slightly */ } diff --git a/web_src/css/repo/issue-card.css b/web_src/css/repo/issue-card.css index 609b1b3dbd..390bfb6a01 100644 --- a/web_src/css/repo/issue-card.css +++ b/web_src/css/repo/issue-card.css @@ -23,3 +23,18 @@ .issue-card.sortable-chosen .issue-card-title { cursor: inherit; } + +.issue-card-bottom { + display: flex; + width: 100%; + justify-content: space-between; + gap: 0.25em; +} + +.issue-card-assignees { + display: flex; + align-items: center; + gap: 0.25em; + justify-content: end; + flex-wrap: wrap; +} From eb8bb82e584f0d0cb91ebc0e37e40c53da729ce8 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Thu, 2 May 2024 21:22:55 +0800 Subject: [PATCH 257/370] Fix activity heat map padding & locale (#30823) Fix #30808 --------- Co-authored-by: silverwind <me@silverwind.io> --- package-lock.json | 26 +++++++++++------------ package.json | 2 +- web_src/js/components/ActivityHeatmap.vue | 12 ++++++----- web_src/js/features/heatmap.js | 17 +++++++++------ 4 files changed, 31 insertions(+), 26 deletions(-) diff --git a/package-lock.json b/package-lock.json index 917ff1029b..bba4ca5a9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@github/text-expander-element": "2.6.1", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", "@primer/octicons": "19.9.0", + "@silverwind/vue3-calendar-heatmap": "2.0.6", "add-asset-webpack-plugin": "2.0.1", "ansi_up": "6.0.2", "asciinema-player": "3.7.1", @@ -57,7 +58,6 @@ "vue-bar-graph": "2.0.0", "vue-chartjs": "5.3.1", "vue-loader": "17.4.2", - "vue3-calendar-heatmap": "2.0.5", "webpack": "5.91.0", "webpack-cli": "5.1.4", "wrap-ansi": "9.0.0" @@ -1626,6 +1626,18 @@ "win32" ] }, + "node_modules/@silverwind/vue3-calendar-heatmap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@silverwind/vue3-calendar-heatmap/-/vue3-calendar-heatmap-2.0.6.tgz", + "integrity": "sha512-efX+nf2GR7EfA7iNgZDeM9Jue5ksglSXvN0C/ja0M1bTmkCpAxKlGJ3vki7wfTPQgX1O0nCfAM62IKqUUEM0cQ==", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "tippy.js": "^6.3.7", + "vue": "^3.2.29" + } + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -12200,18 +12212,6 @@ } } }, - "node_modules/vue3-calendar-heatmap": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/vue3-calendar-heatmap/-/vue3-calendar-heatmap-2.0.5.tgz", - "integrity": "sha512-qvveNQlTS5Aw7AvRLs0zOyu3uP5iGJlXJAnkrkG2ElDdyQ8H1TJhQ8rL702CROjAg16ezIveUY10nCO7lqZ25w==", - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "tippy.js": "^6.3.7", - "vue": "^3.2.29" - } - }, "node_modules/watchpack": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", diff --git a/package.json b/package.json index 5f9b810320..107f0c96cf 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@github/text-expander-element": "2.6.1", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", "@primer/octicons": "19.9.0", + "@silverwind/vue3-calendar-heatmap": "2.0.6", "add-asset-webpack-plugin": "2.0.1", "ansi_up": "6.0.2", "asciinema-player": "3.7.1", @@ -56,7 +57,6 @@ "vue-bar-graph": "2.0.0", "vue-chartjs": "5.3.1", "vue-loader": "17.4.2", - "vue3-calendar-heatmap": "2.0.5", "webpack": "5.91.0", "webpack-cli": "5.1.4", "wrap-ansi": "9.0.0" diff --git a/web_src/js/components/ActivityHeatmap.vue b/web_src/js/components/ActivityHeatmap.vue index 9592a0df3c..71f41dda1a 100644 --- a/web_src/js/components/ActivityHeatmap.vue +++ b/web_src/js/components/ActivityHeatmap.vue @@ -1,5 +1,6 @@ <script> -import {CalendarHeatmap} from 'vue3-calendar-heatmap'; +// TODO: Switch to upstream after https://github.com/razorness/vue3-calendar-heatmap/pull/34 is merged +import {CalendarHeatmap} from '@silverwind/vue3-calendar-heatmap'; export default { components: {CalendarHeatmap}, @@ -55,15 +56,16 @@ export default { </script> <template> <div class="total-contributions"> - {{ locale.contributions_in_the_last_12_months }} + {{ locale.textTotalContributions }} </div> <calendar-heatmap - :locale="locale" - :no-data-text="locale.no_contributions" - :tooltip-unit="locale.contributions" + :locale="locale.heatMapLocale" + :no-data-text="locale.noDataText" + :tooltip-unit="locale.tooltipUnit" :end-date="endDate" :values="values" :range-color="colorRange" @day-click="handleDayClick($event)" + :tippy-props="{theme: 'tooltip'}" /> </template> diff --git a/web_src/js/features/heatmap.js b/web_src/js/features/heatmap.js index b6f06d0cfb..719eeb75fb 100644 --- a/web_src/js/features/heatmap.js +++ b/web_src/js/features/heatmap.js @@ -20,13 +20,16 @@ export function initHeatmap() { // last heatmap tooltip localization attempt https://github.com/go-gitea/gitea/pull/24131/commits/a83761cbbae3c2e3b4bced71e680f44432073ac8 const locale = { - months: new Array(12).fill().map((_, idx) => translateMonth(idx)), - days: new Array(7).fill().map((_, idx) => translateDay(idx)), - contributions: 'contributions', - contributions_in_the_last_12_months: el.getAttribute('data-locale-total-contributions'), - no_contributions: el.getAttribute('data-locale-no-contributions'), - more: el.getAttribute('data-locale-more'), - less: el.getAttribute('data-locale-less'), + heatMapLocale: { + months: new Array(12).fill().map((_, idx) => translateMonth(idx)), + days: new Array(7).fill().map((_, idx) => translateDay(idx)), + on: ' - ', // no correct locale support for it, because in many languages the sentence is not "something on someday" + more: el.getAttribute('data-locale-more'), + less: el.getAttribute('data-locale-less'), + }, + tooltipUnit: 'contributions', + textTotalContributions: el.getAttribute('data-locale-total-contributions'), + noDataText: el.getAttribute('data-locale-no-contributions'), }; const View = createApp(ActivityHeatmap, {values, locale}); From b1bb3642e52ae1401bb06de130b17db48cff379e Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Thu, 2 May 2024 15:42:33 +0200 Subject: [PATCH 258/370] Improve context popup rendering (#30824) Before, lot of empty space when no labels or body: <img width="281" alt="Screenshot 2024-05-02 at 13 51 29" src="https://github.com/go-gitea/gitea/assets/115237/8a980ccd-d53c-43a3-a059-dc8c614621e1"> After, empty space collapsed: <img width="306" alt="Screenshot 2024-05-02 at 13 51 16" src="https://github.com/go-gitea/gitea/assets/115237/8d9c154d-5de1-43d0-8536-afd9194d99b3"> All `<p>` (unsuitable) and `<small>` (discouraged in favor of css) tags are removed. --- web_src/js/components/.eslintrc.yaml | 1 + web_src/js/components/ContextPopup.vue | 22 ++++++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/web_src/js/components/.eslintrc.yaml b/web_src/js/components/.eslintrc.yaml index 0d233442bc..a79e96f330 100644 --- a/web_src/js/components/.eslintrc.yaml +++ b/web_src/js/components/.eslintrc.yaml @@ -18,4 +18,5 @@ rules: vue/attributes-order: [0] vue/html-closing-bracket-spacing: [2, {startTag: never, endTag: never, selfClosingTag: never}] vue/max-attributes-per-line: [0] + vue/singleline-html-element-content-newline: [0] vue-scoped-css/enforce-style-type: [0] diff --git a/web_src/js/components/ContextPopup.vue b/web_src/js/components/ContextPopup.vue index e4e8bce184..8f389ea003 100644 --- a/web_src/js/components/ContextPopup.vue +++ b/web_src/js/components/ContextPopup.vue @@ -91,16 +91,22 @@ export default { <template> <div ref="root"> <div v-if="loading" class="tw-h-12 tw-w-12 is-loading"/> - <div v-if="!loading && issue !== null"> - <p><small>{{ issue.repository.full_name }} on {{ createdAt }}</small></p> - <p><svg-icon :name="icon" :class="['text', color]"/> <strong>{{ issue.title }}</strong> #{{ issue.number }}</p> - <p>{{ body }}</p> + <div v-if="!loading && issue !== null" class="tw-flex tw-flex-col tw-gap-2"> + <div class="tw-text-12">{{ issue.repository.full_name }} on {{ createdAt }}</div> + <div class="flex-text-block"> + <svg-icon :name="icon" :class="['text', color]"/> + <span class="issue-title tw-font-semibold tw-break-anywhere"> + {{ issue.title }} + <span class="index">#{{ issue.number }}</span> + </span> + </div> + <div v-if="body">{{ body }}</div> <!-- eslint-disable-next-line vue/no-v-html --> - <div v-html="renderedLabels"/> + <div v-if="issue.labels.length" v-html="renderedLabels"/> </div> - <div v-if="!loading && issue === null"> - <p><small>{{ i18nErrorOccurred }}</small></p> - <p>{{ i18nErrorMessage }}</p> + <div class="tw-flex tw-flex-col tw-gap-2" v-if="!loading && issue === null"> + <div class="tw-text-12">{{ i18nErrorOccurred }}</div> + <div>{{ i18nErrorMessage }}</div> </div> </div> </template> From cb9e1a3ff66f24f89d99f839376e304161c12962 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Thu, 2 May 2024 22:09:38 +0800 Subject: [PATCH 259/370] Upgrade chi-binding (#30826) Front port #30742 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 2c1fc5d6f2..bab5a64069 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( code.gitea.io/sdk/gitea v0.17.1 codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570 connectrpc.com/connect v1.15.0 - gitea.com/go-chi/binding v0.0.0-20240316035258-17450c5f3028 + gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed gitea.com/go-chi/cache v0.2.0 gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098 gitea.com/go-chi/session v0.0.0-20240316035857-16768d98ec96 diff --git a/go.sum b/go.sum index 8c26b4a7a6..3bb4cbaa42 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,8 @@ git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4H git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs= gitea.com/gitea/act v0.259.1 h1:8GG1o/xtUHl3qjn5f0h/2FXrT5ubBn05TJOM5ry+FBw= gitea.com/gitea/act v0.259.1/go.mod h1:UxZWRYqQG2Yj4+4OqfGWW5a3HELwejyWFQyU7F1jUD8= -gitea.com/go-chi/binding v0.0.0-20240316035258-17450c5f3028 h1:6/QAx4+s0dyRwdaTFPTnhGppuiuu0OqxIH9szyTpvKw= -gitea.com/go-chi/binding v0.0.0-20240316035258-17450c5f3028/go.mod h1:E3i3cgB04dDx0v3CytCgRTTn9Z/9x891aet3r456RVw= +gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed h1:EZZBtilMLSZNWtHHcgq2mt6NSGhJSZBuduAlinMEmso= +gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed/go.mod h1:E3i3cgB04dDx0v3CytCgRTTn9Z/9x891aet3r456RVw= gitea.com/go-chi/cache v0.2.0 h1:E0npuTfDW6CT1yD8NMDVc1SK6IeRjfmRL2zlEsCEd7w= gitea.com/go-chi/cache v0.2.0/go.mod h1:iQlVK2aKTZ/rE9UcHyz9pQWGvdP9i1eI2spOpzgCrtE= gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098 h1:p2ki+WK0cIeNQuqjR98IP2KZQKRzJJiV7aTeMAFwaWo= From 9235442ba58524c8d12ae54865d583acfa1f439d Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Thu, 2 May 2024 16:43:23 +0200 Subject: [PATCH 260/370] Remove external API calls in `TestPassword` (#30716) The test had a dependency on `https://api.pwnedpasswords.com` which caused many failures on CI recently: ``` --- FAIL: TestPassword (2.37s) pwn_test.go:41: Get "https://api.pwnedpasswords.com/range/e6b6a": context deadline exceeded (Client.Timeout exceeded while awaiting headers) FAIL coverage: 82.9% of statements ``` --- go.mod | 2 + go.sum | 6 ++ modules/auth/password/pwn/pwn_test.go | 101 ++++++-------------------- 3 files changed, 32 insertions(+), 77 deletions(-) diff --git a/go.mod b/go.mod index bab5a64069..8afefc6367 100644 --- a/go.mod +++ b/go.mod @@ -59,6 +59,7 @@ require ( github.com/google/uuid v1.6.0 github.com/gorilla/feeds v1.1.2 github.com/gorilla/sessions v1.2.2 + github.com/h2non/gock v1.2.0 github.com/hashicorp/go-version v1.6.0 github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/huandu/xstrings v1.4.0 @@ -209,6 +210,7 @@ require ( github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/securecookie v1.1.2 // indirect + github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.5 // indirect github.com/hashicorp/hcl v1.0.0 // indirect diff --git a/go.sum b/go.sum index 3bb4cbaa42..1d493f4ca4 100644 --- a/go.sum +++ b/go.sum @@ -430,6 +430,10 @@ github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pw github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY= github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= +github.com/h2non/gock v1.2.0 h1:K6ol8rfrRkUOefooBC8elXoaNGYkpp7y2qcxGG6BzUE= +github.com/h2non/gock v1.2.0/go.mod h1:tNhoxHYW2W42cYkYb1WqzdbYIieALC99kpYr7rH/BQk= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= @@ -591,6 +595,8 @@ github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= github.com/msteinert/pam v1.2.0 h1:mYfjlvN2KYs2Pb9G6nb/1f/nPfAttT/Jee5Sq9r3bGE= github.com/msteinert/pam v1.2.0/go.mod h1:d2n0DCUK8rGecChV3JzvmsDjOY4R7AYbsNxAT+ftQl0= +github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4= +github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/niklasfasching/go-org v1.7.0 h1:vyMdcMWWTe/XmANk19F4k8XGBYg0GQ/gJGMimOjGMek= github.com/niklasfasching/go-org v1.7.0/go.mod h1:WuVm4d45oePiE0eX25GqTDQIt/qPW1T9DGkRscqLW5o= github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= diff --git a/modules/auth/password/pwn/pwn_test.go b/modules/auth/password/pwn/pwn_test.go index a2a6b3a174..b3e7734c3f 100644 --- a/modules/auth/password/pwn/pwn_test.go +++ b/modules/auth/password/pwn/pwn_test.go @@ -4,12 +4,11 @@ package pwn import ( - "math/rand/v2" "net/http" - "strings" "testing" "time" + "github.com/h2non/gock" "github.com/stretchr/testify/assert" ) @@ -18,86 +17,34 @@ var client = New(WithHTTP(&http.Client{ })) func TestPassword(t *testing.T) { - // Check input error - _, err := client.CheckPassword("", false) + defer gock.Off() + + count, err := client.CheckPassword("", false) assert.ErrorIs(t, err, ErrEmptyPassword, "blank input should return ErrEmptyPassword") + assert.Equal(t, -1, count) - // Should fail - fail := "password1234" - count, err := client.CheckPassword(fail, false) - assert.NotEmpty(t, count, "%s should fail as a password", fail) + gock.New("https://api.pwnedpasswords.com").Get("/range/5c1d8").Times(1).Reply(200).BodyString("EAF2F254732680E8AC339B84F3266ECCBB5:1\r\nFC446EB88938834178CB9322C1EE273C2A7:2") + count, err = client.CheckPassword("pwned", false) assert.NoError(t, err) + assert.Equal(t, 1, count) - // Should fail (with padding) - failPad := "administrator" - count, err = client.CheckPassword(failPad, true) - assert.NotEmpty(t, count, "%s should fail as a password", failPad) + gock.New("https://api.pwnedpasswords.com").Get("/range/ba189").Times(1).Reply(200).BodyString("FD4CB34F0378BCB15D23F6FFD28F0775C9E:3\r\nFDF342FCD8C3611DAE4D76E8A992A3E4169:4") + count, err = client.CheckPassword("notpwned", false) assert.NoError(t, err) + assert.Equal(t, 0, count) - // Checking for a "good" password isn't going to be perfect, but we can give it a good try - // with hopefully minimal error. Try five times? - assert.Condition(t, func() bool { - for i := 0; i <= 5; i++ { - count, err = client.CheckPassword(testPassword(), false) - assert.NoError(t, err) - if count == 0 { - return true - } - } - return false - }, "no generated passwords passed. there is a chance this is a fluke") + gock.New("https://api.pwnedpasswords.com").Get("/range/a1733").Times(1).Reply(200).BodyString("C4CE0F1F0062B27B9E2F41AF0C08218017C:1\r\nFC446EB88938834178CB9322C1EE273C2A7:2\r\nFE81480327C992FE62065A827429DD1318B:0") + count, err = client.CheckPassword("paddedpwned", true) + assert.NoError(t, err) + assert.Equal(t, 1, count) - // Again, but with padded responses - assert.Condition(t, func() bool { - for i := 0; i <= 5; i++ { - count, err = client.CheckPassword(testPassword(), true) - assert.NoError(t, err) - if count == 0 { - return true - } - } - return false - }, "no generated passwords passed. there is a chance this is a fluke") -} - -// Credit to https://golangbyexample.com/generate-random-password-golang/ -// DO NOT USE THIS FOR AN ACTUAL PASSWORD GENERATOR -var ( - lowerCharSet = "abcdedfghijklmnopqrst" - upperCharSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - specialCharSet = "!@#$%&*" - numberSet = "0123456789" - allCharSet = lowerCharSet + upperCharSet + specialCharSet + numberSet -) - -func testPassword() string { - var password strings.Builder - - // Set special character - for i := 0; i < 5; i++ { - random := rand.IntN(len(specialCharSet)) - password.WriteString(string(specialCharSet[random])) - } - - // Set numeric - for i := 0; i < 5; i++ { - random := rand.IntN(len(numberSet)) - password.WriteString(string(numberSet[random])) - } - - // Set uppercase - for i := 0; i < 5; i++ { - random := rand.IntN(len(upperCharSet)) - password.WriteString(string(upperCharSet[random])) - } - - for i := 0; i < 5; i++ { - random := rand.IntN(len(allCharSet)) - password.WriteString(string(allCharSet[random])) - } - inRune := []rune(password.String()) - rand.Shuffle(len(inRune), func(i, j int) { - inRune[i], inRune[j] = inRune[j], inRune[i] - }) - return string(inRune) + gock.New("https://api.pwnedpasswords.com").Get("/range/5617b").Times(1).Reply(200).BodyString("FD4CB34F0378BCB15D23F6FFD28F0775C9E:3\r\nFDF342FCD8C3611DAE4D76E8A992A3E4169:4\r\nFE81480327C992FE62065A827429DD1318B:0") + count, err = client.CheckPassword("paddednotpwned", true) + assert.NoError(t, err) + assert.Equal(t, 0, count) + + gock.New("https://api.pwnedpasswords.com").Get("/range/79082").Times(1).Reply(200).BodyString("FDF342FCD8C3611DAE4D76E8A992A3E4169:4\r\nFE81480327C992FE62065A827429DD1318B:0\r\nAFEF386F56EB0B4BE314E07696E5E6E6536:0") + count, err = client.CheckPassword("paddednotpwnedzero", true) + assert.NoError(t, err) + assert.Equal(t, 0, count) } From 6f89d5e3a0886d02ead732005f593ae003f78f78 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Thu, 2 May 2024 16:56:17 +0200 Subject: [PATCH 261/370] Add hover outline to heatmap squares (#30828) Makes it easier to use because you see which square is currently hovered: <img width="314" alt="Screenshot 2024-05-02 at 15 38 20" src="https://github.com/go-gitea/gitea/assets/115237/3a15dad1-2259-4f28-9fae-5cf6ad3d8798"> I did try a `scoped` style for this, but that did not work for some reason. --- web_src/css/features/heatmap.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web_src/css/features/heatmap.css b/web_src/css/features/heatmap.css index 364754751a..c064590c46 100644 --- a/web_src/css/features/heatmap.css +++ b/web_src/css/features/heatmap.css @@ -31,6 +31,10 @@ padding: 0 5px; } +#user-heatmap .vch__day__square:hover { + outline: 1.5px solid var(--color-text); +} + /* move the "? contributions in the last ? months" text from top to bottom */ #user-heatmap .total-contributions { font-size: 11px; From 677032d36af9a4052b838e011142d9e0bc706ef5 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Thu, 2 May 2024 23:24:21 +0800 Subject: [PATCH 262/370] Fix incorrect message id for releaes email (#30825) Make generateMessageIDForRelease outputs the same format as generateMessageIDForIssue (old `createReference`) --- services/mailer/mail.go | 10 +++++++--- services/mailer/mail_release.go | 4 ++-- services/mailer/mail_test.go | 14 +++++++++++--- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/services/mailer/mail.go b/services/mailer/mail.go index a63ba7a52a..04194dcf26 100644 --- a/services/mailer/mail.go +++ b/services/mailer/mail.go @@ -289,8 +289,8 @@ func composeIssueCommentMessages(ctx *mailCommentContext, lang string, recipient } // Make sure to compose independent messages to avoid leaking user emails - msgID := createReference(ctx.Issue, ctx.Comment, ctx.ActionType) - reference := createReference(ctx.Issue, nil, activities_model.ActionType(0)) + msgID := generateMessageIDForIssue(ctx.Issue, ctx.Comment, ctx.ActionType) + reference := generateMessageIDForIssue(ctx.Issue, nil, activities_model.ActionType(0)) var replyPayload []byte if ctx.Comment != nil { @@ -362,7 +362,7 @@ func composeIssueCommentMessages(ctx *mailCommentContext, lang string, recipient return msgs, nil } -func createReference(issue *issues_model.Issue, comment *issues_model.Comment, actionType activities_model.ActionType) string { +func generateMessageIDForIssue(issue *issues_model.Issue, comment *issues_model.Comment, actionType activities_model.ActionType) string { var path string if issue.IsPull { path = "pulls" @@ -389,6 +389,10 @@ func createReference(issue *issues_model.Issue, comment *issues_model.Comment, a return fmt.Sprintf("<%s/%s/%d%s@%s>", issue.Repo.FullName(), path, issue.Index, extra, setting.Domain) } +func generateMessageIDForRelease(release *repo_model.Release) string { + return fmt.Sprintf("<%s/releases/%d@%s>", release.Repo.FullName(), release.ID, setting.Domain) +} + func generateAdditionalHeaders(ctx *mailCommentContext, reason string, recipient *user_model.User) map[string]string { repo := ctx.Issue.Repo diff --git a/services/mailer/mail_release.go b/services/mailer/mail_release.go index 6682774a04..2aac21e552 100644 --- a/services/mailer/mail_release.go +++ b/services/mailer/mail_release.go @@ -86,11 +86,11 @@ func mailNewRelease(ctx context.Context, lang string, tos []string, rel *repo_mo msgs := make([]*Message, 0, len(tos)) publisherName := rel.Publisher.DisplayName() - relURL := "<" + rel.HTMLURL() + ">" + msgID := generateMessageIDForRelease(rel) for _, to := range tos { msg := NewMessageFrom(to, publisherName, setting.MailService.FromEmail, subject, mailBody.String()) msg.Info = subject - msg.SetHeader("Message-ID", relURL) + msg.SetHeader("Message-ID", msgID) msgs = append(msgs, msg) } diff --git a/services/mailer/mail_test.go b/services/mailer/mail_test.go index d87c57ffe7..0739f4233f 100644 --- a/services/mailer/mail_test.go +++ b/services/mailer/mail_test.go @@ -288,7 +288,7 @@ func TestGenerateAdditionalHeaders(t *testing.T) { } } -func Test_createReference(t *testing.T) { +func TestGenerateMessageIDForIssue(t *testing.T) { _, _, issue, comment := prepareMailerTest(t) _, _, pullIssue, _ := prepareMailerTest(t) pullIssue.IsPull = true @@ -388,10 +388,18 @@ func Test_createReference(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := createReference(tt.args.issue, tt.args.comment, tt.args.actionType) + got := generateMessageIDForIssue(tt.args.issue, tt.args.comment, tt.args.actionType) if !strings.HasPrefix(got, tt.prefix) { - t.Errorf("createReference() = %v, want %v", got, tt.prefix) + t.Errorf("generateMessageIDForIssue() = %v, want %v", got, tt.prefix) } }) } } + +func TestGenerateMessageIDForRelease(t *testing.T) { + msgID := generateMessageIDForRelease(&repo_model.Release{ + ID: 1, + Repo: &repo_model.Repository{OwnerName: "owner", Name: "repo"}, + }) + assert.Equal(t, "<owner/repo/releases/1@localhost>", msgID) +} From 872caa17c0a30d95f85ab75c068d606e07bd10b3 Mon Sep 17 00:00:00 2001 From: Kemal Zebari <60799661+kemzeb@users.noreply.github.com> Date: Thu, 2 May 2024 09:33:31 -0700 Subject: [PATCH 263/370] Catch and handle unallowed file type errors in issue attachment API (#30791) Before, we would just throw 500 if a user passes an attachment that is not an allowed type. This commit catches this error and throws a 422 instead since this should be considered a validation error. --- routers/api/v1/repo/issue_attachment.go | 9 +++++- .../api/v1/repo/issue_comment_attachment.go | 10 ++++++- templates/swagger/v1_json.tmpl | 6 ++++ .../api_comment_attachment_test.go | 28 +++++++++++++++++++ .../integration/api_issue_attachment_test.go | 27 ++++++++++++++++++ 5 files changed, 78 insertions(+), 2 deletions(-) diff --git a/routers/api/v1/repo/issue_attachment.go b/routers/api/v1/repo/issue_attachment.go index 7a5c6d554d..f5a28e6fa6 100644 --- a/routers/api/v1/repo/issue_attachment.go +++ b/routers/api/v1/repo/issue_attachment.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/attachment" "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/context/upload" "code.gitea.io/gitea/services/convert" issue_service "code.gitea.io/gitea/services/issue" ) @@ -153,6 +154,8 @@ func CreateIssueAttachment(ctx *context.APIContext) { // "$ref": "#/responses/error" // "404": // "$ref": "#/responses/error" + // "422": + // "$ref": "#/responses/validationError" // "423": // "$ref": "#/responses/repoArchivedError" @@ -185,7 +188,11 @@ func CreateIssueAttachment(ctx *context.APIContext) { IssueID: issue.ID, }) if err != nil { - ctx.Error(http.StatusInternalServerError, "UploadAttachment", err) + if upload.IsErrFileTypeForbidden(err) { + ctx.Error(http.StatusUnprocessableEntity, "", err) + } else { + ctx.Error(http.StatusInternalServerError, "UploadAttachment", err) + } return } diff --git a/routers/api/v1/repo/issue_comment_attachment.go b/routers/api/v1/repo/issue_comment_attachment.go index 4096cbf07b..77aa7f0400 100644 --- a/routers/api/v1/repo/issue_comment_attachment.go +++ b/routers/api/v1/repo/issue_comment_attachment.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/attachment" "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/context/upload" "code.gitea.io/gitea/services/convert" issue_service "code.gitea.io/gitea/services/issue" ) @@ -160,6 +161,8 @@ func CreateIssueCommentAttachment(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/error" + // "422": + // "$ref": "#/responses/validationError" // "423": // "$ref": "#/responses/repoArchivedError" @@ -194,9 +197,14 @@ func CreateIssueCommentAttachment(ctx *context.APIContext) { CommentID: comment.ID, }) if err != nil { - ctx.Error(http.StatusInternalServerError, "UploadAttachment", err) + if upload.IsErrFileTypeForbidden(err) { + ctx.Error(http.StatusUnprocessableEntity, "", err) + } else { + ctx.Error(http.StatusInternalServerError, "UploadAttachment", err) + } return } + if err := comment.LoadAttachments(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadAttachments", err) return diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 0c5e5c974d..5ca499e708 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -7478,6 +7478,9 @@ "404": { "$ref": "#/responses/error" }, + "422": { + "$ref": "#/responses/validationError" + }, "423": { "$ref": "#/responses/repoArchivedError" } @@ -8097,6 +8100,9 @@ "404": { "$ref": "#/responses/error" }, + "422": { + "$ref": "#/responses/validationError" + }, "423": { "$ref": "#/responses/repoArchivedError" } diff --git a/tests/integration/api_comment_attachment_test.go b/tests/integration/api_comment_attachment_test.go index 2d7587bbde..0ec950d4c2 100644 --- a/tests/integration/api_comment_attachment_test.go +++ b/tests/integration/api_comment_attachment_test.go @@ -120,6 +120,34 @@ func TestAPICreateCommentAttachment(t *testing.T) { unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{ID: apiAttachment.ID, CommentID: comment.ID}) } +func TestAPICreateCommentAttachmentWithUnallowedFile(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 2}) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}) + repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) + + session := loginUser(t, repoOwner.Name) + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteIssue) + + filename := "file.bad" + body := &bytes.Buffer{} + + // Setup multi-part. + writer := multipart.NewWriter(body) + _, err := writer.CreateFormFile("attachment", filename) + assert.NoError(t, err) + err = writer.Close() + assert.NoError(t, err) + + req := NewRequestWithBody(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d/assets", repoOwner.Name, repo.Name, comment.ID), body). + AddTokenAuth(token). + SetHeader("Content-Type", writer.FormDataContentType()) + + session.MakeRequest(t, req, http.StatusUnprocessableEntity) +} + func TestAPIEditCommentAttachment(t *testing.T) { defer tests.PrepareTestEnv(t)() diff --git a/tests/integration/api_issue_attachment_test.go b/tests/integration/api_issue_attachment_test.go index 497dd0155e..b4196ec6db 100644 --- a/tests/integration/api_issue_attachment_test.go +++ b/tests/integration/api_issue_attachment_test.go @@ -96,6 +96,33 @@ func TestAPICreateIssueAttachment(t *testing.T) { unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{ID: apiAttachment.ID, IssueID: issue.ID}) } +func TestAPICreateIssueAttachmentWithUnallowedFile(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: repo.ID}) + repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) + + session := loginUser(t, repoOwner.Name) + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteIssue) + + filename := "file.bad" + body := &bytes.Buffer{} + + // Setup multi-part. + writer := multipart.NewWriter(body) + _, err := writer.CreateFormFile("attachment", filename) + assert.NoError(t, err) + err = writer.Close() + assert.NoError(t, err) + + req := NewRequestWithBody(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/assets", repoOwner.Name, repo.Name, issue.Index), body). + AddTokenAuth(token) + req.Header.Add("Content-Type", writer.FormDataContentType()) + + session.MakeRequest(t, req, http.StatusUnprocessableEntity) +} + func TestAPIEditIssueAttachment(t *testing.T) { defer tests.PrepareTestEnv(t)() From 5c542ca94caa3587329167cfe9e949357ca15cf1 Mon Sep 17 00:00:00 2001 From: Archer <archer@beezig.eu> Date: Thu, 2 May 2024 19:05:59 +0200 Subject: [PATCH 264/370] Prevent automatic OAuth grants for public clients (#30790) This commit forces the resource owner (user) to always approve OAuth 2.0 authorization requests if the client is public (e.g. native applications). As detailed in [RFC 6749 Section 10.2](https://www.rfc-editor.org/rfc/rfc6749.html#section-10.2), > The authorization server SHOULD NOT process repeated authorization requests automatically (without active resource owner interaction) without authenticating the client or relying on other measures to ensure that the repeated request comes from the original client and not an impersonator. With the implementation prior to this patch, attackers with access to the redirect URI (e.g., the loopback interface for `git-credential-oauth`) can get access to the user account without any user interaction if they can redirect the user to the `/login/oauth/authorize` endpoint somehow (e.g., with `xdg-open` on Linux). Fixes #25061. Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> --- routers/web/auth/oauth.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index c9cb7859cd..354e70bcbf 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -470,8 +470,9 @@ func AuthorizeOAuth(ctx *context.Context) { return } - // Redirect if user already granted access - if grant != nil { + // Redirect if user already granted access and the application is confidential. + // I.e. always require authorization for public clients as recommended by RFC 6749 Section 10.2 + if app.ConfidentialClient && grant != nil { code, err := grant.GenerateNewAuthorizationCode(ctx, form.RedirectURI, form.CodeChallenge, form.CodeChallengeMethod) if err != nil { handleServerError(ctx, form.State, form.RedirectURI) From e67fbe4f15cdc544f6bec975de6560556724f098 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu <appleboy.tw@gmail.com> Date: Fri, 3 May 2024 01:43:29 +0800 Subject: [PATCH 265/370] refactor: merge ListActionTasks func to action.go file (#30811) Just merge actions.go file to action.go Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com> --- routers/api/v1/repo/action.go | 66 ++++++++++++++++++++++++++++ routers/api/v1/repo/actions.go | 80 ---------------------------------- 2 files changed, 66 insertions(+), 80 deletions(-) delete mode 100644 routers/api/v1/repo/actions.go diff --git a/routers/api/v1/repo/action.go b/routers/api/v1/repo/action.go index 311cfca6e9..f6656d89c6 100644 --- a/routers/api/v1/repo/action.go +++ b/routers/api/v1/repo/action.go @@ -17,6 +17,7 @@ import ( "code.gitea.io/gitea/routers/api/v1/utils" actions_service "code.gitea.io/gitea/services/actions" "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/convert" secret_service "code.gitea.io/gitea/services/secrets" ) @@ -517,3 +518,68 @@ type Action struct{} func NewAction() actions_service.API { return Action{} } + +// ListActionTasks list all the actions of a repository +func ListActionTasks(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/actions/tasks repository ListActionTasks + // --- + // summary: List a repository's action tasks + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: page + // in: query + // description: page number of results to return (1-based) + // type: integer + // - name: limit + // in: query + // description: page size of results, default maximum page size is 50 + // type: integer + // responses: + // "200": + // "$ref": "#/responses/TasksList" + // "400": + // "$ref": "#/responses/error" + // "403": + // "$ref": "#/responses/forbidden" + // "404": + // "$ref": "#/responses/notFound" + // "409": + // "$ref": "#/responses/conflict" + // "422": + // "$ref": "#/responses/validationError" + + tasks, total, err := db.FindAndCount[actions_model.ActionTask](ctx, &actions_model.FindTaskOptions{ + ListOptions: utils.GetListOptions(ctx), + RepoID: ctx.Repo.Repository.ID, + }) + if err != nil { + ctx.Error(http.StatusInternalServerError, "ListActionTasks", err) + return + } + + res := new(api.ActionTaskResponse) + res.TotalCount = total + + res.Entries = make([]*api.ActionTask, len(tasks)) + for i := range tasks { + convertedTask, err := convert.ToActionTask(ctx, tasks[i]) + if err != nil { + ctx.Error(http.StatusInternalServerError, "ToActionTask", err) + return + } + res.Entries[i] = convertedTask + } + + ctx.JSON(http.StatusOK, &res) +} diff --git a/routers/api/v1/repo/actions.go b/routers/api/v1/repo/actions.go deleted file mode 100644 index 635cb4e138..0000000000 --- a/routers/api/v1/repo/actions.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package repo - -import ( - "net/http" - - actions_model "code.gitea.io/gitea/models/actions" - "code.gitea.io/gitea/models/db" - api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/routers/api/v1/utils" - "code.gitea.io/gitea/services/context" - "code.gitea.io/gitea/services/convert" -) - -// ListActionTasks list all the actions of a repository -func ListActionTasks(ctx *context.APIContext) { - // swagger:operation GET /repos/{owner}/{repo}/actions/tasks repository ListActionTasks - // --- - // summary: List a repository's action tasks - // produces: - // - application/json - // parameters: - // - name: owner - // in: path - // description: owner of the repo - // type: string - // required: true - // - name: repo - // in: path - // description: name of the repo - // type: string - // required: true - // - name: page - // in: query - // description: page number of results to return (1-based) - // type: integer - // - name: limit - // in: query - // description: page size of results, default maximum page size is 50 - // type: integer - // responses: - // "200": - // "$ref": "#/responses/TasksList" - // "400": - // "$ref": "#/responses/error" - // "403": - // "$ref": "#/responses/forbidden" - // "404": - // "$ref": "#/responses/notFound" - // "409": - // "$ref": "#/responses/conflict" - // "422": - // "$ref": "#/responses/validationError" - - tasks, total, err := db.FindAndCount[actions_model.ActionTask](ctx, &actions_model.FindTaskOptions{ - ListOptions: utils.GetListOptions(ctx), - RepoID: ctx.Repo.Repository.ID, - }) - if err != nil { - ctx.Error(http.StatusInternalServerError, "ListActionTasks", err) - return - } - - res := new(api.ActionTaskResponse) - res.TotalCount = total - - res.Entries = make([]*api.ActionTask, len(tasks)) - for i := range tasks { - convertedTask, err := convert.ToActionTask(ctx, tasks[i]) - if err != nil { - ctx.Error(http.StatusInternalServerError, "ToActionTask", err) - return - } - res.Entries[i] = convertedTask - } - - ctx.JSON(http.StatusOK, &res) -} From c445a85528392a07357b060b19fe29f212cdde25 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Thu, 2 May 2024 21:10:49 +0200 Subject: [PATCH 266/370] Improve repo button row layout (#30668) Since there is now a second `<input>` in the repo buttons, we can make a better-looking layout with no empty space, except on mobile. Also I fixed one bug with focus border on clone panel. ## Large <img width="1163" alt="Screenshot 2024-04-23 at 22 25 22" src="https://github.com/go-gitea/gitea/assets/115237/8135a572-aa67-4672-ad49-b76b06890b52"> ## Medium <img width="870" alt="Screenshot 2024-04-23 at 22 25 34" src="https://github.com/go-gitea/gitea/assets/115237/9e93f61c-3315-4a78-8328-8cefad5b50fa"> ## Mobile <img width="416" alt="Screenshot 2024-04-23 at 22 25 52" src="https://github.com/go-gitea/gitea/assets/115237/859e341f-807a-48e6-8bcf-31715963216c"> --- templates/repo/clone_buttons.tmpl | 2 +- templates/repo/home.tmpl | 12 +++---- web_src/css/modules/input.css | 4 +-- web_src/css/repo.css | 53 +++++++++++++++++++++++++------ 4 files changed, 52 insertions(+), 19 deletions(-) diff --git a/templates/repo/clone_buttons.tmpl b/templates/repo/clone_buttons.tmpl index 89daba9dc9..91952c8a06 100644 --- a/templates/repo/clone_buttons.tmpl +++ b/templates/repo/clone_buttons.tmpl @@ -9,7 +9,7 @@ SSH </button> {{end}} -<input id="repo-clone-url" size="20" class="js-clone-url" value="{{$.CloneButtonOriginLink.HTTPS}}" readonly> +<input id="repo-clone-url" size="10" class="js-clone-url" value="{{$.CloneButtonOriginLink.HTTPS}}" readonly> <button class="ui small icon button" id="clipboard-btn" data-tooltip-content="{{ctx.Locale.Tr "copy_url"}}" data-clipboard-target="#repo-clone-url" aria-label="{{ctx.Locale.Tr "copy_url"}}"> {{svg "octicon-copy" 14}} </button> diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index eb9eb9c149..6df9f7d72a 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -46,7 +46,7 @@ {{$l := Eval $n "-" 1}} {{$isHomepage := (eq $n 0)}} <div class="repo-button-row"> - <div class="tw-flex tw-items-center tw-flex-wrap tw-gap-y-2"> + <div class="repo-button-row-left"> {{template "repo/branch_dropdown" dict "root" . "ContainerClasses" "tw-mr-1"}} {{if and .CanCompareOrPull .IsViewBranch (not .Repository.IsArchived)}} {{$cmpBranch := ""}} @@ -66,7 +66,7 @@ {{end}} {{if and .CanWriteCode .IsViewBranch (not .Repository.IsMirror) (not .Repository.IsArchived) (not .IsViewFile)}} - <button class="ui dropdown basic compact jump button tw-mr-1"{{if not .Repository.CanEnableEditor}} disabled{{end}}> + <button class="ui dropdown basic compact jump button"{{if not .Repository.CanEnableEditor}} disabled{{end}}> {{ctx.Locale.Tr "repo.editor.add_file"}} {{svg "octicon-triangle-down" 14 "dropdown icon"}} <div class="menu"> @@ -93,9 +93,9 @@ {{if $isHomepage}} {{/* only show the "code search" on the repo home page, it only does global search, so do not show it when viewing file or directory to avoid misleading users (it doesn't search in a directory) */}} - <form class="ignore-dirty" action="{{.RepoLink}}/search" method="get"> - <div class="ui small action input"> - <input name="q" placeholder="{{ctx.Locale.Tr "search.code_kind"}}"> + <form class="ignore-dirty tw-flex tw-flex-1" action="{{.RepoLink}}/search" method="get"> + <div class="ui small action input tw-flex-1"> + <input name="q" size="10" placeholder="{{ctx.Locale.Tr "search.code_kind"}}"> {{template "shared/search/button"}} </div> </form> @@ -113,7 +113,7 @@ </span> {{end}} </div> - <div class="tw-flex tw-items-center"> + <div class="repo-button-row-right"> <!-- Only show clone panel in repository home page --> {{if $isHomepage}} <div class="clone-panel ui action tiny input"> diff --git a/web_src/css/modules/input.css b/web_src/css/modules/input.css index 18b785ac82..d39377b4e1 100644 --- a/web_src/css/modules/input.css +++ b/web_src/css/modules/input.css @@ -188,8 +188,8 @@ .ui.action.input:not([class*="left action"]) > input:focus + .ui.dropdown.selection:hover, .ui.action.input:not([class*="left action"]) > input:focus + .button, .ui.action.input:not([class*="left action"]) > input:focus + .button:hover, -.ui.action.input:not([class*="left action"]) > input:focus + .icon + .button, -.ui.action.input:not([class*="left action"]) > input:focus + .icon + .button:hover { +.ui.action.input:not([class*="left action"]) > input:focus + i.icon + .button, +.ui.action.input:not([class*="left action"]) > input:focus + i.icon + .button:hover { border-left-color: var(--color-primary); } .ui.action.input:not([class*="left action"]) > input:focus { diff --git a/web_src/css/repo.css b/web_src/css/repo.css index a930e130f8..408b62ad3c 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -128,15 +128,22 @@ margin-bottom: 12px; } -.repository .clone-panel #repo-clone-url { - width: 320px; - border-radius: 0; +.repository .clone-panel { + display: flex; + flex: 1; } -@media (max-width: 991.98px) { - .repository .clone-panel #repo-clone-url { - width: 200px; - } +.repository.wiki .clone-panel { + flex: 0; +} + +.repository.wiki .clone-panel input { + width: 20ch; +} + +.repository .clone-panel #repo-clone-url { + border-radius: 0; + flex: 1; } .repository .ui.action.input.clone-panel > button + button, @@ -2229,17 +2236,37 @@ td .commit-summary { } .repo-button-row { - margin: 10px 0; + margin: 8px 0; display: flex; align-items: center; - gap: 0.5em; - flex-wrap: wrap; + gap: 8px; justify-content: space-between; } +.repo-button-row-left, +.repo-button-row-right { + display: flex; + flex: 1; + align-items: center; + gap: 0.5rem; +} + +.repo-button-row-right { + justify-content: flex-end; +} + +@media (max-width: 991px) { + .repository:not(.wiki) .repo-button-row { + flex-direction: column; + align-items: stretch; + } +} + .repo-button-row .button { padding: 6px 10px !important; height: 30px; + flex-shrink: 0; + margin: 0; } .repo-button-row .button.dropdown:not(.icon) { @@ -2250,6 +2277,12 @@ td .commit-summary { height: 30px; } +@media (max-width: 600px) { + .repo-button-row-left { + flex-wrap: wrap; + } +} + tbody.commit-list { vertical-align: baseline; } From b30b7df9f4b4e1ae7ec55750bca7577bf88abd0b Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Fri, 3 May 2024 03:48:24 +0200 Subject: [PATCH 267/370] Fix body margin shifting with modals, fix error on project column edit (#30831) Fixes: https://github.com/go-gitea/gitea/issues/30816, regression from https://github.com/go-gitea/gitea/pull/30723. Fixes: https://github.com/go-gitea/gitea/pull/30815, regression from https://github.com/go-gitea/gitea/pull/30723. Fomantic [expects a callback](https://github.com/fomantic/Fomantic-UI/blob/59d9b409879ad9413ea0a3efa4ab2e51017ad9b9/src/definitions/modules/modal.js#L530-L534) to be called during `hide` which we did not do, so it could never remove the margin it added to `body`. I do observe the body content shifting to right by 1px when modal opens, but this is a bug that existed on v1.21 as well, so not a regression. --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> --- web_src/js/modules/fomantic/dimmer.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/web_src/js/modules/fomantic/dimmer.js b/web_src/js/modules/fomantic/dimmer.js index f434e1ca59..e027838d4a 100644 --- a/web_src/js/modules/fomantic/dimmer.js +++ b/web_src/js/modules/fomantic/dimmer.js @@ -3,11 +3,12 @@ import {queryElemChildren} from '../../utils/dom.js'; export function initFomanticDimmer() { // stand-in for removed dimmer module - $.fn.dimmer = function (arg0, $el) { + $.fn.dimmer = function (arg0, arg1) { if (arg0 === 'add content') { + const $el = arg1; const existingDimmer = document.querySelector('body > .ui.dimmer'); if (existingDimmer) { - queryElemChildren(existingDimmer, '*', (el) => el.remove()); + queryElemChildren(existingDimmer, '*', (el) => el.classList.add('hidden')); this._dimmer = existingDimmer; } else { this._dimmer = document.createElement('div'); @@ -21,8 +22,10 @@ export function initFomanticDimmer() { this._dimmer.classList.add('active'); document.body.classList.add('tw-overflow-hidden'); } else if (arg0 === 'hide') { + const cb = arg1; this._dimmer.classList.remove('active'); document.body.classList.remove('tw-overflow-hidden'); + cb(); } return this; }; From c4e875402bd8e787c21bbd4ea07cbb69a8ceef27 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Fri, 3 May 2024 04:12:10 +0200 Subject: [PATCH 268/370] Fix JS error on pull request page (#30838) Fix this error seen on PR page, regression from https://github.com/go-gitea/gitea/pull/30803: Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> --- web_src/js/features/repo-legacy.js | 1 + 1 file changed, 1 insertion(+) diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index 670e60def0..b65938b045 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -57,6 +57,7 @@ export function initRepoCommentForm() { function initBranchSelector() { const elSelectBranch = document.querySelector('.ui.dropdown.select-branch'); + if (!elSelectBranch) return; const isForNewIssue = elSelectBranch.getAttribute('data-for-new-issue') === 'true'; const $selectBranch = $(elSelectBranch); From 53b55223d167c3fc996dd0278a656f421408ace7 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Fri, 3 May 2024 10:39:36 +0800 Subject: [PATCH 269/370] Ignore useless error message "broken pipe" (#30801) Fix #30792 --- routers/api/packages/maven/maven.go | 4 +--- services/context/base.go | 4 +--- services/context/context_response.go | 3 ++- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/routers/api/packages/maven/maven.go b/routers/api/packages/maven/maven.go index 27f0578db7..cb15eae682 100644 --- a/routers/api/packages/maven/maven.go +++ b/routers/api/packages/maven/maven.go @@ -140,9 +140,7 @@ func serveMavenMetadata(ctx *context.Context, params parameters) { ctx.Resp.Header().Set("Content-Length", strconv.Itoa(len(xmlMetadataWithHeader))) ctx.Resp.Header().Set("Content-Type", contentTypeXML) - if _, err := ctx.Resp.Write(xmlMetadataWithHeader); err != nil { - log.Error("write bytes failed: %v", err) - } + _, _ = ctx.Resp.Write(xmlMetadataWithHeader) } func servePackageFile(ctx *context.Context, params parameters, serveContent bool) { diff --git a/services/context/base.go b/services/context/base.go index 62fb743714..05b8ab1b9b 100644 --- a/services/context/base.go +++ b/services/context/base.go @@ -234,9 +234,7 @@ func (b *Base) plainTextInternal(skip, status int, bs []byte) { b.Resp.Header().Set("Content-Type", "text/plain;charset=utf-8") b.Resp.Header().Set("X-Content-Type-Options", "nosniff") b.Resp.WriteHeader(status) - if _, err := b.Resp.Write(bs); err != nil { - log.ErrorWithSkip(skip, "plainTextInternal (status=%d): write bytes failed: %v", status, err) - } + _, _ = b.Resp.Write(bs) } // PlainTextBytes renders bytes as plain text diff --git a/services/context/context_response.go b/services/context/context_response.go index d7fd18acac..87c34c35ed 100644 --- a/services/context/context_response.go +++ b/services/context/context_response.go @@ -13,6 +13,7 @@ import ( "path" "strconv" "strings" + "syscall" "time" user_model "code.gitea.io/gitea/models/user" @@ -77,7 +78,7 @@ func (ctx *Context) HTML(status int, name base.TplName) { } err := ctx.Render.HTML(ctx.Resp, status, string(name), ctx.Data, ctx.TemplateContext) - if err == nil { + if err == nil || errors.Is(err, syscall.EPIPE) { return } From a50026e2f30897904704895362da0fb12c7e5b26 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 3 May 2024 15:11:51 +0900 Subject: [PATCH 270/370] Fix no edit history after editing issue's title and content (#30814) Fix #30807 reuse functions in services --- models/issues/issue_update.go | 56 ----------------------------- modules/structs/pull.go | 2 +- routers/api/v1/repo/issue.go | 36 +++++++++---------- routers/api/v1/repo/pull.go | 37 +++++++++---------- tests/integration/api_issue_test.go | 4 +++ tests/integration/api_pull_test.go | 26 +++++++++----- 6 files changed, 56 insertions(+), 105 deletions(-) diff --git a/models/issues/issue_update.go b/models/issues/issue_update.go index ef96e1ee50..147b7eb3b9 100644 --- a/models/issues/issue_update.go +++ b/models/issues/issue_update.go @@ -429,62 +429,6 @@ func UpdateIssueMentions(ctx context.Context, issueID int64, mentions []*user_mo return nil } -// UpdateIssueByAPI updates all allowed fields of given issue. -// If the issue status is changed a statusChangeComment is returned -// similarly if the title is changed the titleChanged bool is set to true -func UpdateIssueByAPI(ctx context.Context, issue *Issue, doer *user_model.User) (statusChangeComment *Comment, titleChanged bool, err error) { - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return nil, false, err - } - defer committer.Close() - - if err := issue.LoadRepo(ctx); err != nil { - return nil, false, fmt.Errorf("loadRepo: %w", err) - } - - // Reload the issue - currentIssue, err := GetIssueByID(ctx, issue.ID) - if err != nil { - return nil, false, err - } - - if _, err := db.GetEngine(ctx).ID(issue.ID).Cols( - "name", "content", "milestone_id", "priority", - "deadline_unix", "updated_unix", "is_locked"). - Update(issue); err != nil { - return nil, false, err - } - - titleChanged = currentIssue.Title != issue.Title - if titleChanged { - opts := &CreateCommentOptions{ - Type: CommentTypeChangeTitle, - Doer: doer, - Repo: issue.Repo, - Issue: issue, - OldTitle: currentIssue.Title, - NewTitle: issue.Title, - } - _, err := CreateComment(ctx, opts) - if err != nil { - return nil, false, fmt.Errorf("createComment: %w", err) - } - } - - if currentIssue.IsClosed != issue.IsClosed { - statusChangeComment, err = doChangeIssueStatus(ctx, issue, doer, false) - if err != nil { - return nil, false, err - } - } - - if err := issue.AddCrossReferences(ctx, doer, true); err != nil { - return nil, false, err - } - return statusChangeComment, titleChanged, committer.Commit() -} - // UpdateIssueDeadline updates an issue deadline and adds comments. Setting a deadline to 0 means deleting it. func UpdateIssueDeadline(ctx context.Context, issue *Issue, deadlineUnix timeutil.TimeStamp, doer *user_model.User) (err error) { // if the deadline hasn't changed do nothing diff --git a/modules/structs/pull.go b/modules/structs/pull.go index 05a8d59633..b04def52b8 100644 --- a/modules/structs/pull.go +++ b/modules/structs/pull.go @@ -85,7 +85,7 @@ type CreatePullRequestOption struct { // EditPullRequestOption options when modify pull request type EditPullRequestOption struct { Title string `json:"title"` - Body string `json:"body"` + Body *string `json:"body"` Base string `json:"base"` Assignee string `json:"assignee"` Assignees []string `json:"assignees"` diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index dfe6d31f74..b91fbc33bf 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -29,7 +29,6 @@ import ( "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" issue_service "code.gitea.io/gitea/services/issue" - notify_service "code.gitea.io/gitea/services/notify" ) // SearchIssues searches for issues across the repositories that the user has access to @@ -803,12 +802,19 @@ func EditIssue(ctx *context.APIContext) { return } - oldTitle := issue.Title if len(form.Title) > 0 { - issue.Title = form.Title + err = issue_service.ChangeTitle(ctx, issue, ctx.Doer, form.Title) + if err != nil { + ctx.Error(http.StatusInternalServerError, "ChangeTitle", err) + return + } } if form.Body != nil { - issue.Content = *form.Body + err = issue_service.ChangeContent(ctx, issue, ctx.Doer, *form.Body) + if err != nil { + ctx.Error(http.StatusInternalServerError, "ChangeContent", err) + return + } } if form.Ref != nil { err = issue_service.ChangeIssueRef(ctx, issue, ctx.Doer, *form.Ref) @@ -880,24 +886,14 @@ func EditIssue(ctx *context.APIContext) { return } } - issue.IsClosed = api.StateClosed == api.StateType(*form.State) - } - statusChangeComment, titleChanged, err := issues_model.UpdateIssueByAPI(ctx, issue, ctx.Doer) - if err != nil { - if issues_model.IsErrDependenciesLeft(err) { - ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this issue because it still has open dependencies") + if err := issue_service.ChangeStatus(ctx, issue, ctx.Doer, "", api.StateClosed == api.StateType(*form.State)); err != nil { + if issues_model.IsErrDependenciesLeft(err) { + ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this issue because it still has open dependencies") + return + } + ctx.Error(http.StatusInternalServerError, "ChangeStatus", err) return } - ctx.Error(http.StatusInternalServerError, "UpdateIssueByAPI", err) - return - } - - if titleChanged { - notify_service.IssueChangeTitle(ctx, ctx.Doer, issue, oldTitle) - } - - if statusChangeComment != nil { - notify_service.IssueChangeStatus(ctx, ctx.Doer, "", issue, statusChangeComment, issue.IsClosed) } // Refetch from database to assign some automatic values diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index 4129f94ac3..8bd4ddf64b 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -602,12 +602,19 @@ func EditPullRequest(ctx *context.APIContext) { return } - oldTitle := issue.Title if len(form.Title) > 0 { - issue.Title = form.Title + err = issue_service.ChangeTitle(ctx, issue, ctx.Doer, form.Title) + if err != nil { + ctx.Error(http.StatusInternalServerError, "ChangeTitle", err) + return + } } - if len(form.Body) > 0 { - issue.Content = form.Body + if form.Body != nil { + err = issue_service.ChangeContent(ctx, issue, ctx.Doer, *form.Body) + if err != nil { + ctx.Error(http.StatusInternalServerError, "ChangeContent", err) + return + } } // Update or remove deadline if set @@ -686,24 +693,14 @@ func EditPullRequest(ctx *context.APIContext) { ctx.Error(http.StatusPreconditionFailed, "MergedPRState", "cannot change state of this pull request, it was already merged") return } - issue.IsClosed = api.StateClosed == api.StateType(*form.State) - } - statusChangeComment, titleChanged, err := issues_model.UpdateIssueByAPI(ctx, issue, ctx.Doer) - if err != nil { - if issues_model.IsErrDependenciesLeft(err) { - ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this pull request because it still has open dependencies") + if err := issue_service.ChangeStatus(ctx, issue, ctx.Doer, "", api.StateClosed == api.StateType(*form.State)); err != nil { + if issues_model.IsErrDependenciesLeft(err) { + ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this pull request because it still has open dependencies") + return + } + ctx.Error(http.StatusInternalServerError, "ChangeStatus", err) return } - ctx.Error(http.StatusInternalServerError, "UpdateIssueByAPI", err) - return - } - - if titleChanged { - notify_service.IssueChangeTitle(ctx, ctx.Doer, issue, oldTitle) - } - - if statusChangeComment != nil { - notify_service.IssueChangeStatus(ctx, ctx.Doer, "", issue, statusChangeComment, issue.IsClosed) } // change pull target branch diff --git a/tests/integration/api_issue_test.go b/tests/integration/api_issue_test.go index 17b4e5bd71..8bfb6fabe2 100644 --- a/tests/integration/api_issue_test.go +++ b/tests/integration/api_issue_test.go @@ -194,6 +194,10 @@ func TestAPIEditIssue(t *testing.T) { issueAfter := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10}) repoAfter := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID}) + // check comment history + unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: issueAfter.ID, OldTitle: issueBefore.Title, NewTitle: title}) + unittest.AssertExistsAndLoadBean(t, &issues_model.ContentHistory{IssueID: issueAfter.ID, ContentText: body, IsFirstCreated: false}) + // check deleted user assert.Equal(t, int64(500), issueAfter.PosterID) assert.NoError(t, issueAfter.LoadAttributes(db.DefaultContext)) diff --git a/tests/integration/api_pull_test.go b/tests/integration/api_pull_test.go index bb479caf89..9bf0d3d745 100644 --- a/tests/integration/api_pull_test.go +++ b/tests/integration/api_pull_test.go @@ -223,23 +223,33 @@ func TestAPIEditPull(t *testing.T) { session := loginUser(t, owner10.Name) token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) + title := "create a success pr" req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls", owner10.Name, repo10.Name), &api.CreatePullRequestOption{ Head: "develop", Base: "master", - Title: "create a success pr", + Title: title, }).AddTokenAuth(token) - pull := new(api.PullRequest) + apiPull := new(api.PullRequest) resp := MakeRequest(t, req, http.StatusCreated) - DecodeJSON(t, resp, pull) - assert.EqualValues(t, "master", pull.Base.Name) + DecodeJSON(t, resp, apiPull) + assert.EqualValues(t, "master", apiPull.Base.Name) - req = NewRequestWithJSON(t, http.MethodPatch, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d", owner10.Name, repo10.Name, pull.Index), &api.EditPullRequestOption{ + newTitle := "edit a this pr" + newBody := "edited body" + req = NewRequestWithJSON(t, http.MethodPatch, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d", owner10.Name, repo10.Name, apiPull.Index), &api.EditPullRequestOption{ Base: "feature/1", - Title: "edit a this pr", + Title: newTitle, + Body: &newBody, }).AddTokenAuth(token) resp = MakeRequest(t, req, http.StatusCreated) - DecodeJSON(t, resp, pull) - assert.EqualValues(t, "feature/1", pull.Base.Name) + DecodeJSON(t, resp, apiPull) + assert.EqualValues(t, "feature/1", apiPull.Base.Name) + // check comment history + pull := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: apiPull.ID}) + err := pull.LoadIssue(db.DefaultContext) + assert.NoError(t, err) + unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: pull.Issue.ID, OldTitle: title, NewTitle: newTitle}) + unittest.AssertExistsAndLoadBean(t, &issues_model.ContentHistory{IssueID: pull.Issue.ID, ContentText: newBody, IsFirstCreated: false}) req = NewRequestWithJSON(t, http.MethodPatch, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d", owner10.Name, repo10.Name, pull.Index), &api.EditPullRequestOption{ Base: "not-exist", From 9f0ef3621a3b63ccbe93f302a446b67dc54ad725 Mon Sep 17 00:00:00 2001 From: Kemal Zebari <60799661+kemzeb@users.noreply.github.com> Date: Fri, 3 May 2024 00:58:31 -0700 Subject: [PATCH 271/370] Don't only list code-enabled repositories when using repository API (#30817) We should be listing all repositories by default. Fixes #28483. --- routers/api/v1/user/repo.go | 4 +--- tests/integration/api_repo_test.go | 34 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/routers/api/v1/user/repo.go b/routers/api/v1/user/repo.go index 81f8e0f3fe..d0264d6b5a 100644 --- a/routers/api/v1/user/repo.go +++ b/routers/api/v1/user/repo.go @@ -6,10 +6,8 @@ package user import ( "net/http" - "code.gitea.io/gitea/models/perm" access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" - unit_model "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/utils" @@ -44,7 +42,7 @@ func listUserRepos(ctx *context.APIContext, u *user_model.User, private bool) { ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err) return } - if ctx.IsSigned && ctx.Doer.IsAdmin || permission.UnitAccessMode(unit_model.TypeCode) >= perm.AccessModeRead { + if ctx.IsSigned && ctx.Doer.IsAdmin || permission.HasAnyUnitAccess() { apiRepos = append(apiRepos, convert.ToRepo(ctx, repos[i], permission)) } } diff --git a/tests/integration/api_repo_test.go b/tests/integration/api_repo_test.go index f33827e58b..716da762e5 100644 --- a/tests/integration/api_repo_test.go +++ b/tests/integration/api_repo_test.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/models/db" access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" + unit_model "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/setting" @@ -326,6 +327,39 @@ func TestAPIOrgRepos(t *testing.T) { } } +// See issue #28483. Tests to make sure we consider more than just code unit-enabled repositories. +func TestAPIOrgReposWithCodeUnitDisabled(t *testing.T) { + defer tests.PrepareTestEnv(t)() + repo21 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: "repo21"}) + org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo21.OwnerID}) + + // Disable code repository unit. + var units []unit_model.Type + units = append(units, unit_model.TypeCode) + + if err := repo_service.UpdateRepositoryUnits(db.DefaultContext, repo21, nil, units); err != nil { + assert.Fail(t, "should have been able to delete code repository unit; failed to %v", err) + } + assert.False(t, repo21.UnitEnabled(db.DefaultContext, unit_model.TypeCode)) + + session := loginUser(t, "user2") + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadOrganization) + + req := NewRequestf(t, "GET", "/api/v1/orgs/%s/repos", org3.Name). + AddTokenAuth(token) + + resp := MakeRequest(t, req, http.StatusOK) + var apiRepos []*api.Repository + DecodeJSON(t, resp, &apiRepos) + + var repoNames []string + for _, r := range apiRepos { + repoNames = append(repoNames, r.Name) + } + + assert.Contains(t, repoNames, repo21.Name) +} + func TestAPIGetRepoByIDUnauthorized(t *testing.T) { defer tests.PrepareTestEnv(t)() user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) From 0f3e717a1abb2b2161b87dac557beb6475224a2e Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Fri, 3 May 2024 17:13:48 +0800 Subject: [PATCH 272/370] Improve grep search (#30843) Reduce the context line number to 1, make "git grep" search respect the include/exclude patter, and fix #30785 --- modules/git/grep.go | 2 ++ modules/git/grep_test.go | 20 ++++++++++++++++++++ modules/setting/glob.go | 32 ++++++++++++++++++++++++++++++++ modules/setting/indexer.go | 12 +++++------- routers/web/repo/search.go | 18 +++++++++++++++++- routers/web/repo/search_test.go | 19 +++++++++++++++++++ 6 files changed, 95 insertions(+), 8 deletions(-) create mode 100644 modules/setting/glob.go create mode 100644 routers/web/repo/search_test.go diff --git a/modules/git/grep.go b/modules/git/grep.go index e7d238e586..bf6b41a886 100644 --- a/modules/git/grep.go +++ b/modules/git/grep.go @@ -29,6 +29,7 @@ type GrepOptions struct { ContextLineNumber int IsFuzzy bool MaxLineLength int // the maximum length of a line to parse, exceeding chars will be truncated + PathspecList []string } func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepOptions) ([]*GrepResult, error) { @@ -62,6 +63,7 @@ func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepO cmd.AddOptionValues("-e", strings.TrimLeft(search, "-")) } cmd.AddDynamicArguments(util.IfZero(opts.RefName, "HEAD")) + cmd.AddDashesAndList(opts.PathspecList...) opts.MaxResultLimit = util.IfZero(opts.MaxResultLimit, 50) stderr := bytes.Buffer{} err = cmd.Run(&RunOpts{ diff --git a/modules/git/grep_test.go b/modules/git/grep_test.go index 7f4ded478f..6a99f80407 100644 --- a/modules/git/grep_test.go +++ b/modules/git/grep_test.go @@ -31,6 +31,26 @@ func TestGrepSearch(t *testing.T) { }, }, res) + res, err = GrepSearch(context.Background(), repo, "void", GrepOptions{PathspecList: []string{":(glob)java-hello/*"}}) + assert.NoError(t, err) + assert.Equal(t, []*GrepResult{ + { + Filename: "java-hello/main.java", + LineNumbers: []int{3}, + LineCodes: []string{" public static void main(String[] args)"}, + }, + }, res) + + res, err = GrepSearch(context.Background(), repo, "void", GrepOptions{PathspecList: []string{":(glob,exclude)java-hello/*"}}) + assert.NoError(t, err) + assert.Equal(t, []*GrepResult{ + { + Filename: "main.vendor.java", + LineNumbers: []int{3}, + LineCodes: []string{" public static void main(String[] args)"}, + }, + }, res) + res, err = GrepSearch(context.Background(), repo, "void", GrepOptions{MaxResultLimit: 1}) assert.NoError(t, err) assert.Equal(t, []*GrepResult{ diff --git a/modules/setting/glob.go b/modules/setting/glob.go new file mode 100644 index 0000000000..8f1d24dea4 --- /dev/null +++ b/modules/setting/glob.go @@ -0,0 +1,32 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package setting + +import "github.com/gobwas/glob" + +type GlobMatcher struct { + compiledGlob glob.Glob + patternString string +} + +var _ glob.Glob = (*GlobMatcher)(nil) + +func (g *GlobMatcher) Match(s string) bool { + return g.compiledGlob.Match(s) +} + +func (g *GlobMatcher) PatternString() string { + return g.patternString +} + +func GlobMatcherCompile(pattern string, separators ...rune) (*GlobMatcher, error) { + g, err := glob.Compile(pattern, separators...) + if err != nil { + return nil, err + } + return &GlobMatcher{ + compiledGlob: g, + patternString: pattern, + }, nil +} diff --git a/modules/setting/indexer.go b/modules/setting/indexer.go index 6877d70e3c..18585602c3 100644 --- a/modules/setting/indexer.go +++ b/modules/setting/indexer.go @@ -10,8 +10,6 @@ import ( "time" "code.gitea.io/gitea/modules/log" - - "github.com/gobwas/glob" ) // Indexer settings @@ -30,8 +28,8 @@ var Indexer = struct { RepoConnStr string RepoIndexerName string MaxIndexerFileSize int64 - IncludePatterns []glob.Glob - ExcludePatterns []glob.Glob + IncludePatterns []*GlobMatcher + ExcludePatterns []*GlobMatcher ExcludeVendored bool }{ IssueType: "bleve", @@ -93,12 +91,12 @@ func loadIndexerFrom(rootCfg ConfigProvider) { } // IndexerGlobFromString parses a comma separated list of patterns and returns a glob.Glob slice suited for repo indexing -func IndexerGlobFromString(globstr string) []glob.Glob { - extarr := make([]glob.Glob, 0, 10) +func IndexerGlobFromString(globstr string) []*GlobMatcher { + extarr := make([]*GlobMatcher, 0, 10) for _, expr := range strings.Split(strings.ToLower(globstr), ",") { expr = strings.TrimSpace(expr) if expr != "" { - if g, err := glob.Compile(expr, '.', '/'); err != nil { + if g, err := GlobMatcherCompile(expr, '.', '/'); err != nil { log.Info("Invalid glob expression '%s' (skipped): %v", expr, err) } else { extarr = append(extarr, g) diff --git a/routers/web/repo/search.go b/routers/web/repo/search.go index d7854b2499..920a865555 100644 --- a/routers/web/repo/search.go +++ b/routers/web/repo/search.go @@ -17,6 +17,16 @@ import ( const tplSearch base.TplName = "repo/search" +func indexSettingToGitGrepPathspecList() (list []string) { + for _, expr := range setting.Indexer.IncludePatterns { + list = append(list, ":(glob)"+expr.PatternString()) + } + for _, expr := range setting.Indexer.ExcludePatterns { + list = append(list, ":(glob,exclude)"+expr.PatternString()) + } + return list +} + // Search render repository search page func Search(ctx *context.Context) { language := ctx.FormTrim("l") @@ -65,8 +75,14 @@ func Search(ctx *context.Context) { ctx.Data["CodeIndexerUnavailable"] = !code_indexer.IsAvailable(ctx) } } else { - res, err := git.GrepSearch(ctx, ctx.Repo.GitRepo, keyword, git.GrepOptions{ContextLineNumber: 3, IsFuzzy: isFuzzy}) + res, err := git.GrepSearch(ctx, ctx.Repo.GitRepo, keyword, git.GrepOptions{ + ContextLineNumber: 1, + IsFuzzy: isFuzzy, + RefName: git.RefNameFromBranch(ctx.Repo.BranchName).String(), // BranchName should be default branch or the first existing branch + PathspecList: indexSettingToGitGrepPathspecList(), + }) if err != nil { + // TODO: if no branch exists, it reports: exit status 128, fatal: this operation must be run in a work tree. ctx.ServerError("GrepSearch", err) return } diff --git a/routers/web/repo/search_test.go b/routers/web/repo/search_test.go new file mode 100644 index 0000000000..33a1610384 --- /dev/null +++ b/routers/web/repo/search_test.go @@ -0,0 +1,19 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repo + +import ( + "testing" + + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" + + "github.com/stretchr/testify/assert" +) + +func TestIndexSettingToGitGrepPathspecList(t *testing.T) { + defer test.MockVariableValue(&setting.Indexer.IncludePatterns, setting.IndexerGlobFromString("a"))() + defer test.MockVariableValue(&setting.Indexer.ExcludePatterns, setting.IndexerGlobFromString("b"))() + assert.Equal(t, []string{":(glob)a", ":(glob,exclude)b"}, indexSettingToGitGrepPathspecList()) +} From c7bb3aa03436314e20d43e0ae44e791dd3e64909 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sat, 4 May 2024 09:48:16 +0800 Subject: [PATCH 273/370] Fix markdown URL parsing for commit ID (#30812) --- modules/markup/html.go | 122 +++++++++++++++------------ modules/markup/html_codepreview.go | 3 +- modules/markup/html_internal_test.go | 59 +++++++++---- modules/markup/html_test.go | 7 +- 4 files changed, 116 insertions(+), 75 deletions(-) diff --git a/modules/markup/html.go b/modules/markup/html.go index 5ae0cc8755..2958dc9646 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -10,6 +10,7 @@ import ( "path" "path/filepath" "regexp" + "slices" "strings" "sync" @@ -54,7 +55,7 @@ var ( shortLinkPattern = regexp.MustCompile(`\[\[(.*?)\]\](\w*)`) // anyHashPattern splits url containing SHA into parts - anyHashPattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{40,64})(/[-+~_%.a-zA-Z0-9/]+)?(#[-+~_%.a-zA-Z0-9]+)?`) + anyHashPattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{40,64})(/[-+~%./\w]+)?(\?[-+~%.\w&=]+)?(#[-+~%.\w]+)?`) // comparePattern matches "http://domain/org/repo/compare/COMMIT1...COMMIT2#hash" comparePattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{7,64})(\.\.\.?)([0-9a-f]{7,64})?(#[-+~_%.a-zA-Z0-9]+)?`) @@ -591,7 +592,8 @@ func replaceContentList(node *html.Node, i, j int, newNodes []*html.Node) { func mentionProcessor(ctx *RenderContext, node *html.Node) { start := 0 - for node != nil { + nodeStop := node.NextSibling + for node != nodeStop { found, loc := references.FindFirstMentionBytes(util.UnsafeStringToBytes(node.Data[start:])) if !found { node = node.NextSibling @@ -962,57 +964,68 @@ func commitCrossReferencePatternProcessor(ctx *RenderContext, node *html.Node) { } } +type anyHashPatternResult struct { + PosStart int + PosEnd int + FullURL string + CommitID string + SubPath string + QueryHash string +} + +func anyHashPatternExtract(s string) (ret anyHashPatternResult, ok bool) { + m := anyHashPattern.FindStringSubmatchIndex(s) + if m == nil { + return ret, false + } + + ret.PosStart, ret.PosEnd = m[0], m[1] + ret.FullURL = s[ret.PosStart:ret.PosEnd] + if strings.HasSuffix(ret.FullURL, ".") { + // if url ends in '.', it's very likely that it is not part of the actual url but used to finish a sentence. + ret.PosEnd-- + ret.FullURL = ret.FullURL[:len(ret.FullURL)-1] + for i := 0; i < len(m); i++ { + m[i] = min(m[i], ret.PosEnd) + } + } + + ret.CommitID = s[m[2]:m[3]] + if m[5] > 0 { + ret.SubPath = s[m[4]:m[5]] + } + + lastStart, lastEnd := m[len(m)-2], m[len(m)-1] + if lastEnd > 0 { + ret.QueryHash = s[lastStart:lastEnd][1:] + } + return ret, true +} + // fullHashPatternProcessor renders SHA containing URLs func fullHashPatternProcessor(ctx *RenderContext, node *html.Node) { if ctx.Metas == nil { return } - - next := node.NextSibling - for node != nil && node != next { - m := anyHashPattern.FindStringSubmatchIndex(node.Data) - if m == nil { - return + nodeStop := node.NextSibling + for node != nodeStop { + if node.Type != html.TextNode { + node = node.NextSibling + continue } - - urlFull := node.Data[m[0]:m[1]] - text := base.ShortSha(node.Data[m[2]:m[3]]) - - // 3rd capture group matches a optional path - subpath := "" - if m[5] > 0 { - subpath = node.Data[m[4]:m[5]] + ret, ok := anyHashPatternExtract(node.Data) + if !ok { + node = node.NextSibling + continue } - - // 4th capture group matches a optional url hash - hash := "" - if m[7] > 0 { - hash = node.Data[m[6]:m[7]][1:] + text := base.ShortSha(ret.CommitID) + if ret.SubPath != "" { + text += ret.SubPath } - - start := m[0] - end := m[1] - - // If url ends in '.', it's very likely that it is not part of the - // actual url but used to finish a sentence. - if strings.HasSuffix(urlFull, ".") { - end-- - urlFull = urlFull[:len(urlFull)-1] - if hash != "" { - hash = hash[:len(hash)-1] - } else if subpath != "" { - subpath = subpath[:len(subpath)-1] - } + if ret.QueryHash != "" { + text += " (" + ret.QueryHash + ")" } - - if subpath != "" { - text += subpath - } - - if hash != "" { - text += " (" + hash + ")" - } - replaceContent(node, start, end, createCodeLink(urlFull, text, "commit")) + replaceContent(node, ret.PosStart, ret.PosEnd, createCodeLink(ret.FullURL, text, "commit")) node = node.NextSibling.NextSibling } } @@ -1021,19 +1034,16 @@ func comparePatternProcessor(ctx *RenderContext, node *html.Node) { if ctx.Metas == nil { return } - - next := node.NextSibling - for node != nil && node != next { - m := comparePattern.FindStringSubmatchIndex(node.Data) - if m == nil { - return + nodeStop := node.NextSibling + for node != nodeStop { + if node.Type != html.TextNode { + node = node.NextSibling + continue } - - // Ensure that every group (m[0]...m[7]) has a match - for i := 0; i < 8; i++ { - if m[i] == -1 { - return - } + m := comparePattern.FindStringSubmatchIndex(node.Data) + if m == nil || slices.Contains(m[:8], -1) { // ensure that every group (m[0]...m[7]) has a match + node = node.NextSibling + continue } urlFull := node.Data[m[0]:m[1]] diff --git a/modules/markup/html_codepreview.go b/modules/markup/html_codepreview.go index d9da24ea34..5ef2217e3d 100644 --- a/modules/markup/html_codepreview.go +++ b/modules/markup/html_codepreview.go @@ -60,7 +60,8 @@ func renderCodeBlock(ctx *RenderContext, node *html.Node) (urlPosStart, urlPosSt } func codePreviewPatternProcessor(ctx *RenderContext, node *html.Node) { - for node != nil { + nodeStop := node.NextSibling + for node != nodeStop { if node.Type != html.TextNode { node = node.NextSibling continue diff --git a/modules/markup/html_internal_test.go b/modules/markup/html_internal_test.go index e313be7040..3ff0597851 100644 --- a/modules/markup/html_internal_test.go +++ b/modules/markup/html_internal_test.go @@ -399,36 +399,61 @@ func TestRegExp_sha1CurrentPattern(t *testing.T) { } func TestRegExp_anySHA1Pattern(t *testing.T) { - testCases := map[string][]string{ + testCases := map[string]anyHashPatternResult{ "https://github.com/jquery/jquery/blob/a644101ed04d0beacea864ce805e0c4f86ba1cd1/test/unit/event.js#L2703": { - "a644101ed04d0beacea864ce805e0c4f86ba1cd1", - "/test/unit/event.js", - "#L2703", + CommitID: "a644101ed04d0beacea864ce805e0c4f86ba1cd1", + SubPath: "/test/unit/event.js", + QueryHash: "L2703", }, "https://github.com/jquery/jquery/blob/a644101ed04d0beacea864ce805e0c4f86ba1cd1/test/unit/event.js": { - "a644101ed04d0beacea864ce805e0c4f86ba1cd1", - "/test/unit/event.js", - "", + CommitID: "a644101ed04d0beacea864ce805e0c4f86ba1cd1", + SubPath: "/test/unit/event.js", }, "https://github.com/jquery/jquery/commit/0705be475092aede1eddae01319ec931fb9c65fc": { - "0705be475092aede1eddae01319ec931fb9c65fc", - "", - "", + CommitID: "0705be475092aede1eddae01319ec931fb9c65fc", }, "https://github.com/jquery/jquery/tree/0705be475092aede1eddae01319ec931fb9c65fc/src": { - "0705be475092aede1eddae01319ec931fb9c65fc", - "/src", - "", + CommitID: "0705be475092aede1eddae01319ec931fb9c65fc", + SubPath: "/src", }, "https://try.gogs.io/gogs/gogs/commit/d8a994ef243349f321568f9e36d5c3f444b99cae#diff-2": { - "d8a994ef243349f321568f9e36d5c3f444b99cae", - "", - "#diff-2", + CommitID: "d8a994ef243349f321568f9e36d5c3f444b99cae", + QueryHash: "diff-2", + }, + "non-url": {}, + "http://a/b/c/d/e/1234567812345678123456781234567812345678123456781234567812345678?a=b#L1-L2": { + CommitID: "1234567812345678123456781234567812345678123456781234567812345678", + QueryHash: "L1-L2", + }, + "http://a/b/c/d/e/1234567812345678123456781234567812345678123456781234567812345678.": { + CommitID: "1234567812345678123456781234567812345678123456781234567812345678", + }, + "http://a/b/c/d/e/1234567812345678123456781234567812345678123456781234567812345678/sub.": { + CommitID: "1234567812345678123456781234567812345678123456781234567812345678", + SubPath: "/sub", + }, + "http://a/b/c/d/e/1234567812345678123456781234567812345678123456781234567812345678?a=b.": { + CommitID: "1234567812345678123456781234567812345678123456781234567812345678", + }, + "http://a/b/c/d/e/1234567812345678123456781234567812345678123456781234567812345678?a=b&c=d": { + CommitID: "1234567812345678123456781234567812345678123456781234567812345678", + }, + "http://a/b/c/d/e/1234567812345678123456781234567812345678123456781234567812345678#hash.": { + CommitID: "1234567812345678123456781234567812345678123456781234567812345678", + QueryHash: "hash", }, } for k, v := range testCases { - assert.Equal(t, anyHashPattern.FindStringSubmatch(k)[1:], v) + ret, ok := anyHashPatternExtract(k) + if v.CommitID == "" { + assert.False(t, ok) + } else { + assert.EqualValues(t, strings.TrimSuffix(k, "."), ret.FullURL) + assert.EqualValues(t, v.CommitID, ret.CommitID) + assert.EqualValues(t, v.SubPath, ret.SubPath) + assert.EqualValues(t, v.QueryHash, ret.QueryHash) + } } } diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go index 916e74fb62..a2ae18d777 100644 --- a/modules/markup/html_test.go +++ b/modules/markup/html_test.go @@ -124,6 +124,11 @@ func TestRender_CrossReferences(t *testing.T) { test( util.URLJoin(markup.TestAppURL, "gogitea", "some-repo-name", "issues", "12345"), `<p><a href="`+util.URLJoin(markup.TestAppURL, "gogitea", "some-repo-name", "issues", "12345")+`" class="ref-issue" rel="nofollow">gogitea/some-repo-name#12345</a></p>`) + + inputURL := "https://host/a/b/commit/0123456789012345678901234567890123456789/foo.txt?a=b#L2-L3" + test( + inputURL, + `<p><a href="`+inputURL+`" rel="nofollow"><code>0123456789/foo.txt (L2-L3)</code></a></p>`) } func TestMisc_IsSameDomain(t *testing.T) { @@ -695,7 +700,7 @@ func TestIssue18471(t *testing.T) { }, strings.NewReader(data), &res) assert.NoError(t, err) - assert.Equal(t, "<a href=\"http://domain/org/repo/compare/783b039...da951ce\" class=\"compare\"><code class=\"nohighlight\">783b039...da951ce</code></a>", res.String()) + assert.Equal(t, `<a href="http://domain/org/repo/compare/783b039...da951ce" class="compare"><code class="nohighlight">783b039...da951ce</code></a>`, res.String()) } func TestIsFullURL(t *testing.T) { From bb0e4ce581721afabbfcdf8d5a894ba124465577 Mon Sep 17 00:00:00 2001 From: Neal Caffery <bing.ecnu@gmail.com> Date: Sat, 4 May 2024 11:53:18 +0800 Subject: [PATCH 274/370] Update README.md (#30856) fix typo for the Docker README --- docker/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/README.md b/docker/README.md index a6d7c9a843..b014f42367 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,7 +1,7 @@ # Gitea - Docker -Dockerfile is found in root of repository. +Dockerfile is found in the root of the repository. -Docker image can be found on [docker hub](https://hub.docker.com/r/gitea/gitea) +Docker image can be found on [docker hub](https://hub.docker.com/r/gitea/gitea). -Documentation on using docker image can be found on [Gitea Docs site](https://docs.gitea.com/installation/install-with-docker-rootless) +Documentation on using docker image can be found on [Gitea Docs site](https://docs.gitea.com/installation/install-with-docker-rootless). From ecd1d96f494d2400f7659165ff9376354edda395 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Sun, 5 May 2024 11:10:20 +0900 Subject: [PATCH 275/370] Add result check in TestAPIEditUser (#29674) Fix #29514 There are too many usage of `NewRequestWithValues`, so there's no need to check all of them. Just one is enough I think. --- tests/integration/api_admin_test.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/integration/api_admin_test.go b/tests/integration/api_admin_test.go index e8954f5b20..92da7ce041 100644 --- a/tests/integration/api_admin_test.go +++ b/tests/integration/api_admin_test.go @@ -195,14 +195,17 @@ func TestAPIEditUser(t *testing.T) { token := getUserToken(t, adminUsername, auth_model.AccessTokenScopeWriteAdmin) urlStr := fmt.Sprintf("/api/v1/admin/users/%s", "user2") + fullNameToChange := "Full Name User 2" req := NewRequestWithValues(t, "PATCH", urlStr, map[string]string{ // required "login_name": "user2", "source_id": "0", // to change - "full_name": "Full Name User 2", + "full_name": fullNameToChange, }).AddTokenAuth(token) MakeRequest(t, req, http.StatusOK) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{LoginName: "user2"}) + assert.Equal(t, fullNameToChange, user2.FullName) empty := "" req = NewRequestWithJSON(t, "PATCH", urlStr, api.EditUserOption{ @@ -216,7 +219,7 @@ func TestAPIEditUser(t *testing.T) { json.Unmarshal(resp.Body.Bytes(), &errMap) assert.EqualValues(t, "e-mail invalid [email: ]", errMap["message"].(string)) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{LoginName: "user2"}) + user2 = unittest.AssertExistsAndLoadBean(t, &user_model.User{LoginName: "user2"}) assert.False(t, user2.IsRestricted) bTrue := true req = NewRequestWithJSON(t, "PATCH", urlStr, api.EditUserOption{ From 5c236bd4c024dbe4a71516b10aa812893651983a Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sun, 5 May 2024 21:09:41 +0800 Subject: [PATCH 276/370] Fix issue/PR title edit (#30858) 1. "enter" doesn't work (I think it is the last enter support for #14843) 2. if a branch name contains something like `&`, then the branch selector doesn't update --- templates/repo/issue/view_title.tmpl | 43 ++++---- tests/integration/issue_test.go | 2 +- tests/integration/pull_create_test.go | 2 +- web_src/css/repo.css | 75 +++++++------- web_src/js/features/common-global.js | 16 ++- web_src/js/features/comp/QuickSubmit.js | 13 +-- web_src/js/features/repo-issue.js | 129 +++++++++++------------- 7 files changed, 141 insertions(+), 139 deletions(-) diff --git a/templates/repo/issue/view_title.tmpl b/templates/repo/issue/view_title.tmpl index fccf8cca91..4415ad79f5 100644 --- a/templates/repo/issue/view_title.tmpl +++ b/templates/repo/issue/view_title.tmpl @@ -4,29 +4,36 @@ </div> {{end}} <div class="issue-title-header"> - <div class="issue-title" id="issue-title-wrapper"> + {{$canEditIssueTitle := and (or .HasIssuesOrPullsWritePermission .IsIssuePoster) (not .Repository.IsArchived)}} + <div class="issue-title" id="issue-title-display"> <h1 class="gt-word-break"> - <span id="issue-title">{{RenderIssueTitle $.Context .Issue.Title ($.Repository.ComposeMetas ctx) | RenderCodeBlock}} <span class="index">#{{.Issue.Index}}</span> -</span> - <div id="edit-title-input" class="ui input tw-flex-1 tw-hidden"> - <input value="{{.Issue.Title}}" maxlength="255" autocomplete="off"> - </div> + {{RenderIssueTitle $.Context .Issue.Title ($.Repository.ComposeMetas ctx) | RenderCodeBlock}} + <span class="index">#{{.Issue.Index}}</span> </h1> <div class="issue-title-buttons"> - {{if and (or .HasIssuesOrPullsWritePermission .IsIssuePoster) (not .Repository.IsArchived)}} - <button id="edit-title" class="ui small basic button edit-button not-in-edit{{if .Issue.IsPull}} tw-mr-0{{end}}">{{ctx.Locale.Tr "repo.issues.edit"}}</button> + {{if $canEditIssueTitle}} + <button id="issue-title-edit-show" class="ui small basic button">{{ctx.Locale.Tr "repo.issues.edit"}}</button> {{end}} {{if not .Issue.IsPull}} - <a role="button" class="ui small primary button new-issue-button tw-mr-0" href="{{.RepoLink}}/issues/new{{if .NewIssueChooseTemplate}}/choose{{end}}">{{ctx.Locale.Tr "repo.issues.new"}}</a> + <a role="button" class="ui small primary button" href="{{.RepoLink}}/issues/new{{if .NewIssueChooseTemplate}}/choose{{end}}">{{ctx.Locale.Tr "repo.issues.new"}}</a> {{end}} </div> - {{if and (or .HasIssuesOrPullsWritePermission .IsIssuePoster) (not .Repository.IsArchived)}} - <div class="edit-buttons"> - <button id="cancel-edit-title" class="ui small basic button in-edit tw-hidden">{{ctx.Locale.Tr "repo.issues.cancel"}}</button> - <button id="save-edit-title" class="ui small primary button in-edit tw-hidden tw-mr-0" data-update-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/title" {{if .Issue.IsPull}}data-target-update-url="{{$.RepoLink}}/pull/{{.Issue.Index}}/target_branch"{{end}}>{{ctx.Locale.Tr "repo.issues.save"}}</button> - </div> - {{end}} </div> + {{if $canEditIssueTitle}} + <div class="ui form issue-title tw-hidden" id="issue-title-editor"> + <div class="ui input tw-flex-1"> + <input value="{{.Issue.Title}}" data-old-title="{{.Issue.Title}}" maxlength="255" autocomplete="off"> + </div> + <div class="issue-title-buttons"> + <button class="ui small basic cancel button">{{ctx.Locale.Tr "repo.issues.cancel"}}</button> + <button class="ui small primary button" + data-update-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/title" + {{if .Issue.IsPull}}data-target-update-url="{{$.RepoLink}}/pull/{{.Issue.Index}}/target_branch"{{end}}> + {{ctx.Locale.Tr "repo.issues.save"}} + </button> + </div> + </div> + {{end}} <div class="issue-title-meta"> {{if .HasMerged}} <div class="ui purple label issue-state-label">{{svg "octicon-git-merge" 16 "tw-mr-1"}} {{if eq .Issue.PullRequest.Status 3}}{{ctx.Locale.Tr "repo.pulls.manually_merged"}}{{else}}{{ctx.Locale.Tr "repo.pulls.merged"}}{{end}}</div> @@ -63,14 +70,14 @@ {{end}} {{else}} {{if .Issue.OriginalAuthor}} - <span id="pull-desc" class="pull-desc">{{.Issue.OriginalAuthor}} {{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref}}</span> + <span id="pull-desc-display" class="pull-desc">{{.Issue.OriginalAuthor}} {{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref}}</span> {{else}} - <span id="pull-desc" class="pull-desc"> + <span id="pull-desc-display" class="pull-desc"> <a {{if gt .Issue.Poster.ID 0}}href="{{.Issue.Poster.HomeLink}}"{{end}}>{{.Issue.Poster.GetDisplayName}}</a> {{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref}} </span> {{end}} - <span id="pull-desc-edit" class="tw-hidden flex-text-block"> + <span id="pull-desc-editor" class="tw-hidden flex-text-block"> <div class="ui floating filter dropdown"> <div class="ui basic small button tw-mr-0"> <span class="text">{{ctx.Locale.Tr "repo.pulls.compare_compare"}}: {{$.HeadTarget}}</span> diff --git a/tests/integration/issue_test.go b/tests/integration/issue_test.go index b7952b0879..d74516d110 100644 --- a/tests/integration/issue_test.go +++ b/tests/integration/issue_test.go @@ -144,7 +144,7 @@ func testNewIssue(t *testing.T, session *TestSession, user, repo, title, content resp = session.MakeRequest(t, req, http.StatusOK) htmlDoc = NewHTMLParser(t, resp.Body) - val := htmlDoc.doc.Find("#issue-title").Text() + val := htmlDoc.doc.Find("#issue-title-display").Text() assert.Contains(t, val, title) val = htmlDoc.doc.Find(".comment .render-content p").First().Text() assert.Equal(t, content, val) diff --git a/tests/integration/pull_create_test.go b/tests/integration/pull_create_test.go index 609bd73fd5..7add8e1db6 100644 --- a/tests/integration/pull_create_test.go +++ b/tests/integration/pull_create_test.go @@ -125,7 +125,7 @@ func TestPullCreate_TitleEscape(t *testing.T) { req := NewRequest(t, "GET", url) resp = session.MakeRequest(t, req, http.StatusOK) htmlDoc := NewHTMLParser(t, resp.Body) - editTestTitleURL, exists := htmlDoc.doc.Find("#save-edit-title").First().Attr("data-update-url") + editTestTitleURL, exists := htmlDoc.doc.Find(".issue-title-buttons button[data-update-url]").First().Attr("data-update-url") assert.True(t, exists, "The template has changed") req = NewRequestWithValues(t, "POST", editTestTitleURL, map[string]string{ diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 408b62ad3c..7695b632b4 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -575,34 +575,7 @@ td .commit-summary { display: inline-block; } -.issue-title-header { - width: 100%; - padding-bottom: 4px; - margin-bottom: 1rem; -} - -.issue-title-meta { - display: flex; - align-items: center; -} - -.repository.view.issue .issue-title-buttons, -.repository.view.issue .edit-buttons { - display: flex; -} - @media (max-width: 767.98px) { - .repository.view.issue .issue-title { - flex-direction: column; - } - .repository.view.issue .issue-title-buttons, - .repository.view.issue .edit-buttons { - width: 100%; - justify-content: space-between; - } - .repository.view.issue .edit-buttons { - margin-top: .5rem; - } .comment.form .issue-content-left .avatar { display: none; } @@ -617,15 +590,37 @@ td .commit-summary { } } +/* issue title & meta & edit */ +.issue-title-header { + width: 100%; + padding-bottom: 4px; + margin-bottom: 1rem; +} + +.issue-title-meta { + display: flex; + align-items: center; +} + +.repository.view.issue .issue-title-buttons { + display: flex; + gap: 0.5em; +} + +.repository.view.issue .issue-title-buttons > .ui.button { + margin: 0; + height: 35px; +} + .repository.view.issue .issue-title { display: flex; align-items: center; + gap: 0.5em; margin-bottom: 8px; + min-height: 40px; /* avoid layout shift on edit */ } .repository.view.issue .issue-title h1 { - display: flex; - align-items: center; flex: 1; width: 100%; font-weight: var(--font-weight-normal); @@ -633,14 +628,24 @@ td .commit-summary { line-height: 40px; margin: 0; padding-right: 0.25rem; - min-height: 41px; /* avoid layout shift on edit */ } -.repository.view.issue .issue-title h1 .ui.input { - font-size: 0.5em; +@media (max-width: 767.98px) { + .repository.view.issue .issue-title { + flex-direction: column; + } + .repository.view.issue .issue-title-buttons { + width: 100%; + justify-content: space-between; + } } -.repository.view.issue .issue-title h1 .ui.input input { +.repository.view.issue .issue-title .ui.input { + width: 100%; + height: 35px; +} + +.repository.view.issue .issue-title .ui.input input { font-size: 1.5em; padding: 2px .5rem; } @@ -653,10 +658,6 @@ td .commit-summary { margin-right: 10px; } -.issue-title .edit-zone { - margin-top: 10px; -} - .issue-state-label { display: flex !important; align-items: center !important; diff --git a/web_src/js/features/common-global.js b/web_src/js/features/common-global.js index a821e1b921..5b8673105d 100644 --- a/web_src/js/features/common-global.js +++ b/web_src/js/features/common-global.js @@ -47,10 +47,18 @@ export function initFootLanguageMenu() { export function initGlobalEnterQuickSubmit() { document.addEventListener('keydown', (e) => { - const isQuickSubmitEnter = ((e.ctrlKey && !e.altKey) || e.metaKey) && (e.key === 'Enter'); - if (isQuickSubmitEnter && e.target.matches('textarea')) { - e.preventDefault(); - handleGlobalEnterQuickSubmit(e.target); + if (e.key !== 'Enter') return; + const hasCtrlOrMeta = ((e.ctrlKey || e.metaKey) && !e.altKey); + if (hasCtrlOrMeta && e.target.matches('textarea')) { + if (handleGlobalEnterQuickSubmit(e.target)) { + e.preventDefault(); + } + } else if (e.target.matches('input') && !e.target.closest('form')) { + // input in a normal form could handle Enter key by default, so we only handle the input outside a form + // eslint-disable-next-line unicorn/no-lonely-if + if (handleGlobalEnterQuickSubmit(e.target)) { + e.preventDefault(); + } } }); } diff --git a/web_src/js/features/comp/QuickSubmit.js b/web_src/js/features/comp/QuickSubmit.js index 6bd5f6644d..3ff29f4fac 100644 --- a/web_src/js/features/comp/QuickSubmit.js +++ b/web_src/js/features/comp/QuickSubmit.js @@ -3,16 +3,17 @@ export function handleGlobalEnterQuickSubmit(target) { if (form) { if (!form.checkValidity()) { form.reportValidity(); - return; + } else { + // here use the event to trigger the submit event (instead of calling `submit()` method directly) + // otherwise the `areYouSure` handler won't be executed, then there will be an annoying "confirm to leave" dialog + form.dispatchEvent(new SubmitEvent('submit', {bubbles: true, cancelable: true})); } - - // here use the event to trigger the submit event (instead of calling `submit()` method directly) - // otherwise the `areYouSure` handler won't be executed, then there will be an annoying "confirm to leave" dialog - form.dispatchEvent(new SubmitEvent('submit', {bubbles: true, cancelable: true})); - return; + return true; } form = target.closest('.ui.form'); if (form) { form.querySelector('.ui.primary.button')?.click(); + return true; } + return false; } diff --git a/web_src/js/features/repo-issue.js b/web_src/js/features/repo-issue.js index c4e14c62c4..39c364ca50 100644 --- a/web_src/js/features/repo-issue.js +++ b/web_src/js/features/repo-issue.js @@ -7,6 +7,7 @@ import {getComboMarkdownEditor, initComboMarkdownEditor} from './comp/ComboMarkd import {toAbsoluteUrl} from '../utils.js'; import {initDropzone} from './common-global.js'; import {POST, GET} from '../modules/fetch.js'; +import {showErrorToast} from '../modules/toast.js'; const {appSubUrl} = window.config; @@ -602,85 +603,69 @@ export function initRepoIssueWipToggle() { }); } -async function pullrequest_targetbranch_change(update_url) { - const targetBranch = $('#pull-target-branch').data('branch'); - const $branchTarget = $('#branch_target'); - if (targetBranch === $branchTarget.text()) { - window.location.reload(); - return false; - } - try { - await POST(update_url, {data: new URLSearchParams({target_branch: targetBranch})}); - } catch (error) { - console.error(error); - } finally { - window.location.reload(); - } -} - export function initRepoIssueTitleEdit() { - // Edit issue title - const $issueTitle = $('#issue-title'); - const $editInput = $('#edit-title-input input'); + const issueTitleDisplay = document.querySelector('#issue-title-display'); + const issueTitleEditor = document.querySelector('#issue-title-editor'); + if (!issueTitleEditor) return; - const editTitleToggle = function () { - toggleElem($issueTitle); - toggleElem('.not-in-edit'); - toggleElem('#edit-title-input'); - toggleElem('#pull-desc'); - toggleElem('#pull-desc-edit'); - toggleElem('.in-edit'); - toggleElem('.new-issue-button'); - document.getElementById('issue-title-wrapper')?.classList.toggle('edit-active'); - $editInput[0].focus(); - $editInput[0].select(); - return false; - }; - - $('#edit-title').on('click', editTitleToggle); - $('#cancel-edit-title').on('click', editTitleToggle); - $('#save-edit-title').on('click', editTitleToggle).on('click', async function () { - const pullrequest_target_update_url = this.getAttribute('data-target-update-url'); - if (!$editInput.val().length || $editInput.val() === $issueTitle.text()) { - $editInput.val($issueTitle.text()); - await pullrequest_targetbranch_change(pullrequest_target_update_url); - } else { - try { - const params = new URLSearchParams(); - params.append('title', $editInput.val()); - const response = await POST(this.getAttribute('data-update-url'), {data: params}); - const data = await response.json(); - $editInput.val(data.title); - $issueTitle.text(data.title); - if (pullrequest_target_update_url) { - await pullrequest_targetbranch_change(pullrequest_target_update_url); // it will reload the window - } else { - window.location.reload(); - } - } catch (error) { - console.error(error); - } + const issueTitleInput = issueTitleEditor.querySelector('input'); + const oldTitle = issueTitleInput.getAttribute('data-old-title'); + issueTitleDisplay.querySelector('#issue-title-edit-show').addEventListener('click', () => { + hideElem(issueTitleDisplay); + hideElem('#pull-desc-display'); + showElem(issueTitleEditor); + showElem('#pull-desc-editor'); + if (!issueTitleInput.value.trim()) { + issueTitleInput.value = oldTitle; + } + issueTitleInput.focus(); + }); + issueTitleEditor.querySelector('.ui.cancel.button').addEventListener('click', () => { + hideElem(issueTitleEditor); + hideElem('#pull-desc-editor'); + showElem(issueTitleDisplay); + showElem('#pull-desc-display'); + }); + const editSaveButton = issueTitleEditor.querySelector('.ui.primary.button'); + editSaveButton.addEventListener('click', async () => { + const prTargetUpdateUrl = editSaveButton.getAttribute('data-target-update-url'); + const newTitle = issueTitleInput.value.trim(); + try { + if (newTitle && newTitle !== oldTitle) { + const resp = await POST(editSaveButton.getAttribute('data-update-url'), {data: new URLSearchParams({title: newTitle})}); + if (!resp.ok) { + throw new Error(`Failed to update issue title: ${resp.statusText}`); + } + } + if (prTargetUpdateUrl) { + const newTargetBranch = document.querySelector('#pull-target-branch').getAttribute('data-branch'); + const oldTargetBranch = document.querySelector('#branch_target').textContent; + if (newTargetBranch !== oldTargetBranch) { + const resp = await POST(prTargetUpdateUrl, {data: new URLSearchParams({target_branch: newTargetBranch})}); + if (!resp.ok) { + throw new Error(`Failed to update PR target branch: ${resp.statusText}`); + } + } + } + window.location.reload(); + } catch (error) { + console.error(error); + showErrorToast(error.message); } - return false; }); } export function initRepoIssueBranchSelect() { - const changeBranchSelect = function () { - const $selectionTextField = $('#pull-target-branch'); - - const baseName = $selectionTextField.data('basename'); - const branchNameNew = $(this).data('branch'); - const branchNameOld = $selectionTextField.data('branch'); - - // Replace branch name to keep translation from HTML template - $selectionTextField.html($selectionTextField.html().replace( - `${baseName}:${branchNameOld}`, - `${baseName}:${branchNameNew}`, - )); - $selectionTextField.data('branch', branchNameNew); // update branch name in setting - }; - $('#branch-select > .item').on('click', changeBranchSelect); + document.querySelector('#branch-select')?.addEventListener('click', (e) => { + const el = e.target.closest('.item[data-branch]'); + if (!el) return; + const pullTargetBranch = document.querySelector('#pull-target-branch'); + const baseName = pullTargetBranch.getAttribute('data-basename'); + const branchNameNew = el.getAttribute('data-branch'); + const branchNameOld = pullTargetBranch.getAttribute('data-branch'); + pullTargetBranch.textContent = pullTargetBranch.textContent.replace(`${baseName}:${branchNameOld}`, `${baseName}:${branchNameNew}`); + pullTargetBranch.setAttribute('data-branch', branchNameNew); + }); } export function initSingleCommentEditor($commentForm) { From 982b20d259e5bcd94377820ca3559112add36a1b Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Mon, 6 May 2024 00:34:13 +0800 Subject: [PATCH 277/370] Do not show monaco JS errors (#30862) Fix #30861 --- web_src/js/bootstrap.js | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index e466d0b169..8339b4bd82 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -6,13 +6,20 @@ // This file must be imported before any lazy-loading is being attempted. __webpack_public_path__ = `${window.config?.assetUrlPrefix ?? '/assets'}/`; -export function showGlobalErrorMessage(msg) { - const pageContent = document.querySelector('.page-content'); - if (!pageContent) return; +function shouldIgnoreError(err) { + const ignorePatterns = [ + '/assets/js/monaco.', // https://github.com/go-gitea/gitea/issues/30861 , https://github.com/microsoft/monaco-editor/issues/4496 + ]; + for (const pattern of ignorePatterns) { + if (err.stack?.includes(pattern)) return true; + } + return false; +} - // compact the message to a data attribute to avoid too many duplicated messages - const msgCompact = msg.replace(/\W/g, '').trim(); - let msgDiv = pageContent.querySelector(`.js-global-error[data-global-error-msg-compact="${msgCompact}"]`); +export function showGlobalErrorMessage(msg) { + const msgContainer = document.querySelector('.page-content') ?? document.body; + const msgCompact = msg.replace(/\W/g, '').trim(); // compact the message to a data attribute to avoid too many duplicated messages + let msgDiv = msgContainer.querySelector(`.js-global-error[data-global-error-msg-compact="${msgCompact}"]`); if (!msgDiv) { const el = document.createElement('div'); el.innerHTML = `<div class="ui container negative message center aligned js-global-error tw-mt-[15px] tw-whitespace-pre-line"></div>`; @@ -23,7 +30,7 @@ export function showGlobalErrorMessage(msg) { msgDiv.setAttribute(`data-global-error-msg-compact`, msgCompact); msgDiv.setAttribute(`data-global-error-msg-count`, msgCount.toString()); msgDiv.textContent = msg + (msgCount > 1 ? ` (${msgCount})` : ''); - pageContent.prepend(msgDiv); + msgContainer.prepend(msgDiv); } /** @@ -52,10 +59,12 @@ function processWindowErrorEvent({error, reason, message, type, filename, lineno if (runModeIsProd) return; } - // If the error stack trace does not include the base URL of our script assets, it likely came - // from a browser extension or inline script. Do not show such errors in production. - if (err instanceof Error && !err.stack?.includes(assetBaseUrl) && runModeIsProd) { - return; + if (err instanceof Error) { + // If the error stack trace does not include the base URL of our script assets, it likely came + // from a browser extension or inline script. Do not show such errors in production. + if (!err.stack?.includes(assetBaseUrl) && runModeIsProd) return; + // Ignore some known errors that are unable to fix + if (shouldIgnoreError(err)) return; } let msg = err?.message ?? message; From 22c7b3a74459833b86783e84d4708c8934d34e58 Mon Sep 17 00:00:00 2001 From: Kemal Zebari <60799661+kemzeb@users.noreply.github.com> Date: Sun, 5 May 2024 18:36:53 -0700 Subject: [PATCH 278/370] Have time.js use UTC-related getters/setters (#30857) Before this patch, we were using `Date` getter/setter methods that worked with local time to get a list of Sundays that are in the range of some start date and end date. The problem with this was that the Sundays are in Unix epoch time and when we changed the "startDate" argument that was passed to make sure it is on a Sunday, this change would be reflected when we convert it to Unix epoch time. More specifically, I observed that we may get different Unix epochs depending on your timezone when the returned list should rather be timezone-agnostic. This led to issues in US timezones that caused the contributor, code frequency, and recent commit charts to not show any chart data. This fix resolves this by using getter/setter methods that work with UTC since it isn't dependent on timezones. Fixes #30851. --------- Co-authored-by: Sam Fisher <fisher@3echelon.local> --- web_src/js/components/RepoCodeFrequency.vue | 2 +- web_src/js/components/RepoContributors.vue | 2 +- web_src/js/components/RepoRecentCommits.vue | 2 +- web_src/js/utils/time.js | 37 ++++++++++++--------- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/web_src/js/components/RepoCodeFrequency.vue b/web_src/js/components/RepoCodeFrequency.vue index adce431264..1d40d6d417 100644 --- a/web_src/js/components/RepoCodeFrequency.vue +++ b/web_src/js/components/RepoCodeFrequency.vue @@ -67,7 +67,7 @@ export default { const weekValues = Object.values(this.data); const start = weekValues[0].week; const end = firstStartDateAfterDate(new Date()); - const startDays = startDaysBetween(new Date(start), new Date(end)); + const startDays = startDaysBetween(start, end); this.data = fillEmptyStartDaysWithZeroes(startDays, this.data); this.errorText = ''; } else { diff --git a/web_src/js/components/RepoContributors.vue b/web_src/js/components/RepoContributors.vue index 2347c41ae4..f7b05831e0 100644 --- a/web_src/js/components/RepoContributors.vue +++ b/web_src/js/components/RepoContributors.vue @@ -114,7 +114,7 @@ export default { const weekValues = Object.values(total.weeks); this.xAxisStart = weekValues[0].week; this.xAxisEnd = firstStartDateAfterDate(new Date()); - const startDays = startDaysBetween(new Date(this.xAxisStart), new Date(this.xAxisEnd)); + const startDays = startDaysBetween(this.xAxisStart, this.xAxisEnd); total.weeks = fillEmptyStartDaysWithZeroes(startDays, total.weeks); this.xAxisMin = this.xAxisStart; this.xAxisMax = this.xAxisEnd; diff --git a/web_src/js/components/RepoRecentCommits.vue b/web_src/js/components/RepoRecentCommits.vue index 502af533da..8759978e78 100644 --- a/web_src/js/components/RepoRecentCommits.vue +++ b/web_src/js/components/RepoRecentCommits.vue @@ -62,7 +62,7 @@ export default { const data = await response.json(); const start = Object.values(data)[0].week; const end = firstStartDateAfterDate(new Date()); - const startDays = startDaysBetween(new Date(start), new Date(end)); + const startDays = startDaysBetween(start, end); this.data = fillEmptyStartDaysWithZeroes(startDays, data).slice(-52); this.errorText = ''; } else { diff --git a/web_src/js/utils/time.js b/web_src/js/utils/time.js index 1848792c98..7c7eabd1a3 100644 --- a/web_src/js/utils/time.js +++ b/web_src/js/utils/time.js @@ -1,25 +1,30 @@ import dayjs from 'dayjs'; +import utc from 'dayjs/plugin/utc.js'; import {getCurrentLocale} from '../utils.js'; -// Returns an array of millisecond-timestamps of start-of-week days (Sundays) -export function startDaysBetween(startDate, endDate) { - // Ensure the start date is a Sunday - while (startDate.getDay() !== 0) { - startDate.setDate(startDate.getDate() + 1); - } +dayjs.extend(utc); - const start = dayjs(startDate); - const end = dayjs(endDate); - const startDays = []; +/** + * Returns an array of millisecond-timestamps of start-of-week days (Sundays) + * + * @param startConfig The start date. Can take any type that `Date` accepts. + * @param endConfig The end date. Can take any type that `Date` accepts. + */ +export function startDaysBetween(startDate, endDate) { + const start = dayjs.utc(startDate); + const end = dayjs.utc(endDate); let current = start; + + // Ensure the start date is a Sunday + while (current.day() !== 0) { + current = current.add(1, 'day'); + } + + const startDays = []; while (current.isBefore(end)) { startDays.push(current.valueOf()); - // we are adding 7 * 24 hours instead of 1 week because we don't want - // date library to use local time zone to calculate 1 week from now. - // local time zone is problematic because of daylight saving time (dst) - // used on some countries - current = current.add(7 * 24, 'hour'); + current = current.add(1, 'week'); } return startDays; @@ -29,10 +34,10 @@ export function firstStartDateAfterDate(inputDate) { if (!(inputDate instanceof Date)) { throw new Error('Invalid date'); } - const dayOfWeek = inputDate.getDay(); + const dayOfWeek = inputDate.getUTCDay(); const daysUntilSunday = 7 - dayOfWeek; const resultDate = new Date(inputDate.getTime()); - resultDate.setDate(resultDate.getDate() + daysUntilSunday); + resultDate.setUTCDate(resultDate.getUTCDate() + daysUntilSunday); return resultDate.valueOf(); } From ce8b11ae131bef6cd7df0849ed39da7984953a4b Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Mon, 6 May 2024 14:32:05 +0800 Subject: [PATCH 279/370] Fix some UI problems (install/checkbox) (#30854) Fix the space between the box and label for checkboxes, and fix incorrect usages in "repo-issue.js" --- templates/install.tmpl | 314 +++++++++++++++--------------- web_src/css/install.css | 8 +- web_src/css/modules/checkbox.css | 2 +- web_src/js/features/repo-issue.js | 14 +- 4 files changed, 170 insertions(+), 168 deletions(-) diff --git a/templates/install.tmpl b/templates/install.tmpl index f3117af547..965e57f213 100644 --- a/templates/install.tmpl +++ b/templates/install.tmpl @@ -157,168 +157,171 @@ <!-- Optional Settings --> <h4 class="ui dividing header">{{ctx.Locale.Tr "install.optional_title"}}</h4> - - <!-- Email --> - <details class="optional field"> - <summary class="right-content tw-py-2{{if .Err_SMTP}} text red{{end}}"> - {{ctx.Locale.Tr "install.email_title"}} - </summary> - <div class="inline field"> - <label for="smtp_addr">{{ctx.Locale.Tr "install.smtp_addr"}}</label> - <input id="smtp_addr" name="smtp_addr" value="{{.smtp_addr}}"> - </div> - <div class="inline field"> - <label for="smtp_port">{{ctx.Locale.Tr "install.smtp_port"}}</label> - <input id="smtp_port" name="smtp_port" value="{{.smtp_port}}"> - </div> - <div class="inline field {{if .Err_SMTPFrom}}error{{end}}"> - <label for="smtp_from">{{ctx.Locale.Tr "install.smtp_from"}}</label> - <input id="smtp_from" name="smtp_from" value="{{.smtp_from}}"> - <span class="help">{{ctx.Locale.TrString "install.smtp_from_helper"}}{{/* it contains lt/gt chars*/}}</span> - </div> - <div class="inline field {{if .Err_SMTPUser}}error{{end}}"> - <label for="smtp_user">{{ctx.Locale.Tr "install.mailer_user"}}</label> - <input id="smtp_user" name="smtp_user" value="{{.smtp_user}}"> - </div> - <div class="inline field"> - <label for="smtp_passwd">{{ctx.Locale.Tr "install.mailer_password"}}</label> - <input id="smtp_passwd" name="smtp_passwd" type="password" value="{{.smtp_passwd}}"> - </div> - <div class="inline field"> - <div class="ui checkbox"> - <label>{{ctx.Locale.Tr "install.register_confirm"}}</label> - <input name="register_confirm" type="checkbox" {{if .register_confirm}}checked{{end}}> + <div> + <!-- Email --> + <details class="optional field"> + <summary class="right-content tw-py-2{{if .Err_SMTP}} text red{{end}}"> + {{ctx.Locale.Tr "install.email_title"}} + </summary> + <div class="inline field"> + <label for="smtp_addr">{{ctx.Locale.Tr "install.smtp_addr"}}</label> + <input id="smtp_addr" name="smtp_addr" value="{{.smtp_addr}}"> </div> - </div> - <div class="inline field"> - <div class="ui checkbox"> - <label>{{ctx.Locale.Tr "install.mail_notify"}}</label> - <input name="mail_notify" type="checkbox" {{if .mail_notify}}checked{{end}}> + <div class="inline field"> + <label for="smtp_port">{{ctx.Locale.Tr "install.smtp_port"}}</label> + <input id="smtp_port" name="smtp_port" value="{{.smtp_port}}"> </div> - </div> - </details> - - <!-- Server and other services --> - <details class="optional field"> - <summary class="right-content tw-py-2{{if .Err_Services}} text red{{end}}"> - {{ctx.Locale.Tr "install.server_service_title"}} - </summary> - <div class="inline field"> - <div class="ui checkbox" id="offline-mode"> - <label data-tooltip-content="{{ctx.Locale.Tr "install.offline_mode_popup"}}">{{ctx.Locale.Tr "install.offline_mode"}}</label> - <input name="offline_mode" type="checkbox" {{if .offline_mode}}checked{{end}}> + <div class="inline field {{if .Err_SMTPFrom}}error{{end}}"> + <label for="smtp_from">{{ctx.Locale.Tr "install.smtp_from"}}</label> + <input id="smtp_from" name="smtp_from" value="{{.smtp_from}}"> + <span class="help">{{ctx.Locale.TrString "install.smtp_from_helper"}}{{/* it contains lt/gt chars*/}}</span> </div> - </div> - <div class="inline field"> - <div class="ui checkbox" id="disable-gravatar"> - <label data-tooltip-content="{{ctx.Locale.Tr "install.disable_gravatar_popup"}}">{{ctx.Locale.Tr "install.disable_gravatar"}}</label> - <input name="disable_gravatar" type="checkbox" {{if .disable_gravatar}}checked{{end}}> + <div class="inline field {{if .Err_SMTPUser}}error{{end}}"> + <label for="smtp_user">{{ctx.Locale.Tr "install.mailer_user"}}</label> + <input id="smtp_user" name="smtp_user" value="{{.smtp_user}}"> </div> - </div> - <div class="inline field"> - <div class="ui checkbox" id="federated-avatar-lookup"> - <label data-tooltip-content="{{ctx.Locale.Tr "install.federated_avatar_lookup_popup"}}">{{ctx.Locale.Tr "install.federated_avatar_lookup"}}</label> - <input name="enable_federated_avatar" type="checkbox" {{if .enable_federated_avatar}}checked{{end}}> + <div class="inline field"> + <label for="smtp_passwd">{{ctx.Locale.Tr "install.mailer_password"}}</label> + <input id="smtp_passwd" name="smtp_passwd" type="password" value="{{.smtp_passwd}}"> </div> - </div> - <div class="inline field"> - <div class="ui checkbox" id="enable-openid-signin"> - <label data-tooltip-content="{{ctx.Locale.Tr "install.openid_signin_popup"}}">{{ctx.Locale.Tr "install.openid_signin"}}</label> - <input name="enable_open_id_sign_in" type="checkbox" {{if .enable_open_id_sign_in}}checked{{end}}> - </div> - </div> - <div class="inline field"> - <div class="ui checkbox" id="disable-registration"> - <label data-tooltip-content="{{ctx.Locale.Tr "install.disable_registration_popup"}}">{{ctx.Locale.Tr "install.disable_registration"}}</label> - <input name="disable_registration" type="checkbox" {{if .disable_registration}}checked{{end}}> - </div> - </div> - <div class="inline field"> - <div class="ui checkbox" id="allow-only-external-registration"> - <label data-tooltip-content="{{ctx.Locale.Tr "install.allow_only_external_registration_popup"}}">{{ctx.Locale.Tr "install.allow_only_external_registration_popup"}}</label> - <input name="allow_only_external_registration" type="checkbox" {{if .allow_only_external_registration}}checked{{end}}> - </div> - </div> - <div class="inline field"> - <div class="ui checkbox" id="enable-openid-signup"> - <label data-tooltip-content="{{ctx.Locale.Tr "install.openid_signup_popup"}}">{{ctx.Locale.Tr "install.openid_signup"}}</label> - <input name="enable_open_id_sign_up" type="checkbox" {{if .enable_open_id_sign_up}}checked{{end}}> - </div> - </div> - <div class="inline field"> - <div class="ui checkbox" id="enable-captcha"> - <label data-tooltip-content="{{ctx.Locale.Tr "install.enable_captcha_popup"}}">{{ctx.Locale.Tr "install.enable_captcha"}}</label> - <input name="enable_captcha" type="checkbox" {{if .enable_captcha}}checked{{end}}> - </div> - </div> - <div class="inline field"> - <div class="ui checkbox"> - <label data-tooltip-content="{{ctx.Locale.Tr "install.require_sign_in_view_popup"}}">{{ctx.Locale.Tr "install.require_sign_in_view"}}</label> - <input name="require_sign_in_view" type="checkbox" {{if .require_sign_in_view}}checked{{end}}> - </div> - </div> - <div class="inline field"> - <div class="ui checkbox"> - <label data-tooltip-content="{{ctx.Locale.Tr "install.default_keep_email_private_popup"}}">{{ctx.Locale.Tr "install.default_keep_email_private"}}</label> - <input name="default_keep_email_private" type="checkbox" {{if .default_keep_email_private}}checked{{end}}> - </div> - </div> - <div class="inline field"> - <div class="ui checkbox"> - <label data-tooltip-content="{{ctx.Locale.Tr "install.default_allow_create_organization_popup"}}">{{ctx.Locale.Tr "install.default_allow_create_organization"}}</label> - <input name="default_allow_create_organization" type="checkbox" {{if .default_allow_create_organization}}checked{{end}}> - </div> - </div> - <div class="inline field"> - <div class="ui checkbox"> - <label data-tooltip-content="{{ctx.Locale.Tr "install.default_enable_timetracking_popup"}}">{{ctx.Locale.Tr "install.default_enable_timetracking"}}</label> - <input name="default_enable_timetracking" type="checkbox" {{if .default_enable_timetracking}}checked{{end}}> - </div> - </div> - <div class="inline field"> - <label for="no_reply_address">{{ctx.Locale.Tr "install.no_reply_address"}}</label> - <input id="_no_reply_address" name="no_reply_address" value="{{.no_reply_address}}"> - <span class="help">{{ctx.Locale.Tr "install.no_reply_address_helper"}}</span> - </div> - <div class="inline field"> - <label for="password_algorithm">{{ctx.Locale.Tr "install.password_algorithm"}}</label> - <div class="ui selection dropdown"> - <input id="password_algorithm" type="hidden" name="password_algorithm" value="{{.password_algorithm}}"> - <div class="text">{{.password_algorithm}}</div> - {{svg "octicon-triangle-down" 14 "dropdown icon"}} - <div class="menu"> - {{range .PasswordHashAlgorithms}} - <div class="item" data-value="{{.}}">{{.}}</div> - {{end}} + <div class="inline field"> + <div class="ui checkbox"> + <label>{{ctx.Locale.Tr "install.register_confirm"}}</label> + <input name="register_confirm" type="checkbox" {{if .register_confirm}}checked{{end}}> </div> </div> - <span class="help">{{ctx.Locale.Tr "install.password_algorithm_helper"}}</span> - </div> - </details> + <div class="inline field"> + <div class="ui checkbox"> + <label>{{ctx.Locale.Tr "install.mail_notify"}}</label> + <input name="mail_notify" type="checkbox" {{if .mail_notify}}checked{{end}}> + </div> + </div> + </details> - <!-- Admin --> - <details class="optional field"> - <summary class="right-content tw-py-2{{if .Err_Admin}} text red{{end}}"> - {{ctx.Locale.Tr "install.admin_title"}} - </summary> - <p class="center">{{ctx.Locale.Tr "install.admin_setting_desc"}}</p> - <div class="inline field {{if .Err_AdminName}}error{{end}}"> - <label for="admin_name">{{ctx.Locale.Tr "install.admin_name"}}</label> - <input id="admin_name" name="admin_name" value="{{.admin_name}}"> - </div> - <div class="inline field {{if .Err_AdminEmail}}error{{end}}"> - <label for="admin_email">{{ctx.Locale.Tr "install.admin_email"}}</label> - <input id="admin_email" name="admin_email" type="email" value="{{.admin_email}}"> - </div> - <div class="inline field {{if .Err_AdminPasswd}}error{{end}}"> - <label for="admin_passwd">{{ctx.Locale.Tr "install.admin_password"}}</label> - <input id="admin_passwd" name="admin_passwd" type="password" autocomplete="new-password" value="{{.admin_passwd}}"> - </div> - <div class="inline field {{if .Err_AdminPasswd}}error{{end}}"> - <label for="admin_confirm_passwd">{{ctx.Locale.Tr "install.confirm_password"}}</label> - <input id="admin_confirm_passwd" name="admin_confirm_passwd" autocomplete="new-password" type="password" value="{{.admin_confirm_passwd}}"> - </div> - </details> + <!-- Server and other services --> + <details class="optional field"> + <summary class="right-content tw-py-2{{if .Err_Services}} text red{{end}}"> + {{ctx.Locale.Tr "install.server_service_title"}} + </summary> + <div class="inline field"> + <div class="ui checkbox" id="offline-mode"> + <label data-tooltip-content="{{ctx.Locale.Tr "install.offline_mode_popup"}}">{{ctx.Locale.Tr "install.offline_mode"}}</label> + <input name="offline_mode" type="checkbox" {{if .offline_mode}}checked{{end}}> + </div> + </div> + <div class="inline field"> + <div class="ui checkbox" id="disable-gravatar"> + <label data-tooltip-content="{{ctx.Locale.Tr "install.disable_gravatar_popup"}}">{{ctx.Locale.Tr "install.disable_gravatar"}}</label> + <input name="disable_gravatar" type="checkbox" {{if .disable_gravatar}}checked{{end}}> + </div> + </div> + <div class="inline field"> + <div class="ui checkbox" id="federated-avatar-lookup"> + <label data-tooltip-content="{{ctx.Locale.Tr "install.federated_avatar_lookup_popup"}}">{{ctx.Locale.Tr "install.federated_avatar_lookup"}}</label> + <input name="enable_federated_avatar" type="checkbox" {{if .enable_federated_avatar}}checked{{end}}> + </div> + </div> + <div class="inline field"> + <div class="ui checkbox" id="enable-openid-signin"> + <label data-tooltip-content="{{ctx.Locale.Tr "install.openid_signin_popup"}}">{{ctx.Locale.Tr "install.openid_signin"}}</label> + <input name="enable_open_id_sign_in" type="checkbox" {{if .enable_open_id_sign_in}}checked{{end}}> + </div> + </div> + <div class="inline field"> + <div class="ui checkbox" id="disable-registration"> + <label data-tooltip-content="{{ctx.Locale.Tr "install.disable_registration_popup"}}">{{ctx.Locale.Tr "install.disable_registration"}}</label> + <input name="disable_registration" type="checkbox" {{if .disable_registration}}checked{{end}}> + </div> + </div> + <div class="inline field"> + <div class="ui checkbox" id="allow-only-external-registration"> + <label data-tooltip-content="{{ctx.Locale.Tr "install.allow_only_external_registration_popup"}}">{{ctx.Locale.Tr "install.allow_only_external_registration_popup"}}</label> + <input name="allow_only_external_registration" type="checkbox" {{if .allow_only_external_registration}}checked{{end}}> + </div> + </div> + <div class="inline field"> + <div class="ui checkbox" id="enable-openid-signup"> + <label data-tooltip-content="{{ctx.Locale.Tr "install.openid_signup_popup"}}">{{ctx.Locale.Tr "install.openid_signup"}}</label> + <input name="enable_open_id_sign_up" type="checkbox" {{if .enable_open_id_sign_up}}checked{{end}}> + </div> + </div> + <div class="inline field"> + <div class="ui checkbox" id="enable-captcha"> + <label data-tooltip-content="{{ctx.Locale.Tr "install.enable_captcha_popup"}}">{{ctx.Locale.Tr "install.enable_captcha"}}</label> + <input name="enable_captcha" type="checkbox" {{if .enable_captcha}}checked{{end}}> + </div> + </div> + <div class="inline field"> + <div class="ui checkbox"> + <label data-tooltip-content="{{ctx.Locale.Tr "install.require_sign_in_view_popup"}}">{{ctx.Locale.Tr "install.require_sign_in_view"}}</label> + <input name="require_sign_in_view" type="checkbox" {{if .require_sign_in_view}}checked{{end}}> + </div> + </div> + <div class="inline field"> + <div class="ui checkbox"> + <label data-tooltip-content="{{ctx.Locale.Tr "install.default_keep_email_private_popup"}}">{{ctx.Locale.Tr "install.default_keep_email_private"}}</label> + <input name="default_keep_email_private" type="checkbox" {{if .default_keep_email_private}}checked{{end}}> + </div> + </div> + <div class="inline field"> + <div class="ui checkbox"> + <label data-tooltip-content="{{ctx.Locale.Tr "install.default_allow_create_organization_popup"}}">{{ctx.Locale.Tr "install.default_allow_create_organization"}}</label> + <input name="default_allow_create_organization" type="checkbox" {{if .default_allow_create_organization}}checked{{end}}> + </div> + </div> + <div class="inline field"> + <div class="ui checkbox"> + <label data-tooltip-content="{{ctx.Locale.Tr "install.default_enable_timetracking_popup"}}">{{ctx.Locale.Tr "install.default_enable_timetracking"}}</label> + <input name="default_enable_timetracking" type="checkbox" {{if .default_enable_timetracking}}checked{{end}}> + </div> + </div> + <div class="inline field"> + <label for="no_reply_address">{{ctx.Locale.Tr "install.no_reply_address"}}</label> + <input id="_no_reply_address" name="no_reply_address" value="{{.no_reply_address}}"> + <span class="help">{{ctx.Locale.Tr "install.no_reply_address_helper"}}</span> + </div> + <div class="inline field"> + <label for="password_algorithm">{{ctx.Locale.Tr "install.password_algorithm"}}</label> + <div class="ui selection dropdown"> + <input id="password_algorithm" type="hidden" name="password_algorithm" value="{{.password_algorithm}}"> + <div class="text">{{.password_algorithm}}</div> + {{svg "octicon-triangle-down" 14 "dropdown icon"}} + <div class="menu"> + {{range .PasswordHashAlgorithms}} + <div class="item" data-value="{{.}}">{{.}}</div> + {{end}} + </div> + </div> + <span class="help">{{ctx.Locale.Tr "install.password_algorithm_helper"}}</span> + </div> + </details> + + <!-- Admin --> + <details class="optional field"> + <summary class="right-content tw-py-2{{if .Err_Admin}} text red{{end}}"> + {{ctx.Locale.Tr "install.admin_title"}} + </summary> + <p class="center">{{ctx.Locale.Tr "install.admin_setting_desc"}}</p> + <div class="inline field {{if .Err_AdminName}}error{{end}}"> + <label for="admin_name">{{ctx.Locale.Tr "install.admin_name"}}</label> + <input id="admin_name" name="admin_name" value="{{.admin_name}}"> + </div> + <div class="inline field {{if .Err_AdminEmail}}error{{end}}"> + <label for="admin_email">{{ctx.Locale.Tr "install.admin_email"}}</label> + <input id="admin_email" name="admin_email" type="email" value="{{.admin_email}}"> + </div> + <div class="inline field {{if .Err_AdminPasswd}}error{{end}}"> + <label for="admin_passwd">{{ctx.Locale.Tr "install.admin_password"}}</label> + <input id="admin_passwd" name="admin_passwd" type="password" autocomplete="new-password" value="{{.admin_passwd}}"> + </div> + <div class="inline field {{if .Err_AdminPasswd}}error{{end}}"> + <label for="admin_confirm_passwd">{{ctx.Locale.Tr "install.confirm_password"}}</label> + <input id="admin_confirm_passwd" name="admin_confirm_passwd" autocomplete="new-password" type="password" value="{{.admin_confirm_passwd}}"> + </div> + </details> + </div> + + <div class="divider"></div> {{if .EnvConfigKeys}} <!-- Environment Config --> @@ -333,12 +336,11 @@ </div> {{end}} - <div class="divider"></div> <div class="inline field"> <div class="right-content"> These configuration options will be written into: {{.CustomConfFile}} </div> - <div class="right-content tw-mt-2"> + <div class="tw-mt-4 tw-mb-2 tw-text-center"> <button class="ui primary button">{{ctx.Locale.Tr "install.install_btn_confirm"}}</button> </div> </div> diff --git a/web_src/css/install.css b/web_src/css/install.css index ee2395e6c5..7ab729405e 100644 --- a/web_src/css/install.css +++ b/web_src/css/install.css @@ -13,8 +13,7 @@ .page-content.install .ui.form .field > .help, .page-content.install .ui.form .field > .ui.checkbox:first-child, .page-content.install .ui.form .field > .right-content { - margin-left: 30%; - padding-left: 5px; + margin-left: calc(30% + 5px); width: auto; } @@ -24,10 +23,11 @@ } .page-content.install form.ui.form details.optional.field[open] { - border-bottom: 1px dashed var(--color-secondary); padding-bottom: 10px; } - +.page-content.install form.ui.form details.optional.field[open]:not(:last-child) { + border-bottom: 1px dashed var(--color-secondary); +} .page-content.install form.ui.form details.optional.field[open] summary { margin-bottom: 10px; } diff --git a/web_src/css/modules/checkbox.css b/web_src/css/modules/checkbox.css index 8d73573bfa..0a3a71acaa 100644 --- a/web_src/css/modules/checkbox.css +++ b/web_src/css/modules/checkbox.css @@ -41,7 +41,7 @@ input[type="radio"] { .ui.checkbox label, .ui.radio.checkbox label { - margin-left: 1.85714em; + margin-left: 20px; } .ui.checkbox + label { diff --git a/web_src/js/features/repo-issue.js b/web_src/js/features/repo-issue.js index 39c364ca50..d10d4dab8d 100644 --- a/web_src/js/features/repo-issue.js +++ b/web_src/js/features/repo-issue.js @@ -299,23 +299,23 @@ export function initRepoPullRequestMergeInstruction() { export function initRepoPullRequestAllowMaintainerEdit() { const wrapper = document.getElementById('allow-edits-from-maintainers'); if (!wrapper) return; - - wrapper.querySelector('input[type="checkbox"]')?.addEventListener('change', async (e) => { - const checked = e.target.checked; + const checkbox = wrapper.querySelector('input[type="checkbox"]'); + checkbox.addEventListener('input', async () => { const url = `${wrapper.getAttribute('data-url')}/set_allow_maintainer_edit`; wrapper.classList.add('is-loading'); - e.target.disabled = true; try { - const response = await POST(url, {data: {allow_maintainer_edit: checked}}); - if (!response.ok) { + const resp = await POST(url, {data: new URLSearchParams({allow_maintainer_edit: checkbox.checked})}); + if (!resp.ok) { throw new Error('Failed to update maintainer edit permission'); } + const data = await resp.json(); + checkbox.checked = data.allow_maintainer_edit; } catch (error) { + checkbox.checked = !checkbox.checked; console.error(error); showTemporaryTooltip(wrapper, wrapper.getAttribute('data-prompt-error')); } finally { wrapper.classList.remove('is-loading'); - e.target.disabled = false; } }); } From eda10cc2bb229a6b13ace76caea118384b381429 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Mon, 6 May 2024 15:17:22 +0800 Subject: [PATCH 280/370] Fix some UI problems (dropdown/container) (#30849) Follow #30345 Follow #30547 `ellipsis` / `white-space` shouldn't be put on the general dropdown components. --- templates/devtest/fomantic-dropdown.tmpl | 109 +++++++++++ templates/devtest/gitea-ui.tmpl | 88 --------- templates/repo/branch_dropdown.tmpl | 2 +- templates/repo/header.tmpl | 184 +++++++++--------- .../repo/issue/branch_selector_field.tmpl | 2 +- .../view_content/reference_issue_dialog.tmpl | 2 +- templates/repo/settings/options.tmpl | 2 +- web_src/css/base.css | 22 ++- web_src/css/form.css | 4 + web_src/css/modules/container.css | 22 +-- web_src/css/repo.css | 6 + .../js/components/RepoBranchTagSelector.vue | 4 +- web_src/js/features/repo-issue.js | 4 +- 13 files changed, 246 insertions(+), 205 deletions(-) create mode 100644 templates/devtest/fomantic-dropdown.tmpl diff --git a/templates/devtest/fomantic-dropdown.tmpl b/templates/devtest/fomantic-dropdown.tmpl new file mode 100644 index 0000000000..57a7c1313e --- /dev/null +++ b/templates/devtest/fomantic-dropdown.tmpl @@ -0,0 +1,109 @@ +{{template "base/head" .}} +<link rel="stylesheet" href="{{AssetUrlPrefix}}/css/devtest.css?v={{AssetVersion}}"> +<div class="page-content devtest ui container"> + <div> + <h2>Dropdown</h2> + <div> + <div class="ui dropdown tw-border tw-border-red tw-border-dashed" data-tooltip-content="border for demo purpose only"> + <span class="text">search-input & flex-item in menu</span> + {{svg "octicon-triangle-down" 14 "dropdown icon"}} + <div class="menu flex-items-menu"> + <div class="ui icon search input"><i class="icon">{{svg "octicon-search"}}</i><input type="text" value="search input in menu"></div> + <div class="item"><input type="radio">item</div> + <div class="item"><input type="radio">item</div> + </div> + </div> + <div class="ui search selection dropdown"> + <span class="text">search ...</span> + <input name="value" class="search"> + {{svg "octicon-triangle-down" 14 "dropdown icon"}} + {{svg "octicon-x" 14 "remove icon"}} + <div class="menu"> + <div class="item">item</div> + </div> + </div> + <div class="ui multiple selection dropdown"> + <input class="hidden" value="1"> + {{svg "octicon-triangle-down" 14 "dropdown icon"}} + {{svg "octicon-x" 14 "remove icon"}} + <div class="default text">empty multiple dropdown</div> + <div class="menu"> + <div class="item">item</div> + </div> + </div> + <div class="ui multiple clearable search selection dropdown"> + <input type="hidden" value="1"> + {{svg "octicon-triangle-down" 14 "dropdown icon"}} + {{svg "octicon-x" 14 "remove icon"}} + <div class="default text">clearable search dropdown</div> + <div class="menu"> + <div class="item" data-value="1">item</div> + </div> + </div> + <div class="ui buttons"> + <button class="ui button">Button with Dropdown</button> + <div class="ui dropdown button icon"> + {{svg "octicon-triangle-down"}} + <div class="menu"> + <div class="item">item</div> + </div> + </div> + </div> + </div> + + <h2>Selection</h2> + <div> + {{/* the "selection" class is optional, it will be added by JS automatically */}} + <select class="ui dropdown selection ellipsis-items-nowrap"> + <option>a</option> + <option>abcdefuvwxyz</option> + <option>loooooooooooooooooooooooooooooooooooooooooooooooooooooooooong</option> + </select> + <select class="ui dropdown ellipsis-items-nowrap tw-max-w-[8em]"> + <option>loooooooooooooooooooooooooooooooooooooooooooooooooooooooooong</option> + <option>abcdefuvwxyz</option> + <option>a</option> + </select> + </div> + <h2>Dropdown Button (demo only without menu)</h2> + <div> + <div class="ui dropdown mini button"> + <span class="text">mini dropdown</span> + {{svg "octicon-triangle-down" 14 "dropdown icon"}} + </div> + <div class="ui dropdown tiny button"> + <span class="text">tiny dropdown</span> + {{svg "octicon-triangle-down" 14 "dropdown icon"}} + </div> + <div class="ui button dropdown"> + <span class="text">button dropdown</span> + {{svg "octicon-triangle-down" 14 "dropdown icon"}} + </div> + </div> + + <div> + <div class="ui dropdown mini compact button"> + <span class="text">mini compact</span> + {{svg "octicon-triangle-down" 14 "dropdown icon"}} + </div> + <div class="ui dropdown tiny compact button"> + <span class="text">tiny compact</span> + {{svg "octicon-triangle-down" 14 "dropdown icon"}} + </div> + <div class="ui button compact dropdown"> + <span class="text">button compact</span> + {{svg "octicon-triangle-down" 14 "dropdown icon"}} + </div> + </div> + + <div> + <hr> + <div class="ui tiny button">Other button align with ...</div> + <div class="ui dropdown tiny button"> + <span class="text">... Dropdown Button</span> + {{svg "octicon-triangle-down" 14 "dropdown icon"}} + </div> + </div> + </div> +</div> +{{template "base/footer" .}} diff --git a/templates/devtest/gitea-ui.tmpl b/templates/devtest/gitea-ui.tmpl index 3b13c13be8..ea293fd3b4 100644 --- a/templates/devtest/gitea-ui.tmpl +++ b/templates/devtest/gitea-ui.tmpl @@ -180,94 +180,6 @@ <input type="text" placeholder="place holder"> </div> </div> - - <h2>Dropdown with SVG</h2> - <div> - <div class="ui dropdown tw-border tw-border-red tw-border-dashed" data-tooltip-content="border for demo purpose only"> - <span class="text">search-input & flex-item in menu</span> - {{svg "octicon-triangle-down" 14 "dropdown icon"}} - <div class="menu flex-items-menu"> - <div class="ui icon search input"><i class="icon">{{svg "octicon-search"}}</i><input type="text" value="search input in menu"></div> - <div class="item"><input type="radio">item</div> - <div class="item"><input type="radio">item</div> - </div> - </div> - <div class="ui search selection dropdown"> - <span class="text">search ...</span> - <input name="value" class="search"> - {{svg "octicon-triangle-down" 14 "dropdown icon"}} - {{svg "octicon-x" 14 "remove icon"}} - <div class="menu"> - <div class="item">item</div> - </div> - </div> - <div class="ui multiple selection dropdown"> - <input class="hidden" value="1"> - {{svg "octicon-triangle-down" 14 "dropdown icon"}} - {{svg "octicon-x" 14 "remove icon"}} - <div class="default text">empty multiple dropdown</div> - <div class="menu"> - <div class="item">item</div> - </div> - </div> - <div class="ui multiple clearable search selection dropdown"> - <input type="hidden" value="1"> - {{svg "octicon-triangle-down" 14 "dropdown icon"}} - {{svg "octicon-x" 14 "remove icon"}} - <div class="default text">clearable search dropdown</div> - <div class="menu"> - <div class="item" data-value="1">item</div> - </div> - </div> - <div class="ui buttons"> - <button class="ui button">Button with Dropdown</button> - <div class="ui dropdown button icon"> - {{svg "octicon-triangle-down"}} - <div class="menu"> - <div class="item">item</div> - </div> - </div> - </div> - </div> - - <div> - <div class="ui dropdown mini button"> - <span class="text">mini dropdown</span> - {{svg "octicon-triangle-down" 14 "dropdown icon"}} - </div> - <div class="ui dropdown tiny button"> - <span class="text">tiny dropdown</span> - {{svg "octicon-triangle-down" 14 "dropdown icon"}} - </div> - <div class="ui button dropdown"> - <span class="text">button dropdown</span> - {{svg "octicon-triangle-down" 14 "dropdown icon"}} - </div> - </div> - - <div> - <div class="ui dropdown mini compact button"> - <span class="text">mini compact</span> - {{svg "octicon-triangle-down" 14 "dropdown icon"}} - </div> - <div class="ui dropdown tiny compact button"> - <span class="text">tiny compact</span> - {{svg "octicon-triangle-down" 14 "dropdown icon"}} - </div> - <div class="ui button compact dropdown"> - <span class="text">button compact</span> - {{svg "octicon-triangle-down" 14 "dropdown icon"}} - </div> - </div> - - <div> - <hr> - <div class="ui tiny button">Button align with ...</div> - <div class="ui dropdown tiny button"> - <span class="text">... Dropdown Button</span> - {{svg "octicon-triangle-down" 14 "dropdown icon"}} - </div> - </div> </div> <div> diff --git a/templates/repo/branch_dropdown.tmpl b/templates/repo/branch_dropdown.tmpl index 8f58826c6a..c4f73875f2 100644 --- a/templates/repo/branch_dropdown.tmpl +++ b/templates/repo/branch_dropdown.tmpl @@ -69,7 +69,7 @@ <div class="js-branch-tag-selector {{if .ContainerClasses}}{{.ContainerClasses}}{{end}}"> {{/* show dummy elements before Vue componment is mounted, this code must match the code in BranchTagSelector.vue */}} - <div class="ui dropdown custom branch-selector-dropdown"> + <div class="ui dropdown custom branch-selector-dropdown ellipsis-items-nowrap"> <div class="ui button branch-dropdown-button"> <span class="flex-text-block gt-ellipsis"> {{if .release}} diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index c0d833a187..34f47b7d89 100644 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -128,107 +128,109 @@ {{if .IsGenerated}}<div class="fork-flag">{{ctx.Locale.Tr "repo.generated_from"}} <a href="{{(.TemplateRepo ctx).Link}}">{{(.TemplateRepo ctx).FullName}}</a></div>{{end}} </div> {{end}} - <overflow-menu class="ui container secondary pointing tabular top attached borderless menu tw-pt-0 tw-my-0"> - {{if not (or .Repository.IsBeingCreated .Repository.IsBroken)}} - <div class="overflow-menu-items"> - {{if .Permission.CanRead ctx.Consts.RepoUnitTypeCode}} - <a class="{{if .PageIsViewCode}}active {{end}}item" href="{{.RepoLink}}{{if and (ne .BranchName .Repository.DefaultBranch) (not $.PageIsWiki)}}/src/{{.BranchNameSubURL}}{{end}}"> - {{svg "octicon-code"}} {{ctx.Locale.Tr "repo.code"}} - </a> - {{end}} - - {{if .Permission.CanRead ctx.Consts.RepoUnitTypeIssues}} - <a class="{{if .PageIsIssueList}}active {{end}}item" href="{{.RepoLink}}/issues"> - {{svg "octicon-issue-opened"}} {{ctx.Locale.Tr "repo.issues"}} - {{if .Repository.NumOpenIssues}} - <span class="ui small label">{{CountFmt .Repository.NumOpenIssues}}</span> - {{end}} + <div class="ui container"> + <overflow-menu class="ui secondary pointing menu"> + {{if not (or .Repository.IsBeingCreated .Repository.IsBroken)}} + <div class="overflow-menu-items"> + {{if .Permission.CanRead ctx.Consts.RepoUnitTypeCode}} + <a class="{{if .PageIsViewCode}}active {{end}}item" href="{{.RepoLink}}{{if and (ne .BranchName .Repository.DefaultBranch) (not $.PageIsWiki)}}/src/{{.BranchNameSubURL}}{{end}}"> + {{svg "octicon-code"}} {{ctx.Locale.Tr "repo.code"}} </a> - {{end}} - - {{if .Permission.CanRead ctx.Consts.RepoUnitTypeExternalTracker}} - <a class="{{if .PageIsIssueList}}active {{end}}item" href="{{.RepoExternalIssuesLink}}" target="_blank" rel="noopener noreferrer"> - {{svg "octicon-link-external"}} {{ctx.Locale.Tr "repo.issues"}} - </a> - {{end}} - - {{if and .Repository.CanEnablePulls (.Permission.CanRead ctx.Consts.RepoUnitTypePullRequests)}} - <a class="{{if .PageIsPullList}}active {{end}}item" href="{{.RepoLink}}/pulls"> - {{svg "octicon-git-pull-request"}} {{ctx.Locale.Tr "repo.pulls"}} - {{if .Repository.NumOpenPulls}} - <span class="ui small label">{{CountFmt .Repository.NumOpenPulls}}</span> - {{end}} - </a> - {{end}} - - {{if and .EnableActions (not .UnitActionsGlobalDisabled) (.Permission.CanRead ctx.Consts.RepoUnitTypeActions)}} - <a class="{{if .PageIsActions}}active {{end}}item" href="{{.RepoLink}}/actions"> - {{svg "octicon-play"}} {{ctx.Locale.Tr "actions.actions"}} - {{if .Repository.NumOpenActionRuns}} - <span class="ui small label">{{CountFmt .Repository.NumOpenActionRuns}}</span> - {{end}} - </a> - {{end}} - - {{if .Permission.CanRead ctx.Consts.RepoUnitTypePackages}} - <a href="{{.RepoLink}}/packages" class="{{if .IsPackagesPage}}active {{end}}item"> - {{svg "octicon-package"}} {{ctx.Locale.Tr "packages.title"}} - </a> - {{end}} - - {{$projectsUnit := .Repository.MustGetUnit $.Context ctx.Consts.RepoUnitTypeProjects}} - {{if and (not .UnitProjectsGlobalDisabled) (.Permission.CanRead ctx.Consts.RepoUnitTypeProjects) ($projectsUnit.ProjectsConfig.IsProjectsAllowed "repo")}} - <a href="{{.RepoLink}}/projects" class="{{if .IsProjectsPage}}active {{end}}item"> - {{svg "octicon-project"}} {{ctx.Locale.Tr "repo.project_board"}} - {{if .Repository.NumOpenProjects}} - <span class="ui small label">{{CountFmt .Repository.NumOpenProjects}}</span> - {{end}} - </a> - {{end}} - - {{if and (.Permission.CanRead ctx.Consts.RepoUnitTypeReleases) (not .IsEmptyRepo)}} - <a class="{{if or .PageIsReleaseList .PageIsTagList}}active {{end}}item" href="{{.RepoLink}}/releases"> - {{svg "octicon-tag"}} {{ctx.Locale.Tr "repo.releases"}} - {{if .NumReleases}} - <span class="ui small label">{{CountFmt .NumReleases}}</span> {{end}} - </a> - {{end}} - {{if .Permission.CanRead ctx.Consts.RepoUnitTypeWiki}} - <a class="{{if .PageIsWiki}}active {{end}}item" href="{{.RepoLink}}/wiki"> - {{svg "octicon-book"}} {{ctx.Locale.Tr "repo.wiki"}} + {{if .Permission.CanRead ctx.Consts.RepoUnitTypeIssues}} + <a class="{{if .PageIsIssueList}}active {{end}}item" href="{{.RepoLink}}/issues"> + {{svg "octicon-issue-opened"}} {{ctx.Locale.Tr "repo.issues"}} + {{if .Repository.NumOpenIssues}} + <span class="ui small label">{{CountFmt .Repository.NumOpenIssues}}</span> + {{end}} + </a> + {{end}} + + {{if .Permission.CanRead ctx.Consts.RepoUnitTypeExternalTracker}} + <a class="{{if .PageIsIssueList}}active {{end}}item" href="{{.RepoExternalIssuesLink}}" target="_blank" rel="noopener noreferrer"> + {{svg "octicon-link-external"}} {{ctx.Locale.Tr "repo.issues"}} + </a> + {{end}} + + {{if and .Repository.CanEnablePulls (.Permission.CanRead ctx.Consts.RepoUnitTypePullRequests)}} + <a class="{{if .PageIsPullList}}active {{end}}item" href="{{.RepoLink}}/pulls"> + {{svg "octicon-git-pull-request"}} {{ctx.Locale.Tr "repo.pulls"}} + {{if .Repository.NumOpenPulls}} + <span class="ui small label">{{CountFmt .Repository.NumOpenPulls}}</span> + {{end}} + </a> + {{end}} + + {{if and .EnableActions (not .UnitActionsGlobalDisabled) (.Permission.CanRead ctx.Consts.RepoUnitTypeActions)}} + <a class="{{if .PageIsActions}}active {{end}}item" href="{{.RepoLink}}/actions"> + {{svg "octicon-play"}} {{ctx.Locale.Tr "actions.actions"}} + {{if .Repository.NumOpenActionRuns}} + <span class="ui small label">{{CountFmt .Repository.NumOpenActionRuns}}</span> + {{end}} + </a> + {{end}} + + {{if .Permission.CanRead ctx.Consts.RepoUnitTypePackages}} + <a href="{{.RepoLink}}/packages" class="{{if .IsPackagesPage}}active {{end}}item"> + {{svg "octicon-package"}} {{ctx.Locale.Tr "packages.title"}} + </a> + {{end}} + + {{$projectsUnit := .Repository.MustGetUnit $.Context ctx.Consts.RepoUnitTypeProjects}} + {{if and (not .UnitProjectsGlobalDisabled) (.Permission.CanRead ctx.Consts.RepoUnitTypeProjects) ($projectsUnit.ProjectsConfig.IsProjectsAllowed "repo")}} + <a href="{{.RepoLink}}/projects" class="{{if .IsProjectsPage}}active {{end}}item"> + {{svg "octicon-project"}} {{ctx.Locale.Tr "repo.project_board"}} + {{if .Repository.NumOpenProjects}} + <span class="ui small label">{{CountFmt .Repository.NumOpenProjects}}</span> + {{end}} + </a> + {{end}} + + {{if and (.Permission.CanRead ctx.Consts.RepoUnitTypeReleases) (not .IsEmptyRepo)}} + <a class="{{if or .PageIsReleaseList .PageIsTagList}}active {{end}}item" href="{{.RepoLink}}/releases"> + {{svg "octicon-tag"}} {{ctx.Locale.Tr "repo.releases"}} + {{if .NumReleases}} + <span class="ui small label">{{CountFmt .NumReleases}}</span> + {{end}} </a> - {{end}} + {{end}} - {{if .Permission.CanRead ctx.Consts.RepoUnitTypeExternalWiki}} - <a class="item" href="{{(.Repository.MustGetUnit $.Context ctx.Consts.RepoUnitTypeExternalWiki).ExternalWikiConfig.ExternalWikiURL}}" target="_blank" rel="noopener noreferrer"> - {{svg "octicon-link-external"}} {{ctx.Locale.Tr "repo.wiki"}} - </a> - {{end}} + {{if .Permission.CanRead ctx.Consts.RepoUnitTypeWiki}} + <a class="{{if .PageIsWiki}}active {{end}}item" href="{{.RepoLink}}/wiki"> + {{svg "octicon-book"}} {{ctx.Locale.Tr "repo.wiki"}} + </a> + {{end}} - {{if and (.Permission.CanReadAny ctx.Consts.RepoUnitTypePullRequests ctx.Consts.RepoUnitTypeIssues ctx.Consts.RepoUnitTypeReleases) (not .IsEmptyRepo)}} - <a class="{{if .PageIsActivity}}active {{end}}item" href="{{.RepoLink}}/activity"> - {{svg "octicon-pulse"}} {{ctx.Locale.Tr "repo.activity"}} - </a> - {{end}} + {{if .Permission.CanRead ctx.Consts.RepoUnitTypeExternalWiki}} + <a class="item" href="{{(.Repository.MustGetUnit $.Context ctx.Consts.RepoUnitTypeExternalWiki).ExternalWikiConfig.ExternalWikiURL}}" target="_blank" rel="noopener noreferrer"> + {{svg "octicon-link-external"}} {{ctx.Locale.Tr "repo.wiki"}} + </a> + {{end}} - {{template "custom/extra_tabs" .}} + {{if and (.Permission.CanReadAny ctx.Consts.RepoUnitTypePullRequests ctx.Consts.RepoUnitTypeIssues ctx.Consts.RepoUnitTypeReleases) (not .IsEmptyRepo)}} + <a class="{{if .PageIsActivity}}active {{end}}item" href="{{.RepoLink}}/activity"> + {{svg "octicon-pulse"}} {{ctx.Locale.Tr "repo.activity"}} + </a> + {{end}} - {{if .Permission.IsAdmin}} - <span class="item-flex-space"></span> + {{template "custom/extra_tabs" .}} + + {{if .Permission.IsAdmin}} + <span class="item-flex-space"></span> + <a class="{{if .PageIsRepoSettings}}active {{end}} item" href="{{.RepoLink}}/settings"> + {{svg "octicon-tools"}} {{ctx.Locale.Tr "repo.settings"}} + </a> + {{end}} + </div> + {{else if .Permission.IsAdmin}} + <div class="overflow-menu-items"> <a class="{{if .PageIsRepoSettings}}active {{end}} item" href="{{.RepoLink}}/settings"> {{svg "octicon-tools"}} {{ctx.Locale.Tr "repo.settings"}} </a> - {{end}} - </div> - {{else if .Permission.IsAdmin}} - <div class="overflow-menu-items"> - <a class="{{if .PageIsRepoSettings}}active {{end}} item" href="{{.RepoLink}}/settings"> - {{svg "octicon-tools"}} {{ctx.Locale.Tr "repo.settings"}} - </a> - </div> - {{end}} - </overflow-menu> + </div> + {{end}} + </overflow-menu> + </div> <div class="ui tabs divider"></div> </div> diff --git a/templates/repo/issue/branch_selector_field.tmpl b/templates/repo/issue/branch_selector_field.tmpl index e9e5574cd7..cbf7929fdb 100644 --- a/templates/repo/issue/branch_selector_field.tmpl +++ b/templates/repo/issue/branch_selector_field.tmpl @@ -4,7 +4,7 @@ <form method="post" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/ref" id="update_issueref_form"> {{$.CsrfTokenHtml}} </form> -<div class="ui dropdown select-branch branch-selector-dropdown {{if not .HasIssuesOrPullsWritePermission}}disabled{{end}}" +<div class="ui dropdown select-branch branch-selector-dropdown ellipsis-items-nowrap {{if not .HasIssuesOrPullsWritePermission}}disabled{{end}}" data-no-results="{{ctx.Locale.Tr "no_results_found"}}" {{if not .Issue}}data-for-new-issue="true"{{end}} > diff --git a/templates/repo/issue/view_content/reference_issue_dialog.tmpl b/templates/repo/issue/view_content/reference_issue_dialog.tmpl index c7a471f55e..d6c9081001 100644 --- a/templates/repo/issue/view_content/reference_issue_dialog.tmpl +++ b/templates/repo/issue/view_content/reference_issue_dialog.tmpl @@ -7,7 +7,7 @@ {{.CsrfTokenHtml}} <div class="field"> <label><strong>{{ctx.Locale.Tr "repository"}}</strong></label> - <div class="ui search selection dropdown issue_reference_repository_search"> + <div class="ui search selection dropdown issue_reference_repository_search ellipsis-items-nowrap"> <div class="default text gt-ellipsis">{{.Repository.FullName}}</div> <div class="menu"></div> </div> diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index 40617021d9..b94c202f16 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -345,7 +345,7 @@ <div class="inline field"> {{$unitInternalWiki := .Repository.MustGetUnit ctx ctx.Consts.RepoUnitTypeWiki}} <label>{{ctx.Locale.Tr "repo.settings.default_wiki_everyone_access"}}</label> - <select name="default_wiki_everyone_access" class="ui dropdown"> + <select name="default_wiki_everyone_access" class="ui selection dropdown"> {{/* everyone access mode is different from others, none means it is unset and won't be applied */}} <option value="none" {{Iif (eq $unitInternalWiki.EveryoneAccessMode 0) "selected"}}>{{ctx.Locale.Tr "settings.permission_not_set"}}</option> <option value="read" {{Iif (eq $unitInternalWiki.EveryoneAccessMode 1) "selected"}}>{{ctx.Locale.Tr "settings.permission_read"}}</option> diff --git a/web_src/css/base.css b/web_src/css/base.css index c0ced2955c..412d9094e3 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -342,8 +342,6 @@ a.label, .ui.dropdown .menu > .item { color: var(--color-text); - overflow: hidden; - text-overflow: ellipsis; } .ui.dropdown .menu > .item:hover { @@ -374,7 +372,6 @@ a.label, .ui.selection.dropdown .menu > .item { border-color: var(--color-secondary); - white-space: nowrap; } .ui.selection.visible.dropdown > .text:not(.default) { @@ -1342,7 +1339,11 @@ table th[data-sortt-desc] .svg { align-items: center; gap: .25rem; vertical-align: middle; - min-width: 0; + min-width: 0; /* make ellipsis work */ +} + +.ui.ui.dropdown.selection { + min-width: 14em; /* match the default min width */ } .ui.dropdown .ui.label .svg { @@ -1369,3 +1370,16 @@ table th[data-sortt-desc] .svg { gap: .5rem; min-width: 0; } + +.ui.dropdown.ellipsis-items-nowrap > .text { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.ellipsis-items-nowrap > .item, +.ui.dropdown.ellipsis-items-nowrap .menu > .item { + white-space: nowrap !important; + overflow: hidden !important; + text-overflow: ellipsis !important; +} diff --git a/web_src/css/form.css b/web_src/css/form.css index 7479af0c4e..66ead32762 100644 --- a/web_src/css/form.css +++ b/web_src/css/form.css @@ -448,6 +448,10 @@ textarea:focus, } } +.ui.form .field > .selection.dropdown { + min-width: 14em; /* matches the default min width */ +} + .new.webhook form .help { margin-left: 25px; } diff --git a/web_src/css/modules/container.css b/web_src/css/modules/container.css index 9f67ceb8d5..c9df6ab3f5 100644 --- a/web_src/css/modules/container.css +++ b/web_src/css/modules/container.css @@ -2,26 +2,20 @@ unused rules here after refactoring, please remove them. */ .ui.container { - display: block; - max-width: 100%; -} - -.ui.fluid.container { - width: 100%; -} - -.ui[class*="center aligned"].container { - text-align: center; -} - -/* overwrite width of containers inside the main page content div (div with class "page-content") */ -.page-content .ui.ui.ui.container:not(.fluid) { width: 1280px; max-width: calc(100% - calc(2 * var(--page-margin-x))); margin-left: auto; margin-right: auto; } +.ui.fluid.container { + width: 100%; +} + .ui.container.fluid.padded { padding: 0 var(--page-margin-x); } + +.ui[class*="center aligned"].container { + text-align: center; +} diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 7695b632b4..f02b2b7578 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -2860,6 +2860,10 @@ tbody.commit-list { margin-top: 4px; } +.ui.dropdown.branch-selector-dropdown .scrolling.menu { + max-width: min(400px, 90vw); +} + .branch-selector-dropdown .branch-dropdown-button { margin: 0; max-width: 340px; @@ -2909,6 +2913,8 @@ tbody.commit-list { } .branch-selector-dropdown .menu .item .rss-icon { + position: absolute; + right: 4px; visibility: hidden; /* only show RSS icon on hover */ } diff --git a/web_src/js/components/RepoBranchTagSelector.vue b/web_src/js/components/RepoBranchTagSelector.vue index 8a741b68da..87530225e3 100644 --- a/web_src/js/components/RepoBranchTagSelector.vue +++ b/web_src/js/components/RepoBranchTagSelector.vue @@ -246,7 +246,7 @@ export function initRepoBranchTagSelector(selector) { export default sfc; // activate IDE's Vue plugin </script> <template> - <div class="ui dropdown custom branch-selector-dropdown"> + <div class="ui dropdown custom branch-selector-dropdown ellipsis-items-nowrap"> <div class="ui button branch-dropdown-button" @click="menuVisible = !menuVisible" @keyup.enter="menuVisible = !menuVisible"> <span class="flex-text-block gt-ellipsis"> <template v-if="release">{{ textReleaseCompare }}</template> @@ -280,7 +280,7 @@ export default sfc; // activate IDE's Vue plugin <div class="ui label" v-if="item.name===repoDefaultBranch && mode === 'branches'"> {{ textDefaultBranchLabel }} </div> - <a v-show="enableFeed && mode === 'branches'" role="button" class="rss-icon tw-float-right" :href="rssURLPrefix + item.url" target="_blank" @click.stop> + <a v-show="enableFeed && mode === 'branches'" role="button" class="rss-icon" :href="rssURLPrefix + item.url" target="_blank" @click.stop> <!-- creating a lot of Vue component is pretty slow, so we use a static SVG here --> <svg width="14" height="14" class="svg octicon-rss"><use href="#svg-symbol-octicon-rss"/></svg> </a> diff --git a/web_src/js/features/repo-issue.js b/web_src/js/features/repo-issue.js index d10d4dab8d..8ee681aedc 100644 --- a/web_src/js/features/repo-issue.js +++ b/web_src/js/features/repo-issue.js @@ -124,8 +124,8 @@ export function initRepoIssueSidebarList() { return; } filteredResponse.results.push({ - name: `#${issue.number} ${htmlEscape(issue.title) - }<div class="text small gt-word-break">${htmlEscape(issue.repository.full_name)}</div>`, + name: `<div class="gt-ellipsis">#${issue.number} ${htmlEscape(issue.title)}</div> +<div class="text small gt-word-break">${htmlEscape(issue.repository.full_name)}</div>`, value: issue.id, }); }); From 8e8ca6c6530e49e39f970bdfa84716ffda8973d0 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Mon, 6 May 2024 16:36:02 +0200 Subject: [PATCH 281/370] Get repo list with OrderBy alpha should respect owner too (#30784) instead of: - zowner/gcode - awesome/nul - zowner/nul - zowner/zzz we will get: - awesome/nul - zowner/gcode - zowner/nul - zowner/zzz --- models/repo/search.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models/repo/search.go b/models/repo/search.go index 4d64acf8cf..54d6dcfb44 100644 --- a/models/repo/search.go +++ b/models/repo/search.go @@ -8,14 +8,14 @@ import "code.gitea.io/gitea/models/db" // SearchOrderByMap represents all possible search order var SearchOrderByMap = map[string]map[string]db.SearchOrderBy{ "asc": { - "alpha": db.SearchOrderByAlphabetically, + "alpha": "owner_name ASC, name ASC", "created": db.SearchOrderByOldest, "updated": db.SearchOrderByLeastUpdated, "size": db.SearchOrderBySize, "id": db.SearchOrderByID, }, "desc": { - "alpha": db.SearchOrderByAlphabeticallyReverse, + "alpha": "owner_name DESC, name DESC", "created": db.SearchOrderByNewest, "updated": db.SearchOrderByRecentUpdated, "size": db.SearchOrderBySizeReverse, From 7c613f100e032f821df88a75954fc50b1cf2f926 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Tue, 7 May 2024 00:34:16 +0800 Subject: [PATCH 282/370] Make sure git version&feature are always prepared (#30877) Otherwise there would be more similar issues like #29287 --- cmd/hook.go | 7 +- cmd/serv.go | 2 +- modules/git/blame.go | 2 +- modules/git/commit.go | 2 +- modules/git/git.go | 187 +++++++++++-------------- modules/git/object_format.go | 6 +- modules/git/object_id.go | 2 +- modules/git/remote.go | 2 +- modules/git/repo.go | 2 +- modules/git/repo_base.go | 6 - modules/git/repo_base_gogit.go | 4 +- modules/git/repo_base_nogogit.go | 4 +- modules/git/repo_commit.go | 2 +- modules/git/repo_commitgraph.go | 2 +- modules/lfs/pointer_scanner_nogogit.go | 2 +- routers/init.go | 6 +- routers/private/hook_pre_receive.go | 2 +- routers/private/hook_proc_receive.go | 2 +- routers/private/serv.go | 2 +- routers/web/admin/config.go | 2 +- routers/web/misc/misc.go | 2 +- routers/web/repo/githttp.go | 2 +- routers/web/repo/repo.go | 2 +- services/gitdiff/gitdiff.go | 2 +- services/pull/patch.go | 2 +- services/pull/temp_repo.go | 2 +- services/repository/files/patch.go | 2 +- tests/integration/git_test.go | 2 +- 28 files changed, 116 insertions(+), 146 deletions(-) delete mode 100644 modules/git/repo_base.go diff --git a/cmd/hook.go b/cmd/hook.go index 2a9c25add5..9c1cb66f2a 100644 --- a/cmd/hook.go +++ b/cmd/hook.go @@ -220,10 +220,7 @@ Gitea or set your environment appropriately.`, "") } } - supportProcReceive := false - if git.CheckGitVersionAtLeast("2.29") == nil { - supportProcReceive = true - } + supportProcReceive := git.DefaultFeatures().SupportProcReceive for scanner.Scan() { // TODO: support news feeds for wiki @@ -497,7 +494,7 @@ Gitea or set your environment appropriately.`, "") return nil } - if git.CheckGitVersionAtLeast("2.29") != nil { + if !git.DefaultFeatures().SupportProcReceive { return fail(ctx, "No proc-receive support", "current git version doesn't support proc-receive.") } diff --git a/cmd/serv.go b/cmd/serv.go index 90190a19db..2bfd111061 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -178,7 +178,7 @@ func runServ(c *cli.Context) error { } if len(words) < 2 { - if git.CheckGitVersionAtLeast("2.29") == nil { + if git.DefaultFeatures().SupportProcReceive { // for AGit Flow if cmd == "ssh_info" { fmt.Print(`{"type":"gitea","version":1}`) diff --git a/modules/git/blame.go b/modules/git/blame.go index 69e1b08f93..a9b2706f21 100644 --- a/modules/git/blame.go +++ b/modules/git/blame.go @@ -132,7 +132,7 @@ func (r *BlameReader) Close() error { // CreateBlameReader creates reader for given repository, commit and file func CreateBlameReader(ctx context.Context, objectFormat ObjectFormat, repoPath string, commit *Commit, file string, bypassBlameIgnore bool) (*BlameReader, error) { var ignoreRevsFile *string - if CheckGitVersionAtLeast("2.23") == nil && !bypassBlameIgnore { + if DefaultFeatures().CheckVersionAtLeast("2.23") && !bypassBlameIgnore { ignoreRevsFile = tryCreateBlameIgnoreRevsFile(commit) } diff --git a/modules/git/commit.go b/modules/git/commit.go index d96cef37c8..86adaa79a6 100644 --- a/modules/git/commit.go +++ b/modules/git/commit.go @@ -423,7 +423,7 @@ func (c *Commit) GetSubModule(entryname string) (*SubModule, error) { // GetBranchName gets the closest branch name (as returned by 'git name-rev --name-only') func (c *Commit) GetBranchName() (string, error) { cmd := NewCommand(c.repo.Ctx, "name-rev") - if CheckGitVersionAtLeast("2.13.0") == nil { + if DefaultFeatures().CheckVersionAtLeast("2.13.0") { cmd.AddArguments("--exclude", "refs/tags/*") } cmd.AddArguments("--name-only", "--no-undefined").AddDynamicArguments(c.ID.String()) diff --git a/modules/git/git.go b/modules/git/git.go index e411269f7c..05ca260855 100644 --- a/modules/git/git.go +++ b/modules/git/git.go @@ -22,42 +22,63 @@ import ( "github.com/hashicorp/go-version" ) -// RequiredVersion is the minimum Git version required -const RequiredVersion = "2.0.0" +const RequiredVersion = "2.0.0" // the minimum Git version required + +type Features struct { + gitVersion *version.Version + + UsingGogit bool + SupportProcReceive bool // >= 2.29 + SupportHashSha256 bool // >= 2.42, SHA-256 repositories no longer an ‘experimental curiosity’ + SupportedObjectFormats []ObjectFormat // sha1, sha256 +} var ( - // GitExecutable is the command name of git - // Could be updated to an absolute path while initialization - GitExecutable = "git" - - // DefaultContext is the default context to run git commands in, must be initialized by git.InitXxx - DefaultContext context.Context - - DefaultFeatures struct { - GitVersion *version.Version - - SupportProcReceive bool // >= 2.29 - SupportHashSha256 bool // >= 2.42, SHA-256 repositories no longer an ‘experimental curiosity’ - } + GitExecutable = "git" // the command name of git, will be updated to an absolute path during initialization + DefaultContext context.Context // the default context to run git commands in, must be initialized by git.InitXxx + defaultFeatures *Features ) -// loadGitVersion tries to get the current git version and stores it into a global variable -func loadGitVersion() error { - // doesn't need RWMutex because it's executed by Init() - if DefaultFeatures.GitVersion != nil { - return nil - } +func (f *Features) CheckVersionAtLeast(atLeast string) bool { + return f.gitVersion.Compare(version.Must(version.NewVersion(atLeast))) >= 0 +} +// VersionInfo returns git version information +func (f *Features) VersionInfo() string { + return f.gitVersion.Original() +} + +func DefaultFeatures() *Features { + if defaultFeatures == nil { + if !setting.IsProd || setting.IsInTesting { + log.Warn("git.DefaultFeatures is called before git.InitXxx, initializing with default values") + } + if err := InitSimple(context.Background()); err != nil { + log.Fatal("git.InitSimple failed: %v", err) + } + } + return defaultFeatures +} + +func loadGitVersionFeatures() (*Features, error) { stdout, _, runErr := NewCommand(DefaultContext, "version").RunStdString(nil) if runErr != nil { - return runErr + return nil, runErr } ver, err := parseGitVersionLine(strings.TrimSpace(stdout)) - if err == nil { - DefaultFeatures.GitVersion = ver + if err != nil { + return nil, err } - return err + + features := &Features{gitVersion: ver, UsingGogit: isGogit} + features.SupportProcReceive = features.CheckVersionAtLeast("2.29") + features.SupportHashSha256 = features.CheckVersionAtLeast("2.42") && !isGogit + features.SupportedObjectFormats = []ObjectFormat{Sha1ObjectFormat} + if features.SupportHashSha256 { + features.SupportedObjectFormats = append(features.SupportedObjectFormats, Sha256ObjectFormat) + } + return features, nil } func parseGitVersionLine(s string) (*version.Version, error) { @@ -85,56 +106,24 @@ func SetExecutablePath(path string) error { return fmt.Errorf("git not found: %w", err) } GitExecutable = absPath + return nil +} - if err = loadGitVersion(); err != nil { - return fmt.Errorf("unable to load git version: %w", err) - } - - versionRequired, err := version.NewVersion(RequiredVersion) - if err != nil { - return err - } - - if DefaultFeatures.GitVersion.LessThan(versionRequired) { +func ensureGitVersion() error { + if !DefaultFeatures().CheckVersionAtLeast(RequiredVersion) { moreHint := "get git: https://git-scm.com/download/" if runtime.GOOS == "linux" { // there are a lot of CentOS/RHEL users using old git, so we add a special hint for them - if _, err = os.Stat("/etc/redhat-release"); err == nil { + if _, err := os.Stat("/etc/redhat-release"); err == nil { // ius.io is the recommended official(git-scm.com) method to install git moreHint = "get git: https://git-scm.com/download/linux and https://ius.io" } } - return fmt.Errorf("installed git version %q is not supported, Gitea requires git version >= %q, %s", DefaultFeatures.GitVersion.Original(), RequiredVersion, moreHint) + return fmt.Errorf("installed git version %q is not supported, Gitea requires git version >= %q, %s", DefaultFeatures().gitVersion.Original(), RequiredVersion, moreHint) } - if err = checkGitVersionCompatibility(DefaultFeatures.GitVersion); err != nil { - return fmt.Errorf("installed git version %s has a known compatibility issue with Gitea: %w, please upgrade (or downgrade) git", DefaultFeatures.GitVersion.String(), err) - } - return nil -} - -// VersionInfo returns git version information -func VersionInfo() string { - if DefaultFeatures.GitVersion == nil { - return "(git not found)" - } - format := "%s" - args := []any{DefaultFeatures.GitVersion.Original()} - // Since git wire protocol has been released from git v2.18 - if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil { - format += ", Wire Protocol %s Enabled" - args = append(args, "Version 2") // for focus color - } - - return fmt.Sprintf(format, args...) -} - -func checkInit() error { - if setting.Git.HomePath == "" { - return errors.New("unable to init Git's HomeDir, incorrect initialization of the setting and git modules") - } - if DefaultContext != nil { - log.Warn("git module has been initialized already, duplicate init may work but it's better to fix it") + if err := checkGitVersionCompatibility(DefaultFeatures().gitVersion); err != nil { + return fmt.Errorf("installed git version %s has a known compatibility issue with Gitea: %w, please upgrade (or downgrade) git", DefaultFeatures().gitVersion.String(), err) } return nil } @@ -154,8 +143,12 @@ func HomeDir() string { // InitSimple initializes git module with a very simple step, no config changes, no global command arguments. // This method doesn't change anything to filesystem. At the moment, it is only used by some Gitea sub-commands. func InitSimple(ctx context.Context) error { - if err := checkInit(); err != nil { - return err + if setting.Git.HomePath == "" { + return errors.New("unable to init Git's HomeDir, incorrect initialization of the setting and git modules") + } + + if DefaultContext != nil && (!setting.IsProd || setting.IsInTesting) { + log.Warn("git module has been initialized already, duplicate init may work but it's better to fix it") } DefaultContext = ctx @@ -165,7 +158,24 @@ func InitSimple(ctx context.Context) error { defaultCommandExecutionTimeout = time.Duration(setting.Git.Timeout.Default) * time.Second } - return SetExecutablePath(setting.Git.Path) + if err := SetExecutablePath(setting.Git.Path); err != nil { + return err + } + + var err error + defaultFeatures, err = loadGitVersionFeatures() + if err != nil { + return err + } + if err = ensureGitVersion(); err != nil { + return err + } + + // when git works with gnupg (commit signing), there should be a stable home for gnupg commands + if _, ok := os.LookupEnv("GNUPGHOME"); !ok { + _ = os.Setenv("GNUPGHOME", filepath.Join(HomeDir(), ".gnupg")) + } + return nil } // InitFull initializes git module with version check and change global variables, sync gitconfig. @@ -175,30 +185,18 @@ func InitFull(ctx context.Context) (err error) { return err } - // when git works with gnupg (commit signing), there should be a stable home for gnupg commands - if _, ok := os.LookupEnv("GNUPGHOME"); !ok { - _ = os.Setenv("GNUPGHOME", filepath.Join(HomeDir(), ".gnupg")) - } - // Since git wire protocol has been released from git v2.18 - if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil { + if setting.Git.EnableAutoGitWireProtocol && DefaultFeatures().CheckVersionAtLeast("2.18") { globalCommandArgs = append(globalCommandArgs, "-c", "protocol.version=2") } // Explicitly disable credential helper, otherwise Git credentials might leak - if CheckGitVersionAtLeast("2.9") == nil { + if DefaultFeatures().CheckVersionAtLeast("2.9") { globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=") } - DefaultFeatures.SupportProcReceive = CheckGitVersionAtLeast("2.29") == nil - DefaultFeatures.SupportHashSha256 = CheckGitVersionAtLeast("2.42") == nil && !isGogit - if DefaultFeatures.SupportHashSha256 { - SupportedObjectFormats = append(SupportedObjectFormats, Sha256ObjectFormat) - } else { - log.Warn("sha256 hash support is disabled - requires Git >= 2.42. Gogit is currently unsupported") - } if setting.LFS.StartServer { - if CheckGitVersionAtLeast("2.1.2") != nil { + if !DefaultFeatures().CheckVersionAtLeast("2.1.2") { return errors.New("LFS server support requires Git >= 2.1.2") } globalCommandArgs = append(globalCommandArgs, "-c", "filter.lfs.required=", "-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=") @@ -238,13 +236,13 @@ func syncGitConfig() (err error) { return err } - if CheckGitVersionAtLeast("2.10") == nil { + if DefaultFeatures().CheckVersionAtLeast("2.10") { if err := configSet("receive.advertisePushOptions", "true"); err != nil { return err } } - if CheckGitVersionAtLeast("2.18") == nil { + if DefaultFeatures().CheckVersionAtLeast("2.18") { if err := configSet("core.commitGraph", "true"); err != nil { return err } @@ -256,7 +254,7 @@ func syncGitConfig() (err error) { } } - if DefaultFeatures.SupportProcReceive { + if DefaultFeatures().SupportProcReceive { // set support for AGit flow if err := configAddNonExist("receive.procReceiveRefs", "refs/for"); err != nil { return err @@ -294,7 +292,7 @@ func syncGitConfig() (err error) { } // By default partial clones are disabled, enable them from git v2.22 - if !setting.Git.DisablePartialClone && CheckGitVersionAtLeast("2.22") == nil { + if !setting.Git.DisablePartialClone && DefaultFeatures().CheckVersionAtLeast("2.22") { if err = configSet("uploadpack.allowfilter", "true"); err != nil { return err } @@ -309,21 +307,6 @@ func syncGitConfig() (err error) { return err } -// CheckGitVersionAtLeast check git version is at least the constraint version -func CheckGitVersionAtLeast(atLeast string) error { - if DefaultFeatures.GitVersion == nil { - panic("git module is not initialized") // it shouldn't happen - } - atLeastVersion, err := version.NewVersion(atLeast) - if err != nil { - return err - } - if DefaultFeatures.GitVersion.Compare(atLeastVersion) < 0 { - return fmt.Errorf("installed git binary version %s is not at least %s", DefaultFeatures.GitVersion.Original(), atLeast) - } - return nil -} - func checkGitVersionCompatibility(gitVer *version.Version) error { badVersions := []struct { Version *version.Version diff --git a/modules/git/object_format.go b/modules/git/object_format.go index 3de9ff8cf4..242d782e17 100644 --- a/modules/git/object_format.go +++ b/modules/git/object_format.go @@ -120,12 +120,8 @@ var ( Sha256ObjectFormat ObjectFormat = Sha256ObjectFormatImpl{} ) -var SupportedObjectFormats = []ObjectFormat{ - Sha1ObjectFormat, -} - func ObjectFormatFromName(name string) ObjectFormat { - for _, objectFormat := range SupportedObjectFormats { + for _, objectFormat := range DefaultFeatures().SupportedObjectFormats { if name == objectFormat.Name() { return objectFormat } diff --git a/modules/git/object_id.go b/modules/git/object_id.go index 33e5085005..82d30184df 100644 --- a/modules/git/object_id.go +++ b/modules/git/object_id.go @@ -54,7 +54,7 @@ func (*Sha256Hash) Type() ObjectFormat { return Sha256ObjectFormat } func NewIDFromString(hexHash string) (ObjectID, error) { var theObjectFormat ObjectFormat - for _, objectFormat := range SupportedObjectFormats { + for _, objectFormat := range DefaultFeatures().SupportedObjectFormats { if len(hexHash) == objectFormat.FullLength() { theObjectFormat = objectFormat break diff --git a/modules/git/remote.go b/modules/git/remote.go index 3585313f6a..7b10e6b663 100644 --- a/modules/git/remote.go +++ b/modules/git/remote.go @@ -12,7 +12,7 @@ import ( // GetRemoteAddress returns remote url of git repository in the repoPath with special remote name func GetRemoteAddress(ctx context.Context, repoPath, remoteName string) (string, error) { var cmd *Command - if CheckGitVersionAtLeast("2.7") == nil { + if DefaultFeatures().CheckVersionAtLeast("2.7") { cmd = NewCommand(ctx, "remote", "get-url").AddDynamicArguments(remoteName) } else { cmd = NewCommand(ctx, "config", "--get").AddDynamicArguments("remote." + remoteName + ".url") diff --git a/modules/git/repo.go b/modules/git/repo.go index 4511e900e0..d4e1669bec 100644 --- a/modules/git/repo.go +++ b/modules/git/repo.go @@ -101,7 +101,7 @@ func InitRepository(ctx context.Context, repoPath string, bare bool, objectForma if !IsValidObjectFormat(objectFormatName) { return fmt.Errorf("invalid object format: %s", objectFormatName) } - if DefaultFeatures.SupportHashSha256 { + if DefaultFeatures().SupportHashSha256 { cmd.AddOptionValues("--object-format", objectFormatName) } diff --git a/modules/git/repo_base.go b/modules/git/repo_base.go deleted file mode 100644 index 6c148d9af5..0000000000 --- a/modules/git/repo_base.go +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright 2021 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package git - -var isGogit bool diff --git a/modules/git/repo_base_gogit.go b/modules/git/repo_base_gogit.go index 0cd07dcdc8..a1127f4e6c 100644 --- a/modules/git/repo_base_gogit.go +++ b/modules/git/repo_base_gogit.go @@ -22,9 +22,7 @@ import ( "github.com/go-git/go-git/v5/storage/filesystem" ) -func init() { - isGogit = true -} +const isGogit = true // Repository represents a Git repository. type Repository struct { diff --git a/modules/git/repo_base_nogogit.go b/modules/git/repo_base_nogogit.go index 5511526e78..bc241cdd79 100644 --- a/modules/git/repo_base_nogogit.go +++ b/modules/git/repo_base_nogogit.go @@ -15,9 +15,7 @@ import ( "code.gitea.io/gitea/modules/util" ) -func init() { - isGogit = false -} +const isGogit = false // Repository represents a Git repository. type Repository struct { diff --git a/modules/git/repo_commit.go b/modules/git/repo_commit.go index f9168bef7e..8c3285769e 100644 --- a/modules/git/repo_commit.go +++ b/modules/git/repo_commit.go @@ -438,7 +438,7 @@ func (repo *Repository) getCommitsBeforeLimit(id ObjectID, num int) ([]*Commit, } func (repo *Repository) getBranches(commit *Commit, limit int) ([]string, error) { - if CheckGitVersionAtLeast("2.7.0") == nil { + if DefaultFeatures().CheckVersionAtLeast("2.7.0") { stdout, _, err := NewCommand(repo.Ctx, "for-each-ref", "--format=%(refname:strip=2)"). AddOptionFormat("--count=%d", limit). AddOptionValues("--contains", commit.ID.String(), BranchPrefix). diff --git a/modules/git/repo_commitgraph.go b/modules/git/repo_commitgraph.go index 492438be37..087d5bcec4 100644 --- a/modules/git/repo_commitgraph.go +++ b/modules/git/repo_commitgraph.go @@ -11,7 +11,7 @@ import ( // WriteCommitGraph write commit graph to speed up repo access // this requires git v2.18 to be installed func WriteCommitGraph(ctx context.Context, repoPath string) error { - if CheckGitVersionAtLeast("2.18") == nil { + if DefaultFeatures().CheckVersionAtLeast("2.18") { if _, _, err := NewCommand(ctx, "commit-graph", "write").RunStdString(&RunOpts{Dir: repoPath}); err != nil { return fmt.Errorf("unable to write commit-graph for '%s' : %w", repoPath, err) } diff --git a/modules/lfs/pointer_scanner_nogogit.go b/modules/lfs/pointer_scanner_nogogit.go index 658b98feab..c37a93e73b 100644 --- a/modules/lfs/pointer_scanner_nogogit.go +++ b/modules/lfs/pointer_scanner_nogogit.go @@ -41,7 +41,7 @@ func SearchPointerBlobs(ctx context.Context, repo *git.Repository, pointerChan c go pipeline.BlobsLessThan1024FromCatFileBatchCheck(catFileCheckReader, shasToBatchWriter, &wg) // 1. Run batch-check on all objects in the repository - if git.CheckGitVersionAtLeast("2.6.0") != nil { + if !git.DefaultFeatures().CheckVersionAtLeast("2.6.0") { revListReader, revListWriter := io.Pipe() shasToCheckReader, shasToCheckWriter := io.Pipe() wg.Add(2) diff --git a/routers/init.go b/routers/init.go index 030ef3c740..56c95cd1ca 100644 --- a/routers/init.go +++ b/routers/init.go @@ -25,6 +25,7 @@ import ( "code.gitea.io/gitea/modules/system" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/translation" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web/routing" actions_router "code.gitea.io/gitea/routers/api/actions" @@ -112,7 +113,10 @@ func InitWebInstallPage(ctx context.Context) { // InitWebInstalled is for global installed configuration. func InitWebInstalled(ctx context.Context) { mustInitCtx(ctx, git.InitFull) - log.Info("Git version: %s (home: %s)", git.VersionInfo(), git.HomeDir()) + log.Info("Git version: %s (home: %s)", git.DefaultFeatures().VersionInfo(), git.HomeDir()) + if !git.DefaultFeatures().SupportHashSha256 { + log.Warn("sha256 hash support is disabled - requires Git >= 2.42." + util.Iif(git.DefaultFeatures().UsingGogit, " Gogit is currently unsupported.", "")) + } // Setup i18n translation.InitLocales(ctx) diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go index 7189fd715c..0a3c8e2559 100644 --- a/routers/private/hook_pre_receive.go +++ b/routers/private/hook_pre_receive.go @@ -122,7 +122,7 @@ func HookPreReceive(ctx *gitea_context.PrivateContext) { preReceiveBranch(ourCtx, oldCommitID, newCommitID, refFullName) case refFullName.IsTag(): preReceiveTag(ourCtx, refFullName) - case git.DefaultFeatures.SupportProcReceive && refFullName.IsFor(): + case git.DefaultFeatures().SupportProcReceive && refFullName.IsFor(): preReceiveFor(ourCtx, refFullName) default: ourCtx.AssertCanWriteCode() diff --git a/routers/private/hook_proc_receive.go b/routers/private/hook_proc_receive.go index cee3bbdd12..efb3f5831e 100644 --- a/routers/private/hook_proc_receive.go +++ b/routers/private/hook_proc_receive.go @@ -18,7 +18,7 @@ import ( // HookProcReceive proc-receive hook - only handles agit Proc-Receive requests at present func HookProcReceive(ctx *gitea_context.PrivateContext) { opts := web.GetForm(ctx).(*private.HookOptions) - if !git.DefaultFeatures.SupportProcReceive { + if !git.DefaultFeatures().SupportProcReceive { ctx.Status(http.StatusNotFound) return } diff --git a/routers/private/serv.go b/routers/private/serv.go index 85368a0aed..1c309865d7 100644 --- a/routers/private/serv.go +++ b/routers/private/serv.go @@ -297,7 +297,7 @@ func ServCommand(ctx *context.PrivateContext) { } } else { // Because of the special ref "refs/for" we will need to delay write permission check - if git.DefaultFeatures.SupportProcReceive && unitType == unit.TypeCode { + if git.DefaultFeatures().SupportProcReceive && unitType == unit.TypeCode { mode = perm.AccessModeRead } diff --git a/routers/web/admin/config.go b/routers/web/admin/config.go index 48f80dbbf1..fd8c73b62d 100644 --- a/routers/web/admin/config.go +++ b/routers/web/admin/config.go @@ -112,7 +112,7 @@ func Config(ctx *context.Context) { ctx.Data["OfflineMode"] = setting.OfflineMode ctx.Data["RunUser"] = setting.RunUser ctx.Data["RunMode"] = util.ToTitleCase(setting.RunMode) - ctx.Data["GitVersion"] = git.VersionInfo() + ctx.Data["GitVersion"] = git.DefaultFeatures().VersionInfo() ctx.Data["AppDataPath"] = setting.AppDataPath ctx.Data["RepoRootPath"] = setting.RepoRootPath diff --git a/routers/web/misc/misc.go b/routers/web/misc/misc.go index ac5496ce91..caaca7f521 100644 --- a/routers/web/misc/misc.go +++ b/routers/web/misc/misc.go @@ -15,7 +15,7 @@ import ( ) func SSHInfo(rw http.ResponseWriter, req *http.Request) { - if !git.DefaultFeatures.SupportProcReceive { + if !git.DefaultFeatures().SupportProcReceive { rw.WriteHeader(http.StatusNotFound) return } diff --git a/routers/web/repo/githttp.go b/routers/web/repo/githttp.go index 8fb6d93068..f0579b56ea 100644 --- a/routers/web/repo/githttp.go +++ b/routers/web/repo/githttp.go @@ -183,7 +183,7 @@ func httpBase(ctx *context.Context) *serviceHandler { if repoExist { // Because of special ref "refs/for" .. , need delay write permission check - if git.DefaultFeatures.SupportProcReceive { + if git.DefaultFeatures().SupportProcReceive { accessMode = perm.AccessModeRead } diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index 4e448933c7..48be1c2296 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -180,7 +180,7 @@ func Create(ctx *context.Context) { ctx.Data["CanCreateRepo"] = ctx.Doer.CanCreateRepo() ctx.Data["MaxCreationLimit"] = ctx.Doer.MaxCreationLimit() - ctx.Data["SupportedObjectFormats"] = git.SupportedObjectFormats + ctx.Data["SupportedObjectFormats"] = git.DefaultFeatures().SupportedObjectFormats ctx.Data["DefaultObjectFormat"] = git.Sha1ObjectFormat ctx.HTML(http.StatusOK, tplCreate) diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index d115686491..3a35d24dff 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -1143,7 +1143,7 @@ func GetDiff(ctx context.Context, gitRepo *git.Repository, opts *DiffOptions, fi // so if we are using at least this version of git we don't have to tell ParsePatch to do // the skipping for us parsePatchSkipToFile := opts.SkipTo - if opts.SkipTo != "" && git.CheckGitVersionAtLeast("2.31") == nil { + if opts.SkipTo != "" && git.DefaultFeatures().CheckVersionAtLeast("2.31") { cmdDiff.AddOptionFormat("--skip-to=%s", opts.SkipTo) parsePatchSkipToFile = "" } diff --git a/services/pull/patch.go b/services/pull/patch.go index 12b79a0625..981bc989fc 100644 --- a/services/pull/patch.go +++ b/services/pull/patch.go @@ -383,7 +383,7 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo * cmdApply.AddArguments("--ignore-whitespace") } is3way := false - if git.CheckGitVersionAtLeast("2.32.0") == nil { + if git.DefaultFeatures().CheckVersionAtLeast("2.32.0") { cmdApply.AddArguments("--3way") is3way = true } diff --git a/services/pull/temp_repo.go b/services/pull/temp_repo.go index 36bdbde55c..e5753178b8 100644 --- a/services/pull/temp_repo.go +++ b/services/pull/temp_repo.go @@ -104,7 +104,7 @@ func createTemporaryRepoForPR(ctx context.Context, pr *issues_model.PullRequest) baseBranch := "base" fetchArgs := git.TrustedCmdArgs{"--no-tags"} - if git.CheckGitVersionAtLeast("2.25.0") == nil { + if git.DefaultFeatures().CheckVersionAtLeast("2.25.0") { // Writing the commit graph can be slow and is not needed here fetchArgs = append(fetchArgs, "--no-write-commit-graph") } diff --git a/services/repository/files/patch.go b/services/repository/files/patch.go index e5f7e2af96..ab0e7ffd36 100644 --- a/services/repository/files/patch.go +++ b/services/repository/files/patch.go @@ -148,7 +148,7 @@ func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user stderr := &strings.Builder{} cmdApply := git.NewCommand(ctx, "apply", "--index", "--recount", "--cached", "--ignore-whitespace", "--whitespace=fix", "--binary") - if git.CheckGitVersionAtLeast("2.32") == nil { + if git.DefaultFeatures().CheckVersionAtLeast("2.32") { cmdApply.AddArguments("-3") } diff --git a/tests/integration/git_test.go b/tests/integration/git_test.go index 8a091ecab7..993a3d6799 100644 --- a/tests/integration/git_test.go +++ b/tests/integration/git_test.go @@ -695,7 +695,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, headBranch string defer tests.PrintCurrentTest(t)() // skip this test if git version is low - if git.CheckGitVersionAtLeast("2.29") != nil { + if !git.DefaultFeatures().SupportProcReceive { return } From 9c08637eae8c3a44d15e62d85144e07ae9dabbec Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Tue, 7 May 2024 01:02:30 +0800 Subject: [PATCH 283/370] Make "sync branch" also sync object format and add tests (#30878) --- modules/git/repo.go | 27 --------------------------- modules/repository/branch.go | 10 ++++++++++ modules/repository/branch_test.go | 31 +++++++++++++++++++++++++++++++ services/repository/adopt.go | 4 ++++ 4 files changed, 45 insertions(+), 27 deletions(-) create mode 100644 modules/repository/branch_test.go diff --git a/modules/git/repo.go b/modules/git/repo.go index d4e1669bec..1c223018ad 100644 --- a/modules/git/repo.go +++ b/modules/git/repo.go @@ -7,7 +7,6 @@ package git import ( "bytes" "context" - "errors" "fmt" "io" "net/url" @@ -63,32 +62,6 @@ func IsRepoURLAccessible(ctx context.Context, url string) bool { return err == nil } -// GetObjectFormatOfRepo returns the hash type of repository at a given path -func GetObjectFormatOfRepo(ctx context.Context, repoPath string) (ObjectFormat, error) { - var stdout, stderr strings.Builder - - err := NewCommand(ctx, "hash-object", "--stdin").Run(&RunOpts{ - Dir: repoPath, - Stdout: &stdout, - Stderr: &stderr, - Stdin: &strings.Reader{}, - }) - if err != nil { - return nil, err - } - - if stderr.Len() > 0 { - return nil, errors.New(stderr.String()) - } - - h, err := NewIDFromString(strings.TrimRight(stdout.String(), "\n")) - if err != nil { - return nil, err - } - - return h.Type(), nil -} - // InitRepository initializes a new Git repository. func InitRepository(ctx context.Context, repoPath string, bare bool, objectFormatName string) error { err := os.MkdirAll(repoPath, os.ModePerm) diff --git a/modules/repository/branch.go b/modules/repository/branch.go index e448490f4a..a3fca7c7ce 100644 --- a/modules/repository/branch.go +++ b/modules/repository/branch.go @@ -5,6 +5,7 @@ package repository import ( "context" + "fmt" "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" @@ -36,6 +37,15 @@ func SyncRepoBranches(ctx context.Context, repoID, doerID int64) (int64, error) } func SyncRepoBranchesWithRepo(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, doerID int64) (int64, error) { + objFmt, err := gitRepo.GetObjectFormat() + if err != nil { + return 0, fmt.Errorf("GetObjectFormat: %w", err) + } + _, err = db.GetEngine(ctx).ID(repo.ID).Update(&repo_model.Repository{ObjectFormatName: objFmt.Name()}) + if err != nil { + return 0, fmt.Errorf("UpdateRepository: %w", err) + } + allBranches := container.Set[string]{} { branches, _, err := gitRepo.GetBranchNames(0, 0) diff --git a/modules/repository/branch_test.go b/modules/repository/branch_test.go new file mode 100644 index 0000000000..acf75a1ac0 --- /dev/null +++ b/modules/repository/branch_test.go @@ -0,0 +1,31 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repository + +import ( + "testing" + + "code.gitea.io/gitea/models/db" + git_model "code.gitea.io/gitea/models/git" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" + + "github.com/stretchr/testify/assert" +) + +func TestSyncRepoBranches(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + _, err := db.GetEngine(db.DefaultContext).ID(1).Update(&repo_model.Repository{ObjectFormatName: "bad-fmt"}) + assert.NoError(t, db.TruncateBeans(db.DefaultContext, &git_model.Branch{})) + assert.NoError(t, err) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + assert.Equal(t, "bad-fmt", repo.ObjectFormatName) + _, err = SyncRepoBranches(db.DefaultContext, 1, 0) + assert.NoError(t, err) + repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + assert.Equal(t, "sha1", repo.ObjectFormatName) + branch, err := git_model.GetBranch(db.DefaultContext, 1, "master") + assert.NoError(t, err) + assert.EqualValues(t, "master", branch.Name) +} diff --git a/services/repository/adopt.go b/services/repository/adopt.go index 914cd9047b..f4d0da67a5 100644 --- a/services/repository/adopt.go +++ b/services/repository/adopt.go @@ -195,6 +195,10 @@ func adoptRepository(ctx context.Context, repoPath string, repo *repo_model.Repo } defer gitRepo.Close() + if _, err = repo_module.SyncRepoBranchesWithRepo(ctx, repo, gitRepo, 0); err != nil { + return fmt.Errorf("SyncRepoBranches: %w", err) + } + if err = repo_module.SyncReleasesWithTags(ctx, repo, gitRepo); err != nil { return fmt.Errorf("SyncReleasesWithTags: %w", err) } From 6ad77125cabe53a943d46b50e8cb79cfcea5491f Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Tue, 7 May 2024 14:45:30 +0800 Subject: [PATCH 284/370] Fix missing migrate actions artifacts (#30874) The actions artifacts should be able to be migrate to the new storage place. --- cmd/migrate_storage.go | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/cmd/migrate_storage.go b/cmd/migrate_storage.go index aa49445a89..357416fc33 100644 --- a/cmd/migrate_storage.go +++ b/cmd/migrate_storage.go @@ -34,7 +34,7 @@ var CmdMigrateStorage = &cli.Command{ Name: "type", Aliases: []string{"t"}, Value: "", - Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages', 'actions-log'", + Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages', 'actions-log', 'actions-artifacts", }, &cli.StringFlag{ Name: "storage", @@ -160,6 +160,13 @@ func migrateActionsLog(ctx context.Context, dstStorage storage.ObjectStorage) er }) } +func migrateActionsArtifacts(ctx context.Context, dstStorage storage.ObjectStorage) error { + return db.Iterate(ctx, nil, func(ctx context.Context, artifact *actions_model.ActionArtifact) error { + _, err := storage.Copy(dstStorage, artifact.ArtifactPath, storage.ActionsArtifacts, artifact.ArtifactPath) + return err + }) +} + func runMigrateStorage(ctx *cli.Context) error { stdCtx, cancel := installSignals() defer cancel() @@ -223,13 +230,14 @@ func runMigrateStorage(ctx *cli.Context) error { } migratedMethods := map[string]func(context.Context, storage.ObjectStorage) error{ - "attachments": migrateAttachments, - "lfs": migrateLFS, - "avatars": migrateAvatars, - "repo-avatars": migrateRepoAvatars, - "repo-archivers": migrateRepoArchivers, - "packages": migratePackages, - "actions-log": migrateActionsLog, + "attachments": migrateAttachments, + "lfs": migrateLFS, + "avatars": migrateAvatars, + "repo-avatars": migrateRepoAvatars, + "repo-archivers": migrateRepoArchivers, + "packages": migratePackages, + "actions-log": migrateActionsLog, + "actions-artifacts": migrateActionsArtifacts, } tp := strings.ToLower(ctx.String("type")) From ebf0c969403d91ed80745ff5bd7dfbdb08174fc7 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Tue, 7 May 2024 15:36:48 +0800 Subject: [PATCH 285/370] Move database operations of merging a pull request to post receive hook and add a transaction (#30805) Merging PR may fail because of various problems. The pull request may have a dirty state because there is no transaction when merging a pull request. ref https://github.com/go-gitea/gitea/pull/25741#issuecomment-2074126393 This PR moves all database update operations to post-receive handler for merging a pull request and having a database transaction. That means if database operations fail, then the git merging will fail, the git client will get a fail result. There are already many tests for pull request merging, so we don't need to add a new one. --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> --- cmd/hook.go | 3 ++ modules/private/hook.go | 2 + modules/repository/env.go | 8 +++ routers/private/hook_post_receive.go | 64 ++++++++++++++++++++++- routers/private/hook_post_receive_test.go | 49 +++++++++++++++++ services/contexttest/context_tests.go | 13 +++++ services/pull/merge.go | 27 ++++------ services/pull/update.go | 3 +- 8 files changed, 150 insertions(+), 19 deletions(-) create mode 100644 routers/private/hook_post_receive_test.go diff --git a/cmd/hook.go b/cmd/hook.go index 9c1cb66f2a..6e31710caf 100644 --- a/cmd/hook.go +++ b/cmd/hook.go @@ -338,6 +338,7 @@ Gitea or set your environment appropriately.`, "") isWiki, _ := strconv.ParseBool(os.Getenv(repo_module.EnvRepoIsWiki)) repoName := os.Getenv(repo_module.EnvRepoName) pusherID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPusherID), 10, 64) + prID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPRID), 10, 64) pusherName := os.Getenv(repo_module.EnvPusherName) hookOptions := private.HookOptions{ @@ -347,6 +348,8 @@ Gitea or set your environment appropriately.`, "") GitObjectDirectory: os.Getenv(private.GitObjectDirectory), GitQuarantinePath: os.Getenv(private.GitQuarantinePath), GitPushOptions: pushOptions(), + PullRequestID: prID, + PushTrigger: repo_module.PushTrigger(os.Getenv(repo_module.EnvPushTrigger)), } oldCommitIDs := make([]string, hookBatchSize) newCommitIDs := make([]string, hookBatchSize) diff --git a/modules/private/hook.go b/modules/private/hook.go index 79c3d48229..49d9298744 100644 --- a/modules/private/hook.go +++ b/modules/private/hook.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/optional" + "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" ) @@ -54,6 +55,7 @@ type HookOptions struct { GitQuarantinePath string GitPushOptions GitPushOptions PullRequestID int64 + PushTrigger repository.PushTrigger DeployKeyID int64 // if the pusher is a DeployKey, then UserID is the repo's org user. IsWiki bool ActionPerm int diff --git a/modules/repository/env.go b/modules/repository/env.go index 30edd1c9e3..e4f32092fc 100644 --- a/modules/repository/env.go +++ b/modules/repository/env.go @@ -25,11 +25,19 @@ const ( EnvKeyID = "GITEA_KEY_ID" // public key ID EnvDeployKeyID = "GITEA_DEPLOY_KEY_ID" EnvPRID = "GITEA_PR_ID" + EnvPushTrigger = "GITEA_PUSH_TRIGGER" EnvIsInternal = "GITEA_INTERNAL_PUSH" EnvAppURL = "GITEA_ROOT_URL" EnvActionPerm = "GITEA_ACTION_PERM" ) +type PushTrigger string + +const ( + PushTriggerPRMergeToBase PushTrigger = "pr-merge-to-base" + PushTriggerPRUpdateWithBase PushTrigger = "pr-update-with-base" +) + // InternalPushingEnvironment returns an os environment to switch off hooks on push // It is recommended to avoid using this unless you are pushing within a transaction // or if you absolutely are sure that post-receive and pre-receive will do nothing diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index adc435b42c..0c2c1836ed 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -4,20 +4,25 @@ package private import ( + "context" "fmt" "net/http" + "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" access_model "code.gitea.io/gitea/models/perm/access" + pull_model "code.gitea.io/gitea/models/pull" repo_model "code.gitea.io/gitea/models/repo" 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/gitrepo" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/private" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" + timeutil "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" gitea_context "code.gitea.io/gitea/services/context" @@ -158,6 +163,14 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { } } + // handle pull request merging, a pull request action should push at least 1 commit + if opts.PushTrigger == repo_module.PushTriggerPRMergeToBase { + handlePullRequestMerging(ctx, opts, ownerName, repoName, updates) + if ctx.Written() { + return + } + } + isPrivate := opts.GitPushOptions.Bool(private.GitPushOptionRepoPrivate) isTemplate := opts.GitPushOptions.Bool(private.GitPushOptionRepoTemplate) // Handle Push Options @@ -172,7 +185,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { wasEmpty = repo.IsEmpty } - pusher, err := user_model.GetUserByID(ctx, opts.UserID) + pusher, err := loadContextCacheUser(ctx, opts.UserID) if err != nil { log.Error("Failed to Update: %s/%s Error: %v", ownerName, repoName, err) ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{ @@ -307,3 +320,52 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { RepoWasEmpty: wasEmpty, }) } + +func loadContextCacheUser(ctx context.Context, id int64) (*user_model.User, error) { + return cache.GetWithContextCache(ctx, "hook_post_receive_user", id, func() (*user_model.User, error) { + return user_model.GetUserByID(ctx, id) + }) +} + +// handlePullRequestMerging handle pull request merging, a pull request action should push at least 1 commit +func handlePullRequestMerging(ctx *gitea_context.PrivateContext, opts *private.HookOptions, ownerName, repoName string, updates []*repo_module.PushUpdateOptions) { + if len(updates) == 0 { + ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{ + Err: fmt.Sprintf("Pushing a merged PR (pr:%d) no commits pushed ", opts.PullRequestID), + }) + return + } + + pr, err := issues_model.GetPullRequestByID(ctx, opts.PullRequestID) + if err != nil { + log.Error("GetPullRequestByID[%d]: %v", opts.PullRequestID, err) + ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{Err: "GetPullRequestByID failed"}) + return + } + + pusher, err := loadContextCacheUser(ctx, opts.UserID) + if err != nil { + log.Error("Failed to Update: %s/%s Error: %v", ownerName, repoName, err) + ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{Err: "Load pusher user failed"}) + return + } + + pr.MergedCommitID = updates[len(updates)-1].NewCommitID + pr.MergedUnix = timeutil.TimeStampNow() + pr.Merger = pusher + pr.MergerID = pusher.ID + err = db.WithTx(ctx, func(ctx context.Context) error { + // Removing an auto merge pull and ignore if not exist + if err := pull_model.DeleteScheduledAutoMerge(ctx, pr.ID); err != nil && !db.IsErrNotExist(err) { + return fmt.Errorf("DeleteScheduledAutoMerge[%d]: %v", opts.PullRequestID, err) + } + if _, err := pr.SetMerged(ctx); err != nil { + return fmt.Errorf("SetMerged failed: %s/%s Error: %v", ownerName, repoName, err) + } + return nil + }) + if err != nil { + log.Error("Failed to update PR to merged: %v", err) + ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{Err: "Failed to update PR to merged"}) + } +} diff --git a/routers/private/hook_post_receive_test.go b/routers/private/hook_post_receive_test.go new file mode 100644 index 0000000000..658557d3cf --- /dev/null +++ b/routers/private/hook_post_receive_test.go @@ -0,0 +1,49 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package private + +import ( + "testing" + + "code.gitea.io/gitea/models/db" + issues_model "code.gitea.io/gitea/models/issues" + pull_model "code.gitea.io/gitea/models/pull" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/private" + repo_module "code.gitea.io/gitea/modules/repository" + "code.gitea.io/gitea/services/contexttest" + + "github.com/stretchr/testify/assert" +) + +func TestHandlePullRequestMerging(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + pr, err := issues_model.GetUnmergedPullRequest(db.DefaultContext, 1, 1, "branch2", "master", issues_model.PullRequestFlowGithub) + assert.NoError(t, err) + assert.NoError(t, pr.LoadBaseRepo(db.DefaultContext)) + + user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) + + err = pull_model.ScheduleAutoMerge(db.DefaultContext, user1, pr.ID, repo_model.MergeStyleSquash, "squash merge a pr") + assert.NoError(t, err) + + autoMerge := unittest.AssertExistsAndLoadBean(t, &pull_model.AutoMerge{PullID: pr.ID}) + + ctx, resp := contexttest.MockPrivateContext(t, "/") + handlePullRequestMerging(ctx, &private.HookOptions{ + PullRequestID: pr.ID, + UserID: 2, + }, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, []*repo_module.PushUpdateOptions{ + {NewCommitID: "01234567"}, + }) + assert.Equal(t, 0, len(resp.Body.String())) + pr, err = issues_model.GetPullRequestByID(db.DefaultContext, pr.ID) + assert.NoError(t, err) + assert.True(t, pr.HasMerged) + assert.EqualValues(t, "01234567", pr.MergedCommitID) + + unittest.AssertNotExistsBean(t, &pull_model.AutoMerge{ID: autoMerge.ID}) +} diff --git a/services/contexttest/context_tests.go b/services/contexttest/context_tests.go index 0c1e5ee54f..5624d24058 100644 --- a/services/contexttest/context_tests.go +++ b/services/contexttest/context_tests.go @@ -94,6 +94,19 @@ func MockAPIContext(t *testing.T, reqPath string) (*context.APIContext, *httptes return ctx, resp } +func MockPrivateContext(t *testing.T, reqPath string) (*context.PrivateContext, *httptest.ResponseRecorder) { + resp := httptest.NewRecorder() + req := mockRequest(t, reqPath) + base, baseCleanUp := context.NewBaseContext(resp, req) + base.Data = middleware.GetContextData(req.Context()) + base.Locale = &translation.MockLocale{} + ctx := &context.PrivateContext{Base: base} + _ = baseCleanUp // during test, it doesn't need to do clean up. TODO: this can be improved later + chiCtx := chi.NewRouteContext() + ctx.Base.AppendContextValue(chi.RouteCtxKey, chiCtx) + return ctx, resp +} + // LoadRepo load a repo into a test context. func LoadRepo(t *testing.T, ctx gocontext.Context, repoID int64) { var doer *user_model.User diff --git a/services/pull/merge.go b/services/pull/merge.go index 00f23e1e3a..20be7c5b5a 100644 --- a/services/pull/merge.go +++ b/services/pull/merge.go @@ -18,7 +18,6 @@ import ( git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" access_model "code.gitea.io/gitea/models/perm/access" - pull_model "code.gitea.io/gitea/models/pull" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" @@ -162,12 +161,6 @@ func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.U pullWorkingPool.CheckIn(fmt.Sprint(pr.ID)) defer pullWorkingPool.CheckOut(fmt.Sprint(pr.ID)) - // Removing an auto merge pull and ignore if not exist - // FIXME: is this the correct point to do this? Shouldn't this be after IsMergeStyleAllowed? - if err := pull_model.DeleteScheduledAutoMerge(ctx, pr.ID); err != nil && !db.IsErrNotExist(err) { - return err - } - prUnit, err := pr.BaseRepo.GetUnit(ctx, unit.TypePullRequests) if err != nil { log.Error("pr.BaseRepo.GetUnit(unit.TypePullRequests): %v", err) @@ -184,17 +177,15 @@ func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.U go AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false, "", "") }() - pr.MergedCommitID, err = doMergeAndPush(ctx, pr, doer, mergeStyle, expectedHeadCommitID, message) + _, err = doMergeAndPush(ctx, pr, doer, mergeStyle, expectedHeadCommitID, message, repo_module.PushTriggerPRMergeToBase) if err != nil { return err } - pr.MergedUnix = timeutil.TimeStampNow() - pr.Merger = doer - pr.MergerID = doer.ID - - if _, err := pr.SetMerged(ctx); err != nil { - log.Error("SetMerged %-v: %v", pr, err) + // reload pull request because it has been updated by post receive hook + pr, err = issues_model.GetPullRequestByID(ctx, pr.ID) + if err != nil { + return err } if err := pr.LoadIssue(ctx); err != nil { @@ -245,7 +236,7 @@ func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.U } // doMergeAndPush performs the merge operation without changing any pull information in database and pushes it up to the base repository -func doMergeAndPush(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User, mergeStyle repo_model.MergeStyle, expectedHeadCommitID, message string) (string, error) { +func doMergeAndPush(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User, mergeStyle repo_model.MergeStyle, expectedHeadCommitID, message string, pushTrigger repo_module.PushTrigger) (string, error) { // Clone base repo. mergeCtx, cancel, err := createTemporaryRepoForMerge(ctx, pr, doer, expectedHeadCommitID) if err != nil { @@ -318,11 +309,13 @@ func doMergeAndPush(ctx context.Context, pr *issues_model.PullRequest, doer *use pr.BaseRepo.Name, pr.ID, ) + + mergeCtx.env = append(mergeCtx.env, repo_module.EnvPushTrigger+"="+string(pushTrigger)) pushCmd := git.NewCommand(ctx, "push", "origin").AddDynamicArguments(baseBranch + ":" + git.BranchPrefix + pr.BaseBranch) // Push back to upstream. - // TODO: this cause an api call to "/api/internal/hook/post-receive/...", - // that prevents us from doint the whole merge in one db transaction + // This cause an api call to "/api/internal/hook/post-receive/...", + // If it's merge, all db transaction and operations should be there but not here to prevent deadlock. if err := pushCmd.Run(mergeCtx.RunOpts()); err != nil { if strings.Contains(mergeCtx.errbuf.String(), "non-fast-forward") { return "", &git.ErrPushOutOfDate{ diff --git a/services/pull/update.go b/services/pull/update.go index 9b676e13ef..d2c0c2df80 100644 --- a/services/pull/update.go +++ b/services/pull/update.go @@ -15,6 +15,7 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/repository" ) // Update updates pull request with base branch. @@ -72,7 +73,7 @@ func Update(ctx context.Context, pr *issues_model.PullRequest, doer *user_model. BaseBranch: pr.HeadBranch, } - _, err = doMergeAndPush(ctx, reversePR, doer, repo_model.MergeStyleMerge, "", message) + _, err = doMergeAndPush(ctx, reversePR, doer, repo_model.MergeStyleMerge, "", message, repository.PushTriggerPRUpdateWithBase) defer func() { go AddTestPullRequestTask(doer, reversePR.HeadRepo.ID, reversePR.HeadBranch, false, "", "") From 67c1a07285008cc00036a87cef966c3bd519a50c Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Tue, 7 May 2024 16:26:13 +0800 Subject: [PATCH 286/370] Refactor AppURL usage (#30885) Fix #30883 Fix #29591 --------- Co-authored-by: KN4CK3R <admin@oldschoolhack.me> --- models/repo/avatar.go | 12 ++--- models/user/avatar.go | 10 ++-- modules/httplib/url.go | 60 ++++++++++++++++++++- modules/httplib/url_test.go | 59 +++++++++++++++++--- modules/markup/html_codepreview.go | 2 +- routers/api/actions/artifacts.go | 11 ++-- routers/api/actions/artifactsv4.go | 9 ++-- routers/api/packages/container/container.go | 3 +- routers/common/middleware.go | 3 ++ routers/common/redirect.go | 2 +- routers/web/auth/auth.go | 2 +- services/context/base.go | 2 +- services/context/context_response.go | 2 +- 13 files changed, 138 insertions(+), 39 deletions(-) diff --git a/models/repo/avatar.go b/models/repo/avatar.go index 72ee938ada..8395b8c2b7 100644 --- a/models/repo/avatar.go +++ b/models/repo/avatar.go @@ -9,10 +9,10 @@ import ( "image/png" "io" "net/url" - "strings" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/avatar" + "code.gitea.io/gitea/modules/httplib" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" @@ -84,13 +84,7 @@ func (repo *Repository) relAvatarLink(ctx context.Context) string { return setting.AppSubURL + "/repo-avatars/" + url.PathEscape(repo.Avatar) } -// AvatarLink returns a link to the repository's avatar. +// AvatarLink returns the full avatar url with http host. TODO: refactor it to a relative URL, but it is still used in API response at the moment func (repo *Repository) AvatarLink(ctx context.Context) string { - link := repo.relAvatarLink(ctx) - // we only prepend our AppURL to our known (relative, internal) avatar link to get an absolute URL - if strings.HasPrefix(link, "/") && !strings.HasPrefix(link, "//") { - return setting.AppURL + strings.TrimPrefix(link, setting.AppSubURL)[1:] - } - // otherwise, return the link as it is - return link + return httplib.MakeAbsoluteURL(ctx, repo.relAvatarLink(ctx)) } diff --git a/models/user/avatar.go b/models/user/avatar.go index c6937d7b51..921bc1b1a1 100644 --- a/models/user/avatar.go +++ b/models/user/avatar.go @@ -9,11 +9,11 @@ import ( "fmt" "image/png" "io" - "strings" "code.gitea.io/gitea/models/avatars" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/avatar" + "code.gitea.io/gitea/modules/httplib" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" @@ -89,13 +89,9 @@ func (u *User) AvatarLinkWithSize(ctx context.Context, size int) string { return avatars.GenerateEmailAvatarFastLink(ctx, u.AvatarEmail, size) } -// AvatarLink returns the full avatar link with http host +// AvatarLink returns the full avatar url with http host. TODO: refactor it to a relative URL, but it is still used in API response at the moment func (u *User) AvatarLink(ctx context.Context) string { - link := u.AvatarLinkWithSize(ctx, 0) - if !strings.HasPrefix(link, "//") && !strings.Contains(link, "://") { - return setting.AppURL + strings.TrimPrefix(link, setting.AppSubURL+"/") - } - return link + return httplib.MakeAbsoluteURL(ctx, u.AvatarLinkWithSize(ctx, 0)) } // IsUploadAvatarChanged returns true if the current user's avatar would be changed with the provided data diff --git a/modules/httplib/url.go b/modules/httplib/url.go index 903799cb68..541c4f325b 100644 --- a/modules/httplib/url.go +++ b/modules/httplib/url.go @@ -4,6 +4,8 @@ package httplib import ( + "context" + "net/http" "net/url" "strings" @@ -11,6 +13,10 @@ import ( "code.gitea.io/gitea/modules/util" ) +type RequestContextKeyStruct struct{} + +var RequestContextKey = RequestContextKeyStruct{} + func urlIsRelative(s string, u *url.URL) bool { // Unfortunately browsers consider a redirect Location with preceding "//", "\\", "/\" and "\/" as meaning redirect to "http(s)://REST_OF_PATH" // Therefore we should ignore these redirect locations to prevent open redirects @@ -26,7 +32,56 @@ func IsRelativeURL(s string) bool { return err == nil && urlIsRelative(s, u) } -func IsCurrentGiteaSiteURL(s string) bool { +func guessRequestScheme(req *http.Request, def string) string { + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto + if s := req.Header.Get("X-Forwarded-Proto"); s != "" { + return s + } + if s := req.Header.Get("X-Forwarded-Protocol"); s != "" { + return s + } + if s := req.Header.Get("X-Url-Scheme"); s != "" { + return s + } + if s := req.Header.Get("Front-End-Https"); s != "" { + return util.Iif(s == "on", "https", "http") + } + if s := req.Header.Get("X-Forwarded-Ssl"); s != "" { + return util.Iif(s == "on", "https", "http") + } + return def +} + +func guessForwardedHost(req *http.Request) string { + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host + return req.Header.Get("X-Forwarded-Host") +} + +// GuessCurrentAppURL tries to guess the current full URL by http headers. It always has a '/' suffix, exactly the same as setting.AppURL +func GuessCurrentAppURL(ctx context.Context) string { + req, ok := ctx.Value(RequestContextKey).(*http.Request) + if !ok { + return setting.AppURL + } + if host := guessForwardedHost(req); host != "" { + // if it is behind a reverse proxy, use "https" as default scheme in case the site admin forgets to set the correct forwarded-protocol headers + return guessRequestScheme(req, "https") + "://" + host + setting.AppSubURL + "/" + } else if req.Host != "" { + // if it is not behind a reverse proxy, use the scheme from config options, meanwhile use "https" as much as possible + defaultScheme := util.Iif(setting.Protocol == "http", "http", "https") + return guessRequestScheme(req, defaultScheme) + "://" + req.Host + setting.AppSubURL + "/" + } + return setting.AppURL +} + +func MakeAbsoluteURL(ctx context.Context, s string) string { + if IsRelativeURL(s) { + return GuessCurrentAppURL(ctx) + strings.TrimPrefix(s, "/") + } + return s +} + +func IsCurrentGiteaSiteURL(ctx context.Context, s string) bool { u, err := url.Parse(s) if err != nil { return false @@ -45,5 +100,6 @@ func IsCurrentGiteaSiteURL(s string) bool { if u.Path == "" { u.Path = "/" } - return strings.HasPrefix(strings.ToLower(u.String()), strings.ToLower(setting.AppURL)) + urlLower := strings.ToLower(u.String()) + return strings.HasPrefix(urlLower, strings.ToLower(setting.AppURL)) || strings.HasPrefix(urlLower, strings.ToLower(GuessCurrentAppURL(ctx))) } diff --git a/modules/httplib/url_test.go b/modules/httplib/url_test.go index 9bf09bcf2f..e021cd610d 100644 --- a/modules/httplib/url_test.go +++ b/modules/httplib/url_test.go @@ -4,6 +4,8 @@ package httplib import ( + "context" + "net/http" "testing" "code.gitea.io/gitea/modules/setting" @@ -37,9 +39,44 @@ func TestIsRelativeURL(t *testing.T) { } } +func TestMakeAbsoluteURL(t *testing.T) { + defer test.MockVariableValue(&setting.Protocol, "http")() + defer test.MockVariableValue(&setting.AppURL, "http://the-host/sub/")() + defer test.MockVariableValue(&setting.AppSubURL, "/sub")() + + ctx := context.Background() + assert.Equal(t, "http://the-host/sub/", MakeAbsoluteURL(ctx, "")) + assert.Equal(t, "http://the-host/sub/foo", MakeAbsoluteURL(ctx, "foo")) + assert.Equal(t, "http://the-host/sub/foo", MakeAbsoluteURL(ctx, "/foo")) + assert.Equal(t, "http://other/foo", MakeAbsoluteURL(ctx, "http://other/foo")) + + ctx = context.WithValue(ctx, RequestContextKey, &http.Request{ + Host: "user-host", + }) + assert.Equal(t, "http://user-host/sub/foo", MakeAbsoluteURL(ctx, "/foo")) + + ctx = context.WithValue(ctx, RequestContextKey, &http.Request{ + Host: "user-host", + Header: map[string][]string{ + "X-Forwarded-Host": {"forwarded-host"}, + }, + }) + assert.Equal(t, "https://forwarded-host/sub/foo", MakeAbsoluteURL(ctx, "/foo")) + + ctx = context.WithValue(ctx, RequestContextKey, &http.Request{ + Host: "user-host", + Header: map[string][]string{ + "X-Forwarded-Host": {"forwarded-host"}, + "X-Forwarded-Proto": {"https"}, + }, + }) + assert.Equal(t, "https://forwarded-host/sub/foo", MakeAbsoluteURL(ctx, "/foo")) +} + func TestIsCurrentGiteaSiteURL(t *testing.T) { defer test.MockVariableValue(&setting.AppURL, "http://localhost:3000/sub/")() defer test.MockVariableValue(&setting.AppSubURL, "/sub")() + ctx := context.Background() good := []string{ "?key=val", "/sub", @@ -50,7 +87,7 @@ func TestIsCurrentGiteaSiteURL(t *testing.T) { "http://localhost:3000/sub/", } for _, s := range good { - assert.True(t, IsCurrentGiteaSiteURL(s), "good = %q", s) + assert.True(t, IsCurrentGiteaSiteURL(ctx, s), "good = %q", s) } bad := []string{ ".", @@ -64,13 +101,23 @@ func TestIsCurrentGiteaSiteURL(t *testing.T) { "http://other/", } for _, s := range bad { - assert.False(t, IsCurrentGiteaSiteURL(s), "bad = %q", s) + assert.False(t, IsCurrentGiteaSiteURL(ctx, s), "bad = %q", s) } setting.AppURL = "http://localhost:3000/" setting.AppSubURL = "" - assert.False(t, IsCurrentGiteaSiteURL("//")) - assert.False(t, IsCurrentGiteaSiteURL("\\\\")) - assert.False(t, IsCurrentGiteaSiteURL("http://localhost")) - assert.True(t, IsCurrentGiteaSiteURL("http://localhost:3000?key=val")) + assert.False(t, IsCurrentGiteaSiteURL(ctx, "//")) + assert.False(t, IsCurrentGiteaSiteURL(ctx, "\\\\")) + assert.False(t, IsCurrentGiteaSiteURL(ctx, "http://localhost")) + assert.True(t, IsCurrentGiteaSiteURL(ctx, "http://localhost:3000?key=val")) + + ctx = context.WithValue(ctx, RequestContextKey, &http.Request{ + Host: "user-host", + Header: map[string][]string{ + "X-Forwarded-Host": {"forwarded-host"}, + "X-Forwarded-Proto": {"https"}, + }, + }) + assert.True(t, IsCurrentGiteaSiteURL(ctx, "http://localhost:3000")) + assert.True(t, IsCurrentGiteaSiteURL(ctx, "https://forwarded-host")) } diff --git a/modules/markup/html_codepreview.go b/modules/markup/html_codepreview.go index 5ef2217e3d..5ab9290b3e 100644 --- a/modules/markup/html_codepreview.go +++ b/modules/markup/html_codepreview.go @@ -42,7 +42,7 @@ func renderCodeBlock(ctx *RenderContext, node *html.Node) (urlPosStart, urlPosSt CommitID: node.Data[m[6]:m[7]], FilePath: node.Data[m[8]:m[9]], } - if !httplib.IsCurrentGiteaSiteURL(opts.FullURL) { + if !httplib.IsCurrentGiteaSiteURL(ctx.Ctx, opts.FullURL) { return 0, 0, "", nil } u, err := url.Parse(opts.FilePath) diff --git a/routers/api/actions/artifacts.go b/routers/api/actions/artifacts.go index 5bd004bd37..35e3ee6906 100644 --- a/routers/api/actions/artifacts.go +++ b/routers/api/actions/artifacts.go @@ -71,6 +71,7 @@ import ( "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/httplib" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" @@ -184,8 +185,8 @@ type artifactRoutes struct { fs storage.ObjectStorage } -func (ar artifactRoutes) buildArtifactURL(runID int64, artifactHash, suffix string) string { - uploadURL := strings.TrimSuffix(setting.AppURL, "/") + strings.TrimSuffix(ar.prefix, "/") + +func (ar artifactRoutes) buildArtifactURL(ctx *ArtifactContext, runID int64, artifactHash, suffix string) string { + uploadURL := strings.TrimSuffix(httplib.GuessCurrentAppURL(ctx), "/") + strings.TrimSuffix(ar.prefix, "/") + strings.ReplaceAll(artifactRouteBase, "{run_id}", strconv.FormatInt(runID, 10)) + "/" + artifactHash + "/" + suffix return uploadURL @@ -224,7 +225,7 @@ func (ar artifactRoutes) getUploadArtifactURL(ctx *ArtifactContext) { // use md5(artifact_name) to create upload url artifactHash := fmt.Sprintf("%x", md5.Sum([]byte(req.Name))) resp := getUploadArtifactResponse{ - FileContainerResourceURL: ar.buildArtifactURL(runID, artifactHash, "upload"+retentionQuery), + FileContainerResourceURL: ar.buildArtifactURL(ctx, runID, artifactHash, "upload"+retentionQuery), } log.Debug("[artifact] get upload url: %s", resp.FileContainerResourceURL) ctx.JSON(http.StatusOK, resp) @@ -365,7 +366,7 @@ func (ar artifactRoutes) listArtifacts(ctx *ArtifactContext) { artifactHash := fmt.Sprintf("%x", md5.Sum([]byte(art.ArtifactName))) item := listArtifactsResponseItem{ Name: art.ArtifactName, - FileContainerResourceURL: ar.buildArtifactURL(runID, artifactHash, "download_url"), + FileContainerResourceURL: ar.buildArtifactURL(ctx, runID, artifactHash, "download_url"), } items = append(items, item) values[art.ArtifactName] = true @@ -437,7 +438,7 @@ func (ar artifactRoutes) getDownloadArtifactURL(ctx *ArtifactContext) { } } if downloadURL == "" { - downloadURL = ar.buildArtifactURL(runID, strconv.FormatInt(artifact.ID, 10), "download") + downloadURL = ar.buildArtifactURL(ctx, runID, strconv.FormatInt(artifact.ID, 10), "download") } item := downloadArtifactResponseItem{ Path: util.PathJoinRel(itemPath, artifact.ArtifactPath), diff --git a/routers/api/actions/artifactsv4.go b/routers/api/actions/artifactsv4.go index 8300989c75..dde9caf4f2 100644 --- a/routers/api/actions/artifactsv4.go +++ b/routers/api/actions/artifactsv4.go @@ -92,6 +92,7 @@ import ( "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/httplib" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" @@ -160,9 +161,9 @@ func (r artifactV4Routes) buildSignature(endp, expires, artifactName string, tas return mac.Sum(nil) } -func (r artifactV4Routes) buildArtifactURL(endp, artifactName string, taskID int64) string { +func (r artifactV4Routes) buildArtifactURL(ctx *ArtifactContext, endp, artifactName string, taskID int64) string { expires := time.Now().Add(60 * time.Minute).Format("2006-01-02 15:04:05.999999999 -0700 MST") - uploadURL := strings.TrimSuffix(setting.AppURL, "/") + strings.TrimSuffix(r.prefix, "/") + + uploadURL := strings.TrimSuffix(httplib.GuessCurrentAppURL(ctx), "/") + strings.TrimSuffix(r.prefix, "/") + "/" + endp + "?sig=" + base64.URLEncoding.EncodeToString(r.buildSignature(endp, expires, artifactName, taskID)) + "&expires=" + url.QueryEscape(expires) + "&artifactName=" + url.QueryEscape(artifactName) + "&taskID=" + fmt.Sprint(taskID) return uploadURL } @@ -278,7 +279,7 @@ func (r *artifactV4Routes) createArtifact(ctx *ArtifactContext) { respData := CreateArtifactResponse{ Ok: true, - SignedUploadUrl: r.buildArtifactURL("UploadArtifact", artifactName, ctx.ActionTask.ID), + SignedUploadUrl: r.buildArtifactURL(ctx, "UploadArtifact", artifactName, ctx.ActionTask.ID), } r.sendProtbufBody(ctx, &respData) } @@ -454,7 +455,7 @@ func (r *artifactV4Routes) getSignedArtifactURL(ctx *ArtifactContext) { } } if respData.SignedUrl == "" { - respData.SignedUrl = r.buildArtifactURL("DownloadArtifact", artifactName, ctx.ActionTask.ID) + respData.SignedUrl = r.buildArtifactURL(ctx, "DownloadArtifact", artifactName, ctx.ActionTask.ID) } r.sendProtbufBody(ctx, &respData) } diff --git a/routers/api/packages/container/container.go b/routers/api/packages/container/container.go index 2cb16daebc..1efd166eb3 100644 --- a/routers/api/packages/container/container.go +++ b/routers/api/packages/container/container.go @@ -17,6 +17,7 @@ import ( 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" + "code.gitea.io/gitea/modules/httplib" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" packages_module "code.gitea.io/gitea/modules/packages" @@ -115,7 +116,7 @@ func apiErrorDefined(ctx *context.Context, err *namedError) { } func apiUnauthorizedError(ctx *context.Context) { - ctx.Resp.Header().Add("WWW-Authenticate", `Bearer realm="`+setting.AppURL+`v2/token",service="container_registry",scope="*"`) + ctx.Resp.Header().Add("WWW-Authenticate", `Bearer realm="`+httplib.GuessCurrentAppURL(ctx)+`v2/token",service="container_registry",scope="*"`) apiErrorDefined(ctx, errUnauthorized) } diff --git a/routers/common/middleware.go b/routers/common/middleware.go index c7c75fb099..8b661993bb 100644 --- a/routers/common/middleware.go +++ b/routers/common/middleware.go @@ -4,11 +4,13 @@ package common import ( + go_context "context" "fmt" "net/http" "strings" "code.gitea.io/gitea/modules/cache" + "code.gitea.io/gitea/modules/httplib" "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web/middleware" @@ -34,6 +36,7 @@ func ProtocolMiddlewares() (handlers []any) { } }() req = req.WithContext(middleware.WithContextData(req.Context())) + req = req.WithContext(go_context.WithValue(req.Context(), httplib.RequestContextKey, req)) next.ServeHTTP(resp, req) }) }) diff --git a/routers/common/redirect.go b/routers/common/redirect.go index 34044e814b..d64f74ec82 100644 --- a/routers/common/redirect.go +++ b/routers/common/redirect.go @@ -17,7 +17,7 @@ func FetchRedirectDelegate(resp http.ResponseWriter, req *http.Request) { // The typical page is "issue comment" page. The backend responds "/owner/repo/issues/1#comment-2", // then frontend needs this delegate to redirect to the new location with hash correctly. redirect := req.PostFormValue("redirect") - if !httplib.IsCurrentGiteaSiteURL(redirect) { + if !httplib.IsCurrentGiteaSiteURL(req.Context(), redirect) { resp.WriteHeader(http.StatusBadRequest) return } diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 7c873796fe..4083d64226 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -368,7 +368,7 @@ func handleSignInFull(ctx *context.Context, u *user_model.User, remember, obeyRe return setting.AppSubURL + "/" } - if redirectTo := ctx.GetSiteCookie("redirect_to"); redirectTo != "" && httplib.IsCurrentGiteaSiteURL(redirectTo) { + if redirectTo := ctx.GetSiteCookie("redirect_to"); redirectTo != "" && httplib.IsCurrentGiteaSiteURL(ctx, redirectTo) { middleware.DeleteRedirectToCookie(ctx.Resp) if obeyRedirect { ctx.RedirectToCurrentSite(redirectTo) diff --git a/services/context/base.go b/services/context/base.go index 05b8ab1b9b..29e62ae389 100644 --- a/services/context/base.go +++ b/services/context/base.go @@ -254,7 +254,7 @@ func (b *Base) Redirect(location string, status ...int) { code = status[0] } - if strings.HasPrefix(location, "http://") || strings.HasPrefix(location, "https://") || strings.HasPrefix(location, "//") { + if !httplib.IsRelativeURL(location) { // Some browsers (Safari) have buggy behavior for Cookie + Cache + External Redirection, eg: /my-path => https://other/path // 1. the first request to "/my-path" contains cookie // 2. some time later, the request to "/my-path" doesn't contain cookie (caused by Prevent web tracking) diff --git a/services/context/context_response.go b/services/context/context_response.go index 87c34c35ed..c43a649b49 100644 --- a/services/context/context_response.go +++ b/services/context/context_response.go @@ -52,7 +52,7 @@ func (ctx *Context) RedirectToCurrentSite(location ...string) { continue } - if !httplib.IsCurrentGiteaSiteURL(loc) { + if !httplib.IsCurrentGiteaSiteURL(ctx, loc) { continue } From 880e0b7c82c2d9fdecaf4e9d6345206304ca7ca6 Mon Sep 17 00:00:00 2001 From: Kemal Zebari <60799661+kemzeb@users.noreply.github.com> Date: Tue, 7 May 2024 05:41:52 -0700 Subject: [PATCH 287/370] Apply to become a maintainer (#30884) Hello! After contributing for some time I am interested in taking a more involved role as a maintainer. When time allows it, I plan to perform code reviews, continue resolving/triaging issues, and engage with the community to see if I can offer any useful insights. My current interests are in backend work, but I plan to study the web frontend architecture to see if I can contribute there as well. Thanks for this awesome project. I hope I can both learn and contribute to its continued success! PR list: https://github.com/go-gitea/gitea/pulls?q=is%3Apr+is%3Aclosed+author%3Akemzeb Discord: kemzeb --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index eed87529a3..610d76628c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -61,3 +61,4 @@ kerwin612 <kerwin612@qq.com> (@kerwin612) Gary Wang <git@blumia.net> (@BLumia) Tim-Niclas Oelschläger <zokki.softwareschmiede@gmail.com> (@zokkis) Yu Liu <1240335630@qq.com> (@HEREYUA) +Kemal Zebari <kemalzebra@gmail.com> (@kemzeb) From f1b0729078bc143a4e1c09f04d7dad22e3e6b01d Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Wed, 8 May 2024 00:21:06 +0000 Subject: [PATCH 288/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_zh-CN.ini | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index a76ecafd62..599f0d3b07 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -436,6 +436,7 @@ oauth_signin_submit=绑定账号 oauth.signin.error=处理授权请求时出错。 如果此错误仍然存在,请联系站点管理员。 oauth.signin.error.access_denied=授权请求被拒绝。 oauth.signin.error.temporarily_unavailable=授权失败,因为认证服务器暂时不可用。请稍后再试。 +oauth_callback_unable_auto_reg=自动注册已启用,但OAuth2 提供商 %[1]s 返回缺失的字段:%[2]s,无法自动创建帐户,请创建或链接到一个帐户,或联系站点管理员。 openid_connect_submit=连接 openid_connect_title=连接到现有的帐户 openid_connect_desc=所选的 OpenID URI 未知。在这里关联一个新帐户。 @@ -763,6 +764,8 @@ manage_themes=选择默认主题 manage_openid=管理 OpenID 地址 email_desc=您的主要电子邮件地址将用于通知、密码恢复,基于网页界面的Git操作(只要它不是设置为隐藏的)。 theme_desc=这将是您在整个网站上的默认主题。 +theme_colorblindness_help=颜色障碍主题支持 +theme_colorblindness_prompt=Gitea 只能获得一些基本的颜色障碍支持,这些主题只定义了少数颜色。 这项工作仍在进行中,可以通过在主题的 CSS 文件中定义更多颜色来做更多的改进。 primary=主要 activated=已激活 requires_activation=需要激活 @@ -1810,7 +1813,7 @@ 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_approvals=此合并请求还没有足够的批准。已获批准数 %d 个,需获批准数 %d 个。 pulls.blocked_by_rejection=此合并请求有官方审核员请求的更改。 pulls.blocked_by_official_review_requests=此合并请求需要官方评审。 pulls.blocked_by_outdated_branch=此合并请求因过期而被阻止。 @@ -1884,14 +1887,14 @@ pulls.clear_merge_message_hint=清除合并消息只会删除提交消息内容 pulls.auto_merge_button_when_succeed=(当检查成功时) pulls.auto_merge_when_succeed=在所有检查成功后自动合并 pulls.auto_merge_newly_scheduled=合并请求计划在所有检查成功后合并。 -pulls.auto_merge_has_pending_schedule=%[1]s 安排此拉取请求在所有检查成功时自动合并 %[2]s。 +pulls.auto_merge_has_pending_schedule=%[1]s 于 %[2]s 设置此合并请求在所有检查成功时自动合并 。 pulls.auto_merge_cancel_schedule=取消自动合并 -pulls.auto_merge_not_scheduled=此拉取请求没有计划自动合并。 -pulls.auto_merge_canceled_schedule=此拉取请求的自动合并已取消。 +pulls.auto_merge_not_scheduled=此合并请求没有计划自动合并。 +pulls.auto_merge_canceled_schedule=此合并请求的自动合并已取消。 -pulls.auto_merge_newly_scheduled_comment=`已安排此拉取请求在所有检查成功后自动合并 %[1]s` -pulls.auto_merge_canceled_schedule_comment=`已取消当所有检查成功后自动合并此拉取请求 %[1]s` +pulls.auto_merge_newly_scheduled_comment=`已于 %[1]s 设置此拉取请求在所有检查成功后自动合并` +pulls.auto_merge_canceled_schedule_comment=`已于 %[1]s 取消了自动合并设置 ` pulls.delete.title=删除此拉取请求? pulls.delete.text=你真的要删除这个拉取请求吗? (这将永久删除所有内容。如果你打算将内容存档,请考虑关闭它) @@ -3331,7 +3334,7 @@ reopen_pull_request=`重新开启了合并请求 <a href="%[1]s">%[3]s#%[2]s</a> comment_issue=`评论了工单 <a href="%[1]s">%[3]s#%[2]s</a>` comment_pull=`评论了合并请求 <a href="%[1]s">%[3]s#%[2]s</a>` merge_pull_request=`合并了合并请求 <a href="%[1]s">%[3]s#%[2]s</a>` -auto_merge_pull_request=`自动合并了拉取请求 <a href="%[1]s">%[3]s#%[2]s</a>` +auto_merge_pull_request=`自动合并了合并请求 <a href="%[1]s">%[3]s#%[2]s</a>` transfer_repo=将仓库 <code>%s</code> 转移至 <a href="%s">%s</a> push_tag=推送了标签 <a href="%[2]s">%[3]s</a> 至仓库 <a href="%[1]s">%[4]s</a> delete_tag=从<a href="%[1]s">%[3]s</a> 删除了标签 %[2]s @@ -3492,6 +3495,7 @@ npm.install=要使用 npm 安装软件包,请运行以下命令: npm.install2=或将其添加到 package.json 文件: npm.dependencies=依赖项 npm.dependencies.development=开发依赖 +npm.dependencies.bundle=已绑定的依赖关系 npm.dependencies.peer=Peer 依赖 npm.dependencies.optional=可选依赖 npm.details.tag=标签 From d9b37d085acb7e93409061e541b6a3aa53261bb0 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Wed, 8 May 2024 04:42:33 +0200 Subject: [PATCH 289/370] Remove obsolete monaco workaround (#30893) This workaround is not neccessary any more since monaco 0.35.0. Ref: https://github.com/microsoft/monaco-editor/issues/2962 Ref: https://github.com/microsoft/vscode/pull/173688 --- web_src/js/features/codeeditor.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/web_src/js/features/codeeditor.js b/web_src/js/features/codeeditor.js index 4dfef8c2b2..2b1e64c10d 100644 --- a/web_src/js/features/codeeditor.js +++ b/web_src/js/features/codeeditor.js @@ -102,10 +102,6 @@ export async function createMonaco(textarea, filename, editorOpts) { }, }); - // Quick fix: https://github.com/microsoft/monaco-editor/issues/2962 - monaco.languages.register({id: 'vs.editor.nullLanguage'}); - monaco.languages.setLanguageConfiguration('vs.editor.nullLanguage', {}); - const editor = monaco.editor.create(container, { value: textarea.value, theme: 'gitea', From f5f921c09555f5b31226fc31bbbb463649d0bfdc Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Wed, 8 May 2024 21:17:11 +0800 Subject: [PATCH 290/370] Fix wrong transfer hint (#30889) Fix #30187 --- routers/web/repo/setting/setting.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go index 17a400e360..1e0349cdee 100644 --- a/routers/web/repo/setting/setting.go +++ b/routers/web/repo/setting/setting.go @@ -789,6 +789,7 @@ func SettingsPost(ctx *context.Context) { ctx.Repo.GitRepo = nil } + oldFullname := repo.FullName() if err := repo_service.StartRepositoryTransfer(ctx, ctx.Doer, newOwner, repo, nil); err != nil { if repo_model.IsErrRepoAlreadyExist(err) { ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplSettingsOptions, nil) @@ -803,8 +804,13 @@ func SettingsPost(ctx *context.Context) { return } - log.Trace("Repository transfer process was started: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newOwner) - ctx.Flash.Success(ctx.Tr("repo.settings.transfer_started", newOwner.DisplayName())) + if ctx.Repo.Repository.Status == repo_model.RepositoryPendingTransfer { + log.Trace("Repository transfer process was started: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newOwner) + ctx.Flash.Success(ctx.Tr("repo.settings.transfer_started", newOwner.DisplayName())) + } else { + log.Trace("Repository transferred: %s -> %s", oldFullname, ctx.Repo.Repository.FullName()) + ctx.Flash.Success(ctx.Tr("repo.settings.transfer_succeed")) + } ctx.Redirect(repo.Link() + "/settings") case "cancel_transfer": From a303c973e0264dab45a787c4afa200e183e0d953 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Wed, 8 May 2024 21:44:57 +0800 Subject: [PATCH 291/370] Fix various problems around projects board view (#30696) # The problem The previous implementation will start multiple POST requests from the frontend when moving a column and another bug is moving the default column will never be remembered in fact. # What's changed - [x] This PR will allow the default column to move to a non-first position - [x] And it also uses one request instead of multiple requests when moving the columns - [x] Use a star instead of a pin as the icon for setting the default column action - [x] Inserted new column will be append to the end - [x] Fix #30701 the newly added issue will be append to the end of the default column - [x] Fix when deleting a column, all issues in it will be displayed from UI but database records exist. - [x] Add a limitation for columns in a project to 20. So the sorting will not be overflow because it's int8. --------- Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> --- models/db/engine.go | 1 + models/issues/issue_project.go | 107 +++++++++++++++----------- models/project/board.go | 95 ++++++++++++++++++++--- models/project/board_test.go | 87 ++++++++++++++++++++- models/project/issue.go | 51 ++++++++++-- models/project/project.go | 7 ++ routers/web/org/projects.go | 69 ----------------- routers/web/repo/projects.go | 17 ++-- routers/web/repo/pull.go | 14 ++-- routers/web/shared/project/column.go | 48 ++++++++++++ routers/web/web.go | 3 + services/issue/issue.go | 2 +- templates/projects/view.tmpl | 2 +- tests/integration/org_project_test.go | 6 +- tests/integration/project_test.go | 64 +++++++++++++++ web_src/js/features/repo-projects.js | 26 ++++--- 16 files changed, 431 insertions(+), 168 deletions(-) create mode 100644 routers/web/shared/project/column.go diff --git a/models/db/engine.go b/models/db/engine.go index 25f4066ea1..847ba58c26 100755 --- a/models/db/engine.go +++ b/models/db/engine.go @@ -57,6 +57,7 @@ type Engine interface { SumInt(bean any, columnName string) (res int64, err error) Sync(...any) error Select(string) *xorm.Session + SetExpr(string, any) *xorm.Session NotIn(string, ...any) *xorm.Session OrderBy(any, ...any) *xorm.Session Exist(...any) (bool, error) diff --git a/models/issues/issue_project.go b/models/issues/issue_project.go index 907a5a17b9..e31d2ef151 100644 --- a/models/issues/issue_project.go +++ b/models/issues/issue_project.go @@ -5,11 +5,11 @@ package issues import ( "context" - "fmt" "code.gitea.io/gitea/models/db" project_model "code.gitea.io/gitea/models/project" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/util" ) // LoadProject load the project the issue was assigned to @@ -90,58 +90,73 @@ func LoadIssuesFromBoardList(ctx context.Context, bs project_model.BoardList) (m return issuesMap, nil } -// ChangeProjectAssign changes the project associated with an issue -func ChangeProjectAssign(ctx context.Context, issue *Issue, doer *user_model.User, newProjectID int64) error { - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return err - } - defer committer.Close() +// IssueAssignOrRemoveProject changes the project associated with an issue +// If newProjectID is 0, the issue is removed from the project +func IssueAssignOrRemoveProject(ctx context.Context, issue *Issue, doer *user_model.User, newProjectID, newColumnID int64) error { + return db.WithTx(ctx, func(ctx context.Context) error { + oldProjectID := issue.projectID(ctx) - if err := addUpdateIssueProject(ctx, issue, doer, newProjectID); err != nil { - return err - } - - return committer.Commit() -} - -func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.User, newProjectID int64) error { - oldProjectID := issue.projectID(ctx) - - if err := issue.LoadRepo(ctx); err != nil { - return err - } - - // Only check if we add a new project and not remove it. - if newProjectID > 0 { - newProject, err := project_model.GetProjectByID(ctx, newProjectID) - if err != nil { + if err := issue.LoadRepo(ctx); err != nil { return err } - if newProject.RepoID != issue.RepoID && newProject.OwnerID != issue.Repo.OwnerID { - return fmt.Errorf("issue's repository is not the same as project's repository") + + // Only check if we add a new project and not remove it. + if newProjectID > 0 { + newProject, err := project_model.GetProjectByID(ctx, newProjectID) + if err != nil { + return err + } + if !newProject.CanBeAccessedByOwnerRepo(issue.Repo.OwnerID, issue.Repo) { + return util.NewPermissionDeniedErrorf("issue %d can't be accessed by project %d", issue.ID, newProject.ID) + } + if newColumnID == 0 { + newDefaultColumn, err := newProject.GetDefaultBoard(ctx) + if err != nil { + return err + } + newColumnID = newDefaultColumn.ID + } } - } - if _, err := db.GetEngine(ctx).Where("project_issue.issue_id=?", issue.ID).Delete(&project_model.ProjectIssue{}); err != nil { - return err - } - - if oldProjectID > 0 || newProjectID > 0 { - if _, err := CreateComment(ctx, &CreateCommentOptions{ - Type: CommentTypeProject, - Doer: doer, - Repo: issue.Repo, - Issue: issue, - OldProjectID: oldProjectID, - ProjectID: newProjectID, - }); err != nil { + if _, err := db.GetEngine(ctx).Where("project_issue.issue_id=?", issue.ID).Delete(&project_model.ProjectIssue{}); err != nil { return err } - } - return db.Insert(ctx, &project_model.ProjectIssue{ - IssueID: issue.ID, - ProjectID: newProjectID, + if oldProjectID > 0 || newProjectID > 0 { + if _, err := CreateComment(ctx, &CreateCommentOptions{ + Type: CommentTypeProject, + Doer: doer, + Repo: issue.Repo, + Issue: issue, + OldProjectID: oldProjectID, + ProjectID: newProjectID, + }); err != nil { + return err + } + } + if newProjectID == 0 { + return nil + } + if newColumnID == 0 { + panic("newColumnID must not be zero") // shouldn't happen + } + + res := struct { + MaxSorting int64 + IssueCount int64 + }{} + if _, err := db.GetEngine(ctx).Select("max(sorting) as max_sorting, count(*) as issue_count").Table("project_issue"). + Where("project_id=?", newProjectID). + And("project_board_id=?", newColumnID). + Get(&res); err != nil { + return err + } + newSorting := util.Iif(res.IssueCount > 0, res.MaxSorting+1, 0) + return db.Insert(ctx, &project_model.ProjectIssue{ + IssueID: issue.ID, + ProjectID: newProjectID, + ProjectBoardID: newColumnID, + Sorting: newSorting, + }) }) } diff --git a/models/project/board.go b/models/project/board.go index 7faabc52c5..a52baa0c18 100644 --- a/models/project/board.go +++ b/models/project/board.go @@ -5,12 +5,14 @@ package project import ( "context" + "errors" "fmt" "regexp" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) @@ -82,6 +84,17 @@ func (b *Board) NumIssues(ctx context.Context) int { return int(c) } +func (b *Board) GetIssues(ctx context.Context) ([]*ProjectIssue, error) { + issues := make([]*ProjectIssue, 0, 5) + if err := db.GetEngine(ctx).Where("project_id=?", b.ProjectID). + And("project_board_id=?", b.ID). + OrderBy("sorting, id"). + Find(&issues); err != nil { + return nil, err + } + return issues, nil +} + func init() { db.RegisterModel(new(Board)) } @@ -150,12 +163,27 @@ func createBoardsForProjectsType(ctx context.Context, project *Project) error { return db.Insert(ctx, boards) } +// maxProjectColumns max columns allowed in a project, this should not bigger than 127 +// because sorting is int8 in database +const maxProjectColumns = 20 + // NewBoard adds a new project board to a given project func NewBoard(ctx context.Context, board *Board) error { if len(board.Color) != 0 && !BoardColorPattern.MatchString(board.Color) { return fmt.Errorf("bad color code: %s", board.Color) } - + res := struct { + MaxSorting int64 + ColumnCount int64 + }{} + if _, err := db.GetEngine(ctx).Select("max(sorting) as max_sorting, count(*) as column_count").Table("project_board"). + Where("project_id=?", board.ProjectID).Get(&res); err != nil { + return err + } + if res.ColumnCount >= maxProjectColumns { + return fmt.Errorf("NewBoard: maximum number of columns reached") + } + board.Sorting = int8(util.Iif(res.ColumnCount > 0, res.MaxSorting+1, 0)) _, err := db.GetEngine(ctx).Insert(board) return err } @@ -189,7 +217,17 @@ func deleteBoardByID(ctx context.Context, boardID int64) error { return fmt.Errorf("deleteBoardByID: cannot delete default board") } - if err = board.removeIssues(ctx); err != nil { + // move all issues to the default column + project, err := GetProjectByID(ctx, board.ProjectID) + if err != nil { + return err + } + defaultColumn, err := project.GetDefaultBoard(ctx) + if err != nil { + return err + } + + if err = board.moveIssuesToAnotherColumn(ctx, defaultColumn); err != nil { return err } @@ -242,21 +280,15 @@ func UpdateBoard(ctx context.Context, board *Board) error { // GetBoards fetches all boards related to a project func (p *Project) GetBoards(ctx context.Context) (BoardList, error) { boards := make([]*Board, 0, 5) - - if err := db.GetEngine(ctx).Where("project_id=? AND `default`=?", p.ID, false).OrderBy("sorting").Find(&boards); err != nil { + if err := db.GetEngine(ctx).Where("project_id=?", p.ID).OrderBy("sorting, id").Find(&boards); err != nil { return nil, err } - defaultB, err := p.getDefaultBoard(ctx) - if err != nil { - return nil, err - } - - return append([]*Board{defaultB}, boards...), nil + return boards, nil } -// getDefaultBoard return default board and ensure only one exists -func (p *Project) getDefaultBoard(ctx context.Context) (*Board, error) { +// GetDefaultBoard return default board and ensure only one exists +func (p *Project) GetDefaultBoard(ctx context.Context) (*Board, error) { var board Board has, err := db.GetEngine(ctx). Where("project_id=? AND `default` = ?", p.ID, true). @@ -316,3 +348,42 @@ func UpdateBoardSorting(ctx context.Context, bs BoardList) error { return nil }) } + +func GetColumnsByIDs(ctx context.Context, projectID int64, columnsIDs []int64) (BoardList, error) { + columns := make([]*Board, 0, 5) + if err := db.GetEngine(ctx). + Where("project_id =?", projectID). + In("id", columnsIDs). + OrderBy("sorting").Find(&columns); err != nil { + return nil, err + } + return columns, nil +} + +// MoveColumnsOnProject sorts columns in a project +func MoveColumnsOnProject(ctx context.Context, project *Project, sortedColumnIDs map[int64]int64) error { + return db.WithTx(ctx, func(ctx context.Context) error { + sess := db.GetEngine(ctx) + columnIDs := util.ValuesOfMap(sortedColumnIDs) + movedColumns, err := GetColumnsByIDs(ctx, project.ID, columnIDs) + if err != nil { + return err + } + if len(movedColumns) != len(sortedColumnIDs) { + return errors.New("some columns do not exist") + } + + for _, column := range movedColumns { + if column.ProjectID != project.ID { + return fmt.Errorf("column[%d]'s projectID is not equal to project's ID [%d]", column.ProjectID, project.ID) + } + } + + for sorting, columnID := range sortedColumnIDs { + if _, err := sess.Exec("UPDATE `project_board` SET sorting=? WHERE id=?", sorting, columnID); err != nil { + return err + } + } + return nil + }) +} diff --git a/models/project/board_test.go b/models/project/board_test.go index 71ba29a589..da922ff7ad 100644 --- a/models/project/board_test.go +++ b/models/project/board_test.go @@ -4,6 +4,8 @@ package project import ( + "fmt" + "strings" "testing" "code.gitea.io/gitea/models/db" @@ -19,7 +21,7 @@ func TestGetDefaultBoard(t *testing.T) { assert.NoError(t, err) // check if default board was added - board, err := projectWithoutDefault.getDefaultBoard(db.DefaultContext) + board, err := projectWithoutDefault.GetDefaultBoard(db.DefaultContext) assert.NoError(t, err) assert.Equal(t, int64(5), board.ProjectID) assert.Equal(t, "Uncategorized", board.Title) @@ -28,7 +30,7 @@ func TestGetDefaultBoard(t *testing.T) { assert.NoError(t, err) // check if multiple defaults were removed - board, err = projectWithMultipleDefaults.getDefaultBoard(db.DefaultContext) + board, err = projectWithMultipleDefaults.GetDefaultBoard(db.DefaultContext) assert.NoError(t, err) assert.Equal(t, int64(6), board.ProjectID) assert.Equal(t, int64(9), board.ID) @@ -42,3 +44,84 @@ func TestGetDefaultBoard(t *testing.T) { assert.Equal(t, int64(6), board.ProjectID) assert.False(t, board.Default) } + +func Test_moveIssuesToAnotherColumn(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + column1 := unittest.AssertExistsAndLoadBean(t, &Board{ID: 1, ProjectID: 1}) + + issues, err := column1.GetIssues(db.DefaultContext) + assert.NoError(t, err) + assert.Len(t, issues, 1) + assert.EqualValues(t, 1, issues[0].ID) + + column2 := unittest.AssertExistsAndLoadBean(t, &Board{ID: 2, ProjectID: 1}) + issues, err = column2.GetIssues(db.DefaultContext) + assert.NoError(t, err) + assert.Len(t, issues, 1) + assert.EqualValues(t, 3, issues[0].ID) + + err = column1.moveIssuesToAnotherColumn(db.DefaultContext, column2) + assert.NoError(t, err) + + issues, err = column1.GetIssues(db.DefaultContext) + assert.NoError(t, err) + assert.Len(t, issues, 0) + + issues, err = column2.GetIssues(db.DefaultContext) + assert.NoError(t, err) + assert.Len(t, issues, 2) + assert.EqualValues(t, 3, issues[0].ID) + assert.EqualValues(t, 0, issues[0].Sorting) + assert.EqualValues(t, 1, issues[1].ID) + assert.EqualValues(t, 1, issues[1].Sorting) +} + +func Test_MoveColumnsOnProject(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + project1 := unittest.AssertExistsAndLoadBean(t, &Project{ID: 1}) + columns, err := project1.GetBoards(db.DefaultContext) + assert.NoError(t, err) + assert.Len(t, columns, 3) + assert.EqualValues(t, 0, columns[0].Sorting) // even if there is no default sorting, the code should also work + assert.EqualValues(t, 0, columns[1].Sorting) + assert.EqualValues(t, 0, columns[2].Sorting) + + err = MoveColumnsOnProject(db.DefaultContext, project1, map[int64]int64{ + 0: columns[1].ID, + 1: columns[2].ID, + 2: columns[0].ID, + }) + assert.NoError(t, err) + + columnsAfter, err := project1.GetBoards(db.DefaultContext) + assert.NoError(t, err) + assert.Len(t, columnsAfter, 3) + assert.EqualValues(t, columns[1].ID, columnsAfter[0].ID) + assert.EqualValues(t, columns[2].ID, columnsAfter[1].ID) + assert.EqualValues(t, columns[0].ID, columnsAfter[2].ID) +} + +func Test_NewBoard(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + project1 := unittest.AssertExistsAndLoadBean(t, &Project{ID: 1}) + columns, err := project1.GetBoards(db.DefaultContext) + assert.NoError(t, err) + assert.Len(t, columns, 3) + + for i := 0; i < maxProjectColumns-3; i++ { + err := NewBoard(db.DefaultContext, &Board{ + Title: fmt.Sprintf("board-%d", i+4), + ProjectID: project1.ID, + }) + assert.NoError(t, err) + } + err = NewBoard(db.DefaultContext, &Board{ + Title: "board-21", + ProjectID: project1.ID, + }) + assert.Error(t, err) + assert.True(t, strings.Contains(err.Error(), "maximum number of columns reached")) +} diff --git a/models/project/issue.go b/models/project/issue.go index ebc9719de5..32e72e909d 100644 --- a/models/project/issue.go +++ b/models/project/issue.go @@ -9,6 +9,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/util" ) // ProjectIssue saves relation from issue to a project @@ -17,7 +18,7 @@ type ProjectIssue struct { //revive:disable-line:exported IssueID int64 `xorm:"INDEX"` ProjectID int64 `xorm:"INDEX"` - // If 0, then it has not been added to a specific board in the project + // ProjectBoardID should not be zero since 1.22. If it's zero, the issue will not be displayed on UI and it might result in errors. ProjectBoardID int64 `xorm:"INDEX"` // the sorting order on the board @@ -79,11 +80,8 @@ func (p *Project) NumOpenIssues(ctx context.Context) int { func MoveIssuesOnProjectBoard(ctx context.Context, board *Board, sortedIssueIDs map[int64]int64) error { return db.WithTx(ctx, func(ctx context.Context) error { sess := db.GetEngine(ctx) + issueIDs := util.ValuesOfMap(sortedIssueIDs) - issueIDs := make([]int64, 0, len(sortedIssueIDs)) - for _, issueID := range sortedIssueIDs { - issueIDs = append(issueIDs, issueID) - } count, err := sess.Table(new(ProjectIssue)).Where("project_id=?", board.ProjectID).In("issue_id", issueIDs).Count() if err != nil { return err @@ -102,7 +100,44 @@ func MoveIssuesOnProjectBoard(ctx context.Context, board *Board, sortedIssueIDs }) } -func (b *Board) removeIssues(ctx context.Context) error { - _, err := db.GetEngine(ctx).Exec("UPDATE `project_issue` SET project_board_id = 0 WHERE project_board_id = ? ", b.ID) - return err +func (b *Board) moveIssuesToAnotherColumn(ctx context.Context, newColumn *Board) error { + if b.ProjectID != newColumn.ProjectID { + return fmt.Errorf("columns have to be in the same project") + } + + if b.ID == newColumn.ID { + return nil + } + + res := struct { + MaxSorting int64 + IssueCount int64 + }{} + if _, err := db.GetEngine(ctx).Select("max(sorting) as max_sorting, count(*) as issue_count"). + Table("project_issue"). + Where("project_id=?", newColumn.ProjectID). + And("project_board_id=?", newColumn.ID). + Get(&res); err != nil { + return err + } + + issues, err := b.GetIssues(ctx) + if err != nil { + return err + } + if len(issues) == 0 { + return nil + } + + nextSorting := util.Iif(res.IssueCount > 0, res.MaxSorting+1, 0) + return db.WithTx(ctx, func(ctx context.Context) error { + for i, issue := range issues { + issue.ProjectBoardID = newColumn.ID + issue.Sorting = nextSorting + int64(i) + if _, err := db.GetEngine(ctx).ID(issue.ID).Cols("project_board_id", "sorting").Update(issue); err != nil { + return err + } + } + return nil + }) } diff --git a/models/project/project.go b/models/project/project.go index 8f9ee2a99e..8be38694c5 100644 --- a/models/project/project.go +++ b/models/project/project.go @@ -161,6 +161,13 @@ func (p *Project) IsRepositoryProject() bool { return p.Type == TypeRepository } +func (p *Project) CanBeAccessedByOwnerRepo(ownerID int64, repo *repo_model.Repository) bool { + if p.Type == TypeRepository { + return repo != nil && p.RepoID == repo.ID // if a project belongs to a repository, then its OwnerID is 0 and can be ignored + } + return p.OwnerID == ownerID && p.RepoID == 0 +} + func init() { db.RegisterModel(new(Project)) } diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go index 7f78d1c830..50effbe963 100644 --- a/routers/web/org/projects.go +++ b/routers/web/org/projects.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "net/http" - "strconv" "strings" "code.gitea.io/gitea/models/db" @@ -390,74 +389,6 @@ func ViewProject(ctx *context.Context) { ctx.HTML(http.StatusOK, tplProjectsView) } -func getActionIssues(ctx *context.Context) issues_model.IssueList { - commaSeparatedIssueIDs := ctx.FormString("issue_ids") - if len(commaSeparatedIssueIDs) == 0 { - return nil - } - issueIDs := make([]int64, 0, 10) - for _, stringIssueID := range strings.Split(commaSeparatedIssueIDs, ",") { - issueID, err := strconv.ParseInt(stringIssueID, 10, 64) - if err != nil { - ctx.ServerError("ParseInt", err) - return nil - } - issueIDs = append(issueIDs, issueID) - } - issues, err := issues_model.GetIssuesByIDs(ctx, issueIDs) - if err != nil { - ctx.ServerError("GetIssuesByIDs", err) - return nil - } - // Check access rights for all issues - issueUnitEnabled := ctx.Repo.CanRead(unit.TypeIssues) - prUnitEnabled := ctx.Repo.CanRead(unit.TypePullRequests) - for _, issue := range issues { - if issue.RepoID != ctx.Repo.Repository.ID { - ctx.NotFound("some issue's RepoID is incorrect", errors.New("some issue's RepoID is incorrect")) - return nil - } - if issue.IsPull && !prUnitEnabled || !issue.IsPull && !issueUnitEnabled { - ctx.NotFound("IssueOrPullRequestUnitNotAllowed", nil) - return nil - } - if err = issue.LoadAttributes(ctx); err != nil { - ctx.ServerError("LoadAttributes", err) - return nil - } - } - return issues -} - -// UpdateIssueProject change an issue's project -func UpdateIssueProject(ctx *context.Context) { - issues := getActionIssues(ctx) - if ctx.Written() { - return - } - - if err := issues.LoadProjects(ctx); err != nil { - ctx.ServerError("LoadProjects", err) - return - } - - projectID := ctx.FormInt64("id") - for _, issue := range issues { - if issue.Project != nil { - if issue.Project.ID == projectID { - continue - } - } - - if err := issues_model.ChangeProjectAssign(ctx, issue, ctx.Doer, projectID); err != nil { - ctx.ServerError("ChangeProjectAssign", err) - return - } - } - - ctx.JSONOK() -} - // DeleteProjectBoard allows for the deletion of a project board func DeleteProjectBoard(ctx *context.Context) { if ctx.Doer == nil { diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go index 9b765e89e8..6186ee150c 100644 --- a/routers/web/repo/projects.go +++ b/routers/web/repo/projects.go @@ -21,6 +21,7 @@ import ( "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" @@ -383,17 +384,21 @@ func UpdateIssueProject(ctx *context.Context) { ctx.ServerError("LoadProjects", err) return } + if _, err := issues.LoadRepositories(ctx); err != nil { + ctx.ServerError("LoadProjects", err) + return + } projectID := ctx.FormInt64("id") for _, issue := range issues { - if issue.Project != nil { - if issue.Project.ID == projectID { + if issue.Project != nil && issue.Project.ID == projectID { + continue + } + if err := issues_model.IssueAssignOrRemoveProject(ctx, issue, ctx.Doer, projectID, 0); err != nil { + if errors.Is(err, util.ErrPermissionDenied) { continue } - } - - if err := issues_model.ChangeProjectAssign(ctx, issue, ctx.Doer, projectID); err != nil { - ctx.ServerError("ChangeProjectAssign", err) + ctx.ServerError("IssueAssignOrRemoveProject", err) return } } diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 7f131f2e98..7041175d9a 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -1329,14 +1329,12 @@ func CompareAndPullRequestPost(ctx *context.Context) { return } - if projectID > 0 { - if !ctx.Repo.CanWrite(unit.TypeProjects) { - ctx.Error(http.StatusBadRequest, "user hasn't the permission to write to projects") - return - } - if err := issues_model.ChangeProjectAssign(ctx, pullIssue, ctx.Doer, projectID); err != nil { - ctx.ServerError("ChangeProjectAssign", err) - return + if projectID > 0 && ctx.Repo.CanWrite(unit.TypeProjects) { + if err := issues_model.IssueAssignOrRemoveProject(ctx, pullIssue, ctx.Doer, projectID, 0); err != nil { + if !errors.Is(err, util.ErrPermissionDenied) { + ctx.ServerError("IssueAssignOrRemoveProject", err) + return + } } } diff --git a/routers/web/shared/project/column.go b/routers/web/shared/project/column.go new file mode 100644 index 0000000000..599842ea9e --- /dev/null +++ b/routers/web/shared/project/column.go @@ -0,0 +1,48 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package project + +import ( + project_model "code.gitea.io/gitea/models/project" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/services/context" +) + +// MoveColumns moves or keeps columns in a project and sorts them inside that project +func MoveColumns(ctx *context.Context) { + project, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id")) + if err != nil { + ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err) + return + } + if !project.CanBeAccessedByOwnerRepo(ctx.ContextUser.ID, ctx.Repo.Repository) { + ctx.NotFound("CanBeAccessedByOwnerRepo", nil) + return + } + + type movedColumnsForm struct { + Columns []struct { + ColumnID int64 `json:"columnID"` + Sorting int64 `json:"sorting"` + } `json:"columns"` + } + + form := &movedColumnsForm{} + if err = json.NewDecoder(ctx.Req.Body).Decode(&form); err != nil { + ctx.ServerError("DecodeMovedColumnsForm", err) + return + } + + sortedColumnIDs := make(map[int64]int64) + for _, column := range form.Columns { + sortedColumnIDs[column.Sorting] = column.ColumnID + } + + if err = project_model.MoveColumnsOnProject(ctx, project, sortedColumnIDs); err != nil { + ctx.ServerError("MoveColumnsOnProject", err) + return + } + + ctx.JSONOK() +} diff --git a/routers/web/web.go b/routers/web/web.go index 91ab378d97..e1482c1e4a 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -37,6 +37,7 @@ import ( "code.gitea.io/gitea/routers/web/repo" "code.gitea.io/gitea/routers/web/repo/actions" repo_setting "code.gitea.io/gitea/routers/web/repo/setting" + "code.gitea.io/gitea/routers/web/shared/project" "code.gitea.io/gitea/routers/web/user" user_setting "code.gitea.io/gitea/routers/web/user/setting" "code.gitea.io/gitea/routers/web/user/setting/security" @@ -999,6 +1000,7 @@ func registerRoutes(m *web.Route) { m.Post("/new", web.Bind(forms.CreateProjectForm{}), org.NewProjectPost) m.Group("/{id}", func() { m.Post("", web.Bind(forms.EditProjectBoardForm{}), org.AddBoardToProjectPost) + m.Post("/move", project.MoveColumns) m.Post("/delete", org.DeleteProject) m.Get("/edit", org.RenderEditProject) @@ -1354,6 +1356,7 @@ func registerRoutes(m *web.Route) { m.Post("/new", web.Bind(forms.CreateProjectForm{}), repo.NewProjectPost) m.Group("/{id}", func() { m.Post("", web.Bind(forms.EditProjectBoardForm{}), repo.AddBoardToProjectPost) + m.Post("/move", project.MoveColumns) m.Post("/delete", repo.DeleteProject) m.Get("/edit", repo.RenderEditProject) diff --git a/services/issue/issue.go b/services/issue/issue.go index b0e50f2b89..72ea66c8d9 100644 --- a/services/issue/issue.go +++ b/services/issue/issue.go @@ -42,7 +42,7 @@ func NewIssue(ctx context.Context, repo *repo_model.Repository, issue *issues_mo } } if projectID > 0 { - if err := issues_model.ChangeProjectAssign(ctx, issue, issue.Poster, projectID); err != nil { + if err := issues_model.IssueAssignOrRemoveProject(ctx, issue, issue.Poster, projectID, 0); err != nil { return err } } diff --git a/templates/projects/view.tmpl b/templates/projects/view.tmpl index 3e000660e2..47f214a44e 100644 --- a/templates/projects/view.tmpl +++ b/templates/projects/view.tmpl @@ -64,7 +64,7 @@ </div> <div id="project-board"> - <div class="board {{if .CanWriteProjects}}sortable{{end}}"> + <div class="board {{if .CanWriteProjects}}sortable{{end}}"{{if .CanWriteProjects}} data-url="{{$.Link}}/move"{{end}}> {{range .Columns}} <div class="ui segment project-column"{{if .Color}} style="background: {{.Color}} !important; color: {{ContrastColor .Color}} !important"{{end}} data-id="{{.ID}}" data-sorting="{{.Sorting}}" data-url="{{$.Link}}/{{.ID}}"> <div class="project-column-header{{if $canWriteProject}} tw-cursor-grab{{end}}"> diff --git a/tests/integration/org_project_test.go b/tests/integration/org_project_test.go index a14004f6b0..ca39cf5130 100644 --- a/tests/integration/org_project_test.go +++ b/tests/integration/org_project_test.go @@ -5,17 +5,17 @@ package integration import ( "net/http" + "slices" "testing" unit_model "code.gitea.io/gitea/models/unit" + "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/tests" ) func TestOrgProjectAccess(t *testing.T) { defer tests.PrepareTestEnv(t)() - - // disable repo project unit - unit_model.DisabledRepoUnits = []unit_model.Type{unit_model.TypeProjects} + defer test.MockVariableValue(&unit_model.DisabledRepoUnits, append(slices.Clone(unit_model.DisabledRepoUnits), unit_model.TypeProjects))() // repo project, 404 req := NewRequest(t, "GET", "/user2/repo1/projects") diff --git a/tests/integration/project_test.go b/tests/integration/project_test.go index 45061c5b24..1d9c3aae53 100644 --- a/tests/integration/project_test.go +++ b/tests/integration/project_test.go @@ -4,10 +4,18 @@ package integration import ( + "fmt" "net/http" "testing" + "code.gitea.io/gitea/models/db" + project_model "code.gitea.io/gitea/models/project" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unit" + "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/tests" + + "github.com/stretchr/testify/assert" ) func TestPrivateRepoProject(t *testing.T) { @@ -21,3 +29,59 @@ func TestPrivateRepoProject(t *testing.T) { req = NewRequest(t, "GET", "/user31/-/projects") sess.MakeRequest(t, req, http.StatusOK) } + +func TestMoveRepoProjectColumns(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) + + projectsUnit := repo2.MustGetUnit(db.DefaultContext, unit.TypeProjects) + assert.True(t, projectsUnit.ProjectsConfig().IsProjectsAllowed(repo_model.ProjectsModeRepo)) + + project1 := project_model.Project{ + Title: "new created project", + RepoID: repo2.ID, + Type: project_model.TypeRepository, + BoardType: project_model.BoardTypeNone, + } + err := project_model.NewProject(db.DefaultContext, &project1) + assert.NoError(t, err) + + for i := 0; i < 3; i++ { + err = project_model.NewBoard(db.DefaultContext, &project_model.Board{ + Title: fmt.Sprintf("column %d", i+1), + ProjectID: project1.ID, + }) + assert.NoError(t, err) + } + + columns, err := project1.GetBoards(db.DefaultContext) + assert.NoError(t, err) + assert.Len(t, columns, 3) + assert.EqualValues(t, 0, columns[0].Sorting) + assert.EqualValues(t, 1, columns[1].Sorting) + assert.EqualValues(t, 2, columns[2].Sorting) + + sess := loginUser(t, "user1") + req := NewRequest(t, "GET", fmt.Sprintf("/%s/projects/%d", repo2.FullName(), project1.ID)) + resp := sess.MakeRequest(t, req, http.StatusOK) + htmlDoc := NewHTMLParser(t, resp.Body) + + req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/%s/projects/%d/move?_csrf="+htmlDoc.GetCSRF(), repo2.FullName(), project1.ID), map[string]any{ + "columns": []map[string]any{ + {"columnID": columns[1].ID, "sorting": 0}, + {"columnID": columns[2].ID, "sorting": 1}, + {"columnID": columns[0].ID, "sorting": 2}, + }, + }) + sess.MakeRequest(t, req, http.StatusOK) + + columnsAfter, err := project1.GetBoards(db.DefaultContext) + assert.NoError(t, err) + assert.Len(t, columns, 3) + assert.EqualValues(t, columns[1].ID, columnsAfter[0].ID) + assert.EqualValues(t, columns[2].ID, columnsAfter[1].ID) + assert.EqualValues(t, columns[0].ID, columnsAfter[2].ID) + + assert.NoError(t, project_model.DeleteProjectByID(db.DefaultContext, project1.ID)) +} diff --git a/web_src/js/features/repo-projects.js b/web_src/js/features/repo-projects.js index a869c24c82..a1cc4b346b 100644 --- a/web_src/js/features/repo-projects.js +++ b/web_src/js/features/repo-projects.js @@ -2,7 +2,6 @@ import $ from 'jquery'; import {contrastColor} from '../utils/color.js'; import {createSortable} from '../modules/sortable.js'; import {POST, DELETE, PUT} from '../modules/fetch.js'; -import tinycolor from 'tinycolor2'; function updateIssueCount(cards) { const parent = cards.parentElement; @@ -63,17 +62,20 @@ async function initRepoProjectSortable() { delay: 500, onSort: async () => { boardColumns = mainBoard.getElementsByClassName('project-column'); - for (let i = 0; i < boardColumns.length; i++) { - const column = boardColumns[i]; - if (parseInt(column.getAttribute('data-sorting')) !== i) { - try { - const bgColor = column.style.backgroundColor; // will be rgb() string - const color = bgColor ? tinycolor(bgColor).toHexString() : ''; - await PUT(column.getAttribute('data-url'), {data: {sorting: i, color}}); - } catch (error) { - console.error(error); - } - } + + const columnSorting = { + columns: Array.from(boardColumns, (column, i) => ({ + columnID: parseInt(column.getAttribute('data-id')), + sorting: i, + })), + }; + + try { + await POST(mainBoard.getAttribute('data-url'), { + data: columnSorting, + }); + } catch (error) { + console.error(error); } }, }); From f09e68ec33262d5356779572a0b1c66e6e86590f Mon Sep 17 00:00:00 2001 From: Zettat123 <zettat123@gmail.com> Date: Wed, 8 May 2024 22:45:15 +0800 Subject: [PATCH 292/370] Update issue indexer after merging a PR (#30715) Fix #30684 --- services/indexer/notify.go | 16 ++++++++ tests/integration/pull_merge_test.go | 61 ++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/services/indexer/notify.go b/services/indexer/notify.go index f1e21a2d40..e2cfe477d3 100644 --- a/services/indexer/notify.go +++ b/services/indexer/notify.go @@ -152,3 +152,19 @@ func (r *indexerNotifier) IssueChangeLabels(ctx context.Context, doer *user_mode func (r *indexerNotifier) IssueClearLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) { issue_indexer.UpdateIssueIndexer(ctx, issue.ID) } + +func (r *indexerNotifier) MergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { + if err := pr.LoadIssue(ctx); err != nil { + log.Error("LoadIssue: %v", err) + return + } + issue_indexer.UpdateIssueIndexer(ctx, pr.Issue.ID) +} + +func (r *indexerNotifier) AutoMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { + if err := pr.LoadIssue(ctx); err != nil { + log.Error("LoadIssue: %v", err) + return + } + issue_indexer.UpdateIssueIndexer(ctx, pr.Issue.ID) +} diff --git a/tests/integration/pull_merge_test.go b/tests/integration/pull_merge_test.go index daf411f452..826568caf2 100644 --- a/tests/integration/pull_merge_test.go +++ b/tests/integration/pull_merge_test.go @@ -26,6 +26,7 @@ import ( "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" + "code.gitea.io/gitea/modules/queue" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/translation" @@ -587,3 +588,63 @@ func TestPullDontRetargetChildOnWrongRepo(t *testing.T) { assert.EqualValues(t, "Closed", prStatus) }) } + +func TestPullMergeIndexerNotifier(t *testing.T) { + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + // create a pull request + session := loginUser(t, "user1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") + createPullResp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "Indexer notifier test pull") + + assert.NoError(t, queue.GetManager().FlushAll(context.Background(), 0)) + time.Sleep(time.Second) + + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ + OwnerName: "user2", + Name: "repo1", + }) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ + RepoID: repo1.ID, + Title: "Indexer notifier test pull", + IsPull: true, + IsClosed: false, + }) + + // build the request for searching issues + link, _ := url.Parse("/api/v1/repos/issues/search") + query := url.Values{} + query.Add("state", "closed") + query.Add("type", "pulls") + query.Add("q", "notifier") + link.RawQuery = query.Encode() + + // search issues + searchIssuesResp := session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK) + var apiIssuesBefore []*api.Issue + DecodeJSON(t, searchIssuesResp, &apiIssuesBefore) + assert.Len(t, apiIssuesBefore, 0) + + // merge the pull request + elem := strings.Split(test.RedirectURL(createPullResp), "/") + assert.EqualValues(t, "pulls", elem[3]) + testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleMerge, false) + + // check if the issue is closed + issue = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ + ID: issue.ID, + }) + assert.True(t, issue.IsClosed) + + assert.NoError(t, queue.GetManager().FlushAll(context.Background(), 0)) + time.Sleep(time.Second) + + // search issues again + searchIssuesResp = session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK) + var apiIssuesAfter []*api.Issue + DecodeJSON(t, searchIssuesResp, &apiIssuesAfter) + if assert.Len(t, apiIssuesAfter, 1) { + assert.Equal(t, issue.ID, apiIssuesAfter[0].ID) + } + }) +} From 3fdb2d4ad8a3bf4c5fbcc417a274be2fc695882b Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Wed, 8 May 2024 23:39:13 +0800 Subject: [PATCH 293/370] Fix incorrect issue form (#30881) Fix #30864 --- .../repo/issue/branch_selector_field.tmpl | 6 +---- web_src/js/features/repo-legacy.js | 27 ++++++++----------- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/templates/repo/issue/branch_selector_field.tmpl b/templates/repo/issue/branch_selector_field.tmpl index cbf7929fdb..5793a8bfda 100644 --- a/templates/repo/issue/branch_selector_field.tmpl +++ b/templates/repo/issue/branch_selector_field.tmpl @@ -1,12 +1,8 @@ {{if and (not .Issue.IsPull) (not .PageIsComparePull)}} <input id="ref_selector" name="ref" type="hidden" value="{{.Reference}}"> -<input id="editing_mode" name="edit_mode" type="hidden" value="{{(or .IsIssueWriter .HasIssuesOrPullsWritePermission)}}"> -<form method="post" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/ref" id="update_issueref_form"> - {{$.CsrfTokenHtml}} -</form> <div class="ui dropdown select-branch branch-selector-dropdown ellipsis-items-nowrap {{if not .HasIssuesOrPullsWritePermission}}disabled{{end}}" data-no-results="{{ctx.Locale.Tr "no_results_found"}}" - {{if not .Issue}}data-for-new-issue="true"{{end}} + {{if and .Issue (or .IsIssueWriter .HasIssuesOrPullsWritePermission)}}data-url-update-issueref="{{$.RepoLink}}/issues/{{.Issue.Index}}/ref"{{end}} > <div class="ui button branch-dropdown-button"> <span class="text-branch-name gt-ellipsis">{{if .Reference}}{{$.RefEndName}}{{else}}{{ctx.Locale.Tr "repo.issues.no_ref"}}{{end}}</span> diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index b65938b045..2323d818c2 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -58,32 +58,27 @@ export function initRepoCommentForm() { function initBranchSelector() { const elSelectBranch = document.querySelector('.ui.dropdown.select-branch'); if (!elSelectBranch) return; - const isForNewIssue = elSelectBranch.getAttribute('data-for-new-issue') === 'true'; + const urlUpdateIssueRef = elSelectBranch.getAttribute('data-url-update-issueref'); const $selectBranch = $(elSelectBranch); const $branchMenu = $selectBranch.find('.reference-list-menu'); $branchMenu.find('.item:not(.no-select)').on('click', async function (e) { e.preventDefault(); - const selectedValue = $(this).data('id'); // eg: "refs/heads/my-branch" - const editMode = $('#editing_mode').val(); - $($(this).data('id-selector')).val(selectedValue); - if (isForNewIssue) { - elSelectBranch.querySelector('.text-branch-name').textContent = this.getAttribute('data-name'); - return; // only update UI&form, do not send request/reload - } - - if (editMode === 'true') { - const form = document.getElementById('update_issueref_form'); - const params = new URLSearchParams(); - params.append('ref', selectedValue); + const selectedValue = this.getAttribute('data-id'); // eg: "refs/heads/my-branch" + const selectedText = this.getAttribute('data-name'); // eg: "my-branch" + if (urlUpdateIssueRef) { + // for existing issue, send request to update issue ref, and reload page try { - await POST(form.getAttribute('action'), {data: params}); + await POST(urlUpdateIssueRef, {data: new URLSearchParams({ref: selectedValue})}); window.location.reload(); } catch (error) { console.error(error); } - } else if (editMode === '') { - $selectBranch.find('.ui .branch-name').text(selectedValue); + } else { + // for new issue, only update UI&form, do not send request/reload + const selectedHiddenSelector = this.getAttribute('data-id-selector'); + document.querySelector(selectedHiddenSelector).value = selectedValue; + elSelectBranch.querySelector('.text-branch-name').textContent = selectedText; } }); $selectBranch.find('.reference.column').on('click', function () { From f7d2f695a4c57b245830a526e77fa62e99e00254 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 9 May 2024 01:11:43 +0900 Subject: [PATCH 294/370] Fix misspelling of mergable (#30896) https://github.com/go-gitea/gitea/pull/25812#issuecomment-2099833692 Follow #30573 --- routers/api/v1/repo/pull.go | 4 ++-- routers/web/repo/pull.go | 4 ++-- services/automerge/automerge.go | 4 ++-- services/pull/check.go | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index 8bd4ddf64b..38a32a73c7 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -881,7 +881,7 @@ func MergePullRequest(ctx *context.APIContext) { } // start with merging by checking - if err := pull_service.CheckPullMergable(ctx, ctx.Doer, &ctx.Repo.Permission, pr, mergeCheckType, form.ForceMerge); err != nil { + if err := pull_service.CheckPullMergeable(ctx, ctx.Doer, &ctx.Repo.Permission, pr, mergeCheckType, form.ForceMerge); err != nil { if errors.Is(err, pull_service.ErrIsClosed) { ctx.NotFound() } else if errors.Is(err, pull_service.ErrUserNotAllowedToMerge) { @@ -890,7 +890,7 @@ func MergePullRequest(ctx *context.APIContext) { ctx.Error(http.StatusMethodNotAllowed, "PR already merged", "") } else if errors.Is(err, pull_service.ErrIsWorkInProgress) { ctx.Error(http.StatusMethodNotAllowed, "PR is a work in progress", "Work in progress PRs cannot be merged") - } else if errors.Is(err, pull_service.ErrNotMergableState) { + } else if errors.Is(err, pull_service.ErrNotMergeableState) { ctx.Error(http.StatusMethodNotAllowed, "PR not in mergeable state", "Please try again later") } else if models.IsErrDisallowedToMerge(err) { ctx.Error(http.StatusMethodNotAllowed, "PR is not ready to be merged", err) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 7041175d9a..bbdc6ca631 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -1007,7 +1007,7 @@ func MergePullRequest(ctx *context.Context) { } // start with merging by checking - if err := pull_service.CheckPullMergable(ctx, ctx.Doer, &ctx.Repo.Permission, pr, mergeCheckType, form.ForceMerge); err != nil { + if err := pull_service.CheckPullMergeable(ctx, ctx.Doer, &ctx.Repo.Permission, pr, mergeCheckType, form.ForceMerge); err != nil { switch { case errors.Is(err, pull_service.ErrIsClosed): if issue.IsPull { @@ -1021,7 +1021,7 @@ func MergePullRequest(ctx *context.Context) { ctx.JSONError(ctx.Tr("repo.pulls.has_merged")) case errors.Is(err, pull_service.ErrIsWorkInProgress): ctx.JSONError(ctx.Tr("repo.pulls.no_merge_wip")) - case errors.Is(err, pull_service.ErrNotMergableState): + case errors.Is(err, pull_service.ErrNotMergeableState): ctx.JSONError(ctx.Tr("repo.pulls.no_merge_not_ready")) case models.IsErrDisallowedToMerge(err): ctx.JSONError(ctx.Tr("repo.pulls.no_merge_not_ready")) diff --git a/services/automerge/automerge.go b/services/automerge/automerge.go index bd427bef9f..bd1317c7f4 100644 --- a/services/automerge/automerge.go +++ b/services/automerge/automerge.go @@ -229,12 +229,12 @@ func handlePull(pullID int64, sha string) { return } - if err := pull_service.CheckPullMergable(ctx, doer, &perm, pr, pull_service.MergeCheckTypeGeneral, false); err != nil { + if err := pull_service.CheckPullMergeable(ctx, doer, &perm, pr, pull_service.MergeCheckTypeGeneral, false); err != nil { if errors.Is(pull_service.ErrUserNotAllowedToMerge, err) { log.Info("%-v was scheduled to automerge by an unauthorized user", pr) return } - log.Error("%-v CheckPullMergable: %v", pr, err) + log.Error("%-v CheckPullMergeable: %v", pr, err) return } diff --git a/services/pull/check.go b/services/pull/check.go index 9495e8ad5f..7d93ff7a8a 100644 --- a/services/pull/check.go +++ b/services/pull/check.go @@ -39,7 +39,7 @@ var ( ErrHasMerged = errors.New("has already been merged") ErrIsWorkInProgress = errors.New("work in progress PRs cannot be merged") ErrIsChecking = errors.New("cannot merge while conflict checking is in progress") - ErrNotMergableState = errors.New("not in mergeable state") + ErrNotMergeableState = errors.New("not in mergeable state") ErrDependenciesLeft = errors.New("is blocked by an open dependency") ) @@ -66,8 +66,8 @@ const ( MergeCheckTypeAuto // Auto Merge (Scheduled Merge) After Checks Succeed ) -// CheckPullMergable check if the pull mergeable based on all conditions (branch protection, merge options, ...) -func CheckPullMergable(stdCtx context.Context, doer *user_model.User, perm *access_model.Permission, pr *issues_model.PullRequest, mergeCheckType MergeCheckType, adminSkipProtectionCheck bool) error { +// CheckPullMergeable check if the pull mergeable based on all conditions (branch protection, merge options, ...) +func CheckPullMergeable(stdCtx context.Context, doer *user_model.User, perm *access_model.Permission, pr *issues_model.PullRequest, mergeCheckType MergeCheckType, adminSkipProtectionCheck bool) error { return db.WithTx(stdCtx, func(ctx context.Context) error { if pr.HasMerged { return ErrHasMerged @@ -97,7 +97,7 @@ func CheckPullMergable(stdCtx context.Context, doer *user_model.User, perm *acce } if !pr.CanAutoMerge() && !pr.IsEmpty() { - return ErrNotMergableState + return ErrNotMergeableState } if pr.IsChecking() { From ed0fc2729e75f84992521e3c8e54357b83cc4a36 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Thu, 9 May 2024 07:01:25 +0800 Subject: [PATCH 295/370] Add missing menu active item background back (#30897) Fix #30578 --- web_src/css/modules/menu.css | 1 + 1 file changed, 1 insertion(+) diff --git a/web_src/css/modules/menu.css b/web_src/css/modules/menu.css index 830e4cdbc3..76a576cd53 100644 --- a/web_src/css/modules/menu.css +++ b/web_src/css/modules/menu.css @@ -358,6 +358,7 @@ } .ui.vertical.menu .active.item { + background: var(--color-active); border-radius: 0; } .ui.vertical.menu > .active.item:first-child { From e94723f2de7d9bf12d870f5ce9ffb291a99ba090 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 9 May 2024 17:44:26 +0900 Subject: [PATCH 296/370] Fix incorrect default branch when adopt a repository (#30912) Fix #30521 we should sync branches first, then detect default branch, or `git_model.FindBranchNames` will always return empty list, and the detection will be wrong. --- services/repository/adopt.go | 37 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/services/repository/adopt.go b/services/repository/adopt.go index f4d0da67a5..3d6fe71a09 100644 --- a/services/repository/adopt.go +++ b/services/repository/adopt.go @@ -36,10 +36,6 @@ func AdoptRepository(ctx context.Context, doer, u *user_model.User, opts CreateR } } - if len(opts.DefaultBranch) == 0 { - opts.DefaultBranch = setting.Repository.DefaultBranch - } - repo := &repo_model.Repository{ OwnerID: u.ID, Owner: u, @@ -81,7 +77,7 @@ func AdoptRepository(ctx context.Context, doer, u *user_model.User, opts CreateR } if err := adoptRepository(ctx, repoPath, repo, opts.DefaultBranch); err != nil { - return fmt.Errorf("createDelegateHooks: %w", err) + return fmt.Errorf("adoptRepository: %w", err) } if err := repo_module.CheckDaemonExportOK(ctx, repo); err != nil { @@ -143,6 +139,21 @@ func adoptRepository(ctx context.Context, repoPath string, repo *repo_model.Repo } } + // Don't bother looking this repo in the context it won't be there + gitRepo, err := gitrepo.OpenRepository(ctx, repo) + if err != nil { + return fmt.Errorf("openRepository: %w", err) + } + defer gitRepo.Close() + + if _, err = repo_module.SyncRepoBranchesWithRepo(ctx, repo, gitRepo, 0); err != nil { + return fmt.Errorf("SyncRepoBranchesWithRepo: %w", err) + } + + if err = repo_module.SyncReleasesWithTags(ctx, repo, gitRepo); err != nil { + return fmt.Errorf("SyncReleasesWithTags: %w", err) + } + branches, _ := git_model.FindBranchNames(ctx, git_model.FindBranchOptions{ RepoID: repo.ID, ListOptions: db.ListOptionsAll, @@ -183,26 +194,10 @@ func adoptRepository(ctx context.Context, repoPath string, repo *repo_model.Repo return fmt.Errorf("setDefaultBranch: %w", err) } } - if err = repo_module.UpdateRepository(ctx, repo, false); err != nil { return fmt.Errorf("updateRepository: %w", err) } - // Don't bother looking this repo in the context it won't be there - gitRepo, err := gitrepo.OpenRepository(ctx, repo) - if err != nil { - return fmt.Errorf("openRepository: %w", err) - } - defer gitRepo.Close() - - if _, err = repo_module.SyncRepoBranchesWithRepo(ctx, repo, gitRepo, 0); err != nil { - return fmt.Errorf("SyncRepoBranches: %w", err) - } - - if err = repo_module.SyncReleasesWithTags(ctx, repo, gitRepo); err != nil { - return fmt.Errorf("SyncReleasesWithTags: %w", err) - } - return nil } From b9396a9b852e4fea0e2c39ef3ef2fdfbc9ea248a Mon Sep 17 00:00:00 2001 From: Jason Song <i@wolfogre.com> Date: Fri, 10 May 2024 16:23:47 +0800 Subject: [PATCH 297/370] Remove deprecated stuff for runners (#30930) It's time (maybe somewhat late) to remove some deprecated stuff for the runner. - `x-runner-version`: runners needn't to report version in every request, they will call `Declare`. - `AgentLabels`: runners will report them as `Labels`. --- routers/api/actions/runner/interceptor.go | 13 ------------- routers/api/actions/runner/runner.go | 6 ------ 2 files changed, 19 deletions(-) diff --git a/routers/api/actions/runner/interceptor.go b/routers/api/actions/runner/interceptor.go index 0e99f3deda..521ba910e3 100644 --- a/routers/api/actions/runner/interceptor.go +++ b/routers/api/actions/runner/interceptor.go @@ -23,8 +23,6 @@ import ( const ( uuidHeaderKey = "x-runner-uuid" tokenHeaderKey = "x-runner-token" - // Deprecated: will be removed after Gitea 1.20 released. - versionHeaderKey = "x-runner-version" ) var withRunner = connect.WithInterceptors(connect.UnaryInterceptorFunc(func(unaryFunc connect.UnaryFunc) connect.UnaryFunc { @@ -35,9 +33,6 @@ var withRunner = connect.WithInterceptors(connect.UnaryInterceptorFunc(func(unar } uuid := request.Header().Get(uuidHeaderKey) token := request.Header().Get(tokenHeaderKey) - // TODO: version will be removed from request header after Gitea 1.20 released. - // And Gitea will not try to read version from request header - version := request.Header().Get(versionHeaderKey) runner, err := actions_model.GetRunnerByUUID(ctx, uuid) if err != nil { @@ -51,14 +46,6 @@ var withRunner = connect.WithInterceptors(connect.UnaryInterceptorFunc(func(unar } cols := []string{"last_online"} - - // TODO: version will be removed from request header after Gitea 1.20 released. - // And Gitea will not try to read version from request header - version, _ = util.SplitStringAtByteN(version, 64) - if !util.IsEmptyString(version) && runner.Version != version { - runner.Version = version - cols = append(cols, "version") - } runner.LastOnline = timeutil.TimeStampNow() if methodName == "UpdateTask" || methodName == "UpdateLog" { runner.LastActive = timeutil.TimeStampNow() diff --git a/routers/api/actions/runner/runner.go b/routers/api/actions/runner/runner.go index b2f3e7af78..d4078d8af2 100644 --- a/routers/api/actions/runner/runner.go +++ b/routers/api/actions/runner/runner.go @@ -67,12 +67,6 @@ func (s *Service) Register( } labels := req.Msg.Labels - // TODO: agent_labels should be removed from pb after Gitea 1.20 released. - // Old version runner's agent_labels slice is not empty and labels slice is empty. - // And due to compatibility with older versions, it is temporarily marked as Deprecated in pb, so use `//nolint` here. - if len(req.Msg.AgentLabels) > 0 && len(req.Msg.Labels) == 0 { //nolint:staticcheck - labels = req.Msg.AgentLabels //nolint:staticcheck - } // create new runner name, _ := util.SplitStringAtByteN(req.Msg.Name, 255) From 7424f27cf30065a1308aa3ba4d75ea82c0af4af9 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Fri, 10 May 2024 20:07:01 +0800 Subject: [PATCH 298/370] Check if reverse proxy is correctly configured (#30890) Follow #27011 Follow #30885 --------- Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: Giteabot <teabot@gitea.io> --- options/locale/locale_en-US.ini | 1 + routers/web/admin/admin.go | 12 ++++++++++ routers/web/admin/admin_test.go | 24 ++++++++++++++++++++ routers/web/web.go | 1 + services/context/base.go | 3 ++- services/contexttest/context_tests.go | 2 +- templates/admin/self_check.tmpl | 28 ++++++++++++----------- web_src/js/bootstrap.js | 6 ++--- web_src/js/features/admin/selfcheck.js | 31 ++++++++++++++++++++++++++ web_src/js/features/common-global.js | 2 +- web_src/js/index.js | 2 ++ 11 files changed, 93 insertions(+), 19 deletions(-) create mode 100644 web_src/js/features/admin/selfcheck.js diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index eef4f5696a..6a08041a7c 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -3320,6 +3320,7 @@ self_check.database_collation_case_insensitive = Database is using a collation % self_check.database_inconsistent_collation_columns = Database is using collation %s, but these columns are using mismatched collations. It might cause some unexpected problems. self_check.database_fix_mysql = For MySQL/MariaDB users, you could use the "gitea doctor convert" command to fix the collation problems, or you could also fix the problem by "ALTER ... COLLATE ..." SQLs manually. self_check.database_fix_mssql = For MSSQL users, you could only fix the problem by "ALTER ... COLLATE ..." SQLs manually at the moment. +self_check.location_origin_mismatch = Current URL (%[1]s) doesn't match the URL seen by Gitea (%[2]s). If you are using a reverse proxy, please make sure the "Host" and "X-Forwarded-Proto" headers are set correctly. [action] create_repo = created repository <a href="%s">%s</a> diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go index 3dd3c9670f..dee1650b5a 100644 --- a/routers/web/admin/admin.go +++ b/routers/web/admin/admin.go @@ -9,12 +9,14 @@ import ( "net/http" "runtime" "sort" + "strings" "time" activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/modules/httplib" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" @@ -223,6 +225,16 @@ func SelfCheck(ctx *context.Context) { ctx.HTML(http.StatusOK, tplSelfCheck) } +func SelfCheckPost(ctx *context.Context) { + var problems []string + frontendAppURL := ctx.FormString("location_origin") + setting.AppSubURL + "/" + ctxAppURL := httplib.GuessCurrentAppURL(ctx) + if !strings.HasPrefix(ctxAppURL, frontendAppURL) { + problems = append(problems, ctx.Locale.TrString("admin.self_check.location_origin_mismatch", frontendAppURL, ctxAppURL)) + } + ctx.JSON(http.StatusOK, map[string]any{"problems": problems}) +} + func CronTasks(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("admin.monitor.cron") ctx.Data["PageIsAdminMonitorCron"] = true diff --git a/routers/web/admin/admin_test.go b/routers/web/admin/admin_test.go index 2b65ab3ea3..782126adf5 100644 --- a/routers/web/admin/admin_test.go +++ b/routers/web/admin/admin_test.go @@ -4,8 +4,14 @@ package admin import ( + "net/http" "testing" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" + "code.gitea.io/gitea/services/contexttest" + "github.com/stretchr/testify/assert" ) @@ -66,3 +72,21 @@ func TestShadowPassword(t *testing.T) { assert.EqualValues(t, k.Result, shadowPassword(k.Provider, k.CfgItem)) } } + +func TestSelfCheckPost(t *testing.T) { + defer test.MockVariableValue(&setting.AppURL, "http://config/sub/")() + defer test.MockVariableValue(&setting.AppSubURL, "/sub")() + + ctx, resp := contexttest.MockContext(t, "GET http://host/sub/admin/self_check?location_origin=http://frontend") + SelfCheckPost(ctx) + assert.EqualValues(t, http.StatusOK, resp.Code) + + data := struct { + Problems []string `json:"problems"` + }{} + err := json.Unmarshal(resp.Body.Bytes(), &data) + assert.NoError(t, err) + assert.Equal(t, []string{ + ctx.Locale.TrString("admin.self_check.location_origin_mismatch", "http://frontend/sub/", "http://host/sub/"), + }, data.Problems) +} diff --git a/routers/web/web.go b/routers/web/web.go index e1482c1e4a..f3b9969059 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -686,6 +686,7 @@ func registerRoutes(m *web.Route) { m.Post("", web.Bind(forms.AdminDashboardForm{}), admin.DashboardPost) m.Get("/self_check", admin.SelfCheck) + m.Post("/self_check", admin.SelfCheckPost) m.Group("/config", func() { m.Get("", admin.Config) diff --git a/services/context/base.go b/services/context/base.go index 29e62ae389..23f0bcfc33 100644 --- a/services/context/base.go +++ b/services/context/base.go @@ -309,7 +309,8 @@ func NewBaseContext(resp http.ResponseWriter, req *http.Request) (b *Base, close Locale: middleware.Locale(resp, req), Data: middleware.GetContextData(req.Context()), } - b.AppendContextValue(translation.ContextKey, b.Locale) b.Req = b.Req.WithContext(b) + b.AppendContextValue(translation.ContextKey, b.Locale) + b.AppendContextValue(httplib.RequestContextKey, b.Req) return b, b.cleanUp } diff --git a/services/contexttest/context_tests.go b/services/contexttest/context_tests.go index 5624d24058..3c3fa76e3c 100644 --- a/services/contexttest/context_tests.go +++ b/services/contexttest/context_tests.go @@ -39,7 +39,7 @@ func mockRequest(t *testing.T, reqPath string) *http.Request { } requestURL, err := url.Parse(path) assert.NoError(t, err) - req := &http.Request{Method: method, URL: requestURL, Form: maps.Clone(requestURL.Query()), Header: http.Header{}} + req := &http.Request{Method: method, Host: requestURL.Host, URL: requestURL, Form: maps.Clone(requestURL.Query()), Header: http.Header{}} req = req.WithContext(middleware.WithContextData(req.Context())) return req } diff --git a/templates/admin/self_check.tmpl b/templates/admin/self_check.tmpl index a6c2ac1ac9..b249bf228e 100644 --- a/templates/admin/self_check.tmpl +++ b/templates/admin/self_check.tmpl @@ -1,4 +1,4 @@ -{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin config")}} +{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin")}} <div class="admin-setting-content"> <h4 class="ui top attached header"> @@ -6,7 +6,7 @@ </h4> {{if .StartupProblems}} - <div class="ui attached segment"> + <div class="ui attached segment self-check-problem"> <div class="ui warning message"> <div>{{ctx.Locale.Tr "admin.self_check.startup_warnings"}}</div> <ul class="tw-w-full">{{range .StartupProblems}}<li>{{.}}</li>{{end}}</ul> @@ -14,8 +14,10 @@ </div> {{end}} + <div class="ui attached segment tw-hidden self-check-problem" id="self-check-by-frontend"></div> + {{if .DatabaseCheckHasProblems}} - <div class="ui attached segment"> + <div class="ui attached segment self-check-problem"> {{if .DatabaseType.IsMySQL}} <div class="tw-p-2">{{ctx.Locale.Tr "admin.self_check.database_fix_mysql"}}</div> {{else if .DatabaseType.IsMSSQL}} @@ -29,22 +31,22 @@ {{end}} {{if .DatabaseCheckInconsistentCollationColumns}} <div class="ui red message"> - {{ctx.Locale.Tr "admin.self_check.database_inconsistent_collation_columns" .DatabaseCheckResult.DatabaseCollation}} - <ul class="tw-w-full"> - {{range .DatabaseCheckInconsistentCollationColumns}} - <li>{{.}}</li> - {{end}} - </ul> + <details> + <summary>{{ctx.Locale.Tr "admin.self_check.database_inconsistent_collation_columns" .DatabaseCheckResult.DatabaseCollation}}</summary> + <ul class="tw-w-full"> + {{range .DatabaseCheckInconsistentCollationColumns}} + <li>{{.}}</li> + {{end}} + </ul> + </details> </div> {{end}} </div> {{end}} - - {{if and (not .StartupProblems) (not .DatabaseCheckHasProblems)}} - <div class="ui attached segment"> + {{/* only shown when there is no visible "self-check-problem" */}} + <div class="ui attached segment tw-hidden self-check-no-problem"> {{ctx.Locale.Tr "admin.self_check.no_problem_found"}} </div> - {{end}} </div> {{template "admin/layout_footer" .}} diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index 8339b4bd82..26627dfded 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -16,20 +16,20 @@ function shouldIgnoreError(err) { return false; } -export function showGlobalErrorMessage(msg) { +export function showGlobalErrorMessage(msg, msgType = 'error') { const msgContainer = document.querySelector('.page-content') ?? document.body; const msgCompact = msg.replace(/\W/g, '').trim(); // compact the message to a data attribute to avoid too many duplicated messages let msgDiv = msgContainer.querySelector(`.js-global-error[data-global-error-msg-compact="${msgCompact}"]`); if (!msgDiv) { const el = document.createElement('div'); - el.innerHTML = `<div class="ui container negative message center aligned js-global-error tw-mt-[15px] tw-whitespace-pre-line"></div>`; + el.innerHTML = `<div class="ui container js-global-error tw-my-[--page-spacing]"><div class="ui ${msgType} message tw-text-center tw-whitespace-pre-line"></div></div>`; msgDiv = el.childNodes[0]; } // merge duplicated messages into "the message (count)" format const msgCount = Number(msgDiv.getAttribute(`data-global-error-msg-count`)) + 1; msgDiv.setAttribute(`data-global-error-msg-compact`, msgCompact); msgDiv.setAttribute(`data-global-error-msg-count`, msgCount.toString()); - msgDiv.textContent = msg + (msgCount > 1 ? ` (${msgCount})` : ''); + msgDiv.querySelector('.ui.message').textContent = msg + (msgCount > 1 ? ` (${msgCount})` : ''); msgContainer.prepend(msgDiv); } diff --git a/web_src/js/features/admin/selfcheck.js b/web_src/js/features/admin/selfcheck.js new file mode 100644 index 0000000000..699395b363 --- /dev/null +++ b/web_src/js/features/admin/selfcheck.js @@ -0,0 +1,31 @@ +import {toggleElem} from '../../utils/dom.js'; +import {POST} from '../../modules/fetch.js'; + +const {appSubUrl} = window.config; + +export async function initAdminSelfCheck() { + const elCheckByFrontend = document.querySelector('#self-check-by-frontend'); + if (!elCheckByFrontend) return; + + const elContent = document.querySelector('.page-content.admin .admin-setting-content'); + + // send frontend self-check request + const resp = await POST(`${appSubUrl}/admin/self_check`, { + data: new URLSearchParams({ + location_origin: window.location.origin, + now: Date.now(), // TODO: check time difference between server and client + }), + }); + const json = await resp.json(); + toggleElem(elCheckByFrontend, Boolean(json.problems?.length)); + for (const problem of json.problems ?? []) { + const elProblem = document.createElement('div'); + elProblem.classList.add('ui', 'warning', 'message'); + elProblem.textContent = problem; + elCheckByFrontend.append(elProblem); + } + + // only show the "no problem" if there is no visible "self-check-problem" + const hasProblem = Boolean(elContent.querySelectorAll('.self-check-problem:not(.tw-hidden)').length); + toggleElem(elContent.querySelector('.self-check-no-problem'), !hasProblem); +} diff --git a/web_src/js/features/common-global.js b/web_src/js/features/common-global.js index 5b8673105d..3b021d4485 100644 --- a/web_src/js/features/common-global.js +++ b/web_src/js/features/common-global.js @@ -451,5 +451,5 @@ export function checkAppUrl() { return; } showGlobalErrorMessage(`Your ROOT_URL in app.ini is "${appUrl}", it's unlikely matching the site you are visiting. -Mismatched ROOT_URL config causes wrong URL links for web UI/mail content/webhook notification/OAuth2 sign-in.`); +Mismatched ROOT_URL config causes wrong URL links for web UI/mail content/webhook notification/OAuth2 sign-in.`, 'warning'); } diff --git a/web_src/js/index.js b/web_src/js/index.js index fc2f6b9b0b..1867556eee 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -87,6 +87,7 @@ import {initRepoDiffCommitBranchesAndTags} from './features/repo-diff-commit.js' import {initDirAuto} from './modules/dirauto.js'; import {initRepositorySearch} from './features/repo-search.js'; import {initColorPickers} from './features/colorpicker.js'; +import {initAdminSelfCheck} from './features/admin/selfcheck.js'; // Init Gitea's Fomantic settings initGiteaFomantic(); @@ -132,6 +133,7 @@ onDomReady(() => { initAdminEmails(); initAdminUserListSearchForm(); initAdminConfigs(); + initAdminSelfCheck(); initDashboardRepoList(); From 5556782ebeb1ca4d17e2fff434b11651887b9899 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Fri, 10 May 2024 14:25:49 +0200 Subject: [PATCH 299/370] Forbid deprecated `break-word` in CSS (#30934) Forbid [deprecated](https://drafts.csswg.org/css-text-3/#word-break-property) `break-word` and fix all occurences. Regarding `overflow-wrap: break-word` vs `overflow-wrap: anywhere`: Example of difference: https://jsfiddle.net/silverwind/1va6972r/ [Here](https://stackoverflow.com/questions/77651244) it says: > The differences between normal, break-word and anywhere are only clear if you are using width: min-content on the element containing the text, and you also set a max-width. A pretty rare scenario. I don't think this difference will make any practical impact as we are not hitting this rare scenario. --- stylelint.config.js | 2 +- web_src/css/features/console.css | 3 +-- web_src/css/helpers.css | 1 - web_src/css/repo.css | 2 +- web_src/css/shared/flex-list.css | 4 ++-- 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/stylelint.config.js b/stylelint.config.js index 9247eb3c33..6fee242685 100644 --- a/stylelint.config.js +++ b/stylelint.config.js @@ -150,7 +150,7 @@ export default { 'declaration-property-unit-allowed-list': null, 'declaration-property-unit-disallowed-list': {'line-height': ['em']}, 'declaration-property-value-allowed-list': null, - 'declaration-property-value-disallowed-list': null, + 'declaration-property-value-disallowed-list': {'word-break': ['break-word']}, 'declaration-property-value-no-unknown': true, 'font-family-name-quotes': 'always-where-recommended', 'font-family-no-duplicate-names': true, diff --git a/web_src/css/features/console.css b/web_src/css/features/console.css index 99fb25dae5..e2d3327cfa 100644 --- a/web_src/css/features/console.css +++ b/web_src/css/features/console.css @@ -5,8 +5,7 @@ color: var(--color-console-fg); font-family: var(--fonts-monospace); border-radius: var(--border-radius); - word-break: break-word; - overflow-wrap: break-word; + overflow-wrap: anywhere; } .console img { max-width: 100%; } diff --git a/web_src/css/helpers.css b/web_src/css/helpers.css index cf2e73572c..4d12dfaea2 100644 --- a/web_src/css/helpers.css +++ b/web_src/css/helpers.css @@ -5,7 +5,6 @@ Gitea's private styles use `g-` prefix. .gt-word-break { word-wrap: break-word !important; - word-break: break-word; /* compat: Safari */ overflow-wrap: anywhere; } diff --git a/web_src/css/repo.css b/web_src/css/repo.css index f02b2b7578..7f07e732a3 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -410,7 +410,7 @@ td .commit-summary { } .repository.file.list .non-diff-file-content .plain-text pre { - word-break: break-word; + overflow-wrap: anywhere; white-space: pre-wrap; } diff --git a/web_src/css/shared/flex-list.css b/web_src/css/shared/flex-list.css index 6217b45300..0f54779252 100644 --- a/web_src/css/shared/flex-list.css +++ b/web_src/css/shared/flex-list.css @@ -59,7 +59,7 @@ color: var(--color-text); font-size: 16px; font-weight: var(--font-weight-semibold); - word-break: break-word; + overflow-wrap: anywhere; min-width: 0; } @@ -74,7 +74,7 @@ flex-wrap: wrap; gap: .25rem; color: var(--color-text-light-2); - word-break: break-word; + overflow-wrap: anywhere; } .flex-item .flex-item-body a { From 080486e47dba7ed767707fb0a2939677dfbcb0e3 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Fri, 10 May 2024 20:58:05 +0800 Subject: [PATCH 300/370] Fix some UI regressions for commit list (#30920) Close #30919 --------- Co-authored-by: silverwind <me@silverwind.io> --- templates/repo/commits_list_small.tmpl | 14 +++++++++----- web_src/css/base.css | 1 + web_src/css/repo.css | 6 +----- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/templates/repo/commits_list_small.tmpl b/templates/repo/commits_list_small.tmpl index 6ca6dd5cdc..4c67319b8c 100644 --- a/templates/repo/commits_list_small.tmpl +++ b/templates/repo/commits_list_small.tmpl @@ -13,13 +13,12 @@ {{$commitLink:= printf "%s/commit/%s" $.comment.Issue.PullRequest.BaseRepo.Link (PathEscape .ID.String)}} - <span class="tw-flex-1 gt-ellipsis tw-font-mono{{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{RenderCommitMessageLinkSubject $.root.Context .Message $commitLink ($.comment.Issue.PullRequest.BaseRepo.ComposeMetas ctx)}}</span> + <span class="tw-flex-1 tw-font-mono gt-ellipsis" title="{{.Summary}}"> + {{- RenderCommitMessageLinkSubject $.root.Context .Message $commitLink ($.comment.Issue.PullRequest.BaseRepo.ComposeMetas ctx) -}} + </span> {{if IsMultilineCommitMessage .Message}} - <button class="ui button js-toggle-commit-body ellipsis-button" aria-expanded="false">...</button> - {{end}} - {{if IsMultilineCommitMessage .Message}} - <pre class="commit-body tw-hidden">{{RenderCommitBody $.root.Context .Message ($.comment.Issue.PullRequest.BaseRepo.ComposeMetas ctx)}}</pre> + <button class="ui button ellipsis-button show-panel toggle" data-panel="[data-singular-commit-body-for='{{$tag}}']">...</button> {{end}} <span class="shabox tw-flex tw-items-center"> @@ -47,5 +46,10 @@ </a> </span> </div> + {{if IsMultilineCommitMessage .Message}} + <pre class="commit-body tw-ml-[33px] tw-hidden" data-singular-commit-body-for="{{$tag}}"> + {{- RenderCommitBody $.root.Context .Message ($.comment.Issue.PullRequest.BaseRepo.ComposeMetas ctx) -}} + </pre> + {{end}} {{end}} </div> diff --git a/web_src/css/base.css b/web_src/css/base.css index 412d9094e3..2d93690170 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -730,6 +730,7 @@ input:-webkit-autofill:active, font-weight: var(--font-weight-normal); margin: 0 6px; padding: 5px 10px; + flex-shrink: 0; } .ui .sha.label .shortsha { diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 7f07e732a3..d42b3b45bd 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -2349,14 +2349,10 @@ tbody.commit-list { .commit-body { margin: 0.25em 0; white-space: pre-wrap; + overflow-wrap: anywhere; line-height: initial; } -/* PR-comment */ -.repository .timeline-item .commit-body { - margin-left: 45px; -} - .git-notes.top { text-align: left; } From 1f3ada47a3ba7ac978fea702e37adcd400245ba1 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Fri, 10 May 2024 20:53:43 +0200 Subject: [PATCH 301/370] Update JS dependencies, add new eslint rules (#30840) --- .eslintrc.yaml | 9 +- package-lock.json | 1115 ++++++++++++++++++++++++++------------------- package.json | 38 +- 3 files changed, 671 insertions(+), 491 deletions(-) diff --git a/.eslintrc.yaml b/.eslintrc.yaml index d9cbefd124..0eda8a1877 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -127,19 +127,21 @@ rules: "@stylistic/js/computed-property-spacing": [2, never] "@stylistic/js/dot-location": [2, property] "@stylistic/js/eol-last": [2] - "@stylistic/js/function-call-spacing": [2, never] "@stylistic/js/function-call-argument-newline": [0] + "@stylistic/js/function-call-spacing": [2, never] "@stylistic/js/function-paren-newline": [0] "@stylistic/js/generator-star-spacing": [0] "@stylistic/js/implicit-arrow-linebreak": [0] "@stylistic/js/indent": [2, 2, {ignoreComments: true, SwitchCase: 1}] "@stylistic/js/key-spacing": [2] "@stylistic/js/keyword-spacing": [2] + "@stylistic/js/line-comment-position": [0] "@stylistic/js/linebreak-style": [2, unix] "@stylistic/js/lines-around-comment": [0] "@stylistic/js/lines-between-class-members": [0] "@stylistic/js/max-len": [0] "@stylistic/js/max-statements-per-line": [0] + "@stylistic/js/multiline-comment-style": [0] "@stylistic/js/multiline-ternary": [0] "@stylistic/js/new-parens": [2] "@stylistic/js/newline-per-chained-call": [0] @@ -705,6 +707,7 @@ rules: unicorn/better-regex: [0] unicorn/catch-error-name: [0] unicorn/consistent-destructuring: [2] + unicorn/consistent-empty-array-spread: [2] unicorn/consistent-function-scoping: [2] unicorn/custom-error-definition: [0] unicorn/empty-brace-spaces: [2] @@ -731,9 +734,11 @@ rules: unicorn/no-for-loop: [0] unicorn/no-hex-escape: [0] unicorn/no-instanceof-array: [0] + unicorn/no-invalid-fetch-options: [2] unicorn/no-invalid-remove-event-listener: [2] unicorn/no-keyword-prefix: [0] unicorn/no-lonely-if: [2] + unicorn/no-magic-array-flat-depth: [0] unicorn/no-negated-condition: [0] unicorn/no-nested-ternary: [0] unicorn/no-new-array: [0] @@ -799,10 +804,12 @@ rules: unicorn/prefer-set-has: [0] unicorn/prefer-set-size: [2] unicorn/prefer-spread: [0] + unicorn/prefer-string-raw: [0] unicorn/prefer-string-replace-all: [0] unicorn/prefer-string-slice: [0] unicorn/prefer-string-starts-ends-with: [2] unicorn/prefer-string-trim-start-end: [2] + unicorn/prefer-structured-clone: [2] unicorn/prefer-switch: [0] unicorn/prefer-ternary: [0] unicorn/prefer-text-content: [2] diff --git a/package-lock.json b/package-lock.json index bba4ca5a9d..f535c318fa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "": { "dependencies": { "@citation-js/core": "0.7.11", - "@citation-js/plugin-bibtex": "0.7.11", + "@citation-js/plugin-bibtex": "0.7.12", "@citation-js/plugin-csl": "0.7.11", "@citation-js/plugin-software-formats": "0.6.1", "@github/markdown-toolbar-element": "2.2.3", @@ -15,15 +15,15 @@ "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", "@primer/octicons": "19.9.0", "@silverwind/vue3-calendar-heatmap": "2.0.6", - "add-asset-webpack-plugin": "2.0.1", + "add-asset-webpack-plugin": "3.0.0", "ansi_up": "6.0.2", "asciinema-player": "3.7.1", "chart.js": "4.4.2", "chartjs-adapter-dayjs-4": "1.0.4", "chartjs-plugin-zoom": "2.0.1", - "clippie": "4.0.7", + "clippie": "4.1.1", "css-loader": "7.1.1", - "dayjs": "1.11.10", + "dayjs": "1.11.11", "dropzone": "6.0.0-beta.2", "easymde": "2.18.0", "esbuild-loader": "4.1.0", @@ -44,7 +44,7 @@ "postcss-loader": "8.1.1", "postcss-nesting": "12.1.2", "sortablejs": "1.15.2", - "swagger-ui-dist": "5.17.2", + "swagger-ui-dist": "5.17.7", "tailwindcss": "3.4.3", "temporal-polyfill": "0.2.4", "throttle-debounce": "5.0.0", @@ -54,7 +54,7 @@ "tributejs": "5.1.3", "uint8-to-base64": "0.2.0", "vanilla-colorful": "0.7.2", - "vue": "3.4.25", + "vue": "3.4.27", "vue-bar-graph": "2.0.0", "vue-chartjs": "5.3.1", "vue-loader": "17.4.2", @@ -64,10 +64,10 @@ }, "devDependencies": { "@eslint-community/eslint-plugin-eslint-comments": "4.3.0", - "@playwright/test": "1.43.1", + "@playwright/test": "1.44.0", "@stoplight/spectral-cli": "6.11.1", - "@stylistic/eslint-plugin-js": "1.7.2", - "@stylistic/stylelint-plugin": "2.1.1", + "@stylistic/eslint-plugin-js": "2.1.0", + "@stylistic/stylelint-plugin": "2.1.2", "@vitejs/plugin-vue": "5.0.4", "eslint": "8.57.0", "eslint-plugin-array-func": "4.0.0", @@ -77,38 +77,29 @@ "eslint-plugin-no-jquery": "2.7.0", "eslint-plugin-no-use-extend-native": "0.5.0", "eslint-plugin-regexp": "2.5.0", - "eslint-plugin-sonarjs": "0.25.1", - "eslint-plugin-unicorn": "52.0.0", + "eslint-plugin-sonarjs": "1.0.3", + "eslint-plugin-unicorn": "53.0.0", "eslint-plugin-vitest": "0.4.1", "eslint-plugin-vitest-globals": "1.5.0", - "eslint-plugin-vue": "9.25.0", + "eslint-plugin-vue": "9.26.0", "eslint-plugin-vue-scoped-css": "2.8.0", "eslint-plugin-wc": "2.1.0", - "happy-dom": "14.7.1", - "markdownlint-cli": "0.39.0", - "postcss-html": "1.6.0", - "stylelint": "16.4.0", + "happy-dom": "14.10.1", + "markdownlint-cli": "0.40.0", + "postcss-html": "1.7.0", + "stylelint": "16.5.0", "stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-declaration-strict-value": "1.10.4", "stylelint-value-no-unknown-custom-properties": "6.0.1", - "svgo": "3.2.0", + "svgo": "3.3.2", "updates": "16.0.1", - "vite-string-plugin": "1.2.0", - "vitest": "1.5.2" + "vite-string-plugin": "1.3.1", + "vitest": "1.6.0" }, "engines": { "node": ">= 18.0.0" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", @@ -142,19 +133,19 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", - "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", + "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.5", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -233,9 +224,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", - "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz", + "integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==", "bin": { "parser": "bin/babel-parser.js" }, @@ -244,9 +235,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz", - "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz", + "integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -290,9 +281,9 @@ } }, "node_modules/@citation-js/plugin-bibtex": { - "version": "0.7.11", - "resolved": "https://registry.npmjs.org/@citation-js/plugin-bibtex/-/plugin-bibtex-0.7.11.tgz", - "integrity": "sha512-G4vEmLjrQUxgBIp3ffWN5dDOlwjPsrRSi/uTyxDJuFgKBD8GR1eO7Y/ZcePNAOHMqUxG7lxhhBbZJwcJZNVHYw==", + "version": "0.7.12", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-bibtex/-/plugin-bibtex-0.7.12.tgz", + "integrity": "sha512-cvby0llm1a1kjvvN9ivKO3dCFoyljKx2Rn9mMsUm43JTJZ4rP0emAZ8qzRL4cL3IIUaCRgkN36O+uz9yPktC5Q==", "dependencies": { "@citation-js/date": "^0.5.0", "@citation-js/name": "^0.4.2", @@ -395,9 +386,9 @@ } }, "node_modules/@csstools/css-parser-algorithms": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.6.1.tgz", - "integrity": "sha512-ubEkAaTfVZa+WwGhs5jbo5Xfqpeaybr/RvWzvFxRs4jfq16wH8l8Ty/QEEpINxll4xhuGfdMbipRyz5QZh9+FA==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.6.3.tgz", + "integrity": "sha512-xI/tL2zxzEbESvnSxwFgwvy5HS00oCXxL4MLs6HUiDcYfwowsoQaABKxUElp1ARITrINzBnsECOc1q0eg2GOrA==", "dev": true, "funding": [ { @@ -413,13 +404,13 @@ "node": "^14 || ^16 || >=18" }, "peerDependencies": { - "@csstools/css-tokenizer": "^2.2.4" + "@csstools/css-tokenizer": "^2.3.1" } }, "node_modules/@csstools/css-tokenizer": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.2.4.tgz", - "integrity": "sha512-PuWRAewQLbDhGeTvFuq2oClaSCKPIBmHyIobCV39JHRYN0byDcUWJl5baPeNUcqrjtdMNqFooE0FGl31I3JOqw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.3.1.tgz", + "integrity": "sha512-iMNHTyxLbBlWIfGtabT157LH9DUx9X8+Y3oymFEuMj8HNc+rpE3dPFGFgHjpKfjeFDjLjYIAIhXPGvS2lKxL9g==", "dev": true, "funding": [ { @@ -436,9 +427,9 @@ } }, "node_modules/@csstools/media-query-list-parser": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.9.tgz", - "integrity": "sha512-qqGuFfbn4rUmyOB0u8CVISIp5FfJ5GAR3mBrZ9/TKndHakdnm6pY0L/fbLcpPnrzwCyyTEZl1nUcXAYHEWneTA==", + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.11.tgz", + "integrity": "sha512-uox5MVhvNHqitPP+SynrB1o8oPxPMt2JLgp5ghJOWf54WGQ5OKu47efne49r1SWqs3wRP8xSWjnO9MBKxhB1dA==", "dev": true, "funding": [ { @@ -454,8 +445,8 @@ "node": "^14 || ^16 || >=18" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^2.6.1", - "@csstools/css-tokenizer": "^2.2.4" + "@csstools/css-parser-algorithms": "^2.6.3", + "@csstools/css-tokenizer": "^2.3.1" } }, "node_modules/@csstools/selector-resolve-nested": { @@ -509,9 +500,9 @@ } }, "node_modules/@dual-bundle/import-meta-resolve": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.0.0.tgz", - "integrity": "sha512-ZKXyJeFAzcpKM2kk8ipoGIPUqx9BX52omTGnfwjJvxOCaZTM2wtDK7zN0aIgPRbT9XYAlha0HtmZ+XKteuh0Gw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", + "integrity": "sha512-+nxncfwHM5SgAtrVzgpzJOI1ol0PkumhVo469KCf9lUi21IGcY90G98VuHm9VRrUypmAzawAHO9bs6hqeADaVg==", "dev": true, "funding": { "type": "github", @@ -894,6 +885,18 @@ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@eslint-community/regexpp": { "version": "4.10.0", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", @@ -952,6 +955,35 @@ "concat-map": "0.0.1" } }, + "node_modules/@eslint/eslintrc/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -1343,12 +1375,12 @@ } }, "node_modules/@playwright/test": { - "version": "1.43.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.43.1.tgz", - "integrity": "sha512-HgtQzFgNEEo4TE22K/X7sYTYNqEMMTZmFS8kTq6m8hXj+m1D8TgwgIbumHddJa9h4yl4GkKb8/bgAl2+g7eDgA==", + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.44.0.tgz", + "integrity": "sha512-rNX5lbNidamSUorBhB4XZ9SQTjAqfe5M+p37Z8ic0jPFBMo5iCtQz1kRWkEMg+rYOKSlVycpQmpqjSFq7LXOfg==", "dev": true, "dependencies": { - "playwright": "1.43.1" + "playwright": "1.44.0" }, "bin": { "playwright": "cli.js" @@ -1419,9 +1451,9 @@ "dev": true }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.16.4.tgz", - "integrity": "sha512-GkhjAaQ8oUTOKE4g4gsZ0u8K/IHU1+2WQSgS1TwTcYvL+sjbaQjNHFXbOJ6kgqGHIO1DfUhI/Sphi9GkRT9K+Q==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.17.2.tgz", + "integrity": "sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==", "cpu": [ "arm" ], @@ -1432,9 +1464,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.16.4.tgz", - "integrity": "sha512-Bvm6D+NPbGMQOcxvS1zUl8H7DWlywSXsphAeOnVeiZLQ+0J6Is8T7SrjGTH29KtYkiY9vld8ZnpV3G2EPbom+w==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.17.2.tgz", + "integrity": "sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==", "cpu": [ "arm64" ], @@ -1445,9 +1477,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.16.4.tgz", - "integrity": "sha512-i5d64MlnYBO9EkCOGe5vPR/EeDwjnKOGGdd7zKFhU5y8haKhQZTN2DgVtpODDMxUr4t2K90wTUJg7ilgND6bXw==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.17.2.tgz", + "integrity": "sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==", "cpu": [ "arm64" ], @@ -1458,9 +1490,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.16.4.tgz", - "integrity": "sha512-WZupV1+CdUYehaZqjaFTClJI72fjJEgTXdf4NbW69I9XyvdmztUExBtcI2yIIU6hJtYvtwS6pkTkHJz+k08mAQ==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.17.2.tgz", + "integrity": "sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==", "cpu": [ "x64" ], @@ -1471,9 +1503,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.16.4.tgz", - "integrity": "sha512-ADm/xt86JUnmAfA9mBqFcRp//RVRt1ohGOYF6yL+IFCYqOBNwy5lbEK05xTsEoJq+/tJzg8ICUtS82WinJRuIw==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.17.2.tgz", + "integrity": "sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==", "cpu": [ "arm" ], @@ -1484,9 +1516,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.16.4.tgz", - "integrity": "sha512-tJfJaXPiFAG+Jn3cutp7mCs1ePltuAgRqdDZrzb1aeE3TktWWJ+g7xK9SNlaSUFw6IU4QgOxAY4rA+wZUT5Wfg==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.17.2.tgz", + "integrity": "sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==", "cpu": [ "arm" ], @@ -1497,9 +1529,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.16.4.tgz", - "integrity": "sha512-7dy1BzQkgYlUTapDTvK997cgi0Orh5Iu7JlZVBy1MBURk7/HSbHkzRnXZa19ozy+wwD8/SlpJnOOckuNZtJR9w==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.2.tgz", + "integrity": "sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==", "cpu": [ "arm64" ], @@ -1510,9 +1542,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.16.4.tgz", - "integrity": "sha512-zsFwdUw5XLD1gQe0aoU2HVceI6NEW7q7m05wA46eUAyrkeNYExObfRFQcvA6zw8lfRc5BHtan3tBpo+kqEOxmg==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.17.2.tgz", + "integrity": "sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==", "cpu": [ "arm64" ], @@ -1523,9 +1555,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.16.4.tgz", - "integrity": "sha512-p8C3NnxXooRdNrdv6dBmRTddEapfESEUflpICDNKXpHvTjRRq1J82CbU5G3XfebIZyI3B0s074JHMWD36qOW6w==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.17.2.tgz", + "integrity": "sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==", "cpu": [ "ppc64" ], @@ -1536,9 +1568,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.16.4.tgz", - "integrity": "sha512-Lh/8ckoar4s4Id2foY7jNgitTOUQczwMWNYi+Mjt0eQ9LKhr6sK477REqQkmy8YHY3Ca3A2JJVdXnfb3Rrwkng==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.17.2.tgz", + "integrity": "sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==", "cpu": [ "riscv64" ], @@ -1549,9 +1581,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.16.4.tgz", - "integrity": "sha512-1xwwn9ZCQYuqGmulGsTZoKrrn0z2fAur2ujE60QgyDpHmBbXbxLaQiEvzJWDrscRq43c8DnuHx3QorhMTZgisQ==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.17.2.tgz", + "integrity": "sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==", "cpu": [ "s390x" ], @@ -1562,9 +1594,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.16.4.tgz", - "integrity": "sha512-LuOGGKAJ7dfRtxVnO1i3qWc6N9sh0Em/8aZ3CezixSTM+E9Oq3OvTsvC4sm6wWjzpsIlOCnZjdluINKESflJLA==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.2.tgz", + "integrity": "sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==", "cpu": [ "x64" ], @@ -1575,9 +1607,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.16.4.tgz", - "integrity": "sha512-ch86i7KkJKkLybDP2AtySFTRi5fM3KXp0PnHocHuJMdZwu7BuyIKi35BE9guMlmTpwwBTB3ljHj9IQXnTCD0vA==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.17.2.tgz", + "integrity": "sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==", "cpu": [ "x64" ], @@ -1588,9 +1620,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.16.4.tgz", - "integrity": "sha512-Ma4PwyLfOWZWayfEsNQzTDBVW8PZ6TUUN1uFTBQbF2Chv/+sjenE86lpiEwj2FiviSmSZ4Ap4MaAfl1ciF4aSA==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.17.2.tgz", + "integrity": "sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==", "cpu": [ "arm64" ], @@ -1601,9 +1633,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.16.4.tgz", - "integrity": "sha512-9m/ZDrQsdo/c06uOlP3W9G2ENRVzgzbSXmXHT4hwVaDQhYcRpi9bgBT0FTG9OhESxwK0WjQxYOSfv40cU+T69w==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.17.2.tgz", + "integrity": "sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==", "cpu": [ "ia32" ], @@ -1614,9 +1646,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.16.4.tgz", - "integrity": "sha512-YunpoOAyGLDseanENHmbFvQSfVL5BxW3k7hhy0eN4rb3gS/ct75dVD0EXOWIqFT/nE8XYW6LP6vz6ctKRi0k9A==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.17.2.tgz", + "integrity": "sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==", "cpu": [ "x64" ], @@ -2143,38 +2175,37 @@ } }, "node_modules/@stylistic/eslint-plugin-js": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-1.7.2.tgz", - "integrity": "sha512-ZYX7C5p7zlHbACwFLU+lISVh6tdcRP/++PWegh2Sy0UgMT5kU0XkPa2tKWEtJYzZmPhJxu9LxbnWcnE/tTwSDQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.1.0.tgz", + "integrity": "sha512-gdXUjGNSsnY6nPyqxu6lmDTtVrwCOjun4x8PUn0x04d5ucLI74N3MT1Q0UhdcOR9No3bo5PGDyBgXK+KmD787A==", "dev": true, "dependencies": { - "@types/eslint": "^8.56.8", + "@types/eslint": "^8.56.10", "acorn": "^8.11.3", - "escape-string-regexp": "^4.0.0", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1" + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.0.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "peerDependencies": { "eslint": ">=8.40.0" } }, "node_modules/@stylistic/stylelint-plugin": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-2.1.1.tgz", - "integrity": "sha512-xqHTmQZN7EbnFDW7jw0rAsdFNO4IRqvXhrh3qhUlIwF/x09Zm7kgs/ADktHxsTJYcw346PpGihsB0t4pZhpeHw==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-2.1.2.tgz", + "integrity": "sha512-JsSqu0Y3vsX+PBl+DwULxC0cIv9C1yIcq1MXkx7pBOGtTqU26a75I8MPYMiEYvrsXgsKLi65xVgy1iLVSZquJA==", "dev": true, "dependencies": { - "@csstools/css-parser-algorithms": "^2.5.0", - "@csstools/css-tokenizer": "^2.2.3", - "@csstools/media-query-list-parser": "^2.1.7", + "@csstools/css-parser-algorithms": "^2.6.1", + "@csstools/css-tokenizer": "^2.2.4", + "@csstools/media-query-list-parser": "^2.1.9", "is-plain-object": "^5.0.0", - "postcss-selector-parser": "^6.0.15", + "postcss-selector-parser": "^6.0.16", "postcss-value-parser": "^4.2.0", "style-search": "^0.1.0", - "stylelint": "^16.2.1" + "stylelint": "^16.4.0" }, "engines": { "node": "^18.12 || >=20.9" @@ -2293,9 +2324,9 @@ "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" }, "node_modules/@types/node": { - "version": "20.12.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", - "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", + "version": "20.12.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.11.tgz", + "integrity": "sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==", "dependencies": { "undici-types": "~5.26.4" } @@ -2338,16 +2369,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.1.tgz", - "integrity": "sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.8.0.tgz", + "integrity": "sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.7.1", - "@typescript-eslint/type-utils": "7.7.1", - "@typescript-eslint/utils": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/type-utils": "7.8.0", + "@typescript-eslint/utils": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.3.1", @@ -2373,15 +2404,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.1.tgz", - "integrity": "sha512-vmPzBOOtz48F6JAGVS/kZYk4EkXao6iGrD838sp1w3NQQC0W8ry/q641KU4PrG7AKNAf56NOcR8GOpH8l9FPCw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.8.0.tgz", + "integrity": "sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.7.1", - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/typescript-estree": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/typescript-estree": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "debug": "^4.3.4" }, "engines": { @@ -2401,13 +2432,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.1.tgz", - "integrity": "sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.8.0.tgz", + "integrity": "sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1" + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2418,13 +2449,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.1.tgz", - "integrity": "sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.8.0.tgz", + "integrity": "sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.7.1", - "@typescript-eslint/utils": "7.7.1", + "@typescript-eslint/typescript-estree": "7.8.0", + "@typescript-eslint/utils": "7.8.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -2445,9 +2476,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.1.tgz", - "integrity": "sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.8.0.tgz", + "integrity": "sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2458,13 +2489,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.1.tgz", - "integrity": "sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz", + "integrity": "sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2486,17 +2517,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.1.tgz", - "integrity": "sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.8.0.tgz", + "integrity": "sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.15", "@types/semver": "^7.5.8", - "@typescript-eslint/scope-manager": "7.7.1", - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/typescript-estree": "7.7.1", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/typescript-estree": "7.8.0", "semver": "^7.6.0" }, "engines": { @@ -2511,12 +2542,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.1.tgz", - "integrity": "sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.8.0.tgz", + "integrity": "sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/types": "7.8.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -2527,6 +2558,18 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", @@ -2547,13 +2590,13 @@ } }, "node_modules/@vitest/expect": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.5.2.tgz", - "integrity": "sha512-rf7MTD1WCoDlN3FfYJ9Llfp0PbdtOMZ3FIF0AVkDnKbp3oiMW1c8AmvRZBcqbAhDUAvF52e9zx4WQM1r3oraVA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", + "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", "dev": true, "dependencies": { - "@vitest/spy": "1.5.2", - "@vitest/utils": "1.5.2", + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", "chai": "^4.3.10" }, "funding": { @@ -2561,12 +2604,12 @@ } }, "node_modules/@vitest/runner": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.2.tgz", - "integrity": "sha512-7IJ7sJhMZrqx7HIEpv3WrMYcq8ZNz9L6alo81Y6f8hV5mIE6yVZsFoivLZmr0D777klm1ReqonE9LyChdcmw6g==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz", + "integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==", "dev": true, "dependencies": { - "@vitest/utils": "1.5.2", + "@vitest/utils": "1.6.0", "p-limit": "^5.0.0", "pathe": "^1.1.1" }, @@ -2602,9 +2645,9 @@ } }, "node_modules/@vitest/snapshot": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.2.tgz", - "integrity": "sha512-CTEp/lTYos8fuCc9+Z55Ga5NVPKUgExritjF5VY7heRFUfheoAqBneUlvXSUJHUZPjnPmyZA96yLRJDP1QATFQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz", + "integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==", "dev": true, "dependencies": { "magic-string": "^0.30.5", @@ -2625,9 +2668,9 @@ } }, "node_modules/@vitest/spy": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.5.2.tgz", - "integrity": "sha512-xCcPvI8JpCtgikT9nLpHPL1/81AYqZy1GCy4+MCHBE7xi8jgsYkULpW5hrx5PGLgOQjUpb6fd15lqcriJ40tfQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", + "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", "dev": true, "dependencies": { "tinyspy": "^2.2.0" @@ -2637,9 +2680,9 @@ } }, "node_modules/@vitest/utils": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.2.tgz", - "integrity": "sha512-sWOmyofuXLJ85VvXNsroZur7mOJGiQeM0JN3/0D1uU8U9bGFM69X1iqHaRXl6R8BwaLY6yPCogP257zxTzkUdA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", + "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", "dev": true, "dependencies": { "diff-sequences": "^29.6.3", @@ -2667,36 +2710,36 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.4.25", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.25.tgz", - "integrity": "sha512-Y2pLLopaElgWnMNolgG8w3C5nNUVev80L7hdQ5iIKPtMJvhVpG0zhnBG/g3UajJmZdvW0fktyZTotEHD1Srhbg==", + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.27.tgz", + "integrity": "sha512-E+RyqY24KnyDXsCuQrI+mlcdW3ALND6U7Gqa/+bVwbcpcR3BRRIckFoz7Qyd4TTlnugtwuI7YgjbvsLmxb+yvg==", "dependencies": { "@babel/parser": "^7.24.4", - "@vue/shared": "3.4.25", + "@vue/shared": "3.4.27", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-dom": { - "version": "3.4.25", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.25.tgz", - "integrity": "sha512-Ugz5DusW57+HjllAugLci19NsDK+VyjGvmbB2TXaTcSlQxwL++2PETHx/+Qv6qFwNLzSt7HKepPe4DcTE3pBWg==", + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.27.tgz", + "integrity": "sha512-kUTvochG/oVgE1w5ViSr3KUBh9X7CWirebA3bezTbB5ZKBQZwR2Mwj9uoSKRMFcz4gSMzzLXBPD6KpCLb9nvWw==", "dependencies": { - "@vue/compiler-core": "3.4.25", - "@vue/shared": "3.4.25" + "@vue/compiler-core": "3.4.27", + "@vue/shared": "3.4.27" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.4.25", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.25.tgz", - "integrity": "sha512-m7rryuqzIoQpOBZ18wKyq05IwL6qEpZxFZfRxlNYuIPDqywrXQxgUwLXIvoU72gs6cRdY6wHD0WVZIFE4OEaAQ==", + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.27.tgz", + "integrity": "sha512-nDwntUEADssW8e0rrmE0+OrONwmRlegDA1pD6QhVeXxjIytV03yDqTey9SBDiALsvAd5U4ZrEKbMyVXhX6mCGA==", "dependencies": { "@babel/parser": "^7.24.4", - "@vue/compiler-core": "3.4.25", - "@vue/compiler-dom": "3.4.25", - "@vue/compiler-ssr": "3.4.25", - "@vue/shared": "3.4.25", + "@vue/compiler-core": "3.4.27", + "@vue/compiler-dom": "3.4.27", + "@vue/compiler-ssr": "3.4.27", + "@vue/shared": "3.4.27", "estree-walker": "^2.0.2", "magic-string": "^0.30.10", "postcss": "^8.4.38", @@ -2712,57 +2755,57 @@ } }, "node_modules/@vue/compiler-ssr": { - "version": "3.4.25", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.25.tgz", - "integrity": "sha512-H2ohvM/Pf6LelGxDBnfbbXFPyM4NE3hrw0e/EpwuSiYu8c819wx+SVGdJ65p/sFrYDd6OnSDxN1MB2mN07hRSQ==", + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.27.tgz", + "integrity": "sha512-CVRzSJIltzMG5FcidsW0jKNQnNRYC8bT21VegyMMtHmhW3UOI7knmUehzswXLrExDLE6lQCZdrhD4ogI7c+vuw==", "dependencies": { - "@vue/compiler-dom": "3.4.25", - "@vue/shared": "3.4.25" + "@vue/compiler-dom": "3.4.27", + "@vue/shared": "3.4.27" } }, "node_modules/@vue/reactivity": { - "version": "3.4.25", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.25.tgz", - "integrity": "sha512-mKbEtKr1iTxZkAG3vm3BtKHAOhuI4zzsVcN0epDldU/THsrvfXRKzq+lZnjczZGnTdh3ojd86/WrP+u9M51pWQ==", + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.27.tgz", + "integrity": "sha512-kK0g4NknW6JX2yySLpsm2jlunZJl2/RJGZ0H9ddHdfBVHcNzxmQ0sS0b09ipmBoQpY8JM2KmUw+a6sO8Zo+zIA==", "dependencies": { - "@vue/shared": "3.4.25" + "@vue/shared": "3.4.27" } }, "node_modules/@vue/runtime-core": { - "version": "3.4.25", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.25.tgz", - "integrity": "sha512-3qhsTqbEh8BMH3pXf009epCI5E7bKu28fJLi9O6W+ZGt/6xgSfMuGPqa5HRbUxLoehTNp5uWvzCr60KuiRIL0Q==", + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.27.tgz", + "integrity": "sha512-7aYA9GEbOOdviqVvcuweTLe5Za4qBZkUY7SvET6vE8kyypxVgaT1ixHLg4urtOlrApdgcdgHoTZCUuTGap/5WA==", "dependencies": { - "@vue/reactivity": "3.4.25", - "@vue/shared": "3.4.25" + "@vue/reactivity": "3.4.27", + "@vue/shared": "3.4.27" } }, "node_modules/@vue/runtime-dom": { - "version": "3.4.25", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.25.tgz", - "integrity": "sha512-ode0sj77kuwXwSc+2Yhk8JMHZh1sZp9F/51wdBiz3KGaWltbKtdihlJFhQG4H6AY+A06zzeMLkq6qu8uDSsaoA==", + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.27.tgz", + "integrity": "sha512-ScOmP70/3NPM+TW9hvVAz6VWWtZJqkbdf7w6ySsws+EsqtHvkhxaWLecrTorFxsawelM5Ys9FnDEMt6BPBDS0Q==", "dependencies": { - "@vue/runtime-core": "3.4.25", - "@vue/shared": "3.4.25", + "@vue/runtime-core": "3.4.27", + "@vue/shared": "3.4.27", "csstype": "^3.1.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.4.25", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.25.tgz", - "integrity": "sha512-8VTwq0Zcu3K4dWV0jOwIVINESE/gha3ifYCOKEhxOj6MEl5K5y8J8clQncTcDhKF+9U765nRw4UdUEXvrGhyVQ==", + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.27.tgz", + "integrity": "sha512-dlAMEuvmeA3rJsOMJ2J1kXU7o7pOxgsNHVr9K8hB3ImIkSuBrIdy0vF66h8gf8Tuinf1TK3mPAz2+2sqyf3KzA==", "dependencies": { - "@vue/compiler-ssr": "3.4.25", - "@vue/shared": "3.4.25" + "@vue/compiler-ssr": "3.4.27", + "@vue/shared": "3.4.27" }, "peerDependencies": { - "vue": "3.4.25" + "vue": "3.4.27" } }, "node_modules/@vue/shared": { - "version": "3.4.25", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.25.tgz", - "integrity": "sha512-k0yappJ77g2+KNrIaF0FFnzwLvUBLUYr8VOwz+/6vLsmItFp51AcxLL7Ey3iPd7BIRyWPOcqUjMnm7OkahXllA==" + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.27.tgz", + "integrity": "sha512-DL3NmY2OFlqmYYrzp39yi3LDkKxa5vZVwxWdQ3rG0ekuWscHraeIbnI8t+aZK7qhYqEqWKTUdijadunb9pnrgA==" }, "node_modules/@webassemblyjs/ast": { "version": "1.12.1", @@ -2996,11 +3039,11 @@ } }, "node_modules/add-asset-webpack-plugin": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/add-asset-webpack-plugin/-/add-asset-webpack-plugin-2.0.1.tgz", - "integrity": "sha512-Hx9EKnirCUfdh684y1yhx8QOFolpkIG2VRHHgNm8wFy1Cf7P3RGwS678hoN7Y1XvZRPpVXWa+6QnfL/2i0CMCA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/add-asset-webpack-plugin/-/add-asset-webpack-plugin-3.0.0.tgz", + "integrity": "sha512-mg6nL4E+dNZPQfTc/A4xcOYsIxCN7Cuy9OScZsjI9qOYPiJeFZfsYcdoYlqcNNQEC4w8yNwArhD1Gm+G1iWrNg==", "engines": { - "node": ">=10.13.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3010,14 +3053,14 @@ } }, "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", + "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", "dependencies": { - "fast-deep-equal": "^3.1.1", + "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "uri-js": "^4.4.1" }, "funding": { "type": "github", @@ -3569,9 +3612,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001612", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz", - "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==", + "version": "1.0.30001617", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001617.tgz", + "integrity": "sha512-mLyjzNI9I+Pix8zwcrpxEbGlfqOkF9kM3ptzmKNw5tizSyYwMe+nGLTqMK9cO+0E+Bh6TsBxNAaHWEM8xwSsmA==", "funding": [ { "type": "opencollective", @@ -3759,9 +3802,9 @@ } }, "node_modules/clippie": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/clippie/-/clippie-4.0.7.tgz", - "integrity": "sha512-xmIARCRFQUoCR0kNNu4uIv5f/IFqM1fUts0vQwt1hQEdCPEqs3/dTaG38WenlWOgs3Fcn73PBYXbPIVSlOgFRw==" + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/clippie/-/clippie-4.1.1.tgz", + "integrity": "sha512-D9OOW77Kkj9YEiDXTQjZJZLvTjJPEmK2IBx8JbGJIZaqVd8RvSvxwIN4KVSEFQfu9Jh0z5FL6Pdc4SIknllFFA==" }, "node_modules/cliui": { "version": "7.0.4", @@ -4597,9 +4640,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.10", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", - "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" + "version": "1.11.11", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz", + "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==" }, "node_modules/debug": { "version": "4.3.4", @@ -4817,9 +4860,9 @@ } }, "node_modules/dompurify": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.0.tgz", - "integrity": "sha512-yoU4rhgPKCo+p5UrWWWNKiIq+ToGqmVVhk0PmMYBK4kRsR3/qhemNFL8f6CFmBd4gMwm3F4T7HBoydP5uY07fA==" + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.2.tgz", + "integrity": "sha512-hLGGBI1tw5N8qTELr3blKjAML/LY4ANxksbS612UiJyDfyf/2D092Pvm+S7pmeTGJRqvlJkFzBoHBQKgQlOQVg==" }, "node_modules/domutils": { "version": "3.1.0", @@ -4862,9 +4905,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.749", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.749.tgz", - "integrity": "sha512-LRMMrM9ITOvue0PoBrvNIraVmuDbJV5QC9ierz/z5VilMdPOVMjOtpICNld3PuXuTZ3CHH/UPxX9gHhAPwi+0Q==" + "version": "1.4.762", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.762.tgz", + "integrity": "sha512-rrFvGweLxPwwSwJOjIopy3Vr+J3cIPtZzuc74bmlvmBIgQO3VYJDvVrlj94iKZ3ukXUH64Ex31hSfRTLqvjYJQ==" }, "node_modules/elkjs": { "version": "0.9.3", @@ -4885,9 +4928,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", - "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.1.tgz", + "integrity": "sha512-4U5pNsuDl0EhuZpq46M5xPslstkviJuhrdobaRDBk2Jy2KO37FDAJl4lb2KlNabxT0m4MTK2UHNrsAcphE8nyw==", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -4916,9 +4959,9 @@ } }, "node_modules/envinfo": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.12.0.tgz", - "integrity": "sha512-Iw9rQJBGpJRd3rwXm9ft/JiGoAZmLxxJZELYDQoPRZ4USVhkKtIcNBPw6U+/K2mBpaqM25JSV6Yl4Az9vO2wJg==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", + "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", "bin": { "envinfo": "dist/cli.js" }, @@ -5063,9 +5106,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.0.tgz", - "integrity": "sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw==" + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.2.tgz", + "integrity": "sha512-l60ETUTmLqbVbVHv1J4/qj+M8nq7AwMzEcg3kmJDt9dCNrTk+yHcYFf/Kw75pMDwd9mPcIGCG5LcS20SxYRzFA==" }, "node_modules/es-object-atoms": { "version": "1.0.0", @@ -5715,29 +5758,29 @@ } }, "node_modules/eslint-plugin-sonarjs": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.25.1.tgz", - "integrity": "sha512-5IOKvj/GMBNqjxBdItfotfRHo7w48496GOu1hxdeXuD0mB1JBlDCViiLHETDTfA8pDAVSBimBEQoetRXYceQEw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-1.0.3.tgz", + "integrity": "sha512-6s41HLPYPyDrp+5+7Db5yFYbod6h9pC7yx+xfcNwHRcLe1EZwbbQT/tdOAkR7ekVUkNGEvN3GmYakIoQUX7dEg==", "dev": true, "engines": { "node": ">=16" }, "peerDependencies": { - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^8.0.0 || ^9.0.0" } }, "node_modules/eslint-plugin-unicorn": { - "version": "52.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-52.0.0.tgz", - "integrity": "sha512-1Yzm7/m+0R4djH0tjDjfVei/ju2w3AzUGjG6q8JnuNIL5xIwsflyCooW5sfBvQp2pMYQFSWWCFONsjCax1EHng==", + "version": "53.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-53.0.0.tgz", + "integrity": "sha512-kuTcNo9IwwUCfyHGwQFOK/HjJAYzbODHN3wP0PgqbW+jbXqpNWxNVpVhj2tO9SixBwuAdmal8rVcWKBxwFnGuw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.5", "@eslint-community/eslint-utils": "^4.4.0", - "@eslint/eslintrc": "^2.1.4", + "@eslint/eslintrc": "^3.0.2", "ci-info": "^4.0.0", "clean-regexp": "^1.0.0", - "core-js-compat": "^3.34.0", + "core-js-compat": "^3.37.0", "esquery": "^1.5.0", "indent-string": "^4.0.0", "is-builtin-module": "^3.2.1", @@ -5746,11 +5789,11 @@ "read-pkg-up": "^7.0.1", "regexp-tree": "^0.1.27", "regjsparser": "^0.10.0", - "semver": "^7.5.4", + "semver": "^7.6.1", "strip-indent": "^3.0.0" }, "engines": { - "node": ">=16" + "node": ">=18.18" }, "funding": { "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" @@ -5759,6 +5802,85 @@ "eslint": ">=8.56.0" } }, + "node_modules/eslint-plugin-unicorn/node_modules/@eslint/eslintrc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.0.2.tgz", + "integrity": "sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/eslint-plugin-unicorn/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/eslint-plugin-vitest": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/eslint-plugin-vitest/-/eslint-plugin-vitest-0.4.1.tgz", @@ -5790,9 +5912,9 @@ "dev": true }, "node_modules/eslint-plugin-vue": { - "version": "9.25.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.25.0.tgz", - "integrity": "sha512-tDWlx14bVe6Bs+Nnh3IGrD+hb11kf2nukfm6jLsmJIhmiRQ1SUaksvwY9U5MvPB0pcrg0QK0xapQkfITs3RKOA==", + "version": "9.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.26.0.tgz", + "integrity": "sha512-eTvlxXgd4ijE1cdur850G6KalZqk65k1JKoOI2d1kT3hr8sPD07j1q98FRFdNnpxBELGPWxZmInxeHGF/GxtqQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", @@ -5876,12 +5998,12 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -5913,6 +6035,35 @@ "concat-map": "0.0.1" } }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/eslint/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -5932,17 +6083,17 @@ } }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", + "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", "dev": true, "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.11.3", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -6397,9 +6548,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.7.3", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz", - "integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==", + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", + "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==", "dependencies": { "resolve-pkg-maps": "^1.0.0" }, @@ -6522,12 +6673,13 @@ } }, "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, "dependencies": { - "define-properties": "^1.1.3" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -6599,9 +6751,9 @@ } }, "node_modules/happy-dom": { - "version": "14.7.1", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-14.7.1.tgz", - "integrity": "sha512-v60Q0evZ4clvMcrAh5/F8EdxDdfHdFrtffz/CNe10jKD+nFweZVxM91tW+UyY2L4AtpgIaXdZ7TQmiO1pfcwbg==", + "version": "14.10.1", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-14.10.1.tgz", + "integrity": "sha512-GRbrZYIezi8+tTtffF4v2QcF8bk1h2loUTO5VYQz3GZdrL08Vk0fI+bwf/vFEBf4C/qVf/easLJ/MY1wwdhytA==", "dev": true, "dependencies": { "entities": "^4.5.0", @@ -7486,9 +7638,9 @@ "dev": true }, "node_modules/js-tokens": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-8.0.3.tgz", - "integrity": "sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.0.tgz", + "integrity": "sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==", "dev": true }, "node_modules/js-types": { @@ -7960,14 +8112,11 @@ } }, "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", "engines": { - "node": ">=10" + "node": "14 || >=16.14" } }, "node_modules/magic-string": { @@ -7980,9 +8129,9 @@ } }, "node_modules/markdown-it": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.0.0.tgz", - "integrity": "sha512-seFjF0FIcPt4P9U39Bq1JYblX0KZCjDLFFQPHpL5AzHpqPEKtosxmdq/LTVZnjfH7tjt9BxStm+wXcDBNuYmzw==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", "dev": true, "dependencies": { "argparse": "^2.0.1", @@ -7990,20 +8139,20 @@ "linkify-it": "^5.0.0", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", - "uc.micro": "^2.0.0" + "uc.micro": "^2.1.0" }, "bin": { "markdown-it": "bin/markdown-it.mjs" } }, "node_modules/markdownlint": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.33.0.tgz", - "integrity": "sha512-4lbtT14A3m0LPX1WS/3d1m7Blg+ZwiLq36WvjQqFGsX3Gik99NV+VXp/PW3n+Q62xyPdbvGOCfjPqjW+/SKMig==", + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.34.0.tgz", + "integrity": "sha512-qwGyuyKwjkEMOJ10XN6OTKNOVYvOIi35RNvDLNxTof5s8UmyGHlCdpngRHoRGNvQVGuxO3BJ7uNSgdeX166WXw==", "dev": true, "dependencies": { - "markdown-it": "14.0.0", - "markdownlint-micromark": "0.1.8" + "markdown-it": "14.1.0", + "markdownlint-micromark": "0.1.9" }, "engines": { "node": ">=18" @@ -8013,20 +8162,22 @@ } }, "node_modules/markdownlint-cli": { - "version": "0.39.0", - "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.39.0.tgz", - "integrity": "sha512-ZuFN7Xpsbn1Nbp0YYkeLOfXOMOfLQBik2lKRy8pVI/llmKQ2uW7x+8k5OMgF6o7XCsTDSYC/OOmeJ+3qplvnJQ==", + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.40.0.tgz", + "integrity": "sha512-JXhI3dRQcaqwiFYpPz6VJ7aKYheD53GmTz9y4D/d0F1MbZDGOp9pqKlbOfUX/pHP/iAoeiE4wYRmk8/kjLakxA==", "dev": true, "dependencies": { - "commander": "~11.1.0", + "commander": "~12.0.0", "get-stdin": "~9.0.0", - "glob": "~10.3.10", - "ignore": "~5.3.0", + "glob": "~10.3.12", + "ignore": "~5.3.1", "js-yaml": "^4.1.0", "jsonc-parser": "~3.2.1", - "markdownlint": "~0.33.0", - "minimatch": "~9.0.3", - "run-con": "~1.3.2" + "jsonpointer": "5.0.1", + "markdownlint": "~0.34.0", + "minimatch": "~9.0.4", + "run-con": "~1.3.2", + "toml": "~3.0.0" }, "bin": { "markdownlint": "markdownlint.js" @@ -8036,25 +8187,25 @@ } }, "node_modules/markdownlint-cli/node_modules/commander": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", - "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz", + "integrity": "sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==", "dev": true, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/markdownlint-cli/node_modules/glob": { - "version": "10.3.12", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", - "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", + "version": "10.3.14", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.14.tgz", + "integrity": "sha512-4fkAqu93xe9Mk7le9v0y3VrPDqLKHarNi2s4Pv7f2yOvfhWfhc7hRPHC/JyqMqb8B/Dt/eGS4n7ykwf3fOsl8g==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^2.3.6", "minimatch": "^9.0.1", "minipass": "^7.0.4", - "path-scurry": "^1.10.2" + "path-scurry": "^1.11.0" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -8073,12 +8224,12 @@ "dev": true }, "node_modules/markdownlint-micromark": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/markdownlint-micromark/-/markdownlint-micromark-0.1.8.tgz", - "integrity": "sha512-1ouYkMRo9/6gou9gObuMDnvZM8jC/ly3QCFQyoSPCS2XV1ZClU0xpKbL1Ar3bWWRT1RnBZkWUEiNKrI2CwiBQA==", + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/markdownlint-micromark/-/markdownlint-micromark-0.1.9.tgz", + "integrity": "sha512-5hVs/DzAFa8XqYosbEAEg6ok6MF2smDj89ztn9pKkCtdKHVdPQuGMH7frFfYL9mLkvfFe4pTyAMffLbjf3/EyA==", "dev": true, "engines": { - "node": ">=16" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/DavidAnson" @@ -8720,23 +8871,23 @@ } }, "node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.1.tgz", + "integrity": "sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==", "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/mlly": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.6.1.tgz", - "integrity": "sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.0.tgz", + "integrity": "sha512-U9SDaXGEREBYQgfejV97coK0UL1r+qnF2SyO9A3qcI8MzKnsIFKHNVEkrDyNncQTKQQumsasmeq84eNMdBfsNQ==", "dev": true, "dependencies": { "acorn": "^8.11.3", "pathe": "^1.1.2", - "pkg-types": "^1.0.3", - "ufo": "^1.3.2" + "pkg-types": "^1.1.0", + "ufo": "^1.5.3" } }, "node_modules/monaco-editor": { @@ -9099,17 +9250,17 @@ } }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -9211,9 +9362,9 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-scurry": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", - "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.0.tgz", + "integrity": "sha512-LNHTaVkzaYaLGlO+0u3rQTz7QrHTFOuKyba9JMTQutkmtNew8dw8wOD7mTU/5fCPZzCWpfW0XnQKzY61P0aTaw==", "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -9225,14 +9376,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.1.tgz", - "integrity": "sha512-tS24spDe/zXhWbNPErCHs/AGOzbKGHT+ybSBqmdLm8WZ1xXLWvH8Qn71QPAlqVhd0qUTWjy+Kl9JmISgDdEjsA==", - "engines": { - "node": "14 || >=16.14" - } - }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -9354,23 +9497,23 @@ } }, "node_modules/pkg-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.0.tgz", - "integrity": "sha512-/RpmvKdxKf8uILTtoOhAgf30wYbP2Qw+L9p3Rvshx1JZVX+XQNZQFjlbmGHEGIm4CkVPlSn+NXmIM8+9oWQaSA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.1.tgz", + "integrity": "sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==", "dev": true, "dependencies": { "confbox": "^0.1.7", - "mlly": "^1.6.1", + "mlly": "^1.7.0", "pathe": "^1.1.2" } }, "node_modules/playwright": { - "version": "1.43.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.1.tgz", - "integrity": "sha512-V7SoH0ai2kNt1Md9E3Gwas5B9m8KR2GVvwZnAI6Pg0m3sh7UvgiYhRrhsziCmqMJNouPckiOhk8T+9bSAK0VIA==", + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.44.0.tgz", + "integrity": "sha512-F9b3GUCLQ3Nffrfb6dunPOkE5Mh68tR7zN32L4jCk4FjQamgesGay7/dAAe1WaMEGV04DkdJfcJzjoCKygUaRQ==", "dev": true, "dependencies": { - "playwright-core": "1.43.1" + "playwright-core": "1.44.0" }, "bin": { "playwright": "cli.js" @@ -9383,9 +9526,9 @@ } }, "node_modules/playwright-core": { - "version": "1.43.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.1.tgz", - "integrity": "sha512-EI36Mto2Vrx6VF7rm708qSnesVQKbxEWvPrfA1IPY6HgczBplDx7ENtx+K2n4kJ41sLLkuGfmb0ZLSSXlDhqPg==", + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.44.0.tgz", + "integrity": "sha512-ZTbkNpFfYcGWohvTTl+xewITm7EOuqIqex0c7dNZ+aXsbrLj0qI8XlGKfPpipjm0Wny/4Lt4CJsWJk1stVS5qQ==", "dev": true, "bin": { "playwright-core": "cli.js" @@ -9449,13 +9592,13 @@ } }, "node_modules/postcss-html": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-1.6.0.tgz", - "integrity": "sha512-OWgQ9/Pe23MnNJC0PL4uZp8k0EDaUvqpJFSiwFxOLClAhmD7UEisyhO3x5hVsD4xFrjReVTXydlrMes45dJ71w==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-1.7.0.tgz", + "integrity": "sha512-MfcMpSUIaR/nNgeVS8AyvyDugXlADjN9AcV7e5rDfrF1wduIAGSkL4q2+wgrZgA3sHVAHLDO9FuauHhZYW2nBw==", "dev": true, "dependencies": { "htmlparser2": "^8.0.0", - "js-tokens": "^8.0.0", + "js-tokens": "^9.0.0", "postcss": "^8.4.0", "postcss-safe-parser": "^6.0.0" }, @@ -9832,9 +9975,9 @@ } }, "node_modules/react-is": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.0.tgz", - "integrity": "sha512-wRiUsea88TjKDc4FBEn+sLvIDesp6brMbGWnJGjew2waAc9evdhja/2LvePc898HJbHw0L+MTWy7NhpnELAvLQ==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, "node_modules/read-cache": { @@ -10346,12 +10489,9 @@ } }, "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "bin": { "semver": "bin/semver.js" }, @@ -10834,12 +10974,6 @@ "url": "https://github.com/sponsors/antfu" } }, - "node_modules/strip-literal/node_modules/js-tokens": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.0.tgz", - "integrity": "sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==", - "dev": true - }, "node_modules/style-search": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", @@ -10847,9 +10981,9 @@ "dev": true }, "node_modules/stylelint": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.4.0.tgz", - "integrity": "sha512-uSx7VMuXwLuYcNSIg+0/fFNv0WinsfLAqsVVy7h7p80clKOHiGE8pfY6UjqwylTHiJrRIahTl6a8FPxGezhWoA==", + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.5.0.tgz", + "integrity": "sha512-IlCBtVrG+qTy3v+tZTk50W8BIomjY/RUuzdrDqdnlCYwVuzXtPbiGfxYqtyYAyOMcb+195zRsuHn6tgfPmFfbw==", "dev": true, "dependencies": { "@csstools/css-parser-algorithms": "^2.6.1", @@ -11100,15 +11234,15 @@ } }, "node_modules/sucrase/node_modules/glob": { - "version": "10.3.12", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", - "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", + "version": "10.3.14", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.14.tgz", + "integrity": "sha512-4fkAqu93xe9Mk7le9v0y3VrPDqLKHarNi2s4Pv7f2yOvfhWfhc7hRPHC/JyqMqb8B/Dt/eGS4n7ykwf3fOsl8g==", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^2.3.6", "minimatch": "^9.0.1", "minipass": "^7.0.4", - "path-scurry": "^1.10.2" + "path-scurry": "^1.11.0" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -11177,9 +11311,9 @@ "dev": true }, "node_modules/svgo": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.2.0.tgz", - "integrity": "sha512-4PP6CMW/V7l/GmKRKzsLR8xxjdHTV4IMvhTnpuHwwBazSIlw5W/5SmPjN8Dwyt7lKbSJrRDgp4t9ph0HgChFBQ==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", + "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", "dev": true, "dependencies": { "@trysound/sax": "0.2.0", @@ -11211,9 +11345,9 @@ } }, "node_modules/swagger-ui-dist": { - "version": "5.17.2", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.17.2.tgz", - "integrity": "sha512-V/NqUw6QoTrjSpctp2oLQvxrl3vW29UsUtZyq7B1CF0v870KOFbYGDQw8rpKaKm0JxTwHpWnW1SN9YuKZdiCyw==" + "version": "5.17.7", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.17.7.tgz", + "integrity": "sha512-hKnq2Dss6Nvqxzj+tToBz0IJvKXgp7FExxX0Zj0rMajXJp8CJ98yLAwbKwKu8rxQf+2iIDUTGir84SCA8AN+fQ==" }, "node_modules/sync-fetch": { "version": "0.4.5", @@ -11362,9 +11496,9 @@ "integrity": "sha512-lDMFv4nKQrSjlkHKAlHVqKrBG4DyFfa9F74cmBZ3Iy3ed8yvWnlWSIdi4IKfSqwmazAohBNwiN64qGx4y5Q3IQ==" }, "node_modules/terser": { - "version": "5.30.4", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.4.tgz", - "integrity": "sha512-xRdd0v64a8mFK9bnsKVdoNP9GQIKUAaJPTaqEQDL4w/J8WaW4sWXXoMZ+6SimPkfT5bElreXf8m9HnmPc3E1BQ==", + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.0.tgz", + "integrity": "sha512-Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg==", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -11547,6 +11681,12 @@ "resolved": "https://registry.npmjs.org/toastify-js/-/toastify-js-1.12.0.tgz", "integrity": "sha512-HeMHCO9yLPvP9k0apGSdPUWrUbLnxUKNFzgUoZp1PHCLploIX/4DSQ7V8H25ef+h4iO9n0he7ImfcndnN6nDrQ==" }, + "node_modules/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", + "dev": true + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -11796,9 +11936,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.15.tgz", + "integrity": "sha512-K9HWH62x3/EalU1U6sjSZiylm9C8tgq2mSvshZpqc7QE69RaA2qjhkW2HlNA0tFpEbtyFz7HTqbSdN4MSwUodA==", "funding": [ { "type": "opencollective", @@ -11814,7 +11954,7 @@ } ], "dependencies": { - "escalade": "^3.1.1", + "escalade": "^3.1.2", "picocolors": "^1.0.0" }, "bin": { @@ -11918,9 +12058,9 @@ "integrity": "sha512-z2YZusTFC6KnLERx1cgoIRX2CjPRP0W75N+3CC6gbvdX5Ch47rZkEMGO2Xnf+IEmi3RiFLxS18gayMA27iU7Kg==" }, "node_modules/vite": { - "version": "5.2.10", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.10.tgz", - "integrity": "sha512-PAzgUZbP7msvQvqdSD+ErD5qGnSFiGOoWmV5yAKUEI0kdhjbH6nMWVyZQC/hSc4aXwc0oJ9aEdIiF9Oje0JFCw==", + "version": "5.2.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.11.tgz", + "integrity": "sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==", "dev": true, "dependencies": { "esbuild": "^0.20.1", @@ -11973,9 +12113,9 @@ } }, "node_modules/vite-node": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.2.tgz", - "integrity": "sha512-Y8p91kz9zU+bWtF7HGt6DVw2JbhyuB2RlZix3FPYAYmUyZ3n7iTp8eSyLyY6sxtPegvxQtmlTMhfPhUfCUF93A==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz", + "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -11995,9 +12135,9 @@ } }, "node_modules/vite-string-plugin": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vite-string-plugin/-/vite-string-plugin-1.2.0.tgz", - "integrity": "sha512-IijlLgTxUDUwOpLoBLZCZO2us4fZWPRpj8XWoD9OAYjjUEge8enV4gaDTOs7uEsC8EJ9+NmusdLwmgWajFO45Q==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/vite-string-plugin/-/vite-string-plugin-1.3.1.tgz", + "integrity": "sha512-0Wu9yNw4QlSVM4SlwozzxR0geMoKFrAIpMldgPuzDvV8lWT1v+0pFXYt+t48qocYXBaxiuVRE3qcsEwFDHBAmA==", "dev": true }, "node_modules/vite/node_modules/@types/estree": { @@ -12021,9 +12161,9 @@ } }, "node_modules/vite/node_modules/rollup": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.16.4.tgz", - "integrity": "sha512-kuaTJSUbz+Wsb2ATGvEknkI12XV40vIiHmLuFlejoo7HtDok/O5eDDD0UpCVY5bBX5U5RYo8wWP83H7ZsqVEnA==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.17.2.tgz", + "integrity": "sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -12036,36 +12176,36 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.16.4", - "@rollup/rollup-android-arm64": "4.16.4", - "@rollup/rollup-darwin-arm64": "4.16.4", - "@rollup/rollup-darwin-x64": "4.16.4", - "@rollup/rollup-linux-arm-gnueabihf": "4.16.4", - "@rollup/rollup-linux-arm-musleabihf": "4.16.4", - "@rollup/rollup-linux-arm64-gnu": "4.16.4", - "@rollup/rollup-linux-arm64-musl": "4.16.4", - "@rollup/rollup-linux-powerpc64le-gnu": "4.16.4", - "@rollup/rollup-linux-riscv64-gnu": "4.16.4", - "@rollup/rollup-linux-s390x-gnu": "4.16.4", - "@rollup/rollup-linux-x64-gnu": "4.16.4", - "@rollup/rollup-linux-x64-musl": "4.16.4", - "@rollup/rollup-win32-arm64-msvc": "4.16.4", - "@rollup/rollup-win32-ia32-msvc": "4.16.4", - "@rollup/rollup-win32-x64-msvc": "4.16.4", + "@rollup/rollup-android-arm-eabi": "4.17.2", + "@rollup/rollup-android-arm64": "4.17.2", + "@rollup/rollup-darwin-arm64": "4.17.2", + "@rollup/rollup-darwin-x64": "4.17.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.17.2", + "@rollup/rollup-linux-arm-musleabihf": "4.17.2", + "@rollup/rollup-linux-arm64-gnu": "4.17.2", + "@rollup/rollup-linux-arm64-musl": "4.17.2", + "@rollup/rollup-linux-powerpc64le-gnu": "4.17.2", + "@rollup/rollup-linux-riscv64-gnu": "4.17.2", + "@rollup/rollup-linux-s390x-gnu": "4.17.2", + "@rollup/rollup-linux-x64-gnu": "4.17.2", + "@rollup/rollup-linux-x64-musl": "4.17.2", + "@rollup/rollup-win32-arm64-msvc": "4.17.2", + "@rollup/rollup-win32-ia32-msvc": "4.17.2", + "@rollup/rollup-win32-x64-msvc": "4.17.2", "fsevents": "~2.3.2" } }, "node_modules/vitest": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.2.tgz", - "integrity": "sha512-l9gwIkq16ug3xY7BxHwcBQovLZG75zZL0PlsiYQbf76Rz6QGs54416UWMtC0jXeihvHvcHrf2ROEjkQRVpoZYw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz", + "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==", "dev": true, "dependencies": { - "@vitest/expect": "1.5.2", - "@vitest/runner": "1.5.2", - "@vitest/snapshot": "1.5.2", - "@vitest/spy": "1.5.2", - "@vitest/utils": "1.5.2", + "@vitest/expect": "1.6.0", + "@vitest/runner": "1.6.0", + "@vitest/snapshot": "1.6.0", + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", "acorn-walk": "^8.3.2", "chai": "^4.3.10", "debug": "^4.3.4", @@ -12079,7 +12219,7 @@ "tinybench": "^2.5.1", "tinypool": "^0.8.3", "vite": "^5.0.0", - "vite-node": "1.5.2", + "vite-node": "1.6.0", "why-is-node-running": "^2.2.2" }, "bin": { @@ -12094,8 +12234,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.5.2", - "@vitest/ui": "1.5.2", + "@vitest/browser": "1.6.0", + "@vitest/ui": "1.6.0", "happy-dom": "*", "jsdom": "*" }, @@ -12130,15 +12270,15 @@ } }, "node_modules/vue": { - "version": "3.4.25", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.25.tgz", - "integrity": "sha512-HWyDqoBHMgav/OKiYA2ZQg+kjfMgLt/T0vg4cbIF7JbXAjDexRf5JRg+PWAfrAkSmTd2I8aPSXtooBFWHB98cg==", + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.27.tgz", + "integrity": "sha512-8s/56uK6r01r1icG/aEOHqyMVxd1bkYcSe9j8HcKtr/xTOFWvnzIVTehNW+5Yt89f+DLBe4A569pnZLS5HzAMA==", "dependencies": { - "@vue/compiler-dom": "3.4.25", - "@vue/compiler-sfc": "3.4.25", - "@vue/runtime-dom": "3.4.25", - "@vue/server-renderer": "3.4.25", - "@vue/shared": "3.4.25" + "@vue/compiler-dom": "3.4.27", + "@vue/compiler-sfc": "3.4.27", + "@vue/runtime-dom": "3.4.27", + "@vue/server-renderer": "3.4.27", + "@vue/shared": "3.4.27" }, "peerDependencies": { "typescript": "*" @@ -12191,6 +12331,35 @@ "eslint": ">=6.0.0" } }, + "node_modules/vue-eslint-parser/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-eslint-parser/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/vue-loader": { "version": "17.4.2", "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-17.4.2.tgz", @@ -12573,6 +12742,15 @@ "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==" }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wrap-ansi": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", @@ -12699,15 +12877,10 @@ "node": ">=10" } }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/yaml": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", - "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", + "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==", "bin": { "yaml": "bin.mjs" }, diff --git a/package.json b/package.json index 107f0c96cf..d0de1efd5a 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ }, "dependencies": { "@citation-js/core": "0.7.11", - "@citation-js/plugin-bibtex": "0.7.11", + "@citation-js/plugin-bibtex": "0.7.12", "@citation-js/plugin-csl": "0.7.11", "@citation-js/plugin-software-formats": "0.6.1", "@github/markdown-toolbar-element": "2.2.3", @@ -14,15 +14,15 @@ "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", "@primer/octicons": "19.9.0", "@silverwind/vue3-calendar-heatmap": "2.0.6", - "add-asset-webpack-plugin": "2.0.1", + "add-asset-webpack-plugin": "3.0.0", "ansi_up": "6.0.2", "asciinema-player": "3.7.1", "chart.js": "4.4.2", "chartjs-adapter-dayjs-4": "1.0.4", "chartjs-plugin-zoom": "2.0.1", - "clippie": "4.0.7", + "clippie": "4.1.1", "css-loader": "7.1.1", - "dayjs": "1.11.10", + "dayjs": "1.11.11", "dropzone": "6.0.0-beta.2", "easymde": "2.18.0", "esbuild-loader": "4.1.0", @@ -43,7 +43,7 @@ "postcss-loader": "8.1.1", "postcss-nesting": "12.1.2", "sortablejs": "1.15.2", - "swagger-ui-dist": "5.17.2", + "swagger-ui-dist": "5.17.7", "tailwindcss": "3.4.3", "temporal-polyfill": "0.2.4", "throttle-debounce": "5.0.0", @@ -53,7 +53,7 @@ "tributejs": "5.1.3", "uint8-to-base64": "0.2.0", "vanilla-colorful": "0.7.2", - "vue": "3.4.25", + "vue": "3.4.27", "vue-bar-graph": "2.0.0", "vue-chartjs": "5.3.1", "vue-loader": "17.4.2", @@ -63,10 +63,10 @@ }, "devDependencies": { "@eslint-community/eslint-plugin-eslint-comments": "4.3.0", - "@playwright/test": "1.43.1", + "@playwright/test": "1.44.0", "@stoplight/spectral-cli": "6.11.1", - "@stylistic/eslint-plugin-js": "1.7.2", - "@stylistic/stylelint-plugin": "2.1.1", + "@stylistic/eslint-plugin-js": "2.1.0", + "@stylistic/stylelint-plugin": "2.1.2", "@vitejs/plugin-vue": "5.0.4", "eslint": "8.57.0", "eslint-plugin-array-func": "4.0.0", @@ -76,24 +76,24 @@ "eslint-plugin-no-jquery": "2.7.0", "eslint-plugin-no-use-extend-native": "0.5.0", "eslint-plugin-regexp": "2.5.0", - "eslint-plugin-sonarjs": "0.25.1", - "eslint-plugin-unicorn": "52.0.0", + "eslint-plugin-sonarjs": "1.0.3", + "eslint-plugin-unicorn": "53.0.0", "eslint-plugin-vitest": "0.4.1", "eslint-plugin-vitest-globals": "1.5.0", - "eslint-plugin-vue": "9.25.0", + "eslint-plugin-vue": "9.26.0", "eslint-plugin-vue-scoped-css": "2.8.0", "eslint-plugin-wc": "2.1.0", - "happy-dom": "14.7.1", - "markdownlint-cli": "0.39.0", - "postcss-html": "1.6.0", - "stylelint": "16.4.0", + "happy-dom": "14.10.1", + "markdownlint-cli": "0.40.0", + "postcss-html": "1.7.0", + "stylelint": "16.5.0", "stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-declaration-strict-value": "1.10.4", "stylelint-value-no-unknown-custom-properties": "6.0.1", - "svgo": "3.2.0", + "svgo": "3.3.2", "updates": "16.0.1", - "vite-string-plugin": "1.2.0", - "vitest": "1.5.2" + "vite-string-plugin": "1.3.1", + "vitest": "1.6.0" }, "browserslist": [ "defaults" From 40de54ece82356b161cdb9cc224ed9004af8ae5d Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Sat, 11 May 2024 22:16:09 +0800 Subject: [PATCH 302/370] Remove If Exist check on migration for mssql because that syntax required SQL server 2016 (#30894) Fix #30872 We will assume the database is consistent before executing the migration. So the indexes should exist. Removing `IF EXIST` then is safe enough. --------- Co-authored-by: silverwind <me@silverwind.io> --- .../Test_RepositoryFormat/review_state.yml | 2 ++ models/migrations/v1_22/v286.go | 6 +++--- models/migrations/v1_22/v286_test.go | 14 +++++++------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/models/migrations/fixtures/Test_RepositoryFormat/review_state.yml b/models/migrations/fixtures/Test_RepositoryFormat/review_state.yml index 1197b086e3..dd64980916 100644 --- a/models/migrations/fixtures/Test_RepositoryFormat/review_state.yml +++ b/models/migrations/fixtures/Test_RepositoryFormat/review_state.yml @@ -1,3 +1,5 @@ - id: 1 + user_id: 1 + pull_id: 1 commit_sha: 19fe5caf872476db265596eaac1dc35ad1c6422d diff --git a/models/migrations/v1_22/v286.go b/models/migrations/v1_22/v286.go index f46d494dfe..e11d16f8de 100644 --- a/models/migrations/v1_22/v286.go +++ b/models/migrations/v1_22/v286.go @@ -36,9 +36,9 @@ func expandHashReferencesToSha256(x *xorm.Engine) error { if setting.Database.Type.IsMSSQL() { // drop indexes that need to be re-created afterwards droppedIndexes := []string{ - "DROP INDEX IF EXISTS [IDX_commit_status_context_hash] ON [commit_status]", - "DROP INDEX IF EXISTS [UQE_review_state_pull_commit_user] ON [review_state]", - "DROP INDEX IF EXISTS [UQE_repo_archiver_s] ON [repo_archiver]", + "DROP INDEX [IDX_commit_status_context_hash] ON [commit_status]", + "DROP INDEX [UQE_review_state_pull_commit_user] ON [review_state]", + "DROP INDEX [UQE_repo_archiver_s] ON [repo_archiver]", } for _, s := range droppedIndexes { _, err := db.Exec(s) diff --git a/models/migrations/v1_22/v286_test.go b/models/migrations/v1_22/v286_test.go index 7c353747e3..a19c9396e2 100644 --- a/models/migrations/v1_22/v286_test.go +++ b/models/migrations/v1_22/v286_test.go @@ -19,21 +19,21 @@ func PrepareOldRepository(t *testing.T) (*xorm.Engine, func()) { type CommitStatus struct { ID int64 - ContextHash string + ContextHash string `xorm:"char(40) index"` } type RepoArchiver struct { ID int64 - RepoID int64 - Type int - CommitID string + RepoID int64 `xorm:"index unique(s)"` + Type int `xorm:"unique(s)"` + CommitID string `xorm:"VARCHAR(40) unique(s)"` } type ReviewState struct { ID int64 - CommitSHA string - UserID int64 - PullID int64 + UserID int64 `xorm:"NOT NULL UNIQUE(pull_commit_user)"` + PullID int64 `xorm:"NOT NULL INDEX UNIQUE(pull_commit_user) DEFAULT 0"` + CommitSHA string `xorm:"NOT NULL VARCHAR(40) UNIQUE(pull_commit_user)"` } type Comment struct { From 3c2406a2f3008431d0a4956d7e8f68f7352e0613 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sat, 11 May 2024 16:28:56 +0200 Subject: [PATCH 303/370] Use CSS `inset` shorthand (#30939) Use [inset](https://developer.mozilla.org/en-US/docs/Web/CSS/inset) shorthand instead of longhands. There may be more cases but these ones I was able to definitely identify. --- web_src/css/helpers.css | 5 +---- web_src/css/markup/content.css | 5 +---- web_src/css/modules/dimmer.css | 5 +---- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/web_src/css/helpers.css b/web_src/css/helpers.css index 4d12dfaea2..60ecd7db72 100644 --- a/web_src/css/helpers.css +++ b/web_src/css/helpers.css @@ -20,10 +20,7 @@ Gitea's private styles use `g-` prefix. .g-table-auto-ellipsis td.auto-ellipsis span { position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; + inset: 0; padding: inherit; white-space: nowrap; overflow: hidden; diff --git a/web_src/css/markup/content.css b/web_src/css/markup/content.css index 6ba4e40072..3eb40eaf29 100644 --- a/web_src/css/markup/content.css +++ b/web_src/css/markup/content.css @@ -204,10 +204,7 @@ .markup input[type="checkbox"]::after { position: absolute; - left: 0; - top: 0; - bottom: 0; - right: 0; + inset: 0; pointer-events: none; background: var(--color-text); mask-size: cover; diff --git a/web_src/css/modules/dimmer.css b/web_src/css/modules/dimmer.css index a552d103e5..8924821370 100644 --- a/web_src/css/modules/dimmer.css +++ b/web_src/css/modules/dimmer.css @@ -3,10 +3,7 @@ .ui.dimmer { position: fixed; display: none; - top: 0; - left: 0; - right: 0; - bottom: 0; + inset: 0; background: var(--color-overlay-backdrop); opacity: 0; z-index: 1000; From 26ae5922348d2dbaf2161bbd6ac79b2aa455e5f0 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Sat, 11 May 2024 22:55:49 +0800 Subject: [PATCH 304/370] Move reverproxyauth before session so the header will not be ignored even if user has login (#27821) When a user logout and then login another user, the reverseproxy auth should be checked before session otherwise the old user is still login. --- routers/web/web.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/routers/web/web.go b/routers/web/web.go index f3b9969059..194a67bf03 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -98,14 +98,14 @@ func optionsCorsHandler() func(next http.Handler) http.Handler { // The Session plugin is expected to be executed second, in order to skip authentication // for users that have already signed in. func buildAuthGroup() *auth_service.Group { - group := auth_service.NewGroup( - &auth_service.OAuth2{}, // FIXME: this should be removed and only applied in download and oauth related routers - &auth_service.Basic{}, // FIXME: this should be removed and only applied in download and git/lfs routers - &auth_service.Session{}, - ) + group := auth_service.NewGroup() + group.Add(&auth_service.OAuth2{}) // FIXME: this should be removed and only applied in download and oauth related routers + group.Add(&auth_service.Basic{}) // FIXME: this should be removed and only applied in download and git/lfs routers + if setting.Service.EnableReverseProxyAuth { - group.Add(&auth_service.ReverseProxy{}) + group.Add(&auth_service.ReverseProxy{}) // reverseproxy should before Session, otherwise the header will be ignored if user has login } + group.Add(&auth_service.Session{}) if setting.IsWindows && auth_model.IsSSPIEnabled(db.DefaultContext) { group.Add(&auth_service.SSPI{}) // it MUST be the last, see the comment of SSPI From f80b403dc9a263f0805ba9e3cfa9a83af63dc1a0 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Sun, 12 May 2024 00:27:35 +0000 Subject: [PATCH 305/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_pt-PT.ini | 1 + options/locale/locale_zh-CN.ini | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 7d799a20ba..642d8915cf 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -3320,6 +3320,7 @@ self_check.database_collation_case_insensitive=A base de dados está a usar a co self_check.database_inconsistent_collation_columns=A base de dados está a usar a colação %s, mas estas colunas estão a usar colações diferentes. Isso poderá causar alguns problemas inesperados. self_check.database_fix_mysql=Para utilizadores do MySQL/MariaDB, pode usar o comando "gitea doctor convert" para resolver os problemas de colação. Também pode resolver o problema com comandos SQL "ALTER ... COLLATE ..." aplicados manualmente. self_check.database_fix_mssql=Para utilizadores do MSSQL só pode resolver o problema aplicando comandos SQL "ALTER ... COLLATE ..." manualmente, por enquanto. +self_check.location_origin_mismatch=O URL corrente (%[1]s) não corresponde ao URL visto pelo Gitea (%[2]s). Se estiver a usar um reverse proxy, certifique-se que os cabeçalhos "Host" e "X-Forwarded-Proto" estão bem definidos. [action] create_repo=criou o repositório <a href="%s">%s</a> diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 599f0d3b07..c98af46d45 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -2398,7 +2398,7 @@ settings.ignore_stale_approvals_desc=对旧提交(过期审核)的批准将 settings.require_signed_commits=需要签名提交 settings.require_signed_commits_desc=拒绝推送未签名或无法验证的提交到分支 settings.protect_branch_name_pattern=受保护的分支名称模式 -settings.protect_branch_name_pattern_desc=分支保护的名称匹配规则。语法请参阅 <a href="github.com/gobwas/glob">文档</a> 。如:main, release/** +settings.protect_branch_name_pattern_desc=分支保护的名称匹配规则。语法请参阅 <a href="https://github.com/gobwas/glob">文档</a> 。如:main, release/** settings.protect_patterns=规则 settings.protect_protected_file_patterns=受保护的文件模式(使用分号 ';' 分隔): settings.protect_protected_file_patterns_desc=即使用户有权添加、编辑或删除此分支中的文件,也不允许直接更改受保护的文件。 可以使用分号 (';') 分隔多个模式。 见<a href='https://pkg.go.dev/github.com/gobwas/glob#Compile'>github.com/gobwas/glob</a>文档了解模式语法。例如: <code>.drone.yml</code>, <code>/docs/**/*.txt</code> From 46b7004f050bd2fdaf9800794cf2c1e9eeb08d51 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 12 May 2024 04:33:05 +0200 Subject: [PATCH 306/370] Enable `declaration-block-no-redundant-longhand-properties` (#30950) Enable [`declaration-block-no-redundant-longhand-properties`](https://stylelint.io/user-guide/rules/declaration-block-no-redundant-longhand-properties/) and autofix issues. The exclusions are because I find these two shorthands to be harder to read. --- stylelint.config.js | 2 +- web_src/css/modules/grid.css | 5 +---- web_src/css/modules/menu.css | 4 +--- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/stylelint.config.js b/stylelint.config.js index 6fee242685..977c35d9d5 100644 --- a/stylelint.config.js +++ b/stylelint.config.js @@ -141,7 +141,7 @@ export default { 'custom-property-pattern': null, 'declaration-block-no-duplicate-custom-properties': true, 'declaration-block-no-duplicate-properties': [true, {ignore: ['consecutive-duplicates-with-different-values']}], - 'declaration-block-no-redundant-longhand-properties': null, + 'declaration-block-no-redundant-longhand-properties': [true, {ignoreShorthands: ['flex-flow', 'overflow']}], 'declaration-block-no-shorthand-property-overrides': null, 'declaration-block-single-line-max-declarations': null, 'declaration-empty-line-before': null, diff --git a/web_src/css/modules/grid.css b/web_src/css/modules/grid.css index 4aaa452372..a2c558047d 100644 --- a/web_src/css/modules/grid.css +++ b/web_src/css/modules/grid.css @@ -7,10 +7,7 @@ flex-wrap: wrap; align-items: stretch; padding: 0; - margin-top: -1rem; - margin-bottom: -1rem; - margin-left: -1rem; - margin-right: -1rem; + margin: -1rem; } .ui.relaxed.grid { diff --git a/web_src/css/modules/menu.css b/web_src/css/modules/menu.css index 76a576cd53..ff9d7fc5d0 100644 --- a/web_src/css/modules/menu.css +++ b/web_src/css/modules/menu.css @@ -553,13 +553,11 @@ border-bottom: 2px solid var(--color-secondary); } .ui.secondary.pointing.menu .item { - border-bottom-color: transparent; - border-bottom-style: solid; + border-bottom: 2px solid transparent; border-radius: 0; align-self: flex-end; margin: 0 0 -2px; padding: 0.85714286em 1.14285714em; - border-bottom-width: 2px; } .ui.secondary.pointing.menu .ui.dropdown .menu .item { border-bottom-width: 0; From 301eaf60bfb1e4a784763cb066bc9fd1da86468b Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 12 May 2024 06:02:25 +0200 Subject: [PATCH 307/370] Fix file path width in repo non-homepage view (#30951) Fixes: https://github.com/go-gitea/gitea/issues/30940 <img width="1310" alt="Screenshot 2024-05-11 at 20 48 41" src="https://github.com/go-gitea/gitea/assets/115237/f163dfd4-1299-421f-a99e-cd0c793e0e3d"> --- templates/repo/home.tmpl | 2 +- web_src/css/repo.css | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 6df9f7d72a..ef76f3ed5d 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -45,7 +45,7 @@ {{$n := len .TreeNames}} {{$l := Eval $n "-" 1}} {{$isHomepage := (eq $n 0)}} - <div class="repo-button-row"> + <div class="repo-button-row" data-is-homepage="{{$isHomepage}}"> <div class="repo-button-row-left"> {{template "repo/branch_dropdown" dict "root" . "ContainerClasses" "tw-mr-1"}} {{if and .CanCompareOrPull .IsViewBranch (not .Repository.IsArchived)}} diff --git a/web_src/css/repo.css b/web_src/css/repo.css index d42b3b45bd..56235f8ebe 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -2256,6 +2256,10 @@ td .commit-summary { justify-content: flex-end; } +.repo-button-row[data-is-homepage="false"] .repo-button-row-right { + flex-grow: 0; +} + @media (max-width: 991px) { .repository:not(.wiki) .repo-button-row { flex-direction: column; From 2442ead6807528f5791671b8a3aab6629bae66ad Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Mon, 13 May 2024 00:26:15 +0000 Subject: [PATCH 308/370] [skip ci] Updated licenses and gitignores --- options/gitignore/Go | 1 + options/gitignore/Python | 4 +- options/license/CC-BY-3.0 | 350 ++++++++++++--- options/license/CC-BY-NC-3.0 | 367 +++++++++++++--- options/license/CC-BY-NC-ND-3.0 | 335 ++++++++++++--- options/license/CC-BY-NC-SA-3.0 | 397 +++++++++++++++--- options/license/CC-BY-ND-3.0 | 318 +++++++++++--- options/license/CC-BY-SA-3.0 | 396 ++++++++++++++--- .../HPND-sell-variant-MIT-disclaimer-rev | 15 + options/license/LGPL-2.0-only | 1 + options/license/LGPL-2.0-or-later | 1 + options/license/LGPL-2.1-only | 1 + options/license/LGPL-2.1-or-later | 1 + options/license/PCRE2-exception | 8 + options/license/PPL | 96 +++++ options/license/any-OSI | 3 + options/license/cve-tou | 16 + 17 files changed, 1933 insertions(+), 377 deletions(-) create mode 100644 options/license/HPND-sell-variant-MIT-disclaimer-rev create mode 100644 options/license/PCRE2-exception create mode 100644 options/license/PPL create mode 100644 options/license/any-OSI create mode 100644 options/license/cve-tou diff --git a/options/gitignore/Go b/options/gitignore/Go index 3b735ec4a8..6f6f5e6adc 100644 --- a/options/gitignore/Go +++ b/options/gitignore/Go @@ -19,3 +19,4 @@ # Go workspace file go.work +go.work.sum diff --git a/options/gitignore/Python b/options/gitignore/Python index 68bc17f9ff..82f927558a 100644 --- a/options/gitignore/Python +++ b/options/gitignore/Python @@ -106,8 +106,10 @@ ipython_config.py #pdm.lock # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it # in version control. -# https://pdm.fming.dev/#use-with-ide +# https://pdm.fming.dev/latest/usage/project/#working-with-version-control .pdm.toml +.pdm-python +.pdm-build/ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm __pypackages__/ diff --git a/options/license/CC-BY-3.0 b/options/license/CC-BY-3.0 index 465aae75c5..1a16e05564 100644 --- a/options/license/CC-BY-3.0 +++ b/options/license/CC-BY-3.0 @@ -1,93 +1,319 @@ -Creative Commons Attribution 3.0 Unported +Creative Commons Legal Code - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. +Attribution 3.0 Unported + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR + DAMAGES RESULTING FROM ITS USE. License -THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE +COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY +COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS +AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. -BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE +TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY +BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS +CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND +CONDITIONS. 1. Definitions - a. "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. + a. "Adaptation" means a work based upon the Work, or upon the Work and + other pre-existing works, such as a translation, adaptation, + derivative work, arrangement of music or other alterations of a + literary or artistic work, or phonogram or performance and includes + cinematographic adaptations or any other form in which the Work may be + recast, transformed, or adapted including in any form recognizably + derived from the original, except that a work that constitutes a + Collection will not be considered an Adaptation for the purpose of + this License. For the avoidance of doubt, where the Work is a musical + work, performance or phonogram, the synchronization of the Work in + timed-relation with a moving image ("synching") will be considered an + Adaptation for the purpose of this License. + b. "Collection" means a collection of literary or artistic works, such as + encyclopedias and anthologies, or performances, phonograms or + broadcasts, or other works or subject matter other than works listed + in Section 1(f) below, which, by reason of the selection and + arrangement of their contents, constitute intellectual creations, in + which the Work is included in its entirety in unmodified form along + with one or more other contributions, each constituting separate and + independent works in themselves, which together are assembled into a + collective whole. A work that constitutes a Collection will not be + considered an Adaptation (as defined above) for the purposes of this + License. + c. "Distribute" means to make available to the public the original and + copies of the Work or Adaptation, as appropriate, through sale or + other transfer of ownership. + d. "Licensor" means the individual, individuals, entity or entities that + offer(s) the Work under the terms of this License. + e. "Original Author" means, in the case of a literary or artistic work, + the individual, individuals, entity or entities who created the Work + or if no individual or entity can be identified, the publisher; and in + addition (i) in the case of a performance the actors, singers, + musicians, dancers, and other persons who act, sing, deliver, declaim, + play in, interpret or otherwise perform literary or artistic works or + expressions of folklore; (ii) in the case of a phonogram the producer + being the person or legal entity who first fixes the sounds of a + performance or other sounds; and, (iii) in the case of broadcasts, the + organization that transmits the broadcast. + f. "Work" means the literary and/or artistic work offered under the terms + of this License including without limitation any production in the + literary, scientific and artistic domain, whatever may be the mode or + form of its expression including digital form, such as a book, + pamphlet and other writing; a lecture, address, sermon or other work + of the same nature; a dramatic or dramatico-musical work; a + choreographic work or entertainment in dumb show; a musical + composition with or without words; a cinematographic work to which are + assimilated works expressed by a process analogous to cinematography; + a work of drawing, painting, architecture, sculpture, engraving or + lithography; a photographic work to which are assimilated works + expressed by a process analogous to photography; a work of applied + art; an illustration, map, plan, sketch or three-dimensional work + relative to geography, topography, architecture or science; a + performance; a broadcast; a phonogram; a compilation of data to the + extent it is protected as a copyrightable work; or a work performed by + a variety or circus performer to the extent it is not otherwise + considered a literary or artistic work. + g. "You" means an individual or entity exercising rights under this + License who has not previously violated the terms of this License with + respect to the Work, or who has received express permission from the + Licensor to exercise rights under this License despite a previous + violation. + h. "Publicly Perform" means to perform public recitations of the Work and + to communicate to the public those public recitations, by any means or + process, including by wire or wireless means or public digital + performances; to make available to the public Works in such a way that + members of the public may access these Works from a place and at a + place individually chosen by them; to perform the Work to the public + by any means or process and the communication to the public of the + performances of the Work, including by public digital performance; to + broadcast and rebroadcast the Work by any means including signs, + sounds or images. + i. "Reproduce" means to make copies of the Work by any means including + without limitation by sound or visual recordings and the right of + fixation and reproducing fixations of the Work, including storage of a + protected performance or phonogram in digital form or other electronic + medium. - b. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License. +2. Fair Dealing Rights. Nothing in this License is intended to reduce, +limit, or restrict any uses free from copyright or rights arising from +limitations or exceptions that are provided for in connection with the +copyright protection under copyright law or other applicable laws. - c. "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership. +3. License Grant. Subject to the terms and conditions of this License, +Licensor hereby grants You a worldwide, royalty-free, non-exclusive, +perpetual (for the duration of the applicable copyright) license to +exercise the rights in the Work as stated below: - d. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. + a. to Reproduce the Work, to incorporate the Work into one or more + Collections, and to Reproduce the Work as incorporated in the + Collections; + b. to create and Reproduce Adaptations provided that any such Adaptation, + including any translation in any medium, takes reasonable steps to + clearly label, demarcate or otherwise identify that changes were made + to the original Work. For example, a translation could be marked "The + original work was translated from English to Spanish," or a + modification could indicate "The original work has been modified."; + c. to Distribute and Publicly Perform the Work including as incorporated + in Collections; and, + d. to Distribute and Publicly Perform Adaptations. + e. For the avoidance of doubt: - e. "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. + i. Non-waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme cannot be waived, the Licensor + reserves the exclusive right to collect such royalties for any + exercise by You of the rights granted under this License; + ii. Waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme can be waived, the Licensor waives the + exclusive right to collect such royalties for any exercise by You + of the rights granted under this License; and, + iii. Voluntary License Schemes. The Licensor waives the right to + collect royalties, whether individually or, in the event that the + Licensor is a member of a collecting society that administers + voluntary licensing schemes, via that society, from any exercise + by You of the rights granted under this License. - f. "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. +The above rights may be exercised in all media and formats whether now +known or hereafter devised. The above rights include the right to make +such modifications as are technically necessary to exercise the rights in +other media and formats. Subject to Section 8(f), all rights not expressly +granted by Licensor are hereby reserved. - g. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. +4. Restrictions. The license granted in Section 3 above is expressly made +subject to and limited by the following restrictions: - h. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. - - i. "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. - -2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. - -3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: - - a. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; - - b. to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified."; - - c. to Distribute and Publicly Perform the Work including as incorporated in Collections; and, - - d. to Distribute and Publicly Perform Adaptations. - - e. For the avoidance of doubt: - - i. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; - - ii. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and, - - iii. Voluntary License Schemes. The Licensor waives the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License. - -The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved. - -4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: - - a. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(b), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(b), as requested. - - b. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and (iv) , consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4 (b) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. - - c. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise. + a. You may Distribute or Publicly Perform the Work only under the terms + of this License. You must include a copy of, or the Uniform Resource + Identifier (URI) for, this License with every copy of the Work You + Distribute or Publicly Perform. You may not offer or impose any terms + on the Work that restrict the terms of this License or the ability of + the recipient of the Work to exercise the rights granted to that + recipient under the terms of the License. You may not sublicense the + Work. You must keep intact all notices that refer to this License and + to the disclaimer of warranties with every copy of the Work You + Distribute or Publicly Perform. When You Distribute or Publicly + Perform the Work, You may not impose any effective technological + measures on the Work that restrict the ability of a recipient of the + Work from You to exercise the rights granted to that recipient under + the terms of the License. This Section 4(a) applies to the Work as + incorporated in a Collection, but this does not require the Collection + apart from the Work itself to be made subject to the terms of this + License. If You create a Collection, upon notice from any Licensor You + must, to the extent practicable, remove from the Collection any credit + as required by Section 4(b), as requested. If You create an + Adaptation, upon notice from any Licensor You must, to the extent + practicable, remove from the Adaptation any credit as required by + Section 4(b), as requested. + b. If You Distribute, or Publicly Perform the Work or any Adaptations or + Collections, You must, unless a request has been made pursuant to + Section 4(a), keep intact all copyright notices for the Work and + provide, reasonable to the medium or means You are utilizing: (i) the + name of the Original Author (or pseudonym, if applicable) if supplied, + and/or if the Original Author and/or Licensor designate another party + or parties (e.g., a sponsor institute, publishing entity, journal) for + attribution ("Attribution Parties") in Licensor's copyright notice, + terms of service or by other reasonable means, the name of such party + or parties; (ii) the title of the Work if supplied; (iii) to the + extent reasonably practicable, the URI, if any, that Licensor + specifies to be associated with the Work, unless such URI does not + refer to the copyright notice or licensing information for the Work; + and (iv) , consistent with Section 3(b), in the case of an Adaptation, + a credit identifying the use of the Work in the Adaptation (e.g., + "French translation of the Work by Original Author," or "Screenplay + based on original Work by Original Author"). The credit required by + this Section 4 (b) may be implemented in any reasonable manner; + provided, however, that in the case of a Adaptation or Collection, at + a minimum such credit will appear, if a credit for all contributing + authors of the Adaptation or Collection appears, then as part of these + credits and in a manner at least as prominent as the credits for the + other contributing authors. For the avoidance of doubt, You may only + use the credit required by this Section for the purpose of attribution + in the manner set out above and, by exercising Your rights under this + License, You may not implicitly or explicitly assert or imply any + connection with, sponsorship or endorsement by the Original Author, + Licensor and/or Attribution Parties, as appropriate, of You or Your + use of the Work, without the separate, express prior written + permission of the Original Author, Licensor and/or Attribution + Parties. + c. Except as otherwise agreed in writing by the Licensor or as may be + otherwise permitted by applicable law, if You Reproduce, Distribute or + Publicly Perform the Work either by itself or as part of any + Adaptations or Collections, You must not distort, mutilate, modify or + take other derogatory action in relation to the Work which would be + prejudicial to the Original Author's honor or reputation. Licensor + agrees that in those jurisdictions (e.g. Japan), in which any exercise + of the right granted in Section 3(b) of this License (the right to + make Adaptations) would be deemed to be a distortion, mutilation, + modification or other derogatory action prejudicial to the Original + Author's honor and reputation, the Licensor will waive or not assert, + as appropriate, this Section, to the fullest extent permitted by the + applicable national law, to enable You to reasonably exercise Your + right under Section 3(b) of this License (right to make Adaptations) + but not otherwise. 5. Representations, Warranties and Disclaimer -UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR +OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY +KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, +INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, +FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF +LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, +WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION +OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. -6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE +LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR +ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES +ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. Termination - a. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. - - b. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. + a. This License and the rights granted hereunder will terminate + automatically upon any breach by You of the terms of this License. + Individuals or entities who have received Adaptations or Collections + from You under this License, however, will not have their licenses + terminated provided such individuals or entities remain in full + compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will + survive any termination of this License. + b. Subject to the above terms and conditions, the license granted here is + perpetual (for the duration of the applicable copyright in the Work). + Notwithstanding the above, Licensor reserves the right to release the + Work under different license terms or to stop distributing the Work at + any time; provided, however that any such election will not serve to + withdraw this License (or any other license that has been, or is + required to be, granted under the terms of this License), and this + License will continue in full force and effect unless terminated as + stated above. 8. Miscellaneous - a. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. + a. Each time You Distribute or Publicly Perform the Work or a Collection, + the Licensor offers to the recipient a license to the Work on the same + terms and conditions as the license granted to You under this License. + b. Each time You Distribute or Publicly Perform an Adaptation, Licensor + offers to the recipient a license to the original Work on the same + terms and conditions as the license granted to You under this License. + c. If any provision of this License is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this License, and without further action + by the parties to this agreement, such provision shall be reformed to + the minimum extent necessary to make such provision valid and + enforceable. + d. No term or provision of this License shall be deemed waived and no + breach consented to unless such waiver or consent shall be in writing + and signed by the party to be charged with such waiver or consent. + e. This License constitutes the entire agreement between the parties with + respect to the Work licensed here. There are no understandings, + agreements or representations with respect to the Work not specified + here. Licensor shall not be bound by any additional provisions that + may appear in any communication from You. This License may not be + modified without the mutual written agreement of the Licensor and You. + f. The rights granted under, and the subject matter referenced, in this + License were drafted utilizing the terminology of the Berne Convention + for the Protection of Literary and Artistic Works (as amended on + September 28, 1979), the Rome Convention of 1961, the WIPO Copyright + Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 + and the Universal Copyright Convention (as revised on July 24, 1971). + These rights and subject matter take effect in the relevant + jurisdiction in which the License terms are sought to be enforced + according to the corresponding provisions of the implementation of + those treaty provisions in the applicable national law. If the + standard suite of rights granted under applicable copyright law + includes additional rights not granted under this License, such + additional rights are deemed to be included in the License; this + License is not intended to restrict the license of any rights under + applicable law. - b. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. - - c. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - - d. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. - - e. This License may not be modified without the mutual written agreement of the Licensor and You. - - f. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. Creative Commons Notice -Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor. + Creative Commons is not a party to this License, and makes no warranty + whatsoever in connection with the Work. Creative Commons will not be + liable to You or any party on any legal theory for any damages + whatsoever, including without limitation any general, special, + incidental or consequential damages arising in connection to this + license. Notwithstanding the foregoing two (2) sentences, if Creative + Commons has expressly identified itself as the Licensor hereunder, it + shall have all rights and obligations of Licensor. -Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of this License. + Except for the limited purpose of indicating to the public that the + Work is licensed under the CCPL, Creative Commons does not authorize + the use by either party of the trademark "Creative Commons" or any + related trademark or logo of Creative Commons without the prior + written consent of Creative Commons. Any permitted use will be in + compliance with Creative Commons' then-current trademark usage + guidelines, as may be published on its website or otherwise made + available upon request from time to time. For the avoidance of doubt, + this trademark restriction does not form part of this License. -Creative Commons may be contacted at http://creativecommons.org/. + Creative Commons may be contacted at https://creativecommons.org/. diff --git a/options/license/CC-BY-NC-3.0 b/options/license/CC-BY-NC-3.0 index 314fdb212b..197ec4de65 100644 --- a/options/license/CC-BY-NC-3.0 +++ b/options/license/CC-BY-NC-3.0 @@ -1,95 +1,334 @@ -Creative Commons Attribution-NonCommercial 3.0 Unported +Creative Commons Legal Code - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. +Attribution-NonCommercial 3.0 Unported + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR + DAMAGES RESULTING FROM ITS USE. License -THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE +COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY +COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS +AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. -BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE +TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY +BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS +CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND +CONDITIONS. 1. Definitions - a. "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. + a. "Adaptation" means a work based upon the Work, or upon the Work and + other pre-existing works, such as a translation, adaptation, + derivative work, arrangement of music or other alterations of a + literary or artistic work, or phonogram or performance and includes + cinematographic adaptations or any other form in which the Work may be + recast, transformed, or adapted including in any form recognizably + derived from the original, except that a work that constitutes a + Collection will not be considered an Adaptation for the purpose of + this License. For the avoidance of doubt, where the Work is a musical + work, performance or phonogram, the synchronization of the Work in + timed-relation with a moving image ("synching") will be considered an + Adaptation for the purpose of this License. + b. "Collection" means a collection of literary or artistic works, such as + encyclopedias and anthologies, or performances, phonograms or + broadcasts, or other works or subject matter other than works listed + in Section 1(f) below, which, by reason of the selection and + arrangement of their contents, constitute intellectual creations, in + which the Work is included in its entirety in unmodified form along + with one or more other contributions, each constituting separate and + independent works in themselves, which together are assembled into a + collective whole. A work that constitutes a Collection will not be + considered an Adaptation (as defined above) for the purposes of this + License. + c. "Distribute" means to make available to the public the original and + copies of the Work or Adaptation, as appropriate, through sale or + other transfer of ownership. + d. "Licensor" means the individual, individuals, entity or entities that + offer(s) the Work under the terms of this License. + e. "Original Author" means, in the case of a literary or artistic work, + the individual, individuals, entity or entities who created the Work + or if no individual or entity can be identified, the publisher; and in + addition (i) in the case of a performance the actors, singers, + musicians, dancers, and other persons who act, sing, deliver, declaim, + play in, interpret or otherwise perform literary or artistic works or + expressions of folklore; (ii) in the case of a phonogram the producer + being the person or legal entity who first fixes the sounds of a + performance or other sounds; and, (iii) in the case of broadcasts, the + organization that transmits the broadcast. + f. "Work" means the literary and/or artistic work offered under the terms + of this License including without limitation any production in the + literary, scientific and artistic domain, whatever may be the mode or + form of its expression including digital form, such as a book, + pamphlet and other writing; a lecture, address, sermon or other work + of the same nature; a dramatic or dramatico-musical work; a + choreographic work or entertainment in dumb show; a musical + composition with or without words; a cinematographic work to which are + assimilated works expressed by a process analogous to cinematography; + a work of drawing, painting, architecture, sculpture, engraving or + lithography; a photographic work to which are assimilated works + expressed by a process analogous to photography; a work of applied + art; an illustration, map, plan, sketch or three-dimensional work + relative to geography, topography, architecture or science; a + performance; a broadcast; a phonogram; a compilation of data to the + extent it is protected as a copyrightable work; or a work performed by + a variety or circus performer to the extent it is not otherwise + considered a literary or artistic work. + g. "You" means an individual or entity exercising rights under this + License who has not previously violated the terms of this License with + respect to the Work, or who has received express permission from the + Licensor to exercise rights under this License despite a previous + violation. + h. "Publicly Perform" means to perform public recitations of the Work and + to communicate to the public those public recitations, by any means or + process, including by wire or wireless means or public digital + performances; to make available to the public Works in such a way that + members of the public may access these Works from a place and at a + place individually chosen by them; to perform the Work to the public + by any means or process and the communication to the public of the + performances of the Work, including by public digital performance; to + broadcast and rebroadcast the Work by any means including signs, + sounds or images. + i. "Reproduce" means to make copies of the Work by any means including + without limitation by sound or visual recordings and the right of + fixation and reproducing fixations of the Work, including storage of a + protected performance or phonogram in digital form or other electronic + medium. - b. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License. +2. Fair Dealing Rights. Nothing in this License is intended to reduce, +limit, or restrict any uses free from copyright or rights arising from +limitations or exceptions that are provided for in connection with the +copyright protection under copyright law or other applicable laws. - c. "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership. +3. License Grant. Subject to the terms and conditions of this License, +Licensor hereby grants You a worldwide, royalty-free, non-exclusive, +perpetual (for the duration of the applicable copyright) license to +exercise the rights in the Work as stated below: - d. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. + a. to Reproduce the Work, to incorporate the Work into one or more + Collections, and to Reproduce the Work as incorporated in the + Collections; + b. to create and Reproduce Adaptations provided that any such Adaptation, + including any translation in any medium, takes reasonable steps to + clearly label, demarcate or otherwise identify that changes were made + to the original Work. For example, a translation could be marked "The + original work was translated from English to Spanish," or a + modification could indicate "The original work has been modified."; + c. to Distribute and Publicly Perform the Work including as incorporated + in Collections; and, + d. to Distribute and Publicly Perform Adaptations. - e. "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. +The above rights may be exercised in all media and formats whether now +known or hereafter devised. The above rights include the right to make +such modifications as are technically necessary to exercise the rights in +other media and formats. Subject to Section 8(f), all rights not expressly +granted by Licensor are hereby reserved, including but not limited to the +rights set forth in Section 4(d). - f. "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. +4. Restrictions. The license granted in Section 3 above is expressly made +subject to and limited by the following restrictions: - g. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. + a. You may Distribute or Publicly Perform the Work only under the terms + of this License. You must include a copy of, or the Uniform Resource + Identifier (URI) for, this License with every copy of the Work You + Distribute or Publicly Perform. You may not offer or impose any terms + on the Work that restrict the terms of this License or the ability of + the recipient of the Work to exercise the rights granted to that + recipient under the terms of the License. You may not sublicense the + Work. You must keep intact all notices that refer to this License and + to the disclaimer of warranties with every copy of the Work You + Distribute or Publicly Perform. When You Distribute or Publicly + Perform the Work, You may not impose any effective technological + measures on the Work that restrict the ability of a recipient of the + Work from You to exercise the rights granted to that recipient under + the terms of the License. This Section 4(a) applies to the Work as + incorporated in a Collection, but this does not require the Collection + apart from the Work itself to be made subject to the terms of this + License. If You create a Collection, upon notice from any Licensor You + must, to the extent practicable, remove from the Collection any credit + as required by Section 4(c), as requested. If You create an + Adaptation, upon notice from any Licensor You must, to the extent + practicable, remove from the Adaptation any credit as required by + Section 4(c), as requested. + b. You may not exercise any of the rights granted to You in Section 3 + above in any manner that is primarily intended for or directed toward + commercial advantage or private monetary compensation. The exchange of + the Work for other copyrighted works by means of digital file-sharing + or otherwise shall not be considered to be intended for or directed + toward commercial advantage or private monetary compensation, provided + there is no payment of any monetary compensation in connection with + the exchange of copyrighted works. + c. If You Distribute, or Publicly Perform the Work or any Adaptations or + Collections, You must, unless a request has been made pursuant to + Section 4(a), keep intact all copyright notices for the Work and + provide, reasonable to the medium or means You are utilizing: (i) the + name of the Original Author (or pseudonym, if applicable) if supplied, + and/or if the Original Author and/or Licensor designate another party + or parties (e.g., a sponsor institute, publishing entity, journal) for + attribution ("Attribution Parties") in Licensor's copyright notice, + terms of service or by other reasonable means, the name of such party + or parties; (ii) the title of the Work if supplied; (iii) to the + extent reasonably practicable, the URI, if any, that Licensor + specifies to be associated with the Work, unless such URI does not + refer to the copyright notice or licensing information for the Work; + and, (iv) consistent with Section 3(b), in the case of an Adaptation, + a credit identifying the use of the Work in the Adaptation (e.g., + "French translation of the Work by Original Author," or "Screenplay + based on original Work by Original Author"). The credit required by + this Section 4(c) may be implemented in any reasonable manner; + provided, however, that in the case of a Adaptation or Collection, at + a minimum such credit will appear, if a credit for all contributing + authors of the Adaptation or Collection appears, then as part of these + credits and in a manner at least as prominent as the credits for the + other contributing authors. For the avoidance of doubt, You may only + use the credit required by this Section for the purpose of attribution + in the manner set out above and, by exercising Your rights under this + License, You may not implicitly or explicitly assert or imply any + connection with, sponsorship or endorsement by the Original Author, + Licensor and/or Attribution Parties, as appropriate, of You or Your + use of the Work, without the separate, express prior written + permission of the Original Author, Licensor and/or Attribution + Parties. + d. For the avoidance of doubt: - h. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. - - i. "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. - -2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. - -3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: - - a. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; - - b. to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified."; - - c. to Distribute and Publicly Perform the Work including as incorporated in Collections; and, - - d. to Distribute and Publicly Perform Adaptations. - -The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved, including but not limited to the rights set forth in Section 4(d). - -4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: - - a. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(c), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(c), as requested. - - b. You may not exercise any of the rights granted to You in Section 3 above in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation. The exchange of the Work for other copyrighted works by means of digital file-sharing or otherwise shall not be considered to be intended for or directed toward commercial advantage or private monetary compensation, provided there is no payment of any monetary compensation in connection with the exchange of copyrighted works. - - c. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and, (iv) consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4(c) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. - - d. For the avoidance of doubt: - - i. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; - - ii. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License if Your exercise of such rights is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(b) and otherwise waives the right to collect royalties through any statutory or compulsory licensing scheme; and, - - iii. Voluntary License Schemes. The Licensor reserves the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License that is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(c). - - e. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise. + i. Non-waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme cannot be waived, the Licensor + reserves the exclusive right to collect such royalties for any + exercise by You of the rights granted under this License; + ii. Waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme can be waived, the Licensor reserves + the exclusive right to collect such royalties for any exercise by + You of the rights granted under this License if Your exercise of + such rights is for a purpose or use which is otherwise than + noncommercial as permitted under Section 4(b) and otherwise waives + the right to collect royalties through any statutory or compulsory + licensing scheme; and, + iii. Voluntary License Schemes. The Licensor reserves the right to + collect royalties, whether individually or, in the event that the + Licensor is a member of a collecting society that administers + voluntary licensing schemes, via that society, from any exercise + by You of the rights granted under this License that is for a + purpose or use which is otherwise than noncommercial as permitted + under Section 4(c). + e. Except as otherwise agreed in writing by the Licensor or as may be + otherwise permitted by applicable law, if You Reproduce, Distribute or + Publicly Perform the Work either by itself or as part of any + Adaptations or Collections, You must not distort, mutilate, modify or + take other derogatory action in relation to the Work which would be + prejudicial to the Original Author's honor or reputation. Licensor + agrees that in those jurisdictions (e.g. Japan), in which any exercise + of the right granted in Section 3(b) of this License (the right to + make Adaptations) would be deemed to be a distortion, mutilation, + modification or other derogatory action prejudicial to the Original + Author's honor and reputation, the Licensor will waive or not assert, + as appropriate, this Section, to the fullest extent permitted by the + applicable national law, to enable You to reasonably exercise Your + right under Section 3(b) of this License (right to make Adaptations) + but not otherwise. 5. Representations, Warranties and Disclaimer -UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR +OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY +KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, +INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, +FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF +LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, +WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION +OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. -6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE +LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR +ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES +ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. Termination - a. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. - - b. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. + a. This License and the rights granted hereunder will terminate + automatically upon any breach by You of the terms of this License. + Individuals or entities who have received Adaptations or Collections + from You under this License, however, will not have their licenses + terminated provided such individuals or entities remain in full + compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will + survive any termination of this License. + b. Subject to the above terms and conditions, the license granted here is + perpetual (for the duration of the applicable copyright in the Work). + Notwithstanding the above, Licensor reserves the right to release the + Work under different license terms or to stop distributing the Work at + any time; provided, however that any such election will not serve to + withdraw this License (or any other license that has been, or is + required to be, granted under the terms of this License), and this + License will continue in full force and effect unless terminated as + stated above. 8. Miscellaneous - a. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. + a. Each time You Distribute or Publicly Perform the Work or a Collection, + the Licensor offers to the recipient a license to the Work on the same + terms and conditions as the license granted to You under this License. + b. Each time You Distribute or Publicly Perform an Adaptation, Licensor + offers to the recipient a license to the original Work on the same + terms and conditions as the license granted to You under this License. + c. If any provision of this License is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this License, and without further action + by the parties to this agreement, such provision shall be reformed to + the minimum extent necessary to make such provision valid and + enforceable. + d. No term or provision of this License shall be deemed waived and no + breach consented to unless such waiver or consent shall be in writing + and signed by the party to be charged with such waiver or consent. + e. This License constitutes the entire agreement between the parties with + respect to the Work licensed here. There are no understandings, + agreements or representations with respect to the Work not specified + here. Licensor shall not be bound by any additional provisions that + may appear in any communication from You. This License may not be + modified without the mutual written agreement of the Licensor and You. + f. The rights granted under, and the subject matter referenced, in this + License were drafted utilizing the terminology of the Berne Convention + for the Protection of Literary and Artistic Works (as amended on + September 28, 1979), the Rome Convention of 1961, the WIPO Copyright + Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 + and the Universal Copyright Convention (as revised on July 24, 1971). + These rights and subject matter take effect in the relevant + jurisdiction in which the License terms are sought to be enforced + according to the corresponding provisions of the implementation of + those treaty provisions in the applicable national law. If the + standard suite of rights granted under applicable copyright law + includes additional rights not granted under this License, such + additional rights are deemed to be included in the License; this + License is not intended to restrict the license of any rights under + applicable law. - b. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. - - c. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - - d. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. - - e. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. - - f. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. Creative Commons Notice -Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor. + Creative Commons is not a party to this License, and makes no warranty + whatsoever in connection with the Work. Creative Commons will not be + liable to You or any party on any legal theory for any damages + whatsoever, including without limitation any general, special, + incidental or consequential damages arising in connection to this + license. Notwithstanding the foregoing two (2) sentences, if Creative + Commons has expressly identified itself as the Licensor hereunder, it + shall have all rights and obligations of Licensor. -Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of the License. + Except for the limited purpose of indicating to the public that the + Work is licensed under the CCPL, Creative Commons does not authorize + the use by either party of the trademark "Creative Commons" or any + related trademark or logo of Creative Commons without the prior + written consent of Creative Commons. Any permitted use will be in + compliance with Creative Commons' then-current trademark usage + guidelines, as may be published on its website or otherwise made + available upon request from time to time. For the avoidance of doubt, + this trademark restriction does not form part of the License. -Creative Commons may be contacted at http://creativecommons.org/. + Creative Commons may be contacted at https://creativecommons.org/. diff --git a/options/license/CC-BY-NC-ND-3.0 b/options/license/CC-BY-NC-ND-3.0 index 9c30983594..30b08e74db 100644 --- a/options/license/CC-BY-NC-ND-3.0 +++ b/options/license/CC-BY-NC-ND-3.0 @@ -1,89 +1,308 @@ -Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported +Creative Commons Legal Code - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. +Attribution-NonCommercial-NoDerivs 3.0 Unported + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR + DAMAGES RESULTING FROM ITS USE. License -THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE +COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY +COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS +AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. -BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE +TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY +BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS +CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND +CONDITIONS. 1. Definitions - a. "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. + a. "Adaptation" means a work based upon the Work, or upon the Work and + other pre-existing works, such as a translation, adaptation, + derivative work, arrangement of music or other alterations of a + literary or artistic work, or phonogram or performance and includes + cinematographic adaptations or any other form in which the Work may be + recast, transformed, or adapted including in any form recognizably + derived from the original, except that a work that constitutes a + Collection will not be considered an Adaptation for the purpose of + this License. For the avoidance of doubt, where the Work is a musical + work, performance or phonogram, the synchronization of the Work in + timed-relation with a moving image ("synching") will be considered an + Adaptation for the purpose of this License. + b. "Collection" means a collection of literary or artistic works, such as + encyclopedias and anthologies, or performances, phonograms or + broadcasts, or other works or subject matter other than works listed + in Section 1(f) below, which, by reason of the selection and + arrangement of their contents, constitute intellectual creations, in + which the Work is included in its entirety in unmodified form along + with one or more other contributions, each constituting separate and + independent works in themselves, which together are assembled into a + collective whole. A work that constitutes a Collection will not be + considered an Adaptation (as defined above) for the purposes of this + License. + c. "Distribute" means to make available to the public the original and + copies of the Work through sale or other transfer of ownership. + d. "Licensor" means the individual, individuals, entity or entities that + offer(s) the Work under the terms of this License. + e. "Original Author" means, in the case of a literary or artistic work, + the individual, individuals, entity or entities who created the Work + or if no individual or entity can be identified, the publisher; and in + addition (i) in the case of a performance the actors, singers, + musicians, dancers, and other persons who act, sing, deliver, declaim, + play in, interpret or otherwise perform literary or artistic works or + expressions of folklore; (ii) in the case of a phonogram the producer + being the person or legal entity who first fixes the sounds of a + performance or other sounds; and, (iii) in the case of broadcasts, the + organization that transmits the broadcast. + f. "Work" means the literary and/or artistic work offered under the terms + of this License including without limitation any production in the + literary, scientific and artistic domain, whatever may be the mode or + form of its expression including digital form, such as a book, + pamphlet and other writing; a lecture, address, sermon or other work + of the same nature; a dramatic or dramatico-musical work; a + choreographic work or entertainment in dumb show; a musical + composition with or without words; a cinematographic work to which are + assimilated works expressed by a process analogous to cinematography; + a work of drawing, painting, architecture, sculpture, engraving or + lithography; a photographic work to which are assimilated works + expressed by a process analogous to photography; a work of applied + art; an illustration, map, plan, sketch or three-dimensional work + relative to geography, topography, architecture or science; a + performance; a broadcast; a phonogram; a compilation of data to the + extent it is protected as a copyrightable work; or a work performed by + a variety or circus performer to the extent it is not otherwise + considered a literary or artistic work. + g. "You" means an individual or entity exercising rights under this + License who has not previously violated the terms of this License with + respect to the Work, or who has received express permission from the + Licensor to exercise rights under this License despite a previous + violation. + h. "Publicly Perform" means to perform public recitations of the Work and + to communicate to the public those public recitations, by any means or + process, including by wire or wireless means or public digital + performances; to make available to the public Works in such a way that + members of the public may access these Works from a place and at a + place individually chosen by them; to perform the Work to the public + by any means or process and the communication to the public of the + performances of the Work, including by public digital performance; to + broadcast and rebroadcast the Work by any means including signs, + sounds or images. + i. "Reproduce" means to make copies of the Work by any means including + without limitation by sound or visual recordings and the right of + fixation and reproducing fixations of the Work, including storage of a + protected performance or phonogram in digital form or other electronic + medium. - b. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License. +2. Fair Dealing Rights. Nothing in this License is intended to reduce, +limit, or restrict any uses free from copyright or rights arising from +limitations or exceptions that are provided for in connection with the +copyright protection under copyright law or other applicable laws. - c. "Distribute" means to make available to the public the original and copies of the Work through sale or other transfer of ownership. +3. License Grant. Subject to the terms and conditions of this License, +Licensor hereby grants You a worldwide, royalty-free, non-exclusive, +perpetual (for the duration of the applicable copyright) license to +exercise the rights in the Work as stated below: - d. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. + a. to Reproduce the Work, to incorporate the Work into one or more + Collections, and to Reproduce the Work as incorporated in the + Collections; and, + b. to Distribute and Publicly Perform the Work including as incorporated + in Collections. - e. "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. +The above rights may be exercised in all media and formats whether now +known or hereafter devised. The above rights include the right to make +such modifications as are technically necessary to exercise the rights in +other media and formats, but otherwise you have no rights to make +Adaptations. Subject to 8(f), all rights not expressly granted by Licensor +are hereby reserved, including but not limited to the rights set forth in +Section 4(d). - f. "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. +4. Restrictions. The license granted in Section 3 above is expressly made +subject to and limited by the following restrictions: - g. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. + a. You may Distribute or Publicly Perform the Work only under the terms + of this License. You must include a copy of, or the Uniform Resource + Identifier (URI) for, this License with every copy of the Work You + Distribute or Publicly Perform. You may not offer or impose any terms + on the Work that restrict the terms of this License or the ability of + the recipient of the Work to exercise the rights granted to that + recipient under the terms of the License. You may not sublicense the + Work. You must keep intact all notices that refer to this License and + to the disclaimer of warranties with every copy of the Work You + Distribute or Publicly Perform. When You Distribute or Publicly + Perform the Work, You may not impose any effective technological + measures on the Work that restrict the ability of a recipient of the + Work from You to exercise the rights granted to that recipient under + the terms of the License. This Section 4(a) applies to the Work as + incorporated in a Collection, but this does not require the Collection + apart from the Work itself to be made subject to the terms of this + License. If You create a Collection, upon notice from any Licensor You + must, to the extent practicable, remove from the Collection any credit + as required by Section 4(c), as requested. + b. You may not exercise any of the rights granted to You in Section 3 + above in any manner that is primarily intended for or directed toward + commercial advantage or private monetary compensation. The exchange of + the Work for other copyrighted works by means of digital file-sharing + or otherwise shall not be considered to be intended for or directed + toward commercial advantage or private monetary compensation, provided + there is no payment of any monetary compensation in connection with + the exchange of copyrighted works. + c. If You Distribute, or Publicly Perform the Work or Collections, You + must, unless a request has been made pursuant to Section 4(a), keep + intact all copyright notices for the Work and provide, reasonable to + the medium or means You are utilizing: (i) the name of the Original + Author (or pseudonym, if applicable) if supplied, and/or if the + Original Author and/or Licensor designate another party or parties + (e.g., a sponsor institute, publishing entity, journal) for + attribution ("Attribution Parties") in Licensor's copyright notice, + terms of service or by other reasonable means, the name of such party + or parties; (ii) the title of the Work if supplied; (iii) to the + extent reasonably practicable, the URI, if any, that Licensor + specifies to be associated with the Work, unless such URI does not + refer to the copyright notice or licensing information for the Work. + The credit required by this Section 4(c) may be implemented in any + reasonable manner; provided, however, that in the case of a + Collection, at a minimum such credit will appear, if a credit for all + contributing authors of Collection appears, then as part of these + credits and in a manner at least as prominent as the credits for the + other contributing authors. For the avoidance of doubt, You may only + use the credit required by this Section for the purpose of attribution + in the manner set out above and, by exercising Your rights under this + License, You may not implicitly or explicitly assert or imply any + connection with, sponsorship or endorsement by the Original Author, + Licensor and/or Attribution Parties, as appropriate, of You or Your + use of the Work, without the separate, express prior written + permission of the Original Author, Licensor and/or Attribution + Parties. + d. For the avoidance of doubt: - h. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. - - i. "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. - -2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. - -3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: - - a. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; and, - - b. to Distribute and Publicly Perform the Work including as incorporated in Collections. - -The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats, but otherwise you have no rights to make Adaptations. Subject to 8(f), all rights not expressly granted by Licensor are hereby reserved, including but not limited to the rights set forth in Section 4(d). - -4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: - - a. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(c), as requested. - - b. You may not exercise any of the rights granted to You in Section 3 above in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation. The exchange of the Work for other copyrighted works by means of digital file-sharing or otherwise shall not be considered to be intended for or directed toward commercial advantage or private monetary compensation, provided there is no payment of any monetary compensation in connection with the exchange of copyrighted works. - - c. If You Distribute, or Publicly Perform the Work or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work. The credit required by this Section 4(c) may be implemented in any reasonable manner; provided, however, that in the case of a Collection, at a minimum such credit will appear, if a credit for all contributing authors of Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. - - d. For the avoidance of doubt: - - i. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; - - ii. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License if Your exercise of such rights is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(b) and otherwise waives the right to collect royalties through any statutory or compulsory licensing scheme; and, - - iii. Voluntary License Schemes. The Licensor reserves the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License that is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(b). - - e. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. + i. Non-waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme cannot be waived, the Licensor + reserves the exclusive right to collect such royalties for any + exercise by You of the rights granted under this License; + ii. Waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme can be waived, the Licensor reserves + the exclusive right to collect such royalties for any exercise by + You of the rights granted under this License if Your exercise of + such rights is for a purpose or use which is otherwise than + noncommercial as permitted under Section 4(b) and otherwise waives + the right to collect royalties through any statutory or compulsory + licensing scheme; and, + iii. Voluntary License Schemes. The Licensor reserves the right to + collect royalties, whether individually or, in the event that the + Licensor is a member of a collecting society that administers + voluntary licensing schemes, via that society, from any exercise + by You of the rights granted under this License that is for a + purpose or use which is otherwise than noncommercial as permitted + under Section 4(b). + e. Except as otherwise agreed in writing by the Licensor or as may be + otherwise permitted by applicable law, if You Reproduce, Distribute or + Publicly Perform the Work either by itself or as part of any + Collections, You must not distort, mutilate, modify or take other + derogatory action in relation to the Work which would be prejudicial + to the Original Author's honor or reputation. 5. Representations, Warranties and Disclaimer -UNLESS OTHERWISE MUTUALLY AGREED BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. +UNLESS OTHERWISE MUTUALLY AGREED BY THE PARTIES IN WRITING, LICENSOR +OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY +KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, +INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, +FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF +LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, +WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION +OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. -6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE +LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR +ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES +ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. Termination - a. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. - - b. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. + a. This License and the rights granted hereunder will terminate + automatically upon any breach by You of the terms of this License. + Individuals or entities who have received Collections from You under + this License, however, will not have their licenses terminated + provided such individuals or entities remain in full compliance with + those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any + termination of this License. + b. Subject to the above terms and conditions, the license granted here is + perpetual (for the duration of the applicable copyright in the Work). + Notwithstanding the above, Licensor reserves the right to release the + Work under different license terms or to stop distributing the Work at + any time; provided, however that any such election will not serve to + withdraw this License (or any other license that has been, or is + required to be, granted under the terms of this License), and this + License will continue in full force and effect unless terminated as + stated above. 8. Miscellaneous - a. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. + a. Each time You Distribute or Publicly Perform the Work or a Collection, + the Licensor offers to the recipient a license to the Work on the same + terms and conditions as the license granted to You under this License. + b. If any provision of this License is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this License, and without further action + by the parties to this agreement, such provision shall be reformed to + the minimum extent necessary to make such provision valid and + enforceable. + c. No term or provision of this License shall be deemed waived and no + breach consented to unless such waiver or consent shall be in writing + and signed by the party to be charged with such waiver or consent. + d. This License constitutes the entire agreement between the parties with + respect to the Work licensed here. There are no understandings, + agreements or representations with respect to the Work not specified + here. Licensor shall not be bound by any additional provisions that + may appear in any communication from You. This License may not be + modified without the mutual written agreement of the Licensor and You. + e. The rights granted under, and the subject matter referenced, in this + License were drafted utilizing the terminology of the Berne Convention + for the Protection of Literary and Artistic Works (as amended on + September 28, 1979), the Rome Convention of 1961, the WIPO Copyright + Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 + and the Universal Copyright Convention (as revised on July 24, 1971). + These rights and subject matter take effect in the relevant + jurisdiction in which the License terms are sought to be enforced + according to the corresponding provisions of the implementation of + those treaty provisions in the applicable national law. If the + standard suite of rights granted under applicable copyright law + includes additional rights not granted under this License, such + additional rights are deemed to be included in the License; this + License is not intended to restrict the license of any rights under + applicable law. - b. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - - c. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. - - d. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. - - e. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. Creative Commons Notice -Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor. + Creative Commons is not a party to this License, and makes no warranty + whatsoever in connection with the Work. Creative Commons will not be + liable to You or any party on any legal theory for any damages + whatsoever, including without limitation any general, special, + incidental or consequential damages arising in connection to this + license. Notwithstanding the foregoing two (2) sentences, if Creative + Commons has expressly identified itself as the Licensor hereunder, it + shall have all rights and obligations of Licensor. -Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of this License. + Except for the limited purpose of indicating to the public that the + Work is licensed under the CCPL, Creative Commons does not authorize + the use by either party of the trademark "Creative Commons" or any + related trademark or logo of Creative Commons without the prior + written consent of Creative Commons. Any permitted use will be in + compliance with Creative Commons' then-current trademark usage + guidelines, as may be published on its website or otherwise made + available upon request from time to time. For the avoidance of doubt, + this trademark restriction does not form part of this License. -Creative Commons may be contacted at http://creativecommons.org/. + Creative Commons may be contacted at https://creativecommons.org/. diff --git a/options/license/CC-BY-NC-SA-3.0 b/options/license/CC-BY-NC-SA-3.0 index 8d1828791a..a50eacf98c 100644 --- a/options/license/CC-BY-NC-SA-3.0 +++ b/options/license/CC-BY-NC-SA-3.0 @@ -1,99 +1,360 @@ -Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported +Creative Commons Legal Code - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. +Attribution-NonCommercial-ShareAlike 3.0 Unported + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR + DAMAGES RESULTING FROM ITS USE. License -THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE +COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY +COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS +AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. -BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE +TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY +BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS +CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND +CONDITIONS. 1. Definitions - a. "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. + a. "Adaptation" means a work based upon the Work, or upon the Work and + other pre-existing works, such as a translation, adaptation, + derivative work, arrangement of music or other alterations of a + literary or artistic work, or phonogram or performance and includes + cinematographic adaptations or any other form in which the Work may be + recast, transformed, or adapted including in any form recognizably + derived from the original, except that a work that constitutes a + Collection will not be considered an Adaptation for the purpose of + this License. For the avoidance of doubt, where the Work is a musical + work, performance or phonogram, the synchronization of the Work in + timed-relation with a moving image ("synching") will be considered an + Adaptation for the purpose of this License. + b. "Collection" means a collection of literary or artistic works, such as + encyclopedias and anthologies, or performances, phonograms or + broadcasts, or other works or subject matter other than works listed + in Section 1(g) below, which, by reason of the selection and + arrangement of their contents, constitute intellectual creations, in + which the Work is included in its entirety in unmodified form along + with one or more other contributions, each constituting separate and + independent works in themselves, which together are assembled into a + collective whole. A work that constitutes a Collection will not be + considered an Adaptation (as defined above) for the purposes of this + License. + c. "Distribute" means to make available to the public the original and + copies of the Work or Adaptation, as appropriate, through sale or + other transfer of ownership. + d. "License Elements" means the following high-level license attributes + as selected by Licensor and indicated in the title of this License: + Attribution, Noncommercial, ShareAlike. + e. "Licensor" means the individual, individuals, entity or entities that + offer(s) the Work under the terms of this License. + f. "Original Author" means, in the case of a literary or artistic work, + the individual, individuals, entity or entities who created the Work + or if no individual or entity can be identified, the publisher; and in + addition (i) in the case of a performance the actors, singers, + musicians, dancers, and other persons who act, sing, deliver, declaim, + play in, interpret or otherwise perform literary or artistic works or + expressions of folklore; (ii) in the case of a phonogram the producer + being the person or legal entity who first fixes the sounds of a + performance or other sounds; and, (iii) in the case of broadcasts, the + organization that transmits the broadcast. + g. "Work" means the literary and/or artistic work offered under the terms + of this License including without limitation any production in the + literary, scientific and artistic domain, whatever may be the mode or + form of its expression including digital form, such as a book, + pamphlet and other writing; a lecture, address, sermon or other work + of the same nature; a dramatic or dramatico-musical work; a + choreographic work or entertainment in dumb show; a musical + composition with or without words; a cinematographic work to which are + assimilated works expressed by a process analogous to cinematography; + a work of drawing, painting, architecture, sculpture, engraving or + lithography; a photographic work to which are assimilated works + expressed by a process analogous to photography; a work of applied + art; an illustration, map, plan, sketch or three-dimensional work + relative to geography, topography, architecture or science; a + performance; a broadcast; a phonogram; a compilation of data to the + extent it is protected as a copyrightable work; or a work performed by + a variety or circus performer to the extent it is not otherwise + considered a literary or artistic work. + h. "You" means an individual or entity exercising rights under this + License who has not previously violated the terms of this License with + respect to the Work, or who has received express permission from the + Licensor to exercise rights under this License despite a previous + violation. + i. "Publicly Perform" means to perform public recitations of the Work and + to communicate to the public those public recitations, by any means or + process, including by wire or wireless means or public digital + performances; to make available to the public Works in such a way that + members of the public may access these Works from a place and at a + place individually chosen by them; to perform the Work to the public + by any means or process and the communication to the public of the + performances of the Work, including by public digital performance; to + broadcast and rebroadcast the Work by any means including signs, + sounds or images. + j. "Reproduce" means to make copies of the Work by any means including + without limitation by sound or visual recordings and the right of + fixation and reproducing fixations of the Work, including storage of a + protected performance or phonogram in digital form or other electronic + medium. - b. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(g) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License. +2. Fair Dealing Rights. Nothing in this License is intended to reduce, +limit, or restrict any uses free from copyright or rights arising from +limitations or exceptions that are provided for in connection with the +copyright protection under copyright law or other applicable laws. - c. "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership. +3. License Grant. Subject to the terms and conditions of this License, +Licensor hereby grants You a worldwide, royalty-free, non-exclusive, +perpetual (for the duration of the applicable copyright) license to +exercise the rights in the Work as stated below: - d. "License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, Noncommercial, ShareAlike. + a. to Reproduce the Work, to incorporate the Work into one or more + Collections, and to Reproduce the Work as incorporated in the + Collections; + b. to create and Reproduce Adaptations provided that any such Adaptation, + including any translation in any medium, takes reasonable steps to + clearly label, demarcate or otherwise identify that changes were made + to the original Work. For example, a translation could be marked "The + original work was translated from English to Spanish," or a + modification could indicate "The original work has been modified."; + c. to Distribute and Publicly Perform the Work including as incorporated + in Collections; and, + d. to Distribute and Publicly Perform Adaptations. - e. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. +The above rights may be exercised in all media and formats whether now +known or hereafter devised. The above rights include the right to make +such modifications as are technically necessary to exercise the rights in +other media and formats. Subject to Section 8(f), all rights not expressly +granted by Licensor are hereby reserved, including but not limited to the +rights described in Section 4(e). - f. "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. +4. Restrictions. The license granted in Section 3 above is expressly made +subject to and limited by the following restrictions: - g. "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. + a. You may Distribute or Publicly Perform the Work only under the terms + of this License. You must include a copy of, or the Uniform Resource + Identifier (URI) for, this License with every copy of the Work You + Distribute or Publicly Perform. You may not offer or impose any terms + on the Work that restrict the terms of this License or the ability of + the recipient of the Work to exercise the rights granted to that + recipient under the terms of the License. You may not sublicense the + Work. You must keep intact all notices that refer to this License and + to the disclaimer of warranties with every copy of the Work You + Distribute or Publicly Perform. When You Distribute or Publicly + Perform the Work, You may not impose any effective technological + measures on the Work that restrict the ability of a recipient of the + Work from You to exercise the rights granted to that recipient under + the terms of the License. This Section 4(a) applies to the Work as + incorporated in a Collection, but this does not require the Collection + apart from the Work itself to be made subject to the terms of this + License. If You create a Collection, upon notice from any Licensor You + must, to the extent practicable, remove from the Collection any credit + as required by Section 4(d), as requested. If You create an + Adaptation, upon notice from any Licensor You must, to the extent + practicable, remove from the Adaptation any credit as required by + Section 4(d), as requested. + b. You may Distribute or Publicly Perform an Adaptation only under: (i) + the terms of this License; (ii) a later version of this License with + the same License Elements as this License; (iii) a Creative Commons + jurisdiction license (either this or a later license version) that + contains the same License Elements as this License (e.g., + Attribution-NonCommercial-ShareAlike 3.0 US) ("Applicable License"). + You must include a copy of, or the URI, for Applicable License with + every copy of each Adaptation You Distribute or Publicly Perform. You + may not offer or impose any terms on the Adaptation that restrict the + terms of the Applicable License or the ability of the recipient of the + Adaptation to exercise the rights granted to that recipient under the + terms of the Applicable License. You must keep intact all notices that + refer to the Applicable License and to the disclaimer of warranties + with every copy of the Work as included in the Adaptation You + Distribute or Publicly Perform. When You Distribute or Publicly + Perform the Adaptation, You may not impose any effective technological + measures on the Adaptation that restrict the ability of a recipient of + the Adaptation from You to exercise the rights granted to that + recipient under the terms of the Applicable License. This Section 4(b) + applies to the Adaptation as incorporated in a Collection, but this + does not require the Collection apart from the Adaptation itself to be + made subject to the terms of the Applicable License. + c. You may not exercise any of the rights granted to You in Section 3 + above in any manner that is primarily intended for or directed toward + commercial advantage or private monetary compensation. The exchange of + the Work for other copyrighted works by means of digital file-sharing + or otherwise shall not be considered to be intended for or directed + toward commercial advantage or private monetary compensation, provided + there is no payment of any monetary compensation in con-nection with + the exchange of copyrighted works. + d. If You Distribute, or Publicly Perform the Work or any Adaptations or + Collections, You must, unless a request has been made pursuant to + Section 4(a), keep intact all copyright notices for the Work and + provide, reasonable to the medium or means You are utilizing: (i) the + name of the Original Author (or pseudonym, if applicable) if supplied, + and/or if the Original Author and/or Licensor designate another party + or parties (e.g., a sponsor institute, publishing entity, journal) for + attribution ("Attribution Parties") in Licensor's copyright notice, + terms of service or by other reasonable means, the name of such party + or parties; (ii) the title of the Work if supplied; (iii) to the + extent reasonably practicable, the URI, if any, that Licensor + specifies to be associated with the Work, unless such URI does not + refer to the copyright notice or licensing information for the Work; + and, (iv) consistent with Section 3(b), in the case of an Adaptation, + a credit identifying the use of the Work in the Adaptation (e.g., + "French translation of the Work by Original Author," or "Screenplay + based on original Work by Original Author"). The credit required by + this Section 4(d) may be implemented in any reasonable manner; + provided, however, that in the case of a Adaptation or Collection, at + a minimum such credit will appear, if a credit for all contributing + authors of the Adaptation or Collection appears, then as part of these + credits and in a manner at least as prominent as the credits for the + other contributing authors. For the avoidance of doubt, You may only + use the credit required by this Section for the purpose of attribution + in the manner set out above and, by exercising Your rights under this + License, You may not implicitly or explicitly assert or imply any + connection with, sponsorship or endorsement by the Original Author, + Licensor and/or Attribution Parties, as appropriate, of You or Your + use of the Work, without the separate, express prior written + permission of the Original Author, Licensor and/or Attribution + Parties. + e. For the avoidance of doubt: - h. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. - - i. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. - - j. "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. - -2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. - -3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: - - a. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; - - b. to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified."; - - c. to Distribute and Publicly Perform the Work including as incorporated in Collections; and, - - d. to Distribute and Publicly Perform Adaptations. - -The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved, including but not limited to the rights described in Section 4(e). - -4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: - - a. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(d), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(d), as requested. - - b. You may Distribute or Publicly Perform an Adaptation only under: (i) the terms of this License; (ii) a later version of this License with the same License Elements as this License; (iii) a Creative Commons jurisdiction license (either this or a later license version) that contains the same License Elements as this License (e.g., Attribution-NonCommercial-ShareAlike 3.0 US) ("Applicable License"). You must include a copy of, or the URI, for Applicable License with every copy of each Adaptation You Distribute or Publicly Perform. You may not offer or impose any terms on the Adaptation that restrict the terms of the Applicable License or the ability of the recipient of the Adaptation to exercise the rights granted to that recipient under the terms of the Applicable License. You must keep intact all notices that refer to the Applicable License and to the disclaimer of warranties with every copy of the Work as included in the Adaptation You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Adaptation, You may not impose any effective technological measures on the Adaptation that restrict the ability of a recipient of the Adaptation from You to exercise the rights granted to that recipient under the terms of the Applicable License. This Section 4(b) applies to the Adaptation as incorporated in a Collection, but this does not require the Collection apart from the Adaptation itself to be made subject to the terms of the Applicable License. - - c. You may not exercise any of the rights granted to You in Section 3 above in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation. The exchange of the Work for other copyrighted works by means of digital file-sharing or otherwise shall not be considered to be intended for or directed toward commercial advantage or private monetary compensation, provided there is no payment of any monetary compensation in con-nection with the exchange of copyrighted works. - - d. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and, (iv) consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4(d) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. - - e. For the avoidance of doubt: - - i. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; - - ii. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License if Your exercise of such rights is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(c) and otherwise waives the right to collect royalties through any statutory or compulsory licensing scheme; and, - - iii. Voluntary License Schemes. The Licensor reserves the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License that is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(c). - - f. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise. + i. Non-waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme cannot be waived, the Licensor + reserves the exclusive right to collect such royalties for any + exercise by You of the rights granted under this License; + ii. Waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme can be waived, the Licensor reserves + the exclusive right to collect such royalties for any exercise by + You of the rights granted under this License if Your exercise of + such rights is for a purpose or use which is otherwise than + noncommercial as permitted under Section 4(c) and otherwise waives + the right to collect royalties through any statutory or compulsory + licensing scheme; and, + iii. Voluntary License Schemes. The Licensor reserves the right to + collect royalties, whether individually or, in the event that the + Licensor is a member of a collecting society that administers + voluntary licensing schemes, via that society, from any exercise + by You of the rights granted under this License that is for a + purpose or use which is otherwise than noncommercial as permitted + under Section 4(c). + f. Except as otherwise agreed in writing by the Licensor or as may be + otherwise permitted by applicable law, if You Reproduce, Distribute or + Publicly Perform the Work either by itself or as part of any + Adaptations or Collections, You must not distort, mutilate, modify or + take other derogatory action in relation to the Work which would be + prejudicial to the Original Author's honor or reputation. Licensor + agrees that in those jurisdictions (e.g. Japan), in which any exercise + of the right granted in Section 3(b) of this License (the right to + make Adaptations) would be deemed to be a distortion, mutilation, + modification or other derogatory action prejudicial to the Original + Author's honor and reputation, the Licensor will waive or not assert, + as appropriate, this Section, to the fullest extent permitted by the + applicable national law, to enable You to reasonably exercise Your + right under Section 3(b) of this License (right to make Adaptations) + but not otherwise. 5. Representations, Warranties and Disclaimer -UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING AND TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO THIS EXCLUSION MAY NOT APPLY TO YOU. +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING AND TO THE +FULLEST EXTENT PERMITTED BY APPLICABLE LAW, LICENSOR OFFERS THE WORK AS-IS +AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE +WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT +LIMITATION, WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, +ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT +DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED +WARRANTIES, SO THIS EXCLUSION MAY NOT APPLY TO YOU. -6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE +LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR +ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES +ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. Termination - a. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. - - b. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. + a. This License and the rights granted hereunder will terminate + automatically upon any breach by You of the terms of this License. + Individuals or entities who have received Adaptations or Collections + from You under this License, however, will not have their licenses + terminated provided such individuals or entities remain in full + compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will + survive any termination of this License. + b. Subject to the above terms and conditions, the license granted here is + perpetual (for the duration of the applicable copyright in the Work). + Notwithstanding the above, Licensor reserves the right to release the + Work under different license terms or to stop distributing the Work at + any time; provided, however that any such election will not serve to + withdraw this License (or any other license that has been, or is + required to be, granted under the terms of this License), and this + License will continue in full force and effect unless terminated as + stated above. 8. Miscellaneous - a. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. + a. Each time You Distribute or Publicly Perform the Work or a Collection, + the Licensor offers to the recipient a license to the Work on the same + terms and conditions as the license granted to You under this License. + b. Each time You Distribute or Publicly Perform an Adaptation, Licensor + offers to the recipient a license to the original Work on the same + terms and conditions as the license granted to You under this License. + c. If any provision of this License is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this License, and without further action + by the parties to this agreement, such provision shall be reformed to + the minimum extent necessary to make such provision valid and + enforceable. + d. No term or provision of this License shall be deemed waived and no + breach consented to unless such waiver or consent shall be in writing + and signed by the party to be charged with such waiver or consent. + e. This License constitutes the entire agreement between the parties with + respect to the Work licensed here. There are no understandings, + agreements or representations with respect to the Work not specified + here. Licensor shall not be bound by any additional provisions that + may appear in any communication from You. This License may not be + modified without the mutual written agreement of the Licensor and You. + f. The rights granted under, and the subject matter referenced, in this + License were drafted utilizing the terminology of the Berne Convention + for the Protection of Literary and Artistic Works (as amended on + September 28, 1979), the Rome Convention of 1961, the WIPO Copyright + Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 + and the Universal Copyright Convention (as revised on July 24, 1971). + These rights and subject matter take effect in the relevant + jurisdiction in which the License terms are sought to be enforced + according to the corresponding provisions of the implementation of + those treaty provisions in the applicable national law. If the + standard suite of rights granted under applicable copyright law + includes additional rights not granted under this License, such + additional rights are deemed to be included in the License; this + License is not intended to restrict the license of any rights under + applicable law. - b. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. - - c. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - - d. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. - - e. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. - - f. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. Creative Commons Notice -Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor. + Creative Commons is not a party to this License, and makes no warranty + whatsoever in connection with the Work. Creative Commons will not be + liable to You or any party on any legal theory for any damages + whatsoever, including without limitation any general, special, + incidental or consequential damages arising in connection to this + license. Notwithstanding the foregoing two (2) sentences, if Creative + Commons has expressly identified itself as the Licensor hereunder, it + shall have all rights and obligations of Licensor. -Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of this License. + Except for the limited purpose of indicating to the public that the + Work is licensed under the CCPL, Creative Commons does not authorize + the use by either party of the trademark "Creative Commons" or any + related trademark or logo of Creative Commons without the prior + written consent of Creative Commons. Any permitted use will be in + compliance with Creative Commons' then-current trademark usage + guidelines, as may be published on its website or otherwise made + available upon request from time to time. For the avoidance of doubt, + this trademark restriction does not form part of this License. -Creative Commons may be contacted at http://creativecommons.org/. + Creative Commons may be contacted at https://creativecommons.org/. diff --git a/options/license/CC-BY-ND-3.0 b/options/license/CC-BY-ND-3.0 index d9265b9f19..2ec9718946 100644 --- a/options/license/CC-BY-ND-3.0 +++ b/options/license/CC-BY-ND-3.0 @@ -1,87 +1,293 @@ -Creative Commons Attribution-NoDerivs 3.0 Unported +Creative Commons Legal Code - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. +Attribution-NoDerivs 3.0 Unported + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR + DAMAGES RESULTING FROM ITS USE. License -THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE +COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY +COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS +AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. -BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE +TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY +BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS +CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND +CONDITIONS. 1. Definitions - a. "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. + a. "Adaptation" means a work based upon the Work, or upon the Work and + other pre-existing works, such as a translation, adaptation, + derivative work, arrangement of music or other alterations of a + literary or artistic work, or phonogram or performance and includes + cinematographic adaptations or any other form in which the Work may be + recast, transformed, or adapted including in any form recognizably + derived from the original, except that a work that constitutes a + Collection will not be considered an Adaptation for the purpose of + this License. For the avoidance of doubt, where the Work is a musical + work, performance or phonogram, the synchronization of the Work in + timed-relation with a moving image ("synching") will be considered an + Adaptation for the purpose of this License. + b. "Collection" means a collection of literary or artistic works, such as + encyclopedias and anthologies, or performances, phonograms or + broadcasts, or other works or subject matter other than works listed + in Section 1(f) below, which, by reason of the selection and + arrangement of their contents, constitute intellectual creations, in + which the Work is included in its entirety in unmodified form along + with one or more other contributions, each constituting separate and + independent works in themselves, which together are assembled into a + collective whole. A work that constitutes a Collection will not be + considered an Adaptation (as defined above) for the purposes of this + License. + c. "Distribute" means to make available to the public the original and + copies of the Work through sale or other transfer of ownership. + d. "Licensor" means the individual, individuals, entity or entities that + offer(s) the Work under the terms of this License. + e. "Original Author" means, in the case of a literary or artistic work, + the individual, individuals, entity or entities who created the Work + or if no individual or entity can be identified, the publisher; and in + addition (i) in the case of a performance the actors, singers, + musicians, dancers, and other persons who act, sing, deliver, declaim, + play in, interpret or otherwise perform literary or artistic works or + expressions of folklore; (ii) in the case of a phonogram the producer + being the person or legal entity who first fixes the sounds of a + performance or other sounds; and, (iii) in the case of broadcasts, the + organization that transmits the broadcast. + f. "Work" means the literary and/or artistic work offered under the terms + of this License including without limitation any production in the + literary, scientific and artistic domain, whatever may be the mode or + form of its expression including digital form, such as a book, + pamphlet and other writing; a lecture, address, sermon or other work + of the same nature; a dramatic or dramatico-musical work; a + choreographic work or entertainment in dumb show; a musical + composition with or without words; a cinematographic work to which are + assimilated works expressed by a process analogous to cinematography; + a work of drawing, painting, architecture, sculpture, engraving or + lithography; a photographic work to which are assimilated works + expressed by a process analogous to photography; a work of applied + art; an illustration, map, plan, sketch or three-dimensional work + relative to geography, topography, architecture or science; a + performance; a broadcast; a phonogram; a compilation of data to the + extent it is protected as a copyrightable work; or a work performed by + a variety or circus performer to the extent it is not otherwise + considered a literary or artistic work. + g. "You" means an individual or entity exercising rights under this + License who has not previously violated the terms of this License with + respect to the Work, or who has received express permission from the + Licensor to exercise rights under this License despite a previous + violation. + h. "Publicly Perform" means to perform public recitations of the Work and + to communicate to the public those public recitations, by any means or + process, including by wire or wireless means or public digital + performances; to make available to the public Works in such a way that + members of the public may access these Works from a place and at a + place individually chosen by them; to perform the Work to the public + by any means or process and the communication to the public of the + performances of the Work, including by public digital performance; to + broadcast and rebroadcast the Work by any means including signs, + sounds or images. + i. "Reproduce" means to make copies of the Work by any means including + without limitation by sound or visual recordings and the right of + fixation and reproducing fixations of the Work, including storage of a + protected performance or phonogram in digital form or other electronic + medium. - b. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License. +2. Fair Dealing Rights. Nothing in this License is intended to reduce, +limit, or restrict any uses free from copyright or rights arising from +limitations or exceptions that are provided for in connection with the +copyright protection under copyright law or other applicable laws. - c. "Distribute" means to make available to the public the original and copies of the Work through sale or other transfer of ownership. +3. License Grant. Subject to the terms and conditions of this License, +Licensor hereby grants You a worldwide, royalty-free, non-exclusive, +perpetual (for the duration of the applicable copyright) license to +exercise the rights in the Work as stated below: - d. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. + a. to Reproduce the Work, to incorporate the Work into one or more + Collections, and to Reproduce the Work as incorporated in the + Collections; and, + b. to Distribute and Publicly Perform the Work including as incorporated + in Collections. + c. For the avoidance of doubt: - e. "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. + i. Non-waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme cannot be waived, the Licensor + reserves the exclusive right to collect such royalties for any + exercise by You of the rights granted under this License; + ii. Waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme can be waived, the Licensor waives the + exclusive right to collect such royalties for any exercise by You + of the rights granted under this License; and, + iii. Voluntary License Schemes. The Licensor waives the right to + collect royalties, whether individually or, in the event that the + Licensor is a member of a collecting society that administers + voluntary licensing schemes, via that society, from any exercise + by You of the rights granted under this License. - f. "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. +The above rights may be exercised in all media and formats whether now +known or hereafter devised. The above rights include the right to make +such modifications as are technically necessary to exercise the rights in +other media and formats, but otherwise you have no rights to make +Adaptations. Subject to Section 8(f), all rights not expressly granted by +Licensor are hereby reserved. - g. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. +4. Restrictions. The license granted in Section 3 above is expressly made +subject to and limited by the following restrictions: - h. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. - - i. "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. - -2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. - -3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: - - a. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; and, - - b. to Distribute and Publicly Perform the Work including as incorporated in Collections. - - c. For the avoidance of doubt: - - i. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; - - ii. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and, - - iii. Voluntary License Schemes. The Licensor waives the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License. - -The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats, but otherwise you have no rights to make Adaptations. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved. - -4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: - - a. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(b), as requested. - - b. If You Distribute, or Publicly Perform the Work or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work. The credit required by this Section 4(b) may be implemented in any reasonable manner; provided, however, that in the case of a Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. - - c. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. + a. You may Distribute or Publicly Perform the Work only under the terms + of this License. You must include a copy of, or the Uniform Resource + Identifier (URI) for, this License with every copy of the Work You + Distribute or Publicly Perform. You may not offer or impose any terms + on the Work that restrict the terms of this License or the ability of + the recipient of the Work to exercise the rights granted to that + recipient under the terms of the License. You may not sublicense the + Work. You must keep intact all notices that refer to this License and + to the disclaimer of warranties with every copy of the Work You + Distribute or Publicly Perform. When You Distribute or Publicly + Perform the Work, You may not impose any effective technological + measures on the Work that restrict the ability of a recipient of the + Work from You to exercise the rights granted to that recipient under + the terms of the License. This Section 4(a) applies to the Work as + incorporated in a Collection, but this does not require the Collection + apart from the Work itself to be made subject to the terms of this + License. If You create a Collection, upon notice from any Licensor You + must, to the extent practicable, remove from the Collection any credit + as required by Section 4(b), as requested. + b. If You Distribute, or Publicly Perform the Work or Collections, You + must, unless a request has been made pursuant to Section 4(a), keep + intact all copyright notices for the Work and provide, reasonable to + the medium or means You are utilizing: (i) the name of the Original + Author (or pseudonym, if applicable) if supplied, and/or if the + Original Author and/or Licensor designate another party or parties + (e.g., a sponsor institute, publishing entity, journal) for + attribution ("Attribution Parties") in Licensor's copyright notice, + terms of service or by other reasonable means, the name of such party + or parties; (ii) the title of the Work if supplied; (iii) to the + extent reasonably practicable, the URI, if any, that Licensor + specifies to be associated with the Work, unless such URI does not + refer to the copyright notice or licensing information for the Work. + The credit required by this Section 4(b) may be implemented in any + reasonable manner; provided, however, that in the case of a + Collection, at a minimum such credit will appear, if a credit for all + contributing authors of the Collection appears, then as part of these + credits and in a manner at least as prominent as the credits for the + other contributing authors. For the avoidance of doubt, You may only + use the credit required by this Section for the purpose of attribution + in the manner set out above and, by exercising Your rights under this + License, You may not implicitly or explicitly assert or imply any + connection with, sponsorship or endorsement by the Original Author, + Licensor and/or Attribution Parties, as appropriate, of You or Your + use of the Work, without the separate, express prior written + permission of the Original Author, Licensor and/or Attribution + Parties. + c. Except as otherwise agreed in writing by the Licensor or as may be + otherwise permitted by applicable law, if You Reproduce, Distribute or + Publicly Perform the Work either by itself or as part of any + Collections, You must not distort, mutilate, modify or take other + derogatory action in relation to the Work which would be prejudicial + to the Original Author's honor or reputation. 5. Representations, Warranties and Disclaimer -UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR +OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY +KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, +INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, +FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF +LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, +WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION +OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. -6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE +LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR +ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES +ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. Termination - a. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. - - b. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. + a. This License and the rights granted hereunder will terminate + automatically upon any breach by You of the terms of this License. + Individuals or entities who have received Collections from You under + this License, however, will not have their licenses terminated + provided such individuals or entities remain in full compliance with + those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any + termination of this License. + b. Subject to the above terms and conditions, the license granted here is + perpetual (for the duration of the applicable copyright in the Work). + Notwithstanding the above, Licensor reserves the right to release the + Work under different license terms or to stop distributing the Work at + any time; provided, however that any such election will not serve to + withdraw this License (or any other license that has been, or is + required to be, granted under the terms of this License), and this + License will continue in full force and effect unless terminated as + stated above. 8. Miscellaneous - a. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. + a. Each time You Distribute or Publicly Perform the Work or a Collection, + the Licensor offers to the recipient a license to the Work on the same + terms and conditions as the license granted to You under this License. + b. If any provision of this License is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this License, and without further action + by the parties to this agreement, such provision shall be reformed to + the minimum extent necessary to make such provision valid and + enforceable. + c. No term or provision of this License shall be deemed waived and no + breach consented to unless such waiver or consent shall be in writing + and signed by the party to be charged with such waiver or consent. + d. This License constitutes the entire agreement between the parties with + respect to the Work licensed here. There are no understandings, + agreements or representations with respect to the Work not specified + here. Licensor shall not be bound by any additional provisions that + may appear in any communication from You. This License may not be + modified without the mutual written agreement of the Licensor and You. + e. The rights granted under, and the subject matter referenced, in this + License were drafted utilizing the terminology of the Berne Convention + for the Protection of Literary and Artistic Works (as amended on + September 28, 1979), the Rome Convention of 1961, the WIPO Copyright + Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 + and the Universal Copyright Convention (as revised on July 24, 1971). + These rights and subject matter take effect in the relevant + jurisdiction in which the License terms are sought to be enforced + according to the corresponding provisions of the implementation of + those treaty provisions in the applicable national law. If the + standard suite of rights granted under applicable copyright law + includes additional rights not granted under this License, such + additional rights are deemed to be included in the License; this + License is not intended to restrict the license of any rights under + applicable law. - b. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - - c. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. - - d. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. - - e. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. Creative Commons Notice -Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor. + Creative Commons is not a party to this License, and makes no warranty + whatsoever in connection with the Work. Creative Commons will not be + liable to You or any party on any legal theory for any damages + whatsoever, including without limitation any general, special, + incidental or consequential damages arising in connection to this + license. Notwithstanding the foregoing two (2) sentences, if Creative + Commons has expressly identified itself as the Licensor hereunder, it + shall have all rights and obligations of Licensor. -Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of this License. + Except for the limited purpose of indicating to the public that the + Work is licensed under the CCPL, Creative Commons does not authorize + the use by either party of the trademark "Creative Commons" or any + related trademark or logo of Creative Commons without the prior + written consent of Creative Commons. Any permitted use will be in + compliance with Creative Commons' then-current trademark usage + guidelines, as may be published on its website or otherwise made + available upon request from time to time. For the avoidance of doubt, + this trademark restriction does not form part of this License. -Creative Commons may be contacted at http://creativecommons.org/. + Creative Commons may be contacted at https://creativecommons.org/. diff --git a/options/license/CC-BY-SA-3.0 b/options/license/CC-BY-SA-3.0 index 39a8591c4a..604209a804 100644 --- a/options/license/CC-BY-SA-3.0 +++ b/options/license/CC-BY-SA-3.0 @@ -1,99 +1,359 @@ -Creative Commons Attribution-ShareAlike 3.0 Unported +Creative Commons Legal Code - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. +Attribution-ShareAlike 3.0 Unported + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR + DAMAGES RESULTING FROM ITS USE. License -THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE +COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY +COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS +AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. -BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE +TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY +BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS +CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND +CONDITIONS. 1. Definitions - a. "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. + a. "Adaptation" means a work based upon the Work, or upon the Work and + other pre-existing works, such as a translation, adaptation, + derivative work, arrangement of music or other alterations of a + literary or artistic work, or phonogram or performance and includes + cinematographic adaptations or any other form in which the Work may be + recast, transformed, or adapted including in any form recognizably + derived from the original, except that a work that constitutes a + Collection will not be considered an Adaptation for the purpose of + this License. For the avoidance of doubt, where the Work is a musical + work, performance or phonogram, the synchronization of the Work in + timed-relation with a moving image ("synching") will be considered an + Adaptation for the purpose of this License. + b. "Collection" means a collection of literary or artistic works, such as + encyclopedias and anthologies, or performances, phonograms or + broadcasts, or other works or subject matter other than works listed + in Section 1(f) below, which, by reason of the selection and + arrangement of their contents, constitute intellectual creations, in + which the Work is included in its entirety in unmodified form along + with one or more other contributions, each constituting separate and + independent works in themselves, which together are assembled into a + collective whole. A work that constitutes a Collection will not be + considered an Adaptation (as defined below) for the purposes of this + License. + c. "Creative Commons Compatible License" means a license that is listed + at https://creativecommons.org/compatiblelicenses that has been + approved by Creative Commons as being essentially equivalent to this + License, including, at a minimum, because that license: (i) contains + terms that have the same purpose, meaning and effect as the License + Elements of this License; and, (ii) explicitly permits the relicensing + of adaptations of works made available under that license under this + License or a Creative Commons jurisdiction license with the same + License Elements as this License. + d. "Distribute" means to make available to the public the original and + copies of the Work or Adaptation, as appropriate, through sale or + other transfer of ownership. + e. "License Elements" means the following high-level license attributes + as selected by Licensor and indicated in the title of this License: + Attribution, ShareAlike. + f. "Licensor" means the individual, individuals, entity or entities that + offer(s) the Work under the terms of this License. + g. "Original Author" means, in the case of a literary or artistic work, + the individual, individuals, entity or entities who created the Work + or if no individual or entity can be identified, the publisher; and in + addition (i) in the case of a performance the actors, singers, + musicians, dancers, and other persons who act, sing, deliver, declaim, + play in, interpret or otherwise perform literary or artistic works or + expressions of folklore; (ii) in the case of a phonogram the producer + being the person or legal entity who first fixes the sounds of a + performance or other sounds; and, (iii) in the case of broadcasts, the + organization that transmits the broadcast. + h. "Work" means the literary and/or artistic work offered under the terms + of this License including without limitation any production in the + literary, scientific and artistic domain, whatever may be the mode or + form of its expression including digital form, such as a book, + pamphlet and other writing; a lecture, address, sermon or other work + of the same nature; a dramatic or dramatico-musical work; a + choreographic work or entertainment in dumb show; a musical + composition with or without words; a cinematographic work to which are + assimilated works expressed by a process analogous to cinematography; + a work of drawing, painting, architecture, sculpture, engraving or + lithography; a photographic work to which are assimilated works + expressed by a process analogous to photography; a work of applied + art; an illustration, map, plan, sketch or three-dimensional work + relative to geography, topography, architecture or science; a + performance; a broadcast; a phonogram; a compilation of data to the + extent it is protected as a copyrightable work; or a work performed by + a variety or circus performer to the extent it is not otherwise + considered a literary or artistic work. + i. "You" means an individual or entity exercising rights under this + License who has not previously violated the terms of this License with + respect to the Work, or who has received express permission from the + Licensor to exercise rights under this License despite a previous + violation. + j. "Publicly Perform" means to perform public recitations of the Work and + to communicate to the public those public recitations, by any means or + process, including by wire or wireless means or public digital + performances; to make available to the public Works in such a way that + members of the public may access these Works from a place and at a + place individually chosen by them; to perform the Work to the public + by any means or process and the communication to the public of the + performances of the Work, including by public digital performance; to + broadcast and rebroadcast the Work by any means including signs, + sounds or images. + k. "Reproduce" means to make copies of the Work by any means including + without limitation by sound or visual recordings and the right of + fixation and reproducing fixations of the Work, including storage of a + protected performance or phonogram in digital form or other electronic + medium. - b. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined below) for the purposes of this License. +2. Fair Dealing Rights. Nothing in this License is intended to reduce, +limit, or restrict any uses free from copyright or rights arising from +limitations or exceptions that are provided for in connection with the +copyright protection under copyright law or other applicable laws. - c. "Creative Commons Compatible License" means a license that is listed at http://creativecommons.org/compatiblelicenses that has been approved by Creative Commons as being essentially equivalent to this License, including, at a minimum, because that license: (i) contains terms that have the same purpose, meaning and effect as the License Elements of this License; and, (ii) explicitly permits the relicensing of adaptations of works made available under that license under this License or a Creative Commons jurisdiction license with the same License Elements as this License. +3. License Grant. Subject to the terms and conditions of this License, +Licensor hereby grants You a worldwide, royalty-free, non-exclusive, +perpetual (for the duration of the applicable copyright) license to +exercise the rights in the Work as stated below: - d. "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership. + a. to Reproduce the Work, to incorporate the Work into one or more + Collections, and to Reproduce the Work as incorporated in the + Collections; + b. to create and Reproduce Adaptations provided that any such Adaptation, + including any translation in any medium, takes reasonable steps to + clearly label, demarcate or otherwise identify that changes were made + to the original Work. For example, a translation could be marked "The + original work was translated from English to Spanish," or a + modification could indicate "The original work has been modified."; + c. to Distribute and Publicly Perform the Work including as incorporated + in Collections; and, + d. to Distribute and Publicly Perform Adaptations. + e. For the avoidance of doubt: - e. "License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, ShareAlike. + i. Non-waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme cannot be waived, the Licensor + reserves the exclusive right to collect such royalties for any + exercise by You of the rights granted under this License; + ii. Waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme can be waived, the Licensor waives the + exclusive right to collect such royalties for any exercise by You + of the rights granted under this License; and, + iii. Voluntary License Schemes. The Licensor waives the right to + collect royalties, whether individually or, in the event that the + Licensor is a member of a collecting society that administers + voluntary licensing schemes, via that society, from any exercise + by You of the rights granted under this License. - f. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. +The above rights may be exercised in all media and formats whether now +known or hereafter devised. The above rights include the right to make +such modifications as are technically necessary to exercise the rights in +other media and formats. Subject to Section 8(f), all rights not expressly +granted by Licensor are hereby reserved. - g. "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. +4. Restrictions. The license granted in Section 3 above is expressly made +subject to and limited by the following restrictions: - h. "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. - - i. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. - - j. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. - - k. "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. - -2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. - -3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: - - a. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; - - b. to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified."; - - c. to Distribute and Publicly Perform the Work including as incorporated in Collections; and, - - d. to Distribute and Publicly Perform Adaptations. - - e. For the avoidance of doubt: - - i. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; - - ii. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and, - - iii. Voluntary License Schemes. The Licensor waives the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License. - -The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved. - -4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: - - a. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(c), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(c), as requested. - - b. You may Distribute or Publicly Perform an Adaptation only under the terms of: (i) this License; (ii) a later version of this License with the same License Elements as this License; (iii) a Creative Commons jurisdiction license (either this or a later license version) that contains the same License Elements as this License (e.g., Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons Compatible License. If you license the Adaptation under one of the licenses mentioned in (iv), you must comply with the terms of that license. If you license the Adaptation under the terms of any of the licenses mentioned in (i), (ii) or (iii) (the "Applicable License"), you must comply with the terms of the Applicable License generally and the following provisions: (I) You must include a copy of, or the URI for, the Applicable License with every copy of each Adaptation You Distribute or Publicly Perform; (II) You may not offer or impose any terms on the Adaptation that restrict the terms of the Applicable License or the ability of the recipient of the Adaptation to exercise the rights granted to that recipient under the terms of the Applicable License; (III) You must keep intact all notices that refer to the Applicable License and to the disclaimer of warranties with every copy of the Work as included in the Adaptation You Distribute or Publicly Perform; (IV) when You Distribute or Publicly Perform the Adaptation, You may not impose any effective technological measures on the Adaptation that restrict the ability of a recipient of the Adaptation from You to exercise the rights granted to that recipient under the terms of the Applicable License. This Section 4(b) applies to the Adaptation as incorporated in a Collection, but this does not require the Collection apart from the Adaptation itself to be made subject to the terms of the Applicable License. - - c. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and (iv) , consistent with Ssection 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4(c) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. - - d. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise. + a. You may Distribute or Publicly Perform the Work only under the terms + of this License. You must include a copy of, or the Uniform Resource + Identifier (URI) for, this License with every copy of the Work You + Distribute or Publicly Perform. You may not offer or impose any terms + on the Work that restrict the terms of this License or the ability of + the recipient of the Work to exercise the rights granted to that + recipient under the terms of the License. You may not sublicense the + Work. You must keep intact all notices that refer to this License and + to the disclaimer of warranties with every copy of the Work You + Distribute or Publicly Perform. When You Distribute or Publicly + Perform the Work, You may not impose any effective technological + measures on the Work that restrict the ability of a recipient of the + Work from You to exercise the rights granted to that recipient under + the terms of the License. This Section 4(a) applies to the Work as + incorporated in a Collection, but this does not require the Collection + apart from the Work itself to be made subject to the terms of this + License. If You create a Collection, upon notice from any Licensor You + must, to the extent practicable, remove from the Collection any credit + as required by Section 4(c), as requested. If You create an + Adaptation, upon notice from any Licensor You must, to the extent + practicable, remove from the Adaptation any credit as required by + Section 4(c), as requested. + b. You may Distribute or Publicly Perform an Adaptation only under the + terms of: (i) this License; (ii) a later version of this License with + the same License Elements as this License; (iii) a Creative Commons + jurisdiction license (either this or a later license version) that + contains the same License Elements as this License (e.g., + Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons Compatible + License. If you license the Adaptation under one of the licenses + mentioned in (iv), you must comply with the terms of that license. If + you license the Adaptation under the terms of any of the licenses + mentioned in (i), (ii) or (iii) (the "Applicable License"), you must + comply with the terms of the Applicable License generally and the + following provisions: (I) You must include a copy of, or the URI for, + the Applicable License with every copy of each Adaptation You + Distribute or Publicly Perform; (II) You may not offer or impose any + terms on the Adaptation that restrict the terms of the Applicable + License or the ability of the recipient of the Adaptation to exercise + the rights granted to that recipient under the terms of the Applicable + License; (III) You must keep intact all notices that refer to the + Applicable License and to the disclaimer of warranties with every copy + of the Work as included in the Adaptation You Distribute or Publicly + Perform; (IV) when You Distribute or Publicly Perform the Adaptation, + You may not impose any effective technological measures on the + Adaptation that restrict the ability of a recipient of the Adaptation + from You to exercise the rights granted to that recipient under the + terms of the Applicable License. This Section 4(b) applies to the + Adaptation as incorporated in a Collection, but this does not require + the Collection apart from the Adaptation itself to be made subject to + the terms of the Applicable License. + c. If You Distribute, or Publicly Perform the Work or any Adaptations or + Collections, You must, unless a request has been made pursuant to + Section 4(a), keep intact all copyright notices for the Work and + provide, reasonable to the medium or means You are utilizing: (i) the + name of the Original Author (or pseudonym, if applicable) if supplied, + and/or if the Original Author and/or Licensor designate another party + or parties (e.g., a sponsor institute, publishing entity, journal) for + attribution ("Attribution Parties") in Licensor's copyright notice, + terms of service or by other reasonable means, the name of such party + or parties; (ii) the title of the Work if supplied; (iii) to the + extent reasonably practicable, the URI, if any, that Licensor + specifies to be associated with the Work, unless such URI does not + refer to the copyright notice or licensing information for the Work; + and (iv) , consistent with Ssection 3(b), in the case of an + Adaptation, a credit identifying the use of the Work in the Adaptation + (e.g., "French translation of the Work by Original Author," or + "Screenplay based on original Work by Original Author"). The credit + required by this Section 4(c) may be implemented in any reasonable + manner; provided, however, that in the case of a Adaptation or + Collection, at a minimum such credit will appear, if a credit for all + contributing authors of the Adaptation or Collection appears, then as + part of these credits and in a manner at least as prominent as the + credits for the other contributing authors. For the avoidance of + doubt, You may only use the credit required by this Section for the + purpose of attribution in the manner set out above and, by exercising + Your rights under this License, You may not implicitly or explicitly + assert or imply any connection with, sponsorship or endorsement by the + Original Author, Licensor and/or Attribution Parties, as appropriate, + of You or Your use of the Work, without the separate, express prior + written permission of the Original Author, Licensor and/or Attribution + Parties. + d. Except as otherwise agreed in writing by the Licensor or as may be + otherwise permitted by applicable law, if You Reproduce, Distribute or + Publicly Perform the Work either by itself or as part of any + Adaptations or Collections, You must not distort, mutilate, modify or + take other derogatory action in relation to the Work which would be + prejudicial to the Original Author's honor or reputation. Licensor + agrees that in those jurisdictions (e.g. Japan), in which any exercise + of the right granted in Section 3(b) of this License (the right to + make Adaptations) would be deemed to be a distortion, mutilation, + modification or other derogatory action prejudicial to the Original + Author's honor and reputation, the Licensor will waive or not assert, + as appropriate, this Section, to the fullest extent permitted by the + applicable national law, to enable You to reasonably exercise Your + right under Section 3(b) of this License (right to make Adaptations) + but not otherwise. 5. Representations, Warranties and Disclaimer -UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR +OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY +KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, +INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, +FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF +LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, +WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION +OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. -6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE +LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR +ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES +ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. Termination - a. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. - - b. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. + a. This License and the rights granted hereunder will terminate + automatically upon any breach by You of the terms of this License. + Individuals or entities who have received Adaptations or Collections + from You under this License, however, will not have their licenses + terminated provided such individuals or entities remain in full + compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will + survive any termination of this License. + b. Subject to the above terms and conditions, the license granted here is + perpetual (for the duration of the applicable copyright in the Work). + Notwithstanding the above, Licensor reserves the right to release the + Work under different license terms or to stop distributing the Work at + any time; provided, however that any such election will not serve to + withdraw this License (or any other license that has been, or is + required to be, granted under the terms of this License), and this + License will continue in full force and effect unless terminated as + stated above. 8. Miscellaneous - a. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. + a. Each time You Distribute or Publicly Perform the Work or a Collection, + the Licensor offers to the recipient a license to the Work on the same + terms and conditions as the license granted to You under this License. + b. Each time You Distribute or Publicly Perform an Adaptation, Licensor + offers to the recipient a license to the original Work on the same + terms and conditions as the license granted to You under this License. + c. If any provision of this License is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this License, and without further action + by the parties to this agreement, such provision shall be reformed to + the minimum extent necessary to make such provision valid and + enforceable. + d. No term or provision of this License shall be deemed waived and no + breach consented to unless such waiver or consent shall be in writing + and signed by the party to be charged with such waiver or consent. + e. This License constitutes the entire agreement between the parties with + respect to the Work licensed here. There are no understandings, + agreements or representations with respect to the Work not specified + here. Licensor shall not be bound by any additional provisions that + may appear in any communication from You. This License may not be + modified without the mutual written agreement of the Licensor and You. + f. The rights granted under, and the subject matter referenced, in this + License were drafted utilizing the terminology of the Berne Convention + for the Protection of Literary and Artistic Works (as amended on + September 28, 1979), the Rome Convention of 1961, the WIPO Copyright + Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 + and the Universal Copyright Convention (as revised on July 24, 1971). + These rights and subject matter take effect in the relevant + jurisdiction in which the License terms are sought to be enforced + according to the corresponding provisions of the implementation of + those treaty provisions in the applicable national law. If the + standard suite of rights granted under applicable copyright law + includes additional rights not granted under this License, such + additional rights are deemed to be included in the License; this + License is not intended to restrict the license of any rights under + applicable law. - b. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. - - c. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - - d. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. - - e. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. - - f. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. Creative Commons Notice -Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor. + Creative Commons is not a party to this License, and makes no warranty + whatsoever in connection with the Work. Creative Commons will not be + liable to You or any party on any legal theory for any damages + whatsoever, including without limitation any general, special, + incidental or consequential damages arising in connection to this + license. Notwithstanding the foregoing two (2) sentences, if Creative + Commons has expressly identified itself as the Licensor hereunder, it + shall have all rights and obligations of Licensor. -Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of the License. + Except for the limited purpose of indicating to the public that the + Work is licensed under the CCPL, Creative Commons does not authorize + the use by either party of the trademark "Creative Commons" or any + related trademark or logo of Creative Commons without the prior + written consent of Creative Commons. Any permitted use will be in + compliance with Creative Commons' then-current trademark usage + guidelines, as may be published on its website or otherwise made + available upon request from time to time. For the avoidance of doubt, + this trademark restriction does not form part of the License. -Creative Commons may be contacted at http://creativecommons.org/. + Creative Commons may be contacted at https://creativecommons.org/. diff --git a/options/license/HPND-sell-variant-MIT-disclaimer-rev b/options/license/HPND-sell-variant-MIT-disclaimer-rev new file mode 100644 index 0000000000..f68aff5c99 --- /dev/null +++ b/options/license/HPND-sell-variant-MIT-disclaimer-rev @@ -0,0 +1,15 @@ +Disclaimer: + +The software is provided "as is", without warranty of any kind, +express or implied, including but not limited to the warranties +of merchantability, fitness for a particular purpose and +noninfringement. In no event shall the author(s) be liable for +any claim, damages or other liability, whether in an action of +contract, tort or otherwise, arising from, out of or in connection +with the software or the use or other dealings in the software. + +Permission to use, copy, modify, distribute, and sell this +software and its documentation for any purpose is hereby +granted without fee, provided that the above copyright notice +appear in all copies and that both that copyright notice and +this permission notice appear in supporting documentation. diff --git a/options/license/LGPL-2.0-only b/options/license/LGPL-2.0-only index eb3a4cd1db..843b00b561 100644 --- a/options/license/LGPL-2.0-only +++ b/options/license/LGPL-2.0-only @@ -39,6 +39,7 @@ The precise terms and conditions for copying, distribution and modification foll Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. +GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". diff --git a/options/license/LGPL-2.0-or-later b/options/license/LGPL-2.0-or-later index eb3a4cd1db..843b00b561 100644 --- a/options/license/LGPL-2.0-or-later +++ b/options/license/LGPL-2.0-or-later @@ -39,6 +39,7 @@ The precise terms and conditions for copying, distribution and modification foll Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. +GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". diff --git a/options/license/LGPL-2.1-only b/options/license/LGPL-2.1-only index c9aa53018e..c6487f4fdf 100644 --- a/options/license/LGPL-2.1-only +++ b/options/license/LGPL-2.1-only @@ -41,6 +41,7 @@ Although the Lesser General Public License is Less protective of the users' free The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. +GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". diff --git a/options/license/LGPL-2.1-or-later b/options/license/LGPL-2.1-or-later index c9aa53018e..c6487f4fdf 100644 --- a/options/license/LGPL-2.1-or-later +++ b/options/license/LGPL-2.1-or-later @@ -41,6 +41,7 @@ Although the Lesser General Public License is Less protective of the users' free The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. +GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". diff --git a/options/license/PCRE2-exception b/options/license/PCRE2-exception new file mode 100644 index 0000000000..eb7fd11767 --- /dev/null +++ b/options/license/PCRE2-exception @@ -0,0 +1,8 @@ +EXEMPTION FOR BINARY LIBRARY-LIKE PACKAGES +------------------------------------------ + +The second condition in the BSD licence (covering binary redistributions) does +not apply all the way down a chain of software. If binary package A includes +PCRE2, it must respect the condition, but if package B is software that +includes package A, the condition is not imposed on package B unless it uses +PCRE2 independently. diff --git a/options/license/PPL b/options/license/PPL new file mode 100644 index 0000000000..013303699e --- /dev/null +++ b/options/license/PPL @@ -0,0 +1,96 @@ +Peer Production License + +Created by John Magyar, B.A., J.D. and Dmytri Kleiner, the following Peer Production License, a model for a Copyfarleft license, has been derived from the Creative Commons ‘Attribution-NonCommercial-ShareAlike' license available at http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode. + +LICENSE + +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS COPYFARLEFT PUBLIC LICENSE ("LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND ALL OTHER APPLICABLE LAWS. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED IN THIS LICENSE, YOU AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN AS CONSIDERATION FOR ACCEPTING THE TERMS AND CONDITIONS OF THIS LICENSE AND FOR AGREEING TO BE BOUND BY THE TERMS AND CONDITIONS OF THIS LICENSE. + +1. DEFINITIONS + + a. "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. + + b. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License. + + c. "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale, gift or any other transfer of possession or ownership. + + d. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. + + e. "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. + + f. "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. + + g. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. + + h. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. + + i. "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. + +2. FAIR DEALING RIGHTS +Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. + +3. LICENSE GRANT +Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: + + a. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; + + b. to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified."; + + c. to Distribute and Publicly Perform the Work including as incorporated in Collections; and, + + d. to Distribute and Publicly Perform Adaptations. The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved, including but not limited to the rights set forth in Section 4(f). + +4. RESTRICTIONS +The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: + + a. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(d), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(d), as requested. + + b. Subject to the exception in Section 4(c), you may not exercise any of the rights granted to You in Section 3 above in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation. The exchange of the Work for other copyrighted works by means of digital file-sharing or otherwise shall not be considered to be intended for or directed toward commercial advantage or private monetary compensation, provided there is no payment of any monetary compensation in connection with the exchange of copyrighted works. + + c. You may exercise the rights granted in Section 3 for commercial purposes only if: + + i. You are a worker-owned business or worker-owned collective; and + + ii. all financial gain, surplus, profits and benefits produced by the business or collective are distributed among the worker-owners + + d. Any use by a business that is privately owned and managed, and that seeks to generate profit from the labor of employees paid by salary or other wages, is not permitted under this license. + + e. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and, (iv) consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4(d) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. + + f. For the avoidance of doubt: + + i. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; + + ii. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License if Your exercise of such rights is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(b) and otherwise waives the right to collect royalties through any statutory or compulsory licensing scheme; and, + + iii.Voluntary License Schemes. The Licensor reserves the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License that is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(b). + + g. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise. + +5. REPRESENTATIONS, WARRANTIES AND DISCLAIMER + +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. + +6. LIMITATION ON LIABILITY + +EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. TERMINATION + + a. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. + + b. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. + +8. MISCELLANEOUS + + a. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. + + b. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. + + c. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + + d. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. + + e. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. + + f. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. diff --git a/options/license/any-OSI b/options/license/any-OSI new file mode 100644 index 0000000000..5f69e02b8a --- /dev/null +++ b/options/license/any-OSI @@ -0,0 +1,3 @@ +Pick your favourite OSI approved license :) + +http://www.opensource.org/licenses/alphabetical diff --git a/options/license/cve-tou b/options/license/cve-tou new file mode 100644 index 0000000000..c7b2f02e3e --- /dev/null +++ b/options/license/cve-tou @@ -0,0 +1,16 @@ +CVE Usage: MITRE hereby grants you a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable copyright license to reproduce, prepare +derivative works of, publicly display, publicly perform, sublicense, and +distribute Common Vulnerabilities and Exposures (CVE®). Any copy you make for +such purposes is authorized provided that you reproduce MITRE's copyright +designation and this license in any such copy. + +DISCLAIMERS + +ALL DOCUMENTS AND THE INFORMATION CONTAINED THEREIN PROVIDED BY MITRE ARE +PROVIDED ON AN "AS IS" BASIS AND THE CONTRIBUTOR, THE ORGANIZATION HE/SHE +REPRESENTS OR IS SPONSORED BY (IF ANY), THE MITRE CORPORATION, ITS BOARD OF +TRUSTEES, OFFICERS, AGENTS, AND EMPLOYEES, DISCLAIM ALL WARRANTIES, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE +INFORMATION THEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF +MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. From b3beaed147466739de0c24fd80206b5af8b71617 Mon Sep 17 00:00:00 2001 From: Zettat123 <zettat123@gmail.com> Date: Mon, 13 May 2024 12:28:53 +0800 Subject: [PATCH 309/370] Support using label names when changing issue labels (#30943) Resolve #30917 Make the APIs for adding labels and replacing labels support both label IDs and label names so the [`actions/labeler`](https://github.com/actions/labeler) action can work in Gitea. <img width="600px" src="https://github.com/go-gitea/gitea/assets/15528715/7835c771-f637-4c57-9ce5-e4fbf56fa0d3" /> --- modules/structs/issue_label.go | 5 ++- routers/api/v1/repo/issue_label.go | 29 ++++++++++++- templates/swagger/v1_json.tmpl | 7 +-- tests/integration/api_issue_label_test.go | 53 ++++++++++++++++++++++- 4 files changed, 84 insertions(+), 10 deletions(-) diff --git a/modules/structs/issue_label.go b/modules/structs/issue_label.go index bf68726d79..942cc0b3a1 100644 --- a/modules/structs/issue_label.go +++ b/modules/structs/issue_label.go @@ -47,8 +47,9 @@ type EditLabelOption struct { // IssueLabelsOption a collection of labels type IssueLabelsOption struct { - // list of label IDs - Labels []int64 `json:"labels"` + // Labels can be a list of integers representing label IDs + // or a list of strings representing label names + Labels []any `json:"labels"` } // LabelTemplate info of a Label template diff --git a/routers/api/v1/repo/issue_label.go b/routers/api/v1/repo/issue_label.go index 7d9f85d2aa..413693c5ed 100644 --- a/routers/api/v1/repo/issue_label.go +++ b/routers/api/v1/repo/issue_label.go @@ -5,7 +5,9 @@ package repo import ( + "fmt" "net/http" + "reflect" issues_model "code.gitea.io/gitea/models/issues" api "code.gitea.io/gitea/modules/structs" @@ -317,7 +319,32 @@ func prepareForReplaceOrAdd(ctx *context.APIContext, form api.IssueLabelsOption) return nil, nil, err } - labels, err := issues_model.GetLabelsByIDs(ctx, form.Labels, "id", "repo_id", "org_id", "name", "exclusive") + var ( + labelIDs []int64 + labelNames []string + ) + for _, label := range form.Labels { + rv := reflect.ValueOf(label) + switch rv.Kind() { + case reflect.Float64: + labelIDs = append(labelIDs, int64(rv.Float())) + case reflect.String: + labelNames = append(labelNames, rv.String()) + } + } + if len(labelIDs) > 0 && len(labelNames) > 0 { + ctx.Error(http.StatusBadRequest, "InvalidLabels", "labels should be an array of strings or integers") + return nil, nil, fmt.Errorf("invalid labels") + } + if len(labelNames) > 0 { + labelIDs, err = issues_model.GetLabelIDsInRepoByNames(ctx, ctx.Repo.Repository.ID, labelNames) + if err != nil { + ctx.Error(http.StatusInternalServerError, "GetLabelIDsInRepoByNames", err) + return nil, nil, err + } + } + + labels, err := issues_model.GetLabelsByIDs(ctx, labelIDs, "id", "repo_id", "org_id", "name", "exclusive") if err != nil { ctx.Error(http.StatusInternalServerError, "GetLabelsByIDs", err) return nil, nil, err diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 5ca499e708..b1255f1289 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -21897,12 +21897,9 @@ "type": "object", "properties": { "labels": { - "description": "list of label IDs", + "description": "Labels can be a list of integers representing label IDs\nor a list of strings representing label names", "type": "array", - "items": { - "type": "integer", - "format": "int64" - }, + "items": {}, "x-go-name": "Labels" } }, diff --git a/tests/integration/api_issue_label_test.go b/tests/integration/api_issue_label_test.go index 35c0718263..0e4cd8243b 100644 --- a/tests/integration/api_issue_label_test.go +++ b/tests/integration/api_issue_label_test.go @@ -104,7 +104,7 @@ func TestAPIAddIssueLabels(t *testing.T) { urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels", repo.OwnerName, repo.Name, issue.Index) req := NewRequestWithJSON(t, "POST", urlStr, &api.IssueLabelsOption{ - Labels: []int64{1, 2}, + Labels: []any{1, 2}, }).AddTokenAuth(token) resp := MakeRequest(t, req, http.StatusOK) var apiLabels []*api.Label @@ -114,6 +114,32 @@ func TestAPIAddIssueLabels(t *testing.T) { unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: 2}) } +func TestAPIAddIssueLabelsWithLabelNames(t *testing.T) { + assert.NoError(t, unittest.LoadFixtures()) + + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: repo.ID}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) + + session := loginUser(t, owner.Name) + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteIssue) + urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels", + repo.OwnerName, repo.Name, issue.Index) + req := NewRequestWithJSON(t, "POST", urlStr, &api.IssueLabelsOption{ + Labels: []any{"label1", "label2"}, + }).AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusOK) + var apiLabels []*api.Label + DecodeJSON(t, resp, &apiLabels) + assert.Len(t, apiLabels, unittest.GetCount(t, &issues_model.IssueLabel{IssueID: issue.ID})) + + var apiLabelNames []string + for _, label := range apiLabels { + apiLabelNames = append(apiLabelNames, label.Name) + } + assert.ElementsMatch(t, apiLabelNames, []string{"label1", "label2"}) +} + func TestAPIReplaceIssueLabels(t *testing.T) { assert.NoError(t, unittest.LoadFixtures()) @@ -127,7 +153,7 @@ func TestAPIReplaceIssueLabels(t *testing.T) { urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels", owner.Name, repo.Name, issue.Index) req := NewRequestWithJSON(t, "PUT", urlStr, &api.IssueLabelsOption{ - Labels: []int64{label.ID}, + Labels: []any{label.ID}, }).AddTokenAuth(token) resp := MakeRequest(t, req, http.StatusOK) var apiLabels []*api.Label @@ -140,6 +166,29 @@ func TestAPIReplaceIssueLabels(t *testing.T) { unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: label.ID}) } +func TestAPIReplaceIssueLabelsWithLabelNames(t *testing.T) { + assert.NoError(t, unittest.LoadFixtures()) + + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: repo.ID}) + label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{RepoID: repo.ID}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) + + session := loginUser(t, owner.Name) + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteIssue) + urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels", + owner.Name, repo.Name, issue.Index) + req := NewRequestWithJSON(t, "PUT", urlStr, &api.IssueLabelsOption{ + Labels: []any{label.Name}, + }).AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusOK) + var apiLabels []*api.Label + DecodeJSON(t, resp, &apiLabels) + if assert.Len(t, apiLabels, 1) { + assert.EqualValues(t, label.Name, apiLabels[0].Name) + } +} + func TestAPIModifyOrgLabels(t *testing.T) { assert.NoError(t, unittest.LoadFixtures()) From 8218b6484c86eaec6b45e97bbf85a88c2db71568 Mon Sep 17 00:00:00 2001 From: james yang <yanghongday369@gmail.com> Date: Mon, 13 May 2024 22:05:56 +0800 Subject: [PATCH 310/370] fix: change npm scope registry (#30964) https://docs.npmjs.com/cli/v10/using-npm/scope#associating-a-scope-with-a-registry --- docs/content/usage/packages/npm.en-us.md | 4 ++-- docs/content/usage/packages/npm.zh-cn.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/content/usage/packages/npm.en-us.md b/docs/content/usage/packages/npm.en-us.md index 1590b9623a..ccc075b140 100644 --- a/docs/content/usage/packages/npm.en-us.md +++ b/docs/content/usage/packages/npm.en-us.md @@ -30,7 +30,7 @@ The following examples use the `npm` tool with the scope `@test`. To register the package registry you need to configure a new package source. ```shell -npm config set {scope}:registry https://gitea.example.com/api/packages/{owner}/npm/ +npm config set {scope}:registry=https://gitea.example.com/api/packages/{owner}/npm/ npm config set -- '//gitea.example.com/api/packages/{owner}/npm/:_authToken' "{token}" ``` @@ -43,7 +43,7 @@ npm config set -- '//gitea.example.com/api/packages/{owner}/npm/:_authToken' "{t For example: ```shell -npm config set @test:registry https://gitea.example.com/api/packages/testuser/npm/ +npm config set @test:registry=https://gitea.example.com/api/packages/testuser/npm/ npm config set -- '//gitea.example.com/api/packages/testuser/npm/:_authToken' "personal_access_token" ``` diff --git a/docs/content/usage/packages/npm.zh-cn.md b/docs/content/usage/packages/npm.zh-cn.md index d51b8b78a1..772cdc08b2 100644 --- a/docs/content/usage/packages/npm.zh-cn.md +++ b/docs/content/usage/packages/npm.zh-cn.md @@ -30,7 +30,7 @@ menu: 要注册软件包注册表,您需要配置一个新的软件包源。 ```shell -npm config set {scope}:registry https://gitea.example.com/api/packages/{owner}/npm/ +npm config set {scope}:registry=https://gitea.example.com/api/packages/{owner}/npm/ npm config set -- '//gitea.example.com/api/packages/{owner}/npm/:_authToken' "{token}" ``` @@ -43,7 +43,7 @@ npm config set -- '//gitea.example.com/api/packages/{owner}/npm/:_authToken' "{t 例如: ```shell -npm config set @test:registry https://gitea.example.com/api/packages/testuser/npm/ +npm config set @test:registry=https://gitea.example.com/api/packages/testuser/npm/ npm config set -- '//gitea.example.com/api/packages/testuser/npm/:_authToken' "personal_access_token" ``` From ed25676a9ae75c3a5f092dbaa449770fb1e9e70c Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Mon, 13 May 2024 23:33:51 +0200 Subject: [PATCH 311/370] Restyle release list, fix branch dropdown (#30837) Fixes https://github.com/go-gitea/gitea/issues/30821 and restyles the release list. Desktop: <img width="1199" alt="Screenshot 2024-05-02 at 20 46 10" src="https://github.com/go-gitea/gitea/assets/115237/bee92423-d4a9-4b26-8301-3a1e09eef4cd"> Mobile: <img width="443" alt="Screenshot 2024-05-02 at 20 46 21" src="https://github.com/go-gitea/gitea/assets/115237/42ecbae5-bdb6-4b16-a0ee-9c64daede68d"> --------- Co-authored-by: Giteabot <teabot@gitea.io> --- templates/repo/release/list.tmpl | 17 ++++--- templates/repo/tag/list.tmpl | 8 ++-- tests/integration/release_test.go | 8 ++-- web_src/css/repo/release-tag.css | 80 ++++++++++++++++++++----------- 4 files changed, 68 insertions(+), 45 deletions(-) diff --git a/templates/repo/release/list.tmpl b/templates/repo/release/list.tmpl index 5a8668fbe1..34548672b5 100644 --- a/templates/repo/release/list.tmpl +++ b/templates/repo/release/list.tmpl @@ -7,18 +7,18 @@ <ul id="release-list"> {{range $idx, $info := .Releases}} {{$release := $info.Release}} - <li class="ui grid"> - <div class="ui four wide column meta"> + <li class="release-entry"> + <div class="meta"> <a class="muted" href="{{if not (and $release.Sha1 ($.Permission.CanRead ctx.Consts.RepoUnitTypeCode))}}#{{else}}{{$.RepoLink}}/src/tag/{{$release.TagName | PathEscapeSegments}}{{end}}" rel="nofollow">{{svg "octicon-tag" 16 "tw-mr-1"}}{{$release.TagName}}</a> {{if and $release.Sha1 ($.Permission.CanRead ctx.Consts.RepoUnitTypeCode)}} <a class="muted tw-font-mono" href="{{$.RepoLink}}/src/commit/{{$release.Sha1}}" rel="nofollow">{{svg "octicon-git-commit" 16 "tw-mr-1"}}{{ShortSha $release.Sha1}}</a> {{template "repo/branch_dropdown" dict "root" $ "release" $release}} {{end}} </div> - <div class="ui twelve wide column detail"> + <div class="ui segment detail"> <div class="tw-flex tw-items-center tw-justify-between tw-flex-wrap tw-mb-2"> <h4 class="release-list-title gt-word-break"> - {{if $.PageIsSingleTag}}{{$release.Title}}{{else}}<a href="{{$.RepoLink}}/releases/tag/{{$release.TagName | PathEscapeSegments}}">{{$release.Title}}</a>{{end}} + {{if $.PageIsSingleTag}}{{$release.Title}}{{else}}<a class="muted" href="{{$.RepoLink}}/releases/tag/{{$release.TagName | PathEscapeSegments}}">{{$release.Title}}</a>{{end}} {{template "repo/commit_statuses" dict "Status" $info.CommitStatus "Statuses" $info.CommitStatuses "AdditionalClasses" "tw-flex"}} {{if $release.IsDraft}} <span class="ui yellow label">{{ctx.Locale.Tr "repo.release.draft"}}</span> @@ -62,22 +62,22 @@ </div> <div class="divider"></div> <details class="download" {{if eq $idx 0}}open{{end}}> - <summary class="tw-my-4"> + <summary> {{ctx.Locale.Tr "repo.release.downloads"}} </summary> <ul class="list"> {{if and (not $.DisableDownloadSourceArchives) (not $release.IsDraft) ($.Permission.CanRead ctx.Consts.RepoUnitTypeCode)}} <li> - <a class="archive-link" href="{{$.RepoLink}}/archive/{{$release.TagName | PathEscapeSegments}}.zip" rel="nofollow"><strong>{{svg "octicon-file-zip" 16 "tw-mr-1"}}{{ctx.Locale.Tr "repo.release.source_code"}} (ZIP)</strong></a> + <a class="archive-link" href="{{$.RepoLink}}/archive/{{$release.TagName | PathEscapeSegments}}.zip" rel="nofollow"><strong>{{svg "octicon-file-zip" 16 "download-icon"}}{{ctx.Locale.Tr "repo.release.source_code"}} (ZIP)</strong></a> </li> <li> - <a class="archive-link" href="{{$.RepoLink}}/archive/{{$release.TagName | PathEscapeSegments}}.tar.gz" rel="nofollow"><strong>{{svg "octicon-file-zip" 16 "tw-mr-1"}}{{ctx.Locale.Tr "repo.release.source_code"}} (TAR.GZ)</strong></a> + <a class="archive-link" href="{{$.RepoLink}}/archive/{{$release.TagName | PathEscapeSegments}}.tar.gz" rel="nofollow"><strong>{{svg "octicon-file-zip" 16 "download-icon"}}{{ctx.Locale.Tr "repo.release.source_code"}} (TAR.GZ)</strong></a> </li> {{end}} {{range $release.Attachments}} <li> <a target="_blank" rel="nofollow" href="{{.DownloadURL}}" download> - <strong>{{svg "octicon-package" 16 "tw-mr-1"}}{{.Name}}</strong> + <strong>{{svg "octicon-package" 16 "download-icon"}}{{.Name}}</strong> </a> <div> <span class="text grey">{{.Size | FileSize}}</span> @@ -89,7 +89,6 @@ {{end}} </ul> </details> - <div class="dot"></div> </div> </li> {{end}} diff --git a/templates/repo/tag/list.tmpl b/templates/repo/tag/list.tmpl index b3ad3a7c47..354808ed2e 100644 --- a/templates/repo/tag/list.tmpl +++ b/templates/repo/tag/list.tmpl @@ -16,12 +16,12 @@ <tbody class="tag-list"> {{range $idx, $release := .Releases}} <tr> - <td class="tag"> - <h3 class="release-tag-name tw-mb-2"> + <td class="tag-list-row"> + <h3 class="tag-list-row-title tw-mb-2"> {{if $canReadReleases}} - <a class="tw-flex tw-items-center" href="{{$.RepoLink}}/releases/tag/{{.TagName | PathEscapeSegments}}" rel="nofollow">{{.TagName}}</a> + <a class="tag-list-row-link tw-flex tw-items-center" href="{{$.RepoLink}}/releases/tag/{{.TagName | PathEscapeSegments}}" rel="nofollow">{{.TagName}}</a> {{else}} - <a class="tw-flex tw-items-center" href="{{$.RepoLink}}/src/tag/{{.TagName | PathEscapeSegments}}" rel="nofollow">{{.TagName}}</a> + <a class="tag-list-row-link tw-flex tw-items-center" href="{{$.RepoLink}}/src/tag/{{.TagName | PathEscapeSegments}}" rel="nofollow">{{.TagName}}</a> {{end}} </h3> <div class="download tw-flex tw-items-center"> diff --git a/tests/integration/release_test.go b/tests/integration/release_test.go index ce0c440167..40bd798d16 100644 --- a/tests/integration/release_test.go +++ b/tests/integration/release_test.go @@ -142,7 +142,7 @@ func TestViewReleaseListNoLogin(t *testing.T) { rsp := MakeRequest(t, req, http.StatusOK) htmlDoc := NewHTMLParser(t, rsp.Body) - releases := htmlDoc.Find("#release-list li.ui.grid") + releases := htmlDoc.Find("#release-list .release-entry") assert.Equal(t, 5, releases.Length()) links := make([]string, 0, 5) @@ -198,7 +198,7 @@ func TestViewReleaseListLogin(t *testing.T) { rsp := session.MakeRequest(t, req, http.StatusOK) htmlDoc := NewHTMLParser(t, rsp.Body) - releases := htmlDoc.Find("#release-list li.ui.grid") + releases := htmlDoc.Find("#release-list .release-entry") assert.Equal(t, 3, releases.Length()) links := make([]string, 0, 5) @@ -229,12 +229,12 @@ func TestViewTagsList(t *testing.T) { rsp := session.MakeRequest(t, req, http.StatusOK) htmlDoc := NewHTMLParser(t, rsp.Body) - tags := htmlDoc.Find(".tag-list tr") + tags := htmlDoc.Find(".tag-list-row-link") assert.Equal(t, 3, tags.Length()) tagNames := make([]string, 0, 5) tags.Each(func(i int, s *goquery.Selection) { - tagNames = append(tagNames, s.Find(".tag a.tw-flex.tw-items-center").Text()) + tagNames = append(tagNames, s.Text()) }) assert.EqualValues(t, []string{"v1.0", "delete-tag", "v1.1"}, tagNames) diff --git a/web_src/css/repo/release-tag.css b/web_src/css/repo/release-tag.css index a146eda6a9..32027dd886 100644 --- a/web_src/css/repo/release-tag.css +++ b/web_src/css/repo/release-tag.css @@ -1,10 +1,11 @@ -.repository.releases #release-list { - margin-top: 12px; - padding-top: 12px; +#release-list { + display: flex; + flex-direction: column; + gap: var(--page-spacing); padding-left: 0; } -.repository.releases #release-list .release-list-title { +#release-list .release-list-title { font-size: 2rem; font-weight: var(--font-weight-normal); display: flex; @@ -13,58 +14,81 @@ margin: 0; } -.repository.releases #release-list > li .meta { - padding-top: 25px; +#release-list .release-entry { + display: flex; + gap: var(--page-spacing); +} + +#release-list .release-entry .meta { + flex: 0 0 150px; position: relative; text-align: right; display: flex; flex-direction: column; - gap: 1em; + gap: 10px; } -.repository.releases #release-list > li .detail { - padding-bottom: 20px; - border-left: 1px solid var(--color-secondary); +#release-list .release-entry .detail { + flex: 1; + margin: 0; } -.repository.releases #release-list > li .detail .author img { +@media (max-width: 767.98px) { + #release-list .release-entry { + flex-direction: column; + gap: var(--page-spacing); + } + #release-list .release-entry .meta { + margin-left: 6px; + flex-direction: row; + flex-basis: auto; + display: flex; + align-items: center; + } + #release-list .js-branch-tag-selector { + margin-left: auto; + } + #release-list .branch-selector-dropdown .menu { /* open menu to left */ + right: 0; + left: auto; + } +} + +#release-list .release-entry .detail .author img { margin-bottom: 2px; /* the legacy trick to align the avatar vertically, no better solution at the moment */ } -.repository.releases #release-list > li .detail .download .list { +#release-list .release-entry .detail .download .list { padding-left: 0; border: 1px solid var(--color-secondary); border-radius: var(--border-radius); - background: var(--color-light); } -.repository.releases #release-list > li .detail .download .list li { +#release-list .release-entry .detail .download .list li { display: flex; justify-content: space-between; padding: 8px; border-bottom: 1px solid var(--color-secondary); } -.repository.releases #release-list > li .detail .download .list li:last-child { +#release-list .release-entry .detail .download[open] summary { + margin-bottom: 10px; +} + +#release-list .download-icon { + margin-right: .25rem; + color: var(--color-text-light-1); +} + +#release-list .release-entry .detail .download .list li:last-child { border-bottom: none; } -.repository.releases #release-list > li .detail .dot { - width: 10px; - height: 10px; - background-color: var(--color-secondary-dark-3); - position: absolute; - left: -5.5px; - top: 30px; - border-radius: var(--border-radius-circle); - border: 2.5px solid var(--color-body); -} - -.repository.tags #tags-table .tag { +#tags-table .tag-list-row { padding: 8px 12px; } -.repository.tags #tags-table .release-tag-name { +#tags-table .tag-list-row-title { font-size: 18px; font-weight: var(--font-weight-normal); } From 9a577c62e4848a497340cbe8fbfb5d663ccd78a4 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Tue, 14 May 2024 00:25:02 +0000 Subject: [PATCH 312/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_ja-JP.ini | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index e33a1ae173..03a06dab16 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -164,6 +164,8 @@ search=検索… type_tooltip=検索タイプ fuzzy=あいまい fuzzy_tooltip=検索語におおよそ一致する結果も含めます +exact=完全一致 +exact_tooltip=検索語と完全に一致する結果だけを含めます repo_kind=リポジトリを検索... user_kind=ユーザーを検索... org_kind=組織を検索... @@ -177,6 +179,8 @@ branch_kind=ブランチを検索... commit_kind=コミットを検索... runner_kind=ランナーを検索... no_results=一致する結果が見つかりませんでした +issue_kind=イシューを検索... +pull_kind=プルリクエストを検索... keyword_search_unavailable=キーワード検索は現在利用できません。 サイト管理者にお問い合わせください。 [aria] @@ -883,6 +887,7 @@ repo_and_org_access=リポジトリと組織へのアクセス permissions_public_only=公開のみ permissions_access_all=すべて (公開、プライベート、限定) select_permissions=許可の選択 +permission_not_set=設定なし permission_no_access=アクセス不可 permission_read=読み取り permission_write=読み取りと書き込み @@ -2093,6 +2098,7 @@ settings.advanced_settings=拡張設定 settings.wiki_desc=Wikiを有効にする settings.use_internal_wiki=ビルトインのWikiを使用する settings.default_wiki_branch_name=デフォルトのWikiブランチ名 +settings.default_wiki_everyone_access=サインインユーザーのデフォルトのアクセス権限: settings.failed_to_change_default_wiki_branch=デフォルトのWikiブランチを変更できませんでした。 settings.use_external_wiki=外部のWikiを使用する settings.external_wiki_url=外部WikiのURL @@ -3486,6 +3492,7 @@ npm.install=npm を使用してパッケージをインストールするには npm.install2=または package.json ファイルに追加します: npm.dependencies=依存関係 npm.dependencies.development=開発用依存関係 +npm.dependencies.bundle=バンドルされた依存関係 npm.dependencies.peer=Peer依存関係 npm.dependencies.optional=オプションの依存関係 npm.details.tag=タグ From b1d8f13bd0ecd9c576ebf2ecbd9c7dbeb3f5254f Mon Sep 17 00:00:00 2001 From: KN4CK3R <admin@oldschoolhack.me> Date: Tue, 14 May 2024 08:48:21 +0200 Subject: [PATCH 313/370] Protected tag is no internal server error (#30962) Fixes #30959 Adds an API test for protected tags. Fix existing tag in combination with fixtures. --- models/fixtures/protected_tag.yml | 24 ++++++++++++++++++++++++ routers/api/v1/repo/release.go | 11 ++++++++--- routers/api/v1/repo/release_tags.go | 6 +++--- routers/api/v1/repo/tag.go | 8 ++++++-- templates/swagger/v1_json.tmpl | 17 +++++++++++++---- tests/integration/api_releases_test.go | 25 +++++++++++++++++++++++++ tests/integration/repo_tag_test.go | 21 ++++----------------- 7 files changed, 83 insertions(+), 29 deletions(-) create mode 100644 models/fixtures/protected_tag.yml diff --git a/models/fixtures/protected_tag.yml b/models/fixtures/protected_tag.yml new file mode 100644 index 0000000000..dbec52c0c2 --- /dev/null +++ b/models/fixtures/protected_tag.yml @@ -0,0 +1,24 @@ +- + id: 1 + repo_id: 4 + name_pattern: /v.+/ + allowlist_user_i_ds: [] + allowlist_team_i_ds: [] + created_unix: 1715596037 + updated_unix: 1715596037 +- + id: 2 + repo_id: 1 + name_pattern: v-* + allowlist_user_i_ds: [] + allowlist_team_i_ds: [] + created_unix: 1715596037 + updated_unix: 1715596037 +- + id: 3 + repo_id: 1 + name_pattern: v-1.1 + allowlist_user_i_ds: [2] + allowlist_team_i_ds: [] + created_unix: 1715596037 + updated_unix: 1715596037 diff --git a/routers/api/v1/repo/release.go b/routers/api/v1/repo/release.go index f0f3c0bbc7..f92fb86f5c 100644 --- a/routers/api/v1/repo/release.go +++ b/routers/api/v1/repo/release.go @@ -215,6 +215,9 @@ func CreateRelease(ctx *context.APIContext) { // "$ref": "#/responses/notFound" // "409": // "$ref": "#/responses/error" + // "422": + // "$ref": "#/responses/validationError" + form := web.GetForm(ctx).(*api.CreateReleaseOption) if ctx.Repo.Repository.IsEmpty { ctx.Error(http.StatusUnprocessableEntity, "RepoIsEmpty", fmt.Errorf("repo is empty")) @@ -246,6 +249,8 @@ func CreateRelease(ctx *context.APIContext) { if err := release_service.CreateRelease(ctx.Repo.GitRepo, rel, nil, ""); err != nil { if repo_model.IsErrReleaseAlreadyExist(err) { ctx.Error(http.StatusConflict, "ReleaseAlreadyExist", err) + } else if models.IsErrProtectedTagName(err) { + ctx.Error(http.StatusUnprocessableEntity, "ProtectedTagName", err) } else { ctx.Error(http.StatusInternalServerError, "CreateRelease", err) } @@ -386,8 +391,8 @@ func DeleteRelease(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "404": // "$ref": "#/responses/notFound" - // "405": - // "$ref": "#/responses/empty" + // "422": + // "$ref": "#/responses/validationError" id := ctx.ParamsInt64(":id") rel, err := repo_model.GetReleaseForRepoByID(ctx, ctx.Repo.Repository.ID, id) @@ -401,7 +406,7 @@ func DeleteRelease(ctx *context.APIContext) { } if err := release_service.DeleteReleaseByID(ctx, ctx.Repo.Repository, rel, ctx.Doer, false); err != nil { if models.IsErrProtectedTagName(err) { - ctx.Error(http.StatusMethodNotAllowed, "delTag", "user not allowed to delete protected tag") + ctx.Error(http.StatusUnprocessableEntity, "delTag", "user not allowed to delete protected tag") return } ctx.Error(http.StatusInternalServerError, "DeleteReleaseByID", err) diff --git a/routers/api/v1/repo/release_tags.go b/routers/api/v1/repo/release_tags.go index fec91164a2..f845fad53b 100644 --- a/routers/api/v1/repo/release_tags.go +++ b/routers/api/v1/repo/release_tags.go @@ -92,8 +92,8 @@ func DeleteReleaseByTag(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "404": // "$ref": "#/responses/notFound" - // "405": - // "$ref": "#/responses/empty" + // "422": + // "$ref": "#/responses/validationError" tag := ctx.Params(":tag") @@ -114,7 +114,7 @@ func DeleteReleaseByTag(ctx *context.APIContext) { if err = releaseservice.DeleteReleaseByID(ctx, ctx.Repo.Repository, release, ctx.Doer, false); err != nil { if models.IsErrProtectedTagName(err) { - ctx.Error(http.StatusMethodNotAllowed, "delTag", "user not allowed to delete protected tag") + ctx.Error(http.StatusUnprocessableEntity, "delTag", "user not allowed to delete protected tag") return } ctx.Error(http.StatusInternalServerError, "DeleteReleaseByID", err) diff --git a/routers/api/v1/repo/tag.go b/routers/api/v1/repo/tag.go index a6908f3615..8577a0e896 100644 --- a/routers/api/v1/repo/tag.go +++ b/routers/api/v1/repo/tag.go @@ -184,6 +184,8 @@ func CreateTag(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "409": // "$ref": "#/responses/conflict" + // "422": + // "$ref": "#/responses/validationError" // "423": // "$ref": "#/responses/repoArchivedError" form := web.GetForm(ctx).(*api.CreateTagOption) @@ -205,7 +207,7 @@ func CreateTag(ctx *context.APIContext) { return } if models.IsErrProtectedTagName(err) { - ctx.Error(http.StatusMethodNotAllowed, "CreateNewTag", "user not allowed to create protected tag") + ctx.Error(http.StatusUnprocessableEntity, "CreateNewTag", "user not allowed to create protected tag") return } @@ -253,6 +255,8 @@ func DeleteTag(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "409": // "$ref": "#/responses/conflict" + // "422": + // "$ref": "#/responses/validationError" // "423": // "$ref": "#/responses/repoArchivedError" tagName := ctx.Params("*") @@ -274,7 +278,7 @@ func DeleteTag(ctx *context.APIContext) { if err = releaseservice.DeleteReleaseByID(ctx, ctx.Repo.Repository, tag, ctx.Doer, true); err != nil { if models.IsErrProtectedTagName(err) { - ctx.Error(http.StatusMethodNotAllowed, "delTag", "user not allowed to delete protected tag") + ctx.Error(http.StatusUnprocessableEntity, "delTag", "user not allowed to delete protected tag") return } ctx.Error(http.StatusInternalServerError, "DeleteReleaseByID", err) diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index b1255f1289..9ad0aa2ab6 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -12831,6 +12831,9 @@ }, "409": { "$ref": "#/responses/error" + }, + "422": { + "$ref": "#/responses/validationError" } } } @@ -12949,8 +12952,8 @@ "404": { "$ref": "#/responses/notFound" }, - "405": { - "$ref": "#/responses/empty" + "422": { + "$ref": "#/responses/validationError" } } } @@ -13035,8 +13038,8 @@ "404": { "$ref": "#/responses/notFound" }, - "405": { - "$ref": "#/responses/empty" + "422": { + "$ref": "#/responses/validationError" } } }, @@ -13886,6 +13889,9 @@ "409": { "$ref": "#/responses/conflict" }, + "422": { + "$ref": "#/responses/validationError" + }, "423": { "$ref": "#/responses/repoArchivedError" } @@ -13979,6 +13985,9 @@ "409": { "$ref": "#/responses/conflict" }, + "422": { + "$ref": "#/responses/validationError" + }, "423": { "$ref": "#/responses/repoArchivedError" } diff --git a/tests/integration/api_releases_test.go b/tests/integration/api_releases_test.go index 73b371b2cb..0b336a90e2 100644 --- a/tests/integration/api_releases_test.go +++ b/tests/integration/api_releases_test.go @@ -154,6 +154,31 @@ func TestAPICreateAndUpdateRelease(t *testing.T) { assert.EqualValues(t, rel.Note, newRelease.Note) } +func TestAPICreateProtectedTagRelease(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) + writer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) + session := loginUser(t, writer.LowerName) + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) + + gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo) + assert.NoError(t, err) + defer gitRepo.Close() + + commit, err := gitRepo.GetBranchCommit("master") + assert.NoError(t, err) + + req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/releases", repo.OwnerName, repo.Name), &api.CreateReleaseOption{ + TagName: "v0.0.1", + Title: "v0.0.1", + IsDraft: false, + IsPrerelease: false, + Target: commit.ID.String(), + }).AddTokenAuth(token) + MakeRequest(t, req, http.StatusUnprocessableEntity) +} + func TestAPICreateReleaseToDefaultBranch(t *testing.T) { defer tests.PrepareTestEnv(t)() diff --git a/tests/integration/repo_tag_test.go b/tests/integration/repo_tag_test.go index 7e77906473..6d3d85532c 100644 --- a/tests/integration/repo_tag_test.go +++ b/tests/integration/repo_tag_test.go @@ -26,22 +26,10 @@ func TestCreateNewTagProtected(t *testing.T) { repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) - t.Run("API", func(t *testing.T) { + t.Run("Code", func(t *testing.T) { defer tests.PrintCurrentTest(t)() - err := release.CreateNewTag(git.DefaultContext, owner, repo, "master", "v-1", "first tag") - assert.NoError(t, err) - - err = git_model.InsertProtectedTag(db.DefaultContext, &git_model.ProtectedTag{ - RepoID: repo.ID, - NamePattern: "v-*", - }) - assert.NoError(t, err) - err = git_model.InsertProtectedTag(db.DefaultContext, &git_model.ProtectedTag{ - RepoID: repo.ID, - NamePattern: "v-1.1", - AllowlistUserIDs: []int64{repo.OwnerID}, - }) + err := release.CreateNewTag(git.DefaultContext, owner, repo, "master", "t-first", "first tag") assert.NoError(t, err) err = release.CreateNewTag(git.DefaultContext, owner, repo, "master", "v-2", "second tag") @@ -54,13 +42,12 @@ func TestCreateNewTagProtected(t *testing.T) { t.Run("Git", func(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { - username := "user2" - httpContext := NewAPITestContext(t, username, "repo1") + httpContext := NewAPITestContext(t, owner.Name, repo.Name) dstPath := t.TempDir() u.Path = httpContext.GitPath() - u.User = url.UserPassword(username, userPassword) + u.User = url.UserPassword(owner.Name, userPassword) doGitClone(dstPath, u)(t) From f4f4e18b14c3d772e9183e8f1d2b2df45712c496 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Tue, 14 May 2024 21:47:03 +0800 Subject: [PATCH 314/370] Filter out duplicate action(activity) items for a repository (#30957) Fix #20986 --- models/activities/action.go | 11 ++++++++++- models/activities/action_test.go | 21 +++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/models/activities/action.go b/models/activities/action.go index 7e2ef4c9ae..d23f2bd986 100644 --- a/models/activities/action.go +++ b/models/activities/action.go @@ -524,7 +524,12 @@ func activityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder. } if opts.RequestedRepo != nil { - cond = cond.And(builder.Eq{"repo_id": opts.RequestedRepo.ID}) + // repo's actions could have duplicate items, see the comment of NotifyWatchers + // so here we only filter the "original items", aka: user_id == act_user_id + cond = cond.And( + builder.Eq{"`action`.repo_id": opts.RequestedRepo.ID}, + builder.Expr("`action`.user_id = `action`.act_user_id"), + ) } if opts.RequestedTeam != nil { @@ -577,6 +582,10 @@ func DeleteOldActions(ctx context.Context, olderThan time.Duration) (err error) } // NotifyWatchers creates batch of actions for every watcher. +// It could insert duplicate actions for a repository action, like this: +// * Original action: UserID=1 (the real actor), ActUserID=1 +// * Organization action: UserID=100 (the repo's org), ActUserID=1 +// * Watcher action: UserID=20 (a user who is watching a repo), ActUserID=1 func NotifyWatchers(ctx context.Context, actions ...*Action) error { var watchers []*repo_model.Watch var repo *repo_model.Repository diff --git a/models/activities/action_test.go b/models/activities/action_test.go index 5467bd35fb..557415dcda 100644 --- a/models/activities/action_test.go +++ b/models/activities/action_test.go @@ -318,3 +318,24 @@ func TestDeleteIssueActions(t *testing.T) { assert.NoError(t, activities_model.DeleteIssueActions(db.DefaultContext, issue.RepoID, issue.ID, issue.Index)) unittest.AssertCount(t, &activities_model.Action{}, 0) } + +func TestRepoActions(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + _ = db.TruncateBeans(db.DefaultContext, &activities_model.Action{}) + for i := 0; i < 3; i++ { + _ = db.Insert(db.DefaultContext, &activities_model.Action{ + UserID: 2 + int64(i), + ActUserID: 2, + RepoID: repo.ID, + OpType: activities_model.ActionCommentIssue, + }) + } + count, _ := db.Count[activities_model.Action](db.DefaultContext, &db.ListOptions{}) + assert.EqualValues(t, 3, count) + actions, _, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{ + RequestedRepo: repo, + }) + assert.NoError(t, err) + assert.Len(t, actions, 1) +} From effb405cae88474c27f5c8322a2627019af1cf64 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Tue, 14 May 2024 22:21:38 +0800 Subject: [PATCH 315/370] Always load or generate oauth2 jwt secret (#30942) Fix #30923 --- modules/setting/oauth2.go | 17 ++++++----------- modules/setting/oauth2_test.go | 28 +++++++++++++++++++++++++++- routers/install/install.go | 11 +++++++++++ 3 files changed, 44 insertions(+), 12 deletions(-) diff --git a/modules/setting/oauth2.go b/modules/setting/oauth2.go index e59f54420b..0d3e63e0b4 100644 --- a/modules/setting/oauth2.go +++ b/modules/setting/oauth2.go @@ -126,16 +126,15 @@ func loadOAuth2From(rootCfg ConfigProvider) { OAuth2.Enabled = sec.Key("ENABLE").MustBool(OAuth2.Enabled) } - if !OAuth2.Enabled { - return - } - - jwtSecretBase64 := loadSecret(sec, "JWT_SECRET_URI", "JWT_SECRET") - if !filepath.IsAbs(OAuth2.JWTSigningPrivateKeyFile) { OAuth2.JWTSigningPrivateKeyFile = filepath.Join(AppDataPath, OAuth2.JWTSigningPrivateKeyFile) } + // FIXME: at the moment, no matter oauth2 is enabled or not, it must generate a "oauth2 JWT_SECRET" + // Because this secret is also used as GeneralTokenSigningSecret (as a quick not-that-breaking fix for some legacy problems). + // Including: CSRF token, account validation token, etc ... + // In main branch, the signing token should be refactored (eg: one unique for LFS/OAuth2/etc ...) + jwtSecretBase64 := loadSecret(sec, "JWT_SECRET_URI", "JWT_SECRET") if InstallLock { jwtSecretBytes, err := generate.DecodeJwtSecretBase64(jwtSecretBase64) if err != nil { @@ -157,8 +156,6 @@ func loadOAuth2From(rootCfg ConfigProvider) { } } -// generalSigningSecret is used as container for a []byte value -// instead of an additional mutex, we use CompareAndSwap func to change the value thread save var generalSigningSecret atomic.Pointer[[]byte] func GetGeneralTokenSigningSecret() []byte { @@ -166,11 +163,9 @@ func GetGeneralTokenSigningSecret() []byte { if old == nil || len(*old) == 0 { jwtSecret, _, err := generate.NewJwtSecretWithBase64() if err != nil { - log.Fatal("Unable to generate general JWT secret: %s", err.Error()) + log.Fatal("Unable to generate general JWT secret: %v", err) } if generalSigningSecret.CompareAndSwap(old, &jwtSecret) { - // FIXME: in main branch, the signing token should be refactored (eg: one unique for LFS/OAuth2/etc ...) - LogStartupProblem(1, log.WARN, "OAuth2 is not enabled, unable to use a persistent signing secret, a new one is generated, which is not persistent between restarts and cluster nodes") return jwtSecret } return *generalSigningSecret.Load() diff --git a/modules/setting/oauth2_test.go b/modules/setting/oauth2_test.go index 4403f35892..38ee4d248d 100644 --- a/modules/setting/oauth2_test.go +++ b/modules/setting/oauth2_test.go @@ -4,6 +4,7 @@ package setting import ( + "os" "testing" "code.gitea.io/gitea/modules/generate" @@ -14,7 +15,7 @@ import ( func TestGetGeneralSigningSecret(t *testing.T) { // when there is no general signing secret, it should be generated, and keep the same value - assert.Nil(t, generalSigningSecret.Load()) + generalSigningSecret.Store(nil) s1 := GetGeneralTokenSigningSecret() assert.NotNil(t, s1) s2 := GetGeneralTokenSigningSecret() @@ -33,6 +34,31 @@ JWT_SECRET = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB assert.EqualValues(t, expected, actual) } +func TestGetGeneralSigningSecretSave(t *testing.T) { + defer test.MockVariableValue(&InstallLock, true)() + + old := GetGeneralTokenSigningSecret() + assert.Len(t, old, 32) + + tmpFile := t.TempDir() + "/app.ini" + _ = os.WriteFile(tmpFile, nil, 0o644) + cfg, _ := NewConfigProviderFromFile(tmpFile) + loadOAuth2From(cfg) + generated := GetGeneralTokenSigningSecret() + assert.Len(t, generated, 32) + assert.NotEqual(t, old, generated) + + generalSigningSecret.Store(nil) + cfg, _ = NewConfigProviderFromFile(tmpFile) + loadOAuth2From(cfg) + again := GetGeneralTokenSigningSecret() + assert.Equal(t, generated, again) + + iniContent, err := os.ReadFile(tmpFile) + assert.NoError(t, err) + assert.Contains(t, string(iniContent), "JWT_SECRET = ") +} + func TestOauth2DefaultApplications(t *testing.T) { cfg, _ := NewConfigProviderFromData(``) loadOAuth2From(cfg) diff --git a/routers/install/install.go b/routers/install/install.go index 9c6a8849b6..fde8b37ed5 100644 --- a/routers/install/install.go +++ b/routers/install/install.go @@ -481,6 +481,17 @@ func SubmitInstall(ctx *context.Context) { cfg.Section("security").Key("INTERNAL_TOKEN").SetValue(internalToken) } + // FIXME: at the moment, no matter oauth2 is enabled or not, it must generate a "oauth2 JWT_SECRET" + // see the "loadOAuth2From" in "setting/oauth2.go" + if !cfg.Section("oauth2").HasKey("JWT_SECRET") && !cfg.Section("oauth2").HasKey("JWT_SECRET_URI") { + _, jwtSecretBase64, err := generate.NewJwtSecretWithBase64() + if err != nil { + ctx.RenderWithErr(ctx.Tr("install.secret_key_failed", err), tplInstall, &form) + return + } + cfg.Section("oauth2").Key("JWT_SECRET").SetValue(jwtSecretBase64) + } + // if there is already a SECRET_KEY, we should not overwrite it, otherwise the encrypted data will not be able to be decrypted if setting.SecretKey == "" { var secretKey string From 5b6f80989fbd0574ca188ab683389ff7659de30d Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Wed, 15 May 2024 07:06:12 +0800 Subject: [PATCH 316/370] Remove unnecessary double quotes on language file (#30977) The double quotes and the prefix/suffix space are unnecessary. Co-authored-by: KN4CK3R <admin@oldschoolhack.me> --- options/locale/locale_en-US.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 6a08041a7c..a85b107eee 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -3348,7 +3348,7 @@ mirror_sync_create = synced new reference <a href="%[2]s">%[3]s</a> to <a href=" mirror_sync_delete = synced and deleted reference <code>%[2]s</code> at <a href="%[1]s">%[3]s</a> from mirror approve_pull_request = `approved <a href="%[1]s">%[3]s#%[2]s</a>` reject_pull_request = `suggested changes for <a href="%[1]s">%[3]s#%[2]s</a>` -publish_release = `released <a href="%[2]s"> "%[4]s" </a> at <a href="%[1]s">%[3]s</a>` +publish_release = `released <a href="%[2]s">%[4]s</a> at <a href="%[1]s">%[3]s</a>` review_dismissed = `dismissed review from <b>%[4]s</b> for <a href="%[1]s">%[3]s#%[2]s</a>` review_dismissed_reason = Reason: create_branch = created branch <a href="%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a> From db578431ea5e8dc7347ba3dc10e82a01c5ba3ace Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Wed, 15 May 2024 00:25:44 +0000 Subject: [PATCH 317/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_cs-CZ.ini | 1 - options/locale/locale_de-DE.ini | 1 - options/locale/locale_el-GR.ini | 1 - options/locale/locale_es-ES.ini | 1 - options/locale/locale_fa-IR.ini | 1 - options/locale/locale_fr-FR.ini | 1 - options/locale/locale_it-IT.ini | 1 - options/locale/locale_ja-JP.ini | 1 - options/locale/locale_lv-LV.ini | 114 ++++++++++++++++---------------- options/locale/locale_pt-BR.ini | 1 - options/locale/locale_pt-PT.ini | 1 - options/locale/locale_ru-RU.ini | 1 - options/locale/locale_si-LK.ini | 1 - options/locale/locale_tr-TR.ini | 1 - options/locale/locale_uk-UA.ini | 1 - options/locale/locale_zh-CN.ini | 1 - options/locale/locale_zh-TW.ini | 1 - 17 files changed, 57 insertions(+), 73 deletions(-) diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index 82d7867168..6314b62f66 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -3320,7 +3320,6 @@ mirror_sync_create=synchronizoval/a novou referenci <a href="%[2]s">%[3]s</a> do mirror_sync_delete=synchronizoval/a a smazal/a referenci <code>%[2]s</code> v <a href="%[1]s">%[3]s</a> ze zrcadla approve_pull_request=`schválil/a <a href="%[1]s">%[3]s#%[2]s</a>` reject_pull_request=`navrhl/a změny pro <a href="%[1]s">%[3]s#%[2]s</a>` -publish_release=`vydal/a <a href="%[2]s"> "%[4]s" </a> v <a href="%[1]s">%[3]s</a>` review_dismissed=`zamítl/a posouzení z <b>%[4]s</b> pro <a href="%[1]s">%[3]s#%[2]s</a>` review_dismissed_reason=Důvod: create_branch=vytvořil/a větev <a href="%[2]s">%[3]s</a> v <a href="%[1]s">%[4]s</a> diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index dd2b34a6f4..5bca84ca08 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -3329,7 +3329,6 @@ mirror_sync_create=neue Referenz <a href="%[2]s">%[3]s</a> bei <a href="%[1]s">% mirror_sync_delete=hat die Referenz des Mirrors <code>%[2]s</code> in <a href="%[1]s">%[3]s</a> synchronisiert und gelöscht approve_pull_request=`hat <a href="%[1]s">%[3]s#%[2]s</a> approved` reject_pull_request=`schlug Änderungen für <a href="%[1]s">%[3]s#%[2]s</a> vor` -publish_release=`veröffentlichte Release <a href="%[2]s"> "%[4]s" </a> in <a href="%[1]s">%[3]s</a>` review_dismissed=`verwarf das Review von <b>%[4]s</b> in <a href="%[1]s">%[3]s#%[2]s</a>` review_dismissed_reason=Grund: create_branch=legte den Branch <a href="%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a> an diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini index 9553ba2f3a..834d1d7d70 100644 --- a/options/locale/locale_el-GR.ini +++ b/options/locale/locale_el-GR.ini @@ -3210,7 +3210,6 @@ mirror_sync_create=συγχρονίστηκε η νέα αναφορά <a href=" mirror_sync_delete=συγχρόνισε και διάγραψε την αναφορά <code>%[2]s</code> σε <a href="%[1]s">%[3]s</a> από το είδωλο approve_pull_request=`ενέκρινε το <a href="%[1]s">%[3]s#%[2]s</a>` reject_pull_request=`πρότεινε αλλαγές για το <a href="%[1]s">%[3]s#%[2]s</a>` -publish_release=`έκδωσε τη <a href="%[2]s"> "%[4]s" </a> στο <a href="%[1]s">%[3]s</a>` review_dismissed=`ακύρωσε την εξέταση από <b>%[4]s</b> for <a href="%[1]s">%[3]s#%[2]s</a>` review_dismissed_reason=Αιτία: create_branch=δημιούργησε το κλαδο <a href="%[2]s">%[3]s</a> στο <a href="%[1]s">%[4]s</a> diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index f3e2d93e80..3894e0e85b 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -3193,7 +3193,6 @@ mirror_sync_create=sincronizó la nueva referencia <a href="%[2]s">%[3]s</a> a < mirror_sync_delete=sincronizada y eliminada referencia <code>%[2]s</code> en <a href="%[1]s">%[3]s</a> desde réplica approve_pull_request=`aprobó <a href="%[1]s">%[3]s#%[2]s</a>` reject_pull_request=`sugirió cambios para <a href="%[1]s">%[3]s#%[2]s</a>` -publish_release=`se lanzó <a href="%[2]s"> "%[4]s" </a> en <a href="%[1]s">%[3]s</a>` review_dismissed=`descartó la revisión de <b>%[4]s</b> para <a href="%[1]s">%[3]s#%[2]s</a>` review_dismissed_reason=Motivo: create_branch=creó rama <a href="%[2]s">%[3]s</a> en <a href="%[1]s">%[4]s</a> diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini index 25a3361b3f..d720ecf2f8 100644 --- a/options/locale/locale_fa-IR.ini +++ b/options/locale/locale_fa-IR.ini @@ -2508,7 +2508,6 @@ mirror_sync_create=مرجع جدید <a href="%[2]s">%[3]s</a> با <a href="%[1 mirror_sync_delete=از مرجع <code>%[2]s</code> در<a href="%[1]s">%[3]s</a> حذف شده و از قرینه همگام شده approve_pull_request=`تأیید <a href="%[1]s">%[3]s#%[2]s</a>` reject_pull_request=`تغییرات پیشنهادی برای <a href="%[1]s">%[3]s#%[2]s</a>` -publish_release=`<a href="%[2]s"> "%[4]s" </a> در <a href="%[1]s">%[3]s</a> منتشر شد` review_dismissed=`بازبینی از <b>%[4]s</b> برای <a href="%[1]s">%[3]s#%[2]s</a> رد شد` review_dismissed_reason=دلیل: create_branch=شاخه <a href="%[2]s">%[3]s</a> در <a href="%[1]s">%[4]s</a> ایجاد کرد diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index b90039c003..556fab28e8 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -3249,7 +3249,6 @@ mirror_sync_create=a synchronisé la nouvelle référence <a href="%[2]s">%[3]s< mirror_sync_delete=a synchronisé puis supprimé la nouvelle référence <code>%[2]s</code> vers <a href="%[1]s">%[3]s</a> depuis le miroir approve_pull_request=`a approuvé <a href="%[1]s">%[3]s#%[2]s</a>` reject_pull_request=`a suggérés des changements pour <a href="%[1]s">%[3]s#%[2]s</a>` -publish_release=`a publié <a href="%[2]s"> "%[4]s" </a> dans <a href="%[1]s">%[3]s</a>` review_dismissed=`a révoqué l’évaluation de <b>%[4]s</b> dans <a href="%[1]s">%[3]s#%[2]s</a>` review_dismissed_reason=Raison : create_branch=a créé la branche <a href="%[2]s">%[3]s</a> dans <a href="%[1]s">%[4]s</a> diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index eceda0faad..0cecc0b7f3 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -2707,7 +2707,6 @@ mirror_sync_create=ha sincronizzato un nuovo riferimento <a href="%[2]s">%[3]s</ mirror_sync_delete=riferimento sincronizzato ed eliminato <code>%[2]s</code> a <a href="%[1]s">%[3]s</a> dal mirror approve_pull_request=`ha approvato <a href="%[1]s">%[3]s#%[2]s</a>` reject_pull_request=`ha suggerito modifiche per <a href="%[1]s">%[3]s#%[2]s</a>` -publish_release=`ha rilasciato <a href="%[2]s"> "%[4]s" </a> su <a href="%[1]s">%[3]s</a>` review_dismissed=`respinta la recensione da <b>%[4]s</b> per <a href="%[1]s">%[3]s#%[2]s</a>` review_dismissed_reason=Motivo: create_branch=ha creato il ramo <a href="%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a> diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 03a06dab16..cf9d9bbc51 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -3344,7 +3344,6 @@ mirror_sync_create=が <a href="%[1]s">%[4]s</a> の新しい参照 <a href="%[2 mirror_sync_delete=が <a href="%[1]s">%[3]s</a> の参照 <code>%[2]s</code> をミラーから反映し、削除しました approve_pull_request=`が <a href="%[1]s">%[3]s#%[2]s</a> を承認しました` reject_pull_request=`が <a href="%[1]s">%[3]s#%[2]s</a>について変更を提案しました` -publish_release=`が <a href="%[1]s">%[3]s</a> の <a href="%[2]s"> "%[4]s" </a> をリリースしました` review_dismissed=`が <b>%[4]s</b> の <a href="%[1]s">%[3]s#%[2]s</a> へのレビューを棄却しました` review_dismissed_reason=理由: create_branch=がブランチ <a href="%[2]s">%[3]s</a> を <a href="%[1]s">%[4]s</a> に作成しました diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 3aed4bd6c5..bdfe3f8c9f 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -111,7 +111,7 @@ preview=Priekšskatītījums loading=Notiek ielāde… error=Kļūda -error404=Lapa, ko vēlaties atvērt, <strong>neeksistē</strong> vai arī <strong>Jums nav tiesības</strong> to aplūkot. +error404=Lapa, ko tiek mēģināts atvērt, vai nu <strong>nepastāv</strong> vai arī <strong>nav tiesību</strong> to aplūkot. go_back=Atgriezties never=Nekad @@ -133,10 +133,10 @@ concept_user_organization=Organizācija show_timestamps=Rādīt laika zīmogus show_log_seconds=Rādīt sekundes -show_full_screen=Atvērt pilnā logā +show_full_screen=Rādīt pilnekrānā download_logs=Lejupielādēt žurnālus -confirm_delete_selected=Apstiprināt, lai izdzēstu visus atlasītos vienumus? +confirm_delete_selected=Apstiprināt visu atlasīto vienumus dzēšanu? name=Nosaukums value=Vērtība @@ -651,10 +651,11 @@ cancel=Atcelt language=Valoda ui=Motīvs hidden_comment_types=Attēlojot paslēpt šauds komentārus: +hidden_comment_types_description=Komentāru veidi, kas atzīmēti, netiks rādīti problēmu lapā. Piemēram, atzīmējot "Iezīmes" netiks rādīti komentāri "{lietotājs} pievienoja/noņēma {iezīme} iezīmi". hidden_comment_types.ref_tooltip=Komentāri, kad problēmai tiek pievienota atsauce uz citu probēmu, komentāru, … hidden_comment_types.issue_ref_tooltip=Komentāri par lietotāja izmaiņām ar problēmas saistīto atzaru/tagu comment_type_group_reference=Atsauces -comment_type_group_label=Etiķetes +comment_type_group_label=Iezīmes comment_type_group_milestone=Atskaites punktus comment_type_group_assignee=Atbildīgos comment_type_group_title=Nosaukuma izmaiņas @@ -956,8 +957,8 @@ repo_desc_helper=Ievadiet īsu aprakstu (neobligāts) repo_lang=Valoda repo_gitignore_helper=Izvēlieties .gitignore sagatavi. repo_gitignore_helper_desc=Izvēlieties kādi faili netiks glabāti repozitorijā no sagatavēm biežāk lietotājām valodām. Pēc noklusējuma .gitignore iekļauj valodu kompilācijas rīku artifaktus. -issue_labels=Problēmu etiķetes -issue_labels_helper=Izvēlieties problēmu etiķešu kopu. +issue_labels=Problēmu iezīmes +issue_labels_helper=Izvēlieties problēmu iezīmju kopu. license=Licence license_helper=Izvēlieties licences failu. license_helper_desc=Licence nosaka, ko citi var un ko nevar darīt ar šo kodu. Neesat pārliecintāts, kādu izvēlēties šim projektam? Aplūkojiet <a target="_blank" rel="noopener noreferrer" href="%s">licences izvēle</a>. @@ -1030,15 +1031,15 @@ desc.internal=Iekšējs desc.archived=Arhivēts desc.sha256=SHA256 -template.items=Sagataves ieraksti +template.items=Sagataves vienumi template.git_content=Git saturs (noklusētais atzars) template.git_hooks=Git āķi template.git_hooks_tooltip=Pēc repozitorija izveidošanas, Jums nav tiesību mainīt Git āķus. Atzīmējiet šo tikai, ja uzticaties sagataves repozitorija saturam. template.webhooks=Tīmekļa āķi template.topics=Tēmas template.avatar=Profila attēls -template.issue_labels=Problēmu etiķetes -template.one_item=Norādiet vismaz vienu sagataves vienību +template.issue_labels=Problēmu iezīmes +template.one_item=Norādiet vismaz vienu sagataves vienumu template.invalid=Norādiet sagataves repozitoriju archive.title=Šis repozitorijs ir arhivēts. Ir iespējams aplūkot tā failus un to konēt, bet nav iespējams iesūtīt izmaiņas, kā arī izveidot jaunas problēmas vai izmaiņu pieprasījumus. @@ -1060,10 +1061,10 @@ migrate_options_lfs_endpoint.label=LFS galapunkts migrate_options_lfs_endpoint.description=Migrācija mēģinās izmantot attālināto URL, lai <a target="_blank" rel="noopener noreferrer" href="%s">noteiktu LFS serveri</a>. Var norādīt arī citu galapunktu, ja repozitorija LFS dati ir izvietoti citā vietā. migrate_options_lfs_endpoint.description.local=Iespējams norādīt arī servera ceļu. migrate_options_lfs_endpoint.placeholder=Ja nav norādīts, galamērķis tiks atvasināts no klonēšanas URL -migrate_items=Vienības, ko pārņemt +migrate_items=Vienumi, ko pārņemt migrate_items_wiki=Vikivietni migrate_items_milestones=Atskaites punktus -migrate_items_labels=Etiķetes +migrate_items_labels=Iezīmes migrate_items_issues=Problēmas migrate_items_pullrequests=Izmaiņu pieprasījumus migrate_items_merge_requests=Sapludināšanas pieprasījumi @@ -1078,7 +1079,7 @@ migrate.permission_denied_blocked=Nav iespējams importēt no neatļautām adres migrate.invalid_local_path=Nederīgs lokālais ceļš. Tas neeksistē vai nav direktorija. migrate.invalid_lfs_endpoint=LFS galapunkts nav korekts. migrate.failed=Migrācija neizdevās: %v -migrate.migrate_items_options=Piekļuves pilnvara ir nepieciešams, lai migrētu papildus datus +migrate.migrate_items_options=Piekļuves pilnvara ir nepieciešama, lai pārņemtu papildus datus migrated_from=Migrēts no <a href="%[1]s">%[2]s</a> migrated_from_fake=Migrēts no %[1]s migrate.migrate=Migrēt no %s @@ -1097,7 +1098,7 @@ migrate.gitbucket.description=Migrēt datus no GitBucket instancēm. migrate.migrating_git=Migrē git datus migrate.migrating_topics=Migrē tēmas migrate.migrating_milestones=Migrē atskaites punktus -migrate.migrating_labels=Migrē etiķetes +migrate.migrating_labels=Migrē iezīmes migrate.migrating_releases=Migrē laidienus migrate.migrating_issues=Migrācijas problēmas migrate.migrating_pulls=Migrē izmaiņu pieprasījumus @@ -1141,8 +1142,8 @@ pulls=Izmaiņu pieprasījumi project_board=Projekti packages=Pakotnes actions=Darbības -labels=Etiķetes -org_labels_desc=Organizācijas līmeņa etiķetes var tikt izmantotas <strong>visiem repozitorijiem</strong> šajā organizācijā +labels=Iezīmes +org_labels_desc=Organizācijas līmeņa iezīmes var tikt izmantotas <strong>visiem repozitorijiem</strong> šajā organizācijā org_labels_desc_manage=pārvaldīt milestones=Atskaites punkti @@ -1334,19 +1335,19 @@ issues.desc=Organizēt kļūdu ziņojumus, uzdevumus un atskaites punktus. issues.filter_assignees=Filtrēt pēc atbildīgajiem issues.filter_milestones=Filtrēt pēc atskaites punkta issues.filter_projects=Filtrēt pēc projekta -issues.filter_labels=Filtrēt pēc etiķetēm +issues.filter_labels=Filtrēt pēc iezīmēm issues.filter_reviewers=Filtrēt pēc recenzentiem issues.new=Jauna problēma issues.new.title_empty=Nosaukums nevar būt tukšs -issues.new.labels=Etiķetes -issues.new.no_label=Nav etiķešu -issues.new.clear_labels=Noņemt etiķetes +issues.new.labels=Iezīmes +issues.new.no_label=Nav iezīmju +issues.new.clear_labels=Noņemt iezīmes issues.new.projects=Projekti issues.new.clear_projects=Notīrīt projektus issues.new.no_projects=Nav projektu issues.new.open_projects=Aktīvie projekti issues.new.closed_projects=Pabeigtie projekti -issues.new.no_items=Nav neviena ieraksta +issues.new.no_items=Nav vienumu issues.new.milestone=Atskaites punkts issues.new.no_milestone=Nav atskaites punktu issues.new.clear_milestone=Notīrīt atskaites punktus @@ -1365,20 +1366,20 @@ issues.choose.invalid_templates=%v ķļūdaina sagatave(s) atrastas issues.choose.invalid_config=Problēmu konfigurācija satur kļūdas: issues.no_ref=Nav norādīts atzars/tags issues.create=Pieteikt problēmu -issues.new_label=Jauna etiķete -issues.new_label_placeholder=Etiķetes nosaukums +issues.new_label=Jauna iezīme +issues.new_label_placeholder=Iezīmes nosaukums issues.new_label_desc_placeholder=Apraksts -issues.create_label=Izveidot etiķeti -issues.label_templates.title=Ielādēt sākotnēji noteiktu etiķešu kopu -issues.label_templates.info=Nav izveidota neviena etiķete. Jūs varat noklikšķināt uz "Jauna etiķete" augstāk, lai to izveidotu vai izmantot zemāk piedāvātās etiķetes: -issues.label_templates.helper=Izvēlieties etiķešu kopu -issues.label_templates.use=Izmantot etiķešu kopu -issues.label_templates.fail_to_load_file=Neizdevās ielādēt etiķetes sagataves failu "%s": %v -issues.add_label=pievienoja %s etiķeti %s -issues.add_labels=pievienoja %s etiķetes %s -issues.remove_label=noņēma %s etiķeti %s -issues.remove_labels=noņēma %s etiķetes %s -issues.add_remove_labels=pievienoja %s un noņēma %s etiķetes %s +issues.create_label=Izveidot iezīmi +issues.label_templates.title=Ielādēt sākotnēji noteiktu iezīmju kopu +issues.label_templates.info=Nav izveidota neviena iezīme. Nospiediet uz pogas "Jauna iezīme", lai to izveidotu vai izmantojiet zemāk piedāvātās iezīmju kopas: +issues.label_templates.helper=Izvēlieties iezīmju kopu +issues.label_templates.use=Izmantot iezīmju kopu +issues.label_templates.fail_to_load_file=Neizdevās ielādēt iezīmju sagataves failu "%s": %v +issues.add_label=pievienoja %s iezīmi %s +issues.add_labels=pievienoja %s iezīmes %s +issues.remove_label=noņēma %s iezīmi %s +issues.remove_labels=noņēma %s iezīmes %s +issues.add_remove_labels=pievienoja %s un noņēma %s iezīmes %s issues.add_milestone_at=`pievienoja atskaites punktu <b>%s</b> %s` issues.add_project_at=`pievienoja šo problēmu <b>%s</b> projektam %s` issues.change_milestone_at=`nomainīja atskaites punktu no <b>%s</b> uz <b>%s</b> %s` @@ -1396,9 +1397,9 @@ issues.change_ref_at=`nomainīta atsauce no <b><strike>%s</strike></b> uz <b>%s< issues.remove_ref_at=`noņēma atsauci no <b>%s</b> %s` issues.add_ref_at=`pievienoja atsauci uz <b>%s</b> %s` issues.delete_branch_at=`izdzēsa atzaru <b>%s</b> %s` -issues.filter_label=Etiķete -issues.filter_label_exclude=`Izmantojiet <code>alt</code> + <code>peles klikšķis vai enter</code>, lai neiekļautu etiķeti` -issues.filter_label_no_select=Visas etiķetes +issues.filter_label=Iezīme +issues.filter_label_exclude=`Izmantojiet <code>alt</code> + <code>peles klikšķis vai enter</code>, lai neiekļautu iezīmes` +issues.filter_label_no_select=Visas iezīmes issues.filter_label_select_no_label=Nav etiķetes issues.filter_milestone=Atskaites punkts issues.filter_milestone_all=Visi atskaites punkti @@ -1435,13 +1436,13 @@ issues.filter_sort.mostforks=Visvairāk atdalītie issues.filter_sort.fewestforks=Vismazāk atdalītie issues.action_open=Atvērt issues.action_close=Aizvērt -issues.action_label=Etiķete +issues.action_label=Iezīme issues.action_milestone=Atskaites punkts issues.action_milestone_no_select=Nav atskaites punkta issues.action_assignee=Atbildīgais issues.action_assignee_no_select=Nav atbildīgā issues.action_check=Atzīmēt/Notīrīt -issues.action_check_all=Atzīmēt/Notīrīt visus ierakstus +issues.action_check_all=Atzīmēt/notīrīt visus vienumus issues.opened_by=<a href="%[2]s">%[3]s</a> atvēra %[1]s pulls.merged_by=<a href="%[2]s">%[3]s</a> sapludināja %[1]s pulls.merged_by_fake=%[2]s sapludināja %[1]s @@ -1502,23 +1503,23 @@ issues.sign_in_require_desc=Nepieciešams <a href="%s">pieteikties</a>, lai piev issues.edit=Labot issues.cancel=Atcelt issues.save=Saglabāt -issues.label_title=Etiķetes nosaukums -issues.label_description=Etiķetes apraksts -issues.label_color=Etiķetes krāsa -issues.label_exclusive=Ekskluzīvs +issues.label_title=Nosaukums +issues.label_description=Apraksts +issues.label_color=Krāsa +issues.label_exclusive=Sevišķa issues.label_archive=Arhīvēt etiķeti issues.label_archived_filter=Rādīt arhivētās etiķetes issues.label_archive_tooltip=Arhivētās etiķetes pēc noklusējuma netiek iekļautas ieteikumos, kad meklē pēc nosaukuma. -issues.label_exclusive_desc=Nosauciet etiķeti <code>grupa/nosaukums</code>, lai grupētu etiķētes un varētu norādīt tās kā ekskluzīvas ar citām <code>grupa/</code> etiķetēm. -issues.label_exclusive_warning=Jebkura konfliktējoša ekskluzīvas grupas etiķete tiks noņemta, labojot pieteikumu vai izmaiņu pietikumu etiķetes. -issues.label_count=%d etiķetes +issues.label_exclusive_desc=Nosauciet iezīmi <code>grupa/nosaukums</code>, lai tās grupētu un varētu padarīt kā savstarpēji sevišķas ar citām <code>grupa/</code> iezīmēm. +issues.label_exclusive_warning=Jebkura konfliktējoša savstarpēji sevišķas grupas iezīme tiks noņemta, labojot problēmas vai izmaiņu pietikuma iezīmes. +issues.label_count=%d iezīmes issues.label_open_issues=%d atvērtas problēmas issues.label_edit=Labot issues.label_delete=Dzēst -issues.label_modify=Labot etiķeti +issues.label_modify=Labot iezīmi issues.label_deletion=Dzēst etiķeti -issues.label_deletion_desc=Dzēšot etiķeti, tā tiks noņemta no visām problēmām un izmaiņu pieprasījumiem. Vai turpināt? -issues.label_deletion_success=Etiķete tika izdzēsta. +issues.label_deletion_desc=Dzēšot iezīmi, tā tiks noņemta no visām problēmām un izmaiņu pieprasījumiem. Vai turpināt? +issues.label_deletion_success=Iezīme tika izdzēsta. issues.label.filter_sort.alphabetically=Alfabētiski issues.label.filter_sort.reverse_alphabetically=Pretēji alfabētiski issues.label.filter_sort.by_size=Mazākais izmērs @@ -1676,7 +1677,7 @@ pulls.allow_edits_from_maintainers_err=Atjaunošana neizdevās pulls.compare_changes_desc=Izvēlieties atzaru, kurā sapludināt izmaiņas un atzaru, no kura tās saņemt. pulls.has_viewed_file=Skatīts pulls.has_changed_since_last_review=Mainīts kopš pēdējās recenzijas -pulls.viewed_files_label=%[1]d no %[2]d failiem apskatīts +pulls.viewed_files_label=apskatīts %[1]d no %[2]d failiem pulls.expand_files=Izvērst visus failus pulls.collapse_files=Savērst visus failus pulls.compare_base=pamata @@ -1886,7 +1887,7 @@ wiki.page_name_desc=Ievadiet vikivietnes lapas nosaukumu. Speciālie nosaukumi i wiki.original_git_entry_tooltip=Attēlot oriģinālo Git faila nosaukumu. activity=Aktivitāte -activity.period.filter_label=Laika periods: +activity.period.filter_label=Laika posms: activity.period.daily=1 diena activity.period.halfweekly=3 dienas activity.period.weekly=1 nedēļa @@ -2171,8 +2172,8 @@ settings.event_issues=Problēmas settings.event_issues_desc=Problēma atvērta, aizvērta, atkārtoti atvērta vai mainīta. settings.event_issue_assign=Problēmas atbildīgie settings.event_issue_assign_desc=Problēmai piešķirti vai noņemti atbildīgie. -settings.event_issue_label=Problēmu etiķetes -settings.event_issue_label_desc=Problēmai pievienotas vai noņemtas etiķetes. +settings.event_issue_label=Problēmu iezīmes +settings.event_issue_label_desc=Problēmai pievienotas vai noņemtas iezīmes. settings.event_issue_milestone=Problēmas atskaites punkts settings.event_issue_milestone_desc=Problēmai pievienots vai noņemts atskaites punkts. settings.event_issue_comment=Problēmas komentārs @@ -2182,8 +2183,8 @@ settings.event_pull_request=Izmaiņu pieprasījums settings.event_pull_request_desc=Izmaiņu pieprasījums atvērts, aizvērts, atkārtoti atvērts vai mainīts. settings.event_pull_request_assign=Izmaiņu pieprasījuma atbildīgie settings.event_pull_request_assign_desc=Izmaiņu pieprasījumam piešķirti vai noņemti atbildīgie. -settings.event_pull_request_label=Izmaiņu pieprasījuma etiķetes -settings.event_pull_request_label_desc=Izmaiņu pieprasījumam pievienotas vai noņemtas etiķetes. +settings.event_pull_request_label=Izmaiņu pieprasījuma iezīmes +settings.event_pull_request_label_desc=Izmaiņu pieprasījumam tika pievienotas vai noņemtas iezīmes. settings.event_pull_request_milestone=Izmaiņu pieprasījuma atskaites punkts settings.event_pull_request_milestone_desc=Izmaiņu pieprasījumam pievienots vai noņemts atskaites punkts. settings.event_pull_request_comment=Izmaiņu pieprasījuma komentārs @@ -2598,7 +2599,7 @@ settings.delete_org_title=Dzēst organizāciju settings.delete_org_desc=Organizācija tiks dzēsta neatgriezeniski. Vai turpināt? settings.hooks_desc=Pievienot tīmekļa āķus, kas nostrādās <strong>visiem repozitorijiem</strong> šajā organizācijā. -settings.labels_desc=Pievienojiet etiķetes, kas var tikt izmantotas <strong>visos</strong> šīs organizācijas repozitorijos. +settings.labels_desc=Pievienojiet iezīmes, kas var tikt izmantotas <strong>visos</strong> šīs organizācijas repozitorijos. members.membership_visibility=Dalībnieka redzamība: members.public=Redzams @@ -3217,7 +3218,6 @@ mirror_sync_create=ar spoguli sinhronizēta jauna atsauce <a href="%[2]s">%[3]s< mirror_sync_delete=ar spoguli sinhronizēta un izdzēsta atsauce <code>%[2]s</code> repozitorijam <a href="%[1]s">%[3]s</a> approve_pull_request=`apstiprināja izmaiņu pieprasījumu <a href="%[1]s">%[3]s#%[2]s</a>` reject_pull_request=`ieteica izmaiņas izmaiņu pieprasījumam <a href="%[1]s">%[3]s#%[2]s</a>` -publish_release=`izveidoja versiju <a href="%[2]s"> "%[4]s" </a> repozitorijā <a href="%[1]s">%[3]s</a>` review_dismissed=`noraidīja lietotāja <b>%[4]s</b> recenziju izmaiņu pieprasījumam <a href="%[1]s">%[3]s#%[2]s</a>` review_dismissed_reason=Iemesls: create_branch=izveidoja atzaru <a href="%[2]s">%[3]s</a> repozitorijā <a href="%[1]s">%[4]s</a> @@ -3337,7 +3337,7 @@ container.pull=Atgādājiet šo attēlu no komandrindas: container.digest=Īssavilkums: container.multi_arch=OS / arhitektūra container.layers=Attēla slāņi -container.labels=Etiķetes +container.labels=Iezīmes container.labels.key=Atslēga container.labels.value=Vērtība cran.registry=Iestaties šo reģistru savā <code>Rprofile.site</code> failā: diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 2e23cde801..4799727d98 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -3153,7 +3153,6 @@ mirror_sync_create=sincronizou a nova referência <a href="%[2]s">%[3]s</a> para mirror_sync_delete=referência excluída e sincronizada <code>%[2]s</code> em <a href="%[1]s">%[3]s</a> do espelhamento approve_pull_request=`aprovou <a href="%[1]s">%[3]s#%[2]s</a>` reject_pull_request=`sugeriu modificações para <a href="%[1]s">%[3]s#%[2]s</a>` -publish_release=`lançou a versão <a href="%[2]s"> "%[4]s" </a> em <a href="%[1]s">%[3]s</a>` review_dismissed=`descartou a revisão de <b>%[4]s</b> para <a href="%[1]s">%[3]s#%[2]s</a>` review_dismissed_reason=Motivo: create_branch=criou o branch <a href="%[2]s">%[3]s</a> em <a href="%[1]s">%[4]s</a> diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 642d8915cf..f4c77e4981 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -3348,7 +3348,6 @@ mirror_sync_create=sincronizou a nova referência <a href="%[2]s">%[3]s</a> para mirror_sync_delete=sincronizou e eliminou a referência <code>%[2]s</code> em <a href="%[1]s">%[3]s</a> da réplica approve_pull_request=`aprovou <a href="%[1]s">%[3]s#%[2]s</a>` reject_pull_request=`sugeriu modificações para <a href="%[1]s">%[3]s#%[2]s</a>` -publish_release=`lançou <a href="%[2]s"> "%[4]s" </a> em <a href="%[1]s">%[3]s</a>` review_dismissed=`descartou a revisão de <b>%[4]s</b> para <a href="%[1]s">%[3]s#%[2]s</a>` review_dismissed_reason=Motivo: create_branch=criou o ramo <a href="%[2]s">%[3]s</a> em <a href="%[1]s">%[4]s</a> diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index df6df4cf95..81b88dbd45 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -3147,7 +3147,6 @@ mirror_sync_create=синхронизировал(а) новую ссылку <a mirror_sync_delete=синхронизированные и удалённые ссылки <code>%[2]s</code> на <a href="%[1]s">%[3]s</a> из зеркала approve_pull_request=`утвердил(а) задачу <a href="%[1]s">%[3]s#%[2]s</a>` reject_pull_request=`предложил(а) изменения для <a href="%[1]s">%[3]s#%[2]s</a>` -publish_release=`выпустил(а) <a href="%[2]s"> "%[4]s" </a> в <a href="%[1]s">%[3]s</a>` review_dismissed=`отклонил(а) отзыв от <b>%[4]s</b> для <a href="%[1]s">%[3]s#%[2]s</a>` review_dismissed_reason=Причина: create_branch=создал(а) ветку <a href="%[2]s">%[3]s</a> в <a href="%[1]s">%[4]s</a> diff --git a/options/locale/locale_si-LK.ini b/options/locale/locale_si-LK.ini index 15bbcfebb2..cb437e5530 100644 --- a/options/locale/locale_si-LK.ini +++ b/options/locale/locale_si-LK.ini @@ -2465,7 +2465,6 @@ mirror_sync_create=සමමුහුර්ත නව යොමු <a href="%[2] mirror_sync_delete=සමමුහුර්ත සහ මකාදැමූ යොමු <code>%[2]s</code> හි <a href="%[1]s">%[3]s</a> කැඩපතෙන් approve_pull_request=`අනුමත <a href="%[1]s">%[3]s #%[2]s ගේ</a>` reject_pull_request=<a href="%[1]s">%[3]s #%[2]s</a>සඳහා යෝජිත වෙනස්කම් -publish_release=`නිදහස් <a href="%[2]s"> "%[4]s" </a> හි <a href="%[1]s">%[3]s</a>` review_dismissed_reason=හේතුව: create_branch=නිර්මාණය කරන ලද ශාඛාව <a href="%[2]s">%[3]s</a> <a href="%[1]s">%[4]s</a> watched_repo=<a href="%[1]s">%[2]s</a>නැරඹීමට පටන් ගත්තා diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index be89113f0d..7b57e416f7 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -3344,7 +3344,6 @@ mirror_sync_create=<a href="%[2]s">%[3]s</a> yeni referansını, <a href="%[1]s" mirror_sync_delete=<a href="%[1]s">%[3]s</a> adresindeki <code>%[2]s</code> referansını eşitledi ve sildi approve_pull_request=`<a href="%[1]s">%[3]s#%[2]s</a> değişiklik isteğini onayladı` reject_pull_request=`<a href="%[1]s">%[3]s#%[2]s</a> için değişiklikler önerdi` -publish_release=`<a href="%[1]s">%[3]s</a> deposu için <a href="%[2]s"> "%[4]s" </a> sürümü yayınlandı` review_dismissed=`<a href="%[1]s">%[3]s#%[2]s</a> için <b>%[4]s</b> yorumunu reddetti` review_dismissed_reason=Sebep: create_branch=<a href="%[1]s">%[4]s</a> deposunda <a href="%[2]s">%[3]s</a> dalını oluşturdu diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini index 3e38973e02..ddd884e113 100644 --- a/options/locale/locale_uk-UA.ini +++ b/options/locale/locale_uk-UA.ini @@ -2517,7 +2517,6 @@ mirror_sync_create=синхронізував нове посилання <a hre mirror_sync_delete=синхронізовано й видалено посилання <code>%[2]s</code> на <a href="%[1]s">%[3]s</a> із дзеркала approve_pull_request=`схвалив <a href="%[1]s">%[3]s#%[2]s</a>` reject_pull_request=`запропонував зміни до <a href="%[1]s">%[3]s#%[2]s</a>` -publish_release=`опублікував випуск <a href="%[2]s"> "%[4]s" </a> з <a href="%[1]s">%[3]s</a>` review_dismissed=`відхилив відгук від <b>%[4]s</b> для <a href="%[1]s">%[3]s#%[2]s</a>` review_dismissed_reason=Причина: create_branch=створив гілку <a href="%[2]s">%[3]s</a> в <a href="%[1]s">%[4]s</a> diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index c98af46d45..10abf90ed7 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -3347,7 +3347,6 @@ mirror_sync_create=从镜像同步了引用 <a href="%[2]s">%[3]s</a> 至仓库 mirror_sync_delete=从镜像同步并从 <a href="%[1]s">%[3]s</a> 删除了引用 <code>%[2]s</code> approve_pull_request=`批准了 <a href="%[1]s">%[3]s#%[2]s</a>` reject_pull_request=`建议变更 <a href="%[1]s">%[3]s#%[2]s</a>` -publish_release=`在 <a href="%[1]s">%[3]s</a> 发布了 <a href="%[2]s"> "%[4]s" </a>` review_dismissed=`取消了 <b>%[4]s</b> 对 <a href="%[1]s">%[3]s#%[2]s</a> 的变更请求` review_dismissed_reason=原因: create_branch=于 <a href="%[1]s">%[4]s</a> 创建了分支 <a href="%[2]s">%[3]s</a> diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini index 7823426990..50c0276567 100644 --- a/options/locale/locale_zh-TW.ini +++ b/options/locale/locale_zh-TW.ini @@ -2932,7 +2932,6 @@ mirror_sync_create=從鏡像同步了新參考 <a href="%[2]s">%[3]s</a> 到 <a mirror_sync_delete=從鏡像同步並從 <a href="%[1]s">%[3]s</a> 刪除了參考 <code>%[2]s</code> approve_pull_request=`核可了 <a href="%[1]s">%[3]s#%[2]s</a>` reject_pull_request=`提出了修改建議 <a href="%[1]s">%[3]s#%[2]s</a>` -publish_release=`發布了 <a href="%[1]s">%[3]s</a> 的 <a href="%[2]s"> "%[4]s" </a>` review_dismissed=`取消了 <b>%[4]s</b> 對 <a href="%[1]s">%[3]s#%[2]s</a> 的審核` review_dismissed_reason=原因: create_branch=在 <a href="%[1]s">%[4]s</a> 中建立了分支 <a href="%[2]s">%[3]s</a> From d0d6aad85f4d1e2a6d2a6524fe13eccecfd350af Mon Sep 17 00:00:00 2001 From: dicarne <dicarne@zhishudali.ink> Date: Wed, 15 May 2024 21:56:17 +0800 Subject: [PATCH 318/370] Supports forced use of S3 virtual-hosted style (#30969) Add a configuration item to enable S3 virtual-hosted style (V2) to solve the problem caused by some S3 service providers not supporting path style (V1). --- cmd/migrate_storage.go | 6 ++++++ custom/conf/app.example.ini | 6 ++++++ .../config-cheat-sheet.en-us.md | 8 ++++++++ .../config-cheat-sheet.zh-cn.md | 8 ++++++++ modules/setting/storage.go | 2 ++ modules/storage/minio.go | 20 +++++++++++++++---- 6 files changed, 46 insertions(+), 4 deletions(-) diff --git a/cmd/migrate_storage.go b/cmd/migrate_storage.go index 357416fc33..7d1ef052ff 100644 --- a/cmd/migrate_storage.go +++ b/cmd/migrate_storage.go @@ -91,6 +91,11 @@ var CmdMigrateStorage = &cli.Command{ Value: "", Usage: "Minio checksum algorithm (default/md5)", }, + &cli.StringFlag{ + Name: "minio-bucket-lookup-type", + Value: "", + Usage: "Minio bucket lookup type", + }, }, } @@ -220,6 +225,7 @@ func runMigrateStorage(ctx *cli.Context) error { UseSSL: ctx.Bool("minio-use-ssl"), InsecureSkipVerify: ctx.Bool("minio-insecure-skip-verify"), ChecksumAlgorithm: ctx.String("minio-checksum-algorithm"), + BucketLookUpType: ctx.String("minio-bucket-lookup-type"), }, }) default: diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 577479e39f..4df843b8ce 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1895,6 +1895,9 @@ LEVEL = Info ;; ;; Minio checksum algorithm: default (for MinIO or AWS S3) or md5 (for Cloudflare or Backblaze) ;MINIO_CHECKSUM_ALGORITHM = default +;; +;; Minio bucket lookup method defaults to auto mode; set it to `dns` for virtual host style or `path` for path style, only available when STORAGE_TYPE is `minio` +;MINIO_BUCKET_LOOKUP_TYPE = auto ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -2576,6 +2579,9 @@ LEVEL = Info ;; ;; Minio skip SSL verification available when STORAGE_TYPE is `minio` ;MINIO_INSECURE_SKIP_VERIFY = false +;; +;; Minio bucket lookup method defaults to auto mode; set it to `dns` for virtual host style or `path` for path style, only available when STORAGE_TYPE is `minio` +;MINIO_BUCKET_LOOKUP_TYPE = auto ;[proxy] ;; Enable the proxy, all requests to external via HTTP will be affected diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index 07712c1110..6c429bb652 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -851,6 +851,7 @@ Default templates for project boards: - `MINIO_USE_SSL`: **false**: Minio enabled ssl only available when STORAGE_TYPE is `minio` - `MINIO_INSECURE_SKIP_VERIFY`: **false**: Minio skip SSL verification available when STORAGE_TYPE is `minio` - `MINIO_CHECKSUM_ALGORITHM`: **default**: Minio checksum algorithm: `default` (for MinIO or AWS S3) or `md5` (for Cloudflare or Backblaze) +- `MINIO_BUCKET_LOOKUP_TYPE`: **auto**: Minio bucket lookup method defaults to auto mode; set it to `dns` for virtual host style or `path` for path style, only available when STORAGE_TYPE is `minio` ## Log (`log`) @@ -1272,6 +1273,7 @@ is `data/lfs` and the default of `MINIO_BASE_PATH` is `lfs/`. - `MINIO_BASE_PATH`: **lfs/**: Minio base path on the bucket only available when `STORAGE_TYPE` is `minio` - `MINIO_USE_SSL`: **false**: Minio enabled ssl only available when `STORAGE_TYPE` is `minio` - `MINIO_INSECURE_SKIP_VERIFY`: **false**: Minio skip SSL verification available when STORAGE_TYPE is `minio` +- `MINIO_BUCKET_LOOKUP_TYPE`: **auto**: Minio bucket lookup method defaults to auto mode; set it to `dns` for virtual host style or `path` for path style, only available when STORAGE_TYPE is `minio` ## Storage (`storage`) @@ -1286,6 +1288,7 @@ Default storage configuration for attachments, lfs, avatars, repo-avatars, repo- - `MINIO_LOCATION`: **us-east-1**: Minio location to create bucket only available when `STORAGE_TYPE` is `minio` - `MINIO_USE_SSL`: **false**: Minio enabled ssl only available when `STORAGE_TYPE` is `minio` - `MINIO_INSECURE_SKIP_VERIFY`: **false**: Minio skip SSL verification available when STORAGE_TYPE is `minio` +- `MINIO_BUCKET_LOOKUP_TYPE`: **auto**: Minio bucket lookup method defaults to auto mode; set it to `dns` for virtual host style or `path` for path style, only available when STORAGE_TYPE is `minio` The recommended storage configuration for minio like below: @@ -1307,6 +1310,8 @@ MINIO_USE_SSL = false ; Minio skip SSL verification available when STORAGE_TYPE is `minio` MINIO_INSECURE_SKIP_VERIFY = false SERVE_DIRECT = true +; Minio bucket lookup method defaults to auto mode; set it to `dns` for virtual host style or `path` for path style, only available when STORAGE_TYPE is `minio` +MINIO_BUCKET_LOOKUP_TYPE = auto ``` Defaultly every storage has their default base path like below @@ -1353,6 +1358,8 @@ MINIO_LOCATION = us-east-1 MINIO_USE_SSL = false ; Minio skip SSL verification available when STORAGE_TYPE is `minio` MINIO_INSECURE_SKIP_VERIFY = false +; Minio bucket lookup method defaults to auto mode; set it to `dns` for virtual host style or `path` for path style, only available when STORAGE_TYPE is `minio` +MINIO_BUCKET_LOOKUP_TYPE = auto ``` ## Repository Archive Storage (`storage.repo-archive`) @@ -1372,6 +1379,7 @@ is `data/repo-archive` and the default of `MINIO_BASE_PATH` is `repo-archive/`. - `MINIO_BASE_PATH`: **repo-archive/**: Minio base path on the bucket only available when `STORAGE_TYPE` is `minio` - `MINIO_USE_SSL`: **false**: Minio enabled ssl only available when `STORAGE_TYPE` is `minio` - `MINIO_INSECURE_SKIP_VERIFY`: **false**: Minio skip SSL verification available when STORAGE_TYPE is `minio` +- `MINIO_BUCKET_LOOKUP_TYPE`: **auto**: Minio bucket lookup method defaults to auto mode; set it to `dns` for virtual host style or `path` for path style, only available when STORAGE_TYPE is `minio` ## Repository Archives (`repo-archive`) diff --git a/docs/content/administration/config-cheat-sheet.zh-cn.md b/docs/content/administration/config-cheat-sheet.zh-cn.md index 3bb31d3d71..3c6ac8c00a 100644 --- a/docs/content/administration/config-cheat-sheet.zh-cn.md +++ b/docs/content/administration/config-cheat-sheet.zh-cn.md @@ -796,6 +796,7 @@ Gitea 创建以下非唯一队列: - `MINIO_USE_SSL`: **false**: Minio 启用 SSL,仅当 STORAGE_TYPE 为 `minio` 时可用。 - `MINIO_INSECURE_SKIP_VERIFY`: **false**: Minio 跳过 SSL 验证,仅当 STORAGE_TYPE 为 `minio` 时可用。 - `MINIO_CHECKSUM_ALGORITHM`: **default**: Minio 校验算法:`default`(适用于 MinIO 或 AWS S3)或 `md5`(适用于 Cloudflare 或 Backblaze) +- `MINIO_BUCKET_LOOKUP_TYPE`: **auto**: Minio的bucket查找方式默认为`auto`模式,可将其设置为`dns`(虚拟托管样式)或`path`(路径样式),仅当`STORAGE_TYPE`为`minio`时可用。 ## 日志 (`log`) @@ -1201,6 +1202,7 @@ ALLOW_DATA_URI_IMAGES = true - `MINIO_BASE_PATH`:**lfs/**:桶上的 Minio 基本路径,仅在 `STORAGE_TYPE` 为 `minio` 时可用。 - `MINIO_USE_SSL`:**false**:Minio 启用 ssl,仅在 `STORAGE_TYPE` 为 `minio` 时可用。 - `MINIO_INSECURE_SKIP_VERIFY`:**false**:Minio 跳过 SSL 验证,仅在 `STORAGE_TYPE` 为 `minio` 时可用。 +- `MINIO_BUCKET_LOOKUP_TYPE`: **auto**: Minio的bucket查找方式默认为`auto`模式,可将其设置为`dns`(虚拟托管样式)或`path`(路径样式),仅当`STORAGE_TYPE`为`minio`时可用。 ## 存储 (`storage`) @@ -1215,6 +1217,7 @@ ALLOW_DATA_URI_IMAGES = true - `MINIO_LOCATION`:**us-east-1**:创建桶的 Minio 位置,仅在 `STORAGE_TYPE` 为 `minio` 时可用。 - `MINIO_USE_SSL`:**false**:Minio 启用 ssl,仅在 `STORAGE_TYPE` 为 `minio` 时可用。 - `MINIO_INSECURE_SKIP_VERIFY`:**false**:Minio 跳过 SSL 验证,仅在 `STORAGE_TYPE` 为 `minio` 时可用。 +- `MINIO_BUCKET_LOOKUP_TYPE`: **auto**: Minio的bucket查找方式默认为`auto`模式,可将其设置为`dns`(虚拟托管样式)或`path`(路径样式),仅当`STORAGE_TYPE`为`minio`时可用。 建议的 minio 存储配置如下: @@ -1236,6 +1239,8 @@ MINIO_USE_SSL = false ; Minio skip SSL verification available when STORAGE_TYPE is `minio` MINIO_INSECURE_SKIP_VERIFY = false SERVE_DIRECT = true +; Minio bucket lookup method defaults to auto mode; set it to `dns` for virtual host style or `path` for path style, only available when STORAGE_TYPE is `minio` +MINIO_BUCKET_LOOKUP_TYPE = auto ``` 默认情况下,每个存储都有其默认的基本路径,如下所示: @@ -1282,6 +1287,8 @@ MINIO_LOCATION = us-east-1 MINIO_USE_SSL = false ; Minio skip SSL verification available when STORAGE_TYPE is `minio` MINIO_INSECURE_SKIP_VERIFY = false +; Minio bucket lookup method defaults to auto mode; set it to `dns` for virtual host style or `path` for path style, only available when STORAGE_TYPE is `minio` +MINIO_BUCKET_LOOKUP_TYPE = auto ``` ### 存储库归档存储 (`storage.repo-archive`) @@ -1299,6 +1306,7 @@ MINIO_INSECURE_SKIP_VERIFY = false - `MINIO_BASE_PATH`: **repo-archive/**:存储桶上的Minio基本路径,仅在`STORAGE_TYPE`为`minio`时可用。 - `MINIO_USE_SSL`: **false**:启用Minio的SSL,仅在`STORAGE_TYPE`为`minio`时可用。 - `MINIO_INSECURE_SKIP_VERIFY`: **false**:跳过Minio的SSL验证,仅在`STORAGE_TYPE`为`minio`时可用。 +- `MINIO_BUCKET_LOOKUP_TYPE`: **auto**: Minio的bucket查找方式默认为`auto`模式,可将其设置为`dns`(虚拟托管样式)或`path`(路径样式),仅当`STORAGE_TYPE`为`minio`时可用。 ### 存储库归档 (`repo-archive`) diff --git a/modules/setting/storage.go b/modules/setting/storage.go index 0bd52acc0f..d80a61a45e 100644 --- a/modules/setting/storage.go +++ b/modules/setting/storage.go @@ -47,6 +47,7 @@ type MinioStorageConfig struct { InsecureSkipVerify bool `ini:"MINIO_INSECURE_SKIP_VERIFY"` ChecksumAlgorithm string `ini:"MINIO_CHECKSUM_ALGORITHM" json:",omitempty"` ServeDirect bool `ini:"SERVE_DIRECT"` + BucketLookUpType string `ini:"MINIO_BUCKET_LOOKUP_TYPE" json:",omitempty"` } // Storage represents configuration of storages @@ -82,6 +83,7 @@ func getDefaultStorageSection(rootCfg ConfigProvider) ConfigSection { storageSec.Key("MINIO_USE_SSL").MustBool(false) storageSec.Key("MINIO_INSECURE_SKIP_VERIFY").MustBool(false) storageSec.Key("MINIO_CHECKSUM_ALGORITHM").MustString("default") + storageSec.Key("MINIO_BUCKET_LOOKUP_TYPE").MustString("auto") return storageSec } diff --git a/modules/storage/minio.go b/modules/storage/minio.go index b58ab67dc7..986332dfed 100644 --- a/modules/storage/minio.go +++ b/modules/storage/minio.go @@ -85,11 +85,23 @@ func NewMinioStorage(ctx context.Context, cfg *setting.Storage) (ObjectStorage, log.Info("Creating Minio storage at %s:%s with base path %s", config.Endpoint, config.Bucket, config.BasePath) + var lookup minio.BucketLookupType + if config.BucketLookUpType == "auto" || config.BucketLookUpType == "" { + lookup = minio.BucketLookupAuto + } else if config.BucketLookUpType == "dns" { + lookup = minio.BucketLookupDNS + } else if config.BucketLookUpType == "path" { + lookup = minio.BucketLookupPath + } else { + return nil, fmt.Errorf("invalid minio bucket lookup type: %s", config.BucketLookUpType) + } + minioClient, err := minio.New(config.Endpoint, &minio.Options{ - Creds: credentials.NewStaticV4(config.AccessKeyID, config.SecretAccessKey, ""), - Secure: config.UseSSL, - Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: config.InsecureSkipVerify}}, - Region: config.Location, + Creds: credentials.NewStaticV4(config.AccessKeyID, config.SecretAccessKey, ""), + Secure: config.UseSSL, + Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: config.InsecureSkipVerify}}, + Region: config.Location, + BucketLookup: lookup, }) if err != nil { return nil, convertMinioErr(err) From fc89363832c87678d9e35e865b49c63c7ad498f2 Mon Sep 17 00:00:00 2001 From: Zettat123 <zettat123@gmail.com> Date: Wed, 15 May 2024 22:25:47 +0800 Subject: [PATCH 319/370] Check if the release is converted from the tag when updating the release (#30984) Call `notify_service.NewRelease` when a release is created from an existing tag. --- services/release/release.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/services/release/release.go b/services/release/release.go index ba5fd1dd98..399fdc79c0 100644 --- a/services/release/release.go +++ b/services/release/release.go @@ -204,7 +204,7 @@ func UpdateRelease(ctx context.Context, doer *user_model.User, gitRepo *git.Repo if rel.ID == 0 { return errors.New("UpdateRelease only accepts an exist release") } - isCreated, err := createTag(gitRepo.Ctx, gitRepo, rel, "") + isTagCreated, err := createTag(gitRepo.Ctx, gitRepo, rel, "") if err != nil { return err } @@ -216,6 +216,12 @@ func UpdateRelease(ctx context.Context, doer *user_model.User, gitRepo *git.Repo } defer committer.Close() + oldRelease, err := repo_model.GetReleaseByID(ctx, rel.ID) + if err != nil { + return err + } + isConvertedFromTag := oldRelease.IsTag && !rel.IsTag + if err = repo_model.UpdateRelease(ctx, rel); err != nil { return err } @@ -292,7 +298,7 @@ func UpdateRelease(ctx context.Context, doer *user_model.User, gitRepo *git.Repo } if !rel.IsDraft { - if !isCreated { + if !isTagCreated && !isConvertedFromTag { notify_service.UpdateRelease(gitRepo.Ctx, doer, rel) return nil } From ea8e4baacc5c58e45e68291334c3d2c42e9d6737 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Wed, 15 May 2024 16:54:34 +0200 Subject: [PATCH 320/370] Put web editor into a segment (#30966) Implement https://github.com/go-gitea/gitea/pull/30707#issuecomment-2084126206 Diff without whitespace: https://github.com/go-gitea/gitea/pull/30966/files?diff=unified&w=1 Might as well backport. --- templates/repo/editor/edit.tmpl | 42 ++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/templates/repo/editor/edit.tmpl b/templates/repo/editor/edit.tmpl index ae3f12669c..e990177d8a 100644 --- a/templates/repo/editor/edit.tmpl +++ b/templates/repo/editor/edit.tmpl @@ -26,26 +26,30 @@ </div> </div> <div class="field"> - <div class="ui compact small menu small-menu-items repo-editor-menu"> - <a class="active item" data-tab="write">{{svg "octicon-code"}} {{if .IsNewFile}}{{ctx.Locale.Tr "repo.editor.new_file"}}{{else}}{{ctx.Locale.Tr "repo.editor.edit_file"}}{{end}}</a> - <a class="item" data-tab="preview" data-url="{{.Repository.Link}}/markup" data-context="{{.RepoLink}}/src/{{.BranchNameSubURL}}" data-markup-mode="file">{{svg "octicon-eye"}} {{ctx.Locale.Tr "preview"}}</a> - {{if not .IsNewFile}} - <a class="item" data-tab="diff" hx-params="context,content" hx-vals='{"context":"{{.BranchLink}}"}' hx-include="#edit_area" hx-swap="innerHTML" hx-target=".tab[data-tab='diff']" hx-indicator=".tab[data-tab='diff']" hx-post="{{.RepoLink}}/_preview/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">{{svg "octicon-diff"}} {{ctx.Locale.Tr "repo.editor.preview_changes"}}</a> - {{end}} + <div class="ui top attached header"> + <div class="ui compact small menu small-menu-items repo-editor-menu"> + <a class="active item" data-tab="write">{{svg "octicon-code"}} {{if .IsNewFile}}{{ctx.Locale.Tr "repo.editor.new_file"}}{{else}}{{ctx.Locale.Tr "repo.editor.edit_file"}}{{end}}</a> + <a class="item" data-tab="preview" data-url="{{.Repository.Link}}/markup" data-context="{{.RepoLink}}/src/{{.BranchNameSubURL}}" data-markup-mode="file">{{svg "octicon-eye"}} {{ctx.Locale.Tr "preview"}}</a> + {{if not .IsNewFile}} + <a class="item" data-tab="diff" hx-params="context,content" hx-vals='{"context":"{{.BranchLink}}"}' hx-include="#edit_area" hx-swap="innerHTML" hx-target=".tab[data-tab='diff']" hx-indicator=".tab[data-tab='diff']" hx-post="{{.RepoLink}}/_preview/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">{{svg "octicon-diff"}} {{ctx.Locale.Tr "repo.editor.preview_changes"}}</a> + {{end}} + </div> </div> - <div class="ui active tab segment tw-rounded" data-tab="write"> - <textarea id="edit_area" name="content" class="tw-hidden" data-id="repo-{{.Repository.Name}}-{{.TreePath}}" - data-url="{{.Repository.Link}}/markup" - data-context="{{.RepoLink}}" - data-previewable-extensions="{{.PreviewableExtensions}}" - data-line-wrap-extensions="{{.LineWrapExtensions}}">{{.FileContent}}</textarea> - <div class="editor-loading is-loading"></div> - </div> - <div class="ui tab segment markup tw-rounded" data-tab="preview"> - {{ctx.Locale.Tr "loading"}} - </div> - <div class="ui tab segment diff edit-diff" data-tab="diff"> - <div class="tw-p-16"></div> + <div class="ui bottom attached segment tw-p-0"> + <div class="ui active tab tw-rounded" data-tab="write"> + <textarea id="edit_area" name="content" class="tw-hidden" data-id="repo-{{.Repository.Name}}-{{.TreePath}}" + data-url="{{.Repository.Link}}/markup" + data-context="{{.RepoLink}}" + data-previewable-extensions="{{.PreviewableExtensions}}" + data-line-wrap-extensions="{{.LineWrapExtensions}}">{{.FileContent}}</textarea> + <div class="editor-loading is-loading"></div> + </div> + <div class="ui tab markup tw-px-4 tw-py-3" data-tab="preview"> + {{ctx.Locale.Tr "loading"}} + </div> + <div class="ui tab diff edit-diff" data-tab="diff"> + <div class="tw-p-16"></div> + </div> </div> </div> {{template "repo/editor/commit_form" .}} From 2611249511aaab710ad7b0bccd049d3e4dc912f4 Mon Sep 17 00:00:00 2001 From: Frank Villaro-Dixon <frank@vi-di.fr> Date: Thu, 16 May 2024 08:36:31 +0200 Subject: [PATCH 321/370] template: `label` fix correct input id (#30987) Signed-off-by: Frank Villaro-Dixon <frank@villaro-dixon.eu> --- templates/repo/settings/deploy_keys.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/settings/deploy_keys.tmpl b/templates/repo/settings/deploy_keys.tmpl index da1a321785..190ca1af6c 100644 --- a/templates/repo/settings/deploy_keys.tmpl +++ b/templates/repo/settings/deploy_keys.tmpl @@ -28,7 +28,7 @@ <div class="field"> <div class="ui checkbox {{if .Err_IsWritable}}error{{end}}"> <input id="ssh-key-is-writable" name="is_writable" type="checkbox" value="1"> - <label for="is_writable"> + <label for="ssh-key-is-writable"> {{ctx.Locale.Tr "repo.settings.is_writable"}} </label> <small class="tw-pl-[26px]">{{ctx.Locale.Tr "repo.settings.is_writable_info"}}</small> From 740b6e1389911eeea860cfccd4bad218fe33f3bd Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Thu, 16 May 2024 21:04:25 +0800 Subject: [PATCH 322/370] Fix JS error when editing a merged PR's title (#30990) --- templates/repo/issue/view_title.tmpl | 6 ++---- web_src/js/features/repo-issue.js | 5 ++++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/templates/repo/issue/view_title.tmpl b/templates/repo/issue/view_title.tmpl index 4415ad79f5..097d7b1f7c 100644 --- a/templates/repo/issue/view_title.tmpl +++ b/templates/repo/issue/view_title.tmpl @@ -26,9 +26,7 @@ </div> <div class="issue-title-buttons"> <button class="ui small basic cancel button">{{ctx.Locale.Tr "repo.issues.cancel"}}</button> - <button class="ui small primary button" - data-update-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/title" - {{if .Issue.IsPull}}data-target-update-url="{{$.RepoLink}}/pull/{{.Issue.Index}}/target_branch"{{end}}> + <button class="ui small primary button" data-update-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/title"> {{ctx.Locale.Tr "repo.issues.save"}} </button> </div> @@ -77,7 +75,7 @@ {{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref}} </span> {{end}} - <span id="pull-desc-editor" class="tw-hidden flex-text-block"> + <span id="pull-desc-editor" class="tw-hidden flex-text-block" data-target-update-url="{{$.RepoLink}}/pull/{{.Issue.Index}}/target_branch"> <div class="ui floating filter dropdown"> <div class="ui basic small button tw-mr-0"> <span class="text">{{ctx.Locale.Tr "repo.pulls.compare_compare"}}: {{$.HeadTarget}}</span> diff --git a/web_src/js/features/repo-issue.js b/web_src/js/features/repo-issue.js index 8ee681aedc..519db34934 100644 --- a/web_src/js/features/repo-issue.js +++ b/web_src/js/features/repo-issue.js @@ -626,9 +626,12 @@ export function initRepoIssueTitleEdit() { showElem(issueTitleDisplay); showElem('#pull-desc-display'); }); + + const pullDescEditor = document.querySelector('#pull-desc-editor'); // it may not exist for a merged PR + const prTargetUpdateUrl = pullDescEditor?.getAttribute('data-target-update-url'); + const editSaveButton = issueTitleEditor.querySelector('.ui.primary.button'); editSaveButton.addEventListener('click', async () => { - const prTargetUpdateUrl = editSaveButton.getAttribute('data-target-update-url'); const newTitle = issueTitleInput.value.trim(); try { if (newTitle && newTitle !== oldTitle) { From a73e3c6a696029541ebd423f4eb2fec1ba151f79 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Thu, 16 May 2024 21:40:57 +0200 Subject: [PATCH 323/370] Upgrade `tqdm` dependency (#30996) Result of `make update-py` Fixes: https://github.com/go-gitea/gitea/security/dependabot/65 --- poetry.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/poetry.lock b/poetry.lock index 1533ddc5ec..74536495d2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "click" @@ -318,13 +318,13 @@ files = [ [[package]] name = "tqdm" -version = "4.66.2" +version = "4.66.4" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" files = [ - {file = "tqdm-4.66.2-py3-none-any.whl", hash = "sha256:1ee4f8a893eb9bef51c6e35730cebf234d5d0b6bd112b0271e10ed7c24a02bd9"}, - {file = "tqdm-4.66.2.tar.gz", hash = "sha256:6cd52cdf0fef0e0f543299cfc96fec90d7b8a7e88745f411ec33eb44d5ed3531"}, + {file = "tqdm-4.66.4-py3-none-any.whl", hash = "sha256:b75ca56b413b030bc3f00af51fd2c1a1a5eac6a0c1cca83cbb37a5c52abce644"}, + {file = "tqdm-4.66.4.tar.gz", hash = "sha256:e4d936c9de8727928f3be6079590e97d9abfe8d39a590be678eb5919ffc186bb"}, ] [package.dependencies] From 68d5c18953620927101609bbd21508213cbcd589 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Fri, 17 May 2024 00:25:42 +0000 Subject: [PATCH 324/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_zh-CN.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 10abf90ed7..0e224f0061 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -3320,6 +3320,7 @@ self_check.database_collation_case_insensitive=数据库正在使用一个校验 self_check.database_inconsistent_collation_columns=数据库正在使用%s的排序规则,但是这些列使用了不匹配的排序规则。这可能会造成一些意外问题。 self_check.database_fix_mysql=对于MySQL/MariaDB用户,您可以使用“gitea doctor convert”命令来解决校验问题。 或者您也可以通过 "ALTER ... COLLATE ..." 这样的SQL 来手动解决这个问题。 self_check.database_fix_mssql=对于MSSQL用户,您现在只能通过"ALTER ... COLLATE ..."SQLs手动解决这个问题。 +self_check.location_origin_mismatch=当前 URL (%[1]s) 与 Gitea 的 URL (%[2]s) 不匹配 。 如果您正在使用反向代理,请确保设置正确的“主机”和“X-转发-原始”标题。 [action] create_repo=创建了仓库 <a href="%s">%s</a> @@ -3347,6 +3348,7 @@ mirror_sync_create=从镜像同步了引用 <a href="%[2]s">%[3]s</a> 至仓库 mirror_sync_delete=从镜像同步并从 <a href="%[1]s">%[3]s</a> 删除了引用 <code>%[2]s</code> approve_pull_request=`批准了 <a href="%[1]s">%[3]s#%[2]s</a>` reject_pull_request=`建议变更 <a href="%[1]s">%[3]s#%[2]s</a>` +publish_release=`在 <a href="%[1]s">%[3]s</a> 发布了 <a href="%[2]s"> %[4]s </a>` review_dismissed=`取消了 <b>%[4]s</b> 对 <a href="%[1]s">%[3]s#%[2]s</a> 的变更请求` review_dismissed_reason=原因: create_branch=于 <a href="%[1]s">%[4]s</a> 创建了分支 <a href="%[2]s">%[3]s</a> From 821d2fc2a3cc897f21d707455850177077b72410 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sat, 18 May 2024 00:07:41 +0800 Subject: [PATCH 325/370] Simplify mirror repository API logic (#30963) Fix #30921 --- modules/structs/repo.go | 2 +- routers/api/v1/repo/repo.go | 12 +++--------- templates/swagger/v1_json.tmpl | 2 +- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/modules/structs/repo.go b/modules/structs/repo.go index bc8eb0b756..1fe826cf89 100644 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -217,7 +217,7 @@ type EditRepoOption struct { Archived *bool `json:"archived,omitempty"` // set to a string like `8h30m0s` to set the mirror interval time MirrorInterval *string `json:"mirror_interval,omitempty"` - // enable prune - remove obsolete remote-tracking references + // enable prune - remove obsolete remote-tracking references when mirroring EnablePrune *bool `json:"enable_prune,omitempty"` } diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 7f35a7fe41..e759142938 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -1062,16 +1062,10 @@ func updateRepoArchivedState(ctx *context.APIContext, opts api.EditRepoOption) e func updateMirror(ctx *context.APIContext, opts api.EditRepoOption) error { repo := ctx.Repo.Repository - // only update mirror if interval or enable prune are provided - if opts.MirrorInterval == nil && opts.EnablePrune == nil { - return nil - } - - // these values only make sense if the repo is a mirror + // Skip this update if the repo is not a mirror, do not return error. + // Because reporting errors only makes the logic more complex&fragile, it doesn't really help end users. if !repo.IsMirror { - err := fmt.Errorf("repo is not a mirror, can not change mirror interval") - ctx.Error(http.StatusUnprocessableEntity, err.Error(), err) - return err + return nil } // get the mirror from the repo diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 9ad0aa2ab6..0b3f5cdcad 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -20753,7 +20753,7 @@ "x-go-name": "Description" }, "enable_prune": { - "description": "enable prune - remove obsolete remote-tracking references", + "description": "enable prune - remove obsolete remote-tracking references when mirroring", "type": "boolean", "x-go-name": "EnablePrune" }, From 028992429a2e14de39c9bb028637948e446d23ad Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sat, 18 May 2024 10:53:28 +0200 Subject: [PATCH 326/370] Clean up revive linter config, tweak golangci output (#30980) The `errorCode` and `warningCode` options were removed at some point, they are not recognized by golangci-lint any more at least and they do not match their published json schema. `confidence` and `ignore-generated-header` are at the default value so does not need to be configured. https://golangci-lint.run/usage/linters/#revive --- .golangci.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 238f6cb837..1750872765 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -29,6 +29,8 @@ run: output: sort-results: true + sort-order: [file] + show-stats: true linters-settings: stylecheck: @@ -40,11 +42,7 @@ linters-settings: - ifElseChain - singleCaseSwitch # Every time this occurred in the code, there was no other way. revive: - ignore-generated-header: false - severity: warning - confidence: 0.8 - errorCode: 1 - warningCode: 1 + severity: error rules: - name: atomic - name: bare-return From 58a03e9fadb345de5653345c2a68ecfd0750940a Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Sun, 19 May 2024 12:58:39 +0800 Subject: [PATCH 327/370] Fix bug on avatar (#31008) Co-authored-by: silverwind <me@silverwind.io> --- routers/api/v1/org/avatar.go | 2 ++ routers/api/v1/user/avatar.go | 2 ++ services/user/avatar.go | 32 +++++++++++++++++++++----------- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/routers/api/v1/org/avatar.go b/routers/api/v1/org/avatar.go index e34c68dfc9..f11eb6c1cd 100644 --- a/routers/api/v1/org/avatar.go +++ b/routers/api/v1/org/avatar.go @@ -46,6 +46,7 @@ func UpdateAvatar(ctx *context.APIContext) { err = user_service.UploadAvatar(ctx, ctx.Org.Organization.AsUser(), content) if err != nil { ctx.Error(http.StatusInternalServerError, "UploadAvatar", err) + return } ctx.Status(http.StatusNoContent) @@ -72,6 +73,7 @@ func DeleteAvatar(ctx *context.APIContext) { err := user_service.DeleteAvatar(ctx, ctx.Org.Organization.AsUser()) if err != nil { ctx.Error(http.StatusInternalServerError, "DeleteAvatar", err) + return } ctx.Status(http.StatusNoContent) diff --git a/routers/api/v1/user/avatar.go b/routers/api/v1/user/avatar.go index f912296228..30ccb63587 100644 --- a/routers/api/v1/user/avatar.go +++ b/routers/api/v1/user/avatar.go @@ -39,6 +39,7 @@ func UpdateAvatar(ctx *context.APIContext) { err = user_service.UploadAvatar(ctx, ctx.Doer, content) if err != nil { ctx.Error(http.StatusInternalServerError, "UploadAvatar", err) + return } ctx.Status(http.StatusNoContent) @@ -57,6 +58,7 @@ func DeleteAvatar(ctx *context.APIContext) { err := user_service.DeleteAvatar(ctx, ctx.Doer) if err != nil { ctx.Error(http.StatusInternalServerError, "DeleteAvatar", err) + return } ctx.Status(http.StatusNoContent) diff --git a/services/user/avatar.go b/services/user/avatar.go index 2d6c3faf9a..3f87466eaa 100644 --- a/services/user/avatar.go +++ b/services/user/avatar.go @@ -5,8 +5,10 @@ package user import ( "context" + "errors" "fmt" "io" + "os" "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" @@ -48,16 +50,24 @@ func UploadAvatar(ctx context.Context, u *user_model.User, data []byte) error { func DeleteAvatar(ctx context.Context, u *user_model.User) error { aPath := u.CustomAvatarRelativePath() log.Trace("DeleteAvatar[%d]: %s", u.ID, aPath) - if len(u.Avatar) > 0 { - if err := storage.Avatars.Delete(aPath); err != nil { - return fmt.Errorf("Failed to remove %s: %w", aPath, err) - } - } - u.UseCustomAvatar = false - u.Avatar = "" - if _, err := db.GetEngine(ctx).ID(u.ID).Cols("avatar, use_custom_avatar").Update(u); err != nil { - return fmt.Errorf("DeleteAvatar: %w", err) - } - return nil + return db.WithTx(ctx, func(ctx context.Context) error { + hasAvatar := len(u.Avatar) > 0 + u.UseCustomAvatar = false + u.Avatar = "" + if _, err := db.GetEngine(ctx).ID(u.ID).Cols("avatar, use_custom_avatar").Update(u); err != nil { + return fmt.Errorf("DeleteAvatar: %w", err) + } + + if hasAvatar { + if err := storage.Avatars.Delete(aPath); err != nil { + if !errors.Is(err, os.ErrNotExist) { + return fmt.Errorf("failed to remove %s: %w", aPath, err) + } + log.Warn("Deleting avatar %s but it doesn't exist", aPath) + } + } + + return nil + }) } From 339bc8bc8fdb4ead3c43b4604b100f83e6f47cb5 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sun, 19 May 2024 22:56:08 +0800 Subject: [PATCH 328/370] Improve reverse proxy documents and clarify the AppURL guessing behavior (#31003) Fix #31002 1. Mention Make sure `Host` and `X-Fowarded-Proto` headers are correctly passed to Gitea 2. Clarify the basic requirements and move the "general configuration" to the top 3. Add a comment for the "container registry" 4. Use 1.21 behavior if the reverse proxy is not correctly configured Co-authored-by: KN4CK3R <admin@oldschoolhack.me> --- .../administration/reverse-proxies.en-us.md | 92 ++++++++++--------- modules/httplib/url.go | 31 ++++--- modules/httplib/url_test.go | 12 +-- routers/api/packages/container/container.go | 2 + routers/web/admin/admin_test.go | 2 +- 5 files changed, 78 insertions(+), 61 deletions(-) diff --git a/docs/content/administration/reverse-proxies.en-us.md b/docs/content/administration/reverse-proxies.en-us.md index fe54c67d02..5fbd0eb0b7 100644 --- a/docs/content/administration/reverse-proxies.en-us.md +++ b/docs/content/administration/reverse-proxies.en-us.md @@ -17,15 +17,35 @@ menu: # Reverse Proxies +## General configuration + +1. Set `[server] ROOT_URL = https://git.example.com/` in your `app.ini` file. +2. Make the reverse-proxy pass `https://git.example.com/foo` to `http://gitea:3000/foo`. +3. Make sure the reverse-proxy does not decode the URI. The request `https://git.example.com/a%2Fb` should be passed as `http://gitea:3000/a%2Fb`. +4. Make sure `Host` and `X-Fowarded-Proto` headers are correctly passed to Gitea to make Gitea see the real URL being visited. + +### Use a sub-path + +Usually it's **not recommended** to put Gitea in a sub-path, it's not widely used and may have some issues in rare cases. + +To make Gitea work with a sub-path (eg: `https://common.example.com/gitea/`), +there are some extra requirements besides the general configuration above: + +1. Use `[server] ROOT_URL = https://common.example.com/gitea/` in your `app.ini` file. +2. Make the reverse-proxy pass `https://common.example.com/gitea/foo` to `http://gitea:3000/foo`. +3. The container registry requires a fixed sub-path `/v2` at the root level which must be configured: + - Make the reverse-proxy pass `https://common.example.com/v2` to `http://gitea:3000/v2`. + - Make sure the URI and headers are also correctly passed (see the general configuration above). + ## Nginx -If you want Nginx to serve your Gitea instance, add the following `server` section to the `http` section of `nginx.conf`: +If you want Nginx to serve your Gitea instance, add the following `server` section to the `http` section of `nginx.conf`. -``` +Make sure `client_max_body_size` is large enough, otherwise there would be "413 Request Entity Too Large" error when uploading large files. + +```nginx server { - listen 80; - server_name git.example.com; - + ... location / { client_max_body_size 512M; proxy_pass http://localhost:3000; @@ -39,37 +59,35 @@ server { } ``` -### Resolving Error: 413 Request Entity Too Large - -This error indicates nginx is configured to restrict the file upload size, -it affects attachment uploading, form posting, package uploading and LFS pushing, etc. -You can fine tune the `client_max_body_size` option according to [nginx document](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size). - ## Nginx with a sub-path -In case you already have a site, and you want Gitea to share the domain name, you can setup Nginx to serve Gitea under a sub-path by adding the following `server` section inside the `http` section of `nginx.conf`: +In case you already have a site, and you want Gitea to share the domain name, +you can setup Nginx to serve Gitea under a sub-path by adding the following `server` section +into the `http` section of `nginx.conf`: -``` +```nginx server { - listen 80; - server_name git.example.com; - - # Note: Trailing slash - location /gitea/ { + ... + location ~ ^/(gitea|v2)($|/) { client_max_body_size 512M; - # make nginx use unescaped URI, keep "%2F" as is + # make nginx use unescaped URI, keep "%2F" as-is, remove the "/gitea" sub-path prefix, pass "/v2" as-is. rewrite ^ $request_uri; - rewrite ^/gitea(/.*) $1 break; + rewrite ^(/gitea)?(/.*) $2 break; proxy_pass http://127.0.0.1:3000$uri; # other common HTTP headers, see the "Nginx" config section above - proxy_set_header ... + proxy_set_header Connection $http_connection; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; } } ``` -Then you **MUST** set something like `[server] ROOT_URL = http://git.example.com/git/` correctly in your configuration. +Then you **MUST** set something like `[server] ROOT_URL = http://git.example.com/gitea/` correctly in your configuration. ## Nginx and serve static resources directly @@ -93,7 +111,7 @@ or use a cdn for the static files. Set `[server] STATIC_URL_PREFIX = /_/static` in your configuration. -```apacheconf +```nginx server { listen 80; server_name git.example.com; @@ -112,7 +130,7 @@ server { Set `[server] STATIC_URL_PREFIX = http://cdn.example.com/gitea` in your configuration. -```apacheconf +```nginx # application server running Gitea server { listen 80; @@ -124,7 +142,7 @@ server { } ``` -```apacheconf +```nginx # static content delivery server server { listen 80; @@ -151,6 +169,8 @@ If you want Apache HTTPD to serve your Gitea instance, you can add the following ProxyRequests off AllowEncodedSlashes NoDecode ProxyPass / http://localhost:3000/ nocanon + ProxyPreserveHost On + RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME} </VirtualHost> ``` @@ -172,6 +192,8 @@ In case you already have a site, and you want Gitea to share the domain name, yo AllowEncodedSlashes NoDecode # Note: no trailing slash after either /git or port ProxyPass /git http://localhost:3000 nocanon + ProxyPreserveHost On + RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME} </VirtualHost> ``` @@ -183,7 +205,7 @@ Note: The following Apache HTTPD mods must be enabled: `proxy`, `proxy_http`. If you want Caddy to serve your Gitea instance, you can add the following server block to your Caddyfile: -```apacheconf +``` git.example.com { reverse_proxy localhost:3000 } @@ -193,7 +215,7 @@ git.example.com { In case you already have a site, and you want Gitea to share the domain name, you can setup Caddy to serve Gitea under a sub-path by adding the following to your server block in your Caddyfile: -```apacheconf +``` git.example.com { route /git/* { uri strip_prefix /git @@ -371,19 +393,3 @@ gitea: This config assumes that you are handling HTTPS on the traefik side and using HTTP between Gitea and traefik. Then you **MUST** set something like `[server] ROOT_URL = http://example.com/gitea/` correctly in your configuration. - -## General sub-path configuration - -Usually it's not recommended to put Gitea in a sub-path, it's not widely used and may have some issues in rare cases. - -If you really need to do so, to make Gitea works with sub-path (eg: `http://example.com/gitea/`), here are the requirements: - -1. Set `[server] ROOT_URL = http://example.com/gitea/` in your `app.ini` file. -2. Make the reverse-proxy pass `http://example.com/gitea/foo` to `http://gitea-server:3000/foo`. -3. Make sure the reverse-proxy not decode the URI, the request `http://example.com/gitea/a%2Fb` should be passed as `http://gitea-server:3000/a%2Fb`. - -## Docker / Container Registry - -The container registry uses a fixed sub-path `/v2` which can't be changed. -Even if you deploy Gitea with a different sub-path, `/v2` will be used by the `docker` client. -Therefore you may need to add an additional route to your reverse proxy configuration. diff --git a/modules/httplib/url.go b/modules/httplib/url.go index 541c4f325b..8dc5b71181 100644 --- a/modules/httplib/url.go +++ b/modules/httplib/url.go @@ -32,7 +32,7 @@ func IsRelativeURL(s string) bool { return err == nil && urlIsRelative(s, u) } -func guessRequestScheme(req *http.Request, def string) string { +func getRequestScheme(req *http.Request) string { // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto if s := req.Header.Get("X-Forwarded-Proto"); s != "" { return s @@ -49,10 +49,10 @@ func guessRequestScheme(req *http.Request, def string) string { if s := req.Header.Get("X-Forwarded-Ssl"); s != "" { return util.Iif(s == "on", "https", "http") } - return def + return "" } -func guessForwardedHost(req *http.Request) string { +func getForwardedHost(req *http.Request) string { // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host return req.Header.Get("X-Forwarded-Host") } @@ -63,15 +63,24 @@ func GuessCurrentAppURL(ctx context.Context) string { if !ok { return setting.AppURL } - if host := guessForwardedHost(req); host != "" { - // if it is behind a reverse proxy, use "https" as default scheme in case the site admin forgets to set the correct forwarded-protocol headers - return guessRequestScheme(req, "https") + "://" + host + setting.AppSubURL + "/" - } else if req.Host != "" { - // if it is not behind a reverse proxy, use the scheme from config options, meanwhile use "https" as much as possible - defaultScheme := util.Iif(setting.Protocol == "http", "http", "https") - return guessRequestScheme(req, defaultScheme) + "://" + req.Host + setting.AppSubURL + "/" + // If no scheme provided by reverse proxy, then do not guess the AppURL, use the configured one. + // At the moment, if site admin doesn't configure the proxy headers correctly, then Gitea would guess wrong. + // There are some cases: + // 1. The reverse proxy is configured correctly, it passes "X-Forwarded-Proto/Host" headers. Perfect, Gitea can handle it correctly. + // 2. The reverse proxy is not configured correctly, doesn't pass "X-Forwarded-Proto/Host" headers, eg: only one "proxy_pass http://gitea:3000" in Nginx. + // 3. There is no reverse proxy. + // Without an extra config option, Gitea is impossible to distinguish between case 2 and case 3, + // then case 2 would result in wrong guess like guessed AppURL becomes "http://gitea:3000/", which is not accessible by end users. + // So in the future maybe it should introduce a new config option, to let site admin decide how to guess the AppURL. + reqScheme := getRequestScheme(req) + if reqScheme == "" { + return setting.AppURL } - return setting.AppURL + reqHost := getForwardedHost(req) + if reqHost == "" { + reqHost = req.Host + } + return reqScheme + "://" + reqHost + setting.AppSubURL + "/" } func MakeAbsoluteURL(ctx context.Context, s string) string { diff --git a/modules/httplib/url_test.go b/modules/httplib/url_test.go index e021cd610d..9980cb74e8 100644 --- a/modules/httplib/url_test.go +++ b/modules/httplib/url_test.go @@ -41,19 +41,19 @@ func TestIsRelativeURL(t *testing.T) { func TestMakeAbsoluteURL(t *testing.T) { defer test.MockVariableValue(&setting.Protocol, "http")() - defer test.MockVariableValue(&setting.AppURL, "http://the-host/sub/")() + defer test.MockVariableValue(&setting.AppURL, "http://cfg-host/sub/")() defer test.MockVariableValue(&setting.AppSubURL, "/sub")() ctx := context.Background() - assert.Equal(t, "http://the-host/sub/", MakeAbsoluteURL(ctx, "")) - assert.Equal(t, "http://the-host/sub/foo", MakeAbsoluteURL(ctx, "foo")) - assert.Equal(t, "http://the-host/sub/foo", MakeAbsoluteURL(ctx, "/foo")) + assert.Equal(t, "http://cfg-host/sub/", MakeAbsoluteURL(ctx, "")) + assert.Equal(t, "http://cfg-host/sub/foo", MakeAbsoluteURL(ctx, "foo")) + assert.Equal(t, "http://cfg-host/sub/foo", MakeAbsoluteURL(ctx, "/foo")) assert.Equal(t, "http://other/foo", MakeAbsoluteURL(ctx, "http://other/foo")) ctx = context.WithValue(ctx, RequestContextKey, &http.Request{ Host: "user-host", }) - assert.Equal(t, "http://user-host/sub/foo", MakeAbsoluteURL(ctx, "/foo")) + assert.Equal(t, "http://cfg-host/sub/foo", MakeAbsoluteURL(ctx, "/foo")) ctx = context.WithValue(ctx, RequestContextKey, &http.Request{ Host: "user-host", @@ -61,7 +61,7 @@ func TestMakeAbsoluteURL(t *testing.T) { "X-Forwarded-Host": {"forwarded-host"}, }, }) - assert.Equal(t, "https://forwarded-host/sub/foo", MakeAbsoluteURL(ctx, "/foo")) + assert.Equal(t, "http://cfg-host/sub/foo", MakeAbsoluteURL(ctx, "/foo")) ctx = context.WithValue(ctx, RequestContextKey, &http.Request{ Host: "user-host", diff --git a/routers/api/packages/container/container.go b/routers/api/packages/container/container.go index 1efd166eb3..2a6d44ba08 100644 --- a/routers/api/packages/container/container.go +++ b/routers/api/packages/container/container.go @@ -116,6 +116,8 @@ func apiErrorDefined(ctx *context.Context, err *namedError) { } func apiUnauthorizedError(ctx *context.Context) { + // TODO: it doesn't seem quite right but it doesn't really cause problem at the moment. + // container registry requires that the "/v2" must be in the root, so the sub-path in AppURL should be removed, ideally. ctx.Resp.Header().Add("WWW-Authenticate", `Bearer realm="`+httplib.GuessCurrentAppURL(ctx)+`v2/token",service="container_registry",scope="*"`) apiErrorDefined(ctx, errUnauthorized) } diff --git a/routers/web/admin/admin_test.go b/routers/web/admin/admin_test.go index 782126adf5..6c38f0b509 100644 --- a/routers/web/admin/admin_test.go +++ b/routers/web/admin/admin_test.go @@ -87,6 +87,6 @@ func TestSelfCheckPost(t *testing.T) { err := json.Unmarshal(resp.Body.Bytes(), &data) assert.NoError(t, err) assert.Equal(t, []string{ - ctx.Locale.TrString("admin.self_check.location_origin_mismatch", "http://frontend/sub/", "http://host/sub/"), + ctx.Locale.TrString("admin.self_check.location_origin_mismatch", "http://frontend/sub/", "http://config/sub/"), }, data.Problems) } From 82a0c36332824b8ab41efdf6503e86170ce92f08 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Mon, 20 May 2024 00:25:39 +0000 Subject: [PATCH 329/370] [skip ci] Updated licenses and gitignores --- options/license/3D-Slicer-1.0 | 190 ++++++++++++++++++ .../Asterisk-linking-protocols-exception | 13 ++ options/license/HPND-Intel | 25 +++ .../license/HPND-export-US-acknowledgement | 22 ++ options/license/NCBI-PD | 19 ++ 5 files changed, 269 insertions(+) create mode 100644 options/license/3D-Slicer-1.0 create mode 100644 options/license/Asterisk-linking-protocols-exception create mode 100644 options/license/HPND-Intel create mode 100644 options/license/HPND-export-US-acknowledgement create mode 100644 options/license/NCBI-PD diff --git a/options/license/3D-Slicer-1.0 b/options/license/3D-Slicer-1.0 new file mode 100644 index 0000000000..38bd5230c6 --- /dev/null +++ b/options/license/3D-Slicer-1.0 @@ -0,0 +1,190 @@ +3D Slicer Contribution and Software License Agreement ("Agreement") +Version 1.0 (December 20, 2005) + +This Agreement covers contributions to and downloads from the 3D +Slicer project ("Slicer") maintained by The Brigham and Women's +Hospital, Inc. ("Brigham"). Part A of this Agreement applies to +contributions of software and/or data to Slicer (including making +revisions of or additions to code and/or data already in Slicer). Part +B of this Agreement applies to downloads of software and/or data from +Slicer. Part C of this Agreement applies to all transactions with +Slicer. If you distribute Software (as defined below) downloaded from +Slicer, all of the paragraphs of Part B of this Agreement must be +included with and apply to such Software. + +Your contribution of software and/or data to Slicer (including prior +to the date of the first publication of this Agreement, each a +"Contribution") and/or downloading, copying, modifying, displaying, +distributing or use of any software and/or data from Slicer +(collectively, the "Software") constitutes acceptance of all of the +terms and conditions of this Agreement. If you do not agree to such +terms and conditions, you have no right to contribute your +Contribution, or to download, copy, modify, display, distribute or use +the Software. + +PART A. CONTRIBUTION AGREEMENT - License to Brigham with Right to +Sublicense ("Contribution Agreement"). + +1. As used in this Contribution Agreement, "you" means the individual + contributing the Contribution to Slicer and the institution or + entity which employs or is otherwise affiliated with such + individual in connection with such Contribution. + +2. This Contribution Agreement applies to all Contributions made to + Slicer, including without limitation Contributions made prior to + the date of first publication of this Agreement. If at any time you + make a Contribution to Slicer, you represent that (i) you are + legally authorized and entitled to make such Contribution and to + grant all licenses granted in this Contribution Agreement with + respect to such Contribution; (ii) if your Contribution includes + any patient data, all such data is de-identified in accordance with + U.S. confidentiality and security laws and requirements, including + but not limited to the Health Insurance Portability and + Accountability Act (HIPAA) and its regulations, and your disclosure + of such data for the purposes contemplated by this Agreement is + properly authorized and in compliance with all applicable laws and + regulations; and (iii) you have preserved in the Contribution all + applicable attributions, copyright notices and licenses for any + third party software or data included in the Contribution. + +3. Except for the licenses granted in this Agreement, you reserve all + right, title and interest in your Contribution. + +4. You hereby grant to Brigham, with the right to sublicense, a + perpetual, worldwide, non-exclusive, no charge, royalty-free, + irrevocable license to use, reproduce, make derivative works of, + display and distribute the Contribution. If your Contribution is + protected by patent, you hereby grant to Brigham, with the right to + sublicense, a perpetual, worldwide, non-exclusive, no-charge, + royalty-free, irrevocable license under your interest in patent + rights covering the Contribution, to make, have made, use, sell and + otherwise transfer your Contribution, alone or in combination with + any other code. + +5. You acknowledge and agree that Brigham may incorporate your + Contribution into Slicer and may make Slicer available to members + of the public on an open source basis under terms substantially in + accordance with the Software License set forth in Part B of this + Agreement. You further acknowledge and agree that Brigham shall + have no liability arising in connection with claims resulting from + your breach of any of the terms of this Agreement. + +6. YOU WARRANT THAT TO THE BEST OF YOUR KNOWLEDGE YOUR CONTRIBUTION + DOES NOT CONTAIN ANY CODE THAT REQUIRES OR PRESCRIBES AN "OPEN + SOURCE LICENSE" FOR DERIVATIVE WORKS (by way of non-limiting + example, the GNU General Public License or other so-called + "reciprocal" license that requires any derived work to be licensed + under the GNU General Public License or other "open source + license"). + +PART B. DOWNLOADING AGREEMENT - License from Brigham with Right to +Sublicense ("Software License"). + +1. As used in this Software License, "you" means the individual + downloading and/or using, reproducing, modifying, displaying and/or + distributing the Software and the institution or entity which + employs or is otherwise affiliated with such individual in + connection therewith. The Brigham and Women's Hospital, + Inc. ("Brigham") hereby grants you, with right to sublicense, with + respect to Brigham's rights in the software, and data, if any, + which is the subject of this Software License (collectively, the + "Software"), a royalty-free, non-exclusive license to use, + reproduce, make derivative works of, display and distribute the + Software, provided that: + +(a) you accept and adhere to all of the terms and conditions of this +Software License; + +(b) in connection with any copy of or sublicense of all or any portion +of the Software, all of the terms and conditions in this Software +License shall appear in and shall apply to such copy and such +sublicense, including without limitation all source and executable +forms and on any user documentation, prefaced with the following +words: "All or portions of this licensed product (such portions are +the "Software") have been obtained under license from The Brigham and +Women's Hospital, Inc. and are subject to the following terms and +conditions:" + +(c) you preserve and maintain all applicable attributions, copyright +notices and licenses included in or applicable to the Software; + +(d) modified versions of the Software must be clearly identified and +marked as such, and must not be misrepresented as being the original +Software; and + +(e) you consider making, but are under no obligation to make, the +source code of any of your modifications to the Software freely +available to others on an open source basis. + +2. The license granted in this Software License includes without + limitation the right to (i) incorporate the Software into + proprietary programs (subject to any restrictions applicable to + such programs), (ii) add your own copyright statement to your + modifications of the Software, and (iii) provide additional or + different license terms and conditions in your sublicenses of + modifications of the Software; provided that in each case your use, + reproduction or distribution of such modifications otherwise + complies with the conditions stated in this Software License. + +3. This Software License does not grant any rights with respect to + third party software, except those rights that Brigham has been + authorized by a third party to grant to you, and accordingly you + are solely responsible for (i) obtaining any permissions from third + parties that you need to use, reproduce, make derivative works of, + display and distribute the Software, and (ii) informing your + sublicensees, including without limitation your end-users, of their + obligations to secure any such required permissions. + +4. The Software has been designed for research purposes only and has + not been reviewed or approved by the Food and Drug Administration + or by any other agency. YOU ACKNOWLEDGE AND AGREE THAT CLINICAL + APPLICATIONS ARE NEITHER RECOMMENDED NOR ADVISED. Any + commercialization of the Software is at the sole risk of the party + or parties engaged in such commercialization. You further agree to + use, reproduce, make derivative works of, display and distribute + the Software in compliance with all applicable governmental laws, + regulations and orders, including without limitation those relating + to export and import control. + +5. The Software is provided "AS IS" and neither Brigham nor any + contributor to the software (each a "Contributor") shall have any + obligation to provide maintenance, support, updates, enhancements + or modifications thereto. BRIGHAM AND ALL CONTRIBUTORS SPECIFICALLY + DISCLAIM ALL EXPRESS AND IMPLIED WARRANTIES OF ANY KIND INCLUDING, + BUT NOT LIMITED TO, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR + A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + BRIGHAM OR ANY CONTRIBUTOR BE LIABLE TO ANY PARTY FOR DIRECT, + INDIRECT, SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY ARISING IN ANY WAY + RELATED TO THE SOFTWARE, EVEN IF BRIGHAM OR ANY CONTRIBUTOR HAS + BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. TO THE MAXIMUM + EXTENT NOT PROHIBITED BY LAW OR REGULATION, YOU FURTHER ASSUME ALL + LIABILITY FOR YOUR USE, REPRODUCTION, MAKING OF DERIVATIVE WORKS, + DISPLAY, LICENSE OR DISTRIBUTION OF THE SOFTWARE AND AGREE TO + INDEMNIFY AND HOLD HARMLESS BRIGHAM AND ALL CONTRIBUTORS FROM AND + AGAINST ANY AND ALL CLAIMS, SUITS, ACTIONS, DEMANDS AND JUDGMENTS + ARISING THEREFROM. + +6. None of the names, logos or trademarks of Brigham or any of + Brigham's affiliates or any of the Contributors, or any funding + agency, may be used to endorse or promote products produced in + whole or in part by operation of the Software or derived from or + based on the Software without specific prior written permission + from the applicable party. + +7. Any use, reproduction or distribution of the Software which is not + in accordance with this Software License shall automatically revoke + all rights granted to you under this Software License and render + Paragraphs 1 and 2 of this Software License null and void. + +8. This Software License does not grant any rights in or to any + intellectual property owned by Brigham or any Contributor except + those rights expressly granted hereunder. + +PART C. MISCELLANEOUS + +This Agreement shall be governed by and construed in accordance with +the laws of The Commonwealth of Massachusetts without regard to +principles of conflicts of law. This Agreement shall supercede and +replace any license terms that you may have agreed to previously with +respect to Slicer. diff --git a/options/license/Asterisk-linking-protocols-exception b/options/license/Asterisk-linking-protocols-exception new file mode 100644 index 0000000000..6705829f47 --- /dev/null +++ b/options/license/Asterisk-linking-protocols-exception @@ -0,0 +1,13 @@ +Specific permission is also granted to link Asterisk with OpenSSL, OpenH323 +UniMRCP, and/or the UW IMAP Toolkit and distribute the resulting binary files. + +In addition, Asterisk implements several management/control protocols. +This includes the Asterisk Manager Interface (AMI), the Asterisk Gateway +Interface (AGI), and the Asterisk REST Interface (ARI). It is our belief +that applications using these protocols to manage or control an Asterisk +instance do not have to be licensed under the GPL or a compatible license, +as we believe these protocols do not create a 'derivative work' as referred +to in the GPL. However, should any court or other judiciary body find that +these protocols do fall under the terms of the GPL, then we hereby grant you a +license to use these protocols in combination with Asterisk in external +applications licensed under any license you wish. diff --git a/options/license/HPND-Intel b/options/license/HPND-Intel new file mode 100644 index 0000000000..98f0ceb4fd --- /dev/null +++ b/options/license/HPND-Intel @@ -0,0 +1,25 @@ +Copyright (c) 1993 Intel Corporation + +Intel hereby grants you permission to copy, modify, and distribute this +software and its documentation. Intel grants this permission provided +that the above copyright notice appears in all copies and that both the +copyright notice and this permission notice appear in supporting +documentation. In addition, Intel grants this permission provided that +you prominently mark as "not part of the original" any modifications +made to this software or documentation, and that the name of Intel +Corporation not be used in advertising or publicity pertaining to +distribution of the software or the documentation without specific, +written prior permission. + +Intel Corporation provides this AS IS, WITHOUT ANY WARRANTY, EXPRESS OR +IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY +OR FITNESS FOR A PARTICULAR PURPOSE. Intel makes no guarantee or +representations regarding the use of, or the results of the use of, +the software and documentation in terms of correctness, accuracy, +reliability, currentness, or otherwise; and you rely on the software, +documentation and results solely at your own risk. + +IN NO EVENT SHALL INTEL BE LIABLE FOR ANY LOSS OF USE, LOSS OF BUSINESS, +LOSS OF PROFITS, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES +OF ANY KIND. IN NO EVENT SHALL INTEL'S TOTAL LIABILITY EXCEED THE SUM +PAID TO INTEL FOR THE PRODUCT LICENSED HEREUNDER. diff --git a/options/license/HPND-export-US-acknowledgement b/options/license/HPND-export-US-acknowledgement new file mode 100644 index 0000000000..645df4c9aa --- /dev/null +++ b/options/license/HPND-export-US-acknowledgement @@ -0,0 +1,22 @@ +Copyright (C) 1994 by the University of Southern California + + EXPORT OF THIS SOFTWARE from the United States of America may + require a specific license from the United States Government. It + is the responsibility of any person or organization + contemplating export to obtain such a license before exporting. + +WITHIN THAT CONSTRAINT, permission to copy, modify, and distribute +this software and its documentation in source and binary forms is +hereby granted, provided that any documentation or other materials +related to such distribution or use acknowledge that the software +was developed by the University of Southern California. + +DISCLAIMER OF WARRANTY. THIS SOFTWARE IS PROVIDED "AS IS". The +University of Southern California MAKES NO REPRESENTATIONS OR +WARRANTIES, EXPRESS OR IMPLIED. By way of example, but not +limitation, the University of Southern California MAKES NO +REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY +PARTICULAR PURPOSE. The University of Southern California shall not +be held liable for any liability nor for any direct, indirect, or +consequential damages with respect to any claim by the user or +distributor of the ksu software. diff --git a/options/license/NCBI-PD b/options/license/NCBI-PD new file mode 100644 index 0000000000..d838cf36b9 --- /dev/null +++ b/options/license/NCBI-PD @@ -0,0 +1,19 @@ +PUBLIC DOMAIN NOTICE +National Center for Biotechnology Information + +This software is a "United States Government Work" under the terms of the +United States Copyright Act. It was written as part of the authors' +official duties as United States Government employees and thus cannot +be copyrighted. This software is freely available to the public for +use. The National Library of Medicine and the U.S. Government have not +placed any restriction on its use or reproduction. + +Although all reasonable efforts have been taken to ensure the accuracy +and reliability of the software and data, the NLM and the U.S. +Government do not and cannot warrant the performance or results that +may be obtained by using this software or data. The NLM and the U.S. +Government disclaim all warranties, express or implied, including +warranties of performance, merchantability or fitness for any +particular purpose. + +Please cite the author in any work or product based on this material. From edbf74c418061b013a5855f604dd6be6baf34132 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Mon, 20 May 2024 08:56:45 +0800 Subject: [PATCH 330/370] Fix "force private" logic (#31012) When creating a repo, the "FORCE_PRIVATE" config option should be respected, `readonly` doesn't work for checkbox, so it should use `disabled` attribute. --- routers/api/v1/repo/migrate.go | 2 +- routers/api/v1/repo/repo.go | 4 ++-- routers/web/repo/repo.go | 2 +- services/migrations/gitea_uploader.go | 2 +- services/repository/repository.go | 2 +- services/task/task.go | 2 +- templates/repo/create.tmpl | 2 +- templates/repo/migrate/codebase.tmpl | 2 +- templates/repo/migrate/git.tmpl | 2 +- templates/repo/migrate/gitbucket.tmpl | 2 +- templates/repo/migrate/gitea.tmpl | 2 +- templates/repo/migrate/github.tmpl | 2 +- templates/repo/migrate/gitlab.tmpl | 2 +- templates/repo/migrate/gogs.tmpl | 2 +- templates/repo/migrate/onedev.tmpl | 2 +- templates/repo/settings/options.tmpl | 5 +++-- 16 files changed, 19 insertions(+), 18 deletions(-) diff --git a/routers/api/v1/repo/migrate.go b/routers/api/v1/repo/migrate.go index f246b08c0a..14c8c01f4e 100644 --- a/routers/api/v1/repo/migrate.go +++ b/routers/api/v1/repo/migrate.go @@ -175,7 +175,7 @@ func Migrate(ctx *context.APIContext) { Description: opts.Description, OriginalURL: form.CloneAddr, GitServiceType: gitServiceType, - IsPrivate: opts.Private, + IsPrivate: opts.Private || setting.Repository.ForcePrivate, IsMirror: opts.Mirror, Status: repo_model.RepositoryBeingMigrated, }) diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index e759142938..594f2d86f6 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -252,7 +252,7 @@ func CreateUserRepo(ctx *context.APIContext, owner *user_model.User, opt api.Cre Gitignores: opt.Gitignores, License: opt.License, Readme: opt.Readme, - IsPrivate: opt.Private, + IsPrivate: opt.Private || setting.Repository.ForcePrivate, AutoInit: opt.AutoInit, DefaultBranch: opt.DefaultBranch, TrustModel: repo_model.ToTrustModel(opt.TrustModel), @@ -364,7 +364,7 @@ func Generate(ctx *context.APIContext) { Name: form.Name, DefaultBranch: form.DefaultBranch, Description: form.Description, - Private: form.Private, + Private: form.Private || setting.Repository.ForcePrivate, GitContent: form.GitContent, Topics: form.Topics, GitHooks: form.GitHooks, diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index 48be1c2296..71c582b5f9 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -248,7 +248,7 @@ func CreatePost(ctx *context.Context) { opts := repo_service.GenerateRepoOptions{ Name: form.RepoName, Description: form.Description, - Private: form.Private, + Private: form.Private || setting.Repository.ForcePrivate, GitContent: form.GitContent, Topics: form.Topics, GitHooks: form.GitHooks, diff --git a/services/migrations/gitea_uploader.go b/services/migrations/gitea_uploader.go index c63383f5ca..4c8e036f05 100644 --- a/services/migrations/gitea_uploader.go +++ b/services/migrations/gitea_uploader.go @@ -107,7 +107,7 @@ func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, opts base.Migrate Description: repo.Description, OriginalURL: repo.OriginalURL, GitServiceType: opts.GitServiceType, - IsPrivate: opts.Private, + IsPrivate: opts.Private || setting.Repository.ForcePrivate, IsMirror: opts.Mirror, Status: repo_model.RepositoryBeingMigrated, }) diff --git a/services/repository/repository.go b/services/repository/repository.go index d28200c0ad..b7aac3cfe0 100644 --- a/services/repository/repository.go +++ b/services/repository/repository.go @@ -85,7 +85,7 @@ func PushCreateRepo(ctx context.Context, authUser, owner *user_model.User, repoN repo, err := CreateRepository(ctx, authUser, owner, CreateRepoOptions{ Name: repoName, - IsPrivate: setting.Repository.DefaultPushCreatePrivate, + IsPrivate: setting.Repository.DefaultPushCreatePrivate || setting.Repository.ForcePrivate, }) if err != nil { return nil, err diff --git a/services/task/task.go b/services/task/task.go index e15cab7b3c..c90ee91270 100644 --- a/services/task/task.go +++ b/services/task/task.go @@ -107,7 +107,7 @@ func CreateMigrateTask(ctx context.Context, doer, u *user_model.User, opts base. Description: opts.Description, OriginalURL: opts.OriginalURL, GitServiceType: opts.GitServiceType, - IsPrivate: opts.Private, + IsPrivate: opts.Private || setting.Repository.ForcePrivate, IsMirror: opts.Mirror, Status: repo_model.RepositoryBeingMigrated, }) diff --git a/templates/repo/create.tmpl b/templates/repo/create.tmpl index c1c8c2185e..2e1de244ea 100644 --- a/templates/repo/create.tmpl +++ b/templates/repo/create.tmpl @@ -50,7 +50,7 @@ <label>{{ctx.Locale.Tr "repo.visibility"}}</label> <div class="ui checkbox"> {{if .IsForcedPrivate}} - <input name="private" type="checkbox" checked readonly> + <input name="private" type="checkbox" checked disabled> <label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label> {{else}} <input name="private" type="checkbox" {{if .private}}checked{{end}}> diff --git a/templates/repo/migrate/codebase.tmpl b/templates/repo/migrate/codebase.tmpl index 439a883863..c8059b7c7b 100644 --- a/templates/repo/migrate/codebase.tmpl +++ b/templates/repo/migrate/codebase.tmpl @@ -89,7 +89,7 @@ <label>{{ctx.Locale.Tr "repo.visibility"}}</label> <div class="ui checkbox"> {{if .IsForcedPrivate}} - <input name="private" type="checkbox" checked readonly> + <input name="private" type="checkbox" checked disabled> <label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label> {{else}} <input name="private" type="checkbox" {{if .private}}checked{{end}}> diff --git a/templates/repo/migrate/git.tmpl b/templates/repo/migrate/git.tmpl index db01b8d858..9c5f0d7d6d 100644 --- a/templates/repo/migrate/git.tmpl +++ b/templates/repo/migrate/git.tmpl @@ -63,7 +63,7 @@ <label>{{ctx.Locale.Tr "repo.visibility"}}</label> <div class="ui checkbox"> {{if .IsForcedPrivate}} - <input name="private" type="checkbox" checked readonly> + <input name="private" type="checkbox" checked disabled> <label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label> {{else}} <input name="private" type="checkbox" {{if .private}}checked{{end}}> diff --git a/templates/repo/migrate/gitbucket.tmpl b/templates/repo/migrate/gitbucket.tmpl index d1f1db99ba..b667fa828a 100644 --- a/templates/repo/migrate/gitbucket.tmpl +++ b/templates/repo/migrate/gitbucket.tmpl @@ -105,7 +105,7 @@ <label>{{ctx.Locale.Tr "repo.visibility"}}</label> <div class="ui checkbox"> {{if .IsForcedPrivate}} - <input name="private" type="checkbox" checked readonly> + <input name="private" type="checkbox" checked disabled> <label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label> {{else}} <input name="private" type="checkbox" {{if .private}}checked{{end}}> diff --git a/templates/repo/migrate/gitea.tmpl b/templates/repo/migrate/gitea.tmpl index 143f220449..3b8f377096 100644 --- a/templates/repo/migrate/gitea.tmpl +++ b/templates/repo/migrate/gitea.tmpl @@ -101,7 +101,7 @@ <label>{{ctx.Locale.Tr "repo.visibility"}}</label> <div class="ui checkbox"> {{if .IsForcedPrivate}} - <input name="private" type="checkbox" checked readonly> + <input name="private" type="checkbox" checked disabled> <label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label> {{else}} <input name="private" type="checkbox" {{if .private}} checked{{end}}> diff --git a/templates/repo/migrate/github.tmpl b/templates/repo/migrate/github.tmpl index dfb2b4bc46..3535eddfc2 100644 --- a/templates/repo/migrate/github.tmpl +++ b/templates/repo/migrate/github.tmpl @@ -103,7 +103,7 @@ <label>{{ctx.Locale.Tr "repo.visibility"}}</label> <div class="ui checkbox"> {{if .IsForcedPrivate}} - <input name="private" type="checkbox" checked readonly> + <input name="private" type="checkbox" checked disabled> <label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label> {{else}} <input name="private" type="checkbox" {{if .private}}checked{{end}}> diff --git a/templates/repo/migrate/gitlab.tmpl b/templates/repo/migrate/gitlab.tmpl index 76c2828257..f705fb3090 100644 --- a/templates/repo/migrate/gitlab.tmpl +++ b/templates/repo/migrate/gitlab.tmpl @@ -100,7 +100,7 @@ <label>{{ctx.Locale.Tr "repo.visibility"}}</label> <div class="ui checkbox"> {{if .IsForcedPrivate}} - <input name="private" type="checkbox" checked readonly> + <input name="private" type="checkbox" checked disabled> <label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label> {{else}} <input name="private" type="checkbox" {{if .private}}checked{{end}}> diff --git a/templates/repo/migrate/gogs.tmpl b/templates/repo/migrate/gogs.tmpl index b01d0eeb67..eca83b1636 100644 --- a/templates/repo/migrate/gogs.tmpl +++ b/templates/repo/migrate/gogs.tmpl @@ -103,7 +103,7 @@ <label>{{ctx.Locale.Tr "repo.visibility"}}</label> <div class="ui checkbox"> {{if .IsForcedPrivate}} - <input name="private" type="checkbox" checked readonly> + <input name="private" type="checkbox" checked disabled> <label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label> {{else}} <input name="private" type="checkbox" {{if .private}} checked{{end}}> diff --git a/templates/repo/migrate/onedev.tmpl b/templates/repo/migrate/onedev.tmpl index 8b2a2d8730..e1aad96ba4 100644 --- a/templates/repo/migrate/onedev.tmpl +++ b/templates/repo/migrate/onedev.tmpl @@ -89,7 +89,7 @@ <label>{{ctx.Locale.Tr "repo.visibility"}}</label> <div class="ui checkbox"> {{if .IsForcedPrivate}} - <input name="private" type="checkbox" checked readonly> + <input name="private" type="checkbox" checked disabled> <label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label> {{else}} <input name="private" type="checkbox" {{if .private}}checked{{end}}> diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index b94c202f16..3168384072 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -28,9 +28,10 @@ <label>{{ctx.Locale.Tr "repo.visibility"}}</label> <div class="ui checkbox" {{if and (not .Repository.IsPrivate) (gt .Repository.NumStars 0)}}data-tooltip-content="{{ctx.Locale.Tr "repo.stars_remove_warning"}}"{{end}}> {{if .IsAdmin}} - <input name="private" type="checkbox" {{if .Repository.IsPrivate}}checked{{end}}> + <input name="private" type="checkbox" {{if .Repository.IsPrivate}}checked{{end}}> {{else}} - <input name="private" type="checkbox" {{if .Repository.IsPrivate}}checked{{end}}{{if and $.ForcePrivate .Repository.IsPrivate}} readonly{{end}}> + <input name="private" type="checkbox" {{if .Repository.IsPrivate}}checked{{end}}{{if and $.ForcePrivate .Repository.IsPrivate}} disabled{{end}}> + {{if and .Repository.IsPrivate $.ForcePrivate}}<input type="hidden" name="private" value="{{.Repository.IsPrivate}}">{{end}} {{end}} <label>{{ctx.Locale.Tr "repo.visibility_helper"}} {{if .Repository.NumForks}}<span class="text red">{{ctx.Locale.Tr "repo.visibility_fork_helper"}}</span>{{end}}</label> </div> From 47accfebbd69e5f47d1b97a3e39cf181fab7e597 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Mon, 20 May 2024 12:35:38 +0800 Subject: [PATCH 331/370] Fix data-race during testing (#30999) Fix #30992 --- models/unit/unit.go | 26 ++++++++++++++++++++------ models/unit/unit_test.go | 24 ++++++++++++------------ tests/integration/org_project_test.go | 6 ++++-- 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/models/unit/unit.go b/models/unit/unit.go index a78a2f1e47..74efa4caf0 100644 --- a/models/unit/unit.go +++ b/models/unit/unit.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "strings" + "sync/atomic" "code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/modules/container" @@ -106,10 +107,23 @@ var ( TypeExternalTracker, } - // DisabledRepoUnits contains the units that have been globally disabled - DisabledRepoUnits = []Type{} + disabledRepoUnitsAtomic atomic.Pointer[[]Type] // the units that have been globally disabled ) +// DisabledRepoUnitsGet returns the globally disabled units, it is a quick patch to fix data-race during testing. +// Because the queue worker might read when a test is mocking the value. FIXME: refactor to a clear solution later. +func DisabledRepoUnitsGet() []Type { + v := disabledRepoUnitsAtomic.Load() + if v == nil { + return nil + } + return *v +} + +func DisabledRepoUnitsSet(v []Type) { + disabledRepoUnitsAtomic.Store(&v) +} + // Get valid set of default repository units from settings func validateDefaultRepoUnits(defaultUnits, settingDefaultUnits []Type) []Type { units := defaultUnits @@ -127,7 +141,7 @@ func validateDefaultRepoUnits(defaultUnits, settingDefaultUnits []Type) []Type { } // Remove disabled units - for _, disabledUnit := range DisabledRepoUnits { + for _, disabledUnit := range DisabledRepoUnitsGet() { for i, unit := range units { if unit == disabledUnit { units = append(units[:i], units[i+1:]...) @@ -140,11 +154,11 @@ func validateDefaultRepoUnits(defaultUnits, settingDefaultUnits []Type) []Type { // LoadUnitConfig load units from settings func LoadUnitConfig() error { - var invalidKeys []string - DisabledRepoUnits, invalidKeys = FindUnitTypes(setting.Repository.DisabledRepoUnits...) + disabledRepoUnits, invalidKeys := FindUnitTypes(setting.Repository.DisabledRepoUnits...) if len(invalidKeys) > 0 { log.Warn("Invalid keys in disabled repo units: %s", strings.Join(invalidKeys, ", ")) } + DisabledRepoUnitsSet(disabledRepoUnits) setDefaultRepoUnits, invalidKeys := FindUnitTypes(setting.Repository.DefaultRepoUnits...) if len(invalidKeys) > 0 { @@ -167,7 +181,7 @@ func LoadUnitConfig() error { // UnitGlobalDisabled checks if unit type is global disabled func (u Type) UnitGlobalDisabled() bool { - for _, ud := range DisabledRepoUnits { + for _, ud := range DisabledRepoUnitsGet() { if u == ud { return true } diff --git a/models/unit/unit_test.go b/models/unit/unit_test.go index d80d8b118d..7bf6326145 100644 --- a/models/unit/unit_test.go +++ b/models/unit/unit_test.go @@ -14,10 +14,10 @@ import ( func TestLoadUnitConfig(t *testing.T) { t.Run("regular", func(t *testing.T) { defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) { - DisabledRepoUnits = disabledRepoUnits + DisabledRepoUnitsSet(disabledRepoUnits) DefaultRepoUnits = defaultRepoUnits DefaultForkRepoUnits = defaultForkRepoUnits - }(DisabledRepoUnits, DefaultRepoUnits, DefaultForkRepoUnits) + }(DisabledRepoUnitsGet(), DefaultRepoUnits, DefaultForkRepoUnits) defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) { setting.Repository.DisabledRepoUnits = disabledRepoUnits setting.Repository.DefaultRepoUnits = defaultRepoUnits @@ -28,16 +28,16 @@ func TestLoadUnitConfig(t *testing.T) { setting.Repository.DefaultRepoUnits = []string{"repo.code", "repo.releases", "repo.issues", "repo.pulls"} setting.Repository.DefaultForkRepoUnits = []string{"repo.releases"} assert.NoError(t, LoadUnitConfig()) - assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnits) + assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnitsGet()) assert.Equal(t, []Type{TypeCode, TypeReleases, TypePullRequests}, DefaultRepoUnits) assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits) }) t.Run("invalid", func(t *testing.T) { defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) { - DisabledRepoUnits = disabledRepoUnits + DisabledRepoUnitsSet(disabledRepoUnits) DefaultRepoUnits = defaultRepoUnits DefaultForkRepoUnits = defaultForkRepoUnits - }(DisabledRepoUnits, DefaultRepoUnits, DefaultForkRepoUnits) + }(DisabledRepoUnitsGet(), DefaultRepoUnits, DefaultForkRepoUnits) defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) { setting.Repository.DisabledRepoUnits = disabledRepoUnits setting.Repository.DefaultRepoUnits = defaultRepoUnits @@ -48,16 +48,16 @@ func TestLoadUnitConfig(t *testing.T) { setting.Repository.DefaultRepoUnits = []string{"repo.code", "invalid.2", "repo.releases", "repo.issues", "repo.pulls"} setting.Repository.DefaultForkRepoUnits = []string{"invalid.3", "repo.releases"} assert.NoError(t, LoadUnitConfig()) - assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnits) + assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnitsGet()) assert.Equal(t, []Type{TypeCode, TypeReleases, TypePullRequests}, DefaultRepoUnits) assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits) }) t.Run("duplicate", func(t *testing.T) { defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) { - DisabledRepoUnits = disabledRepoUnits + DisabledRepoUnitsSet(disabledRepoUnits) DefaultRepoUnits = defaultRepoUnits DefaultForkRepoUnits = defaultForkRepoUnits - }(DisabledRepoUnits, DefaultRepoUnits, DefaultForkRepoUnits) + }(DisabledRepoUnitsGet(), DefaultRepoUnits, DefaultForkRepoUnits) defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) { setting.Repository.DisabledRepoUnits = disabledRepoUnits setting.Repository.DefaultRepoUnits = defaultRepoUnits @@ -68,16 +68,16 @@ func TestLoadUnitConfig(t *testing.T) { setting.Repository.DefaultRepoUnits = []string{"repo.code", "repo.releases", "repo.issues", "repo.pulls", "repo.code"} setting.Repository.DefaultForkRepoUnits = []string{"repo.releases", "repo.releases"} assert.NoError(t, LoadUnitConfig()) - assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnits) + assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnitsGet()) assert.Equal(t, []Type{TypeCode, TypeReleases, TypePullRequests}, DefaultRepoUnits) assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits) }) t.Run("empty_default", func(t *testing.T) { defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) { - DisabledRepoUnits = disabledRepoUnits + DisabledRepoUnitsSet(disabledRepoUnits) DefaultRepoUnits = defaultRepoUnits DefaultForkRepoUnits = defaultForkRepoUnits - }(DisabledRepoUnits, DefaultRepoUnits, DefaultForkRepoUnits) + }(DisabledRepoUnitsGet(), DefaultRepoUnits, DefaultForkRepoUnits) defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) { setting.Repository.DisabledRepoUnits = disabledRepoUnits setting.Repository.DefaultRepoUnits = defaultRepoUnits @@ -88,7 +88,7 @@ func TestLoadUnitConfig(t *testing.T) { setting.Repository.DefaultRepoUnits = []string{} setting.Repository.DefaultForkRepoUnits = []string{"repo.releases", "repo.releases"} assert.NoError(t, LoadUnitConfig()) - assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnits) + assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnitsGet()) assert.ElementsMatch(t, []Type{TypeCode, TypePullRequests, TypeReleases, TypeWiki, TypePackages, TypeProjects, TypeActions}, DefaultRepoUnits) assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits) }) diff --git a/tests/integration/org_project_test.go b/tests/integration/org_project_test.go index ca39cf5130..31d10f16ff 100644 --- a/tests/integration/org_project_test.go +++ b/tests/integration/org_project_test.go @@ -9,13 +9,15 @@ import ( "testing" unit_model "code.gitea.io/gitea/models/unit" - "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/tests" ) func TestOrgProjectAccess(t *testing.T) { defer tests.PrepareTestEnv(t)() - defer test.MockVariableValue(&unit_model.DisabledRepoUnits, append(slices.Clone(unit_model.DisabledRepoUnits), unit_model.TypeProjects))() + + disabledRepoUnits := unit_model.DisabledRepoUnitsGet() + unit_model.DisabledRepoUnitsSet(append(slices.Clone(disabledRepoUnits), unit_model.TypeProjects)) + defer unit_model.DisabledRepoUnitsSet(disabledRepoUnits) // repo project, 404 req := NewRequest(t, "GET", "/user2/repo1/projects") From b6574099edbb47e119762700f637c8da349cca2b Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Mon, 20 May 2024 13:21:01 +0800 Subject: [PATCH 332/370] Fix project column title overflow (#31011) By the way: * Re-format the "color.go" to Golang code style * Remove unused `overflow-y: scroll;` from `.project-column` because there is `overflow: visible` --- modules/util/color.go | 9 +++++---- templates/projects/view.tmpl | 16 ++++++---------- web_src/css/features/projects.css | 13 +++++-------- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/modules/util/color.go b/modules/util/color.go index 9c520dce78..8fffc91ac4 100644 --- a/modules/util/color.go +++ b/modules/util/color.go @@ -1,5 +1,6 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT + package util import ( @@ -8,7 +9,7 @@ import ( "strings" ) -// Get color as RGB values in 0..255 range from the hex color string (with or without #) +// HexToRBGColor parses color as RGB values in 0..255 range from the hex color string (with or without #) func HexToRBGColor(colorString string) (float64, float64, float64) { hexString := colorString if strings.HasPrefix(colorString, "#") { @@ -35,7 +36,7 @@ func HexToRBGColor(colorString string) (float64, float64, float64) { return r, g, b } -// Returns relative luminance for a SRGB color - https://en.wikipedia.org/wiki/Relative_luminance +// GetRelativeLuminance returns relative luminance for a SRGB color - https://en.wikipedia.org/wiki/Relative_luminance // Keep this in sync with web_src/js/utils/color.js func GetRelativeLuminance(color string) float64 { r, g, b := HexToRBGColor(color) @@ -46,8 +47,8 @@ func UseLightText(backgroundColor string) bool { return GetRelativeLuminance(backgroundColor) < 0.453 } -// Given a background color, returns a black or white foreground color that the highest -// contrast ratio. In the future, the APCA contrast function, or CSS `contrast-color` will be better. +// ContrastColor returns a black or white foreground color that the highest contrast ratio. +// In the future, the APCA contrast function, or CSS `contrast-color` will be better. // https://github.com/color-js/color.js/blob/eb7b53f7a13bb716ec8b28c7a56f052cd599acd9/src/contrast/APCA.js#L42 func ContrastColor(backgroundColor string) string { if UseLightText(backgroundColor) { diff --git a/templates/projects/view.tmpl b/templates/projects/view.tmpl index 47f214a44e..45c8461218 100644 --- a/templates/projects/view.tmpl +++ b/templates/projects/view.tmpl @@ -68,18 +68,14 @@ {{range .Columns}} <div class="ui segment project-column"{{if .Color}} style="background: {{.Color}} !important; color: {{ContrastColor .Color}} !important"{{end}} data-id="{{.ID}}" data-sorting="{{.Sorting}}" data-url="{{$.Link}}/{{.ID}}"> <div class="project-column-header{{if $canWriteProject}} tw-cursor-grab{{end}}"> - <div class="ui large label project-column-title tw-py-1"> - <div class="ui small circular grey label project-column-issue-count"> - {{.NumIssues ctx}} - </div> - <span class="project-column-title-label">{{.Title}}</span> + <div class="ui circular label project-column-issue-count"> + {{.NumIssues ctx}} </div> + <div class="project-column-title-label gt-ellipsis">{{.Title}}</div> {{if $canWriteProject}} - <div class="ui dropdown jump item"> - <div class="tw-px-2"> - {{svg "octicon-kebab-horizontal"}} - </div> - <div class="menu user-menu"> + <div class="ui dropdown tw-p-1"> + {{svg "octicon-kebab-horizontal"}} + <div class="menu"> <a class="item show-modal button" data-modal="#edit-project-column-modal-{{.ID}}"> {{svg "octicon-pencil"}} {{ctx.Locale.Tr "repo.projects.column.edit"}} diff --git a/web_src/css/features/projects.css b/web_src/css/features/projects.css index e23c146748..21e2aee0a2 100644 --- a/web_src/css/features/projects.css +++ b/web_src/css/features/projects.css @@ -14,7 +14,6 @@ width: 320px; height: calc(100vh - 450px); min-height: 60vh; - overflow-y: scroll; flex: 0 0 auto; overflow: visible; display: flex; @@ -30,17 +29,15 @@ display: flex; align-items: center; justify-content: space-between; + gap: 0.5em; } -.project-column-title { - background: none !important; - line-height: 1.25 !important; - cursor: inherit; +.ui.label.project-column-issue-count { + color: inherit; } -.project-column-title, -.project-column-issue-count { - color: inherit !important; +.project-column-title-label { + flex: 1; } .project-column > .cards { From f48cc501c46a2d34eb701561f01d888d689d60d5 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Mon, 20 May 2024 13:57:57 +0800 Subject: [PATCH 333/370] Fix incorrect "blob excerpt" link when comparing files (#31013) When comparing files between the base repo and forked repo, the "blob excerpt" link should point to the forked repo, because the commit doesn't exist in base repo. Co-authored-by: Giteabot <teabot@gitea.io> --- templates/repo/diff/section_split.tmpl | 7 +++-- templates/repo/diff/section_unified.tmpl | 7 +++-- tests/integration/compare_test.go | 39 ++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/templates/repo/diff/section_split.tmpl b/templates/repo/diff/section_split.tmpl index 67e2b195de..349f0c3dfc 100644 --- a/templates/repo/diff/section_split.tmpl +++ b/templates/repo/diff/section_split.tmpl @@ -1,4 +1,5 @@ {{$file := .file}} +{{$blobExcerptRepoLink := or ctx.RootData.CommitRepoLink ctx.RootData.RepoLink}} <colgroup> <col width="50"> <col width="10"> @@ -18,17 +19,17 @@ <td class="lines-num lines-num-old"> <div class="tw-flex"> {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}} - <button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=down&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> + <button class="code-expander-button" hx-target="closest tr" hx-get="{{$blobExcerptRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=down&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> {{svg "octicon-fold-down"}} </button> {{end}} {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4)}} - <button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=up&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> + <button class="code-expander-button" hx-target="closest tr" hx-get="{{$blobExcerptRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=up&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> {{svg "octicon-fold-up"}} </button> {{end}} {{if eq $line.GetExpandDirection 2}} - <button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> + <button class="code-expander-button" hx-target="closest tr" hx-get="{{$blobExcerptRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> {{svg "octicon-fold"}} </button> {{end}} diff --git a/templates/repo/diff/section_unified.tmpl b/templates/repo/diff/section_unified.tmpl index 4111159709..ec59f4d42e 100644 --- a/templates/repo/diff/section_unified.tmpl +++ b/templates/repo/diff/section_unified.tmpl @@ -1,4 +1,5 @@ {{$file := .file}} +{{$blobExcerptRepoLink := or ctx.RootData.CommitRepoLink ctx.RootData.RepoLink}} <colgroup> <col width="50"> <col width="50"> @@ -14,17 +15,17 @@ <td colspan="2" class="lines-num"> <div class="tw-flex"> {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}} - <button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=unified&direction=down&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> + <button class="code-expander-button" hx-target="closest tr" hx-get="{{$blobExcerptRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=unified&direction=down&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> {{svg "octicon-fold-down"}} </button> {{end}} {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4)}} - <button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=unified&direction=up&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> + <button class="code-expander-button" hx-target="closest tr" hx-get="{{$blobExcerptRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=unified&direction=up&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> {{svg "octicon-fold-up"}} </button> {{end}} {{if eq $line.GetExpandDirection 2}} - <button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=unified&direction=&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> + <button class="code-expander-button" hx-target="closest tr" hx-get="{{$blobExcerptRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=unified&direction=&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> {{svg "octicon-fold"}} </button> {{end}} diff --git a/tests/integration/compare_test.go b/tests/integration/compare_test.go index 27b2920cc1..7fb8dbc332 100644 --- a/tests/integration/compare_test.go +++ b/tests/integration/compare_test.go @@ -6,9 +6,14 @@ package integration import ( "fmt" "net/http" + "net/url" "strings" "testing" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + repo_service "code.gitea.io/gitea/services/repository" "code.gitea.io/gitea/tests" "github.com/stretchr/testify/assert" @@ -118,3 +123,37 @@ func TestCompareBranches(t *testing.T) { inspectCompare(t, htmlDoc, diffCount, diffChanges) } + +func TestCompareCodeExpand(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) + repo, err := repo_service.CreateRepositoryDirectly(db.DefaultContext, user1, user1, repo_service.CreateRepoOptions{ + Name: "test_blob_excerpt", + Readme: "Default", + AutoInit: true, + DefaultBranch: "main", + }) + assert.NoError(t, err) + + session := loginUser(t, user1.Name) + testEditFile(t, session, user1.Name, repo.Name, "main", "README.md", strings.Repeat("a\n", 30)) + + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + session = loginUser(t, user2.Name) + testRepoFork(t, session, user1.Name, repo.Name, user2.Name, "test_blob_excerpt-fork") + testCreateBranch(t, session, user2.Name, "test_blob_excerpt-fork", "branch/main", "forked-branch", http.StatusSeeOther) + testEditFile(t, session, user2.Name, "test_blob_excerpt-fork", "forked-branch", "README.md", strings.Repeat("a\n", 15)+"CHANGED\n"+strings.Repeat("a\n", 15)) + + req := NewRequest(t, "GET", "/user1/test_blob_excerpt/compare/main...user2/test_blob_excerpt-fork:forked-branch") + resp := session.MakeRequest(t, req, http.StatusOK) + htmlDoc := NewHTMLParser(t, resp.Body) + els := htmlDoc.Find(`button.code-expander-button[hx-get]`) + + // all the links in the comparison should be to the forked repo&branch + assert.NotZero(t, els.Length()) + for i := 0; i < els.Length(); i++ { + link := els.Eq(i).AttrOr("hx-get", "") + assert.True(t, strings.HasPrefix(link, "/user2/test_blob_excerpt-fork/blob_excerpt/")) + } + }) +} From de9bcd1d23523d736234ccbf73adce4746575e1b Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Mon, 20 May 2024 14:44:16 +0800 Subject: [PATCH 334/370] Avoid 500 panic error when uploading invalid maven package file (#31014) PackageDescriptor.Metadata might be nil (and maybe not only for maven). This is only a quick fix. The new `if` block is written intentionally to avoid unnecessary indenting to the existing code. --- options/locale/locale_en-US.ini | 1 + templates/package/content/maven.tmpl | 6 +++++- templates/package/metadata/maven.tmpl | 5 ++++- tests/integration/api_packages_maven_test.go | 10 ++++++++++ 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index a85b107eee..db4e3ec56b 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -3415,6 +3415,7 @@ error.unit_not_allowed = You are not allowed to access this repository section. title = Packages desc = Manage repository packages. empty = There are no packages yet. +no_metadata = No metadata. empty.documentation = For more information on the package registry, see <a target="_blank" rel="noopener noreferrer" href="%s">the documentation</a>. empty.repo = Did you upload a package, but it's not shown here? Go to <a href="%[1]s">package settings</a> and link it to this repo. registry.documentation = For more information on the %s registry, see <a target="_blank" rel="noopener noreferrer" href="%s">the documentation</a>. diff --git a/templates/package/content/maven.tmpl b/templates/package/content/maven.tmpl index 3a7de335de..f56595a830 100644 --- a/templates/package/content/maven.tmpl +++ b/templates/package/content/maven.tmpl @@ -1,4 +1,8 @@ -{{if eq .PackageDescriptor.Package.Type "maven"}} +{{if and (eq .PackageDescriptor.Package.Type "maven") (not .PackageDescriptor.Metadata)}} + <h4 class="ui top attached header">{{ctx.Locale.Tr "packages.installation"}}</h4> + <div class="ui attached segment">{{ctx.Locale.Tr "packages.no_metadata"}}</div> +{{end}} +{{if and (eq .PackageDescriptor.Package.Type "maven") .PackageDescriptor.Metadata}} <h4 class="ui top attached header">{{ctx.Locale.Tr "packages.installation"}}</h4> <div class="ui attached segment"> <div class="ui form"> diff --git a/templates/package/metadata/maven.tmpl b/templates/package/metadata/maven.tmpl index 548be61790..36412723d2 100644 --- a/templates/package/metadata/maven.tmpl +++ b/templates/package/metadata/maven.tmpl @@ -1,4 +1,7 @@ -{{if eq .PackageDescriptor.Package.Type "maven"}} +{{if and (eq .PackageDescriptor.Package.Type "maven") (not .PackageDescriptor.Metadata)}} + <div class="item">{{svg "octicon-note" 16 "tw-mr-2"}} {{ctx.Locale.Tr "packages.no_metadata"}}</div> +{{end}} +{{if and (eq .PackageDescriptor.Package.Type "maven") .PackageDescriptor.Metadata}} {{if .PackageDescriptor.Metadata.Name}}<div class="item">{{svg "octicon-note" 16 "tw-mr-2"}} {{.PackageDescriptor.Metadata.Name}}</div>{{end}} {{if .PackageDescriptor.Metadata.ProjectURL}}<div class="item">{{svg "octicon-link-external" 16 "tw-mr-2"}} <a href="{{.PackageDescriptor.Metadata.ProjectURL}}" target="_blank" rel="noopener noreferrer me">{{ctx.Locale.Tr "packages.details.project_site"}}</a></div>{{end}} {{range .PackageDescriptor.Metadata.Licenses}}<div class="item" title="{{ctx.Locale.Tr "packages.details.license"}}">{{svg "octicon-law" 16 "tw-mr-2"}} {{.}}</div>{{end}} diff --git a/tests/integration/api_packages_maven_test.go b/tests/integration/api_packages_maven_test.go index c7ed554a9d..0466a727b2 100644 --- a/tests/integration/api_packages_maven_test.go +++ b/tests/integration/api_packages_maven_test.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/packages/maven" + "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/tests" "github.com/stretchr/testify/assert" @@ -241,4 +242,13 @@ func TestPackageMaven(t *testing.T) { putFile(t, fmt.Sprintf("/%s/maven-metadata.xml", snapshotVersion), "test", http.StatusCreated) putFile(t, fmt.Sprintf("/%s/maven-metadata.xml", snapshotVersion), "test-overwrite", http.StatusCreated) }) + + t.Run("InvalidFile", func(t *testing.T) { + ver := packageVersion + "-invalid" + putFile(t, fmt.Sprintf("/%s/%s", ver, filename), "any invalid content", http.StatusCreated) + req := NewRequestf(t, "GET", "/%s/-/packages/maven/%s-%s/%s", user.Name, groupID, artifactID, ver) + resp := MakeRequest(t, req, http.StatusOK) + assert.Contains(t, resp.Body.String(), "No metadata.") + assert.True(t, test.IsNormalPageCompleted(resp.Body.String())) + }) } From f1d9f18d96050d89a4085c961f572f07b1e653d1 Mon Sep 17 00:00:00 2001 From: Zettat123 <zettat123@gmail.com> Date: Mon, 20 May 2024 15:17:00 +0800 Subject: [PATCH 335/370] Return `access_denied` error when an OAuth2 request is denied (#30974) According to [RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2.1), when the resource owner or authorization server denied an request, an `access_denied` error should be returned. But currently in this case Gitea does not return any error. For example, if the user clicks "Cancel" here, an `access_denied` error should be returned. <img width="360px" src="https://github.com/go-gitea/gitea/assets/15528715/be31c09b-4c0a-4701-b7a4-f54b8fe3a6c5" /> --- routers/web/auth/oauth.go | 10 ++++++++++ services/forms/user_form.go | 1 + templates/user/auth/grant.tmpl | 4 ++-- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 354e70bcbf..84fa473044 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -541,6 +541,16 @@ func GrantApplicationOAuth(ctx *context.Context) { ctx.Error(http.StatusBadRequest) return } + + if !form.Granted { + handleAuthorizeError(ctx, AuthorizeError{ + State: form.State, + ErrorDescription: "the request is denied", + ErrorCode: ErrorCodeAccessDenied, + }, form.RedirectURI) + return + } + app, err := auth.GetOAuth2ApplicationByClientID(ctx, form.ClientID) if err != nil { ctx.ServerError("GetOAuth2ApplicationByClientID", err) diff --git a/services/forms/user_form.go b/services/forms/user_form.go index 418a87b863..b4be1e02b7 100644 --- a/services/forms/user_form.go +++ b/services/forms/user_form.go @@ -161,6 +161,7 @@ func (f *AuthorizationForm) Validate(req *http.Request, errs binding.Errors) bin // GrantApplicationForm form for authorizing oauth2 clients type GrantApplicationForm struct { ClientID string `binding:"Required"` + Granted bool RedirectURI string State string Scope string diff --git a/templates/user/auth/grant.tmpl b/templates/user/auth/grant.tmpl index cb9bba8749..a18a3bd27a 100644 --- a/templates/user/auth/grant.tmpl +++ b/templates/user/auth/grant.tmpl @@ -23,8 +23,8 @@ <input type="hidden" name="scope" value="{{.Scope}}"> <input type="hidden" name="nonce" value="{{.Nonce}}"> <input type="hidden" name="redirect_uri" value="{{.RedirectURI}}"> - <button type="submit" id="authorize-app" value="{{ctx.Locale.Tr "auth.authorize_application"}}" class="ui red inline button">{{ctx.Locale.Tr "auth.authorize_application"}}</button> - <a href="{{.RedirectURI}}" class="ui basic primary inline button">Cancel</a> + <button type="submit" id="authorize-app" name="granted" value="true" class="ui red inline button">{{ctx.Locale.Tr "auth.authorize_application"}}</button> + <button type="submit" name="granted" value="false" class="ui basic primary inline button">{{ctx.Locale.Tr "cancel"}}</button> </form> </div> </div> From fb1ad920b769799aa1287441289d15477d9878c5 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Mon, 20 May 2024 23:12:50 +0800 Subject: [PATCH 336/370] Refactor sha1 and time-limited code (#31023) Remove "EncodeSha1", it shouldn't be used as a general purpose hasher (just like we have removed "EncodeMD5" in #28622) Rewrite the "time-limited code" related code and write better tests, the old code doesn't seem quite right. --- models/user/email_address.go | 5 +- models/user/user.go | 7 +-- modules/base/tool.go | 85 ++++++++++++++++------------------ modules/base/tool_test.go | 89 ++++++++++++++++++++---------------- modules/git/utils.go | 8 ++++ modules/git/utils_test.go | 17 +++++++ routers/web/repo/compare.go | 2 +- services/gitdiff/gitdiff.go | 3 +- 8 files changed, 120 insertions(+), 96 deletions(-) create mode 100644 modules/git/utils_test.go diff --git a/models/user/email_address.go b/models/user/email_address.go index 08771efe99..71b96c00be 100644 --- a/models/user/email_address.go +++ b/models/user/email_address.go @@ -10,6 +10,7 @@ import ( "net/mail" "regexp" "strings" + "time" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/base" @@ -353,14 +354,12 @@ func ChangeInactivePrimaryEmail(ctx context.Context, uid int64, oldEmailAddr, ne // VerifyActiveEmailCode verifies active email code when active account func VerifyActiveEmailCode(ctx context.Context, code, email string) *EmailAddress { - minutes := setting.Service.ActiveCodeLives - if user := GetVerifyUser(ctx, code); user != nil { // time limit code prefix := code[:base.TimeLimitCodeLength] data := fmt.Sprintf("%d%s%s%s%s", user.ID, email, user.LowerName, user.Passwd, user.Rands) - if base.VerifyTimeLimitCode(data, minutes, prefix) { + if base.VerifyTimeLimitCode(time.Now(), data, setting.Service.ActiveCodeLives, prefix) { emailAddress := &EmailAddress{UID: user.ID, Email: email} if has, _ := db.GetEngine(ctx).Get(emailAddress); has { return emailAddress diff --git a/models/user/user.go b/models/user/user.go index a5a5b5bdf6..6848d1be95 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -304,7 +304,7 @@ func (u *User) OrganisationLink() string { func (u *User) GenerateEmailActivateCode(email string) string { code := base.CreateTimeLimitCode( fmt.Sprintf("%d%s%s%s%s", u.ID, email, u.LowerName, u.Passwd, u.Rands), - setting.Service.ActiveCodeLives, nil) + setting.Service.ActiveCodeLives, time.Now(), nil) // Add tail hex username code += hex.EncodeToString([]byte(u.LowerName)) @@ -791,14 +791,11 @@ func GetVerifyUser(ctx context.Context, code string) (user *User) { // VerifyUserActiveCode verifies active code when active account func VerifyUserActiveCode(ctx context.Context, code string) (user *User) { - minutes := setting.Service.ActiveCodeLives - if user = GetVerifyUser(ctx, code); user != nil { // time limit code prefix := code[:base.TimeLimitCodeLength] data := fmt.Sprintf("%d%s%s%s%s", user.ID, user.Email, user.LowerName, user.Passwd, user.Rands) - - if base.VerifyTimeLimitCode(data, minutes, prefix) { + if base.VerifyTimeLimitCode(time.Now(), data, setting.Service.ActiveCodeLives, prefix) { return user } } diff --git a/modules/base/tool.go b/modules/base/tool.go index 40785e74e8..378eb7e3dd 100644 --- a/modules/base/tool.go +++ b/modules/base/tool.go @@ -4,12 +4,15 @@ package base import ( + "crypto/hmac" "crypto/sha1" "crypto/sha256" + "crypto/subtle" "encoding/base64" "encoding/hex" "errors" "fmt" + "hash" "os" "path/filepath" "runtime" @@ -25,13 +28,6 @@ import ( "github.com/dustin/go-humanize" ) -// EncodeSha1 string to sha1 hex value. -func EncodeSha1(str string) string { - h := sha1.New() - _, _ = h.Write([]byte(str)) - return hex.EncodeToString(h.Sum(nil)) -} - // EncodeSha256 string to sha256 hex value. func EncodeSha256(str string) string { h := sha256.New() @@ -62,63 +58,62 @@ func BasicAuthDecode(encoded string) (string, string, error) { } // VerifyTimeLimitCode verify time limit code -func VerifyTimeLimitCode(data string, minutes int, code string) bool { +func VerifyTimeLimitCode(now time.Time, data string, minutes int, code string) bool { if len(code) <= 18 { return false } - // split code - start := code[:12] - lives := code[12:18] - if d, err := strconv.ParseInt(lives, 10, 0); err == nil { - minutes = int(d) - } + startTimeStr := code[:12] + aliveTimeStr := code[12:18] + aliveTime, _ := strconv.Atoi(aliveTimeStr) // no need to check err, if anything wrong, the following code check will fail soon - // right active code - retCode := CreateTimeLimitCode(data, minutes, start) - if retCode == code && minutes > 0 { - // check time is expired or not - before, _ := time.ParseInLocation("200601021504", start, time.Local) - now := time.Now() - if before.Add(time.Minute*time.Duration(minutes)).Unix() > now.Unix() { - return true + // check code + retCode := CreateTimeLimitCode(data, aliveTime, startTimeStr, nil) + if subtle.ConstantTimeCompare([]byte(retCode), []byte(code)) != 1 { + retCode = CreateTimeLimitCode(data, aliveTime, startTimeStr, sha1.New()) // TODO: this is only for the support of legacy codes, remove this in/after 1.23 + if subtle.ConstantTimeCompare([]byte(retCode), []byte(code)) != 1 { + return false } } - return false + // check time is expired or not: startTime <= now && now < startTime + minutes + startTime, _ := time.ParseInLocation("200601021504", startTimeStr, time.Local) + return (startTime.Before(now) || startTime.Equal(now)) && now.Before(startTime.Add(time.Minute*time.Duration(minutes))) } // TimeLimitCodeLength default value for time limit code const TimeLimitCodeLength = 12 + 6 + 40 -// CreateTimeLimitCode create a time limit code -// code format: 12 length date time string + 6 minutes string + 40 sha1 encoded string -func CreateTimeLimitCode(data string, minutes int, startInf any) string { - format := "200601021504" +// CreateTimeLimitCode create a time-limited code. +// Format: 12 length date time string + 6 minutes string (not used) + 40 hash string, some other code depends on this fixed length +// If h is nil, then use the default hmac hash. +func CreateTimeLimitCode[T time.Time | string](data string, minutes int, startTimeGeneric T, h hash.Hash) string { + const format = "200601021504" - var start, end time.Time - var startStr, endStr string - - if startInf == nil { - // Use now time create code - start = time.Now() - startStr = start.Format(format) + var start time.Time + var startTimeAny any = startTimeGeneric + if t, ok := startTimeAny.(time.Time); ok { + start = t } else { - // use start string create code - startStr = startInf.(string) - start, _ = time.ParseInLocation(format, startStr, time.Local) - startStr = start.Format(format) + var err error + start, err = time.ParseInLocation(format, startTimeAny.(string), time.Local) + if err != nil { + return "" // return an invalid code because the "parse" failed + } } + startStr := start.Format(format) + end := start.Add(time.Minute * time.Duration(minutes)) - end = start.Add(time.Minute * time.Duration(minutes)) - endStr = end.Format(format) - - // create sha1 encode string - sh := sha1.New() - _, _ = sh.Write([]byte(fmt.Sprintf("%s%s%s%s%d", data, hex.EncodeToString(setting.GetGeneralTokenSigningSecret()), startStr, endStr, minutes))) - encoded := hex.EncodeToString(sh.Sum(nil)) + if h == nil { + h = hmac.New(sha1.New, setting.GetGeneralTokenSigningSecret()) + } + _, _ = fmt.Fprintf(h, "%s%s%s%s%d", data, hex.EncodeToString(setting.GetGeneralTokenSigningSecret()), startStr, end.Format(format), minutes) + encoded := hex.EncodeToString(h.Sum(nil)) code := fmt.Sprintf("%s%06d%s", startStr, minutes, encoded) + if len(code) != TimeLimitCodeLength { + panic("there is a hard requirement for the length of time-limited code") // it shouldn't happen + } return code } diff --git a/modules/base/tool_test.go b/modules/base/tool_test.go index f21b89c74c..62de7229ac 100644 --- a/modules/base/tool_test.go +++ b/modules/base/tool_test.go @@ -4,20 +4,18 @@ package base import ( + "crypto/sha1" + "fmt" "os" "testing" "time" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" + "github.com/stretchr/testify/assert" ) -func TestEncodeSha1(t *testing.T) { - assert.Equal(t, - "8843d7f92416211de9ebb963ff4ce28125932878", - EncodeSha1("foobar"), - ) -} - func TestEncodeSha256(t *testing.T) { assert.Equal(t, "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2", @@ -46,43 +44,54 @@ func TestBasicAuthDecode(t *testing.T) { } func TestVerifyTimeLimitCode(t *testing.T) { - tc := []struct { - data string - minutes int - code string - valid bool - }{{ - data: "data", - minutes: 2, - code: testCreateTimeLimitCode(t, "data", 2), - valid: true, - }, { - data: "abc123-ß", - minutes: 1, - code: testCreateTimeLimitCode(t, "abc123-ß", 1), - valid: true, - }, { - data: "data", - minutes: 2, - code: "2021012723240000005928251dac409d2c33a6eb82c63410aaad569bed", - valid: false, - }} - for _, test := range tc { - actualValid := VerifyTimeLimitCode(test.data, test.minutes, test.code) - assert.Equal(t, test.valid, actualValid, "data: '%s' code: '%s' should be valid: %t", test.data, test.code, test.valid) + defer test.MockVariableValue(&setting.InstallLock, true)() + initGeneralSecret := func(secret string) { + setting.InstallLock = true + setting.CfgProvider, _ = setting.NewConfigProviderFromData(fmt.Sprintf(` +[oauth2] +JWT_SECRET = %s +`, secret)) + setting.LoadCommonSettings() } -} -func testCreateTimeLimitCode(t *testing.T, data string, m int) string { - result0 := CreateTimeLimitCode(data, m, nil) - result1 := CreateTimeLimitCode(data, m, time.Now().Format("200601021504")) - result2 := CreateTimeLimitCode(data, m, time.Unix(time.Now().Unix()+int64(time.Minute)*int64(m), 0).Format("200601021504")) + initGeneralSecret("KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko") + now := time.Now() - assert.Equal(t, result0, result1) - assert.NotEqual(t, result0, result2) + t.Run("TestGenericParameter", func(t *testing.T) { + time2000 := time.Date(2000, 1, 2, 3, 4, 5, 0, time.Local) + assert.Equal(t, "2000010203040000026fa5221b2731b7cf80b1b506f5e39e38c115fee5", CreateTimeLimitCode("test-sha1", 2, time2000, sha1.New())) + assert.Equal(t, "2000010203040000026fa5221b2731b7cf80b1b506f5e39e38c115fee5", CreateTimeLimitCode("test-sha1", 2, "200001020304", sha1.New())) + assert.Equal(t, "2000010203040000024842227a2f87041ff82025199c0187410a9297bf", CreateTimeLimitCode("test-hmac", 2, time2000, nil)) + assert.Equal(t, "2000010203040000024842227a2f87041ff82025199c0187410a9297bf", CreateTimeLimitCode("test-hmac", 2, "200001020304", nil)) + }) - assert.True(t, len(result0) != 0) - return result0 + t.Run("TestInvalidCode", func(t *testing.T) { + assert.False(t, VerifyTimeLimitCode(now, "data", 2, "")) + assert.False(t, VerifyTimeLimitCode(now, "data", 2, "invalid code")) + }) + + t.Run("TestCreateAndVerify", func(t *testing.T) { + code := CreateTimeLimitCode("data", 2, now, nil) + assert.False(t, VerifyTimeLimitCode(now.Add(-time.Minute), "data", 2, code)) // not started yet + assert.True(t, VerifyTimeLimitCode(now, "data", 2, code)) + assert.True(t, VerifyTimeLimitCode(now.Add(time.Minute), "data", 2, code)) + assert.False(t, VerifyTimeLimitCode(now.Add(time.Minute), "DATA", 2, code)) // invalid data + assert.False(t, VerifyTimeLimitCode(now.Add(2*time.Minute), "data", 2, code)) // expired + }) + + t.Run("TestDifferentSecret", func(t *testing.T) { + // use another secret to ensure the code is invalid for different secret + verifyDataCode := func(c string) bool { + return VerifyTimeLimitCode(now, "data", 2, c) + } + code1 := CreateTimeLimitCode("data", 2, now, sha1.New()) + code2 := CreateTimeLimitCode("data", 2, now, nil) + assert.True(t, verifyDataCode(code1)) + assert.True(t, verifyDataCode(code2)) + initGeneralSecret("000_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko") + assert.False(t, verifyDataCode(code1)) + assert.False(t, verifyDataCode(code2)) + }) } func TestFileSize(t *testing.T) { diff --git a/modules/git/utils.go b/modules/git/utils.go index 0d67412707..53211c6451 100644 --- a/modules/git/utils.go +++ b/modules/git/utils.go @@ -4,6 +4,8 @@ package git import ( + "crypto/sha1" + "encoding/hex" "fmt" "io" "os" @@ -128,3 +130,9 @@ func (l *LimitedReaderCloser) Read(p []byte) (n int, err error) { func (l *LimitedReaderCloser) Close() error { return l.C.Close() } + +func HashFilePathForWebUI(s string) string { + h := sha1.New() + _, _ = h.Write([]byte(s)) + return hex.EncodeToString(h.Sum(nil)) +} diff --git a/modules/git/utils_test.go b/modules/git/utils_test.go new file mode 100644 index 0000000000..1291cee637 --- /dev/null +++ b/modules/git/utils_test.go @@ -0,0 +1,17 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package git + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestHashFilePathForWebUI(t *testing.T) { + assert.Equal(t, + "8843d7f92416211de9ebb963ff4ce28125932878", + HashFilePathForWebUI("foobar"), + ) +} diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 8c0fee71a0..818dc4d50f 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -931,7 +931,7 @@ func ExcerptBlob(ctx *context.Context) { } } ctx.Data["section"] = section - ctx.Data["FileNameHash"] = base.EncodeSha1(filePath) + ctx.Data["FileNameHash"] = git.HashFilePathForWebUI(filePath) ctx.Data["AfterCommitID"] = commitID ctx.Data["Anchor"] = anchor ctx.HTML(http.StatusOK, tplBlobExcerpt) diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 3a35d24dff..063c995d52 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -23,7 +23,6 @@ import ( pull_model "code.gitea.io/gitea/models/pull" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/analyze" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/charset" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/highlight" @@ -746,7 +745,7 @@ parsingLoop: diffLineTypeBuffers[DiffLineAdd] = new(bytes.Buffer) diffLineTypeBuffers[DiffLineDel] = new(bytes.Buffer) for _, f := range diff.Files { - f.NameHash = base.EncodeSha1(f.Name) + f.NameHash = git.HashFilePathForWebUI(f.Name) for _, buffer := range diffLineTypeBuffers { buffer.Reset() From ba83d27ab037a3dbcb0c84b731c8030e9bdc26a8 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Tue, 21 May 2024 00:26:00 +0000 Subject: [PATCH 337/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_ja-JP.ini | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index cf9d9bbc51..66dedcbb51 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -436,6 +436,7 @@ oauth_signin_submit=アカウントにリンク oauth.signin.error=認可リクエストの処理中にエラーが発生しました。このエラーが解決しない場合は、サイト管理者に問い合わせてください。 oauth.signin.error.access_denied=認可リクエストが拒否されました。 oauth.signin.error.temporarily_unavailable=認証サーバーが一時的に利用できないため、認可に失敗しました。後でもう一度やり直してください。 +oauth_callback_unable_auto_reg=自動登録が有効になっていますが、OAuth2プロバイダー %[1]s の応答はフィールド %[2]s が不足しており、自動でアカウントを作成することができません。 アカウントを作成またはリンクするか、サイト管理者に問い合わせてください。 openid_connect_submit=接続 openid_connect_title=既存のアカウントに接続 openid_connect_desc=選択したOpenID URIは未登録です。 ここで新しいアカウントと関連付けます。 @@ -763,6 +764,8 @@ manage_themes=デフォルトのテーマを選択 manage_openid=OpenIDアドレスの管理 email_desc=プライマリメールアドレスは、通知、パスワードの回復、さらにメールアドレスを隠さない場合は、WebベースのGit操作にも使用されます。 theme_desc=この設定がサイト全体のデフォルトのテーマとなります。 +theme_colorblindness_help=色覚障害テーマのサポート +theme_colorblindness_prompt=Giteaには基本的な色覚障害サポートを含むテーマがいくつか入っていますが、それらは色定義が少ししかありません。 作業はまだ進行中です。 テーマCSSファイルにもっと多くの色を定義していくことで、さらに改善できる余地があります。 primary=プライマリー activated=アクティベート済み requires_activation=アクティベーションが必要 @@ -3317,6 +3320,7 @@ self_check.database_collation_case_insensitive=データベースは照合順序 self_check.database_inconsistent_collation_columns=データベースは照合順序 %s を使用していますが、以下のカラムはそれと一致しない照合順序を使用しており、予期せぬ問題を引き起こす可能性があります。 self_check.database_fix_mysql=MySQL/MariaDBユーザーの方は、"gitea doctor convert" コマンドを使用することで、照合順序の問題を修正できます。 また、"ALTER ... COLLATE ..." のSQLを手で実行しても修正することができます。 self_check.database_fix_mssql=MSSQLユーザーの方は、問題を修正するには今のところ "ALTER ... COLLATE ..." のSQLを手で実行するしかありません。 +self_check.location_origin_mismatch=現在のURL (%[1]s) は、Giteaが見ているURL (%[2]s) に一致していません。 リバースプロキシを使用している場合は、"Host" ヘッダーと "X-Forwarded-Proto" ヘッダーが正しく設定されていることを確認してください。 [action] create_repo=がリポジトリ <a href="%s">%s</a> を作成しました @@ -3344,6 +3348,7 @@ mirror_sync_create=が <a href="%[1]s">%[4]s</a> の新しい参照 <a href="%[2 mirror_sync_delete=が <a href="%[1]s">%[3]s</a> の参照 <code>%[2]s</code> をミラーから反映し、削除しました approve_pull_request=`が <a href="%[1]s">%[3]s#%[2]s</a> を承認しました` reject_pull_request=`が <a href="%[1]s">%[3]s#%[2]s</a>について変更を提案しました` +publish_release=`が <a href="%[1]s">%[3]s</a> の <a href="%[2]s">%[4]s</a> をリリースしました` review_dismissed=`が <b>%[4]s</b> の <a href="%[1]s">%[3]s#%[2]s</a> へのレビューを棄却しました` review_dismissed_reason=理由: create_branch=がブランチ <a href="%[2]s">%[3]s</a> を <a href="%[1]s">%[4]s</a> に作成しました From 1007ce764ea80b48120b796175d7d1210cbb6f74 Mon Sep 17 00:00:00 2001 From: Kemal Zebari <60799661+kemzeb@users.noreply.github.com> Date: Mon, 20 May 2024 19:23:07 -0700 Subject: [PATCH 338/370] Don't include link of deleted branch when listing branches (#31028) From https://github.com/go-gitea/gitea/issues/31018#issuecomment-2119622680. This commit removes the link to a deleted branch name because it returns a 404 while it is in this deleted state. GitHub also throws a 404 when navigating to a branch link that was just deleted, but this deleted branch is removed from the branch list after a page refresh. Since with Gitea this deleted branch would be kept around for quite some time (well, until the "cleanup deleted branches" cron job begins), it makes sense to not have this as a link that users can navigate to. --- templates/repo/branch/list.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/branch/list.tmpl b/templates/repo/branch/list.tmpl index 77cccd65b7..dcfe082276 100644 --- a/templates/repo/branch/list.tmpl +++ b/templates/repo/branch/list.tmpl @@ -87,7 +87,7 @@ <td class="eight wide"> {{if .DBBranch.IsDeleted}} <div class="flex-text-block"> - <a class="gt-ellipsis" href="{{$.RepoLink}}/src/branch/{{PathEscapeSegments .DBBranch.Name}}">{{.DBBranch.Name}}</a> + <span class="gt-ellipsis">{{.DBBranch.Name}}</span> <button class="btn interact-fg tw-px-1" data-clipboard-text="{{.DBBranch.Name}}">{{svg "octicon-copy" 14}}</button> </div> <p class="info">{{ctx.Locale.Tr "repo.branch.deleted_by" .DBBranch.DeletedBy.Name}} {{TimeSinceUnix .DBBranch.DeletedUnix ctx.Locale}}</p> From c6cf96d31d80ab79d370a6192fd761b4443daec2 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Tue, 21 May 2024 23:23:22 +0800 Subject: [PATCH 339/370] Fix automerge will not work because of some events haven't been triggered (#30780) Replace #25741 Close #24445 Close #30658 Close #20646 ~Depends on #30805~ Since #25741 has been rewritten totally, to make the contribution easier, I will continue the work in this PR. Thanks @6543 --------- Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> --- models/issues/review.go | 6 +- services/automerge/automerge.go | 108 ++++++---- services/automerge/notify.go | 46 ++++ .../repository/commitstatus/commitstatus.go | 2 +- tests/integration/editor_test.go | 41 ++-- tests/integration/pull_merge_test.go | 198 ++++++++++++++++++ tests/integration/pull_review_test.go | 12 +- 7 files changed, 347 insertions(+), 66 deletions(-) create mode 100644 services/automerge/notify.go diff --git a/models/issues/review.go b/models/issues/review.go index 3c6934b060..ca6fd6035b 100644 --- a/models/issues/review.go +++ b/models/issues/review.go @@ -155,14 +155,14 @@ func (r *Review) LoadCodeComments(ctx context.Context) (err error) { if r.CodeComments != nil { return err } - if err = r.loadIssue(ctx); err != nil { + if err = r.LoadIssue(ctx); err != nil { return err } r.CodeComments, err = fetchCodeCommentsByReview(ctx, r.Issue, nil, r, false) return err } -func (r *Review) loadIssue(ctx context.Context) (err error) { +func (r *Review) LoadIssue(ctx context.Context) (err error) { if r.Issue != nil { return err } @@ -199,7 +199,7 @@ func (r *Review) LoadReviewerTeam(ctx context.Context) (err error) { // LoadAttributes loads all attributes except CodeComments func (r *Review) LoadAttributes(ctx context.Context) (err error) { - if err = r.loadIssue(ctx); err != nil { + if err = r.LoadIssue(ctx); err != nil { return err } if err = r.LoadCodeComments(ctx); err != nil { diff --git a/services/automerge/automerge.go b/services/automerge/automerge.go index bd1317c7f4..10f3c28d56 100644 --- a/services/automerge/automerge.go +++ b/services/automerge/automerge.go @@ -22,6 +22,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/queue" + notify_service "code.gitea.io/gitea/services/notify" pull_service "code.gitea.io/gitea/services/pull" ) @@ -30,6 +31,8 @@ var prAutoMergeQueue *queue.WorkerPoolQueue[string] // Init runs the task queue to that handles auto merges func Init() error { + notify_service.RegisterNotifier(NewNotifier()) + prAutoMergeQueue = queue.CreateUniqueQueue(graceful.GetManager().ShutdownContext(), "pr_auto_merge", handler) if prAutoMergeQueue == nil { return fmt.Errorf("unable to create pr_auto_merge queue") @@ -47,7 +50,7 @@ func handler(items ...string) []string { log.Error("could not parse data from pr_auto_merge queue (%v): %v", s, err) continue } - handlePull(id, sha) + handlePullRequestAutoMerge(id, sha) } return nil } @@ -62,16 +65,6 @@ func addToQueue(pr *issues_model.PullRequest, sha string) { // ScheduleAutoMerge if schedule is false and no error, pull can be merged directly func ScheduleAutoMerge(ctx context.Context, doer *user_model.User, pull *issues_model.PullRequest, style repo_model.MergeStyle, message string) (scheduled bool, err error) { err = db.WithTx(ctx, func(ctx context.Context) error { - lastCommitStatus, err := pull_service.GetPullRequestCommitStatusState(ctx, pull) - if err != nil { - return err - } - - // we don't need to schedule - if lastCommitStatus.IsSuccess() { - return nil - } - if err := pull_model.ScheduleAutoMerge(ctx, doer, pull.ID, style, message); err != nil { return err } @@ -95,8 +88,8 @@ func RemoveScheduledAutoMerge(ctx context.Context, doer *user_model.User, pull * }) } -// MergeScheduledPullRequest merges a previously scheduled pull request when all checks succeeded -func MergeScheduledPullRequest(ctx context.Context, sha string, repo *repo_model.Repository) error { +// StartPRCheckAndAutoMergeBySHA start an automerge check and auto merge task for all pull requests of repository and SHA +func StartPRCheckAndAutoMergeBySHA(ctx context.Context, sha string, repo *repo_model.Repository) error { pulls, err := getPullRequestsByHeadSHA(ctx, sha, repo, func(pr *issues_model.PullRequest) bool { return !pr.HasMerged && pr.CanAutoMerge() }) @@ -111,6 +104,32 @@ func MergeScheduledPullRequest(ctx context.Context, sha string, repo *repo_model return nil } +// StartPRCheckAndAutoMerge start an automerge check and auto merge task for a pull request +func StartPRCheckAndAutoMerge(ctx context.Context, pull *issues_model.PullRequest) { + if pull == nil || pull.HasMerged || !pull.CanAutoMerge() { + return + } + + if err := pull.LoadBaseRepo(ctx); err != nil { + log.Error("LoadBaseRepo: %v", err) + return + } + + gitRepo, err := gitrepo.OpenRepository(ctx, pull.BaseRepo) + if err != nil { + log.Error("OpenRepository: %v", err) + return + } + defer gitRepo.Close() + commitID, err := gitRepo.GetRefCommitID(pull.GetGitRefName()) + if err != nil { + log.Error("GetRefCommitID: %v", err) + return + } + + addToQueue(pull, commitID) +} + func getPullRequestsByHeadSHA(ctx context.Context, sha string, repo *repo_model.Repository, filter func(*issues_model.PullRequest) bool) (map[int64]*issues_model.PullRequest, error) { gitRepo, err := gitrepo.OpenRepository(ctx, repo) if err != nil { @@ -161,7 +180,8 @@ func getPullRequestsByHeadSHA(ctx context.Context, sha string, repo *repo_model. return pulls, nil } -func handlePull(pullID int64, sha string) { +// handlePullRequestAutoMerge merge the pull request if all checks are successful +func handlePullRequestAutoMerge(pullID int64, sha string) { ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("Handle AutoMerge of PR[%d] with sha[%s]", pullID, sha)) defer finished() @@ -182,24 +202,50 @@ func handlePull(pullID int64, sha string) { return } + if err = pr.LoadBaseRepo(ctx); err != nil { + log.Error("%-v LoadBaseRepo: %v", pr, err) + return + } + + // check the sha is the same as pull request head commit id + baseGitRepo, err := gitrepo.OpenRepository(ctx, pr.BaseRepo) + if err != nil { + log.Error("OpenRepository: %v", err) + return + } + defer baseGitRepo.Close() + + headCommitID, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName()) + if err != nil { + log.Error("GetRefCommitID: %v", err) + return + } + if headCommitID != sha { + log.Warn("Head commit id of auto merge %-v does not match sha [%s], it may means the head branch has been updated. Just ignore this request because a new request expected in the queue", pr, sha) + return + } + // Get all checks for this pr // We get the latest sha commit hash again to handle the case where the check of a previous push // did not succeed or was not finished yet. - if err = pr.LoadHeadRepo(ctx); err != nil { log.Error("%-v LoadHeadRepo: %v", pr, err) return } - headGitRepo, err := gitrepo.OpenRepository(ctx, pr.HeadRepo) - if err != nil { - log.Error("OpenRepository %-v: %v", pr.HeadRepo, err) - return + var headGitRepo *git.Repository + if pr.BaseRepoID == pr.HeadRepoID { + headGitRepo = baseGitRepo + } else { + headGitRepo, err = gitrepo.OpenRepository(ctx, pr.HeadRepo) + if err != nil { + log.Error("OpenRepository %-v: %v", pr.HeadRepo, err) + return + } + defer headGitRepo.Close() } - defer headGitRepo.Close() headBranchExist := headGitRepo.IsBranchExist(pr.HeadBranch) - if pr.HeadRepo == nil || !headBranchExist { log.Warn("Head branch of auto merge %-v does not exist [HeadRepoID: %d, Branch: %s]", pr, pr.HeadRepoID, pr.HeadBranch) return @@ -238,25 +284,11 @@ func handlePull(pullID int64, sha string) { return } - var baseGitRepo *git.Repository - if pr.BaseRepoID == pr.HeadRepoID { - baseGitRepo = headGitRepo - } else { - if err = pr.LoadBaseRepo(ctx); err != nil { - log.Error("%-v LoadBaseRepo: %v", pr, err) - return - } - - baseGitRepo, err = gitrepo.OpenRepository(ctx, pr.BaseRepo) - if err != nil { - log.Error("OpenRepository %-v: %v", pr.BaseRepo, err) - return - } - defer baseGitRepo.Close() - } - if err := pull_service.Merge(ctx, pr, doer, baseGitRepo, scheduledPRM.MergeStyle, "", scheduledPRM.Message, true); err != nil { log.Error("pull_service.Merge: %v", err) + // FIXME: if merge failed, we should display some error message to the pull request page. + // The resolution is add a new column on automerge table named `error_message` to store the error message and displayed + // on the pull request page. But this should not be finished in a bug fix PR which will be backport to release branch. return } } diff --git a/services/automerge/notify.go b/services/automerge/notify.go new file mode 100644 index 0000000000..cb078214f6 --- /dev/null +++ b/services/automerge/notify.go @@ -0,0 +1,46 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package automerge + +import ( + "context" + + issues_model "code.gitea.io/gitea/models/issues" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/log" + notify_service "code.gitea.io/gitea/services/notify" +) + +type automergeNotifier struct { + notify_service.NullNotifier +} + +var _ notify_service.Notifier = &automergeNotifier{} + +// NewNotifier create a new automergeNotifier notifier +func NewNotifier() notify_service.Notifier { + return &automergeNotifier{} +} + +func (n *automergeNotifier) PullRequestReview(ctx context.Context, pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) { + // as a missing / blocking reviews could have blocked a pending automerge let's recheck + if review.Type == issues_model.ReviewTypeApprove { + if err := StartPRCheckAndAutoMergeBySHA(ctx, review.CommitID, pr.BaseRepo); err != nil { + log.Error("StartPullRequestAutoMergeCheckBySHA: %v", err) + } + } +} + +func (n *automergeNotifier) PullReviewDismiss(ctx context.Context, doer *user_model.User, review *issues_model.Review, comment *issues_model.Comment) { + if err := review.LoadIssue(ctx); err != nil { + log.Error("LoadIssue: %v", err) + return + } + if err := review.Issue.LoadPullRequest(ctx); err != nil { + log.Error("LoadPullRequest: %v", err) + return + } + // as reviews could have blocked a pending automerge let's recheck + StartPRCheckAndAutoMerge(ctx, review.Issue.PullRequest) +} diff --git a/services/repository/commitstatus/commitstatus.go b/services/repository/commitstatus/commitstatus.go index 444ae04d0c..adc59abed8 100644 --- a/services/repository/commitstatus/commitstatus.go +++ b/services/repository/commitstatus/commitstatus.go @@ -115,7 +115,7 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato } if status.State.IsSuccess() { - if err := automerge.MergeScheduledPullRequest(ctx, sha, repo); err != nil { + if err := automerge.StartPRCheckAndAutoMergeBySHA(ctx, sha, repo); err != nil { return fmt.Errorf("MergeScheduledPullRequest[repo_id: %d, user_id: %d, sha: %s]: %w", repo.ID, creator.ID, sha, err) } } diff --git a/tests/integration/editor_test.go b/tests/integration/editor_test.go index 045567ce77..f510c79bc6 100644 --- a/tests/integration/editor_test.go +++ b/tests/integration/editor_test.go @@ -4,6 +4,7 @@ package integration import ( + "fmt" "net/http" "net/http/httptest" "net/url" @@ -19,27 +20,31 @@ import ( func TestCreateFile(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { session := loginUser(t, "user2") - - // Request editor page - req := NewRequest(t, "GET", "/user2/repo1/_new/master/") - resp := session.MakeRequest(t, req, http.StatusOK) - - doc := NewHTMLParser(t, resp.Body) - lastCommit := doc.GetInputValueByName("last_commit") - assert.NotEmpty(t, lastCommit) - - // Save new file to master branch - req = NewRequestWithValues(t, "POST", "/user2/repo1/_new/master/", map[string]string{ - "_csrf": doc.GetCSRF(), - "last_commit": lastCommit, - "tree_path": "test.txt", - "content": "Content", - "commit_choice": "direct", - }) - session.MakeRequest(t, req, http.StatusSeeOther) + testCreateFile(t, session, "user2", "repo1", "master", "test.txt", "Content") }) } +func testCreateFile(t *testing.T, session *TestSession, user, repo, branch, filePath, content string) *httptest.ResponseRecorder { + // Request editor page + newURL := fmt.Sprintf("/%s/%s/_new/%s/", user, repo, branch) + req := NewRequest(t, "GET", newURL) + resp := session.MakeRequest(t, req, http.StatusOK) + + doc := NewHTMLParser(t, resp.Body) + lastCommit := doc.GetInputValueByName("last_commit") + assert.NotEmpty(t, lastCommit) + + // Save new file to master branch + req = NewRequestWithValues(t, "POST", newURL, map[string]string{ + "_csrf": doc.GetCSRF(), + "last_commit": lastCommit, + "tree_path": filePath, + "content": content, + "commit_choice": "direct", + }) + return session.MakeRequest(t, req, http.StatusSeeOther) +} + func TestCreateFileOnProtectedBranch(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { session := loginUser(t, "user2") diff --git a/tests/integration/pull_merge_test.go b/tests/integration/pull_merge_test.go index 826568caf2..979c408388 100644 --- a/tests/integration/pull_merge_test.go +++ b/tests/integration/pull_merge_test.go @@ -12,6 +12,8 @@ import ( "net/url" "os" "path" + "path/filepath" + "strconv" "strings" "testing" "time" @@ -19,7 +21,9 @@ import ( "code.gitea.io/gitea/models" auth_model "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" + git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" + pull_model "code.gitea.io/gitea/models/pull" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -30,8 +34,10 @@ import ( api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/translation" + "code.gitea.io/gitea/services/automerge" "code.gitea.io/gitea/services/pull" repo_service "code.gitea.io/gitea/services/repository" + commitstatus_service "code.gitea.io/gitea/services/repository/commitstatus" files_service "code.gitea.io/gitea/services/repository/files" "github.com/stretchr/testify/assert" @@ -648,3 +654,195 @@ func TestPullMergeIndexerNotifier(t *testing.T) { } }) } + +func testResetRepo(t *testing.T, repoPath, branch, commitID string) { + f, err := os.OpenFile(filepath.Join(repoPath, "refs", "heads", branch), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644) + assert.NoError(t, err) + _, err = f.WriteString(commitID + "\n") + assert.NoError(t, err) + f.Close() + + repo, err := git.OpenRepository(context.Background(), repoPath) + assert.NoError(t, err) + defer repo.Close() + id, err := repo.GetBranchCommitID(branch) + assert.NoError(t, err) + assert.EqualValues(t, commitID, id) +} + +func TestPullAutoMergeAfterCommitStatusSucceed(t *testing.T) { + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + // create a pull request + session := loginUser(t, "user1") + user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) + forkedName := "repo1-1" + testRepoFork(t, session, "user2", "repo1", "user1", forkedName) + defer func() { + testDeleteRepository(t, session, "user1", forkedName) + }() + testEditFile(t, session, "user1", forkedName, "master", "README.md", "Hello, World (Edited)\n") + testPullCreate(t, session, "user1", forkedName, false, "master", "master", "Indexer notifier test pull") + + baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"}) + forkedRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user1", Name: forkedName}) + pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ + BaseRepoID: baseRepo.ID, + BaseBranch: "master", + HeadRepoID: forkedRepo.ID, + HeadBranch: "master", + }) + + // add protected branch for commit status + csrf := GetCSRF(t, session, "/user2/repo1/settings/branches") + // Change master branch to protected + req := NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/edit", map[string]string{ + "_csrf": csrf, + "rule_name": "master", + "enable_push": "true", + "enable_status_check": "true", + "status_check_contexts": "gitea/actions", + }) + session.MakeRequest(t, req, http.StatusSeeOther) + + // first time insert automerge record, return true + scheduled, err := automerge.ScheduleAutoMerge(db.DefaultContext, user1, pr, repo_model.MergeStyleMerge, "auto merge test") + assert.NoError(t, err) + assert.True(t, scheduled) + + // second time insert automerge record, return false because it does exist + scheduled, err = automerge.ScheduleAutoMerge(db.DefaultContext, user1, pr, repo_model.MergeStyleMerge, "auto merge test") + assert.Error(t, err) + assert.False(t, scheduled) + + // reload pr again + pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID}) + assert.False(t, pr.HasMerged) + assert.Empty(t, pr.MergedCommitID) + + // update commit status to success, then it should be merged automatically + baseGitRepo, err := gitrepo.OpenRepository(db.DefaultContext, baseRepo) + assert.NoError(t, err) + sha, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName()) + assert.NoError(t, err) + masterCommitID, err := baseGitRepo.GetBranchCommitID("master") + assert.NoError(t, err) + + branches, _, err := baseGitRepo.GetBranchNames(0, 100) + assert.NoError(t, err) + assert.ElementsMatch(t, []string{"sub-home-md-img-check", "home-md-img-check", "pr-to-update", "branch2", "DefaultBranch", "develop", "feature/1", "master"}, branches) + baseGitRepo.Close() + defer func() { + testResetRepo(t, baseRepo.RepoPath(), "master", masterCommitID) + }() + + err = commitstatus_service.CreateCommitStatus(db.DefaultContext, baseRepo, user1, sha, &git_model.CommitStatus{ + State: api.CommitStatusSuccess, + TargetURL: "https://gitea.com", + Context: "gitea/actions", + }) + assert.NoError(t, err) + + time.Sleep(2 * time.Second) + + // realod pr again + pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID}) + assert.True(t, pr.HasMerged) + assert.NotEmpty(t, pr.MergedCommitID) + + unittest.AssertNotExistsBean(t, &pull_model.AutoMerge{PullID: pr.ID}) + }) +} + +func TestPullAutoMergeAfterCommitStatusSucceedAndApproval(t *testing.T) { + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + // create a pull request + session := loginUser(t, "user1") + user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) + forkedName := "repo1-2" + testRepoFork(t, session, "user2", "repo1", "user1", forkedName) + defer func() { + testDeleteRepository(t, session, "user1", forkedName) + }() + testEditFile(t, session, "user1", forkedName, "master", "README.md", "Hello, World (Edited)\n") + testPullCreate(t, session, "user1", forkedName, false, "master", "master", "Indexer notifier test pull") + + baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"}) + forkedRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user1", Name: forkedName}) + pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ + BaseRepoID: baseRepo.ID, + BaseBranch: "master", + HeadRepoID: forkedRepo.ID, + HeadBranch: "master", + }) + + // add protected branch for commit status + csrf := GetCSRF(t, session, "/user2/repo1/settings/branches") + // Change master branch to protected + req := NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/edit", map[string]string{ + "_csrf": csrf, + "rule_name": "master", + "enable_push": "true", + "enable_status_check": "true", + "status_check_contexts": "gitea/actions", + "required_approvals": "1", + }) + session.MakeRequest(t, req, http.StatusSeeOther) + + // first time insert automerge record, return true + scheduled, err := automerge.ScheduleAutoMerge(db.DefaultContext, user1, pr, repo_model.MergeStyleMerge, "auto merge test") + assert.NoError(t, err) + assert.True(t, scheduled) + + // second time insert automerge record, return false because it does exist + scheduled, err = automerge.ScheduleAutoMerge(db.DefaultContext, user1, pr, repo_model.MergeStyleMerge, "auto merge test") + assert.Error(t, err) + assert.False(t, scheduled) + + // reload pr again + pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID}) + assert.False(t, pr.HasMerged) + assert.Empty(t, pr.MergedCommitID) + + // update commit status to success, then it should be merged automatically + baseGitRepo, err := gitrepo.OpenRepository(db.DefaultContext, baseRepo) + assert.NoError(t, err) + sha, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName()) + assert.NoError(t, err) + masterCommitID, err := baseGitRepo.GetBranchCommitID("master") + assert.NoError(t, err) + baseGitRepo.Close() + defer func() { + testResetRepo(t, baseRepo.RepoPath(), "master", masterCommitID) + }() + + err = commitstatus_service.CreateCommitStatus(db.DefaultContext, baseRepo, user1, sha, &git_model.CommitStatus{ + State: api.CommitStatusSuccess, + TargetURL: "https://gitea.com", + Context: "gitea/actions", + }) + assert.NoError(t, err) + + time.Sleep(2 * time.Second) + + // reload pr again + pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID}) + assert.False(t, pr.HasMerged) + assert.Empty(t, pr.MergedCommitID) + + // approve the PR from non-author + approveSession := loginUser(t, "user2") + req = NewRequest(t, "GET", fmt.Sprintf("/user2/repo1/pulls/%d", pr.Index)) + resp := approveSession.MakeRequest(t, req, http.StatusOK) + htmlDoc := NewHTMLParser(t, resp.Body) + testSubmitReview(t, approveSession, htmlDoc.GetCSRF(), "user2", "repo1", strconv.Itoa(int(pr.Index)), sha, "approve", http.StatusOK) + + time.Sleep(2 * time.Second) + + // realod pr again + pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID}) + assert.True(t, pr.HasMerged) + assert.NotEmpty(t, pr.MergedCommitID) + + unittest.AssertNotExistsBean(t, &pull_model.AutoMerge{PullID: pr.ID}) + }) +} diff --git a/tests/integration/pull_review_test.go b/tests/integration/pull_review_test.go index 273332a36b..df5d7b38ea 100644 --- a/tests/integration/pull_review_test.go +++ b/tests/integration/pull_review_test.go @@ -202,10 +202,10 @@ func TestPullView_GivenApproveOrRejectReviewOnClosedPR(t *testing.T) { htmlDoc := NewHTMLParser(t, resp.Body) // Submit an approve review on the PR. - testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "approve", http.StatusUnprocessableEntity) + testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "", "approve", http.StatusUnprocessableEntity) // Submit a reject review on the PR. - testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "reject", http.StatusUnprocessableEntity) + testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "", "reject", http.StatusUnprocessableEntity) }) t.Run("Submit approve/reject review on closed PR", func(t *testing.T) { @@ -222,18 +222,18 @@ func TestPullView_GivenApproveOrRejectReviewOnClosedPR(t *testing.T) { htmlDoc := NewHTMLParser(t, resp.Body) // Submit an approve review on the PR. - testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "approve", http.StatusUnprocessableEntity) + testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "", "approve", http.StatusUnprocessableEntity) // Submit a reject review on the PR. - testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "reject", http.StatusUnprocessableEntity) + testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "", "reject", http.StatusUnprocessableEntity) }) }) } -func testSubmitReview(t *testing.T, session *TestSession, csrf, owner, repo, pullNumber, reviewType string, expectedSubmitStatus int) *httptest.ResponseRecorder { +func testSubmitReview(t *testing.T, session *TestSession, csrf, owner, repo, pullNumber, commitID, reviewType string, expectedSubmitStatus int) *httptest.ResponseRecorder { options := map[string]string{ "_csrf": csrf, - "commit_id": "", + "commit_id": commitID, "content": "test", "type": reviewType, } From 9c8c9ff6d10b35de8d2d7eae0fc2646ad9bbe94a Mon Sep 17 00:00:00 2001 From: Denys Konovalov <kontakt@denyskon.de> Date: Tue, 21 May 2024 18:23:49 +0200 Subject: [PATCH 340/370] use existing oauth grant for public client (#31015) Do not try to create a new authorization grant when one exists already, thus preventing a DB-related authorization issue. Fix https://github.com/go-gitea/gitea/pull/30790#issuecomment-2118812426 --------- Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> --- routers/web/auth/oauth.go | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 84fa473044..b337b6b156 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -556,15 +556,30 @@ func GrantApplicationOAuth(ctx *context.Context) { ctx.ServerError("GetOAuth2ApplicationByClientID", err) return } - grant, err := app.CreateGrant(ctx, ctx.Doer.ID, form.Scope) + grant, err := app.GetGrantByUserID(ctx, ctx.Doer.ID) if err != nil { + handleServerError(ctx, form.State, form.RedirectURI) + return + } + if grant == nil { + grant, err = app.CreateGrant(ctx, ctx.Doer.ID, form.Scope) + if err != nil { + handleAuthorizeError(ctx, AuthorizeError{ + State: form.State, + ErrorDescription: "cannot create grant for user", + ErrorCode: ErrorCodeServerError, + }, form.RedirectURI) + return + } + } else if grant.Scope != form.Scope { handleAuthorizeError(ctx, AuthorizeError{ State: form.State, - ErrorDescription: "cannot create grant for user", + ErrorDescription: "a grant exists with different scope", ErrorCode: ErrorCodeServerError, }, form.RedirectURI) return } + if len(form.Nonce) > 0 { err := grant.SetNonce(ctx, form.Nonce) if err != nil { From daf2a4c047c88083d8820bdee9074357d5c5d7b7 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 22 May 2024 02:00:35 +0900 Subject: [PATCH 341/370] Fix wrong display of recently pushed notification (#25812) There's a bug in #25715: If user pushed a commit into another repo with same branch name, the no-related repo will display the recently pushed notification incorrectly. It is simple to fix this, we should match the repo id in the sql query.  The latest commit is 2 weeks ago.  The notification comes from another repo with same branch name:  After: In forked repo:  New PR Link will redirect to the original repo:  In the original repo:  New PR Link:  In the same repo:  New PR Link:  08/15 Update: Follow #26257, added permission check and logic fix mentioned in https://github.com/go-gitea/gitea/pull/26257#discussion_r1294085203 2024/04/25 Update: Fix #30611 --------- Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> --- models/fixtures/branch.yml | 36 +++++ models/fixtures/issue_index.yml | 8 + models/fixtures/org_user.yml | 12 ++ models/fixtures/repository.yml | 2 +- models/fixtures/team.yml | 22 +++ models/fixtures/team_unit.yml | 18 +++ models/fixtures/team_user.yml | 12 ++ models/fixtures/user.yml | 8 +- models/git/branch.go | 142 ++++++++++++++--- models/git/branch_list.go | 19 +++ models/organization/org_user_test.go | 6 +- models/repo/repo_list.go | 6 + routers/web/repo/view.go | 26 ++- .../code/recently_pushed_new_branches.tmpl | 4 +- tests/integration/api_user_orgs_test.go | 26 +++ tests/integration/compare_test.go | 2 +- tests/integration/empty_repo_test.go | 13 ++ tests/integration/integration_test.go | 9 ++ tests/integration/pull_compare_test.go | 2 +- tests/integration/pull_create_test.go | 6 +- tests/integration/pull_merge_test.go | 30 ++-- tests/integration/pull_review_test.go | 2 +- tests/integration/pull_status_test.go | 6 +- tests/integration/repo_activity_test.go | 2 +- tests/integration/repo_branch_test.go | 148 +++++++++++++++++- tests/integration/repo_fork_test.go | 13 +- 26 files changed, 508 insertions(+), 72 deletions(-) diff --git a/models/fixtures/branch.yml b/models/fixtures/branch.yml index 93003049c6..c7bdff7733 100644 --- a/models/fixtures/branch.yml +++ b/models/fixtures/branch.yml @@ -45,3 +45,39 @@ is_deleted: false deleted_by_id: 0 deleted_unix: 0 + +- + id: 5 + repo_id: 10 + name: 'master' + commit_id: '65f1bf27bc3bf70f64657658635e66094edbcb4d' + commit_message: 'Initial commit' + commit_time: 1489927679 + pusher_id: 12 + is_deleted: false + deleted_by_id: 0 + deleted_unix: 0 + +- + id: 6 + repo_id: 10 + name: 'outdated-new-branch' + commit_id: 'cb24c347e328d83c1e0c3c908a6b2c0a2fcb8a3d' + commit_message: 'add' + commit_time: 1489927679 + pusher_id: 12 + is_deleted: false + deleted_by_id: 0 + deleted_unix: 0 + +- + id: 14 + repo_id: 11 + name: 'master' + commit_id: '65f1bf27bc3bf70f64657658635e66094edbcb4d' + commit_message: 'Initial commit' + commit_time: 1489927679 + pusher_id: 13 + is_deleted: false + deleted_by_id: 0 + deleted_unix: 0 diff --git a/models/fixtures/issue_index.yml b/models/fixtures/issue_index.yml index de6e955804..5aabc08e38 100644 --- a/models/fixtures/issue_index.yml +++ b/models/fixtures/issue_index.yml @@ -1,27 +1,35 @@ - group_id: 1 max_index: 5 + - group_id: 2 max_index: 2 + - group_id: 3 max_index: 2 + - group_id: 10 max_index: 1 + - group_id: 32 max_index: 2 + - group_id: 48 max_index: 1 + - group_id: 42 max_index: 1 + - group_id: 50 max_index: 1 + - group_id: 51 max_index: 1 diff --git a/models/fixtures/org_user.yml b/models/fixtures/org_user.yml index a7fbcb2c5a..cf21b84aa9 100644 --- a/models/fixtures/org_user.yml +++ b/models/fixtures/org_user.yml @@ -117,3 +117,15 @@ uid: 40 org_id: 41 is_public: true + +- + id: 21 + uid: 12 + org_id: 25 + is_public: true + +- + id: 22 + uid: 2 + org_id: 35 + is_public: true diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml index e5c6224c96..e1f1dd7367 100644 --- a/models/fixtures/repository.yml +++ b/models/fixtures/repository.yml @@ -327,7 +327,7 @@ is_archived: false is_mirror: false status: 0 - is_fork: false + is_fork: true fork_id: 10 is_template: false template_id: 0 diff --git a/models/fixtures/team.yml b/models/fixtures/team.yml index 149fe90888..b549d0589b 100644 --- a/models/fixtures/team.yml +++ b/models/fixtures/team.yml @@ -239,3 +239,25 @@ num_members: 2 includes_all_repositories: false can_create_org_repo: false + +- + id: 23 + org_id: 25 + lower_name: owners + name: Owners + authorize: 4 # owner + num_repos: 0 + num_members: 1 + includes_all_repositories: false + can_create_org_repo: true + +- + id: 24 + org_id: 35 + lower_name: team24 + name: team24 + authorize: 2 # write + num_repos: 0 + num_members: 1 + includes_all_repositories: true + can_create_org_repo: false diff --git a/models/fixtures/team_unit.yml b/models/fixtures/team_unit.yml index de0e8d738b..110019eee3 100644 --- a/models/fixtures/team_unit.yml +++ b/models/fixtures/team_unit.yml @@ -322,3 +322,21 @@ team_id: 22 type: 3 access_mode: 1 + +- + id: 55 + team_id: 18 + type: 1 # code + access_mode: 4 + +- + id: 56 + team_id: 23 + type: 1 # code + access_mode: 4 + +- + id: 57 + team_id: 24 + type: 1 # code + access_mode: 2 diff --git a/models/fixtures/team_user.yml b/models/fixtures/team_user.yml index 02d57ae644..6b2d153278 100644 --- a/models/fixtures/team_user.yml +++ b/models/fixtures/team_user.yml @@ -147,3 +147,15 @@ org_id: 41 team_id: 22 uid: 39 + +- + id: 26 + org_id: 25 + team_id: 23 + uid: 12 + +- + id: 27 + org_id: 35 + team_id: 24 + uid: 2 diff --git a/models/fixtures/user.yml b/models/fixtures/user.yml index a3de535508..8504d88ce5 100644 --- a/models/fixtures/user.yml +++ b/models/fixtures/user.yml @@ -918,8 +918,8 @@ num_following: 0 num_stars: 0 num_repos: 0 - num_teams: 1 - num_members: 1 + num_teams: 2 + num_members: 2 visibility: 0 repo_admin_change_team_access: false theme: "" @@ -1289,8 +1289,8 @@ num_following: 0 num_stars: 0 num_repos: 0 - num_teams: 1 - num_members: 1 + num_teams: 2 + num_members: 2 visibility: 2 repo_admin_change_team_access: false theme: "" diff --git a/models/git/branch.go b/models/git/branch.go index 2979dff3d2..c315d921ff 100644 --- a/models/git/branch.go +++ b/models/git/branch.go @@ -10,9 +10,11 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" + "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/log" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" @@ -102,8 +104,9 @@ func (err ErrBranchesEqual) Unwrap() error { // for pagination, keyword search and filtering type Branch struct { ID int64 - RepoID int64 `xorm:"UNIQUE(s)"` - Name string `xorm:"UNIQUE(s) NOT NULL"` // git's ref-name is case-sensitive internally, however, in some databases (mssql, mysql, by default), it's case-insensitive at the moment + RepoID int64 `xorm:"UNIQUE(s)"` + Repo *repo_model.Repository `xorm:"-"` + Name string `xorm:"UNIQUE(s) NOT NULL"` // git's ref-name is case-sensitive internally, however, in some databases (mssql, mysql, by default), it's case-insensitive at the moment CommitID string CommitMessage string `xorm:"TEXT"` // it only stores the message summary (the first line) PusherID int64 @@ -139,6 +142,14 @@ func (b *Branch) LoadPusher(ctx context.Context) (err error) { return err } +func (b *Branch) LoadRepo(ctx context.Context) (err error) { + if b.Repo != nil || b.RepoID == 0 { + return nil + } + b.Repo, err = repo_model.GetRepositoryByID(ctx, b.RepoID) + return err +} + func init() { db.RegisterModel(new(Branch)) db.RegisterModel(new(RenamedBranch)) @@ -400,24 +411,111 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str return committer.Commit() } -// FindRecentlyPushedNewBranches return at most 2 new branches pushed by the user in 6 hours which has no opened PRs created -// except the indicate branch -func FindRecentlyPushedNewBranches(ctx context.Context, repoID, userID int64, excludeBranchName string) (BranchList, error) { - branches := make(BranchList, 0, 2) - subQuery := builder.Select("head_branch").From("pull_request"). - InnerJoin("issue", "issue.id = pull_request.issue_id"). - Where(builder.Eq{ - "pull_request.head_repo_id": repoID, - "issue.is_closed": false, - }) - err := db.GetEngine(ctx). - Where("pusher_id=? AND is_deleted=?", userID, false). - And("name <> ?", excludeBranchName). - And("repo_id = ?", repoID). - And("commit_time >= ?", time.Now().Add(-time.Hour*6).Unix()). - NotIn("name", subQuery). - OrderBy("branch.commit_time DESC"). - Limit(2). - Find(&branches) - return branches, err +type FindRecentlyPushedNewBranchesOptions struct { + Repo *repo_model.Repository + BaseRepo *repo_model.Repository + CommitAfterUnix int64 + MaxCount int +} + +type RecentlyPushedNewBranch struct { + BranchDisplayName string + BranchLink string + BranchCompareURL string + CommitTime timeutil.TimeStamp +} + +// FindRecentlyPushedNewBranches return at most 2 new branches pushed by the user in 2 hours which has no opened PRs created +// if opts.CommitAfterUnix is 0, we will find the branches that were committed to in the last 2 hours +// if opts.ListOptions is not set, we will only display top 2 latest branch +func FindRecentlyPushedNewBranches(ctx context.Context, doer *user_model.User, opts *FindRecentlyPushedNewBranchesOptions) ([]*RecentlyPushedNewBranch, error) { + if doer == nil { + return []*RecentlyPushedNewBranch{}, nil + } + + // find all related repo ids + repoOpts := repo_model.SearchRepoOptions{ + Actor: doer, + Private: true, + AllPublic: false, // Include also all public repositories of users and public organisations + AllLimited: false, // Include also all public repositories of limited organisations + Fork: optional.Some(true), + ForkFrom: opts.BaseRepo.ID, + Archived: optional.Some(false), + } + repoCond := repo_model.SearchRepositoryCondition(&repoOpts).And(repo_model.AccessibleRepositoryCondition(doer, unit.TypeCode)) + if opts.Repo.ID == opts.BaseRepo.ID { + // should also include the base repo's branches + repoCond = repoCond.Or(builder.Eq{"id": opts.BaseRepo.ID}) + } else { + // in fork repo, we only detect the fork repo's branch + repoCond = repoCond.And(builder.Eq{"id": opts.Repo.ID}) + } + repoIDs := builder.Select("id").From("repository").Where(repoCond) + + if opts.CommitAfterUnix == 0 { + opts.CommitAfterUnix = time.Now().Add(-time.Hour * 2).Unix() + } + + baseBranch, err := GetBranch(ctx, opts.BaseRepo.ID, opts.BaseRepo.DefaultBranch) + if err != nil { + return nil, err + } + + // find all related branches, these branches may already created PRs, we will check later + var branches []*Branch + if err := db.GetEngine(ctx). + Where(builder.And( + builder.Eq{ + "pusher_id": doer.ID, + "is_deleted": false, + }, + builder.Gte{"commit_time": opts.CommitAfterUnix}, + builder.In("repo_id", repoIDs), + // newly created branch have no changes, so skip them + builder.Neq{"commit_id": baseBranch.CommitID}, + )). + OrderBy(db.SearchOrderByRecentUpdated.String()). + Find(&branches); err != nil { + return nil, err + } + + newBranches := make([]*RecentlyPushedNewBranch, 0, len(branches)) + if opts.MaxCount == 0 { + // by default we display 2 recently pushed new branch + opts.MaxCount = 2 + } + for _, branch := range branches { + // whether branch have already created PR + count, err := db.GetEngine(ctx).Table("pull_request"). + // we should not only use branch name here, because if there are branches with same name in other repos, + // we can not detect them correctly + Where(builder.Eq{"head_repo_id": branch.RepoID, "head_branch": branch.Name}).Count() + if err != nil { + return nil, err + } + + // if no PR, we add to the result + if count == 0 { + if err := branch.LoadRepo(ctx); err != nil { + return nil, err + } + + branchDisplayName := branch.Name + if branch.Repo.ID != opts.BaseRepo.ID && branch.Repo.ID != opts.Repo.ID { + branchDisplayName = fmt.Sprintf("%s:%s", branch.Repo.FullName(), branchDisplayName) + } + newBranches = append(newBranches, &RecentlyPushedNewBranch{ + BranchDisplayName: branchDisplayName, + BranchLink: fmt.Sprintf("%s/src/branch/%s", branch.Repo.Link(), util.PathEscapeSegments(branch.Name)), + BranchCompareURL: branch.Repo.ComposeBranchCompareURL(opts.BaseRepo, branch.Name), + CommitTime: branch.CommitTime, + }) + } + if len(newBranches) == opts.MaxCount { + break + } + } + + return newBranches, nil } diff --git a/models/git/branch_list.go b/models/git/branch_list.go index 980bd7b4c9..5c887461d5 100644 --- a/models/git/branch_list.go +++ b/models/git/branch_list.go @@ -7,6 +7,7 @@ import ( "context" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/optional" @@ -59,6 +60,24 @@ func (branches BranchList) LoadPusher(ctx context.Context) error { return nil } +func (branches BranchList) LoadRepo(ctx context.Context) error { + ids := container.FilterSlice(branches, func(branch *Branch) (int64, bool) { + return branch.RepoID, branch.RepoID > 0 && branch.Repo == nil + }) + + reposMap := make(map[int64]*repo_model.Repository, len(ids)) + if err := db.GetEngine(ctx).In("id", ids).Find(&reposMap); err != nil { + return err + } + for _, branch := range branches { + if branch.RepoID <= 0 || branch.Repo != nil { + continue + } + branch.Repo = reposMap[branch.RepoID] + } + return nil +} + type FindBranchOptions struct { db.ListOptions RepoID int64 diff --git a/models/organization/org_user_test.go b/models/organization/org_user_test.go index 7924517f31..cf7acdf83b 100644 --- a/models/organization/org_user_test.go +++ b/models/organization/org_user_test.go @@ -81,7 +81,7 @@ func TestUserListIsPublicMember(t *testing.T) { {3, map[int64]bool{2: true, 4: false, 28: true}}, {6, map[int64]bool{5: true, 28: true}}, {7, map[int64]bool{5: false}}, - {25, map[int64]bool{24: true}}, + {25, map[int64]bool{12: true, 24: true}}, {22, map[int64]bool{}}, } for _, v := range tt { @@ -108,8 +108,8 @@ func TestUserListIsUserOrgOwner(t *testing.T) { {3, map[int64]bool{2: true, 4: false, 28: false}}, {6, map[int64]bool{5: true, 28: false}}, {7, map[int64]bool{5: true}}, - {25, map[int64]bool{24: false}}, // ErrTeamNotExist - {22, map[int64]bool{}}, // No member + {25, map[int64]bool{12: true, 24: false}}, // ErrTeamNotExist + {22, map[int64]bool{}}, // No member } for _, v := range tt { t.Run(fmt.Sprintf("IsUserOrgOwnerOfOrgId%d", v.orgid), func(t *testing.T) { diff --git a/models/repo/repo_list.go b/models/repo/repo_list.go index 987c7df9b0..eacc98e222 100644 --- a/models/repo/repo_list.go +++ b/models/repo/repo_list.go @@ -175,6 +175,8 @@ type SearchRepoOptions struct { // True -> include just forks // False -> include just non-forks Fork optional.Option[bool] + // If Fork option is True, you can use this option to limit the forks of a special repo by repo id. + ForkFrom int64 // None -> include templates AND non-templates // True -> include just templates // False -> include just non-templates @@ -514,6 +516,10 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { cond = cond.And(builder.Eq{"is_fork": false}) } else { cond = cond.And(builder.Eq{"is_fork": opts.Fork.Value()}) + + if opts.ForkFrom > 0 && opts.Fork.Value() { + cond = cond.And(builder.Eq{"fork_id": opts.ForkFrom}) + } } } diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index e4e6201c24..e1498c0d58 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -29,6 +29,7 @@ import ( "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" issue_model "code.gitea.io/gitea/models/issues" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" unit_model "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" @@ -1027,15 +1028,26 @@ func renderHomeCode(ctx *context.Context) { return } - showRecentlyPushedNewBranches := true - if ctx.Repo.Repository.IsMirror || - !ctx.Repo.Repository.UnitEnabled(ctx, unit_model.TypePullRequests) { - showRecentlyPushedNewBranches = false + opts := &git_model.FindRecentlyPushedNewBranchesOptions{ + Repo: ctx.Repo.Repository, + BaseRepo: ctx.Repo.Repository, } - if showRecentlyPushedNewBranches { - ctx.Data["RecentlyPushedNewBranches"], err = git_model.FindRecentlyPushedNewBranches(ctx, ctx.Repo.Repository.ID, ctx.Doer.ID, ctx.Repo.Repository.DefaultBranch) + if ctx.Repo.Repository.IsFork { + opts.BaseRepo = ctx.Repo.Repository.BaseRepo + } + + baseRepoPerm, err := access_model.GetUserRepoPermission(ctx, opts.BaseRepo, ctx.Doer) + if err != nil { + ctx.ServerError("GetUserRepoPermission", err) + return + } + + if !opts.Repo.IsMirror && !opts.BaseRepo.IsMirror && + opts.BaseRepo.UnitEnabled(ctx, unit_model.TypePullRequests) && + baseRepoPerm.CanRead(unit_model.TypePullRequests) { + ctx.Data["RecentlyPushedNewBranches"], err = git_model.FindRecentlyPushedNewBranches(ctx, ctx.Doer, opts) if err != nil { - ctx.ServerError("GetRecentlyPushedBranches", err) + ctx.ServerError("FindRecentlyPushedNewBranches", err) return } } diff --git a/templates/repo/code/recently_pushed_new_branches.tmpl b/templates/repo/code/recently_pushed_new_branches.tmpl index b808f413d3..7f613fcba7 100644 --- a/templates/repo/code/recently_pushed_new_branches.tmpl +++ b/templates/repo/code/recently_pushed_new_branches.tmpl @@ -2,10 +2,10 @@ <div class="ui positive message tw-flex tw-items-center"> <div class="tw-flex-1"> {{$timeSince := TimeSince .CommitTime.AsTime ctx.Locale}} - {{$branchLink := HTMLFormat `<a href="%s/src/branch/%s">%s</a>` $.RepoLink (PathEscapeSegments .Name) .Name}} + {{$branchLink := HTMLFormat `<a href="%s">%s</a>` .BranchLink .BranchDisplayName}} {{ctx.Locale.Tr "repo.pulls.recently_pushed_new_branches" $branchLink $timeSince}} </div> - <a role="button" class="ui compact green button tw-m-0" href="{{$.Repository.ComposeBranchCompareURL $.Repository.BaseRepo .Name}}"> + <a role="button" class="ui compact green button tw-m-0" href="{{.BranchCompareURL}}"> {{ctx.Locale.Tr "repo.pulls.compare_changes"}} </a> </div> diff --git a/tests/integration/api_user_orgs_test.go b/tests/integration/api_user_orgs_test.go index b6b4b6f2b2..c656ded5ae 100644 --- a/tests/integration/api_user_orgs_test.go +++ b/tests/integration/api_user_orgs_test.go @@ -29,6 +29,7 @@ func TestUserOrgs(t *testing.T) { org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "org3"}) org17 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "org17"}) + org35 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "private_org35"}) assert.Equal(t, []*api.Organization{ { @@ -55,6 +56,18 @@ func TestUserOrgs(t *testing.T) { Location: "", Visibility: "public", }, + { + ID: 35, + Name: org35.Name, + UserName: org35.Name, + FullName: org35.FullName, + Email: org35.Email, + AvatarURL: org35.AvatarLink(db.DefaultContext), + Description: "", + Website: "", + Location: "", + Visibility: "private", + }, }, orgs) // user itself should get it's org's he is a member of @@ -102,6 +115,7 @@ func TestMyOrgs(t *testing.T) { DecodeJSON(t, resp, &orgs) org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "org3"}) org17 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "org17"}) + org35 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "private_org35"}) assert.Equal(t, []*api.Organization{ { @@ -128,5 +142,17 @@ func TestMyOrgs(t *testing.T) { Location: "", Visibility: "public", }, + { + ID: 35, + Name: org35.Name, + UserName: org35.Name, + FullName: org35.FullName, + Email: org35.Email, + AvatarURL: org35.AvatarLink(db.DefaultContext), + Description: "", + Website: "", + Location: "", + Visibility: "private", + }, }, orgs) } diff --git a/tests/integration/compare_test.go b/tests/integration/compare_test.go index 7fb8dbc332..9f73ac80e2 100644 --- a/tests/integration/compare_test.go +++ b/tests/integration/compare_test.go @@ -140,7 +140,7 @@ func TestCompareCodeExpand(t *testing.T) { user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) session = loginUser(t, user2.Name) - testRepoFork(t, session, user1.Name, repo.Name, user2.Name, "test_blob_excerpt-fork") + testRepoFork(t, session, user1.Name, repo.Name, user2.Name, "test_blob_excerpt-fork", "") testCreateBranch(t, session, user2.Name, "test_blob_excerpt-fork", "branch/main", "forked-branch", http.StatusSeeOther) testEditFile(t, session, user2.Name, "test_blob_excerpt-fork", "forked-branch", "README.md", strings.Repeat("a\n", 15)+"CHANGED\n"+strings.Repeat("a\n", 15)) diff --git a/tests/integration/empty_repo_test.go b/tests/integration/empty_repo_test.go index ea393a6061..002aa5600e 100644 --- a/tests/integration/empty_repo_test.go +++ b/tests/integration/empty_repo_test.go @@ -6,9 +6,11 @@ package integration import ( "bytes" "encoding/base64" + "fmt" "io" "mime/multipart" "net/http" + "net/http/httptest" "testing" auth_model "code.gitea.io/gitea/models/auth" @@ -24,6 +26,17 @@ import ( "github.com/stretchr/testify/assert" ) +func testAPINewFile(t *testing.T, session *TestSession, user, repo, branch, treePath, content string) *httptest.ResponseRecorder { + url := fmt.Sprintf("/%s/%s/_new/%s", user, repo, branch) + req := NewRequestWithValues(t, "POST", url, map[string]string{ + "_csrf": GetCSRF(t, session, "/user/settings"), + "commit_choice": "direct", + "tree_path": treePath, + "content": content, + }) + return session.MakeRequest(t, req, http.StatusSeeOther) +} + func TestEmptyRepo(t *testing.T) { defer tests.PrepareTestEnv(t)() subPaths := []string{ diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go index f9bd352b62..18f415083c 100644 --- a/tests/integration/integration_test.go +++ b/tests/integration/integration_test.go @@ -485,6 +485,7 @@ func VerifyJSONSchema(t testing.TB, resp *httptest.ResponseRecorder, schemaFile assert.True(t, result.Valid()) } +// GetCSRF returns CSRF token from body func GetCSRF(t testing.TB, session *TestSession, urlStr string) string { t.Helper() req := NewRequest(t, "GET", urlStr) @@ -492,3 +493,11 @@ func GetCSRF(t testing.TB, session *TestSession, urlStr string) string { doc := NewHTMLParser(t, resp.Body) return doc.GetCSRF() } + +// GetCSRFFrom returns CSRF token from body +func GetCSRFFromCookie(t testing.TB, session *TestSession, urlStr string) string { + t.Helper() + req := NewRequest(t, "GET", urlStr) + session.MakeRequest(t, req, http.StatusOK) + return session.GetCookie("_csrf").Value +} diff --git a/tests/integration/pull_compare_test.go b/tests/integration/pull_compare_test.go index 39d9103dfd..aed699fd20 100644 --- a/tests/integration/pull_compare_test.go +++ b/tests/integration/pull_compare_test.go @@ -45,7 +45,7 @@ func TestPullCompare(t *testing.T) { defer tests.PrepareTestEnv(t)() session := loginUser(t, "user1") - testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testCreateBranch(t, session, "user1", "repo1", "branch/master", "master1", http.StatusSeeOther) testEditFile(t, session, "user1", "repo1", "master1", "README.md", "Hello, World (Edited)\n") testPullCreate(t, session, "user1", "repo1", false, "master", "master1", "This is a pull title") diff --git a/tests/integration/pull_create_test.go b/tests/integration/pull_create_test.go index 7add8e1db6..5a06a7817f 100644 --- a/tests/integration/pull_create_test.go +++ b/tests/integration/pull_create_test.go @@ -85,7 +85,7 @@ func testPullCreateDirectly(t *testing.T, session *TestSession, baseRepoOwner, b func TestPullCreate(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { session := loginUser(t, "user1") - testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title") @@ -113,7 +113,7 @@ func TestPullCreate(t *testing.T) { func TestPullCreate_TitleEscape(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { session := loginUser(t, "user1") - testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "<i>XSS PR</i>") @@ -177,7 +177,7 @@ func TestPullBranchDelete(t *testing.T) { defer tests.PrepareTestEnv(t)() session := loginUser(t, "user1") - testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testCreateBranch(t, session, "user1", "repo1", "branch/master", "master1", http.StatusSeeOther) testEditFile(t, session, "user1", "repo1", "master1", "README.md", "Hello, World (Edited)\n") resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master1", "This is a pull title") diff --git a/tests/integration/pull_merge_test.go b/tests/integration/pull_merge_test.go index 979c408388..3e7054c7e8 100644 --- a/tests/integration/pull_merge_test.go +++ b/tests/integration/pull_merge_test.go @@ -95,7 +95,7 @@ func TestPullMerge(t *testing.T) { hookTasksLenBefore := len(hookTasks) session := loginUser(t, "user1") - testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title") @@ -117,7 +117,7 @@ func TestPullRebase(t *testing.T) { hookTasksLenBefore := len(hookTasks) session := loginUser(t, "user1") - testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title") @@ -139,7 +139,7 @@ func TestPullRebaseMerge(t *testing.T) { hookTasksLenBefore := len(hookTasks) session := loginUser(t, "user1") - testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title") @@ -161,7 +161,7 @@ func TestPullSquash(t *testing.T) { hookTasksLenBefore := len(hookTasks) session := loginUser(t, "user1") - testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited!)\n") @@ -180,7 +180,7 @@ func TestPullSquash(t *testing.T) { func TestPullCleanUpAfterMerge(t *testing.T) { onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { session := loginUser(t, "user1") - testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFileToNewBranch(t, session, "user1", "repo1", "master", "feature/test", "README.md", "Hello, World (Edited - TestPullCleanUpAfterMerge)\n") resp := testPullCreate(t, session, "user1", "repo1", false, "master", "feature/test", "This is a pull title") @@ -215,7 +215,7 @@ func TestPullCleanUpAfterMerge(t *testing.T) { func TestCantMergeWorkInProgress(t *testing.T) { onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { session := loginUser(t, "user1") - testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "[wip] This is a pull title") @@ -234,7 +234,7 @@ func TestCantMergeWorkInProgress(t *testing.T) { func TestCantMergeConflict(t *testing.T) { onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { session := loginUser(t, "user1") - testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFileToNewBranch(t, session, "user1", "repo1", "master", "conflict", "README.md", "Hello, World (Edited Once)\n") testEditFileToNewBranch(t, session, "user1", "repo1", "master", "base", "README.md", "Hello, World (Edited Twice)\n") @@ -280,7 +280,7 @@ func TestCantMergeConflict(t *testing.T) { func TestCantMergeUnrelated(t *testing.T) { onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { session := loginUser(t, "user1") - testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFileToNewBranch(t, session, "user1", "repo1", "master", "base", "README.md", "Hello, World (Edited Twice)\n") // Now we want to create a commit on a branch that is totally unrelated to our current head @@ -375,7 +375,7 @@ func TestCantMergeUnrelated(t *testing.T) { func TestFastForwardOnlyMerge(t *testing.T) { onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { session := loginUser(t, "user1") - testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFileToNewBranch(t, session, "user1", "repo1", "master", "update", "README.md", "Hello, World 2\n") // Use API to create a pr from update to master @@ -416,7 +416,7 @@ func TestFastForwardOnlyMerge(t *testing.T) { func TestCantFastForwardOnlyMergeDiverging(t *testing.T) { onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { session := loginUser(t, "user1") - testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFileToNewBranch(t, session, "user1", "repo1", "master", "diverging", "README.md", "Hello, World diverged\n") testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World 2\n") @@ -539,7 +539,7 @@ func TestPullRetargetChildOnBranchDelete(t *testing.T) { onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { session := loginUser(t, "user1") testEditFileToNewBranch(t, session, "user2", "repo1", "master", "base-pr", "README.md", "Hello, World\n(Edited - TestPullRetargetOnCleanup - base PR)\n") - testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFileToNewBranch(t, session, "user1", "repo1", "base-pr", "child-pr", "README.md", "Hello, World\n(Edited - TestPullRetargetOnCleanup - base PR)\n(Edited - TestPullRetargetOnCleanup - child PR)") respBasePR := testPullCreate(t, session, "user2", "repo1", true, "master", "base-pr", "Base Pull Request") @@ -568,7 +568,7 @@ func TestPullRetargetChildOnBranchDelete(t *testing.T) { func TestPullDontRetargetChildOnWrongRepo(t *testing.T) { onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { session := loginUser(t, "user1") - testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFileToNewBranch(t, session, "user1", "repo1", "master", "base-pr", "README.md", "Hello, World\n(Edited - TestPullDontRetargetChildOnWrongRepo - base PR)\n") testEditFileToNewBranch(t, session, "user1", "repo1", "base-pr", "child-pr", "README.md", "Hello, World\n(Edited - TestPullDontRetargetChildOnWrongRepo - base PR)\n(Edited - TestPullDontRetargetChildOnWrongRepo - child PR)") @@ -599,7 +599,7 @@ func TestPullMergeIndexerNotifier(t *testing.T) { onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { // create a pull request session := loginUser(t, "user1") - testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") createPullResp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "Indexer notifier test pull") @@ -676,7 +676,7 @@ func TestPullAutoMergeAfterCommitStatusSucceed(t *testing.T) { session := loginUser(t, "user1") user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) forkedName := "repo1-1" - testRepoFork(t, session, "user2", "repo1", "user1", forkedName) + testRepoFork(t, session, "user2", "repo1", "user1", forkedName, "") defer func() { testDeleteRepository(t, session, "user1", forkedName) }() @@ -759,7 +759,7 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApproval(t *testing.T) { session := loginUser(t, "user1") user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) forkedName := "repo1-2" - testRepoFork(t, session, "user2", "repo1", "user1", forkedName) + testRepoFork(t, session, "user2", "repo1", "user1", forkedName, "") defer func() { testDeleteRepository(t, session, "user1", forkedName) }() diff --git a/tests/integration/pull_review_test.go b/tests/integration/pull_review_test.go index df5d7b38ea..5ecf3ef469 100644 --- a/tests/integration/pull_review_test.go +++ b/tests/integration/pull_review_test.go @@ -186,7 +186,7 @@ func TestPullView_GivenApproveOrRejectReviewOnClosedPR(t *testing.T) { user2Session := loginUser(t, "user2") // Have user1 create a fork of repo1. - testRepoFork(t, user1Session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, user1Session, "user2", "repo1", "user1", "repo1", "") t.Run("Submit approve/reject review on merged PR", func(t *testing.T) { // Create a merged PR (made by user1) in the upstream repo1. diff --git a/tests/integration/pull_status_test.go b/tests/integration/pull_status_test.go index 80eea34513..26e1baeb11 100644 --- a/tests/integration/pull_status_test.go +++ b/tests/integration/pull_status_test.go @@ -23,7 +23,7 @@ import ( func TestPullCreate_CommitStatus(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { session := loginUser(t, "user1") - testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFileToNewBranch(t, session, "user1", "repo1", "master", "status1", "README.md", "status1") url := path.Join("user1", "repo1", "compare", "master...status1") @@ -122,7 +122,7 @@ func TestPullCreate_EmptyChangesWithDifferentCommits(t *testing.T) { // so we need to have this meta commit also in develop branch. onGiteaRun(t, func(t *testing.T, u *url.URL) { session := loginUser(t, "user1") - testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFileToNewBranch(t, session, "user1", "repo1", "master", "status1", "README.md", "status1") testEditFileToNewBranch(t, session, "user1", "repo1", "status1", "status1", "README.md", "# repo1\n\nDescription for repo1") @@ -147,7 +147,7 @@ func TestPullCreate_EmptyChangesWithDifferentCommits(t *testing.T) { func TestPullCreate_EmptyChangesWithSameCommits(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { session := loginUser(t, "user1") - testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testCreateBranch(t, session, "user1", "repo1", "branch/master", "status1", http.StatusSeeOther) url := path.Join("user1", "repo1", "compare", "master...status1") req := NewRequestWithValues(t, "POST", url, diff --git a/tests/integration/repo_activity_test.go b/tests/integration/repo_activity_test.go index 792554db4b..b04560379d 100644 --- a/tests/integration/repo_activity_test.go +++ b/tests/integration/repo_activity_test.go @@ -20,7 +20,7 @@ func TestRepoActivity(t *testing.T) { session := loginUser(t, "user1") // Create PRs (1 merged & 2 proposed) - testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title") elem := strings.Split(test.RedirectURL(resp), "/") diff --git a/tests/integration/repo_branch_test.go b/tests/integration/repo_branch_test.go index baa8da4b75..d1bc9198c3 100644 --- a/tests/integration/repo_branch_test.go +++ b/tests/integration/repo_branch_test.go @@ -4,26 +4,37 @@ package integration import ( + "fmt" "net/http" "net/url" "path" "strings" "testing" + auth_model "code.gitea.io/gitea/models/auth" + org_model "code.gitea.io/gitea/models/organization" + "code.gitea.io/gitea/models/perm" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unit" + "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/setting" + api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/tests" + "github.com/PuerkitoBio/goquery" "github.com/stretchr/testify/assert" ) func testCreateBranch(t testing.TB, session *TestSession, user, repo, oldRefSubURL, newBranchName string, expectedStatus int) string { var csrf string if expectedStatus == http.StatusNotFound { - csrf = GetCSRF(t, session, path.Join(user, repo, "src/branch/master")) + // src/branch/branch_name may not container "_csrf" input, + // so we need to get it from cookies not from body + csrf = GetCSRFFromCookie(t, session, path.Join(user, repo, "src/branch/master")) } else { - csrf = GetCSRF(t, session, path.Join(user, repo, "src", oldRefSubURL)) + csrf = GetCSRFFromCookie(t, session, path.Join(user, repo, "src", oldRefSubURL)) } req := NewRequestWithValues(t, "POST", path.Join(user, repo, "branches/_new", oldRefSubURL), map[string]string{ "_csrf": csrf, @@ -145,3 +156,136 @@ func TestCreateBranchInvalidCSRF(t *testing.T) { strings.TrimSpace(htmlDoc.doc.Find(".ui.message").Text()), ) } + +func prepareBranch(t *testing.T, session *TestSession, repo *repo_model.Repository) { + baseRefSubURL := fmt.Sprintf("branch/%s", repo.DefaultBranch) + + // create branch with no new commit + testCreateBranch(t, session, repo.OwnerName, repo.Name, baseRefSubURL, "no-commit", http.StatusSeeOther) + + // create branch with commit + testCreateBranch(t, session, repo.OwnerName, repo.Name, baseRefSubURL, "new-commit", http.StatusSeeOther) + testAPINewFile(t, session, repo.OwnerName, repo.Name, "new-commit", "new-commit.txt", "new-commit") + + // create deleted branch + testCreateBranch(t, session, repo.OwnerName, repo.Name, "branch/new-commit", "deleted-branch", http.StatusSeeOther) + testUIDeleteBranch(t, session, repo.OwnerName, repo.Name, "deleted-branch") +} + +func testCreatePullToDefaultBranch(t *testing.T, session *TestSession, baseRepo, headRepo *repo_model.Repository, headBranch, title string) string { + srcRef := headBranch + if baseRepo.ID != headRepo.ID { + srcRef = fmt.Sprintf("%s/%s:%s", headRepo.OwnerName, headRepo.Name, headBranch) + } + resp := testPullCreate(t, session, baseRepo.OwnerName, baseRepo.Name, false, baseRepo.DefaultBranch, srcRef, title) + elem := strings.Split(test.RedirectURL(resp), "/") + // return pull request ID + return elem[4] +} + +func prepareRepoPR(t *testing.T, baseSession, headSession *TestSession, baseRepo, headRepo *repo_model.Repository) { + // create opening PR + testCreateBranch(t, headSession, headRepo.OwnerName, headRepo.Name, "branch/new-commit", "opening-pr", http.StatusSeeOther) + testCreatePullToDefaultBranch(t, baseSession, baseRepo, headRepo, "opening-pr", "opening pr") + + // create closed PR + testCreateBranch(t, headSession, headRepo.OwnerName, headRepo.Name, "branch/new-commit", "closed-pr", http.StatusSeeOther) + prID := testCreatePullToDefaultBranch(t, baseSession, baseRepo, headRepo, "closed-pr", "closed pr") + testIssueClose(t, baseSession, baseRepo.OwnerName, baseRepo.Name, prID) + + // create closed PR with deleted branch + testCreateBranch(t, headSession, headRepo.OwnerName, headRepo.Name, "branch/new-commit", "closed-pr-deleted", http.StatusSeeOther) + prID = testCreatePullToDefaultBranch(t, baseSession, baseRepo, headRepo, "closed-pr-deleted", "closed pr with deleted branch") + testIssueClose(t, baseSession, baseRepo.OwnerName, baseRepo.Name, prID) + testUIDeleteBranch(t, headSession, headRepo.OwnerName, headRepo.Name, "closed-pr-deleted") + + // create merged PR + testCreateBranch(t, headSession, headRepo.OwnerName, headRepo.Name, "branch/new-commit", "merged-pr", http.StatusSeeOther) + prID = testCreatePullToDefaultBranch(t, baseSession, baseRepo, headRepo, "merged-pr", "merged pr") + testAPINewFile(t, headSession, headRepo.OwnerName, headRepo.Name, "merged-pr", fmt.Sprintf("new-commit-%s.txt", headRepo.Name), "new-commit") + testPullMerge(t, baseSession, baseRepo.OwnerName, baseRepo.Name, prID, repo_model.MergeStyleRebaseMerge, false) + + // create merged PR with deleted branch + testCreateBranch(t, headSession, headRepo.OwnerName, headRepo.Name, "branch/new-commit", "merged-pr-deleted", http.StatusSeeOther) + prID = testCreatePullToDefaultBranch(t, baseSession, baseRepo, headRepo, "merged-pr-deleted", "merged pr with deleted branch") + testAPINewFile(t, headSession, headRepo.OwnerName, headRepo.Name, "merged-pr-deleted", fmt.Sprintf("new-commit-%s-2.txt", headRepo.Name), "new-commit") + testPullMerge(t, baseSession, baseRepo.OwnerName, baseRepo.Name, prID, repo_model.MergeStyleRebaseMerge, true) +} + +func checkRecentlyPushedNewBranches(t *testing.T, session *TestSession, repoPath string, expected []string) { + branches := make([]string, 0, 2) + req := NewRequest(t, "GET", repoPath) + resp := session.MakeRequest(t, req, http.StatusOK) + doc := NewHTMLParser(t, resp.Body) + doc.doc.Find(".ui.positive.message div a").Each(func(index int, branch *goquery.Selection) { + branches = append(branches, branch.Text()) + }) + assert.Equal(t, expected, branches) +} + +func TestRecentlyPushedNewBranches(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + onGiteaRun(t, func(t *testing.T, u *url.URL) { + user1Session := loginUser(t, "user1") + user2Session := loginUser(t, "user2") + user12Session := loginUser(t, "user12") + user13Session := loginUser(t, "user13") + + // prepare branch and PRs in original repo + repo10 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}) + prepareBranch(t, user12Session, repo10) + prepareRepoPR(t, user12Session, user12Session, repo10, repo10) + + // outdated new branch should not be displayed + checkRecentlyPushedNewBranches(t, user12Session, "user12/repo10", []string{"new-commit"}) + + // create a fork repo in public org + testRepoFork(t, user12Session, repo10.OwnerName, repo10.Name, "org25", "org25_fork_repo10", "new-commit") + orgPublicForkRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: 25, Name: "org25_fork_repo10"}) + prepareRepoPR(t, user12Session, user12Session, repo10, orgPublicForkRepo) + + // user12 is the owner of the repo10 and the organization org25 + // in repo10, user12 has opening/closed/merged pr and closed/merged pr with deleted branch + checkRecentlyPushedNewBranches(t, user12Session, "user12/repo10", []string{"org25/org25_fork_repo10:new-commit", "new-commit"}) + + userForkRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 11}) + testCtx := NewAPITestContext(t, repo10.OwnerName, repo10.Name, auth_model.AccessTokenScopeWriteRepository) + t.Run("AddUser13AsCollaborator", doAPIAddCollaborator(testCtx, "user13", perm.AccessModeWrite)) + prepareBranch(t, user13Session, userForkRepo) + prepareRepoPR(t, user13Session, user13Session, repo10, userForkRepo) + + // create branch with same name in different repo by user13 + testCreateBranch(t, user13Session, repo10.OwnerName, repo10.Name, "branch/new-commit", "same-name-branch", http.StatusSeeOther) + testCreateBranch(t, user13Session, userForkRepo.OwnerName, userForkRepo.Name, "branch/new-commit", "same-name-branch", http.StatusSeeOther) + testCreatePullToDefaultBranch(t, user13Session, repo10, userForkRepo, "same-name-branch", "same name branch pr") + + // user13 pushed 2 branches with the same name in repo10 and repo11 + // and repo11's branch has a pr, but repo10's branch doesn't + // in this case, we should get repo10's branch but not repo11's branch + checkRecentlyPushedNewBranches(t, user13Session, "user12/repo10", []string{"same-name-branch", "user13/repo11:new-commit"}) + + // create a fork repo in private org + testRepoFork(t, user1Session, repo10.OwnerName, repo10.Name, "private_org35", "org35_fork_repo10", "new-commit") + orgPrivateForkRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: 35, Name: "org35_fork_repo10"}) + prepareRepoPR(t, user1Session, user1Session, repo10, orgPrivateForkRepo) + + // user1 is the owner of private_org35 and no write permission to repo10 + // so user1 can only see the branch in org35_fork_repo10 + checkRecentlyPushedNewBranches(t, user1Session, "user12/repo10", []string{"private_org35/org35_fork_repo10:new-commit"}) + + // user2 push a branch in private_org35 + testCreateBranch(t, user2Session, orgPrivateForkRepo.OwnerName, orgPrivateForkRepo.Name, "branch/new-commit", "user-read-permission", http.StatusSeeOther) + // convert write permission to read permission for code unit + token := getTokenForLoggedInUser(t, user1Session, auth_model.AccessTokenScopeWriteOrganization) + req := NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/teams/%d", 24), &api.EditTeamOption{ + Name: "team24", + UnitsMap: map[string]string{"repo.code": "read"}, + }).AddTokenAuth(token) + MakeRequest(t, req, http.StatusOK) + teamUnit := unittest.AssertExistsAndLoadBean(t, &org_model.TeamUnit{TeamID: 24, Type: unit.TypeCode}) + assert.Equal(t, perm.AccessModeRead, teamUnit.AccessMode) + // user2 can see the branch as it is created by user2 + checkRecentlyPushedNewBranches(t, user2Session, "user12/repo10", []string{"private_org35/org35_fork_repo10:user-read-permission"}) + }) +} diff --git a/tests/integration/repo_fork_test.go b/tests/integration/repo_fork_test.go index ca5d61ecc2..feebebf062 100644 --- a/tests/integration/repo_fork_test.go +++ b/tests/integration/repo_fork_test.go @@ -16,7 +16,7 @@ import ( "github.com/stretchr/testify/assert" ) -func testRepoFork(t *testing.T, session *TestSession, ownerName, repoName, forkOwnerName, forkRepoName string) *httptest.ResponseRecorder { +func testRepoFork(t *testing.T, session *TestSession, ownerName, repoName, forkOwnerName, forkRepoName, forkBranch string) *httptest.ResponseRecorder { forkOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: forkOwnerName}) // Step0: check the existence of the to-fork repo @@ -41,9 +41,10 @@ func testRepoFork(t *testing.T, session *TestSession, ownerName, repoName, forkO _, exists = htmlDoc.doc.Find(fmt.Sprintf(".owner.dropdown .item[data-value=\"%d\"]", forkOwner.ID)).Attr("data-value") assert.True(t, exists, fmt.Sprintf("Fork owner '%s' is not present in select box", forkOwnerName)) req = NewRequestWithValues(t, "POST", link, map[string]string{ - "_csrf": htmlDoc.GetCSRF(), - "uid": fmt.Sprintf("%d", forkOwner.ID), - "repo_name": forkRepoName, + "_csrf": htmlDoc.GetCSRF(), + "uid": fmt.Sprintf("%d", forkOwner.ID), + "repo_name": forkRepoName, + "fork_single_branch": forkBranch, }) session.MakeRequest(t, req, http.StatusSeeOther) @@ -57,13 +58,13 @@ func testRepoFork(t *testing.T, session *TestSession, ownerName, repoName, forkO func TestRepoFork(t *testing.T) { defer tests.PrepareTestEnv(t)() session := loginUser(t, "user1") - testRepoFork(t, session, "user2", "repo1", "user1", "repo1") + testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") } func TestRepoForkToOrg(t *testing.T) { defer tests.PrepareTestEnv(t)() session := loginUser(t, "user2") - testRepoFork(t, session, "user2", "repo1", "org3", "repo1") + testRepoFork(t, session, "user2", "repo1", "org3", "repo1", "") // Check that no more forking is allowed as user2 owns repository // and org3 organization that owner user2 is also now has forked this repository From 3066114c2481b5f3a5e4cda65fdd22e768359e94 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Wed, 22 May 2024 00:25:10 +0000 Subject: [PATCH 342/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_pt-PT.ini | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index f4c77e4981..ea4c2d26dc 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -807,7 +807,7 @@ add_new_key=Adicionar Chave SSH add_new_gpg_key=Adicionar chave GPG key_content_ssh_placeholder=Começa com 'ssh-ed25519', 'ssh-rsa', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', 'ecdsa-sha2-nistp521', 'sk-ecdsa-sha2-nistp256@openssh.com', ou 'sk-ssh-ed25519@openssh.com' key_content_gpg_placeholder=Começa com '-----BEGIN PGP PUBLIC KEY BLOCK-----' -add_new_principal=Adicional Protagonista +add_new_principal=Adicionar protagonista ssh_key_been_used=Esta chave SSH já tinha sido adicionada ao servidor. ssh_key_name_used=Já existe uma chave SSH com o mesmo nome na sua conta. ssh_principal_been_used=Este protagonista já tinha sido adicionado ao servidor. @@ -3348,6 +3348,7 @@ mirror_sync_create=sincronizou a nova referência <a href="%[2]s">%[3]s</a> para mirror_sync_delete=sincronizou e eliminou a referência <code>%[2]s</code> em <a href="%[1]s">%[3]s</a> da réplica approve_pull_request=`aprovou <a href="%[1]s">%[3]s#%[2]s</a>` reject_pull_request=`sugeriu modificações para <a href="%[1]s">%[3]s#%[2]s</a>` +publish_release=`lançou <a href="%[2]s"> "%[4]s" </a> em <a href="%[1]s">%[3]s</a>` review_dismissed=`descartou a revisão de <b>%[4]s</b> para <a href="%[1]s">%[3]s#%[2]s</a>` review_dismissed_reason=Motivo: create_branch=criou o ramo <a href="%[2]s">%[3]s</a> em <a href="%[1]s">%[4]s</a> @@ -3414,6 +3415,7 @@ error.unit_not_allowed=Não tem permissão para aceder a esta parte do repositó title=Pacotes desc=Gerir pacotes do repositório. empty=Ainda não há pacotes. +no_metadata=Sem metadados. empty.documentation=Para obter mais informação sobre o registo de pacotes, veja <a target="_blank" rel="noopener noreferrer" href="%s">a documentação</a>. empty.repo=Carregou um pacote mas este não é apresentado aqui? Vá às <a href="%[1]s">configurações do pacote</a> e ligue-o a este repositório. registry.documentation=Para mais informação sobre o registo %s, veja <a target="_blank" rel="noopener noreferrer" href="%s">a documentação</a>. From de6f0488a67ad65bd2ac40356b08a78a365414cd Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 22 May 2024 02:47:18 +0200 Subject: [PATCH 343/370] Add nix flake for dev shell (#30967) To try it you need **nix** installed `nix-daemon ` running and your user has to be member of the **nix-users** group. Or use NixOS. then by just: ```sh nix develop -c $SHELL ``` a dedicated development environment with all needed packages will be created. --- flake.lock | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ flake.nix | 37 +++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000000..0b2278f080 --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1715534503, + "narHash": "sha256-5ZSVkFadZbFP1THataCaSf0JH2cAH3S29hU9rrxTEqk=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "2057814051972fa1453ddfb0d98badbea9b83c06", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000000..c6e915e9db --- /dev/null +++ b/flake.nix @@ -0,0 +1,37 @@ +{ + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + outputs = + { nixpkgs, flake-utils, ... }: + flake-utils.lib.eachDefaultSystem ( + system: + let + pkgs = nixpkgs.legacyPackages.${system}; + in + { + devShells.default = pkgs.mkShell { + buildInputs = with pkgs; [ + # generic + git + git-lfs + gnumake + gnused + gnutar + gzip + + # frontend + nodejs_20 + + # linting + python312 + poetry + + # backend + go_1_22 + ]; + }; + } + ); +} From 945dfed6a2646a5b3957ebcc8a5c08daf7a2c41b Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Wed, 22 May 2024 22:06:22 +0800 Subject: [PATCH 344/370] Update Actions documentation missing feature (#31034) Fix https://github.com/go-gitea/gitea/issues/25897#issuecomment-2117145391 --------- Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: yp05327 <576951401@qq.com> --- docs/content/usage/actions/comparison.en-us.md | 4 ++++ docs/content/usage/actions/comparison.zh-cn.md | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/docs/content/usage/actions/comparison.en-us.md b/docs/content/usage/actions/comparison.en-us.md index 1ea3afac5b..5b084e09c4 100644 --- a/docs/content/usage/actions/comparison.en-us.md +++ b/docs/content/usage/actions/comparison.en-us.md @@ -108,6 +108,10 @@ See [Creating an annotation for an error](https://docs.github.com/en/actions/usi It's ignored by Gitea Actions now. +### Expressions + +For [expressions](https://docs.github.com/en/actions/learn-github-actions/expressions), only [`always()`](https://docs.github.com/en/actions/learn-github-actions/expressions#always) is supported. + ## Missing UI features ### Pre and Post steps diff --git a/docs/content/usage/actions/comparison.zh-cn.md b/docs/content/usage/actions/comparison.zh-cn.md index 16b2181ba2..79450e8eab 100644 --- a/docs/content/usage/actions/comparison.zh-cn.md +++ b/docs/content/usage/actions/comparison.zh-cn.md @@ -108,6 +108,10 @@ Gitea Actions目前不支持此功能。 Gitea Actions目前不支持此功能。 +### 表达式 + +对于 [表达式](https://docs.github.com/en/actions/learn-github-actions/expressions), 当前仅 [`always()`](https://docs.github.com/en/actions/learn-github-actions/expressions#always) 被支持。 + ## 缺失的UI功能 ### 预处理和后处理步骤 From c9eac519961ecd5d0e1d6ee856ab532e8c16c65d Mon Sep 17 00:00:00 2001 From: Kemal Zebari <60799661+kemzeb@users.noreply.github.com> Date: Wed, 22 May 2024 07:39:46 -0700 Subject: [PATCH 345/370] Sync up deleted branches & action assets related cleanup documentation (#31022) Syncs up docs associated to actions and deleted branch cleanup i.e. in custom/app.example.ini and the config cheat sheet. --- custom/conf/app.example.ini | 11 +++++++++++ .../administration/config-cheat-sheet.en-us.md | 10 +++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 4df843b8ce..afbd20eb56 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -2036,6 +2036,17 @@ LEVEL = Info ;; or only create new users if UPDATE_EXISTING is set to false ;UPDATE_EXISTING = true +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Cleanup expired actions assets +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;[cron.cleanup_actions] +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;ENABLED = true +;RUN_AT_START = true +;SCHEDULE = @midnight + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Clean-up deleted branches diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index 6c429bb652..9ac1f5eb10 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -975,12 +975,20 @@ Default templates for project boards: - `SCHEDULE`: **@midnight** : Interval as a duration between each synchronization, it will always attempt synchronization when the instance starts. - `UPDATE_EXISTING`: **true**: Create new users, update existing user data and disable users that are not in external source anymore (default) or only create new users if UPDATE_EXISTING is set to false. -## Cron - Cleanup Expired Actions Assets (`cron.cleanup_actions`) +#### Cron - Cleanup Expired Actions Assets (`cron.cleanup_actions`) - `ENABLED`: **true**: Enable cleanup expired actions assets job. - `RUN_AT_START`: **true**: Run job at start time (if ENABLED). - `SCHEDULE`: **@midnight** : Cron syntax for the job. +#### Cron - Cleanup Deleted Branches (`cron.deleted_branches_cleanup`) + +- `ENABLED`: **true**: Enable deleted branches cleanup. +- `RUN_AT_START`: **true**: Run job at start time (if ENABLED). +- `NOTICE_ON_SUCCESS`: **false**: Set to true to log a success message. +- `SCHEDULE`: **@midnight**: Cron syntax for scheduling deleted branches cleanup. +- `OLDER_THAN`: **24h**: Branches deleted OLDER_THAN ago will be cleaned up. + ### Extended cron tasks (not enabled by default) #### Cron - Garbage collect all repositories (`cron.git_gc_repos`) From 90f4cf51a3b3ceec849970fffaaefbd0a2c1eaf1 Mon Sep 17 00:00:00 2001 From: techknowlogick <techknowlogick@gitea.com> Date: Wed, 22 May 2024 19:34:52 -0400 Subject: [PATCH 346/370] align s3 files with docker naming (#31050) docker images have `-nightly`, this will append the same to binaries uploaded to s3. --- .github/workflows/release-nightly.yml | 2 +- Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release-nightly.yml b/.github/workflows/release-nightly.yml index fbaa27102c..10fe94b296 100644 --- a/.github/workflows/release-nightly.yml +++ b/.github/workflows/release-nightly.yml @@ -47,7 +47,7 @@ jobs: run: | REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//') echo "Cleaned name is ${REF_NAME}" - echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT" + echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT" - name: configure aws uses: aws-actions/configure-aws-credentials@v4 with: diff --git a/Makefile b/Makefile index e8006e4031..80efcbe46d 100644 --- a/Makefile +++ b/Makefile @@ -88,7 +88,7 @@ ifneq ($(GITHUB_REF_TYPE),branch) GITEA_VERSION ?= $(VERSION) else ifneq ($(GITHUB_REF_NAME),) - VERSION ?= $(subst release/v,,$(GITHUB_REF_NAME)) + VERSION ?= $(subst release/v,,$(GITHUB_REF_NAME))-nightly else VERSION ?= main endif From 6d119aafd163d74117336a2d637f4b05c09081e1 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Thu, 23 May 2024 00:25:10 +0000 Subject: [PATCH 347/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_pt-PT.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index ea4c2d26dc..ea0f96e4f8 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -798,9 +798,9 @@ manage_ssh_keys=Gerir chaves SSH manage_ssh_principals=Gerir Protagonistas de Certificados SSH manage_gpg_keys=Gerir chaves GPG add_key=Adicionar chave -ssh_desc=Essas chaves públicas SSH estão associadas à sua conta. As chaves privadas correspondentes permitem acesso total aos seus repositórios. +ssh_desc=Estas chaves públicas SSH estão associadas à sua conta. As chaves privadas correspondentes permitem acesso total aos seus repositórios. principal_desc=Estes protagonistas de certificados SSH estão associados à sua conta e permitem acesso total aos seus repositórios. -gpg_desc=Essas chaves GPG públicas estão associadas à sua conta. Mantenha as suas chaves privadas seguras, uma vez que elas permitem a validação dos cometimentos. +gpg_desc=Estas chaves GPG públicas estão associadas à sua conta. Mantenha as suas chaves privadas seguras, uma vez que elas permitem a validação dos cometimentos. ssh_helper=<strong>Precisa de ajuda?</strong> Dê uma vista de olhos no guia do GitHub para <a href="%s">criar as suas próprias chaves SSH</a> ou para resolver <a href="%s">problemas comuns</a> que pode encontrar ao usar o SSH. gpg_helper=<strong>Precisa de ajuda?</strong> Dê uma vista de olhos no guia do GitHub <a href="%s">sobre GPG</a>. add_new_key=Adicionar Chave SSH From 7b93d6c8f786fe201201060c1785d19a3a1a3be2 Mon Sep 17 00:00:00 2001 From: techknowlogick <techknowlogick@gitea.com> Date: Thu, 23 May 2024 08:18:25 -0400 Subject: [PATCH 348/370] Alpine 3.20 has been released (#31047) --- Dockerfile | 4 ++-- Dockerfile.rootless | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index b647c0cd59..21a8ce0d75 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build stage -FROM docker.io/library/golang:1.22-alpine3.19 AS build-env +FROM docker.io/library/golang:1.22-alpine3.20 AS build-env ARG GOPROXY ENV GOPROXY ${GOPROXY:-direct} @@ -41,7 +41,7 @@ RUN chmod 755 /tmp/local/usr/bin/entrypoint \ /go/src/code.gitea.io/gitea/environment-to-ini RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete -FROM docker.io/library/alpine:3.19 +FROM docker.io/library/alpine:3.20 LABEL maintainer="maintainers@gitea.io" EXPOSE 22 3000 diff --git a/Dockerfile.rootless b/Dockerfile.rootless index dd7da97278..b1d2368252 100644 --- a/Dockerfile.rootless +++ b/Dockerfile.rootless @@ -1,5 +1,5 @@ # Build stage -FROM docker.io/library/golang:1.22-alpine3.19 AS build-env +FROM docker.io/library/golang:1.22-alpine3.20 AS build-env ARG GOPROXY ENV GOPROXY ${GOPROXY:-direct} @@ -39,7 +39,7 @@ RUN chmod 755 /tmp/local/usr/local/bin/docker-entrypoint.sh \ /go/src/code.gitea.io/gitea/environment-to-ini RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete -FROM docker.io/library/alpine:3.19 +FROM docker.io/library/alpine:3.20 LABEL maintainer="maintainers@gitea.io" EXPOSE 2222 3000 From 7ab0988af140aa3e0204979765f75961f1dc9c11 Mon Sep 17 00:00:00 2001 From: Zettat123 <zettat123@gmail.com> Date: Thu, 23 May 2024 21:01:02 +0800 Subject: [PATCH 349/370] Support setting the `default` attribute of the issue template dropdown field (#31045) Fix #31044 According to [GitHub issue template documentation](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-for-dropdown), the `default` attribute can be used to specify the preselected option for a dropdown field. --- modules/issue/template/template.go | 25 ++++++ modules/issue/template/template_test.go | 92 +++++++++++++++++++++++ templates/repo/issue/fields/dropdown.tmpl | 2 +- 3 files changed, 118 insertions(+), 1 deletion(-) diff --git a/modules/issue/template/template.go b/modules/issue/template/template.go index 3be48b9edc..cf5fcf28e5 100644 --- a/modules/issue/template/template.go +++ b/modules/issue/template/template.go @@ -91,6 +91,9 @@ func validateYaml(template *api.IssueTemplate) error { if err := validateOptions(field, idx); err != nil { return err } + if err := validateDropdownDefault(position, field.Attributes); err != nil { + return err + } case api.IssueFormFieldTypeCheckboxes: if err := validateStringItem(position, field.Attributes, false, "description"); err != nil { return err @@ -249,6 +252,28 @@ func validateBoolItem(position errorPosition, m map[string]any, names ...string) return nil } +func validateDropdownDefault(position errorPosition, attributes map[string]any) error { + v, ok := attributes["default"] + if !ok { + return nil + } + defaultValue, ok := v.(int) + if !ok { + return position.Errorf("'default' should be an int") + } + + options, ok := attributes["options"].([]any) + if !ok { + // should not happen + return position.Errorf("'options' is required and should be a array") + } + if defaultValue < 0 || defaultValue >= len(options) { + return position.Errorf("the value of 'default' is out of range") + } + + return nil +} + type errorPosition string func (p errorPosition) Errorf(format string, a ...any) error { diff --git a/modules/issue/template/template_test.go b/modules/issue/template/template_test.go index e24b962d61..481058754d 100644 --- a/modules/issue/template/template_test.go +++ b/modules/issue/template/template_test.go @@ -355,6 +355,96 @@ body: `, wantErr: "body[0](checkboxes), option[1]: can not require a hidden checkbox", }, + { + name: "dropdown default is not an integer", + content: ` +name: "test" +about: "this is about" +body: + - type: dropdown + id: "1" + attributes: + label: Label of dropdown + description: Description of dropdown + multiple: true + options: + - Option 1 of dropdown + - Option 2 of dropdown + - Option 3 of dropdown + default: "def" + validations: + required: true +`, + wantErr: "body[0](dropdown): 'default' should be an int", + }, + { + name: "dropdown default is out of range", + content: ` +name: "test" +about: "this is about" +body: + - type: dropdown + id: "1" + attributes: + label: Label of dropdown + description: Description of dropdown + multiple: true + options: + - Option 1 of dropdown + - Option 2 of dropdown + - Option 3 of dropdown + default: 3 + validations: + required: true +`, + wantErr: "body[0](dropdown): the value of 'default' is out of range", + }, + { + name: "dropdown without default is valid", + content: ` +name: "test" +about: "this is about" +body: + - type: dropdown + id: "1" + attributes: + label: Label of dropdown + description: Description of dropdown + multiple: true + options: + - Option 1 of dropdown + - Option 2 of dropdown + - Option 3 of dropdown + validations: + required: true +`, + want: &api.IssueTemplate{ + Name: "test", + About: "this is about", + Fields: []*api.IssueFormField{ + { + Type: "dropdown", + ID: "1", + Attributes: map[string]any{ + "label": "Label of dropdown", + "description": "Description of dropdown", + "multiple": true, + "options": []any{ + "Option 1 of dropdown", + "Option 2 of dropdown", + "Option 3 of dropdown", + }, + }, + Validations: map[string]any{ + "required": true, + }, + Visible: []api.IssueFormFieldVisible{api.IssueFormFieldVisibleForm, api.IssueFormFieldVisibleContent}, + }, + }, + FileName: "test.yaml", + }, + wantErr: "", + }, { name: "valid", content: ` @@ -399,6 +489,7 @@ body: - Option 1 of dropdown - Option 2 of dropdown - Option 3 of dropdown + default: 1 validations: required: true - type: checkboxes @@ -475,6 +566,7 @@ body: "Option 2 of dropdown", "Option 3 of dropdown", }, + "default": 1, }, Validations: map[string]any{ "required": true, diff --git a/templates/repo/issue/fields/dropdown.tmpl b/templates/repo/issue/fields/dropdown.tmpl index f4fa79738c..26505f58a5 100644 --- a/templates/repo/issue/fields/dropdown.tmpl +++ b/templates/repo/issue/fields/dropdown.tmpl @@ -2,7 +2,7 @@ {{template "repo/issue/fields/header" .}} {{/* FIXME: required validation */}} <div class="ui fluid selection dropdown {{if .item.Attributes.multiple}}multiple clearable{{end}}"> - <input type="hidden" name="form-field-{{.item.ID}}" value="0"> + <input type="hidden" name="form-field-{{.item.ID}}" value="{{.item.Attributes.default}}"> {{svg "octicon-triangle-down" 14 "dropdown icon"}} {{if not .item.Validations.required}} {{svg "octicon-x" 14 "remove icon"}} From ec771fdfcdbc74320b1ef0252444aa5cddd50a04 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Fri, 24 May 2024 00:25:44 +0000 Subject: [PATCH 350/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_pt-PT.ini | 2 +- options/locale/locale_zh-CN.ini | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index ea0f96e4f8..15635b4beb 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -1595,7 +1595,7 @@ issues.label_title=Nome do rótulo issues.label_description=Descrição do rótulo issues.label_color=Cor do rótulo issues.label_exclusive=Exclusivo -issues.label_archive=Rótulo de arquivo +issues.label_archive=Arquivar rótulo issues.label_archived_filter=Mostrar rótulos arquivados issues.label_archive_tooltip=Os rótulos arquivados são, por norma, excluídos das sugestões ao pesquisar por rótulo. issues.label_exclusive_desc=Nomeie o rótulo <code>âmbito/item</code> para torná-lo mutuamente exclusivo com outros rótulos do <code>âmbito/</code>. diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 0e224f0061..75facb4dcb 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -3415,6 +3415,7 @@ error.unit_not_allowed=您没有权限访问此仓库单元 title=软件包 desc=管理仓库软件包。 empty=还没有软件包。 +no_metadata=没有元数据。 empty.documentation=关于软件包注册中心的更多信息,请参阅 <a target="_blank" rel="noopener noreferrer" href="%s"> 文档 </a>。 empty.repo=您上传了一个包,但没有显示在这里吗?转到 <a href="%[1]s">包设置</a> 并将其链接到这个仓库中。 registry.documentation=关于 %s 注册中心的更多信息,请参阅 <a target="_blank" rel="noopener noreferrer" href="%s">文档</a>。 From 47e715a70ff1802fae27d8d922b3185a3d83d640 Mon Sep 17 00:00:00 2001 From: metiftikci <metiftikci@hotmail.com> Date: Sat, 25 May 2024 17:02:07 +0300 Subject: [PATCH 351/370] Fix `View File` button link if branch deleted on pull request files pages (#31063) as title --- routers/web/repo/pull.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index bbdc6ca631..92e0a1674e 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -862,7 +862,7 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi } if pull.HeadRepo != nil { - ctx.Data["SourcePath"] = pull.HeadRepo.Link() + "/src/branch/" + util.PathEscapeSegments(pull.HeadBranch) + ctx.Data["SourcePath"] = pull.HeadRepo.Link() + "/src/commit/" + endCommitID if !pull.HasMerged && ctx.Doer != nil { perm, err := access_model.GetUserRepoPermission(ctx, pull.HeadRepo, ctx.Doer) From 2ced31e81dd9e45659660c1abff529d0192fd8ed Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sat, 25 May 2024 16:33:34 +0200 Subject: [PATCH 352/370] Change `--border-radius-circle` to `--border-radius-full` (#30936) Percentage-based `border-radius` [creates undesirable ellipse](https://jsfiddle.net/silverwind/j9ko5wnt/4/) on non-square content. Instead, use pixel value and use same wording `full` like tailwind does, but increast to 99999px over their 9999px. --- tailwind.config.js | 2 +- web_src/css/base.css | 4 ++-- web_src/css/modules/animations.css | 2 +- web_src/css/repo.css | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tailwind.config.js b/tailwind.config.js index d49e9d7a1c..94dfdbced4 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -66,7 +66,7 @@ export default { 'xl': '12px', '2xl': '16px', '3xl': '24px', - 'full': 'var(--border-radius-circle)', // 50% + 'full': 'var(--border-radius-full)', }, fontFamily: { sans: 'var(--fonts-regular)', diff --git a/web_src/css/base.css b/web_src/css/base.css index 2d93690170..0e54d17262 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -18,7 +18,7 @@ /* other variables */ --border-radius: 4px; --border-radius-medium: 6px; - --border-radius-circle: 50%; + --border-radius-full: 99999px; /* TODO: use calc(infinity * 1px) */ --opacity-disabled: 0.55; --height-loading: 16rem; --min-height-textarea: 132px; /* padding + 6 lines + border = calc(1.57142em + 6lh + 2px), but lh is not fully supported */ @@ -1166,7 +1166,7 @@ overflow-menu .ui.label { .color-icon { display: inline-block; - border-radius: var(--border-radius-circle); + border-radius: var(--border-radius-full); height: 14px; width: 14px; } diff --git a/web_src/css/modules/animations.css b/web_src/css/modules/animations.css index 361618c449..a86c9234aa 100644 --- a/web_src/css/modules/animations.css +++ b/web_src/css/modules/animations.css @@ -31,7 +31,7 @@ border-width: 4px; border-style: solid; border-color: var(--color-secondary) var(--color-secondary) var(--color-secondary-dark-8) var(--color-secondary-dark-8); - border-radius: var(--border-radius-circle); + border-radius: var(--border-radius-full); } .is-loading.loading-icon-2px::after { diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 56235f8ebe..ce5d3c7951 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -790,7 +790,7 @@ td .commit-summary { width: 34px; height: 34px; background-color: var(--color-timeline); - border-radius: var(--border-radius-circle); + border-radius: var(--border-radius-full); display: flex; float: left; margin-left: -33px; From 14f6105ce0c5802518b46d0af337b4e5f1af4f87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Rosenhammer?= <andre.rosenhammer@gmail.com> Date: Sun, 26 May 2024 06:08:13 +0200 Subject: [PATCH 353/370] Make gitea webhooks openproject compatible (#28435) This PR adds some fields to the gitea webhook payload that [openproject](https://www.openproject.org/) expects to exists in order to process the webhooks. These fields do exists in Github's webhook payload so adding them makes Gitea's native webhook more compatible towards Github's. --- models/issues/pull.go | 15 ++++++++ modules/structs/issue.go | 1 + modules/structs/pull.go | 6 ++++ modules/structs/user.go | 2 ++ services/convert/issue.go | 2 ++ services/convert/pull.go | 64 ++++++++++++++++++++++------------ services/convert/user.go | 1 + templates/swagger/v1_json.tmpl | 34 ++++++++++++++++++ 8 files changed, 102 insertions(+), 23 deletions(-) diff --git a/models/issues/pull.go b/models/issues/pull.go index 4194df2e3d..014fcd9fd0 100644 --- a/models/issues/pull.go +++ b/models/issues/pull.go @@ -430,6 +430,21 @@ func (pr *PullRequest) GetGitHeadBranchRefName() string { return fmt.Sprintf("%s%s", git.BranchPrefix, pr.HeadBranch) } +// GetReviewCommentsCount returns the number of review comments made on the diff of a PR review (not including comments on commits or issues in a PR) +func (pr *PullRequest) GetReviewCommentsCount(ctx context.Context) int { + opts := FindCommentsOptions{ + Type: CommentTypeReview, + IssueID: pr.IssueID, + } + conds := opts.ToConds() + + count, err := db.GetEngine(ctx).Where(conds).Count(new(Comment)) + if err != nil { + return 0 + } + return int(count) +} + // IsChecking returns true if this pull request is still checking conflict. func (pr *PullRequest) IsChecking() bool { return pr.Status == PullRequestStatusChecking diff --git a/modules/structs/issue.go b/modules/structs/issue.go index 16242d18ad..3c06e38356 100644 --- a/modules/structs/issue.go +++ b/modules/structs/issue.go @@ -30,6 +30,7 @@ type PullRequestMeta struct { HasMerged bool `json:"merged"` Merged *time.Time `json:"merged_at"` IsWorkInProgress bool `json:"draft"` + HTMLURL string `json:"html_url"` } // RepositoryMeta basic repository information diff --git a/modules/structs/pull.go b/modules/structs/pull.go index b04def52b8..525d90c28e 100644 --- a/modules/structs/pull.go +++ b/modules/structs/pull.go @@ -21,8 +21,14 @@ type PullRequest struct { Assignees []*User `json:"assignees"` RequestedReviewers []*User `json:"requested_reviewers"` State StateType `json:"state"` + Draft bool `json:"draft"` IsLocked bool `json:"is_locked"` Comments int `json:"comments"` + // number of review comments made on the diff of a PR review (not including comments on commits or issues in a PR) + ReviewComments int `json:"review_comments"` + Additions int `json:"additions"` + Deletions int `json:"deletions"` + ChangedFiles int `json:"changed_files"` HTMLURL string `json:"html_url"` DiffURL string `json:"diff_url"` diff --git a/modules/structs/user.go b/modules/structs/user.go index ca6ab79944..5ed677f239 100644 --- a/modules/structs/user.go +++ b/modules/structs/user.go @@ -28,6 +28,8 @@ type User struct { Email string `json:"email"` // URL to the user's avatar AvatarURL string `json:"avatar_url"` + // URL to the user's gitea page + HTMLURL string `json:"html_url"` // User locale Language string `json:"language"` // Is the user an administrator diff --git a/services/convert/issue.go b/services/convert/issue.go index 668affe09a..4fe7ef44fe 100644 --- a/services/convert/issue.go +++ b/services/convert/issue.go @@ -104,6 +104,8 @@ func toIssue(ctx context.Context, doer *user_model.User, issue *issues_model.Iss if issue.PullRequest.HasMerged { apiIssue.PullRequest.Merged = issue.PullRequest.MergedUnix.AsTimePtr() } + // Add pr's html url + apiIssue.PullRequest.HTMLURL = issue.HTMLURL() } } if issue.DeadlineUnix != 0 { diff --git a/services/convert/pull.go b/services/convert/pull.go index 775bf3806d..6d95804b38 100644 --- a/services/convert/pull.go +++ b/services/convert/pull.go @@ -51,29 +51,31 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u } apiPullRequest := &api.PullRequest{ - ID: pr.ID, - URL: pr.Issue.HTMLURL(), - Index: pr.Index, - Poster: apiIssue.Poster, - Title: apiIssue.Title, - Body: apiIssue.Body, - Labels: apiIssue.Labels, - Milestone: apiIssue.Milestone, - Assignee: apiIssue.Assignee, - Assignees: apiIssue.Assignees, - State: apiIssue.State, - IsLocked: apiIssue.IsLocked, - Comments: apiIssue.Comments, - HTMLURL: pr.Issue.HTMLURL(), - DiffURL: pr.Issue.DiffURL(), - PatchURL: pr.Issue.PatchURL(), - HasMerged: pr.HasMerged, - MergeBase: pr.MergeBase, - Mergeable: pr.Mergeable(ctx), - Deadline: apiIssue.Deadline, - Created: pr.Issue.CreatedUnix.AsTimePtr(), - Updated: pr.Issue.UpdatedUnix.AsTimePtr(), - PinOrder: apiIssue.PinOrder, + ID: pr.ID, + URL: pr.Issue.HTMLURL(), + Index: pr.Index, + Poster: apiIssue.Poster, + Title: apiIssue.Title, + Body: apiIssue.Body, + Labels: apiIssue.Labels, + Milestone: apiIssue.Milestone, + Assignee: apiIssue.Assignee, + Assignees: apiIssue.Assignees, + State: apiIssue.State, + Draft: pr.IsWorkInProgress(ctx), + IsLocked: apiIssue.IsLocked, + Comments: apiIssue.Comments, + ReviewComments: pr.GetReviewCommentsCount(ctx), + HTMLURL: pr.Issue.HTMLURL(), + DiffURL: pr.Issue.DiffURL(), + PatchURL: pr.Issue.PatchURL(), + HasMerged: pr.HasMerged, + MergeBase: pr.MergeBase, + Mergeable: pr.Mergeable(ctx), + Deadline: apiIssue.Deadline, + Created: pr.Issue.CreatedUnix.AsTimePtr(), + Updated: pr.Issue.UpdatedUnix.AsTimePtr(), + PinOrder: apiIssue.PinOrder, AllowMaintainerEdit: pr.AllowMaintainerEdit, @@ -168,6 +170,12 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u return nil } + // Outer scope variables to be used in diff calculation + var ( + startCommitID string + endCommitID string + ) + if git.IsErrBranchNotExist(err) { headCommitID, err := headGitRepo.GetRefCommitID(apiPullRequest.Head.Ref) if err != nil && !git.IsErrNotExist(err) { @@ -176,6 +184,7 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u } if err == nil { apiPullRequest.Head.Sha = headCommitID + endCommitID = headCommitID } } else { commit, err := headBranch.GetCommit() @@ -186,8 +195,17 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u if err == nil { apiPullRequest.Head.Ref = pr.HeadBranch apiPullRequest.Head.Sha = commit.ID.String() + endCommitID = commit.ID.String() } } + + // Calculate diff + startCommitID = pr.MergeBase + + apiPullRequest.ChangedFiles, apiPullRequest.Additions, apiPullRequest.Deletions, err = gitRepo.GetDiffShortStat(startCommitID, endCommitID) + if err != nil { + log.Error("GetDiffShortStat: %v", err) + } } if len(apiPullRequest.Head.Sha) == 0 && len(apiPullRequest.Head.Ref) != 0 { diff --git a/services/convert/user.go b/services/convert/user.go index 2957c58b14..90bcf35cf6 100644 --- a/services/convert/user.go +++ b/services/convert/user.go @@ -53,6 +53,7 @@ func toUser(ctx context.Context, user *user_model.User, signed, authed bool) *ap FullName: user.FullName, Email: user.GetPlaceholderEmail(), AvatarURL: user.AvatarLink(ctx), + HTMLURL: user.HTMLURL(), Created: user.CreatedUnix.AsTime(), Restricted: user.IsRestricted, Location: user.Location, diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 0b3f5cdcad..34829a15fc 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -22975,6 +22975,11 @@ "description": "PullRequest represents a pull request", "type": "object", "properties": { + "additions": { + "type": "integer", + "format": "int64", + "x-go-name": "Additions" + }, "allow_maintainer_edit": { "type": "boolean", "x-go-name": "AllowMaintainerEdit" @@ -22996,6 +23001,11 @@ "type": "string", "x-go-name": "Body" }, + "changed_files": { + "type": "integer", + "format": "int64", + "x-go-name": "ChangedFiles" + }, "closed_at": { "type": "string", "format": "date-time", @@ -23011,10 +23021,19 @@ "format": "date-time", "x-go-name": "Created" }, + "deletions": { + "type": "integer", + "format": "int64", + "x-go-name": "Deletions" + }, "diff_url": { "type": "string", "x-go-name": "DiffURL" }, + "draft": { + "type": "boolean", + "x-go-name": "Draft" + }, "due_date": { "type": "string", "format": "date-time", @@ -23091,6 +23110,12 @@ }, "x-go-name": "RequestedReviewers" }, + "review_comments": { + "description": "number of review comments made on the diff of a PR review (not including comments on commits or issues in a PR)", + "type": "integer", + "format": "int64", + "x-go-name": "ReviewComments" + }, "state": { "$ref": "#/definitions/StateType" }, @@ -23121,6 +23146,10 @@ "type": "boolean", "x-go-name": "IsWorkInProgress" }, + "html_url": { + "type": "string", + "x-go-name": "HTMLURL" + }, "merged": { "type": "boolean", "x-go-name": "HasMerged" @@ -24414,6 +24443,11 @@ "type": "string", "x-go-name": "FullName" }, + "html_url": { + "description": "URL to the user's gitea page", + "type": "string", + "x-go-name": "HTMLURL" + }, "id": { "description": "the user's id", "type": "integer", From e625813aa9f585718e9c7677fc441f1f3ad69c61 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Mon, 27 May 2024 00:26:27 +0000 Subject: [PATCH 354/370] [skip ci] Updated licenses and gitignores --- ...e-first-lines => BSD-2-Clause-first-lines} | 0 options/license/Gutmann | 2 + options/license/HPND-export2-US | 21 ++++++ options/license/HPND-merchantability-variant | 9 +++ options/license/RRDtool-FLOSS-exception-2.0 | 66 +++++++++++++++++++ 5 files changed, 98 insertions(+) rename options/license/{BSD-2-clause-first-lines => BSD-2-Clause-first-lines} (100%) create mode 100644 options/license/Gutmann create mode 100644 options/license/HPND-export2-US create mode 100644 options/license/HPND-merchantability-variant create mode 100644 options/license/RRDtool-FLOSS-exception-2.0 diff --git a/options/license/BSD-2-clause-first-lines b/options/license/BSD-2-Clause-first-lines similarity index 100% rename from options/license/BSD-2-clause-first-lines rename to options/license/BSD-2-Clause-first-lines diff --git a/options/license/Gutmann b/options/license/Gutmann new file mode 100644 index 0000000000..c33f4ee3a2 --- /dev/null +++ b/options/license/Gutmann @@ -0,0 +1,2 @@ +You can use this code in whatever way you want, as long as you don't try +to claim you wrote it. diff --git a/options/license/HPND-export2-US b/options/license/HPND-export2-US new file mode 100644 index 0000000000..1dda23a88c --- /dev/null +++ b/options/license/HPND-export2-US @@ -0,0 +1,21 @@ +Copyright 2004-2008 Apple Inc. All Rights Reserved. + + Export of this software from the United States of America may + require a specific license from the United States Government. + It is the responsibility of any person or organization + contemplating export to obtain such a license before exporting. + +WITHIN THAT CONSTRAINT, permission to use, copy, modify, and +distribute this software and its documentation for any purpose and +without fee is hereby granted, provided that the above copyright +notice appear in all copies and that both that copyright notice and +this permission notice appear in supporting documentation, and that +the name of Apple Inc. not be used in advertising or publicity +pertaining to distribution of the software without specific, +written prior permission. Apple Inc. makes no representations +about the suitability of this software for any purpose. It is +provided "as is" without express or implied warranty. + +THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. diff --git a/options/license/HPND-merchantability-variant b/options/license/HPND-merchantability-variant new file mode 100644 index 0000000000..421b9ff96b --- /dev/null +++ b/options/license/HPND-merchantability-variant @@ -0,0 +1,9 @@ +Copyright (C) 2004 Christian Groessler <chris@groessler.org> + +Permission to use, copy, modify, and distribute this file +for any purpose is hereby granted without fee, provided that +the above copyright notice and this notice appears in all +copies. + +This file is distributed WITHOUT ANY WARRANTY; without even the implied +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. diff --git a/options/license/RRDtool-FLOSS-exception-2.0 b/options/license/RRDtool-FLOSS-exception-2.0 new file mode 100644 index 0000000000..d88dae5868 --- /dev/null +++ b/options/license/RRDtool-FLOSS-exception-2.0 @@ -0,0 +1,66 @@ +FLOSS License Exception +======================= +(Adapted from http://www.mysql.com/company/legal/licensing/foss-exception.html) + +I want specified Free/Libre and Open Source Software ("FLOSS") +applications to be able to use specified GPL-licensed RRDtool +libraries (the "Program") despite the fact that not all FLOSS licenses are +compatible with version 2 of the GNU General Public License (the "GPL"). + +As a special exception to the terms and conditions of version 2.0 of the GPL: + +You are free to distribute a Derivative Work that is formed entirely from +the Program and one or more works (each, a "FLOSS Work") licensed under one +or more of the licenses listed below, as long as: + +1. You obey the GPL in all respects for the Program and the Derivative +Work, except for identifiable sections of the Derivative Work which are +not derived from the Program, and which can reasonably be considered +independent and separate works in themselves, + +2. all identifiable sections of the Derivative Work which are not derived +from the Program, and which can reasonably be considered independent and +separate works in themselves, + +1. are distributed subject to one of the FLOSS licenses listed +below, and + +2. the object code or executable form of those sections are +accompanied by the complete corresponding machine-readable source +code for those sections on the same medium and under the same FLOSS +license as the corresponding object code or executable forms of +those sections, and + +3. any works which are aggregated with the Program or with a Derivative +Work on a volume of a storage or distribution medium in accordance with +the GPL, can reasonably be considered independent and separate works in +themselves which are not derivatives of either the Program, a Derivative +Work or a FLOSS Work. + +If the above conditions are not met, then the Program may only be copied, +modified, distributed or used under the terms and conditions of the GPL. + +FLOSS License List +================== +License name Version(s)/Copyright Date +Academic Free License 2.0 +Apache Software License 1.0/1.1/2.0 +Apple Public Source License 2.0 +Artistic license From Perl 5.8.0 +BSD license "July 22 1999" +Common Public License 1.0 +GNU Library or "Lesser" General Public License (LGPL) 2.0/2.1 +IBM Public License, Version 1.0 +Jabber Open Source License 1.0 +MIT License (As listed in file MIT-License.txt) - +Mozilla Public License (MPL) 1.0/1.1 +Open Software License 2.0 +OpenSSL license (with original SSLeay license) "2003" ("1998") +PHP License 3.01 +Python license (CNRI Python License) - +Python Software Foundation License 2.1.1 +Sleepycat License "1999" +W3C License "2001" +X11 License "2001" +Zlib/libpng License - +Zope Public License 2.0/2.1 From 145baa2b3f3bef2b4535d6d3b7b2cdb88da4382b Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Mon, 27 May 2024 06:48:41 +0200 Subject: [PATCH 355/370] Fix border radius on hovered secondary menu (#31089) Presumably a regression from https://github.com/go-gitea/gitea/pull/30325, these menus were showing a border radius on hover, which is fixed with this change. <img width="154" alt="image" src="https://github.com/go-gitea/gitea/assets/115237/eafdc1c5-3cf5-48d1-86c4-21c58f92cfaf"> --- web_src/css/modules/menu.css | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/web_src/css/modules/menu.css b/web_src/css/modules/menu.css index ff9d7fc5d0..43679a3317 100644 --- a/web_src/css/modules/menu.css +++ b/web_src/css/modules/menu.css @@ -512,11 +512,14 @@ background: var(--color-hover); } +.ui.secondary.menu .active.item { + border-radius: 0.28571429rem; +} + .ui.secondary.menu .active.item, .ui.secondary.menu .active.item:hover { color: var(--color-text-dark); background: var(--color-active); - border-radius: 0.28571429rem; } .ui.secondary.item.menu { From e695ba47557ed4c3999c63b28051a449ca4653de Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Mon, 27 May 2024 13:21:00 +0800 Subject: [PATCH 356/370] Fix possible ui 500 if workflow's job is nil (#31092) Fix #31087 --- options/locale/locale_en-US.ini | 1 + routers/web/repo/actions/actions.go | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index db4e3ec56b..40cbdb23fe 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -3638,6 +3638,7 @@ runs.pushed_by = pushed by runs.invalid_workflow_helper = Workflow config file is invalid. Please check your config file: %s runs.no_matching_online_runner_helper = No matching online runner with label: %s runs.no_job_without_needs = The workflow must contain at least one job without dependencies. +runs.no_job = The workflow must contain at least one job runs.actor = Actor runs.status = Status runs.actors_no_select = All actors diff --git a/routers/web/repo/actions/actions.go b/routers/web/repo/actions/actions.go index 6059ad1414..a0f03ec7e9 100644 --- a/routers/web/repo/actions/actions.go +++ b/routers/web/repo/actions/actions.go @@ -107,7 +107,12 @@ func List(ctx *context.Context) { // The workflow must contain at least one job without "needs". Otherwise, a deadlock will occur and no jobs will be able to run. hasJobWithoutNeeds := false // Check whether have matching runner and a job without "needs" + emptyJobsNumber := 0 for _, j := range wf.Jobs { + if j == nil { + emptyJobsNumber++ + continue + } if !hasJobWithoutNeeds && len(j.Needs()) == 0 { hasJobWithoutNeeds = true } @@ -131,6 +136,9 @@ func List(ctx *context.Context) { if !hasJobWithoutNeeds { workflow.ErrMsg = ctx.Locale.TrString("actions.runs.no_job_without_needs") } + if emptyJobsNumber == len(wf.Jobs) { + workflow.ErrMsg = ctx.Locale.TrString("actions.runs.no_job") + } workflows = append(workflows, workflow) } } From 31a0c4dfb4156a7b4d856cceae1e61c7fc1a4a1b Mon Sep 17 00:00:00 2001 From: Zettat123 <zettat123@gmail.com> Date: Mon, 27 May 2024 14:15:34 +0800 Subject: [PATCH 357/370] Improve the handling of `jobs.<job_id>.if` (#31070) Fix #25897 Fix #30322 #29464 cannot handle some complex `if` conditions correctly because it only checks `always()` literally. In fact, it's not easy to evaluate the `if` condition on the Gitea side because evaluating it requires a series of contexts. But act_runner is able to evaluate the `if` condition before running the job (for more information, see [`gitea/act`](https://gitea.com/gitea/act/src/commit/517d11c67126bd97c88e2faabda0832fff482258/pkg/runner/run_context.go#L739-L753)) . So we can use act_runner to check the `if` condition. In this PR, how to handle a blocked job depends on its `needs` and `if`: - If not all jobs in `needs` completed successfully and the job's `if` is empty, set the job status to `StatusSkipped` - In other cases, the job status will be set to `StatusWaiting`, and then act_runner will check the `if` condition and run the job if the condition is met --- services/actions/job_emitter.go | 14 +++++++------- services/actions/job_emitter_test.go | 18 +++++++++--------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/services/actions/job_emitter.go b/services/actions/job_emitter.go index d2bbbd9a7c..1f859fcf70 100644 --- a/services/actions/job_emitter.go +++ b/services/actions/job_emitter.go @@ -7,7 +7,6 @@ import ( "context" "errors" "fmt" - "strings" actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" @@ -141,18 +140,19 @@ func (r *jobStatusResolver) resolve() map[int64]actions_model.Status { if allSucceed { ret[id] = actions_model.StatusWaiting } else { - // If a job's "if" condition is "always()", the job should always run even if some of its dependencies did not succeed. - // See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idneeds - always := false + // Check if the job has an "if" condition + hasIf := false if wfJobs, _ := jobparser.Parse(r.jobMap[id].WorkflowPayload); len(wfJobs) == 1 { _, wfJob := wfJobs[0].Job() - expr := strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(wfJob.If.Value, "${{"), "}}")) - always = expr == "always()" + hasIf = len(wfJob.If.Value) > 0 } - if always { + if hasIf { + // act_runner will check the "if" condition ret[id] = actions_model.StatusWaiting } else { + // If the "if" condition is empty and not all dependent jobs completed successfully, + // the job should be skipped. ret[id] = actions_model.StatusSkipped } } diff --git a/services/actions/job_emitter_test.go b/services/actions/job_emitter_test.go index 038df7d4f8..58c2dc3b24 100644 --- a/services/actions/job_emitter_test.go +++ b/services/actions/job_emitter_test.go @@ -71,9 +71,9 @@ func Test_jobStatusResolver_Resolve(t *testing.T) { want: map[int64]actions_model.Status{}, }, { - name: "with ${{ always() }} condition", + name: "`if` is not empty and all jobs in `needs` completed successfully", jobs: actions_model.ActionJobList{ - {ID: 1, JobID: "job1", Status: actions_model.StatusFailure, Needs: []string{}}, + {ID: 1, JobID: "job1", Status: actions_model.StatusSuccess, Needs: []string{}}, {ID: 2, JobID: "job2", Status: actions_model.StatusBlocked, Needs: []string{"job1"}, WorkflowPayload: []byte( ` name: test @@ -82,15 +82,15 @@ jobs: job2: runs-on: ubuntu-latest needs: job1 - if: ${{ always() }} + if: ${{ always() && needs.job1.result == 'success' }} steps: - - run: echo "always run" + - run: echo "will be checked by act_runner" `)}, }, want: map[int64]actions_model.Status{2: actions_model.StatusWaiting}, }, { - name: "with always() condition", + name: "`if` is not empty and not all jobs in `needs` completed successfully", jobs: actions_model.ActionJobList{ {ID: 1, JobID: "job1", Status: actions_model.StatusFailure, Needs: []string{}}, {ID: 2, JobID: "job2", Status: actions_model.StatusBlocked, Needs: []string{"job1"}, WorkflowPayload: []byte( @@ -101,15 +101,15 @@ jobs: job2: runs-on: ubuntu-latest needs: job1 - if: always() + if: ${{ always() && needs.job1.result == 'failure' }} steps: - - run: echo "always run" + - run: echo "will be checked by act_runner" `)}, }, want: map[int64]actions_model.Status{2: actions_model.StatusWaiting}, }, { - name: "without always() condition", + name: "`if` is empty and not all jobs in `needs` completed successfully", jobs: actions_model.ActionJobList{ {ID: 1, JobID: "job1", Status: actions_model.StatusFailure, Needs: []string{}}, {ID: 2, JobID: "job2", Status: actions_model.StatusBlocked, Needs: []string{"job1"}, WorkflowPayload: []byte( @@ -121,7 +121,7 @@ jobs: runs-on: ubuntu-latest needs: job1 steps: - - run: echo "not always run" + - run: echo "should be skipped" `)}, }, want: map[int64]actions_model.Status{2: actions_model.StatusSkipped}, From 6e140b58ddd318f8e916b1f83551c6b2c8291510 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Mon, 27 May 2024 08:45:16 +0200 Subject: [PATCH 358/370] Prevent tab shifting, remove extra margin on fluid pages (#31090) 1. Extend concept of https://github.com/go-gitea/gitea/pull/29831 to all tabular menus, there were only three left that weren't already `<overflow-menu>`. <img width="634" alt="Screenshot 2024-05-27 at 00 42 16" src="https://github.com/go-gitea/gitea/assets/115237/d9a7e219-d05e-40a1-9e93-777f9a8a90dd"> <img width="965" alt="Screenshot 2024-05-27 at 00 29 32" src="https://github.com/go-gitea/gitea/assets/115237/e6ed71b1-11fb-4a74-9adb-af4524286cff"> 2. Remove extra padding on `fluid padded` container like for example PR diff view. The page margin is already correctly sized via `.ui.container`, so this was just extraneous padding that looked ugly. Before: <img width="1351" alt="Screenshot 2024-05-27 at 00 45 11" src="https://github.com/go-gitea/gitea/assets/115237/4b45fd11-b1b2-4fbb-a618-26eb22be9472"> After: <img width="1344" alt="Screenshot 2024-05-27 at 00 45 22" src="https://github.com/go-gitea/gitea/assets/115237/d09593eb-6c7f-45e7-85b6-f0050047004b"> 3. Replace `gt-word-break` with `tw-break-anywhere` in issue-title, fixing overflow. Before: <img width="1333" alt="Screenshot 2024-05-27 at 00 50 14" src="https://github.com/go-gitea/gitea/assets/115237/64d15d04-b456-401e-a972-df636965f0eb"> After: <img width="1316" alt="Screenshot 2024-05-27 at 00 50 26" src="https://github.com/go-gitea/gitea/assets/115237/ed1ce830-1408-414b-8263-eeaf773f52c8"> --- templates/repo/issue/view_title.tmpl | 2 +- templates/repo/pulls/tab_menu.tmpl | 6 +++--- templates/repo/settings/webhook/history.tmpl | 10 ++++++---- templates/shared/combomarkdowneditor.tmpl | 4 ++-- templates/shared/misc/tabtitle.tmpl | 1 + web_src/css/modules/container.css | 4 ---- 6 files changed, 13 insertions(+), 14 deletions(-) create mode 100644 templates/shared/misc/tabtitle.tmpl diff --git a/templates/repo/issue/view_title.tmpl b/templates/repo/issue/view_title.tmpl index 097d7b1f7c..58d3759a9d 100644 --- a/templates/repo/issue/view_title.tmpl +++ b/templates/repo/issue/view_title.tmpl @@ -6,7 +6,7 @@ <div class="issue-title-header"> {{$canEditIssueTitle := and (or .HasIssuesOrPullsWritePermission .IsIssuePoster) (not .Repository.IsArchived)}} <div class="issue-title" id="issue-title-display"> - <h1 class="gt-word-break"> + <h1 class="tw-break-anywhere"> {{RenderIssueTitle $.Context .Issue.Title ($.Repository.ComposeMetas ctx) | RenderCodeBlock}} <span class="index">#{{.Issue.Index}}</span> </h1> diff --git a/templates/repo/pulls/tab_menu.tmpl b/templates/repo/pulls/tab_menu.tmpl index d5a8d6ed21..8b192c44db 100644 --- a/templates/repo/pulls/tab_menu.tmpl +++ b/templates/repo/pulls/tab_menu.tmpl @@ -2,17 +2,17 @@ <div class="ui top attached pull tabular menu"> <a class="item {{if .PageIsPullConversation}}active{{end}}" href="{{.Issue.Link}}"> {{svg "octicon-comment-discussion"}} - {{ctx.Locale.Tr "repo.pulls.tab_conversation"}} + {{template "shared/misc/tabtitle" (ctx.Locale.Tr "repo.pulls.tab_conversation")}} <span class="ui small label">{{.Issue.NumComments}}</span> </a> <a class="item {{if .PageIsPullCommits}}active{{end}}" {{if .NumCommits}}href="{{.Issue.Link}}/commits"{{end}}> {{svg "octicon-git-commit"}} - {{ctx.Locale.Tr "repo.pulls.tab_commits"}} + {{template "shared/misc/tabtitle" (ctx.Locale.Tr "repo.pulls.tab_commits")}} <span class="ui small label">{{if .NumCommits}}{{.NumCommits}}{{else}}-{{end}}</span> </a> <a class="item {{if .PageIsPullFiles}}active{{end}}" href="{{.Issue.Link}}/files"> {{svg "octicon-diff"}} - {{ctx.Locale.Tr "repo.pulls.tab_files"}} + {{template "shared/misc/tabtitle" (ctx.Locale.Tr "repo.pulls.tab_files")}} <span class="ui small label">{{if .NumFiles}}{{.NumFiles}}{{else}}-{{end}}</span> </a> {{if or .Diff.TotalAddition .Diff.TotalDeletion}} diff --git a/templates/repo/settings/webhook/history.tmpl b/templates/repo/settings/webhook/history.tmpl index 149840b0de..0e03b8ed1b 100644 --- a/templates/repo/settings/webhook/history.tmpl +++ b/templates/repo/settings/webhook/history.tmpl @@ -34,9 +34,11 @@ </div> <div class="info tw-hidden" id="info-{{.ID}}"> <div class="ui top attached tabular menu"> - <a class="item active" data-tab="request-{{.ID}}">{{ctx.Locale.Tr "repo.settings.webhook.request"}}</a> + <a class="item active" data-tab="request-{{.ID}}"> + {{template "shared/misc/tabtitle" (ctx.Locale.Tr "repo.settings.webhook.request")}} + </a> <a class="item" data-tab="response-{{.ID}}"> - {{ctx.Locale.Tr "repo.settings.webhook.response"}} + {{template "shared/misc/tabtitle" (ctx.Locale.Tr "repo.settings.webhook.response")}} {{if .ResponseInfo}} {{if .IsSucceed}} <span class="ui green label">{{.ResponseInfo.Status}}</span> @@ -49,10 +51,10 @@ </a> {{if or $.Permission.IsAdmin $.IsOrganizationOwner $.PageIsAdmin $.PageIsUserSettings}} <div class="right menu"> - <form class="item" action="{{$.Link}}/replay/{{.UUID}}" method="post"> + <form class="tw-py-2" action="{{$.Link}}/replay/{{.UUID}}" method="post"> {{$.CsrfTokenHtml}} <span data-tooltip-content="{{if $.Webhook.IsActive}}{{ctx.Locale.Tr "repo.settings.webhook.replay.description"}}{{else}}{{ctx.Locale.Tr "repo.settings.webhook.replay.description_disabled"}}{{end}}"> - <button class="ui tiny button{{if not $.Webhook.IsActive}} disabled{{end}}">{{svg "octicon-sync"}}</button> + <button class="ui tiny button tw-mr-0{{if not $.Webhook.IsActive}} disabled{{end}}">{{svg "octicon-sync"}}</button> </span> </form> </div> diff --git a/templates/shared/combomarkdowneditor.tmpl b/templates/shared/combomarkdowneditor.tmpl index 5bb71e7cd4..a0145ab297 100644 --- a/templates/shared/combomarkdowneditor.tmpl +++ b/templates/shared/combomarkdowneditor.tmpl @@ -14,8 +14,8 @@ Template Attributes: <div {{if .ContainerId}}id="{{.ContainerId}}"{{end}} class="combo-markdown-editor {{.ContainerClasses}}" data-dropzone-parent-container="{{.DropzoneParentContainer}}"> {{if .MarkdownPreviewUrl}} <div class="ui top tabular menu"> - <a class="active item" data-tab-for="markdown-writer">{{ctx.Locale.Tr "write"}}</a> - <a class="item" data-tab-for="markdown-previewer" data-preview-url="{{.MarkdownPreviewUrl}}" data-preview-context="{{.MarkdownPreviewContext}}">{{ctx.Locale.Tr "preview"}}</a> + <a class="active item" data-tab-for="markdown-writer">{{template "shared/misc/tabtitle" (ctx.Locale.Tr "write")}}</a> + <a class="item" data-tab-for="markdown-previewer" data-preview-url="{{.MarkdownPreviewUrl}}" data-preview-context="{{.MarkdownPreviewContext}}">{{template "shared/misc/tabtitle" (ctx.Locale.Tr "preview")}}</a> </div> {{end}} <div class="ui tab active" data-tab-panel="markdown-writer"> diff --git a/templates/shared/misc/tabtitle.tmpl b/templates/shared/misc/tabtitle.tmpl new file mode 100644 index 0000000000..dea9d4d757 --- /dev/null +++ b/templates/shared/misc/tabtitle.tmpl @@ -0,0 +1 @@ +<span class="resize-for-semibold" data-text="{{.}}">{{.}}</span> diff --git a/web_src/css/modules/container.css b/web_src/css/modules/container.css index c9df6ab3f5..4a442c35b1 100644 --- a/web_src/css/modules/container.css +++ b/web_src/css/modules/container.css @@ -12,10 +12,6 @@ width: 100%; } -.ui.container.fluid.padded { - padding: 0 var(--page-margin-x); -} - .ui[class*="center aligned"].container { text-align: center; } From 072b029b336a3d12c40060e8472373fded676dc2 Mon Sep 17 00:00:00 2001 From: delvh <dev.lh@web.de> Date: Mon, 27 May 2024 10:24:34 +0200 Subject: [PATCH 359/370] Simplify review UI (#31062) Instead of always displaying all available actions as buttons, merge them into a single dropdown menu, same as GitHub. That decreases visual overload and is more mobile-friendly, while not losing any functionality. ## Screenshots <details><summary>Before</summary>  </details> <details><summary>After (unexpanded)</summary>  </details> <details><summary>After (expanded)</summary>  </details> --- templates/repo/diff/box.tmpl | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl index 641de294fd..daacdf4ba0 100644 --- a/templates/repo/diff/box.tmpl +++ b/templates/repo/diff/box.tmpl @@ -159,25 +159,30 @@ {{if and $isReviewFile $file.HasChangedSinceLastReview}} <span class="changed-since-last-review unselectable not-mobile">{{ctx.Locale.Tr "repo.pulls.has_changed_since_last_review"}}</span> {{end}} - {{if not (or $file.IsIncomplete $file.IsBin $file.IsSubmodule)}} - <button class="ui basic tiny button unescape-button not-mobile">{{ctx.Locale.Tr "repo.unescape_control_characters"}}</button> - <button class="ui basic tiny button escape-button tw-hidden">{{ctx.Locale.Tr "repo.escape_control_characters"}}</button> - {{end}} - {{if and (not $file.IsSubmodule) (not $.PageIsWiki)}} - {{if $file.IsDeleted}} - <a class="ui basic tiny button" rel="nofollow" href="{{$.BeforeSourcePath}}/{{PathEscapeSegments .Name}}">{{ctx.Locale.Tr "repo.diff.view_file"}}</a> - {{else}} - <a class="ui basic tiny button" rel="nofollow" href="{{$.SourcePath}}/{{PathEscapeSegments .Name}}">{{ctx.Locale.Tr "repo.diff.view_file"}}</a> - {{if and $.Repository.CanEnableEditor $.CanEditFile (not $file.IsLFSFile) (not $file.IsBin)}} - <a class="ui basic tiny button" rel="nofollow" href="{{$.HeadRepoLink}}/_edit/{{PathEscapeSegments $.HeadBranchName}}/{{PathEscapeSegments $file.Name}}?return_uri={{print $.BackToLink "#diff-" $file.NameHash | QueryEscape}}">{{ctx.Locale.Tr "repo.editor.edit_this_file"}}</a> - {{end}} - {{end}} - {{end}} {{if $isReviewFile}} <label data-link="{{$.Issue.Link}}/viewed-files" data-headcommit="{{$.AfterCommitID}}" class="viewed-file-form unselectable{{if $file.IsViewed}} viewed-file-checked-form{{end}}"> <input type="checkbox" name="{{$file.GetDiffFileName}}" autocomplete="off"{{if $file.IsViewed}} checked{{end}}> {{ctx.Locale.Tr "repo.pulls.has_viewed_file"}} </label> {{end}} + <div class="ui dropdown basic"> + {{svg "octicon-kebab-horizontal" 18 "icon tw-mx-2"}} + <div class="ui menu"> + {{if not (or $file.IsIncomplete $file.IsBin $file.IsSubmodule)}} + <button class="unescape-button item">{{ctx.Locale.Tr "repo.unescape_control_characters"}}</button> + <button class="escape-button tw-hidden item">{{ctx.Locale.Tr "repo.escape_control_characters"}}</button> + {{end}} + {{if and (not $file.IsSubmodule) (not $.PageIsWiki)}} + {{if $file.IsDeleted}} + <a class="item" rel="nofollow" href="{{$.BeforeSourcePath}}/{{PathEscapeSegments .Name}}">{{ctx.Locale.Tr "repo.diff.view_file"}}</a> + {{else}} + <a class="item" rel="nofollow" href="{{$.SourcePath}}/{{PathEscapeSegments .Name}}">{{ctx.Locale.Tr "repo.diff.view_file"}}</a> + {{if and $.Repository.CanEnableEditor $.CanEditFile (not $file.IsLFSFile) (not $file.IsBin)}} + <a class="item" rel="nofollow" href="{{$.HeadRepoLink}}/_edit/{{PathEscapeSegments $.HeadBranchName}}/{{PathEscapeSegments $file.Name}}?return_uri={{print $.BackToLink "#diff-" $file.NameHash | QueryEscape}}">{{ctx.Locale.Tr "repo.editor.edit_this_file"}}</a> + {{end}} + {{end}} + {{end}} + </div> + </div> </div> </h4> <div class="diff-file-body ui attached unstackable table segment" {{if and $file.IsViewed $.IsShowingAllCommits}}data-folded="true"{{end}}> From 98751108b11dc748cc99230ca0fc1acfdf2c8929 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Mon, 27 May 2024 16:59:54 +0800 Subject: [PATCH 360/370] Rename project board -> column to make the UI less confusing (#30170) This PR split the `Board` into two parts. One is the struct has been renamed to `Column` and the second we have a `Template Type`. But to make it easier to review, this PR will not change the database schemas, they are just renames. The database schema changes could be in future PRs. --------- Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: yp05327 <576951401@qq.com> --- .../config-cheat-sheet.en-us.md | 2 +- docs/content/index.en-us.md | 2 +- docs/content/installation/comparison.en-us.md | 2 +- docs/content/usage/permissions.en-us.md | 2 +- models/activities/statistic.go | 4 +- models/issues/comment.go | 6 +- models/issues/issue_project.go | 38 +- models/issues/issue_search.go | 14 +- models/migrations/v1_22/v293_test.go | 24 +- models/project/board.go | 389 ------------------ models/project/column.go | 359 ++++++++++++++++ .../project/{board_test.go => column_test.go} | 48 +-- models/project/issue.go | 24 +- models/project/project.go | 97 ++--- models/project/project_test.go | 14 +- models/project/template.go | 45 ++ models/unit/unit.go | 2 +- modules/indexer/issues/bleve/bleve.go | 4 +- modules/indexer/issues/db/options.go | 2 +- modules/indexer/issues/dboptions.go | 2 +- .../issues/elasticsearch/elasticsearch.go | 4 +- modules/indexer/issues/indexer_test.go | 4 +- modules/indexer/issues/internal/model.go | 6 +- .../indexer/issues/internal/tests/tests.go | 18 +- .../indexer/issues/meilisearch/meilisearch.go | 4 +- modules/indexer/issues/util.go | 2 +- modules/metrics/collector.go | 14 +- options/locale/locale_en-US.ini | 4 +- routers/web/org/projects.go | 114 +++-- routers/web/org/projects_test.go | 8 +- routers/web/repo/issue.go | 12 +- routers/web/repo/projects.go | 118 +++--- routers/web/repo/projects_test.go | 8 +- routers/web/web.go | 20 +- services/forms/repo_form.go | 50 +-- services/forms/user_form_hidden_comments.go | 2 +- templates/projects/new.tmpl | 6 +- templates/repo/header.tmpl | 2 +- templates/repo/issue/filter_actions.tmpl | 2 +- templates/repo/settings/options.tmpl | 2 +- tests/integration/project_test.go | 14 +- web_src/css/features/projects.css | 2 +- web_src/css/themes/theme-gitea-dark.css | 2 +- web_src/css/themes/theme-gitea-light.css | 2 +- 44 files changed, 725 insertions(+), 775 deletions(-) delete mode 100644 models/project/board.go create mode 100644 models/project/column.go rename models/project/{board_test.go => column_test.go} (69%) create mode 100644 models/project/template.go diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index 9ac1f5eb10..1165a83e25 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -828,7 +828,7 @@ and ## Project (`project`) -Default templates for project boards: +Default templates for project board view: - `PROJECT_BOARD_BASIC_KANBAN_TYPE`: **To Do, In Progress, Done** - `PROJECT_BOARD_BUG_TRIAGE_TYPE`: **Needs Triage, High Priority, Low Priority, Closed** diff --git a/docs/content/index.en-us.md b/docs/content/index.en-us.md index 170bf26f71..f9e6df8c1e 100644 --- a/docs/content/index.en-us.md +++ b/docs/content/index.en-us.md @@ -37,7 +37,7 @@ You can try it out using [the online demo](https://try.gitea.io/). - CI/CD: Gitea Actions supports CI/CD functionality, compatible with GitHub Actions. Users can write workflows in familiar YAML format and reuse a variety of existing Actions plugins. Actions plugins support downloading from any Git website. -- Project Management: Gitea tracks project requirements, features, and bugs through boards and issues. Issues support features like branches, tags, milestones, assignments, time tracking, due dates, dependencies, and more. +- Project Management: Gitea tracks project requirements, features, and bugs through columns and issues. Issues support features like branches, tags, milestones, assignments, time tracking, due dates, dependencies, and more. - Artifact Repository: Gitea supports over 20 different types of public or private software package management, including Cargo, Chef, Composer, Conan, Conda, Container, Helm, Maven, npm, NuGet, Pub, PyPI, RubyGems, Vagrant, and more. diff --git a/docs/content/installation/comparison.en-us.md b/docs/content/installation/comparison.en-us.md index 3fb6561f31..fdb8c3bcde 100644 --- a/docs/content/installation/comparison.en-us.md +++ b/docs/content/installation/comparison.en-us.md @@ -104,7 +104,7 @@ _Symbols used in table:_ | Comment reactions | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ | | Lock Discussion | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ | | Batch issue handling | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ | -| Issue Boards (Kanban) | [/](https://github.com/go-gitea/gitea/issues/14710) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | ✘ | +| Projects | [/](https://github.com/go-gitea/gitea/issues/14710) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | ✘ | | Create branch from issue | [✘](https://github.com/go-gitea/gitea/issues/20226) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | ✘ | | Convert comment to new issue | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ | | Issue search | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ | diff --git a/docs/content/usage/permissions.en-us.md b/docs/content/usage/permissions.en-us.md index 1e0c6c0bb1..e4bef138ab 100644 --- a/docs/content/usage/permissions.en-us.md +++ b/docs/content/usage/permissions.en-us.md @@ -48,7 +48,7 @@ With different permissions, people could do different things with these units. | Wiki | View wiki pages. Clone the wiki repository. | Create/Edit wiki pages, push | - | | ExternalWiki | Link to an external wiki | - | - | | ExternalTracker | Link to an external issue tracker | - | - | -| Projects | View the boards | Change issues across boards | - | +| Projects | View the columns of projects | Change issues across columns | - | | Packages | View the packages | Upload/Delete packages | - | | Actions | View the Actions logs | Approve / Cancel / Restart | - | | Settings | - | - | Manage the repository | diff --git a/models/activities/statistic.go b/models/activities/statistic.go index d1a459d1b2..ff81ad78a1 100644 --- a/models/activities/statistic.go +++ b/models/activities/statistic.go @@ -30,7 +30,7 @@ type Statistic struct { Mirror, Release, AuthSource, Webhook, Milestone, Label, HookTask, Team, UpdateTask, Project, - ProjectBoard, Attachment, + ProjectColumn, Attachment, Branches, Tags, CommitStatus int64 IssueByLabel []IssueByLabelCount IssueByRepository []IssueByRepositoryCount @@ -115,6 +115,6 @@ func GetStatistic(ctx context.Context) (stats Statistic) { stats.Counter.Team, _ = e.Count(new(organization.Team)) stats.Counter.Attachment, _ = e.Count(new(repo_model.Attachment)) stats.Counter.Project, _ = e.Count(new(project_model.Project)) - stats.Counter.ProjectBoard, _ = e.Count(new(project_model.Board)) + stats.Counter.ProjectColumn, _ = e.Count(new(project_model.Column)) return stats } diff --git a/models/issues/comment.go b/models/issues/comment.go index 353163ebd6..336bdde58e 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -100,8 +100,8 @@ const ( CommentTypeMergePull // 28 merge pull request CommentTypePullRequestPush // 29 push to PR head branch - CommentTypeProject // 30 Project changed - CommentTypeProjectBoard // 31 Project board changed + CommentTypeProject // 30 Project changed + CommentTypeProjectColumn // 31 Project column changed CommentTypeDismissReview // 32 Dismiss Review @@ -146,7 +146,7 @@ var commentStrings = []string{ "merge_pull", "pull_push", "project", - "project_board", + "project_board", // FIXME: the name should be project_column "dismiss_review", "change_issue_ref", "pull_scheduled_merge", diff --git a/models/issues/issue_project.go b/models/issues/issue_project.go index e31d2ef151..835ea1db52 100644 --- a/models/issues/issue_project.go +++ b/models/issues/issue_project.go @@ -37,22 +37,22 @@ func (issue *Issue) projectID(ctx context.Context) int64 { return ip.ProjectID } -// ProjectBoardID return project board id if issue was assigned to one -func (issue *Issue) ProjectBoardID(ctx context.Context) int64 { +// ProjectColumnID return project column id if issue was assigned to one +func (issue *Issue) ProjectColumnID(ctx context.Context) int64 { var ip project_model.ProjectIssue has, err := db.GetEngine(ctx).Where("issue_id=?", issue.ID).Get(&ip) if err != nil || !has { return 0 } - return ip.ProjectBoardID + return ip.ProjectColumnID } -// LoadIssuesFromBoard load issues assigned to this board -func LoadIssuesFromBoard(ctx context.Context, b *project_model.Board) (IssueList, error) { +// LoadIssuesFromColumn load issues assigned to this column +func LoadIssuesFromColumn(ctx context.Context, b *project_model.Column) (IssueList, error) { issueList, err := Issues(ctx, &IssuesOptions{ - ProjectBoardID: b.ID, - ProjectID: b.ProjectID, - SortType: "project-column-sorting", + ProjectColumnID: b.ID, + ProjectID: b.ProjectID, + SortType: "project-column-sorting", }) if err != nil { return nil, err @@ -60,9 +60,9 @@ func LoadIssuesFromBoard(ctx context.Context, b *project_model.Board) (IssueList if b.Default { issues, err := Issues(ctx, &IssuesOptions{ - ProjectBoardID: db.NoConditionID, - ProjectID: b.ProjectID, - SortType: "project-column-sorting", + ProjectColumnID: db.NoConditionID, + ProjectID: b.ProjectID, + SortType: "project-column-sorting", }) if err != nil { return nil, err @@ -77,11 +77,11 @@ func LoadIssuesFromBoard(ctx context.Context, b *project_model.Board) (IssueList return issueList, nil } -// LoadIssuesFromBoardList load issues assigned to the boards -func LoadIssuesFromBoardList(ctx context.Context, bs project_model.BoardList) (map[int64]IssueList, error) { +// LoadIssuesFromColumnList load issues assigned to the columns +func LoadIssuesFromColumnList(ctx context.Context, bs project_model.ColumnList) (map[int64]IssueList, error) { issuesMap := make(map[int64]IssueList, len(bs)) for i := range bs { - il, err := LoadIssuesFromBoard(ctx, bs[i]) + il, err := LoadIssuesFromColumn(ctx, bs[i]) if err != nil { return nil, err } @@ -110,7 +110,7 @@ func IssueAssignOrRemoveProject(ctx context.Context, issue *Issue, doer *user_mo return util.NewPermissionDeniedErrorf("issue %d can't be accessed by project %d", issue.ID, newProject.ID) } if newColumnID == 0 { - newDefaultColumn, err := newProject.GetDefaultBoard(ctx) + newDefaultColumn, err := newProject.GetDefaultColumn(ctx) if err != nil { return err } @@ -153,10 +153,10 @@ func IssueAssignOrRemoveProject(ctx context.Context, issue *Issue, doer *user_mo } newSorting := util.Iif(res.IssueCount > 0, res.MaxSorting+1, 0) return db.Insert(ctx, &project_model.ProjectIssue{ - IssueID: issue.ID, - ProjectID: newProjectID, - ProjectBoardID: newColumnID, - Sorting: newSorting, + IssueID: issue.ID, + ProjectID: newProjectID, + ProjectColumnID: newColumnID, + Sorting: newSorting, }) }) } diff --git a/models/issues/issue_search.go b/models/issues/issue_search.go index 921dd9973e..491def1229 100644 --- a/models/issues/issue_search.go +++ b/models/issues/issue_search.go @@ -33,7 +33,7 @@ type IssuesOptions struct { //nolint SubscriberID int64 MilestoneIDs []int64 ProjectID int64 - ProjectBoardID int64 + ProjectColumnID int64 IsClosed optional.Option[bool] IsPull optional.Option[bool] LabelIDs []int64 @@ -169,12 +169,12 @@ func applyProjectCondition(sess *xorm.Session, opts *IssuesOptions) *xorm.Sessio return sess } -func applyProjectBoardCondition(sess *xorm.Session, opts *IssuesOptions) *xorm.Session { - // opts.ProjectBoardID == 0 means all project boards, +func applyProjectColumnCondition(sess *xorm.Session, opts *IssuesOptions) *xorm.Session { + // opts.ProjectColumnID == 0 means all project columns, // do not need to apply any condition - if opts.ProjectBoardID > 0 { - sess.In("issue.id", builder.Select("issue_id").From("project_issue").Where(builder.Eq{"project_board_id": opts.ProjectBoardID})) - } else if opts.ProjectBoardID == db.NoConditionID { + if opts.ProjectColumnID > 0 { + sess.In("issue.id", builder.Select("issue_id").From("project_issue").Where(builder.Eq{"project_board_id": opts.ProjectColumnID})) + } else if opts.ProjectColumnID == db.NoConditionID { sess.In("issue.id", builder.Select("issue_id").From("project_issue").Where(builder.Eq{"project_board_id": 0})) } return sess @@ -246,7 +246,7 @@ func applyConditions(sess *xorm.Session, opts *IssuesOptions) *xorm.Session { applyProjectCondition(sess, opts) - applyProjectBoardCondition(sess, opts) + applyProjectColumnCondition(sess, opts) if opts.IsPull.Has() { sess.And("issue.is_pull=?", opts.IsPull.Value()) diff --git a/models/migrations/v1_22/v293_test.go b/models/migrations/v1_22/v293_test.go index ccc92f39a6..cfe4345143 100644 --- a/models/migrations/v1_22/v293_test.go +++ b/models/migrations/v1_22/v293_test.go @@ -15,7 +15,7 @@ import ( func Test_CheckProjectColumnsConsistency(t *testing.T) { // Prepare and load the testing database - x, deferable := base.PrepareTestEnv(t, 0, new(project.Project), new(project.Board)) + x, deferable := base.PrepareTestEnv(t, 0, new(project.Project), new(project.Column)) defer deferable() if x == nil || t.Failed() { return @@ -23,22 +23,22 @@ func Test_CheckProjectColumnsConsistency(t *testing.T) { assert.NoError(t, CheckProjectColumnsConsistency(x)) - // check if default board was added - var defaultBoard project.Board - has, err := x.Where("project_id=? AND `default` = ?", 1, true).Get(&defaultBoard) + // check if default column was added + var defaultColumn project.Column + has, err := x.Where("project_id=? AND `default` = ?", 1, true).Get(&defaultColumn) assert.NoError(t, err) assert.True(t, has) - assert.Equal(t, int64(1), defaultBoard.ProjectID) - assert.True(t, defaultBoard.Default) + assert.Equal(t, int64(1), defaultColumn.ProjectID) + assert.True(t, defaultColumn.Default) // check if multiple defaults, previous were removed and last will be kept - expectDefaultBoard, err := project.GetBoard(db.DefaultContext, 2) + expectDefaultColumn, err := project.GetColumn(db.DefaultContext, 2) assert.NoError(t, err) - assert.Equal(t, int64(2), expectDefaultBoard.ProjectID) - assert.False(t, expectDefaultBoard.Default) + assert.Equal(t, int64(2), expectDefaultColumn.ProjectID) + assert.False(t, expectDefaultColumn.Default) - expectNonDefaultBoard, err := project.GetBoard(db.DefaultContext, 3) + expectNonDefaultColumn, err := project.GetColumn(db.DefaultContext, 3) assert.NoError(t, err) - assert.Equal(t, int64(2), expectNonDefaultBoard.ProjectID) - assert.True(t, expectNonDefaultBoard.Default) + assert.Equal(t, int64(2), expectNonDefaultColumn.ProjectID) + assert.True(t, expectNonDefaultColumn.Default) } diff --git a/models/project/board.go b/models/project/board.go deleted file mode 100644 index a52baa0c18..0000000000 --- a/models/project/board.go +++ /dev/null @@ -1,389 +0,0 @@ -// Copyright 2020 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package project - -import ( - "context" - "errors" - "fmt" - "regexp" - - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/util" - - "xorm.io/builder" -) - -type ( - // BoardType is used to represent a project board type - BoardType uint8 - - // CardType is used to represent a project board card type - CardType uint8 - - // BoardList is a list of all project boards in a repository - BoardList []*Board -) - -const ( - // BoardTypeNone is a project board type that has no predefined columns - BoardTypeNone BoardType = iota - - // BoardTypeBasicKanban is a project board type that has basic predefined columns - BoardTypeBasicKanban - - // BoardTypeBugTriage is a project board type that has predefined columns suited to hunting down bugs - BoardTypeBugTriage -) - -const ( - // CardTypeTextOnly is a project board card type that is text only - CardTypeTextOnly CardType = iota - - // CardTypeImagesAndText is a project board card type that has images and text - CardTypeImagesAndText -) - -// BoardColorPattern is a regexp witch can validate BoardColor -var BoardColorPattern = regexp.MustCompile("^#[0-9a-fA-F]{6}$") - -// Board is used to represent boards on a project -type Board struct { - ID int64 `xorm:"pk autoincr"` - Title string - Default bool `xorm:"NOT NULL DEFAULT false"` // issues not assigned to a specific board will be assigned to this board - Sorting int8 `xorm:"NOT NULL DEFAULT 0"` - Color string `xorm:"VARCHAR(7)"` - - ProjectID int64 `xorm:"INDEX NOT NULL"` - CreatorID int64 `xorm:"NOT NULL"` - - CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` - UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` -} - -// TableName return the real table name -func (Board) TableName() string { - return "project_board" -} - -// NumIssues return counter of all issues assigned to the board -func (b *Board) NumIssues(ctx context.Context) int { - c, err := db.GetEngine(ctx).Table("project_issue"). - Where("project_id=?", b.ProjectID). - And("project_board_id=?", b.ID). - GroupBy("issue_id"). - Cols("issue_id"). - Count() - if err != nil { - return 0 - } - return int(c) -} - -func (b *Board) GetIssues(ctx context.Context) ([]*ProjectIssue, error) { - issues := make([]*ProjectIssue, 0, 5) - if err := db.GetEngine(ctx).Where("project_id=?", b.ProjectID). - And("project_board_id=?", b.ID). - OrderBy("sorting, id"). - Find(&issues); err != nil { - return nil, err - } - return issues, nil -} - -func init() { - db.RegisterModel(new(Board)) -} - -// IsBoardTypeValid checks if the project board type is valid -func IsBoardTypeValid(p BoardType) bool { - switch p { - case BoardTypeNone, BoardTypeBasicKanban, BoardTypeBugTriage: - return true - default: - return false - } -} - -// IsCardTypeValid checks if the project board card type is valid -func IsCardTypeValid(p CardType) bool { - switch p { - case CardTypeTextOnly, CardTypeImagesAndText: - return true - default: - return false - } -} - -func createBoardsForProjectsType(ctx context.Context, project *Project) error { - var items []string - - switch project.BoardType { - case BoardTypeBugTriage: - items = setting.Project.ProjectBoardBugTriageType - - case BoardTypeBasicKanban: - items = setting.Project.ProjectBoardBasicKanbanType - case BoardTypeNone: - fallthrough - default: - return nil - } - - board := Board{ - CreatedUnix: timeutil.TimeStampNow(), - CreatorID: project.CreatorID, - Title: "Backlog", - ProjectID: project.ID, - Default: true, - } - if err := db.Insert(ctx, board); err != nil { - return err - } - - if len(items) == 0 { - return nil - } - - boards := make([]Board, 0, len(items)) - - for _, v := range items { - boards = append(boards, Board{ - CreatedUnix: timeutil.TimeStampNow(), - CreatorID: project.CreatorID, - Title: v, - ProjectID: project.ID, - }) - } - - return db.Insert(ctx, boards) -} - -// maxProjectColumns max columns allowed in a project, this should not bigger than 127 -// because sorting is int8 in database -const maxProjectColumns = 20 - -// NewBoard adds a new project board to a given project -func NewBoard(ctx context.Context, board *Board) error { - if len(board.Color) != 0 && !BoardColorPattern.MatchString(board.Color) { - return fmt.Errorf("bad color code: %s", board.Color) - } - res := struct { - MaxSorting int64 - ColumnCount int64 - }{} - if _, err := db.GetEngine(ctx).Select("max(sorting) as max_sorting, count(*) as column_count").Table("project_board"). - Where("project_id=?", board.ProjectID).Get(&res); err != nil { - return err - } - if res.ColumnCount >= maxProjectColumns { - return fmt.Errorf("NewBoard: maximum number of columns reached") - } - board.Sorting = int8(util.Iif(res.ColumnCount > 0, res.MaxSorting+1, 0)) - _, err := db.GetEngine(ctx).Insert(board) - return err -} - -// DeleteBoardByID removes all issues references to the project board. -func DeleteBoardByID(ctx context.Context, boardID int64) error { - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return err - } - defer committer.Close() - - if err := deleteBoardByID(ctx, boardID); err != nil { - return err - } - - return committer.Commit() -} - -func deleteBoardByID(ctx context.Context, boardID int64) error { - board, err := GetBoard(ctx, boardID) - if err != nil { - if IsErrProjectBoardNotExist(err) { - return nil - } - - return err - } - - if board.Default { - return fmt.Errorf("deleteBoardByID: cannot delete default board") - } - - // move all issues to the default column - project, err := GetProjectByID(ctx, board.ProjectID) - if err != nil { - return err - } - defaultColumn, err := project.GetDefaultBoard(ctx) - if err != nil { - return err - } - - if err = board.moveIssuesToAnotherColumn(ctx, defaultColumn); err != nil { - return err - } - - if _, err := db.GetEngine(ctx).ID(board.ID).NoAutoCondition().Delete(board); err != nil { - return err - } - return nil -} - -func deleteBoardByProjectID(ctx context.Context, projectID int64) error { - _, err := db.GetEngine(ctx).Where("project_id=?", projectID).Delete(&Board{}) - return err -} - -// GetBoard fetches the current board of a project -func GetBoard(ctx context.Context, boardID int64) (*Board, error) { - board := new(Board) - has, err := db.GetEngine(ctx).ID(boardID).Get(board) - if err != nil { - return nil, err - } else if !has { - return nil, ErrProjectBoardNotExist{BoardID: boardID} - } - - return board, nil -} - -// UpdateBoard updates a project board -func UpdateBoard(ctx context.Context, board *Board) error { - var fieldToUpdate []string - - if board.Sorting != 0 { - fieldToUpdate = append(fieldToUpdate, "sorting") - } - - if board.Title != "" { - fieldToUpdate = append(fieldToUpdate, "title") - } - - if len(board.Color) != 0 && !BoardColorPattern.MatchString(board.Color) { - return fmt.Errorf("bad color code: %s", board.Color) - } - fieldToUpdate = append(fieldToUpdate, "color") - - _, err := db.GetEngine(ctx).ID(board.ID).Cols(fieldToUpdate...).Update(board) - - return err -} - -// GetBoards fetches all boards related to a project -func (p *Project) GetBoards(ctx context.Context) (BoardList, error) { - boards := make([]*Board, 0, 5) - if err := db.GetEngine(ctx).Where("project_id=?", p.ID).OrderBy("sorting, id").Find(&boards); err != nil { - return nil, err - } - - return boards, nil -} - -// GetDefaultBoard return default board and ensure only one exists -func (p *Project) GetDefaultBoard(ctx context.Context) (*Board, error) { - var board Board - has, err := db.GetEngine(ctx). - Where("project_id=? AND `default` = ?", p.ID, true). - Desc("id").Get(&board) - if err != nil { - return nil, err - } - - if has { - return &board, nil - } - - // create a default board if none is found - board = Board{ - ProjectID: p.ID, - Default: true, - Title: "Uncategorized", - CreatorID: p.CreatorID, - } - if _, err := db.GetEngine(ctx).Insert(&board); err != nil { - return nil, err - } - return &board, nil -} - -// SetDefaultBoard represents a board for issues not assigned to one -func SetDefaultBoard(ctx context.Context, projectID, boardID int64) error { - return db.WithTx(ctx, func(ctx context.Context) error { - if _, err := GetBoard(ctx, boardID); err != nil { - return err - } - - if _, err := db.GetEngine(ctx).Where(builder.Eq{ - "project_id": projectID, - "`default`": true, - }).Cols("`default`").Update(&Board{Default: false}); err != nil { - return err - } - - _, err := db.GetEngine(ctx).ID(boardID). - Where(builder.Eq{"project_id": projectID}). - Cols("`default`").Update(&Board{Default: true}) - return err - }) -} - -// UpdateBoardSorting update project board sorting -func UpdateBoardSorting(ctx context.Context, bs BoardList) error { - return db.WithTx(ctx, func(ctx context.Context) error { - for i := range bs { - if _, err := db.GetEngine(ctx).ID(bs[i].ID).Cols( - "sorting", - ).Update(bs[i]); err != nil { - return err - } - } - return nil - }) -} - -func GetColumnsByIDs(ctx context.Context, projectID int64, columnsIDs []int64) (BoardList, error) { - columns := make([]*Board, 0, 5) - if err := db.GetEngine(ctx). - Where("project_id =?", projectID). - In("id", columnsIDs). - OrderBy("sorting").Find(&columns); err != nil { - return nil, err - } - return columns, nil -} - -// MoveColumnsOnProject sorts columns in a project -func MoveColumnsOnProject(ctx context.Context, project *Project, sortedColumnIDs map[int64]int64) error { - return db.WithTx(ctx, func(ctx context.Context) error { - sess := db.GetEngine(ctx) - columnIDs := util.ValuesOfMap(sortedColumnIDs) - movedColumns, err := GetColumnsByIDs(ctx, project.ID, columnIDs) - if err != nil { - return err - } - if len(movedColumns) != len(sortedColumnIDs) { - return errors.New("some columns do not exist") - } - - for _, column := range movedColumns { - if column.ProjectID != project.ID { - return fmt.Errorf("column[%d]'s projectID is not equal to project's ID [%d]", column.ProjectID, project.ID) - } - } - - for sorting, columnID := range sortedColumnIDs { - if _, err := sess.Exec("UPDATE `project_board` SET sorting=? WHERE id=?", sorting, columnID); err != nil { - return err - } - } - return nil - }) -} diff --git a/models/project/column.go b/models/project/column.go new file mode 100644 index 0000000000..222f448599 --- /dev/null +++ b/models/project/column.go @@ -0,0 +1,359 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package project + +import ( + "context" + "errors" + "fmt" + "regexp" + + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" + + "xorm.io/builder" +) + +type ( + + // CardType is used to represent a project column card type + CardType uint8 + + // ColumnList is a list of all project columns in a repository + ColumnList []*Column +) + +const ( + // CardTypeTextOnly is a project column card type that is text only + CardTypeTextOnly CardType = iota + + // CardTypeImagesAndText is a project column card type that has images and text + CardTypeImagesAndText +) + +// ColumnColorPattern is a regexp witch can validate ColumnColor +var ColumnColorPattern = regexp.MustCompile("^#[0-9a-fA-F]{6}$") + +// Column is used to represent column on a project +type Column struct { + ID int64 `xorm:"pk autoincr"` + Title string + Default bool `xorm:"NOT NULL DEFAULT false"` // issues not assigned to a specific column will be assigned to this column + Sorting int8 `xorm:"NOT NULL DEFAULT 0"` + Color string `xorm:"VARCHAR(7)"` + + ProjectID int64 `xorm:"INDEX NOT NULL"` + CreatorID int64 `xorm:"NOT NULL"` + + CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` + UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` +} + +// TableName return the real table name +func (Column) TableName() string { + return "project_board" // TODO: the legacy table name should be project_column +} + +// NumIssues return counter of all issues assigned to the column +func (c *Column) NumIssues(ctx context.Context) int { + total, err := db.GetEngine(ctx).Table("project_issue"). + Where("project_id=?", c.ProjectID). + And("project_board_id=?", c.ID). + GroupBy("issue_id"). + Cols("issue_id"). + Count() + if err != nil { + return 0 + } + return int(total) +} + +func (c *Column) GetIssues(ctx context.Context) ([]*ProjectIssue, error) { + issues := make([]*ProjectIssue, 0, 5) + if err := db.GetEngine(ctx).Where("project_id=?", c.ProjectID). + And("project_board_id=?", c.ID). + OrderBy("sorting, id"). + Find(&issues); err != nil { + return nil, err + } + return issues, nil +} + +func init() { + db.RegisterModel(new(Column)) +} + +// IsCardTypeValid checks if the project column card type is valid +func IsCardTypeValid(p CardType) bool { + switch p { + case CardTypeTextOnly, CardTypeImagesAndText: + return true + default: + return false + } +} + +func createDefaultColumnsForProject(ctx context.Context, project *Project) error { + var items []string + + switch project.TemplateType { + case TemplateTypeBugTriage: + items = setting.Project.ProjectBoardBugTriageType + case TemplateTypeBasicKanban: + items = setting.Project.ProjectBoardBasicKanbanType + case TemplateTypeNone: + fallthrough + default: + return nil + } + + return db.WithTx(ctx, func(ctx context.Context) error { + column := Column{ + CreatedUnix: timeutil.TimeStampNow(), + CreatorID: project.CreatorID, + Title: "Backlog", + ProjectID: project.ID, + Default: true, + } + if err := db.Insert(ctx, column); err != nil { + return err + } + + if len(items) == 0 { + return nil + } + + columns := make([]Column, 0, len(items)) + for _, v := range items { + columns = append(columns, Column{ + CreatedUnix: timeutil.TimeStampNow(), + CreatorID: project.CreatorID, + Title: v, + ProjectID: project.ID, + }) + } + + return db.Insert(ctx, columns) + }) +} + +// maxProjectColumns max columns allowed in a project, this should not bigger than 127 +// because sorting is int8 in database +const maxProjectColumns = 20 + +// NewColumn adds a new project column to a given project +func NewColumn(ctx context.Context, column *Column) error { + if len(column.Color) != 0 && !ColumnColorPattern.MatchString(column.Color) { + return fmt.Errorf("bad color code: %s", column.Color) + } + + res := struct { + MaxSorting int64 + ColumnCount int64 + }{} + if _, err := db.GetEngine(ctx).Select("max(sorting) as max_sorting, count(*) as column_count").Table("project_board"). + Where("project_id=?", column.ProjectID).Get(&res); err != nil { + return err + } + if res.ColumnCount >= maxProjectColumns { + return fmt.Errorf("NewBoard: maximum number of columns reached") + } + column.Sorting = int8(util.Iif(res.ColumnCount > 0, res.MaxSorting+1, 0)) + _, err := db.GetEngine(ctx).Insert(column) + return err +} + +// DeleteColumnByID removes all issues references to the project column. +func DeleteColumnByID(ctx context.Context, columnID int64) error { + return db.WithTx(ctx, func(ctx context.Context) error { + return deleteColumnByID(ctx, columnID) + }) +} + +func deleteColumnByID(ctx context.Context, columnID int64) error { + column, err := GetColumn(ctx, columnID) + if err != nil { + if IsErrProjectColumnNotExist(err) { + return nil + } + + return err + } + + if column.Default { + return fmt.Errorf("deleteColumnByID: cannot delete default column") + } + + // move all issues to the default column + project, err := GetProjectByID(ctx, column.ProjectID) + if err != nil { + return err + } + defaultColumn, err := project.GetDefaultColumn(ctx) + if err != nil { + return err + } + + if err = column.moveIssuesToAnotherColumn(ctx, defaultColumn); err != nil { + return err + } + + if _, err := db.GetEngine(ctx).ID(column.ID).NoAutoCondition().Delete(column); err != nil { + return err + } + return nil +} + +func deleteColumnByProjectID(ctx context.Context, projectID int64) error { + _, err := db.GetEngine(ctx).Where("project_id=?", projectID).Delete(&Column{}) + return err +} + +// GetColumn fetches the current column of a project +func GetColumn(ctx context.Context, columnID int64) (*Column, error) { + column := new(Column) + has, err := db.GetEngine(ctx).ID(columnID).Get(column) + if err != nil { + return nil, err + } else if !has { + return nil, ErrProjectColumnNotExist{ColumnID: columnID} + } + + return column, nil +} + +// UpdateColumn updates a project column +func UpdateColumn(ctx context.Context, column *Column) error { + var fieldToUpdate []string + + if column.Sorting != 0 { + fieldToUpdate = append(fieldToUpdate, "sorting") + } + + if column.Title != "" { + fieldToUpdate = append(fieldToUpdate, "title") + } + + if len(column.Color) != 0 && !ColumnColorPattern.MatchString(column.Color) { + return fmt.Errorf("bad color code: %s", column.Color) + } + fieldToUpdate = append(fieldToUpdate, "color") + + _, err := db.GetEngine(ctx).ID(column.ID).Cols(fieldToUpdate...).Update(column) + + return err +} + +// GetColumns fetches all columns related to a project +func (p *Project) GetColumns(ctx context.Context) (ColumnList, error) { + columns := make([]*Column, 0, 5) + if err := db.GetEngine(ctx).Where("project_id=?", p.ID).OrderBy("sorting, id").Find(&columns); err != nil { + return nil, err + } + + return columns, nil +} + +// GetDefaultColumn return default column and ensure only one exists +func (p *Project) GetDefaultColumn(ctx context.Context) (*Column, error) { + var column Column + has, err := db.GetEngine(ctx). + Where("project_id=? AND `default` = ?", p.ID, true). + Desc("id").Get(&column) + if err != nil { + return nil, err + } + + if has { + return &column, nil + } + + // create a default column if none is found + column = Column{ + ProjectID: p.ID, + Default: true, + Title: "Uncategorized", + CreatorID: p.CreatorID, + } + if _, err := db.GetEngine(ctx).Insert(&column); err != nil { + return nil, err + } + return &column, nil +} + +// SetDefaultColumn represents a column for issues not assigned to one +func SetDefaultColumn(ctx context.Context, projectID, columnID int64) error { + return db.WithTx(ctx, func(ctx context.Context) error { + if _, err := GetColumn(ctx, columnID); err != nil { + return err + } + + if _, err := db.GetEngine(ctx).Where(builder.Eq{ + "project_id": projectID, + "`default`": true, + }).Cols("`default`").Update(&Column{Default: false}); err != nil { + return err + } + + _, err := db.GetEngine(ctx).ID(columnID). + Where(builder.Eq{"project_id": projectID}). + Cols("`default`").Update(&Column{Default: true}) + return err + }) +} + +// UpdateColumnSorting update project column sorting +func UpdateColumnSorting(ctx context.Context, cl ColumnList) error { + return db.WithTx(ctx, func(ctx context.Context) error { + for i := range cl { + if _, err := db.GetEngine(ctx).ID(cl[i].ID).Cols( + "sorting", + ).Update(cl[i]); err != nil { + return err + } + } + return nil + }) +} + +func GetColumnsByIDs(ctx context.Context, projectID int64, columnsIDs []int64) (ColumnList, error) { + columns := make([]*Column, 0, 5) + if err := db.GetEngine(ctx). + Where("project_id =?", projectID). + In("id", columnsIDs). + OrderBy("sorting").Find(&columns); err != nil { + return nil, err + } + return columns, nil +} + +// MoveColumnsOnProject sorts columns in a project +func MoveColumnsOnProject(ctx context.Context, project *Project, sortedColumnIDs map[int64]int64) error { + return db.WithTx(ctx, func(ctx context.Context) error { + sess := db.GetEngine(ctx) + columnIDs := util.ValuesOfMap(sortedColumnIDs) + movedColumns, err := GetColumnsByIDs(ctx, project.ID, columnIDs) + if err != nil { + return err + } + if len(movedColumns) != len(sortedColumnIDs) { + return errors.New("some columns do not exist") + } + + for _, column := range movedColumns { + if column.ProjectID != project.ID { + return fmt.Errorf("column[%d]'s projectID is not equal to project's ID [%d]", column.ProjectID, project.ID) + } + } + + for sorting, columnID := range sortedColumnIDs { + if _, err := sess.Exec("UPDATE `project_board` SET sorting=? WHERE id=?", sorting, columnID); err != nil { + return err + } + } + return nil + }) +} diff --git a/models/project/board_test.go b/models/project/column_test.go similarity index 69% rename from models/project/board_test.go rename to models/project/column_test.go index da922ff7ad..911649fb72 100644 --- a/models/project/board_test.go +++ b/models/project/column_test.go @@ -14,48 +14,48 @@ import ( "github.com/stretchr/testify/assert" ) -func TestGetDefaultBoard(t *testing.T) { +func TestGetDefaultColumn(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) projectWithoutDefault, err := GetProjectByID(db.DefaultContext, 5) assert.NoError(t, err) - // check if default board was added - board, err := projectWithoutDefault.GetDefaultBoard(db.DefaultContext) + // check if default column was added + column, err := projectWithoutDefault.GetDefaultColumn(db.DefaultContext) assert.NoError(t, err) - assert.Equal(t, int64(5), board.ProjectID) - assert.Equal(t, "Uncategorized", board.Title) + assert.Equal(t, int64(5), column.ProjectID) + assert.Equal(t, "Uncategorized", column.Title) projectWithMultipleDefaults, err := GetProjectByID(db.DefaultContext, 6) assert.NoError(t, err) // check if multiple defaults were removed - board, err = projectWithMultipleDefaults.GetDefaultBoard(db.DefaultContext) + column, err = projectWithMultipleDefaults.GetDefaultColumn(db.DefaultContext) assert.NoError(t, err) - assert.Equal(t, int64(6), board.ProjectID) - assert.Equal(t, int64(9), board.ID) + assert.Equal(t, int64(6), column.ProjectID) + assert.Equal(t, int64(9), column.ID) - // set 8 as default board - assert.NoError(t, SetDefaultBoard(db.DefaultContext, board.ProjectID, 8)) + // set 8 as default column + assert.NoError(t, SetDefaultColumn(db.DefaultContext, column.ProjectID, 8)) - // then 9 will become a non-default board - board, err = GetBoard(db.DefaultContext, 9) + // then 9 will become a non-default column + column, err = GetColumn(db.DefaultContext, 9) assert.NoError(t, err) - assert.Equal(t, int64(6), board.ProjectID) - assert.False(t, board.Default) + assert.Equal(t, int64(6), column.ProjectID) + assert.False(t, column.Default) } func Test_moveIssuesToAnotherColumn(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - column1 := unittest.AssertExistsAndLoadBean(t, &Board{ID: 1, ProjectID: 1}) + column1 := unittest.AssertExistsAndLoadBean(t, &Column{ID: 1, ProjectID: 1}) issues, err := column1.GetIssues(db.DefaultContext) assert.NoError(t, err) assert.Len(t, issues, 1) assert.EqualValues(t, 1, issues[0].ID) - column2 := unittest.AssertExistsAndLoadBean(t, &Board{ID: 2, ProjectID: 1}) + column2 := unittest.AssertExistsAndLoadBean(t, &Column{ID: 2, ProjectID: 1}) issues, err = column2.GetIssues(db.DefaultContext) assert.NoError(t, err) assert.Len(t, issues, 1) @@ -81,7 +81,7 @@ func Test_MoveColumnsOnProject(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) project1 := unittest.AssertExistsAndLoadBean(t, &Project{ID: 1}) - columns, err := project1.GetBoards(db.DefaultContext) + columns, err := project1.GetColumns(db.DefaultContext) assert.NoError(t, err) assert.Len(t, columns, 3) assert.EqualValues(t, 0, columns[0].Sorting) // even if there is no default sorting, the code should also work @@ -95,7 +95,7 @@ func Test_MoveColumnsOnProject(t *testing.T) { }) assert.NoError(t, err) - columnsAfter, err := project1.GetBoards(db.DefaultContext) + columnsAfter, err := project1.GetColumns(db.DefaultContext) assert.NoError(t, err) assert.Len(t, columnsAfter, 3) assert.EqualValues(t, columns[1].ID, columnsAfter[0].ID) @@ -103,23 +103,23 @@ func Test_MoveColumnsOnProject(t *testing.T) { assert.EqualValues(t, columns[0].ID, columnsAfter[2].ID) } -func Test_NewBoard(t *testing.T) { +func Test_NewColumn(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) project1 := unittest.AssertExistsAndLoadBean(t, &Project{ID: 1}) - columns, err := project1.GetBoards(db.DefaultContext) + columns, err := project1.GetColumns(db.DefaultContext) assert.NoError(t, err) assert.Len(t, columns, 3) for i := 0; i < maxProjectColumns-3; i++ { - err := NewBoard(db.DefaultContext, &Board{ - Title: fmt.Sprintf("board-%d", i+4), + err := NewColumn(db.DefaultContext, &Column{ + Title: fmt.Sprintf("column-%d", i+4), ProjectID: project1.ID, }) assert.NoError(t, err) } - err = NewBoard(db.DefaultContext, &Board{ - Title: "board-21", + err = NewColumn(db.DefaultContext, &Column{ + Title: "column-21", ProjectID: project1.ID, }) assert.Error(t, err) diff --git a/models/project/issue.go b/models/project/issue.go index 32e72e909d..3361b533b9 100644 --- a/models/project/issue.go +++ b/models/project/issue.go @@ -18,10 +18,10 @@ type ProjectIssue struct { //revive:disable-line:exported IssueID int64 `xorm:"INDEX"` ProjectID int64 `xorm:"INDEX"` - // ProjectBoardID should not be zero since 1.22. If it's zero, the issue will not be displayed on UI and it might result in errors. - ProjectBoardID int64 `xorm:"INDEX"` + // ProjectColumnID should not be zero since 1.22. If it's zero, the issue will not be displayed on UI and it might result in errors. + ProjectColumnID int64 `xorm:"'project_board_id' INDEX"` - // the sorting order on the board + // the sorting order on the column Sorting int64 `xorm:"NOT NULL DEFAULT 0"` } @@ -76,13 +76,13 @@ func (p *Project) NumOpenIssues(ctx context.Context) int { return int(c) } -// MoveIssuesOnProjectBoard moves or keeps issues in a column and sorts them inside that column -func MoveIssuesOnProjectBoard(ctx context.Context, board *Board, sortedIssueIDs map[int64]int64) error { +// MoveIssuesOnProjectColumn moves or keeps issues in a column and sorts them inside that column +func MoveIssuesOnProjectColumn(ctx context.Context, column *Column, sortedIssueIDs map[int64]int64) error { return db.WithTx(ctx, func(ctx context.Context) error { sess := db.GetEngine(ctx) issueIDs := util.ValuesOfMap(sortedIssueIDs) - count, err := sess.Table(new(ProjectIssue)).Where("project_id=?", board.ProjectID).In("issue_id", issueIDs).Count() + count, err := sess.Table(new(ProjectIssue)).Where("project_id=?", column.ProjectID).In("issue_id", issueIDs).Count() if err != nil { return err } @@ -91,7 +91,7 @@ func MoveIssuesOnProjectBoard(ctx context.Context, board *Board, sortedIssueIDs } for sorting, issueID := range sortedIssueIDs { - _, err = sess.Exec("UPDATE `project_issue` SET project_board_id=?, sorting=? WHERE issue_id=?", board.ID, sorting, issueID) + _, err = sess.Exec("UPDATE `project_issue` SET project_board_id=?, sorting=? WHERE issue_id=?", column.ID, sorting, issueID) if err != nil { return err } @@ -100,12 +100,12 @@ func MoveIssuesOnProjectBoard(ctx context.Context, board *Board, sortedIssueIDs }) } -func (b *Board) moveIssuesToAnotherColumn(ctx context.Context, newColumn *Board) error { - if b.ProjectID != newColumn.ProjectID { +func (c *Column) moveIssuesToAnotherColumn(ctx context.Context, newColumn *Column) error { + if c.ProjectID != newColumn.ProjectID { return fmt.Errorf("columns have to be in the same project") } - if b.ID == newColumn.ID { + if c.ID == newColumn.ID { return nil } @@ -121,7 +121,7 @@ func (b *Board) moveIssuesToAnotherColumn(ctx context.Context, newColumn *Board) return err } - issues, err := b.GetIssues(ctx) + issues, err := c.GetIssues(ctx) if err != nil { return err } @@ -132,7 +132,7 @@ func (b *Board) moveIssuesToAnotherColumn(ctx context.Context, newColumn *Board) nextSorting := util.Iif(res.IssueCount > 0, res.MaxSorting+1, 0) return db.WithTx(ctx, func(ctx context.Context) error { for i, issue := range issues { - issue.ProjectBoardID = newColumn.ID + issue.ProjectColumnID = newColumn.ID issue.Sorting = nextSorting + int64(i) if _, err := db.GetEngine(ctx).ID(issue.ID).Cols("project_board_id", "sorting").Update(issue); err != nil { return err diff --git a/models/project/project.go b/models/project/project.go index 8be38694c5..fe5d408f64 100644 --- a/models/project/project.go +++ b/models/project/project.go @@ -21,13 +21,7 @@ import ( ) type ( - // BoardConfig is used to identify the type of board that is being created - BoardConfig struct { - BoardType BoardType - Translation string - } - - // CardConfig is used to identify the type of board card that is being used + // CardConfig is used to identify the type of column card that is being used CardConfig struct { CardType CardType Translation string @@ -38,7 +32,7 @@ type ( ) const ( - // TypeIndividual is a type of project board that is owned by an individual + // TypeIndividual is a type of project column that is owned by an individual TypeIndividual Type = iota + 1 // TypeRepository is a project that is tied to a repository @@ -68,39 +62,39 @@ func (err ErrProjectNotExist) Unwrap() error { return util.ErrNotExist } -// ErrProjectBoardNotExist represents a "ProjectBoardNotExist" kind of error. -type ErrProjectBoardNotExist struct { - BoardID int64 +// ErrProjectColumnNotExist represents a "ErrProjectColumnNotExist" kind of error. +type ErrProjectColumnNotExist struct { + ColumnID int64 } -// IsErrProjectBoardNotExist checks if an error is a ErrProjectBoardNotExist -func IsErrProjectBoardNotExist(err error) bool { - _, ok := err.(ErrProjectBoardNotExist) +// IsErrProjectColumnNotExist checks if an error is a ErrProjectColumnNotExist +func IsErrProjectColumnNotExist(err error) bool { + _, ok := err.(ErrProjectColumnNotExist) return ok } -func (err ErrProjectBoardNotExist) Error() string { - return fmt.Sprintf("project board does not exist [id: %d]", err.BoardID) +func (err ErrProjectColumnNotExist) Error() string { + return fmt.Sprintf("project column does not exist [id: %d]", err.ColumnID) } -func (err ErrProjectBoardNotExist) Unwrap() error { +func (err ErrProjectColumnNotExist) Unwrap() error { return util.ErrNotExist } -// Project represents a project board +// Project represents a project type Project struct { - ID int64 `xorm:"pk autoincr"` - Title string `xorm:"INDEX NOT NULL"` - Description string `xorm:"TEXT"` - OwnerID int64 `xorm:"INDEX"` - Owner *user_model.User `xorm:"-"` - RepoID int64 `xorm:"INDEX"` - Repo *repo_model.Repository `xorm:"-"` - CreatorID int64 `xorm:"NOT NULL"` - IsClosed bool `xorm:"INDEX"` - BoardType BoardType - CardType CardType - Type Type + ID int64 `xorm:"pk autoincr"` + Title string `xorm:"INDEX NOT NULL"` + Description string `xorm:"TEXT"` + OwnerID int64 `xorm:"INDEX"` + Owner *user_model.User `xorm:"-"` + RepoID int64 `xorm:"INDEX"` + Repo *repo_model.Repository `xorm:"-"` + CreatorID int64 `xorm:"NOT NULL"` + IsClosed bool `xorm:"INDEX"` + TemplateType TemplateType `xorm:"'board_type'"` // TODO: rename the column to template_type + CardType CardType + Type Type RenderedContent template.HTML `xorm:"-"` @@ -172,16 +166,7 @@ func init() { db.RegisterModel(new(Project)) } -// GetBoardConfig retrieves the types of configurations project boards could have -func GetBoardConfig() []BoardConfig { - return []BoardConfig{ - {BoardTypeNone, "repo.projects.type.none"}, - {BoardTypeBasicKanban, "repo.projects.type.basic_kanban"}, - {BoardTypeBugTriage, "repo.projects.type.bug_triage"}, - } -} - -// GetCardConfig retrieves the types of configurations project board cards could have +// GetCardConfig retrieves the types of configurations project column cards could have func GetCardConfig() []CardConfig { return []CardConfig{ {CardTypeTextOnly, "repo.projects.card_type.text_only"}, @@ -251,8 +236,8 @@ func GetSearchOrderByBySortType(sortType string) db.SearchOrderBy { // NewProject creates a new Project func NewProject(ctx context.Context, p *Project) error { - if !IsBoardTypeValid(p.BoardType) { - p.BoardType = BoardTypeNone + if !IsTemplateTypeValid(p.TemplateType) { + p.TemplateType = TemplateTypeNone } if !IsCardTypeValid(p.CardType) { @@ -263,27 +248,19 @@ func NewProject(ctx context.Context, p *Project) error { return util.NewInvalidArgumentErrorf("project type is not valid") } - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return err - } - defer committer.Close() - - if err := db.Insert(ctx, p); err != nil { - return err - } - - if p.RepoID > 0 { - if _, err := db.Exec(ctx, "UPDATE `repository` SET num_projects = num_projects + 1 WHERE id = ?", p.RepoID); err != nil { + return db.WithTx(ctx, func(ctx context.Context) error { + if err := db.Insert(ctx, p); err != nil { return err } - } - if err := createBoardsForProjectsType(ctx, p); err != nil { - return err - } + if p.RepoID > 0 { + if _, err := db.Exec(ctx, "UPDATE `repository` SET num_projects = num_projects + 1 WHERE id = ?", p.RepoID); err != nil { + return err + } + } - return committer.Commit() + return createDefaultColumnsForProject(ctx, p) + }) } // GetProjectByID returns the projects in a repository @@ -417,7 +394,7 @@ func DeleteProjectByID(ctx context.Context, id int64) error { return err } - if err := deleteBoardByProjectID(ctx, id); err != nil { + if err := deleteColumnByProjectID(ctx, id); err != nil { return err } diff --git a/models/project/project_test.go b/models/project/project_test.go index 8fbbdedecf..dd421b4659 100644 --- a/models/project/project_test.go +++ b/models/project/project_test.go @@ -51,13 +51,13 @@ func TestProject(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) project := &Project{ - Type: TypeRepository, - BoardType: BoardTypeBasicKanban, - CardType: CardTypeTextOnly, - Title: "New Project", - RepoID: 1, - CreatedUnix: timeutil.TimeStampNow(), - CreatorID: 2, + Type: TypeRepository, + TemplateType: TemplateTypeBasicKanban, + CardType: CardTypeTextOnly, + Title: "New Project", + RepoID: 1, + CreatedUnix: timeutil.TimeStampNow(), + CreatorID: 2, } assert.NoError(t, NewProject(db.DefaultContext, project)) diff --git a/models/project/template.go b/models/project/template.go new file mode 100644 index 0000000000..06d5d2af14 --- /dev/null +++ b/models/project/template.go @@ -0,0 +1,45 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package project + +type ( + // TemplateType is used to represent a project template type + TemplateType uint8 + + // TemplateConfig is used to identify the template type of project that is being created + TemplateConfig struct { + TemplateType TemplateType + Translation string + } +) + +const ( + // TemplateTypeNone is a project template type that has no predefined columns + TemplateTypeNone TemplateType = iota + + // TemplateTypeBasicKanban is a project template type that has basic predefined columns + TemplateTypeBasicKanban + + // TemplateTypeBugTriage is a project template type that has predefined columns suited to hunting down bugs + TemplateTypeBugTriage +) + +// GetTemplateConfigs retrieves the template configs of configurations project columns could have +func GetTemplateConfigs() []TemplateConfig { + return []TemplateConfig{ + {TemplateTypeNone, "repo.projects.type.none"}, + {TemplateTypeBasicKanban, "repo.projects.type.basic_kanban"}, + {TemplateTypeBugTriage, "repo.projects.type.bug_triage"}, + } +} + +// IsTemplateTypeValid checks if the project template type is valid +func IsTemplateTypeValid(p TemplateType) bool { + switch p { + case TemplateTypeNone, TemplateTypeBasicKanban, TemplateTypeBugTriage: + return true + default: + return false + } +} diff --git a/models/unit/unit.go b/models/unit/unit.go index 74efa4caf0..8eedcbd347 100644 --- a/models/unit/unit.go +++ b/models/unit/unit.go @@ -28,7 +28,7 @@ const ( TypeWiki // 5 Wiki TypeExternalWiki // 6 ExternalWiki TypeExternalTracker // 7 ExternalTracker - TypeProjects // 8 Kanban board + TypeProjects // 8 Projects TypePackages // 9 Packages TypeActions // 10 Actions ) diff --git a/modules/indexer/issues/bleve/bleve.go b/modules/indexer/issues/bleve/bleve.go index d7957b266a..7ef370e89c 100644 --- a/modules/indexer/issues/bleve/bleve.go +++ b/modules/indexer/issues/bleve/bleve.go @@ -224,8 +224,8 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( if options.ProjectID.Has() { queries = append(queries, inner_bleve.NumericEqualityQuery(options.ProjectID.Value(), "project_id")) } - if options.ProjectBoardID.Has() { - queries = append(queries, inner_bleve.NumericEqualityQuery(options.ProjectBoardID.Value(), "project_board_id")) + if options.ProjectColumnID.Has() { + queries = append(queries, inner_bleve.NumericEqualityQuery(options.ProjectColumnID.Value(), "project_board_id")) } if options.PosterID.Has() { diff --git a/modules/indexer/issues/db/options.go b/modules/indexer/issues/db/options.go index eeaf1696ad..875a4ca279 100644 --- a/modules/indexer/issues/db/options.go +++ b/modules/indexer/issues/db/options.go @@ -61,7 +61,7 @@ func ToDBOptions(ctx context.Context, options *internal.SearchOptions) (*issue_m ReviewedID: convertID(options.ReviewedID), SubscriberID: convertID(options.SubscriberID), ProjectID: convertID(options.ProjectID), - ProjectBoardID: convertID(options.ProjectBoardID), + ProjectColumnID: convertID(options.ProjectColumnID), IsClosed: options.IsClosed, IsPull: options.IsPull, IncludedLabelNames: nil, diff --git a/modules/indexer/issues/dboptions.go b/modules/indexer/issues/dboptions.go index 8f94088742..d9cf9b5e3b 100644 --- a/modules/indexer/issues/dboptions.go +++ b/modules/indexer/issues/dboptions.go @@ -50,7 +50,7 @@ func ToSearchOptions(keyword string, opts *issues_model.IssuesOptions) *SearchOp } searchOpt.ProjectID = convertID(opts.ProjectID) - searchOpt.ProjectBoardID = convertID(opts.ProjectBoardID) + searchOpt.ProjectColumnID = convertID(opts.ProjectColumnID) searchOpt.PosterID = convertID(opts.PosterID) searchOpt.AssigneeID = convertID(opts.AssigneeID) searchOpt.MentionID = convertID(opts.MentionedID) diff --git a/modules/indexer/issues/elasticsearch/elasticsearch.go b/modules/indexer/issues/elasticsearch/elasticsearch.go index c7cb59f2cf..6f70515009 100644 --- a/modules/indexer/issues/elasticsearch/elasticsearch.go +++ b/modules/indexer/issues/elasticsearch/elasticsearch.go @@ -197,8 +197,8 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( if options.ProjectID.Has() { query.Must(elastic.NewTermQuery("project_id", options.ProjectID.Value())) } - if options.ProjectBoardID.Has() { - query.Must(elastic.NewTermQuery("project_board_id", options.ProjectBoardID.Value())) + if options.ProjectColumnID.Has() { + query.Must(elastic.NewTermQuery("project_board_id", options.ProjectColumnID.Value())) } if options.PosterID.Has() { diff --git a/modules/indexer/issues/indexer_test.go b/modules/indexer/issues/indexer_test.go index 0d0cfc8516..e426229f78 100644 --- a/modules/indexer/issues/indexer_test.go +++ b/modules/indexer/issues/indexer_test.go @@ -369,13 +369,13 @@ func searchIssueInProject(t *testing.T) { }, { SearchOptions{ - ProjectBoardID: optional.Some(int64(1)), + ProjectColumnID: optional.Some(int64(1)), }, []int64{1}, }, { SearchOptions{ - ProjectBoardID: optional.Some(int64(0)), // issue with in default board + ProjectColumnID: optional.Some(int64(0)), // issue with in default column }, []int64{2}, }, diff --git a/modules/indexer/issues/internal/model.go b/modules/indexer/issues/internal/model.go index e9c4eca559..2dfee8b72e 100644 --- a/modules/indexer/issues/internal/model.go +++ b/modules/indexer/issues/internal/model.go @@ -27,7 +27,7 @@ type IndexerData struct { NoLabel bool `json:"no_label"` // True if LabelIDs is empty MilestoneID int64 `json:"milestone_id"` ProjectID int64 `json:"project_id"` - ProjectBoardID int64 `json:"project_board_id"` + ProjectColumnID int64 `json:"project_board_id"` // the key should be kept as project_board_id to keep compatible PosterID int64 `json:"poster_id"` AssigneeID int64 `json:"assignee_id"` MentionIDs []int64 `json:"mention_ids"` @@ -89,8 +89,8 @@ type SearchOptions struct { MilestoneIDs []int64 // milestones the issues have - ProjectID optional.Option[int64] // project the issues belong to - ProjectBoardID optional.Option[int64] // project board the issues belong to + ProjectID optional.Option[int64] // project the issues belong to + ProjectColumnID optional.Option[int64] // project column the issues belong to PosterID optional.Option[int64] // poster of the issues diff --git a/modules/indexer/issues/internal/tests/tests.go b/modules/indexer/issues/internal/tests/tests.go index 7f32876d80..16f0a78ec0 100644 --- a/modules/indexer/issues/internal/tests/tests.go +++ b/modules/indexer/issues/internal/tests/tests.go @@ -338,38 +338,38 @@ var cases = []*testIndexerCase{ }, }, { - Name: "ProjectBoardID", + Name: "ProjectColumnID", SearchOptions: &internal.SearchOptions{ Paginator: &db.ListOptions{ PageSize: 5, }, - ProjectBoardID: optional.Some(int64(1)), + ProjectColumnID: optional.Some(int64(1)), }, Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) { assert.Equal(t, 5, len(result.Hits)) for _, v := range result.Hits { - assert.Equal(t, int64(1), data[v.ID].ProjectBoardID) + assert.Equal(t, int64(1), data[v.ID].ProjectColumnID) } assert.Equal(t, countIndexerData(data, func(v *internal.IndexerData) bool { - return v.ProjectBoardID == 1 + return v.ProjectColumnID == 1 }), result.Total) }, }, { - Name: "no ProjectBoardID", + Name: "no ProjectColumnID", SearchOptions: &internal.SearchOptions{ Paginator: &db.ListOptions{ PageSize: 5, }, - ProjectBoardID: optional.Some(int64(0)), + ProjectColumnID: optional.Some(int64(0)), }, Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) { assert.Equal(t, 5, len(result.Hits)) for _, v := range result.Hits { - assert.Equal(t, int64(0), data[v.ID].ProjectBoardID) + assert.Equal(t, int64(0), data[v.ID].ProjectColumnID) } assert.Equal(t, countIndexerData(data, func(v *internal.IndexerData) bool { - return v.ProjectBoardID == 0 + return v.ProjectColumnID == 0 }), result.Total) }, }, @@ -706,7 +706,7 @@ func generateDefaultIndexerData() []*internal.IndexerData { NoLabel: len(labelIDs) == 0, MilestoneID: issueIndex % 4, ProjectID: issueIndex % 5, - ProjectBoardID: issueIndex % 6, + ProjectColumnID: issueIndex % 6, PosterID: id%10 + 1, // PosterID should not be 0 AssigneeID: issueIndex % 10, MentionIDs: mentionIDs, diff --git a/modules/indexer/issues/meilisearch/meilisearch.go b/modules/indexer/issues/meilisearch/meilisearch.go index 8a7cec6cba..9332319339 100644 --- a/modules/indexer/issues/meilisearch/meilisearch.go +++ b/modules/indexer/issues/meilisearch/meilisearch.go @@ -174,8 +174,8 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( if options.ProjectID.Has() { query.And(inner_meilisearch.NewFilterEq("project_id", options.ProjectID.Value())) } - if options.ProjectBoardID.Has() { - query.And(inner_meilisearch.NewFilterEq("project_board_id", options.ProjectBoardID.Value())) + if options.ProjectColumnID.Has() { + query.And(inner_meilisearch.NewFilterEq("project_board_id", options.ProjectColumnID.Value())) } if options.PosterID.Has() { diff --git a/modules/indexer/issues/util.go b/modules/indexer/issues/util.go index 9861c808dc..e752ae6f24 100644 --- a/modules/indexer/issues/util.go +++ b/modules/indexer/issues/util.go @@ -105,7 +105,7 @@ func getIssueIndexerData(ctx context.Context, issueID int64) (*internal.IndexerD NoLabel: len(labels) == 0, MilestoneID: issue.MilestoneID, ProjectID: projectID, - ProjectBoardID: issue.ProjectBoardID(ctx), + ProjectColumnID: issue.ProjectColumnID(ctx), PosterID: issue.PosterID, AssigneeID: issue.AssigneeID, MentionIDs: mentionIDs, diff --git a/modules/metrics/collector.go b/modules/metrics/collector.go index 1bf8f58b93..230260ff94 100755 --- a/modules/metrics/collector.go +++ b/modules/metrics/collector.go @@ -36,7 +36,7 @@ type Collector struct { Oauths *prometheus.Desc Organizations *prometheus.Desc Projects *prometheus.Desc - ProjectBoards *prometheus.Desc + ProjectColumns *prometheus.Desc PublicKeys *prometheus.Desc Releases *prometheus.Desc Repositories *prometheus.Desc @@ -146,9 +146,9 @@ func NewCollector() Collector { "Number of projects", nil, nil, ), - ProjectBoards: prometheus.NewDesc( - namespace+"projects_boards", - "Number of project boards", + ProjectColumns: prometheus.NewDesc( + namespace+"projects_boards", // TODO: change the key name will affect the consume's result history + "Number of project columns", nil, nil, ), PublicKeys: prometheus.NewDesc( @@ -219,7 +219,7 @@ func (c Collector) Describe(ch chan<- *prometheus.Desc) { ch <- c.Oauths ch <- c.Organizations ch <- c.Projects - ch <- c.ProjectBoards + ch <- c.ProjectColumns ch <- c.PublicKeys ch <- c.Releases ch <- c.Repositories @@ -336,9 +336,9 @@ func (c Collector) Collect(ch chan<- prometheus.Metric) { float64(stats.Counter.Project), ) ch <- prometheus.MustNewConstMetric( - c.ProjectBoards, + c.ProjectColumns, prometheus.GaugeValue, - float64(stats.Counter.ProjectBoard), + float64(stats.Counter.ProjectColumn), ) ch <- prometheus.MustNewConstMetric( c.PublicKeys, diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 40cbdb23fe..fd47974fe9 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1215,7 +1215,7 @@ branches = Branches tags = Tags issues = Issues pulls = Pull Requests -project_board = Projects +projects = Projects packages = Packages actions = Actions labels = Labels @@ -1379,7 +1379,7 @@ ext_issues = Access to External Issues ext_issues.desc = Link to an external issue tracker. projects = Projects -projects.desc = Manage issues and pulls in project boards. +projects.desc = Manage issues and pulls in projects. projects.description = Description (optional) projects.description_placeholder = Description projects.create = Create Project diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go index 50effbe963..8fb8f2540f 100644 --- a/routers/web/org/projects.go +++ b/routers/web/org/projects.go @@ -34,7 +34,7 @@ const ( // MustEnableProjects check if projects are enabled in settings func MustEnableProjects(ctx *context.Context) { if unit.TypeProjects.UnitGlobalDisabled() { - ctx.NotFound("EnableKanbanBoard", nil) + ctx.NotFound("EnableProjects", nil) return } } @@ -42,7 +42,7 @@ func MustEnableProjects(ctx *context.Context) { // Projects renders the home page of projects func Projects(ctx *context.Context) { shared_user.PrepareContextForProfileBigAvatar(ctx) - ctx.Data["Title"] = ctx.Tr("repo.project_board") + ctx.Data["Title"] = ctx.Tr("repo.projects") sortType := ctx.FormTrim("sort") @@ -139,7 +139,7 @@ func canWriteProjects(ctx *context.Context) bool { // RenderNewProject render creating a project page func RenderNewProject(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("repo.projects.new") - ctx.Data["BoardTypes"] = project_model.GetBoardConfig() + ctx.Data["TemplateConfigs"] = project_model.GetTemplateConfigs() ctx.Data["CardTypes"] = project_model.GetCardConfig() ctx.Data["CanWriteProjects"] = canWriteProjects(ctx) ctx.Data["PageIsViewProjects"] = true @@ -168,12 +168,12 @@ func NewProjectPost(ctx *context.Context) { } newProject := project_model.Project{ - OwnerID: ctx.ContextUser.ID, - Title: form.Title, - Description: form.Content, - CreatorID: ctx.Doer.ID, - BoardType: form.BoardType, - CardType: form.CardType, + OwnerID: ctx.ContextUser.ID, + Title: form.Title, + Description: form.Content, + CreatorID: ctx.Doer.ID, + TemplateType: form.TemplateType, + CardType: form.CardType, } if ctx.ContextUser.IsOrganization() { @@ -314,7 +314,7 @@ func EditProjectPost(ctx *context.Context) { } } -// ViewProject renders the project board for a project +// ViewProject renders the project with board view for a project func ViewProject(ctx *context.Context) { project, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id")) if err != nil { @@ -326,15 +326,15 @@ func ViewProject(ctx *context.Context) { return } - boards, err := project.GetBoards(ctx) + columns, err := project.GetColumns(ctx) if err != nil { - ctx.ServerError("GetProjectBoards", err) + ctx.ServerError("GetProjectColumns", err) return } - issuesMap, err := issues_model.LoadIssuesFromBoardList(ctx, boards) + issuesMap, err := issues_model.LoadIssuesFromColumnList(ctx, columns) if err != nil { - ctx.ServerError("LoadIssuesOfBoards", err) + ctx.ServerError("LoadIssuesOfColumns", err) return } @@ -377,7 +377,7 @@ func ViewProject(ctx *context.Context) { ctx.Data["CanWriteProjects"] = canWriteProjects(ctx) ctx.Data["Project"] = project ctx.Data["IssuesMap"] = issuesMap - ctx.Data["Columns"] = boards // TODO: rename boards to columns in backend + ctx.Data["Columns"] = columns shared_user.RenderUserHeader(ctx) err = shared_user.LoadHeaderCount(ctx) @@ -389,8 +389,8 @@ func ViewProject(ctx *context.Context) { ctx.HTML(http.StatusOK, tplProjectsView) } -// DeleteProjectBoard allows for the deletion of a project board -func DeleteProjectBoard(ctx *context.Context) { +// DeleteProjectColumn allows for the deletion of a project column +func DeleteProjectColumn(ctx *context.Context) { if ctx.Doer == nil { ctx.JSON(http.StatusForbidden, map[string]string{ "message": "Only signed in users are allowed to perform this action.", @@ -404,36 +404,36 @@ func DeleteProjectBoard(ctx *context.Context) { return } - pb, err := project_model.GetBoard(ctx, ctx.ParamsInt64(":boardID")) + pb, err := project_model.GetColumn(ctx, ctx.ParamsInt64(":columnID")) if err != nil { - ctx.ServerError("GetProjectBoard", err) + ctx.ServerError("GetProjectColumn", err) return } if pb.ProjectID != ctx.ParamsInt64(":id") { ctx.JSON(http.StatusUnprocessableEntity, map[string]string{ - "message": fmt.Sprintf("ProjectBoard[%d] is not in Project[%d] as expected", pb.ID, project.ID), + "message": fmt.Sprintf("ProjectColumn[%d] is not in Project[%d] as expected", pb.ID, project.ID), }) return } if project.OwnerID != ctx.ContextUser.ID { ctx.JSON(http.StatusUnprocessableEntity, map[string]string{ - "message": fmt.Sprintf("ProjectBoard[%d] is not in Owner[%d] as expected", pb.ID, ctx.ContextUser.ID), + "message": fmt.Sprintf("ProjectColumn[%d] is not in Owner[%d] as expected", pb.ID, ctx.ContextUser.ID), }) return } - if err := project_model.DeleteBoardByID(ctx, ctx.ParamsInt64(":boardID")); err != nil { - ctx.ServerError("DeleteProjectBoardByID", err) + if err := project_model.DeleteColumnByID(ctx, ctx.ParamsInt64(":columnID")); err != nil { + ctx.ServerError("DeleteProjectColumnByID", err) return } ctx.JSONOK() } -// AddBoardToProjectPost allows a new board to be added to a project. -func AddBoardToProjectPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.EditProjectBoardForm) +// AddColumnToProjectPost allows a new column to be added to a project. +func AddColumnToProjectPost(ctx *context.Context) { + form := web.GetForm(ctx).(*forms.EditProjectColumnForm) project, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id")) if err != nil { @@ -441,21 +441,21 @@ func AddBoardToProjectPost(ctx *context.Context) { return } - if err := project_model.NewBoard(ctx, &project_model.Board{ + if err := project_model.NewColumn(ctx, &project_model.Column{ ProjectID: project.ID, Title: form.Title, Color: form.Color, CreatorID: ctx.Doer.ID, }); err != nil { - ctx.ServerError("NewProjectBoard", err) + ctx.ServerError("NewProjectColumn", err) return } ctx.JSONOK() } -// CheckProjectBoardChangePermissions check permission -func CheckProjectBoardChangePermissions(ctx *context.Context) (*project_model.Project, *project_model.Board) { +// CheckProjectColumnChangePermissions check permission +func CheckProjectColumnChangePermissions(ctx *context.Context) (*project_model.Project, *project_model.Column) { if ctx.Doer == nil { ctx.JSON(http.StatusForbidden, map[string]string{ "message": "Only signed in users are allowed to perform this action.", @@ -469,62 +469,60 @@ func CheckProjectBoardChangePermissions(ctx *context.Context) (*project_model.Pr return nil, nil } - board, err := project_model.GetBoard(ctx, ctx.ParamsInt64(":boardID")) + column, err := project_model.GetColumn(ctx, ctx.ParamsInt64(":columnID")) if err != nil { - ctx.ServerError("GetProjectBoard", err) + ctx.ServerError("GetProjectColumn", err) return nil, nil } - if board.ProjectID != ctx.ParamsInt64(":id") { + if column.ProjectID != ctx.ParamsInt64(":id") { ctx.JSON(http.StatusUnprocessableEntity, map[string]string{ - "message": fmt.Sprintf("ProjectBoard[%d] is not in Project[%d] as expected", board.ID, project.ID), + "message": fmt.Sprintf("ProjectColumn[%d] is not in Project[%d] as expected", column.ID, project.ID), }) return nil, nil } if project.OwnerID != ctx.ContextUser.ID { ctx.JSON(http.StatusUnprocessableEntity, map[string]string{ - "message": fmt.Sprintf("ProjectBoard[%d] is not in Repository[%d] as expected", board.ID, project.ID), + "message": fmt.Sprintf("ProjectColumn[%d] is not in Repository[%d] as expected", column.ID, project.ID), }) return nil, nil } - return project, board + return project, column } -// EditProjectBoard allows a project board's to be updated -func EditProjectBoard(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.EditProjectBoardForm) - _, board := CheckProjectBoardChangePermissions(ctx) +// EditProjectColumn allows a project column's to be updated +func EditProjectColumn(ctx *context.Context) { + form := web.GetForm(ctx).(*forms.EditProjectColumnForm) + _, column := CheckProjectColumnChangePermissions(ctx) if ctx.Written() { return } if form.Title != "" { - board.Title = form.Title + column.Title = form.Title } - - board.Color = form.Color - + column.Color = form.Color if form.Sorting != 0 { - board.Sorting = form.Sorting + column.Sorting = form.Sorting } - if err := project_model.UpdateBoard(ctx, board); err != nil { - ctx.ServerError("UpdateProjectBoard", err) + if err := project_model.UpdateColumn(ctx, column); err != nil { + ctx.ServerError("UpdateProjectColumn", err) return } ctx.JSONOK() } -// SetDefaultProjectBoard set default board for uncategorized issues/pulls -func SetDefaultProjectBoard(ctx *context.Context) { - project, board := CheckProjectBoardChangePermissions(ctx) +// SetDefaultProjectColumn set default column for uncategorized issues/pulls +func SetDefaultProjectColumn(ctx *context.Context) { + project, column := CheckProjectColumnChangePermissions(ctx) if ctx.Written() { return } - if err := project_model.SetDefaultBoard(ctx, project.ID, board.ID); err != nil { - ctx.ServerError("SetDefaultBoard", err) + if err := project_model.SetDefaultColumn(ctx, project.ID, column.ID); err != nil { + ctx.ServerError("SetDefaultColumn", err) return } @@ -550,14 +548,14 @@ func MoveIssues(ctx *context.Context) { return } - board, err := project_model.GetBoard(ctx, ctx.ParamsInt64(":boardID")) + column, err := project_model.GetColumn(ctx, ctx.ParamsInt64(":columnID")) if err != nil { - ctx.NotFoundOrServerError("GetProjectBoard", project_model.IsErrProjectBoardNotExist, err) + ctx.NotFoundOrServerError("GetProjectColumn", project_model.IsErrProjectColumnNotExist, err) return } - if board.ProjectID != project.ID { - ctx.NotFound("BoardNotInProject", nil) + if column.ProjectID != project.ID { + ctx.NotFound("ColumnNotInProject", nil) return } @@ -602,8 +600,8 @@ func MoveIssues(ctx *context.Context) { } } - if err = project_model.MoveIssuesOnProjectBoard(ctx, board, sortedIssueIDs); err != nil { - ctx.ServerError("MoveIssuesOnProjectBoard", err) + if err = project_model.MoveIssuesOnProjectColumn(ctx, column, sortedIssueIDs); err != nil { + ctx.ServerError("MoveIssuesOnProjectColumn", err) return } diff --git a/routers/web/org/projects_test.go b/routers/web/org/projects_test.go index f4ccfe1c06..ab419cc878 100644 --- a/routers/web/org/projects_test.go +++ b/routers/web/org/projects_test.go @@ -13,16 +13,16 @@ import ( "github.com/stretchr/testify/assert" ) -func TestCheckProjectBoardChangePermissions(t *testing.T) { +func TestCheckProjectColumnChangePermissions(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "user2/-/projects/4/4") contexttest.LoadUser(t, ctx, 2) ctx.ContextUser = ctx.Doer // user2 ctx.SetParams(":id", "4") - ctx.SetParams(":boardID", "4") + ctx.SetParams(":columnID", "4") - project, board := org.CheckProjectBoardChangePermissions(ctx) + project, column := org.CheckProjectColumnChangePermissions(ctx) assert.NotNil(t, project) - assert.NotNil(t, board) + assert.NotNil(t, column) assert.False(t, ctx.Written()) } diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 0c8363a168..465dafefd3 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -2826,12 +2826,12 @@ func ListIssues(ctx *context.Context) { Page: ctx.FormInt("page"), PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")), }, - Keyword: keyword, - RepoIDs: []int64{ctx.Repo.Repository.ID}, - IsPull: isPull, - IsClosed: isClosed, - ProjectBoardID: projectID, - SortBy: issue_indexer.SortByCreatedDesc, + Keyword: keyword, + RepoIDs: []int64{ctx.Repo.Repository.ID}, + IsPull: isPull, + IsClosed: isClosed, + ProjectID: projectID, + SortBy: issue_indexer.SortByCreatedDesc, } if since != 0 { searchOpt.UpdatedAfterUnix = optional.Some(since) diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go index 6186ee150c..9ce5535a0e 100644 --- a/routers/web/repo/projects.go +++ b/routers/web/repo/projects.go @@ -36,7 +36,7 @@ const ( // MustEnableRepoProjects check if repo projects are enabled in settings func MustEnableRepoProjects(ctx *context.Context) { if unit.TypeProjects.UnitGlobalDisabled() { - ctx.NotFound("EnableKanbanBoard", nil) + ctx.NotFound("EnableRepoProjects", nil) return } @@ -51,7 +51,7 @@ func MustEnableRepoProjects(ctx *context.Context) { // Projects renders the home page of projects func Projects(ctx *context.Context) { - ctx.Data["Title"] = ctx.Tr("repo.project_board") + ctx.Data["Title"] = ctx.Tr("repo.projects") sortType := ctx.FormTrim("sort") @@ -132,7 +132,7 @@ func Projects(ctx *context.Context) { // RenderNewProject render creating a project page func RenderNewProject(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("repo.projects.new") - ctx.Data["BoardTypes"] = project_model.GetBoardConfig() + ctx.Data["TemplateConfigs"] = project_model.GetTemplateConfigs() ctx.Data["CardTypes"] = project_model.GetCardConfig() ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects) ctx.Data["CancelLink"] = ctx.Repo.Repository.Link() + "/projects" @@ -150,13 +150,13 @@ func NewProjectPost(ctx *context.Context) { } if err := project_model.NewProject(ctx, &project_model.Project{ - RepoID: ctx.Repo.Repository.ID, - Title: form.Title, - Description: form.Content, - CreatorID: ctx.Doer.ID, - BoardType: form.BoardType, - CardType: form.CardType, - Type: project_model.TypeRepository, + RepoID: ctx.Repo.Repository.ID, + Title: form.Title, + Description: form.Content, + CreatorID: ctx.Doer.ID, + TemplateType: form.TemplateType, + CardType: form.CardType, + Type: project_model.TypeRepository, }); err != nil { ctx.ServerError("NewProject", err) return @@ -289,7 +289,7 @@ func EditProjectPost(ctx *context.Context) { } } -// ViewProject renders the project board for a project +// ViewProject renders the project with board view func ViewProject(ctx *context.Context) { project, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id")) if err != nil { @@ -305,15 +305,15 @@ func ViewProject(ctx *context.Context) { return } - boards, err := project.GetBoards(ctx) + columns, err := project.GetColumns(ctx) if err != nil { - ctx.ServerError("GetProjectBoards", err) + ctx.ServerError("GetProjectColumns", err) return } - issuesMap, err := issues_model.LoadIssuesFromBoardList(ctx, boards) + issuesMap, err := issues_model.LoadIssuesFromColumnList(ctx, columns) if err != nil { - ctx.ServerError("LoadIssuesOfBoards", err) + ctx.ServerError("LoadIssuesOfColumns", err) return } @@ -368,7 +368,7 @@ func ViewProject(ctx *context.Context) { ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects) ctx.Data["Project"] = project ctx.Data["IssuesMap"] = issuesMap - ctx.Data["Columns"] = boards // TODO: rename boards to columns in backend + ctx.Data["Columns"] = columns ctx.HTML(http.StatusOK, tplProjectsView) } @@ -406,8 +406,8 @@ func UpdateIssueProject(ctx *context.Context) { ctx.JSONOK() } -// DeleteProjectBoard allows for the deletion of a project board -func DeleteProjectBoard(ctx *context.Context) { +// DeleteProjectColumn allows for the deletion of a project column +func DeleteProjectColumn(ctx *context.Context) { if ctx.Doer == nil { ctx.JSON(http.StatusForbidden, map[string]string{ "message": "Only signed in users are allowed to perform this action.", @@ -432,36 +432,36 @@ func DeleteProjectBoard(ctx *context.Context) { return } - pb, err := project_model.GetBoard(ctx, ctx.ParamsInt64(":boardID")) + pb, err := project_model.GetColumn(ctx, ctx.ParamsInt64(":columnID")) if err != nil { - ctx.ServerError("GetProjectBoard", err) + ctx.ServerError("GetProjectColumn", err) return } if pb.ProjectID != ctx.ParamsInt64(":id") { ctx.JSON(http.StatusUnprocessableEntity, map[string]string{ - "message": fmt.Sprintf("ProjectBoard[%d] is not in Project[%d] as expected", pb.ID, project.ID), + "message": fmt.Sprintf("ProjectColumn[%d] is not in Project[%d] as expected", pb.ID, project.ID), }) return } if project.RepoID != ctx.Repo.Repository.ID { ctx.JSON(http.StatusUnprocessableEntity, map[string]string{ - "message": fmt.Sprintf("ProjectBoard[%d] is not in Repository[%d] as expected", pb.ID, ctx.Repo.Repository.ID), + "message": fmt.Sprintf("ProjectColumn[%d] is not in Repository[%d] as expected", pb.ID, ctx.Repo.Repository.ID), }) return } - if err := project_model.DeleteBoardByID(ctx, ctx.ParamsInt64(":boardID")); err != nil { - ctx.ServerError("DeleteProjectBoardByID", err) + if err := project_model.DeleteColumnByID(ctx, ctx.ParamsInt64(":columnID")); err != nil { + ctx.ServerError("DeleteProjectColumnByID", err) return } ctx.JSONOK() } -// AddBoardToProjectPost allows a new board to be added to a project. -func AddBoardToProjectPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.EditProjectBoardForm) +// AddColumnToProjectPost allows a new column to be added to a project. +func AddColumnToProjectPost(ctx *context.Context) { + form := web.GetForm(ctx).(*forms.EditProjectColumnForm) if !ctx.Repo.IsOwner() && !ctx.Repo.IsAdmin() && !ctx.Repo.CanAccess(perm.AccessModeWrite, unit.TypeProjects) { ctx.JSON(http.StatusForbidden, map[string]string{ "message": "Only authorized users are allowed to perform this action.", @@ -479,20 +479,20 @@ func AddBoardToProjectPost(ctx *context.Context) { return } - if err := project_model.NewBoard(ctx, &project_model.Board{ + if err := project_model.NewColumn(ctx, &project_model.Column{ ProjectID: project.ID, Title: form.Title, Color: form.Color, CreatorID: ctx.Doer.ID, }); err != nil { - ctx.ServerError("NewProjectBoard", err) + ctx.ServerError("NewProjectColumn", err) return } ctx.JSONOK() } -func checkProjectBoardChangePermissions(ctx *context.Context) (*project_model.Project, *project_model.Board) { +func checkProjectColumnChangePermissions(ctx *context.Context) (*project_model.Project, *project_model.Column) { if ctx.Doer == nil { ctx.JSON(http.StatusForbidden, map[string]string{ "message": "Only signed in users are allowed to perform this action.", @@ -517,62 +517,60 @@ func checkProjectBoardChangePermissions(ctx *context.Context) (*project_model.Pr return nil, nil } - board, err := project_model.GetBoard(ctx, ctx.ParamsInt64(":boardID")) + column, err := project_model.GetColumn(ctx, ctx.ParamsInt64(":columnID")) if err != nil { - ctx.ServerError("GetProjectBoard", err) + ctx.ServerError("GetProjectColumn", err) return nil, nil } - if board.ProjectID != ctx.ParamsInt64(":id") { + if column.ProjectID != ctx.ParamsInt64(":id") { ctx.JSON(http.StatusUnprocessableEntity, map[string]string{ - "message": fmt.Sprintf("ProjectBoard[%d] is not in Project[%d] as expected", board.ID, project.ID), + "message": fmt.Sprintf("ProjectColumn[%d] is not in Project[%d] as expected", column.ID, project.ID), }) return nil, nil } if project.RepoID != ctx.Repo.Repository.ID { ctx.JSON(http.StatusUnprocessableEntity, map[string]string{ - "message": fmt.Sprintf("ProjectBoard[%d] is not in Repository[%d] as expected", board.ID, ctx.Repo.Repository.ID), + "message": fmt.Sprintf("ProjectColumn[%d] is not in Repository[%d] as expected", column.ID, ctx.Repo.Repository.ID), }) return nil, nil } - return project, board + return project, column } -// EditProjectBoard allows a project board's to be updated -func EditProjectBoard(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.EditProjectBoardForm) - _, board := checkProjectBoardChangePermissions(ctx) +// EditProjectColumn allows a project column's to be updated +func EditProjectColumn(ctx *context.Context) { + form := web.GetForm(ctx).(*forms.EditProjectColumnForm) + _, column := checkProjectColumnChangePermissions(ctx) if ctx.Written() { return } if form.Title != "" { - board.Title = form.Title + column.Title = form.Title } - - board.Color = form.Color - + column.Color = form.Color if form.Sorting != 0 { - board.Sorting = form.Sorting + column.Sorting = form.Sorting } - if err := project_model.UpdateBoard(ctx, board); err != nil { - ctx.ServerError("UpdateProjectBoard", err) + if err := project_model.UpdateColumn(ctx, column); err != nil { + ctx.ServerError("UpdateProjectColumn", err) return } ctx.JSONOK() } -// SetDefaultProjectBoard set default board for uncategorized issues/pulls -func SetDefaultProjectBoard(ctx *context.Context) { - project, board := checkProjectBoardChangePermissions(ctx) +// SetDefaultProjectColumn set default column for uncategorized issues/pulls +func SetDefaultProjectColumn(ctx *context.Context) { + project, column := checkProjectColumnChangePermissions(ctx) if ctx.Written() { return } - if err := project_model.SetDefaultBoard(ctx, project.ID, board.ID); err != nil { - ctx.ServerError("SetDefaultBoard", err) + if err := project_model.SetDefaultColumn(ctx, project.ID, column.ID); err != nil { + ctx.ServerError("SetDefaultColumn", err) return } @@ -609,18 +607,18 @@ func MoveIssues(ctx *context.Context) { return } - board, err := project_model.GetBoard(ctx, ctx.ParamsInt64(":boardID")) + column, err := project_model.GetColumn(ctx, ctx.ParamsInt64(":columnID")) if err != nil { - if project_model.IsErrProjectBoardNotExist(err) { - ctx.NotFound("ProjectBoardNotExist", nil) + if project_model.IsErrProjectColumnNotExist(err) { + ctx.NotFound("ProjectColumnNotExist", nil) } else { - ctx.ServerError("GetProjectBoard", err) + ctx.ServerError("GetProjectColumn", err) } return } - if board.ProjectID != project.ID { - ctx.NotFound("BoardNotInProject", nil) + if column.ProjectID != project.ID { + ctx.NotFound("ColumnNotInProject", nil) return } @@ -664,8 +662,8 @@ func MoveIssues(ctx *context.Context) { } } - if err = project_model.MoveIssuesOnProjectBoard(ctx, board, sortedIssueIDs); err != nil { - ctx.ServerError("MoveIssuesOnProjectBoard", err) + if err = project_model.MoveIssuesOnProjectColumn(ctx, column, sortedIssueIDs); err != nil { + ctx.ServerError("MoveIssuesOnProjectColumn", err) return } diff --git a/routers/web/repo/projects_test.go b/routers/web/repo/projects_test.go index 479f8c55a2..d61230a57e 100644 --- a/routers/web/repo/projects_test.go +++ b/routers/web/repo/projects_test.go @@ -12,16 +12,16 @@ import ( "github.com/stretchr/testify/assert" ) -func TestCheckProjectBoardChangePermissions(t *testing.T) { +func TestCheckProjectColumnChangePermissions(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "user2/repo1/projects/1/2") contexttest.LoadUser(t, ctx, 2) contexttest.LoadRepo(t, ctx, 1) ctx.SetParams(":id", "1") - ctx.SetParams(":boardID", "2") + ctx.SetParams(":columnID", "2") - project, board := checkProjectBoardChangePermissions(ctx) + project, column := checkProjectColumnChangePermissions(ctx) assert.NotNil(t, project) - assert.NotNil(t, board) + assert.NotNil(t, column) assert.False(t, ctx.Written()) } diff --git a/routers/web/web.go b/routers/web/web.go index 194a67bf03..6a17c19821 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1000,7 +1000,7 @@ func registerRoutes(m *web.Route) { m.Get("/new", org.RenderNewProject) m.Post("/new", web.Bind(forms.CreateProjectForm{}), org.NewProjectPost) m.Group("/{id}", func() { - m.Post("", web.Bind(forms.EditProjectBoardForm{}), org.AddBoardToProjectPost) + m.Post("", web.Bind(forms.EditProjectColumnForm{}), org.AddColumnToProjectPost) m.Post("/move", project.MoveColumns) m.Post("/delete", org.DeleteProject) @@ -1008,10 +1008,10 @@ func registerRoutes(m *web.Route) { m.Post("/edit", web.Bind(forms.CreateProjectForm{}), org.EditProjectPost) m.Post("/{action:open|close}", org.ChangeProjectStatus) - m.Group("/{boardID}", func() { - m.Put("", web.Bind(forms.EditProjectBoardForm{}), org.EditProjectBoard) - m.Delete("", org.DeleteProjectBoard) - m.Post("/default", org.SetDefaultProjectBoard) + m.Group("/{columnID}", func() { + m.Put("", web.Bind(forms.EditProjectColumnForm{}), org.EditProjectColumn) + m.Delete("", org.DeleteProjectColumn) + m.Post("/default", org.SetDefaultProjectColumn) m.Post("/move", org.MoveIssues) }) }) @@ -1356,7 +1356,7 @@ func registerRoutes(m *web.Route) { m.Get("/new", repo.RenderNewProject) m.Post("/new", web.Bind(forms.CreateProjectForm{}), repo.NewProjectPost) m.Group("/{id}", func() { - m.Post("", web.Bind(forms.EditProjectBoardForm{}), repo.AddBoardToProjectPost) + m.Post("", web.Bind(forms.EditProjectColumnForm{}), repo.AddColumnToProjectPost) m.Post("/move", project.MoveColumns) m.Post("/delete", repo.DeleteProject) @@ -1364,10 +1364,10 @@ func registerRoutes(m *web.Route) { m.Post("/edit", web.Bind(forms.CreateProjectForm{}), repo.EditProjectPost) m.Post("/{action:open|close}", repo.ChangeProjectStatus) - m.Group("/{boardID}", func() { - m.Put("", web.Bind(forms.EditProjectBoardForm{}), repo.EditProjectBoard) - m.Delete("", repo.DeleteProjectBoard) - m.Post("/default", repo.SetDefaultProjectBoard) + m.Group("/{columnID}", func() { + m.Put("", web.Bind(forms.EditProjectColumnForm{}), repo.EditProjectColumn) + m.Delete("", repo.DeleteProjectColumn) + m.Post("/default", repo.SetDefaultProjectColumn) m.Post("/move", repo.MoveIssues) }) }) diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go index f49cc2e86b..32d96abf4d 100644 --- a/services/forms/repo_form.go +++ b/services/forms/repo_form.go @@ -505,45 +505,21 @@ func (i IssueLockForm) HasValidReason() bool { return false } -// __________ __ __ -// \______ \_______ ____ |__| ____ _____/ |_ ______ -// | ___/\_ __ \/ _ \ | |/ __ \_/ ___\ __\/ ___/ -// | | | | \( <_> ) | \ ___/\ \___| | \___ \ -// |____| |__| \____/\__| |\___ >\___ >__| /____ > -// \______| \/ \/ \/ - // CreateProjectForm form for creating a project type CreateProjectForm struct { - Title string `binding:"Required;MaxSize(100)"` - Content string - BoardType project_model.BoardType - CardType project_model.CardType + Title string `binding:"Required;MaxSize(100)"` + Content string + TemplateType project_model.TemplateType + CardType project_model.CardType } -// UserCreateProjectForm is a from for creating an individual or organization -// form. -type UserCreateProjectForm struct { - Title string `binding:"Required;MaxSize(100)"` - Content string - BoardType project_model.BoardType - CardType project_model.CardType - UID int64 `binding:"Required"` -} - -// EditProjectBoardForm is a form for editing a project board -type EditProjectBoardForm struct { +// EditProjectColumnForm is a form for editing a project column +type EditProjectColumnForm struct { Title string `binding:"Required;MaxSize(100)"` Sorting int8 Color string `binding:"MaxSize(7)"` } -// _____ .__.__ __ -// / \ |__| | ____ _______/ |_ ____ ____ ____ -// / \ / \| | | _/ __ \ / ___/\ __\/ _ \ / \_/ __ \ -// / Y \ | |_\ ___/ \___ \ | | ( <_> ) | \ ___/ -// \____|__ /__|____/\___ >____ > |__| \____/|___| /\___ > -// \/ \/ \/ \/ \/ - // CreateMilestoneForm form for creating milestone type CreateMilestoneForm struct { Title string `binding:"Required;MaxSize(50)"` @@ -557,13 +533,6 @@ func (f *CreateMilestoneForm) Validate(req *http.Request, errs binding.Errors) b return middleware.Validate(errs, ctx.Data, f, ctx.Locale) } -// .____ ___. .__ -// | | _____ \_ |__ ____ | | -// | | \__ \ | __ \_/ __ \| | -// | |___ / __ \| \_\ \ ___/| |__ -// |_______ (____ /___ /\___ >____/ -// \/ \/ \/ \/ - // CreateLabelForm form for creating label type CreateLabelForm struct { ID int64 @@ -591,13 +560,6 @@ func (f *InitializeLabelsForm) Validate(req *http.Request, errs binding.Errors) return middleware.Validate(errs, ctx.Data, f, ctx.Locale) } -// __________ .__ .__ __________ __ -// \______ \__ __| | | | \______ \ ____ ________ __ ____ _______/ |_ -// | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\ -// | | | | / |_| |__ | | \ ___< <_| | | /\ ___/ \___ \ | | -// |____| |____/|____/____/ |____|_ /\___ >__ |____/ \___ >____ > |__| -// \/ \/ |__| \/ \/ - // MergePullRequestForm form for merging Pull Request // swagger:model MergePullRequestOption type MergePullRequestForm struct { diff --git a/services/forms/user_form_hidden_comments.go b/services/forms/user_form_hidden_comments.go index c21fddf478..b9677c1800 100644 --- a/services/forms/user_form_hidden_comments.go +++ b/services/forms/user_form_hidden_comments.go @@ -65,7 +65,7 @@ var hiddenCommentTypeGroups = hiddenCommentTypeGroupsType{ }, "project": { /*30*/ issues_model.CommentTypeProject, - /*31*/ issues_model.CommentTypeProjectBoard, + /*31*/ issues_model.CommentTypeProjectColumn, }, "issue_ref": { /*33*/ issues_model.CommentTypeChangeIssueRef, diff --git a/templates/projects/new.tmpl b/templates/projects/new.tmpl index 92ee36c1c4..bd173b54bc 100644 --- a/templates/projects/new.tmpl +++ b/templates/projects/new.tmpl @@ -25,11 +25,11 @@ <div class="field"> <label>{{ctx.Locale.Tr "repo.projects.template.desc"}}</label> <div class="ui selection dropdown"> - <input type="hidden" name="board_type" value="{{.type}}"> + <input type="hidden" name="template_type" value="{{.type}}"> <div class="default text">{{ctx.Locale.Tr "repo.projects.template.desc_helper"}}</div> <div class="menu"> - {{range $element := .BoardTypes}} - <div class="item" data-id="{{$element.BoardType}}" data-value="{{$element.BoardType}}">{{ctx.Locale.Tr $element.Translation}}</div> + {{range $element := .TemplateConfigs}} + <div class="item" data-id="{{$element.TemplateType}}" data-value="{{$element.TemplateType}}">{{ctx.Locale.Tr $element.Translation}}</div> {{end}} </div> </div> diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index 34f47b7d89..22daaab4bc 100644 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -180,7 +180,7 @@ {{$projectsUnit := .Repository.MustGetUnit $.Context ctx.Consts.RepoUnitTypeProjects}} {{if and (not .UnitProjectsGlobalDisabled) (.Permission.CanRead ctx.Consts.RepoUnitTypeProjects) ($projectsUnit.ProjectsConfig.IsProjectsAllowed "repo")}} <a href="{{.RepoLink}}/projects" class="{{if .IsProjectsPage}}active {{end}}item"> - {{svg "octicon-project"}} {{ctx.Locale.Tr "repo.project_board"}} + {{svg "octicon-project"}} {{ctx.Locale.Tr "repo.projects"}} {{if .Repository.NumOpenProjects}} <span class="ui small label">{{CountFmt .Repository.NumOpenProjects}}</span> {{end}} diff --git a/templates/repo/issue/filter_actions.tmpl b/templates/repo/issue/filter_actions.tmpl index f23ca36d78..18986db773 100644 --- a/templates/repo/issue/filter_actions.tmpl +++ b/templates/repo/issue/filter_actions.tmpl @@ -71,7 +71,7 @@ <!-- Projects --> <div class="ui{{if not (or .OpenProjects .ClosedProjects)}} disabled{{end}} dropdown jump item"> <span class="text"> - {{ctx.Locale.Tr "repo.project_board"}} + {{ctx.Locale.Tr "repo.projects"}} </span> {{svg "octicon-triangle-down" 14 "dropdown icon"}} <div class="menu"> diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index 3168384072..6c49f00094 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -467,7 +467,7 @@ {{$isProjectsGlobalDisabled := ctx.Consts.RepoUnitTypeProjects.UnitGlobalDisabled}} {{$projectsUnit := .Repository.MustGetUnit $.Context ctx.Consts.RepoUnitTypeProjects}} <div class="inline field"> - <label>{{ctx.Locale.Tr "repo.project_board"}}</label> + <label>{{ctx.Locale.Tr "repo.projects"}}</label> <div class="ui checkbox{{if $isProjectsGlobalDisabled}} disabled{{end}}"{{if $isProjectsGlobalDisabled}} data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{end}}> <input class="enable-system" name="enable_projects" type="checkbox" data-target="#projects_box" {{if $isProjectsEnabled}}checked{{end}}> <label>{{ctx.Locale.Tr "repo.settings.projects_desc"}}</label> diff --git a/tests/integration/project_test.go b/tests/integration/project_test.go index 1d9c3aae53..cdff9aa2fd 100644 --- a/tests/integration/project_test.go +++ b/tests/integration/project_test.go @@ -39,23 +39,23 @@ func TestMoveRepoProjectColumns(t *testing.T) { assert.True(t, projectsUnit.ProjectsConfig().IsProjectsAllowed(repo_model.ProjectsModeRepo)) project1 := project_model.Project{ - Title: "new created project", - RepoID: repo2.ID, - Type: project_model.TypeRepository, - BoardType: project_model.BoardTypeNone, + Title: "new created project", + RepoID: repo2.ID, + Type: project_model.TypeRepository, + TemplateType: project_model.TemplateTypeNone, } err := project_model.NewProject(db.DefaultContext, &project1) assert.NoError(t, err) for i := 0; i < 3; i++ { - err = project_model.NewBoard(db.DefaultContext, &project_model.Board{ + err = project_model.NewColumn(db.DefaultContext, &project_model.Column{ Title: fmt.Sprintf("column %d", i+1), ProjectID: project1.ID, }) assert.NoError(t, err) } - columns, err := project1.GetBoards(db.DefaultContext) + columns, err := project1.GetColumns(db.DefaultContext) assert.NoError(t, err) assert.Len(t, columns, 3) assert.EqualValues(t, 0, columns[0].Sorting) @@ -76,7 +76,7 @@ func TestMoveRepoProjectColumns(t *testing.T) { }) sess.MakeRequest(t, req, http.StatusOK) - columnsAfter, err := project1.GetBoards(db.DefaultContext) + columnsAfter, err := project1.GetColumns(db.DefaultContext) assert.NoError(t, err) assert.Len(t, columns, 3) assert.EqualValues(t, columns[1].ID, columnsAfter[0].ID) diff --git a/web_src/css/features/projects.css b/web_src/css/features/projects.css index 21e2aee0a2..e25182051a 100644 --- a/web_src/css/features/projects.css +++ b/web_src/css/features/projects.css @@ -7,7 +7,7 @@ } .project-column { - background-color: var(--color-project-board-bg) !important; + background-color: var(--color-project-column-bg) !important; border: 1px solid var(--color-secondary) !important; margin: 0 0.5rem !important; padding: 0.5rem !important; diff --git a/web_src/css/themes/theme-gitea-dark.css b/web_src/css/themes/theme-gitea-dark.css index ad9ab5a8c2..45102b64f5 100644 --- a/web_src/css/themes/theme-gitea-dark.css +++ b/web_src/css/themes/theme-gitea-dark.css @@ -216,7 +216,7 @@ --color-expand-button: #2f363d; --color-placeholder-text: var(--color-text-light-3); --color-editor-line-highlight: var(--color-primary-light-5); - --color-project-board-bg: var(--color-secondary-light-2); + --color-project-column-bg: var(--color-secondary-light-2); --color-caret: var(--color-text); /* should ideally be --color-text-dark, see #15651 */ --color-reaction-bg: #e8f3ff12; --color-reaction-hover-bg: var(--color-primary-light-4); diff --git a/web_src/css/themes/theme-gitea-light.css b/web_src/css/themes/theme-gitea-light.css index 8d4aa6df93..8c7fc8a00d 100644 --- a/web_src/css/themes/theme-gitea-light.css +++ b/web_src/css/themes/theme-gitea-light.css @@ -216,7 +216,7 @@ --color-expand-button: #cfe8fa; --color-placeholder-text: var(--color-text-light-3); --color-editor-line-highlight: var(--color-primary-light-6); - --color-project-board-bg: var(--color-secondary-light-4); + --color-project-column-bg: var(--color-secondary-light-4); --color-caret: var(--color-text-dark); --color-reaction-bg: #0000170a; --color-reaction-hover-bg: var(--color-primary-light-5); From c0880e7695346997c6a93f05cd01634cb3ad03ee Mon Sep 17 00:00:00 2001 From: Rowan Bohde <rowan.bohde@gmail.com> Date: Mon, 27 May 2024 07:56:04 -0500 Subject: [PATCH 361/370] feat: add support for a credentials chain for minio access (#31051) We wanted to be able to use the IAM role provided by the EC2 instance metadata in order to access S3 via the Minio configuration. To do this, a new credentials chain is added that will check the following locations for credentials when an access key is not provided. In priority order, they are: 1. MINIO_ prefixed environment variables 2. AWS_ prefixed environment variables 3. a minio credentials file 4. an aws credentials file 5. EC2 instance metadata --- custom/conf/app.example.ini | 10 +- .../config-cheat-sheet.en-us.md | 18 ++- modules/storage/minio.go | 31 +++++- modules/storage/minio_test.go | 104 ++++++++++++++++++ modules/storage/testdata/aws_credentials | 3 + modules/storage/testdata/minio.json | 12 ++ 6 files changed, 169 insertions(+), 9 deletions(-) create mode 100644 modules/storage/testdata/aws_credentials create mode 100644 modules/storage/testdata/minio.json diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index afbd20eb56..7c05e7fefd 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1872,7 +1872,10 @@ LEVEL = Info ;; Minio endpoint to connect only available when STORAGE_TYPE is `minio` ;MINIO_ENDPOINT = localhost:9000 ;; -;; Minio accessKeyID to connect only available when STORAGE_TYPE is `minio` +;; Minio accessKeyID to connect only available when STORAGE_TYPE is `minio`. +;; If not provided and STORAGE_TYPE is `minio`, will search for credentials in known +;; environment variables (MINIO_ACCESS_KEY_ID, AWS_ACCESS_KEY_ID), credentials files +;; (~/.mc/config.json, ~/.aws/credentials), and EC2 instance metadata. ;MINIO_ACCESS_KEY_ID = ;; ;; Minio secretAccessKey to connect only available when STORAGE_TYPE is `minio` @@ -2573,7 +2576,10 @@ LEVEL = Info ;; Minio endpoint to connect only available when STORAGE_TYPE is `minio` ;MINIO_ENDPOINT = localhost:9000 ;; -;; Minio accessKeyID to connect only available when STORAGE_TYPE is `minio` +;; Minio accessKeyID to connect only available when STORAGE_TYPE is `minio`. +;; If not provided and STORAGE_TYPE is `minio`, will search for credentials in known +;; environment variables (MINIO_ACCESS_KEY_ID, AWS_ACCESS_KEY_ID), credentials files +;; (~/.mc/config.json, ~/.aws/credentials), and EC2 instance metadata. ;MINIO_ACCESS_KEY_ID = ;; ;; Minio secretAccessKey to connect only available when STORAGE_TYPE is `minio` diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index 1165a83e25..2c15d161ea 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -843,7 +843,7 @@ Default templates for project board view: - `SERVE_DIRECT`: **false**: Allows the storage driver to redirect to authenticated URLs to serve files directly. Currently, only Minio/S3 is supported via signed URLs, local does nothing. - `PATH`: **attachments**: Path to store attachments only available when STORAGE_TYPE is `local`, relative paths will be resolved to `${AppDataPath}/${attachment.PATH}`. - `MINIO_ENDPOINT`: **localhost:9000**: Minio endpoint to connect only available when STORAGE_TYPE is `minio` -- `MINIO_ACCESS_KEY_ID`: Minio accessKeyID to connect only available when STORAGE_TYPE is `minio` +- `MINIO_ACCESS_KEY_ID`: Minio accessKeyID to connect only available when STORAGE_TYPE is `minio`. If not provided and STORAGE_TYPE is `minio`, will search for credentials in known environment variables (MINIO_ACCESS_KEY_ID, AWS_ACCESS_KEY_ID), credentials files (~/.mc/config.json, ~/.aws/credentials), and EC2 instance metadata. - `MINIO_SECRET_ACCESS_KEY`: Minio secretAccessKey to connect only available when STORAGE_TYPE is `minio` - `MINIO_BUCKET`: **gitea**: Minio bucket to store the attachments only available when STORAGE_TYPE is `minio` - `MINIO_LOCATION`: **us-east-1**: Minio location to create bucket only available when STORAGE_TYPE is `minio` @@ -1274,7 +1274,7 @@ is `data/lfs` and the default of `MINIO_BASE_PATH` is `lfs/`. - `SERVE_DIRECT`: **false**: Allows the storage driver to redirect to authenticated URLs to serve files directly. Currently, only Minio/S3 is supported via signed URLs, local does nothing. - `PATH`: **./data/lfs**: Where to store LFS files, only available when `STORAGE_TYPE` is `local`. If not set it fall back to deprecated LFS_CONTENT_PATH value in [server] section. - `MINIO_ENDPOINT`: **localhost:9000**: Minio endpoint to connect only available when `STORAGE_TYPE` is `minio` -- `MINIO_ACCESS_KEY_ID`: Minio accessKeyID to connect only available when `STORAGE_TYPE` is `minio` +- `MINIO_ACCESS_KEY_ID`: Minio accessKeyID to connect only available when STORAGE_TYPE is `minio`. If not provided and STORAGE_TYPE is `minio`, will search for credentials in known environment variables (MINIO_ACCESS_KEY_ID, AWS_ACCESS_KEY_ID), credentials files (~/.mc/config.json, ~/.aws/credentials), and EC2 instance metadata. - `MINIO_SECRET_ACCESS_KEY`: Minio secretAccessKey to connect only available when `STORAGE_TYPE is` `minio` - `MINIO_BUCKET`: **gitea**: Minio bucket to store the lfs only available when `STORAGE_TYPE` is `minio` - `MINIO_LOCATION`: **us-east-1**: Minio location to create bucket only available when `STORAGE_TYPE` is `minio` @@ -1290,7 +1290,7 @@ Default storage configuration for attachments, lfs, avatars, repo-avatars, repo- - `STORAGE_TYPE`: **local**: Storage type, `local` for local disk or `minio` for s3 compatible object storage service. - `SERVE_DIRECT`: **false**: Allows the storage driver to redirect to authenticated URLs to serve files directly. Currently, only Minio/S3 is supported via signed URLs, local does nothing. - `MINIO_ENDPOINT`: **localhost:9000**: Minio endpoint to connect only available when `STORAGE_TYPE` is `minio` -- `MINIO_ACCESS_KEY_ID`: Minio accessKeyID to connect only available when `STORAGE_TYPE` is `minio` +- `MINIO_ACCESS_KEY_ID`: Minio accessKeyID to connect only available when STORAGE_TYPE is `minio`. If not provided and STORAGE_TYPE is `minio`, will search for credentials in known environment variables (MINIO_ACCESS_KEY_ID, AWS_ACCESS_KEY_ID), credentials files (~/.mc/config.json, ~/.aws/credentials), and EC2 instance metadata. - `MINIO_SECRET_ACCESS_KEY`: Minio secretAccessKey to connect only available when `STORAGE_TYPE is` `minio` - `MINIO_BUCKET`: **gitea**: Minio bucket to store the data only available when `STORAGE_TYPE` is `minio` - `MINIO_LOCATION`: **us-east-1**: Minio location to create bucket only available when `STORAGE_TYPE` is `minio` @@ -1305,7 +1305,10 @@ The recommended storage configuration for minio like below: STORAGE_TYPE = minio ; Minio endpoint to connect only available when STORAGE_TYPE is `minio` MINIO_ENDPOINT = localhost:9000 -; Minio accessKeyID to connect only available when STORAGE_TYPE is `minio` +; Minio accessKeyID to connect only available when STORAGE_TYPE is `minio`. +; If not provided and STORAGE_TYPE is `minio`, will search for credentials in known +; environment variables (MINIO_ACCESS_KEY_ID, AWS_ACCESS_KEY_ID), credentials files +; (~/.mc/config.json, ~/.aws/credentials), and EC2 instance metadata. MINIO_ACCESS_KEY_ID = ; Minio secretAccessKey to connect only available when STORAGE_TYPE is `minio` MINIO_SECRET_ACCESS_KEY = @@ -1354,7 +1357,10 @@ STORAGE_TYPE = my_minio STORAGE_TYPE = minio ; Minio endpoint to connect only available when STORAGE_TYPE is `minio` MINIO_ENDPOINT = localhost:9000 -; Minio accessKeyID to connect only available when STORAGE_TYPE is `minio` +; Minio accessKeyID to connect only available when STORAGE_TYPE is `minio`. +; If not provided and STORAGE_TYPE is `minio`, will search for credentials in known +; environment variables (MINIO_ACCESS_KEY_ID, AWS_ACCESS_KEY_ID), credentials files +; (~/.mc/config.json, ~/.aws/credentials), and EC2 instance metadata. MINIO_ACCESS_KEY_ID = ; Minio secretAccessKey to connect only available when STORAGE_TYPE is `minio` MINIO_SECRET_ACCESS_KEY = @@ -1380,7 +1386,7 @@ is `data/repo-archive` and the default of `MINIO_BASE_PATH` is `repo-archive/`. - `SERVE_DIRECT`: **false**: Allows the storage driver to redirect to authenticated URLs to serve files directly. Currently, only Minio/S3 is supported via signed URLs, local does nothing. - `PATH`: **./data/repo-archive**: Where to store archive files, only available when `STORAGE_TYPE` is `local`. - `MINIO_ENDPOINT`: **localhost:9000**: Minio endpoint to connect only available when `STORAGE_TYPE` is `minio` -- `MINIO_ACCESS_KEY_ID`: Minio accessKeyID to connect only available when `STORAGE_TYPE` is `minio` +- `MINIO_ACCESS_KEY_ID`: Minio accessKeyID to connect only available when STORAGE_TYPE is `minio`. If not provided and STORAGE_TYPE is `minio`, will search for credentials in known environment variables (MINIO_ACCESS_KEY_ID, AWS_ACCESS_KEY_ID), credentials files (~/.mc/config.json, ~/.aws/credentials), and EC2 instance metadata. - `MINIO_SECRET_ACCESS_KEY`: Minio secretAccessKey to connect only available when `STORAGE_TYPE is` `minio` - `MINIO_BUCKET`: **gitea**: Minio bucket to store the lfs only available when `STORAGE_TYPE` is `minio` - `MINIO_LOCATION`: **us-east-1**: Minio location to create bucket only available when `STORAGE_TYPE` is `minio` diff --git a/modules/storage/minio.go b/modules/storage/minio.go index 986332dfed..1b32b2f54f 100644 --- a/modules/storage/minio.go +++ b/modules/storage/minio.go @@ -97,7 +97,7 @@ func NewMinioStorage(ctx context.Context, cfg *setting.Storage) (ObjectStorage, } minioClient, err := minio.New(config.Endpoint, &minio.Options{ - Creds: credentials.NewStaticV4(config.AccessKeyID, config.SecretAccessKey, ""), + Creds: buildMinioCredentials(config, credentials.DefaultIAMRoleEndpoint), Secure: config.UseSSL, Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: config.InsecureSkipVerify}}, Region: config.Location, @@ -164,6 +164,35 @@ func (m *MinioStorage) buildMinioDirPrefix(p string) string { return p } +func buildMinioCredentials(config setting.MinioStorageConfig, iamEndpoint string) *credentials.Credentials { + // If static credentials are provided, use those + if config.AccessKeyID != "" { + return credentials.NewStaticV4(config.AccessKeyID, config.SecretAccessKey, "") + } + + // Otherwise, fallback to a credentials chain for S3 access + chain := []credentials.Provider{ + // configure based upon MINIO_ prefixed environment variables + &credentials.EnvMinio{}, + // configure based upon AWS_ prefixed environment variables + &credentials.EnvAWS{}, + // read credentials from MINIO_SHARED_CREDENTIALS_FILE + // environment variable, or default json config files + &credentials.FileMinioClient{}, + // read credentials from AWS_SHARED_CREDENTIALS_FILE + // environment variable, or default credentials file + &credentials.FileAWSCredentials{}, + // read IAM role from EC2 metadata endpoint if available + &credentials.IAM{ + Endpoint: iamEndpoint, + Client: &http.Client{ + Transport: http.DefaultTransport, + }, + }, + } + return credentials.NewChainCredentials(chain) +} + // Open opens a file func (m *MinioStorage) Open(path string) (Object, error) { opts := minio.GetObjectOptions{} diff --git a/modules/storage/minio_test.go b/modules/storage/minio_test.go index c6fbb91ab4..ad11046dd6 100644 --- a/modules/storage/minio_test.go +++ b/modules/storage/minio_test.go @@ -6,6 +6,7 @@ package storage import ( "context" "net/http" + "net/http/httptest" "os" "testing" @@ -92,3 +93,106 @@ func TestS3StorageBadRequest(t *testing.T) { _, err := NewStorage(setting.MinioStorageType, cfg) assert.ErrorContains(t, err, message) } + +func TestMinioCredentials(t *testing.T) { + const ( + ExpectedAccessKey = "ExampleAccessKeyID" + ExpectedSecretAccessKey = "ExampleSecretAccessKeyID" + // Use a FakeEndpoint for IAM credentials to avoid logging any + // potential real IAM credentials when running in EC2. + FakeEndpoint = "http://localhost" + ) + + t.Run("Static Credentials", func(t *testing.T) { + cfg := setting.MinioStorageConfig{ + AccessKeyID: ExpectedAccessKey, + SecretAccessKey: ExpectedSecretAccessKey, + } + creds := buildMinioCredentials(cfg, FakeEndpoint) + v, err := creds.Get() + + assert.NoError(t, err) + assert.Equal(t, ExpectedAccessKey, v.AccessKeyID) + assert.Equal(t, ExpectedSecretAccessKey, v.SecretAccessKey) + }) + + t.Run("Chain", func(t *testing.T) { + cfg := setting.MinioStorageConfig{} + + t.Run("EnvMinio", func(t *testing.T) { + t.Setenv("MINIO_ACCESS_KEY", ExpectedAccessKey+"Minio") + t.Setenv("MINIO_SECRET_KEY", ExpectedSecretAccessKey+"Minio") + + creds := buildMinioCredentials(cfg, FakeEndpoint) + v, err := creds.Get() + + assert.NoError(t, err) + assert.Equal(t, ExpectedAccessKey+"Minio", v.AccessKeyID) + assert.Equal(t, ExpectedSecretAccessKey+"Minio", v.SecretAccessKey) + }) + + t.Run("EnvAWS", func(t *testing.T) { + t.Setenv("AWS_ACCESS_KEY", ExpectedAccessKey+"AWS") + t.Setenv("AWS_SECRET_KEY", ExpectedSecretAccessKey+"AWS") + + creds := buildMinioCredentials(cfg, FakeEndpoint) + v, err := creds.Get() + + assert.NoError(t, err) + assert.Equal(t, ExpectedAccessKey+"AWS", v.AccessKeyID) + assert.Equal(t, ExpectedSecretAccessKey+"AWS", v.SecretAccessKey) + }) + + t.Run("FileMinio", func(t *testing.T) { + t.Setenv("MINIO_SHARED_CREDENTIALS_FILE", "testdata/minio.json") + // prevent loading any actual credentials files from the user + t.Setenv("AWS_SHARED_CREDENTIALS_FILE", "testdata/fake") + + creds := buildMinioCredentials(cfg, FakeEndpoint) + v, err := creds.Get() + + assert.NoError(t, err) + assert.Equal(t, ExpectedAccessKey+"MinioFile", v.AccessKeyID) + assert.Equal(t, ExpectedSecretAccessKey+"MinioFile", v.SecretAccessKey) + }) + + t.Run("FileAWS", func(t *testing.T) { + // prevent loading any actual credentials files from the user + t.Setenv("MINIO_SHARED_CREDENTIALS_FILE", "testdata/fake.json") + t.Setenv("AWS_SHARED_CREDENTIALS_FILE", "testdata/aws_credentials") + + creds := buildMinioCredentials(cfg, FakeEndpoint) + v, err := creds.Get() + + assert.NoError(t, err) + assert.Equal(t, ExpectedAccessKey+"AWSFile", v.AccessKeyID) + assert.Equal(t, ExpectedSecretAccessKey+"AWSFile", v.SecretAccessKey) + }) + + t.Run("IAM", func(t *testing.T) { + // prevent loading any actual credentials files from the user + t.Setenv("MINIO_SHARED_CREDENTIALS_FILE", "testdata/fake.json") + t.Setenv("AWS_SHARED_CREDENTIALS_FILE", "testdata/fake") + + // Spawn a server to emulate the EC2 Instance Metadata + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // The client will actually make 3 requests here, + // first will be to get the IMDSv2 token, second to + // get the role, and third for the actual + // credentials. However, we can return credentials + // every request since we're not emulating a full + // IMDSv2 flow. + w.Write([]byte(`{"Code":"Success","AccessKeyId":"ExampleAccessKeyIDIAM","SecretAccessKey":"ExampleSecretAccessKeyIDIAM"}`)) + })) + defer server.Close() + + // Use the provided EC2 Instance Metadata server + creds := buildMinioCredentials(cfg, server.URL) + v, err := creds.Get() + + assert.NoError(t, err) + assert.Equal(t, ExpectedAccessKey+"IAM", v.AccessKeyID) + assert.Equal(t, ExpectedSecretAccessKey+"IAM", v.SecretAccessKey) + }) + }) +} diff --git a/modules/storage/testdata/aws_credentials b/modules/storage/testdata/aws_credentials new file mode 100644 index 0000000000..62a5488b51 --- /dev/null +++ b/modules/storage/testdata/aws_credentials @@ -0,0 +1,3 @@ +[default] +aws_access_key_id=ExampleAccessKeyIDAWSFile +aws_secret_access_key=ExampleSecretAccessKeyIDAWSFile diff --git a/modules/storage/testdata/minio.json b/modules/storage/testdata/minio.json new file mode 100644 index 0000000000..3876257626 --- /dev/null +++ b/modules/storage/testdata/minio.json @@ -0,0 +1,12 @@ +{ + "version": "10", + "aliases": { + "s3": { + "url": "https://s3.amazonaws.com", + "accessKey": "ExampleAccessKeyIDMinioFile", + "secretKey": "ExampleSecretAccessKeyIDMinioFile", + "api": "S3v4", + "path": "dns" + } + } +} From 20c40259f12d5c1f4547df10a627d888b473e1e4 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Mon, 27 May 2024 21:43:32 +0800 Subject: [PATCH 362/370] Fix missing memcache import (#31105) Fix #31102 --- modules/cache/cache.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/cache/cache.go b/modules/cache/cache.go index 2ca77bdb29..0753671158 100644 --- a/modules/cache/cache.go +++ b/modules/cache/cache.go @@ -8,6 +8,8 @@ import ( "time" "code.gitea.io/gitea/modules/setting" + + _ "gitea.com/go-chi/cache/memcache" //nolint:depguard // memcache plugin for cache, it is required for config "ADAPTER=memcache" ) var defaultCache StringCache From 8fc2ec187290419252f2ade497655d62df3a1505 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Mon, 27 May 2024 21:53:33 +0800 Subject: [PATCH 363/370] Update pip related commands for docker (#31106) Thanks to graelo and silverwind for figuring out the problem. Fix #31101 --- docs/content/administration/external-renderers.en-us.md | 6 ++---- docs/content/administration/external-renderers.zh-cn.md | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/docs/content/administration/external-renderers.en-us.md b/docs/content/administration/external-renderers.en-us.md index 1e41b80145..fec2ab64d4 100644 --- a/docs/content/administration/external-renderers.en-us.md +++ b/docs/content/administration/external-renderers.en-us.md @@ -38,12 +38,10 @@ FROM gitea/gitea:@version@ COPY custom/app.ini /data/gitea/conf/app.ini [...] -RUN apk --no-cache add asciidoctor freetype freetype-dev gcc g++ libpng libffi-dev py-pip python3-dev py3-pip py3-pyzmq +RUN apk --no-cache add asciidoctor freetype freetype-dev gcc g++ libpng libffi-dev pandoc python3-dev py3-pyzmq pipx # install any other package you need for your external renderers -RUN pip3 install --upgrade pip -RUN pip3 install -U setuptools -RUN pip3 install jupyter docutils +RUN pipx install jupyter docutils --include-deps # add above any other python package you may need to install ``` diff --git a/docs/content/administration/external-renderers.zh-cn.md b/docs/content/administration/external-renderers.zh-cn.md index fdf7315d7b..1e56d95a66 100644 --- a/docs/content/administration/external-renderers.zh-cn.md +++ b/docs/content/administration/external-renderers.zh-cn.md @@ -37,12 +37,10 @@ FROM gitea/gitea:@version@ COPY custom/app.ini /data/gitea/conf/app.ini [...] -RUN apk --no-cache add asciidoctor freetype freetype-dev gcc g++ libpng libffi-dev py-pip python3-dev py3-pip py3-pyzmq +RUN apk --no-cache add asciidoctor freetype freetype-dev gcc g++ libpng libffi-dev pandoc python3-dev py3-pyzmq pipx # 安装其他您需要的外部渲染器的软件包 -RUN pip3 install --upgrade pip -RUN pip3 install -U setuptools -RUN pip3 install jupyter docutils +RUN pipx install jupyter docutils --include-deps # 在上面添加您需要安装的任何其他 Python 软件包 ``` From 89cc5011716850eb30c9e34130c4b2ecd9829252 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Mon, 27 May 2024 22:53:48 +0800 Subject: [PATCH 364/370] Move documents under actions (#31110) Move secrets and badge under actions --- docs/content/usage/{ => actions}/badge.en-us.md | 4 +--- docs/content/usage/{ => actions}/secrets.en-us.md | 4 +--- docs/content/usage/{ => actions}/secrets.zh-cn.md | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-) rename docs/content/usage/{ => actions}/badge.en-us.md (96%) rename docs/content/usage/{ => actions}/secrets.en-us.md (96%) rename docs/content/usage/{ => actions}/secrets.zh-cn.md (96%) diff --git a/docs/content/usage/badge.en-us.md b/docs/content/usage/actions/badge.en-us.md similarity index 96% rename from docs/content/usage/badge.en-us.md rename to docs/content/usage/actions/badge.en-us.md index 212134e01c..de7a34f4e6 100644 --- a/docs/content/usage/badge.en-us.md +++ b/docs/content/usage/actions/badge.en-us.md @@ -5,11 +5,9 @@ slug: "badge" sidebar_position: 11 toc: false draft: false -aliases: - - /en-us/badge menu: sidebar: - parent: "usage" + parent: "actions" name: "Badge" sidebar_position: 11 identifier: "Badge" diff --git a/docs/content/usage/secrets.en-us.md b/docs/content/usage/actions/secrets.en-us.md similarity index 96% rename from docs/content/usage/secrets.en-us.md rename to docs/content/usage/actions/secrets.en-us.md index 8ad6746614..5bf1f1a1e8 100644 --- a/docs/content/usage/secrets.en-us.md +++ b/docs/content/usage/actions/secrets.en-us.md @@ -5,11 +5,9 @@ slug: "secrets" sidebar_position: 50 draft: false toc: false -aliases: - - /en-us/secrets menu: sidebar: - parent: "usage" + parent: "actions" name: "Secrets" sidebar_position: 50 identifier: "usage-secrets" diff --git a/docs/content/usage/secrets.zh-cn.md b/docs/content/usage/actions/secrets.zh-cn.md similarity index 96% rename from docs/content/usage/secrets.zh-cn.md rename to docs/content/usage/actions/secrets.zh-cn.md index 40e80dc785..939042f0a8 100644 --- a/docs/content/usage/secrets.zh-cn.md +++ b/docs/content/usage/actions/secrets.zh-cn.md @@ -5,11 +5,9 @@ slug: "secrets" sidebar_position: 50 draft: false toc: false -aliases: - - /zh-cn/secrets menu: sidebar: - parent: "usage" + parent: "actions" name: "密钥管理" sidebar_position: 50 identifier: "usage-secrets" From 1ed8e6aa5fad235506f211daa9dffd448d9d5ad4 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Mon, 27 May 2024 23:05:12 +0800 Subject: [PATCH 365/370] Update demo site location from try.gitea.io -> demo.gitea.com (#31054) --- .gitea/issue_template.md | 4 ++-- .github/ISSUE_TEMPLATE/bug-report.yaml | 4 ++-- .github/ISSUE_TEMPLATE/ui.bug-report.yaml | 2 +- CONTRIBUTING.md | 4 ++-- README.md | 6 +++--- README_ZH.md | 2 +- docs/README.md | 5 +---- docs/README_ZH.md | 6 +----- docs/content/development/api-usage.en-us.md | 2 +- docs/content/help/faq.en-us.md | 6 +++--- docs/content/help/faq.zh-cn.md | 6 +++--- docs/content/help/support.en-us.md | 6 +++--- docs/content/help/support.zh-cn.md | 6 +++--- docs/content/index.en-us.md | 2 +- docs/content/usage/authentication.en-us.md | 2 +- docs/content/usage/authentication.zh-cn.md | 2 +- docs/content/usage/issue-pull-request-templates.en-us.md | 2 +- 17 files changed, 30 insertions(+), 37 deletions(-) diff --git a/.gitea/issue_template.md b/.gitea/issue_template.md index 9ad186cca7..cf173a67ca 100644 --- a/.gitea/issue_template.md +++ b/.gitea/issue_template.md @@ -3,7 +3,7 @@ <!-- 1. Please speak English, this is the language all maintainers can speak and write. 2. Please ask questions or configuration/deploy problems on our Discord - server (https://discord.gg/gitea) or forum (https://discourse.gitea.io). + server (https://discord.gg/gitea) or forum (https://forum.gitea.com). 3. Please take a moment to check that your issue doesn't already exist. 4. Make sure it's not mentioned in the FAQ (https://docs.gitea.com/help/faq) 5. Please give all relevant information below for bug reports, because @@ -21,7 +21,7 @@ - [ ] MySQL - [ ] MSSQL - [ ] SQLite -- Can you reproduce the bug at https://try.gitea.io: +- Can you reproduce the bug at https://demo.gitea.com: - [ ] Yes (provide example URL) - [ ] No - Log gist: diff --git a/.github/ISSUE_TEMPLATE/bug-report.yaml b/.github/ISSUE_TEMPLATE/bug-report.yaml index 94c1bd0ab7..ed29bdb4e6 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yaml +++ b/.github/ISSUE_TEMPLATE/bug-report.yaml @@ -37,7 +37,7 @@ body: label: Can you reproduce the bug on the Gitea demo site? description: | If so, please provide a URL in the Description field - URL of Gitea demo: https://try.gitea.io + URL of Gitea demo: https://demo.gitea.com options: - "Yes" - "No" @@ -74,7 +74,7 @@ body: attributes: label: How are you running Gitea? description: | - Please include information on whether you built Gitea yourself, used one of our downloads, are using https://try.gitea.io or are using some other package + Please include information on whether you built Gitea yourself, used one of our downloads, are using https://demo.gitea.com or are using some other package Please also tell us how you are running Gitea, e.g. if it is being run from docker, a command-line, systemd etc. If you are using a package or systemd tell us what distribution you are using validations: diff --git a/.github/ISSUE_TEMPLATE/ui.bug-report.yaml b/.github/ISSUE_TEMPLATE/ui.bug-report.yaml index 387aee897b..1560879674 100644 --- a/.github/ISSUE_TEMPLATE/ui.bug-report.yaml +++ b/.github/ISSUE_TEMPLATE/ui.bug-report.yaml @@ -46,7 +46,7 @@ body: label: Can you reproduce the bug on the Gitea demo site? description: | If so, please provide a URL in the Description field - URL of Gitea demo: https://try.gitea.io + URL of Gitea demo: https://demo.gitea.com options: - "Yes" - "No" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5d20bc2589..04c06ffd14 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -77,7 +77,7 @@ If your issue has not been reported yet, [open an issue](https://github.com/go-g and answer the questions so we can understand and reproduce the problematic behavior. \ Please write clear and concise instructions so that we can reproduce the behavior — even if it seems obvious. \ The more detailed and specific you are, the faster we can fix the issue. \ -It is really helpful if you can reproduce your problem on a site running on the latest commits, i.e. <https://try.gitea.io>, as perhaps your problem has already been fixed on a current version. \ +It is really helpful if you can reproduce your problem on a site running on the latest commits, i.e. <https://demo.gitea.com>, as perhaps your problem has already been fixed on a current version. \ Please follow the guidelines described in [How to Report Bugs Effectively](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html) for your report. Please be kind, remember that Gitea comes at no cost to you, and you're getting free help. @@ -362,7 +362,7 @@ If you add a new feature or change an existing aspect of Gitea, the documentatio ## API v1 -The API is documented by [swagger](http://try.gitea.io/api/swagger) and is based on [the GitHub API](https://docs.github.com/en/rest). +The API is documented by [swagger](https://gitea.com/api/swagger) and is based on [the GitHub API](https://docs.github.com/en/rest). ### GitHub API compatibility diff --git a/README.md b/README.md index f579449174..fd96f9efbd 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ This project has been [forked](https://blog.gitea.com/welcome-to-gitea/) from [Gogs](https://gogs.io) since November of 2016, but a lot has changed. -For online demonstrations, you can visit [try.gitea.io](https://try.gitea.io). +For online demonstrations, you can visit [demo.gitea.com](https://demo.gitea.com). For accessing free Gitea service (with a limited number of repositories), you can visit [gitea.com](https://gitea.com/user/login). @@ -56,7 +56,7 @@ More info: https://docs.gitea.com/installation/install-from-source ./gitea web > [!NOTE] -> If you're interested in using our APIs, we have experimental support with [documentation](https://try.gitea.io/api/swagger). +> If you're interested in using our APIs, we have experimental support with [documentation](https://docs.gitea.com/api). ## Contributing @@ -80,7 +80,7 @@ https://docs.gitea.com/contributing/localization ## Further information For more information and instructions about how to install Gitea, please look at our [documentation](https://docs.gitea.com/). -If you have questions that are not covered by the documentation, you can get in contact with us on our [Discord server](https://discord.gg/Gitea) or create a post in the [discourse forum](https://discourse.gitea.io/). +If you have questions that are not covered by the documentation, you can get in contact with us on our [Discord server](https://discord.gg/Gitea) or create a post in the [discourse forum](https://forum.gitea.com/). We maintain a list of Gitea-related projects at [gitea/awesome-gitea](https://gitea.com/gitea/awesome-gitea). diff --git a/README_ZH.md b/README_ZH.md index 726c4273a6..7aa7900a47 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -18,7 +18,7 @@ Gitea 的首要目标是创建一个极易安装,运行非常快速,安装和使用体验良好的自建 Git 服务。我们采用 Go 作为后端语言,这使我们只要生成一个可执行程序即可。并且他还支持跨平台,支持 Linux, macOS 和 Windows 以及各种架构,除了 x86,amd64,还包括 ARM 和 PowerPC。 -如果你想试用在线演示,请访问 [try.gitea.io](https://try.gitea.io/)。 +如果你想试用在线演示和报告问题,请访问 [demo.gitea.com](https://demo.gitea.com/)。 如果你想使用免费的 Gitea 服务(有仓库数量限制),请访问 [gitea.com](https://gitea.com/user/login)。 diff --git a/docs/README.md b/docs/README.md index d9aa3b80b8..38958525ba 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,8 +1,5 @@ # Gitea: Docs -[](https://discord.gg/Gitea) -[](http://microbadger.com/images/gitea/docs "Get your own image badge on microbadger.com") - These docs are ingested by our [docs repo](https://gitea.com/gitea/gitea-docusaurus). ## Authors @@ -18,5 +15,5 @@ for the full license text. ## Copyright ``` -Copyright (c) 2016 The Gitea Authors <https://gitea.io> +Copyright (c) 2016 The Gitea Authors ``` diff --git a/docs/README_ZH.md b/docs/README_ZH.md index 7d9003a8ab..deff4b5fc7 100644 --- a/docs/README_ZH.md +++ b/docs/README_ZH.md @@ -1,9 +1,5 @@ # Gitea: 文档 -[](http://drone.gitea.io/go-gitea/docs) -[](https://discord.gg/Gitea) -[](http://microbadger.com/images/gitea/docs "Get your own image badge on microbadger.com") - https://gitea.com/gitea/gitea-docusaurus ## 关于我们 @@ -18,5 +14,5 @@ https://gitea.com/gitea/gitea-docusaurus ## 版权声明 ``` -Copyright (c) 2016 The Gitea Authors <https://gitea.io> +Copyright (c) 2016 The Gitea Authors ``` diff --git a/docs/content/development/api-usage.en-us.md b/docs/content/development/api-usage.en-us.md index 94dac70b88..4fe376b11b 100644 --- a/docs/content/development/api-usage.en-us.md +++ b/docs/content/development/api-usage.en-us.md @@ -117,7 +117,7 @@ curl -v "http://localhost/api/v1/repos/search?limit=1" API Reference guide is auto-generated by swagger and available on: `https://gitea.your.host/api/swagger` or on the -[Gitea demo instance](https://try.gitea.io/api/swagger) +[Gitea instance](https://gitea.com/api/swagger) The OpenAPI document is at: `https://gitea.your.host/swagger.v1.json` diff --git a/docs/content/help/faq.en-us.md b/docs/content/help/faq.en-us.md index ba39ec83b0..e94f342198 100644 --- a/docs/content/help/faq.en-us.md +++ b/docs/content/help/faq.en-us.md @@ -45,7 +45,7 @@ To migrate from GitHub to Gitea, you can use Gitea's built-in migration form. In order to migrate items such as issues, pull requests, etc. you will need to input at least your username. -[Example (requires login)](https://try.gitea.io/repo/migrate) +[Example (requires login)](https://demo.gitea.com/repo/migrate) To migrate from GitLab to Gitea, you can use this non-affiliated tool: @@ -137,9 +137,9 @@ All Gitea instances have the built-in API and there is no way to disable it comp You can, however, disable showing its documentation by setting `ENABLE_SWAGGER` to `false` in the `api` section of your `app.ini`. For more information, refer to Gitea's [API docs](development/api-usage.md). -You can see the latest API (for example) on https://try.gitea.io/api/swagger +You can see the latest API (for example) on https://gitea.com/api/swagger -You can also see an example of the `swagger.json` file at https://try.gitea.io/swagger.v1.json +You can also see an example of the `swagger.json` file at https://gitea.com/swagger.v1.json ## Adjusting your server for public/private use diff --git a/docs/content/help/faq.zh-cn.md b/docs/content/help/faq.zh-cn.md index ef8a149ae2..d24dfe24a2 100644 --- a/docs/content/help/faq.zh-cn.md +++ b/docs/content/help/faq.zh-cn.md @@ -47,7 +47,7 @@ menu: 为了迁移诸如问题、拉取请求等项目,您需要至少输入您的用户名。 -[Example (requires login)](https://try.gitea.io/repo/migrate) +[Example (requires login)](https://demo.gitea.com/repo/migrate) 要从GitLab迁移到Gitea,您可以使用这个非关联的工具: @@ -141,9 +141,9 @@ Gitea不提供内置的Pages服务器。您需要一个专用的域名来提供 但是,您可以在app.ini的api部分将ENABLE_SWAGGER设置为false,以禁用其文档显示。 有关更多信息,请参阅Gitea的[API文档](development/api-usage.md)。 -您可以在上查看最新的API(例如)https://try.gitea.io/api/swagger +您可以在上查看最新的API(例如)https://gitea.com/api/swagger -您还可以在上查看`swagger.json`文件的示例 https://try.gitea.io/swagger.v1.json +您还可以在上查看`swagger.json`文件的示例 https://gitea.com/swagger.v1.json ## 调整服务器用于公共/私有使用 diff --git a/docs/content/help/support.en-us.md b/docs/content/help/support.en-us.md index db735b8124..bc8a8e3fd6 100644 --- a/docs/content/help/support.en-us.md +++ b/docs/content/help/support.en-us.md @@ -19,11 +19,11 @@ menu: - [Paid Commercial Support](https://about.gitea.com/) - [Discord](https://discord.gg/Gitea) -- [Discourse Forum](https://discourse.gitea.io/) +- [Forum](https://forum.gitea.com/) - [Matrix](https://matrix.to/#/#gitea-space:matrix.org) - NOTE: Most of the Matrix channels are bridged with their counterpart in Discord and may experience some degree of flakiness with the bridge process. - Chinese Support - - [Discourse Chinese Category](https://discourse.gitea.io/c/5-category/5) + - [Discourse Chinese Category](https://forum.gitea.com/c/5-category/5) - QQ Group 328432459 # Bug Report @@ -39,7 +39,7 @@ If you found a bug, please [create an issue on GitHub](https://github.com/go-git - When using systemd, use `journalctl --lines 1000 --unit gitea` to collect logs. - When using docker, use `docker logs --tail 1000 <gitea-container>` to collect logs. 4. Reproducible steps so that others could reproduce and understand the problem more quickly and easily. - - [try.gitea.io](https://try.gitea.io) could be used to reproduce the problem. + - [demo.gitea.com](https://demo.gitea.com) could be used to reproduce the problem. 5. If you encounter slow/hanging/deadlock problems, please report the stacktrace when the problem occurs. Go to the "Site Admin" -> "Monitoring" -> "Stacktrace" -> "Download diagnosis report". diff --git a/docs/content/help/support.zh-cn.md b/docs/content/help/support.zh-cn.md index 91b37c586c..6c69584c67 100644 --- a/docs/content/help/support.zh-cn.md +++ b/docs/content/help/support.zh-cn.md @@ -19,11 +19,11 @@ menu: - [付费商业支持](https://about.gitea.com/) - [Discord](https://discord.gg/Gitea) -- [Discourse 论坛](https://discourse.gitea.io/) +- [论坛](https://forum.gitea.com/) - [Matrix](https://matrix.to/#/#gitea-space:matrix.org) - 注意:大多数 Matrix 频道都与 Discord 中的对应频道桥接,可能在桥接过程中会出现一定程度的不稳定性。 - 中文支持 - - [Discourse 中文分类](https://discourse.gitea.io/c/5-category/5) + - [Discourse 中文分类](https://forum.gitea.com/c/5-category/5) - QQ 群 328432459 # Bug 报告 @@ -39,7 +39,7 @@ menu: - 在使用 systemd 时,使用 `journalctl --lines 1000 --unit gitea` 收集日志。 - 在使用 Docker 时,使用 `docker logs --tail 1000 <gitea-container>` 收集日志。 4. 可重现的步骤,以便他人能够更快速、更容易地重现和理解问题。 - - [try.gitea.io](https://try.gitea.io) 可用于重现问题。 + - [demo.gitea.com](https://demo.gitea.com) 可用于重现问题。 5. 如果遇到慢速/挂起/死锁等问题,请在出现问题时报告堆栈跟踪。 转到 "Site Admin" -> "Monitoring" -> "Stacktrace" -> "Download diagnosis report"。 diff --git a/docs/content/index.en-us.md b/docs/content/index.en-us.md index f9e6df8c1e..dc2eb1472a 100644 --- a/docs/content/index.en-us.md +++ b/docs/content/index.en-us.md @@ -21,7 +21,7 @@ up a self-hosted Git service. With Go, this can be done platform-independently across **all platforms** which Go supports, including Linux, macOS, and Windows, on x86, amd64, ARM and PowerPC architectures. -You can try it out using [the online demo](https://try.gitea.io/). +You can try it out using [the online demo](https://demo.gitea.com). ## Features diff --git a/docs/content/usage/authentication.en-us.md b/docs/content/usage/authentication.en-us.md index adc936dfbe..963f03a095 100644 --- a/docs/content/usage/authentication.en-us.md +++ b/docs/content/usage/authentication.en-us.md @@ -236,7 +236,7 @@ configure this, set the fields below: - Restrict what domains can log in if using a public SMTP host or SMTP host with multiple domains. - - Example: `gitea.io,mydomain.com,mydomain2.com` + - Example: `gitea.com,mydomain.com,mydomain2.com` - Force SMTPS diff --git a/docs/content/usage/authentication.zh-cn.md b/docs/content/usage/authentication.zh-cn.md index d1cfeeb800..00a24531d9 100644 --- a/docs/content/usage/authentication.zh-cn.md +++ b/docs/content/usage/authentication.zh-cn.md @@ -194,7 +194,7 @@ PAM提供了一种机制,通过对用户进行PAM认证来自动将其添加 - 如果使用公共 SMTP 主机或有多个域的 SMTP 主机,限制哪些域可以登录 限制哪些域可以登录。 - - 示例: `gitea.io,mydomain.com,mydomain2.com` + - 示例: `gitea.com,mydomain.com,mydomain2.com` - 强制使用 SMTPS - 默认情况下将使用SMTPS连接到端口465.如果您希望将smtp用于其他端口,自行设置 diff --git a/docs/content/usage/issue-pull-request-templates.en-us.md b/docs/content/usage/issue-pull-request-templates.en-us.md index e203c0d379..5220e0c7a0 100644 --- a/docs/content/usage/issue-pull-request-templates.en-us.md +++ b/docs/content/usage/issue-pull-request-templates.en-us.md @@ -308,7 +308,7 @@ This is a example for a issue config file blank_issues_enabled: true contact_links: - name: Gitea - url: https://gitea.io + url: https://gitea.com about: Visit the Gitea Website ``` From aa92b13164e84c26be91153b6022220ce0a27720 Mon Sep 17 00:00:00 2001 From: metiftikci <metiftikci@hotmail.com> Date: Mon, 27 May 2024 18:34:18 +0300 Subject: [PATCH 366/370] Prevent simultaneous editing of comments and issues (#31053) fixes #22907 Tested: - [x] issue content edit - [x] issue content change tasklist - [x] pull request content edit - [x] pull request change tasklist  --- models/issues/comment.go | 13 +++- models/issues/issue.go | 3 + models/issues/issue_update.go | 11 +++- models/migrations/migrations.go | 4 ++ models/migrations/v1_23/v299.go | 18 +++++ options/locale/locale_en-US.ini | 4 ++ routers/api/v1/repo/issue.go | 7 +- routers/api/v1/repo/issue_attachment.go | 2 +- routers/api/v1/repo/issue_comment.go | 2 +- .../api/v1/repo/issue_comment_attachment.go | 2 +- routers/api/v1/repo/pull.go | 7 +- routers/web/repo/issue.go | 23 +++++-- services/issue/comments.go | 4 +- services/issue/content.go | 4 +- templates/repo/diff/comments.tmpl | 2 +- templates/repo/issue/view_content.tmpl | 2 +- .../repo/issue/view_content/comments.tmpl | 4 +- .../repo/issue/view_content/conversation.tmpl | 2 +- tests/integration/issue_test.go | 66 +++++++++++++++++++ web_src/js/features/repo-issue-edit.js | 7 ++ web_src/js/markup/tasklist.js | 12 +++- 21 files changed, 172 insertions(+), 27 deletions(-) create mode 100644 models/migrations/v1_23/v299.go diff --git a/models/issues/comment.go b/models/issues/comment.go index 336bdde58e..c6c5dc2432 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -52,6 +52,8 @@ func (err ErrCommentNotExist) Unwrap() error { return util.ErrNotExist } +var ErrCommentAlreadyChanged = util.NewInvalidArgumentErrorf("the comment is already changed") + // CommentType defines whether a comment is just a simple comment, an action (like close) or a reference. type CommentType int @@ -262,6 +264,7 @@ type Comment struct { Line int64 // - previous line / + proposed line TreePath string Content string `xorm:"LONGTEXT"` + ContentVersion int `xorm:"NOT NULL DEFAULT 0"` RenderedContent template.HTML `xorm:"-"` // Path represents the 4 lines of code cemented by this comment @@ -1111,7 +1114,7 @@ func UpdateCommentInvalidate(ctx context.Context, c *Comment) error { } // UpdateComment updates information of comment. -func UpdateComment(ctx context.Context, c *Comment, doer *user_model.User) error { +func UpdateComment(ctx context.Context, c *Comment, contentVersion int, doer *user_model.User) error { ctx, committer, err := db.TxContext(ctx) if err != nil { return err @@ -1119,9 +1122,15 @@ func UpdateComment(ctx context.Context, c *Comment, doer *user_model.User) error defer committer.Close() sess := db.GetEngine(ctx) - if _, err := sess.ID(c.ID).AllCols().Update(c); err != nil { + c.ContentVersion = contentVersion + 1 + + affected, err := sess.ID(c.ID).AllCols().Where("content_version = ?", contentVersion).Update(c) + if err != nil { return err } + if affected == 0 { + return ErrCommentAlreadyChanged + } if err := c.LoadIssue(ctx); err != nil { return err } diff --git a/models/issues/issue.go b/models/issues/issue.go index 87c1c86eb1..aad855522d 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -94,6 +94,8 @@ func (err ErrIssueWasClosed) Error() string { return fmt.Sprintf("Issue [%d] %d was already closed", err.ID, err.Index) } +var ErrIssueAlreadyChanged = util.NewInvalidArgumentErrorf("the issue is already changed") + // Issue represents an issue or pull request of repository. type Issue struct { ID int64 `xorm:"pk autoincr"` @@ -107,6 +109,7 @@ type Issue struct { Title string `xorm:"name"` Content string `xorm:"LONGTEXT"` RenderedContent template.HTML `xorm:"-"` + ContentVersion int `xorm:"NOT NULL DEFAULT 0"` Labels []*Label `xorm:"-"` MilestoneID int64 `xorm:"INDEX"` Milestone *Milestone `xorm:"-"` diff --git a/models/issues/issue_update.go b/models/issues/issue_update.go index 147b7eb3b9..31d76be5e0 100644 --- a/models/issues/issue_update.go +++ b/models/issues/issue_update.go @@ -235,7 +235,7 @@ func UpdateIssueAttachments(ctx context.Context, issueID int64, uuids []string) } // ChangeIssueContent changes issue content, as the given user. -func ChangeIssueContent(ctx context.Context, issue *Issue, doer *user_model.User, content string) (err error) { +func ChangeIssueContent(ctx context.Context, issue *Issue, doer *user_model.User, content string, contentVersion int) (err error) { ctx, committer, err := db.TxContext(ctx) if err != nil { return err @@ -254,9 +254,14 @@ func ChangeIssueContent(ctx context.Context, issue *Issue, doer *user_model.User } issue.Content = content + issue.ContentVersion = contentVersion + 1 - if err = UpdateIssueCols(ctx, issue, "content"); err != nil { - return fmt.Errorf("UpdateIssueCols: %w", err) + affected, err := db.GetEngine(ctx).ID(issue.ID).Cols("content", "content_version").Where("content_version = ?", contentVersion).Update(issue) + if err != nil { + return err + } + if affected == 0 { + return ErrIssueAlreadyChanged } if err = SaveIssueContentHistory(ctx, doer.ID, issue.ID, 0, diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 4501585250..08882fb119 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -21,6 +21,7 @@ import ( "code.gitea.io/gitea/models/migrations/v1_20" "code.gitea.io/gitea/models/migrations/v1_21" "code.gitea.io/gitea/models/migrations/v1_22" + "code.gitea.io/gitea/models/migrations/v1_23" "code.gitea.io/gitea/models/migrations/v1_6" "code.gitea.io/gitea/models/migrations/v1_7" "code.gitea.io/gitea/models/migrations/v1_8" @@ -587,6 +588,9 @@ var migrations = []Migration{ NewMigration("Drop wrongly created table o_auth2_application", v1_22.DropWronglyCreatedTable), // Gitea 1.22.0-rc1 ends at 299 + + // v299 -> v300 + NewMigration("Add content version to issue and comment table", v1_23.AddContentVersionToIssueAndComment), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v1_23/v299.go b/models/migrations/v1_23/v299.go new file mode 100644 index 0000000000..f6db960c3b --- /dev/null +++ b/models/migrations/v1_23/v299.go @@ -0,0 +1,18 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_23 //nolint + +import "xorm.io/xorm" + +func AddContentVersionToIssueAndComment(x *xorm.Engine) error { + type Issue struct { + ContentVersion int `xorm:"NOT NULL DEFAULT 0"` + } + + type Comment struct { + ContentVersion int `xorm:"NOT NULL DEFAULT 0"` + } + + return x.Sync(new(Comment), new(Issue)) +} diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index fd47974fe9..772b11c2ba 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1443,6 +1443,7 @@ issues.new.clear_assignees = Clear assignees issues.new.no_assignees = No Assignees issues.new.no_reviewers = No reviewers issues.new.blocked_user = Cannot create issue because you are blocked by the repository owner. +issues.edit.already_changed = Unable to save changes to the issue. It appears the content has already been changed by another user. Please refresh the page and try editing again to avoid overwriting their changes issues.edit.blocked_user = Cannot edit content because you are blocked by the poster or repository owner. issues.choose.get_started = Get Started issues.choose.open_external_link = Open @@ -1758,6 +1759,7 @@ compare.compare_head = compare pulls.desc = Enable pull requests and code reviews. pulls.new = New Pull Request pulls.new.blocked_user = Cannot create pull request because you are blocked by the repository owner. +pulls.edit.already_changed = Unable to save changes to the pull request. It appears the content has already been changed by another user. Please refresh the page and try editing again to avoid overwriting their changes pulls.view = View Pull Request pulls.compare_changes = New Pull Request pulls.allow_edits_from_maintainers = Allow edits from maintainers @@ -1903,6 +1905,8 @@ pulls.recently_pushed_new_branches = You pushed on branch <strong>%[1]s</strong> pull.deleted_branch = (deleted):%s +comments.edit.already_changed = Unable to save changes to the comment. It appears the content has already been changed by another user. Please refresh the page and try editing again to avoid overwriting their changes + milestones.new = New Milestone milestones.closed = Closed %s milestones.update_ago = Updated %s diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index b91fbc33bf..ddfc36f17d 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -810,8 +810,13 @@ func EditIssue(ctx *context.APIContext) { } } if form.Body != nil { - err = issue_service.ChangeContent(ctx, issue, ctx.Doer, *form.Body) + err = issue_service.ChangeContent(ctx, issue, ctx.Doer, *form.Body, issue.ContentVersion) if err != nil { + if errors.Is(err, issues_model.ErrIssueAlreadyChanged) { + ctx.Error(http.StatusBadRequest, "ChangeContent", err) + return + } + ctx.Error(http.StatusInternalServerError, "ChangeContent", err) return } diff --git a/routers/api/v1/repo/issue_attachment.go b/routers/api/v1/repo/issue_attachment.go index f5a28e6fa6..ef846a43a3 100644 --- a/routers/api/v1/repo/issue_attachment.go +++ b/routers/api/v1/repo/issue_attachment.go @@ -198,7 +198,7 @@ func CreateIssueAttachment(ctx *context.APIContext) { issue.Attachments = append(issue.Attachments, attachment) - if err := issue_service.ChangeContent(ctx, issue, ctx.Doer, issue.Content); err != nil { + if err := issue_service.ChangeContent(ctx, issue, ctx.Doer, issue.Content, issue.ContentVersion); err != nil { ctx.Error(http.StatusInternalServerError, "ChangeContent", err) return } diff --git a/routers/api/v1/repo/issue_comment.go b/routers/api/v1/repo/issue_comment.go index 070571ba62..910cc1ce74 100644 --- a/routers/api/v1/repo/issue_comment.go +++ b/routers/api/v1/repo/issue_comment.go @@ -611,7 +611,7 @@ func editIssueComment(ctx *context.APIContext, form api.EditIssueCommentOption) oldContent := comment.Content comment.Content = form.Body - if err := issue_service.UpdateComment(ctx, comment, ctx.Doer, oldContent); err != nil { + if err := issue_service.UpdateComment(ctx, comment, comment.ContentVersion, ctx.Doer, oldContent); err != nil { if errors.Is(err, user_model.ErrBlockedUser) { ctx.Error(http.StatusForbidden, "UpdateComment", err) } else { diff --git a/routers/api/v1/repo/issue_comment_attachment.go b/routers/api/v1/repo/issue_comment_attachment.go index 77aa7f0400..1ec758ec2c 100644 --- a/routers/api/v1/repo/issue_comment_attachment.go +++ b/routers/api/v1/repo/issue_comment_attachment.go @@ -210,7 +210,7 @@ func CreateIssueCommentAttachment(ctx *context.APIContext) { return } - if err = issue_service.UpdateComment(ctx, comment, ctx.Doer, comment.Content); err != nil { + if err = issue_service.UpdateComment(ctx, comment, comment.ContentVersion, ctx.Doer, comment.Content); err != nil { if errors.Is(err, user_model.ErrBlockedUser) { ctx.Error(http.StatusForbidden, "UpdateComment", err) } else { diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index 38a32a73c7..a9aa5c4d8e 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -610,8 +610,13 @@ func EditPullRequest(ctx *context.APIContext) { } } if form.Body != nil { - err = issue_service.ChangeContent(ctx, issue, ctx.Doer, *form.Body) + err = issue_service.ChangeContent(ctx, issue, ctx.Doer, *form.Body, issue.ContentVersion) if err != nil { + if errors.Is(err, issues_model.ErrIssueAlreadyChanged) { + ctx.Error(http.StatusBadRequest, "ChangeContent", err) + return + } + ctx.Error(http.StatusInternalServerError, "ChangeContent", err) return } diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 465dafefd3..ce459f23b9 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -2247,9 +2247,15 @@ func UpdateIssueContent(ctx *context.Context) { return } - if err := issue_service.ChangeContent(ctx, issue, ctx.Doer, ctx.Req.FormValue("content")); err != nil { + if err := issue_service.ChangeContent(ctx, issue, ctx.Doer, ctx.Req.FormValue("content"), ctx.FormInt("content_version")); err != nil { if errors.Is(err, user_model.ErrBlockedUser) { ctx.JSONError(ctx.Tr("repo.issues.edit.blocked_user")) + } else if errors.Is(err, issues_model.ErrIssueAlreadyChanged) { + if issue.IsPull { + ctx.JSONError(ctx.Tr("repo.pulls.edit.already_changed")) + } else { + ctx.JSONError(ctx.Tr("repo.issues.edit.already_changed")) + } } else { ctx.ServerError("ChangeContent", err) } @@ -2278,8 +2284,9 @@ func UpdateIssueContent(ctx *context.Context) { } ctx.JSON(http.StatusOK, map[string]any{ - "content": content, - "attachments": attachmentsHTML(ctx, issue.Attachments, issue.Content), + "content": content, + "contentVersion": issue.ContentVersion, + "attachments": attachmentsHTML(ctx, issue.Attachments, issue.Content), }) } @@ -3153,12 +3160,15 @@ func UpdateCommentContent(ctx *context.Context) { oldContent := comment.Content newContent := ctx.FormString("content") + contentVersion := ctx.FormInt("content_version") // allow to save empty content comment.Content = newContent - if err = issue_service.UpdateComment(ctx, comment, ctx.Doer, oldContent); err != nil { + if err = issue_service.UpdateComment(ctx, comment, contentVersion, ctx.Doer, oldContent); err != nil { if errors.Is(err, user_model.ErrBlockedUser) { ctx.JSONError(ctx.Tr("repo.issues.comment.blocked_user")) + } else if errors.Is(err, issues_model.ErrCommentAlreadyChanged) { + ctx.JSONError(ctx.Tr("repo.comments.edit.already_changed")) } else { ctx.ServerError("UpdateComment", err) } @@ -3198,8 +3208,9 @@ func UpdateCommentContent(ctx *context.Context) { } ctx.JSON(http.StatusOK, map[string]any{ - "content": renderedContent, - "attachments": attachmentsHTML(ctx, comment.Attachments, comment.Content), + "content": renderedContent, + "contentVersion": comment.ContentVersion, + "attachments": attachmentsHTML(ctx, comment.Attachments, comment.Content), }) } diff --git a/services/issue/comments.go b/services/issue/comments.go index d68623aff6..33b5702a00 100644 --- a/services/issue/comments.go +++ b/services/issue/comments.go @@ -82,7 +82,7 @@ func CreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_m } // UpdateComment updates information of comment. -func UpdateComment(ctx context.Context, c *issues_model.Comment, doer *user_model.User, oldContent string) error { +func UpdateComment(ctx context.Context, c *issues_model.Comment, contentVersion int, doer *user_model.User, oldContent string) error { if err := c.LoadIssue(ctx); err != nil { return err } @@ -110,7 +110,7 @@ func UpdateComment(ctx context.Context, c *issues_model.Comment, doer *user_mode } } - if err := issues_model.UpdateComment(ctx, c, doer); err != nil { + if err := issues_model.UpdateComment(ctx, c, contentVersion, doer); err != nil { return err } diff --git a/services/issue/content.go b/services/issue/content.go index 2f9bee806a..6894182909 100644 --- a/services/issue/content.go +++ b/services/issue/content.go @@ -13,7 +13,7 @@ import ( ) // ChangeContent changes issue content, as the given user. -func ChangeContent(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, content string) error { +func ChangeContent(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, content string, contentVersion int) error { if err := issue.LoadRepo(ctx); err != nil { return err } @@ -26,7 +26,7 @@ func ChangeContent(ctx context.Context, issue *issues_model.Issue, doer *user_mo oldContent := issue.Content - if err := issues_model.ChangeIssueContent(ctx, issue, doer, content); err != nil { + if err := issues_model.ChangeIssueContent(ctx, issue, doer, content, contentVersion); err != nil { return err } diff --git a/templates/repo/diff/comments.tmpl b/templates/repo/diff/comments.tmpl index c7f4337182..90d6a511bf 100644 --- a/templates/repo/diff/comments.tmpl +++ b/templates/repo/diff/comments.tmpl @@ -61,7 +61,7 @@ {{end}} </div> <div id="issuecomment-{{.ID}}-raw" class="raw-content tw-hidden">{{.Content}}</div> - <div class="edit-content-zone tw-hidden" data-update-url="{{$.root.RepoLink}}/comments/{{.ID}}" data-context="{{$.root.RepoLink}}" data-attachment-url="{{$.root.RepoLink}}/comments/{{.ID}}/attachments"></div> + <div class="edit-content-zone tw-hidden" data-update-url="{{$.root.RepoLink}}/comments/{{.ID}}" data-content-version="{{.ContentVersion}}" data-context="{{$.root.RepoLink}}" data-attachment-url="{{$.root.RepoLink}}/comments/{{.ID}}/attachments"></div> {{if .Attachments}} {{template "repo/issue/view_content/attachments" dict "Attachments" .Attachments "RenderedContent" .RenderedContent}} {{end}} diff --git a/templates/repo/issue/view_content.tmpl b/templates/repo/issue/view_content.tmpl index d40134ed08..3088c60510 100644 --- a/templates/repo/issue/view_content.tmpl +++ b/templates/repo/issue/view_content.tmpl @@ -60,7 +60,7 @@ {{end}} </div> <div id="issue-{{.Issue.ID}}-raw" class="raw-content tw-hidden">{{.Issue.Content}}</div> - <div class="edit-content-zone tw-hidden" data-update-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/content" data-context="{{.RepoLink}}" data-attachment-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/attachments" data-view-attachment-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/view-attachments"></div> + <div class="edit-content-zone tw-hidden" data-update-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/content" data-content-version="{{.Issue.ContentVersion}}" data-context="{{.RepoLink}}" data-attachment-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/attachments" data-view-attachment-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/view-attachments"></div> {{if .Issue.Attachments}} {{template "repo/issue/view_content/attachments" dict "Attachments" .Issue.Attachments "RenderedContent" .Issue.RenderedContent}} {{end}} diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index acc04e4c61..3da2f3815e 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -67,7 +67,7 @@ {{end}} </div> <div id="issuecomment-{{.ID}}-raw" class="raw-content tw-hidden">{{.Content}}</div> - <div class="edit-content-zone tw-hidden" data-update-url="{{$.RepoLink}}/comments/{{.ID}}" data-context="{{$.RepoLink}}" data-attachment-url="{{$.RepoLink}}/comments/{{.ID}}/attachments"></div> + <div class="edit-content-zone tw-hidden" data-update-url="{{$.RepoLink}}/comments/{{.ID}}" data-content-version="{{.ContentVersion}}" data-context="{{$.RepoLink}}" data-attachment-url="{{$.RepoLink}}/comments/{{.ID}}/attachments"></div> {{if .Attachments}} {{template "repo/issue/view_content/attachments" dict "Attachments" .Attachments "RenderedContent" .RenderedContent}} {{end}} @@ -441,7 +441,7 @@ {{end}} </div> <div id="issuecomment-{{.ID}}-raw" class="raw-content tw-hidden">{{.Content}}</div> - <div class="edit-content-zone tw-hidden" data-update-url="{{$.RepoLink}}/comments/{{.ID}}" data-context="{{$.RepoLink}}" data-attachment-url="{{$.RepoLink}}/comments/{{.ID}}/attachments"></div> + <div class="edit-content-zone tw-hidden" data-update-url="{{$.RepoLink}}/comments/{{.ID}}" data-content-version="{{.ContentVersion}}" data-context="{{$.RepoLink}}" data-attachment-url="{{$.RepoLink}}/comments/{{.ID}}/attachments"></div> {{if .Attachments}} {{template "repo/issue/view_content/attachments" dict "Attachments" .Attachments "RenderedContent" .RenderedContent}} {{end}} diff --git a/templates/repo/issue/view_content/conversation.tmpl b/templates/repo/issue/view_content/conversation.tmpl index ac32a2db5d..43ec9d75c4 100644 --- a/templates/repo/issue/view_content/conversation.tmpl +++ b/templates/repo/issue/view_content/conversation.tmpl @@ -96,7 +96,7 @@ {{end}} </div> <div id="issuecomment-{{.ID}}-raw" class="raw-content tw-hidden">{{.Content}}</div> - <div class="edit-content-zone tw-hidden" data-update-url="{{$.RepoLink}}/comments/{{.ID}}" data-context="{{$.RepoLink}}" data-attachment-url="{{$.RepoLink}}/comments/{{.ID}}/attachments"></div> + <div class="edit-content-zone tw-hidden" data-update-url="{{$.RepoLink}}/comments/{{.ID}}" data-content-version="{{.ContentVersion}}" data-context="{{$.RepoLink}}" data-attachment-url="{{$.RepoLink}}/comments/{{.ID}}/attachments"></div> {{if .Attachments}} {{template "repo/issue/view_content/attachments" dict "Attachments" .Attachments "RenderedContent" .RenderedContent}} {{end}} diff --git a/tests/integration/issue_test.go b/tests/integration/issue_test.go index d74516d110..308b82d4b9 100644 --- a/tests/integration/issue_test.go +++ b/tests/integration/issue_test.go @@ -191,6 +191,34 @@ func TestNewIssue(t *testing.T) { testNewIssue(t, session, "user2", "repo1", "Title", "Description") } +func TestEditIssue(t *testing.T) { + defer tests.PrepareTestEnv(t)() + session := loginUser(t, "user2") + issueURL := testNewIssue(t, session, "user2", "repo1", "Title", "Description") + + req := NewRequestWithValues(t, "POST", fmt.Sprintf("%s/content", issueURL), map[string]string{ + "_csrf": GetCSRF(t, session, issueURL), + "content": "modified content", + "context": fmt.Sprintf("/%s/%s", "user2", "repo1"), + }) + session.MakeRequest(t, req, http.StatusOK) + + req = NewRequestWithValues(t, "POST", fmt.Sprintf("%s/content", issueURL), map[string]string{ + "_csrf": GetCSRF(t, session, issueURL), + "content": "modified content", + "context": fmt.Sprintf("/%s/%s", "user2", "repo1"), + }) + session.MakeRequest(t, req, http.StatusBadRequest) + + req = NewRequestWithValues(t, "POST", fmt.Sprintf("%s/content", issueURL), map[string]string{ + "_csrf": GetCSRF(t, session, issueURL), + "content": "modified content", + "content_version": "1", + "context": fmt.Sprintf("/%s/%s", "user2", "repo1"), + }) + session.MakeRequest(t, req, http.StatusOK) +} + func TestIssueCommentClose(t *testing.T) { defer tests.PrepareTestEnv(t)() session := loginUser(t, "user2") @@ -257,6 +285,44 @@ func TestIssueCommentUpdate(t *testing.T) { assert.Equal(t, modifiedContent, comment.Content) } +func TestIssueCommentUpdateSimultaneously(t *testing.T) { + defer tests.PrepareTestEnv(t)() + session := loginUser(t, "user2") + issueURL := testNewIssue(t, session, "user2", "repo1", "Title", "Description") + comment1 := "Test comment 1" + commentID := testIssueAddComment(t, session, issueURL, comment1, "") + + comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: commentID}) + assert.Equal(t, comment1, comment.Content) + + modifiedContent := comment.Content + "MODIFIED" + + req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/comments/%d", "user2", "repo1", commentID), map[string]string{ + "_csrf": GetCSRF(t, session, issueURL), + "content": modifiedContent, + }) + session.MakeRequest(t, req, http.StatusOK) + + modifiedContent = comment.Content + "2" + + req = NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/comments/%d", "user2", "repo1", commentID), map[string]string{ + "_csrf": GetCSRF(t, session, issueURL), + "content": modifiedContent, + }) + session.MakeRequest(t, req, http.StatusBadRequest) + + req = NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/comments/%d", "user2", "repo1", commentID), map[string]string{ + "_csrf": GetCSRF(t, session, issueURL), + "content": modifiedContent, + "content_version": "1", + }) + session.MakeRequest(t, req, http.StatusOK) + + comment = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: commentID}) + assert.Equal(t, modifiedContent, comment.Content) + assert.Equal(t, 2, comment.ContentVersion) +} + func TestIssueReaction(t *testing.T) { defer tests.PrepareTestEnv(t)() session := loginUser(t, "user2") diff --git a/web_src/js/features/repo-issue-edit.js b/web_src/js/features/repo-issue-edit.js index abf2d31221..9a8d737e01 100644 --- a/web_src/js/features/repo-issue-edit.js +++ b/web_src/js/features/repo-issue-edit.js @@ -3,6 +3,7 @@ import {handleReply} from './repo-issue.js'; import {getComboMarkdownEditor, initComboMarkdownEditor} from './comp/ComboMarkdownEditor.js'; import {createDropzone} from './dropzone.js'; import {GET, POST} from '../modules/fetch.js'; +import {showErrorToast} from '../modules/toast.js'; import {hideElem, showElem} from '../utils/dom.js'; import {attachRefIssueContextPopup} from './contextpopup.js'; import {initCommentContent, initMarkupContent} from '../markup/content.js'; @@ -124,11 +125,17 @@ async function onEditContent(event) { const params = new URLSearchParams({ content: comboMarkdownEditor.value(), context: editContentZone.getAttribute('data-context'), + content_version: editContentZone.getAttribute('data-content-version'), }); for (const fileInput of dropzoneInst?.element.querySelectorAll('.files [name=files]')) params.append('files[]', fileInput.value); const response = await POST(editContentZone.getAttribute('data-update-url'), {data: params}); const data = await response.json(); + if (response.status === 400) { + showErrorToast(data.errorMessage); + return; + } + editContentZone.setAttribute('data-content-version', data.contentVersion); if (!data.content) { renderContent.innerHTML = document.getElementById('no-content').innerHTML; rawContent.textContent = ''; diff --git a/web_src/js/markup/tasklist.js b/web_src/js/markup/tasklist.js index 00076bce58..a40b5e4abd 100644 --- a/web_src/js/markup/tasklist.js +++ b/web_src/js/markup/tasklist.js @@ -1,4 +1,5 @@ import {POST} from '../modules/fetch.js'; +import {showErrorToast} from '../modules/toast.js'; const preventListener = (e) => e.preventDefault(); @@ -54,13 +55,20 @@ export function initMarkupTasklist() { const editContentZone = container.querySelector('.edit-content-zone'); const updateUrl = editContentZone.getAttribute('data-update-url'); const context = editContentZone.getAttribute('data-context'); + const contentVersion = editContentZone.getAttribute('data-content-version'); const requestBody = new FormData(); requestBody.append('ignore_attachments', 'true'); requestBody.append('content', newContent); requestBody.append('context', context); - await POST(updateUrl, {data: requestBody}); - + requestBody.append('content_version', contentVersion); + const response = await POST(updateUrl, {data: requestBody}); + const data = await response.json(); + if (response.status === 400) { + showErrorToast(data.errorMessage); + return; + } + editContentZone.setAttribute('data-content-version', data.contentVersion); rawContent.textContent = newContent; } catch (err) { checkbox.checked = !checkbox.checked; From 0222f19f19675afcc0e38237618a712908e3852c Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Tue, 28 May 2024 00:26:53 +0000 Subject: [PATCH 367/370] [skip ci] Updated translations via Crowdin --- options/locale/locale_cs-CZ.ini | 5 ++--- options/locale/locale_de-DE.ini | 5 ++--- options/locale/locale_el-GR.ini | 5 ++--- options/locale/locale_es-ES.ini | 5 ++--- options/locale/locale_fa-IR.ini | 5 ++--- options/locale/locale_fi-FI.ini | 4 ++-- options/locale/locale_fr-FR.ini | 5 ++--- options/locale/locale_hu-HU.ini | 4 ++-- options/locale/locale_id-ID.ini | 1 + options/locale/locale_is-IS.ini | 4 ++-- options/locale/locale_it-IT.ini | 5 ++--- options/locale/locale_ja-JP.ini | 5 ++--- options/locale/locale_ko-KR.ini | 1 + options/locale/locale_lv-LV.ini | 5 ++--- options/locale/locale_nl-NL.ini | 5 ++--- options/locale/locale_pl-PL.ini | 4 ++-- options/locale/locale_pt-BR.ini | 5 ++--- options/locale/locale_pt-PT.ini | 5 ++--- options/locale/locale_ru-RU.ini | 5 ++--- options/locale/locale_si-LK.ini | 5 ++--- options/locale/locale_sk-SK.ini | 4 ++-- options/locale/locale_sv-SE.ini | 4 ++-- options/locale/locale_tr-TR.ini | 6 +++--- options/locale/locale_uk-UA.ini | 5 ++--- options/locale/locale_zh-CN.ini | 5 ++--- options/locale/locale_zh-HK.ini | 1 + options/locale/locale_zh-TW.ini | 5 ++--- 27 files changed, 52 insertions(+), 66 deletions(-) diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index 6314b62f66..0c61e5d042 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -1205,7 +1205,7 @@ branches=Větve tags=Značky issues=Úkoly pulls=Pull requesty -project_board=Projekty +projects=Projekty packages=Balíčky actions=Akce labels=Štítky @@ -1364,8 +1364,6 @@ commitstatus.success=Úspěch ext_issues=Přístup k externím úkolům ext_issues.desc=Odkaz na externí systém úkolů. -projects=Projekty -projects.desc=Spravovat úkoly a požadavky na natažení na projektových nástěnkách. projects.description=Popis (volitelné) projects.description_placeholder=Popis projects.create=Vytvořit projekt @@ -1887,6 +1885,7 @@ pulls.recently_pushed_new_branches=Nahráli jste větev <strong>%[1]s</strong> % pull.deleted_branch=(odstraněno):%s + milestones.new=Nový milník milestones.closed=Zavřen dne %s milestones.update_ago=Aktualizováno %s diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 5bca84ca08..8e1194cdd1 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -1206,7 +1206,7 @@ branches=Branches tags=Tags issues=Issues pulls=Pull-Requests -project_board=Projekte +projects=Projekte packages=Pakete actions=Actions labels=Label @@ -1366,8 +1366,6 @@ commitstatus.success=Erfolg ext_issues=Zugriff auf Externe Issues ext_issues.desc=Link zu externem Issuetracker. -projects=Projekte -projects.desc=Verwalte Issues und Pull-Requests in Projektboards. projects.description=Beschreibung (optional) projects.description_placeholder=Beschreibung projects.create=Projekt erstellen @@ -1891,6 +1889,7 @@ pulls.recently_pushed_new_branches=Du hast auf den Branch <strong>%[1]s</strong> pull.deleted_branch=(gelöscht):%s + milestones.new=Neuer Meilenstein milestones.closed=Geschlossen %s milestones.update_ago=%s aktualisiert diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini index 834d1d7d70..74262ff38d 100644 --- a/options/locale/locale_el-GR.ini +++ b/options/locale/locale_el-GR.ini @@ -1137,7 +1137,7 @@ branches=Κλάδοι tags=Ετικέτες issues=Ζητήματα pulls=Pull Requests -project_board=Έργα +projects=Έργα packages=Πακέτα actions=Δράσεις labels=Σήματα @@ -1292,8 +1292,6 @@ commitstatus.success=Επιτυχές ext_issues=Πρόσβαση στα Εξωτερικά Ζητήματα ext_issues.desc=Σύνδεση σε εξωτερικό εφαρμογή ζητημάτων. -projects=Έργα -projects.desc=Διαχείριση ζητημάτων και pulls στους πίνακες των έργων. projects.description=Περιγραφή (προαιρετικό) projects.description_placeholder=Περιγραφή projects.create=Δημιουργία Έργου @@ -1810,6 +1808,7 @@ pulls.recently_pushed_new_branches=Ωθήσατε στο κλάδο <strong>%[1] pull.deleted_branch=(διαγράφηκε):%s + milestones.new=Νέο Ορόσημο milestones.closed=Έκλεισε %s milestones.update_ago=Ενημερώθηκε %s diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index 3894e0e85b..66273eb79a 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -1130,7 +1130,7 @@ branches=Ramas tags=Etiquetas issues=Incidencias pulls=Pull Requests -project_board=Proyectos +projects=Proyectos packages=Paquetes actions=Acciones labels=Etiquetas @@ -1285,8 +1285,6 @@ commitstatus.success=Éxito ext_issues=Acceso a incidencias externas ext_issues.desc=Enlace a un gestor de incidencias externo. -projects=Proyectos -projects.desc=Gestionar problemas y pulls en los tablones del proyecto. projects.description=Descripción (opcional) projects.description_placeholder=Descripción projects.create=Crear Proyecto @@ -1796,6 +1794,7 @@ pulls.recently_pushed_new_branches=Has realizado push en la rama <strong>%[1]s</ pull.deleted_branch=(eliminado):%s + milestones.new=Nuevo hito milestones.closed=Cerrada %s milestones.update_ago=Actualizado %s diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini index d720ecf2f8..94e572f9b4 100644 --- a/options/locale/locale_fa-IR.ini +++ b/options/locale/locale_fa-IR.ini @@ -891,7 +891,7 @@ branches=شاخهها tags=برچسبها issues=مسائل pulls=تقاضاهای واکشی -project_board=پروژهها +projects=پروژهها labels=برچسبها org_labels_desc=برچسب های سطح سازمان که می توانند برای <strong>تمامی مخازن</strong> ذیل این سازمان استفاده شوند org_labels_desc_manage=مدیریت @@ -986,8 +986,6 @@ commitstatus.pending=در انتظار ext_issues.desc=پیوند به ردیاب خارجی برای موضوع. -projects=پروژهها -projects.desc=مدیریت مشکلات و درخواستهای درج در بورد پروژه. projects.description=توضیحات (دلخواه) projects.description_placeholder=توضیحات projects.create=ایجاد پروژه جدید @@ -1377,6 +1375,7 @@ pulls.reopened_at=`این درخواست pull را بازگشایی کرد <a id + milestones.new=نقطه عطف جدید milestones.closed=%s بسته شد milestones.no_due_date=بدون موعد مقرر diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini index f29ad8c6cd..d854e74e61 100644 --- a/options/locale/locale_fi-FI.ini +++ b/options/locale/locale_fi-FI.ini @@ -730,7 +730,7 @@ branches=Branchit tags=Tagit issues=Ongelmat pulls=Pull-pyynnöt -project_board=Projektit +projects=Projektit packages=Paketit labels=Tunnisteet @@ -792,7 +792,6 @@ commitstatus.error=Virhe commitstatus.pending=Odottaa -projects=Projektit projects.description_placeholder=Kuvaus projects.create=Luo projekti projects.title=Otsikko @@ -1002,6 +1001,7 @@ pulls.can_auto_merge_desc=Tämä pull-pyyntö voidaan yhdistää automaattisesti + milestones.new=Uusi merkkipaalu milestones.closed=Suljettu %s milestones.no_due_date=Ei määräpäivää diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index 556fab28e8..0def8f81d1 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -1149,7 +1149,7 @@ branches=Branches tags=Étiquettes issues=Tickets pulls=Demandes d'ajout -project_board=Projets +projects=Projets packages=Paquets actions=Actions labels=Labels @@ -1306,8 +1306,6 @@ commitstatus.success=Succès ext_issues=Accès aux tickets externes ext_issues.desc=Lien vers un gestionnaire de tickets externe. -projects=Projets -projects.desc=Gérer les tickets et les demandes d’ajouts dans les tableaux de projet. projects.description=Description (facultative) projects.description_placeholder=Description projects.create=Créer un projet @@ -1826,6 +1824,7 @@ pulls.recently_pushed_new_branches=Vous avez soumis sur la branche <strong>%[1]s pull.deleted_branch=(supprimé) : %s + milestones.new=Nouveau jalon milestones.closed=%s fermé milestones.update_ago=Actualisé %s diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini index 4e46227fea..06eb31f308 100644 --- a/options/locale/locale_hu-HU.ini +++ b/options/locale/locale_hu-HU.ini @@ -670,7 +670,7 @@ branches=Ágak tags=Címkék issues=Hibajegyek pulls=Egyesítési kérések -project_board=Projektek +projects=Projektek labels=Címkék org_labels_desc_manage=kezelés @@ -736,7 +736,6 @@ commitstatus.pending=Függőben ext_issues.desc=Külső hibakövető csatlakoztatás. -projects=Projektek projects.description_placeholder=Leírás projects.title=Cím projects.new=Új projekt @@ -949,6 +948,7 @@ pulls.status_checks_success=Minden ellenőrzés sikeres volt + milestones.new=Új mérföldkő milestones.closed=Lezárva: %s milestones.no_due_date=Nincs határidő diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini index fe3a6d0b08..a6bac362ab 100644 --- a/options/locale/locale_id-ID.ini +++ b/options/locale/locale_id-ID.ini @@ -763,6 +763,7 @@ pulls.can_auto_merge_desc=Permintaan tarik ini dapat digabung secara otomatis. + milestones.new=Milestone Baru milestones.closed=Tertutup %s milestones.no_due_date=Tidak ada jatuh tempo diff --git a/options/locale/locale_is-IS.ini b/options/locale/locale_is-IS.ini index f2fcfb7eda..f6becbf1c0 100644 --- a/options/locale/locale_is-IS.ini +++ b/options/locale/locale_is-IS.ini @@ -660,7 +660,7 @@ branches=Greinar tags=Merki issues=Vandamál pulls=Sameiningarbeiðnir -project_board=Verkefni +projects=Verkefni packages=Pakkar labels=Skýringar @@ -714,7 +714,6 @@ commitstatus.error=Villa commitstatus.pending=Í bið -projects=Verkefni projects.description=Lýsing (valfrjálst) projects.description_placeholder=Lýsing projects.create=Stofna Verkefni @@ -912,6 +911,7 @@ pulls.status_checks_details=Nánar + milestones.new=Nýtt tímamót milestones.closed=Lokaði %s milestones.no_due_date=Enginn eindagi diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index 0cecc0b7f3..a32ae01868 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -954,7 +954,7 @@ branches=Rami (Branch) tags=Tag issues=Problemi pulls=Pull Requests -project_board=Progetti +projects=Progetti packages=Pacchetti labels=Etichette org_labels_desc=Etichette a livello di organizzazione che possono essere utilizzate con <strong>tutti i repository</strong> sotto questa organizzazione @@ -1072,8 +1072,6 @@ commitstatus.pending=In sospeso ext_issues=Accesso ai Problemi Esterni ext_issues.desc=Collegamento al puntatore di una issue esterna. -projects=Progetti -projects.desc=Gestisci problemi e pull nelle schede di progetto. projects.description=Descrizione (opzionale) projects.description_placeholder=Descrizione projects.create=Crea un progetto @@ -1500,6 +1498,7 @@ pulls.delete.text=Vuoi davvero eliminare questo problema? (Questo rimuoverà per + milestones.new=Nuova Milestone milestones.closed=Chiuso %s milestones.no_due_date=Nessuna data di scadenza diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 66dedcbb51..07c1cbfe7e 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -1215,7 +1215,7 @@ branches=ブランチ tags=タグ issues=イシュー pulls=プルリクエスト -project_board=プロジェクト +projects=プロジェクト packages=パッケージ actions=Actions labels=ラベル @@ -1378,8 +1378,6 @@ commitstatus.success=成功 ext_issues=外部イシューへのアクセス ext_issues.desc=外部のイシュートラッカーへのリンク。 -projects=プロジェクト -projects.desc=プロジェクトボードでイシューとプルを管理します。 projects.description=説明 (オプション) projects.description_placeholder=説明 projects.create=プロジェクトを作成 @@ -1903,6 +1901,7 @@ pulls.recently_pushed_new_branches=%[2]s 、あなたはブランチ <strong>%[1 pull.deleted_branch=(削除済み):%s + milestones.new=新しいマイルストーン milestones.closed=%s にクローズ milestones.update_ago=%sに更新 diff --git a/options/locale/locale_ko-KR.ini b/options/locale/locale_ko-KR.ini index cf3188e9c0..054632e819 100644 --- a/options/locale/locale_ko-KR.ini +++ b/options/locale/locale_ko-KR.ini @@ -862,6 +862,7 @@ pulls.invalid_merge_option=이 풀 리퀘스트에서 설정한 머지 옵션을 + milestones.new=새로운 마일스톤 milestones.closed=닫힘 %s milestones.no_due_date=기한 없음 diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index bdfe3f8c9f..8f9766b082 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -1139,7 +1139,7 @@ branches=Atzari tags=Tagi issues=Problēmas pulls=Izmaiņu pieprasījumi -project_board=Projekti +projects=Projekti packages=Pakotnes actions=Darbības labels=Iezīmes @@ -1294,8 +1294,6 @@ commitstatus.success=Pabeigts ext_issues=Piekļuve ārējām problēmām ext_issues.desc=Saite uz ārējo problēmu sekotāju. -projects=Projekti -projects.desc=Pārvaldīt problēmu un izmaiņu pieprasījumu projektu dēļus. projects.description=Apraksts (neobligāts) projects.description_placeholder=Apraksts projects.create=Izveidot projektu @@ -1812,6 +1810,7 @@ pulls.recently_pushed_new_branches=Tu iesūtīji izmaiņas atzarā <strong>%[1]s pull.deleted_branch=(izdzēsts):%s + milestones.new=Jauns atskaites punkts milestones.closed=Aizvērts %s milestones.update_ago=Atjaunots %s diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini index f511bc5d23..adcbc6b66d 100644 --- a/options/locale/locale_nl-NL.ini +++ b/options/locale/locale_nl-NL.ini @@ -952,7 +952,7 @@ branches=Branches tags=Labels issues=Kwesties pulls=Pull-aanvragen -project_board=Projecten +projects=Projecten packages=Paketten labels=Labels org_labels_desc=Organisatielabel dat gebruikt kan worden met <strong>alle repositories</strong> onder deze organisatie @@ -1070,8 +1070,6 @@ commitstatus.pending=In behandeling ext_issues=Toegang tot Externe Issues ext_issues.desc=Koppelen aan een externe kwestie-tracker. -projects=Projecten -projects.desc=Beheer issues en pulls in projectborden. projects.description=Omschrijving (optioneel) projects.description_placeholder=Omschrijving projects.create=Project aanmaken @@ -1495,6 +1493,7 @@ pulls.delete.text=Weet je zeker dat je deze pull-verzoek wilt verwijderen? (Dit + milestones.new=Nieuwe mijlpaal milestones.closed=%s werd gesloten milestones.no_due_date=Geen vervaldatum diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini index b5a758514e..6fdec5183e 100644 --- a/options/locale/locale_pl-PL.ini +++ b/options/locale/locale_pl-PL.ini @@ -894,7 +894,7 @@ branches=Gałęzie tags=Tagi issues=Zgłoszenia pulls=Oczekujące zmiany -project_board=Projekty +projects=Projekty labels=Etykiety org_labels_desc=Etykiety organizacji, które mogą być używane z <strong>wszystkimi repozytoriami</strong> w tej organizacji org_labels_desc_manage=zarządzaj @@ -987,7 +987,6 @@ commitstatus.pending=Oczekująca ext_issues.desc=Link do zewnętrznego systemu śledzenia zgłoszeń. -projects=Projekty projects.description=Opis (opcjonalnie) projects.description_placeholder=Opis projects.create=Utwórz projekt @@ -1347,6 +1346,7 @@ pulls.reopened_at=`otworzył(-a) ponownie ten Pull Request <a id="%[1]s" href="# + milestones.new=Nowy kamień milowy milestones.closed=Zamknięto %s milestones.no_due_date=Nie ustalono terminu diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 4799727d98..222abc1681 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -1134,7 +1134,7 @@ branches=Branches tags=Tags issues=Issues pulls=Pull requests -project_board=Projetos +projects=Projetos packages=Pacotes actions=Ações labels=Etiquetas @@ -1290,8 +1290,6 @@ commitstatus.success=Sucesso ext_issues=Acesso a Issues Externos ext_issues.desc=Link para o issue tracker externo. -projects=Projetos -projects.desc=Gerencie issues e PRs nos quadros do projeto. projects.description=Descrição (opcional) projects.description_placeholder=Descrição projects.create=Criar Projeto @@ -1804,6 +1802,7 @@ pulls.recently_pushed_new_branches=Você fez push no branch <strong>%[1]s</stron pull.deleted_branch=(excluído):%s + milestones.new=Novo marco milestones.closed=Fechado %s milestones.update_ago=Atualizado há %s diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 15635b4beb..28f040e7cf 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -1215,7 +1215,7 @@ branches=Ramos tags=Etiquetas issues=Questões pulls=Pedidos de integração -project_board=Planeamentos +projects=Planeamentos packages=Pacotes actions=Operações labels=Rótulos @@ -1378,8 +1378,6 @@ commitstatus.success=Sucesso ext_issues=Acesso a questões externas ext_issues.desc=Ligação para um rastreador de questões externo. -projects=Planeamentos -projects.desc=Gerir questões e integrações nos quadros do planeamento. projects.description=Descrição (opcional) projects.description_placeholder=Descrição projects.create=Criar planeamento @@ -1903,6 +1901,7 @@ pulls.recently_pushed_new_branches=Enviou para o ramo <strong>%[1]s</strong> %[2 pull.deleted_branch=(eliminado):%s + milestones.new=Nova etapa milestones.closed=Encerrada %s milestones.update_ago=Modificou %s diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index 81b88dbd45..33634105ff 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -1117,7 +1117,7 @@ branches=Ветки tags=Теги issues=Задачи pulls=Запросы на слияние -project_board=Проекты +projects=Проекты packages=Пакеты actions=Действия labels=Метки @@ -1269,8 +1269,6 @@ commitstatus.success=Успешно ext_issues=Доступ к внешним задачам ext_issues.desc=Ссылка на внешнюю систему отслеживания ошибок. -projects=Проекты -projects.desc=Управление задачами и pull'ами в досках проекта. projects.description=Описание (необязательно) projects.description_placeholder=Описание projects.create=Создать проект @@ -1774,6 +1772,7 @@ pulls.delete.text=Вы действительно хотите удалить э pull.deleted_branch=(удалена):%s + milestones.new=Новый этап milestones.closed=Закрыт %s milestones.update_ago=Обновлено %s diff --git a/options/locale/locale_si-LK.ini b/options/locale/locale_si-LK.ini index cb437e5530..16c11ef713 100644 --- a/options/locale/locale_si-LK.ini +++ b/options/locale/locale_si-LK.ini @@ -863,7 +863,7 @@ branches=ශාඛා tags=ටැග් issues=ගැටළු pulls=ඉල්ලීම් අදින්න -project_board=ව්යාපෘති +projects=ව්යාපෘති labels=ලේබල org_labels_desc=මෙම සංවිධානය යටතේ <strong>සියලුම ගබඩාවලදී</strong> සමඟ භාවිතා කළ හැකි සංවිධාන මට්ටමේ ලේබල් org_labels_desc_manage=කළමනාකරණය @@ -958,8 +958,6 @@ commitstatus.pending=වංගු ext_issues.desc=බාහිර නිකුතුවකට සම්බන්ධ වන්න ට්රැකර්. -projects=ව්යාපෘති -projects.desc=ව්යාපෘති මණ්ඩලවල ගැටළු සහ අදින කළමනාකරණය කිරීම. projects.description=විස්තරය (විකල්ප) projects.description_placeholder=සවිස්තරය projects.create=ව්යාපෘතිය සාදන්න @@ -1340,6 +1338,7 @@ pulls.reopened_at=`මෙම අදින්න ඉල්ලීම නැවත + milestones.new=නව සන්ධිස්ථානයක් milestones.closed=%s වසා ඇත milestones.no_due_date=නියමිත දිනයක් නැත diff --git a/options/locale/locale_sk-SK.ini b/options/locale/locale_sk-SK.ini index be1efa22bc..079523e38c 100644 --- a/options/locale/locale_sk-SK.ini +++ b/options/locale/locale_sk-SK.ini @@ -981,7 +981,7 @@ find_tag=Hľadať tag branches=Vetvy tags=Tagy pulls=Pull requesty -project_board=Projekty +projects=Projekty packages=Balíčky actions=Akcie labels=Štítky @@ -1050,7 +1050,6 @@ commit.cherry-pick-content=Vyberte vetvu pre cherry-pick na: commitstatus.error=Chyba -projects=Projekty projects.title=Názov projects.new=Nový projekt projects.deletion=Vymazať projekt @@ -1121,6 +1120,7 @@ pulls.merge_commit_id=ID zlučovacieho commitu + milestones.open=Otvoriť milestones.close=Zavrieť milestones.cancel=Zrušiť diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini index b975636cb8..ee729911c3 100644 --- a/options/locale/locale_sv-SE.ini +++ b/options/locale/locale_sv-SE.ini @@ -734,7 +734,7 @@ branches=Grenar tags=Taggar issues=Ärenden pulls=Pull-förfrågningar -project_board=Projekt +projects=Projekt labels=Etiketter org_labels_desc=Etiketter på organisationsnivå som kan användas i <strong>alla utvecklingskataloger</strong> tillhörande denna organisation org_labels_desc_manage=hantera @@ -814,7 +814,6 @@ commitstatus.pending=Väntande ext_issues.desc=Länk till externt ärendehanteringssystem. -projects=Projekt projects.description_placeholder=Beskrivning projects.create=Skapa projekt projects.title=Titel @@ -1119,6 +1118,7 @@ pulls.outdated_with_base_branch=Denna branch är föråldrad gentemot bas-branch + milestones.new=Ny milstolpe milestones.closed=Stängt %s milestones.no_due_date=Inget förfallodatum diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index 7b57e416f7..1cb056f578 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -763,6 +763,7 @@ manage_themes=Varsayılan temayı seç manage_openid=OpenID Adreslerini Yönet email_desc=Ana e-posta adresiniz bildirimler, parola kurtarma ve gizlenmemişse eğer web tabanlı Git işlemleri için kullanılacaktır. theme_desc=Bu, sitedeki varsayılan temanız olacak. +theme_colorblindness_help=Renk Körlüğü için Tema Desteği primary=Birincil activated=Aktifleştirildi requires_activation=Etkinleştirme gerekiyor @@ -1212,7 +1213,7 @@ branches=Dal tags=Etiket issues=Konular pulls=Değişiklik İstekleri -project_board=Projeler +projects=Projeler packages=Paketler actions=İşlemler labels=Etiketler @@ -1375,8 +1376,6 @@ commitstatus.success=Başarılı ext_issues=Harici Konulara Erişim ext_issues.desc=Dışsal konu takip sistemine bağla. -projects=Projeler -projects.desc=Proje panolarındaki konuları ve değişiklikleri yönetin. projects.description=Açıklama (isteğe bağlı) projects.description_placeholder=Açıklama projects.create=Proje Oluştur @@ -1900,6 +1899,7 @@ pulls.recently_pushed_new_branches=<strong>%[1]s</strong> dalına ittiniz %[2]s pull.deleted_branch=(silindi): %s + milestones.new=Yeni Kilometre Taşı milestones.closed=Kapalı %s milestones.update_ago=%s tarihinde güncellendi diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini index ddd884e113..cc06c87d32 100644 --- a/options/locale/locale_uk-UA.ini +++ b/options/locale/locale_uk-UA.ini @@ -899,7 +899,7 @@ branches=Гілки tags=Теги issues=Задачі pulls=Запити на злиття -project_board=Проєкти +projects=Проєкти labels=Мітки org_labels_desc=Мітки рівня організації можуть використовуватися <strong>в усіх репозиторіях</strong> цієї організації org_labels_desc_manage=керувати @@ -995,8 +995,6 @@ commitstatus.pending=Очікування ext_issues=Доступ до зовнішніх задач ext_issues.desc=Посилання на зовнішню систему відстеження задач. -projects=Проєкти -projects.desc=Керуйте задачами та запитами злиття на дошках проєкту. projects.description=Опис (необов'язково) projects.description_placeholder=Опис projects.create=Створити проєкт @@ -1387,6 +1385,7 @@ pulls.reopened_at=`повторно відкрив цей запит на зли + milestones.new=Новий етап milestones.closed=Закрито %s milestones.no_due_date=Немає дати завершення diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 75facb4dcb..2d191521d6 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -1215,7 +1215,7 @@ branches=分支列表 tags=标签列表 issues=工单 pulls=合并请求 -project_board=项目 +projects=项目 packages=软件包 actions=Actions labels=标签 @@ -1378,8 +1378,6 @@ commitstatus.success=成功 ext_issues=访问外部工单 ext_issues.desc=链接到外部工单跟踪系统。 -projects=项目 -projects.desc=在项目看板中管理工单和合并请求。 projects.description=描述(可选) projects.description_placeholder=描述 projects.create=创建项目 @@ -1903,6 +1901,7 @@ pulls.recently_pushed_new_branches=您已经于%[2]s推送了分支 <strong>%[1] pull.deleted_branch=(已删除): %s + milestones.new=新的里程碑 milestones.closed=于 %s关闭 milestones.update_ago=已更新 %s diff --git a/options/locale/locale_zh-HK.ini b/options/locale/locale_zh-HK.ini index fb16b82fc5..a6ae0ffe8e 100644 --- a/options/locale/locale_zh-HK.ini +++ b/options/locale/locale_zh-HK.ini @@ -500,6 +500,7 @@ pulls.can_auto_merge_desc=這個拉請求可以自動合併。 + milestones.new=新的里程碑 milestones.closed=於 %s關閉 milestones.no_due_date=暫無截止日期 diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini index 50c0276567..c3590b6acc 100644 --- a/options/locale/locale_zh-TW.ini +++ b/options/locale/locale_zh-TW.ini @@ -1035,7 +1035,7 @@ branches=分支 tags=標籤 issues=問題 pulls=合併請求 -project_board=專案 +projects=專案 packages=套件 actions=Actions labels=標籤 @@ -1176,8 +1176,6 @@ commitstatus.success=成功 ext_issues=存取外部問題 ext_issues.desc=連結到外部問題追蹤器。 -projects=專案 -projects.desc=在專案看板中管理問題與合併請求。 projects.description=描述 (選用) projects.description_placeholder=描述 projects.create=建立專案 @@ -1641,6 +1639,7 @@ pulls.delete.text=您真的要刪除此合併請求嗎?(這將會永久移除 + milestones.new=新增里程碑 milestones.closed=於 %s關閉 milestones.update_ago=已更新 %s From b6b32a55295b121c44b81223a2d1ab331c210e81 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Tue, 28 May 2024 03:50:28 +0200 Subject: [PATCH 368/370] Update JS dependencies (#31120) - Add `eslint-plugin-no-use-extend-native` to exclude list because it requires flat config - Exclude `@github/text-expander-element` because new version has broken positioning - Tested mermaid, monaco, swagger, chartjs --- package-lock.json | 632 +++++++++++++++++++++++----------------------- package.json | 26 +- updates.config.js | 1 + 3 files changed, 331 insertions(+), 328 deletions(-) diff --git a/package-lock.json b/package-lock.json index f535c318fa..90cedd63d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,11 +18,11 @@ "add-asset-webpack-plugin": "3.0.0", "ansi_up": "6.0.2", "asciinema-player": "3.7.1", - "chart.js": "4.4.2", + "chart.js": "4.4.3", "chartjs-adapter-dayjs-4": "1.0.4", "chartjs-plugin-zoom": "2.0.1", "clippie": "4.1.1", - "css-loader": "7.1.1", + "css-loader": "7.1.2", "dayjs": "1.11.11", "dropzone": "6.0.0-beta.2", "easymde": "2.18.0", @@ -34,17 +34,17 @@ "jquery": "3.7.1", "katex": "0.16.10", "license-checker-webpack-plugin": "0.2.1", - "mermaid": "10.9.0", + "mermaid": "10.9.1", "mini-css-extract-plugin": "2.9.0", "minimatch": "9.0.4", - "monaco-editor": "0.48.0", + "monaco-editor": "0.49.0", "monaco-editor-webpack-plugin": "7.1.0", "pdfobject": "2.3.0", "postcss": "8.4.38", "postcss-loader": "8.1.1", - "postcss-nesting": "12.1.2", + "postcss-nesting": "12.1.5", "sortablejs": "1.15.2", - "swagger-ui-dist": "5.17.7", + "swagger-ui-dist": "5.17.13", "tailwindcss": "3.4.3", "temporal-polyfill": "0.2.4", "throttle-debounce": "5.0.0", @@ -64,19 +64,19 @@ }, "devDependencies": { "@eslint-community/eslint-plugin-eslint-comments": "4.3.0", - "@playwright/test": "1.44.0", + "@playwright/test": "1.44.1", "@stoplight/spectral-cli": "6.11.1", "@stylistic/eslint-plugin-js": "2.1.0", "@stylistic/stylelint-plugin": "2.1.2", "@vitejs/plugin-vue": "5.0.4", "eslint": "8.57.0", "eslint-plugin-array-func": "4.0.0", - "eslint-plugin-github": "4.10.2", + "eslint-plugin-github": "5.0.0-2", "eslint-plugin-i": "2.29.1", "eslint-plugin-jquery": "1.5.1", "eslint-plugin-no-jquery": "2.7.0", "eslint-plugin-no-use-extend-native": "0.5.0", - "eslint-plugin-regexp": "2.5.0", + "eslint-plugin-regexp": "2.6.0", "eslint-plugin-sonarjs": "1.0.3", "eslint-plugin-unicorn": "53.0.0", "eslint-plugin-vitest": "0.4.1", @@ -84,15 +84,15 @@ "eslint-plugin-vue": "9.26.0", "eslint-plugin-vue-scoped-css": "2.8.0", "eslint-plugin-wc": "2.1.0", - "happy-dom": "14.10.1", - "markdownlint-cli": "0.40.0", + "happy-dom": "14.11.1", + "markdownlint-cli": "0.41.0", "postcss-html": "1.7.0", - "stylelint": "16.5.0", + "stylelint": "16.6.0", "stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-declaration-strict-value": "1.10.4", "stylelint-value-no-unknown-custom-properties": "6.0.1", "svgo": "3.3.2", - "updates": "16.0.1", + "updates": "16.1.1", "vite-string-plugin": "1.3.1", "vitest": "1.6.0" }, @@ -121,11 +121,11 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", - "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.6.tgz", + "integrity": "sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==", "dependencies": { - "@babel/highlight": "^7.24.2", + "@babel/highlight": "^7.24.6", "picocolors": "^1.0.0" }, "engines": { @@ -133,19 +133,19 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", - "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.6.tgz", + "integrity": "sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", - "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.6.tgz", + "integrity": "sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==", "dependencies": { - "@babel/helper-validator-identifier": "^7.24.5", + "@babel/helper-validator-identifier": "^7.24.6", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -224,9 +224,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz", - "integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.6.tgz", + "integrity": "sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==", "bin": { "parser": "bin/babel-parser.js" }, @@ -235,9 +235,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz", - "integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.6.tgz", + "integrity": "sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -471,9 +471,9 @@ } }, "node_modules/@csstools/selector-specificity": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.0.3.tgz", - "integrity": "sha512-KEPNw4+WW5AVEIyzC80rTbWEUatTW2lXpN8+8ILC8PiPeWPjwUzrPZDIOZ2wwqDmeqOYTdSGyL3+vE5GC3FB3Q==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.1.1.tgz", + "integrity": "sha512-a7cxGcJ2wIlMFLlh8z2ONm+715QkPHiyJcxwQlKOz/03GPw1COpfhcmC9wm4xlZfp//jWHNNMwzjtqHXVWU9KA==", "funding": [ { "type": "github", @@ -1375,12 +1375,12 @@ } }, "node_modules/@playwright/test": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.44.0.tgz", - "integrity": "sha512-rNX5lbNidamSUorBhB4XZ9SQTjAqfe5M+p37Z8ic0jPFBMo5iCtQz1kRWkEMg+rYOKSlVycpQmpqjSFq7LXOfg==", + "version": "1.44.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.44.1.tgz", + "integrity": "sha512-1hZ4TNvD5z9VuhNJ/walIjvMVvYkZKf71axoF/uiAqpntQJXpG64dlXhoDXE3OczPuTuvjf/M5KWFg5VAVUS3Q==", "dev": true, "dependencies": { - "playwright": "1.44.0" + "playwright": "1.44.1" }, "bin": { "playwright": "cli.js" @@ -1451,9 +1451,9 @@ "dev": true }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.17.2.tgz", - "integrity": "sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz", + "integrity": "sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==", "cpu": [ "arm" ], @@ -1464,9 +1464,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.17.2.tgz", - "integrity": "sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz", + "integrity": "sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==", "cpu": [ "arm64" ], @@ -1477,9 +1477,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.17.2.tgz", - "integrity": "sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz", + "integrity": "sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==", "cpu": [ "arm64" ], @@ -1490,9 +1490,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.17.2.tgz", - "integrity": "sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz", + "integrity": "sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==", "cpu": [ "x64" ], @@ -1503,9 +1503,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.17.2.tgz", - "integrity": "sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz", + "integrity": "sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==", "cpu": [ "arm" ], @@ -1516,9 +1516,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.17.2.tgz", - "integrity": "sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz", + "integrity": "sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==", "cpu": [ "arm" ], @@ -1529,9 +1529,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.2.tgz", - "integrity": "sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz", + "integrity": "sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==", "cpu": [ "arm64" ], @@ -1542,9 +1542,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.17.2.tgz", - "integrity": "sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz", + "integrity": "sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==", "cpu": [ "arm64" ], @@ -1555,9 +1555,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.17.2.tgz", - "integrity": "sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz", + "integrity": "sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==", "cpu": [ "ppc64" ], @@ -1568,9 +1568,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.17.2.tgz", - "integrity": "sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz", + "integrity": "sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==", "cpu": [ "riscv64" ], @@ -1581,9 +1581,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.17.2.tgz", - "integrity": "sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz", + "integrity": "sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==", "cpu": [ "s390x" ], @@ -1594,9 +1594,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.2.tgz", - "integrity": "sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz", + "integrity": "sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==", "cpu": [ "x64" ], @@ -1607,9 +1607,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.17.2.tgz", - "integrity": "sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz", + "integrity": "sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==", "cpu": [ "x64" ], @@ -1620,9 +1620,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.17.2.tgz", - "integrity": "sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz", + "integrity": "sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==", "cpu": [ "arm64" ], @@ -1633,9 +1633,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.17.2.tgz", - "integrity": "sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz", + "integrity": "sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==", "cpu": [ "ia32" ], @@ -1646,9 +1646,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.17.2.tgz", - "integrity": "sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz", + "integrity": "sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==", "cpu": [ "x64" ], @@ -2324,9 +2324,9 @@ "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" }, "node_modules/@types/node": { - "version": "20.12.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.11.tgz", - "integrity": "sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==", + "version": "20.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", + "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", "dependencies": { "undici-types": "~5.26.4" } @@ -2343,12 +2343,6 @@ "integrity": "sha512-kRz0VEkJqWLf1LLVN4pT1cg1Z9wAuvI6L97V3m2f5B76Tg8d413ddvLBPTEHAZJlnn4XSvu0FkZtViCQGVyrXQ==", "dev": true }, - "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true - }, "node_modules/@types/tern": { "version": "0.23.9", "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.9.tgz", @@ -2369,21 +2363,19 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.8.0.tgz", - "integrity": "sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg==", + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.10.0.tgz", + "integrity": "sha512-PzCr+a/KAef5ZawX7nbyNwBDtM1HdLIT53aSA2DDlxmxMngZ43O8SIePOeX8H5S+FHXeI6t97mTt/dDdzY4Fyw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.8.0", - "@typescript-eslint/type-utils": "7.8.0", - "@typescript-eslint/utils": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0", - "debug": "^4.3.4", + "@typescript-eslint/scope-manager": "7.10.0", + "@typescript-eslint/type-utils": "7.10.0", + "@typescript-eslint/utils": "7.10.0", + "@typescript-eslint/visitor-keys": "7.10.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "semver": "^7.6.0", "ts-api-utils": "^1.3.0" }, "engines": { @@ -2404,15 +2396,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.8.0.tgz", - "integrity": "sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ==", + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.10.0.tgz", + "integrity": "sha512-2EjZMA0LUW5V5tGQiaa2Gys+nKdfrn2xiTIBLR4fxmPmVSvgPcKNW+AE/ln9k0A4zDUti0J/GZXMDupQoI+e1w==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.8.0", - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/typescript-estree": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0", + "@typescript-eslint/scope-manager": "7.10.0", + "@typescript-eslint/types": "7.10.0", + "@typescript-eslint/typescript-estree": "7.10.0", + "@typescript-eslint/visitor-keys": "7.10.0", "debug": "^4.3.4" }, "engines": { @@ -2432,13 +2424,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.8.0.tgz", - "integrity": "sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==", + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.10.0.tgz", + "integrity": "sha512-7L01/K8W/VGl7noe2mgH0K7BE29Sq6KAbVmxurj8GGaPDZXPr8EEQ2seOeAS+mEV9DnzxBQB6ax6qQQ5C6P4xg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0" + "@typescript-eslint/types": "7.10.0", + "@typescript-eslint/visitor-keys": "7.10.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2449,13 +2441,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.8.0.tgz", - "integrity": "sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A==", + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.10.0.tgz", + "integrity": "sha512-D7tS4WDkJWrVkuzgm90qYw9RdgBcrWmbbRkrLA4d7Pg3w0ttVGDsvYGV19SH8gPR5L7OtcN5J1hTtyenO9xE9g==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.8.0", - "@typescript-eslint/utils": "7.8.0", + "@typescript-eslint/typescript-estree": "7.10.0", + "@typescript-eslint/utils": "7.10.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -2476,9 +2468,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.8.0.tgz", - "integrity": "sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==", + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.10.0.tgz", + "integrity": "sha512-7fNj+Ya35aNyhuqrA1E/VayQX9Elwr8NKZ4WueClR3KwJ7Xx9jcCdOrLW04h51de/+gNbyFMs+IDxh5xIwfbNg==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2489,13 +2481,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz", - "integrity": "sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==", + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.10.0.tgz", + "integrity": "sha512-LXFnQJjL9XIcxeVfqmNj60YhatpRLt6UhdlFwAkjNc6jSUlK8zQOl1oktAP8PlWFzPQC1jny/8Bai3/HPuvN5g==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0", + "@typescript-eslint/types": "7.10.0", + "@typescript-eslint/visitor-keys": "7.10.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2517,18 +2509,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.8.0.tgz", - "integrity": "sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==", + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.10.0.tgz", + "integrity": "sha512-olzif1Fuo8R8m/qKkzJqT7qwy16CzPRWBvERS0uvyc+DHd8AKbO4Jb7kpAvVzMmZm8TrHnI7hvjN4I05zow+tg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.15", - "@types/semver": "^7.5.8", - "@typescript-eslint/scope-manager": "7.8.0", - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/typescript-estree": "7.8.0", - "semver": "^7.6.0" + "@typescript-eslint/scope-manager": "7.10.0", + "@typescript-eslint/types": "7.10.0", + "@typescript-eslint/typescript-estree": "7.10.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2542,12 +2531,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.8.0.tgz", - "integrity": "sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==", + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.10.0.tgz", + "integrity": "sha512-9ntIVgsi6gg6FIq9xjEO4VQJvwOqA3jaBFQJ/6TK5AvEup2+cECI6Fh7QiBxmfMHXU0V0J4RyPeOU1VDNzl9cg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/types": "7.10.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -3053,9 +3042,9 @@ } }, "node_modules/ajv": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", - "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.14.0.tgz", + "integrity": "sha512-oYs1UUtO97ZO2lJ4bwnWeQW8/zvOIQLGKcvPTsWmvc2SYgBb+upuNS5NxoLaMU4h8Ju3Nbj6Cq8mD2LQoqVKFA==", "dependencies": { "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", @@ -3480,11 +3469,11 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -3612,9 +3601,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001617", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001617.tgz", - "integrity": "sha512-mLyjzNI9I+Pix8zwcrpxEbGlfqOkF9kM3ptzmKNw5tizSyYwMe+nGLTqMK9cO+0E+Bh6TsBxNAaHWEM8xwSsmA==", + "version": "1.0.30001623", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001623.tgz", + "integrity": "sha512-X/XhAVKlpIxWPpgRTnlgZssJrF0m6YtRA0QDWgsBNT12uZM6LPRydR7ip405Y3t1LamD8cP2TZFEDZFBf5ApcA==", "funding": [ { "type": "opencollective", @@ -3673,9 +3662,9 @@ } }, "node_modules/chart.js": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.2.tgz", - "integrity": "sha512-6GD7iKwFpP5kbSD4MeRRRlTnQvxfQREy36uEtm1hzHzcOqwWx0YEHuspuoNlslu+nciLIB7fjjsHkUv/FzFcOg==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.3.tgz", + "integrity": "sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==", "dependencies": { "@kurkle/color": "^0.3.0" }, @@ -3933,9 +3922,9 @@ "dev": true }, "node_modules/core-js-compat": { - "version": "3.37.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.0.tgz", - "integrity": "sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA==", + "version": "3.37.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", + "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", "dev": true, "dependencies": { "browserslist": "^4.23.0" @@ -4012,9 +4001,9 @@ } }, "node_modules/css-loader": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.1.tgz", - "integrity": "sha512-OxIR5P2mjO1PSXk44bWuQ8XtMK4dpEqpIyERCx3ewOo3I8EmbcxMPUc5ScLtQfgXtOojoMv57So4V/C02HQLsw==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.2.tgz", + "integrity": "sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA==", "dependencies": { "icss-utils": "^5.1.0", "postcss": "^8.4.33", @@ -4860,9 +4849,9 @@ } }, "node_modules/dompurify": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.2.tgz", - "integrity": "sha512-hLGGBI1tw5N8qTELr3blKjAML/LY4ANxksbS612UiJyDfyf/2D092Pvm+S7pmeTGJRqvlJkFzBoHBQKgQlOQVg==" + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.4.tgz", + "integrity": "sha512-2gnshi6OshmuKil8rMZuQCGiUF3cUxHY3NGDzUAdUx/NPEe5DVnO8BDoAQouvgwnx0R/+a6jUn36Z0FSdq8vww==" }, "node_modules/domutils": { "version": "3.1.0", @@ -4905,9 +4894,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.762", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.762.tgz", - "integrity": "sha512-rrFvGweLxPwwSwJOjIopy3Vr+J3cIPtZzuc74bmlvmBIgQO3VYJDvVrlj94iKZ3ukXUH64Ex31hSfRTLqvjYJQ==" + "version": "1.4.783", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.783.tgz", + "integrity": "sha512-bT0jEz/Xz1fahQpbZ1D7LgmPYZ3iHVY39NcWWro1+hA2IvjiPeaXtfSqrQ+nXjApMvQRE2ASt1itSLRrebHMRQ==" }, "node_modules/elkjs": { "version": "0.9.3", @@ -5106,9 +5095,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.2.tgz", - "integrity": "sha512-l60ETUTmLqbVbVHv1J4/qj+M8nq7AwMzEcg3kmJDt9dCNrTk+yHcYFf/Kw75pMDwd9mPcIGCG5LcS20SxYRzFA==" + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.3.tgz", + "integrity": "sha512-i1gCgmR9dCl6Vil6UKPI/trA69s08g/syhiDK9TG0Nf1RJjjFI+AzoWW7sPufzkgYAn861skuCwJa0pIIHYxvg==" }, "node_modules/es-object-atoms": { "version": "1.0.0", @@ -5443,9 +5432,9 @@ } }, "node_modules/eslint-plugin-github": { - "version": "4.10.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-github/-/eslint-plugin-github-4.10.2.tgz", - "integrity": "sha512-F1F5aAFgi1Y5hYoTFzGQACBkw5W1hu2Fu5FSTrMlXqrojJnKl1S2pWO/rprlowRQpt+hzHhqSpsfnodJEVd5QA==", + "version": "5.0.0-2", + "resolved": "https://registry.npmjs.org/eslint-plugin-github/-/eslint-plugin-github-5.0.0-2.tgz", + "integrity": "sha512-oQUFAF1wMBvRMGLvGWxVhZ46JNjKbPuuDufmUDZ3ZYyovWHCqqR5HLHTpTfmZQcyEXmjv9TWdsgfdMlod2fGMQ==", "dev": true, "dependencies": { "@github/browserslist-config": "^1.0.0", @@ -5737,9 +5726,9 @@ } }, "node_modules/eslint-plugin-regexp": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-2.5.0.tgz", - "integrity": "sha512-I7vKcP0o75WS5SHiVNXN+Eshq49sbrweMQIuqSL3AId9AwDe9Dhbfug65vw64LxmOd4v+yf5l5Xt41y9puiq0g==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-2.6.0.tgz", + "integrity": "sha512-FCL851+kislsTEQEMioAlpDuK5+E5vs0hi1bF8cFlPlHcEjeRhuAzEsGikXRreE+0j4WhW2uO54MqTjXtYOi3A==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", @@ -5803,9 +5792,9 @@ } }, "node_modules/eslint-plugin-unicorn/node_modules/@eslint/eslintrc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.0.2.tgz", - "integrity": "sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -6294,9 +6283,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -6562,6 +6551,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -6751,9 +6741,9 @@ } }, "node_modules/happy-dom": { - "version": "14.10.1", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-14.10.1.tgz", - "integrity": "sha512-GRbrZYIezi8+tTtffF4v2QcF8bk1h2loUTO5VYQz3GZdrL08Vk0fI+bwf/vFEBf4C/qVf/easLJ/MY1wwdhytA==", + "version": "14.11.1", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-14.11.1.tgz", + "integrity": "sha512-JuaGMxD3QlQei6LdAM9mMY9am/cHa978uFbkOpjN5x83DG+QQp/NLyVV4Ru7KOjs70XYZ4KbI0TNiO81nM7uQQ==", "dev": true, "dependencies": { "entities": "^4.5.0", @@ -7028,6 +7018,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -7039,9 +7030,9 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", + "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", "dev": true, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -7575,9 +7566,9 @@ } }, "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.1.2.tgz", + "integrity": "sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==", "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -7828,15 +7819,15 @@ } }, "node_modules/known-css-properties": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.30.0.tgz", - "integrity": "sha512-VSWXYUnsPu9+WYKkfmJyLKtIvaRJi1kXUqVmBACORXZQxT5oZDsoZ2vQP+bQFDnWtpI/4eq3MLoRMjI2fnLzTQ==", + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.31.0.tgz", + "integrity": "sha512-sBPIUGTNF0czz0mwGGUoKKJC8Q7On1GPbCSFPfyEsfHb2DyBG0Y4QtV+EVWpINSaiGKZblDNuF5AezxSgOhesQ==", "dev": true }, "node_modules/language-subtag-registry": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", - "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", "dev": true }, "node_modules/language-tags": { @@ -8162,14 +8153,14 @@ } }, "node_modules/markdownlint-cli": { - "version": "0.40.0", - "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.40.0.tgz", - "integrity": "sha512-JXhI3dRQcaqwiFYpPz6VJ7aKYheD53GmTz9y4D/d0F1MbZDGOp9pqKlbOfUX/pHP/iAoeiE4wYRmk8/kjLakxA==", + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.41.0.tgz", + "integrity": "sha512-kp29tKrMKdn+xonfefjp3a/MsNzAd9c5ke0ydMEI9PR98bOjzglYN4nfMSaIs69msUf1DNkgevAIAPtK2SeX0Q==", "dev": true, "dependencies": { - "commander": "~12.0.0", + "commander": "~12.1.0", "get-stdin": "~9.0.0", - "glob": "~10.3.12", + "glob": "~10.4.1", "ignore": "~5.3.1", "js-yaml": "^4.1.0", "jsonc-parser": "~3.2.1", @@ -8177,7 +8168,7 @@ "markdownlint": "~0.34.0", "minimatch": "~9.0.4", "run-con": "~1.3.2", - "toml": "~3.0.0" + "smol-toml": "~1.2.0" }, "bin": { "markdownlint": "markdownlint.js" @@ -8187,31 +8178,31 @@ } }, "node_modules/markdownlint-cli/node_modules/commander": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz", - "integrity": "sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==", + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "dev": true, "engines": { "node": ">=18" } }, "node_modules/markdownlint-cli/node_modules/glob": { - "version": "10.3.14", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.14.tgz", - "integrity": "sha512-4fkAqu93xe9Mk7le9v0y3VrPDqLKHarNi2s4Pv7f2yOvfhWfhc7hRPHC/JyqMqb8B/Dt/eGS4n7ykwf3fOsl8g==", + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.6", - "minimatch": "^9.0.1", - "minipass": "^7.0.4", - "path-scurry": "^1.11.0" + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=16 || 14 >=14.18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -8329,9 +8320,9 @@ } }, "node_modules/mermaid": { - "version": "10.9.0", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-10.9.0.tgz", - "integrity": "sha512-swZju0hFox/B/qoLKK0rOxxgh8Cf7rJSfAUc1u8fezVihYMvrJAS45GzAxTVf4Q+xn9uMgitBcmWk7nWGXOs/g==", + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-10.9.1.tgz", + "integrity": "sha512-Mx45Obds5W1UkW1nv/7dHRsbfMM1aOKA2+Pxs/IGHNonygDHwmng8xTHyS9z4KWVi0rbko8gjiBmuwwXQ7tiNA==", "dependencies": { "@braintree/sanitize-url": "^6.0.1", "@types/d3-scale": "^4.0.3", @@ -8777,11 +8768,11 @@ ] }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -8871,9 +8862,9 @@ } }, "node_modules/minipass": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.1.tgz", - "integrity": "sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "engines": { "node": ">=16 || 14 >=14.17" } @@ -8891,9 +8882,9 @@ } }, "node_modules/monaco-editor": { - "version": "0.48.0", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.48.0.tgz", - "integrity": "sha512-goSDElNqFfw7iDHMg8WDATkfcyeLTNpBHQpO8incK6p5qZt5G/1j41X0xdGzpIkGojGXM+QiRQyLjnfDVvrpwA==" + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.49.0.tgz", + "integrity": "sha512-2I8/T3X/hLxB2oPHgqcNYUVdA/ZEFShT7IAujifIPMfKkNbLOqY8XCoyHCXrsdjb36dW9MwoTwBCFpXKMwNwaQ==" }, "node_modules/monaco-editor-webpack-plugin": { "version": "7.1.0", @@ -9362,15 +9353,15 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-scurry": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.0.tgz", - "integrity": "sha512-LNHTaVkzaYaLGlO+0u3rQTz7QrHTFOuKyba9JMTQutkmtNew8dw8wOD7mTU/5fCPZzCWpfW0XnQKzY61P0aTaw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=16 || 14 >=14.18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -9406,9 +9397,9 @@ "integrity": "sha512-w/9pXDXTDs3IDmOri/w8lM/w6LHR0/F4fcBLLzH+4csSoyshQ5su0TE7k0FLHZO7aOjVLDGecqd1M89+PVpVAA==" }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -9508,12 +9499,12 @@ } }, "node_modules/playwright": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.44.0.tgz", - "integrity": "sha512-F9b3GUCLQ3Nffrfb6dunPOkE5Mh68tR7zN32L4jCk4FjQamgesGay7/dAAe1WaMEGV04DkdJfcJzjoCKygUaRQ==", + "version": "1.44.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.44.1.tgz", + "integrity": "sha512-qr/0UJ5CFAtloI3avF95Y0L1xQo6r3LQArLIg/z/PoGJ6xa+EwzrwO5lpNr/09STxdHuUoP2mvuELJS+hLdtgg==", "dev": true, "dependencies": { - "playwright-core": "1.44.0" + "playwright-core": "1.44.1" }, "bin": { "playwright": "cli.js" @@ -9526,9 +9517,9 @@ } }, "node_modules/playwright-core": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.44.0.tgz", - "integrity": "sha512-ZTbkNpFfYcGWohvTTl+xewITm7EOuqIqex0c7dNZ+aXsbrLj0qI8XlGKfPpipjm0Wny/4Lt4CJsWJk1stVS5qQ==", + "version": "1.44.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.44.1.tgz", + "integrity": "sha512-wh0JWtYTrhv1+OSsLPgFzGzt67Y7BE/ZS3jEqgGBlp2ppp1ZDj8c+9IARNW4dwf1poq5MgHreEM2KV/GuR4cFA==", "dev": true, "bin": { "playwright-core": "cli.js" @@ -9744,9 +9735,9 @@ } }, "node_modules/postcss-nesting": { - "version": "12.1.2", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-12.1.2.tgz", - "integrity": "sha512-FUmTHGDNundodutB4PUBxt/EPuhgtpk8FJGRsBhOuy+6FnkR2A8RZWIsyyy6XmhvX2DZQQWIkvu+HB4IbJm+Ew==", + "version": "12.1.5", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-12.1.5.tgz", + "integrity": "sha512-N1NgI1PDCiAGWPTYrwqm8wpjv0bgDmkYHH72pNsqTCv9CObxjxftdYu6AKtGN+pnJa7FQjMm3v4sp8QJbFsYdQ==", "funding": [ { "type": "github", @@ -9759,8 +9750,8 @@ ], "dependencies": { "@csstools/selector-resolve-nested": "^1.1.0", - "@csstools/selector-specificity": "^3.0.3", - "postcss-selector-parser": "^6.0.13" + "@csstools/selector-specificity": "^3.1.1", + "postcss-selector-parser": "^6.1.0" }, "engines": { "node": "^14 || ^16 || >=18" @@ -9818,9 +9809,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.16", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", - "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz", + "integrity": "sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -10301,6 +10292,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "dependencies": { "glob": "^7.1.3" @@ -10508,17 +10500,17 @@ } }, "node_modules/seroval": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.0.5.tgz", - "integrity": "sha512-TM+Z11tHHvQVQKeNlOUonOWnsNM+2IBwZ4vwoi4j3zKzIpc5IDw8WPwCfcc8F17wy6cBcJGbZbFOR0UCuTZHQA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.0.7.tgz", + "integrity": "sha512-n6ZMQX5q0Vn19Zq7CIKNIo7E75gPkGCFUEqDpa8jgwpYr/vScjqnQ6H09t1uIiZ0ZSK0ypEGvrYK2bhBGWsGdw==", "engines": { "node": ">=10" } }, "node_modules/seroval-plugins": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.0.5.tgz", - "integrity": "sha512-8+pDC1vOedPXjKG7oz8o+iiHrtF2WswaMQJ7CKFpccvSYfrzmvKY9zOJWCg+881722wIHfwkdnRmiiDm9ym+zQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.0.7.tgz", + "integrity": "sha512-GO7TkWvodGp6buMEX9p7tNyIkbwlyuAWbI6G9Ec5bhcm7mQdu3JOK1IXbEUwb3FVzSc363GraG/wLW23NSavIw==", "engines": { "node": ">=10" }, @@ -10661,6 +10653,16 @@ "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, + "node_modules/smol-toml": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.2.0.tgz", + "integrity": "sha512-KObxdQANC/xje3OoatMbSwQf2XAvJ0RbK+4nmQRszFNZptbNRnMWqbLF/zb4sMi9xJ6HNyhWXeuZ9zC/I/XY7w==", + "dev": true, + "engines": { + "node": ">= 18", + "pnpm": ">= 9" + } + }, "node_modules/solid-js": { "version": "1.8.17", "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.8.17.tgz", @@ -10767,9 +10769,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.17", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", - "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==" + "version": "3.0.18", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", + "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==" }, "node_modules/spdx-ranges": { "version": "2.1.1", @@ -10981,16 +10983,26 @@ "dev": true }, "node_modules/stylelint": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.5.0.tgz", - "integrity": "sha512-IlCBtVrG+qTy3v+tZTk50W8BIomjY/RUuzdrDqdnlCYwVuzXtPbiGfxYqtyYAyOMcb+195zRsuHn6tgfPmFfbw==", + "version": "16.6.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.6.0.tgz", + "integrity": "sha512-vjWYlDEgOS3Z/IcXagQwi8PFJyPro1DxBYOnTML1PAqnrYUHs8owleGStv20sgt0OhW8r9zZm6MK7IT2+l2B6A==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + }, + { + "type": "github", + "url": "https://github.com/sponsors/stylelint" + } + ], "dependencies": { - "@csstools/css-parser-algorithms": "^2.6.1", - "@csstools/css-tokenizer": "^2.2.4", - "@csstools/media-query-list-parser": "^2.1.9", - "@csstools/selector-specificity": "^3.0.3", - "@dual-bundle/import-meta-resolve": "^4.0.0", + "@csstools/css-parser-algorithms": "^2.6.3", + "@csstools/css-tokenizer": "^2.3.1", + "@csstools/media-query-list-parser": "^2.1.11", + "@csstools/selector-specificity": "^3.1.1", + "@dual-bundle/import-meta-resolve": "^4.1.0", "balanced-match": "^2.0.0", "colord": "^2.9.3", "cosmiconfig": "^9.0.0", @@ -11007,16 +11019,16 @@ "ignore": "^5.3.1", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", - "known-css-properties": "^0.30.0", + "known-css-properties": "^0.31.0", "mathml-tag-names": "^2.1.3", "meow": "^13.2.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", - "picocolors": "^1.0.0", + "picocolors": "^1.0.1", "postcss": "^8.4.38", "postcss-resolve-nested-selector": "^0.1.1", "postcss-safe-parser": "^7.0.0", - "postcss-selector-parser": "^6.0.16", + "postcss-selector-parser": "^6.1.0", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "string-width": "^4.2.3", @@ -11031,10 +11043,6 @@ }, "engines": { "node": ">=18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/stylelint" } }, "node_modules/stylelint-declaration-block-no-ignored-properties": { @@ -11234,21 +11242,21 @@ } }, "node_modules/sucrase/node_modules/glob": { - "version": "10.3.14", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.14.tgz", - "integrity": "sha512-4fkAqu93xe9Mk7le9v0y3VrPDqLKHarNi2s4Pv7f2yOvfhWfhc7hRPHC/JyqMqb8B/Dt/eGS4n7ykwf3fOsl8g==", + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.6", - "minimatch": "^9.0.1", - "minipass": "^7.0.4", - "path-scurry": "^1.11.0" + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=16 || 14 >=14.18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -11345,9 +11353,9 @@ } }, "node_modules/swagger-ui-dist": { - "version": "5.17.7", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.17.7.tgz", - "integrity": "sha512-hKnq2Dss6Nvqxzj+tToBz0IJvKXgp7FExxX0Zj0rMajXJp8CJ98yLAwbKwKu8rxQf+2iIDUTGir84SCA8AN+fQ==" + "version": "5.17.13", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.17.13.tgz", + "integrity": "sha512-dyR3HAjwjK9oTd5ELzFh7rJEoMUyqfgaAQEwn0NGhLpOwg7IEbee17qjp50QIVE3sUA8J2d6ySw4IF50nUrKog==" }, "node_modules/sync-fetch": { "version": "0.4.5", @@ -11681,12 +11689,6 @@ "resolved": "https://registry.npmjs.org/toastify-js/-/toastify-js-1.12.0.tgz", "integrity": "sha512-HeMHCO9yLPvP9k0apGSdPUWrUbLnxUKNFzgUoZp1PHCLploIX/4DSQ7V8H25ef+h4iO9n0he7ImfcndnN6nDrQ==" }, - "node_modules/toml": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", - "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", - "dev": true - }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -11936,9 +11938,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.15.tgz", - "integrity": "sha512-K9HWH62x3/EalU1U6sjSZiylm9C8tgq2mSvshZpqc7QE69RaA2qjhkW2HlNA0tFpEbtyFz7HTqbSdN4MSwUodA==", + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", + "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", "funding": [ { "type": "opencollective", @@ -11955,7 +11957,7 @@ ], "dependencies": { "escalade": "^3.1.2", - "picocolors": "^1.0.0" + "picocolors": "^1.0.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -11965,9 +11967,9 @@ } }, "node_modules/updates": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/updates/-/updates-16.0.1.tgz", - "integrity": "sha512-If3NQKzGcA3aVgz2VyOXqQ+4uqYjPUPqh2PeZPtD+OKT4CTmxRYqoyFO+T3nwfccy4SiWy5AabWrBXXhVQ89Aw==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/updates/-/updates-16.1.1.tgz", + "integrity": "sha512-h0Qtbmd9RCi6+99D5o7ACq4h7GxdYjeHFlxd4s0iO3lUOUDo1VnOsbNNIyjHpieVEctaEm/zoEjVggCgAcO/vg==", "dev": true, "bin": { "updates": "dist/updates.js" @@ -12161,9 +12163,9 @@ } }, "node_modules/vite/node_modules/rollup": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.17.2.tgz", - "integrity": "sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz", + "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -12176,22 +12178,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.17.2", - "@rollup/rollup-android-arm64": "4.17.2", - "@rollup/rollup-darwin-arm64": "4.17.2", - "@rollup/rollup-darwin-x64": "4.17.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.17.2", - "@rollup/rollup-linux-arm-musleabihf": "4.17.2", - "@rollup/rollup-linux-arm64-gnu": "4.17.2", - "@rollup/rollup-linux-arm64-musl": "4.17.2", - "@rollup/rollup-linux-powerpc64le-gnu": "4.17.2", - "@rollup/rollup-linux-riscv64-gnu": "4.17.2", - "@rollup/rollup-linux-s390x-gnu": "4.17.2", - "@rollup/rollup-linux-x64-gnu": "4.17.2", - "@rollup/rollup-linux-x64-musl": "4.17.2", - "@rollup/rollup-win32-arm64-msvc": "4.17.2", - "@rollup/rollup-win32-ia32-msvc": "4.17.2", - "@rollup/rollup-win32-x64-msvc": "4.17.2", + "@rollup/rollup-android-arm-eabi": "4.18.0", + "@rollup/rollup-android-arm64": "4.18.0", + "@rollup/rollup-darwin-arm64": "4.18.0", + "@rollup/rollup-darwin-x64": "4.18.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.18.0", + "@rollup/rollup-linux-arm-musleabihf": "4.18.0", + "@rollup/rollup-linux-arm64-gnu": "4.18.0", + "@rollup/rollup-linux-arm64-musl": "4.18.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.18.0", + "@rollup/rollup-linux-riscv64-gnu": "4.18.0", + "@rollup/rollup-linux-s390x-gnu": "4.18.0", + "@rollup/rollup-linux-x64-gnu": "4.18.0", + "@rollup/rollup-linux-x64-musl": "4.18.0", + "@rollup/rollup-win32-arm64-msvc": "4.18.0", + "@rollup/rollup-win32-ia32-msvc": "4.18.0", + "@rollup/rollup-win32-x64-msvc": "4.18.0", "fsevents": "~2.3.2" } }, diff --git a/package.json b/package.json index d0de1efd5a..d7588e093f 100644 --- a/package.json +++ b/package.json @@ -17,11 +17,11 @@ "add-asset-webpack-plugin": "3.0.0", "ansi_up": "6.0.2", "asciinema-player": "3.7.1", - "chart.js": "4.4.2", + "chart.js": "4.4.3", "chartjs-adapter-dayjs-4": "1.0.4", "chartjs-plugin-zoom": "2.0.1", "clippie": "4.1.1", - "css-loader": "7.1.1", + "css-loader": "7.1.2", "dayjs": "1.11.11", "dropzone": "6.0.0-beta.2", "easymde": "2.18.0", @@ -33,17 +33,17 @@ "jquery": "3.7.1", "katex": "0.16.10", "license-checker-webpack-plugin": "0.2.1", - "mermaid": "10.9.0", + "mermaid": "10.9.1", "mini-css-extract-plugin": "2.9.0", "minimatch": "9.0.4", - "monaco-editor": "0.48.0", + "monaco-editor": "0.49.0", "monaco-editor-webpack-plugin": "7.1.0", "pdfobject": "2.3.0", "postcss": "8.4.38", "postcss-loader": "8.1.1", - "postcss-nesting": "12.1.2", + "postcss-nesting": "12.1.5", "sortablejs": "1.15.2", - "swagger-ui-dist": "5.17.7", + "swagger-ui-dist": "5.17.13", "tailwindcss": "3.4.3", "temporal-polyfill": "0.2.4", "throttle-debounce": "5.0.0", @@ -63,19 +63,19 @@ }, "devDependencies": { "@eslint-community/eslint-plugin-eslint-comments": "4.3.0", - "@playwright/test": "1.44.0", + "@playwright/test": "1.44.1", "@stoplight/spectral-cli": "6.11.1", "@stylistic/eslint-plugin-js": "2.1.0", "@stylistic/stylelint-plugin": "2.1.2", "@vitejs/plugin-vue": "5.0.4", "eslint": "8.57.0", "eslint-plugin-array-func": "4.0.0", - "eslint-plugin-github": "4.10.2", + "eslint-plugin-github": "5.0.0-2", "eslint-plugin-i": "2.29.1", "eslint-plugin-jquery": "1.5.1", "eslint-plugin-no-jquery": "2.7.0", "eslint-plugin-no-use-extend-native": "0.5.0", - "eslint-plugin-regexp": "2.5.0", + "eslint-plugin-regexp": "2.6.0", "eslint-plugin-sonarjs": "1.0.3", "eslint-plugin-unicorn": "53.0.0", "eslint-plugin-vitest": "0.4.1", @@ -83,15 +83,15 @@ "eslint-plugin-vue": "9.26.0", "eslint-plugin-vue-scoped-css": "2.8.0", "eslint-plugin-wc": "2.1.0", - "happy-dom": "14.10.1", - "markdownlint-cli": "0.40.0", + "happy-dom": "14.11.1", + "markdownlint-cli": "0.41.0", "postcss-html": "1.7.0", - "stylelint": "16.5.0", + "stylelint": "16.6.0", "stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-declaration-strict-value": "1.10.4", "stylelint-value-no-unknown-custom-properties": "6.0.1", "svgo": "3.3.2", - "updates": "16.0.1", + "updates": "16.1.1", "vite-string-plugin": "1.3.1", "vitest": "1.6.0" }, diff --git a/updates.config.js b/updates.config.js index bd072fe6cb..a4a2fa5228 100644 --- a/updates.config.js +++ b/updates.config.js @@ -3,6 +3,7 @@ export default { '@mcaptcha/vanilla-glue', // breaking changes in rc versions need to be handled 'eslint', // need to migrate to eslint flat config first 'eslint-plugin-array-func', // need to migrate to eslint flat config first + 'eslint-plugin-no-use-extend-native', // need to migrate to eslint flat config first 'eslint-plugin-vitest', // need to migrate to eslint flat config first ], }; From 858d4f221d71e9d761048d302f04cba223d5d9da Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Tue, 28 May 2024 04:13:42 +0200 Subject: [PATCH 369/370] Fix DashboardRepoList margin (#31121) Fixes: https://github.com/go-gitea/gitea/issues/31115 <img width="476" alt="image" src="https://github.com/go-gitea/gitea/assets/115237/ba508ba9-b02d-47c6-ad9f-495101c81330"> --- web_src/js/components/DashboardRepoList.vue | 2 -- 1 file changed, 2 deletions(-) diff --git a/web_src/js/components/DashboardRepoList.vue b/web_src/js/components/DashboardRepoList.vue index 8bce40ee79..3f9f427cd7 100644 --- a/web_src/js/components/DashboardRepoList.vue +++ b/web_src/js/components/DashboardRepoList.vue @@ -509,10 +509,8 @@ ul li:not(:last-child) { } .repos-filter { - padding-top: 0 !important; margin-top: 0 !important; border-bottom-width: 0 !important; - margin-bottom: 2px !important; } .repos-filter .item { From cd7d1314fc6598931e9a651a1c17026b28aa2c62 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Tue, 28 May 2024 10:43:13 +0800 Subject: [PATCH 370/370] Fix API repository object format missed (#31118) Fix #31117 --- services/convert/repository.go | 1 + 1 file changed, 1 insertion(+) diff --git a/services/convert/repository.go b/services/convert/repository.go index 3b293fe550..26c591dd88 100644 --- a/services/convert/repository.go +++ b/services/convert/repository.go @@ -236,6 +236,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR MirrorInterval: mirrorInterval, MirrorUpdated: mirrorUpdated, RepoTransfer: transfer, + ObjectFormatName: repo.ObjectFormatName, } }