From d9b2a4e787da315bc2c197c7148a291fb063ed22 Mon Sep 17 00:00:00 2001 From: yukkop Date: Sat, 26 Sep 2026 21:18:24 +0000 Subject: [PATCH] feat: update gitea vendor --- package/gitea/default.nix | 41 +- package/gitea/source/.changelog.yml | 5 +- .../source/.devcontainer/devcontainer.json | 2 +- package/gitea/source/.dockerignore | 8 - package/gitea/source/.editorconfig | 2 +- package/gitea/source/.gitattributes | 1 + package/gitea/source/.gitea/issue_template.md | 42 - .../.github/ISSUE_TEMPLATE/bug-report.yaml | 83 +- .../ISSUE_TEMPLATE/feature-request.yaml | 20 +- .../.github/ISSUE_TEMPLATE/ui.bug-report.yaml | 66 - .../.github/actions/docker-dryrun/action.yml | 29 + .../actions/free-disk-space/action.yml | 17 + .../.github/actions/go-cache/action.yml | 50 + .../.github/actions/go-setup/action.yml | 24 + .../.github/actions/node-setup/action.yml | 22 + .../.github/actions/pgsql-shard/action.yml | 40 + package/gitea/source/.github/dependabot.yml | 10 - package/gitea/source/.github/labeler.yml | 77 - .../source/.github/pull_request_template.md | 19 +- .../source/.github/workflows/cache-seeder.yml | 72 + .../.github/workflows/cron-flake-updater.yml | 22 - .../.github/workflows/cron-licenses.yml | 6 +- .../.github/workflows/cron-renovate.yml | 32 + .../.github/workflows/cron-translations.yml | 6 +- .../.github/workflows/files-changed.yml | 53 +- .../.github/workflows/giteabot-backport.yml | 26 + .../source/.github/workflows/giteabot.yml | 64 + .../.github/workflows/pull-compliance.yml | 211 +- .../.github/workflows/pull-db-tests.yml | 186 +- .../.github/workflows/pull-docker-dryrun.yml | 51 +- .../.github/workflows/pull-e2e-tests.yml | 28 +- .../source/.github/workflows/pull-labeler.yml | 33 +- .../workflows/release-nightly-snapcraft.yml | 45 + .../.github/workflows/release-nightly.yml | 66 +- .../.github/workflows/release-tag-rc.yml | 69 +- .../.github/workflows/release-tag-version.yml | 69 +- package/gitea/source/.gitignore | 3 - package/gitea/source/.golangci.yml | 23 +- package/gitea/source/.npmrc | 7 - package/gitea/source/.shellcheckrc | 1 + package/gitea/source/CHANGELOG.md | 508 +- package/gitea/source/CONTRIBUTING.md | 473 +- package/gitea/source/Dockerfile | 16 +- package/gitea/source/Dockerfile.rootless | 16 +- package/gitea/source/MAINTAINERS | 2 +- package/gitea/source/Makefile | 400 +- package/gitea/source/README.md | 61 +- package/gitea/source/README.zh-cn.md | 8 +- package/gitea/source/README.zh-tw.md | 8 +- .../source/assets/codemirror-languages.json | 1277 + package/gitea/source/assets/go-licenses.json | 186 +- .../gitea/source/build/generate-bindata.go | 2 +- package/gitea/source/build/generate-emoji.go | 2 +- .../gitea/source/build/generate-gitignores.go | 5 +- .../source/build/generate-go-licenses.go | 4 +- .../gitea/source/build/generate-openapi.go | 97 + .../gitea/source/build/openapi3gen/convert.go | 386 + .../source/build/openapi3gen/convert_test.go | 218 + .../source/build/openapi3gen/enumscan.go | 192 + .../source/build/openapi3gen/enumscan_test.go | 249 + package/gitea/source/build/test-env-check.sh | 24 - .../gitea/source/build/test-env-prepare.sh | 11 - package/gitea/source/cmd/actions.go | 4 +- package/gitea/source/cmd/admin.go | 12 +- package/gitea/source/cmd/admin_auth.go | 6 +- package/gitea/source/cmd/admin_auth_ldap.go | 6 +- .../gitea/source/cmd/admin_auth_ldap_test.go | 6 +- package/gitea/source/cmd/admin_auth_oauth.go | 6 +- .../gitea/source/cmd/admin_auth_oauth_test.go | 4 +- package/gitea/source/cmd/admin_auth_smtp.go | 6 +- .../gitea/source/cmd/admin_auth_smtp_test.go | 4 +- package/gitea/source/cmd/admin_heatmap.go | 10 +- .../gitea/source/cmd/admin_heatmap_test.go | 16 +- package/gitea/source/cmd/admin_regenerate.go | 6 +- .../source/cmd/admin_user_change_password.go | 10 +- .../cmd/admin_user_change_password_test.go | 11 +- package/gitea/source/cmd/admin_user_create.go | 15 +- .../source/cmd/admin_user_create_test.go | 9 +- package/gitea/source/cmd/admin_user_delete.go | 8 +- .../source/cmd/admin_user_delete_test.go | 8 +- .../cmd/admin_user_generate_access_token.go | 4 +- package/gitea/source/cmd/admin_user_list.go | 2 +- .../cmd/admin_user_must_change_password.go | 4 +- .../admin_user_must_change_password_test.go | 6 +- package/gitea/source/cmd/cert_test.go | 2 + package/gitea/source/cmd/cmd_test.go | 38 - package/gitea/source/cmd/cmdtest/cmd_test.go | 248 + package/gitea/source/cmd/config.go | 2 +- package/gitea/source/cmd/doctor.go | 17 +- package/gitea/source/cmd/doctor_convert.go | 6 +- package/gitea/source/cmd/doctor_test.go | 4 +- package/gitea/source/cmd/dump.go | 18 +- package/gitea/source/cmd/dump_repo.go | 16 +- package/gitea/source/cmd/embedded.go | 16 +- package/gitea/source/cmd/generate.go | 78 +- .../gitea/source/cmd/{cmd.go => helper.go} | 33 +- package/gitea/source/cmd/hook.go | 149 +- package/gitea/source/cmd/keys.go | 4 +- package/gitea/source/cmd/mailer.go | 12 +- package/gitea/source/cmd/main.go | 37 +- package/gitea/source/cmd/main_test.go | 236 +- package/gitea/source/cmd/manager.go | 2 +- package/gitea/source/cmd/manager_logging.go | 235 +- package/gitea/source/cmd/migrate.go | 8 +- package/gitea/source/cmd/migrate_storage.go | 22 +- .../gitea/source/cmd/migrate_storage_test.go | 14 +- package/gitea/source/cmd/restore_repo.go | 4 +- package/gitea/source/cmd/serv.go | 53 +- package/gitea/source/cmd/serv_test.go | 56 + package/gitea/source/cmd/web.go | 26 +- package/gitea/source/cmd/web_acme.go | 28 +- package/gitea/source/cmd/web_graceful.go | 6 +- package/gitea/source/cmd/web_https.go | 6 +- package/gitea/source/contrib/backport/README | 41 - .../gitea/source/contrib/backport/backport.go | 456 - .../contrib/{ide => development}/README.md | 4 +- .../{ide => development}/vscode/launch.json | 13 - .../contrib/development/vscode/settings.json | 4 + .../contrib/development/vscode/tasks.json | 27 + .../.gitignore | 0 .../Makefile | 0 .../README.md | 0 .../config.libsonnet | 0 .../dashboards/dashboards.libsonnet | 0 .../dashboards/overview.libsonnet | 0 .../jsonnetfile.json | 0 .../jsonnetfile.lock.json | 0 .../lib/alerts.jsonnet | 0 .../lib/dashboards.jsonnet | 0 .../lib/rules.jsonnet | 0 .../mixin.libsonnet | 0 .../source/contrib/ide/vscode/settings.json | 4 - .../source/contrib/ide/vscode/tasks.json | 49 - .../gitea/source/contrib/init/centos/gitea | 93 - .../gitea/source/contrib/init/debian/gitea | 89 - package/gitea/source/contrib/init/suse/gitea | 115 - .../privacy.html.sample | 0 .../{legal => sample-page}/tos.html.sample | 0 .../contrib/{init => service}/freebsd/gitea | 0 .../contrib/{init => service}/gentoo/gitea | 0 .../{ => service}/launchd/io.gitea.web.plist | 0 .../contrib/{init => service}/openbsd/gitea | 0 .../contrib/{init => service}/openwrt/gitea | 0 .../contrib/{init => service}/sunos/gitea.xml | 0 .../contrib/{ => service}/supervisor/gitea | 0 .../{ => service}/systemd/gitea.service | 0 .../{init/ubuntu => service/sysvinit}/gitea | 7 +- .../source/contrib/update_dependencies.sh | 8 - package/gitea/source/contrib/upgrade.sh | 1 + .../source/docker/root/etc/templates/app.ini | 2 - .../docker/rootless/etc/templates/app.ini | 2 - .../usr/local/bin/docker-entrypoint.sh | 2 +- .../rootless/usr/local/bin/docker-setup.sh | 24 +- package/gitea/source/docs/build-setup.md | 67 + package/gitea/source/docs/build-source.md | 92 + .../gitea/source/docs/community-governance.md | 249 + package/gitea/source/docs/development.md | 141 + .../gitea/source/docs/guidelines-backend.md | 132 + .../gitea/source/docs/guidelines-frontend.md | 98 + .../source/docs/guidelines-refactoring.md | 38 + .../gitea/source/docs/release-management.md | 115 + package/gitea/source/docs/testing.md | 151 + package/gitea/source/eslint.config.ts | 250 +- package/gitea/source/eslint.json.config.ts | 8 +- package/gitea/source/flake.lock | 6 +- package/gitea/source/flake.nix | 2 +- package/gitea/source/go.mod | 199 +- package/gitea/source/go.sum | 410 +- package/gitea/source/main.go | 16 +- .../gitea/source/models/actions/artifact.go | 83 +- .../source/models/actions/artifact_test.go | 27 + package/gitea/source/models/actions/config.go | 10 +- .../gitea/source/models/actions/main_test.go | 3 +- package/gitea/source/models/actions/run.go | 246 +- .../source/models/actions/run_attempt.go | 193 + .../source/models/actions/run_attempt_list.go | 46 + .../gitea/source/models/actions/run_job.go | 593 +- .../source/models/actions/run_job_list.go | 63 +- .../models/actions/run_job_list_test.go | 61 + .../models/actions/run_job_status_test.go | 19 +- .../source/models/actions/run_job_summary.go | 207 + .../source/models/actions/run_job_test.go | 288 + .../gitea/source/models/actions/run_list.go | 132 +- .../source/models/actions/run_list_test.go | 165 + .../gitea/source/models/actions/run_test.go | 65 +- package/gitea/source/models/actions/runner.go | 78 +- .../source/models/actions/runner_list.go | 8 +- .../source/models/actions/runner_test.go | 83 + .../source/models/actions/runner_token.go | 15 +- .../models/actions/runner_token_test.go | 2 +- .../gitea/source/models/actions/schedule.go | 12 +- .../source/models/actions/schedule_list.go | 51 +- .../source/models/actions/schedule_spec.go | 6 +- .../models/actions/schedule_spec_list.go | 6 +- .../models/actions/schedule_spec_test.go | 2 +- .../source/models/actions/scoped_workflow.go | 179 + .../models/actions/scoped_workflow_test.go | 139 + package/gitea/source/models/actions/status.go | 72 +- .../source/models/actions/status_test.go | 104 + package/gitea/source/models/actions/task.go | 401 +- .../gitea/source/models/actions/task_list.go | 6 +- .../source/models/actions/task_output.go | 2 +- .../gitea/source/models/actions/task_step.go | 4 +- .../gitea/source/models/actions/task_test.go | 375 +- .../source/models/actions/tasks_version.go | 6 +- .../models/actions/token_permissions.go | 4 +- package/gitea/source/models/actions/utils.go | 22 +- .../gitea/source/models/actions/utils_test.go | 2 +- .../gitea/source/models/actions/variable.go | 8 +- .../gitea/source/models/activities/action.go | 24 +- .../source/models/activities/action_list.go | 22 +- .../source/models/activities/action_test.go | 16 +- .../models/activities/heatmap_contribution.go | 4 +- .../activities/heatmap_contribution_test.go | 10 +- .../source/models/activities/main_test.go | 6 +- .../source/models/activities/notification.go | 14 +- .../models/activities/notification_list.go | 18 +- .../models/activities/notification_test.go | 10 +- .../source/models/activities/repo_activity.go | 23 +- .../source/models/activities/statistic.go | 28 +- .../source/models/activities/user_heatmap.go | 12 +- .../models/activities/user_heatmap_test.go | 19 +- package/gitea/source/models/admin/task.go | 34 +- package/gitea/source/models/asymkey/error.go | 24 +- .../gitea/source/models/asymkey/gpg_key.go | 6 +- .../source/models/asymkey/gpg_key_add.go | 4 +- .../asymkey/gpg_key_commit_verification.go | 11 +- .../source/models/asymkey/gpg_key_import.go | 2 +- .../source/models/asymkey/gpg_key_list.go | 2 +- .../source/models/asymkey/gpg_key_test.go | 8 +- .../source/models/asymkey/gpg_key_verify.go | 8 +- .../source/models/asymkey/key_display.go | 6 +- .../gitea/source/models/asymkey/main_test.go | 2 +- .../gitea/source/models/asymkey/ssh_key.go | 16 +- .../models/asymkey/ssh_key_authorized_keys.go | 8 +- .../asymkey/ssh_key_authorized_keys_test.go | 4 +- .../source/models/asymkey/ssh_key_deploy.go | 14 +- .../models/asymkey/ssh_key_fingerprint.go | 2 +- .../source/models/asymkey/ssh_key_parse.go | 26 +- .../models/asymkey/ssh_key_principals.go | 8 +- .../source/models/asymkey/ssh_key_test.go | 16 +- .../source/models/asymkey/ssh_key_verify.go | 4 +- .../gitea/source/models/auth/access_token.go | 80 +- .../source/models/auth/access_token_scope.go | 32 +- .../models/auth/access_token_scope_test.go | 23 + .../source/models/auth/access_token_test.go | 13 +- .../gitea/source/models/auth/auth_token.go | 6 +- package/gitea/source/models/auth/main_test.go | 12 +- package/gitea/source/models/auth/oauth2.go | 29 +- .../gitea/source/models/auth/oauth2_list.go | 2 +- .../gitea/source/models/auth/oauth2_test.go | 58 +- package/gitea/source/models/auth/session.go | 4 +- package/gitea/source/models/auth/source.go | 14 +- .../gitea/source/models/auth/source_test.go | 6 +- package/gitea/source/models/auth/twofactor.go | 49 +- .../source/models/auth/twofactor_test.go | 47 + package/gitea/source/models/auth/webauthn.go | 16 +- .../gitea/source/models/auth/webauthn_test.go | 4 +- package/gitea/source/models/avatars/avatar.go | 20 +- .../source/models/avatars/avatar_test.go | 8 +- .../gitea/source/models/avatars/main_test.go | 8 +- package/gitea/source/models/db/collation.go | 17 +- package/gitea/source/models/db/common.go | 4 +- package/gitea/source/models/db/conn.go | 187 + .../db/conn_test.go} | 10 +- package/gitea/source/models/db/context.go | 15 +- .../gitea/source/models/db/context_test.go | 4 +- package/gitea/source/models/db/convert.go | 2 +- .../source/models/db/driver_postgresschema.go | 49 + .../source/models/db/driver_sqlite_mattn.go | 31 + .../source/models/db/driver_sqlite_modernc.go | 41 + package/gitea/source/models/db/engine.go | 60 +- package/gitea/source/models/db/engine_dump.go | 8 +- package/gitea/source/models/db/engine_hook.go | 12 +- package/gitea/source/models/db/engine_init.go | 34 +- package/gitea/source/models/db/engine_test.go | 14 +- package/gitea/source/models/db/error.go | 2 +- package/gitea/source/models/db/index.go | 2 +- package/gitea/source/models/db/index_test.go | 4 +- package/gitea/source/models/db/install/db.go | 4 +- package/gitea/source/models/db/iterate.go | 2 +- .../gitea/source/models/db/iterate_test.go | 6 +- package/gitea/source/models/db/list.go | 8 +- package/gitea/source/models/db/list_test.go | 6 +- package/gitea/source/models/db/log.go | 2 +- package/gitea/source/models/db/main_test.go | 6 +- package/gitea/source/models/db/name.go | 2 +- .../source/models/db/paginator/main_test.go | 2 +- .../models/db/paginator/paginator_test.go | 4 +- package/gitea/source/models/db/sequence.go | 2 +- .../models/db/sql_postgres_with_schema.go | 74 - package/gitea/source/models/dbfs/dbfile.go | 2 +- package/gitea/source/models/dbfs/dbfs.go | 2 +- package/gitea/source/models/dbfs/dbfs_test.go | 2 +- package/gitea/source/models/dbfs/main_test.go | 2 +- .../gitea/source/models/fixtures/access.yml | 2 + .../source/models/fixtures/access_token.yml | 2 + .../gitea/source/models/fixtures/action.yml | 2 + .../models/fixtures/action_artifact.yml | 2 + .../source/models/fixtures/action_run.yml | 21 +- .../source/models/fixtures/action_run_job.yml | 15 +- .../source/models/fixtures/action_runner.yml | 2 + .../models/fixtures/action_runner_token.yml | 2 + .../source/models/fixtures/action_task.yml | 20 +- .../models/fixtures/action_task_output.yml | 2 + .../source/models/fixtures/attachment.yml | 2 + .../gitea/source/models/fixtures/badge.yml | 2 + .../gitea/source/models/fixtures/branch.yml | 2 + .../source/models/fixtures/collaboration.yml | 2 + .../gitea/source/models/fixtures/comment.yml | 2 + .../source/models/fixtures/commit_status.yml | 2 + .../models/fixtures/commit_status_index.yml | 2 + .../source/models/fixtures/deploy_key.yml | 2 + .../source/models/fixtures/email_address.yml | 2 + .../models/fixtures/external_login_user.yml | 2 + .../gitea/source/models/fixtures/follow.yml | 2 + .../gitea/source/models/fixtures/gpg_key.yml | 2 + .../source/models/fixtures/gpg_key_import.yml | 2 + .../source/models/fixtures/hook_task.yml | 39 +- .../gitea/source/models/fixtures/issue.yml | 2 + .../models/fixtures/issue_assignees.yml | 2 + .../source/models/fixtures/issue_index.yml | 2 + .../source/models/fixtures/issue_label.yml | 2 + .../source/models/fixtures/issue_pin.yml | 2 + .../source/models/fixtures/issue_user.yml | 2 + .../source/models/fixtures/issue_watch.yml | 2 + .../gitea/source/models/fixtures/label.yml | 2 + .../models/fixtures/lfs_meta_object.yml | 2 + .../source/models/fixtures/login_source.yml | 2 + .../source/models/fixtures/milestone.yml | 2 + .../gitea/source/models/fixtures/mirror.yml | 2 + .../gitea/source/models/fixtures/notice.yml | 2 + .../source/models/fixtures/notification.yml | 2 + .../models/fixtures/oauth2_application.yml | 4 +- .../fixtures/oauth2_authorization_code.yml | 17 +- .../source/models/fixtures/oauth2_grant.yml | 2 + .../gitea/source/models/fixtures/org_user.yml | 2 + .../gitea/source/models/fixtures/project.yml | 2 + .../source/models/fixtures/project_board.yml | 2 + .../source/models/fixtures/project_issue.yml | 2 + .../models/fixtures/protected_branch.yml | 2 + .../source/models/fixtures/protected_tag.yml | 2 + .../source/models/fixtures/public_key.yml | 2 + .../source/models/fixtures/pull_request.yml | 2 + .../gitea/source/models/fixtures/reaction.yml | 2 + .../gitea/source/models/fixtures/release.yml | 2 + .../source/models/fixtures/renamed_branch.yml | 2 + .../source/models/fixtures/repo_archiver.yml | 2 + .../models/fixtures/repo_indexer_status.yml | 2 + .../source/models/fixtures/repo_license.yml | 2 + .../source/models/fixtures/repo_redirect.yml | 2 + .../source/models/fixtures/repo_topic.yml | 2 + .../source/models/fixtures/repo_transfer.yml | 2 + .../source/models/fixtures/repo_unit.yml | 2 + .../source/models/fixtures/repository.yml | 2 + .../gitea/source/models/fixtures/review.yml | 2 + package/gitea/source/models/fixtures/star.yml | 2 + .../source/models/fixtures/stopwatch.yml | 2 + .../source/models/fixtures/system_setting.yml | 2 + package/gitea/source/models/fixtures/team.yml | 2 + .../source/models/fixtures/team_repo.yml | 2 + .../source/models/fixtures/team_unit.yml | 2 + .../source/models/fixtures/team_user.yml | 2 + .../gitea/source/models/fixtures/topic.yml | 2 + .../source/models/fixtures/tracked_time.yml | 2 + .../source/models/fixtures/two_factor.yml | 2 + package/gitea/source/models/fixtures/user.yml | 2 + .../source/models/fixtures/user_blocking.yml | 2 + .../source/models/fixtures/user_open_id.yml | 2 + .../source/models/fixtures/user_redirect.yml | 2 + .../gitea/source/models/fixtures/watch.yml | 2 + .../models/fixtures/webauthn_credential.yml | 2 + .../gitea/source/models/fixtures/webhook.yml | 54 +- package/gitea/source/models/git/branch.go | 30 +- .../gitea/source/models/git/branch_list.go | 29 +- .../gitea/source/models/git/branch_test.go | 20 +- .../gitea/source/models/git/commit_status.go | 53 +- .../models/git/commit_status_summary.go | 6 +- .../source/models/git/commit_status_test.go | 16 +- package/gitea/source/models/git/lfs.go | 28 +- package/gitea/source/models/git/lfs_lock.go | 10 +- .../gitea/source/models/git/lfs_lock_list.go | 6 +- .../gitea/source/models/git/lfs_lock_test.go | 6 +- package/gitea/source/models/git/lfs_test.go | 16 +- package/gitea/source/models/git/main_test.go | 8 +- .../source/models/git/protected_branch.go | 65 +- .../models/git/protected_branch_list.go | 6 +- .../models/git/protected_branch_test.go | 55 +- .../gitea/source/models/git/protected_tag.go | 13 +- .../source/models/git/protected_tag_test.go | 4 +- .../source/models/gituser/avatar_stack.go | 52 + .../gitea/source/models/gituser/gituser.go | 63 + .../gitea/source/models/issues/assignees.go | 16 +- .../source/models/issues/assignees_test.go | 12 +- package/gitea/source/models/issues/comment.go | 103 +- .../source/models/issues/comment_code.go | 24 +- .../source/models/issues/comment_list.go | 80 +- .../source/models/issues/comment_test.go | 27 +- .../source/models/issues/content_history.go | 10 +- .../models/issues/content_history_test.go | 8 +- .../gitea/source/models/issues/dependency.go | 14 +- .../source/models/issues/dependency_test.go | 6 +- package/gitea/source/models/issues/issue.go | 86 +- .../gitea/source/models/issues/issue_index.go | 2 +- .../gitea/source/models/issues/issue_label.go | 6 +- .../source/models/issues/issue_label_test.go | 6 +- .../gitea/source/models/issues/issue_list.go | 23 +- .../source/models/issues/issue_list_test.go | 29 +- .../gitea/source/models/issues/issue_lock.go | 4 +- .../gitea/source/models/issues/issue_pin.go | 29 +- .../source/models/issues/issue_project.go | 185 +- .../models/issues/issue_project_multi_test.go | 149 + .../source/models/issues/issue_search.go | 74 +- .../gitea/source/models/issues/issue_stats.go | 15 +- .../gitea/source/models/issues/issue_test.go | 38 +- .../source/models/issues/issue_update.go | 64 +- .../source/models/issues/issue_update_test.go | 33 + .../gitea/source/models/issues/issue_user.go | 4 +- .../source/models/issues/issue_user_test.go | 8 +- .../gitea/source/models/issues/issue_watch.go | 12 +- .../source/models/issues/issue_watch_test.go | 6 +- .../gitea/source/models/issues/issue_xref.go | 22 +- .../source/models/issues/issue_xref_test.go | 12 +- package/gitea/source/models/issues/label.go | 73 +- .../gitea/source/models/issues/label_test.go | 62 +- .../gitea/source/models/issues/main_test.go | 14 +- .../gitea/source/models/issues/milestone.go | 12 +- .../source/models/issues/milestone_list.go | 4 +- .../source/models/issues/milestone_test.go | 16 +- package/gitea/source/models/issues/pull.go | 46 +- .../gitea/source/models/issues/pull_list.go | 23 +- .../source/models/issues/pull_list_test.go | 14 +- .../gitea/source/models/issues/pull_test.go | 31 +- .../gitea/source/models/issues/reaction.go | 16 +- package/gitea/source/models/issues/review.go | 109 +- .../gitea/source/models/issues/review_list.go | 14 +- .../gitea/source/models/issues/review_test.go | 102 +- .../gitea/source/models/issues/stopwatch.go | 12 +- .../source/models/issues/stopwatch_test.go | 6 +- .../source/models/issues/tracked_time.go | 17 +- .../source/models/issues/tracked_time_test.go | 8 +- package/gitea/source/models/main_test.go | 14 +- .../gitea/source/models/migrations/base/db.go | 16 +- .../source/models/migrations/base/db_test.go | 15 +- .../source/models/migrations/base/tests.go | 225 - .../source/models/migrations/migrations.go | 88 +- .../models/migrations/migrations_test.go | 2 +- .../models/migrations/migrationtest/tests.go | 120 + .../source/models/migrations/v1_10/v100.go | 4 +- .../source/models/migrations/v1_10/v101.go | 6 +- .../source/models/migrations/v1_10/v88.go | 4 +- .../source/models/migrations/v1_10/v89.go | 4 +- .../source/models/migrations/v1_10/v90.go | 4 +- .../source/models/migrations/v1_10/v91.go | 4 +- .../source/models/migrations/v1_10/v92.go | 5 +- .../source/models/migrations/v1_10/v93.go | 4 +- .../source/models/migrations/v1_10/v94.go | 4 +- .../source/models/migrations/v1_10/v95.go | 4 +- .../source/models/migrations/v1_10/v96.go | 9 +- .../source/models/migrations/v1_10/v97.go | 4 +- .../source/models/migrations/v1_10/v98.go | 4 +- .../source/models/migrations/v1_10/v99.go | 7 +- .../source/models/migrations/v1_11/v102.go | 7 +- .../source/models/migrations/v1_11/v103.go | 6 +- .../source/models/migrations/v1_11/v104.go | 7 +- .../source/models/migrations/v1_11/v105.go | 6 +- .../source/models/migrations/v1_11/v106.go | 6 +- .../source/models/migrations/v1_11/v107.go | 6 +- .../source/models/migrations/v1_11/v108.go | 6 +- .../source/models/migrations/v1_11/v109.go | 6 +- .../source/models/migrations/v1_11/v110.go | 5 +- .../source/models/migrations/v1_11/v111.go | 8 +- .../source/models/migrations/v1_11/v112.go | 10 +- .../source/models/migrations/v1_11/v113.go | 4 +- .../source/models/migrations/v1_11/v114.go | 4 +- .../source/models/migrations/v1_11/v115.go | 13 +- .../source/models/migrations/v1_11/v116.go | 6 +- .../source/models/migrations/v1_12/v117.go | 6 +- .../source/models/migrations/v1_12/v118.go | 6 +- .../source/models/migrations/v1_12/v119.go | 6 +- .../source/models/migrations/v1_12/v120.go | 6 +- .../source/models/migrations/v1_12/v121.go | 4 +- .../source/models/migrations/v1_12/v122.go | 6 +- .../source/models/migrations/v1_12/v123.go | 6 +- .../source/models/migrations/v1_12/v124.go | 6 +- .../source/models/migrations/v1_12/v125.go | 4 +- .../source/models/migrations/v1_12/v126.go | 5 +- .../source/models/migrations/v1_12/v127.go | 7 +- .../source/models/migrations/v1_12/v128.go | 13 +- .../source/models/migrations/v1_12/v129.go | 6 +- .../source/models/migrations/v1_12/v130.go | 9 +- .../source/models/migrations/v1_12/v131.go | 4 +- .../source/models/migrations/v1_12/v132.go | 4 +- .../source/models/migrations/v1_12/v133.go | 4 +- .../source/models/migrations/v1_12/v134.go | 11 +- .../source/models/migrations/v1_12/v135.go | 4 +- .../source/models/migrations/v1_12/v136.go | 15 +- .../source/models/migrations/v1_12/v137.go | 6 +- .../source/models/migrations/v1_12/v138.go | 4 +- .../source/models/migrations/v1_12/v139.go | 7 +- .../source/models/migrations/v1_13/v140.go | 9 +- .../source/models/migrations/v1_13/v141.go | 4 +- .../source/models/migrations/v1_13/v142.go | 6 +- .../source/models/migrations/v1_13/v143.go | 7 +- .../source/models/migrations/v1_13/v144.go | 6 +- .../source/models/migrations/v1_13/v145.go | 7 +- .../source/models/migrations/v1_13/v146.go | 7 +- .../source/models/migrations/v1_13/v147.go | 7 +- .../source/models/migrations/v1_13/v148.go | 6 +- .../source/models/migrations/v1_13/v149.go | 7 +- .../source/models/migrations/v1_13/v150.go | 9 +- .../source/models/migrations/v1_13/v151.go | 8 +- .../source/models/migrations/v1_13/v152.go | 4 +- .../source/models/migrations/v1_13/v153.go | 6 +- .../source/models/migrations/v1_13/v154.go | 7 +- .../models/migrations/v1_14/main_test.go | 4 +- .../source/models/migrations/v1_14/v155.go | 4 +- .../source/models/migrations/v1_14/v156.go | 11 +- .../source/models/migrations/v1_14/v157.go | 6 +- .../source/models/migrations/v1_14/v158.go | 9 +- .../source/models/migrations/v1_14/v159.go | 9 +- .../source/models/migrations/v1_14/v160.go | 6 +- .../source/models/migrations/v1_14/v161.go | 7 +- .../source/models/migrations/v1_14/v162.go | 7 +- .../source/models/migrations/v1_14/v163.go | 7 +- .../source/models/migrations/v1_14/v164.go | 4 +- .../source/models/migrations/v1_14/v165.go | 6 +- .../source/models/migrations/v1_14/v166.go | 5 +- .../source/models/migrations/v1_14/v167.go | 4 +- .../source/models/migrations/v1_14/v168.go | 4 +- .../source/models/migrations/v1_14/v169.go | 6 +- .../source/models/migrations/v1_14/v170.go | 4 +- .../source/models/migrations/v1_14/v171.go | 4 +- .../source/models/migrations/v1_14/v172.go | 7 +- .../source/models/migrations/v1_14/v173.go | 4 +- .../source/models/migrations/v1_14/v174.go | 4 +- .../source/models/migrations/v1_14/v175.go | 9 +- .../source/models/migrations/v1_14/v176.go | 6 +- .../models/migrations/v1_14/v176_test.go | 4 +- .../source/models/migrations/v1_14/v177.go | 4 +- .../models/migrations/v1_14/v177_test.go | 6 +- .../models/migrations/v1_15/main_test.go | 4 +- .../source/models/migrations/v1_15/v178.go | 6 +- .../source/models/migrations/v1_15/v179.go | 6 +- .../source/models/migrations/v1_15/v180.go | 8 +- .../source/models/migrations/v1_15/v181.go | 4 +- .../models/migrations/v1_15/v181_test.go | 4 +- .../source/models/migrations/v1_15/v182.go | 6 +- .../models/migrations/v1_15/v182_test.go | 4 +- .../source/models/migrations/v1_15/v183.go | 7 +- .../source/models/migrations/v1_15/v184.go | 9 +- .../source/models/migrations/v1_15/v185.go | 6 +- .../source/models/migrations/v1_15/v186.go | 7 +- .../source/models/migrations/v1_15/v187.go | 7 +- .../source/models/migrations/v1_15/v188.go | 4 +- .../models/migrations/v1_16/main_test.go | 4 +- .../source/models/migrations/v1_16/v189.go | 9 +- .../models/migrations/v1_16/v189_test.go | 6 +- .../source/models/migrations/v1_16/v190.go | 4 +- .../source/models/migrations/v1_16/v191.go | 7 +- .../source/models/migrations/v1_16/v192.go | 7 +- .../source/models/migrations/v1_16/v193.go | 6 +- .../models/migrations/v1_16/v193_test.go | 4 +- .../source/models/migrations/v1_16/v194.go | 4 +- .../source/models/migrations/v1_16/v195.go | 4 +- .../models/migrations/v1_16/v195_test.go | 4 +- .../source/models/migrations/v1_16/v196.go | 4 +- .../source/models/migrations/v1_16/v197.go | 6 +- .../source/models/migrations/v1_16/v198.go | 7 +- .../source/models/migrations/v1_16/v200.go | 4 +- .../source/models/migrations/v1_16/v201.go | 6 +- .../source/models/migrations/v1_16/v202.go | 4 +- .../source/models/migrations/v1_16/v203.go | 6 +- .../source/models/migrations/v1_16/v204.go | 4 +- .../source/models/migrations/v1_16/v205.go | 6 +- .../source/models/migrations/v1_16/v206.go | 4 +- .../source/models/migrations/v1_16/v207.go | 6 +- .../source/models/migrations/v1_16/v208.go | 6 +- .../source/models/migrations/v1_16/v209.go | 6 +- .../source/models/migrations/v1_16/v210.go | 8 +- .../models/migrations/v1_16/v210_test.go | 6 +- .../models/migrations/v1_17/main_test.go | 4 +- .../source/models/migrations/v1_17/v211.go | 6 +- .../source/models/migrations/v1_17/v212.go | 7 +- .../source/models/migrations/v1_17/v213.go | 6 +- .../source/models/migrations/v1_17/v214.go | 6 +- .../source/models/migrations/v1_17/v215.go | 9 +- .../source/models/migrations/v1_17/v217.go | 7 +- .../source/models/migrations/v1_17/v218.go | 8 +- .../source/models/migrations/v1_17/v219.go | 9 +- .../source/models/migrations/v1_17/v220.go | 8 +- .../source/models/migrations/v1_17/v221.go | 7 +- .../models/migrations/v1_17/v221_test.go | 4 +- .../source/models/migrations/v1_17/v222.go | 9 +- .../source/models/migrations/v1_17/v223.go | 11 +- .../models/migrations/v1_18/main_test.go | 4 +- .../source/models/migrations/v1_18/v224.go | 6 +- .../source/models/migrations/v1_18/v225.go | 7 +- .../source/models/migrations/v1_18/v226.go | 5 +- .../source/models/migrations/v1_18/v227.go | 7 +- .../source/models/migrations/v1_18/v228.go | 7 +- .../source/models/migrations/v1_18/v229.go | 6 +- .../models/migrations/v1_18/v229_test.go | 6 +- .../source/models/migrations/v1_18/v230.go | 6 +- .../models/migrations/v1_18/v230_test.go | 4 +- .../models/migrations/v1_19/main_test.go | 4 +- .../source/models/migrations/v1_19/v231.go | 6 +- .../source/models/migrations/v1_19/v232.go | 7 +- .../source/models/migrations/v1_19/v233.go | 31 +- .../models/migrations/v1_19/v233_test.go | 12 +- .../source/models/migrations/v1_19/v234.go | 7 +- .../source/models/migrations/v1_19/v235.go | 6 +- .../source/models/migrations/v1_19/v236.go | 7 +- .../source/models/migrations/v1_19/v237.go | 6 +- .../source/models/migrations/v1_19/v238.go | 7 +- .../source/models/migrations/v1_19/v239.go | 6 +- .../source/models/migrations/v1_19/v240.go | 8 +- .../source/models/migrations/v1_19/v241.go | 6 +- .../source/models/migrations/v1_19/v242.go | 7 +- .../source/models/migrations/v1_19/v243.go | 6 +- .../models/migrations/v1_20/main_test.go | 4 +- .../source/models/migrations/v1_20/v244.go | 6 +- .../source/models/migrations/v1_20/v245.go | 9 +- .../source/models/migrations/v1_20/v246.go | 6 +- .../source/models/migrations/v1_20/v247.go | 7 +- .../source/models/migrations/v1_20/v248.go | 4 +- .../source/models/migrations/v1_20/v249.go | 6 +- .../source/models/migrations/v1_20/v250.go | 7 +- .../source/models/migrations/v1_20/v251.go | 7 +- .../source/models/migrations/v1_20/v252.go | 7 +- .../source/models/migrations/v1_20/v253.go | 7 +- .../source/models/migrations/v1_20/v254.go | 6 +- .../source/models/migrations/v1_20/v255.go | 7 +- .../source/models/migrations/v1_20/v256.go | 6 +- .../source/models/migrations/v1_20/v257.go | 7 +- .../source/models/migrations/v1_20/v258.go | 6 +- .../source/models/migrations/v1_20/v259.go | 7 +- .../models/migrations/v1_20/v259_test.go | 4 +- .../models/migrations/v1_21/main_test.go | 4 +- .../source/models/migrations/v1_21/v260.go | 7 +- .../source/models/migrations/v1_21/v261.go | 7 +- .../source/models/migrations/v1_21/v262.go | 6 +- .../source/models/migrations/v1_21/v263.go | 4 +- .../source/models/migrations/v1_21/v264.go | 8 +- .../source/models/migrations/v1_21/v265.go | 6 +- .../source/models/migrations/v1_21/v266.go | 6 +- .../source/models/migrations/v1_21/v267.go | 7 +- .../source/models/migrations/v1_21/v268.go | 6 +- .../source/models/migrations/v1_21/v269.go | 6 +- .../source/models/migrations/v1_21/v270.go | 6 +- .../source/models/migrations/v1_21/v271.go | 7 +- .../source/models/migrations/v1_21/v272.go | 6 +- .../source/models/migrations/v1_21/v273.go | 7 +- .../source/models/migrations/v1_21/v274.go | 9 +- .../source/models/migrations/v1_21/v275.go | 6 +- .../source/models/migrations/v1_21/v276.go | 15 +- .../source/models/migrations/v1_21/v277.go | 6 +- .../source/models/migrations/v1_21/v278.go | 6 +- .../source/models/migrations/v1_21/v279.go | 4 +- .../models/migrations/v1_22/main_test.go | 4 +- .../source/models/migrations/v1_22/v280.go | 6 +- .../source/models/migrations/v1_22/v281.go | 7 +- .../source/models/migrations/v1_22/v282.go | 6 +- .../source/models/migrations/v1_22/v283.go | 5 +- .../models/migrations/v1_22/v283_test.go | 4 +- .../source/models/migrations/v1_22/v284.go | 4 +- .../source/models/migrations/v1_22/v285.go | 4 +- .../source/models/migrations/v1_22/v286.go | 11 +- .../models/migrations/v1_22/v286_test.go | 8 +- .../source/models/migrations/v1_22/v287.go | 6 +- .../models/migrations/v1_22/v287_test.go | 4 +- .../source/models/migrations/v1_22/v288.go | 7 +- .../source/models/migrations/v1_22/v289.go | 8 +- .../source/models/migrations/v1_22/v290.go | 4 +- .../source/models/migrations/v1_22/v291.go | 8 +- .../source/models/migrations/v1_22/v293.go | 11 +- .../models/migrations/v1_22/v293_test.go | 6 +- .../source/models/migrations/v1_22/v294.go | 5 +- .../models/migrations/v1_22/v294_test.go | 4 +- .../source/models/migrations/v1_22/v295.go | 6 +- .../source/models/migrations/v1_22/v296.go | 4 +- .../source/models/migrations/v1_22/v297.go | 7 +- .../source/models/migrations/v1_22/v298.go | 4 +- .../models/migrations/v1_23/main_test.go | 4 +- .../source/models/migrations/v1_23/v299.go | 8 +- .../source/models/migrations/v1_23/v300.go | 8 +- .../source/models/migrations/v1_23/v301.go | 8 +- .../source/models/migrations/v1_23/v302.go | 5 +- .../models/migrations/v1_23/v302_test.go | 6 +- .../source/models/migrations/v1_23/v303.go | 4 +- .../source/models/migrations/v1_23/v304.go | 8 +- .../models/migrations/v1_23/v304_test.go | 6 +- .../source/models/migrations/v1_23/v305.go | 7 +- .../source/models/migrations/v1_23/v306.go | 8 +- .../source/models/migrations/v1_23/v307.go | 7 +- .../source/models/migrations/v1_23/v308.go | 6 +- .../source/models/migrations/v1_23/v309.go | 6 +- .../source/models/migrations/v1_23/v310.go | 4 +- .../source/models/migrations/v1_23/v311.go | 4 +- .../source/models/migrations/v1_24/v312.go | 4 +- .../source/models/migrations/v1_24/v313.go | 7 +- .../source/models/migrations/v1_24/v314.go | 6 +- .../source/models/migrations/v1_24/v315.go | 4 +- .../source/models/migrations/v1_24/v316.go | 4 +- .../source/models/migrations/v1_24/v317.go | 6 +- .../source/models/migrations/v1_24/v318.go | 5 +- .../source/models/migrations/v1_24/v319.go | 4 +- .../source/models/migrations/v1_24/v320.go | 5 +- .../models/migrations/v1_25/main_test.go | 4 +- .../source/models/migrations/v1_25/v321.go | 8 +- .../models/migrations/v1_25/v321_test.go | 10 +- .../source/models/migrations/v1_25/v322.go | 6 +- .../models/migrations/v1_25/v322_test.go | 8 +- .../models/migrations/v1_26/main_test.go | 4 +- .../source/models/migrations/v1_26/v323.go | 4 +- .../source/models/migrations/v1_26/v324.go | 4 +- .../source/models/migrations/v1_26/v325.go | 6 +- .../models/migrations/v1_26/v325_test.go | 6 +- .../source/models/migrations/v1_26/v326.go | 53 +- .../models/migrations/v1_26/v326_test.go | 18 +- .../source/models/migrations/v1_26/v327.go | 8 +- .../models/migrations/v1_26/v327_test.go | 4 +- .../source/models/migrations/v1_26/v328.go | 4 +- .../source/models/migrations/v1_26/v329.go | 5 +- .../models/migrations/v1_26/v329_test.go | 4 +- .../source/models/migrations/v1_26/v330.go | 4 +- .../source/models/migrations/v1_26/v331.go | 38 - .../models/migrations/v1_27/main_test.go | 14 + .../source/models/migrations/v1_27/v331.go | 159 + .../models/migrations/v1_27/v331_test.go | 156 + .../source/models/migrations/v1_27/v332.go | 74 + .../models/migrations/v1_27/v332_test.go | 40 + .../source/models/migrations/v1_27/v333.go | 24 + .../models/migrations/v1_27/v333_test.go | 60 + .../source/models/migrations/v1_27/v334.go | 22 + .../models/migrations/v1_27/v334_test.go | 36 + .../source/models/migrations/v1_27/v335.go | 33 + .../source/models/migrations/v1_27/v336.go | 30 + .../source/models/migrations/v1_27/v337.go | 36 + .../source/models/migrations/v1_27/v338.go | 73 + .../models/migrations/v1_27/v338_test.go | 52 + .../source/models/migrations/v1_27/v339.go | 40 + .../models/migrations/v1_27/v339_test.go | 72 + .../source/models/migrations/v1_27/v340.go | 24 + .../source/models/migrations/v1_27/v341.go | 80 + .../models/migrations/v1_27/v341_test.go | 80 + .../source/models/migrations/v1_27/v342.go | 42 + .../source/models/migrations/v1_6/v70.go | 7 +- .../source/models/migrations/v1_6/v71.go | 16 +- .../source/models/migrations/v1_6/v72.go | 7 +- .../source/models/migrations/v1_7/v73.go | 6 +- .../source/models/migrations/v1_7/v74.go | 4 +- .../source/models/migrations/v1_7/v75.go | 5 +- .../source/models/migrations/v1_8/v76.go | 7 +- .../source/models/migrations/v1_8/v77.go | 6 +- .../source/models/migrations/v1_8/v78.go | 7 +- .../source/models/migrations/v1_8/v79.go | 7 +- .../source/models/migrations/v1_8/v80.go | 4 +- .../source/models/migrations/v1_8/v81.go | 5 +- .../source/models/migrations/v1_9/v82.go | 11 +- .../source/models/migrations/v1_9/v83.go | 7 +- .../source/models/migrations/v1_9/v84.go | 6 +- .../source/models/migrations/v1_9/v85.go | 20 +- .../source/models/migrations/v1_9/v86.go | 6 +- .../source/models/migrations/v1_9/v87.go | 6 +- .../source/models/organization/main_test.go | 14 +- .../gitea/source/models/organization/org.go | 88 +- .../source/models/organization/org_list.go | 11 +- .../models/organization/org_list_test.go | 22 +- .../source/models/organization/org_test.go | 111 +- .../source/models/organization/org_user.go | 9 +- .../models/organization/org_user_test.go | 8 +- .../models/organization/org_worktime.go | 2 +- .../gitea/source/models/organization/team.go | 67 +- .../source/models/organization/team_invite.go | 13 +- .../models/organization/team_invite_test.go | 6 +- .../source/models/organization/team_list.go | 69 +- .../models/organization/team_list_test.go | 4 +- .../source/models/organization/team_repo.go | 6 +- .../models/organization/team_repo_test.go | 10 +- .../source/models/organization/team_test.go | 93 +- .../source/models/organization/team_unit.go | 22 +- .../source/models/organization/team_user.go | 12 +- .../source/models/packages/alpine/search.go | 4 +- .../source/models/packages/arch/search.go | 4 +- .../models/packages/conan/references.go | 10 +- .../source/models/packages/conan/search.go | 8 +- .../source/models/packages/conda/search.go | 6 +- .../models/packages/container/search.go | 12 +- .../source/models/packages/cran/search.go | 6 +- .../source/models/packages/debian/search.go | 6 +- .../source/models/packages/descriptor.go | 52 +- .../source/models/packages/nuget/search.go | 4 +- .../gitea/source/models/packages/package.go | 4 +- .../source/models/packages/package_blob.go | 20 +- .../models/packages/package_blob_test.go | 25 +- .../models/packages/package_blob_upload.go | 13 +- .../models/packages/package_cleanup_rule.go | 6 +- .../source/models/packages/package_file.go | 8 +- .../models/packages/package_property.go | 9 +- .../source/models/packages/package_test.go | 12 +- .../source/models/packages/package_version.go | 17 +- .../source/models/packages/rpm/search.go | 4 +- .../gitea/source/models/perm/access/access.go | 14 +- .../source/models/perm/access/access_test.go | 14 +- .../access/actions_repo_permission_test.go | 60 +- .../source/models/perm/access/main_test.go | 12 +- .../models/perm/access/repo_permission.go | 72 +- .../perm/access/repo_permission_test.go | 22 +- .../gitea/source/models/perm/access_mode.go | 2 +- package/gitea/source/models/project/column.go | 24 +- .../source/models/project/column_test.go | 4 +- package/gitea/source/models/project/issue.go | 51 +- .../gitea/source/models/project/main_test.go | 4 +- .../gitea/source/models/project/project.go | 25 +- .../source/models/project/project_test.go | 6 +- package/gitea/source/models/pull/automerge.go | 8 +- .../gitea/source/models/pull/review_state.go | 19 +- .../models/renderhelper/commit_checker.go | 26 +- .../source/models/renderhelper/main_test.go | 11 +- .../models/renderhelper/repo_comment.go | 12 +- .../models/renderhelper/repo_comment_test.go | 19 +- .../source/models/renderhelper/repo_file.go | 23 +- .../models/renderhelper/repo_file_test.go | 45 +- .../source/models/renderhelper/repo_wiki.go | 18 +- .../models/renderhelper/repo_wiki_test.go | 21 +- .../models/renderhelper/simple_document.go | 2 +- .../renderhelper/simple_document_test.go | 7 +- package/gitea/source/models/repo.go | 14 +- package/gitea/source/models/repo/archiver.go | 6 +- .../gitea/source/models/repo/attachment.go | 17 +- .../source/models/repo/attachment_test.go | 4 +- package/gitea/source/models/repo/avatar.go | 12 +- .../gitea/source/models/repo/avatar_test.go | 4 +- .../gitea/source/models/repo/collaboration.go | 62 +- .../source/models/repo/collaboration_test.go | 30 +- package/gitea/source/models/repo/fork.go | 4 +- package/gitea/source/models/repo/fork_test.go | 4 +- package/gitea/source/models/repo/git.go | 12 +- package/gitea/source/models/repo/issue.go | 6 +- .../source/models/repo/language_stats.go | 4 +- package/gitea/source/models/repo/license.go | 4 +- package/gitea/source/models/repo/main_test.go | 14 +- package/gitea/source/models/repo/mirror.go | 14 +- package/gitea/source/models/repo/org_repo.go | 40 +- .../models/repo/pull_request_default.go | 4 +- .../models/repo/pull_request_default_test.go | 84 +- .../gitea/source/models/repo/pushmirror.go | 10 +- .../source/models/repo/pushmirror_test.go | 8 +- package/gitea/source/models/repo/redirect.go | 10 +- .../gitea/source/models/repo/redirect_test.go | 4 +- package/gitea/source/models/repo/release.go | 17 +- .../gitea/source/models/repo/release_test.go | 6 +- package/gitea/source/models/repo/repo.go | 47 +- .../gitea/source/models/repo/repo_indexer.go | 2 +- package/gitea/source/models/repo/repo_list.go | 86 +- .../source/models/repo/repo_list_test.go | 81 +- package/gitea/source/models/repo/repo_test.go | 14 +- package/gitea/source/models/repo/repo_unit.go | 48 +- .../source/models/repo/repo_unit_actions.go | 33 +- .../models/repo/repo_unit_actions_test.go | 51 + .../source/models/repo/repo_unit_test.go | 4 +- package/gitea/source/models/repo/search.go | 2 +- package/gitea/source/models/repo/star.go | 14 +- package/gitea/source/models/repo/star_test.go | 8 +- package/gitea/source/models/repo/topic.go | 14 +- .../gitea/source/models/repo/topic_test.go | 6 +- package/gitea/source/models/repo/transfer.go | 12 +- package/gitea/source/models/repo/update.go | 4 +- package/gitea/source/models/repo/upload.go | 8 +- package/gitea/source/models/repo/user_repo.go | 38 +- .../source/models/repo/user_repo_test.go | 53 +- package/gitea/source/models/repo/watch.go | 22 +- .../gitea/source/models/repo/watch_test.go | 10 +- package/gitea/source/models/repo/wiki.go | 4 +- package/gitea/source/models/repo/wiki_test.go | 4 +- package/gitea/source/models/repo_test.go | 4 +- .../gitea/source/models/secret/main_test.go | 14 + package/gitea/source/models/secret/secret.go | 80 +- .../gitea/source/models/secret/secret_test.go | 174 + .../source/models/shared/types/ownertype.go | 2 +- .../gitea/source/models/system/appstate.go | 8 +- .../gitea/source/models/system/main_test.go | 10 +- package/gitea/source/models/system/notice.go | 23 +- .../gitea/source/models/system/notice_test.go | 6 +- package/gitea/source/models/system/setting.go | 8 +- .../source/models/system/setting_test.go | 6 +- package/gitea/source/models/unit/unit.go | 8 +- package/gitea/source/models/unit/unit_test.go | 2 +- .../source/models/unittest/consistency.go | 2 +- .../gitea/source/models/unittest/fixtures.go | 103 +- .../source/models/unittest/fixtures_loader.go | 36 +- .../source/models/unittest/fixtures_test.go | 10 +- .../gitea/source/models/unittest/fscopy.go | 4 +- .../gitea/source/models/unittest/mock_http.go | 142 + .../source/models/unittest/reflection.go | 2 +- .../gitea/source/models/unittest/testdb.go | 221 +- .../source/models/unittest/unit_tests.go | 4 +- package/gitea/source/models/user/avatar.go | 14 +- .../gitea/source/models/user/avatar_test.go | 8 +- package/gitea/source/models/user/badge.go | 25 +- .../gitea/source/models/user/badge_test.go | 8 +- package/gitea/source/models/user/block.go | 10 +- .../gitea/source/models/user/email_address.go | 23 +- .../source/models/user/email_address_test.go | 8 +- package/gitea/source/models/user/error.go | 23 +- .../source/models/user/external_login_user.go | 29 +- package/gitea/source/models/user/follow.go | 8 +- .../gitea/source/models/user/follow_test.go | 4 +- package/gitea/source/models/user/list.go | 4 +- package/gitea/source/models/user/main_test.go | 10 +- .../models/user/must_change_password.go | 4 +- package/gitea/source/models/user/openid.go | 8 +- .../gitea/source/models/user/openid_test.go | 6 +- package/gitea/source/models/user/redirect.go | 10 +- .../gitea/source/models/user/redirect_test.go | 4 +- package/gitea/source/models/user/search.go | 18 +- package/gitea/source/models/user/setting.go | 19 +- .../gitea/source/models/user/setting_test.go | 4 +- package/gitea/source/models/user/user.go | 140 +- package/gitea/source/models/user/user_list.go | 2 +- .../gitea/source/models/user/user_system.go | 2 +- package/gitea/source/models/user/user_test.go | 62 +- .../gitea/source/models/user/user_update.go | 2 +- .../gitea/source/models/webhook/hooktask.go | 12 +- .../gitea/source/models/webhook/main_test.go | 3 +- .../gitea/source/models/webhook/webhook.go | 18 +- .../source/models/webhook/webhook_system.go | 4 +- .../models/webhook/webhook_system_test.go | 32 +- .../source/models/webhook/webhook_test.go | 255 +- .../gitea/source/modules/actions/artifacts.go | 60 +- .../modules/actions/commit_status_info.go | 70 + .../gitea/source/modules/actions/github.go | 2 +- .../source/modules/actions/github_test.go | 2 +- .../modules/actions/jobparser/aliases.go | 120 + .../modules/actions/jobparser/aliases_test.go | 85 + .../modules/actions/jobparser/evaluator.go | 245 +- .../modules/actions/jobparser/interpeter.go | 15 +- .../modules/actions/jobparser/jobparser.go | 109 +- .../actions/jobparser/jobparser_test.go | 90 + .../source/modules/actions/jobparser/model.go | 190 +- .../modules/actions/jobparser/model_test.go | 203 +- .../actions/jobparser/roundtrip_test.go | 105 + .../testdata/continue_on_error_expr.in.yaml | 10 + .../testdata/continue_on_error_expr.out.yaml | 25 + .../source/modules/actions/jobparser/uses.go | 79 + .../modules/actions/jobparser/uses_test.go | 189 + .../actions/jobparser/workflow_call.go | 375 + .../actions/jobparser/workflow_call_test.go | 471 + package/gitea/source/modules/actions/log.go | 10 +- .../modules/actions/scoped_workflows.go | 90 + .../modules/actions/scoped_workflows_test.go | 62 + .../source/modules/actions/task_state.go | 11 +- .../source/modules/actions/task_state_test.go | 23 +- .../workflowpattern/workflow_pattern.go | 65 + .../workflowpattern/workflow_pattern_test.go | 416 + .../gitea/source/modules/actions/workflows.go | 273 +- .../source/modules/actions/workflows_test.go | 56 +- package/gitea/source/modules/assetfs/embed.go | 4 +- .../gitea/source/modules/assetfs/layered.go | 8 +- package/gitea/source/modules/auth/common.go | 4 +- .../source/modules/auth/httpauth/httpauth.go | 2 +- .../source/modules/auth/openid/openid.go | 22 +- .../source/modules/auth/openid/openid_test.go | 29 + .../gitea/source/modules/auth/pam/pam_test.go | 4 +- .../modules/auth/password/hash/argon2.go | 2 +- .../modules/auth/password/hash/common.go | 4 +- .../source/modules/auth/password/hash/hash.go | 2 +- .../modules/auth/password/hash/hash_test.go | 2 + .../modules/auth/password/hash/pbkdf2.go | 2 +- .../modules/auth/password/hash/scrypt.go | 2 +- .../source/modules/auth/password/password.go | 4 +- .../gitea/source/modules/auth/password/pwn.go | 4 +- .../source/modules/auth/password/pwn/pwn.go | 2 +- .../source/modules/auth/webauthn/webauthn.go | 19 +- .../modules/auth/webauthn/webauthn_test.go | 2 +- package/gitea/source/modules/avatar/avatar.go | 13 +- .../source/modules/avatar/avatar_test.go | 2 +- .../gitea/source/modules/avatar/hash_test.go | 2 +- package/gitea/source/modules/badge/badge.go | 2 +- package/gitea/source/modules/base/tool.go | 4 +- .../gitea/source/modules/base/tool_test.go | 4 +- package/gitea/source/modules/cache/cache.go | 2 +- .../gitea/source/modules/cache/cache_redis.go | 4 +- .../gitea/source/modules/cache/cache_test.go | 2 +- .../source/modules/cache/cache_twoqueue.go | 2 +- .../source/modules/cache/context_test.go | 2 +- .../gitea/source/modules/cache/ephemeral.go | 4 +- .../source/modules/cache/string_cache.go | 6 +- .../gitea/source/modules/charset/ambiguous.go | 2 +- .../modules/charset/ambiguous_gen_test.go | 2 +- .../gitea/source/modules/charset/charset.go | 9 +- .../source/modules/charset/charset_test.go | 4 +- .../gitea/source/modules/charset/escape.go | 4 +- .../source/modules/charset/escape_stream.go | 4 +- .../source/modules/charset/escape_test.go | 6 +- .../modules/charset/generate/generate.go | 2 +- .../gitea/source/modules/consts/asymkey.go | 12 + package/gitea/source/modules/csv/csv.go | 6 +- package/gitea/source/modules/csv/csv_test.go | 4 +- package/gitea/source/modules/dump/dumper.go | 6 +- .../gitea/source/modules/dump/dumper_test.go | 2 +- package/gitea/source/modules/emoji/emoji.go | 2 +- .../gitea/source/modules/emoji/emoji_test.go | 6 +- .../gitea/source/modules/eventsource/event.go | 9 +- .../source/modules/eventsource/manager_run.go | 20 +- .../gitea/source/modules/fileicon/basic.go | 4 +- .../gitea/source/modules/fileicon/entry.go | 2 +- .../gitea/source/modules/fileicon/material.go | 12 +- .../source/modules/fileicon/material_test.go | 6 +- .../gitea/source/modules/fileicon/render.go | 2 +- .../source/modules/fileicon/render_test.go | 8 +- .../gitea/source/modules/generate/generate.go | 83 +- .../source/modules/git/attribute/attribute.go | 2 +- .../source/modules/git/attribute/batch.go | 6 +- .../modules/git/attribute/batch_test.go | 6 +- .../source/modules/git/attribute/checker.go | 4 +- .../modules/git/attribute/checker_test.go | 6 +- .../source/modules/git/attribute/main_test.go | 6 +- package/gitea/source/modules/git/blob.go | 4 +- .../gitea/source/modules/git/blob_gogit.go | 2 +- .../gitea/source/modules/git/blob_nogogit.go | 2 +- .../modules/git/catfile_batch_command.go | 6 +- .../modules/git/catfile_batch_legacy.go | 6 +- .../modules/git/catfile_batch_reader.go | 112 +- .../source/modules/git/catfile_batch_test.go | 2 +- package/gitea/source/modules/git/commit.go | 42 +- .../modules/git/commit_convert_gogit.go | 2 +- .../source/modules/git/commit_info_gogit.go | 10 +- .../source/modules/git/commit_info_nogogit.go | 4 +- .../modules/git/commit_info_nogogit_test.go | 54 + .../source/modules/git/commit_message.go | 201 + .../source/modules/git/commit_message_test.go | 173 + .../gitea/source/modules/git/commit_reader.go | 2 +- .../source/modules/git/commit_sha256_test.go | 2 +- .../modules/git/commit_submodule_file.go | 4 +- .../gitea/source/modules/git/commit_test.go | 19 +- package/gitea/source/modules/git/config.go | 46 +- .../gitea/source/modules/git/config_test.go | 19 +- package/gitea/source/modules/git/diff.go | 8 +- package/gitea/source/modules/git/error.go | 2 +- .../source/modules/git/foreachref/format.go | 2 +- .../modules/git/foreachref/format_test.go | 2 +- .../source/modules/git/foreachref/parser.go | 2 - .../modules/git/foreachref/parser_test.go | 8 +- package/gitea/source/modules/git/git.go | 32 +- .../source/modules/git/gitcmd/command.go | 21 +- .../source/modules/git/gitcmd/command_test.go | 8 +- .../gitea/source/modules/git/gitcmd/env.go | 4 +- .../gitea/source/modules/git/gitcmd/error.go | 61 +- .../source/modules/git/gitcmd/error_test.go | 23 + package/gitea/source/modules/git/gpg.go | 4 +- package/gitea/source/modules/git/grep.go | 4 +- package/gitea/source/modules/git/hook.go | 2 +- package/gitea/source/modules/git/key.go | 4 +- .../git/languagestats/language_stats.go | 4 +- .../git/languagestats/language_stats_gogit.go | 8 +- .../languagestats/language_stats_nogogit.go | 10 +- .../git/languagestats/language_stats_test.go | 4 +- .../modules/git/languagestats/main_test.go | 2 +- .../source/modules/git/last_commit_cache.go | 6 +- .../modules/git/last_commit_cache_nogogit.go | 2 +- ...e_status.go => log_name_status_nogogit.go} | 132 +- .../gitea/source/modules/git/notes_gogit.go | 17 +- .../gitea/source/modules/git/notes_nogogit.go | 2 +- package/gitea/source/modules/git/object_id.go | 23 +- package/gitea/source/modules/git/parse.go | 2 +- .../source/modules/git/parse_treeentry.go | 32 +- .../modules/git/parse_treeentry_test.go | 31 + .../source/modules/git/pipeline/catfile.go | 2 +- .../source/modules/git/pipeline/lfs_common.go | 2 +- .../source/modules/git/pipeline/lfs_gogit.go | 2 +- .../modules/git/pipeline/lfs_nogogit.go | 25 +- .../source/modules/git/pipeline/lfs_test.go | 2 +- .../source/modules/git/pipeline/main_test.go | 2 +- .../source/modules/git/pipeline/namerev.go | 2 +- .../source/modules/git/pipeline/revlist.go | 2 +- .../gitea/source/modules/git/redirection.go | 15 + package/gitea/source/modules/git/ref.go | 26 +- package/gitea/source/modules/git/ref_test.go | 19 + package/gitea/source/modules/git/remote.go | 18 +- package/gitea/source/modules/git/repo.go | 5 +- .../source/modules/git/repo_base_gogit.go | 6 +- .../source/modules/git/repo_base_nogogit.go | 4 +- .../gitea/source/modules/git/repo_branch.go | 2 +- .../source/modules/git/repo_branch_nogogit.go | 4 +- .../gitea/source/modules/git/repo_commit.go | 210 +- .../source/modules/git/repo_commit_gogit.go | 7 +- .../source/modules/git/repo_commit_nogogit.go | 18 +- .../source/modules/git/repo_commit_test.go | 64 +- .../source/modules/git/repo_commitgraph.go | 2 +- .../modules/git/repo_commitgraph_gogit.go | 12 +- .../gitea/source/modules/git/repo_compare.go | 17 +- .../source/modules/git/repo_compare_test.go | 2 +- .../gitea/source/modules/git/repo_index.go | 4 +- .../gitea/source/modules/git/repo_object.go | 2 +- package/gitea/source/modules/git/repo_ref.go | 10 +- .../source/modules/git/repo_ref_nogogit.go | 2 +- .../gitea/source/modules/git/repo_stats.go | 4 +- package/gitea/source/modules/git/repo_tag.go | 13 +- .../source/modules/git/repo_tag_gogit.go | 26 +- .../source/modules/git/repo_tag_nogogit.go | 14 +- .../gitea/source/modules/git/repo_tag_test.go | 41 +- package/gitea/source/modules/git/repo_test.go | 24 + package/gitea/source/modules/git/repo_tree.go | 2 +- .../source/modules/git/repo_tree_gogit.go | 2 +- package/gitea/source/modules/git/signature.go | 2 +- .../source/modules/git/signature_nogogit.go | 2 +- package/gitea/source/modules/git/submodule.go | 4 +- .../source/modules/git/submodule_test.go | 2 +- package/gitea/source/modules/git/tag.go | 7 +- package/gitea/source/modules/git/tag_test.go | 29 +- package/gitea/source/modules/git/tree.go | 2 +- .../gitea/source/modules/git/tree_entry.go | 2 +- .../modules/git/tree_entry_common_test.go | 2 +- .../modules/git/tree_entry_gogit_test.go | 4 +- .../source/modules/git/tree_entry_mode.go | 3 +- .../source/modules/git/tree_entry_nogogit.go | 2 +- .../source/modules/git/tree_entry_test.go | 2 + .../gitea/source/modules/git/tree_nogogit.go | 5 +- package/gitea/source/modules/git/url/url.go | 6 +- .../gitea/source/modules/git/url/url_test.go | 6 +- package/gitea/source/modules/git/utils.go | 2 +- .../gitea/source/modules/gitrepo/archive.go | 4 +- package/gitea/source/modules/gitrepo/blame.go | 6 +- .../modules/gitrepo/blame_sha256_test.go | 4 +- .../source/modules/gitrepo/blame_test.go | 4 +- .../gitea/source/modules/gitrepo/branch.go | 4 +- .../gitea/source/modules/gitrepo/cat_file.go | 2 +- package/gitea/source/modules/gitrepo/clone.go | 2 +- .../gitea/source/modules/gitrepo/command.go | 2 +- .../gitea/source/modules/gitrepo/commit.go | 29 +- .../source/modules/gitrepo/commit_file.go | 4 +- .../source/modules/gitrepo/commit_test.go | 31 + .../source/modules/gitrepo/commitgraph.go | 2 +- .../gitea/source/modules/gitrepo/compare.go | 9 +- .../source/modules/gitrepo/compare_test.go | 72 +- .../gitea/source/modules/gitrepo/config.go | 14 +- package/gitea/source/modules/gitrepo/diff.go | 2 +- package/gitea/source/modules/gitrepo/fetch.go | 4 +- package/gitea/source/modules/gitrepo/fsck.go | 2 +- .../gitea/source/modules/gitrepo/gitrepo.go | 12 +- package/gitea/source/modules/gitrepo/hooks.go | 16 +- .../source/modules/gitrepo/hooks_test.go | 34 + .../gitea/source/modules/gitrepo/main_test.go | 4 +- package/gitea/source/modules/gitrepo/merge.go | 10 +- .../source/modules/gitrepo/merge_tree.go | 4 +- .../source/modules/gitrepo/merge_tree_test.go | 2 +- package/gitea/source/modules/gitrepo/push.go | 2 +- package/gitea/source/modules/gitrepo/ref.go | 2 +- .../gitea/source/modules/gitrepo/remote.go | 10 +- .../gitea/source/modules/gitrepo/signing.go | 2 +- package/gitea/source/modules/gitrepo/tag.go | 2 +- .../source/modules/gitrepo/walk_nogogit.go | 2 +- package/gitea/source/modules/glob/glob.go | 141 +- .../source/modules/globallock/globallock.go | 42 +- .../modules/globallock/globallock_test.go | 57 +- .../source/modules/globallock/locker_test.go | 33 +- .../source/modules/globallock/redis_locker.go | 16 +- .../gitea/source/modules/graceful/manager.go | 12 +- .../source/modules/graceful/manager_common.go | 2 +- .../source/modules/graceful/manager_unix.go | 8 +- .../modules/graceful/manager_windows.go | 5 +- .../gitea/source/modules/graceful/net_unix.go | 6 +- .../gitea/source/modules/graceful/server.go | 6 +- .../source/modules/graceful/server_hooks.go | 2 +- package/gitea/source/modules/gtprof/trace.go | 2 +- .../source/modules/gtprof/trace_builtin.go | 2 +- .../gitea/source/modules/hcaptcha/hcaptcha.go | 4 +- .../source/modules/highlight/highlight.go | 6 +- .../modules/highlight/highlight_test.go | 16 +- .../source/modules/highlight/lexerdetect.go | 13 +- .../source/modules/hostmatcher/hostmatcher.go | 75 +- .../modules/hostmatcher/hostmatcher_test.go | 57 + .../gitea/source/modules/hostmatcher/http.go | 16 + package/gitea/source/modules/htmlutil/html.go | 78 + .../source/modules/htmlutil/html_test.go | 16 + .../source/modules/httpcache/httpcache.go | 21 +- .../modules/httpcache/httpcache_test.go | 4 +- .../modules/httplib/content_disposition.go | 2 +- package/gitea/source/modules/httplib/serve.go | 17 +- .../source/modules/httplib/serve_test.go | 2 +- package/gitea/source/modules/httplib/url.go | 4 +- .../gitea/source/modules/httplib/url_test.go | 4 +- .../modules/indexer/code/bleve/bleve.go | 38 +- .../modules/indexer/code/bleve/bleve_test.go | 59 + .../modules/indexer/code/bleve/code_token.go | 65 + .../indexer/code/bleve/token/path/path.go | 11 +- .../code/elasticsearch/elasticsearch.go | 280 +- .../gitea/source/modules/indexer/code/git.go | 14 +- .../modules/indexer/code/gitgrep/gitgrep.go | 8 +- .../indexer/code/gitgrep/gitgrep_test.go | 4 +- .../source/modules/indexer/code/indexer.go | 24 +- .../modules/indexer/code/indexer_test.go | 35 +- .../modules/indexer/code/internal/indexer.go | 8 +- .../modules/indexer/code/internal/model.go | 2 +- .../modules/indexer/code/internal/util.go | 4 +- .../source/modules/indexer/code/search.go | 6 +- .../modules/indexer/internal/bleve/indexer.go | 4 +- .../modules/indexer/internal/bleve/query.go | 2 +- .../modules/indexer/internal/bleve/util.go | 6 +- .../indexer/internal/bleve/util_test.go | 4 +- .../modules/indexer/internal/db/indexer.go | 2 +- .../indexer/internal/elasticsearch/indexer.go | 391 +- .../internal/elasticsearch/indexer_test.go | 39 + .../indexer/internal/elasticsearch/query.go | 132 + .../indexer/internal/elasticsearch/types.go | 76 + .../indexer/internal/elasticsearch/util.go | 42 +- .../indexer/internal/meilisearch/util.go | 2 +- .../modules/indexer/internal/paginator.go | 2 +- .../modules/indexer/issues/bleve/bleve.go | 54 +- .../indexer/issues/bleve/bleve_test.go | 111 +- .../issues/bleve/camelcase_keep_whole.go | 64 + .../source/modules/indexer/issues/db/db.go | 14 +- .../modules/indexer/issues/db/options.go | 14 +- .../modules/indexer/issues/dboptions.go | 19 +- .../issues/elasticsearch/elasticsearch.go | 207 +- .../elasticsearch/elasticsearch_test.go | 35 +- .../source/modules/indexer/issues/indexer.go | 30 +- .../modules/indexer/issues/indexer_test.go | 58 +- .../indexer/issues/internal/indexer.go | 4 +- .../modules/indexer/issues/internal/model.go | 20 +- .../indexer/issues/internal/tests/tests.go | 115 +- .../indexer/issues/meilisearch/meilisearch.go | 46 +- .../issues/meilisearch/meilisearch_test.go | 21 +- .../source/modules/indexer/issues/util.go | 31 +- .../gitea/source/modules/indexer/stats/db.go | 16 +- .../source/modules/indexer/stats/indexer.go | 8 +- .../modules/indexer/stats/indexer_test.go | 14 +- .../source/modules/indexer/stats/queue.go | 10 +- .../source/modules/issue/template/template.go | 4 +- .../modules/issue/template/template_test.go | 4 +- .../modules/issue/template/unmarshal.go | 12 +- package/gitea/source/modules/label/label.go | 2 +- package/gitea/source/modules/label/parser.go | 4 +- package/gitea/source/modules/lfs/client.go | 20 +- .../gitea/source/modules/lfs/client_test.go | 15 +- .../gitea/source/modules/lfs/content_store.go | 4 +- package/gitea/source/modules/lfs/endpoint.go | 18 +- .../gitea/source/modules/lfs/endpoint_test.go | 18 + .../source/modules/lfs/filesystem_client.go | 2 +- .../gitea/source/modules/lfs/http_client.go | 12 +- .../source/modules/lfs/http_client_test.go | 6 +- .../modules/lfs/pointer_scanner_gogit.go | 2 +- .../modules/lfs/pointer_scanner_nogogit.go | 8 +- package/gitea/source/modules/lfs/shared.go | 2 +- .../source/modules/lfs/transferadapter.go | 4 +- .../modules/lfs/transferadapter_test.go | 11 +- .../modules/lfstransfer/backend/backend.go | 6 +- .../modules/lfstransfer/backend/lock.go | 4 +- .../modules/lfstransfer/backend/util.go | 8 +- .../modules/lfstransfer/backend/util_test.go | 4 +- .../gitea/source/modules/lfstransfer/main.go | 2 +- .../gitea/source/modules/log/event_format.go | 2 +- .../modules/log/event_writer_console.go | 2 +- .../source/modules/log/event_writer_file.go | 4 +- package/gitea/source/modules/log/flags.go | 2 +- .../gitea/source/modules/log/flags_test.go | 2 +- package/gitea/source/modules/log/init.go | 4 +- package/gitea/source/modules/log/level.go | 2 +- .../gitea/source/modules/log/level_test.go | 2 +- .../gitea/source/modules/log/logger_global.go | 25 +- .../gitea/source/modules/log/logger_impl.go | 4 +- .../modules/markup/asciicast/asciicast.go | 49 - package/gitea/source/modules/markup/camo.go | 2 +- .../gitea/source/modules/markup/camo_test.go | 2 +- .../source/modules/markup/console/console.go | 8 +- .../modules/markup/console/console_test.go | 4 +- .../gitea/source/modules/markup/csv/csv.go | 10 +- .../source/modules/markup/csv/csv_test.go | 2 +- .../modules/markup/external/external.go | 66 +- .../modules/markup/external/external_test.go | 24 + .../modules/markup/external/frontend.go | 27 +- package/gitea/source/modules/markup/html.go | 72 +- .../source/modules/markup/html_codepreview.go | 4 +- .../modules/markup/html_codepreview_test.go | 6 +- .../source/modules/markup/html_commit.go | 6 +- .../gitea/source/modules/markup/html_emoji.go | 9 +- .../modules/markup/html_internal_test.go | 12 +- .../gitea/source/modules/markup/html_issue.go | 14 +- .../source/modules/markup/html_issue_test.go | 8 +- .../gitea/source/modules/markup/html_link.go | 4 +- .../source/modules/markup/html_mention.go | 4 +- .../gitea/source/modules/markup/html_node.go | 2 +- .../gitea/source/modules/markup/html_test.go | 35 +- .../source/modules/markup/html_toc_test.go | 6 +- .../modules/markup/internal/renderinternal.go | 5 +- .../modules/markup/jupyter/jupyter-test.ipynb | 74 + .../source/modules/markup/jupyter/jupyter.go | 394 + .../modules/markup/jupyter/jupyter_test.go | 314 + .../gitea/source/modules/markup/main_test.go | 5 +- .../source/modules/markup/markdown/ast.go | 17 +- .../modules/markup/markdown/convertyaml.go | 6 +- .../modules/markup/markdown/goldmark.go | 29 +- .../modules/markup/markdown/main_test.go | 4 +- .../modules/markup/markdown/markdown.go | 29 +- .../markdown/markdown_attention_test.go | 6 +- .../markdown/markdown_benchmark_test.go | 4 +- .../markup/markdown/markdown_math_test.go | 6 +- .../modules/markup/markdown/markdown_test.go | 31 +- .../markup/markdown/math/block_parser.go | 2 +- .../markup/markdown/math/block_renderer.go | 4 +- .../markup/markdown/math/inline_renderer.go | 2 +- .../modules/markup/markdown/math/math.go | 4 +- .../source/modules/markup/markdown/meta.go | 2 +- .../modules/markup/markdown/renderconfig.go | 4 +- .../markup/markdown/renderconfig_test.go | 2 +- .../markup/markdown/transform_blockquote.go | 7 +- .../markup/markdown/transform_codeblock.go | 32 + .../markup/markdown/transform_codespan.go | 11 +- .../modules/markup/markdown/transform_list.go | 2 +- .../modules/markup/mdstripper/mdstripper.go | 6 +- .../source/modules/markup/orgmode/orgmode.go | 34 +- .../modules/markup/orgmode/orgmode_test.go | 80 +- package/gitea/source/modules/markup/render.go | 33 +- .../source/modules/markup/render_helper.go | 2 +- .../source/modules/markup/render_link.go | 4 +- .../source/modules/markup/render_link_test.go | 2 +- .../source/modules/markup/render_test.go | 7 +- .../gitea/source/modules/markup/renderer.go | 4 +- .../source/modules/markup/sanitizer_custom.go | 2 +- .../modules/markup/sanitizer_default.go | 34 +- .../modules/markup/sanitizer_default_test.go | 5 +- .../gitea/source/modules/mcaptcha/mcaptcha.go | 2 +- .../gitea/source/modules/metrics/collector.go | 6 +- .../source/modules/migration/downloader.go | 2 +- .../source/modules/migration/file_format.go | 6 +- .../gitea/source/modules/migration/options.go | 2 +- .../source/modules/migration/pullrequest.go | 2 +- .../gitea/source/modules/migration/repo.go | 1 + .../modules/migration/schemas_bindata.go | 4 +- package/gitea/source/modules/nosql/manager.go | 2 +- .../source/modules/nosql/manager_leveldb.go | 4 +- .../source/modules/nosql/manager_redis.go | 4 +- .../source/modules/optional/option_test.go | 2 +- .../source/modules/optional/serialization.go | 4 +- .../modules/optional/serialization_test.go | 6 +- package/gitea/source/modules/options/base.go | 4 +- .../source/modules/options/options_bindata.go | 4 +- .../source/modules/options/options_dynamic.go | 4 +- .../modules/packages/alpine/metadata.go | 19 +- .../modules/packages/alpine/metadata_test.go | 10 + .../source/modules/packages/arch/metadata.go | 21 +- .../modules/packages/arch/metadata_test.go | 26 + .../source/modules/packages/cargo/parser.go | 4 +- .../source/modules/packages/chef/metadata.go | 6 +- .../modules/packages/composer/metadata.go | 6 +- .../packages/composer/metadata_test.go | 2 +- .../packages/conan/conaninfo_parser.go | 2 +- .../modules/packages/conan/reference.go | 4 +- .../source/modules/packages/conda/metadata.go | 8 +- .../modules/packages/conda/metadata_test.go | 2 +- .../modules/packages/container/metadata.go | 6 +- .../packages/container/metadata_test.go | 2 +- .../source/modules/packages/content_store.go | 6 +- .../source/modules/packages/cran/metadata.go | 2 +- .../modules/packages/debian/metadata.go | 92 +- .../modules/packages/debian/metadata_test.go | 73 +- .../gitea/source/modules/packages/filelist.go | 37 + .../modules/packages/goproxy/metadata.go | 12 +- .../modules/packages/goproxy/metadata_test.go | 10 + .../source/modules/packages/hashed_buffer.go | 4 +- .../modules/packages/hashed_buffer_test.go | 2 +- .../source/modules/packages/helm/metadata.go | 6 +- .../source/modules/packages/maven/metadata.go | 4 +- .../modules/packages/maven/metadata_test.go | 2 +- .../source/modules/packages/npm/creator.go | 63 +- .../modules/packages/npm/creator_test.go | 35 +- .../source/modules/packages/nuget/metadata.go | 4 +- .../packages/nuget/symbol_extractor.go | 4 +- .../packages/nuget/symbol_extractor_test.go | 2 +- .../source/modules/packages/pub/metadata.go | 6 +- .../source/modules/packages/rpm/metadata.go | 4 +- .../modules/packages/rubygems/marshal.go | 4 +- .../modules/packages/rubygems/metadata.go | 21 +- .../packages/rubygems/metadata_test.go | 13 +- .../source/modules/packages/swift/metadata.go | 38 +- .../modules/packages/swift/metadata_test.go | 100 +- .../source/modules/packages/terraform/lock.go | 13 +- .../modules/packages/terraform/state.go | 4 +- .../modules/packages/vagrant/metadata.go | 4 +- .../modules/packages/vagrant/metadata_test.go | 2 +- .../source/modules/paginator/paginator.go | 19 +- package/gitea/source/modules/pprof/pprof.go | 2 +- .../gitea/source/modules/private/actions.go | 2 +- package/gitea/source/modules/private/hook.go | 24 +- .../gitea/source/modules/private/internal.go | 40 +- .../source/modules/private/internal_test.go | 37 + package/gitea/source/modules/private/key.go | 2 +- package/gitea/source/modules/private/mail.go | 2 +- .../gitea/source/modules/private/manager.go | 21 +- .../source/modules/private/pushoptions.go | 2 +- .../gitea/source/modules/private/request.go | 4 +- .../source/modules/private/restore_repo.go | 2 +- package/gitea/source/modules/private/serv.go | 8 +- .../gitea/source/modules/process/manager.go | 4 +- .../modules/process/manager_stacktraces.go | 2 +- package/gitea/source/modules/proxy/proxy.go | 6 +- .../source/modules/proxyprotocol/conn.go | 2 +- .../gitea/source/modules/public/manifest.go | 126 +- .../source/modules/public/manifest_test.go | 68 +- package/gitea/source/modules/public/public.go | 12 +- .../source/modules/public/public_bindata.go | 2 +- .../source/modules/public/public_dynamic.go | 4 +- .../source/modules/public/public_test.go | 2 +- .../gitea/source/modules/public/vitedev.go | 51 +- .../source/modules/queue/base_channel.go | 2 +- .../source/modules/queue/base_levelqueue.go | 4 +- .../modules/queue/base_levelqueue_common.go | 2 +- .../modules/queue/base_levelqueue_test.go | 4 +- .../modules/queue/base_levelqueue_unique.go | 4 +- .../gitea/source/modules/queue/base_redis.go | 6 +- .../source/modules/queue/base_redis_test.go | 11 +- package/gitea/source/modules/queue/config.go | 2 +- package/gitea/source/modules/queue/manager.go | 4 +- .../source/modules/queue/manager_test.go | 6 +- package/gitea/source/modules/queue/queue.go | 2 +- .../gitea/source/modules/queue/workergroup.go | 2 +- .../gitea/source/modules/queue/workerqueue.go | 8 +- .../source/modules/queue/workerqueue_test.go | 4 +- .../source/modules/recaptcha/recaptcha.go | 4 +- .../source/modules/references/references.go | 8 +- .../modules/references/references_test.go | 2 +- .../source/modules/regexplru/regexplru.go | 2 +- .../gitea/source/modules/repository/branch.go | 32 +- .../source/modules/repository/branch_test.go | 8 +- .../source/modules/repository/commits.go | 39 +- .../source/modules/repository/commits_test.go | 46 +- .../gitea/source/modules/repository/create.go | 6 +- .../source/modules/repository/create_test.go | 6 +- .../gitea/source/modules/repository/delete.go | 6 +- .../gitea/source/modules/repository/env.go | 8 +- .../gitea/source/modules/repository/fork.go | 8 +- .../source/modules/repository/fork_test.go | 4 +- .../gitea/source/modules/repository/init.go | 10 +- .../source/modules/repository/license.go | 2 +- .../source/modules/repository/main_test.go | 6 +- .../gitea/source/modules/repository/push.go | 11 +- .../gitea/source/modules/repository/repo.go | 30 +- .../source/modules/repository/repo_test.go | 2 +- .../gitea/source/modules/repository/temp.go | 4 +- .../gitea/source/modules/reqctx/datastore.go | 2 +- package/gitea/source/modules/session/db.go | 4 +- package/gitea/source/modules/session/key.go | 6 + package/gitea/source/modules/session/redis.go | 16 +- package/gitea/source/modules/session/store.go | 2 +- .../gitea/source/modules/session/virtual.go | 2 +- .../gitea/source/modules/setting/actions.go | 68 +- .../source/modules/setting/actions_test.go | 71 + package/gitea/source/modules/setting/admin.go | 4 +- package/gitea/source/modules/setting/api.go | 2 +- package/gitea/source/modules/setting/cache.go | 2 +- package/gitea/source/modules/setting/camo.go | 2 +- .../gitea/source/modules/setting/config.go | 4 +- .../source/modules/setting/config/value.go | 11 +- .../source/modules/setting/config_env.go | 2 +- .../modules/setting/config_option_instance.go | 2 +- .../source/modules/setting/config_provider.go | 4 +- .../gitea/source/modules/setting/database.go | 175 +- .../source/modules/setting/database_sqlite.go | 15 - .../source/modules/setting/federation.go | 2 +- package/gitea/source/modules/setting/git.go | 2 +- .../gitea/source/modules/setting/git_test.go | 2 +- .../source/modules/setting/gloabl_lock.go | 4 +- package/gitea/source/modules/setting/glob.go | 2 +- .../source/modules/setting/incoming_email.go | 2 +- .../gitea/source/modules/setting/indexer.go | 2 +- package/gitea/source/modules/setting/lfs.go | 2 +- package/gitea/source/modules/setting/log.go | 6 +- .../gitea/source/modules/setting/log_test.go | 4 +- .../gitea/source/modules/setting/mailer.go | 2 +- .../source/modules/setting/mailer_test.go | 2 +- .../gitea/source/modules/setting/markup.go | 15 +- .../gitea/source/modules/setting/mirror.go | 2 +- .../gitea/source/modules/setting/oauth2.go | 7 +- .../source/modules/setting/oauth2_test.go | 6 +- package/gitea/source/modules/setting/other.go | 2 +- package/gitea/source/modules/setting/path.go | 10 +- package/gitea/source/modules/setting/proxy.go | 2 +- package/gitea/source/modules/setting/queue.go | 4 +- .../source/modules/setting/repository.go | 10 +- .../source/modules/setting/repository_test.go | 66 + .../gitea/source/modules/setting/security.go | 23 +- .../source/modules/setting/security_test.go | 29 + .../gitea/source/modules/setting/server.go | 73 +- .../gitea/source/modules/setting/service.go | 6 +- .../source/modules/setting/service_test.go | 6 +- .../gitea/source/modules/setting/session.go | 6 +- .../gitea/source/modules/setting/setting.go | 12 +- .../source/modules/setting/setting_test.go | 41 - package/gitea/source/modules/setting/ssh.go | 9 +- .../gitea/source/modules/setting/testenv.go | 171 +- package/gitea/source/modules/setting/time.go | 2 +- package/gitea/source/modules/setting/ui.go | 4 +- .../gitea/source/modules/setting/webhook.go | 7 +- .../gitea/source/modules/sitemap/sitemap.go | 12 +- .../source/modules/sitemap/sitemap_test.go | 8 +- package/gitea/source/modules/ssh/init.go | 6 +- package/gitea/source/modules/ssh/ssh.go | 120 +- .../gitea/source/modules/ssh/ssh_graceful.go | 8 +- package/gitea/source/modules/ssh/ssh_test.go | 124 + .../gitea/source/modules/storage/azureblob.go | 20 +- .../source/modules/storage/azureblob_test.go | 47 +- package/gitea/source/modules/storage/local.go | 6 +- .../source/modules/storage/local_test.go | 2 +- package/gitea/source/modules/storage/minio.go | 72 +- .../source/modules/storage/minio_test.go | 34 +- .../gitea/source/modules/storage/storage.go | 46 +- .../source/modules/storage/storage_test.go | 12 +- .../source/modules/structs/admin_user.go | 9 +- .../source/modules/structs/attachment.go | 2 +- package/gitea/source/modules/structs/hook.go | 20 +- .../gitea/source/modules/structs/hook_test.go | 59 + package/gitea/source/modules/structs/issue.go | 18 +- .../source/modules/structs/issue_test.go | 4 +- .../source/modules/structs/notifications.go | 8 +- package/gitea/source/modules/structs/org.go | 8 +- .../gitea/source/modules/structs/org_team.go | 39 +- .../gitea/source/modules/structs/project.go | 33 + .../source/modules/structs/pull_review.go | 5 + package/gitea/source/modules/structs/repo.go | 39 +- .../source/modules/structs/repo_actions.go | 65 +- .../source/modules/structs/repo_branch.go | 9 + .../modules/structs/repo_collaborator.go | 30 +- .../source/modules/structs/repo_topic.go | 5 + .../gitea/source/modules/structs/status.go | 2 +- package/gitea/source/modules/structs/token.go | 31 + package/gitea/source/modules/structs/user.go | 5 +- .../source/modules/structs/visible_type.go | 11 + package/gitea/source/modules/svg/svg.go | 6 +- package/gitea/source/modules/svg/svg_test.go | 2 +- .../source/modules/system/appstate_test.go | 2 +- package/gitea/source/modules/system/db.go | 6 +- .../gitea/source/modules/tempdir/tempdir.go | 4 +- .../gitea/source/modules/templates/base.go | 4 +- .../source/modules/templates/eval/eval.go | 2 +- .../gitea/source/modules/templates/helper.go | 76 +- .../source/modules/templates/helper_test.go | 13 +- .../source/modules/templates/htmlrenderer.go | 10 +- .../modules/templates/htmlrenderer_test.go | 2 +- .../gitea/source/modules/templates/mail.go | 27 +- .../gitea/source/modules/templates/page.go | 15 +- .../templates/scopedtmpl/scopedtmpl_test.go | 11 +- .../modules/templates/templates_bindata.go | 4 +- .../modules/templates/templates_dynamic.go | 4 +- .../source/modules/templates/util_actions.go | 23 + .../source/modules/templates/util_avatar.go | 16 +- .../source/modules/templates/util_date.go | 4 +- .../modules/templates/util_date_test.go | 6 +- .../source/modules/templates/util_dict.go | 6 +- .../source/modules/templates/util_format.go | 2 +- .../source/modules/templates/util_json.go | 2 +- .../source/modules/templates/util_misc.go | 23 +- .../source/modules/templates/util_render.go | 355 +- .../modules/templates/util_render_comment.go | 12 +- .../templates/util_render_comment_test.go | 6 +- .../modules/templates/util_render_test.go | 162 +- .../source/modules/templates/util_slice.go | 31 + .../source/modules/templates/util_string.go | 2 +- .../source/modules/templates/util_test.go | 10 + .../gitea/source/modules/test/logchecker.go | 2 +- .../source/modules/test/logchecker_test.go | 2 +- package/gitea/source/modules/test/utils.go | 96 +- .../source/modules/testlogger/testlogger.go | 27 +- .../gitea/source/modules/timeutil/since.go | 2 +- .../source/modules/timeutil/since_test.go | 4 +- .../source/modules/timeutil/timestamp.go | 2 +- .../source/modules/timeutil/timestampnano.go | 2 +- .../modules/translation/i18n/localestore.go | 4 +- .../source/modules/translation/translation.go | 10 +- .../modules/translation/translation_test.go | 2 +- .../source/modules/turnstile/turnstile.go | 17 +- .../modules/turnstile/turnstile_test.go | 38 + .../modules/updatechecker/update_checker.go | 8 +- package/gitea/source/modules/uri/uri.go | 10 +- package/gitea/source/modules/uri/uri_test.go | 50 + .../source/modules/util/diff_slice_test.go | 74 + .../modules/util/rotatingfilewriter/writer.go | 4 +- .../gitea/source/modules/util/runtime_test.go | 2 +- package/gitea/source/modules/util/sync.go | 51 + .../gitea/source/modules/util/sync_test.go | 49 + package/gitea/source/modules/util/time_str.go | 7 + .../source/modules/util/time_str_test.go | 3 + package/gitea/source/modules/util/util.go | 85 +- .../gitea/source/modules/util/util_test.go | 28 +- .../source/modules/validation/binding.go | 37 +- .../source/modules/validation/binding_test.go | 1 - .../modules/validation/glob_pattern_test.go | 2 +- .../source/modules/validation/helpers.go | 38 +- .../source/modules/validation/helpers_test.go | 49 +- .../modules/validation/validurllist_test.go | 157 - package/gitea/source/modules/web/handler.go | 11 +- .../source/modules/web/middleware/binding.go | 155 +- .../source/modules/web/middleware/cookie.go | 11 +- .../source/modules/web/middleware/data.go | 6 +- .../source/modules/web/middleware/flash.go | 2 +- .../source/modules/web/middleware/locale.go | 30 +- .../modules/web/middleware/locale_test.go | 27 + package/gitea/source/modules/web/routemock.go | 2 +- .../source/modules/web/routemock_test.go | 2 +- package/gitea/source/modules/web/router.go | 22 +- .../gitea/source/modules/web/router_path.go | 4 +- .../gitea/source/modules/web/router_test.go | 11 +- .../source/modules/web/routing/context.go | 57 +- .../source/modules/web/routing/funcinfo.go | 2 +- .../modules/web/routing/funcinfo_test.go | 2 +- .../source/modules/web/routing/logger.go | 19 +- .../modules/web/routing/logger_manager.go | 106 +- .../source/modules/web/routing/requestinfo.go | 43 + .../modules/web/routing/requestrecord.go | 22 +- .../source/modules/web/types/premiddleware.go | 13 + package/gitea/source/modules/zstd/zstd.go | 4 +- .../options/fileicon/material-icon-rules.json | 703 +- .../options/fileicon/material-icon-svgs.json | 1127 +- .../source/options/locale/locale_cs-CZ.json | 77 +- .../source/options/locale/locale_de-DE.json | 724 +- .../source/options/locale/locale_el-GR.json | 62 +- .../source/options/locale/locale_en-US.json | 123 +- .../source/options/locale/locale_es-ES.json | 62 +- .../source/options/locale/locale_fa-IR.json | 49 +- .../source/options/locale/locale_fi-FI.json | 38 +- .../source/options/locale/locale_fr-FR.json | 129 +- .../source/options/locale/locale_ga-IE.json | 139 +- .../source/options/locale/locale_hu-HU.json | 31 +- .../source/options/locale/locale_id-ID.json | 31 +- .../source/options/locale/locale_is-IS.json | 25 +- .../source/options/locale/locale_it-IT.json | 51 +- .../source/options/locale/locale_ja-JP.json | 250 +- .../source/options/locale/locale_ko-KR.json | 132 +- .../source/options/locale/locale_lv-LV.json | 63 +- .../source/options/locale/locale_nl-NL.json | 49 +- .../source/options/locale/locale_pl-PL.json | 47 +- .../source/options/locale/locale_pt-BR.json | 69 +- .../source/options/locale/locale_pt-PT.json | 294 +- .../source/options/locale/locale_ru-RU.json | 61 +- .../source/options/locale/locale_si-LK.json | 49 +- .../source/options/locale/locale_sk-SK.json | 25 +- .../source/options/locale/locale_sv-SE.json | 54 +- .../source/options/locale/locale_tr-TR.json | 70 +- .../source/options/locale/locale_uk-UA.json | 72 +- .../source/options/locale/locale_zh-CN.json | 303 +- .../source/options/locale/locale_zh-TW.json | 72 +- package/gitea/source/package.json | 142 +- package/gitea/source/pnpm-lock.yaml | 4643 ++- package/gitea/source/pnpm-workspace.yaml | 10 + .../public/assets/img/svg/octicon-flag.svg | 1 + .../img/svg/octicon-repo-forked-locked.svg | 1 + .../public/assets/img/svg/octicon-sandbox.svg | 1 + .../assets/img/svg/octicon-stack-add.svg | 1 + .../assets/img/svg/octicon-stack-check.svg | 1 + .../assets/img/svg/octicon-stack-remove.svg | 1 + .../public/assets/img/svg/octicon-vscode.svg | 2 +- package/gitea/source/pyproject.toml | 3 +- package/gitea/source/renovate.json5 | 116 + .../source/routers/api/actions/actions.go | 6 +- .../source/routers/api/actions/artifact.pb.go | 2 +- .../source/routers/api/actions/artifact.proto | 2 +- .../source/routers/api/actions/artifacts.go | 73 +- .../routers/api/actions/artifacts_chunks.go | 17 +- .../routers/api/actions/artifacts_utils.go | 20 +- .../source/routers/api/actions/artifactsv4.go | 93 +- .../source/routers/api/actions/job_summary.go | 104 + .../source/routers/api/actions/ping/ping.go | 6 +- .../routers/api/actions/ping/ping_test.go | 5 +- .../routers/api/actions/runner/interceptor.go | 35 +- .../routers/api/actions/runner/runner.go | 104 +- .../routers/api/actions/runner/runner_test.go | 57 + .../routers/api/packages/alpine/alpine.go | 39 +- .../gitea/source/routers/api/packages/api.go | 66 +- .../source/routers/api/packages/arch/arch.go | 18 +- .../gitea/source/routers/api/packages/auth.go | 8 +- .../routers/api/packages/cargo/cargo.go | 28 +- .../source/routers/api/packages/chef/auth.go | 8 +- .../source/routers/api/packages/chef/chef.go | 20 +- .../routers/api/packages/composer/api.go | 10 +- .../routers/api/packages/composer/composer.go | 22 +- .../routers/api/packages/conan/conan.go | 30 +- .../routers/api/packages/conan/search.go | 10 +- .../routers/api/packages/conda/conda.go | 18 +- .../routers/api/packages/container/blob.go | 18 +- .../api/packages/container/container.go | 38 +- .../api/packages/container/manifest.go | 26 +- .../source/routers/api/packages/cran/cran.go | 16 +- .../routers/api/packages/debian/debian.go | 26 +- .../routers/api/packages/generic/generic.go | 10 +- .../routers/api/packages/goproxy/goproxy.go | 16 +- .../source/routers/api/packages/helm/helm.go | 22 +- .../routers/api/packages/helper/helper.go | 8 +- .../source/routers/api/packages/maven/api.go | 2 +- .../routers/api/packages/maven/maven.go | 37 +- .../routers/api/packages/maven/maven_test.go | 15 + .../source/routers/api/packages/npm/api.go | 24 +- .../routers/api/packages/npm/api_test.go | 46 + .../source/routers/api/packages/npm/npm.go | 35 +- .../routers/api/packages/nuget/api_v2.go | 4 +- .../routers/api/packages/nuget/api_v3.go | 4 +- .../source/routers/api/packages/nuget/auth.go | 4 +- .../routers/api/packages/nuget/nuget.go | 22 +- .../source/routers/api/packages/pub/pub.go | 18 +- .../source/routers/api/packages/pypi/pypi.go | 16 +- .../source/routers/api/packages/rpm/rpm.go | 24 +- .../routers/api/packages/rubygems/rubygems.go | 18 +- .../api/packages/rubygems/rubygems_test.go | 2 +- .../routers/api/packages/swift/swift.go | 34 +- .../api/packages/terraform/terraform.go | 18 +- .../routers/api/packages/vagrant/vagrant.go | 14 +- .../routers/api/v1/activitypub/person.go | 2 +- .../source/routers/api/v1/admin/action.go | 18 +- .../source/routers/api/v1/admin/adopt.go | 12 +- .../gitea/source/routers/api/v1/admin/cron.go | 12 +- .../source/routers/api/v1/admin/email.go | 10 +- .../source/routers/api/v1/admin/hooks.go | 18 +- .../gitea/source/routers/api/v1/admin/org.go | 20 +- .../gitea/source/routers/api/v1/admin/repo.go | 8 +- .../source/routers/api/v1/admin/runners.go | 4 +- .../gitea/source/routers/api/v1/admin/user.go | 115 +- .../source/routers/api/v1/admin/user_badge.go | 8 +- package/gitea/source/routers/api/v1/api.go | 281 +- .../source/routers/api/v1/misc/gitignore.go | 10 +- .../routers/api/v1/misc/label_templates.go | 8 +- .../source/routers/api/v1/misc/licenses.go | 12 +- .../source/routers/api/v1/misc/markup.go | 34 +- .../source/routers/api/v1/misc/markup_test.go | 95 +- .../source/routers/api/v1/misc/signing.go | 6 +- .../source/routers/api/v1/misc/version.go | 6 +- .../routers/api/v1/notify/notifications.go | 14 +- .../source/routers/api/v1/notify/repo.go | 12 +- .../source/routers/api/v1/notify/threads.go | 14 +- .../source/routers/api/v1/notify/user.go | 12 +- .../gitea/source/routers/api/v1/org/action.go | 48 +- .../gitea/source/routers/api/v1/org/avatar.go | 10 +- .../gitea/source/routers/api/v1/org/block.go | 4 +- .../gitea/source/routers/api/v1/org/hook.go | 10 +- .../gitea/source/routers/api/v1/org/label.go | 18 +- .../gitea/source/routers/api/v1/org/member.go | 20 +- .../gitea/source/routers/api/v1/org/org.go | 129 +- .../gitea/source/routers/api/v1/org/team.go | 140 +- .../source/routers/api/v1/packages/package.go | 34 +- .../source/routers/api/v1/repo/action.go | 477 +- .../source/routers/api/v1/repo/actions_run.go | 21 +- .../source/routers/api/v1/repo/avatar.go | 10 +- .../gitea/source/routers/api/v1/repo/blob.go | 6 +- .../source/routers/api/v1/repo/branch.go | 167 +- .../routers/api/v1/repo/collaborators.go | 75 +- .../source/routers/api/v1/repo/commits.go | 47 +- .../source/routers/api/v1/repo/compare.go | 53 +- .../source/routers/api/v1/repo/download.go | 14 +- .../gitea/source/routers/api/v1/repo/file.go | 69 +- .../gitea/source/routers/api/v1/repo/fork.go | 34 +- .../source/routers/api/v1/repo/git_hook.go | 10 +- .../source/routers/api/v1/repo/git_ref.go | 8 +- .../gitea/source/routers/api/v1/repo/hook.go | 28 +- .../source/routers/api/v1/repo/hook_test.go | 21 +- .../gitea/source/routers/api/v1/repo/issue.go | 182 +- .../routers/api/v1/repo/issue_assignee.go | 238 + .../routers/api/v1/repo/issue_attachment.go | 36 +- .../routers/api/v1/repo/issue_comment.go | 70 +- .../api/v1/repo/issue_comment_attachment.go | 42 +- .../routers/api/v1/repo/issue_dependency.go | 42 +- .../source/routers/api/v1/repo/issue_label.go | 29 +- .../source/routers/api/v1/repo/issue_lock.go | 29 +- .../source/routers/api/v1/repo/issue_pin.go | 10 +- .../routers/api/v1/repo/issue_reaction.go | 50 +- .../routers/api/v1/repo/issue_stopwatch.go | 10 +- .../routers/api/v1/repo/issue_subscription.go | 14 +- .../routers/api/v1/repo/issue_tracked_time.go | 113 +- .../gitea/source/routers/api/v1/repo/key.go | 26 +- .../gitea/source/routers/api/v1/repo/label.go | 30 +- .../source/routers/api/v1/repo/language.go | 6 +- .../source/routers/api/v1/repo/license.go | 6 +- .../source/routers/api/v1/repo/main_test.go | 6 +- .../source/routers/api/v1/repo/migrate.go | 57 +- .../source/routers/api/v1/repo/milestone.go | 18 +- .../source/routers/api/v1/repo/mirror.go | 64 +- .../source/routers/api/v1/repo/mirror_test.go | 40 + .../gitea/source/routers/api/v1/repo/notes.go | 14 +- .../gitea/source/routers/api/v1/repo/patch.go | 8 +- .../gitea/source/routers/api/v1/repo/pull.go | 182 +- .../source/routers/api/v1/repo/pull_review.go | 190 +- .../source/routers/api/v1/repo/release.go | 34 +- .../routers/api/v1/repo/release_attachment.go | 28 +- .../routers/api/v1/repo/release_tags.go | 12 +- .../gitea/source/routers/api/v1/repo/repo.go | 179 +- .../source/routers/api/v1/repo/repo_test.go | 10 +- .../gitea/source/routers/api/v1/repo/star.go | 10 +- .../source/routers/api/v1/repo/status.go | 18 +- .../source/routers/api/v1/repo/subscriber.go | 10 +- .../gitea/source/routers/api/v1/repo/tag.go | 38 +- .../gitea/source/routers/api/v1/repo/teams.go | 35 +- .../gitea/source/routers/api/v1/repo/topic.go | 20 +- .../source/routers/api/v1/repo/transfer.go | 46 +- .../gitea/source/routers/api/v1/repo/tree.go | 4 +- .../gitea/source/routers/api/v1/repo/wiki.go | 52 +- .../routers/api/v1/settings/settings.go | 6 +- .../source/routers/api/v1/shared/action.go | 116 +- .../source/routers/api/v1/shared/block.go | 38 +- .../source/routers/api/v1/shared/runners.go | 24 +- .../source/routers/api/v1/swagger/action.go | 2 +- .../source/routers/api/v1/swagger/activity.go | 2 +- .../source/routers/api/v1/swagger/app.go | 9 +- .../source/routers/api/v1/swagger/cron.go | 2 +- .../source/routers/api/v1/swagger/issue.go | 2 +- .../source/routers/api/v1/swagger/key.go | 2 +- .../source/routers/api/v1/swagger/misc.go | 2 +- .../source/routers/api/v1/swagger/nodeinfo.go | 2 +- .../source/routers/api/v1/swagger/notify.go | 2 +- .../source/routers/api/v1/swagger/options.go | 9 +- .../source/routers/api/v1/swagger/org.go | 2 +- .../source/routers/api/v1/swagger/package.go | 2 +- .../source/routers/api/v1/swagger/repo.go | 4 +- .../source/routers/api/v1/swagger/settings.go | 2 +- .../source/routers/api/v1/swagger/user.go | 6 +- .../source/routers/api/v1/token/token.go | 88 + .../source/routers/api/v1/user/action.go | 56 +- .../gitea/source/routers/api/v1/user/app.go | 66 +- .../source/routers/api/v1/user/avatar.go | 14 +- .../gitea/source/routers/api/v1/user/block.go | 4 +- .../gitea/source/routers/api/v1/user/email.go | 25 +- .../source/routers/api/v1/user/follower.go | 12 +- .../source/routers/api/v1/user/gpg_key.go | 33 +- .../source/routers/api/v1/user/helper.go | 6 +- .../gitea/source/routers/api/v1/user/hook.go | 10 +- .../gitea/source/routers/api/v1/user/key.go | 29 +- .../gitea/source/routers/api/v1/user/repo.go | 14 +- .../source/routers/api/v1/user/runners.go | 6 +- .../source/routers/api/v1/user/settings.go | 12 +- .../gitea/source/routers/api/v1/user/star.go | 26 +- .../gitea/source/routers/api/v1/user/user.go | 14 +- .../gitea/source/routers/api/v1/user/watch.go | 17 +- .../gitea/source/routers/api/v1/utils/git.go | 12 +- .../gitea/source/routers/api/v1/utils/hook.go | 28 +- .../source/routers/api/v1/utils/hook_test.go | 6 +- .../source/routers/api/v1/utils/main_test.go | 6 +- .../gitea/source/routers/api/v1/utils/page.go | 6 +- .../gitea/source/routers/api/v1/utils/sort.go | 38 + .../source/routers/api/v1/utils/sort_test.go | 44 + .../gitea/source/routers/common/actions.go | 22 +- package/gitea/source/routers/common/auth.go | 8 +- .../source/routers/common/blockexpensive.go | 15 +- .../routers/common/blockexpensive_test.go | 2 - .../gitea/source/routers/common/codesearch.go | 8 +- .../gitea/source/routers/common/compare.go | 50 +- .../source/routers/common/compare_test.go | 49 + package/gitea/source/routers/common/db.go | 18 +- .../gitea/source/routers/common/deadline.go | 4 +- .../gitea/source/routers/common/errpage.go | 25 +- .../source/routers/common/errpage_test.go | 6 +- .../source/routers/common/issue_filter.go | 64 +- .../routers/common/issue_filter_test.go | 93 + package/gitea/source/routers/common/lfs.go | 4 +- .../source/routers/common/maintenancemode.go | 4 +- package/gitea/source/routers/common/markup.go | 25 +- .../gitea/source/routers/common/middleware.go | 41 +- .../gitea/source/routers/common/pagetmpl.go | 10 +- package/gitea/source/routers/common/qos.go | 18 +- .../gitea/source/routers/common/qos_test.go | 6 +- .../gitea/source/routers/common/redirect.go | 2 +- .../source/routers/common/redirect_test.go | 4 +- package/gitea/source/routers/common/serve.go | 14 +- package/gitea/source/routers/init.go | 98 +- .../gitea/source/routers/install/install.go | 55 +- .../gitea/source/routers/install/routes.go | 14 +- .../source/routers/install/routes_test.go | 2 +- .../gitea/source/routers/private/actions.go | 16 +- .../source/routers/private/default_branch.go | 48 - .../routers/private/hook_post_receive.go | 432 +- .../routers/private/hook_post_receive_test.go | 20 +- .../routers/private/hook_pre_receive.go | 118 +- .../routers/private/hook_pre_receive_test.go | 69 + .../routers/private/hook_proc_receive.go | 16 +- .../routers/private/hook_verification.go | 8 +- .../routers/private/hook_verification_test.go | 4 +- .../gitea/source/routers/private/internal.go | 33 +- .../source/routers/private/internal_repo.go | 10 +- package/gitea/source/routers/private/key.go | 8 +- package/gitea/source/routers/private/mail.go | 18 +- .../gitea/source/routers/private/main_test.go | 2 +- .../gitea/source/routers/private/manager.go | 127 +- .../source/routers/private/manager_process.go | 8 +- .../source/routers/private/manager_unix.go | 4 +- .../source/routers/private/manager_windows.go | 6 +- .../source/routers/private/restore_repo.go | 8 +- package/gitea/source/routers/private/serv.go | 26 +- .../gitea/source/routers/private/ssh_log.go | 10 +- package/gitea/source/routers/utils/utils.go | 9 +- .../gitea/source/routers/utils/utils_test.go | 9 +- .../gitea/source/routers/web/admin/admin.go | 34 +- .../source/routers/web/admin/admin_test.go | 66 +- .../source/routers/web/admin/applications.go | 12 +- .../gitea/source/routers/web/admin/auths.go | 35 +- .../gitea/source/routers/web/admin/badges.go | 18 +- .../gitea/source/routers/web/admin/config.go | 85 +- .../source/routers/web/admin/diagnosis.go | 8 +- .../gitea/source/routers/web/admin/emails.go | 16 +- .../gitea/source/routers/web/admin/hooks.go | 10 +- .../source/routers/web/admin/main_test.go | 2 +- .../gitea/source/routers/web/admin/notice.go | 12 +- .../gitea/source/routers/web/admin/orgs.go | 20 +- .../source/routers/web/admin/packages.go | 16 +- .../source/routers/web/admin/perftrace.go | 4 +- .../gitea/source/routers/web/admin/queue.go | 6 +- .../source/routers/web/admin/queue_tester.go | 10 +- .../gitea/source/routers/web/admin/repos.go | 20 +- .../source/routers/web/admin/stacktrace.go | 6 +- .../gitea/source/routers/web/admin/users.go | 45 +- .../source/routers/web/admin/users_test.go | 14 +- package/gitea/source/routers/web/auth/2fa.go | 40 +- package/gitea/source/routers/web/auth/auth.go | 139 +- .../source/routers/web/auth/auth_test.go | 70 +- .../source/routers/web/auth/linkaccount.go | 79 +- .../source/routers/web/auth/main_test.go | 2 +- .../gitea/source/routers/web/auth/oauth.go | 156 +- .../routers/web/auth/oauth2_provider.go | 108 +- .../routers/web/auth/oauth_signin_sync.go | 25 +- .../source/routers/web/auth/oauth_test.go | 54 +- .../gitea/source/routers/web/auth/openid.go | 77 +- .../gitea/source/routers/web/auth/password.go | 51 +- .../gitea/source/routers/web/auth/webauthn.go | 40 +- package/gitea/source/routers/web/base.go | 16 +- .../source/routers/web/devtest/devtest.go | 135 +- .../routers/web/devtest/mail_preview.go | 10 +- .../routers/web/devtest/mock_actions.go | 416 +- .../gitea/source/routers/web/events/events.go | 10 +- .../gitea/source/routers/web/explore/code.go | 14 +- .../gitea/source/routers/web/explore/org.go | 23 +- .../gitea/source/routers/web/explore/repo.go | 14 +- .../gitea/source/routers/web/explore/topic.go | 10 +- .../gitea/source/routers/web/explore/user.go | 37 +- .../gitea/source/routers/web/feed/branch.go | 16 +- .../gitea/source/routers/web/feed/convert.go | 19 +- package/gitea/source/routers/web/feed/file.go | 20 +- .../gitea/source/routers/web/feed/profile.go | 17 +- .../source/routers/web/feed/profile_test.go | 8 +- .../gitea/source/routers/web/feed/release.go | 9 +- .../gitea/source/routers/web/feed/render.go | 11 +- package/gitea/source/routers/web/feed/repo.go | 11 +- package/gitea/source/routers/web/githttp.go | 4 +- package/gitea/source/routers/web/goget.go | 62 +- .../source/routers/web/healthcheck/check.go | 20 +- package/gitea/source/routers/web/home.go | 32 +- package/gitea/source/routers/web/metrics.go | 2 +- .../gitea/source/routers/web/misc/markup.go | 10 +- package/gitea/source/routers/web/misc/misc.go | 40 +- .../gitea/source/routers/web/misc/swagger.go | 2 +- .../gitea/source/routers/web/misc/webtheme.go | 14 +- package/gitea/source/routers/web/nodeinfo.go | 4 +- package/gitea/source/routers/web/org/block.go | 18 +- package/gitea/source/routers/web/org/home.go | 52 +- .../gitea/source/routers/web/org/main_test.go | 2 +- .../gitea/source/routers/web/org/members.go | 37 +- .../gitea/source/routers/web/org/mention.go | 8 +- package/gitea/source/routers/web/org/org.go | 18 +- .../source/routers/web/org/org_labels.go | 18 +- .../gitea/source/routers/web/org/projects.go | 40 +- .../source/routers/web/org/projects_test.go | 10 +- .../gitea/source/routers/web/org/setting.go | 38 +- .../source/routers/web/org/setting_oauth2.go | 14 +- .../routers/web/org/setting_packages.go | 10 +- package/gitea/source/routers/web/org/teams.go | 100 +- .../gitea/source/routers/web/org/worktime.go | 8 +- package/gitea/source/routers/web/passkey.go | 4 +- .../routers/web/repo/actions/actions.go | 394 +- .../routers/web/repo/actions/actions_test.go | 52 +- .../source/routers/web/repo/actions/badge.go | 16 +- .../routers/web/repo/actions/main_test.go | 2 +- .../source/routers/web/repo/actions/view.go | 920 +- .../routers/web/repo/actions/view_test.go | 144 +- .../gitea/source/routers/web/repo/activity.go | 18 +- .../source/routers/web/repo/attachment.go | 58 +- .../gitea/source/routers/web/repo/blame.go | 57 +- .../gitea/source/routers/web/repo/branch.go | 57 +- .../source/routers/web/repo/code_frequency.go | 6 +- .../gitea/source/routers/web/repo/commit.go | 134 +- .../routers/web/repo/common_recentbranches.go | 12 +- .../gitea/source/routers/web/repo/compare.go | 389 +- .../source/routers/web/repo/compare_test.go | 29 +- .../source/routers/web/repo/contributors.go | 6 +- .../gitea/source/routers/web/repo/download.go | 20 +- .../gitea/source/routers/web/repo/editor.go | 30 +- .../routers/web/repo/editor_apply_patch.go | 8 +- .../routers/web/repo/editor_cherry_pick.go | 17 +- .../source/routers/web/repo/editor_error.go | 22 +- .../source/routers/web/repo/editor_fork.go | 6 +- .../source/routers/web/repo/editor_preview.go | 6 +- .../source/routers/web/repo/editor_test.go | 6 +- .../routers/web/repo/editor_uploader.go | 12 +- .../source/routers/web/repo/editor_util.go | 22 +- package/gitea/source/routers/web/repo/fork.go | 30 +- .../gitea/source/routers/web/repo/githttp.go | 73 +- .../gitea/source/routers/web/repo/helper.go | 4 +- .../gitea/source/routers/web/repo/issue.go | 74 +- .../source/routers/web/repo/issue_comment.go | 48 +- .../routers/web/repo/issue_content_history.go | 14 +- .../routers/web/repo/issue_dependency.go | 34 +- .../source/routers/web/repo/issue_label.go | 32 +- .../routers/web/repo/issue_label_test.go | 16 +- .../source/routers/web/repo/issue_list.go | 205 +- .../source/routers/web/repo/issue_lock.go | 8 +- .../source/routers/web/repo/issue_new.go | 94 +- .../routers/web/repo/issue_page_meta.go | 123 +- .../source/routers/web/repo/issue_pin.go | 10 +- .../source/routers/web/repo/issue_poster.go | 30 +- .../routers/web/repo/issue_stopwatch.go | 8 +- .../routers/web/repo/issue_suggestions.go | 12 +- .../source/routers/web/repo/issue_test.go | 2 +- .../routers/web/repo/issue_timetrack.go | 16 +- .../source/routers/web/repo/issue_view.go | 441 +- .../source/routers/web/repo/issue_watch.go | 18 +- .../source/routers/web/repo/main_test.go | 2 +- .../gitea/source/routers/web/repo/mention.go | 12 +- .../source/routers/web/repo/middlewares.go | 31 +- .../routers/web/repo/middlewares_test.go | 6 +- .../gitea/source/routers/web/repo/migrate.go | 36 +- .../source/routers/web/repo/milestone.go | 32 +- .../gitea/source/routers/web/repo/packages.go | 16 +- .../gitea/source/routers/web/repo/projects.go | 111 +- .../source/routers/web/repo/projects_test.go | 4 +- package/gitea/source/routers/web/repo/pull.go | 855 +- .../source/routers/web/repo/pull_merge_box.go | 191 + .../routers/web/repo/pull_merge_form.go | 190 + .../source/routers/web/repo/pull_review.go | 36 +- .../routers/web/repo/pull_review_test.go | 14 +- .../source/routers/web/repo/recent_commits.go | 4 +- .../gitea/source/routers/web/repo/release.go | 144 +- .../source/routers/web/repo/release_test.go | 42 +- .../gitea/source/routers/web/repo/render.go | 19 +- package/gitea/source/routers/web/repo/repo.go | 71 +- .../gitea/source/routers/web/repo/search.go | 16 +- .../routers/web/repo/setting/actions.go | 18 +- .../source/routers/web/repo/setting/avatar.go | 14 +- .../routers/web/repo/setting/collaboration.go | 66 +- .../web/repo/setting/default_branch.go | 12 +- .../routers/web/repo/setting/deploy_key.go | 16 +- .../routers/web/repo/setting/git_hooks.go | 6 +- .../source/routers/web/repo/setting/lfs.go | 32 +- .../routers/web/repo/setting/main_test.go | 2 +- .../web/repo/setting/protected_branch.go | 50 +- .../routers/web/repo/setting/protected_tag.go | 24 +- .../routers/web/repo/setting/public_access.go | 12 +- .../routers/web/repo/setting/secrets.go | 10 +- .../routers/web/repo/setting/setting.go | 185 +- .../routers/web/repo/setting/settings_test.go | 118 +- .../routers/web/repo/setting/webhook.go | 63 +- package/gitea/source/routers/web/repo/star.go | 9 +- .../gitea/source/routers/web/repo/topic.go | 6 +- .../gitea/source/routers/web/repo/transfer.go | 8 +- .../gitea/source/routers/web/repo/treelist.go | 14 +- .../source/routers/web/repo/treelist_test.go | 8 +- package/gitea/source/routers/web/repo/view.go | 71 +- .../source/routers/web/repo/view_file.go | 34 +- .../source/routers/web/repo/view_home.go | 46 +- .../source/routers/web/repo/view_home_test.go | 6 +- .../source/routers/web/repo/view_readme.go | 20 +- .../routers/web/repo/view_readme_test.go | 6 +- .../gitea/source/routers/web/repo/watch.go | 9 +- .../gitea/source/routers/web/repo/webgit.go | 12 +- package/gitea/source/routers/web/repo/wiki.go | 77 +- .../source/routers/web/repo/wiki_test.go | 18 +- .../routers/web/shared/actions/general.go | 14 +- .../routers/web/shared/actions/runners.go | 95 +- .../web/shared/actions/scoped_workflows.go | 368 + .../shared/actions/scoped_workflows_test.go | 75 + .../routers/web/shared/actions/variables.go | 20 +- .../routers/web/shared/issue/issue_label.go | 12 +- .../source/routers/web/shared/label/label.go | 10 +- .../routers/web/shared/mention/mention.go | 4 +- .../routers/web/shared/packages/packages.go | 20 +- .../routers/web/shared/project/column.go | 6 +- .../routers/web/shared/secrets/secrets.go | 16 +- .../source/routers/web/shared/user/block.go | 76 +- .../source/routers/web/shared/user/header.go | 38 +- .../source/routers/web/shared/user/helper.go | 46 +- .../routers/web/shared/user/helper_test.go | 2 +- .../gitea/source/routers/web/swagger_json.go | 11 +- .../gitea/source/routers/web/user/avatar.go | 8 +- package/gitea/source/routers/web/user/code.go | 16 +- .../gitea/source/routers/web/user/heatmap.go | 6 +- package/gitea/source/routers/web/user/home.go | 79 +- .../source/routers/web/user/home_test.go | 12 +- .../source/routers/web/user/main_test.go | 2 +- .../source/routers/web/user/notification.go | 62 +- .../routers/web/user/notification_test.go | 37 + .../gitea/source/routers/web/user/package.go | 52 +- .../gitea/source/routers/web/user/profile.go | 45 +- .../gitea/source/routers/web/user/search.go | 12 +- .../routers/web/user/setting/account.go | 77 +- .../routers/web/user/setting/account_test.go | 10 +- .../source/routers/web/user/setting/adopt.go | 10 +- .../routers/web/user/setting/applications.go | 40 +- .../source/routers/web/user/setting/block.go | 15 +- .../source/routers/web/user/setting/keys.go | 47 +- .../routers/web/user/setting/main_test.go | 2 +- .../routers/web/user/setting/notifications.go | 14 +- .../source/routers/web/user/setting/oauth2.go | 6 +- .../routers/web/user/setting/oauth2_common.go | 14 +- .../routers/web/user/setting/packages.go | 14 +- .../routers/web/user/setting/profile.go | 38 +- .../routers/web/user/setting/security/2fa.go | 16 +- .../web/user/setting/security/main_test.go | 2 +- .../web/user/setting/security/openid.go | 16 +- .../web/user/setting/security/openid_test.go | 14 +- .../web/user/setting/security/security.go | 16 +- .../web/user/setting/security/webauthn.go | 32 +- .../routers/web/user/setting/settings.go | 8 +- .../routers/web/user/setting/webhooks.go | 10 +- .../source/routers/web/user/stop_watch.go | 8 +- package/gitea/source/routers/web/web.go | 139 +- package/gitea/source/routers/web/webfinger.go | 8 +- .../gitea/source/services/actions/approve.go | 110 + .../source/services/actions/approve_test.go | 67 + .../source/services/actions/artifacts.go | 65 + package/gitea/source/services/actions/auth.go | 6 +- .../source/services/actions/auth_test.go | 4 +- .../gitea/source/services/actions/cleanup.go | 28 +- .../source/services/actions/clear_tasks.go | 183 +- .../services/actions/clear_tasks_test.go | 143 + .../source/services/actions/commit_status.go | 181 +- .../services/actions/commit_status_test.go | 370 +- .../source/services/actions/concurrency.go | 67 +- .../gitea/source/services/actions/context.go | 207 +- .../source/services/actions/context_test.go | 349 +- .../gitea/source/services/actions/helper.go | 137 + .../source/services/actions/helper_test.go | 90 + package/gitea/source/services/actions/init.go | 14 +- .../source/services/actions/init_test.go | 12 +- .../source/services/actions/interface.go | 2 +- .../source/services/actions/job_emitter.go | 381 +- .../services/actions/job_emitter_test.go | 328 +- .../gitea/source/services/actions/notifier.go | 63 +- .../services/actions/notifier_helper.go | 386 +- .../services/actions/notifier_helper_test.go | 126 + .../gitea/source/services/actions/notify.go | 147 + .../services/actions/permission_parser.go | 24 +- .../actions/permission_parser_test.go | 8 +- .../gitea/source/services/actions/rerun.go | 712 +- .../source/services/actions/rerun_test.go | 341 +- .../services/actions/reusable_workflow.go | 430 + .../actions/reusable_workflow_test.go | 355 + package/gitea/source/services/actions/run.go | 293 +- .../source/services/actions/schedule_tasks.go | 42 +- .../services/actions/schedule_tasks_test.go | 28 +- .../services/actions/scoped_workflow_cache.go | 84 + package/gitea/source/services/actions/task.go | 172 +- .../source/services/actions/task_test.go | 74 + .../source/services/actions/variables.go | 6 +- .../gitea/source/services/actions/workflow.go | 190 +- .../source/services/actions/workflow_test.go | 58 + package/gitea/source/services/agit/agit.go | 46 +- .../gitea/source/services/agit/agit_test.go | 4 +- .../gitea/source/services/asymkey/commit.go | 22 +- .../source/services/asymkey/commit_test.go | 14 +- .../source/services/asymkey/deploy_key.go | 6 +- .../source/services/asymkey/main_test.go | 8 +- package/gitea/source/services/asymkey/sign.go | 85 +- .../source/services/asymkey/sign_test.go | 2 +- .../gitea/source/services/asymkey/ssh_key.go | 6 +- .../asymkey/ssh_key_authorized_keys.go | 8 +- .../asymkey/ssh_key_authorized_principals.go | 10 +- .../services/asymkey/ssh_key_principals.go | 6 +- .../source/services/asymkey/ssh_key_test.go | 10 +- .../source/services/attachment/attachment.go | 12 +- .../services/attachment/attachment_test.go | 8 +- package/gitea/source/services/auth/auth.go | 14 +- .../gitea/source/services/auth/auth_token.go | 37 +- .../source/services/auth/auth_token_test.go | 11 +- package/gitea/source/services/auth/basic.go | 26 +- package/gitea/source/services/auth/group.go | 2 +- .../gitea/source/services/auth/httpsign.go | 12 +- .../gitea/source/services/auth/interface.go | 6 +- .../gitea/source/services/auth/main_test.go | 2 +- package/gitea/source/services/auth/oauth2.go | 22 +- .../gitea/source/services/auth/oauth2_test.go | 8 +- .../source/services/auth/reverseproxy.go | 8 +- package/gitea/source/services/auth/session.go | 4 +- package/gitea/source/services/auth/signin.go | 47 +- package/gitea/source/services/auth/source.go | 6 +- .../auth/source/db/assert_interface_test.go | 6 +- .../services/auth/source/db/authenticate.go | 6 +- .../source/services/auth/source/db/source.go | 4 +- .../auth/source/ldap/assert_interface_test.go | 6 +- .../services/auth/source/ldap/source.go | 10 +- .../auth/source/ldap/source_authenticate.go | 18 +- .../auth/source/ldap/source_search.go | 9 +- .../services/auth/source/ldap/source_sync.go | 22 +- .../source/oauth2/assert_interface_test.go | 6 +- .../services/auth/source/oauth2/init.go | 12 +- .../services/auth/source/oauth2/main_test.go | 2 +- .../services/auth/source/oauth2/providers.go | 10 +- .../auth/source/oauth2/providers_base.go | 4 +- .../auth/source/oauth2/providers_custom.go | 23 +- .../auth/source/oauth2/providers_openid.go | 14 +- .../auth/source/oauth2/providers_simple.go | 2 +- .../services/auth/source/oauth2/source.go | 5 +- .../auth/source/oauth2/source_authenticate.go | 4 +- .../auth/source/oauth2/source_sync.go | 26 +- .../auth/source/oauth2/source_sync_test.go | 20 +- .../services/auth/source/oauth2/store.go | 4 +- .../auth/source/pam/assert_interface_test.go | 6 +- .../source/services/auth/source/pam/source.go | 4 +- .../auth/source/pam/source_authenticate.go | 10 +- .../auth/source/smtp/assert_interface_test.go | 6 +- .../services/auth/source/smtp/source.go | 4 +- .../auth/source/smtp/source_authenticate.go | 8 +- .../services/auth/source/source_group_sync.go | 10 +- .../auth/source/sspi/assert_interface_test.go | 4 +- .../services/auth/source/sspi/source.go | 4 +- package/gitea/source/services/auth/sspi.go | 18 +- package/gitea/source/services/auth/sync.go | 6 +- .../source/services/automerge/automerge.go | 40 +- .../gitea/source/services/automerge/notify.go | 16 +- .../services/automergequeue/automergequeue.go | 10 +- .../source/services/context/access_log.go | 8 +- .../services/context/access_log_test.go | 4 +- package/gitea/source/services/context/api.go | 128 +- .../gitea/source/services/context/api_org.go | 2 +- .../gitea/source/services/context/api_test.go | 2 +- package/gitea/source/services/context/base.go | 46 +- .../source/services/context/base_form.go | 15 +- .../source/services/context/base_path.go | 2 +- .../source/services/context/base_test.go | 9 +- .../gitea/source/services/context/captcha.go | 16 +- .../gitea/source/services/context/context.go | 36 +- .../source/services/context/context_cookie.go | 4 +- .../services/context/context_response.go | 16 +- .../services/context/context_template.go | 76 +- .../source/services/context/context_test.go | 7 +- package/gitea/source/services/context/org.go | 107 +- .../gitea/source/services/context/package.go | 40 +- .../source/services/context/package_test.go | 26 + .../source/services/context/pagination.go | 8 +- .../services/context/pagination_test.go | 22 +- .../source/services/context/permission.go | 48 +- .../gitea/source/services/context/private.go | 17 +- package/gitea/source/services/context/repo.go | 196 +- .../source/services/context/repo_test.go | 28 + .../gitea/source/services/context/response.go | 2 +- .../source/services/context/upload/upload.go | 10 +- package/gitea/source/services/context/user.go | 38 +- .../services/contexttest/context_tests.go | 26 +- .../source/services/convert/action_test.go | 30 +- .../gitea/source/services/convert/activity.go | 12 +- .../source/services/convert/attachment.go | 4 +- .../gitea/source/services/convert/convert.go | 325 +- .../source/services/convert/git_commit.go | 20 +- .../services/convert/git_commit_test.go | 20 +- .../gitea/source/services/convert/issue.go | 27 +- .../source/services/convert/issue_comment.go | 12 +- .../source/services/convert/issue_test.go | 16 +- .../source/services/convert/main_test.go | 4 +- .../gitea/source/services/convert/mirror.go | 4 +- .../source/services/convert/notification.go | 37 +- .../services/convert/notification_test.go | 44 +- .../gitea/source/services/convert/package.go | 8 +- .../gitea/source/services/convert/project.go | 37 + package/gitea/source/services/convert/pull.go | 30 +- .../source/services/convert/pull_review.go | 6 +- .../services/convert/pull_review_test.go | 6 +- .../source/services/convert/pull_test.go | 12 +- .../gitea/source/services/convert/release.go | 4 +- .../source/services/convert/release_test.go | 4 +- .../source/services/convert/repository.go | 29 +- .../gitea/source/services/convert/secret.go | 18 - .../gitea/source/services/convert/status.go | 8 +- package/gitea/source/services/convert/user.go | 10 +- .../source/services/convert/user_test.go | 10 +- .../gitea/source/services/convert/utils.go | 4 +- package/gitea/source/services/convert/wiki.go | 6 +- package/gitea/source/services/cron/cron.go | 10 +- package/gitea/source/services/cron/setting.go | 2 +- package/gitea/source/services/cron/tasks.go | 20 +- .../source/services/cron/tasks_actions.go | 6 +- .../gitea/source/services/cron/tasks_basic.go | 24 +- .../source/services/cron/tasks_extended.go | 22 +- .../services/cron/tasks_extended_test.go | 4 +- .../gitea/source/services/doctor/actions.go | 173 - .../source/services/doctor/actions_test.go | 24 - .../source/services/doctor/authorizedkeys.go | 100 - .../gitea/source/services/doctor/breaking.go | 97 - .../services/doctor/checkOldArchives.go | 57 - .../source/services/doctor/dbconsistency.go | 20 +- .../services/doctor/dbconsistency_test.go | 10 +- .../gitea/source/services/doctor/dbversion.go | 43 - .../gitea/source/services/doctor/doctor.go | 10 +- .../gitea/source/services/doctor/fix16961.go | 328 - .../source/services/doctor/fix16961_test.go | 265 - .../gitea/source/services/doctor/fix8312.go | 61 - package/gitea/source/services/doctor/heads.go | 92 - package/gitea/source/services/doctor/lfs.go | 6 +- .../gitea/source/services/doctor/main_test.go | 2 +- .../gitea/source/services/doctor/mergebase.go | 115 - package/gitea/source/services/doctor/misc.go | 78 +- package/gitea/source/services/doctor/paths.go | 123 - .../source/services/doctor/repository.go | 8 +- .../gitea/source/services/doctor/storage.go | 20 +- .../gitea/source/services/doctor/usertype.go | 41 - .../source/services/externalaccount/user.go | 8 +- package/gitea/source/services/feed/feed.go | 16 +- .../gitea/source/services/feed/feed_test.go | 10 +- .../gitea/source/services/feed/notifier.go | 27 +- .../source/services/feed/notifier_test.go | 12 +- package/gitea/source/services/forms/admin.go | 6 +- .../gitea/source/services/forms/auth_form.go | 6 +- package/gitea/source/services/forms/org.go | 7 +- .../source/services/forms/package_form.go | 4 +- .../source/services/forms/repo_branch_form.go | 4 +- .../gitea/source/services/forms/repo_form.go | 36 +- .../source/services/forms/repo_form_editor.go | 6 +- .../source/services/forms/repo_form_test.go | 2 +- .../source/services/forms/repo_tag_form.go | 4 +- package/gitea/source/services/forms/runner.go | 4 +- .../gitea/source/services/forms/user_form.go | 40 +- .../services/forms/user_form_auth_openid.go | 4 +- .../forms/user_form_hidden_comments.go | 8 +- .../source/services/forms/user_form_test.go | 41 +- package/gitea/source/services/git/commit.go | 61 +- package/gitea/source/services/git/compare.go | 80 +- .../gitea/source/services/gitdiff/csv_test.go | 4 +- .../source/services/gitdiff/git_diff_tree.go | 13 +- .../services/gitdiff/git_diff_tree_test.go | 42 +- .../gitea/source/services/gitdiff/gitdiff.go | 52 +- .../services/gitdiff/gitdiff_excerpt.go | 2 +- .../services/gitdiff/gitdiff_excerpt_test.go | 2 +- .../source/services/gitdiff/gitdiff_test.go | 29 +- .../source/services/gitdiff/highlightdiff.go | 6 +- .../services/gitdiff/highlightdiff_test.go | 2 +- .../source/services/gitdiff/main_test.go | 8 +- .../source/services/gitdiff/submodule.go | 8 +- .../source/services/gitdiff/submodule_test.go | 4 +- .../gitea/source/services/indexer/indexer.go | 8 +- .../gitea/source/services/indexer/notify.go | 20 +- .../gitea/source/services/issue/assignee.go | 487 +- .../source/services/issue/assignee_test.go | 61 +- .../gitea/source/services/issue/comments.go | 34 +- package/gitea/source/services/issue/commit.go | 23 +- .../source/services/issue/commit_test.go | 14 +- .../gitea/source/services/issue/content.go | 8 +- package/gitea/source/services/issue/issue.go | 135 +- .../gitea/source/services/issue/issue_test.go | 8 +- package/gitea/source/services/issue/label.go | 10 +- .../gitea/source/services/issue/label_test.go | 6 +- .../gitea/source/services/issue/main_test.go | 6 +- .../gitea/source/services/issue/milestone.go | 8 +- .../source/services/issue/milestone_test.go | 6 +- package/gitea/source/services/issue/pull.go | 32 +- .../gitea/source/services/issue/reaction.go | 4 +- .../source/services/issue/reaction_test.go | 10 +- .../source/services/issue/review_request.go | 283 + package/gitea/source/services/issue/status.go | 10 +- .../gitea/source/services/issue/suggestion.go | 8 +- .../source/services/issue/suggestion_test.go | 6 +- .../gitea/source/services/issue/template.go | 14 +- package/gitea/source/services/lfs/locks.go | 20 +- package/gitea/source/services/lfs/server.go | 79 +- .../gitea/source/services/lfs/server_test.go | 12 +- .../services/mailer/incoming/incoming.go | 11 +- .../mailer/incoming/incoming_handler.go | 26 +- .../services/mailer/incoming/incoming_test.go | 55 +- .../mailer/incoming/payload/payload.go | 4 +- .../source/services/mailer/incoming/reply.go | 137 + package/gitea/source/services/mailer/mail.go | 18 +- .../source/services/mailer/mail_comment.go | 12 +- .../source/services/mailer/mail_issue.go | 18 +- .../services/mailer/mail_issue_common.go | 30 +- .../source/services/mailer/mail_release.go | 22 +- .../services/mailer/mail_release_test.go | 12 +- .../gitea/source/services/mailer/mail_repo.go | 16 +- .../services/mailer/mail_team_invite.go | 14 +- .../gitea/source/services/mailer/mail_test.go | 59 +- .../gitea/source/services/mailer/mail_user.go | 14 +- .../services/mailer/mail_workflow_run.go | 22 +- .../gitea/source/services/mailer/mailer.go | 14 +- .../gitea/source/services/mailer/main_test.go | 6 +- .../gitea/source/services/mailer/notify.go | 16 +- .../source/services/mailer/sender/dummy.go | 2 +- .../services/mailer/sender/main_test.go | 2 +- .../source/services/mailer/sender/message.go | 8 +- .../services/mailer/sender/message_test.go | 2 +- .../source/services/mailer/sender/sendmail.go | 8 +- .../source/services/mailer/sender/smtp.go | 4 +- .../source/services/mailer/token/token.go | 4 +- .../gitea/source/services/markup/main_test.go | 2 +- .../source/services/markup/renderhelper.go | 6 +- .../markup/renderhelper_codepreview.go | 22 +- .../markup/renderhelper_codepreview_test.go | 10 +- .../markup/renderhelper_issueicontitle.go | 23 +- .../renderhelper_issueicontitle_test.go | 77 +- .../markup/renderhelper_mention_test.go | 8 +- .../GET_%2Fgitea-test%2Fmilestones | 21 + .../GET_%2Fgitea-test%2Ftest | 10 + ...ET_%2Fgitea-test%2Ftest%2Fcommits%2Fmaster | 8 + ...%2Fgitea-test%2Ftest%2Fcommits%2Freadme-mr | 8 + ...2Fgitea-test%2Ftest%2Fmerge_requests%2F100 | 22 + ...arget%2BProject%2522%2Bis%2B%2522test%2522 | 8 + .../GET_%2Fgitea-test%2Ftickets | 41 + .../GET_%2Fgitea-test%2Ftickets%2F1%2Fnotes | 12 + .../GET_%2Fgitea-test%2Ftickets%2F2%2Fnotes | 19 + .../GET_%2Fgitea-test%2Ftickets%2Ftypes | 21 + .../TestCodebaseDownloadRepo/GET_%2Fusers | 12 + .../GET_%2Fapi%2Fv3%2Frate_limit | 22 + ...%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo | 24 + ...%2F1%2Freactions%3Fpage%3D1%26per_page%3D2 | 23 + ...%2F1%2Freactions%3Fpage%3D2%26per_page%3D2 | 25 + ...on%3Dasc%26per_page%3D100%26sort%3Dcreated | 23 + ...%2F2%2Freactions%3Fpage%3D1%26per_page%3D2 | 24 + ...%2F2%2Freactions%3Fpage%3D2%26per_page%3D2 | 24 + ...%2F2%2Freactions%3Fpage%3D3%26per_page%3D2 | 24 + ...%2F2%2Freactions%3Fpage%3D4%26per_page%3D2 | 25 + ...%2F3%2Freactions%3Fpage%3D1%26per_page%3D2 | 24 + ...%2F4%2Freactions%3Fpage%3D1%26per_page%3D2 | 23 + ...%2F4%2Freactions%3Fpage%3D2%26per_page%3D2 | 25 + ...66%2Freactions%3Fpage%3D1%26per_page%3D100 | 23 + ...66%2Freactions%3Fpage%3D2%26per_page%3D100 | 25 + ...56%2Freactions%3Fpage%3D1%26per_page%3D100 | 24 + ...er_page%3D2%26sort%3Dcreated%26state%3Dall | 24 + ..._repo%2Flabels%3Fpage%3D1%26per_page%3D100 | 23 + ...%3Fpage%3D1%26per_page%3D100%26state%3Dall | 23 + ...est_repo%2Fpulls%2F3%2Frequested_reviewers | 23 + ...ws%2F315859956%2Fcomments%3Fper_page%3D100 | 24 + ...ws%2F315860062%2Fcomments%3Fper_page%3D100 | 24 + ...ws%2F315861440%2Fcomments%3Fper_page%3D100 | 24 + ...epo%2Fpulls%2F3%2Freviews%3Fper_page%3D100 | 23 + ...est_repo%2Fpulls%2F4%2Frequested_reviewers | 23 + ...ws%2F338338740%2Fcomments%3Fper_page%3D100 | 23 + ...ws%2F338339651%2Fcomments%3Fper_page%3D100 | 24 + ...ws%2F338349019%2Fcomments%3Fper_page%3D100 | 23 + ...epo%2Fpulls%2F4%2Freviews%3Fper_page%3D100 | 23 + ...88%2Freactions%3Fpage%3D1%26per_page%3D100 | 24 + ...44%2Freactions%3Fpage%3D1%26per_page%3D100 | 24 + ...er_page%3D2%26sort%3Dcreated%26state%3Dall | 23 + ...epo%2Freleases%3Fpage%3D1%26per_page%3D100 | 23 + ...ET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo | 7 + ...es%2F1%2Freactions%3Flimit%3D50%26page%3D1 | 10 + ...s%2F10%2Freactions%3Flimit%3D50%26page%3D1 | 10 + ...s%2F11%2Freactions%3Flimit%3D50%26page%3D1 | 10 + ...s%2F12%2Freactions%3Flimit%3D50%26page%3D1 | 10 + ...s%2F13%2Freactions%3Flimit%3D50%26page%3D1 | 10 + ...es%2F2%2Freactions%3Flimit%3D50%26page%3D1 | 10 + ...es%2F3%2Freactions%3Flimit%3D50%26page%3D1 | 10 + ...ues%2F4%2Fcomments%3Flimit%3D50%26page%3D1 | 10 + ...es%2F4%2Freactions%3Flimit%3D50%26page%3D1 | 10 + ...es%2F5%2Freactions%3Flimit%3D50%26page%3D1 | 10 + ...es%2F6%2Freactions%3Flimit%3D50%26page%3D1 | 10 + ...es%2F7%2Freactions%3Flimit%3D50%26page%3D1 | 10 + ...es%2F8%2Freactions%3Flimit%3D50%26page%3D1 | 10 + ...es%2F9%2Freactions%3Flimit%3D50%26page%3D1 | 10 + ...o%2Fissues%2Fcomments%2F116550%2Freactions | 8 + ...o%2Fissues%2Fcomments%2F116552%2Freactions | 8 + ...2%26page%3D3%26state%3Dall%26type%3Dissues | 10 + ...0%26page%3D1%26state%3Dall%26type%3Dissues | 9 + ...test_repo%2Flabels%3Flimit%3D50%26page%3D1 | 10 + ...ones%3Flimit%3D50%26page%3D1%26state%3Dall | 10 + ...po%2Fpulls%2F7%2Freviews%2F1770%2Fcomments | 8 + ...po%2Fpulls%2F7%2Freviews%2F1771%2Fcomments | 8 + ...po%2Fpulls%2F7%2Freviews%2F1772%2Fcomments | 8 + ...ulls%2F7%2Freviews%3Flimit%3D50%26page%3D1 | 9 + ...pulls%3Flimit%3D3%26page%3D1%26state%3Dall | 10 + ...ulls%3Flimit%3D50%26page%3D1%26state%3Dall | 9 + ...st_repo%2Freleases%3Flimit%3D50%26page%3D1 | 9 + ...Ftest_repo%2Ftopics%3Flimit%3D0%26page%3D1 | 10 + .../GET_%2Fapi%2Fv1%2Fsettings%2Fapi | 8 + .../GET_%2Fapi%2Fv1%2Fversion | 8 + .../GET_%2Fapi%2Fv4%2Fprojects%2F15578026 | 21 + ...F1%2Faward_emoji%3Fpage%3D1%26per_page%3D2 | 28 + ...F1%2Faward_emoji%3Fpage%3D2%26per_page%3D2 | 30 + ...F2%2Faward_emoji%3Fpage%3D1%26per_page%3D2 | 28 + ...F2%2Faward_emoji%3Fpage%3D2%26per_page%3D2 | 28 + ...F2%2Faward_emoji%3Fpage%3D3%26per_page%3D2 | 28 + ...F2%2Faward_emoji%3Fpage%3D4%26per_page%3D2 | 30 + ...%2Fdiscussions%3Fpage%3D1%26per_page%3D100 | 28 + ...e_state_events%3Fpage%3D1%26per_page%3D100 | 30 + ...%26per_page%3D2%26sort%3Dasc%26state%3Dall | 28 + ...78026%2Flabels%3Fpage%3D1%26per_page%3D100 | 28 + ...F15578026%2Fmerge_requests%2F1%2Fapprovals | 21 + ...F15578026%2Fmerge_requests%2F2%2Fapprovals | 21 + ...2Fprojects%2F15578026%2Fmerge_requests%2F3 | 21 + ...F3%2Faward_emoji%3Fpage%3D1%26per_page%3D2 | 28 + ...2Fprojects%2F15578026%2Fmerge_requests%2F4 | 21 + ...F4%2Faward_emoji%3Fpage%3D1%26per_page%3D2 | 30 + ...%3Fpage%3D1%26per_page%3D2%26view%3Dsimple | 28 + ...%3Fpage%3D1%26per_page%3D100%26state%3Dall | 28 + ...026%2Freleases%3Fpage%3D1%26per_page%3D100 | 28 + ...Fapi%2Fv4%2Fprojects%2Fgitea%252Ftest_repo | 21 + .../GET_%2Fapi%2Fv4%2Fversion | 21 + ...%2Fapi%2Fv1%2Frepos%2Flunnytest%2FTESTREPO | 3 + ...nnytest%2FTESTREPO%2Fissues%2F1%2Fcomments | 3 + ...ESTREPO%2Fissues%3Fpage%3D1%26state%3Dopen | 3 + ...v1%2Frepos%2Flunnytest%2FTESTREPO%2Flabels | 3 + ...Frepos%2Flunnytest%2FTESTREPO%2Fmilestones | 3 + .../GET_%2F~api%2Fissues%2F397%2Fiterations | 3 + .../GET_%2F~api%2Fissues%2F398%2Fchanges | 3 + .../GET_%2F~api%2Fissues%2F398%2Fcomments | 3 + .../GET_%2F~api%2Fissues%2F398%2Fiterations | 3 + ...o-gitea-test_repo%2522%26withFields%3Dtrue | 3 + ...49%2Fiterations%3Fcount%3D100%26offset%3D0 | 3 + ...%2Fiterations%3Fcount%3D100%26offset%3D100 | 3 + ...h%2522%2Bis%2B%2522go-gitea-test_repo%2522 | 3 + .../GET_%2F~api%2Fpulls%2F186%2Fmerge-preview | 3 + .../GET_%2F~api%2Fpulls%2F186%2Freviews | 3 + ...t%2522%2Bis%2B%2522go-gitea-test_repo%2522 | 3 + .../GET_%2F~api%2Fusers%2F317 | 3 + ...ET_%2F~api%2Fusers%2F317%2Femail-addresses | 3 + .../GET_%2F~api%2Fusers%2F336 | 3 + ...ET_%2F~api%2Fusers%2F336%2Femail-addresses | 3 + .../GET_%2F~api%2Fversion%2Fserver | 3 + .../source/services/migrations/codebase.go | 8 +- .../services/migrations/codebase_test.go | 37 +- .../source/services/migrations/codecommit.go | 8 +- .../source/services/migrations/common.go | 11 +- .../gitea/source/services/migrations/dump.go | 30 +- .../gitea/source/services/migrations/error.go | 2 +- .../gitea/source/services/migrations/git.go | 2 +- .../source/services/migrations/gitbucket.go | 17 +- .../services/migrations/gitea_downloader.go | 53 +- .../migrations/gitea_downloader_test.go | 67 +- .../services/migrations/gitea_uploader.go | 52 +- .../migrations/gitea_uploader_test.go | 32 +- .../source/services/migrations/github.go | 48 +- .../source/services/migrations/github_test.go | 63 +- .../source/services/migrations/gitlab.go | 20 +- .../source/services/migrations/gitlab_test.go | 156 +- .../gitea/source/services/migrations/gogs.go | 6 +- .../source/services/migrations/gogs_test.go | 30 +- .../source/services/migrations/http_client.go | 35 +- .../source/services/migrations/main_test.go | 8 +- .../source/services/migrations/migrate.go | 38 +- .../services/migrations/migrate_test.go | 20 +- .../source/services/migrations/onedev.go | 18 +- .../source/services/migrations/onedev_test.go | 46 +- .../source/services/migrations/restore.go | 14 +- .../services/migrations/restore_test.go | 74 + .../source/services/migrations/update.go | 10 +- .../gitea/source/services/mirror/mirror.go | 8 +- .../source/services/mirror/mirror_pull.go | 93 +- .../source/services/mirror/mirror_push.go | 34 +- .../gitea/source/services/mirror/notifier.go | 8 +- package/gitea/source/services/mirror/queue.go | 8 +- .../gitea/source/services/notify/notifier.go | 18 +- .../gitea/source/services/notify/notify.go | 28 +- package/gitea/source/services/notify/null.go | 18 +- .../services/oauth2_provider/access_token.go | 18 +- .../source/services/oauth2_provider/init.go | 2 +- .../services/oauth2_provider/jwtsigningkey.go | 6 +- .../source/services/oauth2_provider/token.go | 2 +- package/gitea/source/services/org/org.go | 34 +- package/gitea/source/services/org/org_test.go | 31 +- package/gitea/source/services/org/team.go | 26 +- .../gitea/source/services/org/team_invite.go | 6 +- .../gitea/source/services/org/team_test.go | 18 +- package/gitea/source/services/org/user.go | 10 +- .../gitea/source/services/org/user_test.go | 6 +- .../services/packages/alpine/repository.go | 18 +- .../services/packages/arch/repository.go | 48 +- .../services/packages/arch/repository_test.go | 17 + .../gitea/source/services/packages/auth.go | 8 +- .../source/services/packages/cargo/index.go | 22 +- .../services/packages/cleanup/cleanup.go | 26 +- .../packages/container/blob_uploader.go | 8 +- .../services/packages/container/cleanup.go | 10 +- .../services/packages/container/common.go | 12 +- .../services/packages/debian/repository.go | 16 +- .../services/packages/package_update.go | 14 +- .../source/services/packages/packages.go | 24 +- .../services/packages/pkgspec/manager.go | 6 +- .../services/packages/rpm/repository.go | 16 +- .../source/services/packages/rpm/sign.go | 2 +- .../gitea/source/services/packages/spec.go | 4 +- .../services/packages/terraform/spec.go | 12 +- .../services/packages/terraform/state.go | 6 +- .../gitea/source/services/projects/issue.go | 63 +- .../source/services/projects/issue_test.go | 72 +- .../source/services/projects/main_test.go | 6 +- package/gitea/source/services/pull/check.go | 134 +- .../gitea/source/services/pull/check_test.go | 56 +- package/gitea/source/services/pull/comment.go | 16 +- .../source/services/pull/comment_test.go | 14 +- .../source/services/pull/commit_status.go | 86 +- .../services/pull/commit_status_test.go | 78 +- package/gitea/source/services/pull/edits.go | 8 +- package/gitea/source/services/pull/lfs.go | 14 +- .../gitea/source/services/pull/main_test.go | 4 +- package/gitea/source/services/pull/merge.go | 106 +- .../source/services/pull/merge_ff_only.go | 6 +- .../gitea/source/services/pull/merge_merge.go | 6 +- .../source/services/pull/merge_prepare.go | 26 +- .../source/services/pull/merge_rebase.go | 10 +- .../source/services/pull/merge_squash.go | 24 +- .../gitea/source/services/pull/merge_tree.go | 10 +- .../source/services/pull/merge_tree_test.go | 6 +- package/gitea/source/services/pull/patch.go | 18 +- .../source/services/pull/patch_unmerged.go | 4 +- .../source/services/pull/protected_branch.go | 4 +- package/gitea/source/services/pull/pull.go | 266 +- .../gitea/source/services/pull/pull_test.go | 69 +- package/gitea/source/services/pull/review.go | 30 +- .../gitea/source/services/pull/review_test.go | 8 +- .../gitea/source/services/pull/reviewer.go | 14 +- .../source/services/pull/reviewer_test.go | 6 +- .../gitea/source/services/pull/temp_repo.go | 14 +- package/gitea/source/services/pull/update.go | 103 +- .../source/services/pull/update_rebase.go | 16 +- .../gitea/source/services/pull/update_test.go | 59 +- .../gitea/source/services/release/notes.go | 65 +- .../source/services/release/notes_test.go | 70 +- .../gitea/source/services/release/release.go | 50 +- .../source/services/release/release_test.go | 51 +- package/gitea/source/services/release/tag.go | 12 +- .../gitea/source/services/repository/adopt.go | 26 +- .../source/services/repository/adopt_test.go | 12 +- .../services/repository/archiver/archiver.go | 84 +- .../repository/archiver/archiver_test.go | 26 +- .../source/services/repository/avatar.go | 10 +- .../source/services/repository/avatar_test.go | 6 +- .../source/services/repository/branch.go | 71 +- .../gitea/source/services/repository/cache.go | 8 +- .../gitea/source/services/repository/check.go | 16 +- .../services/repository/collaboration.go | 18 +- .../services/repository/collaboration_test.go | 32 +- .../source/services/repository/commit.go | 4 +- .../repository/commitstatus/commitstatus.go | 24 +- .../services/repository/contributors_graph.go | 20 +- .../repository/contributors_graph_test.go | 8 +- .../source/services/repository/create.go | 85 +- .../source/services/repository/create_test.go | 8 +- .../source/services/repository/delete.go | 57 +- .../source/services/repository/delete_test.go | 38 +- .../services/repository/files/cherry_pick.go | 111 +- .../services/repository/files/commit.go | 6 +- .../services/repository/files/content.go | 25 +- .../services/repository/files/content_test.go | 8 +- .../source/services/repository/files/diff.go | 4 +- .../services/repository/files/diff_test.go | 10 +- .../source/services/repository/files/file.go | 14 +- .../source/services/repository/files/patch.go | 68 +- .../services/repository/files/patch_test.go | 36 + .../services/repository/files/temp_repo.go | 32 +- .../repository/files/temp_repo_test.go | 4 +- .../source/services/repository/files/tree.go | 22 +- .../services/repository/files/tree_test.go | 10 +- .../services/repository/files/update.go | 30 +- .../services/repository/files/upload.go | 6 +- .../gitea/source/services/repository/fork.go | 24 +- .../source/services/repository/fork_test.go | 12 +- .../source/services/repository/generate.go | 23 +- .../services/repository/generate_test.go | 2 +- .../services/repository/gitgraph/graph.go | 6 +- .../repository/gitgraph/graph_models.go | 71 +- .../repository/gitgraph/graph_test.go | 2 +- .../services/repository/gitgraph/parser.go | 4 +- .../services/repository/heatmap_indexer.go | 12 +- .../repository/heatmap_indexer_test.go | 33 +- .../gitea/source/services/repository/hooks.go | 10 +- .../gitea/source/services/repository/init.go | 25 +- .../gitea/source/services/repository/lfs.go | 16 +- .../source/services/repository/lfs_test.go | 16 +- .../source/services/repository/license.go | 18 +- .../services/repository/license_test.go | 2 +- .../source/services/repository/main_test.go | 2 +- .../services/repository/merge_upstream.go | 33 +- .../source/services/repository/migrate.go | 36 +- .../gitea/source/services/repository/push.go | 105 +- .../source/services/repository/repo_team.go | 12 +- .../services/repository/repo_team_test.go | 6 +- .../source/services/repository/repository.go | 43 +- .../services/repository/repository_test.go | 33 +- .../source/services/repository/setting.go | 10 +- .../source/services/repository/template.go | 16 +- .../source/services/repository/transfer.go | 39 +- .../services/repository/transfer_test.go | 24 +- .../gitea/source/services/secrets/secrets.go | 4 +- .../source/services/secrets/validation.go | 2 +- package/gitea/source/services/task/migrate.go | 30 +- package/gitea/source/services/task/task.go | 28 +- .../source/services/uinotification/notify.go | 20 +- package/gitea/source/services/user/avatar.go | 10 +- package/gitea/source/services/user/block.go | 12 +- .../gitea/source/services/user/block_test.go | 4 +- package/gitea/source/services/user/delete.go | 35 +- package/gitea/source/services/user/email.go | 8 +- .../gitea/source/services/user/email_test.go | 4 +- package/gitea/source/services/user/update.go | 17 +- .../gitea/source/services/user/update_test.go | 42 +- package/gitea/source/services/user/user.go | 38 +- .../gitea/source/services/user/user_test.go | 46 +- .../services/versioned_migration/migration.go | 9 +- .../gitea/source/services/webhook/deliver.go | 47 +- .../source/services/webhook/deliver_test.go | 12 +- .../gitea/source/services/webhook/dingtalk.go | 10 +- .../source/services/webhook/dingtalk_test.go | 8 +- .../gitea/source/services/webhook/discord.go | 16 +- .../source/services/webhook/discord_test.go | 10 +- .../gitea/source/services/webhook/feishu.go | 8 +- .../source/services/webhook/feishu_test.go | 8 +- .../gitea/source/services/webhook/general.go | 37 +- .../source/services/webhook/general_test.go | 2 +- .../source/services/webhook/main_test.go | 15 +- .../gitea/source/services/webhook/matrix.go | 18 +- .../source/services/webhook/matrix_test.go | 8 +- .../gitea/source/services/webhook/msteams.go | 10 +- .../source/services/webhook/msteams_test.go | 8 +- .../gitea/source/services/webhook/notifier.go | 65 +- .../source/services/webhook/packagist.go | 10 +- .../source/services/webhook/packagist_test.go | 8 +- .../source/services/webhook/payloader.go | 8 +- .../gitea/source/services/webhook/slack.go | 27 +- .../source/services/webhook/slack_test.go | 27 +- .../gitea/source/services/webhook/telegram.go | 16 +- .../source/services/webhook/telegram_test.go | 8 +- .../gitea/source/services/webhook/webhook.go | 55 +- .../source/services/webhook/webhook_test.go | 151 +- .../source/services/webhook/wechatwork.go | 8 +- .../source/services/webtheme/webtheme.go | 12 +- package/gitea/source/services/wiki/wiki.go | 34 +- .../gitea/source/services/wiki/wiki_path.go | 10 +- .../gitea/source/services/wiki/wiki_test.go | 14 +- package/gitea/source/snap/part-gitea-build.sh | 6 +- package/gitea/source/snap/part-gitea-pull.sh | 2 +- package/gitea/source/snap/snapcraft.yaml | 16 +- ...tylelint.config.js => stylelint.config.ts} | 20 +- package/gitea/source/tailwind.config.ts | 2 +- .../gitea/source/templates/admin/actions.tmpl | 5 +- .../templates/admin/applications/list.tmpl | 2 +- .../admin/applications/oauth2_edit.tmpl | 2 +- .../source/templates/admin/auth/edit.tmpl | 7 +- .../source/templates/admin/auth/list.tmpl | 2 +- .../source/templates/admin/auth/new.tmpl | 2 +- .../templates/admin/auth/source/oauth.tmpl | 5 + .../source/templates/admin/badge/edit.tmpl | 2 +- .../source/templates/admin/badge/list.tmpl | 2 +- .../source/templates/admin/badge/new.tmpl | 2 +- .../source/templates/admin/badge/users.tmpl | 18 +- .../source/templates/admin/badge/view.tmpl | 14 +- .../gitea/source/templates/admin/config.tmpl | 6 +- .../config_settings/config_settings.tmpl | 2 +- .../gitea/source/templates/admin/cron.tmpl | 2 +- .../source/templates/admin/dashboard.tmpl | 7 +- .../source/templates/admin/emails/list.tmpl | 2 +- .../source/templates/admin/hook_new.tmpl | 4 +- .../gitea/source/templates/admin/hooks.tmpl | 2 +- .../source/templates/admin/layout_head.tmpl | 8 +- .../gitea/source/templates/admin/navbar.tmpl | 17 +- .../gitea/source/templates/admin/notice.tmpl | 4 +- .../source/templates/admin/org/list.tmpl | 2 +- .../source/templates/admin/packages/list.tmpl | 4 +- .../source/templates/admin/perftrace.tmpl | 2 +- .../gitea/source/templates/admin/queue.tmpl | 2 +- .../source/templates/admin/queue_manage.tmpl | 2 +- .../source/templates/admin/repo/list.tmpl | 4 +- .../templates/admin/repo/unadopted.tmpl | 2 +- .../source/templates/admin/runners/edit.tmpl | 2 +- .../source/templates/admin/self_check.tmpl | 2 +- .../source/templates/admin/stacktrace.tmpl | 2 +- .../gitea/source/templates/admin/stats.tmpl | 2 +- .../source/templates/admin/system_status.tmpl | 2 +- .../source/templates/admin/user/edit.tmpl | 2 +- .../source/templates/admin/user/list.tmpl | 2 +- .../source/templates/admin/user/new.tmpl | 2 +- .../source/templates/admin/user/view.tmpl | 2 +- .../templates/admin/user/view_details.tmpl | 28 +- .../templates/admin/user/view_emails.tmpl | 6 +- .../gitea/source/templates/base/alert.tmpl | 28 +- .../source/templates/base/alert_details.tmpl | 6 +- .../gitea/source/templates/base/footer.tmpl | 5 +- package/gitea/source/templates/base/head.tmpl | 5 +- .../source/templates/base/head_opengraph.tmpl | 3 +- .../source/templates/base/head_script.tmpl | 10 +- .../source/templates/base/head_style.tmpl | 2 +- .../templates/devtest/avatar-stack.tmpl | 18 + .../templates/devtest/badge-commit-sign.tmpl | 2 +- .../templates/devtest/devtest-header.tmpl | 4 +- .../templates/devtest/fetch-action.tmpl | 21 +- .../source/templates/devtest/flex-list.tmpl | 106 +- .../templates/devtest/fomantic-dropdown.tmpl | 2 +- .../templates/devtest/fomantic-modal.tmpl | 22 +- .../source/templates/devtest/gitea-ui.tmpl | 11 - .../templates/devtest/relative-time.tmpl | 1 + .../templates/devtest/repo-action-view.tmpl | 11 +- .../templates/devtest/toast-and-message.tmpl | 15 + .../gitea/source/templates/devtest/toast.tmpl | 11 - .../gitea/source/templates/explore/repos.tmpl | 1 + .../source/templates/explore/user_list.tmpl | 14 +- package/gitea/source/templates/home.tmpl | 2 +- .../templates/mail/repo/issue/default.tmpl | 22 +- .../source/templates/org/follow_unfollow.tmpl | 2 +- .../gitea/source/templates/org/header.tmpl | 38 +- package/gitea/source/templates/org/home.tmpl | 29 +- .../source/templates/org/member/members.tmpl | 25 +- .../templates/org/settings/actions.tmpl | 4 +- .../org/settings/actions_general.tmpl | 2 +- .../templates/org/settings/applications.tmpl | 2 +- .../settings/applications_oauth2_edit.tmpl | 2 +- .../templates/org/settings/blocked_users.tmpl | 2 +- .../templates/org/settings/hook_new.tmpl | 4 +- .../source/templates/org/settings/hooks.tmpl | 2 +- .../source/templates/org/settings/labels.tmpl | 2 +- .../templates/org/settings/layout_head.tmpl | 10 +- .../source/templates/org/settings/navbar.tmpl | 5 +- .../templates/org/settings/options.tmpl | 2 +- .../org/settings/options_dangerzone.tmpl | 32 +- .../templates/org/settings/packages.tmpl | 2 +- .../settings/packages_cleanup_rules_edit.tmpl | 2 +- .../packages_cleanup_rules_preview.tmpl | 2 +- .../templates/org/settings/runners_edit.tmpl | 2 +- .../source/templates/org/team/invite.tmpl | 20 +- .../source/templates/org/team/members.tmpl | 40 +- .../gitea/source/templates/org/team/new.tmpl | 54 +- .../templates/org/team/repositories.tmpl | 14 +- .../source/templates/org/team/sidebar.tmpl | 54 +- .../source/templates/org/team/teams.tmpl | 73 +- .../templates/package/content/cargo.tmpl | 2 +- .../templates/package/content/chef.tmpl | 2 +- .../templates/package/content/composer.tmpl | 2 +- .../source/templates/package/content/npm.tmpl | 11 +- .../templates/package/content/nuget.tmpl | 6 +- .../source/templates/package/content/pub.tmpl | 2 +- .../templates/package/content/pypi.tmpl | 4 +- .../source/templates/package/settings.tmpl | 12 +- .../package/shared/cleanup_rules/list.tmpl | 22 +- .../source/templates/package/shared/list.tmpl | 10 +- .../templates/package/shared/versionlist.tmpl | 10 +- .../gitea/source/templates/projects/list.tmpl | 24 +- .../gitea/source/templates/projects/view.tmpl | 10 +- .../source/templates/repo/actions/list.tmpl | 147 +- .../templates/repo/actions/runs_list.tmpl | 30 +- .../source/templates/repo/actions/status.tmpl | 23 - .../source/templates/repo/actions/view.tmpl | 3 +- .../repo/actions/view_component.tmpl | 31 +- .../repo/actions/workflow_dispatch.tmpl | 15 +- .../actions/workflow_dispatch_inputs.tmpl | 6 +- .../gitea/source/templates/repo/activity.tmpl | 2 +- .../gitea/source/templates/repo/blame.tmpl | 8 +- .../source/templates/repo/branch/list.tmpl | 42 +- .../repo/commit_load_branches_and_tags.tmpl | 4 +- .../source/templates/repo/commit_page.tmpl | 51 +- .../templates/repo/commit_sign_badge.tmpl | 4 +- .../templates/repo/commit_statuses.tmpl | 8 +- .../source/templates/repo/commits_list.tmpl | 48 +- .../templates/repo/commits_list_small.tmpl | 25 +- .../source/templates/repo/commits_table.tmpl | 27 +- .../source/templates/repo/contributors.tmpl | 1 + .../gitea/source/templates/repo/diff/box.tmpl | 8 +- .../source/templates/repo/diff/compare.tmpl | 4 +- .../templates/repo/diff/image_diff.tmpl | 4 +- .../source/templates/repo/diff/stats.tmpl | 4 +- .../templates/repo/editor/commit_form.tmpl | 6 +- .../source/templates/repo/editor/edit.tmpl | 12 +- .../source/templates/repo/editor/patch.tmpl | 8 +- .../source/templates/repo/graph/commits.tmpl | 9 +- .../gitea/source/templates/repo/header.tmpl | 110 +- .../source/templates/repo/header/fork.tmpl | 47 + .../source/templates/repo/header/star.tmpl | 19 + .../source/templates/repo/header/watch.tmpl | 19 + .../templates/repo/home_sidebar_bottom.tmpl | 90 +- .../templates/repo/home_sidebar_top.tmpl | 115 +- .../templates/repo/icons/action_status.tmpl | 30 + .../repo/{ => icons}/commit_status.tmpl | 0 .../repo/issue/branch_selector_field.tmpl | 7 +- .../source/templates/repo/issue/card.tmpl | 2 +- .../templates/repo/issue/filter_actions.tmpl | 10 +- .../templates/repo/issue/filter_list.tmpl | 30 +- .../templates/repo/issue/milestones.tmpl | 34 +- .../templates/repo/issue/openclose.tmpl | 3 +- .../source/templates/repo/issue/search.tmpl | 2 +- .../repo/issue/sidebar/due_date.tmpl | 2 +- .../issue/sidebar/issue_dependencies.tmpl | 10 +- .../repo/issue/sidebar/label_list.tmpl | 2 +- .../repo/issue/sidebar/project_list.tmpl | 65 +- .../issue/sidebar/stopwatch_timetracker.tmpl | 2 +- .../templates/repo/issue/view_content.tmpl | 17 +- .../repo/issue/view_content/comments.tmpl | 44 +- .../view_content/comments_authorlink.tmpl | 6 +- .../view_content/comments_delete_time.tmpl | 6 +- .../repo/issue/view_content/context_menu.tmpl | 17 +- .../repo/issue/view_content/conversation.tmpl | 2 +- .../issue/view_content/pull_merge_box.tmpl | 451 +- .../view_content/pull_merge_instruction.tmpl | 48 +- .../pull_merge_status_checks.tmpl | 34 + .../view_content/update_branch_by_merge.tmpl | 58 +- .../repo/issue/view_content/watching.tmpl | 19 +- .../source/templates/repo/latest_commit.tmpl | 17 +- .../templates/repo/migrate/migrating.tmpl | 4 +- .../source/templates/repo/pulls/status.tmpl | 63 - .../templates/repo/pulls/status_items.tmpl | 38 + .../source/templates/repo/release/list.tmpl | 2 +- .../source/templates/repo/release/new.tmpl | 2 +- .../source/templates/repo/search_name.tmpl | 2 +- .../templates/repo/settings/actions.tmpl | 2 +- .../repo/settings/actions_general.tmpl | 16 +- .../templates/repo/settings/branches.tmpl | 14 +- .../repo/settings/collaboration.tmpl | 38 +- .../templates/repo/settings/deploy_keys.tmpl | 18 +- .../templates/repo/settings/githook_edit.tmpl | 24 +- .../templates/repo/settings/githooks.tmpl | 11 +- .../templates/repo/settings/layout_head.tmpl | 10 +- .../source/templates/repo/settings/lfs.tmpl | 2 +- .../templates/repo/settings/lfs_file.tmpl | 4 +- .../repo/settings/lfs_file_find.tmpl | 8 +- .../templates/repo/settings/lfs_locks.tmpl | 2 +- .../templates/repo/settings/lfs_pointers.tmpl | 2 +- .../templates/repo/settings/navbar.tmpl | 2 +- .../templates/repo/settings/options.tmpl | 116 +- .../repo/settings/protected_branch.tmpl | 45 +- .../repo/settings/public_access.tmpl | 2 +- .../templates/repo/settings/runner_edit.tmpl | 2 +- .../templates/repo/settings/secrets.tmpl | 2 +- .../source/templates/repo/settings/tags.tmpl | 2 +- .../templates/repo/settings/webhook/base.tmpl | 2 +- .../repo/settings/webhook/base_list.tmpl | 11 +- .../repo/settings/webhook/history.tmpl | 26 +- .../templates/repo/settings/webhook/new.tmpl | 4 +- .../source/templates/repo/star_unstar.tmpl | 13 - .../source/templates/repo/user_cards.tmpl | 13 +- .../source/templates/repo/view_content.tmpl | 6 +- .../source/templates/repo/view_file.tmpl | 8 +- .../source/templates/repo/view_list.tmpl | 14 +- .../source/templates/repo/watch_unwatch.tmpl | 13 - .../gitea/source/templates/repo/wiki/new.tmpl | 2 +- .../source/templates/repo/wiki/pages.tmpl | 2 +- .../source/templates/repo/wiki/revision.tmpl | 6 +- .../source/templates/repo/wiki/view.tmpl | 4 +- .../templates/shared/actions/runner_edit.tmpl | 8 +- .../templates/shared/actions/runner_list.tmpl | 43 +- .../shared/actions/scoped_workflows.tmpl | 88 + .../templates/shared/combomarkdowneditor.tmpl | 3 +- .../source/templates/shared/issuelist.tmpl | 50 +- .../source/templates/shared/repo/list.tmpl | 28 +- .../source/templates/shared/repo/search.tmpl | 13 +- .../templates/shared/search/code/results.tmpl | 6 +- .../source/templates/shared/searchbottom.tmpl | 2 +- .../templates/shared/secrets/add_list.tmpl | 22 +- .../templates/shared/user/authorlink.tmpl | 2 +- .../templates/shared/user/blocked_users.tmpl | 32 +- .../shared/user/profile_big_avatar.tmpl | 21 +- .../shared/variables/variable_list.tmpl | 22 +- .../gitea/source/templates/status/500.tmpl | 4 +- .../templates/swagger/openapi-viewer.tmpl | 7 +- .../source/templates/swagger/v1_json.tmpl | 1658 +- .../templates/swagger/v1_openapi3_json.tmpl | 34336 ++++++++++++++++ .../source/templates/user/auth/captcha.tmpl | 6 +- .../templates/user/auth/link_account.tmpl | 8 +- .../templates/user/dashboard/feeds.tmpl | 28 +- .../templates/user/dashboard/milestones.tmpl | 43 +- .../templates/user/dashboard/repolist.tmpl | 2 +- .../gitea/source/templates/user/heatmap.tmpl | 1 + .../user/notification/notification_div.tmpl | 6 +- .../notification_subscriptions.tmpl | 7 +- .../gitea/source/templates/user/profile.tmpl | 2 + .../templates/user/settings/account.tmpl | 12 +- .../templates/user/settings/actions.tmpl | 4 +- .../user/settings/actions_general.tmpl | 2 +- .../templates/user/settings/appearance.tmpl | 2 +- .../templates/user/settings/applications.tmpl | 22 +- .../settings/applications_oauth2_edit.tmpl | 2 +- .../settings/applications_oauth2_list.tmpl | 20 +- .../user/settings/blocked_users.tmpl | 2 +- .../user/settings/grants_oauth2.tmpl | 20 +- .../templates/user/settings/hook_new.tmpl | 4 +- .../source/templates/user/settings/hooks.tmpl | 2 +- .../source/templates/user/settings/keys.tmpl | 2 +- .../templates/user/settings/keys_gpg.tmpl | 20 +- .../user/settings/keys_principal.tmpl | 20 +- .../templates/user/settings/keys_ssh.tmpl | 26 +- .../templates/user/settings/layout_head.tmpl | 8 +- .../templates/user/settings/navbar.tmpl | 5 +- .../user/settings/notifications.tmpl | 2 +- .../templates/user/settings/organization.tmpl | 31 +- .../templates/user/settings/packages.tmpl | 2 +- .../settings/packages_cleanup_rules_edit.tmpl | 2 +- .../packages_cleanup_rules_preview.tmpl | 2 +- .../templates/user/settings/profile.tmpl | 2 +- .../source/templates/user/settings/repos.tmpl | 2 +- .../templates/user/settings/runner_edit.tmpl | 2 +- .../user/settings/security/accountlinks.tmpl | 18 +- .../user/settings/security/openid.tmpl | 18 +- .../user/settings/security/security.tmpl | 2 +- .../user/settings/security/twofa.tmpl | 6 +- .../user/settings/security/twofa_enroll.tmpl | 2 +- .../user/settings/security/webauthn.tmpl | 18 +- .../gitea/source/templates/webhook/new.tmpl | 30 +- .../gitea/source/tests/e2e/codeeditor.test.ts | 22 +- package/gitea/source/tests/e2e/events.test.ts | 33 +- .../source/tests/e2e/external-render.test.ts | 74 +- .../source/tests/e2e/file-view-render.test.ts | 88 +- package/gitea/source/tests/e2e/fork.test.ts | 18 + .../gitea/source/tests/e2e/heatmap.test.ts | 9 + .../source/tests/e2e/issue-comment.test.ts | 26 + .../source/tests/e2e/issue-project.test.ts | 443 + .../gitea/source/tests/e2e/licenses.test.ts | 2 +- package/gitea/source/tests/e2e/login.test.ts | 11 +- .../gitea/source/tests/e2e/mermaid.test.ts | 13 +- .../gitea/source/tests/e2e/milestone.test.ts | 5 +- package/gitea/source/tests/e2e/org.test.ts | 41 +- .../gitea/source/tests/e2e/pr-create.test.ts | 23 + .../gitea/source/tests/e2e/pr-review.test.ts | 53 + .../gitea/source/tests/e2e/reactions.test.ts | 28 +- package/gitea/source/tests/e2e/readme.test.ts | 3 +- .../gitea/source/tests/e2e/register.test.ts | 5 +- .../gitea/source/tests/e2e/release.test.ts | 19 + .../source/tests/e2e/repo-collab.test.ts | 24 + .../source/tests/e2e/repo-star-watch.test.ts | 20 + package/gitea/source/tests/e2e/repo.test.ts | 3 +- .../source/tests/e2e/user-settings.test.ts | 22 +- package/gitea/source/tests/e2e/utils.ts | 118 +- .../gitea/source/tests/e2e/webauthn.test.ts | 67 + package/gitea/source/tests/fuzz/fuzz_test.go | 6 +- .../user2/commits_search_test.git/config | 2 +- .../gitea/source/tests/integration/README.md | 106 - .../source/tests/integration/README_ZH.md | 91 - ...ET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo | 3 + ...ues%2F1%2Fcomments%3Flimit%3D50%26page%3D1 | 3 + ...es%2F1%2Freactions%3Flimit%3D50%26page%3D1 | 3 + ...es%2F10%2Fcomments%3Flimit%3D50%26page%3D1 | 3 + ...s%2F10%2Freactions%3Flimit%3D50%26page%3D1 | 3 + ...es%2F11%2Fcomments%3Flimit%3D50%26page%3D1 | 3 + ...s%2F11%2Freactions%3Flimit%3D50%26page%3D1 | 3 + ...es%2F12%2Fcomments%3Flimit%3D50%26page%3D1 | 3 + ...s%2F12%2Freactions%3Flimit%3D50%26page%3D1 | 3 + ...es%2F13%2Fcomments%3Flimit%3D50%26page%3D1 | 3 + ...s%2F13%2Freactions%3Flimit%3D50%26page%3D1 | 3 + ...ues%2F2%2Fcomments%3Flimit%3D50%26page%3D1 | 3 + ...es%2F2%2Freactions%3Flimit%3D50%26page%3D1 | 3 + ...ues%2F3%2Fcomments%3Flimit%3D50%26page%3D1 | 3 + ...es%2F3%2Freactions%3Flimit%3D50%26page%3D1 | 3 + ...ues%2F4%2Fcomments%3Flimit%3D50%26page%3D1 | 3 + ...es%2F4%2Freactions%3Flimit%3D50%26page%3D1 | 3 + ...ues%2F5%2Fcomments%3Flimit%3D50%26page%3D1 | 3 + ...es%2F5%2Freactions%3Flimit%3D50%26page%3D1 | 3 + ...ues%2F6%2Fcomments%3Flimit%3D50%26page%3D1 | 3 + ...es%2F6%2Freactions%3Flimit%3D50%26page%3D1 | 3 + ...ues%2F7%2Fcomments%3Flimit%3D50%26page%3D1 | 3 + ...es%2F7%2Freactions%3Flimit%3D50%26page%3D1 | 3 + ...ues%2F8%2Fcomments%3Flimit%3D50%26page%3D1 | 3 + ...es%2F8%2Freactions%3Flimit%3D50%26page%3D1 | 3 + ...ues%2F9%2Fcomments%3Flimit%3D50%26page%3D1 | 3 + ...es%2F9%2Freactions%3Flimit%3D50%26page%3D1 | 3 + ...epo%2Fissues%2Fcomments%2F1553%2Freactions | 3 + ...epo%2Fissues%2Fcomments%2F1554%2Freactions | 3 + ...7%26page%3D1%26state%3Dall%26type%3Dissues | 3 + ...test_repo%2Flabels%3Flimit%3D50%26page%3D1 | 3 + ...ones%3Flimit%3D50%26page%3D1%26state%3Dall | 3 + ...lls%2F10%2Freviews%3Flimit%3D50%26page%3D1 | 3 + ...lls%2F11%2Freviews%3Flimit%3D50%26page%3D1 | 3 + ...lls%2F12%2Freviews%3Flimit%3D50%26page%3D1 | 3 + ...lls%2F13%2Freviews%3Flimit%3D50%26page%3D1 | 3 + ...ulls%2F8%2Freviews%3Flimit%3D50%26page%3D1 | 3 + ...ulls%2F9%2Freviews%3Flimit%3D50%26page%3D1 | 3 + ...ulls%3Flimit%3D49%26page%3D1%26state%3Dall | 3 + ...st_repo%2Freleases%3Flimit%3D50%26page%3D1 | 3 + ...Ftest_repo%2Ftopics%3Flimit%3D0%26page%3D1 | 3 + .../GET_%2Fapi%2Fv1%2Fsettings%2Fapi | 3 + .../GET_%2Fapi%2Fv1%2Fversion | 3 + ...ET_%2Fgitea%2Ftest_repo%2Fpulls%2F10.patch | 2 + ...ET_%2Fgitea%2Ftest_repo%2Fpulls%2F11.patch | 2 + ...ET_%2Fgitea%2Ftest_repo%2Fpulls%2F12.patch | 2 + ...ET_%2Fgitea%2Ftest_repo%2Fpulls%2F13.patch | 2 + ...GET_%2Fgitea%2Ftest_repo%2Fpulls%2F8.patch | 2 + ...GET_%2Fgitea%2Ftest_repo%2Fpulls%2F9.patch | 2 + .../tests/integration/actions_approve_test.go | 119 +- .../integration/actions_concurrency_test.go | 299 +- .../actions_concurrent_claim_test.go | 118 + .../integration/actions_delete_run_test.go | 16 +- .../tests/integration/actions_inputs_test.go | 10 +- .../tests/integration/actions_job_test.go | 201 +- .../integration/actions_job_token_test.go | 35 +- .../integration/actions_list_filter_test.go | 68 + .../integration/actions_log_finalize_test.go | 32 +- .../tests/integration/actions_log_test.go | 107 +- .../tests/integration/actions_rerun_test.go | 458 +- .../actions_reusable_workflow_test.go | 985 + .../tests/integration/actions_route_test.go | 58 +- .../integration/actions_runner_modify_test.go | 72 +- .../integration/actions_runner_sort_test.go | 130 + .../tests/integration/actions_runner_test.go | 17 +- .../integration/actions_schedule_test.go | 35 +- .../actions_scoped_workflow_test.go | 548 + .../integration/actions_settings_test.go | 8 +- .../tests/integration/actions_trigger_test.go | 243 +- .../integration/actions_variables_test.go | 12 +- .../tests/integration/admin_config_test.go | 67 +- .../tests/integration/admin_user_test.go | 6 +- .../integration/api_actions_artifact_test.go | 461 +- .../api_actions_artifact_v4_test.go | 245 +- .../api_actions_permission_test.go | 11 +- .../tests/integration/api_actions_run_test.go | 256 +- .../integration/api_actions_runner_test.go | 65 +- .../tests/integration/api_admin_org_test.go | 13 +- .../tests/integration/api_admin_test.go | 81 +- .../source/tests/integration/api_auth_test.go | 2 +- .../tests/integration/api_branch_test.go | 62 +- .../api_comment_attachment_test.go | 30 +- .../tests/integration/api_comment_test.go | 41 +- .../source/tests/integration/api_fork_test.go | 48 +- .../api_gitignore_templates_test.go | 17 +- .../tests/integration/api_gpg_keys_test.go | 24 +- .../api_helper_for_declarative_test.go | 73 +- .../tests/integration/api_httpsig_test.go | 10 +- .../integration/api_issue_attachment_test.go | 28 +- .../integration/api_issue_config_test.go | 25 +- .../integration/api_issue_dependency_test.go | 69 +- .../tests/integration/api_issue_label_test.go | 77 +- .../tests/integration/api_issue_lock_test.go | 14 +- .../integration/api_issue_milestone_test.go | 31 +- .../tests/integration/api_issue_pin_test.go | 40 +- .../integration/api_issue_reaction_test.go | 32 +- .../integration/api_issue_stopwatch_test.go | 17 +- .../api_issue_subscription_test.go | 17 +- .../integration/api_issue_templates_test.go | 20 +- .../tests/integration/api_issue_test.go | 247 +- .../api_issue_tracked_time_test.go | 94 +- .../source/tests/integration/api_keys_test.go | 40 +- .../integration/api_label_templates_test.go | 12 +- .../integration/api_license_templates_test.go | 21 +- .../integration/api_notification_test.go | 49 +- .../tests/integration/api_oauth2_apps_test.go | 126 +- .../tests/integration/api_org_avatar_test.go | 18 +- .../source/tests/integration/api_org_test.go | 183 +- .../integration/api_packages_alpine_test.go | 42 +- .../integration/api_packages_arch_test.go | 14 +- .../integration/api_packages_cargo_test.go | 42 +- .../integration/api_packages_chef_test.go | 29 +- .../integration/api_packages_composer_test.go | 65 +- .../integration/api_packages_conan_test.go | 80 +- .../integration/api_packages_conda_test.go | 28 +- .../api_packages_container_test.go | 43 +- .../integration/api_packages_cran_test.go | 49 +- .../integration/api_packages_debian_test.go | 14 +- .../integration/api_packages_generic_test.go | 41 +- .../integration/api_packages_goproxy_test.go | 46 +- .../integration/api_packages_helm_test.go | 14 +- .../integration/api_packages_maven_test.go | 18 +- .../integration/api_packages_npm_test.go | 61 +- .../integration/api_packages_nuget_test.go | 72 +- .../integration/api_packages_pub_test.go | 21 +- .../integration/api_packages_pypi_test.go | 10 +- .../integration/api_packages_rpm_test.go | 14 +- .../integration/api_packages_rubygems_test.go | 10 +- .../integration/api_packages_swift_test.go | 93 +- .../api_packages_terraform_test.go | 8 +- .../tests/integration/api_packages_test.go | 57 +- .../integration/api_packages_vagrant_test.go | 17 +- .../integration/api_private_serv_test.go | 6 +- .../tests/integration/api_public_only_test.go | 83 +- .../integration/api_pull_commits_test.go | 13 +- .../tests/integration/api_pull_review_test.go | 110 +- .../source/tests/integration/api_pull_test.go | 51 +- .../api_releases_attachment_test.go | 17 +- .../tests/integration/api_releases_test.go | 69 +- .../integration/api_repo_archive_test.go | 14 +- .../tests/integration/api_repo_avatar_test.go | 24 +- .../tests/integration/api_repo_branch_test.go | 33 +- .../integration/api_repo_collaborator_test.go | 54 +- .../integration/api_repo_compare_test.go | 177 +- .../tests/integration/api_repo_edit_test.go | 123 +- .../integration/api_repo_file_create_test.go | 60 +- .../integration/api_repo_file_delete_test.go | 18 +- .../api_repo_file_diffpatch_test.go | 13 +- .../integration/api_repo_file_get_test.go | 8 +- .../integration/api_repo_file_helpers.go | 10 +- .../integration/api_repo_file_update_test.go | 33 +- .../integration/api_repo_files_change_test.go | 33 +- .../integration/api_repo_files_get_test.go | 27 +- .../api_repo_get_contents_list_test.go | 27 +- .../integration/api_repo_get_contents_test.go | 61 +- .../integration/api_repo_git_blobs_test.go | 15 +- .../integration/api_repo_git_commits_test.go | 72 +- .../integration/api_repo_git_hook_test.go | 34 +- .../integration/api_repo_git_notes_test.go | 11 +- .../integration/api_repo_git_ref_test.go | 8 +- .../integration/api_repo_git_tags_test.go | 17 +- .../integration/api_repo_git_trees_test.go | 18 +- .../tests/integration/api_repo_hook_test.go | 37 +- .../integration/api_repo_languages_test.go | 5 +- .../integration/api_repo_lfs_locks_test.go | 39 +- .../integration/api_repo_lfs_migrate_test.go | 28 +- .../tests/integration/api_repo_lfs_test.go | 65 +- .../integration/api_repo_license_test.go | 9 +- .../tests/integration/api_repo_raw_test.go | 8 +- .../integration/api_repo_secrets_test.go | 12 +- .../tests/integration/api_repo_tags_test.go | 44 +- .../tests/integration/api_repo_teams_test.go | 41 +- .../source/tests/integration/api_repo_test.go | 195 +- .../tests/integration/api_repo_topic_test.go | 50 +- .../integration/api_repo_variables_test.go | 12 +- ...pi_repository_creation_token_scope_test.go | 55 + .../tests/integration/api_settings_test.go | 18 +- .../source/tests/integration/api_team_test.go | 200 +- .../tests/integration/api_team_user_test.go | 15 +- .../tests/integration/api_token_self_test.go | 98 + .../tests/integration/api_token_test.go | 73 +- .../tests/integration/api_twofa_test.go | 20 +- .../tests/integration/api_user_avatar_test.go | 18 +- .../tests/integration/api_user_block_test.go | 24 +- .../tests/integration/api_user_email_test.go | 37 +- .../tests/integration/api_user_follow_test.go | 22 +- .../integration/api_user_heatmap_test.go | 15 +- .../tests/integration/api_user_info_test.go | 20 +- .../integration/api_user_org_perm_test.go | 22 +- .../tests/integration/api_user_orgs_test.go | 18 +- .../integration/api_user_public_only_test.go | 10 +- .../tests/integration/api_user_search_test.go | 39 +- .../integration/api_user_secrets_test.go | 6 +- .../tests/integration/api_user_star_test.go | 89 +- .../tests/integration/api_user_update_test.go | 4 +- .../integration/api_user_variables_test.go | 6 +- .../integration/api_user_visibility_test.go | 76 + .../tests/integration/api_user_watch_test.go | 16 +- .../source/tests/integration/api_wiki_test.go | 15 +- .../tests/integration/attachment_test.go | 56 +- .../tests/integration/auth_ldap_test.go | 323 +- .../tests/integration/auth_oauth2_test.go | 635 + .../source/tests/integration/branches_test.go | 83 +- .../integration/change_default_branch_test.go | 10 +- .../source/tests/integration/cmd_keys_test.go | 9 +- .../source/tests/integration/compare_test.go | 194 +- .../tests/integration/config_instance_test.go | 10 +- .../source/tests/integration/cors_test.go | 8 +- .../integration/create_no_session_test.go | 20 +- .../tests/integration/db_collation_test.go | 8 +- .../tests/integration/delete_user_test.go | 24 +- .../source/tests/integration/download_test.go | 8 +- .../tests/integration/dump_restore_test.go | 30 +- .../source/tests/integration/editor_test.go | 48 +- .../tests/integration/empty_repo_test.go | 28 +- .../ephemeral_actions_runner_deletion_test.go | 14 +- .../tests/integration/eventsource_test.go | 22 +- .../tests/integration/explore_repos_test.go | 2 +- .../tests/integration/explore_user_test.go | 2 +- .../tests/integration/feed_repo_test.go | 41 +- .../tests/integration/feed_user_test.go | 51 +- .../tests/integration/git_general_test.go | 76 +- .../git_helper_for_declarative_test.go | 15 +- .../tests/integration/git_lfs_ssh_test.go | 15 +- .../source/tests/integration/git_misc_test.go | 29 +- .../source/tests/integration/git_push_test.go | 54 +- .../tests/integration/git_smart_http_test.go | 46 +- .../integration/git_ssh_redirect_test.go | 4 +- .../source/tests/integration/goget_test.go | 96 +- .../tests/integration/gpg_ssh_git_test.go | 100 +- .../source/tests/integration/heatmap_test.go | 21 +- .../source/tests/integration/html_helper.go | 17 +- .../tests/integration/incoming_email_test.go | 18 +- .../tests/integration/integration_test.go | 195 +- .../integration/issue_label_scope_test.go | 34 + .../source/tests/integration/issue_test.go | 134 +- .../tests/integration/issue_timetrack_test.go | 6 +- .../tests/integration/lfs_getobject_test.go | 157 +- .../integration/lfs_local_endpoint_test.go | 4 +- .../source/tests/integration/lfs_view_test.go | 19 +- .../source/tests/integration/linguist_test.go | 16 +- .../source/tests/integration/links_test.go | 11 +- .../tests/integration/manual_merge_test.go | 16 +- .../tests/integration/markup_external_test.go | 47 +- .../source/tests/integration/migrate_test.go | 173 +- .../migration-test/gitea-v1.6.4.mssql.sql.gz | Bin 12969 -> 13260 bytes .../migration-test/gitea-v1.7.0.mssql.sql.gz | Bin 13068 -> 13369 bytes .../migration-test/migration_test.go | 205 +- .../tests/integration/mirror_pull_test.go | 86 +- .../tests/integration/mirror_push_test.go | 29 +- .../integration/nonascii_branches_test.go | 2 +- .../tests/integration/oauth_avatar_test.go | 22 +- .../source/tests/integration/oauth_test.go | 468 +- .../tests/integration/org_count_test.go | 16 +- .../tests/integration/org_profile_test.go | 12 +- .../tests/integration/org_project_test.go | 4 +- .../tests/integration/org_team_invite_test.go | 37 +- .../source/tests/integration/org_test.go | 93 +- .../tests/integration/org_worktime_test.go | 4 +- .../integration/packages_service_test.go | 12 +- .../tests/integration/privateactivity_test.go | 26 +- .../source/tests/integration/project_test.go | 174 +- .../tests/integration/pull_comment_test.go | 6 +- .../tests/integration/pull_commit_test.go | 9 +- .../tests/integration/pull_compare_test.go | 12 +- .../tests/integration/pull_create_test.go | 30 +- .../tests/integration/pull_diff_test.go | 2 +- .../tests/integration/pull_merge_test.go | 314 +- .../tests/integration/pull_review_test.go | 49 +- .../tests/integration/pull_status_test.go | 29 +- .../tests/integration/pull_update_test.go | 121 +- .../source/tests/integration/release_test.go | 52 +- .../tests/integration/rename_branch_test.go | 8 +- .../tests/integration/repo_activity_test.go | 8 +- .../tests/integration/repo_archive_test.go | 10 +- .../tests/integration/repo_branch_test.go | 12 +- .../integration/repo_commits_search_test.go | 2 +- .../tests/integration/repo_commits_test.go | 62 +- .../tests/integration/repo_fork_test.go | 16 +- .../tests/integration/repo_generate_test.go | 8 +- .../integration/repo_home_token_scope_test.go | 43 + .../integration/repo_merge_upstream_test.go | 33 +- .../tests/integration/repo_migrate_test.go | 4 +- .../tests/integration/repo_search_test.go | 17 +- .../source/tests/integration/repo_tag_test.go | 25 +- .../source/tests/integration/repo_test.go | 30 +- .../tests/integration/repo_topic_test.go | 27 +- .../tests/integration/repo_visibility_test.go | 12 +- .../tests/integration/repo_watch_test.go | 9 +- .../tests/integration/repo_webhook_test.go | 70 +- .../integration/repofiles_change_test.go | 14 +- .../source/tests/integration/session_test.go | 6 +- .../source/tests/integration/setting_test.go | 12 +- .../source/tests/integration/signin_test.go | 46 +- .../source/tests/integration/signout_test.go | 6 +- .../source/tests/integration/signup_test.go | 14 +- .../source/tests/integration/ssh_key_test.go | 6 +- .../tests/integration/timetracking_test.go | 6 +- .../tests/integration/user_avatar_test.go | 8 +- .../tests/integration/user_settings_test.go | 26 +- .../source/tests/integration/user_test.go | 53 +- .../source/tests/integration/version_test.go | 13 +- .../source/tests/integration/view_test.go | 66 +- .../source/tests/integration/webauthn_test.go | 38 + .../source/tests/integration/wiki_test.go | 10 +- .../workflow_run_api_check_test.go | 125 +- package/gitea/source/tests/mssql.ini.tmpl | 2 +- package/gitea/source/tests/mysql.ini.tmpl | 2 +- package/gitea/source/tests/pgsql.ini.tmpl | 2 +- package/gitea/source/tests/sqlite.ini.tmpl | 8 +- package/gitea/source/tests/test_utils.go | 131 +- package/gitea/source/tools/ci-tools.ts | 133 + .../gitea/source/tools/code-batch-process.go | 273 - .../source/tools/codeformat/formatimports.go | 195 - .../tools/codeformat/formatimports_test.go | 124 - .../unescaped-html-literal.test.ts | 85 + .../eslint-rules/unescaped-html-literal.ts | 39 + .../tools/generate-codemirror-languages.ts | 95 + package/gitea/source/tools/generate-images.ts | 2 +- package/gitea/source/tools/generate-svg.ts | 2 +- package/gitea/source/tools/lint-go-all.go | 104 + package/gitea/source/tools/lint-shell.sh | 11 + package/gitea/source/tools/test-e2e.sh | 108 +- .../gitea/source/tools/test-integration.sh | 31 + package/gitea/source/tsconfig.json | 2 - package/gitea/source/types.d.ts | 44 +- package/gitea/source/updates.config.ts | 9 - package/gitea/source/uv.lock | 456 +- package/gitea/source/vite.config.ts | 17 +- package/gitea/source/vitest.config.ts | 5 +- package/gitea/source/web_src/css/actions.css | 46 +- package/gitea/source/web_src/css/admin.css | 6 - package/gitea/source/web_src/css/avatar.css | 126 + package/gitea/source/web_src/css/base.css | 69 +- package/gitea/source/web_src/css/devtest.css | 10 +- package/gitea/source/web_src/css/easymde.css | 27 +- .../source/web_src/css/features/console.css | 1 + .../source/web_src/css/features/gitgraph.css | 150 +- .../source/web_src/css/features/heatmap.css | 17 +- .../gitea/source/web_src/css/font_i18n.css | 40 +- package/gitea/source/web_src/css/index.css | 9 +- .../source/web_src/css/markup/asciicast.css | 10 - .../source/web_src/css/markup/content.css | 4 - .../source/web_src/css/markup/jupyter.css | 93 + .../source/web_src/css/modules/animations.css | 10 +- .../source/web_src/css/modules/button.css | 9 - .../gitea/source/web_src/css/modules/card.css | 11 - .../source/web_src/css/modules/checkbox.css | 7 +- .../source/web_src/css/modules/codeeditor.css | 47 +- .../source/web_src/css/modules/comment.css | 32 - .../source/web_src/css/modules/divider.css | 8 + .../source/web_src/css/modules/dropdown.css | 13 +- .../gitea/source/web_src/css/modules/form.css | 12 +- .../gitea/source/web_src/css/modules/grid.css | 166 +- .../source/web_src/css/modules/header.css | 6 +- .../source/web_src/css/modules/input.css | 18 - .../source/web_src/css/modules/label.css | 70 +- .../gitea/source/web_src/css/modules/menu.css | 68 +- .../source/web_src/css/modules/message.css | 29 +- .../source/web_src/css/modules/segment.css | 9 +- .../gitea/source/web_src/css/modules/svg.css | 12 +- .../source/web_src/css/modules/table.css | 33 - .../source/web_src/css/modules/toast.css | 4 + .../source/web_src/css/modules/transition.css | 24 + package/gitea/source/web_src/css/org.css | 77 +- package/gitea/source/web_src/css/repo.css | 236 +- .../source/web_src/css/repo/file-view.css | 4 + .../gitea/source/web_src/css/repo/header.css | 29 - .../web_src/css/repo/home-file-list.css | 5 + .../gitea/source/web_src/css/repo/home.css | 9 +- .../source/web_src/css/repo/issue-list.css | 56 +- .../source/web_src/css/repo/reactions.css | 4 +- package/gitea/source/web_src/css/review.css | 2 - .../source/web_src/css/shared/flex-list.css | 109 +- .../source/web_src/css/shared/milestone.css | 62 - .../source/web_src/css/shared/repoorg.css | 18 - .../source/web_src/css/shared/settings.css | 48 +- .../source/web_src/css/swagger-render.css | 2 +- .../web_src/css/themes/theme-gitea-dark.css | 23 +- ...me-gitea-light-protanopia-deuteranopia.css | 4 +- .../themes/theme-gitea-light-tritanopia.css | 2 +- .../web_src/css/themes/theme-gitea-light.css | 21 +- .../fomantic/build/components/dropdown.js | 28 +- .../fomantic/build/components/search.js | 1565 - .../source/web_src/fomantic/build/fomantic.js | 1 - .../source/web_src/fomantic/theme.config.less | 1 - .../js/components/ActionRunArtifacts.test.ts | 36 + .../js/components/ActionRunArtifacts.ts | 24 + .../js/components/ActionRunJobView.vue | 213 +- .../web_src/js/components/ActionRunStatus.vue | 30 - .../js/components/ActionRunSummaryView.vue | 217 +- .../js/components/ActionRunView.test.ts | 8 + .../web_src/js/components/ActionRunView.ts | 68 +- .../js/components/ActionStatusIcon.vue | 32 + .../web_src/js/components/ActivityHeatmap.vue | 198 +- .../web_src/js/components/ContextPopup.vue | 47 +- .../js/components/PullRequestMergeForm.vue | 46 +- .../web_src/js/components/RepoActionView.vue | 469 +- .../js/components/RepoCodeFrequency.vue | 5 +- .../js/components/RepoContributors.vue | 7 +- .../js/components/RepoRecentCommits.vue | 5 +- .../js/components/ViewFileTreeItem.vue | 2 + .../js/components/ViewFileTreeStore.ts | 4 +- .../js/components/WorkflowGraph.utils.test.ts | 210 + .../js/components/WorkflowGraph.utils.ts | 538 + .../web_src/js/components/WorkflowGraph.vue | 917 +- .../web_src/js/external-render-frontend.ts | 16 +- .../web_src/js/external-render-helper.test.ts | 2 +- .../web_src/js/external-render-helper.ts | 14 +- .../web_src/js/features/admin/common.ts | 38 +- .../web_src/js/features/admin/config.test.ts | 6 +- .../web_src/js/features/admin/config.ts | 16 +- .../source/web_src/js/features/admin/users.ts | 4 +- .../source/web_src/js/features/citation.ts | 7 +- .../source/web_src/js/features/clipboard.ts | 40 - .../web_src/js/features/common-button.test.ts | 10 +- .../web_src/js/features/common-button.ts | 96 +- .../js/features/common-fetch-action.test.ts | 59 + .../js/features/common-fetch-action.ts | 428 +- .../source/web_src/js/features/common-form.ts | 16 +- .../web_src/js/features/common-issue-list.ts | 2 +- .../source/web_src/js/features/common-page.ts | 5 +- .../js/features/comp/ComboMarkdownEditor.ts | 41 +- .../web_src/js/features/comp/ConfirmModal.ts | 9 +- .../web_src/js/features/comp/EditorUpload.ts | 4 +- .../web_src/js/features/comp/LabelEdit.ts | 6 +- .../js/features/comp/ScopedWorkflows.test.ts | 104 + .../js/features/comp/ScopedWorkflows.ts | 38 + .../web_src/js/features/comp/SearchRepoBox.ts | 33 +- .../web_src/js/features/comp/SearchUserBox.ts | 61 +- .../web_src/js/features/comp/WebHookEditor.ts | 7 +- .../web_src/js/features/contributors.ts | 1 + .../source/web_src/js/features/copycontent.ts | 57 +- .../source/web_src/js/features/dropzone.ts | 36 +- .../source/web_src/js/features/file-view.ts | 3 +- .../source/web_src/js/features/heatmap.ts | 4 +- .../source/web_src/js/features/imagediff.ts | 9 +- .../source/web_src/js/features/install.ts | 2 +- .../web_src/js/features/notification.ts | 40 +- .../source/web_src/js/features/ref-issue.ts | 75 + .../web_src/js/features/repo-actions.test.ts | 30 + .../web_src/js/features/repo-actions.ts | 64 +- .../source/web_src/js/features/repo-branch.ts | 4 +- .../source/web_src/js/features/repo-code.ts | 10 +- .../source/web_src/js/features/repo-commit.ts | 26 + .../source/web_src/js/features/repo-common.ts | 5 +- .../web_src/js/features/repo-diff-commit.ts | 2 +- .../source/web_src/js/features/repo-diff.ts | 22 +- .../source/web_src/js/features/repo-editor.ts | 56 +- .../source/web_src/js/features/repo-graph.ts | 4 +- .../source/web_src/js/features/repo-home.ts | 5 +- .../web_src/js/features/repo-issue-content.ts | 55 +- .../web_src/js/features/repo-issue-edit.ts | 3 +- .../web_src/js/features/repo-issue-list.ts | 26 +- .../web_src/js/features/repo-issue-pull.ts | 108 +- .../features/repo-issue-sidebar-combolist.ts | 16 +- .../source/web_src/js/features/repo-issue.ts | 38 +- .../source/web_src/js/features/repo-legacy.ts | 7 +- .../source/web_src/js/features/repo-new.ts | 1 - .../web_src/js/features/repo-projects.ts | 8 +- .../web_src/js/features/repo-release.ts | 9 +- .../source/web_src/js/features/repo-search.ts | 29 +- .../features/repo-settings-branches.test.ts | 6 +- .../js/features/repo-settings-branches.ts | 4 +- .../web_src/js/features/repo-settings.ts | 50 +- .../source/web_src/js/features/tribute.ts | 6 +- .../web_src/js/features/user-auth-webauthn.ts | 20 +- package/gitea/source/web_src/js/globals.d.ts | 21 +- package/gitea/source/web_src/js/globals.ts | 11 - package/gitea/source/web_src/js/index.ts | 35 +- .../source/web_src/js/markup/asciicast.ts | 16 - .../gitea/source/web_src/js/markup/common.ts | 6 +- .../gitea/source/web_src/js/markup/content.ts | 4 - .../source/web_src/js/markup/html2markdown.ts | 20 +- .../source/web_src/js/markup/refissue.ts | 42 - .../web_src/js/markup/render-iframe.test.ts | 1 - .../source/web_src/js/markup/render-iframe.ts | 38 +- .../js/modules/action-status-icon.test.ts | 9 + .../web_src/js/modules/action-status-icon.ts | 37 + .../source/web_src/js/modules/clipboard.ts | 90 + .../js/modules/codeeditor/context-menu.ts | 6 +- .../js/modules/codeeditor/main.test.ts | 54 + .../web_src/js/modules/codeeditor/main.ts | 133 +- .../js/modules/codeeditor/utils.test.ts | 39 +- .../web_src/js/modules/codeeditor/utils.ts | 18 +- .../source/web_src/js/modules/devtest.ts | 57 +- .../source/web_src/js/modules/errors.test.ts | 25 +- .../gitea/source/web_src/js/modules/errors.ts | 58 +- .../web_src/js/modules/favicon-status.test.ts | 29 + .../web_src/js/modules/favicon-status.ts | 90 + .../gitea/source/web_src/js/modules/fetch.ts | 14 +- .../source/web_src/js/modules/fomantic.ts | 6 - .../web_src/js/modules/fomantic/aria.md | 2 +- .../web_src/js/modules/fomantic/base.ts | 32 +- .../web_src/js/modules/fomantic/checkbox.ts | 13 - .../js/modules/fomantic/dropdown.test.ts | 33 +- .../web_src/js/modules/fomantic/dropdown.ts | 33 +- .../web_src/js/modules/fomantic/form.ts | 13 - .../web_src/js/modules/fomantic/modal.ts | 21 + .../source/web_src/js/modules/fomantic/tab.ts | 30 +- .../web_src/js/modules/gitea-actions.ts | 46 +- .../source/web_src/js/modules/i18n.test.ts | 10 + .../gitea/source/web_src/js/modules/i18n.ts | 7 + .../source/web_src/js/modules/observer.ts | 30 +- .../gitea/source/web_src/js/modules/search.ts | 116 + .../gitea/source/web_src/js/modules/tippy.ts | 10 +- .../gitea/source/web_src/js/modules/toast.ts | 16 +- .../gitea/source/web_src/js/modules/worker.ts | 2 +- .../source/web_src/js/render/ansi.test.ts | 15 +- .../gitea/source/web_src/js/render/ansi.ts | 43 +- .../js/render/plugins/frontend-asciicast.ts | 23 + .../plugins/frontend-openapi-swagger.ts | 6 +- .../js/render/plugins/inplace-pdf-viewer.ts | 4 +- package/gitea/source/web_src/js/svg.ts | 14 + package/gitea/source/web_src/js/swagger.ts | 2 - package/gitea/source/web_src/js/types.ts | 2 + package/gitea/source/web_src/js/utils.test.ts | 39 +- package/gitea/source/web_src/js/utils.ts | 29 +- .../gitea/source/web_src/js/utils/dom.test.ts | 2 + package/gitea/source/web_src/js/utils/dom.ts | 35 +- .../gitea/source/web_src/js/utils/match.ts | 5 +- .../source/web_src/js/utils/string.test.ts | 13 + .../gitea/source/web_src/js/utils/string.ts | 5 + .../source/web_src/js/utils/testhelper.ts | 12 +- package/gitea/source/web_src/js/utils/time.ts | 21 +- .../gitea/source/web_src/js/utils/url.test.ts | 59 +- package/gitea/source/web_src/js/utils/url.ts | 41 +- .../gitea/source/web_src/js/vitest.setup.ts | 17 +- .../web_src/js/webcomponents/overflow-menu.ts | 20 +- .../js/webcomponents/relative-time.test.ts | 39 + .../web_src/js/webcomponents/relative-time.ts | 16 +- 3538 files changed, 116131 insertions(+), 44340 deletions(-) delete mode 100644 package/gitea/source/.gitea/issue_template.md delete mode 100644 package/gitea/source/.github/ISSUE_TEMPLATE/ui.bug-report.yaml create mode 100644 package/gitea/source/.github/actions/docker-dryrun/action.yml create mode 100644 package/gitea/source/.github/actions/free-disk-space/action.yml create mode 100644 package/gitea/source/.github/actions/go-cache/action.yml create mode 100644 package/gitea/source/.github/actions/go-setup/action.yml create mode 100644 package/gitea/source/.github/actions/node-setup/action.yml create mode 100644 package/gitea/source/.github/actions/pgsql-shard/action.yml delete mode 100644 package/gitea/source/.github/dependabot.yml create mode 100644 package/gitea/source/.github/workflows/cache-seeder.yml delete mode 100644 package/gitea/source/.github/workflows/cron-flake-updater.yml create mode 100644 package/gitea/source/.github/workflows/cron-renovate.yml create mode 100644 package/gitea/source/.github/workflows/giteabot-backport.yml create mode 100644 package/gitea/source/.github/workflows/giteabot.yml create mode 100644 package/gitea/source/.github/workflows/release-nightly-snapcraft.yml delete mode 100644 package/gitea/source/.npmrc create mode 100644 package/gitea/source/.shellcheckrc create mode 100644 package/gitea/source/assets/codemirror-languages.json create mode 100644 package/gitea/source/build/generate-openapi.go create mode 100644 package/gitea/source/build/openapi3gen/convert.go create mode 100644 package/gitea/source/build/openapi3gen/convert_test.go create mode 100644 package/gitea/source/build/openapi3gen/enumscan.go create mode 100644 package/gitea/source/build/openapi3gen/enumscan_test.go delete mode 100755 package/gitea/source/build/test-env-check.sh delete mode 100755 package/gitea/source/build/test-env-prepare.sh delete mode 100644 package/gitea/source/cmd/cmd_test.go create mode 100644 package/gitea/source/cmd/cmdtest/cmd_test.go rename package/gitea/source/cmd/{cmd.go => helper.go} (86%) create mode 100644 package/gitea/source/cmd/serv_test.go delete mode 100644 package/gitea/source/contrib/backport/README delete mode 100644 package/gitea/source/contrib/backport/backport.go rename package/gitea/source/contrib/{ide => development}/README.md (78%) rename package/gitea/source/contrib/{ide => development}/vscode/launch.json (50%) create mode 100644 package/gitea/source/contrib/development/vscode/settings.json create mode 100644 package/gitea/source/contrib/development/vscode/tasks.json rename package/gitea/source/contrib/{gitea-monitoring-mixin => grafana-monitoring-mixin}/.gitignore (100%) rename package/gitea/source/contrib/{gitea-monitoring-mixin => grafana-monitoring-mixin}/Makefile (100%) rename package/gitea/source/contrib/{gitea-monitoring-mixin => grafana-monitoring-mixin}/README.md (100%) rename package/gitea/source/contrib/{gitea-monitoring-mixin => grafana-monitoring-mixin}/config.libsonnet (100%) rename package/gitea/source/contrib/{gitea-monitoring-mixin => grafana-monitoring-mixin}/dashboards/dashboards.libsonnet (100%) rename package/gitea/source/contrib/{gitea-monitoring-mixin => grafana-monitoring-mixin}/dashboards/overview.libsonnet (100%) rename package/gitea/source/contrib/{gitea-monitoring-mixin => grafana-monitoring-mixin}/jsonnetfile.json (100%) rename package/gitea/source/contrib/{gitea-monitoring-mixin => grafana-monitoring-mixin}/jsonnetfile.lock.json (100%) rename package/gitea/source/contrib/{gitea-monitoring-mixin => grafana-monitoring-mixin}/lib/alerts.jsonnet (100%) rename package/gitea/source/contrib/{gitea-monitoring-mixin => grafana-monitoring-mixin}/lib/dashboards.jsonnet (100%) rename package/gitea/source/contrib/{gitea-monitoring-mixin => grafana-monitoring-mixin}/lib/rules.jsonnet (100%) rename package/gitea/source/contrib/{gitea-monitoring-mixin => grafana-monitoring-mixin}/mixin.libsonnet (100%) delete mode 100644 package/gitea/source/contrib/ide/vscode/settings.json delete mode 100644 package/gitea/source/contrib/ide/vscode/tasks.json delete mode 100644 package/gitea/source/contrib/init/centos/gitea delete mode 100644 package/gitea/source/contrib/init/debian/gitea delete mode 100644 package/gitea/source/contrib/init/suse/gitea rename package/gitea/source/contrib/{legal => sample-page}/privacy.html.sample (100%) rename package/gitea/source/contrib/{legal => sample-page}/tos.html.sample (100%) rename package/gitea/source/contrib/{init => service}/freebsd/gitea (100%) rename package/gitea/source/contrib/{init => service}/gentoo/gitea (100%) rename package/gitea/source/contrib/{ => service}/launchd/io.gitea.web.plist (100%) rename package/gitea/source/contrib/{init => service}/openbsd/gitea (100%) rename package/gitea/source/contrib/{init => service}/openwrt/gitea (100%) rename package/gitea/source/contrib/{init => service}/sunos/gitea.xml (100%) rename package/gitea/source/contrib/{ => service}/supervisor/gitea (100%) rename package/gitea/source/contrib/{ => service}/systemd/gitea.service (100%) rename package/gitea/source/contrib/{init/ubuntu => service/sysvinit}/gitea (90%) delete mode 100755 package/gitea/source/contrib/update_dependencies.sh create mode 100644 package/gitea/source/docs/build-setup.md create mode 100644 package/gitea/source/docs/build-source.md create mode 100644 package/gitea/source/docs/community-governance.md create mode 100644 package/gitea/source/docs/development.md create mode 100644 package/gitea/source/docs/guidelines-backend.md create mode 100644 package/gitea/source/docs/guidelines-frontend.md create mode 100644 package/gitea/source/docs/guidelines-refactoring.md create mode 100644 package/gitea/source/docs/release-management.md create mode 100644 package/gitea/source/docs/testing.md create mode 100644 package/gitea/source/models/actions/artifact_test.go create mode 100644 package/gitea/source/models/actions/run_attempt.go create mode 100644 package/gitea/source/models/actions/run_attempt_list.go create mode 100644 package/gitea/source/models/actions/run_job_list_test.go create mode 100644 package/gitea/source/models/actions/run_job_summary.go create mode 100644 package/gitea/source/models/actions/run_job_test.go create mode 100644 package/gitea/source/models/actions/run_list_test.go create mode 100644 package/gitea/source/models/actions/runner_test.go create mode 100644 package/gitea/source/models/actions/scoped_workflow.go create mode 100644 package/gitea/source/models/actions/scoped_workflow_test.go create mode 100644 package/gitea/source/models/actions/status_test.go create mode 100644 package/gitea/source/models/auth/twofactor_test.go create mode 100644 package/gitea/source/models/db/conn.go rename package/gitea/source/{modules/setting/database_test.go => models/db/conn_test.go} (88%) create mode 100644 package/gitea/source/models/db/driver_postgresschema.go create mode 100644 package/gitea/source/models/db/driver_sqlite_mattn.go create mode 100644 package/gitea/source/models/db/driver_sqlite_modernc.go delete mode 100644 package/gitea/source/models/db/sql_postgres_with_schema.go create mode 100644 package/gitea/source/models/gituser/avatar_stack.go create mode 100644 package/gitea/source/models/gituser/gituser.go create mode 100644 package/gitea/source/models/issues/issue_project_multi_test.go create mode 100644 package/gitea/source/models/issues/issue_update_test.go delete mode 100644 package/gitea/source/models/migrations/base/tests.go create mode 100644 package/gitea/source/models/migrations/migrationtest/tests.go delete mode 100644 package/gitea/source/models/migrations/v1_26/v331.go create mode 100644 package/gitea/source/models/migrations/v1_27/main_test.go create mode 100644 package/gitea/source/models/migrations/v1_27/v331.go create mode 100644 package/gitea/source/models/migrations/v1_27/v331_test.go create mode 100644 package/gitea/source/models/migrations/v1_27/v332.go create mode 100644 package/gitea/source/models/migrations/v1_27/v332_test.go create mode 100644 package/gitea/source/models/migrations/v1_27/v333.go create mode 100644 package/gitea/source/models/migrations/v1_27/v333_test.go create mode 100644 package/gitea/source/models/migrations/v1_27/v334.go create mode 100644 package/gitea/source/models/migrations/v1_27/v334_test.go create mode 100644 package/gitea/source/models/migrations/v1_27/v335.go create mode 100644 package/gitea/source/models/migrations/v1_27/v336.go create mode 100644 package/gitea/source/models/migrations/v1_27/v337.go create mode 100644 package/gitea/source/models/migrations/v1_27/v338.go create mode 100644 package/gitea/source/models/migrations/v1_27/v338_test.go create mode 100644 package/gitea/source/models/migrations/v1_27/v339.go create mode 100644 package/gitea/source/models/migrations/v1_27/v339_test.go create mode 100644 package/gitea/source/models/migrations/v1_27/v340.go create mode 100644 package/gitea/source/models/migrations/v1_27/v341.go create mode 100644 package/gitea/source/models/migrations/v1_27/v341_test.go create mode 100644 package/gitea/source/models/migrations/v1_27/v342.go create mode 100644 package/gitea/source/models/repo/repo_unit_actions_test.go create mode 100644 package/gitea/source/models/secret/main_test.go create mode 100644 package/gitea/source/models/secret/secret_test.go create mode 100644 package/gitea/source/models/unittest/mock_http.go create mode 100644 package/gitea/source/modules/actions/commit_status_info.go create mode 100644 package/gitea/source/modules/actions/jobparser/aliases.go create mode 100644 package/gitea/source/modules/actions/jobparser/aliases_test.go create mode 100644 package/gitea/source/modules/actions/jobparser/roundtrip_test.go create mode 100644 package/gitea/source/modules/actions/jobparser/testdata/continue_on_error_expr.in.yaml create mode 100644 package/gitea/source/modules/actions/jobparser/testdata/continue_on_error_expr.out.yaml create mode 100644 package/gitea/source/modules/actions/jobparser/uses.go create mode 100644 package/gitea/source/modules/actions/jobparser/uses_test.go create mode 100644 package/gitea/source/modules/actions/jobparser/workflow_call.go create mode 100644 package/gitea/source/modules/actions/jobparser/workflow_call_test.go create mode 100644 package/gitea/source/modules/actions/scoped_workflows.go create mode 100644 package/gitea/source/modules/actions/scoped_workflows_test.go create mode 100644 package/gitea/source/modules/actions/workflowpattern/workflow_pattern.go create mode 100644 package/gitea/source/modules/actions/workflowpattern/workflow_pattern_test.go create mode 100644 package/gitea/source/modules/auth/openid/openid_test.go create mode 100644 package/gitea/source/modules/consts/asymkey.go create mode 100644 package/gitea/source/modules/git/commit_info_nogogit_test.go create mode 100644 package/gitea/source/modules/git/commit_message.go create mode 100644 package/gitea/source/modules/git/commit_message_test.go create mode 100644 package/gitea/source/modules/git/gitcmd/error_test.go rename package/gitea/source/modules/git/{log_name_status.go => log_name_status_nogogit.go} (73%) create mode 100644 package/gitea/source/modules/git/redirection.go create mode 100644 package/gitea/source/modules/gitrepo/hooks_test.go create mode 100644 package/gitea/source/modules/indexer/code/bleve/bleve_test.go create mode 100644 package/gitea/source/modules/indexer/code/bleve/code_token.go create mode 100644 package/gitea/source/modules/indexer/internal/elasticsearch/indexer_test.go create mode 100644 package/gitea/source/modules/indexer/internal/elasticsearch/query.go create mode 100644 package/gitea/source/modules/indexer/internal/elasticsearch/types.go create mode 100644 package/gitea/source/modules/indexer/issues/bleve/camelcase_keep_whole.go delete mode 100644 package/gitea/source/modules/markup/asciicast/asciicast.go create mode 100644 package/gitea/source/modules/markup/external/external_test.go create mode 100644 package/gitea/source/modules/markup/jupyter/jupyter-test.ipynb create mode 100644 package/gitea/source/modules/markup/jupyter/jupyter.go create mode 100644 package/gitea/source/modules/markup/jupyter/jupyter_test.go create mode 100644 package/gitea/source/modules/markup/markdown/transform_codeblock.go create mode 100644 package/gitea/source/modules/packages/filelist.go create mode 100644 package/gitea/source/modules/private/internal_test.go delete mode 100644 package/gitea/source/modules/setting/database_sqlite.go create mode 100644 package/gitea/source/modules/setting/repository_test.go create mode 100644 package/gitea/source/modules/setting/security_test.go delete mode 100644 package/gitea/source/modules/setting/setting_test.go create mode 100644 package/gitea/source/modules/ssh/ssh_test.go create mode 100644 package/gitea/source/modules/structs/hook_test.go create mode 100644 package/gitea/source/modules/structs/project.go create mode 100644 package/gitea/source/modules/structs/token.go create mode 100644 package/gitea/source/modules/templates/util_actions.go create mode 100644 package/gitea/source/modules/turnstile/turnstile_test.go create mode 100644 package/gitea/source/modules/util/diff_slice_test.go create mode 100644 package/gitea/source/modules/util/sync.go create mode 100644 package/gitea/source/modules/util/sync_test.go delete mode 100644 package/gitea/source/modules/validation/validurllist_test.go create mode 100644 package/gitea/source/modules/web/middleware/locale_test.go create mode 100644 package/gitea/source/modules/web/routing/requestinfo.go create mode 100644 package/gitea/source/modules/web/types/premiddleware.go create mode 100644 package/gitea/source/pnpm-workspace.yaml create mode 100644 package/gitea/source/public/assets/img/svg/octicon-flag.svg create mode 100644 package/gitea/source/public/assets/img/svg/octicon-repo-forked-locked.svg create mode 100644 package/gitea/source/public/assets/img/svg/octicon-sandbox.svg create mode 100644 package/gitea/source/public/assets/img/svg/octicon-stack-add.svg create mode 100644 package/gitea/source/public/assets/img/svg/octicon-stack-check.svg create mode 100644 package/gitea/source/public/assets/img/svg/octicon-stack-remove.svg create mode 100644 package/gitea/source/renovate.json5 create mode 100644 package/gitea/source/routers/api/actions/job_summary.go create mode 100644 package/gitea/source/routers/api/actions/runner/runner_test.go create mode 100644 package/gitea/source/routers/api/packages/maven/maven_test.go create mode 100644 package/gitea/source/routers/api/packages/npm/api_test.go create mode 100644 package/gitea/source/routers/api/v1/repo/issue_assignee.go create mode 100644 package/gitea/source/routers/api/v1/repo/mirror_test.go create mode 100644 package/gitea/source/routers/api/v1/token/token.go create mode 100644 package/gitea/source/routers/api/v1/utils/sort.go create mode 100644 package/gitea/source/routers/api/v1/utils/sort_test.go create mode 100644 package/gitea/source/routers/common/issue_filter_test.go delete mode 100644 package/gitea/source/routers/private/default_branch.go create mode 100644 package/gitea/source/routers/private/hook_pre_receive_test.go create mode 100644 package/gitea/source/routers/web/repo/pull_merge_box.go create mode 100644 package/gitea/source/routers/web/repo/pull_merge_form.go create mode 100644 package/gitea/source/routers/web/shared/actions/scoped_workflows.go create mode 100644 package/gitea/source/routers/web/shared/actions/scoped_workflows_test.go create mode 100644 package/gitea/source/routers/web/user/notification_test.go create mode 100644 package/gitea/source/services/actions/approve.go create mode 100644 package/gitea/source/services/actions/approve_test.go create mode 100644 package/gitea/source/services/actions/artifacts.go create mode 100644 package/gitea/source/services/actions/clear_tasks_test.go create mode 100644 package/gitea/source/services/actions/helper.go create mode 100644 package/gitea/source/services/actions/helper_test.go create mode 100644 package/gitea/source/services/actions/notifier_helper_test.go create mode 100644 package/gitea/source/services/actions/notify.go create mode 100644 package/gitea/source/services/actions/reusable_workflow.go create mode 100644 package/gitea/source/services/actions/reusable_workflow_test.go create mode 100644 package/gitea/source/services/actions/scoped_workflow_cache.go create mode 100644 package/gitea/source/services/actions/task_test.go create mode 100644 package/gitea/source/services/actions/workflow_test.go create mode 100644 package/gitea/source/services/context/package_test.go create mode 100644 package/gitea/source/services/context/repo_test.go create mode 100644 package/gitea/source/services/convert/project.go delete mode 100644 package/gitea/source/services/convert/secret.go delete mode 100644 package/gitea/source/services/doctor/actions.go delete mode 100644 package/gitea/source/services/doctor/actions_test.go delete mode 100644 package/gitea/source/services/doctor/authorizedkeys.go delete mode 100644 package/gitea/source/services/doctor/breaking.go delete mode 100644 package/gitea/source/services/doctor/checkOldArchives.go delete mode 100644 package/gitea/source/services/doctor/dbversion.go delete mode 100644 package/gitea/source/services/doctor/fix16961.go delete mode 100644 package/gitea/source/services/doctor/fix16961_test.go delete mode 100644 package/gitea/source/services/doctor/fix8312.go delete mode 100644 package/gitea/source/services/doctor/heads.go delete mode 100644 package/gitea/source/services/doctor/mergebase.go delete mode 100644 package/gitea/source/services/doctor/paths.go delete mode 100644 package/gitea/source/services/doctor/usertype.go create mode 100644 package/gitea/source/services/issue/review_request.go create mode 100644 package/gitea/source/services/mailer/incoming/reply.go create mode 100644 package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Fmilestones create mode 100644 package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftest create mode 100644 package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftest%2Fcommits%2Fmaster create mode 100644 package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftest%2Fcommits%2Freadme-mr create mode 100644 package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftest%2Fmerge_requests%2F100 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftest%2Fmerge_requests%3Fcount%3D1%26offset%3D0%26query%3D%2522Target%2BProject%2522%2Bis%2B%2522test%2522 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftickets create mode 100644 package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftickets%2F1%2Fnotes create mode 100644 package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftickets%2F2%2Fnotes create mode 100644 package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftickets%2Ftypes create mode 100644 package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fusers create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frate_limit create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F1%2Freactions%3Fpage%3D1%26per_page%3D2 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F1%2Freactions%3Fpage%3D2%26per_page%3D2 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F2%2Fcomments%3Fdirection%3Dasc%26per_page%3D100%26sort%3Dcreated create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F2%2Freactions%3Fpage%3D1%26per_page%3D2 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F2%2Freactions%3Fpage%3D2%26per_page%3D2 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F2%2Freactions%3Fpage%3D3%26per_page%3D2 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F2%2Freactions%3Fpage%3D4%26per_page%3D2 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F3%2Freactions%3Fpage%3D1%26per_page%3D2 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F4%2Freactions%3Fpage%3D1%26per_page%3D2 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F4%2Freactions%3Fpage%3D2%26per_page%3D2 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2Fcomments%2F553111966%2Freactions%3Fpage%3D1%26per_page%3D100 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2Fcomments%2F553111966%2Freactions%3Fpage%3D2%26per_page%3D100 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2Fcomments%2F553138856%2Freactions%3Fpage%3D1%26per_page%3D100 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%3Fdirection%3Dasc%26page%3D1%26per_page%3D2%26sort%3Dcreated%26state%3Dall create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Flabels%3Fpage%3D1%26per_page%3D100 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fmilestones%3Fpage%3D1%26per_page%3D100%26state%3Dall create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F3%2Frequested_reviewers create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F3%2Freviews%2F315859956%2Fcomments%3Fper_page%3D100 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F3%2Freviews%2F315860062%2Fcomments%3Fper_page%3D100 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F3%2Freviews%2F315861440%2Fcomments%3Fper_page%3D100 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F3%2Freviews%3Fper_page%3D100 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F4%2Frequested_reviewers create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F4%2Freviews%2F338338740%2Fcomments%3Fper_page%3D100 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F4%2Freviews%2F338339651%2Fcomments%3Fper_page%3D100 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F4%2Freviews%2F338349019%2Fcomments%3Fper_page%3D100 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F4%2Freviews%3Fper_page%3D100 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2Fcomments%2F363017488%2Freactions%3Fpage%3D1%26per_page%3D100 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2Fcomments%2F363029944%2Freactions%3Fpage%3D1%26per_page%3D100 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%3Fdirection%3Dasc%26page%3D1%26per_page%3D2%26sort%3Dcreated%26state%3Dall create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Freleases%3Fpage%3D1%26per_page%3D100 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F1%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F10%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F11%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F12%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F13%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F2%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F3%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F4%2Fcomments%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F4%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F5%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F6%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F7%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F8%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F9%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2Fcomments%2F116550%2Freactions create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2Fcomments%2F116552%2Freactions create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%3Flimit%3D2%26page%3D3%26state%3Dall%26type%3Dissues create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%3Flimit%3D50%26page%3D1%26state%3Dall%26type%3Dissues create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Flabels%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fmilestones%3Flimit%3D50%26page%3D1%26state%3Dall create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%2F7%2Freviews%2F1770%2Fcomments create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%2F7%2Freviews%2F1771%2Fcomments create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%2F7%2Freviews%2F1772%2Fcomments create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%2F7%2Freviews%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%3Flimit%3D3%26page%3D1%26state%3Dall create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%3Flimit%3D50%26page%3D1%26state%3Dall create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Freleases%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Ftopics%3Flimit%3D0%26page%3D1 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Fsettings%2Fapi create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Fversion create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F1%2Faward_emoji%3Fpage%3D1%26per_page%3D2 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F1%2Faward_emoji%3Fpage%3D2%26per_page%3D2 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Faward_emoji%3Fpage%3D1%26per_page%3D2 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Faward_emoji%3Fpage%3D2%26per_page%3D2 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Faward_emoji%3Fpage%3D3%26per_page%3D2 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Faward_emoji%3Fpage%3D4%26per_page%3D2 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Fdiscussions%3Fpage%3D1%26per_page%3D100 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Fresource_state_events%3Fpage%3D1%26per_page%3D100 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%3Fpage%3D1%26per_page%3D2%26sort%3Dasc%26state%3Dall create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Flabels%3Fpage%3D1%26per_page%3D100 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F1%2Fapprovals create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F2%2Fapprovals create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F3 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F3%2Faward_emoji%3Fpage%3D1%26per_page%3D2 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F4 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F4%2Faward_emoji%3Fpage%3D1%26per_page%3D2 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%3Fpage%3D1%26per_page%3D2%26view%3Dsimple create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmilestones%3Fpage%3D1%26per_page%3D100%26state%3Dall create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Freleases%3Fpage%3D1%26per_page%3D100 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2Fgitea%252Ftest_repo create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fversion create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGogsDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Flunnytest%2FTESTREPO create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGogsDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Flunnytest%2FTESTREPO%2Fissues%2F1%2Fcomments create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGogsDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Flunnytest%2FTESTREPO%2Fissues%3Fpage%3D1%26state%3Dopen create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGogsDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Flunnytest%2FTESTREPO%2Flabels create mode 100644 package/gitea/source/services/migrations/_mock_data/TestGogsDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Flunnytest%2FTESTREPO%2Fmilestones create mode 100644 package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fissues%2F397%2Fiterations create mode 100644 package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fissues%2F398%2Fchanges create mode 100644 package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fissues%2F398%2Fcomments create mode 100644 package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fissues%2F398%2Fiterations create mode 100644 package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fissues%3Fcount%3D2%26offset%3D0%26query%3D%2522Project%2522%2Bis%2B%2522go-gitea-test_repo%2522%26withFields%3Dtrue create mode 100644 package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fprojects%2F149%2Fiterations%3Fcount%3D100%26offset%3D0 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fprojects%2F149%2Fiterations%3Fcount%3D100%26offset%3D100 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fprojects%3Fcount%3D1%26offset%3D0%26query%3D%2522Path%2522%2Bis%2B%2522go-gitea-test_repo%2522 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fpulls%2F186%2Fmerge-preview create mode 100644 package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fpulls%2F186%2Freviews create mode 100644 package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fpulls%3Fcount%3D1%26offset%3D0%26query%3D%2522Target%2BProject%2522%2Bis%2B%2522go-gitea-test_repo%2522 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fusers%2F317 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fusers%2F317%2Femail-addresses create mode 100644 package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fusers%2F336 create mode 100644 package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fusers%2F336%2Femail-addresses create mode 100644 package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fversion%2Fserver create mode 100644 package/gitea/source/services/migrations/restore_test.go create mode 100644 package/gitea/source/services/packages/arch/repository_test.go create mode 100644 package/gitea/source/services/repository/files/patch_test.go rename package/gitea/source/{stylelint.config.js => stylelint.config.ts} (91%) create mode 100644 package/gitea/source/templates/devtest/avatar-stack.tmpl create mode 100644 package/gitea/source/templates/devtest/toast-and-message.tmpl delete mode 100644 package/gitea/source/templates/devtest/toast.tmpl delete mode 100644 package/gitea/source/templates/repo/actions/status.tmpl create mode 100644 package/gitea/source/templates/repo/header/fork.tmpl create mode 100644 package/gitea/source/templates/repo/header/star.tmpl create mode 100644 package/gitea/source/templates/repo/header/watch.tmpl create mode 100644 package/gitea/source/templates/repo/icons/action_status.tmpl rename package/gitea/source/templates/repo/{ => icons}/commit_status.tmpl (100%) create mode 100644 package/gitea/source/templates/repo/issue/view_content/pull_merge_status_checks.tmpl delete mode 100644 package/gitea/source/templates/repo/pulls/status.tmpl create mode 100644 package/gitea/source/templates/repo/pulls/status_items.tmpl delete mode 100644 package/gitea/source/templates/repo/star_unstar.tmpl delete mode 100644 package/gitea/source/templates/repo/watch_unwatch.tmpl create mode 100644 package/gitea/source/templates/shared/actions/scoped_workflows.tmpl create mode 100644 package/gitea/source/templates/swagger/v1_openapi3_json.tmpl create mode 100644 package/gitea/source/tests/e2e/fork.test.ts create mode 100644 package/gitea/source/tests/e2e/heatmap.test.ts create mode 100644 package/gitea/source/tests/e2e/issue-comment.test.ts create mode 100644 package/gitea/source/tests/e2e/issue-project.test.ts create mode 100644 package/gitea/source/tests/e2e/pr-create.test.ts create mode 100644 package/gitea/source/tests/e2e/pr-review.test.ts create mode 100644 package/gitea/source/tests/e2e/release.test.ts create mode 100644 package/gitea/source/tests/e2e/repo-collab.test.ts create mode 100644 package/gitea/source/tests/e2e/repo-star-watch.test.ts create mode 100644 package/gitea/source/tests/e2e/webauthn.test.ts delete mode 100644 package/gitea/source/tests/integration/README.md delete mode 100644 package/gitea/source/tests/integration/README_ZH.md create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F1%2Fcomments%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F1%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F10%2Fcomments%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F10%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F11%2Fcomments%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F11%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F12%2Fcomments%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F12%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F13%2Fcomments%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F13%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F2%2Fcomments%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F2%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F3%2Fcomments%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F3%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F4%2Fcomments%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F4%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F5%2Fcomments%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F5%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F6%2Fcomments%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F6%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F7%2Fcomments%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F7%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F8%2Fcomments%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F8%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F9%2Fcomments%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F9%2Freactions%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2Fcomments%2F1553%2Freactions create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2Fcomments%2F1554%2Freactions create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%3Flimit%3D47%26page%3D1%26state%3Dall%26type%3Dissues create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Flabels%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fmilestones%3Flimit%3D50%26page%3D1%26state%3Dall create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%2F10%2Freviews%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%2F11%2Freviews%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%2F12%2Freviews%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%2F13%2Freviews%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%2F8%2Freviews%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%2F9%2Freviews%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%3Flimit%3D49%26page%3D1%26state%3Dall create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Freleases%3Flimit%3D50%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Ftopics%3Flimit%3D0%26page%3D1 create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Fsettings%2Fapi create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fapi%2Fv1%2Fversion create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fgitea%2Ftest_repo%2Fpulls%2F10.patch create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fgitea%2Ftest_repo%2Fpulls%2F11.patch create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fgitea%2Ftest_repo%2Fpulls%2F12.patch create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fgitea%2Ftest_repo%2Fpulls%2F13.patch create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fgitea%2Ftest_repo%2Fpulls%2F8.patch create mode 100644 package/gitea/source/tests/integration/_mock_data/Test_MigrateFromGiteaToGitea/GET_%2Fgitea%2Ftest_repo%2Fpulls%2F9.patch create mode 100644 package/gitea/source/tests/integration/actions_concurrent_claim_test.go create mode 100644 package/gitea/source/tests/integration/actions_list_filter_test.go create mode 100644 package/gitea/source/tests/integration/actions_reusable_workflow_test.go create mode 100644 package/gitea/source/tests/integration/actions_runner_sort_test.go create mode 100644 package/gitea/source/tests/integration/actions_scoped_workflow_test.go create mode 100644 package/gitea/source/tests/integration/api_repository_creation_token_scope_test.go create mode 100644 package/gitea/source/tests/integration/api_token_self_test.go create mode 100644 package/gitea/source/tests/integration/api_user_visibility_test.go create mode 100644 package/gitea/source/tests/integration/auth_oauth2_test.go create mode 100644 package/gitea/source/tests/integration/issue_label_scope_test.go create mode 100644 package/gitea/source/tests/integration/repo_home_token_scope_test.go create mode 100644 package/gitea/source/tests/integration/webauthn_test.go create mode 100644 package/gitea/source/tools/ci-tools.ts delete mode 100644 package/gitea/source/tools/code-batch-process.go delete mode 100644 package/gitea/source/tools/codeformat/formatimports.go delete mode 100644 package/gitea/source/tools/codeformat/formatimports_test.go create mode 100644 package/gitea/source/tools/eslint-rules/unescaped-html-literal.test.ts create mode 100644 package/gitea/source/tools/eslint-rules/unescaped-html-literal.ts create mode 100755 package/gitea/source/tools/generate-codemirror-languages.ts create mode 100644 package/gitea/source/tools/lint-go-all.go create mode 100755 package/gitea/source/tools/lint-shell.sh create mode 100755 package/gitea/source/tools/test-integration.sh delete mode 100644 package/gitea/source/updates.config.ts create mode 100644 package/gitea/source/web_src/css/avatar.css delete mode 100644 package/gitea/source/web_src/css/markup/asciicast.css create mode 100644 package/gitea/source/web_src/css/markup/jupyter.css create mode 100644 package/gitea/source/web_src/css/modules/transition.css delete mode 100644 package/gitea/source/web_src/css/repo/header.css delete mode 100644 package/gitea/source/web_src/css/shared/milestone.css delete mode 100644 package/gitea/source/web_src/css/shared/repoorg.css delete mode 100644 package/gitea/source/web_src/fomantic/build/components/search.js create mode 100644 package/gitea/source/web_src/js/components/ActionRunArtifacts.test.ts create mode 100644 package/gitea/source/web_src/js/components/ActionRunArtifacts.ts delete mode 100644 package/gitea/source/web_src/js/components/ActionRunStatus.vue create mode 100644 package/gitea/source/web_src/js/components/ActionStatusIcon.vue create mode 100644 package/gitea/source/web_src/js/components/WorkflowGraph.utils.test.ts create mode 100644 package/gitea/source/web_src/js/components/WorkflowGraph.utils.ts delete mode 100644 package/gitea/source/web_src/js/features/clipboard.ts create mode 100644 package/gitea/source/web_src/js/features/common-fetch-action.test.ts create mode 100644 package/gitea/source/web_src/js/features/comp/ScopedWorkflows.test.ts create mode 100644 package/gitea/source/web_src/js/features/comp/ScopedWorkflows.ts create mode 100644 package/gitea/source/web_src/js/features/ref-issue.ts create mode 100644 package/gitea/source/web_src/js/features/repo-actions.test.ts delete mode 100644 package/gitea/source/web_src/js/markup/asciicast.ts delete mode 100644 package/gitea/source/web_src/js/markup/refissue.ts create mode 100644 package/gitea/source/web_src/js/modules/action-status-icon.test.ts create mode 100644 package/gitea/source/web_src/js/modules/action-status-icon.ts create mode 100644 package/gitea/source/web_src/js/modules/clipboard.ts create mode 100644 package/gitea/source/web_src/js/modules/codeeditor/main.test.ts create mode 100644 package/gitea/source/web_src/js/modules/favicon-status.test.ts create mode 100644 package/gitea/source/web_src/js/modules/favicon-status.ts delete mode 100644 package/gitea/source/web_src/js/modules/fomantic/checkbox.ts delete mode 100644 package/gitea/source/web_src/js/modules/fomantic/form.ts create mode 100644 package/gitea/source/web_src/js/modules/i18n.test.ts create mode 100644 package/gitea/source/web_src/js/modules/i18n.ts create mode 100644 package/gitea/source/web_src/js/modules/search.ts create mode 100644 package/gitea/source/web_src/js/render/plugins/frontend-asciicast.ts create mode 100644 package/gitea/source/web_src/js/utils/string.test.ts create mode 100644 package/gitea/source/web_src/js/utils/string.ts diff --git a/package/gitea/default.nix b/package/gitea/default.nix index 3cb126b1..b485dec7 100644 --- a/package/gitea/default.nix +++ b/package/gitea/default.nix @@ -2,12 +2,14 @@ lib, buildGo126Module, makeWrapper, + writeShellScriptBin, git, bash, coreutils, gzip, nodejs, openssh, + fetchurl, fetchPnpmDeps, pnpmConfigHook, pnpm_10, @@ -18,9 +20,29 @@ let pname = "gitea"; - version = "1.26.2"; + version = "1.27.3"; src = ./source; - pnpm = pnpm_10; + pnpm = pnpm_10.overrideAttrs (_: { + version = "11.9.0"; + src = fetchurl { + url = "https://registry.npmjs.org/pnpm/-/pnpm-11.9.0.tgz"; + hash = "sha256-K1Z6pmAmI4B4rC4KM77D/r1g6WKYeqxpdFbzGAgZsoc="; + }; + postPatch = '' + chmod +x bin/pnpm.cjs bin/pnpx.cjs + ''; + }); + pnpmForNix = (writeShellScriptBin "pnpm" '' + if [ "''${1-}" = config ] && [ "''${2-}" = set ] && [ "''${3-}" = manage-package-manager-versions ]; then + exit 0 + fi + exec ${pnpm}/bin/pnpm "$@" + '').overrideAttrs (_: { + version = "11.9.0"; + }); + pnpmPreInstall = '' + export NODE_OPTIONS=--dns-result-order=ipv4first + ''; frontend = stdenv.mkDerivation { pname = "gitea-frontend"; @@ -29,15 +51,18 @@ let pnpmDeps = fetchPnpmDeps { pname = "gitea-frontend"; inherit version src; - inherit pnpm; + pnpm = pnpmForNix; fetcherVersion = 3; - hash = "sha256-Qo0DLuZv+2GVLsBfCv/6CC9E/qhSE4HwV4StQL4HX4Y="; + prePnpmInstall = pnpmPreInstall; + hash = "sha256-rXJmmnaA61YoN7xrmA18MBLFpRRMhWd4gwXGVd5eKpU="; }; + prePnpmInstall = pnpmPreInstall; + nativeBuildInputs = [ nodejs pnpmConfigHook - pnpm + pnpmForNix ]; buildPhase = '' @@ -54,7 +79,7 @@ buildGo126Module rec { inherit pname version src; proxyVendor = true; - vendorHash = "sha256-7+M1n8RSgB3gZ/2na4RF9kYOf90H0bnsJZMDKpgAy64="; + vendorHash = "sha256-YRBMGWKIZgMxOXaXG2bIBj1XzkhSwiMyfRy+yQGw+Bo="; outputs = [ "out" @@ -66,14 +91,14 @@ buildGo126Module rec { overrideModAttrs = _: { postPatch = '' substituteInPlace go.mod \ - --replace-fail "go 1.26.3" "go 1.26" + --replace-fail "go 1.26.4" "go 1.26" ''; }; postPatch = '' substituteInPlace modules/setting/server.go --subst-var data substituteInPlace go.mod \ - --replace-fail "go 1.26.3" "go 1.26" + --replace-fail "go 1.26.4" "go 1.26" ''; subPackages = [ "." ]; diff --git a/package/gitea/source/.changelog.yml b/package/gitea/source/.changelog.yml index a7df8779..74867656 100644 --- a/package/gitea/source/.changelog.yml +++ b/package/gitea/source/.changelog.yml @@ -37,10 +37,7 @@ groups: name: BUGFIXES labels: - type/bug - - - name: API - labels: - - modifies/api + - name: TESTING labels: diff --git a/package/gitea/source/.devcontainer/devcontainer.json b/package/gitea/source/.devcontainer/devcontainer.json index f8e5972a..4863391f 100644 --- a/package/gitea/source/.devcontainer/devcontainer.json +++ b/package/gitea/source/.devcontainer/devcontainer.json @@ -1,6 +1,6 @@ { "name": "Gitea DevContainer", - "image": "mcr.microsoft.com/devcontainers/go:1.25-trixie", + "image": "mcr.microsoft.com/devcontainers/go:1.26-trixie", "containerEnv": { // override "local" from packaged version "GOTOOLCHAIN": "auto" diff --git a/package/gitea/source/.dockerignore b/package/gitea/source/.dockerignore index c88fb144..f61d8aea 100644 --- a/package/gitea/source/.dockerignore +++ b/package/gitea/source/.dockerignore @@ -40,9 +40,7 @@ cpu.out *.log /gitea -/gitea-vet /debug -/integrations.test /bin /dist @@ -54,12 +52,6 @@ cpu.out /indexers /log /tests/integration/gitea-integration-* -/tests/integration/indexers-* -/tests/e2e/gitea-e2e-* -/tests/e2e/indexers-* -/tests/e2e/reports -/tests/e2e/test-artifacts -/tests/e2e/test-snapshots /tests/*.ini /node_modules /yarn.lock diff --git a/package/gitea/source/.editorconfig b/package/gitea/source/.editorconfig index bf1cf757..703a8348 100644 --- a/package/gitea/source/.editorconfig +++ b/package/gitea/source/.editorconfig @@ -18,7 +18,7 @@ indent_style = tab [templates/custom/*.tmpl] insert_final_newline = false -[templates/swagger/v1_json.tmpl] +[templates/swagger/*_json.tmpl] indent_style = space insert_final_newline = false diff --git a/package/gitea/source/.gitattributes b/package/gitea/source/.gitattributes index afd02555..3ddb8f64 100644 --- a/package/gitea/source/.gitattributes +++ b/package/gitea/source/.gitattributes @@ -4,6 +4,7 @@ /assets/*.json linguist-generated /public/assets/img/svg/*.svg linguist-generated /templates/swagger/v1_json.tmpl linguist-generated +/templates/swagger/v1_openapi3_json.tmpl linguist-generated /options/fileicon/** linguist-generated /vendor/** -text -eol linguist-vendored /web_src/js/vendor/** -text -eol linguist-vendored diff --git a/package/gitea/source/.gitea/issue_template.md b/package/gitea/source/.gitea/issue_template.md deleted file mode 100644 index cf173a67..00000000 --- a/package/gitea/source/.gitea/issue_template.md +++ /dev/null @@ -1,42 +0,0 @@ - - - - -- Gitea version (or commit ref): -- Git version: -- Operating system: - - - -- Database (use `[x]`): - - [ ] PostgreSQL - - [ ] MySQL - - [ ] MSSQL - - [ ] SQLite -- Can you reproduce the bug at https://demo.gitea.com: - - [ ] Yes (provide example URL) - - [ ] No -- Log gist: - - - - -## Description - - -... - - -## Screenshots - - diff --git a/package/gitea/source/.github/ISSUE_TEMPLATE/bug-report.yaml b/package/gitea/source/.github/ISSUE_TEMPLATE/bug-report.yaml index 4dbe1a4c..e793e068 100644 --- a/package/gitea/source/.github/ISSUE_TEMPLATE/bug-report.yaml +++ b/package/gitea/source/.github/ISSUE_TEMPLATE/bug-report.yaml @@ -1,91 +1,28 @@ name: Bug Report -description: Found something you weren't expecting? Report it here! +description: Something isn't working as expected. labels: ["type/bug"] body: - type: markdown attributes: value: | - NOTE: If your issue is a security concern, please send an email to security@gitea.io instead of opening a public issue. - - type: markdown - attributes: - value: | - 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://forum.gitea.com). - 3. Make sure you are using the latest release and - take a moment to check that your issue hasn't been reported before. - 4. Make sure it's not mentioned in the FAQ (https://docs.gitea.com/help/faq) - 5. It's really important to provide pertinent details and logs (https://docs.gitea.com/help/support), - incomplete details will be handled as an invalid report. - - type: textarea - id: description - attributes: - label: Description - description: | - Please provide a description of your issue here, with a URL if you were able to reproduce the issue (see below) - If you are using a proxy or a CDN (e.g. Cloudflare) in front of Gitea, please disable the proxy/CDN fully and access Gitea directly to confirm the issue still persists without those services. + - **Security issue?** Email security@gitea.io instead of opening a public issue. + - **Need help** with setup or configuration? Ask on [Discord](https://discord.gg/Gitea) or the [forum](https://forum.gitea.com). + - Search [existing issues](https://github.com/go-gitea/gitea/issues?q=is%3Aissue) first. - type: input id: gitea-ver attributes: label: Gitea Version - description: Gitea version (or commit reference) of your instance validations: required: true - - type: dropdown - id: can-reproduce + - type: textarea + id: description attributes: - 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://demo.gitea.com - options: - - "Yes" - - "No" + label: What happened? + description: What you did, what you expected to happen, and what happened instead. Include logs if relevant. validations: required: true - - type: markdown - attributes: - value: | - It's really important to provide pertinent logs - Please read https://docs.gitea.com/administration/logging-config#collecting-logs-for-help - In addition, if your problem relates to git commands set `RUN_MODE=dev` at the top of app.ini - - type: input - id: logs - attributes: - label: Log Gist - description: Please provide a gist URL of your logs, with any sensitive information (e.g. API keys) removed/hidden - type: textarea - id: screenshots - attributes: - label: Screenshots - description: If this issue involves the Web Interface, please provide one or more screenshots - - type: input - id: git-ver - attributes: - label: Git Version - description: The version of git running on the server - - type: input - id: os-ver - attributes: - label: Operating System - description: The operating system you are using to run Gitea - - type: textarea - id: run-info + id: environment 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://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: - required: true - - type: dropdown - id: database - attributes: - label: Database - description: What database system are you running? - options: - - PostgreSQL - - MySQL/MariaDB - - MSSQL - - SQLite + description: Install method (binary, Docker, package), operating system, and database. diff --git a/package/gitea/source/.github/ISSUE_TEMPLATE/feature-request.yaml b/package/gitea/source/.github/ISSUE_TEMPLATE/feature-request.yaml index d5c480d2..3ad0fb9e 100644 --- a/package/gitea/source/.github/ISSUE_TEMPLATE/feature-request.yaml +++ b/package/gitea/source/.github/ISSUE_TEMPLATE/feature-request.yaml @@ -1,24 +1,20 @@ name: Feature Request -description: Got an idea for a feature that Gitea doesn't have currently? Submit your idea here! +description: Suggest an idea for Gitea. labels: ["type/proposal"] body: - type: markdown attributes: value: | - 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://forum.gitea.com). - 3. Please take a moment to check that your feature hasn't already been suggested. + Search [existing issues](https://github.com/go-gitea/gitea/issues?q=is%3Aissue) first. - type: textarea - id: description + id: problem attributes: - label: Feature Description - placeholder: | - I think it would be great if Gitea had... + label: What problem would this solve? validations: required: true - type: textarea - id: screenshots + id: proposal attributes: - label: Screenshots - description: If you can, provide screenshots of an implementation on another site e.g. GitHub + label: What do you propose? + validations: + required: true diff --git a/package/gitea/source/.github/ISSUE_TEMPLATE/ui.bug-report.yaml b/package/gitea/source/.github/ISSUE_TEMPLATE/ui.bug-report.yaml deleted file mode 100644 index 3ad5dbaf..00000000 --- a/package/gitea/source/.github/ISSUE_TEMPLATE/ui.bug-report.yaml +++ /dev/null @@ -1,66 +0,0 @@ -name: Web Interface Bug Report -description: Something doesn't look quite as it should? Report it here! -labels: ["type/bug", "topic/ui"] -body: - - type: markdown - attributes: - value: | - NOTE: If your issue is a security concern, please send an email to security@gitea.io instead of opening a public issue. - - type: markdown - attributes: - value: | - 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://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 - incomplete details will be handled as an invalid report. - 6. In particular it's really important to provide pertinent logs. If you are certain that this is a javascript - error, show us the javascript console. If the error appears to relate to Gitea the server you must also give us - DEBUG level logs. (See https://docs.gitea.com/administration/logging-config#collecting-logs-for-help) - - type: textarea - id: description - attributes: - label: Description - description: | - Please provide a description of your issue here, with a URL if you were able to reproduce the issue (see below) - If using a proxy or a CDN (e.g. CloudFlare) in front of gitea, please disable the proxy/CDN fully and connect to gitea directly to confirm the issue still persists without those services. - - type: textarea - id: screenshots - attributes: - label: Screenshots - description: Please provide at least 1 screenshot showing the issue. - validations: - required: true - - type: input - id: gitea-ver - attributes: - label: Gitea Version - description: Gitea version (or commit reference) your instance is running - validations: - required: true - - type: dropdown - id: can-reproduce - attributes: - 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://demo.gitea.com - options: - - "Yes" - - "No" - validations: - required: true - - type: input - id: os-ver - attributes: - label: Operating System - description: The operating system you are using to access Gitea - - type: input - id: browser-ver - attributes: - label: Browser Version - description: The browser and version that you are using to access Gitea - validations: - required: true diff --git a/package/gitea/source/.github/actions/docker-dryrun/action.yml b/package/gitea/source/.github/actions/docker-dryrun/action.yml new file mode 100644 index 00000000..e9cd88d4 --- /dev/null +++ b/package/gitea/source/.github/actions/docker-dryrun/action.yml @@ -0,0 +1,29 @@ +name: docker-dryrun +description: Composite action that performs the container build steps for a single platform. + +inputs: + platform: + description: "The target platform: linux/amd64, linux/arm64, linux/riscv64." + required: true + +runs: + using: composite + steps: + - uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0 + - uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 + - name: Build regular image + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 + with: + context: . + platforms: ${{ inputs.platform }} + push: false + file: Dockerfile + cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful + - name: Build rootless image + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 + with: + context: . + platforms: ${{ inputs.platform }} + push: false + file: Dockerfile.rootless + cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootless diff --git a/package/gitea/source/.github/actions/free-disk-space/action.yml b/package/gitea/source/.github/actions/free-disk-space/action.yml new file mode 100644 index 00000000..a20f2bd5 --- /dev/null +++ b/package/gitea/source/.github/actions/free-disk-space/action.yml @@ -0,0 +1,17 @@ +name: free-disk-space +description: Free space on / before large cache restores + +# Delete preinstalled toolchains which gitea doesn't use and show disk space usage +runs: + using: composite + steps: + - shell: bash + run: | + echo "free space before cleanup:" + df -h / + for dir in /usr/local/lib/android /usr/local/.ghcup /opt/ghc /usr/share/dotnet; do + sudo rm -rf "$dir" & + done + wait + echo "free space after cleanup:" + df -h / diff --git a/package/gitea/source/.github/actions/go-cache/action.yml b/package/gitea/source/.github/actions/go-cache/action.yml new file mode 100644 index 00000000..5abf4e31 --- /dev/null +++ b/package/gitea/source/.github/actions/go-cache/action.yml @@ -0,0 +1,50 @@ +name: go-caches +description: Restore the go module, build, and golangci-lint caches. Save only on the cache-seeder workflow. + +# Only the cache-seeder workflow saves; rename requires updating cache-seeder.yml. +# The lint job restores but does not save the gobuild cache, so only one writer +# (the gobuild job) populates it and there is no contention on the cache key. +# Seeder restores by exact key only (no restore-keys) so each go.sum seeds a clean +# cache and size stays bounded; do not add restore-keys here. PR runs keep them. + +inputs: + lint-cache: + description: Restore (and save in cache-seeder) ~/.cache/golangci-lint + default: "false" + +runs: + using: composite + steps: + - if: ${{ github.workflow == 'cache-seeder' }} + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: ~/go/pkg/mod + key: gomod-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }} + - if: ${{ github.workflow != 'cache-seeder' }} + uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: ~/go/pkg/mod + key: gomod-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }} + restore-keys: gomod-${{ runner.os }}-${{ runner.arch }} + - if: ${{ github.workflow == 'cache-seeder' && inputs.lint-cache != 'true' }} + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: ~/.cache/go-build + key: gobuild-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }} + - if: ${{ github.workflow != 'cache-seeder' || inputs.lint-cache == 'true' }} + uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: ~/.cache/go-build + key: gobuild-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }} + restore-keys: gobuild-${{ runner.os }}-${{ runner.arch }} + - if: ${{ inputs.lint-cache == 'true' && github.workflow == 'cache-seeder' }} + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: ~/.cache/golangci-lint + key: golint-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum', '.golangci.yml') }} + - if: ${{ inputs.lint-cache == 'true' && github.workflow != 'cache-seeder' }} + uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: ~/.cache/golangci-lint + key: golint-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum', '.golangci.yml') }} + restore-keys: golint-${{ runner.os }}-${{ runner.arch }} diff --git a/package/gitea/source/.github/actions/go-setup/action.yml b/package/gitea/source/.github/actions/go-setup/action.yml new file mode 100644 index 00000000..8fd6e519 --- /dev/null +++ b/package/gitea/source/.github/actions/go-setup/action.yml @@ -0,0 +1,24 @@ +name: go-setup +description: Set up go and restore caches + +inputs: + cache: + description: Restore go caches + default: "true" + lint-cache: + description: Also restore the golangci-lint cache + default: "false" + +runs: + using: composite + steps: + - uses: ./.github/actions/free-disk-space + - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 + with: + go-version-file: go.mod + check-latest: true + cache: false + - if: ${{ inputs.cache == 'true' }} + uses: ./.github/actions/go-cache + with: + lint-cache: ${{ inputs.lint-cache }} diff --git a/package/gitea/source/.github/actions/node-setup/action.yml b/package/gitea/source/.github/actions/node-setup/action.yml new file mode 100644 index 00000000..cac3e3b1 --- /dev/null +++ b/package/gitea/source/.github/actions/node-setup/action.yml @@ -0,0 +1,22 @@ +name: node-setup +description: Set up pnpm and node and restore caches + +inputs: + cache: + description: Cache pnpm downloads + default: "true" + +runs: + using: composite + steps: + - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 + - if: ${{ inputs.cache == 'true' }} + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: 24 + cache: pnpm + cache-dependency-path: pnpm-lock.yaml + - if: ${{ inputs.cache != 'true' }} + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: 24 diff --git a/package/gitea/source/.github/actions/pgsql-shard/action.yml b/package/gitea/source/.github/actions/pgsql-shard/action.yml new file mode 100644 index 00000000..9a5a03ae --- /dev/null +++ b/package/gitea/source/.github/actions/pgsql-shard/action.yml @@ -0,0 +1,40 @@ +name: pgsql-shard +description: Run one pgsql integration test shard + +inputs: + shard: + description: Shard index + required: true + total-shards: + description: Total shard count + required: true + run-migration: + description: Also run migration tests + default: "false" + +runs: + using: composite + steps: + - name: Add hosts to /etc/hosts + shell: bash + run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 pgsql ldap minio" | sudo tee -a /etc/hosts' + - shell: bash + run: make deps-backend + - shell: bash + run: make backend + env: + TAGS: bindata + - name: run migration tests + if: ${{ inputs.run-migration == 'true' }} + shell: bash + run: GITEA_TEST_DATABASE=pgsql make test-migration + - name: run tests + shell: bash + run: GITEA_TEST_DATABASE=pgsql make test-integration + env: + # pgsql is chosen to be the unlucky one to run with the slow "race detector", it is about 60% slower. + GOTEST_FLAGS: -race -timeout=40m + TAGS: bindata gogit + TEST_LDAP: 1 + TEST_SHARD: ${{ inputs.shard }} + TEST_TOTAL_SHARDS: ${{ inputs.total-shards }} diff --git a/package/gitea/source/.github/dependabot.yml b/package/gitea/source/.github/dependabot.yml deleted file mode 100644 index be33b897..00000000 --- a/package/gitea/source/.github/dependabot.yml +++ /dev/null @@ -1,10 +0,0 @@ -version: 2 - -updates: - - package-ecosystem: github-actions - labels: [modifies/dependencies] - directory: / - schedule: - interval: daily - cooldown: - default-days: 5 diff --git a/package/gitea/source/.github/labeler.yml b/package/gitea/source/.github/labeler.yml index 0f3c5080..937e69ef 100644 --- a/package/gitea/source/.github/labeler.yml +++ b/package/gitea/source/.github/labeler.yml @@ -1,80 +1,3 @@ -modifies/docs: - - changed-files: - - any-glob-to-any-file: - - "**/*.md" - - "docs/**" - -modifies/templates: - - changed-files: - - all-globs-to-any-file: - - "templates/**" - - "!templates/swagger/v1_json.tmpl" - -modifies/api: - - changed-files: - - any-glob-to-any-file: - - "routers/api/**" - - "templates/swagger/v1_json.tmpl" - -modifies/cli: - - changed-files: - - any-glob-to-any-file: - - "cmd/**" - -modifies/translation: - - changed-files: - - any-glob-to-any-file: - - "options/locale/*.ini" - -modifies/migrations: - - changed-files: - - any-glob-to-any-file: - - "models/migrations/**" - -modifies/internal: - - changed-files: - - any-glob-to-any-file: - - ".air.toml" - - "Makefile" - - "Dockerfile" - - "Dockerfile.rootless" - - ".dockerignore" - - "docker/**" - - ".editorconfig" - - ".eslintrc.cjs" - - ".golangci.yml" - - ".markdownlint.yaml" - - ".spectral.yaml" - - "stylelint.config.*" - - ".yamllint.yaml" - - ".github/**" - - ".gitea/**" - - ".devcontainer/**" - - "build/**" - - "contrib/**" - -modifies/dependencies: - - changed-files: - - any-glob-to-any-file: - - "package.json" - - "pnpm-lock.yaml" - - "pyproject.toml" - - "uv.lock" - - "go.mod" - - "go.sum" - -modifies/go: - - changed-files: - - any-glob-to-any-file: - - "**/*.go" - -modifies/frontend: - - changed-files: - - any-glob-to-any-file: - - "*.js" - - "*.ts" - - "web_src/**" - docs-update-needed: - changed-files: - any-glob-to-any-file: diff --git a/package/gitea/source/.github/pull_request_template.md b/package/gitea/source/.github/pull_request_template.md index b7594a1b..6ae22da7 100644 --- a/package/gitea/source/.github/pull_request_template.md +++ b/package/gitea/source/.github/pull_request_template.md @@ -1,10 +1,9 @@ - -Please check the following: -1. Make sure you are targeting the `main` branch, pull requests on release branches are only allowed for backports. -2. Make sure you have read contributing guidelines: https://github.com/go-gitea/gitea/blob/main/CONTRIBUTING.md . -3. For documentations contribution, please go to https://gitea.com/gitea/docs -4. Describe what your pull request does and which issue you're targeting (if any). -5. It is recommended to enable "Allow edits by maintainers", so maintainers can help more easily. -6. Your input here will be included in the commit message when this PR has been merged. If you don't want some content to be included, please separate them with a line like `---`. -7. Delete all these tips before posting. - + diff --git a/package/gitea/source/.github/workflows/cache-seeder.yml b/package/gitea/source/.github/workflows/cache-seeder.yml new file mode 100644 index 00000000..62515787 --- /dev/null +++ b/package/gitea/source/.github/workflows/cache-seeder.yml @@ -0,0 +1,72 @@ +# Populates main's cache scope so PR runs warm-start from it. Saves the go +# module, go build (incl. test compile), and golangci-lint caches. +# +# Caches are ref-scoped: PR runs read their own scope then fall back to the +# base branch. Per .github/actions/go-cache/action.yml, PRs are restore-only, +# so push-to-main is the only opportunity to populate the fallback scope. + +name: cache-seeder + +on: + push: + branches: + - main + paths: + - "go.sum" + - ".golangci.yml" + - ".github/actions/go-cache/action.yml" + - ".github/actions/go-setup/action.yml" + - ".github/workflows/cache-seeder.yml" + +concurrency: + group: cache-seeder + cancel-in-progress: true + +permissions: + contents: read + +jobs: + gobuild: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: ./.github/actions/go-setup + - run: make deps-backend deps-tools + - run: TAGS="bindata" make backend + - run: TAGS="bindata gogit" GOEXPERIMENT="" make backend + - name: warm test compile cache (bindata) + env: + TAGS: bindata + GOTEST_FLAGS: -race -list=^$$ -count=1 + run: make test-backend + - name: warm test compile cache (bindata gogit) + env: + TAGS: bindata gogit + GOEXPERIMENT: + GOTEST_FLAGS: -race -list=^$$ -count=1 + run: make test-backend + - name: warm integration compile cache + run: | + TAGS="bindata" make test-integration-compile + TAGS="bindata gogit" GOEXPERIMENT="" make test-integration-compile + TAGS="bindata gogit" GOTEST_FLAGS="-race" make test-integration-compile + + lint: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - { tags: "bindata", target: "lint-backend" } + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: ./.github/actions/go-setup + with: + lint-cache: "true" + - run: make deps-backend deps-tools + - run: make generate-go + env: + TAGS: ${{ matrix.tags }} + - run: make ${{ matrix.target }} + env: + TAGS: ${{ matrix.tags }} diff --git a/package/gitea/source/.github/workflows/cron-flake-updater.yml b/package/gitea/source/.github/workflows/cron-flake-updater.yml deleted file mode 100644 index c9a1f22a..00000000 --- a/package/gitea/source/.github/workflows/cron-flake-updater.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: cron-flake-updater - -on: - workflow_dispatch: - schedule: - - cron: '0 0 * * 0' # runs weekly on Sunday at 00:00 - -jobs: - nix-flake-update: - permissions: - contents: write - issues: write - pull-requests: write - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - uses: DeterminateSystems/determinate-nix-action@v3 - - uses: DeterminateSystems/update-flake-lock@main - with: - pr-title: "Update Nix flake" - pr-labels: | - dependencies diff --git a/package/gitea/source/.github/workflows/cron-licenses.yml b/package/gitea/source/.github/workflows/cron-licenses.yml index ee1c3e0c..06ea0e30 100644 --- a/package/gitea/source/.github/workflows/cron-licenses.yml +++ b/package/gitea/source/.github/workflows/cron-licenses.yml @@ -12,15 +12,15 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v6 - - uses: actions/setup-go@v6 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 with: go-version-file: go.mod check-latest: true - run: make generate-gitignore timeout-minutes: 40 - name: push translations to repo - uses: appleboy/git-push-action@v1.2.0 + uses: appleboy/git-push-action@3b2c8661652360dbf1afe1b319a49dbb739c39f1 # v1.2.0 with: author_email: "teabot@gitea.io" author_name: GiteaBot diff --git a/package/gitea/source/.github/workflows/cron-renovate.yml b/package/gitea/source/.github/workflows/cron-renovate.yml new file mode 100644 index 00000000..99d3a79d --- /dev/null +++ b/package/gitea/source/.github/workflows/cron-renovate.yml @@ -0,0 +1,32 @@ +name: cron-renovate + +on: + schedule: + - cron: "23 * * * *" # hourly at :23 + workflow_dispatch: + +concurrency: + group: cron-renovate + +env: + RENOVATE_VERSION: 43.141.5 # renovate: datasource=docker depName=ghcr.io/renovatebot/renovate + +permissions: + contents: read + +jobs: + cron-renovate: + runs-on: ubuntu-latest + if: github.repository == 'go-gitea/gitea' # prevent running on forks + timeout-minutes: 30 + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: renovatebot/github-action@6d859fc95779be83a0335ca704879b47e5d79641 # v46.1.16 + with: + renovate-version: ${{ env.RENOVATE_VERSION }} + configurationFile: renovate.json5 + token: ${{ secrets.RENOVATE_TOKEN }} + env: + RENOVATE_BINARY_SOURCE: install # auto-install go/node toolchains needed by post-upgrade tasks. + RENOVATE_ALLOWED_POST_UPGRADE_COMMANDS: '["^make (tidy|svg)$"]' + RENOVATE_REPOSITORIES: '["go-gitea/gitea"]' diff --git a/package/gitea/source/.github/workflows/cron-translations.yml b/package/gitea/source/.github/workflows/cron-translations.yml index 56a30fb5..936a03eb 100644 --- a/package/gitea/source/.github/workflows/cron-translations.yml +++ b/package/gitea/source/.github/workflows/cron-translations.yml @@ -12,8 +12,8 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v6 - - uses: crowdin/github-action@v2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: crowdin/github-action@52aa776766211d83d975df51f3b9c53c2f8ba35f # v2.16.3 with: upload_sources: true upload_translations: false @@ -29,7 +29,7 @@ jobs: - name: update locales run: ./build/update-locales.sh - name: push translations to repo - uses: appleboy/git-push-action@v1.2.0 + uses: appleboy/git-push-action@3b2c8661652360dbf1afe1b319a49dbb739c39f1 # v1.2.0 with: author_email: "teabot@gitea.io" author_name: GiteaBot diff --git a/package/gitea/source/.github/workflows/files-changed.yml b/package/gitea/source/.github/workflows/files-changed.yml index 55d206bb..63548a30 100644 --- a/package/gitea/source/.github/workflows/files-changed.yml +++ b/package/gitea/source/.github/workflows/files-changed.yml @@ -15,19 +15,26 @@ on: value: ${{ jobs.detect.outputs.templates }} docker: value: ${{ jobs.detect.outputs.docker }} + dockerfile: + value: ${{ jobs.detect.outputs.dockerfile }} swagger: value: ${{ jobs.detect.outputs.swagger }} yaml: value: ${{ jobs.detect.outputs.yaml }} json: value: ${{ jobs.detect.outputs.json }} + e2e: + value: ${{ jobs.detect.outputs.e2e }} + shell: + value: ${{ jobs.detect.outputs.shell }} + +permissions: + contents: read jobs: detect: runs-on: ubuntu-latest timeout-minutes: 3 - permissions: - contents: read outputs: backend: ${{ steps.changes.outputs.backend }} frontend: ${{ steps.changes.outputs.frontend }} @@ -35,12 +42,15 @@ jobs: actions: ${{ steps.changes.outputs.actions }} templates: ${{ steps.changes.outputs.templates }} docker: ${{ steps.changes.outputs.docker }} + dockerfile: ${{ steps.changes.outputs.dockerfile }} swagger: ${{ steps.changes.outputs.swagger }} yaml: ${{ steps.changes.outputs.yaml }} json: ${{ steps.changes.outputs.json }} + e2e: ${{ steps.changes.outputs.e2e }} + shell: ${{ steps.changes.outputs.shell }} steps: - - uses: actions/checkout@v6 - - uses: dorny/paths-filter@v4 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1 id: changes with: filters: | @@ -54,49 +64,61 @@ jobs: - ".golangci.yml" - ".editorconfig" - "options/locale/locale_en-US.json" + - "models/fixtures/**" + - "tests/*.ini.tmpl" + - "tests/gitea-repositories-meta/**" + - "tests/testdata/**" + - "tools/test-integration.sh" frontend: - - "*.js" - "*.ts" - "web_src/**" - - "tools/*.js" - - "tools/*.ts" + - "tools/generate-svg.ts" + - "tools/generate-svg-vscode-extensions.json" + - "tsconfig.json" - "assets/emoji.json" - "package.json" - "pnpm-lock.yaml" + - "pnpm-workspace.yaml" - "Makefile" - - ".eslintrc.cjs" - - ".npmrc" docs: - "**/*.md" - ".markdownlint.yaml" - "package.json" - "pnpm-lock.yaml" + - "pnpm-workspace.yaml" actions: - ".github/workflows/*" + - ".github/actions/**" - "Makefile" templates: - - "tools/lint-templates-*.js" + - "tools/lint-templates-*.ts" - "templates/**/*.tmpl" - "pyproject.toml" - "uv.lock" docker: - ".github/workflows/pull-docker-dryrun.yml" + - ".github/actions/docker-dryrun/**" - "Dockerfile" - "Dockerfile.rootless" - "docker/**" - "Makefile" + dockerfile: + - "Dockerfile" + - "Dockerfile.rootless" + swagger: - "templates/swagger/v1_json.tmpl" - "templates/swagger/v1_input.json" - "Makefile" - "package.json" - "pnpm-lock.yaml" + - "pnpm-workspace.yaml" - ".spectral.yaml" yaml: @@ -107,3 +129,14 @@ jobs: json: - "**/*.json" + - "**/*.json5" + - "eslint.json.config.ts" + + e2e: + - "tests/e2e/**" + - "tools/test-e2e.sh" + - "playwright.config.ts" + + shell: + - "**/*.sh" + - ".shellcheckrc" diff --git a/package/gitea/source/.github/workflows/giteabot-backport.yml b/package/gitea/source/.github/workflows/giteabot-backport.yml new file mode 100644 index 00000000..f398d481 --- /dev/null +++ b/package/gitea/source/.github/workflows/giteabot-backport.yml @@ -0,0 +1,26 @@ +name: giteabot backport + +on: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: false + +jobs: + giteabot: + if: github.repository == 'go-gitea/gitea' + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: go-gitea/giteabot@912675d47455ac93be82d8bda4667a02b20a6fe4 # v1.0.4 + with: + github_token: ${{ secrets.GITEABOT_TOKEN }} + gitea_fork: giteabot/gitea + checks: backport diff --git a/package/gitea/source/.github/workflows/giteabot.yml b/package/gitea/source/.github/workflows/giteabot.yml new file mode 100644 index 00000000..c439850a --- /dev/null +++ b/package/gitea/source/.github/workflows/giteabot.yml @@ -0,0 +1,64 @@ +name: giteabot + +on: + # When main advances, rerun merge queue maintenance so the oldest + # reviewed/wait-merge PR can be updated against the new base promptly. + push: + branches: + - main + # pull_request_target gives this workflow access to GITEABOT_TOKEN on PRs from + # forks, which the bot needs to write labels, statuses and comments. Safe here + # because the job only runs a pinned action and never checks out PR HEAD. + # These PR lifecycle events drive label maintenance, queue maintenance, and + # explicit bot actions triggered by relevant label changes. + pull_request_target: # zizmor: ignore[dangerous-triggers] + types: + - opened + - synchronize + - labeled + - unlabeled + - closed + - review_requested + - review_request_removed + # Review events keep review-derived state such as lgtm labels and status checks + # in sync after approvals, edits, or dismissals. + pull_request_review: + types: + - submitted + - edited + - dismissed + # Periodic maintenance is still useful as a backstop for queue cleanup and + # other housekeeping, even though main pushes now trigger it promptly. + schedule: + - cron: "15 3 * * *" + # Allow maintainers to rerun selected checks manually when debugging bot + # behavior without waiting for another repository event. + workflow_dispatch: + inputs: + checks: + description: Comma-separated list of non-backport checks to run + required: false + default: labels,merge_queue,lock,feedback,last_call,milestones,lgtm,translation_comment,pr_actions + +permissions: + contents: read + issues: write + pull-requests: write + statuses: write + +concurrency: + group: ${{ format('{0}-{1}', github.workflow, (github.event_name == 'pull_request_target' || github.event_name == 'pull_request_review') && format('pr-{0}', github.event.pull_request.number) || 'maintenance') }} + cancel-in-progress: false + +jobs: + giteabot: + if: github.repository == 'go-gitea/gitea' + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + # pull_request_review runs without repository secrets on fork PRs, so fall + # back to the workflow token for the non-backport checks handled here. + - uses: go-gitea/giteabot@912675d47455ac93be82d8bda4667a02b20a6fe4 # v1.0.4 + with: + github_token: ${{ secrets.GITEABOT_TOKEN || github.token }} + checks: ${{ github.event.inputs.checks || 'labels,merge_queue,lock,feedback,last_call,milestones,lgtm,translation_comment,pr_actions' }} diff --git a/package/gitea/source/.github/workflows/pull-compliance.yml b/package/gitea/source/.github/workflows/pull-compliance.yml index c93aed05..eff24863 100644 --- a/package/gitea/source/.github/workflows/pull-compliance.yml +++ b/package/gitea/source/.github/workflows/pull-compliance.yml @@ -7,156 +7,63 @@ concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true +permissions: + contents: read + jobs: files-changed: uses: ./.github/workflows/files-changed.yml - permissions: - contents: read lint-backend: if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true' needs: files-changed runs-on: ubuntu-latest - permissions: - contents: read steps: - - uses: actions/checkout@v6 - - uses: actions/setup-go@v6 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: ./.github/actions/go-setup with: - go-version-file: go.mod - check-latest: true + lint-cache: "true" - run: make deps-backend deps-tools + - run: TAGS="bindata" make generate-go # lint-go also lints with "bindata" tags which requires "_bindata.go" - run: make lint-backend - env: - TAGS: bindata sqlite sqlite_unlock_notify - lint-templates: - if: needs.files-changed.outputs.templates == 'true' + lint-on-demand: needs: files-changed runs-on: ubuntu-latest - permissions: - contents: read steps: - - uses: actions/checkout@v6 - - uses: astral-sh/setup-uv@v8.0.0 - - run: uv python install 3.14 - - uses: pnpm/action-setup@v5 - - uses: actions/setup-node@v6 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: ./.github/actions/go-setup with: - node-version: 24 - cache: pnpm - cache-dependency-path: pnpm-lock.yaml - - run: make deps-py - - run: make deps-frontend - - run: make lint-templates - - lint-yaml: - if: needs.files-changed.outputs.yaml == 'true' - needs: files-changed - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - uses: actions/checkout@v6 - - uses: astral-sh/setup-uv@v8.0.0 - - run: uv python install 3.14 - - run: make deps-py - - run: make lint-yaml - - lint-json: - if: needs.files-changed.outputs.json == 'true' - needs: files-changed - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - uses: actions/checkout@v6 - - uses: pnpm/action-setup@v5 - - uses: actions/setup-node@v5 + cache: "false" + - uses: ./.github/actions/node-setup with: - node-version: 24 - - run: make deps-frontend - - run: make lint-json + cache: "false" - lint-swagger: - if: needs.files-changed.outputs.swagger == 'true' - needs: files-changed - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - uses: actions/checkout@v6 - - uses: pnpm/action-setup@v5 - - uses: actions/setup-node@v6 - with: - node-version: 24 - cache: pnpm - cache-dependency-path: pnpm-lock.yaml - - run: make deps-frontend - - run: make lint-swagger - - lint-spell: - if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.actions == 'true' || needs.files-changed.outputs.docs == 'true' || needs.files-changed.outputs.templates == 'true' - needs: files-changed - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - uses: actions/checkout@v6 - - uses: actions/setup-go@v6 - with: - go-version-file: go.mod - check-latest: true - run: make lint-spell - lint-go-windows: - if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true' - needs: files-changed - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - uses: actions/checkout@v6 - - uses: actions/setup-go@v6 + - if: needs.files-changed.outputs.templates == 'true' || needs.files-changed.outputs.yaml == 'true' || needs.files-changed.outputs.actions == 'true' + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: - go-version-file: go.mod - check-latest: true - - run: make deps-backend deps-tools - - run: make lint-go-windows lint-go-gitea-vet - env: - TAGS: bindata sqlite sqlite_unlock_notify - GOOS: windows - GOARCH: amd64 + python-version: 3.14 + - if: needs.files-changed.outputs.templates == 'true' || needs.files-changed.outputs.yaml == 'true' + run: make deps-py lint-templates lint-yaml - lint-go-gogit: - if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true' - needs: files-changed - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - uses: actions/checkout@v6 - - uses: actions/setup-go@v6 - with: - go-version-file: go.mod - check-latest: true - - run: make deps-backend deps-tools - - run: make lint-go - env: - TAGS: bindata gogit sqlite sqlite_unlock_notify + - if: needs.files-changed.outputs.docs == 'true' || needs.files-changed.outputs.swagger == 'true' || needs.files-changed.outputs.json == 'true' + run: make deps-frontend lint-md lint-swagger lint-json + + - if: needs.files-changed.outputs.actions == 'true' + run: make lint-actions + + - if: needs.files-changed.outputs.shell == 'true' + run: make lint-shell checks-backend: if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true' needs: files-changed runs-on: ubuntu-latest - permissions: - contents: read steps: - - uses: actions/checkout@v6 - - uses: actions/setup-go@v6 - with: - go-version-file: go.mod - check-latest: true + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: ./.github/actions/go-setup - run: make deps-backend deps-tools - run: make --always-make checks-backend # ensure the "go-licenses" make target runs @@ -164,16 +71,9 @@ jobs: if: needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.actions == 'true' needs: files-changed runs-on: ubuntu-latest - permissions: - contents: read steps: - - uses: actions/checkout@v6 - - uses: pnpm/action-setup@v5 - - uses: actions/setup-node@v6 - with: - node-version: 24 - cache: pnpm - cache-dependency-path: pnpm-lock.yaml + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: ./.github/actions/node-setup - run: make deps-frontend - run: make lint-frontend - run: make checks-frontend @@ -184,20 +84,14 @@ jobs: if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true' needs: files-changed runs-on: ubuntu-latest - permissions: - contents: read steps: - - uses: actions/checkout@v6 - - uses: actions/setup-go@v6 - with: - go-version-file: go.mod - check-latest: true - # no frontend build here as backend should be able to build - # even without any frontend files - - run: make deps-backend - - run: go build -o gitea_no_gcc # test if build succeeds without the sqlite tag + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: ./.github/actions/go-setup + - run: make deps-backend generate-go + # no frontend build here as backend should be able to build, even without any frontend files + # CGO is not used when cross-compile, so these steps also test if the code is compatible with CGO disabled - name: build-backend-arm64 - run: make backend # test cross compile + run: go build -o gitea_linux_arm64 env: GOOS: linux GOARCH: arm64 @@ -209,38 +103,7 @@ jobs: GOARCH: amd64 TAGS: bindata gogit - name: build-backend-386 - run: go build -o gitea_linux_386 # test if compatible with 32 bit + run: go build -o gitea_linux_386 env: GOOS: linux GOARCH: 386 - - docs: - if: needs.files-changed.outputs.docs == 'true' || needs.files-changed.outputs.actions == 'true' - needs: files-changed - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - uses: actions/checkout@v6 - - uses: pnpm/action-setup@v5 - - uses: actions/setup-node@v6 - with: - node-version: 24 - cache: pnpm - cache-dependency-path: pnpm-lock.yaml - - run: make deps-frontend - - run: make lint-md - - actions: - if: needs.files-changed.outputs.actions == 'true' || needs.files-changed.outputs.actions == 'true' - needs: files-changed - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - uses: actions/checkout@v6 - - uses: actions/setup-go@v6 - with: - go-version-file: go.mod - check-latest: true - - run: make lint-actions diff --git a/package/gitea/source/.github/workflows/pull-db-tests.yml b/package/gitea/source/.github/workflows/pull-db-tests.yml index d168c2ec..83026bcb 100644 --- a/package/gitea/source/.github/workflows/pull-db-tests.yml +++ b/package/gitea/source/.github/workflows/pull-db-tests.yml @@ -7,18 +7,18 @@ concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true +permissions: + contents: read + jobs: files-changed: uses: ./.github/workflows/files-changed.yml - permissions: - contents: read - test-pgsql: - if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true' + test-pgsql-shard-1: + if: needs.files-changed.outputs.backend == 'true' needs: files-changed runs-on: ubuntu-latest - permissions: - contents: read + timeout-minutes: 50 services: pgsql: image: postgres:14 @@ -28,79 +28,100 @@ jobs: ports: - "5432:5432" ldap: - image: gitea/test-openldap:latest + image: gitea/test-openldap:latest@sha256:4ac633b01d684e6b2a458cc0c8530c92f9b3702f6e040ce5f365607df34fbda0 ports: - "389:389" - "636:636" minio: # as github actions doesn't support "entrypoint", we need to use a non-official image # that has a custom entrypoint set to "minio server /data" - image: bitnamilegacy/minio:2023.8.31 + image: bitnamilegacy/minio:2025.7.23 env: MINIO_ROOT_USER: 123456 MINIO_ROOT_PASSWORD: 12345678 ports: - "9000:9000" steps: - - uses: actions/checkout@v6 - - uses: actions/setup-go@v6 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: ./.github/actions/go-setup + - uses: ./.github/actions/pgsql-shard with: - go-version-file: go.mod - check-latest: true - - name: Add hosts to /etc/hosts - run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 pgsql ldap minio" | sudo tee -a /etc/hosts' - - run: make deps-backend - - run: make backend + shard: 1 + total-shards: 2 + run-migration: "true" + + test-pgsql-shard-2: + if: needs.files-changed.outputs.backend == 'true' + needs: files-changed + runs-on: ubuntu-latest + timeout-minutes: 50 + services: + pgsql: + image: postgres:14 env: - TAGS: bindata - - name: run migration tests - run: make test-pgsql-migration - - name: run tests - run: make test-pgsql - timeout-minutes: 50 + POSTGRES_DB: test + POSTGRES_PASSWORD: postgres + ports: + - "5432:5432" + ldap: + image: gitea/test-openldap:latest@sha256:4ac633b01d684e6b2a458cc0c8530c92f9b3702f6e040ce5f365607df34fbda0 + ports: + - "389:389" + - "636:636" + minio: + # as github actions doesn't support "entrypoint", we need to use a non-official image + # that has a custom entrypoint set to "minio server /data" + image: bitnamilegacy/minio:2025.7.23 env: - TAGS: bindata gogit - RACE_ENABLED: true - TEST_TAGS: gogit - TEST_LDAP: 1 + MINIO_ROOT_USER: 123456 + MINIO_ROOT_PASSWORD: 12345678 + ports: + - "9000:9000" + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: ./.github/actions/go-setup + - uses: ./.github/actions/pgsql-shard + with: + shard: 2 + total-shards: 2 test-sqlite: if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true' needs: files-changed runs-on: ubuntu-latest - permissions: - contents: read steps: - - uses: actions/checkout@v6 - - uses: actions/setup-go@v6 - with: - go-version-file: go.mod - check-latest: true + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: ./.github/actions/go-setup - run: make deps-backend - - run: GOEXPERIMENT='' make backend + - run: make backend env: - TAGS: bindata gogit sqlite sqlite_unlock_notify - - name: run migration tests - run: make test-sqlite-migration + TAGS: bindata gogit + GOEXPERIMENT: + - run: GITEA_TEST_DATABASE=sqlite make test-migration + env: + TAGS: bindata gogit - name: run tests - run: GOEXPERIMENT='' make test-sqlite + run: GITEA_TEST_DATABASE=sqlite make test-integration timeout-minutes: 50 env: - TAGS: bindata gogit sqlite sqlite_unlock_notify - RACE_ENABLED: true - TEST_TAGS: gogit sqlite sqlite_unlock_notify + # sqlite driver can contain large amount of Golang code, so don't use race detector for it, otherwise, extremely slow + GOTEST_FLAGS: -timeout=40m + TAGS: bindata gogit + GOEXPERIMENT: test-unit: - if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true' + if: needs.files-changed.outputs.backend == 'true' needs: files-changed runs-on: ubuntu-latest - permissions: - contents: read services: elasticsearch: - image: elasticsearch:7.5.0 + image: docker.elastic.co/elasticsearch/elasticsearch:8.19.15 env: discovery.type: single-node + xpack.security.enabled: false + xpack.ml.enabled: false + ingest.geoip.downloader.enabled: false + ES_JAVA_OPTS: "-Xms1g -Xmx1g" ports: - "9200:9200" meilisearch: @@ -110,7 +131,7 @@ jobs: ports: - "7700:7700" redis: - image: redis + image: redis:latest@sha256:c904002d182255b6db3cbe3a1e8ce6c187d15390c39500b59fc07181aabff7bf options: >- # wait until redis has started --health-cmd "redis-cli ping" --health-interval 5s @@ -119,51 +140,49 @@ jobs: ports: - 6379:6379 minio: - image: bitnamilegacy/minio:2021.3.17 + image: bitnamilegacy/minio:2025.7.23 env: - MINIO_ACCESS_KEY: 123456 - MINIO_SECRET_KEY: 12345678 + MINIO_ROOT_USER: 123456 + MINIO_ROOT_PASSWORD: 12345678 ports: - "9000:9000" devstoreaccount1.azurite.local: # https://github.com/Azure/Azurite/issues/1583 - image: mcr.microsoft.com/azure-storage/azurite:latest + image: mcr.microsoft.com/azure-storage/azurite:latest@sha256:dae2a5f96553962901304b94e72ef87e299d0825e4b679673bcc527a25076fe4 ports: - 10000:10000 steps: - - uses: actions/checkout@v6 - - uses: actions/setup-go@v6 - with: - go-version-file: go.mod - check-latest: true + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: ./.github/actions/go-setup - name: Add hosts to /etc/hosts run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 minio devstoreaccount1.azurite.local mysql elasticsearch meilisearch smtpimap" | sudo tee -a /etc/hosts' - run: make deps-backend - - run: make backend + - run: make generate-go env: TAGS: bindata - name: unit-tests - run: make unit-test-coverage test-check + run: make test-backend env: + GOTEST_FLAGS: -race -timeout=20m TAGS: bindata - RACE_ENABLED: true GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }} - name: unit-tests-gogit - run: GOEXPERIMENT='' make unit-test-coverage test-check + run: make test-backend env: + GOTEST_FLAGS: -race -timeout=20m TAGS: bindata gogit - RACE_ENABLED: true + GOEXPERIMENT: GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }} + GITEA_TEST_CI_SKIP_EXTERNAL: true + - run: make test-check test-mysql: - if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true' + if: needs.files-changed.outputs.backend == 'true' needs: files-changed runs-on: ubuntu-latest - permissions: - contents: read services: mysql: # the bitnami mysql image has more options than the official one, it's easier to customize - image: bitnamilegacy/mysql:8.0 + image: bitnamilegacy/mysql:8.4 env: ALLOW_EMPTY_PASSWORD: true MYSQL_DATABASE: testgitea @@ -172,46 +191,42 @@ jobs: options: >- --mount type=tmpfs,destination=/bitnami/mysql/data elasticsearch: - image: elasticsearch:7.5.0 + image: docker.elastic.co/elasticsearch/elasticsearch:8.19.15 env: discovery.type: single-node + xpack.security.enabled: false + xpack.ml.enabled: false + ingest.geoip.downloader.enabled: false + ES_JAVA_OPTS: "-Xms1g -Xmx1g" ports: - "9200:9200" smtpimap: - image: tabascoterrier/docker-imap-devel:latest + image: tabascoterrier/docker-imap-devel:latest@sha256:3fb7cf50b47693e7b80f6f74abea2def4d7386016931d61359864de8a0aba551 ports: - "25:25" - "143:143" - "587:587" - "993:993" steps: - - uses: actions/checkout@v6 - - uses: actions/setup-go@v6 - with: - go-version-file: go.mod - check-latest: true + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: ./.github/actions/go-setup - name: Add hosts to /etc/hosts run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mysql elasticsearch smtpimap" | sudo tee -a /etc/hosts' - run: make deps-backend - run: make backend env: TAGS: bindata - - name: run migration tests - run: make test-mysql-migration + - run: GITEA_TEST_DATABASE=mysql make test-migration - name: run tests - # run: make integration-test-coverage (at the moment, no coverage is really handled) - run: make test-mysql + run: GITEA_TEST_DATABASE=mysql make test-integration env: TAGS: bindata - RACE_ENABLED: true TEST_INDEXER_CODE_ES_URL: "http://elastic:changeme@elasticsearch:9200" test-mssql: - if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true' + if: needs.files-changed.outputs.backend == 'true' needs: files-changed runs-on: ubuntu-latest - permissions: - contents: read services: mssql: image: mcr.microsoft.com/mssql/server:2019-latest @@ -222,24 +237,21 @@ jobs: ports: - "1433:1433" devstoreaccount1.azurite.local: # https://github.com/Azure/Azurite/issues/1583 - image: mcr.microsoft.com/azure-storage/azurite:latest + image: mcr.microsoft.com/azure-storage/azurite:latest@sha256:dae2a5f96553962901304b94e72ef87e299d0825e4b679673bcc527a25076fe4 ports: - 10000:10000 steps: - - uses: actions/checkout@v6 - - uses: actions/setup-go@v6 - with: - go-version-file: go.mod - check-latest: true + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: ./.github/actions/go-setup - name: Add hosts to /etc/hosts run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mssql devstoreaccount1.azurite.local" | sudo tee -a /etc/hosts' - run: make deps-backend - run: make backend env: TAGS: bindata - - run: make test-mssql-migration + - run: GITEA_TEST_DATABASE=mssql make test-migration - name: run tests - run: make test-mssql + run: GITEA_TEST_DATABASE=mssql make test-integration timeout-minutes: 50 env: TAGS: bindata diff --git a/package/gitea/source/.github/workflows/pull-docker-dryrun.yml b/package/gitea/source/.github/workflows/pull-docker-dryrun.yml index 201825cc..37ba12e7 100644 --- a/package/gitea/source/.github/workflows/pull-docker-dryrun.yml +++ b/package/gitea/source/.github/workflows/pull-docker-dryrun.yml @@ -7,34 +7,41 @@ concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true +permissions: + contents: read + jobs: files-changed: uses: ./.github/workflows/files-changed.yml - permissions: - contents: read - container: + # QEMU-based build is slow (40-50 minutes), so run arm64 and riscv64 when dockerfile changes. + # Run amd64 when any docker-related files change, which is fast (4 minutes). + container-amd64: if: needs.files-changed.outputs.docker == 'true' - needs: files-changed + needs: [files-changed] runs-on: ubuntu-latest - permissions: - contents: read steps: - - uses: actions/checkout@v6 - - uses: docker/setup-qemu-action@v4 - - uses: docker/setup-buildx-action@v4 - - name: Build regular container image - uses: docker/build-push-action@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: ./.github/actions/docker-dryrun with: - context: . - platforms: linux/amd64,linux/arm64,linux/riscv64 - push: false - cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful - - name: Build rootless container image - uses: docker/build-push-action@v7 + platform: linux/amd64 + + container-arm64: + if: needs.files-changed.outputs.dockerfile == 'true' + needs: [files-changed] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: ./.github/actions/docker-dryrun with: - context: . - push: false - platforms: linux/amd64,linux/arm64,linux/riscv64 - file: Dockerfile.rootless - cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootless + platform: linux/arm64 + + container-riscv64: + if: needs.files-changed.outputs.dockerfile == 'true' + needs: [files-changed] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: ./.github/actions/docker-dryrun + with: + platform: linux/riscv64 diff --git a/package/gitea/source/.github/workflows/pull-e2e-tests.yml b/package/gitea/source/.github/workflows/pull-e2e-tests.yml index 3472d517..64d1c4c5 100644 --- a/package/gitea/source/.github/workflows/pull-e2e-tests.yml +++ b/package/gitea/source/.github/workflows/pull-e2e-tests.yml @@ -7,37 +7,31 @@ concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true +permissions: + contents: read + jobs: files-changed: uses: ./.github/workflows/files-changed.yml - permissions: - contents: read test-e2e: - if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.frontend == 'true' + if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.e2e == 'true' needs: files-changed runs-on: ubuntu-latest - permissions: - contents: read steps: - - uses: actions/checkout@v6 - - uses: actions/setup-go@v6 - with: - go-version-file: go.mod - check-latest: true - - uses: pnpm/action-setup@v5 - - uses: actions/setup-node@v6 - with: - node-version: 24 - cache: pnpm - cache-dependency-path: pnpm-lock.yaml + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: ./.github/actions/go-setup + - uses: ./.github/actions/node-setup - run: make deps-frontend - run: make frontend - run: make deps-backend - - run: make gitea-e2e + - run: make backend + env: + TAGS: bindata - run: make playwright - run: make test-e2e timeout-minutes: 10 env: + TAGS: bindata FORCE_COLOR: 1 GITEA_TEST_E2E_DEBUG: 1 diff --git a/package/gitea/source/.github/workflows/pull-labeler.yml b/package/gitea/source/.github/workflows/pull-labeler.yml index d05483e5..22b5e703 100644 --- a/package/gitea/source/.github/workflows/pull-labeler.yml +++ b/package/gitea/source/.github/workflows/pull-labeler.yml @@ -1,8 +1,10 @@ name: labeler on: - pull_request_target: - types: [opened, synchronize, reopened] + # pull_request_target is required to label PRs from forks; jobs only use pinned + # actions or base-branch checkout, never PR-head code. + pull_request_target: # zizmor: ignore[dangerous-triggers] + types: [opened, synchronize, reopened, edited, ready_for_review] concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} @@ -15,6 +17,31 @@ jobs: contents: read pull-requests: write steps: - - uses: actions/labeler@v6 + - uses: actions/labeler@f27b608878404679385c85cfa523b85ccb86e213 # v6.1.0 with: sync-labels: true + + pr-title: + if: github.event.pull_request.draft == false + runs-on: ubuntu-latest + timeout-minutes: 5 + permissions: + contents: read + pull-requests: write + steps: + # Base-branch checkout only: pull_request_target runs with elevated token; never run PR-head code here. + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + with: + ref: ${{ github.event.pull_request.base.sha }} + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: 24 + # Labels are only synced after the title lints, so an invalid title never reaches the label diff. + - run: node ./tools/ci-tools.ts lint-pr-title + env: + PR_TITLE: ${{ github.event.pull_request.title }} + - run: node ./tools/ci-tools.ts set-pr-labels + env: + PR_TITLE: ${{ github.event.pull_request.title }} + PR_NUMBER: ${{ github.event.pull_request.number }} + GITHUB_TOKEN: ${{ github.token }} diff --git a/package/gitea/source/.github/workflows/release-nightly-snapcraft.yml b/package/gitea/source/.github/workflows/release-nightly-snapcraft.yml new file mode 100644 index 00000000..f89654e4 --- /dev/null +++ b/package/gitea/source/.github/workflows/release-nightly-snapcraft.yml @@ -0,0 +1,45 @@ +name: release-nightly-snapcraft + +on: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +jobs: + build-and-publish: + runs-on: ubuntu-latest + + env: + SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }} + + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + + - name: Install snapcraft + run: sudo snap install snapcraft --classic + + - name: Authenticate snapcraft + shell: bash + run: snapcraft login --with <(printf '%s' "$SNAPCRAFT_STORE_CREDENTIALS") + + - name: Remote build + run: | + snapcraft remote-build \ + --launchpad-accept-public-upload \ + --build-for=amd64,arm64,armhf + + - name: List built snaps + run: find . -maxdepth 1 -type f -name '*.snap' -print + + - name: Upload and release snapcraft nightly build + run: | + set -euo pipefail + + for snap in ./*.snap; do + echo "Uploading $snap to edge" + snapcraft upload --release="latest/edge" "$snap" + done diff --git a/package/gitea/source/.github/workflows/release-nightly.yml b/package/gitea/source/.github/workflows/release-nightly.yml index eaebccd7..bf6f46eb 100644 --- a/package/gitea/source/.github/workflows/release-nightly.yml +++ b/package/gitea/source/.github/workflows/release-nightly.yml @@ -13,17 +13,18 @@ jobs: runs-on: namespace-profile-gitea-release-binary permissions: contents: read + id-token: write steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 # fetch all commits instead of only the last as some branches are long lived and could have many between versions # fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567 - run: git fetch --unshallow --quiet --tags --force - - uses: actions/setup-go@v6 + - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 with: go-version-file: go.mod check-latest: true - - uses: pnpm/action-setup@v5 - - uses: actions/setup-node@v6 + - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 24 cache: pnpm @@ -32,34 +33,43 @@ jobs: # xgo build - run: make release env: - TAGS: bindata sqlite sqlite_unlock_notify + TAGS: bindata + - name: Install Cosign + uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 - name: import gpg key id: import_gpg - uses: crazy-max/ghaction-import-gpg@v7 + uses: crazy-max/ghaction-import-gpg@2dc316deee8e90f13e1a351ab510b4d5bc0c82cd # v7.0.0 with: gpg_private_key: ${{ secrets.GPGSIGN_KEY }} passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }} - name: sign binaries + env: + GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} + GPG_PASSPHRASE: ${{ secrets.GPGSIGN_PASSPHRASE }} run: | for f in dist/release/*; do - echo '${{ secrets.GPGSIGN_PASSPHRASE }}' | gpg --pinentry-mode loopback --passphrase-fd 0 --batch --yes --detach-sign -u ${{ steps.import_gpg.outputs.fingerprint }} --output "$f.asc" "$f" + cosign sign-blob "$f" --bundle "$f.sigstore.json" --yes + echo "$GPG_PASSPHRASE" | gpg --pinentry-mode loopback --passphrase-fd 0 --batch --yes --detach-sign -u "$GPG_FINGERPRINT" --output "$f.asc" "$f" done - # clean branch name to get the folder name in S3 + # clean branch name to get the folder name in the object storage - name: Get cleaned branch name id: clean_name + env: + REF: ${{ github.ref }} run: | - REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//') + REF_NAME=$(echo "$REF" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//') echo "Cleaned name is ${REF_NAME}" echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT" - - name: configure aws - uses: aws-actions/configure-aws-credentials@v6 - with: - aws-region: ${{ secrets.AWS_REGION }} - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - - name: upload binaries to s3 + - name: upload binaries to cloudflare r2 + env: + AWS_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: auto + CLOUDFLARE_R2_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_R2_ACCOUNT_ID }} + CLOUDFLARE_R2_BUCKET: ${{ secrets.CLOUDFLARE_R2_BUCKET }} + BRANCH: ${{ steps.clean_name.outputs.branch }} run: | - aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress + aws s3 sync dist/release "s3://$CLOUDFLARE_R2_BUCKET/gitea/$BRANCH" --endpoint-url "https://$CLOUDFLARE_R2_ACCOUNT_ID.r2.cloudflarestorage.com" --no-progress nightly-container: runs-on: namespace-profile-gitea-release-docker @@ -67,18 +77,20 @@ jobs: contents: read packages: write # to publish to ghcr.io steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 # fetch all commits instead of only the last as some branches are long lived and could have many between versions # fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567 - run: git fetch --unshallow --quiet --tags --force - - uses: docker/setup-qemu-action@v4 - - uses: docker/setup-buildx-action@v4 + - uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0 + - uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 - name: Get cleaned branch name id: clean_name + env: + REF: ${{ github.ref }} run: | - REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//') + REF_NAME=$(echo "$REF" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//') echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT" - - uses: docker/metadata-action@v6 + - uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0 id: meta with: images: |- @@ -88,7 +100,7 @@ jobs: type=raw,value=${{ steps.clean_name.outputs.branch }} annotations: | org.opencontainers.image.authors="maintainers@gitea.io" - - uses: docker/metadata-action@v6 + - uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0 id: meta_rootless with: images: |- @@ -102,18 +114,18 @@ jobs: annotations: | org.opencontainers.image.authors="maintainers@gitea.io" - name: Login to Docker Hub - uses: docker/login-action@v4 + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GHCR using PAT - uses: docker/login-action@v4 + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: build regular docker image - uses: docker/build-push-action@v7 + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 with: context: . platforms: linux/amd64,linux/arm64,linux/riscv64 @@ -123,7 +135,7 @@ jobs: cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful cache-to: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful,mode=max - name: build rootless docker image - uses: docker/build-push-action@v7 + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 with: context: . platforms: linux/amd64,linux/arm64,linux/riscv64 diff --git a/package/gitea/source/.github/workflows/release-tag-rc.yml b/package/gitea/source/.github/workflows/release-tag-rc.yml index 248fa532..9093c9f5 100644 --- a/package/gitea/source/.github/workflows/release-tag-rc.yml +++ b/package/gitea/source/.github/workflows/release-tag-rc.yml @@ -14,17 +14,18 @@ jobs: runs-on: namespace-profile-gitea-release-binary permissions: contents: read + id-token: write steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 # fetch all commits instead of only the last as some branches are long lived and could have many between versions # fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567 - run: git fetch --unshallow --quiet --tags --force - - uses: actions/setup-go@v6 + - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 with: go-version-file: go.mod check-latest: true - - uses: pnpm/action-setup@v5 - - uses: actions/setup-node@v6 + - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 24 cache: pnpm @@ -33,43 +34,53 @@ jobs: # xgo build - run: make release env: - TAGS: bindata sqlite sqlite_unlock_notify + TAGS: bindata + - name: Install Cosign + uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 - name: import gpg key id: import_gpg - uses: crazy-max/ghaction-import-gpg@v7 + uses: crazy-max/ghaction-import-gpg@2dc316deee8e90f13e1a351ab510b4d5bc0c82cd # v7.0.0 with: gpg_private_key: ${{ secrets.GPGSIGN_KEY }} passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }} - name: sign binaries + env: + GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} + GPG_PASSPHRASE: ${{ secrets.GPGSIGN_PASSPHRASE }} run: | for f in dist/release/*; do - echo '${{ secrets.GPGSIGN_PASSPHRASE }}' | gpg --pinentry-mode loopback --passphrase-fd 0 --batch --yes --detach-sign -u ${{ steps.import_gpg.outputs.fingerprint }} --output "$f.asc" "$f" + cosign sign-blob "$f" --bundle "$f.sigstore.json" --yes + echo "$GPG_PASSPHRASE" | gpg --pinentry-mode loopback --passphrase-fd 0 --batch --yes --detach-sign -u "$GPG_FINGERPRINT" --output "$f.asc" "$f" done - # clean branch name to get the folder name in S3 + # clean branch name to get the folder name in the object storage - name: Get cleaned branch name id: clean_name + env: + REF: ${{ github.ref }} run: | - REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\/v//' -e 's/release\/v//') + REF_NAME=$(echo "$REF" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\/v//' -e 's/release\/v//') echo "Cleaned name is ${REF_NAME}" echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT" - - name: configure aws - uses: aws-actions/configure-aws-credentials@v6 - with: - aws-region: ${{ secrets.AWS_REGION }} - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - - name: upload binaries to s3 + - name: upload binaries to cloudflare r2 + env: + AWS_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: auto + CLOUDFLARE_R2_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_R2_ACCOUNT_ID }} + CLOUDFLARE_R2_BUCKET: ${{ secrets.CLOUDFLARE_R2_BUCKET }} + BRANCH: ${{ steps.clean_name.outputs.branch }} run: | - aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress + aws s3 sync dist/release "s3://$CLOUDFLARE_R2_BUCKET/gitea/$BRANCH" --endpoint-url "https://$CLOUDFLARE_R2_ACCOUNT_ID.r2.cloudflarestorage.com" --no-progress - name: Install GH CLI - uses: dev-hanz-ops/install-gh-cli-action@v0.2.1 + uses: dev-hanz-ops/install-gh-cli-action@af38ce09b1ec248aeb08eea2b16bbecea9e059f8 # v0.2.1 with: gh-cli-version: 2.39.1 - name: create github release - run: | - gh release create ${{ github.ref_name }} --title ${{ github.ref_name }} --draft --notes-from-tag dist/release/* env: GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} + TAG: ${{ github.ref_name }} + run: | + gh release create "$TAG" --title "$TAG" --draft --notes-from-tag dist/release/* container: runs-on: namespace-profile-gitea-release-docker @@ -77,13 +88,13 @@ jobs: contents: read packages: write # to publish to ghcr.io steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 # fetch all commits instead of only the last as some branches are long lived and could have many between versions # fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567 - run: git fetch --unshallow --quiet --tags --force - - uses: docker/setup-qemu-action@v4 - - uses: docker/setup-buildx-action@v4 - - uses: docker/metadata-action@v6 + - uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0 + - uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 + - uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0 id: meta with: images: |- @@ -96,7 +107,7 @@ jobs: type=semver,pattern={{version}} annotations: | org.opencontainers.image.authors="maintainers@gitea.io" - - uses: docker/metadata-action@v6 + - uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0 id: meta_rootless with: images: |- @@ -112,18 +123,18 @@ jobs: annotations: | org.opencontainers.image.authors="maintainers@gitea.io" - name: Login to Docker Hub - uses: docker/login-action@v4 + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GHCR using PAT - uses: docker/login-action@v4 + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: build regular container image - uses: docker/build-push-action@v7 + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 with: context: . platforms: linux/amd64,linux/arm64,linux/riscv64 @@ -131,7 +142,7 @@ jobs: tags: ${{ steps.meta.outputs.tags }} annotations: ${{ steps.meta.outputs.annotations }} - name: build rootless container image - uses: docker/build-push-action@v7 + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 with: context: . platforms: linux/amd64,linux/arm64,linux/riscv64 diff --git a/package/gitea/source/.github/workflows/release-tag-version.yml b/package/gitea/source/.github/workflows/release-tag-version.yml index 1e84ae17..b24c93b1 100644 --- a/package/gitea/source/.github/workflows/release-tag-version.yml +++ b/package/gitea/source/.github/workflows/release-tag-version.yml @@ -17,17 +17,18 @@ jobs: permissions: contents: read packages: write # to publish to ghcr.io + id-token: write steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 # fetch all commits instead of only the last as some branches are long lived and could have many between versions # fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567 - run: git fetch --unshallow --quiet --tags --force - - uses: actions/setup-go@v6 + - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 with: go-version-file: go.mod check-latest: true - - uses: pnpm/action-setup@v5 - - uses: actions/setup-node@v6 + - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 24 cache: pnpm @@ -36,43 +37,53 @@ jobs: # xgo build - run: make release env: - TAGS: bindata sqlite sqlite_unlock_notify + TAGS: bindata + - name: Install Cosign + uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 - name: import gpg key id: import_gpg - uses: crazy-max/ghaction-import-gpg@v7 + uses: crazy-max/ghaction-import-gpg@2dc316deee8e90f13e1a351ab510b4d5bc0c82cd # v7.0.0 with: gpg_private_key: ${{ secrets.GPGSIGN_KEY }} passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }} - name: sign binaries + env: + GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} + GPG_PASSPHRASE: ${{ secrets.GPGSIGN_PASSPHRASE }} run: | for f in dist/release/*; do - echo '${{ secrets.GPGSIGN_PASSPHRASE }}' | gpg --pinentry-mode loopback --passphrase-fd 0 --batch --yes --detach-sign -u ${{ steps.import_gpg.outputs.fingerprint }} --output "$f.asc" "$f" + cosign sign-blob "$f" --bundle "$f.sigstore.json" --yes + echo "$GPG_PASSPHRASE" | gpg --pinentry-mode loopback --passphrase-fd 0 --batch --yes --detach-sign -u "$GPG_FINGERPRINT" --output "$f.asc" "$f" done - # clean branch name to get the folder name in S3 + # clean branch name to get the folder name in the object storage - name: Get cleaned branch name id: clean_name + env: + REF: ${{ github.ref }} run: | - REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\/v//' -e 's/release\/v//') + REF_NAME=$(echo "$REF" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\/v//' -e 's/release\/v//') echo "Cleaned name is ${REF_NAME}" echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT" - - name: configure aws - uses: aws-actions/configure-aws-credentials@v6 - with: - aws-region: ${{ secrets.AWS_REGION }} - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - - name: upload binaries to s3 + - name: upload binaries to cloudflare r2 + env: + AWS_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: auto + CLOUDFLARE_R2_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_R2_ACCOUNT_ID }} + CLOUDFLARE_R2_BUCKET: ${{ secrets.CLOUDFLARE_R2_BUCKET }} + BRANCH: ${{ steps.clean_name.outputs.branch }} run: | - aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress + aws s3 sync dist/release "s3://$CLOUDFLARE_R2_BUCKET/gitea/$BRANCH" --endpoint-url "https://$CLOUDFLARE_R2_ACCOUNT_ID.r2.cloudflarestorage.com" --no-progress - name: Install GH CLI - uses: dev-hanz-ops/install-gh-cli-action@v0.2.1 + uses: dev-hanz-ops/install-gh-cli-action@af38ce09b1ec248aeb08eea2b16bbecea9e059f8 # v0.2.1 with: gh-cli-version: 2.39.1 - name: create github release - run: | - gh release create ${{ github.ref_name }} --title ${{ github.ref_name }} --notes-from-tag dist/release/* env: GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} + TAG: ${{ github.ref_name }} + run: | + gh release create "$TAG" --title "$TAG" --notes-from-tag dist/release/* container: runs-on: namespace-profile-gitea-release-docker @@ -80,13 +91,13 @@ jobs: contents: read packages: write # to publish to ghcr.io steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 # fetch all commits instead of only the last as some branches are long lived and could have many between versions # fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567 - run: git fetch --unshallow --quiet --tags --force - - uses: docker/setup-qemu-action@v4 - - uses: docker/setup-buildx-action@v4 - - uses: docker/metadata-action@v6 + - uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0 + - uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 + - uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0 id: meta with: images: |- @@ -103,7 +114,7 @@ jobs: type=semver,pattern={{major}}.{{minor}} annotations: | org.opencontainers.image.authors="maintainers@gitea.io" - - uses: docker/metadata-action@v6 + - uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0 id: meta_rootless with: images: |- @@ -124,18 +135,18 @@ jobs: annotations: | org.opencontainers.image.authors="maintainers@gitea.io" - name: Login to Docker Hub - uses: docker/login-action@v4 + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GHCR using PAT - uses: docker/login-action@v4 + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: build regular container image - uses: docker/build-push-action@v7 + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 with: context: . platforms: linux/amd64,linux/arm64,linux/riscv64 @@ -143,7 +154,7 @@ jobs: tags: ${{ steps.meta.outputs.tags }} annotations: ${{ steps.meta.outputs.annotations }} - name: build rootless container image - uses: docker/build-push-action@v7 + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 with: context: . platforms: linux/amd64,linux/arm64,linux/riscv64 diff --git a/package/gitea/source/.gitignore b/package/gitea/source/.gitignore index 019ee94c..76a75786 100644 --- a/package/gitea/source/.gitignore +++ b/package/gitea/source/.gitignore @@ -55,10 +55,7 @@ cpu.out *.log.*.gz /gitea -/gitea-e2e -/gitea-vet /debug -/integrations.test /bin /dist diff --git a/package/gitea/source/.golangci.yml b/package/gitea/source/.golangci.yml index afd91d65..519b74f7 100644 --- a/package/gitea/source/.golangci.yml +++ b/package/gitea/source/.golangci.yml @@ -43,7 +43,7 @@ linters: desc: use os or io instead - pkg: golang.org/x/exp desc: it's experimental and unreliable - - pkg: code.gitea.io/gitea/modules/git/internal + - pkg: gitea.dev/modules/git/internal 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 @@ -51,6 +51,14 @@ linters: desc: do not use the go-chi cache package, use gitea's cache system - pkg: github.com/pkg/errors desc: use builtin errors package instead + migrations: + files: + - '**/models/migrations/**/*.go' + deny: + - pkg: gitea.dev/models$ + desc: migrations must not depend on the models package + - pkg: gitea.dev/modules/structs + desc: migrations must not depend on modules/structs (API structures change over time) nolintlint: allow-unused: false require-explanation: true @@ -99,6 +107,7 @@ linters: - -QF1008 testifylint: disable: + - empty - go-require - require-error usetesting: @@ -158,9 +167,16 @@ issues: max-same-issues: 0 formatters: enable: - - gofmt + - gci - gofumpt settings: + gci: + custom-order: true + sections: + - standard + - prefix(gitea.dev) + - blank + - default gofumpt: extra-rules: true exclusions: @@ -170,9 +186,6 @@ formatters: - .venv - public - web_src - - third_party$ - - builtin$ - - examples$ run: timeout: 10m diff --git a/package/gitea/source/.npmrc b/package/gitea/source/.npmrc deleted file mode 100644 index 790a49a6..00000000 --- a/package/gitea/source/.npmrc +++ /dev/null @@ -1,7 +0,0 @@ -audit=false -fund=false -update-notifier=false -save-exact=true -auto-install-peers=true -dedupe-peer-dependents=false -enable-pre-post-scripts=true diff --git a/package/gitea/source/.shellcheckrc b/package/gitea/source/.shellcheckrc new file mode 100644 index 00000000..a012fba9 --- /dev/null +++ b/package/gitea/source/.shellcheckrc @@ -0,0 +1 @@ +disable=SC1091,SC2001,SC2002,SC2016,SC2028,SC2046,SC2124,SC2128,SC2129,SC2154,SC2155,SC2164,SC2181,SC2207 diff --git a/package/gitea/source/CHANGELOG.md b/package/gitea/source/CHANGELOG.md index c7ab42f6..10de011d 100644 --- a/package/gitea/source/CHANGELOG.md +++ b/package/gitea/source/CHANGELOG.md @@ -4,6 +4,504 @@ 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.27.3](https://github.com/go-gitea/gitea/releases/tag/v1.27.3) - 2026-08-29 + +* SECURITY + * fix(packages): restrict/limited/token-scope access (#39041, #39043, #39044, #39047, #39046) (#39058) + * fix(attachments): enforce owning repository path (#39048) (#39077) + * fix(markup): enforce same-repository issue access (#39045) (#39054) + * fix(actions): verify raw artifact signatures first (#39049) (#39053) + * fix(api): hide limited users from restricted viewers (#39004) (#39039) + * fix(repo): limit gitignore template selections (#39027) (#39040) + * fix(migrations): cancel GitLab version probes (#39023) (#39035) + * fix(packages): limit Swift package manifests (#39025) (#39032) + * fix(migrations): bound OneDev version responses (#39024) (#39033) + * fix(packages): limit Maven checksum uploads (#39028) (#39031) + * fix(packages): bound Alpine metadata entries (#39026) (#39029) + * fix(actions): enforce fork pull request trust boundaries (#39005) (#39018) + * fix(git): restrict hook permissions (#39008) (#39016) + * fix(api): enforce repository creation token authorization (#39007) (#39014) + * fix(api): enforce public-only scope for compare heads (#39006) (#39013) + * fix(repo): hide repositories of hidden owners (#39009) (#39012) + * fix: avoid enumerating every public repository in issue search (#38992) (#39000) + * refactor: private endpoints (#38964) (#38965) +* ENHANCEMENTS + * enhance: add permalinks to pull request reviews (#38849) (#39036) +* BUGFIXES + * fix: add missing query parameters on runner list page (#39163) + * fix(actions): keep step-level continue-on-error expressions unevaluated (#39141) (#39148) + * fix(packages): preserve SemVer prerelease identifiers in Swift Registry (#39156) (#39158) + * fix(repo): prevent MarkAsBrokenEmpty when repository is being migrated (#39091) (#39092) + * fix(asymkey): do not verify OpenPGP signatures with an SSH instance key (#39073) (#39086) + * fix(pull): keep the merged state in sync with git (#39062) (#39118) + * fix(pull): name the head repository in default compare links (#39075) (#39079) + * fix(git): parse co-author trailers that are not RFC 5322 addresses (#39076) (#39081) + * fix(actions): show "Complete job" logs when the last step is skipped (#38939) (#39003) + * fix(actions): Fix how jobs in matrixes are grouped (#38980) (#38998) + * fix: resolve YAML anchors and aliases in Actions workflows (#38984) (#38996) + * fix: honor environment variables during install (#38974) (#38976) + * fix: grant limited-org unit read access to authenticated non-members (#38871) (#38963) + * fix: allow anonymous theme switching when REQUIRE_SIGNIN_VIEW is set (#38956) (#38961) + * fix(actions): drop wrapper span around the action status icon (#38957) (#38959) + * fix(issues): sort scoped labels by exclusive order in dropdowns (#38893) (#38954) + * fix(indexer): correct bleve indexer token filters (#38853) (#38951) + * fix: make "login_name" field optional for API edit user (#38917) (#38945) + * fix(actions): reject non-mapping matrix include/exclude (#38933) + * fix(ui): respect FEED_PAGING_NUM on the dashboard feed (#38935) (#38936) +* MISC + * chore: repo compare link (#39088) (#39119) + * ci: remove AWS S3 uploads from release workflows (#38928) (#38929) + * chore: Pre-register a builtin OAuth2 application for the official Gitea mobile app (#38880) (#38922) + +## [1.27.2](https://github.com/go-gitea/gitea/releases/tag/v1.27.2) - 2026-08-14 + +* SECURITY + * Fix: update collaborator access mode and httpsign (#38894, #38862) (#38895) + * Refactor: external render (#38885) (#38898) + * Fix(actions): resolve pull_request_target reusable workflows at the base commit (#38886) (#38897) + * Refactor: markup render (#38864) (#38869) + * Fix(deps): update dependency mermaid to v11.16.1 (#38816) + * Fix(auth): set WebAuthn user verification per request (#38805) (#38810) + * Fix: render highlight language (#38793) (#38795) + +* ENHANCEMENTS + * enhance: add missing npm package metadata properties (#38826) (#38831) + +* BUGFIXES + * fix(actions): keep github.event.inputs as strings for workflow_dispatch (#38899) (#38908) + * fix(actions): let a rerun of selected jobs read the previous attempt's artifacts (#38857) (#38901) + * fix(lfs): accept successful transfer responses (#38866) (#38875) + * fix(packages): ignore nested Package.swift (#38788) (#38836) + * fix: drop newline-bearing member names in arch ParsePackage (#38102) (#38830) + * fix(storage): fix Azure Blob dump failing with file does not exist (#38814) (#38828) + * fix(migration): migration deletion returned json redirection (#38796) (#38825) + * fix(ui): change underlines to default browser style (#38819) (#38823) + * fix(actions): allow cancelling runs without running jobs (#35842) (#38812) + * fix(actions): evaluate each `${{ }}` part on its own (#38754) (#38797) + * fix(actions): write an action task report in one transaction (#38792) (#38794) + * fix: markup link (#38764) (#38765) + * fix: set a minio part size when the content size is unknown (#38753) (#38755) + * fix: bad path escape in subpath archive download (#38749) (#38750) + * fix: remove the pull merge box from UI when the refreshed page doesn't contain it (#38742) (#38744) + * fix(markdown): fix double strikethough on code (#38707) (#38729) + * fix(lfs): failed upload deletes a concurrent upload's meta object (#38693) (#38722) + * fix: correct full url when using sub-path (#38712) (#38716) + * fix: avoid markup render panic (#38698) (#38703) + * fix(ui): too many participants shown in commit avatar stacks (#38689) (#38700) + * fix: support HEAD requests on Alpine registry APKINDEX.tar.gz (#38686) (#38688) + * fix(migrations): use all configured GitHub tokens (#38841) (#38846) + +## [1.27.1](https://github.com/go-gitea/gitea/releases/tag/v1.27.1) - 2026-07-27 + +* SECURITY + * fix(oauth2): enforce mandatory 2FA policy on OAuth2 authorize/grant endpoints (#38591) (#38606) + +* API + * fix(api): align Swagger schemas for UserSettings and TopicListResponse (#38590) (#38592) + +* ENHANCEMENTS + * enhance: improve diff contrast in light and dark themes (#37477) (#38574) + +* BUGFIXES + * fix: skip OIDC end-session after password login for OAuth2 users (#38439) (#38666) + * fix: make Actions log parser support multiple line message encoding (#38659) (#38664) + * fix(actions): use base branch ref for pull_request_target context (#38636) (#38657) + * fix(actions): skip already-approved runs in `ApproveRuns` (#38653) (#38654) + * fix: orgmode render include path (#38642) (#38645) + * fix(actions): cancel tasks immediately when the runner stopped reporting (#38616) (#38644) + * fix(issues): fix label bulk-load key and reduce log noise in LoadLabel (#38632) (#38643) + * fix(actions): improve runner list status sorting, labels and task job links (#38586) (#38633) + * fix(actions): correctness and hardening fixes (#38518) (#38631) + * fix(repo): prevent double-write redirect collisions on dependency errors, fix ui (#38627) (#38628) + * fix: delete repo-scoped rows of seven more tables when deleting a repository (#38534) (#38618) + * fix(webhook): remove slack channel name check (#38608) (#38612) + * fix: download dropdown menu clipped on the branches page (#38604) (#38609) + * fix(project): prevent database mutations on invalid MoveIssues payload (#38600) (#38602) + * fix(actions): make SingleWorkflow.Marshal round-trip multi-line run blocks (stop silent job stranding) (#38520) (#38599) + * fix(file-tree): handle submodule links and missing view container (#38033) (#38589) + * fix(actions): fail unexpandable reusable workflow callers and decouple the job emitter's cross-run processing (#38565) (#38587) + * fix: keep serving valid ACME cert when renewal fails at startup (#38554) (#38583) + * fix: branch protection user list (#38570) (#38584) + * fix(pulls): respect diff.orderFile in diff file tree (#38566) (#38578) + * fix(issue): make issue action (issue list batch operation) elements have correct attributes (#38575) (#38580) + * fix(actions): support `matrix` when evaluating workflow `if` expression (#38474) (#38557) + * fix(actions): align status icon span for Safari rendering (#38558) (#38562) + * fix: revert git clone http redirection forbidden (#38530) (#38545) + * fix: clean up orphaned user-keyed tables in deleteUser (#38511) (#38514) + * fix(actions): coerce workflow_dispatch boolean inputs to native types (#38472) (#38521) + * fix: make the merge box button red if some checks fail (#38508) (#38516) + * fix(pull): sign the commit when updating a branch by merge (#38441) (#38499) + * fix: make commit message merge correctly (#38490) (#38502) + * fix(actions): explain why a blocked or waiting job has not started (#38476) (#38498) + * fix(actions): make `cancelled()` work in job `if` evaluation (#38495) (#38497) + * fix(actions): show retention info on hover for expired artifacts (#38477) (#38493) + * fix(actions): group reusable-workflow matrix legs in the workflow graph (#38475) (#38492) + * fix: full file highlighting for git diff with CR char (#38484) (#38491) + * fix(packages): serve noarch Alpine index for any requested architecture (#38479) (#38486) + * fix: 500 error when updating user visibility (#38480) (#38483) + * fix(actions): make job list item fully clickable (#38462) (#38471) + * fix: mail template for push event (#38467) (#38468) + * fix: make "test push webhook" always work (#38425) (#38455) + * fix(actions): prevent bulk actions from affecting all runners (#38453) (#38457) + * fix(org): align follow button and wrap description (#38448) (#38454) + * fix(actions): populate `github.event` for scheduled runs (#38446) (#38452) + +* MISC + * refactor: git patch apply (#38637) (#38638) + +## [1.27.0](https://github.com/go-gitea/gitea/releases/tag/v1.27.0) - 2026-07-13 + +* BREAKING + * Feat(actions)!: improve support for reusable workflows (#37478) + * Use Content-Security-Policy: script nonce (#37232) + +* SECURITY + * Fix: various security fixes (#38406) (#38426) + * Fix(security): harden access checks and migration validation (#38324) (#38400) + * Fix: enforce public-only token scope and harden push options / locale parsing (#38323) (#38399) + * Fix(pull): re-evaluate review official flag on target branch change (#38319) (#38402) + * Fix(api): stop leaking private repo metadata after access revocation (#38321) (#38390) + * Fix(lfs): require proof of possession for cross-repo objects (#38322) (#38389) + * Fix(mirror): disable HTTP redirects on pull mirror sync (#38320) (#38367) + * Fix: golang html template url escaping (#38363) (#38369) + * Fix(release): validate web attachment renames against allowed types (#38314) (#38328) + * Fix(release): gate draft release attachments on web download endpoints (#38318) (#38325) + * Fix(deps): update module github.com/go-git/go-git/v5 to v5.19.1 [security] (#37786) + * Fix(oauth): restrict introspection to the token's client (#38042) + * Fix(api): don't expose private org membership via public_members (#38145) + * Fix(actions): deny fork-PR cross-repo access via collaborative owner (#38214) + * Fix(migrations): prevent path traversal in repository restore (#38215) + +* FEATURES + * Feat(actions): add workflow status badge modal (#38196) + * Feat(actions): support owner-level and global scoped workflows (#38154) + * Feat(api): support ref suffixes in compare (#38148) + * Feat(actions): implement `jobs..continue-on-error` (#38100) + * Feat(actions): show run status on browser tab favicon (#38071) + * Feat(api): add token introspection and self-deletion endpoint (#37995) + * Feat(api): add q parameter to list branches API for server-side filtering (#37982) + * Feat(repo): split repository creation limit into user and org scopes (#37872) + * Feat(actions): bulk delete, disable and enable runners in admin UI (#37869) + * Feat(actions): List workflows that were executed once but got removed from the default branch (#37835) + * Feat(org): add team visibility so org members can discover teams (#37680) + * Feat: add raw diff/patch endpoint for repository comparisons (#37632) + * Feat: Add avatar stacks (#37594) + * Feat(actions): add job summaries (GITHUB_STEP_SUMMARY) (#37500) + * Feat(web): Add Jupyter Notebook (.ipynb) Rendering Support (#37433) + * Support for Custom URI Schemes in OAuth2 Redirect URIs (#37356) + * Feat(orgs): Add search bar for organization members tab page (#37347) + * Feat(api): Add assignees APIs (#37330) + * Feat(api): Add GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs (#37196) + * Serve OpenAPI 3.0 spec at /openapi.v1.json (#37038) + * Add project column picker to issue and pull request sidebar (#37037) + * Allow multiple projects per issue and pull requests (#36784) + * Feat(ui): add "follow rename" to file commit history list (#34994) + * Feat(ssh): auto generate additional ssh keys (#33974) + +* ENHANCEMENTS + * Enhance(actions): only create filtered-out workflow commit status for required contexts (#38371) (#38385) + * Enhance: allow builtin default git config options to be overridden (#38172) + * Enhance: allow MathML core elements (#38034) + * Enhance(markup): improve issue title rendering (#37908) + * Enhance(actions): set descriptive browser tab title on run view (#37870) + * Enhance: Migrate remaining gopkg.in/yaml.v3 usages to go.yaml.in/yaml/v4 (#37866) + * Enhance(actions): show workflow name from YAML instead of filename (#37833) + * Feat(actions): add before/after to PR synchronize event payload (#37827) + * Enhance(actions): add branch filters to run list (#37826) + * Enhance(actions): Make Summary UI more beautiful with more infos (#37824) + * Feat: add copy button to action step header, improve other copy buttons (#37744) + * Fix(icon): use repo-forked icon to display forks count (#37731) + * Feat(api): add sort and order query parameters to job list endpoints (#37672) + * Feat(api): add last_sync to repository API (#37566) + * Enhance: Adjust Workflow Graph styling (#37497) + * Improve code editor text selection and clean up lint enablement (#37474) + * Add mirror auth updates to repo edit API and settings (#37468) + * Replace `olivere/elastic` with REST API client, add OpenSearch support (#37411) + * Feat: Add default PR branch update style setting (#37410) + * Fix inconsistent disabled styling on logged-out repo header buttons (#37406) + * Allow fast-forward-only merge when signed commits are required (#37335) + * Enhance styling in actions page (#37323) + * Fix: improve actions status icons and texts (#37206) + * Make Markdown fenced code block work with more syntaxes (#37154) + * Fix: Sort action run jobs by JobID and Name with matrix examples (#37046) + * Add API endpoint to reply to pull request review comments (#36683) + +* PERFORMANCE + * Perf(actions): debounce runner heartbeat writes and throttle task picks (#38281) (#38368) + * Perf(web): sort the action_run query by a repo-scoped index when possible (#38155) + * Perf: Various performance regression fixes (#38078) + * Perf: extend action `c_u` index to include `created_unix` for faster dashboard feeds (#38076) + * Batch-load related data in actions run, job, and task API endpoints (#37032) + +* BUGFIXES + * Fix(util): reject invalid characters between time-estimate units (#38416) (#38423) + * Fix: represent a deleted assignee team as a Ghost team (#38413) (#38419) + * Fix(turnstile): route CAPTCHA verification through the configured proxy (#38412) (#38420) + * Fix: refresh pull request merge box when the commit status is pending (#38410) (#38411) + * Fix: actions task state concurrent update (#38405) (#38409) + * Fix(actions): keep workflow run trailing on one row with long branch names (#38382) (#38403) + * Fix(web): use locale-aware date formatting for contribution calendar tooltips (#38398) (#38401) + * Fix: co-author detection (#38392) (#38397) + * Fix: incorrect co-author detection on commit page (#38386) (#38387) + * Fix(ui): restore commits table column widths (#38379) (#38383) + * Fix: minio init check (#38355) (#38361) + * Fix: org project view assignee list (#38357) (#38360) + * Fix(actions): release claimed task if context is cancelled during `FetchTask` (#38343) (#38347) + * Fix(actions): make runner list pagination order deterministic (#38313) (#38327) + * Fix: Improve since/until when counting commits for X-Total-Count (#38243) (#38304) + * Fix(actions): prevent chevron overlap with log text when timestamps are enabled (#38227) (#38307) + * Fix(workflows): branch protection status checks fail when workflow uses on: paths filter (#38237) (#38302) + * Fix(oauth2): persist linkAccountData during auto-link 2FA flow (#38274) (#38295) + * Fix(actions): allow Actions bot to push to protected branches (#38284) (#38293) + * Fix(actions): include all aggregable run statuses in status filter (#38280) (#38287) + * Fix(archiver): use serializable repo-archive queue payload (#38273) (#38283) + * Fix: update npm dependencies, fix misc issues (#38257) + * Fix(api): respect since/until when counting commits for X-Total-Count (#38204) + * Fix: codemirror regressions (#38248) + * Fix(api): support HEAD requests on all API GET endpoints (#38245) + * Fix(actions): Cleanup workflow status badge code (#38241) + * Fix(web): Correctly align the "disabled" label on larger workflow names (#38240) + * Fix(actions): don't swallow HTML entities into linkified URLs (#38239) + * Fix(packages): accept npm "repository" and "bin" in string form (#38236) + * Fix(actions): fix 500 error when canceling a canceling task (#38223) + * Fix(deps): update module golang.org/x/image to v0.43.0 [security] (#38219) + * Fix(mssql): convert legacy DATETIME columns to DATETIME2 (#38216) + * Fix(api): deny private org member enumeration via /members (#38213) + * Fix(actions): ensure all waiting jobs get runners in large workflows (#38200) + * Fix(deps): update go dependencies (#38194) + * Fix(deps): update npm dependencies (#38193) + * Fix(cli): default must-change-password to false for bot users (#38175) + * Fix(actions): show run index in run view and fix summary graph height (#38165) + * Fix: csp (#38162) + * Fix(deps): update npm dependencies (#38123) + * Fix(mssql): expand legacy issue and comment long-text columns (#38120) + * Fix(packages): validate debian distribution and component names (#38116) + * Fix(packages): validate module version in goproxy ParsePackage (#38104) + * Fix(deps): update dependency esbuild to v0.28.1 [security] (#38097) + * Fix: git push hook post receive (#38089) + * Fix(ui): prevent commit status popup overflowing its row (#38081) + * Fix: validate gem name in rubygems parseMetadataFile (#38061) + * Fix: commit display name (#38057) + * Fix: csp regressions (#38047) + * Fix: api error message (#38031) + * Fix(deps): update npm dependencies (#38029) + * Fix: pgsql lint (#38022) + * Fix(indexer): fix assignee filters in issue search (#38021) + * Fix: various dropdown problems (#38020) + * Fix: refactor git error handling and make archive streaming handle non-existing commit id (#38007) + * Fix: raise git required version to 2.13 (#37996) + * Fix: remove "no-transfrom" from the cache-control header (#37985) + * Fix(deps): update module github.com/google/go-github/v87 to v88 (#37971) + * Fix: use committer time where ever possible as default (#37969) + * Fix(deps): update npm dependencies, remove nolyfill (#37968) + * Fix(deps): update go dependencies (#37967) + * Fix(pull): preserve squash message trailers and additional commit messages (#37954) + * Fix(deps): update module golang.org/x/image to v0.41.0 [security] (#37904) + * Fix: support ##[command] log prefix in action run UI (#37882) + * Fix(deps): update module github.com/google/go-github/v86 to v87 (#37845) + * Fix(deps): update npm dependencies (#37844) + * Fix(deps): update go dependencies (#37841) + * Fix(frontend): resolve Vite assets by manifest source path (#37836) + * Fix(locales): Replace hardcoded strings (#37788) + * Fix(packages): render markdown links relative to linked repo (#37676) + * Fix: persist mirror repository metadata (#37519) + * Fix cmd tests by mocking builtin paths (#37369) + * Add `form-fetch-action` to some forms, fix "fetch action" resp bug (#37305) + * Feat: execute post run cleanup when workflow is cancelled (#37275) + * Fix `relative-time` error and improve global error handler (#37241) + * Refactor flash message and remove SanitizeHTML template func (#37179) + +* TESTING + * Test(e2e): fix race in pdf file render test (#38380) (#38381) + * Test: compare key file contents instead of `FileInfo` in `TestInitKeys` (#38330) (#38331) + * Test: speed up two tests (#37905) + * Test: Fix random failure test (#37887) + * Test: fix flaky `issue-comment` close test (#37880) + * Test: enable WAL for sqlite integration tests (#37861) + * Test: fix flaky `TestResourceIndex` and reduce its runtime (#37847) + * Test: run `TestAPIRepoMigrate` offline via a local clone source (#37817) + * Ci: shard tests and reduce redundant work (#37618) + * Test(e2e): run playwright via container (#37300) + * Remove external service dependencies in migration tests (#36866) + +* BUILD + * Fix(actions): authenticate snapcraft before nightly remote build (#38252) + * Ci: cap Elasticsearch heap in db-tests (#37816) + * Build(snap): publish nightly version to snapcraft via actions (#37814) + * Ci: split pgsql shards into plain jobs, dedupe setup actions (#37802) + * Ci: narrow files-changed frontend filter (#37749) + * Ci: add `zizmor` to `lint-actions` (#37720) + * Chore: clean up "contrib" dir (#37690) + * Fix: snap build (main branch) (#37685) + * Ci: Also lint json5 files (#37659) + * Feat(editor): broaden language detection in web code editor (#37619) + * Build: update pnpm to v11 (#37591) + * Refactor(deps): migrate from `nektos/act` fork to `gitea/runner` (#37557) + * Refactor: lint bare `fill`/`stroke` colors, add vars for git graph color series (#37543) + * Update go js py dependencies (#37525) + * Ci: lint PR titles with commitlint (#37498) + * Chore: upgrade Go version in devcontainer image to 1.26 (#37374) + * Update GitHub Actions to latest major versions (#37313) + * Update go js dependencies (#37312) + * Fail vite build on rolldown warnings via NODE_ENV=test (#37270) + * Remove htmx (#37224) + * Replace custom Go formatter with `golangci-lint fmt` (#37194) + * Refactor htmx and fetch-action related code (#37186) + * Integrate renovate bot for all dependency updates (#37050) + * Build(sign): move to sigstore (#38250) + +* DOCS + * Docs: update changelog for 1.26.3 & 1.26.4 (#38178) + * Docs: fix duplicated word in foreachref doc comment (#38161) + * Docs: Clarify criteria for becoming a merger (#38113) + * Docs: Publish TOC Election Result 2026 (#38111) + * Docs: mark openapi3 as autogenerated in attributes (#37963) + * Docs: add development setup guide (#37960) + +* MISC + * Revert(sign): restore gpg (#38251) + * Refactor: replace legacy `delete-button` with `link-action` (#38143) + * Refactor(actions): read runner capabilities from proto field (#38068) + * Refactor(api): clarify APIError message usage and fix legacy lint error (#38012) + * Refactor: Use db.Get[] instead of db.GetEngine(ctx).Get(bean) to avoid zero value fetching wrong database record (#37977) + * Fix(deps): update go dependencies (#37851) + * Ci: Fix sync PR labels from the conventional-commit title (#37784) (#37825) + * Ci: tweak `files-changed`, add `free-disk-space` (#37819) + * Fix(deps): update module golang.org/x/crypto to v0.52.0 [security] (#37806) + * Test(e2e): add comment, release, star, PR and fork tests (#37800) + * Chore: simplify issue and pull request templates (#37799) + * Chore: Update giteabot to fix failure when backport (#37789) + * Fix(api): handle partial failures in push mirror synchronization gracefully (#37782) + * Fix(deps): update module gitlab.com/gitlab-org/api/client-go/v2 to v2.26.0 (#37771) + * Ci: split giteabot workflow (#37770) + * Fix(deps): update npm dependencies (#37768) + * Refactor(waitgroup): replace Add/Done goroutines with WaitGroup.Go (#37764) + * Fix(deps): update module google.golang.org/grpc to v1.81.1 (#37762) + * Ci: fix cache-related issues (#37761) + * Chore: fix tests (#37760) + * Fix(deps): update module github.com/google/go-github/v85 to v86 (#37754) + * Fix(deps): update npm dependencies (#37753) + * Fix(deps): update go dependencies (#37752) + * Chore(deps): update action dependencies (#37751) + * Fix(markup): wrap indented code blocks for the code-copy button (#37748) + * Chore(db): introduce db.Session and db.EngineMigration interfaces (#37746) + * Feat(web): also display PR counts in repo list (#37739) + * Refactor(glob): use strings.Builder for regexp compilation (#37730) + * Chore(doctor): remove four obsolete doctor check implementations (#37728) + * Refactor(org): simplify owner-team org repo creation logic (#37727) + * Refactor: move `workflowpattern` into `modules/actions` (#37717) + * Chore: clean up tests (#37715) + * Style: misc UI fixes (#37691) + * Ci: add shellcheck linter (#37682) + * Fix: catch and fix more lint problems (#37674) + * Fix(deps): update dependency mermaid to v11.15.0 [security], add e2e test (#37662) + * Fix(deps): update npm dependencies (#37647) + * Ci(renovate): update Go import paths on major bumps (#37641) + * Fix(deps): update go dependencies (major) (#37639) + * Chore(deps): update action dependencies (major) (#37638) + * Fix(deps): update module code.gitea.io/sdk/gitea to v0.25.0 (#37637) + * Fix(deps): update npm dependencies (#37636) + * Refactor(log): replace log.Critical with log.Error (#37624) + * Build(deps): bump fast-uri from 3.1.0 to 3.1.2 (#37616) + * Feat(oauth): Support AWS Cognito OAuth2 provider (#37607) + * Chore(deps): update action dependencies (#37603) + * Ci: allow `chore` type in PR title lint (#37575) + * Refactor: only reset a database table when the table's data was changed (#37573) + * Ci: increase renovate frequency and fix RENOVATE_ALLOWED_POST_UPGRADE_COMMANDS (#37565) + * Refactor: use modernc sqlite driver as default (#37562) + * Docs: fix 4 typos in CHANGELOG.md (#37549) + * Fix(deps): update go dependencies (#37541) + * Chore(deps): update action dependencies (#37540) + * Refactor pull request view (6) (#37522) + * Fix: redirect early CLI console logger to stderr (#37507) + * Refactor "flex-list" to "flex-divided-list" (#37505) + * Refactor compare diff/pull page (1) (#37481) + * Refactor pull request view (4) (#37451) + * Update 1.26.1 changelog in main (#37442) + * Refactor: use named `Permission` field in `Repository` struct instead of anonymous embedding (#37441) + * Refactor: serve site manifest via `/assets/site-manifest.json` endpoint (#37405) + * Remove IsValidExternalURL/IsAPIURL and use IsValidURL at call sites (#37364) + * Update `Block a user` form (#37359) + * Move review request functions to a standalone file (#37358) + * Feat(security): set X-Content-Type-Options: nosniff by default (#37354) + * Enable strict TypeScript, add `errorMessage` helper (#37292) + * Refactor frontend `tw-justify-between` layouts to `flex-left-right` (#37291) + * Update Nix flake (#37284) + * Fix Repository transferring page (#37277) + * Remove `SubmitEvent` polyfill (#37276) + * Remove dead code identified by `deadcode` tool (#37271) + * Upgrade go-git to v5.18.0 (#37268) + * Don't add useless labels which will bother changelog generation (#37267) + * Move heatmap to first-party code (#37262) + * Tests/integration: simplify code (#37249) + * Add pagination and search box to org teams list (#37245) + * Remove error returns from crypto random helpers and callers (#37240) + * Add `ExternalIDClaim` option for OAuth2 OIDC auth source (#37229) + * Refactor: simplify ParseCatFileTreeLine and catBatchParseTreeEntries (#37210) + * Refactor "htmx" to "fetch action" (#37208) + * Update go js py dependencies (#37204) + * Add comment for the design of "user activity time" (#37195) + * Remove outdated RunUser logic (#37180) + * Models/fixtures: add "DO NOT add more test data" comment to all yml fixture files (#37150) + * Update javascript dependencies (#37142) + * Update go dependencies (#37141) + * Frontport changelog of v1.26.0-rc0 (#37138) + * Introduce `ActionRunAttempt` to represent each execution of a run (#37119) + * Workflow Artifact Info Hover (#37100) + * Extend issue context popup beyond markdown content (#36908) + * Add bulk repository deletion for organizations (#36763) + * Feat: Add bypass allowlist for branch protection (#36514) + +## [1.26.4](https://github.com/go-gitea/gitea/releases/tag/1.26.4) - 2026-06-21 + +* SECURITY + * fix(auth): do not auto-reactivate disabled users on OAuth2 callback (#38009) (#38183) + +* BUGFIXES + * fix: walk git log context error handling (#38182) (#38185) + +## [1.26.3](https://github.com/go-gitea/gitea/releases/tag/1.26.3) - 2026-06-18 + +* BREAKING + * fix(actions)!: require merged PR to bypass fork PR approval gate (#38010) (#38041) + +* SECURITY + * fix(hostmatcher): patch incorrect private list (#38170) (#38173) + * fix: Various security fixes (#38103) (#38151) + * fix: Various sec fixes (#38108) (#38147) + * fix: allow git clone of private repos with anonymous code access (#38074) (#38146) + * fix(auth): ignore stale OIDC external login links to organizations (#37875) (#38141) + * fix(hostmatcher): block reserved IP ranges from external/private filters (#38039) (#38059) + * fix(lfs): require Code-unit access for cross-repo LFS object reuse (#38006) (#38050) + * fix(lfs): reject unknown SSH LFS sub-verbs to prevent auth bypass (#38008) (#38015) + * fix: bound CODEOWNERS regex match time (#38011) (#38025) + * fix: bound debian ParseControlFile to a single control stanza (#38044) (#38055) + * fix(deps): update module golang.org/x/net to v0.55.0 [security] (#37813) (#37829) + +* API + * feat(api): add Link header in ListForks (#38052) (#38063) + +* BUGFIXES + * fix: Fix the panic when ssh remote lfs endpoint parsing failure (#38026) (#38158) + * fix(api): nil pointer panic when filtering tracked times by a non-existent user (#38112) (#38115) + * fix: keep literal "false" value displayed in workflow_dispatch choice dropdowns (#38080) (#38096) + * fix: parse HEAD ref (#38119) + * fix: git cmd (#38084) (#38087) + * fix(releases): generate notes for initial tag (#37697) (#37986) + * fix(actions): return 404 when job log blob is missing (#38003) (#38004) + * fix(actions): exclude `workflow_call` from workflow trigger detection (#37894) (#37899) + * fix(actions): keep action run title clickable when commit subject is a URL (#37867) (#37898) + * fix(actions): reject workflow_dispatch for workflows without that trigger (#37660) (#37895) + * fix(actions): ack re-sent `UpdateLog` finalize idempotently (#37885) (#37892) + * fix: http content file render (#37850) (#37856) + * fix(issues): clear stale ReviewTypeRequest when submitting pending review (#37809) (#37815) + * fix: Fix issue target branch selection for non-collaborators (#36916) (#38164) + +* BUILD + * fix(deps): update `@playwright/test` to 1.60.0 (#38144) + * ci: add `tools/ci-tools.ts` for the PR labeler workflow (#37831) + * fix(build): swagger css import (#37801) (#37803) + ## [1.26.2](https://github.com/go-gitea/gitea/releases/tag/1.26.2) - 2026-05-20 * SECURITY @@ -86,7 +584,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Fix button layout shift when collapsing file tree in editor (#37363) #37375 * Fix org team assignee/reviewer lookups for team member permissions (#37365) #37391 * Fix repo init README EOL (#37388) #37399 - * Fix: dump with default zip type produces uncompressed zip (#37401)#37402 + * Fix: dump with default zip type produces uncompressed zip (#37401) #37402 ## [1.26.0](https://github.com/go-gitea/gitea/releases/tag/v1.26.0) - 2026-04-17 @@ -1445,7 +1943,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Fix mCaptcha bug (#33659) (#33661) * Git graph: don't show detached commits (#33645) (#33650) * Use MatchPhraseQuery for bleve code search (#33628) - * Adjust appearence of commit status webhook (#33778) #33789 + * Adjust appearance of commit status webhook (#33778) #33789 * Upgrade golang net from 0.35.0 -> 0.36.0 (#33795) #33796 ## [1.23.4](https://github.com/go-gitea/gitea/releases/tag/v1.23.4) - 2025-02-16 @@ -2176,7 +2674,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Optimize repo-list layout to enhance visual experience (#31272) (#31276) * fixed the dropdown menu for the top New button to expand to the left (#31273) (#31275) * Fix Activity Page Contributors dropdown (#31264) (#31269) - * fix: allow actions artifacts storage migration to complete succesfully (#31251) (#31257) + * fix: allow actions artifacts storage migration to complete successfully (#31251) (#31257) * Make blockquote attention recognize more syntaxes (#31240) (#31250) * Remove .segment from .project-column (#31204) (#31239) * Ignore FindRecentlyPushedNewBranches err (#31164) (#31171) @@ -2360,7 +2858,7 @@ Key highlights of this release encompass significant changes categorized under ` * 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 inline math blocks can't be preceded/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) @@ -5652,7 +6150,7 @@ Key highlights of this release encompass significant changes categorized under ` * Fix navbar on project view (#17749) * More pleasantly handle broken or missing git repositories (#17747) * Use `*PushUpdateOptions` as receiver (#17724) - * Remove unused `user` paramater (#17723) + * Remove unused `user` parameter (#17723) * Better builtin avatar generator (#17707) * Cleanup and use global style on popups (#17674) * Move user/org deletion to services (#17673) diff --git a/package/gitea/source/CONTRIBUTING.md b/package/gitea/source/CONTRIBUTING.md index 4b32631d..71087d34 100644 --- a/package/gitea/source/CONTRIBUTING.md +++ b/package/gitea/source/CONTRIBUTING.md @@ -1,5 +1,19 @@ # Contribution Guidelines +This document explains how to contribute changes to the Gitea project. Topic-specific guides live in separate files so the essentials are easier to find. + +| Topic | Document | +|:-----------------------|:-----------------------------------------------------------------| +| Setup and requirements | [docs/build-setup.md](docs/build-setup.md) | +| Development workflow | [docs/development.md](docs/development.md) | +| Build from source | [docs/build-source.md](docs/build-source.md) | +| Running the tests | [docs/testing.md](docs/testing.md) | +| Frontend guidelines | [docs/guidelines-frontend.md](docs/guidelines-frontend.md) | +| Backend guidelines | [docs/guidelines-backend.md](docs/guidelines-backend.md) | +| Refactoring | [docs/guidelines-refactoring.md](docs/guidelines-refactoring.md) | +| Community Governance | [docs/community-governance.md](docs/community-governance.md) | +| Release management | [docs/release-management.md](docs/release-management.md) | +
Table of Contents - [Contribution Guidelines](#contribution-guidelines) @@ -11,10 +25,6 @@ - [Discuss your design before the implementation](#discuss-your-design-before-the-implementation) - [Issue locking](#issue-locking) - [Building Gitea](#building-gitea) - - [Dependencies](#dependencies) - - [Backend](#backend) - - [Frontend](#frontend) - - [Design guideline](#design-guideline) - [Styleguide](#styleguide) - [Copyright](#copyright) - [Testing](#testing) @@ -22,51 +32,23 @@ - [Code review](#code-review) - [Pull request format](#pull-request-format) - [PR title and summary](#pr-title-and-summary) - - [Milestone](#milestone) - - [Labels](#labels) - [Breaking PRs](#breaking-prs) - [What is a breaking PR?](#what-is-a-breaking-pr) - [How to handle breaking PRs?](#how-to-handle-breaking-prs) - [Maintaining open PRs](#maintaining-open-prs) - - [Getting PRs merged](#getting-prs-merged) - - [Final call](#final-call) - - [Commit messages](#commit-messages) - - [PR Co-authors](#pr-co-authors) - - [PRs targeting `main`](#prs-targeting-main) - - [Backport PRs](#backport-prs) + - [Reviewing PRs](#reviewing-prs) + - [For PR authors](#for-pr-authors) - [Documentation](#documentation) - - [API v1](#api-v1) - - [GitHub API compatibility](#github-api-compatibility) - - [Adding/Maintaining API routes](#addingmaintaining-api-routes) - - [When to use what HTTP method](#when-to-use-what-http-method) - - [Requirements for API routes](#requirements-for-api-routes) - - [Backports and Frontports](#backports-and-frontports) - - [What is backported?](#what-is-backported) - - [How to backport?](#how-to-backport) - - [Format of backport PRs](#format-of-backport-prs) - - [Frontports](#frontports) - [Developer Certificate of Origin (DCO)](#developer-certificate-of-origin-dco) - - [Release Cycle](#release-cycle) - - [Maintainers](#maintainers) - - [Technical Oversight Committee (TOC)](#technical-oversight-committee-toc) - - [TOC election process](#toc-election-process) - - [Current TOC members](#current-toc-members) - - [Previous TOC/owners members](#previous-tocowners-members) - - [Governance Compensation](#governance-compensation) - - [TOC \& Working groups](#toc--working-groups) - - [Roadmap](#roadmap) - - [Versions](#versions) - - [Releasing Gitea](#releasing-gitea)
## Introduction -This document explains how to contribute changes to the Gitea project. \ It assumes you have followed the [installation instructions](https://docs.gitea.com/category/installation). \ Sensitive security-related issues should be reported to [security@gitea.io](mailto:security@gitea.io). -For configuring IDEs for Gitea development, see the [contributed IDE configurations](contrib/ide/). +For configuring IDEs for Gitea development, see the [IDE setup notes](docs/development.md#ide-configuration) and the [contributed configurations](contrib/development/). ## AI Contribution Policy @@ -129,35 +111,8 @@ If further discussion is needed, we encourage you to open a new issue instead an ## Building Gitea -See the [development setup instructions](https://docs.gitea.com/development/hacking-on-gitea). - -## Dependencies - -### Backend - -Go dependencies are managed using [Go Modules](https://go.dev/cmd/go/#hdr-Module_maintenance). \ -You can find more details in the [go mod documentation](https://go.dev/ref/mod) and the [Go Modules Wiki](https://github.com/golang/go/wiki/Modules). - -Pull requests should only modify `go.mod` and `go.sum` where it is related to your change, be it a bugfix or a new feature. \ -Apart from that, these files should only be modified by Pull Requests whose only purpose is to update dependencies. - -The `go.mod`, `go.sum` update needs to be justified as part of the PR description, -and must be verified by the reviewers and/or merger to always reference -an existing upstream commit. - -### Frontend - -For the frontend, we use [npm](https://www.npmjs.com/). - -The same restrictions apply for frontend dependencies as for backend dependencies, with the exceptions that the files for it are `package.json` and `package-lock.json`, and that new versions must always reference an existing version. - -## Design guideline - -Depending on your change, please read the - -- [backend development guideline](https://docs.gitea.com/contributing/guidelines-backend) -- [frontend development guideline](https://docs.gitea.com/contributing/guidelines-frontend) -- [refactoring guideline](https://docs.gitea.com/contributing/guidelines-refactoring) +See [docs/setup.md](docs/setup.md) for prerequisites and [docs/development.md](docs/development.md) +for building Gitea and the development workflow. ## Styleguide @@ -176,33 +131,7 @@ Afterwards, copyright should only be modified when the copyright author changes. ## Testing -Before submitting a pull request, run all tests to make sure your changes don't cause a regression elsewhere. - -Here's how to run the test suite: - -- code lint - -| | | -| :-------------------- | :--------------------------------------------------------------------------- | -|``make lint`` | lint everything (not needed if you only change the front- **or** backend) | -|``make lint-frontend`` | lint frontend files | -|``make lint-backend`` | lint backend files | - -- run tests (we suggest running them on Linux) - -| Command | Action | | -| :------------------------------------------ | :------------------------------------------------------- | ------------------------------------------- | -|``make test[\#SpecificTestName]`` | run unit test(s) | | -|``make test-sqlite[\#SpecificTestName]`` | run [integration](tests/integration) test(s) for SQLite | [More details](tests/integration/README.md) | -|``make test-e2e`` | run [end-to-end](tests/e2e) test(s) using Playwright | | - -- E2E test environment variables - -| Variable | Description | -| :-------------------------------- | :---------------------------------------------------------- | -| ``GITEA_TEST_E2E_DEBUG`` | When set, show Gitea server output | -| ``GITEA_TEST_E2E_FLAGS`` | Additional flags passed to Playwright, for example ``--ui`` | -| ``GITEA_TEST_E2E_TIMEOUT_FACTOR`` | Timeout multiplier (default: 3 on CI, 1 locally) | +Before submitting a pull request, run the linters (`make lint`, or the scoped `make lint-backend` / `make lint-frontend`) and the tests to make sure your changes don't cause a regression elsewhere. See [docs/testing.md](docs/testing.md) for how to run the unit, integration, end-to-end, and migration tests. ## Translation @@ -216,6 +145,8 @@ The tool `go run build/backport-locale.go` can be used to backport locales from ## Code review +How labels, milestones, and the merge queue work is documented in [docs/community-governance.md](docs/community-governance.md). + ### Pull request format Please try to make your pull request easy to review for us. \ @@ -238,6 +169,38 @@ In the PR title, describe the problem you are fixing, not how you are fixing it. Use the first comment as a summary of your PR. \ In the PR summary, you can describe exactly how you are fixing this problem. +PR titles must follow the [Conventional Commits](https://www.conventionalcommits.org/) format, because PRs are squash-merged and the PR title becomes the resulting commit message: + +```text +type(scope)!: subject +``` + +The scope in parentheses is optional. A `!` immediately before the colon marks a [breaking change](https://www.conventionalcommits.org/en/v1.0.0/#summary): either `type!:` or `type(scope)!:` (not `type!(scope):`). + +Use one of these types: + +- `build`: Changes affecting the build system, packaging, or external dependencies +- `ci`: Changes to CI/CD configuration files and scripts +- `chore`: Maintenance changes that do not affect production code or should not appear in the changelog +- `docs`: Documentation-only changes +- `feat`: A larger user-facing feature, improvement, or new functionality +- `enhance`: Small or trivial user-facing improvements or UX polish (for example wording changes, color adjustments, spacing or padding tweaks, placeholders, small UI behavior improvements) +- `fix`: A bug fix, UX correction, or security-related dependency update +- `perf`: Performance improvements (speed, memory, scalability) +- `refactor`: A code change that neither fixes a bug nor adds a feature +- `revert`: Reverts a previous change +- `style`: Formatting or style-only changes that do not affect code behavior (for example lint-driven edits) +- `test`: Adding or correcting tests + +Examples: + +```text +fix(web): prevent avatar upload crash on empty file +feat(api): add pagination to repo hooks list +enhance(repo): improve diff toolbar spacing +ci(workflows): lint PR titles in CI +``` + Keep this summary up-to-date as the PR evolves. \ If your PR changes the UI, you must add **after** screenshots in the PR summary. \ If you are not implementing a new feature, you should also post **before** screenshots for comparison. @@ -250,6 +213,10 @@ Another requirement for merging PRs is that the PR is labeled correctly.\ However, this is not your job as a contributor, but the job of the person merging your PR.\ If you think that your PR was labeled incorrectly, or notice that it was merged without labels, please let us know. +For pull requests that use a valid Conventional Commits title, CI automatically applies a matching `type/…` label when the title prefix is `feat`, `enhance`, `fix`, `docs`, or `test` (for example `enhance(web): …` receives `type/enhancement`).\ +That label is kept in sync with the PR title when the title is edited.\ +Other title prefixes do not get an automatic `type/…` label; the merger still assigns the correct labels (including `type/…` when needed) for changelog and backport decisions. + If your PR closes some issues, you must note that in a way that both GitHub and Gitea understand, i.e. by appending a paragraph like ```text @@ -260,29 +227,6 @@ Fixes/Closes/Resolves #. to your summary. \ Each issue that will be closed must stand on a separate line. -### Milestone - -A PR should only be assigned to a milestone if it will likely be merged into the given version. \ -As a rule of thumb, assume that a PR will stay open for an additional month for every 100 added lines. \ -PRs without a milestone may not be merged. - -### Labels - -Almost all labels used inside Gitea can be classified as one of the following: - -- `modifies/…`: Determines which parts of the codebase are affected. These labels will be set through the CI. -- `topic/…`: Determines the conceptual component of Gitea that is affected, i.e. issues, projects, or authentication. At best, PRs should only target one component but there might be overlap. Must be set manually. -- `type/…`: Determines the type of an issue or PR (feature, refactoring, docs, bug, …). If GitHub supported scoped labels, these labels would be exclusive, so you should set **exactly** one, not more or less (every PR should fall into one of the provided categories, and only one). -- `issue/…` / `pr/…`: Labels that are specific to issues or PRs respectively and that are only necessary in a given context, i.e. `issue/not-a-bug` or `pr/need-2-approvals` - -Every PR should be labeled correctly with every label that applies. - -There are also some labels that will be managed automatically.\ -In particular, these are - -- the amount of pending required approvals -- has all `backport`s or needs a manual backport - ### Breaking PRs #### What is a breaking PR? @@ -311,165 +255,29 @@ Breaking PRs will not be merged as long as not both of these requirements are me ### Maintaining open PRs -The moment you create a non-draft PR or the moment you convert a draft PR to a non-draft PR is the moment code review starts for it. \ -Once that happens, do not rebase or squash your branch anymore as it makes it difficult to review the new changes. \ -Merge the base branch into your branch only when you really need to, i.e. because of conflicting changes in the mean time. \ -This reduces unnecessary CI runs. \ -Don't worry about merge commits messing up your commit history as every PR will be squash merged. \ -This means that all changes are joined into a single new commit whose message is as described below. +Code review starts when you open a non-draft PR or move a draft out of draft state. After that, do not rebase or squash your branch; it makes new changes harder to review. -### Getting PRs merged +Merge the base branch into yours only when you need to, for example because of conflicting changes elsewhere. That limits unnecessary CI runs. -Changes to Gitea must be reviewed before they are accepted — no matter who -makes the change, even if they are an owner or a maintainer. \ -The only exception are critical bugs that prevent Gitea from being compiled or started. \ -Specifically, we require two approvals from maintainers for every PR. \ -Once this criteria has been met, your PR receives the `lgtm/done` label. \ -From this point on, your only responsibility is to fix merge conflicts or respond to/implement requests by maintainers. \ -It is the responsibility of the maintainers from this point to get your PR merged. +Every PR is squash-merged, so merge commits on your branch do not matter for final history. The squash produces a single commit; mergers follow the [commit message format](docs/community-governance.md#commit-messages) in the governance guide. -If a PR has the `lgtm/done` label and there are no open discussions or merge conflicts anymore, any maintainer can add the `reviewed/wait-merge` label. \ -This label means that the PR is part of the merge queue and will be merged as soon as possible. \ -The merge queue will be cleared in the order of the list below: +### Reviewing PRs - +Maintainers are encouraged to review pull requests in areas where they have expertise or particular interest. -Gitea uses it's own tool, the to automate parts of the review process. \ -This tool does the things listed below automatically: +#### For PR authors -- create a backport PR if needed once the initial PR was merged -- remove the PR from the merge queue after the PR merged -- keep the oldest branch in the merge queue up to date with merges +- **Response**: When answering reviewer questions, use real-world cases or examples and avoid speculation. +- **Discussion**: A discussion is always welcome and should be used to clarify the changes and the intent of the PR. +- **Help**: If you need help with the PR or comments are unclear, ask for clarification. -### Final call - -If a PR has been ignored for more than 7 days with no comments or reviews, and the author or any maintainer believes it will not survive a long wait (such as a refactoring PR), they can send "final call" to the TOC by mentioning them in a comment. - -After another 7 days, if there is still zero approval, this is considered a polite refusal, and the PR will be closed to avoid wasting further time. Therefore, the "final call" has a cost, and should be used cautiously. - -However, if there are no objections from maintainers, the PR can be merged with only one approval from the TOC (not the author). - -### Commit messages - -Mergers are able and required to rewrite the PR title and summary (the first comment of a PR) so that it can produce an easily understandable commit message if necessary. \ -The final commit message should no longer contain any uncertainty such as `hopefully, won't happen anymore`. Replace uncertainty with certainty. - -#### PR Co-authors - -A person counts as a PR co-author the moment they (co-)authored a commit that is not simply a `Merge base branch into branch` commit. \ -Mergers are required to remove such "false-positive" co-authors when writing the commit message. \ -The true co-authors must remain in the commit message. - -#### PRs targeting `main` - -The commit message of PRs targeting `main` is always - -```bash -$PR_TITLE ($PR_INDEX) - -$REWRITTEN_PR_SUMMARY -``` - -#### Backport PRs - -The commit message of backport PRs is always - -```bash -$PR_TITLE ($INITIAL_PR_INDEX) ($BACKPORT_PR_INDEX) - -$REWRITTEN_PR_SUMMARY -``` +Guidance for reviewers, the merge queue, and the squash commit message format is in [docs/community-governance.md](docs/community-governance.md). ## Documentation If you add a new feature or change an existing aspect of Gitea, the documentation for that feature must be created or updated in another PR at [https://gitea.com/gitea/docs](https://gitea.com/gitea/docs). **The docs directory on main repository will be removed at some time. We will have a yaml file to store configuration file's meta data. After that completed, configuration documentation should be in the main repository.** -## API v1 - -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 - -Gitea's API should use the same endpoints and fields as the GitHub API as far as possible, unless there are good reasons to deviate. \ -If Gitea provides functionality that GitHub does not, a new endpoint can be created. \ -If information is provided by Gitea that is not provided by the GitHub API, a new field can be used that doesn't collide with any GitHub fields. \ -Updating an existing API should not remove existing fields unless there is a really good reason to do so. \ -The same applies to status responses. If you notice a problem, feel free to leave a comment in the code for future refactoring to API v2 (which is currently not planned). - -### Adding/Maintaining API routes - -All expected results (errors, success, fail messages) must be documented ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L319-L327)). \ -All JSON input types must be defined as a struct in [modules/structs/](modules/structs/) ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/modules/structs/issue.go#L76-L91)) \ -and referenced in [routers/api/v1/swagger/options.go](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/swagger/options.go). \ -They can then be used like [this example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L318). \ -All JSON responses must be defined as a struct in [modules/structs/](modules/structs/) ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/modules/structs/issue.go#L36-L68)) \ -and referenced in its category in [routers/api/v1/swagger/](routers/api/v1/swagger/) ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/swagger/issue.go#L11-L16)) \ -They can be used like [this example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L277-L279). - -### When to use what HTTP method - -In general, HTTP methods are chosen as follows: - -- **GET** endpoints return the requested object(s) and status **OK (200)** -- **DELETE** endpoints return the status **No Content (204)** and no content either -- **POST** endpoints are used to **create** new objects (e.g. a User) and return the status **Created (201)** and the created object -- **PUT** endpoints are used to **add/assign** existing Objects (e.g. a user to a team) and return the status **No Content (204)** and no content either -- **PATCH** endpoints are used to **edit/change** an existing object and return the changed object and the status **OK (200)** - -### Requirements for API routes - -All parameters of endpoints changing/editing an object must be optional (except the ones to identify the object, which are required). - -Endpoints returning lists must - -- support pagination (`page` & `limit` options in query) -- set `X-Total-Count` header via **SetTotalCountHeader** ([example](https://github.com/go-gitea/gitea/blob/7aae98cc5d4113f1e9918b7ee7dd09f67c189e3e/routers/api/v1/repo/issue.go#L444)) - -## Backports and Frontports - -### What is backported? - -We backport PRs given the following circumstances: - -1. Feature freeze is active, but `-rc0` has not been released yet. Here, we backport as much as possible. -2. `rc0` has been released. Here, we only backport bug- and security-fixes, and small enhancements. Large PRs such as refactors are not backported anymore. -3. We never backport new features. -4. We never backport breaking changes except when - 1. The breaking change has no effect on the vast majority of users - 2. The component triggering the breaking change is marked as experimental - -### How to backport? - -In the past, it was necessary to manually backport your PRs. \ -Now, that's not a requirement anymore as our [backport bot](https://github.com/GiteaBot) tries to create backports automatically once the PR is merged when the PR - -- does not have the label `backport/manual` -- has the label `backport/` - -The `backport/manual` label signifies either that you want to backport the change yourself, or that there were conflicts when backporting, thus you **must** do it yourself. - -### Format of backport PRs - -The title of backport PRs should be - -``` - (#) -``` - -The first two lines of the summary of the backporting PR should be - -``` -Backport # - -``` - -with the rest of the summary and labels matching the original PR. - -### Frontports - -Frontports behave exactly as described above for backports. - ## Developer Certificate of Origin (DCO) We consider the act of contributing to the code by submitting a Pull Request as the "Sign off" or agreement to the certifications and terms of the [DCO](DCO) and [MIT license](LICENSE). \ @@ -483,148 +291,3 @@ Signed-off-by: Joe Smith If you set the `user.name` and `user.email` Git config options, you can add the line to the end of your commits automatically with `git commit -s`. We assume in good faith that the information you provide is legally binding. - -## Release Cycle - -We adopted a release schedule to streamline the process of working on, finishing, and issuing releases. \ -The overall goal is to make a major release every three or four months, which breaks down into two or three months of general development followed by one month of testing and polishing known as the release freeze. \ -All the feature pull requests should be -merged before feature freeze. All feature pull requests haven't been merged before this feature freeze will be moved to next milestone, please notice our feature freeze announcement on discord. And, during the frozen period, a corresponding -release branch is open for fixes backported from main branch. Release candidates -are made during this period for user testing to -obtain a final version that is maintained in this branch. - -During a development cycle, we may also publish any necessary minor releases -for the previous version. For example, if the latest, published release is -v1.2, then minor changes for the previous release—e.g., v1.1.0 -> v1.1.1—are -still possible. - -## Maintainers - -To make sure every PR is checked, we have [maintainers](MAINTAINERS). \ -Every PR **must** be reviewed by at least two maintainers (or owners) before it can get merged. \ -For refactoring PRs after a week and documentation only PRs, the approval of only one maintainer is enough. \ -A maintainer should be a contributor of Gitea and contributed at least -4 accepted PRs. A contributor should apply as a maintainer in the -[Discord](https://discord.gg/Gitea) `#develop` channel. The team maintainers may invite the contributor. A maintainer -should spend some time on code reviews. If a maintainer has no -time to do that, they should apply to leave the maintainers team -and we will give them the honor of being a member of the [advisors -team](https://github.com/orgs/go-gitea/teams/advisors). Of course, if -an advisor has time to code review, we will gladly welcome them back -to the maintainers team. If a maintainer is inactive for more than 3 -months and forgets to leave the maintainers team, the owners may move -him or her from the maintainers team to the advisors team. -For security reasons, Maintainers should use 2FA for their accounts and -if possible provide GPG signed commits. -https://help.github.com/articles/securing-your-account-with-two-factor-authentication-2fa/ -https://help.github.com/articles/signing-commits-with-gpg/ - -Furthermore, any account with write access (like bots and TOC members) **must** use 2FA. -https://help.github.com/articles/securing-your-account-with-two-factor-authentication-2fa/ - -## Technical Oversight Committee (TOC) - -At the start of 2023, the `Owners` team was dissolved. Instead, the governance charter proposed a technical oversight committee (TOC) which expands the ownership team of the Gitea project from three elected positions to six positions. Three positions are elected as it has been over the past years, and the other three consist of appointed members from the Gitea company. -https://blog.gitea.com/quarterly-23q1/ - -### TOC election process - -Any maintainer is eligible to be part of the community TOC if they are not associated with the Gitea company. -A maintainer can either nominate themselves, or can be nominated by other maintainers to be a candidate for the TOC election. -If you are nominated by someone else, you must first accept your nomination before the vote starts to be a candidate. - -The TOC is elected for one year, the TOC election happens yearly. -After the announcement of the results of the TOC election, elected members have two weeks time to confirm or refuse the seat. -If an elected member does not answer within this timeframe, they are automatically assumed to refuse the seat. -Refusals result in the person with the next highest vote getting the same choice. -As long as seats are empty in the TOC, members of the previous TOC can fill them until an elected member accepts the seat. - -If an elected member that accepts the seat does not have 2FA configured yet, they will be temporarily counted as `answer pending` until they manage to configure 2FA, thus leaving their seat empty for this duration. - -### Current TOC members - -- 2024-01-01 ~ 2024-12-31 - - Company - - [Jason Song](https://gitea.com/wolfogre) - - [Lunny Xiao](https://gitea.com/lunny) - - [Matti Ranta](https://gitea.com/techknowlogick) - - Community - - [6543](https://gitea.com/6543) <6543@obermui.de> - - [delvh](https://gitea.com/delvh) - - [John Olheiser](https://gitea.com/jolheiser) - -### Previous TOC/owners members - -Here's the history of the owners and the time they served: - -- [Lunny Xiao](https://gitea.com/lunny) - 2016, 2017, [2018](https://github.com/go-gitea/gitea/issues/3255), [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023 -- [Kim Carlbäcker](https://github.com/bkcsoft) - 2016, 2017 -- [Thomas Boerger](https://gitea.com/tboerger) - 2016, 2017 -- [Lauris Bukšis-Haberkorns](https://gitea.com/lafriks) - [2018](https://github.com/go-gitea/gitea/issues/3255), [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801) -- [Matti Ranta](https://gitea.com/techknowlogick) - [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023 -- [Andrew Thornton](https://gitea.com/zeripath) - [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023 -- [6543](https://gitea.com/6543) - 2023 -- [John Olheiser](https://gitea.com/jolheiser) - 2023 -- [Jason Song](https://gitea.com/wolfogre) - 2023 - -## Governance Compensation - -Each member of the community elected TOC will be granted $500 each month as compensation for their work. - -Furthermore, any community release manager for a specific release or LTS will be compensated $500 for the delivery of said release. - -These funds will come from community sources like the OpenCollective rather than directly from the company. -Only non-company members are eligible for this compensation, and if a member of the community TOC takes the responsibility of release manager, they would only be compensated for their TOC duties. -Gitea Ltd employees are not eligible to receive any funds from the OpenCollective unless it is reimbursement for a purchase made for the Gitea project itself. - -## TOC & Working groups - -With Gitea covering many projects outside of the main repository, several groups will be created to help focus on specific areas instead of requiring maintainers to be a jack-of-all-trades. Maintainers are of course more than welcome to be part of multiple groups should they wish to contribute in multiple places. - -The currently proposed groups are: - -- **Core Group**: maintain the primary Gitea repository -- **Integration Group**: maintain the Gitea ecosystem's related tools, including go-sdk/tea/changelog/bots etc. -- **Documentation Group**: maintain related documents and repositories -- **Translation Group**: coordinate with translators and maintain translations -- **Security Group**: managed by TOC directly, members are decided by TOC, maintains security patches/responsible for security items - -## Roadmap - -Each year a roadmap will be discussed with the entire Gitea maintainers team, and feedback will be solicited from various stakeholders. -TOC members need to review the roadmap every year and work together on the direction of the project. - -When a vote is required for a proposal or other change, the vote of community elected TOC members count slightly more than the vote of company elected TOC members. With this approach, we both avoid ties and ensure that changes align with the mission statement and community opinion. - -You can visit our roadmap on the wiki. - -## Versions - -Gitea has the `main` branch as a tip branch and has version branches -such as `release/v1.19`. `release/v1.19` is a release branch and we will -tag `v1.19.0` for binary download. If `v1.19.0` has bugs, we will accept -pull requests on the `release/v1.19` branch and publish a `v1.19.1` tag, -after bringing the bug fix also to the main branch. - -Since the `main` branch is a tip version, if you wish to use Gitea -in production, please download the latest release tag version. All the -branches will be protected via GitHub, all the PRs to every branch must -be reviewed by two maintainers and must pass the automatic tests. - -## Releasing Gitea - -- Let $vmaj, $vmin and $vpat be Major, Minor and Patch version numbers, $vpat should be rc1, rc2, 0, 1, ...... $vmaj.$vmin will be kept the same as milestones on github or gitea in future. -- Before releasing, confirm all the version's milestone issues or PRs has been resolved. Then discuss the release on Discord channel #maintainers and get agreed with almost all the owners and mergers. Or you can declare the version and if nobody is against it in about several hours. -- If this is a big version first you have to create PR for changelog on branch `main` with PRs with label `changelog` and after it has been merged do following steps: - - Create `-dev` tag as `git tag -s -F release.notes v$vmaj.$vmin.0-dev` and push the tag as `git push origin v$vmaj.$vmin.0-dev`. - - When CI has finished building tag then you have to create a new branch named `release/v$vmaj.$vmin` -- If it is bugfix version create PR for changelog on branch `release/v$vmaj.$vmin` and wait till it is reviewed and merged. -- Add a tag as `git tag -s -F release.notes v$vmaj.$vmin.$`, release.notes file could be a temporary file to only include the changelog this version which you added to `CHANGELOG.md`. -- And then push the tag as `git push origin v$vmaj.$vmin.$`. Drone CI will automatically create a release and upload all the compiled binary. (But currently it doesn't add the release notes automatically. Maybe we should fix that.) -- If needed send a frontport PR for the changelog to branch `main` and update the version in `docs/config.yaml` to refer to the new version. -- Send PR to [blog repository](https://gitea.com/gitea/blog) announcing the release. -- Verify all release assets were correctly published through CI on dl.gitea.com and GitHub releases. Once ACKed: - - bump the version of https://dl.gitea.com/gitea/version.json - - merge the blog post PR - - announce the release in discord `#announcements` diff --git a/package/gitea/source/Dockerfile b/package/gitea/source/Dockerfile index 323f0612..57cc12df 100644 --- a/package/gitea/source/Dockerfile +++ b/package/gitea/source/Dockerfile @@ -1,18 +1,18 @@ # syntax=docker/dockerfile:1 # Build frontend on the native platform to avoid QEMU-related issues with nodejs ecosystem -FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.26-alpine3.23 AS frontend-build +FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.26-alpine3.24 AS frontend-build RUN apk --no-cache add build-base git nodejs pnpm WORKDIR /src -COPY package.json pnpm-lock.yaml .npmrc ./ +COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ RUN --mount=type=cache,target=/root/.local/share/pnpm/store pnpm install --frozen-lockfile COPY --exclude=.git/ . . RUN make frontend # Build backend for each target platform -FROM docker.io/library/golang:1.26-alpine3.23 AS build-env +FROM docker.io/library/golang:1.26-alpine3.24 AS build-env ARG GITEA_VERSION -ARG TAGS="sqlite sqlite_unlock_notify" +ARG TAGS="" ENV TAGS="bindata timetzdata $TAGS" ARG CGO_EXTRA_CFLAGS @@ -21,7 +21,7 @@ RUN apk --no-cache add \ build-base \ git -WORKDIR ${GOPATH}/src/code.gitea.io/gitea +WORKDIR ${GOPATH}/src/gitea.dev COPY go.mod go.sum ./ RUN go mod download # Use COPY instead of bind mount as read-only one breaks makefile state tracking and read-write one needs binary to be moved as it's discarded. @@ -42,9 +42,9 @@ RUN chmod 755 /tmp/local/usr/bin/entrypoint \ /tmp/local/etc/s6/gitea/* \ /tmp/local/etc/s6/openssh/* \ /tmp/local/etc/s6/.s6-svscan/* \ - /go/src/code.gitea.io/gitea/gitea + /go/src/gitea.dev/gitea -FROM docker.io/library/alpine:3.23 AS gitea +FROM docker.io/library/alpine:3.24 AS gitea EXPOSE 22 3000 @@ -74,7 +74,7 @@ RUN addgroup \ echo "git:*" | chpasswd -e COPY --from=build-env /tmp/local / -COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea +COPY --from=build-env /go/src/gitea.dev/gitea /app/gitea/gitea ENV USER=git ENV GITEA_CUSTOM=/data/gitea diff --git a/package/gitea/source/Dockerfile.rootless b/package/gitea/source/Dockerfile.rootless index 83c69cbd..4be5a4f8 100644 --- a/package/gitea/source/Dockerfile.rootless +++ b/package/gitea/source/Dockerfile.rootless @@ -1,18 +1,18 @@ # syntax=docker/dockerfile:1 # Build frontend on the native platform to avoid QEMU-related issues with nodejs ecosystem -FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.26-alpine3.23 AS frontend-build +FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.26-alpine3.24 AS frontend-build RUN apk --no-cache add build-base git nodejs pnpm WORKDIR /src -COPY package.json pnpm-lock.yaml .npmrc ./ +COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ RUN --mount=type=cache,target=/root/.local/share/pnpm/store pnpm install --frozen-lockfile COPY --exclude=.git/ . . RUN make frontend # Build backend for each target platform -FROM docker.io/library/golang:1.26-alpine3.23 AS build-env +FROM docker.io/library/golang:1.26-alpine3.24 AS build-env ARG GITEA_VERSION -ARG TAGS="sqlite sqlite_unlock_notify" +ARG TAGS="" ENV TAGS="bindata timetzdata $TAGS" ARG CGO_EXTRA_CFLAGS @@ -21,7 +21,7 @@ RUN apk --no-cache add \ build-base \ git -WORKDIR ${GOPATH}/src/code.gitea.io/gitea +WORKDIR ${GOPATH}/src/gitea.dev COPY go.mod go.sum ./ RUN go mod download # See the comments in Dockerfile @@ -37,9 +37,9 @@ COPY docker/rootless /tmp/local # Set permissions for builds that made under windows which strips the executable bit from file RUN chmod 755 /tmp/local/usr/local/bin/* \ - /go/src/code.gitea.io/gitea/gitea + /go/src/gitea.dev/gitea -FROM docker.io/library/alpine:3.23 AS gitea-rootless +FROM docker.io/library/alpine:3.24 AS gitea-rootless EXPOSE 2222 3000 @@ -68,7 +68,7 @@ RUN mkdir -p /var/lib/gitea /etc/gitea RUN chown git:git /var/lib/gitea /etc/gitea COPY --from=build-env /tmp/local / -COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea +COPY --from=build-env --chown=root:root /go/src/gitea.dev/gitea /app/gitea/gitea # git:git USER 1000:1000 diff --git a/package/gitea/source/MAINTAINERS b/package/gitea/source/MAINTAINERS index 26192eff..03ff6999 100644 --- a/package/gitea/source/MAINTAINERS +++ b/package/gitea/source/MAINTAINERS @@ -64,4 +64,4 @@ metiftikci (@metiftikci) Christopher Homberger (@ChristopherHX) Tobias Balle-Petersen (@tobiasbp) TheFox (@TheFox0x7) -Nicolas (@bircni) \ No newline at end of file +Nicolas (@bircni) diff --git a/package/gitea/source/Makefile b/package/gitea/source/Makefile index 8c73dc35..ea83477f 100644 --- a/package/gitea/source/Makefile +++ b/package/gitea/source/Makefile @@ -7,33 +7,44 @@ export GOEXPERIMENT ?= jsonv2 GO ?= go SHASUM ?= shasum -a 256 -HAS_GO := $(shell hash $(GO) > /dev/null 2>&1 && echo yes) COMMA := , -XGO_VERSION := go-1.25.x +XGO_VERSION := go-1.26.x -AIR_PACKAGE ?= github.com/air-verse/air@v1 -EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3 -GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.9.2 -GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.11.4 -GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.15 -MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.8.0 -SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.33.1 -XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest -GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 -ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.7.11 +AIR_PACKAGE ?= github.com/air-verse/air@v1.65.3 # renovate: datasource=go +EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.7.0 # renovate: datasource=go +GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.12.2 # renovate: datasource=go +GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.15 # renovate: datasource=go +MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.8.0 # renovate: datasource=go +SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.34.1 # renovate: datasource=go +XGO_PACKAGE ?= src.techknowlogick.com/xgo@v1.9.0 # renovate: datasource=go +GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1.4.0 # renovate: datasource=go +ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.7.12 # renovate: datasource=go +SHELLCHECK_IMAGE ?= docker.io/koalaman/shellcheck:v0.11.0@sha256:61862eba1fcf09a484ebcc6feea46f1782532571a34ed51fedf90dd25f925a8d # renovate: datasource=docker -DOCKER_IMAGE ?= gitea/gitea -DOCKER_TAG ?= latest -DOCKER_REF := $(DOCKER_IMAGE):$(DOCKER_TAG) +CONTAINER_RUNTIME ?= $(shell hash docker >/dev/null 2>&1 && echo docker || echo podman) +HAS_GO := $(shell hash $(GO) > /dev/null 2>&1 && echo yes) ifeq ($(HAS_GO), yes) CGO_EXTRA_CFLAGS := -DSQLITE_MAX_VARIABLE_NUMBER=32766 CGO_CFLAGS ?= $(shell $(GO) env CGO_CFLAGS) $(CGO_EXTRA_CFLAGS) endif +MAKE_EVIDENCE_DIR := .make_evidence + +# Use sqlite as default database if running tests, only do so for local tests, not in CI. +# CI should explicitly set the database to avoid unexpected results. +ifneq ($(findstring test-,$(MAKECMDGOALS)),) + ifeq ($(CI),) + GITEA_TEST_DATABASE ?= sqlite + endif +endif + +TAGS ?= +TAGS_EVIDENCE := $(MAKE_EVIDENCE_DIR)/tags + CGO_ENABLED ?= 0 -ifneq (,$(findstring sqlite,$(TAGS))$(findstring pam,$(TAGS))) +ifneq (,$(findstring sqlite_mattn,$(TAGS))$(findstring pam,$(TAGS))) CGO_ENABLED = 1 endif @@ -50,15 +61,16 @@ else ifeq ($(patsubst Windows%,Windows,$(OS)),Windows) IS_WINDOWS := yes endif endif + +# GOFLAGS and EXTRA_GOFLAGS are for the 'go build' command only ifeq ($(IS_WINDOWS),yes) GOFLAGS := -v -buildmode=exe EXECUTABLE ?= gitea.exe - EXECUTABLE_E2E ?= gitea-e2e.exe else GOFLAGS := -v EXECUTABLE ?= gitea - EXECUTABLE_E2E ?= gitea-e2e endif +EXTRA_GOFLAGS ?= ifeq ($(shell sed --version 2>/dev/null | grep -q GNU && echo gnu),gnu) SED_INPLACE := sed -i @@ -66,15 +78,8 @@ else SED_INPLACE := sed -i '' endif -EXTRA_GOFLAGS ?= - -MAKE_EVIDENCE_DIR := .make_evidence - -GOTESTFLAGS ?= -ifeq ($(RACE_ENABLED),true) - GOFLAGS += -race - GOTESTFLAGS += -race -endif +# GOTEST_FLAGS is for unit test and integration test +GOTEST_FLAGS ?= -timeout 40m STORED_VERSION_FILE := VERSION @@ -108,8 +113,8 @@ LDFLAGS := $(LDFLAGS) -X "main.Version=$(GITEA_VERSION)" -X "main.Tags=$(TAGS)" LINUX_ARCHS ?= linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64,linux/riscv64 -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,$(shell $(GO) list ./... | grep -v /vendor/)) -MIGRATE_TEST_PACKAGES ?= $(shell $(GO) list code.gitea.io/gitea/models/migrations/...) +GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list gitea.dev/models/migrations/...) gitea.dev/tests/integration/migration-test gitea.dev/tests gitea.dev/tests/integration,$(shell $(GO) list ./... | grep -v /vendor/)) +MIGRATE_TEST_PACKAGES ?= $(shell $(GO) list gitea.dev/models/migrations/...) FRONTEND_SOURCES := $(shell find web_src/js web_src/css -type f) FRONTEND_CONFIGS := vite.config.ts tailwind.config.ts @@ -122,17 +127,12 @@ BINDATA_DEST_WILDCARD := modules/migration/bindata.* modules/public/bindata.* mo GENERATED_GO_DEST := modules/charset/invisible_gen.go modules/charset/ambiguous_gen.go SVG_DEST_DIR := public/assets/img/svg +SVG_DEST_DIRS := $(SVG_DEST_DIR) options/fileicon AIR_TMP_DIR := .air GO_LICENSE_FILE := assets/go-licenses.json -TAGS ?= -TAGS_SPLIT := $(subst $(COMMA), ,$(TAGS)) -TAGS_EVIDENCE := $(MAKE_EVIDENCE_DIR)/tags - -TEST_TAGS ?= $(TAGS_SPLIT) sqlite sqlite_unlock_notify - TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(DIST) $(MAKE_EVIDENCE_DIR) $(AIR_TMP_DIR) GO_DIRS := build cmd models modules routers services tests tools @@ -151,7 +151,8 @@ ESLINT_CONCURRENCY ?= 2 SWAGGER_SPEC := templates/swagger/v1_json.tmpl SWAGGER_SPEC_INPUT := templates/swagger/v1_input.json -SWAGGER_EXCLUDE := code.gitea.io/sdk +SWAGGER_EXCLUDE := gitea.dev/sdk +OPENAPI3_SPEC := templates/swagger/v1_openapi3_json.tmpl TEST_MYSQL_HOST ?= mysql:3306 TEST_MYSQL_DBNAME ?= testgitea @@ -164,13 +165,19 @@ TEST_PGSQL_PASSWORD ?= postgres TEST_PGSQL_SCHEMA ?= gtestschema TEST_MINIO_ENDPOINT ?= minio:9000 TEST_MSSQL_HOST ?= mssql:1433 -TEST_MSSQL_DBNAME ?= gitea +TEST_MSSQL_DBNAME ?= testgitea TEST_MSSQL_USERNAME ?= sa TEST_MSSQL_PASSWORD ?= MwantsaSecurePassword1 # Include local Makefile # Makefile.local is listed in .gitignore -sinclude Makefile.local +ifneq ("$(wildcard Makefile.local)","") + include Makefile.local +endif + +$(foreach v, $(filter TEST_%, $(.VARIABLES)), $(eval MAKEFILE_VARS+=$v=$($v))) +$(foreach v, $(filter GITEA_TEST_%, $(.VARIABLES)), $(eval MAKEFILE_VARS+=$v=$($v))) +export MAKEFILE_VARS .PHONY: all all: build @@ -179,15 +186,8 @@ all: build help: Makefile ## print Makefile help information. @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m[TARGETS] default target: build\033[0m\n\n\033[35mTargets:\033[0m\n"} /^[0-9A-Za-z._-]+:.*?##/ { printf " \033[36m%-45s\033[0m %s\n", $$1, $$2 }' Makefile #$(MAKEFILE_LIST) @printf " \033[36m%-46s\033[0m %s\n" "test-e2e" "test end to end using playwright" - @printf " \033[36m%-46s\033[0m %s\n" "test[#TestSpecificName]" "run unit test" - @printf " \033[36m%-46s\033[0m %s\n" "test-sqlite[#TestSpecificName]" "run integration test for sqlite" - -.PHONY: git-check -git-check: - @if git lfs >/dev/null 2>&1 ; then : ; else \ - echo "Gitea requires git with lfs support to run tests." ; \ - exit 1; \ - fi + @printf " \033[36m%-46s\033[0m %s\n" "test-backend[#TestSpecificName]" "run unit test (sqlite only)" + @printf " \033[36m%-46s\033[0m %s\n" "test-integration[#TestSpecificName]" "run integration test for GITEA_TEST_DATABASE (sqlite, mysql, pgsql, mssql)" .PHONY: clean-all clean-all: clean ## delete backend, frontend and integration files @@ -195,18 +195,12 @@ clean-all: clean ## delete backend, frontend and integration files .PHONY: clean clean: ## delete backend and integration files - rm -rf $(EXECUTABLE) $(EXECUTABLE_E2E) $(DIST) $(BINDATA_DEST_WILDCARD) \ - integrations*.test \ - tests/integration/gitea-integration-* \ - tests/integration/indexers-* \ - tests/sqlite.ini tests/mysql.ini tests/pgsql.ini tests/mssql.ini man/ \ - tests/e2e/gitea-e2e-*/ \ - tests/e2e/indexers-*/ \ - tests/e2e/reports/ tests/e2e/test-artifacts/ tests/e2e/test-snapshots/ + rm -f $(EXECUTABLE) test-*.test tests/*.ini + rm -rf $(DIST) $(BINDATA_DEST_WILDCARD) man tests/integration/gitea-integration-* .PHONY: fmt fmt: ## format the Go and template code - @GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run tools/code-batch-process.go gitea-fmt -w '{file-list}' + $(GO) run $(GOLANGCI_LINT_PACKAGE) fmt $(eval TEMPLATES := $(shell find templates -type f -name '*.tmpl')) @# strip whitespace after '{{' or '(' and before '}}' or ')' unless there is only @# whitespace before it @@ -234,7 +228,7 @@ TAGS_PREREQ := $(TAGS_EVIDENCE) endif .PHONY: generate-swagger -generate-swagger: $(SWAGGER_SPEC) ## generate the swagger spec from code comments +generate-swagger: $(SWAGGER_SPEC) $(OPENAPI3_SPEC) ## generate the swagger spec from code comments $(SWAGGER_SPEC): $(GO_SOURCES) $(SWAGGER_SPEC_INPUT) $(GO) run $(SWAGGER_PACKAGE) generate spec --exclude "$(SWAGGER_EXCLUDE)" --input "$(SWAGGER_SPEC_INPUT)" --output './$(SWAGGER_SPEC)' @@ -256,6 +250,21 @@ swagger-validate: ## check if the swagger spec is valid $(GO) run $(SWAGGER_PACKAGE) validate './$(SWAGGER_SPEC)' @$(SED_INPLACE) -E -e 's|"basePath":( *)"/(.*)"|"basePath":\1"\2"|g' './$(SWAGGER_SPEC)' # remove the prefix slash from basePath +.PHONY: generate-openapi3 +generate-openapi3: $(OPENAPI3_SPEC) ## generate the OpenAPI 3.0 spec from the Swagger 2.0 spec + +$(OPENAPI3_SPEC): $(SWAGGER_SPEC) build/generate-openapi.go $(wildcard build/openapi3gen/*.go) + $(GO) run build/generate-openapi.go + +.PHONY: openapi3-check +openapi3-check: generate-openapi3 + @diff=$$(git diff --color=always '$(OPENAPI3_SPEC)'); \ + if [ -n "$$diff" ]; then \ + echo "Please run 'make generate-openapi3' and commit the result:"; \ + printf "%s" "$${diff}"; \ + exit 1; \ + fi + .PHONY: checks checks: checks-frontend checks-backend ## run various consistency checks @@ -263,10 +272,10 @@ checks: checks-frontend checks-backend ## run various consistency checks checks-frontend: lockfile-check svg-check ## check frontend files .PHONY: checks-backend -checks-backend: tidy-check swagger-check fmt-check swagger-validate security-check ## check backend files +checks-backend: tidy-check swagger-check openapi3-check fmt-check swagger-validate security-check ## check backend files .PHONY: lint -lint: lint-frontend lint-backend lint-spell ## lint everything +lint: lint-frontend lint-backend lint-templates lint-swagger lint-spell lint-md lint-actions lint-json lint-yaml lint-shell ## lint everything .PHONY: lint-fix lint-fix: lint-frontend-fix lint-backend-fix lint-spell-fix ## lint everything and fix issues @@ -278,10 +287,10 @@ lint-frontend: lint-js lint-css ## lint frontend files lint-frontend-fix: lint-js-fix lint-css-fix ## lint frontend files and fix issues .PHONY: lint-backend -lint-backend: lint-go lint-go-gitea-vet lint-editorconfig ## lint backend files +lint-backend: lint-go lint-editorconfig ## lint backend files .PHONY: lint-backend-fix -lint-backend-fix: lint-go-fix lint-go-gitea-vet lint-editorconfig ## lint backend files and fix issues +lint-backend-fix: lint-go-fix lint-editorconfig ## lint backend files and fix issues .PHONY: lint-js lint-js: node_modules ## lint js and ts files @@ -323,23 +332,11 @@ lint-spell-fix: ## lint spelling and fix issues .PHONY: lint-go lint-go: ## lint go files - $(GO) run $(GOLANGCI_LINT_PACKAGE) run + GO=$(GO) GOLANGCI_LINT_PACKAGE=$(GOLANGCI_LINT_PACKAGE) $(GO) run ./tools/lint-go-all.go .PHONY: lint-go-fix lint-go-fix: ## lint go files and fix issues - $(GO) run $(GOLANGCI_LINT_PACKAGE) run --fix - -# workaround step for the lint-go-windows CI task because 'go run' can not -# have distinct GOOS/GOARCH for its build and run steps -.PHONY: lint-go-windows -lint-go-windows: - @GOOS= GOARCH= $(GO) install $(GOLANGCI_LINT_PACKAGE) - golangci-lint run - -.PHONY: lint-go-gitea-vet -lint-go-gitea-vet: ## lint go files with gitea-vet - @echo "Running gitea-vet..." - @$(GO) vet -vettool="$(shell GOOS= GOARCH= go tool -n gitea-vet)" ./... + GO=$(GO) GOLANGCI_LINT_PACKAGE=$(GOLANGCI_LINT_PACKAGE) $(GO) run ./tools/lint-go-all.go --fix .PHONY: lint-editorconfig lint-editorconfig: @@ -347,8 +344,13 @@ lint-editorconfig: @$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) $(EDITORCONFIG_FILES) .PHONY: lint-actions -lint-actions: ## lint action workflow files - $(GO) run $(ACTIONLINT_PACKAGE) +lint-actions: .venv ## lint action workflow files + @$(GO) run $(ACTIONLINT_PACKAGE) + @uv run --frozen zizmor --quiet --min-confidence=medium .github + +.PHONY: lint-shell +lint-shell: ## lint shell scripts + @SHELLCHECK_IMAGE=$(SHELLCHECK_IMAGE) CONTAINER_RUNTIME=$(CONTAINER_RUNTIME) ./tools/lint-shell.sh $$(git ls-files '*.sh') .PHONY: lint-templates lint-templates: .venv node_modules ## lint template files @@ -379,13 +381,10 @@ watch-frontend: node_modules ## start vite dev server for frontend watch-backend: ## watch backend files and continuously rebuild GITEA_RUN_MODE=dev $(GO) run $(AIR_PACKAGE) -c .air.toml -.PHONY: test -test: test-frontend test-backend ## test everything - .PHONY: test-backend test-backend: ## test backend files - @echo "Running go test with $(GOTESTFLAGS) -tags '$(TEST_TAGS)'..." - @$(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' $(GO_TEST_PACKAGES) + @echo "Running go test with $(GOTEST_FLAGS) -tags '$(TAGS)'..." + @$(GO) test $(GOTEST_FLAGS) -tags='$(TAGS)' $(GO_TEST_PACKAGES) .PHONY: test-frontend test-frontend: node_modules ## test frontend files @@ -403,10 +402,10 @@ test-check: exit 1; \ fi -.PHONY: test\#% -test\#%: - @echo "Running go test with -tags '$(TEST_TAGS)'..." - @$(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -run $(subst .,/,$*) $(GO_TEST_PACKAGES) +.PHONY: test-backend\#% +test-backend\#%: + @echo "Running go test with -tags '$(TAGS)'..." + @$(GO) test $(GOTEST_FLAGS) -tags='$(TAGS)' -run $(subst .,/,$*) $(GO_TEST_PACKAGES) .PHONY: coverage coverage: @@ -416,8 +415,8 @@ coverage: .PHONY: unit-test-coverage unit-test-coverage: - @echo "Running unit-test-coverage $(GOTESTFLAGS) -tags '$(TEST_TAGS)'..." - @$(GO) test $(GOTESTFLAGS) -timeout=20m -tags='$(TEST_TAGS)' -cover -coverprofile coverage.out $(GO_TEST_PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1 + @echo "Running unit-test-coverage $(GOTEST_FLAGS) -tags '$(TAGS)'..." + @$(GO) test $(GOTEST_FLAGS) -tags='$(TAGS)' -cover -coverprofile coverage.out $(GO_TEST_PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1 .PHONY: tidy tidy: ## run go mod tidy @@ -444,193 +443,45 @@ go-licenses: $(GO_LICENSE_FILE) ## regenerate go licenses $(GO_LICENSE_FILE): go.mod go.sum GO=$(GO) $(GO) run build/generate-go-licenses.go $(GO_LICENSE_FILE) -generate-ini-sqlite: - sed -e 's|{{WORK_PATH}}|$(CURDIR)/tests/$(or $(TEST_TYPE),integration)/gitea-$(or $(TEST_TYPE),integration)-sqlite|g' \ - -e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \ - tests/sqlite.ini.tmpl > tests/sqlite.ini +.PHONY: test-integration +test-integration: + @# Use a compiled binary: testlogger forwards gitea logs to t.Log, so `go test -v` + @# would flood output per passing test. testcache can't help these tests anyway — + @# they mutate the work directory, so cache inputs change between runs. + $(GO) test $(GOTEST_FLAGS) -tags '$(TAGS)' -c gitea.dev/tests/integration -o ./test-integration-$(GITEA_TEST_DATABASE).test + ./tools/test-integration.sh ./test-integration-$(GITEA_TEST_DATABASE).test -.PHONY: test-sqlite -test-sqlite: integrations.sqlite.test generate-ini-sqlite - GITEA_TEST_CONF=tests/sqlite.ini ./integrations.sqlite.test +.PHONY: test-integration-compile +test-integration-compile: + $(GO) test $(GOTEST_FLAGS) -tags '$(TAGS)' -c -o /dev/null gitea.dev/tests/integration -.PHONY: test-sqlite\#% -test-sqlite\#%: integrations.sqlite.test generate-ini-sqlite - GITEA_TEST_CONF=tests/sqlite.ini ./integrations.sqlite.test -test.run $(subst .,/,$*) +.PHONY: test-integration\#% +test-integration\#%: + $(GO) test $(GOTEST_FLAGS) -tags '$(TAGS)' -run $(subst .,/,$*) gitea.dev/tests/integration -.PHONY: test-sqlite-migration -test-sqlite-migration: migrations.sqlite.test migrations.individual.sqlite.test +.PHONY: test-migration +test-migration: migrations.integration.test migrations.individual.test -generate-ini-mysql: - sed -e 's|{{TEST_MYSQL_HOST}}|${TEST_MYSQL_HOST}|g' \ - -e 's|{{TEST_MYSQL_DBNAME}}|${TEST_MYSQL_DBNAME}|g' \ - -e 's|{{TEST_MYSQL_USERNAME}}|${TEST_MYSQL_USERNAME}|g' \ - -e 's|{{TEST_MYSQL_PASSWORD}}|${TEST_MYSQL_PASSWORD}|g' \ - -e 's|{{WORK_PATH}}|$(CURDIR)/tests/$(or $(TEST_TYPE),integration)/gitea-$(or $(TEST_TYPE),integration)-mysql|g' \ - -e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \ - tests/mysql.ini.tmpl > tests/mysql.ini +.PHONY: migrations.integration.test +migrations.integration.test: + $(GO) test $(GOTEST_FLAGS) -tags '$(TAGS)' gitea.dev/tests/integration/migration-test -.PHONY: test-mysql -test-mysql: integrations.mysql.test generate-ini-mysql - GITEA_TEST_CONF=tests/mysql.ini ./integrations.mysql.test +.PHONY: migrations.individual.test +migrations.individual.test: + @# tests of multiple packages use the same database, don't run in parallel + $(GO) test $(GOTEST_FLAGS) -tags '$(TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES) -.PHONY: test-mysql\#% -test-mysql\#%: integrations.mysql.test generate-ini-mysql - GITEA_TEST_CONF=tests/mysql.ini ./integrations.mysql.test -test.run $(subst .,/,$*) - -.PHONY: test-mysql-migration -test-mysql-migration: migrations.mysql.test migrations.individual.mysql.test - -generate-ini-pgsql: - sed -e 's|{{TEST_PGSQL_HOST}}|${TEST_PGSQL_HOST}|g' \ - -e 's|{{TEST_PGSQL_DBNAME}}|${TEST_PGSQL_DBNAME}|g' \ - -e 's|{{TEST_PGSQL_USERNAME}}|${TEST_PGSQL_USERNAME}|g' \ - -e 's|{{TEST_PGSQL_PASSWORD}}|${TEST_PGSQL_PASSWORD}|g' \ - -e 's|{{TEST_PGSQL_SCHEMA}}|${TEST_PGSQL_SCHEMA}|g' \ - -e 's|{{TEST_MINIO_ENDPOINT}}|${TEST_MINIO_ENDPOINT}|g' \ - -e 's|{{WORK_PATH}}|$(CURDIR)/tests/$(or $(TEST_TYPE),integration)/gitea-$(or $(TEST_TYPE),integration)-pgsql|g' \ - -e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \ - tests/pgsql.ini.tmpl > tests/pgsql.ini - -.PHONY: test-pgsql -test-pgsql: integrations.pgsql.test generate-ini-pgsql - GITEA_TEST_CONF=tests/pgsql.ini ./integrations.pgsql.test - -.PHONY: test-pgsql\#% -test-pgsql\#%: integrations.pgsql.test generate-ini-pgsql - GITEA_TEST_CONF=tests/pgsql.ini ./integrations.pgsql.test -test.run $(subst .,/,$*) - -.PHONY: test-pgsql-migration -test-pgsql-migration: migrations.pgsql.test migrations.individual.pgsql.test - -generate-ini-mssql: - sed -e 's|{{TEST_MSSQL_HOST}}|${TEST_MSSQL_HOST}|g' \ - -e 's|{{TEST_MSSQL_DBNAME}}|${TEST_MSSQL_DBNAME}|g' \ - -e 's|{{TEST_MSSQL_USERNAME}}|${TEST_MSSQL_USERNAME}|g' \ - -e 's|{{TEST_MSSQL_PASSWORD}}|${TEST_MSSQL_PASSWORD}|g' \ - -e 's|{{WORK_PATH}}|$(CURDIR)/tests/$(or $(TEST_TYPE),integration)/gitea-$(or $(TEST_TYPE),integration)-mssql|g' \ - -e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \ - tests/mssql.ini.tmpl > tests/mssql.ini - -.PHONY: test-mssql -test-mssql: integrations.mssql.test generate-ini-mssql - GITEA_TEST_CONF=tests/mssql.ini ./integrations.mssql.test - -.PHONY: test-mssql\#% -test-mssql\#%: integrations.mssql.test generate-ini-mssql - GITEA_TEST_CONF=tests/mssql.ini ./integrations.mssql.test -test.run $(subst .,/,$*) - -.PHONY: test-mssql-migration -test-mssql-migration: migrations.mssql.test migrations.individual.mssql.test +.PHONY: migrations.individual.test\#% +migrations.individual.test\#%: + $(GO) test $(GOTEST_FLAGS) -tags '$(TAGS)' gitea.dev/models/migrations/$* .PHONY: playwright playwright: deps-frontend - @# on GitHub Actions VMs, playwright's system deps are pre-installed - @pnpm exec playwright install $(if $(GITHUB_ACTIONS),,--with-deps) chromium firefox $(PLAYWRIGHT_FLAGS) + @CONTAINER_RUNTIME=$(CONTAINER_RUNTIME) ./tools/test-e2e.sh install .PHONY: test-e2e -test-e2e: playwright $(EXECUTABLE_E2E) - @EXECUTABLE=$(EXECUTABLE_E2E) ./tools/test-e2e.sh $(GITEA_TEST_E2E_FLAGS) - -.PHONY: bench-sqlite -bench-sqlite: integrations.sqlite.test generate-ini-sqlite - GITEA_TEST_CONF=tests/sqlite.ini ./integrations.sqlite.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench . - -.PHONY: bench-mysql -bench-mysql: integrations.mysql.test generate-ini-mysql - GITEA_TEST_CONF=tests/mysql.ini ./integrations.mysql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench . - -.PHONY: bench-mssql -bench-mssql: integrations.mssql.test generate-ini-mssql - GITEA_TEST_CONF=tests/mssql.ini ./integrations.mssql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench . - -.PHONY: bench-pgsql -bench-pgsql: integrations.pgsql.test generate-ini-pgsql - GITEA_TEST_CONF=tests/pgsql.ini ./integrations.pgsql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench . - -.PHONY: integration-test-coverage -integration-test-coverage: integrations.cover.test generate-ini-mysql - GITEA_TEST_CONF=tests/mysql.ini ./integrations.cover.test -test.coverprofile=integration.coverage.out - -.PHONY: integration-test-coverage-sqlite -integration-test-coverage-sqlite: integrations.cover.sqlite.test generate-ini-sqlite - GITEA_TEST_CONF=tests/sqlite.ini ./integrations.cover.sqlite.test -test.coverprofile=integration.coverage.out - -integrations.mysql.test: git-check $(GO_SOURCES) - $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.mysql.test - -integrations.pgsql.test: git-check $(GO_SOURCES) - $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.pgsql.test - -integrations.mssql.test: git-check $(GO_SOURCES) - $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.mssql.test - -integrations.sqlite.test: git-check $(GO_SOURCES) - $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.sqlite.test -tags '$(TEST_TAGS)' - -integrations.cover.test: git-check $(GO_SOURCES) - $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -coverpkg $(shell echo $(GO_TEST_PACKAGES) | tr ' ' ',') -o integrations.cover.test - -integrations.cover.sqlite.test: git-check $(GO_SOURCES) - $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -coverpkg $(shell echo $(GO_TEST_PACKAGES) | tr ' ' ',') -o integrations.cover.sqlite.test -tags '$(TEST_TAGS)' - -.PHONY: migrations.mysql.test -migrations.mysql.test: $(GO_SOURCES) generate-ini-mysql - $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.mysql.test - GITEA_TEST_CONF=tests/mysql.ini ./migrations.mysql.test - -.PHONY: migrations.pgsql.test -migrations.pgsql.test: $(GO_SOURCES) generate-ini-pgsql - $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.pgsql.test - GITEA_TEST_CONF=tests/pgsql.ini ./migrations.pgsql.test - -.PHONY: migrations.mssql.test -migrations.mssql.test: $(GO_SOURCES) generate-ini-mssql - $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.mssql.test - GITEA_TEST_CONF=tests/mssql.ini ./migrations.mssql.test - -.PHONY: migrations.sqlite.test -migrations.sqlite.test: $(GO_SOURCES) generate-ini-sqlite - $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.sqlite.test -tags '$(TEST_TAGS)' - GITEA_TEST_CONF=tests/sqlite.ini ./migrations.sqlite.test - -.PHONY: migrations.individual.mysql.test -migrations.individual.mysql.test: $(GO_SOURCES) generate-ini-mysql - GITEA_TEST_CONF=tests/mysql.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES) - -.PHONY: migrations.individual.sqlite.test\#% -migrations.individual.sqlite.test\#%: $(GO_SOURCES) generate-ini-sqlite - GITEA_TEST_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$* - -.PHONY: migrations.individual.pgsql.test -migrations.individual.pgsql.test: $(GO_SOURCES) generate-ini-pgsql - GITEA_TEST_CONF=tests/pgsql.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES) - -.PHONY: migrations.individual.pgsql.test\#% -migrations.individual.pgsql.test\#%: $(GO_SOURCES) generate-ini-pgsql - GITEA_TEST_CONF=tests/pgsql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$* - -.PHONY: migrations.individual.mssql.test -migrations.individual.mssql.test: $(GO_SOURCES) generate-ini-mssql - GITEA_TEST_CONF=tests/mssql.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES) - -.PHONY: migrations.individual.mssql.test\#% -migrations.individual.mssql.test\#%: $(GO_SOURCES) generate-ini-mssql - GITEA_TEST_CONF=tests/mssql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$* - -.PHONY: migrations.individual.sqlite.test -migrations.individual.sqlite.test: $(GO_SOURCES) generate-ini-sqlite - GITEA_TEST_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES) - -.PHONY: migrations.individual.sqlite.test\#% -migrations.individual.sqlite.test\#%: $(GO_SOURCES) generate-ini-sqlite - GITEA_TEST_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$* - -.PHONY: check -check: test - -.PHONY: install $(TAGS_PREREQ) -install: $(wildcard *.go) - CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) install -v -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' +test-e2e: playwright frontend backend + @CONTAINER_RUNTIME=$(CONTAINER_RUNTIME) EXECUTABLE=$(EXECUTABLE) ./tools/test-e2e.sh run $(GITEA_TEST_E2E_FLAGS) .PHONY: build build: frontend backend ## build everything @@ -663,9 +514,6 @@ ifneq ($(and $(STATIC),$(findstring pam,$(TAGS))),) endif CGO_ENABLED="$(CGO_ENABLED)" CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(EXTLDFLAGS) $(LDFLAGS)' -o $@ -$(EXECUTABLE_E2E): $(GO_SOURCES) $(FRONTEND_DEST) - CGO_ENABLED=1 $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TEST_TAGS)' -ldflags '-s -w $(EXTLDFLAGS) $(LDFLAGS)' -o $@ - .PHONY: release release: frontend generate release-windows release-linux release-darwin release-freebsd release-copy release-compress vendor release-sources release-check @@ -730,7 +578,6 @@ deps-backend: ## install backend dependencies deps-tools: ## install tool dependencies $(GO) install $(AIR_PACKAGE) & \ $(GO) install $(EDITORCONFIG_CHECKER_PACKAGE) & \ - $(GO) install $(GOFUMPT_PACKAGE) & \ $(GO) install $(GOLANGCI_LINT_PACKAGE) & \ $(GO) install $(GXZ_PACKAGE) & \ $(GO) install $(MISSPELL_PACKAGE) & \ @@ -761,8 +608,6 @@ update-js: node_modules ## update js dependencies pnpm exec updates -u -f package.json rm -rf node_modules pnpm-lock.yaml pnpm install - pnpm exec nolyfill install - pnpm install @touch node_modules .PHONY: update-py @@ -789,10 +634,10 @@ svg: node_modules ## build svg files .PHONY: svg-check svg-check: svg - @git add $(SVG_DEST_DIR) - @diff=$$(git diff --color=always --cached $(SVG_DEST_DIR)); \ + @git add $(SVG_DEST_DIRS) + @diff=$$(git diff --color=always --cached $(SVG_DEST_DIRS)); \ if [ -n "$$diff" ]; then \ - echo "Please run 'make svg' and 'git add $(SVG_DEST_DIR)' and commit the result:"; \ + echo "Please run 'make svg' and 'git add $(SVG_DEST_DIRS)' and commit the result:"; \ printf "%s" "$${diff}"; \ exit 1; \ fi @@ -816,6 +661,10 @@ generate-gitignore: ## update gitignore files generate-images: | node_modules ## generate images cd tools && node generate-images.ts $(TAGS) +.PHONY: generate-codemirror-languages +generate-codemirror-languages: | node_modules ## generate codemirror languages + node tools/generate-codemirror-languages.ts + .PHONY: generate-manpage generate-manpage: ## generate manpage @[ -f gitea ] || make backend @@ -824,11 +673,6 @@ generate-manpage: ## generate manpage @gzip -9 man/man1/gitea.1 && echo man/man1/gitea.1.gz created @#TODO A small script that formats config-cheat-sheet.en-us.md nicely for use as a config man page -.PHONY: docker -docker: - docker build --disable-content-trust=false -t $(DOCKER_REF) . -# support also build args docker build --build-arg GITEA_VERSION=v1.2.3 --build-arg TAGS="bindata sqlite sqlite_unlock_notify" . - # Disable parallel execution because it would break some targets that don't # specify exact dependencies like 'backend' which does currently not depend # on 'frontend' to enable Node.js-less builds from source tarballs. diff --git a/package/gitea/source/README.md b/package/gitea/source/README.md index 7ebeac97..521f2baf 100644 --- a/package/gitea/source/README.md +++ b/package/gitea/source/README.md @@ -2,8 +2,8 @@ [![](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml/badge.svg?branch=main)](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml?query=branch%3Amain "Release Nightly") [![](https://img.shields.io/discord/322538954119184384.svg?logo=discord&logoColor=white&label=Discord&color=5865F2)](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea") -[![](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea "Go Report Card") -[![](https://pkg.go.dev/badge/code.gitea.io/gitea?status.svg)](https://pkg.go.dev/code.gitea.io/gitea "GoDoc") +[![](https://goreportcard.com/badge/gitea.dev)](https://goreportcard.com/report/gitea.dev "Go Report Card") +[![](https://pkg.go.dev/badge/gitea.dev?status.svg)](https://pkg.go.dev/gitea.dev "GoDoc") [![](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest "GitHub release") [![](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source") [![](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea "Become a backer/sponsor of gitea") @@ -14,21 +14,21 @@ ## Purpose -The goal of this project is to make the easiest, fastest, and most -painless way of setting up a self-hosted Git service. +The goal of Gitea is to make the easiest, fastest, and most painless way of +setting up a self-hosted all-in-one software development service, +including Git hosting, code management, code review, issue tracking, project kanban, wiki, +team collaboration, package registry and CI/CD which can reuse GitHub Actions. As Gitea is written in Go, it works across **all** the platforms and -architectures that are supported by Go, including Linux, macOS, and -Windows on x86, amd64, ARM and PowerPC architectures. -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. +architectures that are supported by Go, including Linux, macOS, FreeBSD/OpenBSD and Windows +on x86, amd64, ARM, RISC-V 64 and PowerPC architectures. 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). -To quickly deploy your own dedicated Gitea instance on Gitea Cloud, you can start a free trial at [cloud.gitea.com](https://cloud.gitea.com). +To quickly deploy your own dedicated Gitea instance on Gitea Cloud, you can start a free trial at [cloud.gitea.com](https://cloud.gitea.com), +or use container (docker/podman/etc) to deploy on your own server with the [official image](https://hub.docker.com/r/gitea/gitea). ## Documentation @@ -40,31 +40,12 @@ If you have any suggestions or would like to contribute to it, you can visit the ## Building -From the root of the source tree, run: +See [docs/build-setup.md](docs/build-setup.md) for prerequisites +and [docs/development.md](docs/development.md) for setting up a local development environment, linting, and testing. - TAGS="bindata" make build +If you'd like to build from source or make a distribution package, see [docs/build-source.md](docs/build-source.md) for more information. -or if SQLite support is required: - - TAGS="bindata sqlite sqlite_unlock_notify" make build - -The `build` target is split into two sub-targets: - -- `make backend` which requires [Go Stable](https://go.dev/dl/), the required version is defined in [go.mod](/go.mod). -- `make frontend` which requires [Node.js LTS](https://nodejs.org/en/download/) or greater and [pnpm](https://pnpm.io/installation). - -Internet connectivity is required to download the go and npm modules. When building from the official source tarballs which include pre-built frontend files, the `frontend` target will not be triggered, making it possible to build without Node.js. - -More info: https://docs.gitea.com/installation/install-from-source - -## Using - -After building, a binary file named `gitea` will be generated in the root of the source tree by default. To run it, use: - - ./gitea web - -> [!NOTE] -> If you're interested in using our APIs, we have experimental support with [documentation](https://docs.gitea.com/api). +After building, you can run `./gitea web` to start the server, or `./gitea help` to see all available commands. ## Contributing @@ -73,7 +54,8 @@ Expected workflow is: Fork -> Patch -> Push -> Pull Request > [!NOTE] > > 1. **YOU MUST READ THE [CONTRIBUTORS GUIDE](CONTRIBUTING.md) BEFORE STARTING TO WORK ON A PULL REQUEST.** -> 2. If you have found a vulnerability in the project, please write privately to **security@gitea.io**. Thanks! +> 2. New to the codebase? The [development guide](docs/development.md) walks through setting up a local environment and building from source. +> 3. If you have found a vulnerability in the project, please write privately to **security@gitea.io**. Thanks! ## Translating @@ -130,14 +112,19 @@ Support this project by becoming a sponsor. Your logo will show up here with a l Gitea is pronounced [/ɡɪ’ti:/](https://youtu.be/EM71-2uDAoY) as in "gi-tea" with a hard g. -**Why is this not hosted on a Gitea instance?** +**How do I configure Gitea?** -We're [working on it](https://github.com/go-gitea/gitea/issues/1029). +For dynamic config options, you can change it on your admin panel's configuration section. + +For static config options, you can edit your `app.ini` file and resart the instance. +See [app.example.ini](https://github.com/go-gitea/gitea/blob/main/custom/conf/app.example.ini) or [configuration documentation](https://docs.gitea.com/administration/config-cheat-sheet) for more details. **Where can I find the security patches?** In the [release log](https://github.com/go-gitea/gitea/releases) or the [change log](https://github.com/go-gitea/gitea/blob/main/CHANGELOG.md), search for the keyword `SECURITY` to find the security patches. +(more FAQs are listed in [FAQ documentation](https://docs.gitea.com/help/faq)) + ## License This project is licensed under the MIT License. @@ -147,7 +134,7 @@ for the full license text. ## Further information
-Looking for an overview of the interface? Check it out! +Looking for an overview of the interface? Check it out the screenshots! ### Login/Register Page diff --git a/package/gitea/source/README.zh-cn.md b/package/gitea/source/README.zh-cn.md index 8ccacc0f..0855827f 100644 --- a/package/gitea/source/README.zh-cn.md +++ b/package/gitea/source/README.zh-cn.md @@ -2,8 +2,8 @@ [![](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml/badge.svg?branch=main)](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml?query=branch%3Amain "Release Nightly") [![](https://img.shields.io/discord/322538954119184384.svg?logo=discord&logoColor=white&label=Discord&color=5865F2)](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea") -[![](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea "Go Report Card") -[![](https://pkg.go.dev/badge/code.gitea.io/gitea?status.svg)](https://pkg.go.dev/code.gitea.io/gitea "GoDoc") +[![](https://goreportcard.com/badge/gitea.dev)](https://goreportcard.com/report/gitea.dev "Go Report Card") +[![](https://pkg.go.dev/badge/gitea.dev?status.svg)](https://pkg.go.dev/gitea.dev "GoDoc") [![](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest "GitHub release") [![](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source") [![](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea "Become a backer/sponsor of gitea") @@ -38,10 +38,6 @@ TAGS="bindata" make build -如果需要 SQLite 支持: - - TAGS="bindata sqlite sqlite_unlock_notify" make build - `build` 目标分为两个子目标: - `make backend` 需要 [Go Stable](https://go.dev/dl/),所需版本在 [go.mod](/go.mod) 中定义。 diff --git a/package/gitea/source/README.zh-tw.md b/package/gitea/source/README.zh-tw.md index 4160fd0b..0c89d041 100644 --- a/package/gitea/source/README.zh-tw.md +++ b/package/gitea/source/README.zh-tw.md @@ -2,8 +2,8 @@ [![](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml/badge.svg?branch=main)](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml?query=branch%3Amain "Release Nightly") [![](https://img.shields.io/discord/322538954119184384.svg?logo=discord&logoColor=white&label=Discord&color=5865F2)](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea") -[![](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea "Go Report Card") -[![](https://pkg.go.dev/badge/code.gitea.io/gitea?status.svg)](https://pkg.go.dev/code.gitea.io/gitea "GoDoc") +[![](https://goreportcard.com/badge/gitea.dev)](https://goreportcard.com/report/gitea.dev "Go Report Card") +[![](https://pkg.go.dev/badge/gitea.dev?status.svg)](https://pkg.go.dev/gitea.dev "GoDoc") [![](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest "GitHub release") [![](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source") [![](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea "Become a backer/sponsor of gitea") @@ -38,10 +38,6 @@ TAGS="bindata" make build -如果需要 SQLite 支援: - - TAGS="bindata sqlite sqlite_unlock_notify" make build - `build` 目標分為兩個子目標: - `make backend` 需要 [Go Stable](https://go.dev/dl/),所需版本在 [go.mod](/go.mod) 中定義。 diff --git a/package/gitea/source/assets/codemirror-languages.json b/package/gitea/source/assets/codemirror-languages.json new file mode 100644 index 00000000..573e7c49 --- /dev/null +++ b/package/gitea/source/assets/codemirror-languages.json @@ -0,0 +1,1277 @@ +[ + { + "name": "APL", + "extensions": [ + "apl", + "dyalog" + ], + "filenames": [] + }, + { + "name": "ASN.1", + "extensions": [ + "asn", + "asn1" + ], + "filenames": [] + }, + { + "name": "Brainfuck", + "extensions": [ + "b", + "bf" + ], + "filenames": [] + }, + { + "name": "C", + "extensions": [ + "c", + "cats", + "h", + "idc" + ], + "filenames": [] + }, + { + "name": "C#", + "extensions": [ + "cs", + "cake", + "csx", + "linq" + ], + "filenames": [] + }, + { + "name": "C++", + "extensions": [ + "cpp", + "c++", + "cc", + "cp", + "cppm", + "cxx", + "h++", + "hh", + "hpp", + "hxx", + "inl", + "ipp", + "ixx", + "re", + "tcc", + "tpp", + "txx" + ], + "filenames": [] + }, + { + "name": "Clojure", + "extensions": [ + "clj", + "bb", + "boot", + "cl2", + "cljc", + "cljscm", + "cljx", + "hic" + ], + "filenames": [ + "riemann.config" + ] + }, + { + "name": "CMake", + "extensions": [ + "cmake" + ], + "filenames": [ + "CMakeLists.txt" + ] + }, + { + "name": "Cobol", + "extensions": [ + "cob", + "cbl", + "ccp", + "cobol", + "cpy" + ], + "filenames": [] + }, + { + "name": "CoffeeScript", + "extensions": [ + "coffee", + "_coffee", + "cake", + "cjsx", + "iced" + ], + "filenames": [ + "Cakefile" + ] + }, + { + "name": "Common Lisp", + "extensions": [ + "lisp", + "asd", + "cl", + "l", + "lsp", + "ny", + "podsl", + "sexp" + ], + "filenames": [] + }, + { + "name": "CQL", + "extensions": [ + "cql" + ], + "filenames": [] + }, + { + "name": "Crystal", + "extensions": [ + "cr" + ], + "filenames": [] + }, + { + "name": "CSS", + "extensions": [ + "css" + ], + "filenames": [] + }, + { + "name": "Cypher", + "extensions": [ + "cyp", + "cypher" + ], + "filenames": [] + }, + { + "name": "Cython", + "extensions": [ + "pyx", + "pxd", + "pxi" + ], + "filenames": [] + }, + { + "name": "D", + "extensions": [ + "d", + "di" + ], + "filenames": [] + }, + { + "name": "Dart", + "extensions": [ + "dart" + ], + "filenames": [] + }, + { + "name": "diff", + "extensions": [ + "diff", + "patch" + ], + "filenames": [] + }, + { + "name": "Dylan", + "extensions": [ + "dylan", + "dyl", + "intr", + "lid" + ], + "filenames": [] + }, + { + "name": "EBNF", + "extensions": [ + "ebnf" + ], + "filenames": [] + }, + { + "name": "ECL", + "extensions": [ + "ecl", + "eclxml" + ], + "filenames": [] + }, + { + "name": "edn", + "extensions": [ + "edn" + ], + "filenames": [] + }, + { + "name": "Eiffel", + "extensions": [ + "e" + ], + "filenames": [] + }, + { + "name": "Elm", + "extensions": [ + "elm" + ], + "filenames": [] + }, + { + "name": "Erlang", + "extensions": [ + "erl", + "app", + "es", + "escript", + "hrl", + "xrl", + "yrl" + ], + "filenames": [ + "Emakefile", + "rebar.config", + "rebar.config.lock", + "rebar.lock" + ] + }, + { + "name": "F#", + "extensions": [ + "fs", + "fsi", + "fsx" + ], + "filenames": [] + }, + { + "name": "Factor", + "extensions": [ + "factor" + ], + "filenames": [ + ".factor-boot-rc", + ".factor-rc" + ] + }, + { + "name": "Forth", + "extensions": [ + "fth", + "4th", + "forth", + "fr", + "frt" + ], + "filenames": [] + }, + { + "name": "Fortran", + "extensions": [ + "f", + "f77", + "for", + "fpp" + ], + "filenames": [] + }, + { + "name": "Gherkin", + "extensions": [ + "feature", + "story" + ], + "filenames": [] + }, + { + "name": "Go", + "extensions": [ + "go" + ], + "filenames": [] + }, + { + "name": "Groovy", + "extensions": [ + "groovy", + "grt", + "gtpl", + "gvy" + ], + "filenames": [ + "Jenkinsfile" + ] + }, + { + "name": "Haskell", + "extensions": [ + "hs", + "hs-boot", + "hsc" + ], + "filenames": [] + }, + { + "name": "Haxe", + "extensions": [ + "hx", + "hxsl" + ], + "filenames": [] + }, + { + "name": "HTML", + "extensions": [ + "html", + "hta", + "htm", + "xht", + "xhtml" + ], + "filenames": [] + }, + { + "name": "HTTP", + "extensions": [ + "http" + ], + "filenames": [] + }, + { + "name": "HXML", + "extensions": [ + "hxml" + ], + "filenames": [] + }, + { + "name": "IDL", + "extensions": [ + "pro", + "dlm" + ], + "filenames": [] + }, + { + "name": "Java", + "extensions": [ + "java", + "jav", + "jsh" + ], + "filenames": [] + }, + { + "name": "JavaScript", + "extensions": [ + "js", + "_js", + "bones", + "cjs", + "es", + "es6", + "frag", + "gs", + "jake", + "javascript", + "jsb", + "jscad", + "jsfl", + "jslib", + "jsm", + "jspre", + "jss", + "mjs", + "njs", + "pac", + "sjs", + "ssjs", + "xsjs", + "xsjslib" + ], + "filenames": [ + "Jakefile" + ] + }, + { + "name": "Jinja", + "extensions": [ + "jinja", + "j2", + "jinja2" + ], + "filenames": [] + }, + { + "name": "JSON", + "extensions": [ + "json", + "4DForm", + "4DProject", + "avsc", + "geojson", + "gltf", + "har", + "ice", + "JSON-tmLanguage", + "jsonl", + "mcmeta", + "sarif", + "tact", + "tfstate", + "topojson", + "webapp", + "webmanifest", + "yy", + "yyp" + ], + "filenames": [ + ".all-contributorsrc", + ".arcconfig", + ".auto-changelog", + ".c8rc", + ".htmlhintrc", + ".imgbotconfig", + ".nycrc", + ".tern-config", + ".tern-project", + ".watchmanconfig", + "MODULE.bazel.lock", + "Package.resolved", + "Pipfile.lock", + "bun.lock", + "composer.lock", + "deno.lock", + "flake.lock", + "mcmod.info" + ] + }, + { + "name": "JSON-LD", + "extensions": [ + "jsonld" + ], + "filenames": [] + }, + { + "name": "Julia", + "extensions": [ + "jl" + ], + "filenames": [] + }, + { + "name": "Kotlin", + "extensions": [ + "kt", + "ktm", + "kts" + ], + "filenames": [] + }, + { + "name": "LaTeX", + "extensions": [ + "tex", + "aux", + "bbx", + "cbx", + "cls", + "dtx", + "ins", + "lbx", + "ltx", + "mkii", + "mkiv", + "mkvi", + "sty", + "toc" + ], + "filenames": [] + }, + { + "name": "LESS", + "extensions": [ + "less" + ], + "filenames": [] + }, + { + "name": "Liquid", + "extensions": [ + "liquid" + ], + "filenames": [] + }, + { + "name": "LiveScript", + "extensions": [ + "ls", + "_ls" + ], + "filenames": [ + "Slakefile" + ] + }, + { + "name": "Lua", + "extensions": [ + "lua", + "nse", + "p8", + "pd_lua", + "rbxs", + "rockspec", + "wlua" + ], + "filenames": [ + ".luacheckrc" + ] + }, + { + "name": "Modelica", + "extensions": [ + "mo" + ], + "filenames": [] + }, + { + "name": "Nginx", + "extensions": [ + "nginx", + "nginxconf", + "vhost" + ], + "filenames": [ + "nginx.conf" + ] + }, + { + "name": "NSIS", + "extensions": [ + "nsi", + "nsh" + ], + "filenames": [] + }, + { + "name": "Objective-C", + "extensions": [], + "filenames": [] + }, + { + "name": "Objective-C++", + "extensions": [ + "mm" + ], + "filenames": [] + }, + { + "name": "OCaml", + "extensions": [ + "ml", + "eliom", + "eliomi", + "ml4", + "mli", + "mll", + "mly" + ], + "filenames": [] + }, + { + "name": "Oz", + "extensions": [ + "oz" + ], + "filenames": [] + }, + { + "name": "Pascal", + "extensions": [ + "pas", + "dfm", + "dpr", + "lpr", + "pascal" + ], + "filenames": [] + }, + { + "name": "Perl", + "extensions": [ + "pl", + "al", + "perl", + "ph", + "plx", + "pm", + "psgi", + "t" + ], + "filenames": [ + ".latexmkrc", + "Makefile.PL", + "Rexfile", + "ack", + "cpanfile", + "latexmkrc" + ] + }, + { + "name": "PHP", + "extensions": [ + "php", + "aw", + "ctp", + "php3", + "php4", + "php5", + "phps", + "phpt" + ], + "filenames": [ + ".php", + ".php_cs", + ".php_cs.dist", + "Phakefile" + ] + }, + { + "name": "PLSQL", + "extensions": [ + "pls", + "bdy", + "ddl", + "fnc", + "pck", + "pkb", + "pks", + "plb", + "plsql", + "prc", + "spc", + "tpb", + "tps", + "trg", + "vw" + ], + "filenames": [] + }, + { + "name": "PowerShell", + "extensions": [ + "ps1", + "psd1", + "psm1" + ], + "filenames": [] + }, + { + "name": "Properties files", + "extensions": [ + "ini", + "cnf", + "dof", + "lektorproject", + "prefs", + "properties", + "url", + "conf" + ], + "filenames": [ + ".buckconfig", + ".coveragerc", + ".flake8", + ".pylintrc", + "HOSTS", + "buildozer.spec", + "hosts", + "pylintrc", + "vlcrc", + ".editorconfig", + ".gitconfig", + ".npmrc" + ] + }, + { + "name": "ProtoBuf", + "extensions": [ + "proto" + ], + "filenames": [] + }, + { + "name": "Pug", + "extensions": [ + "jade", + "pug" + ], + "filenames": [] + }, + { + "name": "Puppet", + "extensions": [ + "pp" + ], + "filenames": [ + "Modulefile" + ] + }, + { + "name": "Python", + "extensions": [ + "py", + "gyp", + "gypi", + "lmi", + "py3", + "pyde", + "pyi", + "pyp", + "pyt", + "pyw", + "rpy", + "tac", + "wsgi", + "xpy" + ], + "filenames": [ + ".gclient", + "DEPS", + "SConscript", + "SConstruct", + "wscript", + "Snakefile" + ] + }, + { + "name": "Q", + "extensions": [ + "q" + ], + "filenames": [] + }, + { + "name": "R", + "extensions": [ + "r", + "rd", + "rsx" + ], + "filenames": [ + ".Rprofile", + "expr-dist" + ] + }, + { + "name": "RPM Spec", + "extensions": [ + "spec" + ], + "filenames": [] + }, + { + "name": "Ruby", + "extensions": [ + "rb", + "builder", + "eye", + "gemspec", + "god", + "jbuilder", + "mspec", + "pluginspec", + "podspec", + "prawn", + "rabl", + "rake", + "rbi", + "rbuild", + "rbw", + "rbx", + "ru", + "ruby", + "thor", + "watchr" + ], + "filenames": [ + ".irbrc", + ".pryrc", + ".simplecov", + "Appraisals", + "Berksfile", + "Brewfile", + "Buildfile", + "Capfile", + "Dangerfile", + "Deliverfile", + "Fastfile", + "Gemfile", + "Guardfile", + "Jarfile", + "Mavenfile", + "Podfile", + "Puppetfile", + "Rakefile", + "Snapfile", + "Steepfile", + "Thorfile", + "Vagrantfile", + "buildfile" + ] + }, + { + "name": "Rust", + "extensions": [ + "rs" + ], + "filenames": [] + }, + { + "name": "SAS", + "extensions": [ + "sas" + ], + "filenames": [] + }, + { + "name": "Sass", + "extensions": [ + "sass" + ], + "filenames": [] + }, + { + "name": "Scala", + "extensions": [ + "scala", + "kojo", + "sbt", + "sc" + ], + "filenames": [] + }, + { + "name": "Scheme", + "extensions": [ + "scm", + "sch", + "sld", + "sls", + "sps", + "ss" + ], + "filenames": [] + }, + { + "name": "SCSS", + "extensions": [ + "scss" + ], + "filenames": [] + }, + { + "name": "Shell", + "extensions": [ + "sh", + "bash", + "bats", + "command", + "ksh", + "sbatch", + "slurm", + "tmux", + "tool", + "trigger", + "zsh", + "zsh-theme" + ], + "filenames": [ + ".bash_aliases", + ".bash_functions", + ".bash_history", + ".bash_logout", + ".bash_profile", + ".bashrc", + ".cshrc", + ".envrc", + ".flaskenv", + ".kshrc", + ".login", + ".profile", + ".tmux.conf", + ".xinitrc", + ".xsession", + ".zlogin", + ".zlogout", + ".zprofile", + ".zshenv", + ".zshrc", + "9fs", + "PKGBUILD", + "bash_aliases", + "bash_logout", + "bash_profile", + "bashrc", + "cshrc", + "gradlew", + "kshrc", + "login", + "man", + "mvnw", + "profile", + "tmux.conf", + "xinitrc", + "xsession", + "zlogin", + "zlogout", + "zprofile", + "zshenv", + "zshrc" + ] + }, + { + "name": "Sieve", + "extensions": [ + "sieve" + ], + "filenames": [] + }, + { + "name": "Smalltalk", + "extensions": [ + "st" + ], + "filenames": [] + }, + { + "name": "SPARQL", + "extensions": [ + "sparql", + "rq" + ], + "filenames": [] + }, + { + "name": "SQL", + "extensions": [ + "sql", + "ddl", + "mysql", + "prc", + "tab", + "udf", + "viw" + ], + "filenames": [] + }, + { + "name": "Squirrel", + "extensions": [ + "nut" + ], + "filenames": [] + }, + { + "name": "Stylus", + "extensions": [ + "styl" + ], + "filenames": [] + }, + { + "name": "Swift", + "extensions": [ + "swift" + ], + "filenames": [] + }, + { + "name": "SystemVerilog", + "extensions": [ + "sv", + "svh", + "vh" + ], + "filenames": [] + }, + { + "name": "Tcl", + "extensions": [ + "tcl", + "adp", + "sdc", + "tm", + "xdc" + ], + "filenames": [ + "owh", + "starfield" + ] + }, + { + "name": "Textile", + "extensions": [ + "textile" + ], + "filenames": [] + }, + { + "name": "TOML", + "extensions": [ + "toml" + ], + "filenames": [ + "Cargo.lock", + "Cargo.toml.orig", + "Gopkg.lock", + "Pipfile", + "mise.local.lock", + "mise.lock", + "pdm.lock", + "poetry.lock", + "uv.lock" + ] + }, + { + "name": "TSX", + "extensions": [ + "tsx" + ], + "filenames": [] + }, + { + "name": "Turtle", + "extensions": [ + "ttl" + ], + "filenames": [] + }, + { + "name": "TypeScript", + "extensions": [ + "ts", + "cts", + "mts" + ], + "filenames": [] + }, + { + "name": "VBScript", + "extensions": [ + "vbs" + ], + "filenames": [] + }, + { + "name": "Verilog", + "extensions": [ + "veo" + ], + "filenames": [] + }, + { + "name": "VHDL", + "extensions": [ + "vhdl", + "vhd", + "vhf", + "vhi", + "vho", + "vhs", + "vht", + "vhw" + ], + "filenames": [] + }, + { + "name": "Vue", + "extensions": [ + "vue" + ], + "filenames": [] + }, + { + "name": "WebAssembly", + "extensions": [ + "wast", + "wat" + ], + "filenames": [] + }, + { + "name": "XML", + "extensions": [ + "xml", + "adml", + "admx", + "ant", + "axaml", + "axml", + "builds", + "ccproj", + "ccxml", + "clixml", + "cproject", + "cscfg", + "csdef", + "csl", + "csproj", + "ct", + "depproj", + "dita", + "ditamap", + "ditaval", + "dotsettings", + "filters", + "fsproj", + "fxml", + "glade", + "gml", + "gmx", + "gpx", + "grxml", + "gst", + "hzp", + "icls", + "iml", + "ivy", + "jelly", + "jsproj", + "kml", + "launch", + "mdpolicy", + "mjml", + "mod", + "mojo", + "mxml", + "natvis", + "ncl", + "ndproj", + "nproj", + "nuspec", + "odd", + "osm", + "pkgproj", + "pluginspec", + "proj", + "props", + "ps1xml", + "psc1", + "pt", + "pubxml", + "qhelp", + "rdf", + "res", + "resx", + "rss", + "sch", + "scxml", + "sfproj", + "shproj", + "slnx", + "srdf", + "storyboard", + "sublime-snippet", + "sw", + "targets", + "tml", + "typ", + "ui", + "urdf", + "ux", + "vbproj", + "vcxproj", + "vsixmanifest", + "vssettings", + "vstemplate", + "vxml", + "wixproj", + "workflow", + "wsdl", + "wsf", + "wxi", + "wxl", + "wxs", + "x3d", + "xacro", + "xaml", + "xib", + "xlf", + "xliff", + "xmi", + "xmp", + "xproj", + "xsd", + "xspec", + "xul", + "zcml" + ], + "filenames": [ + ".classpath", + ".cproject", + ".project", + "App.config", + "NuGet.config", + "Settings.StyleCop", + "Web.Debug.config", + "Web.Release.config", + "Web.config", + "packages.config" + ] + }, + { + "name": "XQuery", + "extensions": [ + "xquery", + "xq", + "xql", + "xqm", + "xqy" + ], + "filenames": [] + }, + { + "name": "YAML", + "extensions": [ + "yml", + "mir", + "reek", + "rviz", + "sublime-syntax", + "syntax", + "yaml", + "yaml-tmlanguage" + ], + "filenames": [ + ".clang-format", + ".clang-tidy", + ".clangd", + ".gemrc", + "CITATION.cff", + "glide.lock", + "pixi.lock", + "yarn.lock" + ] + } +] diff --git a/package/gitea/source/assets/go-licenses.json b/package/gitea/source/assets/go-licenses.json index 61bf7670..7b76688f 100644 --- a/package/gitea/source/assets/go-licenses.json +++ b/package/gitea/source/assets/go-licenses.json @@ -4,21 +4,6 @@ "path": "cloud.google.com/go/compute/metadata/LICENSE", "licenseText": "\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 [yyyy] [name of copyright owner]\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": "code.gitea.io/actions-proto-go", - "path": "code.gitea.io/actions-proto-go/LICENSE", - "licenseText": "MIT License\n\nCopyright (c) 2022 The Gitea 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": "code.gitea.io/gitea/modules/lfs", - "path": "code.gitea.io/gitea/modules/lfs/LICENSE", - "licenseText": "Copyright (c) 2016 The Gitea Authors\nCopyright (c) GitHub, Inc. and LFS Test Server contributors\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" - }, - { - "name": "code.gitea.io/sdk/gitea", - "path": "code.gitea.io/sdk/gitea/LICENSE", - "licenseText": "Copyright (c) 2016 The Gitea Authors\nCopyright (c) 2014 The Gogs Authors\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\nall copies 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\nTHE SOFTWARE.\n" - }, { "name": "codeberg.org/gusted/mcaptcha", "path": "codeberg.org/gusted/mcaptcha/LICENSE", @@ -39,6 +24,16 @@ "path": "filippo.io/edwards25519/LICENSE", "licenseText": "Copyright (c) 2009 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": "gitea.com/gitea/runner", + "path": "gitea.com/gitea/runner/LICENSE", + "licenseText": "Copyright (c) 2022 The Gitea Authors\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\nall copies 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\nTHE SOFTWARE.\n" + }, + { + "name": "gitea.com/gitea/runner/act", + "path": "gitea.com/gitea/runner/act/LICENSE", + "licenseText": "MIT License\n\nCopyright (c) 2022 The Gitea Authors\nCopyright (c) 2019\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" + }, { "name": "gitea.com/go-chi/binding", "path": "gitea.com/go-chi/binding/LICENSE", @@ -69,6 +64,21 @@ "path": "gitea.com/lunny/levelqueue/LICENSE", "licenseText": "Copyright (c) 2019 Lunny Xiao\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\nall copies 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\nTHE SOFTWARE.\n" }, + { + "name": "gitea.dev/actions-proto-go", + "path": "gitea.dev/actions-proto-go/LICENSE", + "licenseText": "MIT License\n\nCopyright (c) 2022 The Gitea 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": "gitea.dev/modules/lfs", + "path": "gitea.dev/modules/lfs/LICENSE", + "licenseText": "Copyright (c) 2016 The Gitea Authors\nCopyright (c) GitHub, Inc. and LFS Test Server contributors\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" + }, + { + "name": "gitea.dev/sdk", + "path": "gitea.dev/sdk/LICENSE", + "licenseText": "Copyright (c) 2016 The Gitea Authors\nCopyright (c) 2014 The Gogs Authors\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\nall copies 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\nTHE SOFTWARE.\n" + }, { "name": "github.com/42wim/httpsig", "path": "github.com/42wim/httpsig/LICENSE", @@ -104,6 +114,11 @@ "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/Necoro/html2text", + "path": "github.com/Necoro/html2text/LICENSE", + "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2015 Jay Taylor\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" + }, { "name": "github.com/ProtonMail/go-crypto", "path": "github.com/ProtonMail/go-crypto/LICENSE", @@ -132,7 +147,7 @@ { "name": "github.com/alecthomas/chroma/v2", "path": "github.com/alecthomas/chroma/v2/COPYING", - "licenseText": "Copyright (C) 2017 Alec Thomas\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\nof the Software, and to permit persons to whom the Software is furnished to do\nso, 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" + "licenseText": "Copyright (C) 2017 Alec Thomas\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\nof the Software, and to permit persons to whom the Software is furnished to do\nso, 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\n// formatters/svg/font_liberation_mono.go\n\nDigitized data copyright (c) 2010 Google Corporation\nwith Reserved Font Arimo, Tinos and Cousine.\nCopyright (c) 2012 Red Hat, Inc.\nwith Reserved Font Name Liberation.\n\nThis Font Software is licensed under the SIL Open Font License, Version 1.1.\nThis license is copied below, and is also available with a FAQ at:\nhttps://openfontlicense.org\n\n-----------------------------------------------------------\nSIL OPEN FONT LICENSE Version 1.1 - 26 February 2007\n-----------------------------------------------------------\n\nPREAMBLE\nThe goals of the Open Font License (OFL) are to stimulate worldwide\ndevelopment of collaborative font projects, to support the font creation\nefforts of academic and linguistic communities, and to provide a free and\nopen framework in which fonts may be shared and improved in partnership\nwith others.\n\nThe OFL allows the licensed fonts to be used, studied, modified and\nredistributed freely as long as they are not sold by themselves. The\nfonts, including any derivative works, can be bundled, embedded,\nredistributed and/or sold with any software provided that any reserved\nnames are not used by derivative works. The fonts and derivatives,\nhowever, cannot be released under any other type of license. The\nrequirement for fonts to remain under this license does not apply\nto any document created using the fonts or their derivatives.\n\nDEFINITIONS\n\"Font Software\" refers to the set of files released by the Copyright\nHolder(s) under this license and clearly marked as such. This may\ninclude source files, build scripts and documentation.\n\n\"Reserved Font Name\" refers to any names specified as such after the\ncopyright statement(s).\n\n\"Original Version\" refers to the collection of Font Software components as\ndistributed by the Copyright Holder(s).\n\n\"Modified Version\" refers to any derivative made by adding to, deleting,\nor substituting -- in part or in whole -- any of the components of the\nOriginal Version, by changing formats or by porting the Font Software to a\nnew environment.\n\n\"Author\" refers to any designer, engineer, programmer, technical\nwriter or other person who contributed to the Font Software.\n\nPERMISSION \u0026 CONDITIONS\nPermission is hereby granted, free of charge, to any person obtaining\na copy of the Font Software, to use, study, copy, merge, embed, modify,\nredistribute, and sell modified and unmodified copies of the Font\nSoftware, subject to the following conditions:\n\n1) Neither the Font Software nor any of its individual components,\nin Original or Modified Versions, may be sold by itself.\n\n2) Original or Modified Versions of the Font Software may be bundled,\nredistributed and/or sold with any software, provided that each copy\ncontains the above copyright notice and this license. These can be\nincluded either as stand-alone text files, human-readable headers or\nin the appropriate machine-readable metadata fields within text or\nbinary files as long as those fields can be easily viewed by the user.\n\n3) No Modified Version of the Font Software may use the Reserved Font\nName(s) unless explicit written permission is granted by the corresponding\nCopyright Holder. This restriction only applies to the primary font name as\npresented to the users.\n\n4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font\nSoftware shall not be used to promote, endorse or advertise any\nModified Version, except to acknowledge the contribution(s) of the\nCopyright Holder(s) and the Author(s) or with their explicit written\npermission.\n\n5) The Font Software, modified or unmodified, in part or in whole,\nmust be distributed entirely under this license, and must not be\ndistributed under any other license. The requirement for fonts to\nremain under this license does not apply to any document created\nusing the Font Software.\n\nTERMINATION\nThis license becomes null and void if any of the above conditions are\nnot met.\n\nDISCLAIMER\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\nOF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE\nCOPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nINCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\nDAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM\nOTHER DEALINGS IN THE FONT SOFTWARE.\n" }, { "name": "github.com/andybalholm/brotli", @@ -207,7 +222,7 @@ { "name": "github.com/bits-and-blooms/bitset", "path": "github.com/bits-and-blooms/bitset/LICENSE", - "licenseText": "Copyright (c) 2014 Will Fitzgerald. 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" + "licenseText": "Copyright (c) 2014 the bitset 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/blakesmith/ar", @@ -304,6 +319,11 @@ "path": "github.com/blevesearch/zapx/v16/LICENSE", "licenseText": "\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 [yyyy] [name of copyright owner]\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." }, + { + "name": "github.com/blevesearch/zapx/v17", + "path": "github.com/blevesearch/zapx/v17/LICENSE", + "licenseText": "\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 [yyyy] [name of copyright owner]\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." + }, { "name": "github.com/bmatcuk/doublestar/v4", "path": "github.com/bmatcuk/doublestar/v4/LICENSE", @@ -420,18 +440,8 @@ "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/dgryski/go-rendezvous", - "path": "github.com/dgryski/go-rendezvous/LICENSE", - "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2017-2020 Damian Gryski \u003cdamian@gryski.com\u003e\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\nall copies 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\nTHE SOFTWARE.\n" - }, - { - "name": "github.com/dimiro1/reply", - "path": "github.com/dimiro1/reply/LICENSE", - "licenseText": "MIT License\n\nCopyright (c) Discourse\nCopyright (c) Claudemiro\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" - }, - { - "name": "github.com/dlclark/regexp2", - "path": "github.com/dlclark/regexp2/LICENSE", + "name": "github.com/dlclark/regexp2/v2", + "path": "github.com/dlclark/regexp2/v2/LICENSE", "licenseText": "The MIT License (MIT)\n\nCopyright (c) Doug Clark\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" }, { @@ -489,6 +499,11 @@ "path": "github.com/fxamacker/cbor/v2/LICENSE", "licenseText": "MIT License\n\nCopyright (c) 2019-present Faye Amacker\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." }, + { + "name": "github.com/getkin/kin-openapi", + "path": "github.com/getkin/kin-openapi/LICENSE", + "licenseText": "MIT License\n\nCopyright (c) 2017-2018 the project authors.\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" + }, { "name": "github.com/git-lfs/pktline", "path": "github.com/git-lfs/pktline/LICENSE.md", @@ -524,11 +539,6 @@ "path": "github.com/go-enry/go-enry/v2/LICENSE", "licenseText": "\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 [yyyy] [name of copyright owner]\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." }, - { - "name": "github.com/go-fed/httpsig", - "path": "github.com/go-fed/httpsig/LICENSE", - "licenseText": "BSD 3-Clause License\n\nCopyright (c) 2018, go-fed\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 copyright holder 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/go-git/gcfg", "path": "github.com/go-git/gcfg/LICENSE", @@ -544,16 +554,21 @@ "path": "github.com/go-git/go-git/v5/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 2018 Sourced Technologies, S.L.\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/go-ini/ini", - "path": "github.com/go-ini/ini/LICENSE", - "licenseText": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and\ndistribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright\nowner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities\nthat control, are controlled by, or are under common control with that entity.\nFor the purposes of this definition, \"control\" means (i) the power, direct or\nindirect, to cause the direction or management of such entity, whether by\ncontract or otherwise, or (ii) ownership of fifty percent (50%) or more of the\noutstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\npermissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including\nbut not limited to software source code, documentation source, and configuration\nfiles.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or\ntranslation of a Source form, including but not limited to compiled object code,\ngenerated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form, made\navailable under the License, as indicated by a copyright notice that is included\nin or attached to the work (an example is provided in the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form, that\nis based on (or derived from) the Work and for which the editorial revisions,\nannotations, elaborations, or other modifications represent, as a whole, an\noriginal work of authorship. For the purposes of this License, Derivative Works\nshall not include works that remain separable from, or merely link (or bind by\nname) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original version\nof the Work and any modifications or additions to that Work or Derivative Works\nthereof, that is intentionally submitted to Licensor for inclusion in the Work\nby the copyright owner or by an individual or Legal Entity authorized to submit\non behalf of the copyright owner. For the purposes of this definition,\n\"submitted\" means any form of electronic, verbal, or written communication sent\nto the Licensor or its representatives, including but not limited to\ncommunication on electronic mailing lists, source code control systems, and\nissue tracking systems that are managed by, or on behalf of, the Licensor for\nthe purpose of discussing and improving the Work, but excluding communication\nthat is conspicuously marked or otherwise designated in writing by the copyright\nowner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf\nof whom a Contribution has been received by Licensor and subsequently\nincorporated within the Work.\n\n2. Grant of Copyright License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable copyright license to reproduce, prepare Derivative Works of,\npublicly display, publicly perform, sublicense, and distribute the Work and such\nDerivative Works in Source or Object form.\n\n3. Grant of Patent License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable (except as stated in this section) patent license to make, have\nmade, use, offer to sell, sell, import, and otherwise transfer the Work, where\nsuch license applies only to those patent claims licensable by such Contributor\nthat are necessarily infringed by their Contribution(s) alone or by combination\nof their Contribution(s) with the Work to which such Contribution(s) was\nsubmitted. If You institute patent litigation against any entity (including a\ncross-claim or counterclaim in a lawsuit) alleging that the Work or a\nContribution incorporated within the Work constitutes direct or contributory\npatent infringement, then any patent licenses granted to You under this License\nfor that Work shall terminate as of the date such litigation is filed.\n\n4. Redistribution.\n\nYou may reproduce and distribute copies of the Work or Derivative Works thereof\nin any medium, with or without modifications, and in Source or Object form,\nprovided that You meet the following conditions:\n\nYou must give any other recipients of the Work or Derivative Works a copy of\nthis License; and\nYou must cause any modified files to carry prominent notices stating that You\nchanged the files; and\nYou must retain, in the Source form of any Derivative Works that You distribute,\nall copyright, patent, trademark, and attribution notices from the Source form\nof the Work, excluding those notices that do not pertain to any part of the\nDerivative Works; and\nIf the Work includes a \"NOTICE\" text file as part of its distribution, then any\nDerivative Works that You distribute must include a readable copy of the\nattribution notices contained within such NOTICE file, excluding those notices\nthat do not pertain to any part of the Derivative Works, in at least one of the\nfollowing places: within a NOTICE text file distributed as part of the\nDerivative Works; within the Source form or documentation, if provided along\nwith the Derivative Works; or, within a display generated by the Derivative\nWorks, if and wherever such third-party notices normally appear. The contents of\nthe NOTICE file are for informational purposes only and do not modify the\nLicense. You may add Your own attribution notices within Derivative Works that\nYou distribute, alongside or as an addendum to the NOTICE text from the Work,\nprovided that such additional attribution notices cannot be construed as\nmodifying the License.\nYou may add Your own copyright statement to Your modifications and may provide\nadditional or different license terms and conditions for use, reproduction, or\ndistribution of Your modifications, or for any such Derivative Works as a whole,\nprovided Your use, reproduction, and distribution of the Work otherwise complies\nwith the conditions stated in this License.\n\n5. Submission of Contributions.\n\nUnless You explicitly state otherwise, any Contribution intentionally submitted\nfor inclusion in the Work by You to the Licensor shall be under the terms and\nconditions of this License, without any additional terms or conditions.\nNotwithstanding the above, nothing herein shall supersede or modify the terms of\nany separate license agreement you may have executed with Licensor regarding\nsuch Contributions.\n\n6. Trademarks.\n\nThis License does not grant permission to use the trade names, trademarks,\nservice marks, or product names of the Licensor, except as required for\nreasonable and customary use in describing the origin of the Work and\nreproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\nUnless required by applicable law or agreed to in writing, Licensor provides the\nWork (and each Contributor provides its Contributions) on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,\nincluding, without limitation, any warranties or conditions of TITLE,\nNON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are\nsolely responsible for determining the appropriateness of using or\nredistributing the Work and assume any risks associated with Your exercise of\npermissions under this License.\n\n8. Limitation of Liability.\n\nIn no event and under no legal theory, whether in tort (including negligence),\ncontract, or otherwise, unless required by applicable law (such as deliberate\nand grossly negligent acts) or agreed to in writing, shall any Contributor be\nliable to You for damages, including any direct, indirect, special, incidental,\nor consequential damages of any character arising as a result of this License or\nout of the use or inability to use the Work (including but not limited to\ndamages for loss of goodwill, work stoppage, computer failure or malfunction, or\nany and all other commercial damages or losses), even if such Contributor has\nbeen advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\nWhile redistributing the Work or Derivative Works thereof, You may choose to\noffer, and charge a fee for, acceptance of support, warranty, indemnity, or\nother liability obligations and/or rights consistent with this License. However,\nin accepting such obligations, You may act only on Your own behalf and on Your\nsole responsibility, not on behalf of any other Contributor, and only if You\nagree to indemnify, defend, and hold each Contributor harmless for any liability\nincurred by, or claims asserted against, such Contributor by reason of your\naccepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\nTo apply the Apache License to your work, attach the following boilerplate\nnotice, with the fields enclosed by brackets \"[]\" replaced with your own\nidentifying information. (Don't include the brackets!) The text should be\nenclosed in the appropriate comment syntax for the file format. We also\nrecommend that a file or class name and description of purpose be included on\nthe same \"printed page\" as the copyright notice for easier identification within\nthird-party archives.\n\n Copyright 2014 Unknwon\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/go-ldap/ldap/v3", "path": "github.com/go-ldap/ldap/v3/LICENSE", "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2011-2015 Michael Mitton (mmitton@gmail.com)\nPortions copyright (c) 2015-2024 go-ldap Authors\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" }, + { + "name": "github.com/go-openapi/jsonpointer", + "path": "github.com/go-openapi/jsonpointer/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 [yyyy] [name of copyright owner]\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/go-openapi/swag/jsonname", + "path": "github.com/go-openapi/swag/jsonname/LICENSE", + "licenseText": "\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 [yyyy] [name of copyright owner]\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/go-redsync/redsync/v4", "path": "github.com/go-redsync/redsync/v4/LICENSE", @@ -624,19 +639,14 @@ "path": "github.com/golang/snappy/LICENSE", "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/btree", - "path": "github.com/google/btree/LICENSE", - "licenseText": "\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 [yyyy] [name of copyright owner]\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/google/flatbuffers", "path": "github.com/google/flatbuffers/LICENSE", "licenseText": "\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 [yyyy] [name of copyright owner]\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/google/go-github/v84", - "path": "github.com/google/go-github/v84/LICENSE", + "name": "github.com/google/go-github/v88", + "path": "github.com/google/go-github/v88/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" }, { @@ -734,11 +744,6 @@ "path": "github.com/inbucket/html2text/LICENSE", "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2015 Jay Taylor\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" }, - { - "name": "github.com/jaytaylor/html2text", - "path": "github.com/jaytaylor/html2text/LICENSE", - "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2015 Jay Taylor\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" - }, { "name": "github.com/jbenet/go-context", "path": "github.com/jbenet/go-context/LICENSE", @@ -754,11 +759,6 @@ "path": "github.com/jonboulle/clockwork/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 {yyyy} {name of copyright owner}\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/josharian/intern", - "path": "github.com/josharian/intern/license.md", - "licenseText": "MIT License\n\nCopyright (c) 2019 Josh Bleecher Snyder\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" - }, { "name": "github.com/json-iterator/go", "path": "github.com/json-iterator/go/LICENSE", @@ -824,11 +824,6 @@ "path": "github.com/libdns/libdns/LICENSE", "licenseText": "MIT License\n\nCopyright (c) 2020 Matthew Holt\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" }, - { - "name": "github.com/mailru/easyjson", - "path": "github.com/mailru/easyjson/LICENSE", - "licenseText": "Copyright (c) 2016 Mail.Ru Group\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/markbates/going", "path": "github.com/markbates/going/LICENSE.txt", @@ -939,11 +934,6 @@ "path": "github.com/munnerz/goautoneg/LICENSE", "licenseText": "Copyright (c) 2011, Open Knowledge Foundation Ltd.\nAll 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\n notice, this list of conditions and the following disclaimer.\n\n Redistributions in binary form must reproduce the above copyright\n notice, this list of conditions and the following disclaimer in\n the documentation and/or other materials provided with the\n distribution.\n\n Neither the name of the Open Knowledge Foundation Ltd. nor the\n names of its contributors may be used to endorse or promote\n products derived from this software without specific prior written\n 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\nHOLDER 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/nektos/act", - "path": "github.com/nektos/act/LICENSE", - "licenseText": "MIT License\n\nCopyright (c) 2022 The Gitea Authors\nCopyright (c) 2019\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" - }, { "name": "github.com/niklasfasching/go-org", "path": "github.com/niklasfasching/go-org/LICENSE", @@ -954,6 +944,16 @@ "path": "github.com/nwaples/rardecode/v2/LICENSE", "licenseText": "Copyright (c) 2015, Nicholas Waples\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\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/oasdiff/yaml", + "path": "github.com/oasdiff/yaml/LICENSE", + "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2014 Sam Ghods\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\nCopyright (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/oasdiff/yaml3", + "path": "github.com/oasdiff/yaml3/LICENSE", + "licenseText": "\nThis project is covered by two different licenses: MIT and Apache.\n\n#### MIT License ####\n\nThe following files were ported to Go from C files of libyaml, and thus\nare still covered by their original MIT license, with the additional\ncopyright staring in 2011 when the project was ported over:\n\n apic.go emitterc.go parserc.go readerc.go scannerc.go\n writerc.go yamlh.go yamlprivateh.go\n\nCopyright (c) 2006-2010 Kirill Simonov\nCopyright (c) 2006-2011 Kirill Simonov\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\nof the Software, and to permit persons to whom the Software is furnished to do\nso, 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### Apache License ###\n\nAll the remaining project files are covered by the Apache license:\n\nCopyright (c) 2011-2019 Canonical Ltd\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n" + }, { "name": "github.com/olekukonko/cat", "path": "github.com/olekukonko/cat/LICENSE", @@ -974,16 +974,6 @@ "path": "github.com/olekukonko/tablewriter/LICENSE.md", "licenseText": "Copyright (C) 2014 by Oleku Konko\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\nall copies 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\nTHE SOFTWARE.\n" }, - { - "name": "github.com/olivere/elastic/v7", - "path": "github.com/olivere/elastic/v7/LICENSE", - "licenseText": "The MIT License (MIT)\nCopyright © 2012-2015 Oliver Eilhard\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\nin all copies 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\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\nIN THE SOFTWARE.\n" - }, - { - "name": "github.com/olivere/elastic/v7/uritemplates", - "path": "github.com/olivere/elastic/v7/uritemplates/LICENSE", - "licenseText": "Copyright (c) 2013 Joshua Tacoma\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" - }, { "name": "github.com/opencontainers/go-digest", "path": "github.com/opencontainers/go-digest/LICENSE", @@ -1054,6 +1044,11 @@ "path": "github.com/redis/go-redis/v9/LICENSE", "licenseText": "Copyright (c) 2013 The github.com/redis/go-redis Authors.\nAll 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\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/remyoudompheng/bigfft", + "path": "github.com/remyoudompheng/bigfft/LICENSE", + "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/rhysd/actionlint", "path": "github.com/rhysd/actionlint/LICENSE.txt", @@ -1119,6 +1114,11 @@ "path": "github.com/ssor/bom/LICENSE", "licenseText": "MIT License\n\nCopyright (c) 2017 Asher\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" }, + { + "name": "github.com/stangelandcl/ppmd", + "path": "github.com/stangelandcl/ppmd/LICENSE", + "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2022 Clayton Stangeland\nCopyright (c) 2014 Adam Hathcock\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\nall copies 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\nTHE SOFTWARE." + }, { "name": "github.com/stretchr/testify", "path": "github.com/stretchr/testify/LICENSE", @@ -1205,8 +1205,13 @@ "licenseText": "This work is released into the public domain with CC0 1.0.\n\n-------------------------------------------------------------------------------\n\nCreative Commons Legal Code\n\nCC0 1.0 Universal\n\n CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE\n LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN\n ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS\n INFORMATION ON AN \"AS-IS\" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES\n REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS\n PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM\n THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED\n HEREUNDER.\n\nStatement of Purpose\n\nThe laws of most jurisdictions throughout the world automatically confer\nexclusive Copyright and Related Rights (defined below) upon the creator\nand subsequent owner(s) (each and all, an \"owner\") of an original work of\nauthorship and/or a database (each, a \"Work\").\n\nCertain owners wish to permanently relinquish those rights to a Work for\nthe purpose of contributing to a commons of creative, cultural and\nscientific works (\"Commons\") that the public can reliably and without fear\nof later claims of infringement build upon, modify, incorporate in other\nworks, reuse and redistribute as freely as possible in any form whatsoever\nand for any purposes, including without limitation commercial purposes.\nThese owners may contribute to the Commons to promote the ideal of a free\nculture and the further production of creative, cultural and scientific\nworks, or to gain reputation or greater distribution for their Work in\npart through the use and efforts of others.\n\nFor these and/or other purposes and motivations, and without any\nexpectation of additional consideration or compensation, the person\nassociating CC0 with a Work (the \"Affirmer\"), to the extent that he or she\nis an owner of Copyright and Related Rights in the Work, voluntarily\nelects to apply CC0 to the Work and publicly distribute the Work under its\nterms, with knowledge of his or her Copyright and Related Rights in the\nWork and the meaning and intended legal effect of CC0 on those rights.\n\n1. Copyright and Related Rights. A Work made available under CC0 may be\nprotected by copyright and related or neighboring rights (\"Copyright and\nRelated Rights\"). Copyright and Related Rights include, but are not\nlimited to, the following:\n\n i. the right to reproduce, adapt, distribute, perform, display,\n communicate, and translate a Work;\n ii. moral rights retained by the original author(s) and/or performer(s);\niii. publicity and privacy rights pertaining to a person's image or\n likeness depicted in a Work;\n iv. rights protecting against unfair competition in regards to a Work,\n subject to the limitations in paragraph 4(a), below;\n v. rights protecting the extraction, dissemination, use and reuse of data\n in a Work;\n vi. database rights (such as those arising under Directive 96/9/EC of the\n European Parliament and of the Council of 11 March 1996 on the legal\n protection of databases, and under any national implementation\n thereof, including any amended or successor version of such\n directive); and\nvii. other similar, equivalent or corresponding rights throughout the\n world based on applicable law or treaty, and any national\n implementations thereof.\n\n2. Waiver. To the greatest extent permitted by, but not in contravention\nof, applicable law, Affirmer hereby overtly, fully, permanently,\nirrevocably and unconditionally waives, abandons, and surrenders all of\nAffirmer's Copyright and Related Rights and associated claims and causes\nof action, whether now known or unknown (including existing as well as\nfuture claims and causes of action), in the Work (i) in all territories\nworldwide, (ii) for the maximum duration provided by applicable law or\ntreaty (including future time extensions), (iii) in any current or future\nmedium and for any number of copies, and (iv) for any purpose whatsoever,\nincluding without limitation commercial, advertising or promotional\npurposes (the \"Waiver\"). Affirmer makes the Waiver for the benefit of each\nmember of the public at large and to the detriment of Affirmer's heirs and\nsuccessors, fully intending that such Waiver shall not be subject to\nrevocation, rescission, cancellation, termination, or any other legal or\nequitable action to disrupt the quiet enjoyment of the Work by the public\nas contemplated by Affirmer's express Statement of Purpose.\n\n3. Public License Fallback. Should any part of the Waiver for any reason\nbe judged legally invalid or ineffective under applicable law, then the\nWaiver shall be preserved to the maximum extent permitted taking into\naccount Affirmer's express Statement of Purpose. In addition, to the\nextent the Waiver is so judged Affirmer hereby grants to each affected\nperson a royalty-free, non transferable, non sublicensable, non exclusive,\nirrevocable and unconditional license to exercise Affirmer's Copyright and\nRelated Rights in the Work (i) in all territories worldwide, (ii) for the\nmaximum duration provided by applicable law or treaty (including future\ntime extensions), (iii) in any current or future medium and for any number\nof copies, and (iv) for any purpose whatsoever, including without\nlimitation commercial, advertising or promotional purposes (the\n\"License\"). The License shall be deemed effective as of the date CC0 was\napplied by Affirmer to the Work. Should any part of the License for any\nreason be judged legally invalid or ineffective under applicable law, such\npartial invalidity or ineffectiveness shall not invalidate the remainder\nof the License, and in such case Affirmer hereby affirms that he or she\nwill not (i) exercise any of his or her remaining Copyright and Related\nRights in the Work or (ii) assert any associated claims and causes of\naction with respect to the Work, in either case contrary to Affirmer's\nexpress Statement of Purpose.\n\n4. Limitations and Disclaimers.\n\n a. No trademark or patent rights held by Affirmer are waived, abandoned,\n surrendered, licensed or otherwise affected by this document.\n b. Affirmer offers the Work as-is and makes no representations or\n warranties of any kind concerning the Work, express, implied,\n statutory or otherwise, including without limitation warranties of\n title, merchantability, fitness for a particular purpose, non\n infringement, or the absence of latent or other defects, accuracy, or\n the present or absence of errors, whether or not discoverable, all to\n the greatest extent permissible under applicable law.\n c. Affirmer disclaims responsibility for clearing rights of other persons\n that may apply to the Work or any use thereof, including without\n limitation any person's Copyright and Related Rights in the Work.\n Further, Affirmer disclaims responsibility for obtaining any necessary\n consents, permissions or other rights required for any use of the\n Work.\n d. Affirmer understands and acknowledges that Creative Commons is not a\n party to this document and has no duty or obligation with respect to\n this CC0 or use of the Work.\n" }, { - "name": "gitlab.com/gitlab-org/api/client-go", - "path": "gitlab.com/gitlab-org/api/client-go/LICENSE", + "name": "github.com/zeebo/xxh3", + "path": "github.com/zeebo/xxh3/LICENSE", + "licenseText": "BSD 2-Clause License\n\nCopyright (c) 2012-2014, Yann Collet\nCopyright (c) 2019, Jeff Wendling\nAll rights reserved.\n\nxxHash Library\n\nRedistribution and use in source and binary forms, with or without modification,\nare 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, this\n list of conditions and the following disclaimer in the documentation and/or\n other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + }, + { + "name": "gitlab.com/gitlab-org/api/client-go/v2", + "path": "gitlab.com/gitlab-org/api/client-go/v2/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 {yyyy} {name of copyright owner}\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" }, { @@ -1234,11 +1239,6 @@ "path": "go.uber.org/zap/exp/LICENSE", "licenseText": "Copyright (c) 2016-2024 Uber Technologies, Inc.\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\nall copies 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\nTHE SOFTWARE.\n" }, - { - "name": "go.yaml.in/yaml/v2", - "path": "go.yaml.in/yaml/v2/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 {yyyy} {name of copyright owner}\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": "go.yaml.in/yaml/v3", "path": "go.yaml.in/yaml/v3/LICENSE", @@ -1329,6 +1329,26 @@ "path": "gopkg.in/yaml.v3/LICENSE", "licenseText": "\nThis project is covered by two different licenses: MIT and Apache.\n\n#### MIT License ####\n\nThe following files were ported to Go from C files of libyaml, and thus\nare still covered by their original MIT license, with the additional\ncopyright staring in 2011 when the project was ported over:\n\n apic.go emitterc.go parserc.go readerc.go scannerc.go\n writerc.go yamlh.go yamlprivateh.go\n\nCopyright (c) 2006-2010 Kirill Simonov\nCopyright (c) 2006-2011 Kirill Simonov\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\nof the Software, and to permit persons to whom the Software is furnished to do\nso, 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### Apache License ###\n\nAll the remaining project files are covered by the Apache license:\n\nCopyright (c) 2011-2019 Canonical Ltd\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n" }, + { + "name": "modernc.org/libc", + "path": "modernc.org/libc/LICENSE", + "licenseText": "Copyright (c) 2017 The Libc 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 names of the authors nor the names of the\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": "modernc.org/mathutil", + "path": "modernc.org/mathutil/LICENSE", + "licenseText": "Copyright (c) 2014 The mathutil 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 names of the authors nor the names of the\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": "modernc.org/memory", + "path": "modernc.org/memory/LICENSE", + "licenseText": "Copyright (c) 2017 The Memory 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 names of the authors nor the names of the\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": "modernc.org/sqlite", + "path": "modernc.org/sqlite/LICENSE", + "licenseText": "Copyright (c) 2017 The Sqlite 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 met:\n\n1. Redistributions of source code must retain the above copyright notice, this\nlist of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\nthis list of conditions and the following disclaimer in the documentation\nand/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its contributors\nmay be used to endorse or promote products derived from this software without\nspecific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES 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": "mvdan.cc/xurls/v2", "path": "mvdan.cc/xurls/v2/LICENSE", diff --git a/package/gitea/source/build/generate-bindata.go b/package/gitea/source/build/generate-bindata.go index 25537707..3e14eba4 100644 --- a/package/gitea/source/build/generate-bindata.go +++ b/package/gitea/source/build/generate-bindata.go @@ -9,7 +9,7 @@ import ( "fmt" "os" - "code.gitea.io/gitea/modules/assetfs" + "gitea.dev/modules/assetfs" ) func main() { diff --git a/package/gitea/source/build/generate-emoji.go b/package/gitea/source/build/generate-emoji.go index cbc1be21..7d38a4cb 100644 --- a/package/gitea/source/build/generate-emoji.go +++ b/package/gitea/source/build/generate-emoji.go @@ -20,7 +20,7 @@ import ( "strings" "unicode/utf8" - "code.gitea.io/gitea/modules/json" + "gitea.dev/modules/json" ) const ( diff --git a/package/gitea/source/build/generate-gitignores.go b/package/gitea/source/build/generate-gitignores.go index 1e09c83a..11af4eb7 100644 --- a/package/gitea/source/build/generate-gitignores.go +++ b/package/gitea/source/build/generate-gitignores.go @@ -1,3 +1,6 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + //go:build ignore package main @@ -15,7 +18,7 @@ import ( "path/filepath" "strings" - "code.gitea.io/gitea/modules/util" + "gitea.dev/modules/util" ) func main() { diff --git a/package/gitea/source/build/generate-go-licenses.go b/package/gitea/source/build/generate-go-licenses.go index 057e6a6e..a4aa5b08 100644 --- a/package/gitea/source/build/generate-go-licenses.go +++ b/package/gitea/source/build/generate-go-licenses.go @@ -29,8 +29,8 @@ var primaryLicenseRe = regexp.MustCompile(`^(?i)(LICEN[SC]E|COPYING)$`) // ignoredNames are LicenseEntry.Name values to exclude from the output. var ignoredNames = map[string]bool{ - "code.gitea.io/gitea": true, - "code.gitea.io/gitea/options/license": true, + "gitea.dev": true, + "gitea.dev/options/license": true, } var excludedExt = map[string]bool{ diff --git a/package/gitea/source/build/generate-openapi.go b/package/gitea/source/build/generate-openapi.go new file mode 100644 index 00000000..f0cdd866 --- /dev/null +++ b/package/gitea/source/build/generate-openapi.go @@ -0,0 +1,97 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +// generate-openapi converts Gitea's Swagger 2.0 spec into an OpenAPI 3.0 spec. +// +// Gitea generates a Swagger 2.0 spec from code annotations (make generate-swagger). +// This tool converts it to OAS3 so that SDK generators and tools that require +// OAS3 (e.g. progenitor for Rust) can consume it directly. The conversion also +// deduplicates inline enum definitions into named schema components, producing +// cleaner SDK output with proper enum types instead of anonymous strings. +// +// Run: go run build/generate-openapi.go +// Output: templates/swagger/v1_openapi3_json.tmpl + +//go:build ignore + +package main + +import ( + "encoding/json" + "fmt" + "log" + "os" + "regexp" + "sort" + "strings" + + "gitea.dev/build/openapi3gen" + + "github.com/getkin/kin-openapi/openapi3" +) + +const ( + swaggerSpecPath = "templates/swagger/v1_json.tmpl" + openapi3OutPath = "templates/swagger/v1_openapi3_json.tmpl" + + appSubUrlVar = "{{.SwaggerAppSubUrl}}" + appVerVar = "{{.SwaggerAppVer}}" + + appSubUrlPlaceholder = "GITEA_APP_SUB_URL_PLACEHOLDER" + appVerPlaceholder = "0.0.0-gitea-placeholder" +) + +var ( + appSubUrlRe = regexp.MustCompile(regexp.QuoteMeta(appSubUrlVar)) + appVerRe = regexp.MustCompile(regexp.QuoteMeta(appVerVar)) + + enumScanDirs = []string{ + "modules/structs", + "modules/commitstatus", + } +) + +func main() { + astEnumMap, err := openapi3gen.ScanSwaggerEnumTypes(enumScanDirs) + if err != nil { + log.Fatalf("scanning swagger:enum annotations: %v", err) + } + names := make([]string, 0, len(astEnumMap)) + for _, ns := range astEnumMap { + names = append(names, ns...) + } + sort.Strings(names) + fmt.Fprintf(os.Stderr, "discovered %d swagger:enum types: %s\n", len(names), strings.Join(names, ", ")) + + data, err := os.ReadFile(swaggerSpecPath) + if err != nil { + log.Fatalf("reading swagger spec: %v", err) + } + + cleaned := appSubUrlRe.ReplaceAll(data, []byte(appSubUrlPlaceholder)) + cleaned = appVerRe.ReplaceAll(cleaned, []byte(appVerPlaceholder)) + + oas3, err := openapi3gen.Convert(cleaned, astEnumMap) + if err != nil { + log.Fatalf("converting to openapi 3.0: %v", err) + } + + oas3.Servers = openapi3.Servers{ + {URL: appSubUrlPlaceholder + "/api/v1"}, + } + + out, err := json.MarshalIndent(oas3, "", " ") + if err != nil { + log.Fatalf("marshaling openapi 3.0: %v", err) + } + + result := strings.ReplaceAll(string(out), appSubUrlPlaceholder, appSubUrlVar) + result = strings.ReplaceAll(result, appVerPlaceholder, appVerVar) + result = strings.TrimSpace(result) + + if err := os.WriteFile(openapi3OutPath, []byte(result), 0o644); err != nil { + log.Fatalf("writing openapi 3.0 spec: %v", err) + } + + fmt.Printf("Generated %s\n", openapi3OutPath) +} diff --git a/package/gitea/source/build/openapi3gen/convert.go b/package/gitea/source/build/openapi3gen/convert.go new file mode 100644 index 00000000..d1ee1a3a --- /dev/null +++ b/package/gitea/source/build/openapi3gen/convert.go @@ -0,0 +1,386 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package openapi3gen + +import ( + "fmt" + "regexp" + "sort" + "strings" + + "gitea.dev/modules/json" + + "github.com/getkin/kin-openapi/openapi2" + "github.com/getkin/kin-openapi/openapi2conv" + "github.com/getkin/kin-openapi/openapi3" +) + +// rxDeprecated matches "deprecated" as a word at the start of a description +// or preceded by whitespace/punctuation that indicates a leading marker (e.g. +// "Deprecated: true", "deprecated (use X instead)"). Rejects negated phrases +// like "not deprecated" or "previously deprecated, now supported". +var rxDeprecated = regexp.MustCompile(`(?i)(?:^|[\n.;])\s*deprecated\b`) + +// Convert parses a Swagger 2.0 spec and returns an OAS3 spec, applying +// Gitea-specific post-processing: file-schema fixups, URI formats, +// deprecated flags, and shared-enum extraction. +// +// astEnumMap is a value-set-key → Go-type-name(s) map (built by +// ScanSwaggerEnumTypes). When a value set is shared by multiple Go types, +// per-property disambiguation uses the x-go-enum-desc extension. If a shared +// enum in the spec has no matching entry, Convert returns an error — no +// fallback naming. +func Convert(swaggerJSON []byte, astEnumMap map[string][]string) (*openapi3.T, error) { + var swagger2 openapi2.T + if err := json.Unmarshal(swaggerJSON, &swagger2); err != nil { + return nil, fmt.Errorf("parsing swagger 2.0: %w", err) + } + + oas3, err := openapi2conv.ToV3(&swagger2) + if err != nil { + return nil, fmt.Errorf("converting to openapi 3.0: %w", err) + } + + fixFileSchemas(oas3) + addURIFormats(oas3) + addDeprecatedFlags(oas3) + if err := extractSharedEnums(oas3, astEnumMap); err != nil { + return nil, err + } + return oas3, nil +} + +func fixFileSchemas(doc *openapi3.T) { + for _, pathItem := range doc.Paths.Map() { + for _, op := range []*openapi3.Operation{ + pathItem.Get, pathItem.Post, pathItem.Put, pathItem.Patch, + pathItem.Delete, pathItem.Head, pathItem.Options, pathItem.Trace, + } { + if op == nil { + continue + } + for _, resp := range op.Responses.Map() { + if resp.Value == nil { + continue + } + for _, mediaType := range resp.Value.Content { + fixSchema(mediaType.Schema) + } + } + if op.RequestBody != nil && op.RequestBody.Value != nil { + for _, mediaType := range op.RequestBody.Value.Content { + fixSchema(mediaType.Schema) + } + } + } + } +} + +// fixSchema rewrites any "type: file" schemas to the OAS3 equivalent +// (type: string, format: binary), recursing into Properties, Items, and +// AllOf/OneOf/AnyOf/Not branches. $ref nodes are skipped so shared schemas +// are rewritten exactly once when visited through their declaration. +func fixSchema(ref *openapi3.SchemaRef) { + if ref == nil || ref.Value == nil || ref.Ref != "" { + return + } + s := ref.Value + if s.Type.Is("file") { + s.Type = &openapi3.Types{"string"} + s.Format = "binary" + } + for _, p := range s.Properties { + fixSchema(p) + } + fixSchema(s.Items) + for _, sub := range s.AllOf { + fixSchema(sub) + } + for _, sub := range s.OneOf { + fixSchema(sub) + } + for _, sub := range s.AnyOf { + fixSchema(sub) + } + fixSchema(s.Not) +} + +// addURIFormats sets format: uri on string properties whose names indicate +// they hold URLs. This information is lost in Swagger 2.0 but is valuable +// for code generators. +func addURIFormats(doc *openapi3.T) { + if doc.Components == nil { + return + } + for _, schemaRef := range doc.Components.Schemas { + if schemaRef.Value == nil { + continue + } + for propName, propRef := range schemaRef.Value.Properties { + if propRef == nil || propRef.Value == nil || propRef.Ref != "" { + continue + } + prop := propRef.Value + if !prop.Type.Is("string") || prop.Format != "" { + continue + } + if isURLProperty(propName) { + prop.Format = "uri" + } + } + } +} + +func isURLProperty(name string) bool { + if strings.HasSuffix(name, "_url") { + return true + } + switch name { + case "url", "html_url", "clone_url": + return true + } + return false +} + +// addDeprecatedFlags sets deprecated: true on schema properties whose +// description starts with a "deprecated" marker (e.g. "Deprecated: true" +// or "deprecated (use X instead)"). Does not match negated phrases. +func addDeprecatedFlags(doc *openapi3.T) { + if doc.Components == nil { + return + } + for _, schemaRef := range doc.Components.Schemas { + if schemaRef.Value == nil { + continue + } + for _, propRef := range schemaRef.Value.Properties { + if propRef == nil || propRef.Value == nil || propRef.Ref != "" { + continue + } + if rxDeprecated.MatchString(propRef.Value.Description) { + propRef.Value.Deprecated = true + } + } + } +} + +type enumUsage struct { + schemaName string + propName string + propRef *openapi3.SchemaRef + inItems bool +} + +// extractSharedEnums finds identical enum arrays used by multiple schema +// properties, creates a standalone named schema for each, and replaces +// the inline enums with $ref pointers. +// +// If the derived enum name collides with an existing component schema, or +// no // swagger:enum annotation matches the value set, generation aborts +// with an actionable error — there are no silent fallbacks. +func extractSharedEnums(doc *openapi3.T, astEnumMap map[string][]string) error { + if doc.Components == nil { + return nil + } + + type groupKey struct { + valueSet string + typeName string + } + enumGroups := map[groupKey][]enumUsage{} + groupOrder := []groupKey{} // deterministic iteration + + addUsage := func(key groupKey, u enumUsage) { + if _, seen := enumGroups[key]; !seen { + groupOrder = append(groupOrder, key) + } + enumGroups[key] = append(enumGroups[key], u) + } + + for schemaName, schemaRef := range doc.Components.Schemas { + if schemaRef.Value == nil { + continue + } + for propName, propRef := range schemaRef.Value.Properties { + if propRef == nil || propRef.Value == nil || propRef.Ref != "" { + continue + } + if len(propRef.Value.Enum) > 1 && propRef.Value.Type.Is("string") { + key := groupKey{ + valueSet: EnumKey(propRef.Value.Enum), + typeName: extractEnumTypeName(propRef.Value, astEnumMap), + } + addUsage(key, enumUsage{schemaName, propName, propRef, false}) + } + if propRef.Value.Type.Is("array") && propRef.Value.Items != nil && + propRef.Value.Items.Value != nil && propRef.Value.Items.Ref == "" && + len(propRef.Value.Items.Value.Enum) > 1 && propRef.Value.Items.Value.Type.Is("string") { + key := groupKey{ + valueSet: EnumKey(propRef.Value.Items.Value.Enum), + typeName: extractEnumTypeName(propRef.Value.Items.Value, astEnumMap), + } + addUsage(key, enumUsage{schemaName, propName, propRef, true}) + } + } + } + + for _, key := range groupOrder { + usages := enumGroups[key] + if len(usages) < 2 { + continue + } + + enumName, err := deriveEnumName(key.valueSet, key.typeName, usages, astEnumMap) + if err != nil { + return err + } + if _, exists := doc.Components.Schemas[enumName]; exists { + return fmt.Errorf("enum name collision: %s already exists as a component schema", enumName) + } + + var enumValues []any + if usages[0].inItems { + enumValues = usages[0].propRef.Value.Items.Value.Enum + } else { + enumValues = usages[0].propRef.Value.Enum + } + + doc.Components.Schemas[enumName] = &openapi3.SchemaRef{ + Value: &openapi3.Schema{ + Type: &openapi3.Types{"string"}, + Enum: enumValues, + }, + } + + ref := "#/components/schemas/" + enumName + + for _, usage := range usages { + if usage.inItems { + usage.propRef.Value.Items = &openapi3.SchemaRef{Ref: ref} + } else { + old := usage.propRef.Value + if old.Description == "" && !old.Deprecated && old.Format == "" { + usage.propRef.Ref = ref + usage.propRef.Value = nil + } else { + usage.propRef.Value = &openapi3.Schema{ + AllOf: openapi3.SchemaRefs{ + {Ref: ref}, + }, + Description: old.Description, + Deprecated: old.Deprecated, + Format: old.Format, + } + } + } + } + } + return nil +} + +// deriveEnumName looks up a shared enum's Go type name. If typeName is +// non-empty (because we recovered it from x-go-enum-desc), it is used +// directly. Otherwise the value-set must map to exactly one known type. On +// failure, returns an error identifying the offending properties. +func deriveEnumName(key, typeName string, usages []enumUsage, astEnumMap map[string][]string) (string, error) { + if typeName != "" { + return typeName, nil + } + names := astEnumMap[key] + if len(names) == 1 { + return names[0], nil + } + + props := map[string]bool{} + for _, u := range usages { + props[fmt.Sprintf("%s.%s", u.schemaName, u.propName)] = true + } + propList := make([]string, 0, len(props)) + for p := range props { + propList = append(propList, p) + } + if len(names) > 1 { + return "", fmt.Errorf( + "value-set %q is shared by multiple swagger:enum types %v and could not be disambiguated for properties: %v; "+ + "ensure go-swagger emits x-go-enum-desc for those properties", + key, names, propList, + ) + } + return "", fmt.Errorf( + "no swagger:enum annotation matches value-set %q used by %d properties: %v; "+ + "fix by adding a named string type with // swagger:enum to modules/structs or modules/commitstatus", + key, len(usages), propList, + ) +} + +// extractEnumTypeName recovers the Go type name a schema's enum came from by +// parsing the property's x-go-enum-desc extension. go-swagger emits one line +// per value as " [ ]"; the type is the longest +// common prefix of the const names, narrowed to the candidate set in +// astEnumMap. Returns "" if extraction is inconclusive. +func extractEnumTypeName(s *openapi3.Schema, astEnumMap map[string][]string) string { + if s == nil || s.Extensions == nil { + return "" + } + raw, ok := s.Extensions["x-go-enum-desc"] + if !ok { + return "" + } + desc, ok := raw.(string) + if !ok { + return "" + } + candidates := astEnumMap[EnumKey(s.Enum)] + if len(candidates) == 0 { + return "" + } + // Collect the const names (second whitespace-separated field per line). + var consts []string + for line := range strings.SplitSeq(desc, "\n") { + fields := strings.Fields(line) + if len(fields) >= 2 { + consts = append(consts, fields[1]) + } + } + if len(consts) == 0 { + return "" + } + // A candidate matches when it is a prefix of every const name AND the + // first character after the prefix is an uppercase ASCII letter — this + // rejects e.g. "Alpha" matching "Alphabet" (suffix "bet" starts lower) + // while still accepting both "Alpha" and "AlphaPlus" against "AlphaPlusX" + // (both prefixes valid). The most specific (longest) wins; ties return + // "" so deriveEnumName surfaces the ambiguity rather than silently + // picking a winner. + ordered := append([]string(nil), candidates...) + sort.Slice(ordered, func(i, j int) bool { return len(ordered[i]) > len(ordered[j]) }) + var matches []string + for _, name := range ordered { + ok := true + for _, c := range consts { + if !strings.HasPrefix(c, name) { + ok = false + break + } + suffix := c[len(name):] + // Empty suffix means the const name exactly equals the type name — valid exact match. + // A non-empty suffix must begin with an uppercase letter to reject incidental + // prefix matches (e.g. "Alpha" should not match "Alphabet"). + if len(suffix) > 0 && (suffix[0] < 'A' || suffix[0] > 'Z') { + ok = false + break + } + } + if ok { + matches = append(matches, name) + } + } + if len(matches) == 0 { + return "" + } + if len(matches) > 1 && len(matches[0]) == len(matches[1]) { + return "" + } + return matches[0] +} diff --git a/package/gitea/source/build/openapi3gen/convert_test.go b/package/gitea/source/build/openapi3gen/convert_test.go new file mode 100644 index 00000000..1cf73bd1 --- /dev/null +++ b/package/gitea/source/build/openapi3gen/convert_test.go @@ -0,0 +1,218 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package openapi3gen + +import ( + "strings" + "testing" + + "github.com/getkin/kin-openapi/openapi3" +) + +func TestDeriveEnumName_hit(t *testing.T) { + key := EnumKey([]any{"red", "green", "blue"}) + astMap := map[string][]string{key: {"Color"}} + usages := []enumUsage{{schemaName: "Paint", propName: "color"}} + got, err := deriveEnumName(key, "", usages, astMap) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if got != "Color" { + t.Fatalf("got %q, want %q", got, "Color") + } +} + +func TestDeriveEnumName_miss(t *testing.T) { + key := EnumKey([]any{"x", "y"}) + usages := []enumUsage{{schemaName: "Thing", propName: "kind"}} + _, err := deriveEnumName(key, "", usages, map[string][]string{}) + if err == nil { + t.Fatal("expected miss error, got nil") + } + msg := err.Error() + if !strings.Contains(msg, "Thing.kind") { + t.Fatalf("error %q should list the missing usage", msg) + } + if !strings.Contains(msg, "swagger:enum") { + t.Fatalf("error %q should hint at the fix", msg) + } +} + +func TestExtractSharedEnums_usesASTMap(t *testing.T) { + doc := &openapi3.T{ + Components: &openapi3.Components{ + Schemas: openapi3.Schemas{ + "A": {Value: &openapi3.Schema{ + Type: &openapi3.Types{"object"}, + Properties: openapi3.Schemas{ + "color": {Value: &openapi3.Schema{ + Type: &openapi3.Types{"string"}, + Enum: []any{"red", "green", "blue"}, + }}, + }, + }}, + "B": {Value: &openapi3.Schema{ + Type: &openapi3.Types{"object"}, + Properties: openapi3.Schemas{ + "color": {Value: &openapi3.Schema{ + Type: &openapi3.Types{"string"}, + Enum: []any{"red", "green", "blue"}, + }}, + }, + }}, + }, + }, + } + astMap := map[string][]string{EnumKey([]any{"red", "green", "blue"}): {"Color"}} + if err := extractSharedEnums(doc, astMap); err != nil { + t.Fatalf("extractSharedEnums: %v", err) + } + if _, ok := doc.Components.Schemas["Color"]; !ok { + t.Fatalf("expected Color schema to be extracted") + } +} + +func TestFixFileSchemas_recursesIntoNested(t *testing.T) { + fileType := func() *openapi3.SchemaRef { + return &openapi3.SchemaRef{Value: &openapi3.Schema{Type: &openapi3.Types{"file"}}} + } + doc := &openapi3.T{ + Paths: openapi3.NewPaths(), + } + doc.Paths.Set("/upload", &openapi3.PathItem{ + Post: &openapi3.Operation{ + RequestBody: &openapi3.RequestBodyRef{ + Value: &openapi3.RequestBody{ + Content: openapi3.Content{ + "multipart/form-data": { + Schema: &openapi3.SchemaRef{Value: &openapi3.Schema{ + Type: &openapi3.Types{"object"}, + Properties: openapi3.Schemas{ + "attachment": fileType(), + "items": {Value: &openapi3.Schema{ + Type: &openapi3.Types{"array"}, + Items: fileType(), + }}, + "alt": {Value: &openapi3.Schema{ + AllOf: openapi3.SchemaRefs{fileType()}, + }}, + "one": {Value: &openapi3.Schema{ + OneOf: openapi3.SchemaRefs{fileType()}, + }}, + "any": {Value: &openapi3.Schema{ + AnyOf: openapi3.SchemaRefs{fileType()}, + }}, + "not": {Value: &openapi3.Schema{ + Not: fileType(), + }}, + }, + }}, + }, + }, + }, + }, + Responses: openapi3.NewResponses(), + }, + }) + + fixFileSchemas(doc) + + props := doc.Paths.Value("/upload").Post.RequestBody.Value.Content["multipart/form-data"].Schema.Value.Properties + if !props["attachment"].Value.Type.Is("string") || props["attachment"].Value.Format != "binary" { + t.Errorf("nested property not fixed: %+v", props["attachment"].Value) + } + if !props["items"].Value.Items.Value.Type.Is("string") || props["items"].Value.Items.Value.Format != "binary" { + t.Errorf("array items not fixed: %+v", props["items"].Value.Items.Value) + } + if !props["alt"].Value.AllOf[0].Value.Type.Is("string") || props["alt"].Value.AllOf[0].Value.Format != "binary" { + t.Errorf("allOf branch not fixed: %+v", props["alt"].Value.AllOf[0].Value) + } + if !props["one"].Value.OneOf[0].Value.Type.Is("string") || props["one"].Value.OneOf[0].Value.Format != "binary" { + t.Errorf("oneOf branch not fixed: %+v", props["one"].Value.OneOf[0].Value) + } + if !props["any"].Value.AnyOf[0].Value.Type.Is("string") || props["any"].Value.AnyOf[0].Value.Format != "binary" { + t.Errorf("anyOf branch not fixed: %+v", props["any"].Value.AnyOf[0].Value) + } + if !props["not"].Value.Not.Value.Type.Is("string") || props["not"].Value.Not.Value.Format != "binary" { + t.Errorf("not branch not fixed: %+v", props["not"].Value.Not.Value) + } +} + +func TestExtractEnumTypeName_TeamVisibility(t *testing.T) { + enum := []any{"public", "limited", "private"} + key := EnumKey(enum) + astMap := map[string][]string{key: {"UserVisibility", "TeamVisibility"}} + schema := &openapi3.Schema{ + Type: &openapi3.Types{"string"}, + Enum: enum, + Extensions: map[string]any{ + "x-go-enum-desc": "public TeamVisibilityPublic\nlimited TeamVisibilityLimited\nprivate TeamVisibilityPrivate", + }, + } + if got := extractEnumTypeName(schema, astMap); got != "TeamVisibility" { + t.Fatalf("got %q, want %q", got, "TeamVisibility") + } +} + +func TestExtractEnumTypeName_ambiguousPrefixTie(t *testing.T) { + enum := []any{"one", "two"} + key := EnumKey(enum) + astMap := map[string][]string{key: {"AB", "AC"}} + schema := &openapi3.Schema{ + Type: &openapi3.Types{"string"}, + Enum: enum, + Extensions: map[string]any{ + "x-go-enum-desc": "one ABOne\ntwo ACTwo", + }, + } + if got := extractEnumTypeName(schema, astMap); got != "" { + t.Fatalf("got %q, want empty string for ambiguous tie", got) + } +} + +func TestExtractEnumTypeName_rejectsIncidentalPrefix(t *testing.T) { + enum := []any{"a", "b"} + key := EnumKey(enum) + astMap := map[string][]string{key: {"Alpha", "Alphabet"}} + schema := &openapi3.Schema{ + Type: &openapi3.Types{"string"}, + Enum: enum, + Extensions: map[string]any{ + "x-go-enum-desc": "a AlphabetA\nb AlphabetB", + }, + } + if got := extractEnumTypeName(schema, astMap); got != "Alphabet" { + t.Fatalf("got %q, want %q", got, "Alphabet") + } +} + +func TestExtractSharedEnums_missReturnsError(t *testing.T) { + doc := &openapi3.T{ + Components: &openapi3.Components{ + Schemas: openapi3.Schemas{ + "A": {Value: &openapi3.Schema{ + Type: &openapi3.Types{"object"}, + Properties: openapi3.Schemas{ + "color": {Value: &openapi3.Schema{ + Type: &openapi3.Types{"string"}, + Enum: []any{"red", "green"}, + }}, + }, + }}, + "B": {Value: &openapi3.Schema{ + Type: &openapi3.Types{"object"}, + Properties: openapi3.Schemas{ + "color": {Value: &openapi3.Schema{ + Type: &openapi3.Types{"string"}, + Enum: []any{"red", "green"}, + }}, + }, + }}, + }, + }, + } + if err := extractSharedEnums(doc, map[string][]string{}); err == nil { + t.Fatal("expected miss error") + } +} diff --git a/package/gitea/source/build/openapi3gen/enumscan.go b/package/gitea/source/build/openapi3gen/enumscan.go new file mode 100644 index 00000000..73bbcb5e --- /dev/null +++ b/package/gitea/source/build/openapi3gen/enumscan.go @@ -0,0 +1,192 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +// Package openapi3gen converts Gitea's Swagger 2.0 spec to an OpenAPI 3.0 +// spec. It discovers Go enum type names by scanning swagger:enum annotations +// in the source tree, then names extracted shared-enum schemas accordingly. +package openapi3gen + +import ( + "fmt" + "go/ast" + "go/parser" + "go/token" + "os" + "path/filepath" + "regexp" + "sort" + "strconv" + "strings" +) + +// EnumKey returns a canonical key for a set of enum values: values are +// stringified, sorted, and joined with "|". Used to match enum value sets +// across spec properties and scanned Go type declarations. +func EnumKey(values []any) string { + strs := make([]string, len(values)) + for i, v := range values { + strs[i] = fmt.Sprintf("%v", v) + } + sort.Strings(strs) + return strings.Join(strs, "|") +} + +var rxSwaggerEnum = regexp.MustCompile(`swagger:enum\s+(\w+)`) + +// ScanSwaggerEnumTypes walks .go files under each dir and returns a map from +// a canonical value-set key (see EnumKey) to the Go type names declared with +// // swagger:enum TypeName. Multiple type names per key are allowed (e.g. +// distinct enum types that happen to share a value set such as +// {public, limited, private}); callers must disambiguate per-usage (typically +// by parsing the property's x-go-enum-desc extension to recover the const +// type prefix). +// +// Returns an error on parse failure or on an annotation for a type whose +// constants can't be extracted. +func ScanSwaggerEnumTypes(dirs []string) (map[string][]string, error) { + fset := token.NewFileSet() + parsed := []*ast.File{} + + for _, dir := range dirs { + entries, err := os.ReadDir(dir) + if err != nil { + return nil, fmt.Errorf("reading %s: %w", dir, err) + } + for _, entry := range entries { + if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".go") { + continue + } + if strings.HasSuffix(entry.Name(), "_test.go") { + continue + } + path := filepath.Join(dir, entry.Name()) + file, err := parser.ParseFile(fset, path, nil, parser.ParseComments) + if err != nil { + return nil, fmt.Errorf("%s: %w", path, err) + } + parsed = append(parsed, file) + } + } + + enumTypes := map[string]string{} // typeName → "" (presence marker) + enumValues := map[string][]any{} // typeName → values + + // Pass 1: collect every // swagger:enum TypeName declaration. + for _, file := range parsed { + for _, decl := range file.Decls { + gd, ok := decl.(*ast.GenDecl) + if !ok || gd.Tok != token.TYPE { + continue + } + if err := collectEnumType(gd, enumTypes); err != nil { + return nil, fmt.Errorf("%s: %w", fset.Position(gd.Pos()).Filename, err) + } + } + } + + // Pass 2: collect const values; now every annotated type is visible. + for _, file := range parsed { + for _, decl := range file.Decls { + gd, ok := decl.(*ast.GenDecl) + if !ok || gd.Tok != token.CONST { + continue + } + collectEnumValues(gd, enumTypes, enumValues) + } + } + + result := map[string][]string{} + for typeName := range enumTypes { + values, ok := enumValues[typeName] + if !ok || len(values) == 0 { + return nil, fmt.Errorf("swagger:enum %s has no const block with typed string values", typeName) + } + key := EnumKey(values) + result[key] = append(result[key], typeName) + } + for key, names := range result { + sort.Strings(names) + result[key] = names + } + return result, nil +} + +// collectEnumType scans a `type` GenDecl for // swagger:enum annotations, +// handling both the lone form (`// swagger:enum Foo\n type Foo string`) +// where the comment group is attached to the GenDecl, and the grouped form: +// +// type ( +// // swagger:enum Foo +// Foo string +// ) +// +// where the comment group is attached to each TypeSpec. Caveat: Go's parser +// only attaches a CommentGroup when it is immediately adjacent to the decl. +// A blank line (not a `//` continuation line) between the comment and the +// declaration drops the Doc, so annotations MUST sit directly above their +// type. All current annotated files obey this — the rule is noted here so +// a future edit that inserts a blank line fails fast rather than silently. +func collectEnumType(gd *ast.GenDecl, enumTypes map[string]string) error { + if err := registerEnumAnnotation(gd.Doc, gd.Specs, enumTypes); err != nil { + return err + } + for _, spec := range gd.Specs { + ts, ok := spec.(*ast.TypeSpec) + if !ok || ts.Doc == nil { + continue + } + if err := registerEnumAnnotation(ts.Doc, []ast.Spec{ts}, enumTypes); err != nil { + return err + } + } + return nil +} + +func registerEnumAnnotation(doc *ast.CommentGroup, specs []ast.Spec, enumTypes map[string]string) error { + if doc == nil { + return nil + } + matches := rxSwaggerEnum.FindStringSubmatch(doc.Text()) + if len(matches) < 2 { + return nil + } + annotated := matches[1] + for _, spec := range specs { + ts, ok := spec.(*ast.TypeSpec) + if !ok { + continue + } + if ts.Name.Name == annotated { + enumTypes[annotated] = "" + return nil + } + } + return fmt.Errorf("swagger:enum %s: no type declaration with that name in the same decl group; check for a typo", annotated) +} + +func collectEnumValues(gd *ast.GenDecl, enumTypes map[string]string, enumValues map[string][]any) { + for _, spec := range gd.Specs { + vs, ok := spec.(*ast.ValueSpec) + if !ok || vs.Type == nil { + continue + } + ident, ok := vs.Type.(*ast.Ident) + if !ok { + continue + } + if _, isEnum := enumTypes[ident.Name]; !isEnum { + continue + } + for _, val := range vs.Values { + lit, ok := val.(*ast.BasicLit) + if !ok || lit.Kind != token.STRING { + continue + } + unquoted, err := strconv.Unquote(lit.Value) + if err != nil { + continue + } + enumValues[ident.Name] = append(enumValues[ident.Name], unquoted) + } + } +} diff --git a/package/gitea/source/build/openapi3gen/enumscan_test.go b/package/gitea/source/build/openapi3gen/enumscan_test.go new file mode 100644 index 00000000..8cb16b72 --- /dev/null +++ b/package/gitea/source/build/openapi3gen/enumscan_test.go @@ -0,0 +1,249 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package openapi3gen + +import ( + "os" + "path/filepath" + "slices" + "strings" + "testing" +) + +func single(got map[string][]string, key string) string { + v := got[key] + if len(v) != 1 { + return "" + } + return v[0] +} + +func TestEnumKey_sortsAndJoins(t *testing.T) { + key := EnumKey([]any{"b", "a", "c"}) + if key != "a|b|c" { + t.Fatalf("EnumKey = %q, want %q", key, "a|b|c") + } +} + +func TestEnumKey_handlesNonStringValues(t *testing.T) { + key := EnumKey([]any{2, 1, 3}) + if key != "1|2|3" { + t.Fatalf("EnumKey = %q, want %q", key, "1|2|3") + } +} + +func TestScanSwaggerEnumTypes_basic(t *testing.T) { + dir := t.TempDir() + src := `package fixture + +// Color is a primary color. +// swagger:enum Color +type Color string + +const ( + ColorRed Color = "red" + ColorGreen Color = "green" + ColorBlue Color = "blue" +) +` + if err := os.WriteFile(filepath.Join(dir, "color.go"), []byte(src), 0o644); err != nil { + t.Fatal(err) + } + + got, err := ScanSwaggerEnumTypes([]string{dir}) + if err != nil { + t.Fatalf("ScanSwaggerEnumTypes: %v", err) + } + wantKey := EnumKey([]any{"red", "green", "blue"}) + if single(got, wantKey) != "Color" { + t.Fatalf("map[%q] = %q, want %q", wantKey, got[wantKey], "Color") + } +} + +func TestScanSwaggerEnumTypes_orphanAnnotation(t *testing.T) { + dir := t.TempDir() + src := `package fixture + +// swagger:enum Sttype +type StateType string + +const ( + StateOpen StateType = "open" +) +` + if err := os.WriteFile(filepath.Join(dir, "typo.go"), []byte(src), 0o644); err != nil { + t.Fatal(err) + } + + _, err := ScanSwaggerEnumTypes([]string{dir}) + if err == nil { + t.Fatal("expected error for annotation referencing a non-matching type name") + } + if !strings.Contains(err.Error(), "Sttype") { + t.Fatalf("error %q should mention the typo'd name Sttype", err.Error()) + } +} + +func TestScanSwaggerEnumTypes_collision(t *testing.T) { + dir := t.TempDir() + src := `package fixture + +// swagger:enum Alpha +type Alpha string +const ( + AlphaX Alpha = "x" + AlphaY Alpha = "y" +) + +// swagger:enum Beta +type Beta string +const ( + BetaX Beta = "x" + BetaY Beta = "y" +) +` + if err := os.WriteFile(filepath.Join(dir, "dup.go"), []byte(src), 0o644); err != nil { + t.Fatal(err) + } + + got, err := ScanSwaggerEnumTypes([]string{dir}) + if err != nil { + t.Fatalf("ScanSwaggerEnumTypes: %v", err) + } + key := EnumKey([]any{"x", "y"}) + names := got[key] + if !slices.Equal(names, []string{"Alpha", "Beta"}) { + t.Fatalf("map[%q] = %v, want [Alpha Beta]", key, names) + } +} + +func TestScanSwaggerEnumTypes_parseFailure(t *testing.T) { + dir := t.TempDir() + if err := os.WriteFile(filepath.Join(dir, "bad.go"), []byte("package fixture\nfunc Foo() {"), 0o644); err != nil { + t.Fatal(err) + } + + _, err := ScanSwaggerEnumTypes([]string{dir}) + if err == nil { + t.Fatal("expected parse error, got nil") + } +} + +func TestScanSwaggerEnumTypes_annotationWithoutConsts(t *testing.T) { + dir := t.TempDir() + src := `package fixture + +// swagger:enum Lonely +type Lonely string +` + if err := os.WriteFile(filepath.Join(dir, "lonely.go"), []byte(src), 0o644); err != nil { + t.Fatal(err) + } + + _, err := ScanSwaggerEnumTypes([]string{dir}) + if err == nil { + t.Fatal("expected error for annotation without consts") + } + if !strings.Contains(err.Error(), "Lonely") { + t.Fatalf("error %q should mention Lonely", err.Error()) + } +} + +func TestScanSwaggerEnumTypes_constsAndTypeInDifferentFiles(t *testing.T) { + dir := t.TempDir() + // Name ordering: `a_consts.go` < `b_type.go`, so readdir returns consts first. + // Old single-pass scanner would miss the values; two-pass must not. + constsSrc := `package fixture + +const ( + HueA Hue = "a" + HueB Hue = "b" +) +` + typeSrc := `package fixture + +// swagger:enum Hue +type Hue string +` + if err := os.WriteFile(filepath.Join(dir, "a_consts.go"), []byte(constsSrc), 0o644); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, "b_type.go"), []byte(typeSrc), 0o644); err != nil { + t.Fatal(err) + } + + got, err := ScanSwaggerEnumTypes([]string{dir}) + if err != nil { + t.Fatalf("ScanSwaggerEnumTypes: %v", err) + } + wantKey := EnumKey([]any{"a", "b"}) + if single(got, wantKey) != "Hue" { + t.Fatalf("map[%q] = %q, want %q", wantKey, got[wantKey], "Hue") + } +} + +func TestScanSwaggerEnumTypes_constsBeforeType(t *testing.T) { + dir := t.TempDir() + src := `package fixture + +const ( + ShadeDark Shade = "dark" + ShadeLight Shade = "light" +) + +// swagger:enum Shade +type Shade string +` + if err := os.WriteFile(filepath.Join(dir, "shade.go"), []byte(src), 0o644); err != nil { + t.Fatal(err) + } + + got, err := ScanSwaggerEnumTypes([]string{dir}) + if err != nil { + t.Fatalf("ScanSwaggerEnumTypes: %v", err) + } + wantKey := EnumKey([]any{"dark", "light"}) + if single(got, wantKey) != "Shade" { + t.Fatalf("map[%q] = %q, want %q", wantKey, got[wantKey], "Shade") + } +} + +func TestScanSwaggerEnumTypes_groupedTypeDecl(t *testing.T) { + dir := t.TempDir() + src := `package fixture + +type ( + // swagger:enum Color + Color string + // swagger:enum Shade + Shade string +) + +const ( + ColorRed Color = "red" + ColorBlue Color = "blue" +) + +const ( + ShadeDark Shade = "dark" + ShadeLight Shade = "light" +) +` + if err := os.WriteFile(filepath.Join(dir, "grouped.go"), []byte(src), 0o644); err != nil { + t.Fatal(err) + } + + got, err := ScanSwaggerEnumTypes([]string{dir}) + if err != nil { + t.Fatalf("ScanSwaggerEnumTypes: %v", err) + } + colorKey := EnumKey([]any{"red", "blue"}) + shadeKey := EnumKey([]any{"dark", "light"}) + if single(got, colorKey) != "Color" { + t.Fatalf("Color: map[%q] = %q, want %q", colorKey, got[colorKey], "Color") + } + if single(got, shadeKey) != "Shade" { + t.Fatalf("Shade: map[%q] = %q, want %q", shadeKey, got[shadeKey], "Shade") + } +} diff --git a/package/gitea/source/build/test-env-check.sh b/package/gitea/source/build/test-env-check.sh deleted file mode 100755 index 38e5a288..00000000 --- a/package/gitea/source/build/test-env-check.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh - -set -e - -if [ ! -f ./build/test-env-check.sh ]; then - echo "${0} can only be executed in gitea source root directory" - exit 1 -fi - - -echo "check uid ..." - -# the uid of gitea defined in "https://gitea.com/gitea/test-env" is 1000 -gitea_uid=$(id -u gitea) -if [ "$gitea_uid" != "1000" ]; then - echo "The uid of linux user 'gitea' is expected to be 1000, but it is $gitea_uid" - exit 1 -fi - -cur_uid=$(id -u) -if [ "$cur_uid" != "0" -a "$cur_uid" != "$gitea_uid" ]; then - echo "The uid of current linux user is expected to be 0 or $gitea_uid, but it is $cur_uid" - exit 1 -fi diff --git a/package/gitea/source/build/test-env-prepare.sh b/package/gitea/source/build/test-env-prepare.sh deleted file mode 100755 index 0c5bc25f..00000000 --- a/package/gitea/source/build/test-env-prepare.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -set -e - -if [ ! -f ./build/test-env-prepare.sh ]; then - echo "${0} can only be executed in gitea source root directory" - exit 1 -fi - -echo "change the owner of files to gitea ..." -chown -R gitea:gitea . diff --git a/package/gitea/source/cmd/actions.go b/package/gitea/source/cmd/actions.go index 44b6b7b5..576be764 100644 --- a/package/gitea/source/cmd/actions.go +++ b/package/gitea/source/cmd/actions.go @@ -7,8 +7,8 @@ import ( "context" "fmt" - "code.gitea.io/gitea/modules/private" - "code.gitea.io/gitea/modules/setting" + "gitea.dev/modules/private" + "gitea.dev/modules/setting" "github.com/urfave/cli/v3" ) diff --git a/package/gitea/source/cmd/admin.go b/package/gitea/source/cmd/admin.go index e5bde560..8fb79fb6 100644 --- a/package/gitea/source/cmd/admin.go +++ b/package/gitea/source/cmd/admin.go @@ -8,12 +8,12 @@ import ( "context" "fmt" - "code.gitea.io/gitea/models/db" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/log" - repo_module "code.gitea.io/gitea/modules/repository" + "gitea.dev/models/db" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/git" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/log" + repo_module "gitea.dev/modules/repository" "github.com/urfave/cli/v3" ) diff --git a/package/gitea/source/cmd/admin_auth.go b/package/gitea/source/cmd/admin_auth.go index b55bb148..6a00e961 100644 --- a/package/gitea/source/cmd/admin_auth.go +++ b/package/gitea/source/cmd/admin_auth.go @@ -10,9 +10,9 @@ import ( "os" "text/tabwriter" - auth_model "code.gitea.io/gitea/models/auth" - "code.gitea.io/gitea/models/db" - auth_service "code.gitea.io/gitea/services/auth" + auth_model "gitea.dev/models/auth" + "gitea.dev/models/db" + auth_service "gitea.dev/services/auth" "github.com/urfave/cli/v3" ) diff --git a/package/gitea/source/cmd/admin_auth_ldap.go b/package/gitea/source/cmd/admin_auth_ldap.go index c9be5abb..d3266fa4 100644 --- a/package/gitea/source/cmd/admin_auth_ldap.go +++ b/package/gitea/source/cmd/admin_auth_ldap.go @@ -8,9 +8,9 @@ import ( "fmt" "strings" - "code.gitea.io/gitea/models/auth" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/services/auth/source/ldap" + "gitea.dev/models/auth" + "gitea.dev/modules/util" + "gitea.dev/services/auth/source/ldap" "github.com/urfave/cli/v3" ) diff --git a/package/gitea/source/cmd/admin_auth_ldap_test.go b/package/gitea/source/cmd/admin_auth_ldap_test.go index 0e3e465e..f9b5338b 100644 --- a/package/gitea/source/cmd/admin_auth_ldap_test.go +++ b/package/gitea/source/cmd/admin_auth_ldap_test.go @@ -7,9 +7,9 @@ import ( "context" "testing" - "code.gitea.io/gitea/models/auth" - "code.gitea.io/gitea/modules/test" - "code.gitea.io/gitea/services/auth/source/ldap" + "gitea.dev/models/auth" + "gitea.dev/modules/test" + "gitea.dev/services/auth/source/ldap" "github.com/stretchr/testify/assert" "github.com/urfave/cli/v3" diff --git a/package/gitea/source/cmd/admin_auth_oauth.go b/package/gitea/source/cmd/admin_auth_oauth.go index 8848c94f..c4a86191 100644 --- a/package/gitea/source/cmd/admin_auth_oauth.go +++ b/package/gitea/source/cmd/admin_auth_oauth.go @@ -9,9 +9,9 @@ import ( "fmt" "net/url" - auth_model "code.gitea.io/gitea/models/auth" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/services/auth/source/oauth2" + auth_model "gitea.dev/models/auth" + "gitea.dev/modules/util" + "gitea.dev/services/auth/source/oauth2" "github.com/urfave/cli/v3" ) diff --git a/package/gitea/source/cmd/admin_auth_oauth_test.go b/package/gitea/source/cmd/admin_auth_oauth_test.go index bb9da667..c16dd96d 100644 --- a/package/gitea/source/cmd/admin_auth_oauth_test.go +++ b/package/gitea/source/cmd/admin_auth_oauth_test.go @@ -7,8 +7,8 @@ import ( "context" "testing" - auth_model "code.gitea.io/gitea/models/auth" - "code.gitea.io/gitea/services/auth/source/oauth2" + auth_model "gitea.dev/models/auth" + "gitea.dev/services/auth/source/oauth2" "github.com/stretchr/testify/assert" "github.com/urfave/cli/v3" diff --git a/package/gitea/source/cmd/admin_auth_smtp.go b/package/gitea/source/cmd/admin_auth_smtp.go index 93e0587f..b7c1a880 100644 --- a/package/gitea/source/cmd/admin_auth_smtp.go +++ b/package/gitea/source/cmd/admin_auth_smtp.go @@ -8,9 +8,9 @@ import ( "errors" "strings" - auth_model "code.gitea.io/gitea/models/auth" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/services/auth/source/smtp" + auth_model "gitea.dev/models/auth" + "gitea.dev/modules/util" + "gitea.dev/services/auth/source/smtp" "github.com/urfave/cli/v3" ) diff --git a/package/gitea/source/cmd/admin_auth_smtp_test.go b/package/gitea/source/cmd/admin_auth_smtp_test.go index e54e0183..2b890f15 100644 --- a/package/gitea/source/cmd/admin_auth_smtp_test.go +++ b/package/gitea/source/cmd/admin_auth_smtp_test.go @@ -7,8 +7,8 @@ import ( "context" "testing" - auth_model "code.gitea.io/gitea/models/auth" - "code.gitea.io/gitea/services/auth/source/smtp" + auth_model "gitea.dev/models/auth" + "gitea.dev/services/auth/source/smtp" "github.com/stretchr/testify/assert" "github.com/urfave/cli/v3" diff --git a/package/gitea/source/cmd/admin_heatmap.go b/package/gitea/source/cmd/admin_heatmap.go index ac2546f4..01da4b1f 100644 --- a/package/gitea/source/cmd/admin_heatmap.go +++ b/package/gitea/source/cmd/admin_heatmap.go @@ -8,11 +8,11 @@ import ( "fmt" "strings" - "code.gitea.io/gitea/models/db" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/log" - repo_service "code.gitea.io/gitea/services/repository" + "gitea.dev/models/db" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/git" + "gitea.dev/modules/log" + repo_service "gitea.dev/services/repository" "github.com/urfave/cli/v3" ) diff --git a/package/gitea/source/cmd/admin_heatmap_test.go b/package/gitea/source/cmd/admin_heatmap_test.go index 831fe10b..dc7f829f 100644 --- a/package/gitea/source/cmd/admin_heatmap_test.go +++ b/package/gitea/source/cmd/admin_heatmap_test.go @@ -9,14 +9,14 @@ import ( "testing" "time" - activities_model "code.gitea.io/gitea/models/activities" - "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" - "code.gitea.io/gitea/modules/git/gitcmd" - "code.gitea.io/gitea/modules/timeutil" - repo_service "code.gitea.io/gitea/services/repository" + activities_model "gitea.dev/models/activities" + "gitea.dev/models/db" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/timeutil" + repo_service "gitea.dev/services/repository" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/package/gitea/source/cmd/admin_regenerate.go b/package/gitea/source/cmd/admin_regenerate.go index aa235441..89b7bf38 100644 --- a/package/gitea/source/cmd/admin_regenerate.go +++ b/package/gitea/source/cmd/admin_regenerate.go @@ -6,9 +6,9 @@ package cmd import ( "context" - "code.gitea.io/gitea/modules/graceful" - asymkey_service "code.gitea.io/gitea/services/asymkey" - repo_service "code.gitea.io/gitea/services/repository" + "gitea.dev/modules/graceful" + asymkey_service "gitea.dev/services/asymkey" + repo_service "gitea.dev/services/repository" "github.com/urfave/cli/v3" ) diff --git a/package/gitea/source/cmd/admin_user_change_password.go b/package/gitea/source/cmd/admin_user_change_password.go index c27905b4..4d5fe586 100644 --- a/package/gitea/source/cmd/admin_user_change_password.go +++ b/package/gitea/source/cmd/admin_user_change_password.go @@ -8,11 +8,11 @@ import ( "errors" "fmt" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/auth/password" - "code.gitea.io/gitea/modules/optional" - "code.gitea.io/gitea/modules/setting" - user_service "code.gitea.io/gitea/services/user" + user_model "gitea.dev/models/user" + "gitea.dev/modules/auth/password" + "gitea.dev/modules/optional" + "gitea.dev/modules/setting" + user_service "gitea.dev/services/user" "github.com/urfave/cli/v3" ) diff --git a/package/gitea/source/cmd/admin_user_change_password_test.go b/package/gitea/source/cmd/admin_user_change_password_test.go index 902632f3..50fd8d9e 100644 --- a/package/gitea/source/cmd/admin_user_change_password_test.go +++ b/package/gitea/source/cmd/admin_user_change_password_test.go @@ -4,11 +4,12 @@ package cmd import ( + "io" "testing" - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" + "gitea.dev/models/db" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -82,7 +83,9 @@ func TestChangePasswordCommand(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - err := microcmdUserChangePassword().Run(ctx, tc.args) + cmd := microcmdUserChangePassword() + cmd.Writer, cmd.ErrWriter = io.Discard, io.Discard + err := cmd.Run(ctx, tc.args) require.Error(t, err) require.Contains(t, err.Error(), tc.expectedErr) }) diff --git a/package/gitea/source/cmd/admin_user_create.go b/package/gitea/source/cmd/admin_user_create.go index 7e5675cf..81b6f87a 100644 --- a/package/gitea/source/cmd/admin_user_create.go +++ b/package/gitea/source/cmd/admin_user_create.go @@ -9,12 +9,12 @@ import ( "fmt" "strings" - 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" - "code.gitea.io/gitea/modules/setting" + auth_model "gitea.dev/models/auth" + "gitea.dev/models/db" + user_model "gitea.dev/models/user" + pwd "gitea.dev/modules/auth/password" + "gitea.dev/modules/optional" + "gitea.dev/modules/setting" "github.com/urfave/cli/v3" ) @@ -158,7 +158,8 @@ func runCreateUser(ctx context.Context, c *cli.Command) error { } isAdmin := c.Bool("admin") - mustChangePassword := true // always default to true + // Only local, existing, regular users should be forced to update their password. Bot users for example are non-interactive + mustChangePassword := userType == user_model.UserTypeIndividual if c.IsSet("must-change-password") { if userType != user_model.UserTypeIndividual { return errors.New("must-change-password flag can only be set for individual users") diff --git a/package/gitea/source/cmd/admin_user_create_test.go b/package/gitea/source/cmd/admin_user_create_test.go index dbe949ff..ece2e886 100644 --- a/package/gitea/source/cmd/admin_user_create_test.go +++ b/package/gitea/source/cmd/admin_user_create_test.go @@ -8,10 +8,10 @@ import ( "strings" "testing" - auth_model "code.gitea.io/gitea/models/auth" - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" + auth_model "gitea.dev/models/auth" + "gitea.dev/models/db" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -63,6 +63,7 @@ func TestAdminUserCreate(t *testing.T) { u := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "u"}) assert.Equal(t, user_model.UserTypeBot, u.Type) assert.Empty(t, u.Passwd) + assert.False(t, u.MustChangePassword, "bot users should not be forced to change password") }) t.Run("AccessToken", func(t *testing.T) { diff --git a/package/gitea/source/cmd/admin_user_delete.go b/package/gitea/source/cmd/admin_user_delete.go index f9104157..cc70fe70 100644 --- a/package/gitea/source/cmd/admin_user_delete.go +++ b/package/gitea/source/cmd/admin_user_delete.go @@ -9,10 +9,10 @@ import ( "fmt" "strings" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/storage" - user_service "code.gitea.io/gitea/services/user" + user_model "gitea.dev/models/user" + "gitea.dev/modules/setting" + "gitea.dev/modules/storage" + user_service "gitea.dev/services/user" "github.com/urfave/cli/v3" ) diff --git a/package/gitea/source/cmd/admin_user_delete_test.go b/package/gitea/source/cmd/admin_user_delete_test.go index b68b3581..4fbd0435 100644 --- a/package/gitea/source/cmd/admin_user_delete_test.go +++ b/package/gitea/source/cmd/admin_user_delete_test.go @@ -8,10 +8,10 @@ import ( "strings" "testing" - auth_model "code.gitea.io/gitea/models/auth" - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" + auth_model "gitea.dev/models/auth" + "gitea.dev/models/db" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" "github.com/stretchr/testify/require" ) diff --git a/package/gitea/source/cmd/admin_user_generate_access_token.go b/package/gitea/source/cmd/admin_user_generate_access_token.go index 7f8330ff..cf42a97c 100644 --- a/package/gitea/source/cmd/admin_user_generate_access_token.go +++ b/package/gitea/source/cmd/admin_user_generate_access_token.go @@ -8,8 +8,8 @@ import ( "errors" "fmt" - auth_model "code.gitea.io/gitea/models/auth" - user_model "code.gitea.io/gitea/models/user" + auth_model "gitea.dev/models/auth" + user_model "gitea.dev/models/user" "github.com/urfave/cli/v3" ) diff --git a/package/gitea/source/cmd/admin_user_list.go b/package/gitea/source/cmd/admin_user_list.go index 2958fe0c..7f9ce57e 100644 --- a/package/gitea/source/cmd/admin_user_list.go +++ b/package/gitea/source/cmd/admin_user_list.go @@ -9,7 +9,7 @@ import ( "os" "text/tabwriter" - user_model "code.gitea.io/gitea/models/user" + user_model "gitea.dev/models/user" "github.com/urfave/cli/v3" ) diff --git a/package/gitea/source/cmd/admin_user_must_change_password.go b/package/gitea/source/cmd/admin_user_must_change_password.go index 468d462b..ff318dd0 100644 --- a/package/gitea/source/cmd/admin_user_must_change_password.go +++ b/package/gitea/source/cmd/admin_user_must_change_password.go @@ -8,8 +8,8 @@ import ( "errors" "fmt" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/setting" + user_model "gitea.dev/models/user" + "gitea.dev/modules/setting" "github.com/urfave/cli/v3" ) diff --git a/package/gitea/source/cmd/admin_user_must_change_password_test.go b/package/gitea/source/cmd/admin_user_must_change_password_test.go index efdbe3a9..cf81fbe0 100644 --- a/package/gitea/source/cmd/admin_user_must_change_password_test.go +++ b/package/gitea/source/cmd/admin_user_must_change_password_test.go @@ -6,9 +6,9 @@ package cmd import ( "testing" - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" + "gitea.dev/models/db" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/package/gitea/source/cmd/cert_test.go b/package/gitea/source/cmd/cert_test.go index 4242d891..c5775e52 100644 --- a/package/gitea/source/cmd/cert_test.go +++ b/package/gitea/source/cmd/cert_test.go @@ -4,6 +4,7 @@ package cmd import ( + "io" "path/filepath" "testing" @@ -107,6 +108,7 @@ func TestCertCommandFailures(t *testing.T) { for _, c := range cases { t.Run(c.name, func(t *testing.T) { app := cmdCert() + app.Writer, app.ErrWriter = io.Discard, io.Discard tempDir := t.TempDir() certFile := filepath.Join(tempDir, "cert.pem") diff --git a/package/gitea/source/cmd/cmd_test.go b/package/gitea/source/cmd/cmd_test.go deleted file mode 100644 index a36d05c7..00000000 --- a/package/gitea/source/cmd/cmd_test.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2025 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package cmd - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/urfave/cli/v3" -) - -func TestDefaultCommand(t *testing.T) { - test := func(t *testing.T, args []string, expectedRetName string, expectedRetValid bool) { - called := false - cmd := &cli.Command{ - DefaultCommand: "test", - Commands: []*cli.Command{ - { - Name: "test", - Action: func(ctx context.Context, command *cli.Command) error { - retName, retValid := isValidDefaultSubCommand(command) - assert.Equal(t, expectedRetName, retName) - assert.Equal(t, expectedRetValid, retValid) - called = true - return nil - }, - }, - }, - } - assert.NoError(t, cmd.Run(t.Context(), args)) - assert.True(t, called) - } - test(t, []string{"./gitea"}, "", true) - test(t, []string{"./gitea", "test"}, "", true) - test(t, []string{"./gitea", "other"}, "other", false) -} diff --git a/package/gitea/source/cmd/cmdtest/cmd_test.go b/package/gitea/source/cmd/cmdtest/cmd_test.go new file mode 100644 index 00000000..f41793c8 --- /dev/null +++ b/package/gitea/source/cmd/cmdtest/cmd_test.go @@ -0,0 +1,248 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +// Tests here reload the config system multiple times with uncontrollable details. +// So they must be in a separate package, to avoid affecting other tests + +package cmdtest + +import ( + "context" + "errors" + "fmt" + "io" + "path/filepath" + "strings" + "testing" + + "gitea.dev/cmd" + "gitea.dev/models/unittest" + "gitea.dev/modules/setting" + "gitea.dev/modules/test" + "gitea.dev/modules/util" + + "github.com/stretchr/testify/assert" + "github.com/urfave/cli/v3" +) + +func TestMain(m *testing.M) { + unittest.MainTest(m) +} + +func makePathOutput(workPath, customPath, customConf string) string { + return fmt.Sprintf("WorkPath=%s\nCustomPath=%s\nCustomConf=%s", workPath, customPath, customConf) +} + +func newTestApp(testCmd cli.Command) *cli.Command { + app := cmd.NewMainApp(cmd.AppVersion{}) + testCmd.Name = util.IfZero(testCmd.Name, "test-cmd") + cmd.PrepareSubcommandWithGlobalFlags(&testCmd) + app.Commands = append(app.Commands, &testCmd) + app.DefaultCommand = testCmd.Name + return app +} + +type runResult struct { + Stdout string + Stderr string + ExitCode int +} + +func runTestApp(app *cli.Command, args ...string) (runResult, error) { + outBuf := new(strings.Builder) + errBuf := new(strings.Builder) + app.Writer = outBuf + app.ErrWriter = errBuf + exitCode := -1 + defer test.MockVariableValue(&cli.ErrWriter, app.ErrWriter)() + defer test.MockVariableValue(&cli.OsExiter, func(code int) { + if exitCode == -1 { + exitCode = code // save the exit code once and then reset the writer (to simulate the exit) + app.Writer, app.ErrWriter, cli.ErrWriter = io.Discard, io.Discard, io.Discard + } + })() + err := cmd.RunMainApp(app, args...) + return runResult{outBuf.String(), errBuf.String(), exitCode}, err +} + +func TestCliCmd(t *testing.T) { + defaultWorkPath := filepath.FromSlash("/tmp/mocked-work-path") + defaultCustomPath := filepath.Join(defaultWorkPath, "custom") + defaultCustomConf := filepath.Join(defaultCustomPath, "conf/app.ini") + defer setting.MockBuiltinPaths(defaultWorkPath, "", "")() + + cli.CommandHelpTemplate = "(command help template)" + cli.RootCommandHelpTemplate = "(app help template)" + cli.SubcommandHelpTemplate = "(subcommand help template)" + + cases := []struct { + env map[string]string + cmd string + exp string + }{ + // help commands + { + cmd: "./gitea -h", + exp: "DEFAULT CONFIGURATION:", + }, + { + cmd: "./gitea help", + exp: "DEFAULT CONFIGURATION:", + }, + + { + cmd: "./gitea -c /dev/null -h", + exp: "ConfigFile: /dev/null", + }, + + { + cmd: "./gitea -c /dev/null help", + exp: "ConfigFile: /dev/null", + }, + { + cmd: "./gitea help -c /dev/null", + exp: "ConfigFile: /dev/null", + }, + + { + cmd: "./gitea -c /dev/null test-cmd -h", + exp: "ConfigFile: /dev/null", + }, + { + cmd: "./gitea test-cmd -c /dev/null -h", + exp: "ConfigFile: /dev/null", + }, + { + cmd: "./gitea test-cmd -h -c /dev/null", + exp: "ConfigFile: /dev/null", + }, + + { + cmd: "./gitea -c /dev/null test-cmd help", + exp: "ConfigFile: /dev/null", + }, + { + cmd: "./gitea test-cmd -c /dev/null help", + exp: "ConfigFile: /dev/null", + }, + { + cmd: "./gitea test-cmd help -c /dev/null", + exp: "ConfigFile: /dev/null", + }, + + // parse paths + { + cmd: "./gitea test-cmd", + exp: makePathOutput(defaultWorkPath, defaultCustomPath, defaultCustomConf), + }, + { + cmd: "./gitea -c /tmp/app.ini test-cmd", + exp: makePathOutput(defaultWorkPath, defaultCustomPath, "/tmp/app.ini"), + }, + { + cmd: "./gitea test-cmd -c /tmp/app.ini", + exp: makePathOutput(defaultWorkPath, defaultCustomPath, "/tmp/app.ini"), + }, + { + env: map[string]string{"GITEA_WORK_DIR": "/tmp"}, + cmd: "./gitea test-cmd", + exp: makePathOutput("/tmp", "/tmp/custom", "/tmp/custom/conf/app.ini"), + }, + { + env: map[string]string{"GITEA_WORK_DIR": "/tmp"}, + cmd: "./gitea test-cmd --work-path /tmp/other", + exp: makePathOutput("/tmp/other", "/tmp/other/custom", "/tmp/other/custom/conf/app.ini"), + }, + { + env: map[string]string{"GITEA_WORK_DIR": "/tmp"}, + cmd: "./gitea test-cmd --config /tmp/app-other.ini", + exp: makePathOutput("/tmp", "/tmp/custom", "/tmp/app-other.ini"), + }, + } + + for _, c := range cases { + t.Run(c.cmd, func(t *testing.T) { + app := newTestApp(cli.Command{ + Action: func(ctx context.Context, cmd *cli.Command) error { + _, _ = fmt.Fprint(cmd.Root().Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf)) + return nil + }, + }) + for k, v := range c.env { + t.Setenv(k, v) + } + args := strings.Split(c.cmd, " ") // for test only, "split" is good enough + r, err := runTestApp(app, args...) + assert.NoError(t, err, c.cmd) + assert.NotEmpty(t, c.exp, c.cmd) + if !assert.Contains(t, r.Stdout, c.exp, c.cmd) { + t.Log("Full output:\n" + r.Stdout) + t.Log("Expected:\n" + c.exp) + } + }) + } +} + +func TestCliCmdError(t *testing.T) { + app := newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return errors.New("normal error") }}) + r, err := runTestApp(app, "./gitea", "test-cmd") + assert.Error(t, err) + assert.Equal(t, 1, r.ExitCode) + assert.Empty(t, r.Stdout) + assert.Equal(t, "Command error: normal error\n", r.Stderr) + + app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return cli.Exit("exit error", 2) }}) + r, err = runTestApp(app, "./gitea", "test-cmd") + assert.Error(t, err) + assert.Equal(t, 2, r.ExitCode) + assert.Empty(t, r.Stdout) + assert.Equal(t, "exit error\n", r.Stderr) + + app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return nil }}) + r, err = runTestApp(app, "./gitea", "test-cmd", "--no-such") + assert.Error(t, err) + assert.Equal(t, 1, r.ExitCode) + assert.Empty(t, r.Stdout) + assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n", r.Stderr) + + app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return nil }}) + r, err = runTestApp(app, "./gitea", "test-cmd") + assert.NoError(t, err) + assert.Equal(t, -1, r.ExitCode) // the cli.OsExiter is not called + assert.Empty(t, r.Stdout) + assert.Empty(t, r.Stderr) +} + +func TestCliCmdBefore(t *testing.T) { + ctxNew := context.WithValue(context.Background(), any("key"), "value") + configValues := map[string]string{} + setting.CustomConf = "/tmp/any.ini" + var actionCtx context.Context + app := newTestApp(cli.Command{ + Before: func(context.Context, *cli.Command) (context.Context, error) { + configValues["before"] = setting.CustomConf + return ctxNew, nil + }, + Action: func(ctx context.Context, cmd *cli.Command) error { + configValues["action"] = setting.CustomConf + actionCtx = ctx + return nil + }, + }) + _, err := runTestApp(app, "./gitea", "--config", "/dev/null", "test-cmd") + assert.NoError(t, err) + assert.Equal(t, ctxNew, actionCtx) + assert.Equal(t, "/tmp/any.ini", configValues["before"], "BeforeFunc must be called before preparing config") + assert.Equal(t, "/dev/null", configValues["action"]) +} + +func TestCliCmdCompletion(t *testing.T) { + app := newTestApp(cli.Command{ + Action: func(ctx context.Context, cmd *cli.Command) error { return nil }, + }) + res, err := runTestApp(app, "./gitea", "completion", "bash", "--nonexist") + assert.Error(t, err) + assert.Equal(t, 1, res.ExitCode) + assert.Equal(t, "", res.Stdout) + assert.Equal(t, "Incorrect Usage: flag provided but not defined: -nonexist\n", res.Stderr) +} diff --git a/package/gitea/source/cmd/config.go b/package/gitea/source/cmd/config.go index 5303b0e1..42880d99 100644 --- a/package/gitea/source/cmd/config.go +++ b/package/gitea/source/cmd/config.go @@ -9,7 +9,7 @@ import ( "fmt" "os" - "code.gitea.io/gitea/modules/setting" + "gitea.dev/modules/setting" "github.com/urfave/cli/v3" ) diff --git a/package/gitea/source/cmd/doctor.go b/package/gitea/source/cmd/doctor.go index 188740db..8941be0c 100644 --- a/package/gitea/source/cmd/doctor.go +++ b/package/gitea/source/cmd/doctor.go @@ -12,16 +12,15 @@ import ( "strings" "text/tabwriter" - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/migrations" - migrate_base "code.gitea.io/gitea/models/migrations/base" - "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/services/doctor" + "gitea.dev/models/db" + "gitea.dev/models/migrations" + migrate_base "gitea.dev/models/migrations/base" + "gitea.dev/modules/container" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" + "gitea.dev/services/doctor" "github.com/urfave/cli/v3" - "xorm.io/xorm" ) func newDoctorCommand() *cli.Command { @@ -132,7 +131,7 @@ func runRecreateTable(ctx context.Context, cmd *cli.Command) error { } recreateTables := migrate_base.RecreateTables(beans...) - return db.InitEngineWithMigration(context.Background(), func(ctx context.Context, x *xorm.Engine) error { + return db.InitEngineWithMigration(context.Background(), func(ctx context.Context, x db.EngineMigration) error { if err := migrations.EnsureUpToDate(ctx, x); err != nil { return err } diff --git a/package/gitea/source/cmd/doctor_convert.go b/package/gitea/source/cmd/doctor_convert.go index f4867912..eceda001 100644 --- a/package/gitea/source/cmd/doctor_convert.go +++ b/package/gitea/source/cmd/doctor_convert.go @@ -7,9 +7,9 @@ import ( "context" "fmt" - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" + "gitea.dev/models/db" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" "github.com/urfave/cli/v3" ) diff --git a/package/gitea/source/cmd/doctor_test.go b/package/gitea/source/cmd/doctor_test.go index 7d2f3589..6cc22b0c 100644 --- a/package/gitea/source/cmd/doctor_test.go +++ b/package/gitea/source/cmd/doctor_test.go @@ -7,8 +7,8 @@ import ( "context" "testing" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/services/doctor" + "gitea.dev/modules/log" + "gitea.dev/services/doctor" "github.com/stretchr/testify/assert" "github.com/urfave/cli/v3" diff --git a/package/gitea/source/cmd/dump.go b/package/gitea/source/cmd/dump.go index 49f4d9e8..719e62d3 100644 --- a/package/gitea/source/cmd/dump.go +++ b/package/gitea/source/cmd/dump.go @@ -11,13 +11,13 @@ import ( "path/filepath" "strings" - "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" - "code.gitea.io/gitea/modules/storage" - "code.gitea.io/gitea/modules/util" + "gitea.dev/models/db" + "gitea.dev/modules/dump" + "gitea.dev/modules/json" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" + "gitea.dev/modules/storage" + "gitea.dev/modules/util" "gitea.com/go-chi/session" "github.com/urfave/cli/v3" @@ -203,8 +203,8 @@ func runDump(ctx context.Context, cmd *cli.Command) error { } }() - targetDBType := cmd.String("database") - if len(targetDBType) > 0 && targetDBType != setting.Database.Type.String() { + targetDBType := setting.DatabaseType(cmd.String("database")) + if targetDBType != "" && targetDBType != setting.Database.Type { log.Info("Dumping database %s => %s...", setting.Database.Type, targetDBType) } else { log.Info("Dumping database...") diff --git a/package/gitea/source/cmd/dump_repo.go b/package/gitea/source/cmd/dump_repo.go index 36745436..cc84922e 100644 --- a/package/gitea/source/cmd/dump_repo.go +++ b/package/gitea/source/cmd/dump_repo.go @@ -10,14 +10,14 @@ import ( "os" "strings" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/log" - base "code.gitea.io/gitea/modules/migration" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/services/convert" - "code.gitea.io/gitea/services/migrations" + "gitea.dev/modules/git" + "gitea.dev/modules/log" + base "gitea.dev/modules/migration" + "gitea.dev/modules/setting" + "gitea.dev/modules/structs" + "gitea.dev/modules/util" + "gitea.dev/services/convert" + "gitea.dev/services/migrations" "github.com/urfave/cli/v3" ) diff --git a/package/gitea/source/cmd/embedded.go b/package/gitea/source/cmd/embedded.go index e2110756..add8dda1 100644 --- a/package/gitea/source/cmd/embedded.go +++ b/package/gitea/source/cmd/embedded.go @@ -11,14 +11,14 @@ import ( "path/filepath" "strings" - "code.gitea.io/gitea/modules/assetfs" - "code.gitea.io/gitea/modules/glob" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/options" - "code.gitea.io/gitea/modules/public" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/templates" - "code.gitea.io/gitea/modules/util" + "gitea.dev/modules/assetfs" + "gitea.dev/modules/glob" + "gitea.dev/modules/log" + "gitea.dev/modules/options" + "gitea.dev/modules/public" + "gitea.dev/modules/setting" + "gitea.dev/modules/templates" + "gitea.dev/modules/util" "github.com/urfave/cli/v3" ) diff --git a/package/gitea/source/cmd/generate.go b/package/gitea/source/cmd/generate.go index 21f8b42b..239b75ba 100644 --- a/package/gitea/source/cmd/generate.go +++ b/package/gitea/source/cmd/generate.go @@ -6,10 +6,12 @@ package cmd import ( "context" + "errors" "fmt" "os" - "code.gitea.io/gitea/modules/generate" + "gitea.dev/modules/generate" + "gitea.dev/modules/ssh" "github.com/mattn/go-isatty" "github.com/urfave/cli/v3" @@ -21,6 +23,7 @@ func newGenerateCommand() *cli.Command { Usage: "Generate Gitea's secrets/keys/tokens", Commands: []*cli.Command{ newGenerateSecretCommand(), + newGenerateSSHCommand(), }, } } @@ -37,6 +40,17 @@ func newGenerateSecretCommand() *cli.Command { } } +func newGenerateSSHCommand() *cli.Command { + return &cli.Command{ + Name: "ssh", + Usage: "Generate ssh keys", + Commands: []*cli.Command{ + newGenerateSSHKeyCommand(), + newGenerateSSHHostKeysCommand(), + }, + } +} + func newGenerateInternalTokenCommand() *cli.Command { return &cli.Command{ Name: "INTERNAL_TOKEN", @@ -62,6 +76,30 @@ func newGenerateSecretKeyCommand() *cli.Command { } } +func newGenerateSSHKeyCommand() *cli.Command { + return &cli.Command{ + Name: "key", + Usage: "Generate a new ssh key", + Flags: []cli.Flag{ + &cli.IntFlag{Name: "bits", Aliases: []string{"b"}, Usage: "Number of bits in the key, ignored when key is ed25519"}, + &cli.StringFlag{Name: "type", Aliases: []string{"t"}, Value: "ed25519", Usage: "Specifies the type of key to create."}, + &cli.StringFlag{Name: "file", Aliases: []string{"f"}, Usage: "Specifies the path or base directory for the key file", Required: true}, + }, + Action: runGenerateKeyPair, + } +} + +func newGenerateSSHHostKeysCommand() *cli.Command { + return &cli.Command{ + Name: "host-keys", + Usage: "Generate host keys of all default key types (rsa, ecdsa, and ed25519) if they do not already exist.", + Flags: []cli.Flag{ + &cli.StringFlag{Name: "dir", Aliases: []string{"d"}, Usage: "Specifies the base directory for the key files", Required: true}, + }, + Action: runGenerateHostKey, + } +} + func runGenerateInternalToken(_ context.Context, c *cli.Command) error { internalToken, err := generate.NewInternalToken() if err != nil { @@ -103,3 +141,41 @@ func runGenerateSecretKey(_ context.Context, c *cli.Command) error { return nil } + +func runGenerateHostKey(_ context.Context, c *cli.Command) error { + file := c.String("dir") + info, err := os.Stat(file) + if errors.Is(err, os.ErrNotExist) { + if err = os.MkdirAll(file, 0o644); err != nil { + return err + } + } else if err != nil { + return err + } else if !info.IsDir() { + return errors.New("file already exists and is not a directory") + } + fmt.Fprintf(c.Writer, "Generating host keys in %s\n", file) + _, err = ssh.InitDefaultHostKeys(file) + return err +} + +func runGenerateKeyPair(_ context.Context, c *cli.Command) error { + file := c.String("file") + keyType := c.String("type") + + fmt.Fprintf(c.Writer, "Generating public/private %s key pair.\n", keyType) + + // Check if file exists to prevent overwriting + if _, err := os.Stat(file); err == nil { + if !confirm(c.Reader, c.Writer, "%s already exists.\nOverwrite (y/n)? ", file) { + fmt.Println("Aborting") + return nil + } + } + bits := c.Int("bits") + err := ssh.GenKeyPair(file, generate.SSHKeyType(keyType), bits) + if err == nil { + fmt.Printf("Your SSH key has been saved in %s\n", file) + } + return err +} diff --git a/package/gitea/source/cmd/cmd.go b/package/gitea/source/cmd/helper.go similarity index 86% rename from package/gitea/source/cmd/cmd.go rename to package/gitea/source/cmd/helper.go index 25e90a16..37b20104 100644 --- a/package/gitea/source/cmd/cmd.go +++ b/package/gitea/source/cmd/helper.go @@ -15,9 +15,9 @@ import ( "strings" "syscall" - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" + "gitea.dev/models/db" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" "github.com/urfave/cli/v3" ) @@ -38,22 +38,15 @@ func argsSet(c *cli.Command, args ...string) error { } // confirm waits for user input which confirms an action -func confirm() (bool, error) { +func confirm(stdin io.Reader, stdout io.Writer, msg string, args ...any) bool { var response string - - _, err := fmt.Scanln(&response) - if err != nil { - return false, err - } - + _, _ = fmt.Fprintf(stdout, msg, args...) + _, _ = fmt.Fscanln(stdin, &response) switch strings.ToLower(response) { case "y", "yes": - return true, nil - case "n", "no": - return false, nil - default: - return false, errors.New(response + " isn't a correct confirmation string") + return true } + return false } func initDB(ctx context.Context) error { @@ -124,7 +117,7 @@ func PrepareConsoleLoggerLevel(defaultLevel log.Level) func(context.Context, *cl if setting.InstallLock { // During config loading, there might also be logs (for example: deprecation warnings). // It must make sure that console logger is set up before config is loaded. - log.Error("Config is loaded before console logger is setup, it will cause bugs. Please fix it.") + log.Error("Config is loaded before console logger is setup, it will cause bugs. Please fix it. CustomConf=%s", setting.CustomConf) return nil, errors.New("console logger must be setup before config is loaded") } level := defaultLevel @@ -134,7 +127,7 @@ func PrepareConsoleLoggerLevel(defaultLevel log.Level) func(context.Context, *cl if globalBool(c, "debug") || globalBool(c, "verbose") { level = log.TRACE } - log.SetConsoleLogger(log.DEFAULT, "console-default", level) + log.SetupStderrLogger(log.DEFAULT, "console-stderr", level) return ctx, nil } } @@ -142,9 +135,9 @@ func PrepareConsoleLoggerLevel(defaultLevel log.Level) func(context.Context, *cl func isValidDefaultSubCommand(cmd *cli.Command) (string, bool) { // Dirty patch for urfave/cli's strange design. // "./gitea bad-cmd" should not start the web server. - rootArgs := cmd.Root().Args().Slice() - if len(rootArgs) != 0 && rootArgs[0] != cmd.Name { - return rootArgs[0], false + args := cmd.Args().Slice() + if len(args) != 0 { + return args[0], false } return "", true } diff --git a/package/gitea/source/cmd/hook.go b/package/gitea/source/cmd/hook.go index 4a6c7c29..f8e964d0 100644 --- a/package/gitea/source/cmd/hook.go +++ b/package/gitea/source/cmd/hook.go @@ -14,12 +14,12 @@ import ( "strings" "time" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/git/gitcmd" - "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" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/log" + "gitea.dev/modules/private" + repo_module "gitea.dev/modules/repository" + "gitea.dev/modules/setting" "github.com/urfave/cli/v3" ) @@ -151,9 +151,6 @@ func (d *delayWriter) WriteString(s string) (n int, err error) { } func (d *delayWriter) Close() error { - if d == nil { - return nil - } stopped := d.timer.Stop() if stopped || d.buf == nil { return nil @@ -163,16 +160,6 @@ func (d *delayWriter) Close() error { return err } -type nilWriter struct{} - -func (n *nilWriter) Write(p []byte) (int, error) { - return len(p), nil -} - -func (n *nilWriter) WriteString(s string) (int, error) { - return len(s), nil -} - func parseGitHookCommitRefLine(line string) (oldCommitID, newCommitID string, refFullName git.RefName, ok bool) { fields := strings.Split(line, " ") if len(fields) != 3 { @@ -227,8 +214,7 @@ Gitea or set your environment appropriately.`, "") total := 0 lastline := 0 - var out io.Writer - out = &nilWriter{} + out := io.Discard if setting.Git.VerbosePush { if setting.Git.VerbosePushDelay > 0 { dWriter := newDelayWriter(os.Stdout, setting.Git.VerbosePushDelay) @@ -350,12 +336,10 @@ Gitea or set your environment appropriately.`, "") return nil } - var out io.Writer - var dWriter *delayWriter - out = &nilWriter{} + out := io.Discard if setting.Git.VerbosePush { if setting.Git.VerbosePushDelay > 0 { - dWriter = newDelayWriter(os.Stdout, setting.Git.VerbosePushDelay) + dWriter := newDelayWriter(os.Stdout, setting.Git.VerbosePushDelay) defer dWriter.Close() out = dWriter } else { @@ -382,101 +366,62 @@ Gitea or set your environment appropriately.`, "") PushTrigger: repo_module.PushTrigger(os.Getenv(repo_module.EnvPushTrigger)), IsWiki: isWiki, } - oldCommitIDs := make([]string, hookBatchSize) - newCommitIDs := make([]string, hookBatchSize) - refFullNames := make([]git.RefName, hookBatchSize) - count := 0 - total := 0 - wasEmpty := false - masterPushed := false + + oldCommitIDs := make([]string, 0, hookBatchSize) + newCommitIDs := make([]string, 0, hookBatchSize) + refFullNames := make([]git.RefName, 0, hookBatchSize) results := make([]private.HookPostReceiveBranchResult, 0) + defer func() { + hookPrintResults(results) + }() + + processBatch := func() error { + if len(refFullNames) == 0 { + return nil + } + _, _ = fmt.Fprintf(out, " Processing %d references\n", len(refFullNames)) + hookOptions.OldCommitIDs = oldCommitIDs + hookOptions.NewCommitIDs = newCommitIDs + hookOptions.RefFullNames = refFullNames + resp, extra := private.HookPostReceive(ctx, repoUser, repoName, hookOptions) + if extra.HasError() { + return fail(ctx, extra.UserMsg, "HookPostReceive failed: %v", extra.Error) + } + results = append(results, resp.Results...) + oldCommitIDs = oldCommitIDs[:0] + newCommitIDs = newCommitIDs[:0] + refFullNames = refFullNames[:0] + return nil + } + scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { - // TODO: support news feeds for wiki + // wiki doesn't need "post-receive" at the moment if isWiki { continue } - var ok bool - oldCommitIDs[count], newCommitIDs[count], refFullNames[count], ok = parseGitHookCommitRefLine(scanner.Text()) + oldCommitID, newCommitID, refFullName, ok := parseGitHookCommitRefLine(scanner.Text()) if !ok { continue } + _, _ = fmt.Fprintf(out, ".") - fmt.Fprintf(out, ".") - commitID, _ := git.NewIDFromString(newCommitIDs[count]) - if refFullNames[count] == git.BranchPrefix+"master" && !commitID.IsZero() && count == total { - masterPushed = true - } - count++ - total++ - - if count >= hookBatchSize { - fmt.Fprintf(out, " Processing %d references\n", count) - hookOptions.OldCommitIDs = oldCommitIDs - hookOptions.NewCommitIDs = newCommitIDs - hookOptions.RefFullNames = refFullNames - resp, extra := private.HookPostReceive(ctx, repoUser, repoName, hookOptions) - if extra.HasError() { - _ = dWriter.Close() - hookPrintResults(results) - return fail(ctx, extra.UserMsg, "HookPostReceive failed: %v", extra.Error) + oldCommitIDs = append(oldCommitIDs, oldCommitID) + newCommitIDs = append(newCommitIDs, newCommitID) + refFullNames = append(refFullNames, refFullName) + if len(refFullNames) >= hookBatchSize { + // process and start a new batch + if err := processBatch(); err != nil { + return err } - wasEmpty = wasEmpty || resp.RepoWasEmpty - results = append(results, resp.Results...) - count = 0 } } if err := scanner.Err(); err != nil { - _ = dWriter.Close() - hookPrintResults(results) return fail(ctx, "Hook failed: stdin read error", "scanner error: %v", err) } - - if count == 0 { - if wasEmpty && masterPushed { - // We need to tell the repo to reset the default branch to master - extra := private.SetDefaultBranch(ctx, repoUser, repoName, "master") - if extra.HasError() { - return fail(ctx, extra.UserMsg, "SetDefaultBranch failed: %v", extra.Error) - } - } - fmt.Fprintf(out, "Processed %d references in total\n", total) - - _ = dWriter.Close() - hookPrintResults(results) - return nil - } - - hookOptions.OldCommitIDs = oldCommitIDs[:count] - hookOptions.NewCommitIDs = newCommitIDs[:count] - hookOptions.RefFullNames = refFullNames[:count] - - fmt.Fprintf(out, " Processing %d references\n", count) - - resp, extra := private.HookPostReceive(ctx, repoUser, repoName, hookOptions) - if resp == nil { - _ = dWriter.Close() - hookPrintResults(results) - return fail(ctx, extra.UserMsg, "HookPostReceive failed: %v", extra.Error) - } - wasEmpty = wasEmpty || resp.RepoWasEmpty - results = append(results, resp.Results...) - - fmt.Fprintf(out, "Processed %d references in total\n", total) - - if wasEmpty && masterPushed { - // We need to tell the repo to reset the default branch to master - extra := private.SetDefaultBranch(ctx, repoUser, repoName, "master") - if extra.HasError() { - return fail(ctx, extra.UserMsg, "SetDefaultBranch failed: %v", extra.Error) - } - } - _ = dWriter.Close() - hookPrintResults(results) - - return nil + return processBatch() } func hookPrintResults(results []private.HookPostReceiveBranchResult) { diff --git a/package/gitea/source/cmd/keys.go b/package/gitea/source/cmd/keys.go index 912cf250..2f9f52e5 100644 --- a/package/gitea/source/cmd/keys.go +++ b/package/gitea/source/cmd/keys.go @@ -9,8 +9,8 @@ import ( "fmt" "strings" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/private" + "gitea.dev/modules/log" + "gitea.dev/modules/private" "github.com/urfave/cli/v3" ) diff --git a/package/gitea/source/cmd/mailer.go b/package/gitea/source/cmd/mailer.go index a7dbd68e..d7b2f6b7 100644 --- a/package/gitea/source/cmd/mailer.go +++ b/package/gitea/source/cmd/mailer.go @@ -7,8 +7,8 @@ import ( "context" "fmt" - "code.gitea.io/gitea/modules/private" - "code.gitea.io/gitea/modules/setting" + "gitea.dev/modules/private" + "gitea.dev/modules/setting" "github.com/urfave/cli/v3" ) @@ -22,14 +22,10 @@ func runSendMail(ctx context.Context, c *cli.Command) error { if !confirmSkipped { if len(body) == 0 { - fmt.Print("warning: Content is empty") + fmt.Println("warning: Content is empty") } - fmt.Print("Proceed with sending email? [Y/n] ") - isConfirmed, err := confirm() - if err != nil { - return err - } else if !isConfirmed { + if !confirm(c.Reader, c.Writer, "Proceed with sending email? [Y/n] ") { fmt.Println("The mail was not sent") return nil } diff --git a/package/gitea/source/cmd/main.go b/package/gitea/source/cmd/main.go index a6b89a6f..66b2fba4 100644 --- a/package/gitea/source/cmd/main.go +++ b/package/gitea/source/cmd/main.go @@ -5,13 +5,13 @@ package cmd import ( "context" + "errors" "fmt" "io" "os" - "strings" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" "github.com/urfave/cli/v3" ) @@ -48,7 +48,7 @@ DEFAULT CONFIGURATION: } } -func prepareSubcommandWithGlobalFlags(originCmd *cli.Command) { +func PrepareSubcommandWithGlobalFlags(originCmd *cli.Command) { originBefore := originCmd.Before originCmd.Before = func(ctxOrig context.Context, cmd *cli.Command) (ctx context.Context, err error) { ctx = ctxOrig @@ -145,7 +145,7 @@ func NewMainApp(appVer AppVersion) *cli.Command { app.Before = PrepareConsoleLoggerLevel(log.INFO) for i := range subCmdWithConfig { - prepareSubcommandWithGlobalFlags(subCmdWithConfig[i]) + PrepareSubcommandWithGlobalFlags(subCmdWithConfig[i]) } app.Commands = append(app.Commands, subCmdWithConfig...) app.Commands = append(app.Commands, subCmdStandalone...) @@ -154,16 +154,37 @@ func NewMainApp(appVer AppVersion) *cli.Command { return app } +// usageErr marks a usage error already reported by cliOnUsageError, so RunMainApp does not print it again. +type usageErr struct{ err error } + +func (e usageErr) Error() string { return e.err.Error() } +func (e usageErr) Unwrap() error { return e.err } + +// cliOnUsageError reports usage errors itself instead of letting urfave/cli dump the full help to stdout (since urfave/cli v3.10). +func cliOnUsageError(_ context.Context, cmd *cli.Command, err error, _ bool) error { + _, _ = fmt.Fprintf(cmd.Root().ErrWriter, "Incorrect Usage: %s\n", err.Error()) + return usageErr{err} +} + +func setCLIOnUsageError(cmd *cli.Command) { + _ = cmd.Walk(func(c *cli.Command) error { + c.OnUsageError = cliOnUsageError + return nil + }) +} + func RunMainApp(app *cli.Command, args ...string) error { ctx, cancel := installSignals() defer cancel() + setCLIOnUsageError(app) + // the completion subcommands are built during app.Run, after the Walk above, so cover them via this hook + app.ConfigureShellCompletionCommand = setCLIOnUsageError err := app.Run(ctx, args) if err == nil { return nil } - if strings.HasPrefix(err.Error(), "flag provided but not defined:") { - // the cli package should already have output the error message, so just exit - cli.OsExiter(1) + if _, ok := errors.AsType[usageErr](err); ok { + cli.OsExiter(1) // cliOnUsageError already reported it return err } _, _ = fmt.Fprintf(app.ErrWriter, "Command error: %v\n", err) diff --git a/package/gitea/source/cmd/main_test.go b/package/gitea/source/cmd/main_test.go index b1f6bb3b..04769807 100644 --- a/package/gitea/source/cmd/main_test.go +++ b/package/gitea/source/cmd/main_test.go @@ -5,17 +5,9 @@ package cmd import ( "context" - "errors" - "fmt" - "io" - "path/filepath" - "strings" "testing" - "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/test" - "code.gitea.io/gitea/modules/util" + "gitea.dev/models/unittest" "github.com/stretchr/testify/assert" "github.com/urfave/cli/v3" @@ -25,209 +17,29 @@ func TestMain(m *testing.M) { unittest.MainTest(m) } -func makePathOutput(workPath, customPath, customConf string) string { - return fmt.Sprintf("WorkPath=%s\nCustomPath=%s\nCustomConf=%s", workPath, customPath, customConf) -} - -func newTestApp(testCmd cli.Command) *cli.Command { - app := NewMainApp(AppVersion{}) - testCmd.Name = util.IfZero(testCmd.Name, "test-cmd") - prepareSubcommandWithGlobalFlags(&testCmd) - app.Commands = append(app.Commands, &testCmd) - app.DefaultCommand = testCmd.Name - return app -} - -type runResult struct { - Stdout string - Stderr string - ExitCode int -} - -func runTestApp(app *cli.Command, args ...string) (runResult, error) { - outBuf := new(strings.Builder) - errBuf := new(strings.Builder) - app.Writer = outBuf - app.ErrWriter = errBuf - exitCode := -1 - defer test.MockVariableValue(&cli.ErrWriter, app.ErrWriter)() - defer test.MockVariableValue(&cli.OsExiter, func(code int) { - if exitCode == -1 { - exitCode = code // save the exit code once and then reset the writer (to simulate the exit) - app.Writer, app.ErrWriter, cli.ErrWriter = io.Discard, io.Discard, io.Discard - } - })() - err := RunMainApp(app, args...) - return runResult{outBuf.String(), errBuf.String(), exitCode}, err -} - -func TestCliCmd(t *testing.T) { - defaultWorkPath := filepath.Dir(setting.AppPath) - defaultCustomPath := filepath.Join(defaultWorkPath, "custom") - defaultCustomConf := filepath.Join(defaultCustomPath, "conf/app.ini") - - cli.CommandHelpTemplate = "(command help template)" - cli.RootCommandHelpTemplate = "(app help template)" - cli.SubcommandHelpTemplate = "(subcommand help template)" - - cases := []struct { - env map[string]string - cmd string - exp string - }{ - // help commands - { - cmd: "./gitea -h", - exp: "DEFAULT CONFIGURATION:", - }, - { - cmd: "./gitea help", - exp: "DEFAULT CONFIGURATION:", - }, - - { - cmd: "./gitea -c /dev/null -h", - exp: "ConfigFile: /dev/null", - }, - - { - cmd: "./gitea -c /dev/null help", - exp: "ConfigFile: /dev/null", - }, - { - cmd: "./gitea help -c /dev/null", - exp: "ConfigFile: /dev/null", - }, - - { - cmd: "./gitea -c /dev/null test-cmd -h", - exp: "ConfigFile: /dev/null", - }, - { - cmd: "./gitea test-cmd -c /dev/null -h", - exp: "ConfigFile: /dev/null", - }, - { - cmd: "./gitea test-cmd -h -c /dev/null", - exp: "ConfigFile: /dev/null", - }, - - { - cmd: "./gitea -c /dev/null test-cmd help", - exp: "ConfigFile: /dev/null", - }, - { - cmd: "./gitea test-cmd -c /dev/null help", - exp: "ConfigFile: /dev/null", - }, - { - cmd: "./gitea test-cmd help -c /dev/null", - exp: "ConfigFile: /dev/null", - }, - - // parse paths - { - cmd: "./gitea test-cmd", - exp: makePathOutput(defaultWorkPath, defaultCustomPath, defaultCustomConf), - }, - { - cmd: "./gitea -c /tmp/app.ini test-cmd", - exp: makePathOutput(defaultWorkPath, defaultCustomPath, "/tmp/app.ini"), - }, - { - cmd: "./gitea test-cmd -c /tmp/app.ini", - exp: makePathOutput(defaultWorkPath, defaultCustomPath, "/tmp/app.ini"), - }, - { - env: map[string]string{"GITEA_WORK_DIR": "/tmp"}, - cmd: "./gitea test-cmd", - exp: makePathOutput("/tmp", "/tmp/custom", "/tmp/custom/conf/app.ini"), - }, - { - env: map[string]string{"GITEA_WORK_DIR": "/tmp"}, - cmd: "./gitea test-cmd --work-path /tmp/other", - exp: makePathOutput("/tmp/other", "/tmp/other/custom", "/tmp/other/custom/conf/app.ini"), - }, - { - env: map[string]string{"GITEA_WORK_DIR": "/tmp"}, - cmd: "./gitea test-cmd --config /tmp/app-other.ini", - exp: makePathOutput("/tmp", "/tmp/custom", "/tmp/app-other.ini"), - }, - } - - for _, c := range cases { - t.Run(c.cmd, func(t *testing.T) { - defer test.MockVariableValue(&setting.InstallLock, false)() - app := newTestApp(cli.Command{ - Action: func(ctx context.Context, cmd *cli.Command) error { - _, _ = fmt.Fprint(cmd.Root().Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf)) - return nil +func TestDefaultCommand(t *testing.T) { + test := func(t *testing.T, args []string, expectedRetName string, expectedRetValid bool) { + called := false + cmd := &cli.Command{ + DefaultCommand: "test", + Commands: []*cli.Command{ + { + Name: "test", + Action: func(ctx context.Context, command *cli.Command) error { + retName, retValid := isValidDefaultSubCommand(command) + assert.Equal(t, expectedRetName, retName) + assert.Equal(t, expectedRetValid, retValid) + called = true + return nil + }, }, - }) - for k, v := range c.env { - t.Setenv(k, v) - } - args := strings.Split(c.cmd, " ") // for test only, "split" is good enough - r, err := runTestApp(app, args...) - assert.NoError(t, err, c.cmd) - assert.NotEmpty(t, c.exp, c.cmd) - if !assert.Contains(t, r.Stdout, c.exp, c.cmd) { - t.Log("Full output:\n" + r.Stdout) - t.Log("Expected:\n" + c.exp) - } - }) + }, + } + assert.NoError(t, cmd.Run(t.Context(), args)) + assert.True(t, called) } -} - -func TestCliCmdError(t *testing.T) { - app := newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return errors.New("normal error") }}) - r, err := runTestApp(app, "./gitea", "test-cmd") - assert.Error(t, err) - assert.Equal(t, 1, r.ExitCode) - assert.Empty(t, r.Stdout) - assert.Equal(t, "Command error: normal error\n", r.Stderr) - - app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return cli.Exit("exit error", 2) }}) - r, err = runTestApp(app, "./gitea", "test-cmd") - assert.Error(t, err) - assert.Equal(t, 2, r.ExitCode) - assert.Empty(t, r.Stdout) - assert.Equal(t, "exit error\n", r.Stderr) - - app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return nil }}) - r, err = runTestApp(app, "./gitea", "test-cmd", "--no-such") - assert.Error(t, err) - assert.Equal(t, 1, r.ExitCode) - assert.Empty(t, r.Stdout) - assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n\n", r.Stderr) - - app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return nil }}) - r, err = runTestApp(app, "./gitea", "test-cmd") - assert.NoError(t, err) - assert.Equal(t, -1, r.ExitCode) // the cli.OsExiter is not called - assert.Empty(t, r.Stdout) - assert.Empty(t, r.Stderr) -} - -func TestCliCmdBefore(t *testing.T) { - ctxNew := context.WithValue(context.Background(), any("key"), "value") - configValues := map[string]string{} - setting.CustomConf = "/tmp/any.ini" - var actionCtx context.Context - app := newTestApp(cli.Command{ - Before: func(context.Context, *cli.Command) (context.Context, error) { - configValues["before"] = setting.CustomConf - return ctxNew, nil - }, - Action: func(ctx context.Context, cmd *cli.Command) error { - configValues["action"] = setting.CustomConf - actionCtx = ctx - return nil - }, - }) - _, err := runTestApp(app, "./gitea", "--config", "/dev/null", "test-cmd") - assert.NoError(t, err) - assert.Equal(t, ctxNew, actionCtx) - assert.Equal(t, "/tmp/any.ini", configValues["before"], "BeforeFunc must be called before preparing config") - assert.Equal(t, "/dev/null", configValues["action"]) + test(t, []string{"./gitea"}, "", true) + test(t, []string{"./gitea", "test"}, "", true) + test(t, []string{"./gitea", "other"}, "other", false) + test(t, []string{"./gitea", "test", "extra"}, "extra", false) } diff --git a/package/gitea/source/cmd/manager.go b/package/gitea/source/cmd/manager.go index 586c6599..85fccc99 100644 --- a/package/gitea/source/cmd/manager.go +++ b/package/gitea/source/cmd/manager.go @@ -8,7 +8,7 @@ import ( "os" "time" - "code.gitea.io/gitea/modules/private" + "gitea.dev/modules/private" "github.com/urfave/cli/v3" ) diff --git a/package/gitea/source/cmd/manager_logging.go b/package/gitea/source/cmd/manager_logging.go index 5812e707..a54041f0 100644 --- a/package/gitea/source/cmd/manager_logging.go +++ b/package/gitea/source/cmd/manager_logging.go @@ -5,60 +5,14 @@ package cmd import ( "context" - "errors" "fmt" "os" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/private" + "gitea.dev/modules/private" "github.com/urfave/cli/v3" ) -func defaultLoggingFlags() []cli.Flag { - return []cli.Flag{ - &cli.StringFlag{ - Name: "logger", - Usage: `Logger name - will default to "default"`, - }, - &cli.StringFlag{ - Name: "writer", - Usage: "Name of the log writer - will default to mode", - }, - &cli.StringFlag{ - Name: "level", - Usage: "Logging level for the new logger", - }, - &cli.StringFlag{ - Name: "stacktrace-level", - Aliases: []string{"L"}, - Usage: "Stacktrace logging level", - }, - &cli.StringFlag{ - Name: "flags", - Aliases: []string{"F"}, - Usage: "Flags for the logger", - }, - &cli.StringFlag{ - Name: "expression", - Aliases: []string{"e"}, - Usage: "Matching expression for the logger", - }, - &cli.StringFlag{ - Name: "prefix", - Aliases: []string{"p"}, - Usage: "Prefix for the logger", - }, - &cli.BoolFlag{ - Name: "color", - Usage: "Use color in the logs", - }, - &cli.BoolFlag{ - Name: "debug", - }, - } -} - func newLoggingCommand() *cli.Command { return &cli.Command{ Name: "logging", @@ -91,92 +45,6 @@ func newLoggingCommand() *cli.Command { }, }, Action: runReleaseReopenLogging, - }, { - Name: "remove", - Usage: "Remove a logger", - ArgsUsage: "[name] Name of logger to remove", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "debug", - }, &cli.StringFlag{ - Name: "logger", - Usage: `Logger name - will default to "default"`, - }, - }, - Action: runRemoveLogger, - }, { - Name: "add", - Usage: "Add a logger", - Commands: []*cli.Command{ - { - Name: "file", - Usage: "Add a file logger", - Flags: append(defaultLoggingFlags(), []cli.Flag{ - &cli.StringFlag{ - Name: "filename", - Aliases: []string{"f"}, - Usage: "Filename for the logger - this must be set.", - }, - &cli.BoolFlag{ - Name: "rotate", - Aliases: []string{"r"}, - Usage: "Rotate logs", - }, - &cli.Int64Flag{ - Name: "max-size", - Aliases: []string{"s"}, - Usage: "Maximum size in bytes before rotation", - }, - &cli.BoolFlag{ - Name: "daily", - Aliases: []string{"d"}, - Usage: "Rotate logs daily", - }, - &cli.IntFlag{ - Name: "max-days", - Aliases: []string{"D"}, - Usage: "Maximum number of daily logs to keep", - }, - &cli.BoolFlag{ - Name: "compress", - Aliases: []string{"z"}, - Usage: "Compress rotated logs", - }, - &cli.IntFlag{ - Name: "compression-level", - Aliases: []string{"Z"}, - Usage: "Compression level to use", - }, - }...), - Action: runAddFileLogger, - }, { - Name: "conn", - Usage: "Add a net conn logger", - Flags: append(defaultLoggingFlags(), []cli.Flag{ - &cli.BoolFlag{ - Name: "reconnect-on-message", - Aliases: []string{"R"}, - Usage: "Reconnect to host for every message", - }, - &cli.BoolFlag{ - Name: "reconnect", - Aliases: []string{"r"}, - Usage: "Reconnect to host when connection is dropped", - }, - &cli.StringFlag{ - Name: "protocol", - Aliases: []string{"P"}, - Usage: "Set protocol to use: tcp, unix, or udp (defaults to tcp)", - }, - &cli.StringFlag{ - Name: "address", - Aliases: []string{"a"}, - Usage: "Host address and port to connect to (defaults to :7020)", - }, - }...), - Action: runAddConnLogger, - }, - }, }, { Name: "log-sql", Usage: "Set LogSQL", @@ -195,107 +63,6 @@ func newLoggingCommand() *cli.Command { } } -func runRemoveLogger(ctx context.Context, c *cli.Command) error { - setup(ctx, c.Bool("debug")) - logger := c.String("logger") - if len(logger) == 0 { - logger = log.DEFAULT - } - writer := c.Args().First() - - extra := private.RemoveLogger(ctx, logger, writer) - return handleCliResponseExtra(extra) -} - -func runAddConnLogger(ctx context.Context, c *cli.Command) error { - setup(ctx, c.Bool("debug")) - vals := map[string]any{} - mode := "conn" - vals["net"] = "tcp" - if c.IsSet("protocol") { - switch c.String("protocol") { - case "udp": - vals["net"] = "udp" - case "unix": - vals["net"] = "unix" - } - } - if c.IsSet("address") { - vals["address"] = c.String("address") - } else { - vals["address"] = ":7020" - } - if c.IsSet("reconnect") { - vals["reconnect"] = c.Bool("reconnect") - } - if c.IsSet("reconnect-on-message") { - vals["reconnectOnMsg"] = c.Bool("reconnect-on-message") - } - return commonAddLogger(ctx, c, mode, vals) -} - -func runAddFileLogger(ctx context.Context, c *cli.Command) error { - setup(ctx, c.Bool("debug")) - vals := map[string]any{} - mode := "file" - if c.IsSet("filename") { - vals["filename"] = c.String("filename") - } else { - return errors.New("filename must be set when creating a file logger") - } - if c.IsSet("rotate") { - vals["rotate"] = c.Bool("rotate") - } - if c.IsSet("max-size") { - vals["maxsize"] = c.Int64("max-size") - } - if c.IsSet("daily") { - vals["daily"] = c.Bool("daily") - } - if c.IsSet("max-days") { - vals["maxdays"] = c.Int("max-days") - } - if c.IsSet("compress") { - vals["compress"] = c.Bool("compress") - } - if c.IsSet("compression-level") { - vals["compressionLevel"] = c.Int("compression-level") - } - return commonAddLogger(ctx, c, mode, vals) -} - -func commonAddLogger(ctx context.Context, c *cli.Command, mode string, vals map[string]any) error { - if len(c.String("level")) > 0 { - vals["level"] = log.LevelFromString(c.String("level")).String() - } - if len(c.String("stacktrace-level")) > 0 { - vals["stacktraceLevel"] = log.LevelFromString(c.String("stacktrace-level")).String() - } - if len(c.String("expression")) > 0 { - vals["expression"] = c.String("expression") - } - if len(c.String("prefix")) > 0 { - vals["prefix"] = c.String("prefix") - } - if len(c.String("flags")) > 0 { - vals["flags"] = log.FlagsFromString(c.String("flags")) - } - if c.IsSet("color") { - vals["colorize"] = c.Bool("color") - } - logger := log.DEFAULT - if c.IsSet("logger") { - logger = c.String("logger") - } - writer := mode - if c.IsSet("writer") { - writer = c.String("writer") - } - - extra := private.AddLogger(ctx, logger, writer, mode, vals) - return handleCliResponseExtra(extra) -} - func runPauseLogging(ctx context.Context, c *cli.Command) error { setup(ctx, c.Bool("debug")) userMsg := private.PauseLogging(ctx) diff --git a/package/gitea/source/cmd/migrate.go b/package/gitea/source/cmd/migrate.go index 016f8a0d..cc4fee33 100644 --- a/package/gitea/source/cmd/migrate.go +++ b/package/gitea/source/cmd/migrate.go @@ -6,10 +6,10 @@ package cmd import ( "context" - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/services/versioned_migration" + "gitea.dev/models/db" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" + "gitea.dev/services/versioned_migration" "github.com/urfave/cli/v3" ) diff --git a/package/gitea/source/cmd/migrate_storage.go b/package/gitea/source/cmd/migrate_storage.go index c9b82055..36b224fb 100644 --- a/package/gitea/source/cmd/migrate_storage.go +++ b/package/gitea/source/cmd/migrate_storage.go @@ -10,17 +10,17 @@ import ( "io/fs" "strings" - actions_model "code.gitea.io/gitea/models/actions" - "code.gitea.io/gitea/models/db" - git_model "code.gitea.io/gitea/models/git" - packages_model "code.gitea.io/gitea/models/packages" - repo_model "code.gitea.io/gitea/models/repo" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/log" - packages_module "code.gitea.io/gitea/modules/packages" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/storage" - "code.gitea.io/gitea/services/versioned_migration" + actions_model "gitea.dev/models/actions" + "gitea.dev/models/db" + git_model "gitea.dev/models/git" + packages_model "gitea.dev/models/packages" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/log" + packages_module "gitea.dev/modules/packages" + "gitea.dev/modules/setting" + "gitea.dev/modules/storage" + "gitea.dev/services/versioned_migration" "github.com/urfave/cli/v3" ) diff --git a/package/gitea/source/cmd/migrate_storage_test.go b/package/gitea/source/cmd/migrate_storage_test.go index 3ea193eb..67a6b9e2 100644 --- a/package/gitea/source/cmd/migrate_storage_test.go +++ b/package/gitea/source/cmd/migrate_storage_test.go @@ -8,13 +8,13 @@ import ( "strings" "testing" - "code.gitea.io/gitea/models/packages" - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" - packages_module "code.gitea.io/gitea/modules/packages" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/storage" - packages_service "code.gitea.io/gitea/services/packages" + "gitea.dev/models/packages" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + packages_module "gitea.dev/modules/packages" + "gitea.dev/modules/setting" + "gitea.dev/modules/storage" + packages_service "gitea.dev/services/packages" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/cmd/restore_repo.go b/package/gitea/source/cmd/restore_repo.go index 26b4682f..c7bbddd7 100644 --- a/package/gitea/source/cmd/restore_repo.go +++ b/package/gitea/source/cmd/restore_repo.go @@ -7,8 +7,8 @@ import ( "context" "strings" - "code.gitea.io/gitea/modules/private" - "code.gitea.io/gitea/modules/setting" + "gitea.dev/modules/private" + "gitea.dev/modules/setting" "github.com/urfave/cli/v3" ) diff --git a/package/gitea/source/cmd/serv.go b/package/gitea/source/cmd/serv.go index a35d476c..b39076f6 100644 --- a/package/gitea/source/cmd/serv.go +++ b/package/gitea/source/cmd/serv.go @@ -15,21 +15,21 @@ import ( "strings" "unicode" - asymkey_model "code.gitea.io/gitea/models/asymkey" - git_model "code.gitea.io/gitea/models/git" - "code.gitea.io/gitea/models/perm" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/git/gitcmd" - "code.gitea.io/gitea/modules/json" - "code.gitea.io/gitea/modules/lfstransfer" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/pprof" - "code.gitea.io/gitea/modules/private" - "code.gitea.io/gitea/modules/process" - repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/services/lfs" + asymkey_model "gitea.dev/models/asymkey" + git_model "gitea.dev/models/git" + "gitea.dev/models/perm" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/json" + "gitea.dev/modules/lfstransfer" + "gitea.dev/modules/log" + "gitea.dev/modules/pprof" + "gitea.dev/modules/private" + "gitea.dev/modules/process" + repo_module "gitea.dev/modules/repository" + "gitea.dev/modules/setting" + "gitea.dev/services/lfs" "github.com/kballard/go-shellquote" "github.com/urfave/cli/v3" @@ -113,23 +113,25 @@ func handleCliResponseExtra(extra private.ResponseExtra) error { return nil } -func getAccessMode(verb, lfsVerb string) perm.AccessMode { +// getAccessMode maps an SSH git/LFS verb to the access mode it requires, with +// ok=false for an unrecognised verb. Callers MUST reject the request when ok is +// false: AccessModeNone would otherwise pass the `userMode < mode` permission +// check in routers/private/serv.go and grant access. +func getAccessMode(verb, lfsVerb string) (mode perm.AccessMode, ok bool) { switch verb { case git.CmdVerbUploadPack, git.CmdVerbUploadArchive: - return perm.AccessModeRead + return perm.AccessModeRead, true case git.CmdVerbReceivePack: - return perm.AccessModeWrite + return perm.AccessModeWrite, true case git.CmdVerbLfsAuthenticate, git.CmdVerbLfsTransfer: switch lfsVerb { case git.CmdSubVerbLfsUpload: - return perm.AccessModeWrite + return perm.AccessModeWrite, true case git.CmdSubVerbLfsDownload: - return perm.AccessModeRead + return perm.AccessModeRead, true } } - // should be unreachable - setting.PanicInDevOrTesting("unknown verb: %s %s", verb, lfsVerb) - return perm.AccessModeNone + return perm.AccessModeNone, false } func runServ(ctx context.Context, c *cli.Command) error { @@ -247,7 +249,10 @@ func runServ(ctx context.Context, c *cli.Command) error { } } - requestedMode := getAccessMode(verb, lfsVerb) + requestedMode, ok := getAccessMode(verb, lfsVerb) + if !ok { + return fail(ctx, "Unknown git command", "Unknown git command %s %s", verb, lfsVerb) + } results, extra := private.ServCommand(ctx, keyID, username, reponame, requestedMode, verb, lfsVerb) if extra.HasError() { diff --git a/package/gitea/source/cmd/serv_test.go b/package/gitea/source/cmd/serv_test.go new file mode 100644 index 00000000..3bdcba1d --- /dev/null +++ b/package/gitea/source/cmd/serv_test.go @@ -0,0 +1,56 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package cmd + +import ( + "testing" + + "gitea.dev/models/perm" + "gitea.dev/modules/git" + + "github.com/stretchr/testify/assert" +) + +func TestGetAccessMode(t *testing.T) { + cases := []struct { + verb, lfsVerb string + expected perm.AccessMode + }{ + {git.CmdVerbUploadPack, "", perm.AccessModeRead}, + {git.CmdVerbUploadArchive, "", perm.AccessModeRead}, + {git.CmdVerbReceivePack, "", perm.AccessModeWrite}, + {git.CmdVerbLfsAuthenticate, git.CmdSubVerbLfsUpload, perm.AccessModeWrite}, + {git.CmdVerbLfsAuthenticate, git.CmdSubVerbLfsDownload, perm.AccessModeRead}, + {git.CmdVerbLfsTransfer, git.CmdSubVerbLfsUpload, perm.AccessModeWrite}, + {git.CmdVerbLfsTransfer, git.CmdSubVerbLfsDownload, perm.AccessModeRead}, + } + for _, tc := range cases { + t.Run(tc.verb+"/"+tc.lfsVerb, func(t *testing.T) { + mode, ok := getAccessMode(tc.verb, tc.lfsVerb) + assert.True(t, ok) + assert.Equal(t, tc.expected, mode) + }) + } +} + +// TestGetAccessModeUnknownVerb locks in the invariant that getAccessMode reports +// ok=false for unrecognised verbs and LFS sub-verbs, so runServ rejects them. An +// unknown verb has no valid access mode; if it were treated as AccessModeNone (0) +// it would pass the `userMode < mode` permission check in routers/private/serv.go +// and hand out valid LFS JWTs for any private repository. +func TestGetAccessModeUnknownVerb(t *testing.T) { + cases := []struct{ verb, lfsVerb string }{ + {git.CmdVerbLfsAuthenticate, ""}, + {git.CmdVerbLfsAuthenticate, "badverb"}, + {git.CmdVerbLfsTransfer, "badverb"}, + {"git-unknown-verb", ""}, + } + for _, tc := range cases { + t.Run(tc.verb+"/"+tc.lfsVerb, func(t *testing.T) { + mode, ok := getAccessMode(tc.verb, tc.lfsVerb) + assert.False(t, ok) + assert.Equal(t, perm.AccessModeNone, mode) + }) + } +} diff --git a/package/gitea/source/cmd/web.go b/package/gitea/source/cmd/web.go index 994c481f..5644f37d 100644 --- a/package/gitea/source/cmd/web.go +++ b/package/gitea/source/cmd/web.go @@ -15,17 +15,17 @@ import ( "strings" "time" - "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/gtprof" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/process" - "code.gitea.io/gitea/modules/public" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/templates" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/routers" - "code.gitea.io/gitea/routers/install" + "gitea.dev/modules/container" + "gitea.dev/modules/graceful" + "gitea.dev/modules/gtprof" + "gitea.dev/modules/log" + "gitea.dev/modules/process" + "gitea.dev/modules/public" + "gitea.dev/modules/setting" + "gitea.dev/modules/templates" + "gitea.dev/modules/util" + "gitea.dev/routers" + "gitea.dev/routers/install" "github.com/felixge/fgprof" "github.com/urfave/cli/v3" @@ -150,7 +150,7 @@ func serveInstall(cmd *cli.Command) error { c := install.Routes() err := listen(c, false) if err != nil { - log.Critical("Unable to open listener for installer. Is Gitea already running?") + log.Error("Unable to open listener for installer. Is Gitea already running?") graceful.GetManager().DoGracefulShutdown() } select { @@ -375,7 +375,7 @@ func listen(m http.Handler, handleRedirector bool) error { log.Fatal("Invalid protocol: %s", setting.Protocol) } if err != nil { - log.Critical("Failed to start server: %v", err) + log.Error("Failed to start server: %v", err) } log.Info("HTTP Listener: %s Closed", listenAddr) return err diff --git a/package/gitea/source/cmd/web_acme.go b/package/gitea/source/cmd/web_acme.go index a2e14638..68fd5d00 100644 --- a/package/gitea/source/cmd/web_acme.go +++ b/package/gitea/source/cmd/web_acme.go @@ -6,6 +6,7 @@ package cmd import ( "crypto/x509" "encoding/pem" + "errors" "fmt" "net" "net/http" @@ -13,11 +14,11 @@ import ( "strconv" "strings" - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/process" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" + "gitea.dev/modules/graceful" + "gitea.dev/modules/log" + "gitea.dev/modules/process" + "gitea.dev/modules/setting" + "gitea.dev/modules/util" "github.com/caddyserver/certmagic" ) @@ -93,10 +94,21 @@ func runACME(listenAddr string, m http.Handler) error { myACME := certmagic.NewACMEIssuer(magic, certmagic.DefaultACME) magic.Issuers = []certmagic.Issuer{myACME} - // this obtains certificates or renews them if necessary - err := magic.ManageSync(graceful.GetManager().HammerContext(), []string{setting.Domain}) + // Obtain certificates or renew them if necessary. ManageSync fails closed on + // renewal errors even when a still-valid certificate is already on disk, which + // takes HTTPS down on restart (https://github.com/go-gitea/gitea/issues/38519). + // Prefer keeping the existing cert and retrying renewals asynchronously. + ctx := graceful.GetManager().ShutdownContext() + err := magic.ManageSync(ctx, []string{setting.Domain}) if err != nil { - return err + cert, cacheErr := magic.CacheManagedCertificate(ctx, setting.Domain) + if cacheErr != nil || cert.Expired() { + return errors.Join(err, cacheErr) + } + log.Error("ACME certificate manage failed; continuing with existing certificate: %v", err) + if err := magic.ManageAsync(ctx, []string{setting.Domain}); err != nil { + log.Error("Failed to start async ACME management: %v", err) + } } tlsConfig := magic.TLSConfig() diff --git a/package/gitea/source/cmd/web_graceful.go b/package/gitea/source/cmd/web_graceful.go index 5e06d2c2..13eb9ddc 100644 --- a/package/gitea/source/cmd/web_graceful.go +++ b/package/gitea/source/cmd/web_graceful.go @@ -9,9 +9,9 @@ import ( "net/http/fcgi" "strings" - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" + "gitea.dev/modules/graceful" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" ) func runHTTP(network, listenAddr, name string, m http.Handler, useProxyProtocol bool) error { diff --git a/package/gitea/source/cmd/web_https.go b/package/gitea/source/cmd/web_https.go index 70d35cd4..2eabe32c 100644 --- a/package/gitea/source/cmd/web_https.go +++ b/package/gitea/source/cmd/web_https.go @@ -9,9 +9,9 @@ import ( "os" "strings" - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" + "gitea.dev/modules/graceful" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" "github.com/klauspost/cpuid/v2" ) diff --git a/package/gitea/source/contrib/backport/README b/package/gitea/source/contrib/backport/README deleted file mode 100644 index 466b79c6..00000000 --- a/package/gitea/source/contrib/backport/README +++ /dev/null @@ -1,41 +0,0 @@ -`backport` -========== - -`backport` is a command to help create backports of PRs. It backports a -provided PR from main on to a released version. - -It will create a backport branch, cherry-pick the PR's merge commit, adjust -the commit message and then push this back up to your fork's remote. - -The default version will read from `docs/config.yml`. You can override this -using the option `--version`. - -The upstream branches will be fetched, using the remote `origin`. This can -be overridden using `--upstream`, and fetching can be avoided using -`--no-fetch`. - -By default the branch created will be called `backport-$PR-$VERSION`. You -can override this using the option `--backport-branch`. This branch will -be created from `--release-branch` which is `release/$(VERSION)` -by default and will be pulled from `$(UPSTREAM)`. - -The merge-commit as determined by the github API will be used as the SHA to -cherry-pick. You can override this using `--cherry-pick`. - -The commit message will be amended to add the `Backport` header. -`--no-amend-message` can be set to stop this from happening. - -If cherry-pick is successful the backported branch will be pushed up to your -fork using your remote. These will be determined using `git remote -v`. You -can set your fork name using `--fork-user` and your remote name using -`--remote`. You can avoid pushing using `--no-push`. - -If the push is successful, `xdg-open` will be called to open a backport url. -You can stop this using `--no-xdg-open`. - -Installation -============ - -```bash -go install contrib/backport/backport.go -``` diff --git a/package/gitea/source/contrib/backport/backport.go b/package/gitea/source/contrib/backport/backport.go deleted file mode 100644 index 2af980e5..00000000 --- a/package/gitea/source/contrib/backport/backport.go +++ /dev/null @@ -1,456 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -//nolint:forbidigo // use of print functions is allowed in cli -package main - -import ( - "context" - "errors" - "fmt" - "log" - "net/http" - "os" - "os/exec" - "path" - "strconv" - "strings" - - "github.com/google/go-github/v84/github" - "github.com/urfave/cli/v3" - "gopkg.in/yaml.v3" -) - -const defaultVersion = "v1.18" // to backport to - -func main() { - app := &cli.Command{} - app.Name = "backport" - app.Usage = "Backport provided PR-number on to the current or previous released version" - app.Description = `Backport will look-up the PR in Gitea's git log and attempt to cherry-pick it on the current version` - app.ArgsUsage = "" - - app.Flags = []cli.Flag{ - &cli.StringFlag{ - Name: "version", - Usage: "Version branch to backport on to", - }, - &cli.StringFlag{ - Name: "upstream", - Value: "origin", - Usage: "Upstream remote for the Gitea upstream", - }, - &cli.StringFlag{ - Name: "release-branch", - Value: "", - Usage: "Release branch to backport on. Will default to release/", - }, - &cli.StringFlag{ - Name: "cherry-pick", - Usage: "SHA to cherry-pick as backport", - }, - &cli.StringFlag{ - Name: "backport-branch", - Usage: "Backport branch to backport on to (default: backport--", - }, - &cli.StringFlag{ - Name: "remote", - Value: "", - Usage: "Remote for your fork of the Gitea upstream", - }, - &cli.StringFlag{ - Name: "fork-user", - Value: "", - Usage: "Forked user name on Github", - }, - &cli.StringFlag{ - Name: "gh-access-token", - Value: "", - Usage: "Access token for GitHub api request", - }, - &cli.BoolFlag{ - Name: "no-fetch", - Usage: "Set this flag to prevent fetch of remote branches", - }, - &cli.BoolFlag{ - Name: "no-amend-message", - Usage: "Set this flag to prevent automatic amendment of the commit message", - }, - &cli.BoolFlag{ - Name: "no-push", - Usage: "Set this flag to prevent pushing the backport up to your fork", - }, - &cli.BoolFlag{ - Name: "no-xdg-open", - Usage: "Set this flag to not use xdg-open to open the PR URL", - }, - &cli.BoolFlag{ - Name: "continue", - Usage: "Set this flag to continue from a git cherry-pick that has broken", - }, - } - cli.RootCommandHelpTemplate = `NAME: - {{.Name}} - {{.Usage}} -USAGE: - {{.HelpName}} {{if .VisibleFlags}}[options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}} - {{if len .Authors}} -AUTHOR: - {{range .Authors}}{{ . }}{{end}} - {{end}}{{if .Commands}} -OPTIONS: - {{range .VisibleFlags}}{{.}} - {{end}}{{end}} -` - - app.Action = runBackport - if err := app.Run(context.Background(), os.Args); err != nil { - fmt.Fprintf(os.Stderr, "Unable to backport: %v\n", err) - } -} - -func runBackport(ctx context.Context, c *cli.Command) error { - continuing := c.Bool("continue") - - var pr string - - version := c.String("version") - if version == "" && continuing { - // determine version from current branch name - var err error - pr, version, err = readCurrentBranch(ctx) - if err != nil { - return err - } - } - if version == "" { - version = readVersion() - } - if version == "" { - version = defaultVersion - } - - upstream := c.String("upstream") - if upstream == "" { - upstream = "origin" - } - - forkUser := c.String("fork-user") - remote := c.String("remote") - if remote == "" && !c.Bool("--no-push") { - var err error - remote, forkUser, err = determineRemote(ctx, forkUser) - if err != nil { - return err - } - } - - upstreamReleaseBranch := c.String("release-branch") - if upstreamReleaseBranch == "" { - upstreamReleaseBranch = path.Join("release", version) - } - - localReleaseBranch := path.Join(upstream, upstreamReleaseBranch) - - args := c.Args().Slice() - if len(args) == 0 && pr == "" { - return errors.New("no PR number provided\nProvide a PR number to backport") - } else if len(args) != 1 && pr == "" { - return fmt.Errorf("multiple PRs provided %v\nOnly a single PR can be backported at a time", args) - } - if pr == "" { - pr = args[0] - } - - backportBranch := c.String("backport-branch") - if backportBranch == "" { - backportBranch = "backport-" + pr + "-" + version - } - - fmt.Printf("* Backporting %s to %s as %s\n", pr, localReleaseBranch, backportBranch) - - sha := c.String("cherry-pick") - accessToken := c.String("gh-access-token") - if sha == "" { - var err error - sha, err = determineSHAforPR(ctx, pr, accessToken) - if err != nil { - return err - } - } - if sha == "" { - return fmt.Errorf("unable to determine sha for cherry-pick of %s", pr) - } - - if !c.Bool("no-fetch") { - if err := fetchRemoteAndMain(ctx, upstream, upstreamReleaseBranch); err != nil { - return err - } - } - - if !continuing { - if err := checkoutBackportBranch(ctx, backportBranch, localReleaseBranch); err != nil { - return err - } - } - - if err := cherrypick(ctx, sha); err != nil { - return err - } - - if !c.Bool("no-amend-message") { - if err := amendCommit(ctx, pr); err != nil { - return err - } - } - - if !c.Bool("no-push") { - url := "https://github.com/go-gitea/gitea/compare/" + upstreamReleaseBranch + "..." + forkUser + ":" + backportBranch - - if err := gitPushUp(ctx, remote, backportBranch); err != nil { - return err - } - - if !c.Bool("no-xdg-open") { - if err := xdgOpen(ctx, url); err != nil { - return err - } - } else { - fmt.Printf("* Navigate to %s to open PR\n", url) - } - } - return nil -} - -func xdgOpen(ctx context.Context, url string) error { - fmt.Printf("* `xdg-open %s`\n", url) - out, err := exec.CommandContext(ctx, "xdg-open", url).Output() - if err != nil { - fmt.Fprintf(os.Stderr, "%s", string(out)) - return fmt.Errorf("unable to xdg-open to %s: %w", url, err) - } - return nil -} - -func gitPushUp(ctx context.Context, remote, backportBranch string) error { - fmt.Printf("* `git push -u %s %s`\n", remote, backportBranch) - out, err := exec.CommandContext(ctx, "git", "push", "-u", remote, backportBranch).Output() - if err != nil { - fmt.Fprintf(os.Stderr, "%s", string(out)) - return fmt.Errorf("unable to push up to %s: %w", remote, err) - } - return nil -} - -func amendCommit(ctx context.Context, pr string) error { - fmt.Printf("* Amending commit to prepend `Backport #%s` to body\n", pr) - out, err := exec.CommandContext(ctx, "git", "log", "-1", "--pretty=format:%B").Output() - if err != nil { - fmt.Fprintf(os.Stderr, "%s", string(out)) - return fmt.Errorf("unable to get last log message: %w", err) - } - - parts := strings.SplitN(string(out), "\n", 2) - - if len(parts) != 2 { - return fmt.Errorf("unable to interpret log message:\n%s", string(out)) - } - subject, body := parts[0], parts[1] - if !strings.HasSuffix(subject, " (#"+pr+")") { - subject = subject + " (#" + pr + ")" - } - - out, err = exec.CommandContext(ctx, "git", "commit", "--amend", "-m", subject+"\n\nBackport #"+pr+"\n"+body).Output() - if err != nil { - fmt.Fprintf(os.Stderr, "%s", string(out)) - return fmt.Errorf("unable to amend last log message: %w", err) - } - return nil -} - -func cherrypick(ctx context.Context, sha string) error { - // Check if a CHERRY_PICK_HEAD exists - if _, err := os.Stat(".git/CHERRY_PICK_HEAD"); err == nil { - // Assume that we are in the middle of cherry-pick - continue it - fmt.Println("* Attempting git cherry-pick --continue") - out, err := exec.CommandContext(ctx, "git", "cherry-pick", "--continue").Output() - if err != nil { - fmt.Fprintf(os.Stderr, "git cherry-pick --continue failed:\n%s\n", string(out)) - return fmt.Errorf("unable to continue cherry-pick: %w", err) - } - return nil - } - - fmt.Printf("* Attempting git cherry-pick %s\n", sha) - out, err := exec.CommandContext(ctx, "git", "cherry-pick", sha).Output() - if err != nil { - fmt.Fprintf(os.Stderr, "git cherry-pick %s failed:\n%s\n", sha, string(out)) - return fmt.Errorf("git cherry-pick %s failed: %w", sha, err) - } - return nil -} - -func checkoutBackportBranch(ctx context.Context, backportBranch, releaseBranch string) error { - out, err := exec.CommandContext(ctx, "git", "branch", "--show-current").Output() - if err != nil { - return fmt.Errorf("unable to check current branch %w", err) - } - - currentBranch := strings.TrimSpace(string(out)) - fmt.Printf("* Current branch is %s\n", currentBranch) - if currentBranch == backportBranch { - fmt.Printf("* Current branch is %s - not checking out\n", currentBranch) - return nil - } - - if _, err := exec.CommandContext(ctx, "git", "rev-list", "-1", backportBranch).Output(); err == nil { - fmt.Printf("* Branch %s already exists. Checking it out...\n", backportBranch) - return exec.CommandContext(ctx, "git", "checkout", "-f", backportBranch).Run() - } - - fmt.Printf("* `git checkout -b %s %s`\n", backportBranch, releaseBranch) - return exec.CommandContext(ctx, "git", "checkout", "-b", backportBranch, releaseBranch).Run() -} - -func fetchRemoteAndMain(ctx context.Context, remote, releaseBranch string) error { - fmt.Printf("* `git fetch %s main`\n", remote) - out, err := exec.CommandContext(ctx, "git", "fetch", remote, "main").Output() - if err != nil { - fmt.Println(string(out)) - return fmt.Errorf("unable to fetch %s from %s: %w", "main", remote, err) - } - fmt.Println(string(out)) - - fmt.Printf("* `git fetch %s %s`\n", remote, releaseBranch) - out, err = exec.CommandContext(ctx, "git", "fetch", remote, releaseBranch).Output() - if err != nil { - fmt.Println(string(out)) - return fmt.Errorf("unable to fetch %s from %s: %w", releaseBranch, remote, err) - } - fmt.Println(string(out)) - - return nil -} - -func determineRemote(ctx context.Context, forkUser string) (string, string, error) { - out, err := exec.CommandContext(ctx, "git", "remote", "-v").Output() - if err != nil { - fmt.Fprintf(os.Stderr, "Unable to list git remotes:\n%s\n", string(out)) - return "", "", fmt.Errorf("unable to determine forked remote: %w", err) - } - lines := strings.SplitSeq(string(out), "\n") - for line := range lines { - fields := strings.Split(line, "\t") - name, remote := fields[0], fields[1] - // only look at pushers - if !strings.HasSuffix(remote, " (push)") { - continue - } - // only look at github.com pushes - if !strings.Contains(remote, "github.com") { - continue - } - // ignore go-gitea/gitea - if strings.Contains(remote, "go-gitea/gitea") { - continue - } - if !strings.Contains(remote, forkUser) { - continue - } - if after, ok := strings.CutPrefix(remote, "git@github.com:"); ok { - forkUser = after - } else if after, ok := strings.CutPrefix(remote, "https://github.com/"); ok { - forkUser = after - } else if after, ok := strings.CutPrefix(remote, "https://www.github.com/"); ok { - forkUser = after - } else if forkUser == "" { - return "", "", fmt.Errorf("unable to extract forkUser from remote %s: %s", name, remote) - } - idx := strings.Index(forkUser, "/") - if idx >= 0 { - forkUser = forkUser[:idx] - } - return name, forkUser, nil - } - return "", "", fmt.Errorf("unable to find appropriate remote in:\n%s", string(out)) -} - -func readCurrentBranch(ctx context.Context) (pr, version string, err error) { - out, err := exec.CommandContext(ctx, "git", "branch", "--show-current").Output() - if err != nil { - fmt.Fprintf(os.Stderr, "Unable to read current git branch:\n%s\n", string(out)) - return "", "", fmt.Errorf("unable to read current git branch: %w", err) - } - parts := strings.Split(strings.TrimSpace(string(out)), "-") - - if len(parts) != 3 || parts[0] != "backport" { - fmt.Fprintf(os.Stderr, "Unable to continue from git branch:\n%s\n", string(out)) - return "", "", fmt.Errorf("unable to continue from git branch:\n%s", string(out)) - } - - return parts[1], parts[2], nil -} - -func readVersion() string { - bs, err := os.ReadFile("docs/config.yaml") - if err != nil { - if err == os.ErrNotExist { - log.Println("`docs/config.yaml` not present") - return "" - } - fmt.Fprintf(os.Stderr, "Unable to read `docs/config.yaml`: %v\n", err) - return "" - } - - type params struct { - Version string - } - type docConfig struct { - Params params - } - dc := &docConfig{} - if err := yaml.Unmarshal(bs, dc); err != nil { - fmt.Fprintf(os.Stderr, "Unable to read `docs/config.yaml`: %v\n", err) - return "" - } - - if dc.Params.Version == "" { - fmt.Fprintf(os.Stderr, "No version in `docs/config.yaml`") - return "" - } - - version := dc.Params.Version - if version[0] != 'v' { - version = "v" + version - } - - split := strings.SplitN(version, ".", 3) - - return strings.Join(split[:2], ".") -} - -func determineSHAforPR(ctx context.Context, prStr, accessToken string) (string, error) { - prNum, err := strconv.Atoi(prStr) - if err != nil { - return "", err - } - - client := github.NewClient(http.DefaultClient) - if accessToken != "" { - client = client.WithAuthToken(accessToken) - } - - pr, _, err := client.PullRequests.Get(ctx, "go-gitea", "gitea", prNum) - if err != nil { - return "", err - } - - if pr.Merged == nil || !*pr.Merged { - return "", fmt.Errorf("PR #%d is not yet merged - cannot determine sha to backport", prNum) - } - - if pr.MergeCommitSHA != nil { - return *pr.MergeCommitSHA, nil - } - - return "", nil -} diff --git a/package/gitea/source/contrib/ide/README.md b/package/gitea/source/contrib/development/README.md similarity index 78% rename from package/gitea/source/contrib/ide/README.md rename to package/gitea/source/contrib/development/README.md index a9abfa3e..5fc5dd39 100644 --- a/package/gitea/source/contrib/ide/README.md +++ b/package/gitea/source/contrib/development/README.md @@ -1,12 +1,14 @@ # IDE and code editor configuration ## Table of Contents + - [IDE and code editor configuration](#ide-and-code-editor-configuration) - [Microsoft Visual Studio Code](#microsoft-visual-studio-code) ## Microsoft Visual Studio Code + Download Microsoft Visual Studio Code at https://code.visualstudio.com/ and follow instructions at https://code.visualstudio.com/docs/languages/go to setup Go extension for it. -Create new directory `.vscode` in Gitea root folder and copy contents of folder [contrib/ide/vscode](vscode/) to it. You can now use `Ctrl`+`Shift`+`B` to build gitea executable and `F5` to run it in debug mode. +Create new directory `.vscode` in Gitea root folder and copy contents of folder [contrib/development/vscode](vscode/) to it. You can now use `Ctrl`+`Shift`+`B` to build gitea executable and `F5` to run it in debug mode. Supported on Debian, Ubuntu, Red Hat, Fedora, SUSE Linux, MacOS and Microsoft Windows. diff --git a/package/gitea/source/contrib/ide/vscode/launch.json b/package/gitea/source/contrib/development/vscode/launch.json similarity index 50% rename from package/gitea/source/contrib/ide/vscode/launch.json rename to package/gitea/source/contrib/development/vscode/launch.json index b80b826f..048428fc 100644 --- a/package/gitea/source/contrib/ide/vscode/launch.json +++ b/package/gitea/source/contrib/development/vscode/launch.json @@ -13,19 +13,6 @@ }, "args": ["web"], "showLog": true - }, - { - "name": "Launch (with SQLite3)", - "type": "go", - "request": "launch", - "mode": "debug", - "buildFlags": "-tags='sqlite sqlite_unlock_notify'", - "program": "${workspaceRoot}/main.go", - "env": { - "GITEA_WORK_DIR": "${workspaceRoot}", - }, - "args": ["web"], - "showLog": true } ] } diff --git a/package/gitea/source/contrib/development/vscode/settings.json b/package/gitea/source/contrib/development/vscode/settings.json new file mode 100644 index 00000000..d968e4da --- /dev/null +++ b/package/gitea/source/contrib/development/vscode/settings.json @@ -0,0 +1,4 @@ +{ + "go.buildTags": "", + "go.testFlags": ["-v"] +} diff --git a/package/gitea/source/contrib/development/vscode/tasks.json b/package/gitea/source/contrib/development/vscode/tasks.json new file mode 100644 index 00000000..490e3033 --- /dev/null +++ b/package/gitea/source/contrib/development/vscode/tasks.json @@ -0,0 +1,27 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Build", + "type": "shell", + "command": "go", + "group": "build", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "linux": { + "args": ["build", "-o", "gitea", "${workspaceRoot}/main.go" ] + }, + "osx": { + "args": ["build", "-o", "gitea", "${workspaceRoot}/main.go" ] + }, + "windows": { + "args": ["build", "-o", "gitea.exe", "\"${workspaceRoot}\\main.go\""] + }, + "problemMatcher": ["$go"] + } + ] +} diff --git a/package/gitea/source/contrib/gitea-monitoring-mixin/.gitignore b/package/gitea/source/contrib/grafana-monitoring-mixin/.gitignore similarity index 100% rename from package/gitea/source/contrib/gitea-monitoring-mixin/.gitignore rename to package/gitea/source/contrib/grafana-monitoring-mixin/.gitignore diff --git a/package/gitea/source/contrib/gitea-monitoring-mixin/Makefile b/package/gitea/source/contrib/grafana-monitoring-mixin/Makefile similarity index 100% rename from package/gitea/source/contrib/gitea-monitoring-mixin/Makefile rename to package/gitea/source/contrib/grafana-monitoring-mixin/Makefile diff --git a/package/gitea/source/contrib/gitea-monitoring-mixin/README.md b/package/gitea/source/contrib/grafana-monitoring-mixin/README.md similarity index 100% rename from package/gitea/source/contrib/gitea-monitoring-mixin/README.md rename to package/gitea/source/contrib/grafana-monitoring-mixin/README.md diff --git a/package/gitea/source/contrib/gitea-monitoring-mixin/config.libsonnet b/package/gitea/source/contrib/grafana-monitoring-mixin/config.libsonnet similarity index 100% rename from package/gitea/source/contrib/gitea-monitoring-mixin/config.libsonnet rename to package/gitea/source/contrib/grafana-monitoring-mixin/config.libsonnet diff --git a/package/gitea/source/contrib/gitea-monitoring-mixin/dashboards/dashboards.libsonnet b/package/gitea/source/contrib/grafana-monitoring-mixin/dashboards/dashboards.libsonnet similarity index 100% rename from package/gitea/source/contrib/gitea-monitoring-mixin/dashboards/dashboards.libsonnet rename to package/gitea/source/contrib/grafana-monitoring-mixin/dashboards/dashboards.libsonnet diff --git a/package/gitea/source/contrib/gitea-monitoring-mixin/dashboards/overview.libsonnet b/package/gitea/source/contrib/grafana-monitoring-mixin/dashboards/overview.libsonnet similarity index 100% rename from package/gitea/source/contrib/gitea-monitoring-mixin/dashboards/overview.libsonnet rename to package/gitea/source/contrib/grafana-monitoring-mixin/dashboards/overview.libsonnet diff --git a/package/gitea/source/contrib/gitea-monitoring-mixin/jsonnetfile.json b/package/gitea/source/contrib/grafana-monitoring-mixin/jsonnetfile.json similarity index 100% rename from package/gitea/source/contrib/gitea-monitoring-mixin/jsonnetfile.json rename to package/gitea/source/contrib/grafana-monitoring-mixin/jsonnetfile.json diff --git a/package/gitea/source/contrib/gitea-monitoring-mixin/jsonnetfile.lock.json b/package/gitea/source/contrib/grafana-monitoring-mixin/jsonnetfile.lock.json similarity index 100% rename from package/gitea/source/contrib/gitea-monitoring-mixin/jsonnetfile.lock.json rename to package/gitea/source/contrib/grafana-monitoring-mixin/jsonnetfile.lock.json diff --git a/package/gitea/source/contrib/gitea-monitoring-mixin/lib/alerts.jsonnet b/package/gitea/source/contrib/grafana-monitoring-mixin/lib/alerts.jsonnet similarity index 100% rename from package/gitea/source/contrib/gitea-monitoring-mixin/lib/alerts.jsonnet rename to package/gitea/source/contrib/grafana-monitoring-mixin/lib/alerts.jsonnet diff --git a/package/gitea/source/contrib/gitea-monitoring-mixin/lib/dashboards.jsonnet b/package/gitea/source/contrib/grafana-monitoring-mixin/lib/dashboards.jsonnet similarity index 100% rename from package/gitea/source/contrib/gitea-monitoring-mixin/lib/dashboards.jsonnet rename to package/gitea/source/contrib/grafana-monitoring-mixin/lib/dashboards.jsonnet diff --git a/package/gitea/source/contrib/gitea-monitoring-mixin/lib/rules.jsonnet b/package/gitea/source/contrib/grafana-monitoring-mixin/lib/rules.jsonnet similarity index 100% rename from package/gitea/source/contrib/gitea-monitoring-mixin/lib/rules.jsonnet rename to package/gitea/source/contrib/grafana-monitoring-mixin/lib/rules.jsonnet diff --git a/package/gitea/source/contrib/gitea-monitoring-mixin/mixin.libsonnet b/package/gitea/source/contrib/grafana-monitoring-mixin/mixin.libsonnet similarity index 100% rename from package/gitea/source/contrib/gitea-monitoring-mixin/mixin.libsonnet rename to package/gitea/source/contrib/grafana-monitoring-mixin/mixin.libsonnet diff --git a/package/gitea/source/contrib/ide/vscode/settings.json b/package/gitea/source/contrib/ide/vscode/settings.json deleted file mode 100644 index e33bccf9..00000000 --- a/package/gitea/source/contrib/ide/vscode/settings.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "go.buildTags": "'sqlite sqlite_unlock_notify'", - "go.testFlags": ["-v"] -} \ No newline at end of file diff --git a/package/gitea/source/contrib/ide/vscode/tasks.json b/package/gitea/source/contrib/ide/vscode/tasks.json deleted file mode 100644 index e35ae303..00000000 --- a/package/gitea/source/contrib/ide/vscode/tasks.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "label": "Build", - "type": "shell", - "command": "go", - "group": "build", - "presentation": { - "echo": true, - "reveal": "always", - "focus": false, - "panel": "shared" - }, - "linux": { - "args": ["build", "-o", "gitea", "${workspaceRoot}/main.go" ] - }, - "osx": { - "args": ["build", "-o", "gitea", "${workspaceRoot}/main.go" ] - }, - "windows": { - "args": ["build", "-o", "gitea.exe", "\"${workspaceRoot}\\main.go\""] - }, - "problemMatcher": ["$go"] - }, - { - "label": "Build (with SQLite3)", - "type": "shell", - "command": "go", - "group": "build", - "presentation": { - "echo": true, - "reveal": "always", - "focus": false, - "panel": "shared" - }, - "linux": { - "args": ["build", "-tags=\"sqlite sqlite_unlock_notify\"", "-o", "gitea", "${workspaceRoot}/main.go"] - }, - "osx": { - "args": ["build", "-tags=\"sqlite sqlite_unlock_notify\"", "-o", "gitea", "${workspaceRoot}/main.go"] - }, - "windows": { - "args": ["build", "-tags=\"sqlite sqlite_unlock_notify\"", "-o", "gitea.exe", "\"${workspaceRoot}\\main.go\""] - }, - "problemMatcher": ["$go"] - } - ] -} diff --git a/package/gitea/source/contrib/init/centos/gitea b/package/gitea/source/contrib/init/centos/gitea deleted file mode 100644 index 4f0d0d99..00000000 --- a/package/gitea/source/contrib/init/centos/gitea +++ /dev/null @@ -1,93 +0,0 @@ -#!/bin/sh -# -# /etc/rc.d/init.d/gitea -# -# Runs the Gitea Git with a cup of tea. -# -# -# chkconfig: - 85 15 -# - -### BEGIN INIT INFO -# Provides: gitea -# Required-Start: $remote_fs $syslog -# Required-Stop: $remote_fs $syslog -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Start gitea at boot time. -# Description: Control gitea. -### END INIT INFO - -# Source function library. -. /etc/init.d/functions - -# Default values - -NAME=gitea -GITEA_HOME=/var/lib/${NAME} -GITEA_PATH=/usr/local/bin/${NAME} -GITEA_USER=git -SERVICENAME="Gitea - Git with a cup of tea" -LOCKFILE=/var/lock/subsys/gitea -LOGPATH=${GITEA_HOME}/log -LOGFILE=${LOGPATH}/gitea.log -RETVAL=0 - -# Read configuration from /etc/sysconfig/gitea to override defaults -[ -r /etc/sysconfig/$NAME ] && . /etc/sysconfig/$NAME - -# Don't do anything if nothing is installed -[ -x ${GITEA_PATH} ] || exit 0 -# exit if logpath dir is not created. -[ -x ${LOGPATH} ] || exit 0 - -DAEMON_OPTS="--check $NAME" - -# Set additional options, if any -[ ! -z "$GITEA_USER" ] && DAEMON_OPTS="$DAEMON_OPTS --user=${GITEA_USER}" - -start() { - cd ${GITEA_HOME} - echo -n "Starting ${SERVICENAME}: " - daemon $DAEMON_OPTS "${GITEA_PATH} web -c /etc/${NAME}/app.ini > ${LOGFILE} 2>&1 &" - RETVAL=$? - echo - [ $RETVAL = 0 ] && touch ${LOCKFILE} - - return $RETVAL -} - -stop() { - cd ${GITEA_HOME} - echo -n "Shutting down ${SERVICENAME}: " - killproc ${NAME} - RETVAL=$? - echo - [ $RETVAL = 0 ] && rm -f ${LOCKFILE} -} - -case "$1" in - start) - status ${NAME} > /dev/null 2>&1 && exit 0 - start - ;; - stop) - stop - ;; - status) - status ${NAME} - ;; - restart) - stop - start - ;; - reload) - stop - start - ;; - *) - echo "Usage: ${NAME} {start|stop|status|restart}" - exit 1 - ;; -esac -exit $RETVAL diff --git a/package/gitea/source/contrib/init/debian/gitea b/package/gitea/source/contrib/init/debian/gitea deleted file mode 100644 index 22463094..00000000 --- a/package/gitea/source/contrib/init/debian/gitea +++ /dev/null @@ -1,89 +0,0 @@ -#!/bin/sh -### BEGIN INIT INFO -# Provides: gitea -# Required-Start: $syslog $network -# Required-Stop: $syslog -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: A self-hosted Git service written in Go. -# Description: A self-hosted Git service written in Go. -### END INIT INFO - -# Author: Danny Boisvert - -# Do NOT "set -e" - -# PATH should only include /usr/* if it runs after the mountnfs.sh script -PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin -DESC="Gitea - Git with a cup of tea" -NAME=gitea -SERVICEVERBOSE=yes -PIDFILE=/run/$NAME.pid -SCRIPTNAME=/etc/init.d/$NAME -WORKINGDIR=/var/lib/$NAME -DAEMON=/usr/local/bin/$NAME -DAEMON_ARGS="web -c /etc/$NAME/app.ini" -USER=git -USERBIND="" -# If you want to bind Gitea to a port below 1024 uncomment -# the line below -#USERBIND="setcap cap_net_bind_service=+ep" -STOP_SCHEDULE="${STOP_SCHEDULE:-QUIT/5/TERM/1/KILL/5}" - -# Read configuration variable file if it is present -[ -r /etc/default/$NAME ] && . /etc/default/$NAME - -# Exit if the package is not installed -[ -x "$DAEMON" ] || exit 0 - -do_start() -{ - $USERBIND $DAEMON - sh -c "USER=$USER HOME=/home/$USER GITEA_WORK_DIR=$WORKINGDIR start-stop-daemon --start --quiet --pidfile $PIDFILE --make-pidfile \\ - --background --chdir $WORKINGDIR --chuid $USER \\ - --exec $DAEMON -- $DAEMON_ARGS" -} - -do_stop() -{ - start-stop-daemon --stop --quiet --retry=$STOP_SCHEDULE --pidfile $PIDFILE --name $NAME --oknodo - rm -f $PIDFILE -} - -do_status() -{ - if [ -f $PIDFILE ]; then - if kill -0 $(cat "$PIDFILE"); then - echo "$NAME is running, PID is $(cat $PIDFILE)" - else - echo "$NAME process is dead, but pidfile exists" - fi - else - echo "$NAME is not running" - fi -} - -case "$1" in - start) - echo "Starting $DESC" "$NAME" - do_start - ;; - stop) - echo "Stopping $DESC" "$NAME" - do_stop - ;; - status) - do_status - ;; - restart) - echo "Restarting $DESC" "$NAME" - do_stop - do_start - ;; - *) - echo "Usage: $SCRIPTNAME {start|stop|status|restart}" >&2 - exit 2 - ;; -esac - -exit 0 diff --git a/package/gitea/source/contrib/init/suse/gitea b/package/gitea/source/contrib/init/suse/gitea deleted file mode 100644 index 6391beda..00000000 --- a/package/gitea/source/contrib/init/suse/gitea +++ /dev/null @@ -1,115 +0,0 @@ -#!/bin/sh -# -# /etc/init.d/gitea -# -# Runs the Gitea Git with a cup of tea. -# - -### BEGIN INIT INFO -# Provides: gitea -# Required-Start: $remote_fs -# Required-Stop: $remote_fs -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Start gitea at boot time. -# Description: Control gitea. -### END INIT INFO - -# Default values - -NAME=gitea -GITEA_HOME=/var/lib/$NAME -GITEA_PATH=/usr/local/bin/$NAME -GITEA_USER=git -SERVICENAME="Gitea - Git with a cup of tea" -LOCKFILE=/var/lock/subsys/gitea -LOGPATH=${GITEA_HOME}/log -LOGFILE=${LOGPATH}/error.log -# gitea creates its own gitea.log from stdout -RETVAL=0 - -# Read configuration from /etc/sysconfig/gitea to override defaults -[ -r /etc/sysconfig/$NAME ] && . /etc/sysconfig/$NAME - -# Don't do anything if nothing is installed -test -x ${GITEA_PATH} || { echo "$NAME not installed"; - if [ "$1" = "stop" ]; then exit 0; - else exit 5; fi; } - -# exit if logpath dir is not created. -test -r ${LOGPATH} || { echo "$LOGPATH not existing"; - if [ "$1" = "stop" ]; then exit 0; - else exit 6; fi; } - -# Source function library. -. /etc/rc.status - -# Reset status of this service -rc_reset - - -case "$1" in - start) - echo -n "Starting ${SERVICENAME} " - - # As we can't use startproc, we have to check ourselves if the service is already running - /sbin/checkproc ${GITEA_PATH} - if [ $? -eq 0 ]; then - # return skipped as service is already running - (exit 5) - else - su - ${GITEA_USER} -c "USER=${GITEA_USER} GITEA_WORK_DIR=${GITEA_HOME} ${GITEA_PATH} web -c /etc/${NAME}/app.ini 2>&1 >>${LOGFILE} &" - fi - - # Remember status and be verbose - rc_status -v - ;; - - stop) - echo -n "Shutting down ${SERVICENAME} " - - ## Stop daemon with killproc(8) and if this fails - ## killproc sets the return value according to LSB. - /sbin/killproc ${GITEA_PATH} - - # Remember status and be verbose - rc_status -v - ;; - - restart) - ## Stop the service and regardless of whether it was - ## running or not, start it again. - $0 stop - $0 start - - # Remember status and be quiet - rc_status - ;; - - status) - echo -n "Checking for ${SERVICENAME} " - ## Check status with checkproc(8), if process is running - ## checkproc will return with exit status 0. - - # Return value is slightly different for the status command: - # 0 - service up and running - # 1 - service dead, but /run/ pid file exists - # 2 - service dead, but /var/lock/ lock file exists - # 3 - service not running (unused) - # 4 - service status unknown :-( - # 5--199 reserved (5--99 LSB, 100--149 distro, 150--199 appl.) - - # NOTE: checkproc returns LSB compliant status values. - /sbin/checkproc ${GITEA_PATH} - # NOTE: rc_status knows that we called this init script with - # "status" option and adapts its messages accordingly. - rc_status -v - ;; - - *) - echo "Usage: $0 {start|stop|status|restart}" - exit 1 - ;; - -esac -rc_exit diff --git a/package/gitea/source/contrib/legal/privacy.html.sample b/package/gitea/source/contrib/sample-page/privacy.html.sample similarity index 100% rename from package/gitea/source/contrib/legal/privacy.html.sample rename to package/gitea/source/contrib/sample-page/privacy.html.sample diff --git a/package/gitea/source/contrib/legal/tos.html.sample b/package/gitea/source/contrib/sample-page/tos.html.sample similarity index 100% rename from package/gitea/source/contrib/legal/tos.html.sample rename to package/gitea/source/contrib/sample-page/tos.html.sample diff --git a/package/gitea/source/contrib/init/freebsd/gitea b/package/gitea/source/contrib/service/freebsd/gitea similarity index 100% rename from package/gitea/source/contrib/init/freebsd/gitea rename to package/gitea/source/contrib/service/freebsd/gitea diff --git a/package/gitea/source/contrib/init/gentoo/gitea b/package/gitea/source/contrib/service/gentoo/gitea similarity index 100% rename from package/gitea/source/contrib/init/gentoo/gitea rename to package/gitea/source/contrib/service/gentoo/gitea diff --git a/package/gitea/source/contrib/launchd/io.gitea.web.plist b/package/gitea/source/contrib/service/launchd/io.gitea.web.plist similarity index 100% rename from package/gitea/source/contrib/launchd/io.gitea.web.plist rename to package/gitea/source/contrib/service/launchd/io.gitea.web.plist diff --git a/package/gitea/source/contrib/init/openbsd/gitea b/package/gitea/source/contrib/service/openbsd/gitea similarity index 100% rename from package/gitea/source/contrib/init/openbsd/gitea rename to package/gitea/source/contrib/service/openbsd/gitea diff --git a/package/gitea/source/contrib/init/openwrt/gitea b/package/gitea/source/contrib/service/openwrt/gitea similarity index 100% rename from package/gitea/source/contrib/init/openwrt/gitea rename to package/gitea/source/contrib/service/openwrt/gitea diff --git a/package/gitea/source/contrib/init/sunos/gitea.xml b/package/gitea/source/contrib/service/sunos/gitea.xml similarity index 100% rename from package/gitea/source/contrib/init/sunos/gitea.xml rename to package/gitea/source/contrib/service/sunos/gitea.xml diff --git a/package/gitea/source/contrib/supervisor/gitea b/package/gitea/source/contrib/service/supervisor/gitea similarity index 100% rename from package/gitea/source/contrib/supervisor/gitea rename to package/gitea/source/contrib/service/supervisor/gitea diff --git a/package/gitea/source/contrib/systemd/gitea.service b/package/gitea/source/contrib/service/systemd/gitea.service similarity index 100% rename from package/gitea/source/contrib/systemd/gitea.service rename to package/gitea/source/contrib/service/systemd/gitea.service diff --git a/package/gitea/source/contrib/init/ubuntu/gitea b/package/gitea/source/contrib/service/sysvinit/gitea similarity index 90% rename from package/gitea/source/contrib/init/ubuntu/gitea rename to package/gitea/source/contrib/service/sysvinit/gitea index da56b6e4..1508da7f 100644 --- a/package/gitea/source/contrib/init/ubuntu/gitea +++ b/package/gitea/source/contrib/service/sysvinit/gitea @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash ### BEGIN INIT INFO # Provides: gitea # Required-Start: $syslog $network @@ -9,6 +9,8 @@ # Description: A self-hosted Git service written in Go. ### END INIT INFO +# This is a System V Init (init.d) startup script for legacy Linux distributions + # Do NOT "set -e" # PATH should only include /usr/* if it runs after the mountnfs.sh script @@ -24,6 +26,9 @@ DAEMON_ARGS="web -c /etc/$NAME/app.ini" USER=git STOP_SCHEDULE="${STOP_SCHEDULE:-QUIT/5/TERM/1/KILL/5}" +# If you want to bind Gitea to a port below 1024, apply "setcap" to the gitea binary +#setcap cap_net_bind_service=+ep $DAEMON" + # Read configuration variable file if it is present [ -r /etc/default/$NAME ] && . /etc/default/$NAME diff --git a/package/gitea/source/contrib/update_dependencies.sh b/package/gitea/source/contrib/update_dependencies.sh deleted file mode 100755 index 5700a198..00000000 --- a/package/gitea/source/contrib/update_dependencies.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - -grep 'git' go.mod | grep '\.com' | grep -v indirect | grep -v replace | cut -f 2 | cut -d ' ' -f 1 | while read line; do - go get -u "$line" - make vendor - git add . - git commit -m "update $line" -done diff --git a/package/gitea/source/contrib/upgrade.sh b/package/gitea/source/contrib/upgrade.sh index 2593d245..71d0435d 100755 --- a/package/gitea/source/contrib/upgrade.sh +++ b/package/gitea/source/contrib/upgrade.sh @@ -126,6 +126,7 @@ giteacmd manager flush-queues echo "Stopping gitea at $(date)" $service_stop echo "Creating backup in $giteahome" +# shellcheck disable=SC2086 # flag string giteacmd dump $backupopts echo "Updating binary at $giteabin" cp -f "$giteabin" "$giteabin.bak" && mv -f "$binname" "$giteabin" diff --git a/package/gitea/source/docker/root/etc/templates/app.ini b/package/gitea/source/docker/root/etc/templates/app.ini index 01fb407f..1794d1f1 100644 --- a/package/gitea/source/docker/root/etc/templates/app.ini +++ b/package/gitea/source/docker/root/etc/templates/app.ini @@ -51,8 +51,6 @@ ROOT_PATH = /data/gitea/log [security] INSTALL_LOCK = $INSTALL_LOCK SECRET_KEY = $SECRET_KEY -REVERSE_PROXY_LIMIT = 1 -REVERSE_PROXY_TRUSTED_PROXIES = * [service] DISABLE_REGISTRATION = $DISABLE_REGISTRATION diff --git a/package/gitea/source/docker/rootless/etc/templates/app.ini b/package/gitea/source/docker/rootless/etc/templates/app.ini index 00576350..0357e6aa 100644 --- a/package/gitea/source/docker/rootless/etc/templates/app.ini +++ b/package/gitea/source/docker/rootless/etc/templates/app.ini @@ -48,8 +48,6 @@ ROOT_PATH = $GITEA_WORK_DIR/data/log [security] INSTALL_LOCK = $INSTALL_LOCK SECRET_KEY = $SECRET_KEY -REVERSE_PROXY_LIMIT = 1 -REVERSE_PROXY_TRUSTED_PROXIES = * [service] DISABLE_REGISTRATION = $DISABLE_REGISTRATION diff --git a/package/gitea/source/docker/rootless/usr/local/bin/docker-entrypoint.sh b/package/gitea/source/docker/rootless/usr/local/bin/docker-entrypoint.sh index ca509214..4ffc4ff3 100755 --- a/package/gitea/source/docker/rootless/usr/local/bin/docker-entrypoint.sh +++ b/package/gitea/source/docker/rootless/usr/local/bin/docker-entrypoint.sh @@ -13,5 +13,5 @@ fi if [ $# -gt 0 ]; then exec "$@" else - exec /usr/local/bin/gitea -c ${GITEA_APP_INI} web + exec /usr/local/bin/gitea -c "${GITEA_APP_INI}" web fi diff --git a/package/gitea/source/docker/rootless/usr/local/bin/docker-setup.sh b/package/gitea/source/docker/rootless/usr/local/bin/docker-setup.sh index feab02a3..3320d69d 100755 --- a/package/gitea/source/docker/rootless/usr/local/bin/docker-setup.sh +++ b/package/gitea/source/docker/rootless/usr/local/bin/docker-setup.sh @@ -1,23 +1,23 @@ #!/bin/bash # Prepare git folder -mkdir -p ${HOME} && chmod 0700 ${HOME} -if [ ! -w ${HOME} ]; then echo "${HOME} is not writable"; exit 1; fi +mkdir -p "${HOME}" && chmod 0700 "${HOME}" +if [ ! -w "${HOME}" ]; then echo "${HOME} is not writable"; exit 1; fi # Prepare custom folder -mkdir -p ${GITEA_CUSTOM} && chmod 0700 ${GITEA_CUSTOM} +mkdir -p "${GITEA_CUSTOM}" && chmod 0700 "${GITEA_CUSTOM}" # Prepare temp folder -mkdir -p ${GITEA_TEMP} && chmod 0700 ${GITEA_TEMP} -if [ ! -w ${GITEA_TEMP} ]; then echo "${GITEA_TEMP} is not writable"; exit 1; fi +mkdir -p "${GITEA_TEMP}" && chmod 0700 "${GITEA_TEMP}" +if [ ! -w "${GITEA_TEMP}" ]; then echo "${GITEA_TEMP} is not writable"; exit 1; fi #Prepare config file -if [ ! -f ${GITEA_APP_INI} ]; then +if [ ! -f "${GITEA_APP_INI}" ]; then #Prepare config file folder - GITEA_APP_INI_DIR=$(dirname ${GITEA_APP_INI}) - mkdir -p ${GITEA_APP_INI_DIR} && chmod 0700 ${GITEA_APP_INI_DIR} - if [ ! -w ${GITEA_APP_INI_DIR} ]; then echo "${GITEA_APP_INI_DIR} is not writable"; exit 1; fi + GITEA_APP_INI_DIR=$(dirname "${GITEA_APP_INI}") + mkdir -p "${GITEA_APP_INI_DIR}" && chmod 0700 "${GITEA_APP_INI_DIR}" + if [ ! -w "${GITEA_APP_INI_DIR}" ]; then echo "${GITEA_APP_INI_DIR} is not writable"; exit 1; fi # Set INSTALL_LOCK to true only if SECRET_KEY is not empty and # INSTALL_LOCK is empty @@ -34,7 +34,7 @@ if [ ! -f ${GITEA_APP_INI} ]; then ROOT_URL=${ROOT_URL:-""} \ DISABLE_SSH=${DISABLE_SSH:-"false"} \ SSH_PORT=${SSH_PORT:-"2222"} \ - SSH_LISTEN_PORT=${SSH_LISTEN_PORT:-$SSH_PORT} \ + SSH_LISTEN_PORT=${SSH_LISTEN_PORT:-} \ DB_TYPE=${DB_TYPE:-"sqlite3"} \ DB_HOST=${DB_HOST:-"localhost:3306"} \ DB_NAME=${DB_NAME:-"gitea"} \ @@ -44,8 +44,8 @@ if [ ! -f ${GITEA_APP_INI} ]; then DISABLE_REGISTRATION=${DISABLE_REGISTRATION:-"false"} \ REQUIRE_SIGNIN_VIEW=${REQUIRE_SIGNIN_VIEW:-"false"} \ SECRET_KEY=${SECRET_KEY:-""} \ - envsubst < /etc/templates/app.ini > ${GITEA_APP_INI} + envsubst < /etc/templates/app.ini > "${GITEA_APP_INI}" fi # Replace app.ini settings with env variables in the form GITEA__SECTION_NAME__KEY_NAME -environment-to-ini --config ${GITEA_APP_INI} +environment-to-ini --config "${GITEA_APP_INI}" diff --git a/package/gitea/source/docs/build-setup.md b/package/gitea/source/docs/build-setup.md new file mode 100644 index 00000000..d1cd465a --- /dev/null +++ b/package/gitea/source/docs/build-setup.md @@ -0,0 +1,67 @@ +# Setup and requirements + +This document lists the tools you need to build Gitea from source and how to get +the code. Once your environment is ready, see [development.md](development.md) for +the build and development workflow, and [testing.md](testing.md) for running tests. + +For the contribution workflow and review process, see [CONTRIBUTING.md](../CONTRIBUTING.md). + +## Requirements + +### Go + +[Install Go](https://go.dev/doc/install) and set up your Go environment. The +required version is the one declared in [`go.mod`](../go.mod); installing the same +version your continuous integration uses avoids `gofmt` differences between Go +releases. + +> [!NOTE] +> Some `make` tasks build external Go tools on demand (for example `make +> watch-backend`). To use them, the `"$GOPATH"/bin` directory must be on your +> executable `PATH`; otherwise you have to manage those tools yourself. + +### Node.js and pnpm + +[Install Node.js](https://nodejs.org/en/download/) to build the JavaScript and CSS +files. The minimum supported version is the one declared in +[`package.json`](../package.json) (`engines.node`); the latest LTS is recommended. + +Gitea manages frontend dependencies with [pnpm](https://pnpm.io/). The `make` +targets invoke it for you, so installing pnpm manually is only needed if you want +to run `pnpm` commands directly. + +### Make + +Gitea uses [Make](https://www.gnu.org/software/make/) to drive builds, linting, and +tests. On Windows it can be installed via [MSYS2](https://www.msys2.org/) or +[Chocolatey](https://chocolatey.org/packages/make). + +### Python with uv (optional) + +Linting the templates, workflow files, and YAML requires Python tooling that Gitea +runs through [uv](https://docs.astral.sh/uv/). After installing uv, `make` creates +the environment automatically (`uv sync`); you only need this if you run +`make lint-templates`, `make lint-yaml`, or `make lint-actions` locally. + +### Git LFS + +The integration tests require [Git LFS](https://git-lfs.com/) to be installed. + +## Getting the source code + +Clone the repository: + +```bash +git clone https://github.com/go-gitea/gitea +``` + +To contribute changes, [fork the repository](https://github.com/go-gitea/gitea) on +GitHub and add your fork as a git remote so you can push branches and open pull +requests. See GitHub's [working with forks](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks) +documentation for the details. + +## Installing dependencies + +Most build and test targets install the dependencies they need on their own. To +fetch everything up front, run `make deps` (or the per-group `make deps-frontend`, +`make deps-backend`, `make deps-tools`, `make deps-py`). diff --git a/package/gitea/source/docs/build-source.md b/package/gitea/source/docs/build-source.md new file mode 100644 index 00000000..17e2ef7a --- /dev/null +++ b/package/gitea/source/docs/build-source.md @@ -0,0 +1,92 @@ +# Prepare build environment + +Complete the steps in [build-setup.md](build-setup.md) to prepare your environment for building Gitea from source. + +## Choose a branch + +By default, the cloned repository is on main branch (the current development branch for next major release, aka: main nightly). + +You can switch to a versioned branch (the branch for the next minor stable release, aka: stable nightly ) +or a versioned tag (matches the official releases with version numbers) + +To test a Pull Request, you can fetch its code by its Pull Request number (take `PR #123456` as example): + +```bash +git fetch origin pull/123456/head:pr-123456 +``` + +# Build + +Various [make tasks](https://github.com/go-gitea/gitea/blob/main/Makefile) +are provided to keep the build process as simple as possible. + +Depending on requirements, the following build tags can be included. + +- `bindata`: Build a single monolithic binary, with all assets included. Required for distribution and production build. +- `pam`: Enable support for PAM (Linux Pluggable Authentication Modules). + Can be used to authenticate local users or extend authentication to methods available to PAM. +- `gogit`: (EXPERIMENTAL) Use go-git variants of Git commands. + +To include all assets, use the `bindata` tag: + +```bash +TAGS="bindata" make build +``` + +Tag `gogit` is used to try to resolve some Windows-specific performance problems, POSIX systems don't need it. +You can build a Windows binary by: + +```bash +GOOS=windows TAGS="bindata gogit" make build +``` + +## Changing default paths + +Gitea will search for a number of things from the _`CustomPath`_. +By default, this is the `custom/` directory in the current working directory when running Gitea. +It will also look for its configuration file _`CustomConf`_ in `$(CustomPath)/conf/app.ini`, +and will use the current working directory as the relative base path _`AppWorkPath`_. + +These values, although useful when developing, may conflict with downstream users preferences. + +For packagers who need to use paths like `/etc/gitea/app.ini`, +they should define these values at build time for `make build` by environment variable like +`LDFLAGS='-X "module.Var1=Value1" -X "module.Var2=Value2"' TAGS="bindata" make build`. + +- _`CustomConf`_: `-X "code.gitea.io/gitea/modules/setting.CustomConf=/etc/gitea/app.ini"` +- _`AppWorkPath`_: `-X "code.gitea.io/gitea/modules/setting.AppWorkPath=/var/lib/gitea"` +- _`CustomPath`_: `-X "code.gitea.io/gitea/modules/setting.CustomPath=/var/lib/gitea/custom"` +- Default PID file location: `-X "code.gitea.io/gitea/cmd.PIDFile=/run/gitea.pid"` + +Add as many of the strings with their preceding `-X` to the `LDFLAGS` variable and run `make build` +with the appropriate `TAGS` as above. + +Running `gitea help` will allow you to review what the computed settings will be for your `gitea`. + +## Cross Build + +Gitea use's Golang's toolchain variables for cross-building. + +For example, to cross build for Linux ARM64: + +``` +GOOS=linux GOARCH=arm64 TAGS="bindata" make build +``` + +### Adding shell autocompletion + +Shell completion can be generated directly from binary with: +```sh +gitea completion +``` + +Supported values for `` are `bash`, `fish`, `pwsh` and `zsh`. +Details on how to load the completion for your shell can be found in the completion command help. + +## Source Maps + +By default, gitea generates reduced source maps for frontend files to conserve space. This can be controlled with the `ENABLE_SOURCEMAP` environment variable: + +- `ENABLE_SOURCEMAP=true` generates all source maps, the default for development builds +- `ENABLE_SOURCEMAP=reduced` generates limited source maps, the default for production builds +- `ENABLE_SOURCEMAP=false` generates no source maps diff --git a/package/gitea/source/docs/community-governance.md b/package/gitea/source/docs/community-governance.md new file mode 100644 index 00000000..b721a2e8 --- /dev/null +++ b/package/gitea/source/docs/community-governance.md @@ -0,0 +1,249 @@ +# Community governance and review process + +This document describes maintainer expectations, project governance, and the detailed pull request review workflow (labels, merge queue, commit message format for mergers). For what contributors should do when opening and updating a PR, see [CONTRIBUTING.md](../CONTRIBUTING.md). + +## Table of contents + +- [Community governance and review process](#community-governance-and-review-process) + - [Table of contents](#table-of-contents) + - [Code review](#code-review) + - [Milestone](#milestone) + - [Labels](#labels) + - [Reviewing PRs](#reviewing-prs) + - [For reviewers](#for-reviewers) + - [Getting PRs merged](#getting-prs-merged) + - [Final call](#final-call) + - [Commit messages](#commit-messages) + - [PR Co-authors](#pr-co-authors) + - [PRs targeting `main`](#prs-targeting-main) + - [Backport PRs](#backport-prs) + - [Contribution Roles](#contribution-roles) + - [Maintainers](#maintainers) + - [Review expectations](#review-expectations) + - [Becoming a maintainer](#becoming-a-maintainer) + - [Stepping down, advisors, and inactivity](#stepping-down-advisors-and-inactivity) + - [Account security](#account-security) + - [Mergers](#mergers) + - [Becoming a merger](#becoming-a-merger) + - [Technical Oversight Committee (TOC)](#technical-oversight-committee-toc) + - [TOC election process](#toc-election-process) + - [Current TOC members](#current-toc-members) + - [Previous TOC/owners members](#previous-tocowners-members) + - [Governance Compensation](#governance-compensation) + - [Roadmap](#roadmap) + +## Code review + +### Milestone + +A PR should only be assigned to a milestone if it will likely be merged into the given version. \ +PRs without a milestone may not be merged. + +### Labels + +Almost all labels used inside Gitea can be classified as one of the following: + +- `modifies/…`: Determines which parts of the codebase are affected. These labels will be set through the CI. +- `topic/…`: Determines the conceptual component of Gitea that is affected, i.e. issues, projects, or authentication. At best, PRs should only target one component but there might be overlap. Must be set manually. +- `type/…`: Determines the type of an issue or PR (feature, refactoring, docs, bug, …). If GitHub supported scoped labels, these labels would be exclusive, so you should set **exactly** one, not more or less (every PR should fall into one of the provided categories, and only one). +- `issue/…` / `lgtm/…`: Labels that are specific to issues or PRs respectively and that are only necessary in a given context, i.e. `issue/not-a-bug` or `lgtm/need 2` + +Every PR should be labeled correctly with every label that applies. + +There are also some labels that will be managed automatically.\ +In particular, these are + +- the amount of pending required approvals +- has all `backport`s or needs a manual backport + +### Reviewing PRs + +Maintainers are encouraged to review pull requests in areas where they have expertise or particular interest. + +#### For reviewers + +- **Verification**: Verify that the PR accurately reflects the changes, and verify that the tests and documentation are complete and aligned with the implementation. +- **Actionable feedback**: Say what should change and why, and distinguish required changes from optional suggestions. +- **Feedback**: Focus feedback on the issue itself and avoid comments about the contributor's abilities. +- **Request changes**: If you request changes (i.e., block a PR), give a clear rationale and, whenever possible, a concrete path to resolution. +- **Approval**: Only approve a PR when you are fully satisfied with its current state - "rubber-stamp" approvals need to be highlighted as such. + +### Getting PRs merged + +Changes to Gitea must be reviewed before they are accepted, including changes from owners and maintainers. The exception is critical bugs that prevent Gitea from compiling or starting. + +We require two maintainer approvals for every PR. When that is satisfied, your PR gets the `lgtm/done` label. After that, you mainly fix merge conflicts and respond to or implement maintainer requests; maintainers drive getting the PR merged. + +If a PR has `lgtm/done`, no open discussions, and no merge conflicts, any maintainer may add `reviewed/wait-merge`. That puts the PR in the merge queue. PRs are merged from the queue in the order of this list: + + + +Gitea uses its own tool, , to automate parts of the review process. The backporter: + +- Creates a backport PR when needed after the initial PR merges. +- Removes the PR from the merge queue after it merges. +- Keeps the oldest branch in the merge queue up to date with merges. + +### Final call + +If a PR has been ignored for more than 7 days with no comments or reviews, and the author or any maintainer believes it will not survive a long wait (such as a refactoring PR), they can send "final call" to the TOC by mentioning them in a comment. + +After another 7 days, if there is still zero approval, this is considered a polite refusal, and the PR will be closed to avoid wasting further time. Therefore, the "final call" has a cost, and should be used cautiously. + +However, if there are no objections from maintainers, the PR can be merged with only one approval from the TOC (not the author). + +### Commit messages + +Mergers are required to rewrite the PR title and the first comment (the summary) when necessary so the squash commit message is clear. + +The final commit message should not hedge: replace phrases like `hopefully, won't happen anymore` with definite wording. + +#### PR Co-authors + +A person counts as a PR co-author once they (co-)authored a commit that is not simply a `Merge base branch into branch` commit. Mergers must remove such false-positive co-authors when writing the squash message. Every true co-author must remain in the commit message. + +#### PRs targeting `main` + +The commit message of PRs targeting `main` is always + +```bash +$PR_TITLE ($PR_INDEX) + +$REWRITTEN_PR_SUMMARY +``` + +#### Backport PRs + +The commit message of backport PRs is always + +```bash +$PR_TITLE ($INITIAL_PR_INDEX) ($BACKPORT_PR_INDEX) + +$REWRITTEN_PR_SUMMARY +``` + +## Contribution Roles + +### Maintainers + +We list [maintainers](../MAINTAINERS) so every PR gets proper review. + +#### Review expectations + +Every PR **must** be reviewed by at least two maintainers (or owners) before merge. **Exception:** after one week, refactoring PRs and documentation-only PRs need only one maintainer approval. + +Maintainers are expected to spend time on code reviews. + +#### Becoming a maintainer + +A maintainer should already be a Gitea contributor with at least four merged PRs. To apply, use the [Discord](https://discord.gg/Gitea) `#develop` channel. Maintainer teams may also invite contributors. + +#### Stepping down, advisors, and inactivity + +If you cannot keep reviewing, apply to leave the maintainers team. You can join the [advisors team](https://github.com/orgs/go-gitea/teams/advisors); advisors who want to review again are welcome back as maintainers. + +If a maintainer is inactive for more than three months and has not left the team, owners may move them to the advisors team. + +#### Account security + +For security, maintainers should enable 2FA and sign commits with GPG when possible: + +- [Two-factor authentication](https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication) +- [Signing commits with GPG](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits) + +Any account with write access (including bots and TOC members) **must** use [2FA](https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication). + +### Mergers + +Mergers are the maintainers who carry out the final merge of approved PRs. Their responsibilities, described throughout this guide, are: + +- Merging PRs from the [merge queue](#getting-prs-merged) in order, once a PR has `lgtm/done`, no open discussions, and no merge conflicts. +- Rewriting the PR title and summary so the squash [commit message](#commit-messages) is clear, removing false-positive co-authors while keeping every true co-author. +- Assigning the correct labels (including `type/…`) needed for changelog and backport decisions. +- Agreeing, together with the owners, on when a release is ready (see [release management](release-management.md)). + +#### Becoming a merger + +A merger must already be a Gitea maintainer. +To apply, use the [Discord](https://discord.gg/Gitea) `#maintainers` channel. +The minimum requirement for applications to become a merger is to have participated actively in the community for at least four months before applying. +Ultimately, regardless of previous participation, you can only become a merger if the TOC votes in your favor. + +You may also be invited by the TOC to become a merger. + +### Technical Oversight Committee (TOC) + +At the start of 2023, the `Owners` team was dissolved. Instead, the governance charter proposed a technical oversight committee (TOC) which expands the ownership team of the Gitea project from three elected positions to six positions. Three positions are elected as it has been over the past years, and the other three consist of appointed members from the Gitea company. +https://blog.gitea.com/quarterly-23q1/ + +#### TOC election process + +Any maintainer is eligible to be part of the community TOC if they are not associated with the Gitea company. +A maintainer can either nominate themselves, or can be nominated by other maintainers to be a candidate for the TOC election. +If you are nominated by someone else, you must first accept your nomination before the vote starts to be a candidate. + +The TOC is elected for one year, the TOC election happens yearly. +After the announcement of the results of the TOC election, elected members have two weeks time to confirm or refuse the seat. +If an elected member does not answer within this timeframe, they are automatically assumed to refuse the seat. +Refusals result in the person with the next highest vote getting the same choice. +As long as seats are empty in the TOC, members of the previous TOC can fill them until an elected member accepts the seat. + +If an elected member that accepts the seat does not have 2FA configured yet, they will be temporarily counted as `answer pending` until they manage to configure 2FA, thus leaving their seat empty for this duration. + +If multiple persons have the same amount of votes, a random draw will be used to determine the order of the candidates with the same amount of votes, and thus who gets the seat first. +The candidates will be placed in the list in an alphabetical insensitive order by their username. +We use this script to determine the order of candidates with the same amount of votes: + +```python +import random +random.seed("Gitea TOC Election") +random.choice([, , ...]) +``` + +The result of this script needs then to be published in the TOC election issue to ensure transparency of the process. + +### Current TOC members + +- 2026-06-14 ~ 2026-12-31 + - Company + - [Jason Song](https://gitea.com/wolfogre) + - [Lunny Xiao](https://gitea.com/lunny) + - [Matti Ranta](https://gitea.com/techknowlogick) + - Community + - [bircni](https://gitea.com/bircni) + - [delvh](https://gitea.com/delvh) + - [TheFox0x7](https://gitea.com/TheFox0x7) + + +### Previous TOC/owners members + +Here's the history of the owners and the time they served: + +- [Lunny Xiao](https://gitea.com/lunny) - 2016, 2017, [2018](https://github.com/go-gitea/gitea/issues/3255), [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023 +- [Kim Carlbäcker](https://github.com/bkcsoft) - 2016, 2017 +- [Thomas Boerger](https://gitea.com/tboerger) - 2016, 2017 +- [Lauris Bukšis](https://gitea.com/lafriks) - [2018](https://github.com/go-gitea/gitea/issues/3255), [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), 2025 +- [Matti Ranta](https://gitea.com/techknowlogick) - [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023 +- [Andrew Thornton](https://gitea.com/zeripath) - [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023 +- [6543](https://gitea.com/6543) - 2023, 2025 +- [John Olheiser](https://gitea.com/jolheiser) - 2023, 2024 +- [Jason Song](https://gitea.com/wolfogre) - 2023 + +## Governance Compensation + +Each member of the community elected TOC will be granted $500 each month as compensation for their work. + +Furthermore, any community release manager for a specific release or LTS will be compensated $500 for the delivery of said release. + +These funds will come from community sources like the OpenCollective rather than directly from the company. +Only non-company members are eligible for this compensation, and if a member of the community TOC takes the responsibility of release manager, they would only be compensated for their TOC duties. +Gitea Ltd employees are not eligible to receive any funds from the OpenCollective unless it is reimbursement for a purchase made for the Gitea project itself. + +## Roadmap + +Each year a roadmap will be discussed with the entire Gitea maintainers team, and feedback will be solicited from various stakeholders. +TOC members need to review the roadmap every year and work together on the direction of the project. + +When a vote is required for a proposal or other change, the vote of community elected TOC members count slightly more than the vote of company elected TOC members. With this approach, we both avoid ties and ensure that changes align with the mission statement and community opinion. + +You can visit our roadmap on the wiki. diff --git a/package/gitea/source/docs/development.md b/package/gitea/source/docs/development.md new file mode 100644 index 00000000..e0858a71 --- /dev/null +++ b/package/gitea/source/docs/development.md @@ -0,0 +1,141 @@ +# Development + +This document describes how to build Gitea from source and the day-to-day +development workflow. For prerequisites and how to obtain the code, see +[build-setup.md](build-setup.md). For running tests, see [testing.md](testing.md). For the +contribution workflow and review process, see [CONTRIBUTING.md](../CONTRIBUTING.md). + +Area-specific guidelines: + +- [Backend development guidelines](guidelines-backend.md) +- [Frontend development guidelines](guidelines-frontend.md) +- [Refactoring guidelines](guidelines-refactoring.md) + +## Building + +To build Gitea for development, run: + +```bash +make build +``` + +No build tags are required: SQLite support is compiled in by default, which is +enough for local development. The `build` target runs two sub-targets, `frontend` +and `backend`. The `bindata` tag embeds the frontend assets into the binary and is +only needed when packaging a self-contained build, so leave it out during +development. + +See `make help` for all available targets, and the workflows in +[`.github/workflows`](https://github.com/go-gitea/gitea/tree/main/.github/workflows) +to see how continuous integration builds and checks Gitea. + +## Building continuously + +To rebuild automatically when source files change: + +```bash +# watch both frontend and backend +make watch + +# or watch only the frontend (starts the Vite dev server) +make watch-frontend + +# or watch only the backend (Go) +make watch-backend +``` + +Watching all backend source files may hit the default open-files limit on macOS or +Linux; raise it with `ulimit -n 12288` for the current shell, or in your shell +startup file to make it permanent. + +## Formatting, linting and checks + +Continuous integration rejects pull requests that fail formatting, linting, or +consistency checks. Format your code first: + +```bash +make fmt +``` + +Then lint: + +```bash +# lint everything +make lint +# or only one side +make lint-backend +make lint-frontend +``` + +Many linters can fix issues automatically with `make lint-fix` (or the scoped +`make lint-backend-fix` / `make lint-frontend-fix`). The combined consistency +checks that CI runs are available as `make checks`. + +## Building and adding SVGs + +SVG icons are built with `make svg`, which compiles the icon sources into +`public/assets/img/svg`. Custom icons can be added under `web_src/svg`. + +## Updating the API + +When you create or change API routes, you **must** update the +[Swagger](https://swagger.io/docs/specification/2-0/what-is-swagger/) documentation +using [go-swagger](https://goswagger.io/) comments. See the +[backend development guidelines](guidelines-backend.md) for how API routes, +request/response structs, and swagger definitions fit together. + +Regenerate and validate the spec after changing an endpoint, then commit the +updated JSON: + +```bash +make generate-swagger +make swagger-validate +``` + +CI verifies the committed spec is up to date with: + +```bash +make swagger-check +``` + +## Creating new configuration options + +When adding configuration options it is not enough to add them to the +`modules/setting` files. Also update +[`custom/conf/app.example.ini`](../custom/conf/app.example.ini), and document them in +the [configuration cheat sheet](https://docs.gitea.com/administration/config-cheat-sheet), +which lives in the [documentation repository](https://gitea.com/gitea/docs). + +## Database migrations + +If you make breaking changes to a database-persisted struct under `models/`, add a +new migration in `models/migrations/`. See [testing.md](testing.md#migration-tests) +for running the migration tests. + +## Testing + +For unit, integration, end-to-end, and migration tests, see [testing.md](testing.md). + +## IDE configuration + +### Visual Studio Code + +A `launch.json` and `tasks.json` are provided in +[`contrib/development/vscode`](../contrib/development/vscode). See +[`contrib/development/README.md`](../contrib/development/README.md) for details. + +### GoLand + +Clicking the `Run Application` arrow on `func main()` in `/main.go` starts a +debuggable Gitea instance. + +The `Output Directory` in `Run/Debug Configuration` **must** be set to the Gitea +project directory (the one containing `main.go` and `go.mod`). Otherwise the working +directory is a GoLand temporary directory, which prevents Gitea from loading dynamic +resources (such as templates) in development. + +## Submitting your changes + +Push your branch and open a pull request. See [CONTRIBUTING.md](../CONTRIBUTING.md) +for the review process and PR requirements. For help, join the `#Develop` channel on +[Discord](https://discord.gg/gitea). diff --git a/package/gitea/source/docs/guidelines-backend.md b/package/gitea/source/docs/guidelines-backend.md new file mode 100644 index 00000000..5342c1d9 --- /dev/null +++ b/package/gitea/source/docs/guidelines-backend.md @@ -0,0 +1,132 @@ +# Backend development guidelines + +This document covers backend-specific architecture and contribution expectations. +For the general workflow see [CONTRIBUTING.md](../CONTRIBUTING.md), and for building +and testing see [development.md](development.md) and [testing.md](testing.md). + +## Background + +The backend is written in Go. Web routing is handled by +[chi](https://github.com/go-chi/chi) and database access goes through the +[XORM](https://xorm.io/) ORM. Understanding how the packages depend on each other is +essential before contributing backend code. + +## Package design + +### Package layout + +The backend is split into top-level packages, each with a focused responsibility: + +- `build`: helper scripts used at compile time +- `cmd`: subcommands such as `web`, `serv`, `hooks`, `doctor`, and admin utilities +- `models`: data structures and database operations (XORM); keeps external + dependencies to a minimum + - `models/db`: core database operations + - `models/fixtures`: sample data used by tests + - `models/migrations`: schema migration scripts +- `modules`: standalone functionality with few dependencies + - `modules/setting`: configuration handling + - `modules/git`: interaction with the Git command line +- `routers`: request handlers, split into `api`, `web`, `install`, and `private` +- `services`: business logic that ties routers and models together +- `templates`: Go HTML templates +- `public`: compiled frontend assets +- `tests`: integration and end-to-end test helpers + +### Dependency direction + +Dependencies only flow in one direction: + +```text +cmd → routers → services → models → modules +``` + +A package on the left may import a package on its right, but never the reverse. + +### Naming conventions + +- Top-level packages use the plural form: `services`, `models`, `routers`. +- Subpackages use the singular form: `services/user`, `models/repository`. + +When packages from different layers share a name, use a snake_case import alias to +disambiguate: + +```go +import user_service "gitea.dev/services/user" +``` + +### Database transactions + +Operations that must roll back together should run inside `db.WithTx()` (or +`db.WithTx2()` when a value must be returned), defined in `models/db/context.go`. +Functions that participate in a transaction take a `context.Context` as their first +parameter so the transaction can be propagated. + +### XORM gotchas + +- Never call `x.Update(exemplar)` without an explicit `WHERE` clause — it updates + every row in the table. +- Partial table migrations must use `SyncWithOptions(IgnoreDrop...)` rather than a + plain `Sync`. +- When inserting rows with preset IDs, MSSQL requires `SET IDENTITY_INSERT` to be + enabled and PostgreSQL requires the sequence to be updated afterwards. + +## Dependencies + +Go dependencies are managed with [Go Modules](https://go.dev/ref/mod). + +Pull requests should only modify `go.mod` and `go.sum` where it relates to the +change at hand, be it a bug fix or a new feature. Otherwise, these files should only +be touched by pull requests whose sole purpose is updating dependencies. Run +`make tidy` after any change to `go.mod`. + +Any `go.mod` / `go.sum` update must be justified in the PR description and must be +verified by reviewers and the merger to reference an existing upstream commit. + +## API v1 + +The API is documented with [Swagger](https://gitea.com/api/swagger) and is modelled +on [the GitHub API](https://docs.github.com/en/rest). + +### GitHub API compatibility + +Gitea's API should use the same endpoints and fields as the GitHub API where +possible, unless there is a good reason to deviate. + +- If Gitea offers functionality GitHub does not, a new endpoint may be added. +- If Gitea exposes information the GitHub API does not, a new field may be added as + long as it does not collide with a GitHub field. +- Existing fields should not be removed unless there is a strong reason; the same + applies to status responses. + +If you notice a problem that would require a breaking change, leave a comment in the +code for a future refactor to API v2 (which is currently not planned) rather than +breaking v1. + +### Adding and maintaining API routes + +- All possible results (errors, success, and failure messages) must be documented in + the swagger comments on the route. +- Every JSON request body must be defined as a struct in `modules/structs/` and + registered in [`routers/api/v1/swagger/options.go`](../routers/api/v1/swagger/options.go). +- Every JSON response must be defined as a struct in `modules/structs/` and + registered with its category under [`routers/api/v1/swagger/`](../routers/api/v1/swagger). + +### HTTP methods and status codes + +In general, choose HTTP methods as follows: + +- **GET** returns the requested object(s) with status **200 OK**. +- **POST** creates a new object (e.g. a user) and returns **201 Created** with the + created object. +- **PUT** adds or assigns an existing object (e.g. a user to a team) and returns + **204 No Content** with no body. +- **PATCH** edits an existing object and returns the changed object with **200 OK**. +- **DELETE** removes an object and returns **204 No Content** with no body. + +### Requirements for API routes + +- All parameters of endpoints that edit an object must be optional, except those + needed to identify the object, which are required. +- Endpoints returning lists must support pagination (`page` and `limit` query + options) and set the `X-Total-Count` header via `ctx.SetTotalCountHeader(...)`. diff --git a/package/gitea/source/docs/guidelines-frontend.md b/package/gitea/source/docs/guidelines-frontend.md new file mode 100644 index 00000000..61a801ba --- /dev/null +++ b/package/gitea/source/docs/guidelines-frontend.md @@ -0,0 +1,98 @@ +# Frontend development guidelines + +This document covers frontend-specific architecture and contribution expectations. +For the general workflow see [CONTRIBUTING.md](../CONTRIBUTING.md), and for building +and testing see [development.md](development.md) and [testing.md](testing.md). + +## Background + +The frontend uses [Vue 3](https://vuejs.org/), [Fomantic-UI](https://fomantic-ui.com/) (built on jQuery) +and [Tailwind CSS](https://tailwindcss.com/). Pages are rendered with Go HTML templates. +Source files live in: + +- `web_src/css/`: CSS styles +- `web_src/js/`: JavaScript and TypeScript +- `web_src/js/components/`: Vue components +- `web_src/js/features/`: feature modules wired up at page load +- `templates/`: Go HTML templates + +## Dependencies + +Frontend dependencies are managed with [pnpm](https://pnpm.io/). The same rules as +for [backend dependencies](guidelines-backend.md#dependencies) apply, except the +relevant files are `package.json` and `pnpm-lock.yaml`, and new versions must always +reference an existing published version. + +## Framework usage + +Mixing frameworks arbitrarily makes code hard to maintain. Recommended combinations: + +- Vue3 +- Vanilla JavaScript +- Fomantic-UI (jQuery), deprecated, we vendored a specific version with a lot of changes. + +Avoid combinations such as Vue with Fomantic-UI. +Vue components may reuse Fomantic-UI CSS classes for visual consistency. +Use Go templates for simple or SEO-relevant pages and Vue for complex, interactive pages. +Gitea uses Vue 3 **without** JSX to keep HTML and JavaScript separate. + +> [!NOTE] +> Fomantic-UI is not an accessibility-friendly framework. Gitea patches some ARIA +> behavior, but accessibility work is ongoing — prefer semantic HTML and test +> keyboard/screen-reader behavior where you can. + +## Gitea-specific conventions + +- Keep features in their own files or directories. +- Use kebab-case for HTML `id`s and classes, ideally with 2-3 feature keywords. +- Prefix classes to avoid short-name conflicts between different frameworks. +- Create a new class name when overriding framework styles instead of editing the framework's own classes, + or fix the framework's source to fix all cases. +- Prefer semantic elements such as ``, + ``, link, dataHiddenCommentIDs, svg.RenderHTML(svgName), ) } @@ -1285,6 +1285,8 @@ func getDiffBasic(ctx context.Context, gitRepo *git.Repository, opts *DiffOption return nil, nil, nil, err } + // HINT: GIT-DIFF-HIGHLIGHT-LINE-NUMBER: git doesn't treat CR(\r) as EOL, CR is just a plain char which can appear anywhere in the diff output + // Since we have to do full-file-highlighting for the diff result, we need to make sure the highlighted lines exactly match the git's diff output. cmdDiff := gitcmd.NewCommand(). AddArguments("diff", "--src-prefix=\\a/", "--dst-prefix=\\b/"). AddArguments(opts.WhitespaceBehavior...). @@ -1405,8 +1407,12 @@ func highlightCodeLines(name, lang string, sections []*DiffSection, isLeft bool, if setting.Git.DisableDiffHighlight || len(rawContent) > MaxFullFileHighlightSizeLimit { return nil } - content := util.UnsafeBytesToString(charset.ToUTF8(rawContent, charset.ConvertOpts{})) + // HINT: GIT-DIFF-HIGHLIGHT-LINE-NUMBER: it should handle all CR(\r) before highlight to make line numbers match + if strings.Contains(content, "\r") { + content = strings.ReplaceAll(content, "\r\n", "\n") + content = strings.ReplaceAll(content, "\r", "␍") + } lexer := highlight.DetectChromaLexerByFileName(name, lang) highlightedNewContent := highlight.RenderCodeByLexer(lexer, content) unsafeLines := highlight.UnsafeSplitHighlightedLines(highlightedNewContent) diff --git a/package/gitea/source/services/gitdiff/gitdiff_excerpt.go b/package/gitea/source/services/gitdiff/gitdiff_excerpt.go index 4b1958fc..f5ff6483 100644 --- a/package/gitea/source/services/gitdiff/gitdiff_excerpt.go +++ b/package/gitea/source/services/gitdiff/gitdiff_excerpt.go @@ -10,7 +10,7 @@ import ( "html/template" "io" - "code.gitea.io/gitea/modules/setting" + "gitea.dev/modules/setting" "github.com/alecthomas/chroma/v2" ) diff --git a/package/gitea/source/services/gitdiff/gitdiff_excerpt_test.go b/package/gitea/source/services/gitdiff/gitdiff_excerpt_test.go index cb71e664..3d94cde6 100644 --- a/package/gitea/source/services/gitdiff/gitdiff_excerpt_test.go +++ b/package/gitea/source/services/gitdiff/gitdiff_excerpt_test.go @@ -8,7 +8,7 @@ import ( "strconv" "testing" - "code.gitea.io/gitea/modules/translation" + "gitea.dev/modules/translation" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/package/gitea/source/services/gitdiff/gitdiff_test.go b/package/gitea/source/services/gitdiff/gitdiff_test.go index e1b35821..ebe5fc90 100644 --- a/package/gitea/source/services/gitdiff/gitdiff_test.go +++ b/package/gitea/source/services/gitdiff/gitdiff_test.go @@ -10,14 +10,14 @@ import ( "strings" "testing" - issues_model "code.gitea.io/gitea/models/issues" - pull_model "code.gitea.io/gitea/models/pull" - "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/git/gitcmd" - "code.gitea.io/gitea/modules/json" - "code.gitea.io/gitea/modules/setting" + issues_model "gitea.dev/models/issues" + pull_model "gitea.dev/models/pull" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/json" + "gitea.dev/modules/setting" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -1143,6 +1143,19 @@ func TestHighlightCodeLines(t *testing.T) { 1: `b` + nl, }, ret) }) + t.Run("CharCR", func(t *testing.T) { + diffFile := &DiffFile{ + Name: "a.txt", + Sections: []*DiffSection{ + { + Lines: []*DiffLine{{LeftIdx: 1}, {LeftIdx: 2}}, + }, + }, + } + ret := highlightCodeLinesForDiffFile(diffFile, true, []byte("a\rb\r\nc")) + assert.Equal(t, "a␍b\n", string(ret[0])) + assert.Equal(t, `c`, string(ret[1])) + }) } func TestSyncUserSpecificDiff_UpdatedFiles(t *testing.T) { diff --git a/package/gitea/source/services/gitdiff/highlightdiff.go b/package/gitea/source/services/gitdiff/highlightdiff.go index 1de39637..fef61de2 100644 --- a/package/gitea/source/services/gitdiff/highlightdiff.go +++ b/package/gitea/source/services/gitdiff/highlightdiff.go @@ -6,10 +6,11 @@ package gitdiff import ( "bytes" "html/template" + "slices" "strings" "unicode/utf8" - "code.gitea.io/gitea/modules/util" + "gitea.dev/modules/util" "github.com/sergi/go-diff/diffmatchpatch" ) @@ -385,8 +386,7 @@ func (hcd *highlightCodeDiff) recoverOneDiff(str string) template.HTML { } // close all opening tags - for i := len(tagStack) - 1; i >= 0; i-- { - tagToClose := tagStack[i] + for _, tagToClose := range slices.Backward(tagStack) { // get the closing tag "" from "" or "" pos := strings.IndexAny(tagToClose, " >") // pos must be positive, because the tags were pushed by us diff --git a/package/gitea/source/services/gitdiff/highlightdiff_test.go b/package/gitea/source/services/gitdiff/highlightdiff_test.go index ea9a8829..9036311b 100644 --- a/package/gitea/source/services/gitdiff/highlightdiff_test.go +++ b/package/gitea/source/services/gitdiff/highlightdiff_test.go @@ -9,7 +9,7 @@ import ( "strings" "testing" - "code.gitea.io/gitea/modules/highlight" + "gitea.dev/modules/highlight" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/gitdiff/main_test.go b/package/gitea/source/services/gitdiff/main_test.go index cd9dcd8c..3ec7f3ba 100644 --- a/package/gitea/source/services/gitdiff/main_test.go +++ b/package/gitea/source/services/gitdiff/main_test.go @@ -6,11 +6,11 @@ package gitdiff import ( "testing" - "code.gitea.io/gitea/models/unittest" + "gitea.dev/models/unittest" - _ "code.gitea.io/gitea/models" - _ "code.gitea.io/gitea/models/actions" - _ "code.gitea.io/gitea/models/activities" + _ "gitea.dev/models" + _ "gitea.dev/models/actions" + _ "gitea.dev/models/activities" ) func TestMain(m *testing.M) { diff --git a/package/gitea/source/services/gitdiff/submodule.go b/package/gitea/source/services/gitdiff/submodule.go index 4347743e..9fffd130 100644 --- a/package/gitea/source/services/gitdiff/submodule.go +++ b/package/gitea/source/services/gitdiff/submodule.go @@ -7,10 +7,10 @@ import ( "context" "html/template" - "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/htmlutil" - "code.gitea.io/gitea/modules/log" + "gitea.dev/modules/base" + "gitea.dev/modules/git" + "gitea.dev/modules/htmlutil" + "gitea.dev/modules/log" ) type SubmoduleDiffInfo struct { diff --git a/package/gitea/source/services/gitdiff/submodule_test.go b/package/gitea/source/services/gitdiff/submodule_test.go index 9f2cf1d1..23afce33 100644 --- a/package/gitea/source/services/gitdiff/submodule_test.go +++ b/package/gitea/source/services/gitdiff/submodule_test.go @@ -7,8 +7,8 @@ import ( "strings" "testing" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/setting" + "gitea.dev/modules/git" + "gitea.dev/modules/setting" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/indexer/indexer.go b/package/gitea/source/services/indexer/indexer.go index 38dd012a..0e4f1873 100644 --- a/package/gitea/source/services/indexer/indexer.go +++ b/package/gitea/source/services/indexer/indexer.go @@ -4,10 +4,10 @@ package indexer import ( - code_indexer "code.gitea.io/gitea/modules/indexer/code" - issue_indexer "code.gitea.io/gitea/modules/indexer/issues" - stats_indexer "code.gitea.io/gitea/modules/indexer/stats" - notify_service "code.gitea.io/gitea/services/notify" + code_indexer "gitea.dev/modules/indexer/code" + issue_indexer "gitea.dev/modules/indexer/issues" + stats_indexer "gitea.dev/modules/indexer/stats" + notify_service "gitea.dev/services/notify" ) // Init initialize the repo indexer diff --git a/package/gitea/source/services/indexer/notify.go b/package/gitea/source/services/indexer/notify.go index e2cfe477..3bd68ebc 100644 --- a/package/gitea/source/services/indexer/notify.go +++ b/package/gitea/source/services/indexer/notify.go @@ -6,16 +6,16 @@ package indexer import ( "context" - issues_model "code.gitea.io/gitea/models/issues" - repo_model "code.gitea.io/gitea/models/repo" - user_model "code.gitea.io/gitea/models/user" - code_indexer "code.gitea.io/gitea/modules/indexer/code" - issue_indexer "code.gitea.io/gitea/modules/indexer/issues" - stats_indexer "code.gitea.io/gitea/modules/indexer/stats" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/setting" - notify_service "code.gitea.io/gitea/services/notify" + issues_model "gitea.dev/models/issues" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + code_indexer "gitea.dev/modules/indexer/code" + issue_indexer "gitea.dev/modules/indexer/issues" + stats_indexer "gitea.dev/modules/indexer/stats" + "gitea.dev/modules/log" + "gitea.dev/modules/repository" + "gitea.dev/modules/setting" + notify_service "gitea.dev/services/notify" ) type indexerNotifier struct { diff --git a/package/gitea/source/services/issue/assignee.go b/package/gitea/source/services/issue/assignee.go index 5a64c722..4b241155 100644 --- a/package/gitea/source/services/issue/assignee.go +++ b/package/gitea/source/services/issue/assignee.go @@ -6,19 +6,16 @@ package issue import ( "context" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/organization" - "code.gitea.io/gitea/models/perm" - access_model "code.gitea.io/gitea/models/perm/access" - 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/log" - notify_service "code.gitea.io/gitea/services/notify" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/container" + notify_service "gitea.dev/services/notify" ) -// DeleteNotPassedAssignee deletes all assignees who aren't passed via the "assignees" array -func DeleteNotPassedAssignee(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, assignees []*user_model.User) (err error) { +func toBeRemovedAssignees(issue *issues_model.Issue, assignees []*user_model.User) (toBeRemovedAssignees []*user_model.User) { var found bool oriAssignees := make([]*user_model.User, len(issue.Assignees)) _ = copy(oriAssignees, issue.Assignees) @@ -34,295 +31,255 @@ func DeleteNotPassedAssignee(ctx context.Context, issue *issues_model.Issue, doe if !found { // This function also does comments and hooks, which is why we call it separately instead of directly removing the assignees here - if _, _, err := ToggleAssigneeWithNotify(ctx, issue, doer, assignee.ID); err != nil { - return err - } + toBeRemovedAssignees = append(toBeRemovedAssignees, assignee) + } + } + return toBeRemovedAssignees +} + +// DeleteNotPassedAssignee deletes all assignees who aren't passed via the "assignees" array +func DeleteNotPassedAssignee(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, assignees []*user_model.User) (err error) { + toBeRemoved := toBeRemovedAssignees(issue, assignees) + + for _, assignee := range toBeRemoved { + // This function also does comments and hooks, which is why we call it separately instead of directly removing the assignees here + removed, comment, err := ToggleAssignee(ctx, issue, doer, assignee) + if err != nil { + return err + } + if removed { + notify_service.IssueChangeAssignee(ctx, doer, issue, assignee, true, comment) } } return nil } -// ToggleAssigneeWithNoNotify changes a user between assigned and not assigned for this issue, and make issue comment for it. -func ToggleAssigneeWithNotify(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, assigneeID int64) (removed bool, comment *issues_model.Comment, err error) { - removed, comment, err = issues_model.ToggleIssueAssignee(ctx, issue, doer, assigneeID) +// ToggleAssignee changes a user between assigned and not assigned for this issue, and make issue comment for it. +func ToggleAssignee(ctx context.Context, issue *issues_model.Issue, doer, assignee *user_model.User) (removed bool, comment *issues_model.Comment, err error) { + removed, comment, err = issues_model.ToggleIssueAssignee(ctx, issue, doer, assignee.ID) if err != nil { return false, nil, err } + issue.AssigneeID = assignee.ID + issue.Assignee = assignee + + return removed, comment, nil +} + +// ToggleAssignee changes a user between assigned and not assigned for this issue, and make issue comment for it. +func ToggleAssigneeWithNotify(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, assigneeID int64) (removed bool, comment *issues_model.Comment, err error) { assignee, err := user_model.GetUserByID(ctx, assigneeID) if err != nil { return false, nil, err } - issue.AssigneeID = assigneeID - issue.Assignee = assignee + + removed, comment, err = ToggleAssignee(ctx, issue, doer, assignee) + if err != nil { + return false, nil, err + } notify_service.IssueChangeAssignee(ctx, doer, issue, assignee, removed, comment) return removed, comment, err } -// ReviewRequest add or remove a review request from a user for this PR, and make comment for it. -func ReviewRequest(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, permDoer *access_model.Permission, reviewer *user_model.User, isAdd bool) (comment *issues_model.Comment, err error) { - err = isValidReviewRequest(ctx, reviewer, doer, isAdd, issue, permDoer) - if err != nil { - return nil, err +// UpdateAssignees is a helper function to add or delete one or multiple issue assignee(s) +// Deleting is done the GitHub way (quote from their api documentation): +// https://developer.github.com/v3/issues/#edit-an-issue +// "assignees" (array): Logins for Users to assign to this issue. +// Pass one or more user logins to replace the set of assignees on this Issue. +// Send an empty array ([]) to clear all assignees from the Issue. +func UpdateAssignees(ctx context.Context, issue *issues_model.Issue, oneAssignee string, multipleAssignees []string, doer *user_model.User) (err error) { + uniqueAssignees := container.SetOf(multipleAssignees...) + + // Keep the old assignee thingy for compatibility reasons + if oneAssignee != "" { + uniqueAssignees.Add(oneAssignee) } - if isAdd { - comment, err = issues_model.AddReviewRequest(ctx, issue, reviewer, doer, false) - } else { - comment, err = issues_model.RemoveReviewRequest(ctx, issue, reviewer, doer) - } - - if err != nil { - return nil, err - } - - if comment != nil { - notify_service.PullRequestReviewRequest(ctx, doer, issue, reviewer, isAdd, comment) - } - - return comment, err -} - -// isValidReviewRequest Check permission for ReviewRequest -func isValidReviewRequest(ctx context.Context, reviewer, doer *user_model.User, isAdd bool, issue *issues_model.Issue, permDoer *access_model.Permission) error { - if reviewer.IsOrganization() { - return issues_model.ErrNotValidReviewRequest{ - Reason: "Organization can't be added as reviewer", - UserID: doer.ID, - RepoID: issue.Repo.ID, - } - } - if doer.IsOrganization() { - return issues_model.ErrNotValidReviewRequest{ - Reason: "Organization can't be doer to add reviewer", - UserID: doer.ID, - RepoID: issue.Repo.ID, - } - } - - permReviewer, err := access_model.GetIndividualUserRepoPermission(ctx, issue.Repo, reviewer) - if err != nil { - return err - } - - if permDoer == nil { - permDoer = new(access_model.Permission) - *permDoer, err = access_model.GetDoerRepoPermission(ctx, issue.Repo, doer) + // Loop through all assignees to add them + allNewAssignees := make([]*user_model.User, 0, len(uniqueAssignees)) + for _, assigneeName := range uniqueAssignees.Values() { + assignee, err := user_model.GetUserByName(ctx, assigneeName) if err != nil { return err } - } - lastReview, err := issues_model.GetReviewByIssueIDAndUserID(ctx, issue.ID, reviewer.ID) - if err != nil && !issues_model.IsErrReviewNotExist(err) { - return err - } - - canDoerChangeReviewRequests := CanDoerChangeReviewRequests(ctx, doer, issue.Repo, issue.PosterID) - - if isAdd { - if !permReviewer.CanAccessAny(perm.AccessModeRead, unit.TypePullRequests) { - return issues_model.ErrNotValidReviewRequest{ - Reason: "Reviewer can't read", - UserID: doer.ID, - RepoID: issue.Repo.ID, - } + if err := validateAssignee(ctx, issue, doer, assignee); err != nil { + return err } - if reviewer.ID == issue.PosterID && issue.OriginalAuthorID == 0 { - return issues_model.ErrNotValidReviewRequest{ - Reason: "poster of pr can't be reviewer", - UserID: doer.ID, - RepoID: issue.Repo.ID, - } - } - - if canDoerChangeReviewRequests { - return nil - } - - if doer.ID == issue.PosterID && issue.OriginalAuthorID == 0 && lastReview != nil && lastReview.Type != issues_model.ReviewTypeRequest { - return nil - } - - return issues_model.ErrNotValidReviewRequest{ - Reason: "Doer can't choose reviewer", - UserID: doer.ID, - RepoID: issue.Repo.ID, - } + allNewAssignees = append(allNewAssignees, assignee) } - if canDoerChangeReviewRequests { - return nil - } + assigneeCommentMap := make(map[int64]*issues_model.Comment) + assigneeRemovedCommentMap := make(map[int64]*issues_model.Comment) + assigneeRemoved := make(map[int64]*user_model.User) + if err := db.WithTx(ctx, func(ctx context.Context) error { + // Delete all old assignees not passed. + toBeRemoved := toBeRemovedAssignees(issue, allNewAssignees) - if lastReview != nil && lastReview.Type == issues_model.ReviewTypeRequest && lastReview.ReviewerID == doer.ID { - return nil - } - - return issues_model.ErrNotValidReviewRequest{ - Reason: "Doer can't remove reviewer", - UserID: doer.ID, - RepoID: issue.Repo.ID, - } -} - -// isValidTeamReviewRequest Check permission for ReviewRequest Team -func isValidTeamReviewRequest(ctx context.Context, reviewer *organization.Team, doer *user_model.User, isAdd bool, issue *issues_model.Issue) error { - if doer.IsOrganization() { - return issues_model.ErrNotValidReviewRequest{ - Reason: "Organization can't be doer to add reviewer", - UserID: doer.ID, - RepoID: issue.Repo.ID, - } - } - - canDoerChangeReviewRequests := CanDoerChangeReviewRequests(ctx, doer, issue.Repo, issue.PosterID) - - if isAdd { - if issue.Repo.IsPrivate { - hasTeam := organization.HasTeamRepo(ctx, reviewer.OrgID, reviewer.ID, issue.RepoID) - - if !hasTeam { - return issues_model.ErrNotValidReviewRequest{ - Reason: "Reviewing team can't read repo", - UserID: doer.ID, - RepoID: issue.Repo.ID, - } - } - } - - if canDoerChangeReviewRequests { - return nil - } - - return issues_model.ErrNotValidReviewRequest{ - Reason: "Doer can't choose reviewer", - UserID: doer.ID, - RepoID: issue.Repo.ID, - } - } - - if canDoerChangeReviewRequests { - return nil - } - - return issues_model.ErrNotValidReviewRequest{ - Reason: "Doer can't remove reviewer", - UserID: doer.ID, - RepoID: issue.Repo.ID, - } -} - -// TeamReviewRequest add or remove a review request from a team for this PR, and make comment for it. -func TeamReviewRequest(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, reviewer *organization.Team, isAdd bool) (comment *issues_model.Comment, err error) { - err = isValidTeamReviewRequest(ctx, reviewer, doer, isAdd, issue) - if err != nil { - return nil, err - } - if isAdd { - comment, err = issues_model.AddTeamReviewRequest(ctx, issue, reviewer, doer, false) - } else { - comment, err = issues_model.RemoveTeamReviewRequest(ctx, issue, reviewer, doer) - } - - if err != nil { - return nil, err - } - - if comment == nil || !isAdd { - return nil, nil //nolint:nilnil // return nil because no comment was created or it is a removal - } - - return comment, teamReviewRequestNotify(ctx, issue, doer, reviewer, isAdd, comment) -} - -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) - } - } - } -} - -// teamReviewRequestNotify notify all user in this team -func teamReviewRequestNotify(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, reviewer *organization.Team, isAdd bool, comment *issues_model.Comment) error { - // notify all user in this team - if err := comment.LoadIssue(ctx); err != nil { - return err - } - - members, err := organization.GetTeamMembers(ctx, &organization.SearchMembersOptions{ - TeamID: reviewer.ID, - }) - if err != nil { - return err - } - - for _, member := range members { - if member.ID == comment.Issue.PosterID { - continue - } - comment.AssigneeID = member.ID - notify_service.PullRequestReviewRequest(ctx, doer, issue, member, isAdd, comment) - } - - return err -} - -// CanDoerChangeReviewRequests returns if the doer can add/remove review requests of a PR -func CanDoerChangeReviewRequests(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, posterID int64) bool { - if repo.IsArchived { - return false - } - // The poster of the PR can change the reviewers - if doer.ID == posterID { - return true - } - - // The owner of the repo can change the reviewers - if doer.ID == repo.OwnerID { - return true - } - - // Collaborators of the repo can change the reviewers - isCollaborator, err := repo_model.IsCollaborator(ctx, repo.ID, doer.ID) - if err != nil { - log.Error("IsCollaborator: %v", err) - return false - } - if isCollaborator { - return true - } - - // If the repo's owner is an organization, members of teams with read permission on pull requests can change reviewers - if repo.Owner.IsOrganization() { - teams, err := organization.GetTeamsWithAccessToAnyRepoUnit(ctx, repo.OwnerID, repo.ID, perm.AccessModeRead, unit.TypePullRequests) - if err != nil { - log.Error("GetTeamsWithAccessToRepo: %v", err) - return false - } - for _, team := range teams { - if !team.UnitEnabled(ctx, unit.TypePullRequests) { - continue - } - isMember, err := organization.IsTeamMember(ctx, repo.OwnerID, team.ID, doer.ID) + for _, assignee := range toBeRemoved { + // This function also does comments and hooks, which is why we call it separately instead of directly removing the assignees here + removed, comment, err := ToggleAssignee(ctx, issue, doer, assignee) if err != nil { - log.Error("IsTeamMember: %v", err) - continue + return err } - if isMember { - return true + if removed { + assigneeRemoved[assignee.ID] = assignee + assigneeRemovedCommentMap[assignee.ID] = comment } } + + // Add all new assignees. + // Update the assignee. The function will check if the user exists, is already + // assigned (which he shouldn't as we deleted all assignees before) and + // has access to the repo. + for _, assignee := range allNewAssignees { + // Extra method to prevent double adding (which would result in removing). + comment, err := AddAssigneeIfNotAssigned(ctx, issue, doer, assignee) + if err != nil { + return err + } + assigneeCommentMap[assignee.ID] = comment + } + + return nil + }); err != nil { + return err + } + + for _, assignee := range assigneeRemoved { + notify_service.IssueChangeAssignee(ctx, doer, issue, assignee, true, assigneeRemovedCommentMap[assignee.ID]) + } + + for _, assignee := range allNewAssignees { + comment := assigneeCommentMap[assignee.ID] + if comment != nil { + notify_service.IssueChangeAssignee(ctx, doer, issue, assignee, false, comment) + } } - return false + return nil +} + +func validateAssignee(ctx context.Context, issue *issues_model.Issue, doer, assignee *user_model.User) error { + if user_model.IsUserBlockedBy(ctx, doer, assignee.ID) { + return user_model.ErrBlockedUser + } + + valid, err := access_model.CanBeAssigned(ctx, assignee, issue.Repo) + if err != nil { + return err + } + if !valid { + return repo_model.ErrUserDoesNotHaveAccessToRepo{UserID: assignee.ID, RepoName: issue.Repo.Name} + } + + return nil +} + +// AddAssigneeIfNotAssigned adds an assignee only if he isn't already assigned to the issue. +// Also checks for access of assigned user +func AddAssigneeIfNotAssigned(ctx context.Context, issue *issues_model.Issue, doer, assignee *user_model.User) (comment *issues_model.Comment, err error) { + // Check if the user is already assigned + isAssigned, err := issues_model.IsUserAssignedToIssue(ctx, issue, assignee.ID) + if err != nil { + return nil, err + } + if isAssigned { + // nothing to do + return nil, nil //nolint:nilnil // return nil because the user is already assigned + } + + if err := validateAssignee(ctx, issue, doer, assignee); err != nil { + return nil, err + } + + _, comment, err = issues_model.ToggleIssueAssignee(ctx, issue, doer, assignee.ID) + return comment, err +} + +// AddAssignees adds multiple assignees to an issue atomically. +func AddAssignees(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, assigneeIDs []int64) error { + assigneeCommentMap := make(map[int64]*issues_model.Comment) + assignees := make(map[int64]*user_model.User) + if err := db.WithTx(ctx, func(ctx context.Context) error { + for _, assigneeID := range assigneeIDs { + isAssigned, err := issues_model.IsUserAssignedToIssue(ctx, issue, assigneeID) + if err != nil { + return err + } + if isAssigned { + continue + } + + assignee, err := user_model.GetUserByID(ctx, assigneeID) + if err != nil { + return err + } + if err := validateAssignee(ctx, issue, doer, assignee); err != nil { + return err + } + + comment, err := AddAssigneeIfNotAssigned(ctx, issue, doer, assignee) + if err != nil { + return err + } + assignees[assigneeID] = assignee + assigneeCommentMap[assigneeID] = comment + } + + return nil + }); err != nil { + return err + } + + if len(assignees) > 0 { + for assigneeID, assignee := range assignees { + notify_service.IssueChangeAssignee(ctx, doer, issue, assignee, false, assigneeCommentMap[assigneeID]) + } + } + return nil +} + +// RemoveAssignees removes multiple assignees from an issue atomically. +func RemoveAssignees(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, assigneeIDs []int64) error { + assigneeCommentMap := make(map[int64]*issues_model.Comment) + assignees := make(map[int64]*user_model.User) + if err := db.WithTx(ctx, func(ctx context.Context) error { + for _, assigneeID := range assigneeIDs { + isAssigned, err := issues_model.IsUserAssignedToIssue(ctx, issue, assigneeID) + if err != nil { + return err + } + if !isAssigned { + continue + } + removed, comment, err := issues_model.ToggleIssueAssignee(ctx, issue, doer, assigneeID) + if err != nil { + return err + } + if removed { + assignee, err := user_model.GetUserByID(ctx, assigneeID) + if err != nil { + return err + } + assignees[assigneeID] = assignee + assigneeCommentMap[assigneeID] = comment + } + } + return nil + }); err != nil { + return err + } + + if len(assignees) > 0 { + for assigneeID, assignee := range assignees { + notify_service.IssueChangeAssignee(ctx, doer, issue, assignee, true, assigneeCommentMap[assigneeID]) + } + } + return nil } diff --git a/package/gitea/source/services/issue/assignee_test.go b/package/gitea/source/services/issue/assignee_test.go index 4bf0884f..4c427a28 100644 --- a/package/gitea/source/services/issue/assignee_test.go +++ b/package/gitea/source/services/issue/assignee_test.go @@ -6,9 +6,10 @@ package issue import ( "testing" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" "github.com/stretchr/testify/assert" ) @@ -29,7 +30,7 @@ func TestDeleteNotPassedAssignee(t *testing.T) { assert.NoError(t, err) // Check if he got removed - isAssigned, err := issues_model.IsUserAssignedToIssue(t.Context(), issue, user1) + isAssigned, err := issues_model.IsUserAssignedToIssue(t.Context(), issue, user1.ID) assert.NoError(t, err) assert.True(t, isAssigned) @@ -44,3 +45,55 @@ func TestDeleteNotPassedAssignee(t *testing.T) { assert.Empty(t, issue.Assignees) assert.Empty(t, issue.Assignee) } + +func TestAddAssigneeIfNotAssignedBlocked(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + issue, err := issues_model.GetIssueByID(t.Context(), 1) + assert.NoError(t, err) + assert.NoError(t, issue.LoadRepo(t.Context())) + + doer, err := user_model.GetUserByID(t.Context(), 4) + assert.NoError(t, err) + + assignee, err := user_model.GetUserByID(t.Context(), 2) + assert.NoError(t, err) + + assert.NoError(t, db.Insert(t.Context(), &user_model.Blocking{ + BlockerID: assignee.ID, + BlockeeID: doer.ID, + })) + + _, err = AddAssigneeIfNotAssigned(t.Context(), issue, doer, assignee) + assert.ErrorIs(t, err, user_model.ErrBlockedUser) + + isAssigned, err := issues_model.IsUserAssignedToIssue(t.Context(), issue, assignee.ID) + assert.NoError(t, err) + assert.False(t, isAssigned) +} + +func TestAddAssigneesBlockedIsAtomic(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + issue, err := issues_model.GetIssueByID(t.Context(), 1) + assert.NoError(t, err) + assert.NoError(t, issue.LoadAttributes(t.Context())) + + doer, err := user_model.GetUserByID(t.Context(), 2) + assert.NoError(t, err) + + blockedAssignee, err := user_model.GetUserByID(t.Context(), 40) + assert.NoError(t, err) + + assert.NoError(t, db.Insert(t.Context(), &user_model.Blocking{ + BlockerID: blockedAssignee.ID, + BlockeeID: doer.ID, + })) + + err = AddAssignees(t.Context(), issue, doer, []int64{doer.ID, blockedAssignee.ID}) + assert.ErrorIs(t, err, user_model.ErrBlockedUser) + + assigneeIDs, err := issues_model.GetAssigneeIDsByIssue(t.Context(), issue.ID) + assert.NoError(t, err) + assert.ElementsMatch(t, []int64{1}, assigneeIDs) +} diff --git a/package/gitea/source/services/issue/comments.go b/package/gitea/source/services/issue/comments.go index 3ce2e2a5..5b70dbf7 100644 --- a/package/gitea/source/services/issue/comments.go +++ b/package/gitea/source/services/issue/comments.go @@ -8,17 +8,19 @@ import ( "errors" "fmt" - "code.gitea.io/gitea/models/db" - 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/gitrepo" - "code.gitea.io/gitea/modules/json" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/timeutil" - git_service "code.gitea.io/gitea/services/git" - notify_service "code.gitea.io/gitea/services/notify" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/json" + "gitea.dev/modules/log" + "gitea.dev/modules/timeutil" + git_service "gitea.dev/services/git" + notify_service "gitea.dev/services/notify" + + "xorm.io/builder" ) // CreateRefComment creates a commit reference comment to issue. @@ -34,10 +36,10 @@ func CreateRefComment(ctx context.Context, doer *user_model.User, repo *repo_mod } // Check if same reference from same commit has already existed. - has, err := db.GetEngine(ctx).Get(&issues_model.Comment{ - Type: issues_model.CommentTypeCommitRef, - IssueID: issue.ID, - CommitSHA: commitSHA, + has, err := db.Exist[issues_model.Comment](ctx, builder.Eq{ + "`type`": issues_model.CommentTypeCommitRef, + "issue_id": issue.ID, + "commit_sha": commitSHA, }) if err != nil { return fmt.Errorf("check reference comment: %w", err) @@ -184,7 +186,7 @@ func LoadCommentPushCommits(ctx context.Context, c *issues_model.Comment) error } defer closer.Close() - c.Commits, err = git_service.ConvertFromGitCommit(ctx, gitRepo.GetCommitsFromIDs(data.CommitIDs), c.Issue.Repo) + c.Commits, err = git_service.ConvertFromGitCommit(ctx, gitRepo.GetCommitsFromIDs(data.CommitIDs), c.Issue.Repo, "") // no current ref sub path for PR commit list if err != nil { log.Debug("ConvertFromGitCommit: %v", err) // no need to show 500 error to end user when the commit does not exist } else { diff --git a/package/gitea/source/services/issue/commit.go b/package/gitea/source/services/issue/commit.go index 68ccc906..0fb070d0 100644 --- a/package/gitea/source/services/issue/commit.go +++ b/package/gitea/source/services/issue/commit.go @@ -10,19 +10,20 @@ import ( "html" "net/url" "regexp" + "slices" "strconv" "strings" "time" - 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/container" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/references" - "code.gitea.io/gitea/modules/repository" + issues_model "gitea.dev/models/issues" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/container" + "gitea.dev/modules/git" + "gitea.dev/modules/log" + "gitea.dev/modules/references" + "gitea.dev/modules/repository" ) const ( @@ -123,9 +124,7 @@ func getIssueFromRef(ctx context.Context, repo *repo_model.Repository, index int // UpdateIssuesCommit checks if issues are manipulated by commit message. func UpdateIssuesCommit(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, commits []*repository.PushCommit, branchName string) error { // Commits are appended in the reverse order. - for i := len(commits) - 1; i >= 0; i-- { - c := commits[i] - + for _, c := range slices.Backward(commits) { type markKey struct { ID int64 Action references.XRefAction diff --git a/package/gitea/source/services/issue/commit_test.go b/package/gitea/source/services/issue/commit_test.go index 5950762c..61e4b00c 100644 --- a/package/gitea/source/services/issue/commit_test.go +++ b/package/gitea/source/services/issue/commit_test.go @@ -6,13 +6,13 @@ package issue import ( "testing" - activities_model "code.gitea.io/gitea/models/activities" - 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/repository" - "code.gitea.io/gitea/modules/setting" + activities_model "gitea.dev/models/activities" + issues_model "gitea.dev/models/issues" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/modules/repository" + "gitea.dev/modules/setting" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/issue/content.go b/package/gitea/source/services/issue/content.go index 68941829..41f30e09 100644 --- a/package/gitea/source/services/issue/content.go +++ b/package/gitea/source/services/issue/content.go @@ -6,10 +6,10 @@ package issue import ( "context" - issues_model "code.gitea.io/gitea/models/issues" - access_model "code.gitea.io/gitea/models/perm/access" - user_model "code.gitea.io/gitea/models/user" - notify_service "code.gitea.io/gitea/services/notify" + issues_model "gitea.dev/models/issues" + access_model "gitea.dev/models/perm/access" + user_model "gitea.dev/models/user" + notify_service "gitea.dev/services/notify" ) // ChangeContent changes issue content, as the given user. diff --git a/package/gitea/source/services/issue/issue.go b/package/gitea/source/services/issue/issue.go index 9beb4c46..51135737 100644 --- a/package/gitea/source/services/issue/issue.go +++ b/package/gitea/source/services/issue/issue.go @@ -7,24 +7,23 @@ import ( "context" "fmt" - activities_model "code.gitea.io/gitea/models/activities" - "code.gitea.io/gitea/models/db" - issues_model "code.gitea.io/gitea/models/issues" - access_model "code.gitea.io/gitea/models/perm/access" - project_model "code.gitea.io/gitea/models/project" - repo_model "code.gitea.io/gitea/models/repo" - system_model "code.gitea.io/gitea/models/system" - 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/gitrepo" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/storage" - notify_service "code.gitea.io/gitea/services/notify" + activities_model "gitea.dev/models/activities" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + access_model "gitea.dev/models/perm/access" + project_model "gitea.dev/models/project" + repo_model "gitea.dev/models/repo" + system_model "gitea.dev/models/system" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/log" + "gitea.dev/modules/storage" + notify_service "gitea.dev/services/notify" ) // NewIssue creates new issue with labels for repository. -func NewIssue(ctx context.Context, repo *repo_model.Repository, issue *issues_model.Issue, labelIDs []int64, uuids []string, assigneeIDs []int64, projectID int64) error { +func NewIssue(ctx context.Context, repo *repo_model.Repository, issue *issues_model.Issue, labelIDs []int64, uuids []string, assigneeIDs, projectIDs []int64) error { if err := issue.LoadPoster(ctx); err != nil { return err } @@ -33,17 +32,28 @@ func NewIssue(ctx context.Context, repo *repo_model.Repository, issue *issues_mo return user_model.ErrBlockedUser } + assigneeCommentMap := make(map[int64]*issues_model.Comment) + assignees := make(map[int64]*user_model.User) if err := db.WithTx(ctx, func(ctx context.Context) error { if err := issues_model.NewIssue(ctx, repo, issue, labelIDs, uuids); err != nil { return err } for _, assigneeID := range assigneeIDs { - if _, err := AddAssigneeIfNotAssigned(ctx, issue, issue.Poster, assigneeID, true); err != nil { + assignee, err := user_model.GetUserByID(ctx, assigneeID) + if err != nil { + log.Error("GetUserByID: %v", err) + continue + } + assignees[assigneeID] = assignee + comment, err := AddAssigneeIfNotAssigned(ctx, issue, issue.Poster, assignee) + if err != nil { return err } + assigneeCommentMap[assigneeID] = comment } - if projectID > 0 { - if err := issues_model.IssueAssignOrRemoveProject(ctx, issue, issue.Poster, projectID, 0); err != nil { + if len(projectIDs) > 0 { + err := issues_model.IssueAssignOrRemoveProject(ctx, issue, issue.Poster, projectIDs) + if err != nil { return err } } @@ -65,6 +75,12 @@ func NewIssue(ctx context.Context, repo *repo_model.Repository, issue *issues_mo notify_service.IssueChangeMilestone(ctx, issue.Poster, issue, 0) } + if len(assigneeIDs) > 0 { + for _, assignee := range assignees { + notify_service.IssueChangeAssignee(ctx, issue.Poster, issue, assignee, false, assigneeCommentMap[assignee.ID]) + } + } + return nil } @@ -131,55 +147,6 @@ func ChangeIssueRef(ctx context.Context, issue *issues_model.Issue, doer *user_m return nil } -// UpdateAssignees is a helper function to add or delete one or multiple issue assignee(s) -// Deleting is done the GitHub way (quote from their api documentation): -// https://developer.github.com/v3/issues/#edit-an-issue -// "assignees" (array): Logins for Users to assign to this issue. -// Pass one or more user logins to replace the set of assignees on this Issue. -// Send an empty array ([]) to clear all assignees from the Issue. -func UpdateAssignees(ctx context.Context, issue *issues_model.Issue, oneAssignee string, multipleAssignees []string, doer *user_model.User) (err error) { - uniqueAssignees := container.SetOf(multipleAssignees...) - - // Keep the old assignee thingy for compatibility reasons - if oneAssignee != "" { - uniqueAssignees.Add(oneAssignee) - } - - // Loop through all assignees to add them - allNewAssignees := make([]*user_model.User, 0, len(uniqueAssignees)) - for _, assigneeName := range uniqueAssignees.Values() { - assignee, err := user_model.GetUserByName(ctx, assigneeName) - if err != nil { - return err - } - - if user_model.IsUserBlockedBy(ctx, doer, assignee.ID) { - return user_model.ErrBlockedUser - } - - allNewAssignees = append(allNewAssignees, assignee) - } - - // Delete all old assignees not passed - if err = DeleteNotPassedAssignee(ctx, issue, doer, allNewAssignees); err != nil { - return err - } - - // Add all new assignees - // Update the assignee. The function will check if the user exists, is already - // assigned (which he shouldn't as we deleted all assignees before) and - // has access to the repo. - for _, assignee := range allNewAssignees { - // Extra method to prevent double adding (which would result in removing) - _, err = AddAssigneeIfNotAssigned(ctx, issue, doer, assignee.ID, true) - if err != nil { - return err - } - } - - return err -} - // DeleteIssue deletes an issue func DeleteIssue(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) error { // load issue before deleting it @@ -214,40 +181,6 @@ func DeleteIssue(ctx context.Context, doer *user_model.User, issue *issues_model return nil } -// AddAssigneeIfNotAssigned adds an assignee only if he isn't already assigned to the issue. -// Also checks for access of assigned user -func AddAssigneeIfNotAssigned(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, assigneeID int64, notify bool) (comment *issues_model.Comment, err error) { - assignee, err := user_model.GetUserByID(ctx, assigneeID) - if err != nil { - return nil, err - } - - // Check if the user is already assigned - isAssigned, err := issues_model.IsUserAssignedToIssue(ctx, issue, assignee) - if err != nil { - return nil, err - } - if isAssigned { - // nothing to do - return nil, nil //nolint:nilnil // return nil because the user is already assigned - } - - valid, err := access_model.CanBeAssigned(ctx, assignee, issue.Repo, issue.IsPull) - if err != nil { - return nil, err - } - if !valid { - return nil, repo_model.ErrUserDoesNotHaveAccessToRepo{UserID: assigneeID, RepoName: issue.Repo.Name} - } - - if notify { - _, comment, err = ToggleAssigneeWithNotify(ctx, issue, doer, assigneeID) - return comment, err - } - _, comment, err = issues_model.ToggleIssueAssignee(ctx, issue, doer, assigneeID) - return comment, err -} - // GetRefEndNamesAndURLs retrieves the ref end names (e.g. refs/heads/branch-name -> branch-name) // and their respective URLs. func GetRefEndNamesAndURLs(issues []*issues_model.Issue, repoLink string) (map[int64]string, map[int64]string) { diff --git a/package/gitea/source/services/issue/issue_test.go b/package/gitea/source/services/issue/issue_test.go index 61ed13ed..e8fae5a1 100644 --- a/package/gitea/source/services/issue/issue_test.go +++ b/package/gitea/source/services/issue/issue_test.go @@ -6,10 +6,10 @@ package issue import ( "testing" - 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" + issues_model "gitea.dev/models/issues" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/issue/label.go b/package/gitea/source/services/issue/label.go index 93a3c258..2e788553 100644 --- a/package/gitea/source/services/issue/label.go +++ b/package/gitea/source/services/issue/label.go @@ -6,11 +6,11 @@ package issue import ( "context" - "code.gitea.io/gitea/models/db" - issues_model "code.gitea.io/gitea/models/issues" - access_model "code.gitea.io/gitea/models/perm/access" - user_model "code.gitea.io/gitea/models/user" - notify_service "code.gitea.io/gitea/services/notify" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + access_model "gitea.dev/models/perm/access" + user_model "gitea.dev/models/user" + notify_service "gitea.dev/services/notify" ) // ClearLabels clears all of an issue's labels diff --git a/package/gitea/source/services/issue/label_test.go b/package/gitea/source/services/issue/label_test.go index 093b16b5..04079c85 100644 --- a/package/gitea/source/services/issue/label_test.go +++ b/package/gitea/source/services/issue/label_test.go @@ -6,9 +6,9 @@ package issue import ( "testing" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" + issues_model "gitea.dev/models/issues" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/issue/main_test.go b/package/gitea/source/services/issue/main_test.go index 819c5d98..7c126d19 100644 --- a/package/gitea/source/services/issue/main_test.go +++ b/package/gitea/source/services/issue/main_test.go @@ -6,10 +6,10 @@ package issue import ( "testing" - "code.gitea.io/gitea/models/unittest" + "gitea.dev/models/unittest" - _ "code.gitea.io/gitea/models" - _ "code.gitea.io/gitea/models/actions" + _ "gitea.dev/models" + _ "gitea.dev/models/actions" ) func TestMain(m *testing.M) { diff --git a/package/gitea/source/services/issue/milestone.go b/package/gitea/source/services/issue/milestone.go index 05aefad7..d229a9e1 100644 --- a/package/gitea/source/services/issue/milestone.go +++ b/package/gitea/source/services/issue/milestone.go @@ -8,10 +8,10 @@ import ( "errors" "fmt" - "code.gitea.io/gitea/models/db" - issues_model "code.gitea.io/gitea/models/issues" - user_model "code.gitea.io/gitea/models/user" - notify_service "code.gitea.io/gitea/services/notify" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + user_model "gitea.dev/models/user" + notify_service "gitea.dev/services/notify" ) func changeMilestoneAssign(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) error { diff --git a/package/gitea/source/services/issue/milestone_test.go b/package/gitea/source/services/issue/milestone_test.go index 2ef482e2..e2946471 100644 --- a/package/gitea/source/services/issue/milestone_test.go +++ b/package/gitea/source/services/issue/milestone_test.go @@ -6,9 +6,9 @@ package issue import ( "testing" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" + issues_model "gitea.dev/models/issues" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/issue/pull.go b/package/gitea/source/services/issue/pull.go index f415ebe7..260ac5ce 100644 --- a/package/gitea/source/services/issue/pull.go +++ b/package/gitea/source/services/issue/pull.go @@ -7,14 +7,15 @@ import ( "context" "fmt" "slices" + "time" - issues_model "code.gitea.io/gitea/models/issues" - org_model "code.gitea.io/gitea/models/organization" - 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" - "code.gitea.io/gitea/modules/setting" + issues_model "gitea.dev/models/issues" + org_model "gitea.dev/models/organization" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" ) type ReviewRequestNotifier struct { @@ -26,6 +27,10 @@ type ReviewRequestNotifier struct { var codeOwnerFiles = []string{"CODEOWNERS", "docs/CODEOWNERS", ".gitea/CODEOWNERS"} +// codeOwnerMatchBudget caps the total wall-clock time spent evaluating all +// CODEOWNERS rules against all changed files for a single PR. +const codeOwnerMatchBudget = 2 * time.Second + func IsCodeOwnerFile(f string) bool { return slices.Contains(codeOwnerFiles, f) } @@ -93,8 +98,17 @@ func PullRequestCodeOwnersReview(ctx context.Context, pr *issues_model.PullReque uniqUsers := make(map[int64]*user_model.User) uniqTeams := make(map[string]*org_model.Team) + // Bound the total time spent matching rules×files. The per-rule MatchTimeout + // only caps a single match; without an aggregate budget a crafted CODEOWNERS + // plus a PR touching many files could still exhaust CPU inside this loop. + matchDeadline := time.Now().Add(codeOwnerMatchBudget) +ruleLoop: for _, rule := range rules { for _, f := range changedFiles { + if time.Now().After(matchDeadline) { + log.Warn("CODEOWNERS matching for PR %s#%d exceeded its time budget; some rules were not evaluated", pr.BaseRepo.FullName(), pr.ID) + break ruleLoop + } shouldMatch := !rule.Negative matched, _ := rule.Rule.MatchString(f) // err only happens when timeouts, any error can be considered as not matched if matched == shouldMatch { @@ -133,7 +147,7 @@ func PullRequestCodeOwnersReview(ctx context.Context, pr *issues_model.PullReque if u.ID != issue.Poster.ID && !contain(latestReviews, u) { comment, err := issues_model.AddReviewRequest(ctx, issue, u, issue.Poster, true) if err != nil { - log.Warn("Failed add assignee user: %s to PR review: %s#%d, error: %s", u.Name, pr.BaseRepo.Name, pr.ID, err) + log.Warn("Failed add review user: %s to PR review: %s#%d, error: %s", u.Name, pr.BaseRepo.Name, pr.ID, err) return nil, err } if comment == nil { // comment maybe nil if review type is ReviewTypeRequest @@ -150,7 +164,7 @@ func PullRequestCodeOwnersReview(ctx context.Context, pr *issues_model.PullReque for _, t := range uniqTeams { comment, err := issues_model.AddTeamReviewRequest(ctx, issue, t, issue.Poster, true) if err != nil { - log.Warn("Failed add assignee team: %s to PR review: %s#%d, error: %s", t.Name, pr.BaseRepo.Name, pr.ID, err) + log.Warn("Failed add reviewer team: %s to PR review: %s#%d, error: %s", t.Name, pr.BaseRepo.Name, pr.ID, err) return nil, err } if comment == nil { // comment maybe nil if review type is ReviewTypeRequest diff --git a/package/gitea/source/services/issue/reaction.go b/package/gitea/source/services/issue/reaction.go index deb99169..e06d8116 100644 --- a/package/gitea/source/services/issue/reaction.go +++ b/package/gitea/source/services/issue/reaction.go @@ -6,8 +6,8 @@ package issue import ( "context" - issues_model "code.gitea.io/gitea/models/issues" - user_model "code.gitea.io/gitea/models/user" + issues_model "gitea.dev/models/issues" + user_model "gitea.dev/models/user" ) // CreateIssueReaction creates a reaction on an issue. diff --git a/package/gitea/source/services/issue/reaction_test.go b/package/gitea/source/services/issue/reaction_test.go index bf2e554d..62bb9e69 100644 --- a/package/gitea/source/services/issue/reaction_test.go +++ b/package/gitea/source/services/issue/reaction_test.go @@ -6,11 +6,11 @@ package issue import ( "testing" - 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/setting" + issues_model "gitea.dev/models/issues" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/modules/setting" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/issue/review_request.go b/package/gitea/source/services/issue/review_request.go new file mode 100644 index 00000000..d2826f85 --- /dev/null +++ b/package/gitea/source/services/issue/review_request.go @@ -0,0 +1,283 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package issue + +import ( + "context" + + issues_model "gitea.dev/models/issues" + "gitea.dev/models/organization" + "gitea.dev/models/perm" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unit" + user_model "gitea.dev/models/user" + "gitea.dev/modules/log" + notify_service "gitea.dev/services/notify" +) + +// ReviewRequest add or remove a review request from a user for this PR, and make comment for it. +func ReviewRequest(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, permDoer *access_model.Permission, reviewer *user_model.User, isAdd bool) (comment *issues_model.Comment, err error) { + err = isValidReviewRequest(ctx, reviewer, doer, isAdd, issue, permDoer) + if err != nil { + return nil, err + } + + if isAdd { + comment, err = issues_model.AddReviewRequest(ctx, issue, reviewer, doer, false) + } else { + comment, err = issues_model.RemoveReviewRequest(ctx, issue, reviewer, doer) + } + + if err != nil { + return nil, err + } + + if comment != nil { + notify_service.PullRequestReviewRequest(ctx, doer, issue, reviewer, isAdd, comment) + } + + return comment, err +} + +// isValidReviewRequest Check permission for ReviewRequest +func isValidReviewRequest(ctx context.Context, reviewer, doer *user_model.User, isAdd bool, issue *issues_model.Issue, permDoer *access_model.Permission) error { + if reviewer.IsOrganization() { + return issues_model.ErrNotValidReviewRequest{ + Reason: "Organization can't be added as reviewer", + UserID: doer.ID, + RepoID: issue.Repo.ID, + } + } + if doer.IsOrganization() { + return issues_model.ErrNotValidReviewRequest{ + Reason: "Organization can't be doer to add reviewer", + UserID: doer.ID, + RepoID: issue.Repo.ID, + } + } + + permReviewer, err := access_model.GetIndividualUserRepoPermission(ctx, issue.Repo, reviewer) + if err != nil { + return err + } + + if permDoer == nil { + permDoer = new(access_model.Permission) + *permDoer, err = access_model.GetDoerRepoPermission(ctx, issue.Repo, doer) + if err != nil { + return err + } + } + + lastReview, err := issues_model.GetReviewByIssueIDAndUserID(ctx, issue.ID, reviewer.ID) + if err != nil && !issues_model.IsErrReviewNotExist(err) { + return err + } + + canDoerChangeReviewRequests := CanDoerChangeReviewRequests(ctx, doer, issue.Repo, issue.PosterID) + + if isAdd { + if !permReviewer.CanAccessAny(perm.AccessModeRead, unit.TypePullRequests) { + return issues_model.ErrNotValidReviewRequest{ + Reason: "Reviewer can't read", + UserID: doer.ID, + RepoID: issue.Repo.ID, + } + } + + if reviewer.ID == issue.PosterID && issue.OriginalAuthorID == 0 { + return issues_model.ErrNotValidReviewRequest{ + Reason: "poster of pr can't be reviewer", + UserID: doer.ID, + RepoID: issue.Repo.ID, + } + } + + if canDoerChangeReviewRequests { + return nil + } + + if doer.ID == issue.PosterID && issue.OriginalAuthorID == 0 && lastReview != nil && lastReview.Type != issues_model.ReviewTypeRequest { + return nil + } + + return issues_model.ErrNotValidReviewRequest{ + Reason: "Doer can't choose reviewer", + UserID: doer.ID, + RepoID: issue.Repo.ID, + } + } + + if canDoerChangeReviewRequests { + return nil + } + + if lastReview != nil && lastReview.Type == issues_model.ReviewTypeRequest && lastReview.ReviewerID == doer.ID { + return nil + } + + return issues_model.ErrNotValidReviewRequest{ + Reason: "Doer can't remove reviewer", + UserID: doer.ID, + RepoID: issue.Repo.ID, + } +} + +// isValidTeamReviewRequest Check permission for ReviewRequest Team +func isValidTeamReviewRequest(ctx context.Context, reviewer *organization.Team, doer *user_model.User, isAdd bool, issue *issues_model.Issue) error { + if doer.IsOrganization() { + return issues_model.ErrNotValidReviewRequest{ + Reason: "Organization can't be doer to add reviewer", + UserID: doer.ID, + RepoID: issue.Repo.ID, + } + } + + canDoerChangeReviewRequests := CanDoerChangeReviewRequests(ctx, doer, issue.Repo, issue.PosterID) + + if isAdd { + if issue.Repo.IsPrivate { + hasTeam := organization.HasTeamRepo(ctx, reviewer.OrgID, reviewer.ID, issue.RepoID) + + if !hasTeam { + return issues_model.ErrNotValidReviewRequest{ + Reason: "Reviewing team can't read repo", + UserID: doer.ID, + RepoID: issue.Repo.ID, + } + } + } + + if canDoerChangeReviewRequests { + return nil + } + + return issues_model.ErrNotValidReviewRequest{ + Reason: "Doer can't choose reviewer", + UserID: doer.ID, + RepoID: issue.Repo.ID, + } + } + + if canDoerChangeReviewRequests { + return nil + } + + return issues_model.ErrNotValidReviewRequest{ + Reason: "Doer can't remove reviewer", + UserID: doer.ID, + RepoID: issue.Repo.ID, + } +} + +// TeamReviewRequest add or remove a review request from a team for this PR, and make comment for it. +func TeamReviewRequest(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, reviewer *organization.Team, isAdd bool) (comment *issues_model.Comment, err error) { + err = isValidTeamReviewRequest(ctx, reviewer, doer, isAdd, issue) + if err != nil { + return nil, err + } + if isAdd { + comment, err = issues_model.AddTeamReviewRequest(ctx, issue, reviewer, doer, false) + } else { + comment, err = issues_model.RemoveTeamReviewRequest(ctx, issue, reviewer, doer) + } + + if err != nil { + return nil, err + } + + if comment == nil || !isAdd { + return nil, nil //nolint:nilnil // return nil because no comment was created or it is a removal + } + + return comment, teamReviewRequestNotify(ctx, issue, doer, reviewer, isAdd, comment) +} + +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) + } + } + } +} + +// teamReviewRequestNotify notify all user in this team +func teamReviewRequestNotify(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, reviewer *organization.Team, isAdd bool, comment *issues_model.Comment) error { + // notify all user in this team + if err := comment.LoadIssue(ctx); err != nil { + return err + } + + members, err := organization.GetTeamMembers(ctx, &organization.SearchMembersOptions{ + TeamID: reviewer.ID, + }) + if err != nil { + return err + } + + for _, member := range members { + if member.ID == comment.Issue.PosterID { + continue + } + comment.AssigneeID = member.ID + notify_service.PullRequestReviewRequest(ctx, doer, issue, member, isAdd, comment) + } + + return err +} + +// CanDoerChangeReviewRequests returns if the doer can add/remove review requests of a PR +func CanDoerChangeReviewRequests(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, posterID int64) bool { + if repo.IsArchived { + return false + } + // The poster of the PR can change the reviewers + if doer.ID == posterID { + return true + } + + // The owner of the repo can change the reviewers + if doer.ID == repo.OwnerID { + return true + } + + // Collaborators of the repo can change the reviewers + isCollaborator, err := repo_model.IsCollaborator(ctx, repo.ID, doer.ID) + if err != nil { + log.Error("IsCollaborator: %v", err) + return false + } + if isCollaborator { + return true + } + + // If the repo's owner is an organization, members of teams with read permission on pull requests can change reviewers + if repo.Owner.IsOrganization() { + teams, err := organization.GetTeamsWithAccessToAnyRepoUnit(ctx, repo.OwnerID, repo.ID, perm.AccessModeRead, unit.TypePullRequests) + if err != nil { + log.Error("GetTeamsWithAccessToRepo: %v", err) + return false + } + for _, team := range teams { + if !team.UnitEnabled(ctx, unit.TypePullRequests) { + continue + } + isMember, err := organization.IsTeamMember(ctx, repo.OwnerID, team.ID, doer.ID) + if err != nil { + log.Error("IsTeamMember: %v", err) + continue + } + if isMember { + return true + } + } + } + + return false +} diff --git a/package/gitea/source/services/issue/status.go b/package/gitea/source/services/issue/status.go index fa59df93..8ce44d5c 100644 --- a/package/gitea/source/services/issue/status.go +++ b/package/gitea/source/services/issue/status.go @@ -6,11 +6,11 @@ package issue import ( "context" - "code.gitea.io/gitea/models/db" - 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" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + user_model "gitea.dev/models/user" + "gitea.dev/modules/log" + notify_service "gitea.dev/services/notify" ) // CloseIssue close an issue. diff --git a/package/gitea/source/services/issue/suggestion.go b/package/gitea/source/services/issue/suggestion.go index 22eddb19..58c0e9ae 100644 --- a/package/gitea/source/services/issue/suggestion.go +++ b/package/gitea/source/services/issue/suggestion.go @@ -7,10 +7,10 @@ import ( "context" "strconv" - issues_model "code.gitea.io/gitea/models/issues" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/optional" - "code.gitea.io/gitea/modules/structs" + issues_model "gitea.dev/models/issues" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/optional" + "gitea.dev/modules/structs" ) func GetSuggestion(ctx context.Context, repo *repo_model.Repository, isPull optional.Option[bool], keyword string) ([]*structs.Issue, error) { diff --git a/package/gitea/source/services/issue/suggestion_test.go b/package/gitea/source/services/issue/suggestion_test.go index 9b23e5ac..a6ce0bc8 100644 --- a/package/gitea/source/services/issue/suggestion_test.go +++ b/package/gitea/source/services/issue/suggestion_test.go @@ -6,9 +6,9 @@ package issue import ( "testing" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/optional" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + "gitea.dev/modules/optional" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/issue/template.go b/package/gitea/source/services/issue/template.go index 99977c67..c1a0ff2f 100644 --- a/package/gitea/source/services/issue/template.go +++ b/package/gitea/source/services/issue/template.go @@ -9,14 +9,14 @@ import ( "path" "strings" - "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/issue/template" - "code.gitea.io/gitea/modules/log" - api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" + "gitea.dev/models/repo" + "gitea.dev/modules/git" + "gitea.dev/modules/issue/template" + "gitea.dev/modules/log" + api "gitea.dev/modules/structs" + "gitea.dev/modules/util" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v4" ) // templateDirCandidates issue templates directory diff --git a/package/gitea/source/services/lfs/locks.go b/package/gitea/source/services/lfs/locks.go index c2279eda..fe3f4bdb 100644 --- a/package/gitea/source/services/lfs/locks.go +++ b/package/gitea/source/services/lfs/locks.go @@ -8,16 +8,16 @@ import ( "strconv" "strings" - 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/modules/json" - lfs_module "code.gitea.io/gitea/modules/lfs" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/services/context" - "code.gitea.io/gitea/services/convert" + auth_model "gitea.dev/models/auth" + git_model "gitea.dev/models/git" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/json" + lfs_module "gitea.dev/modules/lfs" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" + api "gitea.dev/modules/structs" + "gitea.dev/services/context" + "gitea.dev/services/convert" ) func handleLockListOut(ctx *context.Context, repo *repo_model.Repository, lock *git_model.LFSLock, err error) { diff --git a/package/gitea/source/services/lfs/server.go b/package/gitea/source/services/lfs/server.go index 26eb4878..3661dbde 100644 --- a/package/gitea/source/services/lfs/server.go +++ b/package/gitea/source/services/lfs/server.go @@ -18,22 +18,22 @@ import ( "strings" "time" - auth_model "code.gitea.io/gitea/models/auth" - git_model "code.gitea.io/gitea/models/git" - perm_model "code.gitea.io/gitea/models/perm" - access_model "code.gitea.io/gitea/models/perm/access" - 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/auth/httpauth" - "code.gitea.io/gitea/modules/httplib" - "code.gitea.io/gitea/modules/json" - lfs_module "code.gitea.io/gitea/modules/lfs" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/storage" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/services/context" + auth_model "gitea.dev/models/auth" + git_model "gitea.dev/models/git" + perm_model "gitea.dev/models/perm" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unit" + user_model "gitea.dev/models/user" + "gitea.dev/modules/auth/httpauth" + "gitea.dev/modules/httplib" + "gitea.dev/modules/json" + lfs_module "gitea.dev/modules/lfs" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" + "gitea.dev/modules/storage" + "gitea.dev/modules/util" + "gitea.dev/services/context" "github.com/golang-jwt/jwt/v5" ) @@ -254,6 +254,17 @@ func BatchHandler(ctx *context.Context) { var responseObject *lfs_module.ObjectResponse if isUpload { + if exists && meta == nil { + // The object exists in the content store but is not linked to this + // repo. Do not auto-link it based on cross-repo access: the token + // only authorizes this repo, and for deploy keys ctx.Doer is the + // repo owner, so trusting it here would let a single-repo key pull + // objects from any repo the owner can see. Require proof of + // possession by making the client upload the (hash-verified) bytes, + // and treat it as a new upload for size-limit enforcement below. + exists = false + } + var err *lfs_module.ObjectError if !exists && setting.LFS.MaxFileSize > 0 && p.Size > setting.LFS.MaxFileSize { err = &lfs_module.ObjectError{ @@ -262,25 +273,6 @@ func BatchHandler(ctx *context.Context) { } } - if exists && meta == nil { - accessible, err := git_model.LFSObjectAccessible(ctx, ctx.Doer, p.Oid) - if err != nil { - log.Error("Unable to check if LFS MetaObject [%s] is accessible. Error: %v", p.Oid, err) - writeStatus(ctx, http.StatusInternalServerError) - return - } - if accessible { - _, err := git_model.NewLFSMetaObject(ctx, repository.ID, p) - if err != nil { - log.Error("Unable to create LFS MetaObject [%s] for %s/%s. Error: %v", p.Oid, rc.User, rc.Repo, err) - writeStatus(ctx, http.StatusInternalServerError) - return - } - } else { - exists = false - } - } - responseObject = buildObjectResponse(rc, p, false, !exists, err) } else { var err *lfs_module.ObjectError @@ -337,13 +329,17 @@ func UploadHandler(ctx *context.Context) { uploadOrVerify := func() error { if exists { - accessible, err := git_model.LFSObjectAccessible(ctx, ctx.Doer, p.Oid) - if err != nil { - log.Error("Unable to check if LFS MetaObject [%s] is accessible. Error: %v", p.Oid, err) + // The bytes already exist in the content store. Only skip proof of + // possession when the object is already linked to *this* repo; never + // trust cross-repo access (ctx.Doer is the repo owner for deploy keys), + // which would let a caller link an object it cannot produce. + meta, err := git_model.GetLFSMetaObjectByOid(ctx, repository.ID, p.Oid) + if err != nil && err != git_model.ErrLFSObjectNotExist { + log.Error("Unable to get LFS MetaObject [%s]. Error: %v", p.Oid, err) return err } - if !accessible { - // The file exists but the user has no access to it. + if meta == nil { + // The file exists but is not linked to this repo. // The upload gets verified by hashing and size comparison to prove access to it. hash := sha256.New() written, err := io.Copy(hash, ctx.Req.Body) @@ -376,9 +372,6 @@ func UploadHandler(ctx *context.Context) { log.Error("Error whilst uploadOrVerify LFS OID[%s]: %v", p.Oid, err) writeStatus(ctx, http.StatusInternalServerError) } - if _, err = git_model.RemoveLFSMetaObjectByOid(ctx, repository.ID, p.Oid); err != nil { - log.Error("Error whilst removing MetaObject for LFS OID[%s]: %v", p.Oid, err) - } return } diff --git a/package/gitea/source/services/lfs/server_test.go b/package/gitea/source/services/lfs/server_test.go index d8e5a925..f7312d2a 100644 --- a/package/gitea/source/services/lfs/server_test.go +++ b/package/gitea/source/services/lfs/server_test.go @@ -7,12 +7,12 @@ import ( "strings" "testing" - "code.gitea.io/gitea/models/db" - perm_model "code.gitea.io/gitea/models/perm" - 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/services/contexttest" + "gitea.dev/models/db" + perm_model "gitea.dev/models/perm" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/services/contexttest" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/package/gitea/source/services/mailer/incoming/incoming.go b/package/gitea/source/services/mailer/incoming/incoming.go index d08afac0..eab7ad6c 100644 --- a/package/gitea/source/services/mailer/incoming/incoming.go +++ b/package/gitea/source/services/mailer/incoming/incoming.go @@ -12,12 +12,11 @@ import ( "strings" "time" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/process" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/services/mailer/token" + "gitea.dev/modules/log" + "gitea.dev/modules/process" + "gitea.dev/modules/setting" + "gitea.dev/services/mailer/token" - "github.com/dimiro1/reply" "github.com/emersion/go-imap" "github.com/emersion/go-imap/client" "github.com/jhillyerd/enmime/v2" @@ -356,7 +355,7 @@ func getContentFromMailReader(env *enmime.Envelope) *MailContent { } return &MailContent{ - Content: reply.FromText(env.Text), + Content: extractReply(env.Text), Attachments: attachments, } } diff --git a/package/gitea/source/services/mailer/incoming/incoming_handler.go b/package/gitea/source/services/mailer/incoming/incoming_handler.go index 3c350e3d..29999856 100644 --- a/package/gitea/source/services/mailer/incoming/incoming_handler.go +++ b/package/gitea/source/services/mailer/incoming/incoming_handler.go @@ -9,19 +9,19 @@ import ( "errors" "fmt" - 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/log" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" - attachment_service "code.gitea.io/gitea/services/attachment" - "code.gitea.io/gitea/services/context/upload" - issue_service "code.gitea.io/gitea/services/issue" - incoming_payload "code.gitea.io/gitea/services/mailer/incoming/payload" - "code.gitea.io/gitea/services/mailer/token" - pull_service "code.gitea.io/gitea/services/pull" + issues_model "gitea.dev/models/issues" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" + "gitea.dev/modules/util" + attachment_service "gitea.dev/services/attachment" + "gitea.dev/services/context/upload" + issue_service "gitea.dev/services/issue" + incoming_payload "gitea.dev/services/mailer/incoming/payload" + "gitea.dev/services/mailer/token" + pull_service "gitea.dev/services/pull" ) type MailHandler interface { diff --git a/package/gitea/source/services/mailer/incoming/incoming_test.go b/package/gitea/source/services/mailer/incoming/incoming_test.go index 11db5160..9588c902 100644 --- a/package/gitea/source/services/mailer/incoming/incoming_test.go +++ b/package/gitea/source/services/mailer/incoming/incoming_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "code.gitea.io/gitea/modules/setting" + "gitea.dev/modules/setting" "github.com/jhillyerd/enmime/v2" "github.com/stretchr/testify/assert" @@ -150,3 +150,56 @@ func TestGetContentFromMailReader(t *testing.T) { assert.Equal(t, "mail content without signature", content.Content) assert.Empty(t, content.Attachments) } + +func TestExtractReply(t *testing.T) { + cases := []struct { + name string + input string + expected string + }{ + {"plain text", "Email with only text.", "Email with only text."}, + {"crlf normalized", "line one\r\nline two\r\n", "line one\nline two"}, + {"trim blank lines", "\n\n\nactual reply\n\n\n", "actual reply"}, + {"signature delimiter", "the reply\n--\nJohn Doe\nAcme", "the reply"}, + {"rfc signature delimiter", "the reply\n-- \nJohn Doe", "the reply"}, + {"mobile signature", "My answer is yes.\n\nSent from my iPhone", "My answer is yes."}, + {"quote only kept", "> Email with only quote.", "> Email with only quote."}, + {"leading quote kept", "> This is a quote.\n\nAnd this is some text.", "> This is a quote.\n\nAnd this is some text."}, + {"trailing quote stripped", "My reply.\n\n> original line 1\n> original line 2", "My reply."}, + {"attribution and quote", "Looks good.\n\nOn Mon, Jan 1, 2024 John wrote:\n> please review", "Looks good."}, + {"attribution without quote marks", "My reply.\n\nOn Wed, Sep 25, 2013, richard wrote:\noriginal text", "My reply."}, + {"original message separator", "Foo\n\n-------- Original Message --------\n\nTHE END.", "Foo"}, + {"outlook header block", "This is the actual reply.\n\nFrom: Some One \nSent: Monday\nTo: Someone\nSubject: hi\n\nquoted body", "This is the actual reply."}, + {"french attribution", "C'est super !\n\nLe 4 janv. 2016 19:03, \"Neil\" a écrit :\n> quoted", "C'est super !"}, + {"german attribution", "Hey :)\n\nAm 03.02.2016 3:35 schrieb Max :\n> quoted", "Hey :)"}, + {"cyrillic wrote verb", "Yes.\n\n6 октября 2014 lidel написал:\n> quoted", "Yes."}, + {"localized signature", "My answer.\n\nEnvoyé depuis mon iPhone", "My answer."}, + {"swedish header block", "Hi everyone!\n\nFrån: Foo \nSkickat: den 5 juni\nTill: x@y.com\nÄmne: hi\n\nbody", "Hi everyone!"}, + {"attribution only is empty", "On Mon, Jan 1, 2024 at 10:00 John wrote:\n> please review", ""}, + {"prose ending in wrote kept", "Hi Bob,\nThanks for the report you wrote\nI'll fix it.", "Hi Bob,\nThanks for the report you wrote\nI'll fix it."}, + {"on with year and no time kept", "Hi,\nOn the 2024 roadmap we have three items.\nPlease review.", "Hi,\nOn the 2024 roadmap we have three items.\nPlease review."}, + {"date prose kept", "Notes:\n5 issues 2024 fixed at 9:15 today\nmore notes", "Notes:\n5 issues 2024 fixed at 9:15 today\nmore notes"}, + {"header needs from first", "Quick note:\nTo: which server?\nFrom: tests pass.\nThanks", "Quick note:\nTo: which server?\nFrom: tests pass.\nThanks"}, + {"indented header block", "Reply text.\n\n From: A \n Sent: Monday\n To: x\n Subject: hi\n\nbody", "Reply text."}, + {"chinese signature", "回复内容\n\n發自我的iPhone", "回复内容"}, + {"japanese signature", "返信します\n\niPhoneから送信", "返信します"}, + {"chinese header block", "回复内容\n\n发件人:张三\n收件人:李四\n主题:你好\n\n原文", "回复内容"}, + {"japanese header block", "本文です\n\n差出人:山田\n宛先:田中\n件名:こんにちは\n\n原文", "本文です"}, + {"name-first attribution", "Okay.\n\nErlend schrieb am Di., 16. Aug. 2016\num 12:52 Uhr:\n> quoted", "Okay."}, + {"chinese attribution", "你好,谢谢回复。\n\n在 2024年1月1日,张三 写道:\n> 原始内容", "你好,谢谢回复。"}, + {"japanese attribution", "了解しました。\n\n田中さんは書きました:\n> 引用", "了解しました。"}, + {"korean attribution", "감사합니다.\n\n홍길동님이 작성:\n> 인용", "감사합니다."}, + {"email mention kept", "I asked Bob and he wrote back yes.\nSo we proceed.", "I asked Bob and he wrote back yes.\nSo we proceed."}, + {"trailing mailbox glyph", "My reply here.\n\nᐧ", "My reply here."}, + {"on with year and time prose kept", "On the 2024 roadmap we should meet at 10:00.\nI'll send invites.", "On the 2024 roadmap we should meet at 10:00.\nI'll send invites."}, + {"spanish year and time prose kept", "El informe del 2024 estará listo a las 10:00.\nGracias.", "El informe del 2024 estará listo a las 10:00.\nGracias."}, + {"chinese prose kept", "谢谢,已测试。\n发自我的内心的感谢", "谢谢,已测试。\n发自我的内心的感谢"}, + {"korean prose kept", "확인했습니다.\n이 문서는 회사에서 보냄", "확인했습니다.\n이 문서는 회사에서 보냄"}, + {"japanese prose kept", "了解しました。\n資料は会議から送信", "了解しました。\n資料は会議から送信"}, + } + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + assert.Equal(t, c.expected, extractReply(c.input)) + }) + } +} diff --git a/package/gitea/source/services/mailer/incoming/payload/payload.go b/package/gitea/source/services/mailer/incoming/payload/payload.go index 00ada782..01f7bd17 100644 --- a/package/gitea/source/services/mailer/incoming/payload/payload.go +++ b/package/gitea/source/services/mailer/incoming/payload/payload.go @@ -6,8 +6,8 @@ package payload import ( "context" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/modules/util" + issues_model "gitea.dev/models/issues" + "gitea.dev/modules/util" ) const replyPayloadVersion1 byte = 1 diff --git a/package/gitea/source/services/mailer/incoming/reply.go b/package/gitea/source/services/mailer/incoming/reply.go new file mode 100644 index 00000000..3f27909c --- /dev/null +++ b/package/gitea/source/services/mailer/incoming/reply.go @@ -0,0 +1,137 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package incoming + +import ( + "regexp" + "strings" + "sync" + + "gitea.dev/modules/util" +) + +const ( + yearToken = `\b\d{4}\b` // 4-digit year + timeToken = `\b\d{1,2}[:.]\d{2}\b` // HH:MM or HH.MM + // "wrote" verbs ending an attribution line; CJK ones are matched without a + // preceding word-separator since those scripts don't space their words + wroteVerbs = `wrote|writes|schrieb|skrev|napisał|escreveu|escribió|написал|пише|a écrit` + cjkWroteVerbs = `写道|寫道|書きました|작성` + // device names anchoring CJK mobile signatures, so prose isn't mistaken for one + cjkDevice = `iphone|ipad|ipod|android|galaxy|手机|手機|平板` +) + +// forwarded-mail header fields across the common mail clients/locales. headerFromFields +// (the "From"-equivalents) must begin a block; headerFields is the full set allowed to +// follow. Matched as a prefix by headerLine, so adding a locale is a one-line change. +var ( + headerFromFields = []string{ + "from", "fra", "de", "von", "da", "van", "från", "expéditeur", + "发件人", "寄件者", "差出人", "보낸사람", + } + headerFields = append([]string{ + "to", "cc", "bcc", "sent", "date", "subject", "reply-to", + "til", "emne", "an", "betreff", "gesendet", "para", "assunto", "asunto", + "risposta", "inviato", "oggetto", "destinataire", "objet", "répondre à", + "aan", "onderwerp", "beantwoorden", "skickat", "till", "ämne", + "收件人", "主题", "主旨", "主題", "收件者", "抄送", "日期", "宛先", "件名", "받는사람", "제목", + }, headerFromFields...) +) + +// patterns are compiled on first use so the incoming-mail feature adds nothing to startup. +var patterns = sync.OnceValue(func() (ret struct { + signature, attribution, separator *regexp.Regexp +}, +) { + // "-- " delimiter and common mobile footers with frequent localizations. The CJK + // forms require a device name so ordinary prose like "发自我的内心" or "会議から送信" + // is not mistaken for a signature. + ret.signature = regexp.MustCompile(`(?i)^(--|__|—` + + `|sent (from|via|with) .+|get outlook for .+` + + `|envoyé depuis mon .+|sendt fra min .+|von meinem .+|verzonden (met|vanaf) .+` + + `|(發|发)自我的.*(` + cjkDevice + `).*` + + `|.*(` + cjkDevice + `).*(から送信|에서 보냄|傳送|发送))$`) + + // attribution introducing quoted history: a line ending in a "wrote:" verb + // (Latin/Cyrillic or CJK), a "Name wrote" line, a lead word directly + // followed by a day number or weekday plus a year and a time, or an ISO-date-led + // line. The date phrasing, trailing colon and the email before the verb guard + // against prose (so "On the 2024 roadmap … at 10:00" is not an attribution). + ret.attribution = regexp.MustCompile(`(?i)^>*\s*(` + + `.*[\s">'](` + wroteVerbs + `)\s*[::]` + + `|.*(` + cjkWroteVerbs + `)\s*[::]` + + `|.*<\S+@\S+>\s+(` + wroteVerbs + `)\b.*` + + `|(on|at|le|am|el|em|den|il|op|dnia|w dniu)\b[\s,]*(\d|(?:mon|tue|wed|thu|fri|sat|sun)\b).*` + yearToken + `.*` + timeToken + `.*` + + `|\d{4}-\d{2}-\d{2}\b.*` + timeToken + `.*` + + `)$`) + + // a dash/underscore rule line, or text fenced by dashes such as + // "-------- Original Message --------" or "-----Mensaje original-----" + ret.separator = regexp.MustCompile(`(?i)^\s*\*?\s*([-_]{5,}|-{2,}.+-{2,}|original message|forwarded message)\s*\*?\s*$`) + return ret +}) + +// extractReply returns the user-written part of a plain-text email body, dropping +// quoted history, the reply attribution, signatures and forwarded headers. It is a +// slim, dependency-free reimplementation based on github.com/dimiro1/reply (MIT), +// covering the common mail-client formats and languages; bottom posting and +// forwarded bodies are not handled. +func extractReply(text string) string { + p := patterns() + lines := strings.Split(util.NormalizeStringEOL(text), "\n") + + // cut at the first line that begins quoted history, a signature or a header block + for i := range lines { + trimmed := strings.TrimSpace(lines[i]) + if p.signature.MatchString(trimmed) || p.attribution.MatchString(trimmed) || + p.separator.MatchString(trimmed) || headerBlock(trimmed, lines[i+1:]) { + lines = lines[:i] + break + } + } + + // drop the trailing block of quoted/blank lines, unless the whole body is quoted + end := len(lines) + for end > 0 { + // "ᐧ" is the trailing marker some mobile clients (Mailbox) append + if t := strings.TrimSpace(lines[end-1]); t != "" && t != "ᐧ" && !strings.HasPrefix(t, ">") { + break + } + end-- + } + if end > 0 { + lines = lines[:end] + } + + return strings.TrimSpace(strings.Join(lines, "\n")) +} + +// headerBlock reports whether a forwarded-mail header block starts here: the +// (already-trimmed) first line is a "From" field and the next non-blank line is +// another field, so a lone "Subject:" sentence is not a boundary. +func headerBlock(first string, rest []string) bool { + if !headerLine(first, headerFromFields) { + return false + } + for _, next := range rest { + if t := strings.TrimSpace(next); t != "" { + return headerLine(t, headerFields) + } + } + return false +} + +// headerLine reports whether the already-trimmed line is a "Field:" header for one +// of fields. An ASCII colon must be followed by a space so prose like "To:do this" +// is ignored; the CJK fullwidth colon ":" needs no space. +func headerLine(line string, fields []string) bool { + lower := strings.ToLower(line) + for _, field := range fields { + if rest, ok := strings.CutPrefix(lower, field); ok && + (strings.HasPrefix(rest, ": ") || strings.HasPrefix(rest, ":")) { + return true + } + } + return false +} diff --git a/package/gitea/source/services/mailer/mail.go b/package/gitea/source/services/mailer/mail.go index a08ed714..4bbb8b15 100644 --- a/package/gitea/source/services/mailer/mail.go +++ b/package/gitea/source/services/mailer/mail.go @@ -16,15 +16,15 @@ import ( "regexp" "strings" - repo_model "code.gitea.io/gitea/models/repo" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/httplib" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/storage" - "code.gitea.io/gitea/modules/templates" - "code.gitea.io/gitea/modules/typesniffer" - sender_service "code.gitea.io/gitea/services/mailer/sender" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/httplib" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" + "gitea.dev/modules/storage" + "gitea.dev/modules/templates" + "gitea.dev/modules/typesniffer" + sender_service "gitea.dev/services/mailer/sender" "golang.org/x/net/html" ) diff --git a/package/gitea/source/services/mailer/mail_comment.go b/package/gitea/source/services/mailer/mail_comment.go index e8d12e42..2e564fcb 100644 --- a/package/gitea/source/services/mailer/mail_comment.go +++ b/package/gitea/source/services/mailer/mail_comment.go @@ -6,12 +6,12 @@ package mailer import ( "context" - activities_model "code.gitea.io/gitea/models/activities" - issues_model "code.gitea.io/gitea/models/issues" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" + activities_model "gitea.dev/models/activities" + issues_model "gitea.dev/models/issues" + user_model "gitea.dev/models/user" + "gitea.dev/modules/container" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" ) // MailParticipantsComment sends new comment emails to repository watchers and mentioned people. diff --git a/package/gitea/source/services/mailer/mail_issue.go b/package/gitea/source/services/mailer/mail_issue.go index b854d61a..482bb3c9 100644 --- a/package/gitea/source/services/mailer/mail_issue.go +++ b/package/gitea/source/services/mailer/mail_issue.go @@ -7,15 +7,15 @@ import ( "context" "fmt" - activities_model "code.gitea.io/gitea/models/activities" - 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" - "code.gitea.io/gitea/models/unit" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" + activities_model "gitea.dev/models/activities" + issues_model "gitea.dev/models/issues" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unit" + user_model "gitea.dev/models/user" + "gitea.dev/modules/container" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" ) const MailBatchSize = 100 // batch size used in mailIssueCommentBatch diff --git a/package/gitea/source/services/mailer/mail_issue_common.go b/package/gitea/source/services/mailer/mail_issue_common.go index 544a504a..11979691 100644 --- a/package/gitea/source/services/mailer/mail_issue_common.go +++ b/package/gitea/source/services/mailer/mail_issue_common.go @@ -12,19 +12,19 @@ import ( "strings" "time" - activities_model "code.gitea.io/gitea/models/activities" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/renderhelper" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/emoji" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/markup/markdown" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/translation" - "code.gitea.io/gitea/modules/util" - incoming_payload "code.gitea.io/gitea/services/mailer/incoming/payload" - sender_service "code.gitea.io/gitea/services/mailer/sender" - "code.gitea.io/gitea/services/mailer/token" + activities_model "gitea.dev/models/activities" + issues_model "gitea.dev/models/issues" + "gitea.dev/models/renderhelper" + user_model "gitea.dev/models/user" + "gitea.dev/modules/emoji" + "gitea.dev/modules/log" + "gitea.dev/modules/markup/markdown" + "gitea.dev/modules/setting" + "gitea.dev/modules/translation" + "gitea.dev/modules/util" + incoming_payload "gitea.dev/services/mailer/incoming/payload" + sender_service "gitea.dev/services/mailer/sender" + "gitea.dev/services/mailer/token" ) // maxEmailBodySize is the approximate maximum size of an email body in bytes @@ -99,7 +99,9 @@ func composeIssueCommentMessages(ctx context.Context, comment *mailComment, lang } } locale := translation.NewLocale(lang) - + if lang == "mock" { + locale = &translation.MockLocale{} + } mailMeta := map[string]any{ "locale": locale, "FallbackSubject": fallback, diff --git a/package/gitea/source/services/mailer/mail_release.go b/package/gitea/source/services/mailer/mail_release.go index 1f940f33..db45c201 100644 --- a/package/gitea/source/services/mailer/mail_release.go +++ b/package/gitea/source/services/mailer/mail_release.go @@ -9,17 +9,17 @@ import ( "fmt" "slices" - access_model "code.gitea.io/gitea/models/perm/access" - "code.gitea.io/gitea/models/renderhelper" - 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/log" - "code.gitea.io/gitea/modules/markup/markdown" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/templates" - "code.gitea.io/gitea/modules/translation" - sender_service "code.gitea.io/gitea/services/mailer/sender" + access_model "gitea.dev/models/perm/access" + "gitea.dev/models/renderhelper" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unit" + user_model "gitea.dev/models/user" + "gitea.dev/modules/log" + "gitea.dev/modules/markup/markdown" + "gitea.dev/modules/setting" + "gitea.dev/modules/templates" + "gitea.dev/modules/translation" + sender_service "gitea.dev/services/mailer/sender" ) const tplNewReleaseMail templates.TplName = "repo/release" diff --git a/package/gitea/source/services/mailer/mail_release_test.go b/package/gitea/source/services/mailer/mail_release_test.go index 6fc8587f..e71b2132 100644 --- a/package/gitea/source/services/mailer/mail_release_test.go +++ b/package/gitea/source/services/mailer/mail_release_test.go @@ -6,12 +6,12 @@ package mailer import ( "testing" - 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/setting" - "code.gitea.io/gitea/modules/test" - sender_service "code.gitea.io/gitea/services/mailer/sender" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/modules/setting" + "gitea.dev/modules/test" + sender_service "gitea.dev/services/mailer/sender" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/package/gitea/source/services/mailer/mail_repo.go b/package/gitea/source/services/mailer/mail_repo.go index b5fdfbf2..2631a5c6 100644 --- a/package/gitea/source/services/mailer/mail_repo.go +++ b/package/gitea/source/services/mailer/mail_repo.go @@ -8,14 +8,14 @@ import ( "context" "fmt" - "code.gitea.io/gitea/models/organization" - repo_model "code.gitea.io/gitea/models/repo" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/templates" - "code.gitea.io/gitea/modules/translation" - sender_service "code.gitea.io/gitea/services/mailer/sender" + "gitea.dev/models/organization" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" + "gitea.dev/modules/templates" + "gitea.dev/modules/translation" + sender_service "gitea.dev/services/mailer/sender" ) const ( diff --git a/package/gitea/source/services/mailer/mail_team_invite.go b/package/gitea/source/services/mailer/mail_team_invite.go index 4819f299..6d016ae8 100644 --- a/package/gitea/source/services/mailer/mail_team_invite.go +++ b/package/gitea/source/services/mailer/mail_team_invite.go @@ -10,13 +10,13 @@ import ( "fmt" "net/url" - org_model "code.gitea.io/gitea/models/organization" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/templates" - "code.gitea.io/gitea/modules/translation" - sender_service "code.gitea.io/gitea/services/mailer/sender" + org_model "gitea.dev/models/organization" + user_model "gitea.dev/models/user" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" + "gitea.dev/modules/templates" + "gitea.dev/modules/translation" + sender_service "gitea.dev/services/mailer/sender" ) const tplTeamInviteMail templates.TplName = "org/team_invite" diff --git a/package/gitea/source/services/mailer/mail_test.go b/package/gitea/source/services/mailer/mail_test.go index caa07272..29253283 100644 --- a/package/gitea/source/services/mailer/mail_test.go +++ b/package/gitea/source/services/mailer/mail_test.go @@ -16,19 +16,23 @@ import ( "testing" texttmpl "text/template" - actions_model "code.gitea.io/gitea/models/actions" - activities_model "code.gitea.io/gitea/models/activities" - 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/markup" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/storage" - "code.gitea.io/gitea/modules/templates" - "code.gitea.io/gitea/modules/test" - "code.gitea.io/gitea/services/attachment" - sender_service "code.gitea.io/gitea/services/mailer/sender" + actions_model "gitea.dev/models/actions" + activities_model "gitea.dev/models/activities" + "gitea.dev/models/asymkey" + git_model "gitea.dev/models/git" + "gitea.dev/models/gituser" + issues_model "gitea.dev/models/issues" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/markup" + "gitea.dev/modules/setting" + "gitea.dev/modules/storage" + "gitea.dev/modules/templates" + "gitea.dev/modules/test" + "gitea.dev/services/attachment" + sender_service "gitea.dev/services/mailer/sender" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -556,3 +560,32 @@ func TestEmbedBase64Images(t *testing.T) { assert.Equal(t, expected, string(resultMailBody)) }) } + +func TestMailPullRequestPush(t *testing.T) { + doer, _, issue, comment := prepareMailerTest(t) + mc := &mailComment{ + Issue: issue, + Comment: comment, + Doer: doer, + } + issue.IsPull = true + issue.PullRequest = &issues_model.PullRequest{BaseRepo: mc.Issue.Repo} + mc.Comment.Type = issues_model.CommentTypePullRequestPush + mc.Comment.Commits = []*git_model.SignCommitWithStatuses{ + { + SignCommit: &asymkey.SignCommit{ + UserCommit: &gituser.UserCommit{ + GitCommit: &git.Commit{ + CommitMessage: git.CommitMessage{MessageRaw: "test commit msg"}, + ID: git.Sha1ObjectFormat.EmptyObjectID(), + }, + }, + }, + }, + } + + msgs, err := composeIssueCommentMessages(t.Context(), mc, "mock", []*user_model.User{{Name: "Test", Email: "test@gitea.com"}}, false, "pull request push") + require.NoError(t, err) + assert.Contains(t, msgs[0].Body, `0000000000 - test commit msg`) + assert.Contains(t, msgs[0].Body, ``) +} diff --git a/package/gitea/source/services/mailer/mail_user.go b/package/gitea/source/services/mailer/mail_user.go index 867a8b2a..504b62e0 100644 --- a/package/gitea/source/services/mailer/mail_user.go +++ b/package/gitea/source/services/mailer/mail_user.go @@ -7,13 +7,13 @@ import ( "bytes" "fmt" - user_model "code.gitea.io/gitea/models/user" - "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/translation" - sender_service "code.gitea.io/gitea/services/mailer/sender" + user_model "gitea.dev/models/user" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" + "gitea.dev/modules/templates" + "gitea.dev/modules/timeutil" + "gitea.dev/modules/translation" + sender_service "gitea.dev/services/mailer/sender" ) const ( diff --git a/package/gitea/source/services/mailer/mail_workflow_run.go b/package/gitea/source/services/mailer/mail_workflow_run.go index 9efaa418..aa2827bf 100644 --- a/package/gitea/source/services/mailer/mail_workflow_run.go +++ b/package/gitea/source/services/mailer/mail_workflow_run.go @@ -10,16 +10,16 @@ import ( "sort" "time" - 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/base" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/templates" - "code.gitea.io/gitea/modules/translation" - "code.gitea.io/gitea/services/convert" - sender_service "code.gitea.io/gitea/services/mailer/sender" + actions_model "gitea.dev/models/actions" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/base" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" + "gitea.dev/modules/templates" + "gitea.dev/modules/translation" + "gitea.dev/services/convert" + sender_service "gitea.dev/services/mailer/sender" ) const tplWorkflowRun templates.TplName = "repo/actions/workflow_run" @@ -37,7 +37,7 @@ func generateMessageIDForActionsWorkflowRunStatusEmail(repo *repo_model.Reposito } func composeAndSendActionsWorkflowRunStatusEmail(ctx context.Context, repo *repo_model.Repository, run *actions_model.ActionRun, sender *user_model.User, recipients []*user_model.User) error { - jobs, err := actions_model.GetRunJobsByRunID(ctx, run.ID) + jobs, err := actions_model.GetLatestAttemptJobsByRepoAndRunID(ctx, repo.ID, run.ID) if err != nil { return err } diff --git a/package/gitea/source/services/mailer/mailer.go b/package/gitea/source/services/mailer/mailer.go index 05dd5d85..d697f139 100644 --- a/package/gitea/source/services/mailer/mailer.go +++ b/package/gitea/source/services/mailer/mailer.go @@ -7,13 +7,13 @@ package mailer import ( "context" - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/queue" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/templates" - sender_service "code.gitea.io/gitea/services/mailer/sender" - notify_service "code.gitea.io/gitea/services/notify" + "gitea.dev/modules/graceful" + "gitea.dev/modules/log" + "gitea.dev/modules/queue" + "gitea.dev/modules/setting" + "gitea.dev/modules/templates" + sender_service "gitea.dev/services/mailer/sender" + notify_service "gitea.dev/services/notify" ) var mailQueue *queue.WorkerPoolQueue[*sender_service.Message] diff --git a/package/gitea/source/services/mailer/main_test.go b/package/gitea/source/services/mailer/main_test.go index 5591bea0..1933f8ed 100644 --- a/package/gitea/source/services/mailer/main_test.go +++ b/package/gitea/source/services/mailer/main_test.go @@ -6,10 +6,10 @@ package mailer import ( "testing" - "code.gitea.io/gitea/models/unittest" + "gitea.dev/models/unittest" - _ "code.gitea.io/gitea/models" - _ "code.gitea.io/gitea/models/actions" + _ "gitea.dev/models" + _ "gitea.dev/models/actions" ) func TestMain(m *testing.M) { diff --git a/package/gitea/source/services/mailer/notify.go b/package/gitea/source/services/mailer/notify.go index 5921021c..0ec7ab01 100644 --- a/package/gitea/source/services/mailer/notify.go +++ b/package/gitea/source/services/mailer/notify.go @@ -7,14 +7,14 @@ import ( "context" "fmt" - actions_model "code.gitea.io/gitea/models/actions" - activities_model "code.gitea.io/gitea/models/activities" - issues_model "code.gitea.io/gitea/models/issues" - repo_model "code.gitea.io/gitea/models/repo" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/log" - issue_service "code.gitea.io/gitea/services/issue" - notify_service "code.gitea.io/gitea/services/notify" + actions_model "gitea.dev/models/actions" + activities_model "gitea.dev/models/activities" + issues_model "gitea.dev/models/issues" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/log" + issue_service "gitea.dev/services/issue" + notify_service "gitea.dev/services/notify" ) type mailNotifier struct { diff --git a/package/gitea/source/services/mailer/sender/dummy.go b/package/gitea/source/services/mailer/sender/dummy.go index dd5f14ab..1400ad76 100644 --- a/package/gitea/source/services/mailer/sender/dummy.go +++ b/package/gitea/source/services/mailer/sender/dummy.go @@ -7,7 +7,7 @@ import ( "bytes" "io" - "code.gitea.io/gitea/modules/log" + "gitea.dev/modules/log" ) // DummySender Sender sendmail mail sender diff --git a/package/gitea/source/services/mailer/sender/main_test.go b/package/gitea/source/services/mailer/sender/main_test.go index c6705796..bd3d5f70 100644 --- a/package/gitea/source/services/mailer/sender/main_test.go +++ b/package/gitea/source/services/mailer/sender/main_test.go @@ -6,7 +6,7 @@ package sender import ( "testing" - "code.gitea.io/gitea/models/unittest" + "gitea.dev/models/unittest" ) func TestMain(m *testing.M) { diff --git a/package/gitea/source/services/mailer/sender/message.go b/package/gitea/source/services/mailer/sender/message.go index 55f03e4f..bf22ddef 100644 --- a/package/gitea/source/services/mailer/sender/message.go +++ b/package/gitea/source/services/mailer/sender/message.go @@ -10,11 +10,11 @@ import ( "strings" "time" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" + "gitea.dev/modules/util" - "github.com/jaytaylor/html2text" + "github.com/Necoro/html2text" gomail "github.com/wneessen/go-mail" ) diff --git a/package/gitea/source/services/mailer/sender/message_test.go b/package/gitea/source/services/mailer/sender/message_test.go index ae153ebf..441fb818 100644 --- a/package/gitea/source/services/mailer/sender/message_test.go +++ b/package/gitea/source/services/mailer/sender/message_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - "code.gitea.io/gitea/modules/setting" + "gitea.dev/modules/setting" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/mailer/sender/sendmail.go b/package/gitea/source/services/mailer/sender/sendmail.go index 7064c60f..6f7fadc3 100644 --- a/package/gitea/source/services/mailer/sender/sendmail.go +++ b/package/gitea/source/services/mailer/sender/sendmail.go @@ -9,10 +9,10 @@ import ( "os/exec" "strings" - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/process" - "code.gitea.io/gitea/modules/setting" + "gitea.dev/modules/graceful" + "gitea.dev/modules/log" + "gitea.dev/modules/process" + "gitea.dev/modules/setting" ) // SendmailSender Sender sendmail mail sender diff --git a/package/gitea/source/services/mailer/sender/smtp.go b/package/gitea/source/services/mailer/sender/smtp.go index fa078033..dc29c0fa 100644 --- a/package/gitea/source/services/mailer/sender/smtp.go +++ b/package/gitea/source/services/mailer/sender/smtp.go @@ -14,8 +14,8 @@ import ( "os" "strings" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" ) // SMTPSender Sender SMTP mail sender diff --git a/package/gitea/source/services/mailer/token/token.go b/package/gitea/source/services/mailer/token/token.go index a78f5349..de9a60dd 100644 --- a/package/gitea/source/services/mailer/token/token.go +++ b/package/gitea/source/services/mailer/token/token.go @@ -12,8 +12,8 @@ import ( "strings" "time" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/util" + user_model "gitea.dev/models/user" + "gitea.dev/modules/util" ) // A token is a verifiable container describing an action. diff --git a/package/gitea/source/services/markup/main_test.go b/package/gitea/source/services/markup/main_test.go index d04a18bf..01985034 100644 --- a/package/gitea/source/services/markup/main_test.go +++ b/package/gitea/source/services/markup/main_test.go @@ -6,7 +6,7 @@ package markup import ( "testing" - "code.gitea.io/gitea/models/unittest" + "gitea.dev/models/unittest" ) func TestMain(m *testing.M) { diff --git a/package/gitea/source/services/markup/renderhelper.go b/package/gitea/source/services/markup/renderhelper.go index ea494146..ac94cb6e 100644 --- a/package/gitea/source/services/markup/renderhelper.go +++ b/package/gitea/source/services/markup/renderhelper.go @@ -6,9 +6,9 @@ package markup import ( "context" - "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/markup" - gitea_context "code.gitea.io/gitea/services/context" + "gitea.dev/models/user" + "gitea.dev/modules/markup" + gitea_context "gitea.dev/services/context" ) func FormalRenderHelperFuncs() *markup.RenderHelperFuncs { diff --git a/package/gitea/source/services/markup/renderhelper_codepreview.go b/package/gitea/source/services/markup/renderhelper_codepreview.go index fd2db0d1..962cced1 100644 --- a/package/gitea/source/services/markup/renderhelper_codepreview.go +++ b/package/gitea/source/services/markup/renderhelper_codepreview.go @@ -10,17 +10,17 @@ import ( "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/git/languagestats" - "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" - "code.gitea.io/gitea/modules/util" - gitea_context "code.gitea.io/gitea/services/context" + "gitea.dev/models/perm/access" + "gitea.dev/models/repo" + "gitea.dev/models/unit" + "gitea.dev/modules/charset" + "gitea.dev/modules/git/languagestats" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/indexer/code" + "gitea.dev/modules/markup" + "gitea.dev/modules/setting" + "gitea.dev/modules/util" + gitea_context "gitea.dev/services/context" ) func renderRepoFileCodePreview(ctx context.Context, opts markup.RenderCodePreviewOptions) (template.HTML, error) { diff --git a/package/gitea/source/services/markup/renderhelper_codepreview_test.go b/package/gitea/source/services/markup/renderhelper_codepreview_test.go index 94ed5b41..954b4036 100644 --- a/package/gitea/source/services/markup/renderhelper_codepreview_test.go +++ b/package/gitea/source/services/markup/renderhelper_codepreview_test.go @@ -6,11 +6,11 @@ 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/modules/util" - "code.gitea.io/gitea/services/contexttest" + "gitea.dev/models/unittest" + "gitea.dev/modules/markup" + "gitea.dev/modules/templates" + "gitea.dev/modules/util" + "gitea.dev/services/contexttest" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/markup/renderhelper_issueicontitle.go b/package/gitea/source/services/markup/renderhelper_issueicontitle.go index 651e2997..a62257a8 100644 --- a/package/gitea/source/services/markup/renderhelper_issueicontitle.go +++ b/package/gitea/source/services/markup/renderhelper_issueicontitle.go @@ -9,13 +9,13 @@ import ( "fmt" "html/template" - "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/perm/access" - "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/htmlutil" - "code.gitea.io/gitea/modules/markup" - "code.gitea.io/gitea/modules/util" - gitea_context "code.gitea.io/gitea/services/context" + "gitea.dev/models/issues" + "gitea.dev/models/perm/access" + "gitea.dev/models/repo" + "gitea.dev/modules/htmlutil" + "gitea.dev/modules/markup" + "gitea.dev/modules/util" + gitea_context "gitea.dev/services/context" ) func renderRepoIssueIconTitle(ctx context.Context, opts markup.RenderIssueIconTitleOptions) (_ template.HTML, err error) { @@ -42,14 +42,15 @@ func renderRepoIssueIconTitle(ctx context.Context, opts markup.RenderIssueIconTi return "", err } + permission := webCtx.Repo.Permission if webCtx.Repo.Repository == nil || dbRepo.ID != webCtx.Repo.Repository.ID { - perms, err := access.GetDoerRepoPermission(ctx, dbRepo, webCtx.Doer) + permission, err = access.GetDoerRepoPermission(ctx, dbRepo, webCtx.Doer) if err != nil { return "", err } - if !perms.CanReadIssuesOrPulls(issue.IsPull) { - return "", util.ErrPermissionDenied - } + } + if !permission.CanReadIssuesOrPulls(issue.IsPull) { + return "", util.ErrPermissionDenied } if issue.IsPull { diff --git a/package/gitea/source/services/markup/renderhelper_issueicontitle_test.go b/package/gitea/source/services/markup/renderhelper_issueicontitle_test.go index 774c340d..94cc975d 100644 --- a/package/gitea/source/services/markup/renderhelper_issueicontitle_test.go +++ b/package/gitea/source/services/markup/renderhelper_issueicontitle_test.go @@ -6,44 +6,63 @@ package markup import ( "testing" - "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/markup" - "code.gitea.io/gitea/modules/templates" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/services/contexttest" + issue_model "gitea.dev/models/issues" + perm_model "gitea.dev/models/perm" + "gitea.dev/models/repo" + "gitea.dev/models/unit" + "gitea.dev/models/unittest" + "gitea.dev/modules/markup" + "gitea.dev/modules/templates" + "gitea.dev/modules/util" + "gitea.dev/services/contexttest" "github.com/stretchr/testify/assert" + "xorm.io/builder" ) func TestRenderHelperIssueIconTitle(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - ctx, _ := contexttest.MockContext(t, "/", contexttest.MockContextOption{Render: templates.PageRenderer()}) - ctx.Repo.Repository = unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) - htm, err := renderRepoIssueIconTitle(ctx, markup.RenderIssueIconTitleOptions{ - LinkHref: "/link", - IssueIndex: 1, - }) - assert.NoError(t, err) - assert.Equal(t, `octicon-issue-opened(16/tw-text-green) issue1 (#1)`, string(htm)) + t.Run("RenderInCurrentRepo", func(t *testing.T) { + ctx, _ := contexttest.MockContext(t, "/", contexttest.MockContextOption{Render: templates.PageRenderer()}) + contexttest.LoadRepo(t, ctx, 1) + htm, err := renderRepoIssueIconTitle(ctx, markup.RenderIssueIconTitleOptions{ + LinkHref: "/link", + IssueIndex: 1, + }) + assert.NoError(t, err) + assert.Equal(t, `octicon-issue-opened(16/tw-text-green) issue1 (#1)`, string(htm)) - ctx, _ = contexttest.MockContext(t, "/", contexttest.MockContextOption{Render: templates.PageRenderer()}) - htm, err = renderRepoIssueIconTitle(ctx, markup.RenderIssueIconTitleOptions{ - OwnerName: "user2", - RepoName: "repo1", - LinkHref: "/link", - IssueIndex: 1, + ctx.Repo.Permission.SetUnitsWithDefaultAccessMode([]*repo.RepoUnit{{Type: unit.TypeWiki}}, perm_model.AccessModeRead) + issueA := unittest.AssertExistsAndLoadBean(t, &issue_model.Issue{}, builder.Eq{"repo_id": 1, "`index`": 1, "is_pull": false}) + issueB := unittest.AssertExistsAndLoadBean(t, &issue_model.Issue{}, builder.Eq{"repo_id": 1, "`index`": 2, "is_pull": true}) + for _, issueIndex := range []int64{issueA.Index, issueB.Index} { + _, err = renderRepoIssueIconTitle(ctx, markup.RenderIssueIconTitleOptions{ + LinkHref: "/link", + IssueIndex: issueIndex, + }) + assert.ErrorIs(t, err, util.ErrPermissionDenied) + } }) - assert.NoError(t, err) - assert.Equal(t, `octicon-issue-opened(16/tw-text-green) issue1 (user2/repo1#1)`, string(htm)) - ctx, _ = contexttest.MockContext(t, "/", contexttest.MockContextOption{Render: templates.PageRenderer()}) - _, err = renderRepoIssueIconTitle(ctx, markup.RenderIssueIconTitleOptions{ - OwnerName: "user2", - RepoName: "repo2", - LinkHref: "/link", - IssueIndex: 2, + t.Run("RenderAcrossRepo", func(t *testing.T) { + ctx, _ := contexttest.MockContext(t, "/", contexttest.MockContextOption{Render: templates.PageRenderer()}) + htm, err := renderRepoIssueIconTitle(ctx, markup.RenderIssueIconTitleOptions{ + OwnerName: "user2", + RepoName: "repo1", + LinkHref: "/link", + IssueIndex: 1, + }) + assert.NoError(t, err) + assert.Equal(t, `octicon-issue-opened(16/tw-text-green) issue1 (user2/repo1#1)`, string(htm)) + + ctx, _ = contexttest.MockContext(t, "/", contexttest.MockContextOption{Render: templates.PageRenderer()}) + _, err = renderRepoIssueIconTitle(ctx, markup.RenderIssueIconTitleOptions{ + OwnerName: "user2", + RepoName: "repo2", + LinkHref: "/link", + IssueIndex: 2, + }) + assert.ErrorIs(t, err, util.ErrPermissionDenied) }) - assert.ErrorIs(t, err, util.ErrPermissionDenied) } diff --git a/package/gitea/source/services/markup/renderhelper_mention_test.go b/package/gitea/source/services/markup/renderhelper_mention_test.go index 11aa7b21..d4b34c20 100644 --- a/package/gitea/source/services/markup/renderhelper_mention_test.go +++ b/package/gitea/source/services/markup/renderhelper_mention_test.go @@ -8,10 +8,10 @@ import ( "net/http/httptest" "testing" - "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/models/user" - gitea_context "code.gitea.io/gitea/services/context" - "code.gitea.io/gitea/services/contexttest" + "gitea.dev/models/unittest" + "gitea.dev/models/user" + gitea_context "gitea.dev/services/context" + "gitea.dev/services/contexttest" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Fmilestones b/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Fmilestones new file mode 100644 index 00000000..039abf0c --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Fmilestones @@ -0,0 +1,21 @@ +Content-Type: application/xml; charset=utf-8 + + + + + 1 + milestone1 + Milestone1 + 2021-09-16 + + active + + + 2 + milestone2 + Milestone2 + 2021-09-17 + + closed + + diff --git a/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftest b/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftest new file mode 100644 index 00000000..e459a32d --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftest @@ -0,0 +1,10 @@ +Content-Type: application/xml; charset=utf-8 + + + + test + Repository Description + test + git@codebasehq.com:gitea-test/gitea-test/test.git + + diff --git a/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftest%2Fcommits%2Fmaster b/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftest%2Fcommits%2Fmaster new file mode 100644 index 00000000..e2051975 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftest%2Fcommits%2Fmaster @@ -0,0 +1,8 @@ +Content-Type: application/xml; charset=utf-8 + + + + + f32b0a9dfd09a60f616f29158f772cedd89942d2 + + diff --git a/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftest%2Fcommits%2Freadme-mr b/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftest%2Fcommits%2Freadme-mr new file mode 100644 index 00000000..0581ef37 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftest%2Fcommits%2Freadme-mr @@ -0,0 +1,8 @@ +Content-Type: application/xml; charset=utf-8 + + + + + 1287f206b888d4d13540e0a8e1c07458f5420059 + + diff --git a/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftest%2Fmerge_requests%2F100 b/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftest%2Fmerge_requests%2F100 new file mode 100644 index 00000000..322d1b36 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftest%2Fmerge_requests%2F100 @@ -0,0 +1,22 @@ +Content-Type: application/xml; charset=utf-8 + + + + 100 + readme-mr + master + Readme Change + new + 43 + 2021-09-26T20:25:47+00:00 + 2021-09-26T20:25:47+00:00 + + + Merge Request comment + 300 + 43 + + 2021-09-26T20:25:47+00:00 + + + diff --git a/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftest%2Fmerge_requests%3Fcount%3D1%26offset%3D0%26query%3D%2522Target%2BProject%2522%2Bis%2B%2522test%2522 b/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftest%2Fmerge_requests%3Fcount%3D1%26offset%3D0%26query%3D%2522Target%2BProject%2522%2Bis%2B%2522test%2522 new file mode 100644 index 00000000..08989080 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftest%2Fmerge_requests%3Fcount%3D1%26offset%3D0%26query%3D%2522Target%2BProject%2522%2Bis%2B%2522test%2522 @@ -0,0 +1,8 @@ +Content-Type: application/xml; charset=utf-8 + + + + + 100 + + diff --git a/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftickets b/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftickets new file mode 100644 index 00000000..dfff5c3a --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftickets @@ -0,0 +1,41 @@ +Content-Type: application/xml; charset=utf-8 + + + + + 2 + Open Ticket + Feature + 43 + gitea-test-43 + + Feature + + + false + + + + + 2021-09-26T19:19:34+00:00 + 2021-09-26T19:19:14+00:00 + + + 1 + Closed Ticket + Bug + 43 + gitea-test-43 + + Bug + + + true + + + Milestone1 + + 2021-09-26T19:18:55+00:00 + 2021-09-26T19:18:33+00:00 + + diff --git a/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftickets%2F1%2Fnotes b/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftickets%2F1%2Fnotes new file mode 100644 index 00000000..640888fb --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftickets%2F1%2Fnotes @@ -0,0 +1,12 @@ +Content-Type: application/xml; charset=utf-8 + + + + + Closed Ticket Message + 2021-09-26T19:18:33+00:00 + 2021-09-26T19:18:33+00:00 + 200 + 43 + + diff --git a/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftickets%2F2%2Fnotes b/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftickets%2F2%2Fnotes new file mode 100644 index 00000000..60628026 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftickets%2F2%2Fnotes @@ -0,0 +1,19 @@ +Content-Type: application/xml; charset=utf-8 + + + + + Open Ticket Message + 2021-09-26T19:19:14+00:00 + 2021-09-26T19:19:14+00:00 + 100 + 43 + + + open comment + 2021-09-26T19:19:34+00:00 + 2021-09-26T19:19:34+00:00 + 101 + 43 + + diff --git a/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftickets%2Ftypes b/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftickets%2Ftypes new file mode 100644 index 00000000..d7320dde --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fgitea-test%2Ftickets%2Ftypes @@ -0,0 +1,21 @@ +Content-Type: application/xml; charset=utf-8 + + + + + 1 + Bug + + + 2 + Feature + + + 3 + Enhancement + + + 4 + Task + + diff --git a/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fusers b/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fusers new file mode 100644 index 00000000..c6560f42 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestCodebaseDownloadRepo/GET_%2Fusers @@ -0,0 +1,12 @@ +Content-Type: application/xml; charset=utf-8 + + + + + gitea-codebase@smack.email + 43 + Test + Gitea + gitea-test-43 + + diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frate_limit b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frate_limit new file mode 100644 index 00000000..ecc04fe8 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frate_limit @@ -0,0 +1,22 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: no-cache +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: allows_permissionless_access=true +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; format=json +X-Github-Request-Id: C4F6:A93E1:6A2E9E:5B1BA1:69AF24E6 +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4937 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 63 +X-Xss-Protection: 0 + +{"resources":{"core":{"limit":5000,"used":63,"remaining":4937,"reset":1773089427},"search":{"limit":30,"used":0,"remaining":30,"reset":1773085986},"graphql":{"limit":5000,"used":40,"remaining":4960,"reset":1773087278},"integration_manifest":{"limit":5000,"used":0,"remaining":5000,"reset":1773089526},"source_import":{"limit":100,"used":0,"remaining":100,"reset":1773085986},"code_scanning_upload":{"limit":5000,"used":63,"remaining":4937,"reset":1773089427},"code_scanning_autofix":{"limit":10,"used":0,"remaining":10,"reset":1773085986},"actions_runner_registration":{"limit":10000,"used":0,"remaining":10000,"reset":1773089526},"scim":{"limit":15000,"used":0,"remaining":15000,"reset":1773089526},"dependency_snapshots":{"limit":100,"used":0,"remaining":100,"reset":1773085986},"dependency_sbom":{"limit":100,"used":0,"remaining":100,"reset":1773085986},"audit_log":{"limit":1750,"used":0,"remaining":1750,"reset":1773089526},"audit_log_streaming":{"limit":15,"used":0,"remaining":15,"reset":1773089526},"code_search":{"limit":10,"used":0,"remaining":10,"reset":1773085986}},"rate":{"limit":5000,"used":63,"remaining":4937,"reset":1773089427}} \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo new file mode 100644 index 00000000..ae9a3350 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo @@ -0,0 +1,24 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: W/"4bd381e9d79f99cd2153b922e196d49eee23b7a4c10bb22a3ab3ffc6cf78ce39" +Last-Modified: Thu, 02 Mar 2023 14:02:26 GMT +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: metadata=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; param=scarlet-witch-preview; format=json, github.mercy-preview; param=baptiste-preview.nebula-preview; format=json +X-Github-Request-Id: C4F6:A93E1:6A3367:5B1FCA:69AF24E6 +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4935 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 65 +X-Xss-Protection: 0 + +{"id":220672974,"node_id":"MDEwOlJlcG9zaXRvcnkyMjA2NzI5NzQ=","name":"test_repo","full_name":"go-gitea/test_repo","private":false,"owner":{"login":"go-gitea","id":12724356,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEyNzI0MzU2","avatar_url":"https://avatars.githubusercontent.com/u/12724356?v=4","gravatar_id":"","url":"https://api.github.com/users/go-gitea","html_url":"https://github.com/go-gitea","followers_url":"https://api.github.com/users/go-gitea/followers","following_url":"https://api.github.com/users/go-gitea/following{/other_user}","gists_url":"https://api.github.com/users/go-gitea/gists{/gist_id}","starred_url":"https://api.github.com/users/go-gitea/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/go-gitea/subscriptions","organizations_url":"https://api.github.com/users/go-gitea/orgs","repos_url":"https://api.github.com/users/go-gitea/repos","events_url":"https://api.github.com/users/go-gitea/events{/privacy}","received_events_url":"https://api.github.com/users/go-gitea/received_events","type":"Organization","user_view_type":"public","site_admin":false},"html_url":"https://github.com/go-gitea/test_repo","description":"Test repository for testing migration from github to gitea","fork":false,"url":"https://api.github.com/repos/go-gitea/test_repo","forks_url":"https://api.github.com/repos/go-gitea/test_repo/forks","keys_url":"https://api.github.com/repos/go-gitea/test_repo/keys{/key_id}","collaborators_url":"https://api.github.com/repos/go-gitea/test_repo/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/go-gitea/test_repo/teams","hooks_url":"https://api.github.com/repos/go-gitea/test_repo/hooks","issue_events_url":"https://api.github.com/repos/go-gitea/test_repo/issues/events{/number}","events_url":"https://api.github.com/repos/go-gitea/test_repo/events","assignees_url":"https://api.github.com/repos/go-gitea/test_repo/assignees{/user}","branches_url":"https://api.github.com/repos/go-gitea/test_repo/branches{/branch}","tags_url":"https://api.github.com/repos/go-gitea/test_repo/tags","blobs_url":"https://api.github.com/repos/go-gitea/test_repo/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/go-gitea/test_repo/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/go-gitea/test_repo/git/refs{/sha}","trees_url":"https://api.github.com/repos/go-gitea/test_repo/git/trees{/sha}","statuses_url":"https://api.github.com/repos/go-gitea/test_repo/statuses/{sha}","languages_url":"https://api.github.com/repos/go-gitea/test_repo/languages","stargazers_url":"https://api.github.com/repos/go-gitea/test_repo/stargazers","contributors_url":"https://api.github.com/repos/go-gitea/test_repo/contributors","subscribers_url":"https://api.github.com/repos/go-gitea/test_repo/subscribers","subscription_url":"https://api.github.com/repos/go-gitea/test_repo/subscription","commits_url":"https://api.github.com/repos/go-gitea/test_repo/commits{/sha}","git_commits_url":"https://api.github.com/repos/go-gitea/test_repo/git/commits{/sha}","comments_url":"https://api.github.com/repos/go-gitea/test_repo/comments{/number}","issue_comment_url":"https://api.github.com/repos/go-gitea/test_repo/issues/comments{/number}","contents_url":"https://api.github.com/repos/go-gitea/test_repo/contents/{+path}","compare_url":"https://api.github.com/repos/go-gitea/test_repo/compare/{base}...{head}","merges_url":"https://api.github.com/repos/go-gitea/test_repo/merges","archive_url":"https://api.github.com/repos/go-gitea/test_repo/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/go-gitea/test_repo/downloads","issues_url":"https://api.github.com/repos/go-gitea/test_repo/issues{/number}","pulls_url":"https://api.github.com/repos/go-gitea/test_repo/pulls{/number}","milestones_url":"https://api.github.com/repos/go-gitea/test_repo/milestones{/number}","notifications_url":"https://api.github.com/repos/go-gitea/test_repo/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/go-gitea/test_repo/labels{/name}","releases_url":"https://api.github.com/repos/go-gitea/test_repo/releases{/id}","deployments_url":"https://api.github.com/repos/go-gitea/test_repo/deployments","created_at":"2019-11-09T16:49:20Z","updated_at":"2023-03-02T14:02:26Z","pushed_at":"2019-11-12T21:54:19Z","git_url":"git://github.com/go-gitea/test_repo.git","ssh_url":"git@github.com:go-gitea/test_repo.git","clone_url":"https://github.com/go-gitea/test_repo.git","svn_url":"https://github.com/go-gitea/test_repo","homepage":"https://gitea.com/test-repo","size":1,"stargazers_count":3,"watchers_count":3,"language":null,"has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"has_discussions":false,"forks_count":3,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":3,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"has_pull_requests":true,"pull_request_creation_policy":"all","topics":["gitea"],"visibility":"public","forks":3,"open_issues":3,"watchers":3,"default_branch":"master","permissions":{"admin":false,"maintain":true,"push":true,"triage":true,"pull":true},"custom_properties":{"vanta_production_branch_name":"main"},"organization":{"login":"go-gitea","id":12724356,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEyNzI0MzU2","avatar_url":"https://avatars.githubusercontent.com/u/12724356?v=4","gravatar_id":"","url":"https://api.github.com/users/go-gitea","html_url":"https://github.com/go-gitea","followers_url":"https://api.github.com/users/go-gitea/followers","following_url":"https://api.github.com/users/go-gitea/following{/other_user}","gists_url":"https://api.github.com/users/go-gitea/gists{/gist_id}","starred_url":"https://api.github.com/users/go-gitea/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/go-gitea/subscriptions","organizations_url":"https://api.github.com/users/go-gitea/orgs","repos_url":"https://api.github.com/users/go-gitea/repos","events_url":"https://api.github.com/users/go-gitea/events{/privacy}","received_events_url":"https://api.github.com/users/go-gitea/received_events","type":"Organization","user_view_type":"public","site_admin":false},"network_count":3,"subscribers_count":4} \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F1%2Freactions%3Fpage%3D1%26per_page%3D2 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F1%2Freactions%3Fpage%3D1%26per_page%3D2 new file mode 100644 index 00000000..4f602dfe --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F1%2Freactions%3Fpage%3D1%26per_page%3D2 @@ -0,0 +1,23 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: W/"93e41c3c4bea65e67bf69efd92c3b35de2086bf32d265bba99b2128b469a0f2a" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: issues=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; param=squirrel-girl-preview +X-Github-Request-Id: C4F6:A93E1:6A3CBA:5B27F2:69AF24E8 +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4930 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 70 +X-Xss-Protection: 0 + +[{"id":55441655,"node_id":"MDEzOklzc3VlUmVhY3Rpb241NTQ0MTY1NQ==","user":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?u=7c1ba931adbdd9bab5be1a41d244425d463568cd&v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"content":"+1","created_at":"2019-11-12T20:22:13Z"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F1%2Freactions%3Fpage%3D2%26per_page%3D2 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F1%2Freactions%3Fpage%3D2%26per_page%3D2 new file mode 100644 index 00000000..49afda33 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F1%2Freactions%3Fpage%3D2%26per_page%3D2 @@ -0,0 +1,25 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Length: 2 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: "440897bed2748f095d024d64264317f3f31eadc9413bf26dc0450eecbfbbef7b" +Link: ; rel="prev", ; rel="last", ; rel="first" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: issues=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; param=squirrel-girl-preview +X-Github-Request-Id: C4F6:A93E1:6A3E9A:5B29CC:69AF24E8 +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4929 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 71 +X-Xss-Protection: 0 + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F2%2Fcomments%3Fdirection%3Dasc%26per_page%3D100%26sort%3Dcreated b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F2%2Fcomments%3Fdirection%3Dasc%26per_page%3D100%26sort%3Dcreated new file mode 100644 index 00000000..1a20a130 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F2%2Fcomments%3Fdirection%3Dasc%26per_page%3D100%26sort%3Dcreated @@ -0,0 +1,23 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: W/"a6b46e35c9645e8f329af283e0f1cd6709c9d41ebc7ad811607a142f4f6f7332" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: issues=read; pull_requests=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; param=squirrel-girl-preview +X-Github-Request-Id: C4F6:A93E1:6A494E:5B32E2:69AF24EA +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4924 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 76 +X-Xss-Protection: 0 + +[{"url":"https://api.github.com/repos/go-gitea/test_repo/issues/comments/553111966","html_url":"https://github.com/go-gitea/test_repo/issues/2#issuecomment-553111966","issue_url":"https://api.github.com/repos/go-gitea/test_repo/issues/2","id":553111966,"node_id":"MDEyOklzc3VlQ29tbWVudDU1MzExMTk2Ng==","user":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"created_at":"2019-11-12T21:00:13Z","updated_at":"2019-11-12T21:00:13Z","body":"This is a comment","author_association":"MEMBER","pin":null,"reactions":{"url":"https://api.github.com/repos/go-gitea/test_repo/issues/comments/553111966/reactions","total_count":1,"+1":1,"-1":0,"laugh":0,"hooray":0,"confused":0,"heart":0,"rocket":0,"eyes":0},"performed_via_github_app":null},{"url":"https://api.github.com/repos/go-gitea/test_repo/issues/comments/553138856","html_url":"https://github.com/go-gitea/test_repo/issues/2#issuecomment-553138856","issue_url":"https://api.github.com/repos/go-gitea/test_repo/issues/2","id":553138856,"node_id":"MDEyOklzc3VlQ29tbWVudDU1MzEzODg1Ng==","user":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"created_at":"2019-11-12T22:07:14Z","updated_at":"2019-11-12T22:07:14Z","body":"A second comment","author_association":"MEMBER","pin":null,"reactions":{"url":"https://api.github.com/repos/go-gitea/test_repo/issues/comments/553138856/reactions","total_count":0,"+1":0,"-1":0,"laugh":0,"hooray":0,"confused":0,"heart":0,"rocket":0,"eyes":0},"performed_via_github_app":null}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F2%2Freactions%3Fpage%3D1%26per_page%3D2 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F2%2Freactions%3Fpage%3D1%26per_page%3D2 new file mode 100644 index 00000000..c81db801 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F2%2Freactions%3Fpage%3D1%26per_page%3D2 @@ -0,0 +1,24 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: W/"9c80e4756af3227671cb0bde1c1798372e9ab36d1d8c27c5332d14ab201b07bd" +Link: ; rel="next", ; rel="last" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: issues=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; param=squirrel-girl-preview +X-Github-Request-Id: C4F6:A93E1:6A40BF:5B2B98:69AF24E8 +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4928 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 72 +X-Xss-Protection: 0 + +[{"id":55445108,"node_id":"MDEzOklzc3VlUmVhY3Rpb241NTQ0NTEwOA==","user":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?u=7c1ba931adbdd9bab5be1a41d244425d463568cd&v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"content":"heart","created_at":"2019-11-12T21:02:05Z"},{"id":55445150,"node_id":"MDEzOklzc3VlUmVhY3Rpb241NTQ0NTE1MA==","user":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?u=7c1ba931adbdd9bab5be1a41d244425d463568cd&v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"content":"laugh","created_at":"2019-11-12T21:02:35Z"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F2%2Freactions%3Fpage%3D2%26per_page%3D2 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F2%2Freactions%3Fpage%3D2%26per_page%3D2 new file mode 100644 index 00000000..308262c1 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F2%2Freactions%3Fpage%3D2%26per_page%3D2 @@ -0,0 +1,24 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: W/"2df1254488e1d85bd03b21124ee9d20468fa1297c34aa3d347771f1f6035ee01" +Link: ; rel="prev", ; rel="next", ; rel="last", ; rel="first" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: issues=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; param=squirrel-girl-preview +X-Github-Request-Id: C4F6:A93E1:6A4345:5B2DBE:69AF24E9 +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4927 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 73 +X-Xss-Protection: 0 + +[{"id":55445169,"node_id":"MDEzOklzc3VlUmVhY3Rpb241NTQ0NTE2OQ==","user":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?u=7c1ba931adbdd9bab5be1a41d244425d463568cd&v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"content":"-1","created_at":"2019-11-12T21:02:47Z"},{"id":55445177,"node_id":"MDEzOklzc3VlUmVhY3Rpb241NTQ0NTE3Nw==","user":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?u=7c1ba931adbdd9bab5be1a41d244425d463568cd&v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"content":"confused","created_at":"2019-11-12T21:02:52Z"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F2%2Freactions%3Fpage%3D3%26per_page%3D2 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F2%2Freactions%3Fpage%3D3%26per_page%3D2 new file mode 100644 index 00000000..b82e9fe3 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F2%2Freactions%3Fpage%3D3%26per_page%3D2 @@ -0,0 +1,24 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: W/"bc8bfbd8766b50c610b6d7933bdcb10497b92df72b007e78dac92be18c6e9e71" +Link: ; rel="prev", ; rel="first" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: issues=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; param=squirrel-girl-preview +X-Github-Request-Id: C4F6:A93E1:6A452E:5B2F62:69AF24E9 +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4926 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 74 +X-Xss-Protection: 0 + +[{"id":55445188,"node_id":"MDEzOklzc3VlUmVhY3Rpb241NTQ0NTE4OA==","user":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?u=7c1ba931adbdd9bab5be1a41d244425d463568cd&v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"content":"hooray","created_at":"2019-11-12T21:02:58Z"},{"id":55445441,"node_id":"MDEzOklzc3VlUmVhY3Rpb241NTQ0NTQ0MQ==","user":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?u=7c1ba931adbdd9bab5be1a41d244425d463568cd&v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"content":"+1","created_at":"2019-11-12T21:06:04Z"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F2%2Freactions%3Fpage%3D4%26per_page%3D2 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F2%2Freactions%3Fpage%3D4%26per_page%3D2 new file mode 100644 index 00000000..333a2f69 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F2%2Freactions%3Fpage%3D4%26per_page%3D2 @@ -0,0 +1,25 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Length: 2 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: "440897bed2748f095d024d64264317f3f31eadc9413bf26dc0450eecbfbbef7b" +Link: ; rel="prev", ; rel="last", ; rel="first" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: issues=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; param=squirrel-girl-preview +X-Github-Request-Id: C4F6:A93E1:6A4762:5B313E:69AF24E9 +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4925 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 75 +X-Xss-Protection: 0 + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F3%2Freactions%3Fpage%3D1%26per_page%3D2 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F3%2Freactions%3Fpage%3D1%26per_page%3D2 new file mode 100644 index 00000000..7701572a --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F3%2Freactions%3Fpage%3D1%26per_page%3D2 @@ -0,0 +1,24 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Length: 2 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: "440897bed2748f095d024d64264317f3f31eadc9413bf26dc0450eecbfbbef7b" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: issues=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; param=squirrel-girl-preview +X-Github-Request-Id: C4F6:A93E1:6A5190:5B3A2F:69AF24EB +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4919 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 81 +X-Xss-Protection: 0 + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F4%2Freactions%3Fpage%3D1%26per_page%3D2 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F4%2Freactions%3Fpage%3D1%26per_page%3D2 new file mode 100644 index 00000000..89b2c158 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F4%2Freactions%3Fpage%3D1%26per_page%3D2 @@ -0,0 +1,23 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: W/"28ed9be77bd4b321f93ff1cf9a8ca1b27a7a6eb9cb1495e138864a1b229b3618" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: issues=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; param=squirrel-girl-preview +X-Github-Request-Id: C4F6:A93E1:6A5612:5B3DFA:69AF24EC +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4918 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 82 +X-Xss-Protection: 0 + +[{"id":59496724,"node_id":"MDEzOklzc3VlUmVhY3Rpb241OTQ5NjcyNA==","user":{"login":"lunny","id":81045,"node_id":"MDQ6VXNlcjgxMDQ1","avatar_url":"https://avatars.githubusercontent.com/u/81045?u=99b64f0ca6ef63643c7583ab87dd31c52d28e673&v=4","gravatar_id":"","url":"https://api.github.com/users/lunny","html_url":"https://github.com/lunny","followers_url":"https://api.github.com/users/lunny/followers","following_url":"https://api.github.com/users/lunny/following{/other_user}","gists_url":"https://api.github.com/users/lunny/gists{/gist_id}","starred_url":"https://api.github.com/users/lunny/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lunny/subscriptions","organizations_url":"https://api.github.com/users/lunny/orgs","repos_url":"https://api.github.com/users/lunny/repos","events_url":"https://api.github.com/users/lunny/events{/privacy}","received_events_url":"https://api.github.com/users/lunny/received_events","type":"User","user_view_type":"public","site_admin":false},"content":"heart","created_at":"2020-01-10T08:31:30Z"},{"id":59496731,"node_id":"MDEzOklzc3VlUmVhY3Rpb241OTQ5NjczMQ==","user":{"login":"lunny","id":81045,"node_id":"MDQ6VXNlcjgxMDQ1","avatar_url":"https://avatars.githubusercontent.com/u/81045?u=99b64f0ca6ef63643c7583ab87dd31c52d28e673&v=4","gravatar_id":"","url":"https://api.github.com/users/lunny","html_url":"https://github.com/lunny","followers_url":"https://api.github.com/users/lunny/followers","following_url":"https://api.github.com/users/lunny/following{/other_user}","gists_url":"https://api.github.com/users/lunny/gists{/gist_id}","starred_url":"https://api.github.com/users/lunny/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lunny/subscriptions","organizations_url":"https://api.github.com/users/lunny/orgs","repos_url":"https://api.github.com/users/lunny/repos","events_url":"https://api.github.com/users/lunny/events{/privacy}","received_events_url":"https://api.github.com/users/lunny/received_events","type":"User","user_view_type":"public","site_admin":false},"content":"+1","created_at":"2020-01-10T08:31:39Z"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F4%2Freactions%3Fpage%3D2%26per_page%3D2 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F4%2Freactions%3Fpage%3D2%26per_page%3D2 new file mode 100644 index 00000000..7795ad40 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2F4%2Freactions%3Fpage%3D2%26per_page%3D2 @@ -0,0 +1,25 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Length: 2 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: "440897bed2748f095d024d64264317f3f31eadc9413bf26dc0450eecbfbbef7b" +Link: ; rel="prev", ; rel="last", ; rel="first" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: issues=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; param=squirrel-girl-preview +X-Github-Request-Id: C4F6:A93E1:6A5886:5B402D:69AF24EC +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4917 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 83 +X-Xss-Protection: 0 + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2Fcomments%2F553111966%2Freactions%3Fpage%3D1%26per_page%3D100 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2Fcomments%2F553111966%2Freactions%3Fpage%3D1%26per_page%3D100 new file mode 100644 index 00000000..3b181445 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2Fcomments%2F553111966%2Freactions%3Fpage%3D1%26per_page%3D100 @@ -0,0 +1,23 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: W/"1555b1716eec684789b7de36b017090fb2c1b1f1f3264cfdb120d9af0428b43d" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: issues=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; param=squirrel-girl-preview +X-Github-Request-Id: C4F6:A93E1:6A4AF3:5B343F:69AF24EA +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4923 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 77 +X-Xss-Protection: 0 + +[{"id":55446208,"node_id":"MDIwOklzc3VlQ29tbWVudFJlYWN0aW9uNTU0NDYyMDg=","user":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"content":"+1","created_at":"2019-11-12T21:13:22Z"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2Fcomments%2F553111966%2Freactions%3Fpage%3D2%26per_page%3D100 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2Fcomments%2F553111966%2Freactions%3Fpage%3D2%26per_page%3D100 new file mode 100644 index 00000000..dd9a7682 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2Fcomments%2F553111966%2Freactions%3Fpage%3D2%26per_page%3D100 @@ -0,0 +1,25 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Length: 2 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: "440897bed2748f095d024d64264317f3f31eadc9413bf26dc0450eecbfbbef7b" +Link: ; rel="prev", ; rel="last", ; rel="first" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: issues=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; param=squirrel-girl-preview +X-Github-Request-Id: C4F6:A93E1:6A4C94:5B35BA:69AF24EA +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4922 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 78 +X-Xss-Protection: 0 + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2Fcomments%2F553138856%2Freactions%3Fpage%3D1%26per_page%3D100 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2Fcomments%2F553138856%2Freactions%3Fpage%3D1%26per_page%3D100 new file mode 100644 index 00000000..7adba95f --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%2Fcomments%2F553138856%2Freactions%3Fpage%3D1%26per_page%3D100 @@ -0,0 +1,24 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Length: 2 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: "440897bed2748f095d024d64264317f3f31eadc9413bf26dc0450eecbfbbef7b" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: issues=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; param=squirrel-girl-preview +X-Github-Request-Id: C4F6:A93E1:6A4E12:5B36FD:69AF24EA +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4921 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 79 +X-Xss-Protection: 0 + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%3Fdirection%3Dasc%26page%3D1%26per_page%3D2%26sort%3Dcreated%26state%3Dall b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%3Fdirection%3Dasc%26page%3D1%26per_page%3D2%26sort%3Dcreated%26state%3Dall new file mode 100644 index 00000000..73154f44 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fissues%3Fdirection%3Dasc%26page%3D1%26per_page%3D2%26sort%3Dcreated%26state%3Dall @@ -0,0 +1,24 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: W/"4d1d8ecb86bafe76a686d250018cc158745dd6bc794ef651eeeeecbfc1a947bc" +Link: ; rel="next", ; rel="last" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: issues=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; param=squirrel-girl-preview +X-Github-Request-Id: C4F6:A93E1:6A3A9E:5B260C:69AF24E7 +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4931 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 69 +X-Xss-Protection: 0 + +[{"url":"https://api.github.com/repos/go-gitea/test_repo/issues/1","repository_url":"https://api.github.com/repos/go-gitea/test_repo","labels_url":"https://api.github.com/repos/go-gitea/test_repo/issues/1/labels{/name}","comments_url":"https://api.github.com/repos/go-gitea/test_repo/issues/1/comments","events_url":"https://api.github.com/repos/go-gitea/test_repo/issues/1/events","html_url":"https://github.com/go-gitea/test_repo/issues/1","id":520479843,"node_id":"MDU6SXNzdWU1MjA0Nzk4NDM=","number":1,"title":"Please add an animated gif icon to the merge button","user":{"login":"guillep2k","id":18600385,"node_id":"MDQ6VXNlcjE4NjAwMzg1","avatar_url":"https://avatars.githubusercontent.com/u/18600385?v=4","gravatar_id":"","url":"https://api.github.com/users/guillep2k","html_url":"https://github.com/guillep2k","followers_url":"https://api.github.com/users/guillep2k/followers","following_url":"https://api.github.com/users/guillep2k/following{/other_user}","gists_url":"https://api.github.com/users/guillep2k/gists{/gist_id}","starred_url":"https://api.github.com/users/guillep2k/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/guillep2k/subscriptions","organizations_url":"https://api.github.com/users/guillep2k/orgs","repos_url":"https://api.github.com/users/guillep2k/repos","events_url":"https://api.github.com/users/guillep2k/events{/privacy}","received_events_url":"https://api.github.com/users/guillep2k/received_events","type":"User","user_view_type":"public","site_admin":false},"labels":[{"id":1667254252,"node_id":"MDU6TGFiZWwxNjY3MjU0MjUy","url":"https://api.github.com/repos/go-gitea/test_repo/labels/bug","name":"bug","color":"d73a4a","default":true,"description":"Something isn't working"},{"id":1667254261,"node_id":"MDU6TGFiZWwxNjY3MjU0MjYx","url":"https://api.github.com/repos/go-gitea/test_repo/labels/good%20first%20issue","name":"good first issue","color":"7057ff","default":true,"description":"Good for newcomers"}],"state":"closed","locked":false,"assignees":[],"milestone":{"url":"https://api.github.com/repos/go-gitea/test_repo/milestones/1","html_url":"https://github.com/go-gitea/test_repo/milestone/1","labels_url":"https://api.github.com/repos/go-gitea/test_repo/milestones/1/labels","id":4839941,"node_id":"MDk6TWlsZXN0b25lNDgzOTk0MQ==","number":1,"title":"1.0.0","description":"Milestone 1.0.0","creator":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"open_issues":1,"closed_issues":1,"state":"closed","created_at":"2019-11-12T19:37:08Z","updated_at":"2019-11-12T21:56:17Z","due_on":"2019-11-11T00:00:00Z","closed_at":"2019-11-12T19:45:49Z"},"comments":0,"created_at":"2019-11-09T17:00:29Z","updated_at":"2019-11-12T20:29:53Z","closed_at":"2019-11-12T20:22:22Z","assignee":null,"author_association":"MEMBER","type":null,"active_lock_reason":null,"sub_issues_summary":{"total":0,"completed":0,"percent_completed":0},"issue_dependencies_summary":{"blocked_by":0,"total_blocked_by":0,"blocking":0,"total_blocking":0},"body":"I just want the merge button to hurt my eyes a little. 😝 ","closed_by":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"reactions":{"url":"https://api.github.com/repos/go-gitea/test_repo/issues/1/reactions","total_count":1,"+1":1,"-1":0,"laugh":0,"hooray":0,"confused":0,"heart":0,"rocket":0,"eyes":0},"timeline_url":"https://api.github.com/repos/go-gitea/test_repo/issues/1/timeline","performed_via_github_app":null,"state_reason":"completed","pinned_comment":null},{"url":"https://api.github.com/repos/go-gitea/test_repo/issues/2","repository_url":"https://api.github.com/repos/go-gitea/test_repo","labels_url":"https://api.github.com/repos/go-gitea/test_repo/issues/2/labels{/name}","comments_url":"https://api.github.com/repos/go-gitea/test_repo/issues/2/comments","events_url":"https://api.github.com/repos/go-gitea/test_repo/issues/2/events","html_url":"https://github.com/go-gitea/test_repo/issues/2","id":521799485,"node_id":"MDU6SXNzdWU1MjE3OTk0ODU=","number":2,"title":"Test issue","user":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"labels":[{"id":1667254257,"node_id":"MDU6TGFiZWwxNjY3MjU0MjU3","url":"https://api.github.com/repos/go-gitea/test_repo/labels/duplicate","name":"duplicate","color":"cfd3d7","default":true,"description":"This issue or pull request already exists"}],"state":"closed","locked":false,"assignees":[],"milestone":{"url":"https://api.github.com/repos/go-gitea/test_repo/milestones/2","html_url":"https://github.com/go-gitea/test_repo/milestone/2","labels_url":"https://api.github.com/repos/go-gitea/test_repo/milestones/2/labels","id":4839942,"node_id":"MDk6TWlsZXN0b25lNDgzOTk0Mg==","number":2,"title":"1.1.0","description":"Milestone 1.1.0","creator":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"open_issues":0,"closed_issues":2,"state":"closed","created_at":"2019-11-12T19:37:25Z","updated_at":"2019-11-12T21:39:27Z","due_on":"2019-11-12T00:00:00Z","closed_at":"2019-11-12T19:45:46Z"},"comments":2,"created_at":"2019-11-12T21:00:06Z","updated_at":"2019-11-12T22:07:14Z","closed_at":"2019-11-12T21:01:31Z","assignee":null,"author_association":"MEMBER","type":null,"active_lock_reason":null,"sub_issues_summary":{"total":0,"completed":0,"percent_completed":0},"issue_dependencies_summary":{"blocked_by":0,"total_blocked_by":0,"blocking":0,"total_blocking":0},"body":"This is test issue 2, do not touch!","closed_by":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"reactions":{"url":"https://api.github.com/repos/go-gitea/test_repo/issues/2/reactions","total_count":6,"+1":1,"-1":1,"laugh":1,"hooray":1,"confused":1,"heart":1,"rocket":0,"eyes":0},"timeline_url":"https://api.github.com/repos/go-gitea/test_repo/issues/2/timeline","performed_via_github_app":null,"state_reason":"completed","pinned_comment":null}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Flabels%3Fpage%3D1%26per_page%3D100 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Flabels%3Fpage%3D1%26per_page%3D100 new file mode 100644 index 00000000..2a8f7ba3 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Flabels%3Fpage%3D1%26per_page%3D100 @@ -0,0 +1,23 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: W/"ea38b60f45fc2583351b3e4cc26f7e7a1b0ba2f6545b0e2dac7ffc5eea59c03e" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: issues=read; pull_requests=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; format=json +X-Github-Request-Id: C4F6:A93E1:6A36E8:5B22E4:69AF24E7 +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4933 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 67 +X-Xss-Protection: 0 + +[{"id":1667254252,"node_id":"MDU6TGFiZWwxNjY3MjU0MjUy","url":"https://api.github.com/repos/go-gitea/test_repo/labels/bug","name":"bug","color":"d73a4a","default":true,"description":"Something isn't working"},{"id":1667254254,"node_id":"MDU6TGFiZWwxNjY3MjU0MjU0","url":"https://api.github.com/repos/go-gitea/test_repo/labels/documentation","name":"documentation","color":"0075ca","default":true,"description":"Improvements or additions to documentation"},{"id":1667254257,"node_id":"MDU6TGFiZWwxNjY3MjU0MjU3","url":"https://api.github.com/repos/go-gitea/test_repo/labels/duplicate","name":"duplicate","color":"cfd3d7","default":true,"description":"This issue or pull request already exists"},{"id":1667254260,"node_id":"MDU6TGFiZWwxNjY3MjU0MjYw","url":"https://api.github.com/repos/go-gitea/test_repo/labels/enhancement","name":"enhancement","color":"a2eeef","default":true,"description":"New feature or request"},{"id":1667254261,"node_id":"MDU6TGFiZWwxNjY3MjU0MjYx","url":"https://api.github.com/repos/go-gitea/test_repo/labels/good%20first%20issue","name":"good first issue","color":"7057ff","default":true,"description":"Good for newcomers"},{"id":1667254265,"node_id":"MDU6TGFiZWwxNjY3MjU0MjY1","url":"https://api.github.com/repos/go-gitea/test_repo/labels/help%20wanted","name":"help wanted","color":"008672","default":true,"description":"Extra attention is needed"},{"id":1667254269,"node_id":"MDU6TGFiZWwxNjY3MjU0MjY5","url":"https://api.github.com/repos/go-gitea/test_repo/labels/invalid","name":"invalid","color":"e4e669","default":true,"description":"This doesn't seem right"},{"id":1667254273,"node_id":"MDU6TGFiZWwxNjY3MjU0Mjcz","url":"https://api.github.com/repos/go-gitea/test_repo/labels/question","name":"question","color":"d876e3","default":true,"description":"Further information is requested"},{"id":1667254276,"node_id":"MDU6TGFiZWwxNjY3MjU0Mjc2","url":"https://api.github.com/repos/go-gitea/test_repo/labels/wontfix","name":"wontfix","color":"ffffff","default":true,"description":"This will not be worked on"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fmilestones%3Fpage%3D1%26per_page%3D100%26state%3Dall b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fmilestones%3Fpage%3D1%26per_page%3D100%26state%3Dall new file mode 100644 index 00000000..0eda560b --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fmilestones%3Fpage%3D1%26per_page%3D100%26state%3Dall @@ -0,0 +1,23 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: W/"c2c4c54255928bb9bebc8c65c989b904b06ffb4eb763f804d70dbb40473d3122" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: issues=read; pull_requests=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; format=json +X-Github-Request-Id: C4F6:A93E1:6A356B:5B2172:69AF24E7 +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4934 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 66 +X-Xss-Protection: 0 + +[{"url":"https://api.github.com/repos/go-gitea/test_repo/milestones/1","html_url":"https://github.com/go-gitea/test_repo/milestone/1","labels_url":"https://api.github.com/repos/go-gitea/test_repo/milestones/1/labels","id":4839941,"node_id":"MDk6TWlsZXN0b25lNDgzOTk0MQ==","number":1,"title":"1.0.0","description":"Milestone 1.0.0","creator":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"open_issues":1,"closed_issues":1,"state":"closed","created_at":"2019-11-12T19:37:08Z","updated_at":"2019-11-12T21:56:17Z","due_on":"2019-11-11T00:00:00Z","closed_at":"2019-11-12T19:45:49Z"},{"url":"https://api.github.com/repos/go-gitea/test_repo/milestones/2","html_url":"https://github.com/go-gitea/test_repo/milestone/2","labels_url":"https://api.github.com/repos/go-gitea/test_repo/milestones/2/labels","id":4839942,"node_id":"MDk6TWlsZXN0b25lNDgzOTk0Mg==","number":2,"title":"1.1.0","description":"Milestone 1.1.0","creator":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"open_issues":0,"closed_issues":2,"state":"closed","created_at":"2019-11-12T19:37:25Z","updated_at":"2019-11-12T21:39:27Z","due_on":"2019-11-12T00:00:00Z","closed_at":"2019-11-12T19:45:46Z"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F3%2Frequested_reviewers b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F3%2Frequested_reviewers new file mode 100644 index 00000000..ecf6a3a5 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F3%2Frequested_reviewers @@ -0,0 +1,23 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: W/"db6d3f5496df397024cfe34bfce143f4940ddf0e169ffcb7c24343afcd0ce6b1" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: pull_requests=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; format=json +X-Github-Request-Id: C4F6:A93E1:6A628A:5B48F4:69AF24EE +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4912 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 88 +X-Xss-Protection: 0 + +{"users":[],"teams":[]} \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F3%2Freviews%2F315859956%2Fcomments%3Fper_page%3D100 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F3%2Freviews%2F315859956%2Fcomments%3Fper_page%3D100 new file mode 100644 index 00000000..60c33488 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F3%2Freviews%2F315859956%2Fcomments%3Fper_page%3D100 @@ -0,0 +1,24 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Length: 2 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: "7b5b784c0a881ecba5ae21871c054e30f6d6fef4c73d12a917530925ea2b258a" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: pull_requests=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; format=json +X-Github-Request-Id: C4F6:A93E1:6A5D81:5B4466:69AF24ED +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4915 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 85 +X-Xss-Protection: 0 + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F3%2Freviews%2F315860062%2Fcomments%3Fper_page%3D100 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F3%2Freviews%2F315860062%2Fcomments%3Fper_page%3D100 new file mode 100644 index 00000000..190df1ea --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F3%2Freviews%2F315860062%2Fcomments%3Fper_page%3D100 @@ -0,0 +1,24 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Length: 2 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: "7b5b784c0a881ecba5ae21871c054e30f6d6fef4c73d12a917530925ea2b258a" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: pull_requests=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; format=json +X-Github-Request-Id: C4F6:A93E1:6A5F1B:5B45DB:69AF24ED +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4914 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 86 +X-Xss-Protection: 0 + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F3%2Freviews%2F315861440%2Fcomments%3Fper_page%3D100 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F3%2Freviews%2F315861440%2Fcomments%3Fper_page%3D100 new file mode 100644 index 00000000..7fd19617 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F3%2Freviews%2F315861440%2Fcomments%3Fper_page%3D100 @@ -0,0 +1,24 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Length: 2 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: "7b5b784c0a881ecba5ae21871c054e30f6d6fef4c73d12a917530925ea2b258a" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: pull_requests=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; format=json +X-Github-Request-Id: C4F6:A93E1:6A60C3:5B4760:69AF24ED +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4913 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 87 +X-Xss-Protection: 0 + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F3%2Freviews%3Fper_page%3D100 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F3%2Freviews%3Fper_page%3D100 new file mode 100644 index 00000000..6ff0bf9c --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F3%2Freviews%3Fper_page%3D100 @@ -0,0 +1,23 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: W/"3f634d6cfe0d88ce43a5d40e74ca0d79ec9c242bee77582ad8d889491a72fefc" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: pull_requests=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; format=json +X-Github-Request-Id: C4F6:A93E1:6A5A92:5B41D6:69AF24EC +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4916 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 84 +X-Xss-Protection: 0 + +[{"id":315859956,"node_id":"MDE3OlB1bGxSZXF1ZXN0UmV2aWV3MzE1ODU5OTU2","user":{"login":"jolheiser","id":42128690,"node_id":"MDQ6VXNlcjQyMTI4Njkw","avatar_url":"https://avatars.githubusercontent.com/u/42128690?u=0ee1052506846129445fa12a76cd9ad9d305de71&v=4","gravatar_id":"","url":"https://api.github.com/users/jolheiser","html_url":"https://github.com/jolheiser","followers_url":"https://api.github.com/users/jolheiser/followers","following_url":"https://api.github.com/users/jolheiser/following{/other_user}","gists_url":"https://api.github.com/users/jolheiser/gists{/gist_id}","starred_url":"https://api.github.com/users/jolheiser/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jolheiser/subscriptions","organizations_url":"https://api.github.com/users/jolheiser/orgs","repos_url":"https://api.github.com/users/jolheiser/repos","events_url":"https://api.github.com/users/jolheiser/events{/privacy}","received_events_url":"https://api.github.com/users/jolheiser/received_events","type":"User","user_view_type":"public","site_admin":false},"body":"","state":"APPROVED","html_url":"https://github.com/go-gitea/test_repo/pull/3#pullrequestreview-315859956","pull_request_url":"https://api.github.com/repos/go-gitea/test_repo/pulls/3","author_association":"MEMBER","_links":{"html":{"href":"https://github.com/go-gitea/test_repo/pull/3#pullrequestreview-315859956"},"pull_request":{"href":"https://api.github.com/repos/go-gitea/test_repo/pulls/3"}},"submitted_at":"2019-11-12T21:35:24Z","commit_id":"076160cf0b039f13e5eff19619932d181269414b"},{"id":315860062,"node_id":"MDE3OlB1bGxSZXF1ZXN0UmV2aWV3MzE1ODYwMDYy","user":{"login":"zeripath","id":1824502,"node_id":"MDQ6VXNlcjE4MjQ1MDI=","avatar_url":"https://avatars.githubusercontent.com/u/1824502?u=fcd8a9dba8714edf6ac3f87596eb72149911c720&v=4","gravatar_id":"","url":"https://api.github.com/users/zeripath","html_url":"https://github.com/zeripath","followers_url":"https://api.github.com/users/zeripath/followers","following_url":"https://api.github.com/users/zeripath/following{/other_user}","gists_url":"https://api.github.com/users/zeripath/gists{/gist_id}","starred_url":"https://api.github.com/users/zeripath/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zeripath/subscriptions","organizations_url":"https://api.github.com/users/zeripath/orgs","repos_url":"https://api.github.com/users/zeripath/repos","events_url":"https://api.github.com/users/zeripath/events{/privacy}","received_events_url":"https://api.github.com/users/zeripath/received_events","type":"User","user_view_type":"public","site_admin":false},"body":"","state":"APPROVED","html_url":"https://github.com/go-gitea/test_repo/pull/3#pullrequestreview-315860062","pull_request_url":"https://api.github.com/repos/go-gitea/test_repo/pulls/3","author_association":"MEMBER","_links":{"html":{"href":"https://github.com/go-gitea/test_repo/pull/3#pullrequestreview-315860062"},"pull_request":{"href":"https://api.github.com/repos/go-gitea/test_repo/pulls/3"}},"submitted_at":"2019-11-12T21:35:36Z","commit_id":"076160cf0b039f13e5eff19619932d181269414b"},{"id":315861440,"node_id":"MDE3OlB1bGxSZXF1ZXN0UmV2aWV3MzE1ODYxNDQw","user":{"login":"lafriks","id":165205,"node_id":"MDQ6VXNlcjE2NTIwNQ==","avatar_url":"https://avatars.githubusercontent.com/u/165205?u=efe2335d2197f524c25caa7abdfcb90b77eb8d98&v=4","gravatar_id":"","url":"https://api.github.com/users/lafriks","html_url":"https://github.com/lafriks","followers_url":"https://api.github.com/users/lafriks/followers","following_url":"https://api.github.com/users/lafriks/following{/other_user}","gists_url":"https://api.github.com/users/lafriks/gists{/gist_id}","starred_url":"https://api.github.com/users/lafriks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lafriks/subscriptions","organizations_url":"https://api.github.com/users/lafriks/orgs","repos_url":"https://api.github.com/users/lafriks/repos","events_url":"https://api.github.com/users/lafriks/events{/privacy}","received_events_url":"https://api.github.com/users/lafriks/received_events","type":"User","user_view_type":"public","site_admin":false},"body":"","state":"APPROVED","html_url":"https://github.com/go-gitea/test_repo/pull/3#pullrequestreview-315861440","pull_request_url":"https://api.github.com/repos/go-gitea/test_repo/pulls/3","author_association":"MEMBER","_links":{"html":{"href":"https://github.com/go-gitea/test_repo/pull/3#pullrequestreview-315861440"},"pull_request":{"href":"https://api.github.com/repos/go-gitea/test_repo/pulls/3"}},"submitted_at":"2019-11-12T21:38:00Z","commit_id":"076160cf0b039f13e5eff19619932d181269414b"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F4%2Frequested_reviewers b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F4%2Frequested_reviewers new file mode 100644 index 00000000..d6b38603 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F4%2Frequested_reviewers @@ -0,0 +1,23 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: W/"db6d3f5496df397024cfe34bfce143f4940ddf0e169ffcb7c24343afcd0ce6b1" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: pull_requests=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; format=json +X-Github-Request-Id: C4F6:A93E1:6A7048:5B54F3:69AF24F0 +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4905 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 95 +X-Xss-Protection: 0 + +{"users":[],"teams":[]} \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F4%2Freviews%2F338338740%2Fcomments%3Fper_page%3D100 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F4%2Freviews%2F338338740%2Fcomments%3Fper_page%3D100 new file mode 100644 index 00000000..d6554c42 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F4%2Freviews%2F338338740%2Fcomments%3Fper_page%3D100 @@ -0,0 +1,23 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: W/"8f714d80f3d155fff562fefb57d0e91261d5647dfc0e5d2f68f5567937814326" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: pull_requests=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; format=json +X-Github-Request-Id: C4F6:A93E1:6A6731:5B4CF6:69AF24EE +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4910 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 90 +X-Xss-Protection: 0 + +[{"id":363017488,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDM2MzAxNzQ4OA==","url":"https://api.github.com/repos/go-gitea/test_repo/pulls/comments/363017488","pull_request_review_id":338338740,"diff_hunk":"@@ -1,2 +1,4 @@\n # test_repo\n Test repository for testing migration from github to gitea\n+","path":"README.md","position":3,"original_position":3,"commit_id":"2be9101c543658591222acbee3eb799edfc3853d","user":{"login":"lunny","id":81045,"node_id":"MDQ6VXNlcjgxMDQ1","avatar_url":"https://avatars.githubusercontent.com/u/81045?v=4","gravatar_id":"","url":"https://api.github.com/users/lunny","html_url":"https://github.com/lunny","followers_url":"https://api.github.com/users/lunny/followers","following_url":"https://api.github.com/users/lunny/following{/other_user}","gists_url":"https://api.github.com/users/lunny/gists{/gist_id}","starred_url":"https://api.github.com/users/lunny/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lunny/subscriptions","organizations_url":"https://api.github.com/users/lunny/orgs","repos_url":"https://api.github.com/users/lunny/repos","events_url":"https://api.github.com/users/lunny/events{/privacy}","received_events_url":"https://api.github.com/users/lunny/received_events","type":"User","user_view_type":"public","site_admin":false},"body":"This is a good pull request.","created_at":"2020-01-04T05:33:06Z","updated_at":"2020-01-04T05:33:18Z","html_url":"https://github.com/go-gitea/test_repo/pull/4#discussion_r363017488","pull_request_url":"https://api.github.com/repos/go-gitea/test_repo/pulls/4","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/go-gitea/test_repo/pulls/comments/363017488"},"html":{"href":"https://github.com/go-gitea/test_repo/pull/4#discussion_r363017488"},"pull_request":{"href":"https://api.github.com/repos/go-gitea/test_repo/pulls/4"}},"original_commit_id":"2be9101c543658591222acbee3eb799edfc3853d","reactions":{"url":"https://api.github.com/repos/go-gitea/test_repo/pulls/comments/363017488/reactions","total_count":0,"+1":0,"-1":0,"laugh":0,"hooray":0,"confused":0,"heart":0,"rocket":0,"eyes":0}}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F4%2Freviews%2F338339651%2Fcomments%3Fper_page%3D100 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F4%2Freviews%2F338339651%2Fcomments%3Fper_page%3D100 new file mode 100644 index 00000000..27d36619 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F4%2Freviews%2F338339651%2Fcomments%3Fper_page%3D100 @@ -0,0 +1,24 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Length: 2 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: "7b5b784c0a881ecba5ae21871c054e30f6d6fef4c73d12a917530925ea2b258a" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: pull_requests=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; format=json +X-Github-Request-Id: C4F6:A93E1:6A6B06:5B5056:69AF24EF +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4908 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 92 +X-Xss-Protection: 0 + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F4%2Freviews%2F338349019%2Fcomments%3Fper_page%3D100 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F4%2Freviews%2F338349019%2Fcomments%3Fper_page%3D100 new file mode 100644 index 00000000..86af31a7 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F4%2Freviews%2F338349019%2Fcomments%3Fper_page%3D100 @@ -0,0 +1,23 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: W/"69b86138edd30116a19b2236faee0e90afecfda0f12903fb6f38e180a06d1daf" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: pull_requests=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; format=json +X-Github-Request-Id: C4F6:A93E1:6A6C8F:5B5195:69AF24EF +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4907 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 93 +X-Xss-Protection: 0 + +[{"id":363029944,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDM2MzAyOTk0NA==","url":"https://api.github.com/repos/go-gitea/test_repo/pulls/comments/363029944","pull_request_review_id":338349019,"diff_hunk":"@@ -19,3 +19,5 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n+","path":"LICENSE","position":4,"original_position":4,"commit_id":"2be9101c543658591222acbee3eb799edfc3853d","user":{"login":"lunny","id":81045,"node_id":"MDQ6VXNlcjgxMDQ1","avatar_url":"https://avatars.githubusercontent.com/u/81045?v=4","gravatar_id":"","url":"https://api.github.com/users/lunny","html_url":"https://github.com/lunny","followers_url":"https://api.github.com/users/lunny/followers","following_url":"https://api.github.com/users/lunny/following{/other_user}","gists_url":"https://api.github.com/users/lunny/gists{/gist_id}","starred_url":"https://api.github.com/users/lunny/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lunny/subscriptions","organizations_url":"https://api.github.com/users/lunny/orgs","repos_url":"https://api.github.com/users/lunny/repos","events_url":"https://api.github.com/users/lunny/events{/privacy}","received_events_url":"https://api.github.com/users/lunny/received_events","type":"User","user_view_type":"public","site_admin":false},"body":"test a single comment.","created_at":"2020-01-04T11:21:41Z","updated_at":"2020-01-04T11:21:41Z","html_url":"https://github.com/go-gitea/test_repo/pull/4#discussion_r363029944","pull_request_url":"https://api.github.com/repos/go-gitea/test_repo/pulls/4","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/go-gitea/test_repo/pulls/comments/363029944"},"html":{"href":"https://github.com/go-gitea/test_repo/pull/4#discussion_r363029944"},"pull_request":{"href":"https://api.github.com/repos/go-gitea/test_repo/pulls/4"}},"original_commit_id":"2be9101c543658591222acbee3eb799edfc3853d","reactions":{"url":"https://api.github.com/repos/go-gitea/test_repo/pulls/comments/363029944/reactions","total_count":0,"+1":0,"-1":0,"laugh":0,"hooray":0,"confused":0,"heart":0,"rocket":0,"eyes":0}}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F4%2Freviews%3Fper_page%3D100 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F4%2Freviews%3Fper_page%3D100 new file mode 100644 index 00000000..c751d619 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2F4%2Freviews%3Fper_page%3D100 @@ -0,0 +1,23 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: W/"35421809939e0816567e6576339fcf4854de7ec5978b09c6b00ed708e0ba3fe0" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: pull_requests=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; format=json +X-Github-Request-Id: C4F6:A93E1:6A6442:5B4A5B:69AF24EE +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4911 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 89 +X-Xss-Protection: 0 + +[{"id":338338740,"node_id":"MDE3OlB1bGxSZXF1ZXN0UmV2aWV3MzM4MzM4NzQw","user":{"login":"lunny","id":81045,"node_id":"MDQ6VXNlcjgxMDQ1","avatar_url":"https://avatars.githubusercontent.com/u/81045?u=99b64f0ca6ef63643c7583ab87dd31c52d28e673&v=4","gravatar_id":"","url":"https://api.github.com/users/lunny","html_url":"https://github.com/lunny","followers_url":"https://api.github.com/users/lunny/followers","following_url":"https://api.github.com/users/lunny/following{/other_user}","gists_url":"https://api.github.com/users/lunny/gists{/gist_id}","starred_url":"https://api.github.com/users/lunny/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lunny/subscriptions","organizations_url":"https://api.github.com/users/lunny/orgs","repos_url":"https://api.github.com/users/lunny/repos","events_url":"https://api.github.com/users/lunny/events{/privacy}","received_events_url":"https://api.github.com/users/lunny/received_events","type":"User","user_view_type":"public","site_admin":false},"body":"","state":"APPROVED","html_url":"https://github.com/go-gitea/test_repo/pull/4#pullrequestreview-338338740","pull_request_url":"https://api.github.com/repos/go-gitea/test_repo/pulls/4","author_association":"MEMBER","_links":{"html":{"href":"https://github.com/go-gitea/test_repo/pull/4#pullrequestreview-338338740"},"pull_request":{"href":"https://api.github.com/repos/go-gitea/test_repo/pulls/4"}},"submitted_at":"2020-01-04T05:33:18Z","commit_id":"2be9101c543658591222acbee3eb799edfc3853d"},{"id":338339651,"node_id":"MDE3OlB1bGxSZXF1ZXN0UmV2aWV3MzM4MzM5NjUx","user":{"login":"lunny","id":81045,"node_id":"MDQ6VXNlcjgxMDQ1","avatar_url":"https://avatars.githubusercontent.com/u/81045?u=99b64f0ca6ef63643c7583ab87dd31c52d28e673&v=4","gravatar_id":"","url":"https://api.github.com/users/lunny","html_url":"https://github.com/lunny","followers_url":"https://api.github.com/users/lunny/followers","following_url":"https://api.github.com/users/lunny/following{/other_user}","gists_url":"https://api.github.com/users/lunny/gists{/gist_id}","starred_url":"https://api.github.com/users/lunny/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lunny/subscriptions","organizations_url":"https://api.github.com/users/lunny/orgs","repos_url":"https://api.github.com/users/lunny/repos","events_url":"https://api.github.com/users/lunny/events{/privacy}","received_events_url":"https://api.github.com/users/lunny/received_events","type":"User","user_view_type":"public","site_admin":false},"body":"Don't add more reviews","state":"CHANGES_REQUESTED","html_url":"https://github.com/go-gitea/test_repo/pull/4#pullrequestreview-338339651","pull_request_url":"https://api.github.com/repos/go-gitea/test_repo/pulls/4","author_association":"MEMBER","_links":{"html":{"href":"https://github.com/go-gitea/test_repo/pull/4#pullrequestreview-338339651"},"pull_request":{"href":"https://api.github.com/repos/go-gitea/test_repo/pulls/4"}},"submitted_at":"2020-01-04T06:07:06Z","commit_id":"2be9101c543658591222acbee3eb799edfc3853d"},{"id":338349019,"node_id":"MDE3OlB1bGxSZXF1ZXN0UmV2aWV3MzM4MzQ5MDE5","user":{"login":"lunny","id":81045,"node_id":"MDQ6VXNlcjgxMDQ1","avatar_url":"https://avatars.githubusercontent.com/u/81045?u=99b64f0ca6ef63643c7583ab87dd31c52d28e673&v=4","gravatar_id":"","url":"https://api.github.com/users/lunny","html_url":"https://github.com/lunny","followers_url":"https://api.github.com/users/lunny/followers","following_url":"https://api.github.com/users/lunny/following{/other_user}","gists_url":"https://api.github.com/users/lunny/gists{/gist_id}","starred_url":"https://api.github.com/users/lunny/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lunny/subscriptions","organizations_url":"https://api.github.com/users/lunny/orgs","repos_url":"https://api.github.com/users/lunny/repos","events_url":"https://api.github.com/users/lunny/events{/privacy}","received_events_url":"https://api.github.com/users/lunny/received_events","type":"User","user_view_type":"public","site_admin":false},"body":"","state":"COMMENTED","html_url":"https://github.com/go-gitea/test_repo/pull/4#pullrequestreview-338349019","pull_request_url":"https://api.github.com/repos/go-gitea/test_repo/pulls/4","author_association":"MEMBER","_links":{"html":{"href":"https://github.com/go-gitea/test_repo/pull/4#pullrequestreview-338349019"},"pull_request":{"href":"https://api.github.com/repos/go-gitea/test_repo/pulls/4"}},"submitted_at":"2020-01-04T11:21:41Z","commit_id":"2be9101c543658591222acbee3eb799edfc3853d"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2Fcomments%2F363017488%2Freactions%3Fpage%3D1%26per_page%3D100 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2Fcomments%2F363017488%2Freactions%3Fpage%3D1%26per_page%3D100 new file mode 100644 index 00000000..6c6ab19d --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2Fcomments%2F363017488%2Freactions%3Fpage%3D1%26per_page%3D100 @@ -0,0 +1,24 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Length: 2 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: "440897bed2748f095d024d64264317f3f31eadc9413bf26dc0450eecbfbbef7b" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: pull_requests=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; param=squirrel-girl-preview +X-Github-Request-Id: C4F6:A93E1:6A6956:5B4EEB:69AF24EF +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4909 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 91 +X-Xss-Protection: 0 + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2Fcomments%2F363029944%2Freactions%3Fpage%3D1%26per_page%3D100 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2Fcomments%2F363029944%2Freactions%3Fpage%3D1%26per_page%3D100 new file mode 100644 index 00000000..5a1ba878 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%2Fcomments%2F363029944%2Freactions%3Fpage%3D1%26per_page%3D100 @@ -0,0 +1,24 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Length: 2 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: "440897bed2748f095d024d64264317f3f31eadc9413bf26dc0450eecbfbbef7b" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: pull_requests=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; param=squirrel-girl-preview +X-Github-Request-Id: C4F6:A93E1:6A6EC5:5B536E:69AF24EF +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4906 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 94 +X-Xss-Protection: 0 + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%3Fdirection%3Dasc%26page%3D1%26per_page%3D2%26sort%3Dcreated%26state%3Dall b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%3Fdirection%3Dasc%26page%3D1%26per_page%3D2%26sort%3Dcreated%26state%3Dall new file mode 100644 index 00000000..c67a36d1 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Fpulls%3Fdirection%3Dasc%26page%3D1%26per_page%3D2%26sort%3Dcreated%26state%3Dall @@ -0,0 +1,23 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: W/"5d8135a4b8204fb8548ef5b2153ecdecb0d676e2907ecd115101ba728a27c4d2" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: pull_requests=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; format=json +X-Github-Request-Id: C4F6:A93E1:6A4FA3:5B384B:69AF24EB +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4920 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 80 +X-Xss-Protection: 0 + +[{"url":"https://api.github.com/repos/go-gitea/test_repo/pulls/3","id":340118745,"node_id":"MDExOlB1bGxSZXF1ZXN0MzQwMTE4NzQ1","html_url":"https://github.com/go-gitea/test_repo/pull/3","diff_url":"https://github.com/go-gitea/test_repo/pull/3.diff","patch_url":"https://github.com/go-gitea/test_repo/pull/3.patch","issue_url":"https://api.github.com/repos/go-gitea/test_repo/issues/3","number":3,"state":"closed","locked":false,"title":"Update README.md","user":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"body":"add warning to readme","created_at":"2019-11-12T21:21:43Z","updated_at":"2019-11-12T21:39:28Z","closed_at":"2019-11-12T21:39:27Z","merged_at":"2019-11-12T21:39:27Z","merge_commit_sha":"f32b0a9dfd09a60f616f29158f772cedd89942d2","assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1667254254,"node_id":"MDU6TGFiZWwxNjY3MjU0MjU0","url":"https://api.github.com/repos/go-gitea/test_repo/labels/documentation","name":"documentation","color":"0075ca","default":true,"description":"Improvements or additions to documentation"}],"milestone":{"url":"https://api.github.com/repos/go-gitea/test_repo/milestones/2","html_url":"https://github.com/go-gitea/test_repo/milestone/2","labels_url":"https://api.github.com/repos/go-gitea/test_repo/milestones/2/labels","id":4839942,"node_id":"MDk6TWlsZXN0b25lNDgzOTk0Mg==","number":2,"title":"1.1.0","description":"Milestone 1.1.0","creator":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"open_issues":0,"closed_issues":2,"state":"closed","created_at":"2019-11-12T19:37:25Z","updated_at":"2019-11-12T21:39:27Z","due_on":"2019-11-12T00:00:00Z","closed_at":"2019-11-12T19:45:46Z"},"draft":false,"commits_url":"https://api.github.com/repos/go-gitea/test_repo/pulls/3/commits","review_comments_url":"https://api.github.com/repos/go-gitea/test_repo/pulls/3/comments","review_comment_url":"https://api.github.com/repos/go-gitea/test_repo/pulls/comments{/number}","comments_url":"https://api.github.com/repos/go-gitea/test_repo/issues/3/comments","statuses_url":"https://api.github.com/repos/go-gitea/test_repo/statuses/076160cf0b039f13e5eff19619932d181269414b","head":{"label":"mrsdizzie:master","ref":"master","sha":"076160cf0b039f13e5eff19619932d181269414b","user":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"repo":{"id":221313794,"node_id":"MDEwOlJlcG9zaXRvcnkyMjEzMTM3OTQ=","name":"test_repo","full_name":"mrsdizzie/test_repo","private":false,"owner":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"html_url":"https://github.com/mrsdizzie/test_repo","description":"Test repository for testing migration from github to gitea","fork":true,"url":"https://api.github.com/repos/mrsdizzie/test_repo","forks_url":"https://api.github.com/repos/mrsdizzie/test_repo/forks","keys_url":"https://api.github.com/repos/mrsdizzie/test_repo/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mrsdizzie/test_repo/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mrsdizzie/test_repo/teams","hooks_url":"https://api.github.com/repos/mrsdizzie/test_repo/hooks","issue_events_url":"https://api.github.com/repos/mrsdizzie/test_repo/issues/events{/number}","events_url":"https://api.github.com/repos/mrsdizzie/test_repo/events","assignees_url":"https://api.github.com/repos/mrsdizzie/test_repo/assignees{/user}","branches_url":"https://api.github.com/repos/mrsdizzie/test_repo/branches{/branch}","tags_url":"https://api.github.com/repos/mrsdizzie/test_repo/tags","blobs_url":"https://api.github.com/repos/mrsdizzie/test_repo/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mrsdizzie/test_repo/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mrsdizzie/test_repo/git/refs{/sha}","trees_url":"https://api.github.com/repos/mrsdizzie/test_repo/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mrsdizzie/test_repo/statuses/{sha}","languages_url":"https://api.github.com/repos/mrsdizzie/test_repo/languages","stargazers_url":"https://api.github.com/repos/mrsdizzie/test_repo/stargazers","contributors_url":"https://api.github.com/repos/mrsdizzie/test_repo/contributors","subscribers_url":"https://api.github.com/repos/mrsdizzie/test_repo/subscribers","subscription_url":"https://api.github.com/repos/mrsdizzie/test_repo/subscription","commits_url":"https://api.github.com/repos/mrsdizzie/test_repo/commits{/sha}","git_commits_url":"https://api.github.com/repos/mrsdizzie/test_repo/git/commits{/sha}","comments_url":"https://api.github.com/repos/mrsdizzie/test_repo/comments{/number}","issue_comment_url":"https://api.github.com/repos/mrsdizzie/test_repo/issues/comments{/number}","contents_url":"https://api.github.com/repos/mrsdizzie/test_repo/contents/{+path}","compare_url":"https://api.github.com/repos/mrsdizzie/test_repo/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mrsdizzie/test_repo/merges","archive_url":"https://api.github.com/repos/mrsdizzie/test_repo/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mrsdizzie/test_repo/downloads","issues_url":"https://api.github.com/repos/mrsdizzie/test_repo/issues{/number}","pulls_url":"https://api.github.com/repos/mrsdizzie/test_repo/pulls{/number}","milestones_url":"https://api.github.com/repos/mrsdizzie/test_repo/milestones{/number}","notifications_url":"https://api.github.com/repos/mrsdizzie/test_repo/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mrsdizzie/test_repo/labels{/name}","releases_url":"https://api.github.com/repos/mrsdizzie/test_repo/releases{/id}","deployments_url":"https://api.github.com/repos/mrsdizzie/test_repo/deployments","created_at":"2019-11-12T21:17:42Z","updated_at":"2019-11-12T21:18:46Z","pushed_at":"2019-11-12T21:53:39Z","git_url":"git://github.com/mrsdizzie/test_repo.git","ssh_url":"git@github.com:mrsdizzie/test_repo.git","clone_url":"https://github.com/mrsdizzie/test_repo.git","svn_url":"https://github.com/mrsdizzie/test_repo","homepage":null,"size":3,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"has_discussions":false,"forks_count":0,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":0,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"has_pull_requests":true,"pull_request_creation_policy":"all","topics":[],"visibility":"public","forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"go-gitea:master","ref":"master","sha":"72866af952e98d02a73003501836074b286a78f6","user":{"login":"go-gitea","id":12724356,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEyNzI0MzU2","avatar_url":"https://avatars.githubusercontent.com/u/12724356?v=4","gravatar_id":"","url":"https://api.github.com/users/go-gitea","html_url":"https://github.com/go-gitea","followers_url":"https://api.github.com/users/go-gitea/followers","following_url":"https://api.github.com/users/go-gitea/following{/other_user}","gists_url":"https://api.github.com/users/go-gitea/gists{/gist_id}","starred_url":"https://api.github.com/users/go-gitea/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/go-gitea/subscriptions","organizations_url":"https://api.github.com/users/go-gitea/orgs","repos_url":"https://api.github.com/users/go-gitea/repos","events_url":"https://api.github.com/users/go-gitea/events{/privacy}","received_events_url":"https://api.github.com/users/go-gitea/received_events","type":"Organization","user_view_type":"public","site_admin":false},"repo":{"id":220672974,"node_id":"MDEwOlJlcG9zaXRvcnkyMjA2NzI5NzQ=","name":"test_repo","full_name":"go-gitea/test_repo","private":false,"owner":{"login":"go-gitea","id":12724356,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEyNzI0MzU2","avatar_url":"https://avatars.githubusercontent.com/u/12724356?v=4","gravatar_id":"","url":"https://api.github.com/users/go-gitea","html_url":"https://github.com/go-gitea","followers_url":"https://api.github.com/users/go-gitea/followers","following_url":"https://api.github.com/users/go-gitea/following{/other_user}","gists_url":"https://api.github.com/users/go-gitea/gists{/gist_id}","starred_url":"https://api.github.com/users/go-gitea/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/go-gitea/subscriptions","organizations_url":"https://api.github.com/users/go-gitea/orgs","repos_url":"https://api.github.com/users/go-gitea/repos","events_url":"https://api.github.com/users/go-gitea/events{/privacy}","received_events_url":"https://api.github.com/users/go-gitea/received_events","type":"Organization","user_view_type":"public","site_admin":false},"html_url":"https://github.com/go-gitea/test_repo","description":"Test repository for testing migration from github to gitea","fork":false,"url":"https://api.github.com/repos/go-gitea/test_repo","forks_url":"https://api.github.com/repos/go-gitea/test_repo/forks","keys_url":"https://api.github.com/repos/go-gitea/test_repo/keys{/key_id}","collaborators_url":"https://api.github.com/repos/go-gitea/test_repo/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/go-gitea/test_repo/teams","hooks_url":"https://api.github.com/repos/go-gitea/test_repo/hooks","issue_events_url":"https://api.github.com/repos/go-gitea/test_repo/issues/events{/number}","events_url":"https://api.github.com/repos/go-gitea/test_repo/events","assignees_url":"https://api.github.com/repos/go-gitea/test_repo/assignees{/user}","branches_url":"https://api.github.com/repos/go-gitea/test_repo/branches{/branch}","tags_url":"https://api.github.com/repos/go-gitea/test_repo/tags","blobs_url":"https://api.github.com/repos/go-gitea/test_repo/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/go-gitea/test_repo/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/go-gitea/test_repo/git/refs{/sha}","trees_url":"https://api.github.com/repos/go-gitea/test_repo/git/trees{/sha}","statuses_url":"https://api.github.com/repos/go-gitea/test_repo/statuses/{sha}","languages_url":"https://api.github.com/repos/go-gitea/test_repo/languages","stargazers_url":"https://api.github.com/repos/go-gitea/test_repo/stargazers","contributors_url":"https://api.github.com/repos/go-gitea/test_repo/contributors","subscribers_url":"https://api.github.com/repos/go-gitea/test_repo/subscribers","subscription_url":"https://api.github.com/repos/go-gitea/test_repo/subscription","commits_url":"https://api.github.com/repos/go-gitea/test_repo/commits{/sha}","git_commits_url":"https://api.github.com/repos/go-gitea/test_repo/git/commits{/sha}","comments_url":"https://api.github.com/repos/go-gitea/test_repo/comments{/number}","issue_comment_url":"https://api.github.com/repos/go-gitea/test_repo/issues/comments{/number}","contents_url":"https://api.github.com/repos/go-gitea/test_repo/contents/{+path}","compare_url":"https://api.github.com/repos/go-gitea/test_repo/compare/{base}...{head}","merges_url":"https://api.github.com/repos/go-gitea/test_repo/merges","archive_url":"https://api.github.com/repos/go-gitea/test_repo/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/go-gitea/test_repo/downloads","issues_url":"https://api.github.com/repos/go-gitea/test_repo/issues{/number}","pulls_url":"https://api.github.com/repos/go-gitea/test_repo/pulls{/number}","milestones_url":"https://api.github.com/repos/go-gitea/test_repo/milestones{/number}","notifications_url":"https://api.github.com/repos/go-gitea/test_repo/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/go-gitea/test_repo/labels{/name}","releases_url":"https://api.github.com/repos/go-gitea/test_repo/releases{/id}","deployments_url":"https://api.github.com/repos/go-gitea/test_repo/deployments","created_at":"2019-11-09T16:49:20Z","updated_at":"2023-03-02T14:02:26Z","pushed_at":"2019-11-12T21:54:19Z","git_url":"git://github.com/go-gitea/test_repo.git","ssh_url":"git@github.com:go-gitea/test_repo.git","clone_url":"https://github.com/go-gitea/test_repo.git","svn_url":"https://github.com/go-gitea/test_repo","homepage":null,"size":1,"stargazers_count":3,"watchers_count":3,"language":null,"has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"has_discussions":false,"forks_count":3,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":3,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"has_pull_requests":true,"pull_request_creation_policy":"all","topics":["gitea"],"visibility":"public","forks":3,"open_issues":3,"watchers":3,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/go-gitea/test_repo/pulls/3"},"html":{"href":"https://github.com/go-gitea/test_repo/pull/3"},"issue":{"href":"https://api.github.com/repos/go-gitea/test_repo/issues/3"},"comments":{"href":"https://api.github.com/repos/go-gitea/test_repo/issues/3/comments"},"review_comments":{"href":"https://api.github.com/repos/go-gitea/test_repo/pulls/3/comments"},"review_comment":{"href":"https://api.github.com/repos/go-gitea/test_repo/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/go-gitea/test_repo/pulls/3/commits"},"statuses":{"href":"https://api.github.com/repos/go-gitea/test_repo/statuses/076160cf0b039f13e5eff19619932d181269414b"}},"author_association":"MEMBER","auto_merge":null,"assignee":null,"active_lock_reason":null},{"url":"https://api.github.com/repos/go-gitea/test_repo/pulls/4","id":340131577,"node_id":"MDExOlB1bGxSZXF1ZXN0MzQwMTMxNTc3","html_url":"https://github.com/go-gitea/test_repo/pull/4","diff_url":"https://github.com/go-gitea/test_repo/pull/4.diff","patch_url":"https://github.com/go-gitea/test_repo/pull/4.patch","issue_url":"https://api.github.com/repos/go-gitea/test_repo/issues/4","number":4,"state":"open","locked":false,"title":"Test branch","user":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"body":"do not merge this PR","created_at":"2019-11-12T21:54:18Z","updated_at":"2025-03-16T15:46:20Z","closed_at":null,"merged_at":null,"merge_commit_sha":"565d1208f5fffdc1c5ae1a2436491eb9a5e4ebae","assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1667254252,"node_id":"MDU6TGFiZWwxNjY3MjU0MjUy","url":"https://api.github.com/repos/go-gitea/test_repo/labels/bug","name":"bug","color":"d73a4a","default":true,"description":"Something isn't working"}],"milestone":{"url":"https://api.github.com/repos/go-gitea/test_repo/milestones/1","html_url":"https://github.com/go-gitea/test_repo/milestone/1","labels_url":"https://api.github.com/repos/go-gitea/test_repo/milestones/1/labels","id":4839941,"node_id":"MDk6TWlsZXN0b25lNDgzOTk0MQ==","number":1,"title":"1.0.0","description":"Milestone 1.0.0","creator":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"open_issues":1,"closed_issues":1,"state":"closed","created_at":"2019-11-12T19:37:08Z","updated_at":"2019-11-12T21:56:17Z","due_on":"2019-11-11T00:00:00Z","closed_at":"2019-11-12T19:45:49Z"},"draft":false,"commits_url":"https://api.github.com/repos/go-gitea/test_repo/pulls/4/commits","review_comments_url":"https://api.github.com/repos/go-gitea/test_repo/pulls/4/comments","review_comment_url":"https://api.github.com/repos/go-gitea/test_repo/pulls/comments{/number}","comments_url":"https://api.github.com/repos/go-gitea/test_repo/issues/4/comments","statuses_url":"https://api.github.com/repos/go-gitea/test_repo/statuses/2be9101c543658591222acbee3eb799edfc3853d","head":{"label":"mrsdizzie:test-branch","ref":"test-branch","sha":"2be9101c543658591222acbee3eb799edfc3853d","user":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"repo":{"id":221313794,"node_id":"MDEwOlJlcG9zaXRvcnkyMjEzMTM3OTQ=","name":"test_repo","full_name":"mrsdizzie/test_repo","private":false,"owner":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"html_url":"https://github.com/mrsdizzie/test_repo","description":"Test repository for testing migration from github to gitea","fork":true,"url":"https://api.github.com/repos/mrsdizzie/test_repo","forks_url":"https://api.github.com/repos/mrsdizzie/test_repo/forks","keys_url":"https://api.github.com/repos/mrsdizzie/test_repo/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mrsdizzie/test_repo/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mrsdizzie/test_repo/teams","hooks_url":"https://api.github.com/repos/mrsdizzie/test_repo/hooks","issue_events_url":"https://api.github.com/repos/mrsdizzie/test_repo/issues/events{/number}","events_url":"https://api.github.com/repos/mrsdizzie/test_repo/events","assignees_url":"https://api.github.com/repos/mrsdizzie/test_repo/assignees{/user}","branches_url":"https://api.github.com/repos/mrsdizzie/test_repo/branches{/branch}","tags_url":"https://api.github.com/repos/mrsdizzie/test_repo/tags","blobs_url":"https://api.github.com/repos/mrsdizzie/test_repo/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mrsdizzie/test_repo/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mrsdizzie/test_repo/git/refs{/sha}","trees_url":"https://api.github.com/repos/mrsdizzie/test_repo/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mrsdizzie/test_repo/statuses/{sha}","languages_url":"https://api.github.com/repos/mrsdizzie/test_repo/languages","stargazers_url":"https://api.github.com/repos/mrsdizzie/test_repo/stargazers","contributors_url":"https://api.github.com/repos/mrsdizzie/test_repo/contributors","subscribers_url":"https://api.github.com/repos/mrsdizzie/test_repo/subscribers","subscription_url":"https://api.github.com/repos/mrsdizzie/test_repo/subscription","commits_url":"https://api.github.com/repos/mrsdizzie/test_repo/commits{/sha}","git_commits_url":"https://api.github.com/repos/mrsdizzie/test_repo/git/commits{/sha}","comments_url":"https://api.github.com/repos/mrsdizzie/test_repo/comments{/number}","issue_comment_url":"https://api.github.com/repos/mrsdizzie/test_repo/issues/comments{/number}","contents_url":"https://api.github.com/repos/mrsdizzie/test_repo/contents/{+path}","compare_url":"https://api.github.com/repos/mrsdizzie/test_repo/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mrsdizzie/test_repo/merges","archive_url":"https://api.github.com/repos/mrsdizzie/test_repo/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mrsdizzie/test_repo/downloads","issues_url":"https://api.github.com/repos/mrsdizzie/test_repo/issues{/number}","pulls_url":"https://api.github.com/repos/mrsdizzie/test_repo/pulls{/number}","milestones_url":"https://api.github.com/repos/mrsdizzie/test_repo/milestones{/number}","notifications_url":"https://api.github.com/repos/mrsdizzie/test_repo/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mrsdizzie/test_repo/labels{/name}","releases_url":"https://api.github.com/repos/mrsdizzie/test_repo/releases{/id}","deployments_url":"https://api.github.com/repos/mrsdizzie/test_repo/deployments","created_at":"2019-11-12T21:17:42Z","updated_at":"2019-11-12T21:18:46Z","pushed_at":"2019-11-12T21:53:39Z","git_url":"git://github.com/mrsdizzie/test_repo.git","ssh_url":"git@github.com:mrsdizzie/test_repo.git","clone_url":"https://github.com/mrsdizzie/test_repo.git","svn_url":"https://github.com/mrsdizzie/test_repo","homepage":null,"size":3,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"has_discussions":false,"forks_count":0,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":0,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"has_pull_requests":true,"pull_request_creation_policy":"all","topics":[],"visibility":"public","forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"go-gitea:master","ref":"master","sha":"f32b0a9dfd09a60f616f29158f772cedd89942d2","user":{"login":"go-gitea","id":12724356,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEyNzI0MzU2","avatar_url":"https://avatars.githubusercontent.com/u/12724356?v=4","gravatar_id":"","url":"https://api.github.com/users/go-gitea","html_url":"https://github.com/go-gitea","followers_url":"https://api.github.com/users/go-gitea/followers","following_url":"https://api.github.com/users/go-gitea/following{/other_user}","gists_url":"https://api.github.com/users/go-gitea/gists{/gist_id}","starred_url":"https://api.github.com/users/go-gitea/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/go-gitea/subscriptions","organizations_url":"https://api.github.com/users/go-gitea/orgs","repos_url":"https://api.github.com/users/go-gitea/repos","events_url":"https://api.github.com/users/go-gitea/events{/privacy}","received_events_url":"https://api.github.com/users/go-gitea/received_events","type":"Organization","user_view_type":"public","site_admin":false},"repo":{"id":220672974,"node_id":"MDEwOlJlcG9zaXRvcnkyMjA2NzI5NzQ=","name":"test_repo","full_name":"go-gitea/test_repo","private":false,"owner":{"login":"go-gitea","id":12724356,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEyNzI0MzU2","avatar_url":"https://avatars.githubusercontent.com/u/12724356?v=4","gravatar_id":"","url":"https://api.github.com/users/go-gitea","html_url":"https://github.com/go-gitea","followers_url":"https://api.github.com/users/go-gitea/followers","following_url":"https://api.github.com/users/go-gitea/following{/other_user}","gists_url":"https://api.github.com/users/go-gitea/gists{/gist_id}","starred_url":"https://api.github.com/users/go-gitea/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/go-gitea/subscriptions","organizations_url":"https://api.github.com/users/go-gitea/orgs","repos_url":"https://api.github.com/users/go-gitea/repos","events_url":"https://api.github.com/users/go-gitea/events{/privacy}","received_events_url":"https://api.github.com/users/go-gitea/received_events","type":"Organization","user_view_type":"public","site_admin":false},"html_url":"https://github.com/go-gitea/test_repo","description":"Test repository for testing migration from github to gitea","fork":false,"url":"https://api.github.com/repos/go-gitea/test_repo","forks_url":"https://api.github.com/repos/go-gitea/test_repo/forks","keys_url":"https://api.github.com/repos/go-gitea/test_repo/keys{/key_id}","collaborators_url":"https://api.github.com/repos/go-gitea/test_repo/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/go-gitea/test_repo/teams","hooks_url":"https://api.github.com/repos/go-gitea/test_repo/hooks","issue_events_url":"https://api.github.com/repos/go-gitea/test_repo/issues/events{/number}","events_url":"https://api.github.com/repos/go-gitea/test_repo/events","assignees_url":"https://api.github.com/repos/go-gitea/test_repo/assignees{/user}","branches_url":"https://api.github.com/repos/go-gitea/test_repo/branches{/branch}","tags_url":"https://api.github.com/repos/go-gitea/test_repo/tags","blobs_url":"https://api.github.com/repos/go-gitea/test_repo/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/go-gitea/test_repo/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/go-gitea/test_repo/git/refs{/sha}","trees_url":"https://api.github.com/repos/go-gitea/test_repo/git/trees{/sha}","statuses_url":"https://api.github.com/repos/go-gitea/test_repo/statuses/{sha}","languages_url":"https://api.github.com/repos/go-gitea/test_repo/languages","stargazers_url":"https://api.github.com/repos/go-gitea/test_repo/stargazers","contributors_url":"https://api.github.com/repos/go-gitea/test_repo/contributors","subscribers_url":"https://api.github.com/repos/go-gitea/test_repo/subscribers","subscription_url":"https://api.github.com/repos/go-gitea/test_repo/subscription","commits_url":"https://api.github.com/repos/go-gitea/test_repo/commits{/sha}","git_commits_url":"https://api.github.com/repos/go-gitea/test_repo/git/commits{/sha}","comments_url":"https://api.github.com/repos/go-gitea/test_repo/comments{/number}","issue_comment_url":"https://api.github.com/repos/go-gitea/test_repo/issues/comments{/number}","contents_url":"https://api.github.com/repos/go-gitea/test_repo/contents/{+path}","compare_url":"https://api.github.com/repos/go-gitea/test_repo/compare/{base}...{head}","merges_url":"https://api.github.com/repos/go-gitea/test_repo/merges","archive_url":"https://api.github.com/repos/go-gitea/test_repo/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/go-gitea/test_repo/downloads","issues_url":"https://api.github.com/repos/go-gitea/test_repo/issues{/number}","pulls_url":"https://api.github.com/repos/go-gitea/test_repo/pulls{/number}","milestones_url":"https://api.github.com/repos/go-gitea/test_repo/milestones{/number}","notifications_url":"https://api.github.com/repos/go-gitea/test_repo/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/go-gitea/test_repo/labels{/name}","releases_url":"https://api.github.com/repos/go-gitea/test_repo/releases{/id}","deployments_url":"https://api.github.com/repos/go-gitea/test_repo/deployments","created_at":"2019-11-09T16:49:20Z","updated_at":"2023-03-02T14:02:26Z","pushed_at":"2019-11-12T21:54:19Z","git_url":"git://github.com/go-gitea/test_repo.git","ssh_url":"git@github.com:go-gitea/test_repo.git","clone_url":"https://github.com/go-gitea/test_repo.git","svn_url":"https://github.com/go-gitea/test_repo","homepage":null,"size":1,"stargazers_count":3,"watchers_count":3,"language":null,"has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"has_discussions":false,"forks_count":3,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":3,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"has_pull_requests":true,"pull_request_creation_policy":"all","topics":["gitea"],"visibility":"public","forks":3,"open_issues":3,"watchers":3,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/go-gitea/test_repo/pulls/4"},"html":{"href":"https://github.com/go-gitea/test_repo/pull/4"},"issue":{"href":"https://api.github.com/repos/go-gitea/test_repo/issues/4"},"comments":{"href":"https://api.github.com/repos/go-gitea/test_repo/issues/4/comments"},"review_comments":{"href":"https://api.github.com/repos/go-gitea/test_repo/pulls/4/comments"},"review_comment":{"href":"https://api.github.com/repos/go-gitea/test_repo/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/go-gitea/test_repo/pulls/4/commits"},"statuses":{"href":"https://api.github.com/repos/go-gitea/test_repo/statuses/2be9101c543658591222acbee3eb799edfc3853d"}},"author_association":"MEMBER","auto_merge":null,"assignee":null,"active_lock_reason":null}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Freleases%3Fpage%3D1%26per_page%3D100 b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Freleases%3Fpage%3D1%26per_page%3D100 new file mode 100644 index 00000000..7ec652e4 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitHubDownloadRepo/GET_%2Fapi%2Fv3%2Frepos%2Fgo-gitea%2Ftest_repo%2Freleases%3Fpage%3D1%26per_page%3D100 @@ -0,0 +1,23 @@ +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset +Cache-Control: private, max-age=60, s-maxage=60 +Content-Security-Policy: default-src 'none' +Content-Type: application/json; charset=utf-8 +Etag: W/"931091ce17d88742881c4964d7ec028088be47e87af3f507a83795eaf54056ac" +Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000; includeSubdomains; preload +Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With +X-Accepted-Github-Permissions: contents=read +X-Content-Type-Options: nosniff +X-Frame-Options: deny +X-Github-Api-Version-Selected: 2022-11-28 +X-Github-Media-Type: github.v3; format=json +X-Github-Request-Id: C4F6:A93E1:6A38A8:5B2462:69AF24E7 +X-Ratelimit-Limit: 5000 +X-Ratelimit-Remaining: 4932 +X-Ratelimit-Reset: 1773089427 +X-Ratelimit-Resource: core +X-Ratelimit-Used: 68 +X-Xss-Protection: 0 + +[{"url":"https://api.github.com/repos/go-gitea/test_repo/releases/21419432","assets_url":"https://api.github.com/repos/go-gitea/test_repo/releases/21419432/assets","upload_url":"https://uploads.github.com/repos/go-gitea/test_repo/releases/21419432/assets{?name,label}","html_url":"https://github.com/go-gitea/test_repo/releases/tag/v0.9.99","id":21419432,"author":{"login":"mrsdizzie","id":1669571,"node_id":"MDQ6VXNlcjE2Njk1NzE=","avatar_url":"https://avatars.githubusercontent.com/u/1669571?v=4","gravatar_id":"","url":"https://api.github.com/users/mrsdizzie","html_url":"https://github.com/mrsdizzie","followers_url":"https://api.github.com/users/mrsdizzie/followers","following_url":"https://api.github.com/users/mrsdizzie/following{/other_user}","gists_url":"https://api.github.com/users/mrsdizzie/gists{/gist_id}","starred_url":"https://api.github.com/users/mrsdizzie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrsdizzie/subscriptions","organizations_url":"https://api.github.com/users/mrsdizzie/orgs","repos_url":"https://api.github.com/users/mrsdizzie/repos","events_url":"https://api.github.com/users/mrsdizzie/events{/privacy}","received_events_url":"https://api.github.com/users/mrsdizzie/received_events","type":"User","user_view_type":"public","site_admin":false},"node_id":"MDc6UmVsZWFzZTIxNDE5NDMy","tag_name":"v0.9.99","target_commitish":"master","name":"First Release","draft":false,"immutable":false,"prerelease":false,"created_at":"2019-11-09T16:49:21Z","updated_at":"2019-11-12T20:12:10Z","published_at":"2019-11-12T20:12:10Z","assets":[],"tarball_url":"https://api.github.com/repos/go-gitea/test_repo/tarball/v0.9.99","zipball_url":"https://api.github.com/repos/go-gitea/test_repo/zipball/v0.9.99","body":"A test release"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo new file mode 100644 index 00000000..b824ab27 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo @@ -0,0 +1,7 @@ +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff + +{"id":16268,"owner":{"id":3,"login":"gitea","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/35dea380390772b3130aafbac7ca49e6","html_url":"https://gitea.com/gitea","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2018-11-29T03:16:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"Git Universe","website":"https://gitea.com","description":"Git with a cup of tea","visibility":"public","followers_count":100,"following_count":0,"starred_repos_count":0,"username":"gitea"},"name":"test_repo","full_name":"gitea/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":false,"template":false,"mirror":false,"size":68,"language":"","languages_url":"https://gitea.com/api/v1/repos/gitea/test_repo/languages","html_url":"https://gitea.com/gitea/test_repo","url":"https://gitea.com/api/v1/repos/gitea/test_repo","link":"","ssh_url":"git@gitea.com:gitea/test_repo.git","clone_url":"https://gitea.com/gitea/test_repo.git","original_url":"","website":"https://gitea.com/test-repo","stars_count":1,"forks_count":2,"watchers_count":10,"open_issues_count":2,"open_pr_counter":2,"release_counter":2,"default_branch":"master","archived":false,"created_at":"2020-09-01T00:12:27Z","updated_at":"2020-09-01T18:03:41Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"projects_mode":"","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"allow_fast_forward_only_merge":false,"allow_rebase_update":true,"allow_manual_merge":false,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":["gitea","test","migration","ci"],"licenses":[]} \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F1%2Freactions%3Flimit%3D50%26page%3D1 b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F1%2Freactions%3Flimit%3D50%26page%3D1 new file mode 100644 index 00000000..64b2192d --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F1%2Freactions%3Flimit%3D50%26page%3D1 @@ -0,0 +1,10 @@ +Access-Control-Expose-Headers: X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 1322 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 2 + +[{"user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"content":"gitea","created_at":"2020-09-01T00:15:14Z"},{"user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"content":"confused","created_at":"2020-09-01T00:15:19Z"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F10%2Freactions%3Flimit%3D50%26page%3D1 b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F10%2Freactions%3Flimit%3D50%26page%3D1 new file mode 100644 index 00000000..da062089 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F10%2Freactions%3Flimit%3D50%26page%3D1 @@ -0,0 +1,10 @@ +Access-Control-Expose-Headers: X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 4 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 0 + +null \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F11%2Freactions%3Flimit%3D50%26page%3D1 b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F11%2Freactions%3Flimit%3D50%26page%3D1 new file mode 100644 index 00000000..da062089 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F11%2Freactions%3Flimit%3D50%26page%3D1 @@ -0,0 +1,10 @@ +Access-Control-Expose-Headers: X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 4 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 0 + +null \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F12%2Freactions%3Flimit%3D50%26page%3D1 b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F12%2Freactions%3Flimit%3D50%26page%3D1 new file mode 100644 index 00000000..da062089 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F12%2Freactions%3Flimit%3D50%26page%3D1 @@ -0,0 +1,10 @@ +Access-Control-Expose-Headers: X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 4 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 0 + +null \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F13%2Freactions%3Flimit%3D50%26page%3D1 b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F13%2Freactions%3Flimit%3D50%26page%3D1 new file mode 100644 index 00000000..da062089 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F13%2Freactions%3Flimit%3D50%26page%3D1 @@ -0,0 +1,10 @@ +Access-Control-Expose-Headers: X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 4 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 0 + +null \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F2%2Freactions%3Flimit%3D50%26page%3D1 b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F2%2Freactions%3Flimit%3D50%26page%3D1 new file mode 100644 index 00000000..da062089 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F2%2Freactions%3Flimit%3D50%26page%3D1 @@ -0,0 +1,10 @@ +Access-Control-Expose-Headers: X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 4 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 0 + +null \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F3%2Freactions%3Flimit%3D50%26page%3D1 b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F3%2Freactions%3Flimit%3D50%26page%3D1 new file mode 100644 index 00000000..da062089 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F3%2Freactions%3Flimit%3D50%26page%3D1 @@ -0,0 +1,10 @@ +Access-Control-Expose-Headers: X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 4 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 0 + +null \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F4%2Fcomments%3Flimit%3D50%26page%3D1 b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F4%2Fcomments%3Flimit%3D50%26page%3D1 new file mode 100644 index 00000000..365bd500 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F4%2Fcomments%3Flimit%3D50%26page%3D1 @@ -0,0 +1,10 @@ +Access-Control-Expose-Headers: X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 1834 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 2 + +[{"id":116550,"html_url":"https://gitea.com/gitea/test_repo/issues/4#issuecomment-116550","pull_request_url":"","issue_url":"https://gitea.com/gitea/test_repo/issues/4","user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"original_author":"","original_author_id":0,"body":"a really good question!\n\nIt is the used as TESTSET for gitea2gitea repo migration function","assets":[],"created_at":"2020-09-01T15:49:30Z","updated_at":"2020-09-02T18:21:05Z"},{"id":116552,"html_url":"https://gitea.com/gitea/test_repo/issues/4#issuecomment-116552","pull_request_url":"","issue_url":"https://gitea.com/gitea/test_repo/issues/4","user":{"id":-1,"login":"Ghost","login_name":"","source_id":0,"full_name":"","email":"-1+ghost@noreply.gitea.com","avatar_url":"https://gitea.com/assets/img/avatar_default.png","html_url":"https://gitea.com/Ghost","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"1970-01-01T00:00:00Z","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"Ghost"},"original_author":"","original_author_id":0,"body":"Oh!","assets":[],"created_at":"2020-09-01T15:49:53Z","updated_at":"2020-09-01T15:49:53Z"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F4%2Freactions%3Flimit%3D50%26page%3D1 b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F4%2Freactions%3Flimit%3D50%26page%3D1 new file mode 100644 index 00000000..802314b5 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F4%2Freactions%3Flimit%3D50%26page%3D1 @@ -0,0 +1,10 @@ +Access-Control-Expose-Headers: X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 1319 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 2 + +[{"user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"content":"gitea","created_at":"2020-09-01T19:36:40Z"},{"user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"content":"laugh","created_at":"2020-09-01T19:36:45Z"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F5%2Freactions%3Flimit%3D50%26page%3D1 b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F5%2Freactions%3Flimit%3D50%26page%3D1 new file mode 100644 index 00000000..da1a14de --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F5%2Freactions%3Flimit%3D50%26page%3D1 @@ -0,0 +1,10 @@ +Access-Control-Expose-Headers: X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 1317 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 2 + +[{"user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"content":"+1","created_at":"2020-09-01T16:07:06Z"},{"user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"content":"hooray","created_at":"2020-09-01T16:07:11Z"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F6%2Freactions%3Flimit%3D50%26page%3D1 b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F6%2Freactions%3Flimit%3D50%26page%3D1 new file mode 100644 index 00000000..da062089 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F6%2Freactions%3Flimit%3D50%26page%3D1 @@ -0,0 +1,10 @@ +Access-Control-Expose-Headers: X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 4 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 0 + +null \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F7%2Freactions%3Flimit%3D50%26page%3D1 b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F7%2Freactions%3Flimit%3D50%26page%3D1 new file mode 100644 index 00000000..da062089 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F7%2Freactions%3Flimit%3D50%26page%3D1 @@ -0,0 +1,10 @@ +Access-Control-Expose-Headers: X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 4 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 0 + +null \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F8%2Freactions%3Flimit%3D50%26page%3D1 b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F8%2Freactions%3Flimit%3D50%26page%3D1 new file mode 100644 index 00000000..da062089 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F8%2Freactions%3Flimit%3D50%26page%3D1 @@ -0,0 +1,10 @@ +Access-Control-Expose-Headers: X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 4 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 0 + +null \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F9%2Freactions%3Flimit%3D50%26page%3D1 b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F9%2Freactions%3Flimit%3D50%26page%3D1 new file mode 100644 index 00000000..da062089 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2F9%2Freactions%3Flimit%3D50%26page%3D1 @@ -0,0 +1,10 @@ +Access-Control-Expose-Headers: X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 4 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 0 + +null \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2Fcomments%2F116550%2Freactions b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2Fcomments%2F116550%2Freactions new file mode 100644 index 00000000..054c0660 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2Fcomments%2F116550%2Freactions @@ -0,0 +1,8 @@ +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 4 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff + +null \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2Fcomments%2F116552%2Freactions b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2Fcomments%2F116552%2Freactions new file mode 100644 index 00000000..054c0660 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%2Fcomments%2F116552%2Freactions @@ -0,0 +1,8 @@ +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 4 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff + +null \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%3Flimit%3D2%26page%3D3%26state%3Dall%26type%3Dissues b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%3Flimit%3D2%26page%3D3%26state%3Dall%26type%3Dissues new file mode 100644 index 00000000..c0b1ef28 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%3Flimit%3D2%26page%3D3%26state%3Dall%26type%3Dissues @@ -0,0 +1,10 @@ +Access-Control-Expose-Headers: Link, X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Type: application/json;charset=utf-8 +Link: ; rel="next",; rel="last",; rel="first",; rel="prev" +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 7 + +[{"id":30475,"url":"https://gitea.com/api/v1/repos/gitea/test_repo/issues/4","html_url":"https://gitea.com/gitea/test_repo/issues/4","number":4,"user":{"id":-1,"login":"Ghost","login_name":"","source_id":0,"full_name":"","email":"-1+ghost@noreply.gitea.com","avatar_url":"https://gitea.com/assets/img/avatar_default.png","html_url":"https://gitea.com/Ghost","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"1970-01-01T00:00:00Z","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"Ghost"},"original_author":"","original_author_id":0,"title":"what is this repo about?","body":"","ref":"","assets":[],"labels":[{"id":3733,"name":"Question","exclusive":false,"is_archived":false,"color":"fbca04","description":"","url":"https://gitea.com/api/v1/repos/gitea/test_repo/labels/3733"}],"milestone":{"id":1300,"title":"V1","description":"Generate Content","state":"closed","open_issues":0,"closed_issues":4,"created_at":"1970-01-01T00:00:00Z","updated_at":"1970-01-01T00:00:00Z","closed_at":"2020-09-01T18:36:46Z","due_on":null},"assignee":null,"assignees":null,"state":"closed","is_locked":true,"comments":2,"created_at":"2020-09-01T15:48:41Z","updated_at":"2020-09-01T15:50:00Z","closed_at":"2020-09-01T15:49:34Z","due_date":null,"time_estimate":0,"pull_request":null,"repository":{"id":16268,"name":"test_repo","owner":"gitea","full_name":"gitea/test_repo"},"pin_order":0},{"id":30471,"url":"https://gitea.com/api/v1/repos/gitea/test_repo/issues/2","html_url":"https://gitea.com/gitea/test_repo/issues/2","number":2,"user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"original_author":"","original_author_id":0,"title":"Spam","body":":(","ref":"","assets":[],"labels":[{"id":3732,"name":"Invalid","exclusive":false,"is_archived":false,"color":"d4c5f9","description":"","url":"https://gitea.com/api/v1/repos/gitea/test_repo/labels/3732"}],"milestone":null,"assignee":null,"assignees":null,"state":"closed","is_locked":false,"comments":2,"created_at":"2020-09-01T00:23:00Z","updated_at":"2020-09-01T14:11:37Z","closed_at":"2020-09-01T14:11:37Z","due_date":null,"time_estimate":0,"pull_request":null,"repository":{"id":16268,"name":"test_repo","owner":"gitea","full_name":"gitea/test_repo"},"pin_order":0}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%3Flimit%3D50%26page%3D1%26state%3Dall%26type%3Dissues b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%3Flimit%3D50%26page%3D1%26state%3Dall%26type%3Dissues new file mode 100644 index 00000000..aef3e266 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fissues%3Flimit%3D50%26page%3D1%26state%3Dall%26type%3Dissues @@ -0,0 +1,9 @@ +Access-Control-Expose-Headers: X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 7 + +[{"id":30481,"url":"https://gitea.com/api/v1/repos/gitea/test_repo/issues/10","html_url":"https://gitea.com/gitea/test_repo/issues/10","number":10,"user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"original_author":"","original_author_id":0,"title":"A'm I allowed to fork it?","body":"yes but do not create pull requests anymore","ref":"","assets":[],"labels":[{"id":3733,"name":"Question","exclusive":false,"is_archived":false,"color":"fbca04","description":"","url":"https://gitea.com/api/v1/repos/gitea/test_repo/labels/3733"}],"milestone":null,"assignee":null,"assignees":null,"state":"open","is_locked":false,"comments":0,"created_at":"2020-09-01T17:48:14Z","updated_at":"2020-09-01T17:48:14Z","closed_at":null,"due_date":null,"time_estimate":0,"pull_request":null,"repository":{"id":16268,"name":"test_repo","owner":"gitea","full_name":"gitea/test_repo"},"pin_order":0},{"id":30480,"url":"https://gitea.com/api/v1/repos/gitea/test_repo/issues/9","html_url":"https://gitea.com/gitea/test_repo/issues/9","number":9,"user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"original_author":"","original_author_id":0,"title":"Idears","body":"this is an example for an open issue - they just cant be all closed ;)","ref":"","assets":[],"labels":[{"id":3735,"name":"Enhancement","exclusive":false,"is_archived":false,"color":"207de5","description":"","url":"https://gitea.com/api/v1/repos/gitea/test_repo/labels/3735"}],"milestone":{"id":1301,"title":"V2 Finalize","description":"","state":"open","open_issues":1,"closed_issues":2,"created_at":"1970-01-01T00:00:00Z","updated_at":"2022-11-13T05:29:15Z","closed_at":null,"due_on":"2020-09-04T23:59:59Z"},"assignee":null,"assignees":null,"state":"open","is_locked":false,"comments":0,"created_at":"2020-09-01T17:47:11Z","updated_at":"2020-09-01T17:47:17Z","closed_at":null,"due_date":null,"time_estimate":0,"pull_request":null,"repository":{"id":16268,"name":"test_repo","owner":"gitea","full_name":"gitea/test_repo"},"pin_order":0},{"id":30477,"url":"https://gitea.com/api/v1/repos/gitea/test_repo/issues/6","html_url":"https://gitea.com/gitea/test_repo/issues/6","number":6,"user":{"id":9,"login":"techknowlogick","login_name":"","source_id":0,"full_name":"","email":"9+techknowlogick@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/9b588dd0b384d6f6ae841c5d62302033","html_url":"https://gitea.com/techknowlogick","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-01-14T06:48:35Z","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"https://techknowlogick.com","description":"","visibility":"public","followers_count":15,"following_count":1,"starred_repos_count":51,"username":"techknowlogick"},"original_author":"","original_author_id":0,"title":"Please add a tag (or a release)","body":"","ref":"","assets":[],"labels":[],"milestone":null,"assignee":null,"assignees":null,"state":"closed","is_locked":false,"comments":1,"created_at":"2020-09-01T16:07:01Z","updated_at":"2020-09-01T17:26:02Z","closed_at":"2020-09-01T17:26:02Z","due_date":null,"time_estimate":0,"pull_request":null,"repository":{"id":16268,"name":"test_repo","owner":"gitea","full_name":"gitea/test_repo"},"pin_order":0},{"id":30476,"url":"https://gitea.com/api/v1/repos/gitea/test_repo/issues/5","html_url":"https://gitea.com/gitea/test_repo/issues/5","number":5,"user":{"id":9,"login":"techknowlogick","login_name":"","source_id":0,"full_name":"","email":"9+techknowlogick@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/9b588dd0b384d6f6ae841c5d62302033","html_url":"https://gitea.com/techknowlogick","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-01-14T06:48:35Z","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"https://techknowlogick.com","description":"","visibility":"public","followers_count":15,"following_count":1,"starred_repos_count":51,"username":"techknowlogick"},"original_author":"","original_author_id":0,"title":"Need more contributors to this repo","body":"I volunteer as one","ref":"","assets":[],"labels":[],"milestone":{"id":1301,"title":"V2 Finalize","description":"","state":"open","open_issues":1,"closed_issues":2,"created_at":"1970-01-01T00:00:00Z","updated_at":"2022-11-13T05:29:15Z","closed_at":null,"due_on":"2020-09-04T23:59:59Z"},"assignee":null,"assignees":null,"state":"closed","is_locked":false,"comments":1,"created_at":"2020-09-01T16:06:30Z","updated_at":"2020-09-01T17:46:09Z","closed_at":"2020-09-01T17:46:09Z","due_date":null,"time_estimate":0,"pull_request":null,"repository":{"id":16268,"name":"test_repo","owner":"gitea","full_name":"gitea/test_repo"},"pin_order":0},{"id":30475,"url":"https://gitea.com/api/v1/repos/gitea/test_repo/issues/4","html_url":"https://gitea.com/gitea/test_repo/issues/4","number":4,"user":{"id":-1,"login":"Ghost","login_name":"","source_id":0,"full_name":"","email":"-1+ghost@noreply.gitea.com","avatar_url":"https://gitea.com/assets/img/avatar_default.png","html_url":"https://gitea.com/Ghost","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"1970-01-01T00:00:00Z","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"Ghost"},"original_author":"","original_author_id":0,"title":"what is this repo about?","body":"","ref":"","assets":[],"labels":[{"id":3733,"name":"Question","exclusive":false,"is_archived":false,"color":"fbca04","description":"","url":"https://gitea.com/api/v1/repos/gitea/test_repo/labels/3733"}],"milestone":{"id":1300,"title":"V1","description":"Generate Content","state":"closed","open_issues":0,"closed_issues":4,"created_at":"1970-01-01T00:00:00Z","updated_at":"1970-01-01T00:00:00Z","closed_at":"2020-09-01T18:36:46Z","due_on":null},"assignee":null,"assignees":null,"state":"closed","is_locked":true,"comments":2,"created_at":"2020-09-01T15:48:41Z","updated_at":"2020-09-01T15:50:00Z","closed_at":"2020-09-01T15:49:34Z","due_date":null,"time_estimate":0,"pull_request":null,"repository":{"id":16268,"name":"test_repo","owner":"gitea","full_name":"gitea/test_repo"},"pin_order":0},{"id":30471,"url":"https://gitea.com/api/v1/repos/gitea/test_repo/issues/2","html_url":"https://gitea.com/gitea/test_repo/issues/2","number":2,"user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"original_author":"","original_author_id":0,"title":"Spam","body":":(","ref":"","assets":[],"labels":[{"id":3732,"name":"Invalid","exclusive":false,"is_archived":false,"color":"d4c5f9","description":"","url":"https://gitea.com/api/v1/repos/gitea/test_repo/labels/3732"}],"milestone":null,"assignee":null,"assignees":null,"state":"closed","is_locked":false,"comments":2,"created_at":"2020-09-01T00:23:00Z","updated_at":"2020-09-01T14:11:37Z","closed_at":"2020-09-01T14:11:37Z","due_date":null,"time_estimate":0,"pull_request":null,"repository":{"id":16268,"name":"test_repo","owner":"gitea","full_name":"gitea/test_repo"},"pin_order":0},{"id":30470,"url":"https://gitea.com/api/v1/repos/gitea/test_repo/issues/1","html_url":"https://gitea.com/gitea/test_repo/issues/1","number":1,"user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"original_author":"","original_author_id":0,"title":"Here Is no content!","body":"","ref":"","assets":[],"labels":[{"id":3734,"name":"Valid","exclusive":false,"is_archived":false,"color":"53e917","description":"","url":"https://gitea.com/api/v1/repos/gitea/test_repo/labels/3734"}],"milestone":{"id":1300,"title":"V1","description":"Generate Content","state":"closed","open_issues":0,"closed_issues":4,"created_at":"1970-01-01T00:00:00Z","updated_at":"1970-01-01T00:00:00Z","closed_at":"2020-09-01T18:36:46Z","due_on":null},"assignee":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"assignees":[{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"}],"state":"closed","is_locked":false,"comments":0,"created_at":"2020-09-01T00:15:11Z","updated_at":"2020-09-01T17:26:25Z","closed_at":"2020-09-01T17:26:25Z","due_date":null,"time_estimate":0,"pull_request":null,"repository":{"id":16268,"name":"test_repo","owner":"gitea","full_name":"gitea/test_repo"},"pin_order":0}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Flabels%3Flimit%3D50%26page%3D1 b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Flabels%3Flimit%3D50%26page%3D1 new file mode 100644 index 00000000..db9a0c05 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Flabels%3Flimit%3D50%26page%3D1 @@ -0,0 +1,10 @@ +Access-Control-Expose-Headers: X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 1025 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 6 + +[{"id":3730,"name":"Bug","exclusive":false,"is_archived":false,"color":"e11d21","description":"","url":"https://gitea.com/api/v1/repos/gitea/test_repo/labels/3730"},{"id":3735,"name":"Enhancement","exclusive":false,"is_archived":false,"color":"207de5","description":"","url":"https://gitea.com/api/v1/repos/gitea/test_repo/labels/3735"},{"id":3731,"name":"Feature","exclusive":false,"is_archived":false,"color":"0052cc","description":"a feature request","url":"https://gitea.com/api/v1/repos/gitea/test_repo/labels/3731"},{"id":3732,"name":"Invalid","exclusive":false,"is_archived":false,"color":"d4c5f9","description":"","url":"https://gitea.com/api/v1/repos/gitea/test_repo/labels/3732"},{"id":3733,"name":"Question","exclusive":false,"is_archived":false,"color":"fbca04","description":"","url":"https://gitea.com/api/v1/repos/gitea/test_repo/labels/3733"},{"id":3734,"name":"Valid","exclusive":false,"is_archived":false,"color":"53e917","description":"","url":"https://gitea.com/api/v1/repos/gitea/test_repo/labels/3734"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fmilestones%3Flimit%3D50%26page%3D1%26state%3Dall b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fmilestones%3Flimit%3D50%26page%3D1%26state%3Dall new file mode 100644 index 00000000..49aa331b --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fmilestones%3Flimit%3D50%26page%3D1%26state%3Dall @@ -0,0 +1,10 @@ +Access-Control-Expose-Headers: X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 452 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 2 + +[{"id":1300,"title":"V1","description":"Generate Content","state":"closed","open_issues":0,"closed_issues":4,"created_at":"1970-01-01T00:00:00Z","updated_at":"1970-01-01T00:00:00Z","closed_at":"2020-09-01T18:36:46Z","due_on":null},{"id":1301,"title":"V2 Finalize","description":"","state":"open","open_issues":1,"closed_issues":2,"created_at":"1970-01-01T00:00:00Z","updated_at":"2022-11-13T05:29:15Z","closed_at":null,"due_on":"2020-09-04T23:59:59Z"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%2F7%2Freviews%2F1770%2Fcomments b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%2F7%2Freviews%2F1770%2Fcomments new file mode 100644 index 00000000..e4d090dd --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%2F7%2Freviews%2F1770%2Fcomments @@ -0,0 +1,8 @@ +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 1225 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff + +[{"id":116561,"body":"is one `\\newline` to less?","user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"resolver":null,"pull_request_review_id":1770,"created_at":"2020-09-01T16:12:58Z","updated_at":"2024-06-03T01:18:36Z","path":"README.md","commit_id":"187ece0cb6631e2858a6872e5733433bb3ca3b03","original_commit_id":"","diff_hunk":"@@ -2,3 +2,3 @@\n \n-Test repository for testing migration from gitea 2 gitea\n\\ No newline at end of file\n+Test repository for testing migration from gitea 2 gitea","position":4,"original_position":0,"html_url":"https://gitea.com/gitea/test_repo/pulls/7#issuecomment-116561","pull_request_url":"https://gitea.com/gitea/test_repo/pulls/7"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%2F7%2Freviews%2F1771%2Fcomments b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%2F7%2Freviews%2F1771%2Fcomments new file mode 100644 index 00000000..a8ae76d7 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%2F7%2Freviews%2F1771%2Fcomments @@ -0,0 +1,8 @@ +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 2 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%2F7%2Freviews%2F1772%2Fcomments b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%2F7%2Freviews%2F1772%2Fcomments new file mode 100644 index 00000000..a8ae76d7 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%2F7%2Freviews%2F1772%2Fcomments @@ -0,0 +1,8 @@ +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 2 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%2F7%2Freviews%3Flimit%3D50%26page%3D1 b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%2F7%2Freviews%3Flimit%3D50%26page%3D1 new file mode 100644 index 00000000..5aee56e7 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%2F7%2Freviews%3Flimit%3D50%26page%3D1 @@ -0,0 +1,9 @@ +Access-Control-Expose-Headers: X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 3 + +[{"id":1770,"user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"team":null,"state":"COMMENT","body":"","commit_id":"187ece0cb6631e2858a6872e5733433bb3ca3b03","stale":false,"official":false,"dismissed":true,"comments_count":1,"submitted_at":"2020-09-01T16:12:58Z","updated_at":"2021-04-18T22:00:49Z","html_url":"https://gitea.com/gitea/test_repo/pulls/7#issuecomment-116562","pull_request_url":"https://gitea.com/gitea/test_repo/pulls/7"},{"id":1771,"user":{"id":9,"login":"techknowlogick","login_name":"","source_id":0,"full_name":"","email":"9+techknowlogick@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/9b588dd0b384d6f6ae841c5d62302033","html_url":"https://gitea.com/techknowlogick","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-01-14T06:48:35Z","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"https://techknowlogick.com","description":"","visibility":"public","followers_count":15,"following_count":1,"starred_repos_count":51,"username":"techknowlogick"},"team":null,"state":"REQUEST_CHANGES","body":"I think this needs some changes","commit_id":"187ece0cb6631e2858a6872e5733433bb3ca3b03","stale":false,"official":false,"dismissed":true,"comments_count":0,"submitted_at":"2020-09-01T17:06:47Z","updated_at":"2021-04-18T22:00:49Z","html_url":"https://gitea.com/gitea/test_repo/pulls/7#issuecomment-116563","pull_request_url":"https://gitea.com/gitea/test_repo/pulls/7"},{"id":1772,"user":{"id":9,"login":"techknowlogick","login_name":"","source_id":0,"full_name":"","email":"9+techknowlogick@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/9b588dd0b384d6f6ae841c5d62302033","html_url":"https://gitea.com/techknowlogick","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-01-14T06:48:35Z","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"https://techknowlogick.com","description":"","visibility":"public","followers_count":15,"following_count":1,"starred_repos_count":51,"username":"techknowlogick"},"team":null,"state":"APPROVED","body":"looks good","commit_id":"187ece0cb6631e2858a6872e5733433bb3ca3b03","stale":false,"official":true,"dismissed":true,"comments_count":0,"submitted_at":"2020-09-01T17:19:51Z","updated_at":"2021-04-18T22:00:49Z","html_url":"https://gitea.com/gitea/test_repo/pulls/7#issuecomment-116564","pull_request_url":"https://gitea.com/gitea/test_repo/pulls/7"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%3Flimit%3D3%26page%3D1%26state%3Dall b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%3Flimit%3D3%26page%3D1%26state%3Dall new file mode 100644 index 00000000..cdf1f0d2 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%3Flimit%3D3%26page%3D1%26state%3Dall @@ -0,0 +1,10 @@ +Access-Control-Expose-Headers: Link, X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Type: application/json;charset=utf-8 +Link: ; rel="next",; rel="last" +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 6 + +[{"id":4955,"url":"https://gitea.com/gitea/test_repo/pulls/13","number":13,"user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"title":"extend","body":"","labels":[],"milestone":null,"assignee":null,"assignees":null,"requested_reviewers":null,"requested_reviewers_teams":null,"state":"open","draft":false,"is_locked":true,"comments":1,"review_comments":0,"html_url":"https://gitea.com/gitea/test_repo/pulls/13","diff_url":"https://gitea.com/gitea/test_repo/pulls/13.diff","patch_url":"https://gitea.com/gitea/test_repo/pulls/13.patch","mergeable":true,"merged":false,"merged_at":null,"merge_commit_sha":null,"merged_by":null,"allow_maintainer_edit":false,"base":{"label":"master","ref":"master","sha":"827aa28a907853e5ddfa40c8f9bc52471a2685fd","repo_id":16268,"repo":{"id":16268,"owner":{"id":3,"login":"gitea","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/35dea380390772b3130aafbac7ca49e6","html_url":"https://gitea.com/gitea","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2018-11-29T03:16:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"Git Universe","website":"https://gitea.com","description":"Git with a cup of tea","visibility":"public","followers_count":100,"following_count":0,"starred_repos_count":0,"username":"gitea"},"name":"test_repo","full_name":"gitea/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":false,"template":false,"mirror":false,"size":68,"language":"","languages_url":"https://gitea.com/api/v1/repos/gitea/test_repo/languages","html_url":"https://gitea.com/gitea/test_repo","url":"https://gitea.com/api/v1/repos/gitea/test_repo","link":"","ssh_url":"git@gitea.com:gitea/test_repo.git","clone_url":"https://gitea.com/gitea/test_repo.git","original_url":"","website":"","stars_count":1,"forks_count":2,"watchers_count":10,"open_issues_count":2,"open_pr_counter":2,"release_counter":2,"default_branch":"master","archived":false,"created_at":"2020-09-01T00:12:27Z","updated_at":"2020-09-01T18:03:41Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"projects_mode":"","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"allow_fast_forward_only_merge":false,"allow_rebase_update":true,"allow_manual_merge":false,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":["gitea","test","migration","ci"],"licenses":[]}},"head":{"label":"6543-patch-1","ref":"6543-patch-1","sha":"0ba7693bfd50d26df7f1b7414e937786c5efb05d","repo_id":16268,"repo":{"id":16268,"owner":{"id":3,"login":"gitea","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/35dea380390772b3130aafbac7ca49e6","html_url":"https://gitea.com/gitea","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2018-11-29T03:16:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"Git Universe","website":"https://gitea.com","description":"Git with a cup of tea","visibility":"public","followers_count":100,"following_count":0,"starred_repos_count":0,"username":"gitea"},"name":"test_repo","full_name":"gitea/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":false,"template":false,"mirror":false,"size":68,"language":"","languages_url":"https://gitea.com/api/v1/repos/gitea/test_repo/languages","html_url":"https://gitea.com/gitea/test_repo","url":"https://gitea.com/api/v1/repos/gitea/test_repo","link":"","ssh_url":"git@gitea.com:gitea/test_repo.git","clone_url":"https://gitea.com/gitea/test_repo.git","original_url":"","website":"","stars_count":1,"forks_count":2,"watchers_count":10,"open_issues_count":2,"open_pr_counter":2,"release_counter":2,"default_branch":"master","archived":false,"created_at":"2020-09-01T00:12:27Z","updated_at":"2020-09-01T18:03:41Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"projects_mode":"","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"allow_fast_forward_only_merge":false,"allow_rebase_update":true,"allow_manual_merge":false,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":["gitea","test","migration","ci"],"licenses":[]}},"merge_base":"827aa28a907853e5ddfa40c8f9bc52471a2685fd","due_date":null,"created_at":"2020-09-01T18:03:54Z","updated_at":"2020-09-01T18:04:26Z","closed_at":null,"pin_order":0},{"id":4954,"url":"https://gitea.com/gitea/test_repo/pulls/12","number":12,"user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"title":"Dont Touch","body":"\r\nadd dont touch note","labels":[],"milestone":{"id":1301,"title":"V2 Finalize","description":"","state":"open","open_issues":1,"closed_issues":2,"created_at":"1970-01-01T00:00:00Z","updated_at":"2022-11-13T05:29:15Z","closed_at":null,"due_on":"2020-09-04T23:59:59Z"},"assignee":{"id":9,"login":"techknowlogick","login_name":"","source_id":0,"full_name":"","email":"9+techknowlogick@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/9b588dd0b384d6f6ae841c5d62302033","html_url":"https://gitea.com/techknowlogick","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-01-14T06:48:35Z","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"https://techknowlogick.com","description":"","visibility":"public","followers_count":15,"following_count":1,"starred_repos_count":51,"username":"techknowlogick"},"assignees":[{"id":9,"login":"techknowlogick","login_name":"","source_id":0,"full_name":"","email":"9+techknowlogick@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/9b588dd0b384d6f6ae841c5d62302033","html_url":"https://gitea.com/techknowlogick","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-01-14T06:48:35Z","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"https://techknowlogick.com","description":"","visibility":"public","followers_count":15,"following_count":1,"starred_repos_count":51,"username":"techknowlogick"}],"requested_reviewers":null,"requested_reviewers_teams":null,"state":"closed","draft":false,"is_locked":false,"comments":3,"review_comments":3,"html_url":"https://gitea.com/gitea/test_repo/pulls/12","diff_url":"https://gitea.com/gitea/test_repo/pulls/12.diff","patch_url":"https://gitea.com/gitea/test_repo/pulls/12.patch","mergeable":true,"merged":true,"merged_at":"2020-09-01T17:55:34Z","merge_commit_sha":"827aa28a907853e5ddfa40c8f9bc52471a2685fd","merged_by":null,"allow_maintainer_edit":false,"base":{"label":"master","ref":"master","sha":"827aa28a907853e5ddfa40c8f9bc52471a2685fd","repo_id":16268,"repo":{"id":16268,"owner":{"id":3,"login":"gitea","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/35dea380390772b3130aafbac7ca49e6","html_url":"https://gitea.com/gitea","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2018-11-29T03:16:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"Git Universe","website":"https://gitea.com","description":"Git with a cup of tea","visibility":"public","followers_count":100,"following_count":0,"starred_repos_count":0,"username":"gitea"},"name":"test_repo","full_name":"gitea/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":false,"template":false,"mirror":false,"size":68,"language":"","languages_url":"https://gitea.com/api/v1/repos/gitea/test_repo/languages","html_url":"https://gitea.com/gitea/test_repo","url":"https://gitea.com/api/v1/repos/gitea/test_repo","link":"","ssh_url":"git@gitea.com:gitea/test_repo.git","clone_url":"https://gitea.com/gitea/test_repo.git","original_url":"","website":"","stars_count":1,"forks_count":2,"watchers_count":10,"open_issues_count":2,"open_pr_counter":2,"release_counter":2,"default_branch":"master","archived":false,"created_at":"2020-09-01T00:12:27Z","updated_at":"2020-09-01T18:03:41Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"projects_mode":"","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"allow_fast_forward_only_merge":false,"allow_rebase_update":true,"allow_manual_merge":false,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":["gitea","test","migration","ci"],"licenses":[]}},"head":{"label":"Add-Dont-Touch-Note","ref":"refs/pull/12/head","sha":"b6ab5d9ae000b579a5fff03f92c486da4ddf48b6","repo_id":16280,"repo":{"id":16280,"owner":{"id":9756,"login":"6543-forks","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/c3948ab3b9b62e070e87a22681909dee","html_url":"https://gitea.com/6543-forks","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2020-09-01T17:33:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"","description":"@6543's fork org","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"6543-forks"},"name":"test_repo","full_name":"6543-forks/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":true,"template":false,"parent":{"id":16268,"owner":{"id":3,"login":"gitea","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/35dea380390772b3130aafbac7ca49e6","html_url":"https://gitea.com/gitea","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2018-11-29T03:16:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"Git Universe","website":"https://gitea.com","description":"Git with a cup of tea","visibility":"public","followers_count":100,"following_count":0,"starred_repos_count":0,"username":"gitea"},"name":"test_repo","full_name":"gitea/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":false,"template":false,"mirror":false,"size":68,"language":"","languages_url":"https://gitea.com/api/v1/repos/gitea/test_repo/languages","html_url":"https://gitea.com/gitea/test_repo","url":"https://gitea.com/api/v1/repos/gitea/test_repo","link":"","ssh_url":"git@gitea.com:gitea/test_repo.git","clone_url":"https://gitea.com/gitea/test_repo.git","original_url":"","website":"","stars_count":1,"forks_count":2,"watchers_count":10,"open_issues_count":2,"open_pr_counter":2,"release_counter":2,"default_branch":"master","archived":false,"created_at":"2020-09-01T00:12:27Z","updated_at":"2020-09-01T18:03:41Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"projects_mode":"","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"allow_fast_forward_only_merge":false,"allow_rebase_update":true,"allow_manual_merge":false,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":["gitea","test","migration","ci"],"licenses":[]},"mirror":false,"size":67,"language":"","languages_url":"https://gitea.com/api/v1/repos/6543-forks/test_repo/languages","html_url":"https://gitea.com/6543-forks/test_repo","url":"https://gitea.com/api/v1/repos/6543-forks/test_repo","link":"","ssh_url":"git@gitea.com:6543-forks/test_repo.git","clone_url":"https://gitea.com/6543-forks/test_repo.git","original_url":"","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2020-09-01T17:39:26Z","updated_at":"2020-09-01T17:57:07Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":false,"has_wiki":false,"has_pull_requests":false,"has_projects":false,"projects_mode":"all","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":false,"allow_rebase":false,"allow_rebase_explicit":false,"allow_squash_merge":false,"allow_fast_forward_only_merge":false,"allow_rebase_update":false,"allow_manual_merge":true,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":[],"licenses":[]}},"merge_base":"d9e165e4c7ab6b701f0205d0ffb637e5d2856297","due_date":null,"created_at":"2020-09-01T17:52:39Z","updated_at":"2020-09-02T05:10:25Z","closed_at":"2020-09-01T17:55:33Z","pin_order":0},{"id":4953,"url":"https://gitea.com/gitea/test_repo/pulls/11","number":11,"user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"title":"add-xkcd-2199","body":"","labels":[{"id":3734,"name":"Valid","exclusive":false,"is_archived":false,"color":"53e917","description":"","url":"https://gitea.com/api/v1/repos/gitea/test_repo/labels/3734"}],"milestone":null,"assignee":null,"assignees":null,"requested_reviewers":null,"requested_reviewers_teams":null,"state":"open","draft":false,"is_locked":false,"comments":0,"review_comments":0,"html_url":"https://gitea.com/gitea/test_repo/pulls/11","diff_url":"https://gitea.com/gitea/test_repo/pulls/11.diff","patch_url":"https://gitea.com/gitea/test_repo/pulls/11.patch","mergeable":true,"merged":false,"merged_at":null,"merge_commit_sha":null,"merged_by":null,"allow_maintainer_edit":false,"base":{"label":"master","ref":"master","sha":"827aa28a907853e5ddfa40c8f9bc52471a2685fd","repo_id":16268,"repo":{"id":16268,"owner":{"id":3,"login":"gitea","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/35dea380390772b3130aafbac7ca49e6","html_url":"https://gitea.com/gitea","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2018-11-29T03:16:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"Git Universe","website":"https://gitea.com","description":"Git with a cup of tea","visibility":"public","followers_count":100,"following_count":0,"starred_repos_count":0,"username":"gitea"},"name":"test_repo","full_name":"gitea/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":false,"template":false,"mirror":false,"size":68,"language":"","languages_url":"https://gitea.com/api/v1/repos/gitea/test_repo/languages","html_url":"https://gitea.com/gitea/test_repo","url":"https://gitea.com/api/v1/repos/gitea/test_repo","link":"","ssh_url":"git@gitea.com:gitea/test_repo.git","clone_url":"https://gitea.com/gitea/test_repo.git","original_url":"","website":"","stars_count":1,"forks_count":2,"watchers_count":10,"open_issues_count":2,"open_pr_counter":2,"release_counter":2,"default_branch":"master","archived":false,"created_at":"2020-09-01T00:12:27Z","updated_at":"2020-09-01T18:03:41Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"projects_mode":"","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"allow_fast_forward_only_merge":false,"allow_rebase_update":true,"allow_manual_merge":false,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":["gitea","test","migration","ci"],"licenses":[]}},"head":{"label":"add-xkcd-2199","ref":"add-xkcd-2199","sha":"6bbd02573205288faa95d25e917812b2815a37e5","repo_id":16280,"repo":{"id":16280,"owner":{"id":9756,"login":"6543-forks","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/c3948ab3b9b62e070e87a22681909dee","html_url":"https://gitea.com/6543-forks","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2020-09-01T17:33:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"","description":"@6543's fork org","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"6543-forks"},"name":"test_repo","full_name":"6543-forks/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":true,"template":false,"parent":{"id":16268,"owner":{"id":3,"login":"gitea","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/35dea380390772b3130aafbac7ca49e6","html_url":"https://gitea.com/gitea","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2018-11-29T03:16:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"Git Universe","website":"https://gitea.com","description":"Git with a cup of tea","visibility":"public","followers_count":100,"following_count":0,"starred_repos_count":0,"username":"gitea"},"name":"test_repo","full_name":"gitea/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":false,"template":false,"mirror":false,"size":68,"language":"","languages_url":"https://gitea.com/api/v1/repos/gitea/test_repo/languages","html_url":"https://gitea.com/gitea/test_repo","url":"https://gitea.com/api/v1/repos/gitea/test_repo","link":"","ssh_url":"git@gitea.com:gitea/test_repo.git","clone_url":"https://gitea.com/gitea/test_repo.git","original_url":"","website":"","stars_count":1,"forks_count":2,"watchers_count":10,"open_issues_count":2,"open_pr_counter":2,"release_counter":2,"default_branch":"master","archived":false,"created_at":"2020-09-01T00:12:27Z","updated_at":"2020-09-01T18:03:41Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"projects_mode":"","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"allow_fast_forward_only_merge":false,"allow_rebase_update":true,"allow_manual_merge":false,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":["gitea","test","migration","ci"],"licenses":[]},"mirror":false,"size":67,"language":"","languages_url":"https://gitea.com/api/v1/repos/6543-forks/test_repo/languages","html_url":"https://gitea.com/6543-forks/test_repo","url":"https://gitea.com/api/v1/repos/6543-forks/test_repo","link":"","ssh_url":"git@gitea.com:6543-forks/test_repo.git","clone_url":"https://gitea.com/6543-forks/test_repo.git","original_url":"","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2020-09-01T17:39:26Z","updated_at":"2020-09-01T17:57:07Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":false,"has_wiki":false,"has_pull_requests":false,"has_projects":false,"projects_mode":"all","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":false,"allow_rebase":false,"allow_rebase_explicit":false,"allow_squash_merge":false,"allow_fast_forward_only_merge":false,"allow_rebase_update":false,"allow_manual_merge":true,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":[],"licenses":[]}},"merge_base":"b6ab5d9ae000b579a5fff03f92c486da4ddf48b6","due_date":null,"created_at":"2020-09-01T17:52:28Z","updated_at":"2020-09-01T17:52:29Z","closed_at":null,"pin_order":0}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%3Flimit%3D50%26page%3D1%26state%3Dall b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%3Flimit%3D50%26page%3D1%26state%3Dall new file mode 100644 index 00000000..bee7f367 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Fpulls%3Flimit%3D50%26page%3D1%26state%3Dall @@ -0,0 +1,9 @@ +Access-Control-Expose-Headers: X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 6 + +[{"id":4955,"url":"https://gitea.com/gitea/test_repo/pulls/13","number":13,"user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"title":"extend","body":"","labels":[],"milestone":null,"assignee":null,"assignees":null,"requested_reviewers":null,"requested_reviewers_teams":null,"state":"open","draft":false,"is_locked":true,"comments":1,"review_comments":0,"html_url":"https://gitea.com/gitea/test_repo/pulls/13","diff_url":"https://gitea.com/gitea/test_repo/pulls/13.diff","patch_url":"https://gitea.com/gitea/test_repo/pulls/13.patch","mergeable":true,"merged":false,"merged_at":null,"merge_commit_sha":null,"merged_by":null,"allow_maintainer_edit":false,"base":{"label":"master","ref":"master","sha":"827aa28a907853e5ddfa40c8f9bc52471a2685fd","repo_id":16268,"repo":{"id":16268,"owner":{"id":3,"login":"gitea","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/35dea380390772b3130aafbac7ca49e6","html_url":"https://gitea.com/gitea","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2018-11-29T03:16:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"Git Universe","website":"https://gitea.com","description":"Git with a cup of tea","visibility":"public","followers_count":100,"following_count":0,"starred_repos_count":0,"username":"gitea"},"name":"test_repo","full_name":"gitea/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":false,"template":false,"mirror":false,"size":68,"language":"","languages_url":"https://gitea.com/api/v1/repos/gitea/test_repo/languages","html_url":"https://gitea.com/gitea/test_repo","url":"https://gitea.com/api/v1/repos/gitea/test_repo","link":"","ssh_url":"git@gitea.com:gitea/test_repo.git","clone_url":"https://gitea.com/gitea/test_repo.git","original_url":"","website":"","stars_count":1,"forks_count":2,"watchers_count":10,"open_issues_count":2,"open_pr_counter":2,"release_counter":2,"default_branch":"master","archived":false,"created_at":"2020-09-01T00:12:27Z","updated_at":"2020-09-01T18:03:41Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"projects_mode":"","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"allow_fast_forward_only_merge":false,"allow_rebase_update":true,"allow_manual_merge":false,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":["gitea","test","migration","ci"],"licenses":[]}},"head":{"label":"6543-patch-1","ref":"6543-patch-1","sha":"0ba7693bfd50d26df7f1b7414e937786c5efb05d","repo_id":16268,"repo":{"id":16268,"owner":{"id":3,"login":"gitea","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/35dea380390772b3130aafbac7ca49e6","html_url":"https://gitea.com/gitea","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2018-11-29T03:16:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"Git Universe","website":"https://gitea.com","description":"Git with a cup of tea","visibility":"public","followers_count":100,"following_count":0,"starred_repos_count":0,"username":"gitea"},"name":"test_repo","full_name":"gitea/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":false,"template":false,"mirror":false,"size":68,"language":"","languages_url":"https://gitea.com/api/v1/repos/gitea/test_repo/languages","html_url":"https://gitea.com/gitea/test_repo","url":"https://gitea.com/api/v1/repos/gitea/test_repo","link":"","ssh_url":"git@gitea.com:gitea/test_repo.git","clone_url":"https://gitea.com/gitea/test_repo.git","original_url":"","website":"","stars_count":1,"forks_count":2,"watchers_count":10,"open_issues_count":2,"open_pr_counter":2,"release_counter":2,"default_branch":"master","archived":false,"created_at":"2020-09-01T00:12:27Z","updated_at":"2020-09-01T18:03:41Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"projects_mode":"","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"allow_fast_forward_only_merge":false,"allow_rebase_update":true,"allow_manual_merge":false,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":["gitea","test","migration","ci"],"licenses":[]}},"merge_base":"827aa28a907853e5ddfa40c8f9bc52471a2685fd","due_date":null,"created_at":"2020-09-01T18:03:54Z","updated_at":"2020-09-01T18:04:26Z","closed_at":null,"pin_order":0},{"id":4954,"url":"https://gitea.com/gitea/test_repo/pulls/12","number":12,"user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"title":"Dont Touch","body":"\r\nadd dont touch note","labels":[],"milestone":{"id":1301,"title":"V2 Finalize","description":"","state":"open","open_issues":1,"closed_issues":2,"created_at":"1970-01-01T00:00:00Z","updated_at":"2022-11-13T05:29:15Z","closed_at":null,"due_on":"2020-09-04T23:59:59Z"},"assignee":{"id":9,"login":"techknowlogick","login_name":"","source_id":0,"full_name":"","email":"9+techknowlogick@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/9b588dd0b384d6f6ae841c5d62302033","html_url":"https://gitea.com/techknowlogick","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-01-14T06:48:35Z","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"https://techknowlogick.com","description":"","visibility":"public","followers_count":15,"following_count":1,"starred_repos_count":51,"username":"techknowlogick"},"assignees":[{"id":9,"login":"techknowlogick","login_name":"","source_id":0,"full_name":"","email":"9+techknowlogick@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/9b588dd0b384d6f6ae841c5d62302033","html_url":"https://gitea.com/techknowlogick","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-01-14T06:48:35Z","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"https://techknowlogick.com","description":"","visibility":"public","followers_count":15,"following_count":1,"starred_repos_count":51,"username":"techknowlogick"}],"requested_reviewers":null,"requested_reviewers_teams":null,"state":"closed","draft":false,"is_locked":false,"comments":3,"review_comments":3,"html_url":"https://gitea.com/gitea/test_repo/pulls/12","diff_url":"https://gitea.com/gitea/test_repo/pulls/12.diff","patch_url":"https://gitea.com/gitea/test_repo/pulls/12.patch","mergeable":true,"merged":true,"merged_at":"2020-09-01T17:55:34Z","merge_commit_sha":"827aa28a907853e5ddfa40c8f9bc52471a2685fd","merged_by":null,"allow_maintainer_edit":false,"base":{"label":"master","ref":"master","sha":"827aa28a907853e5ddfa40c8f9bc52471a2685fd","repo_id":16268,"repo":{"id":16268,"owner":{"id":3,"login":"gitea","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/35dea380390772b3130aafbac7ca49e6","html_url":"https://gitea.com/gitea","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2018-11-29T03:16:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"Git Universe","website":"https://gitea.com","description":"Git with a cup of tea","visibility":"public","followers_count":100,"following_count":0,"starred_repos_count":0,"username":"gitea"},"name":"test_repo","full_name":"gitea/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":false,"template":false,"mirror":false,"size":68,"language":"","languages_url":"https://gitea.com/api/v1/repos/gitea/test_repo/languages","html_url":"https://gitea.com/gitea/test_repo","url":"https://gitea.com/api/v1/repos/gitea/test_repo","link":"","ssh_url":"git@gitea.com:gitea/test_repo.git","clone_url":"https://gitea.com/gitea/test_repo.git","original_url":"","website":"","stars_count":1,"forks_count":2,"watchers_count":10,"open_issues_count":2,"open_pr_counter":2,"release_counter":2,"default_branch":"master","archived":false,"created_at":"2020-09-01T00:12:27Z","updated_at":"2020-09-01T18:03:41Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"projects_mode":"","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"allow_fast_forward_only_merge":false,"allow_rebase_update":true,"allow_manual_merge":false,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":["gitea","test","migration","ci"],"licenses":[]}},"head":{"label":"Add-Dont-Touch-Note","ref":"refs/pull/12/head","sha":"b6ab5d9ae000b579a5fff03f92c486da4ddf48b6","repo_id":16280,"repo":{"id":16280,"owner":{"id":9756,"login":"6543-forks","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/c3948ab3b9b62e070e87a22681909dee","html_url":"https://gitea.com/6543-forks","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2020-09-01T17:33:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"","description":"@6543's fork org","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"6543-forks"},"name":"test_repo","full_name":"6543-forks/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":true,"template":false,"parent":{"id":16268,"owner":{"id":3,"login":"gitea","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/35dea380390772b3130aafbac7ca49e6","html_url":"https://gitea.com/gitea","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2018-11-29T03:16:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"Git Universe","website":"https://gitea.com","description":"Git with a cup of tea","visibility":"public","followers_count":100,"following_count":0,"starred_repos_count":0,"username":"gitea"},"name":"test_repo","full_name":"gitea/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":false,"template":false,"mirror":false,"size":68,"language":"","languages_url":"https://gitea.com/api/v1/repos/gitea/test_repo/languages","html_url":"https://gitea.com/gitea/test_repo","url":"https://gitea.com/api/v1/repos/gitea/test_repo","link":"","ssh_url":"git@gitea.com:gitea/test_repo.git","clone_url":"https://gitea.com/gitea/test_repo.git","original_url":"","website":"","stars_count":1,"forks_count":2,"watchers_count":10,"open_issues_count":2,"open_pr_counter":2,"release_counter":2,"default_branch":"master","archived":false,"created_at":"2020-09-01T00:12:27Z","updated_at":"2020-09-01T18:03:41Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"projects_mode":"","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"allow_fast_forward_only_merge":false,"allow_rebase_update":true,"allow_manual_merge":false,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":["gitea","test","migration","ci"],"licenses":[]},"mirror":false,"size":67,"language":"","languages_url":"https://gitea.com/api/v1/repos/6543-forks/test_repo/languages","html_url":"https://gitea.com/6543-forks/test_repo","url":"https://gitea.com/api/v1/repos/6543-forks/test_repo","link":"","ssh_url":"git@gitea.com:6543-forks/test_repo.git","clone_url":"https://gitea.com/6543-forks/test_repo.git","original_url":"","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2020-09-01T17:39:26Z","updated_at":"2020-09-01T17:57:07Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":false,"has_wiki":false,"has_pull_requests":false,"has_projects":false,"projects_mode":"all","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":false,"allow_rebase":false,"allow_rebase_explicit":false,"allow_squash_merge":false,"allow_fast_forward_only_merge":false,"allow_rebase_update":false,"allow_manual_merge":true,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":[],"licenses":[]}},"merge_base":"d9e165e4c7ab6b701f0205d0ffb637e5d2856297","due_date":null,"created_at":"2020-09-01T17:52:39Z","updated_at":"2020-09-02T05:10:25Z","closed_at":"2020-09-01T17:55:33Z","pin_order":0},{"id":4953,"url":"https://gitea.com/gitea/test_repo/pulls/11","number":11,"user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"title":"add-xkcd-2199","body":"","labels":[{"id":3734,"name":"Valid","exclusive":false,"is_archived":false,"color":"53e917","description":"","url":"https://gitea.com/api/v1/repos/gitea/test_repo/labels/3734"}],"milestone":null,"assignee":null,"assignees":null,"requested_reviewers":null,"requested_reviewers_teams":null,"state":"open","draft":false,"is_locked":false,"comments":0,"review_comments":0,"html_url":"https://gitea.com/gitea/test_repo/pulls/11","diff_url":"https://gitea.com/gitea/test_repo/pulls/11.diff","patch_url":"https://gitea.com/gitea/test_repo/pulls/11.patch","mergeable":true,"merged":false,"merged_at":null,"merge_commit_sha":null,"merged_by":null,"allow_maintainer_edit":false,"base":{"label":"master","ref":"master","sha":"827aa28a907853e5ddfa40c8f9bc52471a2685fd","repo_id":16268,"repo":{"id":16268,"owner":{"id":3,"login":"gitea","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/35dea380390772b3130aafbac7ca49e6","html_url":"https://gitea.com/gitea","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2018-11-29T03:16:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"Git Universe","website":"https://gitea.com","description":"Git with a cup of tea","visibility":"public","followers_count":100,"following_count":0,"starred_repos_count":0,"username":"gitea"},"name":"test_repo","full_name":"gitea/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":false,"template":false,"mirror":false,"size":68,"language":"","languages_url":"https://gitea.com/api/v1/repos/gitea/test_repo/languages","html_url":"https://gitea.com/gitea/test_repo","url":"https://gitea.com/api/v1/repos/gitea/test_repo","link":"","ssh_url":"git@gitea.com:gitea/test_repo.git","clone_url":"https://gitea.com/gitea/test_repo.git","original_url":"","website":"","stars_count":1,"forks_count":2,"watchers_count":10,"open_issues_count":2,"open_pr_counter":2,"release_counter":2,"default_branch":"master","archived":false,"created_at":"2020-09-01T00:12:27Z","updated_at":"2020-09-01T18:03:41Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"projects_mode":"","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"allow_fast_forward_only_merge":false,"allow_rebase_update":true,"allow_manual_merge":false,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":["gitea","test","migration","ci"],"licenses":[]}},"head":{"label":"add-xkcd-2199","ref":"add-xkcd-2199","sha":"6bbd02573205288faa95d25e917812b2815a37e5","repo_id":16280,"repo":{"id":16280,"owner":{"id":9756,"login":"6543-forks","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/c3948ab3b9b62e070e87a22681909dee","html_url":"https://gitea.com/6543-forks","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2020-09-01T17:33:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"","description":"@6543's fork org","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"6543-forks"},"name":"test_repo","full_name":"6543-forks/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":true,"template":false,"parent":{"id":16268,"owner":{"id":3,"login":"gitea","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/35dea380390772b3130aafbac7ca49e6","html_url":"https://gitea.com/gitea","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2018-11-29T03:16:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"Git Universe","website":"https://gitea.com","description":"Git with a cup of tea","visibility":"public","followers_count":100,"following_count":0,"starred_repos_count":0,"username":"gitea"},"name":"test_repo","full_name":"gitea/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":false,"template":false,"mirror":false,"size":68,"language":"","languages_url":"https://gitea.com/api/v1/repos/gitea/test_repo/languages","html_url":"https://gitea.com/gitea/test_repo","url":"https://gitea.com/api/v1/repos/gitea/test_repo","link":"","ssh_url":"git@gitea.com:gitea/test_repo.git","clone_url":"https://gitea.com/gitea/test_repo.git","original_url":"","website":"","stars_count":1,"forks_count":2,"watchers_count":10,"open_issues_count":2,"open_pr_counter":2,"release_counter":2,"default_branch":"master","archived":false,"created_at":"2020-09-01T00:12:27Z","updated_at":"2020-09-01T18:03:41Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"projects_mode":"","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"allow_fast_forward_only_merge":false,"allow_rebase_update":true,"allow_manual_merge":false,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":["gitea","test","migration","ci"],"licenses":[]},"mirror":false,"size":67,"language":"","languages_url":"https://gitea.com/api/v1/repos/6543-forks/test_repo/languages","html_url":"https://gitea.com/6543-forks/test_repo","url":"https://gitea.com/api/v1/repos/6543-forks/test_repo","link":"","ssh_url":"git@gitea.com:6543-forks/test_repo.git","clone_url":"https://gitea.com/6543-forks/test_repo.git","original_url":"","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2020-09-01T17:39:26Z","updated_at":"2020-09-01T17:57:07Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":false,"has_wiki":false,"has_pull_requests":false,"has_projects":false,"projects_mode":"all","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":false,"allow_rebase":false,"allow_rebase_explicit":false,"allow_squash_merge":false,"allow_fast_forward_only_merge":false,"allow_rebase_update":false,"allow_manual_merge":true,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":[],"licenses":[]}},"merge_base":"b6ab5d9ae000b579a5fff03f92c486da4ddf48b6","due_date":null,"created_at":"2020-09-01T17:52:28Z","updated_at":"2020-09-01T17:52:29Z","closed_at":null,"pin_order":0},{"id":4952,"url":"https://gitea.com/gitea/test_repo/pulls/8","number":8,"user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"title":"add garbage for close pull","body":"well you'll see","labels":[],"milestone":null,"assignee":null,"assignees":null,"requested_reviewers":null,"requested_reviewers_teams":null,"state":"closed","draft":false,"is_locked":false,"comments":0,"review_comments":0,"html_url":"https://gitea.com/gitea/test_repo/pulls/8","diff_url":"https://gitea.com/gitea/test_repo/pulls/8.diff","patch_url":"https://gitea.com/gitea/test_repo/pulls/8.patch","mergeable":true,"merged":false,"merged_at":null,"merge_commit_sha":null,"merged_by":null,"allow_maintainer_edit":false,"base":{"label":"master","ref":"master","sha":"827aa28a907853e5ddfa40c8f9bc52471a2685fd","repo_id":16268,"repo":{"id":16268,"owner":{"id":3,"login":"gitea","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/35dea380390772b3130aafbac7ca49e6","html_url":"https://gitea.com/gitea","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2018-11-29T03:16:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"Git Universe","website":"https://gitea.com","description":"Git with a cup of tea","visibility":"public","followers_count":100,"following_count":0,"starred_repos_count":0,"username":"gitea"},"name":"test_repo","full_name":"gitea/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":false,"template":false,"mirror":false,"size":68,"language":"","languages_url":"https://gitea.com/api/v1/repos/gitea/test_repo/languages","html_url":"https://gitea.com/gitea/test_repo","url":"https://gitea.com/api/v1/repos/gitea/test_repo","link":"","ssh_url":"git@gitea.com:gitea/test_repo.git","clone_url":"https://gitea.com/gitea/test_repo.git","original_url":"","website":"","stars_count":1,"forks_count":2,"watchers_count":10,"open_issues_count":2,"open_pr_counter":2,"release_counter":2,"default_branch":"master","archived":false,"created_at":"2020-09-01T00:12:27Z","updated_at":"2020-09-01T18:03:41Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"projects_mode":"","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"allow_fast_forward_only_merge":false,"allow_rebase_update":true,"allow_manual_merge":false,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":["gitea","test","migration","ci"],"licenses":[]}},"head":{"label":"garbage-patch","ref":"refs/pull/8/head","sha":"a3427235639a33d2d749e76f076e7619acc75341","repo_id":16280,"repo":{"id":16280,"owner":{"id":9756,"login":"6543-forks","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/c3948ab3b9b62e070e87a22681909dee","html_url":"https://gitea.com/6543-forks","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2020-09-01T17:33:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"","description":"@6543's fork org","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"6543-forks"},"name":"test_repo","full_name":"6543-forks/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":true,"template":false,"parent":{"id":16268,"owner":{"id":3,"login":"gitea","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/35dea380390772b3130aafbac7ca49e6","html_url":"https://gitea.com/gitea","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2018-11-29T03:16:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"Git Universe","website":"https://gitea.com","description":"Git with a cup of tea","visibility":"public","followers_count":100,"following_count":0,"starred_repos_count":0,"username":"gitea"},"name":"test_repo","full_name":"gitea/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":false,"template":false,"mirror":false,"size":68,"language":"","languages_url":"https://gitea.com/api/v1/repos/gitea/test_repo/languages","html_url":"https://gitea.com/gitea/test_repo","url":"https://gitea.com/api/v1/repos/gitea/test_repo","link":"","ssh_url":"git@gitea.com:gitea/test_repo.git","clone_url":"https://gitea.com/gitea/test_repo.git","original_url":"","website":"","stars_count":1,"forks_count":2,"watchers_count":10,"open_issues_count":2,"open_pr_counter":2,"release_counter":2,"default_branch":"master","archived":false,"created_at":"2020-09-01T00:12:27Z","updated_at":"2020-09-01T18:03:41Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"projects_mode":"","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"allow_fast_forward_only_merge":false,"allow_rebase_update":true,"allow_manual_merge":false,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":["gitea","test","migration","ci"],"licenses":[]},"mirror":false,"size":67,"language":"","languages_url":"https://gitea.com/api/v1/repos/6543-forks/test_repo/languages","html_url":"https://gitea.com/6543-forks/test_repo","url":"https://gitea.com/api/v1/repos/6543-forks/test_repo","link":"","ssh_url":"git@gitea.com:6543-forks/test_repo.git","clone_url":"https://gitea.com/6543-forks/test_repo.git","original_url":"","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2020-09-01T17:39:26Z","updated_at":"2020-09-01T17:57:07Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":false,"has_wiki":false,"has_pull_requests":false,"has_projects":false,"projects_mode":"all","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":false,"allow_rebase":false,"allow_rebase_explicit":false,"allow_squash_merge":false,"allow_fast_forward_only_merge":false,"allow_rebase_update":false,"allow_manual_merge":true,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":[],"licenses":[]}},"merge_base":"d9e165e4c7ab6b701f0205d0ffb637e5d2856297","due_date":null,"created_at":"2020-09-01T17:43:20Z","updated_at":"2020-09-01T17:48:41Z","closed_at":"2020-09-01T17:48:29Z","pin_order":0},{"id":4951,"url":"https://gitea.com/gitea/test_repo/pulls/7","number":7,"user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"title":"Prepare for Release V1","body":"@techknowlogick you might have a look at it?\n\nclose #6","labels":[{"id":3735,"name":"Enhancement","exclusive":false,"is_archived":false,"color":"207de5","description":"","url":"https://gitea.com/api/v1/repos/gitea/test_repo/labels/3735"}],"milestone":{"id":1300,"title":"V1","description":"Generate Content","state":"closed","open_issues":0,"closed_issues":4,"created_at":"1970-01-01T00:00:00Z","updated_at":"1970-01-01T00:00:00Z","closed_at":"2020-09-01T18:36:46Z","due_on":null},"assignee":null,"assignees":null,"requested_reviewers":null,"requested_reviewers_teams":null,"state":"closed","draft":false,"is_locked":false,"comments":4,"review_comments":3,"html_url":"https://gitea.com/gitea/test_repo/pulls/7","diff_url":"https://gitea.com/gitea/test_repo/pulls/7.diff","patch_url":"https://gitea.com/gitea/test_repo/pulls/7.patch","mergeable":true,"merged":true,"merged_at":"2020-09-01T17:26:02Z","merge_commit_sha":"d9e165e4c7ab6b701f0205d0ffb637e5d2856297","merged_by":null,"allow_maintainer_edit":false,"base":{"label":"master","ref":"master","sha":"827aa28a907853e5ddfa40c8f9bc52471a2685fd","repo_id":16268,"repo":{"id":16268,"owner":{"id":3,"login":"gitea","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/35dea380390772b3130aafbac7ca49e6","html_url":"https://gitea.com/gitea","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2018-11-29T03:16:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"Git Universe","website":"https://gitea.com","description":"Git with a cup of tea","visibility":"public","followers_count":100,"following_count":0,"starred_repos_count":0,"username":"gitea"},"name":"test_repo","full_name":"gitea/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":false,"template":false,"mirror":false,"size":68,"language":"","languages_url":"https://gitea.com/api/v1/repos/gitea/test_repo/languages","html_url":"https://gitea.com/gitea/test_repo","url":"https://gitea.com/api/v1/repos/gitea/test_repo","link":"","ssh_url":"git@gitea.com:gitea/test_repo.git","clone_url":"https://gitea.com/gitea/test_repo.git","original_url":"","website":"","stars_count":1,"forks_count":2,"watchers_count":10,"open_issues_count":2,"open_pr_counter":2,"release_counter":2,"default_branch":"master","archived":false,"created_at":"2020-09-01T00:12:27Z","updated_at":"2020-09-01T18:03:41Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"projects_mode":"","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"allow_fast_forward_only_merge":false,"allow_rebase_update":true,"allow_manual_merge":false,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":["gitea","test","migration","ci"],"licenses":[]}},"head":{"label":"prepare-v1","ref":"refs/pull/7/head","sha":"187ece0cb6631e2858a6872e5733433bb3ca3b03","repo_id":16268,"repo":{"id":16268,"owner":{"id":3,"login":"gitea","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/35dea380390772b3130aafbac7ca49e6","html_url":"https://gitea.com/gitea","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2018-11-29T03:16:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"Git Universe","website":"https://gitea.com","description":"Git with a cup of tea","visibility":"public","followers_count":100,"following_count":0,"starred_repos_count":0,"username":"gitea"},"name":"test_repo","full_name":"gitea/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":false,"template":false,"mirror":false,"size":68,"language":"","languages_url":"https://gitea.com/api/v1/repos/gitea/test_repo/languages","html_url":"https://gitea.com/gitea/test_repo","url":"https://gitea.com/api/v1/repos/gitea/test_repo","link":"","ssh_url":"git@gitea.com:gitea/test_repo.git","clone_url":"https://gitea.com/gitea/test_repo.git","original_url":"","website":"","stars_count":1,"forks_count":2,"watchers_count":10,"open_issues_count":2,"open_pr_counter":2,"release_counter":2,"default_branch":"master","archived":false,"created_at":"2020-09-01T00:12:27Z","updated_at":"2020-09-01T18:03:41Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"projects_mode":"","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"allow_fast_forward_only_merge":false,"allow_rebase_update":true,"allow_manual_merge":false,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":["gitea","test","migration","ci"],"licenses":[]}},"merge_base":"9396b697d905d1bcb5380befdf4d7e52c6a7ceb2","due_date":null,"created_at":"2020-09-01T16:10:04Z","updated_at":"2020-09-01T17:26:08Z","closed_at":"2020-09-01T17:26:02Z","pin_order":0},{"id":4949,"url":"https://gitea.com/gitea/test_repo/pulls/3","number":3,"user":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"title":"Readme: use '2'","body":"","labels":[{"id":3735,"name":"Enhancement","exclusive":false,"is_archived":false,"color":"207de5","description":"","url":"https://gitea.com/api/v1/repos/gitea/test_repo/labels/3735"}],"milestone":{"id":1300,"title":"V1","description":"Generate Content","state":"closed","open_issues":0,"closed_issues":4,"created_at":"1970-01-01T00:00:00Z","updated_at":"1970-01-01T00:00:00Z","closed_at":"2020-09-01T18:36:46Z","due_on":null},"assignee":null,"assignees":null,"requested_reviewers":null,"requested_reviewers_teams":null,"state":"closed","draft":false,"is_locked":false,"comments":0,"review_comments":0,"html_url":"https://gitea.com/gitea/test_repo/pulls/3","diff_url":"https://gitea.com/gitea/test_repo/pulls/3.diff","patch_url":"https://gitea.com/gitea/test_repo/pulls/3.patch","mergeable":true,"merged":true,"merged_at":"2020-09-01T00:27:14Z","merge_commit_sha":"9396b697d905d1bcb5380befdf4d7e52c6a7ceb2","merged_by":null,"allow_maintainer_edit":false,"base":{"label":"master","ref":"master","sha":"827aa28a907853e5ddfa40c8f9bc52471a2685fd","repo_id":16268,"repo":{"id":16268,"owner":{"id":3,"login":"gitea","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/35dea380390772b3130aafbac7ca49e6","html_url":"https://gitea.com/gitea","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2018-11-29T03:16:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"Git Universe","website":"https://gitea.com","description":"Git with a cup of tea","visibility":"public","followers_count":100,"following_count":0,"starred_repos_count":0,"username":"gitea"},"name":"test_repo","full_name":"gitea/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":false,"template":false,"mirror":false,"size":68,"language":"","languages_url":"https://gitea.com/api/v1/repos/gitea/test_repo/languages","html_url":"https://gitea.com/gitea/test_repo","url":"https://gitea.com/api/v1/repos/gitea/test_repo","link":"","ssh_url":"git@gitea.com:gitea/test_repo.git","clone_url":"https://gitea.com/gitea/test_repo.git","original_url":"","website":"","stars_count":1,"forks_count":2,"watchers_count":10,"open_issues_count":2,"open_pr_counter":2,"release_counter":2,"default_branch":"master","archived":false,"created_at":"2020-09-01T00:12:27Z","updated_at":"2020-09-01T18:03:41Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"projects_mode":"","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"allow_fast_forward_only_merge":false,"allow_rebase_update":true,"allow_manual_merge":false,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":["gitea","test","migration","ci"],"licenses":[]}},"head":{"label":"readme_nit","ref":"refs/pull/3/head","sha":"c273a16d4c3b2d745df690005dabe79cc6504ac3","repo_id":16268,"repo":{"id":16268,"owner":{"id":3,"login":"gitea","login_name":"","source_id":0,"full_name":"","email":"","avatar_url":"https://gitea.com/avatars/35dea380390772b3130aafbac7ca49e6","html_url":"https://gitea.com/gitea","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2018-11-29T03:16:17Z","restricted":false,"active":false,"prohibit_login":false,"location":"Git Universe","website":"https://gitea.com","description":"Git with a cup of tea","visibility":"public","followers_count":100,"following_count":0,"starred_repos_count":0,"username":"gitea"},"name":"test_repo","full_name":"gitea/test_repo","description":"Test repository for testing migration from gitea to gitea","empty":false,"private":false,"fork":false,"template":false,"mirror":false,"size":68,"language":"","languages_url":"https://gitea.com/api/v1/repos/gitea/test_repo/languages","html_url":"https://gitea.com/gitea/test_repo","url":"https://gitea.com/api/v1/repos/gitea/test_repo","link":"","ssh_url":"git@gitea.com:gitea/test_repo.git","clone_url":"https://gitea.com/gitea/test_repo.git","original_url":"","website":"","stars_count":1,"forks_count":2,"watchers_count":10,"open_issues_count":2,"open_pr_counter":2,"release_counter":2,"default_branch":"master","archived":false,"created_at":"2020-09-01T00:12:27Z","updated_at":"2020-09-01T18:03:41Z","archived_at":"1970-01-01T00:00:00Z","permissions":{"admin":false,"push":false,"pull":true},"has_code":true,"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"projects_mode":"","has_releases":true,"has_packages":false,"has_actions":false,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"allow_fast_forward_only_merge":false,"allow_rebase_update":true,"allow_manual_merge":false,"autodetect_manual_merge":false,"default_delete_branch_after_merge":false,"default_merge_style":"merge","default_allow_maintainer_edit":false,"avatar_url":"","internal":false,"mirror_interval":"","object_format_name":"sha1","mirror_updated":"0001-01-01T00:00:00Z","topics":["gitea","test","migration","ci"],"licenses":[]}},"merge_base":"a016fd754759b2cdfe5cad1cdf638c7e6b281940","due_date":null,"created_at":"2020-09-01T00:27:03Z","updated_at":"2020-09-01T15:54:30Z","closed_at":"2020-09-01T00:27:14Z","pin_order":0}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Freleases%3Flimit%3D50%26page%3D1 b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Freleases%3Flimit%3D50%26page%3D1 new file mode 100644 index 00000000..8757df58 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Freleases%3Flimit%3D50%26page%3D1 @@ -0,0 +1,9 @@ +Access-Control-Expose-Headers: X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 2 + +[{"id":167250,"tag_name":"v2-rc1","target_commitish":"master","name":"Second Release","body":"this repo has:\r\n* reactions\r\n* wiki\r\n* issues (open/closed)\r\n* pulls (open/closed/merged) (external/internal)\r\n* pull reviews\r\n* projects\r\n* milestones\r\n* labels\r\n* releases\r\n\r\nto test migration against","url":"https://gitea.com/api/v1/repos/gitea/test_repo/releases/167250","html_url":"https://gitea.com/gitea/test_repo/releases/tag/v2-rc1","tarball_url":"https://gitea.com/gitea/test_repo/archive/v2-rc1.tar.gz","zipball_url":"https://gitea.com/gitea/test_repo/archive/v2-rc1.zip","upload_url":"https://gitea.com/api/v1/repos/gitea/test_repo/releases/167250/assets","draft":false,"prerelease":true,"created_at":"2020-09-01T18:02:43Z","published_at":"2020-09-01T18:02:43Z","author":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"assets":[]},{"id":167249,"tag_name":"V1","target_commitish":"master","name":"First Release","body":"as title","url":"https://gitea.com/api/v1/repos/gitea/test_repo/releases/167249","html_url":"https://gitea.com/gitea/test_repo/releases/tag/V1","tarball_url":"https://gitea.com/gitea/test_repo/archive/V1.tar.gz","zipball_url":"https://gitea.com/gitea/test_repo/archive/V1.zip","upload_url":"https://gitea.com/api/v1/repos/gitea/test_repo/releases/167249/assets","draft":false,"prerelease":false,"created_at":"2020-09-01T17:30:32Z","published_at":"2020-09-01T17:30:32Z","author":{"id":689,"login":"6543","login_name":"","source_id":0,"full_name":"6543","email":"689+6543@noreply.gitea.com","avatar_url":"https://gitea.com/avatars/aeb6c290f1988daefa7421c5409e80dc","html_url":"https://gitea.com/6543","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2019-07-17T21:08:41Z","restricted":false,"active":false,"prohibit_login":false,"location":"Germany","website":"https://mh.obermui.de","description":"gitea instance: https://code.obermui.de","visibility":"public","followers_count":12,"following_count":7,"starred_repos_count":19,"username":"6543"},"assets":[]}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Ftopics%3Flimit%3D0%26page%3D1 b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Ftopics%3Flimit%3D0%26page%3D1 new file mode 100644 index 00000000..75117adf --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Fgitea%2Ftest_repo%2Ftopics%3Flimit%3D0%26page%3D1 @@ -0,0 +1,10 @@ +Access-Control-Expose-Headers: X-Total-Count +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 44 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff +X-Total-Count: 4 + +{"topics":["ci","gitea","migration","test"]} \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Fsettings%2Fapi b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Fsettings%2Fapi new file mode 100644 index 00000000..44c71a31 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Fsettings%2Fapi @@ -0,0 +1,8 @@ +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 154 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff + +{"max_response_items":50,"default_paging_num":10,"default_git_trees_per_page":1000,"default_max_blob_size":10485760,"default_max_response_size":104857600} \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Fversion b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Fversion new file mode 100644 index 00000000..4c24027b --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGiteaDownloadRepo/GET_%2Fapi%2Fv1%2Fversion @@ -0,0 +1,8 @@ +Alt-Svc: h3=":443"; ma=2592000 +Cache-Control: max-age=0, private, must-revalidate, no-transform +Content-Length: 40 +Content-Type: application/json;charset=utf-8 +Vary: Origin +X-Content-Type-Options: nosniff + +{"version":"1.26.0+dev-489-gc9a038bc4e"} \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026 b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026 new file mode 100644 index 00000000..72b97a2b --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026 @@ -0,0 +1,21 @@ +Cache-Control: max-age=0, private, must-revalidate +Cf-Cache-Status: MISS +Content-Security-Policy: default-src 'none' +Content-Type: application/json +Etag: W/"4b614e9f590cbbbc47e0f5a026615034" +Gitlab-Lb: haproxy-main-23-lb-gprd +Gitlab-Sv: api-gke-us-east1-c +Ratelimit-Limit: 2000 +Ratelimit-Name: throttle_authenticated_api +Ratelimit-Observed: 4 +Ratelimit-Remaining: 1996 +Ratelimit-Reset: 1776937500 +Referrer-Policy: strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"9f0bee77dc47c27f-VIE","version":"1"} +X-Runtime: 0.143727 + +{"id":15578026,"description":"Test repository for testing migration from gitlab to gitea","name":"test_repo","name_with_namespace":"gitea / test_repo","path":"test_repo","path_with_namespace":"gitea/test_repo","created_at":"2019-11-28T08:20:33.019Z","default_branch":"master","tag_list":["migration","test"],"topics":["migration","test"],"ssh_url_to_repo":"git@gitlab.com:gitea/test_repo.git","http_url_to_repo":"https://gitlab.com/gitea/test_repo.git","web_url":"https://gitlab.com/gitea/test_repo","readme_url":"https://gitlab.com/gitea/test_repo/-/blob/master/README.md","forks_count":1,"avatar_url":null,"star_count":0,"last_activity_at":"2025-11-25T09:21:43.130Z","visibility":"public","namespace":{"id":3181312,"name":"gitea","path":"gitea","kind":"group","full_path":"gitea","parent_id":null,"avatar_url":"/uploads/-/system/group/avatar/3181312/gitea.png","web_url":"https://gitlab.com/groups/gitea"},"container_registry_image_prefix":"registry.gitlab.com/gitea/test_repo","_links":{"self":"https://gitlab.com/api/v4/projects/15578026","issues":"https://gitlab.com/api/v4/projects/15578026/issues","merge_requests":"https://gitlab.com/api/v4/projects/15578026/merge_requests","repo_branches":"https://gitlab.com/api/v4/projects/15578026/repository/branches","labels":"https://gitlab.com/api/v4/projects/15578026/labels","events":"https://gitlab.com/api/v4/projects/15578026/events","members":"https://gitlab.com/api/v4/projects/15578026/members","cluster_agents":"https://gitlab.com/api/v4/projects/15578026/cluster_agents"},"marked_for_deletion_at":null,"marked_for_deletion_on":null,"packages_enabled":true,"empty_repo":false,"archived":false,"resolve_outdated_diff_discussions":false,"repository_object_format":"sha1","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"jobs_enabled":true,"snippets_enabled":true,"container_registry_enabled":true,"service_desk_enabled":true,"can_create_merge_request_in":true,"issues_access_level":"enabled","repository_access_level":"enabled","merge_requests_access_level":"enabled","forking_access_level":"enabled","wiki_access_level":"enabled","builds_access_level":"enabled","snippets_access_level":"enabled","pages_access_level":"enabled","analytics_access_level":"enabled","container_registry_access_level":"enabled","security_and_compliance_access_level":"private","releases_access_level":"enabled","environments_access_level":"enabled","feature_flags_access_level":"enabled","infrastructure_access_level":"enabled","monitor_access_level":"enabled","model_experiments_access_level":"enabled","model_registry_access_level":"enabled","package_registry_access_level":"public","emails_disabled":false,"emails_enabled":true,"show_diff_preview_in_email":true,"shared_runners_enabled":true,"lfs_enabled":true,"creator_id":1241334,"import_status":"none","open_issues_count":0,"description_html":"\u003cp data-sourcepos=\"1:1-1:58\" dir=\"auto\"\u003eTest repository for testing migration from gitlab to gitea\u003c/p\u003e","updated_at":"2025-11-25T09:21:43.130Z","ci_config_path":null,"public_jobs":true,"shared_with_groups":[],"only_allow_merge_if_pipeline_succeeds":false,"allow_merge_on_skipped_pipeline":null,"request_access_enabled":true,"only_allow_merge_if_all_discussions_are_resolved":false,"remove_source_branch_after_merge":true,"printing_merge_request_link_enabled":true,"merge_method":"ff","squash_option":"default_off","enforce_auth_checks_on_uploads":true,"suggestion_commit_message":null,"merge_commit_template":null,"squash_commit_template":null,"issue_branch_template":null,"warn_about_potentially_unwanted_characters":true,"autoclose_referenced_issues":true,"max_artifacts_size":null,"external_authorization_classification_label":"","requirements_enabled":false,"requirements_access_level":"enabled","security_and_compliance_enabled":false,"compliance_frameworks":[],"permissions":{"project_access":null,"group_access":null}} \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F1%2Faward_emoji%3Fpage%3D1%26per_page%3D2 b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F1%2Faward_emoji%3Fpage%3D1%26per_page%3D2 new file mode 100644 index 00000000..136de652 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F1%2Faward_emoji%3Fpage%3D1%26per_page%3D2 @@ -0,0 +1,28 @@ +Cache-Control: max-age=0, private, must-revalidate +Cf-Cache-Status: MISS +Content-Security-Policy: default-src 'none' +Content-Type: application/json +Etag: W/"5d658c62fd97f12d795c95ef106690e4" +Gitlab-Lb: haproxy-main-33-lb-gprd +Gitlab-Sv: api-gke-us-east1-d +Link: ; rel="first", ; rel="last" +Ratelimit-Limit: 2000 +Ratelimit-Name: throttle_authenticated_api +Ratelimit-Observed: 9 +Ratelimit-Remaining: 1991 +Ratelimit-Reset: 1776937500 +Referrer-Policy: strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"9f0bee819eddc27f-VIE","version":"1"} +X-Next-Page: +X-Page: 1 +X-Per-Page: 2 +X-Prev-Page: +X-Runtime: 0.068866 +X-Total: 2 +X-Total-Pages: 1 + +[{"id":3009580,"name":"thumbsup","user":{"id":1241334,"username":"lafriks","public_email":"","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:43:40.322Z","updated_at":"2019-11-28T08:43:40.322Z","awardable_id":27687675,"awardable_type":"Issue","url":null},{"id":3009585,"name":"open_mouth","user":{"id":1241334,"username":"lafriks","public_email":"","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:44:01.902Z","updated_at":"2019-11-28T08:44:01.902Z","awardable_id":27687675,"awardable_type":"Issue","url":null}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F1%2Faward_emoji%3Fpage%3D2%26per_page%3D2 b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F1%2Faward_emoji%3Fpage%3D2%26per_page%3D2 new file mode 100644 index 00000000..8350faf5 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F1%2Faward_emoji%3Fpage%3D2%26per_page%3D2 @@ -0,0 +1,30 @@ +Accept-Ranges: bytes +Cache-Control: max-age=0, private, must-revalidate +Cf-Cache-Status: MISS +Content-Length: 2 +Content-Security-Policy: default-src 'none' +Content-Type: application/json +Etag: W/"4f53cda18c2baa0c0354bb5f9a3ecbe5" +Gitlab-Lb: haproxy-main-30-lb-gprd +Gitlab-Sv: api-gke-us-east1-d +Link: ; rel="first", ; rel="last" +Ratelimit-Limit: 2000 +Ratelimit-Name: throttle_authenticated_api +Ratelimit-Observed: 10 +Ratelimit-Remaining: 1990 +Ratelimit-Reset: 1776937500 +Referrer-Policy: strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"9f0bee83389cc27f-VIE","version":"1"} +X-Next-Page: +X-Page: 2 +X-Per-Page: 2 +X-Prev-Page: +X-Runtime: 0.064390 +X-Total: 2 +X-Total-Pages: 1 + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Faward_emoji%3Fpage%3D1%26per_page%3D2 b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Faward_emoji%3Fpage%3D1%26per_page%3D2 new file mode 100644 index 00000000..264afd44 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Faward_emoji%3Fpage%3D1%26per_page%3D2 @@ -0,0 +1,28 @@ +Cache-Control: max-age=0, private, must-revalidate +Cf-Cache-Status: MISS +Content-Security-Policy: default-src 'none' +Content-Type: application/json +Etag: W/"c14d66cdce11232dc1358893d1c5fb88" +Gitlab-Lb: haproxy-main-29-lb-gprd +Gitlab-Sv: api-gke-us-east1-c +Link: ; rel="next", ; rel="first", ; rel="last" +Ratelimit-Limit: 2000 +Ratelimit-Name: throttle_authenticated_api +Ratelimit-Observed: 11 +Ratelimit-Remaining: 1989 +Ratelimit-Reset: 1776937500 +Referrer-Policy: strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"9f0bee850a9ac27f-VIE","version":"1"} +X-Next-Page: 2 +X-Page: 1 +X-Per-Page: 2 +X-Prev-Page: +X-Runtime: 0.079850 +X-Total: 6 +X-Total-Pages: 3 + +[{"id":3009627,"name":"thumbsup","user":{"id":1241334,"username":"lafriks","public_email":"","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:46:42.657Z","updated_at":"2019-11-28T08:46:42.657Z","awardable_id":27687706,"awardable_type":"Issue","url":null},{"id":3009628,"name":"thumbsdown","user":{"id":1241334,"username":"lafriks","public_email":"","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:46:43.471Z","updated_at":"2019-11-28T08:46:43.471Z","awardable_id":27687706,"awardable_type":"Issue","url":null}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Faward_emoji%3Fpage%3D2%26per_page%3D2 b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Faward_emoji%3Fpage%3D2%26per_page%3D2 new file mode 100644 index 00000000..d15f53ca --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Faward_emoji%3Fpage%3D2%26per_page%3D2 @@ -0,0 +1,28 @@ +Cache-Control: max-age=0, private, must-revalidate +Cf-Cache-Status: MISS +Content-Security-Policy: default-src 'none' +Content-Type: application/json +Etag: W/"3330f45ad310a47e7d50a94586f0384b" +Gitlab-Lb: haproxy-main-53-lb-gprd +Gitlab-Sv: api-gke-us-east1-c +Link: ; rel="prev", ; rel="next", ; rel="first", ; rel="last" +Ratelimit-Limit: 2000 +Ratelimit-Name: throttle_authenticated_api +Ratelimit-Observed: 12 +Ratelimit-Remaining: 1988 +Ratelimit-Reset: 1776937500 +Referrer-Policy: strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"9f0bee86fcb5c27f-VIE","version":"1"} +X-Next-Page: 3 +X-Page: 2 +X-Per-Page: 2 +X-Prev-Page: 1 +X-Runtime: 0.073056 +X-Total: 6 +X-Total-Pages: 3 + +[{"id":3009632,"name":"laughing","user":{"id":1241334,"username":"lafriks","public_email":"","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:47:14.381Z","updated_at":"2019-11-28T08:47:14.381Z","awardable_id":27687706,"awardable_type":"Issue","url":null},{"id":3009634,"name":"tada","user":{"id":1241334,"username":"lafriks","public_email":"","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:47:18.254Z","updated_at":"2019-11-28T08:47:18.254Z","awardable_id":27687706,"awardable_type":"Issue","url":null}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Faward_emoji%3Fpage%3D3%26per_page%3D2 b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Faward_emoji%3Fpage%3D3%26per_page%3D2 new file mode 100644 index 00000000..2932e00a --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Faward_emoji%3Fpage%3D3%26per_page%3D2 @@ -0,0 +1,28 @@ +Cache-Control: max-age=0, private, must-revalidate +Cf-Cache-Status: MISS +Content-Security-Policy: default-src 'none' +Content-Type: application/json +Etag: W/"1b206b5cf267607532b738fd49085d11" +Gitlab-Lb: haproxy-main-20-lb-gprd +Gitlab-Sv: api-gke-us-east1-c +Link: ; rel="prev", ; rel="first", ; rel="last" +Ratelimit-Limit: 2000 +Ratelimit-Name: throttle_authenticated_api +Ratelimit-Observed: 13 +Ratelimit-Remaining: 1987 +Ratelimit-Reset: 1776937500 +Referrer-Policy: strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"9f0bee88de9fc27f-VIE","version":"1"} +X-Next-Page: +X-Page: 3 +X-Per-Page: 2 +X-Prev-Page: 2 +X-Runtime: 0.079463 +X-Total: 6 +X-Total-Pages: 3 + +[{"id":3009636,"name":"confused","user":{"id":1241334,"username":"lafriks","public_email":"","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:47:27.248Z","updated_at":"2019-11-28T08:47:27.248Z","awardable_id":27687706,"awardable_type":"Issue","url":null},{"id":3009640,"name":"hearts","user":{"id":1241334,"username":"lafriks","public_email":"","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:47:33.059Z","updated_at":"2019-11-28T08:47:33.059Z","awardable_id":27687706,"awardable_type":"Issue","url":null}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Faward_emoji%3Fpage%3D4%26per_page%3D2 b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Faward_emoji%3Fpage%3D4%26per_page%3D2 new file mode 100644 index 00000000..46669b63 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Faward_emoji%3Fpage%3D4%26per_page%3D2 @@ -0,0 +1,30 @@ +Accept-Ranges: bytes +Cache-Control: max-age=0, private, must-revalidate +Cf-Cache-Status: MISS +Content-Length: 2 +Content-Security-Policy: default-src 'none' +Content-Type: application/json +Etag: W/"4f53cda18c2baa0c0354bb5f9a3ecbe5" +Gitlab-Lb: haproxy-main-60-lb-gprd +Gitlab-Sv: api-gke-us-east1-d +Link: ; rel="first", ; rel="last" +Ratelimit-Limit: 2000 +Ratelimit-Name: throttle_authenticated_api +Ratelimit-Observed: 14 +Ratelimit-Remaining: 1986 +Ratelimit-Reset: 1776937500 +Referrer-Policy: strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"9f0bee8aa8bac27f-VIE","version":"1"} +X-Next-Page: +X-Page: 4 +X-Per-Page: 2 +X-Prev-Page: +X-Runtime: 0.073394 +X-Total: 6 +X-Total-Pages: 3 + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Fdiscussions%3Fpage%3D1%26per_page%3D100 b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Fdiscussions%3Fpage%3D1%26per_page%3D100 new file mode 100644 index 00000000..dc3ff6f3 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Fdiscussions%3Fpage%3D1%26per_page%3D100 @@ -0,0 +1,28 @@ +Cache-Control: max-age=0, private, must-revalidate +Cf-Cache-Status: MISS +Content-Security-Policy: default-src 'none' +Content-Type: application/json +Etag: W/"3a60a8124f040aa4a8458c91b49f4b0f" +Gitlab-Lb: haproxy-main-29-lb-gprd +Gitlab-Sv: api-gke-us-east1-c +Link: ; rel="first", ; rel="last" +Ratelimit-Limit: 2000 +Ratelimit-Name: throttle_authenticated_api +Ratelimit-Observed: 15 +Ratelimit-Remaining: 1985 +Ratelimit-Reset: 1776937500 +Referrer-Policy: strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"9f0bee8c4a95c27f-VIE","version":"1"} +X-Next-Page: +X-Page: 1 +X-Per-Page: 100 +X-Prev-Page: +X-Runtime: 0.170698 +X-Total: 4 +X-Total-Pages: 1 + +[{"id":"617967369d98d8b73b6105a40318fe839f931a24","individual_note":true,"resolvable":false,"notes":[{"id":251637434,"type":null,"body":"This is a comment","author":{"id":1241334,"username":"lafriks","public_email":"","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:44:52.501Z","updated_at":"2019-11-28T08:44:52.501Z","system":false,"noteable_id":27687706,"noteable_type":"Issue","project_id":15578026,"resolvable":false,"confidential":false,"internal":false,"imported":false,"imported_from":"none","noteable_iid":2,"commands_changes":{}}]},{"id":"b92d74daee411a17d844041bcd3c267ade58f680","individual_note":true,"resolvable":false,"notes":[{"id":251637528,"type":null,"body":"changed milestone to %2","author":{"id":1241334,"username":"lafriks","public_email":"","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:45:02.329Z","updated_at":"2019-11-28T08:45:02.335Z","system":true,"noteable_id":27687706,"noteable_type":"Issue","project_id":15578026,"resolvable":false,"confidential":false,"internal":false,"imported":false,"imported_from":"none","noteable_iid":2,"commands_changes":{}}]},{"id":"6010f567d2b58758ef618070372c97891ac75349","individual_note":true,"resolvable":false,"notes":[{"id":251637892,"type":null,"body":"closed","author":{"id":1241334,"username":"lafriks","public_email":"","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:45:45.007Z","updated_at":"2019-11-28T08:45:45.010Z","system":true,"noteable_id":27687706,"noteable_type":"Issue","project_id":15578026,"resolvable":false,"confidential":false,"internal":false,"imported":false,"imported_from":"none","noteable_iid":2,"commands_changes":{}}]},{"id":"632d0cbfd6a1a08f38aaf9ef7715116f4b188ebb","individual_note":true,"resolvable":false,"notes":[{"id":251637999,"type":null,"body":"A second comment","author":{"id":1241334,"username":"lafriks","public_email":"","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:45:53.501Z","updated_at":"2019-11-28T08:45:53.501Z","system":false,"noteable_id":27687706,"noteable_type":"Issue","project_id":15578026,"resolvable":false,"confidential":false,"internal":false,"imported":false,"imported_from":"none","noteable_iid":2,"commands_changes":{}}]}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Fresource_state_events%3Fpage%3D1%26per_page%3D100 b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Fresource_state_events%3Fpage%3D1%26per_page%3D100 new file mode 100644 index 00000000..6ddcf3fa --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%2F2%2Fresource_state_events%3Fpage%3D1%26per_page%3D100 @@ -0,0 +1,30 @@ +Accept-Ranges: bytes +Cache-Control: max-age=0, private, must-revalidate +Cf-Cache-Status: MISS +Content-Length: 2 +Content-Security-Policy: default-src 'none' +Content-Type: application/json +Etag: W/"4f53cda18c2baa0c0354bb5f9a3ecbe5" +Gitlab-Lb: haproxy-main-60-lb-gprd +Gitlab-Sv: api-gke-us-east1-d +Link: ; rel="first", ; rel="last" +Ratelimit-Limit: 2000 +Ratelimit-Name: throttle_authenticated_api +Ratelimit-Observed: 16 +Ratelimit-Remaining: 1984 +Ratelimit-Reset: 1776937500 +Referrer-Policy: strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"9f0bee8ead54c27f-VIE","version":"1"} +X-Next-Page: +X-Page: 1 +X-Per-Page: 100 +X-Prev-Page: +X-Runtime: 0.095668 +X-Total: 0 +X-Total-Pages: 1 + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%3Fpage%3D1%26per_page%3D2%26sort%3Dasc%26state%3Dall b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%3Fpage%3D1%26per_page%3D2%26sort%3Dasc%26state%3Dall new file mode 100644 index 00000000..7df08ca4 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fissues%3Fpage%3D1%26per_page%3D2%26sort%3Dasc%26state%3Dall @@ -0,0 +1,28 @@ +Cache-Control: max-age=0, private, must-revalidate +Cf-Cache-Status: MISS +Content-Security-Policy: default-src 'none' +Content-Type: application/json +Etag: W/"b12dae3f9a06df734eaeea56b1becb28" +Gitlab-Lb: haproxy-main-09-lb-gprd +Gitlab-Sv: api-gke-us-east1-d +Link: ; rel="next", ; rel="first", ; rel="last" +Ratelimit-Limit: 2000 +Ratelimit-Name: throttle_authenticated_api +Ratelimit-Observed: 8 +Ratelimit-Remaining: 1992 +Ratelimit-Reset: 1776937500 +Referrer-Policy: strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"9f0bee7f8c9ac27f-VIE","version":"1"} +X-Next-Page: 2 +X-Page: 1 +X-Per-Page: 2 +X-Prev-Page: +X-Runtime: 0.141229 +X-Total: 3 +X-Total-Pages: 2 + +[{"id":27687675,"iid":1,"project_id":15578026,"title":"Please add an animated gif icon to the merge button","description":"I just want the merge button to hurt my eyes a little. :stuck_out_tongue_closed_eyes:","state":"closed","created_at":"2019-11-28T08:43:35.459Z","updated_at":"2019-11-28T08:46:23.304Z","closed_at":"2019-11-28T08:46:23.275Z","closed_by":{"id":1241334,"username":"lafriks","public_email":"","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"labels":["bug","discussion"],"milestone":{"id":1082926,"iid":1,"project_id":15578026,"title":"1.0.0","description":"","state":"closed","created_at":"2019-11-28T08:42:30.301Z","updated_at":"2019-11-28T15:57:52.401Z","due_date":null,"start_date":null,"expired":false,"web_url":"https://gitlab.com/gitea/test_repo/-/milestones/1"},"assignees":[],"author":{"id":1241334,"username":"lafriks","public_email":"","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"type":"ISSUE","assignee":null,"user_notes_count":0,"merge_requests_count":0,"upvotes":1,"downvotes":0,"start_date":null,"due_date":null,"confidential":false,"discussion_locked":null,"issue_type":"issue","web_url":"https://gitlab.com/gitea/test_repo/-/work_items/1","time_stats":{"time_estimate":0,"total_time_spent":0,"human_time_estimate":null,"human_total_time_spent":null},"task_completion_status":{"count":0,"completed_count":0},"blocking_issues_count":0,"has_tasks":true,"task_status":"0 of 0 checklist items completed","_links":{"self":"https://gitlab.com/api/v4/projects/15578026/issues/1","notes":"https://gitlab.com/api/v4/projects/15578026/issues/1/notes","award_emoji":"https://gitlab.com/api/v4/projects/15578026/issues/1/award_emoji","project":"https://gitlab.com/api/v4/projects/15578026","closed_as_duplicate_of":null},"references":{"short":"#1","relative":"#1","full":"gitea/test_repo#1"},"severity":"UNKNOWN","moved_to_id":null,"imported":false,"imported_from":"none","service_desk_reply_to":null},{"id":27687706,"iid":2,"project_id":15578026,"title":"Test issue","description":"This is test issue 2, do not touch!","state":"closed","created_at":"2019-11-28T08:44:46.277Z","updated_at":"2019-11-28T08:45:44.987Z","closed_at":"2019-11-28T08:45:44.959Z","closed_by":{"id":1241334,"username":"lafriks","public_email":"","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"labels":["duplicate"],"milestone":{"id":1082927,"iid":2,"project_id":15578026,"title":"1.1.0","description":"","state":"active","created_at":"2019-11-28T08:42:44.575Z","updated_at":"2019-11-28T08:42:44.575Z","due_date":null,"start_date":null,"expired":false,"web_url":"https://gitlab.com/gitea/test_repo/-/milestones/2"},"assignees":[],"author":{"id":1241334,"username":"lafriks","public_email":"","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"type":"ISSUE","assignee":null,"user_notes_count":2,"merge_requests_count":0,"upvotes":1,"downvotes":1,"start_date":null,"due_date":null,"confidential":false,"discussion_locked":null,"issue_type":"issue","web_url":"https://gitlab.com/gitea/test_repo/-/work_items/2","time_stats":{"time_estimate":0,"total_time_spent":0,"human_time_estimate":null,"human_total_time_spent":null},"task_completion_status":{"count":0,"completed_count":0},"blocking_issues_count":0,"has_tasks":true,"task_status":"0 of 0 checklist items completed","_links":{"self":"https://gitlab.com/api/v4/projects/15578026/issues/2","notes":"https://gitlab.com/api/v4/projects/15578026/issues/2/notes","award_emoji":"https://gitlab.com/api/v4/projects/15578026/issues/2/award_emoji","project":"https://gitlab.com/api/v4/projects/15578026","closed_as_duplicate_of":null},"references":{"short":"#2","relative":"#2","full":"gitea/test_repo#2"},"severity":"UNKNOWN","moved_to_id":null,"imported":false,"imported_from":"none","service_desk_reply_to":null}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Flabels%3Fpage%3D1%26per_page%3D100 b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Flabels%3Fpage%3D1%26per_page%3D100 new file mode 100644 index 00000000..f5f8643b --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Flabels%3Fpage%3D1%26per_page%3D100 @@ -0,0 +1,28 @@ +Cache-Control: max-age=0, private, must-revalidate +Cf-Cache-Status: MISS +Content-Security-Policy: default-src 'none' +Content-Type: application/json +Etag: W/"d7c1b7d1a56d73d88c746a4e1241b673" +Gitlab-Lb: haproxy-main-32-lb-gprd +Gitlab-Sv: api-gke-us-east1-c +Link: ; rel="first", ; rel="last" +Ratelimit-Limit: 2000 +Ratelimit-Name: throttle_authenticated_api +Ratelimit-Observed: 6 +Ratelimit-Remaining: 1994 +Ratelimit-Reset: 1776937500 +Referrer-Policy: strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"9f0bee7bc888c27f-VIE","version":"1"} +X-Next-Page: +X-Page: 1 +X-Per-Page: 100 +X-Prev-Page: +X-Runtime: 0.104606 +X-Total: 9 +X-Total-Pages: 1 + +[{"id":12959095,"name":"bug","description":null,"text_color":"#FFFFFF","description_html":"","color":"#d9534f","archived":false,"subscribed":false,"priority":null,"is_project_label":true},{"id":12959097,"name":"confirmed","description":null,"text_color":"#FFFFFF","description_html":"","color":"#d9534f","archived":false,"subscribed":false,"priority":null,"is_project_label":true},{"id":12959096,"name":"critical","description":null,"text_color":"#FFFFFF","description_html":"","color":"#d9534f","archived":false,"subscribed":false,"priority":null,"is_project_label":true},{"id":12959100,"name":"discussion","description":null,"text_color":"#FFFFFF","description_html":"","color":"#428bca","archived":false,"subscribed":false,"priority":null,"is_project_label":true},{"id":12959098,"name":"documentation","description":null,"text_color":"#1F1E24","description_html":"","color":"#f0ad4e","archived":false,"subscribed":false,"priority":null,"is_project_label":true},{"id":12959554,"name":"duplicate","description":null,"text_color":"#FFFFFF","description_html":"","color":"#7F8C8D","archived":false,"subscribed":false,"priority":null,"is_project_label":true},{"id":12959102,"name":"enhancement","description":null,"text_color":"#FFFFFF","description_html":"","color":"#5cb85c","archived":false,"subscribed":false,"priority":null,"is_project_label":true},{"id":12959101,"name":"suggestion","description":null,"text_color":"#FFFFFF","description_html":"","color":"#428bca","archived":false,"subscribed":false,"priority":null,"is_project_label":true},{"id":12959099,"name":"support","description":null,"text_color":"#1F1E24","description_html":"","color":"#f0ad4e","archived":false,"subscribed":false,"priority":null,"is_project_label":true}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F1%2Fapprovals b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F1%2Fapprovals new file mode 100644 index 00000000..4b0c4f6b --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F1%2Fapprovals @@ -0,0 +1,21 @@ +Cache-Control: max-age=0, private, must-revalidate +Cf-Cache-Status: MISS +Content-Security-Policy: default-src 'none' +Content-Type: application/json +Etag: W/"03275c2a6cc732959835fa9ad779f0ae" +Gitlab-Lb: haproxy-main-14-lb-gprd +Gitlab-Sv: api-gke-us-east1-c +Ratelimit-Limit: 2000 +Ratelimit-Name: throttle_authenticated_api +Ratelimit-Observed: 22 +Ratelimit-Remaining: 1978 +Ratelimit-Reset: 1776937500 +Referrer-Policy: strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"9f0bee9a6be9c27f-VIE","version":"1"} +X-Runtime: 0.110926 + +{"id":43486906,"iid":1,"project_id":15578026,"title":"Update README.md","description":"add warning to readme","state":"merged","created_at":"2019-11-28T08:54:41.034Z","updated_at":"2019-11-28T16:02:08.377Z","merge_status":"can_be_merged","approved":true,"approvals_required":0,"approvals_left":0,"require_password_to_approve":false,"approved_by":[{"user":{"id":527793,"username":"axifive","public_email":"","name":"Alexey Terentyev","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/b5eee878c9129969b55d221a823fd15e55aad8dc15d521f4170e3c93728e02b6?s=80\u0026d=identicon","web_url":"https://gitlab.com/axifive"},"approved_at":"2019-11-28T12:58:33.257Z"},{"user":{"id":4102996,"username":"zeripath","public_email":"","name":"zeripath","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/3bad2cdad37aa0bbb3ad276ce8f77e32a1a9567a7083f0866d8df8ed0e92e5b5?s=80\u0026d=identicon","web_url":"https://gitlab.com/zeripath"},"approved_at":"2019-11-28T13:10:47.321Z"}],"suggested_approvers":[],"approvers":[],"approver_groups":[],"user_has_approved":false,"user_can_approve":false,"approval_rules_left":[],"has_approval_rules":true,"merge_request_approvers_available":false,"multiple_approval_rules_available":false,"invalid_approvers_rules":[]} \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F2%2Fapprovals b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F2%2Fapprovals new file mode 100644 index 00000000..64778374 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F2%2Fapprovals @@ -0,0 +1,21 @@ +Cache-Control: max-age=0, private, must-revalidate +Cf-Cache-Status: MISS +Content-Security-Policy: default-src 'none' +Content-Type: application/json +Etag: W/"7b17d8be4001a23ef2e3265138046ebd" +Gitlab-Lb: haproxy-main-36-lb-gprd +Gitlab-Sv: api-gke-us-east1-d +Ratelimit-Limit: 2000 +Ratelimit-Name: throttle_authenticated_api +Ratelimit-Observed: 23 +Ratelimit-Remaining: 1977 +Ratelimit-Reset: 1776937500 +Referrer-Policy: strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"9f0bee9c6e8ac27f-VIE","version":"1"} +X-Runtime: 0.178166 + +{"id":43524600,"iid":2,"project_id":15578026,"title":"Test branch","description":"do not merge this PR","state":"opened","created_at":"2019-11-28T15:56:54.104Z","updated_at":"2020-04-19T19:24:21.108Z","merge_status":"can_be_merged","approved":true,"approvals_required":0,"approvals_left":0,"require_password_to_approve":false,"approved_by":[{"user":{"id":4575606,"username":"real6543","public_email":"","name":"6543","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/4575606/avatar.png","web_url":"https://gitlab.com/real6543"},"approved_at":"2020-04-19T19:24:21.089Z"}],"suggested_approvers":[],"approvers":[],"approver_groups":[{"group":{"id":3181312,"web_url":"https://gitlab.com/groups/gitea","name":"gitea","path":"gitea","description":"Mirror of Gitea source code repositories","visibility":"public","share_with_group_lock":false,"require_two_factor_authentication":false,"two_factor_grace_period":48,"project_creation_level":"maintainer","auto_devops_enabled":null,"subgroup_creation_level":"owner","emails_disabled":false,"emails_enabled":true,"show_diff_preview_in_email":true,"mentions_disabled":null,"lfs_enabled":true,"archived":false,"math_rendering_limits_enabled":true,"lock_math_rendering_limits_enabled":false,"default_branch":null,"default_branch_protection":2,"default_branch_protection_defaults":{"allowed_to_push":[{"access_level":40}],"allow_force_push":false,"allowed_to_merge":[{"access_level":40}]},"avatar_url":"https://gitlab.com/uploads/-/system/group/avatar/3181312/gitea.png","request_access_enabled":true,"full_name":"gitea","full_path":"gitea","created_at":"2018-07-04T16:32:10.176Z","parent_id":null,"organization_id":1,"shared_runners_setting":"enabled","max_artifacts_size":null,"marked_for_deletion_on":null,"ldap_cn":null,"ldap_access":null,"wiki_access_level":"enabled"}}],"user_has_approved":false,"user_can_approve":false,"approval_rules_left":[],"has_approval_rules":true,"merge_request_approvers_available":false,"multiple_approval_rules_available":false,"invalid_approvers_rules":[]} \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F3 b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F3 new file mode 100644 index 00000000..6ccdcb02 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F3 @@ -0,0 +1,21 @@ +Cache-Control: max-age=0, private, must-revalidate +Cf-Cache-Status: MISS +Content-Security-Policy: default-src 'none' +Content-Type: application/json +Etag: W/"e083f0fed8ec0f3bd66c07010daf4918" +Gitlab-Lb: haproxy-main-45-lb-gprd +Gitlab-Sv: api-gke-us-east1-d +Ratelimit-Limit: 2000 +Ratelimit-Name: throttle_authenticated_api +Ratelimit-Observed: 20 +Ratelimit-Remaining: 1980 +Ratelimit-Reset: 1776937500 +Referrer-Policy: strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"9f0bee964ec6c27f-VIE","version":"1"} +X-Runtime: 0.140863 + +{"id":324656914,"iid":3,"project_id":15578026,"title":"Test branch","description":"do not merge this PR","state":"closed","created_at":"2024-09-03T07:52:08.078Z","updated_at":"2024-09-03T08:09:34.155Z","merged_by":null,"merge_user":null,"merged_at":null,"closed_by":{"id":2005797,"username":"oliverpool","public_email":"","name":"oliverpool","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/2005797/avatar.png","web_url":"https://gitlab.com/oliverpool"},"closed_at":"2024-09-03T07:52:28.488Z","target_branch":"master","source_branch":"feat/test","user_notes_count":1,"upvotes":1,"downvotes":0,"author":{"id":2005797,"username":"oliverpool","public_email":"","name":"oliverpool","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/2005797/avatar.png","web_url":"https://gitlab.com/oliverpool"},"assignees":[],"assignee":null,"reviewers":[],"source_project_id":61363672,"target_project_id":15578026,"labels":[],"draft":false,"imported":false,"imported_from":"none","work_in_progress":false,"milestone":null,"merge_when_pipeline_succeeds":false,"merge_status":"can_be_merged","detailed_merge_status":"not_open","merge_after":null,"sha":"9f733b96b98a4175276edf6a2e1231489c3bdd23","merge_commit_sha":null,"squash_commit_sha":null,"discussion_locked":null,"should_remove_source_branch":null,"force_remove_source_branch":true,"prepared_at":"2024-09-03T08:09:34.153Z","allow_collaboration":true,"allow_maintainer_to_push":true,"reference":"!3","references":{"short":"!3","relative":"!3","full":"gitea/test_repo!3"},"web_url":"https://gitlab.com/gitea/test_repo/-/merge_requests/3","time_stats":{"time_estimate":0,"total_time_spent":0,"human_time_estimate":null,"human_total_time_spent":null},"squash":false,"squash_on_merge":false,"task_completion_status":{"count":0,"completed_count":0},"has_conflicts":false,"blocking_discussions_resolved":true,"approvals_before_merge":null,"subscribed":false,"changes_count":"1","latest_build_started_at":null,"latest_build_finished_at":null,"first_deployed_to_production_at":null,"pipeline":null,"head_pipeline":null,"diff_refs":{"base_sha":"c59c9b451acca9d106cc19d61d87afe3fbbb8b83","head_sha":"9f733b96b98a4175276edf6a2e1231489c3bdd23","start_sha":"c59c9b451acca9d106cc19d61d87afe3fbbb8b83"},"merge_error":null,"first_contribution":true,"user":{"can_merge":false}} \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F3%2Faward_emoji%3Fpage%3D1%26per_page%3D2 b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F3%2Faward_emoji%3Fpage%3D1%26per_page%3D2 new file mode 100644 index 00000000..4a748d30 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F3%2Faward_emoji%3Fpage%3D1%26per_page%3D2 @@ -0,0 +1,28 @@ +Cache-Control: max-age=0, private, must-revalidate +Cf-Cache-Status: MISS +Content-Security-Policy: default-src 'none' +Content-Type: application/json +Etag: W/"ef98d22b26e55b4da238d1ae4fc66140" +Gitlab-Lb: haproxy-main-58-lb-gprd +Gitlab-Sv: api-gke-us-east1-b +Link: ; rel="first", ; rel="last" +Ratelimit-Limit: 2000 +Ratelimit-Name: throttle_authenticated_api +Ratelimit-Observed: 21 +Ratelimit-Remaining: 1979 +Ratelimit-Reset: 1776937500 +Referrer-Policy: strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"9f0bee98da1fc27f-VIE","version":"1"} +X-Next-Page: +X-Page: 1 +X-Per-Page: 2 +X-Prev-Page: +X-Runtime: 0.057694 +X-Total: 1 +X-Total-Pages: 1 + +[{"id":28081326,"name":"thumbsup","user":{"id":2005797,"username":"oliverpool","public_email":"","name":"oliverpool","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/2005797/avatar.png","web_url":"https://gitlab.com/oliverpool"},"created_at":"2024-09-03T07:52:13.111Z","updated_at":"2024-09-03T07:52:13.111Z","awardable_id":324656914,"awardable_type":"MergeRequest","url":null}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F4 b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F4 new file mode 100644 index 00000000..f05e6ab4 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F4 @@ -0,0 +1,21 @@ +Cache-Control: max-age=0, private, must-revalidate +Cf-Cache-Status: MISS +Content-Security-Policy: default-src 'none' +Content-Type: application/json +Etag: W/"b0504885540d26b31a16be8421368581" +Gitlab-Lb: haproxy-main-15-lb-gprd +Gitlab-Sv: api-gke-us-east1-d +Ratelimit-Limit: 2000 +Ratelimit-Name: throttle_authenticated_api +Ratelimit-Observed: 18 +Ratelimit-Remaining: 1982 +Ratelimit-Reset: 1776937500 +Referrer-Policy: strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"9f0bee927a8ac27f-VIE","version":"1"} +X-Runtime: 0.146911 + +{"id":435554087,"iid":4,"project_id":15578026,"title":"Test/parsing","description":"This MR was created in error, feel free to delete when convenient. Sorry for the noise.","state":"closed","created_at":"2025-11-25T09:21:42.628Z","updated_at":"2025-11-25T13:46:43.471Z","merged_by":null,"merge_user":null,"merged_at":null,"closed_by":{"id":10529876,"username":"patdyn","public_email":"","name":"Pat Dyn","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/10529876/avatar.png","web_url":"https://gitlab.com/patdyn"},"closed_at":"2025-11-25T09:43:14.581Z","target_branch":"master","source_branch":"test/parsing","user_notes_count":0,"upvotes":0,"downvotes":0,"author":{"id":10529876,"username":"patdyn","public_email":"","name":"Pat Dyn","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/10529876/avatar.png","web_url":"https://gitlab.com/patdyn"},"assignees":[],"assignee":null,"reviewers":[],"source_project_id":61363672,"target_project_id":15578026,"labels":[],"draft":false,"imported":false,"imported_from":"none","work_in_progress":false,"milestone":null,"merge_when_pipeline_succeeds":false,"merge_status":"cannot_be_merged","detailed_merge_status":"not_open","merge_after":null,"sha":"c59c9b451acca9d106cc19d61d87afe3fbbb8b83","merge_commit_sha":null,"squash_commit_sha":null,"discussion_locked":null,"should_remove_source_branch":null,"force_remove_source_branch":true,"prepared_at":"2025-11-25T09:21:43.464Z","allow_collaboration":true,"allow_maintainer_to_push":true,"reference":"!4","references":{"short":"!4","relative":"!4","full":"gitea/test_repo!4"},"web_url":"https://gitlab.com/gitea/test_repo/-/merge_requests/4","time_stats":{"time_estimate":0,"total_time_spent":0,"human_time_estimate":null,"human_total_time_spent":null},"squash":false,"squash_on_merge":false,"task_completion_status":{"count":0,"completed_count":0},"has_conflicts":true,"blocking_discussions_resolved":true,"approvals_before_merge":null,"subscribed":false,"changes_count":null,"latest_build_started_at":null,"latest_build_finished_at":null,"first_deployed_to_production_at":null,"pipeline":null,"head_pipeline":null,"diff_refs":{"base_sha":"c59c9b451acca9d106cc19d61d87afe3fbbb8b83","head_sha":"c59c9b451acca9d106cc19d61d87afe3fbbb8b83","start_sha":"c59c9b451acca9d106cc19d61d87afe3fbbb8b83"},"merge_error":null,"first_contribution":true,"user":{"can_merge":false}} \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F4%2Faward_emoji%3Fpage%3D1%26per_page%3D2 b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F4%2Faward_emoji%3Fpage%3D1%26per_page%3D2 new file mode 100644 index 00000000..fd860f4e --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%2F4%2Faward_emoji%3Fpage%3D1%26per_page%3D2 @@ -0,0 +1,30 @@ +Accept-Ranges: bytes +Cache-Control: max-age=0, private, must-revalidate +Cf-Cache-Status: MISS +Content-Length: 2 +Content-Security-Policy: default-src 'none' +Content-Type: application/json +Etag: W/"4f53cda18c2baa0c0354bb5f9a3ecbe5" +Gitlab-Lb: haproxy-main-12-lb-gprd +Gitlab-Sv: gke-cny-api +Link: ; rel="first", ; rel="last" +Ratelimit-Limit: 2000 +Ratelimit-Name: throttle_authenticated_api +Ratelimit-Observed: 19 +Ratelimit-Remaining: 1981 +Ratelimit-Reset: 1776937500 +Referrer-Policy: strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"9f0bee949d06c27f-VIE","version":"1"} +X-Next-Page: +X-Page: 1 +X-Per-Page: 2 +X-Prev-Page: +X-Runtime: 0.070976 +X-Total: 0 +X-Total-Pages: 1 + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%3Fpage%3D1%26per_page%3D2%26view%3Dsimple b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%3Fpage%3D1%26per_page%3D2%26view%3Dsimple new file mode 100644 index 00000000..993d0b66 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmerge_requests%3Fpage%3D1%26per_page%3D2%26view%3Dsimple @@ -0,0 +1,28 @@ +Cache-Control: max-age=0, private, must-revalidate +Cf-Cache-Status: MISS +Content-Security-Policy: default-src 'none' +Content-Type: application/json +Etag: W/"523433e2f02ff01da9306c97204424c2" +Gitlab-Lb: haproxy-main-21-lb-gprd +Gitlab-Sv: api-gke-us-east1-d +Link: ; rel="next", ; rel="first", ; rel="last" +Ratelimit-Limit: 2000 +Ratelimit-Name: throttle_authenticated_api +Ratelimit-Observed: 17 +Ratelimit-Remaining: 1983 +Ratelimit-Reset: 1776937500 +Referrer-Policy: strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"9f0bee906802c27f-VIE","version":"1"} +X-Next-Page: 2 +X-Page: 1 +X-Per-Page: 2 +X-Prev-Page: +X-Runtime: 0.079335 +X-Total: 4 +X-Total-Pages: 2 + +[{"id":435554087,"iid":4,"project_id":15578026,"title":"Test/parsing","description":"This MR was created in error, feel free to delete when convenient. Sorry for the noise.","state":"closed","created_at":"2025-11-25T09:21:42.628Z","updated_at":"2025-11-25T13:46:43.471Z","web_url":"https://gitlab.com/gitea/test_repo/-/merge_requests/4"},{"id":324656914,"iid":3,"project_id":15578026,"title":"Test branch","description":"do not merge this PR","state":"closed","created_at":"2024-09-03T07:52:08.078Z","updated_at":"2024-09-03T08:09:34.155Z","web_url":"https://gitlab.com/gitea/test_repo/-/merge_requests/3"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmilestones%3Fpage%3D1%26per_page%3D100%26state%3Dall b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmilestones%3Fpage%3D1%26per_page%3D100%26state%3Dall new file mode 100644 index 00000000..0a5caf5e --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Fmilestones%3Fpage%3D1%26per_page%3D100%26state%3Dall @@ -0,0 +1,28 @@ +Cache-Control: max-age=0, private, must-revalidate +Cf-Cache-Status: MISS +Content-Security-Policy: default-src 'none' +Content-Type: application/json +Etag: W/"c8e2d3a5f05ee29c58b665c86684f9f9" +Gitlab-Lb: haproxy-main-47-lb-gprd +Gitlab-Sv: api-gke-us-east1-c +Link: ; rel="first", ; rel="last" +Ratelimit-Limit: 2000 +Ratelimit-Name: throttle_authenticated_api +Ratelimit-Observed: 5 +Ratelimit-Remaining: 1995 +Ratelimit-Reset: 1776937500 +Referrer-Policy: strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"9f0bee7a2e97c27f-VIE","version":"1"} +X-Next-Page: +X-Page: 1 +X-Per-Page: 100 +X-Prev-Page: +X-Runtime: 0.070685 +X-Total: 2 +X-Total-Pages: 1 + +[{"id":1082927,"iid":2,"project_id":15578026,"title":"1.1.0","description":"","state":"active","created_at":"2019-11-28T08:42:44.575Z","updated_at":"2019-11-28T08:42:44.575Z","due_date":null,"start_date":null,"expired":false,"web_url":"https://gitlab.com/gitea/test_repo/-/milestones/2"},{"id":1082926,"iid":1,"project_id":15578026,"title":"1.0.0","description":"","state":"closed","created_at":"2019-11-28T08:42:30.301Z","updated_at":"2019-11-28T15:57:52.401Z","due_date":null,"start_date":null,"expired":false,"web_url":"https://gitlab.com/gitea/test_repo/-/milestones/1"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Freleases%3Fpage%3D1%26per_page%3D100 b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Freleases%3Fpage%3D1%26per_page%3D100 new file mode 100644 index 00000000..5735af83 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2F15578026%2Freleases%3Fpage%3D1%26per_page%3D100 @@ -0,0 +1,28 @@ +Cache-Control: max-age=0, private, must-revalidate +Cf-Cache-Status: MISS +Content-Security-Policy: default-src 'none' +Content-Type: application/json +Etag: W/"5c4c02bdd0b9515c20be9a3c92cd45f1" +Gitlab-Lb: haproxy-main-43-lb-gprd +Gitlab-Sv: api-gke-us-east1-b +Link: ; rel="first", ; rel="last" +Ratelimit-Limit: 2000 +Ratelimit-Name: throttle_authenticated_api +Ratelimit-Observed: 7 +Ratelimit-Remaining: 1993 +Ratelimit-Reset: 1776937500 +Referrer-Policy: strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"9f0bee7daa8cc27f-VIE","version":"1"} +X-Next-Page: +X-Page: 1 +X-Per-Page: 100 +X-Prev-Page: +X-Runtime: 0.097425 +X-Total: 1 +X-Total-Pages: 1 + +[{"name":"First Release","tag_name":"v0.9.99","description":"A test release","created_at":"2019-11-28T09:09:48.840Z","released_at":"2019-11-28T09:09:48.836Z","upcoming_release":false,"author":{"id":1241334,"username":"lafriks","public_email":"","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"commit":{"id":"0720a3ec57c1f843568298117b874319e7deee75","short_id":"0720a3ec","created_at":"2019-11-28T08:49:16.000+00:00","parent_ids":["93ea21ce45d35690c35e80961d239645139e872c"],"title":"Add new file","message":"Add new file","author_name":"Lauris BH","author_email":"lauris@nix.lv","authored_date":"2019-11-28T08:49:16.000+00:00","committer_name":"Lauris BH","committer_email":"lauris@nix.lv","committed_date":"2019-11-28T08:49:16.000+00:00","trailers":{},"extended_trailers":{},"web_url":"https://gitlab.com/gitea/test_repo/-/commit/0720a3ec57c1f843568298117b874319e7deee75"},"commit_path":"/gitea/test_repo/-/commit/0720a3ec57c1f843568298117b874319e7deee75","tag_path":"/gitea/test_repo/-/tags/v0.9.99","assets":{"count":4,"sources":[{"format":"zip","url":"https://gitlab.com/gitea/test_repo/-/archive/v0.9.99/test_repo-v0.9.99.zip"},{"format":"tar.gz","url":"https://gitlab.com/gitea/test_repo/-/archive/v0.9.99/test_repo-v0.9.99.tar.gz"},{"format":"tar.bz2","url":"https://gitlab.com/gitea/test_repo/-/archive/v0.9.99/test_repo-v0.9.99.tar.bz2"},{"format":"tar","url":"https://gitlab.com/gitea/test_repo/-/archive/v0.9.99/test_repo-v0.9.99.tar"}],"links":[]},"evidences":[{"sha":"89f1223473ee01f192a83d0cb89f4d1eac1de74f01ad","filepath":"https://gitlab.com/gitea/test_repo/-/releases/v0.9.99/evidences/52147.json","collected_at":"2019-11-28T09:09:48.888Z"}],"_links":{"closed_issues_url":"https://gitlab.com/gitea/test_repo/-/issues?release_tag=v0.9.99\u0026scope=all\u0026state=closed","closed_merge_requests_url":"https://gitlab.com/gitea/test_repo/-/merge_requests?release_tag=v0.9.99\u0026scope=all\u0026state=closed","merged_merge_requests_url":"https://gitlab.com/gitea/test_repo/-/merge_requests?release_tag=v0.9.99\u0026scope=all\u0026state=merged","opened_issues_url":"https://gitlab.com/gitea/test_repo/-/issues?release_tag=v0.9.99\u0026scope=all\u0026state=opened","opened_merge_requests_url":"https://gitlab.com/gitea/test_repo/-/merge_requests?release_tag=v0.9.99\u0026scope=all\u0026state=opened","self":"https://gitlab.com/gitea/test_repo/-/releases/v0.9.99"}}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2Fgitea%252Ftest_repo b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2Fgitea%252Ftest_repo new file mode 100644 index 00000000..a0597181 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fprojects%2Fgitea%252Ftest_repo @@ -0,0 +1,21 @@ +Cache-Control: max-age=0, private, must-revalidate +Cf-Cache-Status: MISS +Content-Security-Policy: default-src 'none' +Content-Type: application/json +Etag: W/"4b614e9f590cbbbc47e0f5a026615034" +Gitlab-Lb: haproxy-main-01-lb-gprd +Gitlab-Sv: api-gke-us-east1-b +Ratelimit-Limit: 2000 +Ratelimit-Name: throttle_authenticated_api +Ratelimit-Observed: 2 +Ratelimit-Remaining: 1998 +Ratelimit-Reset: 1776937500 +Referrer-Policy: strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"9f0bee728f28c27f-VIE","version":"1"} +X-Runtime: 0.320807 + +{"id":15578026,"description":"Test repository for testing migration from gitlab to gitea","name":"test_repo","name_with_namespace":"gitea / test_repo","path":"test_repo","path_with_namespace":"gitea/test_repo","created_at":"2019-11-28T08:20:33.019Z","default_branch":"master","tag_list":["migration","test"],"topics":["migration","test"],"ssh_url_to_repo":"git@gitlab.com:gitea/test_repo.git","http_url_to_repo":"https://gitlab.com/gitea/test_repo.git","web_url":"https://gitlab.com/gitea/test_repo","readme_url":"https://gitlab.com/gitea/test_repo/-/blob/master/README.md","forks_count":1,"avatar_url":null,"star_count":0,"last_activity_at":"2025-11-25T09:21:43.130Z","visibility":"public","namespace":{"id":3181312,"name":"gitea","path":"gitea","kind":"group","full_path":"gitea","parent_id":null,"avatar_url":"/uploads/-/system/group/avatar/3181312/gitea.png","web_url":"https://gitlab.com/groups/gitea"},"container_registry_image_prefix":"registry.gitlab.com/gitea/test_repo","_links":{"self":"https://gitlab.com/api/v4/projects/15578026","issues":"https://gitlab.com/api/v4/projects/15578026/issues","merge_requests":"https://gitlab.com/api/v4/projects/15578026/merge_requests","repo_branches":"https://gitlab.com/api/v4/projects/15578026/repository/branches","labels":"https://gitlab.com/api/v4/projects/15578026/labels","events":"https://gitlab.com/api/v4/projects/15578026/events","members":"https://gitlab.com/api/v4/projects/15578026/members","cluster_agents":"https://gitlab.com/api/v4/projects/15578026/cluster_agents"},"marked_for_deletion_at":null,"marked_for_deletion_on":null,"packages_enabled":true,"empty_repo":false,"archived":false,"resolve_outdated_diff_discussions":false,"repository_object_format":"sha1","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"jobs_enabled":true,"snippets_enabled":true,"container_registry_enabled":true,"service_desk_enabled":true,"can_create_merge_request_in":true,"issues_access_level":"enabled","repository_access_level":"enabled","merge_requests_access_level":"enabled","forking_access_level":"enabled","wiki_access_level":"enabled","builds_access_level":"enabled","snippets_access_level":"enabled","pages_access_level":"enabled","analytics_access_level":"enabled","container_registry_access_level":"enabled","security_and_compliance_access_level":"private","releases_access_level":"enabled","environments_access_level":"enabled","feature_flags_access_level":"enabled","infrastructure_access_level":"enabled","monitor_access_level":"enabled","model_experiments_access_level":"enabled","model_registry_access_level":"enabled","package_registry_access_level":"public","emails_disabled":false,"emails_enabled":true,"show_diff_preview_in_email":true,"shared_runners_enabled":true,"lfs_enabled":true,"creator_id":1241334,"import_status":"none","open_issues_count":0,"description_html":"\u003cp data-sourcepos=\"1:1-1:58\" dir=\"auto\"\u003eTest repository for testing migration from gitlab to gitea\u003c/p\u003e","updated_at":"2025-11-25T09:21:43.130Z","ci_config_path":null,"public_jobs":true,"shared_with_groups":[],"only_allow_merge_if_pipeline_succeeds":false,"allow_merge_on_skipped_pipeline":null,"request_access_enabled":true,"only_allow_merge_if_all_discussions_are_resolved":false,"remove_source_branch_after_merge":true,"printing_merge_request_link_enabled":true,"merge_method":"ff","squash_option":"default_off","enforce_auth_checks_on_uploads":true,"suggestion_commit_message":null,"merge_commit_template":null,"squash_commit_template":null,"issue_branch_template":null,"warn_about_potentially_unwanted_characters":true,"autoclose_referenced_issues":true,"max_artifacts_size":null,"external_authorization_classification_label":"","requirements_enabled":false,"requirements_access_level":"enabled","security_and_compliance_enabled":false,"compliance_frameworks":[],"permissions":{"project_access":null,"group_access":null}} \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fversion b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fversion new file mode 100644 index 00000000..4ac49026 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGitlabDownloadRepo/GET_%2Fapi%2Fv4%2Fversion @@ -0,0 +1,21 @@ +Cache-Control: max-age=0, private, must-revalidate +Cf-Cache-Status: MISS +Content-Security-Policy: default-src 'none' +Content-Type: application/json +Etag: W/"68fb72a6f737a013c4a1e293abfb186f" +Gitlab-Lb: haproxy-main-50-lb-gprd +Gitlab-Sv: api-gke-us-east1-c +Ratelimit-Limit: 2000 +Ratelimit-Name: throttle_authenticated_api +Ratelimit-Observed: 1 +Ratelimit-Remaining: 1999 +Ratelimit-Reset: 1776937500 +Referrer-Policy: strict-origin-when-cross-origin +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"9f0bee70fdcfc27f-VIE","version":"1"} +X-Runtime: 0.046078 + +{"version":"19.0.0-pre","revision":"3b95b4c0792","kas":{"enabled":true,"externalUrl":"wss://kas.gitlab.com","externalK8sProxyUrl":"https://kas.gitlab.com/k8s-proxy","version":"19.0.0-rc1+5cc4df2b2383c124b4a7501896f19c7df7a147cf"},"enterprise":true} \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGogsDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Flunnytest%2FTESTREPO b/package/gitea/source/services/migrations/_mock_data/TestGogsDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Flunnytest%2FTESTREPO new file mode 100644 index 00000000..61d77fbc --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGogsDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Flunnytest%2FTESTREPO @@ -0,0 +1,3 @@ +Content-Type: application/json; charset=UTF-8 + +{"id":1,"owner":{"id":5331,"login":"lunny","full_name":"","email":"xiaolunwen@gmail.com","avatar_url":"https://try.gogs.io/avatars/5331"},"name":"TESTREPO","full_name":"lunnytest/TESTREPO","description":"","private":false,"fork":false,"parent":null,"empty":false,"mirror":false,"size":0,"html_url":"https://try.gogs.io/lunnytest/TESTREPO","ssh_url":"git@try.gogs.io:lunnytest/TESTREPO.git","clone_url":"https://try.gogs.io/lunnytest/TESTREPO.git","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":1,"default_branch":"master","created_at":"2019-06-11T08:15:00Z","updated_at":"2019-06-11T08:15:00Z","permissions":{"admin":false,"push":false,"pull":true}} \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGogsDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Flunnytest%2FTESTREPO%2Fissues%2F1%2Fcomments b/package/gitea/source/services/migrations/_mock_data/TestGogsDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Flunnytest%2FTESTREPO%2Fissues%2F1%2Fcomments new file mode 100644 index 00000000..814fb999 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGogsDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Flunnytest%2FTESTREPO%2Fissues%2F1%2Fcomments @@ -0,0 +1,3 @@ +Content-Type: application/json; charset=UTF-8 + +[{"id":1,"user":{"id":5331,"login":"lunny","full_name":"","email":"xiaolunwen@gmail.com","avatar_url":"https://try.gogs.io/avatars/5331"},"body":"1111","created_at":"2019-06-11T08:19:50Z","updated_at":"2019-06-11T08:19:50Z"},{"id":2,"user":{"id":15822,"login":"clacplouf","full_name":"","email":"test1234@dbn.re","avatar_url":"https://try.gogs.io/avatars/15822"},"body":"88888888","created_at":"2019-10-26T11:07:02Z","updated_at":"2019-10-26T11:07:02Z"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGogsDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Flunnytest%2FTESTREPO%2Fissues%3Fpage%3D1%26state%3Dopen b/package/gitea/source/services/migrations/_mock_data/TestGogsDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Flunnytest%2FTESTREPO%2Fissues%3Fpage%3D1%26state%3Dopen new file mode 100644 index 00000000..5923e6e7 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGogsDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Flunnytest%2FTESTREPO%2Fissues%3Fpage%3D1%26state%3Dopen @@ -0,0 +1,3 @@ +Content-Type: application/json; charset=UTF-8 + +[{"id":1,"number":1,"user":{"id":5331,"login":"lunny","full_name":"","email":"xiaolunwen@gmail.com","avatar_url":"https://try.gogs.io/avatars/5331"},"title":"test","body":"test","labels":[{"id":1,"name":"bug","color":"ee0701"}],"milestone":null,"assignee":null,"state":"open","comments":2,"created_at":"2019-06-11T08:16:44Z","updated_at":"2019-10-26T11:07:02Z","pull_request":null}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGogsDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Flunnytest%2FTESTREPO%2Flabels b/package/gitea/source/services/migrations/_mock_data/TestGogsDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Flunnytest%2FTESTREPO%2Flabels new file mode 100644 index 00000000..ec19f2d0 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGogsDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Flunnytest%2FTESTREPO%2Flabels @@ -0,0 +1,3 @@ +Content-Type: application/json; charset=UTF-8 + +[{"id":1,"name":"bug","color":"ee0701"},{"id":2,"name":"duplicate","color":"cccccc"},{"id":3,"name":"enhancement","color":"84b6eb"},{"id":4,"name":"help wanted","color":"128a0c"},{"id":5,"name":"invalid","color":"e6e6e6"},{"id":6,"name":"question","color":"cc317c"},{"id":7,"name":"wontfix","color":"ffffff"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestGogsDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Flunnytest%2FTESTREPO%2Fmilestones b/package/gitea/source/services/migrations/_mock_data/TestGogsDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Flunnytest%2FTESTREPO%2Fmilestones new file mode 100644 index 00000000..f4c6d9dd --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestGogsDownloadRepo/GET_%2Fapi%2Fv1%2Frepos%2Flunnytest%2FTESTREPO%2Fmilestones @@ -0,0 +1,3 @@ +Content-Type: application/json; charset=UTF-8 + +[{"id":1,"title":"1.0","description":"","state":"open","open_issues":1,"closed_issues":0,"closed_at":null,"due_on":null}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fissues%2F397%2Fiterations b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fissues%2F397%2Fiterations new file mode 100644 index 00000000..2d6b18f5 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fissues%2F397%2Fiterations @@ -0,0 +1,3 @@ +Content-Type: application/json;charset=utf-8 + +[{"id":51,"name":"1.1.0"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fissues%2F398%2Fchanges b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fissues%2F398%2Fchanges new file mode 100644 index 00000000..1dcbc6ae --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fissues%2F398%2Fchanges @@ -0,0 +1,3 @@ +Content-Type: application/json;charset=utf-8 + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fissues%2F398%2Fcomments b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fissues%2F398%2Fcomments new file mode 100644 index 00000000..42683ef6 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fissues%2F398%2Fcomments @@ -0,0 +1,3 @@ +Content-Type: application/json;charset=utf-8 + +[{"id":1001,"date":"2021-08-09T22:56:31.128Z","userId":336,"content":"it has a comment\n\nEDIT: that got edited"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fissues%2F398%2Fiterations b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fissues%2F398%2Fiterations new file mode 100644 index 00000000..1dcbc6ae --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fissues%2F398%2Fiterations @@ -0,0 +1,3 @@ +Content-Type: application/json;charset=utf-8 + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fissues%3Fcount%3D2%26offset%3D0%26query%3D%2522Project%2522%2Bis%2B%2522go-gitea-test_repo%2522%26withFields%3Dtrue b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fissues%3Fcount%3D2%26offset%3D0%26query%3D%2522Project%2522%2Bis%2B%2522go-gitea-test_repo%2522%26withFields%3Dtrue new file mode 100644 index 00000000..0f2de921 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fissues%3Fcount%3D2%26offset%3D0%26query%3D%2522Project%2522%2Bis%2B%2522go-gitea-test_repo%2522%26withFields%3Dtrue @@ -0,0 +1,3 @@ +Content-Type: application/json;charset=utf-8 + +[{"id":398,"number":4,"state":"Open","title":"Hi there","description":"an issue not assigned to a milestone","submitterId":336,"submitDate":"2021-08-09T22:56:16.734Z","fields":[{"name":"Type","value":"Improvement"}]},{"id":397,"number":3,"state":"Open","title":"Add an awesome feature","description":"just another issue to test against","submitterId":336,"submitDate":"2021-08-09T22:55:49.878Z","fields":[{"name":"Type","value":"New Feature"}]}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fprojects%2F149%2Fiterations%3Fcount%3D100%26offset%3D0 b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fprojects%2F149%2Fiterations%3Fcount%3D100%26offset%3D0 new file mode 100644 index 00000000..85fe3fec --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fprojects%2F149%2Fiterations%3Fcount%3D100%26offset%3D0 @@ -0,0 +1,3 @@ +Content-Type: application/json;charset=utf-8 + +[{"id":50,"name":"1.0.0","description":"","dueDay":18751,"closed":true},{"id":51,"name":"1.1.0","description":"next things?","dueDay":0,"closed":false}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fprojects%2F149%2Fiterations%3Fcount%3D100%26offset%3D100 b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fprojects%2F149%2Fiterations%3Fcount%3D100%26offset%3D100 new file mode 100644 index 00000000..1dcbc6ae --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fprojects%2F149%2Fiterations%3Fcount%3D100%26offset%3D100 @@ -0,0 +1,3 @@ +Content-Type: application/json;charset=utf-8 + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fprojects%3Fcount%3D1%26offset%3D0%26query%3D%2522Path%2522%2Bis%2B%2522go-gitea-test_repo%2522 b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fprojects%3Fcount%3D1%26offset%3D0%26query%3D%2522Path%2522%2Bis%2B%2522go-gitea-test_repo%2522 new file mode 100644 index 00000000..dc4e332e --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fprojects%3Fcount%3D1%26offset%3D0%26query%3D%2522Path%2522%2Bis%2B%2522go-gitea-test_repo%2522 @@ -0,0 +1,3 @@ +Content-Type: application/json;charset=utf-8 + +[{"id":149,"name":"go-gitea-test_repo","path":"/go-gitea-test_repo","description":"Test repository for testing migration from OneDev to gitea"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fpulls%2F186%2Fmerge-preview b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fpulls%2F186%2Fmerge-preview new file mode 100644 index 00000000..ef3b5261 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fpulls%2F186%2Fmerge-preview @@ -0,0 +1,3 @@ +Content-Type: application/json;charset=utf-8 + +{"targetHeadCommitHash":"f32b0a9dfd09a60f616f29158f772cedd89942d2","headCommitHash":"343deffe3526b9bc84e873743ff7f6e6d8b827c0","mergeStrategy":"MERGE_IF_NECESSARY","mergeCommitHash":"abc123"} \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fpulls%2F186%2Freviews b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fpulls%2F186%2Freviews new file mode 100644 index 00000000..e0dc043b --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fpulls%2F186%2Freviews @@ -0,0 +1,3 @@ +Content-Type: application/json;charset=utf-8 + +[{"id":2001,"userId":317,"status":"PENDING"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fpulls%3Fcount%3D1%26offset%3D0%26query%3D%2522Target%2BProject%2522%2Bis%2B%2522go-gitea-test_repo%2522 b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fpulls%3Fcount%3D1%26offset%3D0%26query%3D%2522Target%2BProject%2522%2Bis%2B%2522go-gitea-test_repo%2522 new file mode 100644 index 00000000..0d40db72 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fpulls%3Fcount%3D1%26offset%3D0%26query%3D%2522Target%2BProject%2522%2Bis%2B%2522go-gitea-test_repo%2522 @@ -0,0 +1,3 @@ +Content-Type: application/json;charset=utf-8 + +[{"id":186,"number":1,"title":"Pull to add a new file","description":"just do some git stuff","submitterId":336,"submitDate":"2021-08-09T23:01:16.025Z","targetBranch":"master","sourceBranch":"branch-for-a-pull","baseCommitHash":"f32b0a9dfd09a60f616f29158f772cedd89942d2","status":"OPEN"}] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fusers%2F317 b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fusers%2F317 new file mode 100644 index 00000000..6d42ce89 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fusers%2F317 @@ -0,0 +1,3 @@ +Content-Type: application/json;charset=utf-8 + +{"name":"User 317"} \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fusers%2F317%2Femail-addresses b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fusers%2F317%2Femail-addresses new file mode 100644 index 00000000..1dcbc6ae --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fusers%2F317%2Femail-addresses @@ -0,0 +1,3 @@ +Content-Type: application/json;charset=utf-8 + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fusers%2F336 b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fusers%2F336 new file mode 100644 index 00000000..bf8a0e58 --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fusers%2F336 @@ -0,0 +1,3 @@ +Content-Type: application/json;charset=utf-8 + +{"name":"User 336"} \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fusers%2F336%2Femail-addresses b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fusers%2F336%2Femail-addresses new file mode 100644 index 00000000..1dcbc6ae --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fusers%2F336%2Femail-addresses @@ -0,0 +1,3 @@ +Content-Type: application/json;charset=utf-8 + +[] \ No newline at end of file diff --git a/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fversion%2Fserver b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fversion%2Fserver new file mode 100644 index 00000000..65c20b7e --- /dev/null +++ b/package/gitea/source/services/migrations/_mock_data/TestOneDevDownloadRepo/GET_%2F~api%2Fversion%2Fserver @@ -0,0 +1,3 @@ +Content-Type: text/plain;charset=utf-8 + +12.0.1 \ No newline at end of file diff --git a/package/gitea/source/services/migrations/codebase.go b/package/gitea/source/services/migrations/codebase.go index 240c7bcd..97c6cfe7 100644 --- a/package/gitea/source/services/migrations/codebase.go +++ b/package/gitea/source/services/migrations/codebase.go @@ -13,10 +13,10 @@ import ( "strings" "time" - "code.gitea.io/gitea/modules/log" - base "code.gitea.io/gitea/modules/migration" - "code.gitea.io/gitea/modules/proxy" - "code.gitea.io/gitea/modules/structs" + "gitea.dev/modules/log" + base "gitea.dev/modules/migration" + "gitea.dev/modules/proxy" + "gitea.dev/modules/structs" ) var ( diff --git a/package/gitea/source/services/migrations/codebase_test.go b/package/gitea/source/services/migrations/codebase_test.go index dabe7e1a..4e8f6f83 100644 --- a/package/gitea/source/services/migrations/codebase_test.go +++ b/package/gitea/source/services/migrations/codebase_test.go @@ -6,39 +6,34 @@ package migrations import ( "net/url" "os" + "path/filepath" + "runtime" "testing" "time" - base "code.gitea.io/gitea/modules/migration" + "gitea.dev/models/unittest" + base "gitea.dev/modules/migration" "github.com/stretchr/testify/assert" ) func TestCodebaseDownloadRepo(t *testing.T) { - // Skip tests if Codebase token is not found - cloneUser := os.Getenv("CODEBASE_CLONE_USER") - clonePassword := os.Getenv("CODEBASE_CLONE_PASSWORD") apiUser := os.Getenv("CODEBASE_API_USER") apiPassword := os.Getenv("CODEBASE_API_TOKEN") - if apiUser == "" || apiPassword == "" { - t.Skip("skipped test because a CODEBASE_ variable was not in the environment") - } + liveMode := apiUser != "" && apiPassword != "" + + _, callerFile, _, _ := runtime.Caller(0) + fixtureDir := filepath.Join(filepath.Dir(callerFile), "_mock_data/TestCodebaseDownloadRepo") + mockServer := unittest.NewMockWebServer(t, "https://api3.codebasehq.com", fixtureDir, liveMode) cloneAddr := "https://gitea-test.codebasehq.com/gitea-test/test.git" - u, _ := url.Parse(cloneAddr) - if cloneUser != "" { - u.User = url.UserPassword(cloneUser, clonePassword) - } + projectURL, _ := url.Parse(cloneAddr) + projectURL.User = nil + ctx := t.Context() - factory := &CodebaseDownloaderFactory{} - downloader, err := factory.New(ctx, base.MigrateOptions{ - CloneAddr: u.String(), - AuthUsername: apiUser, - AuthPassword: apiPassword, - }) - if err != nil { - t.Fatalf("Error creating Codebase downloader: %v", err) - } + downloader := NewCodebaseDownloader(ctx, projectURL, "gitea-test", "test", apiUser, apiPassword) + downloader.baseURL, _ = url.Parse(mockServer.URL) + repo, err := downloader.GetRepoInfo(ctx) assert.NoError(t, err) assertRepositoryEqual(t, &base.Repository{ @@ -144,6 +139,6 @@ func TestCodebaseDownloadRepo(t *testing.T) { }, prs) rvs, err := downloader.GetReviews(ctx, prs[0]) - assert.NoError(t, err) + assert.Error(t, err) assert.Empty(t, rvs) } diff --git a/package/gitea/source/services/migrations/codecommit.go b/package/gitea/source/services/migrations/codecommit.go index 18828027..2c201947 100644 --- a/package/gitea/source/services/migrations/codecommit.go +++ b/package/gitea/source/services/migrations/codecommit.go @@ -10,10 +10,10 @@ import ( "strconv" "strings" - git_module "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/log" - base "code.gitea.io/gitea/modules/migration" - "code.gitea.io/gitea/modules/structs" + git_module "gitea.dev/modules/git" + "gitea.dev/modules/log" + base "gitea.dev/modules/migration" + "gitea.dev/modules/structs" "github.com/aws/aws-sdk-go-v2/credentials" "github.com/aws/aws-sdk-go-v2/service/codecommit" diff --git a/package/gitea/source/services/migrations/common.go b/package/gitea/source/services/migrations/common.go index d8851889..ba809e40 100644 --- a/package/gitea/source/services/migrations/common.go +++ b/package/gitea/source/services/migrations/common.go @@ -7,10 +7,10 @@ import ( "fmt" "strings" - system_model "code.gitea.io/gitea/models/system" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/log" - base "code.gitea.io/gitea/modules/migration" + system_model "gitea.dev/models/system" + "gitea.dev/modules/git" + "gitea.dev/modules/log" + base "gitea.dev/modules/migration" ) // WarnAndNotice will log the provided message and send a repository notice @@ -22,6 +22,9 @@ func WarnAndNotice(fmtStr string, args ...any) { } func hasBaseURL(toCheck, baseURL string) bool { + if baseURL == "" { + return false + } if len(baseURL) > 0 && baseURL[len(baseURL)-1] != '/' { baseURL += "/" } diff --git a/package/gitea/source/services/migrations/dump.go b/package/gitea/source/services/migrations/dump.go index eb0367e9..e5a56975 100644 --- a/package/gitea/source/services/migrations/dump.go +++ b/package/gitea/source/services/migrations/dump.go @@ -8,7 +8,6 @@ import ( "errors" "fmt" "io" - "net/http" "net/url" "os" "path/filepath" @@ -16,17 +15,17 @@ import ( "strings" "time" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/git/gitcmd" - "code.gitea.io/gitea/modules/log" - base "code.gitea.io/gitea/modules/migration" - "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/structs" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/log" + base "gitea.dev/modules/migration" + "gitea.dev/modules/repository" + "gitea.dev/modules/setting" + "gitea.dev/modules/structs" "github.com/google/uuid" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v4" ) var _ base.Uploader = &RepositoryDumper{} @@ -115,6 +114,7 @@ func (g *RepositoryDumper) CreateRepo(ctx context.Context, repo *base.Repository "name": repo.Name, "owner": repo.Owner, "description": repo.Description, + "website": repo.Website, "clone_addr": opts.CloneAddr, "original_url": repo.OriginalURL, "is_private": opts.Private, @@ -309,7 +309,9 @@ func (g *RepositoryDumper) CreateReleases(_ context.Context, releases ...*base.R } defer rc.Close() } else { - resp, err := http.Get(*asset.DownloadURL) + // use the migration client so the fetch (including any redirect) is + // validated against the migration host allow/block list + resp, err := getMigrationHTTPClient().Get(*asset.DownloadURL) if err != nil { return err } @@ -449,8 +451,10 @@ func (g *RepositoryDumper) handlePullRequest(ctx context.Context, pr *base.PullR } // SECURITY: We will assume that the pr.PatchURL has been checked - // pr.PatchURL maybe a local file - but note EnsureSafe should be asserting that this safe - resp, err := http.Get(u) // TODO: This probably needs to use the downloader as there may be rate limiting issues here + // pr.PatchURL maybe a local file - but note EnsureSafe should be asserting that this safe. + // Use the migration client so an http(s) PatchURL (and any redirect it follows) is + // validated against the migration host allow/block list at dial time. + resp, err := getMigrationHTTPClient().Get(u) if err != nil { return err } diff --git a/package/gitea/source/services/migrations/error.go b/package/gitea/source/services/migrations/error.go index db9b6b4c..2dd5540f 100644 --- a/package/gitea/source/services/migrations/error.go +++ b/package/gitea/source/services/migrations/error.go @@ -7,7 +7,7 @@ package migrations import ( "errors" - "github.com/google/go-github/v84/github" + "github.com/google/go-github/v88/github" ) // ErrRepoNotCreated returns the error that repository not created diff --git a/package/gitea/source/services/migrations/git.go b/package/gitea/source/services/migrations/git.go index 1ed99499..c9b5eaaf 100644 --- a/package/gitea/source/services/migrations/git.go +++ b/package/gitea/source/services/migrations/git.go @@ -6,7 +6,7 @@ package migrations import ( "context" - base "code.gitea.io/gitea/modules/migration" + base "gitea.dev/modules/migration" ) var _ base.Downloader = &PlainGitDownloader{} diff --git a/package/gitea/source/services/migrations/gitbucket.go b/package/gitea/source/services/migrations/gitbucket.go index 4fe9e30a..026fa3c1 100644 --- a/package/gitea/source/services/migrations/gitbucket.go +++ b/package/gitea/source/services/migrations/gitbucket.go @@ -9,9 +9,9 @@ import ( "net/url" "strings" - "code.gitea.io/gitea/modules/log" - base "code.gitea.io/gitea/modules/migration" - "code.gitea.io/gitea/modules/structs" + "gitea.dev/modules/log" + base "gitea.dev/modules/migration" + "gitea.dev/modules/structs" ) var ( @@ -43,7 +43,7 @@ func (f *GitBucketDownloaderFactory) New(ctx context.Context, opts base.MigrateO oldName := strings.TrimSuffix(fields[len(fields)-1], ".git") log.Trace("Create GitBucket downloader. BaseURL: %s RepoOwner: %s RepoName: %s", baseURL, oldOwner, oldName) - return NewGitBucketDownloader(ctx, baseURL, opts.AuthUsername, opts.AuthPassword, opts.AuthToken, oldOwner, oldName), nil + return NewGitBucketDownloader(ctx, baseURL, opts.AuthUsername, opts.AuthPassword, opts.AuthToken, oldOwner, oldName) } // GitServiceType returns the type of git service @@ -70,8 +70,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) +func NewGitBucketDownloader(ctx context.Context, baseURL, userName, password, token, repoOwner, repoName string) (*GitBucketDownloader, error) { + githubDownloader, err := NewGithubDownloaderV3(ctx, baseURL, userName, password, token, repoOwner, repoName) + if err != nil { + return nil, err + } // 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 @@ -81,7 +84,7 @@ func NewGitBucketDownloader(ctx context.Context, baseURL, userName, password, to githubDownloader.SkipReviews = true return &GitBucketDownloader{ githubDownloader, - } + }, nil } // SupportGetRepoComments return true if it supports get repo comments diff --git a/package/gitea/source/services/migrations/gitea_downloader.go b/package/gitea/source/services/migrations/gitea_downloader.go index 5609e326..6ec70e2b 100644 --- a/package/gitea/source/services/migrations/gitea_downloader.go +++ b/package/gitea/source/services/migrations/gitea_downloader.go @@ -13,11 +13,10 @@ import ( "strings" "time" - "code.gitea.io/gitea/modules/log" - base "code.gitea.io/gitea/modules/migration" - "code.gitea.io/gitea/modules/structs" - - gitea_sdk "code.gitea.io/sdk/gitea" + "gitea.dev/modules/log" + base "gitea.dev/modules/migration" + "gitea.dev/modules/structs" + gitea_sdk "gitea.dev/sdk" ) var ( @@ -67,6 +66,7 @@ func (f *GiteaDownloaderFactory) GitServiceType() structs.GitServiceType { // GiteaDownloader implements a Downloader interface to get repository information's type GiteaDownloader struct { base.NullDownloader + ctx context.Context client *gitea_sdk.Client baseURL string repoOwner string @@ -84,8 +84,7 @@ func NewGiteaDownloader(ctx context.Context, baseURL, repoPath, username, passwo baseURL, gitea_sdk.SetToken(token), gitea_sdk.SetBasicAuth(username, password), - gitea_sdk.SetContext(ctx), - gitea_sdk.SetHTTPClient(NewMigrationHTTPClient()), + gitea_sdk.SetHTTPClient(newMigrationHTTPClient()), ) if err != nil { log.Error(fmt.Sprintf("Failed to create NewGiteaDownloader for: %s. Error: %v", baseURL, err)) @@ -95,7 +94,7 @@ func NewGiteaDownloader(ctx context.Context, baseURL, repoPath, username, passwo path := strings.Split(repoPath, "/") paginationSupport := true - if err = giteaClient.CheckServerVersionConstraint(">=1.12"); err != nil { + if err = giteaClient.CheckServerVersionConstraint(ctx, ">=1.12"); err != nil { paginationSupport = false } @@ -103,7 +102,7 @@ func NewGiteaDownloader(ctx context.Context, baseURL, repoPath, username, passwo // (default would be 50 but this can differ) maxPerPage := 10 // gitea instances >=1.13 can tell us what maximum they have - apiConf, _, err := giteaClient.GetGlobalAPISettings() + apiConf, _, err := giteaClient.Settings.GetGlobalAPISettings(ctx) if err != nil { log.Info("Unable to get global API settings. Ignoring these.") log.Debug("giteaClient.GetGlobalAPISettings. Error: %v", err) @@ -113,6 +112,7 @@ func NewGiteaDownloader(ctx context.Context, baseURL, repoPath, username, passwo } return &GiteaDownloader{ + ctx: ctx, client: giteaClient, baseURL: baseURL, repoOwner: path[0], @@ -140,7 +140,7 @@ func (g *GiteaDownloader) GetRepoInfo(_ context.Context) (*base.Repository, erro return nil, errors.New("error: GiteaDownloader is nil") } - repo, _, err := g.client.GetRepo(g.repoOwner, g.repoName) + repo, _, err := g.client.Repositories.GetRepo(g.ctx, g.repoOwner, g.repoName) if err != nil { return nil, err } @@ -150,6 +150,7 @@ func (g *GiteaDownloader) GetRepoInfo(_ context.Context) (*base.Repository, erro Owner: repo.Owner.UserName, IsPrivate: repo.Private, Description: repo.Description, + Website: repo.Website, CloneURL: repo.CloneURL, OriginalURL: repo.HTMLURL, DefaultBranch: repo.DefaultBranch, @@ -158,7 +159,7 @@ func (g *GiteaDownloader) GetRepoInfo(_ context.Context) (*base.Repository, erro // GetTopics return gitea topics func (g *GiteaDownloader) GetTopics(_ context.Context) ([]string, error) { - topics, _, err := g.client.ListRepoTopics(g.repoOwner, g.repoName, gitea_sdk.ListRepoTopicsOptions{}) + topics, _, err := g.client.Repositories.ListRepoTopics(g.ctx, g.repoOwner, g.repoName, gitea_sdk.ListRepoTopicsOptions{}) return topics, err } @@ -174,7 +175,7 @@ func (g *GiteaDownloader) GetMilestones(ctx context.Context) ([]*base.Milestone, default: } - ms, _, err := g.client.ListRepoMilestones(g.repoOwner, g.repoName, gitea_sdk.ListMilestoneOption{ + ms, _, err := g.client.Repositories.ListMilestones(g.ctx, g.repoOwner, g.repoName, gitea_sdk.ListMilestoneOption{ ListOptions: gitea_sdk.ListOptions{ PageSize: g.maxPerPage, Page: i, @@ -239,7 +240,7 @@ func (g *GiteaDownloader) GetLabels(ctx context.Context) ([]*base.Label, error) default: } - ls, _, err := g.client.ListRepoLabels(g.repoOwner, g.repoName, gitea_sdk.ListLabelsOptions{ListOptions: gitea_sdk.ListOptions{ + ls, _, err := g.client.Repositories.ListRepoLabels(g.ctx, g.repoOwner, g.repoName, gitea_sdk.ListLabelsOptions{ListOptions: gitea_sdk.ListOptions{ PageSize: g.maxPerPage, Page: i, }}) @@ -272,7 +273,7 @@ func (g *GiteaDownloader) convertGiteaRelease(rel *gitea_sdk.Release) *base.Rele Created: rel.CreatedAt, } - httpClient := NewMigrationHTTPClient() + httpClient := newMigrationHTTPClient() for _, asset := range rel.Attachments { assetID := asset.ID // Don't optimize this, for closure we need a local variable @@ -287,7 +288,7 @@ func (g *GiteaDownloader) convertGiteaRelease(rel *gitea_sdk.Release) *base.Rele Created: asset.Created, DownloadURL: &asset.DownloadURL, DownloadFunc: func() (io.ReadCloser, error) { - asset, _, err := g.client.GetReleaseAttachment(g.repoOwner, g.repoName, rel.ID, assetID) + asset, _, err := g.client.Releases.GetReleaseAttachment(g.ctx, g.repoOwner, g.repoName, rel.ID, assetID) if err != nil { return nil, err } @@ -327,7 +328,7 @@ func (g *GiteaDownloader) GetReleases(ctx context.Context) ([]*base.Release, err default: } - rl, _, err := g.client.ListReleases(g.repoOwner, g.repoName, gitea_sdk.ListReleasesOptions{ListOptions: gitea_sdk.ListOptions{ + rl, _, err := g.client.Releases.ListReleases(g.ctx, g.repoOwner, g.repoName, gitea_sdk.ListReleasesOptions{ListOptions: gitea_sdk.ListOptions{ PageSize: g.maxPerPage, Page: i, }}) @@ -346,7 +347,7 @@ func (g *GiteaDownloader) GetReleases(ctx context.Context) ([]*base.Release, err } func (g *GiteaDownloader) getIssueReactions(ctx context.Context, index int64) ([]*base.Reaction, error) { - if err := g.client.CheckServerVersionConstraint(">=1.11"); err != nil { + if err := g.client.CheckServerVersionConstraint(g.ctx, ">=1.11"); err != nil { log.Info("GiteaDownloader: instance to old, skip getIssueReactions") return nil, nil } @@ -361,7 +362,7 @@ func (g *GiteaDownloader) getIssueReactions(ctx context.Context, index int64) ([ default: } - reactions, _, err := g.client.ListIssueReactions(g.repoOwner, g.repoName, index, gitea_sdk.ListIssueReactionsOptions{ListOptions: gitea_sdk.ListOptions{ + reactions, _, err := g.client.Issues.ListIssueReactions(g.ctx, g.repoOwner, g.repoName, index, gitea_sdk.ListIssueReactionsOptions{ListOptions: gitea_sdk.ListOptions{ PageSize: g.maxPerPage, Page: i, }}) @@ -386,11 +387,11 @@ func (g *GiteaDownloader) getIssueReactions(ctx context.Context, index int64) ([ func (g *GiteaDownloader) getCommentReactions(commentID int64) ([]*base.Reaction, error) { var reactions []*base.Reaction - if err := g.client.CheckServerVersionConstraint(">=1.11"); err != nil { + if err := g.client.CheckServerVersionConstraint(g.ctx, ">=1.11"); err != nil { log.Info("GiteaDownloader: instance to old, skip getCommentReactions") return reactions, nil } - rl, _, err := g.client.GetIssueCommentReactions(g.repoOwner, g.repoName, commentID) + rl, _, err := g.client.Issues.GetIssueCommentReactions(g.ctx, g.repoOwner, g.repoName, commentID) if err != nil { return nil, err } @@ -412,7 +413,7 @@ func (g *GiteaDownloader) GetIssues(ctx context.Context, page, perPage int) ([]* } allIssues := make([]*base.Issue, 0, perPage) - issues, _, err := g.client.ListRepoIssues(g.repoOwner, g.repoName, gitea_sdk.ListIssueOption{ + issues, _, err := g.client.Issues.ListRepoIssues(g.ctx, g.repoOwner, g.repoName, gitea_sdk.ListIssueOption{ ListOptions: gitea_sdk.ListOptions{Page: page, PageSize: perPage}, State: gitea_sdk.StateAll, Type: gitea_sdk.IssueTypeIssue, @@ -480,7 +481,7 @@ func (g *GiteaDownloader) GetComments(ctx context.Context, commentable base.Comm default: } - comments, _, err := g.client.ListIssueComments(g.repoOwner, g.repoName, commentable.GetForeignIndex(), gitea_sdk.ListIssueCommentOptions{ListOptions: gitea_sdk.ListOptions{ + comments, _, err := g.client.Issues.ListIssueComments(g.ctx, g.repoOwner, g.repoName, commentable.GetForeignIndex(), gitea_sdk.ListIssueCommentOptions{ListOptions: gitea_sdk.ListOptions{ PageSize: g.maxPerPage, Page: i, }}) @@ -521,7 +522,7 @@ func (g *GiteaDownloader) GetPullRequests(ctx context.Context, page, perPage int } allPRs := make([]*base.PullRequest, 0, perPage) - prs, _, err := g.client.ListRepoPullRequests(g.repoOwner, g.repoName, gitea_sdk.ListPullRequestsOptions{ + prs, _, err := g.client.PullRequests.ListRepoPullRequests(g.ctx, g.repoOwner, g.repoName, gitea_sdk.ListPullRequestsOptions{ ListOptions: gitea_sdk.ListOptions{ Page: page, PageSize: perPage, @@ -636,7 +637,7 @@ func (g *GiteaDownloader) GetPullRequests(ctx context.Context, page, perPage int // GetReviews returns pull requests review func (g *GiteaDownloader) GetReviews(ctx context.Context, reviewable base.Reviewable) ([]*base.Review, error) { - if err := g.client.CheckServerVersionConstraint(">=1.12"); err != nil { + if err := g.client.CheckServerVersionConstraint(g.ctx, ">=1.12"); err != nil { log.Info("GiteaDownloader: instance to old, skip GetReviews") return nil, nil } @@ -651,7 +652,7 @@ func (g *GiteaDownloader) GetReviews(ctx context.Context, reviewable base.Review default: } - prl, _, err := g.client.ListPullReviews(g.repoOwner, g.repoName, reviewable.GetForeignIndex(), gitea_sdk.ListPullReviewsOptions{ListOptions: gitea_sdk.ListOptions{ + prl, _, err := g.client.PullRequests.ListPullReviews(g.ctx, g.repoOwner, g.repoName, reviewable.GetForeignIndex(), gitea_sdk.ListPullReviewsOptions{ListOptions: gitea_sdk.ListOptions{ Page: i, PageSize: g.maxPerPage, }}) @@ -666,7 +667,7 @@ func (g *GiteaDownloader) GetReviews(ctx context.Context, reviewable base.Review continue } - rcl, _, err := g.client.ListPullReviewComments(g.repoOwner, g.repoName, reviewable.GetForeignIndex(), pr.ID) + rcl, _, err := g.client.PullRequests.ListPullReviewComments(g.ctx, g.repoOwner, g.repoName, reviewable.GetForeignIndex(), pr.ID) if err != nil { return nil, err } diff --git a/package/gitea/source/services/migrations/gitea_downloader_test.go b/package/gitea/source/services/migrations/gitea_downloader_test.go index cf727b44..e65aa024 100644 --- a/package/gitea/source/services/migrations/gitea_downloader_test.go +++ b/package/gitea/source/services/migrations/gitea_downloader_test.go @@ -4,32 +4,30 @@ package migrations import ( - "net/http" "os" + "path/filepath" + "runtime" "sort" "testing" "time" - base "code.gitea.io/gitea/modules/migration" + "gitea.dev/models/unittest" + base "gitea.dev/modules/migration" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestGiteaDownloadRepo(t *testing.T) { - // Skip tests if Gitea token is not found (TODO: this test seems stopped for long time because there is no token in CI secrets) - giteaToken := os.Getenv("GITEA_TEST_OFFICIAL_SITE_TOKEN") - if giteaToken == "" { - t.Skip("skipped test because GITEA_TEST_OFFICIAL_SITE_TOKEN was not in the environment") - } + token := os.Getenv("GITEA_TEST_OFFICIAL_SITE_TOKEN") + liveMode := token != "" + + _, callerFile, _, _ := runtime.Caller(0) + fixtureDir := filepath.Join(filepath.Dir(callerFile), "_mock_data/TestGiteaDownloadRepo") + mockServer := unittest.NewMockWebServer(t, "https://gitea.com", fixtureDir, liveMode) - resp, err := http.Get("https://gitea.com/gitea") - if err != nil || resp.StatusCode != http.StatusOK { - t.Skipf("Can't reach https://gitea.com, skipping %s", t.Name()) - } - defer resp.Body.Close() ctx := t.Context() - downloader, err := NewGiteaDownloader(ctx, "https://gitea.com", "gitea/test_repo", "", "", giteaToken) + downloader, err := NewGiteaDownloader(ctx, mockServer.URL, "gitea/test_repo", "", "", token) require.NoError(t, err, "NewGiteaDownloader error occur") require.NotNil(t, downloader, "NewGiteaDownloader is nil") @@ -40,8 +38,9 @@ func TestGiteaDownloadRepo(t *testing.T) { Owner: "gitea", IsPrivate: false, Description: "Test repository for testing migration from gitea to gitea", - CloneURL: "https://gitea.com/gitea/test_repo.git", - OriginalURL: "https://gitea.com/gitea/test_repo", + Website: mockServer.URL + "/test-repo", + CloneURL: mockServer.URL + "/gitea/test_repo.git", + OriginalURL: mockServer.URL + "/gitea/test_repo", DefaultBranch: "master", }, repo) @@ -83,21 +82,21 @@ func TestGiteaDownloadRepo(t *testing.T) { milestones, err := downloader.GetMilestones(ctx) assert.NoError(t, err) assertMilestonesEqual(t, []*base.Milestone{ - { - Title: "V2 Finalize", - Created: time.Unix(0, 0), - Deadline: new(time.Unix(1599263999, 0)), - Updated: new(time.Unix(0, 0)), - State: "open", - }, { Title: "V1", Description: "Generate Content", Created: time.Unix(0, 0), Updated: new(time.Unix(0, 0)), - Closed: new(time.Unix(1598985406, 0)), + Closed: new(time.Date(2020, 9, 1, 18, 36, 46, 0, time.UTC)), State: "closed", }, + { + Title: "V2 Finalize", + Created: time.Unix(0, 0), + Deadline: new(time.Date(2020, 9, 4, 23, 59, 59, 0, time.UTC)), + Updated: new(time.Date(2022, 11, 13, 5, 29, 15, 0, time.UTC)), + State: "open", + }, }, milestones) releases, err := downloader.GetReleases(ctx) @@ -114,7 +113,7 @@ func TestGiteaDownloadRepo(t *testing.T) { Published: time.Date(2020, 9, 1, 18, 2, 43, 0, time.UTC), PublisherID: 689, PublisherName: "6543", - PublisherEmail: "6543@obermui.de", + PublisherEmail: "689+6543@noreply.gitea.com", }, { Name: "First Release", @@ -127,7 +126,7 @@ func TestGiteaDownloadRepo(t *testing.T) { Published: time.Date(2020, 9, 1, 17, 30, 32, 0, time.UTC), PublisherID: 689, PublisherName: "6543", - PublisherEmail: "6543@obermui.de", + PublisherEmail: "689+6543@noreply.gitea.com", }, }, releases) @@ -149,7 +148,7 @@ func TestGiteaDownloadRepo(t *testing.T) { Milestone: "V1", PosterID: -1, PosterName: "Ghost", - PosterEmail: "", + PosterEmail: "-1+ghost@noreply.gitea.com", State: "closed", IsLocked: true, Created: time.Unix(1598975321, 0), @@ -180,7 +179,7 @@ func TestGiteaDownloadRepo(t *testing.T) { Milestone: "", PosterID: 689, PosterName: "6543", - PosterEmail: "6543@obermui.de", + PosterEmail: "689+6543@noreply.gitea.com", State: "closed", IsLocked: false, Created: time.Unix(1598919780, 0), @@ -201,7 +200,7 @@ func TestGiteaDownloadRepo(t *testing.T) { IssueIndex: 4, PosterID: 689, PosterName: "6543", - PosterEmail: "6543@obermui.de", + PosterEmail: "689+6543@noreply.gitea.com", Created: time.Unix(1598975370, 0), Updated: time.Unix(1599070865, 0), Content: "a really good question!\n\nIt is the used as TESTSET for gitea2gitea repo migration function", @@ -210,7 +209,7 @@ func TestGiteaDownloadRepo(t *testing.T) { IssueIndex: 4, PosterID: -1, PosterName: "Ghost", - PosterEmail: "", + PosterEmail: "-1+ghost@noreply.gitea.com", Created: time.Unix(1598975393, 0), Updated: time.Unix(1598975393, 0), Content: "Oh!", @@ -229,7 +228,7 @@ func TestGiteaDownloadRepo(t *testing.T) { Number: 12, PosterID: 689, PosterName: "6543", - PosterEmail: "6543@obermui.de", + PosterEmail: "689+6543@noreply.gitea.com", Title: "Dont Touch", Content: "\r\nadd dont touch note", Milestone: "V2 Finalize", @@ -237,7 +236,7 @@ func TestGiteaDownloadRepo(t *testing.T) { IsLocked: false, Created: time.Unix(1598982759, 0), Updated: time.Unix(1599023425, 0), - Closed: new(time.Unix(1598982934, 0)), + Closed: new(time.Unix(1598982933, 0)), Assignees: []string{"techknowlogick"}, Base: base.PullRequestBranch{ CloneURL: "", @@ -247,7 +246,7 @@ func TestGiteaDownloadRepo(t *testing.T) { OwnerName: "gitea", }, Head: base.PullRequestBranch{ - CloneURL: "https://gitea.com/6543-forks/test_repo.git", + CloneURL: mockServer.URL + "/6543-forks/test_repo.git", Ref: "refs/pull/12/head", SHA: "b6ab5d9ae000b579a5fff03f92c486da4ddf48b6", RepoName: "test_repo", @@ -256,7 +255,7 @@ func TestGiteaDownloadRepo(t *testing.T) { Merged: true, MergedTime: new(time.Unix(1598982934, 0)), MergeCommitSHA: "827aa28a907853e5ddfa40c8f9bc52471a2685fd", - PatchURL: "https://gitea.com/gitea/test_repo/pulls/12.patch", + PatchURL: mockServer.URL + "/gitea/test_repo/pulls/12.patch", }, prs[1]) reviews, err := downloader.GetReviews(ctx, &base.Issue{Number: 7, ForeignIndex: 7}) @@ -283,7 +282,7 @@ func TestGiteaDownloadRepo(t *testing.T) { PosterID: 689, Reactions: nil, CreatedAt: time.Date(2020, 9, 1, 16, 12, 58, 0, time.UTC), - UpdatedAt: time.Date(2020, 9, 1, 16, 12, 58, 0, time.UTC), + UpdatedAt: time.Date(2024, 6, 3, 1, 18, 36, 0, time.UTC), }, }, }, diff --git a/package/gitea/source/services/migrations/gitea_uploader.go b/package/gitea/source/services/migrations/gitea_uploader.go index 6c6ff7bc..01b8557b 100644 --- a/package/gitea/source/services/migrations/gitea_uploader.go +++ b/package/gitea/source/services/migrations/gitea_uploader.go @@ -13,26 +13,26 @@ import ( "strings" "time" - "code.gitea.io/gitea/models" - "code.gitea.io/gitea/models/db" - issues_model "code.gitea.io/gitea/models/issues" - 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/git/gitcmd" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/label" - "code.gitea.io/gitea/modules/log" - base "code.gitea.io/gitea/modules/migration" - repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/storage" - "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/uri" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/services/pull" - repo_service "code.gitea.io/gitea/services/repository" + "gitea.dev/models" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/label" + "gitea.dev/modules/log" + base "gitea.dev/modules/migration" + repo_module "gitea.dev/modules/repository" + "gitea.dev/modules/setting" + "gitea.dev/modules/storage" + "gitea.dev/modules/structs" + "gitea.dev/modules/timeutil" + "gitea.dev/modules/uri" + "gitea.dev/modules/util" + "gitea.dev/services/pull" + repo_service "gitea.dev/services/repository" "github.com/google/uuid" ) @@ -102,6 +102,7 @@ func (g *GiteaLocalUploader) CreateRepo(ctx context.Context, repo *base.Reposito r, err = repo_service.CreateRepositoryDirectly(ctx, g.doer, owner, repo_service.CreateRepoOptions{ Name: g.repoName, Description: repo.Description, + Website: repo.Website, OriginalURL: repo.OriginalURL, GitServiceType: opts.GitServiceType, IsPrivate: opts.Private || setting.Repository.ForcePrivate, @@ -116,6 +117,7 @@ func (g *GiteaLocalUploader) CreateRepo(ctx context.Context, repo *base.Reposito } r.DefaultBranch = repo.DefaultBranch r.Description = repo.Description + r.Website = repo.Website r, err = repo_service.MigrateRepositoryGitData(ctx, owner, r, base.MigrateOptions{ RepoName: g.repoName, @@ -338,7 +340,9 @@ func (g *GiteaLocalUploader) CreateReleases(ctx context.Context, releases ...*ba return err } } else if asset.DownloadURL != nil { - rc, err = uri.Open(*asset.DownloadURL) + // use the migration client so the fetch (including any redirect) is + // validated against the migration host allow/block list + rc, err = uri.OpenWithClient(*asset.DownloadURL, getMigrationHTTPClient()) if err != nil { return err } @@ -583,8 +587,10 @@ func (g *GiteaLocalUploader) updateGitForPullRequest(ctx context.Context, pr *ba } // SECURITY: We will assume that the pr.PatchURL has been checked - // pr.PatchURL maybe a local file - but note EnsureSafe should be asserting that this safe - ret, err := uri.Open(pr.PatchURL) // TODO: This probably needs to use the downloader as there may be rate limiting issues here + // pr.PatchURL maybe a local file - but note EnsureSafe should be asserting that this safe. + // Use the migration client so an http(s) PatchURL (and any redirect it follows) is + // validated against the migration host allow/block list at dial time. + ret, err := uri.OpenWithClient(pr.PatchURL, getMigrationHTTPClient()) if err != nil { return err } diff --git a/package/gitea/source/services/migrations/gitea_uploader_test.go b/package/gitea/source/services/migrations/gitea_uploader_test.go index 0b9f0eb9..ce6b177a 100644 --- a/package/gitea/source/services/migrations/gitea_uploader_test.go +++ b/package/gitea/source/services/migrations/gitea_uploader_test.go @@ -9,18 +9,19 @@ import ( "testing" "time" - "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/graceful" - base "code.gitea.io/gitea/modules/migration" - "code.gitea.io/gitea/modules/optional" - "code.gitea.io/gitea/modules/structs" - repo_service "code.gitea.io/gitea/services/repository" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/modules/graceful" + base "gitea.dev/modules/migration" + "gitea.dev/modules/optional" + "gitea.dev/modules/structs" + repo_service "gitea.dev/services/repository" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestGiteaUploadRepo(t *testing.T) { @@ -31,14 +32,15 @@ func TestGiteaUploadRepo(t *testing.T) { user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) + ctx := t.Context() + downloader, err := NewGithubDownloaderV3(ctx, "https://github.com", "", "", "", "go-xorm", "builder") + require.NoError(t, err) var ( - ctx = t.Context() - downloader = NewGithubDownloaderV3(ctx, "https://github.com", "", "", "", "go-xorm", "builder") - repoName = "builder-" + time.Now().Format("2006-01-02-15-04-05") - uploader = NewGiteaLocalUploader(graceful.GetManager().HammerContext(), user, user.Name, repoName) + repoName = "builder-" + time.Now().Format("2006-01-02-15-04-05") + uploader = NewGiteaLocalUploader(graceful.GetManager().HammerContext(), user, user.Name, repoName) ) - err := migrateRepository(t.Context(), user, downloader, uploader, base.MigrateOptions{ + err = migrateRepository(t.Context(), user, downloader, uploader, base.MigrateOptions{ CloneAddr: "https://github.com/go-xorm/builder", RepoName: repoName, AuthUsername: "", diff --git a/package/gitea/source/services/migrations/github.go b/package/gitea/source/services/migrations/github.go index 91e6b78f..952bca78 100644 --- a/package/gitea/source/services/migrations/github.go +++ b/package/gitea/source/services/migrations/github.go @@ -14,13 +14,13 @@ import ( "strings" "time" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/log" - base "code.gitea.io/gitea/modules/migration" - "code.gitea.io/gitea/modules/proxy" - "code.gitea.io/gitea/modules/structs" + "gitea.dev/modules/git" + "gitea.dev/modules/log" + base "gitea.dev/modules/migration" + "gitea.dev/modules/proxy" + "gitea.dev/modules/structs" - "github.com/google/go-github/v84/github" + "github.com/google/go-github/v88/github" "golang.org/x/oauth2" ) @@ -52,7 +52,7 @@ func (f *GithubDownloaderV3Factory) New(ctx context.Context, opts base.MigrateOp log.Trace("Create github downloader BaseURL: %s %s/%s", baseURL, oldOwner, oldName) - return NewGithubDownloaderV3(ctx, baseURL, opts.AuthUsername, opts.AuthPassword, opts.AuthToken, oldOwner, oldName), nil + return NewGithubDownloaderV3(ctx, baseURL, opts.AuthUsername, opts.AuthPassword, opts.AuthToken, oldOwner, oldName) } // GitServiceType returns the type of git service @@ -78,7 +78,7 @@ type GithubDownloaderV3 struct { } // NewGithubDownloaderV3 creates a github Downloader via github v3 API -func NewGithubDownloaderV3(_ context.Context, baseURL, userName, password, token, repoOwner, repoName string) *GithubDownloaderV3 { +func NewGithubDownloaderV3(_ context.Context, baseURL, userName, password, token, repoOwner, repoName string) (*GithubDownloaderV3, error) { downloader := GithubDownloaderV3{ userName: userName, baseURL: baseURL, @@ -102,7 +102,9 @@ func NewGithubDownloaderV3(_ context.Context, baseURL, userName, password, token }, } - downloader.addClient(client, baseURL) + if err := downloader.addClient(client, baseURL); err != nil { + return nil, err + } } } else { transport := NewMigrationHTTPTransport() @@ -113,9 +115,11 @@ func NewGithubDownloaderV3(_ context.Context, baseURL, userName, password, token client := &http.Client{ Transport: transport, } - downloader.addClient(client, baseURL) + if err := downloader.addClient(client, baseURL); err != nil { + return nil, err + } } - return &downloader + return &downloader, nil } // String implements Stringer @@ -130,25 +134,34 @@ func (g *GithubDownloaderV3) LogString() string { return fmt.Sprintf("", g.baseURL, g.repoOwner, g.repoName) } -func (g *GithubDownloaderV3) addClient(client *http.Client, baseURL string) { - githubClient := github.NewClient(client) +func (g *GithubDownloaderV3) addClient(client *http.Client, baseURL string) error { + opts := []github.ClientOptionsFunc{github.WithHTTPClient(client)} if baseURL != "https://github.com" { - githubClient, _ = githubClient.WithEnterpriseURLs(baseURL, baseURL) + opts = append(opts, github.WithEnterpriseURLs(baseURL, baseURL)) + } + githubClient, err := github.NewClient(opts...) + if err != nil { + return err } g.clients = append(g.clients, githubClient) g.rates = append(g.rates, nil) + return nil } func (g *GithubDownloaderV3) waitAndPickClient(ctx context.Context) { var recentIdx int var maxRemaining int for i := 0; i < len(g.clients); i++ { - if g.rates[i] != nil && g.rates[i].Remaining > maxRemaining { + if g.rates[i] == nil { // probe unknown clients once, else their rate never gets learned + g.curClientIdx = i + return + } + if g.rates[i].Remaining > maxRemaining { maxRemaining = g.rates[i].Remaining recentIdx = i } } - g.curClientIdx = recentIdx // if no max remain, it will always pick the first client. + g.curClientIdx = recentIdx for g.rates[g.curClientIdx] != nil && g.rates[g.curClientIdx].Remaining <= GithubLimitRateRemaining { timer := time.NewTimer(time.Until(g.rates[g.curClientIdx].Reset.Time)) @@ -205,6 +218,7 @@ func (g *GithubDownloaderV3) GetRepoInfo(ctx context.Context) (*base.Repository, Name: gr.GetName(), IsPrivate: gr.GetPrivate(), Description: gr.GetDescription(), + Website: gr.GetHomepage(), OriginalURL: gr.GetHTMLURL(), CloneURL: gr.GetCloneURL(), DefaultBranch: gr.GetDefaultBranch(), @@ -319,7 +333,7 @@ func (g *GithubDownloaderV3) convertGithubRelease(ctx context.Context, rel *gith r.Published = rel.PublishedAt.Time } - httpClient := NewMigrationHTTPClient() + httpClient := newMigrationHTTPClient() for _, asset := range rel.Assets { assetID := asset.GetID() // Don't optimize this, for closure we need a local variable TODO: no need to do so in new Golang diff --git a/package/gitea/source/services/migrations/github_test.go b/package/gitea/source/services/migrations/github_test.go index 198062f7..dab7812a 100644 --- a/package/gitea/source/services/migrations/github_test.go +++ b/package/gitea/source/services/migrations/github_test.go @@ -6,25 +6,35 @@ package migrations import ( "os" + "path/filepath" + "runtime" "testing" "time" - base "code.gitea.io/gitea/modules/migration" + "gitea.dev/models/unittest" + base "gitea.dev/modules/migration" + "github.com/google/go-github/v88/github" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestGitHubDownloadRepo(t *testing.T) { - GithubLimitRateRemaining = 3 // Wait at 3 remaining since we could have 3 CI in // token := os.Getenv("GITHUB_READ_TOKEN") - if token == "" { - t.Skip("Skipping GitHub migration test because GITHUB_READ_TOKEN is empty") - } + liveMode := token != "" + + _, callerFile, _, _ := runtime.Caller(0) + fixtureDir := filepath.Join(filepath.Dir(callerFile), "_mock_data/TestGitHubDownloadRepo") + mockServer := unittest.NewMockWebServer(t, "https://api.github.com", fixtureDir, liveMode, unittest.MockServerOptions{ + StripPrefix: "/api/v3", + }) + + GithubLimitRateRemaining = 3 // Wait at 3 remaining since we could have 3 CI in // ctx := t.Context() - downloader := NewGithubDownloaderV3(ctx, "https://github.com", "", "", token, "go-gitea", "test_repo") - err := downloader.RefreshRate(ctx) - assert.NoError(t, err) + downloader, err := NewGithubDownloaderV3(ctx, mockServer.URL, "", "", token, "go-gitea", "test_repo") + require.NoError(t, err) + err = downloader.RefreshRate(ctx) + require.NoError(t, err) repo, err := downloader.GetRepoInfo(ctx) assert.NoError(t, err) @@ -32,6 +42,7 @@ func TestGitHubDownloadRepo(t *testing.T) { Name: "test_repo", Owner: "go-gitea", Description: "Test repository for testing migration from github to gitea", + Website: "https://gitea.com/test-repo", CloneURL: "https://github.com/go-gitea/test_repo.git", OriginalURL: "https://github.com/go-gitea/test_repo", DefaultBranch: "master", @@ -47,7 +58,7 @@ func TestGitHubDownloadRepo(t *testing.T) { { Title: "1.0.0", Description: "Milestone 1.0.0", - Deadline: new(time.Date(2019, 11, 11, 8, 0, 0, 0, time.UTC)), + Deadline: new(time.Date(2019, 11, 11, 0, 0, 0, 0, time.UTC)), Created: time.Date(2019, 11, 12, 19, 37, 8, 0, time.UTC), Updated: new(time.Date(2019, 11, 12, 21, 56, 17, 0, time.UTC)), Closed: new(time.Date(2019, 11, 12, 19, 45, 49, 0, time.UTC)), @@ -56,7 +67,7 @@ func TestGitHubDownloadRepo(t *testing.T) { { Title: "1.1.0", Description: "Milestone 1.1.0", - Deadline: new(time.Date(2019, 11, 12, 8, 0, 0, 0, time.UTC)), + Deadline: new(time.Date(2019, 11, 12, 0, 0, 0, 0, time.UTC)), Created: time.Date(2019, 11, 12, 19, 37, 25, 0, time.UTC), Updated: new(time.Date(2019, 11, 12, 21, 39, 27, 0, time.UTC)), Closed: new(time.Date(2019, 11, 12, 19, 45, 46, 0, time.UTC)), @@ -269,10 +280,10 @@ func TestGitHubDownloadRepo(t *testing.T) { Description: "Improvements or additions to documentation", }, }, - PatchURL: "https://github.com/go-gitea/test_repo/pull/3.patch", + PatchURL: "", Head: base.PullRequestBranch{ Ref: "master", - CloneURL: "https://github.com/mrsdizzie/test_repo.git", + CloneURL: "", SHA: "076160cf0b039f13e5eff19619932d181269414b", RepoName: "test_repo", @@ -299,7 +310,7 @@ func TestGitHubDownloadRepo(t *testing.T) { PosterName: "mrsdizzie", State: "open", Created: time.Date(2019, 11, 12, 21, 54, 18, 0, time.UTC), - Updated: time.Date(2020, 1, 4, 11, 30, 1, 0, time.UTC), + Updated: time.Date(2025, 3, 16, 15, 46, 20, 0, time.UTC), Labels: []*base.Label{ { Name: "bug", @@ -307,13 +318,13 @@ func TestGitHubDownloadRepo(t *testing.T) { Description: "Something isn't working", }, }, - PatchURL: "https://github.com/go-gitea/test_repo/pull/4.patch", + PatchURL: "", Head: base.PullRequestBranch{ Ref: "test-branch", SHA: "2be9101c543658591222acbee3eb799edfc3853d", RepoName: "test_repo", OwnerName: "mrsdizzie", - CloneURL: "https://github.com/mrsdizzie/test_repo.git", + CloneURL: "", }, Base: base.PullRequestBranch{ Ref: "master", @@ -463,3 +474,25 @@ func TestGithubMultiToken(t *testing.T) { }) } } + +func TestGithubMultiTokenClientSelection(t *testing.T) { + downloader := &GithubDownloaderV3{ + clients: make([]*github.Client, 3), + rates: make([]*github.Rate, 3), + } + + downloader.waitAndPickClient(t.Context()) + assert.Equal(t, 0, downloader.curClientIdx) + + downloader.rates[0] = &github.Rate{Remaining: 100} + downloader.waitAndPickClient(t.Context()) + assert.Equal(t, 1, downloader.curClientIdx) + + downloader.rates[1] = &github.Rate{Remaining: 200} + downloader.waitAndPickClient(t.Context()) + assert.Equal(t, 2, downloader.curClientIdx) + + downloader.rates[2] = &github.Rate{Remaining: 50} + downloader.waitAndPickClient(t.Context()) + assert.Equal(t, 1, downloader.curClientIdx) +} diff --git a/package/gitea/source/services/migrations/gitlab.go b/package/gitea/source/services/migrations/gitlab.go index ec49049f..db04f3f3 100644 --- a/package/gitea/source/services/migrations/gitlab.go +++ b/package/gitea/source/services/migrations/gitlab.go @@ -15,14 +15,14 @@ import ( "strings" "time" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/log" - base "code.gitea.io/gitea/modules/migration" - "code.gitea.io/gitea/modules/structs" + issues_model "gitea.dev/models/issues" + "gitea.dev/models/user" + "gitea.dev/modules/container" + "gitea.dev/modules/log" + base "gitea.dev/modules/migration" + "gitea.dev/modules/structs" - gitlab "gitlab.com/gitlab-org/api/client-go" + gitlab "gitlab.com/gitlab-org/api/client-go/v2" ) var ( @@ -94,7 +94,7 @@ type GitlabDownloader struct { // Use either a username/password, personal token entered into the username field, or anonymous/public access // Note: Public access only allows very basic access func NewGitlabDownloader(ctx context.Context, baseURL, repoPath, token string) (*GitlabDownloader, error) { - gitlabClient, err := gitlab.NewClient(token, gitlab.WithBaseURL(baseURL), gitlab.WithHTTPClient(NewMigrationHTTPClient())) + gitlabClient, err := gitlab.NewClient(token, gitlab.WithBaseURL(baseURL), gitlab.WithHTTPClient(newMigrationHTTPClient())) if err != nil { log.Trace("Error logging into gitlab: %v", err) return nil, err @@ -105,7 +105,7 @@ func NewGitlabDownloader(ctx context.Context, baseURL, repoPath, token string) ( var resp *gitlab.Response u, _ := url.Parse(baseURL) for len(pathParts) >= 2 { - _, resp, err = gitlabClient.Version.GetVersion() + _, resp, err = gitlabClient.Version.GetVersion(gitlab.WithContext(ctx)) if err == nil || resp != nil && resp.StatusCode == http.StatusUnauthorized { err = nil // if no authentication given, this still should work break @@ -314,7 +314,7 @@ func (g *GitlabDownloader) convertGitlabRelease(ctx context.Context, rel *gitlab PublisherName: rel.Author.Username, } - httpClient := NewMigrationHTTPClient() + httpClient := newMigrationHTTPClient() for _, asset := range rel.Assets.Links { assetID := asset.ID // Don't optimize this, for closure we need a local variable diff --git a/package/gitea/source/services/migrations/gitlab_test.go b/package/gitea/source/services/migrations/gitlab_test.go index 1304977c..b0dbd819 100644 --- a/package/gitea/source/services/migrations/gitlab_test.go +++ b/package/gitea/source/services/migrations/gitlab_test.go @@ -4,35 +4,35 @@ package migrations import ( + "context" "fmt" "net/http" "net/http/httptest" "os" + "path/filepath" + "runtime" "strconv" "testing" "time" - "code.gitea.io/gitea/modules/json" - base "code.gitea.io/gitea/modules/migration" + "gitea.dev/models/unittest" + "gitea.dev/modules/json" + base "gitea.dev/modules/migration" "github.com/stretchr/testify/assert" - gitlab "gitlab.com/gitlab-org/api/client-go" + gitlab "gitlab.com/gitlab-org/api/client-go/v2" ) func TestGitlabDownloadRepo(t *testing.T) { - // Skip tests if Gitlab token is not found - gitlabPersonalAccessToken := os.Getenv("GITLAB_READ_TOKEN") - if gitlabPersonalAccessToken == "" { - t.Skip("skipped test because GITLAB_READ_TOKEN was not in the environment") - } + token := os.Getenv("GITLAB_READ_TOKEN") + liveMode := token != "" + + _, callerFile, _, _ := runtime.Caller(0) + fixtureDir := filepath.Join(filepath.Dir(callerFile), "_mock_data/TestGitlabDownloadRepo") + mockServer := unittest.NewMockWebServer(t, "https://gitlab.com", fixtureDir, liveMode) - resp, err := http.Get("https://gitlab.com/gitea/test_repo") - if err != nil || resp.StatusCode != http.StatusOK { - t.Skipf("Can't access test repo, skipping %s", t.Name()) - } - defer resp.Body.Close() ctx := t.Context() - downloader, err := NewGitlabDownloader(ctx, "https://gitlab.com", "gitea/test_repo", gitlabPersonalAccessToken) + downloader, err := NewGitlabDownloader(ctx, mockServer.URL, "gitea/test_repo", token) if err != nil { t.Fatalf("NewGitlabDownloader is nil: %v", err) } @@ -43,8 +43,8 @@ func TestGitlabDownloadRepo(t *testing.T) { Name: "test_repo", Owner: "", Description: "Test repository for testing migration from gitlab to gitea", - CloneURL: "https://gitlab.com/gitea/test_repo.git", - OriginalURL: "https://gitlab.com/gitea/test_repo", + CloneURL: mockServer.URL + "/gitea/test_repo.git", + OriginalURL: mockServer.URL + "/gitea/test_repo", DefaultBranch: "master", }, repo) @@ -255,51 +255,75 @@ func TestGitlabDownloadRepo(t *testing.T) { }, }, comments) - prs, _, err := downloader.GetPullRequests(ctx, 1, 1) + prs, _, err := downloader.GetPullRequests(ctx, 1, 2) assert.NoError(t, err) assertPullRequestsEqual(t, []*base.PullRequest{ { - Number: 4, - Title: "Test branch", - Content: "do not merge this PR", - Milestone: "1.0.0", - PosterID: 1241334, - PosterName: "lafriks", - State: "opened", - Created: time.Date(2019, 11, 28, 15, 56, 54, 104000000, time.UTC), - Labels: []*base.Label{ - { - Name: "bug", - }, - }, - Reactions: []*base.Reaction{{ - UserID: 4575606, - UserName: "real6543", - Content: "thumbsup", - }, { - UserID: 4575606, - UserName: "real6543", - Content: "tada", - }}, - PatchURL: "https://gitlab.com/gitea/test_repo/-/merge_requests/2.patch", + Number: 6, + Title: "Test/parsing", + Content: "This MR was created in error, feel free to delete when convenient. Sorry for the noise.", + Milestone: "", + PosterID: 10529876, + PosterName: "patdyn", + State: "closed", + Created: time.Date(2025, 11, 25, 9, 21, 42, 628000000, time.UTC), + Labels: []*base.Label{}, + Reactions: []*base.Reaction{}, + PatchURL: mockServer.URL + "/gitea/test_repo/-/merge_requests/4.patch", Head: base.PullRequestBranch{ - Ref: "feat/test", - CloneURL: "https://gitlab.com/gitea/test_repo/-/merge_requests/2", - SHA: "9f733b96b98a4175276edf6a2e1231489c3bdd23", + Ref: "test/parsing", + CloneURL: mockServer.URL + "/gitea/test_repo/-/merge_requests/4", + SHA: "c59c9b451acca9d106cc19d61d87afe3fbbb8b83", RepoName: "test_repo", - OwnerName: "lafriks", + OwnerName: "patdyn", }, Base: base.PullRequestBranch{ Ref: "master", - SHA: "", - OwnerName: "lafriks", + SHA: "c59c9b451acca9d106cc19d61d87afe3fbbb8b83", + OwnerName: "patdyn", RepoName: "test_repo", }, - Closed: nil, + Closed: new(time.Date(2025, 11, 25, 9, 43, 14, 581000000, time.UTC)), Merged: false, MergedTime: nil, MergeCommitSHA: "", - ForeignIndex: 2, + ForeignIndex: 4, + Context: gitlabIssueContext{IsMergeRequest: true}, + }, + { + Number: 5, + Title: "Test branch", + Content: "do not merge this PR", + Milestone: "", + PosterID: 2005797, + PosterName: "oliverpool", + State: "closed", + Created: time.Date(2024, 9, 3, 7, 52, 8, 78000000, time.UTC), + Labels: []*base.Label{}, + Reactions: []*base.Reaction{{ + UserID: 2005797, + UserName: "oliverpool", + Content: "thumbsup", + }}, + PatchURL: mockServer.URL + "/gitea/test_repo/-/merge_requests/3.patch", + Head: base.PullRequestBranch{ + Ref: "feat/test", + CloneURL: mockServer.URL + "/gitea/test_repo/-/merge_requests/3", + SHA: "9f733b96b98a4175276edf6a2e1231489c3bdd23", + RepoName: "test_repo", + OwnerName: "oliverpool", + }, + Base: base.PullRequestBranch{ + Ref: "master", + SHA: "c59c9b451acca9d106cc19d61d87afe3fbbb8b83", + OwnerName: "oliverpool", + RepoName: "test_repo", + }, + Closed: new(time.Date(2024, 9, 3, 7, 52, 28, 488000000, time.UTC)), + Merged: false, + MergedTime: nil, + MergeCommitSHA: "", + ForeignIndex: 3, Context: gitlabIssueContext{IsMergeRequest: true}, }, }, prs) @@ -309,16 +333,16 @@ func TestGitlabDownloadRepo(t *testing.T) { assertReviewsEqual(t, []*base.Review{ { IssueIndex: 1, - ReviewerID: 4102996, - ReviewerName: "zeripath", - CreatedAt: time.Date(2019, 11, 28, 16, 2, 8, 377000000, time.UTC), + ReviewerID: 527793, + ReviewerName: "axifive", + CreatedAt: time.Date(2019, 11, 28, 8, 54, 41, 34000000, time.UTC), State: "APPROVED", }, { IssueIndex: 1, - ReviewerID: 527793, - ReviewerName: "axifive", - CreatedAt: time.Date(2019, 11, 28, 16, 2, 8, 377000000, time.UTC), + ReviewerID: 4102996, + ReviewerName: "zeripath", + CreatedAt: time.Date(2019, 11, 28, 8, 54, 41, 34000000, time.UTC), State: "APPROVED", }, }, rvs) @@ -330,12 +354,34 @@ func TestGitlabDownloadRepo(t *testing.T) { IssueIndex: 2, ReviewerID: 4575606, ReviewerName: "real6543", - CreatedAt: time.Date(2020, 4, 19, 19, 24, 21, 108000000, time.UTC), + CreatedAt: time.Date(2019, 11, 28, 15, 56, 54, 104000000, time.UTC), State: "APPROVED", }, }, rvs) } +func TestGitlabVersionProbeUsesMigrationContext(t *testing.T) { + started := make(chan struct{}) + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + close(started) + <-r.Context().Done() + })) + defer server.Close() + + ctx, cancel := context.WithCancel(t.Context()) + defer cancel() + + result := make(chan error, 1) + go func() { + _, err := NewGitlabDownloader(ctx, server.URL, "owner/repo", "") + result <- err + }() + + <-started + cancel() + assert.Error(t, <-result) +} + func gitlabClientMockSetup(t *testing.T) (*http.ServeMux, *httptest.Server, *gitlab.Client) { // mux is the HTTP request multiplexer used with the test server. mux := http.NewServeMux() diff --git a/package/gitea/source/services/migrations/gogs.go b/package/gitea/source/services/migrations/gogs.go index a4f84dbf..7a41851e 100644 --- a/package/gitea/source/services/migrations/gogs.go +++ b/package/gitea/source/services/migrations/gogs.go @@ -11,9 +11,9 @@ import ( "strings" "time" - "code.gitea.io/gitea/modules/log" - base "code.gitea.io/gitea/modules/migration" - "code.gitea.io/gitea/modules/structs" + "gitea.dev/modules/log" + base "gitea.dev/modules/migration" + "gitea.dev/modules/structs" "github.com/gogs/go-gogs-client" ) diff --git a/package/gitea/source/services/migrations/gogs_test.go b/package/gitea/source/services/migrations/gogs_test.go index de7351b5..196be94f 100644 --- a/package/gitea/source/services/migrations/gogs_test.go +++ b/package/gitea/source/services/migrations/gogs_test.go @@ -4,32 +4,28 @@ package migrations import ( - "net/http" "os" + "path/filepath" + "runtime" "testing" "time" - base "code.gitea.io/gitea/modules/migration" + "gitea.dev/models/unittest" + base "gitea.dev/modules/migration" "github.com/stretchr/testify/assert" ) func TestGogsDownloadRepo(t *testing.T) { - // Skip tests if Gogs token is not found - gogsPersonalAccessToken := os.Getenv("GOGS_READ_TOKEN") - if len(gogsPersonalAccessToken) == 0 { - t.Skip("skipped test because GOGS_READ_TOKEN was not in the environment") - } + token := os.Getenv("GOGS_READ_TOKEN") + liveMode := token != "" + + _, callerFile, _, _ := runtime.Caller(0) + fixtureDir := filepath.Join(filepath.Dir(callerFile), "_mock_data/TestGogsDownloadRepo") + mockServer := unittest.NewMockWebServer(t, "https://try.gogs.io", fixtureDir, liveMode) - resp, err := http.Get("https://try.gogs.io/lunnytest/TESTREPO") - if err != nil || resp.StatusCode/100 != 2 { - // skip and don't run test - t.Skipf("visit test repo failed, ignored") - return - } - defer resp.Body.Close() ctx := t.Context() - downloader := NewGogsDownloader(ctx, "https://try.gogs.io", "", "", gogsPersonalAccessToken, "lunnytest", "TESTREPO") + downloader := NewGogsDownloader(ctx, mockServer.URL, "", "", token, "lunnytest", "TESTREPO") repo, err := downloader.GetRepoInfo(ctx) assert.NoError(t, err) @@ -37,8 +33,8 @@ func TestGogsDownloadRepo(t *testing.T) { Name: "TESTREPO", Owner: "lunnytest", Description: "", - CloneURL: "https://try.gogs.io/lunnytest/TESTREPO.git", - OriginalURL: "https://try.gogs.io/lunnytest/TESTREPO", + CloneURL: mockServer.URL + "/lunnytest/TESTREPO.git", + OriginalURL: mockServer.URL + "/lunnytest/TESTREPO", DefaultBranch: "master", }, repo) diff --git a/package/gitea/source/services/migrations/http_client.go b/package/gitea/source/services/migrations/http_client.go index 0b997e08..6fe7440c 100644 --- a/package/gitea/source/services/migrations/http_client.go +++ b/package/gitea/source/services/migrations/http_client.go @@ -7,23 +7,36 @@ import ( "crypto/tls" "net/http" - "code.gitea.io/gitea/modules/hostmatcher" - "code.gitea.io/gitea/modules/proxy" - "code.gitea.io/gitea/modules/setting" + "gitea.dev/modules/hostmatcher" + "gitea.dev/modules/proxy" + "gitea.dev/modules/setting" + "gitea.dev/modules/util" ) -// NewMigrationHTTPClient returns a HTTP client for migration -func NewMigrationHTTPClient() *http.Client { +// migrationHTTPClient is the shared migration client. Callers that would otherwise build a client per +// request use it (via getMigrationHTTPClient) so a single connection pool is reused across downloads — +// e.g. many release assets from the same host — instead of a fresh pool and TLS handshake each time. It +// is built lazily on first use and reset by Init whenever the allow/block lists change; OnceValue keeps +// concurrent callers sharing a single client instead of racing to create their own. +var migrationHTTPClient = util.OnceValue[*http.Client]{Func: newMigrationHTTPClient} + +// newMigrationHTTPClient returns a HTTP client for migration +func newMigrationHTTPClient() *http.Client { return &http.Client{ Transport: NewMigrationHTTPTransport(), } } -// NewMigrationHTTPTransport returns a HTTP transport for migration +// getMigrationHTTPClient returns the shared migration client, building it on first use so no request +// escapes the SSRF-validated transport even before Init has run. +func getMigrationHTTPClient() *http.Client { + return migrationHTTPClient.Value() +} + +// NewMigrationHTTPTransport returns a HTTP transport for migration. The target is validated against the +// allow/block lists on both the direct-dial and proxy paths, so a configured proxy cannot be used to +// reach an otherwise-forbidden target (SSRF). func NewMigrationHTTPTransport() *http.Transport { - return &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: setting.Migrations.SkipTLSVerify}, - Proxy: proxy.Proxy(), - DialContext: hostmatcher.NewDialContext("migration", allowList, blockList, setting.Proxy.ProxyURLFixed), - } + return hostmatcher.NewHTTPTransport("migration", allowList, blockList, proxy.Proxy(), setting.Proxy.ProxyURLFixed, + &tls.Config{InsecureSkipVerify: setting.Migrations.SkipTLSVerify}) } diff --git a/package/gitea/source/services/migrations/main_test.go b/package/gitea/source/services/migrations/main_test.go index 8c14b072..d7230165 100644 --- a/package/gitea/source/services/migrations/main_test.go +++ b/package/gitea/source/services/migrations/main_test.go @@ -8,8 +8,8 @@ import ( "testing" "time" - "code.gitea.io/gitea/models/unittest" - base "code.gitea.io/gitea/modules/migration" + "gitea.dev/models/unittest" + base "gitea.dev/modules/migration" "github.com/stretchr/testify/assert" ) @@ -25,8 +25,7 @@ func assertTimeEqual(t *testing.T, expected, actual time.Time) { func assertTimePtrEqual(t *testing.T, expected, actual *time.Time) { if expected == nil { assert.Nil(t, actual) - } else { - assert.NotNil(t, actual) + } else if assert.NotNil(t, actual) { assertTimeEqual(t, *expected, *actual) } } @@ -211,6 +210,7 @@ func assertRepositoryEqual(t *testing.T, expected, actual *base.Repository) { assert.Equal(t, expected.IsPrivate, actual.IsPrivate) assert.Equal(t, expected.IsMirror, actual.IsMirror) assert.Equal(t, expected.Description, actual.Description) + assert.Equal(t, expected.Website, actual.Website) assert.Equal(t, expected.CloneURL, actual.CloneURL) assert.Equal(t, expected.OriginalURL, actual.OriginalURL) assert.Equal(t, expected.DefaultBranch, actual.DefaultBranch) diff --git a/package/gitea/source/services/migrations/migrate.go b/package/gitea/source/services/migrations/migrate.go index 0cdd9649..b1768f04 100644 --- a/package/gitea/source/services/migrations/migrate.go +++ b/package/gitea/source/services/migrations/migrate.go @@ -13,16 +13,16 @@ import ( "path/filepath" "strings" - repo_model "code.gitea.io/gitea/models/repo" - system_model "code.gitea.io/gitea/models/system" - 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/hostmatcher" - "code.gitea.io/gitea/modules/log" - base "code.gitea.io/gitea/modules/migration" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" + repo_model "gitea.dev/models/repo" + system_model "gitea.dev/models/system" + user_model "gitea.dev/models/user" + "gitea.dev/modules/container" + "gitea.dev/modules/git" + "gitea.dev/modules/hostmatcher" + "gitea.dev/modules/log" + base "gitea.dev/modules/migration" + "gitea.dev/modules/setting" + "gitea.dev/modules/util" ) // MigrateOptions is equal to base.MigrateOptions @@ -87,15 +87,14 @@ func IsMigrateURLAllowed(remoteURL string, doer *user_model.User) error { } func checkByAllowBlockList(hostName string, addrList []net.IP) error { - var ipAllowed bool + ipAllowed := len(addrList) > 0 var ipBlocked bool for _, addr := range addrList { - ipAllowed = ipAllowed || allowList.MatchIPAddr(addr) + ipAllowed = ipAllowed && allowList.MatchIPAddr(addr) ipBlocked = ipBlocked || blockList.MatchIPAddr(addr) } - var blockedError error if blockList.MatchHostName(hostName) || ipBlocked { - blockedError = &git.ErrInvalidCloneAddr{Host: hostName, IsPermissionDenied: true} + return &git.ErrInvalidCloneAddr{Host: hostName, IsPermissionDenied: true} } // if we have an allow-list, check the allow-list before return to get the more accurate error if !allowList.IsEmpty() { @@ -104,7 +103,7 @@ func checkByAllowBlockList(hostName string, addrList []net.IP) error { } } // otherwise, we always follow the blocked list - return blockedError + return nil } // MigrateRepository migrate repository according MigrateOptions @@ -524,9 +523,14 @@ func Init() error { if setting.Migrations.AllowLocalNetworks { allowList.AppendBuiltin(hostmatcher.MatchBuiltinPrivate) allowList.AppendBuiltin(hostmatcher.MatchBuiltinLoopback) + } else { + blockList.AppendBuiltin(hostmatcher.MatchBuiltinPrivate) + blockList.AppendBuiltin(hostmatcher.MatchBuiltinLoopback) } - // TODO: at the moment, if ALLOW_LOCALNETWORKS=false, ALLOWED_DOMAINS=domain.com, and domain.com has IP 127.0.0.1, then it's still allowed. - // if we want to block such case, the private&loopback should be added to the blockList when ALLOW_LOCALNETWORKS=false + + // reset the shared client so it is rebuilt from the freshly parsed lists on next use; download paths + // then reuse one connection pool instead of creating a client (and pool) per request + migrationHTTPClient.Reset() return nil } diff --git a/package/gitea/source/services/migrations/migrate_test.go b/package/gitea/source/services/migrations/migrate_test.go index 03efa618..6903224b 100644 --- a/package/gitea/source/services/migrations/migrate_test.go +++ b/package/gitea/source/services/migrations/migrate_test.go @@ -8,9 +8,9 @@ import ( "path/filepath" "testing" - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/setting" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/modules/setting" "github.com/stretchr/testify/assert" ) @@ -93,23 +93,25 @@ func TestAllowBlockList(t *testing.T) { assert.NoError(t, checkByAllowBlockList("domain.com", []net.IP{net.ParseIP("1.2.3.4")})) assert.NoError(t, checkByAllowBlockList("domain.com", []net.IP{net.ParseIP("127.0.0.1")})) - // allow wildcard, block some subdomains. if the domain name is allowed, then the local network check is skipped + // allow wildcard, block some subdomains. every resolved address must still be allowed. init("*.domain.com", "blocked.domain.com", false) assert.NoError(t, checkByAllowBlockList("sub.domain.com", []net.IP{net.ParseIP("1.2.3.4")})) - assert.NoError(t, checkByAllowBlockList("sub.domain.com", []net.IP{net.ParseIP("127.0.0.1")})) + assert.Error(t, checkByAllowBlockList("sub.domain.com", []net.IP{net.ParseIP("127.0.0.1")})) + assert.Error(t, checkByAllowBlockList("sub.domain.com", []net.IP{net.ParseIP("1.2.3.4"), net.ParseIP("127.0.0.1")})) assert.Error(t, checkByAllowBlockList("blocked.domain.com", []net.IP{net.ParseIP("1.2.3.4")})) assert.Error(t, checkByAllowBlockList("sub.other.com", []net.IP{net.ParseIP("1.2.3.4")})) - // allow wildcard (it could lead to SSRF in production) + // allow wildcard still follows the local network policy for resolved addresses. init("*", "", false) assert.NoError(t, checkByAllowBlockList("domain.com", []net.IP{net.ParseIP("1.2.3.4")})) - assert.NoError(t, checkByAllowBlockList("domain.com", []net.IP{net.ParseIP("127.0.0.1")})) + assert.Error(t, checkByAllowBlockList("domain.com", []net.IP{net.ParseIP("127.0.0.1")})) + assert.Error(t, checkByAllowBlockList("domain.com", []net.IP{net.ParseIP("1.2.3.4"), net.ParseIP("127.0.0.1")})) // local network can still be blocked init("*", "127.0.0.*", false) assert.NoError(t, checkByAllowBlockList("domain.com", []net.IP{net.ParseIP("1.2.3.4")})) assert.Error(t, checkByAllowBlockList("domain.com", []net.IP{net.ParseIP("127.0.0.1")})) - // reset - init("", "", false) + // reset to allow local networks (mock servers use 127.0.0.1) + init("", "", true) } diff --git a/package/gitea/source/services/migrations/onedev.go b/package/gitea/source/services/migrations/onedev.go index a30e36c8..54ad5b8f 100644 --- a/package/gitea/source/services/migrations/onedev.go +++ b/package/gitea/source/services/migrations/onedev.go @@ -13,15 +13,18 @@ import ( "strings" "time" - "code.gitea.io/gitea/modules/json" - "code.gitea.io/gitea/modules/log" - base "code.gitea.io/gitea/modules/migration" - "code.gitea.io/gitea/modules/structs" + "gitea.dev/modules/json" + "gitea.dev/modules/log" + base "gitea.dev/modules/migration" + "gitea.dev/modules/structs" "github.com/hashicorp/go-version" ) -const OneDevRequiredVersion = "12.0.1" +const ( + OneDevRequiredVersion = "12.0.1" + maxOneDevVersionResponseSize = 1024 +) var ( _ base.Downloader = &OneDevDownloader{} @@ -137,10 +140,13 @@ func (d *OneDevDownloader) callAPI(ctx context.Context, endpoint string, paramet // special case to read OneDev server version, which is not valid JSON if presult, ok := result.(**version.Version); ok { - bytes, err := io.ReadAll(resp.Body) + bytes, err := io.ReadAll(io.LimitReader(resp.Body, maxOneDevVersionResponseSize+1)) if err != nil { return err } + if len(bytes) > maxOneDevVersionResponseSize { + return fmt.Errorf("OneDev server version response exceeds %d bytes", maxOneDevVersionResponseSize) + } vers, err := version.NewVersion(string(bytes)) if err != nil { return err diff --git a/package/gitea/source/services/migrations/onedev_test.go b/package/gitea/source/services/migrations/onedev_test.go index 9e93272d..eb2e4780 100644 --- a/package/gitea/source/services/migrations/onedev_test.go +++ b/package/gitea/source/services/migrations/onedev_test.go @@ -4,24 +4,45 @@ package migrations import ( + "bytes" "net/http" + "net/http/httptest" "net/url" + "os" + "path/filepath" + "runtime" "testing" "time" - base "code.gitea.io/gitea/modules/migration" + "gitea.dev/models/unittest" + base "gitea.dev/modules/migration" + "github.com/hashicorp/go-version" "github.com/stretchr/testify/assert" ) -func TestOneDevDownloadRepo(t *testing.T) { - resp, err := http.Get("https://code.onedev.io/projects/go-gitea-test_repo") - if err != nil || resp.StatusCode != http.StatusOK { - t.Skipf("Can't access test repo, skipping %s", t.Name()) - } - defer resp.Body.Close() +func TestOneDevVersionResponseSizeLimit(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write(bytes.Repeat([]byte("1"), maxOneDevVersionResponseSize+1)) + })) + defer server.Close() - u, _ := url.Parse("https://code.onedev.io") + baseURL, err := url.Parse(server.URL) + assert.NoError(t, err) + download := &OneDevDownloader{baseURL: baseURL, client: server.Client()} + var version *version.Version + err = download.callAPI(t.Context(), "/~api/version/server", nil, &version) + assert.Error(t, err) +} + +func TestOneDevDownloadRepo(t *testing.T) { + liveMode := os.Getenv("ONEDEV_LIVE") != "" + + _, callerFile, _, _ := runtime.Caller(0) + fixtureDir := filepath.Join(filepath.Dir(callerFile), "_mock_data/TestOneDevDownloadRepo") + mockServer := unittest.NewMockWebServer(t, "https://code.onedev.io", fixtureDir, liveMode) + + u, _ := url.Parse(mockServer.URL) ctx := t.Context() downloader := NewOneDevDownloader(ctx, u, "", "", "go-gitea-test_repo") repo, err := downloader.GetRepoInfo(ctx) @@ -30,8 +51,8 @@ func TestOneDevDownloadRepo(t *testing.T) { Name: "go-gitea-test_repo", Owner: "", Description: "Test repository for testing migration from OneDev to gitea", - CloneURL: "https://code.onedev.io/go-gitea-test_repo", - OriginalURL: "https://code.onedev.io/projects/go-gitea-test_repo", + CloneURL: mockServer.URL + "/go-gitea-test_repo", + OriginalURL: mockServer.URL + "/go-gitea-test_repo", }, repo) milestones, err := downloader.GetMilestones(ctx) @@ -42,10 +63,12 @@ func TestOneDevDownloadRepo(t *testing.T) { Title: "1.0.0", Deadline: &deadline, Closed: &deadline, + State: "closed", }, { Title: "1.1.0", Description: "next things?", + State: "open", }, }, milestones) @@ -101,6 +124,7 @@ func TestOneDevDownloadRepo(t *testing.T) { assertCommentsEqual(t, []*base.Comment{ { IssueIndex: 4, + PosterID: 336, PosterName: "User 336", Created: time.Unix(1628549791, 128000000), Updated: time.Unix(1628549791, 128000000), @@ -115,6 +139,7 @@ func TestOneDevDownloadRepo(t *testing.T) { Number: 5, Title: "Pull to add a new file", Content: "just do some git stuff", + PosterID: 336, PosterName: "User 336", State: "open", Created: time.Unix(1628550076, 25000000), @@ -139,6 +164,7 @@ func TestOneDevDownloadRepo(t *testing.T) { assertReviewsEqual(t, []*base.Review{ { IssueIndex: 5, + ReviewerID: 317, ReviewerName: "User 317", State: "PENDING", }, diff --git a/package/gitea/source/services/migrations/restore.go b/package/gitea/source/services/migrations/restore.go index 56862859..a07c4d96 100644 --- a/package/gitea/source/services/migrations/restore.go +++ b/package/gitea/source/services/migrations/restore.go @@ -10,9 +10,10 @@ import ( "path/filepath" "strconv" - base "code.gitea.io/gitea/modules/migration" + base "gitea.dev/modules/migration" + "gitea.dev/modules/util" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v4" ) // RepositoryRestorer implements an Downloader from the local directory @@ -75,6 +76,7 @@ func (r *RepositoryRestorer) GetRepoInfo(_ context.Context) (*base.Repository, e Name: r.repoName, IsPrivate: isPrivate, Description: opts["description"], + Website: opts["website"], OriginalURL: opts["original_url"], CloneURL: filepath.Join(r.baseDir, "git"), DefaultBranch: opts["default_branch"], @@ -143,7 +145,7 @@ func (r *RepositoryRestorer) GetReleases(_ context.Context) ([]*base.Release, er for _, rel := range releases { for _, asset := range rel.Assets { if asset.DownloadURL != nil { - *asset.DownloadURL = "file://" + filepath.Join(r.baseDir, *asset.DownloadURL) + *asset.DownloadURL = "file://" + util.FilePathJoinAbs(r.baseDir, *asset.DownloadURL) } } } @@ -234,8 +236,10 @@ func (r *RepositoryRestorer) GetPullRequests(_ context.Context, page, perPage in return nil, false, err } for _, pr := range pulls { - pr.PatchURL = "file://" + filepath.Join(r.baseDir, pr.PatchURL) - CheckAndEnsureSafePR(pr, "", r) + if pr.PatchURL != "" { + pr.PatchURL = "file://" + util.FilePathJoinAbs(r.baseDir, pr.PatchURL) + } + CheckAndEnsureSafePR(pr, "file://"+r.baseDir, r) } return pulls, true, nil } diff --git a/package/gitea/source/services/migrations/restore_test.go b/package/gitea/source/services/migrations/restore_test.go new file mode 100644 index 00000000..21cba5e3 --- /dev/null +++ b/package/gitea/source/services/migrations/restore_test.go @@ -0,0 +1,74 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package migrations + +import ( + "os" + "path/filepath" + "testing" + + "gitea.dev/modules/optional" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestRepositoryRestorer_GetReleases_LocalFileInclusion ensures a crafted +// release.yml cannot make the restorer read files outside the dump +// directory via a path-traversal DownloadURL. +func TestRepositoryRestorer_GetReleases_LocalFileInclusion(t *testing.T) { + baseDir := t.TempDir() + + // a legitimate attachment that lives inside the dump directory + require.NoError(t, os.WriteFile(filepath.Join(baseDir, "good.txt"), []byte("ok"), 0o644)) + + releaseYML := ` +- assets: + - name: good.txt + download_url: good.txt + - name: evil.txt + download_url: ../../../../../../../../etc/passwd +` + require.NoError(t, os.WriteFile(filepath.Join(baseDir, "release.yml"), []byte(releaseYML), 0o644)) + + r, err := NewRepositoryRestorer(t.Context(), baseDir, "owner", "repo", false) + require.NoError(t, err) + + releases, err := r.GetReleases(t.Context()) + require.NoError(t, err) + require.Len(t, releases, 1) + require.Len(t, releases[0].Assets, 2) + + // the in-dump asset keeps a file:// URL pointing inside baseDir + assets := releases[0].Assets + assert.Equal(t, "file://"+filepath.Join(baseDir, "good.txt"), optional.FromPtr(assets[0].DownloadURL).Value()) + assert.Equal(t, "file://"+filepath.Join(baseDir, "etc/passwd"), optional.FromPtr(assets[1].DownloadURL).Value()) +} + +func TestRepositoryRestorer_GetPullRequestsStripsUnsafeCloneURL(t *testing.T) { + baseDir := t.TempDir() + require.NoError(t, os.WriteFile(filepath.Join(baseDir, "change.patch"), []byte("patch"), 0o644)) + + pullRequestYML := ` +- number: 1 + patch_url: change.patch + head: + clone_url: http://127.0.0.1/private.git + ref: feature + base: + ref: main +` + require.NoError(t, os.WriteFile(filepath.Join(baseDir, "pull_request.yml"), []byte(pullRequestYML), 0o644)) + + r, err := NewRepositoryRestorer(t.Context(), baseDir, "owner", "repo", false) + require.NoError(t, err) + + pulls, _, err := r.GetPullRequests(t.Context(), 1, 10) + require.NoError(t, err) + require.Len(t, pulls, 1) + + assert.Equal(t, "file://"+filepath.Join(baseDir, "change.patch"), pulls[0].PatchURL) + assert.Empty(t, pulls[0].Head.CloneURL) + assert.True(t, pulls[0].EnsuredSafe) +} diff --git a/package/gitea/source/services/migrations/update.go b/package/gitea/source/services/migrations/update.go index 4a49206f..b7ecb1e2 100644 --- a/package/gitea/source/services/migrations/update.go +++ b/package/gitea/source/services/migrations/update.go @@ -6,11 +6,11 @@ package migrations import ( "context" - "code.gitea.io/gitea/models/db" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/services/externalaccount" + "gitea.dev/models/db" + user_model "gitea.dev/models/user" + "gitea.dev/modules/log" + "gitea.dev/modules/structs" + "gitea.dev/services/externalaccount" ) // UpdateMigrationPosterID updates all migrated repositories' issues and comments posterID diff --git a/package/gitea/source/services/mirror/mirror.go b/package/gitea/source/services/mirror/mirror.go index 7fb7fabb..ed3e0912 100644 --- a/package/gitea/source/services/mirror/mirror.go +++ b/package/gitea/source/services/mirror/mirror.go @@ -7,10 +7,10 @@ import ( "context" "errors" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/queue" - "code.gitea.io/gitea/modules/setting" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/log" + "gitea.dev/modules/queue" + "gitea.dev/modules/setting" ) // doMirrorSync causes this request to mirror itself diff --git a/package/gitea/source/services/mirror/mirror_pull.go b/package/gitea/source/services/mirror/mirror_pull.go index c182a645..c8330001 100644 --- a/package/gitea/source/services/mirror/mirror_pull.go +++ b/package/gitea/source/services/mirror/mirror_pull.go @@ -9,25 +9,25 @@ import ( "strings" "time" - repo_model "code.gitea.io/gitea/models/repo" - system_model "code.gitea.io/gitea/models/system" - "code.gitea.io/gitea/modules/cache" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/git/gitcmd" - giturl "code.gitea.io/gitea/modules/git/url" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/globallock" - "code.gitea.io/gitea/modules/lfs" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/process" - "code.gitea.io/gitea/modules/proxy" - repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/services/migrations" - notify_service "code.gitea.io/gitea/services/notify" - repo_service "code.gitea.io/gitea/services/repository" + repo_model "gitea.dev/models/repo" + system_model "gitea.dev/models/system" + "gitea.dev/modules/cache" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + giturl "gitea.dev/modules/git/url" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/globallock" + "gitea.dev/modules/lfs" + "gitea.dev/modules/log" + "gitea.dev/modules/process" + "gitea.dev/modules/proxy" + repo_module "gitea.dev/modules/repository" + "gitea.dev/modules/setting" + "gitea.dev/modules/timeutil" + "gitea.dev/modules/util" + "gitea.dev/services/migrations" + notify_service "gitea.dev/services/notify" + repo_service "gitea.dev/services/repository" ) // UpdateAddress writes new address to Git repository and database @@ -71,7 +71,9 @@ func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error } func pruneBrokenReferences(ctx context.Context, m *repo_model.Mirror, gitRepo gitrepo.Repository, timeout time.Duration) error { + // Never follow HTTP redirects, see cmdFetch in runSync. cmd := gitcmd.NewCommand("remote", "prune").AddDynamicArguments(m.GetRemoteName()).WithTimeout(timeout) + git.HandleGitCmdHTTPRedirection(cmd, m.GetRemoteName()) stdout, _, pruneErr := gitrepo.RunCmdString(ctx, gitRepo, cmd) if pruneErr != nil { // sanitize the output, since it may contain the remote address, which may contain a password @@ -114,12 +116,22 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*repo_module.SyncResu log.Error("SyncMirrors [repo: %-v]: GetRemoteURL Error %v", m.Repo, remoteErr) return nil, false } + // re-validate on every sync: the host may now resolve to an internal IP (rebinding) or the + // allow/block list may have changed. ssh/file are skipped (not an HTTP SSRF vector). + switch remoteURL.URL.Scheme { + case "http", "https", "git": + if allowErr := migrations.IsMigrateURLAllowed(remoteURL.String(), m.Repo.MustOwner(ctx)); allowErr != nil { + log.Error("SyncMirrors [repo: %-v]: remote URL is not allowed: %v", m.Repo, allowErr) + return nil, false + } + } envs := proxy.EnvWithProxy(remoteURL.URL) timeout := time.Duration(setting.Git.Timeout.Mirror) * time.Second // use fetch but not remote update because git fetch support --tags but remote update doesn't cmdFetch := func() *gitcmd.Command { cmd := gitcmd.NewCommand("fetch", "--tags") + git.HandleGitCmdHTTPRedirection(cmd, m.GetRemoteName()) if m.EnablePrune { cmd.AddArguments("--prune") } @@ -172,9 +184,10 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*repo_module.SyncResu if m.LFS && setting.LFS.StartServer { log.Trace("SyncMirrors [repo: %-v]: syncing LFS objects...", m.Repo) - endpoint := lfs.DetermineEndpoint(remoteURL.String(), m.LFSEndpoint) - lfsClient := lfs.NewClient(endpoint, migrations.NewMigrationHTTPTransport()) - if err = repo_module.StoreMissingLfsObjectsInRepository(ctx, m.Repo, gitRepo, lfsClient); err != nil { + lfsClient, err := lfs.NewClientFromEndpoint(remoteURL.String(), m.LFSEndpoint, migrations.NewMigrationHTTPTransport()) + if err != nil { + log.Error("SyncMirrors [repo: %-v]: failed to initialize LFS client: %v", m.Repo.FullName(), err) + } else if err = repo_module.StoreMissingLfsObjectsInRepository(ctx, m.Repo, gitRepo, lfsClient); err != nil { log.Error("SyncMirrors [repo: %-v]: failed to synchronize LFS objects for repository: %v", m.Repo.FullName(), err) } } @@ -199,8 +212,9 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*repo_module.SyncResu } cmdRemoteUpdatePrune := func() *gitcmd.Command { - return gitcmd.NewCommand("remote", "update", "--prune"). - AddDynamicArguments(m.GetRemoteName()).WithTimeout(timeout).WithEnv(envs) + cmd := gitcmd.NewCommand("remote", "update", "--prune").AddDynamicArguments(m.GetRemoteName()).WithTimeout(timeout).WithEnv(envs) + git.HandleGitCmdHTTPRedirection(cmd, m.GetRemoteName()) + return cmd } if repo_service.HasWiki(ctx, m.Repo) { @@ -289,7 +303,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { log.Error("SyncMirrors [repo_id: %v]: unable to GetMirrorByRepoID: %v", repoID, err) return false } - repo := m.GetRepository(ctx) // force load repository of mirror + m.GetRepository(ctx) // force load repository of mirror ctx, _, finished := process.GetManager().AddContext(ctx, fmt.Sprintf("Syncing Mirror %s/%s", m.Repo.OwnerName, m.Repo.Name)) defer finished() @@ -305,6 +319,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { log.Trace("SyncMirrors [repo: %-v]: Scheduling next update", m.Repo) m.ScheduleNextUpdate() + m.LastSyncUnix = m.UpdatedUnix if err = repo_model.UpdateMirror(ctx, m); err != nil { log.Error("SyncMirrors [repo: %-v]: failed to UpdateMirror with next update date: %v", m.Repo, err) return false @@ -358,41 +373,27 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { continue } - // Push commits - oldCommitID, err := gitrepo.GetFullCommitID(ctx, repo, result.OldCommitID) + oldCommitID, newCommitID := result.OldCommitID, result.NewCommitID + commits, err := gitRepo.CommitsBetween(newCommitID, oldCommitID, setting.UI.FeedMaxCommitNum) if err != nil { - log.Error("SyncMirrors [repo: %-v]: unable to get GetFullCommitID[%s]: %v", m.Repo, result.OldCommitID, err) + log.Error("SyncMirrors [repo: %-v]: unable to get CommitsBetween [new_commit_id: %s, old_commit_id: %s]: %v", m.Repo, newCommitID, oldCommitID, err) continue } - newCommitID, err := gitrepo.GetFullCommitID(ctx, repo, result.NewCommitID) - if err != nil { - log.Error("SyncMirrors [repo: %-v]: unable to get GetFullCommitID [%s]: %v", m.Repo, result.NewCommitID, err) - continue - } - commits, err := gitRepo.CommitsBetweenIDs(newCommitID, oldCommitID) - if err != nil { - log.Error("SyncMirrors [repo: %-v]: unable to get CommitsBetweenIDs [new_commit_id: %s, old_commit_id: %s]: %v", m.Repo, newCommitID, oldCommitID, err) - continue - } - theCommits := repo_module.GitToPushCommits(commits) - if len(theCommits.Commits) > setting.UI.FeedMaxCommitNum { - theCommits.Commits = theCommits.Commits[:setting.UI.FeedMaxCommitNum] - } - newCommit, err := gitRepo.GetCommit(newCommitID) + newCommit, err := gitRepo.GetCommit(newCommitID.String()) if err != nil { log.Error("SyncMirrors [repo: %-v]: unable to get commit %s: %v", m.Repo, newCommitID, err) continue } theCommits.HeadCommit = repo_module.CommitToPushCommit(newCommit) - theCommits.CompareURL = m.Repo.ComposeCompareURL(oldCommitID, newCommitID) + theCommits.CompareURL = m.Repo.ComposeCompareURL(oldCommitID.String(), newCommitID.String()) notify_service.SyncPushCommits(ctx, m.Repo.MustOwner(ctx), m.Repo, &repo_module.PushUpdateOptions{ RefFullName: result.RefName, - OldCommitID: oldCommitID, - NewCommitID: newCommitID, + OldCommitID: oldCommitID.String(), + NewCommitID: newCommitID.String(), }, theCommits) } if indexHeatmap { diff --git a/package/gitea/source/services/mirror/mirror_push.go b/package/gitea/source/services/mirror/mirror_push.go index 844e1868..5df0c8a0 100644 --- a/package/gitea/source/services/mirror/mirror_push.go +++ b/package/gitea/source/services/mirror/mirror_push.go @@ -11,20 +11,20 @@ import ( "regexp" "time" - "code.gitea.io/gitea/models/db" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/lfs" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/process" - "code.gitea.io/gitea/modules/proxy" - "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/services/migrations" - repo_service "code.gitea.io/gitea/services/repository" + "gitea.dev/models/db" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/git" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/lfs" + "gitea.dev/modules/log" + "gitea.dev/modules/process" + "gitea.dev/modules/proxy" + "gitea.dev/modules/repository" + "gitea.dev/modules/setting" + "gitea.dev/modules/timeutil" + "gitea.dev/modules/util" + "gitea.dev/services/migrations" + repo_service "gitea.dev/services/repository" ) var stripExitStatus = regexp.MustCompile(`exit status \d+ - `) @@ -144,8 +144,10 @@ func runPushSync(ctx context.Context, m *repo_model.PushMirror) error { } defer gitRepo.Close() - endpoint := lfs.DetermineEndpoint(remoteURL.String(), "") - lfsClient := lfs.NewClient(endpoint, migrations.NewMigrationHTTPTransport()) + lfsClient, err := lfs.NewClientFromEndpoint(remoteURL.String(), "", migrations.NewMigrationHTTPTransport()) + if err != nil { + return err + } if err := pushAllLFSObjects(ctx, gitRepo, lfsClient); err != nil { return util.SanitizeErrorCredentialURLs(err) } diff --git a/package/gitea/source/services/mirror/notifier.go b/package/gitea/source/services/mirror/notifier.go index 93d90447..026205ff 100644 --- a/package/gitea/source/services/mirror/notifier.go +++ b/package/gitea/source/services/mirror/notifier.go @@ -6,10 +6,10 @@ package mirror import ( "context" - repo_model "code.gitea.io/gitea/models/repo" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/repository" - notify_service "code.gitea.io/gitea/services/notify" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/repository" + notify_service "gitea.dev/services/notify" ) func init() { diff --git a/package/gitea/source/services/mirror/queue.go b/package/gitea/source/services/mirror/queue.go index ca5e2c72..49bbbf10 100644 --- a/package/gitea/source/services/mirror/queue.go +++ b/package/gitea/source/services/mirror/queue.go @@ -4,10 +4,10 @@ package mirror import ( - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/queue" - "code.gitea.io/gitea/modules/setting" + "gitea.dev/modules/graceful" + "gitea.dev/modules/log" + "gitea.dev/modules/queue" + "gitea.dev/modules/setting" ) var mirrorQueue *queue.WorkerPoolQueue[*SyncRequest] diff --git a/package/gitea/source/services/notify/notifier.go b/package/gitea/source/services/notify/notifier.go index 875a70e5..513def72 100644 --- a/package/gitea/source/services/notify/notifier.go +++ b/package/gitea/source/services/notify/notifier.go @@ -6,14 +6,14 @@ package notify import ( "context" - actions_model "code.gitea.io/gitea/models/actions" - git_model "code.gitea.io/gitea/models/git" - issues_model "code.gitea.io/gitea/models/issues" - packages_model "code.gitea.io/gitea/models/packages" - 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/repository" + actions_model "gitea.dev/models/actions" + git_model "gitea.dev/models/git" + issues_model "gitea.dev/models/issues" + packages_model "gitea.dev/models/packages" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/repository" ) // Notifier defines an interface to notify receiver @@ -45,7 +45,7 @@ type Notifier interface { NewPullRequest(ctx context.Context, pr *issues_model.PullRequest, mentions []*user_model.User) MergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) AutoMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) - PullRequestSynchronized(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) + PullRequestSynchronized(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest, before, after string) PullRequestReview(ctx context.Context, pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) PullRequestCodeComment(ctx context.Context, pr *issues_model.PullRequest, comment *issues_model.Comment, mentions []*user_model.User) PullRequestChangeTargetBranch(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest, oldBranch string) diff --git a/package/gitea/source/services/notify/notify.go b/package/gitea/source/services/notify/notify.go index 2416cbd2..b0de0b6a 100644 --- a/package/gitea/source/services/notify/notify.go +++ b/package/gitea/source/services/notify/notify.go @@ -6,15 +6,15 @@ package notify import ( "context" - actions_model "code.gitea.io/gitea/models/actions" - git_model "code.gitea.io/gitea/models/git" - issues_model "code.gitea.io/gitea/models/issues" - packages_model "code.gitea.io/gitea/models/packages" - 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/log" - "code.gitea.io/gitea/modules/repository" + actions_model "gitea.dev/models/actions" + git_model "gitea.dev/models/git" + issues_model "gitea.dev/models/issues" + packages_model "gitea.dev/models/packages" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/log" + "gitea.dev/modules/repository" ) var notifiers []Notifier @@ -120,9 +120,9 @@ func NewPullRequest(ctx context.Context, pr *issues_model.PullRequest, mentions } // PullRequestSynchronized notifies Synchronized pull request -func PullRequestSynchronized(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { +func PullRequestSynchronized(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest, before, after string) { for _, notifier := range notifiers { - notifier.PullRequestSynchronized(ctx, doer, pr) + notifier.PullRequestSynchronized(ctx, doer, pr, before, after) } } @@ -399,12 +399,18 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, commit } } +// WorkflowRunStatusUpdate dispatches a workflow run status change to every registered notifier. +// Prefer the helpers in services/actions/notify.go over calling this directly; +// unless you are sure the caller has already resolved the correct sender and paired notifications. func WorkflowRunStatusUpdate(ctx context.Context, repo *repo_model.Repository, sender *user_model.User, run *actions_model.ActionRun) { for _, notifier := range notifiers { notifier.WorkflowRunStatusUpdate(ctx, repo, sender, run) } } +// WorkflowJobStatusUpdate dispatches a workflow job status change to every registered notifier. +// Prefer the helpers in services/actions/notify.go over calling this directly; +// unless you are sure the caller has already resolved the correct sender and paired notifications. func WorkflowJobStatusUpdate(ctx context.Context, repo *repo_model.Repository, sender *user_model.User, job *actions_model.ActionRunJob, task *actions_model.ActionTask) { for _, notifier := range notifiers { notifier.WorkflowJobStatusUpdate(ctx, repo, sender, job, task) diff --git a/package/gitea/source/services/notify/null.go b/package/gitea/source/services/notify/null.go index c3085d7c..2ff1869c 100644 --- a/package/gitea/source/services/notify/null.go +++ b/package/gitea/source/services/notify/null.go @@ -6,14 +6,14 @@ package notify import ( "context" - actions_model "code.gitea.io/gitea/models/actions" - git_model "code.gitea.io/gitea/models/git" - issues_model "code.gitea.io/gitea/models/issues" - packages_model "code.gitea.io/gitea/models/packages" - 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/repository" + actions_model "gitea.dev/models/actions" + git_model "gitea.dev/models/git" + issues_model "gitea.dev/models/issues" + packages_model "gitea.dev/models/packages" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/repository" ) // NullNotifier implements a blank notifier @@ -63,7 +63,7 @@ func (*NullNotifier) AutoMergePullRequest(ctx context.Context, doer *user_model. } // PullRequestSynchronized places a place holder function -func (*NullNotifier) PullRequestSynchronized(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { +func (*NullNotifier) PullRequestSynchronized(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest, before, after string) { } // PullRequestChangeTargetBranch places a place holder function diff --git a/package/gitea/source/services/oauth2_provider/access_token.go b/package/gitea/source/services/oauth2_provider/access_token.go index 3a77c86d..a577085e 100644 --- a/package/gitea/source/services/oauth2_provider/access_token.go +++ b/package/gitea/source/services/oauth2_provider/access_token.go @@ -10,15 +10,15 @@ import ( "strconv" "strings" - auth "code.gitea.io/gitea/models/auth" - "code.gitea.io/gitea/models/db" - org_model "code.gitea.io/gitea/models/organization" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/util" + auth "gitea.dev/models/auth" + "gitea.dev/models/db" + org_model "gitea.dev/models/organization" + user_model "gitea.dev/models/user" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" + api "gitea.dev/modules/structs" + "gitea.dev/modules/timeutil" + "gitea.dev/modules/util" "github.com/golang-jwt/jwt/v5" ) diff --git a/package/gitea/source/services/oauth2_provider/init.go b/package/gitea/source/services/oauth2_provider/init.go index c412bd64..d325dc89 100644 --- a/package/gitea/source/services/oauth2_provider/init.go +++ b/package/gitea/source/services/oauth2_provider/init.go @@ -6,7 +6,7 @@ package oauth2_provider import ( "context" - "code.gitea.io/gitea/modules/setting" + "gitea.dev/modules/setting" ) // Init initializes the oauth source diff --git a/package/gitea/source/services/oauth2_provider/jwtsigningkey.go b/package/gitea/source/services/oauth2_provider/jwtsigningkey.go index 4898d541..7ce37c5e 100644 --- a/package/gitea/source/services/oauth2_provider/jwtsigningkey.go +++ b/package/gitea/source/services/oauth2_provider/jwtsigningkey.go @@ -18,9 +18,9 @@ import ( "path/filepath" "strings" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" + "gitea.dev/modules/util" "github.com/golang-jwt/jwt/v5" ) diff --git a/package/gitea/source/services/oauth2_provider/token.go b/package/gitea/source/services/oauth2_provider/token.go index 935c4cc0..499865a9 100644 --- a/package/gitea/source/services/oauth2_provider/token.go +++ b/package/gitea/source/services/oauth2_provider/token.go @@ -8,7 +8,7 @@ import ( "fmt" "time" - "code.gitea.io/gitea/modules/timeutil" + "gitea.dev/modules/timeutil" "github.com/golang-jwt/jwt/v5" ) diff --git a/package/gitea/source/services/org/org.go b/package/gitea/source/services/org/org.go index 629b5acc..7ab8493a 100644 --- a/package/gitea/source/services/org/org.go +++ b/package/gitea/source/services/org/org.go @@ -7,20 +7,20 @@ import ( "context" "fmt" - actions_model "code.gitea.io/gitea/models/actions" - activities_model "code.gitea.io/gitea/models/activities" - "code.gitea.io/gitea/models/db" - org_model "code.gitea.io/gitea/models/organization" - packages_model "code.gitea.io/gitea/models/packages" - access_model "code.gitea.io/gitea/models/perm/access" - repo_model "code.gitea.io/gitea/models/repo" - secret_model "code.gitea.io/gitea/models/secret" - user_model "code.gitea.io/gitea/models/user" - issue_indexer "code.gitea.io/gitea/modules/indexer/issues" - "code.gitea.io/gitea/modules/storage" - "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" - repo_service "code.gitea.io/gitea/services/repository" + actions_model "gitea.dev/models/actions" + activities_model "gitea.dev/models/activities" + "gitea.dev/models/db" + org_model "gitea.dev/models/organization" + packages_model "gitea.dev/models/packages" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + secret_model "gitea.dev/models/secret" + user_model "gitea.dev/models/user" + issue_indexer "gitea.dev/modules/indexer/issues" + "gitea.dev/modules/storage" + "gitea.dev/modules/structs" + "gitea.dev/modules/util" + repo_service "gitea.dev/services/repository" ) // deleteOrganization deletes models associated to an organization. @@ -39,6 +39,7 @@ func deleteOrganization(ctx context.Context, org *org_model.Organization) error &user_model.Blocking{BlockerID: org.ID}, &actions_model.ActionRunner{OwnerID: org.ID}, &actions_model.ActionRunnerToken{OwnerID: org.ID}, + &actions_model.ActionScopedWorkflowSource{OwnerID: org.ID}, ); err != nil { return fmt.Errorf("DeleteBeans: %w", err) } @@ -119,9 +120,14 @@ func updateRepoForVisibilityChanged(ctx context.Context, repo *repo_model.Reposi return err } + // the repo is no longer publicly visible, so drop stars and watches from users who can no longer + // see it, matching the direct repository-private transition (see services/repository) if err := repo_model.ClearRepoStars(ctx, repo.ID); err != nil { return err } + if err := repo_model.ClearRepoWatches(ctx, repo.ID); err != nil { + return err + } } // Create/Remove git-daemon-export-ok for git-daemon... diff --git a/package/gitea/source/services/org/org_test.go b/package/gitea/source/services/org/org_test.go index 9c0aa163..2f30db32 100644 --- a/package/gitea/source/services/org/org_test.go +++ b/package/gitea/source/services/org/org_test.go @@ -6,12 +6,12 @@ package org import ( "testing" - "code.gitea.io/gitea/models/organization" - 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/structs" - "code.gitea.io/gitea/modules/util" + "gitea.dev/models/organization" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/modules/structs" + "gitea.dev/modules/util" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -68,4 +68,23 @@ func TestOrg(t *testing.T) { require.NoError(t, ChangeOrganizationVisibility(t.Context(), org, structs.VisibleTypePrivate)) unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: org.ID, Visibility: structs.VisibleTypePrivate}) }) + + t.Run("ChangeVisibilityClearsWatchesAndStars", func(t *testing.T) { + // org3 is a public organization owning the public repo32 + org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) + require.Equal(t, structs.VisibleTypePublic, org.Visibility) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 32, OwnerID: org.ID}) + + // an outside user watches and stars the repo while the org is still visible + watcher := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) + require.NoError(t, repo_model.WatchRepo(t.Context(), watcher, repo, true)) + require.NoError(t, repo_model.StarRepo(t.Context(), watcher, repo, true)) + unittest.AssertExistsAndLoadBean(t, &repo_model.Watch{UserID: watcher.ID, RepoID: repo.ID}) + + require.NoError(t, ChangeOrganizationVisibility(t.Context(), org, structs.VisibleTypePrivate)) + + // making the org private must drop watches, not only stars, from users who can no longer see it + unittest.AssertNotExistsBean(t, &repo_model.Watch{UserID: watcher.ID, RepoID: repo.ID}) + unittest.AssertNotExistsBean(t, &repo_model.Star{UID: watcher.ID, RepoID: repo.ID}) + }) } diff --git a/package/gitea/source/services/org/team.go b/package/gitea/source/services/org/team.go index 6c92ee4f..b0793133 100644 --- a/package/gitea/source/services/org/team.go +++ b/package/gitea/source/services/org/team.go @@ -9,18 +9,18 @@ import ( "fmt" "strings" - "code.gitea.io/gitea/models/db" - git_model "code.gitea.io/gitea/models/git" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/organization" - 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/graceful" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" - repo_service "code.gitea.io/gitea/services/repository" + "gitea.dev/models/db" + git_model "gitea.dev/models/git" + issues_model "gitea.dev/models/issues" + "gitea.dev/models/organization" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/graceful" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" + "gitea.dev/modules/util" + repo_service "gitea.dev/services/repository" "xorm.io/builder" ) @@ -110,7 +110,7 @@ func UpdateTeam(ctx context.Context, t *organization.Team, authChanged, includeA sess := db.GetEngine(ctx) if _, err = sess.ID(t.ID).Cols("name", "lower_name", "description", - "can_create_org_repo", "authorize", "includes_all_repositories").Update(t); err != nil { + "can_create_org_repo", "authorize", "includes_all_repositories", "visibility").Update(t); err != nil { return fmt.Errorf("update: %w", err) } diff --git a/package/gitea/source/services/org/team_invite.go b/package/gitea/source/services/org/team_invite.go index 3f28044d..a326c7df 100644 --- a/package/gitea/source/services/org/team_invite.go +++ b/package/gitea/source/services/org/team_invite.go @@ -6,9 +6,9 @@ package org import ( "context" - org_model "code.gitea.io/gitea/models/organization" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/services/mailer" + org_model "gitea.dev/models/organization" + user_model "gitea.dev/models/user" + "gitea.dev/services/mailer" ) // CreateTeamInvite make a persistent invite in db and mail it diff --git a/package/gitea/source/services/org/team_test.go b/package/gitea/source/services/org/team_test.go index 5cb588b7..5275c377 100644 --- a/package/gitea/source/services/org/team_test.go +++ b/package/gitea/source/services/org/team_test.go @@ -8,15 +8,15 @@ import ( "strings" "testing" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/organization" - "code.gitea.io/gitea/models/perm" - access_model "code.gitea.io/gitea/models/perm/access" - 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/structs" - repo_service "code.gitea.io/gitea/services/repository" + issues_model "gitea.dev/models/issues" + "gitea.dev/models/organization" + "gitea.dev/models/perm" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/modules/structs" + repo_service "gitea.dev/services/repository" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/org/user.go b/package/gitea/source/services/org/user.go index 68582718..754ffa44 100644 --- a/package/gitea/source/services/org/user.go +++ b/package/gitea/source/services/org/user.go @@ -8,11 +8,11 @@ import ( "context" "fmt" - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/organization" - 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" + "gitea.dev/models/db" + "gitea.dev/models/organization" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" ) // RemoveOrgUser removes user from given organization. diff --git a/package/gitea/source/services/org/user_test.go b/package/gitea/source/services/org/user_test.go index 3df9d533..17d94ba6 100644 --- a/package/gitea/source/services/org/user_test.go +++ b/package/gitea/source/services/org/user_test.go @@ -6,9 +6,9 @@ package org import ( "testing" - "code.gitea.io/gitea/models/organization" - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" + "gitea.dev/models/organization" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/packages/alpine/repository.go b/package/gitea/source/services/packages/alpine/repository.go index 277c1888..146e9e4a 100644 --- a/package/gitea/source/services/packages/alpine/repository.go +++ b/package/gitea/source/services/packages/alpine/repository.go @@ -20,15 +20,15 @@ import ( "io" "strings" - packages_model "code.gitea.io/gitea/models/packages" - alpine_model "code.gitea.io/gitea/models/packages/alpine" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/json" - packages_module "code.gitea.io/gitea/modules/packages" - alpine_module "code.gitea.io/gitea/modules/packages/alpine" - "code.gitea.io/gitea/modules/util" - packages_service "code.gitea.io/gitea/services/packages" + packages_model "gitea.dev/models/packages" + alpine_model "gitea.dev/models/packages/alpine" + user_model "gitea.dev/models/user" + "gitea.dev/modules/container" + "gitea.dev/modules/json" + packages_module "gitea.dev/modules/packages" + alpine_module "gitea.dev/modules/packages/alpine" + "gitea.dev/modules/util" + packages_service "gitea.dev/services/packages" ) const ( diff --git a/package/gitea/source/services/packages/arch/repository.go b/package/gitea/source/services/packages/arch/repository.go index 3a22db1b..1943c5f2 100644 --- a/package/gitea/source/services/packages/arch/repository.go +++ b/package/gitea/source/services/packages/arch/repository.go @@ -13,19 +13,20 @@ import ( "fmt" "io" "os" + "slices" "strconv" "strings" - packages_model "code.gitea.io/gitea/models/packages" - arch_model "code.gitea.io/gitea/models/packages/arch" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/globallock" - "code.gitea.io/gitea/modules/json" - packages_module "code.gitea.io/gitea/modules/packages" - arch_module "code.gitea.io/gitea/modules/packages/arch" - "code.gitea.io/gitea/modules/util" - packages_service "code.gitea.io/gitea/services/packages" + packages_model "gitea.dev/models/packages" + arch_model "gitea.dev/models/packages/arch" + user_model "gitea.dev/models/user" + "gitea.dev/modules/container" + "gitea.dev/modules/globallock" + "gitea.dev/modules/json" + packages_module "gitea.dev/modules/packages" + arch_module "gitea.dev/modules/packages/arch" + "gitea.dev/modules/util" + packages_service "gitea.dev/services/packages" "github.com/ProtonMail/go-crypto/openpgp" "github.com/ProtonMail/go-crypto/openpgp/armor" @@ -360,9 +361,16 @@ type keyValue struct { Value string } +// pacman parses the index line by line, so a value with a newline could forge extra fields +func joinFields(values []string) string { + return strings.Join(slices.DeleteFunc(slices.Clone(values), func(value string) bool { + return strings.ContainsAny(value, "\n\r") + }), "\n") +} + func writeFiles(tw *tar.Writer, opts *entryOptions) error { return writeFields(tw, fmt.Sprintf("%s-%s/files", opts.Package.Name, opts.Version.Version), []keyValue{ - {"FILES", strings.Join(opts.FileMetadata.Files, "\n")}, + {"FILES", joinFields(opts.FileMetadata.Files)}, }) } @@ -381,17 +389,17 @@ func writeDescription(tw *tar.Writer, opts *entryOptions) error { {"VERSION", opts.Version.Version}, {"DESC", opts.VersionMetadata.Description}, {"URL", opts.VersionMetadata.ProjectURL}, - {"LICENSE", strings.Join(opts.VersionMetadata.Licenses, "\n")}, - {"GROUPS", strings.Join(opts.FileMetadata.Groups, "\n")}, + {"LICENSE", joinFields(opts.VersionMetadata.Licenses)}, + {"GROUPS", joinFields(opts.FileMetadata.Groups)}, {"BUILDDATE", strconv.FormatInt(opts.FileMetadata.BuildDate, 10)}, {"PACKAGER", opts.FileMetadata.Packager}, - {"PROVIDES", strings.Join(opts.FileMetadata.Provides, "\n")}, - {"REPLACES", strings.Join(opts.FileMetadata.Replaces, "\n")}, - {"CONFLICTS", strings.Join(opts.FileMetadata.Conflicts, "\n")}, - {"DEPENDS", strings.Join(opts.FileMetadata.Depends, "\n")}, - {"OPTDEPENDS", strings.Join(opts.FileMetadata.OptDepends, "\n")}, - {"MAKEDEPENDS", strings.Join(opts.FileMetadata.MakeDepends, "\n")}, - {"CHECKDEPENDS", strings.Join(opts.FileMetadata.CheckDepends, "\n")}, + {"PROVIDES", joinFields(opts.FileMetadata.Provides)}, + {"REPLACES", joinFields(opts.FileMetadata.Replaces)}, + {"CONFLICTS", joinFields(opts.FileMetadata.Conflicts)}, + {"DEPENDS", joinFields(opts.FileMetadata.Depends)}, + {"OPTDEPENDS", joinFields(opts.FileMetadata.OptDepends)}, + {"MAKEDEPENDS", joinFields(opts.FileMetadata.MakeDepends)}, + {"CHECKDEPENDS", joinFields(opts.FileMetadata.CheckDepends)}, }) } diff --git a/package/gitea/source/services/packages/arch/repository_test.go b/package/gitea/source/services/packages/arch/repository_test.go new file mode 100644 index 00000000..f2d2a322 --- /dev/null +++ b/package/gitea/source/services/packages/arch/repository_test.go @@ -0,0 +1,17 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package arch + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestJoinFields(t *testing.T) { + values := []string{"usr/bin/a", "usr/bin/b\n\n%FILES%\netc/cron.d/x", "usr/bin/c"} + + assert.Equal(t, "usr/bin/a\nusr/bin/c", joinFields(values)) + assert.Len(t, values, 3) // must not modify the caller's slice +} diff --git a/package/gitea/source/services/packages/auth.go b/package/gitea/source/services/packages/auth.go index dd1f68a7..d0099ffb 100644 --- a/package/gitea/source/services/packages/auth.go +++ b/package/gitea/source/services/packages/auth.go @@ -10,10 +10,10 @@ import ( "strings" "time" - auth_model "code.gitea.io/gitea/models/auth" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" + auth_model "gitea.dev/models/auth" + user_model "gitea.dev/models/user" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" "github.com/golang-jwt/jwt/v5" ) diff --git a/package/gitea/source/services/packages/cargo/index.go b/package/gitea/source/services/packages/cargo/index.go index 580d84eb..dd95e300 100644 --- a/package/gitea/source/services/packages/cargo/index.go +++ b/package/gitea/source/services/packages/cargo/index.go @@ -12,17 +12,17 @@ import ( "path" "strconv" - packages_model "code.gitea.io/gitea/models/packages" - 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/json" - cargo_module "code.gitea.io/gitea/modules/packages/cargo" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" - repo_service "code.gitea.io/gitea/services/repository" - files_service "code.gitea.io/gitea/services/repository/files" + packages_model "gitea.dev/models/packages" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/json" + cargo_module "gitea.dev/modules/packages/cargo" + "gitea.dev/modules/setting" + "gitea.dev/modules/structs" + "gitea.dev/modules/util" + repo_service "gitea.dev/services/repository" + files_service "gitea.dev/services/repository/files" ) const ( diff --git a/package/gitea/source/services/packages/cleanup/cleanup.go b/package/gitea/source/services/packages/cleanup/cleanup.go index 5cff16fe..3c3424c7 100644 --- a/package/gitea/source/services/packages/cleanup/cleanup.go +++ b/package/gitea/source/services/packages/cleanup/cleanup.go @@ -8,19 +8,19 @@ import ( "fmt" "time" - "code.gitea.io/gitea/models/db" - packages_model "code.gitea.io/gitea/models/packages" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/optional" - packages_module "code.gitea.io/gitea/modules/packages" - packages_service "code.gitea.io/gitea/services/packages" - alpine_service "code.gitea.io/gitea/services/packages/alpine" - arch_service "code.gitea.io/gitea/services/packages/arch" - cargo_service "code.gitea.io/gitea/services/packages/cargo" - container_service "code.gitea.io/gitea/services/packages/container" - debian_service "code.gitea.io/gitea/services/packages/debian" - rpm_service "code.gitea.io/gitea/services/packages/rpm" + "gitea.dev/models/db" + packages_model "gitea.dev/models/packages" + user_model "gitea.dev/models/user" + "gitea.dev/modules/log" + "gitea.dev/modules/optional" + packages_module "gitea.dev/modules/packages" + packages_service "gitea.dev/services/packages" + alpine_service "gitea.dev/services/packages/alpine" + arch_service "gitea.dev/services/packages/arch" + cargo_service "gitea.dev/services/packages/cargo" + container_service "gitea.dev/services/packages/container" + debian_service "gitea.dev/services/packages/debian" + rpm_service "gitea.dev/services/packages/rpm" ) // CleanupTask executes cleanup rules and cleanup expired package data diff --git a/package/gitea/source/services/packages/container/blob_uploader.go b/package/gitea/source/services/packages/container/blob_uploader.go index d2df2c81..8b6e55d5 100644 --- a/package/gitea/source/services/packages/container/blob_uploader.go +++ b/package/gitea/source/services/packages/container/blob_uploader.go @@ -9,10 +9,10 @@ import ( "io" "os" - packages_model "code.gitea.io/gitea/models/packages" - packages_module "code.gitea.io/gitea/modules/packages" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/tempdir" + packages_model "gitea.dev/models/packages" + packages_module "gitea.dev/modules/packages" + "gitea.dev/modules/setting" + "gitea.dev/modules/tempdir" ) var ( diff --git a/package/gitea/source/services/packages/container/cleanup.go b/package/gitea/source/services/packages/container/cleanup.go index 263562a3..7aab4769 100644 --- a/package/gitea/source/services/packages/container/cleanup.go +++ b/package/gitea/source/services/packages/container/cleanup.go @@ -7,11 +7,11 @@ import ( "context" "time" - packages_model "code.gitea.io/gitea/models/packages" - container_model "code.gitea.io/gitea/models/packages/container" - "code.gitea.io/gitea/modules/optional" - container_module "code.gitea.io/gitea/modules/packages/container" - packages_service "code.gitea.io/gitea/services/packages" + packages_model "gitea.dev/models/packages" + container_model "gitea.dev/models/packages/container" + "gitea.dev/modules/optional" + container_module "gitea.dev/modules/packages/container" + packages_service "gitea.dev/services/packages" "github.com/opencontainers/go-digest" ) diff --git a/package/gitea/source/services/packages/container/common.go b/package/gitea/source/services/packages/container/common.go index d3e2996a..c359794d 100644 --- a/package/gitea/source/services/packages/container/common.go +++ b/package/gitea/source/services/packages/container/common.go @@ -8,12 +8,12 @@ import ( "io" "strings" - packages_model "code.gitea.io/gitea/models/packages" - container_service "code.gitea.io/gitea/models/packages/container" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/json" - "code.gitea.io/gitea/modules/packages" - container_module "code.gitea.io/gitea/modules/packages/container" + packages_model "gitea.dev/models/packages" + container_service "gitea.dev/models/packages/container" + user_model "gitea.dev/models/user" + "gitea.dev/modules/json" + "gitea.dev/modules/packages" + container_module "gitea.dev/modules/packages/container" v1 "github.com/opencontainers/image-spec/specs-go/v1" ) diff --git a/package/gitea/source/services/packages/debian/repository.go b/package/gitea/source/services/packages/debian/repository.go index 910f93b0..7073d44e 100644 --- a/package/gitea/source/services/packages/debian/repository.go +++ b/package/gitea/source/services/packages/debian/repository.go @@ -15,14 +15,14 @@ import ( "strings" "time" - packages_model "code.gitea.io/gitea/models/packages" - debian_model "code.gitea.io/gitea/models/packages/debian" - user_model "code.gitea.io/gitea/models/user" - packages_module "code.gitea.io/gitea/modules/packages" - debian_module "code.gitea.io/gitea/modules/packages/debian" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" - packages_service "code.gitea.io/gitea/services/packages" + packages_model "gitea.dev/models/packages" + debian_model "gitea.dev/models/packages/debian" + user_model "gitea.dev/models/user" + packages_module "gitea.dev/modules/packages" + debian_module "gitea.dev/modules/packages/debian" + "gitea.dev/modules/setting" + "gitea.dev/modules/util" + packages_service "gitea.dev/services/packages" "github.com/ProtonMail/go-crypto/openpgp" "github.com/ProtonMail/go-crypto/openpgp/armor" diff --git a/package/gitea/source/services/packages/package_update.go b/package/gitea/source/services/packages/package_update.go index d0ec43b7..880d0fd9 100644 --- a/package/gitea/source/services/packages/package_update.go +++ b/package/gitea/source/services/packages/package_update.go @@ -7,13 +7,13 @@ import ( "context" "fmt" - org_model "code.gitea.io/gitea/models/organization" - packages_model "code.gitea.io/gitea/models/packages" - access_model "code.gitea.io/gitea/models/perm/access" - 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/util" + org_model "gitea.dev/models/organization" + packages_model "gitea.dev/models/packages" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unit" + user_model "gitea.dev/models/user" + "gitea.dev/modules/util" ) func LinkToRepository(ctx context.Context, pkg *packages_model.Package, repo *repo_model.Repository, doer *user_model.User) error { diff --git a/package/gitea/source/services/packages/packages.go b/package/gitea/source/services/packages/packages.go index cf86592c..abd4b4c5 100644 --- a/package/gitea/source/services/packages/packages.go +++ b/package/gitea/source/services/packages/packages.go @@ -13,18 +13,18 @@ import ( "net/url" "strings" - "code.gitea.io/gitea/models/db" - packages_model "code.gitea.io/gitea/models/packages" - repo_model "code.gitea.io/gitea/models/repo" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/globallock" - "code.gitea.io/gitea/modules/json" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/optional" - packages_module "code.gitea.io/gitea/modules/packages" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/storage" - notify_service "code.gitea.io/gitea/services/notify" + "gitea.dev/models/db" + packages_model "gitea.dev/models/packages" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/globallock" + "gitea.dev/modules/json" + "gitea.dev/modules/log" + "gitea.dev/modules/optional" + packages_module "gitea.dev/modules/packages" + "gitea.dev/modules/setting" + "gitea.dev/modules/storage" + notify_service "gitea.dev/services/notify" ) var ( diff --git a/package/gitea/source/services/packages/pkgspec/manager.go b/package/gitea/source/services/packages/pkgspec/manager.go index d2f33e0d..97c672a4 100644 --- a/package/gitea/source/services/packages/pkgspec/manager.go +++ b/package/gitea/source/services/packages/pkgspec/manager.go @@ -4,9 +4,9 @@ package pkgspec import ( - packages_model "code.gitea.io/gitea/models/packages" - packages_service "code.gitea.io/gitea/services/packages" - "code.gitea.io/gitea/services/packages/terraform" + packages_model "gitea.dev/models/packages" + packages_service "gitea.dev/services/packages" + "gitea.dev/services/packages/terraform" ) func InitManager() error { diff --git a/package/gitea/source/services/packages/rpm/repository.go b/package/gitea/source/services/packages/rpm/repository.go index ddf306b6..5ea08bf0 100644 --- a/package/gitea/source/services/packages/rpm/repository.go +++ b/package/gitea/source/services/packages/rpm/repository.go @@ -17,14 +17,14 @@ import ( "strings" "time" - packages_model "code.gitea.io/gitea/models/packages" - rpm_model "code.gitea.io/gitea/models/packages/rpm" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/json" - packages_module "code.gitea.io/gitea/modules/packages" - rpm_module "code.gitea.io/gitea/modules/packages/rpm" - "code.gitea.io/gitea/modules/util" - packages_service "code.gitea.io/gitea/services/packages" + packages_model "gitea.dev/models/packages" + rpm_model "gitea.dev/models/packages/rpm" + user_model "gitea.dev/models/user" + "gitea.dev/modules/json" + packages_module "gitea.dev/modules/packages" + rpm_module "gitea.dev/modules/packages/rpm" + "gitea.dev/modules/util" + packages_service "gitea.dev/services/packages" "github.com/ProtonMail/go-crypto/openpgp" "github.com/ProtonMail/go-crypto/openpgp/armor" diff --git a/package/gitea/source/services/packages/rpm/sign.go b/package/gitea/source/services/packages/rpm/sign.go index 820355a6..e12c4a97 100644 --- a/package/gitea/source/services/packages/rpm/sign.go +++ b/package/gitea/source/services/packages/rpm/sign.go @@ -8,7 +8,7 @@ import ( "io" "strings" - packages_module "code.gitea.io/gitea/modules/packages" + packages_module "gitea.dev/modules/packages" "github.com/ProtonMail/go-crypto/openpgp" "github.com/sassoftware/go-rpmutils" diff --git a/package/gitea/source/services/packages/spec.go b/package/gitea/source/services/packages/spec.go index 0815bdc9..3d5888e2 100644 --- a/package/gitea/source/services/packages/spec.go +++ b/package/gitea/source/services/packages/spec.go @@ -7,8 +7,8 @@ import ( "context" "sync" - packages_model "code.gitea.io/gitea/models/packages" - user_model "code.gitea.io/gitea/models/user" + packages_model "gitea.dev/models/packages" + user_model "gitea.dev/models/user" ) type nop struct{} diff --git a/package/gitea/source/services/packages/terraform/spec.go b/package/gitea/source/services/packages/terraform/spec.go index 982f29fb..0aabbb36 100644 --- a/package/gitea/source/services/packages/terraform/spec.go +++ b/package/gitea/source/services/packages/terraform/spec.go @@ -6,12 +6,12 @@ package terraform import ( "context" - packages_model "code.gitea.io/gitea/models/packages" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/optional" - terraform_module "code.gitea.io/gitea/modules/packages/terraform" - "code.gitea.io/gitea/modules/util" - packages_service "code.gitea.io/gitea/services/packages" + packages_model "gitea.dev/models/packages" + user_model "gitea.dev/models/user" + "gitea.dev/modules/optional" + terraform_module "gitea.dev/modules/packages/terraform" + "gitea.dev/modules/util" + packages_service "gitea.dev/services/packages" ) type Specialization struct{} diff --git a/package/gitea/source/services/packages/terraform/state.go b/package/gitea/source/services/packages/terraform/state.go index cdd6f0c5..d3d860e0 100644 --- a/package/gitea/source/services/packages/terraform/state.go +++ b/package/gitea/source/services/packages/terraform/state.go @@ -6,9 +6,9 @@ package terraform import ( "context" - packages_model "code.gitea.io/gitea/models/packages" - "code.gitea.io/gitea/modules/optional" - terraform_module "code.gitea.io/gitea/modules/packages/terraform" + packages_model "gitea.dev/models/packages" + "gitea.dev/modules/optional" + terraform_module "gitea.dev/modules/packages/terraform" ) // IsLocked is a helper function to check if the terraform state is locked diff --git a/package/gitea/source/services/projects/issue.go b/package/gitea/source/services/projects/issue.go index ece9910c..ad9abe9d 100644 --- a/package/gitea/source/services/projects/issue.go +++ b/package/gitea/source/services/projects/issue.go @@ -9,12 +9,13 @@ import ( "slices" "strings" - "code.gitea.io/gitea/models/db" - issues_model "code.gitea.io/gitea/models/issues" - project_model "code.gitea.io/gitea/models/project" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/optional" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + project_model "gitea.dev/models/project" + user_model "gitea.dev/models/user" + "gitea.dev/modules/optional" + + "xorm.io/builder" ) // MoveIssuesOnProjectColumn moves or keeps issues in a column and sorts them inside that column @@ -59,11 +60,13 @@ func MoveIssuesOnProjectColumn(ctx context.Context, doer *user_model.User, colum continue } - projectColumnID, err := curIssue.ProjectColumnID(ctx) + projectColumnMap, err := curIssue.ProjectColumnMap(ctx) if err != nil { return err } + projectColumnID := projectColumnMap[column.ProjectID] + if projectColumnID != column.ID { // add timeline to issue if _, err := issues_model.CreateComment(ctx, &issues_model.CreateCommentOptions{ @@ -80,7 +83,16 @@ func MoveIssuesOnProjectColumn(ctx context.Context, doer *user_model.User, colum } } - _, err = db.Exec(ctx, "UPDATE `project_issue` SET project_board_id=?, sorting=? WHERE issue_id=?", column.ID, sorting, issueID) + // Update the column and sorting for this specific issue in this specific project. + // IMPORTANT: The WHERE clause must include both issue_id AND project_id to ensure + // that moving an issue's column in one project doesn't affect its column in other + // projects when the issue is assigned to multiple projects. + _, err = db.GetEngine(ctx).Table("project_issue"). + Where("issue_id = ? AND project_id = ?", issueID, column.ProjectID). + Update(map[string]any{ + "project_board_id": column.ID, + "sorting": sorting, + }) if err != nil { return err } @@ -89,35 +101,22 @@ func MoveIssuesOnProjectColumn(ctx context.Context, doer *user_model.User, colum }) } -func LoadIssuesAssigneesForProject(ctx context.Context, issuesMap map[int64]issues_model.IssueList) ([]*user_model.User, error) { - var issueList issues_model.IssueList - for _, colIssues := range issuesMap { - issueList = append(issueList, colIssues...) - } - err := issueList.LoadAssignees(ctx) +func LoadIssuesAssigneesForProject(ctx context.Context, projectID int64) (users []*user_model.User, _ error) { + sub := builder.Select("distinct issue_assignees.assignee_id"). + From("project_issue").Join("INNER", "issue_assignees", "project_issue.issue_id=issue_assignees.issue_id"). + Where(builder.Eq{"project_issue.project_id": projectID}) + err := db.GetEngine(ctx).Table("`user`").Where(builder.In("id", sub)).Find(&users) if err != nil { return nil, err } - users := make([]*user_model.User, 0, len(issueList)) - usersAdded := container.Set[int64]{} - for _, issue := range issueList { - for _, assignee := range issue.Assignees { - if !usersAdded.Contains(assignee.ID) { - usersAdded.Add(assignee.ID) - users = append(users, assignee) - } - } - } - slices.SortFunc(users, func(a, b *user_model.User) int { - return strings.Compare(a.Name, b.Name) - }) + slices.SortFunc(users, func(a, b *user_model.User) int { return strings.Compare(a.Name, b.Name) }) return users, nil } // LoadIssuesFromProject load issues assigned to each project column inside the given project func LoadIssuesFromProject(ctx context.Context, project *project_model.Project, opts *issues_model.IssuesOptions) (results map[int64]issues_model.IssueList, _ error) { issueList, err := issues_model.Issues(ctx, opts.Copy(func(o *issues_model.IssuesOptions) { - o.ProjectID = project.ID + o.ProjectIDs = []int64{project.ID} o.SortType = "project-column-sorting" })) if err != nil { @@ -211,10 +210,10 @@ func LoadIssueNumbersForProject(ctx context.Context, project *project_model.Proj // for user or org projects, we need to check access permissions opts := issues_model.IssuesOptions{ - ProjectID: project.ID, - Doer: doer, - AllPublic: doer == nil, - Owner: project.Owner, + ProjectIDs: []int64{project.ID}, + Doer: doer, + AllPublic: doer == nil, + Owner: project.Owner, } var err error diff --git a/package/gitea/source/services/projects/issue_test.go b/package/gitea/source/services/projects/issue_test.go index 17d0fef2..7f353ca5 100644 --- a/package/gitea/source/services/projects/issue_test.go +++ b/package/gitea/source/services/projects/issue_test.go @@ -6,16 +6,15 @@ package project import ( "testing" - "code.gitea.io/gitea/models/db" - issues_model "code.gitea.io/gitea/models/issues" - org_model "code.gitea.io/gitea/models/organization" - project_model "code.gitea.io/gitea/models/project" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + org_model "gitea.dev/models/organization" + project_model "gitea.dev/models/project" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func Test_Projects(t *testing.T) { @@ -25,6 +24,9 @@ func Test_Projects(t *testing.T) { user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) org3 := unittest.AssertExistsAndLoadBean(t, &org_model.Organization{ID: 3}) user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) + // user15 is on org3's team7 (write access to the public repo32 only), so it can see org3 public repos + // but has no access to the private repo3 — a genuine "no permission to the private repo" org member. + user15 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}) t.Run("User projects", func(t *testing.T) { pi1 := project_model.ProjectIssue{ @@ -102,28 +104,18 @@ func Test_Projects(t *testing.T) { assert.NoError(t, err) }() - column1 := project_model.Column{ - Title: "column 1", - ProjectID: project1.ID, - } - err = project_model.NewColumn(t.Context(), &column1) - assert.NoError(t, err) - - column2 := project_model.Column{ - Title: "column 2", - ProjectID: project1.ID, - } - err = project_model.NewColumn(t.Context(), &column2) + // Get the default column created by the template (issues will be assigned here) + defaultColumn, err := project1.MustDefaultColumn(t.Context()) assert.NoError(t, err) // issue 6 belongs to private repo 3 under org 3 issue6 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 6}) - err = issues_model.IssueAssignOrRemoveProject(t.Context(), issue6, user2, project1.ID, column1.ID) + err = issues_model.IssueAssignOrRemoveProject(t.Context(), issue6, user2, []int64{project1.ID}) assert.NoError(t, err) // issue 16 belongs to public repo 16 under org 3 issue16 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 16}) - err = issues_model.IssueAssignOrRemoveProject(t.Context(), issue16, user2, project1.ID, column1.ID) + err = issues_model.IssueAssignOrRemoveProject(t.Context(), issue16, user2, []int64{project1.ID}) assert.NoError(t, err) projects, err := db.Find[project_model.Project](t.Context(), project_model.SearchOptions{ @@ -139,8 +131,8 @@ func Test_Projects(t *testing.T) { Doer: userAdmin, }) assert.NoError(t, err) - assert.Len(t, columnIssues, 1) // column1 has 2 issues, 6 will not contains here because 0 issues - assert.Len(t, columnIssues[column1.ID], 2) // user2 can visit both issues, one from public repository one from private repository + assert.Len(t, columnIssues, 1) // default column has 2 issues + assert.Len(t, columnIssues[defaultColumn.ID], 2) // admin can visit both issues, one from public repository one from private repository }) t.Run("Anonymous user", func(t *testing.T) { @@ -149,17 +141,31 @@ func Test_Projects(t *testing.T) { }) assert.NoError(t, err) assert.Len(t, columnIssues, 1) - assert.Len(t, columnIssues[column1.ID], 1) // anonymous user can only visit public repo issues + assert.Len(t, columnIssues[defaultColumn.ID], 1) // anonymous user can only visit public repo issues }) t.Run("Authenticated user with no permission to the private repo", func(t *testing.T) { + // user2 is on org3's Owners team and has owner access to the private repo3, so it is not a + // valid "no permission" subject; user15 has no access to repo3 but can see the public repo32. + columnIssues, err := LoadIssuesFromProject(t.Context(), projects[0], &issues_model.IssuesOptions{ + Owner: org3.AsUser(), + Doer: user15, + }) + assert.NoError(t, err) + assert.Len(t, columnIssues, 1) + assert.Len(t, columnIssues[defaultColumn.ID], 1) // user15 can only visit public repo issues + }) + + t.Run("Org owner team member", func(t *testing.T) { + // user2 is on org3's Owners team, so it has access to the private repo3 and must see both the + // public and the private issue — the owner-team access that team.authorize grants at runtime. columnIssues, err := LoadIssuesFromProject(t.Context(), projects[0], &issues_model.IssuesOptions{ Owner: org3.AsUser(), Doer: user2, }) assert.NoError(t, err) assert.Len(t, columnIssues, 1) - assert.Len(t, columnIssues[column1.ID], 1) // user4 can only visit public repo issues + assert.Len(t, columnIssues[defaultColumn.ID], 2) // owner-team member visits both public and private issues }) }) @@ -208,18 +214,4 @@ func Test_Projects(t *testing.T) { assert.Len(t, columnIssues[3], 1) }) }) - - t.Run("LoadIssuesAssigneesForProject", func(t *testing.T) { - issuesMap := map[int64]issues_model.IssueList{} - issue1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}) - issue6 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 6}) - issuesMap[1] = issues_model.IssueList{issue1} - issuesMap[2] = issues_model.IssueList{issue6} - assignees, err := LoadIssuesAssigneesForProject(t.Context(), issuesMap) - require.NoError(t, err) - require.Len(t, assignees, 3) - require.Equal(t, "user1", assignees[0].Name) - require.Equal(t, "user10", assignees[1].Name) - require.Equal(t, "user2", assignees[2].Name) - }) } diff --git a/package/gitea/source/services/projects/main_test.go b/package/gitea/source/services/projects/main_test.go index d39c82a1..c30b34f4 100644 --- a/package/gitea/source/services/projects/main_test.go +++ b/package/gitea/source/services/projects/main_test.go @@ -6,10 +6,10 @@ package project import ( "testing" - "code.gitea.io/gitea/models/unittest" + "gitea.dev/models/unittest" - _ "code.gitea.io/gitea/models/actions" - _ "code.gitea.io/gitea/models/activities" + _ "gitea.dev/models/actions" + _ "gitea.dev/models/activities" ) func TestMain(m *testing.M) { diff --git a/package/gitea/source/services/pull/check.go b/package/gitea/source/services/pull/check.go index f39f042c..145eff5d 100644 --- a/package/gitea/source/services/pull/check.go +++ b/package/gitea/source/services/pull/check.go @@ -11,41 +11,42 @@ import ( "strings" "time" - "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" - "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" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/git/gitcmd" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/globallock" - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/process" - "code.gitea.io/gitea/modules/queue" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/timeutil" - asymkey_service "code.gitea.io/gitea/services/asymkey" - "code.gitea.io/gitea/services/automergequeue" - notify_service "code.gitea.io/gitea/services/notify" + "gitea.dev/models/db" + git_model "gitea.dev/models/git" + issues_model "gitea.dev/models/issues" + access_model "gitea.dev/models/perm/access" + "gitea.dev/models/pull" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unit" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/globallock" + "gitea.dev/modules/graceful" + "gitea.dev/modules/log" + "gitea.dev/modules/process" + "gitea.dev/modules/queue" + "gitea.dev/modules/setting" + "gitea.dev/modules/timeutil" + asymkey_service "gitea.dev/services/asymkey" + "gitea.dev/services/automergequeue" + notify_service "gitea.dev/services/notify" ) // prPatchCheckerQueue represents a queue to handle update pull request tests var prPatchCheckerQueue *queue.WorkerPoolQueue[string] var ( - ErrIsClosed = errors.New("pull is closed") - ErrNoPermissionToMerge = errors.New("no permission to merge") - ErrNotReadyToMerge = errors.New("not ready to merge") - 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") - ErrNotMergeableState = errors.New("not in mergeable state") - ErrDependenciesLeft = errors.New("is blocked by an open dependency") + ErrIsClosed = errors.New("pull is closed") + ErrNoPermissionToMerge = errors.New("no permission to merge") + ErrNotReadyToMerge = errors.New("not ready to merge") + 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") + ErrNotMergeableState = errors.New("not in mergeable state") + ErrDependenciesLeft = errors.New("is blocked by an open dependency") + ErrHeadCommitsNotAllVerified = errors.New("the branch requires signed commits but not all head commits are verified") ) func markPullRequestStatusAsChecking(ctx context.Context, pr *issues_model.PullRequest) bool { @@ -132,7 +133,13 @@ const ( ) // 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, adminForceMerge bool) error { +// mergeStyle tailors the "require signed commits" prechecks: +// - fast-forward-only: no Gitea commit is produced, so Gitea's merge-signing check is skipped; +// only the user's head commits are verified. +// - merge: both the head commits must be verified and Gitea must sign the merge commit. +// - rebase, rebase-merge, squash: Gitea rewrites the commits and signs each, so only Gitea's +// signing ability is checked. +func CheckPullMergeable(stdCtx context.Context, doer *user_model.User, perm *access_model.Permission, pr *issues_model.PullRequest, mergeCheckType MergeCheckType, mergeStyle repo_model.MergeStyle, forceMerge bool) error { return db.WithTx(stdCtx, func(ctx context.Context) error { if pr.HasMerged { return ErrHasMerged @@ -161,7 +168,7 @@ func CheckPullMergeable(stdCtx context.Context, doer *user_model.User, perm *acc return ErrIsWorkInProgress } - if !pr.CanAutoMerge() && !pr.IsEmpty() { + if !pr.IsStatusMergeable() && !pr.IsEmpty() { return ErrNotMergeableState } @@ -169,21 +176,21 @@ func CheckPullMergeable(stdCtx context.Context, doer *user_model.User, perm *acc return ErrIsChecking } - if err := CheckPullBranchProtections(ctx, pr, false); err != nil { - if !errors.Is(err, ErrNotReadyToMerge) { - log.Error("Error whilst checking pull branch protection for %-v: %v", pr, err) - return err + if errProtection := CheckPullBranchProtections(ctx, pr, false); errProtection != nil { + if !errors.Is(errProtection, ErrNotReadyToMerge) { + log.Error("Error whilst checking pull branch protection for %-v: %v", pr, errProtection) + return errProtection } // Now the branch protection check failed, check whether the failure could be skipped (skip by setting err = nil) // * when doing Auto Merge (Scheduled Merge After Checks Succeed), skip the branch protection check if mergeCheckType == MergeCheckTypeAuto { - err = nil + errProtection = nil } - // * if admin tries to "Force Merge", they could sometimes skip the branch protection check - if adminForceMerge { + // * if the doer tries to "Force Merge", check whether it is really allowed + if forceMerge { isRepoAdmin, errForceMerge := access_model.IsUserRepoAdmin(ctx, pr.BaseRepo, doer) if errForceMerge != nil { return fmt.Errorf("IsUserRepoAdmin failed, repo: %v, doer: %v, err: %w", pr.BaseRepoID, doer.ID, errForceMerge) @@ -194,20 +201,22 @@ func CheckPullMergeable(stdCtx context.Context, doer *user_model.User, perm *acc return fmt.Errorf("GetFirstMatchProtectedBranchRule failed, repo: %v, base branch: %v, err: %w", pr.BaseRepoID, pr.BaseBranch, errForceMerge) } - // if doer is admin and the "Force Merge" is not blocked, then clear the branch protection check error - blockAdminForceMerge := protectedBranchRule != nil && protectedBranchRule.BlockAdminMergeOverride - if isRepoAdmin && !blockAdminForceMerge { - err = nil + canForceMerge := isRepoAdmin + if protectedBranchRule != nil { + canForceMerge = git_model.CanBypassBranchProtection(ctx, protectedBranchRule, doer, isRepoAdmin) + } + if canForceMerge { + errProtection = nil } } // If there is still a branch protection check error, return it - if err != nil { - return err + if errProtection != nil { + return errProtection } } - if _, err := isSignedIfRequired(ctx, pr, doer); err != nil { + if err := checkSigningRequirements(ctx, pr, doer, mergeStyle); err != nil { return err } @@ -221,26 +230,45 @@ func CheckPullMergeable(stdCtx context.Context, doer *user_model.User, perm *acc }) } -// isSignedIfRequired check if merge will be signed if required -func isSignedIfRequired(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User) (bool, error) { +// checkSigningRequirements enforces the target branch's RequireSignedCommits rule +// against the selected merge style: +// - fast-forward-only and merge keep the user's commits on the base branch, so +// those commits must all be verified, or the pre-receive hook will reject the +// push with a generic error. +// - fast-forward-only creates no Gitea commit, so Gitea's signing key is not used. +// - merge, rebase, rebase-merge and squash produce a Gitea-signed commit, so +// Gitea must be configured to sign it. +func checkSigningRequirements(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User, mergeStyle repo_model.MergeStyle) error { pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, pr.BaseBranch) if err != nil { - return false, err + return err } - if pb == nil || !pb.RequireSignedCommits { - return true, nil + return nil } gitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, pr.BaseRepo) if err != nil { - return false, err + return err } defer closer.Close() - sign, _, _, err := asymkey_service.SignMerge(ctx, pr, doer, gitRepo) + if mergeStyle == repo_model.MergeStyleFastForwardOnly || mergeStyle == repo_model.MergeStyleMerge { + verified, err := asymkey_service.AllHeadCommitsVerified(ctx, pr, gitRepo) + if err != nil { + return err + } + if !verified { + return ErrHeadCommitsNotAllVerified + } + } - return sign, err + if mergeStyle != repo_model.MergeStyleFastForwardOnly { + if _, _, _, err := asymkey_service.SignMerge(ctx, pr, doer, gitRepo, pr.BaseBranch, pr.GetGitHeadRefName()); err != nil { + return err + } + } + return nil } // markPullRequestAsMergeable checks if pull request is possible to leaving checking status, diff --git a/package/gitea/source/services/pull/check_test.go b/package/gitea/source/services/pull/check_test.go index 0f392379..ad4ade83 100644 --- a/package/gitea/source/services/pull/check_test.go +++ b/package/gitea/source/services/pull/check_test.go @@ -8,17 +8,18 @@ import ( "testing" "time" - "code.gitea.io/gitea/models/db" - issues_model "code.gitea.io/gitea/models/issues" - "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/graceful" - "code.gitea.io/gitea/modules/queue" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/test" - "code.gitea.io/gitea/services/automergequeue" + "gitea.dev/models/db" + git_model "gitea.dev/models/git" + issues_model "gitea.dev/models/issues" + "gitea.dev/models/pull" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/modules/graceful" + "gitea.dev/modules/queue" + "gitea.dev/modules/setting" + "gitea.dev/modules/test" + "gitea.dev/services/automergequeue" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -73,6 +74,39 @@ func TestPullRequest_AddToTaskQueue(t *testing.T) { prPatchCheckerQueue = nil } +func TestCheckSigningRequirementsHeadCommits(t *testing.T) { + require.NoError(t, unittest.PrepareTestDatabase()) + ctx := t.Context() + + pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}) + require.NoError(t, pr.LoadBaseRepo(ctx)) + require.NoError(t, pr.LoadHeadRepo(ctx)) + + check := func() error { + return checkSigningRequirements(ctx, pr, nil, repo_model.MergeStyleFastForwardOnly) + } + + // No protected branch rule on the base branch: the check must pass. + require.NoError(t, check()) + + // Protected branch without RequireSignedCommits: the check must still pass. + require.NoError(t, git_model.UpdateProtectBranch(ctx, pr.BaseRepo, &git_model.ProtectedBranch{ + RepoID: pr.BaseRepoID, + RuleName: pr.BaseBranch, + RequireSignedCommits: false, + }, git_model.WhitelistOptions{})) + require.NoError(t, check()) + + // With RequireSignedCommits enabled: the test fixture commits have no signatures, + // so the check must report ErrHeadCommitsNotAllVerified. + pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, pr.BaseBranch) + require.NoError(t, err) + require.NotNil(t, pb) + pb.RequireSignedCommits = true + require.NoError(t, git_model.UpdateProtectBranch(ctx, pr.BaseRepo, pb, git_model.WhitelistOptions{})) + require.ErrorIs(t, check(), ErrHeadCommitsNotAllVerified) +} + func TestMarkPullRequestAsMergeable(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) diff --git a/package/gitea/source/services/pull/comment.go b/package/gitea/source/services/pull/comment.go index 1d055a0c..7cbd84b7 100644 --- a/package/gitea/source/services/pull/comment.go +++ b/package/gitea/source/services/pull/comment.go @@ -7,14 +7,14 @@ import ( "context" "slices" - "code.gitea.io/gitea/models/db" - issues_model "code.gitea.io/gitea/models/issues" - 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/gitrepo" - "code.gitea.io/gitea/modules/json" - "code.gitea.io/gitea/modules/log" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + user_model "gitea.dev/models/user" + "gitea.dev/modules/container" + "gitea.dev/modules/git" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/json" + "gitea.dev/modules/log" ) const maxPushCommitsInCommentCount = 1000 diff --git a/package/gitea/source/services/pull/comment_test.go b/package/gitea/source/services/pull/comment_test.go index 975aec66..3d5b995e 100644 --- a/package/gitea/source/services/pull/comment_test.go +++ b/package/gitea/source/services/pull/comment_test.go @@ -6,13 +6,13 @@ package pull import ( "testing" - "code.gitea.io/gitea/models/db" - issues_model "code.gitea.io/gitea/models/issues" - "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/json" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/json" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/package/gitea/source/services/pull/commit_status.go b/package/gitea/source/services/pull/commit_status.go index 656bcc50..9a2e7b84 100644 --- a/package/gitea/source/services/pull/commit_status.go +++ b/package/gitea/source/services/pull/commit_status.go @@ -8,14 +8,18 @@ import ( "context" "errors" "fmt" + "slices" - "code.gitea.io/gitea/models/db" - git_model "code.gitea.io/gitea/models/git" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/modules/commitstatus" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/glob" - "code.gitea.io/gitea/modules/log" + actions_model "gitea.dev/models/actions" + "gitea.dev/models/db" + git_model "gitea.dev/models/git" + issues_model "gitea.dev/models/issues" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/commitstatus" + "gitea.dev/modules/container" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/glob" + "gitea.dev/modules/log" ) // MergeRequiredContextsCommitStatus returns a commit status state for given required contexts @@ -69,11 +73,25 @@ func MergeRequiredContextsCommitStatus(commitStatuses []*git_model.CommitStatus, func IsPullCommitStatusPass(ctx context.Context, pr *issues_model.PullRequest) (bool, error) { pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, pr.BaseBranch) if err != nil { - return false, fmt.Errorf("GetLatestCommitStatus: %w", err) + return false, fmt.Errorf("GetFirstMatchProtectedBranchRule: %w", err) } - if pb == nil || !pb.EnableStatusCheck { + if pb == nil { return true, nil } + if !pb.EnableStatusCheck { + // The branch's own status check is off, but required scoped checks (mandated by the owner or instance admin) still gate the merge. + if err := pr.LoadBaseRepo(ctx); err != nil { + return false, err + } + required, err := EffectiveRequiredContexts(ctx, pr.BaseRepo, pb) + if err != nil { + return false, err + } + if len(required) == 0 { + // With none in effect there is nothing to enforce, so don't block + return true, nil + } + } state, err := GetPullRequestCommitStatusState(ctx, pr) if err != nil { @@ -130,10 +148,54 @@ func GetPullRequestCommitStatusState(ctx context.Context, pr *issues_model.PullR if err != nil { return "", fmt.Errorf("LoadProtectedBranch: %w", err) } - var requiredContexts []string - if pb != nil { - requiredContexts = pb.StatusCheckContexts + requiredContexts, err := EffectiveRequiredContexts(ctx, pr.BaseRepo, pb) + if err != nil { + return "", err } return MergeRequiredContextsCommitStatus(commitStatuses, requiredContexts), nil } + +// EffectiveRequiredContexts returns the required status-check contexts to enforce, drawn from: +// 1. every required scoped workflow's status-check patterns effective for the repo (always) +// 2. each given protected branch rule's own configured contexts, only when that rule's status check is enabled +// +// Passing no rule or a single nil rule yields nothing, not even scoped patterns. +// A single rule yields that rule's effective contexts. +// Passing several rules unions their effective contexts; this is used when the governing rule is not yet known. +func EffectiveRequiredContexts(ctx context.Context, repo *repo_model.Repository, pbs ...*git_model.ProtectedBranch) ([]string, error) { + // No protection rule in effect: nothing is required. + if len(pbs) == 0 || (len(pbs) == 1 && pbs[0] == nil) { + return nil, nil + } + + sources, err := actions_model.GetEffectiveScopedWorkflowSources(ctx, repo.OwnerID) + if err != nil { + return nil, fmt.Errorf("GetEffectiveScopedWorkflowSources: %w", err) + } + + required := make(container.Set[string]) + + // Every required scoped workflow's admin-authored status-check patterns, matched must-present-and-pass: + // a required scoped check that posts no matching status blocks the merge. + for _, source := range sources { + for _, cfg := range source.WorkflowConfigs { + if !cfg.Required { + continue + } + required.AddMultiple(cfg.Patterns...) + } + } + + // Union the configured contexts of every rule whose own status check is enabled (a disabled rule contributes none) + for _, pb := range pbs { + if pb == nil || !pb.EnableStatusCheck { + continue + } + required.AddMultiple(pb.StatusCheckContexts...) + } + + values := required.Values() + slices.Sort(values) // stable output + return values, nil +} diff --git a/package/gitea/source/services/pull/commit_status_test.go b/package/gitea/source/services/pull/commit_status_test.go index a58e788c..20889a76 100644 --- a/package/gitea/source/services/pull/commit_status_test.go +++ b/package/gitea/source/services/pull/commit_status_test.go @@ -7,10 +7,15 @@ package pull import ( "testing" - git_model "code.gitea.io/gitea/models/git" - "code.gitea.io/gitea/modules/commitstatus" + actions_model "gitea.dev/models/actions" + "gitea.dev/models/db" + git_model "gitea.dev/models/git" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + "gitea.dev/modules/commitstatus" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestMergeRequiredContextsCommitStatus(t *testing.T) { @@ -90,3 +95,72 @@ func TestMergeRequiredContextsCommitStatus(t *testing.T) { assert.Equal(t, c.expected, MergeRequiredContextsCommitStatus(c.commitStatuses, c.requiredContexts), "case %d", i) } } + +// TestEffectiveRequiredContexts: every required scoped workflow's stored status-check patterns are appended to the +// branch protection's configured contexts unconditionally (must-present; the matching is done downstream). +func TestEffectiveRequiredContexts(t *testing.T) { + require.NoError(t, unittest.PrepareTestDatabase()) + consumer := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) // owned by user5 + pbOn := &git_model.ProtectedBranch{EnableStatusCheck: true, StatusCheckContexts: []string{"configured/check"}} + + t.Run("nil protected branch: nil", func(t *testing.T) { + got, err := EffectiveRequiredContexts(t.Context(), consumer, nil) + require.NoError(t, err) + assert.Nil(t, got) + }) + + t.Run("status checks disabled, no required scoped: nothing required", func(t *testing.T) { + pbOff := &git_model.ProtectedBranch{EnableStatusCheck: false, StatusCheckContexts: []string{"configured/check"}} + got, err := EffectiveRequiredContexts(t.Context(), consumer, pbOff) + require.NoError(t, err) + assert.Empty(t, got) // the rule's own status check is off and no required scoped workflow applies -> nothing gates + }) + + t.Run("owner with no scoped sources: configured contexts unchanged", func(t *testing.T) { + noSourceRepo := &repo_model.Repository{ID: consumer.ID, OwnerID: 99999} + got, err := EffectiveRequiredContexts(t.Context(), noSourceRepo, pbOn) + require.NoError(t, err) + assert.Equal(t, []string{"configured/check"}, got) + }) + + t.Run("required workflow patterns appended", func(t *testing.T) { + require.NoError(t, db.Insert(t.Context(), &actions_model.ActionScopedWorkflowSource{ + OwnerID: consumer.OwnerID, + SourceRepoID: 1, + WorkflowConfigs: map[string]*actions_model.ScopedWorkflowConfig{ + "ci.yaml": {Required: true, Patterns: []string{"org/src: ci.yaml / build (pull_request)", "org/src: ci.yaml / lint (pull_request)"}}, + "old.yaml": {Required: false, Patterns: []string{"org/src: old.yaml / *"}}, // kept as history, must NOT be enforced + }, + })) + // No status is passed/needed: required patterns are enforced even though nothing has posted them yet (must-present). + got, err := EffectiveRequiredContexts(t.Context(), consumer, pbOn) + require.NoError(t, err) + assert.ElementsMatch(t, []string{ + "configured/check", + "org/src: ci.yaml / build (pull_request)", + "org/src: ci.yaml / lint (pull_request)", + }, got) + assert.NotContains(t, got, "org/src: old.yaml / *", "a non-required (history) config must not be enforced") + }) + + t.Run("status checks disabled, with required scoped: only the scoped patterns gate", func(t *testing.T) { + pbOff := &git_model.ProtectedBranch{EnableStatusCheck: false, StatusCheckContexts: []string{"configured/check"}} + got, err := EffectiveRequiredContexts(t.Context(), consumer, pbOff) + require.NoError(t, err) + // "configured/check" is dropped (the rule's own status check is off); only the required scoped patterns remain. + assert.ElementsMatch(t, []string{ + "org/src: ci.yaml / build (pull_request)", + "org/src: ci.yaml / lint (pull_request)", + }, got) + }) + + t.Run("several rules union their enabled contexts, deduplicated; a disabled rule contributes none", func(t *testing.T) { + noSourceRepo := &repo_model.Repository{ID: consumer.ID, OwnerID: 99999} // no scoped sources, so only the rules' contexts gate + a := &git_model.ProtectedBranch{EnableStatusCheck: true, StatusCheckContexts: []string{"a/check", "shared/check"}} + b := &git_model.ProtectedBranch{EnableStatusCheck: true, StatusCheckContexts: []string{"b/check", "shared/check"}} + off := &git_model.ProtectedBranch{EnableStatusCheck: false, StatusCheckContexts: []string{"off/check"}} + got, err := EffectiveRequiredContexts(t.Context(), noSourceRepo, a, b, off) + require.NoError(t, err) + assert.ElementsMatch(t, []string{"a/check", "b/check", "shared/check"}, got) + }) +} diff --git a/package/gitea/source/services/pull/edits.go b/package/gitea/source/services/pull/edits.go index 193e385d..6c9ee10c 100644 --- a/package/gitea/source/services/pull/edits.go +++ b/package/gitea/source/services/pull/edits.go @@ -8,10 +8,10 @@ import ( "context" "errors" - issues_model "code.gitea.io/gitea/models/issues" - access_model "code.gitea.io/gitea/models/perm/access" - unit_model "code.gitea.io/gitea/models/unit" - user_model "code.gitea.io/gitea/models/user" + issues_model "gitea.dev/models/issues" + access_model "gitea.dev/models/perm/access" + unit_model "gitea.dev/models/unit" + user_model "gitea.dev/models/user" ) var ErrUserHasNoPermissionForAction = errors.New("user not allowed to do this action") diff --git a/package/gitea/source/services/pull/lfs.go b/package/gitea/source/services/pull/lfs.go index 094b563b..34d811a3 100644 --- a/package/gitea/source/services/pull/lfs.go +++ b/package/gitea/source/services/pull/lfs.go @@ -11,13 +11,13 @@ import ( "io" "strconv" - git_model "code.gitea.io/gitea/models/git" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/modules/git/gitcmd" - "code.gitea.io/gitea/modules/git/pipeline" - "code.gitea.io/gitea/modules/lfs" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/util" + git_model "gitea.dev/models/git" + issues_model "gitea.dev/models/issues" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/git/pipeline" + "gitea.dev/modules/lfs" + "gitea.dev/modules/log" + "gitea.dev/modules/util" "golang.org/x/sync/errgroup" ) diff --git a/package/gitea/source/services/pull/main_test.go b/package/gitea/source/services/pull/main_test.go index efbb63a3..b73c7073 100644 --- a/package/gitea/source/services/pull/main_test.go +++ b/package/gitea/source/services/pull/main_test.go @@ -7,9 +7,9 @@ package pull import ( "testing" - "code.gitea.io/gitea/models/unittest" + "gitea.dev/models/unittest" - _ "code.gitea.io/gitea/models/actions" + _ "gitea.dev/models/actions" ) func TestMain(m *testing.M) { diff --git a/package/gitea/source/services/pull/merge.go b/package/gitea/source/services/pull/merge.go index 1137296c..6f46ab89 100644 --- a/package/gitea/source/services/pull/merge.go +++ b/package/gitea/source/services/pull/merge.go @@ -16,27 +16,28 @@ import ( "strings" "unicode" - "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" - "code.gitea.io/gitea/models/unit" - 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/git/gitcmd" - "code.gitea.io/gitea/modules/globallock" - "code.gitea.io/gitea/modules/httplib" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/references" - repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/util" - issue_service "code.gitea.io/gitea/services/issue" - notify_service "code.gitea.io/gitea/services/notify" + "gitea.dev/models/db" + git_model "gitea.dev/models/git" + issues_model "gitea.dev/models/issues" + access_model "gitea.dev/models/perm/access" + pull_model "gitea.dev/models/pull" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unit" + user_model "gitea.dev/models/user" + "gitea.dev/modules/cache" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/globallock" + "gitea.dev/modules/graceful" + "gitea.dev/modules/httplib" + "gitea.dev/modules/log" + "gitea.dev/modules/references" + repo_module "gitea.dev/modules/repository" + "gitea.dev/modules/setting" + "gitea.dev/modules/timeutil" + "gitea.dev/modules/util" + issue_service "gitea.dev/services/issue" + notify_service "gitea.dev/services/notify" ) // getMergeMessage composes the message used when merging a pull request. @@ -218,9 +219,28 @@ func (err ErrInvalidMergeStyle) Unwrap() error { return util.ErrInvalidArgument } +func addTestPullRequestTaskAfterWebOperation(pr *issues_model.PullRequest, doer *user_model.User) { + // This is a duplicated call to AddTestPullRequestTask (it will also be called by the post-receive hook, via a push queue). + // This call will do some operations (push to base repo, sync commit divergence, add PR conflict check queue task, etc) + // immediately instead of waiting for the "push queue"'s task. The code is from https://github.com/go-gitea/gitea/pull/7082. + // But it's really questionable whether it's worth to do it ahead without waiting for the "push queue" task to run. + // TODO: DUPLICATE-PR-TASK: maybe can try to remove this in 1.26 to see if there is any issue. + go AddTestPullRequestTask(TestPullRequestOptions{ + RepoID: pr.BaseRepo.ID, + Doer: doer, + Branch: pr.BaseBranch, + IsSync: false, + IsForcePush: false, + OldCommitID: "", + NewCommitID: "", + }) +} + // Merge merges pull request to base repository. // Caller should check PR is ready to be merged (review and status checks) -func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User, mergeStyle repo_model.MergeStyle, expectedHeadCommitID, message string, wasAutoMerged bool) error { +func Merge(pr *issues_model.PullRequest, doer *user_model.User, mergeStyle repo_model.MergeStyle, expectedHeadCommitID, message string, wasAutoMerged bool) error { + ctx := graceful.GetManager().HammerContext() // don't abort the git operation even if the user's request is canceled + if err := pr.LoadBaseRepo(ctx); err != nil { log.Error("Unable to load base repo: %v", err) return fmt.Errorf("unable to load base repo: %w", err) @@ -241,37 +261,27 @@ func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.U return ErrInvalidMergeStyle{ID: pr.BaseRepo.ID, Style: mergeStyle} } - releaser, err := globallock.Lock(ctx, getPullWorkingLockKey(pr.ID)) - if err != nil { - log.Error("lock.Lock(): %v", err) - return fmt.Errorf("lock.Lock: %w", err) - } - defer releaser() - defer func() { - // This is a duplicated call to AddTestPullRequestTask (it will also be called by the post-receive hook, via a push queue). - // This call will do some operations (push to base repo, sync commit divergence, add PR conflict check queue task, etc) - // immediately instead of waiting for the "push queue"'s task. The code is from https://github.com/go-gitea/gitea/pull/7082. - // But it's really questionable whether it's worth to do it ahead without waiting for the "push queue" task to run. - // TODO: DUPLICATE-PR-TASK: maybe can try to remove this in 1.26 to see if there is any issue. - go AddTestPullRequestTask(TestPullRequestOptions{ - RepoID: pr.BaseRepo.ID, - Doer: doer, - Branch: pr.BaseBranch, - IsSync: false, - IsForcePush: false, - OldCommitID: "", - NewCommitID: "", - }) - }() - - _, err = doMergeAndPush(ctx, pr, doer, mergeStyle, expectedHeadCommitID, message, repo_module.PushTriggerPRMergeToBase) - releaser() + err = globallock.LockAndDo(ctx, getPullWorkingLockKey(pr.ID), func(ctx context.Context) error { + _, err := doMergeAndPush(ctx, pr, doer, mergeStyle, expectedHeadCommitID, message, repo_module.PushTriggerPRMergeToBase) + return err + }) + defer addTestPullRequestTaskAfterWebOperation(pr, doer) // keep the same behavior as old code: always call AddTestPullRequestTask + // TODO: the "merge" operation has finished, there could still be some edge cases: + // * if the post-process hook isn't executed correctly: + // * the commit has been merged into target branch + // * the PR's status is still "open (unmerged)" + // * something wrong happens (e.g.: out of sync?) + // * maybe this is the reason that why the duplicate AddTestPullRequestTask is called in defer func above if err != nil { return err } + // TODO: it is questionable whether it should return error here, the "merge" operation has succeeded + return handleMergePostProcess(ctx, pr.ID, doer, wasAutoMerged) +} +func handleMergePostProcess(ctx context.Context, prID int64, doer *user_model.User, wasAutoMerged bool) error { // reload pull request because it has been updated by post receive hook - pr, err = issues_model.GetPullRequestByID(ctx, pr.ID) + pr, err := issues_model.GetPullRequestByID(ctx, prID) if err != nil { return err } diff --git a/package/gitea/source/services/pull/merge_ff_only.go b/package/gitea/source/services/pull/merge_ff_only.go index 2ed09a71..7920d97c 100644 --- a/package/gitea/source/services/pull/merge_ff_only.go +++ b/package/gitea/source/services/pull/merge_ff_only.go @@ -4,9 +4,9 @@ package pull import ( - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/git/gitcmd" - "code.gitea.io/gitea/modules/log" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/log" ) // doMergeStyleFastForwardOnly merges the tracking into the current HEAD - which is assumed to be staging branch (equal to the pr.BaseBranch) diff --git a/package/gitea/source/services/pull/merge_merge.go b/package/gitea/source/services/pull/merge_merge.go index 2bc1fb9a..526aeb0e 100644 --- a/package/gitea/source/services/pull/merge_merge.go +++ b/package/gitea/source/services/pull/merge_merge.go @@ -4,9 +4,9 @@ package pull import ( - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/git/gitcmd" - "code.gitea.io/gitea/modules/log" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/log" ) // doMergeStyleMerge merges the tracking branch into the current HEAD - which is assumed to be the staging branch (equal to the pr.BaseBranch) diff --git a/package/gitea/source/services/pull/merge_prepare.go b/package/gitea/source/services/pull/merge_prepare.go index c23bfdc7..c50bb3cc 100644 --- a/package/gitea/source/services/pull/merge_prepare.go +++ b/package/gitea/source/services/pull/merge_prepare.go @@ -13,15 +13,14 @@ import ( "strings" "time" - issues_model "code.gitea.io/gitea/models/issues" - 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/git/gitcmd" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/util" - asymkey_service "code.gitea.io/gitea/services/asymkey" + issues_model "gitea.dev/models/issues" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/log" + "gitea.dev/modules/util" + asymkey_service "gitea.dev/services/asymkey" ) type mergeContext struct { @@ -103,15 +102,18 @@ func createTemporaryRepoForMerge(ctx context.Context, pr *issues_model.PullReque mergeCtx.sig = doer.NewGitSig() mergeCtx.committer = mergeCtx.sig - gitRepo, err := gitrepo.OpenRepository(ctx, pr.BaseRepo) + gitRepo, err := git.OpenRepository(ctx, mergeCtx.tmpBasePath) if err != nil { defer cancel() return nil, nil, fmt.Errorf("failed to open temp git repo for pr[%d]: %w", mergeCtx.pr.ID, err) } defer gitRepo.Close() - // Determine if we should sign - sign, key, signer, _ := asymkey_service.SignMerge(ctx, pr, doer, gitRepo) + // Determine if we should sign, using the temp repo's own refs (see SignMerge for why) + sign, key, signer, err := asymkey_service.SignMerge(ctx, pr, doer, gitRepo, git.BranchPrefix+tmpRepoBaseBranch, git.BranchPrefix+tmpRepoTrackingBranch) + if err != nil && !asymkey_service.IsErrWontSign(err) { + log.Error("%-v SignMerge: %v", mergeCtx.pr, err) // the merge proceeds unsigned regardless, so log it here + } if sign { mergeCtx.signKey = key if pr.BaseRepo.GetTrustModel() == repo_model.CommitterTrustModel || pr.BaseRepo.GetTrustModel() == repo_model.CollaboratorCommitterTrustModel { diff --git a/package/gitea/source/services/pull/merge_rebase.go b/package/gitea/source/services/pull/merge_rebase.go index 0224f7f1..57b771e3 100644 --- a/package/gitea/source/services/pull/merge_rebase.go +++ b/package/gitea/source/services/pull/merge_rebase.go @@ -7,11 +7,11 @@ import ( "fmt" "strings" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/git/gitcmd" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/log" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/log" ) // getRebaseAmendMessage composes the message to amend commits in rebase merge of a pull request. diff --git a/package/gitea/source/services/pull/merge_squash.go b/package/gitea/source/services/pull/merge_squash.go index 0f716f4d..54b91594 100644 --- a/package/gitea/source/services/pull/merge_squash.go +++ b/package/gitea/source/services/pull/merge_squash.go @@ -6,13 +6,13 @@ package pull import ( "fmt" - 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/git" - "code.gitea.io/gitea/modules/git/gitcmd" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/container" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" ) // doMergeStyleSquash gets a commit author signature for squash commits @@ -22,7 +22,7 @@ func getAuthorSignatureSquash(ctx *mergeContext) (*git.Signature, error) { return nil, err } - // Try to get an signature from the same user in one of the commits, as the + // Try to get a signature from the same user in one of the commits, as the // poster email might be private or commits might have a different signature // than the primary email address of the poster. gitRepo, err := git.OpenRepository(ctx, ctx.tmpBasePath) @@ -32,9 +32,9 @@ func getAuthorSignatureSquash(ctx *mergeContext) (*git.Signature, error) { } defer gitRepo.Close() - commits, err := gitRepo.CommitsBetweenIDs(tmpRepoTrackingBranch, "HEAD") + commits, err := gitRepo.CommitsBetween(git.RefNameFromBranch(tmpRepoTrackingBranch), git.RefNameHead, -1) if err != nil { - log.Error("%-v Unable to get commits between: %s %s: %v", ctx.pr, "HEAD", tmpRepoTrackingBranch, err) + log.Error("%-v Unable to get commits between: head and tracking branch: %v", ctx.pr, err) return nil, err } @@ -65,9 +65,7 @@ func doMergeStyleSquash(ctx *mergeContext, message string) error { } if setting.Repository.PullRequest.AddCoCommitterTrailers && ctx.committer.String() != sig.String() { - // add trailer - message = AddCommitMessageTailer(message, "Co-authored-by", sig.String()) - message = AddCommitMessageTailer(message, "Co-committed-by", sig.String()) // FIXME: this one should be removed, it is not really used or widely used + message = AddCommitMessageTailer(message, git.CoAuthoredByTrailer, sig.String()) } cmdCommit := gitcmd.NewCommand("commit"). AddOptionFormat("--author='%s <%s>'", sig.Name, sig.Email). diff --git a/package/gitea/source/services/pull/merge_tree.go b/package/gitea/source/services/pull/merge_tree.go index 18d59fab..10bdcf99 100644 --- a/package/gitea/source/services/pull/merge_tree.go +++ b/package/gitea/source/services/pull/merge_tree.go @@ -8,11 +8,11 @@ import ( "errors" "fmt" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/git/gitcmd" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/log" + issues_model "gitea.dev/models/issues" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/log" ) // checkConflictsMergeTree uses git merge-tree to check for conflicts and if none are found checks if the patch is empty diff --git a/package/gitea/source/services/pull/merge_tree_test.go b/package/gitea/source/services/pull/merge_tree_test.go index 6fa2cf70..91d6a915 100644 --- a/package/gitea/source/services/pull/merge_tree_test.go +++ b/package/gitea/source/services/pull/merge_tree_test.go @@ -8,9 +8,9 @@ import ( "fmt" "testing" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/git/gitcmd" + issues_model "gitea.dev/models/issues" + "gitea.dev/models/unittest" + "gitea.dev/modules/git/gitcmd" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/package/gitea/source/services/pull/patch.go b/package/gitea/source/services/pull/patch.go index 114a437c..38440725 100644 --- a/package/gitea/source/services/pull/patch.go +++ b/package/gitea/source/services/pull/patch.go @@ -12,15 +12,15 @@ import ( "path/filepath" "strings" - git_model "code.gitea.io/gitea/models/git" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/git/gitcmd" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/glob" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/process" - "code.gitea.io/gitea/modules/util" + git_model "gitea.dev/models/git" + issues_model "gitea.dev/models/issues" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/glob" + "gitea.dev/modules/log" + "gitea.dev/modules/process" + "gitea.dev/modules/util" ) // DownloadDiffOrPatch will write the patch for the pr to the writer diff --git a/package/gitea/source/services/pull/patch_unmerged.go b/package/gitea/source/services/pull/patch_unmerged.go index 78a31a87..447cf4e1 100644 --- a/package/gitea/source/services/pull/patch_unmerged.go +++ b/package/gitea/source/services/pull/patch_unmerged.go @@ -12,8 +12,8 @@ import ( "strconv" "strings" - "code.gitea.io/gitea/modules/git/gitcmd" - "code.gitea.io/gitea/modules/log" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/log" ) // lsFileLine is a Quadruplet struct (+error) representing a partially parsed line from ls-files diff --git a/package/gitea/source/services/pull/protected_branch.go b/package/gitea/source/services/pull/protected_branch.go index 68ae7bc2..667a4b9d 100644 --- a/package/gitea/source/services/pull/protected_branch.go +++ b/package/gitea/source/services/pull/protected_branch.go @@ -6,8 +6,8 @@ package pull import ( "context" - git_model "code.gitea.io/gitea/models/git" - repo_model "code.gitea.io/gitea/models/repo" + git_model "gitea.dev/models/git" + repo_model "gitea.dev/models/repo" ) func CreateOrUpdateProtectedBranch(ctx context.Context, repo *repo_model.Repository, diff --git a/package/gitea/source/services/pull/pull.go b/package/gitea/source/services/pull/pull.go index 34ca9676..6af56b7e 100644 --- a/package/gitea/source/services/pull/pull.go +++ b/package/gitea/source/services/pull/pull.go @@ -4,37 +4,39 @@ package pull import ( + "bytes" "context" "errors" "fmt" "io" - "regexp" + "slices" "strings" "time" + "unicode" "unicode/utf8" - "code.gitea.io/gitea/models/db" - git_model "code.gitea.io/gitea/models/git" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/organization" - access_model "code.gitea.io/gitea/models/perm/access" - 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/base" - "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/git/gitcmd" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/globallock" - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/log" - repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" - git_service "code.gitea.io/gitea/services/git" - issue_service "code.gitea.io/gitea/services/issue" - notify_service "code.gitea.io/gitea/services/notify" + "gitea.dev/models/db" + git_model "gitea.dev/models/git" + issues_model "gitea.dev/models/issues" + "gitea.dev/models/organization" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unit" + user_model "gitea.dev/models/user" + "gitea.dev/modules/base" + "gitea.dev/modules/container" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/globallock" + "gitea.dev/modules/graceful" + "gitea.dev/modules/log" + repo_module "gitea.dev/modules/repository" + "gitea.dev/modules/setting" + "gitea.dev/modules/util" + git_service "gitea.dev/services/git" + issue_service "gitea.dev/services/issue" + notify_service "gitea.dev/services/notify" ) func getPullWorkingLockKey(prID int64) string { @@ -50,7 +52,7 @@ type NewPullRequestOptions struct { AssigneeIDs []int64 Reviewers []*user_model.User TeamReviewers []*organization.Team - ProjectID int64 + ProjectIDs []int64 } // NewPullRequest creates new pull request with labels for repository. @@ -95,7 +97,7 @@ func NewPullRequest(ctx context.Context, opts *NewPullRequestOptions) error { } assigneeCommentMap := make(map[int64]*issues_model.Comment) - + assignees := make(map[int64]*user_model.User) 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 { @@ -103,15 +105,21 @@ func NewPullRequest(ctx context.Context, opts *NewPullRequestOptions) error { } for _, assigneeID := range assigneeIDs { - comment, err := issue_service.AddAssigneeIfNotAssigned(ctx, issue, issue.Poster, assigneeID, false) + assignee, err := user_model.GetUserByID(ctx, assigneeID) + if err != nil { + log.Error("GetUserByID: %v", err) + continue + } + comment, err := issue_service.AddAssigneeIfNotAssigned(ctx, issue, issue.Poster, assignee) if err != nil { return err } + assignees[assigneeID] = assignee assigneeCommentMap[assigneeID] = comment } - if opts.ProjectID > 0 && canAssignProject { - if err := issues_model.IssueAssignOrRemoveProject(ctx, issue, issue.Poster, opts.ProjectID, 0); err != nil { + if len(opts.ProjectIDs) > 0 && canAssignProject { + if err := issues_model.IssueAssignOrRemoveProject(ctx, issue, issue.Poster, opts.ProjectIDs); err != nil { return err } } @@ -185,12 +193,8 @@ func NewPullRequest(ctx context.Context, opts *NewPullRequestOptions) error { if issue.Milestone != nil { notify_service.IssueChangeMilestone(ctx, issue.Poster, issue, 0) } - for _, assigneeID := range assigneeIDs { - assignee, err := user_model.GetUserByID(ctx, assigneeID) - if err != nil { - return ErrDependenciesLeft - } - notify_service.IssueChangeAssignee(ctx, issue.Poster, issue, assignee, false, assigneeCommentMap[assigneeID]) + for _, assignee := range assignees { + notify_service.IssueChangeAssignee(ctx, issue.Poster, issue, assignee, false, assigneeCommentMap[assignee.ID]) } return nil @@ -322,6 +326,14 @@ func ChangeTargetBranch(ctx context.Context, pr *issues_model.PullRequest, doer return fmt.Errorf("syncCommitDivergence: %w", err) } + // The "official" flag of existing reviews was computed against the previous + // target branch's protection rules, so re-evaluate it against the new branch. + // Otherwise a stale official approval could bypass the new branch's protection. + pr.Issue.PullRequest = pr + if err := issues_model.RecalculateReviewsOfficial(ctx, pr.Issue); err != nil { + return fmt.Errorf("RecalculateReviewsOfficial: %w", err) + } + // Create comment options := &issues_model.CreateCommentOptions{ Type: issues_model.CommentTypeChangeTargetBranch, @@ -478,7 +490,7 @@ func AddTestPullRequestTask(opts TestPullRequestOptions) { } } - notify_service.PullRequestSynchronized(ctx, opts.Doer, pr) + notify_service.PullRequestSynchronized(ctx, opts.Doer, pr, opts.OldCommitID, opts.NewCommitID) } } } @@ -764,116 +776,88 @@ func CloseRepoBranchesPulls(ctx context.Context, doer *user_model.User, repo *re return errors.Join(errs...) } -var commitMessageTrailersPattern = regexp.MustCompile(`(?:^|\n\n)(?:[\w-]+[ \t]*:[^\n]+\n*(?:[ \t]+[^\n]+\n*)*)+$`) - // GetSquashMergeCommitMessages returns the commit messages between head and merge base (if there is one) -func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequest) string { +func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequest) (_ string, err error) { if err := pr.LoadIssue(ctx); err != nil { - log.Error("Cannot load issue %d for PR id %d: Error: %v", pr.IssueID, pr.ID, err) - return "" + return "", err } if err := pr.Issue.LoadPoster(ctx); err != nil { - log.Error("Cannot load poster %d for pr id %d, index %d Error: %v", pr.Issue.PosterID, pr.ID, pr.Index, err) - return "" + return "", err } if pr.HeadRepo == nil { - var err error pr.HeadRepo, err = repo_model.GetRepositoryByID(ctx, pr.HeadRepoID) if err != nil { - log.Error("GetRepositoryByIdCtx[%d]: %v", pr.HeadRepoID, err) - return "" + return "", err } } gitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, pr.HeadRepo) if err != nil { - log.Error("Unable to open head repository: Error: %v", err) - return "" + return "", err } defer closer.Close() - var headCommit *git.Commit + var headCommitRef git.RefName if pr.Flow == issues_model.PullRequestFlowGithub { - headCommit, err = gitRepo.GetBranchCommit(pr.HeadBranch) + headCommitRef = git.RefNameFromBranch(pr.HeadBranch) } else { pr.HeadCommitID, err = gitRepo.GetRefCommitID(pr.GetGitHeadRefName()) if err != nil { - log.Error("Unable to get head commit: %s Error: %v", pr.GetGitHeadRefName(), err) - return "" + return "", err } - headCommit, err = gitRepo.GetCommit(pr.HeadCommitID) - } - if err != nil { - log.Error("Unable to get head commit: %s Error: %v", pr.HeadBranch, err) - return "" + headCommitRef = git.RefNameFromCommit(pr.HeadCommitID) } - mergeBase, err := gitRepo.GetCommit(pr.MergeBase) - if err != nil { - log.Error("Unable to get merge base commit: %s Error: %v", pr.MergeBase, err) - return "" - } + mergeBaseRef := git.RefNameFromCommit(pr.MergeBase) limit := setting.Repository.PullRequest.DefaultMergeMessageCommitsLimit - commits, err := gitRepo.CommitsBetweenLimit(headCommit, mergeBase, limit, 0) + limitedCommits, err := gitRepo.CommitsBetween(headCommitRef, mergeBaseRef, limit) if err != nil { - log.Error("Unable to get commits between: %s %s Error: %v", pr.HeadBranch, pr.MergeBase, err) - return "" + return "", err } + mergeMessage := strings.TrimSpace(pr.Issue.Content) // use PR's title and description as squash commit message + if setting.Repository.PullRequest.PopulateSquashCommentWithCommitMessages { + mergeMessage = formatSquashMergeCommitMessages(limitedCommits) // use PR's commit messages as squash commit message + } + coAuthors := collectSquashMergeCommitCoAuthors(ctx, gitRepo, pr, headCommitRef, mergeBaseRef, limit, limitedCommits) + return buildSquashMergeCommitMessages(mergeMessage, coAuthors), nil +} + +func buildSquashMergeCommitMessages(mergeMessage string, coAuthors []string) string { + if len(coAuthors) == 0 { + return mergeMessage + } + + msgContent, msgSep, msgTrailer := git.CommitMessageSplitTrailer(mergeMessage) + if (msgSep == "" || msgSep == "\n\n") && msgTrailer == "" { + msgContent = strings.TrimRightFunc(msgContent, unicode.IsSpace) + msgSep = "\n\n---------\n\n" + } + var sb strings.Builder + sb.WriteString(msgContent) + sb.WriteString(msgSep) + if msgTrailer = strings.TrimSpace(msgTrailer); msgTrailer != "" { + sb.WriteString(msgTrailer) + sb.WriteRune('\n') + } + for _, author := range coAuthors { + sb.WriteString(git.CoAuthoredByTrailer + ": ") + sb.WriteString(author) + sb.WriteRune('\n') + } + return sb.String() +} + +func collectSquashMergeCommitCoAuthors(ctx context.Context, gitRepo *git.Repository, pr *issues_model.PullRequest, headCommitRef, mergeBaseRef git.RefName, limitFirst int, limitedCommits []*git.Commit) []string { posterSig := pr.Issue.Poster.NewGitSig().String() - uniqueAuthors := make(container.Set[string]) - authors := make([]string, 0, len(commits)) - stringBuilder := strings.Builder{} + authors := make([]string, 0, len(limitedCommits)) - if !setting.Repository.PullRequest.PopulateSquashCommentWithCommitMessages { - // use PR's title and description as squash commit message - message := strings.TrimSpace(pr.Issue.Content) - stringBuilder.WriteString(message) - if stringBuilder.Len() > 0 { - stringBuilder.WriteRune('\n') - if !commitMessageTrailersPattern.MatchString(message) { - // TODO: this trailer check doesn't work with the separator line added below for the co-authors - stringBuilder.WriteRune('\n') - } - } - } else { - // use PR's commit messages as squash commit message - // commits list is in reverse chronological order - maxMsgSize := setting.Repository.PullRequest.DefaultMergeMessageSize - for i := len(commits) - 1; i >= 0; i-- { - commit := commits[i] - msg := strings.TrimSpace(commit.Message()) - if msg == "" { - continue - } - - // This format follows GitHub's squash commit message style, - // even if there are other "* " in the commit message body, they are written as-is. - // Maybe, ideally, we should indent those lines too. - _, _ = fmt.Fprintf(&stringBuilder, "* %s\n\n", msg) - if maxMsgSize > 0 && stringBuilder.Len() >= maxMsgSize { - tmp := stringBuilder.String() - wasValidUtf8 := utf8.ValidString(tmp) - tmp = tmp[:maxMsgSize] + "..." - if wasValidUtf8 { - // If the message was valid UTF-8 before truncation, ensure it remains valid after truncation - // For non-utf8 messages, we can't do much about it, end users should use utf-8 as much as possible - tmp = strings.ToValidUTF8(tmp, "") - } - stringBuilder.Reset() - stringBuilder.WriteString(tmp) - break - } - } - } - - // collect co-authors - for _, commit := range commits { + for _, commit := range limitedCommits { authorString := commit.Author.String() if uniqueAuthors.Add(authorString) && authorString != posterSig { // Compare use account as well to avoid adding the same author multiple times @@ -886,14 +870,14 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ } // collect the remaining authors - if limit >= 0 && setting.Repository.PullRequest.DefaultMergeMessageAllAuthors { - skip := limit - limit = 30 + if limitFirst >= 0 && setting.Repository.PullRequest.DefaultMergeMessageAllAuthors { + skip := limitFirst + batchLimit := 30 for { - commits, err = gitRepo.CommitsBetweenLimit(headCommit, mergeBase, limit, skip) + commits, err := gitRepo.CommitsBetween(headCommitRef, mergeBaseRef, batchLimit, skip) if err != nil { log.Error("Unable to get commits between: %s %s Error: %v", pr.HeadBranch, pr.MergeBase, err) - return "" + return authors } if len(commits) == 0 { break @@ -907,22 +891,46 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ } } } - skip += limit + skip += batchLimit + } + } + return authors +} + +func formatSquashMergeCommitMessages(commits []*git.Commit) string { + maxMsgSize := setting.Repository.PullRequest.DefaultMergeMessageSize + sb := &bytes.Buffer{} + // commits list is in reverse chronological order + for _, commit := range slices.Backward(commits) { + msg := strings.TrimSpace(commit.MessageUTF8()) + if msg == "" { + continue + } + + // This format follows GitHub's squash commit message style, + // even if there are other "* " in the commit message body, they are written as-is. + // Maybe, ideally, we should indent those lines too. + _, _ = fmt.Fprintf(sb, "* %s\n\n", msg) + if maxMsgSize > 0 && sb.Len() >= maxMsgSize { + break } } - if stringBuilder.Len() > 0 && len(authors) > 0 { - // TODO: this separator line doesn't work with the trailer check (commitMessageTrailersPattern) above - stringBuilder.WriteString("---------\n\n") + buf := bytes.TrimSpace(sb.Bytes()) + if maxMsgSize > 0 && len(buf) > maxMsgSize { + buf = buf[:maxMsgSize] + for { + r, sz := utf8.DecodeLastRune(buf) + if r == utf8.RuneError && sz == 1 { + buf = buf[:len(buf)-1] + continue + } + break + } + buf = append(buf, '.', '.', '.') } - - for _, author := range authors { - stringBuilder.WriteString("Co-authored-by: ") - stringBuilder.WriteString(author) - stringBuilder.WriteRune('\n') - } - - return stringBuilder.String() + buf = append(buf, '\n', '\n') + return util.UnsafeBytesToString(buf) } // GetIssuesAllCommitStatus returns a map of issue ID to a list of all statuses for the most recent commit as well as a map of issue ID to only the commit's latest status @@ -1074,7 +1082,7 @@ func GetPullCommits(ctx context.Context, baseGitRepo *git.Repository, doer *user } commits = append(commits, CommitInfo{ - Summary: commit.Summary(), + Summary: commit.MessageTitle(), CommitterOrAuthorName: committerOrAuthorName, ID: commit.ID.String(), ShortSha: base.ShortSha(commit.ID.String()), diff --git a/package/gitea/source/services/pull/pull_test.go b/package/gitea/source/services/pull/pull_test.go index 1c03ab45..554c9ed5 100644 --- a/package/gitea/source/services/pull/pull_test.go +++ b/package/gitea/source/services/pull/pull_test.go @@ -7,32 +7,37 @@ package pull import ( "testing" - issues_model "code.gitea.io/gitea/models/issues" - 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/gitrepo" + issues_model "gitea.dev/models/issues" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unit" + "gitea.dev/models/unittest" + "gitea.dev/modules/git" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/setting" + "gitea.dev/modules/test" "github.com/stretchr/testify/assert" ) // TODO TestPullRequest_PushToBaseRepo -func TestPullRequest_CommitMessageTrailersPattern(t *testing.T) { - // Not a valid trailer section - assert.False(t, commitMessageTrailersPattern.MatchString("")) - assert.False(t, commitMessageTrailersPattern.MatchString("No trailer.")) - assert.False(t, commitMessageTrailersPattern.MatchString("Signed-off-by: Bob \nNot a trailer due to following text.")) - assert.False(t, commitMessageTrailersPattern.MatchString("Message body not correctly separated from trailer section by empty line.\nSigned-off-by: Bob ")) - // Valid trailer section - assert.True(t, commitMessageTrailersPattern.MatchString("Signed-off-by: Bob ")) - assert.True(t, commitMessageTrailersPattern.MatchString("Signed-off-by: Bob \nOther-Trailer: Value")) - assert.True(t, commitMessageTrailersPattern.MatchString("Message body correctly separated from trailer section by empty line.\n\nSigned-off-by: Bob ")) - assert.True(t, commitMessageTrailersPattern.MatchString("Multiple trailers.\n\nSigned-off-by: Bob \nOther-Trailer: Value")) - assert.True(t, commitMessageTrailersPattern.MatchString("Newline after trailer section.\n\nSigned-off-by: Bob \n")) - assert.True(t, commitMessageTrailersPattern.MatchString("No space after colon is accepted.\n\nSigned-off-by:Bob ")) - assert.True(t, commitMessageTrailersPattern.MatchString("Additional whitespace is accepted.\n\nSigned-off-by \t : \tBob ")) - assert.True(t, commitMessageTrailersPattern.MatchString("Folded value.\n\nFolded-trailer: This is\n a folded\n trailer value\nOther-Trailer: Value")) +func TestPullRequest_FormatSquashMergeCommitMessages(t *testing.T) { + oldest := &git.Commit{CommitMessage: git.CommitMessage{MessageRaw: "commit msg 1"}} + newest := &git.Commit{CommitMessage: git.CommitMessage{MessageRaw: "commit msg 2\n\nCommit description."}} + + defer test.MockVariableValue(&setting.Repository.PullRequest.DefaultMergeMessageSize, 0)() + + assert.Equal(t, "* commit msg 1\n\n* commit msg 2\n\nCommit description.\n\n", formatSquashMergeCommitMessages([]*git.Commit{newest, oldest})) + + utf8Msg := &git.Commit{CommitMessage: git.CommitMessage{MessageRaw: "🌞"}} + setting.Repository.PullRequest.DefaultMergeMessageSize = 3 + assert.Equal(t, "* ...\n\n", formatSquashMergeCommitMessages([]*git.Commit{utf8Msg})) + setting.Repository.PullRequest.DefaultMergeMessageSize = 4 + assert.Equal(t, "* ...\n\n", formatSquashMergeCommitMessages([]*git.Commit{utf8Msg})) + setting.Repository.PullRequest.DefaultMergeMessageSize = 5 + assert.Equal(t, "* ...\n\n", formatSquashMergeCommitMessages([]*git.Commit{utf8Msg})) + setting.Repository.PullRequest.DefaultMergeMessageSize = 6 + assert.Equal(t, "* 🌞\n\n", formatSquashMergeCommitMessages([]*git.Commit{utf8Msg})) } func TestPullRequest_GetDefaultMergeMessage_InternalTracker(t *testing.T) { @@ -88,3 +93,27 @@ func TestPullRequest_GetDefaultMergeMessage_ExternalTracker(t *testing.T) { assert.Equal(t, "Merge pull request 'issue3' (#3) from user2/repo2:branch2 into master", mergeMessage) } + +func TestBuildSquashMergeCommitMessages(t *testing.T) { + cases := []struct { + msg string + coAuthors []string + expected string + }{ + {"title", nil, "title"}, + {"title", []string{"the-user"}, "title\n\n---------\n\nCo-authored-by: the-user\n"}, + {"title\n\n", []string{"the-user"}, "title\n\n---------\n\nCo-authored-by: the-user\n"}, + {"title\n\nKey: val", []string{"the-user"}, "title\n\nKey: val\nCo-authored-by: the-user\n"}, + {"title\n\n----\nKey: val", []string{"the-user"}, "title\n\n----\nKey: val\nCo-authored-by: the-user\n"}, + {"title\n\n----\nKey: val\n\n", []string{"the-user"}, "title\n\n----\nKey: val\nCo-authored-by: the-user\n"}, + + {"title\n\nbody", nil, "title\n\nbody"}, + {"title\n\nbody", []string{"the-user"}, "title\n\nbody\n\n---------\n\nCo-authored-by: the-user\n"}, + {"title\n\nbody\n\nKey: val", []string{"the-user"}, "title\n\nbody\n\nKey: val\nCo-authored-by: the-user\n"}, + {"title\n\nbody\n\n----\nKey: val", []string{"the-user"}, "title\n\nbody\n\n----\nKey: val\nCo-authored-by: the-user\n"}, + } + for _, c := range cases { + msg := buildSquashMergeCommitMessages(c.msg, c.coAuthors) + assert.Equal(t, c.expected, msg, "msg: %s", c.msg) + } +} diff --git a/package/gitea/source/services/pull/review.go b/package/gitea/source/services/pull/review.go index 261cf234..18abdb04 100644 --- a/package/gitea/source/services/pull/review.go +++ b/package/gitea/source/services/pull/review.go @@ -10,19 +10,19 @@ import ( "fmt" "strings" - "code.gitea.io/gitea/models/db" - issues_model "code.gitea.io/gitea/models/issues" - 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/git/gitcmd" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/optional" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/services/gitdiff" - notify_service "code.gitea.io/gitea/services/notify" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/log" + "gitea.dev/modules/optional" + "gitea.dev/modules/setting" + "gitea.dev/modules/util" + "gitea.dev/services/gitdiff" + notify_service "gitea.dev/services/notify" ) func isErrBlameNotFoundOrNotEnoughLines(err error) bool { @@ -35,7 +35,7 @@ func isErrBlameNotFoundOrNotEnoughLines(err error) bool { return notFound || notEnoughLines } -// ErrDismissRequestOnClosedPR represents an error when an user tries to dismiss a review associated to a closed or merged PR. +// ErrDismissRequestOnClosedPR represents an error when a user tries to dismiss a review associated to a closed or merged PR. type ErrDismissRequestOnClosedPR struct{} // IsErrDismissRequestOnClosedPR checks if an error is an ErrDismissRequestOnClosedPR. @@ -52,7 +52,7 @@ 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. +// ErrSubmitReviewOnClosedPR represents an error when a 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") // LineBlame returns the latest commit at the given line diff --git a/package/gitea/source/services/pull/review_test.go b/package/gitea/source/services/pull/review_test.go index ddb2c04e..2254e304 100644 --- a/package/gitea/source/services/pull/review_test.go +++ b/package/gitea/source/services/pull/review_test.go @@ -6,10 +6,10 @@ package pull_test import ( "testing" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" - pull_service "code.gitea.io/gitea/services/pull" + issues_model "gitea.dev/models/issues" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + pull_service "gitea.dev/services/pull" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/pull/reviewer.go b/package/gitea/source/services/pull/reviewer.go index 139aeeb9..b98c85eb 100644 --- a/package/gitea/source/services/pull/reviewer.go +++ b/package/gitea/source/services/pull/reviewer.go @@ -6,13 +6,13 @@ package pull import ( "context" - "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" - "code.gitea.io/gitea/models/unit" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/container" + "gitea.dev/models/db" + "gitea.dev/models/organization" + "gitea.dev/models/perm" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unit" + user_model "gitea.dev/models/user" + "gitea.dev/modules/container" "xorm.io/builder" ) diff --git a/package/gitea/source/services/pull/reviewer_test.go b/package/gitea/source/services/pull/reviewer_test.go index 9fab65ce..81ca7891 100644 --- a/package/gitea/source/services/pull/reviewer_test.go +++ b/package/gitea/source/services/pull/reviewer_test.go @@ -6,9 +6,9 @@ package pull_test import ( "testing" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/models/unittest" - pull_service "code.gitea.io/gitea/services/pull" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + pull_service "gitea.dev/services/pull" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/pull/temp_repo.go b/package/gitea/source/services/pull/temp_repo.go index d0da8702..17bfd6a8 100644 --- a/package/gitea/source/services/pull/temp_repo.go +++ b/package/gitea/source/services/pull/temp_repo.go @@ -11,13 +11,13 @@ import ( "os" "path/filepath" - git_model "code.gitea.io/gitea/models/git" - issues_model "code.gitea.io/gitea/models/issues" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/git/gitcmd" - "code.gitea.io/gitea/modules/log" - repo_module "code.gitea.io/gitea/modules/repository" + git_model "gitea.dev/models/git" + issues_model "gitea.dev/models/issues" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/log" + repo_module "gitea.dev/modules/repository" ) // Temporary repos created here use standard branch names to help simplify diff --git a/package/gitea/source/services/pull/update.go b/package/gitea/source/services/pull/update.go index 4033e11e..091c336c 100644 --- a/package/gitea/source/services/pull/update.go +++ b/package/gitea/source/services/pull/update.go @@ -8,20 +8,22 @@ import ( "errors" "fmt" - 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" - "code.gitea.io/gitea/models/unit" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/globallock" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/repository" + git_model "gitea.dev/models/git" + issues_model "gitea.dev/models/issues" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unit" + user_model "gitea.dev/models/user" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/globallock" + "gitea.dev/modules/graceful" + "gitea.dev/modules/log" + "gitea.dev/modules/repository" ) // Update updates pull request with base branch. -func Update(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User, message string, rebase bool) error { +func Update(pr *issues_model.PullRequest, doer *user_model.User, message string, rebase bool) error { + ctx := graceful.GetManager().HammerContext() // don't abort the git operation even if the user's request is canceled if pr.Flow == issues_model.PullRequestFlowAGit { // TODO: update of agit flow pull request's head branch is unsupported return errors.New("update of agit flow pull request's head branch is unsupported") @@ -62,20 +64,10 @@ func Update(ctx context.Context, pr *issues_model.PullRequest, doer *user_model. return fmt.Errorf("unable to load HeadRepo for PR[%d] during update-by-merge: %w", pr.ID, err) } - defer func() { - // The code is from https://github.com/go-gitea/gitea/pull/9784, - // it seems a simple copy-paste from https://github.com/go-gitea/gitea/pull/7082 without a real reason. - // TODO: DUPLICATE-PR-TASK: search and see another TODO comment for more details - go AddTestPullRequestTask(TestPullRequestOptions{ - RepoID: pr.BaseRepo.ID, - Doer: doer, - Branch: pr.BaseBranch, - IsSync: false, - IsForcePush: false, - OldCommitID: "", - NewCommitID: "", - }) - }() + // TODO: The code is from https://github.com/go-gitea/gitea/pull/9784, + // it seems a simple copy-paste from https://github.com/go-gitea/gitea/pull/7082 without a real reason. + // TODO: DUPLICATE-PR-TASK: search and see another TODO comment for more details + defer addTestPullRequestTaskAfterWebOperation(pr, doer) if rebase { return updateHeadByRebaseOnToBase(ctx, pr, doer) @@ -97,6 +89,13 @@ func Update(ctx context.Context, pr *issues_model.PullRequest, doer *user_model. } _, err = doMergeAndPush(ctx, reversePR, doer, repo_model.MergeStyleMerge, "", message, repository.PushTriggerPRUpdateWithBase) + // TODO: the "update" (merge target branch to PR head branch) operation has finished, there could still be some edge cases: + // * the database was already out of sync: the target branch was already in head branch: + // * so no post-receive hook is really executed, no PR status update + // * then the PR status is stuck in "behind the target branch" (a new push can be used as a workaround) + // * "merge" operation does finish, but the post-receive hook isn't correctly executed due to other reasons: + // * although the target branch is merged into head branch by this "update" (head branch receives new commits) + // * but database isn't updated, so the PR status is still "behind the target branch" return err } @@ -131,74 +130,82 @@ func isUserAllowedToPushOrForcePushInRepoBranch(ctx context.Context, user *user_ return pushAllowed, forcePushAllowed, nil } -// IsUserAllowedToUpdate check if user is allowed to update PR with given permissions and branch protections +// CheckUserAllowedToUpdate check if user is allowed to update PR with given permissions and branch protections // update PR means send new commits to PR head branch from base branch -func IsUserAllowedToUpdate(ctx context.Context, pull *issues_model.PullRequest, user *user_model.User) (pushAllowed, rebaseAllowed bool, err error) { +func CheckUserAllowedToUpdate(ctx context.Context, pull *issues_model.PullRequest, user *user_model.User) (ret struct { + MergeAllowed, RebaseAllowed bool + DefaultUpdateStyle repo_model.UpdateStyle +}, err error, +) { if user == nil { - return false, false, nil + return ret, nil } if err := pull.LoadBaseRepo(ctx); err != nil { - return false, false, err + return ret, err } if err := pull.LoadHeadRepo(ctx); err != nil { - return false, false, err + return ret, err } // 1. check whether pull request enabled. prBaseUnit, err := pull.BaseRepo.GetUnit(ctx, unit.TypePullRequests) if repo_model.IsErrUnitTypeNotExist(err) { - return false, false, nil // the PR unit is disabled in base repo means no update allowed + return ret, nil // the PR unit is disabled in base repo means no update allowed } else if err != nil { - return false, false, fmt.Errorf("get base repo unit: %v", err) + return ret, fmt.Errorf("get base repo unit: %v", err) } // 2. only support Github style pull request if pull.Flow == issues_model.PullRequestFlowAGit { - return false, false, nil + return ret, nil } // 3. check user push permission on head repository - pushAllowed, rebaseAllowed, err = isUserAllowedToPushOrForcePushInRepoBranch(ctx, user, pull.HeadRepo, pull.HeadBranch) + ret.MergeAllowed, ret.RebaseAllowed, err = isUserAllowedToPushOrForcePushInRepoBranch(ctx, user, pull.HeadRepo, pull.HeadBranch) if err != nil { - return false, false, err + return ret, err } // 4. if the pull creator allows maintainer to edit, we need to check whether // user is a maintainer (has permission to merge into base branch) and inherit pull request poster's permission - if pull.AllowMaintainerEdit && (!pushAllowed || !rebaseAllowed) { + if pull.AllowMaintainerEdit && (!ret.MergeAllowed || !ret.RebaseAllowed) { baseRepoPerm, err := access_model.GetDoerRepoPermission(ctx, pull.BaseRepo, user) if err != nil { - return false, false, err + return ret, err } userAllowedToMergePR, err := isUserAllowedToMergeInRepoBranch(ctx, pull.BaseRepoID, pull.BaseBranch, baseRepoPerm, user) if err != nil { - return false, false, err + return ret, err } if userAllowedToMergePR { // the user is maintainer (can merge PR), and this PR is allowed to be edited by maintainers, // then the user should inherit the PR poster's push/rebase permission for the head branch if err := pull.LoadIssue(ctx); err != nil { - return false, false, err + return ret, err } if err := pull.Issue.LoadPoster(ctx); err != nil { - return false, false, err + return ret, err } posterPushAllowed, posterRebaseAllowed, err := isUserAllowedToPushOrForcePushInRepoBranch(ctx, pull.Issue.Poster, pull.HeadRepo, pull.HeadBranch) if err != nil { - return false, false, err + return ret, err } - if !pushAllowed { - pushAllowed = posterPushAllowed + if !ret.MergeAllowed { + ret.MergeAllowed = posterPushAllowed } - if !rebaseAllowed { - rebaseAllowed = posterRebaseAllowed + if !ret.RebaseAllowed { + ret.RebaseAllowed = posterRebaseAllowed } } } - // 5. check base repository's AllowRebaseUpdate configuration - // it is a config in base repo but controls the head (fork) repo's "Update" behavior - return pushAllowed, rebaseAllowed && prBaseUnit.PullRequestsConfig().AllowRebaseUpdate, nil + // 5. apply base repository's update configuration; it is a config on the base repo, + // but it controls the head (fork) repo's "Update" behavior. + prConfig := prBaseUnit.PullRequestsConfig() + ret.MergeAllowed = ret.MergeAllowed && prConfig.AllowMergeUpdate + ret.RebaseAllowed = ret.RebaseAllowed && prConfig.AllowRebaseUpdate + ret.DefaultUpdateStyle = prConfig.DefaultUpdateStyle + return ret, nil } func syncCommitDivergence(ctx context.Context, pr *issues_model.PullRequest) error { diff --git a/package/gitea/source/services/pull/update_rebase.go b/package/gitea/source/services/pull/update_rebase.go index 6b90e5d7..2479db54 100644 --- a/package/gitea/source/services/pull/update_rebase.go +++ b/package/gitea/source/services/pull/update_rebase.go @@ -8,14 +8,14 @@ import ( "fmt" "strings" - issues_model "code.gitea.io/gitea/models/issues" - 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/git/gitcmd" - "code.gitea.io/gitea/modules/log" - repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/setting" + issues_model "gitea.dev/models/issues" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/log" + repo_module "gitea.dev/modules/repository" + "gitea.dev/modules/setting" ) // updateHeadByRebaseOnToBase handles updating a PR's head branch by rebasing it on the PR current base branch diff --git a/package/gitea/source/services/pull/update_test.go b/package/gitea/source/services/pull/update_test.go index 0bb67544..b340a7a5 100644 --- a/package/gitea/source/services/pull/update_test.go +++ b/package/gitea/source/services/pull/update_test.go @@ -4,17 +4,18 @@ package pull import ( + "context" "testing" - "code.gitea.io/gitea/models/db" - git_model "code.gitea.io/gitea/models/git" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/perm" - access_model "code.gitea.io/gitea/models/perm/access" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/models/unit" - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" + "gitea.dev/models/db" + git_model "gitea.dev/models/git" + issues_model "gitea.dev/models/issues" + "gitea.dev/models/perm" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unit" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -23,11 +24,21 @@ import ( func TestIsUserAllowedToUpdate(t *testing.T) { require.NoError(t, unittest.PrepareTestDatabase()) - setRepoAllowRebaseUpdate := func(t *testing.T, repoID int64, allow bool) { + updatePRConfig := func(t *testing.T, repoID int64, update func(*repo_model.PullRequestsConfig)) { repoUnit := unittest.AssertExistsAndLoadBean(t, &repo_model.RepoUnit{RepoID: repoID, Type: unit.TypePullRequests}) - repoUnit.PullRequestsConfig().AllowRebaseUpdate = allow + update(repoUnit.PullRequestsConfig()) require.NoError(t, repo_model.UpdateRepoUnitConfig(t.Context(), repoUnit)) } + setRepoAllowRebaseUpdate := func(t *testing.T, repoID int64, allow bool) { + updatePRConfig(t, repoID, func(c *repo_model.PullRequestsConfig) { c.AllowRebaseUpdate = allow }) + } + setRepoAllowMergeUpdate := func(t *testing.T, repoID int64, allow bool) { + updatePRConfig(t, repoID, func(c *repo_model.PullRequestsConfig) { c.AllowMergeUpdate = allow }) + } + checkUserAllowedToUpdate := func(ctx context.Context, pull *issues_model.PullRequest, user *user_model.User) (bool, bool, repo_model.UpdateStyle, error) { + ret, err := CheckUserAllowedToUpdate(ctx, pull, user) + return ret.MergeAllowed, ret.RebaseAllowed, ret.DefaultUpdateStyle, err + } user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) @@ -43,21 +54,33 @@ func TestIsUserAllowedToUpdate(t *testing.T) { require.NoError(t, err) defer db.DeleteByBean(t.Context(), protectedBranch) - pushAllowed, rebaseAllowed, err := IsUserAllowedToUpdate(t.Context(), pr2, user2) + pushAllowed, rebaseAllowed, defaultMergeStyle, err := checkUserAllowedToUpdate(t.Context(), pr2, user2) assert.NoError(t, err) assert.False(t, pushAllowed) assert.False(t, rebaseAllowed) + assert.Equal(t, repo_model.UpdateStyleMerge, defaultMergeStyle) }) t.Run("DisallowRebaseWhenConfigDisabled", func(t *testing.T) { pr2 := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}) setRepoAllowRebaseUpdate(t, pr2.BaseRepoID, false) - pushAllowed, rebaseAllowed, err := IsUserAllowedToUpdate(t.Context(), pr2, user2) + pushAllowed, rebaseAllowed, _, err := checkUserAllowedToUpdate(t.Context(), pr2, user2) assert.NoError(t, err) assert.True(t, pushAllowed) assert.False(t, rebaseAllowed) }) + t.Run("DisallowMergeWhenConfigDisabled", func(t *testing.T) { + pr2 := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}) + setRepoAllowRebaseUpdate(t, pr2.BaseRepoID, true) + setRepoAllowMergeUpdate(t, pr2.BaseRepoID, false) + pushAllowed, rebaseAllowed, _, err := checkUserAllowedToUpdate(t.Context(), pr2, user2) + assert.NoError(t, err) + assert.False(t, pushAllowed) + assert.True(t, rebaseAllowed) + setRepoAllowMergeUpdate(t, pr2.BaseRepoID, true) + }) + t.Run("ReadOnlyAccessDenied", func(t *testing.T) { pr2 := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}) user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) @@ -73,7 +96,7 @@ func TestIsUserAllowedToUpdate(t *testing.T) { require.NoError(t, pr2.LoadHeadRepo(t.Context())) assert.NoError(t, access_model.RecalculateUserAccess(t.Context(), pr2.HeadRepo, user4.ID)) - pushAllowed, rebaseAllowed, err := IsUserAllowedToUpdate(t.Context(), pr2, user4) + pushAllowed, rebaseAllowed, _, err := checkUserAllowedToUpdate(t.Context(), pr2, user4) assert.NoError(t, err) assert.False(t, pushAllowed) assert.False(t, rebaseAllowed) @@ -91,7 +114,7 @@ func TestIsUserAllowedToUpdate(t *testing.T) { require.NoError(t, err) defer db.DeleteByBean(t.Context(), protectedBranch) - pushAllowed, rebaseAllowed, err := IsUserAllowedToUpdate(t.Context(), pr2, user2) + pushAllowed, rebaseAllowed, _, err := checkUserAllowedToUpdate(t.Context(), pr2, user2) assert.NoError(t, err) assert.True(t, pushAllowed) assert.False(t, rebaseAllowed) @@ -102,7 +125,7 @@ func TestIsUserAllowedToUpdate(t *testing.T) { t.Run("MaintainerEditRespectsPosterPermissions", func(t *testing.T) { pr3 := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 3}) pr3.AllowMaintainerEdit = true - pushAllowed, rebaseAllowed, err := IsUserAllowedToUpdate(t.Context(), pr3, pr3Poster) + pushAllowed, rebaseAllowed, _, err := checkUserAllowedToUpdate(t.Context(), pr3, pr3Poster) assert.NoError(t, err) assert.False(t, pushAllowed) assert.False(t, rebaseAllowed) @@ -132,7 +155,7 @@ func TestIsUserAllowedToUpdate(t *testing.T) { require.NoError(t, pr3.LoadHeadRepo(t.Context())) assert.NoError(t, access_model.RecalculateUserAccess(t.Context(), pr3.HeadRepo, pr3Poster.ID)) - pushAllowed, rebaseAllowed, err := IsUserAllowedToUpdate(t.Context(), pr3, pr3Poster) + pushAllowed, rebaseAllowed, _, err := checkUserAllowedToUpdate(t.Context(), pr3, pr3Poster) assert.NoError(t, err) assert.True(t, pushAllowed) assert.True(t, rebaseAllowed) @@ -164,7 +187,7 @@ func TestIsUserAllowedToUpdate(t *testing.T) { setRepoAllowRebaseUpdate(t, pr3.BaseRepoID, false) - pushAllowed, rebaseAllowed, err := IsUserAllowedToUpdate(t.Context(), pr3, pr3Poster) + pushAllowed, rebaseAllowed, _, err := checkUserAllowedToUpdate(t.Context(), pr3, pr3Poster) assert.NoError(t, err) assert.True(t, pushAllowed) assert.False(t, rebaseAllowed) diff --git a/package/gitea/source/services/release/notes.go b/package/gitea/source/services/release/notes.go index 92ee22e6..bf41d342 100644 --- a/package/gitea/source/services/release/notes.go +++ b/package/gitea/source/services/release/notes.go @@ -10,12 +10,13 @@ import ( "slices" "strings" - issues_model "code.gitea.io/gitea/models/issues" - 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/git" - "code.gitea.io/gitea/modules/util" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/container" + "gitea.dev/modules/git" + "gitea.dev/modules/util" ) // GenerateReleaseNotesOptions describes how to build release notes content. @@ -25,27 +26,32 @@ type GenerateReleaseNotesOptions struct { PreviousTag string } -// GenerateReleaseNotes builds the markdown snippet for release notes. +// GenerateReleaseNotes builds the Markdown snippet for release notes. func GenerateReleaseNotes(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, opts GenerateReleaseNotesOptions) (string, error) { headCommit, err := resolveHeadCommit(gitRepo, opts.TagName, opts.TagTarget) if err != nil { return "", err } - if opts.PreviousTag == "" { - // no previous tag, usually due to there is no tag in the repo, use the same content as GitHub - content := fmt.Sprintf("**Full Changelog**: %s/commits/tag/%s\n", repo.HTMLURL(ctx), util.PathEscapeSegments(opts.TagName)) - return content, nil + isFirstRelease, err := repoReleaseIsEmpty(ctx, repo.ID) + if err != nil { + return "", fmt.Errorf("repoReleaseIsEmpty: %w", err) } - baseCommit, err := gitRepo.GetCommit(opts.PreviousTag) - if err != nil { + var baseCommitID git.RefName + if opts.PreviousTag != "" { + baseCommit, err := gitRepo.GetCommit(opts.PreviousTag) + if err != nil { + return "", util.ErrorWrapTranslatable(util.ErrNotExist, "repo.release.generate_notes_tag_not_found", opts.PreviousTag) + } + baseCommitID = baseCommit.ID.RefName() + } else if !isFirstRelease { return "", util.ErrorWrapTranslatable(util.ErrNotExist, "repo.release.generate_notes_tag_not_found", opts.TagName) } - commits, err := gitRepo.CommitsBetweenIDs(headCommit.ID.String(), baseCommit.ID.String()) + commits, err := gitRepo.CommitsBetween(headCommit.ID.RefName(), baseCommitID, -1) if err != nil { - return "", fmt.Errorf("CommitsBetweenIDs: %w", err) + return "", fmt.Errorf("CommitsBetween: %w", err) } prs, err := collectPullRequestsFromCommits(ctx, repo.ID, commits) @@ -58,10 +64,27 @@ func GenerateReleaseNotes(ctx context.Context, repo *repo_model.Repository, gitR return "", err } - content := buildReleaseNotesContent(ctx, repo, opts.TagName, opts.PreviousTag, prs, contributors, newContributors) + fullChangelogURL := "" + if isFirstRelease { + // Keep the first-release changelog link aligned with GitHub, while collecting PRs from full history. + fullChangelogURL = fmt.Sprintf("%s/commits/tag/%s", repo.HTMLURL(ctx), util.PathEscapeSegments(opts.TagName)) + } + + content := buildReleaseNotesContent(ctx, repo, opts.TagName, opts.PreviousTag, prs, contributors, newContributors, fullChangelogURL) return content, nil } +func repoReleaseIsEmpty(ctx context.Context, repoID int64) (bool, error) { + count, err := db.Count[repo_model.Release](ctx, repo_model.FindReleasesOptions{ + RepoID: repoID, + IncludeDrafts: false, + }) + if err != nil { + return false, err + } + return count == 0, nil +} + func resolveHeadCommit(gitRepo *git.Repository, tagName, tagTarget string) (*git.Commit, error) { ref := tagName if !gitRepo.IsTagExist(tagName) { @@ -107,7 +130,7 @@ func collectPullRequestsFromCommits(ctx context.Context, repoID int64, commits [ return prs, nil } -func buildReleaseNotesContent(ctx context.Context, repo *repo_model.Repository, tagName, baseRef string, prs []*issues_model.PullRequest, contributors []*user_model.User, newContributors []*issues_model.PullRequest) string { +func buildReleaseNotesContent(ctx context.Context, repo *repo_model.Repository, tagName, baseRef string, prs []*issues_model.PullRequest, contributors []*user_model.User, newContributors []*issues_model.PullRequest, fullChangelogURL string) string { var builder strings.Builder builder.WriteString("## What's Changed\n") @@ -136,8 +159,12 @@ func buildReleaseNotesContent(ctx context.Context, repo *repo_model.Repository, } builder.WriteString("**Full Changelog**: ") - compareURL := fmt.Sprintf("%s/compare/%s...%s", repo.HTMLURL(ctx), util.PathEscapeSegments(baseRef), util.PathEscapeSegments(tagName)) - fmt.Fprintf(&builder, "[%s...%s](%s)", baseRef, tagName, compareURL) + if fullChangelogURL != "" { + builder.WriteString(fullChangelogURL) + } else { + compareURL := fmt.Sprintf("%s/compare/%s...%s", repo.HTMLURL(ctx), util.PathEscapeSegments(baseRef), util.PathEscapeSegments(tagName)) + fmt.Fprintf(&builder, "[%s...%s](%s)", baseRef, tagName, compareURL) + } builder.WriteByte('\n') return builder.String() } diff --git a/package/gitea/source/services/release/notes_test.go b/package/gitea/source/services/release/notes_test.go index 211c364d..3fb3b7c5 100644 --- a/package/gitea/source/services/release/notes_test.go +++ b/package/gitea/source/services/release/notes_test.go @@ -6,13 +6,13 @@ package release import ( "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/gitrepo" - "code.gitea.io/gitea/modules/timeutil" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/timeutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -21,13 +21,14 @@ import ( func TestGenerateReleaseNotes(t *testing.T) { unittest.PrepareTestEnv(t) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - gitRepo, err := gitrepo.OpenRepository(t.Context(), repo) - require.NoError(t, err) - t.Run("ChangeLogsWithPRs", func(t *testing.T) { + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + gitRepo, err := gitrepo.OpenRepository(t.Context(), repo) + require.NoError(t, err) + t.Cleanup(func() { gitRepo.Close() }) + mergedCommit := "90c1019714259b24fb81711d4416ac0f18667dfa" - createMergedPullRequest(t, repo, mergedCommit, 5) + createMergedPullRequest(t, repo, mergedCommit, 5, "Release notes test pull request") content, err := GenerateReleaseNotes(t.Context(), repo, gitRepo, GenerateReleaseNotesOptions{ TagName: "v1.2.0", @@ -50,16 +51,51 @@ func TestGenerateReleaseNotes(t *testing.T) { }) t.Run("NoPreviousTag", func(t *testing.T) { + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) + gitRepo, err := gitrepo.OpenRepository(t.Context(), repo) + require.NoError(t, err) + t.Cleanup(func() { gitRepo.Close() }) + + createMergedPullRequest(t, repo, "69554a64c1e6030f051e5c3f94bfbd773cd6a324", 5, "Initial tag PR 1") + createMergedPullRequest(t, repo, "27566bd5738fc8b4e3fef3c5e72cce608537bd95", 4, "Initial tag PR 2") + createMergedPullRequest(t, repo, "5099b81332712fe655e34e8dd63574f503f61811", 8, "Initial tag PR 3") + content, err := GenerateReleaseNotes(t.Context(), repo, gitRepo, GenerateReleaseNotesOptions{ - TagName: "v1.2.0", - TagTarget: "DefaultBranch", + TagName: "v0.1.0", + TagTarget: repo.DefaultBranch, }) require.NoError(t, err) - assert.Equal(t, "**Full Changelog**: https://try.gitea.io/user2/repo1/commits/tag/v1.2.0\n", content) + + assert.Contains(t, content, "## What's Changed\n") + assert.Contains(t, content, "* Initial tag PR 1 in [#") + assert.Contains(t, content, "* Initial tag PR 2 in [#") + assert.Contains(t, content, "* Initial tag PR 3 in [#") + assert.Contains(t, content, "\n## Contributors\n") + assert.Contains(t, content, "* @user5\n") + assert.Contains(t, content, "* @user4\n") + assert.Contains(t, content, "* @user8\n") + assert.Contains(t, content, "\n## New Contributors\n") + assert.Contains(t, content, "* @user5 made their first contribution in [#") + assert.Contains(t, content, "* @user4 made their first contribution in [#") + assert.Contains(t, content, "* @user8 made their first contribution in [#") + assert.Contains(t, content, "**Full Changelog**: https://try.gitea.io/user2/repo16/commits/tag/v0.1.0\n") + }) + + t.Run("EmptyPreviousTagWithExistingTags", func(t *testing.T) { + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + gitRepo, err := gitrepo.OpenRepository(t.Context(), repo) + require.NoError(t, err) + t.Cleanup(func() { gitRepo.Close() }) + + _, err = GenerateReleaseNotes(t.Context(), repo, gitRepo, GenerateReleaseNotesOptions{ + TagName: "v1.2.0", + TagTarget: repo.DefaultBranch, + }) + require.Error(t, err) }) } -func createMergedPullRequest(t *testing.T, repo *repo_model.Repository, mergeCommit string, posterID int64) *issues_model.PullRequest { +func createMergedPullRequest(t *testing.T, repo *repo_model.Repository, mergeCommit string, posterID int64, title string) *issues_model.PullRequest { user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: posterID}) issue := &issues_model.Issue{ @@ -67,7 +103,7 @@ func createMergedPullRequest(t *testing.T, repo *repo_model.Repository, mergeCom Repo: repo, Poster: user, PosterID: user.ID, - Title: "Release notes test pull request", + Title: title, Content: "content", } diff --git a/package/gitea/source/services/release/release.go b/package/gitea/source/services/release/release.go index a4825011..5d4063c0 100644 --- a/package/gitea/source/services/release/release.go +++ b/package/gitea/source/services/release/release.go @@ -9,21 +9,23 @@ import ( "fmt" "strings" - "code.gitea.io/gitea/models/db" - git_model "code.gitea.io/gitea/models/git" - 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/git" - "code.gitea.io/gitea/modules/git/gitcmd" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/storage" - "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/util" - notify_service "code.gitea.io/gitea/services/notify" + "gitea.dev/models/db" + git_model "gitea.dev/models/git" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/container" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/graceful" + "gitea.dev/modules/log" + "gitea.dev/modules/repository" + "gitea.dev/modules/setting" + "gitea.dev/modules/storage" + "gitea.dev/modules/timeutil" + "gitea.dev/modules/util" + "gitea.dev/services/context/upload" + notify_service "gitea.dev/services/notify" ) // ErrInvalidTagName represents a "InvalidTagName" kind of error. @@ -319,13 +321,17 @@ func UpdateRelease(ctx context.Context, doer *user_model.User, gitRepo *git.Repo } for uuid, newName := range editAttachments { - if !deletedUUIDs.Contains(uuid) { - if err = repo_model.UpdateAttachmentByUUID(ctx, &repo_model.Attachment{ - UUID: uuid, - Name: newName, - }, "name"); err != nil { - return err - } + if deletedUUIDs.Contains(uuid) { + continue + } + if err = upload.Verify(nil, newName, setting.Repository.Release.AllowedTypes); err != nil { + return err + } + if err = repo_model.UpdateAttachmentByUUID(ctx, &repo_model.Attachment{ + UUID: uuid, + Name: newName, + }, "name"); err != nil { + return err } } } diff --git a/package/gitea/source/services/release/release_test.go b/package/gitea/source/services/release/release_test.go index ef495632..1c0f910b 100644 --- a/package/gitea/source/services/release/release_test.go +++ b/package/gitea/source/services/release/release_test.go @@ -8,13 +8,17 @@ import ( "testing" "time" - 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/gitrepo" - "code.gitea.io/gitea/services/attachment" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/setting" + "gitea.dev/modules/test" + "gitea.dev/modules/timeutil" + "gitea.dev/services/attachment" + "gitea.dev/services/context/upload" - _ "code.gitea.io/gitea/models/actions" + _ "gitea.dev/models/actions" "github.com/stretchr/testify/assert" ) @@ -138,6 +142,12 @@ func TestRelease_Update(t *testing.T) { assert.NoError(t, err) defer gitRepo.Close() + // Advance a mocked clock between create and update instead of sleeping, so the + // timestamp-sensitive assertions below stay deterministic. + fakeNow := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC) + defer timeutil.MockSet(fakeNow)() + advance := func() { fakeNow = fakeNow.Add(time.Second); timeutil.MockSet(fakeNow) } + // Test a changed release assert.NoError(t, CreateRelease(gitRepo, &repo_model.Release{ RepoID: repo.ID, @@ -155,7 +165,7 @@ func TestRelease_Update(t *testing.T) { release, err := repo_model.GetRelease(t.Context(), repo.ID, "v1.1.1") assert.NoError(t, err) releaseCreatedUnix := release.CreatedUnix - time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp + advance() release.Note = "Changed note" assert.NoError(t, UpdateRelease(t.Context(), user, gitRepo, release, nil, nil, nil)) release, err = repo_model.GetReleaseByID(t.Context(), release.ID) @@ -179,7 +189,7 @@ func TestRelease_Update(t *testing.T) { release, err = repo_model.GetRelease(t.Context(), repo.ID, "v1.2.1") assert.NoError(t, err) releaseCreatedUnix = release.CreatedUnix - time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp + advance() release.Title = "Changed title" assert.NoError(t, UpdateRelease(t.Context(), user, gitRepo, release, nil, nil, nil)) release, err = repo_model.GetReleaseByID(t.Context(), release.ID) @@ -203,7 +213,7 @@ func TestRelease_Update(t *testing.T) { release, err = repo_model.GetRelease(t.Context(), repo.ID, "v1.3.1") assert.NoError(t, err) releaseCreatedUnix = release.CreatedUnix - time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp + advance() release.Title = "Changed title" release.Note = "Changed note" assert.NoError(t, UpdateRelease(t.Context(), user, gitRepo, release, nil, nil, nil)) @@ -263,6 +273,17 @@ func TestRelease_Update(t *testing.T) { assert.Equal(t, release.ID, release.Attachments[0].ReleaseID) assert.Equal(t, "test2.txt", release.Attachments[0].Name) + defer test.MockVariableValue(&setting.Repository.Release.AllowedTypes, ".zip")() + err = UpdateRelease(t.Context(), user, gitRepo, release, nil, nil, map[string]string{ + attach.UUID: "test.exe", + }) + assert.Error(t, err) + assert.True(t, upload.IsErrFileTypeForbidden(err)) + release.Attachments = nil + assert.NoError(t, repo_model.GetReleaseAttachments(t.Context(), release)) + assert.Len(t, release.Attachments, 1) + assert.Equal(t, "test2.txt", release.Attachments[0].Name) + // delete the attachment assert.NoError(t, UpdateRelease(t.Context(), user, gitRepo, release, nil, []string{attach.UUID}, nil)) release.Attachments = nil @@ -280,6 +301,12 @@ func TestRelease_createTag(t *testing.T) { assert.NoError(t, err) defer gitRepo.Close() + // Advance a mocked clock between create and update instead of sleeping, so the + // timestamp-sensitive assertions below stay deterministic. + fakeNow := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC) + defer timeutil.MockSet(fakeNow)() + advance := func() { fakeNow = fakeNow.Add(time.Second); timeutil.MockSet(fakeNow) } + // Test a changed release release := &repo_model.Release{ RepoID: repo.ID, @@ -298,7 +325,7 @@ func TestRelease_createTag(t *testing.T) { assert.NoError(t, err) assert.NotEmpty(t, release.CreatedUnix) releaseCreatedUnix := release.CreatedUnix - time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp + advance() release.Note = "Changed note" _, err = createTag(t.Context(), gitRepo, release, "") assert.NoError(t, err) @@ -321,7 +348,7 @@ func TestRelease_createTag(t *testing.T) { _, err = createTag(t.Context(), gitRepo, release, "") assert.NoError(t, err) releaseCreatedUnix = release.CreatedUnix - time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp + advance() release.Title = "Changed title" _, err = createTag(t.Context(), gitRepo, release, "") assert.NoError(t, err) @@ -344,7 +371,7 @@ func TestRelease_createTag(t *testing.T) { _, err = createTag(t.Context(), gitRepo, release, "") assert.NoError(t, err) releaseCreatedUnix = release.CreatedUnix - time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp + advance() release.Title = "Changed title" release.Note = "Changed note" _, err = createTag(t.Context(), gitRepo, release, "") diff --git a/package/gitea/source/services/release/tag.go b/package/gitea/source/services/release/tag.go index dae2b70f..2a880733 100644 --- a/package/gitea/source/services/release/tag.go +++ b/package/gitea/source/services/release/tag.go @@ -8,12 +8,12 @@ import ( "errors" "fmt" - "code.gitea.io/gitea/models/db" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/queue" - repo_module "code.gitea.io/gitea/modules/repository" + "gitea.dev/models/db" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/graceful" + "gitea.dev/modules/log" + "gitea.dev/modules/queue" + repo_module "gitea.dev/modules/repository" "xorm.io/builder" ) diff --git a/package/gitea/source/services/repository/adopt.go b/package/gitea/source/services/repository/adopt.go index 1255967e..a05cfb66 100644 --- a/package/gitea/source/services/repository/adopt.go +++ b/package/gitea/source/services/repository/adopt.go @@ -11,19 +11,19 @@ import ( "path/filepath" "strings" - "code.gitea.io/gitea/models/db" - git_model "code.gitea.io/gitea/models/git" - 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/gitrepo" - "code.gitea.io/gitea/modules/glob" - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/optional" - repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/setting" - notify_service "code.gitea.io/gitea/services/notify" + "gitea.dev/models/db" + git_model "gitea.dev/models/git" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/container" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/glob" + "gitea.dev/modules/graceful" + "gitea.dev/modules/log" + "gitea.dev/modules/optional" + repo_module "gitea.dev/modules/repository" + "gitea.dev/modules/setting" + notify_service "gitea.dev/services/notify" ) func deleteFailedAdoptRepository(repoID int64) error { diff --git a/package/gitea/source/services/repository/adopt_test.go b/package/gitea/source/services/repository/adopt_test.go index a7de9180..89a506f6 100644 --- a/package/gitea/source/services/repository/adopt_test.go +++ b/package/gitea/source/services/repository/adopt_test.go @@ -9,12 +9,12 @@ import ( "path/filepath" "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" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" + "gitea.dev/models/db" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/modules/setting" + "gitea.dev/modules/util" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/repository/archiver/archiver.go b/package/gitea/source/services/repository/archiver/archiver.go index f7069f22..b73d4667 100644 --- a/package/gitea/source/services/repository/archiver/archiver.go +++ b/package/gitea/source/services/repository/archiver/archiver.go @@ -12,20 +12,20 @@ import ( "strings" "time" - "code.gitea.io/gitea/models/db" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/git/gitcmd" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/httplib" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/process" - "code.gitea.io/gitea/modules/queue" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/storage" - "code.gitea.io/gitea/modules/util" - gitea_context "code.gitea.io/gitea/services/context" + "gitea.dev/models/db" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/graceful" + "gitea.dev/modules/httplib" + "gitea.dev/modules/log" + "gitea.dev/modules/process" + "gitea.dev/modules/queue" + "gitea.dev/modules/setting" + "gitea.dev/modules/storage" + "gitea.dev/modules/util" + gitea_context "gitea.dev/services/context" ) // ArchiveRequest defines the parameters of an archive request, which notably @@ -42,6 +42,38 @@ type ArchiveRequest struct { archiveRefShortName string // the ref short name to download the archive, for example: "master", "v1.0.0", "commit id" } +type archiveQueueItem struct { + RepoID int64 `json:"RepoID"` + Type repo_model.ArchiveType `json:"Type"` + CommitID string `json:"CommitID"` + Paths []string `json:"Paths,omitempty"` + ArchiveRefShortName string `json:"ArchiveRefShortName,omitempty"` +} + +func (aReq *ArchiveRequest) toQueueItem() *archiveQueueItem { + return &archiveQueueItem{ + RepoID: aReq.Repo.ID, + Type: aReq.Type, + CommitID: aReq.CommitID, + Paths: aReq.Paths, + ArchiveRefShortName: aReq.archiveRefShortName, + } +} + +func (item *archiveQueueItem) toArchiveRequest(ctx context.Context) (*ArchiveRequest, error) { + repo, err := repo_model.GetRepositoryByID(ctx, item.RepoID) + if err != nil { + return nil, err + } + return &ArchiveRequest{ + Repo: repo, + Type: item.Type, + CommitID: item.CommitID, + Paths: item.Paths, + archiveRefShortName: item.ArchiveRefShortName, + }, nil +} + // NewRequest creates an archival request, based on the URI. The // resulting ArchiveRequest is suitable for being passed to Await() // if it's determined that the request still needs to be satisfied. @@ -56,13 +88,13 @@ func NewRequest(repo *repo_model.Repository, gitRepo *git.Repository, archiveRef } // Get corresponding commit. - commitID, err := gitRepo.ConvertToGitID(archiveRefShortName) + commit, err := gitRepo.GetCommit(archiveRefShortName) if err != nil { return nil, util.NewNotExistErrorf("unrecognized repository reference: %s", archiveRefShortName) } r := &ArchiveRequest{Repo: repo, archiveRefShortName: archiveRefShortName, Type: archiveType, Paths: paths} - r.CommitID = commitID.String() + r.CommitID = commit.ID.String() return r, nil } @@ -227,13 +259,18 @@ func doArchive(ctx context.Context, r *ArchiveRequest) (*repo_model.RepoArchiver return archiver, nil } -var archiverQueue *queue.WorkerPoolQueue[*ArchiveRequest] +var archiverQueue *queue.WorkerPoolQueue[*archiveQueueItem] // Init initializes archiver func Init(ctx context.Context) error { - handler := func(items ...*ArchiveRequest) []*ArchiveRequest { - for _, archiveReq := range items { - log.Trace("ArchiverData Process: %#v", archiveReq) + handler := func(items ...*archiveQueueItem) []*archiveQueueItem { + for _, item := range items { + log.Trace("ArchiverData Process: %#v", item) + archiveReq, err := item.toArchiveRequest(ctx) + if err != nil { + log.Error("Archive repo %d: %v", item.RepoID, err) + continue + } if archiver, err := doArchive(ctx, archiveReq); err != nil { log.Error("Archive %v failed: %v", archiveReq, err) } else { @@ -254,14 +291,15 @@ func Init(ctx context.Context) error { // StartArchive push the archive request to the queue func StartArchive(request *ArchiveRequest) error { - has, err := archiverQueue.Has(request) + item := request.toQueueItem() + has, err := archiverQueue.Has(item) if err != nil { return err } if has { return nil } - return archiverQueue.Push(request) + return archiverQueue.Push(item) } func deleteOldRepoArchiver(ctx context.Context, archiver *repo_model.RepoArchiver) error { @@ -330,7 +368,7 @@ func ServeRepoArchive(ctx *gitea_context.Base, archiveReq *ArchiveRequest) error // because errors may happen in git command and such cases aren't in our control. httplib.ServeSetHeaders(ctx.Resp, httplib.ServeHeaderOptions{Filename: downloadName}) if err := archiveReq.Stream(ctx, ctx.Resp); err != nil && !ctx.Written() { - if gitcmd.StderrHasPrefix(err, "fatal: pathspec") { + if gitcmd.IsStderr(err, gitcmd.StderrPathSpec) || gitcmd.IsStderr(err, gitcmd.StderrNotTreeObject) { return util.NewInvalidArgumentErrorf("path doesn't exist or is invalid") } return fmt.Errorf("archive repo %s: failed to stream: %w", archiveReq.Repo.FullName(), err) diff --git a/package/gitea/source/services/repository/archiver/archiver_test.go b/package/gitea/source/services/repository/archiver/archiver_test.go index 6cc1856a..8829ac1b 100644 --- a/package/gitea/source/services/repository/archiver/archiver_test.go +++ b/package/gitea/source/services/repository/archiver/archiver_test.go @@ -7,11 +7,13 @@ import ( "testing" "time" - "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/services/contexttest" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + "gitea.dev/modules/json" + "gitea.dev/modules/util" + "gitea.dev/services/contexttest" - _ "code.gitea.io/gitea/models/actions" + _ "gitea.dev/models/actions" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -21,6 +23,22 @@ func TestMain(m *testing.M) { unittest.MainTest(m) } +func TestArchiveQueueItemJSON(t *testing.T) { + orig := &archiveQueueItem{ + RepoID: 7, + Type: repo_model.ArchiveZip, + CommitID: "abc123", + Paths: []string{"agents"}, + ArchiveRefShortName: "main", + } + bs, err := json.Marshal(orig) + require.NoError(t, err) + + var decoded archiveQueueItem + require.NoError(t, json.Unmarshal(bs, &decoded)) + assert.Equal(t, *orig, decoded) +} + func TestArchive_Basic(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) diff --git a/package/gitea/source/services/repository/avatar.go b/package/gitea/source/services/repository/avatar.go index 7ab6badf..fabe8dea 100644 --- a/package/gitea/source/services/repository/avatar.go +++ b/package/gitea/source/services/repository/avatar.go @@ -9,11 +9,11 @@ import ( "io" "strconv" - "code.gitea.io/gitea/models/db" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/avatar" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/storage" + "gitea.dev/models/db" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/avatar" + "gitea.dev/modules/log" + "gitea.dev/modules/storage" ) // UploadAvatar saves custom avatar for repository. diff --git a/package/gitea/source/services/repository/avatar_test.go b/package/gitea/source/services/repository/avatar_test.go index 6c7b9e6d..67f41a1b 100644 --- a/package/gitea/source/services/repository/avatar_test.go +++ b/package/gitea/source/services/repository/avatar_test.go @@ -9,9 +9,9 @@ import ( "image/png" "testing" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/avatar" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + "gitea.dev/modules/avatar" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/repository/branch.go b/package/gitea/source/services/repository/branch.go index 1a5c2392..f580883d 100644 --- a/package/gitea/source/services/repository/branch.go +++ b/package/gitea/source/services/repository/branch.go @@ -9,30 +9,30 @@ import ( "fmt" "strings" - actions_model "code.gitea.io/gitea/models/actions" - "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" - 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/cache" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/json" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/optional" - "code.gitea.io/gitea/modules/queue" - repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/reqctx" - "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/util" - webhook_module "code.gitea.io/gitea/modules/webhook" - actions_service "code.gitea.io/gitea/services/actions" - notify_service "code.gitea.io/gitea/services/notify" - release_service "code.gitea.io/gitea/services/release" + actions_model "gitea.dev/models/actions" + "gitea.dev/models/db" + git_model "gitea.dev/models/git" + issues_model "gitea.dev/models/issues" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unit" + user_model "gitea.dev/models/user" + "gitea.dev/modules/cache" + "gitea.dev/modules/git" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/graceful" + "gitea.dev/modules/json" + "gitea.dev/modules/log" + "gitea.dev/modules/optional" + "gitea.dev/modules/queue" + repo_module "gitea.dev/modules/repository" + "gitea.dev/modules/reqctx" + "gitea.dev/modules/timeutil" + "gitea.dev/modules/util" + webhook_module "gitea.dev/modules/webhook" + actions_service "gitea.dev/services/actions" + notify_service "gitea.dev/services/notify" + release_service "gitea.dev/services/release" "xorm.io/builder" ) @@ -59,9 +59,9 @@ type Branch struct { } // LoadBranches loads branches from the repository limited by page & pageSize. -func LoadBranches(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, isDeletedBranch optional.Option[bool], keyword string, page, pageSize int) (*Branch, []*Branch, int64, error) { - defaultDBBranch, err := git_model.GetBranch(ctx, repo.ID, repo.DefaultBranch) - if err != nil { +func LoadBranches(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, isDeletedBranch optional.Option[bool], keyword string, page, pageSize int) (defaultBranchOptional *Branch, _ []*Branch, _ int64, _ error) { + defaultDBBranchOptional, err := git_model.GetBranch(ctx, repo.ID, repo.DefaultBranch) + if err != nil && !errors.Is(err, util.ErrNotExist) { return nil, nil, 0, err } @@ -108,13 +108,14 @@ func LoadBranches(ctx context.Context, repo *repo_model.Repository, gitRepo *git branches = append(branches, branch) } - // Always add the default branch - log.Debug("loadOneBranch: load default: '%s'", defaultDBBranch.Name) - defaultBranch, err := loadOneBranch(ctx, repo, defaultDBBranch, &rules, repoIDToRepo, repoIDToGitRepo) - if err != nil { - return nil, nil, 0, fmt.Errorf("loadOneBranch: %v", err) + if defaultDBBranchOptional != nil { + // Always add the default branch + defaultBranchOptional, err = loadOneBranch(ctx, repo, defaultDBBranchOptional, &rules, repoIDToRepo, repoIDToGitRepo) + if err != nil { + return nil, nil, 0, fmt.Errorf("loadOneBranch: %v", err) + } } - return defaultBranch, branches, totalNumOfBranches, nil + return defaultBranchOptional, branches, totalNumOfBranches, nil } func getDivergenceCacheKey(repoID int64, branchName string) string { @@ -359,7 +360,7 @@ func SyncBranchesToDB(ctx context.Context, repoID, pusherID int64, branchNames, RepoID: repoID, Name: branchName, CommitID: commit.ID.String(), - CommitMessage: commit.Summary(), + CommitMessage: commit.MessageTitle(), PusherID: pusherID, CommitTime: timeutil.TimeStamp(commit.Committer.When.Unix()), }) @@ -640,7 +641,7 @@ func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.R func deleteBranchSuccessPostProcess(doer *user_model.User, repo *repo_model.Repository, branchName string, branchCommit *git.Commit) { objectFormat := git.ObjectFormatFromName(repo.ObjectFormatName) - if err := PushUpdate( + if err := PushUpdates( &repo_module.PushUpdateOptions{ RefFullName: git.RefNameFromBranch(branchName), OldCommitID: branchCommit.ID.String(), diff --git a/package/gitea/source/services/repository/cache.go b/package/gitea/source/services/repository/cache.go index 4fc8d3dd..ff1955f1 100644 --- a/package/gitea/source/services/repository/cache.go +++ b/package/gitea/source/services/repository/cache.go @@ -6,10 +6,10 @@ package repository import ( "context" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/cache" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/gitrepo" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/cache" + "gitea.dev/modules/git" + "gitea.dev/modules/gitrepo" ) // CacheRef cachhe last commit information of the branch or the tag diff --git a/package/gitea/source/services/repository/check.go b/package/gitea/source/services/repository/check.go index 4ae49d81..8f731861 100644 --- a/package/gitea/source/services/repository/check.go +++ b/package/gitea/source/services/repository/check.go @@ -9,14 +9,14 @@ import ( "strings" "time" - "code.gitea.io/gitea/models/db" - repo_model "code.gitea.io/gitea/models/repo" - system_model "code.gitea.io/gitea/models/system" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/git/gitcmd" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/log" - repo_module "code.gitea.io/gitea/modules/repository" + "gitea.dev/models/db" + repo_model "gitea.dev/models/repo" + system_model "gitea.dev/models/system" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/log" + repo_module "gitea.dev/modules/repository" "xorm.io/builder" ) diff --git a/package/gitea/source/services/repository/collaboration.go b/package/gitea/source/services/repository/collaboration.go index cb56d90a..37c41a8a 100644 --- a/package/gitea/source/services/repository/collaboration.go +++ b/package/gitea/source/services/repository/collaboration.go @@ -8,18 +8,20 @@ import ( "context" "fmt" - "code.gitea.io/gitea/models/db" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/perm" - 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" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + "gitea.dev/models/perm" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" "xorm.io/builder" ) func AddOrUpdateCollaborator(ctx context.Context, repo *repo_model.Repository, u *user_model.User, mode perm.AccessMode) error { - // only allow valid access modes, read, write and admin + // Only allow valid access modes, read, write and admin + // Keep in mind: do not allow "owner" here: because "admin" user can update collaborators but not make dangerous operations. + // If the "admin" user updates a user to "owner", then it means that the admin user can use owner permission, which is not expected. if mode < perm.AccessModeRead || mode > perm.AccessModeAdmin { return perm.ErrInvalidAccessMode } @@ -100,7 +102,7 @@ func DeleteCollaboration(ctx context.Context, repo *repo_model.Repository, colla } func ReconsiderRepoIssuesAssignee(ctx context.Context, repo *repo_model.Repository, user *user_model.User) error { - if canAssigned, err := access_model.CanBeAssigned(ctx, user, repo, true); err != nil || canAssigned { + if canAssigned, err := access_model.CanBeAssigned(ctx, user, repo); err != nil || canAssigned { return err } diff --git a/package/gitea/source/services/repository/collaboration_test.go b/package/gitea/source/services/repository/collaboration_test.go index 56d9d72e..ce405919 100644 --- a/package/gitea/source/services/repository/collaboration_test.go +++ b/package/gitea/source/services/repository/collaboration_test.go @@ -6,13 +6,13 @@ package repository import ( "testing" - "code.gitea.io/gitea/models/db" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/perm" - access_model "code.gitea.io/gitea/models/perm/access" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + "gitea.dev/models/perm" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" "github.com/stretchr/testify/assert" ) @@ -20,16 +20,20 @@ import ( func TestRepository_AddCollaborator(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - testSuccess := func(repoID, userID int64) { - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) + user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) + testSuccess := func(repo *repo_model.Repository, user *user_model.User) { assert.NoError(t, repo.LoadOwner(t.Context())) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID}) assert.NoError(t, AddOrUpdateCollaborator(t.Context(), repo, user, perm.AccessModeWrite)) - unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repoID}, &user_model.User{ID: userID}) + unittest.CheckConsistencyFor(t, repo, user) } - testSuccess(1, 4) - testSuccess(1, 4) - testSuccess(3, 4) + testSuccess(repo1, user4) + testSuccess(repo1, user4) + testSuccess(repo3, user4) + + assert.Error(t, AddOrUpdateCollaborator(t.Context(), repo1, user4, perm.AccessModeOwner)) + assert.NoError(t, AddOrUpdateCollaborator(t.Context(), repo1, user4, perm.AccessModeAdmin)) } func TestRepository_DeleteCollaboration(t *testing.T) { diff --git a/package/gitea/source/services/repository/commit.go b/package/gitea/source/services/repository/commit.go index e8c0262e..3eb0e66b 100644 --- a/package/gitea/source/services/repository/commit.go +++ b/package/gitea/source/services/repository/commit.go @@ -7,8 +7,8 @@ import ( "context" "fmt" - "code.gitea.io/gitea/modules/util" - gitea_ctx "code.gitea.io/gitea/services/context" + "gitea.dev/modules/util" + gitea_ctx "gitea.dev/services/context" ) type ContainedLinks struct { // TODO: better name? diff --git a/package/gitea/source/services/repository/commitstatus/commitstatus.go b/package/gitea/source/services/repository/commitstatus/commitstatus.go index 26a8c614..63b31a1c 100644 --- a/package/gitea/source/services/repository/commitstatus/commitstatus.go +++ b/package/gitea/source/services/repository/commitstatus/commitstatus.go @@ -9,18 +9,18 @@ import ( "fmt" "slices" - "code.gitea.io/gitea/models/db" - git_model "code.gitea.io/gitea/models/git" - 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/commitstatus" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/json" - "code.gitea.io/gitea/modules/log" - repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/services/notify" + "gitea.dev/models/db" + git_model "gitea.dev/models/git" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/cache" + "gitea.dev/modules/commitstatus" + "gitea.dev/modules/git" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/json" + "gitea.dev/modules/log" + repo_module "gitea.dev/modules/repository" + "gitea.dev/services/notify" ) func getCacheKey(repoID int64, brancheName string) string { diff --git a/package/gitea/source/services/repository/contributors_graph.go b/package/gitea/source/services/repository/contributors_graph.go index 9953d61b..503ce968 100644 --- a/package/gitea/source/services/repository/contributors_graph.go +++ b/package/gitea/source/services/repository/contributors_graph.go @@ -13,16 +13,16 @@ import ( "sync" "time" - "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/git/gitcmd" - "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.dev/models/avatars" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/cache" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/graceful" + "gitea.dev/modules/log" + api "gitea.dev/modules/structs" ) const ( diff --git a/package/gitea/source/services/repository/contributors_graph_test.go b/package/gitea/source/services/repository/contributors_graph_test.go index efdecf4b..fb9695c1 100644 --- a/package/gitea/source/services/repository/contributors_graph_test.go +++ b/package/gitea/source/services/repository/contributors_graph_test.go @@ -7,10 +7,10 @@ import ( "slices" "testing" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/cache" - "code.gitea.io/gitea/modules/setting" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + "gitea.dev/modules/cache" + "gitea.dev/modules/setting" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/repository/create.go b/package/gitea/source/services/repository/create.go index 20a46c9c..e02c721c 100644 --- a/package/gitea/source/services/repository/create.go +++ b/package/gitea/source/services/repository/create.go @@ -12,32 +12,33 @@ import ( "strings" "time" - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/organization" - "code.gitea.io/gitea/models/perm" - access_model "code.gitea.io/gitea/models/perm/access" - repo_model "code.gitea.io/gitea/models/repo" - system_model "code.gitea.io/gitea/models/system" - "code.gitea.io/gitea/models/unit" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/git/gitcmd" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/options" - repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/setting" - api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/templates/vars" - "code.gitea.io/gitea/modules/util" + "gitea.dev/models/db" + "gitea.dev/models/organization" + "gitea.dev/models/perm" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + system_model "gitea.dev/models/system" + "gitea.dev/models/unit" + user_model "gitea.dev/models/user" + "gitea.dev/models/webhook" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/graceful" + "gitea.dev/modules/log" + "gitea.dev/modules/options" + repo_module "gitea.dev/modules/repository" + "gitea.dev/modules/setting" + api "gitea.dev/modules/structs" + "gitea.dev/modules/templates/vars" + "gitea.dev/modules/util" ) // CreateRepoOptions contains the create repository options type CreateRepoOptions struct { Name string Description string + Website string OriginalURL string GitServiceType api.GitServiceType Gitignores string @@ -151,6 +152,16 @@ func initRepository(ctx context.Context, u *user_model.User, repo *repo_model.Re return fmt.Errorf("createDelegateHooks: %w", err) } + repo.DefaultBranch = util.IfZero(opts.DefaultBranch, setting.Repository.DefaultBranch) + repo.DefaultWikiBranch = setting.Repository.DefaultBranch + if !opts.AutoInit { + repo.IsEmpty = true + } + + if err = repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "is_empty", "default_branch", "default_wiki_branch"); err != nil { + return fmt.Errorf("updateRepository: %w", err) + } + // Initialize repository according to user's choice. if opts.AutoInit { tmpDir, cleanup, err := setting.AppDataTempDir("git-repo-content").MkdirTempRandom("repos-" + repo.Name) @@ -164,39 +175,22 @@ func initRepository(ctx context.Context, u *user_model.User, repo *repo_model.Re } // Apply changes and commit. - if err = initRepoCommit(ctx, tmpDir, repo, u, opts.DefaultBranch); err != nil { + if err = initRepoCommit(ctx, tmpDir, repo, u); err != nil { return fmt.Errorf("initRepoCommit: %w", err) } } - // Re-fetch the repository from database before updating it (else it would - // override changes that were done earlier with sql) + if err = gitrepo.SetDefaultBranch(ctx, repo, repo.DefaultBranch); err != nil { + return fmt.Errorf("setDefaultBranch: %w", err) + } + + // Re-fetch the repository from database before updating it (keep changes that were done earlier with SQL) if repo, err = repo_model.GetRepositoryByID(ctx, repo.ID); err != nil { return fmt.Errorf("getRepositoryByID: %w", err) } - if !opts.AutoInit { - repo.IsEmpty = true - } - - repo.DefaultBranch = setting.Repository.DefaultBranch - repo.DefaultWikiBranch = setting.Repository.DefaultBranch - - if len(opts.DefaultBranch) > 0 { - repo.DefaultBranch = opts.DefaultBranch - if err = gitrepo.SetDefaultBranch(ctx, repo, repo.DefaultBranch); err != nil { - return fmt.Errorf("setDefaultBranch: %w", err) - } - - if !repo.IsEmpty { - if _, err := repo_module.SyncRepoBranches(ctx, repo.ID, u.ID); err != nil { - return fmt.Errorf("SyncRepoBranches: %w", err) - } - } - } - - if err = repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "is_empty", "default_branch", "default_wiki_branch"); err != nil { - return fmt.Errorf("updateRepository: %w", err) + if _, err := repo_module.SyncRepoBranches(ctx, repo.ID, u.ID); err != nil { + return fmt.Errorf("SyncRepoBranches: %w", err) } if err = repo_module.UpdateRepoSize(ctx, repo); err != nil { @@ -242,6 +236,7 @@ func CreateRepositoryDirectly(ctx context.Context, doer, owner *user_model.User, Name: opts.Name, LowerName: strings.ToLower(opts.Name), Description: opts.Description, + Website: opts.Website, OriginalURL: opts.OriginalURL, OriginalServiceType: opts.GitServiceType, IsPrivate: opts.IsPrivate, diff --git a/package/gitea/source/services/repository/create_test.go b/package/gitea/source/services/repository/create_test.go index b8c2ea59..60f9f2b4 100644 --- a/package/gitea/source/services/repository/create_test.go +++ b/package/gitea/source/services/repository/create_test.go @@ -7,10 +7,10 @@ import ( "os" "testing" - 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/util" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/modules/util" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/repository/delete.go b/package/gitea/source/services/repository/delete.go index aa16a968..6f67dca9 100644 --- a/package/gitea/source/services/repository/delete.go +++ b/package/gitea/source/services/repository/delete.go @@ -7,30 +7,30 @@ import ( "context" "fmt" - actions_model "code.gitea.io/gitea/models/actions" - activities_model "code.gitea.io/gitea/models/activities" - admin_model "code.gitea.io/gitea/models/admin" - "code.gitea.io/gitea/models/db" - git_model "code.gitea.io/gitea/models/git" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/organization" - packages_model "code.gitea.io/gitea/models/packages" - access_model "code.gitea.io/gitea/models/perm/access" - project_model "code.gitea.io/gitea/models/project" - repo_model "code.gitea.io/gitea/models/repo" - secret_model "code.gitea.io/gitea/models/secret" - system_model "code.gitea.io/gitea/models/system" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/models/webhook" - actions_module "code.gitea.io/gitea/modules/actions" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/lfs" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/storage" - actions_service "code.gitea.io/gitea/services/actions" - asymkey_service "code.gitea.io/gitea/services/asymkey" - issue_service "code.gitea.io/gitea/services/issue" + actions_model "gitea.dev/models/actions" + activities_model "gitea.dev/models/activities" + admin_model "gitea.dev/models/admin" + "gitea.dev/models/db" + git_model "gitea.dev/models/git" + issues_model "gitea.dev/models/issues" + "gitea.dev/models/organization" + packages_model "gitea.dev/models/packages" + access_model "gitea.dev/models/perm/access" + project_model "gitea.dev/models/project" + repo_model "gitea.dev/models/repo" + secret_model "gitea.dev/models/secret" + system_model "gitea.dev/models/system" + user_model "gitea.dev/models/user" + "gitea.dev/models/webhook" + actions_module "gitea.dev/modules/actions" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/graceful" + "gitea.dev/modules/lfs" + "gitea.dev/modules/log" + "gitea.dev/modules/storage" + actions_service "gitea.dev/services/actions" + asymkey_service "gitea.dev/services/asymkey" + issue_service "gitea.dev/services/issue" "xorm.io/builder" ) @@ -150,7 +150,10 @@ func DeleteRepositoryDirectly(ctx context.Context, repoID int64, ignoreOrgTeams &repo_model.Collaboration{RepoID: repoID}, &issues_model.Comment{RefRepoID: repoID}, &git_model.CommitStatus{RepoID: repoID}, + &git_model.CommitStatusIndex{RepoID: repoID}, + &git_model.CommitStatusSummary{RepoID: repoID}, &git_model.Branch{RepoID: repoID}, + &git_model.RenamedBranch{RepoID: repoID}, &git_model.LFSLock{RepoID: repoID}, &repo_model.LanguageStat{RepoID: repoID}, &repo_model.RepoLicense{RepoID: repoID}, @@ -163,21 +166,27 @@ func DeleteRepositoryDirectly(ctx context.Context, repoID int64, ignoreOrgTeams &repo_model.Release{RepoID: repoID}, &repo_model.RepoIndexerStatus{RepoID: repoID}, &repo_model.Redirect{RedirectRepoID: repoID}, + &repo_model.RepoTransfer{RepoID: repoID}, // this column doesn't have index, maybe it's fine since the table shouldn't be too large. &repo_model.RepoUnit{RepoID: repoID}, &repo_model.Star{RepoID: repoID}, &admin_model.Task{RepoID: repoID}, &repo_model.Watch{RepoID: repoID}, &webhook.Webhook{RepoID: repoID}, &secret_model.Secret{RepoID: repoID}, + &actions_model.ActionVariable{RepoID: repoID}, &actions_model.ActionTaskStep{RepoID: repoID}, &actions_model.ActionTask{RepoID: repoID}, &actions_model.ActionRunJob{RepoID: repoID}, &actions_model.ActionRun{RepoID: repoID}, + &actions_model.ActionRunAttempt{RepoID: repoID}, &actions_model.ActionRunner{RepoID: repoID}, &actions_model.ActionScheduleSpec{RepoID: repoID}, &actions_model.ActionSchedule{RepoID: repoID}, &actions_model.ActionArtifact{RepoID: repoID}, + &actions_model.ActionRunJobSummary{RepoID: repoID}, &actions_model.ActionRunnerToken{RepoID: repoID}, + &actions_model.ActionTasksVersion{RepoID: repoID}, + &actions_model.ActionScopedWorkflowSource{SourceRepoID: repoID}, &issues_model.IssuePin{RepoID: repoID}, ); err != nil { return fmt.Errorf("deleteBeans: %w", err) diff --git a/package/gitea/source/services/repository/delete_test.go b/package/gitea/source/services/repository/delete_test.go index f06373f2..c747d008 100644 --- a/package/gitea/source/services/repository/delete_test.go +++ b/package/gitea/source/services/repository/delete_test.go @@ -6,11 +6,14 @@ package repository_test import ( "testing" - "code.gitea.io/gitea/models/organization" - 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" + actions_model "gitea.dev/models/actions" + "gitea.dev/models/db" + git_model "gitea.dev/models/git" + "gitea.dev/models/organization" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + repo_service "gitea.dev/services/repository" "github.com/stretchr/testify/assert" ) @@ -52,3 +55,28 @@ func TestDeleteOwnerRepositoriesDirectly(t *testing.T) { assert.NoError(t, repo_service.DeleteOwnerRepositoriesDirectly(t.Context(), user)) } + +func TestDeleteRepositoryDirectlyPurgesRepoScopedRows(t *testing.T) { + unittest.PrepareTestEnv(t) + + // One row per table that repository deletion used to leave behind (#38494). + assert.NoError(t, db.Insert(t.Context(), + &actions_model.ActionVariable{RepoID: 1, Name: "to_purge", Data: "value"}, + &actions_model.ActionRunAttempt{RepoID: 1, RunID: unittest.NonexistentID, Attempt: 1}, + &actions_model.ActionTasksVersion{RepoID: 1, Version: 1}, + &git_model.RenamedBranch{RepoID: 1, From: "old-name", To: "new-name"}, + &git_model.CommitStatusSummary{RepoID: 1, SHA: "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef", State: "success"}, + &repo_model.RepoTransfer{RepoID: 1, DoerID: 2, RecipientID: 3}, + )) + unittest.AssertExistsAndLoadBean(t, &git_model.CommitStatusIndex{RepoID: 1}) + + assert.NoError(t, repo_service.DeleteRepositoryDirectly(t.Context(), 1)) + + unittest.AssertNotExistsBean(t, &actions_model.ActionVariable{RepoID: 1}) + unittest.AssertNotExistsBean(t, &actions_model.ActionRunAttempt{RepoID: 1}) + unittest.AssertNotExistsBean(t, &actions_model.ActionTasksVersion{RepoID: 1}) + unittest.AssertNotExistsBean(t, &git_model.RenamedBranch{RepoID: 1}) + unittest.AssertNotExistsBean(t, &git_model.CommitStatusSummary{RepoID: 1}) + unittest.AssertNotExistsBean(t, &git_model.CommitStatusIndex{RepoID: 1}) + unittest.AssertNotExistsBean(t, &repo_model.RepoTransfer{RepoID: 1}) +} diff --git a/package/gitea/source/services/repository/files/cherry_pick.go b/package/gitea/source/services/repository/files/cherry_pick.go index 5018327d..e4f779e2 100644 --- a/package/gitea/source/services/repository/files/cherry_pick.go +++ b/package/gitea/source/services/repository/files/cherry_pick.go @@ -4,18 +4,17 @@ package files import ( - "context" "errors" "fmt" "strings" - 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" - "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/services/pull" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/reqctx" + "gitea.dev/modules/structs" + "gitea.dev/services/pull" ) // ErrCommitIDDoesNotMatch represents a "CommitIDDoesNotMatch" kind of error. @@ -35,57 +34,23 @@ func (err ErrCommitIDDoesNotMatch) Error() string { } // CherryPick cherry-picks or reverts a commit to the given repository -func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_model.User, revert bool, opts *ApplyDiffPatchOptions) (*structs.FileResponse, error) { - gitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, repo) +func CherryPick(ctx reqctx.RequestContext, repo *repo_model.Repository, doer *user_model.User, revert bool, opts *ApplyDiffPatchOptions) (*structs.FileResponse, error) { + gitRepo, err := gitrepo.RepositoryFromRequestContextOrOpen(ctx, repo) if err != nil { return nil, err } - defer closer.Close() - - if err := opts.Validate(ctx, repo, gitRepo, doer); err != nil { - return nil, err - } - message := strings.TrimSpace(opts.Message) - - t, err := NewTemporaryUploadRepository(repo) + t, err := gitPatchPrepare(ctx, repo, gitRepo, doer, opts) if err != nil { - log.Error("NewTemporaryUploadRepository failed: %v", err) + return nil, err } defer t.Close() - if err := t.Clone(ctx, opts.OldBranch, false); err != nil { - return nil, err - } - if err := t.SetDefaultIndex(ctx); err != nil { - return nil, err - } - if err := t.RefreshIndex(ctx); err != nil { - return nil, err - } - // Get the commit of the original branch - commit, err := t.GetBranchCommit(opts.OldBranch) + err = t.RefreshIndex(ctx) if err != nil { - return nil, err // Couldn't get a commit for the branch + return nil, err } - // Assigned LastCommitID in opts if it hasn't been set - if opts.LastCommitID == "" { - opts.LastCommitID = commit.ID.String() - } else { - lastCommitID, err := t.gitRepo.ConvertToGitID(opts.LastCommitID) - if err != nil { - return nil, fmt.Errorf("CherryPick: Invalid last commit ID: %w", err) - } - opts.LastCommitID = lastCommitID.String() - if commit.ID.String() != opts.LastCommitID { - return nil, ErrCommitIDDoesNotMatch{ - GivenCommitID: opts.LastCommitID, - CurrentCommitID: opts.LastCommitID, - } - } - } - - commit, err = t.GetCommit(strings.TrimSpace(opts.Content)) + commit, err := t.GetCommit(strings.TrimSpace(opts.Content)) if err != nil { return nil, err } @@ -101,8 +66,7 @@ func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_mod } description := fmt.Sprintf("CherryPick %s onto %s", right, opts.OldBranch) - conflict, _, err := pull.AttemptThreeWayMerge(ctx, - t.basePath, t.gitRepo, base, opts.LastCommitID, right, description) + conflict, _, err := pull.AttemptThreeWayMerge(ctx, t.basePath, t.gitRepo, base, opts.LastCommitID, right, description) if err != nil { return nil, fmt.Errorf("failed to three-way merge %s onto %s: %w", right, opts.OldBranch, err) } @@ -111,48 +75,5 @@ func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_mod return nil, errors.New("failed to merge due to conflicts") } - treeHash, err := t.WriteTree(ctx) - if err != nil { - // likely non-sensical tree due to merge conflicts... - return nil, err - } - - // Now commit the tree - commitOpts := &CommitTreeUserOptions{ - ParentCommitID: "HEAD", - TreeHash: treeHash, - CommitMessage: message, - SignOff: opts.Signoff, - DoerUser: doer, - AuthorIdentity: opts.Author, - AuthorTime: nil, - CommitterIdentity: opts.Committer, - CommitterTime: nil, - } - if opts.Dates != nil { - commitOpts.AuthorTime, commitOpts.CommitterTime = &opts.Dates.Author, &opts.Dates.Committer - } - commitHash, err := t.CommitTree(ctx, commitOpts) - if err != nil { - return nil, err - } - - // Then push this tree to NewBranch - if err := t.Push(ctx, doer, commitHash, opts.NewBranch, false); err != nil { - return nil, err - } - - commit, err = t.GetCommit(commitHash) - if err != nil { - return nil, err - } - - fileCommitResponse, _ := GetFileCommitResponse(repo, commit) // ok if fails, then will be nil - verification := GetPayloadCommitVerification(ctx, commit) - fileResponse := &structs.FileResponse{ - Commit: fileCommitResponse, - Verification: verification, - } - - return fileResponse, nil + return gitPatchCommitPush(ctx, t, repo, doer, opts) } diff --git a/package/gitea/source/services/repository/files/commit.go b/package/gitea/source/services/repository/files/commit.go index 2e279214..2a941b0d 100644 --- a/package/gitea/source/services/repository/files/commit.go +++ b/package/gitea/source/services/repository/files/commit.go @@ -6,9 +6,9 @@ package files import ( "context" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/structs" - asymkey_service "code.gitea.io/gitea/services/asymkey" + "gitea.dev/modules/git" + "gitea.dev/modules/structs" + asymkey_service "gitea.dev/services/asymkey" ) // GetPayloadCommitVerification returns the verification information of a commit diff --git a/package/gitea/source/services/repository/files/content.go b/package/gitea/source/services/repository/files/content.go index fc0e00a1..42e8c193 100644 --- a/package/gitea/source/services/repository/files/content.go +++ b/package/gitea/source/services/repository/files/content.go @@ -10,15 +10,15 @@ import ( "path" "strings" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/cache" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/lfs" - "code.gitea.io/gitea/modules/setting" - api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/routers/api/v1/utils" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/cache" + "gitea.dev/modules/git" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/lfs" + "gitea.dev/modules/setting" + api "gitea.dev/modules/structs" + "gitea.dev/modules/util" + "gitea.dev/routers/api/v1/utils" ) // ContentType repo content type @@ -32,11 +32,6 @@ const ( ContentTypeSubmodule ContentType = "submodule" // submodule content type (submodule) ) -// String gets the string of ContentType -func (ct *ContentType) String() string { - return string(*ct) -} - type GetContentsOrListOptions struct { TreePath string IncludeSingleFileContent bool // include the file's content when the tree path is a file @@ -184,7 +179,7 @@ func getFileContentsByEntryInternal(ctx context.Context, repo *repo_model.Reposi } } if opts.IncludeCommitMessage { - contentsResponse.LastCommitMessage = new(lastCommit.Message()) + contentsResponse.LastCommitMessage = new(lastCommit.MessageUTF8()) } } diff --git a/package/gitea/source/services/repository/files/content_test.go b/package/gitea/source/services/repository/files/content_test.go index dda5572a..52b7e8a0 100644 --- a/package/gitea/source/services/repository/files/content_test.go +++ b/package/gitea/source/services/repository/files/content_test.go @@ -6,11 +6,11 @@ package files import ( "testing" - "code.gitea.io/gitea/models/unittest" - api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/services/contexttest" + "gitea.dev/models/unittest" + api "gitea.dev/modules/structs" + "gitea.dev/services/contexttest" - _ "code.gitea.io/gitea/models/actions" + _ "gitea.dev/models/actions" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/repository/files/diff.go b/package/gitea/source/services/repository/files/diff.go index aa4b55a3..ff52faa8 100644 --- a/package/gitea/source/services/repository/files/diff.go +++ b/package/gitea/source/services/repository/files/diff.go @@ -7,8 +7,8 @@ import ( "context" "strings" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/services/gitdiff" + repo_model "gitea.dev/models/repo" + "gitea.dev/services/gitdiff" ) // GetDiffPreview produces and returns diff result of a file which is not yet committed. diff --git a/package/gitea/source/services/repository/files/diff_test.go b/package/gitea/source/services/repository/files/diff_test.go index 52958796..373e283e 100644 --- a/package/gitea/source/services/repository/files/diff_test.go +++ b/package/gitea/source/services/repository/files/diff_test.go @@ -6,11 +6,11 @@ package files import ( "testing" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/json" - "code.gitea.io/gitea/services/contexttest" - "code.gitea.io/gitea/services/gitdiff" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + "gitea.dev/modules/json" + "gitea.dev/services/contexttest" + "gitea.dev/services/gitdiff" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/repository/files/file.go b/package/gitea/source/services/repository/files/file.go index f48e32b4..df88ee4d 100644 --- a/package/gitea/source/services/repository/files/file.go +++ b/package/gitea/source/services/repository/files/file.go @@ -11,12 +11,12 @@ import ( "strings" "time" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/setting" - api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/routers/api/v1/utils" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/git" + "gitea.dev/modules/setting" + api "gitea.dev/modules/structs" + "gitea.dev/modules/util" + "gitea.dev/routers/api/v1/utils" ) func GetContentsListFromTreePaths(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, refCommit *utils.RefCommit, treePaths []string) (files []*api.ContentsResponse) { @@ -110,7 +110,7 @@ func GetFileCommitResponse(repo *repo_model.Repository, commit *git.Commit) (*ap }, Date: commit.Committer.When.UTC().Format(time.RFC3339), }, - Message: commit.Message(), + Message: commit.MessageUTF8(), Tree: &api.CommitMeta{ URL: commitTreeURL.String(), SHA: commit.Tree.ID.String(), diff --git a/package/gitea/source/services/repository/files/patch.go b/package/gitea/source/services/repository/files/patch.go index 10f923f2..53db2502 100644 --- a/package/gitea/source/services/repository/files/patch.go +++ b/package/gitea/source/services/repository/files/patch.go @@ -8,16 +8,16 @@ import ( "fmt" "strings" - git_model "code.gitea.io/gitea/models/git" - 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/git/gitcmd" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" - asymkey_service "code.gitea.io/gitea/services/asymkey" + git_model "gitea.dev/models/git" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/reqctx" + "gitea.dev/modules/structs" + "gitea.dev/modules/util" + asymkey_service "gitea.dev/services/asymkey" ) // ErrUserCannotCommit represents "UserCannotCommit" kind of error. @@ -110,31 +110,27 @@ func (opts *ApplyDiffPatchOptions) Validate(ctx context.Context, repo *repo_mode return nil } -// ApplyDiffPatch applies a patch to the given repository -func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user_model.User, opts *ApplyDiffPatchOptions) (*structs.FileResponse, error) { +func gitPatchPrepare(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, doer *user_model.User, opts *ApplyDiffPatchOptions) (_ *TemporaryUploadRepository, retErr error) { err := repo.MustNotBeArchived() if err != nil { return nil, err } - gitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, repo) - if err != nil { - return nil, err - } - defer closer.Close() - if err := opts.Validate(ctx, repo, gitRepo, doer); err != nil { return nil, err } - message := strings.TrimSpace(opts.Message) - t, err := NewTemporaryUploadRepository(repo) if err != nil { - log.Error("NewTemporaryUploadRepository failed: %v", err) + return nil, fmt.Errorf("NewTemporaryUploadRepository failed: %w", err) } - defer t.Close() - if err := t.Clone(ctx, opts.OldBranch, true); err != nil { + defer func() { + if retErr != nil { + t.Close() + } + }() + // here must NOT use bare repo, because the following git commands might operate working tree ("--index") directly + if err := t.Clone(ctx, opts.OldBranch, false); err != nil { return nil, err } if err := t.SetDefaultIndex(ctx); err != nil { @@ -153,7 +149,7 @@ func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user } else { lastCommitID, err := t.gitRepo.ConvertToGitID(opts.LastCommitID) if err != nil { - return nil, fmt.Errorf("ApplyPatch: Invalid last commit ID: %w", err) + return nil, fmt.Errorf("invalid last commit ID: %w", err) } opts.LastCommitID = lastCommitID.String() if commit.ID.String() != opts.LastCommitID { @@ -163,6 +159,20 @@ func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user } } } + return t, nil +} + +// ApplyDiffPatch applies a patch to the given repository +func ApplyDiffPatch(ctx reqctx.RequestContext, repo *repo_model.Repository, doer *user_model.User, opts *ApplyDiffPatchOptions) (*structs.FileResponse, error) { + gitRepo, err := gitrepo.RepositoryFromRequestContextOrOpen(ctx, repo) + if err != nil { + return nil, err + } + t, err := gitPatchPrepare(ctx, repo, gitRepo, doer, opts) + if err != nil { + return nil, err + } + defer t.Close() cmdApply := gitcmd.NewCommand("apply", "--index", "--recount", "--cached", "--ignore-whitespace", "--whitespace=fix", "--binary") if git.DefaultFeatures().CheckVersionAtLeast("2.32") { @@ -175,17 +185,19 @@ func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user return nil, fmt.Errorf("git apply error: %w", err) } - // Now write the tree + return gitPatchCommitPush(ctx, t, repo, doer, opts) +} + +func gitPatchCommitPush(ctx context.Context, t *TemporaryUploadRepository, repo *repo_model.Repository, doer *user_model.User, opts *ApplyDiffPatchOptions) (*structs.FileResponse, error) { treeHash, err := t.WriteTree(ctx) if err != nil { return nil, err } - // Now commit the tree commitOpts := &CommitTreeUserOptions{ ParentCommitID: "HEAD", TreeHash: treeHash, - CommitMessage: message, + CommitMessage: strings.TrimSpace(opts.Message), SignOff: opts.Signoff, DoerUser: doer, AuthorIdentity: opts.Author, @@ -206,7 +218,7 @@ func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user return nil, err } - commit, err = t.GetCommit(commitHash) + commit, err := t.GetCommit(commitHash) if err != nil { return nil, err } diff --git a/package/gitea/source/services/repository/files/patch_test.go b/package/gitea/source/services/repository/files/patch_test.go new file mode 100644 index 00000000..37d21b4d --- /dev/null +++ b/package/gitea/source/services/repository/files/patch_test.go @@ -0,0 +1,36 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package files + +import ( + "os" + "path/filepath" + "testing" + + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/modules/gitrepo" + + "github.com/stretchr/testify/require" +) + +func TestGitPatchPrepare(t *testing.T) { + unittest.PrepareTestEnv(t) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + + gitRepo, err := gitrepo.OpenRepository(t.Context(), repo1) + require.NoError(t, err) + defer gitRepo.Close() + + opts := &ApplyDiffPatchOptions{} + tmpRepo, err := gitPatchPrepare(t.Context(), repo1, gitRepo, user2, opts) + require.NoError(t, err) + defer tmpRepo.Close() + // temporary repository for patch should not be a bare repo because "--index" argument is used, + // while it is questionable whether "--index" argument should be really used, need to figure out in the future. + _, err = os.Stat(filepath.Join(tmpRepo.basePath, ".git")) + require.NoError(t, err) +} diff --git a/package/gitea/source/services/repository/files/temp_repo.go b/package/gitea/source/services/repository/files/temp_repo.go index 5d5cc225..bffd3525 100644 --- a/package/gitea/source/services/repository/files/temp_repo.go +++ b/package/gitea/source/services/repository/files/temp_repo.go @@ -14,17 +14,17 @@ import ( "strings" "time" - 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/git/gitcmd" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/log" - repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" - asymkey_service "code.gitea.io/gitea/services/asymkey" - "code.gitea.io/gitea/services/gitdiff" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/log" + repo_module "gitea.dev/modules/repository" + "gitea.dev/modules/setting" + "gitea.dev/modules/util" + asymkey_service "gitea.dev/services/asymkey" + "gitea.dev/services/gitdiff" ) // TemporaryUploadRepository is a type to wrap our upload repositories as a shallow clone @@ -47,7 +47,8 @@ func NewTemporaryUploadRepository(repo *repo_model.Repository) (*TemporaryUpload // Close the repository cleaning up all files func (t *TemporaryUploadRepository) Close() { - defer t.gitRepo.Close() + // must stop the repo access before removal, otherwise Windows can't remove the directory occupied by other processes + t.gitRepo.Close() if t.cleanup != nil { t.cleanup() } @@ -300,12 +301,7 @@ func (t *TemporaryUploadRepository) CommitTree(ctx context.Context, opts *Commit cmdCommitTree.AddOptionFormat("-S%s", key.KeyID) if t.repo.GetTrustModel() == repo_model.CommitterTrustModel || t.repo.GetTrustModel() == repo_model.CollaboratorCommitterTrustModel { if committerSig.Name != authorSig.Name || committerSig.Email != authorSig.Email { - // Add trailers - _, _ = messageBytes.WriteString("\n") - _, _ = messageBytes.WriteString("Co-authored-by: ") - _, _ = messageBytes.WriteString(committerSig.String()) - _, _ = messageBytes.WriteString("\n") - _, _ = messageBytes.WriteString("Co-committed-by: ") + _, _ = messageBytes.WriteString("\n" + git.CoAuthoredByTrailer + ": ") _, _ = messageBytes.WriteString(committerSig.String()) _, _ = messageBytes.WriteString("\n") } diff --git a/package/gitea/source/services/repository/files/temp_repo_test.go b/package/gitea/source/services/repository/files/temp_repo_test.go index 89e44e27..cb651674 100644 --- a/package/gitea/source/services/repository/files/temp_repo_test.go +++ b/package/gitea/source/services/repository/files/temp_repo_test.go @@ -7,8 +7,8 @@ import ( "bytes" "testing" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/git" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/git" "github.com/stretchr/testify/require" ) diff --git a/package/gitea/source/services/repository/files/tree.go b/package/gitea/source/services/repository/files/tree.go index 36d0ae3c..7b822db0 100644 --- a/package/gitea/source/services/repository/files/tree.go +++ b/package/gitea/source/services/repository/files/tree.go @@ -12,14 +12,14 @@ import ( "sort" "strings" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/fileicon" - "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" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/base" + "gitea.dev/modules/fileicon" + "gitea.dev/modules/git" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" + api "gitea.dev/modules/structs" + "gitea.dev/modules/util" ) // ErrSHANotFound represents a "SHADoesNotMatch" kind of error. @@ -27,12 +27,6 @@ type ErrSHANotFound struct { SHA string } -// IsErrSHANotFound checks if an error is a ErrSHANotFound. -func IsErrSHANotFound(err error) bool { - _, ok := err.(ErrSHANotFound) - return ok -} - func (err ErrSHANotFound) Error() string { return fmt.Sprintf("sha not found [%s]", err.SHA) } diff --git a/package/gitea/source/services/repository/files/tree_test.go b/package/gitea/source/services/repository/files/tree_test.go index b85f65f4..fe42bdb0 100644 --- a/package/gitea/source/services/repository/files/tree_test.go +++ b/package/gitea/source/services/repository/files/tree_test.go @@ -7,11 +7,11 @@ import ( "html/template" "testing" - "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/fileicon" - "code.gitea.io/gitea/modules/git" - api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/services/contexttest" + "gitea.dev/models/unittest" + "gitea.dev/modules/fileicon" + "gitea.dev/modules/git" + api "gitea.dev/modules/structs" + "gitea.dev/services/contexttest" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/repository/files/update.go b/package/gitea/source/services/repository/files/update.go index 3523b2d3..4fab88af 100644 --- a/package/gitea/source/services/repository/files/update.go +++ b/package/gitea/source/services/repository/files/update.go @@ -12,20 +12,20 @@ import ( "strings" "time" - git_model "code.gitea.io/gitea/models/git" - 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/git/attribute" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/lfs" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/routers/api/v1/utils" - asymkey_service "code.gitea.io/gitea/services/asymkey" - pull_service "code.gitea.io/gitea/services/pull" + git_model "gitea.dev/models/git" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/git/attribute" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/lfs" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" + "gitea.dev/modules/structs" + "gitea.dev/modules/util" + "gitea.dev/routers/api/v1/utils" + asymkey_service "gitea.dev/services/asymkey" + pull_service "gitea.dev/services/pull" ) // IdentityOptions for a person's identity like an author or committer @@ -175,7 +175,7 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use t, err := NewTemporaryUploadRepository(repo) if err != nil { - log.Error("NewTemporaryUploadRepository failed: %v", err) + return nil, fmt.Errorf("NewTemporaryUploadRepository failed: %w", err) } defer t.Close() hasOldBranch := true diff --git a/package/gitea/source/services/repository/files/upload.go b/package/gitea/source/services/repository/files/upload.go index b783cbd0..b131afb1 100644 --- a/package/gitea/source/services/repository/files/upload.go +++ b/package/gitea/source/services/repository/files/upload.go @@ -10,9 +10,9 @@ import ( "path" "sync" - repo_model "code.gitea.io/gitea/models/repo" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/log" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/log" ) // UploadRepoFileOptions contains the uploaded repository file options diff --git a/package/gitea/source/services/repository/fork.go b/package/gitea/source/services/repository/fork.go index 8cf41d56..a469836d 100644 --- a/package/gitea/source/services/repository/fork.go +++ b/package/gitea/source/services/repository/fork.go @@ -9,18 +9,18 @@ import ( "strings" "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/unit" - 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" - repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" - notify_service "code.gitea.io/gitea/services/notify" + "gitea.dev/models/db" + git_model "gitea.dev/models/git" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unit" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/log" + repo_module "gitea.dev/modules/repository" + "gitea.dev/modules/structs" + "gitea.dev/modules/util" + notify_service "gitea.dev/services/notify" "xorm.io/builder" ) diff --git a/package/gitea/source/services/repository/fork_test.go b/package/gitea/source/services/repository/fork_test.go index 680a7f32..2549e695 100644 --- a/package/gitea/source/services/repository/fork_test.go +++ b/package/gitea/source/services/repository/fork_test.go @@ -7,12 +7,12 @@ import ( "os" "testing" - 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/setting" - "code.gitea.io/gitea/modules/test" - "code.gitea.io/gitea/modules/util" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/modules/setting" + "gitea.dev/modules/test" + "gitea.dev/modules/util" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/repository/generate.go b/package/gitea/source/services/repository/generate.go index fb747067..361f7cc3 100644 --- a/package/gitea/source/services/repository/generate.go +++ b/package/gitea/source/services/repository/generate.go @@ -18,15 +18,15 @@ import ( "sync" "time" - git_model "code.gitea.io/gitea/models/git" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/glob" - "code.gitea.io/gitea/modules/log" - repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" + git_model "gitea.dev/models/git" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/git" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/glob" + "gitea.dev/modules/log" + repo_module "gitea.dev/modules/repository" + "gitea.dev/modules/setting" + "gitea.dev/modules/util" "github.com/huandu/xstrings" ) @@ -208,7 +208,7 @@ func processGiteaTemplateFile(ctx context.Context, tmpDir string, templateRepo, func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *repo_model.Repository, tmpDir string) error { // set default branch based on whether it's specified in the newly generated repo or not - repo.DefaultBranch = util.IfZero(repo.DefaultBranch, templateRepo.DefaultBranch) + repo.DefaultBranch = util.IfZero(repo.DefaultBranch, util.IfZero(templateRepo.DefaultBranch, setting.Repository.DefaultBranch)) // Clone to temporary path and do the init commit. if err := gitrepo.CloneRepoToLocal(ctx, templateRepo, tmpDir, git.CloneRepoOptions{ @@ -249,7 +249,7 @@ func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *r return fmt.Errorf("failed to add submodules: %v", err) } - return initRepoCommit(ctx, tmpDir, repo, repo.Owner, repo.DefaultBranch) + return initRepoCommit(ctx, tmpDir, repo, repo.Owner) } // GenerateGitContent generates git content from a template repository @@ -277,6 +277,7 @@ func GenerateGitContent(ctx context.Context, templateRepo, generateRepo *repo_mo if err := git_model.CopyLFS(ctx, generateRepo, templateRepo); err != nil { return fmt.Errorf("failed to copy LFS: %w", err) } + if _, err := repo_module.SyncRepoBranches(ctx, generateRepo.ID, 0); err != nil { return fmt.Errorf("SyncRepoBranches: %w", err) } diff --git a/package/gitea/source/services/repository/generate_test.go b/package/gitea/source/services/repository/generate_test.go index 160dbb9a..d484f736 100644 --- a/package/gitea/source/services/repository/generate_test.go +++ b/package/gitea/source/services/repository/generate_test.go @@ -9,7 +9,7 @@ import ( "path/filepath" "testing" - repo_model "code.gitea.io/gitea/models/repo" + repo_model "gitea.dev/models/repo" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/package/gitea/source/services/repository/gitgraph/graph.go b/package/gitea/source/services/repository/gitgraph/graph.go index 8d9bec47..ab0203f4 100644 --- a/package/gitea/source/services/repository/gitgraph/graph.go +++ b/package/gitea/source/services/repository/gitgraph/graph.go @@ -7,9 +7,9 @@ import ( "bufio" "bytes" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/git/gitcmd" - "code.gitea.io/gitea/modules/setting" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/setting" ) // GetCommitGraph return a list of commit (GraphItems) from all branches diff --git a/package/gitea/source/services/repository/gitgraph/graph_models.go b/package/gitea/source/services/repository/gitgraph/graph_models.go index fc2eb85b..c2507b84 100644 --- a/package/gitea/source/services/repository/gitgraph/graph_models.go +++ b/package/gitea/source/services/repository/gitgraph/graph_models.go @@ -10,14 +10,16 @@ import ( "strings" "time" - asymkey_model "code.gitea.io/gitea/models/asymkey" - "code.gitea.io/gitea/models/db" - git_model "code.gitea.io/gitea/models/git" - 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/log" - asymkey_service "code.gitea.io/gitea/services/asymkey" + asymkey_model "gitea.dev/models/asymkey" + "gitea.dev/models/db" + git_model "gitea.dev/models/git" + "gitea.dev/models/gituser" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/container" + "gitea.dev/modules/git" + "gitea.dev/modules/log" + asymkey_service "gitea.dev/services/asymkey" ) // NewGraph creates a basic graph @@ -93,9 +95,7 @@ func (graph *Graph) AddCommit(row, column int, flowID int64, data []byte) error // before finally retrieving the latest status func (graph *Graph) LoadAndProcessCommits(ctx context.Context, repository *repo_model.Repository, gitRepo *git.Repository) error { var err error - var ok bool - - emails := map[string]*user_model.User{} + emailSet := make(container.Set[string]) keyMap := map[string]bool{} for _, c := range graph.Commits { @@ -106,14 +106,26 @@ func (graph *Graph) LoadAndProcessCommits(ctx context.Context, repository *repo_ if err != nil { return fmt.Errorf("GetCommit: %s Error: %w", c.Rev, err) } - if c.Commit.Author != nil { - email := c.Commit.Author.Email - if c.User, ok = emails[email]; !ok { - c.User, _ = user_model.GetUserByEmail(ctx, email) - emails[email] = c.User - } + emailSet.Add(c.Commit.Author.Email) } + for _, sig := range c.Commit.AllAuthorIdentities() { + emailSet.Add(sig.Email) + } + } + + emailUserMap, err := user_model.GetUsersByEmails(ctx, emailSet.Values()) + if err != nil { + log.Error("GetUsersByEmails: %v", err) + } + + for _, c := range graph.Commits { + if c.Commit == nil { + continue + } + + c.User = emailUserMap.GetByEmail(c.Commit.Author.Email) + c.AvatarStackData = gituser.BuildAvatarStackData(ctx, c.Commit.AllAuthorIdentities(), emailUserMap) c.Verification = asymkey_service.ParseCommitWithSignature(ctx, c.Commit) @@ -246,18 +258,19 @@ func newRefsFromRefNames(refNames []byte) []git.Reference { // Commit represents a commit at coordinate X, Y with the data type Commit struct { - Commit *git.Commit - User *user_model.User - Verification *asymkey_model.CommitVerification - Status *git_model.CommitStatus - Flow int64 - Row int - Column int - Refs []git.Reference - Rev string - Date time.Time - ShortRev string - Subject string + Commit *git.Commit + User *user_model.User // author + AvatarStackData *gituser.AvatarStackData + Verification *asymkey_model.CommitVerification + Status *git_model.CommitStatus + Flow int64 + Row int + Column int + Refs []git.Reference + Rev string + Date time.Time // author date from "%ad" + ShortRev string + Subject string } // OnlyRelation returns whether this a relation only commit diff --git a/package/gitea/source/services/repository/gitgraph/graph_test.go b/package/gitea/source/services/repository/gitgraph/graph_test.go index 83813e7b..a6cc0ae0 100644 --- a/package/gitea/source/services/repository/gitgraph/graph_test.go +++ b/package/gitea/source/services/repository/gitgraph/graph_test.go @@ -10,7 +10,7 @@ import ( "strings" "testing" - "code.gitea.io/gitea/modules/git" + "gitea.dev/modules/git" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/repository/gitgraph/parser.go b/package/gitea/source/services/repository/gitgraph/parser.go index 859deff1..ca555218 100644 --- a/package/gitea/source/services/repository/gitgraph/parser.go +++ b/package/gitea/source/services/repository/gitgraph/parser.go @@ -6,6 +6,7 @@ package gitgraph import ( "bytes" "fmt" + "slices" ) // Parser represents a git graph parser. It is stateful containing the previous @@ -163,8 +164,7 @@ func (parser *Parser) ParseGlyphs(glyphs []byte) { // release unused colors parser.releaseUnusedColors() - for i := len(glyphs) - 1; i >= 0; i-- { - glyph := glyphs[i] + for i, glyph := range slices.Backward(glyphs) { switch glyph { case '|': fallthrough diff --git a/package/gitea/source/services/repository/heatmap_indexer.go b/package/gitea/source/services/repository/heatmap_indexer.go index bc530b78..2f19e499 100644 --- a/package/gitea/source/services/repository/heatmap_indexer.go +++ b/package/gitea/source/services/repository/heatmap_indexer.go @@ -7,12 +7,12 @@ import ( "context" "strings" - activities_model "code.gitea.io/gitea/models/activities" - 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/timeutil" + activities_model "gitea.dev/models/activities" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/timeutil" ) const heatmapIndexCommitsPageSize = 100 diff --git a/package/gitea/source/services/repository/heatmap_indexer_test.go b/package/gitea/source/services/repository/heatmap_indexer_test.go index 4993bf59..7e4d2380 100644 --- a/package/gitea/source/services/repository/heatmap_indexer_test.go +++ b/package/gitea/source/services/repository/heatmap_indexer_test.go @@ -9,15 +9,16 @@ import ( "testing" "time" - activities_model "code.gitea.io/gitea/models/activities" - "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" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/git/gitcmd" - repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/timeutil" + activities_model "gitea.dev/models/activities" + "gitea.dev/models/db" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/queue" + repo_module "gitea.dev/modules/repository" + "gitea.dev/modules/timeutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -46,7 +47,8 @@ func TestHeatmapIndexDefaultBranchAuthorDates(t *testing.T) { emailAddress, err := user_model.GetEmailAddressByEmail(t.Context(), "user2@example.com") require.NoError(t, err) emailAddress.UID = 1 - require.NoError(t, user_model.UpdateEmailAddress(t.Context(), emailAddress)) + _, err = db.GetEngine(t.Context()).ID(emailAddress.ID).Cols("uid").Update(emailAddress) + require.NoError(t, err) require.NoError(t, IndexDefaultBranchHeatmapContributions(t.Context(), repo)) contributions = loadHeatmapContributionsForRepo(t, repo.ID) @@ -83,6 +85,13 @@ func TestHeatmapIndexIgnoresPusherAndNonDefaultBranch(t *testing.T) { } func TestHeatmapIndexOnPushDefaultBranch(t *testing.T) { + previousLicenseUpdaterQueue := licenseUpdaterQueue + licenseUpdaterQueue = queue.CreateUniqueQueue[*LicenseUpdaterOptions](t.Context(), "heatmap_test_license_updater", nil) + require.NotNil(t, licenseUpdaterQueue) + defer func() { + licenseUpdaterQueue = previousLicenseUpdaterQueue + }() + repo, commits := prepareHeatmapIndexRepo(t, "heatmap-push-default", []heatmapIndexTestCommit{ {Branch: "main", Mark: "initial", AuthorName: "User Two", AuthorEmail: "user2@example.com", CommitterName: "User One", CommitterEmail: "user1@example.com", AuthorDate: "2020-01-15T12:00:00Z"}, }) @@ -96,7 +105,7 @@ func TestHeatmapIndexOnPushDefaultBranch(t *testing.T) { newCommits := runFastImport(t, repo, []heatmapIndexTestCommit{ {Branch: "main", Mark: "pushed", Parent: commits["initial"], AuthorName: "User Two", AuthorEmail: "user2@example.com", CommitterName: "User One", CommitterEmail: "user1@example.com", AuthorDate: "2020-01-16T12:00:00Z"}, }) - require.NoError(t, pushUpdates([]*repo_module.PushUpdateOptions{ + require.NoError(t, pushQueueHandleUpdates([]*repo_module.PushUpdateOptions{ { RefFullName: git.RefNameFromBranch("main"), OldCommitID: commits["initial"], @@ -115,7 +124,7 @@ func TestHeatmapIndexOnPushDefaultBranch(t *testing.T) { featureCommits := runFastImport(t, repo, []heatmapIndexTestCommit{ {Branch: "feature", Mark: "feature-pushed", AuthorName: "User Two", AuthorEmail: "user2@example.com", CommitterName: "User One", CommitterEmail: "user1@example.com", AuthorDate: "2020-01-17T12:00:00Z"}, }) - require.NoError(t, pushUpdates([]*repo_module.PushUpdateOptions{ + require.NoError(t, pushQueueHandleUpdates([]*repo_module.PushUpdateOptions{ { RefFullName: git.RefNameFromBranch("feature"), OldCommitID: git.Sha1ObjectFormat.EmptyObjectID().String(), diff --git a/package/gitea/source/services/repository/hooks.go b/package/gitea/source/services/repository/hooks.go index c5bd3b8a..c75c66af 100644 --- a/package/gitea/source/services/repository/hooks.go +++ b/package/gitea/source/services/repository/hooks.go @@ -7,11 +7,11 @@ import ( "context" "fmt" - "code.gitea.io/gitea/models/db" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/log" + "gitea.dev/models/db" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/webhook" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/log" "xorm.io/builder" ) diff --git a/package/gitea/source/services/repository/init.go b/package/gitea/source/services/repository/init.go index 6aeb5ec6..e32041c6 100644 --- a/package/gitea/source/services/repository/init.go +++ b/package/gitea/source/services/repository/init.go @@ -9,19 +9,18 @@ import ( "os" "time" - 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/git/gitcmd" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/log" - repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/setting" - asymkey_service "code.gitea.io/gitea/services/asymkey" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/log" + repo_module "gitea.dev/modules/repository" + asymkey_service "gitea.dev/services/asymkey" ) // initRepoCommit temporarily changes with work directory. -func initRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Repository, u *user_model.User, defaultBranch string) (err error) { +func initRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Repository, u *user_model.User) (err error) { commitTimeStr := time.Now().Format(time.RFC3339) sig := u.NewGitSig() @@ -69,13 +68,9 @@ func initRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Reposi return fmt.Errorf("git commit: %w", err) } - if len(defaultBranch) == 0 { - defaultBranch = setting.Repository.DefaultBranch - } - if err := gitrepo.PushFromLocal(ctx, tmpPath, repo, git.PushOptions{ LocalRefName: "HEAD", - Branch: defaultBranch, + Branch: repo.DefaultBranch, Env: repo_module.InternalPushingEnvironment(u, repo), }); err != nil { log.Error("Failed to push back to HEAD Error: %v", err) diff --git a/package/gitea/source/services/repository/lfs.go b/package/gitea/source/services/repository/lfs.go index 5ef2dbda..08a5ab49 100644 --- a/package/gitea/source/services/repository/lfs.go +++ b/package/gitea/source/services/repository/lfs.go @@ -9,14 +9,14 @@ import ( "fmt" "time" - git_model "code.gitea.io/gitea/models/git" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/lfs" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/timeutil" + git_model "gitea.dev/models/git" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/git" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/lfs" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" + "gitea.dev/modules/timeutil" ) // GarbageCollectLFSMetaObjectsOptions provides options for GarbageCollectLFSMetaObjects function diff --git a/package/gitea/source/services/repository/lfs_test.go b/package/gitea/source/services/repository/lfs_test.go index 1335d48c..cfca83d8 100644 --- a/package/gitea/source/services/repository/lfs_test.go +++ b/package/gitea/source/services/repository/lfs_test.go @@ -8,14 +8,14 @@ import ( "testing" "time" - git_model "code.gitea.io/gitea/models/git" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/lfs" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/storage" - "code.gitea.io/gitea/modules/test" - repo_service "code.gitea.io/gitea/services/repository" + git_model "gitea.dev/models/git" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + "gitea.dev/modules/lfs" + "gitea.dev/modules/setting" + "gitea.dev/modules/storage" + "gitea.dev/modules/test" + repo_service "gitea.dev/services/repository" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/repository/license.go b/package/gitea/source/services/repository/license.go index 8622911f..61c58e72 100644 --- a/package/gitea/source/services/repository/license.go +++ b/package/gitea/source/services/repository/license.go @@ -8,15 +8,15 @@ import ( "fmt" "io" - "code.gitea.io/gitea/models/db" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/options" - "code.gitea.io/gitea/modules/queue" + "gitea.dev/models/db" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/container" + "gitea.dev/modules/git" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/graceful" + "gitea.dev/modules/log" + "gitea.dev/modules/options" + "gitea.dev/modules/queue" licenseclassifier "github.com/google/licenseclassifier/v2" ) diff --git a/package/gitea/source/services/repository/license_test.go b/package/gitea/source/services/repository/license_test.go index eb897f3c..a8a28cdf 100644 --- a/package/gitea/source/services/repository/license_test.go +++ b/package/gitea/source/services/repository/license_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - repo_module "code.gitea.io/gitea/modules/repository" + repo_module "gitea.dev/modules/repository" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/package/gitea/source/services/repository/main_test.go b/package/gitea/source/services/repository/main_test.go index 7ad1540a..67217a43 100644 --- a/package/gitea/source/services/repository/main_test.go +++ b/package/gitea/source/services/repository/main_test.go @@ -6,7 +6,7 @@ package repository import ( "testing" - "code.gitea.io/gitea/models/unittest" + "gitea.dev/models/unittest" ) func TestMain(m *testing.M) { diff --git a/package/gitea/source/services/repository/merge_upstream.go b/package/gitea/source/services/repository/merge_upstream.go index 692b8013..77190d05 100644 --- a/package/gitea/source/services/repository/merge_upstream.go +++ b/package/gitea/source/services/repository/merge_upstream.go @@ -7,15 +7,17 @@ import ( "errors" "fmt" - issue_model "code.gitea.io/gitea/models/issues" - 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" - repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/reqctx" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/services/pull" + issue_model "gitea.dev/models/issues" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unit" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/gitrepo" + repo_module "gitea.dev/modules/repository" + "gitea.dev/modules/reqctx" + "gitea.dev/modules/util" + "gitea.dev/services/pull" ) // MergeUpstream merges the base repository's default branch into the fork repository's current branch. @@ -26,6 +28,17 @@ func MergeUpstream(ctx reqctx.RequestContext, doer *user_model.User, repo *repo_ if err = repo.GetBaseRepo(ctx); err != nil { return "", err } + + // The doer must still be able to read the base repository's code. Otherwise a fork created + // while the base repo was public could keep pulling commits after it turned private. + basePerm, err := access_model.GetDoerRepoPermission(ctx, repo.BaseRepo, doer) + if err != nil { + return "", err + } + if !basePerm.CanRead(unit.TypeCode) { + return "", util.NewPermissionDeniedErrorf("permission denied to read base repo %d", repo.BaseRepo.ID) + } + divergingInfo, err := GetUpstreamDivergingInfo(ctx, repo, branch) if err != nil { return "", err @@ -75,7 +88,7 @@ func MergeUpstream(ctx reqctx.RequestContext, doer *user_model.User, repo *repo_ BaseBranch: divergingInfo.BaseBranchName, } fakeIssue.PullRequest = fakePR - err = pull.Update(ctx, fakePR, doer, "merge upstream", false) + err = pull.Update(fakePR, doer, "merge upstream", false) if err != nil { return "", err } diff --git a/package/gitea/source/services/repository/migrate.go b/package/gitea/source/services/repository/migrate.go index 0a27e7d7..694ed951 100644 --- a/package/gitea/source/services/repository/migrate.go +++ b/package/gitea/source/services/repository/migrate.go @@ -10,21 +10,21 @@ import ( "net/http" "time" - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/organization" - repo_model "code.gitea.io/gitea/models/repo" - unit_model "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/git/gitcmd" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/lfs" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/migration" - repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/util" + "gitea.dev/models/db" + "gitea.dev/models/organization" + repo_model "gitea.dev/models/repo" + unit_model "gitea.dev/models/unit" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/lfs" + "gitea.dev/modules/log" + "gitea.dev/modules/migration" + repo_module "gitea.dev/modules/repository" + "gitea.dev/modules/setting" + "gitea.dev/modules/timeutil" + "gitea.dev/modules/util" ) func cloneWiki(ctx context.Context, repo *repo_model.Repository, opts migration.MigrateOptions, migrateTimeout time.Duration) (string, error) { @@ -159,8 +159,10 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, } if opts.LFS { - endpoint := lfs.DetermineEndpoint(opts.CloneAddr, opts.LFSEndpoint) - lfsClient := lfs.NewClient(endpoint, httpTransport) + lfsClient, err := lfs.NewClientFromEndpoint(opts.CloneAddr, opts.LFSEndpoint, httpTransport) + if err != nil { + return repo, fmt.Errorf("NewClientFromEndpoint: %w", err) + } if err = repo_module.StoreMissingLfsObjectsInRepository(ctx, repo, gitRepo, lfsClient); err != nil { log.Error("Failed to store missing LFS objects for repository: %v", err) return repo, fmt.Errorf("StoreMissingLfsObjectsInRepository: %w", err) diff --git a/package/gitea/source/services/repository/push.go b/package/gitea/source/services/repository/push.go index 46e5fdff..49e794f1 100644 --- a/package/gitea/source/services/repository/push.go +++ b/package/gitea/source/services/repository/push.go @@ -10,32 +10,48 @@ import ( "strings" "time" - "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/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" - "code.gitea.io/gitea/modules/process" - "code.gitea.io/gitea/modules/queue" - repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/util" - issue_service "code.gitea.io/gitea/services/issue" - notify_service "code.gitea.io/gitea/services/notify" - pull_service "code.gitea.io/gitea/services/pull" + "gitea.dev/models/db" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/cache" + "gitea.dev/modules/git" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/graceful" + "gitea.dev/modules/log" + "gitea.dev/modules/process" + "gitea.dev/modules/queue" + repo_module "gitea.dev/modules/repository" + "gitea.dev/modules/setting" + "gitea.dev/modules/timeutil" + "gitea.dev/modules/util" + issue_service "gitea.dev/services/issue" + notify_service "gitea.dev/services/notify" + pull_service "gitea.dev/services/pull" ) // pushQueue represents a queue to handle update pull request tests var pushQueue *queue.WorkerPoolQueue[[]*repo_module.PushUpdateOptions] -// handle passed PR IDs and test the PRs -func handler(items ...[]*repo_module.PushUpdateOptions) [][]*repo_module.PushUpdateOptions { +func initPushQueue() error { + pushQueue = queue.CreateSimpleQueue(graceful.GetManager().ShutdownContext(), "push_update", pushQueueHandler) + if pushQueue == nil { + return errors.New("unable to create push_update queue") + } + go graceful.GetManager().RunWithCancel(pushQueue) + return nil +} + +// PushUpdates adds a push update to push queue, each call must pass the same repo updates +func PushUpdates(opts ...*repo_module.PushUpdateOptions) error { + if len(opts) == 0 { + return nil + } + return pushQueue.Push(opts) +} + +func pushQueueHandler(items ...[]*repo_module.PushUpdateOptions) [][]*repo_module.PushUpdateOptions { for _, opts := range items { - if err := pushUpdates(opts); err != nil { + if err := pushQueueHandleUpdates(opts); err != nil { // Username and repository stays the same between items in opts. pushUpdate := opts[0] log.Error("pushUpdate[%s/%s] failed: %v", pushUpdate.RepoUserName, pushUpdate.RepoName, err) @@ -44,37 +60,8 @@ func handler(items ...[]*repo_module.PushUpdateOptions) [][]*repo_module.PushUpd return nil } -func initPushQueue() error { - pushQueue = queue.CreateSimpleQueue(graceful.GetManager().ShutdownContext(), "push_update", handler) - if pushQueue == nil { - return errors.New("unable to create push_update queue") - } - go graceful.GetManager().RunWithCancel(pushQueue) - return nil -} - -// PushUpdate is an alias of PushUpdates for single push update options -func PushUpdate(opts *repo_module.PushUpdateOptions) error { - return PushUpdates([]*repo_module.PushUpdateOptions{opts}) -} - -// PushUpdates adds a push update to push queue -func PushUpdates(opts []*repo_module.PushUpdateOptions) error { - if len(opts) == 0 { - return nil - } - - for _, opt := range opts { - if opt.IsNewRef() && opt.IsDelRef() { - return errors.New("Old and new revisions are both NULL") - } - } - - return pushQueue.Push(opts) -} - -// pushUpdates generates push action history feeds for push updating multiple refs -func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { +// pushQueueHandleUpdates generates push action history feeds for push updating multiple refs +func pushQueueHandleUpdates(optsList []*repo_module.PushUpdateOptions) error { if len(optsList) == 0 { return nil } @@ -94,7 +81,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { defer gitRepo.Close() if err = repo_module.UpdateRepoSize(ctx, repo); err != nil { - return fmt.Errorf("Failed to update size for repository: %v", err) + return fmt.Errorf("failed to update size for repository: %v", err) } addTags := make([]string, 0, len(optsList)) @@ -104,10 +91,11 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { for _, opts := range optsList { log.Trace("pushUpdates: %-v %s %s %s", repo, opts.OldCommitID, opts.NewCommitID, opts.RefFullName) - if opts.IsNewRef() && opts.IsDelRef() { - return fmt.Errorf("old and new revisions are both %s", objectFormat.EmptyObjectID()) + setting.PanicInDevOrTesting("invalid push update (add+del): %+v", opts) + continue } + if opts.RefFullName.IsTag() { if pusher == nil || pusher.ID != opts.PusherID { if opts.PusherID == user_model.ActionsUserID { @@ -189,12 +177,15 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { return err } - // delete cache for divergence + // sync branch related database data if branch == repo.DefaultBranch { if err := DelRepoDivergenceFromCache(ctx, repo.ID); err != nil { log.Error("DelRepoDivergenceFromCache: %v", err) } indexHeatmap = true + if err := AddRepoToLicenseUpdaterQueue(&LicenseUpdaterOptions{RepoID: repo.ID}); err != nil { + log.Error("AddRepoToLicenseUpdaterQueue: %v", err) + } } else { if err := DelDivergenceFromCache(repo.ID, branch); err != nil { log.Error("DelDivergenceFromCache: %v", err) @@ -305,7 +296,7 @@ func pushNewBranch(ctx context.Context, repo *repo_model.Repository, pusher *use } func pushUpdateBranch(_ context.Context, repo *repo_model.Repository, pusher *user_model.User, opts *repo_module.PushUpdateOptions, newCommit *git.Commit) ([]*git.Commit, error) { - l, err := newCommit.CommitsBeforeUntil(opts.OldCommitID) + l, err := newCommit.CommitsBeforeUntil(git.RefNameFromCommit(opts.OldCommitID)) if err != nil { return nil, fmt.Errorf("newCommit.CommitsBeforeUntil: %w", err) } @@ -410,7 +401,7 @@ func pushUpdateAddTags(ctx context.Context, repo *repo_model.Repository, gitRepo } rel, has := relMap[lowerTag] - title, note := git.SplitCommitTitleBody(strings.ToValidUTF8(tag.Message, "?"), 255) + title, note := git.SplitCommitTitleBody(tag.MessageUTF8(), 255) if !has { rel = &repo_model.Release{ RepoID: repo.ID, diff --git a/package/gitea/source/services/repository/repo_team.go b/package/gitea/source/services/repository/repo_team.go index 9a9df290..3a11d109 100644 --- a/package/gitea/source/services/repository/repo_team.go +++ b/package/gitea/source/services/repository/repo_team.go @@ -8,12 +8,12 @@ import ( "errors" "fmt" - "code.gitea.io/gitea/models/db" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/organization" - access_model "code.gitea.io/gitea/models/perm/access" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/setting" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + "gitea.dev/models/organization" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/setting" ) // TeamAddRepository adds new repository to team of organization. diff --git a/package/gitea/source/services/repository/repo_team_test.go b/package/gitea/source/services/repository/repo_team_test.go index 1139d06c..f3451aaa 100644 --- a/package/gitea/source/services/repository/repo_team_test.go +++ b/package/gitea/source/services/repository/repo_team_test.go @@ -6,9 +6,9 @@ package repository import ( "testing" - "code.gitea.io/gitea/models/organization" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/models/unittest" + "gitea.dev/models/organization" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/repository/repository.go b/package/gitea/source/services/repository/repository.go index 2ac95ffe..7d1b47b6 100644 --- a/package/gitea/source/services/repository/repository.go +++ b/package/gitea/source/services/repository/repository.go @@ -9,25 +9,25 @@ import ( "fmt" "strings" - activities_model "code.gitea.io/gitea/models/activities" - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/git" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/organization" - access_model "code.gitea.io/gitea/models/perm/access" - 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/gitrepo" - "code.gitea.io/gitea/modules/graceful" - issue_indexer "code.gitea.io/gitea/modules/indexer/issues" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/queue" - repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/structs" - notify_service "code.gitea.io/gitea/services/notify" - pull_service "code.gitea.io/gitea/services/pull" + activities_model "gitea.dev/models/activities" + "gitea.dev/models/db" + "gitea.dev/models/git" + issues_model "gitea.dev/models/issues" + "gitea.dev/models/organization" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unit" + user_model "gitea.dev/models/user" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/graceful" + issue_indexer "gitea.dev/modules/indexer/issues" + "gitea.dev/modules/log" + "gitea.dev/modules/queue" + repo_module "gitea.dev/modules/repository" + "gitea.dev/modules/setting" + "gitea.dev/modules/structs" + notify_service "gitea.dev/services/notify" + pull_service "gitea.dev/services/pull" ) // WebSearchRepository represents a repository returned by web search @@ -273,6 +273,11 @@ func updateRepository(ctx context.Context, repo *repo_model.Repository, visibili if err = repo_model.ClearRepoStars(ctx, repo.ID); err != nil { return err } + + // watchers who lost access must not keep watching the now-private repo + if err = repo_model.ClearRepoWatches(ctx, repo.ID); err != nil { + return err + } } // Create/Remove git-daemon-export-ok for git-daemon... diff --git a/package/gitea/source/services/repository/repository_test.go b/package/gitea/source/services/repository/repository_test.go index 5a879a6a..756801c2 100644 --- a/package/gitea/source/services/repository/repository_test.go +++ b/package/gitea/source/services/repository/repository_test.go @@ -6,11 +6,11 @@ package repository import ( "testing" - activities_model "code.gitea.io/gitea/models/activities" - "code.gitea.io/gitea/models/db" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/models/unit" - "code.gitea.io/gitea/models/unittest" + activities_model "gitea.dev/models/activities" + "gitea.dev/models/db" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unit" + "gitea.dev/models/unittest" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -90,3 +90,26 @@ func TestMakeRepoPrivateClearsWatches(t *testing.T) { assert.True(t, updatedRepo.IsPrivate) assert.Zero(t, updatedRepo.NumWatches) } + +// TestUpdateRepositoryClearsWatchesOnVisibilityChange ensures the shared updateRepository +// helper (used by the API EditRepo path) also clears watches when a repo goes private. +func TestUpdateRepositoryClearsWatchesOnVisibilityChange(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + assert.False(t, repo.IsPrivate) + + watchers, err := repo_model.GetRepoWatchersIDs(t.Context(), repo.ID) + require.NoError(t, err) + require.NotEmpty(t, watchers) + + repo.IsPrivate = true + require.NoError(t, updateRepository(t.Context(), repo, true)) + + watchers, err = repo_model.GetRepoWatchersIDs(t.Context(), repo.ID) + assert.NoError(t, err) + assert.Empty(t, watchers) + + updatedRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID}) + assert.Zero(t, updatedRepo.NumWatches) +} diff --git a/package/gitea/source/services/repository/setting.go b/package/gitea/source/services/repository/setting.go index b6873691..5182c9b2 100644 --- a/package/gitea/source/services/repository/setting.go +++ b/package/gitea/source/services/repository/setting.go @@ -7,11 +7,11 @@ import ( "context" "slices" - "code.gitea.io/gitea/models/db" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/models/unit" - "code.gitea.io/gitea/modules/log" - actions_service "code.gitea.io/gitea/services/actions" + "gitea.dev/models/db" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unit" + "gitea.dev/modules/log" + actions_service "gitea.dev/services/actions" ) // UpdateRepositoryUnits updates a repository's units diff --git a/package/gitea/source/services/repository/template.go b/package/gitea/source/services/repository/template.go index c49e2cdd..96f7cdb4 100644 --- a/package/gitea/source/services/repository/template.go +++ b/package/gitea/source/services/repository/template.go @@ -8,14 +8,14 @@ import ( "fmt" "strings" - "code.gitea.io/gitea/models/db" - git_model "code.gitea.io/gitea/models/git" - issues_model "code.gitea.io/gitea/models/issues" - repo_model "code.gitea.io/gitea/models/repo" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/log" - notify_service "code.gitea.io/gitea/services/notify" + "gitea.dev/models/db" + git_model "gitea.dev/models/git" + issues_model "gitea.dev/models/issues" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/log" + notify_service "gitea.dev/services/notify" ) // GenerateIssueLabels generates issue labels from a template repository diff --git a/package/gitea/source/services/repository/transfer.go b/package/gitea/source/services/repository/transfer.go index 217ecb01..76051ac4 100644 --- a/package/gitea/source/services/repository/transfer.go +++ b/package/gitea/source/services/repository/transfer.go @@ -8,21 +8,20 @@ import ( "fmt" "strings" - actions_model "code.gitea.io/gitea/models/actions" - "code.gitea.io/gitea/models/db" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/organization" - "code.gitea.io/gitea/models/perm" - access_model "code.gitea.io/gitea/models/perm/access" - project_model "code.gitea.io/gitea/models/project" - repo_model "code.gitea.io/gitea/models/repo" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/globallock" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" - notify_service "code.gitea.io/gitea/services/notify" + actions_model "gitea.dev/models/actions" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + "gitea.dev/models/organization" + "gitea.dev/models/perm" + access_model "gitea.dev/models/perm/access" + project_model "gitea.dev/models/project" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/globallock" + "gitea.dev/modules/log" + "gitea.dev/modules/util" + notify_service "gitea.dev/services/notify" ) type LimitReachedError struct{ Limit int } @@ -62,8 +61,7 @@ func AcceptTransferOwnership(ctx context.Context, repo *repo_model.Repository, d } if !doer.CanCreateRepoIn(repoTransfer.Recipient) { - limit := util.Iif(repoTransfer.Recipient.MaxRepoCreation >= 0, repoTransfer.Recipient.MaxRepoCreation, setting.Repository.MaxCreationLimit) - return LimitReachedError{Limit: limit} + return LimitReachedError{Limit: repoTransfer.Recipient.MaxCreationLimit()} } if !repoTransfer.CanUserAcceptOrRejectTransfer(ctx, doer) { @@ -120,7 +118,7 @@ func transferOwnership(ctx context.Context, doer *user_model.User, newOwnerName if repoRenamed { oldRelativePath, newRelativePath := repo_model.RelativePath(newOwnerName, repo.Name), repo_model.RelativePath(oldOwnerName, repo.Name) if err := gitrepo.RenameRepository(ctx, repo_model.StorageRepo(oldRelativePath), repo_model.StorageRepo(newRelativePath)); err != nil { - log.Critical("Unable to move repository %s/%s directory from %s back to correct place %s: %v", oldOwnerName, repo.Name, + log.Error("Unable to move repository %s/%s directory from %s back to correct place %s: %v", oldOwnerName, repo.Name, oldRelativePath, newRelativePath, err) } } @@ -128,7 +126,7 @@ func transferOwnership(ctx context.Context, doer *user_model.User, newOwnerName if wikiRenamed { oldRelativePath, newRelativePath := repo_model.RelativeWikiPath(newOwnerName, repo.Name), repo_model.RelativeWikiPath(oldOwnerName, repo.Name) if err := gitrepo.RenameRepository(ctx, repo_model.StorageRepo(oldRelativePath), repo_model.StorageRepo(newRelativePath)); err != nil { - log.Critical("Unable to move wiki for repository %s/%s directory from %s back to correct place %s: %v", oldOwnerName, repo.Name, + log.Error("Unable to move wiki for repository %s/%s directory from %s back to correct place %s: %v", oldOwnerName, repo.Name, oldRelativePath, newRelativePath, err) } } @@ -434,8 +432,7 @@ func StartRepositoryTransfer(ctx context.Context, doer, newOwner *user_model.Use } if !doer.CanForkRepoIn(newOwner) { - limit := util.Iif(newOwner.MaxRepoCreation >= 0, newOwner.MaxRepoCreation, setting.Repository.MaxCreationLimit) - return LimitReachedError{Limit: limit} + return LimitReachedError{Limit: newOwner.MaxCreationLimit()} } var isDirectTransfer bool diff --git a/package/gitea/source/services/repository/transfer_test.go b/package/gitea/source/services/repository/transfer_test.go index 8d73fef7..85282a11 100644 --- a/package/gitea/source/services/repository/transfer_test.go +++ b/package/gitea/source/services/repository/transfer_test.go @@ -7,17 +7,17 @@ import ( "sync" "testing" - activities_model "code.gitea.io/gitea/models/activities" - "code.gitea.io/gitea/models/organization" - access_model "code.gitea.io/gitea/models/perm/access" - 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/setting" - "code.gitea.io/gitea/modules/test" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/services/feed" - notify_service "code.gitea.io/gitea/services/notify" + activities_model "gitea.dev/models/activities" + "gitea.dev/models/organization" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/modules/setting" + "gitea.dev/modules/test" + "gitea.dev/modules/util" + "gitea.dev/services/feed" + notify_service "gitea.dev/services/notify" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -133,6 +133,8 @@ func TestRepositoryTransferRejection(t *testing.T) { require.NoError(t, unittest.PrepareTestDatabase()) // Set limit to 0 repositories so no repositories can be transferred defer test.MockVariableValue(&setting.Repository.MaxCreationLimit, 0)() + defer test.MockVariableValue(&setting.Repository.UserMaxCreationLimit, 0)() + defer test.MockVariableValue(&setting.Repository.OrgMaxCreationLimit, 0)() // Admin case doerAdmin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) diff --git a/package/gitea/source/services/secrets/secrets.go b/package/gitea/source/services/secrets/secrets.go index 1aec6e14..af7f8977 100644 --- a/package/gitea/source/services/secrets/secrets.go +++ b/package/gitea/source/services/secrets/secrets.go @@ -6,8 +6,8 @@ package secrets import ( "context" - "code.gitea.io/gitea/models/db" - secret_model "code.gitea.io/gitea/models/secret" + "gitea.dev/models/db" + secret_model "gitea.dev/models/secret" ) func CreateOrUpdateSecret(ctx context.Context, ownerID, repoID int64, name, data, description string) (*secret_model.Secret, bool, error) { diff --git a/package/gitea/source/services/secrets/validation.go b/package/gitea/source/services/secrets/validation.go index d3636ded..6b711f63 100644 --- a/package/gitea/source/services/secrets/validation.go +++ b/package/gitea/source/services/secrets/validation.go @@ -8,7 +8,7 @@ import ( "strings" "sync" - "code.gitea.io/gitea/modules/util" + "gitea.dev/modules/util" ) // https://docs.github.com/en/actions/learn-github-actions/variables#naming-conventions-for-configuration-variables diff --git a/package/gitea/source/services/task/migrate.go b/package/gitea/source/services/task/migrate.go index 9cef77a6..e8627d0c 100644 --- a/package/gitea/source/services/task/migrate.go +++ b/package/gitea/source/services/task/migrate.go @@ -10,20 +10,20 @@ import ( "strings" "time" - admin_model "code.gitea.io/gitea/models/admin" - "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/graceful" - "code.gitea.io/gitea/modules/json" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/migration" - "code.gitea.io/gitea/modules/process" - "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/services/migrations" - notify_service "code.gitea.io/gitea/services/notify" + admin_model "gitea.dev/models/admin" + "gitea.dev/models/db" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/graceful" + "gitea.dev/modules/json" + "gitea.dev/modules/log" + "gitea.dev/modules/migration" + "gitea.dev/modules/process" + "gitea.dev/modules/structs" + "gitea.dev/modules/timeutil" + "gitea.dev/modules/util" + "gitea.dev/services/migrations" + notify_service "gitea.dev/services/notify" ) func handleCreateError(owner *user_model.User, err error) error { @@ -45,7 +45,7 @@ func runMigrateTask(ctx context.Context, t *admin_model.Task) (err error) { defer func(ctx context.Context) { if e := recover(); e != nil { err = fmt.Errorf("PANIC whilst trying to do migrate task: %v", e) - log.Critical("PANIC during runMigrateTask[%d] by DoerID[%d] to RepoID[%d] for OwnerID[%d]: %v\nStacktrace: %v", t.ID, t.DoerID, t.RepoID, t.OwnerID, e, log.Stack(2)) + log.Error("PANIC during runMigrateTask[%d] by DoerID[%d] to RepoID[%d] for OwnerID[%d]: %v\nStacktrace: %v", t.ID, t.DoerID, t.RepoID, t.OwnerID, e, log.Stack(2)) } if err == nil { err = admin_model.FinishMigrateTask(ctx, t) diff --git a/package/gitea/source/services/task/task.go b/package/gitea/source/services/task/task.go index 25eccd10..869e2427 100644 --- a/package/gitea/source/services/task/task.go +++ b/package/gitea/source/services/task/task.go @@ -8,20 +8,20 @@ import ( "errors" "fmt" - admin_model "code.gitea.io/gitea/models/admin" - repo_model "code.gitea.io/gitea/models/repo" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/json" - "code.gitea.io/gitea/modules/log" - base "code.gitea.io/gitea/modules/migration" - "code.gitea.io/gitea/modules/queue" - "code.gitea.io/gitea/modules/secret" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/util" - repo_service "code.gitea.io/gitea/services/repository" + admin_model "gitea.dev/models/admin" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/graceful" + "gitea.dev/modules/json" + "gitea.dev/modules/log" + base "gitea.dev/modules/migration" + "gitea.dev/modules/queue" + "gitea.dev/modules/secret" + "gitea.dev/modules/setting" + "gitea.dev/modules/structs" + "gitea.dev/modules/timeutil" + "gitea.dev/modules/util" + repo_service "gitea.dev/services/repository" ) // taskQueue is a global queue of tasks diff --git a/package/gitea/source/services/uinotification/notify.go b/package/gitea/source/services/uinotification/notify.go index dd3f1557..1a6caf63 100644 --- a/package/gitea/source/services/uinotification/notify.go +++ b/package/gitea/source/services/uinotification/notify.go @@ -6,16 +6,16 @@ package uinotification import ( "context" - activities_model "code.gitea.io/gitea/models/activities" - "code.gitea.io/gitea/models/db" - issues_model "code.gitea.io/gitea/models/issues" - 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/graceful" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/queue" - notify_service "code.gitea.io/gitea/services/notify" + activities_model "gitea.dev/models/activities" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/container" + "gitea.dev/modules/graceful" + "gitea.dev/modules/log" + "gitea.dev/modules/queue" + notify_service "gitea.dev/services/notify" ) type ( diff --git a/package/gitea/source/services/user/avatar.go b/package/gitea/source/services/user/avatar.go index 6a43681e..f49a8526 100644 --- a/package/gitea/source/services/user/avatar.go +++ b/package/gitea/source/services/user/avatar.go @@ -10,11 +10,11 @@ import ( "io" "os" - "code.gitea.io/gitea/models/db" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/avatar" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/storage" + "gitea.dev/models/db" + user_model "gitea.dev/models/user" + "gitea.dev/modules/avatar" + "gitea.dev/modules/log" + "gitea.dev/modules/storage" ) // UploadAvatar saves custom avatar for user. diff --git a/package/gitea/source/services/user/block.go b/package/gitea/source/services/user/block.go index 7727780d..19b4dfa5 100644 --- a/package/gitea/source/services/user/block.go +++ b/package/gitea/source/services/user/block.go @@ -6,12 +6,12 @@ package user import ( "context" - "code.gitea.io/gitea/models/db" - issues_model "code.gitea.io/gitea/models/issues" - org_model "code.gitea.io/gitea/models/organization" - repo_model "code.gitea.io/gitea/models/repo" - user_model "code.gitea.io/gitea/models/user" - repo_service "code.gitea.io/gitea/services/repository" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + org_model "gitea.dev/models/organization" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + repo_service "gitea.dev/services/repository" ) func CanBlockUser(ctx context.Context, doer, blocker, blockee *user_model.User) bool { diff --git a/package/gitea/source/services/user/block_test.go b/package/gitea/source/services/user/block_test.go index 5dc6c121..dc90ddd7 100644 --- a/package/gitea/source/services/user/block_test.go +++ b/package/gitea/source/services/user/block_test.go @@ -6,8 +6,8 @@ package user import ( "testing" - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/user/delete.go b/package/gitea/source/services/user/delete.go index 39c6ef05..e6ff7075 100644 --- a/package/gitea/source/services/user/delete.go +++ b/package/gitea/source/services/user/delete.go @@ -8,26 +8,26 @@ import ( "fmt" "time" - _ "image/jpeg" // Needed for jpeg support + actions_model "gitea.dev/models/actions" + activities_model "gitea.dev/models/activities" + asymkey_model "gitea.dev/models/asymkey" + auth_model "gitea.dev/models/auth" + "gitea.dev/models/db" + git_model "gitea.dev/models/git" + issues_model "gitea.dev/models/issues" + "gitea.dev/models/organization" + access_model "gitea.dev/models/perm/access" + pull_model "gitea.dev/models/pull" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/setting" - actions_model "code.gitea.io/gitea/models/actions" - activities_model "code.gitea.io/gitea/models/activities" - asymkey_model "code.gitea.io/gitea/models/asymkey" - auth_model "code.gitea.io/gitea/models/auth" - "code.gitea.io/gitea/models/db" - git_model "code.gitea.io/gitea/models/git" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/organization" - 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/setting" + _ "image/jpeg" // Needed for jpeg support "xorm.io/builder" ) -// deleteUser deletes models associated to an user. +// deleteUser deletes models associated to a user. func deleteUser(ctx context.Context, u *user_model.User, purge bool) (err error) { e := db.GetEngine(ctx) @@ -95,6 +95,11 @@ func deleteUser(ctx context.Context, u *user_model.User, purge bool) (err error) &user_model.Blocking{BlockerID: u.ID}, &user_model.Blocking{BlockeeID: u.ID}, &actions_model.ActionRunnerToken{OwnerID: u.ID}, + &actions_model.ActionScopedWorkflowSource{OwnerID: u.ID}, + &auth_model.TwoFactor{UID: u.ID}, + &auth_model.WebAuthnCredential{UserID: u.ID}, + &activities_model.Notification{UserID: u.ID}, + &issues_model.IssueWatch{UserID: u.ID}, ); err != nil { return fmt.Errorf("deleteBeans: %w", err) } diff --git a/package/gitea/source/services/user/email.go b/package/gitea/source/services/user/email.go index 927e4b72..09939fa5 100644 --- a/package/gitea/source/services/user/email.go +++ b/package/gitea/source/services/user/email.go @@ -8,10 +8,10 @@ import ( "errors" "strings" - "code.gitea.io/gitea/models/db" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" + "gitea.dev/models/db" + user_model "gitea.dev/models/user" + "gitea.dev/modules/setting" + "gitea.dev/modules/util" ) // ReplacePrimaryEmailAddress replaces the user's primary email address with the given email address. diff --git a/package/gitea/source/services/user/email_test.go b/package/gitea/source/services/user/email_test.go index 9fb0560b..809fb621 100644 --- a/package/gitea/source/services/user/email_test.go +++ b/package/gitea/source/services/user/email_test.go @@ -6,8 +6,8 @@ package user import ( "testing" - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/user/update.go b/package/gitea/source/services/user/update.go index 4793a781..5ff4652e 100644 --- a/package/gitea/source/services/user/update.go +++ b/package/gitea/source/services/user/update.go @@ -7,13 +7,13 @@ import ( "context" "fmt" - auth_model "code.gitea.io/gitea/models/auth" - "code.gitea.io/gitea/models/db" - user_model "code.gitea.io/gitea/models/user" - password_module "code.gitea.io/gitea/modules/auth/password" - "code.gitea.io/gitea/modules/optional" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/structs" + auth_model "gitea.dev/models/auth" + "gitea.dev/models/db" + user_model "gitea.dev/models/user" + password_module "gitea.dev/modules/auth/password" + "gitea.dev/modules/optional" + "gitea.dev/modules/setting" + "gitea.dev/modules/structs" ) type UpdateOptionField[T any] struct { @@ -147,7 +147,8 @@ func UpdateUser(ctx context.Context, u *user_model.User, opts *UpdateOptions) er } } - if opts.Visibility.Has() { + // only validate and persist the visibility when it actually changes + if opts.Visibility.Has() && opts.Visibility.Value() != u.Visibility { if !u.IsOrganization() && !setting.Service.AllowedUserVisibilityModesSlice.IsAllowedVisibility(opts.Visibility.Value()) { return fmt.Errorf("visibility mode not allowed: %s", opts.Visibility.Value().String()) } diff --git a/package/gitea/source/services/user/update_test.go b/package/gitea/source/services/user/update_test.go index 9567a04b..65e9cc0d 100644 --- a/package/gitea/source/services/user/update_test.go +++ b/package/gitea/source/services/user/update_test.go @@ -6,11 +6,13 @@ package user import ( "testing" - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" - password_module "code.gitea.io/gitea/modules/auth/password" - "code.gitea.io/gitea/modules/optional" - "code.gitea.io/gitea/modules/structs" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + password_module "gitea.dev/modules/auth/password" + "gitea.dev/modules/optional" + "gitea.dev/modules/setting" + "gitea.dev/modules/structs" + "gitea.dev/modules/test" "github.com/stretchr/testify/assert" ) @@ -128,3 +130,33 @@ func TestUpdateAuth(t *testing.T) { Password: optional.Some("aaaa"), }), password_module.ErrMinLength) } + +func TestUpdateUserVisibility(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + // user28's current visibility is public, e.g. an account created before public was disallowed + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 28}) + assert.Equal(t, structs.VisibleTypePublic, user.Visibility) + + // public is no longer an allowed visibility mode, e.g. ALLOWED_USER_VISIBILITY_MODES = limited, private + defer test.MockVariableValue(&setting.Service.AllowedUserVisibilityModesSlice, setting.AllowedVisibility{false, true, true})() + + // re-submitting the unchanged (now-disallowed) visibility must not fail the whole update + assert.NoError(t, UpdateUser(t.Context(), user, &UpdateOptions{ + FullName: optional.Some("Changed Name"), + Visibility: optional.Some(structs.VisibleTypePublic), + })) + assert.Equal(t, "Changed Name", user.FullName) + assert.Equal(t, structs.VisibleTypePublic, user.Visibility) + + // changing to an allowed visibility still works + assert.NoError(t, UpdateUser(t.Context(), user, &UpdateOptions{ + Visibility: optional.Some(structs.VisibleTypePrivate), + })) + assert.Equal(t, structs.VisibleTypePrivate, user.Visibility) + + // genuinely changing to a disallowed visibility is still rejected + assert.Error(t, UpdateUser(t.Context(), user, &UpdateOptions{ + Visibility: optional.Some(structs.VisibleTypePublic), + })) +} diff --git a/package/gitea/source/services/user/user.go b/package/gitea/source/services/user/user.go index 9b8bcf83..91551fe2 100644 --- a/package/gitea/source/services/user/user.go +++ b/package/gitea/source/services/user/user.go @@ -10,24 +10,24 @@ import ( "strings" "time" - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/organization" - packages_model "code.gitea.io/gitea/models/packages" - repo_model "code.gitea.io/gitea/models/repo" - system_model "code.gitea.io/gitea/models/system" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/eventsource" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/storage" - "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/services/agit" - asymkey_service "code.gitea.io/gitea/services/asymkey" - org_service "code.gitea.io/gitea/services/org" - "code.gitea.io/gitea/services/packages" - container_service "code.gitea.io/gitea/services/packages/container" - repo_service "code.gitea.io/gitea/services/repository" + "gitea.dev/models/db" + "gitea.dev/models/organization" + packages_model "gitea.dev/models/packages" + repo_model "gitea.dev/models/repo" + system_model "gitea.dev/models/system" + user_model "gitea.dev/models/user" + "gitea.dev/modules/eventsource" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" + "gitea.dev/modules/storage" + "gitea.dev/modules/structs" + "gitea.dev/modules/util" + "gitea.dev/services/agit" + asymkey_service "gitea.dev/services/asymkey" + org_service "gitea.dev/services/org" + "gitea.dev/services/packages" + container_service "gitea.dev/services/packages/container" + repo_service "gitea.dev/services/repository" ) // RenameUser renames a user @@ -108,7 +108,7 @@ func RenameUser(ctx context.Context, u *user_model.User, newUserName string, doe u.Name = oldUserName u.LowerName = strings.ToLower(oldUserName) if err2 := util.Rename(user_model.UserPath(newUserName), user_model.UserPath(oldUserName)); err2 != nil && !os.IsNotExist(err2) { - log.Critical("Unable to rollback directory change during failed username change from: %s to: %s. DB Error: %v. Filesystem Error: %v", oldUserName, newUserName, err, err2) + log.Error("Unable to rollback directory change during failed username change from: %s to: %s. DB Error: %v. Filesystem Error: %v", oldUserName, newUserName, err, err2) return fmt.Errorf("failed to rollback directory change during failed username change from: %s to: %s. DB Error: %w. Filesystem Error: %v", oldUserName, newUserName, err, err2) } return err diff --git a/package/gitea/source/services/user/user_test.go b/package/gitea/source/services/user/user_test.go index 4d8d448d..3daf5763 100644 --- a/package/gitea/source/services/user/user_test.go +++ b/package/gitea/source/services/user/user_test.go @@ -9,15 +9,17 @@ import ( "testing" "time" - "code.gitea.io/gitea/models/auth" - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/organization" - 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/setting" - "code.gitea.io/gitea/modules/timeutil" - org_service "code.gitea.io/gitea/services/org" + activities_model "gitea.dev/models/activities" + "gitea.dev/models/auth" + "gitea.dev/models/db" + issues_model "gitea.dev/models/issues" + "gitea.dev/models/organization" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/modules/setting" + "gitea.dev/modules/timeutil" + org_service "gitea.dev/services/org" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -61,6 +63,32 @@ func TestDeleteUser(t *testing.T) { org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) assert.Error(t, DeleteUser(t.Context(), org, false)) + + t.Run("CleanupOrphanedTables", func(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + // assert they exist before deletion + unittest.AssertExistsAndLoadBean(t, &auth.TwoFactor{UID: 24}) + unittest.AssertExistsAndLoadBean(t, &auth.WebAuthnCredential{UserID: 32}) + unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{UserID: 2}) + unittest.AssertExistsAndLoadBean(t, &issues_model.IssueWatch{UserID: 2}) + + // delete users + user24 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 24}) + assert.NoError(t, DeleteUser(t.Context(), user24, true)) + + user32 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 32}) + assert.NoError(t, DeleteUser(t.Context(), user32, true)) + + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + assert.NoError(t, DeleteUser(t.Context(), user2, true)) + + // assert they do not exist after deletion + unittest.AssertNotExistsBean(t, &auth.TwoFactor{UID: 24}) + unittest.AssertNotExistsBean(t, &auth.WebAuthnCredential{UserID: 32}) + unittest.AssertNotExistsBean(t, &activities_model.Notification{UserID: 2}) + unittest.AssertNotExistsBean(t, &issues_model.IssueWatch{UserID: 2}) + }) } func TestDeleteUserUnlinkedAttachments(t *testing.T) { diff --git a/package/gitea/source/services/versioned_migration/migration.go b/package/gitea/source/services/versioned_migration/migration.go index c064bf79..cf92b9b6 100644 --- a/package/gitea/source/services/versioned_migration/migration.go +++ b/package/gitea/source/services/versioned_migration/migration.go @@ -6,13 +6,12 @@ package versioned_migration import ( "context" - "code.gitea.io/gitea/models/migrations" - "code.gitea.io/gitea/modules/globallock" - - "xorm.io/xorm" + "gitea.dev/models/db" + "gitea.dev/models/migrations" + "gitea.dev/modules/globallock" ) -func Migrate(ctx context.Context, x *xorm.Engine) error { +func Migrate(ctx context.Context, x db.EngineMigration) error { // only one instance can do the migration at the same time if there are multiple instances release, err := globallock.Lock(ctx, "gitea_versioned_migration") if err != nil { diff --git a/package/gitea/source/services/webhook/deliver.go b/package/gitea/source/services/webhook/deliver.go index 58fba9f6..fc674f7c 100644 --- a/package/gitea/source/services/webhook/deliver.go +++ b/package/gitea/source/services/webhook/deliver.go @@ -19,27 +19,24 @@ import ( "sync" "time" - user_model "code.gitea.io/gitea/models/user" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/glob" - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/hostmatcher" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/process" - "code.gitea.io/gitea/modules/proxy" - "code.gitea.io/gitea/modules/queue" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/util" - webhook_module "code.gitea.io/gitea/modules/webhook" + user_model "gitea.dev/models/user" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/glob" + "gitea.dev/modules/graceful" + "gitea.dev/modules/hostmatcher" + "gitea.dev/modules/log" + "gitea.dev/modules/process" + "gitea.dev/modules/proxy" + "gitea.dev/modules/queue" + "gitea.dev/modules/setting" + "gitea.dev/modules/timeutil" + "gitea.dev/modules/util" + webhook_module "gitea.dev/modules/webhook" ) func newDefaultRequest(ctx context.Context, w *webhook_model.Webhook, t *webhook_model.HookTask) (req *http.Request, body []byte, err error) { switch w.HTTPMethod { - case "": - log.Info("HTTP Method for %s webhook %s [ID: %d] is not set, defaulting to POST", w.Type, w.URL, w.ID) - fallthrough - case http.MethodPost: + case "", http.MethodPost: switch w.ContentType { case webhook_model.ContentTypeJSON: req, err = http.NewRequest(http.MethodPost, w.URL, strings.NewReader(t.PayloadContent)) @@ -311,20 +308,14 @@ func webhookProxy(allowList *hostmatcher.HostMatchList) func(req *http.Request) // Init starts the hooks delivery thread func Init() error { timeout := time.Duration(setting.Webhook.DeliverTimeout) * time.Second + allowedHostMatcher := hostmatcher.ParseHostMatchList("security.ALLOWED_HOST_LIST", setting.Webhook.AllowedHostList) - allowedHostListValue := setting.Webhook.AllowedHostList - if allowedHostListValue == "" { - allowedHostListValue = hostmatcher.MatchBuiltinExternal - } - allowedHostMatcher := hostmatcher.ParseHostMatchList("webhook.ALLOWED_HOST_LIST", allowedHostListValue) - + // NewHTTPTransport enforces the allow-list on direct connections; when webhookProxy routes a request + // through a configured proxy, restricting the proxied target is the proxy server's responsibility. webhookHTTPClient = &http.Client{ Timeout: timeout, - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: setting.Webhook.SkipTLSVerify}, - Proxy: webhookProxy(allowedHostMatcher), - DialContext: hostmatcher.NewDialContext("webhook", allowedHostMatcher, nil, setting.Webhook.ProxyURLFixed), - }, + Transport: hostmatcher.NewHTTPTransport("webhook", allowedHostMatcher, nil, webhookProxy(allowedHostMatcher), setting.Webhook.ProxyURLFixed, + &tls.Config{InsecureSkipVerify: setting.Webhook.SkipTLSVerify}), } hookQueue = queue.CreateUniqueQueue(graceful.GetManager().ShutdownContext(), "webhook_sender", handler) diff --git a/package/gitea/source/services/webhook/deliver_test.go b/package/gitea/source/services/webhook/deliver_test.go index 822184aa..83d55072 100644 --- a/package/gitea/source/services/webhook/deliver_test.go +++ b/package/gitea/source/services/webhook/deliver_test.go @@ -12,12 +12,12 @@ import ( "testing" "time" - "code.gitea.io/gitea/models/unittest" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/hostmatcher" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" - webhook_module "code.gitea.io/gitea/modules/webhook" + "gitea.dev/models/unittest" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/hostmatcher" + "gitea.dev/modules/setting" + "gitea.dev/modules/util" + webhook_module "gitea.dev/modules/webhook" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/package/gitea/source/services/webhook/dingtalk.go b/package/gitea/source/services/webhook/dingtalk.go index 95582654..0403fdaa 100644 --- a/package/gitea/source/services/webhook/dingtalk.go +++ b/package/gitea/source/services/webhook/dingtalk.go @@ -10,11 +10,11 @@ import ( "net/url" "strings" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/git" - api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" - webhook_module "code.gitea.io/gitea/modules/webhook" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/git" + api "gitea.dev/modules/structs" + "gitea.dev/modules/util" + webhook_module "gitea.dev/modules/webhook" dingtalk "gitea.com/lunny/dingtalk_webhook" ) diff --git a/package/gitea/source/services/webhook/dingtalk_test.go b/package/gitea/source/services/webhook/dingtalk_test.go index 763d2304..afe391d8 100644 --- a/package/gitea/source/services/webhook/dingtalk_test.go +++ b/package/gitea/source/services/webhook/dingtalk_test.go @@ -7,10 +7,10 @@ import ( "net/url" "testing" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/json" - api "code.gitea.io/gitea/modules/structs" - webhook_module "code.gitea.io/gitea/modules/webhook" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/json" + api "gitea.dev/modules/structs" + webhook_module "gitea.dev/modules/webhook" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/package/gitea/source/services/webhook/discord.go b/package/gitea/source/services/webhook/discord.go index c0af7c02..9bbeab3f 100644 --- a/package/gitea/source/services/webhook/discord.go +++ b/package/gitea/source/services/webhook/discord.go @@ -13,14 +13,14 @@ import ( "strings" "unicode/utf8" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/json" - "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" - webhook_module "code.gitea.io/gitea/modules/webhook" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/git" + "gitea.dev/modules/json" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" + api "gitea.dev/modules/structs" + "gitea.dev/modules/util" + webhook_module "gitea.dev/modules/webhook" ) type ( diff --git a/package/gitea/source/services/webhook/discord_test.go b/package/gitea/source/services/webhook/discord_test.go index 7f503e33..162a15f7 100644 --- a/package/gitea/source/services/webhook/discord_test.go +++ b/package/gitea/source/services/webhook/discord_test.go @@ -6,11 +6,11 @@ package webhook import ( "testing" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/json" - "code.gitea.io/gitea/modules/setting" - api "code.gitea.io/gitea/modules/structs" - webhook_module "code.gitea.io/gitea/modules/webhook" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/json" + "gitea.dev/modules/setting" + api "gitea.dev/modules/structs" + webhook_module "gitea.dev/modules/webhook" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/package/gitea/source/services/webhook/feishu.go b/package/gitea/source/services/webhook/feishu.go index ac581df8..18651ade 100644 --- a/package/gitea/source/services/webhook/feishu.go +++ b/package/gitea/source/services/webhook/feishu.go @@ -13,10 +13,10 @@ import ( "strings" "time" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/git" - api "code.gitea.io/gitea/modules/structs" - webhook_module "code.gitea.io/gitea/modules/webhook" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/git" + api "gitea.dev/modules/structs" + webhook_module "gitea.dev/modules/webhook" ) type ( diff --git a/package/gitea/source/services/webhook/feishu_test.go b/package/gitea/source/services/webhook/feishu_test.go index 7e200ea1..f8a5f7a9 100644 --- a/package/gitea/source/services/webhook/feishu_test.go +++ b/package/gitea/source/services/webhook/feishu_test.go @@ -6,10 +6,10 @@ package webhook import ( "testing" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/json" - api "code.gitea.io/gitea/modules/structs" - webhook_module "code.gitea.io/gitea/modules/webhook" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/json" + api "gitea.dev/modules/structs" + webhook_module "gitea.dev/modules/webhook" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/package/gitea/source/services/webhook/general.go b/package/gitea/source/services/webhook/general.go index 9572c926..327e36c1 100644 --- a/package/gitea/source/services/webhook/general.go +++ b/package/gitea/source/services/webhook/general.go @@ -9,13 +9,13 @@ import ( "net/url" "strings" - user_model "code.gitea.io/gitea/models/user" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/setting" - api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" - webhook_module "code.gitea.io/gitea/modules/webhook" + user_model "gitea.dev/models/user" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/base" + "gitea.dev/modules/setting" + api "gitea.dev/modules/structs" + "gitea.dev/modules/util" + webhook_module "gitea.dev/modules/webhook" ) type linkFormatter = func(string, string) string @@ -404,20 +404,17 @@ func ToHook(repoLink string, w *webhook_model.Webhook) (*api.Hook, error) { config["color"] = s.Color } - authorizationHeader, err := w.HeaderAuthorization() - if err != nil { - return nil, err - } - return &api.Hook{ - ID: w.ID, - Name: w.Name, - Type: w.Type, - URL: fmt.Sprintf("%s/settings/hooks/%d", repoLink, w.ID), - Active: w.IsActive, - Config: config, - Events: w.EventsArray(), - AuthorizationHeader: authorizationHeader, + ID: w.ID, + Name: w.Name, + Type: w.Type, + URL: fmt.Sprintf("%s/settings/hooks/%d", repoLink, w.ID), + Active: w.IsActive, + Config: config, + Events: w.EventsArray(), + // the stored authorization header is a secret and must never be returned by the API, + // consistent with the webhook secret which is also omitted from the response + AuthorizationHeader: "", Updated: w.UpdatedUnix.AsTime(), Created: w.CreatedUnix.AsTime(), BranchFilter: w.BranchFilter, diff --git a/package/gitea/source/services/webhook/general_test.go b/package/gitea/source/services/webhook/general_test.go index ec735d78..879f0f62 100644 --- a/package/gitea/source/services/webhook/general_test.go +++ b/package/gitea/source/services/webhook/general_test.go @@ -6,7 +6,7 @@ package webhook import ( "testing" - api "code.gitea.io/gitea/modules/structs" + api "gitea.dev/modules/structs" "github.com/stretchr/testify/assert" ) diff --git a/package/gitea/source/services/webhook/main_test.go b/package/gitea/source/services/webhook/main_test.go index 756b9db2..9bed4df1 100644 --- a/package/gitea/source/services/webhook/main_test.go +++ b/package/gitea/source/services/webhook/main_test.go @@ -6,19 +6,20 @@ package webhook import ( "testing" - "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/hostmatcher" - "code.gitea.io/gitea/modules/setting" + "gitea.dev/models/unittest" + "gitea.dev/modules/hostmatcher" + "gitea.dev/modules/setting" - _ "code.gitea.io/gitea/models" - _ "code.gitea.io/gitea/models/actions" + _ "gitea.dev/models" + _ "gitea.dev/models/actions" ) func TestMain(m *testing.M) { - // for tests, allow only loopback IPs - setting.Webhook.AllowedHostList = hostmatcher.MatchBuiltinLoopback unittest.MainTest(m, &unittest.TestOptions{ SetUp: func() error { + // for tests, allow only loopback IPs. This must run after the test config is loaded (which + // resets the shared Security.AllowedHostList) and before Init() builds the delivery client. + setting.Security.AllowedHostList = hostmatcher.MatchBuiltinLoopback setting.LoadQueueSettings() return Init() }, diff --git a/package/gitea/source/services/webhook/matrix.go b/package/gitea/source/services/webhook/matrix.go index fa01ecd0..e9dc17ae 100644 --- a/package/gitea/source/services/webhook/matrix.go +++ b/package/gitea/source/services/webhook/matrix.go @@ -14,15 +14,15 @@ import ( "regexp" "strings" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/json" - "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" - webhook_module "code.gitea.io/gitea/modules/webhook" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/base" + "gitea.dev/modules/git" + "gitea.dev/modules/json" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" + api "gitea.dev/modules/structs" + "gitea.dev/modules/util" + webhook_module "gitea.dev/modules/webhook" ) func init() { diff --git a/package/gitea/source/services/webhook/matrix_test.go b/package/gitea/source/services/webhook/matrix_test.go index 59b78f42..29b7affc 100644 --- a/package/gitea/source/services/webhook/matrix_test.go +++ b/package/gitea/source/services/webhook/matrix_test.go @@ -7,10 +7,10 @@ import ( "strings" "testing" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/json" - api "code.gitea.io/gitea/modules/structs" - webhook_module "code.gitea.io/gitea/modules/webhook" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/json" + api "gitea.dev/modules/structs" + webhook_module "gitea.dev/modules/webhook" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/package/gitea/source/services/webhook/msteams.go b/package/gitea/source/services/webhook/msteams.go index 34db9037..7024036d 100644 --- a/package/gitea/source/services/webhook/msteams.go +++ b/package/gitea/source/services/webhook/msteams.go @@ -11,11 +11,11 @@ import ( "strconv" "strings" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/git" - api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" - webhook_module "code.gitea.io/gitea/modules/webhook" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/git" + api "gitea.dev/modules/structs" + "gitea.dev/modules/util" + webhook_module "gitea.dev/modules/webhook" ) type ( diff --git a/package/gitea/source/services/webhook/msteams_test.go b/package/gitea/source/services/webhook/msteams_test.go index 0d98b94b..cf7f9fbb 100644 --- a/package/gitea/source/services/webhook/msteams_test.go +++ b/package/gitea/source/services/webhook/msteams_test.go @@ -6,10 +6,10 @@ package webhook import ( "testing" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/json" - api "code.gitea.io/gitea/modules/structs" - webhook_module "code.gitea.io/gitea/modules/webhook" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/json" + api "gitea.dev/modules/structs" + webhook_module "gitea.dev/modules/webhook" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/package/gitea/source/services/webhook/notifier.go b/package/gitea/source/services/webhook/notifier.go index 2b301d4d..2586d097 100644 --- a/package/gitea/source/services/webhook/notifier.go +++ b/package/gitea/source/services/webhook/notifier.go @@ -7,26 +7,25 @@ import ( "context" "errors" - actions_model "code.gitea.io/gitea/models/actions" - git_model "code.gitea.io/gitea/models/git" - issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/organization" - packages_model "code.gitea.io/gitea/models/packages" - "code.gitea.io/gitea/models/perm" - 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/httplib" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/setting" - api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" - webhook_module "code.gitea.io/gitea/modules/webhook" - "code.gitea.io/gitea/services/convert" - notify_service "code.gitea.io/gitea/services/notify" + actions_model "gitea.dev/models/actions" + git_model "gitea.dev/models/git" + issues_model "gitea.dev/models/issues" + "gitea.dev/models/organization" + packages_model "gitea.dev/models/packages" + "gitea.dev/models/perm" + access_model "gitea.dev/models/perm/access" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/httplib" + "gitea.dev/modules/log" + "gitea.dev/modules/repository" + "gitea.dev/modules/setting" + api "gitea.dev/modules/structs" + "gitea.dev/modules/util" + webhook_module "gitea.dev/modules/webhook" + "gitea.dev/services/convert" + notify_service "gitea.dev/services/notify" ) func init() { @@ -818,7 +817,7 @@ func (m *webhookNotifier) CreateRef(ctx context.Context, pusher *user_model.User } } -func (m *webhookNotifier) PullRequestSynchronized(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { +func (m *webhookNotifier) PullRequestSynchronized(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest, before, after string) { if err := pr.LoadIssue(ctx); err != nil { log.Error("LoadIssue: %v", err) return @@ -830,6 +829,8 @@ func (m *webhookNotifier) PullRequestSynchronized(ctx context.Context, doer *use if err := PrepareWebhooks(ctx, EventSource{Repository: pr.Issue.Repo}, webhook_module.HookEventPullRequestSync, &api.PullRequestPayload{ Action: api.HookIssueSynchronized, + Before: before, + After: after, Index: pr.Issue.Index, PullRequest: convert.ToAPIPullRequest(ctx, pr, doer), Repository: convert.ToRepo(ctx, pr.Issue.Repo, access_model.Permission{AccessMode: perm.AccessModeOwner}), @@ -1027,23 +1028,19 @@ func (*webhookNotifier) WorkflowRunStatusUpdate(ctx context.Context, repo *repo_ status := convert.ToWorkflowRunAction(run.Status) - gitRepo, err := gitrepo.OpenRepository(ctx, repo) + // Resolve the workflow definition from its source repo. + convertedWorkflow, err := convert.ResolveActionWorkflowForRun(ctx, repo, run) if err != nil { - log.Error("OpenRepository: %v", err) - return - } - defer gitRepo.Close() - - convertedWorkflow, err := convert.GetActionWorkflowByRef(ctx, gitRepo, repo, run.WorkflowID, git.RefName(run.Ref)) - if err != nil && errors.Is(err, util.ErrNotExist) { - convertedWorkflow, err = convert.GetActionWorkflow(ctx, gitRepo, repo, run.WorkflowID) - } - if err != nil { - log.Error("GetActionWorkflow: %v", err) + if errors.Is(err, util.ErrNotExist) { + log.Debug("WorkflowRunStatusUpdate: workflow %q for run %d not found: %v", run.WorkflowID, run.ID, err) + return + } + log.Error("ResolveActionWorkflowForRun: %v", err) return } - convertedRun, err := convert.ToActionWorkflowRun(ctx, repo, run) + run.Repo = repo + convertedRun, err := convert.ToActionWorkflowRun(ctx, run, nil, false) if err != nil { log.Error("ToActionWorkflowRun: %v", err) return diff --git a/package/gitea/source/services/webhook/packagist.go b/package/gitea/source/services/webhook/packagist.go index e6a00b02..f8c69292 100644 --- a/package/gitea/source/services/webhook/packagist.go +++ b/package/gitea/source/services/webhook/packagist.go @@ -8,11 +8,11 @@ import ( "fmt" "net/http" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/json" - "code.gitea.io/gitea/modules/log" - api "code.gitea.io/gitea/modules/structs" - webhook_module "code.gitea.io/gitea/modules/webhook" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/json" + "gitea.dev/modules/log" + api "gitea.dev/modules/structs" + webhook_module "gitea.dev/modules/webhook" ) type ( diff --git a/package/gitea/source/services/webhook/packagist_test.go b/package/gitea/source/services/webhook/packagist_test.go index 4e77f29e..28396d79 100644 --- a/package/gitea/source/services/webhook/packagist_test.go +++ b/package/gitea/source/services/webhook/packagist_test.go @@ -6,10 +6,10 @@ package webhook import ( "testing" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/json" - api "code.gitea.io/gitea/modules/structs" - webhook_module "code.gitea.io/gitea/modules/webhook" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/json" + api "gitea.dev/modules/structs" + webhook_module "gitea.dev/modules/webhook" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/package/gitea/source/services/webhook/payloader.go b/package/gitea/source/services/webhook/payloader.go index b607bf32..0abe5b89 100644 --- a/package/gitea/source/services/webhook/payloader.go +++ b/package/gitea/source/services/webhook/payloader.go @@ -8,10 +8,10 @@ import ( "fmt" "net/http" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/json" - api "code.gitea.io/gitea/modules/structs" - webhook_module "code.gitea.io/gitea/modules/webhook" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/json" + api "gitea.dev/modules/structs" + webhook_module "gitea.dev/modules/webhook" ) // payloadConvertor defines the interface to convert system payload to webhook payload diff --git a/package/gitea/source/services/webhook/slack.go b/package/gitea/source/services/webhook/slack.go index 94d41d21..23fd5a5b 100644 --- a/package/gitea/source/services/webhook/slack.go +++ b/package/gitea/source/services/webhook/slack.go @@ -7,16 +7,15 @@ import ( "context" "fmt" "net/http" - "regexp" "strings" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/json" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - api "code.gitea.io/gitea/modules/structs" - webhook_module "code.gitea.io/gitea/modules/webhook" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/git" + "gitea.dev/modules/json" + "gitea.dev/modules/log" + "gitea.dev/modules/setting" + api "gitea.dev/modules/structs" + webhook_module "gitea.dev/modules/webhook" ) // SlackMeta contains the slack metadata @@ -317,12 +316,10 @@ func init() { RegisterWebhookRequester(webhook_module.SLACK, newSlackRequest) } -var slackChannel = regexp.MustCompile(`^#?[a-z0-9_-]{1,80}$`) - -// IsValidSlackChannel validates a channel name conforms to what slack expects: -// https://api.slack.com/methods/conversations.rename#naming -// Conversation names can only contain lowercase letters, numbers, hyphens, and underscores, and must be 80 characters or less. -// Gitea accepts if it starts with a #. func IsValidSlackChannel(name string) bool { - return slackChannel.MatchString(name) + // Some documents: https://api.slack.com/methods/conversations.rename#naming + // 1. Internal channel name should "only contain lowercase letters, numbers, hyphens, and underscores, and must be 80 characters or less" + // 2. Slack would also "modify it to meet the above criteria" + // Since we know nothing about the details, don't do any validation here. + return name != "" } diff --git a/package/gitea/source/services/webhook/slack_test.go b/package/gitea/source/services/webhook/slack_test.go index 839ed6f7..f49e7203 100644 --- a/package/gitea/source/services/webhook/slack_test.go +++ b/package/gitea/source/services/webhook/slack_test.go @@ -6,10 +6,10 @@ package webhook import ( "testing" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/json" - api "code.gitea.io/gitea/modules/structs" - webhook_module "code.gitea.io/gitea/modules/webhook" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/json" + api "gitea.dev/modules/structs" + webhook_module "gitea.dev/modules/webhook" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -191,22 +191,3 @@ func TestSlackJSONPayload(t *testing.T) { assert.NoError(t, err) assert.Equal(t, "[:] 2 new commits pushed by user1", body.Text) } - -func TestIsValidSlackChannel(t *testing.T) { - tt := []struct { - channelName string - expected bool - }{ - {"gitea", true}, - {"#gitea", true}, - {" ", false}, - {"#", false}, - {" #", false}, - {"gitea ", false}, - {" gitea", false}, - } - - for _, v := range tt { - assert.Equal(t, v.expected, IsValidSlackChannel(v.channelName)) - } -} diff --git a/package/gitea/source/services/webhook/telegram.go b/package/gitea/source/services/webhook/telegram.go index 8e9a53a5..99a0b417 100644 --- a/package/gitea/source/services/webhook/telegram.go +++ b/package/gitea/source/services/webhook/telegram.go @@ -10,14 +10,14 @@ import ( "net/http" "strings" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/json" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/markup" - api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" - webhook_module "code.gitea.io/gitea/modules/webhook" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/git" + "gitea.dev/modules/json" + "gitea.dev/modules/log" + "gitea.dev/modules/markup" + api "gitea.dev/modules/structs" + "gitea.dev/modules/util" + webhook_module "gitea.dev/modules/webhook" ) type ( diff --git a/package/gitea/source/services/webhook/telegram_test.go b/package/gitea/source/services/webhook/telegram_test.go index 3fa8e278..7c820957 100644 --- a/package/gitea/source/services/webhook/telegram_test.go +++ b/package/gitea/source/services/webhook/telegram_test.go @@ -6,10 +6,10 @@ package webhook import ( "testing" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/json" - api "code.gitea.io/gitea/modules/structs" - webhook_module "code.gitea.io/gitea/modules/webhook" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/json" + api "gitea.dev/modules/structs" + webhook_module "gitea.dev/modules/webhook" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/package/gitea/source/services/webhook/webhook.go b/package/gitea/source/services/webhook/webhook.go index a35997dd..0a53f289 100644 --- a/package/gitea/source/services/webhook/webhook.go +++ b/package/gitea/source/services/webhook/webhook.go @@ -9,20 +9,20 @@ import ( "fmt" "net/http" - "code.gitea.io/gitea/models/db" - repo_model "code.gitea.io/gitea/models/repo" - user_model "code.gitea.io/gitea/models/user" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/glob" - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/optional" - "code.gitea.io/gitea/modules/queue" - "code.gitea.io/gitea/modules/setting" - api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" - webhook_module "code.gitea.io/gitea/modules/webhook" + "gitea.dev/models/db" + repo_model "gitea.dev/models/repo" + user_model "gitea.dev/models/user" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/git" + "gitea.dev/modules/glob" + "gitea.dev/modules/graceful" + "gitea.dev/modules/log" + "gitea.dev/modules/optional" + "gitea.dev/modules/queue" + "gitea.dev/modules/setting" + api "gitea.dev/modules/structs" + "gitea.dev/modules/util" + webhook_module "gitea.dev/modules/webhook" ) type Requester func(context.Context, *webhook_model.Webhook, *webhook_model.HookTask) (req *http.Request, body []byte, err error) @@ -129,6 +129,33 @@ func checkBranchFilter(branchFilter string, ref git.RefName) bool { return g.Match(ref.String()) } +// PrepareTestWebhook always creates and enqueues a hook task for manual testing. +// Unlike PrepareWebhook, it ignores event subscriptions and branch filters so the +// Test Push Event control can verify delivery even when those gates would suppress +// a real event. +func PrepareTestWebhook(ctx context.Context, w *webhook_model.Webhook, event webhook_module.HookEventType, p api.Payloader) error { + if setting.DisableWebhooks { + return nil + } + + payload, err := p.JSONPayload() + if err != nil { + return fmt.Errorf("JSONPayload for %s: %w", event, err) + } + + task, err := webhook_model.CreateHookTask(ctx, &webhook_model.HookTask{ + HookID: w.ID, + PayloadContent: string(payload), + EventType: event, + PayloadVersion: 2, + }) + if err != nil { + return fmt.Errorf("CreateHookTask for %s: %w", event, err) + } + + return enqueueHookTask(task.ID) +} + // PrepareWebhook creates a hook task and enqueues it for processing. // The payload is saved as-is. The adjustments depending on the webhook type happen // right before delivery, in the [Deliver] method. diff --git a/package/gitea/source/services/webhook/webhook_test.go b/package/gitea/source/services/webhook/webhook_test.go index f4432cc3..6ecf2433 100644 --- a/package/gitea/source/services/webhook/webhook_test.go +++ b/package/gitea/source/services/webhook/webhook_test.go @@ -6,22 +6,34 @@ package webhook import ( "testing" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/setting" - api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/test" - webhook_module "code.gitea.io/gitea/modules/webhook" - "code.gitea.io/gitea/services/convert" + "gitea.dev/models/db" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/git" + "gitea.dev/modules/setting" + api "gitea.dev/modules/structs" + "gitea.dev/modules/test" + webhook_module "gitea.dev/modules/webhook" + "gitea.dev/services/convert" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -func TestWebhook_GetSlackHook(t *testing.T) { +func TestWebhookService(t *testing.T) { + unittest.PrepareTestEnv(t) + t.Run("GetSlackHook", testWebhookGetSlackHook) + t.Run("PrepareWebhooks", testWebhookPrepare) + t.Run("PrepareBranchFilterMatch", testWebhookPrepareBranchFilterMatch) + t.Run("PrepareBranchFilterNoMatch", testWebhookPrepareBranchFilterNoMatch) + t.Run("WebhookUserMail", testWebhookUserMail) + t.Run("CheckBranchFilter", testWebhookCheckBranchFilter) + t.Run("PrepareTestWebhookIgnoresGates", testPrepareTestWebhookIgnoresGates) +} + +func testWebhookGetSlackHook(t *testing.T) { w := &webhook_model.Webhook{ Meta: `{"channel": "foo", "username": "username", "color": "blue"}`, } @@ -33,66 +45,69 @@ func TestWebhook_GetSlackHook(t *testing.T) { }, *slackHook) } -func TestPrepareWebhooks(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - +func testWebhookPrepare(t *testing.T) { repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - hookTasks := []*webhook_model.HookTask{ - {HookID: 1, EventType: webhook_module.HookEventPush}, - } - for _, hookTask := range hookTasks { - unittest.AssertNotExistsBean(t, hookTask) - } - assert.NoError(t, PrepareWebhooks(t.Context(), EventSource{Repository: repo}, webhook_module.HookEventPush, &api.PushPayload{Commits: []*api.PayloadCommit{{}}})) - for _, hookTask := range hookTasks { - unittest.AssertExistsAndLoadBean(t, hookTask) + hook := &webhook_model.Webhook{ + RepoID: repo.ID, + URL: "http://localhost/gitea-webhook-test-prepare_webhooks", + ContentType: webhook_model.ContentTypeJSON, + Events: `{"push_only":true}`, + IsActive: true, } + require.NoError(t, db.Insert(t.Context(), hook)) + + hookTask := &webhook_model.HookTask{HookID: hook.ID, EventType: webhook_module.HookEventPush} + unittest.AssertNotExistsBean(t, hookTask) + err := PrepareWebhooks(t.Context(), EventSource{Repository: repo}, webhook_module.HookEventPush, &api.PushPayload{Commits: []*api.PayloadCommit{{}}}) + require.NoError(t, err) + unittest.AssertExistsAndLoadBean(t, hookTask) } -func TestPrepareWebhooksBranchFilterMatch(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - +func testWebhookPrepareBranchFilterMatch(t *testing.T) { repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) - hookTasks := []*webhook_model.HookTask{ - {HookID: 4, EventType: webhook_module.HookEventPush}, - } - for _, hookTask := range hookTasks { - unittest.AssertNotExistsBean(t, hookTask) + hook := &webhook_model.Webhook{ + RepoID: repo.ID, + URL: "http://localhost/gitea-webhook-test-branch_filter_match", + ContentType: webhook_model.ContentTypeJSON, + Events: `{"push_only":true,"branch_filter":"{master,feature*}"}`, + IsActive: true, } + require.NoError(t, db.Insert(t.Context(), hook)) + + hookTask := &webhook_model.HookTask{HookID: hook.ID, EventType: webhook_module.HookEventPush} + unittest.AssertNotExistsBean(t, hookTask) // this test also ensures that * doesn't handle / in any special way (like shell would) - assert.NoError(t, PrepareWebhooks(t.Context(), EventSource{Repository: repo}, webhook_module.HookEventPush, &api.PushPayload{Ref: "refs/heads/feature/7791", Commits: []*api.PayloadCommit{{}}})) - for _, hookTask := range hookTasks { - unittest.AssertExistsAndLoadBean(t, hookTask) - } + err := PrepareWebhooks(t.Context(), EventSource{Repository: repo}, webhook_module.HookEventPush, &api.PushPayload{Ref: "refs/heads/feature/7791", Commits: []*api.PayloadCommit{{}}}) + require.NoError(t, err) + unittest.AssertExistsAndLoadBean(t, hookTask) } -func TestPrepareWebhooksBranchFilterNoMatch(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - +func testWebhookPrepareBranchFilterNoMatch(t *testing.T) { repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) - hookTasks := []*webhook_model.HookTask{ - {HookID: 4, EventType: webhook_module.HookEventPush}, + hook := &webhook_model.Webhook{ + RepoID: repo.ID, + URL: "http://localhost/gitea-webhook-test-branch_filter_no_match", + ContentType: webhook_model.ContentTypeJSON, + Events: `{"push_only":true,"branch_filter":"{master,feature*}"}`, + IsActive: true, } - for _, hookTask := range hookTasks { - unittest.AssertNotExistsBean(t, hookTask) - } - assert.NoError(t, PrepareWebhooks(t.Context(), EventSource{Repository: repo}, webhook_module.HookEventPush, &api.PushPayload{Ref: "refs/heads/fix_weird_bug"})) + require.NoError(t, db.Insert(t.Context(), hook)) - for _, hookTask := range hookTasks { - unittest.AssertNotExistsBean(t, hookTask) - } + hookTask := &webhook_model.HookTask{HookID: hook.ID, EventType: webhook_module.HookEventPush} + unittest.AssertNotExistsBean(t, hookTask) + err := PrepareWebhooks(t.Context(), EventSource{Repository: repo}, webhook_module.HookEventPush, &api.PushPayload{Ref: "refs/heads/fix_weird_bug"}) + require.NoError(t, err) + unittest.AssertNotExistsBean(t, hookTask) } -func TestWebhookUserMail(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) +func testWebhookUserMail(t *testing.T) { defer test.MockVariableValue(&setting.Service.NoReplyAddress, "no-reply.com")() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) assert.Equal(t, user.GetPlaceholderEmail(), convert.ToUser(t.Context(), user, nil).Email) assert.Equal(t, user.Email, convert.ToUser(t.Context(), user, user).Email) } -func TestCheckBranchFilter(t *testing.T) { +func testWebhookCheckBranchFilter(t *testing.T) { cases := []struct { filter string ref git.RefName @@ -118,3 +133,37 @@ func TestCheckBranchFilter(t *testing.T) { assert.Equal(t, v.match, checkBranchFilter(v.filter, v.ref), "filter: %q ref: %q", v.filter, v.ref) } } + +func testPrepareTestWebhookIgnoresGates(t *testing.T) { + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + hook := &webhook_model.Webhook{ + RepoID: repo.ID, + URL: "http://localhost/gitea-webhook-test-prepare_test_webhook", + ContentType: webhook_model.ContentTypeJSON, + IsActive: true, + HookEvent: &webhook_module.HookEvent{ + ChooseEvents: true, + BranchFilter: "dev", + HookEvents: webhook_module.HookEvents{ + webhook_module.HookEventWorkflowRun: true, + }, + }, + } + require.NoError(t, hook.UpdateEvent()) + require.NoError(t, db.Insert(t.Context(), hook)) + + payload := &api.PushPayload{ + Ref: "refs/heads/master", + Commits: []*api.PayloadCommit{{}}, + } + hookTask := &webhook_model.HookTask{HookID: hook.ID, EventType: webhook_module.HookEventPush} + + // Real deliveries stay gated: no push event + branch filter mismatch => nothing queued. + unittest.AssertNotExistsBean(t, hookTask) + require.NoError(t, PrepareWebhook(t.Context(), hook, webhook_module.HookEventPush, payload)) + unittest.AssertNotExistsBean(t, hookTask) + + // Manual test delivery always queues so the endpoint can be verified. + require.NoError(t, PrepareTestWebhook(t.Context(), hook, webhook_module.HookEventPush, payload)) + unittest.AssertExistsAndLoadBean(t, hookTask) +} diff --git a/package/gitea/source/services/webhook/wechatwork.go b/package/gitea/source/services/webhook/wechatwork.go index cac6a700..938be3b4 100644 --- a/package/gitea/source/services/webhook/wechatwork.go +++ b/package/gitea/source/services/webhook/wechatwork.go @@ -9,10 +9,10 @@ import ( "net/http" "strings" - webhook_model "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/git" - api "code.gitea.io/gitea/modules/structs" - webhook_module "code.gitea.io/gitea/modules/webhook" + webhook_model "gitea.dev/models/webhook" + "gitea.dev/modules/git" + api "gitea.dev/modules/structs" + webhook_module "gitea.dev/modules/webhook" ) type ( diff --git a/package/gitea/source/services/webtheme/webtheme.go b/package/gitea/source/services/webtheme/webtheme.go index e82008c6..3ce42936 100644 --- a/package/gitea/source/services/webtheme/webtheme.go +++ b/package/gitea/source/services/webtheme/webtheme.go @@ -14,11 +14,11 @@ import ( "sync/atomic" "time" - "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/public" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" + "gitea.dev/modules/container" + "gitea.dev/modules/log" + "gitea.dev/modules/public" + "gitea.dev/modules/setting" + "gitea.dev/modules/util" ) type themeCollectionStruct struct { @@ -45,7 +45,7 @@ type ThemeMetaInfo struct { } func (info *ThemeMetaInfo) PublicAssetURI() string { - return public.AssetURI("css/theme-" + url.PathEscape(info.InternalName) + ".css") + return public.AssetURI("web_src/css/themes/theme-" + url.PathEscape(info.InternalName) + ".css") } func (info *ThemeMetaInfo) GetDescription() string { diff --git a/package/gitea/source/services/wiki/wiki.go b/package/gitea/source/services/wiki/wiki.go index 5bc62d45..d1006abf 100644 --- a/package/gitea/source/services/wiki/wiki.go +++ b/package/gitea/source/services/wiki/wiki.go @@ -7,22 +7,22 @@ package wiki import ( "context" "fmt" - "os" - "code.gitea.io/gitea/models/db" - repo_model "code.gitea.io/gitea/models/repo" - system_model "code.gitea.io/gitea/models/system" - "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/git/gitcmd" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/globallock" - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/log" - repo_module "code.gitea.io/gitea/modules/repository" - asymkey_service "code.gitea.io/gitea/services/asymkey" - repo_service "code.gitea.io/gitea/services/repository" + "gitea.dev/models/db" + repo_model "gitea.dev/models/repo" + system_model "gitea.dev/models/system" + "gitea.dev/models/unit" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" + "gitea.dev/modules/gitrepo" + "gitea.dev/modules/globallock" + "gitea.dev/modules/graceful" + "gitea.dev/modules/log" + repo_module "gitea.dev/modules/repository" + "gitea.dev/modules/util" + asymkey_service "gitea.dev/services/asymkey" + repo_service "gitea.dev/services/repository" ) func getWikiWorkingLockKey(repoID int64) string { @@ -59,7 +59,7 @@ func prepareGitPath(gitRepo *git.Repository, defaultWikiBranch string, wikiPath // Look for both files filesInIndex, err := gitRepo.LsTree(defaultWikiBranch, unescaped, gitPath) if err != nil { - if gitcmd.IsStdErrorNotValidObjectName(err) { + if gitcmd.IsStderr(err, gitcmd.StderrNotValidObjectName) { return false, gitPath, nil // branch doesn't exist } log.Error("Wiki LsTree failed, err: %v", err) @@ -304,7 +304,7 @@ func DeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model return err } } else { - return os.ErrNotExist + return util.ErrNotExist } // FIXME: The wiki doesn't have lfs support at present - if this changes need to check attributes here diff --git a/package/gitea/source/services/wiki/wiki_path.go b/package/gitea/source/services/wiki/wiki_path.go index a4dd3c70..58cb22b4 100644 --- a/package/gitea/source/services/wiki/wiki_path.go +++ b/package/gitea/source/services/wiki/wiki_path.go @@ -8,11 +8,11 @@ import ( "path" "strings" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/git" - api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/services/convert" + repo_model "gitea.dev/models/repo" + "gitea.dev/modules/git" + api "gitea.dev/modules/structs" + "gitea.dev/modules/util" + "gitea.dev/services/convert" ) // To define the wiki related concepts: diff --git a/package/gitea/source/services/wiki/wiki_test.go b/package/gitea/source/services/wiki/wiki_test.go index e571e093..9b1160d7 100644 --- a/package/gitea/source/services/wiki/wiki_test.go +++ b/package/gitea/source/services/wiki/wiki_test.go @@ -8,14 +8,14 @@ import ( "strings" "testing" - 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" - repo_service "code.gitea.io/gitea/services/repository" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" + "gitea.dev/modules/git" + "gitea.dev/modules/gitrepo" + repo_service "gitea.dev/services/repository" - _ "code.gitea.io/gitea/models/actions" + _ "gitea.dev/models/actions" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/package/gitea/source/snap/part-gitea-build.sh b/package/gitea/source/snap/part-gitea-build.sh index 7ad6383c..00516248 100755 --- a/package/gitea/source/snap/part-gitea-build.sh +++ b/package/gitea/source/snap/part-gitea-build.sh @@ -1,7 +1,7 @@ #!/bin/sh set -e -if [ ! -f go.mod -o ! -d snap ]; then +if [ ! -f go.mod ] || [ ! -d snap ]; then echo "This script should be run from the root of the gitea repository" exit 1 fi @@ -13,7 +13,9 @@ fi command -v pnpm >/dev/null 2>&1 || npm install -g pnpm -TAGS="bindata sqlite sqlite_unlock_notify pam cert" make build +# build tags for 1.26: "bindata sqlite sqlite_unlock_notify pam cert" +# for 1.27: sqlite is not needed, "cert" seems doing nothing +TAGS="bindata pam" make build install -D gitea "${SNAPCRAFT_PART_INSTALL}/gitea" cp -r options "${SNAPCRAFT_PART_INSTALL}/" diff --git a/package/gitea/source/snap/part-gitea-pull.sh b/package/gitea/source/snap/part-gitea-pull.sh index 0d117bb4..83fde11a 100755 --- a/package/gitea/source/snap/part-gitea-pull.sh +++ b/package/gitea/source/snap/part-gitea-pull.sh @@ -1,7 +1,7 @@ #!/bin/sh set -e -if [ ! -f go.mod -o ! -d snap ]; then +if [ ! -f go.mod ] || [ ! -d snap ]; then echo "This script should be run from the root of the gitea repository" exit 1 fi diff --git a/package/gitea/source/snap/snapcraft.yaml b/package/gitea/source/snap/snapcraft.yaml index ce9e02dd..2fea108d 100644 --- a/package/gitea/source/snap/snapcraft.yaml +++ b/package/gitea/source/snap/snapcraft.yaml @@ -8,13 +8,19 @@ description: | icon: public/assets/img/logo.png confinement: strict -base: core22 +base: core24 adopt-info: gitea -architectures: - - build-on: armhf - - build-on: amd64 - - build-on: arm64 +platforms: + armhf: + build-on: [armhf] + build-for: [armhf] + amd64: + build-on: [amd64] + build-for: [amd64] + arm64: + build-on: [arm64] + build-for: [arm64] environment: GITEA_CUSTOM: "$SNAP_COMMON" diff --git a/package/gitea/source/stylelint.config.js b/package/gitea/source/stylelint.config.ts similarity index 91% rename from package/gitea/source/stylelint.config.js rename to package/gitea/source/stylelint.config.ts index 0aee1a5d..d3baa1b4 100644 --- a/package/gitea/source/stylelint.config.js +++ b/package/gitea/source/stylelint.config.ts @@ -1,6 +1,5 @@ -// @ts-check -// TODO: Move to .ts after https://github.com/stylelint/stylelint/issues/8893 is fixed import {fileURLToPath} from 'node:url'; +import type {Config} from 'stylelint'; const cssVarFiles = [ fileURLToPath(new URL('web_src/css/base.css', import.meta.url)), @@ -8,7 +7,6 @@ const cssVarFiles = [ fileURLToPath(new URL('web_src/css/themes/theme-gitea-dark.css', import.meta.url)), ]; -/** @type {import('stylelint').Config} */ export default { extends: 'stylelint-config-recommended', reportUnscopedDisables: true, @@ -25,18 +23,6 @@ export default { '/web_src/fomantic', ], overrides: [ - { - files: ['**/chroma/*', '**/codemirror/*', '**/console.css', 'font_i18n.css'], - rules: { - 'scale-unlimited/declaration-strict-value': null, - }, - }, - { - files: ['**/chroma/*', '**/codemirror/*'], - rules: { - 'block-no-empty': null, - }, - }, { files: ['**/*.vue'], customSyntax: 'postcss-html', @@ -139,7 +125,7 @@ export default { 'no-unknown-custom-media': null, // disabled until stylelint supports multi-file linting 'no-unknown-custom-properties': null, // disabled until stylelint supports multi-file linting 'plugin/declaration-block-no-ignored-properties': true, - 'scale-unlimited/declaration-strict-value': [['/color$/', 'font-weight'], {ignoreValues: '/^(inherit|transparent|unset|initial|currentcolor|none)$/', ignoreFunctions: true, disableFix: true, expandShorthand: true}], + 'scale-unlimited/declaration-strict-value': [['/color$/', 'fill', 'stroke', 'font-weight'], {ignoreValues: '/^(inherit|transparent|unset|initial|currentcolor|none)$/', ignoreFunctions: true, disableFix: true, expandShorthand: true}], 'selector-attribute-quotes': 'always', 'selector-no-vendor-prefix': true, 'selector-pseudo-element-colon-notation': 'double', @@ -148,4 +134,4 @@ export default { 'shorthand-property-no-redundant-values': true, 'value-no-vendor-prefix': [true, {ignoreValues: ['box', 'inline-box']}], }, -}; +} satisfies Config; diff --git a/package/gitea/source/tailwind.config.ts b/package/gitea/source/tailwind.config.ts index 199433d0..f5971217 100644 --- a/package/gitea/source/tailwind.config.ts +++ b/package/gitea/source/tailwind.config.ts @@ -90,7 +90,7 @@ export default { '8xl': '96px', '9xl': '128px', ...Object.fromEntries(Array.from({length: 100}, (_, i) => { - return [`${i}`, `${i === 0 ? '0' : `${i}px`}`]; + return [String(i), i === 0 ? '0' : `${i}px`]; })), }, extend: { diff --git a/package/gitea/source/templates/admin/actions.tmpl b/package/gitea/source/templates/admin/actions.tmpl index 597863d7..6be9bdf7 100644 --- a/package/gitea/source/templates/admin/actions.tmpl +++ b/package/gitea/source/templates/admin/actions.tmpl @@ -1,4 +1,4 @@ -{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin actions")}} +{{template "admin/layout_head" (dict "pageClass" "admin actions")}}
{{if eq .PageType "runners"}} {{template "shared/actions/runner_list" .}} @@ -6,5 +6,8 @@ {{if eq .PageType "variables"}} {{template "shared/variables/variable_list" .}} {{end}} + {{if eq .PageType "scoped-workflows"}} + {{template "shared/actions/scoped_workflows" .}} + {{end}}
{{template "admin/layout_footer" .}} diff --git a/package/gitea/source/templates/admin/applications/list.tmpl b/package/gitea/source/templates/admin/applications/list.tmpl index cbb66b16..efc4e6e0 100644 --- a/package/gitea/source/templates/admin/applications/list.tmpl +++ b/package/gitea/source/templates/admin/applications/list.tmpl @@ -1,4 +1,4 @@ -{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin config")}} +{{template "admin/layout_head" (dict "pageClass" "admin config")}}

{{ctx.Locale.Tr "settings.applications"}} diff --git a/package/gitea/source/templates/admin/applications/oauth2_edit.tmpl b/package/gitea/source/templates/admin/applications/oauth2_edit.tmpl index 668bfe06..34ae0bf4 100644 --- a/package/gitea/source/templates/admin/applications/oauth2_edit.tmpl +++ b/package/gitea/source/templates/admin/applications/oauth2_edit.tmpl @@ -1,4 +1,4 @@ -{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin config")}} +{{template "admin/layout_head" (dict "pageClass" "admin config")}}
{{template "user/settings/applications_oauth2_edit_form" .}} diff --git a/package/gitea/source/templates/admin/auth/edit.tmpl b/package/gitea/source/templates/admin/auth/edit.tmpl index 56f9e1b9..40f19667 100644 --- a/package/gitea/source/templates/admin/auth/edit.tmpl +++ b/package/gitea/source/templates/admin/auth/edit.tmpl @@ -1,4 +1,4 @@ -{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin edit authentication")}} +{{template "admin/layout_head" (dict "pageClass" "admin edit authentication")}}

{{ctx.Locale.Tr "admin.auths.edit"}} @@ -330,6 +330,11 @@

+
+ + +

{{ctx.Locale.Tr "admin.auths.open_id_connect_external_id_claim_helper"}}

+
diff --git a/package/gitea/source/templates/admin/auth/list.tmpl b/package/gitea/source/templates/admin/auth/list.tmpl index 7296e955..17795880 100644 --- a/package/gitea/source/templates/admin/auth/list.tmpl +++ b/package/gitea/source/templates/admin/auth/list.tmpl @@ -1,4 +1,4 @@ -{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin authentication")}} +{{template "admin/layout_head" (dict "pageClass" "admin authentication")}}

{{ctx.Locale.Tr "admin.auths.auth_manage_panel"}} ({{ctx.Locale.Tr "admin.total" .Total}}) diff --git a/package/gitea/source/templates/admin/auth/new.tmpl b/package/gitea/source/templates/admin/auth/new.tmpl index 256f648c..6bc273c8 100644 --- a/package/gitea/source/templates/admin/auth/new.tmpl +++ b/package/gitea/source/templates/admin/auth/new.tmpl @@ -1,4 +1,4 @@ -{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin new authentication")}} +{{template "admin/layout_head" (dict "pageClass" "admin new authentication")}}

{{ctx.Locale.Tr "admin.auths.new"}} diff --git a/package/gitea/source/templates/admin/auth/source/oauth.tmpl b/package/gitea/source/templates/admin/auth/source/oauth.tmpl index 69590635..94664a38 100644 --- a/package/gitea/source/templates/admin/auth/source/oauth.tmpl +++ b/package/gitea/source/templates/admin/auth/source/oauth.tmpl @@ -88,6 +88,11 @@

+
+ + +

{{ctx.Locale.Tr "admin.auths.open_id_connect_external_id_claim_helper"}}

+
diff --git a/package/gitea/source/templates/admin/badge/edit.tmpl b/package/gitea/source/templates/admin/badge/edit.tmpl index f2cdc4ad..582ba60c 100644 --- a/package/gitea/source/templates/admin/badge/edit.tmpl +++ b/package/gitea/source/templates/admin/badge/edit.tmpl @@ -1,4 +1,4 @@ -{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin edit badge")}} +{{template "admin/layout_head" (dict "pageClass" "admin edit badge")}}

{{ctx.Locale.Tr "admin.badges.edit_badge"}} diff --git a/package/gitea/source/templates/admin/badge/list.tmpl b/package/gitea/source/templates/admin/badge/list.tmpl index 3020b7b2..691bc448 100644 --- a/package/gitea/source/templates/admin/badge/list.tmpl +++ b/package/gitea/source/templates/admin/badge/list.tmpl @@ -1,4 +1,4 @@ -{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin badge")}} +{{template "admin/layout_head" (dict "pageClass" "admin badge")}}

{{ctx.Locale.Tr "admin.badges.badges_manage_panel"}} ({{ctx.Locale.Tr "admin.total" .Total}}) diff --git a/package/gitea/source/templates/admin/badge/new.tmpl b/package/gitea/source/templates/admin/badge/new.tmpl index 5b67bed3..0c64c396 100644 --- a/package/gitea/source/templates/admin/badge/new.tmpl +++ b/package/gitea/source/templates/admin/badge/new.tmpl @@ -1,4 +1,4 @@ -{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin new badge")}} +{{template "admin/layout_head" (dict "pageClass" "admin new badge")}}

{{ctx.Locale.Tr "admin.badges.new_badge"}} diff --git a/package/gitea/source/templates/admin/badge/users.tmpl b/package/gitea/source/templates/admin/badge/users.tmpl index 97d33201..051de1b4 100644 --- a/package/gitea/source/templates/admin/badge/users.tmpl +++ b/package/gitea/source/templates/admin/badge/users.tmpl @@ -1,11 +1,11 @@ -{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin badge")}} +{{template "admin/layout_head" (dict "pageClass" "admin badge")}}

{{.Title}}

-
- {{if .Users}}
-
+
{{range .Users}} -
-
+
+ -
-
+
+
{{template "shared/user/name" .}}
-
+
{{ctx.Locale.Tr "admin.badges.remove_user"}} diff --git a/package/gitea/source/templates/admin/badge/view.tmpl b/package/gitea/source/templates/admin/badge/view.tmpl index efd31f4c..26d3d8db 100644 --- a/package/gitea/source/templates/admin/badge/view.tmpl +++ b/package/gitea/source/templates/admin/badge/view.tmpl @@ -1,4 +1,4 @@ -{{template "admin/layout_head" (dict "ctxData" .)}} +{{template "admin/layout_head" (dict)}}
@@ -10,18 +10,18 @@

-
-
+
+
{{if .Badge.ImageURL}} -
+
{{.Badge.Description}}
{{end}} -
-
+
+
{{.Badge.Slug}}
-
+
{{.Badge.Description}}
diff --git a/package/gitea/source/templates/admin/config.tmpl b/package/gitea/source/templates/admin/config.tmpl index b68f2c1a..ae37950f 100644 --- a/package/gitea/source/templates/admin/config.tmpl +++ b/package/gitea/source/templates/admin/config.tmpl @@ -1,4 +1,4 @@ -{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin config")}} +{{template "admin/layout_head" (dict "pageClass" "admin config")}}

{{ctx.Locale.Tr "admin.config.server_config"}} @@ -244,8 +244,6 @@
{{.CacheInterval}} {{ctx.Locale.Tr "tool.raw_seconds"}}
{{end}} {{if .CacheConn}} -
{{ctx.Locale.Tr "admin.config.cache_conn"}}
-
{{.CacheConn}}
{{ctx.Locale.Tr "admin.config.cache_item_ttl"}}
{{.CacheItemTTL}}
{{end}} @@ -266,8 +264,6 @@
{{ctx.Locale.Tr "admin.config.session_provider"}}
{{.SessionConfig.Provider}}
-
{{ctx.Locale.Tr "admin.config.provider_config"}}
-
{{if .SessionConfig.ProviderConfig}}{{.SessionConfig.ProviderConfig}}{{else}}-{{end}}
{{ctx.Locale.Tr "admin.config.cookie_name"}}
{{.SessionConfig.CookieName}}
{{ctx.Locale.Tr "admin.config.gc_interval_time"}}
diff --git a/package/gitea/source/templates/admin/config_settings/config_settings.tmpl b/package/gitea/source/templates/admin/config_settings/config_settings.tmpl index 6d1db4f8..b12c2dc3 100644 --- a/package/gitea/source/templates/admin/config_settings/config_settings.tmpl +++ b/package/gitea/source/templates/admin/config_settings/config_settings.tmpl @@ -1,4 +1,4 @@ -{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin config" "dataGlobalInit" "initAdminConfigSettings")}} +{{template "admin/layout_head" (dict "pageClass" "admin config" "dataGlobalInit" "initAdminConfigSettings")}} {{template "admin/config_settings/avatars" .}} {{template "admin/config_settings/repository" .}} diff --git a/package/gitea/source/templates/admin/cron.tmpl b/package/gitea/source/templates/admin/cron.tmpl index 8e44614d..457cdd52 100644 --- a/package/gitea/source/templates/admin/cron.tmpl +++ b/package/gitea/source/templates/admin/cron.tmpl @@ -1,4 +1,4 @@ -{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin monitor")}} +{{template "admin/layout_head" (dict "pageClass" "admin monitor")}}

{{ctx.Locale.Tr "admin.monitor.cron"}} diff --git a/package/gitea/source/templates/admin/dashboard.tmpl b/package/gitea/source/templates/admin/dashboard.tmpl index 834c5667..059ddd3c 100644 --- a/package/gitea/source/templates/admin/dashboard.tmpl +++ b/package/gitea/source/templates/admin/dashboard.tmpl @@ -1,4 +1,4 @@ -{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin dashboard")}} +{{template "admin/layout_head" (dict "pageClass" "admin dashboard")}}
{{if .NeedUpdate}}
@@ -76,10 +76,7 @@

{{/* TODO: make these stats work in multi-server deployments, likely needs per-server stats in DB */}}
-
-
- {{template "admin/system_status" .}} -
+ {{template "admin/system_status" .}}
{{template "admin/layout_footer" .}} diff --git a/package/gitea/source/templates/admin/emails/list.tmpl b/package/gitea/source/templates/admin/emails/list.tmpl index d597a275..135b4da3 100644 --- a/package/gitea/source/templates/admin/emails/list.tmpl +++ b/package/gitea/source/templates/admin/emails/list.tmpl @@ -1,4 +1,4 @@ -{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin user")}} +{{template "admin/layout_head" (dict "pageClass" "admin user")}}

{{ctx.Locale.Tr "admin.emails.email_manage_panel"}} ({{ctx.Locale.Tr "admin.total" .Total}}) diff --git a/package/gitea/source/templates/admin/hook_new.tmpl b/package/gitea/source/templates/admin/hook_new.tmpl index 37dcc49d..d8df2054 100644 --- a/package/gitea/source/templates/admin/hook_new.tmpl +++ b/package/gitea/source/templates/admin/hook_new.tmpl @@ -1,4 +1,4 @@ -{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin settings new webhook")}} +{{template "admin/layout_head" (dict "pageClass" "admin settings new webhook")}}
{{$CustomHeaderTitle := ctx.Locale.Tr "admin.defaulthooks.update_webhook"}} {{if .PageIsAdminDefaultHooksNew}} @@ -8,6 +8,6 @@ {{else if .Webhook.IsSystemWebhook}} {{$CustomHeaderTitle = ctx.Locale.Tr "admin.systemhooks.update_webhook"}} {{end}} - {{template "webhook/new" (dict "ctxData" . "CustomHeaderTitle" $CustomHeaderTitle)}} + {{template "webhook/new" (dict "CustomHeaderTitle" $CustomHeaderTitle)}}
{{template "admin/layout_footer" .}} diff --git a/package/gitea/source/templates/admin/hooks.tmpl b/package/gitea/source/templates/admin/hooks.tmpl index d5fdef68..c36a9b10 100644 --- a/package/gitea/source/templates/admin/hooks.tmpl +++ b/package/gitea/source/templates/admin/hooks.tmpl @@ -1,4 +1,4 @@ -{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin hooks")}} +{{template "admin/layout_head" (dict "pageClass" "admin hooks")}}
{{template "repo/settings/webhook/base_list" .SystemWebhooks}} {{template "repo/settings/webhook/base_list" .DefaultWebhooks}} diff --git a/package/gitea/source/templates/admin/layout_head.tmpl b/package/gitea/source/templates/admin/layout_head.tmpl index 397516da..ce989c40 100644 --- a/package/gitea/source/templates/admin/layout_head.tmpl +++ b/package/gitea/source/templates/admin/layout_head.tmpl @@ -1,9 +1,9 @@ -{{template "base/head" .ctxData}} -
+{{template "base/head" ctx.RootData}} +
- {{template "admin/navbar" .ctxData}} + {{template "admin/navbar" ctx.RootData}}
- {{template "base/alert" .ctxData}} + {{template "base/alert" ctx.RootData}} {{/* block: admin-setting-content */}} {{if false}}{{/* to make html structure "likely" complete to prevent IDE warnings */}} diff --git a/package/gitea/source/templates/admin/navbar.tmpl b/package/gitea/source/templates/admin/navbar.tmpl index ce3048ed..a54fa530 100644 --- a/package/gitea/source/templates/admin/navbar.tmpl +++ b/package/gitea/source/templates/admin/navbar.tmpl @@ -2,7 +2,7 @@