Compare commits

..

1 Commits

Author SHA1 Message Date
Grzegorz Alibożek
4563148a61 Upgrade Alpine from 3.13 to 3.15 (#18050)
* Upgrade alpine to 3.15

* Add executability test to entrypoint for too old dockers

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Update docker/rootless/usr/local/bin/docker-entrypoint.sh

Co-authored-by: zeripath <art27@cantab.net>
2022-01-19 16:55:17 -05:00
273 changed files with 2415 additions and 5770 deletions

File diff suppressed because it is too large Load Diff

2
.gitignore vendored
View File

@@ -36,8 +36,6 @@ _testmain.go
coverage.all
cpu.out
/modules/migration/bindata.go
/modules/migration/bindata.go.hash
/modules/options/bindata.go
/modules/options/bindata.go.hash
/modules/public/bindata.go

View File

@@ -13,7 +13,7 @@ linters:
#- gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time.
- gofmt
- misspell
#- gocritic # TODO: disabled until fixed with go 1.18
- gocritic
- bidichk
- ineffassign
- revive
@@ -22,11 +22,7 @@ linters:
fast: false
run:
timeout: 10m
skip-dirs:
- node_modules
- public
- web_src
timeout: 3m
linters-settings:
gocritic:
@@ -61,9 +57,6 @@ linters-settings:
- name: errorf
- name: duplicated-imports
- name: modifies-value-receiver
gofumpt:
extra-rules: true
lang-version: 1.18
issues:
exclude-rules:
@@ -151,11 +144,3 @@ issues:
- path: models/user/openid.go
linters:
- golint
- linters: staticcheck
text: "strings.Title is deprecated: The rule Title uses for word boundaries does not handle Unicode punctuation properly. Use golang.org/x/text/cases instead."
- linters: staticcheck
text: "util.FindClosure is deprecated: This function can not handle newlines. Many elements can be existed over multiple lines(e.g. link labels). Use text.Reader.FindClosure."
- linters: staticcheck
text: "gossh.SigAlgoRSASHA2256 is deprecated: use KeyAlgoRSASHA256."
- linters: staticcheck
text: "gossh.SigAlgoRSASHA2512 is deprecated: use KeyAlgoRSASHA512."

View File

@@ -4,210 +4,13 @@ This changelog goes through all 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.io).
## [1.16.6](https://github.com/go-gitea/gitea/releases/tag/v1.16.6) - 2022-04-20
* ENHANCEMENTS
* Only request write when necessary (#18657) (#19422)
* Disable service worker by default (#18914) (#19342)
* BUGFIXES
* When dumping trim the standard suffices instead of a random suffix (#19440) (#19447)
* Fix DELETE request for non-existent public key (#19443) (#19444)
* Don't panic on ErrEmailInvalid (#19441) (#19442)
* Add uploadpack.allowAnySHA1InWant to allow --filter=blob:none with older git clients (#19430) (#19438)
* Warn on SSH connection for incorrect configuration (#19317) (#19437)
* Search Issues via API, dont show 500 if filter result in empty list (#19244) (#19436)
* When updating mirror repo intervals by API reschedule next update too (#19429) (#19433)
* Fix nil error when some pages are rendered outside request context (#19427) (#19428)
* Fix double blob-hunk on diff page (#19404) (#19405)
* Don't allow merging PR's which are being conflict checked (#19357) (#19358)
* Fix middleware function's placements (#19377) (#19378)
* Fix invalid CSRF token bug, make sure CSRF tokens can be up-to-date (#19338)
* Restore user autoregistration with email addresses (#19261) (#19312)
* Move checks for pulls before merge into own function (#19271) (#19277)
* Granular webhook events in editHook (#19251) (#19257)
* Only send webhook events to active system webhooks and only deliver to active hooks (#19234) (#19248)
* Use full output of git show-ref --tags to get tags for PushUpdateAddTag (#19235) (#19236)
* Touch mirrors on even on fail to update (#19217) (#19233)
* Hide sensitive content on admin panel progress monitor (#19218 & #19226) (#19231)
* Fix clone url JS error for the empty repo page (#19209)
* Bump goldmark to v1.4.11 (#19201) (#19203)
* TESTING
* Prevent intermittent failures in RepoIndexerTest (#19225 #19229) (#19228)
* BUILD
* Revert the minimal golang version requirement from 1.17 to 1.16 and add a warning in Makefile (#19319)
* MISC
* Performance improvement for add team user when org has more than 1000 repositories (#19227) (#19289)
* Check go and nodejs version by go.mod and package.json (#19197) (#19254)
## [1.16.5](https://github.com/go-gitea/gitea/releases/tag/v1.16.5) - 2022-03-23
* BREAKING
* Bump to build with go1.18 (#19120 et al) (#19127)
* SECURITY
* Prevent redirect to Host (2) (#19175) (#19186)
* Try to prevent autolinking of displaynames by email readers (#19169) (#19183)
* Clean paths when looking in Storage (#19124) (#19179)
* Do not send notification emails to inactive users (#19131) (#19139)
* Do not send activation email if manual confirm is set (#19119) (#19122)
* ENHANCEMENTS
* Use the new/choose link for New Issue on project page (#19172) (#19176)
* BUGFIXES
* Fix showing issues in your repositories (#18916) (#19191)
* Fix compare link in active feeds for new branch (#19149) (#19185)
* Redirect .wiki/* ui link to /wiki (#18831) (#19184)
* Ensure deploy keys with write access can push (#19010) (#19182)
* Ensure that setting.LocalURL always has a trailing slash (#19171) (#19177)
* Cleanup protected branches when deleting users & teams (#19158) (#19174)
* Use IterateBufferSize whilst querying repositories during adoption check (#19140) (#19160)
* Fix NPE /repos/issues/search when not signed in (#19154) (#19155)
* Use custom favicon when viewing static files if it exists (#19130) (#19152)
* Fix the editor height in review box (#19003) (#19147)
* Ensure isSSH is set whenever DISABLE_HTTP_GIT is set (#19028) (#19146)
* Fix wrong scopes caused by empty scope input (#19029) (#19145)
* Make migrations SKIP_TLS_VERIFY apply to git too (#19132) (#19141)
* Handle email address not exist (#19089) (#19121)
* MISC
* Update json-iterator to allow compilation with go1.18 (#18644) (#19100)
* Update golang.org/x/crypto (#19097) (#19098)
## [1.16.4](https://github.com/go-gitea/gitea/releases/tag/v1.16.4) - 2022-03-14
* SECURITY
* Restrict email address validation (#17688) (#19085)
* Fix lfs bug (#19072) (#19080)
* ENHANCEMENTS
* Improve SyncMirrors logging (#19045) (#19050)
* BUGFIXES
* Refactor mirror code & fix `StartToMirror` (#18904) (#19075)
* Update the webauthn_credential_id_sequence in Postgres (#19048) (#19060)
* Prevent 500 when there is an error during new auth source post (#19041) (#19059)
* If rendering has failed due to a net.OpError stop rendering (attempt 2) (#19049) (#19056)
* Fix flag validation (#19046) (#19051)
* Add pam account authorization check (#19040) (#19047)
* Ignore missing comment for user notifications (#18954) (#19043)
* Set `rel="nofollow noindex"` on new issue links (#19023) (#19042)
* Upgrading binding package (#19034) (#19035)
* Don't show context cancelled errors in attribute reader (#19006) (#19027)
* Fix update hint bug (#18996) (#19002)
* MISC
* Fix potential assignee query for repo (#18994) (#18999)
## [1.16.3](https://github.com/go-gitea/gitea/releases/tag/v1.16.3) - 2022-03-02
* SECURITY
* Git backend ignore replace objects (#18979) (#18980)
* ENHANCEMENTS
* Adjust error for already locked db and prevent level db lock on malformed connstr (#18923) (#18938)
* BUGFIXES
* Set max text height to prevent overflow (#18862) (#18977)
* Fix newAttachmentPaths deletion for DeleteRepository() (#18973) (#18974)
* Accounts with WebAuthn only (no TOTP) now exist ... fix code to handle that case (#18897) (#18964)
* Send 404 on `/{org}.gpg` (#18959) (#18962)
* Fix admin user list pagination (#18957) (#18960)
* Fix lfs management setting (#18947) (#18946)
* Fix login with email panic when email is not exist (#18942)
* Update go-org to v1.6.1 (#18932) (#18933)
* Fix `<strong>` html in translation (#18929) (#18931)
* Fix page and missing return on unadopted repos API (#18848) (#18927)
* Allow adminstrator teams members to see other teams (#18918) (#18919)
* Don't treat BOM escape sequence as hidden character. (#18909) (#18910)
* Correctly link URLs to users/repos with dashes, dots or underscores (… (#18908)
* Fix redirect when using lowercase repo name (#18775) (#18902)
* Fix migration v210 (#18893) (#18892)
* Fix team management UI (#18887) (18886)
* BeforeSourcePath should point to base commit (#18880) (#18799)
* TRANSLATION
* Backport locales from master (#18944)
* MISC
* Don't update email for organisation (#18905) (#18906)
## [1.16.2](https://github.com/go-gitea/gitea/releases/tag/v1.16.2) - 2022-02-24
* ENHANCEMENTS
* Show fullname on issue edits and gpg/ssh signing info (#18828)
* Immediately Hammer if second kill is sent (#18823) (#18826)
* Allow mermaid render error to wrap (#18791)
* BUGFIXES
* Fix ldap user sync missed email in email_address table (#18786) (#18876)
* Update assignees check to include any writing team and change org sidebar (#18680) (#18873)
* Don't report signal: killed errors in serviceRPC (#18850) (#18865)
* Fix bug where certain LDAP settings were reverted (#18859)
* Update go-org to 1.6.0 (#18824) (#18839)
* Fix login with email for ldap users (#18800) (#18836)
* Fix bug for get user by email (#18834)
* Fix panic in EscapeReader (#18820) (#18821)
* Fix ldap loginname (#18789) (#18804)
* Remove redundant call to UpdateRepoStats during migration (#18591) (#18794)
* In disk_channel queues synchronously push to disk on shutdown (#18415) (#18788)
* Fix template bug of LFS lock (#18784) (#18787)
* Attempt to fix the webauthn migration again - part 3 (#18770) (#18771)
* Send mail to issue/pr assignee/reviewer also when OnMention is set (#18707) (#18765)
* Fix a broken link in commits_list_small.tmpl (#18763) (#18764)
* Increase the size of the webauthn_credential credential_id field (#18739) (#18756)
* Prevent dangling GetAttribute calls (#18754) (#18755)
* Fix isempty detection of git repository (#18746) (#18750)
* Fix source code line highlighting on external tracker (#18729) (#18740)
* Prevent double encoding of branch names in delete branch (#18714) (#18738)
* Always set PullRequestWorkInProgressPrefixes in PrepareViewPullInfo (#18713) (#18737)
* Fix forked repositories missed tags (#18719) (#18735)
* Fix release typo (#18728) (#18731)
* Separate the details links of commit-statuses in headers (#18661) (#18730)
* Update object repo with the migrated repository (#18684) (#18726)
* Fix bug for version update hint (#18701) (#18705)
* Fix issue with docker-rootless shimming script (#18690) (#18699)
* Let `MinUnitAccessMode` return correct perm (#18675) (#18689)
* Prevent security failure due to bad APP_ID (#18678) (#18682)
* Restart zero worker if there is still work to do (#18658) (#18672)
* If rendering has failed due to a net.OpError stop rendering (#18642) (#18645)
* TESTING
* Ensure git tag tests and others create test repos in tmpdir (#18447) (#18767)
* BUILD
* Reduce CI go module downloads, add make targets (#18708, #18475, #18443) (#18741)
* MISC
* Put buttons back in org dashboard (#18817) (#18825)
* Various Mermaid improvements (#18776) (#18780)
* C preprocessor colors improvement (#18671) (#18696)
* Fix the missing i18n key for update checker (#18646) (#18665)
## [1.16.1](https://github.com/go-gitea/gitea/releases/tag/v1.16.1) - 2022-02-06
* SECURITY
* Update JS dependencies, fix lint (#18389) (#18540)
* ENHANCEMENTS
* Add dropdown icon to label set template dropdown (#18564) (#18571)
* BUGFIXES
* Comments on migrated issues/prs must link to the comment ID (#18630) (#18637)
* Stop logging an error when notes are not found (#18626) (#18635)
* Ensure that blob-excerpt links work for wiki (#18587) (#18624)
* Only attempt to flush queue if the underlying worker pool is not finished (#18593) (#18620)
* Ensure commit-statuses box is sized correctly in headers (#18538) (#18606)
* Prevent merge messages from being sorted to the top of email chains (#18566) (#18588)
* Prevent panic on prohibited user login with oauth2 (#18562) (#18563)
* Collaborator trust model should trust collaborators (#18539) (#18557)
* Detect conflicts with 3way merge (#18536) (#18537)
* In docker rootless use $GITEA_APP_INI if provided (#18524) (#18535)
* Add `GetUserTeams` (#18499) (#18531)
* Fix review excerpt (#18502) (#18530)
* Fix for AvatarURL database type (#18487) (#18529)
* Use `ImagedProvider` for gplus oauth2 provider (#18504) (#18505)
* Fix OAuth Source Edit Page (#18495) (#18503)
* Use "read" value for General Access (#18496) (#18500)
* Prevent NPE on partial match of compare URL and allow short SHA1 compare URLs (#18472) (#18473)
* BUILD
* Make docker gitea/gitea:v1.16-dev etc refer to the latest build on that branch (#18551) (#18569)
* DOCS
* Update 1.16.0 changelog to set #17846 as breaking (#18533) (#18534)
## [1.16.0](https://github.com/go-gitea/gitea/releases/tag/v1.16.0) - 2022-01-30
## [1.16.0-rc1](https://github.com/go-gitea/gitea/releases/tag/v1.16.0-rc1) - 2022-01-19
* BREAKING
* Remove golang vendored directory (#18277)
* Paginate releases page & set default page size to 10 (#16857)
* Use shadowing script for docker (#17846)
* Only allow webhook to send requests to allowed hosts (#17482)
* SECURITY
* Disable content sniffing on `PlainTextBytes` (#18359) (#18365)
* Only view milestones from current repo (#18414) (#18417)
* Sanitize user-input on file name (#17666)
* Use `hostmatcher` to replace `matchlist` to improve blocking of bad hosts in Webhooks (#17605)
* FEATURES
@@ -425,16 +228,6 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Add left padding for chunk header of split diff view (#13397)
* Allow U2F 2FA without TOTP (#11573)
* BUGFIXES
* GitLab reviews may not have the updated_at field set (#18450) (#18461)
* Fix detection of no commits when the default branch is not master (#18422) (#18423)
* Fix broken oauth2 authentication source edit page (#18412) (#18419)
* Place inline diff comment dialogs on split diff in 4th and 8th columns (#18403) (#18404)
* Fix restore without topic failure (#18387) (#18400)
* Fix commit's time (#18375) (#18392)
* Fix partial cloning a repo (#18373) (#18377)
* Stop trimming preceding and suffixing spaces from editor filenames (#18334)
* Prevent showing webauthn error for every time visiting `/user/settings/security` (#18386)
* Fix mime-type detection for HTTP server (#18370) (#18371)
* Stop trimming preceding and suffixing spaces from editor filenames (#18334)
* Restore propagation of ErrDependenciesLeft (#18325)
* Fix PR comments UI (#18323)
@@ -502,22 +295,10 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* BUILD
* Add lockfile-check (#18285)
* Don't store assets modified time into generated files (#18193)
* Use shadowing script for docker (#17846)
* MISC
* Update JS dependencies (#17611)
## [1.15.11](https://github.com/go-gitea/gitea/releases/tag/v1.15.11) - 2022-01-29
* SECURITY
* Only view milestones from current repo (#18414) (#18418)
* BUGFIXES
* Fix broken when no commits and default branch is not master (#18422) (#18424)
* Fix commit's time (#18375) (#18409)
* Fix restore without topic failure (#18387) (#18401)
* Fix mermaid import in 1.15 (it uses ESModule now) (#18382)
* Update to go/text 0.3.7 (#18336)
* MISC
* Upgrade EasyMDE to 2.16.1 (#18278) (#18279)
## [1.15.10](https://github.com/go-gitea/gitea/releases/tag/v1.15.10) - 2022-01-14
* BUGFIXES

View File

@@ -1,5 +1,5 @@
#Build stage
FROM golang:1.18-alpine3.15 AS build-env
FROM golang:1.17-alpine3.15 AS build-env
ARG GOPROXY
ENV GOPROXY ${GOPROXY:-direct}
@@ -23,7 +23,7 @@ RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
# Begin env-to-ini build
RUN go build contrib/environment-to-ini/environment-to-ini.go
FROM alpine:3.13
FROM alpine:3.15
LABEL maintainer="maintainers@gitea.io"
EXPOSE 22 3000

View File

@@ -1,5 +1,5 @@
#Build stage
FROM golang:1.18-alpine3.15 AS build-env
FROM golang:1.17-alpine3.15 AS build-env
ARG GOPROXY
ENV GOPROXY ${GOPROXY:-direct}
@@ -23,7 +23,7 @@ RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
# Begin env-to-ini build
RUN go build contrib/environment-to-ini/environment-to-ini.go
FROM alpine:3.13
FROM alpine:3.15
LABEL maintainer="maintainers@gitea.io"
EXPOSE 2222 3000

127
Makefile
View File

@@ -24,17 +24,10 @@ SHASUM ?= shasum -a 256
HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
COMMA := ,
XGO_VERSION := go-1.18.x
AIR_PACKAGE ?= github.com/cosmtrek/air@v1.29.0
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.4.0
ERRCHECK_PACKAGE ?= github.com/kisielk/errcheck@v1.6.0
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.3.0
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.44.2
GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.10
MISSPELL_PACKAGE ?= github.com/client9/misspell/cmd/misspell@v0.3.4
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.29.0
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
XGO_VERSION := go-1.17.x
MIN_GO_VERSION := 001016000
MIN_NODE_VERSION := 012017000
MIN_GOLANGCI_LINT_VERSION := 001043000
DOCKER_IMAGE ?= gitea/gitea
DOCKER_TAG ?= latest
@@ -132,6 +125,8 @@ ifeq ($(filter $(TAGS_SPLIT),bindata),bindata)
GO_SOURCES += $(BINDATA_DEST)
endif
#To update swagger use: GO111MODULE=on go get -u github.com/go-swagger/go-swagger/cmd/swagger
SWAGGER := $(GO) run github.com/go-swagger/go-swagger/cmd/swagger
SWAGGER_SPEC := templates/swagger/v1_json.tmpl
SWAGGER_SPEC_S_TMPL := s|"basePath": *"/api/v1"|"basePath": "{{AppSubUrl \| JSEscape \| Safe}}/api/v1"|g
SWAGGER_SPEC_S_JSON := s|"basePath": *"{{AppSubUrl \| JSEscape \| Safe}}/api/v1"|"basePath": "/api/v1"|g
@@ -171,9 +166,6 @@ help:
@echo " - watch-backend watch backend files and continuously rebuild"
@echo " - clean delete backend and integration files"
@echo " - clean-all delete backend, frontend and integration files"
@echo " - deps install dependencies"
@echo " - deps-frontend install frontend dependencies"
@echo " - deps-backend install backend dependencies"
@echo " - lint lint everything"
@echo " - lint-frontend lint frontend files"
@echo " - lint-backend lint backend files"
@@ -201,15 +193,10 @@ help:
.PHONY: go-check
go-check:
$(eval MIN_GO_VERSION_STR := $(shell grep -Eo '^go\s+[0-9]+\.[0-9.]+' go.mod | cut -d' ' -f2))
$(eval MIN_GO_VERSION := $(shell printf "%03d%03d%03d" $(shell echo '$(MIN_GO_VERSION_STR)' | tr '.' ' ')))
$(eval GO_VERSION_STR := $(shell $(GO) version | grep -Eo '[0-9]+\.[0-9.]+'))
$(eval GO_VERSION := $(shell printf "%03d%03d%03d" $(shell echo '$(GO_VERSION_STR)' | tr '.' ' ')))
$(eval GO_VERSION := $(shell printf "%03d%03d%03d" $(shell $(GO) version | grep -Eo '[0-9]+\.[0-9.]+' | tr '.' ' ');))
@if [ "$(GO_VERSION)" -lt "$(MIN_GO_VERSION)" ]; then \
echo "Gitea requires Go $(MIN_GO_VERSION_STR) or greater to build, but $(GO_VERSION) was found. You can get an updated version at https://go.dev/dl/"; \
echo "Gitea requires Go 1.16 or greater to build. You can get it at https://golang.org/dl/"; \
exit 1; \
else \
echo "WARNING: Please ensure Go $(GO_VERSION_STR) is still maintained to avoid possible security problems. You can check it at https://go.dev/dl/"; \
fi
.PHONY: git-check
@@ -221,12 +208,11 @@ git-check:
.PHONY: node-check
node-check:
$(eval MIN_NODE_VERSION_STR := $(shell grep -Eo '"node":.*[0-9.]+"' package.json | sed -n 's/.*[^0-9.]\([0-9.]*\)"/\1/p'))
$(eval MIN_NODE_VERSION := $(shell printf "%03d%03d%03d" $(shell echo '$(MIN_NODE_VERSION_STR)' | tr '.' ' ')))
$(eval NODE_VERSION := $(shell printf "%03d%03d%03d" $(shell node -v | cut -c2- | tr '.' ' ');))
$(eval MIN_NODE_VER_FMT := $(shell printf "%g.%g.%g" $(shell echo $(MIN_NODE_VERSION) | grep -o ...)))
$(eval NPM_MISSING := $(shell hash npm > /dev/null 2>&1 || echo 1))
@if [ "$(NODE_VERSION)" -lt "$(MIN_NODE_VERSION)" -o "$(NPM_MISSING)" = "1" ]; then \
echo "Gitea requires Node.js $(MIN_NODE_VERSION_STR) or greater and npm to build. You can get it at https://nodejs.org/en/download/"; \
echo "Gitea requires Node.js $(MIN_NODE_VER_FMT) or greater and npm to build. You can get it at https://nodejs.org/en/download/"; \
exit 1; \
fi
@@ -245,8 +231,8 @@ clean:
.PHONY: fmt
fmt:
@echo "Running gitea-fmt (with gofumpt)..."
@MISSPELL_PACKAGE=$(MISSPELL_PACKAGE) GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}'
@echo "Running gitea-fmt(with gofmt)..."
@$(GO) run build/code-batch-process.go gitea-fmt -s -w '{file-list}'
.PHONY: vet
vet:
@@ -265,7 +251,7 @@ endif
.PHONY: generate-swagger
generate-swagger:
$(GO) run $(SWAGGER_PACKAGE) generate spec -x "$(SWAGGER_EXCLUDE)" -o './$(SWAGGER_SPEC)'
$(SWAGGER) generate spec -x "$(SWAGGER_EXCLUDE)" -o './$(SWAGGER_SPEC)'
$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)'
$(SED_INPLACE) $(SWAGGER_NEWLINE_COMMAND) './$(SWAGGER_SPEC)'
@@ -281,18 +267,21 @@ swagger-check: generate-swagger
.PHONY: swagger-validate
swagger-validate:
$(SED_INPLACE) '$(SWAGGER_SPEC_S_JSON)' './$(SWAGGER_SPEC)'
$(GO) run $(SWAGGER_PACKAGE) validate './$(SWAGGER_SPEC)'
$(SWAGGER) validate './$(SWAGGER_SPEC)'
$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)'
.PHONY: errcheck
errcheck:
@hash errcheck > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install github.com/kisielk/errcheck@8ddee489636a8311a376fc92e27a6a13c6658344; \
fi
@echo "Running errcheck..."
$(GO) run $(ERRCHECK_PACKAGE) $(GO_PACKAGES)
@errcheck $(GO_PACKAGES)
.PHONY: fmt-check
fmt-check:
# get all go files and run gitea-fmt (with gofmt) on them
@diff=$$(MISSPELL_PACKAGE=$(MISSPELL_PACKAGE) GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -l '{file-list}'); \
@diff=$$($(GO) run build/code-batch-process.go gitea-fmt -s -d '{file-list}'); \
if [ -n "$$diff" ]; then \
echo "Please run 'make fmt' and commit the result:"; \
echo "$${diff}"; \
@@ -331,7 +320,10 @@ watch-frontend: node-check node_modules
.PHONY: watch-backend
watch-backend: go-check
$(GO) run $(AIR_PACKAGE) -c .air.toml
@hash air > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install github.com/cosmtrek/air@bedc18201271882c2be66d216d0e1a275b526ec4; \
fi
air -c .air.toml
.PHONY: test
test: test-frontend test-backend
@@ -404,11 +396,6 @@ test-sqlite-migration: migrations.sqlite.test migrations.individual.sqlite.test
GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/sqlite.ini ./migrations.sqlite.test
GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/sqlite.ini ./migrations.individual.sqlite.test
.PHONY: test-sqlite-migration\#%
test-sqlite-migration\#%: migrations.sqlite.test migrations.individual.sqlite.test generate-ini-sqlite
GITEA_ROOT="$(CURDIR)" GITEA_CONF=integrations/sqlite.ini ./migrations.individual.sqlite.test -test.run $(subst .,/,$*)
generate-ini-mysql:
sed -e 's|{{TEST_MYSQL_HOST}}|${TEST_MYSQL_HOST}|g' \
-e 's|{{TEST_MYSQL_DBNAME}}|${TEST_MYSQL_DBNAME}|g' \
@@ -604,9 +591,12 @@ $(DIST_DIRS):
.PHONY: release-windows
release-windows: | $(DIST_DIRS)
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install src.techknowlogick.com/xgo@latest; \
fi
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
ifeq (,$(findstring gogit,$(TAGS)))
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit .
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit .
endif
ifeq ($(CI),drone)
cp /build/* $(DIST)/binaries
@@ -614,14 +604,20 @@ endif
.PHONY: release-linux
release-linux: | $(DIST_DIRS)
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) .
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install src.techknowlogick.com/xgo@latest; \
fi
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) .
ifeq ($(CI),drone)
cp /build/* $(DIST)/binaries
endif
.PHONY: release-darwin
release-darwin: | $(DIST_DIRS)
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) .
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install src.techknowlogick.com/xgo@latest; \
fi
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) .
ifeq ($(CI),drone)
cp /build/* $(DIST)/binaries
endif
@@ -636,7 +632,10 @@ release-check: | $(DIST_DIRS)
.PHONY: release-compress
release-compress: | $(DIST_DIRS)
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && $(GO) run $(GXZ_PAGAGE) -k -9 $${file}; done;
@hash gxz > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install github.com/ulikunitz/xz/cmd/gxz@v0.5.10; \
fi
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && gxz -k -9 $${file}; done;
.PHONY: release-sources
release-sources: | $(DIST_DIRS)
@@ -657,25 +656,6 @@ docs:
fi
cd docs; make trans-copy clean build-offline;
.PHONY: deps
deps: deps-frontend deps-backend
.PHONY: deps-frontend
deps-frontend: node_modules
.PHONY: deps-backend
deps-backend:
$(GO) mod download
$(GO) install $(AIR_PACKAGE)
$(GO) install $(EDITORCONFIG_CHECKER_PACKAGE)
$(GO) install $(ERRCHECK_PACKAGE)
$(GO) install $(GOFUMPT_PACKAGE)
$(GO) install $(GOLANGCI_LINT_PACKAGE)
$(GO) install $(GXZ_PAGAGE)
$(GO) install $(MISSPELL_PACKAGE)
$(GO) install $(SWAGGER_PACKAGE)
$(GO) install $(XGO_PACKAGE)
node_modules: package-lock.json
npm install --no-save
@touch node_modules
@@ -768,19 +748,22 @@ pr\#%: clean-all
$(GO) run contrib/pr/checkout.go $*
.PHONY: golangci-lint
golangci-lint:
$(GO) run $(GOLANGCI_LINT_PACKAGE) run
golangci-lint: golangci-lint-check
golangci-lint run --timeout 10m
# workaround step for the lint-backend-windows CI task because 'go run' can not
# have distinct GOOS/GOARCH for its build and run steps
.PHONY: golangci-lint-windows
golangci-lint-windows:
@GOOS= GOARCH= $(GO) install $(GOLANGCI_LINT_PACKAGE)
golangci-lint run
.PHONY: editorconfig-checker
editorconfig-checker:
$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) templates
.PHONY: golangci-lint-check
golangci-lint-check:
$(eval GOLANGCI_LINT_VERSION := $(shell printf "%03d%03d%03d" $(shell golangci-lint --version | grep -Eo '[0-9]+\.[0-9.]+' | tr '.' ' ');))
$(eval MIN_GOLANGCI_LINT_VER_FMT := $(shell printf "%g.%g.%g" $(shell echo $(MIN_GOLANGCI_LINT_VERSION) | grep -o ...)))
@hash golangci-lint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
echo "Downloading golangci-lint v${MIN_GOLANGCI_LINT_VER_FMT}"; \
export BINARY="golangci-lint"; \
curl -sfL "https://raw.githubusercontent.com/golangci/golangci-lint/v${MIN_GOLANGCI_LINT_VER_FMT}/install.sh" | sh -s -- -b $(GOPATH)/bin v$(MIN_GOLANGCI_LINT_VER_FMT); \
elif [ "$(GOLANGCI_LINT_VERSION)" -lt "$(MIN_GOLANGCI_LINT_VERSION)" ]; then \
echo "Downloading newer version of golangci-lint v${MIN_GOLANGCI_LINT_VER_FMT}"; \
export BINARY="golangci-lint"; \
curl -sfL "https://raw.githubusercontent.com/golangci/golangci-lint/v${MIN_GOLANGCI_LINT_VER_FMT}/install.sh" | sh -s -- -b $(GOPATH)/bin v$(MIN_GOLANGCI_LINT_VER_FMT); \
fi
.PHONY: docker
docker:

View File

@@ -73,7 +73,7 @@ or if SQLite support is required:
The `build` target is split into two sub-targets:
- `make backend` which requires [Go 1.17](https://go.dev/dl/) or greater.
- `make backend` which requires [Go 1.16](https://golang.org/dl/) or greater.
- `make frontend` which requires [Node.js LTS](https://nodejs.org/en/download/) or greater and Internet connectivity to download npm dependencies.
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 and Internet connectivity.

View File

@@ -40,7 +40,7 @@ func passThroughCmd(cmd string, args []string) error {
}
c := exec.Cmd{
Path: foundCmd,
Args: append([]string{cmd}, args...),
Args: args,
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
@@ -270,10 +270,9 @@ func main() {
if containsString(subArgs, "-w") {
cmdErrors = append(cmdErrors, giteaFormatGoImports(files))
}
cmdErrors = append(cmdErrors, giteaFormatGoImports(files, containsString(subArgs, "-l"), containsString(subArgs, "-w")))
cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("GOFUMPT_PACKAGE"), "-extra", "-lang", "1.17"}, substArgs...)))
cmdErrors = append(cmdErrors, passThroughCmd("gofmt", substArgs))
case "misspell":
cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("MISSPELL_PACKAGE")}, substArgs...)))
cmdErrors = append(cmdErrors, passThroughCmd("misspell", substArgs))
default:
log.Fatalf("unknown cmd: %s %v", subCmd, subArgs)
}

View File

@@ -31,7 +31,7 @@ func argsSet(c *cli.Context, args ...string) error {
return errors.New(a + " is not set")
}
if util.IsEmptyString(c.String(a)) {
if util.IsEmptyString(a) {
return errors.New(a + " is required")
}
}

View File

@@ -86,7 +86,7 @@ func (o outputType) String() string {
}
var outputTypeEnum = &outputType{
Enum: []string{"zip", "tar", "tar.sz", "tar.gz", "tar.xz", "tar.bz2", "tar.br", "tar.lz4"},
Enum: []string{"zip", "rar", "tar", "sz", "tar.gz", "tar.xz", "tar.bz2", "tar.br", "tar.lz4"},
Default: "zip",
}
@@ -160,12 +160,7 @@ func runDump(ctx *cli.Context) error {
fatal("Deleting default logger failed. Can not write to stdout: %v", err)
}
} else {
for _, suffix := range outputTypeEnum.Enum {
if strings.HasSuffix(fileName, "."+suffix) {
fileName = strings.TrimSuffix(fileName, "."+suffix)
break
}
}
fileName = strings.TrimSuffix(fileName, path.Ext(fileName))
fileName += "." + outType
}
setting.LoadFromExisting()

View File

@@ -185,7 +185,7 @@ Gitea or set your environment appropriately.`, "")
reponame := os.Getenv(models.EnvRepoName)
userID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64)
prID, _ := strconv.ParseInt(os.Getenv(models.EnvPRID), 10, 64)
deployKeyID, _ := strconv.ParseInt(os.Getenv(models.EnvDeployKeyID), 10, 64)
isDeployKey, _ := strconv.ParseBool(os.Getenv(models.EnvIsDeployKey))
hookOptions := private.HookOptions{
UserID: userID,
@@ -194,7 +194,7 @@ Gitea or set your environment appropriately.`, "")
GitQuarantinePath: os.Getenv(private.GitQuarantinePath),
GitPushOptions: pushOptions(),
PullRequestID: prID,
DeployKeyID: deployKeyID,
IsDeployKey: isDeployKey,
}
scanner := bufio.NewScanner(os.Stdin)

View File

@@ -243,7 +243,7 @@ func runServ(c *cli.Context) error {
os.Setenv(models.EnvPusherID, strconv.FormatInt(results.UserID, 10))
os.Setenv(models.EnvRepoID, strconv.FormatInt(results.RepoID, 10))
os.Setenv(models.EnvPRID, fmt.Sprintf("%d", 0))
os.Setenv(models.EnvDeployKeyID, fmt.Sprintf("%d", results.DeployKeyID))
os.Setenv(models.EnvIsDeployKey, fmt.Sprintf("%t", results.IsDeployKey))
os.Setenv(models.EnvKeyID, fmt.Sprintf("%d", results.KeyID))
os.Setenv(models.EnvAppURL, setting.AppURL)
@@ -297,15 +297,6 @@ func runServ(c *cli.Context) error {
gitcmd = exec.CommandContext(ctx, verb, repoPath)
}
// Check if setting.RepoRootPath exists. It could be the case that it doesn't exist, this can happen when
// `[repository]` `ROOT` is a relative path and $GITEA_WORK_DIR isn't passed to the SSH connection.
if _, err := os.Stat(setting.RepoRootPath); err != nil {
if os.IsNotExist(err) {
return fail("Incorrect configuration.",
"Directory `[repository]` `ROOT` was not found, please check if $GITEA_WORK_DIR is passed to the SSH connection or make `[repository]` `ROOT` an absolute value.")
}
}
gitcmd.Dir = setting.RepoRootPath
gitcmd.Stdout = os.Stdout
gitcmd.Stdin = os.Stdin

View File

@@ -33,8 +33,10 @@ for i in "$@"; do
done
if [ -z "$APP_INI_SET" ]; then
CONF_ARG=("-c" "${GITEA_APP_INI:-$APP_INI}")
CONF_ARG="-c \"$APP_INI\""
fi
# Provide FHS compliant defaults
GITEA_WORK_DIR="${GITEA_WORK_DIR:-$WORK_DIR}" exec -a "$0" "$GITEA" "${CONF_ARG[@]}" "$@"
GITEA_WORK_DIR="${GITEA_WORK_DIR:-$WORK_DIR}" exec -a "$0" "$GITEA" $CONF_ARG "$@"

View File

@@ -1075,7 +1075,7 @@ PATH =
;SEARCH_REPO_DESCRIPTION = true
;;
;; Whether to enable a Service Worker to cache frontend assets
;USE_SERVICE_WORKER = false
;USE_SERVICE_WORKER = true
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@@ -1,4 +1,4 @@
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-rootless
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}dev{{/if}}-rootless
{{#if build.tags}}
tags:
{{#each build.tags}}
@@ -8,12 +8,12 @@ tags:
{{/if}}
manifests:
-
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-linux-amd64-rootless
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}dev{{/if}}-linux-amd64-rootless
platform:
architecture: amd64
os: linux
-
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-linux-arm64-rootless
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}dev{{/if}}-linux-arm64-rootless
platform:
architecture: arm64
os: linux

View File

@@ -1,4 +1,4 @@
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}dev{{/if}}
{{#if build.tags}}
tags:
{{#each build.tags}}
@@ -8,13 +8,13 @@ tags:
{{/if}}
manifests:
-
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-linux-amd64
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{else}}dev-{{/if}}linux-amd64
platform:
architecture: amd64
os: linux
-
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-linux-arm64
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{else}}dev-{{/if}}linux-arm64
platform:
architecture: arm64
os: linux
variant: v8
variant: v8

View File

@@ -1,5 +1,11 @@
#!/bin/sh
# Protect against buggy runc in docker <20.10.6 causing problems in with Alpine >= 3.14
if [ ! -x /bin/sh ]; then
echo "Executable test for /bin/sh failed. Your Docker version is too old to run Alpine 3.14+ and Gitea. You must upgrade Docker.";
exit 1;
fi
if [ "${USER}" != "git" ]; then
# rename user
sed -i -e "s/^git\:/${USER}\:/g" /etc/passwd

View File

@@ -1,5 +1,11 @@
#!/bin/sh
# Protect against buggy runc in docker <20.10.6 causing problems in with Alpine >= 3.14
if [ ! -x /bin/sh ]; then
echo "Executable test for /bin/sh failed. Your Docker version is too old to run Alpine 3.14+ and Gitea. You must upgrade Docker.";
exit 1;
fi
if [ -x /usr/local/bin/docker-setup.sh ]; then
/usr/local/bin/docker-setup.sh || { echo 'docker setup failed' ; exit 1; }
fi

View File

@@ -32,9 +32,11 @@ for i in "$@"; do
done
if [ -z "$APP_INI_SET" ]; then
CONF_ARG=("-c" "${GITEA_APP_INI:-$APP_INI}")
CONF_ARG="-c \"$APP_INI\""
fi
# Provide docker defaults
GITEA_WORK_DIR="${GITEA_WORK_DIR:-$WORK_DIR}" exec -a "$0" "$GITEA" "${CONF_ARG[@]}" "$@"
GITEA_WORK_DIR="${GITEA_WORK_DIR:-$WORK_DIR}" exec -a "$0" "$GITEA" $CONF_ARG "$@"

View File

@@ -18,9 +18,9 @@ params:
description: Git with a cup of tea
author: The Gitea Authors
website: https://docs.gitea.io
version: 1.16.4
version: 1.15.10
minGoVersion: 1.16
goVersion: 1.18
goVersion: 1.17
minNodeVersion: 12.17
outputs:

View File

@@ -189,7 +189,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
add it to this config.
- `DEFAULT_SHOW_FULL_NAME`: **false**: Whether the full name of the users should be shown where possible. If the full name isn't set, the username will be used.
- `SEARCH_REPO_DESCRIPTION`: **true**: Whether to search within description at repository search on explore page.
- `USE_SERVICE_WORKER`: **false**: Whether to enable a Service Worker to cache frontend assets.
- `USE_SERVICE_WORKER`: **true**: Whether to enable a Service Worker to cache frontend assets.
### UI - Admin (`ui.admin`)

View File

@@ -42,7 +42,7 @@ To maintain understandable code and avoid circular dependencies it is important
- `modules/setting`: Store all system configurations read from ini files and has been referenced by everywhere. But they should be used as function parameters when possible.
- `modules/git`: Package to interactive with `Git` command line or Gogit package.
- `public`: Compiled frontend files (javascript, images, css, etc.)
- `routers`: Handling of server requests. As it uses other Gitea packages to serve the request, other packages (models, modules or services) must not depend on routers.
- `routers`: Handling of server requests. As it uses other Gitea packages to serve the request, other packages (models, modules or services) shall not depend on routers.
- `routers/api` Contains routers for `/api/v1` aims to handle RESTful API requests.
- `routers/install` Could only respond when system is in INSTALL mode (INSTALL_LOCK=false).
- `routers/private` will only be invoked by internal sub commands, especially `serv` and `hooks`.
@@ -106,20 +106,10 @@ i.e. `servcies/user`, `models/repository`.
Since there are some packages which use the same package name, it is possible that you find packages like `modules/user`, `models/user`, and `services/user`. When these packages are imported in one Go file, it's difficult to know which package we are using and if it's a variable name or an import name. So, we always recommend to use import aliases. To differ from package variables which are commonly in camelCase, just use **snake_case** for import aliases.
i.e. `import user_service "code.gitea.io/gitea/services/user"`
### Important Gotchas
- Never write `x.Update(exemplar)` without an explicit `WHERE` clause:
- This will cause all rows in the table to be updated with the non-zero values of the exemplar - including IDs.
- You should usually write `x.ID(id).Update(exemplar)`.
- If during a migration you are inserting into a table using `x.Insert(exemplar)` where the ID is preset:
- You will need to ``SET IDENTITY_INSERT `table` ON`` for the MSSQL variant (the migration will fail otherwise)
- However, you will also need to update the id sequence for postgres - the migration will silently pass here but later insertions will fail:
``SELECT setval('table_name_id_seq', COALESCE((SELECT MAX(id)+1 FROM `table_name`), 1), false)``
### Future Tasks
Currently, we are creating some refactors to do the following things:
- Correct that codes which doesn't follow the rules.
- There are too many files in `models`, so we are moving some of them into a sub package `models/xxx`.
- Some `modules` sub packages should be moved to `services` because they depend on `models`.
- Some `modules` sub packages should be moved to `services` because they depends on `models`.

View File

@@ -185,6 +185,8 @@ Before committing, make sure the linters pass:
make lint-frontend
```
Note: When working on frontend code, set `USE_SERVICE_WORKER` to `false` in `app.ini` to prevent undesirable caching of frontend assets.
### Building and adding SVGs
SVG icons are built using the `make svg` target which compiles the icon sources defined in `build/generate-svg.js` into the output directory `public/img/svg`. Custom icons can be added in the `web_src/svg` directory.

View File

@@ -32,7 +32,7 @@ image as a service. Since there is no database available, one can be initialized
Create a directory for `data` and `config` then paste the following content into a file named `docker-compose.yml`.
Note that the volume should be owned by the user/group with the UID/GID specified in the config file. By default Gitea in docker will use uid:1000 gid:1000. If needed you can set ownership on those folders with the command: `sudo chown 1000:1000 config/ data/`
If you don't give the volume correct permissions, the container may not start.
For a stable release you could use `:latest-rootless`, `:1-rootless` or specify a certain release like `:{{< version >}}-rootless`, but if you'd like to use the latest development version then `:dev-rootless` would be an appropriate tag. If you'd like to run the latest commit from a release branch you can use the `:1.x-dev-rootless` tag, where x is the minor version of Gitea. (e.g. `:1.16-dev-rootless`)
For a stable release you could use `:latest-rootless`, `:1-rootless` or specify a certain release like `:{{< version >}}-rootless`, but if you'd like to use the latest development version then `:dev-rootless` would be an appropriate tag.
```yaml
version: "2"

View File

@@ -34,7 +34,7 @@ image as a service. Since there is no database available, one can be initialized
Create a directory like `gitea` and paste the following content into a file named `docker-compose.yml`.
Note that the volume should be owned by the user/group with the UID/GID specified in the config file.
If you don't give the volume correct permissions, the container may not start.
For a stable release you can use `:latest`, `:1` or specify a certain release like `:{{< version >}}`, but if you'd like to use the latest development version of Gitea then you could use the `:dev` tag. If you'd like to run the latest commit from a release branch you can use the `:1.x-dev` tag, where x is the minor version of Gitea. (e.g. `:1.16-dev`)
For a stable release you can use `:latest`, `:1` or specify a certain release like `:{{< version >}}`, but if you'd like to use the latest development version of Gitea then you could use the `:dev` tag.
```yaml
version: "3"

156
go.mod
View File

@@ -3,30 +3,41 @@ module code.gitea.io/gitea
go 1.16
require (
cloud.google.com/go v0.78.0 // indirect
code.gitea.io/gitea-vet v0.2.1
code.gitea.io/sdk/gitea v0.15.1
gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb
gitea.com/go-chi/binding v0.0.0-20211013065440-d16dc407c2be
gitea.com/go-chi/cache v0.0.0-20211013020926-78790b11abf1
gitea.com/go-chi/captcha v0.0.0-20211013065431-70641c1a35d5
gitea.com/go-chi/session v0.0.0-20211218221615-e3605d8b28b8
gitea.com/lunny/levelqueue v0.4.1
github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121
github.com/Microsoft/go-winio v0.5.0 // indirect
github.com/NYTimes/gziphandler v1.1.1
github.com/PuerkitoBio/goquery v1.8.0
github.com/alecthomas/chroma v0.10.0
github.com/blevesearch/bleve/v2 v2.3.1
github.com/caddyserver/certmagic v0.15.4
github.com/ProtonMail/go-crypto v0.0.0-20210705153151-cc34b1f6908b // indirect
github.com/PuerkitoBio/goquery v1.7.0
github.com/alecthomas/chroma v0.9.4
github.com/andybalholm/brotli v1.0.3 // indirect
github.com/andybalholm/cascadia v1.2.0 // indirect
github.com/blevesearch/bleve/v2 v2.3.0
github.com/boombuler/barcode v1.0.1 // indirect
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect
github.com/caddyserver/certmagic v0.15.2
github.com/chi-middleware/proxy v1.1.1
github.com/denisenkom/go-mssqldb v0.12.0
github.com/couchbase/go-couchbase v0.0.0-20210224140812-5740cd35f448 // indirect
github.com/couchbase/gomemcached v0.1.2 // indirect
github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401 // indirect
github.com/denisenkom/go-mssqldb v0.10.0
github.com/djherbis/buffer v1.2.0
github.com/djherbis/nio/v3 v3.0.1
github.com/duo-labs/webauthn v0.0.0-20220122034320-81aea484c951
github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b
github.com/dustin/go-humanize v1.0.0
github.com/editorconfig/editorconfig-core-go/v2 v2.4.2
github.com/emirpasic/gods v1.12.0
github.com/ethantkoenig/rupture v1.0.0
github.com/gliderlabs/ssh v0.3.3
github.com/go-chi/chi/v5 v5.0.7
github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect
github.com/go-chi/chi/v5 v5.0.4
github.com/go-chi/cors v1.2.0
github.com/go-enry/go-enry/v2 v2.7.1
github.com/go-git/go-billy/v5 v5.3.1
@@ -40,65 +51,87 @@ require (
github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
github.com/golang-jwt/jwt/v4 v4.3.0
github.com/golang-jwt/jwt/v4 v4.2.0
github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-github/v39 v39.2.0
github.com/google/uuid v1.3.0
github.com/google/uuid v1.2.0
github.com/gorilla/feeds v1.1.1
github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/sessions v1.2.1
github.com/hashicorp/go-version v1.4.0
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
github.com/hashicorp/go-version v1.3.1
github.com/hashicorp/golang-lru v0.5.4
github.com/huandu/xstrings v1.3.2
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7
github.com/json-iterator/go v1.1.12
github.com/json-iterator/go v1.1.11
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/kevinburke/ssh_config v1.1.0 // indirect
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4
github.com/klauspost/compress v1.13.6
github.com/klauspost/compress v1.13.1
github.com/klauspost/cpuid/v2 v2.0.9
github.com/klauspost/pgzip v1.2.5 // indirect
github.com/lib/pq v1.10.2
github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96
github.com/markbates/goth v1.69.0
github.com/mattn/go-isatty v0.0.14
github.com/mattn/go-sqlite3 v1.14.12
github.com/mholt/archiver/v3 v3.5.1
github.com/microcosm-cc/bluemonday v1.0.18
github.com/minio/minio-go/v7 v7.0.23
github.com/msteinert/pam v1.0.0
github.com/markbates/goth v1.68.0
github.com/mattn/go-isatty v0.0.13
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mattn/go-sqlite3 v1.14.8
github.com/mholt/archiver/v3 v3.5.0
github.com/microcosm-cc/bluemonday v1.0.16
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/minio-go/v7 v7.0.12
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect
github.com/msteinert/pam v0.0.0-20201130170657-e61372126161
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
github.com/niklasfasching/go-org v1.6.2
github.com/niklasfasching/go-org v1.5.0
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/oliamb/cutter v0.2.2
github.com/olivere/elastic/v7 v7.0.31
github.com/olivere/elastic/v7 v7.0.25
github.com/pelletier/go-toml v1.9.0 // indirect
github.com/pierrec/lz4/v4 v4.1.8 // indirect
github.com/pkg/errors v0.9.1
github.com/pquerna/otp v1.3.0
github.com/prometheus/client_golang v1.12.1
github.com/quasoft/websspi v1.1.2
github.com/prometheus/client_golang v1.11.0
github.com/quasoft/websspi v1.0.0
github.com/rs/xid v1.3.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sergi/go-diff v1.2.0
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
github.com/stretchr/testify v1.7.0
github.com/syndtr/goleveldb v1.0.0
github.com/tstranex/u2f v1.0.0
github.com/ulikunitz/xz v0.5.10 // indirect
github.com/unknwon/com v1.0.1
github.com/unknwon/i18n v0.0.0-20210321134014-0ebbf2df1c44
github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae
github.com/unrolled/render v1.4.0
github.com/urfave/cli v1.22.5
github.com/xanzy/go-gitlab v0.58.0
github.com/xanzy/go-gitlab v0.50.1
github.com/yohcop/openid-go v1.0.0
github.com/yuin/goldmark v1.4.11
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594
github.com/yuin/goldmark-meta v1.1.0
github.com/yuin/goldmark v1.4.0
github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01
github.com/yuin/goldmark-meta v1.0.0
go.etcd.io/bbolt v1.3.6 // indirect
go.jolheiser.com/hcaptcha v0.0.4
go.jolheiser.com/pwn v0.0.3
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.21.0 // indirect
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9
go.uber.org/multierr v1.7.0 // indirect
go.uber.org/zap v1.19.0 // indirect
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1
golang.org/x/text v0.3.7
golang.org/x/tools v0.1.9
golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 // indirect
golang.org/x/tools v0.1.0
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gopkg.in/ini.v1 v1.66.2
gopkg.in/ini.v1 v1.62.0
gopkg.in/yaml.v2 v2.4.0
mvdan.cc/xurls/v2 v2.2.0
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
@@ -106,61 +139,14 @@ require (
xorm.io/xorm v1.2.5
)
require (
github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f // indirect
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/bits-and-blooms/bitset v1.2.1 // indirect
github.com/boombuler/barcode v1.0.1 // indirect
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect
github.com/cloudflare/cfssl v1.6.1 // indirect
github.com/couchbase/go-couchbase v0.0.0-20210224140812-5740cd35f448 // indirect
github.com/couchbase/gomemcached v0.1.2 // indirect
github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401 // indirect
github.com/felixge/httpsnoop v1.0.2 // indirect
github.com/fxamacker/cbor/v2 v2.4.0 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect
github.com/go-openapi/analysis v0.21.2 // indirect
github.com/go-openapi/errors v0.20.2 // indirect
github.com/go-openapi/runtime v0.21.1 // indirect
github.com/go-openapi/strfmt v0.21.1 // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
github.com/kevinburke/ssh_config v1.1.0 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mholt/acmez v1.0.2 // indirect
github.com/miekg/dns v1.1.46 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect
github.com/nwaples/rardecode v1.1.3 // indirect
github.com/pierrec/lz4/v4 v4.1.14 // indirect
github.com/rogpeppe/go-internal v1.8.1 // indirect
github.com/rs/xid v1.3.0 // indirect
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect
github.com/spf13/afero v1.8.0 // indirect
github.com/spf13/cobra v1.3.0 // indirect
github.com/spf13/viper v1.10.1 // indirect
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
github.com/ulikunitz/xz v0.5.10 // indirect
github.com/xanzy/ssh-agent v0.3.1 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
go.mongodb.org/mongo-driver v1.8.2 // indirect
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
)
replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1
replace github.com/markbates/goth v1.68.0 => github.com/zeripath/goth v1.68.1-0.20220109111530-754359885dce
replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0
replace github.com/duo-labs/webauthn => github.com/authelia/webauthn v0.0.0-20211225121951-80d1f2a572e4
replace github.com/satori/go.uuid v1.2.0 => github.com/gofrs/uuid v4.2.0+incompatible
exclude github.com/gofrs/uuid v3.2.0+incompatible

876
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,6 @@ import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"os"
"testing"
@@ -263,26 +262,23 @@ func doAPIMergePullRequest(ctx APITestContext, owner, repo string, index int64)
return func(t *testing.T) {
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/merge?token=%s",
owner, repo, index, ctx.Token)
req := NewRequestWithJSON(t, http.MethodPost, urlStr, &forms.MergePullRequestForm{
MergeMessageField: "doAPIMergePullRequest Merge",
Do: string(repo_model.MergeStyleMerge),
})
var req *http.Request
var resp *httptest.ResponseRecorder
resp := ctx.Session.MakeRequest(t, req, NoExpectedStatus)
for i := 0; i < 6; i++ {
req = NewRequestWithJSON(t, http.MethodPost, urlStr, &forms.MergePullRequestForm{
MergeMessageField: "doAPIMergePullRequest Merge",
Do: string(repo_model.MergeStyleMerge),
})
resp = ctx.Session.MakeRequest(t, req, NoExpectedStatus)
if resp.Code != http.StatusMethodNotAllowed {
break
}
if resp.Code == http.StatusMethodNotAllowed {
err := api.APIError{}
DecodeJSON(t, resp, &err)
assert.EqualValues(t, "Please try again later", err.Message)
queue.GetManager().FlushAll(context.Background(), 5*time.Second)
<-time.After(1 * time.Second)
req = NewRequestWithJSON(t, http.MethodPost, urlStr, &forms.MergePullRequestForm{
MergeMessageField: "doAPIMergePullRequest Merge",
Do: string(repo_model.MergeStyleMerge),
})
resp = ctx.Session.MakeRequest(t, req, NoExpectedStatus)
}
expected := ctx.ExpectedCode

View File

@@ -47,7 +47,7 @@ func TestAPIPrivateServ(t *testing.T) {
results, err := private.ServCommand(ctx, 1, "user2", "repo1", perm.AccessModeWrite, "git-upload-pack", "")
assert.NoError(t, err)
assert.False(t, results.IsWiki)
assert.Zero(t, results.DeployKeyID)
assert.False(t, results.IsDeployKey)
assert.Equal(t, int64(1), results.KeyID)
assert.Equal(t, "user2@localhost", results.KeyName)
assert.Equal(t, "user2", results.UserName)
@@ -70,7 +70,7 @@ func TestAPIPrivateServ(t *testing.T) {
results, err = private.ServCommand(ctx, 1, "user15", "big_test_public_1", perm.AccessModeRead, "git-upload-pack", "")
assert.NoError(t, err)
assert.False(t, results.IsWiki)
assert.Zero(t, results.DeployKeyID)
assert.False(t, results.IsDeployKey)
assert.Equal(t, int64(1), results.KeyID)
assert.Equal(t, "user2@localhost", results.KeyName)
assert.Equal(t, "user2", results.UserName)
@@ -92,7 +92,7 @@ func TestAPIPrivateServ(t *testing.T) {
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeRead, "git-upload-pack", "")
assert.NoError(t, err)
assert.False(t, results.IsWiki)
assert.NotZero(t, results.DeployKeyID)
assert.True(t, results.IsDeployKey)
assert.Equal(t, deployKey.KeyID, results.KeyID)
assert.Equal(t, "test-deploy", results.KeyName)
assert.Equal(t, "user15", results.UserName)
@@ -129,7 +129,7 @@ func TestAPIPrivateServ(t *testing.T) {
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeRead, "git-upload-pack", "")
assert.NoError(t, err)
assert.False(t, results.IsWiki)
assert.NotZero(t, results.DeployKeyID)
assert.True(t, results.IsDeployKey)
assert.Equal(t, deployKey.KeyID, results.KeyID)
assert.Equal(t, "test-deploy", results.KeyName)
assert.Equal(t, "user15", results.UserName)
@@ -142,7 +142,7 @@ func TestAPIPrivateServ(t *testing.T) {
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeWrite, "git-upload-pack", "")
assert.NoError(t, err)
assert.False(t, results.IsWiki)
assert.NotZero(t, results.DeployKeyID)
assert.True(t, results.IsDeployKey)
assert.Equal(t, deployKey.KeyID, results.KeyID)
assert.Equal(t, "test-deploy", results.KeyName)
assert.Equal(t, "user15", results.UserName)

View File

@@ -445,6 +445,7 @@ func TestAPIRepoTransfer(t *testing.T) {
expectedStatus int
}{
// Disclaimer for test story: "user1" is an admin, "user2" is normal user and part of in owner team of org "user3"
// Transfer to a user with teams in another org should fail
{ctxUserID: 1, newOwner: "user3", teams: &[]int64{5}, expectedStatus: http.StatusForbidden},
// Transfer to a user with non-existent team IDs should fail

View File

@@ -69,12 +69,6 @@ func TestAPIAddEmail(t *testing.T) {
Primary: false,
},
}, emails)
opts = api.CreateEmailOption{
Emails: []string{"notAEmail"},
}
req = NewRequestWithJSON(t, "POST", "/api/v1/user/emails?token="+token, &opts)
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
}
func TestAPIDeleteEmail(t *testing.T) {

View File

@@ -123,17 +123,6 @@ func doGitClone(dstLocalPath string, u *url.URL) func(*testing.T) {
}
}
func doPartialGitClone(dstLocalPath string, u *url.URL) func(*testing.T) {
return func(t *testing.T) {
assert.NoError(t, git.CloneWithArgs(context.Background(), u.String(), dstLocalPath, allowLFSFilters(), git.CloneRepoOptions{
Filter: "blob:none",
}))
exist, err := util.IsExist(filepath.Join(dstLocalPath, "README.md"))
assert.NoError(t, err)
assert.True(t, exist)
}
}
func doGitCloneFail(u *url.URL) func(*testing.T) {
return func(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "doGitCloneFail")

View File

@@ -69,12 +69,6 @@ func testGit(t *testing.T, u *url.URL) {
t.Run("Clone", doGitClone(dstPath, u))
dstPath2, err := os.MkdirTemp("", httpContext.Reponame)
assert.NoError(t, err)
defer util.RemoveAll(dstPath2)
t.Run("Partial Clone", doPartialGitClone(dstPath2, u))
little, big := standardCommitAndPushTest(t, dstPath)
littleLFS, bigLFS := lfsCommitAndPushTest(t, dstPath)
rawTest(t, &httpContext, little, big, littleLFS, bigLFS)

View File

@@ -83,7 +83,7 @@ PROVIDER_CONFIG = integrations/gitea-integration-mssql/data/sessions
[log]
MODE = test,file
ROOT_PATH = {{REPO_TEST_DIR}}mssql-log
ROOT_PATH = mssql-log
ROUTER = ,
XORM = file
ENABLE_SSH_LOG = true

View File

@@ -101,7 +101,7 @@ PROVIDER_CONFIG = integrations/gitea-integration-mysql/data/sessions
[log]
MODE = test,file
ROOT_PATH = {{REPO_TEST_DIR}}mysql-log
ROOT_PATH = mysql-log
ROUTER = ,
XORM = file
ENABLE_SSH_LOG = true

View File

@@ -80,7 +80,7 @@ PROVIDER_CONFIG = integrations/gitea-integration-mysql8/data/sessions
[log]
MODE = test,file
ROOT_PATH = {{REPO_TEST_DIR}}mysql8-log
ROOT_PATH = mysql8-log
ROUTER = ,
XORM = file
ENABLE_SSH_LOG = true

View File

@@ -84,7 +84,7 @@ PROVIDER_CONFIG = integrations/gitea-integration-pgsql/data/sessions
[log]
MODE = test,file
ROOT_PATH = {{REPO_TEST_DIR}}pgsql-log
ROOT_PATH = pgsql-log
ROUTER = ,
XORM = file
ENABLE_SSH_LOG = true

View File

@@ -51,6 +51,8 @@ func TestSignin(t *testing.T) {
{username: "wrongUsername", password: "password", message: i18n.Tr("en", "form.username_password_incorrect")},
{username: "user15", password: "wrongPassword", message: i18n.Tr("en", "form.username_password_incorrect")},
{username: "user1@example.com", password: "wrongPassword", message: i18n.Tr("en", "form.username_password_incorrect")},
// test for duplicate email
{username: "user2@example.com", password: "password", message: i18n.Tr("en", "form.email_been_used")},
}
for _, s := range samples {

View File

@@ -79,7 +79,7 @@ PROVIDER_CONFIG = integrations/gitea-integration-sqlite/data/sessions
[log]
MODE = test,file
ROOT_PATH = {{REPO_TEST_DIR}}sqlite-log
ROOT_PATH = sqlite-log
ROUTER = ,
XORM = file
ENABLE_SSH_LOG = true

View File

@@ -71,7 +71,7 @@ const (
)
// ParseCommitsWithSignature checks if signaute of commits are corresponding to users gpg keys.
func ParseCommitsWithSignature(oldCommits []*user_model.UserCommit, repoTrustModel repo_model.TrustModelType, isOwnerMemberCollaborator func(*user_model.User) (bool, error)) []*SignCommit {
func ParseCommitsWithSignature(oldCommits []*user_model.UserCommit, repoTrustModel repo_model.TrustModelType, isCodeReader func(*user_model.User) (bool, error)) []*SignCommit {
newCommits := make([]*SignCommit, 0, len(oldCommits))
keyMap := map[string]bool{}
@@ -81,7 +81,7 @@ func ParseCommitsWithSignature(oldCommits []*user_model.UserCommit, repoTrustMod
Verification: ParseCommitWithSignature(c.Commit),
}
_ = CalculateTrustStatus(signCommit.Verification, repoTrustModel, isOwnerMemberCollaborator, &keyMap)
_ = CalculateTrustStatus(signCommit.Verification, repoTrustModel, isCodeReader, &keyMap)
newCommits = append(newCommits, signCommit)
}
@@ -455,7 +455,7 @@ func hashAndVerifyForKeyID(sig *packet.Signature, payload string, committer *use
// CalculateTrustStatus will calculate the TrustStatus for a commit verification within a repository
// There are several trust models in Gitea
func CalculateTrustStatus(verification *CommitVerification, repoTrustModel repo_model.TrustModelType, isOwnerMemberCollaborator func(*user_model.User) (bool, error), keyMap *map[string]bool) (err error) {
func CalculateTrustStatus(verification *CommitVerification, repoTrustModel repo_model.TrustModelType, isCodeReader func(*user_model.User) (bool, error), keyMap *map[string]bool) (err error) {
if !verification.Verified {
return
}
@@ -500,11 +500,11 @@ func CalculateTrustStatus(verification *CommitVerification, repoTrustModel repo_
var has bool
isMember, has = (*keyMap)[verification.SigningKey.KeyID]
if !has {
isMember, err = isOwnerMemberCollaborator(verification.SigningUser)
isMember, err = isCodeReader(verification.SigningUser)
(*keyMap)[verification.SigningKey.KeyID] = isMember
}
} else {
isMember, err = isOwnerMemberCollaborator(verification.SigningUser)
isMember, err = isCodeReader(verification.SigningUser)
}
if !isMember {

View File

@@ -58,7 +58,7 @@ func (key *DeployKey) GetContent() error {
return nil
}
// IsReadOnly checks if the key can only be used for read operations, used by template
// IsReadOnly checks if the key can only be used for read operations
func (key *DeployKey) IsReadOnly() bool {
return key.Mode == perm.AccessModeRead
}
@@ -203,6 +203,12 @@ func UpdateDeployKeyCols(key *DeployKey, cols ...string) error {
return err
}
// UpdateDeployKey updates deploy key information.
func UpdateDeployKey(key *DeployKey) error {
_, err := db.GetEngine(db.DefaultContext).ID(key.ID).AllCols().Update(key)
return err
}
// ListDeployKeysOptions are options for ListDeployKeys
type ListDeployKeysOptions struct {
db.ListOptions

View File

@@ -43,7 +43,7 @@ type WebAuthnCredential struct {
Name string
LowerName string `xorm:"unique(s)"`
UserID int64 `xorm:"INDEX unique(s)"`
CredentialID string `xorm:"INDEX VARCHAR(410)"`
CredentialID string `xorm:"INDEX"`
PublicKey []byte
AttestationType string
AAGUID []byte

View File

@@ -18,7 +18,7 @@ func ConvertFromGitCommit(commits []*git.Commit, repo *repo_model.Repository) []
user_model.ValidateCommitsWithEmails(commits),
repo.GetTrustModel(),
func(user *user_model.User) (bool, error) {
return IsOwnerMemberCollaborator(repo, user.ID)
return IsUserRepoAdmin(repo, user)
},
),
repo,

View File

@@ -23,8 +23,8 @@ const (
EnvPusherName = "GITEA_PUSHER_NAME"
EnvPusherEmail = "GITEA_PUSHER_EMAIL"
EnvPusherID = "GITEA_PUSHER_ID"
EnvKeyID = "GITEA_KEY_ID" // public key ID
EnvDeployKeyID = "GITEA_DEPLOY_KEY_ID"
EnvKeyID = "GITEA_KEY_ID"
EnvIsDeployKey = "GITEA_IS_DEPLOY_KEY"
EnvPRID = "GITEA_PR_ID"
EnvIsInternal = "GITEA_INTERNAL_PUSH"
EnvAppURL = "GITEA_ROOT_URL"

View File

@@ -1238,7 +1238,7 @@ func sortIssuesSession(sess *xorm.Session, sortType string, priorityRepoID int64
}
}
func (opts *IssuesOptions) setupSessionWithLimit(sess *xorm.Session) {
func (opts *IssuesOptions) setupSession(sess *xorm.Session) {
if opts.Page >= 0 && opts.PageSize > 0 {
var start int
if opts.Page == 0 {
@@ -1248,10 +1248,7 @@ func (opts *IssuesOptions) setupSessionWithLimit(sess *xorm.Session) {
}
sess.Limit(opts.PageSize, start)
}
opts.setupSessionNoLimit(sess)
}
func (opts *IssuesOptions) setupSessionNoLimit(sess *xorm.Session) {
if len(opts.IssueIDs) > 0 {
sess.In("issue.id", opts.IssueIDs)
}
@@ -1417,7 +1414,7 @@ func CountIssuesByRepo(opts *IssuesOptions) (map[int64]int64, error) {
sess := e.Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
opts.setupSessionNoLimit(sess)
opts.setupSession(sess)
countsSlice := make([]*struct {
RepoID int64
@@ -1427,7 +1424,7 @@ func CountIssuesByRepo(opts *IssuesOptions) (map[int64]int64, error) {
Select("issue.repo_id AS repo_id, COUNT(*) AS count").
Table("issue").
Find(&countsSlice); err != nil {
return nil, fmt.Errorf("unable to CountIssuesByRepo: %w", err)
return nil, err
}
countMap := make(map[int64]int64, len(countsSlice))
@@ -1444,14 +1441,14 @@ func GetRepoIDsForIssuesOptions(opts *IssuesOptions, user *user_model.User) ([]i
sess := e.Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
opts.setupSessionNoLimit(sess)
opts.setupSession(sess)
accessCond := accessibleRepositoryCondition(user)
if err := sess.Where(accessCond).
Distinct("issue.repo_id").
Table("issue").
Find(&repoIDs); err != nil {
return nil, fmt.Errorf("unable to GetRepoIDsForIssuesOptions: %w", err)
return nil, err
}
return repoIDs, nil
@@ -1462,16 +1459,17 @@ func Issues(opts *IssuesOptions) ([]*Issue, error) {
e := db.GetEngine(db.DefaultContext)
sess := e.Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
opts.setupSessionWithLimit(sess)
opts.setupSession(sess)
sortIssuesSession(sess, opts.SortType, opts.PriorityRepoID)
issues := make([]*Issue, 0, opts.ListOptions.PageSize)
if err := sess.Find(&issues); err != nil {
return nil, fmt.Errorf("unable to query Issues: %w", err)
return nil, fmt.Errorf("Find: %v", err)
}
sess.Close()
if err := IssueList(issues).LoadAttributes(); err != nil {
return nil, fmt.Errorf("unable to LoadAttributes for Issues: %w", err)
return nil, fmt.Errorf("LoadAttributes: %v", err)
}
return issues, nil
@@ -1482,17 +1480,18 @@ func CountIssues(opts *IssuesOptions) (int64, error) {
e := db.GetEngine(db.DefaultContext)
countsSlice := make([]*struct {
Count int64
RepoID int64
Count int64
}, 0, 1)
sess := e.Select("COUNT(issue.id) AS count").Table("issue")
sess.Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
opts.setupSessionNoLimit(sess)
opts.setupSession(sess)
if err := sess.Find(&countsSlice); err != nil {
return 0, fmt.Errorf("unable to CountIssues: %w", err)
return 0, fmt.Errorf("Find: %v", err)
}
if len(countsSlice) != 1 {
return 0, fmt.Errorf("unable to get one row result when CountIssues, row count=%d", len(countsSlice))
if len(countsSlice) < 1 {
return 0, fmt.Errorf("there is less than one result sql record")
}
return countsSlice[0].Count, nil
}
@@ -1552,7 +1551,6 @@ const (
FilterModeCreate
FilterModeMention
FilterModeReviewRequested
FilterModeYourRepositories
)
func parseCountResult(results []map[string][]byte) int64 {
@@ -1697,7 +1695,6 @@ type UserIssueStatsOptions struct {
IssueIDs []int64
IsArchived util.OptionalBool
LabelIDs []int64
RepoCond builder.Cond
Org *Organization
Team *Team
}
@@ -1715,9 +1712,6 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
if len(opts.IssueIDs) > 0 {
cond = cond.And(builder.In("issue.id", opts.IssueIDs))
}
if opts.RepoCond != nil {
cond = cond.And(opts.RepoCond)
}
if opts.UserID > 0 {
cond = cond.And(issuePullAccessibleRepoCond("issue.repo_id", opts.UserID, opts.Org, opts.Team, opts.IsPull))
@@ -1739,7 +1733,7 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
}
switch opts.FilterMode {
case FilterModeAll, FilterModeYourRepositories:
case FilterModeAll:
stats.OpenCount, err = sess(cond).
And("issue.is_closed = ?", false).
Count(new(Issue))

View File

@@ -134,6 +134,22 @@ func GetMilestoneByRepoIDANDName(repoID int64, name string) (*Milestone, error)
return &mile, nil
}
// GetMilestoneByID returns the milestone via id .
func GetMilestoneByID(id int64) (*Milestone, error) {
return getMilestoneByID(db.GetEngine(db.DefaultContext), id)
}
func getMilestoneByID(e db.Engine, id int64) (*Milestone, error) {
var m Milestone
has, err := e.ID(id).Get(&m)
if err != nil {
return nil, err
} else if !has {
return nil, ErrMilestoneNotExist{ID: id, RepoID: 0}
}
return &m, nil
}
// UpdateMilestone updates information of given milestone.
func UpdateMilestone(m *Milestone, oldIsClosed bool) error {
ctx, committer, err := db.TxContext()

View File

@@ -137,7 +137,6 @@ func QueryIssueContentHistoryEditedCountMap(dbCtx context.Context, issueID int64
type IssueContentListItem struct {
UserID int64
UserName string
UserFullName string
UserAvatarLink string
HistoryID int64
@@ -149,7 +148,7 @@ type IssueContentListItem struct {
// FetchIssueContentHistoryList fetch list
func FetchIssueContentHistoryList(dbCtx context.Context, issueID, commentID int64) ([]*IssueContentListItem, error) {
res := make([]*IssueContentListItem, 0)
err := db.GetEngine(dbCtx).Select("u.id as user_id, u.name as user_name, u.full_name as user_full_name,"+
err := db.GetEngine(dbCtx).Select("u.id as user_id, u.name as user_name,"+
"h.id as history_id, h.edited_unix, h.is_first_created, h.is_deleted").
Table([]string{"issue_content_history", "h"}).
Join("LEFT", []string{"user", "u"}, "h.poster_id = u.id").

View File

@@ -43,9 +43,8 @@ func TestContentHistory(t *testing.T) {
when the refactor of models are done, this test will be possible to be run then with a real `User` model.
*/
type User struct {
ID int64
Name string
FullName string
ID int64
Name string
}
_ = dbEngine.Sync2(&User{})

View File

@@ -193,13 +193,12 @@ func LFSAutoAssociate(metas []*LFSMetaObject, user *user_model.User, repoID int6
// admin can associate any LFS object to any repository, and we do not care about errors (eg: duplicated unique key),
// even if error occurs, it won't hurt users and won't make things worse
for i := range metas {
p := lfs.Pointer{Oid: metas[i].Oid, Size: metas[i].Size}
_, err = sess.Insert(&LFSMetaObject{
Pointer: p,
Pointer: lfs.Pointer{Oid: metas[i].Oid, Size: metas[i].Size},
RepositoryID: repoID,
})
if err != nil {
log.Warn("failed to insert LFS meta object %-v for repo_id: %d into database, err=%v", p, repoID, err)
log.Warn("failed to insert LFS meta object into database, err=%v", err)
}
}
}

View File

@@ -52,6 +52,10 @@ func InsertIssues(issues ...*Issue) error {
return err
}
}
err = UpdateRepoStats(ctx, issues[0].RepoID)
if err != nil {
return err
}
return committer.Commit()
}
@@ -143,6 +147,11 @@ func InsertPullRequests(prs ...*PullRequest) error {
return err
}
}
err = UpdateRepoStats(ctx, prs[0].Issue.RepoID)
if err != nil {
return err
}
return committer.Commit()
}

View File

@@ -32,9 +32,8 @@ func TestMigrate_InsertMilestones(t *testing.T) {
unittest.CheckConsistencyFor(t, &Milestone{})
}
func assertCreateIssues(t *testing.T, isPull bool) {
func assertCreateIssues(t *testing.T, reponame string, isPull bool) {
assert.NoError(t, unittest.PrepareTestDatabase())
reponame := "repo1"
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame}).(*repo_model.Repository)
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
label := unittest.AssertExistsAndLoadBean(t, &Label{ID: 1}).(*Label)
@@ -64,14 +63,38 @@ func assertCreateIssues(t *testing.T, isPull bool) {
i := unittest.AssertExistsAndLoadBean(t, &Issue{Title: title}).(*Issue)
unittest.AssertExistsAndLoadBean(t, &Reaction{Type: "heart", UserID: owner.ID, IssueID: i.ID})
labelModified := unittest.AssertExistsAndLoadBean(t, &Label{ID: 1}).(*Label)
assert.EqualValues(t, label.NumIssues+1, labelModified.NumIssues)
assert.EqualValues(t, label.NumClosedIssues+1, labelModified.NumClosedIssues)
milestoneModified := unittest.AssertExistsAndLoadBean(t, &Milestone{ID: milestone.ID}).(*Milestone)
assert.EqualValues(t, milestone.NumIssues+1, milestoneModified.NumIssues)
assert.EqualValues(t, milestone.NumClosedIssues+1, milestoneModified.NumClosedIssues)
}
func TestMigrate_CreateIssuesIsPullFalse(t *testing.T) {
assertCreateIssues(t, false)
assert.NoError(t, unittest.PrepareTestDatabase())
reponame := "repo1"
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame}).(*repo_model.Repository)
assertCreateIssues(t, reponame, false)
repoModified := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID}).(*repo_model.Repository)
assert.EqualValues(t, repo.NumIssues+1, repoModified.NumIssues)
assert.EqualValues(t, repo.NumClosedIssues+1, repoModified.NumClosedIssues)
}
func TestMigrate_CreateIssuesIsPullTrue(t *testing.T) {
assertCreateIssues(t, true)
assert.NoError(t, unittest.PrepareTestDatabase())
reponame := "repo1"
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame}).(*repo_model.Repository)
assertCreateIssues(t, reponame, true)
repoModified := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID}).(*repo_model.Repository)
assert.EqualValues(t, repo.NumPulls+1, repoModified.NumPulls)
assert.EqualValues(t, repo.NumClosedPulls+1, repoModified.NumClosedPulls)
}
func TestMigrate_InsertIssueComments(t *testing.T) {

View File

@@ -1,12 +0,0 @@
-
id: 1
credential_id: "TVHE44TOH7DF7V48SEAIT3EMMJ7TGBOQ289E5AQB34S98LFCUFJ7U2NAVI8RJG6K2F4TC8AQ8KBNO7AGEOQOL9NE43GR63HTEHJSLOG="
-
id: 2
credential_id: "TVHE44TOH7DF7V48SEAIT3EMMJ7TGBOQ289E5AQB34S98LFCUFJ7U2NAVI8RJG6K2F4TC8AQ8KBNO7AGEOQOL9NE43GR63HTEHJSLOG="
-
id: 3
credential_id: "TVHE44TOH7DF7V48SEAIT3EMMJ7TGBOQ289E5AQB34S98LFCUFJ7U2NAVI8RJG6K2F4TC8AQ8KBNO7AGEOQOL9NE43GR63HTEHJSLOG="
-
id: 4
credential_id: "TVHE44TOH7DF7V48SEAIT3EMMJ7TGBOQ289E5AQB34S98LFCUFJ7U2NAVI8RJG6K2F4TC8AQ8KBNO7AGEOQOL9NE43GR63HTEHJSLOG="

View File

@@ -1,21 +0,0 @@
-
id: 1
name: "u2fkey-correctly-migrated"
user_id: 1
raw: 0x05040d0967a2cad045011631187576492a0beb5b377954b4f694c5afc8bdf25270f87f09a9ab6ce9c282f447ba71b2f2bae2105b32b847e0704f310f48644e3eddf240efe2e213b889daf3fc88e3952e8dd6b4cfd82f1a1212e2ab4b19389455ecf3e67f0aeafc91b9c0d413c9d6215a45177c1d5076358aa6ee20e1b30e3d7467cae2308202bd308201a5a00302010202041e8f8734300d06092a864886f70d01010b0500302e312c302a0603550403132359756269636f2055324620526f6f742043412053657269616c203435373230303633313020170d3134303830313030303030305a180f32303530303930343030303030305a306e310b300906035504061302534531123010060355040a0c0959756269636f20414231223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e3127302506035504030c1e59756269636f205532462045452053657269616c203531323732323734303059301306072a8648ce3d020106082a8648ce3d03010703420004a879f82338ed1494bac0704bcc7fc663d1b271715976243101c7605115d7c1529e281c1c67322d384b5cd55dd3e9818d5fd85c22af326e0c64fc20afe33f2366a36c306a302206092b0601040182c40a020415312e332e362e312e342e312e34313438322e312e373013060b2b0601040182e51c0201010404030204303021060b2b0601040182e51c010104041204102fc0579f811347eab116bb5a8db9202a300c0603551d130101ff04023000300d06092a864886f70d01010b050003820101008693ff62df0d5779d4748d7fc8d10227318a8e580e6a3a57c108e94e03c38568b366894fce5624be4a3efd7f34118b3d993743f792a1989160c8fc9ae0b04e3df9ee15e3e88c04fc82a8dcbf5818e108dcc2968577ae79ff662b94734e3dec4597305d73e6e55ee2beb9cd9678ca0935e533eb638f8e26fabb817cda441fbe9831832ae5f6e2ad992f9ebbdb4c62238b8f8d7ab481d6d3263bcdbf9e4a57550370988ad5813440fa032cadb6723cadd8f8d7ba809f75b43cffa0a5b9add14232ef9d9e14812638233c4ca4a873b9f8ac98e32ba19167606e15909fcddb4a2dffbdae4620249f9a6646ac81e4832d1119febfaa731a882da25a77827d46d190173046022100b579338a44c236d3f214b2e150011a08cf251193ecfae2244edb0a5794e9b301022100fab468862c47d98204d437cf2be8c54a5a4ecd1ebb1c61a6c23da7b9c75f6841
counter: 0
- id: 2
name: "u2fkey-incorrectly-migrated"
user_id: 1
raw: 0x05040d0967a2cad045011631187576492a0beb5b377954b4f694c5afc8bdf25270f87f09a9ab6ce9c282f447ba71b2f2bae2105b32b847e0704f310f48644e3eddf240efe2e213b889daf3fc88e3952e8dd6b4cfd82f1a1212e2ab4b19389455ecf3e67f0aeafc91b9c0d413c9d6215a45177c1d5076358aa6ee20e1b30e3d7467cae2308202bd308201a5a00302010202041e8f8734300d06092a864886f70d01010b0500302e312c302a0603550403132359756269636f2055324620526f6f742043412053657269616c203435373230303633313020170d3134303830313030303030305a180f32303530303930343030303030305a306e310b300906035504061302534531123010060355040a0c0959756269636f20414231223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e3127302506035504030c1e59756269636f205532462045452053657269616c203531323732323734303059301306072a8648ce3d020106082a8648ce3d03010703420004a879f82338ed1494bac0704bcc7fc663d1b271715976243101c7605115d7c1529e281c1c67322d384b5cd55dd3e9818d5fd85c22af326e0c64fc20afe33f2366a36c306a302206092b0601040182c40a020415312e332e362e312e342e312e34313438322e312e373013060b2b0601040182e51c0201010404030204303021060b2b0601040182e51c010104041204102fc0579f811347eab116bb5a8db9202a300c0603551d130101ff04023000300d06092a864886f70d01010b050003820101008693ff62df0d5779d4748d7fc8d10227318a8e580e6a3a57c108e94e03c38568b366894fce5624be4a3efd7f34118b3d993743f792a1989160c8fc9ae0b04e3df9ee15e3e88c04fc82a8dcbf5818e108dcc2968577ae79ff662b94734e3dec4597305d73e6e55ee2beb9cd9678ca0935e533eb638f8e26fabb817cda441fbe9831832ae5f6e2ad992f9ebbdb4c62238b8f8d7ab481d6d3263bcdbf9e4a57550370988ad5813440fa032cadb6723cadd8f8d7ba809f75b43cffa0a5b9add14232ef9d9e14812638233c4ca4a873b9f8ac98e32ba19167606e15909fcddb4a2dffbdae4620249f9a6646ac81e4832d1119febfaa731a882da25a77827d46d190173046022100b579338a44c236d3f214b2e150011a08cf251193ecfae2244edb0a5794e9b301022100fab468862c47d98204d437cf2be8c54a5a4ecd1ebb1c61a6c23da7b9c75f6841
counter: 0
- id: 3
name: "u2fkey-deleted"
user_id: 1
raw: 0x05040d0967a2cad045011631187576492a0beb5b377954b4f694c5afc8bdf25270f87f09a9ab6ce9c282f447ba71b2f2bae2105b32b847e0704f310f48644e3eddf240efe2e213b889daf3fc88e3952e8dd6b4cfd82f1a1212e2ab4b19389455ecf3e67f0aeafc91b9c0d413c9d6215a45177c1d5076358aa6ee20e1b30e3d7467cae2308202bd308201a5a00302010202041e8f8734300d06092a864886f70d01010b0500302e312c302a0603550403132359756269636f2055324620526f6f742043412053657269616c203435373230303633313020170d3134303830313030303030305a180f32303530303930343030303030305a306e310b300906035504061302534531123010060355040a0c0959756269636f20414231223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e3127302506035504030c1e59756269636f205532462045452053657269616c203531323732323734303059301306072a8648ce3d020106082a8648ce3d03010703420004a879f82338ed1494bac0704bcc7fc663d1b271715976243101c7605115d7c1529e281c1c67322d384b5cd55dd3e9818d5fd85c22af326e0c64fc20afe33f2366a36c306a302206092b0601040182c40a020415312e332e362e312e342e312e34313438322e312e373013060b2b0601040182e51c0201010404030204303021060b2b0601040182e51c010104041204102fc0579f811347eab116bb5a8db9202a300c0603551d130101ff04023000300d06092a864886f70d01010b050003820101008693ff62df0d5779d4748d7fc8d10227318a8e580e6a3a57c108e94e03c38568b366894fce5624be4a3efd7f34118b3d993743f792a1989160c8fc9ae0b04e3df9ee15e3e88c04fc82a8dcbf5818e108dcc2968577ae79ff662b94734e3dec4597305d73e6e55ee2beb9cd9678ca0935e533eb638f8e26fabb817cda441fbe9831832ae5f6e2ad992f9ebbdb4c62238b8f8d7ab481d6d3263bcdbf9e4a57550370988ad5813440fa032cadb6723cadd8f8d7ba809f75b43cffa0a5b9add14232ef9d9e14812638233c4ca4a873b9f8ac98e32ba19167606e15909fcddb4a2dffbdae4620249f9a6646ac81e4832d1119febfaa731a882da25a77827d46d190173046022100b579338a44c236d3f214b2e150011a08cf251193ecfae2244edb0a5794e9b301022100fab468862c47d98204d437cf2be8c54a5a4ecd1ebb1c61a6c23da7b9c75f6841
counter: 0
- id: 4
name: "u2fkey-wrong-user-id"
user_id: 2
raw: 0x05040d0967a2cad045011631187576492a0beb5b377954b4f694c5afc8bdf25270f87f09a9ab6ce9c282f447ba71b2f2bae2105b32b847e0704f310f48644e3eddf240efe2e213b889daf3fc88e3952e8dd6b4cfd82f1a1212e2ab4b19389455ecf3e67f0aeafc91b9c0d413c9d6215a45177c1d5076358aa6ee20e1b30e3d7467cae2308202bd308201a5a00302010202041e8f8734300d06092a864886f70d01010b0500302e312c302a0603550403132359756269636f2055324620526f6f742043412053657269616c203435373230303633313020170d3134303830313030303030305a180f32303530303930343030303030305a306e310b300906035504061302534531123010060355040a0c0959756269636f20414231223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e3127302506035504030c1e59756269636f205532462045452053657269616c203531323732323734303059301306072a8648ce3d020106082a8648ce3d03010703420004a879f82338ed1494bac0704bcc7fc663d1b271715976243101c7605115d7c1529e281c1c67322d384b5cd55dd3e9818d5fd85c22af326e0c64fc20afe33f2366a36c306a302206092b0601040182c40a020415312e332e362e312e342e312e34313438322e312e373013060b2b0601040182e51c0201010404030204303021060b2b0601040182e51c010104041204102fc0579f811347eab116bb5a8db9202a300c0603551d130101ff04023000300d06092a864886f70d01010b050003820101008693ff62df0d5779d4748d7fc8d10227318a8e580e6a3a57c108e94e03c38568b366894fce5624be4a3efd7f34118b3d993743f792a1989160c8fc9ae0b04e3df9ee15e3e88c04fc82a8dcbf5818e108dcc2968577ae79ff662b94734e3dec4597305d73e6e55ee2beb9cd9678ca0935e533eb638f8e26fabb817cda441fbe9831832ae5f6e2ad992f9ebbdb4c62238b8f8d7ab481d6d3263bcdbf9e4a57550370988ad5813440fa032cadb6723cadd8f8d7ba809f75b43cffa0a5b9add14232ef9d9e14812638233c4ca4a873b9f8ac98e32ba19167606e15909fcddb4a2dffbdae4620249f9a6646ac81e4832d1119febfaa731a882da25a77827d46d190173046022100b579338a44c236d3f214b2e150011a08cf251193ecfae2244edb0a5794e9b301022100fab468862c47d98204d437cf2be8c54a5a4ecd1ebb1c61a6c23da7b9c75f6841
counter: 0

View File

@@ -1,30 +0,0 @@
-
id: 1
lower_name: "u2fkey-correctly-migrated"
name: "u2fkey-correctly-migrated"
user_id: 1
credential_id: "TVHE44TOH7DF7V48SEAIT3EMMJ7TGBOQ289E5AQB34S98LFCUFJ7U2NAVI8RJG6K2F4TC8AQ8KBNO7AGEOQOL9NE43GR63HTEHJSLOG="
public_key: 0x040d0967a2cad045011631187576492a0beb5b377954b4f694c5afc8bdf25270f87f09a9ab6ce9c282f447ba71b2f2bae2105b32b847e0704f310f48644e3eddf2
attestation_type: 'fido-u2f'
sign_count: 1
clone_warning: false
-
id: 2
lower_name: "u2fkey-incorrectly-migrated"
name: "u2fkey-incorrectly-migrated"
user_id: 1
credential_id: "TVHE44TOH7DF7V48SEAIT3EMMJ7TGBOQ289E5AQB34S98LFCUFJ7U2NAVI8RJG6K2F4TC8A"
public_key: 0x040d0967a2cad045011631187576492a0beb5b377954b4f694c5afc8bdf25270f87f09a9ab6ce9c282f447ba71b2f2bae2105b32b847e0704f310f48644e3eddf2
attestation_type: 'fido-u2f'
sign_count: 1
clone_warning: false
-
id: 4
lower_name: "u2fkey-wrong-user-id"
name: "u2fkey-wrong-user-id"
user_id: 1
credential_id: "THIS SHOULD CHANGE"
public_key: 0x040d0967a2cad045011631187576492a0beb5b377954b4f694c5afc8bdf25270f87f09a9ab6ce9c282f447ba71b2f2bae2105b32b847e0704f310f48644e3eddf2
attestation_type: 'fido-u2f'
sign_count: 1
clone_warning: false

View File

@@ -61,6 +61,7 @@ type Version struct {
// update minDBVersion accordingly
var migrations = []Migration{
// Gitea 1.5.0 ends at v69
// v70 -> v71
NewMigration("add issue_dependencies", addIssueDependencies),
// v71 -> v72
@@ -366,13 +367,9 @@ var migrations = []Migration{
// v206 -> v207
NewMigration("Add authorize column to team_unit table", addAuthorizeColForTeamUnit),
// v207 -> v208
NewMigration("Add webauthn table and migrate u2f data to webauthn - NO-OPED", addWebAuthnCred),
NewMigration("Add webauthn table and migrate u2f data to webauthn", addWebAuthnCred),
// v208 -> v209
NewMigration("Use base32.HexEncoding instead of base64 encoding for cred ID as it is case insensitive - NO-OPED", useBase32HexForCredIDInWebAuthnCredential),
// v209 -> v210
NewMigration("Increase WebAuthentication CredentialID size to 410 - NO-OPED", increaseCredentialIDTo410),
// v210 -> v211
NewMigration("v208 was completely broken - remigrate", remigrateU2FCredentials),
NewMigration("Use base32.HexEncoding instead of base64 encoding for cred ID as it is case insensitive", useBase32HexForCredIDInWebAuthnCredential),
}
// GetCurrentDBVersion returns the current db version
@@ -453,12 +450,9 @@ Please try upgrading to a lower version first (suggested v1.6.4), then upgrade t
// Downgrading Gitea's database version not supported
if int(v-minDBVersion) > len(migrations) {
msg := fmt.Sprintf("Your database (migration version: %d) is for a newer Gita, you can not use the newer database for this old Gitea release (%d).", v, minDBVersion+len(migrations))
msg += "\nGitea will exit to keep your database safe and unchanged. Please use the correct Gitea release, do not change the migration version manually (incorrect manual operation may lose data)."
if !setting.IsProd {
msg += fmt.Sprintf("\nIf you are in development and really know what you're doing, you can force changing the migration version by executing: UPDATE version SET version=%d WHERE id=1;", minDBVersion+len(migrations))
}
_, _ = fmt.Fprintln(os.Stderr, msg)
msg := fmt.Sprintf("Downgrading database version from '%d' to '%d' is not supported and may result in loss of data integrity.\nIf you really know what you're doing, execute `UPDATE version SET version=%d WHERE id=1;`\n",
v, minDBVersion+len(migrations), minDBVersion+len(migrations))
fmt.Fprint(os.Stderr, msg)
log.Fatal(msg)
return nil
}

View File

@@ -5,11 +5,87 @@
package migrations
import (
"crypto/elliptic"
"encoding/base64"
"strings"
"code.gitea.io/gitea/modules/timeutil"
"github.com/tstranex/u2f"
"xorm.io/xorm"
)
func addWebAuthnCred(x *xorm.Engine) error {
// NO-OP Don't migrate here - let v210 do this.
// Create webauthnCredential table
type webauthnCredential struct {
ID int64 `xorm:"pk autoincr"`
Name string
LowerName string `xorm:"unique(s)"`
UserID int64 `xorm:"INDEX unique(s)"`
CredentialID string `xorm:"INDEX"`
PublicKey []byte
AttestationType string
AAGUID []byte
SignCount uint32 `xorm:"BIGINT"`
CloneWarning bool
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
}
if err := x.Sync2(&webauthnCredential{}); err != nil {
return err
}
// Now migrate the old u2f registrations to the new format
type u2fRegistration struct {
ID int64 `xorm:"pk autoincr"`
Name string
UserID int64 `xorm:"INDEX"`
Raw []byte
Counter uint32 `xorm:"BIGINT"`
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
}
var start int
regs := make([]*u2fRegistration, 0, 50)
for {
err := x.OrderBy("id").Limit(50, start).Find(&regs)
if err != nil {
return err
}
for _, reg := range regs {
parsed := new(u2f.Registration)
err = parsed.UnmarshalBinary(reg.Raw)
if err != nil {
continue
}
c := &webauthnCredential{
ID: reg.ID,
Name: reg.Name,
LowerName: strings.ToLower(reg.Name),
UserID: reg.UserID,
CredentialID: base64.RawStdEncoding.EncodeToString(parsed.KeyHandle),
PublicKey: elliptic.Marshal(elliptic.P256(), parsed.PubKey.X, parsed.PubKey.Y),
AttestationType: "fido-u2f",
AAGUID: []byte{},
SignCount: reg.Counter,
}
_, err := x.Insert(c)
if err != nil {
return err
}
}
if len(regs) < 50 {
break
}
start += 50
regs = regs[:0]
}
return nil
}

View File

@@ -5,10 +5,47 @@
package migrations
import (
"encoding/base32"
"encoding/base64"
"xorm.io/xorm"
)
func useBase32HexForCredIDInWebAuthnCredential(x *xorm.Engine) error {
// noop
// Create webauthnCredential table
type webauthnCredential struct {
ID int64 `xorm:"pk autoincr"`
CredentialID string `xorm:"INDEX"`
}
if err := x.Sync2(&webauthnCredential{}); err != nil {
return err
}
var start int
regs := make([]*webauthnCredential, 0, 50)
for {
err := x.OrderBy("id").Limit(50, start).Find(&regs)
if err != nil {
return err
}
for _, reg := range regs {
credID, _ := base64.RawStdEncoding.DecodeString(reg.CredentialID)
reg.CredentialID = base32.HexEncoding.EncodeToString(credID)
_, err := x.Update(reg)
if err != nil {
return err
}
}
if len(regs) < 50 {
break
}
start += 50
regs = regs[:0]
}
return nil
}

View File

@@ -1,17 +0,0 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
import (
"xorm.io/xorm"
)
func increaseCredentialIDTo410(x *xorm.Engine) error {
// no-op
// V208 is badly broken
// So now we have to no-op again.
return nil
}

View File

@@ -1,184 +0,0 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
import (
"crypto/elliptic"
"encoding/base32"
"fmt"
"strings"
"code.gitea.io/gitea/modules/timeutil"
"github.com/tstranex/u2f"
"xorm.io/xorm"
"xorm.io/xorm/schemas"
)
// v208 migration was completely broken
func remigrateU2FCredentials(x *xorm.Engine) error {
// Create webauthnCredential table
type webauthnCredential struct {
ID int64 `xorm:"pk autoincr"`
Name string
LowerName string `xorm:"unique(s)"`
UserID int64 `xorm:"INDEX unique(s)"`
CredentialID string `xorm:"INDEX VARCHAR(410)"` // CredentalID in U2F is at most 255bytes / 5 * 8 = 408 - add a few extra characters for safety
PublicKey []byte
AttestationType string
AAGUID []byte
SignCount uint32 `xorm:"BIGINT"`
CloneWarning bool
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
}
if err := x.Sync2(&webauthnCredential{}); err != nil {
return err
}
switch x.Dialect().URI().DBType {
case schemas.MYSQL:
_, err := x.Exec("ALTER TABLE webauthn_credential MODIFY COLUMN credential_id VARCHAR(410)")
if err != nil {
return err
}
case schemas.ORACLE:
_, err := x.Exec("ALTER TABLE webauthn_credential MODIFY credential_id VARCHAR(410)")
if err != nil {
return err
}
case schemas.MSSQL:
// This column has an index on it. I could write all of the code to attempt to change the index OR
// I could just use recreate table.
sess := x.NewSession()
if err := sess.Begin(); err != nil {
_ = sess.Close()
return err
}
if err := recreateTable(sess, new(webauthnCredential)); err != nil {
_ = sess.Close()
return err
}
if err := sess.Commit(); err != nil {
_ = sess.Close()
return err
}
if err := sess.Close(); err != nil {
return err
}
case schemas.POSTGRES:
_, err := x.Exec("ALTER TABLE webauthn_credential ALTER COLUMN credential_id TYPE VARCHAR(410)")
if err != nil {
return err
}
default:
// SQLite doesn't support ALTER COLUMN, and it already makes String _TEXT_ by default so no migration needed
// nor is there any need to re-migrate
}
exist, err := x.IsTableExist("u2f_registration")
if err != nil {
return err
}
if !exist {
return nil
}
// Now migrate the old u2f registrations to the new format
type u2fRegistration struct {
ID int64 `xorm:"pk autoincr"`
Name string
UserID int64 `xorm:"INDEX"`
Raw []byte
Counter uint32 `xorm:"BIGINT"`
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
}
var start int
regs := make([]*u2fRegistration, 0, 50)
for {
err := x.OrderBy("id").Limit(50, start).Find(&regs)
if err != nil {
return err
}
err = func() error {
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return fmt.Errorf("unable to allow start session. Error: %w", err)
}
if x.Dialect().URI().DBType == schemas.MSSQL {
if _, err := sess.Exec("SET IDENTITY_INSERT `webauthn_credential` ON"); err != nil {
return fmt.Errorf("unable to allow identity insert on webauthn_credential. Error: %w", err)
}
}
for _, reg := range regs {
parsed := new(u2f.Registration)
err = parsed.UnmarshalBinary(reg.Raw)
if err != nil {
continue
}
remigrated := &webauthnCredential{
ID: reg.ID,
Name: reg.Name,
LowerName: strings.ToLower(reg.Name),
UserID: reg.UserID,
CredentialID: base32.HexEncoding.EncodeToString(parsed.KeyHandle),
PublicKey: elliptic.Marshal(elliptic.P256(), parsed.PubKey.X, parsed.PubKey.Y),
AttestationType: "fido-u2f",
AAGUID: []byte{},
SignCount: reg.Counter,
UpdatedUnix: reg.UpdatedUnix,
CreatedUnix: reg.CreatedUnix,
}
has, err := sess.ID(reg.ID).Get(new(webauthnCredential))
if err != nil {
return fmt.Errorf("unable to get webauthn_credential[%d]. Error: %w", reg.ID, err)
}
if !has {
has, err := sess.Where("`lower_name`=?", remigrated.LowerName).And("`user_id`=?", remigrated.UserID).Exist(new(webauthnCredential))
if err != nil {
return fmt.Errorf("unable to check webauthn_credential[lower_name: %s, user_id:%v]. Error: %w", remigrated.LowerName, remigrated.UserID, err)
}
if !has {
_, err = sess.Insert(remigrated)
if err != nil {
return fmt.Errorf("unable to (re)insert webauthn_credential[%d]. Error: %w", reg.ID, err)
}
continue
}
}
_, err = sess.ID(remigrated.ID).AllCols().Update(remigrated)
if err != nil {
return fmt.Errorf("unable to update webauthn_credential[%d]. Error: %w", reg.ID, err)
}
}
return sess.Commit()
}()
if err != nil {
return err
}
if len(regs) < 50 {
break
}
start += 50
regs = regs[:0]
}
if x.Dialect().URI().DBType == schemas.POSTGRES {
if _, err := x.Exec("SELECT setval('webauthn_credential_id_seq', COALESCE((SELECT MAX(id)+1 FROM `webauthn_credential`), 1), false)"); err != nil {
return err
}
}
return nil
}

View File

@@ -1,75 +0,0 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
import (
"testing"
"code.gitea.io/gitea/modules/timeutil"
"github.com/stretchr/testify/assert"
"xorm.io/xorm/schemas"
)
func Test_remigrateU2FCredentials(t *testing.T) {
// Create webauthnCredential table
type WebauthnCredential struct {
ID int64 `xorm:"pk autoincr"`
Name string
LowerName string `xorm:"unique(s)"`
UserID int64 `xorm:"INDEX unique(s)"`
CredentialID string `xorm:"INDEX VARCHAR(410)"` // CredentalID in U2F is at most 255bytes / 5 * 8 = 408 - add a few extra characters for safety
PublicKey []byte
AttestationType string
SignCount uint32 `xorm:"BIGINT"`
CloneWarning bool
}
// Now migrate the old u2f registrations to the new format
type U2fRegistration struct {
ID int64 `xorm:"pk autoincr"`
Name string
UserID int64 `xorm:"INDEX"`
Raw []byte
Counter uint32 `xorm:"BIGINT"`
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
}
type ExpectedWebauthnCredential struct {
ID int64 `xorm:"pk autoincr"`
CredentialID string `xorm:"INDEX VARCHAR(410)"` // CredentalID in U2F is at most 255bytes / 5 * 8 = 408 - add a few extra characters for safety
}
// Prepare and load the testing database
x, deferable := prepareTestEnv(t, 0, new(WebauthnCredential), new(U2fRegistration), new(ExpectedWebauthnCredential))
if x == nil || t.Failed() {
defer deferable()
return
}
defer deferable()
if x.Dialect().URI().DBType == schemas.SQLITE {
return
}
// Run the migration
if err := remigrateU2FCredentials(x); err != nil {
assert.NoError(t, err)
return
}
expected := []ExpectedWebauthnCredential{}
if err := x.Table("expected_webauthn_credential").Asc("id").Find(&expected); !assert.NoError(t, err) {
return
}
got := []ExpectedWebauthnCredential{}
if err := x.Table("webauthn_credential").Select("id, credential_id").Asc("id").Find(&got); !assert.NoError(t, err) {
return
}
assert.EqualValues(t, expected, got)
}

View File

@@ -498,15 +498,14 @@ func (n *Notification) APIURL() string {
type NotificationList []*Notification
// LoadAttributes load Repo Issue User and Comment if not loaded
func (nl NotificationList) LoadAttributes() error {
var err error
func (nl NotificationList) LoadAttributes() (err error) {
for i := 0; i < len(nl); i++ {
err = nl[i].LoadAttributes()
if err != nil && !IsErrCommentNotExist(err) {
return err
return
}
}
return nil
return
}
func (nl NotificationList) getPendingRepoIDs() []int64 {

View File

@@ -19,7 +19,6 @@ import (
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"
"xorm.io/builder"
)
@@ -50,67 +49,22 @@ func init() {
db.RegisterModel(new(TeamUnit))
}
// SearchOrgTeamOptions holds the search options
type SearchOrgTeamOptions struct {
// SearchTeamOptions holds the search options
type SearchTeamOptions struct {
db.ListOptions
UserID int64
Keyword string
OrgID int64
IncludeDesc bool
}
// GetUserTeamOptions holds the search options.
type GetUserTeamOptions struct {
db.ListOptions
UserID int64
}
// SearchMembersOptions holds the search options
type SearchMembersOptions struct {
db.ListOptions
}
// GetUserTeams search for org teams. Caller is responsible to check permissions.
func GetUserTeams(opts *GetUserTeamOptions) ([]*Team, int64, error) {
if opts.Page <= 0 {
opts.Page = 1
}
if opts.PageSize == 0 {
// Default limit
opts.PageSize = 10
}
sess := db.GetEngine(db.DefaultContext)
sess = sess.Join("INNER", "team_user", "team_user.team_id = team.id").
And("team_user.uid=?", opts.UserID)
count, err := sess.
Count(new(Team))
if err != nil {
return nil, 0, err
}
if opts.PageSize == -1 {
opts.PageSize = int(count)
} else {
sess = sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
}
sess = sess.Join("INNER", "team_user", "team_user.team_id = team.id").
And("team_user.uid=?", opts.UserID)
teams := make([]*Team, 0, opts.PageSize)
if err = sess.
OrderBy("lower_name").
Find(&teams); err != nil {
return nil, 0, err
}
return teams, count, nil
}
// SearchOrgTeams search for org teams. Caller is responsible to check permissions.
func SearchOrgTeams(opts *SearchOrgTeamOptions) ([]*Team, int64, error) {
// SearchTeam search for teams. Caller is responsible to check permissions.
func SearchTeam(opts *SearchTeamOptions) ([]*Team, int64, error) {
if opts.Page <= 0 {
opts.Page = 1
}
@@ -242,7 +196,7 @@ func (t *Team) getRepositories(e db.Engine) error {
}
// GetRepositories returns paginated repositories in team of organization.
func (t *Team) GetRepositories(opts *SearchOrgTeamOptions) error {
func (t *Team) GetRepositories(opts *SearchTeamOptions) error {
if opts.Page == 0 {
return t.getRepositories(db.GetEngine(db.DefaultContext))
}
@@ -762,7 +716,7 @@ func UpdateTeam(t *Team, authChanged, includeAllChanged bool) (err error) {
// DeleteTeam deletes given team.
// It's caller's responsibility to assign organization ID.
func DeleteTeam(t *Team) error {
if err := t.GetRepositories(&SearchOrgTeamOptions{}); err != nil {
if err := t.GetRepositories(&SearchTeamOptions{}); err != nil {
return err
}
@@ -777,45 +731,8 @@ func DeleteTeam(t *Team) error {
return err
}
// update branch protections
{
protections := make([]*ProtectedBranch, 0, 10)
err := sess.In("repo_id",
builder.Select("id").From("repository").Where(builder.Eq{"owner_id": t.OrgID})).
Find(&protections)
if err != nil {
return fmt.Errorf("findProtectedBranches: %v", err)
}
for _, p := range protections {
var matched1, matched2, matched3 bool
if len(p.WhitelistTeamIDs) != 0 {
p.WhitelistTeamIDs, matched1 = util.RemoveIDFromList(
p.WhitelistTeamIDs, t.ID)
}
if len(p.ApprovalsWhitelistTeamIDs) != 0 {
p.ApprovalsWhitelistTeamIDs, matched2 = util.RemoveIDFromList(
p.ApprovalsWhitelistTeamIDs, t.ID)
}
if len(p.MergeWhitelistTeamIDs) != 0 {
p.MergeWhitelistTeamIDs, matched3 = util.RemoveIDFromList(
p.MergeWhitelistTeamIDs, t.ID)
}
if matched1 || matched2 || matched3 {
if _, err = sess.ID(p.ID).Cols(
"whitelist_team_i_ds",
"merge_whitelist_team_i_ds",
"approvals_whitelist_team_i_ds",
).Update(p); err != nil {
return fmt.Errorf("updateProtectedBranches: %v", err)
}
}
}
}
if !t.IncludesAllRepositories {
if err := t.removeAllRepositories(ctx); err != nil {
return err
}
if err := t.removeAllRepositories(ctx); err != nil {
return err
}
// Delete team-user.
@@ -940,6 +857,11 @@ func AddTeamMember(team *Team, userID int64) error {
return err
}
// Get team and its repositories.
if err := team.GetRepositories(&SearchTeamOptions{}); err != nil {
return err
}
ctx, committer, err := db.TxContext()
if err != nil {
return err
@@ -961,49 +883,15 @@ func AddTeamMember(team *Team, userID int64) error {
team.NumMembers++
// Give access to team repositories.
// update exist access if mode become bigger
subQuery := builder.Select("repo_id").From("team_repo").
Where(builder.Eq{"team_id": team.ID})
if _, err := sess.Where("user_id=?", userID).
In("repo_id", subQuery).
And("mode < ?", team.AccessMode).
SetExpr("mode", team.AccessMode).
Update(new(Access)); err != nil {
return fmt.Errorf("update user accesses: %v", err)
}
// for not exist access
var repoIDs []int64
accessSubQuery := builder.Select("repo_id").From("access").Where(builder.Eq{"user_id": userID})
if err := sess.SQL(subQuery.And(builder.NotIn("repo_id", accessSubQuery))).Find(&repoIDs); err != nil {
return fmt.Errorf("select id accesses: %v", err)
}
accesses := make([]*Access, 0, 100)
for i, repoID := range repoIDs {
accesses = append(accesses, &Access{RepoID: repoID, UserID: userID, Mode: team.AccessMode})
if (i%100 == 0 || i == len(repoIDs)-1) && len(accesses) > 0 {
if err = db.Insert(ctx, accesses); err != nil {
return fmt.Errorf("insert new user accesses: %v", err)
}
accesses = accesses[:0]
for _, repo := range team.Repos {
if err := recalculateUserAccess(ctx, repo, userID); err != nil {
return err
}
}
// watch could be failed, so run it in a goroutine
if setting.Service.AutoWatchNewRepos {
// Get team and its repositories.
if err := team.GetRepositories(&SearchOrgTeamOptions{}); err != nil {
log.Error("getRepositories failed: %v", err)
}
go func(repos []*repo_model.Repository) {
for _, repo := range repos {
if err = repo_model.WatchRepoCtx(db.DefaultContext, userID, repo.ID, true); err != nil {
log.Error("watch repo failed: %v", err)
}
if setting.Service.AutoWatchNewRepos {
if err = repo_model.WatchRepoCtx(ctx, userID, repo.ID, true); err != nil {
return err
}
}(team.Repos)
}
}
return committer.Commit()

View File

@@ -46,7 +46,7 @@ func TestTeam_GetRepositories(t *testing.T) {
test := func(teamID int64) {
team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team)
assert.NoError(t, team.GetRepositories(&SearchOrgTeamOptions{}))
assert.NoError(t, team.GetRepositories(&SearchTeamOptions{}))
assert.Len(t, team.Repos, team.NumRepos)
for _, repo := range team.Repos {
unittest.AssertExistsAndLoadBean(t, &TeamRepo{TeamID: teamID, RepoID: repo.ID})
@@ -292,7 +292,7 @@ func TestGetTeamMembers(t *testing.T) {
func TestGetUserTeams(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
test := func(userID int64) {
teams, _, err := GetUserTeams(&GetUserTeamOptions{UserID: userID})
teams, _, err := SearchTeam(&SearchTeamOptions{UserID: userID})
assert.NoError(t, err)
for _, team := range teams {
unittest.AssertExistsAndLoadBean(t, &TeamUser{TeamID: team.ID, UID: userID})

View File

@@ -222,19 +222,22 @@ func (pr *PullRequest) loadProtectedBranch(ctx context.Context) (err error) {
}
// GetDefaultMergeMessage returns default message used when merging pull request
func (pr *PullRequest) GetDefaultMergeMessage() (string, error) {
func (pr *PullRequest) GetDefaultMergeMessage() string {
if pr.HeadRepo == nil {
var err error
pr.HeadRepo, err = repo_model.GetRepositoryByID(pr.HeadRepoID)
if err != nil {
return "", fmt.Errorf("GetRepositoryById[%d]: %v", pr.HeadRepoID, err)
log.Error("GetRepositoryById[%d]: %v", pr.HeadRepoID, err)
return ""
}
}
if err := pr.LoadIssue(); err != nil {
return "", fmt.Errorf("Cannot load issue %d for PR id %d: Error: %v", pr.IssueID, pr.ID, err)
log.Error("Cannot load issue %d for PR id %d: Error: %v", pr.IssueID, pr.ID, err)
return ""
}
if err := pr.LoadBaseRepo(); err != nil {
return "", fmt.Errorf("LoadBaseRepo: %v", err)
log.Error("LoadBaseRepo: %v", err)
return ""
}
issueReference := "#"
@@ -243,10 +246,10 @@ func (pr *PullRequest) GetDefaultMergeMessage() (string, error) {
}
if pr.BaseRepoID == pr.HeadRepoID {
return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadBranch, pr.BaseBranch), nil
return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadBranch, pr.BaseBranch)
}
return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s:%s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseBranch), nil
return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s:%s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseBranch)
}
// ReviewCount represents a count of Reviews
@@ -332,17 +335,19 @@ func (pr *PullRequest) getReviewedByLines(writer io.Writer) error {
}
// GetDefaultSquashMessage returns default message used when squash and merging pull request
func (pr *PullRequest) GetDefaultSquashMessage() (string, error) {
func (pr *PullRequest) GetDefaultSquashMessage() string {
if err := pr.LoadIssue(); err != nil {
return "", fmt.Errorf("LoadIssue: %v", err)
log.Error("LoadIssue: %v", err)
return ""
}
if err := pr.LoadBaseRepo(); err != nil {
return "", fmt.Errorf("LoadBaseRepo: %v", err)
log.Error("LoadBaseRepo: %v", err)
return ""
}
if pr.BaseRepo.UnitEnabled(unit.TypeExternalTracker) {
return fmt.Sprintf("%s (!%d)", pr.Issue.Title, pr.Issue.Index), nil
return fmt.Sprintf("%s (!%d)", pr.Issue.Title, pr.Issue.Index)
}
return fmt.Sprintf("%s (#%d)", pr.Issue.Title, pr.Issue.Index), nil
return fmt.Sprintf("%s (#%d)", pr.Issue.Title, pr.Issue.Index)
}
// GetGitRefName returns git ref for hidden pull request branch

View File

@@ -261,15 +261,11 @@ func TestPullRequest_GetDefaultMergeMessage_InternalTracker(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
pr := unittest.AssertExistsAndLoadBean(t, &PullRequest{ID: 2}).(*PullRequest)
msg, err := pr.GetDefaultMergeMessage()
assert.NoError(t, err)
assert.Equal(t, "Merge pull request 'issue3' (#3) from branch2 into master", msg)
assert.Equal(t, "Merge pull request 'issue3' (#3) from branch2 into master", pr.GetDefaultMergeMessage())
pr.BaseRepoID = 1
pr.HeadRepoID = 2
msg, err = pr.GetDefaultMergeMessage()
assert.NoError(t, err)
assert.Equal(t, "Merge pull request 'issue3' (#3) from user2/repo1:branch2 into master", msg)
assert.Equal(t, "Merge pull request 'issue3' (#3) from user2/repo1:branch2 into master", pr.GetDefaultMergeMessage())
}
func TestPullRequest_GetDefaultMergeMessage_ExternalTracker(t *testing.T) {
@@ -287,13 +283,9 @@ func TestPullRequest_GetDefaultMergeMessage_ExternalTracker(t *testing.T) {
pr := unittest.AssertExistsAndLoadBean(t, &PullRequest{ID: 2, BaseRepo: baseRepo}).(*PullRequest)
msg, err := pr.GetDefaultMergeMessage()
assert.NoError(t, err)
assert.Equal(t, "Merge pull request 'issue3' (!3) from branch2 into master", msg)
assert.Equal(t, "Merge pull request 'issue3' (!3) from branch2 into master", pr.GetDefaultMergeMessage())
pr.BaseRepoID = 1
pr.HeadRepoID = 2
msg, err = pr.GetDefaultMergeMessage()
assert.NoError(t, err)
assert.Equal(t, "Merge pull request 'issue3' (!3) from user2/repo1:branch2 into master", msg)
assert.Equal(t, "Merge pull request 'issue3' (!3) from user2/repo1:branch2 into master", pr.GetDefaultMergeMessage())
}

View File

@@ -150,56 +150,27 @@ func getRepoAssignees(ctx context.Context, repo *repo_model.Repository) (_ []*us
}
e := db.GetEngine(ctx)
userIDs := make([]int64, 0, 10)
if err = e.Table("access").
accesses := make([]*Access, 0, 10)
if err = e.
Where("repo_id = ? AND mode >= ?", repo.ID, perm.AccessModeWrite).
Select("user_id").
Find(&userIDs); err != nil {
Find(&accesses); err != nil {
return nil, err
}
additionalUserIDs := make([]int64, 0, 10)
if err = e.Table("team_user").
Join("INNER", "team_repo", "`team_repo`.team_id = `team_user`.team_id").
Join("INNER", "team_unit", "`team_unit`.team_id = `team_user`.team_id").
Where("`team_repo`.repo_id = ? AND `team_unit`.access_mode >= ?", repo.ID, perm.AccessModeWrite).
Distinct("`team_user`.uid").
Select("`team_user`.uid").
Find(&additionalUserIDs); err != nil {
return nil, err
}
uidMap := map[int64]bool{}
i := 0
for _, uid := range userIDs {
if uidMap[uid] {
continue
}
uidMap[uid] = true
userIDs[i] = uid
i++
}
userIDs = userIDs[:i]
userIDs = append(userIDs, additionalUserIDs...)
for _, uid := range additionalUserIDs {
if uidMap[uid] {
continue
}
userIDs[i] = uid
i++
}
userIDs = userIDs[:i]
// Leave a seat for owner itself to append later, but if owner is an organization
// and just waste 1 unit is cheaper than re-allocate memory once.
users := make([]*user_model.User, 0, len(userIDs)+1)
if len(userIDs) > 0 {
users := make([]*user_model.User, 0, len(accesses)+1)
if len(accesses) > 0 {
userIDs := make([]int64, len(accesses))
for i := 0; i < len(accesses); i++ {
userIDs[i] = accesses[i].UserID
}
if err = e.In("id", userIDs).Find(&users); err != nil {
return nil, err
}
}
if !repo.Owner.IsOrganization() && !uidMap[repo.OwnerID] {
if !repo.Owner.IsOrganization() {
users = append(users, repo.Owner)
}
@@ -977,7 +948,7 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
// Remove attachment with no issue_id and release_id.
for i := range newAttachmentPaths {
admin_model.RemoveStorageWithNotice(db.DefaultContext, storage.Attachments, "Delete issue attachment", newAttachmentPaths[i])
admin_model.RemoveStorageWithNotice(db.DefaultContext, storage.Attachments, "Delete issue attachment", attachmentPaths[i])
}
if len(repo.Avatar) > 0 {

View File

@@ -6,7 +6,6 @@
package repo
import (
"context"
"errors"
"fmt"
"time"
@@ -116,13 +115,6 @@ func UpdateMirror(m *Mirror) error {
return updateMirror(db.GetEngine(db.DefaultContext), m)
}
// TouchMirror updates the mirror updatedUnix
func TouchMirror(ctx context.Context, m *Mirror) error {
m.UpdatedUnix = timeutil.TimeStampNow()
_, err := db.GetEngine(ctx).ID(m.ID).Cols("updated_unix").Update(m)
return err
}
// DeleteMirrorByRepoID deletes a mirror by repoID
func DeleteMirrorByRepoID(repoID int64) error {
_, err := db.GetEngine(db.DefaultContext).Delete(&Mirror{RepoID: repoID})

View File

@@ -167,21 +167,3 @@ func TestLinkedRepository(t *testing.T) {
})
}
}
func TestRepoAssignees(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository)
users, err := GetRepoAssignees(repo2)
assert.NoError(t, err)
assert.Len(t, users, 1)
assert.Equal(t, users[0].ID, int64(2))
repo21 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 21}).(*repo_model.Repository)
users, err = GetRepoAssignees(repo21)
assert.NoError(t, err)
assert.Len(t, users, 3)
assert.Equal(t, users[0].ID, int64(15))
assert.Equal(t, users[1].ID, int64(18))
assert.Equal(t, users[2].ID, int64(16))
}

View File

@@ -328,12 +328,7 @@ func AllUnitKeyNames() []string {
// MinUnitAccessMode returns the minial permission of the permission map
func MinUnitAccessMode(unitsMap map[Type]perm.AccessMode) perm.AccessMode {
res := perm.AccessModeNone
for t, mode := range unitsMap {
// Don't allow `TypeExternal{Tracker,Wiki}` to influence this as they can only be set to READ perms.
if t == TypeExternalTracker || t == TypeExternalWiki {
continue
}
for _, mode := range unitsMap {
// get the minial permission great than AccessModeNone except all are AccessModeNone
if mode > perm.AccessModeNone && (res == perm.AccessModeNone || mode < res) {
res = mode

View File

@@ -18,7 +18,6 @@ import (
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"xorm.io/builder"
)
@@ -131,50 +130,6 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
}
}
// ***** START: Branch Protections *****
{
const batchSize = 50
for start := 0; ; start += batchSize {
protections := make([]*ProtectedBranch, 0, batchSize)
// @perf: We can't filter on DB side by u.ID, as those IDs are serialized as JSON strings.
// We could filter down with `WHERE repo_id IN (reposWithPushPermission(u))`,
// though that query will be quite complex and tricky to maintain (compare `getRepoAssignees()`).
// Also, as we didn't update branch protections when removing entries from `access` table,
// it's safer to iterate all protected branches.
if err = e.Limit(batchSize, start).Find(&protections); err != nil {
return fmt.Errorf("findProtectedBranches: %v", err)
}
if len(protections) == 0 {
break
}
for _, p := range protections {
var matched1, matched2, matched3 bool
if len(p.WhitelistUserIDs) != 0 {
p.WhitelistUserIDs, matched1 = util.RemoveIDFromList(
p.WhitelistUserIDs, u.ID)
}
if len(p.ApprovalsWhitelistUserIDs) != 0 {
p.ApprovalsWhitelistUserIDs, matched2 = util.RemoveIDFromList(
p.ApprovalsWhitelistUserIDs, u.ID)
}
if len(p.MergeWhitelistUserIDs) != 0 {
p.MergeWhitelistUserIDs, matched3 = util.RemoveIDFromList(
p.MergeWhitelistUserIDs, u.ID)
}
if matched1 || matched2 || matched3 {
if _, err = e.ID(p.ID).Cols(
"whitelist_user_i_ds",
"merge_whitelist_user_i_ds",
"approvals_whitelist_user_i_ds",
).Update(p); err != nil {
return fmt.Errorf("updateProtectedBranches: %v", err)
}
}
}
}
}
// ***** END: Branch Protections *****
// ***** START: PublicKey *****
if _, err = e.Delete(&asymkey_model.PublicKey{OwnerID: u.ID}); err != nil {
return fmt.Errorf("deletePublicKeys: %v", err)

View File

@@ -10,7 +10,6 @@ import (
"errors"
"fmt"
"net/mail"
"regexp"
"strings"
"code.gitea.io/gitea/models/db"
@@ -22,23 +21,10 @@ import (
"xorm.io/builder"
)
// ErrEmailNotActivated e-mail address has not been activated error
var ErrEmailNotActivated = errors.New("e-mail address has not been activated")
// ErrEmailCharIsNotSupported e-mail address contains unsupported character
type ErrEmailCharIsNotSupported struct {
Email string
}
// IsErrEmailCharIsNotSupported checks if an error is an ErrEmailCharIsNotSupported
func IsErrEmailCharIsNotSupported(err error) bool {
_, ok := err.(ErrEmailCharIsNotSupported)
return ok
}
func (err ErrEmailCharIsNotSupported) Error() string {
return fmt.Sprintf("e-mail address contains unsupported character [email: %s]", err.Email)
}
var (
// ErrEmailNotActivated e-mail address has not been activated error
ErrEmailNotActivated = errors.New("E-mail address has not been activated")
)
// ErrEmailInvalid represents an error where the email address does not comply with RFC 5322
type ErrEmailInvalid struct {
@@ -122,24 +108,12 @@ func (email *EmailAddress) BeforeInsert() {
}
}
var emailRegexp = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
// ValidateEmail check if email is a allowed address
func ValidateEmail(email string) error {
if len(email) == 0 {
return nil
}
if !emailRegexp.MatchString(email) {
return ErrEmailCharIsNotSupported{email}
}
if !(email[0] >= 'a' && email[0] <= 'z') &&
!(email[0] >= 'A' && email[0] <= 'Z') &&
!(email[0] >= '0' && email[0] <= '9') {
return ErrEmailInvalid{email}
}
if _, err := mail.ParseAddress(email); err != nil {
return ErrEmailInvalid{email}
}

View File

@@ -252,58 +252,3 @@ func TestListEmails(t *testing.T) {
assert.Len(t, emails, 5)
assert.Greater(t, count, int64(len(emails)))
}
func TestEmailAddressValidate(t *testing.T) {
kases := map[string]error{
"abc@gmail.com": nil,
"132@hotmail.com": nil,
"1-3-2@test.org": nil,
"1.3.2@test.org": nil,
"a_123@test.org.cn": nil,
`first.last@iana.org`: nil,
`first!last@iana.org`: nil,
`first#last@iana.org`: nil,
`first$last@iana.org`: nil,
`first%last@iana.org`: nil,
`first&last@iana.org`: nil,
`first'last@iana.org`: nil,
`first*last@iana.org`: nil,
`first+last@iana.org`: nil,
`first/last@iana.org`: nil,
`first=last@iana.org`: nil,
`first?last@iana.org`: nil,
`first^last@iana.org`: nil,
"first`last@iana.org": nil,
`first{last@iana.org`: nil,
`first|last@iana.org`: nil,
`first}last@iana.org`: nil,
`first~last@iana.org`: nil,
`first;last@iana.org`: ErrEmailCharIsNotSupported{`first;last@iana.org`},
".233@qq.com": ErrEmailInvalid{".233@qq.com"},
"!233@qq.com": ErrEmailInvalid{"!233@qq.com"},
"#233@qq.com": ErrEmailInvalid{"#233@qq.com"},
"$233@qq.com": ErrEmailInvalid{"$233@qq.com"},
"%233@qq.com": ErrEmailInvalid{"%233@qq.com"},
"&233@qq.com": ErrEmailInvalid{"&233@qq.com"},
"'233@qq.com": ErrEmailInvalid{"'233@qq.com"},
"*233@qq.com": ErrEmailInvalid{"*233@qq.com"},
"+233@qq.com": ErrEmailInvalid{"+233@qq.com"},
"/233@qq.com": ErrEmailInvalid{"/233@qq.com"},
"=233@qq.com": ErrEmailInvalid{"=233@qq.com"},
"?233@qq.com": ErrEmailInvalid{"?233@qq.com"},
"^233@qq.com": ErrEmailInvalid{"^233@qq.com"},
"`233@qq.com": ErrEmailInvalid{"`233@qq.com"},
"{233@qq.com": ErrEmailInvalid{"{233@qq.com"},
"|233@qq.com": ErrEmailInvalid{"|233@qq.com"},
"}233@qq.com": ErrEmailInvalid{"}233@qq.com"},
"~233@qq.com": ErrEmailInvalid{"~233@qq.com"},
";233@qq.com": ErrEmailCharIsNotSupported{";233@qq.com"},
"Foo <foo@bar.com>": ErrEmailCharIsNotSupported{"Foo <foo@bar.com>"},
string([]byte{0xE2, 0x84, 0xAA}): ErrEmailCharIsNotSupported{string([]byte{0xE2, 0x84, 0xAA})},
}
for kase, err := range kases {
t.Run(kase, func(t *testing.T) {
assert.EqualValues(t, err, ValidateEmail(kase))
})
}
}

View File

@@ -60,7 +60,7 @@ type ExternalLoginUser struct {
LastName string
NickName string
Description string
AvatarURL string `xorm:"TEXT"`
AvatarURL string
Location string
AccessToken string `xorm:"TEXT"`
AccessTokenSecret string `xorm:"TEXT"`

View File

@@ -30,19 +30,13 @@ func (users UserList) GetTwoFaStatus() map[int64]bool {
for _, user := range users {
results[user.ID] = false // Set default to false
}
if tokenMaps, err := users.loadTwoFactorStatus(db.GetEngine(db.DefaultContext)); err == nil {
tokenMaps, err := users.loadTwoFactorStatus(db.GetEngine(db.DefaultContext))
if err == nil {
for _, token := range tokenMaps {
results[token.UID] = true
}
}
if ids, err := users.userIDsWithWebAuthn(db.GetEngine(db.DefaultContext)); err == nil {
for _, id := range ids {
results[id] = true
}
}
return results
}
@@ -53,23 +47,15 @@ func (users UserList) loadTwoFactorStatus(e db.Engine) (map[int64]*auth.TwoFacto
userIDs := users.GetUserIDs()
tokenMaps := make(map[int64]*auth.TwoFactor, len(userIDs))
if err := e.In("uid", userIDs).Find(&tokenMaps); err != nil {
err := e.
In("uid", userIDs).
Find(&tokenMaps)
if err != nil {
return nil, fmt.Errorf("find two factor: %v", err)
}
return tokenMaps, nil
}
func (users UserList) userIDsWithWebAuthn(e db.Engine) ([]int64, error) {
if len(users) == 0 {
return nil, nil
}
ids := make([]int64, 0, len(users))
if err := e.Table(new(auth.WebAuthnCredential)).In("user_id", users.GetUserIDs()).Select("user_id").Distinct("user_id").Find(&ids); err != nil {
return nil, fmt.Errorf("find two factor: %v", err)
}
return ids, nil
}
// GetUsersByIDs returns all resolved users from a list of Ids.
func GetUsersByIDs(ids []int64) (UserList, error) {
ous := make([]*User, 0, len(ids))

View File

@@ -20,7 +20,6 @@ import (
// SearchUserOptions contains the options for searching
type SearchUserOptions struct {
db.ListOptions
Keyword string
Type UserType
UID int64
@@ -34,8 +33,6 @@ type SearchUserOptions struct {
IsRestricted util.OptionalBool
IsTwoFactorEnabled util.OptionalBool
IsProhibitLogin util.OptionalBool
ExtraParamStrings map[string]string
}
func (opts *SearchUserOptions) toSearchQueryBase() *xorm.Session {

View File

@@ -644,15 +644,6 @@ func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err e
u.Visibility = overwriteDefault[0].Visibility
}
// validate data
if err := validateUser(u); err != nil {
return err
}
if err := ValidateEmail(u.Email); err != nil {
return err
}
ctx, committer, err := db.TxContext()
if err != nil {
return err
@@ -661,6 +652,11 @@ func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err e
sess := db.GetEngine(ctx)
// validate data
if err := validateUser(u); err != nil {
return err
}
isExist, err := isUserExist(sess, 0, u.Name)
if err != nil {
return err
@@ -831,9 +827,8 @@ func validateUser(u *User) error {
return ValidateEmail(u.Email)
}
func updateUser(ctx context.Context, u *User, changePrimaryEmail bool, cols ...string) error {
err := validateUser(u)
if err != nil {
func updateUser(ctx context.Context, u *User, changePrimaryEmail bool) error {
if err := validateUser(u); err != nil {
return err
}
@@ -865,35 +860,15 @@ func updateUser(ctx context.Context, u *User, changePrimaryEmail bool, cols ...s
}); err != nil {
return err
}
} else if !u.IsOrganization() { // check if primary email in email_address table
primaryEmailExist, err := e.Where("uid=? AND is_primary=?", u.ID, true).Exist(&EmailAddress{})
if err != nil {
return err
}
if !primaryEmailExist {
if _, err = e.Insert(&EmailAddress{
Email: u.Email,
UID: u.ID,
IsActivated: true,
IsPrimary: true,
}); err != nil {
return err
}
}
}
if len(cols) == 0 {
_, err = e.ID(u.ID).AllCols().Update(u)
} else {
_, err = e.ID(u.ID).Cols(cols...).Update(u)
}
_, err := e.ID(u.ID).AllCols().Update(u)
return err
}
// UpdateUser updates user's information.
func UpdateUser(u *User, emailChanged bool, cols ...string) error {
return updateUser(db.DefaultContext, u, emailChanged, cols...)
func UpdateUser(u *User, emailChanged bool) error {
return updateUser(db.DefaultContext, u, emailChanged)
}
// UpdateUserCols update user according special columns
@@ -1129,9 +1104,19 @@ func GetUserByEmailContext(ctx context.Context, email string) (*User, error) {
}
email = strings.ToLower(email)
// First try to find the user by primary email
user := &User{Email: email}
has, err := db.GetEngine(ctx).Get(user)
if err != nil {
return nil, err
}
if has {
return user, nil
}
// Otherwise, check in alternative list for activated email addresses
emailAddress := &EmailAddress{LowerEmail: email, IsActivated: true}
has, err := db.GetEngine(ctx).Get(emailAddress)
emailAddress := &EmailAddress{Email: email, IsActivated: true}
has, err = db.GetEngine(ctx).Get(emailAddress)
if err != nil {
return nil, err
}

View File

@@ -232,21 +232,7 @@ func TestCreateUserInvalidEmail(t *testing.T) {
err := CreateUser(user)
assert.Error(t, err)
assert.True(t, IsErrEmailCharIsNotSupported(err))
}
func TestCreateUserEmailAlreadyUsed(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
user := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
// add new user with user2's email
user.Name = "testuser"
user.LowerName = strings.ToLower(user.Name)
user.ID = 0
err := CreateUser(user)
assert.Error(t, err)
assert.True(t, IsErrEmailAlreadyUsed(err))
assert.True(t, IsErrEmailInvalid(err))
}
func TestGetUserIDsByNames(t *testing.T) {

View File

@@ -497,19 +497,14 @@ func GetSystemOrDefaultWebhook(id int64) (*Webhook, error) {
}
// GetSystemWebhooks returns all admin system webhooks.
func GetSystemWebhooks(isActive util.OptionalBool) ([]*Webhook, error) {
return getSystemWebhooks(db.GetEngine(db.DefaultContext), isActive)
func GetSystemWebhooks() ([]*Webhook, error) {
return getSystemWebhooks(db.GetEngine(db.DefaultContext))
}
func getSystemWebhooks(e db.Engine, isActive util.OptionalBool) ([]*Webhook, error) {
func getSystemWebhooks(e db.Engine) ([]*Webhook, error) {
webhooks := make([]*Webhook, 0, 5)
if isActive.IsNone() {
return webhooks, e.
Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, true).
Find(&webhooks)
}
return webhooks, e.
Where("repo_id=? AND org_id=? AND is_system_webhook=? AND is_active = ?", 0, 0, true, isActive.IsTrue()).
Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, true).
Find(&webhooks)
}

View File

@@ -35,10 +35,6 @@ func Auth(serviceName, userName, passwd string) (string, error) {
if err = t.Authenticate(0); err != nil {
return "", err
}
if err = t.AcctMgmt(0); err != nil {
return "", err
}
// PAM login names might suffer transformations in the PAM stack.
// We should take whatever the PAM stack returns for it.

View File

@@ -63,7 +63,6 @@ func EscapeControlBytes(text []byte) (EscapeStatus, []byte) {
func EscapeControlReader(text io.Reader, output io.Writer) (escaped EscapeStatus, err error) {
buf := make([]byte, 4096)
readStart := 0
runeCount := 0
var n int
var writePos int
@@ -75,13 +74,10 @@ readingloop:
for err == nil {
n, err = text.Read(buf[readStart:])
bs := buf[:n+readStart]
n = len(bs)
i := 0
for i < len(bs) {
r, size := utf8.DecodeRune(bs[i:])
runeCount++
// Now handle the codepoints
switch {
case r == utf8.RuneError:
@@ -116,8 +112,6 @@ readingloop:
lineHasRTLScript = false
lineHasLTRScript = false
case runeCount == 1 && r == 0xFEFF: // UTF BOM
// the first BOM is safe
case r == '\r' || r == '\t' || r == ' ':
// These are acceptable control characters and space characters
case unicode.IsSpace(r):
@@ -149,8 +143,7 @@ readingloop:
return
}
writePos = i + size
// 65279 == BOM rune.
case unicode.Is(unicode.C, r) && r != rune(65279):
case unicode.Is(unicode.C, r):
escaped.Escaped = true
escaped.HasControls = true
if writePos < i {

View File

@@ -129,14 +129,6 @@ then resh (ר), and finally heh (ה) (which should appear leftmost).`,
"\n" + `if access_level != "user<span class="escaped-code-point" data-escaped="[U+202E]"><span class="char">` + "\u202e" + `</span></span> <span class="escaped-code-point" data-escaped="[U+2066]"><span class="char">` + "\u2066" + `</span></span>// Check if admin<span class="escaped-code-point" data-escaped="[U+2069]"><span class="char">` + "\u2069" + `</span></span> <span class="escaped-code-point" data-escaped="[U+2066]"><span class="char">` + "\u2066" + `</span></span>" {` + "\n",
status: EscapeStatus{Escaped: true, HasBIDI: true, BadBIDI: true, HasLTRScript: true, HasRTLScript: true},
},
{
// UTF-8/16/32 all use the same codepoint for BOM
// Gitea could read UTF-16/32 content and convert into UTF-8 internally then render it, so we only process UTF-8 internally
name: "UTF BOM",
text: "\xef\xbb\xbftest",
result: "\xef\xbb\xbftest",
status: EscapeStatus{HasLTRScript: true},
},
}
func TestEscapeControlString(t *testing.T) {
@@ -171,18 +163,10 @@ func TestEscapeControlReader(t *testing.T) {
// lets add some control characters to the tests
tests := make([]escapeControlTest, 0, len(escapeControlTests)*3)
copy(tests, escapeControlTests)
// if there is a BOM, we should keep the BOM
addPrefix := func(prefix, s string) string {
if strings.HasPrefix(s, "\xef\xbb\xbf") {
return s[:3] + prefix + s[3:]
}
return prefix + s
}
for _, test := range escapeControlTests {
test.name += " (+Control)"
test.text = addPrefix("\u001E", test.text)
test.result = addPrefix(`<span class="escaped-code-point" data-escaped="[U+001E]"><span class="char">`+"\u001e"+`</span></span>`, test.result)
test.text = "\u001E" + test.text
test.result = `<span class="escaped-code-point" data-escaped="[U+001E]"><span class="char">` + "\u001e" + `</span></span>` + test.result
test.status.Escaped = true
test.status.HasControls = true
tests = append(tests, test)
@@ -190,8 +174,8 @@ func TestEscapeControlReader(t *testing.T) {
for _, test := range escapeControlTests {
test.name += " (+Mark)"
test.text = addPrefix("\u0300", test.text)
test.result = addPrefix(`<span class="escaped-code-point" data-escaped="[U+0300]"><span class="char">`+"\u0300"+`</span></span>`, test.result)
test.text = "\u0300" + test.text
test.result = `<span class="escaped-code-point" data-escaped="[U+0300]"><span class="char">` + "\u0300" + `</span></span>` + test.result
test.status.Escaped = true
test.status.HasMarks = true
tests = append(tests, test)
@@ -216,12 +200,3 @@ func TestEscapeControlReader(t *testing.T) {
})
}
}
func TestEscapeControlReader_panic(t *testing.T) {
bs := make([]byte, 0, 20479)
bs = append(bs, 'A')
for i := 0; i < 6826; i++ {
bs = append(bs, []byte("—")...)
}
_, _ = EscapeControlBytes(bs)
}

View File

@@ -9,11 +9,9 @@ import (
"context"
"crypto/sha256"
"encoding/hex"
"errors"
"html"
"html/template"
"io"
"net"
"net/http"
"net/url"
"path"
@@ -181,12 +179,6 @@ func (ctx *Context) RedirectToFirst(location ...string) {
continue
}
// Unfortunately browsers consider a redirect Location with preceding "//" and "/\" as meaning redirect to "http(s)://REST_OF_PATH"
// Therefore we should ignore these redirect locations to prevent open redirects
if len(loc) > 1 && loc[0] == '/' && (loc[1] == '/' || loc[1] == '\\') {
continue
}
u, err := url.Parse(loc)
if err != nil || ((u.Scheme != "" || u.Host != "") && !strings.HasPrefix(strings.ToLower(loc), strings.ToLower(setting.AppURL))) {
continue
@@ -272,12 +264,6 @@ func (ctx *Context) ServerError(logMsg string, logErr error) {
func (ctx *Context) serverErrorInternal(logMsg string, logErr error) {
if logErr != nil {
log.ErrorWithSkip(2, "%s: %v", logMsg, logErr)
if _, ok := logErr.(*net.OpError); ok || errors.Is(logErr, &net.OpError{}) {
// This is an error within the underlying connection
// and further rendering will not work so just return
return
}
if !setting.IsProd {
ctx.Data["ErrorMsg"] = logErr
}
@@ -305,7 +291,6 @@ func (ctx *Context) PlainTextBytes(status int, bs []byte) {
}
ctx.Resp.WriteHeader(status)
ctx.Resp.Header().Set("Content-Type", "text/plain;charset=utf-8")
ctx.Resp.Header().Set("X-Content-Type-Options", "nosniff")
if _, err := ctx.Resp.Write(bs); err != nil {
log.Error("Write bytes failed: %v", err)
}

View File

@@ -229,7 +229,6 @@ func Csrfer(opt CsrfOptions, ctx *Context) CSRF {
}
}
needsNew = needsNew || ctx.Req.Method == "GET" // If this request is a Get request, it will generate a new token, make sure the token is always up-to-date.
if needsNew {
// FIXME: actionId.
x.Token = GenerateToken(x.Secret, x.ID, "POST")

View File

@@ -129,23 +129,7 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
// Team.
if ctx.Org.IsMember {
shouldSeeAllTeams := false
if ctx.Org.IsOwner {
shouldSeeAllTeams = true
} else {
teams, err := org.GetUserTeams(ctx.User.ID)
if err != nil {
ctx.ServerError("GetUserTeams", err)
return
}
for _, team := range teams {
if team.IncludesAllRepositories && team.AccessMode >= perm.AccessModeAdmin {
shouldSeeAllTeams = true
break
}
}
}
if shouldSeeAllTeams {
ctx.Org.Teams, err = org.LoadTeams()
if err != nil {
ctx.ServerError("LoadTeams", err)

View File

@@ -440,26 +440,6 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
ctx.Repo.Owner = owner
ctx.Data["Username"] = ctx.Repo.Owner.Name
// redirect link to wiki
if strings.HasSuffix(repoName, ".wiki") {
// ctx.Req.URL.Path does not have the preceding appSubURL - any redirect must have this added
// Now we happen to know that all of our paths are: /:username/:reponame/whatever_else
originalRepoName := ctx.Params(":reponame")
redirectRepoName := strings.TrimSuffix(repoName, ".wiki")
redirectRepoName += originalRepoName[len(redirectRepoName)+5:]
redirectPath := strings.Replace(
ctx.Req.URL.EscapedPath(),
url.PathEscape(userName)+"/"+url.PathEscape(originalRepoName),
url.PathEscape(userName)+"/"+url.PathEscape(redirectRepoName)+"/wiki",
1,
)
if ctx.Req.URL.RawQuery != "" {
redirectPath += "?" + ctx.Req.URL.RawQuery
}
ctx.Redirect(path.Join(setting.AppSubURL, redirectPath))
return
}
// Get repository.
repo, err := repo_model.GetRepositoryByName(owner.ID, repoName)
if err != nil {
@@ -931,7 +911,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
if refType == RepoRefLegacy {
// redirect from old URL scheme to new URL scheme
prefix := strings.TrimPrefix(setting.AppSubURL+strings.ToLower(strings.TrimSuffix(ctx.Req.URL.Path, ctx.Params("*"))), strings.ToLower(ctx.Repo.RepoLink))
prefix := strings.TrimPrefix(setting.AppSubURL+strings.TrimSuffix(ctx.Req.URL.Path, ctx.Params("*")), ctx.Repo.RepoLink)
ctx.Redirect(path.Join(
ctx.Repo.RepoLink,

View File

@@ -17,7 +17,6 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/util"
)
var (
@@ -33,11 +32,10 @@ const DefaultLocale = "C"
// Command represents a command with its subcommands or arguments.
type Command struct {
name string
args []string
parentContext context.Context
desc string
globalArgsLength int
name string
args []string
parentContext context.Context
desc string
}
func (c *Command) String() string {
@@ -58,10 +56,9 @@ func NewCommandContext(ctx context.Context, args ...string) *Command {
cargs := make([]string, len(GlobalCommandArgs))
copy(cargs, GlobalCommandArgs)
return &Command{
name: GitExecutable,
args: append(cargs, args...),
parentContext: ctx,
globalArgsLength: len(GlobalCommandArgs),
name: GitExecutable,
args: append(cargs, args...),
parentContext: ctx,
}
}
@@ -148,21 +145,7 @@ func (c *Command) RunWithContext(rc *RunContext) error {
desc := c.desc
if desc == "" {
args := c.args[c.globalArgsLength:]
var argSensitiveURLIndexes []int
for i, arg := range c.args {
if strings.Contains(arg, "://") && strings.Contains(arg, "@") {
argSensitiveURLIndexes = append(argSensitiveURLIndexes, i)
}
}
if len(argSensitiveURLIndexes) > 0 {
args = make([]string, len(c.args))
copy(args, c.args)
for _, urlArgIndex := range argSensitiveURLIndexes {
args[urlArgIndex] = util.NewStringURLSanitizer(args[urlArgIndex], true).Replace(args[urlArgIndex])
}
}
desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(args, " "), rc.Dir)
desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(c.args, " "), rc.Dir)
}
ctx, cancel, finished := process.GetManager().AddContextTimeout(c.parentContext, rc.Timeout, desc)
@@ -180,8 +163,6 @@ func (c *Command) RunWithContext(rc *RunContext) error {
fmt.Sprintf("LC_ALL=%s", DefaultLocale),
// avoid prompting for credentials interactively, supported since git v2.3
"GIT_TERMINAL_PROMPT=0",
// ignore replace references (https://git-scm.com/docs/git-replace)
"GIT_NO_REPLACE_OBJECTS=1",
)
// TODO: verify if this is still needed in golang 1.15

View File

@@ -16,25 +16,20 @@ import (
"github.com/stretchr/testify/assert"
)
const (
testReposDir = "tests/repos/"
)
const testReposDir = "tests/repos/"
const benchmarkReposDir = "benchmark/repos/"
func cloneRepo(url, name string) (string, error) {
repoDir, err := os.MkdirTemp("", name)
if err != nil {
return "", err
func cloneRepo(url, dir, name string) (string, error) {
repoDir := filepath.Join(dir, name)
if _, err := os.Stat(repoDir); err == nil {
return repoDir, nil
}
if err := Clone(url, repoDir, CloneRepoOptions{
return repoDir, Clone(url, repoDir, CloneRepoOptions{
Mirror: false,
Bare: false,
Quiet: true,
Timeout: 5 * time.Minute,
}); err != nil {
_ = util.RemoveAll(repoDir)
return "", err
}
return repoDir, nil
})
}
func testGetCommitsInfo(t *testing.T, repo1 *Repository) {
@@ -64,35 +59,20 @@ func testGetCommitsInfo(t *testing.T, repo1 *Repository) {
}
for _, testCase := range testCases {
commit, err := repo1.GetCommit(testCase.CommitID)
if err != nil {
assert.NoError(t, err, "Unable to get commit: %s from testcase due to error: %v", testCase.CommitID, err)
// no point trying to do anything else for this test.
continue
}
assert.NoError(t, err)
assert.NotNil(t, commit)
assert.NotNil(t, commit.Tree)
assert.NotNil(t, commit.Tree.repo)
tree, err := commit.Tree.SubTree(testCase.Path)
if err != nil {
assert.NoError(t, err, "Unable to get subtree: %s of commit: %s from testcase due to error: %v", testCase.Path, testCase.CommitID, err)
// no point trying to do anything else for this test.
continue
}
assert.NotNil(t, tree, "tree is nil for testCase CommitID %s in Path %s", testCase.CommitID, testCase.Path)
assert.NotNil(t, tree.repo, "repo is nil for testCase CommitID %s in Path %s", testCase.CommitID, testCase.Path)
assert.NoError(t, err)
entries, err := tree.ListEntries()
if err != nil {
assert.NoError(t, err, "Unable to get entries of subtree: %s in commit: %s from testcase due to error: %v", testCase.Path, testCase.CommitID, err)
// no point trying to do anything else for this test.
continue
}
// FIXME: Context.TODO() - if graceful has started we should use its Shutdown context otherwise use install signals in TestMain.
commitsInfo, treeCommit, err := entries.GetCommitsInfo(context.TODO(), commit, testCase.Path, nil)
assert.NoError(t, err, "Unable to get commit information for entries of subtree: %s in commit: %s from testcase due to error: %v", testCase.Path, testCase.CommitID, err)
assert.NoError(t, err)
commitsInfo, treeCommit, err := entries.GetCommitsInfo(context.Background(), commit, testCase.Path, nil)
assert.NoError(t, err)
if err != nil {
t.FailNow()
}
@@ -118,52 +98,40 @@ func TestEntries_GetCommitsInfo(t *testing.T) {
testGetCommitsInfo(t, bareRepo1)
clonedPath, err := cloneRepo(bareRepo1Path, "repo1_TestEntries_GetCommitsInfo")
if err != nil {
assert.NoError(t, err)
}
clonedPath, err := cloneRepo(bareRepo1Path, testReposDir, "repo1_TestEntries_GetCommitsInfo")
assert.NoError(t, err)
defer util.RemoveAll(clonedPath)
clonedRepo1, err := OpenRepository(clonedPath)
if err != nil {
assert.NoError(t, err)
}
assert.NoError(t, err)
defer clonedRepo1.Close()
testGetCommitsInfo(t, clonedRepo1)
}
func BenchmarkEntries_GetCommitsInfo(b *testing.B) {
type benchmarkType struct {
benchmarks := []struct {
url string
name string
}
benchmarks := []benchmarkType{
}{
{url: "https://github.com/go-gitea/gitea.git", name: "gitea"},
{url: "https://github.com/ethantkoenig/manyfiles.git", name: "manyfiles"},
{url: "https://github.com/moby/moby.git", name: "moby"},
{url: "https://github.com/golang/go.git", name: "go"},
{url: "https://github.com/torvalds/linux.git", name: "linux"},
}
doBenchmark := func(benchmark benchmarkType) {
for _, benchmark := range benchmarks {
var commit *Commit
var entries Entries
var repo *Repository
repoPath, err := cloneRepo(benchmark.url, benchmark.name)
if err != nil {
if repoPath, err := cloneRepo(benchmark.url, benchmarkReposDir, benchmark.name); err != nil {
b.Fatal(err)
}
defer util.RemoveAll(repoPath)
if repo, err = OpenRepository(repoPath); err != nil {
} else if repo, err = OpenRepository(repoPath); err != nil {
b.Fatal(err)
}
defer repo.Close()
if commit, err = repo.GetBranchCommit("master"); err != nil {
} else if commit, err = repo.GetBranchCommit("master"); err != nil {
repo.Close()
b.Fatal(err)
} else if entries, err = commit.Tree.ListEntries(); err != nil {
repo.Close()
b.Fatal(err)
}
entries.Sort()
@@ -176,9 +144,6 @@ func BenchmarkEntries_GetCommitsInfo(b *testing.B) {
}
}
})
}
for _, benchmark := range benchmarks {
doBenchmark(benchmark)
repo.Close()
}
}

View File

@@ -59,28 +59,27 @@ func GetRepoRawDiffForFile(repo *Repository, startCommit, endCommit string, diff
ctx, _, finished := process.GetManager().AddContext(repo.Ctx, fmt.Sprintf("GetRawDiffForFile: [repo_path: %s]", repo.Path))
defer finished()
cmd := exec.CommandContext(ctx, GitExecutable, GlobalCommandArgs...)
var cmd *exec.Cmd
switch diffType {
case RawDiffNormal:
if len(startCommit) != 0 {
cmd.Args = append(cmd.Args, append([]string{"diff", "-M", startCommit, endCommit}, fileArgs...)...)
cmd = exec.CommandContext(ctx, GitExecutable, append([]string{"diff", "-M", startCommit, endCommit}, fileArgs...)...)
} else if commit.ParentCount() == 0 {
cmd.Args = append(cmd.Args, append([]string{"show", endCommit}, fileArgs...)...)
cmd = exec.CommandContext(ctx, GitExecutable, append([]string{"show", endCommit}, fileArgs...)...)
} else {
c, _ := commit.Parent(0)
cmd.Args = append(cmd.Args, append([]string{"diff", "-M", c.ID.String(), endCommit}, fileArgs...)...)
cmd = exec.CommandContext(ctx, GitExecutable, append([]string{"diff", "-M", c.ID.String(), endCommit}, fileArgs...)...)
}
case RawDiffPatch:
if len(startCommit) != 0 {
query := fmt.Sprintf("%s...%s", endCommit, startCommit)
cmd.Args = append(cmd.Args, append([]string{"format-patch", "--no-signature", "--stdout", "--root", query}, fileArgs...)...)
cmd = exec.CommandContext(ctx, GitExecutable, append([]string{"format-patch", "--no-signature", "--stdout", "--root", query}, fileArgs...)...)
} else if commit.ParentCount() == 0 {
cmd.Args = append(cmd.Args, append([]string{"format-patch", "--no-signature", "--stdout", "--root", endCommit}, fileArgs...)...)
cmd = exec.CommandContext(ctx, GitExecutable, append([]string{"format-patch", "--no-signature", "--stdout", "--root", endCommit}, fileArgs...)...)
} else {
c, _ := commit.Parent(0)
query := fmt.Sprintf("%s...%s", endCommit, c.ID.String())
cmd.Args = append(cmd.Args, append([]string{"format-patch", "--no-signature", "--stdout", query}, fileArgs...)...)
cmd = exec.CommandContext(ctx, GitExecutable, append([]string{"format-patch", "--no-signature", "--stdout", query}, fileArgs...)...)
}
default:
return fmt.Errorf("invalid diffType: %s", diffType)

View File

@@ -112,8 +112,8 @@ func SetExecutablePath(path string) error {
// VersionInfo returns git version information
func VersionInfo() string {
format := "Git Version: %s"
args := []interface{}{gitVersion.Original()}
var format = "Git Version: %s"
var args = []interface{}{gitVersion.Original()}
// Since git wire protocol has been released from git v2.18
if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil {
format += ", Wire Protocol %s Enabled"
@@ -148,7 +148,7 @@ func Init(ctx context.Context) error {
// By default partial clones are disabled, enable them from git v2.22
if !setting.Git.DisablePartialClone && CheckGitVersionAtLeast("2.22") == nil {
GlobalCommandArgs = append(GlobalCommandArgs, "-c", "uploadpack.allowfilter=true", "-c", "uploadpack.allowAnySHA1InWant=true")
GlobalCommandArgs = append(GlobalCommandArgs, "-c", "uploadpack.allowfilter=true")
}
// Save current git version on init to gitVersion otherwise it would require an RWMutex

View File

@@ -22,9 +22,6 @@ func GetNote(ctx context.Context, repo *Repository, commitID string, note *Note)
log.Trace("Searching for git note corresponding to the commit %q in the repository %q", commitID, repo.Path)
notes, err := repo.GetCommit(NotesRef)
if err != nil {
if IsErrNotExist(err) {
return err
}
log.Error("Unable to get commit from ref %q. Error: %v", NotesRef, err)
return err
}

View File

@@ -21,9 +21,6 @@ func GetNote(ctx context.Context, repo *Repository, commitID string, note *Note)
log.Trace("Searching for git note corresponding to the commit %q in the repository %q", commitID, repo.Path)
notes, err := repo.GetCommit(NotesRef)
if err != nil {
if IsErrNotExist(err) {
return err
}
log.Error("Unable to get commit from ref %q. Error: %v", NotesRef, err)
return err
}

View File

@@ -19,7 +19,6 @@ import (
"time"
"code.gitea.io/gitea/modules/proxy"
"code.gitea.io/gitea/modules/util"
)
// GPGSettings represents the default GPG settings for this repository
@@ -80,34 +79,28 @@ func InitRepository(repoPath string, bare bool) error {
// IsEmpty Check if repository is empty.
func (repo *Repository) IsEmpty() (bool, error) {
var errbuf, output strings.Builder
if err := NewCommandContext(repo.Ctx, "show-ref", "--head", "^HEAD$").RunWithContext(&RunContext{
Timeout: -1,
Dir: repo.Path,
Stdout: &output,
Stderr: &errbuf,
}); err != nil {
if err.Error() == "exit status 1" && errbuf.String() == "" {
var errbuf strings.Builder
if err := NewCommand("log", "-1").RunInDirPipeline(repo.Path, nil, &errbuf); err != nil {
if strings.Contains(errbuf.String(), "fatal: bad default revision 'HEAD'") ||
strings.Contains(errbuf.String(), "fatal: your current branch 'master' does not have any commits yet") {
return true, nil
}
return true, fmt.Errorf("check empty: %v - %s", err, errbuf.String())
}
return strings.TrimSpace(output.String()) == "", nil
return false, nil
}
// CloneRepoOptions options when clone a repository
type CloneRepoOptions struct {
Timeout time.Duration
Mirror bool
Bare bool
Quiet bool
Branch string
Shared bool
NoCheckout bool
Depth int
Filter string
SkipTLSVerify bool
Timeout time.Duration
Mirror bool
Bare bool
Quiet bool
Branch string
Shared bool
NoCheckout bool
Depth int
}
// Clone clones original repository to target path.
@@ -130,9 +123,6 @@ func CloneWithArgs(ctx context.Context, from, to string, args []string, opts Clo
}
cmd := NewCommandContextNoGlobals(ctx, args...).AddArguments("clone")
if opts.SkipTLSVerify {
cmd.AddArguments("-c", "http.sslVerify=false")
}
if opts.Mirror {
cmd.AddArguments("--mirror")
}
@@ -151,20 +141,12 @@ func CloneWithArgs(ctx context.Context, from, to string, args []string, opts Clo
if opts.Depth > 0 {
cmd.AddArguments("--depth", strconv.Itoa(opts.Depth))
}
if opts.Filter != "" {
cmd.AddArguments("--filter", opts.Filter)
}
if len(opts.Branch) > 0 {
cmd.AddArguments("-b", opts.Branch)
}
cmd.AddArguments("--", from, to)
if strings.Contains(from, "://") && strings.Contains(from, "@") {
cmd.SetDescription(fmt.Sprintf("clone branch %s from %s to %s (shared: %t, mirror: %t, depth: %d)", opts.Branch, util.NewStringURLSanitizer(from, true).Replace(from), to, opts.Shared, opts.Mirror, opts.Depth))
} else {
cmd.SetDescription(fmt.Sprintf("clone branch %s from %s to %s (shared: %t, mirror: %t, depth: %d)", opts.Branch, from, to, opts.Shared, opts.Mirror, opts.Depth))
}
if opts.Timeout <= 0 {
opts.Timeout = -1
}
@@ -241,11 +223,6 @@ func Push(ctx context.Context, repoPath string, opts PushOptions) error {
if len(opts.Branch) > 0 {
cmd.AddArguments(opts.Branch)
}
if strings.Contains(opts.Remote, "://") && strings.Contains(opts.Remote, "@") {
cmd.SetDescription(fmt.Sprintf("push branch %s to %s (force: %t, mirror: %t)", opts.Branch, util.NewStringURLSanitizer(opts.Remote, true).Replace(opts.Remote), opts.Force, opts.Mirror))
} else {
cmd.SetDescription(fmt.Sprintf("push branch %s to %s (force: %t, mirror: %t)", opts.Branch, opts.Remote, opts.Force, opts.Mirror))
}
var outbuf, errbuf strings.Builder
if opts.Timeout == 0 {

View File

@@ -87,7 +87,7 @@ func (repo *Repository) CheckAttribute(opts CheckAttributeOpts) (map[string]map[
return nil, fmt.Errorf("wrong number of fields in return from check-attr")
}
name2attribute2info := make(map[string]map[string]string)
var name2attribute2info = make(map[string]map[string]string)
for i := 0; i < (len(fields) / 3); i++ {
filename := string(fields[3*i])
@@ -179,23 +179,17 @@ func (c *CheckAttributeReader) Init(ctx context.Context) error {
// Run run cmd
func (c *CheckAttributeReader) Run() error {
defer func() {
_ = c.stdinReader.Close()
_ = c.stdOut.Close()
_ = c.Close()
}()
stdErr := new(bytes.Buffer)
err := c.cmd.RunInDirTimeoutEnvFullPipelineFunc(c.env, -1, c.Repo.Path, c.stdOut, stdErr, c.stdinReader, func(_ context.Context, _ context.CancelFunc) error {
select {
case <-c.running:
default:
close(c.running)
}
close(c.running)
return nil
})
if err != nil && // If there is an error we need to return but:
c.ctx.Err() != err && // 1. Ignore the context error if the context is cancelled or exceeds the deadline (RunWithContext could return c.ctx.Err() which is Canceled or DeadlineExceeded)
err.Error() != "signal: killed" { // 2. We should not pass up errors due to the program being killed
if err != nil && c.ctx.Err() != nil && err.Error() != "signal: killed" {
return fmt.Errorf("failed to run attr-check. Error: %w\nStderr: %s", err, stdErr.String())
}
return nil
}
@@ -235,8 +229,10 @@ func (c *CheckAttributeReader) CheckPath(path string) (rs map[string]string, err
// Close close pip after use
func (c *CheckAttributeReader) Close() error {
c.cancel()
err := c.stdinWriter.Close()
_ = c.stdinReader.Close()
_ = c.stdOut.Close()
c.cancel()
select {
case <-c.running:
default:

View File

@@ -13,7 +13,6 @@ import (
"strings"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/storer"
)
// IsObjectExist returns true if given reference exists in the repository.
@@ -83,8 +82,7 @@ func (repo *Repository) GetBranchNames(skip, limit int) ([]string, int, error) {
}
// WalkReferences walks all the references from the repository
// refType should be empty, ObjectTag or ObjectBranch. All other values are equivalent to empty.
func WalkReferences(ctx context.Context, repoPath string, walkfn func(sha1, refname string) error) (int, error) {
func WalkReferences(ctx context.Context, repoPath string, walkfn func(string) error) (int, error) {
repo, err := OpenRepositoryCtx(ctx, repoPath)
if err != nil {
return 0, err
@@ -99,45 +97,9 @@ func WalkReferences(ctx context.Context, repoPath string, walkfn func(sha1, refn
defer iter.Close()
err = iter.ForEach(func(ref *plumbing.Reference) error {
err := walkfn(ref.Hash().String(), string(ref.Name()))
err := walkfn(string(ref.Name()))
i++
return err
})
return i, err
}
// WalkReferences walks all the references from the repository
func (repo *Repository) WalkReferences(arg ObjectType, skip, limit int, walkfn func(sha1, refname string) error) (int, error) {
i := 0
var iter storer.ReferenceIter
var err error
switch arg {
case ObjectTag:
iter, err = repo.gogitRepo.Tags()
case ObjectBranch:
iter, err = repo.gogitRepo.Branches()
default:
iter, err = repo.gogitRepo.References()
}
if err != nil {
return i, err
}
defer iter.Close()
err = iter.ForEach(func(ref *plumbing.Reference) error {
if i < skip {
i++
return nil
}
err := walkfn(ref.Hash().String(), string(ref.Name()))
i++
if err != nil {
return err
}
if limit != 0 && i >= skip+limit {
return storer.ErrStop
}
return nil
})
return i, err
}

View File

@@ -68,29 +68,13 @@ func (repo *Repository) GetBranchNames(skip, limit int) ([]string, int, error) {
}
// WalkReferences walks all the references from the repository
func WalkReferences(ctx context.Context, repoPath string, walkfn func(sha1, refname string) error) (int, error) {
func WalkReferences(ctx context.Context, repoPath string, walkfn func(string) error) (int, error) {
return walkShowRef(ctx, repoPath, "", 0, 0, walkfn)
}
// WalkReferences walks all the references from the repository
// refType should be empty, ObjectTag or ObjectBranch. All other values are equivalent to empty.
func (repo *Repository) WalkReferences(refType ObjectType, skip, limit int, walkfn func(sha1, refname string) error) (int, error) {
var arg string
switch refType {
case ObjectTag:
arg = "--tags"
case ObjectBranch:
arg = "--heads"
default:
arg = ""
}
return walkShowRef(repo.Ctx, repo.Path, arg, skip, limit, walkfn)
}
// callShowRef return refs, if limit = 0 it will not limit
func callShowRef(ctx context.Context, repoPath, prefix, arg string, skip, limit int) (branchNames []string, countAll int, err error) {
countAll, err = walkShowRef(ctx, repoPath, arg, skip, limit, func(_, branchName string) error {
countAll, err = walkShowRef(ctx, repoPath, arg, skip, limit, func(branchName string) error {
branchName = strings.TrimPrefix(branchName, prefix)
branchNames = append(branchNames, branchName)
@@ -99,7 +83,7 @@ func callShowRef(ctx context.Context, repoPath, prefix, arg string, skip, limit
return
}
func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, walkfn func(sha1, refname string) error) (countAll int, err error) {
func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, walkfn func(string) error) (countAll int, err error) {
stdoutReader, stdoutWriter := io.Pipe()
defer func() {
_ = stdoutReader.Close()
@@ -141,7 +125,11 @@ func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, wal
for limit == 0 || i < skip+limit {
// The output of show-ref is simply a list:
// <sha> SP <ref> LF
sha, err := bufReader.ReadString(' ')
_, err := bufReader.ReadSlice(' ')
for err == bufio.ErrBufferFull {
// This shouldn't happen but we'll tolerate it for the sake of peace
_, err = bufReader.ReadSlice(' ')
}
if err == io.EOF {
return i, nil
}
@@ -161,12 +149,7 @@ func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, wal
if len(branchName) > 0 {
branchName = branchName[:len(branchName)-1]
}
if len(sha) > 0 {
sha = sha[:len(sha)-1]
}
err = walkfn(sha, branchName)
err = walkfn(branchName)
if err != nil {
return i, err
}

View File

@@ -1,21 +0,0 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package git
import (
"context"
"fmt"
)
// WriteCommitGraph write commit graph to speed up repo access
// this requires git v2.18 to be installed
func WriteCommitGraph(ctx context.Context, repoPath string) error {
if CheckGitVersionAtLeast("2.18") == nil {
if _, err := NewCommandContext(ctx, "commit-graph", "write").RunInDir(repoPath); err != nil {
return fmt.Errorf("unable to write commit-graph for '%s' : %w", repoPath, err)
}
}
return nil
}

View File

@@ -17,33 +17,17 @@ import (
func TestGetFormatPatch(t *testing.T) {
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
clonedPath, err := cloneRepo(bareRepo1Path, "repo1_TestGetFormatPatch")
if err != nil {
assert.NoError(t, err)
return
}
clonedPath, err := cloneRepo(bareRepo1Path, testReposDir, "repo1_TestGetFormatPatch")
defer util.RemoveAll(clonedPath)
assert.NoError(t, err)
repo, err := OpenRepository(clonedPath)
if err != nil {
assert.NoError(t, err)
return
}
defer repo.Close()
assert.NoError(t, err)
rd := &bytes.Buffer{}
err = repo.GetPatch("8d92fc95^", "8d92fc95", rd)
if err != nil {
assert.NoError(t, err)
return
}
assert.NoError(t, err)
patchb, err := io.ReadAll(rd)
if err != nil {
assert.NoError(t, err)
return
}
assert.NoError(t, err)
patch := string(patchb)
assert.Regexp(t, "^From 8d92fc95", patch)
assert.Contains(t, patch, "Subject: [PATCH] Add file2.txt")
@@ -53,25 +37,17 @@ func TestReadPatch(t *testing.T) {
// Ensure we can read the patch files
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
repo, err := OpenRepository(bareRepo1Path)
if err != nil {
assert.NoError(t, err)
return
}
defer repo.Close()
assert.NoError(t, err)
// This patch doesn't exist
noFile, err := repo.ReadPatchCommit(0)
assert.Error(t, err)
// This patch is an empty one (sometimes it's a 404)
noCommit, err := repo.ReadPatchCommit(1)
assert.Error(t, err)
// This patch is legit and should return a commit
oldCommit, err := repo.ReadPatchCommit(2)
if err != nil {
assert.NoError(t, err)
return
}
assert.NoError(t, err)
assert.Empty(t, noFile)
assert.Empty(t, noCommit)
@@ -82,45 +58,23 @@ func TestReadPatch(t *testing.T) {
func TestReadWritePullHead(t *testing.T) {
// Ensure we can write SHA1 head corresponding to PR and open them
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
// As we are writing we should clone the repository first
clonedPath, err := cloneRepo(bareRepo1Path, "TestReadWritePullHead")
if err != nil {
assert.NoError(t, err)
return
}
defer util.RemoveAll(clonedPath)
repo, err := OpenRepository(clonedPath)
if err != nil {
assert.NoError(t, err)
return
}
repo, err := OpenRepository(bareRepo1Path)
assert.NoError(t, err)
defer repo.Close()
// Try to open non-existing Pull
_, err = repo.GetRefCommitID(PullPrefix + "0/head")
assert.Error(t, err)
// Write a fake sha1 with only 40 zeros
newCommit := "feaf4ba6bc635fec442f46ddd4512416ec43c2c2"
err = repo.SetReference(PullPrefix+"1/head", newCommit)
if err != nil {
assert.NoError(t, err)
return
}
assert.NoError(t, err)
// Remove file after the test
defer func() {
_ = repo.RemoveReference(PullPrefix + "1/head")
}()
// Read the file created
headContents, err := repo.GetRefCommitID(PullPrefix + "1/head")
if err != nil {
assert.NoError(t, err)
return
}
assert.NoError(t, err)
assert.Len(t, string(headContents), 40)
assert.True(t, string(headContents) == newCommit)
// Remove file after the test
err = repo.RemoveReference(PullPrefix + "1/head")
assert.NoError(t, err)
}

View File

@@ -88,10 +88,7 @@ func (repo *Repository) GetLanguageStats(commitID string) (map[string]int64, err
}
}()
}
defer func() {
_ = checker.Close()
cancel()
}()
defer cancel()
}
}

View File

@@ -10,6 +10,7 @@ import (
"fmt"
"strings"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/util"
)
@@ -33,6 +34,69 @@ func (repo *Repository) CreateAnnotatedTag(name, message, revision string) error
return err
}
func (repo *Repository) getTag(tagID SHA1, name string) (*Tag, error) {
t, ok := repo.tagCache.Get(tagID.String())
if ok {
log.Debug("Hit cache: %s", tagID)
tagClone := *t.(*Tag)
tagClone.Name = name // This is necessary because lightweight tags may have same id
return &tagClone, nil
}
tp, err := repo.GetTagType(tagID)
if err != nil {
return nil, err
}
// Get the commit ID and tag ID (may be different for annotated tag) for the returned tag object
commitIDStr, err := repo.GetTagCommitID(name)
if err != nil {
// every tag should have a commit ID so return all errors
return nil, err
}
commitID, err := NewIDFromString(commitIDStr)
if err != nil {
return nil, err
}
// If type is "commit, the tag is a lightweight tag
if ObjectType(tp) == ObjectCommit {
commit, err := repo.GetCommit(commitIDStr)
if err != nil {
return nil, err
}
tag := &Tag{
Name: name,
ID: tagID,
Object: commitID,
Type: tp,
Tagger: commit.Committer,
Message: commit.Message(),
}
repo.tagCache.Set(tagID.String(), tag)
return tag, nil
}
// The tag is an annotated tag with a message.
data, err := NewCommandContext(repo.Ctx, "cat-file", "-p", tagID.String()).RunInDirBytes(repo.Path)
if err != nil {
return nil, err
}
tag, err := parseTagData(data)
if err != nil {
return nil, err
}
tag.Name = name
tag.ID = tagID
tag.Type = tp
repo.tagCache.Set(tagID.String(), tag)
return tag, nil
}
// GetTagNameBySHA returns the name of a tag from its tag object SHA or commit SHA
func (repo *Repository) GetTagNameBySHA(sha string) (string, error) {
if len(sha) < 5 {
@@ -95,20 +159,6 @@ func (repo *Repository) GetTag(name string) (*Tag, error) {
return tag, nil
}
// GetTagWithID returns a Git tag by given name and ID
func (repo *Repository) GetTagWithID(idStr, name string) (*Tag, error) {
id, err := NewIDFromString(idStr)
if err != nil {
return nil, err
}
tag, err := repo.getTag(id, name)
if err != nil {
return nil, err
}
return tag, nil
}
// GetTagInfos returns all tag infos of the repository.
func (repo *Repository) GetTagInfos(page, pageSize int) ([]*Tag, int, error) {
// TODO this a slow implementation, makes one git command per tag
@@ -142,6 +192,19 @@ func (repo *Repository) GetTagInfos(page, pageSize int) ([]*Tag, int, error) {
return tags, tagsTotal, nil
}
// GetTagType gets the type of the tag, either commit (simple) or tag (annotated)
func (repo *Repository) GetTagType(id SHA1) (string, error) {
// Get tag type
stdout, err := NewCommandContext(repo.Ctx, "cat-file", "-t", id.String()).RunInDir(repo.Path)
if err != nil {
return "", err
}
if len(stdout) == 0 {
return "", ErrNotExist{ID: id.String()}
}
return strings.TrimSpace(stdout), nil
}
// GetAnnotatedTag returns a Git tag by its SHA, must be an annotated tag
func (repo *Repository) GetAnnotatedTag(sha string) (*Tag, error) {
id, err := NewIDFromString(sha)

Some files were not shown because too many files have changed in this diff Show More