Merge branch 'master' of https://github.com/go-gitea/gitea
# Conflicts: # models/migrations/v51.go
This commit is contained in:
commit
172b1f054a
23
.drone.yml
23
.drone.yml
|
|
@ -55,6 +55,16 @@ pipeline:
|
||||||
when:
|
when:
|
||||||
event: [ push, tag, pull_request ]
|
event: [ push, tag, pull_request ]
|
||||||
|
|
||||||
|
build-without-gcc:
|
||||||
|
image: webhippie/golang:edge
|
||||||
|
pull: true
|
||||||
|
environment:
|
||||||
|
GOPATH: /srv/app
|
||||||
|
commands:
|
||||||
|
- go build -o gitea_no_gcc # test if build succeeds without the sqlite tag
|
||||||
|
when:
|
||||||
|
event: [ push, tag, pull_request ]
|
||||||
|
|
||||||
build:
|
build:
|
||||||
image: webhippie/golang:edge
|
image: webhippie/golang:edge
|
||||||
pull: true
|
pull: true
|
||||||
|
|
@ -86,6 +96,19 @@ pipeline:
|
||||||
event: [ push, pull_request ]
|
event: [ push, pull_request ]
|
||||||
branch: [ master ]
|
branch: [ master ]
|
||||||
|
|
||||||
|
test:
|
||||||
|
image: webhippie/golang:edge
|
||||||
|
pull: true
|
||||||
|
group: test
|
||||||
|
environment:
|
||||||
|
TAGS: bindata sqlite
|
||||||
|
GOPATH: /srv/app
|
||||||
|
commands:
|
||||||
|
- make test
|
||||||
|
when:
|
||||||
|
event: [ push, pull_request ]
|
||||||
|
branch: [ release/* ]
|
||||||
|
|
||||||
test:
|
test:
|
||||||
image: webhippie/golang:edge
|
image: webhippie/golang:edge
|
||||||
pull: true
|
pull: true
|
||||||
|
|
|
||||||
237
CHANGELOG.md
237
CHANGELOG.md
|
|
@ -1,5 +1,242 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [1.3.1](https://github.com/go-gitea/gitea/releases/tag/v1.3.1) - 2017-12-08
|
||||||
|
* BUGFIXES
|
||||||
|
* Sanitize logs for mirror sync (#3057, #3082) (#3078)
|
||||||
|
* Fix missing branch in release bug (#3108) (#3117)
|
||||||
|
* Fix repo indexer and submodule bug (#3107) (#3110)
|
||||||
|
* Fix legacy URL redirects (#3100) (#3106)
|
||||||
|
* Fix redis session failed (#3086) (#3089)
|
||||||
|
* Fix issue list branch link broken (#3061) (#3070)
|
||||||
|
* Fix missing password length check when change password (#3039) (#3071)
|
||||||
|
|
||||||
|
## [1.3.0](https://github.com/go-gitea/gitea/releases/tag/v1.3.0) - 2017-11-29
|
||||||
|
* BREAKING
|
||||||
|
* Make URL scheme unambiguous (#2408)
|
||||||
|
* FEATURE
|
||||||
|
* Add branch overiew page (#2108)
|
||||||
|
* Code/repo search (#2582)
|
||||||
|
* Add Activity page to repository (#2674)
|
||||||
|
* Issue Timetracking (#2211)
|
||||||
|
* Add orgmode document type on file view and readme (#2525)
|
||||||
|
* Add external markup render support (#2570)
|
||||||
|
* Implementation of discord webhook (#2402)
|
||||||
|
* Webhooks for repo creation/deletion (#1663)
|
||||||
|
* Complete push webhooks (#2530)
|
||||||
|
* Add possibility to record branch information in an issue (#780)
|
||||||
|
* Create new branch from branch selection dropdown (#2130)
|
||||||
|
* Implementation of all repositories of a user from user->settings (#1740)
|
||||||
|
* Add LFS object verification step after upload (#2868)
|
||||||
|
* Configurable SSH cipher suite (#913)
|
||||||
|
* Disable custom Git Hooks globally via configuration file (#2450)
|
||||||
|
* Sync releases table with tags on push and for mirrors (#2459)
|
||||||
|
* BUGFIXES
|
||||||
|
* Fix label comments for French locale (#3017)
|
||||||
|
* Remove duplicate "Max Diff Lines" from config view (#3001)
|
||||||
|
* Fix over-escaped characters (#2992)
|
||||||
|
* Fix go-get, src and raw urls to new scheme (#2986)
|
||||||
|
* Fix error when add user has full name to team (#2975)
|
||||||
|
* Fix files/commits of merged PRs (#2970)
|
||||||
|
* Update golang x/crypto dependencies - Fix SSH transport fail (#2951)
|
||||||
|
* Fix memcache support when value is returned as string always (#2950)
|
||||||
|
* Fix issue link rendering in commit messages (#2897)
|
||||||
|
* Fix adding a new authentication source after selecting OAuth (#2889)
|
||||||
|
* Fix new branch creation to new url scheme (#2884)
|
||||||
|
* Allow spaces in username for LDAP users (#2880)
|
||||||
|
* Fix LFS not returning correct content length when requesting a range … (#2864)
|
||||||
|
* Fix fork repository cycle to self (#2860)
|
||||||
|
* Fix click create pull request button 404 (#2859)
|
||||||
|
* Fix API raw file content access for default branch (#2849)
|
||||||
|
* Clean repository ROOT directory name with filepath.Clean (#2846)
|
||||||
|
* Fix API raw requests for commits and tags (#2841)
|
||||||
|
* Fix order of comments (#2835)
|
||||||
|
* Issue content should not be updated when closing with comment (#2833)
|
||||||
|
* Fix ordering in app.ini and fix run mode option (#2829)
|
||||||
|
* Fix redirect url of legacy commits route (#2825)
|
||||||
|
* Fix commits page url (#2823)
|
||||||
|
* Fix wrong translations (#2818)
|
||||||
|
* Fix dropdown menu position when explore repos (#2808)
|
||||||
|
* Fix Git LFS object/repo link storage in database and small refactoring (#2803)
|
||||||
|
* Use relative URLs for avatars on the dashboard (#2800)
|
||||||
|
* Add checks for commits with missing author and time (#2771)
|
||||||
|
* Fix emojify image URL (#2769)
|
||||||
|
* Hide unactive on explore users and some refactors (#2741)
|
||||||
|
* Fix IE unsupported javascript construction in branch dropdown (#2736)
|
||||||
|
* Only update mirror last update after successful sync (#2730)
|
||||||
|
* Fix semantic-ui style conflict with v-cloak (#2722)
|
||||||
|
* Fixing wrong translation on sort type oldest/latest (#2720)
|
||||||
|
* Fix PR, milestone and label functionality if issue unit is disabled (#2710)
|
||||||
|
* Fix plain readme didn't render correctly on repo home page (#2705)
|
||||||
|
* Fix organization removal from watch table migration (#2703)
|
||||||
|
* Fix repository search function (#2689)
|
||||||
|
* fix panic on gogs webhook creation (#2675)
|
||||||
|
* Fix orgnization user watch repository (#2670)
|
||||||
|
* GPG key email verification no longer case sensitive (#2661) (#2663)
|
||||||
|
* Fix index column deletion (#2651)
|
||||||
|
* table `pull_request` wasn't updated correctly (#2649)
|
||||||
|
* Fix go get response if only app URL is custom in configuration (#2634)
|
||||||
|
* Fix doubled issue tab introduced in migration v16 (#2611)
|
||||||
|
* Rewrite migrations to not depend on future code changes (#2604)
|
||||||
|
* Fix implementation of repo Home func (#2601)
|
||||||
|
* Fix translation upload to crowdin (#2599)
|
||||||
|
* Reduce usage of allcols on update (#2596)
|
||||||
|
* fix go get subpackage bug (#2584)
|
||||||
|
* Fix broken migration to add can_push field back to table (#2574)
|
||||||
|
* fix readme view bug (#2566)
|
||||||
|
* Fix sending mail with a non-latin display name. #2102 (#2559)
|
||||||
|
* Restricting access to fork functioanlity to users with Code access (#2534)
|
||||||
|
* fix updated update on public key (#2514)
|
||||||
|
* Added bucket name to s3 drone plugin (#2505)
|
||||||
|
* fixes 500 error on dashboard when using MSSQL (#2504)
|
||||||
|
* fix wrong rendering of commit detail page (#2503)
|
||||||
|
* Hotfix: Add time manually adds time in nanoseconds (#2499)
|
||||||
|
* Remove repository mirrors from "collaborative" list (#2497)
|
||||||
|
* fix release failed since the wrong token name (#2496)
|
||||||
|
* Fix slice out of bounds error in mailer (#2479)
|
||||||
|
* Fix #2470 (#2477)
|
||||||
|
* fix orgnization webhooks (#2422)
|
||||||
|
* fix webhook test (#2415)
|
||||||
|
* fix missing orgnization discord webhook (#2414)
|
||||||
|
* Fix route handler order (#2409)
|
||||||
|
* Prevent sending emails and notifications to inactive users (#2384)
|
||||||
|
* Move themes to plugin directory. Fixes #2372 (#2375)
|
||||||
|
* fix duplicated feed (#2370)
|
||||||
|
* Fix missing collabrative repos (#2367)
|
||||||
|
* Only check at least one email gpg key (#2266)
|
||||||
|
* don't check minimum key size when disabled (#1754)
|
||||||
|
* Fix run command race (#1470)
|
||||||
|
* fix .netrc authentication (#2700)
|
||||||
|
* Fix so that user can still fork his own repository to his organizations (#2699)
|
||||||
|
* Fix can_push value to false in protected_branch (#2560)
|
||||||
|
* Fix copy in email templates (#2801)
|
||||||
|
* Fix inconsistencies in user settings UI (#2901)
|
||||||
|
* Fix attachments icon size on zoom in/out (#2853)
|
||||||
|
* Fix ignored errors in API route (#2850)
|
||||||
|
* Fix activity css conflit with semantic ui (#2758)
|
||||||
|
* Fix notifications tabs according to semantic-ui docs (#2733)
|
||||||
|
* Fix typos in app.ini (#2732)
|
||||||
|
* Fix duplicated rel attribute (#2549)
|
||||||
|
* Fix tests code to prevent some runtime errors (#2381)
|
||||||
|
* ENHANCEMENT
|
||||||
|
* Memory usage improvements and lower minimal git requirement to 1.7.2 (#3013) (#3028)
|
||||||
|
* Set OpenID support on by default when installing new instance (#3010) (#3027)
|
||||||
|
* Use api.TrackedTime in API (#2807)
|
||||||
|
* Configurable SSH key exchange algorithm and MAC suite (#2806)
|
||||||
|
* Add Safari pinned tab icon (#2799)
|
||||||
|
* Improve force push detect when push (#2798)
|
||||||
|
* Add wrapping to long diff lines (#2789)
|
||||||
|
* Link members and repositories count to each page on org home. (#2787)
|
||||||
|
* Show Sendmail settings on admin config page (#2782)
|
||||||
|
* Add commit count caching (#2774)
|
||||||
|
* Use identicon image for default gravatar. (#2767)
|
||||||
|
* Add default ssh ciphers (#2761)
|
||||||
|
* Remove manual of unsupported option (#2757)
|
||||||
|
* Add search mode option to /api/repo/search (#2756)
|
||||||
|
* Move swagger-ui under /api/v1 (#2746)
|
||||||
|
* Add support for extra sendmail arguments (#2731)
|
||||||
|
* Use buffersize to reduce database connection when iterate (#2724)
|
||||||
|
* Render plain text README.txt monospaced (#2721)
|
||||||
|
* Integration test for activity page (#2704)
|
||||||
|
* Merge password and 2fa page on user settings (#2695)
|
||||||
|
* Allow custom SSH user in UI for built-in SSH server (#2617) (#2678)
|
||||||
|
* Refactor duplicated code in repo handlers (#2657)
|
||||||
|
* Replace deprecated Id method with ID (#2655)
|
||||||
|
* Remove redudant functions and code (#2652)
|
||||||
|
* hide navbar when only 1 sign-in method is available (#2444) (#2648)
|
||||||
|
* Change default sort order (#2647)
|
||||||
|
* Change pull description text (#2075) (#2646)
|
||||||
|
* Remove direct user adding to organization members (#2641)
|
||||||
|
* Use session when creating user (#2638)
|
||||||
|
* Use Semantic UI's Search component for user and repo search (#2636)
|
||||||
|
* Use AfterLoad instead of AfterSet on Structs (#2628)
|
||||||
|
* Remove redudant CheckUnit calls in router (#2627)
|
||||||
|
* Remove repo unit index (#2621)
|
||||||
|
* Remove redudant issue LoadAttributes() calls (#2614)
|
||||||
|
* Make indexer code more reusable (#2590)
|
||||||
|
* Use custom type and constants to hold available order by options (#2572)
|
||||||
|
* Use named ActionType constants in template helper (#2545)
|
||||||
|
* Make basic functionality work without JavaScript (#2541)
|
||||||
|
* Ctrl + Enter to submit forms (#2540)
|
||||||
|
* Automatically regenerate indexer for incompatible versions (#2524)
|
||||||
|
* Set default lfs content path to data/lfs (#2521)
|
||||||
|
* Convert spaces to tabs in footer.tmpl (#2520)
|
||||||
|
* Sort repository tree entries in natural way (#2506)
|
||||||
|
* Open external wiki in new window (#2489)
|
||||||
|
* Use created & updated instead BeforeInsert & BeforeUpdate (#2482)
|
||||||
|
* Hide branch on pull request view or create UI (#2454)
|
||||||
|
* improve protected branch to add whitelist support (#2451)
|
||||||
|
* some refactors for issue and comments (#2419)
|
||||||
|
* Restructure markup & markdown to prepare for multiple markup language… (#2411)
|
||||||
|
* Improve issue search (#2387)
|
||||||
|
* Add UseCompatSSHURI setting (#2356)
|
||||||
|
* Use custom search for each filter type in dashboard (#2343)
|
||||||
|
* Failed authentication are now properly logged (#2334)
|
||||||
|
* Add environment variable support for Docker image (#2201)
|
||||||
|
* Set session and indexers' data files rel to AppDataPath (#2192)
|
||||||
|
* Display commit status on landing page of repo (#1784)
|
||||||
|
* TESTING
|
||||||
|
* Add integration test for logging out (#2892)
|
||||||
|
* Integration test for user deleting account (#2891)
|
||||||
|
* Use different directories for session files in integration tests (#2834)
|
||||||
|
* Add deleted_branch table fixture (#2832)
|
||||||
|
* Include HTTP method in test error message (#2815)
|
||||||
|
* Add repository search unit and integration tests (#2575)
|
||||||
|
* Expand fixtures (#2571)
|
||||||
|
* Fix /api/repo/search integration tests (#2550)
|
||||||
|
* Make integration tests more user-friendly (#2536)
|
||||||
|
* Fix unit test race condition (#2516)
|
||||||
|
* Add missing fixture to clean gpg_key table (#2494)
|
||||||
|
* Hotfix for integration testing (#2473)
|
||||||
|
* Make repo private to not interfere with other tests (#2467)
|
||||||
|
* Error message for integration test (#2410)
|
||||||
|
* Fix "index out of range" runtime error in repo_list tests (#2376)
|
||||||
|
* Add git clone test on integration test (#1682)
|
||||||
|
* TRANSLATION
|
||||||
|
* Fix localization texts that contain semicolon (#2900)
|
||||||
|
* Fix activity locale (#2709)
|
||||||
|
* Update translation from crowdin (#2368)
|
||||||
|
* BUILD
|
||||||
|
* change the email and name to GitBot account. (#2848)
|
||||||
|
* Fix removing backslash before quotes in translations (#2831)
|
||||||
|
* add gitea remote in drone. (#2817)
|
||||||
|
* add remote name for git push. (#2816)
|
||||||
|
* Launch Gitea with custom UID/GID for 'git' user (fixes #2286) (#2791)
|
||||||
|
* Download and pushing translations (#2727)
|
||||||
|
* Automatic update of translations (#2585)
|
||||||
|
* Add pre-build step for nodejs stuff (#2581)
|
||||||
|
* Compress css with nodejs (#2580)
|
||||||
|
* Remove go version check for make fmt (#2558)
|
||||||
|
* Fix lint errors (#2547)
|
||||||
|
* Always run fmt check in CI (#2546)
|
||||||
|
* Fix fmt errors (#2544)
|
||||||
|
* add codecov.io service. (#2493)
|
||||||
|
* Fix some tests : make coverage -> test (#2492)
|
||||||
|
* Fix fmt error in mailer (#2490)
|
||||||
|
* Allow changing integration test database connection using env variables (#2484)
|
||||||
|
* Add changelog config file for generate changelog (#2461)
|
||||||
|
* Changes for latest DroneCI (#2362)
|
||||||
|
* Use standard lessc and minify CSS using Node.js (#2337)
|
||||||
|
* DOCS
|
||||||
|
* Update screenshots on README (#2910)
|
||||||
|
* Gogs -> Gitea (#2909)
|
||||||
|
* Update swagger documentation (#2899)
|
||||||
|
* Fix typo (#2810)
|
||||||
|
* Fix Polish language name spelling (#2766)
|
||||||
|
* Fix Various Grammar Issues and Adjust Unnatural Wording (#2737)
|
||||||
|
* Add maintainer label for docker file (#2658)
|
||||||
|
* Link to gitea-specific Vagrant example (#2624)
|
||||||
|
* add release notes of v1.1.4 (#2463)
|
||||||
|
* Wrap most paragraphs to 80 columns (#2396)
|
||||||
|
* Update CONTRIBUTING following #2329 discussion (#2394)
|
||||||
|
* Update hard-coded version to 1.3.0+dev (#2390)
|
||||||
|
* Clarify Translation Process. Also fix branch names (#2378)
|
||||||
|
* Admin grammar fixes and improvements (#2056)
|
||||||
|
* MISC
|
||||||
|
* Sync MaxGitDiffLineCharacters with conf/app.ini (#2779)
|
||||||
|
* Dockerfile: Updated alpine image to 3.6. (#2486)
|
||||||
|
* Basic VSCode configuration for building and debugging (#2483)
|
||||||
|
* Added vendor dir for js/css libs; Documented sources (#1484) (#2241)
|
||||||
|
|
||||||
## [1.2.3](https://github.com/go-gitea/gitea/releases/tag/v1.2.3) - 2017-11-03
|
## [1.2.3](https://github.com/go-gitea/gitea/releases/tag/v1.2.3) - 2017-11-03
|
||||||
* BUGFIXES
|
* BUGFIXES
|
||||||
* Only require one email when validating GPG key (#2266, #2467, #2663) (#2788)
|
* Only require one email when validating GPG key (#2266, #2467, #2663) (#2788)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
FROM alpine:3.6
|
FROM alpine:3.7
|
||||||
LABEL maintainer="The Gitea Authors"
|
LABEL maintainer="The Gitea Authors"
|
||||||
|
|
||||||
EXPOSE 22 3000
|
EXPOSE 22 3000
|
||||||
|
|
|
||||||
4
Makefile
4
Makefile
|
|
@ -131,7 +131,7 @@ fmt-check:
|
||||||
|
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
test:
|
test:
|
||||||
$(GO) test $(PACKAGES)
|
$(GO) test -tags=sqlite $(PACKAGES)
|
||||||
|
|
||||||
.PHONY: coverage
|
.PHONY: coverage
|
||||||
coverage:
|
coverage:
|
||||||
|
|
@ -142,7 +142,7 @@ coverage:
|
||||||
|
|
||||||
.PHONY: unit-test-coverage
|
.PHONY: unit-test-coverage
|
||||||
unit-test-coverage:
|
unit-test-coverage:
|
||||||
for PKG in $(PACKAGES); do $(GO) test -cover -coverprofile $$GOPATH/src/$$PKG/coverage.out $$PKG || exit 1; done;
|
for PKG in $(PACKAGES); do $(GO) test -tags=sqlite -cover -coverprofile $$GOPATH/src/$$PKG/coverage.out $$PKG || exit 1; done;
|
||||||
|
|
||||||
.PHONY: test-vendor
|
.PHONY: test-vendor
|
||||||
test-vendor:
|
test-vendor:
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/private"
|
"code.gitea.io/gitea/modules/private"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/Unknwon/com"
|
"github.com/Unknwon/com"
|
||||||
"github.com/dgrijalva/jwt-go"
|
"github.com/dgrijalva/jwt-go"
|
||||||
|
|
@ -219,8 +220,8 @@ func runServ(c *cli.Context) error {
|
||||||
fail("Internal error", "GetDeployKey: %v", err)
|
fail("Internal error", "GetDeployKey: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
deployKey.Updated = time.Now()
|
deployKey.UpdatedUnix = util.TimeStampNow()
|
||||||
if err = models.UpdateDeployKey(deployKey); err != nil {
|
if err = models.UpdateDeployKeyCols(deployKey, "updated_unix"); err != nil {
|
||||||
fail("Internal error", "UpdateDeployKey: %v", err)
|
fail("Internal error", "UpdateDeployKey: %v", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
30
cmd/web.go
30
cmd/web.go
|
|
@ -19,8 +19,10 @@ import (
|
||||||
"code.gitea.io/gitea/routers"
|
"code.gitea.io/gitea/routers"
|
||||||
"code.gitea.io/gitea/routers/routes"
|
"code.gitea.io/gitea/routers/routes"
|
||||||
|
|
||||||
|
"github.com/Unknwon/com"
|
||||||
context2 "github.com/gorilla/context"
|
context2 "github.com/gorilla/context"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
|
ini "gopkg.in/ini.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdWeb represents the available web sub-command.
|
// CmdWeb represents the available web sub-command.
|
||||||
|
|
@ -69,6 +71,34 @@ func runWeb(ctx *cli.Context) error {
|
||||||
if ctx.IsSet("port") {
|
if ctx.IsSet("port") {
|
||||||
setting.AppURL = strings.Replace(setting.AppURL, setting.HTTPPort, ctx.String("port"), 1)
|
setting.AppURL = strings.Replace(setting.AppURL, setting.HTTPPort, ctx.String("port"), 1)
|
||||||
setting.HTTPPort = ctx.String("port")
|
setting.HTTPPort = ctx.String("port")
|
||||||
|
|
||||||
|
switch setting.Protocol {
|
||||||
|
case setting.UnixSocket:
|
||||||
|
case setting.FCGI:
|
||||||
|
default:
|
||||||
|
// Save LOCAL_ROOT_URL if port changed
|
||||||
|
cfg := ini.Empty()
|
||||||
|
if com.IsFile(setting.CustomConf) {
|
||||||
|
// Keeps custom settings if there is already something.
|
||||||
|
if err := cfg.Append(setting.CustomConf); err != nil {
|
||||||
|
return fmt.Errorf("Failed to load custom conf '%s': %v", setting.CustomConf, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultLocalURL := string(setting.Protocol) + "://"
|
||||||
|
if setting.HTTPAddr == "0.0.0.0" {
|
||||||
|
defaultLocalURL += "localhost"
|
||||||
|
} else {
|
||||||
|
defaultLocalURL += setting.HTTPAddr
|
||||||
|
}
|
||||||
|
defaultLocalURL += ":" + setting.HTTPPort + "/"
|
||||||
|
|
||||||
|
cfg.Section("server").Key("LOCAL_ROOT_URL").SetValue(defaultLocalURL)
|
||||||
|
|
||||||
|
if err := cfg.SaveTo(setting.CustomConf); err != nil {
|
||||||
|
return fmt.Errorf("Error saving generated JWT Secret to custom config: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var listenAddr string
|
var listenAddr string
|
||||||
|
|
|
||||||
|
|
@ -175,14 +175,14 @@ LFS_START_SERVER = false
|
||||||
; Where your lfs files put on, default is data/lfs.
|
; Where your lfs files put on, default is data/lfs.
|
||||||
LFS_CONTENT_PATH = data/lfs
|
LFS_CONTENT_PATH = data/lfs
|
||||||
; LFS authentication secret, changed this to yourself.
|
; LFS authentication secret, changed this to yourself.
|
||||||
LFS_JWT_SECRET =
|
LFS_JWT_SECRET =
|
||||||
|
|
||||||
; Define allowed algorithms and their minimum key length (use -1 to disable a type)
|
; Define allowed algorithms and their minimum key length (use -1 to disable a type)
|
||||||
[ssh.minimum_key_sizes]
|
[ssh.minimum_key_sizes]
|
||||||
ED25519 = 256
|
ED25519 = 256
|
||||||
ECDSA = 256
|
ECDSA = 256
|
||||||
RSA = 2048
|
RSA = 2048
|
||||||
DSA = 1024
|
DSA = 1024
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
; Either "mysql", "postgres", "mssql" or "sqlite3", it's your choice
|
; Either "mysql", "postgres", "mssql" or "sqlite3", it's your choice
|
||||||
|
|
@ -496,7 +496,11 @@ SCHEDULE = @every 24h
|
||||||
|
|
||||||
; Clean up old repository archives
|
; Clean up old repository archives
|
||||||
[cron.archive_cleanup]
|
[cron.archive_cleanup]
|
||||||
|
; Whether to enable the job
|
||||||
|
ENABLED = true
|
||||||
|
; Whether to always run at least once at start up time (if ENABLED)
|
||||||
RUN_AT_START = true
|
RUN_AT_START = true
|
||||||
|
; Time interval for job to run
|
||||||
SCHEDULE = @every 24h
|
SCHEDULE = @every 24h
|
||||||
; Archives created more than OLDER_THAN ago are subject to deletion
|
; Archives created more than OLDER_THAN ago are subject to deletion
|
||||||
OLDER_THAN = 24h
|
OLDER_THAN = 24h
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,10 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
|
||||||
- `FORCE_PRIVATE`: Force every new repository to be private.
|
- `FORCE_PRIVATE`: Force every new repository to be private.
|
||||||
- `MAX_CREATION_LIMIT`: Global maximum creation limit of repositories per user, `-1` means no limit.
|
- `MAX_CREATION_LIMIT`: Global maximum creation limit of repositories per user, `-1` means no limit.
|
||||||
- `PULL_REQUEST_QUEUE_LENGTH`:exclamation:: Length of pull request patch test queue, make it as large as possible.
|
- `PULL_REQUEST_QUEUE_LENGTH`:exclamation:: Length of pull request patch test queue, make it as large as possible.
|
||||||
|
- `MIRROR_QUEUE_LENGTH`: Patch test queue length, increase if pull request patch testing starts hanging. Defaults to 1000.
|
||||||
|
- `PREFERRED_LICENSES`: Preferred Licenses to place at the top of the List. Name must match file name in conf/license or custom/conf/license. Defaults to 'Apache License 2.0,MIT License'
|
||||||
|
- `DISABLE_HTTP_GIT`: Disable ability to interact with repositories by HTTP protocol. Defaults to false
|
||||||
|
- `USE_COMPAT_SSH_URI`: Force ssh:// clone url instead of scp-style uri when default SSH port is used. Defaults to false.
|
||||||
|
|
||||||
## UI (`ui`)
|
## UI (`ui`)
|
||||||
|
|
||||||
|
|
@ -189,6 +193,13 @@ Note: Actually, Gitea supports only SMTP with STARTTLS.
|
||||||
- `ENABLED`: Enable this to run cron tasks periodically.
|
- `ENABLED`: Enable this to run cron tasks periodically.
|
||||||
- `RUN_AT_START`: Enable this to run cron tasks at start time.
|
- `RUN_AT_START`: Enable this to run cron tasks at start time.
|
||||||
|
|
||||||
|
### Cron - Cleanup old repository archives (`cron.archive_cleanup`)
|
||||||
|
|
||||||
|
- `ENABLED`: Enable service. Defaults to true.
|
||||||
|
- `RUN_AT_START`: Run tasks at start up time (if ENABLED). Defaults to true.
|
||||||
|
- `SCHEDULE`: Cron syntax for scheduling repository archive cleanup, e.g. `@every 1h`. Defaults to `@every 24h`.
|
||||||
|
- `OLDER_THAN`: Archives created more than `OLDER_THAN` ago are subject to deletion, e.g. `12h`. Defaults to `24h`.
|
||||||
|
|
||||||
### Cron - Update Mirrors (`cron.update_mirrors`)
|
### Cron - Update Mirrors (`cron.update_mirrors`)
|
||||||
|
|
||||||
- `SCHEDULE`: Cron syntax for scheduling update mirrors, e.g. `@every 1h`.
|
- `SCHEDULE`: Cron syntax for scheduling update mirrors, e.g. `@every 1h`.
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ func TestAPILFSLocksLogged(t *testing.T) {
|
||||||
assert.Len(t, lfsLocks.Locks, test.totalCount)
|
assert.Len(t, lfsLocks.Locks, test.totalCount)
|
||||||
for i, lock := range lfsLocks.Locks {
|
for i, lock := range lfsLocks.Locks {
|
||||||
assert.EqualValues(t, test.locksOwners[i].DisplayName(), lock.Owner.Name)
|
assert.EqualValues(t, test.locksOwners[i].DisplayName(), lock.Owner.Name)
|
||||||
assert.WithinDuration(t, test.locksTimes[i], lock.LockedAt, 1*time.Second)
|
assert.WithinDuration(t, test.locksTimes[i], lock.LockedAt, 3*time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/%s.git/info/lfs/locks/verify", test.repo.FullName()), map[string]string{})
|
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/%s.git/info/lfs/locks/verify", test.repo.FullName()), map[string]string{})
|
||||||
|
|
|
||||||
|
|
@ -6,27 +6,32 @@ package integrations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/git"
|
"code.gitea.io/git"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
api "code.gitea.io/sdk/gitea"
|
||||||
|
|
||||||
"github.com/Unknwon/com"
|
"github.com/Unknwon/com"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func onGiteaWebRun(t *testing.T, callback func(*testing.T, string)) {
|
func onGiteaWebRun(t *testing.T, callback func(*testing.T, *url.URL)) {
|
||||||
s := http.Server{
|
s := http.Server{
|
||||||
Handler: mac,
|
Handler: mac,
|
||||||
}
|
}
|
||||||
|
|
||||||
listener, err := net.Listen("tcp", "")
|
u, err := url.Parse(setting.AppURL)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
listener, err := net.Listen("tcp", u.Host)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|
@ -37,24 +42,144 @@ func onGiteaWebRun(t *testing.T, callback func(*testing.T, string)) {
|
||||||
|
|
||||||
go s.Serve(listener)
|
go s.Serve(listener)
|
||||||
|
|
||||||
_, port, err := net.SplitHostPort(listener.Addr().String())
|
callback(t, u)
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
callback(t, fmt.Sprintf("http://localhost:%s/", port))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClone_ViaHTTP_NoLogin(t *testing.T) {
|
func TestGit(t *testing.T) {
|
||||||
prepareTestEnv(t)
|
prepareTestEnv(t)
|
||||||
|
|
||||||
onGiteaWebRun(t, func(t *testing.T, urlPrefix string) {
|
onGiteaWebRun(t, func(t *testing.T, u *url.URL) {
|
||||||
dstPath, err := ioutil.TempDir("", "repo1")
|
dstPath, err := ioutil.TempDir("", "repo-tmp-17")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer os.RemoveAll(dstPath)
|
defer os.RemoveAll(dstPath)
|
||||||
|
u.Path = "user2/repo1.git"
|
||||||
|
|
||||||
err = git.Clone(fmt.Sprintf("%suser2/repo1.git", urlPrefix),
|
t.Run("Standard", func(t *testing.T) {
|
||||||
dstPath, git.CloneRepoOptions{})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
assert.True(t, com.IsExist(filepath.Join(dstPath, "README.md")))
|
t.Run("CloneNoLogin", func(t *testing.T) {
|
||||||
|
dstLocalPath, err := ioutil.TempDir("", "repo1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer os.RemoveAll(dstLocalPath)
|
||||||
|
err = git.Clone(u.String(), dstLocalPath, git.CloneRepoOptions{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, com.IsExist(filepath.Join(dstLocalPath, "README.md")))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("CreateRepo", func(t *testing.T) {
|
||||||
|
session := loginUser(t, "user2")
|
||||||
|
req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos", &api.CreateRepoOption{
|
||||||
|
AutoInit: true,
|
||||||
|
Description: "Temporary repo",
|
||||||
|
Name: "repo-tmp-17",
|
||||||
|
Private: false,
|
||||||
|
Gitignores: "",
|
||||||
|
License: "WTFPL",
|
||||||
|
Readme: "Default",
|
||||||
|
})
|
||||||
|
session.MakeRequest(t, req, http.StatusCreated)
|
||||||
|
})
|
||||||
|
|
||||||
|
u.Path = "user2/repo-tmp-17.git"
|
||||||
|
u.User = url.UserPassword("user2", userPassword)
|
||||||
|
t.Run("Clone", func(t *testing.T) {
|
||||||
|
err = git.Clone(u.String(), dstPath, git.CloneRepoOptions{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, com.IsExist(filepath.Join(dstPath, "README.md")))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("PushCommit", func(t *testing.T) {
|
||||||
|
data := make([]byte, 1024)
|
||||||
|
_, err := rand.Read(data)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
tmpFile, err := ioutil.TempFile(dstPath, "data-file-")
|
||||||
|
defer tmpFile.Close()
|
||||||
|
_, err = tmpFile.Write(data)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
//Commit
|
||||||
|
err = git.AddChanges(dstPath, false, filepath.Base(tmpFile.Name()))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = git.CommitChanges(dstPath, git.CommitChangesOptions{
|
||||||
|
Committer: &git.Signature{
|
||||||
|
Email: "user2@example.com",
|
||||||
|
Name: "User Two",
|
||||||
|
When: time.Now(),
|
||||||
|
},
|
||||||
|
Author: &git.Signature{
|
||||||
|
Email: "user2@example.com",
|
||||||
|
Name: "User Two",
|
||||||
|
When: time.Now(),
|
||||||
|
},
|
||||||
|
Message: "Testing commit",
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
//Push
|
||||||
|
err = git.Push(dstPath, git.PushOptions{
|
||||||
|
Branch: "master",
|
||||||
|
Remote: u.String(),
|
||||||
|
Force: false,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
t.Run("LFS", func(t *testing.T) {
|
||||||
|
t.Run("PushCommit", func(t *testing.T) {
|
||||||
|
/* Generate random file */
|
||||||
|
data := make([]byte, 1024)
|
||||||
|
_, err := rand.Read(data)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
tmpFile, err := ioutil.TempFile(dstPath, "data-file-")
|
||||||
|
defer tmpFile.Close()
|
||||||
|
_, err = tmpFile.Write(data)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
//Setup git LFS
|
||||||
|
_, err = git.NewCommand("lfs").AddArguments("install").RunInDir(dstPath)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = git.NewCommand("lfs").AddArguments("track", "data-file-*").RunInDir(dstPath)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
//Commit
|
||||||
|
err = git.AddChanges(dstPath, false, ".gitattributes", filepath.Base(tmpFile.Name()))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = git.CommitChanges(dstPath, git.CommitChangesOptions{
|
||||||
|
Committer: &git.Signature{
|
||||||
|
Email: "user2@example.com",
|
||||||
|
Name: "User Two",
|
||||||
|
When: time.Now(),
|
||||||
|
},
|
||||||
|
Author: &git.Signature{
|
||||||
|
Email: "user2@example.com",
|
||||||
|
Name: "User Two",
|
||||||
|
When: time.Now(),
|
||||||
|
},
|
||||||
|
Message: "Testing LFS ",
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
//Push
|
||||||
|
u.User = url.UserPassword("user2", userPassword)
|
||||||
|
err = git.Push(dstPath, git.PushOptions{
|
||||||
|
Branch: "master",
|
||||||
|
Remote: u.String(),
|
||||||
|
Force: false,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
})
|
||||||
|
t.Run("Locks", func(t *testing.T) {
|
||||||
|
_, err = git.NewCommand("remote").AddArguments("set-url", "origin", u.String()).RunInDir(dstPath) //TODO add test ssh git-lfs-creds
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = git.NewCommand("lfs").AddArguments("locks").RunInDir(dstPath)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = git.NewCommand("lfs").AddArguments("lock", "README.md").RunInDir(dstPath)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = git.NewCommand("lfs").AddArguments("locks").RunInDir(dstPath)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = git.NewCommand("lfs").AddArguments("unlock", "README.md").RunInDir(dstPath)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
"$GITEA_ROOT/gitea" hook --config='integrations/app.ini' post-receive
|
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" post-receive
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
"$GITEA_ROOT/gitea" hook --config='integrations/app.ini' pre-receive
|
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" pre-receive
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
"$GITEA_ROOT/gitea" hook --config='integrations/app.ini' update $1 $2 $3
|
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" update $1 $2 $3
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
"$GITEA_ROOT/gitea" hook --config='integrations/app.ini' post-receive
|
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" post-receive
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
"$GITEA_ROOT/gitea" hook --config='integrations/app.ini' pre-receive
|
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" pre-receive
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
"$GITEA_ROOT/gitea" hook --config='integrations/app.ini' update $1 $2 $3
|
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" update $1 $2 $3
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
"$GITEA_ROOT/gitea" hook --config='integrations/app.ini' post-receive
|
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" post-receive
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
"$GITEA_ROOT/gitea" hook --config='integrations/app.ini' pre-receive
|
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" pre-receive
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
"$GITEA_ROOT/gitea" hook --config='integrations/app.ini' update $1 $2 $3
|
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" update $1 $2 $3
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"code.gitea.io/gitea/routers"
|
"code.gitea.io/gitea/routers"
|
||||||
"code.gitea.io/gitea/routers/routes"
|
"code.gitea.io/gitea/routers/routes"
|
||||||
|
|
||||||
|
"github.com/PuerkitoBio/goquery"
|
||||||
"github.com/Unknwon/com"
|
"github.com/Unknwon/com"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/macaron.v1"
|
"gopkg.in/macaron.v1"
|
||||||
|
|
@ -136,6 +137,7 @@ func initIntegrationTest() {
|
||||||
func prepareTestEnv(t testing.TB) {
|
func prepareTestEnv(t testing.TB) {
|
||||||
assert.NoError(t, models.LoadFixtures())
|
assert.NoError(t, models.LoadFixtures())
|
||||||
assert.NoError(t, os.RemoveAll(setting.RepoRootPath))
|
assert.NoError(t, os.RemoveAll(setting.RepoRootPath))
|
||||||
|
assert.NoError(t, os.RemoveAll(models.LocalCopyPath()))
|
||||||
|
|
||||||
assert.NoError(t, com.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"),
|
assert.NoError(t, com.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"),
|
||||||
setting.RepoRootPath))
|
setting.RepoRootPath))
|
||||||
|
|
@ -259,12 +261,37 @@ func MakeRequest(t testing.TB, req *http.Request, expectedStatus int) *httptest.
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
mac.ServeHTTP(recorder, req)
|
mac.ServeHTTP(recorder, req)
|
||||||
if expectedStatus != NoExpectedStatus {
|
if expectedStatus != NoExpectedStatus {
|
||||||
assert.EqualValues(t, expectedStatus, recorder.Code,
|
if !assert.EqualValues(t, expectedStatus, recorder.Code,
|
||||||
"Request: %s %s", req.Method, req.URL.String())
|
"Request: %s %s", req.Method, req.URL.String()) {
|
||||||
|
logUnexpectedResponse(t, recorder)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return recorder
|
return recorder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// logUnexpectedResponse logs the contents of an unexpected response.
|
||||||
|
func logUnexpectedResponse(t testing.TB, recorder *httptest.ResponseRecorder) {
|
||||||
|
respBytes := recorder.Body.Bytes()
|
||||||
|
if len(respBytes) == 0 {
|
||||||
|
return
|
||||||
|
} else if len(respBytes) < 500 {
|
||||||
|
// if body is short, just log the whole thing
|
||||||
|
t.Log("Response:", string(respBytes))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// log the "flash" error message, if one exists
|
||||||
|
// we must create a new buffer, so that we don't "use up" resp.Body
|
||||||
|
htmlDoc, err := goquery.NewDocumentFromReader(bytes.NewBuffer(respBytes))
|
||||||
|
if err != nil {
|
||||||
|
return // probably a non-HTML response
|
||||||
|
}
|
||||||
|
errMsg := htmlDoc.Find(".ui.negative.message").Text()
|
||||||
|
if len(errMsg) > 0 {
|
||||||
|
t.Log("A flash error message was found:", errMsg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func DecodeJSON(t testing.TB, resp *httptest.ResponseRecorder, v interface{}) {
|
func DecodeJSON(t testing.TB, resp *httptest.ResponseRecorder, v interface{}) {
|
||||||
decoder := json.NewDecoder(resp.Body)
|
decoder := json.NewDecoder(resp.Body)
|
||||||
assert.NoError(t, decoder.Decode(v))
|
assert.NoError(t, decoder.Decode(v))
|
||||||
|
|
@ -276,9 +303,3 @@ func GetCSRF(t testing.TB, session *TestSession, urlStr string) string {
|
||||||
doc := NewHTMLParser(t, resp.Body)
|
doc := NewHTMLParser(t, resp.Body)
|
||||||
return doc.GetCSRF()
|
return doc.GetCSRF()
|
||||||
}
|
}
|
||||||
|
|
||||||
func RedirectURL(t testing.TB, resp *httptest.ResponseRecorder) string {
|
|
||||||
urlSlice := resp.HeaderMap["Location"]
|
|
||||||
assert.NotEmpty(t, urlSlice, "No redirect URL founds")
|
|
||||||
return urlSlice[0]
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/test"
|
||||||
|
|
||||||
"github.com/PuerkitoBio/goquery"
|
"github.com/PuerkitoBio/goquery"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
@ -122,7 +123,7 @@ func testNewIssue(t *testing.T, session *TestSession, user, repo, title, content
|
||||||
})
|
})
|
||||||
resp = session.MakeRequest(t, req, http.StatusFound)
|
resp = session.MakeRequest(t, req, http.StatusFound)
|
||||||
|
|
||||||
issueURL := RedirectURL(t, resp)
|
issueURL := test.RedirectURL(resp)
|
||||||
req = NewRequest(t, "GET", issueURL)
|
req = NewRequest(t, "GET", issueURL)
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
|
@ -153,7 +154,7 @@ func testIssueAddComment(t *testing.T, session *TestSession, issueURL, content,
|
||||||
})
|
})
|
||||||
resp = session.MakeRequest(t, req, http.StatusFound)
|
resp = session.MakeRequest(t, req, http.StatusFound)
|
||||||
|
|
||||||
req = NewRequest(t, "GET", RedirectURL(t, resp))
|
req = NewRequest(t, "GET", test.RedirectURL(resp))
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
htmlDoc = NewHTMLParser(t, resp.Body)
|
htmlDoc = NewHTMLParser(t, resp.Body)
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/test"
|
||||||
api "code.gitea.io/sdk/gitea"
|
api "code.gitea.io/sdk/gitea"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
@ -46,13 +47,15 @@ func TestRedirectsNoLogin(t *testing.T) {
|
||||||
prepareTestEnv(t)
|
prepareTestEnv(t)
|
||||||
|
|
||||||
var redirects = map[string]string{
|
var redirects = map[string]string{
|
||||||
"/user2/repo1/commits/master": "/user2/repo1/commits/branch/master",
|
"/user2/repo1/commits/master": "/user2/repo1/commits/branch/master",
|
||||||
"/user2/repo1/src/master": "/user2/repo1/src/branch/master",
|
"/user2/repo1/src/master": "/user2/repo1/src/branch/master",
|
||||||
|
"/user2/repo1/src/master/file.txt": "/user2/repo1/src/branch/master/file.txt",
|
||||||
|
"/user2/repo1/src/master/directory/file.txt": "/user2/repo1/src/branch/master/directory/file.txt",
|
||||||
}
|
}
|
||||||
for link, redirectLink := range redirects {
|
for link, redirectLink := range redirects {
|
||||||
req := NewRequest(t, "GET", link)
|
req := NewRequest(t, "GET", link)
|
||||||
resp := MakeRequest(t, req, http.StatusFound)
|
resp := MakeRequest(t, req, http.StatusFound)
|
||||||
assert.EqualValues(t, path.Join(setting.AppSubURL, redirectLink), RedirectURL(t, resp))
|
assert.EqualValues(t, path.Join(setting.AppSubURL, redirectLink), test.RedirectURL(resp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/test"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -54,7 +56,7 @@ func TestPullMerge(t *testing.T) {
|
||||||
|
|
||||||
resp := testPullCreate(t, session, "user1", "repo1", "master")
|
resp := testPullCreate(t, session, "user1", "repo1", "master")
|
||||||
|
|
||||||
elem := strings.Split(RedirectURL(t, resp), "/")
|
elem := strings.Split(test.RedirectURL(resp), "/")
|
||||||
assert.EqualValues(t, "pulls", elem[3])
|
assert.EqualValues(t, "pulls", elem[3])
|
||||||
testPullMerge(t, session, elem[1], elem[2], elem[4])
|
testPullMerge(t, session, elem[1], elem[2], elem[4])
|
||||||
}
|
}
|
||||||
|
|
@ -67,7 +69,7 @@ func TestPullCleanUpAfterMerge(t *testing.T) {
|
||||||
|
|
||||||
resp := testPullCreate(t, session, "user1", "repo1", "feature/test")
|
resp := testPullCreate(t, session, "user1", "repo1", "feature/test")
|
||||||
|
|
||||||
elem := strings.Split(RedirectURL(t, resp), "/")
|
elem := strings.Split(test.RedirectURL(resp), "/")
|
||||||
assert.EqualValues(t, "pulls", elem[3])
|
assert.EqualValues(t, "pulls", elem[3])
|
||||||
testPullMerge(t, session, elem[1], elem[2], elem[4])
|
testPullMerge(t, session, elem[1], elem[2], elem[4])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/test"
|
||||||
|
|
||||||
"github.com/Unknwon/i18n"
|
"github.com/Unknwon/i18n"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
@ -38,7 +40,7 @@ func createNewRelease(t *testing.T, session *TestSession, repoURL, tag, title st
|
||||||
|
|
||||||
resp = session.MakeRequest(t, req, http.StatusFound)
|
resp = session.MakeRequest(t, req, http.StatusFound)
|
||||||
|
|
||||||
RedirectURL(t, resp) // check that redirect URL exists
|
test.RedirectURL(resp) // check that redirect URL exists
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkLatestReleaseAndCount(t *testing.T, session *TestSession, repoURL, version, label string, count int) {
|
func checkLatestReleaseAndCount(t *testing.T, session *TestSession, repoURL, version, label string, count int) {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/test"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -20,7 +22,7 @@ func TestRepoActivity(t *testing.T) {
|
||||||
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
||||||
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
|
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
|
||||||
resp := testPullCreate(t, session, "user1", "repo1", "master")
|
resp := testPullCreate(t, session, "user1", "repo1", "master")
|
||||||
elem := strings.Split(RedirectURL(t, resp), "/")
|
elem := strings.Split(test.RedirectURL(resp), "/")
|
||||||
assert.EqualValues(t, "pulls", elem[3])
|
assert.EqualValues(t, "pulls", elem[3])
|
||||||
testPullMerge(t, session, elem[1], elem[2], elem[4])
|
testPullMerge(t, session, elem[1], elem[2], elem[4])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/test"
|
||||||
|
|
||||||
"github.com/Unknwon/i18n"
|
"github.com/Unknwon/i18n"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
@ -29,7 +31,7 @@ func testCreateBranch(t *testing.T, session *TestSession, user, repo, oldRefSubU
|
||||||
if expectedStatus != http.StatusFound {
|
if expectedStatus != http.StatusFound {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return RedirectURL(t, resp)
|
return test.RedirectURL(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateBranch(t *testing.T) {
|
func TestCreateBranch(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/test"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -47,7 +49,7 @@ func testViewTimetrackingControls(t *testing.T, session *TestSession, user, repo
|
||||||
if canTrackTime {
|
if canTrackTime {
|
||||||
resp = session.MakeRequest(t, req, http.StatusSeeOther)
|
resp = session.MakeRequest(t, req, http.StatusSeeOther)
|
||||||
|
|
||||||
req = NewRequest(t, "GET", RedirectURL(t, resp))
|
req = NewRequest(t, "GET", test.RedirectURL(resp))
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
htmlDoc = NewHTMLParser(t, resp.Body)
|
htmlDoc = NewHTMLParser(t, resp.Body)
|
||||||
|
|
||||||
|
|
@ -65,7 +67,7 @@ func testViewTimetrackingControls(t *testing.T, session *TestSession, user, repo
|
||||||
})
|
})
|
||||||
resp = session.MakeRequest(t, req, http.StatusSeeOther)
|
resp = session.MakeRequest(t, req, http.StatusSeeOther)
|
||||||
|
|
||||||
req = NewRequest(t, "GET", RedirectURL(t, resp))
|
req = NewRequest(t, "GET", test.RedirectURL(resp))
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
htmlDoc = NewHTMLParser(t, resp.Body)
|
htmlDoc = NewHTMLParser(t, resp.Body)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
|
"code.gitea.io/gitea/modules/test"
|
||||||
|
|
||||||
"github.com/Unknwon/i18n"
|
"github.com/Unknwon/i18n"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
@ -86,7 +87,7 @@ func TestRenameReservedUsername(t *testing.T) {
|
||||||
})
|
})
|
||||||
resp := session.MakeRequest(t, req, http.StatusFound)
|
resp := session.MakeRequest(t, req, http.StatusFound)
|
||||||
|
|
||||||
req = NewRequest(t, "GET", RedirectURL(t, resp))
|
req = NewRequest(t, "GET", test.RedirectURL(resp))
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||||
assert.Contains(t,
|
assert.Contains(t,
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
api "code.gitea.io/sdk/gitea"
|
api "code.gitea.io/sdk/gitea"
|
||||||
|
|
||||||
"github.com/Unknwon/com"
|
"github.com/Unknwon/com"
|
||||||
|
|
@ -85,15 +86,9 @@ type Action struct {
|
||||||
Comment *Comment `xorm:"-"`
|
Comment *Comment `xorm:"-"`
|
||||||
IsDeleted bool `xorm:"INDEX NOT NULL DEFAULT false"`
|
IsDeleted bool `xorm:"INDEX NOT NULL DEFAULT false"`
|
||||||
RefName string
|
RefName string
|
||||||
IsPrivate bool `xorm:"INDEX NOT NULL DEFAULT false"`
|
IsPrivate bool `xorm:"INDEX NOT NULL DEFAULT false"`
|
||||||
Content string `xorm:"TEXT"`
|
Content string `xorm:"TEXT"`
|
||||||
Created time.Time `xorm:"-"`
|
CreatedUnix util.TimeStamp `xorm:"INDEX created"`
|
||||||
CreatedUnix int64 `xorm:"INDEX created"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
|
||||||
func (a *Action) AfterLoad() {
|
|
||||||
a.Created = time.Unix(a.CreatedUnix, 0).Local()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOpType gets the ActionType of this action.
|
// GetOpType gets the ActionType of this action.
|
||||||
|
|
@ -229,7 +224,7 @@ func (a *Action) GetContent() string {
|
||||||
|
|
||||||
// GetCreate returns the action creation time.
|
// GetCreate returns the action creation time.
|
||||||
func (a *Action) GetCreate() time.Time {
|
func (a *Action) GetCreate() time.Time {
|
||||||
return a.Created
|
return a.CreatedUnix.AsTime()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIssueInfos returns a list of issues associated with
|
// GetIssueInfos returns a list of issues associated with
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
@ -26,14 +25,8 @@ const (
|
||||||
type Notice struct {
|
type Notice struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
Type NoticeType
|
Type NoticeType
|
||||||
Description string `xorm:"TEXT"`
|
Description string `xorm:"TEXT"`
|
||||||
Created time.Time `xorm:"-"`
|
CreatedUnix util.TimeStamp `xorm:"INDEX created"`
|
||||||
CreatedUnix int64 `xorm:"INDEX created"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
|
||||||
func (n *Notice) AfterLoad() {
|
|
||||||
n.Created = time.Unix(n.CreatedUnix, 0).Local()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrStr returns a translation format string.
|
// TrStr returns a translation format string.
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,11 @@ import (
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"time"
|
|
||||||
|
|
||||||
gouuid "github.com/satori/go.uuid"
|
gouuid "github.com/satori/go.uuid"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Attachment represent a attachment of issue/comment/release.
|
// Attachment represent a attachment of issue/comment/release.
|
||||||
|
|
@ -25,24 +25,14 @@ type Attachment struct {
|
||||||
ReleaseID int64 `xorm:"INDEX"`
|
ReleaseID int64 `xorm:"INDEX"`
|
||||||
CommentID int64
|
CommentID int64
|
||||||
Name string
|
Name string
|
||||||
DownloadCount int64 `xorm:"DEFAULT 0"`
|
DownloadCount int64 `xorm:"DEFAULT 0"`
|
||||||
Created time.Time `xorm:"-"`
|
CreatedUnix util.TimeStamp `xorm:"created"`
|
||||||
CreatedUnix int64 `xorm:"created"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the value of a field of
|
|
||||||
// this object.
|
|
||||||
func (a *Attachment) AfterLoad() {
|
|
||||||
a.Created = time.Unix(a.CreatedUnix, 0).Local()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IncreaseDownloadCount is update download count + 1
|
// IncreaseDownloadCount is update download count + 1
|
||||||
func (a *Attachment) IncreaseDownloadCount() error {
|
func (a *Attachment) IncreaseDownloadCount() error {
|
||||||
sess := x.NewSession()
|
|
||||||
defer sess.Close()
|
|
||||||
|
|
||||||
// Update download count.
|
// Update download count.
|
||||||
if _, err := sess.Exec("UPDATE `attachment` SET download_count=download_count+1 WHERE id=?", a.ID); err != nil {
|
if _, err := x.Exec("UPDATE `attachment` SET download_count=download_count+1 WHERE id=?", a.ID); err != nil {
|
||||||
return fmt.Errorf("increase attachment count: %v", err)
|
return fmt.Errorf("increase attachment count: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,12 +29,10 @@ type ProtectedBranch struct {
|
||||||
BranchName string `xorm:"UNIQUE(s)"`
|
BranchName string `xorm:"UNIQUE(s)"`
|
||||||
CanPush bool `xorm:"NOT NULL DEFAULT false"`
|
CanPush bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
EnableWhitelist bool
|
EnableWhitelist bool
|
||||||
WhitelistUserIDs []int64 `xorm:"JSON TEXT"`
|
WhitelistUserIDs []int64 `xorm:"JSON TEXT"`
|
||||||
WhitelistTeamIDs []int64 `xorm:"JSON TEXT"`
|
WhitelistTeamIDs []int64 `xorm:"JSON TEXT"`
|
||||||
Created time.Time `xorm:"-"`
|
CreatedUnix util.TimeStamp `xorm:"created"`
|
||||||
CreatedUnix int64 `xorm:"created"`
|
UpdatedUnix util.TimeStamp `xorm:"updated"`
|
||||||
Updated time.Time `xorm:"-"`
|
|
||||||
UpdatedUnix int64 `xorm:"updated"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsProtected returns if the branch is protected
|
// IsProtected returns if the branch is protected
|
||||||
|
|
@ -197,19 +195,13 @@ func (repo *Repository) DeleteProtectedBranch(id int64) (err error) {
|
||||||
|
|
||||||
// DeletedBranch struct
|
// DeletedBranch struct
|
||||||
type DeletedBranch struct {
|
type DeletedBranch struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"`
|
RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"`
|
||||||
Name string `xorm:"UNIQUE(s) NOT NULL"`
|
Name string `xorm:"UNIQUE(s) NOT NULL"`
|
||||||
Commit string `xorm:"UNIQUE(s) NOT NULL"`
|
Commit string `xorm:"UNIQUE(s) NOT NULL"`
|
||||||
DeletedByID int64 `xorm:"INDEX"`
|
DeletedByID int64 `xorm:"INDEX"`
|
||||||
DeletedBy *User `xorm:"-"`
|
DeletedBy *User `xorm:"-"`
|
||||||
Deleted time.Time `xorm:"-"`
|
DeletedUnix util.TimeStamp `xorm:"INDEX created"`
|
||||||
DeletedUnix int64 `xorm:"INDEX created"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
|
||||||
func (deletedBranch *DeletedBranch) AfterLoad() {
|
|
||||||
deletedBranch.Deleted = time.Unix(deletedBranch.DeletedUnix, 0).Local()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddDeletedBranch adds a deleted branch to the database
|
// AddDeletedBranch adds a deleted branch to the database
|
||||||
|
|
|
||||||
|
|
@ -19,3 +19,25 @@
|
||||||
issue_id: 2
|
issue_id: 2
|
||||||
created_unix: 946684800
|
created_unix: 946684800
|
||||||
updated_unix: 946684800
|
updated_unix: 946684800
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 3
|
||||||
|
user_id: 2
|
||||||
|
repo_id: 1
|
||||||
|
status: 3 # pinned
|
||||||
|
source: 1 # issue
|
||||||
|
updated_by: 1
|
||||||
|
issue_id: 2
|
||||||
|
created_unix: 946684800
|
||||||
|
updated_unix: 946684800
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 4
|
||||||
|
user_id: 2
|
||||||
|
repo_id: 1
|
||||||
|
status: 1 # unread
|
||||||
|
source: 1 # issue
|
||||||
|
updated_by: 1
|
||||||
|
issue_id: 2
|
||||||
|
created_unix: 946684800
|
||||||
|
updated_unix: 946684800
|
||||||
1
models/fixtures/public_key.yml
Normal file
1
models/fixtures/public_key.yml
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
[] # empty
|
||||||
|
|
@ -238,7 +238,7 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
|
||||||
var (
|
var (
|
||||||
diff = &Diff{Files: make([]*DiffFile, 0)}
|
diff = &Diff{Files: make([]*DiffFile, 0)}
|
||||||
|
|
||||||
curFile *DiffFile
|
curFile = &DiffFile{}
|
||||||
curSection = &DiffSection{
|
curSection = &DiffSection{
|
||||||
Lines: make([]*DiffLine, 0, 10),
|
Lines: make([]*DiffLine, 0, 10),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/git"
|
"code.gitea.io/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
"github.com/keybase/go-crypto/openpgp"
|
"github.com/keybase/go-crypto/openpgp"
|
||||||
|
|
@ -26,17 +27,14 @@ import (
|
||||||
|
|
||||||
// GPGKey represents a GPG key.
|
// GPGKey represents a GPG key.
|
||||||
type GPGKey struct {
|
type GPGKey struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
OwnerID int64 `xorm:"INDEX NOT NULL"`
|
OwnerID int64 `xorm:"INDEX NOT NULL"`
|
||||||
KeyID string `xorm:"INDEX CHAR(16) NOT NULL"`
|
KeyID string `xorm:"INDEX CHAR(16) NOT NULL"`
|
||||||
PrimaryKeyID string `xorm:"CHAR(16)"`
|
PrimaryKeyID string `xorm:"CHAR(16)"`
|
||||||
Content string `xorm:"TEXT NOT NULL"`
|
Content string `xorm:"TEXT NOT NULL"`
|
||||||
Created time.Time `xorm:"-"`
|
CreatedUnix util.TimeStamp `xorm:"created"`
|
||||||
CreatedUnix int64
|
ExpiredUnix util.TimeStamp
|
||||||
Expired time.Time `xorm:"-"`
|
AddedUnix util.TimeStamp
|
||||||
ExpiredUnix int64
|
|
||||||
Added time.Time `xorm:"-"`
|
|
||||||
AddedUnix int64
|
|
||||||
SubsKey []*GPGKey `xorm:"-"`
|
SubsKey []*GPGKey `xorm:"-"`
|
||||||
Emails []*EmailAddress
|
Emails []*EmailAddress
|
||||||
CanSign bool
|
CanSign bool
|
||||||
|
|
@ -47,17 +45,11 @@ type GPGKey struct {
|
||||||
|
|
||||||
// BeforeInsert will be invoked by XORM before inserting a record
|
// BeforeInsert will be invoked by XORM before inserting a record
|
||||||
func (key *GPGKey) BeforeInsert() {
|
func (key *GPGKey) BeforeInsert() {
|
||||||
key.AddedUnix = time.Now().Unix()
|
key.AddedUnix = util.TimeStampNow()
|
||||||
key.ExpiredUnix = key.Expired.Unix()
|
|
||||||
key.CreatedUnix = key.Created.Unix()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
||||||
func (key *GPGKey) AfterLoad(session *xorm.Session) {
|
func (key *GPGKey) AfterLoad(session *xorm.Session) {
|
||||||
key.Added = time.Unix(key.AddedUnix, 0).Local()
|
|
||||||
key.Expired = time.Unix(key.ExpiredUnix, 0).Local()
|
|
||||||
key.Created = time.Unix(key.CreatedUnix, 0).Local()
|
|
||||||
|
|
||||||
err := session.Where("primary_key_id=?", key.KeyID).Find(&key.SubsKey)
|
err := session.Where("primary_key_id=?", key.KeyID).Find(&key.SubsKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(3, "Find Sub GPGkeys[%d]: %v", key.KeyID, err)
|
log.Error(3, "Find Sub GPGkeys[%d]: %v", key.KeyID, err)
|
||||||
|
|
@ -163,8 +155,8 @@ func parseSubGPGKey(ownerID int64, primaryID string, pubkey *packet.PublicKey, e
|
||||||
KeyID: pubkey.KeyIdString(),
|
KeyID: pubkey.KeyIdString(),
|
||||||
PrimaryKeyID: primaryID,
|
PrimaryKeyID: primaryID,
|
||||||
Content: content,
|
Content: content,
|
||||||
Created: pubkey.CreationTime,
|
CreatedUnix: util.TimeStamp(pubkey.CreationTime.Unix()),
|
||||||
Expired: expiry,
|
ExpiredUnix: util.TimeStamp(expiry.Unix()),
|
||||||
CanSign: pubkey.CanSign(),
|
CanSign: pubkey.CanSign(),
|
||||||
CanEncryptComms: pubkey.PubKeyAlgo.CanEncrypt(),
|
CanEncryptComms: pubkey.PubKeyAlgo.CanEncrypt(),
|
||||||
CanEncryptStorage: pubkey.PubKeyAlgo.CanEncrypt(),
|
CanEncryptStorage: pubkey.PubKeyAlgo.CanEncrypt(),
|
||||||
|
|
@ -236,8 +228,8 @@ func parseGPGKey(ownerID int64, e *openpgp.Entity) (*GPGKey, error) {
|
||||||
KeyID: pubkey.KeyIdString(),
|
KeyID: pubkey.KeyIdString(),
|
||||||
PrimaryKeyID: "",
|
PrimaryKeyID: "",
|
||||||
Content: content,
|
Content: content,
|
||||||
Created: pubkey.CreationTime,
|
CreatedUnix: util.TimeStamp(pubkey.CreationTime.Unix()),
|
||||||
Expired: expiry,
|
ExpiredUnix: util.TimeStamp(expiry.Unix()),
|
||||||
Emails: emails,
|
Emails: emails,
|
||||||
SubsKey: subkeys,
|
SubsKey: subkeys,
|
||||||
CanSign: pubkey.CanSign(),
|
CanSign: pubkey.CanSign(),
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ package models
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -109,7 +111,7 @@ MkM/fdpyc2hY7Dl/+qFmN5MG5yGmMpQcX+RNNR222ibNC1D3wg==
|
||||||
key := &GPGKey{
|
key := &GPGKey{
|
||||||
KeyID: pubkey.KeyIdString(),
|
KeyID: pubkey.KeyIdString(),
|
||||||
Content: content,
|
Content: content,
|
||||||
Created: pubkey.CreationTime,
|
CreatedUnix: util.TimeStamp(pubkey.CreationTime.Unix()),
|
||||||
CanSign: pubkey.CanSign(),
|
CanSign: pubkey.CanSign(),
|
||||||
CanEncryptComms: pubkey.PubKeyAlgo.CanEncrypt(),
|
CanEncryptComms: pubkey.PubKeyAlgo.CanEncrypt(),
|
||||||
CanEncryptStorage: pubkey.PubKeyAlgo.CanEncrypt(),
|
CanEncryptStorage: pubkey.PubKeyAlgo.CanEncrypt(),
|
||||||
|
|
@ -119,7 +121,7 @@ MkM/fdpyc2hY7Dl/+qFmN5MG5yGmMpQcX+RNNR222ibNC1D3wg==
|
||||||
cannotsignkey := &GPGKey{
|
cannotsignkey := &GPGKey{
|
||||||
KeyID: pubkey.KeyIdString(),
|
KeyID: pubkey.KeyIdString(),
|
||||||
Content: content,
|
Content: content,
|
||||||
Created: pubkey.CreationTime,
|
CreatedUnix: util.TimeStamp(pubkey.CreationTime.Unix()),
|
||||||
CanSign: false,
|
CanSign: false,
|
||||||
CanEncryptComms: false,
|
CanEncryptComms: false,
|
||||||
CanEncryptStorage: false,
|
CanEncryptStorage: false,
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
api "code.gitea.io/sdk/gitea"
|
api "code.gitea.io/sdk/gitea"
|
||||||
"github.com/Unknwon/com"
|
"github.com/Unknwon/com"
|
||||||
|
|
@ -45,31 +44,15 @@ type Issue struct {
|
||||||
NumComments int
|
NumComments int
|
||||||
Ref string
|
Ref string
|
||||||
|
|
||||||
Deadline time.Time `xorm:"-"`
|
DeadlineUnix util.TimeStamp `xorm:"INDEX"`
|
||||||
DeadlineUnix int64 `xorm:"INDEX"`
|
CreatedUnix util.TimeStamp `xorm:"INDEX created"`
|
||||||
Created time.Time `xorm:"-"`
|
UpdatedUnix util.TimeStamp `xorm:"INDEX updated"`
|
||||||
CreatedUnix int64 `xorm:"INDEX created"`
|
|
||||||
Updated time.Time `xorm:"-"`
|
|
||||||
UpdatedUnix int64 `xorm:"INDEX updated"`
|
|
||||||
|
|
||||||
Attachments []*Attachment `xorm:"-"`
|
Attachments []*Attachment `xorm:"-"`
|
||||||
Comments []*Comment `xorm:"-"`
|
Comments []*Comment `xorm:"-"`
|
||||||
Reactions ReactionList `xorm:"-"`
|
Reactions ReactionList `xorm:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeforeUpdate is invoked from XORM before updating this object.
|
|
||||||
func (issue *Issue) BeforeUpdate() {
|
|
||||||
issue.DeadlineUnix = issue.Deadline.Unix()
|
|
||||||
}
|
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the value of a field of
|
|
||||||
// this object.
|
|
||||||
func (issue *Issue) AfterLoad() {
|
|
||||||
issue.Deadline = time.Unix(issue.DeadlineUnix, 0).Local()
|
|
||||||
issue.Created = time.Unix(issue.CreatedUnix, 0).Local()
|
|
||||||
issue.Updated = time.Unix(issue.UpdatedUnix, 0).Local()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (issue *Issue) loadRepo(e Engine) (err error) {
|
func (issue *Issue) loadRepo(e Engine) (err error) {
|
||||||
if issue.Repo == nil {
|
if issue.Repo == nil {
|
||||||
issue.Repo, err = getRepositoryByID(e, issue.RepoID)
|
issue.Repo, err = getRepositoryByID(e, issue.RepoID)
|
||||||
|
|
@ -307,8 +290,8 @@ func (issue *Issue) APIFormat() *api.Issue {
|
||||||
Labels: apiLabels,
|
Labels: apiLabels,
|
||||||
State: issue.State(),
|
State: issue.State(),
|
||||||
Comments: issue.NumComments,
|
Comments: issue.NumComments,
|
||||||
Created: issue.Created,
|
Created: issue.CreatedUnix.AsTime(),
|
||||||
Updated: issue.Updated,
|
Updated: issue.UpdatedUnix.AsTime(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if issue.Milestone != nil {
|
if issue.Milestone != nil {
|
||||||
|
|
@ -322,7 +305,7 @@ func (issue *Issue) APIFormat() *api.Issue {
|
||||||
HasMerged: issue.PullRequest.HasMerged,
|
HasMerged: issue.PullRequest.HasMerged,
|
||||||
}
|
}
|
||||||
if issue.PullRequest.HasMerged {
|
if issue.PullRequest.HasMerged {
|
||||||
apiIssue.PullRequest.Merged = &issue.PullRequest.Merged
|
apiIssue.PullRequest.Merged = issue.PullRequest.MergedUnix.AsTimePtr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -599,7 +582,7 @@ func updateIssueCols(e Engine, issue *Issue, cols ...string) error {
|
||||||
if _, err := e.ID(issue.ID).Cols(cols...).Update(issue); err != nil {
|
if _, err := e.ID(issue.ID).Cols(cols...).Update(issue); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
UpdateIssueIndexer(issue.ID)
|
UpdateIssueIndexerCols(issue.ID, cols...)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ package models
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Unknwon/com"
|
"github.com/Unknwon/com"
|
||||||
"github.com/go-xorm/builder"
|
"github.com/go-xorm/builder"
|
||||||
|
|
@ -17,6 +16,7 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/markup"
|
"code.gitea.io/gitea/modules/markup"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CommentType defines whether a comment is just a simple comment, an action (like close) or a reference.
|
// CommentType defines whether a comment is just a simple comment, an action (like close) or a reference.
|
||||||
|
|
@ -104,10 +104,8 @@ type Comment struct {
|
||||||
Content string `xorm:"TEXT"`
|
Content string `xorm:"TEXT"`
|
||||||
RenderedContent string `xorm:"-"`
|
RenderedContent string `xorm:"-"`
|
||||||
|
|
||||||
Created time.Time `xorm:"-"`
|
CreatedUnix util.TimeStamp `xorm:"INDEX created"`
|
||||||
CreatedUnix int64 `xorm:"INDEX created"`
|
UpdatedUnix util.TimeStamp `xorm:"INDEX updated"`
|
||||||
Updated time.Time `xorm:"-"`
|
|
||||||
UpdatedUnix int64 `xorm:"INDEX updated"`
|
|
||||||
|
|
||||||
// Reference issue in commit message
|
// Reference issue in commit message
|
||||||
CommitSHA string `xorm:"VARCHAR(40)"`
|
CommitSHA string `xorm:"VARCHAR(40)"`
|
||||||
|
|
@ -121,9 +119,6 @@ type Comment struct {
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
||||||
func (c *Comment) AfterLoad(session *xorm.Session) {
|
func (c *Comment) AfterLoad(session *xorm.Session) {
|
||||||
c.Created = time.Unix(c.CreatedUnix, 0).Local()
|
|
||||||
c.Updated = time.Unix(c.UpdatedUnix, 0).Local()
|
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
c.Attachments, err = getAttachmentsByCommentID(session, c.ID)
|
c.Attachments, err = getAttachmentsByCommentID(session, c.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -197,8 +192,8 @@ func (c *Comment) APIFormat() *api.Comment {
|
||||||
IssueURL: c.IssueURL(),
|
IssueURL: c.IssueURL(),
|
||||||
PRURL: c.PRURL(),
|
PRURL: c.PRURL(),
|
||||||
Body: c.Content,
|
Body: c.Content,
|
||||||
Created: c.Created,
|
Created: c.CreatedUnix.AsTime(),
|
||||||
Updated: c.Updated,
|
Updated: c.UpdatedUnix.AsTime(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,9 @@ func TestCreateComment(t *testing.T) {
|
||||||
assert.EqualValues(t, "Hello", comment.Content)
|
assert.EqualValues(t, "Hello", comment.Content)
|
||||||
assert.EqualValues(t, issue.ID, comment.IssueID)
|
assert.EqualValues(t, issue.ID, comment.IssueID)
|
||||||
assert.EqualValues(t, doer.ID, comment.PosterID)
|
assert.EqualValues(t, doer.ID, comment.PosterID)
|
||||||
AssertInt64InRange(t, now, then, comment.CreatedUnix)
|
AssertInt64InRange(t, now, then, int64(comment.CreatedUnix))
|
||||||
AssertExistsAndLoadBean(t, comment) // assert actually added to DB
|
AssertExistsAndLoadBean(t, comment) // assert actually added to DB
|
||||||
|
|
||||||
updatedIssue := AssertExistsAndLoadBean(t, &Issue{ID: issue.ID}).(*Issue)
|
updatedIssue := AssertExistsAndLoadBean(t, &Issue{ID: issue.ID}).(*Issue)
|
||||||
AssertInt64InRange(t, now, then, updatedIssue.UpdatedUnix)
|
AssertInt64InRange(t, now, then, int64(updatedIssue.UpdatedUnix))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,26 @@ func (issue *Issue) update() indexer.IssueIndexerUpdate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// updateNeededCols whether a change to the specified columns requires updating
|
||||||
|
// the issue indexer
|
||||||
|
func updateNeededCols(cols []string) bool {
|
||||||
|
for _, col := range cols {
|
||||||
|
switch col {
|
||||||
|
case "name", "content":
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateIssueIndexerCols update an issue in the issue indexer, given changes
|
||||||
|
// to the specified columns
|
||||||
|
func UpdateIssueIndexerCols(issueID int64, cols ...string) {
|
||||||
|
if updateNeededCols(cols) {
|
||||||
|
UpdateIssueIndexer(issueID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateIssueIndexer add/update an issue to the issue indexer
|
// UpdateIssueIndexer add/update an issue to the issue indexer
|
||||||
func UpdateIssueIndexer(issueID int64) {
|
func UpdateIssueIndexer(issueID int64) {
|
||||||
select {
|
select {
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,8 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
api "code.gitea.io/sdk/gitea"
|
api "code.gitea.io/sdk/gitea"
|
||||||
|
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
|
|
@ -27,16 +26,14 @@ type Milestone struct {
|
||||||
Completeness int // Percentage(1-100).
|
Completeness int // Percentage(1-100).
|
||||||
IsOverDue bool `xorm:"-"`
|
IsOverDue bool `xorm:"-"`
|
||||||
|
|
||||||
DeadlineString string `xorm:"-"`
|
DeadlineString string `xorm:"-"`
|
||||||
Deadline time.Time `xorm:"-"`
|
DeadlineUnix util.TimeStamp
|
||||||
DeadlineUnix int64
|
ClosedDateUnix util.TimeStamp
|
||||||
ClosedDate time.Time `xorm:"-"`
|
|
||||||
ClosedDateUnix int64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeforeInsert is invoked from XORM before inserting an object of this type.
|
// BeforeInsert is invoked from XORM before inserting an object of this type.
|
||||||
func (m *Milestone) BeforeInsert() {
|
func (m *Milestone) BeforeInsert() {
|
||||||
m.DeadlineUnix = m.Deadline.Unix()
|
m.DeadlineUnix = util.TimeStampNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeforeUpdate is invoked from XORM before updating this object.
|
// BeforeUpdate is invoked from XORM before updating this object.
|
||||||
|
|
@ -46,26 +43,20 @@ func (m *Milestone) BeforeUpdate() {
|
||||||
} else {
|
} else {
|
||||||
m.Completeness = 0
|
m.Completeness = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
m.DeadlineUnix = m.Deadline.Unix()
|
|
||||||
m.ClosedDateUnix = m.ClosedDate.Unix()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the value of a field of
|
// AfterLoad is invoked from XORM after setting the value of a field of
|
||||||
// this object.
|
// this object.
|
||||||
func (m *Milestone) AfterLoad() {
|
func (m *Milestone) AfterLoad() {
|
||||||
m.NumOpenIssues = m.NumIssues - m.NumClosedIssues
|
m.NumOpenIssues = m.NumIssues - m.NumClosedIssues
|
||||||
m.Deadline = time.Unix(m.DeadlineUnix, 0).Local()
|
if m.DeadlineUnix.Year() == 9999 {
|
||||||
if m.Deadline.Year() == 9999 {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
m.DeadlineString = m.Deadline.Format("2006-01-02")
|
m.DeadlineString = m.DeadlineUnix.Format("2006-01-02")
|
||||||
if time.Now().Local().After(m.Deadline) {
|
if util.TimeStampNow() >= m.DeadlineUnix {
|
||||||
m.IsOverDue = true
|
m.IsOverDue = true
|
||||||
}
|
}
|
||||||
|
|
||||||
m.ClosedDate = time.Unix(m.ClosedDateUnix, 0).Local()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// State returns string representation of milestone status.
|
// State returns string representation of milestone status.
|
||||||
|
|
@ -87,10 +78,10 @@ func (m *Milestone) APIFormat() *api.Milestone {
|
||||||
ClosedIssues: m.NumClosedIssues,
|
ClosedIssues: m.NumClosedIssues,
|
||||||
}
|
}
|
||||||
if m.IsClosed {
|
if m.IsClosed {
|
||||||
apiMilestone.Closed = &m.ClosedDate
|
apiMilestone.Closed = m.ClosedDateUnix.AsTimePtr()
|
||||||
}
|
}
|
||||||
if m.Deadline.Year() < 9999 {
|
if m.DeadlineUnix.Year() < 9999 {
|
||||||
apiMilestone.Deadline = &m.Deadline
|
apiMilestone.Deadline = m.DeadlineUnix.AsTimePtr()
|
||||||
}
|
}
|
||||||
return apiMilestone
|
return apiMilestone
|
||||||
}
|
}
|
||||||
|
|
@ -174,31 +165,33 @@ func UpdateMilestone(m *Milestone) error {
|
||||||
return updateMilestone(x, m)
|
return updateMilestone(x, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func countRepoMilestones(e Engine, repoID int64) int64 {
|
func countRepoMilestones(e Engine, repoID int64) (int64, error) {
|
||||||
count, _ := e.
|
return e.
|
||||||
Where("repo_id=?", repoID).
|
Where("repo_id=?", repoID).
|
||||||
Count(new(Milestone))
|
Count(new(Milestone))
|
||||||
return count
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func countRepoClosedMilestones(e Engine, repoID int64) int64 {
|
func countRepoClosedMilestones(e Engine, repoID int64) (int64, error) {
|
||||||
closed, _ := e.
|
return e.
|
||||||
Where("repo_id=? AND is_closed=?", repoID, true).
|
Where("repo_id=? AND is_closed=?", repoID, true).
|
||||||
Count(new(Milestone))
|
Count(new(Milestone))
|
||||||
return closed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CountRepoClosedMilestones returns number of closed milestones in given repository.
|
// CountRepoClosedMilestones returns number of closed milestones in given repository.
|
||||||
func CountRepoClosedMilestones(repoID int64) int64 {
|
func CountRepoClosedMilestones(repoID int64) (int64, error) {
|
||||||
return countRepoClosedMilestones(x, repoID)
|
return countRepoClosedMilestones(x, repoID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MilestoneStats returns number of open and closed milestones of given repository.
|
// MilestoneStats returns number of open and closed milestones of given repository.
|
||||||
func MilestoneStats(repoID int64) (open int64, closed int64) {
|
func MilestoneStats(repoID int64) (open int64, closed int64, err error) {
|
||||||
open, _ = x.
|
open, err = x.
|
||||||
Where("repo_id=? AND is_closed=?", repoID, false).
|
Where("repo_id=? AND is_closed=?", repoID, false).
|
||||||
Count(new(Milestone))
|
Count(new(Milestone))
|
||||||
return open, CountRepoClosedMilestones(repoID)
|
if err != nil {
|
||||||
|
return 0, 0, nil
|
||||||
|
}
|
||||||
|
closed, err = CountRepoClosedMilestones(repoID)
|
||||||
|
return open, closed, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChangeMilestoneStatus changes the milestone open/closed status.
|
// ChangeMilestoneStatus changes the milestone open/closed status.
|
||||||
|
|
@ -219,8 +212,17 @@ func ChangeMilestoneStatus(m *Milestone, isClosed bool) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
repo.NumMilestones = int(countRepoMilestones(sess, repo.ID))
|
numMilestones, err := countRepoMilestones(sess, repo.ID)
|
||||||
repo.NumClosedMilestones = int(countRepoClosedMilestones(sess, repo.ID))
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
numClosedMilestones, err := countRepoClosedMilestones(sess, repo.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
repo.NumMilestones = int(numMilestones)
|
||||||
|
repo.NumClosedMilestones = int(numClosedMilestones)
|
||||||
|
|
||||||
if _, err = sess.ID(repo.ID).Cols("num_milestones, num_closed_milestones").Update(repo); err != nil {
|
if _, err = sess.ID(repo.ID).Cols("num_milestones, num_closed_milestones").Update(repo); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -291,7 +293,7 @@ func changeMilestoneAssign(e *xorm.Session, doer *User, issue *Issue, oldMilesto
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return updateIssue(e, issue)
|
return updateIssueCols(e, issue, "milestone_id")
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChangeMilestoneAssign changes assignment of milestone for issue.
|
// ChangeMilestoneAssign changes assignment of milestone for issue.
|
||||||
|
|
@ -333,8 +335,17 @@ func DeleteMilestoneByRepoID(repoID, id int64) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
repo.NumMilestones = int(countRepoMilestones(sess, repo.ID))
|
numMilestones, err := countRepoMilestones(sess, repo.ID)
|
||||||
repo.NumClosedMilestones = int(countRepoClosedMilestones(sess, repo.ID))
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
numClosedMilestones, err := countRepoClosedMilestones(sess, repo.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
repo.NumMilestones = int(numMilestones)
|
||||||
|
repo.NumClosedMilestones = int(numClosedMilestones)
|
||||||
|
|
||||||
if _, err = sess.ID(repo.ID).Cols("num_milestones, num_closed_milestones").Update(repo); err != nil {
|
if _, err = sess.ID(repo.ID).Cols("num_milestones, num_closed_milestones").Update(repo); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
api "code.gitea.io/sdk/gitea"
|
api "code.gitea.io/sdk/gitea"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
@ -28,7 +29,7 @@ func TestMilestone_APIFormat(t *testing.T) {
|
||||||
IsClosed: false,
|
IsClosed: false,
|
||||||
NumOpenIssues: 5,
|
NumOpenIssues: 5,
|
||||||
NumClosedIssues: 6,
|
NumClosedIssues: 6,
|
||||||
Deadline: time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC),
|
DeadlineUnix: util.TimeStamp(time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC).Unix()),
|
||||||
}
|
}
|
||||||
assert.Equal(t, api.Milestone{
|
assert.Equal(t, api.Milestone{
|
||||||
ID: milestone.ID,
|
ID: milestone.ID,
|
||||||
|
|
@ -37,7 +38,7 @@ func TestMilestone_APIFormat(t *testing.T) {
|
||||||
Description: milestone.Content,
|
Description: milestone.Content,
|
||||||
OpenIssues: milestone.NumOpenIssues,
|
OpenIssues: milestone.NumOpenIssues,
|
||||||
ClosedIssues: milestone.NumClosedIssues,
|
ClosedIssues: milestone.NumClosedIssues,
|
||||||
Deadline: &milestone.Deadline,
|
Deadline: milestone.DeadlineUnix.AsTimePtr(),
|
||||||
}, *milestone.APIFormat())
|
}, *milestone.APIFormat())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -145,31 +146,42 @@ func TestCountRepoMilestones(t *testing.T) {
|
||||||
assert.NoError(t, PrepareTestDatabase())
|
assert.NoError(t, PrepareTestDatabase())
|
||||||
test := func(repoID int64) {
|
test := func(repoID int64) {
|
||||||
repo := AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository)
|
repo := AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository)
|
||||||
assert.EqualValues(t, repo.NumMilestones, countRepoMilestones(x, repoID))
|
count, err := countRepoMilestones(x, repoID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, repo.NumMilestones, count)
|
||||||
}
|
}
|
||||||
test(1)
|
test(1)
|
||||||
test(2)
|
test(2)
|
||||||
test(3)
|
test(3)
|
||||||
assert.EqualValues(t, 0, countRepoMilestones(x, NonexistentID))
|
|
||||||
|
count, err := countRepoMilestones(x, NonexistentID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 0, count)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCountRepoClosedMilestones(t *testing.T) {
|
func TestCountRepoClosedMilestones(t *testing.T) {
|
||||||
assert.NoError(t, PrepareTestDatabase())
|
assert.NoError(t, PrepareTestDatabase())
|
||||||
test := func(repoID int64) {
|
test := func(repoID int64) {
|
||||||
repo := AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository)
|
repo := AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository)
|
||||||
assert.EqualValues(t, repo.NumClosedMilestones, CountRepoClosedMilestones(repoID))
|
count, err := CountRepoClosedMilestones(repoID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, repo.NumClosedMilestones, count)
|
||||||
}
|
}
|
||||||
test(1)
|
test(1)
|
||||||
test(2)
|
test(2)
|
||||||
test(3)
|
test(3)
|
||||||
assert.EqualValues(t, 0, countRepoMilestones(x, NonexistentID))
|
|
||||||
|
count, err := CountRepoClosedMilestones(NonexistentID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 0, count)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMilestoneStats(t *testing.T) {
|
func TestMilestoneStats(t *testing.T) {
|
||||||
assert.NoError(t, PrepareTestDatabase())
|
assert.NoError(t, PrepareTestDatabase())
|
||||||
test := func(repoID int64) {
|
test := func(repoID int64) {
|
||||||
repo := AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository)
|
repo := AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository)
|
||||||
open, closed := MilestoneStats(repoID)
|
open, closed, err := MilestoneStats(repoID)
|
||||||
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, repo.NumMilestones-repo.NumClosedMilestones, open)
|
assert.EqualValues(t, repo.NumMilestones-repo.NumClosedMilestones, open)
|
||||||
assert.EqualValues(t, repo.NumClosedMilestones, closed)
|
assert.EqualValues(t, repo.NumClosedMilestones, closed)
|
||||||
}
|
}
|
||||||
|
|
@ -177,7 +189,8 @@ func TestMilestoneStats(t *testing.T) {
|
||||||
test(2)
|
test(2)
|
||||||
test(3)
|
test(3)
|
||||||
|
|
||||||
open, closed := MilestoneStats(NonexistentID)
|
open, closed, err := MilestoneStats(NonexistentID)
|
||||||
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 0, open)
|
assert.EqualValues(t, 0, open)
|
||||||
assert.EqualValues(t, 0, closed)
|
assert.EqualValues(t, 0, closed)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ package models
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/go-xorm/builder"
|
"github.com/go-xorm/builder"
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
|
|
@ -17,19 +17,13 @@ import (
|
||||||
|
|
||||||
// Reaction represents a reactions on issues and comments.
|
// Reaction represents a reactions on issues and comments.
|
||||||
type Reaction struct {
|
type Reaction struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
Type string `xorm:"INDEX UNIQUE(s) NOT NULL"`
|
Type string `xorm:"INDEX UNIQUE(s) NOT NULL"`
|
||||||
IssueID int64 `xorm:"INDEX UNIQUE(s) NOT NULL"`
|
IssueID int64 `xorm:"INDEX UNIQUE(s) NOT NULL"`
|
||||||
CommentID int64 `xorm:"INDEX UNIQUE(s)"`
|
CommentID int64 `xorm:"INDEX UNIQUE(s)"`
|
||||||
UserID int64 `xorm:"INDEX UNIQUE(s) NOT NULL"`
|
UserID int64 `xorm:"INDEX UNIQUE(s) NOT NULL"`
|
||||||
User *User `xorm:"-"`
|
User *User `xorm:"-"`
|
||||||
Created time.Time `xorm:"-"`
|
CreatedUnix util.TimeStamp `xorm:"INDEX created"`
|
||||||
CreatedUnix int64 `xorm:"INDEX created"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
|
||||||
func (s *Reaction) AfterLoad() {
|
|
||||||
s.Created = time.Unix(s.CreatedUnix, 0).Local()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindReactionsOptions describes the conditions to Find reactions
|
// FindReactionsOptions describes the conditions to Find reactions
|
||||||
|
|
|
||||||
|
|
@ -7,26 +7,16 @@ package models
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Stopwatch represents a stopwatch for time tracking.
|
// Stopwatch represents a stopwatch for time tracking.
|
||||||
type Stopwatch struct {
|
type Stopwatch struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
IssueID int64 `xorm:"INDEX"`
|
IssueID int64 `xorm:"INDEX"`
|
||||||
UserID int64 `xorm:"INDEX"`
|
UserID int64 `xorm:"INDEX"`
|
||||||
Created time.Time `xorm:"-"`
|
CreatedUnix util.TimeStamp `xorm:"created"`
|
||||||
CreatedUnix int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// BeforeInsert will be invoked by XORM before inserting a record
|
|
||||||
// representing this object.
|
|
||||||
func (s *Stopwatch) BeforeInsert() {
|
|
||||||
s.CreatedUnix = time.Now().Unix()
|
|
||||||
}
|
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
|
||||||
func (s *Stopwatch) AfterLoad() {
|
|
||||||
s.Created = time.Unix(s.CreatedUnix, 0).Local()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getStopwatch(e Engine, userID, issueID int64) (sw *Stopwatch, exists bool, err error) {
|
func getStopwatch(e Engine, userID, issueID int64) (sw *Stopwatch, exists bool, err error) {
|
||||||
|
|
@ -61,7 +51,7 @@ func CreateOrStopIssueStopwatch(user *User, issue *Issue) error {
|
||||||
}
|
}
|
||||||
if exists {
|
if exists {
|
||||||
// Create tracked time out of the time difference between start date and actual date
|
// Create tracked time out of the time difference between start date and actual date
|
||||||
timediff := time.Now().Unix() - sw.CreatedUnix
|
timediff := time.Now().Unix() - int64(sw.CreatedUnix)
|
||||||
|
|
||||||
// Create TrackedTime
|
// Create TrackedTime
|
||||||
tt := &TrackedTime{
|
tt := &TrackedTime{
|
||||||
|
|
@ -92,7 +82,6 @@ func CreateOrStopIssueStopwatch(user *User, issue *Issue) error {
|
||||||
sw = &Stopwatch{
|
sw = &Stopwatch{
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
IssueID: issue.ID,
|
IssueID: issue.ID,
|
||||||
Created: time.Now(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := x.Insert(sw); err != nil {
|
if _, err := x.Insert(sw); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@ package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
@ -62,7 +63,7 @@ func TestCreateOrStopIssueStopwatch(t *testing.T) {
|
||||||
|
|
||||||
assert.NoError(t, CreateOrStopIssueStopwatch(user3, issue1))
|
assert.NoError(t, CreateOrStopIssueStopwatch(user3, issue1))
|
||||||
sw := AssertExistsAndLoadBean(t, &Stopwatch{UserID: 3, IssueID: 1}).(*Stopwatch)
|
sw := AssertExistsAndLoadBean(t, &Stopwatch{UserID: 3, IssueID: 1}).(*Stopwatch)
|
||||||
assert.Equal(t, true, sw.Created.Before(time.Now()))
|
assert.Equal(t, true, sw.CreatedUnix <= util.TimeStampNow())
|
||||||
|
|
||||||
assert.NoError(t, CreateOrStopIssueStopwatch(user2, issue2))
|
assert.NoError(t, CreateOrStopIssueStopwatch(user2, issue2))
|
||||||
AssertNotExistsBean(t, &Stopwatch{UserID: 2, IssueID: 2})
|
AssertNotExistsBean(t, &Stopwatch{UserID: 2, IssueID: 2})
|
||||||
|
|
|
||||||
|
|
@ -166,5 +166,5 @@ func TestUpdateIssueCols(t *testing.T) {
|
||||||
updatedIssue := AssertExistsAndLoadBean(t, &Issue{ID: issue.ID}).(*Issue)
|
updatedIssue := AssertExistsAndLoadBean(t, &Issue{ID: issue.ID}).(*Issue)
|
||||||
assert.EqualValues(t, newTitle, updatedIssue.Title)
|
assert.EqualValues(t, newTitle, updatedIssue.Title)
|
||||||
assert.EqualValues(t, prevContent, updatedIssue.Content)
|
assert.EqualValues(t, prevContent, updatedIssue.Content)
|
||||||
AssertInt64InRange(t, now, then, updatedIssue.UpdatedUnix)
|
AssertInt64InRange(t, now, then, int64(updatedIssue.UpdatedUnix))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ package models
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/sdk/gitea"
|
api "code.gitea.io/sdk/gitea"
|
||||||
|
|
||||||
"github.com/go-xorm/builder"
|
"github.com/go-xorm/builder"
|
||||||
|
|
@ -24,7 +25,7 @@ type TrackedTime struct {
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
||||||
func (t *TrackedTime) AfterLoad() {
|
func (t *TrackedTime) AfterLoad() {
|
||||||
t.Created = time.Unix(t.CreatedUnix, 0).Local()
|
t.Created = time.Unix(t.CreatedUnix, 0).In(setting.UILocation)
|
||||||
}
|
}
|
||||||
|
|
||||||
// APIFormat converts TrackedTime to API format
|
// APIFormat converts TrackedTime to API format
|
||||||
|
|
|
||||||
|
|
@ -4,42 +4,16 @@
|
||||||
|
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import "code.gitea.io/gitea/modules/util"
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IssueWatch is connection request for receiving issue notification.
|
// IssueWatch is connection request for receiving issue notification.
|
||||||
type IssueWatch struct {
|
type IssueWatch struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
UserID int64 `xorm:"UNIQUE(watch) NOT NULL"`
|
UserID int64 `xorm:"UNIQUE(watch) NOT NULL"`
|
||||||
IssueID int64 `xorm:"UNIQUE(watch) NOT NULL"`
|
IssueID int64 `xorm:"UNIQUE(watch) NOT NULL"`
|
||||||
IsWatching bool `xorm:"NOT NULL"`
|
IsWatching bool `xorm:"NOT NULL"`
|
||||||
Created time.Time `xorm:"-"`
|
CreatedUnix util.TimeStamp `xorm:"created NOT NULL"`
|
||||||
CreatedUnix int64 `xorm:"NOT NULL"`
|
UpdatedUnix util.TimeStamp `xorm:"updated NOT NULL"`
|
||||||
Updated time.Time `xorm:"-"`
|
|
||||||
UpdatedUnix int64 `xorm:"NOT NULL"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// BeforeInsert is invoked from XORM before inserting an object of this type.
|
|
||||||
func (iw *IssueWatch) BeforeInsert() {
|
|
||||||
var (
|
|
||||||
t = time.Now()
|
|
||||||
u = t.Unix()
|
|
||||||
)
|
|
||||||
iw.Created = t
|
|
||||||
iw.CreatedUnix = u
|
|
||||||
iw.Updated = t
|
|
||||||
iw.UpdatedUnix = u
|
|
||||||
}
|
|
||||||
|
|
||||||
// BeforeUpdate is invoked from XORM before updating an object of this type.
|
|
||||||
func (iw *IssueWatch) BeforeUpdate() {
|
|
||||||
var (
|
|
||||||
t = time.Now()
|
|
||||||
u = t.Unix()
|
|
||||||
)
|
|
||||||
iw.Updated = t
|
|
||||||
iw.UpdatedUnix = u
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateOrUpdateIssueWatch set watching for a user and issue
|
// CreateOrUpdateIssueWatch set watching for a user and issue
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,18 @@ package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"time"
|
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LFSMetaObject stores metadata for LFS tracked files.
|
// LFSMetaObject stores metadata for LFS tracked files.
|
||||||
type LFSMetaObject struct {
|
type LFSMetaObject struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
Oid string `xorm:"UNIQUE(s) INDEX NOT NULL"`
|
Oid string `xorm:"UNIQUE(s) INDEX NOT NULL"`
|
||||||
Size int64 `xorm:"NOT NULL"`
|
Size int64 `xorm:"NOT NULL"`
|
||||||
RepositoryID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"`
|
RepositoryID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"`
|
||||||
Existing bool `xorm:"-"`
|
Existing bool `xorm:"-"`
|
||||||
Created time.Time `xorm:"-"`
|
CreatedUnix util.TimeStamp `xorm:"created"`
|
||||||
CreatedUnix int64 `xorm:"created"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LFSTokenResponse defines the JSON structure in which the JWT token is stored.
|
// LFSTokenResponse defines the JSON structure in which the JWT token is stored.
|
||||||
|
|
@ -105,8 +105,3 @@ func (repo *Repository) RemoveLFSMetaObjectByOid(oid string) error {
|
||||||
|
|
||||||
return sess.Commit()
|
return sess.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// AfterLoad stores the LFSMetaObject creation time in the database as local time.
|
|
||||||
func (m *LFSMetaObject) AfterLoad() {
|
|
||||||
m.Created = time.Unix(m.CreatedUnix, 0).Local()
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ func (l *LFSLock) AfterLoad() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanPath(p string) string {
|
func cleanPath(p string) string {
|
||||||
return strings.ToLower(path.Clean(p))
|
return path.Clean(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// APIFormat convert a Release to lfs.LFSLock
|
// APIFormat convert a Release to lfs.LFSLock
|
||||||
|
|
@ -73,8 +73,8 @@ func CreateLFSLock(lock *LFSLock) (*LFSLock, error) {
|
||||||
// GetLFSLock returns release by given path.
|
// GetLFSLock returns release by given path.
|
||||||
func GetLFSLock(repoID int64, path string) (*LFSLock, error) {
|
func GetLFSLock(repoID int64, path string) (*LFSLock, error) {
|
||||||
path = cleanPath(path)
|
path = cleanPath(path)
|
||||||
rel := &LFSLock{RepoID: repoID, Path: path}
|
rel := &LFSLock{RepoID: repoID}
|
||||||
has, err := x.Get(rel)
|
has, err := x.Where("lower(path) = ?", strings.ToLower(path)).Get(rel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ import (
|
||||||
"net/smtp"
|
"net/smtp"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Unknwon/com"
|
"github.com/Unknwon/com"
|
||||||
"github.com/go-macaron/binding"
|
"github.com/go-macaron/binding"
|
||||||
|
|
@ -23,6 +22,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/auth/oauth2"
|
"code.gitea.io/gitea/modules/auth/oauth2"
|
||||||
"code.gitea.io/gitea/modules/auth/pam"
|
"code.gitea.io/gitea/modules/auth/pam"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LoginType represents an login type.
|
// LoginType represents an login type.
|
||||||
|
|
@ -147,10 +147,8 @@ type LoginSource struct {
|
||||||
IsSyncEnabled bool `xorm:"INDEX NOT NULL DEFAULT false"`
|
IsSyncEnabled bool `xorm:"INDEX NOT NULL DEFAULT false"`
|
||||||
Cfg core.Conversion `xorm:"TEXT"`
|
Cfg core.Conversion `xorm:"TEXT"`
|
||||||
|
|
||||||
Created time.Time `xorm:"-"`
|
CreatedUnix util.TimeStamp `xorm:"INDEX created"`
|
||||||
CreatedUnix int64 `xorm:"INDEX created"`
|
UpdatedUnix util.TimeStamp `xorm:"INDEX updated"`
|
||||||
Updated time.Time `xorm:"-"`
|
|
||||||
UpdatedUnix int64 `xorm:"INDEX updated"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cell2Int64 converts a xorm.Cell type to int64,
|
// Cell2Int64 converts a xorm.Cell type to int64,
|
||||||
|
|
@ -183,12 +181,6 @@ func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
|
||||||
func (source *LoginSource) AfterLoad() {
|
|
||||||
source.Created = time.Unix(source.CreatedUnix, 0).Local()
|
|
||||||
source.Updated = time.Unix(source.UpdatedUnix, 0).Local()
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypeName return name of this login source type.
|
// TypeName return name of this login source type.
|
||||||
func (source *LoginSource) TypeName() string {
|
func (source *LoginSource) TypeName() string {
|
||||||
return LoginNames[source.Type]
|
return LoginNames[source.Type]
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,10 @@ type Version struct {
|
||||||
Version int64
|
Version int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func emptyMigration(x *xorm.Engine) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// This is a sequence of migrations. Add new migrations to the bottom of the list.
|
// This is a sequence of migrations. Add new migrations to the bottom of the list.
|
||||||
// If you want to "retire" a migration, remove it from the top of the list and
|
// If you want to "retire" a migration, remove it from the top of the list and
|
||||||
// update minDBVersion accordingly
|
// update minDBVersion accordingly
|
||||||
|
|
@ -127,17 +131,17 @@ var migrations = []Migration{
|
||||||
// v38 -> v39
|
// v38 -> v39
|
||||||
NewMigration("remove commits and settings unit types", removeCommitsUnitType),
|
NewMigration("remove commits and settings unit types", removeCommitsUnitType),
|
||||||
// v39 -> v40
|
// v39 -> v40
|
||||||
NewMigration("adds time tracking and stopwatches", addTimetracking),
|
|
||||||
// v40 -> v41
|
|
||||||
NewMigration("migrate protected branch struct", migrateProtectedBranchStruct),
|
|
||||||
// v41 -> v42
|
|
||||||
NewMigration("add default value to user prohibit_login", addDefaultValueToUserProhibitLogin),
|
|
||||||
// v42 -> v43
|
|
||||||
NewMigration("add tags to releases and sync existing repositories", releaseAddColumnIsTagAndSyncTags),
|
NewMigration("add tags to releases and sync existing repositories", releaseAddColumnIsTagAndSyncTags),
|
||||||
// v43 -> v44
|
// v40 -> v41
|
||||||
NewMigration("fix protected branch can push value to false", fixProtectedBranchCanPushValue),
|
NewMigration("fix protected branch can push value to false", fixProtectedBranchCanPushValue),
|
||||||
// v44 -> v45
|
// v41 -> v42
|
||||||
NewMigration("remove duplicate unit types", removeDuplicateUnitTypes),
|
NewMigration("remove duplicate unit types", removeDuplicateUnitTypes),
|
||||||
|
// v42 -> v43
|
||||||
|
NewMigration("empty step", emptyMigration),
|
||||||
|
// v43 -> v44
|
||||||
|
NewMigration("empty step", emptyMigration),
|
||||||
|
// v44 -> v45
|
||||||
|
NewMigration("empty step", emptyMigration),
|
||||||
// v45 -> v46
|
// v45 -> v46
|
||||||
NewMigration("remove index column from repo_unit table", removeIndexColumnFromRepoUnitTable),
|
NewMigration("remove index column from repo_unit table", removeIndexColumnFromRepoUnitTable),
|
||||||
// v46 -> v47
|
// v46 -> v47
|
||||||
|
|
@ -147,8 +151,14 @@ var migrations = []Migration{
|
||||||
// v48 -> v49
|
// v48 -> v49
|
||||||
NewMigration("add repo indexer status", addRepoIndexerStatus),
|
NewMigration("add repo indexer status", addRepoIndexerStatus),
|
||||||
// v49 -> v50
|
// v49 -> v50
|
||||||
NewMigration("add lfs lock table", addLFSLock),
|
NewMigration("adds time tracking and stopwatches", addTimetracking),
|
||||||
// v50 -> v51
|
// v50 -> v51
|
||||||
|
NewMigration("migrate protected branch struct", migrateProtectedBranchStruct),
|
||||||
|
// v51 -> v52
|
||||||
|
NewMigration("add default value to user prohibit_login", addDefaultValueToUserProhibitLogin),
|
||||||
|
// v52 -> v53
|
||||||
|
NewMigration("add lfs lock table", addLFSLock),
|
||||||
|
// v53 -> v54
|
||||||
NewMigration("add reactions", addReactions),
|
NewMigration("add reactions", addReactions),
|
||||||
// v51 -> v52
|
// v51 -> v52
|
||||||
NewMigration("add issue_dependencies", addIssueDependencies),
|
NewMigration("add issue_dependencies", addIssueDependencies),
|
||||||
|
|
|
||||||
|
|
@ -6,69 +6,52 @@ package migrations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/git"
|
||||||
|
"code.gitea.io/gitea/models"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func addTimetracking(x *xorm.Engine) error {
|
// ReleaseV39 describes the added field for Release
|
||||||
// RepoUnit describes all units of a repository
|
type ReleaseV39 struct {
|
||||||
type RepoUnit struct {
|
IsTag bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
ID int64
|
}
|
||||||
RepoID int64 `xorm:"INDEX(s)"`
|
|
||||||
Type int `xorm:"INDEX(s)"`
|
|
||||||
Index int
|
|
||||||
Config map[string]interface{} `xorm:"JSON"`
|
|
||||||
CreatedUnix int64 `xorm:"INDEX CREATED"`
|
|
||||||
Created time.Time `xorm:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stopwatch see models/issue_stopwatch.go
|
// TableName will be invoked by XORM to customrize the table name
|
||||||
type Stopwatch struct {
|
func (*ReleaseV39) TableName() string {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
return "release"
|
||||||
IssueID int64 `xorm:"INDEX"`
|
}
|
||||||
UserID int64 `xorm:"INDEX"`
|
|
||||||
Created time.Time `xorm:"-"`
|
|
||||||
CreatedUnix int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// TrackedTime see models/issue_tracked_time.go
|
func releaseAddColumnIsTagAndSyncTags(x *xorm.Engine) error {
|
||||||
type TrackedTime struct {
|
if err := x.Sync2(new(ReleaseV39)); err != nil {
|
||||||
ID int64 `xorm:"pk autoincr" json:"id"`
|
|
||||||
IssueID int64 `xorm:"INDEX" json:"issue_id"`
|
|
||||||
UserID int64 `xorm:"INDEX" json:"user_id"`
|
|
||||||
Created time.Time `xorm:"-" json:"created"`
|
|
||||||
CreatedUnix int64 `json:"-"`
|
|
||||||
Time int64 `json:"time"`
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := x.Sync2(new(Stopwatch)); err != nil {
|
|
||||||
return fmt.Errorf("Sync2: %v", err)
|
return fmt.Errorf("Sync2: %v", err)
|
||||||
}
|
}
|
||||||
if err := x.Sync2(new(TrackedTime)); err != nil {
|
|
||||||
return fmt.Errorf("Sync2: %v", err)
|
// For the sake of SQLite3, we can't use x.Iterate here.
|
||||||
}
|
offset := 0
|
||||||
//Updating existing issue units
|
pageSize := 20
|
||||||
units := make([]*RepoUnit, 0, 100)
|
for {
|
||||||
err := x.Where("`type` = ?", V16UnitTypeIssues).Find(&units)
|
repos := make([]*models.Repository, 0, pageSize)
|
||||||
if err != nil {
|
if err := x.Table("repository").Asc("id").Limit(pageSize, offset).Find(&repos); err != nil {
|
||||||
return fmt.Errorf("Query repo units: %v", err)
|
return fmt.Errorf("select repos [offset: %d]: %v", offset, err)
|
||||||
}
|
|
||||||
for _, unit := range units {
|
|
||||||
if unit.Config == nil {
|
|
||||||
unit.Config = make(map[string]interface{})
|
|
||||||
}
|
}
|
||||||
if _, ok := unit.Config["EnableTimetracker"]; !ok {
|
for _, repo := range repos {
|
||||||
unit.Config["EnableTimetracker"] = setting.Service.DefaultEnableTimetracking
|
gitRepo, err := git.OpenRepository(repo.RepoPath())
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("OpenRepository: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = models.SyncReleasesWithTags(repo, gitRepo); err != nil {
|
||||||
|
log.Warn("SyncReleasesWithTags: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if _, ok := unit.Config["AllowOnlyContributorsToTrackTime"]; !ok {
|
if len(repos) < pageSize {
|
||||||
unit.Config["AllowOnlyContributorsToTrackTime"] = setting.Service.DefaultAllowOnlyContributorsToTrackTime
|
break
|
||||||
}
|
|
||||||
if _, err := x.ID(unit.ID).Cols("config").Update(unit); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
offset += pageSize
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,50 +6,21 @@ package migrations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
|
||||||
|
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func migrateProtectedBranchStruct(x *xorm.Engine) error {
|
func fixProtectedBranchCanPushValue(x *xorm.Engine) error {
|
||||||
type ProtectedBranch struct {
|
type ProtectedBranch struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
CanPush bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
RepoID int64 `xorm:"UNIQUE(s)"`
|
|
||||||
BranchName string `xorm:"UNIQUE(s)"`
|
|
||||||
CanPush bool
|
|
||||||
Created time.Time `xorm:"-"`
|
|
||||||
CreatedUnix int64
|
|
||||||
Updated time.Time `xorm:"-"`
|
|
||||||
UpdatedUnix int64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var pbs []ProtectedBranch
|
if err := x.Sync2(new(ProtectedBranch)); err != nil {
|
||||||
err := x.Find(&pbs)
|
return fmt.Errorf("Sync2: %v", err)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pb := range pbs {
|
_, err := x.Cols("can_push").Update(&ProtectedBranch{
|
||||||
if pb.CanPush {
|
CanPush: false,
|
||||||
if _, err = x.ID(pb.ID).Delete(new(ProtectedBranch)); err != nil {
|
})
|
||||||
return err
|
return err
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case setting.UseSQLite3:
|
|
||||||
log.Warn("Unable to drop columns in SQLite")
|
|
||||||
case setting.UseMySQL, setting.UsePostgreSQL, setting.UseMSSQL, setting.UseTiDB:
|
|
||||||
if _, err := x.Exec("ALTER TABLE protected_branch DROP COLUMN can_push"); err != nil {
|
|
||||||
return fmt.Errorf("DROP COLUMN can_push: %v", err)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
log.Fatal(4, "Unrecognized DB")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,36 +7,63 @@ package migrations
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
|
||||||
|
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func addDefaultValueToUserProhibitLogin(x *xorm.Engine) (err error) {
|
func removeDuplicateUnitTypes(x *xorm.Engine) error {
|
||||||
user := &models.User{
|
// RepoUnit describes all units of a repository
|
||||||
ProhibitLogin: false,
|
type RepoUnit struct {
|
||||||
|
RepoID int64
|
||||||
|
Type int
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := x.Where("`prohibit_login` IS NULL").Cols("prohibit_login").Update(user); err != nil {
|
// Enumerate all the unit types
|
||||||
|
const (
|
||||||
|
UnitTypeCode = iota + 1 // 1 code
|
||||||
|
UnitTypeIssues // 2 issues
|
||||||
|
UnitTypePullRequests // 3 PRs
|
||||||
|
UnitTypeReleases // 4 Releases
|
||||||
|
UnitTypeWiki // 5 Wiki
|
||||||
|
UnitTypeExternalWiki // 6 ExternalWiki
|
||||||
|
UnitTypeExternalTracker // 7 ExternalTracker
|
||||||
|
)
|
||||||
|
|
||||||
|
var externalIssueRepoUnits []RepoUnit
|
||||||
|
err := x.Where("type = ?", UnitTypeExternalTracker).Find(&externalIssueRepoUnits)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Query repositories: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var externalWikiRepoUnits []RepoUnit
|
||||||
|
err = x.Where("type = ?", UnitTypeExternalWiki).Find(&externalWikiRepoUnits)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Query repositories: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sess := x.NewSession()
|
||||||
|
defer sess.Close()
|
||||||
|
|
||||||
|
if err := sess.Begin(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
dialect := x.Dialect().DriverName()
|
for _, repoUnit := range externalIssueRepoUnits {
|
||||||
|
if _, err = sess.Delete(&RepoUnit{
|
||||||
switch dialect {
|
RepoID: repoUnit.RepoID,
|
||||||
case "mysql":
|
Type: UnitTypeIssues,
|
||||||
_, err = x.Exec("ALTER TABLE user MODIFY `prohibit_login` tinyint(1) NOT NULL DEFAULT 0")
|
}); err != nil {
|
||||||
case "postgres":
|
return fmt.Errorf("Delete repo unit: %v", err)
|
||||||
_, err = x.Exec("ALTER TABLE \"user\" ALTER COLUMN `prohibit_login` SET NOT NULL, ALTER COLUMN `prohibit_login` SET DEFAULT false")
|
}
|
||||||
case "mssql":
|
|
||||||
// xorm already set DEFAULT 0 for data type BIT in mssql
|
|
||||||
_, err = x.Exec(`ALTER TABLE [user] ALTER COLUMN "prohibit_login" BIT NOT NULL`)
|
|
||||||
case "sqlite3":
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
for _, repoUnit := range externalWikiRepoUnits {
|
||||||
return fmt.Errorf("Error changing user prohibit_login column definition: %v", err)
|
if _, err = sess.Delete(&RepoUnit{
|
||||||
|
RepoID: repoUnit.RepoID,
|
||||||
|
Type: UnitTypeWiki,
|
||||||
|
}); err != nil {
|
||||||
|
return fmt.Errorf("Delete repo unit: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return sess.Commit()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
// Copyright 2017 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 (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"code.gitea.io/git"
|
|
||||||
"code.gitea.io/gitea/models"
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
|
||||||
|
|
||||||
"github.com/go-xorm/xorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ReleaseV39 describes the added field for Release
|
|
||||||
type ReleaseV39 struct {
|
|
||||||
IsTag bool `xorm:"NOT NULL DEFAULT false"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// TableName will be invoked by XORM to customrize the table name
|
|
||||||
func (*ReleaseV39) TableName() string {
|
|
||||||
return "release"
|
|
||||||
}
|
|
||||||
|
|
||||||
func releaseAddColumnIsTagAndSyncTags(x *xorm.Engine) error {
|
|
||||||
if err := x.Sync2(new(ReleaseV39)); err != nil {
|
|
||||||
return fmt.Errorf("Sync2: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// For the sake of SQLite3, we can't use x.Iterate here.
|
|
||||||
offset := 0
|
|
||||||
pageSize := 20
|
|
||||||
for {
|
|
||||||
repos := make([]*models.Repository, 0, pageSize)
|
|
||||||
if err := x.Table("repository").Asc("id").Limit(pageSize, offset).Find(&repos); err != nil {
|
|
||||||
return fmt.Errorf("select repos [offset: %d]: %v", offset, err)
|
|
||||||
}
|
|
||||||
for _, repo := range repos {
|
|
||||||
gitRepo, err := git.OpenRepository(repo.RepoPath())
|
|
||||||
if err != nil {
|
|
||||||
log.Warn("OpenRepository: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = models.SyncReleasesWithTags(repo, gitRepo); err != nil {
|
|
||||||
log.Warn("SyncReleasesWithTags: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(repos) < pageSize {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
offset += pageSize
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
// Copyright 2017 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 (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/go-xorm/xorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
func fixProtectedBranchCanPushValue(x *xorm.Engine) error {
|
|
||||||
type ProtectedBranch struct {
|
|
||||||
CanPush bool `xorm:"NOT NULL DEFAULT false"`
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := x.Sync2(new(ProtectedBranch)); err != nil {
|
|
||||||
return fmt.Errorf("Sync2: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := x.Cols("can_push").Update(&ProtectedBranch{
|
|
||||||
CanPush: false,
|
|
||||||
})
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
// Copyright 2017 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 (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/go-xorm/xorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
func removeDuplicateUnitTypes(x *xorm.Engine) error {
|
|
||||||
// RepoUnit describes all units of a repository
|
|
||||||
type RepoUnit struct {
|
|
||||||
RepoID int64
|
|
||||||
Type int
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enumerate all the unit types
|
|
||||||
const (
|
|
||||||
UnitTypeCode = iota + 1 // 1 code
|
|
||||||
UnitTypeIssues // 2 issues
|
|
||||||
UnitTypePullRequests // 3 PRs
|
|
||||||
UnitTypeReleases // 4 Releases
|
|
||||||
UnitTypeWiki // 5 Wiki
|
|
||||||
UnitTypeExternalWiki // 6 ExternalWiki
|
|
||||||
UnitTypeExternalTracker // 7 ExternalTracker
|
|
||||||
)
|
|
||||||
|
|
||||||
var externalIssueRepoUnits []RepoUnit
|
|
||||||
err := x.Where("type = ?", UnitTypeExternalTracker).Find(&externalIssueRepoUnits)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Query repositories: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var externalWikiRepoUnits []RepoUnit
|
|
||||||
err = x.Where("type = ?", UnitTypeExternalWiki).Find(&externalWikiRepoUnits)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Query repositories: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
sess := x.NewSession()
|
|
||||||
defer sess.Close()
|
|
||||||
|
|
||||||
if err := sess.Begin(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, repoUnit := range externalIssueRepoUnits {
|
|
||||||
if _, err = sess.Delete(&RepoUnit{
|
|
||||||
RepoID: repoUnit.RepoID,
|
|
||||||
Type: UnitTypeIssues,
|
|
||||||
}); err != nil {
|
|
||||||
return fmt.Errorf("Delete repo unit: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, repoUnit := range externalWikiRepoUnits {
|
|
||||||
if _, err = sess.Delete(&RepoUnit{
|
|
||||||
RepoID: repoUnit.RepoID,
|
|
||||||
Type: UnitTypeWiki,
|
|
||||||
}); err != nil {
|
|
||||||
return fmt.Errorf("Delete repo unit: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
|
||||||
|
|
@ -5,10 +5,9 @@
|
||||||
package migrations
|
package migrations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -18,7 +17,8 @@ func removeIndexColumnFromRepoUnitTable(x *xorm.Engine) (err error) {
|
||||||
log.Warn("Unable to drop columns in SQLite")
|
log.Warn("Unable to drop columns in SQLite")
|
||||||
case setting.UseMySQL, setting.UsePostgreSQL, setting.UseMSSQL, setting.UseTiDB:
|
case setting.UseMySQL, setting.UsePostgreSQL, setting.UseMSSQL, setting.UseTiDB:
|
||||||
if _, err := x.Exec("ALTER TABLE repo_unit DROP COLUMN `index`"); err != nil {
|
if _, err := x.Exec("ALTER TABLE repo_unit DROP COLUMN `index`"); err != nil {
|
||||||
return fmt.Errorf("DROP COLUMN index: %v", err)
|
// Ignoring this error in case we run this migration second time (after migration reordering)
|
||||||
|
log.Warn("DROP COLUMN index: %v", err)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
log.Fatal(4, "Unrecognized DB")
|
log.Fatal(4, "Unrecognized DB")
|
||||||
|
|
|
||||||
|
|
@ -8,24 +8,66 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func addLFSLock(x *xorm.Engine) error {
|
func addTimetracking(x *xorm.Engine) error {
|
||||||
// LFSLock see models/lfs_lock.go
|
// RepoUnit describes all units of a repository
|
||||||
type LFSLock struct {
|
type RepoUnit struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64
|
||||||
RepoID int64 `xorm:"INDEX NOT NULL"`
|
RepoID int64 `xorm:"INDEX(s)"`
|
||||||
Owner *models.User `xorm:"-"`
|
Type int `xorm:"INDEX(s)"`
|
||||||
OwnerID int64 `xorm:"INDEX NOT NULL"`
|
Config map[string]interface{} `xorm:"JSON"`
|
||||||
Path string `xorm:"TEXT"`
|
CreatedUnix int64 `xorm:"INDEX CREATED"`
|
||||||
Created time.Time `xorm:"created"`
|
Created time.Time `xorm:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := x.Sync2(new(LFSLock)); err != nil {
|
// Stopwatch see models/issue_stopwatch.go
|
||||||
|
type Stopwatch struct {
|
||||||
|
ID int64 `xorm:"pk autoincr"`
|
||||||
|
IssueID int64 `xorm:"INDEX"`
|
||||||
|
UserID int64 `xorm:"INDEX"`
|
||||||
|
Created time.Time `xorm:"-"`
|
||||||
|
CreatedUnix int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrackedTime see models/issue_tracked_time.go
|
||||||
|
type TrackedTime struct {
|
||||||
|
ID int64 `xorm:"pk autoincr" json:"id"`
|
||||||
|
IssueID int64 `xorm:"INDEX" json:"issue_id"`
|
||||||
|
UserID int64 `xorm:"INDEX" json:"user_id"`
|
||||||
|
Created time.Time `xorm:"-" json:"created"`
|
||||||
|
CreatedUnix int64 `json:"-"`
|
||||||
|
Time int64 `json:"time"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := x.Sync2(new(Stopwatch)); err != nil {
|
||||||
return fmt.Errorf("Sync2: %v", err)
|
return fmt.Errorf("Sync2: %v", err)
|
||||||
}
|
}
|
||||||
|
if err := x.Sync2(new(TrackedTime)); err != nil {
|
||||||
|
return fmt.Errorf("Sync2: %v", err)
|
||||||
|
}
|
||||||
|
//Updating existing issue units
|
||||||
|
units := make([]*RepoUnit, 0, 100)
|
||||||
|
err := x.Where("`type` = ?", V16UnitTypeIssues).Find(&units)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Query repo units: %v", err)
|
||||||
|
}
|
||||||
|
for _, unit := range units {
|
||||||
|
if unit.Config == nil {
|
||||||
|
unit.Config = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
if _, ok := unit.Config["EnableTimetracker"]; !ok {
|
||||||
|
unit.Config["EnableTimetracker"] = setting.Service.DefaultEnableTimetracking
|
||||||
|
}
|
||||||
|
if _, ok := unit.Config["AllowOnlyContributorsToTrackTime"]; !ok {
|
||||||
|
unit.Config["AllowOnlyContributorsToTrackTime"] = setting.Service.DefaultAllowOnlyContributorsToTrackTime
|
||||||
|
}
|
||||||
|
if _, err := x.ID(unit.ID).Cols("config").Update(unit); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,24 +5,51 @@
|
||||||
package migrations
|
package migrations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func addReactions(x *xorm.Engine) error {
|
func migrateProtectedBranchStruct(x *xorm.Engine) error {
|
||||||
// Reaction see models/issue_reaction.go
|
type ProtectedBranch struct {
|
||||||
type Reaction struct {
|
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
Type string `xorm:"INDEX UNIQUE(s) NOT NULL"`
|
RepoID int64 `xorm:"UNIQUE(s)"`
|
||||||
IssueID int64 `xorm:"INDEX UNIQUE(s) NOT NULL"`
|
BranchName string `xorm:"UNIQUE(s)"`
|
||||||
CommentID int64 `xorm:"INDEX UNIQUE(s)"`
|
CanPush bool
|
||||||
UserID int64 `xorm:"INDEX UNIQUE(s) NOT NULL"`
|
Created time.Time `xorm:"-"`
|
||||||
CreatedUnix int64 `xorm:"INDEX created"`
|
CreatedUnix int64
|
||||||
|
Updated time.Time `xorm:"-"`
|
||||||
|
UpdatedUnix int64
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := x.Sync2(new(Reaction)); err != nil {
|
var pbs []ProtectedBranch
|
||||||
return fmt.Errorf("Sync2: %v", err)
|
err := x.Find(&pbs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, pb := range pbs {
|
||||||
|
if pb.CanPush {
|
||||||
|
if _, err = x.ID(pb.ID).Delete(new(ProtectedBranch)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case setting.UseSQLite3:
|
||||||
|
log.Warn("Unable to drop columns in SQLite")
|
||||||
|
case setting.UseMySQL, setting.UsePostgreSQL, setting.UseMSSQL, setting.UseTiDB:
|
||||||
|
if _, err := x.Exec("ALTER TABLE protected_branch DROP COLUMN can_push"); err != nil {
|
||||||
|
// Ignoring this error in case we run this migration second time (after migration reordering)
|
||||||
|
log.Warn("DROP COLUMN can_push (skipping): %v", err)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Fatal(4, "Unrecognized DB")
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,56 +5,38 @@
|
||||||
package migrations
|
package migrations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"code.gitea.io/gitea/models"
|
||||||
"time"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func addIssueDependencies(x *xorm.Engine) (err error) {
|
func addDefaultValueToUserProhibitLogin(x *xorm.Engine) (err error) {
|
||||||
|
user := &models.User{
|
||||||
type IssueDependency struct {
|
ProhibitLogin: false,
|
||||||
ID int64 `xorm:"pk autoincr"`
|
|
||||||
UserID int64 `xorm:"NOT NULL"`
|
|
||||||
IssueID int64 `xorm:"NOT NULL"`
|
|
||||||
DependencyID int64 `xorm:"NOT NULL"`
|
|
||||||
Created time.Time `xorm:"-"`
|
|
||||||
CreatedUnix int64 `xorm:"INDEX created"`
|
|
||||||
Updated time.Time `xorm:"-"`
|
|
||||||
UpdatedUnix int64 `xorm:"updated"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = x.Sync(new(IssueDependency)); err != nil {
|
if _, err := x.Where("`prohibit_login` IS NULL").Cols("prohibit_login").Update(user); err != nil {
|
||||||
return fmt.Errorf("Error creating issue_dependency_table column definition: %v", err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// RepoUnit describes all units of a repository
|
dialect := x.Dialect().DriverName()
|
||||||
type RepoUnit struct {
|
|
||||||
ID int64
|
switch dialect {
|
||||||
RepoID int64 `xorm:"INDEX(s)"`
|
case "mysql":
|
||||||
Type int `xorm:"INDEX(s)"`
|
_, err = x.Exec("ALTER TABLE user MODIFY `prohibit_login` tinyint(1) NOT NULL DEFAULT 0")
|
||||||
Config map[string]interface{} `xorm:"JSON"`
|
case "postgres":
|
||||||
CreatedUnix int64 `xorm:"INDEX CREATED"`
|
_, err = x.Exec("ALTER TABLE \"user\" ALTER COLUMN `prohibit_login` SET NOT NULL, ALTER COLUMN `prohibit_login` SET DEFAULT false")
|
||||||
Created time.Time `xorm:"-"`
|
case "mssql":
|
||||||
|
// xorm already set DEFAULT 0 for data type BIT in mssql
|
||||||
|
_, err = x.Exec(`ALTER TABLE [user] ALTER COLUMN "prohibit_login" BIT NOT NULL`)
|
||||||
|
case "sqlite3":
|
||||||
}
|
}
|
||||||
|
|
||||||
//Updating existing issue units
|
|
||||||
units := make([]*RepoUnit, 0, 100)
|
|
||||||
err = x.Where("`type` = ?", V16UnitTypeIssues).Find(&units)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Query repo units: %v", err)
|
// Ignoring this error in case we run this migration second time (after migration reordering)
|
||||||
}
|
log.Warn("Error changing user prohibit_login column definition (skipping): %v", err)
|
||||||
for _, unit := range units {
|
|
||||||
if unit.Config == nil {
|
|
||||||
unit.Config = make(map[string]interface{})
|
|
||||||
}
|
|
||||||
if _, ok := unit.Config["EnableDependencies"]; !ok {
|
|
||||||
unit.Config["EnableDependencies"] = setting.Service.DefaultEnableDependencies
|
|
||||||
}
|
|
||||||
if _, err := x.ID(unit.ID).Cols("config").Update(unit); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
31
models/migrations/v52.go
Normal file
31
models/migrations/v52.go
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright 2017 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 (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models"
|
||||||
|
|
||||||
|
"github.com/go-xorm/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func addLFSLock(x *xorm.Engine) error {
|
||||||
|
// LFSLock see models/lfs_lock.go
|
||||||
|
type LFSLock struct {
|
||||||
|
ID int64 `xorm:"pk autoincr"`
|
||||||
|
RepoID int64 `xorm:"INDEX NOT NULL"`
|
||||||
|
Owner *models.User `xorm:"-"`
|
||||||
|
OwnerID int64 `xorm:"INDEX NOT NULL"`
|
||||||
|
Path string `xorm:"TEXT"`
|
||||||
|
Created time.Time `xorm:"created"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := x.Sync2(new(LFSLock)); err != nil {
|
||||||
|
return fmt.Errorf("Sync2: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
28
models/migrations/v53.go
Normal file
28
models/migrations/v53.go
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
// Copyright 2017 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 (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/go-xorm/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func addReactions(x *xorm.Engine) error {
|
||||||
|
// Reaction see models/issue_reaction.go
|
||||||
|
type Reaction struct {
|
||||||
|
ID int64 `xorm:"pk autoincr"`
|
||||||
|
Type string `xorm:"INDEX UNIQUE(s) NOT NULL"`
|
||||||
|
IssueID int64 `xorm:"INDEX UNIQUE(s) NOT NULL"`
|
||||||
|
CommentID int64 `xorm:"INDEX UNIQUE(s)"`
|
||||||
|
UserID int64 `xorm:"INDEX UNIQUE(s) NOT NULL"`
|
||||||
|
CreatedUnix int64 `xorm:"INDEX created"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := x.Sync2(new(Reaction)); err != nil {
|
||||||
|
return fmt.Errorf("Sync2: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
1
models/migrations/v54.go
Normal file
1
models/migrations/v54.go
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
package migrations
|
||||||
|
|
@ -6,7 +6,8 @@ package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
|
@ -51,32 +52,8 @@ type Notification struct {
|
||||||
Issue *Issue `xorm:"-"`
|
Issue *Issue `xorm:"-"`
|
||||||
Repository *Repository `xorm:"-"`
|
Repository *Repository `xorm:"-"`
|
||||||
|
|
||||||
Created time.Time `xorm:"-"`
|
CreatedUnix util.TimeStamp `xorm:"created INDEX NOT NULL"`
|
||||||
CreatedUnix int64 `xorm:"INDEX NOT NULL"`
|
UpdatedUnix util.TimeStamp `xorm:"updated INDEX NOT NULL"`
|
||||||
Updated time.Time `xorm:"-"`
|
|
||||||
UpdatedUnix int64 `xorm:"INDEX NOT NULL"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// BeforeInsert runs while inserting a record
|
|
||||||
func (n *Notification) BeforeInsert() {
|
|
||||||
var (
|
|
||||||
now = time.Now()
|
|
||||||
nowUnix = now.Unix()
|
|
||||||
)
|
|
||||||
n.Created = now
|
|
||||||
n.CreatedUnix = nowUnix
|
|
||||||
n.Updated = now
|
|
||||||
n.UpdatedUnix = nowUnix
|
|
||||||
}
|
|
||||||
|
|
||||||
// BeforeUpdate runs while updating a record
|
|
||||||
func (n *Notification) BeforeUpdate() {
|
|
||||||
var (
|
|
||||||
now = time.Now()
|
|
||||||
nowUnix = now.Unix()
|
|
||||||
)
|
|
||||||
n.Updated = now
|
|
||||||
n.UpdatedUnix = nowUnix
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateOrUpdateIssueNotifications creates an issue notification
|
// CreateOrUpdateIssueNotifications creates an issue notification
|
||||||
|
|
@ -212,6 +189,7 @@ func getIssueNotification(e Engine, userID, issueID int64) (*Notification, error
|
||||||
func NotificationsForUser(user *User, statuses []NotificationStatus, page, perPage int) ([]*Notification, error) {
|
func NotificationsForUser(user *User, statuses []NotificationStatus, page, perPage int) ([]*Notification, error) {
|
||||||
return notificationsForUser(x, user, statuses, page, perPage)
|
return notificationsForUser(x, user, statuses, page, perPage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func notificationsForUser(e Engine, user *User, statuses []NotificationStatus, page, perPage int) (notifications []*Notification, err error) {
|
func notificationsForUser(e Engine, user *User, statuses []NotificationStatus, page, perPage int) (notifications []*Notification, err error) {
|
||||||
if len(statuses) == 0 {
|
if len(statuses) == 0 {
|
||||||
return
|
return
|
||||||
|
|
@ -311,3 +289,13 @@ func getNotificationByID(notificationID int64) (*Notification, error) {
|
||||||
|
|
||||||
return notification, nil
|
return notification, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateNotificationStatuses updates the statuses of all of a user's notifications that are of the currentStatus type to the desiredStatus
|
||||||
|
func UpdateNotificationStatuses(user *User, currentStatus NotificationStatus, desiredStatus NotificationStatus) error {
|
||||||
|
n := &Notification{Status: desiredStatus, UpdatedBy: user.ID}
|
||||||
|
_, err := x.
|
||||||
|
Where("user_id = ? AND status = ?", user.ID, currentStatus).
|
||||||
|
Cols("status", "updated_by", "updated_unix").
|
||||||
|
Update(n)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,11 @@ func TestNotificationsForUser(t *testing.T) {
|
||||||
statuses := []NotificationStatus{NotificationStatusRead, NotificationStatusUnread}
|
statuses := []NotificationStatus{NotificationStatusRead, NotificationStatusUnread}
|
||||||
notfs, err := NotificationsForUser(user, statuses, 1, 10)
|
notfs, err := NotificationsForUser(user, statuses, 1, 10)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if assert.Len(t, notfs, 1) {
|
if assert.Len(t, notfs, 2) {
|
||||||
assert.EqualValues(t, 2, notfs[0].ID)
|
assert.EqualValues(t, 2, notfs[0].ID)
|
||||||
assert.EqualValues(t, user.ID, notfs[0].UserID)
|
assert.EqualValues(t, user.ID, notfs[0].UserID)
|
||||||
|
assert.EqualValues(t, 4, notfs[1].ID)
|
||||||
|
assert.EqualValues(t, user.ID, notfs[1].UserID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,12 +59,12 @@ func TestNotification_GetIssue(t *testing.T) {
|
||||||
|
|
||||||
func TestGetNotificationCount(t *testing.T) {
|
func TestGetNotificationCount(t *testing.T) {
|
||||||
assert.NoError(t, PrepareTestDatabase())
|
assert.NoError(t, PrepareTestDatabase())
|
||||||
user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
|
user := AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
|
||||||
cnt, err := GetNotificationCount(user, NotificationStatusUnread)
|
cnt, err := GetNotificationCount(user, NotificationStatusRead)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 0, cnt)
|
assert.EqualValues(t, 0, cnt)
|
||||||
|
|
||||||
cnt, err = GetNotificationCount(user, NotificationStatusRead)
|
cnt, err = GetNotificationCount(user, NotificationStatusUnread)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 1, cnt)
|
assert.EqualValues(t, 1, cnt)
|
||||||
}
|
}
|
||||||
|
|
@ -79,3 +81,21 @@ func TestSetNotificationStatus(t *testing.T) {
|
||||||
assert.Error(t, SetNotificationStatus(1, user, NotificationStatusRead))
|
assert.Error(t, SetNotificationStatus(1, user, NotificationStatusRead))
|
||||||
assert.Error(t, SetNotificationStatus(NonexistentID, user, NotificationStatusRead))
|
assert.Error(t, SetNotificationStatus(NonexistentID, user, NotificationStatusRead))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUpdateNotificationStatuses(t *testing.T) {
|
||||||
|
assert.NoError(t, PrepareTestDatabase())
|
||||||
|
user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
|
||||||
|
notfUnread := AssertExistsAndLoadBean(t,
|
||||||
|
&Notification{UserID: user.ID, Status: NotificationStatusUnread}).(*Notification)
|
||||||
|
notfRead := AssertExistsAndLoadBean(t,
|
||||||
|
&Notification{UserID: user.ID, Status: NotificationStatusRead}).(*Notification)
|
||||||
|
notfPinned := AssertExistsAndLoadBean(t,
|
||||||
|
&Notification{UserID: user.ID, Status: NotificationStatusPinned}).(*Notification)
|
||||||
|
assert.NoError(t, UpdateNotificationStatuses(user, NotificationStatusUnread, NotificationStatusRead))
|
||||||
|
AssertExistsAndLoadBean(t,
|
||||||
|
&Notification{ID: notfUnread.ID, Status: NotificationStatusRead})
|
||||||
|
AssertExistsAndLoadBean(t,
|
||||||
|
&Notification{ID: notfRead.ID, Status: NotificationStatusRead})
|
||||||
|
AssertExistsAndLoadBean(t,
|
||||||
|
&Notification{ID: notfPinned.ID, Status: NotificationStatusPinned})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -453,7 +453,12 @@ func RemoveOrgUser(orgID, userID int64) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if t.NumMembers == 1 {
|
if t.NumMembers == 1 {
|
||||||
return ErrLastOrgOwner{UID: userID}
|
if err := t.GetMembers(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if t.Members[0].ID == userID {
|
||||||
|
return ErrLastOrgOwner{UID: userID}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/process"
|
"code.gitea.io/gitea/modules/process"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/sync"
|
"code.gitea.io/gitea/modules/sync"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
api "code.gitea.io/sdk/gitea"
|
api "code.gitea.io/sdk/gitea"
|
||||||
|
|
||||||
"github.com/Unknwon/com"
|
"github.com/Unknwon/com"
|
||||||
|
|
@ -67,27 +68,11 @@ type PullRequest struct {
|
||||||
BaseBranch string
|
BaseBranch string
|
||||||
MergeBase string `xorm:"VARCHAR(40)"`
|
MergeBase string `xorm:"VARCHAR(40)"`
|
||||||
|
|
||||||
HasMerged bool `xorm:"INDEX"`
|
HasMerged bool `xorm:"INDEX"`
|
||||||
MergedCommitID string `xorm:"VARCHAR(40)"`
|
MergedCommitID string `xorm:"VARCHAR(40)"`
|
||||||
MergerID int64 `xorm:"INDEX"`
|
MergerID int64 `xorm:"INDEX"`
|
||||||
Merger *User `xorm:"-"`
|
Merger *User `xorm:"-"`
|
||||||
Merged time.Time `xorm:"-"`
|
MergedUnix util.TimeStamp `xorm:"updated INDEX"`
|
||||||
MergedUnix int64 `xorm:"INDEX"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// BeforeUpdate is invoked from XORM before updating an object of this type.
|
|
||||||
func (pr *PullRequest) BeforeUpdate() {
|
|
||||||
pr.MergedUnix = pr.Merged.Unix()
|
|
||||||
}
|
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
|
||||||
// Note: don't try to get Issue because will end up recursive querying.
|
|
||||||
func (pr *PullRequest) AfterLoad() {
|
|
||||||
if !pr.HasMerged {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pr.Merged = time.Unix(pr.MergedUnix, 0).Local()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: don't try to get Issue because will end up recursive querying.
|
// Note: don't try to get Issue because will end up recursive querying.
|
||||||
|
|
@ -194,8 +179,8 @@ func (pr *PullRequest) APIFormat() *api.PullRequest {
|
||||||
Base: apiBaseBranchInfo,
|
Base: apiBaseBranchInfo,
|
||||||
Head: apiHeadBranchInfo,
|
Head: apiHeadBranchInfo,
|
||||||
MergeBase: pr.MergeBase,
|
MergeBase: pr.MergeBase,
|
||||||
Created: &pr.Issue.Created,
|
Created: pr.Issue.CreatedUnix.AsTimePtr(),
|
||||||
Updated: &pr.Issue.Updated,
|
Updated: pr.Issue.UpdatedUnix.AsTimePtr(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if pr.Status != PullRequestStatusChecking {
|
if pr.Status != PullRequestStatusChecking {
|
||||||
|
|
@ -203,7 +188,7 @@ func (pr *PullRequest) APIFormat() *api.PullRequest {
|
||||||
apiPullRequest.Mergeable = mergeable
|
apiPullRequest.Mergeable = mergeable
|
||||||
}
|
}
|
||||||
if pr.HasMerged {
|
if pr.HasMerged {
|
||||||
apiPullRequest.Merged = &pr.Merged
|
apiPullRequest.Merged = pr.MergedUnix.AsTimePtr()
|
||||||
apiPullRequest.MergedCommitID = &pr.MergedCommitID
|
apiPullRequest.MergedCommitID = &pr.MergedCommitID
|
||||||
apiPullRequest.MergedBy = pr.Merger.APIFormat()
|
apiPullRequest.MergedBy = pr.Merger.APIFormat()
|
||||||
}
|
}
|
||||||
|
|
@ -330,7 +315,7 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error
|
||||||
return fmt.Errorf("GetBranchCommit: %v", err)
|
return fmt.Errorf("GetBranchCommit: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pr.Merged = time.Now()
|
pr.MergedUnix = util.TimeStampNow()
|
||||||
pr.Merger = doer
|
pr.Merger = doer
|
||||||
pr.MergerID = doer.ID
|
pr.MergerID = doer.ID
|
||||||
|
|
||||||
|
|
@ -396,7 +381,7 @@ func (pr *PullRequest) setMerged() (err error) {
|
||||||
if pr.HasMerged {
|
if pr.HasMerged {
|
||||||
return fmt.Errorf("PullRequest[%d] already merged", pr.Index)
|
return fmt.Errorf("PullRequest[%d] already merged", pr.Index)
|
||||||
}
|
}
|
||||||
if pr.MergedCommitID == "" || pr.Merged.IsZero() || pr.Merger == nil {
|
if pr.MergedCommitID == "" || pr.MergedUnix == 0 || pr.Merger == nil {
|
||||||
return fmt.Errorf("Unable to merge PullRequest[%d], some required fields are empty", pr.Index)
|
return fmt.Errorf("Unable to merge PullRequest[%d], some required fields are empty", pr.Index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -442,7 +427,7 @@ func (pr *PullRequest) manuallyMerged() bool {
|
||||||
}
|
}
|
||||||
if commit != nil {
|
if commit != nil {
|
||||||
pr.MergedCommitID = commit.ID.String()
|
pr.MergedCommitID = commit.ID.String()
|
||||||
pr.Merged = commit.Author.When
|
pr.MergedUnix = util.TimeStamp(commit.Author.When.Unix())
|
||||||
pr.Status = PullRequestStatusManuallyMerged
|
pr.Status = PullRequestStatusManuallyMerged
|
||||||
merger, _ := GetUserByEmail(commit.Author.Email)
|
merger, _ := GetUserByEmail(commit.Author.Email)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,11 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"code.gitea.io/git"
|
"code.gitea.io/git"
|
||||||
"code.gitea.io/gitea/modules/process"
|
"code.gitea.io/gitea/modules/process"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
api "code.gitea.io/sdk/gitea"
|
api "code.gitea.io/sdk/gitea"
|
||||||
"github.com/go-xorm/builder"
|
"github.com/go-xorm/builder"
|
||||||
)
|
)
|
||||||
|
|
@ -30,28 +30,13 @@ type Release struct {
|
||||||
Title string
|
Title string
|
||||||
Sha1 string `xorm:"VARCHAR(40)"`
|
Sha1 string `xorm:"VARCHAR(40)"`
|
||||||
NumCommits int64
|
NumCommits int64
|
||||||
NumCommitsBehind int64 `xorm:"-"`
|
NumCommitsBehind int64 `xorm:"-"`
|
||||||
Note string `xorm:"TEXT"`
|
Note string `xorm:"TEXT"`
|
||||||
IsDraft bool `xorm:"NOT NULL DEFAULT false"`
|
IsDraft bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
IsPrerelease bool `xorm:"NOT NULL DEFAULT false"`
|
IsPrerelease bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
IsTag bool `xorm:"NOT NULL DEFAULT false"`
|
IsTag bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
|
Attachments []*Attachment `xorm:"-"`
|
||||||
Attachments []*Attachment `xorm:"-"`
|
CreatedUnix util.TimeStamp `xorm:"created INDEX"`
|
||||||
|
|
||||||
Created time.Time `xorm:"-"`
|
|
||||||
CreatedUnix int64 `xorm:"INDEX"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// BeforeInsert is invoked from XORM before inserting an object of this type.
|
|
||||||
func (r *Release) BeforeInsert() {
|
|
||||||
if r.CreatedUnix == 0 {
|
|
||||||
r.CreatedUnix = time.Now().Unix()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
|
||||||
func (r *Release) AfterLoad() {
|
|
||||||
r.Created = time.Unix(r.CreatedUnix, 0).Local()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Release) loadAttributes(e Engine) error {
|
func (r *Release) loadAttributes(e Engine) error {
|
||||||
|
|
@ -104,8 +89,8 @@ func (r *Release) APIFormat() *api.Release {
|
||||||
ZipURL: r.ZipURL(),
|
ZipURL: r.ZipURL(),
|
||||||
IsDraft: r.IsDraft,
|
IsDraft: r.IsDraft,
|
||||||
IsPrerelease: r.IsPrerelease,
|
IsPrerelease: r.IsPrerelease,
|
||||||
CreatedAt: r.Created,
|
CreatedAt: r.CreatedUnix.AsTime(),
|
||||||
PublishedAt: r.Created,
|
PublishedAt: r.CreatedUnix.AsTime(),
|
||||||
Publisher: r.Publisher.APIFormat(),
|
Publisher: r.Publisher.APIFormat(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -144,7 +129,7 @@ func createTag(gitRepo *git.Repository, rel *Release) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
rel.Sha1 = commit.ID.String()
|
rel.Sha1 = commit.ID.String()
|
||||||
rel.CreatedUnix = commit.Author.When.Unix()
|
rel.CreatedUnix = util.TimeStamp(commit.Author.When.Unix())
|
||||||
rel.NumCommits, err = commit.CommitsCount()
|
rel.NumCommits, err = commit.CommitsCount()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("CommitsCount: %v", err)
|
return fmt.Errorf("CommitsCount: %v", err)
|
||||||
|
|
@ -345,7 +330,7 @@ func (rs *releaseSorter) Less(i, j int) bool {
|
||||||
if diffNum != 0 {
|
if diffNum != 0 {
|
||||||
return diffNum > 0
|
return diffNum > 0
|
||||||
}
|
}
|
||||||
return rs.rels[i].Created.After(rs.rels[j].Created)
|
return rs.rels[i].CreatedUnix > rs.rels[j].CreatedUnix
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *releaseSorter) Swap(i, j int) {
|
func (rs *releaseSorter) Swap(i, j int) {
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/process"
|
"code.gitea.io/gitea/modules/process"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/sync"
|
"code.gitea.io/gitea/modules/sync"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
api "code.gitea.io/sdk/gitea"
|
api "code.gitea.io/sdk/gitea"
|
||||||
|
|
||||||
"github.com/Unknwon/cae/zip"
|
"github.com/Unknwon/cae/zip"
|
||||||
|
|
@ -211,10 +212,8 @@ type Repository struct {
|
||||||
Size int64 `xorm:"NOT NULL DEFAULT 0"`
|
Size int64 `xorm:"NOT NULL DEFAULT 0"`
|
||||||
IndexerStatus *RepoIndexerStatus `xorm:"-"`
|
IndexerStatus *RepoIndexerStatus `xorm:"-"`
|
||||||
|
|
||||||
Created time.Time `xorm:"-"`
|
CreatedUnix util.TimeStamp `xorm:"INDEX created"`
|
||||||
CreatedUnix int64 `xorm:"INDEX created"`
|
UpdatedUnix util.TimeStamp `xorm:"INDEX updated"`
|
||||||
Updated time.Time `xorm:"-"`
|
|
||||||
UpdatedUnix int64 `xorm:"INDEX updated"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
||||||
|
|
@ -227,8 +226,6 @@ func (repo *Repository) AfterLoad() {
|
||||||
repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
|
repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
|
||||||
repo.NumOpenPulls = repo.NumPulls - repo.NumClosedPulls
|
repo.NumOpenPulls = repo.NumPulls - repo.NumClosedPulls
|
||||||
repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
|
repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
|
||||||
repo.Created = time.Unix(repo.CreatedUnix, 0).Local()
|
|
||||||
repo.Updated = time.Unix(repo.UpdatedUnix, 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MustOwner always returns a valid *User object to avoid
|
// MustOwner always returns a valid *User object to avoid
|
||||||
|
|
@ -309,8 +306,8 @@ func (repo *Repository) innerAPIFormat(mode AccessMode, isParent bool) *api.Repo
|
||||||
Watchers: repo.NumWatches,
|
Watchers: repo.NumWatches,
|
||||||
OpenIssues: repo.NumOpenIssues,
|
OpenIssues: repo.NumOpenIssues,
|
||||||
DefaultBranch: repo.DefaultBranch,
|
DefaultBranch: repo.DefaultBranch,
|
||||||
Created: repo.Created,
|
Created: repo.CreatedUnix.AsTime(),
|
||||||
Updated: repo.Updated,
|
Updated: repo.UpdatedUnix.AsTime(),
|
||||||
Permissions: permission,
|
Permissions: permission,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -757,12 +754,17 @@ func (repo *Repository) DescriptionHTML() template.HTML {
|
||||||
return template.HTML(descPattern.ReplaceAllStringFunc(markup.Sanitize(repo.Description), sanitize))
|
return template.HTML(descPattern.ReplaceAllStringFunc(markup.Sanitize(repo.Description), sanitize))
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocalCopyPath returns the local repository copy path
|
// LocalCopyPath returns the local repository copy path.
|
||||||
func (repo *Repository) LocalCopyPath() string {
|
func LocalCopyPath() string {
|
||||||
if filepath.IsAbs(setting.Repository.Local.LocalCopyPath) {
|
if filepath.IsAbs(setting.Repository.Local.LocalCopyPath) {
|
||||||
return path.Join(setting.Repository.Local.LocalCopyPath, com.ToStr(repo.ID))
|
return setting.Repository.Local.LocalCopyPath
|
||||||
}
|
}
|
||||||
return path.Join(setting.AppDataPath, setting.Repository.Local.LocalCopyPath, com.ToStr(repo.ID))
|
return path.Join(setting.AppDataPath, setting.Repository.Local.LocalCopyPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LocalCopyPath returns the local repository copy path for the given repo.
|
||||||
|
func (repo *Repository) LocalCopyPath() string {
|
||||||
|
return path.Join(LocalCopyPath(), com.ToStr(repo.ID))
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateLocalCopyBranch pulls latest changes of given branch from repoPath to localPath.
|
// UpdateLocalCopyBranch pulls latest changes of given branch from repoPath to localPath.
|
||||||
|
|
@ -1006,10 +1008,10 @@ func MigrateRepository(doer, u *User, opts MigrateRepoOptions) (*Repository, err
|
||||||
|
|
||||||
if opts.IsMirror {
|
if opts.IsMirror {
|
||||||
if _, err = x.InsertOne(&Mirror{
|
if _, err = x.InsertOne(&Mirror{
|
||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
Interval: setting.Mirror.DefaultInterval,
|
Interval: setting.Mirror.DefaultInterval,
|
||||||
EnablePrune: true,
|
EnablePrune: true,
|
||||||
NextUpdate: time.Now().Add(setting.Mirror.DefaultInterval),
|
NextUpdateUnix: util.TimeStampNow().AddDuration(setting.Mirror.DefaultInterval),
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return repo, fmt.Errorf("InsertOne: %v", err)
|
return repo, fmt.Errorf("InsertOne: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,10 +100,6 @@ func populateRepoIndexer() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type updateBatch struct {
|
|
||||||
updates []indexer.RepoIndexerUpdate
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateRepoIndexer(repo *Repository) error {
|
func updateRepoIndexer(repo *Repository) error {
|
||||||
changes, err := getRepoChanges(repo)
|
changes, err := getRepoChanges(repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -163,6 +159,10 @@ func addUpdate(filename string, repo *Repository, batch *indexer.Batch) error {
|
||||||
return err
|
return err
|
||||||
} else if stat.Size() > setting.Indexer.MaxIndexerFileSize {
|
} else if stat.Size() > setting.Indexer.MaxIndexerFileSize {
|
||||||
return nil
|
return nil
|
||||||
|
} else if stat.IsDir() {
|
||||||
|
// file could actually be a directory, if it is the root of a submodule.
|
||||||
|
// We do not index submodule contents, so don't do anything.
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
fileContents, err := ioutil.ReadFile(filepath)
|
fileContents, err := ioutil.ReadFile(filepath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -31,10 +31,8 @@ type Mirror struct {
|
||||||
Interval time.Duration
|
Interval time.Duration
|
||||||
EnablePrune bool `xorm:"NOT NULL DEFAULT true"`
|
EnablePrune bool `xorm:"NOT NULL DEFAULT true"`
|
||||||
|
|
||||||
Updated time.Time `xorm:"-"`
|
UpdatedUnix util.TimeStamp `xorm:"INDEX"`
|
||||||
UpdatedUnix int64 `xorm:"INDEX"`
|
NextUpdateUnix util.TimeStamp `xorm:"INDEX"`
|
||||||
NextUpdate time.Time `xorm:"-"`
|
|
||||||
NextUpdateUnix int64 `xorm:"INDEX"`
|
|
||||||
|
|
||||||
address string `xorm:"-"`
|
address string `xorm:"-"`
|
||||||
}
|
}
|
||||||
|
|
@ -42,16 +40,8 @@ type Mirror struct {
|
||||||
// BeforeInsert will be invoked by XORM before inserting a record
|
// BeforeInsert will be invoked by XORM before inserting a record
|
||||||
func (m *Mirror) BeforeInsert() {
|
func (m *Mirror) BeforeInsert() {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
m.UpdatedUnix = time.Now().Unix()
|
m.UpdatedUnix = util.TimeStampNow()
|
||||||
m.NextUpdateUnix = m.NextUpdate.Unix()
|
m.NextUpdateUnix = util.TimeStampNow()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BeforeUpdate is invoked from XORM before updating this object.
|
|
||||||
func (m *Mirror) BeforeUpdate() {
|
|
||||||
if m != nil {
|
|
||||||
m.UpdatedUnix = m.Updated.Unix()
|
|
||||||
m.NextUpdateUnix = m.NextUpdate.Unix()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,14 +56,11 @@ func (m *Mirror) AfterLoad(session *xorm.Session) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(3, "getRepositoryByID[%d]: %v", m.ID, err)
|
log.Error(3, "getRepositoryByID[%d]: %v", m.ID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Updated = time.Unix(m.UpdatedUnix, 0).Local()
|
|
||||||
m.NextUpdate = time.Unix(m.NextUpdateUnix, 0).Local()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScheduleNextUpdate calculates and sets next update time.
|
// ScheduleNextUpdate calculates and sets next update time.
|
||||||
func (m *Mirror) ScheduleNextUpdate() {
|
func (m *Mirror) ScheduleNextUpdate() {
|
||||||
m.NextUpdate = time.Now().Add(m.Interval)
|
m.NextUpdateUnix = util.TimeStampNow().AddDuration(m.Interval)
|
||||||
}
|
}
|
||||||
|
|
||||||
func remoteAddress(repoPath string) (string, error) {
|
func remoteAddress(repoPath string) (string, error) {
|
||||||
|
|
@ -193,7 +180,7 @@ func (m *Mirror) runSync() bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Updated = time.Now()
|
m.UpdatedUnix = util.TimeStampNow()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@ package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"time"
|
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/Unknwon/com"
|
"github.com/Unknwon/com"
|
||||||
"github.com/go-xorm/core"
|
"github.com/go-xorm/core"
|
||||||
|
|
@ -19,8 +20,7 @@ type RepoUnit struct {
|
||||||
RepoID int64 `xorm:"INDEX(s)"`
|
RepoID int64 `xorm:"INDEX(s)"`
|
||||||
Type UnitType `xorm:"INDEX(s)"`
|
Type UnitType `xorm:"INDEX(s)"`
|
||||||
Config core.Conversion `xorm:"TEXT"`
|
Config core.Conversion `xorm:"TEXT"`
|
||||||
CreatedUnix int64 `xorm:"INDEX CREATED"`
|
CreatedUnix util.TimeStamp `xorm:"INDEX CREATED"`
|
||||||
Created time.Time `xorm:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnitConfig describes common unit config
|
// UnitConfig describes common unit config
|
||||||
|
|
@ -106,11 +106,6 @@ func (r *RepoUnit) BeforeSet(colName string, val xorm.Cell) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
|
||||||
func (r *RepoUnit) AfterLoad() {
|
|
||||||
r.Created = time.Unix(r.CreatedUnix, 0).Local()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unit returns Unit
|
// Unit returns Unit
|
||||||
func (r *RepoUnit) Unit() Unit {
|
func (r *RepoUnit) Unit() Unit {
|
||||||
return Units[r.Type]
|
return Units[r.Type]
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/process"
|
"code.gitea.io/gitea/modules/process"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -54,20 +55,16 @@ type PublicKey struct {
|
||||||
Mode AccessMode `xorm:"NOT NULL DEFAULT 2"`
|
Mode AccessMode `xorm:"NOT NULL DEFAULT 2"`
|
||||||
Type KeyType `xorm:"NOT NULL DEFAULT 1"`
|
Type KeyType `xorm:"NOT NULL DEFAULT 1"`
|
||||||
|
|
||||||
Created time.Time `xorm:"-"`
|
CreatedUnix util.TimeStamp `xorm:"created"`
|
||||||
CreatedUnix int64 `xorm:"created"`
|
UpdatedUnix util.TimeStamp `xorm:"updated"`
|
||||||
Updated time.Time `xorm:"-"`
|
HasRecentActivity bool `xorm:"-"`
|
||||||
UpdatedUnix int64 `xorm:"updated"`
|
HasUsed bool `xorm:"-"`
|
||||||
HasRecentActivity bool `xorm:"-"`
|
|
||||||
HasUsed bool `xorm:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
||||||
func (key *PublicKey) AfterLoad() {
|
func (key *PublicKey) AfterLoad() {
|
||||||
key.Created = time.Unix(key.CreatedUnix, 0).Local()
|
key.HasUsed = key.UpdatedUnix > key.CreatedUnix
|
||||||
key.Updated = time.Unix(key.UpdatedUnix, 0).Local()
|
key.HasRecentActivity = key.UpdatedUnix.AddDuration(7*24*time.Hour) > util.TimeStampNow()
|
||||||
key.HasUsed = key.Updated.After(key.Created)
|
|
||||||
key.HasRecentActivity = key.Updated.Add(7 * 24 * time.Hour).After(time.Now())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OmitEmail returns content of public key without email address.
|
// OmitEmail returns content of public key without email address.
|
||||||
|
|
@ -484,7 +481,7 @@ func UpdatePublicKeyUpdated(id int64) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := x.ID(id).Cols("updated_unix").Update(&PublicKey{
|
_, err := x.ID(id).Cols("updated_unix").Update(&PublicKey{
|
||||||
UpdatedUnix: time.Now().Unix(),
|
UpdatedUnix: util.TimeStampNow(),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -603,20 +600,16 @@ type DeployKey struct {
|
||||||
Fingerprint string
|
Fingerprint string
|
||||||
Content string `xorm:"-"`
|
Content string `xorm:"-"`
|
||||||
|
|
||||||
Created time.Time `xorm:"-"`
|
CreatedUnix util.TimeStamp `xorm:"created"`
|
||||||
CreatedUnix int64 `xorm:"created"`
|
UpdatedUnix util.TimeStamp `xorm:"updated"`
|
||||||
Updated time.Time `xorm:"-"`
|
HasRecentActivity bool `xorm:"-"`
|
||||||
UpdatedUnix int64 `xorm:"updated"`
|
HasUsed bool `xorm:"-"`
|
||||||
HasRecentActivity bool `xorm:"-"`
|
|
||||||
HasUsed bool `xorm:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
||||||
func (key *DeployKey) AfterLoad() {
|
func (key *DeployKey) AfterLoad() {
|
||||||
key.Created = time.Unix(key.CreatedUnix, 0).Local()
|
key.HasUsed = key.UpdatedUnix > key.CreatedUnix
|
||||||
key.Updated = time.Unix(key.UpdatedUnix, 0).Local()
|
key.HasRecentActivity = key.UpdatedUnix.AddDuration(7*24*time.Hour) > util.TimeStampNow()
|
||||||
key.HasUsed = key.Updated.After(key.Created)
|
|
||||||
key.HasRecentActivity = key.Updated.Add(7 * 24 * time.Hour).After(time.Now())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetContent gets associated public key content.
|
// GetContent gets associated public key content.
|
||||||
|
|
@ -743,6 +736,12 @@ func GetDeployKeyByRepo(keyID, repoID int64) (*DeployKey, error) {
|
||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateDeployKeyCols updates deploy key information in the specified columns.
|
||||||
|
func UpdateDeployKeyCols(key *DeployKey, cols ...string) error {
|
||||||
|
_, err := x.ID(key.ID).Cols(cols...).Update(key)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateDeployKey updates deploy key information.
|
// UpdateDeployKey updates deploy key information.
|
||||||
func UpdateDeployKey(key *DeployKey) error {
|
func UpdateDeployKey(key *DeployKey) error {
|
||||||
_, err := x.ID(key.ID).AllCols().Update(key)
|
_, err := x.ID(key.ID).AllCols().Update(key)
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,11 @@ import (
|
||||||
"container/list"
|
"container/list"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"code.gitea.io/git"
|
"code.gitea.io/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
api "code.gitea.io/sdk/gitea"
|
api "code.gitea.io/sdk/gitea"
|
||||||
|
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
|
|
@ -65,17 +65,8 @@ type CommitStatus struct {
|
||||||
Creator *User `xorm:"-"`
|
Creator *User `xorm:"-"`
|
||||||
CreatorID int64
|
CreatorID int64
|
||||||
|
|
||||||
Created time.Time `xorm:"-"`
|
CreatedUnix util.TimeStamp `xorm:"INDEX created"`
|
||||||
CreatedUnix int64 `xorm:"INDEX created"`
|
UpdatedUnix util.TimeStamp `xorm:"INDEX updated"`
|
||||||
Updated time.Time `xorm:"-"`
|
|
||||||
UpdatedUnix int64 `xorm:"INDEX updated"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the value of a field of
|
|
||||||
// this object.
|
|
||||||
func (status *CommitStatus) AfterLoad() {
|
|
||||||
status.Created = time.Unix(status.CreatedUnix, 0).Local()
|
|
||||||
status.Updated = time.Unix(status.UpdatedUnix, 0).Local()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (status *CommitStatus) loadRepo(e Engine) (err error) {
|
func (status *CommitStatus) loadRepo(e Engine) (err error) {
|
||||||
|
|
@ -106,8 +97,8 @@ func (status *CommitStatus) APIURL() string {
|
||||||
func (status *CommitStatus) APIFormat() *api.Status {
|
func (status *CommitStatus) APIFormat() *api.Status {
|
||||||
status.loadRepo(x)
|
status.loadRepo(x)
|
||||||
apiStatus := &api.Status{
|
apiStatus := &api.Status{
|
||||||
Created: status.Created,
|
Created: status.CreatedUnix.AsTime(),
|
||||||
Updated: status.Created,
|
Updated: status.CreatedUnix.AsTime(),
|
||||||
State: api.StatusState(status.State),
|
State: api.StatusState(status.State),
|
||||||
TargetURL: status.TargetURL,
|
TargetURL: status.TargetURL,
|
||||||
Description: status.Description,
|
Description: status.Description,
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
gouuid "github.com/satori/go.uuid"
|
gouuid "github.com/satori/go.uuid"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AccessToken represents a personal access token.
|
// AccessToken represents a personal access token.
|
||||||
|
|
@ -19,20 +20,16 @@ type AccessToken struct {
|
||||||
Name string
|
Name string
|
||||||
Sha1 string `xorm:"UNIQUE VARCHAR(40)"`
|
Sha1 string `xorm:"UNIQUE VARCHAR(40)"`
|
||||||
|
|
||||||
Created time.Time `xorm:"-"`
|
CreatedUnix util.TimeStamp `xorm:"INDEX created"`
|
||||||
CreatedUnix int64 `xorm:"INDEX created"`
|
UpdatedUnix util.TimeStamp `xorm:"INDEX updated"`
|
||||||
Updated time.Time `xorm:"-"`
|
HasRecentActivity bool `xorm:"-"`
|
||||||
UpdatedUnix int64 `xorm:"INDEX updated"`
|
HasUsed bool `xorm:"-"`
|
||||||
HasRecentActivity bool `xorm:"-"`
|
|
||||||
HasUsed bool `xorm:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
||||||
func (t *AccessToken) AfterLoad() {
|
func (t *AccessToken) AfterLoad() {
|
||||||
t.Created = time.Unix(t.CreatedUnix, 0).Local()
|
t.HasUsed = t.UpdatedUnix > t.CreatedUnix
|
||||||
t.Updated = time.Unix(t.UpdatedUnix, 0).Local()
|
t.HasRecentActivity = t.UpdatedUnix.AddDuration(7*24*time.Hour) > util.TimeStampNow()
|
||||||
t.HasUsed = t.Updated.After(t.Created)
|
|
||||||
t.HasRecentActivity = t.Updated.Add(7 * 24 * time.Hour).After(time.Now())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAccessToken creates new access token.
|
// NewAccessToken creates new access token.
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@ import (
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Unknwon/com"
|
"github.com/Unknwon/com"
|
||||||
"github.com/pquerna/otp/totp"
|
"github.com/pquerna/otp/totp"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TwoFactor represents a two-factor authentication token.
|
// TwoFactor represents a two-factor authentication token.
|
||||||
|
|
@ -23,17 +23,8 @@ type TwoFactor struct {
|
||||||
UID int64 `xorm:"UNIQUE"`
|
UID int64 `xorm:"UNIQUE"`
|
||||||
Secret string
|
Secret string
|
||||||
ScratchToken string
|
ScratchToken string
|
||||||
|
CreatedUnix util.TimeStamp `xorm:"INDEX created"`
|
||||||
Created time.Time `xorm:"-"`
|
UpdatedUnix util.TimeStamp `xorm:"INDEX updated"`
|
||||||
CreatedUnix int64 `xorm:"INDEX created"`
|
|
||||||
Updated time.Time `xorm:"-"`
|
|
||||||
UpdatedUnix int64 `xorm:"INDEX updated"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
|
||||||
func (t *TwoFactor) AfterLoad() {
|
|
||||||
t.Created = time.Unix(t.CreatedUnix, 0).Local()
|
|
||||||
t.Updated = time.Unix(t.UpdatedUnix, 0).Local()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateScratchToken recreates the scratch token the user is using.
|
// GenerateScratchToken recreates the scratch token the user is using.
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,9 @@ import (
|
||||||
"github.com/Unknwon/com"
|
"github.com/Unknwon/com"
|
||||||
"github.com/go-xorm/core"
|
"github.com/go-xorm/core"
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
_ "github.com/mattn/go-sqlite3" // for the test engine
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/testfixtures.v2"
|
"gopkg.in/testfixtures.v2"
|
||||||
|
"net/url"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NonexistentID an ID that will never exist
|
// NonexistentID an ID that will never exist
|
||||||
|
|
@ -29,9 +29,10 @@ var giteaRoot string
|
||||||
// MainTest a reusable TestMain(..) function for unit tests that need to use a
|
// MainTest a reusable TestMain(..) function for unit tests that need to use a
|
||||||
// test database. Creates the test database, and sets necessary settings.
|
// test database. Creates the test database, and sets necessary settings.
|
||||||
func MainTest(m *testing.M, pathToGiteaRoot string) {
|
func MainTest(m *testing.M, pathToGiteaRoot string) {
|
||||||
|
var err error
|
||||||
giteaRoot = pathToGiteaRoot
|
giteaRoot = pathToGiteaRoot
|
||||||
fixturesDir := filepath.Join(pathToGiteaRoot, "models", "fixtures")
|
fixturesDir := filepath.Join(pathToGiteaRoot, "models", "fixtures")
|
||||||
if err := createTestEngine(fixturesDir); err != nil {
|
if err = createTestEngine(fixturesDir); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error creating test engine: %v\n", err)
|
fmt.Fprintf(os.Stderr, "Error creating test engine: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
@ -42,6 +43,13 @@ func MainTest(m *testing.M, pathToGiteaRoot string) {
|
||||||
setting.SSH.Domain = "try.gitea.io"
|
setting.SSH.Domain = "try.gitea.io"
|
||||||
setting.RepoRootPath = filepath.Join(os.TempDir(), "repos")
|
setting.RepoRootPath = filepath.Join(os.TempDir(), "repos")
|
||||||
setting.AppDataPath = filepath.Join(os.TempDir(), "appdata")
|
setting.AppDataPath = filepath.Join(os.TempDir(), "appdata")
|
||||||
|
setting.AppWorkPath = pathToGiteaRoot
|
||||||
|
setting.StaticRootPath = pathToGiteaRoot
|
||||||
|
setting.GravatarSourceURL, err = url.Parse("https://secure.gravatar.com/avatar/")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error url.Parse: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
os.Exit(m.Run())
|
os.Exit(m.Run())
|
||||||
}
|
}
|
||||||
|
|
@ -141,6 +149,14 @@ func AssertNotExistsBean(t *testing.T, bean interface{}, conditions ...interface
|
||||||
assert.False(t, exists)
|
assert.False(t, exists)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AssertExistsIf asserts that a bean exists or does not exist, depending on
|
||||||
|
// what is expected.
|
||||||
|
func AssertExistsIf(t *testing.T, expected bool, bean interface{}, conditions ...interface{}) {
|
||||||
|
exists, err := loadBeanIfExists(bean, conditions...)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, expected, exists)
|
||||||
|
}
|
||||||
|
|
||||||
// AssertSuccessfulInsert assert that beans is successfully inserted
|
// AssertSuccessfulInsert assert that beans is successfully inserted
|
||||||
func AssertSuccessfulInsert(t *testing.T, beans ...interface{}) {
|
func AssertSuccessfulInsert(t *testing.T, beans ...interface{}) {
|
||||||
_, err := x.Insert(beans...)
|
_, err := x.Insert(beans...)
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"code.gitea.io/git"
|
"code.gitea.io/git"
|
||||||
"code.gitea.io/gitea/modules/cache"
|
"code.gitea.io/gitea/modules/cache"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// env keys for git hooks need
|
// env keys for git hooks need
|
||||||
|
|
@ -158,8 +159,7 @@ func pushUpdateAddTag(repo *Repository, gitRepo *git.Repository, tagName string)
|
||||||
IsDraft: false,
|
IsDraft: false,
|
||||||
IsPrerelease: false,
|
IsPrerelease: false,
|
||||||
IsTag: true,
|
IsTag: true,
|
||||||
Created: createdAt,
|
CreatedUnix: util.TimeStamp(createdAt.Unix()),
|
||||||
CreatedUnix: createdAt.Unix(),
|
|
||||||
}
|
}
|
||||||
if author != nil {
|
if author != nil {
|
||||||
rel.PublisherID = author.ID
|
rel.PublisherID = author.ID
|
||||||
|
|
@ -170,8 +170,7 @@ func pushUpdateAddTag(repo *Repository, gitRepo *git.Repository, tagName string)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rel.Sha1 = commit.ID.String()
|
rel.Sha1 = commit.ID.String()
|
||||||
rel.Created = createdAt
|
rel.CreatedUnix = util.TimeStamp(createdAt.Unix())
|
||||||
rel.CreatedUnix = createdAt.Unix()
|
|
||||||
rel.NumCommits = commitsCount
|
rel.NumCommits = commitsCount
|
||||||
rel.IsDraft = false
|
rel.IsDraft = false
|
||||||
if rel.IsTag && author != nil {
|
if rel.IsTag && author != nil {
|
||||||
|
|
|
||||||
|
|
@ -94,12 +94,9 @@ type User struct {
|
||||||
Rands string `xorm:"VARCHAR(10)"`
|
Rands string `xorm:"VARCHAR(10)"`
|
||||||
Salt string `xorm:"VARCHAR(10)"`
|
Salt string `xorm:"VARCHAR(10)"`
|
||||||
|
|
||||||
Created time.Time `xorm:"-"`
|
CreatedUnix util.TimeStamp `xorm:"INDEX created"`
|
||||||
CreatedUnix int64 `xorm:"INDEX created"`
|
UpdatedUnix util.TimeStamp `xorm:"INDEX updated"`
|
||||||
Updated time.Time `xorm:"-"`
|
LastLoginUnix util.TimeStamp `xorm:"INDEX"`
|
||||||
UpdatedUnix int64 `xorm:"INDEX updated"`
|
|
||||||
LastLogin time.Time `xorm:"-"`
|
|
||||||
LastLoginUnix int64 `xorm:"INDEX"`
|
|
||||||
|
|
||||||
// Remember visibility choice for convenience, true for private
|
// Remember visibility choice for convenience, true for private
|
||||||
LastRepoVisibility bool
|
LastRepoVisibility bool
|
||||||
|
|
@ -145,7 +142,7 @@ func (u *User) BeforeUpdate() {
|
||||||
|
|
||||||
// SetLastLogin set time to last login
|
// SetLastLogin set time to last login
|
||||||
func (u *User) SetLastLogin() {
|
func (u *User) SetLastLogin() {
|
||||||
u.LastLoginUnix = time.Now().Unix()
|
u.LastLoginUnix = util.TimeStampNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateDiffViewStyle updates the users diff view style
|
// UpdateDiffViewStyle updates the users diff view style
|
||||||
|
|
@ -154,13 +151,6 @@ func (u *User) UpdateDiffViewStyle(style string) error {
|
||||||
return UpdateUserCols(u, "diff_view_style")
|
return UpdateUserCols(u, "diff_view_style")
|
||||||
}
|
}
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
|
||||||
func (u *User) AfterLoad() {
|
|
||||||
u.Created = time.Unix(u.CreatedUnix, 0).Local()
|
|
||||||
u.Updated = time.Unix(u.UpdatedUnix, 0).Local()
|
|
||||||
u.LastLogin = time.Unix(u.LastLoginUnix, 0).Local()
|
|
||||||
}
|
|
||||||
|
|
||||||
// getEmail returns an noreply email, if the user has set to keep his
|
// getEmail returns an noreply email, if the user has set to keep his
|
||||||
// email address private, otherwise the primary email address.
|
// email address private, otherwise the primary email address.
|
||||||
func (u *User) getEmail() string {
|
func (u *User) getEmail() string {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/sync"
|
"code.gitea.io/gitea/modules/sync"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
api "code.gitea.io/sdk/gitea"
|
api "code.gitea.io/sdk/gitea"
|
||||||
|
|
||||||
gouuid "github.com/satori/go.uuid"
|
gouuid "github.com/satori/go.uuid"
|
||||||
|
|
@ -105,10 +106,8 @@ type Webhook struct {
|
||||||
Meta string `xorm:"TEXT"` // store hook-specific attributes
|
Meta string `xorm:"TEXT"` // store hook-specific attributes
|
||||||
LastStatus HookStatus // Last delivery status
|
LastStatus HookStatus // Last delivery status
|
||||||
|
|
||||||
Created time.Time `xorm:"-"`
|
CreatedUnix util.TimeStamp `xorm:"INDEX created"`
|
||||||
CreatedUnix int64 `xorm:"INDEX created"`
|
UpdatedUnix util.TimeStamp `xorm:"INDEX updated"`
|
||||||
Updated time.Time `xorm:"-"`
|
|
||||||
UpdatedUnix int64 `xorm:"INDEX updated"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AfterLoad updates the webhook object upon setting a column
|
// AfterLoad updates the webhook object upon setting a column
|
||||||
|
|
@ -117,9 +116,6 @@ func (w *Webhook) AfterLoad() {
|
||||||
if err := json.Unmarshal([]byte(w.Events), w.HookEvent); err != nil {
|
if err := json.Unmarshal([]byte(w.Events), w.HookEvent); err != nil {
|
||||||
log.Error(3, "Unmarshal[%d]: %v", w.ID, err)
|
log.Error(3, "Unmarshal[%d]: %v", w.ID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Created = time.Unix(w.CreatedUnix, 0).Local()
|
|
||||||
w.Updated = time.Unix(w.UpdatedUnix, 0).Local()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSlackHook returns slack metadata
|
// GetSlackHook returns slack metadata
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ package auth
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Unknwon/com"
|
"github.com/Unknwon/com"
|
||||||
"github.com/go-macaron/binding"
|
"github.com/go-macaron/binding"
|
||||||
|
|
@ -19,6 +18,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/modules/validation"
|
"code.gitea.io/gitea/modules/validation"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -59,7 +59,7 @@ func SignedInID(ctx *macaron.Context, sess session.Store) int64 {
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
t.Updated = time.Now()
|
t.UpdatedUnix = util.TimeStampNow()
|
||||||
if err = models.UpdateAccessToken(t); err != nil {
|
if err = models.UpdateAccessToken(t); err != nil {
|
||||||
log.Error(4, "UpdateAccessToken: %v", err)
|
log.Error(4, "UpdateAccessToken: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
"github.com/Unknwon/com"
|
"github.com/Unknwon/com"
|
||||||
"github.com/Unknwon/i18n"
|
"github.com/Unknwon/i18n"
|
||||||
"github.com/gogits/chardet"
|
"github.com/gogits/chardet"
|
||||||
|
|
@ -357,11 +358,15 @@ func timeSincePro(then, now time.Time, lang string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func timeSince(then, now time.Time, lang string) string {
|
func timeSince(then, now time.Time, lang string) string {
|
||||||
|
return timeSinceUnix(then.Unix(), now.Unix(), lang)
|
||||||
|
}
|
||||||
|
|
||||||
|
func timeSinceUnix(then, now int64, lang string) string {
|
||||||
lbl := "tool.ago"
|
lbl := "tool.ago"
|
||||||
diff := now.Unix() - then.Unix()
|
diff := now - then
|
||||||
if then.After(now) {
|
if then > now {
|
||||||
lbl = "tool.from_now"
|
lbl = "tool.from_now"
|
||||||
diff = then.Unix() - now.Unix()
|
diff = then - now
|
||||||
}
|
}
|
||||||
if diff <= 0 {
|
if diff <= 0 {
|
||||||
return i18n.Tr(lang, "tool.now")
|
return i18n.Tr(lang, "tool.now")
|
||||||
|
|
@ -387,6 +392,17 @@ func htmlTimeSince(then, now time.Time, lang string) template.HTML {
|
||||||
timeSince(then, now, lang)))
|
timeSince(then, now, lang)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TimeSinceUnix calculates the time interval and generate user-friendly string.
|
||||||
|
func TimeSinceUnix(then util.TimeStamp, lang string) template.HTML {
|
||||||
|
return htmlTimeSinceUnix(then, util.TimeStamp(time.Now().Unix()), lang)
|
||||||
|
}
|
||||||
|
|
||||||
|
func htmlTimeSinceUnix(then, now util.TimeStamp, lang string) template.HTML {
|
||||||
|
return template.HTML(fmt.Sprintf(`<span class="time-since" title="%s">%s</span>`,
|
||||||
|
then.Format(setting.TimeFormat),
|
||||||
|
timeSinceUnix(int64(then), int64(now), lang)))
|
||||||
|
}
|
||||||
|
|
||||||
// Storage space size types
|
// Storage space size types
|
||||||
const (
|
const (
|
||||||
Byte = 1
|
Byte = 1
|
||||||
|
|
|
||||||
|
|
@ -435,7 +435,6 @@ func RepoAssignment() macaron.Handler {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.Data["IsForkedRepo"] = repo.IsFork
|
|
||||||
|
|
||||||
// People who have push access or have forked repository can propose a new pull request.
|
// People who have push access or have forked repository can propose a new pull request.
|
||||||
if ctx.Repo.IsWriter() || (ctx.IsSigned && ctx.User.HasForkedRepo(ctx.Repo.Repository.ID)) {
|
if ctx.Repo.IsWriter() || (ctx.IsSigned && ctx.User.HasForkedRepo(ctx.Repo.Repository.ID)) {
|
||||||
|
|
@ -626,7 +625,11 @@ func RepoRefByType(refType RepoRefType) macaron.Handler {
|
||||||
|
|
||||||
if refType == RepoRefLegacy {
|
if refType == RepoRefLegacy {
|
||||||
// redirect from old URL scheme to new URL scheme
|
// redirect from old URL scheme to new URL scheme
|
||||||
ctx.Redirect(path.Join(setting.AppSubURL, strings.TrimSuffix(ctx.Req.URL.String(), ctx.Params("*")), ctx.Repo.BranchNameSubURL()))
|
ctx.Redirect(path.Join(
|
||||||
|
setting.AppSubURL,
|
||||||
|
strings.TrimSuffix(ctx.Req.URL.String(), ctx.Params("*")),
|
||||||
|
ctx.Repo.BranchNameSubURL(),
|
||||||
|
ctx.Repo.TreePath))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,12 +68,12 @@ type ObjectError struct {
|
||||||
|
|
||||||
// ObjectLink builds a URL linking to the object.
|
// ObjectLink builds a URL linking to the object.
|
||||||
func (v *RequestVars) ObjectLink() string {
|
func (v *RequestVars) ObjectLink() string {
|
||||||
return setting.AppURL + path.Join(v.User, v.Repo, "info/lfs/objects", v.Oid)
|
return setting.AppURL + path.Join(v.User, v.Repo+".git", "info/lfs/objects", v.Oid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifyLink builds a URL for verifying the object.
|
// VerifyLink builds a URL for verifying the object.
|
||||||
func (v *RequestVars) VerifyLink() string {
|
func (v *RequestVars) VerifyLink() string {
|
||||||
return setting.AppURL + path.Join(v.User, v.Repo, "info/lfs/verify")
|
return setting.AppURL + path.Join(v.User, v.Repo+".git", "info/lfs/verify")
|
||||||
}
|
}
|
||||||
|
|
||||||
// link provides a structure used to build a hypermedia representation of an HTTP link.
|
// link provides a structure used to build a hypermedia representation of an HTTP link.
|
||||||
|
|
|
||||||
|
|
@ -531,6 +531,9 @@ var (
|
||||||
IterateBufferSize int
|
IterateBufferSize int
|
||||||
|
|
||||||
ExternalMarkupParsers []MarkupParser
|
ExternalMarkupParsers []MarkupParser
|
||||||
|
// UILocation is the location on the UI, so that we can display the time on UI.
|
||||||
|
// Currently only show the default time.Local, it could be added to app.ini after UI is ready
|
||||||
|
UILocation = time.Local
|
||||||
)
|
)
|
||||||
|
|
||||||
// DateLang transforms standard language locale name to corresponding value in datetime plugin.
|
// DateLang transforms standard language locale name to corresponding value in datetime plugin.
|
||||||
|
|
|
||||||
|
|
@ -65,14 +65,15 @@ func NewFuncMap() []template.FuncMap {
|
||||||
"LoadTimes": func(startTime time.Time) string {
|
"LoadTimes": func(startTime time.Time) string {
|
||||||
return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms"
|
return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms"
|
||||||
},
|
},
|
||||||
"AvatarLink": base.AvatarLink,
|
"AvatarLink": base.AvatarLink,
|
||||||
"Safe": Safe,
|
"Safe": Safe,
|
||||||
"SafeJS": SafeJS,
|
"SafeJS": SafeJS,
|
||||||
"Str2html": Str2html,
|
"Str2html": Str2html,
|
||||||
"TimeSince": base.TimeSince,
|
"TimeSince": base.TimeSince,
|
||||||
"RawTimeSince": base.RawTimeSince,
|
"TimeSinceUnix": base.TimeSinceUnix,
|
||||||
"FileSize": base.FileSize,
|
"RawTimeSince": base.RawTimeSince,
|
||||||
"Subtract": base.Subtract,
|
"FileSize": base.FileSize,
|
||||||
|
"Subtract": base.Subtract,
|
||||||
"Add": func(a, b int) int {
|
"Add": func(a, b int) int {
|
||||||
return a + b
|
return a + b
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,14 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/git"
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
|
|
||||||
"github.com/go-macaron/session"
|
"github.com/go-macaron/session"
|
||||||
_ "github.com/mattn/go-sqlite3" // for the test engine
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/macaron.v1"
|
"gopkg.in/macaron.v1"
|
||||||
|
"net/http/httptest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MockContext mock context for unit tests
|
// MockContext mock context for unit tests
|
||||||
|
|
@ -44,6 +45,7 @@ func MockContext(t *testing.T, path string) *context.Context {
|
||||||
func LoadRepo(t *testing.T, ctx *context.Context, repoID int64) {
|
func LoadRepo(t *testing.T, ctx *context.Context, repoID int64) {
|
||||||
ctx.Repo = &context.Repository{}
|
ctx.Repo = &context.Repository{}
|
||||||
ctx.Repo.Repository = models.AssertExistsAndLoadBean(t, &models.Repository{ID: repoID}).(*models.Repository)
|
ctx.Repo.Repository = models.AssertExistsAndLoadBean(t, &models.Repository{ID: repoID}).(*models.Repository)
|
||||||
|
ctx.Repo.RepoLink = ctx.Repo.Repository.Link()
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadUser load a user into a test context.
|
// LoadUser load a user into a test context.
|
||||||
|
|
@ -51,6 +53,15 @@ func LoadUser(t *testing.T, ctx *context.Context, userID int64) {
|
||||||
ctx.User = models.AssertExistsAndLoadBean(t, &models.User{ID: userID}).(*models.User)
|
ctx.User = models.AssertExistsAndLoadBean(t, &models.User{ID: userID}).(*models.User)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadGitRepo load a git repo into a test context. Requires that ctx.Repo has
|
||||||
|
// already been populated.
|
||||||
|
func LoadGitRepo(t *testing.T, ctx *context.Context) {
|
||||||
|
assert.NoError(t, ctx.Repo.Repository.GetOwner())
|
||||||
|
var err error
|
||||||
|
ctx.Repo.GitRepo, err = git.OpenRepository(ctx.Repo.Repository.RepoPath())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
type mockLocale struct{}
|
type mockLocale struct{}
|
||||||
|
|
||||||
func (l mockLocale) Language() string {
|
func (l mockLocale) Language() string {
|
||||||
|
|
@ -62,32 +73,21 @@ func (l mockLocale) Tr(s string, _ ...interface{}) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
type mockResponseWriter struct {
|
type mockResponseWriter struct {
|
||||||
status int
|
httptest.ResponseRecorder
|
||||||
size int
|
size int
|
||||||
}
|
|
||||||
|
|
||||||
func (rw *mockResponseWriter) Header() http.Header {
|
|
||||||
return map[string][]string{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rw *mockResponseWriter) Write(b []byte) (int, error) {
|
func (rw *mockResponseWriter) Write(b []byte) (int, error) {
|
||||||
rw.size += len(b)
|
rw.size += len(b)
|
||||||
return len(b), nil
|
return rw.ResponseRecorder.Write(b)
|
||||||
}
|
|
||||||
|
|
||||||
func (rw *mockResponseWriter) WriteHeader(status int) {
|
|
||||||
rw.status = status
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rw *mockResponseWriter) Flush() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rw *mockResponseWriter) Status() int {
|
func (rw *mockResponseWriter) Status() int {
|
||||||
return rw.status
|
return rw.ResponseRecorder.Code
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rw *mockResponseWriter) Written() bool {
|
func (rw *mockResponseWriter) Written() bool {
|
||||||
return rw.status > 0
|
return rw.ResponseRecorder.Code > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rw *mockResponseWriter) Size() int {
|
func (rw *mockResponseWriter) Size() int {
|
||||||
|
|
|
||||||
14
modules/test/utils.go
Normal file
14
modules/test/utils.go
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright 2017 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 test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RedirectURL returns the redirect URL of a http response.
|
||||||
|
func RedirectURL(resp http.ResponseWriter) string {
|
||||||
|
return resp.Header().Get("Location")
|
||||||
|
}
|
||||||
61
modules/util/time_stamp.go
Normal file
61
modules/util/time_stamp.go
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
// Copyright 2017 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 util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TimeStamp defines a timestamp
|
||||||
|
type TimeStamp int64
|
||||||
|
|
||||||
|
// TimeStampNow returns now int64
|
||||||
|
func TimeStampNow() TimeStamp {
|
||||||
|
return TimeStamp(time.Now().Unix())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add adds seconds and return sum
|
||||||
|
func (ts TimeStamp) Add(seconds int64) TimeStamp {
|
||||||
|
return ts + TimeStamp(seconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddDuration adds time.Duration and return sum
|
||||||
|
func (ts TimeStamp) AddDuration(interval time.Duration) TimeStamp {
|
||||||
|
return ts + TimeStamp(interval/time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Year returns the time's year
|
||||||
|
func (ts TimeStamp) Year() int {
|
||||||
|
return ts.AsTime().Year()
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsTime convert timestamp as time.Time in Local locale
|
||||||
|
func (ts TimeStamp) AsTime() (tm time.Time) {
|
||||||
|
tm = time.Unix(int64(ts), 0).In(setting.UILocation)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsTimePtr convert timestamp as *time.Time in Local locale
|
||||||
|
func (ts TimeStamp) AsTimePtr() *time.Time {
|
||||||
|
tm := time.Unix(int64(ts), 0).In(setting.UILocation)
|
||||||
|
return &tm
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format formats timestamp as
|
||||||
|
func (ts TimeStamp) Format(f string) string {
|
||||||
|
return ts.AsTime().Format(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatLong formats as RFC1123Z
|
||||||
|
func (ts TimeStamp) FormatLong() string {
|
||||||
|
return ts.Format(time.RFC1123Z)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatShort formats as short
|
||||||
|
func (ts TimeStamp) FormatShort() string {
|
||||||
|
return ts.Format("Jan 02, 2006")
|
||||||
|
}
|
||||||
|
|
@ -1569,6 +1569,7 @@ no_read = You do not have any read notifications.
|
||||||
pin = Pin notification
|
pin = Pin notification
|
||||||
mark_as_read = Mark as read
|
mark_as_read = Mark as read
|
||||||
mark_as_unread = Mark as unread
|
mark_as_unread = Mark as unread
|
||||||
|
mark_all_as_read = Mark all as read
|
||||||
|
|
||||||
[gpg]
|
[gpg]
|
||||||
error.extract_sign = Failed to extract signature
|
error.extract_sign = Failed to extract signature
|
||||||
|
|
|
||||||
|
|
@ -489,6 +489,8 @@ mirror_last_synced=Dernière synchronisation
|
||||||
watchers=Observateurs
|
watchers=Observateurs
|
||||||
stargazers=Fans
|
stargazers=Fans
|
||||||
forks=Bifurcations
|
forks=Bifurcations
|
||||||
|
pick_reaction=Choisissez votre réaction
|
||||||
|
reactions_more=et %d de plus
|
||||||
|
|
||||||
form.reach_limit_of_creation=Vous avez déjà atteint la limite des %d dépôts.
|
form.reach_limit_of_creation=Vous avez déjà atteint la limite des %d dépôts.
|
||||||
form.name_reserved=Le dépôt "%s" a un nom réservé.
|
form.name_reserved=Le dépôt "%s" a un nom réservé.
|
||||||
|
|
@ -539,6 +541,7 @@ pulls=Demandes d'ajout
|
||||||
labels=Étiquettes
|
labels=Étiquettes
|
||||||
milestones=Jalons
|
milestones=Jalons
|
||||||
commits=Révisions
|
commits=Révisions
|
||||||
|
commit=Commit
|
||||||
releases=Versions
|
releases=Versions
|
||||||
file_raw=Brut
|
file_raw=Brut
|
||||||
file_history=Historique
|
file_history=Historique
|
||||||
|
|
@ -804,6 +807,7 @@ wiki.new_page_button=Nouvelle Page
|
||||||
wiki.delete_page_button=Supprimer la page
|
wiki.delete_page_button=Supprimer la page
|
||||||
wiki.delete_page_notice_1=Cela supprimera la page <code>"%s"</code>. Êtes-vous sûr ?
|
wiki.delete_page_notice_1=Cela supprimera la page <code>"%s"</code>. Êtes-vous sûr ?
|
||||||
wiki.page_already_exists=Une page de wiki avec le même nom existe déjà.
|
wiki.page_already_exists=Une page de wiki avec le même nom existe déjà.
|
||||||
|
wiki.reserved_page=Le nom de page Wiki %s est réservé, veuillez choisir un autre nom.
|
||||||
wiki.pages=Pages
|
wiki.pages=Pages
|
||||||
wiki.last_updated=Dernière mise à jour: %s
|
wiki.last_updated=Dernière mise à jour: %s
|
||||||
|
|
||||||
|
|
@ -978,6 +982,7 @@ settings.slack_token=Jeton
|
||||||
settings.slack_domain=Domaine
|
settings.slack_domain=Domaine
|
||||||
settings.slack_channel=Canal
|
settings.slack_channel=Canal
|
||||||
settings.add_discord_hook_desc=Ajouter l'intégration de <a href="%s">Discord</a> à votre dépôt.
|
settings.add_discord_hook_desc=Ajouter l'intégration de <a href="%s">Discord</a> à votre dépôt.
|
||||||
|
settings.add_dingtalk_hook_desc=Intégrer <a href="%s">Dingtalk</a> à votre dépôt.
|
||||||
settings.deploy_keys=Clés de déploiement
|
settings.deploy_keys=Clés de déploiement
|
||||||
settings.add_deploy_key=Ajouter une clé de déploiement
|
settings.add_deploy_key=Ajouter une clé de déploiement
|
||||||
settings.deploy_key_desc=Les clés de déploiement ont un accès en lecture seule. Elles sont différentes des clés SSH personnelles.
|
settings.deploy_key_desc=Les clés de déploiement ont un accès en lecture seule. Elles sont différentes des clés SSH personnelles.
|
||||||
|
|
@ -1542,6 +1547,7 @@ no_read=Vous n'avez aucune notification lue.
|
||||||
pin=Epingler la notification
|
pin=Epingler la notification
|
||||||
mark_as_read=Marquer comme lu
|
mark_as_read=Marquer comme lu
|
||||||
mark_as_unread=Marquer comme non lue
|
mark_as_unread=Marquer comme non lue
|
||||||
|
mark_all_as_read=Tout marquer comme lu
|
||||||
|
|
||||||
[gpg]
|
[gpg]
|
||||||
error.extract_sign=Impossible d'extraire la signature
|
error.extract_sign=Impossible d'extraire la signature
|
||||||
|
|
|
||||||
|
|
@ -1547,6 +1547,7 @@ no_read=Nincsen olvasott értesítés.
|
||||||
pin=Értesítés kitűzése
|
pin=Értesítés kitűzése
|
||||||
mark_as_read=Megjelölés olvasottként
|
mark_as_read=Megjelölés olvasottként
|
||||||
mark_as_unread=Megjelölés olvasatlanként
|
mark_as_unread=Megjelölés olvasatlanként
|
||||||
|
mark_all_as_read=Összes üzenet megjelölése olvasottként
|
||||||
|
|
||||||
[gpg]
|
[gpg]
|
||||||
error.extract_sign=Nem sikerült kinyerni az aláírást
|
error.extract_sign=Nem sikerült kinyerni az aláírást
|
||||||
|
|
|
||||||
|
|
@ -489,6 +489,8 @@ mirror_last_synced=Pēdējo reizi sinhronizēts
|
||||||
watchers=Novērotāji
|
watchers=Novērotāji
|
||||||
stargazers=Zvaigžņdevēji
|
stargazers=Zvaigžņdevēji
|
||||||
forks=Atdalītie repozitoriji
|
forks=Atdalītie repozitoriji
|
||||||
|
pick_reaction=Izvēlieties reakciju
|
||||||
|
reactions_more=un vēl %d
|
||||||
|
|
||||||
form.reach_limit_of_creation=Ir sasniegts Jums noteiktais %d repozitoriju ierobežojums.
|
form.reach_limit_of_creation=Ir sasniegts Jums noteiktais %d repozitoriju ierobežojums.
|
||||||
form.name_reserved=Repozitorija nosaukums '%s' ir jau rezervēts.
|
form.name_reserved=Repozitorija nosaukums '%s' ir jau rezervēts.
|
||||||
|
|
@ -539,6 +541,7 @@ pulls=Izmaiņu pieprasījumi
|
||||||
labels=Etiķetes
|
labels=Etiķetes
|
||||||
milestones=Atskaites punkti
|
milestones=Atskaites punkti
|
||||||
commits=Revīzijas
|
commits=Revīzijas
|
||||||
|
commit=Revīzija
|
||||||
releases=Laidieni
|
releases=Laidieni
|
||||||
file_raw=Neapstrādāts
|
file_raw=Neapstrādāts
|
||||||
file_history=Vēsture
|
file_history=Vēsture
|
||||||
|
|
@ -1544,6 +1547,7 @@ no_read=Jums nav neviena izlasīta paziņojuma.
|
||||||
pin=Piespraust paziņojumu
|
pin=Piespraust paziņojumu
|
||||||
mark_as_read=Atzīmēt kā izlasītu
|
mark_as_read=Atzīmēt kā izlasītu
|
||||||
mark_as_unread=Atzīmēt kā nelasītu
|
mark_as_unread=Atzīmēt kā nelasītu
|
||||||
|
mark_all_as_read=Atzīmēt visus kā izlasītus
|
||||||
|
|
||||||
[gpg]
|
[gpg]
|
||||||
error.extract_sign=Neizdevās izgūt parakstu
|
error.extract_sign=Neizdevās izgūt parakstu
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,6 @@ invalid_repo_path=Ścieżka repozytoriów nie jest poprawna: %v
|
||||||
run_user_not_match=Użytkownik aplikacji nie jest aktualnym użytkownikiem: %s -> %s
|
run_user_not_match=Użytkownik aplikacji nie jest aktualnym użytkownikiem: %s -> %s
|
||||||
save_config_failed=Nie udało się zapisać konfiguracji: %v
|
save_config_failed=Nie udało się zapisać konfiguracji: %v
|
||||||
invalid_admin_setting=Nieprawidłowe ustawienia konta admina: %v
|
invalid_admin_setting=Nieprawidłowe ustawienia konta admina: %v
|
||||||
install_success=Witaj! Dziękujemy za wybranie Gitea. Miłej zabawy. Trzymaj się!
|
|
||||||
invalid_log_root_path=Ścieżka dla logów jest niepoprawna: %v
|
invalid_log_root_path=Ścieżka dla logów jest niepoprawna: %v
|
||||||
default_keep_email_private=Domyślnie ukrywaj adresy e-mail
|
default_keep_email_private=Domyślnie ukrywaj adresy e-mail
|
||||||
default_keep_email_private_popup=To jest domyślne ustawienie widoczności adresu e-mail użytkowników. Włączone spowoduje, że adres e-mail wszystkich nowych użytkowników zostanie domyślnie ukryty.
|
default_keep_email_private_popup=To jest domyślne ustawienie widoczności adresu e-mail użytkowników. Włączone spowoduje, że adres e-mail wszystkich nowych użytkowników zostanie domyślnie ukryty.
|
||||||
|
|
@ -201,8 +200,6 @@ non_local_account=Nie lokalne konta nie mogą zmieniać haseł przez webowy inte
|
||||||
verify=Potwierdź
|
verify=Potwierdź
|
||||||
scratch_code=Scratch kod
|
scratch_code=Scratch kod
|
||||||
use_scratch_code=Użyj scratch kod
|
use_scratch_code=Użyj scratch kod
|
||||||
twofa_scratch_used=Użyłeś/aś swojego kodu zdrapki. Przekierowano Cię do strony z ustawieniami autoryzacji dwuetapowej, gdzie możesz usunąć usunąć swoje urządzenie lub wygenerować nowy kod zdrapkę.
|
|
||||||
twofa_passcode_incorrect=Twój kod autoryzacji jest niepoprawny. Jeśli zapodziałeś/aś swoje urządzenie, użyj swojego kodu zdrapki do zalogowania.
|
|
||||||
twofa_scratch_token_incorrect=Scratch token nie jest poprawny.
|
twofa_scratch_token_incorrect=Scratch token nie jest poprawny.
|
||||||
login_userpass=Użytkownik / Hasło
|
login_userpass=Użytkownik / Hasło
|
||||||
login_openid=OpenID
|
login_openid=OpenID
|
||||||
|
|
@ -434,11 +431,9 @@ twofa_disable_note=W razie potrzeby można wyłączyć uwierzytelnianie dwuetapo
|
||||||
twofa_disable_desc=Wyłączenie dwuetapowej autoryzacji sprawi, że Twoje konto będzie mniej bezpieczne. Czy na pewno chcesz kontynuować?
|
twofa_disable_desc=Wyłączenie dwuetapowej autoryzacji sprawi, że Twoje konto będzie mniej bezpieczne. Czy na pewno chcesz kontynuować?
|
||||||
regenerate_scratch_token_desc=Jeśli zgubiłeś lub zużyłeś swój scratch token możesz go wygenerować tutaj.
|
regenerate_scratch_token_desc=Jeśli zgubiłeś lub zużyłeś swój scratch token możesz go wygenerować tutaj.
|
||||||
twofa_disabled=Dwuetapowa autoryzacja została wyłączona.
|
twofa_disabled=Dwuetapowa autoryzacja została wyłączona.
|
||||||
scan_this_image=Zeskanuj ten obraz za pomocą swojej aplikacji autoryzacyjnej:
|
|
||||||
or_enter_secret=Lub wprowadź sekret: %s
|
or_enter_secret=Lub wprowadź sekret: %s
|
||||||
then_enter_passcode=I podaj kod autoryzacji otrzymany z aplikacji:
|
then_enter_passcode=I podaj kod autoryzacji otrzymany z aplikacji:
|
||||||
passcode_invalid=Kod dostępu jest nieprawidłowy. Spróbuj ponownie.
|
passcode_invalid=Kod dostępu jest nieprawidłowy. Spróbuj ponownie.
|
||||||
twofa_enrolled=Twoje konto ma teraz włączoną autoryzację dwuetapową. Koniecznie zachowaj swój kod zdrapkę (%s), ponieważ będzie pokazany tylko raz!
|
|
||||||
|
|
||||||
manage_account_links=Zarządzaj połączonymi kontami
|
manage_account_links=Zarządzaj połączonymi kontami
|
||||||
manage_account_links_desc=Zewnętrzne konta połączone z tym kontem
|
manage_account_links_desc=Zewnętrzne konta połączone z tym kontem
|
||||||
|
|
@ -460,7 +455,6 @@ owner=Właściciel
|
||||||
repo_name=Nazwa repozytorium
|
repo_name=Nazwa repozytorium
|
||||||
repo_name_helper=Dobra nazwa repozytorium jest utworzona z krótkich, łatwych do zapamiętania i unikalnych słów kluczowych.
|
repo_name_helper=Dobra nazwa repozytorium jest utworzona z krótkich, łatwych do zapamiętania i unikalnych słów kluczowych.
|
||||||
visibility=Widoczność
|
visibility=Widoczność
|
||||||
visiblity_helper=Te repozytorium jest <span class="ui red text">prywatne</span>
|
|
||||||
visiblity_helper_forced=Administrator systemu wymaga, żeby wszystkie nowe repozytoria były <span class="ui red text">prywatne</span>
|
visiblity_helper_forced=Administrator systemu wymaga, żeby wszystkie nowe repozytoria były <span class="ui red text">prywatne</span>
|
||||||
visiblity_fork_helper=(Zmiana tej wartości wpłynie na wszystkie forki)
|
visiblity_fork_helper=(Zmiana tej wartości wpłynie na wszystkie forki)
|
||||||
clone_helper=Potrzebujesz pomocy z klonowaniem? Odwiedź <a target="_blank" rel="noopener" href="%s">Pomoc</a>!
|
clone_helper=Potrzebujesz pomocy z klonowaniem? Odwiedź <a target="_blank" rel="noopener" href="%s">Pomoc</a>!
|
||||||
|
|
@ -494,7 +488,6 @@ form.name_pattern_not_allowed=Wzorzec nazwy repozytorium „%s” jest niedozwol
|
||||||
|
|
||||||
need_auth=Wymaga autoryzacji
|
need_auth=Wymaga autoryzacji
|
||||||
migrate_type=Typ migracji
|
migrate_type=Typ migracji
|
||||||
migrate_type_helper=Te repozytorium będzie <span class="text blue">kopią lustrzaną</span>
|
|
||||||
migrate_repo=Przenieś repozytorium
|
migrate_repo=Przenieś repozytorium
|
||||||
migrate.clone_address=Sklonuj adres
|
migrate.clone_address=Sklonuj adres
|
||||||
migrate.clone_address_desc=To może być adres HTTP/HTTPS/GIT lub ścieżka lokalna serwera.
|
migrate.clone_address_desc=To może być adres HTTP/HTTPS/GIT lub ścieżka lokalna serwera.
|
||||||
|
|
@ -550,7 +543,6 @@ editor.edit_file=Edytuj plik
|
||||||
editor.preview_changes=Podgląd zmian
|
editor.preview_changes=Podgląd zmian
|
||||||
editor.cannot_edit_non_text_files=Nie można edytować plików binarnych przez interfejs webowy
|
editor.cannot_edit_non_text_files=Nie można edytować plików binarnych przez interfejs webowy
|
||||||
editor.edit_this_file=Edytuj ten plik
|
editor.edit_this_file=Edytuj ten plik
|
||||||
editor.must_be_on_a_branch=Musisz być na gałęzi aby zgłosić lub zaproponować zmiany tego pliku
|
|
||||||
editor.fork_before_edit=Musisz sforkować to repozytorium przed edycją tego pliku
|
editor.fork_before_edit=Musisz sforkować to repozytorium przed edycją tego pliku
|
||||||
editor.delete_this_file=Usuń ten plik
|
editor.delete_this_file=Usuń ten plik
|
||||||
editor.must_have_write_access=Musisz mieć uprawnienia do zapisu, aby zgłosić lub zaproponować zmiany do tego pliku
|
editor.must_have_write_access=Musisz mieć uprawnienia do zapisu, aby zgłosić lub zaproponować zmiany do tego pliku
|
||||||
|
|
@ -1264,7 +1256,6 @@ auths.domain=Domena
|
||||||
auths.host=Serwer
|
auths.host=Serwer
|
||||||
auths.port=Port
|
auths.port=Port
|
||||||
auths.bind_password=Hasło Bind
|
auths.bind_password=Hasło Bind
|
||||||
auths.bind_password_helper=Uwaga: Te hasło jest przechowywane bez szyfrowania. Zdecydowanie zalecane jest użycie konta z uprawnieniami tylko do odczytu.
|
|
||||||
auths.user_base=Baza wyszukiwania
|
auths.user_base=Baza wyszukiwania
|
||||||
auths.user_dn=DN użytkownika
|
auths.user_dn=DN użytkownika
|
||||||
auths.attribute_username=Atrybut nazwy użytkownika
|
auths.attribute_username=Atrybut nazwy użytkownika
|
||||||
|
|
@ -1446,7 +1437,6 @@ notices.type=Typ
|
||||||
notices.type_1=Repozytorium
|
notices.type_1=Repozytorium
|
||||||
notices.desc=Opis
|
notices.desc=Opis
|
||||||
notices.op=Operacja
|
notices.op=Operacja
|
||||||
notices.delete_success=Powiadomienia systemowe zostały usunięte.
|
|
||||||
|
|
||||||
[action]
|
[action]
|
||||||
create_repo=tworzy repozytorium <a href="%s">%s</a>
|
create_repo=tworzy repozytorium <a href="%s">%s</a>
|
||||||
|
|
|
||||||
|
|
@ -489,6 +489,8 @@ mirror_last_synced=Última sincronização
|
||||||
watchers=Observadores
|
watchers=Observadores
|
||||||
stargazers=Usuários que estrelaram
|
stargazers=Usuários que estrelaram
|
||||||
forks=Forks
|
forks=Forks
|
||||||
|
pick_reaction=Escolha sua reação
|
||||||
|
reactions_more=e %d mais
|
||||||
|
|
||||||
form.reach_limit_of_creation=Você já atingiu o seu limite de %d repositórios.
|
form.reach_limit_of_creation=Você já atingiu o seu limite de %d repositórios.
|
||||||
form.name_reserved=O nome de repositório '%s' é reservado e não pode ser usado.
|
form.name_reserved=O nome de repositório '%s' é reservado e não pode ser usado.
|
||||||
|
|
@ -539,6 +541,7 @@ pulls=Pull Requests
|
||||||
labels=Etiquetas
|
labels=Etiquetas
|
||||||
milestones=Marcos
|
milestones=Marcos
|
||||||
commits=Commits
|
commits=Commits
|
||||||
|
commit=Commit
|
||||||
releases=Versões
|
releases=Versões
|
||||||
file_raw=Original
|
file_raw=Original
|
||||||
file_history=Histórico
|
file_history=Histórico
|
||||||
|
|
@ -752,7 +755,6 @@ pulls.is_checking=A verificação do conflito ainda está em progresso, por favo
|
||||||
pulls.can_auto_merge_desc=O merge deste pull request pode ser aplicado automaticamente.
|
pulls.can_auto_merge_desc=O merge deste pull request pode ser aplicado automaticamente.
|
||||||
pulls.cannot_auto_merge_desc=O merge deste pull request não pode ser aplicado automaticamente pois há conflitos.
|
pulls.cannot_auto_merge_desc=O merge deste pull request não pode ser aplicado automaticamente pois há conflitos.
|
||||||
pulls.cannot_auto_merge_helper=Por favor, aplique o merge manualmente para resolver os conflitos.
|
pulls.cannot_auto_merge_helper=Por favor, aplique o merge manualmente para resolver os conflitos.
|
||||||
pulls.merge_pull_request=Solicitação de merge de Pull Request
|
|
||||||
pulls.open_unmerged_pull_exists=`Você não pode executar a operação de reabrir porque já existe um pull request aberto (#%d) do mesmo repositório com as mesmas informações de merge e está esperando pelo merge.`
|
pulls.open_unmerged_pull_exists=`Você não pode executar a operação de reabrir porque já existe um pull request aberto (#%d) do mesmo repositório com as mesmas informações de merge e está esperando pelo merge.`
|
||||||
|
|
||||||
milestones.new=Novo marco
|
milestones.new=Novo marco
|
||||||
|
|
@ -804,6 +806,7 @@ wiki.new_page_button=Nova página
|
||||||
wiki.delete_page_button=Excluir página
|
wiki.delete_page_button=Excluir página
|
||||||
wiki.delete_page_notice_1=Isso vai deletar a página <code>"%s"</code>. Por favor, verifique se você quer mesmo deletar esta página.
|
wiki.delete_page_notice_1=Isso vai deletar a página <code>"%s"</code>. Por favor, verifique se você quer mesmo deletar esta página.
|
||||||
wiki.page_already_exists=já existe uma página de wiki com o mesmo nome.
|
wiki.page_already_exists=já existe uma página de wiki com o mesmo nome.
|
||||||
|
wiki.reserved_page=O nome %s para página wiki está reservado, por favor, selecione um nome diferente.
|
||||||
wiki.pages=Páginas
|
wiki.pages=Páginas
|
||||||
wiki.last_updated=Última atualização %s
|
wiki.last_updated=Última atualização %s
|
||||||
|
|
||||||
|
|
@ -1543,6 +1546,7 @@ no_read=Você não possui nenhuma notificação lida.
|
||||||
pin=Fixar notificação
|
pin=Fixar notificação
|
||||||
mark_as_read=Marcar como lida
|
mark_as_read=Marcar como lida
|
||||||
mark_as_unread=Marcar como não lida
|
mark_as_unread=Marcar como não lida
|
||||||
|
mark_all_as_read=Marcar todas como lidas
|
||||||
|
|
||||||
[gpg]
|
[gpg]
|
||||||
error.extract_sign=Falha ao extrair assinatura
|
error.extract_sign=Falha ao extrair assinatura
|
||||||
|
|
|
||||||
|
|
@ -489,6 +489,8 @@ mirror_last_synced=Последняя синхронизация
|
||||||
watchers=Наблюдатели
|
watchers=Наблюдатели
|
||||||
stargazers=Звездочеты
|
stargazers=Звездочеты
|
||||||
forks=Форки
|
forks=Форки
|
||||||
|
pick_reaction=Оставьте свою оценку!
|
||||||
|
reactions_more=и ещё %d
|
||||||
|
|
||||||
form.reach_limit_of_creation=Вы уже достигли ваш предел %d репозиториев.
|
form.reach_limit_of_creation=Вы уже достигли ваш предел %d репозиториев.
|
||||||
form.name_reserved=Имя репозитория '%s' зарезервировано.
|
form.name_reserved=Имя репозитория '%s' зарезервировано.
|
||||||
|
|
@ -529,16 +531,17 @@ bare_message=В репозитории нет файлов.
|
||||||
|
|
||||||
code=Код
|
code=Код
|
||||||
code.desc=Хранилище кода с историей изменений
|
code.desc=Хранилище кода с историей изменений
|
||||||
branch=Ветка
|
branch=ветка
|
||||||
tree=Дерево
|
tree=Дерево
|
||||||
filter_branch_and_tag=Фильтр по ветке или тегу
|
filter_branch_and_tag=Фильтр по ветке или тегу
|
||||||
branches=Ветки
|
branches=веток
|
||||||
tags=Теги
|
tags=Теги
|
||||||
issues=Задачи
|
issues=Задачи
|
||||||
pulls=Pull Request'ы
|
pulls=Pull Request'ы
|
||||||
labels=Метки
|
labels=Метки
|
||||||
milestones=Этапы
|
milestones=Этапы
|
||||||
commits=Коммиты
|
commits=коммитов
|
||||||
|
commit=коммит
|
||||||
releases=Релизы
|
releases=Релизы
|
||||||
file_raw=Исходник
|
file_raw=Исходник
|
||||||
file_history=История
|
file_history=История
|
||||||
|
|
@ -1544,6 +1547,7 @@ no_read=У вас нет прочитанных уведомлений.
|
||||||
pin=Прикрепить уведомление
|
pin=Прикрепить уведомление
|
||||||
mark_as_read=Отметить как прочитанное
|
mark_as_read=Отметить как прочитанное
|
||||||
mark_as_unread=Пометить как непрочитанное
|
mark_as_unread=Пометить как непрочитанное
|
||||||
|
mark_all_as_read=Пометить все как прочитанные
|
||||||
|
|
||||||
[gpg]
|
[gpg]
|
||||||
error.extract_sign=Не удалось извлечь подпись
|
error.extract_sign=Не удалось извлечь подпись
|
||||||
|
|
|
||||||
|
|
@ -405,6 +405,7 @@ key_state_desc=7 天内使用过该密钥
|
||||||
token_state_desc=7 天内使用过该密钥
|
token_state_desc=7 天内使用过该密钥
|
||||||
show_openid=在个人信息上显示
|
show_openid=在个人信息上显示
|
||||||
hide_openid=在个人信息上隐藏
|
hide_openid=在个人信息上隐藏
|
||||||
|
ssh_disabled=SSH 被禁用
|
||||||
|
|
||||||
manage_social=管理关联社交帐户
|
manage_social=管理关联社交帐户
|
||||||
social_desc=这是相关联的社会帐户的列表。出于安全考虑,请确保你认识的所有这些条目,因为它们可以用于登录到您的帐户。
|
social_desc=这是相关联的社会帐户的列表。出于安全考虑,请确保你认识的所有这些条目,因为它们可以用于登录到您的帐户。
|
||||||
|
|
@ -488,6 +489,8 @@ mirror_last_synced=上次同步时间:
|
||||||
watchers=关注者
|
watchers=关注者
|
||||||
stargazers=称赞者
|
stargazers=称赞者
|
||||||
forks=派生仓库
|
forks=派生仓库
|
||||||
|
pick_reaction=选择你的表情
|
||||||
|
reactions_more=再加载 %d
|
||||||
|
|
||||||
form.reach_limit_of_creation=你已经达到了您的 %d 仓库的限制。
|
form.reach_limit_of_creation=你已经达到了您的 %d 仓库的限制。
|
||||||
form.name_reserved=仓库名称 '%s' 是被保留的。
|
form.name_reserved=仓库名称 '%s' 是被保留的。
|
||||||
|
|
@ -538,6 +541,7 @@ pulls=合并请求
|
||||||
labels=标签
|
labels=标签
|
||||||
milestones=里程碑
|
milestones=里程碑
|
||||||
commits=提交
|
commits=提交
|
||||||
|
commit=提交
|
||||||
releases=版本发布
|
releases=版本发布
|
||||||
file_raw=原始文件
|
file_raw=原始文件
|
||||||
file_history=文件历史
|
file_history=文件历史
|
||||||
|
|
@ -803,6 +807,7 @@ wiki.new_page_button=新的页面
|
||||||
wiki.delete_page_button=删除页面
|
wiki.delete_page_button=删除页面
|
||||||
wiki.delete_page_notice_1=此操作将删除页面 <code>"%s"</code>。请确保您想要删除此页。
|
wiki.delete_page_notice_1=此操作将删除页面 <code>"%s"</code>。请确保您想要删除此页。
|
||||||
wiki.page_already_exists=相同名称的 Wiki 页面已经存在。
|
wiki.page_already_exists=相同名称的 Wiki 页面已经存在。
|
||||||
|
wiki.reserved_page=wiki 页面名称 %s 是保留的, 请选择其他名称。
|
||||||
wiki.pages=所有页面
|
wiki.pages=所有页面
|
||||||
wiki.last_updated=最后更新于 %s
|
wiki.last_updated=最后更新于 %s
|
||||||
|
|
||||||
|
|
@ -813,8 +818,8 @@ activity.period.halfweekly=3 天
|
||||||
activity.period.weekly=1周
|
activity.period.weekly=1周
|
||||||
activity.period.monthly=1 个月
|
activity.period.monthly=1 个月
|
||||||
activity.overview=概览
|
activity.overview=概览
|
||||||
activity.active_prs_count_1=<strong>%d</strong>活动请求
|
activity.active_prs_count_1=<strong>%d</strong> 合并请求
|
||||||
activity.active_prs_count_n=<strong>%d</strong>活动请求
|
activity.active_prs_count_n=<strong>%d</strong> 合并请求
|
||||||
activity.merged_prs_count_1=合并请求
|
activity.merged_prs_count_1=合并请求
|
||||||
activity.merged_prs_count_n=合并请求
|
activity.merged_prs_count_n=合并请求
|
||||||
activity.opened_prs_count_1=新合并请求
|
activity.opened_prs_count_1=新合并请求
|
||||||
|
|
@ -827,8 +832,8 @@ activity.title.prs_merged_by=%[2]s 由 %[1]s 合并
|
||||||
activity.title.prs_opened_by=%[2]s 创建了 %[1]s
|
activity.title.prs_opened_by=%[2]s 创建了 %[1]s
|
||||||
activity.merged_prs_label=已合并
|
activity.merged_prs_label=已合并
|
||||||
activity.opened_prs_label=已创建
|
activity.opened_prs_label=已创建
|
||||||
activity.active_issues_count_1=<strong>%d</strong>活动工单
|
activity.active_issues_count_1=<strong>%d</strong> 工单
|
||||||
activity.active_issues_count_n=<strong>%d</strong>活动工单
|
activity.active_issues_count_n=<strong>%d</strong> 工单
|
||||||
activity.closed_issues_count_1=已关闭的工单
|
activity.closed_issues_count_1=已关闭的工单
|
||||||
activity.closed_issues_count_n=已关闭的工单
|
activity.closed_issues_count_n=已关闭的工单
|
||||||
activity.title.issues_1=%d 工单
|
activity.title.issues_1=%d 工单
|
||||||
|
|
@ -977,6 +982,7 @@ settings.slack_token=令牌
|
||||||
settings.slack_domain=域名
|
settings.slack_domain=域名
|
||||||
settings.slack_channel=频道
|
settings.slack_channel=频道
|
||||||
settings.add_discord_hook_desc=为您的仓库增加 <a href="%s">Discord</a> 集成。
|
settings.add_discord_hook_desc=为您的仓库增加 <a href="%s">Discord</a> 集成。
|
||||||
|
settings.add_dingtalk_hook_desc=为您的仓库增加 <a href="%s">钉钉</a> 集成。
|
||||||
settings.deploy_keys=管理部署密钥
|
settings.deploy_keys=管理部署密钥
|
||||||
settings.add_deploy_key=添加部署密钥
|
settings.add_deploy_key=添加部署密钥
|
||||||
settings.deploy_key_desc=部署密钥仅具有只读权限,它在功能上和个人用户的公开密钥有本质区别。
|
settings.deploy_key_desc=部署密钥仅具有只读权限,它在功能上和个人用户的公开密钥有本质区别。
|
||||||
|
|
@ -1050,7 +1056,7 @@ release.prerelease_helper=我们会告知用户不建议将本次发布投入生
|
||||||
release.cancel=取消
|
release.cancel=取消
|
||||||
release.publish=发布版本
|
release.publish=发布版本
|
||||||
release.save_draft=保存草稿
|
release.save_draft=保存草稿
|
||||||
release.edit_release=编辑发布信息
|
release.edit_release=保存此次发布
|
||||||
release.delete_release=删除此次发布
|
release.delete_release=删除此次发布
|
||||||
release.deletion=删除版本发布操作
|
release.deletion=删除版本发布操作
|
||||||
release.deletion_desc=删除该版本发布将会移除相应的 Git 标签。是否继续?
|
release.deletion_desc=删除该版本发布将会移除相应的 Git 标签。是否继续?
|
||||||
|
|
@ -1541,6 +1547,7 @@ no_read=您没有任何已读的通知。
|
||||||
pin=Pin 通知
|
pin=Pin 通知
|
||||||
mark_as_read=标记为已读
|
mark_as_read=标记为已读
|
||||||
mark_as_unread=标记为未读
|
mark_as_unread=标记为未读
|
||||||
|
mark_all_as_read=全部标记为已读
|
||||||
|
|
||||||
[gpg]
|
[gpg]
|
||||||
error.extract_sign=无法提取签名
|
error.extract_sign=无法提取签名
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user