From f2fbb897f3bf68a1af1410a2b4ce7a289ef73c1a Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 20 Feb 2025 20:17:56 -0800 Subject: [PATCH 1/8] Deleting repository should unlink all related packages (#33653) Fix #33634 --------- Co-authored-by: Giteabot Co-authored-by: wxiaoguang --- services/repository/delete.go | 6 ++++++ services/repository/repository.go | 7 +------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/services/repository/delete.go b/services/repository/delete.go index fb3fffdca71a0..3b953d3ec7f37 100644 --- a/services/repository/delete.go +++ b/services/repository/delete.go @@ -14,6 +14,7 @@ import ( 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" @@ -267,6 +268,11 @@ func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, repoID return err } + // unlink packages linked to this repository + if err = packages_model.UnlinkRepositoryFromAllPackages(ctx, repoID); err != nil { + return err + } + if err = committer.Commit(); err != nil { return err } diff --git a/services/repository/repository.go b/services/repository/repository.go index 59b4491132da9..fcc617979ef29 100644 --- a/services/repository/repository.go +++ b/services/repository/repository.go @@ -11,7 +11,6 @@ import ( "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" repo_model "code.gitea.io/gitea/models/repo" system_model "code.gitea.io/gitea/models/system" "code.gitea.io/gitea/models/unit" @@ -63,11 +62,7 @@ func DeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_mod notify_service.DeleteRepository(ctx, doer, repo) } - if err := DeleteRepositoryDirectly(ctx, doer, repo.ID); err != nil { - return err - } - - return packages_model.UnlinkRepositoryFromAllPackages(ctx, repo.ID) + return DeleteRepositoryDirectly(ctx, doer, repo.ID) } // PushCreateRepo creates a repository when a new repository is pushed to an appropriate namespace From 4adb7cad8b75b0d6154c91de1a64582ada2e300e Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Fri, 21 Feb 2025 16:04:30 +0800 Subject: [PATCH 2/8] Improve swagger generation (#33664) Remove most "sed" tricks --------- Co-authored-by: silverwind --- .editorconfig | 1 + .github/workflows/files-changed.yml | 1 + Makefile | 17 ++++++++--------- routers/api/v1/api.go | 2 -- templates/swagger/v1_input.json | 6 ++++++ templates/swagger/v1_json.tmpl | 2 +- 6 files changed, 17 insertions(+), 12 deletions(-) create mode 100644 templates/swagger/v1_input.json diff --git a/.editorconfig b/.editorconfig index c0946ac9975cd..e23e4cd649a42 100644 --- a/.editorconfig +++ b/.editorconfig @@ -17,6 +17,7 @@ insert_final_newline = false [templates/swagger/v1_json.tmpl] indent_style = space +insert_final_newline = false [templates/user/auth/oidc_wellknown.tmpl] indent_style = space diff --git a/.github/workflows/files-changed.yml b/.github/workflows/files-changed.yml index 7c1fb024421bc..b3ee93e6f8331 100644 --- a/.github/workflows/files-changed.yml +++ b/.github/workflows/files-changed.yml @@ -85,6 +85,7 @@ jobs: swagger: - "templates/swagger/v1_json.tmpl" + - "templates/swagger/v1_input.json" - "Makefile" - "package.json" - "package-lock.json" diff --git a/Makefile b/Makefile index 89a6f1261fff8..e38fb801c318a 100644 --- a/Makefile +++ b/Makefile @@ -165,10 +165,8 @@ ifdef DEPS_PLAYWRIGHT endif SWAGGER_SPEC := templates/swagger/v1_json.tmpl -SWAGGER_SPEC_S_TMPL := s|"basePath": *"/api/v1"|"basePath": "{{AppSubUrl \| JSEscape}}/api/v1"|g -SWAGGER_SPEC_S_JSON := s|"basePath": *"{{AppSubUrl \| JSEscape}}/api/v1"|"basePath": "/api/v1"|g +SWAGGER_SPEC_INPUT := templates/swagger/v1_input.json SWAGGER_EXCLUDE := code.gitea.io/sdk -SWAGGER_NEWLINE_COMMAND := -e '$$a\' TEST_MYSQL_HOST ?= mysql:3306 TEST_MYSQL_DBNAME ?= testgitea @@ -271,10 +269,8 @@ endif .PHONY: generate-swagger generate-swagger: $(SWAGGER_SPEC) ## generate the swagger spec from code comments -$(SWAGGER_SPEC): $(GO_SOURCES_NO_BINDATA) - $(GO) run $(SWAGGER_PACKAGE) generate spec -x "$(SWAGGER_EXCLUDE)" -o './$(SWAGGER_SPEC)' - $(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)' - $(SED_INPLACE) $(SWAGGER_NEWLINE_COMMAND) './$(SWAGGER_SPEC)' +$(SWAGGER_SPEC): $(GO_SOURCES_NO_BINDATA) $(SWAGGER_SPEC_INPUT) + $(GO) run $(SWAGGER_PACKAGE) generate spec --exclude "$(SWAGGER_EXCLUDE)" --input "$(SWAGGER_SPEC_INPUT)" --output './$(SWAGGER_SPEC)' .PHONY: swagger-check swagger-check: generate-swagger @@ -287,9 +283,11 @@ swagger-check: generate-swagger .PHONY: swagger-validate swagger-validate: ## check if the swagger spec is valid - $(SED_INPLACE) '$(SWAGGER_SPEC_S_JSON)' './$(SWAGGER_SPEC)' + @# swagger "validate" requires that the "basePath" must start with a slash, but we are using Golang template "{{...}}" + @$(SED_INPLACE) -E -e 's|"basePath":( *)"(.*)"|"basePath":\1"/\2"|g' './$(SWAGGER_SPEC)' # add a prefix slash to basePath + @# FIXME: there are some warnings $(GO) run $(SWAGGER_PACKAGE) validate './$(SWAGGER_SPEC)' - $(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)' + @$(SED_INPLACE) -E -e 's|"basePath":( *)"/(.*)"|"basePath":\1"\2"|g' './$(SWAGGER_SPEC)' # remove the prefix slash from basePath .PHONY: checks checks: checks-frontend checks-backend ## run various consistency checks @@ -380,6 +378,7 @@ lint-go-gopls: ## lint go files with gopls .PHONY: lint-editorconfig lint-editorconfig: + @echo "Running editorconfig check..." @$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) $(EDITORCONFIG_FILES) .PHONY: lint-actions diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 907a2f08fe280..bc76b5285e5a2 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -7,8 +7,6 @@ // This documentation describes the Gitea API. // // Schemes: https, http -// BasePath: /api/v1 -// Version: {{AppVer | JSEscape}} // License: MIT http://opensource.org/licenses/MIT // // Consumes: diff --git a/templates/swagger/v1_input.json b/templates/swagger/v1_input.json new file mode 100644 index 0000000000000..1979febebb9db --- /dev/null +++ b/templates/swagger/v1_input.json @@ -0,0 +1,6 @@ +{ + "info": { + "version": "{{AppVer | JSEscape}}" + }, + "basePath": "{{AppSubUrl | JSEscape}}/api/v1" +} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index d173f3161b553..fd3e2a70f1337 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -27580,4 +27580,4 @@ "TOTPHeader": [] } ] -} +} \ No newline at end of file From a61014ea4741aff420c7ba8adb2b2c1845a85488 Mon Sep 17 00:00:00 2001 From: Diana <80010947+dianaStr7@users.noreply.github.com> Date: Fri, 21 Feb 2025 18:38:49 +0100 Subject: [PATCH 3/8] Fix for Maven Package Naming Convention Handling (#33678) Make legacy package names could be listed and add tests --------- Co-authored-by: diana.strebkova@t-systems.com Co-authored-by: wxiaoguang --- routers/api/packages/maven/api.go | 9 +++------ routers/api/packages/maven/maven.go | 17 ++++++++--------- tests/integration/api_packages_maven_test.go | 14 ++++++++++++++ 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/routers/api/packages/maven/api.go b/routers/api/packages/maven/api.go index 167fe42b56d51..ec6b9cfb0e05b 100644 --- a/routers/api/packages/maven/api.go +++ b/routers/api/packages/maven/api.go @@ -8,7 +8,6 @@ import ( "strings" packages_model "code.gitea.io/gitea/models/packages" - maven_module "code.gitea.io/gitea/modules/packages/maven" ) // MetadataResponse https://maven.apache.org/ref/3.2.5/maven-repository-metadata/repository-metadata.html @@ -22,7 +21,7 @@ type MetadataResponse struct { } // pds is expected to be sorted ascending by CreatedUnix -func createMetadataResponse(pds []*packages_model.PackageDescriptor) *MetadataResponse { +func createMetadataResponse(pds []*packages_model.PackageDescriptor, groupID, artifactID string) *MetadataResponse { var release *packages_model.PackageDescriptor versions := make([]string, 0, len(pds)) @@ -35,11 +34,9 @@ func createMetadataResponse(pds []*packages_model.PackageDescriptor) *MetadataRe latest := pds[len(pds)-1] - metadata := latest.Metadata.(*maven_module.Metadata) - resp := &MetadataResponse{ - GroupID: metadata.GroupID, - ArtifactID: metadata.ArtifactID, + GroupID: groupID, + ArtifactID: artifactID, Latest: latest.Version.Version, Version: versions, } diff --git a/routers/api/packages/maven/maven.go b/routers/api/packages/maven/maven.go index 4d04d4d1e9f32..4f9ced25b4bba 100644 --- a/routers/api/packages/maven/maven.go +++ b/routers/api/packages/maven/maven.go @@ -84,20 +84,19 @@ func handlePackageFile(ctx *context.Context, serveContent bool) { } func serveMavenMetadata(ctx *context.Context, params parameters) { - // /com/foo/project/maven-metadata.xml[.md5/.sha1/.sha256/.sha512] - - pvs, err := packages_model.GetVersionsByPackageName(ctx, ctx.Package.Owner.ID, packages_model.TypeMaven, params.toInternalPackageName()) - if errors.Is(err, util.ErrNotExist) { - pvs, err = packages_model.GetVersionsByPackageName(ctx, ctx.Package.Owner.ID, packages_model.TypeMaven, params.toInternalPackageNameLegacy()) - } + // path pattern: /com/foo/project/maven-metadata.xml[.md5/.sha1/.sha256/.sha512] + // in case there are legacy package names ("GroupID-ArtifactID") we need to check both, new packages always use ":" as separator("GroupID:ArtifactID") + pvsLegacy, err := packages_model.GetVersionsByPackageName(ctx, ctx.Package.Owner.ID, packages_model.TypeMaven, params.toInternalPackageNameLegacy()) if err != nil { apiError(ctx, http.StatusInternalServerError, err) return } - if len(pvs) == 0 { - apiError(ctx, http.StatusNotFound, packages_model.ErrPackageNotExist) + pvs, err := packages_model.GetVersionsByPackageName(ctx, ctx.Package.Owner.ID, packages_model.TypeMaven, params.toInternalPackageName()) + if err != nil { + apiError(ctx, http.StatusInternalServerError, err) return } + pvs = append(pvsLegacy, pvs...) pds, err := packages_model.GetPackageDescriptors(ctx, pvs) if err != nil { @@ -110,7 +109,7 @@ func serveMavenMetadata(ctx *context.Context, params parameters) { return pds[i].Version.CreatedUnix < pds[j].Version.CreatedUnix }) - xmlMetadata, err := xml.Marshal(createMetadataResponse(pds)) + xmlMetadata, err := xml.Marshal(createMetadataResponse(pds, params.GroupID, params.ArtifactID)) if err != nil { apiError(ctx, http.StatusInternalServerError, err) return diff --git a/tests/integration/api_packages_maven_test.go b/tests/integration/api_packages_maven_test.go index 486a5af93e17b..408c8805c2412 100644 --- a/tests/integration/api_packages_maven_test.go +++ b/tests/integration/api_packages_maven_test.go @@ -80,6 +80,7 @@ func TestPackageMaven(t *testing.T) { t.Run("UploadLegacy", func(t *testing.T) { defer tests.PrintCurrentTest(t)() + // try to upload a package with legacy package name (will be saved as "GroupID-ArtifactID") legacyRootLink := "/api/packages/user2/maven/com/gitea/legacy-project" req := NewRequestWithBody(t, "PUT", legacyRootLink+"/1.0.2/any-file-name?use_legacy_package_name=1", strings.NewReader("test-content")).AddBasicAuth(user.Name) MakeRequest(t, req, http.StatusCreated) @@ -97,6 +98,13 @@ func TestPackageMaven(t *testing.T) { req = NewRequest(t, "GET", "/user2/-/packages/maven/com.gitea%3Alegacy-project/1.0.2") MakeRequest(t, req, http.StatusNotFound) + // legacy package names should also be able to be listed + req = NewRequest(t, "GET", legacyRootLink+"/maven-metadata.xml").AddBasicAuth(user.Name) + resp := MakeRequest(t, req, http.StatusOK) + respBody := resp.Body.String() + assert.Contains(t, respBody, "1.0.2") + + // then upload a package with correct package name (will be saved as "GroupID:ArtifactID") req = NewRequestWithBody(t, "PUT", legacyRootLink+"/1.0.3/any-file-name", strings.NewReader("test-content")).AddBasicAuth(user.Name) MakeRequest(t, req, http.StatusCreated) _, err = packages.GetPackageByName(db.DefaultContext, user.ID, packages.TypeMaven, "com.gitea-legacy-project") @@ -114,6 +122,12 @@ func TestPackageMaven(t *testing.T) { req = NewRequest(t, "GET", "/user2/-/packages/maven/com.gitea%3Alegacy-project/1.0.2") MakeRequest(t, req, http.StatusOK) + // now 2 packages should be listed + req = NewRequest(t, "GET", legacyRootLink+"/maven-metadata.xml").AddBasicAuth(user.Name) + resp = MakeRequest(t, req, http.StatusOK) + respBody = resp.Body.String() + assert.Contains(t, respBody, "1.0.2") + assert.Contains(t, respBody, "1.0.3") require.NoError(t, packages.DeletePackageByID(db.DefaultContext, p.ID)) }) From ead716d204d6e30ae702a8c0192078488a3856f5 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Sat, 22 Feb 2025 01:46:05 +0800 Subject: [PATCH 4/8] Improve Open-with URL encoding (#33666) Fix #33665 --- web_src/js/features/repo-common.test.ts | 7 +++++++ web_src/js/features/repo-common.ts | 10 +++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 web_src/js/features/repo-common.test.ts diff --git a/web_src/js/features/repo-common.test.ts b/web_src/js/features/repo-common.test.ts new file mode 100644 index 0000000000000..009dfc86b1016 --- /dev/null +++ b/web_src/js/features/repo-common.test.ts @@ -0,0 +1,7 @@ +import {substituteRepoOpenWithUrl} from './repo-common.ts'; + +test('substituteRepoOpenWithUrl', () => { + // For example: "x-github-client://openRepo/https://github.com/go-gitea/gitea" + expect(substituteRepoOpenWithUrl('proto://a/{url}', 'https://gitea')).toEqual('proto://a/https://gitea'); + expect(substituteRepoOpenWithUrl('proto://a?link={url}', 'https://gitea')).toEqual('proto://a?link=https%3A%2F%2Fgitea'); +}); diff --git a/web_src/js/features/repo-common.ts b/web_src/js/features/repo-common.ts index 2f62d51597c44..444cb163bf140 100644 --- a/web_src/js/features/repo-common.ts +++ b/web_src/js/features/repo-common.ts @@ -42,6 +42,14 @@ export function initRepoActivityTopAuthorsChart() { } } +export function substituteRepoOpenWithUrl(tmpl: string, url: string): string { + const pos = tmpl.indexOf('{url}'); + if (pos === -1) return tmpl; + const posQuestionMark = tmpl.indexOf('?'); + const needEncode = posQuestionMark >= 0 && posQuestionMark < pos; + return tmpl.replace('{url}', needEncode ? encodeURIComponent(url) : url); +} + function initCloneSchemeUrlSelection(parent: Element) { const elCloneUrlInput = parent.querySelector('.repo-clone-url'); @@ -70,7 +78,7 @@ function initCloneSchemeUrlSelection(parent: Element) { } } for (const el of parent.querySelectorAll('.js-clone-url-editor')) { - el.href = el.getAttribute('data-href-template').replace('{url}', encodeURIComponent(link)); + el.href = substituteRepoOpenWithUrl(el.getAttribute('data-href-template'), link); } }; From 9e75c545598fe8a195f9b69f8e1e8258d50dc8d0 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sun, 23 Feb 2025 00:34:45 +0000 Subject: [PATCH 5/8] [skip ci] Updated translations via Crowdin --- options/locale/locale_ja-JP.ini | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index bc29d530b497a..ed2a16cf90ff4 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -385,6 +385,12 @@ show_only_public=公開のみ表示 issues.in_your_repos=あなたのリポジトリ +guide_title=アクティビティはありません +guide_desc=現在フォロー中のリポジトリやユーザーがないため、表示するコンテンツがありません。 以下のリンクから、興味のあるリポジトリやユーザーを探すことができます。 +explore_repos=リポジトリを探す +explore_users=ユーザーを探す +empty_org=組織はまだありません。 +empty_repo=リポジトリはまだありません。 [explore] repos=リポジトリ @@ -1348,6 +1354,8 @@ editor.new_branch_name_desc=新しいブランチ名… editor.cancel=キャンセル editor.filename_cannot_be_empty=ファイル名は空にできません。 editor.filename_is_invalid=`ファイル名が不正です: "%s"` +editor.commit_email=コミット メールアドレス +editor.invalid_commit_email=コミットに使うメールアドレスが正しくありません。 editor.branch_does_not_exist=このリポジトリにブランチ "%s" は存在しません。 editor.branch_already_exists=ブランチ "%s" は、このリポジトリに既に存在します。 editor.directory_is_a_file=ディレクトリ名 "%s" はすでにリポジトリ内のファイルで使用されています。 @@ -1693,7 +1701,9 @@ issues.time_estimate_invalid=見積時間のフォーマットが不正です issues.start_tracking_history=が作業を開始 %s issues.tracker_auto_close=タイマーは、このイシューがクローズされると自動的に終了します issues.tracking_already_started=`別のイシューで既にタイムトラッキングを開始しています!` +issues.stop_tracking=タイマー終了 issues.stop_tracking_history=が %[1]s の作業を終了 %[2]s +issues.cancel_tracking=破棄 issues.cancel_tracking_history=`がタイムトラッキングを中止 %s` issues.del_time=このタイムログを削除 issues.add_time_history=が作業時間 %[1]s を追加 %[2]s @@ -2329,6 +2339,8 @@ settings.event_fork=フォーク settings.event_fork_desc=リポジトリがフォークされたとき。 settings.event_wiki=Wiki settings.event_wiki_desc=Wikiページが作成・名前変更・編集・削除されたとき。 +settings.event_statuses=ステータス +settings.event_statuses_desc=APIによってコミットのステータスが更新されたとき。 settings.event_release=リリース settings.event_release_desc=リポジトリでリリースが作成・更新・削除されたとき。 settings.event_push=プッシュ @@ -2876,6 +2888,14 @@ view_as_role=表示: %s view_as_public_hint=READMEを公開ユーザーとして見ています。 view_as_member_hint=READMEをこの組織のメンバーとして見ています。 +worktime=作業時間 +worktime.date_range_start=期間 (自) +worktime.date_range_end=期間 (至) +worktime.query=集計 +worktime.time=時間 +worktime.by_repositories=リポジトリ別 +worktime.by_milestones=マイルストーン別 +worktime.by_members=メンバー別 [admin] maintenance=メンテナンス From f991807f7ed6940f1ac2a306a00b522b51a1273d Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Sun, 23 Feb 2025 13:12:08 +0800 Subject: [PATCH 6/8] Try to fix ACME path when renew (#33668) Try to fix #32191 --- cmd/web_acme.go | 16 ++++++++++------ modules/setting/server.go | 25 ++++++++++++++++--------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/cmd/web_acme.go b/cmd/web_acme.go index 5daf0f55f243f..bca4ae021217b 100644 --- a/cmd/web_acme.go +++ b/cmd/web_acme.go @@ -54,10 +54,6 @@ func runACME(listenAddr string, m http.Handler) error { altTLSALPNPort = p } - // FIXME: this path is not right, it uses "AppWorkPath" incorrectly, and writes the data into "AppWorkPath/https" - // Ideally it should migrate to AppDataPath write to "AppDataPath/https" - certmagic.Default.Storage = &certmagic.FileStorage{Path: setting.AcmeLiveDirectory} - magic := certmagic.NewDefault() // Try to use private CA root if provided, otherwise defaults to system's trust var certPool *x509.CertPool if setting.AcmeCARoot != "" { @@ -67,7 +63,13 @@ func runACME(listenAddr string, m http.Handler) error { log.Warn("Failed to parse CA Root certificate, using default CA trust: %v", err) } } - myACME := certmagic.NewACMEIssuer(magic, certmagic.ACMEIssuer{ + // FIXME: this path is not right, it uses "AppWorkPath" incorrectly, and writes the data into "AppWorkPath/https" + // Ideally it should migrate to AppDataPath write to "AppDataPath/https" + // And one more thing, no idea why we should set the global default variables here + // But it seems that the current ACME code needs these global variables to make renew work. + // Otherwise, "renew" will use incorrect storage path + certmagic.Default.Storage = &certmagic.FileStorage{Path: setting.AcmeLiveDirectory} + certmagic.DefaultACME = certmagic.ACMEIssuer{ CA: setting.AcmeURL, TrustedRoots: certPool, Email: setting.AcmeEmail, @@ -77,8 +79,10 @@ func runACME(listenAddr string, m http.Handler) error { ListenHost: setting.HTTPAddr, AltTLSALPNPort: altTLSALPNPort, AltHTTPPort: altHTTPPort, - }) + } + magic := certmagic.NewDefault() + myACME := certmagic.NewACMEIssuer(magic, certmagic.DefaultACME) magic.Issuers = []certmagic.Issuer{myACME} // this obtains certificates or renews them if necessary diff --git a/modules/setting/server.go b/modules/setting/server.go index d7a71578d4ab6..e15b790906738 100644 --- a/modules/setting/server.go +++ b/modules/setting/server.go @@ -169,20 +169,24 @@ func loadServerFrom(rootCfg ConfigProvider) { HTTPAddr = sec.Key("HTTP_ADDR").MustString("0.0.0.0") HTTPPort = sec.Key("HTTP_PORT").MustString("3000") + // DEPRECATED should not be removed because users maybe upgrade from lower version to the latest version + // if these are removed, the warning will not be shown + if sec.HasKey("ENABLE_ACME") { + EnableAcme = sec.Key("ENABLE_ACME").MustBool(false) + } else { + deprecatedSetting(rootCfg, "server", "ENABLE_LETSENCRYPT", "server", "ENABLE_ACME", "v1.19.0") + EnableAcme = sec.Key("ENABLE_LETSENCRYPT").MustBool(false) + } + Protocol = HTTP protocolCfg := sec.Key("PROTOCOL").String() + if protocolCfg != "https" && EnableAcme { + log.Fatal("ACME could only be used with HTTPS protocol") + } + switch protocolCfg { case "https": Protocol = HTTPS - - // DEPRECATED should not be removed because users maybe upgrade from lower version to the latest version - // if these are removed, the warning will not be shown - if sec.HasKey("ENABLE_ACME") { - EnableAcme = sec.Key("ENABLE_ACME").MustBool(false) - } else { - deprecatedSetting(rootCfg, "server", "ENABLE_LETSENCRYPT", "server", "ENABLE_ACME", "v1.19.0") - EnableAcme = sec.Key("ENABLE_LETSENCRYPT").MustBool(false) - } if EnableAcme { AcmeURL = sec.Key("ACME_URL").MustString("") AcmeCARoot = sec.Key("ACME_CA_ROOT").MustString("") @@ -210,6 +214,9 @@ func loadServerFrom(rootCfg ConfigProvider) { deprecatedSetting(rootCfg, "server", "LETSENCRYPT_EMAIL", "server", "ACME_EMAIL", "v1.19.0") AcmeEmail = sec.Key("LETSENCRYPT_EMAIL").MustString("") } + if AcmeEmail == "" { + log.Fatal("ACME Email is not set (ACME_EMAIL).") + } } else { CertFile = sec.Key("CERT_FILE").String() KeyFile = sec.Key("KEY_FILE").String() From 8ae46d9684b93392885b3dd31a3185f53e046300 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Sun, 23 Feb 2025 20:33:43 +0800 Subject: [PATCH 7/8] Fix some user name usages (#33689) 1. GetUserOrgsList should "order by" lower_name 2. GetIssuePostersWithSearch should search in-case-sensitive-ly 3. LoginName should not be used as username By the way, remove unnecessary "onGiteaRun" --- models/organization/org_list.go | 1 + models/repo/user_repo.go | 5 +- models/repo/user_repo_test.go | 17 ++ routers/api/v1/repo/collaborators.go | 6 +- .../integration/api_repo_collaborator_test.go | 188 ++++++++++-------- 5 files changed, 125 insertions(+), 92 deletions(-) diff --git a/models/organization/org_list.go b/models/organization/org_list.go index 4c4168af1f826..78ac0e704a1fb 100644 --- a/models/organization/org_list.go +++ b/models/organization/org_list.go @@ -124,6 +124,7 @@ func GetUserOrgsList(ctx context.Context, user *user_model.User) ([]*MinimalOrg, if err := db.GetEngine(ctx).Select(columnsStr). Table("user"). Where(builder.In("`user`.`id`", queryUserOrgIDs(user.ID, true))). + OrderBy("`user`.lower_name ASC"). Find(&orgs); err != nil { return nil, err } diff --git a/models/repo/user_repo.go b/models/repo/user_repo.go index a9b1360df1410..232087d86594e 100644 --- a/models/repo/user_repo.go +++ b/models/repo/user_repo.go @@ -5,6 +5,7 @@ package repo import ( "context" + "strings" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" @@ -149,9 +150,9 @@ func GetRepoAssignees(ctx context.Context, repo *Repository) (_ []*user_model.Us // If isShowFullName is set to true, also include full name prefix search func GetIssuePostersWithSearch(ctx context.Context, repo *Repository, isPull bool, search string, isShowFullName bool) ([]*user_model.User, error) { users := make([]*user_model.User, 0, 30) - var prefixCond builder.Cond = builder.Like{"name", search + "%"} + var prefixCond builder.Cond = builder.Like{"lower_name", strings.ToLower(search) + "%"} if isShowFullName { - prefixCond = prefixCond.Or(builder.Like{"full_name", "%" + search + "%"}) + prefixCond = prefixCond.Or(db.BuildCaseInsensitiveLike("full_name", "%"+search+"%")) } cond := builder.In("`user`.id", diff --git a/models/repo/user_repo_test.go b/models/repo/user_repo_test.go index 44ebe5f214c6e..50c970344cb3f 100644 --- a/models/repo/user_repo_test.go +++ b/models/repo/user_repo_test.go @@ -12,6 +12,7 @@ import ( user_model "code.gitea.io/gitea/models/user" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestRepoAssignees(t *testing.T) { @@ -38,3 +39,19 @@ func TestRepoAssignees(t *testing.T) { assert.NotContains(t, []int64{users[0].ID, users[1].ID, users[2].ID}, 15) } } + +func TestGetIssuePostersWithSearch(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) + + users, err := repo_model.GetIssuePostersWithSearch(db.DefaultContext, repo2, false, "USER", false /* full name */) + require.NoError(t, err) + require.Len(t, users, 1) + assert.Equal(t, "user2", users[0].Name) + + users, err = repo_model.GetIssuePostersWithSearch(db.DefaultContext, repo2, false, "TW%O", true /* full name */) + require.NoError(t, err) + require.Len(t, users, 1) + assert.Equal(t, "user2", users[0].Name) +} diff --git a/routers/api/v1/repo/collaborators.go b/routers/api/v1/repo/collaborators.go index c397d7972b56d..a54225f0fd76d 100644 --- a/routers/api/v1/repo/collaborators.go +++ b/routers/api/v1/repo/collaborators.go @@ -7,6 +7,7 @@ package repo import ( "errors" "net/http" + "strings" "code.gitea.io/gitea/models/perm" access_model "code.gitea.io/gitea/models/perm/access" @@ -274,12 +275,13 @@ func GetRepoPermissions(ctx *context.APIContext) { // "403": // "$ref": "#/responses/forbidden" - if !ctx.Doer.IsAdmin && ctx.Doer.LoginName != ctx.PathParam("collaborator") && !ctx.IsUserRepoAdmin() { + collaboratorUsername := ctx.PathParam("collaborator") + if !ctx.Doer.IsAdmin && ctx.Doer.LowerName != strings.ToLower(collaboratorUsername) && !ctx.IsUserRepoAdmin() { ctx.APIError(http.StatusForbidden, "Only admins can query all permissions, repo admins can query all repo permissions, collaborators can query only their own") return } - collaborator, err := user_model.GetUserByName(ctx, ctx.PathParam("collaborator")) + collaborator, err := user_model.GetUserByName(ctx, collaboratorUsername) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.APIError(http.StatusNotFound, err) diff --git a/tests/integration/api_repo_collaborator_test.go b/tests/integration/api_repo_collaborator_test.go index 463db1dfb1305..11e2924e8423e 100644 --- a/tests/integration/api_repo_collaborator_test.go +++ b/tests/integration/api_repo_collaborator_test.go @@ -5,7 +5,6 @@ package integration import ( "net/http" - "net/url" "testing" auth_model "code.gitea.io/gitea/models/auth" @@ -14,132 +13,145 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/tests" "github.com/stretchr/testify/assert" ) func TestAPIRepoCollaboratorPermission(t *testing.T) { - onGiteaRun(t, func(t *testing.T, u *url.URL) { - repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) - repo2Owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo2.OwnerID}) + defer tests.PrepareTestEnv(t)() + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) + repo2Owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo2.OwnerID}) - user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) - user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) - user10 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 10}) - user11 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 11}) - user34 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 34}) + user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) + user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) + user10 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 10}) + user11 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 11}) + user34 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 34}) - testCtx := NewAPITestContext(t, repo2Owner.Name, repo2.Name, auth_model.AccessTokenScopeWriteRepository) + testCtx := NewAPITestContext(t, repo2Owner.Name, repo2.Name, auth_model.AccessTokenScopeWriteRepository) - t.Run("RepoOwnerShouldBeOwner", func(t *testing.T) { - req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, repo2Owner.Name). - AddTokenAuth(testCtx.Token) - resp := MakeRequest(t, req, http.StatusOK) + t.Run("RepoOwnerShouldBeOwner", func(t *testing.T) { + req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, repo2Owner.Name). + AddTokenAuth(testCtx.Token) + resp := MakeRequest(t, req, http.StatusOK) - var repoPermission api.RepoCollaboratorPermission - DecodeJSON(t, resp, &repoPermission) + var repoPermission api.RepoCollaboratorPermission + DecodeJSON(t, resp, &repoPermission) - assert.Equal(t, "owner", repoPermission.Permission) - }) + assert.Equal(t, "owner", repoPermission.Permission) + }) - t.Run("CollaboratorWithReadAccess", func(t *testing.T) { - t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user4.Name, perm.AccessModeRead)) + t.Run("CollaboratorWithReadAccess", func(t *testing.T) { + t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user4.Name, perm.AccessModeRead)) - req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user4.Name). - AddTokenAuth(testCtx.Token) - resp := MakeRequest(t, req, http.StatusOK) + req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user4.Name). + AddTokenAuth(testCtx.Token) + resp := MakeRequest(t, req, http.StatusOK) - var repoPermission api.RepoCollaboratorPermission - DecodeJSON(t, resp, &repoPermission) + var repoPermission api.RepoCollaboratorPermission + DecodeJSON(t, resp, &repoPermission) - assert.Equal(t, "read", repoPermission.Permission) - }) + assert.Equal(t, "read", repoPermission.Permission) + }) - t.Run("CollaboratorWithWriteAccess", func(t *testing.T) { - t.Run("AddUserAsCollaboratorWithWriteAccess", doAPIAddCollaborator(testCtx, user4.Name, perm.AccessModeWrite)) + t.Run("CollaboratorWithWriteAccess", func(t *testing.T) { + t.Run("AddUserAsCollaboratorWithWriteAccess", doAPIAddCollaborator(testCtx, user4.Name, perm.AccessModeWrite)) - req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user4.Name). - AddTokenAuth(testCtx.Token) - resp := MakeRequest(t, req, http.StatusOK) + req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user4.Name). + AddTokenAuth(testCtx.Token) + resp := MakeRequest(t, req, http.StatusOK) - var repoPermission api.RepoCollaboratorPermission - DecodeJSON(t, resp, &repoPermission) + var repoPermission api.RepoCollaboratorPermission + DecodeJSON(t, resp, &repoPermission) - assert.Equal(t, "write", repoPermission.Permission) - }) + assert.Equal(t, "write", repoPermission.Permission) + }) - t.Run("CollaboratorWithAdminAccess", func(t *testing.T) { - t.Run("AddUserAsCollaboratorWithAdminAccess", doAPIAddCollaborator(testCtx, user4.Name, perm.AccessModeAdmin)) + t.Run("CollaboratorWithAdminAccess", func(t *testing.T) { + t.Run("AddUserAsCollaboratorWithAdminAccess", doAPIAddCollaborator(testCtx, user4.Name, perm.AccessModeAdmin)) - req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user4.Name). - AddTokenAuth(testCtx.Token) - resp := MakeRequest(t, req, http.StatusOK) + req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user4.Name). + AddTokenAuth(testCtx.Token) + resp := MakeRequest(t, req, http.StatusOK) - var repoPermission api.RepoCollaboratorPermission - DecodeJSON(t, resp, &repoPermission) + var repoPermission api.RepoCollaboratorPermission + DecodeJSON(t, resp, &repoPermission) - assert.Equal(t, "admin", repoPermission.Permission) - }) + assert.Equal(t, "admin", repoPermission.Permission) + }) - t.Run("CollaboratorNotFound", func(t *testing.T) { - req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, "non-existent-user"). - AddTokenAuth(testCtx.Token) - MakeRequest(t, req, http.StatusNotFound) - }) + t.Run("CollaboratorNotFound", func(t *testing.T) { + req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, "non-existent-user"). + AddTokenAuth(testCtx.Token) + MakeRequest(t, req, http.StatusNotFound) + }) - t.Run("CollaboratorBlocked", func(t *testing.T) { - ctx := NewAPITestContext(t, repo2Owner.Name, repo2.Name, auth_model.AccessTokenScopeWriteRepository) - ctx.ExpectedCode = http.StatusForbidden - doAPIAddCollaborator(ctx, user34.Name, perm.AccessModeAdmin)(t) - }) + t.Run("CollaboratorBlocked", func(t *testing.T) { + ctx := NewAPITestContext(t, repo2Owner.Name, repo2.Name, auth_model.AccessTokenScopeWriteRepository) + ctx.ExpectedCode = http.StatusForbidden + doAPIAddCollaborator(ctx, user34.Name, perm.AccessModeAdmin)(t) + }) + + t.Run("CollaboratorCanQueryItsPermissions", func(t *testing.T) { + t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user5.Name, perm.AccessModeRead)) + + _session := loginUser(t, user5.Name) + _testCtx := NewAPITestContext(t, user5.Name, repo2.Name, auth_model.AccessTokenScopeReadRepository) + + req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user5.Name). + AddTokenAuth(_testCtx.Token) + resp := _session.MakeRequest(t, req, http.StatusOK) - t.Run("CollaboratorCanQueryItsPermissions", func(t *testing.T) { - t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user5.Name, perm.AccessModeRead)) + var repoPermission api.RepoCollaboratorPermission + DecodeJSON(t, resp, &repoPermission) - _session := loginUser(t, user5.Name) - _testCtx := NewAPITestContext(t, user5.Name, repo2.Name, auth_model.AccessTokenScopeReadRepository) + assert.Equal(t, "read", repoPermission.Permission) - req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user5.Name). - AddTokenAuth(_testCtx.Token) - resp := _session.MakeRequest(t, req, http.StatusOK) + t.Run("CollaboratorCanReadOwnPermission", func(t *testing.T) { + session := loginUser(t, user5.Name) + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository) - var repoPermission api.RepoCollaboratorPermission - DecodeJSON(t, resp, &repoPermission) + req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user5.Name).AddTokenAuth(token) + resp = MakeRequest(t, req, http.StatusOK) - assert.Equal(t, "read", repoPermission.Permission) + repoCollPerm := api.RepoCollaboratorPermission{} + DecodeJSON(t, resp, &repoCollPerm) + + assert.Equal(t, "read", repoCollPerm.Permission) }) + }) - t.Run("CollaboratorCanQueryItsPermissions", func(t *testing.T) { - t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user5.Name, perm.AccessModeRead)) + t.Run("CollaboratorCanQueryItsPermissions", func(t *testing.T) { + t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user5.Name, perm.AccessModeRead)) - _session := loginUser(t, user5.Name) - _testCtx := NewAPITestContext(t, user5.Name, repo2.Name, auth_model.AccessTokenScopeReadRepository) + _session := loginUser(t, user5.Name) + _testCtx := NewAPITestContext(t, user5.Name, repo2.Name, auth_model.AccessTokenScopeReadRepository) - req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user5.Name). - AddTokenAuth(_testCtx.Token) - resp := _session.MakeRequest(t, req, http.StatusOK) + req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user5.Name). + AddTokenAuth(_testCtx.Token) + resp := _session.MakeRequest(t, req, http.StatusOK) - var repoPermission api.RepoCollaboratorPermission - DecodeJSON(t, resp, &repoPermission) + var repoPermission api.RepoCollaboratorPermission + DecodeJSON(t, resp, &repoPermission) - assert.Equal(t, "read", repoPermission.Permission) - }) + assert.Equal(t, "read", repoPermission.Permission) + }) - t.Run("RepoAdminCanQueryACollaboratorsPermissions", func(t *testing.T) { - t.Run("AddUserAsCollaboratorWithAdminAccess", doAPIAddCollaborator(testCtx, user10.Name, perm.AccessModeAdmin)) - t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user11.Name, perm.AccessModeRead)) + t.Run("RepoAdminCanQueryACollaboratorsPermissions", func(t *testing.T) { + t.Run("AddUserAsCollaboratorWithAdminAccess", doAPIAddCollaborator(testCtx, user10.Name, perm.AccessModeAdmin)) + t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user11.Name, perm.AccessModeRead)) - _session := loginUser(t, user10.Name) - _testCtx := NewAPITestContext(t, user10.Name, repo2.Name, auth_model.AccessTokenScopeReadRepository) + _session := loginUser(t, user10.Name) + _testCtx := NewAPITestContext(t, user10.Name, repo2.Name, auth_model.AccessTokenScopeReadRepository) - req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user11.Name). - AddTokenAuth(_testCtx.Token) - resp := _session.MakeRequest(t, req, http.StatusOK) + req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user11.Name). + AddTokenAuth(_testCtx.Token) + resp := _session.MakeRequest(t, req, http.StatusOK) - var repoPermission api.RepoCollaboratorPermission - DecodeJSON(t, resp, &repoPermission) + var repoPermission api.RepoCollaboratorPermission + DecodeJSON(t, resp, &repoPermission) - assert.Equal(t, "read", repoPermission.Permission) - }) + assert.Equal(t, "read", repoPermission.Permission) }) } From 56a0a9c750b4cd48ca44a22ff0c860b9d035c950 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 24 Feb 2025 10:11:29 +0800 Subject: [PATCH 8/8] Fix git empty check and HEAD request (#33690) --- routers/web/repo/githttp.go | 2 +- services/context/api.go | 5 ++++ tests/integration/empty_repo_test.go | 8 +++++ tests/integration/git_smart_http_test.go | 37 ++++++++++++++---------- 4 files changed, 36 insertions(+), 16 deletions(-) diff --git a/routers/web/repo/githttp.go b/routers/web/repo/githttp.go index e27040edc6512..5b7b0188dc13b 100644 --- a/routers/web/repo/githttp.go +++ b/routers/web/repo/githttp.go @@ -78,7 +78,7 @@ func httpBase(ctx *context.Context) *serviceHandler { strings.HasSuffix(ctx.Req.URL.Path, "git-upload-archive") { isPull = true } else { - isPull = ctx.Req.Method == "GET" + isPull = ctx.Req.Method == "HEAD" || ctx.Req.Method == "GET" } var accessMode perm.AccessMode diff --git a/services/context/api.go b/services/context/api.go index 230c3456d1996..c163de036c719 100644 --- a/services/context/api.go +++ b/services/context/api.go @@ -291,6 +291,11 @@ func RepoRefForAPI(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { ctx := GetAPIContext(req) + if ctx.Repo.Repository.IsEmpty { + ctx.APIErrorNotFound("repository is empty") + return + } + if ctx.Repo.GitRepo == nil { ctx.APIErrorInternal(fmt.Errorf("no open git repo")) return diff --git a/tests/integration/empty_repo_test.go b/tests/integration/empty_repo_test.go index b19774a826814..e122531dc9877 100644 --- a/tests/integration/empty_repo_test.go +++ b/tests/integration/empty_repo_test.go @@ -60,12 +60,20 @@ func TestEmptyRepoAddFile(t *testing.T) { defer tests.PrepareTestEnv(t)() session := loginUser(t, "user30") + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository) + + // test web page req := NewRequest(t, "GET", "/user30/empty") resp := session.MakeRequest(t, req, http.StatusOK) bodyString := resp.Body.String() assert.Contains(t, bodyString, "empty-repo-guide") assert.True(t, test.IsNormalPageCompleted(bodyString)) + // test api + req = NewRequest(t, "GET", "/api/v1/repos/user30/empty/raw/main/README.md").AddTokenAuth(token) + session.MakeRequest(t, req, http.StatusNotFound) + + // create a new file req = NewRequest(t, "GET", "/user30/empty/_new/"+setting.Repository.DefaultBranch) resp = session.MakeRequest(t, req, http.StatusOK) doc := NewHTMLParser(t, resp.Body).Find(`input[name="commit_choice"]`) diff --git a/tests/integration/git_smart_http_test.go b/tests/integration/git_smart_http_test.go index 15336b9b81f39..55d647672a2ba 100644 --- a/tests/integration/git_smart_http_test.go +++ b/tests/integration/git_smart_http_test.go @@ -9,7 +9,10 @@ import ( "net/url" "testing" + "code.gitea.io/gitea/modules/util" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestGitSmartHTTP(t *testing.T) { @@ -18,51 +21,55 @@ func TestGitSmartHTTP(t *testing.T) { func testGitSmartHTTP(t *testing.T, u *url.URL) { kases := []struct { - p string - code int + method, path string + code int }{ { - p: "user2/repo1/info/refs", + path: "user2/repo1/info/refs", code: http.StatusOK, }, { - p: "user2/repo1/HEAD", + method: "HEAD", + path: "user2/repo1/info/refs", + code: http.StatusOK, + }, + { + path: "user2/repo1/HEAD", code: http.StatusOK, }, { - p: "user2/repo1/objects/info/alternates", + path: "user2/repo1/objects/info/alternates", code: http.StatusNotFound, }, { - p: "user2/repo1/objects/info/http-alternates", + path: "user2/repo1/objects/info/http-alternates", code: http.StatusNotFound, }, { - p: "user2/repo1/../../custom/conf/app.ini", + path: "user2/repo1/../../custom/conf/app.ini", code: http.StatusNotFound, }, { - p: "user2/repo1/objects/info/../../../../custom/conf/app.ini", + path: "user2/repo1/objects/info/../../../../custom/conf/app.ini", code: http.StatusNotFound, }, { - p: `user2/repo1/objects/info/..\..\..\..\custom\conf\app.ini`, + path: `user2/repo1/objects/info/..\..\..\..\custom\conf\app.ini`, code: http.StatusBadRequest, }, } for _, kase := range kases { - t.Run(kase.p, func(t *testing.T) { - p := u.String() + kase.p - req, err := http.NewRequest("GET", p, nil) - assert.NoError(t, err) + t.Run(kase.path, func(t *testing.T) { + req, err := http.NewRequest(util.IfZero(kase.method, "GET"), u.String()+kase.path, nil) + require.NoError(t, err) req.SetBasicAuth("user2", userPassword) resp, err := http.DefaultClient.Do(req) - assert.NoError(t, err) + require.NoError(t, err) defer resp.Body.Close() assert.EqualValues(t, kase.code, resp.StatusCode) _, err = io.ReadAll(resp.Body) - assert.NoError(t, err) + require.NoError(t, err) }) } }