From 70532b86ed52623a395e6b2f3578cb6301285f9a Mon Sep 17 00:00:00 2001 From: Gitea Date: Thu, 19 Sep 2019 22:42:25 +0800 Subject: [PATCH 001/173] 'update' --- go.mod | 2 ++ 1 file changed, 2 insertions(+) diff --git a/go.mod b/go.mod index f5d49294d4361..d0e847ca98bf1 100644 --- a/go.mod +++ b/go.mod @@ -75,6 +75,8 @@ require ( github.com/mattn/go-sqlite3 v1.11.0 github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 github.com/microcosm-cc/bluemonday v0.0.0-20161012083705-f77f16ffc87a + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae // indirect github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 From b2cfbe158634f0e522d90f3db215d5546b5951f6 Mon Sep 17 00:00:00 2001 From: Benno Lin Date: Mon, 30 Sep 2019 21:01:16 +0800 Subject: [PATCH 002/173] Send push tag event when release created --- services/release/release.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/services/release/release.go b/services/release/release.go index 4451633798c08..332a718c3493d 100644 --- a/services/release/release.go +++ b/services/release/release.go @@ -35,6 +35,31 @@ func createTag(gitRepo *git.Repository, rel *models.Release) error { return err } rel.LowerTagName = strings.ToLower(rel.TagName) + + // Prepare Webhook + if err := rel.LoadAttributes(); err != nil { + log.Error("LoadAttributes: %v", err) + } else { + var shaSum string + mode, _ := models.AccessLevel(rel.Publisher, rel.Repo) + apiRepo := rel.Repo.APIFormat(mode) + apiPusher := rel.Publisher.APIFormat() + shaSum, err = gitRepo.GetTagCommitID(rel.TagName) + if err != nil { + log.Error("GetTagCommitID[%s]: %v", rel.TagName, err) + } + if err = models.PrepareWebhooks(rel.Repo, models.HookEventPush, &api.CreatePayload{ + Ref: git.TagPrefix + rel.TagName, + Sha: shaSum, + RefType: "tag", + Repo: apiRepo, + Sender: apiPusher, + }); err != nil { + log.Error("PrepareWebhooks: %v", err) + } else { + go models.HookQueue.Add(rel.Repo.ID) + } + } } commit, err := gitRepo.GetTagCommit(rel.TagName) if err != nil { From b15aabdf387aa7dac66f8ab3ab5e462ad2330420 Mon Sep 17 00:00:00 2001 From: Benno Lin Date: Mon, 30 Sep 2019 22:00:44 +0800 Subject: [PATCH 003/173] send tag create event while release created in UI --- services/release/release.go | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/services/release/release.go b/services/release/release.go index 96b79fecd78b9..498e9791d07d3 100644 --- a/services/release/release.go +++ b/services/release/release.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" ) @@ -40,6 +41,11 @@ func createTag(gitRepo *git.Repository, rel *models.Release) error { if err := rel.LoadAttributes(); err != nil { log.Error("LoadAttributes: %v", err) } else { + + defer func() { + go models.HookQueue.Add(rel.Repo.ID) + }() + var shaSum string mode, _ := models.AccessLevel(rel.Publisher, rel.Repo) apiRepo := rel.Repo.APIFormat(mode) @@ -48,16 +54,29 @@ func createTag(gitRepo *git.Repository, rel *models.Release) error { if err != nil { log.Error("GetTagCommitID[%s]: %v", rel.TagName, err) } - if err = models.PrepareWebhooks(rel.Repo, models.HookEventPush, &api.CreatePayload{ + + // Tag Create + if err = models.PrepareWebhooks(rel.Repo, models.HookEventCreate, &api.CreatePayload{ Ref: git.TagPrefix + rel.TagName, Sha: shaSum, RefType: "tag", Repo: apiRepo, Sender: apiPusher, }); err != nil { - log.Error("PrepareWebhooks: %v", err) - } else { - go models.HookQueue.Add(rel.Repo.ID) + return fmt.Errorf("PrepareWebhooks: %v", err) + } + // Tag Push + if err = models.PrepareWebhooks(rel.Repo, models.HookEventPush, &api.PushPayload{ + Ref: git.TagPrefix + rel.TagName, + Before: git.EmptySHA, + After: shaSum, + CompareURL: setting.AppURL, + Commits: make([]*api.PayloadCommit, 0), + Repo: apiRepo, + Pusher: apiPusher, + Sender: apiPusher, + }); err != nil { + return fmt.Errorf("PrepareWebhooks: %v", err) } } } From 15e5ac686ced175de4c5ab5d79567fcfb299a5a5 Mon Sep 17 00:00:00 2001 From: Benno Lin Date: Tue, 1 Oct 2019 23:27:00 +0800 Subject: [PATCH 004/173] update to go v1.13 --- go.mod | 2 -- 1 file changed, 2 deletions(-) diff --git a/go.mod b/go.mod index 0606303cb6856..c8a44da1b5390 100644 --- a/go.mod +++ b/go.mod @@ -75,8 +75,6 @@ require ( github.com/mattn/go-sqlite3 v1.11.0 github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 github.com/microcosm-cc/bluemonday v0.0.0-20161012083705-f77f16ffc87a - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.1 // indirect github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae // indirect github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 From 57146dc8dacbe40af43d84219956bd9ed0578516 Mon Sep 17 00:00:00 2001 From: Benno Lin Date: Tue, 1 Oct 2019 23:42:43 +0800 Subject: [PATCH 005/173] fix gofmt error --- services/release/release.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/release/release.go b/services/release/release.go index 4d60bd5cc584b..abd397489b45e 100644 --- a/services/release/release.go +++ b/services/release/release.go @@ -12,8 +12,8 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/process" + "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" ) From cd1c960a2aed20b7e3f793a87d497ab41eaf471d Mon Sep 17 00:00:00 2001 From: helix84 Date: Wed, 2 Oct 2019 01:25:32 +0200 Subject: [PATCH 006/173] typo fix (#8345) --- docs/content/doc/advanced/config-cheat-sheet.en-us.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 60d7341f241ab..198cff6f04948 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -292,7 +292,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `INTERVAL`: **60**: Garbage Collection interval (sec), for memory cache only. - `HOST`: **\**: Connection string for `redis` and `memcache`. - Redis: `network=tcp,addr=127.0.0.1:6379,password=macaron,db=0,pool_size=100,idle_timeout=180` - - Memache: `127.0.0.1:9090;127.0.0.1:9091` + - Memcache: `127.0.0.1:9090;127.0.0.1:9091` - `ITEM_TTL`: **16h**: Time to keep items in cache if not used, Setting it to 0 disables caching. ## Session (`session`) @@ -521,4 +521,4 @@ Two special environment variables are passed to the render command: - `SHOW_FOOTER_BRANDING`: **false**: Show Gitea branding in the footer. - `SHOW_FOOTER_VERSION`: **true**: Show Gitea version information in the footer. -- `SHOW_FOOTER_TEMPLATE_LOAD_TIME`: **true**: Show time of template execution in the footer. \ No newline at end of file +- `SHOW_FOOTER_TEMPLATE_LOAD_TIME`: **true**: Show time of template execution in the footer. From 3a7e3dbfb40b892bf2b90e3d6bf30a028eae478a Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Tue, 1 Oct 2019 23:27:07 +0000 Subject: [PATCH 007/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_tr-TR.ini | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index 00612292ced37..5c90a682508a1 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -499,6 +499,7 @@ passcode_invalid=Şifre geçersiz. Tekrar deneyin. u2f_register_key=Güvenlik Anahtarı Ekle u2f_nickname=Takma Ad +u2f_delete_key=Güvenlik Anahtarını Sil manage_account_links=Bağlı Hesapları Yönet manage_account_links_desc=Bu harici hesaplar Gitea hesabınızla bağlantılı. @@ -576,9 +577,13 @@ migrate_items_pullrequests=Değişiklik İstekleri migrate_items_releases=Sürümler migrate_repo=Depoyu Göç Ettir migrate.clone_address=URL'den Taşı / Klonla +migrate.clone_address_desc=Varolan bir deponun HTTP(S) veya Git 'klonlama' URL'si migrate.clone_local_path=veya bir yerel sunucu yolu migrate.permission_denied=Yerel depoları içeri aktarma izniniz yok. +migrate.invalid_local_path=Yerel yol geçersiz. Mevcut değil veya bir dizin değil. migrate.failed=Göç başarısız: %v +migrate.lfs_mirror_unsupported=LFS nesnelerini yansılama desteklenmiyor - yerine 'git lfs fetch --all' ve 'git lfs push --all' kullanın. +migrate.migrate_items_options=Github'dan göç yaparken, bir kullanıcı adı girin ve göç seçenekleri görüntülenecektir. migrated_from_fake=%[1]s Konumundan Taşındı mirror_from=şunun yansıması @@ -720,6 +725,8 @@ issues.remove_milestone_at=`bu dosya %s yol taşından kaldırıldı %s` issues.deleted_milestone=`(silindi)` issues.self_assign_at=`kendiliğinden atanmış bu %s` issues.add_assignee_at=`%s tarafından atandı %s` +issues.remove_assignee_at=`%s tarafından atama kaldırıldı %s` +issues.remove_self_assignment=`atamalarını kaldırdı %s` issues.change_title_at=`başlık %s iken %s olarak değiştirildi %s` issues.delete_branch_at=`branş %s silindi %s` issues.open_tab=%d açık @@ -751,8 +758,8 @@ issues.filter_sort.fewestforks=En az çatallananlar issues.action_open=Açık issues.action_close=Kapalı issues.action_label=Etiket -issues.action_milestone=Katedilen Yol -issues.action_milestone_no_select=Katedilen Yol Yok +issues.action_milestone=Kilometre Taşı +issues.action_milestone_no_select=Kilometre Taşı Yok issues.action_assignee=Vekil issues.action_assignee_no_select=Vekil yok issues.opened_by=%[3]s tarafından %[1]s açıldı @@ -910,6 +917,9 @@ pulls.no_merge_helper=Depo ayarlarındaki birleştirme seçeneklerini etkinleşt pulls.no_merge_wip=Bu değişiklik isteği birleştirilemez çünkü devam eden bir çalışma olarak işaretlendi. pulls.no_merge_status_check=Gerekli olan tüm durum denetimleri başarılı olmadığından bu değişiklik isteği birleştirilemez. pulls.merge_pull_request=Değişiklik İsteğini Birleştir +pulls.rebase_merge_pull_request=Rebase ve Merge +pulls.rebase_merge_commit_pull_request=Rebase ve Merge (--no-ff) +pulls.squash_merge_pull_request=Squash ve Merge pulls.invalid_merge_option=Bu değişiklik isteği için bu birleştirme seçeneğini kullanamazsınız. pulls.open_unmerged_pull_exists=`Aynı özelliklere sahip bekleyen bir çekme isteği (#%d) olduğundan yeniden açma işlemini gerçekleştiremezsiniz.` pulls.status_checking=Bazı denetlemeler beklemede @@ -1444,6 +1454,8 @@ dashboard.delete_missing_repos=Git dosyaları eksik olan tüm depoları sil dashboard.delete_missing_repos_success=Git dosyaları eksik olan tüm depolar silindi. dashboard.delete_generated_repository_avatars=Oluşturulan depo resimlerini sil dashboard.delete_generated_repository_avatars_success=Oluşturulan depo resimleri silindi. +dashboard.git_gc_repos=Depolardaki çöpleri topla +dashboard.git_gc_repos_success=Tüm depolardaki çöp toplama işlemi bitti. dashboard.resync_all_sshkeys_success=Gitea tarafından kontrol edilen açık SSH anahtarları güncellendi. dashboard.reinit_missing_repos=Kayıtları bulunanlar için tüm eksik Git depolarını yeniden başlat dashboard.reinit_missing_repos_success=Kayıtları bulunanlar için tüm eksik Git depoları yeniden başlatıldı. @@ -1607,6 +1619,7 @@ config.reverse_auth_user=Tersine Yetkilendirme Kullanıcısı config.ssh_config=SSH Yapılandırması config.ssh_enabled=Aktif +config.ssh_domain=Sunucu Alan Adı config.ssh_port=Bağlantı Noktası config.ssh_listen_port=Port'u Dinle config.ssh_root_path=Kök Yol @@ -1761,6 +1774,7 @@ raw_minutes=dakikalar [dropzone] default_message=Dosyaları buraya bırakın veya yüklemek için tıklayın. invalid_input_type=Bu tür dosyaları yükleyemezsiniz. +file_too_big=Dosya boyutu ({{filesize}} MB) maksimum boyutu ({{maxFilesize}} MB) aşıyor. remove_file=Dosya Kaldır [notification] @@ -1780,6 +1794,7 @@ error.generate_hash=İşlemenin sağlama kodu oluşturulamadı error.no_committer_account=İşleme yapanın e-posta adresine bağlı hesap yok error.no_gpg_keys_found=Veri tabanında bu imza için bilinen anahtar bulunamadı error.not_signed_commit=İmzalı bir işleme değil +error.failed_retrieval_gpg_keys=İşleme yapanın hesabına bağlı herhangi bir anahtar alınamadı [units] error.no_unit_allowed_repo=Bu deponun hiçbir bölümüne erişme izniniz yok. From 149758c912842bedda86b5087cffd59ce0682e58 Mon Sep 17 00:00:00 2001 From: Antoine GIRARD Date: Wed, 2 Oct 2019 02:32:12 +0200 Subject: [PATCH 008/173] Update to github.com/lafriks/xormstore@v1.3.0 (#8317) --- go.mod | 8 +- go.sum | 31 +- .../denisenkom/go-mssqldb/README.md | 6 +- .../denisenkom/go-mssqldb/appveyor.yml | 6 +- .../github.com/denisenkom/go-mssqldb/buf.go | 24 +- .../denisenkom/go-mssqldb/bulkcopy.go | 117 +++-- .../denisenkom/go-mssqldb/conn_str.go | 453 ++++++++++++++++ .../denisenkom/go-mssqldb/decimal.go | 131 ----- .../github.com/denisenkom/go-mssqldb/go.mod | 4 +- .../github.com/denisenkom/go-mssqldb/go.sum | 167 +----- .../go-mssqldb/internal/decimal/decimal.go | 252 +++++++++ .../denisenkom/go-mssqldb/mssql_go19.go | 2 +- .../github.com/denisenkom/go-mssqldb/net.go | 145 ++++-- .../github.com/denisenkom/go-mssqldb/tds.go | 483 +----------------- .../github.com/denisenkom/go-mssqldb/types.go | 18 +- .../denisenkom/go-mssqldb/uniqueidentifier.go | 6 + .../golang-sql/civil/CONTRIBUTING.md | 73 +++ vendor/github.com/golang-sql/civil/LICENSE | 202 ++++++++ vendor/github.com/golang-sql/civil/README.md | 15 + .../golang-sql}/civil/civil.go | 0 vendor/github.com/lafriks/xormstore/go.mod | 16 +- vendor/github.com/lafriks/xormstore/go.sum | 88 +--- vendor/golang.org/x/crypto/acme/acme.go | 189 +++++-- .../x/crypto/acme/autocert/autocert.go | 42 +- vendor/golang.org/x/crypto/acme/http.go | 20 +- vendor/golang.org/x/crypto/acme/jws.go | 33 +- vendor/golang.org/x/crypto/acme/rfc8555.go | 122 +++++ vendor/golang.org/x/crypto/acme/types.go | 89 +++- vendor/golang.org/x/crypto/ssh/common.go | 10 +- .../appengine/internal/net.go | 2 +- vendor/modules.txt | 12 +- 31 files changed, 1680 insertions(+), 1086 deletions(-) create mode 100644 vendor/github.com/denisenkom/go-mssqldb/conn_str.go delete mode 100644 vendor/github.com/denisenkom/go-mssqldb/decimal.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/internal/decimal/decimal.go create mode 100644 vendor/github.com/golang-sql/civil/CONTRIBUTING.md create mode 100644 vendor/github.com/golang-sql/civil/LICENSE create mode 100644 vendor/github.com/golang-sql/civil/README.md rename vendor/{cloud.google.com/go => github.com/golang-sql}/civil/civil.go (100%) create mode 100644 vendor/golang.org/x/crypto/acme/rfc8555.go diff --git a/go.mod b/go.mod index c8a44da1b5390..08a663dcdd837 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d // indirect github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 // indirect - github.com/denisenkom/go-mssqldb v0.0.0-20190820223206-44cdfe8d8ba9 + github.com/denisenkom/go-mssqldb v0.0.0-20190924004331-208c0a498538 github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/emirpasic/gods v1.12.0 github.com/etcd-io/bbolt v1.3.2 // indirect @@ -64,7 +64,7 @@ require ( github.com/klauspost/compress v0.0.0-20161025140425-8df558b6cb6f github.com/klauspost/cpuid v0.0.0-20160302075316-09cded8978dc // indirect github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6 // indirect - github.com/lafriks/xormstore v1.2.0 + github.com/lafriks/xormstore v1.3.0 github.com/lib/pq v1.2.0 github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 github.com/lunny/levelqueue v0.0.0-20190217115915-02b525a4418e @@ -104,16 +104,14 @@ require ( github.com/urfave/cli v1.20.0 github.com/willf/bitset v0.0.0-20180426185212-8ce1146b8621 // indirect github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53 - golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472 + golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad golang.org/x/net v0.0.0-20190909003024-a7b16738d86b golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 golang.org/x/sys v0.0.0-20190910064555-bbd175535a8b golang.org/x/text v0.3.2 golang.org/x/tools v0.0.0-20190910221609-7f5965fd7709 // indirect - google.golang.org/appengine v1.6.2 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 // indirect - gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/editorconfig/editorconfig-core-go.v1 v1.3.0 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/ini.v1 v1.46.0 diff --git a/go.sum b/go.sum index 477199616c7f3..10ad062635280 100644 --- a/go.sum +++ b/go.sum @@ -123,8 +123,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= -github.com/denisenkom/go-mssqldb v0.0.0-20190820223206-44cdfe8d8ba9 h1:r05vdZzhwcLFTrNCNirAQEL30b/tlqnI0ow7BCcUiT4= -github.com/denisenkom/go-mssqldb v0.0.0-20190820223206-44cdfe8d8ba9/go.mod h1:uU0N10vx1abI4qeVe79CxepBP6PPREVTgMS5Gx6/mOk= +github.com/denisenkom/go-mssqldb v0.0.0-20190924004331-208c0a498538 h1:bpWCJ5MddHsv4Xtl3azkK89mZzd/vvut32mvAnKbyUA= +github.com/denisenkom/go-mssqldb v0.0.0-20190924004331-208c0a498538/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= @@ -249,7 +249,6 @@ github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013 h1:l github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013/go.mod h1:b65mBPzqzZWxOZGxSWrqs4GInLIn+u99Q9q7p+GKni0= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= -github.com/go-xorm/xorm v0.7.6/go.mod h1:nqz2TAsuOHWH2yk4FYWtacCGgdbrcdZ5mF1XadqEHls= github.com/go-xorm/xorm v0.7.8 h1:rKxZJB9mWQ9Nw2TbjsepiThR031jkGePOWXwTtEAU08= github.com/go-xorm/xorm v0.7.8/go.mod h1:XiVxrMMIhFkwSkh96BW7PACl7UhLtx2iJIHMdmjh5sQ= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= @@ -262,6 +261,8 @@ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 h1:yXtpJr/LV6PFu4nTLgfjQdcMdzjbqqXMEnHfq0Or6p8= github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14/go.mod h1:jPoNZLWDAqA5N3G5amEoiNbhVrmM+ZQEcnQvNQ2KaZk= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -338,10 +339,6 @@ github.com/issue9/identicon v0.0.0-20160320065130-d36b54562f4c h1:A/PDn117UYld5m github.com/issue9/identicon v0.0.0-20160320065130-d36b54562f4c/go.mod h1:5mTb/PQNkqmq2x3IxlQZE0aSnTksJg7fg/oWmJ5SKXQ= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= -github.com/jackc/pgx v3.3.0+incompatible h1:Wa90/+qsITBAPkAZjiByeIGHFcj3Ztu+VzrrIpHjL90= -github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= -github.com/jackc/pgx v3.5.0+incompatible h1:BRJ4G3UPtvml5R1ey0biqqGuYUGayMYekm3woO75orY= -github.com/jackc/pgx v3.5.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jackc/pgx v3.6.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4= github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d h1:ig/iUfDDg06RVW8OMby+GrmW6K2nPO3AFHlEIdvJSd4= @@ -387,8 +384,8 @@ github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lafriks/xormstore v1.2.0 h1:3L1lbjpLAAE+91vU3yPlXhHfnYnhxAklFUi2eiMalc4= -github.com/lafriks/xormstore v1.2.0/go.mod h1:g47/cl3RfWykO5c4nw/Io3N0R+JuDqiD2YY7NzfWDoU= +github.com/lafriks/xormstore v1.3.0 h1:9A2wAZrdEXtTgfjCFtclPz3pwnmmxY7sJxQgIi62li4= +github.com/lafriks/xormstore v1.3.0/go.mod h1:RAhtOztWBjK9xeZpXwKq59rhUxoRgo1zfYl0H1mtK7A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -628,10 +625,8 @@ golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 h1:7KByu05hhLed2MO29w7p1XfZvZ13m8mub3shuVftRs0= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472 h1:Gv7RPwsi3eZ2Fgewe3CBsuOebPwO27PoXzRpJPsvSSM= -golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad h1:5E5raQxcv+6CZ11RrBYQe5WRbUIWpScjh0kvHZkZIrQ= +golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= @@ -699,7 +694,6 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -729,7 +723,6 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -754,8 +747,8 @@ google.golang.org/appengine v1.6.0 h1:Tfd7cKwKbFRsI8RMAD3oqqw7JPFRrvFlOsfbgVkjOO google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.2 h1:j8RI1yW0SkI+paT6uGwMlrMI/6zwYA6/CFil8rxOzGI= -google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.4 h1:WiKh4+/eMB2HaY7QhCfW/R7MuRAoA8QMCSJA6jP5/fo= +google.golang.org/appengine v1.6.4/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -824,12 +817,8 @@ mvdan.cc/xurls/v2 v2.0.0/go.mod h1:2/webFPYOXN9jp/lzuj0zuAVlF+9g4KPFJANH1oJhRU= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a h1:8q33ShxKXRwQ7JVd1ZnhIU3hZhwwn0Le+4fTeAackuM= strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY= -xorm.io/builder v0.3.5 h1:EilU39fvWDxjb1cDaELpYhsF+zziRBhew8xk4pngO+A= -xorm.io/builder v0.3.5/go.mod h1:ZFbByS/KxZI1FKRjL05PyJ4YrK2bcxlUaAxdum5aTR8= xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8= xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU= -xorm.io/core v0.7.0 h1:hKxuOKWZNeiFQsSuGet/KV8HZ788hclvAl+7azx3tkM= -xorm.io/core v0.7.0/go.mod h1:TuOJjIVa7e3w/rN8tDcAvuLBMtwzdHPbyOzE6Gk1EUI= xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb h1:msX3zG3BPl8Ti+LDzP33/9K7BzO/WqFXk610K1kYKfo= xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM= xorm.io/core v0.7.2 h1:mEO22A2Z7a3fPaZMk6gKL/jMD80iiyNwRrX5HOv3XLw= diff --git a/vendor/github.com/denisenkom/go-mssqldb/README.md b/vendor/github.com/denisenkom/go-mssqldb/README.md index 41d9461a00c4b..669b0fe9914e9 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/README.md +++ b/vendor/github.com/denisenkom/go-mssqldb/README.md @@ -220,9 +220,9 @@ are supported: * time.Time -> datetimeoffset or datetime (TDS version dependent) * mssql.DateTime1 -> datetime * mssql.DateTimeOffset -> datetimeoffset - * "cloud.google.com/go/civil".Date -> date - * "cloud.google.com/go/civil".DateTime -> datetime2 - * "cloud.google.com/go/civil".Time -> time + * "github.com/golang-sql/civil".Date -> date + * "github.com/golang-sql/civil".DateTime -> datetime2 + * "github.com/golang-sql/civil".Time -> time * mssql.TVP -> Table Value Parameter (TDS version dependent) ## Important Notes diff --git a/vendor/github.com/denisenkom/go-mssqldb/appveyor.yml b/vendor/github.com/denisenkom/go-mssqldb/appveyor.yml index 2ae5456d5cb70..c4d2bb060eed5 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/appveyor.yml +++ b/vendor/github.com/denisenkom/go-mssqldb/appveyor.yml @@ -10,7 +10,7 @@ environment: SQLUSER: sa SQLPASSWORD: Password12! DATABASE: test - GOVERSION: 110 + GOVERSION: 111 matrix: - GOVERSION: 18 SQLINSTANCE: SQL2016 @@ -18,6 +18,8 @@ environment: SQLINSTANCE: SQL2016 - GOVERSION: 110 SQLINSTANCE: SQL2016 + - GOVERSION: 111 + SQLINSTANCE: SQL2016 - SQLINSTANCE: SQL2014 - SQLINSTANCE: SQL2012SP1 - SQLINSTANCE: SQL2008R2SP2 @@ -27,7 +29,7 @@ install: - set PATH=%GOPATH%\bin;%GOROOT%\bin;%PATH% - go version - go env - - go get -u cloud.google.com/go/civil + - go get -u github.com/golang-sql/civil build_script: - go build diff --git a/vendor/github.com/denisenkom/go-mssqldb/buf.go b/vendor/github.com/denisenkom/go-mssqldb/buf.go index 927d75d1b78b4..ba39b40f173a9 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/buf.go +++ b/vendor/github.com/denisenkom/go-mssqldb/buf.go @@ -221,23 +221,27 @@ func (r *tdsBuffer) uint16() uint16 { } func (r *tdsBuffer) BVarChar() string { - l := int(r.byte()) - return r.readUcs2(l) + return readBVarCharOrPanic(r) } -func (r *tdsBuffer) UsVarChar() string { - l := int(r.uint16()) - return r.readUcs2(l) +func readBVarCharOrPanic(r io.Reader) string { + s, err := readBVarChar(r) + if err != nil { + badStreamPanic(err) + } + return s } -func (r *tdsBuffer) readUcs2(numchars int) string { - b := make([]byte, numchars*2) - r.ReadFull(b) - res, err := ucs22str(b) +func readUsVarCharOrPanic(r io.Reader) string { + s, err := readUsVarChar(r) if err != nil { badStreamPanic(err) } - return res + return s +} + +func (r *tdsBuffer) UsVarChar() string { + return readUsVarCharOrPanic(r) } func (r *tdsBuffer) Read(buf []byte) (copied int, err error) { diff --git a/vendor/github.com/denisenkom/go-mssqldb/bulkcopy.go b/vendor/github.com/denisenkom/go-mssqldb/bulkcopy.go index 3b319af893fd3..1d5eacb381844 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/bulkcopy.go +++ b/vendor/github.com/denisenkom/go-mssqldb/bulkcopy.go @@ -7,9 +7,10 @@ import ( "fmt" "math" "reflect" - "strconv" "strings" "time" + + "github.com/denisenkom/go-mssqldb/internal/decimal" ) type Bulk struct { @@ -42,6 +43,11 @@ type BulkOptions struct { type DataValue interface{} +const ( + sqlDateFormat = "2006-01-02" + sqlTimeFormat = "2006-01-02 15:04:05.999999999Z07:00" +) + func (cn *Conn) CreateBulk(table string, columns []string) (_ *Bulk) { b := Bulk{ctx: context.Background(), cn: cn, tablename: table, headerSent: false, columnsName: columns} b.Debug = false @@ -334,7 +340,7 @@ func (b *Bulk) makeParam(val DataValue, col columnStruct) (res param, err error) case int64: intvalue = val default: - err = fmt.Errorf("mssql: invalid type for int column") + err = fmt.Errorf("mssql: invalid type for int column: %T", val) return } @@ -361,7 +367,7 @@ func (b *Bulk) makeParam(val DataValue, col columnStruct) (res param, err error) case int64: floatvalue = float64(val) default: - err = fmt.Errorf("mssql: invalid type for float column: %s", val) + err = fmt.Errorf("mssql: invalid type for float column: %T %s", val, val) return } @@ -380,7 +386,7 @@ func (b *Bulk) makeParam(val DataValue, col columnStruct) (res param, err error) case []byte: res.buffer = val default: - err = fmt.Errorf("mssql: invalid type for nvarchar column: %s", val) + err = fmt.Errorf("mssql: invalid type for nvarchar column: %T %s", val, val) return } res.ti.Size = len(res.buffer) @@ -392,14 +398,14 @@ func (b *Bulk) makeParam(val DataValue, col columnStruct) (res param, err error) case []byte: res.buffer = val default: - err = fmt.Errorf("mssql: invalid type for varchar column: %s", val) + err = fmt.Errorf("mssql: invalid type for varchar column: %T %s", val, val) return } res.ti.Size = len(res.buffer) case typeBit, typeBitN: if reflect.TypeOf(val).Kind() != reflect.Bool { - err = fmt.Errorf("mssql: invalid type for bit column: %s", val) + err = fmt.Errorf("mssql: invalid type for bit column: %T %s", val, val) return } res.ti.TypeId = typeBitN @@ -413,18 +419,31 @@ func (b *Bulk) makeParam(val DataValue, col columnStruct) (res param, err error) case time.Time: res.buffer = encodeDateTime2(val, int(col.ti.Scale)) res.ti.Size = len(res.buffer) + case string: + var t time.Time + if t, err = time.Parse(sqlTimeFormat, val); err != nil { + return res, fmt.Errorf("bulk: unable to convert string to date: %v", err) + } + res.buffer = encodeDateTime2(t, int(col.ti.Scale)) + res.ti.Size = len(res.buffer) default: - err = fmt.Errorf("mssql: invalid type for datetime2 column: %s", val) + err = fmt.Errorf("mssql: invalid type for datetime2 column: %T %s", val, val) return } case typeDateTimeOffsetN: switch val := val.(type) { case time.Time: - res.buffer = encodeDateTimeOffset(val, int(res.ti.Scale)) + res.buffer = encodeDateTimeOffset(val, int(col.ti.Scale)) + res.ti.Size = len(res.buffer) + case string: + var t time.Time + if t, err = time.Parse(sqlTimeFormat, val); err != nil { + return res, fmt.Errorf("bulk: unable to convert string to date: %v", err) + } + res.buffer = encodeDateTimeOffset(t, int(col.ti.Scale)) res.ti.Size = len(res.buffer) - default: - err = fmt.Errorf("mssql: invalid type for datetimeoffset column: %s", val) + err = fmt.Errorf("mssql: invalid type for datetimeoffset column: %T %s", val, val) return } case typeDateN: @@ -432,69 +451,79 @@ func (b *Bulk) makeParam(val DataValue, col columnStruct) (res param, err error) case time.Time: res.buffer = encodeDate(val) res.ti.Size = len(res.buffer) + case string: + var t time.Time + if t, err = time.ParseInLocation(sqlDateFormat, val, time.UTC); err != nil { + return res, fmt.Errorf("bulk: unable to convert string to date: %v", err) + } + res.buffer = encodeDate(t) + res.ti.Size = len(res.buffer) default: - err = fmt.Errorf("mssql: invalid type for date column: %s", val) + err = fmt.Errorf("mssql: invalid type for date column: %T %s", val, val) return } case typeDateTime, typeDateTimeN, typeDateTim4: + var t time.Time switch val := val.(type) { case time.Time: - if col.ti.Size == 4 { - res.buffer = encodeDateTim4(val) - res.ti.Size = len(res.buffer) - } else if col.ti.Size == 8 { - res.buffer = encodeDateTime(val) - res.ti.Size = len(res.buffer) - } else { - err = fmt.Errorf("mssql: invalid size of column") + t = val + case string: + if t, err = time.Parse(sqlTimeFormat, val); err != nil { + return res, fmt.Errorf("bulk: unable to convert string to date: %v", err) } - default: - err = fmt.Errorf("mssql: invalid type for datetime column: %s", val) + err = fmt.Errorf("mssql: invalid type for datetime column: %T %s", val, val) + return + } + + if col.ti.Size == 4 { + res.buffer = encodeDateTim4(t) + res.ti.Size = len(res.buffer) + } else if col.ti.Size == 8 { + res.buffer = encodeDateTime(t) + res.ti.Size = len(res.buffer) + } else { + err = fmt.Errorf("mssql: invalid size of column %d", col.ti.Size) } // case typeMoney, typeMoney4, typeMoneyN: case typeDecimal, typeDecimalN, typeNumeric, typeNumericN: - var value float64 + prec := col.ti.Prec + scale := col.ti.Scale + var dec decimal.Decimal switch v := val.(type) { case int: - value = float64(v) + dec = decimal.Int64ToDecimalScale(int64(v), 0) case int8: - value = float64(v) + dec = decimal.Int64ToDecimalScale(int64(v), 0) case int16: - value = float64(v) + dec = decimal.Int64ToDecimalScale(int64(v), 0) case int32: - value = float64(v) + dec = decimal.Int64ToDecimalScale(int64(v), 0) case int64: - value = float64(v) + dec = decimal.Int64ToDecimalScale(int64(v), 0) case float32: - value = float64(v) + dec, err = decimal.Float64ToDecimalScale(float64(v), scale) case float64: - value = v + dec, err = decimal.Float64ToDecimalScale(float64(v), scale) case string: - if value, err = strconv.ParseFloat(v, 64); err != nil { - return res, fmt.Errorf("bulk: unable to convert string to float: %v", err) - } + dec, err = decimal.StringToDecimalScale(v, scale) default: - return res, fmt.Errorf("unknown value for decimal: %#v", v) + return res, fmt.Errorf("unknown value for decimal: %T %#v", v, v) } - perc := col.ti.Prec - scale := col.ti.Scale - var dec Decimal - dec, err = Float64ToDecimalScale(value, scale) if err != nil { return res, err } - dec.prec = perc + dec.SetPrec(prec) var length byte switch { - case perc <= 9: + case prec <= 9: length = 4 - case perc <= 19: + case prec <= 19: length = 8 - case perc <= 28: + case prec <= 28: length = 12 default: length = 16 @@ -504,7 +533,7 @@ func (b *Bulk) makeParam(val DataValue, col columnStruct) (res param, err error) // first byte length written by typeInfo.writer res.ti.Size = int(length) + 1 // second byte sign - if value < 0 { + if !dec.IsPositive() { buf[0] = 0 } else { buf[0] = 1 @@ -527,7 +556,7 @@ func (b *Bulk) makeParam(val DataValue, col columnStruct) (res param, err error) res.ti.Size = len(val) res.buffer = val default: - err = fmt.Errorf("mssql: invalid type for Binary column: %s", val) + err = fmt.Errorf("mssql: invalid type for Binary column: %T %s", val, val) return } case typeGuid: @@ -536,7 +565,7 @@ func (b *Bulk) makeParam(val DataValue, col columnStruct) (res param, err error) res.ti.Size = len(val) res.buffer = val default: - err = fmt.Errorf("mssql: invalid type for Guid column: %s", val) + err = fmt.Errorf("mssql: invalid type for Guid column: %T %s", val, val) return } diff --git a/vendor/github.com/denisenkom/go-mssqldb/conn_str.go b/vendor/github.com/denisenkom/go-mssqldb/conn_str.go new file mode 100644 index 0000000000000..412a8716adb5c --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/conn_str.go @@ -0,0 +1,453 @@ +package mssql + +import ( + "fmt" + "net" + "net/url" + "os" + "strconv" + "strings" + "time" + "unicode" +) + +type connectParams struct { + logFlags uint64 + port uint64 + host string + instance string + database string + user string + password string + dial_timeout time.Duration + conn_timeout time.Duration + keepAlive time.Duration + encrypt bool + disableEncryption bool + trustServerCertificate bool + certificate string + hostInCertificate string + hostInCertificateProvided bool + serverSPN string + workstation string + appname string + typeFlags uint8 + failOverPartner string + failOverPort uint64 + packetSize uint16 +} + +func parseConnectParams(dsn string) (connectParams, error) { + var p connectParams + + var params map[string]string + if strings.HasPrefix(dsn, "odbc:") { + parameters, err := splitConnectionStringOdbc(dsn[len("odbc:"):]) + if err != nil { + return p, err + } + params = parameters + } else if strings.HasPrefix(dsn, "sqlserver://") { + parameters, err := splitConnectionStringURL(dsn) + if err != nil { + return p, err + } + params = parameters + } else { + params = splitConnectionString(dsn) + } + + strlog, ok := params["log"] + if ok { + var err error + p.logFlags, err = strconv.ParseUint(strlog, 10, 64) + if err != nil { + return p, fmt.Errorf("Invalid log parameter '%s': %s", strlog, err.Error()) + } + } + server := params["server"] + parts := strings.SplitN(server, `\`, 2) + p.host = parts[0] + if p.host == "." || strings.ToUpper(p.host) == "(LOCAL)" || p.host == "" { + p.host = "localhost" + } + if len(parts) > 1 { + p.instance = parts[1] + } + p.database = params["database"] + p.user = params["user id"] + p.password = params["password"] + + p.port = 1433 + strport, ok := params["port"] + if ok { + var err error + p.port, err = strconv.ParseUint(strport, 10, 16) + if err != nil { + f := "Invalid tcp port '%v': %v" + return p, fmt.Errorf(f, strport, err.Error()) + } + } + + // https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/configure-the-network-packet-size-server-configuration-option + // Default packet size remains at 4096 bytes + p.packetSize = 4096 + strpsize, ok := params["packet size"] + if ok { + var err error + psize, err := strconv.ParseUint(strpsize, 0, 16) + if err != nil { + f := "Invalid packet size '%v': %v" + return p, fmt.Errorf(f, strpsize, err.Error()) + } + + // Ensure packet size falls within the TDS protocol range of 512 to 32767 bytes + // NOTE: Encrypted connections have a maximum size of 16383 bytes. If you request + // a higher packet size, the server will respond with an ENVCHANGE request to + // alter the packet size to 16383 bytes. + p.packetSize = uint16(psize) + if p.packetSize < 512 { + p.packetSize = 512 + } else if p.packetSize > 32767 { + p.packetSize = 32767 + } + } + + // https://msdn.microsoft.com/en-us/library/dd341108.aspx + // + // Do not set a connection timeout. Use Context to manage such things. + // Default to zero, but still allow it to be set. + if strconntimeout, ok := params["connection timeout"]; ok { + timeout, err := strconv.ParseUint(strconntimeout, 10, 64) + if err != nil { + f := "Invalid connection timeout '%v': %v" + return p, fmt.Errorf(f, strconntimeout, err.Error()) + } + p.conn_timeout = time.Duration(timeout) * time.Second + } + p.dial_timeout = 15 * time.Second + if strdialtimeout, ok := params["dial timeout"]; ok { + timeout, err := strconv.ParseUint(strdialtimeout, 10, 64) + if err != nil { + f := "Invalid dial timeout '%v': %v" + return p, fmt.Errorf(f, strdialtimeout, err.Error()) + } + p.dial_timeout = time.Duration(timeout) * time.Second + } + + // default keep alive should be 30 seconds according to spec: + // https://msdn.microsoft.com/en-us/library/dd341108.aspx + p.keepAlive = 30 * time.Second + if keepAlive, ok := params["keepalive"]; ok { + timeout, err := strconv.ParseUint(keepAlive, 10, 64) + if err != nil { + f := "Invalid keepAlive value '%s': %s" + return p, fmt.Errorf(f, keepAlive, err.Error()) + } + p.keepAlive = time.Duration(timeout) * time.Second + } + encrypt, ok := params["encrypt"] + if ok { + if strings.EqualFold(encrypt, "DISABLE") { + p.disableEncryption = true + } else { + var err error + p.encrypt, err = strconv.ParseBool(encrypt) + if err != nil { + f := "Invalid encrypt '%s': %s" + return p, fmt.Errorf(f, encrypt, err.Error()) + } + } + } else { + p.trustServerCertificate = true + } + trust, ok := params["trustservercertificate"] + if ok { + var err error + p.trustServerCertificate, err = strconv.ParseBool(trust) + if err != nil { + f := "Invalid trust server certificate '%s': %s" + return p, fmt.Errorf(f, trust, err.Error()) + } + } + p.certificate = params["certificate"] + p.hostInCertificate, ok = params["hostnameincertificate"] + if ok { + p.hostInCertificateProvided = true + } else { + p.hostInCertificate = p.host + p.hostInCertificateProvided = false + } + + serverSPN, ok := params["serverspn"] + if ok { + p.serverSPN = serverSPN + } else { + p.serverSPN = fmt.Sprintf("MSSQLSvc/%s:%d", p.host, p.port) + } + + workstation, ok := params["workstation id"] + if ok { + p.workstation = workstation + } else { + workstation, err := os.Hostname() + if err == nil { + p.workstation = workstation + } + } + + appname, ok := params["app name"] + if !ok { + appname = "go-mssqldb" + } + p.appname = appname + + appintent, ok := params["applicationintent"] + if ok { + if appintent == "ReadOnly" { + p.typeFlags |= fReadOnlyIntent + } + } + + failOverPartner, ok := params["failoverpartner"] + if ok { + p.failOverPartner = failOverPartner + } + + failOverPort, ok := params["failoverport"] + if ok { + var err error + p.failOverPort, err = strconv.ParseUint(failOverPort, 0, 16) + if err != nil { + f := "Invalid tcp port '%v': %v" + return p, fmt.Errorf(f, failOverPort, err.Error()) + } + } + + return p, nil +} + +func splitConnectionString(dsn string) (res map[string]string) { + res = map[string]string{} + parts := strings.Split(dsn, ";") + for _, part := range parts { + if len(part) == 0 { + continue + } + lst := strings.SplitN(part, "=", 2) + name := strings.TrimSpace(strings.ToLower(lst[0])) + if len(name) == 0 { + continue + } + var value string = "" + if len(lst) > 1 { + value = strings.TrimSpace(lst[1]) + } + res[name] = value + } + return res +} + +// Splits a URL of the form sqlserver://username:password@host/instance?param1=value¶m2=value +func splitConnectionStringURL(dsn string) (map[string]string, error) { + res := map[string]string{} + + u, err := url.Parse(dsn) + if err != nil { + return res, err + } + + if u.Scheme != "sqlserver" { + return res, fmt.Errorf("scheme %s is not recognized", u.Scheme) + } + + if u.User != nil { + res["user id"] = u.User.Username() + p, exists := u.User.Password() + if exists { + res["password"] = p + } + } + + host, port, err := net.SplitHostPort(u.Host) + if err != nil { + host = u.Host + } + + if len(u.Path) > 0 { + res["server"] = host + "\\" + u.Path[1:] + } else { + res["server"] = host + } + + if len(port) > 0 { + res["port"] = port + } + + query := u.Query() + for k, v := range query { + if len(v) > 1 { + return res, fmt.Errorf("key %s provided more than once", k) + } + res[strings.ToLower(k)] = v[0] + } + + return res, nil +} + +// Splits a URL in the ODBC format +func splitConnectionStringOdbc(dsn string) (map[string]string, error) { + res := map[string]string{} + + type parserState int + const ( + // Before the start of a key + parserStateBeforeKey parserState = iota + + // Inside a key + parserStateKey + + // Beginning of a value. May be bare or braced + parserStateBeginValue + + // Inside a bare value + parserStateBareValue + + // Inside a braced value + parserStateBracedValue + + // A closing brace inside a braced value. + // May be the end of the value or an escaped closing brace, depending on the next character + parserStateBracedValueClosingBrace + + // After a value. Next character should be a semicolon or whitespace. + parserStateEndValue + ) + + var state = parserStateBeforeKey + + var key string + var value string + + for i, c := range dsn { + switch state { + case parserStateBeforeKey: + switch { + case c == '=': + return res, fmt.Errorf("Unexpected character = at index %d. Expected start of key or semi-colon or whitespace.", i) + case !unicode.IsSpace(c) && c != ';': + state = parserStateKey + key += string(c) + } + + case parserStateKey: + switch c { + case '=': + key = normalizeOdbcKey(key) + state = parserStateBeginValue + + case ';': + // Key without value + key = normalizeOdbcKey(key) + res[key] = value + key = "" + value = "" + state = parserStateBeforeKey + + default: + key += string(c) + } + + case parserStateBeginValue: + switch { + case c == '{': + state = parserStateBracedValue + case c == ';': + // Empty value + res[key] = value + key = "" + state = parserStateBeforeKey + case unicode.IsSpace(c): + // Ignore whitespace + default: + state = parserStateBareValue + value += string(c) + } + + case parserStateBareValue: + if c == ';' { + res[key] = strings.TrimRightFunc(value, unicode.IsSpace) + key = "" + value = "" + state = parserStateBeforeKey + } else { + value += string(c) + } + + case parserStateBracedValue: + if c == '}' { + state = parserStateBracedValueClosingBrace + } else { + value += string(c) + } + + case parserStateBracedValueClosingBrace: + if c == '}' { + // Escaped closing brace + value += string(c) + state = parserStateBracedValue + continue + } + + // End of braced value + res[key] = value + key = "" + value = "" + + // This character is the first character past the end, + // so it needs to be parsed like the parserStateEndValue state. + state = parserStateEndValue + switch { + case c == ';': + state = parserStateBeforeKey + case unicode.IsSpace(c): + // Ignore whitespace + default: + return res, fmt.Errorf("Unexpected character %c at index %d. Expected semi-colon or whitespace.", c, i) + } + + case parserStateEndValue: + switch { + case c == ';': + state = parserStateBeforeKey + case unicode.IsSpace(c): + // Ignore whitespace + default: + return res, fmt.Errorf("Unexpected character %c at index %d. Expected semi-colon or whitespace.", c, i) + } + } + } + + switch state { + case parserStateBeforeKey: // Okay + case parserStateKey: // Unfinished key. Treat as key without value. + key = normalizeOdbcKey(key) + res[key] = value + case parserStateBeginValue: // Empty value + res[key] = value + case parserStateBareValue: + res[key] = strings.TrimRightFunc(value, unicode.IsSpace) + case parserStateBracedValue: + return res, fmt.Errorf("Unexpected end of braced value at index %d.", len(dsn)) + case parserStateBracedValueClosingBrace: // End of braced value + res[key] = value + case parserStateEndValue: // Okay + } + + return res, nil +} + +// Normalizes the given string as an ODBC-format key +func normalizeOdbcKey(s string) string { + return strings.ToLower(strings.TrimRightFunc(s, unicode.IsSpace)) +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/decimal.go b/vendor/github.com/denisenkom/go-mssqldb/decimal.go deleted file mode 100644 index 372f64b4eb148..0000000000000 --- a/vendor/github.com/denisenkom/go-mssqldb/decimal.go +++ /dev/null @@ -1,131 +0,0 @@ -package mssql - -import ( - "encoding/binary" - "errors" - "math" - "math/big" -) - -// http://msdn.microsoft.com/en-us/library/ee780893.aspx -type Decimal struct { - integer [4]uint32 - positive bool - prec uint8 - scale uint8 -} - -var scaletblflt64 [39]float64 - -func (d Decimal) ToFloat64() float64 { - val := float64(0) - for i := 3; i >= 0; i-- { - val *= 0x100000000 - val += float64(d.integer[i]) - } - if !d.positive { - val = -val - } - if d.scale != 0 { - val /= scaletblflt64[d.scale] - } - return val -} - -const autoScale = 100 - -func Float64ToDecimal(f float64) (Decimal, error) { - return Float64ToDecimalScale(f, autoScale) -} - -func Float64ToDecimalScale(f float64, scale uint8) (Decimal, error) { - var dec Decimal - if math.IsNaN(f) { - return dec, errors.New("NaN") - } - if math.IsInf(f, 0) { - return dec, errors.New("Infinity can't be converted to decimal") - } - dec.positive = f >= 0 - if !dec.positive { - f = math.Abs(f) - } - if f > 3.402823669209385e+38 { - return dec, errors.New("Float value is out of range") - } - dec.prec = 20 - var integer float64 - for dec.scale = 0; dec.scale <= scale; dec.scale++ { - integer = f * scaletblflt64[dec.scale] - _, frac := math.Modf(integer) - if frac == 0 && scale == autoScale { - break - } - } - for i := 0; i < 4; i++ { - mod := math.Mod(integer, 0x100000000) - integer -= mod - integer /= 0x100000000 - dec.integer[i] = uint32(mod) - } - return dec, nil -} - -func init() { - var acc float64 = 1 - for i := 0; i <= 38; i++ { - scaletblflt64[i] = acc - acc *= 10 - } -} - -func (d Decimal) BigInt() big.Int { - bytes := make([]byte, 16) - binary.BigEndian.PutUint32(bytes[0:4], d.integer[3]) - binary.BigEndian.PutUint32(bytes[4:8], d.integer[2]) - binary.BigEndian.PutUint32(bytes[8:12], d.integer[1]) - binary.BigEndian.PutUint32(bytes[12:16], d.integer[0]) - var x big.Int - x.SetBytes(bytes) - if !d.positive { - x.Neg(&x) - } - return x -} - -func (d Decimal) Bytes() []byte { - x := d.BigInt() - return scaleBytes(x.String(), d.scale) -} - -func (d Decimal) UnscaledBytes() []byte { - x := d.BigInt() - return x.Bytes() -} - -func scaleBytes(s string, scale uint8) []byte { - z := make([]byte, 0, len(s)+1) - if s[0] == '-' || s[0] == '+' { - z = append(z, byte(s[0])) - s = s[1:] - } - pos := len(s) - int(scale) - if pos <= 0 { - z = append(z, byte('0')) - } else if pos > 0 { - z = append(z, []byte(s[:pos])...) - } - if scale > 0 { - z = append(z, byte('.')) - for pos < 0 { - z = append(z, byte('0')) - pos++ - } - z = append(z, []byte(s[pos:])...) - } - return z -} - -func (d Decimal) String() string { - return string(d.Bytes()) -} diff --git a/vendor/github.com/denisenkom/go-mssqldb/go.mod b/vendor/github.com/denisenkom/go-mssqldb/go.mod index 096fc96b208ac..ebc02ab88f915 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/go.mod +++ b/vendor/github.com/denisenkom/go-mssqldb/go.mod @@ -3,8 +3,6 @@ module github.com/denisenkom/go-mssqldb go 1.11 require ( - cloud.google.com/go v0.37.4 + github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c - gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect - gopkg.in/yaml.v2 v2.2.2 // indirect ) diff --git a/vendor/github.com/denisenkom/go-mssqldb/go.sum b/vendor/github.com/denisenkom/go-mssqldb/go.sum index e1936ecf70ba3..1887801bbf408 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/go.sum +++ b/vendor/github.com/denisenkom/go-mssqldb/go.sum @@ -1,168 +1,5 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.37.2 h1:4y4L7BdHenTfZL0HervofNTHh9Ad6mNX72cQvl+5eH0= -cloud.google.com/go v0.37.2/go.mod h1:H8IAquKe2L30IxoupDgqTaQvKSwF/c8prYHynGIWQbA= -git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/grpc-ecosystem/grpc-gateway v1.6.2/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= -github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= -go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= -go.opencensus.io v0.19.1/go.mod h1:gug0GbSHa8Pafr0d2urOSgoXHZ6x/RUlaiT0d9pqb4A= -go.opencensus.io v0.19.2/go.mod h1:NO/8qkisMZLZ1FCsKNqtJPwc8/TaclWyY0B6wcYNg9M= -go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= -golang.org/x/build v0.0.0-20190314133821-5284462c4bec/go.mod h1:atTaCNAy0f16Ah5aV1gMSwgiKVHwu/JncqDpuRr7lS4= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181218192612-074acd46bca6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181219222714-6e267b5cc78e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.0.0-20181220000619-583d854617af/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.2.0/go.mod h1:IfRCZScioGtypHNTlz3gFk67J8uePVW7uDTBzXuIkhU= -google.golang.org/api v0.3.0/go.mod h1:IuvZyQh8jgscv8qWfQ4ABd8m7hEudgBFM/EdhA3BnXw= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181219182458-5a97ab628bfb/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/decimal/decimal.go b/vendor/github.com/denisenkom/go-mssqldb/internal/decimal/decimal.go new file mode 100644 index 0000000000000..7da0375d91dbb --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/decimal/decimal.go @@ -0,0 +1,252 @@ +package decimal + +import ( + "encoding/binary" + "errors" + "fmt" + "math" + "math/big" + "strings" +) + +// Decimal represents decimal type in the Microsoft Open Specifications: http://msdn.microsoft.com/en-us/library/ee780893.aspx +type Decimal struct { + integer [4]uint32 // Little-endian + positive bool + prec uint8 + scale uint8 +} + +var ( + scaletblflt64 [39]float64 + int10 big.Int + int1e5 big.Int +) + +func init() { + var acc float64 = 1 + for i := 0; i <= 38; i++ { + scaletblflt64[i] = acc + acc *= 10 + } + + int10.SetInt64(10) + int1e5.SetInt64(1e5) +} + +const autoScale = 100 + +// SetInteger sets the ind'th element in the integer array +func (d *Decimal) SetInteger(integer uint32, ind uint8) { + d.integer[ind] = integer +} + +// SetPositive sets the positive member +func (d *Decimal) SetPositive(positive bool) { + d.positive = positive +} + +// SetPrec sets the prec member +func (d *Decimal) SetPrec(prec uint8) { + d.prec = prec +} + +// SetScale sets the scale member +func (d *Decimal) SetScale(scale uint8) { + d.scale = scale +} + +// IsPositive returns true if the Decimal is positive +func (d *Decimal) IsPositive() bool { + return d.positive +} + +// ToFloat64 converts decimal to a float64 +func (d Decimal) ToFloat64() float64 { + val := float64(0) + for i := 3; i >= 0; i-- { + val *= 0x100000000 + val += float64(d.integer[i]) + } + if !d.positive { + val = -val + } + if d.scale != 0 { + val /= scaletblflt64[d.scale] + } + return val +} + +// BigInt converts decimal to a bigint +func (d Decimal) BigInt() big.Int { + bytes := make([]byte, 16) + binary.BigEndian.PutUint32(bytes[0:4], d.integer[3]) + binary.BigEndian.PutUint32(bytes[4:8], d.integer[2]) + binary.BigEndian.PutUint32(bytes[8:12], d.integer[1]) + binary.BigEndian.PutUint32(bytes[12:16], d.integer[0]) + var x big.Int + x.SetBytes(bytes) + if !d.positive { + x.Neg(&x) + } + return x +} + +// Bytes converts decimal to a scaled byte slice +func (d Decimal) Bytes() []byte { + x := d.BigInt() + return ScaleBytes(x.String(), d.scale) +} + +// UnscaledBytes converts decimal to a unscaled byte slice +func (d Decimal) UnscaledBytes() []byte { + x := d.BigInt() + return x.Bytes() +} + +// String converts decimal to a string +func (d Decimal) String() string { + return string(d.Bytes()) +} + +// Float64ToDecimal converts float64 to decimal +func Float64ToDecimal(f float64) (Decimal, error) { + return Float64ToDecimalScale(f, autoScale) +} + +// Float64ToDecimalScale converts float64 to decimal; user can specify the scale +func Float64ToDecimalScale(f float64, scale uint8) (Decimal, error) { + var dec Decimal + if math.IsNaN(f) { + return dec, errors.New("NaN") + } + if math.IsInf(f, 0) { + return dec, errors.New("Infinity can't be converted to decimal") + } + dec.positive = f >= 0 + if !dec.positive { + f = math.Abs(f) + } + if f > 3.402823669209385e+38 { + return dec, errors.New("Float value is out of range") + } + dec.prec = 20 + var integer float64 + for dec.scale = 0; dec.scale <= scale; dec.scale++ { + integer = f * scaletblflt64[dec.scale] + _, frac := math.Modf(integer) + if frac == 0 && scale == autoScale { + break + } + } + for i := 0; i < 4; i++ { + mod := math.Mod(integer, 0x100000000) + integer -= mod + integer /= 0x100000000 + dec.integer[i] = uint32(mod) + if mod-math.Trunc(mod) >= 0.5 { + dec.integer[i] = uint32(mod) + 1 + } + } + return dec, nil +} + +// Int64ToDecimalScale converts float64 to decimal; user can specify the scale +func Int64ToDecimalScale(v int64, scale uint8) Decimal { + positive := v >= 0 + if !positive { + if v == math.MinInt64 { + // Special case - can't negate + return Decimal{ + integer: [4]uint32{0, 0x80000000, 0, 0}, + positive: false, + prec: 20, + scale: 0, + } + } + v = -v + } + return Decimal{ + integer: [4]uint32{uint32(v), uint32(v >> 32), 0, 0}, + positive: positive, + prec: 20, + scale: scale, + } +} + +// StringToDecimalScale converts string to decimal +func StringToDecimalScale(v string, outScale uint8) (Decimal, error) { + var r big.Int + var unscaled string + var inScale int + + point := strings.LastIndexByte(v, '.') + if point == -1 { + inScale = 0 + unscaled = v + } else { + inScale = len(v) - point - 1 + unscaled = v[:point] + v[point+1:] + } + if inScale > math.MaxUint8 { + return Decimal{}, fmt.Errorf("can't parse %q as a decimal number: scale too large", v) + } + + _, ok := r.SetString(unscaled, 10) + if !ok { + return Decimal{}, fmt.Errorf("can't parse %q as a decimal number", v) + } + + if inScale > int(outScale) { + return Decimal{}, fmt.Errorf("can't parse %q as a decimal number: scale %d is larger than the scale %d of the target column", v, inScale, outScale) + } + for inScale < int(outScale) { + if int(outScale)-inScale >= 5 { + r.Mul(&r, &int1e5) + inScale += 5 + } else { + r.Mul(&r, &int10) + inScale++ + } + } + + bytes := r.Bytes() + if len(bytes) > 16 { + return Decimal{}, fmt.Errorf("can't parse %q as a decimal number: precision too large", v) + } + var out [4]uint32 + for i, b := range bytes { + pos := len(bytes) - i - 1 + out[pos/4] += uint32(b) << uint(pos%4*8) + } + return Decimal{ + integer: out, + positive: r.Sign() >= 0, + prec: 20, + scale: uint8(inScale), + }, nil +} + +// ScaleBytes converts a stringified decimal to a scaled byte slice +func ScaleBytes(s string, scale uint8) []byte { + z := make([]byte, 0, len(s)+1) + if s[0] == '-' || s[0] == '+' { + z = append(z, byte(s[0])) + s = s[1:] + } + pos := len(s) - int(scale) + if pos <= 0 { + z = append(z, byte('0')) + } else if pos > 0 { + z = append(z, []byte(s[:pos])...) + } + if scale > 0 { + z = append(z, byte('.')) + for pos < 0 { + z = append(z, byte('0')) + pos++ + } + z = append(z, []byte(s[pos:])...) + } + return z +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql_go19.go b/vendor/github.com/denisenkom/go-mssqldb/mssql_go19.go index 7f2295c384d78..a2bd1167ba377 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/mssql_go19.go +++ b/vendor/github.com/denisenkom/go-mssqldb/mssql_go19.go @@ -11,7 +11,7 @@ import ( "time" // "github.com/cockroachdb/apd" - "cloud.google.com/go/civil" + "github.com/golang-sql/civil" ) // Type alias provided for compatibility. diff --git a/vendor/github.com/denisenkom/go-mssqldb/net.go b/vendor/github.com/denisenkom/go-mssqldb/net.go index e3864d1a22245..94858cc74fe29 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/net.go +++ b/vendor/github.com/denisenkom/go-mssqldb/net.go @@ -9,9 +9,6 @@ import ( type timeoutConn struct { c net.Conn timeout time.Duration - buf *tdsBuffer - packetPending bool - continueRead bool } func newTimeoutConn(conn net.Conn, timeout time.Duration) *timeoutConn { @@ -22,32 +19,6 @@ func newTimeoutConn(conn net.Conn, timeout time.Duration) *timeoutConn { } func (c *timeoutConn) Read(b []byte) (n int, err error) { - if c.buf != nil { - if c.packetPending { - c.packetPending = false - err = c.buf.FinishPacket() - if err != nil { - err = fmt.Errorf("Cannot send handshake packet: %s", err.Error()) - return - } - c.continueRead = false - } - if !c.continueRead { - var packet packetType - packet, err = c.buf.BeginRead() - if err != nil { - err = fmt.Errorf("Cannot read handshake packet: %s", err.Error()) - return - } - if packet != packPrelogin { - err = fmt.Errorf("unexpected packet %d, expecting prelogin", packet) - return - } - c.continueRead = true - } - n, err = c.buf.Read(b) - return - } if c.timeout > 0 { err = c.c.SetDeadline(time.Now().Add(c.timeout)) if err != nil { @@ -58,17 +29,6 @@ func (c *timeoutConn) Read(b []byte) (n int, err error) { } func (c *timeoutConn) Write(b []byte) (n int, err error) { - if c.buf != nil { - if !c.packetPending { - c.buf.BeginPacket(packPrelogin, false) - c.packetPending = true - } - n, err = c.buf.Write(b) - if err != nil { - return - } - return - } if c.timeout > 0 { err = c.c.SetDeadline(time.Now().Add(c.timeout)) if err != nil { @@ -101,3 +61,108 @@ func (c timeoutConn) SetReadDeadline(t time.Time) error { func (c timeoutConn) SetWriteDeadline(t time.Time) error { panic("Not implemented") } + +// this connection is used during TLS Handshake +// TDS protocol requires TLS handshake messages to be sent inside TDS packets +type tlsHandshakeConn struct { + buf *tdsBuffer + packetPending bool + continueRead bool +} + +func (c *tlsHandshakeConn) Read(b []byte) (n int, err error) { + if c.packetPending { + c.packetPending = false + err = c.buf.FinishPacket() + if err != nil { + err = fmt.Errorf("Cannot send handshake packet: %s", err.Error()) + return + } + c.continueRead = false + } + if !c.continueRead { + var packet packetType + packet, err = c.buf.BeginRead() + if err != nil { + err = fmt.Errorf("Cannot read handshake packet: %s", err.Error()) + return + } + if packet != packPrelogin { + err = fmt.Errorf("unexpected packet %d, expecting prelogin", packet) + return + } + c.continueRead = true + } + return c.buf.Read(b) +} + +func (c *tlsHandshakeConn) Write(b []byte) (n int, err error) { + if !c.packetPending { + c.buf.BeginPacket(packPrelogin, false) + c.packetPending = true + } + return c.buf.Write(b) +} + +func (c *tlsHandshakeConn) Close() error { + panic("Not implemented") +} + +func (c *tlsHandshakeConn) LocalAddr() net.Addr { + panic("Not implemented") +} + +func (c *tlsHandshakeConn) RemoteAddr() net.Addr { + panic("Not implemented") +} + +func (c *tlsHandshakeConn) SetDeadline(t time.Time) error { + panic("Not implemented") +} + +func (c *tlsHandshakeConn) SetReadDeadline(t time.Time) error { + panic("Not implemented") +} + +func (c *tlsHandshakeConn) SetWriteDeadline(t time.Time) error { + panic("Not implemented") +} + +// this connection just delegates all methods to it's wrapped connection +// it also allows switching underlying connection on the fly +// it is needed because tls.Conn does not allow switching underlying connection +type passthroughConn struct { + c net.Conn +} + +func (c passthroughConn) Read(b []byte) (n int, err error) { + return c.c.Read(b) +} + +func (c passthroughConn) Write(b []byte) (n int, err error) { + return c.c.Write(b) +} + +func (c passthroughConn) Close() error { + return c.c.Close() +} + +func (c passthroughConn) LocalAddr() net.Addr { + panic("Not implemented") +} + +func (c passthroughConn) RemoteAddr() net.Addr { + panic("Not implemented") +} + +func (c passthroughConn) SetDeadline(t time.Time) error { + panic("Not implemented") +} + +func (c passthroughConn) SetReadDeadline(t time.Time) error { + panic("Not implemented") +} + +func (c passthroughConn) SetWriteDeadline(t time.Time) error { + panic("Not implemented") +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/tds.go b/vendor/github.com/denisenkom/go-mssqldb/tds.go index a924e90109be7..5a9f53b705dea 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/tds.go +++ b/vendor/github.com/denisenkom/go-mssqldb/tds.go @@ -10,13 +10,9 @@ import ( "io" "io/ioutil" "net" - "net/url" - "os" "sort" "strconv" "strings" - "time" - "unicode" "unicode/utf16" "unicode/utf8" ) @@ -51,15 +47,13 @@ func parseInstances(msg []byte) map[string]map[string]string { } func getInstances(ctx context.Context, d Dialer, address string) (map[string]map[string]string, error) { - maxTime := 5 * time.Second - ctx, cancel := context.WithTimeout(ctx, maxTime) - defer cancel() conn, err := d.DialContext(ctx, "udp", address+":1434") if err != nil { return nil, err } defer conn.Close() - conn.SetDeadline(time.Now().Add(maxTime)) + deadline, _ := ctx.Deadline() + conn.SetDeadline(deadline) _, err = conn.Write([]byte{3}) if err != nil { return nil, err @@ -474,10 +468,9 @@ func readUcs2(r io.Reader, numchars int) (res string, err error) { } func readUsVarChar(r io.Reader) (res string, err error) { - var numchars uint16 - err = binary.Read(r, binary.LittleEndian, &numchars) + numchars, err := readUshort(r) if err != nil { - return "", err + return } return readUcs2(r, int(numchars)) } @@ -497,8 +490,7 @@ func writeUsVarChar(w io.Writer, s string) (err error) { } func readBVarChar(r io.Reader) (res string, err error) { - var numchars uint8 - err = binary.Read(r, binary.LittleEndian, &numchars) + numchars, err := readByte(r) if err != nil { return "", err } @@ -525,8 +517,7 @@ func writeBVarChar(w io.Writer, s string) (err error) { } func readBVarByte(r io.Reader) (res []byte, err error) { - var length uint8 - err = binary.Read(r, binary.LittleEndian, &length) + length, err := readByte(r) if err != nil { return } @@ -654,458 +645,6 @@ func sendAttention(buf *tdsBuffer) error { return buf.FinishPacket() } -type connectParams struct { - logFlags uint64 - port uint64 - host string - instance string - database string - user string - password string - dial_timeout time.Duration - conn_timeout time.Duration - keepAlive time.Duration - encrypt bool - disableEncryption bool - trustServerCertificate bool - certificate string - hostInCertificate string - hostInCertificateProvided bool - serverSPN string - workstation string - appname string - typeFlags uint8 - failOverPartner string - failOverPort uint64 - packetSize uint16 -} - -func splitConnectionString(dsn string) (res map[string]string) { - res = map[string]string{} - parts := strings.Split(dsn, ";") - for _, part := range parts { - if len(part) == 0 { - continue - } - lst := strings.SplitN(part, "=", 2) - name := strings.TrimSpace(strings.ToLower(lst[0])) - if len(name) == 0 { - continue - } - var value string = "" - if len(lst) > 1 { - value = strings.TrimSpace(lst[1]) - } - res[name] = value - } - return res -} - -// Splits a URL in the ODBC format -func splitConnectionStringOdbc(dsn string) (map[string]string, error) { - res := map[string]string{} - - type parserState int - const ( - // Before the start of a key - parserStateBeforeKey parserState = iota - - // Inside a key - parserStateKey - - // Beginning of a value. May be bare or braced - parserStateBeginValue - - // Inside a bare value - parserStateBareValue - - // Inside a braced value - parserStateBracedValue - - // A closing brace inside a braced value. - // May be the end of the value or an escaped closing brace, depending on the next character - parserStateBracedValueClosingBrace - - // After a value. Next character should be a semicolon or whitespace. - parserStateEndValue - ) - - var state = parserStateBeforeKey - - var key string - var value string - - for i, c := range dsn { - switch state { - case parserStateBeforeKey: - switch { - case c == '=': - return res, fmt.Errorf("Unexpected character = at index %d. Expected start of key or semi-colon or whitespace.", i) - case !unicode.IsSpace(c) && c != ';': - state = parserStateKey - key += string(c) - } - - case parserStateKey: - switch c { - case '=': - key = normalizeOdbcKey(key) - if len(key) == 0 { - return res, fmt.Errorf("Unexpected end of key at index %d.", i) - } - - state = parserStateBeginValue - - case ';': - // Key without value - key = normalizeOdbcKey(key) - if len(key) == 0 { - return res, fmt.Errorf("Unexpected end of key at index %d.", i) - } - - res[key] = value - key = "" - value = "" - state = parserStateBeforeKey - - default: - key += string(c) - } - - case parserStateBeginValue: - switch { - case c == '{': - state = parserStateBracedValue - case c == ';': - // Empty value - res[key] = value - key = "" - state = parserStateBeforeKey - case unicode.IsSpace(c): - // Ignore whitespace - default: - state = parserStateBareValue - value += string(c) - } - - case parserStateBareValue: - if c == ';' { - res[key] = strings.TrimRightFunc(value, unicode.IsSpace) - key = "" - value = "" - state = parserStateBeforeKey - } else { - value += string(c) - } - - case parserStateBracedValue: - if c == '}' { - state = parserStateBracedValueClosingBrace - } else { - value += string(c) - } - - case parserStateBracedValueClosingBrace: - if c == '}' { - // Escaped closing brace - value += string(c) - state = parserStateBracedValue - continue - } - - // End of braced value - res[key] = value - key = "" - value = "" - - // This character is the first character past the end, - // so it needs to be parsed like the parserStateEndValue state. - state = parserStateEndValue - switch { - case c == ';': - state = parserStateBeforeKey - case unicode.IsSpace(c): - // Ignore whitespace - default: - return res, fmt.Errorf("Unexpected character %c at index %d. Expected semi-colon or whitespace.", c, i) - } - - case parserStateEndValue: - switch { - case c == ';': - state = parserStateBeforeKey - case unicode.IsSpace(c): - // Ignore whitespace - default: - return res, fmt.Errorf("Unexpected character %c at index %d. Expected semi-colon or whitespace.", c, i) - } - } - } - - switch state { - case parserStateBeforeKey: // Okay - case parserStateKey: // Unfinished key. Treat as key without value. - key = normalizeOdbcKey(key) - if len(key) == 0 { - return res, fmt.Errorf("Unexpected end of key at index %d.", len(dsn)) - } - res[key] = value - case parserStateBeginValue: // Empty value - res[key] = value - case parserStateBareValue: - res[key] = strings.TrimRightFunc(value, unicode.IsSpace) - case parserStateBracedValue: - return res, fmt.Errorf("Unexpected end of braced value at index %d.", len(dsn)) - case parserStateBracedValueClosingBrace: // End of braced value - res[key] = value - case parserStateEndValue: // Okay - } - - return res, nil -} - -// Normalizes the given string as an ODBC-format key -func normalizeOdbcKey(s string) string { - return strings.ToLower(strings.TrimRightFunc(s, unicode.IsSpace)) -} - -// Splits a URL of the form sqlserver://username:password@host/instance?param1=value¶m2=value -func splitConnectionStringURL(dsn string) (map[string]string, error) { - res := map[string]string{} - - u, err := url.Parse(dsn) - if err != nil { - return res, err - } - - if u.Scheme != "sqlserver" { - return res, fmt.Errorf("scheme %s is not recognized", u.Scheme) - } - - if u.User != nil { - res["user id"] = u.User.Username() - p, exists := u.User.Password() - if exists { - res["password"] = p - } - } - - host, port, err := net.SplitHostPort(u.Host) - if err != nil { - host = u.Host - } - - if len(u.Path) > 0 { - res["server"] = host + "\\" + u.Path[1:] - } else { - res["server"] = host - } - - if len(port) > 0 { - res["port"] = port - } - - query := u.Query() - for k, v := range query { - if len(v) > 1 { - return res, fmt.Errorf("key %s provided more than once", k) - } - res[strings.ToLower(k)] = v[0] - } - - return res, nil -} - -func parseConnectParams(dsn string) (connectParams, error) { - var p connectParams - - var params map[string]string - if strings.HasPrefix(dsn, "odbc:") { - parameters, err := splitConnectionStringOdbc(dsn[len("odbc:"):]) - if err != nil { - return p, err - } - params = parameters - } else if strings.HasPrefix(dsn, "sqlserver://") { - parameters, err := splitConnectionStringURL(dsn) - if err != nil { - return p, err - } - params = parameters - } else { - params = splitConnectionString(dsn) - } - - strlog, ok := params["log"] - if ok { - var err error - p.logFlags, err = strconv.ParseUint(strlog, 10, 64) - if err != nil { - return p, fmt.Errorf("Invalid log parameter '%s': %s", strlog, err.Error()) - } - } - server := params["server"] - parts := strings.SplitN(server, `\`, 2) - p.host = parts[0] - if p.host == "." || strings.ToUpper(p.host) == "(LOCAL)" || p.host == "" { - p.host = "localhost" - } - if len(parts) > 1 { - p.instance = parts[1] - } - p.database = params["database"] - p.user = params["user id"] - p.password = params["password"] - - p.port = 1433 - strport, ok := params["port"] - if ok { - var err error - p.port, err = strconv.ParseUint(strport, 10, 16) - if err != nil { - f := "Invalid tcp port '%v': %v" - return p, fmt.Errorf(f, strport, err.Error()) - } - } - - // https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/configure-the-network-packet-size-server-configuration-option - // Default packet size remains at 4096 bytes - p.packetSize = 4096 - strpsize, ok := params["packet size"] - if ok { - var err error - psize, err := strconv.ParseUint(strpsize, 0, 16) - if err != nil { - f := "Invalid packet size '%v': %v" - return p, fmt.Errorf(f, strpsize, err.Error()) - } - - // Ensure packet size falls within the TDS protocol range of 512 to 32767 bytes - // NOTE: Encrypted connections have a maximum size of 16383 bytes. If you request - // a higher packet size, the server will respond with an ENVCHANGE request to - // alter the packet size to 16383 bytes. - p.packetSize = uint16(psize) - if p.packetSize < 512 { - p.packetSize = 512 - } else if p.packetSize > 32767 { - p.packetSize = 32767 - } - } - - // https://msdn.microsoft.com/en-us/library/dd341108.aspx - // - // Do not set a connection timeout. Use Context to manage such things. - // Default to zero, but still allow it to be set. - if strconntimeout, ok := params["connection timeout"]; ok { - timeout, err := strconv.ParseUint(strconntimeout, 10, 64) - if err != nil { - f := "Invalid connection timeout '%v': %v" - return p, fmt.Errorf(f, strconntimeout, err.Error()) - } - p.conn_timeout = time.Duration(timeout) * time.Second - } - p.dial_timeout = 15 * time.Second - if strdialtimeout, ok := params["dial timeout"]; ok { - timeout, err := strconv.ParseUint(strdialtimeout, 10, 64) - if err != nil { - f := "Invalid dial timeout '%v': %v" - return p, fmt.Errorf(f, strdialtimeout, err.Error()) - } - p.dial_timeout = time.Duration(timeout) * time.Second - } - - // default keep alive should be 30 seconds according to spec: - // https://msdn.microsoft.com/en-us/library/dd341108.aspx - p.keepAlive = 30 * time.Second - if keepAlive, ok := params["keepalive"]; ok { - timeout, err := strconv.ParseUint(keepAlive, 10, 64) - if err != nil { - f := "Invalid keepAlive value '%s': %s" - return p, fmt.Errorf(f, keepAlive, err.Error()) - } - p.keepAlive = time.Duration(timeout) * time.Second - } - encrypt, ok := params["encrypt"] - if ok { - if strings.EqualFold(encrypt, "DISABLE") { - p.disableEncryption = true - } else { - var err error - p.encrypt, err = strconv.ParseBool(encrypt) - if err != nil { - f := "Invalid encrypt '%s': %s" - return p, fmt.Errorf(f, encrypt, err.Error()) - } - } - } else { - p.trustServerCertificate = true - } - trust, ok := params["trustservercertificate"] - if ok { - var err error - p.trustServerCertificate, err = strconv.ParseBool(trust) - if err != nil { - f := "Invalid trust server certificate '%s': %s" - return p, fmt.Errorf(f, trust, err.Error()) - } - } - p.certificate = params["certificate"] - p.hostInCertificate, ok = params["hostnameincertificate"] - if ok { - p.hostInCertificateProvided = true - } else { - p.hostInCertificate = p.host - p.hostInCertificateProvided = false - } - - serverSPN, ok := params["serverspn"] - if ok { - p.serverSPN = serverSPN - } else { - p.serverSPN = fmt.Sprintf("MSSQLSvc/%s:%d", p.host, p.port) - } - - workstation, ok := params["workstation id"] - if ok { - p.workstation = workstation - } else { - workstation, err := os.Hostname() - if err == nil { - p.workstation = workstation - } - } - - appname, ok := params["app name"] - if !ok { - appname = "go-mssqldb" - } - p.appname = appname - - appintent, ok := params["applicationintent"] - if ok { - if appintent == "ReadOnly" { - p.typeFlags |= fReadOnlyIntent - } - } - - failOverPartner, ok := params["failoverpartner"] - if ok { - p.failOverPartner = failOverPartner - } - - failOverPort, ok := params["failoverport"] - if ok { - var err error - p.failOverPort, err = strconv.ParseUint(failOverPort, 0, 16) - if err != nil { - f := "Invalid tcp port '%v': %v" - return p, fmt.Errorf(f, failOverPort, err.Error()) - } - } - - return p, nil -} - type auth interface { InitialBytes() ([]byte, error) NextBytes([]byte) ([]byte, error) @@ -1277,12 +816,12 @@ initiate_connection: // while SQL Server seems to expect one TCP segment per encrypted TDS package. // Setting DynamicRecordSizingDisabled to true disables that algorithm and uses 16384 bytes per TLS package config.DynamicRecordSizingDisabled = true - outbuf.transport = conn - toconn.buf = outbuf - tlsConn := tls.Client(toconn, &config) + // setting up connection handler which will allow wrapping of TLS handshake packets inside TDS stream + handshakeConn := tlsHandshakeConn{buf: outbuf} + passthrough := passthroughConn{c: &handshakeConn} + tlsConn := tls.Client(&passthrough, &config) err = tlsConn.Handshake() - - toconn.buf = nil + passthrough.c = toconn outbuf.transport = tlsConn if err != nil { return nil, fmt.Errorf("TLS Handshake failed: %v", err) diff --git a/vendor/github.com/denisenkom/go-mssqldb/types.go b/vendor/github.com/denisenkom/go-mssqldb/types.go index c9f17b9e71c31..b6e7fb2b5264f 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/types.go +++ b/vendor/github.com/denisenkom/go-mssqldb/types.go @@ -11,6 +11,7 @@ import ( "time" "github.com/denisenkom/go-mssqldb/internal/cp" + "github.com/denisenkom/go-mssqldb/internal/decimal" ) // fixed-length data types @@ -818,12 +819,12 @@ func decodeMoney(buf []byte) []byte { uint64(buf[1])<<40 | uint64(buf[2])<<48 | uint64(buf[3])<<56) - return scaleBytes(strconv.FormatInt(money, 10), 4) + return decimal.ScaleBytes(strconv.FormatInt(money, 10), 4) } func decodeMoney4(buf []byte) []byte { money := int32(binary.LittleEndian.Uint32(buf[0:4])) - return scaleBytes(strconv.FormatInt(int64(money), 10), 4) + return decimal.ScaleBytes(strconv.FormatInt(int64(money), 10), 4) } func decodeGuid(buf []byte) []byte { @@ -835,15 +836,14 @@ func decodeGuid(buf []byte) []byte { func decodeDecimal(prec uint8, scale uint8, buf []byte) []byte { var sign uint8 sign = buf[0] - dec := Decimal{ - positive: sign != 0, - prec: prec, - scale: scale, - } + var dec decimal.Decimal + dec.SetPositive(sign != 0) + dec.SetPrec(prec) + dec.SetScale(scale) buf = buf[1:] l := len(buf) / 4 for i := 0; i < l; i++ { - dec.integer[i] = binary.LittleEndian.Uint32(buf[0:4]) + dec.SetInteger(binary.LittleEndian.Uint32(buf[0:4]), uint8(i)) buf = buf[4:] } return dec.Bytes() @@ -1186,7 +1186,7 @@ func makeDecl(ti typeInfo) string { case typeBigChar, typeChar: return fmt.Sprintf("char(%d)", ti.Size) case typeBigVarChar, typeVarChar: - if ti.Size > 4000 || ti.Size == 0 { + if ti.Size > 8000 || ti.Size == 0 { return fmt.Sprintf("varchar(max)") } else { return fmt.Sprintf("varchar(%d)", ti.Size) diff --git a/vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier.go b/vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier.go index c8ef3149b19f0..3ad6f8634a201 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier.go +++ b/vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier.go @@ -72,3 +72,9 @@ func (u UniqueIdentifier) Value() (driver.Value, error) { func (u UniqueIdentifier) String() string { return fmt.Sprintf("%X-%X-%X-%X-%X", u[0:4], u[4:6], u[6:8], u[8:10], u[10:]) } + +// MarshalText converts Uniqueidentifier to bytes corresponding to the stringified hexadecimal representation of the Uniqueidentifier +// e.g., "AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA" -> [65 65 65 65 65 65 65 65 45 65 65 65 65 45 65 65 65 65 45 65 65 65 65 65 65 65 65 65 65 65 65] +func (u UniqueIdentifier) MarshalText() []byte { + return []byte(u.String()) +} diff --git a/vendor/github.com/golang-sql/civil/CONTRIBUTING.md b/vendor/github.com/golang-sql/civil/CONTRIBUTING.md new file mode 100644 index 0000000000000..d0635c3ab56dd --- /dev/null +++ b/vendor/github.com/golang-sql/civil/CONTRIBUTING.md @@ -0,0 +1,73 @@ +# Contributing + +1. Sign one of the contributor license agreements below. + +#### Running + +Once you've done the necessary setup, you can run the integration tests by +running: + +``` sh +$ go test -v github.com/golang-sql/civil +``` + +## Contributor License Agreements + +Before we can accept your pull requests you'll need to sign a Contributor +License Agreement (CLA): + +- **If you are an individual writing original source code** and **you own the +intellectual property**, then you'll need to sign an [individual CLA][indvcla]. +- **If you work for a company that wants to allow you to contribute your +work**, then you'll need to sign a [corporate CLA][corpcla]. + +You can sign these electronically (just scroll to the bottom). After that, +we'll be able to accept your pull requests. + +## Contributor Code of Conduct + +As contributors and maintainers of this project, +and in the interest of fostering an open and welcoming community, +we pledge to respect all people who contribute through reporting issues, +posting feature requests, updating documentation, +submitting pull requests or patches, and other activities. + +We are committed to making participation in this project +a harassment-free experience for everyone, +regardless of level of experience, gender, gender identity and expression, +sexual orientation, disability, personal appearance, +body size, race, ethnicity, age, religion, or nationality. + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery +* Personal attacks +* Trolling or insulting/derogatory comments +* Public or private harassment +* Publishing other's private information, +such as physical or electronic +addresses, without explicit permission +* Other unethical or unprofessional conduct. + +Project maintainers have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct. +By adopting this Code of Conduct, +project maintainers commit themselves to fairly and consistently +applying these principles to every aspect of managing this project. +Project maintainers who do not follow or enforce the Code of Conduct +may be permanently removed from the project team. + +This code of conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior +may be reported by opening an issue +or contacting one or more of the project maintainers. + +This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, +available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) + +[gcloudcli]: https://developers.google.com/cloud/sdk/gcloud/ +[indvcla]: https://developers.google.com/open-source/cla/individual +[corpcla]: https://developers.google.com/open-source/cla/corporate \ No newline at end of file diff --git a/vendor/github.com/golang-sql/civil/LICENSE b/vendor/github.com/golang-sql/civil/LICENSE new file mode 100644 index 0000000000000..7a4a3ea2424c0 --- /dev/null +++ b/vendor/github.com/golang-sql/civil/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/vendor/github.com/golang-sql/civil/README.md b/vendor/github.com/golang-sql/civil/README.md new file mode 100644 index 0000000000000..3a7956ecda4fc --- /dev/null +++ b/vendor/github.com/golang-sql/civil/README.md @@ -0,0 +1,15 @@ +# Civil Date and Time + +[![GoDoc](https://godoc.org/github.com/golang-sql/civil?status.svg)](https://godoc.org/github.com/golang-sql/civil) + +Civil provides Date, Time of Day, and DateTime data types. + +While there are many uses, using specific types when working +with databases make is conceptually eaiser to understand what value +is set in the remote system. + +## Source + +This civil package was extracted and forked from `cloud.google.com/go/civil`. +As such the license and contributing requirements remain the same as that +module. diff --git a/vendor/cloud.google.com/go/civil/civil.go b/vendor/github.com/golang-sql/civil/civil.go similarity index 100% rename from vendor/cloud.google.com/go/civil/civil.go rename to vendor/github.com/golang-sql/civil/civil.go diff --git a/vendor/github.com/lafriks/xormstore/go.mod b/vendor/github.com/lafriks/xormstore/go.mod index 5f364e3bd481b..a0386f1256555 100644 --- a/vendor/github.com/lafriks/xormstore/go.mod +++ b/vendor/github.com/lafriks/xormstore/go.mod @@ -3,18 +3,18 @@ module github.com/lafriks/xormstore go 1.11 require ( - cloud.google.com/go v0.44.3 // indirect - github.com/denisenkom/go-mssqldb v0.0.0-20190820223206-44cdfe8d8ba9 + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/denisenkom/go-mssqldb v0.0.0-20190924004331-208c0a498538 github.com/go-sql-driver/mysql v1.4.1 - github.com/go-xorm/xorm v0.7.6 - github.com/google/go-cmp v0.3.1 // indirect + github.com/go-xorm/xorm v0.7.8 github.com/gorilla/context v1.1.1 github.com/gorilla/securecookie v1.1.1 github.com/gorilla/sessions v1.2.0 - github.com/jackc/pgx v3.5.0+incompatible // indirect + github.com/kr/pretty v0.1.0 // indirect github.com/lib/pq v1.2.0 github.com/mattn/go-sqlite3 v1.11.0 - github.com/stretchr/testify v1.4.0 // indirect - golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 // indirect - xorm.io/core v0.7.0 + golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad // indirect + google.golang.org/appengine v1.6.4 // indirect + gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect + xorm.io/core v0.7.2 ) diff --git a/vendor/github.com/lafriks/xormstore/go.sum b/vendor/github.com/lafriks/xormstore/go.sum index b076be6049aa3..b3326c7f44753 100644 --- a/vendor/github.com/lafriks/xormstore/go.sum +++ b/vendor/github.com/lafriks/xormstore/go.sum @@ -2,13 +2,7 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU= cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.3 h1:0sMegbmn/8uTwpNkB0q9cLEpZ2W5a6kl+wtBQgPWBJQ= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -22,8 +16,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= -github.com/denisenkom/go-mssqldb v0.0.0-20190820223206-44cdfe8d8ba9 h1:r05vdZzhwcLFTrNCNirAQEL30b/tlqnI0ow7BCcUiT4= -github.com/denisenkom/go-mssqldb v0.0.0-20190820223206-44cdfe8d8ba9/go.mod h1:uU0N10vx1abI4qeVe79CxepBP6PPREVTgMS5Gx6/mOk= +github.com/denisenkom/go-mssqldb v0.0.0-20190924004331-208c0a498538 h1:bpWCJ5MddHsv4Xtl3azkK89mZzd/vvut32mvAnKbyUA= +github.com/denisenkom/go-mssqldb v0.0.0-20190924004331-208c0a498538/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= @@ -35,30 +29,25 @@ github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= -github.com/go-xorm/xorm v0.7.6 h1:qFbuobVfAYzMlf9C8hrLnp4B17VUEIH0eZuZ0IfXWjo= -github.com/go-xorm/xorm v0.7.6/go.mod h1:nqz2TAsuOHWH2yk4FYWtacCGgdbrcdZ5mF1XadqEHls= +github.com/go-xorm/xorm v0.7.8 h1:rKxZJB9mWQ9Nw2TbjsepiThR031jkGePOWXwTtEAU08= +github.com/go-xorm/xorm v0.7.8/go.mod h1:XiVxrMMIhFkwSkh96BW7PACl7UhLtx2iJIHMdmjh5sQ= +github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= @@ -67,14 +56,10 @@ github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+ github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= -github.com/jackc/pgx v3.3.0+incompatible h1:Wa90/+qsITBAPkAZjiByeIGHFcj3Ztu+VzrrIpHjL90= -github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= -github.com/jackc/pgx v3.5.0+incompatible h1:BRJ4G3UPtvml5R1ey0biqqGuYUGayMYekm3woO75orY= -github.com/jackc/pgx v3.5.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= +github.com/jackc/pgx v3.6.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -113,8 +98,6 @@ github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -128,24 +111,17 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 h1:7KByu05hhLed2MO29w7p1XfZvZ13m8mub3shuVftRs0= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad h1:5E5raQxcv+6CZ11RrBYQe5WRbUIWpScjh0kvHZkZIrQ= +golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -155,13 +131,9 @@ golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -173,57 +145,37 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.4 h1:WiKh4+/eMB2HaY7QhCfW/R7MuRAoA8QMCSJA6jP5/fo= +google.golang.org/appengine v1.6.4/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -232,9 +184,9 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -xorm.io/builder v0.3.5 h1:EilU39fvWDxjb1cDaELpYhsF+zziRBhew8xk4pngO+A= -xorm.io/builder v0.3.5/go.mod h1:ZFbByS/KxZI1FKRjL05PyJ4YrK2bcxlUaAxdum5aTR8= -xorm.io/core v0.7.0 h1:hKxuOKWZNeiFQsSuGet/KV8HZ788hclvAl+7azx3tkM= -xorm.io/core v0.7.0/go.mod h1:TuOJjIVa7e3w/rN8tDcAvuLBMtwzdHPbyOzE6Gk1EUI= +xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8= +xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU= +xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb h1:msX3zG3BPl8Ti+LDzP33/9K7BzO/WqFXk610K1kYKfo= +xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM= +xorm.io/core v0.7.2 h1:mEO22A2Z7a3fPaZMk6gKL/jMD80iiyNwRrX5HOv3XLw= +xorm.io/core v0.7.2/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM= diff --git a/vendor/golang.org/x/crypto/acme/acme.go b/vendor/golang.org/x/crypto/acme/acme.go index fa365b7b6adf8..31d07e30f7d4c 100644 --- a/vendor/golang.org/x/crypto/acme/acme.go +++ b/vendor/golang.org/x/crypto/acme/acme.go @@ -4,7 +4,10 @@ // Package acme provides an implementation of the // Automatic Certificate Management Environment (ACME) spec. -// See https://tools.ietf.org/html/draft-ietf-acme-acme-02 for details. +// The intial implementation was based on ACME draft-02 and +// is now being extended to comply with RFC8555. +// See https://tools.ietf.org/html/draft-ietf-acme-acme-02 +// and https://tools.ietf.org/html/rfc8555 for details. // // Most common scenarios will want to use autocert subdirectory instead, // which provides automatic access to certificates from Let's Encrypt @@ -116,21 +119,49 @@ type Client struct { // identifiable by the server, in case they are causing issues. UserAgent string - dirMu sync.Mutex // guards writes to dir - dir *Directory // cached result of Client's Discover method + cacheMu sync.Mutex + dir *Directory // cached result of Client's Discover method + kid keyID // cached Account.URI obtained from registerRFC or getAccountRFC noncesMu sync.Mutex nonces map[string]struct{} // nonces collected from previous responses } +// accountKID returns a key ID associated with c.Key, the account identity +// provided by the CA during RFC based registration. +// It assumes c.Discover has already been called. +// +// accountKID requires at most one network roundtrip. +// It caches only successful result. +// +// When in pre-RFC mode or when c.getRegRFC responds with an error, accountKID +// returns noKeyID. +func (c *Client) accountKID(ctx context.Context) keyID { + c.cacheMu.Lock() + defer c.cacheMu.Unlock() + if c.dir.OrderURL == "" { + // Assume legacy CA. + return noKeyID + } + if c.kid != noKeyID { + return c.kid + } + a, err := c.getRegRFC(ctx) + if err != nil { + return noKeyID + } + c.kid = keyID(a.URI) + return c.kid +} + // Discover performs ACME server discovery using c.DirectoryURL. // // It caches successful result. So, subsequent calls will not result in // a network round-trip. This also means mutating c.DirectoryURL after successful call // of this method will have no effect. func (c *Client) Discover(ctx context.Context) (Directory, error) { - c.dirMu.Lock() - defer c.dirMu.Unlock() + c.cacheMu.Lock() + defer c.cacheMu.Unlock() if c.dir != nil { return *c.dir, nil } @@ -143,27 +174,53 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) { c.addNonce(res.Header) var v struct { - Reg string `json:"new-reg"` - Authz string `json:"new-authz"` - Cert string `json:"new-cert"` - Revoke string `json:"revoke-cert"` - Meta struct { - Terms string `json:"terms-of-service"` - Website string `json:"website"` - CAA []string `json:"caa-identities"` + Reg string `json:"new-reg"` + RegRFC string `json:"newAccount"` + Authz string `json:"new-authz"` + AuthzRFC string `json:"newAuthz"` + OrderRFC string `json:"newOrder"` + Cert string `json:"new-cert"` + Revoke string `json:"revoke-cert"` + RevokeRFC string `json:"revokeCert"` + NonceRFC string `json:"newNonce"` + KeyChangeRFC string `json:"keyChange"` + Meta struct { + Terms string `json:"terms-of-service"` + TermsRFC string `json:"termsOfService"` + WebsiteRFC string `json:"website"` + CAA []string `json:"caa-identities"` + CAARFC []string `json:"caaIdentities"` + ExternalAcctRFC bool `json:"externalAccountRequired"` } } if err := json.NewDecoder(res.Body).Decode(&v); err != nil { return Directory{}, err } + if v.OrderRFC == "" { + // Non-RFC compliant ACME CA. + c.dir = &Directory{ + RegURL: v.Reg, + AuthzURL: v.Authz, + CertURL: v.Cert, + RevokeURL: v.Revoke, + Terms: v.Meta.Terms, + Website: v.Meta.WebsiteRFC, + CAA: v.Meta.CAA, + } + return *c.dir, nil + } + // RFC compliant ACME CA. c.dir = &Directory{ - RegURL: v.Reg, - AuthzURL: v.Authz, - CertURL: v.Cert, - RevokeURL: v.Revoke, - Terms: v.Meta.Terms, - Website: v.Meta.Website, - CAA: v.Meta.CAA, + RegURL: v.RegRFC, + AuthzURL: v.AuthzRFC, + OrderURL: v.OrderRFC, + RevokeURL: v.RevokeRFC, + NonceURL: v.NonceRFC, + KeyChangeURL: v.KeyChangeRFC, + Terms: v.Meta.TermsRFC, + Website: v.Meta.WebsiteRFC, + CAA: v.Meta.CAARFC, + ExternalAccountRequired: v.Meta.ExternalAcctRFC, } return *c.dir, nil } @@ -206,7 +263,7 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration, req.NotAfter = now.Add(exp).Format(time.RFC3339) } - res, err := c.post(ctx, c.Key, c.dir.CertURL, req, wantStatus(http.StatusCreated)) + res, err := c.post(ctx, nil, c.dir.CertURL, req, wantStatus(http.StatusCreated)) if err != nil { return nil, "", err } @@ -260,9 +317,6 @@ func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte, Cert: base64.RawURLEncoding.EncodeToString(cert), Reason: int(reason), } - if key == nil { - key = c.Key - } res, err := c.post(ctx, key, c.dir.RevokeURL, body, wantStatus(http.StatusOK)) if err != nil { return err @@ -275,20 +329,32 @@ func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte, // during account registration. See Register method of Client for more details. func AcceptTOS(tosURL string) bool { return true } -// Register creates a new account registration by following the "new-reg" flow. -// It returns the registered account. The account is not modified. +// Register creates a new account with the CA using c.Key. +// It returns the registered account. The account acct is not modified. // // The registration may require the caller to agree to the CA's Terms of Service (TOS). // If so, and the account has not indicated the acceptance of the terms (see Account for details), // Register calls prompt with a TOS URL provided by the CA. Prompt should report // whether the caller agrees to the terms. To always accept the terms, the caller can use AcceptTOS. -func (c *Client) Register(ctx context.Context, a *Account, prompt func(tosURL string) bool) (*Account, error) { - if _, err := c.Discover(ctx); err != nil { +// +// When interfacing with RFC compliant CA, non-RFC8555 compliant fields of acct are ignored +// and prompt is called if Directory's Terms field is non-zero. +// Also see Error's Instance field for when a CA requires already registered accounts to agree +// to an updated Terms of Service. +func (c *Client) Register(ctx context.Context, acct *Account, prompt func(tosURL string) bool) (*Account, error) { + dir, err := c.Discover(ctx) + if err != nil { return nil, err } - var err error - if a, err = c.doReg(ctx, c.dir.RegURL, "new-reg", a); err != nil { + // RFC8555 compliant account registration. + if dir.OrderURL != "" { + return c.registerRFC(ctx, acct, prompt) + } + + // Legacy ACME draft registration flow. + a, err := c.doReg(ctx, dir.RegURL, "new-reg", acct) + if err != nil { return nil, err } var accept bool @@ -302,9 +368,22 @@ func (c *Client) Register(ctx context.Context, a *Account, prompt func(tosURL st return a, err } -// GetReg retrieves an existing registration. -// The url argument is an Account URI. +// GetReg retrieves an existing account associated with c.Key. +// +// The url argument is an Account URI used with pre-RFC8555 CAs. +// It is ignored when interfacing with an RFC compliant CA. func (c *Client) GetReg(ctx context.Context, url string) (*Account, error) { + dir, err := c.Discover(ctx) + if err != nil { + return nil, err + } + + // Assume RFC8555 compliant CA. + if dir.OrderURL != "" { + return c.getRegRFC(ctx) + } + + // Legacy CA. a, err := c.doReg(ctx, url, "reg", nil) if err != nil { return nil, err @@ -315,9 +394,23 @@ func (c *Client) GetReg(ctx context.Context, url string) (*Account, error) { // UpdateReg updates an existing registration. // It returns an updated account copy. The provided account is not modified. -func (c *Client) UpdateReg(ctx context.Context, a *Account) (*Account, error) { - uri := a.URI - a, err := c.doReg(ctx, uri, "reg", a) +// +// When interfacing with RFC compliant CAs, a.URI is ignored and the account URL +// associated with c.Key is used instead. +func (c *Client) UpdateReg(ctx context.Context, acct *Account) (*Account, error) { + dir, err := c.Discover(ctx) + if err != nil { + return nil, err + } + + // Assume RFC8555 compliant CA. + if dir.OrderURL != "" { + return c.updateRegRFC(ctx, acct) + } + + // Legacy CA. + uri := acct.URI + a, err := c.doReg(ctx, uri, "reg", acct) if err != nil { return nil, err } @@ -362,7 +455,7 @@ func (c *Client) authorize(ctx context.Context, typ, val string) (*Authorization Resource: "new-authz", Identifier: authzID{Type: typ, Value: val}, } - res, err := c.post(ctx, c.Key, c.dir.AuthzURL, req, wantStatus(http.StatusCreated)) + res, err := c.post(ctx, nil, c.dir.AuthzURL, req, wantStatus(http.StatusCreated)) if err != nil { return nil, err } @@ -405,6 +498,11 @@ func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorizati // // It does not revoke existing certificates. func (c *Client) RevokeAuthorization(ctx context.Context, url string) error { + // Required for c.accountKID() when in RFC mode. + if _, err := c.Discover(ctx); err != nil { + return err + } + req := struct { Resource string `json:"resource"` Status string `json:"status"` @@ -414,7 +512,7 @@ func (c *Client) RevokeAuthorization(ctx context.Context, url string) error { Status: "deactivated", Delete: true, } - res, err := c.post(ctx, c.Key, url, req, wantStatus(http.StatusOK)) + res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK)) if err != nil { return err } @@ -491,6 +589,11 @@ func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, erro // // The server will then perform the validation asynchronously. func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error) { + // Required for c.accountKID() when in RFC mode. + if _, err := c.Discover(ctx); err != nil { + return nil, err + } + auth, err := keyAuth(c.Key.Public(), chal.Token) if err != nil { return nil, err @@ -505,7 +608,7 @@ func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error Type: chal.Type, Auth: auth, } - res, err := c.post(ctx, c.Key, chal.URI, req, wantStatus( + res, err := c.post(ctx, nil, chal.URI, req, wantStatus( http.StatusOK, // according to the spec http.StatusAccepted, // Let's Encrypt: see https://goo.gl/WsJ7VT (acme-divergences.md) )) @@ -682,7 +785,7 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun req.Contact = acct.Contact req.Agreement = acct.AgreedTerms } - res, err := c.post(ctx, c.Key, url, req, wantStatus( + res, err := c.post(ctx, nil, url, req, wantStatus( http.StatusOK, // updates and deletes http.StatusCreated, // new account creation http.StatusAccepted, // Let's Encrypt divergent implementation @@ -721,12 +824,16 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun } // popNonce returns a nonce value previously stored with c.addNonce -// or fetches a fresh one from a URL by issuing a HEAD request. -// It first tries c.directoryURL() and then the provided url if the former fails. +// or fetches a fresh one from c.dir.NonceURL. +// If NonceURL is empty, it first tries c.directoryURL() and, failing that, +// the provided url. func (c *Client) popNonce(ctx context.Context, url string) (string, error) { c.noncesMu.Lock() defer c.noncesMu.Unlock() if len(c.nonces) == 0 { + if c.dir != nil && c.dir.NonceURL != "" { + return c.fetchNonce(ctx, c.dir.NonceURL) + } dirURL := c.directoryURL() v, err := c.fetchNonce(ctx, dirURL) if err != nil && url != dirURL { diff --git a/vendor/golang.org/x/crypto/acme/autocert/autocert.go b/vendor/golang.org/x/crypto/acme/autocert/autocert.go index 70ab355f373c6..5256bc3105ca9 100644 --- a/vendor/golang.org/x/crypto/acme/autocert/autocert.go +++ b/vendor/golang.org/x/crypto/acme/autocert/autocert.go @@ -88,9 +88,9 @@ func defaultHostPolicy(context.Context, string) error { } // Manager is a stateful certificate manager built on top of acme.Client. -// It obtains and refreshes certificates automatically using "tls-alpn-01", -// "tls-sni-01", "tls-sni-02" and "http-01" challenge types, -// as well as providing them to a TLS server via tls.Config. +// It obtains and refreshes certificates automatically using "tls-alpn-01" +// or "http-01" challenge types, as well as providing them to a TLS server +// via tls.Config. // // You must specify a cache implementation, such as DirCache, // to reuse obtained certificates across program restarts. @@ -184,10 +184,8 @@ type Manager struct { // to be provisioned. // The entries are stored for the duration of the authorization flow. httpTokens map[string][]byte - // certTokens contains temporary certificates for tls-sni and tls-alpn challenges - // and is keyed by token domain name, which matches server name of ClientHello. - // Keys always have ".acme.invalid" suffix for tls-sni. Otherwise, they are domain names - // for tls-alpn. + // certTokens contains temporary certificates for tls-alpn-01 challenges + // and is keyed by the domain name which matches the ClientHello server name. // The entries are stored for the duration of the authorization flow. certTokens map[string]*tls.Certificate // nowFunc, if not nil, returns the current time. This may be set for @@ -226,7 +224,7 @@ func (m *Manager) TLSConfig() *tls.Config { // GetCertificate implements the tls.Config.GetCertificate hook. // It provides a TLS certificate for hello.ServerName host, including answering -// tls-alpn-01 and *.acme.invalid (tls-sni-01 and tls-sni-02) challenges. +// tls-alpn-01 challenges. // All other fields of hello are ignored. // // If m.HostPolicy is non-nil, GetCertificate calls the policy before requesting @@ -235,9 +233,7 @@ func (m *Manager) TLSConfig() *tls.Config { // This does not affect cached certs. See HostPolicy field description for more details. // // If GetCertificate is used directly, instead of via Manager.TLSConfig, package users will -// also have to add acme.ALPNProto to NextProtos for tls-alpn-01, or use HTTPHandler -// for http-01. (The tls-sni-* challenges have been deprecated by popular ACME providers -// due to security issues in the ecosystem.) +// also have to add acme.ALPNProto to NextProtos for tls-alpn-01, or use HTTPHandler for http-01. func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) { if m.Prompt == nil { return nil, errors.New("acme/autocert: Manager.Prompt not set") @@ -269,13 +265,10 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) defer cancel() - // Check whether this is a token cert requested for TLS-SNI or TLS-ALPN challenge. + // Check whether this is a token cert requested for TLS-ALPN challenge. if wantsTokenCert(hello) { m.tokensMu.RLock() defer m.tokensMu.RUnlock() - // It's ok to use the same token cert key for both tls-sni and tls-alpn - // because there's always at most 1 token cert per on-going domain authorization. - // See m.verify for details. if cert := m.certTokens[name]; cert != nil { return cert, nil } @@ -318,8 +311,7 @@ func wantsTokenCert(hello *tls.ClientHelloInfo) bool { if len(hello.SupportedProtos) == 1 && hello.SupportedProtos[0] == acme.ALPNProto { return true } - // tls-sni-xx - return strings.HasSuffix(hello.ServerName, ".acme.invalid") + return false } func supportsECDSA(hello *tls.ClientHelloInfo) bool { @@ -688,7 +680,7 @@ func (m *Manager) revokePendingAuthz(ctx context.Context, uri []string) { func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string) error { // The list of challenge types we'll try to fulfill // in this specific order. - challengeTypes := []string{"tls-alpn-01", "tls-sni-02", "tls-sni-01"} + challengeTypes := []string{"tls-alpn-01"} m.tokensMu.RLock() if m.tryHTTP01 { challengeTypes = append(challengeTypes, "http-01") @@ -776,20 +768,6 @@ func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.C } m.putCertToken(ctx, domain, &cert) return func() { go m.deleteCertToken(domain) }, nil - case "tls-sni-01": - cert, name, err := client.TLSSNI01ChallengeCert(chal.Token) - if err != nil { - return nil, err - } - m.putCertToken(ctx, name, &cert) - return func() { go m.deleteCertToken(name) }, nil - case "tls-sni-02": - cert, name, err := client.TLSSNI02ChallengeCert(chal.Token) - if err != nil { - return nil, err - } - m.putCertToken(ctx, name, &cert) - return func() { go m.deleteCertToken(name) }, nil case "http-01": resp, err := client.HTTP01ChallengeResponse(chal.Token) if err != nil { diff --git a/vendor/golang.org/x/crypto/acme/http.go b/vendor/golang.org/x/crypto/acme/http.go index 600d5798b86ce..b145292f9e968 100644 --- a/vendor/golang.org/x/crypto/acme/http.go +++ b/vendor/golang.org/x/crypto/acme/http.go @@ -156,7 +156,7 @@ func (c *Client) get(ctx context.Context, url string, ok resOkay) (*http.Respons } // post issues a signed POST request in JWS format using the provided key -// to the specified URL. +// to the specified URL. If key is nil, c.Key is used instead. // It returns a non-error value only when ok reports true. // // post retries unsuccessful attempts according to c.RetryBackoff @@ -193,14 +193,28 @@ func (c *Client) post(ctx context.Context, key crypto.Signer, url string, body i } // postNoRetry signs the body with the given key and POSTs it to the provided url. -// The body argument must be JSON-serializable. // It is used by c.post to retry unsuccessful attempts. +// The body argument must be JSON-serializable. +// +// If key argument is nil, c.Key is used to sign the request. +// If key argument is nil and c.accountKID returns a non-zero keyID, +// the request is sent in KID form. Otherwise, JWK form is used. +// +// In practice, when interfacing with RFC compliant CAs most requests are sent in KID form +// and JWK is used only when KID is unavailable: new account endpoint and certificate +// revocation requests authenticated by a cert key. +// See jwsEncodeJSON for other details. func (c *Client) postNoRetry(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, *http.Request, error) { + kid := noKeyID + if key == nil { + key = c.Key + kid = c.accountKID(ctx) + } nonce, err := c.popNonce(ctx, url) if err != nil { return nil, nil, err } - b, err := jwsEncodeJSON(body, key, nonce) + b, err := jwsEncodeJSON(body, key, kid, nonce, url) if err != nil { return nil, nil, err } diff --git a/vendor/golang.org/x/crypto/acme/jws.go b/vendor/golang.org/x/crypto/acme/jws.go index 1093b50390144..f8bc2c467981c 100644 --- a/vendor/golang.org/x/crypto/acme/jws.go +++ b/vendor/golang.org/x/crypto/acme/jws.go @@ -17,19 +17,38 @@ import ( "math/big" ) +// keyID is the account identity provided by a CA during registration. +type keyID string + +// noKeyID indicates that jwsEncodeJSON should compute and use JWK instead of a KID. +// See jwsEncodeJSON for details. +const noKeyID = keyID("") + // jwsEncodeJSON signs claimset using provided key and a nonce. -// The result is serialized in JSON format. +// The result is serialized in JSON format containing either kid or jwk +// fields based on the provided keyID value. +// +// If kid is non-empty, its quoted value is inserted in the protected head +// as "kid" field value. Otherwise, JWK is computed using jwkEncode and inserted +// as "jwk" field value. The "jwk" and "kid" fields are mutually exclusive. +// // See https://tools.ietf.org/html/rfc7515#section-7. -func jwsEncodeJSON(claimset interface{}, key crypto.Signer, nonce string) ([]byte, error) { - jwk, err := jwkEncode(key.Public()) - if err != nil { - return nil, err - } +func jwsEncodeJSON(claimset interface{}, key crypto.Signer, kid keyID, nonce, url string) ([]byte, error) { alg, sha := jwsHasher(key.Public()) if alg == "" || !sha.Available() { return nil, ErrUnsupportedKey } - phead := fmt.Sprintf(`{"alg":%q,"jwk":%s,"nonce":%q}`, alg, jwk, nonce) + var phead string + switch kid { + case noKeyID: + jwk, err := jwkEncode(key.Public()) + if err != nil { + return nil, err + } + phead = fmt.Sprintf(`{"alg":%q,"jwk":%s,"nonce":%q,"url":%q}`, alg, jwk, nonce, url) + default: + phead = fmt.Sprintf(`{"alg":%q,"kid":%q,"nonce":%q,"url":%q}`, alg, kid, nonce, url) + } phead = base64.RawURLEncoding.EncodeToString([]byte(phead)) cs, err := json.Marshal(claimset) if err != nil { diff --git a/vendor/golang.org/x/crypto/acme/rfc8555.go b/vendor/golang.org/x/crypto/acme/rfc8555.go new file mode 100644 index 0000000000000..51839a0723c7a --- /dev/null +++ b/vendor/golang.org/x/crypto/acme/rfc8555.go @@ -0,0 +1,122 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package acme + +import ( + "context" + "encoding/json" + "fmt" + "net/http" +) + +// DeactivateReg permanently disables an existing account associated with c.Key. +// A deactivated account can no longer request certificate issuance or access +// resources related to the account, such as orders or authorizations. +// +// It works only with RFC8555 compliant CAs. +func (c *Client) DeactivateReg(ctx context.Context) error { + url := string(c.accountKID(ctx)) + if url == "" { + return ErrNoAccount + } + req := json.RawMessage(`{"status": "deactivated"}`) + res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK)) + if err != nil { + return err + } + res.Body.Close() + return nil +} + +// registerRFC is quivalent to c.Register but for RFC-compliant CAs. +// It expects c.Discover to have already been called. +// TODO: Implement externalAccountBinding. +func (c *Client) registerRFC(ctx context.Context, acct *Account, prompt func(tosURL string) bool) (*Account, error) { + c.cacheMu.Lock() // guard c.kid access + defer c.cacheMu.Unlock() + + req := struct { + TermsAgreed bool `json:"termsOfServiceAgreed,omitempty"` + Contact []string `json:"contact,omitempty"` + }{ + Contact: acct.Contact, + } + if c.dir.Terms != "" { + req.TermsAgreed = prompt(c.dir.Terms) + } + res, err := c.post(ctx, c.Key, c.dir.RegURL, req, wantStatus( + http.StatusOK, // account with this key already registered + http.StatusCreated, // new account created + )) + if err != nil { + return nil, err + } + + defer res.Body.Close() + a, err := responseAccount(res) + if err != nil { + return nil, err + } + // Cache Account URL even if we return an error to the caller. + // It is by all means a valid and usable "kid" value for future requests. + c.kid = keyID(a.URI) + if res.StatusCode == http.StatusOK { + return nil, ErrAccountAlreadyExists + } + return a, nil +} + +// updateGegRFC is equivalent to c.UpdateReg but for RFC-compliant CAs. +// It expects c.Discover to have already been called. +func (c *Client) updateRegRFC(ctx context.Context, a *Account) (*Account, error) { + url := string(c.accountKID(ctx)) + if url == "" { + return nil, ErrNoAccount + } + req := struct { + Contact []string `json:"contact,omitempty"` + }{ + Contact: a.Contact, + } + res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK)) + if err != nil { + return nil, err + } + defer res.Body.Close() + return responseAccount(res) +} + +// getGegRFC is equivalent to c.GetReg but for RFC-compliant CAs. +// It expects c.Discover to have already been called. +func (c *Client) getRegRFC(ctx context.Context) (*Account, error) { + req := json.RawMessage(`{"onlyReturnExisting": true}`) + res, err := c.post(ctx, c.Key, c.dir.RegURL, req, wantStatus(http.StatusOK)) + if e, ok := err.(*Error); ok && e.ProblemType == "urn:ietf:params:acme:error:accountDoesNotExist" { + return nil, ErrNoAccount + } + if err != nil { + return nil, err + } + + defer res.Body.Close() + return responseAccount(res) +} + +func responseAccount(res *http.Response) (*Account, error) { + var v struct { + Status string + Contact []string + Orders string + } + if err := json.NewDecoder(res.Body).Decode(&v); err != nil { + return nil, fmt.Errorf("acme: invalid response: %v", err) + } + return &Account{ + URI: res.Header.Get("Location"), + Status: v.Status, + Contact: v.Contact, + OrdersURL: v.Orders, + }, nil +} diff --git a/vendor/golang.org/x/crypto/acme/types.go b/vendor/golang.org/x/crypto/acme/types.go index 54792c0650fa9..4432afbc21a4b 100644 --- a/vendor/golang.org/x/crypto/acme/types.go +++ b/vendor/golang.org/x/crypto/acme/types.go @@ -16,12 +16,13 @@ import ( // ACME server response statuses used to describe Authorization and Challenge states. const ( - StatusUnknown = "unknown" - StatusPending = "pending" - StatusProcessing = "processing" - StatusValid = "valid" - StatusInvalid = "invalid" - StatusRevoked = "revoked" + StatusDeactivated = "deactivated" + StatusInvalid = "invalid" + StatusPending = "pending" + StatusProcessing = "processing" + StatusRevoked = "revoked" + StatusUnknown = "unknown" + StatusValid = "valid" ) // CRLReasonCode identifies the reason for a certificate revocation. @@ -41,8 +42,17 @@ const ( CRLReasonAACompromise CRLReasonCode = 10 ) -// ErrUnsupportedKey is returned when an unsupported key type is encountered. -var ErrUnsupportedKey = errors.New("acme: unknown key type; only RSA and ECDSA are supported") +var ( + // ErrUnsupportedKey is returned when an unsupported key type is encountered. + ErrUnsupportedKey = errors.New("acme: unknown key type; only RSA and ECDSA are supported") + + // ErrAccountAlreadyExists indicates that the Client's key has already been registered + // with the CA. It is returned by Register method. + ErrAccountAlreadyExists = errors.New("acme: account already exists") + + // ErrNoAccount indicates that the Client's key has not been registered with the CA. + ErrNoAccount = errors.New("acme: account does not exist") +) // Error is an ACME error, defined in Problem Details for HTTP APIs doc // http://tools.ietf.org/html/draft-ietf-appsawg-http-problem. @@ -54,6 +64,12 @@ type Error struct { ProblemType string // Detail is a human-readable explanation specific to this occurrence of the problem. Detail string + // Instance indicates a URL that the client should direct a human user to visit + // in order for instructions on how to agree to the updated Terms of Service. + // In such an event CA sets StatusCode to 403, ProblemType to + // "urn:ietf:params:acme:error:userActionRequired" and a Link header with relation + // "terms-of-service" containing the latest TOS URL. + Instance string // Header is the original server error response headers. // It may be nil. Header http.Header @@ -108,49 +124,88 @@ func RateLimit(err error) (time.Duration, bool) { } // Account is a user account. It is associated with a private key. +// Non-RFC8555 fields are empty when interfacing with a compliant CA. type Account struct { // URI is the account unique ID, which is also a URL used to retrieve // account data from the CA. + // When interfacing with RFC8555-compliant CAs, URI is the "kid" field + // value in JWS signed requests. URI string // Contact is a slice of contact info used during registration. + // See https://tools.ietf.org/html/rfc8555#section-7.3 for supported + // formats. Contact []string + // Status indicates current account status as returned by the CA. + // Possible values are "valid", "deactivated", and "revoked". + Status string + + // OrdersURL is a URL from which a list of orders submitted by this account + // can be fetched. + OrdersURL string + // The terms user has agreed to. // A value not matching CurrentTerms indicates that the user hasn't agreed // to the actual Terms of Service of the CA. + // + // It is non-RFC8555 compliant. Package users can store the ToS they agree to + // during Client's Register call in the prompt callback function. AgreedTerms string // Actual terms of a CA. + // + // It is non-RFC8555 compliant. Use Directory's Terms field. + // When a CA updates their terms and requires an account agreement, + // a URL at which instructions to do so is available in Error's Instance field. CurrentTerms string // Authz is the authorization URL used to initiate a new authz flow. + // + // It is non-RFC8555 compliant. Use Directory's AuthzURL or OrderURL. Authz string // Authorizations is a URI from which a list of authorizations // granted to this account can be fetched via a GET request. + // + // It is non-RFC8555 compliant and is obsoleted by OrdersURL. Authorizations string // Certificates is a URI from which a list of certificates // issued for this account can be fetched via a GET request. + // + // It is non-RFC8555 compliant and is obsoleted by OrdersURL. Certificates string } // Directory is ACME server discovery data. +// See https://tools.ietf.org/html/rfc8555#section-7.1.1 for more details. type Directory struct { - // RegURL is an account endpoint URL, allowing for creating new - // and modifying existing accounts. + // NonceURL indicates an endpoint where to fetch fresh nonce values from. + NonceURL string + + // RegURL is an account endpoint URL, allowing for creating new accounts. + // Pre-RFC8555 CAs also allow modifying existing accounts at this URL. RegURL string - // AuthzURL is used to initiate Identifier Authorization flow. + // OrderURL is used to initiate the certificate issuance flow + // as described in RFC8555. + OrderURL string + + // AuthzURL is used to initiate identifier pre-authorization flow. + // Empty string indicates the flow is unsupported by the CA. AuthzURL string // CertURL is a new certificate issuance endpoint URL. + // It is non-RFC8555 compliant and is obsoleted by OrderURL. CertURL string // RevokeURL is used to initiate a certificate revocation flow. RevokeURL string + // KeyChangeURL allows to perform account key rollover flow. + KeyChangeURL string + // Term is a URI identifying the current terms of service. Terms string @@ -162,6 +217,10 @@ type Directory struct { // recognises as referring to itself for the purposes of CAA record validation // as defined in RFC6844. CAA []string + + // ExternalAccountRequired indicates that the CA requires for all account-related + // requests to include external account binding information. + ExternalAccountRequired bool } // Challenge encodes a returned CA challenge. @@ -282,9 +341,10 @@ func (c *wireChallenge) challenge() *Challenge { // wireError is a subset of fields of the Problem Details object // as described in https://tools.ietf.org/html/rfc7807#section-3.1. type wireError struct { - Status int - Type string - Detail string + Status int + Type string + Detail string + Instance string } func (e *wireError) error(h http.Header) *Error { @@ -292,6 +352,7 @@ func (e *wireError) error(h http.Header) *Error { StatusCode: e.Status, ProblemType: e.Type, Detail: e.Detail, + Instance: e.Instance, Header: h, } } diff --git a/vendor/golang.org/x/crypto/ssh/common.go b/vendor/golang.org/x/crypto/ssh/common.go index e55fe0ad62611..290382d059eff 100644 --- a/vendor/golang.org/x/crypto/ssh/common.go +++ b/vendor/golang.org/x/crypto/ssh/common.go @@ -58,6 +58,14 @@ var serverForbiddenKexAlgos = map[string]struct{}{ kexAlgoDHGEXSHA256: {}, // server half implementation is only minimal to satisfy the automated tests } +// preferredKexAlgos specifies the default preference for key-exchange algorithms +// in preference order. +var preferredKexAlgos = []string{ + kexAlgoCurve25519SHA256, + kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521, + kexAlgoDH14SHA1, +} + // supportedHostKeyAlgos specifies the supported host-key algorithms (i.e. methods // of authenticating servers) in preference order. var supportedHostKeyAlgos = []string{ @@ -246,7 +254,7 @@ func (c *Config) SetDefaults() { c.Ciphers = ciphers if c.KeyExchanges == nil { - c.KeyExchanges = supportedKexAlgos + c.KeyExchanges = preferredKexAlgos } if c.MACs == nil { diff --git a/vendor/google.golang.org/appengine/internal/net.go b/vendor/google.golang.org/appengine/internal/net.go index 3b94cf0c6a8b1..fe429720e1f25 100644 --- a/vendor/google.golang.org/appengine/internal/net.go +++ b/vendor/google.golang.org/appengine/internal/net.go @@ -32,7 +32,7 @@ func limitDial(network, addr string) (net.Conn, error) { // Dial with a timeout in case the API host is MIA. // The connection should normally be very fast. - conn, err := net.DialTimeout(network, addr, 500*time.Millisecond) + conn, err := net.DialTimeout(network, addr, 10*time.Second) if err != nil { limitRelease() return nil, err diff --git a/vendor/modules.txt b/vendor/modules.txt index dd055ddcef858..e2cb07eda9cec 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,5 +1,4 @@ # cloud.google.com/go v0.45.0 -cloud.google.com/go/civil cloud.google.com/go/compute/metadata # gitea.com/macaron/binding v0.0.0-20190822013154-a5f53841ed2b gitea.com/macaron/binding @@ -113,9 +112,10 @@ github.com/couchbase/vellum/utf8 github.com/couchbaselabs/go-couchbase # github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew/spew -# github.com/denisenkom/go-mssqldb v0.0.0-20190820223206-44cdfe8d8ba9 +# github.com/denisenkom/go-mssqldb v0.0.0-20190924004331-208c0a498538 github.com/denisenkom/go-mssqldb github.com/denisenkom/go-mssqldb/internal/cp +github.com/denisenkom/go-mssqldb/internal/decimal github.com/denisenkom/go-mssqldb/internal/querytext # github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dgrijalva/jwt-go @@ -213,6 +213,8 @@ github.com/gobwas/glob/util/strings github.com/gogits/chardet # github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 github.com/gogs/cron +# github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe +github.com/golang-sql/civil # github.com/golang/protobuf v1.3.2 github.com/golang/protobuf/proto # github.com/golang/snappy v0.0.1 @@ -279,7 +281,7 @@ github.com/klauspost/crc32 github.com/kr/pretty # github.com/kr/text v0.1.0 github.com/kr/text -# github.com/lafriks/xormstore v1.2.0 +# github.com/lafriks/xormstore v1.3.0 github.com/lafriks/xormstore github.com/lafriks/xormstore/util # github.com/lib/pq v1.2.0 @@ -445,7 +447,7 @@ go.mongodb.org/mongo-driver/bson/bsonrw go.mongodb.org/mongo-driver/bson/bsontype go.mongodb.org/mongo-driver/bson/primitive go.mongodb.org/mongo-driver/x/bsonx/bsoncore -# golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472 +# golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad golang.org/x/crypto/acme golang.org/x/crypto/acme/autocert golang.org/x/crypto/argon2 @@ -528,7 +530,7 @@ golang.org/x/tools/internal/gopathwalk golang.org/x/tools/internal/imports golang.org/x/tools/internal/module golang.org/x/tools/internal/semver -# google.golang.org/appengine v1.6.2 +# google.golang.org/appengine v1.6.4 google.golang.org/appengine google.golang.org/appengine/cloudsql google.golang.org/appengine/internal From f8899678d214581095709fd59f613979829c616b Mon Sep 17 00:00:00 2001 From: spaeps <1037160+spaeps@users.noreply.github.com> Date: Wed, 2 Oct 2019 09:20:30 +0200 Subject: [PATCH 009/173] [arc-green] white on hover for active menu items (#8344) * [arc-green] white on hover for active menu items Actually, hovered active menu elements are in an unreadable black text colour. This should be changed to white. * [arc-green] white on hover for active menu items Actually, hovered active menu elements are in an unreadable black text colour. This should be changed to white. Now editing less files and commiting with `make css`. --- public/css/theme-arc-green.css | 2 +- public/less/themes/arc-green.less | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/public/css/theme-arc-green.css b/public/css/theme-arc-green.css index 938904c0bc216..28a127a3dd7b1 100644 --- a/public/css/theme-arc-green.css +++ b/public/css/theme-arc-green.css @@ -42,7 +42,7 @@ a:hover{color:#a0cc75} .ui.attached.table{border:1px solid #304251;background:#304251} .feeds .list ul li:not(:last-child){border-bottom:1px solid #333640} .feeds .list ul li.private{background:#353945;border:1px solid #333640} -.ui.secondary.menu .dropdown.item:hover,.ui.secondary.menu .link.item:hover,.ui.secondary.menu a.item:hover{color:#fff} +.ui.secondary.menu .active.item:hover,.ui.secondary.menu .dropdown.item:hover,.ui.secondary.menu .link.item:hover,.ui.secondary.menu a.item:hover{color:#fff} .ui.menu .ui.dropdown .menu>.item{background:#2c303a!important;color:#9e9e9e!important} .ui.secondary.menu .dropdown.item>.menu,.ui.text.menu .dropdown.item>.menu{border:1px solid #434444} footer{background:#2e323e;border-top:1px solid #313131} diff --git a/public/less/themes/arc-green.less b/public/less/themes/arc-green.less index cff51f0908f9d..27c32728a2f61 100644 --- a/public/less/themes/arc-green.less +++ b/public/less/themes/arc-green.less @@ -225,6 +225,7 @@ a:hover { .ui.secondary.menu .dropdown.item:hover, .ui.secondary.menu .link.item:hover, +.ui.secondary.menu .active.item:hover, .ui.secondary.menu a.item:hover { color: #ffffff; } From 90ab3056eb3c757637f1fd597584ce1f9d5ce863 Mon Sep 17 00:00:00 2001 From: David Svantesson Date: Wed, 2 Oct 2019 11:30:41 +0200 Subject: [PATCH 010/173] Api: advanced settings for repository (external wiki, issue tracker etc.) (#7756) * Add API for Repo Advanced Settings of wiki and issue tracker Signed-off-by: David Svantesson * Add some integration tests for tracker and wiki settings through API * Should return StatusUnprocessableEntity in case of invalid API values. * Add tests for invalid URLs for external tracker and wiki. * Do not set inital values if they are default of type * Make issue tracker and wiki units separate structures in Repository API structure. Signed-off-by: David Svantesson * Fix comment of structures Signed-off-by: David Svantesson * Rewrite API to use struct for setting tracker and wiki settings. * LetOnlyContributorsTrackTime -> AllowOnlyContributorsToTrackTime --- integrations/api_repo_edit_test.go | 106 ++++++++++++++++++++++++++++- models/repo.go | 28 +++++++- modules/structs/repo.go | 60 +++++++++++++--- routers/api/v1/repo/repo.go | 100 +++++++++++++++++++-------- templates/swagger/v1_json.tmpl | 74 ++++++++++++++++++++ 5 files changed, 327 insertions(+), 41 deletions(-) diff --git a/integrations/api_repo_edit_test.go b/integrations/api_repo_edit_test.go index 1231201b978fe..c1b513d0753c1 100644 --- a/integrations/api_repo_edit_test.go +++ b/integrations/api_repo_edit_test.go @@ -23,12 +23,35 @@ func getRepoEditOptionFromRepo(repo *models.Repository) *api.EditRepoOption { website := repo.Website private := repo.IsPrivate hasIssues := false - if _, err := repo.GetUnit(models.UnitTypeIssues); err == nil { + var internalTracker *api.InternalTracker + var externalTracker *api.ExternalTracker + if unit, err := repo.GetUnit(models.UnitTypeIssues); err == nil { + config := unit.IssuesConfig() hasIssues = true + internalTracker = &api.InternalTracker{ + EnableTimeTracker: config.EnableTimetracker, + AllowOnlyContributorsToTrackTime: config.AllowOnlyContributorsToTrackTime, + EnableIssueDependencies: config.EnableDependencies, + } + } else if unit, err := repo.GetUnit(models.UnitTypeExternalTracker); err == nil { + config := unit.ExternalTrackerConfig() + hasIssues = true + externalTracker = &api.ExternalTracker{ + ExternalTrackerURL: config.ExternalTrackerURL, + ExternalTrackerFormat: config.ExternalTrackerFormat, + ExternalTrackerStyle: config.ExternalTrackerStyle, + } } hasWiki := false + var externalWiki *api.ExternalWiki if _, err := repo.GetUnit(models.UnitTypeWiki); err == nil { hasWiki = true + } else if unit, err := repo.GetUnit(models.UnitTypeExternalWiki); err == nil { + hasWiki = true + config := unit.ExternalWikiConfig() + externalWiki = &api.ExternalWiki{ + ExternalWikiURL: config.ExternalWikiURL, + } } defaultBranch := repo.DefaultBranch hasPullRequests := false @@ -53,7 +76,10 @@ func getRepoEditOptionFromRepo(repo *models.Repository) *api.EditRepoOption { Website: &website, Private: &private, HasIssues: &hasIssues, + ExternalTracker: externalTracker, + InternalTracker: internalTracker, HasWiki: &hasWiki, + ExternalWiki: externalWiki, DefaultBranch: &defaultBranch, HasPullRequests: &hasPullRequests, IgnoreWhitespaceConflicts: &ignoreWhitespaceConflicts, @@ -143,6 +169,84 @@ func TestAPIRepoEdit(t *testing.T) { assert.Equal(t, *repoEditOption.Archived, *repo1editedOption.Archived) assert.Equal(t, *repoEditOption.Private, *repo1editedOption.Private) assert.Equal(t, *repoEditOption.HasWiki, *repo1editedOption.HasWiki) + + //Test editing repo1 to use internal issue and wiki (default) + *repoEditOption.HasIssues = true + repoEditOption.ExternalTracker = nil + repoEditOption.InternalTracker = &api.InternalTracker{ + EnableTimeTracker: false, + AllowOnlyContributorsToTrackTime: false, + EnableIssueDependencies: false, + } + *repoEditOption.HasWiki = true + repoEditOption.ExternalWiki = nil + url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, *repoEditOption.Name, token2) + req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &repo) + assert.NotNil(t, repo) + // check repo1 was written to database + repo1edited = models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository) + repo1editedOption = getRepoEditOptionFromRepo(repo1edited) + assert.Equal(t, *repo1editedOption.HasIssues, true) + assert.Nil(t, repo1editedOption.ExternalTracker) + assert.Equal(t, *repo1editedOption.InternalTracker, *repoEditOption.InternalTracker) + assert.Equal(t, *repo1editedOption.HasWiki, true) + assert.Nil(t, repo1editedOption.ExternalWiki) + + //Test editing repo1 to use external issue and wiki + repoEditOption.ExternalTracker = &api.ExternalTracker{ + ExternalTrackerURL: "http://www.somewebsite.com", + ExternalTrackerFormat: "http://www.somewebsite.com/{user}/{repo}?issue={index}", + ExternalTrackerStyle: "alphanumeric", + } + repoEditOption.ExternalWiki = &api.ExternalWiki{ + ExternalWikiURL: "http://www.somewebsite.com", + } + req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &repo) + assert.NotNil(t, repo) + // check repo1 was written to database + repo1edited = models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository) + repo1editedOption = getRepoEditOptionFromRepo(repo1edited) + assert.Equal(t, *repo1editedOption.HasIssues, true) + assert.Equal(t, *repo1editedOption.ExternalTracker, *repoEditOption.ExternalTracker) + assert.Equal(t, *repo1editedOption.HasWiki, true) + assert.Equal(t, *repo1editedOption.ExternalWiki, *repoEditOption.ExternalWiki) + + // Do some tests with invalid URL for external tracker and wiki + repoEditOption.ExternalTracker.ExternalTrackerURL = "htp://www.somewebsite.com" + req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption) + resp = session.MakeRequest(t, req, http.StatusUnprocessableEntity) + repoEditOption.ExternalTracker.ExternalTrackerURL = "http://www.somewebsite.com" + repoEditOption.ExternalTracker.ExternalTrackerFormat = "http://www.somewebsite.com/{user/{repo}?issue={index}" + req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption) + resp = session.MakeRequest(t, req, http.StatusUnprocessableEntity) + repoEditOption.ExternalTracker.ExternalTrackerFormat = "http://www.somewebsite.com/{user}/{repo}?issue={index}" + repoEditOption.ExternalWiki.ExternalWikiURL = "htp://www.somewebsite.com" + req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption) + resp = session.MakeRequest(t, req, http.StatusUnprocessableEntity) + + //Test small repo change through API with issue and wiki option not set; They shall not be touched. + *repoEditOption.Description = "small change" + repoEditOption.HasIssues = nil + repoEditOption.ExternalTracker = nil + repoEditOption.HasWiki = nil + repoEditOption.ExternalWiki = nil + req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &repo) + assert.NotNil(t, repo) + // check repo1 was written to database + repo1edited = models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository) + repo1editedOption = getRepoEditOptionFromRepo(repo1edited) + assert.Equal(t, *repo1editedOption.Description, *repoEditOption.Description) + assert.Equal(t, *repo1editedOption.HasIssues, true) + assert.NotNil(t, *repo1editedOption.ExternalTracker) + assert.Equal(t, *repo1editedOption.HasWiki, true) + assert.NotNil(t, *repo1editedOption.ExternalWiki) + // reset repo in db url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, *repoEditOption.Name, token2) req = NewRequestWithJSON(t, "PATCH", url, &origRepoEditOption) diff --git a/models/repo.go b/models/repo.go index eb7f286fec40a..69f32ae4a521a 100644 --- a/models/repo.go +++ b/models/repo.go @@ -275,12 +275,35 @@ func (repo *Repository) innerAPIFormat(e Engine, mode AccessMode, isParent bool) } } hasIssues := false - if _, err := repo.getUnit(e, UnitTypeIssues); err == nil { + var externalTracker *api.ExternalTracker + var internalTracker *api.InternalTracker + if unit, err := repo.getUnit(e, UnitTypeIssues); err == nil { + config := unit.IssuesConfig() hasIssues = true + internalTracker = &api.InternalTracker{ + EnableTimeTracker: config.EnableTimetracker, + AllowOnlyContributorsToTrackTime: config.AllowOnlyContributorsToTrackTime, + EnableIssueDependencies: config.EnableDependencies, + } + } else if unit, err := repo.getUnit(e, UnitTypeExternalTracker); err == nil { + config := unit.ExternalTrackerConfig() + hasIssues = true + externalTracker = &api.ExternalTracker{ + ExternalTrackerURL: config.ExternalTrackerURL, + ExternalTrackerFormat: config.ExternalTrackerFormat, + ExternalTrackerStyle: config.ExternalTrackerStyle, + } } hasWiki := false + var externalWiki *api.ExternalWiki if _, err := repo.getUnit(e, UnitTypeWiki); err == nil { hasWiki = true + } else if unit, err := repo.getUnit(e, UnitTypeExternalWiki); err == nil { + hasWiki = true + config := unit.ExternalWikiConfig() + externalWiki = &api.ExternalWiki{ + ExternalWikiURL: config.ExternalWikiURL, + } } hasPullRequests := false ignoreWhitespaceConflicts := false @@ -324,7 +347,10 @@ func (repo *Repository) innerAPIFormat(e Engine, mode AccessMode, isParent bool) Updated: repo.UpdatedUnix.AsTime(), Permissions: permission, HasIssues: hasIssues, + ExternalTracker: externalTracker, + InternalTracker: internalTracker, HasWiki: hasWiki, + ExternalWiki: externalWiki, HasPullRequests: hasPullRequests, IgnoreWhitespaceConflicts: ignoreWhitespaceConflicts, AllowMerge: allowMerge, diff --git a/modules/structs/repo.go b/modules/structs/repo.go index d94980fca4c7e..87396d6ce99a9 100644 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -15,6 +15,35 @@ type Permission struct { Pull bool `json:"pull"` } +// InternalTracker represents settings for internal tracker +// swagger:model +type InternalTracker struct { + // Enable time tracking (Built-in issue tracker) + EnableTimeTracker bool `json:"enable_time_tracker"` + // Let only contributors track time (Built-in issue tracker) + AllowOnlyContributorsToTrackTime bool `json:"allow_only_contributors_to_track_time"` + // Enable dependencies for issues and pull requests (Built-in issue tracker) + EnableIssueDependencies bool `json:"enable_issue_dependencies"` +} + +// ExternalTracker represents settings for external tracker +// swagger:model +type ExternalTracker struct { + // URL of external issue tracker. + ExternalTrackerURL string `json:"external_tracker_url"` + // External Issue Tracker URL Format. Use the placeholders {user}, {repo} and {index} for the username, repository name and issue index. + ExternalTrackerFormat string `json:"external_tracker_format"` + // External Issue Tracker Number Format, either `numeric` or `alphanumeric` + ExternalTrackerStyle string `json:"external_tracker_style"` +} + +// ExternalWiki represents setting for external wiki +// swagger:model +type ExternalWiki struct { + // URL of external wiki. + ExternalWikiURL string `json:"external_wiki_url"` +} + // Repository represents a repository type Repository struct { ID int64 `json:"id"` @@ -42,17 +71,20 @@ type Repository struct { // swagger:strfmt date-time Created time.Time `json:"created_at"` // swagger:strfmt date-time - Updated time.Time `json:"updated_at"` - Permissions *Permission `json:"permissions,omitempty"` - HasIssues bool `json:"has_issues"` - HasWiki bool `json:"has_wiki"` - HasPullRequests bool `json:"has_pull_requests"` - IgnoreWhitespaceConflicts bool `json:"ignore_whitespace_conflicts"` - AllowMerge bool `json:"allow_merge_commits"` - AllowRebase bool `json:"allow_rebase"` - AllowRebaseMerge bool `json:"allow_rebase_explicit"` - AllowSquash bool `json:"allow_squash_merge"` - AvatarURL string `json:"avatar_url"` + Updated time.Time `json:"updated_at"` + Permissions *Permission `json:"permissions,omitempty"` + HasIssues bool `json:"has_issues"` + InternalTracker *InternalTracker `json:"internal_tracker,omitempty"` + ExternalTracker *ExternalTracker `json:"external_tracker,omitempty"` + HasWiki bool `json:"has_wiki"` + ExternalWiki *ExternalWiki `json:"external_wiki,omitempty"` + HasPullRequests bool `json:"has_pull_requests"` + IgnoreWhitespaceConflicts bool `json:"ignore_whitespace_conflicts"` + AllowMerge bool `json:"allow_merge_commits"` + AllowRebase bool `json:"allow_rebase"` + AllowRebaseMerge bool `json:"allow_rebase_explicit"` + AllowSquash bool `json:"allow_squash_merge"` + AvatarURL string `json:"avatar_url"` } // CreateRepoOption options when creating repository @@ -95,8 +127,14 @@ type EditRepoOption struct { Private *bool `json:"private,omitempty"` // either `true` to enable issues for this repository or `false` to disable them. HasIssues *bool `json:"has_issues,omitempty"` + // set this structure to configure internal issue tracker (requires has_issues) + InternalTracker *InternalTracker `json:"internal_tracker,omitempty"` + // set this structure to use external issue tracker (requires has_issues) + ExternalTracker *ExternalTracker `json:"external_tracker,omitempty"` // either `true` to enable the wiki for this repository or `false` to disable it. HasWiki *bool `json:"has_wiki,omitempty"` + // set this structure to use external wiki instead of internal (requires has_wiki) + ExternalWiki *ExternalWiki `json:"external_wiki,omitempty"` // sets the default branch for this repository. DefaultBranch *string `json:"default_branch,omitempty"` // either `true` to allow pull requests, or `false` to prevent pull request. diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 513e7a37b3560..d8b06862a5ea6 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -19,6 +19,7 @@ import ( "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/modules/validation" "code.gitea.io/gitea/routers/api/v1/convert" mirror_service "code.gitea.io/gitea/services/mirror" ) @@ -669,27 +670,56 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { units = append(units, *unit) } } else if *opts.HasIssues { - // We don't currently allow setting individual issue settings through the API, - // only can enable/disable issues, so when enabling issues, - // we either get the existing config which means it was already enabled, - // or create a new config since it doesn't exist. - unit, err := repo.GetUnit(models.UnitTypeIssues) - var config *models.IssuesConfig - if err != nil { - // Unit type doesn't exist so we make a new config file with default values - config = &models.IssuesConfig{ - EnableTimetracker: true, - AllowOnlyContributorsToTrackTime: true, - EnableDependencies: true, + if opts.ExternalTracker != nil { + + // Check that values are valid + if !validation.IsValidExternalURL(opts.ExternalTracker.ExternalTrackerURL) { + err := fmt.Errorf("External tracker URL not valid") + ctx.Error(http.StatusUnprocessableEntity, "Invalid external tracker URL", err) + return err } + if len(opts.ExternalTracker.ExternalTrackerFormat) != 0 && !validation.IsValidExternalTrackerURLFormat(opts.ExternalTracker.ExternalTrackerFormat) { + err := fmt.Errorf("External tracker URL format not valid") + ctx.Error(http.StatusUnprocessableEntity, "Invalid external tracker URL format", err) + return err + } + + units = append(units, models.RepoUnit{ + RepoID: repo.ID, + Type: models.UnitTypeExternalTracker, + Config: &models.ExternalTrackerConfig{ + ExternalTrackerURL: opts.ExternalTracker.ExternalTrackerURL, + ExternalTrackerFormat: opts.ExternalTracker.ExternalTrackerFormat, + ExternalTrackerStyle: opts.ExternalTracker.ExternalTrackerStyle, + }, + }) } else { - config = unit.IssuesConfig() + // Default to built-in tracker + var config *models.IssuesConfig + + if opts.InternalTracker != nil { + config = &models.IssuesConfig{ + EnableTimetracker: opts.InternalTracker.EnableTimeTracker, + AllowOnlyContributorsToTrackTime: opts.InternalTracker.AllowOnlyContributorsToTrackTime, + EnableDependencies: opts.InternalTracker.EnableIssueDependencies, + } + } else if unit, err := repo.GetUnit(models.UnitTypeIssues); err != nil { + // Unit type doesn't exist so we make a new config file with default values + config = &models.IssuesConfig{ + EnableTimetracker: true, + AllowOnlyContributorsToTrackTime: true, + EnableDependencies: true, + } + } else { + config = unit.IssuesConfig() + } + + units = append(units, models.RepoUnit{ + RepoID: repo.ID, + Type: models.UnitTypeIssues, + Config: config, + }) } - units = append(units, models.RepoUnit{ - RepoID: repo.ID, - Type: models.UnitTypeIssues, - Config: config, - }) } if opts.HasWiki == nil { @@ -700,16 +730,30 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { units = append(units, *unit) } } else if *opts.HasWiki { - // We don't currently allow setting individual wiki settings through the API, - // only can enable/disable the wiki, so when enabling the wiki, - // we either get the existing config which means it was already enabled, - // or create a new config since it doesn't exist. - config := &models.UnitConfig{} - units = append(units, models.RepoUnit{ - RepoID: repo.ID, - Type: models.UnitTypeWiki, - Config: config, - }) + if opts.ExternalWiki != nil { + + // Check that values are valid + if !validation.IsValidExternalURL(opts.ExternalWiki.ExternalWikiURL) { + err := fmt.Errorf("External wiki URL not valid") + ctx.Error(http.StatusUnprocessableEntity, "", "Invalid external wiki URL") + return err + } + + units = append(units, models.RepoUnit{ + RepoID: repo.ID, + Type: models.UnitTypeExternalWiki, + Config: &models.ExternalWikiConfig{ + ExternalWikiURL: opts.ExternalWiki.ExternalWikiURL, + }, + }) + } else { + config := &models.UnitConfig{} + units = append(units, models.RepoUnit{ + RepoID: repo.ID, + Type: models.UnitTypeWiki, + Config: config, + }) + } } if opts.HasPullRequests == nil { diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index fcc26f5c54bcd..d8750d8bcce46 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -8469,6 +8469,12 @@ "type": "string", "x-go-name": "Description" }, + "external_tracker": { + "$ref": "#/definitions/ExternalTracker" + }, + "external_wiki": { + "$ref": "#/definitions/ExternalWiki" + }, "has_issues": { "description": "either `true` to enable issues for this repository or `false` to disable them.", "type": "boolean", @@ -8489,6 +8495,9 @@ "type": "boolean", "x-go-name": "IgnoreWhitespaceConflicts" }, + "internal_tracker": { + "$ref": "#/definitions/InternalTracker" + }, "name": { "description": "name of the repository", "type": "string", @@ -8644,6 +8653,40 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "ExternalTracker": { + "description": "ExternalTracker represents settings for external tracker", + "type": "object", + "properties": { + "external_tracker_format": { + "description": "External Issue Tracker URL Format. Use the placeholders {user}, {repo} and {index} for the username, repository name and issue index.", + "type": "string", + "x-go-name": "ExternalTrackerFormat" + }, + "external_tracker_style": { + "description": "External Issue Tracker Number Format, either `numeric` or `alphanumeric`", + "type": "string", + "x-go-name": "ExternalTrackerStyle" + }, + "external_tracker_url": { + "description": "URL of external issue tracker.", + "type": "string", + "x-go-name": "ExternalTrackerURL" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, + "ExternalWiki": { + "description": "ExternalWiki represents setting for external wiki", + "type": "object", + "properties": { + "external_wiki_url": { + "description": "URL of external wiki.", + "type": "string", + "x-go-name": "ExternalWikiURL" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "FileCommitResponse": { "type": "object", "title": "FileCommitResponse contains information generated from a Git commit for a repo's file.", @@ -9008,6 +9051,28 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "InternalTracker": { + "description": "InternalTracker represents settings for internal tracker", + "type": "object", + "properties": { + "allow_only_contributors_to_track_time": { + "description": "Let only contributors track time (Built-in issue tracker)", + "type": "boolean", + "x-go-name": "AllowOnlyContributorsToTrackTime" + }, + "enable_issue_dependencies": { + "description": "Enable dependencies for issues and pull requests (Built-in issue tracker)", + "type": "boolean", + "x-go-name": "EnableIssueDependencies" + }, + "enable_time_tracker": { + "description": "Enable time tracking (Built-in issue tracker)", + "type": "boolean", + "x-go-name": "EnableTimeTracker" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "Issue": { "description": "Issue represents an issue in a repository", "type": "object", @@ -9863,6 +9928,12 @@ "type": "boolean", "x-go-name": "Empty" }, + "external_tracker": { + "$ref": "#/definitions/ExternalTracker" + }, + "external_wiki": { + "$ref": "#/definitions/ExternalWiki" + }, "fork": { "type": "boolean", "x-go-name": "Fork" @@ -9901,6 +9972,9 @@ "type": "boolean", "x-go-name": "IgnoreWhitespaceConflicts" }, + "internal_tracker": { + "$ref": "#/definitions/InternalTracker" + }, "mirror": { "type": "boolean", "x-go-name": "Mirror" From bcd4af483d58b538d609c0a0acacbbdb8dd82d08 Mon Sep 17 00:00:00 2001 From: Aam Surganda Date: Wed, 2 Oct 2019 19:58:40 +0700 Subject: [PATCH 011/173] Change general form binding to gogs form (#8334) --- routers/repo/webhook.go | 13 +++++-------- routers/routes/routes.go | 8 ++++---- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/routers/repo/webhook.go b/routers/repo/webhook.go index 0711270cb9fd7..48b4e7afff66e 100644 --- a/routers/repo/webhook.go +++ b/routers/repo/webhook.go @@ -198,20 +198,17 @@ func WebHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) { } // GogsHooksNewPost response for creating webhook -func GogsHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) { - newGenericWebhookPost(ctx, form, models.GOGS) +func GogsHooksNewPost(ctx *context.Context, form auth.NewGogshookForm) { + newGogsWebhookPost(ctx, form, models.GOGS) } -func newGenericWebhookPost(ctx *context.Context, form auth.NewWebhookForm, kind models.HookTaskType) { +// newGogsWebhookPost response for creating gogs hook +func newGogsWebhookPost(ctx *context.Context, form auth.NewGogshookForm, kind models.HookTaskType) { ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook") ctx.Data["PageIsSettingsHooks"] = true ctx.Data["PageIsSettingsHooksNew"] = true ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}} - - ctx.Data["HookType"] = "gitea" - if kind == models.GOGS { - ctx.Data["HookType"] = "gogs" - } + ctx.Data["HookType"] = "gogs" orCtx, err := getOrgRepoCtx(ctx) if err != nil { diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 5262d4ad5cf7f..11f2029226a7a 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -444,7 +444,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/delete", admin.DeleteDefaultWebhook) m.Get("/:type/new", repo.WebhooksNew) m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost) - m.Post("/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.GogsHooksNewPost) + m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost) m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost) @@ -452,7 +452,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/msteams/new", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost) m.Get("/:id", repo.WebHooksEdit) m.Post("/gitea/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost) - m.Post("/gogs/:id", bindIgnErr(auth.NewWebhookForm{}), repo.GogsHooksEditPost) + m.Post("/gogs/:id", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksEditPost) m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost) m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost) m.Post("/dingtalk/:id", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost) @@ -585,7 +585,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/delete", org.DeleteWebhook) m.Get("/:type/new", repo.WebhooksNew) m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost) - m.Post("/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.GogsHooksNewPost) + m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost) m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost) @@ -647,7 +647,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/delete", repo.DeleteWebhook) m.Get("/:type/new", repo.WebhooksNew) m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost) - m.Post("/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.GogsHooksNewPost) + m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost) m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost) From 0d93430695d91bd31f6169d5d58d5d9aaf32a3a7 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Wed, 2 Oct 2019 13:01:01 +0000 Subject: [PATCH 012/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_ja-JP.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index e464b016b1b55..ca38757e1c7fe 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -1325,6 +1325,7 @@ settings.protect_merge_whitelist_committers_desc=ホワイトリストに登録 settings.protect_merge_whitelist_users=マージ・ホワイトリストに含むユーザー: settings.protect_merge_whitelist_teams=マージ・ホワイトリストに含むチーム: settings.protect_check_status_contexts=ステータスチェックを有効にする +settings.protect_check_status_contexts_desc=マージの前にステータスチェックがパスしていることを必須にします。 このルールの対象ブランチへのマージが可能となるまでに、事前にパスしている必要があるステータスチェックを選んでください。 有効にする場合は、まずコミットを別のブランチにプッシュし、ステータスチェックがパスしたあと、このルールの対象ブランチにマージするか、直接プッシュするようにします。 条件が選択されていない場合は、最後のコミットが成功していることが必須条件となります。 settings.protect_check_status_contexts_list=1週間の間にこのリポジトリにあったステータスチェック settings.protect_required_approvals=必要な承認数: settings.protect_required_approvals_desc=ホワイトリストに登録したユーザーやチームがレビューを行い、肯定的なレビューの数を満たしたプルリクエストしかマージできないようにします。 From e3eb9fa33d26d5643d99bda4e62796ae377a3867 Mon Sep 17 00:00:00 2001 From: Tekaoh <45337851+Tekaoh@users.noreply.github.com> Date: Wed, 2 Oct 2019 15:02:04 -0500 Subject: [PATCH 013/173] Fix a comment typo (#8358) --- routers/repo/wiki.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/repo/wiki.go b/routers/repo/wiki.go index 54cb4b83dde83..bf8ac658ae7c0 100644 --- a/routers/repo/wiki.go +++ b/routers/repo/wiki.go @@ -55,7 +55,7 @@ func MustEnableWiki(ctx *context.Context) { } } -// PageMeta wiki page meat information +// PageMeta wiki page meta information type PageMeta struct { Name string SubURL string From 3be43dc5e3db1edb2587fce91ee220397493532c Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Wed, 2 Oct 2019 20:04:16 +0000 Subject: [PATCH 014/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_tr-TR.ini | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index 5c90a682508a1..9fa1b7d42b130 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -518,6 +518,7 @@ delete_account_title=Kullanıcı Hesabını Silin delete_account_desc=Bu kullanıcı hesabını kalıcı olarak silmek istediğinizden emin misiniz? email_notifications.enable=E-posta Bildirimlerini Etkinleştir +email_notifications.onmention=Sadece Bahsedilen E-posta email_notifications.disable=E-posta Bildirimlerini Devre Dışı Bırak email_notifications.submit=E-posta Tercihlerini Ayarla @@ -691,6 +692,8 @@ commits.newer=Daha yeni commits.signed_by=İmzalayan commits.gpg_key_id=GPC Anahtar Kimliği +ext_issues=Dışsal Konular +ext_issues.desc=Dışsal konu takip sistemine bağla. issues.desc=Hata raporlarını, görevleri ve kilometre taşlarını yönetmenizi sağlar. issues.new=Yeni Sorun @@ -784,6 +787,8 @@ issues.reopened_at=`%[2]s yeniden açtı` issues.commit_ref_at=`%[2]s işlemesinde bu sorunu işaret etti` issues.ref_issue_at=`bu konudan bahsetti %[1]s` issues.ref_pull_at=`bu değişiklik isteğinden bahsetti %[1]s` +issues.ref_issue_ext_at=`%[1]s'den bu konuya değinildi %[2]s` +issues.ref_pull_ext_at=`%[1]s'den bu değişiklik isteğine değinildi %[2]s` issues.poster=Poster issues.collaborator=Katkıcı issues.owner=Sahibi @@ -800,6 +805,7 @@ issues.label_edit=Düzenle issues.label_delete=Sil issues.label_modify=Etiketi Düzenle issues.label_deletion=Etiketi Sil +issues.label_deletion_desc=Bir etiketi silmek onu bütün konulardan kaldırır. Devam edilsin mi? issues.label_deletion_success=Etiket silindi. issues.label.filter_sort.alphabetically=Alfabetik issues.label.filter_sort.reverse_alphabetically=Ters alfabetik @@ -815,11 +821,13 @@ issues.unlock=Konuşmanın kilidini aç issues.lock.unknown_reason=Sebep belirtmeden konuyu kilitleyemezsiniz. issues.lock_duplicate=Bir konu iki kez kilitlenemez. issues.unlock_error=Kilitlenmemiş bir konunun kilidini açamazsınız. +issues.lock_with_reason=%s olarak kilitlendi ve katkıcılar için sınırlandırıldı %s issues.lock_no_reason=konuşma kilitlendi ve katkıcılar için sınırlandırıldı %s issues.unlock_comment=bu konuşmanın kilidini açtı %s issues.lock_confirm=Kilitle issues.unlock_confirm=Kilidi Aç issues.lock.notice_1=- Diğer kullanıcılar bu konuya yeni yorum ekleyemez. +issues.lock.notice_2=- Siz ve bu depoya erişimi olan diğer katkıcılar, başkalarının görebileceği yorumlar bırakabilir. issues.lock.notice_3=- Her zaman bu konunun kilidini açabilirsiniz. issues.unlock.notice_1=- Herkes bu konuda bir kez daha yorum yapabilir. issues.unlock.notice_2=- İlerde her zaman bu konuyu kilitleyebilirsiniz. @@ -850,6 +858,7 @@ issues.due_date_form=yyyy-aa-gg issues.due_date_form_add=Bitiş tarihi ekle issues.due_date_form_edit=Düzenle issues.due_date_form_remove=Kaldır +issues.due_date_not_writer=Bir konunun bitiş tarihini değiştirmek için depoda yazma hakkınız olmalıdır. issues.due_date_not_set=Bitiş tarihi atanmadı. issues.dependency.title=Bağımlılıklar issues.dependency.issue_no_dependencies=Bu konu henüz bir bağımlılık içermiyor. @@ -888,8 +897,11 @@ issues.review.reviewers=Gözden Geçirenler pulls.desc=Değişiklik isteklerini ve kod incelemelerini etkinleştir. pulls.new=Yeni Değişiklik İsteği pulls.compare_changes=Yeni Değişiklik İsteği +pulls.compare_compare=şuradan çek pulls.filter_branch=Dal filtrele pulls.no_results=Sonuç bulunamadı. +pulls.nothing_to_compare=Bu dallar eşit. Değişiklik isteği oluşturmaya gerek yok. +pulls.has_pull_request=`Bu dallar arasında bir değişiklik isteği zaten var: %[2]s#%[3]d` pulls.create=Değişiklik İsteği Oluştur pulls.title_desc=%[3]s içindeki %[2]s işlemelerini %[1]d ile birleştirmek istiyor pulls.merged_title_desc=%[3]s %[4]s içindeki %[2]s işlemelerini %[1]d ile birleştirdi @@ -1021,6 +1033,7 @@ activity.title.releases_n=%d Serbest bırakmalar activity.title.releases_published_by=%s tarafından %s yayınlandı activity.published_release_label=Yayınlandı activity.no_git_activity=Bu dönemde herhangi bir işleme yapılmamıştır. +activity.git_stats_exclude_merges=Birleştirmeler hariç, activity.git_stats_author_1=%d yazar activity.git_stats_author_n=%d yazar activity.git_stats_pushed_1=itti @@ -1125,19 +1138,24 @@ settings.team_not_in_organization=Takım, depo ile aynı organizasyonda değil settings.add_team_duplicate=Takım zaten bu depoya sahip settings.add_team_success=Takım artık bu depoya erişebilir. settings.add_webhook=Web İsteği Ekle +settings.hooks_desc=Web istemcileri, belirli Gitea olayları tetiklendiğinde otomatik olarak bir sunucuya HTTP POST isteği yapar. Web istekleri kılavuzundan daha fazla bilgi edinebilirsiniz. settings.webhook_deletion=Web İsteğini Sil +settings.webhook_deletion_desc=Bir web isteğini kaldırmak, ayarlarını ve teslimat geçmişini siler. Devam edilsin mi? settings.webhook_deletion_success=Web isteği silindi. settings.webhook.test_delivery=Test Dağıtımı settings.webhook.test_delivery_desc=Bu web isteğini sahte bir olayla test edin. +settings.webhook.test_delivery_success=Teslim sırasına sahte bir olay eklendi. Teslim geçmişinde görünmesi birkaç saniye sürebilir. settings.webhook.request=İstekler settings.webhook.response=Cevaplar settings.webhook.headers=Başlıklar settings.webhook.payload=İçerik settings.webhook.body=Gövde +settings.githooks_desc=Git istekleri Git'in kendisi tarafından desteklenmektedir. Özel işlemler ayarlamak için aşağıdaki istek dosyalarını düzenleyebilirsiniz. settings.githook_edit_desc=İstek aktif değilse örnek içerik sunulacaktır. İçeriği boş bırakmak, isteği devre dışı bırakmayı beraberinde getirecektir. settings.githook_name=İstek İsmi settings.githook_content=İstek İçeriği settings.update_githook=İsteği Güncelle +settings.add_webhook_desc=Gitea, belirtilen içerik türüne sahip POST isteğini hedef URL’ye gönderecektir. Web istekleri kılavuzundan daha fazla bilgi edinebilirsiniz. settings.payload_url=Hedef URL settings.http_method=HTTP Yöntemi settings.content_type=POST İçerik Türü @@ -1171,6 +1189,7 @@ settings.branch_filter=Dal filtresi settings.event_repository=Depo settings.event_repository_desc=Depo oluşturuldu veya silindi. settings.active=Etkin +settings.active_helper=Tetiklenen olaylar hakkındaki bilgiler bu web isteği URL'sine gönderilir. settings.add_hook_success=Web isteği eklendi. settings.update_webhook=Web İsteğini Düzenle settings.update_hook_success=Web isteği güncellendi. @@ -1262,6 +1281,7 @@ diff.whitespace_button=Boşluk diff.whitespace_show_everything=Tüm değişiklikleri göster diff.whitespace_ignore_all_whitespace=Satırları karşılaştırırken boşluğu yoksay diff.whitespace_ignore_amount_changes=Boşluk miktarındaki değişiklikleri yoksay +diff.whitespace_ignore_at_eol=Satır sonundaki boşluk değişiklikleri yoksay diff.stats_desc= %d değiştirilmiş dosya ile %d ekleme ve %d silme diff.bin=BIN diff.view_file=Dosyayı Görüntüle @@ -1291,6 +1311,7 @@ release.stable=Kararlı release.edit=düzenle release.ahead=%s son sürümden beri %d işleme release.source_code=Kaynak Kodu +release.new_subheader=Sürümler proje versiyonlarını yönetmenizi sağlar. release.edit_subheader=Sürümler proje versiyonlarını yönetmenizi sağlar. release.tag_name=Biçim imi adı release.target=Hedef @@ -1305,7 +1326,10 @@ release.save_draft=Taslağı Kaydet release.edit_release=Sürümü Güncelle release.delete_release=Sürümü Sil release.deletion=Sürümü Sil +release.deletion_desc=Bir sürümün silinmesi Git etiketini depodan kaldırır. Depo içerikleri ve tarihçeleri değişmeden kalır. Devam edilsin mi? release.deletion_success=Sürüm silindi. +release.tag_name_already_exist=Bu etiket adına sahip bir sürüm zaten var. +release.tag_name_invalid=Etiket adı geçerli değil. release.downloads=İndirmeler branch.name=Dal Adı @@ -1425,7 +1449,7 @@ teams.repos.none=Bu takım tarafından hiçbir depoya erişilemedi. teams.members.none=Bu takımda üye yok. [admin] -dashboard=Başlangıç +dashboard=Pano users=Kullanıcı Hesapları organizations=Organizasyonlar repositories=Depolar @@ -1715,6 +1739,7 @@ monitor.name=İsim monitor.schedule=Program monitor.next=Sonraki Zaman monitor.previous=Önceki Zaman +monitor.execute_times=Çalıştırma monitor.process=Çalışan Süreçler monitor.desc=Açıklama monitor.start=Başlangıç Zamanı @@ -1737,6 +1762,7 @@ notices.delete_success=Sistem bildirimleri silindi. [action] create_repo=depo %s oluşturuldu rename_repo=%[1]s olan depo adını %[3]s buna çevirdi +commit_repo=%[4]s deposunda %[3]s dalını itti create_issue=`%s#%[2]s sorununu açtı` close_issue=`%s#%[2]s sorununu kapattı` reopen_issue=`%s#%[2]s sorununu tekrar açtı` @@ -1746,8 +1772,12 @@ reopen_pull_request=`%s#%[2]s değişiklik isteğini t comment_issue=`%s#%[2]s sorununa yorum yazdı` merge_pull_request=`%s#%[2]s değişim isteğini birleştirdi` transfer_repo=depo %s %s'a aktarıldı +push_tag=%[3]s deposuna %[2]s etiketi itildi +delete_tag=%[2]s etiketi %[3]s deposundan silindi +delete_branch=%[3]s deposundan %[2]s dalı silindi compare_commits=%d işlemeyi karşılaştır compare_commits_general=İşlemeleri karşılaştır +mirror_sync_push=işlemeler yansıdan %[4]s deposundaki %[3]s dalına eşitlendi [tool] ago=%s önce From c9f819eae0ac9cdce82e25abe25c067b1927e923 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 3 Oct 2019 04:47:20 +0800 Subject: [PATCH 015/173] Upgrade xorm to v0.7.9 to fix some bugs (#8354) * upgrade xorm to v0.7.9 to fix some bugs * upgrade xormstore to v1.3.1 --- go.mod | 4 +- go.sum | 8 +- vendor/github.com/go-xorm/xorm/.drone.yml | 116 +++++++-- .../github.com/go-xorm/xorm/dialect_mssql.go | 22 +- .../github.com/go-xorm/xorm/dialect_mysql.go | 16 +- .../go-xorm/xorm/dialect_postgres.go | 32 ++- .../go-xorm/xorm/dialect_sqlite3.go | 98 ++++--- vendor/github.com/go-xorm/xorm/engine.go | 58 +++-- .../github.com/go-xorm/xorm/session_schema.go | 241 +++++++++--------- vendor/github.com/go-xorm/xorm/statement.go | 8 + vendor/github.com/go-xorm/xorm/tag.go | 1 + vendor/github.com/go-xorm/xorm/test_mssql.sh | 2 +- vendor/github.com/lafriks/xormstore/go.mod | 3 +- vendor/github.com/lafriks/xormstore/go.sum | 4 +- vendor/modules.txt | 4 +- 15 files changed, 380 insertions(+), 237 deletions(-) diff --git a/go.mod b/go.mod index 08a663dcdd837..e1a2b7b4044a9 100644 --- a/go.mod +++ b/go.mod @@ -48,7 +48,7 @@ require ( github.com/go-redis/redis v6.15.2+incompatible github.com/go-sql-driver/mysql v1.4.1 github.com/go-swagger/go-swagger v0.20.1 - github.com/go-xorm/xorm v0.7.8 + github.com/go-xorm/xorm v0.7.9 github.com/gobwas/glob v0.2.3 github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 @@ -64,7 +64,7 @@ require ( github.com/klauspost/compress v0.0.0-20161025140425-8df558b6cb6f github.com/klauspost/cpuid v0.0.0-20160302075316-09cded8978dc // indirect github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6 // indirect - github.com/lafriks/xormstore v1.3.0 + github.com/lafriks/xormstore v1.3.1 github.com/lib/pq v1.2.0 github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 github.com/lunny/levelqueue v0.0.0-20190217115915-02b525a4418e diff --git a/go.sum b/go.sum index 10ad062635280..c068caa2f74f7 100644 --- a/go.sum +++ b/go.sum @@ -249,8 +249,8 @@ github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013 h1:l github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013/go.mod h1:b65mBPzqzZWxOZGxSWrqs4GInLIn+u99Q9q7p+GKni0= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= -github.com/go-xorm/xorm v0.7.8 h1:rKxZJB9mWQ9Nw2TbjsepiThR031jkGePOWXwTtEAU08= -github.com/go-xorm/xorm v0.7.8/go.mod h1:XiVxrMMIhFkwSkh96BW7PACl7UhLtx2iJIHMdmjh5sQ= +github.com/go-xorm/xorm v0.7.9 h1:LZze6n1UvRmM5gpL9/U9Gucwqo6aWlFVlfcHKH10qA0= +github.com/go-xorm/xorm v0.7.9/go.mod h1:XiVxrMMIhFkwSkh96BW7PACl7UhLtx2iJIHMdmjh5sQ= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -384,8 +384,8 @@ github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lafriks/xormstore v1.3.0 h1:9A2wAZrdEXtTgfjCFtclPz3pwnmmxY7sJxQgIi62li4= -github.com/lafriks/xormstore v1.3.0/go.mod h1:RAhtOztWBjK9xeZpXwKq59rhUxoRgo1zfYl0H1mtK7A= +github.com/lafriks/xormstore v1.3.1 h1:KpzRUamSV3zmA85Kzw+PZOU9wgMbYsNzuDzLuBMbxpA= +github.com/lafriks/xormstore v1.3.1/go.mod h1:qALRD4Vto2Ic7/A5eplMpu5V62mugtSqFysRwz8FETs= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= diff --git a/vendor/github.com/go-xorm/xorm/.drone.yml b/vendor/github.com/go-xorm/xorm/.drone.yml index bd682e5ff16da..b162d7c8a4ff3 100644 --- a/vendor/github.com/go-xorm/xorm/.drone.yml +++ b/vendor/github.com/go-xorm/xorm/.drone.yml @@ -114,7 +114,18 @@ steps: commands: - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic" - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic" - - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt > coverage.txt + when: + event: + - push + - pull_request + +- name: test-tidb + pull: default + image: golang:1.10 + commands: + - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -coverprofile=coverage7-1.txt -covermode=atomic" + - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -cache=true -coverprofile=coverage7-2.txt -covermode=atomic" + - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt coverage7-1.txt coverage7-2.txt > coverage.txt when: event: - push @@ -133,6 +144,15 @@ services: - tag - pull_request +- name: tidb + pull: default + image: pingcap/tidb:v3.0.3 + when: + event: + - push + - tag + - pull_request + - name: pgsql pull: default image: postgres:9.5 @@ -309,8 +329,23 @@ steps: commands: - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic" - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic" + + when: + event: + - push + - pull_request + +- name: test-tidb + pull: default + image: golang:1.11 + environment: + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" + commands: + - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -coverprofile=coverage7-1.txt -covermode=atomic" + - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -cache=true -coverprofile=coverage7-2.txt -covermode=atomic" - go get github.com/wadey/gocovmerge - - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt > coverage.txt + - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt coverage7-1.txt coverage7-2.txt > coverage.txt when: event: - push @@ -329,6 +364,15 @@ services: - tag - pull_request +- name: tidb + pull: default + image: pingcap/tidb:v3.0.3 + when: + event: + - push + - tag + - pull_request + - name: pgsql pull: default image: postgres:9.5 @@ -377,13 +421,6 @@ steps: depth: 50 tags: true -- name: init_postgres - pull: default - image: postgres:9.5 - commands: - - "until psql -U postgres -d xorm_test -h pgsql \\\n -c \"SELECT 1;\" >/dev/null 2>&1; do sleep 1; done\n" - - "psql -U postgres -d xorm_test -h pgsql \\\n -c \"create schema xorm;\"\n" - - name: build pull: default image: golang:1.12 @@ -505,8 +542,22 @@ steps: commands: - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic" - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic" - - go get -u github.com/wadey/gocovmerge - - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt > coverage.txt + when: + event: + - push + - pull_request + +- name: test-tidb + pull: default + image: golang:1.12 + environment: + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" + commands: + - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -coverprofile=coverage7-1.txt -covermode=atomic" + - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -cache=true -coverprofile=coverage7-2.txt -covermode=atomic" + - go get github.com/wadey/gocovmerge + - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt coverage7-1.txt coverage7-2.txt > coverage.txt when: event: - push @@ -525,6 +576,15 @@ services: - tag - pull_request +- name: tidb + pull: default + image: pingcap/tidb:v3.0.3 + when: + event: + - push + - tag + - pull_request + - name: pgsql pull: default image: postgres:9.5 @@ -573,13 +633,6 @@ steps: depth: 50 tags: true -- name: init_postgres - pull: default - image: postgres:9.5 - commands: - - "until psql -U postgres -d xorm_test -h pgsql \\\n -c \"SELECT 1;\" >/dev/null 2>&1; do sleep 1; done\n" - - "psql -U postgres -d xorm_test -h pgsql \\\n -c \"create schema xorm;\"\n" - - name: build pull: default image: golang:1.13 @@ -701,8 +754,22 @@ steps: commands: - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic" - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic" - - go get -u github.com/wadey/gocovmerge - - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt > coverage.txt + when: + event: + - push + - pull_request + +- name: test-tidb + pull: default + image: golang:1.13 + environment: + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" + commands: + - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -coverprofile=coverage7-1.txt -covermode=atomic" + - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -cache=true -coverprofile=coverage7-2.txt -covermode=atomic" + - go get github.com/wadey/gocovmerge + - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt coverage7-1.txt coverage7-2.txt > coverage.txt when: event: - push @@ -721,6 +788,15 @@ services: - tag - pull_request +- name: tidb + pull: default + image: pingcap/tidb:v3.0.3 + when: + event: + - push + - tag + - pull_request + - name: pgsql pull: default image: postgres:9.5 diff --git a/vendor/github.com/go-xorm/xorm/dialect_mssql.go b/vendor/github.com/go-xorm/xorm/dialect_mssql.go index ce4dd00c19bd6..29070da2fbec3 100644 --- a/vendor/github.com/go-xorm/xorm/dialect_mssql.go +++ b/vendor/github.com/go-xorm/xorm/dialect_mssql.go @@ -338,8 +338,9 @@ func (db *mssql) TableCheckSql(tableName string) (string, []interface{}) { func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { args := []interface{}{} s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale,a.is_nullable as nullable, + "default_is_null" = (CASE WHEN c.text is null THEN 1 ELSE 0 END), replace(replace(isnull(c.text,''),'(',''),')','') as vdefault, - ISNULL(i.is_primary_key, 0) + ISNULL(i.is_primary_key, 0), a.is_identity as is_identity from sys.columns a left join sys.types b on a.user_type_id=b.user_type_id left join sys.syscomments c on a.default_object_id=c.id @@ -361,8 +362,8 @@ func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column for rows.Next() { var name, ctype, vdefault string var maxLen, precision, scale int - var nullable, isPK bool - err = rows.Scan(&name, &ctype, &maxLen, &precision, &scale, &nullable, &vdefault, &isPK) + var nullable, isPK, defaultIsNull, isIncrement bool + err = rows.Scan(&name, &ctype, &maxLen, &precision, &scale, &nullable, &defaultIsNull, &vdefault, &isPK, &isIncrement) if err != nil { return nil, nil, err } @@ -371,8 +372,12 @@ func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column col.Indexes = make(map[string]int) col.Name = strings.Trim(name, "` ") col.Nullable = nullable - col.Default = vdefault + col.DefaultIsEmpty = defaultIsNull + if !defaultIsNull { + col.Default = vdefault + } col.IsPrimaryKey = isPK + col.IsAutoIncrement = isIncrement ct := strings.ToUpper(ctype) if ct == "DECIMAL" { col.Length = precision @@ -395,15 +400,6 @@ func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column } } - if col.SQLType.IsText() || col.SQLType.IsTime() { - if col.Default != "" { - col.Default = "'" + col.Default + "'" - } else { - if col.DefaultIsEmpty { - col.Default = "''" - } - } - } cols[col.Name] = col colSeq = append(colSeq, col.Name) } diff --git a/vendor/github.com/go-xorm/xorm/dialect_mysql.go b/vendor/github.com/go-xorm/xorm/dialect_mysql.go index a108b81f5e0ca..cf1dbb6f214f3 100644 --- a/vendor/github.com/go-xorm/xorm/dialect_mysql.go +++ b/vendor/github.com/go-xorm/xorm/dialect_mysql.go @@ -345,9 +345,9 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column if colDefault != nil { col.Default = *colDefault - if col.Default == "" { - col.DefaultIsEmpty = true - } + col.DefaultIsEmpty = false + } else { + col.DefaultIsEmpty = true } cts := strings.Split(colType, "(") @@ -411,13 +411,11 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column col.IsAutoIncrement = true } - if col.SQLType.IsText() || col.SQLType.IsTime() { - if col.Default != "" { + if !col.DefaultIsEmpty { + if col.SQLType.IsText() { + col.Default = "'" + col.Default + "'" + } else if col.SQLType.IsTime() && col.Default != "CURRENT_TIMESTAMP" { col.Default = "'" + col.Default + "'" - } else { - if col.DefaultIsEmpty { - col.Default = "''" - } } } cols[col.Name] = col diff --git a/vendor/github.com/go-xorm/xorm/dialect_postgres.go b/vendor/github.com/go-xorm/xorm/dialect_postgres.go index 3df682e81ac4c..ccef3086b264a 100644 --- a/vendor/github.com/go-xorm/xorm/dialect_postgres.go +++ b/vendor/github.com/go-xorm/xorm/dialect_postgres.go @@ -1005,16 +1005,18 @@ WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.att col.Name = strings.Trim(colName, `" `) - if colDefault != nil || isPK { - if isPK { - col.IsPrimaryKey = true - } else { - col.Default = *colDefault + if colDefault != nil { + col.Default = *colDefault + col.DefaultIsEmpty = false + if strings.HasPrefix(col.Default, "nextval(") { + col.IsAutoIncrement = true } + } else { + col.DefaultIsEmpty = true } - if colDefault != nil && strings.HasPrefix(*colDefault, "nextval(") { - col.IsAutoIncrement = true + if isPK { + col.IsPrimaryKey = true } col.Nullable = (isNullable == "YES") @@ -1043,12 +1045,16 @@ WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.att col.Length = maxLen - if col.SQLType.IsText() || col.SQLType.IsTime() { - if col.Default != "" { - col.Default = "'" + col.Default + "'" - } else { - if col.DefaultIsEmpty { - col.Default = "''" + if !col.DefaultIsEmpty { + if col.SQLType.IsText() { + if strings.HasSuffix(col.Default, "::character varying") { + col.Default = strings.TrimRight(col.Default, "::character varying") + } else if !strings.HasPrefix(col.Default, "'") { + col.Default = "'" + col.Default + "'" + } + } else if col.SQLType.IsTime() { + if strings.HasSuffix(col.Default, "::timestamp without time zone") { + col.Default = strings.TrimRight(col.Default, "::timestamp without time zone") } } } diff --git a/vendor/github.com/go-xorm/xorm/dialect_sqlite3.go b/vendor/github.com/go-xorm/xorm/dialect_sqlite3.go index 60f07295e843b..0a290f3c480df 100644 --- a/vendor/github.com/go-xorm/xorm/dialect_sqlite3.go +++ b/vendor/github.com/go-xorm/xorm/dialect_sqlite3.go @@ -270,6 +270,68 @@ func (db *sqlite3) IsColumnExist(tableName, colName string) (bool, error) { return false, nil } +// splitColStr splits a sqlite col strings as fields +func splitColStr(colStr string) []string { + colStr = strings.TrimSpace(colStr) + var results = make([]string, 0, 10) + var lastIdx int + var hasC, hasQuote bool + for i, c := range colStr { + if c == ' ' && !hasQuote { + if hasC { + results = append(results, colStr[lastIdx:i]) + hasC = false + } + } else { + if c == '\'' { + hasQuote = !hasQuote + } + if !hasC { + lastIdx = i + } + hasC = true + if i == len(colStr)-1 { + results = append(results, colStr[lastIdx:i+1]) + } + } + } + return results +} + +func parseString(colStr string) (*core.Column, error) { + fields := splitColStr(colStr) + col := new(core.Column) + col.Indexes = make(map[string]int) + col.Nullable = true + col.DefaultIsEmpty = true + + for idx, field := range fields { + if idx == 0 { + col.Name = strings.Trim(strings.Trim(field, "`[] "), `"`) + continue + } else if idx == 1 { + col.SQLType = core.SQLType{Name: field, DefaultLength: 0, DefaultLength2: 0} + continue + } + switch field { + case "PRIMARY": + col.IsPrimaryKey = true + case "AUTOINCREMENT": + col.IsAutoIncrement = true + case "NULL": + if fields[idx-1] == "NOT" { + col.Nullable = false + } else { + col.Nullable = true + } + case "DEFAULT": + col.Default = fields[idx+1] + col.DefaultIsEmpty = false + } + } + return col, nil +} + func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { args := []interface{}{tableName} s := "SELECT sql FROM sqlite_master WHERE type='table' and name = ?" @@ -299,6 +361,7 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Colu colCreates := reg.FindAllString(name[nStart+1:nEnd], -1) cols := make(map[string]*core.Column) colSeq := make([]string, 0) + for _, colStr := range colCreates { reg = regexp.MustCompile(`,\s`) colStr = reg.ReplaceAllString(colStr, ",") @@ -315,38 +378,11 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Colu continue } - fields := strings.Fields(strings.TrimSpace(colStr)) - col := new(core.Column) - col.Indexes = make(map[string]int) - col.Nullable = true - col.DefaultIsEmpty = true - - for idx, field := range fields { - if idx == 0 { - col.Name = strings.Trim(strings.Trim(field, "`[] "), `"`) - continue - } else if idx == 1 { - col.SQLType = core.SQLType{Name: field, DefaultLength: 0, DefaultLength2: 0} - } - switch field { - case "PRIMARY": - col.IsPrimaryKey = true - case "AUTOINCREMENT": - col.IsAutoIncrement = true - case "NULL": - if fields[idx-1] == "NOT" { - col.Nullable = false - } else { - col.Nullable = true - } - case "DEFAULT": - col.Default = fields[idx+1] - col.DefaultIsEmpty = false - } - } - if !col.SQLType.IsNumeric() && !col.DefaultIsEmpty { - col.Default = "'" + col.Default + "'" + col, err := parseString(colStr) + if err != nil { + return colSeq, cols, err } + cols[col.Name] = col colSeq = append(colSeq, col.Name) } diff --git a/vendor/github.com/go-xorm/xorm/engine.go b/vendor/github.com/go-xorm/xorm/engine.go index 649fd1e306bc0..4ed0f77a9269a 100644 --- a/vendor/github.com/go-xorm/xorm/engine.go +++ b/vendor/github.com/go-xorm/xorm/engine.go @@ -377,6 +377,32 @@ func (engine *Engine) NoAutoCondition(no ...bool) *Session { return session.NoAutoCondition(no...) } +func (engine *Engine) loadTableInfo(table *core.Table) error { + colSeq, cols, err := engine.dialect.GetColumns(table.Name) + if err != nil { + return err + } + for _, name := range colSeq { + table.AddColumn(cols[name]) + } + indexes, err := engine.dialect.GetIndexes(table.Name) + if err != nil { + return err + } + table.Indexes = indexes + + for _, index := range indexes { + for _, name := range index.Cols { + if col := table.GetColumn(name); col != nil { + col.Indexes[index.Name] = index.Type + } else { + return fmt.Errorf("Unknown col %s in index %v of table %v, columns %v", name, index.Name, table.Name, table.ColumnsSeq()) + } + } + } + return nil +} + // DBMetas Retrieve all tables, columns, indexes' informations from database. func (engine *Engine) DBMetas() ([]*core.Table, error) { tables, err := engine.dialect.GetTables() @@ -385,28 +411,9 @@ func (engine *Engine) DBMetas() ([]*core.Table, error) { } for _, table := range tables { - colSeq, cols, err := engine.dialect.GetColumns(table.Name) - if err != nil { - return nil, err - } - for _, name := range colSeq { - table.AddColumn(cols[name]) - } - indexes, err := engine.dialect.GetIndexes(table.Name) - if err != nil { + if err = engine.loadTableInfo(table); err != nil { return nil, err } - table.Indexes = indexes - - for _, index := range indexes { - for _, name := range index.Cols { - if col := table.GetColumn(name); col != nil { - col.Indexes[index.Name] = index.Type - } else { - return nil, fmt.Errorf("Unknown col %s in index %v of table %v, columns %v", name, index.Name, table.Name, table.ColumnsSeq()) - } - } - } } return tables, nil } @@ -907,8 +914,15 @@ func (engine *Engine) mapType(v reflect.Value) (*core.Table, error) { fieldType := fieldValue.Type() if ormTagStr != "" { - col = &core.Column{FieldName: t.Field(i).Name, Nullable: true, IsPrimaryKey: false, - IsAutoIncrement: false, MapType: core.TWOSIDES, Indexes: make(map[string]int)} + col = &core.Column{ + FieldName: t.Field(i).Name, + Nullable: true, + IsPrimaryKey: false, + IsAutoIncrement: false, + MapType: core.TWOSIDES, + Indexes: make(map[string]int), + DefaultIsEmpty: true, + } tags := splitTag(ormTagStr) if len(tags) > 0 { diff --git a/vendor/github.com/go-xorm/xorm/session_schema.go b/vendor/github.com/go-xorm/xorm/session_schema.go index da5c88559914a..5e576c29aa103 100644 --- a/vendor/github.com/go-xorm/xorm/session_schema.go +++ b/vendor/github.com/go-xorm/xorm/session_schema.go @@ -228,7 +228,7 @@ func (session *Session) Sync2(beans ...interface{}) error { defer session.Close() } - tables, err := engine.DBMetas() + tables, err := engine.dialect.GetTables() if err != nil { return err } @@ -239,26 +239,29 @@ func (session *Session) Sync2(beans ...interface{}) error { session.resetStatement() }() - var structTables []*core.Table - for _, bean := range beans { v := rValue(bean) table, err := engine.mapType(v) if err != nil { return err } - structTables = append(structTables, table) - tbName := engine.TableName(bean) - tbNameWithSchema := engine.TableName(tbName, true) + var tbName string + if len(session.statement.AltTableName) > 0 { + tbName = session.statement.AltTableName + } else { + tbName = engine.TableName(bean) + } + tbNameWithSchema := engine.tbNameWithSchema(tbName) var oriTable *core.Table for _, tb := range tables { - if strings.EqualFold(tb.Name, tbName) { + if strings.EqualFold(engine.tbNameWithSchema(tb.Name), engine.tbNameWithSchema(tbName)) { oriTable = tb break } } + // this is a new table if oriTable == nil { err = session.StoreEngine(session.statement.StoreEngine).createTable(bean) if err != nil { @@ -274,148 +277,154 @@ func (session *Session) Sync2(beans ...interface{}) error { if err != nil { return err } - } else { - for _, col := range table.Columns() { - var oriCol *core.Column - for _, col2 := range oriTable.Columns() { - if strings.EqualFold(col.Name, col2.Name) { - oriCol = col2 - break - } - } + continue + } - if oriCol != nil { - expectedType := engine.dialect.SqlType(col) - curType := engine.dialect.SqlType(oriCol) - if expectedType != curType { - if expectedType == core.Text && - strings.HasPrefix(curType, core.Varchar) { - // currently only support mysql & postgres - if engine.dialect.DBType() == core.MYSQL || - engine.dialect.DBType() == core.POSTGRES { - engine.logger.Infof("Table %s column %s change type from %s to %s\n", - tbNameWithSchema, col.Name, curType, expectedType) - _, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col)) - } else { - engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s\n", - tbNameWithSchema, col.Name, curType, expectedType) - } - } else if strings.HasPrefix(curType, core.Varchar) && strings.HasPrefix(expectedType, core.Varchar) { - if engine.dialect.DBType() == core.MYSQL { - if oriCol.Length < col.Length { - engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n", - tbNameWithSchema, col.Name, oriCol.Length, col.Length) - _, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col)) - } - } - } else { - if !(strings.HasPrefix(curType, expectedType) && curType[len(expectedType)] == '(') { - engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s", - tbNameWithSchema, col.Name, curType, expectedType) - } - } - } else if expectedType == core.Varchar { - if engine.dialect.DBType() == core.MYSQL { - if oriCol.Length < col.Length { - engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n", - tbNameWithSchema, col.Name, oriCol.Length, col.Length) - _, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col)) - } - } - } - if col.Default != oriCol.Default { - engine.logger.Warnf("Table %s Column %s db default is %s, struct default is %s", - tbName, col.Name, oriCol.Default, col.Default) - } - if col.Nullable != oriCol.Nullable { - engine.logger.Warnf("Table %s Column %s db nullable is %v, struct nullable is %v", - tbName, col.Name, oriCol.Nullable, col.Nullable) - } - } else { - session.statement.RefTable = table - session.statement.tableName = tbNameWithSchema - err = session.addColumn(col.Name) + // this will modify an old table + if err = engine.loadTableInfo(oriTable); err != nil { + return err + } + + // check columns + for _, col := range table.Columns() { + var oriCol *core.Column + for _, col2 := range oriTable.Columns() { + if strings.EqualFold(col.Name, col2.Name) { + oriCol = col2 + break } - if err != nil { + } + + // column is not exist on table + if oriCol == nil { + session.statement.RefTable = table + session.statement.tableName = tbNameWithSchema + if err = session.addColumn(col.Name); err != nil { return err } + continue } - var foundIndexNames = make(map[string]bool) - var addedNames = make(map[string]*core.Index) - - for name, index := range table.Indexes { - var oriIndex *core.Index - for name2, index2 := range oriTable.Indexes { - if index.Equal(index2) { - oriIndex = index2 - foundIndexNames[name2] = true - break + err = nil + expectedType := engine.dialect.SqlType(col) + curType := engine.dialect.SqlType(oriCol) + if expectedType != curType { + if expectedType == core.Text && + strings.HasPrefix(curType, core.Varchar) { + // currently only support mysql & postgres + if engine.dialect.DBType() == core.MYSQL || + engine.dialect.DBType() == core.POSTGRES { + engine.logger.Infof("Table %s column %s change type from %s to %s\n", + tbNameWithSchema, col.Name, curType, expectedType) + _, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col)) + } else { + engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s\n", + tbNameWithSchema, col.Name, curType, expectedType) } - } - - if oriIndex != nil { - if oriIndex.Type != index.Type { - sql := engine.dialect.DropIndexSql(tbNameWithSchema, oriIndex) - _, err = session.exec(sql) - if err != nil { - return err + } else if strings.HasPrefix(curType, core.Varchar) && strings.HasPrefix(expectedType, core.Varchar) { + if engine.dialect.DBType() == core.MYSQL { + if oriCol.Length < col.Length { + engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n", + tbNameWithSchema, col.Name, oriCol.Length, col.Length) + _, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col)) } - oriIndex = nil + } + } else { + if !(strings.HasPrefix(curType, expectedType) && curType[len(expectedType)] == '(') { + engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s", + tbNameWithSchema, col.Name, curType, expectedType) + } + } + } else if expectedType == core.Varchar { + if engine.dialect.DBType() == core.MYSQL { + if oriCol.Length < col.Length { + engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n", + tbNameWithSchema, col.Name, oriCol.Length, col.Length) + _, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col)) } } + } - if oriIndex == nil { - addedNames[name] = index + if col.Default != oriCol.Default { + if (col.SQLType.Name == core.Bool || col.SQLType.Name == core.Boolean) && + ((strings.EqualFold(col.Default, "true") && oriCol.Default == "1") || + (strings.EqualFold(col.Default, "false") && oriCol.Default == "0")) { + } else { + engine.logger.Warnf("Table %s Column %s db default is %s, struct default is %s", + tbName, col.Name, oriCol.Default, col.Default) } } + if col.Nullable != oriCol.Nullable { + engine.logger.Warnf("Table %s Column %s db nullable is %v, struct nullable is %v", + tbName, col.Name, oriCol.Nullable, col.Nullable) + } + + if err != nil { + return err + } + } + + var foundIndexNames = make(map[string]bool) + var addedNames = make(map[string]*core.Index) + for name, index := range table.Indexes { + var oriIndex *core.Index for name2, index2 := range oriTable.Indexes { - if _, ok := foundIndexNames[name2]; !ok { - sql := engine.dialect.DropIndexSql(tbNameWithSchema, index2) + if index.Equal(index2) { + oriIndex = index2 + foundIndexNames[name2] = true + break + } + } + + if oriIndex != nil { + if oriIndex.Type != index.Type { + sql := engine.dialect.DropIndexSql(tbNameWithSchema, oriIndex) _, err = session.exec(sql) if err != nil { return err } + oriIndex = nil } } - for name, index := range addedNames { - if index.Type == core.UniqueType { - session.statement.RefTable = table - session.statement.tableName = tbNameWithSchema - err = session.addUnique(tbNameWithSchema, name) - } else if index.Type == core.IndexType { - session.statement.RefTable = table - session.statement.tableName = tbNameWithSchema - err = session.addIndex(tbNameWithSchema, name) - } + if oriIndex == nil { + addedNames[name] = index + } + } + + for name2, index2 := range oriTable.Indexes { + if _, ok := foundIndexNames[name2]; !ok { + sql := engine.dialect.DropIndexSql(tbNameWithSchema, index2) + _, err = session.exec(sql) if err != nil { return err } } } - } - for _, table := range tables { - var oriTable *core.Table - for _, structTable := range structTables { - if strings.EqualFold(table.Name, session.tbNameNoSchema(structTable)) { - oriTable = structTable - break + for name, index := range addedNames { + if index.Type == core.UniqueType { + session.statement.RefTable = table + session.statement.tableName = tbNameWithSchema + err = session.addUnique(tbNameWithSchema, name) + } else if index.Type == core.IndexType { + session.statement.RefTable = table + session.statement.tableName = tbNameWithSchema + err = session.addIndex(tbNameWithSchema, name) + } + if err != nil { + return err } } - if oriTable == nil { - //engine.LogWarnf("Table %s has no struct to mapping it", table.Name) - continue - } - - for _, colName := range table.ColumnsSeq() { - if oriTable.GetColumn(colName) == nil { - engine.logger.Warnf("Table %s has column %s but struct has not related field", engine.TableName(table.Name, true), colName) + // check all the columns which removed from struct fields but left on database tables. + for _, colName := range oriTable.ColumnsSeq() { + if table.GetColumn(colName) == nil { + engine.logger.Warnf("Table %s has column %s but struct has not related field", engine.TableName(oriTable.Name, true), colName) } } } + return nil } diff --git a/vendor/github.com/go-xorm/xorm/statement.go b/vendor/github.com/go-xorm/xorm/statement.go index 3cc0831eec42a..ae396c4bae4dd 100644 --- a/vendor/github.com/go-xorm/xorm/statement.go +++ b/vendor/github.com/go-xorm/xorm/statement.go @@ -266,6 +266,14 @@ func (statement *Statement) buildUpdates(bean interface{}, continue } + if statement.incrColumns.isColExist(col.Name) { + continue + } else if statement.decrColumns.isColExist(col.Name) { + continue + } else if statement.exprColumns.isColExist(col.Name) { + continue + } + fieldValuePtr, err := col.ValueOf(bean) if err != nil { engine.logger.Error(err) diff --git a/vendor/github.com/go-xorm/xorm/tag.go b/vendor/github.com/go-xorm/xorm/tag.go index 6feb581a4685e..ec8d5cf05bf3c 100644 --- a/vendor/github.com/go-xorm/xorm/tag.go +++ b/vendor/github.com/go-xorm/xorm/tag.go @@ -125,6 +125,7 @@ func DefaultTagHandler(ctx *tagContext) error { ctx.col.Default = ctx.nextTag ctx.ignoreNext = true } + ctx.col.DefaultIsEmpty = false return nil } diff --git a/vendor/github.com/go-xorm/xorm/test_mssql.sh b/vendor/github.com/go-xorm/xorm/test_mssql.sh index e26e164118993..7f060cff32cda 100644 --- a/vendor/github.com/go-xorm/xorm/test_mssql.sh +++ b/vendor/github.com/go-xorm/xorm/test_mssql.sh @@ -1 +1 @@ -go test -db=mssql -conn_str="server=localhost;user id=sa;password=MwantsaSecurePassword1;database=xorm_test" \ No newline at end of file +go test -db=mssql -conn_str="server=localhost;user id=sa;password=yourStrong(!)Password;database=xorm_test" \ No newline at end of file diff --git a/vendor/github.com/lafriks/xormstore/go.mod b/vendor/github.com/lafriks/xormstore/go.mod index a0386f1256555..1a68ce65136e3 100644 --- a/vendor/github.com/lafriks/xormstore/go.mod +++ b/vendor/github.com/lafriks/xormstore/go.mod @@ -3,10 +3,9 @@ module github.com/lafriks/xormstore go 1.11 require ( - github.com/davecgh/go-spew v1.1.1 // indirect github.com/denisenkom/go-mssqldb v0.0.0-20190924004331-208c0a498538 github.com/go-sql-driver/mysql v1.4.1 - github.com/go-xorm/xorm v0.7.8 + github.com/go-xorm/xorm v0.7.9 github.com/gorilla/context v1.1.1 github.com/gorilla/securecookie v1.1.1 github.com/gorilla/sessions v1.2.0 diff --git a/vendor/github.com/lafriks/xormstore/go.sum b/vendor/github.com/lafriks/xormstore/go.sum index b3326c7f44753..d3dc6aee6282d 100644 --- a/vendor/github.com/lafriks/xormstore/go.sum +++ b/vendor/github.com/lafriks/xormstore/go.sum @@ -29,8 +29,8 @@ github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= -github.com/go-xorm/xorm v0.7.8 h1:rKxZJB9mWQ9Nw2TbjsepiThR031jkGePOWXwTtEAU08= -github.com/go-xorm/xorm v0.7.8/go.mod h1:XiVxrMMIhFkwSkh96BW7PACl7UhLtx2iJIHMdmjh5sQ= +github.com/go-xorm/xorm v0.7.9 h1:LZze6n1UvRmM5gpL9/U9Gucwqo6aWlFVlfcHKH10qA0= +github.com/go-xorm/xorm v0.7.9/go.mod h1:XiVxrMMIhFkwSkh96BW7PACl7UhLtx2iJIHMdmjh5sQ= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= diff --git a/vendor/modules.txt b/vendor/modules.txt index e2cb07eda9cec..71ba2748675f3 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -198,7 +198,7 @@ github.com/go-swagger/go-swagger/cmd/swagger/commands/initcmd github.com/go-swagger/go-swagger/codescan github.com/go-swagger/go-swagger/generator github.com/go-swagger/go-swagger/scan -# github.com/go-xorm/xorm v0.7.8 +# github.com/go-xorm/xorm v0.7.9 github.com/go-xorm/xorm # github.com/gobwas/glob v0.2.3 github.com/gobwas/glob @@ -281,7 +281,7 @@ github.com/klauspost/crc32 github.com/kr/pretty # github.com/kr/text v0.1.0 github.com/kr/text -# github.com/lafriks/xormstore v1.3.0 +# github.com/lafriks/xormstore v1.3.1 github.com/lafriks/xormstore github.com/lafriks/xormstore/util # github.com/lib/pq v1.2.0 From cd13f273d1663ef5f1f506bf3824f79bc73656ff Mon Sep 17 00:00:00 2001 From: guillep2k <18600385+guillep2k@users.noreply.github.com> Date: Wed, 2 Oct 2019 19:28:30 -0300 Subject: [PATCH 016/173] Transaction-aware retry create issue to cope with duplicate keys (#8307) * Revert #7898 * Transaction-aware retry create issue to cope with duplicate keys * Restore INSERT ... WHERE usage * Rearrange code for clarity * Fix error return in newIssue() * Fix error message --- models/error.go | 15 +++++++++++++++ models/issue.go | 40 +++++++++++++++++++++++----------------- models/pull.go | 20 +++++++++++++++++++- 3 files changed, 57 insertions(+), 18 deletions(-) diff --git a/models/error.go b/models/error.go index 9974287a0aef1..995617e83b8ae 100644 --- a/models/error.go +++ b/models/error.go @@ -1089,6 +1089,21 @@ func (err ErrIssueLabelTemplateLoad) Error() string { return fmt.Sprintf("Failed to load label template file '%s': %v", err.TemplateFile, err.OriginalError) } +// ErrNewIssueInsert is used when the INSERT statement in newIssue fails +type ErrNewIssueInsert struct { + OriginalError error +} + +// IsErrNewIssueInsert checks if an error is a ErrNewIssueInsert. +func IsErrNewIssueInsert(err error) bool { + _, ok := err.(ErrNewIssueInsert) + return ok +} + +func (err ErrNewIssueInsert) Error() string { + return err.OriginalError.Error() +} + // __________ .__ .__ __________ __ // \______ \__ __| | | |\______ \ ____ ________ __ ____ _______/ |_ // | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\ diff --git a/models/issue.go b/models/issue.go index da98fac7df367..09d443384b90c 100644 --- a/models/issue.go +++ b/models/issue.go @@ -1104,21 +1104,10 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) { } // Milestone and assignee validation should happen before insert actual object. - - // There's no good way to identify a duplicate key error in database/sql; brute force some retries - dupIndexAttempts := issueMaxDupIndexAttempts - for { - _, err := e.SetExpr("`index`", "coalesce(MAX(`index`),0)+1"). - Where("repo_id=?", opts.Issue.RepoID). - Insert(opts.Issue) - if err == nil { - break - } - - dupIndexAttempts-- - if dupIndexAttempts <= 0 { - return err - } + if _, err := e.SetExpr("`index`", "coalesce(MAX(`index`),0)+1"). + Where("repo_id=?", opts.Issue.RepoID). + Insert(opts.Issue); err != nil { + return ErrNewIssueInsert{err} } inserted, err := getIssueByID(e, opts.Issue.ID) @@ -1201,6 +1190,24 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) { // NewIssue creates new issue with labels for repository. func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, assigneeIDs []int64, uuids []string) (err error) { + // Retry several times in case INSERT fails due to duplicate key for (repo_id, index); see #7887 + i := 0 + for { + if err = newIssueAttempt(repo, issue, labelIDs, assigneeIDs, uuids); err == nil { + return nil + } + if !IsErrNewIssueInsert(err) { + return err + } + if i++; i == issueMaxDupIndexAttempts { + break + } + log.Error("NewIssue: error attempting to insert the new issue; will retry. Original error: %v", err) + } + return fmt.Errorf("NewIssue: too many errors attempting to insert the new issue. Last error was: %v", err) +} + +func newIssueAttempt(repo *Repository, issue *Issue, labelIDs []int64, assigneeIDs []int64, uuids []string) (err error) { sess := x.NewSession() defer sess.Close() if err = sess.Begin(); err != nil { @@ -1214,7 +1221,7 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, assigneeIDs []in Attachments: uuids, AssigneeIDs: assigneeIDs, }); err != nil { - if IsErrUserDoesNotHaveAccessToRepo(err) { + if IsErrUserDoesNotHaveAccessToRepo(err) || IsErrNewIssueInsert(err) { return err } return fmt.Errorf("newIssue: %v", err) @@ -1223,7 +1230,6 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, assigneeIDs []in if err = sess.Commit(); err != nil { return fmt.Errorf("Commit: %v", err) } - sess.Close() return nil } diff --git a/models/pull.go b/models/pull.go index b41fb004e1fce..ff1f7b773b2b1 100644 --- a/models/pull.go +++ b/models/pull.go @@ -657,6 +657,24 @@ func (pr *PullRequest) testPatch(e Engine) (err error) { // NewPullRequest creates new pull request with labels for repository. func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []string, pr *PullRequest, patch []byte, assigneeIDs []int64) (err error) { + // Retry several times in case INSERT fails due to duplicate key for (repo_id, index); see #7887 + i := 0 + for { + if err = newPullRequestAttempt(repo, pull, labelIDs, uuids, pr, patch, assigneeIDs); err == nil { + return nil + } + if !IsErrNewIssueInsert(err) { + return err + } + if i++; i == issueMaxDupIndexAttempts { + break + } + log.Error("NewPullRequest: error attempting to insert the new issue; will retry. Original error: %v", err) + } + return fmt.Errorf("NewPullRequest: too many errors attempting to insert the new issue. Last error was: %v", err) +} + +func newPullRequestAttempt(repo *Repository, pull *Issue, labelIDs []int64, uuids []string, pr *PullRequest, patch []byte, assigneeIDs []int64) (err error) { sess := x.NewSession() defer sess.Close() if err = sess.Begin(); err != nil { @@ -671,7 +689,7 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str IsPull: true, AssigneeIDs: assigneeIDs, }); err != nil { - if IsErrUserDoesNotHaveAccessToRepo(err) { + if IsErrUserDoesNotHaveAccessToRepo(err) || IsErrNewIssueInsert(err) { return err } return fmt.Errorf("newIssue: %v", err) From 740a0c4dd46a93ec6d35c44f57b677d99f267210 Mon Sep 17 00:00:00 2001 From: guillep2k <18600385+guillep2k@users.noreply.github.com> Date: Wed, 2 Oct 2019 21:03:18 -0300 Subject: [PATCH 017/173] Fix column name ambiguity in GetUserIssueStats() (#8347) * Add test for FilterModeMention * Fix column name ambiguity * Fix fmt --- models/issue.go | 8 ++++---- models/issue_test.go | 13 +++++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/models/issue.go b/models/issue.go index 09d443384b90c..9590bc04ff627 100644 --- a/models/issue.go +++ b/models/issue.go @@ -1661,14 +1661,14 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) { return nil, err } case FilterModeAssign: - stats.OpenCount, err = x.Where(cond).And("is_closed = ?", false). + stats.OpenCount, err = x.Where(cond).And("issue.is_closed = ?", false). Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id"). And("issue_assignees.assignee_id = ?", opts.UserID). Count(new(Issue)) if err != nil { return nil, err } - stats.ClosedCount, err = x.Where(cond).And("is_closed = ?", true). + stats.ClosedCount, err = x.Where(cond).And("issue.is_closed = ?", true). Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id"). And("issue_assignees.assignee_id = ?", opts.UserID). Count(new(Issue)) @@ -1689,14 +1689,14 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) { return nil, err } case FilterModeMention: - stats.OpenCount, err = x.Where(cond).And("is_closed = ?", false). + stats.OpenCount, err = x.Where(cond).And("issue.is_closed = ?", false). Join("INNER", "issue_user", "issue.id = issue_user.issue_id and issue_user.is_mentioned = ?", true). And("issue_user.uid = ?", opts.UserID). Count(new(Issue)) if err != nil { return nil, err } - stats.ClosedCount, err = x.Where(cond).And("is_closed = ?", true). + stats.ClosedCount, err = x.Where(cond).And("issue.is_closed = ?", true). Join("INNER", "issue_user", "issue.id = issue_user.issue_id and issue_user.is_mentioned = ?", true). And("issue_user.uid = ?", opts.UserID). Count(new(Issue)) diff --git a/models/issue_test.go b/models/issue_test.go index 317fc7bbc8828..9cd9ff0ad98a8 100644 --- a/models/issue_test.go +++ b/models/issue_test.go @@ -279,6 +279,19 @@ func TestGetUserIssueStats(t *testing.T) { ClosedCount: 2, }, }, + { + UserIssueStatsOptions{ + UserID: 1, + FilterMode: FilterModeMention, + }, + IssueStats{ + YourRepositoriesCount: 0, + AssignCount: 2, + CreateCount: 2, + OpenCount: 0, + ClosedCount: 0, + }, + }, } { stats, err := GetUserIssueStats(test.Opts) if !assert.NoError(t, err) { From 0bda87616182ba8c43c48be9a9db10be54d8aecc Mon Sep 17 00:00:00 2001 From: guillep2k <18600385+guillep2k@users.noreply.github.com> Date: Thu, 3 Oct 2019 04:56:26 -0300 Subject: [PATCH 018/173] Fix lfs locks (#8361) * Extend time window for TestAPILFSLocksLogged --- integrations/api_repo_lfs_locks_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/api_repo_lfs_locks_test.go b/integrations/api_repo_lfs_locks_test.go index 6c0aeb1152950..4fe92b33b5f3b 100644 --- a/integrations/api_repo_lfs_locks_test.go +++ b/integrations/api_repo_lfs_locks_test.go @@ -126,7 +126,7 @@ func TestAPILFSLocksLogged(t *testing.T) { assert.Len(t, lfsLocks.Locks, test.totalCount) for i, lock := range lfsLocks.Locks { assert.EqualValues(t, test.locksOwners[i].DisplayName(), lock.Owner.Name) - assert.WithinDuration(t, test.locksTimes[i], lock.LockedAt, 3*time.Second) + assert.WithinDuration(t, test.locksTimes[i], lock.LockedAt, 10*time.Second) assert.EqualValues(t, lock.LockedAt.Format(time.RFC3339), lock.LockedAt.Format(time.RFC3339Nano)) //locked at should be rounded to second } From 9543aeaf84cae7ce3700133ff048536471c543aa Mon Sep 17 00:00:00 2001 From: Norwin Date: Thu, 3 Oct 2019 16:54:33 +0000 Subject: [PATCH 019/173] readd .markdown class to all markup renderers (#8357) fixes #8299, a regression from 867f46f. unlike it's name suggests, the .markdown class is needed for most markup types. a future refactor should rename this class to something more generic --- public/css/index.css | 2 +- public/less/_repository.less | 1 + templates/repo/view_file.tmpl | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/public/css/index.css b/public/css/index.css index 1da2399c461b8..294539d39ffbb 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -505,7 +505,7 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository.file.list .non-diff-file-content .view-raw img{padding:5px 5px 0 5px} .repository.file.list .non-diff-file-content .plain-text{padding:1em 2em 1em 2em} .repository.file.list .non-diff-file-content .plain-text pre{word-break:break-word;white-space:pre-wrap} -.repository.file.list .non-diff-file-content .csv{overflow-x:auto} +.repository.file.list .non-diff-file-content .csv{overflow-x:auto;padding:0!important} .repository.file.list .non-diff-file-content pre{overflow:auto} .repository.file.list .sidebar{padding-left:0} .repository.file.list .sidebar .octicon{width:16px} diff --git a/public/less/_repository.less b/public/less/_repository.less index fde11f7a4d619..ade3477ccca7b 100644 --- a/public/less/_repository.less +++ b/public/less/_repository.less @@ -429,6 +429,7 @@ .csv { overflow-x: auto; + padding: 0 !important; } pre { diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl index 895a72aaee5b0..50e4c33946b1e 100644 --- a/templates/repo/view_file.tmpl +++ b/templates/repo/view_file.tmpl @@ -45,7 +45,7 @@
-
+
{{if .IsMarkup}} {{if .FileContent}}{{.FileContent | Safe}}{{end}} {{else if .IsRenderedHTML}} From 6ea77523bbda75255e04bb5befafe24f5279ab5e Mon Sep 17 00:00:00 2001 From: 8ctopus <13252042+8ctopus@users.noreply.github.com> Date: Fri, 4 Oct 2019 05:54:05 +0500 Subject: [PATCH 020/173] Cleanup https support code snippet (#8370) --- docs/content/doc/usage/https-support.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/content/doc/usage/https-support.md b/docs/content/doc/usage/https-support.md index 5e1f4be56e646..22cbc684aa4c6 100644 --- a/docs/content/doc/usage/https-support.md +++ b/docs/content/doc/usage/https-support.md @@ -24,11 +24,11 @@ To use Gitea's built-in HTTPS support, you must change your `app.ini` file: ```ini [server] -PROTOCOL=https -ROOT_URL = `https://git.example.com:3000/` +PROTOCOL = https +ROOT_URL = https://git.example.com:3000/ HTTP_PORT = 3000 CERT_FILE = cert.pem -KEY_FILE = key.pem +KEY_FILE = key.pem ``` To learn more about the config values, please checkout the [Config Cheat Sheet](../config-cheat-sheet#server). From 1a2d7207ea38a2c5f32b0fa8e7778c747a5631c8 Mon Sep 17 00:00:00 2001 From: jaqra <48099350+jaqra@users.noreply.github.com> Date: Fri, 4 Oct 2019 10:18:46 +0300 Subject: [PATCH 021/173] Make 100% width issues page left menu and add reponame as title attribute (#8359) --- public/css/index.css | 1 + public/less/_dashboard.less | 2 ++ templates/user/dashboard/issues.tmpl | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/public/css/index.css b/public/css/index.css index 294539d39ffbb..496194decc352 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -955,6 +955,7 @@ tbody.commit-list{vertical-align:baseline} .dashboard{padding-top:15px} .dashboard.feeds .context.user.menu,.dashboard.issues .context.user.menu{z-index:101;min-width:200px} .dashboard.feeds .context.user.menu .ui.header,.dashboard.issues .context.user.menu .ui.header{font-size:1rem;text-transform:none} +.dashboard.feeds .filter.menu,.dashboard.issues .filter.menu{width:initial} .dashboard.feeds .filter.menu .item,.dashboard.issues .filter.menu .item{text-align:left} .dashboard.feeds .filter.menu .item .text,.dashboard.issues .filter.menu .item .text{height:16px;vertical-align:middle} .dashboard.feeds .filter.menu .item .text.truncate,.dashboard.issues .filter.menu .item .text.truncate{width:85%} diff --git a/public/less/_dashboard.less b/public/less/_dashboard.less index 1b5d231499a53..8749fb88025bd 100644 --- a/public/less/_dashboard.less +++ b/public/less/_dashboard.less @@ -14,6 +14,8 @@ } .filter.menu { + width: initial; + .item { text-align: left; diff --git a/templates/user/dashboard/issues.tmpl b/templates/user/dashboard/issues.tmpl index 83e630e97e238..ac5f10a599434 100644 --- a/templates/user/dashboard/issues.tmpl +++ b/templates/user/dashboard/issues.tmpl @@ -25,7 +25,7 @@ {{end}}
{{range .Repos}} - + {{.FullName}}
{{index $.Counts .ID}}
From ae939652eafd95e7f9318187be4bd41fc9de6e2a Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Fri, 4 Oct 2019 07:22:20 +0000 Subject: [PATCH 022/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_zh-CN.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 9bdf45c41769b..76676097936a7 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -1325,6 +1325,7 @@ settings.protect_merge_whitelist_committers_desc=仅允许白名单用户或团 settings.protect_merge_whitelist_users=合并白名单用户: settings.protect_merge_whitelist_teams=合并白名单团队: settings.protect_check_status_contexts=启用状态检查 +settings.protect_check_status_contexts_desc=要求状态检查通过才能合并,选择必须先通过哪些状态检查才能合并。如果启用,推送的合并请求必须先通过状态检查才能够合并到对应的分支。如果没有选择具体的状态检查上下文,则所有的状态检查都通过才能合并。 settings.protect_check_status_contexts_list=此仓库上周进行过的状态检查 settings.protect_required_approvals=所需的批准: settings.protect_required_approvals_desc=只允许合并有足够审批的请求。 From de8a0a3938e811ffaa6800a771d7f09fd6428608 Mon Sep 17 00:00:00 2001 From: Km Date: Fri, 4 Oct 2019 19:30:05 +0200 Subject: [PATCH 023/173] Add buildbot CI (#8378) Buildbot can work with Gitea --- docs/content/doc/advanced/ci-cd.en-us.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/content/doc/advanced/ci-cd.en-us.md b/docs/content/doc/advanced/ci-cd.en-us.md index 5d643375331df..7d22078a9db06 100644 --- a/docs/content/doc/advanced/ci-cd.en-us.md +++ b/docs/content/doc/advanced/ci-cd.en-us.md @@ -27,6 +27,8 @@ the purpose is to give a starting point to integrate a CI/CD process with your G - [Agola](https://agola.io) - [Buildkite](https://buildkite.com) with [Gitea connector](https://github.com/techknowlogick/gitea-buildkite-connector) - [AppVeyor](https://www.appveyor.com) with [built-in Gitea support](https://www.appveyor.com/blog/2019/09/05/gitea-receives-first-class-support-in-appveyor/) + - [Buildbot](https://www.buildbot.net/) with [Gitea plugin](https://github.com/lab132/buildbot-gitea) + Others CI/CD solutions that partially can be integrated with Gitea: - [Concourse](https://www.concourse-ci.org), see more information at [Concourse community forum](https://discuss.concourse-ci.org/t/concourse-ci-and-gitea-oauth/1475) From f92a0b68fed81128fa278e82aa0e3d49d74ffdf6 Mon Sep 17 00:00:00 2001 From: Mario Lubenka Date: Fri, 4 Oct 2019 21:58:54 +0200 Subject: [PATCH 024/173] Bugfix for image compare and minor improvements to image compare (#8289) * Resolve error when comparing images Signed-off-by: Mario Lubenka * Check blob existence instead of git-ls when checking if file exists Signed-off-by: Mario Lubenka * Show file metadata also when a file was newly added Signed-off-by: Mario Lubenka * Fixes error in commit view Signed-off-by: Mario Lubenka * Excludes assigning path and image infos for compare routers to service package Signed-off-by: Mario Lubenka * Removes nil default and fixes import order Signed-off-by: Mario Lubenka * Adds missing comments Signed-off-by: Mario Lubenka * Moves methods for assigning compare data to context into repo router package Signed-off-by: Mario Lubenka * Show image compare for deleted images as well. Simplify check if image should be displayed Signed-off-by: Mario Lubenka --- modules/git/commit.go | 7 ++- routers/repo/commit.go | 24 +++------ routers/repo/compare.go | 77 ++++++++++++++++------------- routers/repo/pull.go | 25 +--------- templates/repo/diff/box.tmpl | 7 ++- templates/repo/diff/image_diff.tmpl | 57 ++++++++++++++++----- 6 files changed, 106 insertions(+), 91 deletions(-) diff --git a/modules/git/commit.go b/modules/git/commit.go index 83e03c27956eb..eb442f988d497 100644 --- a/modules/git/commit.go +++ b/modules/git/commit.go @@ -355,8 +355,11 @@ func (c *Commit) FileChangedSinceCommit(filename, pastCommit string) (bool, erro // HasFile returns true if the file given exists on this commit // This does only mean it's there - it does not mean the file was changed during the commit. func (c *Commit) HasFile(filename string) (bool, error) { - result, err := c.repo.LsFiles(filename) - return result[0] == filename, err + _, err := c.GetBlobByPath(filename) + if err != nil { + return false, err + } + return true, nil } // GetSubModules get all the sub modules of current revision git tree diff --git a/routers/repo/commit.go b/routers/repo/commit.go index 919ebabf42a99..3cedf70319e0b 100644 --- a/routers/repo/commit.go +++ b/routers/repo/commit.go @@ -239,24 +239,18 @@ func Diff(ctx *context.Context) { ctx.Data["CommitID"] = commitID ctx.Data["Username"] = userName ctx.Data["Reponame"] = repoName - ctx.Data["IsImageFile"] = commit.IsImageFile - ctx.Data["ImageInfo"] = func(name string) *git.ImageMetaData { - result, err := commit.ImageInfo(name) - if err != nil { - log.Error("ImageInfo failed: %v", err) - return nil - } - return result - } - ctx.Data["ImageInfoBase"] = ctx.Data["ImageInfo"] + + var parentCommit *git.Commit if commit.ParentCount() > 0 { - parentCommit, err := ctx.Repo.GitRepo.GetCommit(parents[0]) + parentCommit, err = ctx.Repo.GitRepo.GetCommit(parents[0]) if err != nil { ctx.NotFound("GetParentCommit", err) return } - ctx.Data["ImageInfo"] = parentCommit.ImageInfo } + setImageCompareContext(ctx, parentCommit, commit) + headTarget := path.Join(userName, repoName) + setPathsCompareContext(ctx, parentCommit, commit, headTarget) ctx.Data["Title"] = commit.Summary() + " · " + base.ShortSha(commitID) ctx.Data["Commit"] = commit ctx.Data["Verification"] = models.ParseCommitWithSignature(commit) @@ -264,8 +258,6 @@ func Diff(ctx *context.Context) { ctx.Data["Diff"] = diff ctx.Data["Parents"] = parents ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0 - ctx.Data["SourcePath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "src", "commit", commitID) - ctx.Data["RawPath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "raw", "commit", commitID) note := &git.Note{} err = git.GetNote(ctx.Repo.GitRepo, commitID, note) @@ -275,10 +267,6 @@ func Diff(ctx *context.Context) { ctx.Data["NoteAuthor"] = models.ValidateCommitWithEmail(note.Commit) } - if commit.ParentCount() > 0 { - ctx.Data["BeforeSourcePath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "src", "commit", parents[0]) - ctx.Data["BeforeRawPath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "raw", "commit", parents[0]) - } ctx.Data["BranchName"], err = commit.GetBranchName() if err != nil { ctx.ServerError("commit.GetBranchName", err) diff --git a/routers/repo/compare.go b/routers/repo/compare.go index 7c55dfca30020..f8534f68b77b6 100644 --- a/routers/repo/compare.go +++ b/routers/repo/compare.go @@ -5,6 +5,7 @@ package repo import ( + "fmt" "path" "strings" @@ -21,6 +22,45 @@ const ( tplCompare base.TplName = "repo/diff/compare" ) +// setPathsCompareContext sets context data for source and raw paths +func setPathsCompareContext(ctx *context.Context, base *git.Commit, head *git.Commit, headTarget string) { + sourcePath := setting.AppSubURL + "/%s/src/commit/%s" + rawPath := setting.AppSubURL + "/%s/raw/commit/%s" + + ctx.Data["SourcePath"] = fmt.Sprintf(sourcePath, headTarget, head.ID) + ctx.Data["RawPath"] = fmt.Sprintf(rawPath, headTarget, head.ID) + if base != nil { + baseTarget := path.Join(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name) + ctx.Data["BeforeSourcePath"] = fmt.Sprintf(sourcePath, baseTarget, base.ID) + ctx.Data["BeforeRawPath"] = fmt.Sprintf(rawPath, baseTarget, base.ID) + } +} + +// setImageCompareContext sets context data that is required by image compare template +func setImageCompareContext(ctx *context.Context, base *git.Commit, head *git.Commit) { + ctx.Data["IsImageFileInHead"] = head.IsImageFile + ctx.Data["IsImageFileInBase"] = base.IsImageFile + ctx.Data["ImageInfoBase"] = func(name string) *git.ImageMetaData { + if base == nil { + return nil + } + result, err := base.ImageInfo(name) + if err != nil { + log.Error("ImageInfo failed: %v", err) + return nil + } + return result + } + ctx.Data["ImageInfo"] = func(name string) *git.ImageMetaData { + result, err := head.ImageInfo(name) + if err != nil { + log.Error("ImageInfo failed: %v", err) + return nil + } + return result + } +} + // ParseCompareInfo parse compare info between two commit for preparing comparing references func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *git.Repository, *git.CompareInfo, string, string) { baseRepo := ctx.Repo.Repository @@ -291,43 +331,10 @@ func PrepareCompareDiff( ctx.Data["title"] = title ctx.Data["Username"] = headUser.Name ctx.Data["Reponame"] = headRepo.Name - ctx.Data["IsImageFile"] = headCommit.IsImageFile - ctx.Data["ImageInfo"] = func(name string) *git.ImageMetaData { - result, err := headCommit.ImageInfo(name) - if err != nil { - log.Error("ImageInfo failed: %v", err) - return nil - } - return result - } - ctx.Data["FileExistsInBaseCommit"] = func(filename string) bool { - result, err := baseCommit.HasFile(filename) - if err != nil { - log.Error( - "Error while checking if file \"%s\" exists in base commit \"%s\" (repo: %s): %v", - filename, - baseCommit, - baseGitRepo.Path, - err) - return false - } - return result - } - ctx.Data["ImageInfoBase"] = func(name string) *git.ImageMetaData { - result, err := baseCommit.ImageInfo(name) - if err != nil { - log.Error("ImageInfo failed: %v", err) - return nil - } - return result - } + setImageCompareContext(ctx, baseCommit, headCommit) headTarget := path.Join(headUser.Name, repo.Name) - baseTarget := path.Join(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name) - ctx.Data["SourcePath"] = setting.AppSubURL + "/" + path.Join(headTarget, "src", "commit", headCommitID) - ctx.Data["RawPath"] = setting.AppSubURL + "/" + path.Join(headTarget, "raw", "commit", headCommitID) - ctx.Data["BeforeSourcePath"] = setting.AppSubURL + "/" + path.Join(baseTarget, "src", "commit", baseCommitID) - ctx.Data["BeforeRawPath"] = setting.AppSubURL + "/" + path.Join(baseTarget, "raw", "commit", baseCommitID) + setPathsCompareContext(ctx, baseCommit, headCommit, headTarget) return false } diff --git a/routers/repo/pull.go b/routers/repo/pull.go index 72d2ffcaa7d66..7af01c46ba660 100644 --- a/routers/repo/pull.go +++ b/routers/repo/pull.go @@ -564,29 +564,8 @@ func ViewPullFiles(ctx *context.Context) { return } - ctx.Data["IsImageFile"] = commit.IsImageFile - ctx.Data["ImageInfoBase"] = func(name string) *git.ImageMetaData { - result, err := baseCommit.ImageInfo(name) - if err != nil { - log.Error("ImageInfo failed: %v", err) - return nil - } - return result - } - ctx.Data["ImageInfo"] = func(name string) *git.ImageMetaData { - result, err := commit.ImageInfo(name) - if err != nil { - log.Error("ImageInfo failed: %v", err) - return nil - } - return result - } - - baseTarget := path.Join(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name) - ctx.Data["SourcePath"] = setting.AppSubURL + "/" + path.Join(headTarget, "src", "commit", endCommitID) - ctx.Data["RawPath"] = setting.AppSubURL + "/" + path.Join(headTarget, "raw", "commit", endCommitID) - ctx.Data["BeforeSourcePath"] = setting.AppSubURL + "/" + path.Join(baseTarget, "src", "commit", startCommitID) - ctx.Data["BeforeRawPath"] = setting.AppSubURL + "/" + path.Join(baseTarget, "raw", "commit", startCommitID) + setImageCompareContext(ctx, baseCommit, commit) + setPathsCompareContext(ctx, baseCommit, commit, headTarget) ctx.Data["RequireHighlightJS"] = true ctx.Data["RequireTribute"] = true diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl index edc04f9068851..b5fde36a6f1fc 100644 --- a/templates/repo/diff/box.tmpl +++ b/templates/repo/diff/box.tmpl @@ -106,7 +106,12 @@
{{if ne $file.Type 4}} - {{$isImage := (call $.IsImageFile $file.Name)}} + {{$isImage := false}} + {{if $file.IsDeleted}} + {{$isImage = (call $.IsImageFileInBase $file.Name)}} + {{else}} + {{$isImage = (call $.IsImageFileInHead $file.Name)}} + {{end}}
diff --git a/templates/repo/diff/image_diff.tmpl b/templates/repo/diff/image_diff.tmpl index 8fa7f6b872f79..6afb985e9a98b 100644 --- a/templates/repo/diff/image_diff.tmpl +++ b/templates/repo/diff/image_diff.tmpl @@ -11,36 +11,69 @@ {{ $imageInfoBase := (call .root.ImageInfoBase .file.OldName) }} {{ $imageInfoHead := (call .root.ImageInfo .file.Name) }} -{{if and $imageInfoBase $imageInfoHead }} +{{if or $imageInfoBase $imageInfoHead }} {{end}} From fb7c23f911bebcb72f170f3d8bc8343546805f3b Mon Sep 17 00:00:00 2001 From: guillep2k <18600385+guillep2k@users.noreply.github.com> Date: Fri, 4 Oct 2019 23:09:19 -0300 Subject: [PATCH 025/173] Fix editor commit to new branch if PR disabled (#8375) --- options/locale/locale_en-US.ini | 1 + routers/repo/editor.go | 6 +++--- templates/repo/editor/commit_form.tmpl | 14 ++++++++++++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 938c53af3f211..c8be059b72027 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -706,6 +706,7 @@ editor.delete = Delete '%s' editor.commit_message_desc = Add an optional extended description… editor.commit_directly_to_this_branch = Commit directly to the %s branch. editor.create_new_branch = Create a new branch for this commit and start a pull request. +editor.create_new_branch_np = Create a new branch for this commit. editor.propose_file_change = Propose file change editor.new_branch_name_desc = New branch name… editor.cancel = Cancel diff --git a/routers/repo/editor.go b/routers/repo/editor.go index 68b94662dc856..d4a7dab074816 100644 --- a/routers/repo/editor.go +++ b/routers/repo/editor.go @@ -269,7 +269,7 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo } } - if form.CommitChoice == frmCommitChoiceNewBranch { + if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(models.UnitTypePullRequests) { ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + ctx.Repo.BranchName + "..." + form.NewBranchName) } else { ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath)) @@ -434,7 +434,7 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) { } ctx.Flash.Success(ctx.Tr("repo.editor.file_delete_success", ctx.Repo.TreePath)) - if form.CommitChoice == frmCommitChoiceNewBranch { + if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(models.UnitTypePullRequests) { ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + ctx.Repo.BranchName + "..." + form.NewBranchName) } else { treePath := filepath.Dir(ctx.Repo.TreePath) @@ -589,7 +589,7 @@ func UploadFilePost(ctx *context.Context, form auth.UploadRepoFileForm) { return } - if form.CommitChoice == frmCommitChoiceNewBranch { + if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(models.UnitTypePullRequests) { ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + ctx.Repo.BranchName + "..." + form.NewBranchName) } else { ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath)) diff --git a/templates/repo/editor/commit_form.tmpl b/templates/repo/editor/commit_form.tmpl index d22cd07b03fb2..2ff08e3931303 100644 --- a/templates/repo/editor/commit_form.tmpl +++ b/templates/repo/editor/commit_form.tmpl @@ -19,11 +19,21 @@
+ {{$pullRequestEnabled := .Repository.UnitEnabled $.UnitTypePullRequests}} + {{$prUnit := .Repository.MustGetUnit $.UnitTypePullRequests}}
- + {{if $pullRequestEnabled}} + + {{else}} + + {{end}}
From bd41a04a5613a2e017b458351bea0f02b767b893 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 5 Oct 2019 19:09:27 +0800 Subject: [PATCH 026/173] Add extra user information when migrating release (#8331) * add extra user information when migrating release * add migrations * fix tests --- models/migrations/migrations.go | 2 ++ models/migrations/v98.go | 17 +++++++++++++++++ models/release.go | 2 ++ modules/migrations/base/release.go | 3 +++ modules/migrations/gitea.go | 26 ++++++++++++++------------ modules/migrations/github.go | 8 ++++++++ modules/migrations/github_test.go | 2 ++ templates/repo/release/list.tmpl | 7 +++++++ 8 files changed, 55 insertions(+), 12 deletions(-) create mode 100644 models/migrations/v98.go diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 7680e7747c306..1f5b918de854e 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -250,6 +250,8 @@ var migrations = []Migration{ NewMigration("delete orphaned attachments", deleteOrphanedAttachments), // v97 -> v98 NewMigration("add repo_admin_change_team_access to user", addRepoAdminChangeTeamAccessColumnForUser), + // v98 -> v99 + NewMigration("add original author name and id on migrated release", addOriginalAuthorOnMigratedReleases), } // Migrate database to current version diff --git a/models/migrations/v98.go b/models/migrations/v98.go new file mode 100644 index 0000000000000..3b9fdbb1c5982 --- /dev/null +++ b/models/migrations/v98.go @@ -0,0 +1,17 @@ +// Copyright 2019 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 "github.com/go-xorm/xorm" + +func addOriginalAuthorOnMigratedReleases(x *xorm.Engine) error { + type Release struct { + ID int64 + OriginalAuthor string + OriginalAuthorID int64 `xorm:"index"` + } + + return x.Sync2(new(Release)) +} diff --git a/models/release.go b/models/release.go index 3729a6f690925..243cc2fa3c31a 100644 --- a/models/release.go +++ b/models/release.go @@ -26,6 +26,8 @@ type Release struct { PublisherID int64 `xorm:"INDEX"` Publisher *User `xorm:"-"` TagName string `xorm:"INDEX UNIQUE(n)"` + OriginalAuthor string + OriginalAuthorID int64 `xorm:"index"` LowerTagName string Target string Title string diff --git a/modules/migrations/base/release.go b/modules/migrations/base/release.go index 4ebc37315de7b..b2541f1bf5016 100644 --- a/modules/migrations/base/release.go +++ b/modules/migrations/base/release.go @@ -25,6 +25,9 @@ type Release struct { Body string Draft bool Prerelease bool + PublisherID int64 + PublisherName string + PublisherEmail string Assets []ReleaseAsset Created time.Time Published time.Time diff --git a/modules/migrations/gitea.go b/modules/migrations/gitea.go index 271c5616a714e..1edac47a6eceb 100644 --- a/modules/migrations/gitea.go +++ b/modules/migrations/gitea.go @@ -175,18 +175,20 @@ func (g *GiteaLocalUploader) CreateReleases(releases ...*base.Release) error { var rels = make([]*models.Release, 0, len(releases)) for _, release := range releases { var rel = models.Release{ - RepoID: g.repo.ID, - PublisherID: g.doer.ID, - TagName: release.TagName, - LowerTagName: strings.ToLower(release.TagName), - Target: release.TargetCommitish, - Title: release.Name, - Sha1: release.TargetCommitish, - Note: release.Body, - IsDraft: release.Draft, - IsPrerelease: release.Prerelease, - IsTag: false, - CreatedUnix: timeutil.TimeStamp(release.Created.Unix()), + RepoID: g.repo.ID, + PublisherID: g.doer.ID, + TagName: release.TagName, + LowerTagName: strings.ToLower(release.TagName), + Target: release.TargetCommitish, + Title: release.Name, + Sha1: release.TargetCommitish, + Note: release.Body, + IsDraft: release.Draft, + IsPrerelease: release.Prerelease, + IsTag: false, + CreatedUnix: timeutil.TimeStamp(release.Created.Unix()), + OriginalAuthor: release.PublisherName, + OriginalAuthorID: release.PublisherID, } // calc NumCommits diff --git a/modules/migrations/github.go b/modules/migrations/github.go index c5f29cabb7e14..754f98941c174 100644 --- a/modules/migrations/github.go +++ b/modules/migrations/github.go @@ -214,6 +214,11 @@ func (g *GithubDownloaderV3) convertGithubRelease(rel *github.RepositoryRelease) name = *rel.Name } + var email string + if rel.Author.Email != nil { + email = *rel.Author.Email + } + r := &base.Release{ TagName: *rel.TagName, TargetCommitish: *rel.TargetCommitish, @@ -222,6 +227,9 @@ func (g *GithubDownloaderV3) convertGithubRelease(rel *github.RepositoryRelease) Draft: *rel.Draft, Prerelease: *rel.Prerelease, Created: rel.CreatedAt.Time, + PublisherID: *rel.Author.ID, + PublisherName: *rel.Author.Login, + PublisherEmail: email, Published: rel.PublishedAt.Time, } diff --git a/modules/migrations/github_test.go b/modules/migrations/github_test.go index 62fce6bbcc65c..2a0a4edf32681 100644 --- a/modules/migrations/github_test.go +++ b/modules/migrations/github_test.go @@ -167,6 +167,8 @@ func TestGitHubDownloadRepo(t *testing.T) { Body: "Forked source from Gogs into Gitea\n", Created: time.Date(2016, 10, 17, 02, 17, 59, 0, time.UTC), Published: time.Date(2016, 11, 17, 15, 37, 0, 0, time.UTC), + PublisherID: 4726179, + PublisherName: "bkcsoft", }, }, releases[len(releases)-1:]) diff --git a/templates/repo/release/list.tmpl b/templates/repo/release/list.tmpl index c57a180873948..777d3a2b050cf 100644 --- a/templates/repo/release/list.tmpl +++ b/templates/repo/release/list.tmpl @@ -54,8 +54,15 @@

+ {{if .OriginalAuthor}} + + {{.OriginalAuthor}} + {{else if .Publisher}} {{.Publisher.Name}} + {{else}} + Ghost + {{end}} {{if .CreatedUnix}}{{TimeSinceUnix .CreatedUnix $.Lang}}{{end}} {{$.i18n.Tr "repo.release.ahead" .NumCommitsBehind .Target | Str2html}} From 8a828500e689b7958e050ebd2dc46d380c3d6ae6 Mon Sep 17 00:00:00 2001 From: 8ctopus <13252042+8ctopus@users.noreply.github.com> Date: Sat, 5 Oct 2019 19:16:30 +0500 Subject: [PATCH 027/173] Doc config file should not be readable by others as it contains sensitive info (#8385) --- .../doc/installation/from-binary.en-us.md | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/content/doc/installation/from-binary.en-us.md b/docs/content/doc/installation/from-binary.en-us.md index c93973f222d43..10f0ff15b64e7 100644 --- a/docs/content/doc/installation/from-binary.en-us.md +++ b/docs/content/doc/installation/from-binary.en-us.md @@ -44,7 +44,7 @@ location. When launched manually, Gitea can be killed using `Ctrl+C`. ## Recommended server configuration -**NOTE:** Many of the following directories can be configured using [Environment Variables]({{< relref "doc/advanced/specific-variables.en-us.md" >}}) as well! +**NOTE:** Many of the following directories can be configured using [Environment Variables]({{< relref "doc/advanced/specific-variables.en-us.md" >}}) as well! Of note, configuring `GITEA_WORK_DIR` will tell Gitea where to base its working directory, as well as ease installation. ### Prepare environment @@ -80,7 +80,7 @@ chmod 770 /etc/gitea **NOTE:** `/etc/gitea` is temporary set with write rights for user `git` so that Web installer could write configuration file. After installation is done, it is recommended to set rights to read-only using: ``` chmod 750 /etc/gitea -chmod 644 /etc/gitea/app.ini +chmod 640 /etc/gitea/app.ini ``` If you don't want the web installer to be able to write the config file at all, it is also possible to make the config file read-only for the gitea user (owner/group `root:root`, mode `0660`), and set `INSTALL_LOCK = true`. In that case all database configuration details must be set beforehand in the config file, as well as the `SECRET_KEY` and `INTERNAL_TOKEN` values. See the [command line documentation]({{< relref "doc/usage/command-line.en-us.md" >}}) for information on using `gitea generate secret INTERNAL_TOKEN`. @@ -113,16 +113,16 @@ GITEA_WORK_DIR=/var/lib/gitea/ /usr/local/bin/gitea web -c /etc/gitea/app.ini ## Updating to a new version -You can update to a new version of Gitea by stopping Gitea, replacing the binary at `/usr/local/bin/gitea` and restarting the instance. -The binary file name should not be changed during the update to avoid problems -in existing repositories. +You can update to a new version of Gitea by stopping Gitea, replacing the binary at `/usr/local/bin/gitea` and restarting the instance. +The binary file name should not be changed during the update to avoid problems +in existing repositories. It is recommended you do a [backup]({{< relref "doc/usage/backup-and-restore.en-us.md" >}}) before updating your installation. -If you have carried out the installation steps as described above, the binary should -have the generic name `gitea`. Do not change this, i.e. to include the version number. +If you have carried out the installation steps as described above, the binary should +have the generic name `gitea`. Do not change this, i.e. to include the version number. -See below for troubleshooting instructions to repair broken repositories after +See below for troubleshooting instructions to repair broken repositories after an update of your Gitea version. ## Troubleshooting @@ -145,7 +145,7 @@ is already running. ### Running Gitea on Raspbian -As of v1.8, there is a problem with the arm7 version of Gitea and it doesn't run on Raspberry Pi and similar devices. +As of v1.8, there is a problem with the arm7 version of Gitea and it doesn't run on Raspberry Pi and similar devices. It is therefore recommended to switch to the arm6 version which has been tested and shown to work on Raspberry Pi and similar devices. @@ -154,18 +154,18 @@ please remove after fixing the arm7 bug ---> ### Git error after updating to a new version of Gitea -If the binary file name has been changed during the update to a new version of Gitea, -git hooks in existing repositories will not work any more. In that case, a git +If the binary file name has been changed during the update to a new version of Gitea, +git hooks in existing repositories will not work any more. In that case, a git error will be displayed when pushing to the repository. ``` remote: ./hooks/pre-receive.d/gitea: line 2: [...]: No such file or directory ``` -The `[...]` part of the error message will contain the path to your previous Gitea +The `[...]` part of the error message will contain the path to your previous Gitea binary. -To solve this, go to the admin options and run the task `Resynchronize pre-receive, +To solve this, go to the admin options and run the task `Resynchronize pre-receive, update and post-receive hooks of all repositories` to update all hooks to contain the new binary path. Please note that this overwrite all git hooks including ones with customizations made. From 93e2ce699babb60818c0d5e75eda39f0e9263216 Mon Sep 17 00:00:00 2001 From: 8ctopus <13252042+8ctopus@users.noreply.github.com> Date: Sun, 6 Oct 2019 09:38:10 +0500 Subject: [PATCH 028/173] Doc added instructions for Git LFS support (#8391) --- docs/content/doc/usage/git-lfs-support.md | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 docs/content/doc/usage/git-lfs-support.md diff --git a/docs/content/doc/usage/git-lfs-support.md b/docs/content/doc/usage/git-lfs-support.md new file mode 100644 index 0000000000000..2d5fab3cb3829 --- /dev/null +++ b/docs/content/doc/usage/git-lfs-support.md @@ -0,0 +1,26 @@ +--- +date: "2019-10-06T08:00:00+05:00" +title: "Usage: Git LFS setup" +slug: "git-lfs-setup" +weight: 12 +toc: true +draft: false +menu: + sidebar: + parent: "usage" + name: "Git LFS setup" + weight: 12 + identifier: "git-lfs-setup" +--- + +# Git Large File Storage setup + +To use Gitea's built-in LFS support, you must update the `app.ini` file: + +```ini +[server] +; Enables git-lfs support. true or false, default is false. +LFS_START_SERVER = true +; Where your lfs files reside, default is data/lfs. +LFS_CONTENT_PATH = /home/gitea/data/lfs +``` \ No newline at end of file From bc5a479fefa77ee54a9fddecdbbb7e7991f22da1 Mon Sep 17 00:00:00 2001 From: Thomas McWork Date: Sun, 6 Oct 2019 20:32:23 +0200 Subject: [PATCH 029/173] Add unix socket help (#8377) When using unix socket as listener (`HTTP_ADDR = /run/gitea/gitea.socket`) then it's required to have the folder `/run/gitea` with appropriate owner/group. Manual creation leads to vanishing after reboot. This directive enables Systemd to handle this. --- contrib/systemd/gitea.service | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/systemd/gitea.service b/contrib/systemd/gitea.service index d88df4a03719d..b7e6629ebfe13 100644 --- a/contrib/systemd/gitea.service +++ b/contrib/systemd/gitea.service @@ -20,6 +20,9 @@ Type=simple User=git Group=git WorkingDirectory=/var/lib/gitea/ +# If using unix socket: Tells Systemd to create /run/gitea folder to home gitea.sock +# Manual cration would vanish after reboot. +#RuntimeDirectory=gitea ExecStart=/usr/local/bin/gitea web -c /etc/gitea/app.ini Restart=always Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea From 51fade4c44c3517923cd07783ab05a55aaa84dcd Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 7 Oct 2019 05:26:19 +0800 Subject: [PATCH 030/173] Fix milestone num_issues (#8221) * fix milestone num_issues * update missing completeness * only update milestone closed number when closed issue is assigned a new milestone or clear milestone * fix tests * fix update milestone num * fix completeness calculate * make completeness calucation more clear --- models/issue.go | 4 +- models/issue_milestone.go | 75 ++++++++++++++++++---------------- models/issue_milestone_test.go | 6 +-- 3 files changed, 44 insertions(+), 41 deletions(-) diff --git a/models/issue.go b/models/issue.go index 9590bc04ff627..e4cc1291c2a7d 100644 --- a/models/issue.go +++ b/models/issue.go @@ -766,7 +766,7 @@ func (issue *Issue) changeStatus(e *xorm.Session, doer *User, isClosed bool) (er } // Update issue count of milestone - if err = changeMilestoneIssueStats(e, issue); err != nil { + if err := updateMilestoneClosedNum(e, issue.MilestoneID); err != nil { return err } @@ -1119,7 +1119,7 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) { opts.Issue.Index = inserted.Index if opts.Issue.MilestoneID > 0 { - if err = changeMilestoneAssign(e, doer, opts.Issue, -1); err != nil { + if _, err = e.Exec("UPDATE `milestone` SET num_issues=num_issues+1 WHERE id=?", opts.Issue.MilestoneID); err != nil { return err } } diff --git a/models/issue_milestone.go b/models/issue_milestone.go index f8f414e7166e6..29e13689bf3ab 100644 --- a/models/issue_milestone.go +++ b/models/issue_milestone.go @@ -311,71 +311,74 @@ func ChangeMilestoneStatus(m *Milestone, isClosed bool) (err error) { return sess.Commit() } -func changeMilestoneIssueStats(e *xorm.Session, issue *Issue) error { - if issue.MilestoneID == 0 { - return nil +func updateMilestoneTotalNum(e Engine, milestoneID int64) (err error) { + if _, err = e.Exec("UPDATE `milestone` SET num_issues=(SELECT count(*) FROM issue WHERE milestone_id=?) WHERE id=?", + milestoneID, + milestoneID, + ); err != nil { + return } - m, err := getMilestoneByRepoID(e, issue.RepoID, issue.MilestoneID) - if err != nil { - return err - } + _, err = e.Exec("UPDATE `milestone` SET completeness=100*num_closed_issues/(CASE WHEN num_issues > 0 THEN num_issues ELSE 1 END) WHERE id=?", + milestoneID, + ) - if issue.IsClosed { - m.NumOpenIssues-- - m.NumClosedIssues++ - } else { - m.NumOpenIssues++ - m.NumClosedIssues-- + return +} + +func updateMilestoneClosedNum(e Engine, milestoneID int64) (err error) { + if _, err = e.Exec("UPDATE `milestone` SET num_closed_issues=(SELECT count(*) FROM issue WHERE milestone_id=? AND is_closed=?) WHERE id=?", + milestoneID, + true, + milestoneID, + ); err != nil { + return } - return updateMilestone(e, m) + _, err = e.Exec("UPDATE `milestone` SET completeness=100*num_closed_issues/(CASE WHEN num_issues > 0 THEN num_issues ELSE 1 END) WHERE id=?", + milestoneID, + ) + return } func changeMilestoneAssign(e *xorm.Session, doer *User, issue *Issue, oldMilestoneID int64) error { + if err := updateIssueCols(e, issue, "milestone_id"); err != nil { + return err + } + if oldMilestoneID > 0 { - m, err := getMilestoneByRepoID(e, issue.RepoID, oldMilestoneID) - if err != nil { + if err := updateMilestoneTotalNum(e, oldMilestoneID); err != nil { return err } - - m.NumIssues-- if issue.IsClosed { - m.NumClosedIssues-- - } - - if err = updateMilestone(e, m); err != nil { - return err + if err := updateMilestoneClosedNum(e, oldMilestoneID); err != nil { + return err + } } } if issue.MilestoneID > 0 { - m, err := getMilestoneByRepoID(e, issue.RepoID, issue.MilestoneID) - if err != nil { + if err := updateMilestoneTotalNum(e, issue.MilestoneID); err != nil { return err } - - m.NumIssues++ if issue.IsClosed { - m.NumClosedIssues++ + if err := updateMilestoneClosedNum(e, issue.MilestoneID); err != nil { + return err + } } + } - if err = updateMilestone(e, m); err != nil { + if oldMilestoneID > 0 || issue.MilestoneID > 0 { + if err := issue.loadRepo(e); err != nil { return err } - } - - if err := issue.loadRepo(e); err != nil { - return err - } - if oldMilestoneID > 0 || issue.MilestoneID > 0 { if _, err := createMilestoneComment(e, doer, issue.Repo, issue, oldMilestoneID, issue.MilestoneID); err != nil { return err } } - return updateIssueCols(e, issue, "milestone_id") + return nil } // ChangeMilestoneAssign changes assignment of milestone for issue. diff --git a/models/issue_milestone_test.go b/models/issue_milestone_test.go index 09c6ff7595aee..6f8548ec67155 100644 --- a/models/issue_milestone_test.go +++ b/models/issue_milestone_test.go @@ -231,7 +231,7 @@ func TestChangeMilestoneStatus(t *testing.T) { CheckConsistencyFor(t, &Repository{ID: milestone.RepoID}, &Milestone{}) } -func TestChangeMilestoneIssueStats(t *testing.T) { +func TestUpdateMilestoneClosedNum(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) issue := AssertExistsAndLoadBean(t, &Issue{MilestoneID: 1}, "is_closed=0").(*Issue) @@ -240,14 +240,14 @@ func TestChangeMilestoneIssueStats(t *testing.T) { issue.ClosedUnix = timeutil.TimeStampNow() _, err := x.Cols("is_closed", "closed_unix").Update(issue) assert.NoError(t, err) - assert.NoError(t, changeMilestoneIssueStats(x.NewSession(), issue)) + assert.NoError(t, updateMilestoneClosedNum(x, issue.MilestoneID)) CheckConsistencyFor(t, &Milestone{}) issue.IsClosed = false issue.ClosedUnix = 0 _, err = x.Cols("is_closed", "closed_unix").Update(issue) assert.NoError(t, err) - assert.NoError(t, changeMilestoneIssueStats(x.NewSession(), issue)) + assert.NoError(t, updateMilestoneClosedNum(x, issue.MilestoneID)) CheckConsistencyFor(t, &Milestone{}) } From 08896cd9f657c3697af0ed2415a8461080a0eb0a Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 7 Oct 2019 06:59:17 +0200 Subject: [PATCH 031/173] add file line count info on UI (#8396) Also reworked the header to remove the filename (which is redundant with the file path above) and made the header a flexbox with a monospace font. Fixes: https://github.com/go-gitea/gitea/issues/8170 --- options/locale/locale_en-US.ini | 1 + public/css/index.css | 5 +- public/less/_repository.less | 20 +++++++- routers/repo/view.go | 2 + templates/repo/view_file.tmpl | 82 +++++++++++++++++---------------- 5 files changed, 68 insertions(+), 42 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index c8be059b72027..d9d27af26f39d 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -681,6 +681,7 @@ stored_lfs = Stored with Git LFS commit_graph = Commit Graph blame = Blame normal_view = Normal View +lines = lines editor.new_file = New File editor.upload_file = Upload File diff --git a/public/css/index.css b/public/css/index.css index 496194decc352..0efd787122241 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -494,7 +494,7 @@ footer .ui.left,footer .ui.right{line-height:40px} .repository.file.list #repo-files-table tr:hover{background-color:#ffe} .repository.file.list #repo-files-table .jumpable-path{color:#888} .repository.file.list .non-diff-file-content .header .icon{font-size:1em} -.repository.file.list .non-diff-file-content .header .file-actions{margin-top:0;margin-bottom:-5px;padding-left:20px} +.repository.file.list .non-diff-file-content .header .file-actions{margin-bottom:-5px} .repository.file.list .non-diff-file-content .header .file-actions .btn-octicon{display:inline-block;padding:5px;margin-left:5px;line-height:1;color:#767676;vertical-align:middle;background:0 0;border:0;outline:0} .repository.file.list .non-diff-file-content .header .file-actions .btn-octicon:hover{color:#4078c0} .repository.file.list .non-diff-file-content .header .file-actions .btn-octicon-danger:hover{color:#bd2c00} @@ -878,6 +878,9 @@ tbody.commit-list{vertical-align:baseline} .repo-buttons .disabled-repo-button a.button:hover{background:0 0!important;color:rgba(0,0,0,.6)!important;box-shadow:0 0 0 1px rgba(34,36,38,.15) inset!important} .repo-buttons .ui.labeled.button>.label{border-left:0!important;margin:0!important} .tag-code,.tag-code td{background-color:#f0f0f0!important;border-color:#d3cfcf!important;padding-top:8px;padding-bottom:8px} +.file-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px!important} +.file-info{display:flex;align-items:center} +.file-info-entry+.file-info-entry{border-left:1px solid currentColor;margin-left:8px;padding-left:8px} .CodeMirror{font:14px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace} .CodeMirror.cm-s-default{border-radius:3px;padding:0!important} .CodeMirror .cm-comment{background:inherit!important} diff --git a/public/less/_repository.less b/public/less/_repository.less index ade3477ccca7b..0527759ed4826 100644 --- a/public/less/_repository.less +++ b/public/less/_repository.less @@ -371,9 +371,7 @@ } .file-actions { - margin-top: 0; margin-bottom: -5px; - padding-left: 20px; .btn-octicon { display: inline-block; @@ -2385,3 +2383,21 @@ tbody.commit-list { padding-top: 8px; padding-bottom: 8px; } + +.file-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 8px 12px !important; +} + +.file-info { + display: flex; + align-items: center; +} + +.file-info-entry + .file-info-entry { + border-left: 1px solid currentColor; + margin-left: 8px; + padding-left: 8px; +} diff --git a/routers/repo/view.go b/routers/repo/view.go index 00790a4ef35be..1967b511ca4f7 100644 --- a/routers/repo/view.go +++ b/routers/repo/view.go @@ -304,6 +304,8 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st var output bytes.Buffer lines := strings.Split(fileContent, "\n") + ctx.Data["NumLines"] = len(lines) + //Remove blank line at the end of file if len(lines) > 0 && lines[len(lines)-1] == "" { lines = lines[:len(lines)-1] diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl index 50e4c33946b1e..71607bd1f8b74 100644 --- a/templates/repo/view_file.tmpl +++ b/templates/repo/view_file.tmpl @@ -1,48 +1,52 @@

-

-
-
- {{if .ReadmeExist}} - - {{if .ReadmeInList}} - {{.FileName}} - {{else}} - {{.FileName}} {{FileSize .FileSize}}{{if .IsLFSFile}} ({{.i18n.Tr "repo.stored_lfs"}}){{end}} +

+
+ {{if .ReadmeInList}} + + {{.FileName}} + {{else}} +
+ {{if .NumLines}} +
+ {{.NumLines}} {{.i18n.Tr "repo.lines"}} +
{{end}} - {{else}} - - {{.FileName}} {{FileSize .FileSize}}{{if .IsLFSFile}} ({{.i18n.Tr "repo.stored_lfs"}}){{end}} - {{end}} -
-
- {{if not .ReadmeInList}} -
-
- {{.i18n.Tr "repo.file_raw"}} - {{if not .IsViewCommit}} - {{.i18n.Tr "repo.file_permalink"}} - {{end}} - {{if .IsTextFile}} - {{.i18n.Tr "repo.blame"}} - {{end}} - {{.i18n.Tr "repo.file_history"}} + {{if .FileSize}} +
+ {{FileSize .FileSize}}{{if .IsLFSFile}} ({{.i18n.Tr "repo.stored_lfs"}}){{end}}
- {{if .Repository.CanEnableEditor}} - {{if .CanEditFile}} - - {{else}} - - {{end}} - {{if .CanDeleteFile}} - - {{else}} - - {{end}} - {{end}} -
+ {{end}} +
+ {{end}} +
+ {{if not .ReadmeInList}} +
+
+
+ {{.i18n.Tr "repo.file_raw"}} + {{if not .IsViewCommit}} + {{.i18n.Tr "repo.file_permalink"}} + {{end}} + {{if .IsTextFile}} + {{.i18n.Tr "repo.blame"}} + {{end}} + {{.i18n.Tr "repo.file_history"}} +
+ {{if .Repository.CanEnableEditor}} + {{if .CanEditFile}} + + {{else}} + + {{end}} + {{if .CanDeleteFile}} + + {{else}} + + {{end}} {{end}}
+ {{end}}

From 356e1a70ea4fb8b30ac2014284511773ce59bcf5 Mon Sep 17 00:00:00 2001 From: guillep2k <18600385+guillep2k@users.noreply.github.com> Date: Mon, 7 Oct 2019 02:49:14 -0300 Subject: [PATCH 032/173] Reduce test sensibility (#8393) --- modules/charset/charset_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/charset/charset_test.go b/modules/charset/charset_test.go index 3c77f127894df..a81a6e03eecad 100644 --- a/modules/charset/charset_test.go +++ b/modules/charset/charset_test.go @@ -179,7 +179,8 @@ func TestToUTF8DropErrors(t *testing.T) { // "Hola, así cómo ños" res = ToUTF8DropErrors([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0xF1, 0x6F, 0x73}) - assert.Equal(t, []byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xC3, 0xAD, 0x20, 0x63, 0xC3, 0xB3, 0x6D, 0x6F, 0x20, 0xC3, 0xB1, 0x6F, 0x73}, res) + assert.Equal(t, []byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73}, res[:8]) + assert.Equal(t, []byte{0x73}, res[len(res)-1:]) // "Hola, así cómo " minmatch := []byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xC3, 0xAD, 0x20, 0x63, 0xC3, 0xB3, 0x6D, 0x6F, 0x20} From 249dbbe0bcc57e3034321fdf7b933c62f34cfa83 Mon Sep 17 00:00:00 2001 From: kolaente Date: Mon, 7 Oct 2019 19:22:35 +0200 Subject: [PATCH 033/173] Update golangci to v1.19.1 (#8414) Signed-off-by: kolaente --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b881bc9553205..e8220ef36c1a8 100644 --- a/Makefile +++ b/Makefile @@ -515,6 +515,6 @@ pr: golangci-lint: @hash golangci-lint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ export BINARY="golangci-lint"; \ - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin v1.18.0; \ + curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin v1.19.1; \ fi golangci-lint run --deadline=3m From af6cc5b9d86ea8e4afa7e906f6bd2b4af3cfe545 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Mon, 7 Oct 2019 17:24:26 +0000 Subject: [PATCH 034/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_de-DE.ini | 11 +++++++++++ options/locale/locale_pt-BR.ini | 2 ++ 2 files changed, 13 insertions(+) diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 3add4be1a95f9..fcec489af8fdf 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -318,6 +318,7 @@ enterred_invalid_repo_name=Der eingegebenen Repository-Name ist falsch. enterred_invalid_owner_name=Der Name des neuen Besitzers ist ungültig. enterred_invalid_password=Das eingegebene Passwort ist falsch. user_not_exist=Dieser Benutzer ist nicht vorhanden. +team_not_exist=Dieses Team existiert nicht. last_org_owner=Du kannst den letzten Benutzer nicht aus dem „Besitzer“-Team entfernen. Es muss mindestens einen Besitzer in einer Organisation geben. cannot_add_org_to_team=Eine Organisation kann nicht als Teammitglied hinzugefügt werden. @@ -679,6 +680,7 @@ stored_lfs=Gespeichert mit Git LFS commit_graph=Commit graph blame=Blame normal_view=Normale Ansicht +lines=Zeilen editor.new_file=Neue Datei editor.upload_file=Datei hochladen @@ -704,6 +706,7 @@ editor.delete=„%s“ löschen editor.commit_message_desc=Eine ausführlichere (optionale) Beschreibung hinzufügen… editor.commit_directly_to_this_branch=Direkt in den Branch „%s“ einchecken. editor.create_new_branch=Einen neuen Branch für diesen Commit erstellen und einen Pull Request starten. +editor.create_new_branch_np=Erstelle einen neuen Branch für diesen Commit. editor.propose_file_change=Dateiänderung vorschlagen editor.new_branch_name_desc=Neuer Branchname… editor.cancel=Abbrechen @@ -1131,6 +1134,7 @@ settings.collaboration=Mitarbeiter settings.collaboration.admin=Administrator settings.collaboration.write=Schreibrechte settings.collaboration.read=Leserechte +settings.collaboration.owner=Besitzer settings.collaboration.undefined=Nicht definiert settings.hooks=Webhooks settings.githooks=Git-Hooks @@ -1212,6 +1216,11 @@ settings.collaborator_deletion_desc=Nach dem Löschen wird dieser Mitarbeiter ke settings.remove_collaborator_success=Der Mitarbeiter wurde entfernt. settings.search_user_placeholder=Benutzer suchen… settings.org_not_allowed_to_be_collaborator=Organisationen können nicht als Mitarbeiter hinzugefügt werden. +settings.change_team_access_not_allowed=Nur der Besitzer der Organisation kann die Zugangsrechte des Teams ändern +settings.team_not_in_organization=Das Team ist nicht in der gleichen Organisation wie das Repository +settings.add_team_duplicate=Das Team ist dem Repository schon zugeordnet +settings.add_team_success=Das Team hat nun Zugriff auf das Repository. +settings.remove_team_success=Der Zugriff des Teams auf das Repository wurde zurückgezogen. settings.add_webhook=Webhook hinzufügen settings.add_webhook.invalid_channel_name=Der Name des Webhook-Kanals darf nicht leer sein und darf nicht nur das Zeichen # enthalten. settings.hooks_desc=Webhooks senden bei bestimmten Gitea-Events automatisch „HTTP POST“-Anfragen an einen Server. Lies mehr in unserer Anleitung zu Webhooks (auf Englisch). @@ -1469,6 +1478,8 @@ settings.options=Organisation settings.full_name=Vollständiger Name settings.website=Webseite settings.location=Standort +settings.permission=Berechtigungen +settings.repoadminchangeteam=Der Repository-Administrator kann den Zugriff für Teams hinzufügen und zurückziehen settings.visibility=Sichtbarkeit settings.visibility.public=Öffentlich settings.visibility.limited=Eingeschränkt (nur für angemeldete Nutzer sichtbar) diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 66c2d9fd4cdb8..76890ddc794d2 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -680,6 +680,7 @@ stored_lfs=Armazenado com Git LFS commit_graph=Gráfico de commits blame=Anotar normal_view=Visão normal +lines=linhas editor.new_file=Novo arquivo editor.upload_file=Enviar arquivo @@ -705,6 +706,7 @@ editor.delete=Excluir '%s' editor.commit_message_desc=Adicione uma descrição detalhada (opcional)... editor.commit_directly_to_this_branch=Commit diretamente no branch %s. editor.create_new_branch=Crie um novo branch para este commit e crie um pull request. +editor.create_new_branch_np=Crie um novo branch para este commit. editor.propose_file_change=Propor alteração de arquivo editor.new_branch_name_desc=Novo nome do branch... editor.cancel=Cancelar From 1b96c4a471e016c5c61cec5caa54ebc00401a961 Mon Sep 17 00:00:00 2001 From: guillep2k <18600385+guillep2k@users.noreply.github.com> Date: Mon, 7 Oct 2019 16:51:54 -0300 Subject: [PATCH 035/173] Fix backers badge (#8399) --- README.md | 2 +- README_ZH.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 92ed78a497dc7..5d565e4a3ad1d 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ [![GoDoc](https://godoc.org/code.gitea.io/gitea?status.svg)](https://godoc.org/code.gitea.io/gitea) [![GitHub release](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest) [![Help Contribute to Open Source](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea) -[![Become a backer/sponsor of gitea](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backer&color=brightgreen)](https://opencollective.com/gitea) +[![Become a backer/sponsor of gitea](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) ## Purpose diff --git a/README_ZH.md b/README_ZH.md index e143f23b417bc..b546a15a3eb2a 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -9,7 +9,7 @@ [![Go Report Card](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea) [![GoDoc](https://godoc.org/code.gitea.io/gitea?status.svg)](https://godoc.org/code.gitea.io/gitea) [![GitHub release](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest) -[![Become a backer/sponsor of gitea](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backer&color=brightgreen)](https://opencollective.com/gitea) +[![Become a backer/sponsor of gitea](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) ## 目标 From 662a40ea29261167f43bdd3f695a6b22e2958de0 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 8 Oct 2019 05:44:58 +0800 Subject: [PATCH 036/173] Update milestone issues numbers when save milestone and other code improvements (#8411) * update milestone issues numbers when save milestone and other code improvements * fix tests * extract duplicate codes as a new function --- models/issue_milestone.go | 67 ++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/models/issue_milestone.go b/models/issue_milestone.go index 29e13689bf3ab..1587e5e341c7f 100644 --- a/models/issue_milestone.go +++ b/models/issue_milestone.go @@ -10,6 +10,7 @@ import ( "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" + "xorm.io/builder" "github.com/go-xorm/xorm" ) @@ -191,7 +192,6 @@ func (milestones MilestoneList) getMilestoneIDs() []int64 { // GetMilestonesByRepoID returns all opened milestones of a repository. func GetMilestonesByRepoID(repoID int64, state api.StateType) (MilestoneList, error) { - sess := x.Where("repo_id = ?", repoID) switch state { @@ -238,13 +238,34 @@ func GetMilestones(repoID int64, page int, isClosed bool, sortType string) (Mile } func updateMilestone(e Engine, m *Milestone) error { - _, err := e.ID(m.ID).AllCols().Update(m) + _, err := e.ID(m.ID).AllCols(). + SetExpr("num_issues", builder.Select("count(*)").From("issue").Where( + builder.Eq{"milestone_id": m.ID}, + )). + SetExpr("num_closed_issues", builder.Select("count(*)").From("issue").Where( + builder.Eq{ + "milestone_id": m.ID, + "is_closed": true, + }, + )). + Update(m) return err } // UpdateMilestone updates information of given milestone. func UpdateMilestone(m *Milestone) error { - return updateMilestone(x, m) + if err := updateMilestone(x, m); err != nil { + return err + } + + return updateMilestoneCompleteness(x, m.ID) +} + +func updateMilestoneCompleteness(e Engine, milestoneID int64) error { + _, err := e.Exec("UPDATE `milestone` SET completeness=100*num_closed_issues/(CASE WHEN num_issues > 0 THEN num_issues ELSE 1 END) WHERE id=?", + milestoneID, + ) + return err } func countRepoMilestones(e Engine, repoID int64) (int64, error) { @@ -278,11 +299,6 @@ func MilestoneStats(repoID int64) (open int64, closed int64, err error) { // ChangeMilestoneStatus changes the milestone open/closed status. func ChangeMilestoneStatus(m *Milestone, isClosed bool) (err error) { - repo, err := GetRepositoryByID(m.RepoID) - if err != nil { - return err - } - sess := x.NewSession() defer sess.Close() if err = sess.Begin(); err != nil { @@ -290,27 +306,27 @@ func ChangeMilestoneStatus(m *Milestone, isClosed bool) (err error) { } m.IsClosed = isClosed - if err = updateMilestone(sess, m); err != nil { + if _, err := sess.ID(m.ID).Cols("is_closed").Update(m); err != nil { return err } - numMilestones, err := countRepoMilestones(sess, repo.ID) - if err != nil { + if err := updateRepoMilestoneNum(sess, m.RepoID); 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 { - return err - } return sess.Commit() } +func updateRepoMilestoneNum(e Engine, repoID int64) error { + _, err := e.Exec("UPDATE `repository` SET num_milestones=(SELECT count(*) FROM milestone WHERE repo_id=?),num_closed_milestones=(SELECT count(*) FROM milestone WHERE repo_id=? AND is_closed=?) WHERE id=?", + repoID, + repoID, + true, + repoID, + ) + return err +} + func updateMilestoneTotalNum(e Engine, milestoneID int64) (err error) { if _, err = e.Exec("UPDATE `milestone` SET num_issues=(SELECT count(*) FROM issue WHERE milestone_id=?) WHERE id=?", milestoneID, @@ -319,11 +335,7 @@ func updateMilestoneTotalNum(e Engine, milestoneID int64) (err error) { return } - _, err = e.Exec("UPDATE `milestone` SET completeness=100*num_closed_issues/(CASE WHEN num_issues > 0 THEN num_issues ELSE 1 END) WHERE id=?", - milestoneID, - ) - - return + return updateMilestoneCompleteness(e, milestoneID) } func updateMilestoneClosedNum(e Engine, milestoneID int64) (err error) { @@ -335,10 +347,7 @@ func updateMilestoneClosedNum(e Engine, milestoneID int64) (err error) { return } - _, err = e.Exec("UPDATE `milestone` SET completeness=100*num_closed_issues/(CASE WHEN num_issues > 0 THEN num_issues ELSE 1 END) WHERE id=?", - milestoneID, - ) - return + return updateMilestoneCompleteness(e, milestoneID) } func changeMilestoneAssign(e *xorm.Session, doer *User, issue *Issue, oldMilestoneID int64) error { From 28d5347cf3da0a0e3c192f39b553c0ae6df53a09 Mon Sep 17 00:00:00 2001 From: Lauris BH Date: Tue, 8 Oct 2019 02:38:41 +0300 Subject: [PATCH 037/173] Singular form for files that has only one line (#8416) --- options/locale/locale_en-US.ini | 1 + templates/repo/view_file.tmpl | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index d9d27af26f39d..ca09b6120d717 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -681,6 +681,7 @@ stored_lfs = Stored with Git LFS commit_graph = Commit Graph blame = Blame normal_view = Normal View +line = line lines = lines editor.new_file = New File diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl index 71607bd1f8b74..e3d346db3efa6 100644 --- a/templates/repo/view_file.tmpl +++ b/templates/repo/view_file.tmpl @@ -8,7 +8,7 @@
{{if .NumLines}}
- {{.NumLines}} {{.i18n.Tr "repo.lines"}} + {{.NumLines}} {{.i18n.Tr (TrN .i18n.Lang .NumLines "repo.line" "repo.lines") }}
{{end}} {{if .FileSize}} From 1a269f7ef81b1a7865c4679b91a4037059ad4938 Mon Sep 17 00:00:00 2001 From: 6543 <24977596+6543@users.noreply.github.com> Date: Tue, 8 Oct 2019 04:03:44 +0200 Subject: [PATCH 038/173] add 6543 to maintainers (#8417) --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index bf657fabe2260..9d3e4bc8483a0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -33,3 +33,4 @@ silverwind (@silverwind) Gary Kim (@gary-kim) Guillermo Prandi (@guillep2k) Mura Li (@typeless) +6543 <6543@obermui.de> (@6543) From 78438d310be42f9c5e0e2937ee54e6050cc8f381 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 8 Oct 2019 10:57:41 +0800 Subject: [PATCH 039/173] Fix issues/pr list broken when there are many repositories (#8409) * fix issues/pr list broken when there are many repositories * remove unused codes * fix counting error on issues/prs * keep the old logic * fix panic * fix tests --- models/issue.go | 54 ++++++++++------- models/issue_test.go | 11 ++-- models/user.go | 61 +++++++------------ models/user_test.go | 22 ------- routers/user/home.go | 140 +++++++++++++++---------------------------- 5 files changed, 110 insertions(+), 178 deletions(-) diff --git a/models/issue.go b/models/issue.go index e4cc1291c2a7d..cfa6191b4744d 100644 --- a/models/issue.go +++ b/models/issue.go @@ -1306,18 +1306,19 @@ func GetIssuesByIDs(issueIDs []int64) ([]*Issue, error) { // IssuesOptions represents options of an issue. type IssuesOptions struct { - RepoIDs []int64 // include all repos if empty - AssigneeID int64 - PosterID int64 - MentionedID int64 - MilestoneID int64 - Page int - PageSize int - IsClosed util.OptionalBool - IsPull util.OptionalBool - LabelIDs []int64 - SortType string - IssueIDs []int64 + RepoIDs []int64 // include all repos if empty + RepoSubQuery *builder.Builder + AssigneeID int64 + PosterID int64 + MentionedID int64 + MilestoneID int64 + Page int + PageSize int + IsClosed util.OptionalBool + IsPull util.OptionalBool + LabelIDs []int64 + SortType string + IssueIDs []int64 } // sortIssuesSession sort an issues-related session based on the provided @@ -1360,7 +1361,9 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) { sess.In("issue.id", opts.IssueIDs) } - if len(opts.RepoIDs) > 0 { + if opts.RepoSubQuery != nil { + sess.In("issue.repo_id", opts.RepoSubQuery) + } else if len(opts.RepoIDs) > 0 { // In case repository IDs are provided but actually no repository has issue. sess.In("issue.repo_id", opts.RepoIDs) } @@ -1627,12 +1630,12 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) { // UserIssueStatsOptions contains parameters accepted by GetUserIssueStats. type UserIssueStatsOptions struct { - UserID int64 - RepoID int64 - UserRepoIDs []int64 - FilterMode int - IsPull bool - IsClosed bool + UserID int64 + RepoID int64 + RepoSubQuery *builder.Builder + FilterMode int + IsPull bool + IsClosed bool } // GetUserIssueStats returns issue statistic information for dashboard by given conditions. @@ -1646,16 +1649,23 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) { cond = cond.And(builder.Eq{"issue.repo_id": opts.RepoID}) } + var repoCond = builder.NewCond() + if opts.RepoSubQuery != nil { + repoCond = builder.In("issue.repo_id", opts.RepoSubQuery) + } else { + repoCond = builder.Expr("0=1") + } + switch opts.FilterMode { case FilterModeAll: stats.OpenCount, err = x.Where(cond).And("is_closed = ?", false). - And(builder.In("issue.repo_id", opts.UserRepoIDs)). + And(repoCond). Count(new(Issue)) if err != nil { return nil, err } stats.ClosedCount, err = x.Where(cond).And("is_closed = ?", true). - And(builder.In("issue.repo_id", opts.UserRepoIDs)). + And(repoCond). Count(new(Issue)) if err != nil { return nil, err @@ -1730,7 +1740,7 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) { } stats.YourRepositoriesCount, err = x.Where(cond). - And(builder.In("issue.repo_id", opts.UserRepoIDs)). + And(repoCond). Count(new(Issue)) if err != nil { return nil, err diff --git a/models/issue_test.go b/models/issue_test.go index 9cd9ff0ad98a8..65f4d6ba664fd 100644 --- a/models/issue_test.go +++ b/models/issue_test.go @@ -10,6 +10,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "xorm.io/builder" ) func TestIssue_ReplaceLabels(t *testing.T) { @@ -266,10 +267,12 @@ func TestGetUserIssueStats(t *testing.T) { }, { UserIssueStatsOptions{ - UserID: 2, - UserRepoIDs: []int64{1, 2}, - FilterMode: FilterModeAll, - IsClosed: true, + UserID: 2, + RepoSubQuery: builder.Select("repository.id"). + From("repository"). + Where(builder.In("repository.id", []int64{1, 2})), + FilterMode: FilterModeAll, + IsClosed: true, }, IssueStats{ YourRepositoriesCount: 2, diff --git a/models/user.go b/models/user.go index 030e23c383afb..8c4befb139612 100644 --- a/models/user.go +++ b/models/user.go @@ -615,50 +615,35 @@ func (u *User) GetRepositories(page, pageSize int) (err error) { return err } -// GetRepositoryIDs returns repositories IDs where user owned and has unittypes -func (u *User) GetRepositoryIDs(units ...UnitType) ([]int64, error) { - var ids []int64 - - sess := x.Table("repository").Cols("repository.id") +// UnitRepositoriesSubQuery returns repositories query builder according units +func (u *User) UnitRepositoriesSubQuery(units ...UnitType) *builder.Builder { + b := builder.Select("repository.id").From("repository") if len(units) > 0 { - sess = sess.Join("INNER", "repo_unit", "repository.id = repo_unit.repo_id") - sess = sess.In("repo_unit.type", units) + b.Join("INNER", "repo_unit", builder.Expr("repository.id = repo_unit.repo_id"). + And(builder.In("repo_unit.type", units)), + ) } - - return ids, sess.Where("owner_id = ?", u.ID).Find(&ids) + return b.Where(builder.Eq{"repository.owner_id": u.ID}) } -// GetOrgRepositoryIDs returns repositories IDs where user's team owned and has unittypes -func (u *User) GetOrgRepositoryIDs(units ...UnitType) ([]int64, error) { - var ids []int64 - - sess := x.Table("repository"). - Cols("repository.id"). - Join("INNER", "team_user", "repository.owner_id = team_user.org_id"). - Join("INNER", "team_repo", "repository.is_private != ? OR (team_user.team_id = team_repo.team_id AND repository.id = team_repo.repo_id)", true) - +// OrgUnitRepositoriesSubQuery returns repositories query builder according orgnizations and units +func (u *User) OrgUnitRepositoriesSubQuery(userID int64, units ...UnitType) *builder.Builder { + b := builder. + Select("team_repo.repo_id"). + From("team_repo"). + Join("INNER", "team_user", builder.Eq{"team_user.uid": userID}.And( + builder.Expr("team_user.team_id = team_repo.team_id"), + )) if len(units) > 0 { - sess = sess.Join("INNER", "team_unit", "team_unit.team_id = team_user.team_id") - sess = sess.In("team_unit.type", units) - } - - return ids, sess. - Where("team_user.uid = ?", u.ID). - GroupBy("repository.id").Find(&ids) -} - -// GetAccessRepoIDs returns all repositories IDs where user's or user is a team member organizations -func (u *User) GetAccessRepoIDs(units ...UnitType) ([]int64, error) { - ids, err := u.GetRepositoryIDs(units...) - if err != nil { - return nil, err - } - ids2, err := u.GetOrgRepositoryIDs(units...) - if err != nil { - return nil, err - } - return append(ids, ids2...), nil + b.Join("INNER", "team_unit", builder.Eq{"team_unit.org_id": u.ID}.And( + builder.Expr("team_unit.team_id = team_repo.team_id").And( + builder.In("`type`", units), + ), + )) + } + return b.Where(builder.Eq{"team_repo.org_id": u.ID}). + GroupBy("team_repo.repo_id") } // GetMirrorRepositories returns mirror repositories that user owns, including private repositories. diff --git a/models/user_test.go b/models/user_test.go index bcb955817c330..75d806eadc34f 100644 --- a/models/user_test.go +++ b/models/user_test.go @@ -275,28 +275,6 @@ func BenchmarkHashPassword(b *testing.B) { } } -func TestGetOrgRepositoryIDs(t *testing.T) { - assert.NoError(t, PrepareTestDatabase()) - user2 := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) - user4 := AssertExistsAndLoadBean(t, &User{ID: 4}).(*User) - user5 := AssertExistsAndLoadBean(t, &User{ID: 5}).(*User) - - accessibleRepos, err := user2.GetOrgRepositoryIDs() - assert.NoError(t, err) - // User 2's team has access to private repos 3, 5, repo 32 is a public repo of the organization - assert.Equal(t, []int64{3, 5, 23, 24, 32}, accessibleRepos) - - accessibleRepos, err = user4.GetOrgRepositoryIDs() - assert.NoError(t, err) - // User 4's team has access to private repo 3, repo 32 is a public repo of the organization - assert.Equal(t, []int64{3, 32}, accessibleRepos) - - accessibleRepos, err = user5.GetOrgRepositoryIDs() - assert.NoError(t, err) - // User 5's team has no access to any repo - assert.Len(t, accessibleRepos, 0) -} - func TestNewGitSig(t *testing.T) { users := make([]*User, 0, 20) sess := x.NewSession() diff --git a/routers/user/home.go b/routers/user/home.go index 40b3bc3fc1b81..21fc62aae5507 100644 --- a/routers/user/home.go +++ b/routers/user/home.go @@ -14,13 +14,11 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "github.com/keybase/go-crypto/openpgp" "github.com/keybase/go-crypto/openpgp/armor" - "github.com/unknwon/com" ) const ( @@ -152,6 +150,24 @@ func Dashboard(ctx *context.Context) { // Issues render the user issues page func Issues(ctx *context.Context) { isPullList := ctx.Params(":type") == "pulls" + repoID := ctx.QueryInt64("repo") + if repoID > 0 { + repo, err := models.GetRepositoryByID(repoID) + if err != nil { + ctx.ServerError("GetRepositoryByID", err) + return + } + perm, err := models.GetUserRepoPermission(repo, ctx.User) + if err != nil { + ctx.ServerError("GetUserRepoPermission", err) + return + } + if !perm.CanReadIssuesOrPulls(isPullList) { + ctx.NotFound("Repository does not exist or you have no permission", nil) + return + } + } + if isPullList { ctx.Data["Title"] = ctx.Tr("pull_requests") ctx.Data["PageIsPulls"] = true @@ -194,58 +210,32 @@ func Issues(ctx *context.Context) { page = 1 } - repoID := ctx.QueryInt64("repo") - isShowClosed := ctx.Query("state") == "closed" + var ( + isShowClosed = ctx.Query("state") == "closed" + err error + opts = &models.IssuesOptions{ + IsClosed: util.OptionalBoolOf(isShowClosed), + IsPull: util.OptionalBoolOf(isPullList), + SortType: sortType, + } + ) // Get repositories. - var err error - var userRepoIDs []int64 - if ctxUser.IsOrganization() { - env, err := ctxUser.AccessibleReposEnv(ctx.User.ID) - if err != nil { - ctx.ServerError("AccessibleReposEnv", err) - return - } - userRepoIDs, err = env.RepoIDs(1, ctxUser.NumRepos) - if err != nil { - ctx.ServerError("env.RepoIDs", err) - return - } + if repoID > 0 { + opts.RepoIDs = []int64{repoID} } else { unitType := models.UnitTypeIssues if isPullList { unitType = models.UnitTypePullRequests } - userRepoIDs, err = ctxUser.GetAccessRepoIDs(unitType) - if err != nil { - ctx.ServerError("ctxUser.GetAccessRepoIDs", err) - return + if ctxUser.IsOrganization() { + opts.RepoSubQuery = ctxUser.OrgUnitRepositoriesSubQuery(ctx.User.ID, unitType) + } else { + opts.RepoSubQuery = ctxUser.UnitRepositoriesSubQuery(unitType) } } - if len(userRepoIDs) == 0 { - userRepoIDs = []int64{-1} - } - - opts := &models.IssuesOptions{ - IsClosed: util.OptionalBoolOf(isShowClosed), - IsPull: util.OptionalBoolOf(isPullList), - SortType: sortType, - } - - if repoID > 0 { - opts.RepoIDs = []int64{repoID} - } switch filterMode { - case models.FilterModeAll: - if repoID > 0 { - if !com.IsSliceContainsInt64(userRepoIDs, repoID) { - // force an empty result - opts.RepoIDs = []int64{-1} - } - } else { - opts.RepoIDs = userRepoIDs - } case models.FilterModeAssign: opts.AssigneeID = ctxUser.ID case models.FilterModeCreate: @@ -254,14 +244,6 @@ func Issues(ctx *context.Context) { opts.MentionedID = ctxUser.ID } - counts, err := models.CountIssuesByRepo(opts) - if err != nil { - ctx.ServerError("CountIssuesByRepo", err) - return - } - - opts.Page = page - opts.PageSize = setting.UI.IssuePagingNum var labelIDs []int64 selectLabels := ctx.Query("labels") if len(selectLabels) > 0 && selectLabels != "0" { @@ -273,6 +255,15 @@ func Issues(ctx *context.Context) { } opts.LabelIDs = labelIDs + counts, err := models.CountIssuesByRepo(opts) + if err != nil { + ctx.ServerError("CountIssuesByRepo", err) + return + } + + opts.Page = page + opts.PageSize = setting.UI.IssuePagingNum + issues, err := models.Issues(opts) if err != nil { ctx.ServerError("Issues", err) @@ -289,41 +280,6 @@ func Issues(ctx *context.Context) { showReposMap[repoID] = repo } - if repoID > 0 { - if _, ok := showReposMap[repoID]; !ok { - repo, err := models.GetRepositoryByID(repoID) - if models.IsErrRepoNotExist(err) { - ctx.NotFound("GetRepositoryByID", err) - return - } else if err != nil { - ctx.ServerError("GetRepositoryByID", fmt.Errorf("[%d]%v", repoID, err)) - return - } - showReposMap[repoID] = repo - } - - repo := showReposMap[repoID] - - // Check if user has access to given repository. - perm, err := models.GetUserRepoPermission(repo, ctxUser) - if err != nil { - ctx.ServerError("GetUserRepoPermission", fmt.Errorf("[%d]%v", repoID, err)) - return - } - if !perm.CanRead(models.UnitTypeIssues) { - if log.IsTrace() { - log.Trace("Permission Denied: User %-v cannot read %-v of repo %-v\n"+ - "User in repo has Permissions: %-+v", - ctxUser, - models.UnitTypeIssues, - repo, - perm) - } - ctx.Status(404) - return - } - } - showRepos := models.RepositoryListOfMap(showReposMap) sort.Sort(showRepos) if err = showRepos.LoadAttributes(); err != nil { @@ -341,12 +297,12 @@ func Issues(ctx *context.Context) { } issueStats, err := models.GetUserIssueStats(models.UserIssueStatsOptions{ - UserID: ctxUser.ID, - RepoID: repoID, - UserRepoIDs: userRepoIDs, - FilterMode: filterMode, - IsPull: isPullList, - IsClosed: isShowClosed, + UserID: ctxUser.ID, + RepoID: repoID, + RepoSubQuery: opts.RepoSubQuery, + FilterMode: filterMode, + IsPull: isPullList, + IsClosed: isShowClosed, }) if err != nil { ctx.ServerError("GetUserIssueStats", err) From 170743c8a0cdf216ee21076aadc5d905dfef0cd6 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 9 Oct 2019 01:55:16 +0800 Subject: [PATCH 040/173] Revert "Fix issues/pr list broken when there are many repositories (#8409)" (#8427) This reverts commit 78438d310be42f9c5e0e2937ee54e6050cc8f381. --- models/issue.go | 54 +++++++---------- models/issue_test.go | 11 ++-- models/user.go | 61 ++++++++++++------- models/user_test.go | 22 +++++++ routers/user/home.go | 140 ++++++++++++++++++++++++++++--------------- 5 files changed, 178 insertions(+), 110 deletions(-) diff --git a/models/issue.go b/models/issue.go index cfa6191b4744d..e4cc1291c2a7d 100644 --- a/models/issue.go +++ b/models/issue.go @@ -1306,19 +1306,18 @@ func GetIssuesByIDs(issueIDs []int64) ([]*Issue, error) { // IssuesOptions represents options of an issue. type IssuesOptions struct { - RepoIDs []int64 // include all repos if empty - RepoSubQuery *builder.Builder - AssigneeID int64 - PosterID int64 - MentionedID int64 - MilestoneID int64 - Page int - PageSize int - IsClosed util.OptionalBool - IsPull util.OptionalBool - LabelIDs []int64 - SortType string - IssueIDs []int64 + RepoIDs []int64 // include all repos if empty + AssigneeID int64 + PosterID int64 + MentionedID int64 + MilestoneID int64 + Page int + PageSize int + IsClosed util.OptionalBool + IsPull util.OptionalBool + LabelIDs []int64 + SortType string + IssueIDs []int64 } // sortIssuesSession sort an issues-related session based on the provided @@ -1361,9 +1360,7 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) { sess.In("issue.id", opts.IssueIDs) } - if opts.RepoSubQuery != nil { - sess.In("issue.repo_id", opts.RepoSubQuery) - } else if len(opts.RepoIDs) > 0 { + if len(opts.RepoIDs) > 0 { // In case repository IDs are provided but actually no repository has issue. sess.In("issue.repo_id", opts.RepoIDs) } @@ -1630,12 +1627,12 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) { // UserIssueStatsOptions contains parameters accepted by GetUserIssueStats. type UserIssueStatsOptions struct { - UserID int64 - RepoID int64 - RepoSubQuery *builder.Builder - FilterMode int - IsPull bool - IsClosed bool + UserID int64 + RepoID int64 + UserRepoIDs []int64 + FilterMode int + IsPull bool + IsClosed bool } // GetUserIssueStats returns issue statistic information for dashboard by given conditions. @@ -1649,23 +1646,16 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) { cond = cond.And(builder.Eq{"issue.repo_id": opts.RepoID}) } - var repoCond = builder.NewCond() - if opts.RepoSubQuery != nil { - repoCond = builder.In("issue.repo_id", opts.RepoSubQuery) - } else { - repoCond = builder.Expr("0=1") - } - switch opts.FilterMode { case FilterModeAll: stats.OpenCount, err = x.Where(cond).And("is_closed = ?", false). - And(repoCond). + And(builder.In("issue.repo_id", opts.UserRepoIDs)). Count(new(Issue)) if err != nil { return nil, err } stats.ClosedCount, err = x.Where(cond).And("is_closed = ?", true). - And(repoCond). + And(builder.In("issue.repo_id", opts.UserRepoIDs)). Count(new(Issue)) if err != nil { return nil, err @@ -1740,7 +1730,7 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) { } stats.YourRepositoriesCount, err = x.Where(cond). - And(repoCond). + And(builder.In("issue.repo_id", opts.UserRepoIDs)). Count(new(Issue)) if err != nil { return nil, err diff --git a/models/issue_test.go b/models/issue_test.go index 65f4d6ba664fd..9cd9ff0ad98a8 100644 --- a/models/issue_test.go +++ b/models/issue_test.go @@ -10,7 +10,6 @@ import ( "time" "github.com/stretchr/testify/assert" - "xorm.io/builder" ) func TestIssue_ReplaceLabels(t *testing.T) { @@ -267,12 +266,10 @@ func TestGetUserIssueStats(t *testing.T) { }, { UserIssueStatsOptions{ - UserID: 2, - RepoSubQuery: builder.Select("repository.id"). - From("repository"). - Where(builder.In("repository.id", []int64{1, 2})), - FilterMode: FilterModeAll, - IsClosed: true, + UserID: 2, + UserRepoIDs: []int64{1, 2}, + FilterMode: FilterModeAll, + IsClosed: true, }, IssueStats{ YourRepositoriesCount: 2, diff --git a/models/user.go b/models/user.go index 8c4befb139612..030e23c383afb 100644 --- a/models/user.go +++ b/models/user.go @@ -615,35 +615,50 @@ func (u *User) GetRepositories(page, pageSize int) (err error) { return err } -// UnitRepositoriesSubQuery returns repositories query builder according units -func (u *User) UnitRepositoriesSubQuery(units ...UnitType) *builder.Builder { - b := builder.Select("repository.id").From("repository") +// GetRepositoryIDs returns repositories IDs where user owned and has unittypes +func (u *User) GetRepositoryIDs(units ...UnitType) ([]int64, error) { + var ids []int64 + + sess := x.Table("repository").Cols("repository.id") if len(units) > 0 { - b.Join("INNER", "repo_unit", builder.Expr("repository.id = repo_unit.repo_id"). - And(builder.In("repo_unit.type", units)), - ) + sess = sess.Join("INNER", "repo_unit", "repository.id = repo_unit.repo_id") + sess = sess.In("repo_unit.type", units) } - return b.Where(builder.Eq{"repository.owner_id": u.ID}) + + return ids, sess.Where("owner_id = ?", u.ID).Find(&ids) } -// OrgUnitRepositoriesSubQuery returns repositories query builder according orgnizations and units -func (u *User) OrgUnitRepositoriesSubQuery(userID int64, units ...UnitType) *builder.Builder { - b := builder. - Select("team_repo.repo_id"). - From("team_repo"). - Join("INNER", "team_user", builder.Eq{"team_user.uid": userID}.And( - builder.Expr("team_user.team_id = team_repo.team_id"), - )) +// GetOrgRepositoryIDs returns repositories IDs where user's team owned and has unittypes +func (u *User) GetOrgRepositoryIDs(units ...UnitType) ([]int64, error) { + var ids []int64 + + sess := x.Table("repository"). + Cols("repository.id"). + Join("INNER", "team_user", "repository.owner_id = team_user.org_id"). + Join("INNER", "team_repo", "repository.is_private != ? OR (team_user.team_id = team_repo.team_id AND repository.id = team_repo.repo_id)", true) + if len(units) > 0 { - b.Join("INNER", "team_unit", builder.Eq{"team_unit.org_id": u.ID}.And( - builder.Expr("team_unit.team_id = team_repo.team_id").And( - builder.In("`type`", units), - ), - )) - } - return b.Where(builder.Eq{"team_repo.org_id": u.ID}). - GroupBy("team_repo.repo_id") + sess = sess.Join("INNER", "team_unit", "team_unit.team_id = team_user.team_id") + sess = sess.In("team_unit.type", units) + } + + return ids, sess. + Where("team_user.uid = ?", u.ID). + GroupBy("repository.id").Find(&ids) +} + +// GetAccessRepoIDs returns all repositories IDs where user's or user is a team member organizations +func (u *User) GetAccessRepoIDs(units ...UnitType) ([]int64, error) { + ids, err := u.GetRepositoryIDs(units...) + if err != nil { + return nil, err + } + ids2, err := u.GetOrgRepositoryIDs(units...) + if err != nil { + return nil, err + } + return append(ids, ids2...), nil } // GetMirrorRepositories returns mirror repositories that user owns, including private repositories. diff --git a/models/user_test.go b/models/user_test.go index 75d806eadc34f..bcb955817c330 100644 --- a/models/user_test.go +++ b/models/user_test.go @@ -275,6 +275,28 @@ func BenchmarkHashPassword(b *testing.B) { } } +func TestGetOrgRepositoryIDs(t *testing.T) { + assert.NoError(t, PrepareTestDatabase()) + user2 := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) + user4 := AssertExistsAndLoadBean(t, &User{ID: 4}).(*User) + user5 := AssertExistsAndLoadBean(t, &User{ID: 5}).(*User) + + accessibleRepos, err := user2.GetOrgRepositoryIDs() + assert.NoError(t, err) + // User 2's team has access to private repos 3, 5, repo 32 is a public repo of the organization + assert.Equal(t, []int64{3, 5, 23, 24, 32}, accessibleRepos) + + accessibleRepos, err = user4.GetOrgRepositoryIDs() + assert.NoError(t, err) + // User 4's team has access to private repo 3, repo 32 is a public repo of the organization + assert.Equal(t, []int64{3, 32}, accessibleRepos) + + accessibleRepos, err = user5.GetOrgRepositoryIDs() + assert.NoError(t, err) + // User 5's team has no access to any repo + assert.Len(t, accessibleRepos, 0) +} + func TestNewGitSig(t *testing.T) { users := make([]*User, 0, 20) sess := x.NewSession() diff --git a/routers/user/home.go b/routers/user/home.go index 21fc62aae5507..40b3bc3fc1b81 100644 --- a/routers/user/home.go +++ b/routers/user/home.go @@ -14,11 +14,13 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "github.com/keybase/go-crypto/openpgp" "github.com/keybase/go-crypto/openpgp/armor" + "github.com/unknwon/com" ) const ( @@ -150,24 +152,6 @@ func Dashboard(ctx *context.Context) { // Issues render the user issues page func Issues(ctx *context.Context) { isPullList := ctx.Params(":type") == "pulls" - repoID := ctx.QueryInt64("repo") - if repoID > 0 { - repo, err := models.GetRepositoryByID(repoID) - if err != nil { - ctx.ServerError("GetRepositoryByID", err) - return - } - perm, err := models.GetUserRepoPermission(repo, ctx.User) - if err != nil { - ctx.ServerError("GetUserRepoPermission", err) - return - } - if !perm.CanReadIssuesOrPulls(isPullList) { - ctx.NotFound("Repository does not exist or you have no permission", nil) - return - } - } - if isPullList { ctx.Data["Title"] = ctx.Tr("pull_requests") ctx.Data["PageIsPulls"] = true @@ -210,32 +194,58 @@ func Issues(ctx *context.Context) { page = 1 } - var ( - isShowClosed = ctx.Query("state") == "closed" - err error - opts = &models.IssuesOptions{ - IsClosed: util.OptionalBoolOf(isShowClosed), - IsPull: util.OptionalBoolOf(isPullList), - SortType: sortType, - } - ) + repoID := ctx.QueryInt64("repo") + isShowClosed := ctx.Query("state") == "closed" // Get repositories. - if repoID > 0 { - opts.RepoIDs = []int64{repoID} + var err error + var userRepoIDs []int64 + if ctxUser.IsOrganization() { + env, err := ctxUser.AccessibleReposEnv(ctx.User.ID) + if err != nil { + ctx.ServerError("AccessibleReposEnv", err) + return + } + userRepoIDs, err = env.RepoIDs(1, ctxUser.NumRepos) + if err != nil { + ctx.ServerError("env.RepoIDs", err) + return + } } else { unitType := models.UnitTypeIssues if isPullList { unitType = models.UnitTypePullRequests } - if ctxUser.IsOrganization() { - opts.RepoSubQuery = ctxUser.OrgUnitRepositoriesSubQuery(ctx.User.ID, unitType) - } else { - opts.RepoSubQuery = ctxUser.UnitRepositoriesSubQuery(unitType) + userRepoIDs, err = ctxUser.GetAccessRepoIDs(unitType) + if err != nil { + ctx.ServerError("ctxUser.GetAccessRepoIDs", err) + return } } + if len(userRepoIDs) == 0 { + userRepoIDs = []int64{-1} + } + + opts := &models.IssuesOptions{ + IsClosed: util.OptionalBoolOf(isShowClosed), + IsPull: util.OptionalBoolOf(isPullList), + SortType: sortType, + } + + if repoID > 0 { + opts.RepoIDs = []int64{repoID} + } switch filterMode { + case models.FilterModeAll: + if repoID > 0 { + if !com.IsSliceContainsInt64(userRepoIDs, repoID) { + // force an empty result + opts.RepoIDs = []int64{-1} + } + } else { + opts.RepoIDs = userRepoIDs + } case models.FilterModeAssign: opts.AssigneeID = ctxUser.ID case models.FilterModeCreate: @@ -244,6 +254,14 @@ func Issues(ctx *context.Context) { opts.MentionedID = ctxUser.ID } + counts, err := models.CountIssuesByRepo(opts) + if err != nil { + ctx.ServerError("CountIssuesByRepo", err) + return + } + + opts.Page = page + opts.PageSize = setting.UI.IssuePagingNum var labelIDs []int64 selectLabels := ctx.Query("labels") if len(selectLabels) > 0 && selectLabels != "0" { @@ -255,15 +273,6 @@ func Issues(ctx *context.Context) { } opts.LabelIDs = labelIDs - counts, err := models.CountIssuesByRepo(opts) - if err != nil { - ctx.ServerError("CountIssuesByRepo", err) - return - } - - opts.Page = page - opts.PageSize = setting.UI.IssuePagingNum - issues, err := models.Issues(opts) if err != nil { ctx.ServerError("Issues", err) @@ -280,6 +289,41 @@ func Issues(ctx *context.Context) { showReposMap[repoID] = repo } + if repoID > 0 { + if _, ok := showReposMap[repoID]; !ok { + repo, err := models.GetRepositoryByID(repoID) + if models.IsErrRepoNotExist(err) { + ctx.NotFound("GetRepositoryByID", err) + return + } else if err != nil { + ctx.ServerError("GetRepositoryByID", fmt.Errorf("[%d]%v", repoID, err)) + return + } + showReposMap[repoID] = repo + } + + repo := showReposMap[repoID] + + // Check if user has access to given repository. + perm, err := models.GetUserRepoPermission(repo, ctxUser) + if err != nil { + ctx.ServerError("GetUserRepoPermission", fmt.Errorf("[%d]%v", repoID, err)) + return + } + if !perm.CanRead(models.UnitTypeIssues) { + if log.IsTrace() { + log.Trace("Permission Denied: User %-v cannot read %-v of repo %-v\n"+ + "User in repo has Permissions: %-+v", + ctxUser, + models.UnitTypeIssues, + repo, + perm) + } + ctx.Status(404) + return + } + } + showRepos := models.RepositoryListOfMap(showReposMap) sort.Sort(showRepos) if err = showRepos.LoadAttributes(); err != nil { @@ -297,12 +341,12 @@ func Issues(ctx *context.Context) { } issueStats, err := models.GetUserIssueStats(models.UserIssueStatsOptions{ - UserID: ctxUser.ID, - RepoID: repoID, - RepoSubQuery: opts.RepoSubQuery, - FilterMode: filterMode, - IsPull: isPullList, - IsClosed: isShowClosed, + UserID: ctxUser.ID, + RepoID: repoID, + UserRepoIDs: userRepoIDs, + FilterMode: filterMode, + IsPull: isPullList, + IsClosed: isShowClosed, }) if err != nil { ctx.ServerError("GetUserIssueStats", err) From 736ad8f091696371ac15c9631e0f95b4073b23f5 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Tue, 8 Oct 2019 18:23:11 +0000 Subject: [PATCH 041/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_de-DE.ini | 1 + options/locale/locale_pt-BR.ini | 1 + 2 files changed, 2 insertions(+) diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index fcec489af8fdf..c038444f6278f 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -680,6 +680,7 @@ stored_lfs=Gespeichert mit Git LFS commit_graph=Commit graph blame=Blame normal_view=Normale Ansicht +line=zeile lines=Zeilen editor.new_file=Neue Datei diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 76890ddc794d2..f38380bb4828d 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -680,6 +680,7 @@ stored_lfs=Armazenado com Git LFS commit_graph=Gráfico de commits blame=Anotar normal_view=Visão normal +line=linha lines=linhas editor.new_file=Novo arquivo From 4843723d001a7442db46a205e8a41d38e7e0d7c9 Mon Sep 17 00:00:00 2001 From: guillep2k <18600385+guillep2k@users.noreply.github.com> Date: Tue, 8 Oct 2019 16:18:17 -0300 Subject: [PATCH 042/173] Allow users with explicit read access to give approvals (#8382) --- models/branches.go | 23 ++++++++++++++++++++++- models/repo.go | 13 +++++++++++++ routers/repo/setting_protected_branch.go | 4 ++-- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/models/branches.go b/models/branches.go index 9daaa487e79cd..fa8beb866c9b1 100644 --- a/models/branches.go +++ b/models/branches.go @@ -195,7 +195,7 @@ func UpdateProtectBranch(repo *Repository, protectBranch *ProtectedBranch, opts } protectBranch.MergeWhitelistUserIDs = whitelist - whitelist, err = updateUserWhitelist(repo, protectBranch.ApprovalsWhitelistUserIDs, opts.ApprovalsUserIDs) + whitelist, err = updateApprovalWhitelist(repo, protectBranch.ApprovalsWhitelistUserIDs, opts.ApprovalsUserIDs) if err != nil { return err } @@ -301,6 +301,27 @@ func (repo *Repository) IsProtectedBranchForMerging(pr *PullRequest, branchName return false, nil } +// updateApprovalWhitelist checks whether the user whitelist changed and returns a whitelist with +// the users from newWhitelist which have explicit read or write access to the repo. +func updateApprovalWhitelist(repo *Repository, currentWhitelist, newWhitelist []int64) (whitelist []int64, err error) { + hasUsersChanged := !util.IsSliceInt64Eq(currentWhitelist, newWhitelist) + if !hasUsersChanged { + return currentWhitelist, nil + } + + whitelist = make([]int64, 0, len(newWhitelist)) + for _, userID := range newWhitelist { + if reader, err := repo.IsReader(userID); err != nil { + return nil, err + } else if !reader { + continue + } + whitelist = append(whitelist, userID) + } + + return +} + // updateUserWhitelist checks whether the user whitelist changed and returns a whitelist with // the users from newWhitelist which have write access to the repo. func updateUserWhitelist(repo *Repository, currentWhitelist, newWhitelist []int64) (whitelist []int64, err error) { diff --git a/models/repo.go b/models/repo.go index 69f32ae4a521a..8b3784bae051b 100644 --- a/models/repo.go +++ b/models/repo.go @@ -735,11 +735,24 @@ func (repo *Repository) CanEnableEditor() bool { return !repo.IsMirror } +// GetReaders returns all users that have explicit read access or higher to the repository. +func (repo *Repository) GetReaders() (_ []*User, err error) { + return repo.getUsersWithAccessMode(x, AccessModeRead) +} + // GetWriters returns all users that have write access to the repository. func (repo *Repository) GetWriters() (_ []*User, err error) { return repo.getUsersWithAccessMode(x, AccessModeWrite) } +// IsReader returns true if user has explicit read access or higher to the repository. +func (repo *Repository) IsReader(userID int64) (bool, error) { + if repo.OwnerID == userID { + return true, nil + } + return x.Where("repo_id = ? AND user_id = ? AND mode >= ?", repo.ID, userID, AccessModeRead).Get(&Access{}) +} + // getUsersWithAccessMode returns users that have at least given access mode to the repository. func (repo *Repository) getUsersWithAccessMode(e Engine, mode AccessMode) (_ []*User, err error) { if err = repo.getOwner(e); err != nil { diff --git a/routers/repo/setting_protected_branch.go b/routers/repo/setting_protected_branch.go index 80f44ead99c8e..2a8502e6f4584 100644 --- a/routers/repo/setting_protected_branch.go +++ b/routers/repo/setting_protected_branch.go @@ -117,9 +117,9 @@ func SettingsProtectedBranch(c *context.Context) { } } - users, err := c.Repo.Repository.GetWriters() + users, err := c.Repo.Repository.GetReaders() if err != nil { - c.ServerError("Repo.Repository.GetWriters", err) + c.ServerError("Repo.Repository.GetReaders", err) return } c.Data["Users"] = users From 4fe04f1adcd7897d4db3beee69d62d3ccdbd18da Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Tue, 8 Oct 2019 19:20:34 +0000 Subject: [PATCH 043/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_tr-TR.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index 9fa1b7d42b130..9c06ba326f598 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -634,6 +634,8 @@ stored_lfs=Git LFS ile depolandı commit_graph=İşleme Grafiği blame=Bahset normal_view=Normal Görünüm +line=satır +lines=satır editor.new_file=Yeni dosya editor.upload_file=Dosya Yükle From f05a3353f4788ade6156bf132796690cf3154fd3 Mon Sep 17 00:00:00 2001 From: guillep2k <18600385+guillep2k@users.noreply.github.com> Date: Tue, 8 Oct 2019 16:48:57 -0300 Subject: [PATCH 044/173] Update strk.kbt.io/projects/go/libravatar to latest; closes #7860 (#8429) --- go.mod | 2 +- go.sum | 4 +- vendor/modules.txt | 2 +- .../projects/go/libravatar/Makefile | 12 ++++ .../projects/go/libravatar/README.md | 6 +- .../projects/go/libravatar/libravatar.go | 72 +++++++++++-------- 6 files changed, 61 insertions(+), 37 deletions(-) create mode 100644 vendor/strk.kbt.io/projects/go/libravatar/Makefile diff --git a/go.mod b/go.mod index e1a2b7b4044a9..d2520da73982e 100644 --- a/go.mod +++ b/go.mod @@ -121,7 +121,7 @@ require ( gopkg.in/stretchr/testify.v1 v1.2.2 // indirect gopkg.in/testfixtures.v2 v2.5.0 mvdan.cc/xurls/v2 v2.0.0 - strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a + strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 xorm.io/builder v0.3.6 xorm.io/core v0.7.2 ) diff --git a/go.sum b/go.sum index c068caa2f74f7..3adf91e926bf0 100644 --- a/go.sum +++ b/go.sum @@ -815,8 +815,8 @@ honnef.co/go/tools v0.0.1-2019.2.2/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt mvdan.cc/xurls/v2 v2.0.0 h1:r1zSOSNS/kqtpmATyMMMvaZ4/djsesbYz5kr0+qMRWc= mvdan.cc/xurls/v2 v2.0.0/go.mod h1:2/webFPYOXN9jp/lzuj0zuAVlF+9g4KPFJANH1oJhRU= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a h1:8q33ShxKXRwQ7JVd1ZnhIU3hZhwwn0Le+4fTeAackuM= -strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY= +strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 h1:mUcz5b3FJbP5Cvdq7Khzn6J9OCUQJaBwgBkCR+MOwSs= +strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY= xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8= xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU= xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb h1:msX3zG3BPl8Ti+LDzP33/9K7BzO/WqFXk610K1kYKfo= diff --git a/vendor/modules.txt b/vendor/modules.txt index 71ba2748675f3..8b2224f54abd3 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -612,7 +612,7 @@ gopkg.in/warnings.v0 gopkg.in/yaml.v2 # mvdan.cc/xurls/v2 v2.0.0 mvdan.cc/xurls/v2 -# strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a +# strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 strk.kbt.io/projects/go/libravatar # xorm.io/builder v0.3.6 xorm.io/builder diff --git a/vendor/strk.kbt.io/projects/go/libravatar/Makefile b/vendor/strk.kbt.io/projects/go/libravatar/Makefile new file mode 100644 index 0000000000000..2a70ddc72c83d --- /dev/null +++ b/vendor/strk.kbt.io/projects/go/libravatar/Makefile @@ -0,0 +1,12 @@ +PACKAGES ?= $(shell go list ./...) + +.PHONY: check +check: lint + go test + +.PHONY: lint +lint: + @which golint > /dev/null; if [ $$? -ne 0 ]; then \ + go get -u github.com/golang/lint/golint; \ + fi + @for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done; diff --git a/vendor/strk.kbt.io/projects/go/libravatar/README.md b/vendor/strk.kbt.io/projects/go/libravatar/README.md index 660cd906435d0..c0a9f942e2346 100644 --- a/vendor/strk.kbt.io/projects/go/libravatar/README.md +++ b/vendor/strk.kbt.io/projects/go/libravatar/README.md @@ -1,12 +1,14 @@ Simple [golang](https://www.golang.org) library for serving [federated avatars](https://www.libravatar.org) +[![trunk](https://goreportcard.com/badge/strk.kbt.io/projects/go/libravatar)] +(https://goreportcard.com/report/strk.kbt.io/projects/go/libravatar) + # Use ```sh go get strk.kbt.io/projects/go/libravatar -cd $GOPATH/src/strk.kbt.io/projects/go/libravatar -go doc +go doc strk.kbt.io/projects/go/libravatar ``` # Contribute diff --git a/vendor/strk.kbt.io/projects/go/libravatar/libravatar.go b/vendor/strk.kbt.io/projects/go/libravatar/libravatar.go index 4c748456f3604..fe544cd4b4de5 100644 --- a/vendor/strk.kbt.io/projects/go/libravatar/libravatar.go +++ b/vendor/strk.kbt.io/projects/go/libravatar/libravatar.go @@ -5,7 +5,7 @@ // Implements support for federated avatars lookup. // See https://wiki.libravatar.org/api/ -package libravatar +package libravatar // import "strk.kbt.io/projects/go/libravatar" import ( "crypto/md5" @@ -16,6 +16,7 @@ import ( "net/mail" "net/url" "strings" + "sync" "time" ) @@ -38,7 +39,8 @@ const ( ) var ( - // Default object, enabling object-less function calls + // DefaultLibravatar is a default Libravatar object, + // enabling object-less function calls DefaultLibravatar = New() ) @@ -53,14 +55,16 @@ type cacheValue struct { checkedAt time.Time } +// Libravatar is an opaque structure holding service configuration type Libravatar struct { - defUrl string // default url + defURL string // default url picSize int // picture size fallbackHost string // default fallback URL secureFallbackHost string // default fallback URL for secure connections useHTTPS bool nameCache map[cacheKey]cacheValue nameCacheDuration time.Duration + nameCacheMutex *sync.Mutex minSize uint // smallest image dimension allowed maxSize uint // largest image dimension allowed size uint // what dimension should be used @@ -68,7 +72,7 @@ type Libravatar struct { secureServiceBase string // SRV record to be queried for federation with secure servers } -// Instanciate a library handle +// New instanciates a new Libravatar object (handle) func New() *Libravatar { // According to https://wiki.libravatar.org/running_your_own/ // the time-to-live (cache expiry) should be set to at least 1 day. @@ -82,27 +86,28 @@ func New() *Libravatar { secureServiceBase: `avatars-sec`, nameCache: make(map[cacheKey]cacheValue), nameCacheDuration: 24 * time.Hour, + nameCacheMutex: &sync.Mutex{}, } } -// Set the hostname for fallbacks in case no avatar service is defined -// for a domain +// SetFallbackHost sets the hostname for fallbacks in case no avatar +// service is defined for a domain func (v *Libravatar) SetFallbackHost(host string) { v.fallbackHost = host } -// Set the hostname for fallbacks in case no avatar service is defined -// for a domain, when requiring secure domains +// SetSecureFallbackHost sets the hostname for fallbacks in case no +// avatar service is defined for a domain, when requiring secure domains func (v *Libravatar) SetSecureFallbackHost(host string) { v.secureFallbackHost = host } -// Set useHTTPS flag +// SetUseHTTPS sets flag requesting use of https for fetching avatars func (v *Libravatar) SetUseHTTPS(use bool) { v.useHTTPS = use } -// Set Avatars image dimension (0 for default) +// SetAvatarSize sets avatars image dimension (0 for default) func (v *Libravatar) SetAvatarSize(size uint) { v.size = size } @@ -150,8 +155,8 @@ func (v *Libravatar) process(email *mail.Address, openid *url.URL) (string, erro res := fmt.Sprintf("%s/avatar/%s", URL, v.genHash(email, openid)) values := make(url.Values) - if v.defUrl != "" { - values.Add("d", v.defUrl) + if v.defURL != "" { + values.Add("d", v.defURL) } if v.size > 0 { values.Add("s", fmt.Sprintf("%d", v.size)) @@ -181,7 +186,9 @@ func (v *Libravatar) baseURL(email *mail.Address, openid *url.URL) (string, erro host := v.getDomain(email, openid) key := cacheKey{service, host} now := time.Now() + v.nameCacheMutex.Lock() val, found := v.nameCache[key] + v.nameCacheMutex.Unlock() if found && now.Sub(val.checkedAt) <= v.nameCacheDuration { return protocol + val.target, nil } @@ -204,53 +211,55 @@ func (v *Libravatar) baseURL(email *mail.Address, openid *url.URL) (string, erro } var ( - total_weight uint16 - records []record - top_priority = addrs[0].Priority - top_record *net.SRV + totalWeight uint16 + records []record + topPriority = addrs[0].Priority + topRecord *net.SRV ) for _, rr := range addrs { - if rr.Priority > top_priority { + if rr.Priority > topPriority { continue - } else if rr.Priority < top_priority { + } else if rr.Priority < topPriority { // won't happen, because net sorts // by priority, but just in case - total_weight = 0 + totalWeight = 0 records = nil - top_priority = rr.Priority + topPriority = rr.Priority } - total_weight += rr.Weight + totalWeight += rr.Weight if rr.Weight > 0 { - records = append(records, record{rr, total_weight}) + records = append(records, record{rr, totalWeight}) } else if rr.Weight == 0 { - records = append([]record{record{srv: rr, weight: total_weight}}, records...) + records = append([]record{record{srv: rr, weight: totalWeight}}, records...) } } if len(records) == 1 { - top_record = records[0].srv + topRecord = records[0].srv } else { - randnum := uint16(rand.Intn(int(total_weight))) + randnum := uint16(rand.Intn(int(totalWeight))) for _, rr := range records { if rr.weight >= randnum { - top_record = rr.srv + topRecord = rr.srv break } } } - domain = fmt.Sprintf("%s:%d", top_record.Target, top_record.Port) + domain = fmt.Sprintf("%s:%d", topRecord.Target, topRecord.Port) } + v.nameCacheMutex.Lock() v.nameCache[key] = cacheValue{checkedAt: now, target: domain} + v.nameCacheMutex.Unlock() return protocol + domain, nil } -// Return url of the avatar for the given email +// FromEmail returns the url of the avatar for the given email func (v *Libravatar) FromEmail(email string) (string, error) { addr, err := mail.ParseAddress(email) if err != nil { @@ -265,12 +274,13 @@ func (v *Libravatar) FromEmail(email string) (string, error) { return link, nil } -// Object-less call to DefaultLibravatar for an email adders +// FromEmail is the object-less call to DefaultLibravatar for an email adders func FromEmail(email string) (string, error) { return DefaultLibravatar.FromEmail(email) } -// Return url of the avatar for the given url (typically for OpenID) +// FromURL returns the url of the avatar for the given url (typically +// for OpenID) func (v *Libravatar) FromURL(openid string) (string, error) { ourl, err := url.Parse(openid) if err != nil { @@ -291,7 +301,7 @@ func (v *Libravatar) FromURL(openid string) (string, error) { return link, nil } -// Object-less call to DefaultLibravatar for a URL +// FromURL is the object-less call to DefaultLibravatar for a URL func FromURL(openid string) (string, error) { return DefaultLibravatar.FromURL(openid) } From 7408942c802cd11c0fe4b9498a0de26964893cfd Mon Sep 17 00:00:00 2001 From: kolaente Date: Tue, 8 Oct 2019 22:42:30 +0200 Subject: [PATCH 045/173] Update golangci to v1.20 (#8432) * Update golangci to v1.20 Signed-off-by: kolaente * Use the timeout flag instead of deadline, move it to config Signed-off-by: kolaente --- .golangci.yml | 3 +++ Makefile | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 9c78a834513d4..fd7393372be41 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -19,6 +19,9 @@ linters: disable-all: true fast: false +run: + timeout: 3m + linters-settings: gocritic: disabled-checks: diff --git a/Makefile b/Makefile index e8220ef36c1a8..953abe83b0c8d 100644 --- a/Makefile +++ b/Makefile @@ -515,6 +515,6 @@ pr: golangci-lint: @hash golangci-lint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ export BINARY="golangci-lint"; \ - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin v1.19.1; \ + curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin v1.20.0; \ fi - golangci-lint run --deadline=3m + golangci-lint run From a3612f9d35811e41bd0e7387dce86a6ddb099f49 Mon Sep 17 00:00:00 2001 From: guillep2k <18600385+guillep2k@users.noreply.github.com> Date: Tue, 8 Oct 2019 22:27:45 -0300 Subject: [PATCH 046/173] Changelog for v1.9.4 (#8422) (#8433) * changelog * Update CHANGELOG.md We ned to revert this then ... Co-Authored-By: Lauris BH --- CHANGELOG.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 540b1a9790826..9c71af6b73ef1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,32 @@ This changelog goes through all the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.io). +## [1.9.4](https://github.com/go-gitea/gitea/releases/tag/v1.9.4) - 2019-10-08 +* BUGFIXES + * Highlight issue references (#8101) (#8404) + * Fix bug when migrating a private repository #7917 (#8403) + * Change general form binding to gogs form (#8334) (#8402) + * Fix editor commit to new branch if PR disabled (#8375) (#8401) + * Fix milestone num_issues (#8221) (#8400) + * Allow users with explicit read access to give approvals (#8398) + * Fix commit status in PR #8316 and PR #8321 (#8339) + * Fix API for edit and delete release attachment (#8290) + * Fix assets on release webhook (#8283) + * Fix release API URL generation (#8239) + * Allow registration when button is hidden (#8238) + * MS Teams webhook misses commit messages (backport v1.9) (#8225) + * Fix data race (#8206) + * Fix pull merge 500 error caused by git-fetch breaking behaviors (#8194) + * Fix the SSH config specification in the authorized_keys template (#8193) + * Fix reading git notes from nested trees (#8189) + * Fix team user api (#8172) (#8188) + * Add reviewers as participants (#8124) +* BUILD + * Use vendored go-swagger (#8087) (#8165) + * Fix version-validation for GO 1.13 (go-macaron/cors) (#8389) +* MISC + * Make show private icon when repo avatar set (#8144) (#8175) + ## [1.9.3](https://github.com/go-gitea/gitea/releases/tag/v1.9.3) - 2019-09-06 * BUGFIXES * Fix go get from a private repository with Go 1.13 (#8100) From 3810fa48ac46620432fbf91571a01eeea0b460b3 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Wed, 9 Oct 2019 01:29:16 +0000 Subject: [PATCH 047/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_ja-JP.ini | 3 +++ 1 file changed, 3 insertions(+) diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index ca38757e1c7fe..9fe31ec5ba4e6 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -680,6 +680,8 @@ stored_lfs=Git LFSで保管されています commit_graph=コミットグラフ blame=Blame normal_view=通常表示 +line=行 +lines=行 editor.new_file=新規ファイル editor.upload_file=ファイルをアップロード @@ -705,6 +707,7 @@ editor.delete='%s' を削除 editor.commit_message_desc=詳細な説明を追加… editor.commit_directly_to_this_branch=ブランチ%sへ直接コミットする。 editor.create_new_branch=新しいブランチにコミットしてプルリクエストを作成する。 +editor.create_new_branch_np=新しいブランチにコミットする。 editor.propose_file_change=ファイル修正を提案 editor.new_branch_name_desc=新しいブランチ名… editor.cancel=キャンセル From dd611c9a86f5a192a7a76146613a7e087b09f221 Mon Sep 17 00:00:00 2001 From: guillep2k <18600385+guillep2k@users.noreply.github.com> Date: Wed, 9 Oct 2019 06:36:53 -0300 Subject: [PATCH 048/173] Fix migration v96 to keep issue attachments (#8435) * Fix migration v96 to keep issue attachments * Fix == operator --- models/migrations/v96.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/migrations/v96.go b/models/migrations/v96.go index 5c2135ffc6ad4..34f67534c267c 100644 --- a/models/migrations/v96.go +++ b/models/migrations/v96.go @@ -27,7 +27,7 @@ func deleteOrphanedAttachments(x *xorm.Engine) error { defer sess.Close() err := sess.BufferSize(setting.Database.IterateBufferSize). - Where("`comment_id` = 0 and (`release_id` = 0 or `release_id` not in (select `id` from `release`))").Cols("uuid"). + Where("`issue_id` = 0 and (`release_id` = 0 or `release_id` not in (select `id` from `release`))").Cols("uuid"). Iterate(new(Attachment), func(idx int, bean interface{}) error { attachment := bean.(*Attachment) From 7ad46cc116e4749a0d45572f1a8c53d0c8729080 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 9 Oct 2019 21:09:02 +0800 Subject: [PATCH 049/173] fix template bug on mirror repository setting page (#8438) --- modules/templates/helper.go | 2 ++ templates/repo/settings/options.tmpl | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/templates/helper.go b/modules/templates/helper.go index b40f7117f5915..2c53e05fcad49 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -236,6 +236,8 @@ func NewFuncMap() []template.FuncMap { "CommentMustAsDiff": gitdiff.CommentMustAsDiff, "MirrorAddress": mirror_service.Address, "MirrorFullAddress": mirror_service.AddressNoCredentials, + "MirrorUserName": mirror_service.Username, + "MirrorPassword": mirror_service.Password, }} } diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index 4f7d32479eb64..a93efb8d2584d 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -88,15 +88,15 @@ -
+
- +
- +
From b6616591d190da56ba1ce06570f38a6cca3821d6 Mon Sep 17 00:00:00 2001 From: Tekaoh <45337851+Tekaoh@users.noreply.github.com> Date: Wed, 9 Oct 2019 13:49:37 -0500 Subject: [PATCH 050/173] Check for either escaped or unescaped wiki filenames (#8408) * Check for either escaped or unescaped wiki filenames + Gitea currently saves wiki pages with escaped filenames. + Wikis mirrored from other places like Github use unescaped filenames. + We need to be checking for filenames in either format to increase compatibility. * Better logic for escaped and unescaped wiki filenames Co-Authored-By: null --- routers/repo/wiki.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/routers/repo/wiki.go b/routers/repo/wiki.go index bf8ac658ae7c0..02fbe4a1ddad6 100644 --- a/routers/repo/wiki.go +++ b/routers/repo/wiki.go @@ -8,6 +8,7 @@ package repo import ( "fmt" "io/ioutil" + "net/url" "path/filepath" "strings" @@ -68,11 +69,22 @@ func findEntryForFile(commit *git.Commit, target string) (*git.TreeEntry, error) if err != nil { return nil, err } + // The longest name should be checked first for _, entry := range entries { if entry.IsRegular() && entry.Name() == target { return entry, nil } } + // Then the unescaped, shortest alternative + var unescapedTarget string + if unescapedTarget, err = url.QueryUnescape(target); err != nil { + return nil, err + } + for _, entry := range entries { + if entry.IsRegular() && entry.Name() == unescapedTarget { + return entry, nil + } + } return nil, nil } From 5109d18b298235c09e75eb0d3e900e777ac786b2 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Wed, 9 Oct 2019 19:02:21 +0000 Subject: [PATCH 051/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_es-ES.ini | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index 675de019b00b0..dbfa4622173b9 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -299,6 +299,7 @@ max_size_error=` debe contener como máximo %s caracteres.` email_error=` no es una dirección de correo válida.` url_error=` no es una URL válida.` include_error=` debe contener la subcadena '%s'.` +glob_pattern_error=` el patrón globo no es válido: %s.` unknown_error=Error desconocido: captcha_incorrect=El código CAPTCHA no es correcto. password_not_match=Las contraseñas no coinciden. @@ -317,6 +318,7 @@ enterred_invalid_repo_name=El nombre de repositorio que ha entrado es incorrecto enterred_invalid_owner_name=El nuevo nombre de usuario no es válido. enterred_invalid_password=La contraseña que ha introducido es incorrecta. user_not_exist=Este usuario no existe. +team_not_exist=Este equipo no existe. last_org_owner=No puedes eliminar al último usuario del equipo de 'propietarios'. Debe haber al menos un propietario en ningún equipo dado. cannot_add_org_to_team=Una organización no puede ser añadida como miembro de un equipo. @@ -556,6 +558,10 @@ confirm_delete_account=Confirmar Eliminación delete_account_title=Eliminar cuenta de usuario delete_account_desc=¿Está seguro que desea eliminar permanentemente esta cuenta de usuario? +email_notifications.enable=Habilitar notificaciones por correo electrónico +email_notifications.onmention=Enviar correo sólo al ser mencionado +email_notifications.disable=Deshabilitar las notificaciones por correo electrónico +email_notifications.submit=Establecer preferencias de correo electrónico [repo] owner=Propietario @@ -572,6 +578,8 @@ fork_visibility_helper=La visibilidad de un repositorio del cual se ha hecho for repo_desc=Descripción repo_lang=Idioma repo_gitignore_helper=Seleccionar plantillas de .gitignore. +issue_labels=Etiquetas de incidencia +issue_labels_helper=Seleccione un conjunto de etiquetas de incidencia. license=Licencia license_helper=Seleccione un archivo de licencia. readme=LÉAME @@ -584,6 +592,7 @@ mirror_prune_desc=Eliminar referencias de seguimiento de remotes obsoletas mirror_interval=Intervalo de réplica (Las unidades de tiempo válidas son 'h', 'm', 's'). Pone 0 para deshabilitar la sincronización automática. mirror_interval_invalid=El intervalo de réplica no es válido. mirror_address=Clonar desde URL +mirror_address_desc=Agregue las credenciales que sean necesarias en la sección de Autorización de Clonado. mirror_address_url_invalid=La url proporcionada no es válida. Debe escapar correctamente de todos los componentes de la url. mirror_address_protocol_invalid=La url proporcionada no es válida. Sólo las ubicaciones http(s):// o git:// pueden ser replicadas desde. mirror_last_synced=Sincronizado por última vez @@ -670,6 +679,7 @@ stored_lfs=Almacenados con Git LFS commit_graph=Gráfico de commits blame=Blame normal_view=Vista normal +lines=líneas editor.new_file=Nuevo Archivo editor.upload_file=Subir archivo @@ -695,6 +705,7 @@ editor.delete=Eliminar '%s' editor.commit_message_desc=Añadir una descripción extendida opcional… editor.commit_directly_to_this_branch=Hacer commit directamente en la rama %s. editor.create_new_branch=Crear una nueva rama para este commit y hacer un pull request. +editor.create_new_branch_np=Crear una nueva rama para este commit. editor.propose_file_change=Proponer cambio de archivo editor.new_branch_name_desc=Nombre de la rama nueva… editor.cancel=Cancelar @@ -769,6 +780,7 @@ issues.self_assign_at=`auto asignado este %s` issues.add_assignee_at='fue asignado por %s %s' issues.remove_assignee_at=`fue desasignado por %s %s` issues.remove_self_assignment=`eliminado su asignación %s` +issues.change_title_at=`cambió el título de %s a %s %s` issues.delete_branch_at=`rama eliminada %s %s` issues.open_tab=%d abiertas issues.close_tab=%d cerradas @@ -825,6 +837,7 @@ issues.create_comment=Comentar issues.closed_at=`cerró %[2]s` issues.reopened_at=`reabrió %[2]s` issues.commit_ref_at=`mencionada esta incidencia en un commit %[2]s` +issues.ref_issue_at=`referenciada esta incidencia %[1]s` issues.poster=Autor issues.collaborator=Colaborador issues.owner=Propietario @@ -1116,6 +1129,7 @@ settings.collaboration=Colaboradores settings.collaboration.admin=Administrador settings.collaboration.write=Escritura settings.collaboration.read=Lectura +settings.collaboration.owner=Propietario settings.collaboration.undefined=Indefinido settings.hooks=Webhooks settings.githooks=Git Hooks @@ -1123,6 +1137,7 @@ settings.basic_settings=Configuración Básica settings.mirror_settings=Configuración de réplica settings.sync_mirror=Sincronizar ahora settings.mirror_sync_in_progress=La sincronización del repositorio replicado está en curso. Vuelva a intentarlo más tarde. +settings.email_notifications.enable=Habilitar las notificaciones por correo electrónico settings.site=Sitio web settings.update_settings=Actualizar configuración settings.advanced_settings=Ajustes avanzados From e270896a834f9f73c25b3e27fe596d2ced55b414 Mon Sep 17 00:00:00 2001 From: 8ctopus <13252042+8ctopus@users.noreply.github.com> Date: Thu, 10 Oct 2019 03:33:03 +0500 Subject: [PATCH 052/173] Doc updated list of supported webhooks and added example (#8388) * Doc updated list of supported webhooks and added example * Replaced webhook password verification by signature verification --- docs/content/doc/features/webhooks.en-us.md | 82 ++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/docs/content/doc/features/webhooks.en-us.md b/docs/content/doc/features/webhooks.en-us.md index 628afb73569eb..1a0a180e7a427 100644 --- a/docs/content/doc/features/webhooks.en-us.md +++ b/docs/content/doc/features/webhooks.en-us.md @@ -17,7 +17,15 @@ menu: Gitea supports web hooks for repository events. This can be found in the settings page `/:username/:reponame/settings/hooks`. All event pushes are POST requests. -The two methods currently supported are Gitea and Slack. +The methods currently supported are: + +- Gitea +- Gogs +- Slack +- Discord +- Dingtalk +- Telegram +- Microsoft Teams ### Event information @@ -104,3 +112,75 @@ X-Gitea-Event: push } } ``` + +### Example + +This is an example of how to use webhooks to run a php script upon push requests to the repository. +In your repository Settings, under Webhooks, Setup a Gitea webhook as follows: + +- Target URL: http://mydomain.com/webhook.php +- HTTP Method: POST +- POST Content Type: application/json +- Secret: 123 +- Trigger On: Push Events +- Active: Checked + +Now on your server create the php file webhook.php + +``` + Date: Thu, 10 Oct 2019 04:11:25 +0500 Subject: [PATCH 053/173] =?UTF-8?q?Doc=20recommend=20to=20use=20reverse=20?= =?UTF-8?q?proxy=20if=20Apache/nginx=20is=20also=20running=20on=E2=80=A6?= =?UTF-8?q?=20(#8384)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Doc recommend to use reverse proxy if Apache/nginx is also running on server * Update docs/content/doc/usage/https-support.md Co-Authored-By: John Olheiser <42128690+jolheiser@users.noreply.github.com> --- docs/content/doc/usage/https-support.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/content/doc/usage/https-support.md b/docs/content/doc/usage/https-support.md index 22cbc684aa4c6..e2b5332c05d55 100644 --- a/docs/content/doc/usage/https-support.md +++ b/docs/content/doc/usage/https-support.md @@ -20,6 +20,8 @@ menu: Before you enable HTTPS, make sure that you have valid SSL/TLS certificates. You could use self-generated certificates for evaluation and testing. Please run `gitea cert --host [HOST]` to generate a self signed certificate. +If you are using Apache or nginx on the server, it's recommended to check the [reverse proxy guide]({{< relref "doc/usage/reverse-proxies.en-us.md" >}}). + To use Gitea's built-in HTTPS support, you must change your `app.ini` file: ```ini From 1fe81bc22edbb5c82dd2b1518fb9337c1bd503bb Mon Sep 17 00:00:00 2001 From: 6543 <24977596+6543@users.noreply.github.com> Date: Thu, 10 Oct 2019 04:16:58 +0200 Subject: [PATCH 054/173] add crowdin badge (#8447) --- README.md | 1 + README_ZH.md | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index 5d565e4a3ad1d..76feebdbe72a5 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ [![Help Contribute to Open Source](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea) [![Become a backer/sponsor of gitea](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) +[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://crowdin.com/project/gitea) ## Purpose diff --git a/README_ZH.md b/README_ZH.md index b546a15a3eb2a..0d9d6d27daa65 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -11,6 +11,7 @@ [![GitHub release](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest) [![Become a backer/sponsor of gitea](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) +[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://crowdin.com/project/gitea) ## 目标 From eac5a8be751341b388cf16c5a43aeb2f83c8ed2c Mon Sep 17 00:00:00 2001 From: pseudocoder Date: Thu, 10 Oct 2019 15:42:01 +0300 Subject: [PATCH 055/173] DOCS: add mention of swagger api reference (#8452) It's(swagger api link) mentioned vaguely in the FAQ but IMHO missing from API usage page. --- docs/content/doc/advanced/api-usage.en-us.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/content/doc/advanced/api-usage.en-us.md b/docs/content/doc/advanced/api-usage.en-us.md index 8e0b43ec241c2..624d639545c96 100644 --- a/docs/content/doc/advanced/api-usage.en-us.md +++ b/docs/content/doc/advanced/api-usage.en-us.md @@ -68,6 +68,14 @@ curl -X POST "http://localhost:4000/api/v1/repos/test1/test1/issues" \ As mentioned above, the token used is the same one you would use in the `token=` string in a GET request. +## API Guide: + +API Reference guide is auto-generated by swagger and available on: + `https://gitea.your.host/api/swagger` + or on + [gitea demo instance](https://try.gitea.io/api/swagger) + + ## Listing your issued tokens via the API As mentioned in From 7c1ddd5692cd62a208886276196f02422dbead95 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Thu, 10 Oct 2019 12:44:06 +0000 Subject: [PATCH 056/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_tr-TR.ini | 8 ++++++++ options/locale/locale_zh-CN.ini | 3 +++ 2 files changed, 11 insertions(+) diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index 9c06ba326f598..b387bf2e80778 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -768,6 +768,8 @@ issues.action_milestone_no_select=Kilometre Taşı Yok issues.action_assignee=Vekil issues.action_assignee_no_select=Vekil yok issues.opened_by=%[3]s tarafından %[1]s açıldı +pulls.merged_by=%[3]s tarafından %[1]s birleştirildi +pulls.merged_by_fake=%[2]s tarafından %[1]s birleştirildi issues.closed_by=%[3]s tarafından %[1]s kapatıldı issues.opened_by_fake=%[2]s tarafından %[1]s açıldı issues.closed_by_fake=%[2]s tarafından %[1]s kapatıldı @@ -837,11 +839,15 @@ issues.lock.reason=Kilitleme nedeni issues.lock.title=Konuşmayı kilitle. issues.unlock.title=Konuşmanın kilidini aç. issues.comment_on_locked=Kilitli bir konuya yorum yapamazsınız. +issues.tracker=Zaman İzleyici issues.start_tracking_short=Başlat +issues.start_tracking=Zaman İzlemeyi Başlat issues.start_tracking_history=`%s çalışması başlatıldı` +issues.tracker_auto_close=Bu konu kapatıldığında zamanlayıcı otomatik olarak durur issues.tracking_already_started=`Bu konuda zaten zaman izleyicisini başlattınız!` issues.stop_tracking=Durdur issues.stop_tracking_history=`%s çalışması durduruldu` +issues.add_time=El ile Zaman Ekle issues.add_time_short=Zaman Ekle issues.add_time_cancel=İptal issues.add_time_history=`%s harcanan zaman eklendi` @@ -862,6 +868,8 @@ issues.due_date_form_edit=Düzenle issues.due_date_form_remove=Kaldır issues.due_date_not_writer=Bir konunun bitiş tarihini değiştirmek için depoda yazma hakkınız olmalıdır. issues.due_date_not_set=Bitiş tarihi atanmadı. +issues.due_date_added=eklenen bitiş tarihi %s %s +issues.due_date_remove=kaldırılan bitiş tarihi %s %s issues.dependency.title=Bağımlılıklar issues.dependency.issue_no_dependencies=Bu konu henüz bir bağımlılık içermiyor. issues.dependency.pr_no_dependencies=Bu çekme isteği henüz bir bağımlılık içermiyor. diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 76676097936a7..7b62bf9c12806 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -680,6 +680,8 @@ stored_lfs=存储到Git LFS commit_graph=提交图 blame=Blame normal_view=普通视图 +line=行 +lines=行 editor.new_file=新建文件 editor.upload_file=上传文件 @@ -705,6 +707,7 @@ editor.delete=删除 '%s' editor.commit_message_desc=添加一个可选的扩展描述... editor.commit_directly_to_this_branch=直接提交至 %s 分支。 editor.create_new_branch=为此提交创建一个 新的分支 并发起合并请求。 +editor.create_new_branch_np=为此提交创建 新分支。 editor.propose_file_change=提议文件更改 editor.new_branch_name_desc=新的分支名称... editor.cancel=取消 From 57b0d9a38ba7d8dcc05a74fe39ab9f9e765ed8b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C5=9Far=20=C3=87iv?= <42207558+yasarciv67@users.noreply.github.com> Date: Thu, 10 Oct 2019 16:47:38 +0300 Subject: [PATCH 057/173] Add @yasarciv67 to TRANSLATORS file (#8451) --- options/locale/TRANSLATORS | 1 + 1 file changed, 1 insertion(+) diff --git a/options/locale/TRANSLATORS b/options/locale/TRANSLATORS index c413626ec140b..98a47a6c536d0 100644 --- a/options/locale/TRANSLATORS +++ b/options/locale/TRANSLATORS @@ -73,5 +73,6 @@ Toni Villena Jiménez Viktor Sperl Vladimir Jigulin mogaika AT yandex DOT ru Vladimir Vissoultchev +Yaşar Çiv YJSoft Łukasz Jan Niemier From df2c11a878719719b8600745888c570af93827be Mon Sep 17 00:00:00 2001 From: guillep2k <18600385+guillep2k@users.noreply.github.com> Date: Thu, 10 Oct 2019 13:45:11 -0300 Subject: [PATCH 058/173] Ignore mentions for users with no access (#8395) * Draft for ResolveMentionsByVisibility() * Correct typo * Resolve teams instead of orgs for mentions * Create test for ResolveMentionsByVisibility * Fix check for individual users and doer * Test and fix team mentions * Run all mentions through visibility filter * Fix error check * Simplify code, fix doer included in teams * Simplify team id list build --- models/issue.go | 155 +++++++++++++++++++++++++------- models/issue_test.go | 32 +++++++ models/org_team.go | 2 +- services/mailer/mail_comment.go | 13 ++- services/mailer/mail_issue.go | 13 ++- 5 files changed, 175 insertions(+), 40 deletions(-) diff --git a/models/issue.go b/models/issue.go index e4cc1291c2a7d..f8fa1377a8fb2 100644 --- a/models/issue.go +++ b/models/issue.go @@ -1477,46 +1477,18 @@ func getParticipantsByIssueID(e Engine, issueID int64) ([]*User, error) { return users, e.In("id", userIDs).Find(&users) } -// UpdateIssueMentions extracts mentioned people from content and -// updates issue-user relations for them. -func UpdateIssueMentions(ctx DBContext, issueID int64, mentions []string) error { +// UpdateIssueMentions updates issue-user relations for mentioned users. +func UpdateIssueMentions(ctx DBContext, issueID int64, mentions []*User) error { if len(mentions) == 0 { return nil } - - for i := range mentions { - mentions[i] = strings.ToLower(mentions[i]) - } - users := make([]*User, 0, len(mentions)) - - if err := ctx.e.In("lower_name", mentions).Asc("lower_name").Find(&users); err != nil { - return fmt.Errorf("find mentioned users: %v", err) - } - - ids := make([]int64, 0, len(mentions)) - for _, user := range users { - ids = append(ids, user.ID) - if !user.IsOrganization() || user.NumMembers == 0 { - continue - } - - memberIDs := make([]int64, 0, user.NumMembers) - orgUsers, err := getOrgUsersByOrgID(ctx.e, user.ID) - if err != nil { - return fmt.Errorf("GetOrgUsersByOrgID [%d]: %v", user.ID, err) - } - - for _, orgUser := range orgUsers { - memberIDs = append(memberIDs, orgUser.ID) - } - - ids = append(ids, memberIDs...) + ids := make([]int64, len(mentions)) + for i, u := range mentions { + ids[i] = u.ID } - if err := UpdateIssueUsersByMentions(ctx, issueID, ids); err != nil { return fmt.Errorf("UpdateIssueUsersByMentions: %v", err) } - return nil } @@ -1909,3 +1881,120 @@ func (issue *Issue) updateClosedNum(e Engine) (err error) { } return } + +// ResolveMentionsByVisibility returns the users mentioned in an issue, removing those that +// don't have access to reading it. Teams are expanded into their users, but organizations are ignored. +func (issue *Issue) ResolveMentionsByVisibility(ctx DBContext, doer *User, mentions []string) (users []*User, err error) { + if len(mentions) == 0 { + return + } + if err = issue.loadRepo(ctx.e); err != nil { + return + } + resolved := make(map[string]bool, 20) + names := make([]string, 0, 20) + resolved[doer.LowerName] = true + for _, name := range mentions { + name := strings.ToLower(name) + if _, ok := resolved[name]; ok { + continue + } + resolved[name] = false + names = append(names, name) + } + + if err := issue.Repo.getOwner(ctx.e); err != nil { + return nil, err + } + + if issue.Repo.Owner.IsOrganization() { + // Since there can be users with names that match the name of a team, + // if the team exists and can read the issue, the team takes precedence. + teams := make([]*Team, 0, len(names)) + if err := ctx.e. + Join("INNER", "team_repo", "team_repo.team_id = team.id"). + Where("team_repo.repo_id=?", issue.Repo.ID). + In("team.lower_name", names). + Find(&teams); err != nil { + return nil, fmt.Errorf("find mentioned teams: %v", err) + } + if len(teams) != 0 { + checked := make([]int64, 0, len(teams)) + unittype := UnitTypeIssues + if issue.IsPull { + unittype = UnitTypePullRequests + } + for _, team := range teams { + if team.Authorize >= AccessModeOwner { + checked = append(checked, team.ID) + resolved[team.LowerName] = true + continue + } + has, err := ctx.e.Get(&TeamUnit{OrgID: issue.Repo.Owner.ID, TeamID: team.ID, Type: unittype}) + if err != nil { + return nil, fmt.Errorf("get team units (%d): %v", team.ID, err) + } + if has { + checked = append(checked, team.ID) + resolved[team.LowerName] = true + } + } + if len(checked) != 0 { + teamusers := make([]*User, 0, 20) + if err := ctx.e. + Join("INNER", "team_user", "team_user.uid = `user`.id"). + In("`team_user`.team_id", checked). + And("`user`.is_active = ?", true). + And("`user`.prohibit_login = ?", false). + Find(&teamusers); err != nil { + return nil, fmt.Errorf("get teams users: %v", err) + } + if len(teamusers) > 0 { + users = make([]*User, 0, len(teamusers)) + for _, user := range teamusers { + if already, ok := resolved[user.LowerName]; !ok || !already { + users = append(users, user) + resolved[user.LowerName] = true + } + } + } + } + } + + // Remove names already in the list to avoid querying the database if pending names remain + names = make([]string, 0, len(resolved)) + for name, already := range resolved { + if !already { + names = append(names, name) + } + } + if len(names) == 0 { + return + } + } + + unchecked := make([]*User, 0, len(names)) + if err := ctx.e. + Where("`user`.is_active = ?", true). + And("`user`.prohibit_login = ?", false). + In("`user`.lower_name", names). + Find(&unchecked); err != nil { + return nil, fmt.Errorf("find mentioned users: %v", err) + } + for _, user := range unchecked { + if already := resolved[user.LowerName]; already || user.IsOrganization() { + continue + } + // Normal users must have read access to the referencing issue + perm, err := getUserRepoPermission(ctx.e, issue.Repo, user) + if err != nil { + return nil, fmt.Errorf("getUserRepoPermission [%d]: %v", user.ID, err) + } + if !perm.CanReadIssuesOrPulls(issue.IsPull) { + continue + } + users = append(users, user) + } + + return +} diff --git a/models/issue_test.go b/models/issue_test.go index 9cd9ff0ad98a8..5b039bc1d5fff 100644 --- a/models/issue_test.go +++ b/models/issue_test.go @@ -366,3 +366,35 @@ func TestIssue_InsertIssue(t *testing.T) { testInsertIssue(t, "my issue1", "special issue's comments?") testInsertIssue(t, `my issue2, this is my son's love \n \r \ `, "special issue's '' comments?") } + +func TestIssue_ResolveMentions(t *testing.T) { + assert.NoError(t, PrepareTestDatabase()) + + testSuccess := func(owner, repo, doer string, mentions []string, expected []int64) { + o := AssertExistsAndLoadBean(t, &User{LowerName: owner}).(*User) + r := AssertExistsAndLoadBean(t, &Repository{OwnerID: o.ID, LowerName: repo}).(*Repository) + issue := &Issue{RepoID: r.ID} + d := AssertExistsAndLoadBean(t, &User{LowerName: doer}).(*User) + resolved, err := issue.ResolveMentionsByVisibility(DefaultDBContext(), d, mentions) + assert.NoError(t, err) + ids := make([]int64, len(resolved)) + for i, user := range resolved { + ids[i] = user.ID + } + sort.Slice(ids, func(i, j int) bool { return ids[i] < ids[j] }) + assert.EqualValues(t, expected, ids) + } + + // Public repo, existing user + testSuccess("user2", "repo1", "user1", []string{"user5"}, []int64{5}) + // Public repo, non-existing user + testSuccess("user2", "repo1", "user1", []string{"nonexisting"}, []int64{}) + // Public repo, doer + testSuccess("user2", "repo1", "user1", []string{"user1"}, []int64{}) + // Private repo, team member + testSuccess("user17", "big_test_private_4", "user20", []string{"user2"}, []int64{2}) + // Private repo, not a team member + testSuccess("user17", "big_test_private_4", "user20", []string{"user5"}, []int64{}) + // Private repo, whole team + testSuccess("user17", "big_test_private_4", "user15", []string{"owners"}, []int64{18}) +} diff --git a/models/org_team.go b/models/org_team.go index fc5d5834ef603..9170ea2c2af88 100644 --- a/models/org_team.go +++ b/models/org_team.go @@ -314,7 +314,7 @@ func (t *Team) UnitEnabled(tp UnitType) bool { func (t *Team) unitEnabled(e Engine, tp UnitType) bool { if err := t.getUnits(e); err != nil { - log.Warn("Error loading repository (ID: %d) units: %s", t.ID, err.Error()) + log.Warn("Error loading team (ID: %d) units: %s", t.ID, err.Error()) } for _, unit := range t.Units { diff --git a/services/mailer/mail_comment.go b/services/mailer/mail_comment.go index cb477f887b5cc..f64db04fffa9d 100644 --- a/services/mailer/mail_comment.go +++ b/services/mailer/mail_comment.go @@ -19,11 +19,18 @@ func MailParticipantsComment(c *models.Comment, opType models.ActionType, issue } func mailParticipantsComment(ctx models.DBContext, c *models.Comment, opType models.ActionType, issue *models.Issue) (err error) { - mentions := markup.FindAllMentions(c.Content) - if err = models.UpdateIssueMentions(ctx, c.IssueID, mentions); err != nil { + rawMentions := markup.FindAllMentions(c.Content) + userMentions, err := issue.ResolveMentionsByVisibility(ctx, c.Poster, rawMentions) + if err != nil { + return fmt.Errorf("ResolveMentionsByVisibility [%d]: %v", c.IssueID, err) + } + if err = models.UpdateIssueMentions(ctx, c.IssueID, userMentions); err != nil { return fmt.Errorf("UpdateIssueMentions [%d]: %v", c.IssueID, err) } - + mentions := make([]string, len(userMentions)) + for i, u := range userMentions { + mentions[i] = u.LowerName + } if len(c.Content) > 0 { if err = mailIssueCommentToParticipants(issue, c.Poster, c.Content, c, mentions); err != nil { log.Error("mailIssueCommentToParticipants: %v", err) diff --git a/services/mailer/mail_issue.go b/services/mailer/mail_issue.go index 92d2c5a8795f8..da0249d595dab 100644 --- a/services/mailer/mail_issue.go +++ b/services/mailer/mail_issue.go @@ -123,11 +123,18 @@ func MailParticipants(issue *models.Issue, doer *models.User, opType models.Acti } func mailParticipants(ctx models.DBContext, issue *models.Issue, doer *models.User, opType models.ActionType) (err error) { - mentions := markup.FindAllMentions(issue.Content) - - if err = models.UpdateIssueMentions(ctx, issue.ID, mentions); err != nil { + rawMentions := markup.FindAllMentions(issue.Content) + userMentions, err := issue.ResolveMentionsByVisibility(ctx, doer, rawMentions) + if err != nil { + return fmt.Errorf("ResolveMentionsByVisibility [%d]: %v", issue.ID, err) + } + if err = models.UpdateIssueMentions(ctx, issue.ID, userMentions); err != nil { return fmt.Errorf("UpdateIssueMentions [%d]: %v", issue.ID, err) } + mentions := make([]string, len(userMentions)) + for i, u := range userMentions { + mentions[i] = u.LowerName + } if len(issue.Content) > 0 { if err = mailIssueCommentToParticipants(issue, doer, issue.Content, nil, mentions); err != nil { From 6551a9d6ca8ab79fe1460eb9d60a5a0e76110eb3 Mon Sep 17 00:00:00 2001 From: zeripath Date: Thu, 10 Oct 2019 18:42:28 +0100 Subject: [PATCH 059/173] Ensure Request Body Readers are closed in LFS server (#8454) --- modules/lfs/locks.go | 8 ++++++-- modules/lfs/server.go | 12 +++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/modules/lfs/locks.go b/modules/lfs/locks.go index d7b2429698990..9ffe6b9d59482 100644 --- a/modules/lfs/locks.go +++ b/modules/lfs/locks.go @@ -155,7 +155,9 @@ func PostLockHandler(ctx *context.Context) { } var req api.LFSLockRequest - dec := json.NewDecoder(ctx.Req.Body().ReadCloser()) + bodyReader := ctx.Req.Body().ReadCloser() + defer bodyReader.Close() + dec := json.NewDecoder(bodyReader) if err := dec.Decode(&req); err != nil { writeStatus(ctx, 400) return @@ -269,7 +271,9 @@ func UnLockHandler(ctx *context.Context) { } var req api.LFSLockDeleteRequest - dec := json.NewDecoder(ctx.Req.Body().ReadCloser()) + bodyReader := ctx.Req.Body().ReadCloser() + defer bodyReader.Close() + dec := json.NewDecoder(bodyReader) if err := dec.Decode(&req); err != nil { writeStatus(ctx, 400) return diff --git a/modules/lfs/server.go b/modules/lfs/server.go index 652610acf4b6c..6fa97a2894080 100644 --- a/modules/lfs/server.go +++ b/modules/lfs/server.go @@ -327,7 +327,9 @@ func PutHandler(ctx *context.Context) { } contentStore := &ContentStore{BasePath: setting.LFS.ContentPath} - if err := contentStore.Put(meta, ctx.Req.Body().ReadCloser()); err != nil { + bodyReader := ctx.Req.Body().ReadCloser() + defer bodyReader.Close() + if err := contentStore.Put(meta, bodyReader); err != nil { ctx.Resp.WriteHeader(500) fmt.Fprintf(ctx.Resp, `{"message":"%s"}`, err) if err = repository.RemoveLFSMetaObjectByOid(rv.Oid); err != nil { @@ -434,7 +436,9 @@ func unpack(ctx *context.Context) *RequestVars { if r.Method == "POST" { // Maybe also check if +json var p RequestVars - dec := json.NewDecoder(r.Body().ReadCloser()) + bodyReader := r.Body().ReadCloser() + defer bodyReader.Close() + dec := json.NewDecoder(bodyReader) err := dec.Decode(&p) if err != nil { return rv @@ -453,7 +457,9 @@ func unpackbatch(ctx *context.Context) *BatchVars { r := ctx.Req var bv BatchVars - dec := json.NewDecoder(r.Body().ReadCloser()) + bodyReader := r.Body().ReadCloser() + defer bodyReader.Close() + dec := json.NewDecoder(bodyReader) err := dec.Decode(&bv) if err != nil { return &bv From 9ff9f5ad1d8d2680c9c146831458afdbd4e641df Mon Sep 17 00:00:00 2001 From: zeripath Date: Thu, 10 Oct 2019 22:08:33 +0100 Subject: [PATCH 060/173] Ensure that LFS files are relative to the LFS content path (#8455) --- models/repo.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/models/repo.go b/models/repo.go index 8b3784bae051b..50402c8e1aeda 100644 --- a/models/repo.go +++ b/models/repo.go @@ -1946,12 +1946,11 @@ func DeleteRepository(doer *User, uid, repoID int64) error { if err != nil { return err } - if count > 1 { continue } - oidPath := filepath.Join(v.Oid[0:2], v.Oid[2:4], v.Oid[4:len(v.Oid)]) + oidPath := filepath.Join(setting.LFS.ContentPath, v.Oid[0:2], v.Oid[2:4], v.Oid[4:len(v.Oid)]) removeAllWithNotice(sess, "Delete orphaned LFS file", oidPath) } From 46a12f196b1742a2462259ed3dd9c33c4c2f150b Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 11 Oct 2019 14:44:43 +0800 Subject: [PATCH 061/173] Move change issue title from models to issue service package (#8456) * move change issue title from models to issue service package * make the change less * fix typo --- integrations/api_pull_test.go | 3 +- models/issue.go | 57 ++--------------------------------- models/issue_lock.go | 17 ++++++++--- models/issue_test.go | 2 +- routers/repo/issue.go | 2 +- services/issue/issue.go | 51 +++++++++++++++++++++++++++++++ 6 files changed, 71 insertions(+), 61 deletions(-) diff --git a/integrations/api_pull_test.go b/integrations/api_pull_test.go index 8d24cdc188766..ed5a55a9db043 100644 --- a/integrations/api_pull_test.go +++ b/integrations/api_pull_test.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + issue_service "code.gitea.io/gitea/services/issue" "github.com/stretchr/testify/assert" ) @@ -40,7 +41,7 @@ func TestAPIMergePullWIP(t *testing.T) { owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User) pr := models.AssertExistsAndLoadBean(t, &models.PullRequest{Status: models.PullRequestStatusMergeable}, models.Cond("has_merged = ?", false)).(*models.PullRequest) pr.LoadIssue() - pr.Issue.ChangeTitle(owner, setting.Repository.PullRequest.WorkInProgressPrefixes[0]+" "+pr.Issue.Title) + issue_service.ChangeTitle(pr.Issue, owner, setting.Repository.PullRequest.WorkInProgressPrefixes[0]+" "+pr.Issue.Title) // force reload pr.LoadAttributes() diff --git a/models/issue.go b/models/issue.go index f8fa1377a8fb2..8ce7d496ab465 100644 --- a/models/issue.go +++ b/models/issue.go @@ -714,11 +714,6 @@ func updateIssueCols(e Engine, issue *Issue, cols ...string) error { return nil } -// UpdateIssueCols only updates values of specific columns for given issue. -func UpdateIssueCols(issue *Issue, cols ...string) error { - return updateIssueCols(x, issue, cols...) -} - func (issue *Issue) changeStatus(e *xorm.Session, doer *User, isClosed bool) (err error) { // Reload the issue currentIssue, err := getIssueByID(e, issue.ID) @@ -844,9 +839,7 @@ func (issue *Issue) ChangeStatus(doer *User, isClosed bool) (err error) { } // ChangeTitle changes the title of this issue, as the given user. -func (issue *Issue) ChangeTitle(doer *User, title string) (err error) { - oldTitle := issue.Title - issue.Title = title +func (issue *Issue) ChangeTitle(doer *User, oldTitle string) (err error) { sess := x.NewSession() defer sess.Close() @@ -862,7 +855,7 @@ func (issue *Issue) ChangeTitle(doer *User, title string) (err error) { return fmt.Errorf("loadRepo: %v", err) } - if _, err = createChangeTitleComment(sess, doer, issue.Repo, issue, oldTitle, title); err != nil { + if _, err = createChangeTitleComment(sess, doer, issue.Repo, issue, oldTitle, issue.Title); err != nil { return fmt.Errorf("createChangeTitleComment: %v", err) } @@ -874,51 +867,7 @@ func (issue *Issue) ChangeTitle(doer *User, title string) (err error) { return err } - if err = sess.Commit(); err != nil { - return err - } - sess.Close() - - mode, _ := AccessLevel(issue.Poster, issue.Repo) - if issue.IsPull { - if err = issue.loadPullRequest(sess); err != nil { - return fmt.Errorf("loadPullRequest: %v", err) - } - issue.PullRequest.Issue = issue - err = PrepareWebhooks(issue.Repo, HookEventPullRequest, &api.PullRequestPayload{ - Action: api.HookIssueEdited, - Index: issue.Index, - Changes: &api.ChangesPayload{ - Title: &api.ChangesFromPayload{ - From: oldTitle, - }, - }, - PullRequest: issue.PullRequest.APIFormat(), - Repository: issue.Repo.APIFormat(mode), - Sender: doer.APIFormat(), - }) - } else { - err = PrepareWebhooks(issue.Repo, HookEventIssues, &api.IssuePayload{ - Action: api.HookIssueEdited, - Index: issue.Index, - Changes: &api.ChangesPayload{ - Title: &api.ChangesFromPayload{ - From: oldTitle, - }, - }, - Issue: issue.APIFormat(), - Repository: issue.Repo.APIFormat(mode), - Sender: issue.Poster.APIFormat(), - }) - } - - if err != nil { - log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err) - } else { - go HookQueue.Add(issue.RepoID) - } - - return nil + return sess.Commit() } // AddDeletePRBranchComment adds delete branch comment for pull request issue diff --git a/models/issue_lock.go b/models/issue_lock.go index 5a2d996b640d6..dc6655ad3b51d 100644 --- a/models/issue_lock.go +++ b/models/issue_lock.go @@ -28,7 +28,6 @@ func updateIssueLock(opts *IssueLockOptions, lock bool) error { } opts.Issue.IsLocked = lock - var commentType CommentType if opts.Issue.IsLocked { commentType = CommentTypeLock @@ -36,16 +35,26 @@ func updateIssueLock(opts *IssueLockOptions, lock bool) error { commentType = CommentTypeUnlock } - if err := UpdateIssueCols(opts.Issue, "is_locked"); err != nil { + sess := x.NewSession() + defer sess.Close() + if err := sess.Begin(); err != nil { + return err + } + + if err := updateIssueCols(sess, opts.Issue, "is_locked"); err != nil { return err } - _, err := CreateComment(&CreateCommentOptions{ + _, err := createComment(sess, &CreateCommentOptions{ Doer: opts.Doer, Issue: opts.Issue, Repo: opts.Issue.Repo, Type: commentType, Content: opts.Reason, }) - return err + if err != nil { + return err + } + + return sess.Commit() } diff --git a/models/issue_test.go b/models/issue_test.go index 5b039bc1d5fff..0be3f68808254 100644 --- a/models/issue_test.go +++ b/models/issue_test.go @@ -160,7 +160,7 @@ func TestUpdateIssueCols(t *testing.T) { issue.Content = "This should have no effect" now := time.Now().Unix() - assert.NoError(t, UpdateIssueCols(issue, "name")) + assert.NoError(t, updateIssueCols(x, issue, "name")) then := time.Now().Unix() updatedIssue := AssertExistsAndLoadBean(t, &Issue{ID: issue.ID}).(*Issue) diff --git a/routers/repo/issue.go b/routers/repo/issue.go index e4ef3b1dbb033..16a049c7aa6df 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -1044,7 +1044,7 @@ func UpdateIssueTitle(ctx *context.Context) { } oldTitle := issue.Title - if err := issue.ChangeTitle(ctx.User, title); err != nil { + if err := issue_service.ChangeTitle(issue, ctx.User, title); err != nil { ctx.ServerError("ChangeTitle", err) return } diff --git a/services/issue/issue.go b/services/issue/issue.go index 5afdfc9901b7a..a28916a7f9b5e 100644 --- a/services/issue/issue.go +++ b/services/issue/issue.go @@ -45,3 +45,54 @@ func NewIssue(repo *models.Repository, issue *models.Issue, labelIDs []int64, as return nil } + +// ChangeTitle changes the title of this issue, as the given user. +func ChangeTitle(issue *models.Issue, doer *models.User, title string) (err error) { + oldTitle := issue.Title + issue.Title = title + + if err = issue.ChangeTitle(doer, oldTitle); err != nil { + return + } + + mode, _ := models.AccessLevel(issue.Poster, issue.Repo) + if issue.IsPull { + if err = issue.LoadPullRequest(); err != nil { + return fmt.Errorf("loadPullRequest: %v", err) + } + issue.PullRequest.Issue = issue + err = models.PrepareWebhooks(issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{ + Action: api.HookIssueEdited, + Index: issue.Index, + Changes: &api.ChangesPayload{ + Title: &api.ChangesFromPayload{ + From: oldTitle, + }, + }, + PullRequest: issue.PullRequest.APIFormat(), + Repository: issue.Repo.APIFormat(mode), + Sender: doer.APIFormat(), + }) + } else { + err = models.PrepareWebhooks(issue.Repo, models.HookEventIssues, &api.IssuePayload{ + Action: api.HookIssueEdited, + Index: issue.Index, + Changes: &api.ChangesPayload{ + Title: &api.ChangesFromPayload{ + From: oldTitle, + }, + }, + Issue: issue.APIFormat(), + Repository: issue.Repo.APIFormat(mode), + Sender: issue.Poster.APIFormat(), + }) + } + + if err != nil { + log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err) + } else { + go models.HookQueue.Add(issue.RepoID) + } + + return nil +} From 633cd7f473c24ee379e98b9f33ef79c7d664b32e Mon Sep 17 00:00:00 2001 From: spaeps <1037160+spaeps@users.noreply.github.com> Date: Fri, 11 Oct 2019 19:04:59 +0200 Subject: [PATCH 062/173] Add home template italian translation (#8352) It was just missing --- templates/home.tmpl | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/templates/home.tmpl b/templates/home.tmpl index f5eb455b5599b..91347c7e2c0bc 100644 --- a/templates/home.tmpl +++ b/templates/home.tmpl @@ -349,6 +349,46 @@

+ {{else if eq .Lang "it-IT"}} +
+
+

+ Facile da installare +

+

+ Semplicemente avvia l'eseguibile per la tua piattaforma. Oppure avvia Gitea con Docker o con Vagrant, oppure ottienilo pacchettizzato. +

+
+
+

+ Multipiattaforma +

+

+ Gitea funziona ovunque Go possa essere compilato: Windows, macOS, Linux, ARM, etc. Scegli ciò che ami! +

+
+
+
+
+

+ Leggero +

+

+ Gitea ha requisiti minimi bassi e può funzionare su un economico Raspberry Pi. Risparmia l'energia della tua macchina! +

+
+
+

+ Open Source +

+

+Ottieni code.gitea.io/gitea! +Partecipa per contribuire +a rendere questo progetto ancora migliore. +Non aver paura di diventare un collaboratore! +

+
+
{{else}}
From 772241b3245eaf4a7930ec48a4634b40699f132e Mon Sep 17 00:00:00 2001 From: Lauris BH Date: Sat, 12 Oct 2019 00:32:52 +0300 Subject: [PATCH 063/173] Latvian translation for home page (#8468) --- templates/home.tmpl | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/templates/home.tmpl b/templates/home.tmpl index 91347c7e2c0bc..d31094a5b2f9d 100644 --- a/templates/home.tmpl +++ b/templates/home.tmpl @@ -389,6 +389,46 @@ Non aver paura di diventare un collaboratore!

+ {{else if eq .Lang "lv-LV"}} +
+
+

+ Vienkārši instalējams +

+

+ Nepieciešams tikai palaist izpildāmo failu vajadzīgajai platformai. Vai izmantot Docker vai Vagrant, vai izmantot pakotni. +

+
+
+

+ Pieejama dažādām platformām +

+

+ Gitea iespējams uzstādīt jebkur, kam Go var nokompilēt: Windows, macOS, Linux, ARM utt. Izvēlies to, kas tev patīk! +

+
+
+
+
+

+ Viegla +

+

+ Gitea ir miminālas prasības un to var darbināt uz nedārga Raspberry Pi datora. Ietaupi savai ierīcei jaudu! +

+
+
+

+ Arvērtā pirmkoda +

+

+Iegūsti code.gitea.io/gitea! +Pievienojies un palīdzi uzlabot, +lai padarītu šo projektu vēl labāku! +Nekautrējies un līdzdarbojies! +

+
+
{{else}}
From ac3613b791884f29c386bda2ccaad5c7434d822c Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Fri, 11 Oct 2019 21:34:17 +0000 Subject: [PATCH 064/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_lv-LV.ini | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index ff930d8da7e09..21a1b7e269035 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -299,6 +299,7 @@ max_size_error=` jabūt ne mazāk kā %s simbolu garumā.` email_error=` nav derīga e-pasta adrese.` url_error=` nav korekts URL.` include_error=` ir jāsatur tekstu '%s'.` +glob_pattern_error=` glob izteiksme nav korekta: %s.` unknown_error=Nezināma kļūda: captcha_incorrect=Ievadīts nepareizs drošības kods. password_not_match=Izvēlētā parole nesakrīt ar atkārtoti ievadīto. @@ -317,6 +318,7 @@ enterred_invalid_repo_name=Pārliecinieties, vai ievadītā repozitorija nosauku enterred_invalid_owner_name=Pārliecinieties, vai ievadītā īpašnieka vārds ir pareizs. enterred_invalid_password=Pārliecinieties, vai ievadītā parole ir pareiza. user_not_exist=Lietotājs neeksistē. +team_not_exist=Komanda neeksistē. last_org_owner=Nevar noņemt pēdējo īpašnieku komandas lietotāju, jo organizācijām ir jābūt vismaz vienam īpašniekam. cannot_add_org_to_team=Organizāciju nevar pievienot kā komandas biedru. @@ -577,6 +579,8 @@ fork_visibility_helper=Atdalītam repozitorijam nav iespējams mainīt tā redza repo_desc=Apraksts repo_lang=Valoda repo_gitignore_helper=Izvēlieties .gitignore sagatavi. +issue_labels=Problēmu etiķetes +issue_labels_helper=Izvēlieties problēmu etiķešu kopu. license=Licence license_helper=Izvēlieties licences failu. readme=LASIMANI @@ -676,6 +680,8 @@ stored_lfs=Saglabāts Git LFS commit_graph=Revīziju grafs blame=Vainot normal_view=Parastais skats +line=rinda +lines=rindas editor.new_file=Jauna datne editor.upload_file=Augšupielādēt failu @@ -701,6 +707,7 @@ editor.delete=Dzēst '%s' editor.commit_message_desc=Pievienot neobligātu paplašinātu aprakstu… editor.commit_directly_to_this_branch=Apstiprināt revīzijas izmaiņas atzarā %s. editor.create_new_branch=Izveidot jaunu atzaru un izmaiņu pieprasījumu šai revīzijai. +editor.create_new_branch_np=Izveidot jaunu atzaru šai revīzijai. editor.propose_file_change=Ieteikt faila izmaiņas editor.new_branch_name_desc=Jaunā atzara nosaukums… editor.cancel=Atcelt @@ -832,6 +839,10 @@ issues.create_comment=Komentēt issues.closed_at=`aizvērts %[2]s` issues.reopened_at=`atvērts atkārtoti %[2]s` issues.commit_ref_at=`pieminēja šo problēmu revīzijā %[2]s` +issues.ref_issue_at=`atsaucās uz šo problēmu %[1]s` +issues.ref_pull_at=`atsaucās uz šo izmaiņu pieprasījumu %[1]s` +issues.ref_issue_ext_at=`atsaucās uz šo problēmu no %[1]s %[2]s` +issues.ref_pull_ext_at=`atsaucās uz šo izmaiņu pieprasījumu no %[1]s %[2]s` issues.poster=Autors issues.collaborator=Līdzstrādnieks issues.owner=Īpašnieks @@ -977,6 +988,8 @@ pulls.cannot_merge_work_in_progress=Šis izmaiņu pieprasījums ir atzīmēts, k pulls.data_broken=Izmaiņu pieprasījums ir bojāts, jo dzēsta informācija no atdalītā repozitorija. pulls.files_conflicted=Šīs izmaiņu pieprasījuma izmaiņas konfliktē ar mērķa atzaru. pulls.is_checking=Notiek konfliktu pārbaude, mirkli uzgaidiet un atjaunojiet lapu. +pulls.required_status_check_failed=Dažas no pārbaudēm nebija veiksmīgas. +pulls.required_status_check_administrator=Kā administrators Jūs varat sapludināt šo izmaiņu pieprasījumu. pulls.blocked_by_approvals=Šim izmaiņu pieprasījumam nav nepieciešamais apstiprinājumu daudzums. %d no %d apstiprinājumi piešķirti. pulls.can_auto_merge_desc=Šo izmaiņu pieprasījumu var automātiski sapludināt. pulls.cannot_auto_merge_desc=Šis izmaiņu pieprasījums nevar tikt automātiski sapludināts konfliktu dēļ. @@ -984,6 +997,7 @@ pulls.cannot_auto_merge_helper=Sapludiniet manuāli, lai atrisinātu konfliktus. pulls.no_merge_desc=Šo izmaiņu pieprasījumu nav iespējams sapludināt, jo nav atļauts neviens sapludināšanas veids. pulls.no_merge_helper=Lai sapludinātu šo izmaiņu pieprasījumu, iespējojiet vismaz vienu sapludināšanas veidu repozitorija iestatījumos vai sapludiniet to manuāli. pulls.no_merge_wip=Šo izmaiņu pieprasījumu nav iespējams sapludināt, jo tas ir atzīmēts, ka darbs pie tā vēl nav pabeigts. +pulls.no_merge_status_check=Šo izmaiņu pieprasījumu nevar saplusināt, jo nav veiksmīgi izildītas visas obligātas statusa pārbaudes. pulls.merge_pull_request=Izmaiņu pieprasījuma sapludināšana pulls.rebase_merge_pull_request=Pārbāzēt un sapludināt pulls.rebase_merge_commit_pull_request=Pārbāzēt un sapludināt (--no-ff) @@ -1125,6 +1139,7 @@ settings.collaboration=Līdzstrādnieks settings.collaboration.admin=Administrators settings.collaboration.write=Rakstīšanas settings.collaboration.read=Skatīšanās +settings.collaboration.owner=Īpašnieks settings.collaboration.undefined=Nedefinētas settings.hooks=Tīmekļa āķi settings.githooks=Git āķi @@ -1206,6 +1221,11 @@ settings.collaborator_deletion_desc=Noņemot līdzstrādnieku, tam tiks liegta p settings.remove_collaborator_success=Līdzstrādnieks tika noņemts. settings.search_user_placeholder=Meklēt lietotāju… settings.org_not_allowed_to_be_collaborator=Organizācijas nevar tikt pievienotas kā līdzstrādnieki. +settings.change_team_access_not_allowed=Iespēja mainīt komandu piekļuvi repozitorijam ir organizācijas īpašniekam +settings.team_not_in_organization=Komanda nav tajā pašā organizācijā kā repozitorijs +settings.add_team_duplicate=Komandai jau ir piekļuve šim repozitorijam +settings.add_team_success=Komandai tagad ir piekļuve šim repozitorijam. +settings.remove_team_success=Komandas piekļuve šim repozitorijam ir noņemta. settings.add_webhook=Pievienot tīmekļa āķi settings.add_webhook.invalid_channel_name=Tīmekļa āķa kanāla nosaukums nevar būt tukšs vai saturēt tikai # simbolu. settings.hooks_desc=Tīmekļa āķi ļauj paziņot ārējiem servisiem par noteiktiem notikumiem, kas notiek Gitea. Kad iestāsies kāds notikums, katram ārējā servisa URL tiks nosūtīts POST pieprasījums. Lai uzzinātu sīkāk skatieties tīmekļa āķu rokasgrāmatā. @@ -1255,6 +1275,8 @@ settings.event_pull_request=Izmaiņu pieprasījums settings.event_pull_request_desc=Izmaiņu pieprasījums izveidots, slēgts, atkārtoti atvērts, labots, apstiprināts, noraidīts, recenzēts, piešķirts, pievienots vai noņemts atbildīgais, pievienota etiķete, noņemta etiķete, pievienots vai noņemts atskaites punkts. settings.event_push=Izmaiņu nosūtīšana settings.event_push_desc=Git izmaiņu nosūtīšana uz repozitoriju. +settings.branch_filter=Atzaru filtrs +settings.branch_filter_desc=Atzaru ierobežojumi izmaiņu iesūtīšanas, zaru izveidošanas vai dzēšanas notikumien, izmantojot, glob izteiksmi. Ja norādīts tukšs vai *, notikumi uz visiem zariem tiks nosūtīti. Skatieties github.com/gobwas/glob pieraksta dokumentāciju. Piemērs: master, {master,release*}. settings.event_repository=Repozitorijs settings.event_repository_desc=Repozitorijs izveidots vai dzēsts. settings.active=Aktīvs @@ -1305,6 +1327,9 @@ settings.protect_merge_whitelist_committers=Iespējot sapludināšanas ierobežo settings.protect_merge_whitelist_committers_desc=Atļaut tikai noteiktiem lietotājiem vai komandām sapludināt izmaiņu pieprasījumus šajā atzarā. settings.protect_merge_whitelist_users=Lietotāji, kas var veikt izmaiņu sapludināšanu: settings.protect_merge_whitelist_teams=Komandas, kas var veikt izmaiņu sapludināšanu: +settings.protect_check_status_contexts=Iespējot statusu pārbaudi +settings.protect_check_status_contexts_desc=Nepieciešamas veiksmīgas statusa pārbaudes pirms sapludināšanas. Izvēlieties, kurām statusa pārbaudēm ir jāizpildās pirms ir iespejams tās sapludināt. Ja iespējots, tad revīzijas sākotnēji jānosūta uz atsevišķu atzaru, pēc kā var tikt saplusinātas vai tieši nosūtītas uz atzariem, kas atbildst veiksmīgām norādītajām stautsa pārbaudēm. Ja konteksts nav norādīts, pēdējai revīzijai ir jābūt veiksmīga neatkarīgi no konteksta. +settings.protect_check_status_contexts_list=Statusu pārbaudes, kas šim repozitorijam bijušas pēdējās nedēļas laikā settings.protect_required_approvals=Vajadzīgi apstiprinājumi: settings.protect_required_approvals_desc=Atļaut tikai noteiktiem lietotājiem vai komandām sapludināt izmaiņu pieprasījumu, kam veikts noteikts daudzums pozitīvu recenziju. settings.protect_approvals_whitelist_users=Lietotāji, kas var veikt recenzijas: @@ -1352,6 +1377,11 @@ diff.whitespace_ignore_at_eol=Ignorēt atstarpju izmaiņas rindu beigās diff.stats_desc=%d mainītis faili ar %d papildinājumiem un %d dzēšanām diff.bin=Binārs diff.view_file=Parādīt failu +diff.file_before=Pirms +diff.file_after=Pēc +diff.file_image_width=Platums +diff.file_image_height=Augstums +diff.file_byte_size=Izmērs diff.file_suppressed=Failā izmaiņas netiks attēlotas, jo tās ir par lielu diff.too_many_files=Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels diff.comment.placeholder=Ievadiet komentāru @@ -1454,6 +1484,8 @@ settings.options=Organizācija settings.full_name=Pilns vārds, uzvārds settings.website=Mājas lapa settings.location=Atrašanās vieta +settings.permission=Tiesības +settings.repoadminchangeteam=Repozitorija administrators var pievienot vain noņemt piekļuvi komandām settings.visibility=Redzamība settings.visibility.public=Publiska settings.visibility.limited=Ierobežota (redzama tikai autorizētiem lietotājiem) @@ -1700,6 +1732,7 @@ auths.tip.google_plus=Iegūstiet OAuth2 klienta pilnvaru no Google API konsoles auths.tip.openid_connect=Izmantojiet OpenID pieslēgšanās atklāšanas URL (/.well-known/openid-configuration), lai norādītu galapunktus auths.tip.twitter=Dodieties uz adresi https://dev.twitter.com/apps, izveidojiet aplikāciju un pārliecinieties, ka ir atzīmēts “Allow this application to be used to Sign in with Twitter” auths.tip.discord=Reģistrējiet jaunu aplikāciju adresē https://discordapp.com/developers/applications/me +auths.tip.gitea=Reģistrēt jaunu OAuth2 lietojumprogrammu. Pamācību iespējams atrast https://docs.gitea.io/en-us/oauth2-provider/ auths.edit=Labot autentifikācijas avotu auths.activated=Autentifikācijas avots ir atkivizēts auths.new_success=Jauna autentifikācija'%s' tika pievienota. From 5e759b60cca3cd8484a6235fcc9120d18e8cd455 Mon Sep 17 00:00:00 2001 From: zeripath Date: Sat, 12 Oct 2019 01:13:27 +0100 Subject: [PATCH 065/173] Restore functionality for early gits (#7775) * Change tests to make it possible to run TestGit with 1.7.2 * Make merge run on 1.7.2 * Fix tracking and staging branch name problem * Ensure that git 1.7.2 works on tests * ensure that there is no chance for conflicts * Fix-up missing merge issues * Final rm * Ensure LFS filters run on the tests * Do not sign commits from temp repo * Restore tracking fetch change * Apply suggestions from code review * Update modules/repofiles/temp_repo.go --- .../git_helper_for_declarative_test.go | 31 ++++++++ integrations/git_test.go | 62 +++++++++++---- integrations/lfs_getobject_test.go | 5 ++ models/repo.go | 2 +- modules/git/repo_branch.go | 2 +- modules/git/repo_tree.go | 22 ++++-- modules/process/manager.go | 14 ++++ modules/repofiles/temp_repo.go | 38 ++++++++- modules/repofiles/update.go | 25 +++--- modules/repofiles/upload.go | 11 ++- services/mirror/mirror.go | 2 +- services/pull/merge.go | 78 +++++++++++++------ 12 files changed, 226 insertions(+), 66 deletions(-) diff --git a/integrations/git_helper_for_declarative_test.go b/integrations/git_helper_for_declarative_test.go index 628611d2d7f24..294f0bc5fe6ba 100644 --- a/integrations/git_helper_for_declarative_test.go +++ b/integrations/git_helper_for_declarative_test.go @@ -12,7 +12,9 @@ import ( "net/http" "net/url" "os" + "path" "path/filepath" + "strings" "testing" "time" @@ -37,7 +39,12 @@ func withKeyFile(t *testing.T, keyname string, callback func(string)) { err = ssh.GenKeyPair(keyFile) assert.NoError(t, err) + err = ioutil.WriteFile(path.Join(tmpDir, "ssh"), []byte("#!/bin/bash\n"+ + "ssh -o \"UserKnownHostsFile=/dev/null\" -o \"StrictHostKeyChecking=no\" -o \"IdentitiesOnly=yes\" -i \""+keyFile+"\" \"$@\""), 0700) + assert.NoError(t, err) + //Setup ssh wrapper + os.Setenv("GIT_SSH", path.Join(tmpDir, "ssh")) os.Setenv("GIT_SSH_COMMAND", "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentitiesOnly=yes -i \""+keyFile+"\"") os.Setenv("GIT_SSH_VARIANT", "ssh") @@ -54,6 +61,24 @@ func createSSHUrl(gitPath string, u *url.URL) *url.URL { return &u2 } +func allowLFSFilters() []string { + // Now here we should explicitly allow lfs filters to run + globalArgs := git.GlobalCommandArgs + filteredLFSGlobalArgs := make([]string, len(git.GlobalCommandArgs)) + j := 0 + for _, arg := range git.GlobalCommandArgs { + if strings.Contains(arg, "lfs") { + j-- + } else { + filteredLFSGlobalArgs[j] = arg + j++ + } + } + filteredLFSGlobalArgs = filteredLFSGlobalArgs[:j] + git.GlobalCommandArgs = filteredLFSGlobalArgs + return globalArgs +} + func onGiteaRun(t *testing.T, callback func(*testing.T, *url.URL)) { prepareTestEnv(t, 1) s := http.Server{ @@ -79,7 +104,9 @@ func onGiteaRun(t *testing.T, callback func(*testing.T, *url.URL)) { func doGitClone(dstLocalPath string, u *url.URL) func(*testing.T) { return func(t *testing.T) { + oldGlobals := allowLFSFilters() assert.NoError(t, git.Clone(u.String(), dstLocalPath, git.CloneRepoOptions{})) + git.GlobalCommandArgs = oldGlobals assert.True(t, com.IsExist(filepath.Join(dstLocalPath, "README.md"))) } } @@ -140,7 +167,9 @@ func doGitCreateBranch(dstPath, branch string) func(*testing.T) { func doGitCheckoutBranch(dstPath string, args ...string) func(*testing.T) { return func(t *testing.T) { + oldGlobals := allowLFSFilters() _, err := git.NewCommand(append([]string{"checkout"}, args...)...).RunInDir(dstPath) + git.GlobalCommandArgs = oldGlobals assert.NoError(t, err) } } @@ -154,7 +183,9 @@ func doGitMerge(dstPath string, args ...string) func(*testing.T) { func doGitPull(dstPath string, args ...string) func(*testing.T) { return func(t *testing.T) { + oldGlobals := allowLFSFilters() _, err := git.NewCommand(append([]string{"pull"}, args...)...).RunInDir(dstPath) + git.GlobalCommandArgs = oldGlobals assert.NoError(t, err) } } diff --git a/integrations/git_test.go b/integrations/git_test.go index 8578fb86d5d76..dbcc26522765f 100644 --- a/integrations/git_test.go +++ b/integrations/git_test.go @@ -19,6 +19,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "github.com/stretchr/testify/assert" @@ -135,6 +136,11 @@ func standardCommitAndPushTest(t *testing.T, dstPath string) (little, big string func lfsCommitAndPushTest(t *testing.T, dstPath string) (littleLFS, bigLFS string) { t.Run("LFS", func(t *testing.T) { PrintCurrentTest(t) + setting.CheckLFSVersion() + if !setting.LFS.StartServer { + t.Skip() + return + } prefix := "lfs-data-file-" _, err := git.NewCommand("lfs").AddArguments("install").RunInDir(dstPath) assert.NoError(t, err) @@ -142,6 +148,21 @@ func lfsCommitAndPushTest(t *testing.T, dstPath string) (littleLFS, bigLFS strin assert.NoError(t, err) err = git.AddChanges(dstPath, false, ".gitattributes") assert.NoError(t, err) + oldGlobals := allowLFSFilters() + 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: fmt.Sprintf("Testing commit @ %v", time.Now()), + }) + git.GlobalCommandArgs = oldGlobals littleLFS, bigLFS = commitAndPushTest(t, dstPath, prefix) @@ -185,20 +206,25 @@ func rawTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS s resp := session.MakeRequest(t, req, http.StatusOK) assert.Equal(t, littleSize, resp.Body.Len()) - req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", littleLFS)) - resp = session.MakeRequest(t, req, http.StatusOK) - assert.NotEqual(t, littleSize, resp.Body.Len()) - assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier) + setting.CheckLFSVersion() + if setting.LFS.StartServer { + req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", littleLFS)) + resp = session.MakeRequest(t, req, http.StatusOK) + assert.NotEqual(t, littleSize, resp.Body.Len()) + assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier) + } if !testing.Short() { req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", big)) resp = session.MakeRequest(t, req, http.StatusOK) assert.Equal(t, bigSize, resp.Body.Len()) - req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", bigLFS)) - resp = session.MakeRequest(t, req, http.StatusOK) - assert.NotEqual(t, bigSize, resp.Body.Len()) - assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier) + if setting.LFS.StartServer { + req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", bigLFS)) + resp = session.MakeRequest(t, req, http.StatusOK) + assert.NotEqual(t, bigSize, resp.Body.Len()) + assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier) + } } }) } @@ -217,18 +243,23 @@ func mediaTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) assert.Equal(t, littleSize, resp.Length) - req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", littleLFS)) - resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) - assert.Equal(t, littleSize, resp.Length) + setting.CheckLFSVersion() + if setting.LFS.StartServer { + req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", littleLFS)) + resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) + assert.Equal(t, littleSize, resp.Length) + } if !testing.Short() { req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", big)) resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) assert.Equal(t, bigSize, resp.Length) - req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", bigLFS)) - resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) - assert.Equal(t, bigSize, resp.Length) + if setting.LFS.StartServer { + req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", bigLFS)) + resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) + assert.Equal(t, bigSize, resp.Length) + } } }) } @@ -274,6 +305,8 @@ func generateCommitWithNewData(size int, repoPath, email, fullName, prefix strin } //Commit + // Now here we should explicitly allow lfs filters to run + oldGlobals := allowLFSFilters() err = git.AddChanges(repoPath, false, filepath.Base(tmpFile.Name())) if err != nil { return "", err @@ -291,6 +324,7 @@ func generateCommitWithNewData(size int, repoPath, email, fullName, prefix strin }, Message: fmt.Sprintf("Testing commit @ %v", time.Now()), }) + git.GlobalCommandArgs = oldGlobals return filepath.Base(tmpFile.Name()), err } diff --git a/integrations/lfs_getobject_test.go b/integrations/lfs_getobject_test.go index bb269d5eeba45..373fffa4453bd 100644 --- a/integrations/lfs_getobject_test.go +++ b/integrations/lfs_getobject_test.go @@ -58,6 +58,11 @@ func storeObjectInRepo(t *testing.T, repositoryID int64, content *[]byte) string func doLfs(t *testing.T, content *[]byte, expectGzip bool) { prepareTestEnv(t) + setting.CheckLFSVersion() + if !setting.LFS.StartServer { + t.Skip() + return + } repo, err := models.GetRepositoryByOwnerAndName("user2", "repo1") assert.NoError(t, err) oid := storeObjectInRepo(t, repo.ID, content) diff --git a/models/repo.go b/models/repo.go index 50402c8e1aeda..8db527477b03b 100644 --- a/models/repo.go +++ b/models/repo.go @@ -1093,7 +1093,7 @@ func CleanUpMigrateInfo(repo *Repository) (*Repository, error) { } } - _, err := git.NewCommand("remote", "remove", "origin").RunInDir(repoPath) + _, err := git.NewCommand("remote", "rm", "origin").RunInDir(repoPath) if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { return repo, fmt.Errorf("CleanUpMigrateInfo: %v", err) } diff --git a/modules/git/repo_branch.go b/modules/git/repo_branch.go index 9209f4a764f4a..3e1261d294cf8 100644 --- a/modules/git/repo_branch.go +++ b/modules/git/repo_branch.go @@ -165,7 +165,7 @@ func (repo *Repository) AddRemote(name, url string, fetch bool) error { // RemoveRemote removes a remote from repository. func (repo *Repository) RemoveRemote(name string) error { - _, err := NewCommand("remote", "remove", name).RunInDir(repo.Path) + _, err := NewCommand("remote", "rm", name).RunInDir(repo.Path) return err } diff --git a/modules/git/repo_tree.go b/modules/git/repo_tree.go index b31e4330cd3cf..f5262ba81cb54 100644 --- a/modules/git/repo_tree.go +++ b/modules/git/repo_tree.go @@ -6,10 +6,13 @@ package git import ( + "bytes" "fmt" "os" "strings" "time" + + "github.com/mcuadros/go-version" ) func (repo *Repository) getTree(id SHA1) (*Tree, error) { @@ -61,6 +64,11 @@ type CommitTreeOpts struct { // CommitTree creates a commit from a given tree id for the user with provided message func (repo *Repository) CommitTree(sig *Signature, tree *Tree, opts CommitTreeOpts) (SHA1, error) { + binVersion, err := BinVersion() + if err != nil { + return SHA1{}, err + } + commitTimeStr := time.Now().Format(time.RFC3339) // Because this may call hooks we should pass in the environment @@ -78,20 +86,24 @@ func (repo *Repository) CommitTree(sig *Signature, tree *Tree, opts CommitTreeOp cmd.AddArguments("-p", parent) } - cmd.AddArguments("-m", opts.Message) + messageBytes := new(bytes.Buffer) + _, _ = messageBytes.WriteString(opts.Message) + _, _ = messageBytes.WriteString("\n") if opts.KeyID != "" { cmd.AddArguments(fmt.Sprintf("-S%s", opts.KeyID)) } - if opts.NoGPGSign { + if version.Compare(binVersion, "2.0.0", ">=") && opts.NoGPGSign { cmd.AddArguments("--no-gpg-sign") } - res, err := cmd.RunInDirWithEnv(repo.Path, env) + stdout := new(bytes.Buffer) + stderr := new(bytes.Buffer) + err = cmd.RunInDirTimeoutEnvFullPipeline(env, -1, repo.Path, stdout, stderr, messageBytes) if err != nil { - return SHA1{}, err + return SHA1{}, concatenateError(err, stderr.String()) } - return NewIDFromString(strings.TrimSpace(res)) + return NewIDFromString(strings.TrimSpace(stdout.String())) } diff --git a/modules/process/manager.go b/modules/process/manager.go index 9ac3af86f106e..3e77c0a6a90f1 100644 --- a/modules/process/manager.go +++ b/modules/process/manager.go @@ -1,4 +1,5 @@ // Copyright 2014 The Gogs Authors. All rights reserved. +// Copyright 2019 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. @@ -9,6 +10,7 @@ import ( "context" "errors" "fmt" + "io" "os/exec" "sync" "time" @@ -93,6 +95,14 @@ func (pm *Manager) ExecDir(timeout time.Duration, dir, desc, cmdName string, arg // Returns its complete stdout and stderr // outputs and an error, if any (including timeout) func (pm *Manager) ExecDirEnv(timeout time.Duration, dir, desc string, env []string, cmdName string, args ...string) (string, string, error) { + return pm.ExecDirEnvStdIn(timeout, dir, desc, env, nil, cmdName, args...) +} + +// ExecDirEnvStdIn runs a command in given path and environment variables with provided stdIN, and waits for its completion +// up to the given timeout (or DefaultTimeout if -1 is given). +// Returns its complete stdout and stderr +// outputs and an error, if any (including timeout) +func (pm *Manager) ExecDirEnvStdIn(timeout time.Duration, dir, desc string, env []string, stdIn io.Reader, cmdName string, args ...string) (string, string, error) { if timeout == -1 { timeout = 60 * time.Second } @@ -108,6 +118,10 @@ func (pm *Manager) ExecDirEnv(timeout time.Duration, dir, desc string, env []str cmd.Env = env cmd.Stdout = stdOut cmd.Stderr = stdErr + if stdIn != nil { + cmd.Stdin = stdIn + } + if err := cmd.Start(); err != nil { return "", "", err } diff --git a/modules/repofiles/temp_repo.go b/modules/repofiles/temp_repo.go index f791c3cb96584..4a50e641927dd 100644 --- a/modules/repofiles/temp_repo.go +++ b/modules/repofiles/temp_repo.go @@ -21,6 +21,8 @@ import ( "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/services/gitdiff" + + "github.com/mcuadros/go-version" ) // TemporaryUploadRepository is a type to wrap our upload repositories as a shallow clone @@ -254,6 +256,11 @@ func (t *TemporaryUploadRepository) CommitTree(author, committer *models.User, t authorSig := author.NewGitSig() committerSig := committer.NewGitSig() + binVersion, err := git.BinVersion() + if err != nil { + return "", fmt.Errorf("Unable to get git version: %v", err) + } + // FIXME: Should we add SSH_ORIGINAL_COMMAND to this // Because this may call hooks we should pass in the environment env := append(os.Environ(), @@ -264,11 +271,21 @@ func (t *TemporaryUploadRepository) CommitTree(author, committer *models.User, t "GIT_COMMITTER_EMAIL="+committerSig.Email, "GIT_COMMITTER_DATE="+commitTimeStr, ) - commitHash, stderr, err := process.GetManager().ExecDirEnv(5*time.Minute, + messageBytes := new(bytes.Buffer) + _, _ = messageBytes.WriteString(message) + _, _ = messageBytes.WriteString("\n") + + args := []string{"commit-tree", treeHash, "-p", "HEAD"} + if version.Compare(binVersion, "2.0.0", ">=") { + args = append(args, "--no-gpg-sign") + } + + commitHash, stderr, err := process.GetManager().ExecDirEnvStdIn(5*time.Minute, t.basePath, fmt.Sprintf("commitTree (git commit-tree): %s", t.basePath), env, - git.GitExecutable, "commit-tree", treeHash, "-p", "HEAD", "-m", message) + messageBytes, + git.GitExecutable, args...) if err != nil { return "", fmt.Errorf("git commit-tree: %s", stderr) } @@ -328,6 +345,12 @@ func (t *TemporaryUploadRepository) DiffIndex() (diff *gitdiff.Diff, err error) // CheckAttribute checks the given attribute of the provided files func (t *TemporaryUploadRepository) CheckAttribute(attribute string, args ...string) (map[string]map[string]string, error) { + binVersion, err := git.BinVersion() + if err != nil { + log.Error("Error retrieving git version: %v", err) + return nil, err + } + stdOut := new(bytes.Buffer) stdErr := new(bytes.Buffer) @@ -335,7 +358,14 @@ func (t *TemporaryUploadRepository) CheckAttribute(attribute string, args ...str ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() - cmdArgs := []string{"check-attr", "-z", attribute, "--cached", "--"} + cmdArgs := []string{"check-attr", "-z", attribute} + + // git check-attr --cached first appears in git 1.7.8 + if version.Compare(binVersion, "1.7.8", ">=") { + cmdArgs = append(cmdArgs, "--cached") + } + cmdArgs = append(cmdArgs, "--") + for _, arg := range args { if arg != "" { cmdArgs = append(cmdArgs, arg) @@ -353,7 +383,7 @@ func (t *TemporaryUploadRepository) CheckAttribute(attribute string, args ...str } pid := process.GetManager().Add(desc, cmd) - err := cmd.Wait() + err = cmd.Wait() process.GetManager().Remove(pid) if err != nil { diff --git a/modules/repofiles/update.go b/modules/repofiles/update.go index ee1b16bce9dbd..1a1fe6c389f48 100644 --- a/modules/repofiles/update.go +++ b/modules/repofiles/update.go @@ -313,12 +313,6 @@ func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *Up } } - // Check there is no way this can return multiple infos - filename2attribute2info, err := t.CheckAttribute("filter", treePath) - if err != nil { - return nil, err - } - content := opts.Content if bom { content = string(charset.UTF8BOM) + content @@ -341,16 +335,23 @@ func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *Up opts.Content = content var lfsMetaObject *models.LFSMetaObject - if setting.LFS.StartServer && filename2attribute2info[treePath] != nil && filename2attribute2info[treePath]["filter"] == "lfs" { - // OK so we are supposed to LFS this data! - oid, err := models.GenerateLFSOid(strings.NewReader(opts.Content)) + if setting.LFS.StartServer { + // Check there is no way this can return multiple infos + filename2attribute2info, err := t.CheckAttribute("filter", treePath) if err != nil { return nil, err } - lfsMetaObject = &models.LFSMetaObject{Oid: oid, Size: int64(len(opts.Content)), RepositoryID: repo.ID} - content = lfsMetaObject.Pointer() - } + if filename2attribute2info[treePath] != nil && filename2attribute2info[treePath]["filter"] == "lfs" { + // OK so we are supposed to LFS this data! + oid, err := models.GenerateLFSOid(strings.NewReader(opts.Content)) + if err != nil { + return nil, err + } + lfsMetaObject = &models.LFSMetaObject{Oid: oid, Size: int64(len(opts.Content)), RepositoryID: repo.ID} + content = lfsMetaObject.Pointer() + } + } // Add the object to the database objectHash, err := t.HashObject(strings.NewReader(content)) if err != nil { diff --git a/modules/repofiles/upload.go b/modules/repofiles/upload.go index f2ffec7ebcddb..202e66b89a1ca 100644 --- a/modules/repofiles/upload.go +++ b/modules/repofiles/upload.go @@ -74,9 +74,12 @@ func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRep infos[i] = uploadInfo{upload: upload} } - filename2attribute2info, err := t.CheckAttribute("filter", names...) - if err != nil { - return err + var filename2attribute2info map[string]map[string]string + if setting.LFS.StartServer { + filename2attribute2info, err = t.CheckAttribute("filter", names...) + if err != nil { + return err + } } // Copy uploaded files into repository. @@ -88,7 +91,7 @@ func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRep defer file.Close() var objectHash string - if filename2attribute2info[uploadInfo.upload.Name] != nil && filename2attribute2info[uploadInfo.upload.Name]["filter"] == "lfs" { + if setting.LFS.StartServer && filename2attribute2info[uploadInfo.upload.Name] != nil && filename2attribute2info[uploadInfo.upload.Name]["filter"] == "lfs" { // Handle LFS // FIXME: Inefficient! this should probably happen in models.Upload oid, err := models.GenerateLFSOid(file) diff --git a/services/mirror/mirror.go b/services/mirror/mirror.go index 3339f7232955d..7bfc5fd4da044 100644 --- a/services/mirror/mirror.go +++ b/services/mirror/mirror.go @@ -91,7 +91,7 @@ func AddressNoCredentials(m *models.Mirror) string { func SaveAddress(m *models.Mirror, addr string) error { repoPath := m.Repo.RepoPath() // Remove old origin - _, err := git.NewCommand("remote", "remove", "origin").RunInDir(repoPath) + _, err := git.NewCommand("remote", "rm", "origin").RunInDir(repoPath) if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { return err } diff --git a/services/pull/merge.go b/services/pull/merge.go index 6150c1518e79e..e83784f31ebdb 100644 --- a/services/pull/merge.go +++ b/services/pull/merge.go @@ -11,7 +11,6 @@ import ( "fmt" "io/ioutil" "os" - "path" "path/filepath" "strings" @@ -22,6 +21,8 @@ import ( "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" + + "github.com/mcuadros/go-version" ) // Merge merges pull request to base repository. @@ -66,20 +67,17 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor headRepoPath := models.RepoPath(pr.HeadUserName, pr.HeadRepo.Name) - if err := git.Clone(baseGitRepo.Path, tmpBasePath, git.CloneRepoOptions{ - Shared: true, - NoCheckout: true, - Branch: pr.BaseBranch, - }); err != nil { - return fmt.Errorf("git clone: %v", err) + if err := git.InitRepository(tmpBasePath, false); err != nil { + return fmt.Errorf("git init: %v", err) } remoteRepoName := "head_repo" + baseBranch := "base" // Add head repo remote. addCacheRepo := func(staging, cache string) error { p := filepath.Join(staging, ".git", "objects", "info", "alternates") - f, err := os.OpenFile(p, os.O_APPEND|os.O_WRONLY, 0600) + f, err := os.OpenFile(p, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600) if err != nil { return err } @@ -91,25 +89,41 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor return nil } - if err := addCacheRepo(tmpBasePath, headRepoPath); err != nil { + if err := addCacheRepo(tmpBasePath, baseGitRepo.Path); err != nil { return fmt.Errorf("addCacheRepo [%s -> %s]: %v", headRepoPath, tmpBasePath, err) } var errbuf strings.Builder + if err := git.NewCommand("remote", "add", "-t", pr.BaseBranch, "-m", pr.BaseBranch, "origin", baseGitRepo.Path).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git remote add [%s -> %s]: %s", baseGitRepo.Path, tmpBasePath, errbuf.String()) + } + + if err := git.NewCommand("fetch", "origin", "--no-tags", pr.BaseBranch+":"+baseBranch, pr.BaseBranch+":original_"+baseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) + } + + if err := git.NewCommand("symbolic-ref", "HEAD", git.BranchPrefix+baseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git symbolic-ref HEAD base [%s]: %s", tmpBasePath, errbuf.String()) + } + + if err := addCacheRepo(tmpBasePath, headRepoPath); err != nil { + return fmt.Errorf("addCacheRepo [%s -> %s]: %v", headRepoPath, tmpBasePath, err) + } + if err := git.NewCommand("remote", "add", remoteRepoName, headRepoPath).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { return fmt.Errorf("git remote add [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) } + trackingBranch := "tracking" // Fetch head branch - if err := git.NewCommand("fetch", remoteRepoName, fmt.Sprintf("%s:refs/remotes/%s/%s", pr.HeadBranch, remoteRepoName, pr.HeadBranch)).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + if err := git.NewCommand("fetch", "--no-tags", remoteRepoName, pr.HeadBranch+":"+trackingBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { return fmt.Errorf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) } - trackingBranch := path.Join(remoteRepoName, pr.HeadBranch) - stagingBranch := fmt.Sprintf("%s_%s", remoteRepoName, pr.HeadBranch) + stagingBranch := "staging" // Enable sparse-checkout - sparseCheckoutList, err := getDiffTree(tmpBasePath, pr.BaseBranch, trackingBranch) + sparseCheckoutList, err := getDiffTree(tmpBasePath, baseBranch, trackingBranch) if err != nil { return fmt.Errorf("getDiffTree: %v", err) } @@ -123,21 +137,37 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor return fmt.Errorf("Writing sparse-checkout file to %s: %v", sparseCheckoutListPath, err) } + gitConfigCommand := func() func() *git.Command { + binVersion, err := git.BinVersion() + if err != nil { + log.Fatal("Error retrieving git version: %v", err) + } + + if version.Compare(binVersion, "1.8.0", ">=") { + return func() *git.Command { + return git.NewCommand("config", "--local") + } + } + return func() *git.Command { + return git.NewCommand("config") + } + }() + // Switch off LFS process (set required, clean and smudge here also) - if err := git.NewCommand("config", "--local", "filter.lfs.process", "").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + if err := gitConfigCommand().AddArguments("filter.lfs.process", "").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { return fmt.Errorf("git config [filter.lfs.process -> <> ]: %v", errbuf.String()) } - if err := git.NewCommand("config", "--local", "filter.lfs.required", "false").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + if err := gitConfigCommand().AddArguments("filter.lfs.required", "false").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { return fmt.Errorf("git config [filter.lfs.required -> ]: %v", errbuf.String()) } - if err := git.NewCommand("config", "--local", "filter.lfs.clean", "").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + if err := gitConfigCommand().AddArguments("filter.lfs.clean", "").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { return fmt.Errorf("git config [filter.lfs.clean -> <> ]: %v", errbuf.String()) } - if err := git.NewCommand("config", "--local", "filter.lfs.smudge", "").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + if err := gitConfigCommand().AddArguments("filter.lfs.smudge", "").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { return fmt.Errorf("git config [filter.lfs.smudge -> <> ]: %v", errbuf.String()) } - if err := git.NewCommand("config", "--local", "core.sparseCheckout", "true").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + if err := gitConfigCommand().AddArguments("core.sparseCheckout", "true").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { return fmt.Errorf("git config [core.sparsecheckout -> true]: %v", errbuf.String()) } @@ -163,11 +193,11 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor return fmt.Errorf("git checkout: %s", errbuf.String()) } // Rebase before merging - if err := git.NewCommand("rebase", "-q", pr.BaseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + if err := git.NewCommand("rebase", "-q", baseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { return fmt.Errorf("git rebase [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) } // Checkout base branch again - if err := git.NewCommand("checkout", pr.BaseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + if err := git.NewCommand("checkout", baseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { return fmt.Errorf("git checkout: %s", errbuf.String()) } // Merge fast forward @@ -180,11 +210,11 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor return fmt.Errorf("git checkout: %s", errbuf.String()) } // Rebase before merging - if err := git.NewCommand("rebase", "-q", pr.BaseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + if err := git.NewCommand("rebase", "-q", baseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { return fmt.Errorf("git rebase [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) } // Checkout base branch again - if err := git.NewCommand("checkout", pr.BaseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { + if err := git.NewCommand("checkout", baseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { return fmt.Errorf("git checkout: %s", errbuf.String()) } // Prepare merge with commit @@ -216,7 +246,7 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor if err != nil { return fmt.Errorf("Failed to get full commit id for HEAD: %v", err) } - mergeBaseSHA, err := git.GetFullCommitID(tmpBasePath, "origin/"+pr.BaseBranch) + mergeBaseSHA, err := git.GetFullCommitID(tmpBasePath, "original_"+baseBranch) if err != nil { return fmt.Errorf("Failed to get full commit id for origin/%s: %v", pr.BaseBranch, err) } @@ -249,7 +279,7 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor ) // Push back to upstream. - if err := git.NewCommand("push", "origin", pr.BaseBranch).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, nil, &errbuf); err != nil { + if err := git.NewCommand("push", "origin", baseBranch+":"+pr.BaseBranch).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, nil, &errbuf); err != nil { return fmt.Errorf("git push: %s", errbuf.String()) } From f1fdd782d57ddbd2a759dad2843ee619709a4609 Mon Sep 17 00:00:00 2001 From: guillep2k <18600385+guillep2k@users.noreply.github.com> Date: Sat, 12 Oct 2019 01:55:07 -0300 Subject: [PATCH 066/173] Add check for empty set when dropping indexes during migration (#8471) * Add check for empty set when dropping indexes during migration --- models/migrations/migrations.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 1f5b918de854e..e14437a04b351 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -404,9 +404,11 @@ func dropTableColumns(sess *xorm.Session, tableName string, columnNames ...strin } for _, index := range res { indexName := index["column_name"] - _, err := sess.Exec(fmt.Sprintf("DROP INDEX `%s` ON `%s`", indexName, tableName)) - if err != nil { - return err + if len(indexName) > 0 { + _, err := sess.Exec(fmt.Sprintf("DROP INDEX `%s` ON `%s`", indexName, tableName)) + if err != nil { + return err + } } } From 0a96e59884ca5c4fedc8c3d166d97f35b245ad6e Mon Sep 17 00:00:00 2001 From: zeripath Date: Sat, 12 Oct 2019 16:45:00 +0100 Subject: [PATCH 067/173] Fix #8453 by making openssh listen on SSH_LISTEN_PORT not SSH_PORT (#8477) --- docker/root/etc/s6/openssh/setup | 1 + docker/root/etc/templates/sshd_config | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docker/root/etc/s6/openssh/setup b/docker/root/etc/s6/openssh/setup index 10d195b74f70d..2a5eb9b09f0a9 100755 --- a/docker/root/etc/s6/openssh/setup +++ b/docker/root/etc/s6/openssh/setup @@ -26,6 +26,7 @@ fi if [ -d /etc/ssh ]; then SSH_PORT=${SSH_PORT:-"22"} \ + SSH_LISTEN_PORT=${SSH_LISTEN_PORT:-"${SSH_PORT}"} \ envsubst < /etc/templates/sshd_config > /etc/ssh/sshd_config chmod 0644 /etc/ssh/sshd_config diff --git a/docker/root/etc/templates/sshd_config b/docker/root/etc/templates/sshd_config index bf0b936d7c099..20e0b36012c91 100644 --- a/docker/root/etc/templates/sshd_config +++ b/docker/root/etc/templates/sshd_config @@ -1,4 +1,4 @@ -Port ${SSH_PORT} +Port ${SSH_LISTEN_PORT} Protocol 2 AddressFamily any @@ -30,4 +30,4 @@ AllowUsers ${USER} Banner none Subsystem sftp /usr/lib/ssh/sftp-server -AcceptEnv GIT_PROTOCOL \ No newline at end of file +AcceptEnv GIT_PROTOCOL From f2a3abc683ad4b2177b7c7c6160a2c0b4316120a Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 13 Oct 2019 21:23:14 +0800 Subject: [PATCH 068/173] Move migrating repository from frontend to backend (#6200) * move migrating to backend * add loading image when migrating and fix tests * fix format * fix lint * add redis task queue support and improve docs * add redis vendor * fix vet * add database migrations and fix app.ini sample * add comments for task section on app.ini.sample * Update models/migrations/v84.go Co-Authored-By: lunny * Update models/repo.go Co-Authored-By: lunny * move migrating to backend * add loading image when migrating and fix tests * fix fmt * add redis task queue support and improve docs * fix fixtures * fix fixtures * fix duplicate function on index.js * fix tests * rename repository statuses * check if repository is being create when SSH request * fix lint * fix template * some improvements * fix template * unified migrate options * fix lint * fix loading page * refactor * When gitea restart, don't restart the running tasks because we may have servel gitea instances, that may break the migration * fix js * Update models/repo.go Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Update docs/content/doc/advanced/config-cheat-sheet.en-us.md Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * fix tests * rename ErrTaskIsNotExist to ErrTaskDoesNotExist * delete release after add one on tests to make it run happy * fix tests * fix tests * improve codes * fix lint * fix lint * fix migrations --- .gitignore | 1 + custom/conf/app.ini.sample | 9 + .../doc/advanced/config-cheat-sheet.en-us.md | 7 + .../doc/advanced/config-cheat-sheet.zh-cn.md | 7 + models/fixtures/repository.yml | 43 +++- models/migrations/migrations.go | 2 + models/migrations/v99.go | 34 +++ models/models.go | 1 + models/repo.go | 83 +++--- models/task.go | 240 ++++++++++++++++++ modules/context/repo.go | 35 +-- modules/migrations/base/options.go | 21 +- modules/migrations/gitea.go | 36 ++- modules/migrations/gitea_test.go | 7 +- modules/migrations/github.go | 4 +- modules/migrations/migrate.go | 12 +- modules/setting/setting.go | 1 + modules/setting/task.go | 25 ++ modules/structs/repo.go | 16 +- modules/structs/task.go | 34 +++ modules/task/migrate.go | 120 +++++++++ modules/task/queue.go | 14 + modules/task/queue_channel.go | 48 ++++ modules/task/queue_redis.go | 130 ++++++++++ modules/task/task.go | 66 +++++ options/locale/locale_en-US.ini | 2 + public/img/loading.png | Bin 0 -> 18713 bytes public/js/index.js | 36 +++ routers/api/v1/repo/repo.go | 4 +- routers/init.go | 4 + routers/private/serv.go | 9 + routers/repo/repo.go | 103 +++++--- routers/repo/view.go | 30 +++ routers/routes/routes.go | 2 + services/mirror/mirror_test.go | 29 ++- templates/repo/header.tmpl | 144 +++++------ templates/repo/migrating.tmpl | 31 +++ 37 files changed, 1180 insertions(+), 210 deletions(-) create mode 100644 models/migrations/v99.go create mode 100644 models/task.go create mode 100644 modules/setting/task.go create mode 100644 modules/structs/task.go create mode 100644 modules/task/migrate.go create mode 100644 modules/task/queue.go create mode 100644 modules/task/queue_channel.go create mode 100644 modules/task/queue_redis.go create mode 100644 modules/task/task.go create mode 100644 public/img/loading.png create mode 100644 templates/repo/migrating.tmpl diff --git a/.gitignore b/.gitignore index fa6cbb454b5cf..773b4726c0aec 100644 --- a/.gitignore +++ b/.gitignore @@ -77,3 +77,4 @@ prime/ *.snap *.snap-build *_source.tar.bz2 +.DS_Store \ No newline at end of file diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index 9bfddc97e8f25..dd14089d2b06d 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -808,3 +808,12 @@ IS_INPUT_FILE = false ENABLED = false ; If you want to add authorization, specify a token here TOKEN = + +[task] +; Task queue type, could be `channel` or `redis`. +QUEUE_TYPE = channel +; Task queue length, available only when `QUEUE_TYPE` is `channel`. +QUEUE_LENGTH = 1000 +; Task queue connction string, available only when `QUEUE_TYPE` is `redis`. +; If there is a password of redis, use `addrs=127.0.0.1:6379 password=123 db=0`. +QUEUE_CONN_STR = "addrs=127.0.0.1:6379 db=0" \ No newline at end of file diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 198cff6f04948..ed34be032bbda 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -514,9 +514,16 @@ Two special environment variables are passed to the render command: - `GITEA_PREFIX_RAW`, which contains the current URL prefix in the `raw` path tree. To be used as prefix for image paths. ## Time (`time`) + - `FORMAT`: Time format to diplay on UI. i.e. RFC1123 or 2006-01-02 15:04:05 - `DEFAULT_UI_LOCATION`: Default location of time on the UI, so that we can display correct user's time on UI. i.e. Shanghai/Asia +## Task (`task`) + +- `QUEUE_TYPE`: **channel**: Task queue type, could be `channel` or `redis`. +- `QUEUE_LENGTH`: **1000**: Task queue length, available only when `QUEUE_TYPE` is `channel`. +- `QUEUE_CONN_STR`: **addrs=127.0.0.1:6379 db=0**: Task queue connection string, available only when `QUEUE_TYPE` is `redis`. If there redis needs a password, use `addrs=127.0.0.1:6379 password=123 db=0`. + ## Other (`other`) - `SHOW_FOOTER_BRANDING`: **false**: Show Gitea branding in the footer. diff --git a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md index 541d66f4e9b62..01ba821a47a38 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md +++ b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md @@ -241,9 +241,16 @@ IS_INPUT_FILE = false - IS_INPUT_FILE: 输入方式是最后一个参数为文件路径还是从标准输入读取。 ## Time (`time`) + - `FORMAT`: 显示在界面上的时间格式。比如: RFC1123 或者 2006-01-02 15:04:05 - `DEFAULT_UI_LOCATION`: 默认显示在界面上的时区,默认为本地时区。比如: Asia/Shanghai +## Task (`task`) + +- `QUEUE_TYPE`: **channel**: 任务队列类型,可以为 `channel` 或 `redis`。 +- `QUEUE_LENGTH`: **1000**: 任务队列长度,当 `QUEUE_TYPE` 为 `channel` 时有效。 +- `QUEUE_CONN_STR`: **addrs=127.0.0.1:6379 db=0**: 任务队列连接字符串,当 `QUEUE_TYPE` 为 `redis` 时有效。如果redis有密码,则可以 `addrs=127.0.0.1:6379 password=123 db=0`。 + ## Other (`other`) - `SHOW_FOOTER_BRANDING`: 为真则在页面底部显示Gitea的字样。 diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml index 2e38c5e1dd6ea..cf7d24c6cdb3c 100644 --- a/models/fixtures/repository.yml +++ b/models/fixtures/repository.yml @@ -11,6 +11,7 @@ num_milestones: 3 num_closed_milestones: 1 num_watches: 3 + status: 0 - id: 2 @@ -24,6 +25,7 @@ num_closed_pulls: 0 num_stars: 1 close_issues_via_commit_in_any_branch: true + status: 0 - id: 3 @@ -36,6 +38,7 @@ num_pulls: 0 num_closed_pulls: 0 num_watches: 0 + status: 0 - id: 4 @@ -48,6 +51,7 @@ num_pulls: 0 num_closed_pulls: 0 num_stars: 1 + status: 0 - id: 5 @@ -61,6 +65,7 @@ num_closed_pulls: 0 num_watches: 0 is_mirror: true + status: 0 - id: 6 @@ -73,6 +78,7 @@ num_pulls: 0 num_closed_pulls: 0 is_mirror: false + status: 0 - id: 7 @@ -85,6 +91,7 @@ num_pulls: 0 num_closed_pulls: 0 is_mirror: false + status: 0 - id: 8 @@ -97,6 +104,7 @@ num_pulls: 0 num_closed_pulls: 0 is_mirror: false + status: 0 - id: 9 @@ -109,6 +117,7 @@ num_pulls: 0 num_closed_pulls: 0 is_mirror: false + status: 0 - id: 10 @@ -122,6 +131,7 @@ num_closed_pulls: 0 is_mirror: false num_forks: 1 + status: 0 - id: 11 @@ -135,6 +145,7 @@ num_pulls: 0 num_closed_pulls: 0 is_mirror: false + status: 0 - id: 12 @@ -147,6 +158,7 @@ num_pulls: 0 num_closed_pulls: 0 is_mirror: false + status: 0 - id: 13 @@ -159,6 +171,7 @@ num_pulls: 0 num_closed_pulls: 0 is_mirror: false + status: 0 - id: 14 @@ -172,6 +185,7 @@ num_pulls: 0 num_closed_pulls: 0 is_mirror: false + status: 0 - id: 15 @@ -179,6 +193,7 @@ lower_name: repo15 name: repo15 is_empty: true + status: 0 - id: 16 @@ -191,6 +206,7 @@ num_pulls: 0 num_closed_pulls: 0 num_watches: 0 + status: 0 - id: 17 @@ -205,6 +221,7 @@ num_watches: 0 is_mirror: false is_fork: false + status: 0 - id: 18 @@ -218,6 +235,7 @@ num_closed_pulls: 0 is_mirror: false is_fork: false + status: 0 - id: 19 @@ -231,6 +249,7 @@ num_closed_pulls: 0 is_mirror: false is_fork: false + status: 0 - id: 20 @@ -244,6 +263,7 @@ num_closed_pulls: 0 is_mirror: false is_fork: false + status: 0 - id: 21 @@ -257,6 +277,7 @@ num_closed_pulls: 0 is_mirror: false is_fork: false + status: 0 - id: 22 @@ -270,6 +291,7 @@ num_closed_pulls: 0 is_mirror: false is_fork: false + status: 0 - id: 23 @@ -283,6 +305,7 @@ num_closed_pulls: 0 is_mirror: false is_fork: false + status: 0 - id: 24 @@ -296,6 +319,7 @@ num_closed_pulls: 0 is_mirror: false is_fork: false + status: 0 - id: 25 @@ -310,6 +334,7 @@ num_watches: 0 is_mirror: true is_fork: false + status: 0 - id: 26 @@ -324,6 +349,7 @@ num_watches: 0 is_mirror: true is_fork: false + status: 0 - id: 27 @@ -339,6 +365,7 @@ is_mirror: true num_forks: 1 is_fork: false + status: 0 - id: 28 @@ -354,6 +381,7 @@ is_mirror: true num_forks: 1 is_fork: false + status: 0 - id: 29 @@ -368,6 +396,7 @@ num_closed_pulls: 0 is_mirror: false is_fork: true + status: 0 - id: 30 @@ -382,6 +411,7 @@ num_closed_pulls: 0 is_mirror: false is_fork: true + status: 0 - id: 31 @@ -392,6 +422,7 @@ num_forks: 0 num_issues: 0 is_mirror: false + status: 0 - id: 32 # org public repo @@ -403,6 +434,7 @@ num_forks: 0 num_issues: 0 is_mirror: false + status: 0 - id: 33 @@ -410,6 +442,7 @@ lower_name: utf8 name: utf8 is_private: false + status: 0 - id: 34 @@ -421,6 +454,7 @@ num_forks: 0 num_issues: 0 is_mirror: false + status: 0 - id: 35 @@ -432,6 +466,7 @@ num_forks: 0 num_issues: 0 is_mirror: false + status: 0 - id: 36 @@ -443,6 +478,7 @@ num_forks: 0 num_issues: 0 is_mirror: false + status: 0 - id: 37 @@ -454,6 +490,7 @@ num_forks: 0 num_issues: 0 is_mirror: false + status: 0 - id: 38 @@ -465,6 +502,7 @@ num_forks: 0 num_issues: 0 is_mirror: false + status: 0 - id: 39 @@ -476,6 +514,7 @@ num_forks: 0 num_issues: 0 is_mirror: false + status: 0 - id: 40 @@ -487,6 +526,7 @@ num_forks: 0 num_issues: 0 is_mirror: false + status: 0 - id: 41 @@ -519,4 +559,5 @@ num_stars: 0 num_forks: 0 num_issues: 0 - is_mirror: false \ No newline at end of file + is_mirror: false + status: 0 diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index e14437a04b351..ef5cd377a6c11 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -252,6 +252,8 @@ var migrations = []Migration{ NewMigration("add repo_admin_change_team_access to user", addRepoAdminChangeTeamAccessColumnForUser), // v98 -> v99 NewMigration("add original author name and id on migrated release", addOriginalAuthorOnMigratedReleases), + // v99 -> v100 + NewMigration("add task table and status column for repository table", addTaskTable), } // Migrate database to current version diff --git a/models/migrations/v99.go b/models/migrations/v99.go new file mode 100644 index 0000000000000..3eb287af6c960 --- /dev/null +++ b/models/migrations/v99.go @@ -0,0 +1,34 @@ +// Copyright 2019 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 ( + "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/timeutil" + + "github.com/go-xorm/xorm" +) + +func addTaskTable(x *xorm.Engine) error { + type Task struct { + ID int64 + DoerID int64 `xorm:"index"` // operator + OwnerID int64 `xorm:"index"` // repo owner id, when creating, the repoID maybe zero + RepoID int64 `xorm:"index"` + Type structs.TaskType + Status structs.TaskStatus `xorm:"index"` + StartTime timeutil.TimeStamp + EndTime timeutil.TimeStamp + PayloadContent string `xorm:"TEXT"` + Errors string `xorm:"TEXT"` // if task failed, saved the error reason + Created timeutil.TimeStamp `xorm:"created"` + } + + type Repository struct { + Status int `xorm:"NOT NULL DEFAULT 0"` + } + + return x.Sync2(new(Task), new(Repository)) +} diff --git a/models/models.go b/models/models.go index e802a35a77709..ea550cb839fed 100644 --- a/models/models.go +++ b/models/models.go @@ -112,6 +112,7 @@ func init() { new(OAuth2Application), new(OAuth2AuthorizationCode), new(OAuth2Grant), + new(Task), ) gonicNames := []string{"SSL", "UID"} diff --git a/models/repo.go b/models/repo.go index 8db527477b03b..23b1c2ef52c4d 100644 --- a/models/repo.go +++ b/models/repo.go @@ -126,6 +126,15 @@ func NewRepoContext() { RemoveAllWithNotice("Clean up repository temporary data", filepath.Join(setting.AppDataPath, "tmp")) } +// RepositoryStatus defines the status of repository +type RepositoryStatus int + +// all kinds of RepositoryStatus +const ( + RepositoryReady RepositoryStatus = iota // a normal repository + RepositoryBeingMigrated // repository is migrating +) + // Repository represents a git repository. type Repository struct { ID int64 `xorm:"pk autoincr"` @@ -156,9 +165,9 @@ type Repository struct { IsPrivate bool `xorm:"INDEX"` IsEmpty bool `xorm:"INDEX"` IsArchived bool `xorm:"INDEX"` - - IsMirror bool `xorm:"INDEX"` - *Mirror `xorm:"-"` + IsMirror bool `xorm:"INDEX"` + *Mirror `xorm:"-"` + Status RepositoryStatus `xorm:"NOT NULL DEFAULT 0"` ExternalMetas map[string]string `xorm:"-"` Units []*RepoUnit `xorm:"-"` @@ -197,6 +206,16 @@ func (repo *Repository) ColorFormat(s fmt.State) { repo.Name) } +// IsBeingMigrated indicates that repository is being migtated +func (repo *Repository) IsBeingMigrated() bool { + return repo.Status == RepositoryBeingMigrated +} + +// IsBeingCreated indicates that repository is being migrated or forked +func (repo *Repository) IsBeingCreated() bool { + return repo.IsBeingMigrated() +} + // AfterLoad is invoked from XORM after setting the values of all fields of this object. func (repo *Repository) AfterLoad() { // FIXME: use models migration to solve all at once. @@ -884,18 +903,6 @@ func (repo *Repository) CloneLink() (cl *CloneLink) { return repo.cloneLink(x, false) } -// MigrateRepoOptions contains the repository migrate options -type MigrateRepoOptions struct { - Name string - Description string - OriginalURL string - IsPrivate bool - IsMirror bool - RemoteAddr string - Wiki bool // include wiki repository - SyncReleasesWithTags bool // sync releases from tags -} - /* GitHub, GitLab, Gogs: *.wiki.git BitBucket: *.git/wiki @@ -915,20 +922,28 @@ func wikiRemoteURL(remote string) string { return "" } -// MigrateRepository migrates an existing repository from other project hosting. -func MigrateRepository(doer, u *User, opts MigrateRepoOptions) (*Repository, error) { - repo, err := CreateRepository(doer, u, CreateRepoOptions{ - Name: opts.Name, - Description: opts.Description, - OriginalURL: opts.OriginalURL, - IsPrivate: opts.IsPrivate, - IsMirror: opts.IsMirror, - }) +// CheckCreateRepository check if could created a repository +func CheckCreateRepository(doer, u *User, name string) error { + if !doer.CanCreateRepo() { + return ErrReachLimitOfRepo{u.MaxRepoCreation} + } + + if err := IsUsableRepoName(name); err != nil { + return err + } + + has, err := isRepositoryExist(x, u, name) if err != nil { - return nil, err + return fmt.Errorf("IsRepositoryExist: %v", err) + } else if has { + return ErrRepoAlreadyExist{u.Name, name} } + return nil +} - repoPath := RepoPath(u.Name, opts.Name) +// MigrateRepositoryGitData starts migrating git related data after created migrating repository +func MigrateRepositoryGitData(doer, u *User, repo *Repository, opts api.MigrateRepoOption) (*Repository, error) { + repoPath := RepoPath(u.Name, opts.RepoName) if u.IsOrganization() { t, err := u.GetOwnerTeam() @@ -942,11 +957,12 @@ func MigrateRepository(doer, u *User, opts MigrateRepoOptions) (*Repository, err migrateTimeout := time.Duration(setting.Git.Timeout.Migrate) * time.Second - if err := os.RemoveAll(repoPath); err != nil { + var err error + if err = os.RemoveAll(repoPath); err != nil { return repo, fmt.Errorf("Failed to remove %s: %v", repoPath, err) } - if err = git.Clone(opts.RemoteAddr, repoPath, git.CloneRepoOptions{ + if err = git.Clone(opts.CloneAddr, repoPath, git.CloneRepoOptions{ Mirror: true, Quiet: true, Timeout: migrateTimeout, @@ -955,8 +971,8 @@ func MigrateRepository(doer, u *User, opts MigrateRepoOptions) (*Repository, err } if opts.Wiki { - wikiPath := WikiPath(u.Name, opts.Name) - wikiRemotePath := wikiRemoteURL(opts.RemoteAddr) + wikiPath := WikiPath(u.Name, opts.RepoName) + wikiRemotePath := wikiRemoteURL(opts.CloneAddr) if len(wikiRemotePath) > 0 { if err := os.RemoveAll(wikiPath); err != nil { return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err) @@ -986,7 +1002,7 @@ func MigrateRepository(doer, u *User, opts MigrateRepoOptions) (*Repository, err return repo, fmt.Errorf("git.IsEmpty: %v", err) } - if opts.SyncReleasesWithTags && !repo.IsEmpty { + if !opts.Releases && !repo.IsEmpty { // Try to get HEAD branch and set it as default branch. headBranch, err := gitRepo.GetHEADBranch() if err != nil { @@ -1005,7 +1021,7 @@ func MigrateRepository(doer, u *User, opts MigrateRepoOptions) (*Repository, err log.Error("Failed to update size for repository: %v", err) } - if opts.IsMirror { + if opts.Mirror { if _, err = x.InsertOne(&Mirror{ RepoID: repo.ID, Interval: setting.Mirror.DefaultInterval, @@ -1143,6 +1159,7 @@ type CreateRepoOptions struct { IsPrivate bool IsMirror bool AutoInit bool + Status RepositoryStatus } func getRepoInitFile(tp, name string) ([]byte, error) { @@ -1410,6 +1427,7 @@ func CreateRepository(doer, u *User, opts CreateRepoOptions) (_ *Repository, err IsPrivate: opts.IsPrivate, IsFsckEnabled: !opts.IsMirror, CloseIssuesViaCommitInAnyBranch: setting.Repository.DefaultCloseIssuesViaCommitsInAnyBranch, + Status: opts.Status, } sess := x.NewSession() @@ -1856,6 +1874,7 @@ func DeleteRepository(doer *User, uid, repoID int64) error { &CommitStatus{RepoID: repoID}, &RepoIndexerStatus{RepoID: repoID}, &Comment{RefRepoID: repoID}, + &Task{RepoID: repoID}, ); err != nil { return fmt.Errorf("deleteBeans: %v", err) } diff --git a/models/task.go b/models/task.go new file mode 100644 index 0000000000000..cb878d387c12b --- /dev/null +++ b/models/task.go @@ -0,0 +1,240 @@ +// Copyright 2019 Gitea. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package models + +import ( + "encoding/json" + "fmt" + + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/migrations/base" + "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/timeutil" + + "xorm.io/builder" +) + +// Task represents a task +type Task struct { + ID int64 + DoerID int64 `xorm:"index"` // operator + Doer *User `xorm:"-"` + OwnerID int64 `xorm:"index"` // repo owner id, when creating, the repoID maybe zero + Owner *User `xorm:"-"` + RepoID int64 `xorm:"index"` + Repo *Repository `xorm:"-"` + Type structs.TaskType + Status structs.TaskStatus `xorm:"index"` + StartTime timeutil.TimeStamp + EndTime timeutil.TimeStamp + PayloadContent string `xorm:"TEXT"` + Errors string `xorm:"TEXT"` // if task failed, saved the error reason + Created timeutil.TimeStamp `xorm:"created"` +} + +// LoadRepo loads repository of the task +func (task *Task) LoadRepo() error { + return task.loadRepo(x) +} + +func (task *Task) loadRepo(e Engine) error { + if task.Repo != nil { + return nil + } + var repo Repository + has, err := e.ID(task.RepoID).Get(&repo) + if err != nil { + return err + } else if !has { + return ErrRepoNotExist{ + ID: task.RepoID, + } + } + task.Repo = &repo + return nil +} + +// LoadDoer loads do user +func (task *Task) LoadDoer() error { + if task.Doer != nil { + return nil + } + + var doer User + has, err := x.ID(task.DoerID).Get(&doer) + if err != nil { + return err + } else if !has { + return ErrUserNotExist{ + UID: task.DoerID, + } + } + task.Doer = &doer + + return nil +} + +// LoadOwner loads owner user +func (task *Task) LoadOwner() error { + if task.Owner != nil { + return nil + } + + var owner User + has, err := x.ID(task.OwnerID).Get(&owner) + if err != nil { + return err + } else if !has { + return ErrUserNotExist{ + UID: task.OwnerID, + } + } + task.Owner = &owner + + return nil +} + +// UpdateCols updates some columns +func (task *Task) UpdateCols(cols ...string) error { + _, err := x.ID(task.ID).Cols(cols...).Update(task) + return err +} + +// MigrateConfig returns task config when migrate repository +func (task *Task) MigrateConfig() (*structs.MigrateRepoOption, error) { + if task.Type == structs.TaskTypeMigrateRepo { + var opts structs.MigrateRepoOption + err := json.Unmarshal([]byte(task.PayloadContent), &opts) + if err != nil { + return nil, err + } + return &opts, nil + } + return nil, fmt.Errorf("Task type is %s, not Migrate Repo", task.Type.Name()) +} + +// ErrTaskDoesNotExist represents a "TaskDoesNotExist" kind of error. +type ErrTaskDoesNotExist struct { + ID int64 + RepoID int64 + Type structs.TaskType +} + +// IsErrTaskDoesNotExist checks if an error is a ErrTaskIsNotExist. +func IsErrTaskDoesNotExist(err error) bool { + _, ok := err.(ErrTaskDoesNotExist) + return ok +} + +func (err ErrTaskDoesNotExist) Error() string { + return fmt.Sprintf("task is not exist [id: %d, repo_id: %d, type: %d]", + err.ID, err.RepoID, err.Type) +} + +// GetMigratingTask returns the migrating task by repo's id +func GetMigratingTask(repoID int64) (*Task, error) { + var task = Task{ + RepoID: repoID, + Type: structs.TaskTypeMigrateRepo, + } + has, err := x.Get(&task) + if err != nil { + return nil, err + } else if !has { + return nil, ErrTaskDoesNotExist{0, repoID, task.Type} + } + return &task, nil +} + +// FindTaskOptions find all tasks +type FindTaskOptions struct { + Status int +} + +// ToConds generates conditions for database operation. +func (opts FindTaskOptions) ToConds() builder.Cond { + var cond = builder.NewCond() + if opts.Status >= 0 { + cond = cond.And(builder.Eq{"status": opts.Status}) + } + return cond +} + +// FindTasks find all tasks +func FindTasks(opts FindTaskOptions) ([]*Task, error) { + var tasks = make([]*Task, 0, 10) + err := x.Where(opts.ToConds()).Find(&tasks) + return tasks, err +} + +func createTask(e Engine, task *Task) error { + _, err := e.Insert(task) + return err +} + +// CreateMigrateTask creates a migrate task +func CreateMigrateTask(doer, u *User, opts base.MigrateOptions) (*Task, error) { + bs, err := json.Marshal(&opts) + if err != nil { + return nil, err + } + + var task = Task{ + DoerID: doer.ID, + OwnerID: u.ID, + Type: structs.TaskTypeMigrateRepo, + Status: structs.TaskStatusQueue, + PayloadContent: string(bs), + } + + if err := createTask(x, &task); err != nil { + return nil, err + } + + repo, err := CreateRepository(doer, u, CreateRepoOptions{ + Name: opts.RepoName, + Description: opts.Description, + OriginalURL: opts.CloneAddr, + IsPrivate: opts.Private, + IsMirror: opts.Mirror, + Status: RepositoryBeingMigrated, + }) + if err != nil { + task.EndTime = timeutil.TimeStampNow() + task.Status = structs.TaskStatusFailed + err2 := task.UpdateCols("end_time", "status") + if err2 != nil { + log.Error("UpdateCols Failed: %v", err2.Error()) + } + return nil, err + } + + task.RepoID = repo.ID + if err = task.UpdateCols("repo_id"); err != nil { + return nil, err + } + + return &task, nil +} + +// FinishMigrateTask updates database when migrate task finished +func FinishMigrateTask(task *Task) error { + task.Status = structs.TaskStatusFinished + task.EndTime = timeutil.TimeStampNow() + sess := x.NewSession() + defer sess.Close() + if err := sess.Begin(); err != nil { + return err + } + if _, err := sess.ID(task.ID).Cols("status", "end_time").Update(task); err != nil { + return err + } + task.Repo.Status = RepositoryReady + if _, err := sess.ID(task.RepoID).Cols("status").Update(task.Repo); err != nil { + return err + } + + return sess.Commit() +} diff --git a/modules/context/repo.go b/modules/context/repo.go index 3caf583f836a3..f4af19a0e835d 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -146,6 +146,9 @@ func (r *Repository) FileExists(path string, branch string) (bool, error) { // GetEditorconfig returns the .editorconfig definition if found in the // HEAD of the default repo branch. func (r *Repository) GetEditorconfig() (*editorconfig.Editorconfig, error) { + if r.GitRepo == nil { + return nil, nil + } commit, err := r.GitRepo.GetBranchCommit(r.Repository.DefaultBranch) if err != nil { return nil, err @@ -358,12 +361,6 @@ func RepoAssignment() macaron.Handler { return } - gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName)) - if err != nil { - ctx.ServerError("RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err) - return - } - ctx.Repo.GitRepo = gitRepo ctx.Repo.RepoLink = repo.Link() ctx.Data["RepoLink"] = ctx.Repo.RepoLink ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name @@ -373,13 +370,6 @@ func RepoAssignment() macaron.Handler { ctx.Data["RepoExternalIssuesLink"] = unit.ExternalTrackerConfig().ExternalTrackerURL } - tags, err := ctx.Repo.GitRepo.GetTags() - if err != nil { - ctx.ServerError("GetTags", err) - return - } - ctx.Data["Tags"] = tags - count, err := models.GetReleaseCountByRepoID(ctx.Repo.Repository.ID, models.FindReleasesOptions{ IncludeDrafts: false, IncludeTags: true, @@ -425,12 +415,25 @@ func RepoAssignment() macaron.Handler { } // repo is empty and display enable - if ctx.Repo.Repository.IsEmpty { + if ctx.Repo.Repository.IsEmpty || ctx.Repo.Repository.IsBeingCreated() { ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch return } - ctx.Data["TagName"] = ctx.Repo.TagName + gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName)) + if err != nil { + ctx.ServerError("RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err) + return + } + ctx.Repo.GitRepo = gitRepo + + tags, err := ctx.Repo.GitRepo.GetTags() + if err != nil { + ctx.ServerError("GetTags", err) + return + } + ctx.Data["Tags"] = tags + brs, err := ctx.Repo.GitRepo.GetBranches() if err != nil { ctx.ServerError("GetBranches", err) @@ -439,6 +442,8 @@ func RepoAssignment() macaron.Handler { ctx.Data["Branches"] = brs ctx.Data["BranchesCount"] = len(brs) + ctx.Data["TagName"] = ctx.Repo.TagName + // If not branch selected, try default one. // If default branch doesn't exists, fall back to some other branch. if len(ctx.Repo.BranchName) == 0 { diff --git a/modules/migrations/base/options.go b/modules/migrations/base/options.go index ba7fdc68156ac..2d180b61d955a 100644 --- a/modules/migrations/base/options.go +++ b/modules/migrations/base/options.go @@ -5,22 +5,7 @@ package base -// MigrateOptions defines the way a repository gets migrated -type MigrateOptions struct { - RemoteURL string - AuthUsername string - AuthPassword string - Name string - Description string - OriginalURL string +import "code.gitea.io/gitea/modules/structs" - Wiki bool - Issues bool - Milestones bool - Labels bool - Releases bool - Comments bool - PullRequests bool - Private bool - Mirror bool -} +// MigrateOptions defines the way a repository gets migrated +type MigrateOptions = structs.MigrateRepoOption diff --git a/modules/migrations/gitea.go b/modules/migrations/gitea.go index 1edac47a6eceb..ab3b0b9f694ad 100644 --- a/modules/migrations/gitea.go +++ b/modules/migrations/gitea.go @@ -22,6 +22,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/migrations/base" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" gouuid "github.com/satori/go.uuid" @@ -90,16 +91,33 @@ func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, opts base.Migrate remoteAddr = u.String() } - r, err := models.MigrateRepository(g.doer, owner, models.MigrateRepoOptions{ - Name: g.repoName, - Description: repo.Description, - OriginalURL: repo.OriginalURL, - IsMirror: repo.IsMirror, - RemoteAddr: remoteAddr, - IsPrivate: repo.IsPrivate, - Wiki: opts.Wiki, - SyncReleasesWithTags: !opts.Releases, // if didn't get releases, then sync them from tags + var r *models.Repository + if opts.MigrateToRepoID <= 0 { + r, err = models.CreateRepository(g.doer, owner, models.CreateRepoOptions{ + Name: g.repoName, + Description: repo.Description, + OriginalURL: repo.OriginalURL, + IsPrivate: opts.Private, + IsMirror: opts.Mirror, + Status: models.RepositoryBeingMigrated, + }) + } else { + r, err = models.GetRepositoryByID(opts.MigrateToRepoID) + } + if err != nil { + return err + } + + r, err = models.MigrateRepositoryGitData(g.doer, owner, r, structs.MigrateRepoOption{ + RepoName: g.repoName, + Description: repo.Description, + Mirror: repo.IsMirror, + CloneAddr: remoteAddr, + Private: repo.IsPrivate, + Wiki: opts.Wiki, + Releases: opts.Releases, // if didn't get releases, then sync them from tags }) + g.repo = r if err != nil { return err diff --git a/modules/migrations/gitea_test.go b/modules/migrations/gitea_test.go index 88a3a6d2189dc..73c119a15de74 100644 --- a/modules/migrations/gitea_test.go +++ b/modules/migrations/gitea_test.go @@ -10,6 +10,7 @@ import ( "time" "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" @@ -29,9 +30,9 @@ func TestGiteaUploadRepo(t *testing.T) { uploader = NewGiteaLocalUploader(user, user.Name, repoName) ) - err := migrateRepository(downloader, uploader, MigrateOptions{ - RemoteURL: "https://github.com/go-xorm/builder", - Name: repoName, + err := migrateRepository(downloader, uploader, structs.MigrateRepoOption{ + CloneAddr: "https://github.com/go-xorm/builder", + RepoName: repoName, AuthUsername: "", Wiki: true, diff --git a/modules/migrations/github.go b/modules/migrations/github.go index 754f98941c174..1c5d96c03d471 100644 --- a/modules/migrations/github.go +++ b/modules/migrations/github.go @@ -34,7 +34,7 @@ type GithubDownloaderV3Factory struct { // Match returns ture if the migration remote URL matched this downloader factory func (f *GithubDownloaderV3Factory) Match(opts base.MigrateOptions) (bool, error) { - u, err := url.Parse(opts.RemoteURL) + u, err := url.Parse(opts.CloneAddr) if err != nil { return false, err } @@ -44,7 +44,7 @@ func (f *GithubDownloaderV3Factory) Match(opts base.MigrateOptions) (bool, error // New returns a Downloader related to this factory according MigrateOptions func (f *GithubDownloaderV3Factory) New(opts base.MigrateOptions) (base.Downloader, error) { - u, err := url.Parse(opts.RemoteURL) + u, err := url.Parse(opts.CloneAddr) if err != nil { return nil, err } diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go index 27782cb94034e..3f5c0d1118c32 100644 --- a/modules/migrations/migrate.go +++ b/modules/migrations/migrate.go @@ -6,6 +6,8 @@ package migrations import ( + "fmt" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/migrations/base" @@ -27,7 +29,7 @@ func RegisterDownloaderFactory(factory base.DownloaderFactory) { func MigrateRepository(doer *models.User, ownerName string, opts base.MigrateOptions) (*models.Repository, error) { var ( downloader base.Downloader - uploader = NewGiteaLocalUploader(doer, ownerName, opts.Name) + uploader = NewGiteaLocalUploader(doer, ownerName, opts.RepoName) ) for _, factory := range factories { @@ -50,14 +52,18 @@ func MigrateRepository(doer *models.User, ownerName string, opts base.MigrateOpt opts.Comments = false opts.Issues = false opts.PullRequests = false - downloader = NewPlainGitDownloader(ownerName, opts.Name, opts.RemoteURL) - log.Trace("Will migrate from git: %s", opts.RemoteURL) + downloader = NewPlainGitDownloader(ownerName, opts.RepoName, opts.CloneAddr) + log.Trace("Will migrate from git: %s", opts.CloneAddr) } if err := migrateRepository(downloader, uploader, opts); err != nil { if err1 := uploader.Rollback(); err1 != nil { log.Error("rollback failed: %v", err1) } + + if err2 := models.CreateRepositoryNotice(fmt.Sprintf("Migrate repository from %s failed: %v", opts.CloneAddr, err)); err2 != nil { + log.Error("create respotiry notice failed: ", err2) + } return nil, err } diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 5e476854b2295..8c61bdbb7719d 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -1043,4 +1043,5 @@ func NewServices() { newNotifyMailService() newWebhookService() newIndexerService() + newTaskService() } diff --git a/modules/setting/task.go b/modules/setting/task.go new file mode 100644 index 0000000000000..97704d4a4da68 --- /dev/null +++ b/modules/setting/task.go @@ -0,0 +1,25 @@ +// Copyright 2019 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 setting + +var ( + // Task settings + Task = struct { + QueueType string + QueueLength int + QueueConnStr string + }{ + QueueType: ChannelQueueType, + QueueLength: 1000, + QueueConnStr: "addrs=127.0.0.1:6379 db=0", + } +) + +func newTaskService() { + sec := Cfg.Section("task") + Task.QueueType = sec.Key("QUEUE_TYPE").MustString(ChannelQueueType) + Task.QueueLength = sec.Key("QUEUE_LENGTH").MustInt(1000) + Task.QueueConnStr = sec.Key("QUEUE_CONN_STR").MustString("addrs=127.0.0.1:6379 db=0") +} diff --git a/modules/structs/repo.go b/modules/structs/repo.go index 87396d6ce99a9..57f1768a0b943 100644 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -162,8 +162,16 @@ type MigrateRepoOption struct { // required: true UID int `json:"uid" binding:"Required"` // required: true - RepoName string `json:"repo_name" binding:"Required"` - Mirror bool `json:"mirror"` - Private bool `json:"private"` - Description string `json:"description"` + RepoName string `json:"repo_name" binding:"Required"` + Mirror bool `json:"mirror"` + Private bool `json:"private"` + Description string `json:"description"` + Wiki bool + Issues bool + Milestones bool + Labels bool + Releases bool + Comments bool + PullRequests bool + MigrateToRepoID int64 } diff --git a/modules/structs/task.go b/modules/structs/task.go new file mode 100644 index 0000000000000..e83d0437ceffc --- /dev/null +++ b/modules/structs/task.go @@ -0,0 +1,34 @@ +// Copyright 2019 Gitea. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package structs + +// TaskType defines task type +type TaskType int + +// all kinds of task types +const ( + TaskTypeMigrateRepo TaskType = iota // migrate repository from external or local disk +) + +// Name returns the task type name +func (taskType TaskType) Name() string { + switch taskType { + case TaskTypeMigrateRepo: + return "Migrate Repository" + } + return "" +} + +// TaskStatus defines task status +type TaskStatus int + +// enumerate all the kinds of task status +const ( + TaskStatusQueue TaskStatus = iota // 0 task is queue + TaskStatusRunning // 1 task is running + TaskStatusStopped // 2 task is stopped + TaskStatusFailed // 3 task is failed + TaskStatusFinished // 4 task is finished +) diff --git a/modules/task/migrate.go b/modules/task/migrate.go new file mode 100644 index 0000000000000..5d15a506d7932 --- /dev/null +++ b/modules/task/migrate.go @@ -0,0 +1,120 @@ +// Copyright 2019 Gitea. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package task + +import ( + "bytes" + "errors" + "fmt" + "strings" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/migrations" + "code.gitea.io/gitea/modules/notification" + "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" +) + +func handleCreateError(owner *models.User, err error, name string) error { + switch { + case models.IsErrReachLimitOfRepo(err): + return fmt.Errorf("You have already reached your limit of %d repositories", owner.MaxCreationLimit()) + case models.IsErrRepoAlreadyExist(err): + return errors.New("The repository name is already used") + case models.IsErrNameReserved(err): + return fmt.Errorf("The repository name '%s' is reserved", err.(models.ErrNameReserved).Name) + case models.IsErrNamePatternNotAllowed(err): + return fmt.Errorf("The pattern '%s' is not allowed in a repository name", err.(models.ErrNamePatternNotAllowed).Pattern) + default: + return err + } +} + +func runMigrateTask(t *models.Task) (err error) { + defer func() { + if e := recover(); e != nil { + var buf bytes.Buffer + fmt.Fprintf(&buf, "Handler crashed with error: %v", log.Stack(2)) + + err = errors.New(buf.String()) + } + + if err == nil { + err = models.FinishMigrateTask(t) + if err == nil { + notification.NotifyMigrateRepository(t.Doer, t.Owner, t.Repo) + return + } + + log.Error("FinishMigrateTask failed: %s", err.Error()) + } + + t.EndTime = timeutil.TimeStampNow() + t.Status = structs.TaskStatusFailed + t.Errors = err.Error() + if err := t.UpdateCols("status", "errors", "end_time"); err != nil { + log.Error("Task UpdateCols failed: %s", err.Error()) + } + + if t.Repo != nil { + if errDelete := models.DeleteRepository(t.Doer, t.OwnerID, t.Repo.ID); errDelete != nil { + log.Error("DeleteRepository: %v", errDelete) + } + } + }() + + if err := t.LoadRepo(); err != nil { + return err + } + + // if repository is ready, then just finsih the task + if t.Repo.Status == models.RepositoryReady { + return nil + } + + if err := t.LoadDoer(); err != nil { + return err + } + if err := t.LoadOwner(); err != nil { + return err + } + t.StartTime = timeutil.TimeStampNow() + t.Status = structs.TaskStatusRunning + if err := t.UpdateCols("start_time", "status"); err != nil { + return err + } + + var opts *structs.MigrateRepoOption + opts, err = t.MigrateConfig() + if err != nil { + return err + } + + opts.MigrateToRepoID = t.RepoID + repo, err := migrations.MigrateRepository(t.Doer, t.Owner.Name, *opts) + if err == nil { + notification.NotifyMigrateRepository(t.Doer, t.Owner, repo) + + log.Trace("Repository migrated [%d]: %s/%s", repo.ID, t.Owner.Name, repo.Name) + return nil + } + + if models.IsErrRepoAlreadyExist(err) { + return errors.New("The repository name is already used") + } + + // remoteAddr may contain credentials, so we sanitize it + err = util.URLSanitizedError(err, opts.CloneAddr) + if strings.Contains(err.Error(), "Authentication failed") || + strings.Contains(err.Error(), "could not read Username") { + return fmt.Errorf("Authentication failed: %v", err.Error()) + } else if strings.Contains(err.Error(), "fatal:") { + return fmt.Errorf("Migration failed: %v", err.Error()) + } + + return handleCreateError(t.Owner, err, "MigratePost") +} diff --git a/modules/task/queue.go b/modules/task/queue.go new file mode 100644 index 0000000000000..ddee0b3d46274 --- /dev/null +++ b/modules/task/queue.go @@ -0,0 +1,14 @@ +// Copyright 2019 Gitea. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package task + +import "code.gitea.io/gitea/models" + +// Queue defines an interface to run task queue +type Queue interface { + Run() error + Push(*models.Task) error + Stop() +} diff --git a/modules/task/queue_channel.go b/modules/task/queue_channel.go new file mode 100644 index 0000000000000..da541f47551f5 --- /dev/null +++ b/modules/task/queue_channel.go @@ -0,0 +1,48 @@ +// Copyright 2019 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 task + +import ( + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/log" +) + +var ( + _ Queue = &ChannelQueue{} +) + +// ChannelQueue implements +type ChannelQueue struct { + queue chan *models.Task +} + +// NewChannelQueue create a memory channel queue +func NewChannelQueue(queueLen int) *ChannelQueue { + return &ChannelQueue{ + queue: make(chan *models.Task, queueLen), + } +} + +// Run starts to run the queue +func (c *ChannelQueue) Run() error { + for task := range c.queue { + err := Run(task) + if err != nil { + log.Error("Run task failed: %s", err.Error()) + } + } + return nil +} + +// Push will push the task ID to queue +func (c *ChannelQueue) Push(task *models.Task) error { + c.queue <- task + return nil +} + +// Stop stop the queue +func (c *ChannelQueue) Stop() { + close(c.queue) +} diff --git a/modules/task/queue_redis.go b/modules/task/queue_redis.go new file mode 100644 index 0000000000000..127de0cdbf1d3 --- /dev/null +++ b/modules/task/queue_redis.go @@ -0,0 +1,130 @@ +// Copyright 2019 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 task + +import ( + "encoding/json" + "errors" + "strconv" + "strings" + "time" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/log" + + "github.com/go-redis/redis" +) + +var ( + _ Queue = &RedisQueue{} +) + +type redisClient interface { + RPush(key string, args ...interface{}) *redis.IntCmd + LPop(key string) *redis.StringCmd + Ping() *redis.StatusCmd +} + +// RedisQueue redis queue +type RedisQueue struct { + client redisClient + queueName string + closeChan chan bool +} + +func parseConnStr(connStr string) (addrs, password string, dbIdx int, err error) { + fields := strings.Fields(connStr) + for _, f := range fields { + items := strings.SplitN(f, "=", 2) + if len(items) < 2 { + continue + } + switch strings.ToLower(items[0]) { + case "addrs": + addrs = items[1] + case "password": + password = items[1] + case "db": + dbIdx, err = strconv.Atoi(items[1]) + if err != nil { + return + } + } + } + return +} + +// NewRedisQueue creates single redis or cluster redis queue +func NewRedisQueue(addrs string, password string, dbIdx int) (*RedisQueue, error) { + dbs := strings.Split(addrs, ",") + var queue = RedisQueue{ + queueName: "task_queue", + closeChan: make(chan bool), + } + if len(dbs) == 0 { + return nil, errors.New("no redis host found") + } else if len(dbs) == 1 { + queue.client = redis.NewClient(&redis.Options{ + Addr: strings.TrimSpace(dbs[0]), // use default Addr + Password: password, // no password set + DB: dbIdx, // use default DB + }) + } else { + // cluster will ignore db + queue.client = redis.NewClusterClient(&redis.ClusterOptions{ + Addrs: dbs, + Password: password, + }) + } + if err := queue.client.Ping().Err(); err != nil { + return nil, err + } + return &queue, nil +} + +// Run starts to run the queue +func (r *RedisQueue) Run() error { + for { + select { + case <-r.closeChan: + return nil + case <-time.After(time.Millisecond * 100): + } + + bs, err := r.client.LPop(r.queueName).Bytes() + if err != nil { + if err != redis.Nil { + log.Error("LPop failed: %v", err) + } + time.Sleep(time.Millisecond * 100) + continue + } + + var task models.Task + err = json.Unmarshal(bs, &task) + if err != nil { + log.Error("Unmarshal task failed: %s", err.Error()) + } else { + err = Run(&task) + if err != nil { + log.Error("Run task failed: %s", err.Error()) + } + } + } +} + +// Push implements Queue +func (r *RedisQueue) Push(task *models.Task) error { + bs, err := json.Marshal(task) + if err != nil { + return err + } + return r.client.RPush(r.queueName, bs).Err() +} + +// Stop stop the queue +func (r *RedisQueue) Stop() { + r.closeChan <- true +} diff --git a/modules/task/task.go b/modules/task/task.go new file mode 100644 index 0000000000000..64744afe7a4c7 --- /dev/null +++ b/modules/task/task.go @@ -0,0 +1,66 @@ +// Copyright 2019 Gitea. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package task + +import ( + "fmt" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/migrations/base" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/structs" +) + +// taskQueue is a global queue of tasks +var taskQueue Queue + +// Run a task +func Run(t *models.Task) error { + switch t.Type { + case structs.TaskTypeMigrateRepo: + return runMigrateTask(t) + default: + return fmt.Errorf("Unknow task type: %d", t.Type) + } +} + +// Init will start the service to get all unfinished tasks and run them +func Init() error { + switch setting.Task.QueueType { + case setting.ChannelQueueType: + taskQueue = NewChannelQueue(setting.Task.QueueLength) + case setting.RedisQueueType: + var err error + addrs, pass, idx, err := parseConnStr(setting.Task.QueueConnStr) + if err != nil { + return err + } + taskQueue, err = NewRedisQueue(addrs, pass, idx) + if err != nil { + return err + } + default: + return fmt.Errorf("Unsupported task queue type: %v", setting.Task.QueueType) + } + + go func() { + if err := taskQueue.Run(); err != nil { + log.Error("taskQueue.Run end failed: %v", err) + } + }() + + return nil +} + +// MigrateRepository add migration repository to task +func MigrateRepository(doer, u *models.User, opts base.MigrateOptions) error { + task, err := models.CreateMigrateTask(doer, u, opts) + if err != nil { + return err + } + + return taskQueue.Push(task) +} diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index ca09b6120d717..e6c5839a645c5 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -633,6 +633,8 @@ migrate.lfs_mirror_unsupported = Mirroring LFS objects is not supported - use 'g migrate.migrate_items_options = When migrating from github, input a username and migration options will be displayed. migrated_from = Migrated from %[2]s migrated_from_fake = Migrated From %[1]s +migrate.migrating = Migrating from %s ... +migrate.migrating_failed = Migrating from %s failed. mirror_from = mirror of forked_from = forked from diff --git a/public/img/loading.png b/public/img/loading.png new file mode 100644 index 0000000000000000000000000000000000000000..aac702cfd6d010abb22f4ebd8f011b606075ef62 GIT binary patch literal 18713 zcmZsCWl$VJ*EQ}A!3i2%7I$}8+%@RpE(sRgHRuA1ySoN=Sr)foA-H=81j3i+mHPg? zQ#I3f?%cUEbGo~x&Z*n6n(B(!7~~jmaB$elN^;t8aPYu?HVh5%-_fdn`ac)YEUk6_ z<3#$m!v)TO=KeKnnm}Fof30#Ri$|@lU4^nunVfbmFA&V3kiqCssp?v-VUWjXTp(mx zC<3YgT9?XdWOF)JYnv8|s)5-J3ng^&gp3P>&5Gr$%YmQ@4V6q5%TguPELOQRhPSu3 ze`(L}Pt0>j$F_U_o$@D&_9~oA_2E1C{O{XnytUPJ;Eu4FH2PP6Ns||Z+qv^M8h@T_ zoJ%c=4^GI;?QS=%C#%1l{ufIQ`frT>ng0#oKjXhQ`2XNmphfTxHQY>PIceR`-_O5q zB;^9|LM$n~_?SXlNwnHoP80OoY}#<=9)lacN7|qnVcBy5-u3^oDl@J9wJ1bLl7@tz7BN2m;Gg05wcOzYk8k^m7E$v7S~6a!Ogu%03&pZqBnwd9!uri9l!MTL zlsM?!1|)Pp23Mf2O&hJU2{(Uudj-gu?8Muh)x)w-T^%ujQ|bhjvsH;_>^D6}Pq2dd zr82CcS_FT0&$S`jqDm|}jl#R^uaf@J3`(Rr0BVi!WIzP;YTwJZ*-o3b#eJbHinbA(uqK*XDgJ;cfw zWVM|udK4Owkt?4E_Ew_*rEDZ7{PSiYB{GyHEkKd(Q3`I;kY3a!zB_J~$&Y@b4O-J`+Ip4Xz zl!ef&zqNd&2J>aphM1R+R1%$cg4}LVjBU@8Q7a z8^Ht{bdK8;BLo%tb?uE2VgRn!5QI}6gN!mUT8eO4;Wb)ae&1UC2Ttstbf=J14x&78 z$v82AJ28cEyRMg265!}l7YdPcmDQuqC4M6>^TByfugTI(7VB1I-w;{=$TjSkj@n<_c5-Me2q zT?r2X2h{wUgoq#r7nIx9u^*}M_!x}&aO+q>Uh^KwIueXuyX4JaGKJu2w(2cuANE-v)~ zgQ?9)ux&h*`Yjw|=ZVH(4_P51t)5AG?N3A|#z<7aI02A$+VbnRj4}6^h7f*MHV2fz zlz9NyKK1}YmGM{ZUpT8CjFo%%P7GRd|2$5^o@@ND9lDnFM~EU!N!Mjz38Or`|AN&J z<1yP<{2nWVj>MjmKOU zgZkjX?OP^yu$bZkY1;e6C5(#jfFuK7(Ed{QrN=^P*%bJq!EO0k=x&R)&qt=%{aki_ ziK1m0WC7VU7wYt}neQR7_~igq{7x;miuiN?I{qb*6}4ZCIY%jb0SprIV|YVU|Gxds zD*BPO8kd`KuhyYZIo5=qDLS&7oYclVW2{!vqQ3u!7@Ydy$dQi7(O83HGdHi5bCU=~GNw>+dS_jE+ni|80$d-t&#cLkRd=qZ5X8y|Pm}v&t^peC6 zVgH7T(Ya?xKzO3Iz+p~AGP-|0FN~UMy=@eh9btZ8WjJqc+cq#s|E+rsUJhmW>rxqS z>Q#mfgiCQRJ;3{A=8ZoNJBohr-#=RMm1X(tgxb$wF;@Ujj{D<>xe)EDXmi#@v*a-} z=a0_lIC#i^-`rUFTqM8H2a{D0$_ZtY_8p^nE2M)$Sh?Vg7mJ^KI;N z2pa=*H8Cn4o12tLDw_zUKJVL6*a@zOZ`-S|)+HU(%UT_S(NZTFD8~LlgJ+-usaWFr zsC!5(1~A+7wj~A>TV){R`als=6t2iA@gR-cR1Q$ZKRoN-aM{9o z_P<-`K^&@OLz`92EGYglBW=O(8BaF)3SoVBI8TNO$EmvX8E0)dYEn4|-Jyq)gEX!h zkasv-yVGkJ&0F;h!Em#191fVlLi_akI5L-)uqC&*8mRvIB0Nus$LP!lMSIasuQLr( zJKMJQ`nmXpG!Wt&niow1f@kf&#s01QK13YZT38_OiBEuBqg>owlEgkFj*=Xk&G-18 zd9naX#`=fPhR)2`E37SiJ*c0FYP}m#cgJ)BX=tg%Gd7w0j8*O6b;MpM|DN8uEn-p% zydaK9%4Ia0g{d$EqL<0iXKrI$&e6foDMb7ZAA9!X`2yxsU`^-DK&?EzmP3*)f$mIg zeMi59&jo8c)!xFrlfa23o*GJ^L}e1YJG(dL$wRGlhY#n`vmEneiCX8YDnKv&_XeGE z`KKvntI&QK_OB<_n!YdRR&5ZMtVYxYd$AgH5Aoq9>VruGtVNIf z;4C@OjQs{J1!BLIkoa{LE#>I?gkY>D5YXJD2s)5%WseU!Bx18d<$v-?eGrt(4g(A( zaQdF=zs`*eL2D8=Q7TLE`jLlpnMvUjifcw$-e4x+0IPq~JA~C*7sO>)#)eWN+V1Ij zimccc)n%KSZ1r^a-OxJ`X8yLdYGA>a4m25rdEoBmvk+?@FaXu1l$AeBj2x@i&Q+06 z;)@T$^m|BYLv7074|@nqjeEv zK0Vx2!9w#6I@qE|d2HDxG@@#jQ-=h>o8nk?kbLP^VK>TvGQVUMO0v$mIbX?3(nR_{ zwX=Mcc{=)Oj^Ssjc9xeye;+T8kh@=vY-U=dbTmZA8S2)B!=s0wvBtY!U{7KvgaqHA zFkE$Mfh(;G7jq_PW@mwyM8#wH$B6G`nsKM@m%f}>KfvO_oBG_7sBuF`m*cX9xGfXL z^y%+C9zJ}K{HexmdKhffI?R6I(XFG~zA-P;@#w)5BVl+)_$%gsx2|ew<2C9bm~d47 zZx%tGoZ;yZ#3$Wj^-UxnJD7h0t!XUkc-Xf<~`_=)Ge zf|gA(ppy9XeKOatjnfpNB_x^Lj@D`bf_59Ws5pRl*PXt+s$IwcN zNfOI;an2#qcs`1`u6H678VVjo9dZclU*^Z|bBH;Ae$EX@sRC3W_yU{|Bo{+YYB!Ie zq;fUVk;2FJhz$ywrC#Hl4=})xF6P?9V=uuXP6L@5_&RbUU$(c~J>Um6=B2mF(y{NS z>5P29Ol1k$1IIs-ka{rE6f(UmZ`n5qBv8@`hea56CU~WIJfpSjJUxaijCeD)^$w9q zO7cvb)^gfG+{Dx5rX>NJ9X%KEi-I29{gmRp^pXa9mpmsWN{qpq#<0*%kp^X%tdX3nD})Ji!xW5 zD}IHt^6E$ZqRPN;=1p6zpLuE1qGlZOxTM{|!shwuiLwK&3xAHOa%JrF#Tnz}n;V)n zaea-gzi0djLC&K+u_>n)+RQb-m=2P9WoAB(G5j%OyVSjT6xh%dyMyBVjnysKjOB@V z4y5syN7+qs!8c>oDeZn`xK+SZGJb0ZF1Ni*`04Qy#(`>y7gIb+^asx6zTxH$hO7M8 zFQJp8l(4cQH=UQ?7?uVPLP6kyNW1a=9jHK@?L$Z2?@#C=A9qQU91bilYe#RVZ$%cd z%5@YdK+Rk!hpUhws}+!!Jt!F|Z|sO8T3Ric5`Cs^JbNX*@n76n`O6tL+Vi3>p zeC6U}&%k5QULH1=EHBnh2jc9Rph$_9AYZ|04(P^KnI<0GhWcTH!P+Kjb{uW%ErBlK z#-`nbx;*~X^IJBiY3D#jf4Hvo@Sk<8Vb@uwFSdJ58&O3O4X&i^W;Mtk`~6?d1+ivk z3pSt};yQ@_WY=haIPbOA?|%@&XL_fDDb&eqM{AEGMBjBPnhAF|V}T9H=@02QFR)M& z72?%AEdHR(dhDCuj76RZMa6Jw%sTOthYwmz%>AxyVjoJgS;gc~GpKnAY+2{b`ZH=J zB3`@tZQZ%q1R>IVvWU_?d;d-k-Aw+s-Z{llyI2&P!efHqU8G6hcno+S>zRAC zZsY3N>(m%VKe@Qsi^|H#vd*K7aVQLiE4pIkwN|DRG|{Fs zyX92O`O8^`+1OKiJfQt@hQKRlj*x7?#(SQhx=D&p3s**5t#TC{ieU8Cc*|TR0ewp4 zj`MLpGckC_Ei(yqMNQAi4KQ3wAk=Ety6ISsJ?is#23d>yVGA^;MZYIqQBLvqGX5PC zd?*8?lc>YWP{yg>!W;`2V{7yKHkg(WWE+sJEh0DSrw?C-_TyRzbc6Jfe)_s8);_Z> zpOQP+ouP=K4CAj_Lh?s9_8c8;p`5nvQfT~~e8QXmf^pbK-=T#1(!a_#IbqSBi)PA3 z5nYKM56VDOt@${Kq8?{#I3ZgP^gPARTgGMUu>h3>%4uSFnuS_8-qB^Jd~0?05AvcD zCPzh-(?7?gK+D#wjZkj$dAzL&hb&T6KL}f+18WGGOI3ME4c5hicH*AtjcwB2Xr0<( zBV6jyEqLQJs|x`YFKGpCkb>P$E_Tlp8HyfC+zl1(2oxOeLI9IiG+Z(J)YX>th&KEc zGO(Q8|CG+yJ&~SykbHN_-Gq=v=3-BkcQobI<6Jo8Q9s0!+@ULLx9n=v7yZra1K@E< zh9??MOfspf>PvP_qunj08iP|-cXZDeuh6&BWZ%5lk`v+b$F*JF_e^34jWvOM8N=Ra zDX9sQPXR146&Y?hDi-fyfML&gF=1{H^$*P-LIzf|`;TeN(bcJzNuJy$eM`#evt3!PD`mN%QD?P@l6mr~Nh-a#PTfM<}mnUX=W z^_OGuyX_=pIHhsv4$qok*V46o2LzTcd`RWVuB(VVPlQn1PAK|MGNja@59-FuTpFP@ zz8?U%WFXYSIqeoLSAn^3ndzQlah+}W6XF!Q>F)5`J9IPV2qP_m78K2U>5lFs4A0in zhVOa=_=>hH~EgEHDd7Bb9vo-qshPE zAEBRF0A@5#6d;PN>5`0(_SOITaTJrEgM=5}sxSZ zqEN^;wnse9K>`jf@>TZbZIwhful@7qdd1)YHR<6Z^d6(vWESnbeUjwO+g`5uzD=0SrVGBWM`6Dg_p8e zO!fhMs249Z*Zjk*36%uY&Q(C_=pJWM@=ZbH(IUI$mU0e%K<*B=Pc-;>*0MUs%q;{u z+2iQ>yI=IN5N2b<_nto-{o7r@M+=eEFOFa0hA82<`U^}y!|8~tpXFL^Ux>Zj^sZmN zFF$Q@GEL8M^wkqIa@74K`*dhkK8I@XJ#@VSbw+Ao7+hsCe8GMv?cIsRAo!--kSV+v z{i+H6gIT1=N?*o`NMT+9Mb=0D__Je&eM zO59WRm>)eDVG#5^N<^aa{DW(ITn72h3OQY&^`#4*{vA`+P`>Y6?0_Ne&?L*Lj4;~~ zmUrrQfZf1*QLoiw)mdY^37Y_eJ|sv4H{A!FPP64~$?<~-_|_lSUl{9mJ2yoA7%=fU zwCTWKzS5|VG{+>Fhx)nT-nE`Jiw{~HdH`01%#We4~CMlfp+E^V66ri8{kqPRKJyEN5s;u25yqHu(Gg>4Sa^w%vo~MyL2|RFNNVmv(Vu4dSDt`f{2NH{ zTDi5Y{2&(y7F`kEJL!X=gPu9GPr=xD5-+!*3eqhO^dr09B$L}~P-?K*(AO-oIGvn< z1Inc*LoRqMPb`?HK3GWDXfuHRht|f)-7EgMlHMXCLVb7VSl_C(`hw;-&Q7EVMQCf- z6J8h`)0*pJbI^f=yj#~G>I+^(49(lXvvVITI*J?<6|O(eu!iSB< zeG90W+N5(;r-S=lv68B9*X}C?nsI*$jN^mWPX!Fb(`EjF2WzrZK!QHotQKS#b-;3QCszG3;Xxj%>7$A2w?RfXPOtamH_b5o;4z=!rasl(~W+UH5!u9Nx6LF5;1=N|>>s*&h?l-kOM!Z_P zkw)c7MTW_wCviscJxONg{)MI|$A3=tC-~0xB)i>qQI3tIl}kGH0bQ*|Os<->kpSmva=>-6ME{f%};g)A?A~m)J*(s4EEsxB>P+=5z3Vk zDP)A%jBAJQN0m7j?UjpoVvp~sJ^@bl2qdr7$pwbVrN?YjgSyYfi^T1dezS)7`TOI*GMaH1^a;TR1Tu3hNNhO<6 z-2GESxqaR#0Jk~WpyGd9uG-n~w$~v_tZCF=eUx<{e(LTNi-;N&Z~%t_6Q!svgUXex zc=9(@Fhiuk;8rCac+b7>V?+qfL>i|Pp_C>3}UI3JpTBLpq2%&_y} z%hZn=JyitSZaQ#omnFAd@P;&s)~jH zz8y;7w!{KUo@j+MXpvtDxZL}N{N?V8H`g&F5gjk90mK5w9;b|iyVR@}A+w)keAXx= zhC6W0_Llv7iS{>uk8AnS+3d0b_Pwl56R3l&Z3 z6UwPpqsuQ!c^rblhDyK|}2sDE;&@ppx?tU?0 zxqFr>kKg^bxa0IDFH=uzE^WXOE_WIME3gz<~Sl z9J+78qT>sV31i|+q7$9QI(=!Ai^4C(F&eYJNlrRE29R@idf)5B{5;R`A4L_o+q@5i zvwj8HfqZvV^uY9YjFHsTw^$#eK@O+OFk0)RhP%D#xOa!-dw0e+@ngAR%^E=&o#@Xn)J&EzO90n8rB|Yd>d@>?Xa89rVYOY$QWq|& z5jLVJtZ%J$iu4#&E>akSVeUkdl0BbUZSnBcck?>es?iV<$EKGMbAHoFV9m8#L8w&3 z+ezg!%w^mwEotpr$Y1vP()Vlivl`K1Mdv2se4-P#jkSGQ5GCWL zO~`DBRd6>IRzgn@M%uOp{@9Q5;KzHu^GM6ef}+lBh@XVSR^3#P)m%ZuXSOdl_lq8j z$$fuco@@-X5th@(z$6nN-WY({>&c>WnZ9tGB$+m@DaxnHV3(PApog6(#?WWC4s=i~ zsL$#^8H_u)KG*dA34xf6LWI{MF0f(9=9bPf;Ud`=Zj9f%nZc5?Lr$j3(p_P5@%Ka= z%+r!Q*pMgIt1F=5wh(XstNJ#SP1^Dct{hDVYU=T(!1}LGmF_Y z?gn97S5skBj26HFt1sH%EMsM!g?n{7 z1SQikOleDn!KXo$vDQuf z3)%DOM|Tlb-|3-t5kNNe1Q=yQ*>7RT(UUdmys?@Q!h{Xqo(aVFy(2V^<5$QLMt}Mg zYowws<6&K)fQF($PK#q`qmnMzAFmZF*;MXPl3fLlGl*f`-8OZ=yQK5CQJ2Fhr-q%6 z&(pKVAEj{uZ`T7@dwI331OD=H!p6M_do^A?-*ZnfA&=|gP9w8N{p3kredf<7tS!mB z$(yw1n}>G?&@lA|Z_vTv0mq$M_LG03PC>9PtXqu?j%J8A1?(+&J6AYKbuvf zUk)DEfUEw^Gv`VF)~kI>Fn6f*#k918x=Q42oenWDz$3RV+R>%^ufgRPc<0m1mHqy1 z(eRasP?`jg?78EDKKAFciy7O&x3@oWYpl!FT3AmK)WS$IoXImV7>q}FkMN0xp`TTx zSsPb|k?=6Tt$hZes@~bY%!STC<{M0Vtz7L|7?9RRcCD3NiX9Wgqo=wKZ0x_#MFiCm1x6zjDlxkL-KvfZ>q|HdGNn zCgoZuz!lweyx!tK)_z#3e+^T$FlA^1YA9rSJBk^2fHjP?^@+-^kv$NsMu zY`S2VoNj-*od|Ev<{BM^|J3XJuXy#({=bS)PFmS6{)tyb|07-@{S&Y9Fh4B-NTW6o z4q$5*0|S_}lRU=m+H*w!t~;!^H%Xo%D(aSU2fa+Jpkz@y(eBXXt51_ze8xrxd@9R> zg%%|75kxK5=BMtwo`O{R^6;iV5X0q!o7j+1pi(jO~p(M-&cq-8u#j8mH{Yno$IxWBVf zKj6W?CEIO3V(NgW@Grgo3)4a8&~@!WE z(j6arK6?y}a%`R4|Jicw7}q0N6aM`?t<(^(?Aoz&KMU7l6(vUHK06gEyOni-U(Lganl_2Hl1LBqPOR*gz7fQMpz2~6>R6B>J zAc7|TmxX4060tDY1sGN(?E$VAnUGDjTkf$Ar6g3KiW-EnB`PCL%DkkfI!U?NpaCHZ zV8YPmg~p$bP0MZrVuuhTZCz?DH`w$_1E0nBBZa5~s7x{UIO(3u{*(|9__7n~7h(B+ z2#PPJjOF3!IH@aG=p=}6_=t8W%(%yp={uQPT^g)0lK>&B3xUuvDzk4je=v{@UUij& z-GdV3g0vQ-1y`F0blV?rcN0R$)DqPR5@J2H4pr^>-i9{^y$Pmp2TLtK)D#AVFT_At zqJ}56Bti-Kw0#Uinomi+K%FjHgL3(RS@w)mU_glj0`NJbD^_(9ol*D$lzi;$4KR9X z6R^>gTsBr~sFKl|9Gy6kz1t`JX~obH+Du-qV?*I(ak?1i(;n}%o-ZWPq&=}BG0z9b zC=Y*Typm1C$hgb1@Oyg#3H0I&aYZ3490jhmlkEgsU?$5&qLGm^0; zvQ=+FLfE4HV9Mgro~}brP%U2{qfnXqY zI|ZEAFcK%-#kva<2h@D!n@AF;oxc_A?X;;g`;!ae z3Jo8=Z-B$b)TrT$d%#_^T23D`w`cD+@-KKo{K`aLkgTDE?qBzSyy5nXFU8#bX4qW9 z>KynuSy_Y12J*rNH9>QAn33FE(XvT*+K6g~*`i@GdMI8o9vrd@=~V1uJ>31K*pcdy00#-N3;A1YC$EV(|E+h8|3a7^%*3Ph#{^s^`cdghQf2ffIQ_gEmsm#V=$ z_YHm7fppmS8KoSDM6%sdjReBWP(suWsCv%im>e!yS}=~#{34nwbHdNXOnsU#jfDRM zRv|MjQ6DEVcwClh-z|+fuMeeQ5O>y^ZWU83tl&A^Ks(HuS3*@6QX{Qq z3C4=CaQ&G0&C$_%A?3i<9x4PI&ho94)P%kD`PIZpgVMW++@?Ln&Q(6 zbL1B9zk|1r1c#?p0p$Xa?Sx%122rJ)I3~{Y@g~7-9kM&|0s{0*N9&=>G0T09T}kv% z{*;lNiYkZh;9z;>vPdQ*^fFUS^|d!GhM9At7F@O|M2fq;Wjt@;9*UDe^k`wJipf+&5BfR6^sD5@OxdK@7yGSwy z#~5dSE7Wwr*0U+8g|y9)uA1;cZwAJx3wenGrl=b!zKS`FdKpq5XCHd|{)&pLd*~w2 z_o6NugvWOC@@?80B;CQwDoEOV6Hh<~rx*rRm0Q}M#Io*t{oE!rzDn>-no?qTw2UK@ z#8AV^)}-(WP%iw0vn`B~B`QF*nMUNm4-w;&v>~|goztxmFbnrEpQ0rm>Sv;5>t0mI zs0ySw$=*`Na{=1JJ6$Gwk&)N)(6ZM!_}!(G#ow8&e`XB~f)Fzv3IRn5?SG~Jd?68Z z0E!@^f8|C}|2l>`Exk4kzl)<52C7k`eg}AWBzh+IF(e=O+!E{odsm~D)(bp1MdLGT z_J71X(igz6#?TE(r<-cJ3-(Zu{g9*oUTFk`lnQb$ZzLGOwFd51Oy=z9iB!RdXuN?;h$XnFQLQ0}?5eT}%=q1a%0ntGXF%)r(8w zvXK*#bChn*5j9-^j?ylMDi`P-2i93f*X5~U)!cR;Sf1;#xk!kBgnz82rgJfoL|!@P zCgpQuyyC~<18JvYl0n+cMqW0B)~#p2zvu{N@JB8AtDie@KMmKBc_CX9+|hTniz5Df zg`=Y9nLDwtb43+Xd)ScuV11bru82TZZJJpwIp>9v!v}-d{rHvtiNfUd7n|!0SO`bT zCu8I@)3i`4(SauFa5>#9g8fl#JpR4-&&`FH6IJy`X*ru^u$Wx>8FubK*Y0GPTitfo z>gM^xU+&f*b$JpHCHcg`d-xWr5RhIWd$4%Z-Jqy6#6$#V;L{L9Ij1vLzkH)`)k8&p zUa#O6``@?8WLqFZVdOHtS1L6o%|loyNUxZpRLIZr3Zl}LDU%|K-4z;V<{&yK{B^;h zba0hz8nyB`foo(gi5veQDGv7Q7h{q^^vl3lgto|=JE1{rzZZ^-SK}4(`u8z8COJ-L za|kUuopUY%(usag!c+i;g1oi9O)7?*HfQVc-EG(RL?Jx3L*0G zCsG!YdzK;U+K(vuCd5X~V^-wA*0v9OKmVo z=drGjVAmW1d-v;%5DOCCq7Un8n z)sDU)i{=n7&qo@euVd#Me23R0S~dht+g8Fb={BJT-xtW03Udk`w^97mgd;01V(~=j zew*hf6vUP%h`A!gU#f$BEc+Nsf+kDxRQ!55*6dXFOpD$aUMp0N|*5jby3c54@Xk8 zur3rJu&pSs2LFUMVe*fXB+AmYL^u35{^NlkFM+xWN;jon0^zK!XlEE^VNrG{tq|tk zSa3eP2MbY&7_Af3(lG13Wu_%yz8iTe41r}nda>&JNsf45K2u+#(9_`P>d3j`a3P5} zi3u)GY4)$nj%e;6orFMlZmaBPZ58L_78@Y+i*wa{V7}44kvfqk7Z++|W0&St<6kOf zVH9_Jjt~=0b~3`5j*cYTw%*x14X%D$C9i6@cr`_lGl$i$DcK|5ukNCTc(SYs4sMaF zVhf{+)oZIsZeC_vbBCXL@i=%7**N5B{M3vV1GApeHJ7rk3Y(B-JPg1$pueR?J*^T|RD7+btUXQk& zf}`gjgLyO-JopBvP!u)k+4$on9T`Q1=!<-!aos$*h>0*=P7jm3mLLOWf3d7~SI1ls5vyPD% z<3!pgv2dG&xp}sKhWm<_6=vu@4D?LhW&8aOuA>j3E~M8xiTT-_JS6fZ%!Loemz&mQ z-=o*cgj;7PN7ln45kq4L0wyYyi#t`PWoVa<)G`wn8ZGD>PddI#?I?~px8 zDmC6)dyb*&@s}S_erznKf($FEG&#&C#*iJ+3zqNo%&om|@a0%{guEq5UP_vZi_=;Y zw;c|2#Pc3@biGwk@b>4UhSrA?jj>J2g`)mM{&mw zNZshMSVzb1W9LE-1PEI~>VL+Zh4>dKY`k@ZUY}x|eNWLEe3sQac_tZPV39u+Zot*5 z0?lrU(d_h}zyi}=^-VrId^@@zdg*O1$Ex>HYAr$})6sz}P@95w9aVl)tXz;soD0M> zKt1VGw_`OU{_*q0XVZ<#T)dj)(#^k(=nyT>ysK%$5BR?b&QOHUL>}I89`n^(ar36} zNfR`!_!qcfVDY=4*f~=`lFu_GOD8-jOgKL8zJ8S$8TNf;h~}+i=k#Qk+)w5c zsne+<9QK;UkD{ynA&y@2S6AQS?v0!I?EKr0dm@mVcFS`ZE7c=N_vZLb((N|mV-e-| zVk%(KkwtkY<4zog!Iw>`x&KsH{ja2j{C`VYNMDSy{z+OA|08Lk{C`PnQKo2<3}7K@ zUa34`FHI>cJ>ElA@%BcY4R-z5RPIp0jvtitK2N=3cAM*?t8FE7{gt2y)ohhMdX-2L z@3Hr3MT!3E<3?F({NFUfj-}d1N||e_2!QlUREo*TL(gCLO=p2`w*C9viVmwjTgFuv zS>F!I3nMUw<+uG9AWwl3x%fTX+qDe_Y&R6_(l6@EtQz&J4FxyHx99DCzD~gz=A3o9 zjvcSAHT^Y@;7Q*&e`AW zq1p_F9x=Z;_1~x>qM}C&C}K`{0<=eVmtl?FedY~r5<%Zx`&|Wcr`^77T`cQ)e;dV0 z_Ka%Y9bsf*IdoPFC*o7+&X|1X+aJ0u+RrjfN&{J*!q@c|W6}@_`w}c9CP|&Bu;-yV zcaUzPVV&Qh{@X1NH(Jb?3jWR7T;sc^J{t?>oc*`2-#NPkEIG(1;1iz$w~`OOsL7ADkdAWCaU-lr4zQ6D(lo3@ukX{wsu5fXQ6qu^x{3#73nBM*!aw9pZ|fSN{Ft+*e1bv4W|$k0j0m{%XY+D* zhOWP~D%}LlrJVS@M)`&8dHm9vA=jz9Ug>Ixx~v1gO}Mjj&=89vE(u5EBs=5Q>cy6tonkak(#5y# zlx~(jz}>%WshAxOZ59B_f$tYO(oqhN6xt`3kiB4f`e!cbA#7c zhm5#EV{A05gACKQWl>A5=o^L%i=^JeN@83&wh38D@jR8nV|Ew%>3*cs=Qc=$dyd$) z+T6iA6Li_GdRt%67+um6?f!-=L~-k!x7ryzQM%4CpHLLof7d!R1^IG~cSd`+f^TBW zv3d6XaG#n>jF(1u^Koy#X0fO-eQzIqO_)1GC9EyTRNUl^Ei|h`a@(z{II^mJz^VXWQ|$8+)1jBBL%ep!t7WrUSE8F=<9 znjUl7)EWCNo2Q}feFLKW4X%DhSKu0#>LG^BDJkV=Y$Qg9PE+?xT5P(2R2Dmh99LHZ z)VMJBo1gi}s}9p(7FQRaub_qetQG6pP&)D&;F&2{l~Js_fTJZbMc%29Iq<6${+P(g zP&#mp7a`jL;6N+YkNL?Wd*03+yfE3nSjL@w9oTwXj8BW5PH`0?xIvr6ng@S?OpTt$ zI0jsYp54xebool^XzW=m`hs68{oYv7sy_dl_#w`R)``&fQ)*9hi@)SEp{pcm9WoVU z`wlr=w$-yCny#h~t*_UEFQ2)yJ@XV;DRYFy?2BBF1Srkq)&~RqxU=2!ba(|0rZ&4M zF47;-bD0I{XGVvHQFPpIJe&9yf(x@tKx29({-M%@)b4Xjs5%V1KP2CP*vF;#mh>#V zdkWFvo;o_`?bH%rX-cTU?aaa6S%krcBWCvLa@V^6D!*_C1*UuI&dv;!J^ioJgrFS8 zuqW*vcoFLPf9`z|m29K{0j!*_oL~feAiYS@+klQ#&W3{jCM)|aH9uGf?XV9vZhtWs z%-|!lq*1{?!!_Fy{)7?sUs*q|Y3Lk*>K#tQl?ey=iV2@_TfKZFx%w&`=)lx^CMwY@ z=o)a+sM;YOB@_9Fi7Efw4Wkt0-a}4;cKuig%C5eoewSRv)#5=o|L!j%{I#=G<26}3 zq1)mUqqv+th$YzrQLi8z)J0khQSS^fiyFj1nb|Sc&P4k|E};+D0dke9!bV9FfkNye zaJ$5PU$DjK>S7Mjr&JGS8Jt5c zLYSoTx$M9GY&c7P zj$kllRrr$x8BkczxQ97J-|mJ9@!kg~^71H; z@^$^fH!|UBKhMQ&5kM4~CJ*58oj(J}S}7ds&Fi5%&oZgDn(KXxZDlkTRl|58EjWR44!OKjKxD z&(C#{-dIunGob^uF~`LT_Qhd#UL7B#9N#oin1gjOaw=<-5U?@+BuX?IJ^-@!TY7Y% zh0*?*DpANzpgcXRCDL&8{{<@u)c5Q%f;zwIJ zrMlrPHBlI0TSwEHFeiVUM_G)yOgSmMKh&V71M}&%@h~gg^~UvYM&FFH7D&`YC_})Pk!6Li_VJZB&jx&xF&r+fK{$ygf|6K=okEv>tpYQ9A7wQ~LuQ zX}se(c;H!k(cPZ6UkSE*DljH7RU&@p(FGU~==a+W15uCWwhOu%F^CUUt$z-;-NH1U37g4C|JJB}U4 zxhTMx*m0wY3&vayHIalgi2^D1&-pG;(Ftfq7?Z1F&-s`%h%S-(I48qkOzJqyom|44 z6UJny*vXWxk96SouUx@;fr?&Or3~1Ni72Pl*_$SA7KDQH0#&M}bp8=0J|&JQCut7y zc+>N~1gsaR=t+p0aT*iTH(JLzX`%_@xY42@L z4{@H?m~&j9l2|d*yLUNaF(z8cQ%hTww!bG%U;A3B*ttzE*Uo4WEM4rWa~KmvX4l$7 z&ANvoNiWV_Vd4zoEm$Uwn`APk5{$+~k*TjvVoq(G1MP2iMAXSvU?NlgnDw~U&pwJw zT~&Mg;MAQQ3HtOPI1vTAa(Rr2BC}%ct!7OFC%ypfiu}18=UQ>NAV-rFnfbuUYb%eO zB~G1Gq!;I5kk-#Y$mjaqJB-Oc$)w$h%$_r!(=d^pA!<83;58;bBVk*))onKtoZzXE z&yB#O%JC^_%pf#!jrYVdpw@BS_Ym&6^Etg{iuEuj`pH0Y8xu1QGitVNAO57`T;#~+ zXtkl#-H6K!#wk{;yy{VQQ$I_wUmiY14Or^msPSW;n3h8fNV|SM^aB6`{8{+QEVoy*n07E@O(HIQdq9aF0d*9Y3=$T>}cPF)u1c zwLYer95{!M*33)eN3~F}zqSgM;#teNF z>_zD%25~Gn$6H1Fgv*#eFvu)UHmu2kb0pO|%Wn~rF=pt|nz$rpAU3u3kkE%W{0Opnk&d3DI--VBhw)75t5CcwDV~VfE zkBhccCjy;i93L6l`8l=9r7AKy15Q3;3UQw7{FF>59`0Y5!WkUEn17Nj$%wf-72-Jjr%6O{1W24+(Dkm@$Q@S(kq@~dM8%d z6*uYELFsA6!=h4+*LSHF&o;{*=t1c98)Yrmw_Zr@|1CF7Afm2@X0)0x6ocU% zp;P7*L1E%uNx~2Ds>ebL)eA4Q@Bc=_4%!V?#>Qxqevj~RlKdz6IlCJlLZTPzsiu?PezWgML<=NzEKeTlam7>L>MIz^?<2^1#sEI(N62&l4D2W+0Aax5x<=F2H` z%g?L=0kOP^4ui<4xbQ>eVLBDwGTT3NQgtn|0Vu9H1H`+%ha==)biO7`7!2a@;%p22 kJJzct@F0X_`M)OL0qtIKw2(NPegFUf07*qoM6N<$f_ez0CjbBd literal 0 HcmV?d00001 diff --git a/public/js/index.js b/public/js/index.js index 8a85ad91579e5..3b15ad8f1883d 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -241,6 +241,41 @@ function updateIssuesMeta(url, action, issueIds, elementId) { }) } +function initRepoStatusChecker() { + const migrating = $("#repo_migrating"); + $('#repo_migrating_failed').hide(); + if (migrating) { + const repo_name = migrating.attr('repo'); + if (typeof repo_name === 'undefined') { + return + } + $.ajax({ + type: "GET", + url: suburl +"/"+repo_name+"/status", + data: { + "_csrf": csrf, + }, + complete: function(xhr) { + if (xhr.status == 200) { + if (xhr.responseJSON) { + if (xhr.responseJSON["status"] == 0) { + location.reload(); + return + } + + setTimeout(function () { + initRepoStatusChecker() + }, 2000); + return + } + } + $('#repo_migrating_progress').hide(); + $('#repo_migrating_failed').show(); + } + }) + } +} + function initReactionSelector(parent) { let reactions = ''; if (!parent) { @@ -2219,6 +2254,7 @@ $(document).ready(function () { initIssueList(); initWipTitle(); initPullRequestReview(); + initRepoStatusChecker(); // Repo clone url. if ($('#repo-clone-url').length > 0) { diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index d8b06862a5ea6..08c0635bc3128 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -398,8 +398,8 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) { } var opts = migrations.MigrateOptions{ - RemoteURL: remoteAddr, - Name: form.RepoName, + CloneAddr: remoteAddr, + RepoName: form.RepoName, Description: form.Description, Private: form.Private || setting.Repository.ForcePrivate, Mirror: form.Mirror, diff --git a/routers/init.go b/routers/init.go index 1efddcfaa6c60..c37bbeb6b08d4 100644 --- a/routers/init.go +++ b/routers/init.go @@ -20,6 +20,7 @@ import ( "code.gitea.io/gitea/modules/markup/external" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/ssh" + "code.gitea.io/gitea/modules/task" "code.gitea.io/gitea/services/mailer" mirror_service "code.gitea.io/gitea/services/mirror" @@ -102,6 +103,9 @@ func GlobalInit() { mirror_service.InitSyncMirrors() models.InitDeliverHooks() models.InitTestPullRequests() + if err := task.Init(); err != nil { + log.Fatal("Failed to initialize task scheduler: %v", err) + } } if setting.EnableSQLite3 { log.Info("SQLite3 Supported") diff --git a/routers/private/serv.go b/routers/private/serv.go index 71c0f6ea2c48c..c4508b4cb5e0a 100644 --- a/routers/private/serv.go +++ b/routers/private/serv.go @@ -119,6 +119,15 @@ func ServCommand(ctx *macaron.Context) { repo.OwnerName = ownerName results.RepoID = repo.ID + if repo.IsBeingCreated() { + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "results": results, + "type": "InternalServerError", + "err": "Repository is being created, you could retry after it finished", + }) + return + } + // We can shortcut at this point if the repo is a mirror if mode > models.AccessModeRead && repo.IsMirror { ctx.JSON(http.StatusUnauthorized, map[string]interface{}{ diff --git a/routers/repo/repo.go b/routers/repo/repo.go index b67384d72193f..bfd0c771b0585 100644 --- a/routers/repo/repo.go +++ b/routers/repo/repo.go @@ -19,6 +19,7 @@ import ( "code.gitea.io/gitea/modules/migrations" "code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/task" "code.gitea.io/gitea/modules/util" "github.com/unknwon/com" @@ -133,8 +134,6 @@ func Create(ctx *context.Context) { func handleCreateError(ctx *context.Context, owner *models.User, err error, name string, tpl base.TplName, form interface{}) { switch { - case migrations.IsRateLimitError(err): - ctx.RenderWithErr(ctx.Tr("form.visit_rate_limit"), tpl, form) case models.IsErrReachLimitOfRepo(err): ctx.RenderWithErr(ctx.Tr("repo.form.reach_limit_of_creation", owner.MaxCreationLimit()), tpl, form) case models.IsErrRepoAlreadyExist(err): @@ -221,6 +220,40 @@ func Migrate(ctx *context.Context) { ctx.HTML(200, tplMigrate) } +func handleMigrateError(ctx *context.Context, owner *models.User, err error, name string, tpl base.TplName, form *auth.MigrateRepoForm) { + switch { + case migrations.IsRateLimitError(err): + ctx.RenderWithErr(ctx.Tr("form.visit_rate_limit"), tpl, form) + case migrations.IsTwoFactorAuthError(err): + ctx.RenderWithErr(ctx.Tr("form.2fa_auth_required"), tpl, form) + case models.IsErrReachLimitOfRepo(err): + ctx.RenderWithErr(ctx.Tr("repo.form.reach_limit_of_creation", owner.MaxCreationLimit()), tpl, form) + case models.IsErrRepoAlreadyExist(err): + ctx.Data["Err_RepoName"] = true + ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tpl, form) + case models.IsErrNameReserved(err): + ctx.Data["Err_RepoName"] = true + ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), tpl, form) + case models.IsErrNamePatternNotAllowed(err): + ctx.Data["Err_RepoName"] = true + ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tpl, form) + default: + remoteAddr, _ := form.ParseRemoteAddr(owner) + err = util.URLSanitizedError(err, remoteAddr) + if strings.Contains(err.Error(), "Authentication failed") || + strings.Contains(err.Error(), "Bad credentials") || + strings.Contains(err.Error(), "could not read Username") { + ctx.Data["Err_Auth"] = true + ctx.RenderWithErr(ctx.Tr("form.auth_failed", err.Error()), tpl, form) + } else if strings.Contains(err.Error(), "fatal:") { + ctx.Data["Err_CloneAddr"] = true + ctx.RenderWithErr(ctx.Tr("repo.migrate.failed", err.Error()), tpl, form) + } else { + ctx.ServerError(name, err) + } + } +} + // MigratePost response for migrating from external git repository func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) { ctx.Data["Title"] = ctx.Tr("new_migrate") @@ -258,8 +291,8 @@ func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) { } var opts = migrations.MigrateOptions{ - RemoteURL: remoteAddr, - Name: form.RepoName, + CloneAddr: remoteAddr, + RepoName: form.RepoName, Description: form.Description, Private: form.Private || setting.Repository.ForcePrivate, Mirror: form.Mirror, @@ -282,47 +315,19 @@ func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) { opts.Releases = false } - repo, err := migrations.MigrateRepository(ctx.User, ctxUser.Name, opts) - if err == nil { - notification.NotifyCreateRepository(ctx.User, ctxUser, repo) - - log.Trace("Repository migrated [%d]: %s/%s successfully", repo.ID, ctxUser.Name, form.RepoName) - ctx.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + form.RepoName) + err = models.CheckCreateRepository(ctx.User, ctxUser, opts.RepoName) + if err != nil { + handleMigrateError(ctx, ctxUser, err, "MigratePost", tplMigrate, &form) return } - switch { - case models.IsErrReachLimitOfRepo(err): - ctx.RenderWithErr(ctx.Tr("repo.form.reach_limit_of_creation", ctxUser.MaxCreationLimit()), tplMigrate, &form) - case models.IsErrNameReserved(err): - ctx.Data["Err_RepoName"] = true - ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), tplMigrate, &form) - case models.IsErrRepoAlreadyExist(err): - ctx.Data["Err_RepoName"] = true - ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tplMigrate, &form) - case models.IsErrNamePatternNotAllowed(err): - ctx.Data["Err_RepoName"] = true - ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tplMigrate, &form) - case migrations.IsRateLimitError(err): - ctx.RenderWithErr(ctx.Tr("form.visit_rate_limit"), tplMigrate, &form) - case migrations.IsTwoFactorAuthError(err): - ctx.Data["Err_Auth"] = true - ctx.RenderWithErr(ctx.Tr("form.2fa_auth_required"), tplMigrate, &form) - default: - // remoteAddr may contain credentials, so we sanitize it - err = util.URLSanitizedError(err, remoteAddr) - if strings.Contains(err.Error(), "Authentication failed") || - strings.Contains(err.Error(), "Bad credentials") || - strings.Contains(err.Error(), "could not read Username") { - ctx.Data["Err_Auth"] = true - ctx.RenderWithErr(ctx.Tr("form.auth_failed", err.Error()), tplMigrate, &form) - } else if strings.Contains(err.Error(), "fatal:") { - ctx.Data["Err_CloneAddr"] = true - ctx.RenderWithErr(ctx.Tr("repo.migrate.failed", err.Error()), tplMigrate, &form) - } else { - ctx.ServerError("MigratePost", err) - } + err = task.MigrateRepository(ctx.User, ctxUser, opts) + if err == nil { + ctx.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + opts.RepoName) + return } + + handleMigrateError(ctx, ctxUser, err, "MigratePost", tplMigrate, &form) } // Action response for actions to a repository @@ -460,3 +465,19 @@ func Download(ctx *context.Context) { ctx.ServeFile(archivePath, ctx.Repo.Repository.Name+"-"+refName+ext) } + +// Status returns repository's status +func Status(ctx *context.Context) { + task, err := models.GetMigratingTask(ctx.Repo.Repository.ID) + if err != nil { + ctx.JSON(500, map[string]interface{}{ + "err": err, + }) + return + } + + ctx.JSON(200, map[string]interface{}{ + "status": ctx.Repo.Repository.Status, + "err": task.Errors, + }) +} diff --git a/routers/repo/view.go b/routers/repo/view.go index 1967b511ca4f7..c4e6a69220aaa 100644 --- a/routers/repo/view.go +++ b/routers/repo/view.go @@ -11,6 +11,7 @@ import ( "fmt" gotemplate "html/template" "io/ioutil" + "net/url" "path" "strings" @@ -31,6 +32,7 @@ const ( tplRepoHome base.TplName = "repo/home" tplWatchers base.TplName = "repo/watchers" tplForks base.TplName = "repo/forks" + tplMigrating base.TplName = "repo/migrating" ) func renderDirectory(ctx *context.Context, treeLink string) { @@ -356,9 +358,37 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st } } +func safeURL(address string) string { + u, err := url.Parse(address) + if err != nil { + return address + } + u.User = nil + return u.String() +} + // Home render repository home page func Home(ctx *context.Context) { if len(ctx.Repo.Units) > 0 { + if ctx.Repo.Repository.IsBeingCreated() { + task, err := models.GetMigratingTask(ctx.Repo.Repository.ID) + if err != nil { + ctx.ServerError("models.GetMigratingTask", err) + return + } + cfg, err := task.MigrateConfig() + if err != nil { + ctx.ServerError("task.MigrateConfig", err) + return + } + + ctx.Data["Repo"] = ctx.Repo + ctx.Data["MigrateTask"] = task + ctx.Data["CloneAddr"] = safeURL(cfg.CloneAddr) + ctx.HTML(200, tplMigrating) + return + } + var firstUnit *models.Unit for _, repoUnit := range ctx.Repo.Units { if repoUnit.Type == models.UnitTypeCode { diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 11f2029226a7a..8dfcdb9c9b64c 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -845,6 +845,8 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/archive/*", repo.MustBeNotEmpty, reqRepoCodeReader, repo.Download) + m.Get("/status", reqRepoCodeReader, repo.Status) + m.Group("/branches", func() { m.Get("", repo.Branches) }, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader) diff --git a/services/mirror/mirror_test.go b/services/mirror/mirror_test.go index 76bd4c72f76e0..9ad11b726563c 100644 --- a/services/mirror/mirror_test.go +++ b/services/mirror/mirror_test.go @@ -10,6 +10,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/structs" release_service "code.gitea.io/gitea/services/release" "github.com/stretchr/testify/assert" @@ -26,16 +27,26 @@ func TestRelease_MirrorDelete(t *testing.T) { repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository) repoPath := models.RepoPath(user.Name, repo.Name) - migrationOptions := models.MigrateRepoOptions{ - Name: "test_mirror", - Description: "Test mirror", - IsPrivate: false, - IsMirror: true, - RemoteAddr: repoPath, - Wiki: true, - SyncReleasesWithTags: true, + opts := structs.MigrateRepoOption{ + RepoName: "test_mirror", + Description: "Test mirror", + Private: false, + Mirror: true, + CloneAddr: repoPath, + Wiki: true, + Releases: false, } - mirror, err := models.MigrateRepository(user, user, migrationOptions) + + mirrorRepo, err := models.CreateRepository(user, user, models.CreateRepoOptions{ + Name: opts.RepoName, + Description: opts.Description, + IsPrivate: opts.Private, + IsMirror: opts.Mirror, + Status: models.RepositoryBeingMigrated, + }) + assert.NoError(t, err) + + mirror, err := models.MigrateRepositoryGitData(user, user, mirrorRepo, opts) assert.NoError(t, err) gitRepo, err := git.OpenRepository(repoPath) diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index fc7f1b660ca62..9fb3e32899ae0 100644 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -16,93 +16,95 @@ {{if .IsMirror}}
{{$.i18n.Tr "repo.mirror_from"}} {{MirrorAddress $.Mirror}}
{{end}} {{if .IsFork}}
{{$.i18n.Tr "repo.forked_from"}} {{SubStr .BaseRepo.RelLink 1 -1}}
{{end}}
-
{{end}} -
- + {{end}}
-
diff --git a/templates/repo/migrating.tmpl b/templates/repo/migrating.tmpl new file mode 100644 index 0000000000000..34031d5653efc --- /dev/null +++ b/templates/repo/migrating.tmpl @@ -0,0 +1,31 @@ +{{template "base/head" .}} +
+ {{template "repo/header" .}} +
+
+
+ {{template "base/alert" .}} +
+
+
+
+ +
+
+
+
+
+
+

{{.i18n.Tr "repo.migrate.migrating" .CloneAddr | Safe}}

+
+
+

{{.i18n.Tr "repo.migrate.migrating_failed" .CloneAddr | Safe}}

+
+
+
+
+
+
+
+
+{{template "base/footer" .}} From 300d9a1c709a0addde7c77efa7153f66ff6748d8 Mon Sep 17 00:00:00 2001 From: zeripath Date: Sun, 13 Oct 2019 15:35:19 +0100 Subject: [PATCH 069/173] Fixes #8369: Create .ssh dir as necessary (#8486) * Ensure .ssh dir exists before rewriting public keys * Ensure .ssh dir exists before appending to authorized_keys * Log the error because it would be useful to know where it is trying to MkdirAll * Only try to create RootPath if it's not empty --- models/ssh_key.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/models/ssh_key.go b/models/ssh_key.go index b7c5b4fe6e587..d1132bf0c61a0 100644 --- a/models/ssh_key.go +++ b/models/ssh_key.go @@ -358,6 +358,18 @@ func appendAuthorizedKeysToFile(keys ...*PublicKey) error { sshOpLocker.Lock() defer sshOpLocker.Unlock() + if setting.SSH.RootPath != "" { + // First of ensure that the RootPath is present, and if not make it with 0700 permissions + // This of course doesn't guarantee that this is the right directory for authorized_keys + // but at least if it's supposed to be this directory and it doesn't exist and we're the + // right user it will at least be created properly. + err := os.MkdirAll(setting.SSH.RootPath, 0700) + if err != nil { + log.Error("Unable to MkdirAll(%s): %v", setting.SSH.RootPath, err) + return err + } + } + fPath := filepath.Join(setting.SSH.RootPath, "authorized_keys") f, err := os.OpenFile(fPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) if err != nil { @@ -645,6 +657,18 @@ func rewriteAllPublicKeys(e Engine) error { sshOpLocker.Lock() defer sshOpLocker.Unlock() + if setting.SSH.RootPath != "" { + // First of ensure that the RootPath is present, and if not make it with 0700 permissions + // This of course doesn't guarantee that this is the right directory for authorized_keys + // but at least if it's supposed to be this directory and it doesn't exist and we're the + // right user it will at least be created properly. + err := os.MkdirAll(setting.SSH.RootPath, 0700) + if err != nil { + log.Error("Unable to MkdirAll(%s): %v", setting.SSH.RootPath, err) + return err + } + } + fPath := filepath.Join(setting.SSH.RootPath, "authorized_keys") tmpPath := fPath + ".tmp" t, err := os.OpenFile(tmpPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) From f858b89b130352265d59b5d46af626373796b74e Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sun, 13 Oct 2019 14:37:37 +0000 Subject: [PATCH 070/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_es-ES.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index dbfa4622173b9..c29476987d29c 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -1354,6 +1354,7 @@ diff.whitespace_ignore_at_eol=Ignorar cambios en espacios en blanco al final de diff.stats_desc=Se han modificado %d ficheros con %d adiciones y %d borrados diff.bin=BIN diff.view_file=Ver fichero +diff.file_byte_size=Tamaño diff.file_suppressed=La diferencia del archivo ha sido suprimido porque es demasiado grande diff.too_many_files=Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio diff.comment.placeholder=Deja un comentario @@ -1456,6 +1457,7 @@ settings.options=Organización settings.full_name=Nombre completo settings.website=Página web settings.location=Localización +settings.permission=Permisos settings.visibility=Visibilidad settings.visibility.public=Público settings.visibility.limited=Limitado (Visible sólo para los usuarios registrados) From c888ebfba713b4d5be88c427a34d29153be52076 Mon Sep 17 00:00:00 2001 From: zeripath Date: Sun, 13 Oct 2019 17:29:08 +0100 Subject: [PATCH 071/173] IsBranchExist: return false if provided name is empty (#8485) * IsBranchExist: return false if provided name is empty * Ensure that the reference returned is actually of a valid type --- modules/git/repo_branch.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/modules/git/repo_branch.go b/modules/git/repo_branch.go index 3e1261d294cf8..a2bf9ac973e49 100644 --- a/modules/git/repo_branch.go +++ b/modules/git/repo_branch.go @@ -28,8 +28,14 @@ func IsBranchExist(repoPath, name string) bool { // IsBranchExist returns true if given branch exists in current repository. func (repo *Repository) IsBranchExist(name string) bool { - _, err := repo.gogitRepo.Reference(plumbing.ReferenceName(BranchPrefix+name), true) - return err == nil + if name == "" { + return false + } + reference, err := repo.gogitRepo.Reference(plumbing.ReferenceName(BranchPrefix+name), true) + if err != nil { + return false + } + return reference.Type() != plumbing.InvalidReference } // Branch represents a Git branch. From c23cf4c97c82c7f09a85459b676777b597a99c8d Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sun, 13 Oct 2019 16:31:19 +0000 Subject: [PATCH 072/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_es-ES.ini | 12 ++++++++++++ options/locale/locale_lv-LV.ini | 2 ++ 2 files changed, 14 insertions(+) diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index c29476987d29c..f5355a488fa7b 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -568,6 +568,7 @@ owner=Propietario repo_name=Nombre del repositorio repo_name_helper=Un buen nombre de repositorio está compuesto por palabras clave cortas, memorables y únicas. visibility=Visibilidad +visibility_description=Sólo el propietario o los miembros de la organización -si tienen derechos- podrán verlo. visibility_helper=Hacer repositorio privado visibility_helper_forced=El administrador de su sitio obliga a nuevos repositorios a ser privados. visibility_fork_helper=(Cambiar esto afectará a todos los forks) @@ -1208,6 +1209,9 @@ settings.collaborator_deletion_desc=Eliminar un colaborador revocará su acceso settings.remove_collaborator_success=El colaborador ha sido eliminado. settings.search_user_placeholder=Buscar usuario… settings.org_not_allowed_to_be_collaborator=Las organizaciones no pueden ser añadidas como colaboradoras. +settings.add_team_duplicate=El equipo ya tiene acceso al repositorio +settings.add_team_success=Ahora el equipo ya tiene acceso al repositorio. +settings.remove_team_success=Se ha eliminado el acceso del equipo al repositorio. settings.add_webhook=Añadir Webhook settings.add_webhook.invalid_channel_name=El nombre del canal Webhook no puede estar vacío y no puede contener sólo un # carácter. settings.hooks_desc=Los webhooks automáticamente hacen peticiones HTTP POST a un servidor cuando ciertos eventos de Gitea se activan. Lee más en la guía de webhooks. @@ -1257,6 +1261,7 @@ settings.event_pull_request=Pull Request settings.event_pull_request_desc=Pull Request abierta, cerrada, reabierta, editada, aprobada, rechazada, comentario de revisión, asignada, no asignada, etiqueta actualizada, etiqueta borrada o sincronizada. settings.event_push=Push settings.event_push_desc=Git push a un repositorio. +settings.branch_filter=Filtro de rama settings.event_repository=Repositorio settings.event_repository_desc=Repositorio creado o eliminado. settings.active=Activo @@ -1307,6 +1312,8 @@ settings.protect_merge_whitelist_committers=Activar lista blanca para fusionar settings.protect_merge_whitelist_committers_desc=Permitir a los usuarios o equipos de la lista a fusionar peticiones pull dentro de esta rama. settings.protect_merge_whitelist_users=Usuarios en la lista blanca para fusionar: settings.protect_merge_whitelist_teams=Equipos en la lista blanca para fusionar: +settings.protect_check_status_contexts=Habilitar comprobación de estado +settings.protect_check_status_contexts_list=Comprobaciones de estado para este repositorio encontradas durante la semana pasada settings.protect_required_approvals=Aprobaciones requeridas: settings.protect_required_approvals_desc=Permitir solo fusionar un pull request con suficientes revisiones positivas de usuarios o equipos en la lista blanca. settings.protect_approvals_whitelist_users=Lista blanca de usuarios revisores: @@ -1354,6 +1361,10 @@ diff.whitespace_ignore_at_eol=Ignorar cambios en espacios en blanco al final de diff.stats_desc=Se han modificado %d ficheros con %d adiciones y %d borrados diff.bin=BIN diff.view_file=Ver fichero +diff.file_before=Antes +diff.file_after=Después +diff.file_image_width=Anchura +diff.file_image_height=Altura diff.file_byte_size=Tamaño diff.file_suppressed=La diferencia del archivo ha sido suprimido porque es demasiado grande diff.too_many_files=Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio @@ -1704,6 +1715,7 @@ auths.tip.google_plus=Obtener credenciales de cliente OAuth2 desde la consola AP auths.tip.openid_connect=Use el OpenID Connect Discovery URL (/.well-known/openid-configuration) para especificar los puntos finales auths.tip.twitter=Ir a https://dev.twitter.com/apps, crear una aplicación y asegurarse de que la opción "Permitir que esta aplicación sea usada para iniciar sesión con Twitter" está activada auths.tip.discord=Registrar una nueva aplicación en https://discordapp.com/developers/applications/me +auths.tip.gitea=Registra una nueva aplicación OAuth2. La guía puede ser encontrada en https://docs.gitea.io/es-us/oauth2-provider/ auths.edit=Editar origen de autenticación auths.activated=Este origen de autenticación ha sido activado auths.new_success=Se agregó la autenticación '%s'. diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 21a1b7e269035..f8a21ac0f0588 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -632,6 +632,8 @@ migrate.lfs_mirror_unsupported=LFS objektu spoguļošana netiek atbalstīta - t migrate.migrate_items_options=Pārņemot datus no GitHub, ievadiet lietotāja vārdu, lai redzētu papildus iestatījumus. migrated_from=Migrēts no %[2]s migrated_from_fake=Migrēts no %[1]s +migrate.migrating=Migrācija no %s ... +migrate.migrating_failed=Migrācija no %s neizdevās. mirror_from=spogulis no forked_from=atdalīts no From ba716705b5420707fac05d362f986c9aee359ad2 Mon Sep 17 00:00:00 2001 From: Benson Muite Date: Sun, 13 Oct 2019 23:07:30 +0300 Subject: [PATCH 073/173] Update seek-help.en-us.md (#8487) Update link to Mandarin help --- docs/content/doc/help/seek-help.en-us.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/doc/help/seek-help.en-us.md b/docs/content/doc/help/seek-help.en-us.md index e9d0211029ea5..058a5bb592b5e 100644 --- a/docs/content/doc/help/seek-help.en-us.md +++ b/docs/content/doc/help/seek-help.en-us.md @@ -33,4 +33,4 @@ If you found a bug, please create an [issue on GitHub](https://github.com/go-git ## Chinese Support -Support for the Chinese language is provided at [gocn.io](https://gocn.io/topic/Gitea). +Support for the Chinese language is provided at [gocn.vip](https://gocn.vip/topic/gitea). From 0c680f337d7ab71f530ccb41a499aa9371b7e161 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sun, 13 Oct 2019 20:23:11 +0000 Subject: [PATCH 074/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_es-ES.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index f5355a488fa7b..b5fa9b3bddfb7 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -1209,6 +1209,7 @@ settings.collaborator_deletion_desc=Eliminar un colaborador revocará su acceso settings.remove_collaborator_success=El colaborador ha sido eliminado. settings.search_user_placeholder=Buscar usuario… settings.org_not_allowed_to_be_collaborator=Las organizaciones no pueden ser añadidas como colaboradoras. +settings.team_not_in_organization=El equipo no pertenece a la misma organización que el repositorio settings.add_team_duplicate=El equipo ya tiene acceso al repositorio settings.add_team_success=Ahora el equipo ya tiene acceso al repositorio. settings.remove_team_success=Se ha eliminado el acceso del equipo al repositorio. From 6e3f51098b29cd5c61d62732a42a7554cbc8cc2f Mon Sep 17 00:00:00 2001 From: Benson Muite Date: Mon, 14 Oct 2019 00:36:09 +0300 Subject: [PATCH 075/173] Update seek-help.zh-cn.md (#8488) Update link to Mandarin help forum --- docs/content/doc/help/seek-help.zh-cn.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/doc/help/seek-help.zh-cn.md b/docs/content/doc/help/seek-help.zh-cn.md index ac62b9b8cf68d..7e4e2f1beb3a5 100644 --- a/docs/content/doc/help/seek-help.zh-cn.md +++ b/docs/content/doc/help/seek-help.zh-cn.md @@ -18,6 +18,6 @@ menu: 如果您在使用或者开发过程中遇到问题,请到以下渠道咨询: - 到[Github issue](https://github.com/go-gitea/gitea/issues)提问(因为项目维护人员来自世界各地,为保证沟通顺畅,请使用英文提问) -- 中文问题到[gocn.io](https://gocn.io/topic/Gitea)提问 +- 中文问题到[gocn.vip](https://gocn.vip/topic/gitea)提问 - 访问 [Discord server - 英文](https://discord.gg/NsatcWJ) - 加入 QQ群 328432459 获得进一步的支持 From 15809d81f7d36759f289b941352a9754611c5dba Mon Sep 17 00:00:00 2001 From: guillep2k <18600385+guillep2k@users.noreply.github.com> Date: Sun, 13 Oct 2019 19:29:10 -0300 Subject: [PATCH 076/173] Rewrite reference processing code in preparation for opening/closing from comment references (#8261) * Add a markdown stripper for mentions and xrefs * Improve comments * Small code simplification * Move reference code to modules/references * Fix typo * Make MarkdownStripper return [][]byte * Implement preliminary keywords parsing * Add FIXME comment * Fix comment * make fmt * Fix permissions check * Fix text assumptions * Fix imports * Fix lint, fmt * Fix unused import * Add missing export comment * Bypass revive on implemented interface * Move mdstripper into its own package * Support alphanumeric patterns * Refactor FindAllMentions * Move mentions test to references * Parse mentions from reference package * Refactor code to implement renderizable references * Fix typo * Move patterns and tests to the references package * Fix nil reference * Preliminary rendering attempt of closing keywords * Normalize names, comments, general tidy-up * Add CSS style for action keywords * Fix permission for admin and owner * Fix golangci-lint * Fix golangci-lint --- integrations/issue_test.go | 13 +- models/action.go | 177 +++------- models/action_test.go | 53 +-- models/issue_comment.go | 11 +- models/issue_xref.go | 111 +++---- modules/markup/html.go | 124 +++---- modules/markup/html_internal_test.go | 92 ------ modules/markup/mdstripper/mdstripper.go | 260 +++++++++++++++ modules/markup/mdstripper/mdstripper_test.go | 71 ++++ modules/markup/sanitizer.go | 3 + modules/references/references.go | 322 +++++++++++++++++++ modules/references/references_test.go | 296 +++++++++++++++++ public/css/index.css | 1 + public/less/_repository.less | 5 + services/mailer/mail_comment.go | 4 +- services/mailer/mail_issue.go | 4 +- 16 files changed, 1116 insertions(+), 431 deletions(-) create mode 100644 modules/markup/mdstripper/mdstripper.go create mode 100644 modules/markup/mdstripper/mdstripper_test.go create mode 100644 modules/references/references.go create mode 100644 modules/references/references_test.go diff --git a/integrations/issue_test.go b/integrations/issue_test.go index 0b153607ee645..aa17c44254fc2 100644 --- a/integrations/issue_test.go +++ b/integrations/issue_test.go @@ -13,6 +13,7 @@ import ( "testing" "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/references" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/test" @@ -207,7 +208,7 @@ func TestIssueCrossReference(t *testing.T) { RefIssueID: issueRef.ID, RefCommentID: 0, RefIsPull: false, - RefAction: models.XRefActionNone}) + RefAction: references.XRefActionNone}) // Edit title, neuter ref testIssueChangeInfo(t, "user2", issueRefURL, "title", "Title no ref") @@ -217,7 +218,7 @@ func TestIssueCrossReference(t *testing.T) { RefIssueID: issueRef.ID, RefCommentID: 0, RefIsPull: false, - RefAction: models.XRefActionNeutered}) + RefAction: references.XRefActionNeutered}) // Ref from issue content issueRefURL, issueRef = testIssueWithBean(t, "user2", 1, "TitleXRef", fmt.Sprintf("Description ref #%d", issueBase.Index)) @@ -227,7 +228,7 @@ func TestIssueCrossReference(t *testing.T) { RefIssueID: issueRef.ID, RefCommentID: 0, RefIsPull: false, - RefAction: models.XRefActionNone}) + RefAction: references.XRefActionNone}) // Edit content, neuter ref testIssueChangeInfo(t, "user2", issueRefURL, "content", "Description no ref") @@ -237,7 +238,7 @@ func TestIssueCrossReference(t *testing.T) { RefIssueID: issueRef.ID, RefCommentID: 0, RefIsPull: false, - RefAction: models.XRefActionNeutered}) + RefAction: references.XRefActionNeutered}) // Ref from a comment session := loginUser(t, "user2") @@ -248,7 +249,7 @@ func TestIssueCrossReference(t *testing.T) { RefIssueID: issueRef.ID, RefCommentID: commentID, RefIsPull: false, - RefAction: models.XRefActionNone} + RefAction: references.XRefActionNone} models.AssertExistsAndLoadBean(t, comment) // Ref from a different repository @@ -259,7 +260,7 @@ func TestIssueCrossReference(t *testing.T) { RefIssueID: issueRef.ID, RefCommentID: 0, RefIsPull: false, - RefAction: models.XRefActionNone}) + RefAction: references.XRefActionNone}) } func testIssueWithBean(t *testing.T, user string, repoID int64, title, content string) (string, *models.Issue) { diff --git a/models/action.go b/models/action.go index 87088101f97fc..2d2999f8809a4 100644 --- a/models/action.go +++ b/models/action.go @@ -10,15 +10,14 @@ import ( "fmt" "html" "path" - "regexp" "strconv" "strings" "time" - "unicode" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/references" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" @@ -54,29 +53,6 @@ const ( ActionMirrorSyncDelete // 20 ) -var ( - // Same as GitHub. See - // https://help.github.com/articles/closing-issues-via-commit-messages - issueCloseKeywords = []string{"close", "closes", "closed", "fix", "fixes", "fixed", "resolve", "resolves", "resolved"} - issueReopenKeywords = []string{"reopen", "reopens", "reopened"} - - issueCloseKeywordsPat, issueReopenKeywordsPat *regexp.Regexp - issueReferenceKeywordsPat *regexp.Regexp -) - -const issueRefRegexpStr = `(?:([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+))?(#[0-9]+)+` -const issueRefRegexpStrNoKeyword = `(?:\s|^|\(|\[)(?:([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+))?(#[0-9]+)(?:\s|$|\)|\]|:|\.(\s|$))` - -func assembleKeywordsPattern(words []string) string { - return fmt.Sprintf(`(?i)(?:%s)(?::?) %s`, strings.Join(words, "|"), issueRefRegexpStr) -} - -func init() { - issueCloseKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueCloseKeywords)) - issueReopenKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueReopenKeywords)) - issueReferenceKeywordsPat = regexp.MustCompile(issueRefRegexpStrNoKeyword) -} - // Action represents user operation type and other information to // repository. It implemented interface base.Actioner so that can be // used in template render. @@ -351,10 +327,6 @@ func RenameRepoAction(actUser *User, oldRepoName string, repo *Repository) error return renameRepoAction(x, actUser, oldRepoName, repo) } -func issueIndexTrimRight(c rune) bool { - return !unicode.IsDigit(c) -} - // PushCommit represents a commit in a push operation. type PushCommit struct { Sha1 string @@ -480,39 +452,9 @@ func (pc *PushCommits) AvatarLink(email string) string { } // getIssueFromRef returns the issue referenced by a ref. Returns a nil *Issue -// if the provided ref is misformatted or references a non-existent issue. -func getIssueFromRef(repo *Repository, ref string) (*Issue, error) { - ref = ref[strings.IndexByte(ref, ' ')+1:] - ref = strings.TrimRightFunc(ref, issueIndexTrimRight) - - var refRepo *Repository - poundIndex := strings.IndexByte(ref, '#') - if poundIndex < 0 { - return nil, nil - } else if poundIndex == 0 { - refRepo = repo - } else { - slashIndex := strings.IndexByte(ref, '/') - if slashIndex < 0 || slashIndex >= poundIndex { - return nil, nil - } - ownerName := ref[:slashIndex] - repoName := ref[slashIndex+1 : poundIndex] - var err error - refRepo, err = GetRepositoryByOwnerAndName(ownerName, repoName) - if err != nil { - if IsErrRepoNotExist(err) { - return nil, nil - } - return nil, err - } - } - issueIndex, err := strconv.ParseInt(ref[poundIndex+1:], 10, 64) - if err != nil { - return nil, nil - } - - issue, err := GetIssueByIndex(refRepo.ID, issueIndex) +// if the provided ref references a non-existent issue. +func getIssueFromRef(repo *Repository, index int64) (*Issue, error) { + issue, err := GetIssueByIndex(repo.ID, index) if err != nil { if IsErrIssueNotExist(err) { return nil, nil @@ -522,20 +464,7 @@ func getIssueFromRef(repo *Repository, ref string) (*Issue, error) { return issue, nil } -func changeIssueStatus(repo *Repository, doer *User, ref string, refMarked map[int64]bool, status bool) error { - issue, err := getIssueFromRef(repo, ref) - if err != nil { - return err - } - - if issue == nil || refMarked[issue.ID] { - return nil - } - refMarked[issue.ID] = true - - if issue.RepoID != repo.ID || issue.IsClosed == status { - return nil - } +func changeIssueStatus(repo *Repository, issue *Issue, doer *User, status bool) error { stopTimerIfAvailable := func(doer *User, issue *Issue) error { @@ -549,7 +478,7 @@ func changeIssueStatus(repo *Repository, doer *User, ref string, refMarked map[i } issue.Repo = repo - if err = issue.ChangeStatus(doer, status); err != nil { + if err := issue.ChangeStatus(doer, status); err != nil { // Don't return an error when dependencies are open as this would let the push fail if IsErrDependenciesLeft(err) { return stopTimerIfAvailable(doer, issue) @@ -566,99 +495,67 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit, bra for i := len(commits) - 1; i >= 0; i-- { c := commits[i] - refMarked := make(map[int64]bool) + type markKey struct { + ID int64 + Action references.XRefAction + } + + refMarked := make(map[markKey]bool) var refRepo *Repository + var refIssue *Issue var err error - for _, m := range issueReferenceKeywordsPat.FindAllStringSubmatch(c.Message, -1) { - if len(m[3]) == 0 { - continue - } - ref := m[3] + for _, ref := range references.FindAllIssueReferences(c.Message) { // issue is from another repo - if len(m[1]) > 0 && len(m[2]) > 0 { - refRepo, err = GetRepositoryFromMatch(m[1], m[2]) + if len(ref.Owner) > 0 && len(ref.Name) > 0 { + refRepo, err = GetRepositoryFromMatch(ref.Owner, ref.Name) if err != nil { continue } } else { refRepo = repo } - issue, err := getIssueFromRef(refRepo, ref) - if err != nil { + if refIssue, err = getIssueFromRef(refRepo, ref.Index); err != nil { return err } - - if issue == nil || refMarked[issue.ID] { + if refIssue == nil { continue } - refMarked[issue.ID] = true - message := fmt.Sprintf(`%s`, repo.Link(), c.Sha1, html.EscapeString(c.Message)) - if err = CreateRefComment(doer, refRepo, issue, message, c.Sha1); err != nil { + perm, err := GetUserRepoPermission(refRepo, doer) + if err != nil { return err } - } - // Change issue status only if the commit has been pushed to the default branch. - // and if the repo is configured to allow only that - if repo.DefaultBranch != branchName && !repo.CloseIssuesViaCommitInAnyBranch { - continue - } - refMarked = make(map[int64]bool) - for _, m := range issueCloseKeywordsPat.FindAllStringSubmatch(c.Message, -1) { - if len(m[3]) == 0 { + key := markKey{ID: refIssue.ID, Action: ref.Action} + if refMarked[key] { continue } - ref := m[3] + refMarked[key] = true - // issue is from another repo - if len(m[1]) > 0 && len(m[2]) > 0 { - refRepo, err = GetRepositoryFromMatch(m[1], m[2]) - if err != nil { - continue - } - } else { - refRepo = repo - } - - perm, err := GetUserRepoPermission(refRepo, doer) - if err != nil { - return err - } - // only close issues in another repo if user has push access - if perm.CanWrite(UnitTypeCode) { - if err := changeIssueStatus(refRepo, doer, ref, refMarked, true); err != nil { + // only create comments for issues if user has permission for it + if perm.IsAdmin() || perm.IsOwner() || perm.CanWrite(UnitTypeIssues) { + message := fmt.Sprintf(`%s`, repo.Link(), c.Sha1, html.EscapeString(c.Message)) + if err = CreateRefComment(doer, refRepo, refIssue, message, c.Sha1); err != nil { return err } } - } - // It is conflict to have close and reopen at same time, so refsMarked doesn't need to reinit here. - for _, m := range issueReopenKeywordsPat.FindAllStringSubmatch(c.Message, -1) { - if len(m[3]) == 0 { + // Process closing/reopening keywords + if ref.Action != references.XRefActionCloses && ref.Action != references.XRefActionReopens { continue } - ref := m[3] - // issue is from another repo - if len(m[1]) > 0 && len(m[2]) > 0 { - refRepo, err = GetRepositoryFromMatch(m[1], m[2]) - if err != nil { - continue - } - } else { - refRepo = repo - } - - perm, err := GetUserRepoPermission(refRepo, doer) - if err != nil { - return err + // Change issue status only if the commit has been pushed to the default branch. + // and if the repo is configured to allow only that + // FIXME: we should be using Issue.ref if set instead of repo.DefaultBranch + if repo.DefaultBranch != branchName && !repo.CloseIssuesViaCommitInAnyBranch { + continue } - // only reopen issues in another repo if user has push access - if perm.CanWrite(UnitTypeCode) { - if err := changeIssueStatus(refRepo, doer, ref, refMarked, false); err != nil { + // only close issues in another repo if user has push access + if perm.IsAdmin() || perm.IsOwner() || perm.CanWrite(UnitTypeCode) { + if err := changeIssueStatus(refRepo, refIssue, doer, ref.Action == references.XRefActionCloses); err != nil { return err } } diff --git a/models/action_test.go b/models/action_test.go index c90538ebe6024..df41556850d0c 100644 --- a/models/action_test.go +++ b/models/action_test.go @@ -1,7 +1,6 @@ package models import ( - "fmt" "path" "strings" "testing" @@ -181,56 +180,6 @@ func TestPushCommits_AvatarLink(t *testing.T) { pushCommits.AvatarLink("nonexistent@example.com")) } -func TestRegExp_issueReferenceKeywordsPat(t *testing.T) { - trueTestCases := []string{ - "#2", - "[#2]", - "please see go-gitea/gitea#5", - "#2:", - } - falseTestCases := []string{ - "kb#2", - "#2xy", - } - - for _, testCase := range trueTestCases { - assert.True(t, issueReferenceKeywordsPat.MatchString(testCase)) - } - for _, testCase := range falseTestCases { - assert.False(t, issueReferenceKeywordsPat.MatchString(testCase)) - } -} - -func Test_getIssueFromRef(t *testing.T) { - assert.NoError(t, PrepareTestDatabase()) - repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) - for _, test := range []struct { - Ref string - ExpectedIssueID int64 - }{ - {"#2", 2}, - {"reopen #2", 2}, - {"user2/repo2#1", 4}, - {"fixes user2/repo2#1", 4}, - {"fixes: user2/repo2#1", 4}, - } { - issue, err := getIssueFromRef(repo, test.Ref) - assert.NoError(t, err) - if assert.NotNil(t, issue) { - assert.EqualValues(t, test.ExpectedIssueID, issue.ID) - } - } - - for _, badRef := range []string{ - "doesnotexist/doesnotexist#1", - fmt.Sprintf("#%d", NonexistentID), - } { - issue, err := getIssueFromRef(repo, badRef) - assert.NoError(t, err) - assert.Nil(t, issue) - } -} - func TestUpdateIssuesCommit(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) pushCommits := []*PushCommit{ @@ -431,7 +380,7 @@ func TestUpdateIssuesCommit_AnotherRepoNoPermission(t *testing.T) { AssertNotExistsBean(t, commentBean) AssertNotExistsBean(t, issueBean, "is_closed=1") assert.NoError(t, UpdateIssuesCommit(user, repo, pushCommits, repo.DefaultBranch)) - AssertExistsAndLoadBean(t, commentBean) + AssertNotExistsBean(t, commentBean) AssertNotExistsBean(t, issueBean, "is_closed=1") CheckConsistencyFor(t, &Action{}) } diff --git a/models/issue_comment.go b/models/issue_comment.go index e8043c1ec7f3a..7d38302b98dbb 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup/markdown" + "code.gitea.io/gitea/modules/references" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" @@ -144,10 +145,10 @@ type Comment struct { // Reference an issue or pull from another comment, issue or PR // All information is about the origin of the reference - RefRepoID int64 `xorm:"index"` // Repo where the referencing - RefIssueID int64 `xorm:"index"` - RefCommentID int64 `xorm:"index"` // 0 if origin is Issue title or content (or PR's) - RefAction XRefAction `xorm:"SMALLINT"` // What hapens if RefIssueID resolves + RefRepoID int64 `xorm:"index"` // Repo where the referencing + RefIssueID int64 `xorm:"index"` + RefCommentID int64 `xorm:"index"` // 0 if origin is Issue title or content (or PR's) + RefAction references.XRefAction `xorm:"SMALLINT"` // What hapens if RefIssueID resolves RefIsPull bool RefRepo *Repository `xorm:"-"` @@ -773,7 +774,7 @@ type CreateCommentOptions struct { RefRepoID int64 RefIssueID int64 RefCommentID int64 - RefAction XRefAction + RefAction references.XRefAction RefIsPull bool } diff --git a/models/issue_xref.go b/models/issue_xref.go index 1cc0bcfe6a11e..141a7e0e8cc71 100644 --- a/models/issue_xref.go +++ b/models/issue_xref.go @@ -5,42 +5,16 @@ package models import ( - "regexp" - "strconv" - "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/references" "github.com/go-xorm/xorm" "github.com/unknwon/com" ) -var ( - // TODO: Unify all regexp treatment of cross references in one place - - // issueNumericPattern matches string that references to a numeric issue, e.g. #1287 - issueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)(?:#)([0-9]+)(?:\s|$|\)|\]|:|\.(\s|$))`) - // crossReferenceIssueNumericPattern matches string that references a numeric issue in a different repository - // e.g. gogits/gogs#12345 - crossReferenceIssueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+)#([0-9]+)(?:\s|$|\)|\]|\.(\s|$))`) -) - -// XRefAction represents the kind of effect a cross reference has once is resolved -type XRefAction int64 - -const ( - // XRefActionNone means the cross-reference is a mention (commit, etc.) - XRefActionNone XRefAction = iota // 0 - // XRefActionCloses means the cross-reference should close an issue if it is resolved - XRefActionCloses // 1 - not implemented yet - // XRefActionReopens means the cross-reference should reopen an issue if it is resolved - XRefActionReopens // 2 - Not implemented yet - // XRefActionNeutered means the cross-reference will no longer affect the source - XRefActionNeutered // 3 -) - type crossReference struct { Issue *Issue - Action XRefAction + Action references.XRefAction } // crossReferencesContext is context to pass along findCrossReference functions @@ -72,7 +46,7 @@ func newCrossReference(e *xorm.Session, ctx *crossReferencesContext, xref *cross func neuterCrossReferences(e Engine, issueID int64, commentID int64) error { active := make([]*Comment, 0, 10) - sess := e.Where("`ref_action` IN (?, ?, ?)", XRefActionNone, XRefActionCloses, XRefActionReopens) + sess := e.Where("`ref_action` IN (?, ?, ?)", references.XRefActionNone, references.XRefActionCloses, references.XRefActionReopens) if issueID != 0 { sess = sess.And("`ref_issue_id` = ?", issueID) } @@ -86,7 +60,7 @@ func neuterCrossReferences(e Engine, issueID int64, commentID int64) error { for i, c := range active { ids[i] = c.ID } - _, err := e.In("id", ids).Cols("`ref_action`").Update(&Comment{RefAction: XRefActionNeutered}) + _, err := e.In("id", ids).Cols("`ref_action`").Update(&Comment{RefAction: references.XRefActionNeutered}) return err } @@ -110,11 +84,11 @@ func (issue *Issue) addCrossReferences(e *xorm.Session, doer *User) error { Doer: doer, OrigIssue: issue, } - return issue.createCrossReferences(e, ctx, issue.Title+"\n"+issue.Content) + return issue.createCrossReferences(e, ctx, issue.Title, issue.Content) } -func (issue *Issue) createCrossReferences(e *xorm.Session, ctx *crossReferencesContext, content string) error { - xreflist, err := ctx.OrigIssue.getCrossReferences(e, ctx, content) +func (issue *Issue) createCrossReferences(e *xorm.Session, ctx *crossReferencesContext, plaincontent, mdcontent string) error { + xreflist, err := ctx.OrigIssue.getCrossReferences(e, ctx, plaincontent, mdcontent) if err != nil { return err } @@ -126,47 +100,43 @@ func (issue *Issue) createCrossReferences(e *xorm.Session, ctx *crossReferencesC return nil } -func (issue *Issue) getCrossReferences(e *xorm.Session, ctx *crossReferencesContext, content string) ([]*crossReference, error) { +func (issue *Issue) getCrossReferences(e *xorm.Session, ctx *crossReferencesContext, plaincontent, mdcontent string) ([]*crossReference, error) { xreflist := make([]*crossReference, 0, 5) - var xref *crossReference - - // Issues in the same repository - // FIXME: Should we support IssueNameStyleAlphanumeric? - matches := issueNumericPattern.FindAllStringSubmatch(content, -1) - for _, match := range matches { - if index, err := strconv.ParseInt(match[1], 10, 64); err == nil { - if err = ctx.OrigIssue.loadRepo(e); err != nil { + var ( + refRepo *Repository + refIssue *Issue + err error + ) + + allrefs := append(references.FindAllIssueReferences(plaincontent), references.FindAllIssueReferencesMarkdown(mdcontent)...) + + for _, ref := range allrefs { + if ref.Owner == "" && ref.Name == "" { + // Issues in the same repository + if err := ctx.OrigIssue.loadRepo(e); err != nil { return nil, err } - if xref, err = ctx.OrigIssue.isValidCommentReference(e, ctx, issue.Repo, index); err != nil { - return nil, err - } - if xref != nil { - xreflist = ctx.OrigIssue.updateCrossReferenceList(xreflist, xref) - } - } - } - - // Issues in other repositories - matches = crossReferenceIssueNumericPattern.FindAllStringSubmatch(content, -1) - for _, match := range matches { - if index, err := strconv.ParseInt(match[3], 10, 64); err == nil { - repo, err := getRepositoryByOwnerAndName(e, match[1], match[2]) + refRepo = ctx.OrigIssue.Repo + } else { + // Issues in other repositories + refRepo, err = getRepositoryByOwnerAndName(e, ref.Owner, ref.Name) if err != nil { if IsErrRepoNotExist(err) { continue } return nil, err } - if err = ctx.OrigIssue.loadRepo(e); err != nil { - return nil, err - } - if xref, err = issue.isValidCommentReference(e, ctx, repo, index); err != nil { - return nil, err - } - if xref != nil { - xreflist = issue.updateCrossReferenceList(xreflist, xref) - } + } + if refIssue, err = ctx.OrigIssue.findReferencedIssue(e, ctx, refRepo, ref.Index); err != nil { + return nil, err + } + if refIssue != nil { + xreflist = ctx.OrigIssue.updateCrossReferenceList(xreflist, &crossReference{ + Issue: refIssue, + // FIXME: currently ignore keywords + // Action: ref.Action, + Action: references.XRefActionNone, + }) } } @@ -179,7 +149,7 @@ func (issue *Issue) updateCrossReferenceList(list []*crossReference, xref *cross } for i, r := range list { if r.Issue.ID == xref.Issue.ID { - if xref.Action != XRefActionNone { + if xref.Action != references.XRefActionNone { list[i].Action = xref.Action } return list @@ -188,7 +158,7 @@ func (issue *Issue) updateCrossReferenceList(list []*crossReference, xref *cross return append(list, xref) } -func (issue *Issue) isValidCommentReference(e Engine, ctx *crossReferencesContext, repo *Repository, index int64) (*crossReference, error) { +func (issue *Issue) findReferencedIssue(e Engine, ctx *crossReferencesContext, repo *Repository, index int64) (*Issue, error) { refIssue := &Issue{RepoID: repo.ID, Index: index} if has, _ := e.Get(refIssue); !has { return nil, nil @@ -206,10 +176,7 @@ func (issue *Issue) isValidCommentReference(e Engine, ctx *crossReferencesContex return nil, nil } } - return &crossReference{ - Issue: refIssue, - Action: XRefActionNone, - }, nil + return refIssue, nil } func (issue *Issue) neuterCrossReferences(e Engine) error { @@ -237,7 +204,7 @@ func (comment *Comment) addCrossReferences(e *xorm.Session, doer *User) error { OrigIssue: comment.Issue, OrigComment: comment, } - return comment.Issue.createCrossReferences(e, ctx, comment.Content) + return comment.Issue.createCrossReferences(e, ctx, "", comment.Content) } func (comment *Comment) neuterCrossReferences(e Engine) error { diff --git a/modules/markup/html.go b/modules/markup/html.go index f07993bc4cc8f..fc823b1f308ab 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/references" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" @@ -36,17 +37,6 @@ var ( // While fast, this is also incorrect and lead to false positives. // TODO: fix invalid linking issue - // mentionPattern matches all mentions in the form of "@user" - mentionPattern = regexp.MustCompile(`(?:\s|^|\(|\[)(@[0-9a-zA-Z-_\.]+)(?:\s|$|\)|\])`) - - // issueNumericPattern matches string that references to a numeric issue, e.g. #1287 - issueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)(#[0-9]+)(?:\s|$|\)|\]|:|\.(\s|$))`) - // issueAlphanumericPattern matches string that references to an alphanumeric issue, e.g. ABC-1234 - issueAlphanumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([A-Z]{1,10}-[1-9][0-9]*)(?:\s|$|\)|\]|:|\.(\s|$))`) - // crossReferenceIssueNumericPattern matches string that references a numeric issue in a different repository - // e.g. gogits/gogs#12345 - crossReferenceIssueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+/[0-9a-zA-Z-_\.]+#[0-9]+)(?:\s|$|\)|\]|\.(\s|$))`) - // sha1CurrentPattern matches string that represents a commit SHA, e.g. d8a994ef243349f321568f9e36d5c3f444b99cae // Although SHA1 hashes are 40 chars long, the regex matches the hash from 7 to 40 chars in length // so that abbreviated hash links can be used as well. This matches git and github useability. @@ -70,6 +60,9 @@ var ( linkRegex, _ = xurls.StrictMatchingScheme("https?://") ) +// CSS class for action keywords (e.g. "closes: #1") +const keywordClass = "issue-keyword" + // regexp for full links to issues/pulls var issueFullPattern *regexp.Regexp @@ -99,17 +92,6 @@ func getIssueFullPattern() *regexp.Regexp { return issueFullPattern } -// FindAllMentions matches mention patterns in given content -// and returns a list of found user names without @ prefix. -func FindAllMentions(content string) []string { - mentions := mentionPattern.FindAllStringSubmatch(content, -1) - ret := make([]string, len(mentions)) - for i, val := range mentions { - ret[i] = val[1][1:] - } - return ret -} - // IsSameDomain checks if given url string has the same hostname as current Gitea instance func IsSameDomain(s string) bool { if strings.HasPrefix(s, "/") { @@ -142,7 +124,6 @@ var defaultProcessors = []processor{ linkProcessor, mentionProcessor, issueIndexPatternProcessor, - crossReferenceIssueIndexPatternProcessor, sha1CurrentPatternProcessor, emailAddressProcessor, } @@ -183,7 +164,6 @@ var commitMessageProcessors = []processor{ linkProcessor, mentionProcessor, issueIndexPatternProcessor, - crossReferenceIssueIndexPatternProcessor, sha1CurrentPatternProcessor, emailAddressProcessor, } @@ -217,7 +197,6 @@ var commitMessageSubjectProcessors = []processor{ linkProcessor, mentionProcessor, issueIndexPatternProcessor, - crossReferenceIssueIndexPatternProcessor, sha1CurrentPatternProcessor, } @@ -330,6 +309,24 @@ func (ctx *postProcessCtx) textNode(node *html.Node) { } } +// createKeyword() renders a highlighted version of an action keyword +func createKeyword(content string) *html.Node { + span := &html.Node{ + Type: html.ElementNode, + Data: atom.Span.String(), + Attr: []html.Attribute{}, + } + span.Attr = append(span.Attr, html.Attribute{Key: "class", Val: keywordClass}) + + text := &html.Node{ + Type: html.TextNode, + Data: content, + } + span.AppendChild(text) + + return span +} + func createLink(href, content, class string) *html.Node { a := &html.Node{ Type: html.ElementNode, @@ -377,10 +374,16 @@ func createCodeLink(href, content, class string) *html.Node { return a } -// replaceContent takes a text node, and in its content it replaces a section of -// it with the specified newNode. An example to visualize how this can work can -// be found here: https://play.golang.org/p/5zP8NnHZ03s +// replaceContent takes text node, and in its content it replaces a section of +// it with the specified newNode. func replaceContent(node *html.Node, i, j int, newNode *html.Node) { + replaceContentList(node, i, j, []*html.Node{newNode}) +} + +// replaceContentList takes text node, and in its content it replaces a section of +// it with the specified newNodes. An example to visualize how this can work can +// be found here: https://play.golang.org/p/5zP8NnHZ03s +func replaceContentList(node *html.Node, i, j int, newNodes []*html.Node) { // get the data before and after the match before := node.Data[:i] after := node.Data[j:] @@ -392,7 +395,9 @@ func replaceContent(node *html.Node, i, j int, newNode *html.Node) { // Get the current next sibling, before which we place the replaced data, // and after that we place the new text node. nextSibling := node.NextSibling - node.Parent.InsertBefore(newNode, nextSibling) + for _, n := range newNodes { + node.Parent.InsertBefore(n, nextSibling) + } if after != "" { node.Parent.InsertBefore(&html.Node{ Type: html.TextNode, @@ -402,13 +407,13 @@ func replaceContent(node *html.Node, i, j int, newNode *html.Node) { } func mentionProcessor(_ *postProcessCtx, node *html.Node) { - m := mentionPattern.FindStringSubmatchIndex(node.Data) - if m == nil { + // We replace only the first mention; other mentions will be addressed later + found, loc := references.FindFirstMentionBytes([]byte(node.Data)) + if !found { return } - // Replace the mention with a link to the specified user. - mention := node.Data[m[2]:m[3]] - replaceContent(node, m[2], m[3], createLink(util.URLJoin(setting.AppURL, mention[1:]), mention, "mention")) + mention := node.Data[loc.Start:loc.End] + replaceContent(node, loc.Start, loc.End, createLink(util.URLJoin(setting.AppURL, mention[1:]), mention, "mention")) } func shortLinkProcessor(ctx *postProcessCtx, node *html.Node) { @@ -597,45 +602,44 @@ func issueIndexPatternProcessor(ctx *postProcessCtx, node *html.Node) { if ctx.metas == nil { return } - // default to numeric pattern, unless alphanumeric is requested. - pattern := issueNumericPattern + + var ( + found bool + ref *references.RenderizableReference + ) + if ctx.metas["style"] == IssueNameStyleAlphanumeric { - pattern = issueAlphanumericPattern + found, ref = references.FindRenderizableReferenceAlphanumeric(node.Data) + } else { + found, ref = references.FindRenderizableReferenceNumeric(node.Data) } - - match := pattern.FindStringSubmatchIndex(node.Data) - if match == nil { + if !found { return } - id := node.Data[match[2]:match[3]] var link *html.Node + reftext := node.Data[ref.RefLocation.Start:ref.RefLocation.End] if _, ok := ctx.metas["format"]; ok { - // Support for external issue tracker - if ctx.metas["style"] == IssueNameStyleAlphanumeric { - ctx.metas["index"] = id - } else { - ctx.metas["index"] = id[1:] - } - link = createLink(com.Expand(ctx.metas["format"], ctx.metas), id, "issue") + ctx.metas["index"] = ref.Issue + link = createLink(com.Expand(ctx.metas["format"], ctx.metas), reftext, "issue") + } else if ref.Owner == "" { + link = createLink(util.URLJoin(setting.AppURL, ctx.metas["user"], ctx.metas["repo"], "issues", ref.Issue), reftext, "issue") } else { - link = createLink(util.URLJoin(setting.AppURL, ctx.metas["user"], ctx.metas["repo"], "issues", id[1:]), id, "issue") + link = createLink(util.URLJoin(setting.AppURL, ref.Owner, ref.Name, "issues", ref.Issue), reftext, "issue") } - replaceContent(node, match[2], match[3], link) -} -func crossReferenceIssueIndexPatternProcessor(ctx *postProcessCtx, node *html.Node) { - m := crossReferenceIssueNumericPattern.FindStringSubmatchIndex(node.Data) - if m == nil { + if ref.Action == references.XRefActionNone { + replaceContent(node, ref.RefLocation.Start, ref.RefLocation.End, link) return } - ref := node.Data[m[2]:m[3]] - parts := strings.SplitN(ref, "#", 2) - repo, issue := parts[0], parts[1] - - replaceContent(node, m[2], m[3], - createLink(util.URLJoin(setting.AppURL, repo, "issues", issue), ref, issue)) + // Decorate action keywords + keyword := createKeyword(node.Data[ref.ActionLocation.Start:ref.ActionLocation.End]) + spaces := &html.Node{ + Type: html.TextNode, + Data: node.Data[ref.ActionLocation.End:ref.RefLocation.Start], + } + replaceContentList(node, ref.ActionLocation.Start, ref.RefLocation.End, []*html.Node{keyword, spaces, link}) } // fullSha1PatternProcessor renders SHA containing URLs diff --git a/modules/markup/html_internal_test.go b/modules/markup/html_internal_test.go index 2824ce3e6817e..9722063e177a2 100644 --- a/modules/markup/html_internal_test.go +++ b/modules/markup/html_internal_test.go @@ -239,34 +239,6 @@ func TestRender_FullIssueURLs(t *testing.T) { `#4`) } -func TestRegExp_issueNumericPattern(t *testing.T) { - trueTestCases := []string{ - "#1234", - "#0", - "#1234567890987654321", - " #12", - "#12:", - "ref: #12: msg", - } - falseTestCases := []string{ - "# 1234", - "# 0", - "# ", - "#", - "#ABC", - "#1A2B", - "", - "ABC", - } - - for _, testCase := range trueTestCases { - assert.True(t, issueNumericPattern.MatchString(testCase)) - } - for _, testCase := range falseTestCases { - assert.False(t, issueNumericPattern.MatchString(testCase)) - } -} - func TestRegExp_sha1CurrentPattern(t *testing.T) { trueTestCases := []string{ "d8a994ef243349f321568f9e36d5c3f444b99cae", @@ -325,70 +297,6 @@ func TestRegExp_anySHA1Pattern(t *testing.T) { } } -func TestRegExp_mentionPattern(t *testing.T) { - trueTestCases := []string{ - "@Unknwon", - "@ANT_123", - "@xxx-DiN0-z-A..uru..s-xxx", - " @lol ", - " @Te-st", - "(@gitea)", - "[@gitea]", - } - falseTestCases := []string{ - "@ 0", - "@ ", - "@", - "", - "ABC", - "/home/gitea/@gitea", - "\"@gitea\"", - } - - for _, testCase := range trueTestCases { - res := mentionPattern.MatchString(testCase) - assert.True(t, res) - } - for _, testCase := range falseTestCases { - res := mentionPattern.MatchString(testCase) - assert.False(t, res) - } -} - -func TestRegExp_issueAlphanumericPattern(t *testing.T) { - trueTestCases := []string{ - "ABC-1234", - "A-1", - "RC-80", - "ABCDEFGHIJ-1234567890987654321234567890", - "ABC-123.", - "(ABC-123)", - "[ABC-123]", - "ABC-123:", - } - falseTestCases := []string{ - "RC-08", - "PR-0", - "ABCDEFGHIJK-1", - "PR_1", - "", - "#ABC", - "", - "ABC", - "GG-", - "rm-1", - "/home/gitea/ABC-1234", - "MY-STRING-ABC-123", - } - - for _, testCase := range trueTestCases { - assert.True(t, issueAlphanumericPattern.MatchString(testCase)) - } - for _, testCase := range falseTestCases { - assert.False(t, issueAlphanumericPattern.MatchString(testCase)) - } -} - func TestRegExp_shortLinkPattern(t *testing.T) { trueTestCases := []string{ "[[stuff]]", diff --git a/modules/markup/mdstripper/mdstripper.go b/modules/markup/mdstripper/mdstripper.go new file mode 100644 index 0000000000000..7a901b17a925f --- /dev/null +++ b/modules/markup/mdstripper/mdstripper.go @@ -0,0 +1,260 @@ +// Copyright 2019 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 mdstripper + +import ( + "bytes" + + "github.com/russross/blackfriday" +) + +// MarkdownStripper extends blackfriday.Renderer +type MarkdownStripper struct { + blackfriday.Renderer + links []string + coallesce bool +} + +const ( + blackfridayExtensions = 0 | + blackfriday.EXTENSION_NO_INTRA_EMPHASIS | + blackfriday.EXTENSION_TABLES | + blackfriday.EXTENSION_FENCED_CODE | + blackfriday.EXTENSION_STRIKETHROUGH | + blackfriday.EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK | + blackfriday.EXTENSION_DEFINITION_LISTS | + blackfriday.EXTENSION_FOOTNOTES | + blackfriday.EXTENSION_HEADER_IDS | + blackfriday.EXTENSION_AUTO_HEADER_IDS | + // Not included in modules/markup/markdown/markdown.go; + // required here to process inline links + blackfriday.EXTENSION_AUTOLINK +) + +//revive:disable:var-naming Implementing the Rendering interface requires breaking some linting rules + +// StripMarkdown parses markdown content by removing all markup and code blocks +// in order to extract links and other references +func StripMarkdown(rawBytes []byte) (string, []string) { + stripper := &MarkdownStripper{ + links: make([]string, 0, 10), + } + body := blackfriday.Markdown(rawBytes, stripper, blackfridayExtensions) + return string(body), stripper.GetLinks() +} + +// StripMarkdownBytes parses markdown content by removing all markup and code blocks +// in order to extract links and other references +func StripMarkdownBytes(rawBytes []byte) ([]byte, []string) { + stripper := &MarkdownStripper{ + links: make([]string, 0, 10), + } + body := blackfriday.Markdown(rawBytes, stripper, blackfridayExtensions) + return body, stripper.GetLinks() +} + +// block-level callbacks + +// BlockCode dummy function to proceed with rendering +func (r *MarkdownStripper) BlockCode(out *bytes.Buffer, text []byte, infoString string) { + // Not rendered + r.coallesce = false +} + +// BlockQuote dummy function to proceed with rendering +func (r *MarkdownStripper) BlockQuote(out *bytes.Buffer, text []byte) { + // FIXME: perhaps it's better to leave out block quote for this? + r.processString(out, text, false) +} + +// BlockHtml dummy function to proceed with rendering +func (r *MarkdownStripper) BlockHtml(out *bytes.Buffer, text []byte) { //nolint + // Not rendered + r.coallesce = false +} + +// Header dummy function to proceed with rendering +func (r *MarkdownStripper) Header(out *bytes.Buffer, text func() bool, level int, id string) { + text() + r.coallesce = false +} + +// HRule dummy function to proceed with rendering +func (r *MarkdownStripper) HRule(out *bytes.Buffer) { + // Not rendered + r.coallesce = false +} + +// List dummy function to proceed with rendering +func (r *MarkdownStripper) List(out *bytes.Buffer, text func() bool, flags int) { + text() + r.coallesce = false +} + +// ListItem dummy function to proceed with rendering +func (r *MarkdownStripper) ListItem(out *bytes.Buffer, text []byte, flags int) { + r.processString(out, text, false) +} + +// Paragraph dummy function to proceed with rendering +func (r *MarkdownStripper) Paragraph(out *bytes.Buffer, text func() bool) { + text() + r.coallesce = false +} + +// Table dummy function to proceed with rendering +func (r *MarkdownStripper) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) { + r.processString(out, header, false) + r.processString(out, body, false) +} + +// TableRow dummy function to proceed with rendering +func (r *MarkdownStripper) TableRow(out *bytes.Buffer, text []byte) { + r.processString(out, text, false) +} + +// TableHeaderCell dummy function to proceed with rendering +func (r *MarkdownStripper) TableHeaderCell(out *bytes.Buffer, text []byte, flags int) { + r.processString(out, text, false) +} + +// TableCell dummy function to proceed with rendering +func (r *MarkdownStripper) TableCell(out *bytes.Buffer, text []byte, flags int) { + r.processString(out, text, false) +} + +// Footnotes dummy function to proceed with rendering +func (r *MarkdownStripper) Footnotes(out *bytes.Buffer, text func() bool) { + text() +} + +// FootnoteItem dummy function to proceed with rendering +func (r *MarkdownStripper) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) { + r.processString(out, text, false) +} + +// TitleBlock dummy function to proceed with rendering +func (r *MarkdownStripper) TitleBlock(out *bytes.Buffer, text []byte) { + r.processString(out, text, false) +} + +// Span-level callbacks + +// AutoLink dummy function to proceed with rendering +func (r *MarkdownStripper) AutoLink(out *bytes.Buffer, link []byte, kind int) { + r.processLink(out, link, []byte{}) +} + +// CodeSpan dummy function to proceed with rendering +func (r *MarkdownStripper) CodeSpan(out *bytes.Buffer, text []byte) { + // Not rendered + r.coallesce = false +} + +// DoubleEmphasis dummy function to proceed with rendering +func (r *MarkdownStripper) DoubleEmphasis(out *bytes.Buffer, text []byte) { + r.processString(out, text, false) +} + +// Emphasis dummy function to proceed with rendering +func (r *MarkdownStripper) Emphasis(out *bytes.Buffer, text []byte) { + r.processString(out, text, false) +} + +// Image dummy function to proceed with rendering +func (r *MarkdownStripper) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) { + // Not rendered + r.coallesce = false +} + +// LineBreak dummy function to proceed with rendering +func (r *MarkdownStripper) LineBreak(out *bytes.Buffer) { + // Not rendered + r.coallesce = false +} + +// Link dummy function to proceed with rendering +func (r *MarkdownStripper) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) { + r.processLink(out, link, content) +} + +// RawHtmlTag dummy function to proceed with rendering +func (r *MarkdownStripper) RawHtmlTag(out *bytes.Buffer, tag []byte) { //nolint + // Not rendered + r.coallesce = false +} + +// TripleEmphasis dummy function to proceed with rendering +func (r *MarkdownStripper) TripleEmphasis(out *bytes.Buffer, text []byte) { + r.processString(out, text, false) +} + +// StrikeThrough dummy function to proceed with rendering +func (r *MarkdownStripper) StrikeThrough(out *bytes.Buffer, text []byte) { + r.processString(out, text, false) +} + +// FootnoteRef dummy function to proceed with rendering +func (r *MarkdownStripper) FootnoteRef(out *bytes.Buffer, ref []byte, id int) { + // Not rendered + r.coallesce = false +} + +// Low-level callbacks + +// Entity dummy function to proceed with rendering +func (r *MarkdownStripper) Entity(out *bytes.Buffer, entity []byte) { + // FIXME: literal entities are not parsed; perhaps they should + r.coallesce = false +} + +// NormalText dummy function to proceed with rendering +func (r *MarkdownStripper) NormalText(out *bytes.Buffer, text []byte) { + r.processString(out, text, true) +} + +// Header and footer + +// DocumentHeader dummy function to proceed with rendering +func (r *MarkdownStripper) DocumentHeader(out *bytes.Buffer) { + r.coallesce = false +} + +// DocumentFooter dummy function to proceed with rendering +func (r *MarkdownStripper) DocumentFooter(out *bytes.Buffer) { + r.coallesce = false +} + +// GetFlags returns rendering flags +func (r *MarkdownStripper) GetFlags() int { + return 0 +} + +//revive:enable:var-naming + +func doubleSpace(out *bytes.Buffer) { + if out.Len() > 0 { + out.WriteByte('\n') + } +} + +func (r *MarkdownStripper) processString(out *bytes.Buffer, text []byte, coallesce bool) { + // Always break-up words + if !coallesce || !r.coallesce { + doubleSpace(out) + } + out.Write(text) + r.coallesce = coallesce +} +func (r *MarkdownStripper) processLink(out *bytes.Buffer, link []byte, content []byte) { + // Links are processed out of band + r.links = append(r.links, string(link)) + r.coallesce = false +} + +// GetLinks returns the list of link data collected while parsing +func (r *MarkdownStripper) GetLinks() []string { + return r.links +} diff --git a/modules/markup/mdstripper/mdstripper_test.go b/modules/markup/mdstripper/mdstripper_test.go new file mode 100644 index 0000000000000..157fe1975b16b --- /dev/null +++ b/modules/markup/mdstripper/mdstripper_test.go @@ -0,0 +1,71 @@ +// Copyright 2019 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 mdstripper + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestMarkdownStripper(t *testing.T) { + type testItem struct { + markdown string + expectedText []string + expectedLinks []string + } + + list := []testItem{ + { + ` +## This is a title + +This is [one](link) to paradise. +This **is emphasized**. +This: should coallesce. + +` + "```" + ` +This is a code block. +This should not appear in the output at all. +` + "```" + ` + +* Bullet 1 +* Bullet 2 + +A HIDDEN ` + "`" + `GHOST` + "`" + ` IN THIS LINE. + `, + []string{ + "This is a title", + "This is", + "to paradise.", + "This", + "is emphasized", + ".", + "This: should coallesce.", + "Bullet 1", + "Bullet 2", + "A HIDDEN", + "IN THIS LINE.", + }, + []string{ + "link", + }}, + } + + for _, test := range list { + text, links := StripMarkdown([]byte(test.markdown)) + rawlines := strings.Split(text, "\n") + lines := make([]string, 0, len(rawlines)) + for _, line := range rawlines { + line := strings.TrimSpace(line) + if line != "" { + lines = append(lines, line) + } + } + assert.EqualValues(t, test.expectedText, lines) + assert.EqualValues(t, test.expectedLinks, links) + } +} diff --git a/modules/markup/sanitizer.go b/modules/markup/sanitizer.go index 2ec43cf4fd3c8..fd6f90b2ab1bf 100644 --- a/modules/markup/sanitizer.go +++ b/modules/markup/sanitizer.go @@ -38,6 +38,9 @@ func NewSanitizer() { // Custom URL-Schemes sanitizer.policy.AllowURLSchemes(setting.Markdown.CustomURLSchemes...) + + // Allow keyword markup + sanitizer.policy.AllowAttrs("class").Matching(regexp.MustCompile(`^` + keywordClass + `$`)).OnElements("span") }) } diff --git a/modules/references/references.go b/modules/references/references.go new file mode 100644 index 0000000000000..9c74d0d081ae6 --- /dev/null +++ b/modules/references/references.go @@ -0,0 +1,322 @@ +// Copyright 2019 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 references + +import ( + "net/url" + "regexp" + "strconv" + "strings" + "sync" + + "code.gitea.io/gitea/modules/markup/mdstripper" + "code.gitea.io/gitea/modules/setting" +) + +var ( + // validNamePattern performs only the most basic validation for user or repository names + // Repository name should contain only alphanumeric, dash ('-'), underscore ('_') and dot ('.') characters. + validNamePattern = regexp.MustCompile(`^[a-z0-9_.-]+$`) + + // NOTE: All below regex matching do not perform any extra validation. + // Thus a link is produced even if the linked entity does not exist. + // While fast, this is also incorrect and lead to false positives. + // TODO: fix invalid linking issue + + // mentionPattern matches all mentions in the form of "@user" + mentionPattern = regexp.MustCompile(`(?:\s|^|\(|\[)(@[0-9a-zA-Z-_\.]+)(?:\s|$|\)|\])`) + // issueNumericPattern matches string that references to a numeric issue, e.g. #1287 + issueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)(#[0-9]+)(?:\s|$|\)|\]|:|\.(\s|$))`) + // issueAlphanumericPattern matches string that references to an alphanumeric issue, e.g. ABC-1234 + issueAlphanumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([A-Z]{1,10}-[1-9][0-9]*)(?:\s|$|\)|\]|:|\.(\s|$))`) + // crossReferenceIssueNumericPattern matches string that references a numeric issue in a different repository + // e.g. gogits/gogs#12345 + crossReferenceIssueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+/[0-9a-zA-Z-_\.]+#[0-9]+)(?:\s|$|\)|\]|\.(\s|$))`) + + // Same as GitHub. See + // https://help.github.com/articles/closing-issues-via-commit-messages + issueCloseKeywords = []string{"close", "closes", "closed", "fix", "fixes", "fixed", "resolve", "resolves", "resolved"} + issueReopenKeywords = []string{"reopen", "reopens", "reopened"} + + issueCloseKeywordsPat, issueReopenKeywordsPat *regexp.Regexp + + giteaHostInit sync.Once + giteaHost string +) + +// XRefAction represents the kind of effect a cross reference has once is resolved +type XRefAction int64 + +const ( + // XRefActionNone means the cross-reference is simply a comment + XRefActionNone XRefAction = iota // 0 + // XRefActionCloses means the cross-reference should close an issue if it is resolved + XRefActionCloses // 1 + // XRefActionReopens means the cross-reference should reopen an issue if it is resolved + XRefActionReopens // 2 + // XRefActionNeutered means the cross-reference will no longer affect the source + XRefActionNeutered // 3 +) + +// IssueReference contains an unverified cross-reference to a local issue or pull request +type IssueReference struct { + Index int64 + Owner string + Name string + Action XRefAction +} + +// RenderizableReference contains an unverified cross-reference to with rendering information +type RenderizableReference struct { + Issue string + Owner string + Name string + RefLocation *RefSpan + Action XRefAction + ActionLocation *RefSpan +} + +type rawReference struct { + index int64 + owner string + name string + action XRefAction + issue string + refLocation *RefSpan + actionLocation *RefSpan +} + +func rawToIssueReferenceList(reflist []*rawReference) []IssueReference { + refarr := make([]IssueReference, len(reflist)) + for i, r := range reflist { + refarr[i] = IssueReference{ + Index: r.index, + Owner: r.owner, + Name: r.name, + Action: r.action, + } + } + return refarr +} + +// RefSpan is the position where the reference was found within the parsed text +type RefSpan struct { + Start int + End int +} + +func makeKeywordsPat(keywords []string) *regexp.Regexp { + return regexp.MustCompile(`(?i)(?:\s|^|\(|\[)(` + strings.Join(keywords, `|`) + `):? $`) +} + +func init() { + issueCloseKeywordsPat = makeKeywordsPat(issueCloseKeywords) + issueReopenKeywordsPat = makeKeywordsPat(issueReopenKeywords) +} + +// getGiteaHostName returns a normalized string with the local host name, with no scheme or port information +func getGiteaHostName() string { + giteaHostInit.Do(func() { + if uapp, err := url.Parse(setting.AppURL); err == nil { + giteaHost = strings.ToLower(uapp.Host) + } else { + giteaHost = "" + } + }) + return giteaHost +} + +// FindAllMentionsMarkdown matches mention patterns in given content and +// returns a list of found unvalidated user names **not including** the @ prefix. +func FindAllMentionsMarkdown(content string) []string { + bcontent, _ := mdstripper.StripMarkdownBytes([]byte(content)) + locations := FindAllMentionsBytes(bcontent) + mentions := make([]string, len(locations)) + for i, val := range locations { + mentions[i] = string(bcontent[val.Start+1 : val.End]) + } + return mentions +} + +// FindAllMentionsBytes matches mention patterns in given content +// and returns a list of locations for the unvalidated user names, including the @ prefix. +func FindAllMentionsBytes(content []byte) []RefSpan { + mentions := mentionPattern.FindAllSubmatchIndex(content, -1) + ret := make([]RefSpan, len(mentions)) + for i, val := range mentions { + ret[i] = RefSpan{Start: val[2], End: val[3]} + } + return ret +} + +// FindFirstMentionBytes matches the first mention in then given content +// and returns the location of the unvalidated user name, including the @ prefix. +func FindFirstMentionBytes(content []byte) (bool, RefSpan) { + mention := mentionPattern.FindSubmatchIndex(content) + if mention == nil { + return false, RefSpan{} + } + return true, RefSpan{Start: mention[2], End: mention[3]} +} + +// FindAllIssueReferencesMarkdown strips content from markdown markup +// and returns a list of unvalidated references found in it. +func FindAllIssueReferencesMarkdown(content string) []IssueReference { + return rawToIssueReferenceList(findAllIssueReferencesMarkdown(content)) +} + +func findAllIssueReferencesMarkdown(content string) []*rawReference { + bcontent, links := mdstripper.StripMarkdownBytes([]byte(content)) + return findAllIssueReferencesBytes(bcontent, links) +} + +// FindAllIssueReferences returns a list of unvalidated references found in a string. +func FindAllIssueReferences(content string) []IssueReference { + return rawToIssueReferenceList(findAllIssueReferencesBytes([]byte(content), []string{})) +} + +// FindRenderizableReferenceNumeric returns the first unvalidated reference found in a string. +func FindRenderizableReferenceNumeric(content string) (bool, *RenderizableReference) { + match := issueNumericPattern.FindStringSubmatchIndex(content) + if match == nil { + if match = crossReferenceIssueNumericPattern.FindStringSubmatchIndex(content); match == nil { + return false, nil + } + } + r := getCrossReference([]byte(content), match[2], match[3], false) + if r == nil { + return false, nil + } + + return true, &RenderizableReference{ + Issue: r.issue, + Owner: r.owner, + Name: r.name, + RefLocation: r.refLocation, + Action: r.action, + ActionLocation: r.actionLocation, + } +} + +// FindRenderizableReferenceAlphanumeric returns the first alphanumeric unvalidated references found in a string. +func FindRenderizableReferenceAlphanumeric(content string) (bool, *RenderizableReference) { + match := issueAlphanumericPattern.FindStringSubmatchIndex(content) + if match == nil { + return false, nil + } + + action, location := findActionKeywords([]byte(content), match[2]) + + return true, &RenderizableReference{ + Issue: string(content[match[2]:match[3]]), + RefLocation: &RefSpan{Start: match[2], End: match[3]}, + Action: action, + ActionLocation: location, + } +} + +// FindAllIssueReferencesBytes returns a list of unvalidated references found in a byte slice. +func findAllIssueReferencesBytes(content []byte, links []string) []*rawReference { + + ret := make([]*rawReference, 0, 10) + + matches := issueNumericPattern.FindAllSubmatchIndex(content, -1) + for _, match := range matches { + if ref := getCrossReference(content, match[2], match[3], false); ref != nil { + ret = append(ret, ref) + } + } + + matches = crossReferenceIssueNumericPattern.FindAllSubmatchIndex(content, -1) + for _, match := range matches { + if ref := getCrossReference(content, match[2], match[3], false); ref != nil { + ret = append(ret, ref) + } + } + + localhost := getGiteaHostName() + for _, link := range links { + if u, err := url.Parse(link); err == nil { + // Note: we're not attempting to match the URL scheme (http/https) + host := strings.ToLower(u.Host) + if host != "" && host != localhost { + continue + } + parts := strings.Split(u.EscapedPath(), "/") + // /user/repo/issues/3 + if len(parts) != 5 || parts[0] != "" { + continue + } + if parts[3] != "issues" && parts[3] != "pulls" { + continue + } + // Note: closing/reopening keywords not supported with URLs + bytes := []byte(parts[1] + "/" + parts[2] + "#" + parts[4]) + if ref := getCrossReference(bytes, 0, len(bytes), true); ref != nil { + ref.refLocation = nil + ret = append(ret, ref) + } + } + } + + return ret +} + +func getCrossReference(content []byte, start, end int, fromLink bool) *rawReference { + refid := string(content[start:end]) + parts := strings.Split(refid, "#") + if len(parts) != 2 { + return nil + } + repo, issue := parts[0], parts[1] + index, err := strconv.ParseInt(issue, 10, 64) + if err != nil { + return nil + } + if repo == "" { + if fromLink { + // Markdown links must specify owner/repo + return nil + } + action, location := findActionKeywords(content, start) + return &rawReference{ + index: index, + action: action, + issue: issue, + refLocation: &RefSpan{Start: start, End: end}, + actionLocation: location, + } + } + parts = strings.Split(strings.ToLower(repo), "/") + if len(parts) != 2 { + return nil + } + owner, name := parts[0], parts[1] + if !validNamePattern.MatchString(owner) || !validNamePattern.MatchString(name) { + return nil + } + action, location := findActionKeywords(content, start) + return &rawReference{ + index: index, + owner: owner, + name: name, + action: action, + issue: issue, + refLocation: &RefSpan{Start: start, End: end}, + actionLocation: location, + } +} + +func findActionKeywords(content []byte, start int) (XRefAction, *RefSpan) { + m := issueCloseKeywordsPat.FindSubmatchIndex(content[:start]) + if m != nil { + return XRefActionCloses, &RefSpan{Start: m[2], End: m[3]} + } + m = issueReopenKeywordsPat.FindSubmatchIndex(content[:start]) + if m != nil { + return XRefActionReopens, &RefSpan{Start: m[2], End: m[3]} + } + return XRefActionNone, nil +} diff --git a/modules/references/references_test.go b/modules/references/references_test.go new file mode 100644 index 0000000000000..f8153ffe36daf --- /dev/null +++ b/modules/references/references_test.go @@ -0,0 +1,296 @@ +// Copyright 2019 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 references + +import ( + "testing" + + "code.gitea.io/gitea/modules/setting" + + "github.com/stretchr/testify/assert" +) + +func TestFindAllIssueReferences(t *testing.T) { + + type result struct { + Index int64 + Owner string + Name string + Issue string + Action XRefAction + RefLocation *RefSpan + ActionLocation *RefSpan + } + + type testFixture struct { + input string + expected []result + } + + fixtures := []testFixture{ + { + "Simply closes: #29 yes", + []result{ + {29, "", "", "29", XRefActionCloses, &RefSpan{Start: 15, End: 18}, &RefSpan{Start: 7, End: 13}}, + }, + }, + { + "#123 no, this is a title.", + []result{}, + }, + { + " #124 yes, this is a reference.", + []result{ + {124, "", "", "124", XRefActionNone, &RefSpan{Start: 0, End: 4}, nil}, + }, + }, + { + "```\nThis is a code block.\n#723 no, it's a code block.```", + []result{}, + }, + { + "This `#724` no, it's inline code.", + []result{}, + }, + { + "This user3/repo4#200 yes.", + []result{ + {200, "user3", "repo4", "200", XRefActionNone, &RefSpan{Start: 5, End: 20}, nil}, + }, + }, + { + "This [one](#919) no, this is a URL fragment.", + []result{}, + }, + { + "This [two](/user2/repo1/issues/921) yes.", + []result{ + {921, "user2", "repo1", "921", XRefActionNone, nil, nil}, + }, + }, + { + "This [three](/user2/repo1/pulls/922) yes.", + []result{ + {922, "user2", "repo1", "922", XRefActionNone, nil, nil}, + }, + }, + { + "This [four](http://gitea.com:3000/user3/repo4/issues/203) yes.", + []result{ + {203, "user3", "repo4", "203", XRefActionNone, nil, nil}, + }, + }, + { + "This [five](http://github.com/user3/repo4/issues/204) no.", + []result{}, + }, + { + "This http://gitea.com:3000/user4/repo5/201 no, bad URL.", + []result{}, + }, + { + "This http://gitea.com:3000/user4/repo5/pulls/202 yes.", + []result{ + {202, "user4", "repo5", "202", XRefActionNone, nil, nil}, + }, + }, + { + "This http://GiTeA.COM:3000/user4/repo6/pulls/205 yes.", + []result{ + {205, "user4", "repo6", "205", XRefActionNone, nil, nil}, + }, + }, + { + "Reopens #15 yes", + []result{ + {15, "", "", "15", XRefActionReopens, &RefSpan{Start: 8, End: 11}, &RefSpan{Start: 0, End: 7}}, + }, + }, + { + "This closes #20 for you yes", + []result{ + {20, "", "", "20", XRefActionCloses, &RefSpan{Start: 12, End: 15}, &RefSpan{Start: 5, End: 11}}, + }, + }, + { + "Do you fix user6/repo6#300 ? yes", + []result{ + {300, "user6", "repo6", "300", XRefActionCloses, &RefSpan{Start: 11, End: 26}, &RefSpan{Start: 7, End: 10}}, + }, + }, + { + "For 999 #1235 no keyword, but yes", + []result{ + {1235, "", "", "1235", XRefActionNone, &RefSpan{Start: 8, End: 13}, nil}, + }, + }, + { + "Which abc. #9434 same as above", + []result{ + {9434, "", "", "9434", XRefActionNone, &RefSpan{Start: 11, End: 16}, nil}, + }, + }, + { + "This closes #600 and reopens #599", + []result{ + {600, "", "", "600", XRefActionCloses, &RefSpan{Start: 12, End: 16}, &RefSpan{Start: 5, End: 11}}, + {599, "", "", "599", XRefActionReopens, &RefSpan{Start: 29, End: 33}, &RefSpan{Start: 21, End: 28}}, + }, + }, + } + + // Save original value for other tests that may rely on it + prevURL := setting.AppURL + setting.AppURL = "https://gitea.com:3000/" + + for _, fixture := range fixtures { + expraw := make([]*rawReference, len(fixture.expected)) + for i, e := range fixture.expected { + expraw[i] = &rawReference{ + index: e.Index, + owner: e.Owner, + name: e.Name, + action: e.Action, + issue: e.Issue, + refLocation: e.RefLocation, + actionLocation: e.ActionLocation, + } + } + expref := rawToIssueReferenceList(expraw) + refs := FindAllIssueReferencesMarkdown(fixture.input) + assert.EqualValues(t, expref, refs, "Failed to parse: {%s}", fixture.input) + rawrefs := findAllIssueReferencesMarkdown(fixture.input) + assert.EqualValues(t, expraw, rawrefs, "Failed to parse: {%s}", fixture.input) + } + + // Restore for other tests that may rely on the original value + setting.AppURL = prevURL + + type alnumFixture struct { + input string + issue string + refLocation *RefSpan + action XRefAction + actionLocation *RefSpan + } + + alnumFixtures := []alnumFixture{ + { + "This ref ABC-123 is alphanumeric", + "ABC-123", &RefSpan{Start: 9, End: 16}, + XRefActionNone, nil, + }, + { + "This closes ABCD-1234 alphanumeric", + "ABCD-1234", &RefSpan{Start: 12, End: 21}, + XRefActionCloses, &RefSpan{Start: 5, End: 11}, + }, + } + + for _, fixture := range alnumFixtures { + found, ref := FindRenderizableReferenceAlphanumeric(fixture.input) + if fixture.issue == "" { + assert.False(t, found, "Failed to parse: {%s}", fixture.input) + } else { + assert.True(t, found, "Failed to parse: {%s}", fixture.input) + assert.Equal(t, fixture.issue, ref.Issue, "Failed to parse: {%s}", fixture.input) + assert.Equal(t, fixture.refLocation, ref.RefLocation, "Failed to parse: {%s}", fixture.input) + assert.Equal(t, fixture.action, ref.Action, "Failed to parse: {%s}", fixture.input) + assert.Equal(t, fixture.actionLocation, ref.ActionLocation, "Failed to parse: {%s}", fixture.input) + } + } +} + +func TestRegExp_mentionPattern(t *testing.T) { + trueTestCases := []string{ + "@Unknwon", + "@ANT_123", + "@xxx-DiN0-z-A..uru..s-xxx", + " @lol ", + " @Te-st", + "(@gitea)", + "[@gitea]", + } + falseTestCases := []string{ + "@ 0", + "@ ", + "@", + "", + "ABC", + "/home/gitea/@gitea", + "\"@gitea\"", + } + + for _, testCase := range trueTestCases { + res := mentionPattern.MatchString(testCase) + assert.True(t, res) + } + for _, testCase := range falseTestCases { + res := mentionPattern.MatchString(testCase) + assert.False(t, res) + } +} + +func TestRegExp_issueNumericPattern(t *testing.T) { + trueTestCases := []string{ + "#1234", + "#0", + "#1234567890987654321", + " #12", + "#12:", + "ref: #12: msg", + } + falseTestCases := []string{ + "# 1234", + "# 0", + "# ", + "#", + "#ABC", + "#1A2B", + "", + "ABC", + } + + for _, testCase := range trueTestCases { + assert.True(t, issueNumericPattern.MatchString(testCase)) + } + for _, testCase := range falseTestCases { + assert.False(t, issueNumericPattern.MatchString(testCase)) + } +} + +func TestRegExp_issueAlphanumericPattern(t *testing.T) { + trueTestCases := []string{ + "ABC-1234", + "A-1", + "RC-80", + "ABCDEFGHIJ-1234567890987654321234567890", + "ABC-123.", + "(ABC-123)", + "[ABC-123]", + "ABC-123:", + } + falseTestCases := []string{ + "RC-08", + "PR-0", + "ABCDEFGHIJK-1", + "PR_1", + "", + "#ABC", + "", + "ABC", + "GG-", + "rm-1", + "/home/gitea/ABC-1234", + "MY-STRING-ABC-123", + } + + for _, testCase := range trueTestCases { + assert.True(t, issueAlphanumericPattern.MatchString(testCase)) + } + for _, testCase := range falseTestCases { + assert.False(t, issueAlphanumericPattern.MatchString(testCase)) + } +} diff --git a/public/css/index.css b/public/css/index.css index 0efd787122241..fda26f4e0847b 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -878,6 +878,7 @@ tbody.commit-list{vertical-align:baseline} .repo-buttons .disabled-repo-button a.button:hover{background:0 0!important;color:rgba(0,0,0,.6)!important;box-shadow:0 0 0 1px rgba(34,36,38,.15) inset!important} .repo-buttons .ui.labeled.button>.label{border-left:0!important;margin:0!important} .tag-code,.tag-code td{background-color:#f0f0f0!important;border-color:#d3cfcf!important;padding-top:8px;padding-bottom:8px} +.issue-keyword{border-bottom:1px dotted #959da5;display:inline-block} .file-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px!important} .file-info{display:flex;align-items:center} .file-info-entry+.file-info-entry{border-left:1px solid currentColor;margin-left:8px;padding-left:8px} diff --git a/public/less/_repository.less b/public/less/_repository.less index 0527759ed4826..5f6a7fbd97cc9 100644 --- a/public/less/_repository.less +++ b/public/less/_repository.less @@ -2384,6 +2384,11 @@ tbody.commit-list { padding-bottom: 8px; } +.issue-keyword { + border-bottom: 1px dotted #959da5; + display: inline-block; +} + .file-header { display: flex; justify-content: space-between; diff --git a/services/mailer/mail_comment.go b/services/mailer/mail_comment.go index f64db04fffa9d..d306c14f42915 100644 --- a/services/mailer/mail_comment.go +++ b/services/mailer/mail_comment.go @@ -9,7 +9,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/references" ) // MailParticipantsComment sends new comment emails to repository watchers @@ -19,7 +19,7 @@ func MailParticipantsComment(c *models.Comment, opType models.ActionType, issue } func mailParticipantsComment(ctx models.DBContext, c *models.Comment, opType models.ActionType, issue *models.Issue) (err error) { - rawMentions := markup.FindAllMentions(c.Content) + rawMentions := references.FindAllMentionsMarkdown(c.Content) userMentions, err := issue.ResolveMentionsByVisibility(ctx, c.Poster, rawMentions) if err != nil { return fmt.Errorf("ResolveMentionsByVisibility [%d]: %v", c.IssueID, err) diff --git a/services/mailer/mail_issue.go b/services/mailer/mail_issue.go index da0249d595dab..b16323909ca5e 100644 --- a/services/mailer/mail_issue.go +++ b/services/mailer/mail_issue.go @@ -9,7 +9,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/references" "code.gitea.io/gitea/modules/setting" "github.com/unknwon/com" @@ -123,7 +123,7 @@ func MailParticipants(issue *models.Issue, doer *models.User, opType models.Acti } func mailParticipants(ctx models.DBContext, issue *models.Issue, doer *models.User, opType models.ActionType) (err error) { - rawMentions := markup.FindAllMentions(issue.Content) + rawMentions := references.FindAllMentionsMarkdown(issue.Content) userMentions, err := issue.ResolveMentionsByVisibility(ctx, doer, rawMentions) if err != nil { return fmt.Errorf("ResolveMentionsByVisibility [%d]: %v", issue.ID, err) From ba201aaa44b19f633fab0c4682d5f97558b3205e Mon Sep 17 00:00:00 2001 From: Antoine GIRARD Date: Mon, 14 Oct 2019 02:38:15 +0200 Subject: [PATCH 077/173] vendor: update mvdan.cc/xurls/v2 to v2.1.0 (#8495) --- go.mod | 2 +- go.sum | 4 ++-- vendor/modules.txt | 2 +- vendor/mvdan.cc/xurls/v2/.travis.yml | 17 ----------------- vendor/mvdan.cc/xurls/v2/README.md | 18 +++++++++++------- vendor/mvdan.cc/xurls/v2/go.mod | 2 ++ vendor/mvdan.cc/xurls/v2/schemes.go | 23 +++++++++++++++++++++++ vendor/mvdan.cc/xurls/v2/tlds.go | 19 +++++-------------- vendor/mvdan.cc/xurls/v2/xurls.go | 10 ++++++---- 9 files changed, 51 insertions(+), 46 deletions(-) delete mode 100644 vendor/mvdan.cc/xurls/v2/.travis.yml diff --git a/go.mod b/go.mod index d2520da73982e..203b6ce4c1bf4 100644 --- a/go.mod +++ b/go.mod @@ -120,7 +120,7 @@ require ( gopkg.in/src-d/go-git.v4 v4.13.1 gopkg.in/stretchr/testify.v1 v1.2.2 // indirect gopkg.in/testfixtures.v2 v2.5.0 - mvdan.cc/xurls/v2 v2.0.0 + mvdan.cc/xurls/v2 v2.1.0 strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 xorm.io/builder v0.3.6 xorm.io/core v0.7.2 diff --git a/go.sum b/go.sum index 3adf91e926bf0..7306966800bb6 100644 --- a/go.sum +++ b/go.sum @@ -812,8 +812,8 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.2/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -mvdan.cc/xurls/v2 v2.0.0 h1:r1zSOSNS/kqtpmATyMMMvaZ4/djsesbYz5kr0+qMRWc= -mvdan.cc/xurls/v2 v2.0.0/go.mod h1:2/webFPYOXN9jp/lzuj0zuAVlF+9g4KPFJANH1oJhRU= +mvdan.cc/xurls/v2 v2.1.0 h1:KaMb5GLhlcSX+e+qhbRJODnUUBvlw01jt4yrjFIHAuA= +mvdan.cc/xurls/v2 v2.1.0/go.mod h1:5GrSd9rOnKOpZaji1OZLYL/yeAAtGDlo/cFe+8K5n8E= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 h1:mUcz5b3FJbP5Cvdq7Khzn6J9OCUQJaBwgBkCR+MOwSs= strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY= diff --git a/vendor/modules.txt b/vendor/modules.txt index 8b2224f54abd3..30b1370933fbe 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -610,7 +610,7 @@ gopkg.in/testfixtures.v2 gopkg.in/warnings.v0 # gopkg.in/yaml.v2 v2.2.2 gopkg.in/yaml.v2 -# mvdan.cc/xurls/v2 v2.0.0 +# mvdan.cc/xurls/v2 v2.1.0 mvdan.cc/xurls/v2 # strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 strk.kbt.io/projects/go/libravatar diff --git a/vendor/mvdan.cc/xurls/v2/.travis.yml b/vendor/mvdan.cc/xurls/v2/.travis.yml deleted file mode 100644 index e9bd7a7650318..0000000000000 --- a/vendor/mvdan.cc/xurls/v2/.travis.yml +++ /dev/null @@ -1,17 +0,0 @@ -language: go - -go: - - 1.10.x - - 1.11.x - -go_import_path: mvdan.cc/xurls - -env: - - GO111MODULE=on - -install: true - -script: - - go get -t -d ./... - - go build ./... - - go test ./... diff --git a/vendor/mvdan.cc/xurls/v2/README.md b/vendor/mvdan.cc/xurls/v2/README.md index 5058efe7a7944..07fbdb3b2507c 100644 --- a/vendor/mvdan.cc/xurls/v2/README.md +++ b/vendor/mvdan.cc/xurls/v2/README.md @@ -1,18 +1,20 @@ # xurls [![GoDoc](https://godoc.org/mvdan.cc/xurls?status.svg)](https://godoc.org/mvdan.cc/xurls) -[![Travis](https://travis-ci.org/mvdan/xurls.svg?branch=master)](https://travis-ci.org/mvdan/xurls) -Extract urls from text using regular expressions. Requires Go 1.10.3 or later. +Extract urls from text using regular expressions. Requires Go 1.12 or later. ```go import "mvdan.cc/xurls/v2" func main() { - xurls.Relaxed().FindString("Do gophers live in golang.org?") - // "golang.org" - xurls.Strict().FindAllString("foo.com is http://foo.com/.", -1) - // []string{"http://foo.com/"} + rxRelaxed := xurls.Relaxed() + rxRelaxed.FindString("Do gophers live in golang.org?") // "golang.org" + rxRelaxed.FindString("This string does not have a URL") // "" + + rxStrict := xurls.Strict() + rxStrict.FindAllString("must have scheme: http://foo.com/.", -1) // []string{"http://foo.com/"} + rxStrict.FindAllString("no scheme, no match: foo.com", -1) // []string{} } ``` @@ -20,7 +22,9 @@ Note that the funcs compile regexes, so avoid calling them repeatedly. #### cmd/xurls - go get -u mvdan.cc/xurls/v2/cmd/xurls +To install the tool globally: + + go get mvdan.cc/xurls/cmd/xurls ```shell $ echo "Do gophers live in http://golang.org?" | xurls diff --git a/vendor/mvdan.cc/xurls/v2/go.mod b/vendor/mvdan.cc/xurls/v2/go.mod index 6f0822a737226..d9d334543c30c 100644 --- a/vendor/mvdan.cc/xurls/v2/go.mod +++ b/vendor/mvdan.cc/xurls/v2/go.mod @@ -1 +1,3 @@ module mvdan.cc/xurls/v2 + +go 1.13 diff --git a/vendor/mvdan.cc/xurls/v2/schemes.go b/vendor/mvdan.cc/xurls/v2/schemes.go index 01b7944ae33eb..e8e6585f47931 100644 --- a/vendor/mvdan.cc/xurls/v2/schemes.go +++ b/vendor/mvdan.cc/xurls/v2/schemes.go @@ -12,13 +12,18 @@ var Schemes = []string{ `about`, `acap`, `acct`, + `acd`, `acr`, `adiumxtra`, + `adt`, `afp`, `afs`, `aim`, + `amss`, + `android`, `appdata`, `apt`, + `ark`, `attachment`, `aw`, `barion`, @@ -28,8 +33,11 @@ var Schemes = []string{ `blob`, `bolo`, `browserext`, + `calculator`, `callto`, `cap`, + `cast`, + `casts`, `chrome`, `chrome-extension`, `cid`, @@ -44,6 +52,7 @@ var Schemes = []string{ `conti`, `crid`, `cvs`, + `dab`, `data`, `dav`, `diaspora`, @@ -54,6 +63,9 @@ var Schemes = []string{ `dlna-playsingle`, `dns`, `dntp`, + `dpp`, + `drm`, + `drop`, `dtn`, `dvb`, `ed2k`, @@ -66,8 +78,11 @@ var Schemes = []string{ `file`, `filesystem`, `finger`, + `first-run-pen-experience`, `fish`, + `fm`, `ftp`, + `fuchsia-pkg`, `geo`, `gg`, `git`, @@ -112,6 +127,8 @@ var Schemes = []string{ `lastfm`, `ldap`, `ldaps`, + `leaptofrogans`, + `lorawan`, `lvlt`, `magnet`, `mailserver`, @@ -129,9 +146,11 @@ var Schemes = []string{ `moz`, `ms-access`, `ms-browser-extension`, + `ms-calculator`, `ms-drive-to`, `ms-enrollment`, `ms-excel`, + `ms-eyecontrolspeech`, `ms-gamebarservices`, `ms-gamingoverlay`, `ms-getoffice`, @@ -141,6 +160,7 @@ var Schemes = []string{ `ms-lockscreencomponent-config`, `ms-media-stream-id`, `ms-mixedrealitycapture`, + `ms-mobileplans`, `ms-officeapp`, `ms-people`, `ms-project`, @@ -186,6 +206,7 @@ var Schemes = []string{ `msnim`, `msrp`, `msrps`, + `mss`, `mtqp`, `mumble`, `mupdate`, @@ -205,6 +226,7 @@ var Schemes = []string{ `pack`, `palm`, `paparazzi`, + `payto`, `pkcs11`, `platform`, `pop`, @@ -213,6 +235,7 @@ var Schemes = []string{ `proxy`, `pwid`, `psyc`, + `pttp`, `qb`, `query`, `redis`, diff --git a/vendor/mvdan.cc/xurls/v2/tlds.go b/vendor/mvdan.cc/xurls/v2/tlds.go index 084ab84d46d90..c98ce508d699f 100644 --- a/vendor/mvdan.cc/xurls/v2/tlds.go +++ b/vendor/mvdan.cc/xurls/v2/tlds.go @@ -24,7 +24,6 @@ var TLDs = []string{ `accountant`, `accountants`, `aco`, - `active`, `actor`, `ad`, `adac`, @@ -154,7 +153,6 @@ var TLDs = []string{ `bj`, `black`, `blackfriday`, - `blanco`, `blockbuster`, `blog`, `bloomberg`, @@ -163,7 +161,6 @@ var TLDs = []string{ `bms`, `bmw`, `bn`, - `bnl`, `bnpparibas`, `bo`, `boats`, @@ -307,6 +304,7 @@ var TLDs = []string{ `coupon`, `coupons`, `courses`, + `cpa`, `cr`, `credit`, `creditcard`, @@ -370,7 +368,6 @@ var TLDs = []string{ `doctor`, `dodge`, `dog`, - `doha`, `domains`, `dot`, `download`, @@ -379,7 +376,6 @@ var TLDs = []string{ `dubai`, `duck`, `dunlop`, - `duns`, `dupont`, `durban`, `dvag`, @@ -400,7 +396,6 @@ var TLDs = []string{ `engineer`, `engineering`, `enterprises`, - `epost`, `epson`, `equipment`, `er`, @@ -496,6 +491,7 @@ var TLDs = []string{ `games`, `gap`, `garden`, + `gay`, `gb`, `gbiz`, `gd`, @@ -588,7 +584,6 @@ var TLDs = []string{ `homes`, `homesense`, `honda`, - `honeywell`, `horse`, `hospital`, `host`, @@ -642,7 +637,6 @@ var TLDs = []string{ `ir`, `irish`, `is`, - `iselect`, `ismaili`, `ist`, `istanbul`, @@ -752,6 +746,7 @@ var TLDs = []string{ `lixil`, `lk`, `llc`, + `llp`, `loan`, `loans`, `locker`, @@ -827,7 +822,6 @@ var TLDs = []string{ `mo`, `mobi`, `mobile`, - `mobily`, `moda`, `moe`, `moi`, @@ -1161,21 +1155,19 @@ var TLDs = []string{ `sony`, `soy`, `space`, - `spiegel`, `sport`, `spot`, `spreadbetting`, `sr`, `srl`, `srt`, + `ss`, `st`, `stada`, `staples`, `star`, - `starhub`, `statebank`, `statefarm`, - `statoil`, `stc`, `stcgroup`, `stockholm`, @@ -1391,7 +1383,6 @@ var TLDs = []string{ `zara`, `zero`, `zip`, - `zippo`, `zm`, `zone`, `zuerich`, @@ -1449,7 +1440,7 @@ var TLDs = []string{ `كوم`, `مصر`, `مليسيا`, - `موبايلي`, + `موريتانيا`, `موقع`, `همراه`, `پاكستان`, diff --git a/vendor/mvdan.cc/xurls/v2/xurls.go b/vendor/mvdan.cc/xurls/v2/xurls.go index d6279ae60b568..7244c709a0b39 100644 --- a/vendor/mvdan.cc/xurls/v2/xurls.go +++ b/vendor/mvdan.cc/xurls/v2/xurls.go @@ -19,9 +19,9 @@ const ( iriChar = letter + mark + number currency = `\p{Sc}` otherSymb = `\p{So}` - endChar = iriChar + `/\-+_&~*%=#` + currency + otherSymb + endChar = iriChar + `/\-+&~%=#` + currency + otherSymb otherPunc = `\p{Po}` - midChar = endChar + `|` + otherPunc + midChar = endChar + "_*" + otherPunc wellParen = `\([` + midChar + `]*(\([` + midChar + `]*\)[` + midChar + `]*)*\)` wellBrack = `\[[` + midChar + `]*(\[[` + midChar + `]*\][` + midChar + `]*)*\]` wellBrace = `\{[` + midChar + `]*(\{[` + midChar + `]*\}[` + midChar + `]*)*\}` @@ -72,9 +72,11 @@ func strictExp() string { } func relaxedExp() string { - site := domain + `(?i)` + anyOf(append(TLDs, PseudoTLDs...)...) + `(?-i)` + punycode := `xn--[a-z0-9-]+` + knownTLDs := anyOf(append(TLDs, PseudoTLDs...)...) + site := domain + `(?i)(` + punycode + `|` + knownTLDs + `)(?-i)` hostName := `(` + site + `|` + ipAddr + `)` - webURL := hostName + port + `(/|/` + pathCont + `?|\b|$)` + webURL := hostName + port + `(/|/` + pathCont + `?|\b|(?m)$)` return strictExp() + `|` + webURL } From e3e44a59d01da3af2be3a830f4a90394e7af4ff4 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 14 Oct 2019 14:10:42 +0800 Subject: [PATCH 078/173] Update migrated repositories' issues/comments/prs poster id if user has a github external user saved (#7751) * update migrated issues/comments when login as github * add get userid when migrating or login with github oauth2 * fix lint * add migrations for repository service type * fix build * remove unnecessary dependencies on migrations * add cron task to update migrations poster ids and fix posterid when migrating * fix lint * fix lint * improve code * fix lint * improve code * replace releases publish id to actual author id * fix import * fix bug * fix lint * fix rawdata definition * fix some bugs * fix error message --- custom/conf/app.ini.sample | 5 + .../doc/advanced/config-cheat-sheet.en-us.md | 4 + .../doc/advanced/config-cheat-sheet.zh-cn.md | 6 +- models/external_login_user.go | 143 +++++++++-- models/issue.go | 16 +- models/issue_comment.go | 21 ++ models/migrations/migrations.go | 2 + models/migrations/v100.go | 83 ++++++ models/release.go | 14 + models/repo.go | 22 +- modules/cron/cron.go | 23 +- modules/migrations/base/downloader.go | 3 + modules/migrations/gitea.go | 239 +++++++++++++----- modules/migrations/github.go | 8 +- modules/migrations/migrate.go | 7 + modules/migrations/update.go | 59 +++++ modules/setting/cron.go | 8 + modules/structs/repo.go | 39 +++ routers/api/v1/repo/repo.go | 37 ++- routers/user/auth.go | 88 ++++--- services/externalaccount/user.go | 66 +++++ 21 files changed, 737 insertions(+), 156 deletions(-) create mode 100644 models/migrations/v100.go create mode 100644 modules/migrations/update.go create mode 100644 services/externalaccount/user.go diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index dd14089d2b06d..fd8d928ede544 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -690,6 +690,11 @@ SCHEDULE = @every 24h ; or only create new users if UPDATE_EXISTING is set to false UPDATE_EXISTING = true +; Update migrated repositories' issues and comments' posterid, it will always attempt synchronization when the instance starts. +[cron.update_migration_post_id] +; Interval as a duration between each synchronization. (default every 24h) +SCHEDULE = @every 24h + [git] ; The path of git executable. If empty, Gitea searches through the PATH environment. PATH = diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index ed34be032bbda..b927793a50811 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -419,6 +419,10 @@ NB: You must `REDIRECT_MACARON_LOG` and have `DISABLE_ROUTER_LOG` set to `false` - `RUN_AT_START`: **true**: Run repository statistics check at start time. - `SCHEDULE`: **@every 24h**: Cron syntax for scheduling repository statistics check. +### Cron - Update Migration Poster ID (`cron.update_migration_post_id`) + +- `SCHEDULE`: **@every 24h** : Interval as a duration between each synchronization, it will always attempt synchronization when the instance starts. + ## Git (`git`) - `PATH`: **""**: The path of git executable. If empty, Gitea searches through the PATH environment. diff --git a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md index 01ba821a47a38..ab73e2059eca0 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md +++ b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md @@ -196,7 +196,11 @@ menu: ### Cron - Repository Statistics Check (`cron.check_repo_stats`) - `RUN_AT_START`: 是否启动时自动运行仓库统计。 -- `SCHEDULE`: 藏亏统计时的Cron 语法,比如:`@every 24h`. +- `SCHEDULE`: 仓库统计时的Cron 语法,比如:`@every 24h`. + +### Cron - Update Migration Poster ID (`cron.update_migration_post_id`) + +- `SCHEDULE`: **@every 24h** : 每次同步的间隔时间。此任务总是在启动时自动进行。 ## Git (`git`) diff --git a/models/external_login_user.go b/models/external_login_user.go index 21a3cbbd312bc..5058fd1b4b781 100644 --- a/models/external_login_user.go +++ b/models/external_login_user.go @@ -4,13 +4,34 @@ package models -import "github.com/markbates/goth" +import ( + "time" + + "code.gitea.io/gitea/modules/structs" + + "github.com/markbates/goth" + "xorm.io/builder" +) // ExternalLoginUser makes the connecting between some existing user and additional external login sources type ExternalLoginUser struct { - ExternalID string `xorm:"pk NOT NULL"` - UserID int64 `xorm:"INDEX NOT NULL"` - LoginSourceID int64 `xorm:"pk NOT NULL"` + ExternalID string `xorm:"pk NOT NULL"` + UserID int64 `xorm:"INDEX NOT NULL"` + LoginSourceID int64 `xorm:"pk NOT NULL"` + RawData map[string]interface{} `xorm:"TEXT JSON"` + Provider string `xorm:"index VARCHAR(25)"` + Email string + Name string + FirstName string + LastName string + NickName string + Description string + AvatarURL string + Location string + AccessToken string + AccessTokenSecret string + RefreshToken string + ExpiresAt time.Time } // GetExternalLogin checks if a externalID in loginSourceID scope already exists @@ -32,23 +53,15 @@ func ListAccountLinks(user *User) ([]*ExternalLoginUser, error) { return externalAccounts, nil } -// LinkAccountToUser link the gothUser to the user -func LinkAccountToUser(user *User, gothUser goth.User) error { - loginSource, err := GetActiveOAuth2LoginSourceByName(gothUser.Provider) - if err != nil { - return err - } - - externalLoginUser := &ExternalLoginUser{ - ExternalID: gothUser.UserID, - UserID: user.ID, - LoginSourceID: loginSource.ID, - } - has, err := x.Get(externalLoginUser) +// LinkExternalToUser link the external user to the user +func LinkExternalToUser(user *User, externalLoginUser *ExternalLoginUser) error { + has, err := x.Where("external_id=? AND login_source_id=?", externalLoginUser.ExternalID, externalLoginUser.LoginSourceID). + NoAutoCondition(). + Exist(externalLoginUser) if err != nil { return err } else if has { - return ErrExternalLoginUserAlreadyExist{gothUser.UserID, user.ID, loginSource.ID} + return ErrExternalLoginUserAlreadyExist{externalLoginUser.ExternalID, user.ID, externalLoginUser.LoginSourceID} } _, err = x.Insert(externalLoginUser) @@ -72,3 +85,97 @@ func removeAllAccountLinks(e Engine, user *User) error { _, err := e.Delete(&ExternalLoginUser{UserID: user.ID}) return err } + +// GetUserIDByExternalUserID get user id according to provider and userID +func GetUserIDByExternalUserID(provider string, userID string) (int64, error) { + var id int64 + _, err := x.Table("external_login_user"). + Select("user_id"). + Where("provider=?", provider). + And("external_id=?", userID). + Get(&id) + if err != nil { + return 0, err + } + return id, nil +} + +// UpdateExternalUser updates external user's information +func UpdateExternalUser(user *User, gothUser goth.User) error { + loginSource, err := GetActiveOAuth2LoginSourceByName(gothUser.Provider) + if err != nil { + return err + } + externalLoginUser := &ExternalLoginUser{ + ExternalID: gothUser.UserID, + UserID: user.ID, + LoginSourceID: loginSource.ID, + RawData: gothUser.RawData, + Provider: gothUser.Provider, + Email: gothUser.Email, + Name: gothUser.Name, + FirstName: gothUser.FirstName, + LastName: gothUser.LastName, + NickName: gothUser.NickName, + Description: gothUser.Description, + AvatarURL: gothUser.AvatarURL, + Location: gothUser.Location, + AccessToken: gothUser.AccessToken, + AccessTokenSecret: gothUser.AccessTokenSecret, + RefreshToken: gothUser.RefreshToken, + ExpiresAt: gothUser.ExpiresAt, + } + + has, err := x.Where("external_id=? AND login_source_id=?", gothUser.UserID, loginSource.ID). + NoAutoCondition(). + Exist(externalLoginUser) + if err != nil { + return err + } else if !has { + return ErrExternalLoginUserNotExist{user.ID, loginSource.ID} + } + + _, err = x.Where("external_id=? AND login_source_id=?", gothUser.UserID, loginSource.ID).AllCols().Update(externalLoginUser) + return err +} + +// FindExternalUserOptions represents an options to find external users +type FindExternalUserOptions struct { + Provider string + Limit int + Start int +} + +func (opts FindExternalUserOptions) toConds() builder.Cond { + var cond = builder.NewCond() + if len(opts.Provider) > 0 { + cond = cond.And(builder.Eq{"provider": opts.Provider}) + } + return cond +} + +// FindExternalUsersByProvider represents external users via provider +func FindExternalUsersByProvider(opts FindExternalUserOptions) ([]ExternalLoginUser, error) { + var users []ExternalLoginUser + err := x.Where(opts.toConds()). + Limit(opts.Limit, opts.Start). + Asc("id"). + Find(&users) + if err != nil { + return nil, err + } + return users, nil +} + +// UpdateMigrationsByType updates all migrated repositories' posterid from gitServiceType to replace originalAuthorID to posterID +func UpdateMigrationsByType(tp structs.GitServiceType, externalUserID, userID int64) error { + if err := UpdateIssuesMigrationsByType(tp, externalUserID, userID); err != nil { + return err + } + + if err := UpdateCommentsMigrationsByType(tp, externalUserID, userID); err != nil { + return err + } + + return UpdateReleasesMigrationsByType(tp, externalUserID, userID) +} diff --git a/models/issue.go b/models/issue.go index 8ce7d496ab465..fc675a3ffbe2a 100644 --- a/models/issue.go +++ b/models/issue.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" @@ -32,7 +33,7 @@ type Issue struct { PosterID int64 `xorm:"INDEX"` Poster *User `xorm:"-"` OriginalAuthor string - OriginalAuthorID int64 + OriginalAuthorID int64 `xorm:"index"` Title string `xorm:"name"` Content string `xorm:"TEXT"` RenderedContent string `xorm:"-"` @@ -1947,3 +1948,16 @@ func (issue *Issue) ResolveMentionsByVisibility(ctx DBContext, doer *User, menti return } + +// UpdateIssuesMigrationsByType updates all migrated repositories' issues from gitServiceType to replace originalAuthorID to posterID +func UpdateIssuesMigrationsByType(gitServiceType structs.GitServiceType, originalAuthorID, posterID int64) error { + _, err := x.Table("issue"). + Where("repo_id IN (SELECT id FROM repository WHERE original_service_type = ?)", gitServiceType). + And("original_author_id = ?", originalAuthorID). + Update(map[string]interface{}{ + "poster_id": posterID, + "original_author": "", + "original_author_id": 0, + }) + return err +} diff --git a/models/issue_comment.go b/models/issue_comment.go index 7d38302b98dbb..3a090c3b19fd3 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/references" + "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" @@ -1022,3 +1023,23 @@ func fetchCodeCommentsByReview(e Engine, issue *Issue, currentUser *User, review func FetchCodeComments(issue *Issue, currentUser *User) (CodeComments, error) { return fetchCodeComments(x, issue, currentUser) } + +// UpdateCommentsMigrationsByType updates comments' migrations information via given git service type and original id and poster id +func UpdateCommentsMigrationsByType(tp structs.GitServiceType, originalAuthorID, posterID int64) error { + _, err := x.Table("comment"). + Where(builder.In("issue_id", + builder.Select("issue.id"). + From("issue"). + InnerJoin("repository", "issue.repo_id = repository.id"). + Where(builder.Eq{ + "repository.original_service_type": tp, + }), + )). + And("comment.original_author_id = ?", originalAuthorID). + Update(map[string]interface{}{ + "poster_id": posterID, + "original_author": "", + "original_author_id": 0, + }) + return err +} diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index ef5cd377a6c11..60a416c6e92ea 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -254,6 +254,8 @@ var migrations = []Migration{ NewMigration("add original author name and id on migrated release", addOriginalAuthorOnMigratedReleases), // v99 -> v100 NewMigration("add task table and status column for repository table", addTaskTable), + // v100 -> v101 + NewMigration("update migration repositories' service type", updateMigrationServiceTypes), } // Migrate database to current version diff --git a/models/migrations/v100.go b/models/migrations/v100.go new file mode 100644 index 0000000000000..ac3b73e2ad2a9 --- /dev/null +++ b/models/migrations/v100.go @@ -0,0 +1,83 @@ +// Copyright 2019 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 ( + "net/url" + "strings" + "time" + + "github.com/go-xorm/xorm" +) + +func updateMigrationServiceTypes(x *xorm.Engine) error { + type Repository struct { + ID int64 + OriginalServiceType int `xorm:"index default(0)"` + OriginalURL string `xorm:"VARCHAR(2048)"` + } + + if err := x.Sync2(new(Repository)); err != nil { + return err + } + + var last int + const batchSize = 50 + for { + var results = make([]Repository, 0, batchSize) + err := x.Where("original_url <> '' AND original_url IS NOT NULL"). + And("original_service_type = 0 OR original_service_type IS NULL"). + OrderBy("id"). + Limit(batchSize, last). + Find(&results) + if err != nil { + return err + } + if len(results) == 0 { + break + } + last += len(results) + + const PlainGitService = 1 // 1 plain git service + const GithubService = 2 // 2 github.com + + for _, res := range results { + u, err := url.Parse(res.OriginalURL) + if err != nil { + return err + } + var serviceType = PlainGitService + if strings.EqualFold(u.Host, "github.com") { + serviceType = GithubService + } + _, err = x.Exec("UPDATE repository SET original_service_type = ? WHERE id = ?", serviceType, res.ID) + if err != nil { + return err + } + } + } + + type ExternalLoginUser struct { + ExternalID string `xorm:"pk NOT NULL"` + UserID int64 `xorm:"INDEX NOT NULL"` + LoginSourceID int64 `xorm:"pk NOT NULL"` + RawData map[string]interface{} `xorm:"TEXT JSON"` + Provider string `xorm:"index VARCHAR(25)"` + Email string + Name string + FirstName string + LastName string + NickName string + Description string + AvatarURL string + Location string + AccessToken string + AccessTokenSecret string + RefreshToken string + ExpiresAt time.Time + } + + return x.Sync2(new(ExternalLoginUser)) +} diff --git a/models/release.go b/models/release.go index 243cc2fa3c31a..03685e0a44c79 100644 --- a/models/release.go +++ b/models/release.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" @@ -366,3 +367,16 @@ func SyncReleasesWithTags(repo *Repository, gitRepo *git.Repository) error { } return nil } + +// UpdateReleasesMigrationsByType updates all migrated repositories' releases from gitServiceType to replace originalAuthorID to posterID +func UpdateReleasesMigrationsByType(gitServiceType structs.GitServiceType, originalAuthorID, posterID int64) error { + _, err := x.Table("release"). + Where("repo_id IN (SELECT id FROM repository WHERE original_service_type = ?)", gitServiceType). + And("original_author_id = ?", originalAuthorID). + Update(map[string]interface{}{ + "publisher_id": posterID, + "original_author": "", + "original_author_id": 0, + }) + return err +} diff --git a/models/repo.go b/models/repo.go index 23b1c2ef52c4d..aa2cf06f326dd 100644 --- a/models/repo.go +++ b/models/repo.go @@ -32,6 +32,7 @@ import ( "code.gitea.io/gitea/modules/options" "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/sync" "code.gitea.io/gitea/modules/timeutil" @@ -137,16 +138,17 @@ const ( // Repository represents a git repository. type Repository struct { - ID int64 `xorm:"pk autoincr"` - OwnerID int64 `xorm:"UNIQUE(s) index"` - OwnerName string `xorm:"-"` - Owner *User `xorm:"-"` - LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"` - Name string `xorm:"INDEX NOT NULL"` - Description string `xorm:"TEXT"` - Website string `xorm:"VARCHAR(2048)"` - OriginalURL string `xorm:"VARCHAR(2048)"` - DefaultBranch string + ID int64 `xorm:"pk autoincr"` + OwnerID int64 `xorm:"UNIQUE(s) index"` + OwnerName string `xorm:"-"` + Owner *User `xorm:"-"` + LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"` + Name string `xorm:"INDEX NOT NULL"` + Description string `xorm:"TEXT"` + Website string `xorm:"VARCHAR(2048)"` + OriginalServiceType structs.GitServiceType `xorm:"index"` + OriginalURL string `xorm:"VARCHAR(2048)"` + DefaultBranch string NumWatches int NumStars int diff --git a/modules/cron/cron.go b/modules/cron/cron.go index 089f0fa767a6f..795fafb51fdaa 100644 --- a/modules/cron/cron.go +++ b/modules/cron/cron.go @@ -10,6 +10,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/migrations" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/sync" mirror_service "code.gitea.io/gitea/services/mirror" @@ -18,12 +19,13 @@ import ( ) const ( - mirrorUpdate = "mirror_update" - gitFsck = "git_fsck" - checkRepos = "check_repos" - archiveCleanup = "archive_cleanup" - syncExternalUsers = "sync_external_users" - deletedBranchesCleanup = "deleted_branches_cleanup" + mirrorUpdate = "mirror_update" + gitFsck = "git_fsck" + checkRepos = "check_repos" + archiveCleanup = "archive_cleanup" + syncExternalUsers = "sync_external_users" + deletedBranchesCleanup = "deleted_branches_cleanup" + updateMigrationPosterID = "update_migration_post_id" ) var c = cron.New() @@ -117,6 +119,15 @@ func NewContext() { go WithUnique(deletedBranchesCleanup, models.RemoveOldDeletedBranches)() } } + + entry, err = c.AddFunc("Update migrated repositories' issues and comments' posterid", setting.Cron.UpdateMigrationPosterID.Schedule, WithUnique(updateMigrationPosterID, migrations.UpdateMigrationPosterID)) + if err != nil { + log.Fatal("Cron[Update migrated repositories]: %v", err) + } + entry.Prev = time.Now() + entry.ExecTimes++ + go WithUnique(updateMigrationPosterID, migrations.UpdateMigrationPosterID)() + c.Start() } diff --git a/modules/migrations/base/downloader.go b/modules/migrations/base/downloader.go index ab5ca6dec80ff..69c2adb9e9503 100644 --- a/modules/migrations/base/downloader.go +++ b/modules/migrations/base/downloader.go @@ -5,6 +5,8 @@ package base +import "code.gitea.io/gitea/modules/structs" + // Downloader downloads the site repo informations type Downloader interface { GetRepoInfo() (*Repository, error) @@ -21,4 +23,5 @@ type Downloader interface { type DownloaderFactory interface { Match(opts MigrateOptions) (bool, error) New(opts MigrateOptions) (Downloader, error) + GitServiceType() structs.GitServiceType } diff --git a/modules/migrations/gitea.go b/modules/migrations/gitea.go index ab3b0b9f694ad..2452a7a88322f 100644 --- a/modules/migrations/gitea.go +++ b/modules/migrations/gitea.go @@ -34,15 +34,17 @@ var ( // GiteaLocalUploader implements an Uploader to gitea sites type GiteaLocalUploader struct { - doer *models.User - repoOwner string - repoName string - repo *models.Repository - labels sync.Map - milestones sync.Map - issues sync.Map - gitRepo *git.Repository - prHeadCache map[string]struct{} + doer *models.User + repoOwner string + repoName string + repo *models.Repository + labels sync.Map + milestones sync.Map + issues sync.Map + gitRepo *git.Repository + prHeadCache map[string]struct{} + userMap map[int64]int64 // external user id mapping to user id + gitServiceType structs.GitServiceType } // NewGiteaLocalUploader creates an gitea Uploader via gitea API v1 @@ -52,6 +54,7 @@ func NewGiteaLocalUploader(doer *models.User, repoOwner, repoName string) *Gitea repoOwner: repoOwner, repoName: repoName, prHeadCache: make(map[string]struct{}), + userMap: make(map[int64]int64), } } @@ -109,13 +112,15 @@ func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, opts base.Migrate } r, err = models.MigrateRepositoryGitData(g.doer, owner, r, structs.MigrateRepoOption{ - RepoName: g.repoName, - Description: repo.Description, - Mirror: repo.IsMirror, - CloneAddr: remoteAddr, - Private: repo.IsPrivate, - Wiki: opts.Wiki, - Releases: opts.Releases, // if didn't get releases, then sync them from tags + RepoName: g.repoName, + Description: repo.Description, + OriginalURL: repo.OriginalURL, + GitServiceType: opts.GitServiceType, + Mirror: repo.IsMirror, + CloneAddr: remoteAddr, + Private: repo.IsPrivate, + Wiki: opts.Wiki, + Releases: opts.Releases, // if didn't get releases, then sync them from tags }) g.repo = r @@ -193,20 +198,38 @@ func (g *GiteaLocalUploader) CreateReleases(releases ...*base.Release) error { var rels = make([]*models.Release, 0, len(releases)) for _, release := range releases { var rel = models.Release{ - RepoID: g.repo.ID, - PublisherID: g.doer.ID, - TagName: release.TagName, - LowerTagName: strings.ToLower(release.TagName), - Target: release.TargetCommitish, - Title: release.Name, - Sha1: release.TargetCommitish, - Note: release.Body, - IsDraft: release.Draft, - IsPrerelease: release.Prerelease, - IsTag: false, - CreatedUnix: timeutil.TimeStamp(release.Created.Unix()), - OriginalAuthor: release.PublisherName, - OriginalAuthorID: release.PublisherID, + RepoID: g.repo.ID, + TagName: release.TagName, + LowerTagName: strings.ToLower(release.TagName), + Target: release.TargetCommitish, + Title: release.Name, + Sha1: release.TargetCommitish, + Note: release.Body, + IsDraft: release.Draft, + IsPrerelease: release.Prerelease, + IsTag: false, + CreatedUnix: timeutil.TimeStamp(release.Created.Unix()), + } + + userid, ok := g.userMap[release.PublisherID] + tp := g.gitServiceType.Name() + if !ok && tp != "" { + var err error + userid, err = models.GetUserIDByExternalUserID(tp, fmt.Sprintf("%v", release.PublisherID)) + if err != nil { + log.Error("GetUserIDByExternalUserID: %v", err) + } + if userid > 0 { + g.userMap[release.PublisherID] = userid + } + } + + if userid > 0 { + rel.PublisherID = userid + } else { + rel.PublisherID = g.doer.ID + rel.OriginalAuthor = release.PublisherName + rel.OriginalAuthorID = release.PublisherID } // calc NumCommits @@ -284,20 +307,39 @@ func (g *GiteaLocalUploader) CreateIssues(issues ...*base.Issue) error { } var is = models.Issue{ - RepoID: g.repo.ID, - Repo: g.repo, - Index: issue.Number, - PosterID: g.doer.ID, - OriginalAuthor: issue.PosterName, - OriginalAuthorID: issue.PosterID, - Title: issue.Title, - Content: issue.Content, - IsClosed: issue.State == "closed", - IsLocked: issue.IsLocked, - MilestoneID: milestoneID, - Labels: labels, - CreatedUnix: timeutil.TimeStamp(issue.Created.Unix()), + RepoID: g.repo.ID, + Repo: g.repo, + Index: issue.Number, + Title: issue.Title, + Content: issue.Content, + IsClosed: issue.State == "closed", + IsLocked: issue.IsLocked, + MilestoneID: milestoneID, + Labels: labels, + CreatedUnix: timeutil.TimeStamp(issue.Created.Unix()), + } + + userid, ok := g.userMap[issue.PosterID] + tp := g.gitServiceType.Name() + if !ok && tp != "" { + var err error + userid, err = models.GetUserIDByExternalUserID(tp, fmt.Sprintf("%v", issue.PosterID)) + if err != nil { + log.Error("GetUserIDByExternalUserID: %v", err) + } + if userid > 0 { + g.userMap[issue.PosterID] = userid + } + } + + if userid > 0 { + is.PosterID = userid + } else { + is.PosterID = g.doer.ID + is.OriginalAuthor = issue.PosterName + is.OriginalAuthorID = issue.PosterID } + if issue.Closed != nil { is.ClosedUnix = timeutil.TimeStamp(issue.Closed.Unix()) } @@ -331,15 +373,35 @@ func (g *GiteaLocalUploader) CreateComments(comments ...*base.Comment) error { issueID = issueIDStr.(int64) } - cms = append(cms, &models.Comment{ - IssueID: issueID, - Type: models.CommentTypeComment, - PosterID: g.doer.ID, - OriginalAuthor: comment.PosterName, - OriginalAuthorID: comment.PosterID, - Content: comment.Content, - CreatedUnix: timeutil.TimeStamp(comment.Created.Unix()), - }) + userid, ok := g.userMap[comment.PosterID] + tp := g.gitServiceType.Name() + if !ok && tp != "" { + var err error + userid, err = models.GetUserIDByExternalUserID(tp, fmt.Sprintf("%v", comment.PosterID)) + if err != nil { + log.Error("GetUserIDByExternalUserID: %v", err) + } + if userid > 0 { + g.userMap[comment.PosterID] = userid + } + } + + cm := models.Comment{ + IssueID: issueID, + Type: models.CommentTypeComment, + Content: comment.Content, + CreatedUnix: timeutil.TimeStamp(comment.Created.Unix()), + } + + if userid > 0 { + cm.PosterID = userid + } else { + cm.PosterID = g.doer.ID + cm.OriginalAuthor = comment.PosterName + cm.OriginalAuthorID = comment.PosterID + } + + cms = append(cms, &cm) // TODO: Reactions } @@ -355,6 +417,28 @@ func (g *GiteaLocalUploader) CreatePullRequests(prs ...*base.PullRequest) error if err != nil { return err } + + userid, ok := g.userMap[pr.PosterID] + tp := g.gitServiceType.Name() + if !ok && tp != "" { + var err error + userid, err = models.GetUserIDByExternalUserID(tp, fmt.Sprintf("%v", pr.PosterID)) + if err != nil { + log.Error("GetUserIDByExternalUserID: %v", err) + } + if userid > 0 { + g.userMap[pr.PosterID] = userid + } + } + + if userid > 0 { + gpr.Issue.PosterID = userid + } else { + gpr.Issue.PosterID = g.doer.ID + gpr.Issue.OriginalAuthor = pr.PosterName + gpr.Issue.OriginalAuthorID = pr.PosterID + } + gprs = append(gprs, gpr) } if err := models.InsertPullRequests(gprs...); err != nil { @@ -460,6 +544,40 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR head = pr.Head.Ref } + var issue = models.Issue{ + RepoID: g.repo.ID, + Repo: g.repo, + Title: pr.Title, + Index: pr.Number, + Content: pr.Content, + MilestoneID: milestoneID, + IsPull: true, + IsClosed: pr.State == "closed", + IsLocked: pr.IsLocked, + Labels: labels, + CreatedUnix: timeutil.TimeStamp(pr.Created.Unix()), + } + + userid, ok := g.userMap[pr.PosterID] + if !ok { + var err error + userid, err = models.GetUserIDByExternalUserID("github", fmt.Sprintf("%v", pr.PosterID)) + if err != nil { + log.Error("GetUserIDByExternalUserID: %v", err) + } + if userid > 0 { + g.userMap[pr.PosterID] = userid + } + } + + if userid > 0 { + issue.PosterID = userid + } else { + issue.PosterID = g.doer.ID + issue.OriginalAuthor = pr.PosterName + issue.OriginalAuthorID = pr.PosterID + } + var pullRequest = models.PullRequest{ HeadRepoID: g.repo.ID, HeadBranch: head, @@ -470,22 +588,7 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR Index: pr.Number, HasMerged: pr.Merged, - Issue: &models.Issue{ - RepoID: g.repo.ID, - Repo: g.repo, - Title: pr.Title, - Index: pr.Number, - PosterID: g.doer.ID, - OriginalAuthor: pr.PosterName, - OriginalAuthorID: pr.PosterID, - Content: pr.Content, - MilestoneID: milestoneID, - IsPull: true, - IsClosed: pr.State == "closed", - IsLocked: pr.IsLocked, - Labels: labels, - CreatedUnix: timeutil.TimeStamp(pr.Created.Unix()), - }, + Issue: &issue, } if pullRequest.Issue.IsClosed && pr.Closed != nil { diff --git a/modules/migrations/github.go b/modules/migrations/github.go index 1c5d96c03d471..00d137a3de69a 100644 --- a/modules/migrations/github.go +++ b/modules/migrations/github.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/migrations/base" + "code.gitea.io/gitea/modules/structs" "github.com/google/go-github/v24/github" "golang.org/x/oauth2" @@ -39,7 +40,7 @@ func (f *GithubDownloaderV3Factory) Match(opts base.MigrateOptions) (bool, error return false, err } - return u.Host == "github.com" && opts.AuthUsername != "", nil + return strings.EqualFold(u.Host, "github.com") && opts.AuthUsername != "", nil } // New returns a Downloader related to this factory according MigrateOptions @@ -58,6 +59,11 @@ func (f *GithubDownloaderV3Factory) New(opts base.MigrateOptions) (base.Download return NewGithubDownloaderV3(opts.AuthUsername, opts.AuthPassword, oldOwner, oldName), nil } +// GitServiceType returns the type of git service +func (f *GithubDownloaderV3Factory) GitServiceType() structs.GitServiceType { + return structs.GithubService +} + // GithubDownloaderV3 implements a Downloader interface to get repository informations // from github via APIv3 type GithubDownloaderV3 struct { diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go index 3f5c0d1118c32..bbc1dc2d56107 100644 --- a/modules/migrations/migrate.go +++ b/modules/migrations/migrate.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/migrations/base" + "code.gitea.io/gitea/modules/structs" ) // MigrateOptions is equal to base.MigrateOptions @@ -30,6 +31,7 @@ func MigrateRepository(doer *models.User, ownerName string, opts base.MigrateOpt var ( downloader base.Downloader uploader = NewGiteaLocalUploader(doer, ownerName, opts.RepoName) + theFactory base.DownloaderFactory ) for _, factory := range factories { @@ -40,6 +42,7 @@ func MigrateRepository(doer *models.User, ownerName string, opts base.MigrateOpt if err != nil { return nil, err } + theFactory = factory break } } @@ -52,10 +55,14 @@ func MigrateRepository(doer *models.User, ownerName string, opts base.MigrateOpt opts.Comments = false opts.Issues = false opts.PullRequests = false + opts.GitServiceType = structs.PlainGitService downloader = NewPlainGitDownloader(ownerName, opts.RepoName, opts.CloneAddr) log.Trace("Will migrate from git: %s", opts.CloneAddr) + } else if opts.GitServiceType == structs.NotMigrated { + opts.GitServiceType = theFactory.GitServiceType() } + uploader.gitServiceType = opts.GitServiceType if err := migrateRepository(downloader, uploader, opts); err != nil { if err1 := uploader.Rollback(); err1 != nil { log.Error("rollback failed: %v", err1) diff --git a/modules/migrations/update.go b/modules/migrations/update.go new file mode 100644 index 0000000000000..df626ddd955e9 --- /dev/null +++ b/modules/migrations/update.go @@ -0,0 +1,59 @@ +// Copyright 2019 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 ( + "strconv" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/structs" +) + +// UpdateMigrationPosterID updates all migrated repositories' issues and comments posterID +func UpdateMigrationPosterID() { + for _, gitService := range structs.SupportedFullGitService { + if err := updateMigrationPosterIDByGitService(gitService); err != nil { + log.Error("updateMigrationPosterIDByGitService failed: %v", err) + } + } +} + +func updateMigrationPosterIDByGitService(tp structs.GitServiceType) error { + provider := tp.Name() + if len(provider) == 0 { + return nil + } + + const batchSize = 100 + var start int + for { + users, err := models.FindExternalUsersByProvider(models.FindExternalUserOptions{ + Provider: provider, + Start: start, + Limit: batchSize, + }) + if err != nil { + return err + } + + for _, user := range users { + externalUserID, err := strconv.ParseInt(user.ExternalID, 10, 64) + if err != nil { + log.Warn("Parse externalUser %#v 's userID failed: %v", user, err) + continue + } + if err := models.UpdateMigrationsByType(tp, externalUserID, user.UserID); err != nil { + log.Error("UpdateMigrationsByType type %s external user id %v to local user id %v failed: %v", tp.Name(), user.ExternalID, user.UserID, err) + } + } + + if len(users) < batchSize { + break + } + start += len(users) + } + return nil +} diff --git a/modules/setting/cron.go b/modules/setting/cron.go index c544c6c22878e..77f55168aa3b7 100644 --- a/modules/setting/cron.go +++ b/modules/setting/cron.go @@ -49,6 +49,9 @@ var ( Schedule string OlderThan time.Duration } `ini:"cron.deleted_branches_cleanup"` + UpdateMigrationPosterID struct { + Schedule string + } `ini:"cron.update_migration_poster_id"` }{ UpdateMirror: struct { Enabled bool @@ -114,6 +117,11 @@ var ( Schedule: "@every 24h", OlderThan: 24 * time.Hour, }, + UpdateMigrationPosterID: struct { + Schedule string + }{ + Schedule: "@every 24h", + }, } ) diff --git a/modules/structs/repo.go b/modules/structs/repo.go index 57f1768a0b943..be6a3d4b43e4f 100644 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -153,6 +153,43 @@ type EditRepoOption struct { Archived *bool `json:"archived,omitempty"` } +// GitServiceType represents a git service +type GitServiceType int + +// enumerate all GitServiceType +const ( + NotMigrated GitServiceType = iota // 0 not migrated from external sites + PlainGitService // 1 plain git service + GithubService // 2 github.com + GiteaService // 3 gitea service + GitlabService // 4 gitlab service + GogsService // 5 gogs service +) + +// Name represents the service type's name +// WARNNING: the name have to be equal to that on goth's library +func (gt GitServiceType) Name() string { + switch gt { + case GithubService: + return "github" + case GiteaService: + return "gitea" + case GitlabService: + return "gitlab" + case GogsService: + return "gogs" + } + return "" +} + +var ( + // SupportedFullGitService represents all git services supported to migrate issues/labels/prs and etc. + // TODO: add to this list after new git service added + SupportedFullGitService = []GitServiceType{ + GithubService, + } +) + // MigrateRepoOption options for migrating a repository from an external service type MigrateRepoOption struct { // required: true @@ -166,6 +203,8 @@ type MigrateRepoOption struct { Mirror bool `json:"mirror"` Private bool `json:"private"` Description string `json:"description"` + OriginalURL string + GitServiceType GitServiceType Wiki bool Issues bool Milestones bool diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 08c0635bc3128..a4417107ee384 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -8,6 +8,7 @@ package repo import ( "fmt" "net/http" + "net/url" "strings" "code.gitea.io/gitea/models" @@ -17,6 +18,7 @@ import ( "code.gitea.io/gitea/modules/migrations" "code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/validation" @@ -397,21 +399,28 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) { return } + var gitServiceType = structs.PlainGitService + u, err := url.Parse(remoteAddr) + if err == nil && strings.EqualFold(u.Host, "github.com") { + gitServiceType = structs.GithubService + } + var opts = migrations.MigrateOptions{ - CloneAddr: remoteAddr, - RepoName: form.RepoName, - Description: form.Description, - Private: form.Private || setting.Repository.ForcePrivate, - Mirror: form.Mirror, - AuthUsername: form.AuthUsername, - AuthPassword: form.AuthPassword, - Wiki: form.Wiki, - Issues: form.Issues, - Milestones: form.Milestones, - Labels: form.Labels, - Comments: true, - PullRequests: form.PullRequests, - Releases: form.Releases, + CloneAddr: remoteAddr, + RepoName: form.RepoName, + Description: form.Description, + Private: form.Private || setting.Repository.ForcePrivate, + Mirror: form.Mirror, + AuthUsername: form.AuthUsername, + AuthPassword: form.AuthPassword, + Wiki: form.Wiki, + Issues: form.Issues, + Milestones: form.Milestones, + Labels: form.Labels, + Comments: true, + PullRequests: form.PullRequests, + Releases: form.Releases, + GitServiceType: gitServiceType, } if opts.Mirror { opts.Issues = false diff --git a/routers/user/auth.go b/routers/user/auth.go index 3def867f6456d..212d535a06498 100644 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -21,6 +21,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/externalaccount" "code.gitea.io/gitea/services/mailer" "gitea.com/macaron/captcha" @@ -277,7 +278,7 @@ func TwoFactorPost(ctx *context.Context, form auth.TwoFactorAuthForm) { return } - err = models.LinkAccountToUser(u, gothUser.(goth.User)) + err = externalaccount.LinkAccountToUser(u, gothUser.(goth.User)) if err != nil { ctx.ServerError("UserSignIn", err) return @@ -452,7 +453,7 @@ func U2FSign(ctx *context.Context, signResp u2f.SignResponse) { return } - err = models.LinkAccountToUser(user, gothUser.(goth.User)) + err = externalaccount.LinkAccountToUser(user, gothUser.(goth.User)) if err != nil { ctx.ServerError("UserSignIn", err) return @@ -601,36 +602,42 @@ func handleOAuth2SignIn(u *models.User, gothUser goth.User, ctx *context.Context // Instead, redirect them to the 2FA authentication page. _, err = models.GetTwoFactorByUID(u.ID) if err != nil { - if models.IsErrTwoFactorNotEnrolled(err) { - err = ctx.Session.Set("uid", u.ID) - if err != nil { - log.Error(fmt.Sprintf("Error setting session: %v", err)) - } - err = ctx.Session.Set("uname", u.Name) - if err != nil { - log.Error(fmt.Sprintf("Error setting session: %v", err)) - } + if !models.IsErrTwoFactorNotEnrolled(err) { + ctx.ServerError("UserSignIn", err) + return + } - // Clear whatever CSRF has right now, force to generate a new one - ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) + err = ctx.Session.Set("uid", u.ID) + if err != nil { + log.Error(fmt.Sprintf("Error setting session: %v", err)) + } + err = ctx.Session.Set("uname", u.Name) + if err != nil { + log.Error(fmt.Sprintf("Error setting session: %v", err)) + } - // Register last login - u.SetLastLogin() - if err := models.UpdateUserCols(u, "last_login_unix"); err != nil { - ctx.ServerError("UpdateUserCols", err) - return - } + // Clear whatever CSRF has right now, force to generate a new one + ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) - if redirectTo := ctx.GetCookie("redirect_to"); len(redirectTo) > 0 { - ctx.SetCookie("redirect_to", "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true) - ctx.RedirectToFirst(redirectTo) - return - } + // Register last login + u.SetLastLogin() + if err := models.UpdateUserCols(u, "last_login_unix"); err != nil { + ctx.ServerError("UpdateUserCols", err) + return + } - ctx.Redirect(setting.AppSubURL + "/") - } else { - ctx.ServerError("UserSignIn", err) + // update external user information + if err := models.UpdateExternalUser(u, gothUser); err != nil { + log.Error("UpdateExternalUser failed: %v", err) + } + + if redirectTo := ctx.GetCookie("redirect_to"); len(redirectTo) > 0 { + ctx.SetCookie("redirect_to", "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true) + ctx.RedirectToFirst(redirectTo) + return } + + ctx.Redirect(setting.AppSubURL + "/") return } @@ -675,7 +682,7 @@ func oAuth2UserLoginCallback(loginSource *models.LoginSource, request *http.Requ } if hasUser { - return user, goth.User{}, nil + return user, gothUser, nil } // search in external linked users @@ -689,7 +696,7 @@ func oAuth2UserLoginCallback(loginSource *models.LoginSource, request *http.Requ } if hasUser { user, err = models.GetUserByID(externalLoginUser.UserID) - return user, goth.User{}, err + return user, gothUser, err } // no user found to login @@ -789,16 +796,18 @@ func LinkAccountPostSignIn(ctx *context.Context, signInForm auth.SignInForm) { // Instead, redirect them to the 2FA authentication page. _, err = models.GetTwoFactorByUID(u.ID) if err != nil { - if models.IsErrTwoFactorNotEnrolled(err) { - err = models.LinkAccountToUser(u, gothUser.(goth.User)) - if err != nil { - ctx.ServerError("UserLinkAccount", err) - } else { - handleSignIn(ctx, u, signInForm.Remember) - } - } else { + if !models.IsErrTwoFactorNotEnrolled(err) { + ctx.ServerError("UserLinkAccount", err) + return + } + + err = externalaccount.LinkAccountToUser(u, gothUser.(goth.User)) + if err != nil { ctx.ServerError("UserLinkAccount", err) + return } + + handleSignIn(ctx, u, signInForm.Remember) return } @@ -947,6 +956,11 @@ func LinkAccountPostRegister(ctx *context.Context, cpt *captcha.Captcha, form au } } + // update external user information + if err := models.UpdateExternalUser(u, gothUser.(goth.User)); err != nil { + log.Error("UpdateExternalUser failed: %v", err) + } + // Send confirmation email if setting.Service.RegisterEmailConfirm && u.ID > 1 { mailer.SendActivateAccountMail(ctx.Locale, u) diff --git a/services/externalaccount/user.go b/services/externalaccount/user.go new file mode 100644 index 0000000000000..800546f123114 --- /dev/null +++ b/services/externalaccount/user.go @@ -0,0 +1,66 @@ +// Copyright 2019 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 externalaccount + +import ( + "strconv" + "strings" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/structs" + + "github.com/markbates/goth" +) + +// LinkAccountToUser link the gothUser to the user +func LinkAccountToUser(user *models.User, gothUser goth.User) error { + loginSource, err := models.GetActiveOAuth2LoginSourceByName(gothUser.Provider) + if err != nil { + return err + } + + externalLoginUser := &models.ExternalLoginUser{ + ExternalID: gothUser.UserID, + UserID: user.ID, + LoginSourceID: loginSource.ID, + RawData: gothUser.RawData, + Provider: gothUser.Provider, + Email: gothUser.Email, + Name: gothUser.Name, + FirstName: gothUser.FirstName, + LastName: gothUser.LastName, + NickName: gothUser.NickName, + Description: gothUser.Description, + AvatarURL: gothUser.AvatarURL, + Location: gothUser.Location, + AccessToken: gothUser.AccessToken, + AccessTokenSecret: gothUser.AccessTokenSecret, + RefreshToken: gothUser.RefreshToken, + ExpiresAt: gothUser.ExpiresAt, + } + + if err := models.LinkExternalToUser(user, externalLoginUser); err != nil { + return err + } + + externalID, err := strconv.ParseInt(externalLoginUser.ExternalID, 10, 64) + if err != nil { + return err + } + + var tp structs.GitServiceType + for _, s := range structs.SupportedFullGitService { + if strings.EqualFold(s.Name(), gothUser.Provider) { + tp = s + break + } + } + + if tp.Name() != "" { + return models.UpdateMigrationsByType(tp, externalID, user.ID) + } + + return nil +} From f9aba9ba0f07b77cb46dde6eda3c3f5b8fa841fe Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 14 Oct 2019 15:22:46 +0800 Subject: [PATCH 079/173] fix bug on FindExternalUsersByProvider (#8504) --- models/external_login_user.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/external_login_user.go b/models/external_login_user.go index 5058fd1b4b781..59c37321844f5 100644 --- a/models/external_login_user.go +++ b/models/external_login_user.go @@ -159,7 +159,7 @@ func FindExternalUsersByProvider(opts FindExternalUserOptions) ([]ExternalLoginU var users []ExternalLoginUser err := x.Where(opts.toConds()). Limit(opts.Limit, opts.Start). - Asc("id"). + OrderBy("login_source_id ASC, external_id ASC"). Find(&users) if err != nil { return nil, err From db657192d0349f7b10a62515fbf085d3a48d88f9 Mon Sep 17 00:00:00 2001 From: Maxim Tkachenko Date: Mon, 14 Oct 2019 22:24:26 +0700 Subject: [PATCH 080/173] Password Complexity Checks (#6230) Add password complexity checks. The default settings require a lowercase, uppercase, number and a special character within passwords. Co-Authored-By: T-M-A Co-Authored-By: Lanre Adelowo Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> Co-Authored-By: Lauris BH --- cmd/admin.go | 19 ++--- custom/conf/app.ini.sample | 5 +- .../doc/advanced/config-cheat-sheet.en-us.md | 5 ++ modules/password/password.go | 73 +++++++++++++++++ modules/setting/setting.go | 22 +++++ options/locale/locale_en-US.ini | 1 + routers/admin/users.go | 10 ++- routers/api/v1/admin/user.go | 14 +++- routers/user/auth.go | 11 +-- routers/user/setting/account.go | 3 + routers/user/setting/account_test.go | 81 ++++++++++++++----- 11 files changed, 207 insertions(+), 37 deletions(-) create mode 100644 modules/password/password.go diff --git a/cmd/admin.go b/cmd/admin.go index 4c4d6f9b66e37..4346159febf81 100644 --- a/cmd/admin.go +++ b/cmd/admin.go @@ -13,9 +13,9 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/auth/oauth2" - "code.gitea.io/gitea/modules/generate" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" + pwd "code.gitea.io/gitea/modules/password" "code.gitea.io/gitea/modules/setting" "github.com/urfave/cli" @@ -233,7 +233,9 @@ func runChangePassword(c *cli.Context) error { if err := initDB(); err != nil { return err } - + if !pwd.IsComplexEnough(c.String("password")) { + return errors.New("Password does not meet complexity requirements") + } uname := c.String("username") user, err := models.GetUserByName(uname) if err != nil { @@ -243,6 +245,7 @@ func runChangePassword(c *cli.Context) error { return err } user.HashPassword(c.String("password")) + if err := models.UpdateUserCols(user, "passwd", "salt"); err != nil { return err } @@ -275,26 +278,24 @@ func runCreateUser(c *cli.Context) error { fmt.Fprintf(os.Stderr, "--name flag is deprecated. Use --username instead.\n") } - var password string + if err := initDB(); err != nil { + return err + } + var password string if c.IsSet("password") { password = c.String("password") } else if c.IsSet("random-password") { var err error - password, err = generate.GetRandomString(c.Int("random-password-length")) + password, err = pwd.Generate(c.Int("random-password-length")) if err != nil { return err } - fmt.Printf("generated random password is '%s'\n", password) } else { return errors.New("must set either password or random-password flag") } - if err := initDB(); err != nil { - return err - } - // always default to true var changePassword = true diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index fd8d928ede544..79d9960052490 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -332,6 +332,9 @@ MIN_PASSWORD_LENGTH = 6 IMPORT_LOCAL_PATHS = false ; Set to true to prevent all users (including admin) from creating custom git hooks DISABLE_GIT_HOOKS = false +;Comma separated list of character classes required to pass minimum complexity. +;If left empty or no valid values are specified, the default values (`lower,upper,digit,spec`) will be used. +PASSWORD_COMPLEXITY = lower,upper,digit,spec ; Password Hash algorithm, either "pbkdf2", "argon2", "scrypt" or "bcrypt" PASSWORD_HASH_ALGO = pbkdf2 ; Set false to allow JavaScript to read CSRF cookie @@ -415,7 +418,7 @@ DEFAULT_ALLOW_CREATE_ORGANIZATION = true ; Public is for everyone DEFAULT_ORG_VISIBILITY = public ; Default value for DefaultOrgMemberVisible -; True will make the membership of the users visible when added to the organisation +; True will make the membership of the users visible when added to the organisation DEFAULT_ORG_MEMBER_VISIBLE = false ; Default value for EnableDependencies ; Repositories will use dependencies by default depending on this setting diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index b927793a50811..100bb229ee6ab 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -208,6 +208,11 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `INTERNAL_TOKEN_URI`: ****: Instead of defining internal token in the configuration, this configuration option can be used to give Gitea a path to a file that contains the internal token (example value: `file:/etc/gitea/internal_token`) - `PASSWORD_HASH_ALGO`: **pbkdf2**: The hash algorithm to use \[pbkdf2, argon2, scrypt, bcrypt\]. - `CSRF_COOKIE_HTTP_ONLY`: **true**: Set false to allow JavaScript to read CSRF cookie. +- `PASSWORD_COMPLEXITY`: **lower,upper,digit,spec**: Comma separated list of character classes required to pass minimum complexity. If left empty or no valid values are specified, the default values will be used. Possible values are: + - lower - use one or more lower latin characters + - upper - use one or more upper latin characters + - digit - use one or more digits + - spec - use one or more special characters as ``][!"#$%&'()*+,./:;<=>?@\^_{|}~`-`` and space symbol. ## OpenID (`openid`) diff --git a/modules/password/password.go b/modules/password/password.go new file mode 100644 index 0000000000000..54131b9641556 --- /dev/null +++ b/modules/password/password.go @@ -0,0 +1,73 @@ +// Copyright 2019 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 password + +import ( + "crypto/rand" + "math/big" + "regexp" + "sync" + + "code.gitea.io/gitea/modules/setting" +) + +var matchComplexities = map[string]regexp.Regexp{} +var matchComplexityOnce sync.Once +var validChars string +var validComplexities = map[string]string{ + "lower": "abcdefghijklmnopqrstuvwxyz", + "upper": "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "digit": "0123456789", + "spec": `][ !"#$%&'()*+,./:;<=>?@\^_{|}~` + "`-", +} + +// NewComplexity for preparation +func NewComplexity() { + matchComplexityOnce.Do(func() { + if len(setting.PasswordComplexity) > 0 { + for key, val := range setting.PasswordComplexity { + matchComplexity := regexp.MustCompile(val) + matchComplexities[key] = *matchComplexity + validChars += validComplexities[key] + } + } else { + for _, val := range validComplexities { + validChars += val + } + } + }) +} + +// IsComplexEnough return True if password is Complexity +func IsComplexEnough(pwd string) bool { + if len(setting.PasswordComplexity) > 0 { + NewComplexity() + for _, val := range matchComplexities { + if !val.MatchString(pwd) { + return false + } + } + } + return true +} + +// Generate a random password +func Generate(n int) (string, error) { + NewComplexity() + buffer := make([]byte, n) + max := big.NewInt(int64(len(validChars))) + for { + for j := 0; j < n; j++ { + rnd, err := rand.Int(rand.Reader, max) + if err != nil { + return "", err + } + buffer[j] = validChars[rnd.Int64()] + } + if IsComplexEnough(string(buffer)) && string(buffer[0]) != " " && string(buffer[n-1]) != " " { + return string(buffer), nil + } + } +} diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 8c61bdbb7719d..278ed4b107e98 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -146,6 +146,7 @@ var ( MinPasswordLength int ImportLocalPaths bool DisableGitHooks bool + PasswordComplexity map[string]string PasswordHashAlgo string // UI settings @@ -774,6 +775,27 @@ func NewContext() { InternalToken = loadInternalToken(sec) + var dictPC = map[string]string{ + "lower": "[a-z]+", + "upper": "[A-Z]+", + "digit": "[0-9]+", + "spec": `][ !"#$%&'()*+,./:;<=>?@\\^_{|}~` + "`-", + } + PasswordComplexity = make(map[string]string) + cfgdata := sec.Key("PASSWORD_COMPLEXITY").Strings(",") + for _, y := range cfgdata { + ts := strings.TrimSpace(y) + for a := range dictPC { + if strings.ToLower(ts) == a { + PasswordComplexity[ts] = dictPC[ts] + break + } + } + } + if len(PasswordComplexity) == 0 { + PasswordComplexity = dictPC + } + sec = Cfg.Section("attachment") AttachmentPath = sec.Key("PATH").MustString(path.Join(AppDataPath, "attachments")) if !filepath.IsAbs(AttachmentPath) { diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index e6c5839a645c5..4a92b080300b1 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -315,6 +315,7 @@ team_no_units_error = Allow access to at least one repository section. email_been_used = The email address is already used. openid_been_used = The OpenID address '%s' is already used. username_password_incorrect = Username or password is incorrect. +password_complexity = Password does not pass complexity requirements. enterred_invalid_repo_name = The repository name you entered is incorrect. enterred_invalid_owner_name = The new owner name is not valid. enterred_invalid_password = The password you entered is incorrect. diff --git a/routers/admin/users.go b/routers/admin/users.go index 660f116682806..fdc4e0e371b41 100644 --- a/routers/admin/users.go +++ b/routers/admin/users.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/password" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/routers" "code.gitea.io/gitea/services/mailer" @@ -94,7 +95,10 @@ func NewUserPost(ctx *context.Context, form auth.AdminCreateUserForm) { u.LoginName = form.LoginName } } - + if !password.IsComplexEnough(form.Password) { + ctx.RenderWithErr(ctx.Tr("form.password_complexity"), tplUserNew, &form) + return + } if err := models.CreateUser(u); err != nil { switch { case models.IsErrUserAlreadyExist(err): @@ -201,6 +205,10 @@ func EditUserPost(ctx *context.Context, form auth.AdminEditUserForm) { ctx.ServerError("UpdateUser", err) return } + if !password.IsComplexEnough(form.Password) { + ctx.RenderWithErr(ctx.Tr("form.password_complexity"), tplUserEdit, &form) + return + } u.HashPassword(form.Password) } diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go index 70076b626b347..f35ad297b0ca4 100644 --- a/routers/api/v1/admin/user.go +++ b/routers/api/v1/admin/user.go @@ -6,9 +6,12 @@ package admin import ( + "errors" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/password" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/convert" "code.gitea.io/gitea/routers/api/v1/user" @@ -73,7 +76,11 @@ func CreateUser(ctx *context.APIContext, form api.CreateUserOption) { if ctx.Written() { return } - + if !password.IsComplexEnough(form.Password) { + err := errors.New("PasswordComplexity") + ctx.Error(400, "PasswordComplexity", err) + return + } if err := models.CreateUser(u); err != nil { if models.IsErrUserAlreadyExist(err) || models.IsErrEmailAlreadyUsed(err) || @@ -131,6 +138,11 @@ func EditUser(ctx *context.APIContext, form api.EditUserOption) { } if len(form.Password) > 0 { + if !password.IsComplexEnough(form.Password) { + err := errors.New("PasswordComplexity") + ctx.Error(400, "PasswordComplexity", err) + return + } var err error if u.Salt, err = models.GetUserSalt(); err != nil { ctx.Error(500, "UpdateUser", err) diff --git a/routers/user/auth.go b/routers/user/auth.go index 212d535a06498..82a508e4dc84f 100644 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -17,6 +17,7 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/password" "code.gitea.io/gitea/modules/recaptcha" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" @@ -1334,6 +1335,11 @@ func ResetPasswdPost(ctx *context.Context) { ctx.Data["Err_Password"] = true ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplResetPassword, nil) return + } else if !password.IsComplexEnough(passwd) { + ctx.Data["IsResetForm"] = true + ctx.Data["Err_Password"] = true + ctx.RenderWithErr(ctx.Tr("form.password_complexity"), tplResetPassword, nil) + return } var err error @@ -1364,7 +1370,6 @@ func ResetPasswdPost(ctx *context.Context) { func MustChangePassword(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("auth.must_change_password") ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/settings/change_password" - ctx.HTML(200, tplMustChangePassword) } @@ -1372,16 +1377,12 @@ func MustChangePassword(ctx *context.Context) { // account was created by an admin func MustChangePasswordPost(ctx *context.Context, cpt *captcha.Captcha, form auth.MustChangePasswordForm) { ctx.Data["Title"] = ctx.Tr("auth.must_change_password") - ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/settings/change_password" - if ctx.HasError() { ctx.HTML(200, tplMustChangePassword) return } - u := ctx.User - // Make sure only requests for users who are eligible to change their password via // this method passes through if !u.MustChangePassword { diff --git a/routers/user/setting/account.go b/routers/user/setting/account.go index 71d98fd3b9676..c7822242162f7 100644 --- a/routers/user/setting/account.go +++ b/routers/user/setting/account.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/password" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/services/mailer" @@ -52,6 +53,8 @@ func AccountPost(ctx *context.Context, form auth.ChangePasswordForm) { ctx.Flash.Error(ctx.Tr("settings.password_incorrect")) } else if form.Password != form.Retype { ctx.Flash.Error(ctx.Tr("form.password_not_match")) + } else if !password.IsComplexEnough(form.Password) { + ctx.Flash.Error(ctx.Tr("settings.password_complexity")) } else { var err error if ctx.User.Salt, err = models.GetUserSalt(); err != nil { diff --git a/routers/user/setting/account_test.go b/routers/user/setting/account_test.go index 59fbda156979c..497ee658b0ca5 100644 --- a/routers/user/setting/account_test.go +++ b/routers/user/setting/account_test.go @@ -19,36 +19,77 @@ import ( func TestChangePassword(t *testing.T) { oldPassword := "password" setting.MinPasswordLength = 6 + setting.PasswordComplexity = map[string]string{ + "lower": "[a-z]+", + "upper": "[A-Z]+", + "digit": "[0-9]+", + "spec": "[-_]+", + } + var pcLUN = map[string]string{ + "lower": "[a-z]+", + "upper": "[A-Z]+", + "digit": "[0-9]+", + } + var pcLU = map[string]string{ + "lower": "[a-z]+", + "upper": "[A-Z]+", + } for _, req := range []struct { - OldPassword string - NewPassword string - Retype string - Message string + OldPassword string + NewPassword string + Retype string + Message string + PasswordComplexity map[string]string }{ { - OldPassword: oldPassword, - NewPassword: "123456", - Retype: "123456", - Message: "", + OldPassword: oldPassword, + NewPassword: "Qwerty123456-", + Retype: "Qwerty123456-", + Message: "", + PasswordComplexity: setting.PasswordComplexity, + }, + { + OldPassword: oldPassword, + NewPassword: "12345", + Retype: "12345", + Message: "auth.password_too_short", + PasswordComplexity: setting.PasswordComplexity, + }, + { + OldPassword: "12334", + NewPassword: "123456", + Retype: "123456", + Message: "settings.password_incorrect", + PasswordComplexity: setting.PasswordComplexity, + }, + { + OldPassword: oldPassword, + NewPassword: "123456", + Retype: "12345", + Message: "form.password_not_match", + PasswordComplexity: setting.PasswordComplexity, }, { - OldPassword: oldPassword, - NewPassword: "12345", - Retype: "12345", - Message: "auth.password_too_short", + OldPassword: oldPassword, + NewPassword: "Qwerty", + Retype: "Qwerty", + Message: "settings.password_complexity", + PasswordComplexity: setting.PasswordComplexity, }, { - OldPassword: "12334", - NewPassword: "123456", - Retype: "123456", - Message: "settings.password_incorrect", + OldPassword: oldPassword, + NewPassword: "Qwerty", + Retype: "Qwerty", + Message: "settings.password_complexity", + PasswordComplexity: pcLUN, }, { - OldPassword: oldPassword, - NewPassword: "123456", - Retype: "12345", - Message: "form.password_not_match", + OldPassword: oldPassword, + NewPassword: "QWERTY", + Retype: "QWERTY", + Message: "settings.password_complexity", + PasswordComplexity: pcLU, }, } { models.PrepareTestEnv(t) From 8c8a93c02558dfe94fd5979fa6a9f1cad6bd6d21 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Mon, 14 Oct 2019 15:45:33 +0000 Subject: [PATCH 081/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_pl-PL.ini | 2 +- options/locale/locale_pt-BR.ini | 2 ++ options/locale/locale_zh-CN.ini | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini index 52cddf4735f25..17c6d6a0ddcdd 100644 --- a/options/locale/locale_pl-PL.ini +++ b/options/locale/locale_pl-PL.ini @@ -1797,7 +1797,7 @@ notices.delete_success=Powiadomienia systemu zostały usunięte. [action] create_repo=tworzy repozytorium %s rename_repo=zmienia nazwę repozytorium %[1]s na %[3]s -commit_repo=wypycha do %[3]s w[4]s +commit_repo=wypycha do %[3]s w%[4]s create_issue=`otwiera zgłoszenie %s#%[2]s` close_issue=`zamyka zgłoszenie %s#%[2]s` reopen_issue=`ponownie otwiera zgłoszenie %s#%[2]s` diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index f38380bb4828d..3c748fed841f9 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -632,6 +632,8 @@ migrate.lfs_mirror_unsupported=Espelhamento de objetos Git LFS não é suportado migrate.migrate_items_options=Ao migrar do github, insira um nome de usuário e as opções de migração serão exibidas. migrated_from=Migrado de %[2]s migrated_from_fake=Migrado de %[1]s +migrate.migrating=Migrando a partir de %s ... +migrate.migrating_failed=Migração a partir de %s falhou. mirror_from=espelhamento de forked_from=feito fork de diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 7b62bf9c12806..92b17719312d5 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -632,6 +632,8 @@ migrate.lfs_mirror_unsupported=不支持镜像 LFS 对象 - 使用 'git lfs fetc migrate.migrate_items_options=当从 github 迁移并且输入了用户名时,迁移选项将会显示。 migrated_from=从 %[2]s 迁移 migrated_from_fake=从 %[1]s 迁移成功 +migrate.migrating=正在从 %s 迁移... +migrate.migrating_failed=从 %s 迁移失败。 mirror_from=镜像自地址 forked_from=派生自 From eb8975dcce5492a7a3af8d5b4b22de4145c4db1b Mon Sep 17 00:00:00 2001 From: guillep2k <18600385+guillep2k@users.noreply.github.com> Date: Mon, 14 Oct 2019 14:43:48 -0300 Subject: [PATCH 082/173] Add nofollow to sign in links (#8509) --- templates/base/head_navbar.tmpl | 2 +- templates/repo/header.tmpl | 2 +- templates/user/auth/signin_navbar.tmpl | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl index 30316e7e5b074..390a1fe8044ca 100644 --- a/templates/base/head_navbar.tmpl +++ b/templates/base/head_navbar.tmpl @@ -125,7 +125,7 @@ {{.i18n.Tr "register"}} {{end}} - + {{.i18n.Tr "sign_in"}}
diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index 9fb3e32899ae0..111609efefb6d 100644 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -36,7 +36,7 @@
{{if and (not .IsEmpty) ($.Permission.CanRead $.UnitTypeCode)}}
- + {{$.i18n.Tr "repo.fork"}} diff --git a/templates/user/auth/signin_navbar.tmpl b/templates/user/auth/signin_navbar.tmpl index 3f0db26713fa1..345e2212963f8 100644 --- a/templates/user/auth/signin_navbar.tmpl +++ b/templates/user/auth/signin_navbar.tmpl @@ -1,9 +1,9 @@ {{if .EnableOpenIDSignIn}}
-
+
-
+
From db0d4ffdc7d0800b7785beddee4a715b1f7589bd Mon Sep 17 00:00:00 2001 From: 6543 <24977596+6543@users.noreply.github.com> Date: Mon, 14 Oct 2019 21:34:21 +0200 Subject: [PATCH 085/173] Changelog for 1.10.0-RC1 (#8510) * Changelog for 1.10.0 * clean up | remove TESTING and DOCS sction | short BUILD section Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> Co-Authored-By: John Olheiser <42128690+jolheiser@users.noreply.github.com> Co-Authored-By: zeripath --- CHANGELOG.md | 273 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 266 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c71af6b73ef1..2a88eb10357d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,265 @@ This changelog goes through all the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.io). +## [1.10.0-RC1](https://github.com/go-gitea/gitea/releases/tag/v1.10.0-rc1) - 2019-10-14 +* BREAKING + * Remove legacy handling of drone token (#8191) + * Change repo search to use exact match for topic search. (#7941) + * Add pagination for admin api get orgs and fix only list public orgs bug (#7742) + * Implement the ability to change the ssh port to match what is in the gitea config (#7286) +* FEATURE + * Org/Members: display 2FA members states + optimize sql requests (#7621) + * SetDefaultBranch on pushing to empty repository (#7610) + * Adds side-by-side diff for images (#6784) + * API method to list all commits of a repository (#6408) + * Password Complexity Checks (#6230) + * Add option to initialize repository with labels (#6061) + * Add additional password hash algorithms (#6023) +* BUGFIXES + * Fix errors in create org UI regarding team access permission (#8506) + * Fix bug on FindExternalUsersByProvider (#8504) + * Create .ssh dir as necessary (#8486) + * IsBranchExist: return false if provided name is empty (#8485) + * Making openssh listen on SSH_LISTEN_PORT not SSH_PORT (#8477) + * Add check for empty set when dropping indexes during migration (#8471) + * LFS files are relative to LFS content path, ensure that when deleting they are made relative to this (#8455) + * Ensure Request Body Readers are closed in LFS server (#8454) + * Fix template bug on mirror repository setting page (#8438) + * Fix migration v96 to keep issue attachments (#8435) + * Update strk.kbt.io/projects/go/libravatar to latest (#8429) + * Singular form for files that has only one line (#8416) + * Check for either escaped or unescaped wiki filenames (#8408) + * Allow users with explicit read access to give approvals (#8382) + * Fix editor commit to new branch if PR disabled (#8375) + * readd .markdown class to all markup renderers (#8357) + * Upgrade xorm to v0.7.9 to fix some bugs (#8354) + * Fix column name ambiguity in GetUserIssueStats() (#8347) + * Change general form binding to gogs form (#8334) + * Fix pull request commit status in user dashboard list (#8321) + * Fix repo_admin_change_team_access always checked in org settings (#8319) + * Update to github.com/lafriks/xormstore@v1.3.0 (#8317) + * Show correct commit status in PR list (#8316) + * Bugfix for image compare and minor improvements to image compare (#8289) + * Update xorm (#8286) + * Fix API for edit and delete release attachment (#8285) + * Fix nil object access in some conditions when parsing cross references (#8281) + * Fix label count (#8267) + * Only show teams access for organization repositories on collaboration setting page (#8265) + * Test more reserved usernames (#8263) + * Rewrite reference processing code in preparation for opening/closing from comment references (#8261) + * Fix assets key on release webhook (#8253) + * Allow registration when button is hidden (#8237) + * Fix release API URL generation (#8234) + * Fix milestone num_issues (#8221) + * MS Teams webhook misses commit messages (#8209) + * Fix data race (#8204) + * Fix team user api (#8172) + * Fix pull merge 500 error caused by git-fetch breaking behaviors (#8161) + * Make show private icon when repo avatar set (#8144) + * Add reviewers as participants (#8121) + * Fix Go 1.13 private repository go get issue (#8112) + * feat: highlight issue references with : (#8101) + * Make AllowedUsers configurable in sshd_config (#8094) + * Strict name matching for Repository.GetTagID() (#8074) + * Avoid ambiguity of branch/directory names for the git-diff-tree command (#8066) + * Add change title notification for issues (#8061) + * [ssh] fix the config specification in the authorized_keys template (#8031) + * Fix reading git notes from nested trees (#8026) + * Fixes synchronize tags to releases for repository - makes sure we are only getting tag refs (#7990) + * Fix adding default Telegram webhook (#7972) + * Run CORS handler first for /api routes (#7967) + * Abort synchronization from LDAP source if there is some error. (#7960) + * Fix wrong sender when send slack webhook (#7918) + * Fix bug when migrating a private repository (#7917) + * Evaluate emojis in commit messages in list view (#7906) + * Fix upload file type check (#7890) + * lfs/lock: round locked_at timestamp to second (#7872) + * fix non existent milestone with 500 error instead of 404 (#7867) + * gpg/bugfix: Use .ExpiredUnix.IsZero to display green color of forever valid gpg key (#7846) + * Fix duplicate call of webhook (#7821) + * Enable switching to a different source branch when PR already exists (#7819) + * Convert files to utf-8 for indexing (#7814) + * Do not fetch all refs in pull-request compare (#7797) + * Fix multiple bugs with statuses endpoints at API (#7785) + * Restore functionality for early gits (#7775) + * Fix Slack webhook fork message (#7774) + * Rewrite existing repo units if setting is not included in api body (#7763) + * Fix rename failed when rewrite public keys (#7761) + * Fix approvals counting (#7757) + * Add migration step to remove old repo_indexer_status orphaned records (#7746) + * Fix repo_index_status lingering when deleting a repository (#7734) + * Remove camel case tokenization from repo indexer (#7733) + * Fix milestone completness calculation when migrating (#7725) + * Regression: Include "executable" files in the index, as they are not necessarily … (#7718) + * Fixes indexed repos keeping outdated indexes when files grow too large (#7712) + * Skip non-regular files (e.g. submodules) on repo indexing (#7711) + * Fix dropTableColumns sqlite implementation (#7710) + * Update gopkg.in/src-d/go-git.v4 to v4.13.1 (#7705) + * improve branches list performance and fix protected branch icon when no-login (#7695) + * Correct wrong datetime format for git (#7689) + * Move add to hook queue for created repo to outside xorm session. (#7675) + * sugestion to use range .Branches (#7674) + * Fix bug on migrating milestone from github (#7665) + * hide delete/restore button on archived repos (#7658) + * css: use flex to fix floating paginate (#7656) + * Fix syntax highlight initialization (#7617) + * Fix panic on push at - Merging pull request causes 500 error (#7615) + * Make PKCS8, PEM and SSH2 keys work (#7600) + * Fix mistake in arc-green.less split-diff css code. (#7587) + * Handle ErrUserProhibitLogin in http git (#7586) + * Fix bug create/edit wiki pages when code master branch protected (#7580) + * Fixes Malformed URLs in API git/commits response (#7565) + * Fix file header overflow in file and blame views (#7562) + * Improve SSH key parser to handle newlines in keys (#7522) + * Fix empty commits now showing in repo overview (#7521) + * Fix repository's pull request count error (#7518) + * Fix markdown invoke sequence (#7513) + * Remove duplicated webhook trigger (#7511) + * Update User.NumRepos atomically in createRepository (#7493) + * Fix settings page of repo you aren't admin print error - Settings pages giving UnitType error message (#7482) + * Fix redirection after file edit - Handles all redirects for Web UI File CRUD (#7478) + * cmd/serv: actually exit after fatal errors (#7458) + * Fix an issue with some pages throwing 'not defined' js exceptions (#7450) + * fix Dropzone.js integration (#7445) + * Fix regex for issues in commit messages (#7444) + * Diff: Fix indentation on unhighlighted code (#7435) + * Only show "New Pull Request" button if repo allows pulls (#7426) + * Upgrade macaron/captcha to fix random error problem (#7407) + * create class for inline positioned lists (#7393) + * Fetch refs for successful testing for tag (#7388) + * add missing template variable on organisation settings (#7385) + * fix post parameter - on issue list - unset assignee (#7380) + * fix/define autochecked checkboxes on issue list in firefox (#7320) + * only return head: null if source branch was deleted (#6705) +* ENHANCEMENT + * Add nofollow to sign in links (#8509) + * vendor: update mvdan.cc/xurls/v2 to v2.1.0 (#8495) + * Update milestone issues numbers when save milestone and other code improvements (#8411) + * Add extra user information when migrating release (#8331) + * Require overall success if no context is given for status check (#8318) + * Transaction-aware retry create issue to cope with duplicate keys (#8307) + * Change link on issue milestone (#8246) + * Alwaywas return local url for users avatar (#8245) + * Move some milestone functions to a standalone package (#8213) + * Move create issue comment to comments package (#8212) + * Disable max height property of comment textarea (#8203) + * Add 'Mentioning you' group to /issues page (#8201) + * oauth2 with remote Gitea (#8149) + * Reference issues from pull requests and other issues (#8137) + * Fix webhooks to use proxy from environment (#8116) + * Add merged commit id on pull view when it's merged (#8062) + * Add teams to repo on collaboration page. (#8045) + * Update swagger to 0.20.1 (#8010) + * Make link last commit massages in repository home page and commit tables (#8006) + * Add API endpoint for accessing repo topics (#7963) + * Include description in repository search (#7942) + * Use gitea forked macaron (#7933) + * Fix pull creation with empty changes (#7920) + * Allow token as authorization for accessing attachments (#7909) + * Retry create issue to cope with duplicate keys (#7898) + * Move git diff codes from models to services/gitdiff (#7889) + * migrate gplus to google oauth2 provider (#7885) + * Remove unique filter from repo indexer analyzer. (#7878) + * Detect delimiter in CSV rendering (#7869) + * Import topics during migration (#7851) + * Move CreateReview to modules/pull (#7841) + * vendor: update pdf.js to v2.1.266 (#7834) + * Support SSH_LISTEN_PORT env var in docker app.ini template (#7829) + * Add Ability for User to Customize Email Notification Frequency (#7813) + * Move database settings from models to setting (#7806) + * Display ui time with customize time location (#7792) + * Implement webhook branch filter (#7791) + * Restrict repository indexing by glob match (#7767) + * Api: advanced settings for repository (external wiki, issue tracker etc.) (#7756) + * Update migrated repositories' issues/comments/prs poster id if user has a github external user saved (#7751) + * deps: Upgrade gopkg.in/editorconfig/editorconfig-core-go.v1 (#7749) + * Apply emoji on commit graph page (#7743) + * Add a lot of extension to language mappings for syntax highlights (#7741) + * Add SQL execution on log and indexes on table repository and comment (#7740) + * Set DB connection error level to error (#7724) + * Check commit message hashes before making links (#7713) + * remove unnecessary fmt on generate bindata (#7706) + * Fix specific highlighting (CMakeLists.txt ...) (#7686) + * Add file status on API (#7671) + * Add support for DEFAULT_ORG_MEMBER_VISIBLE (#7669) + * Provide links in commit summaries in commits table/view list (#7659) + * Change length of some repository's columns (#7652) + * Move commit repo action from models to repofiles package (#7645) + * fix wrong email when use gitea as OAuth2 provider (#7640) + * [Branch View] add download button (#7604) + * Update to xorm@v0.7.4 (#7596) + * use 403 instead of 401 for ErrUserProhibitLogin (#7591) + * Removed unnecessary conversions (#7557) + * Un-lambda base.FileSize (#7556) + * Added missing error checks in tests (#7554) + * Move create release from models to a standalone package (#7539) + * Make default branch name link to default branch (#7519) + * Added total count of contributions to heatmap (#7517) + * Move mirror to a standalone package from models (#7486) + * Move models.PushUpdate to repofiles.PushUpdate (#7485) + * Include thread related headers in issue/coment mail (#7484) + * Refuse merge until all required status checks success (#7481) + * convert all js var to let/const (#7464) + * Only create branches for opened pull requestes when migrating from github (#7463) + * jQuery 3 (#7425) + * Add notification placeholder (#7409) + * Search Commits via Commit Hash (#7400) + * Move status table to cron package (#7370) + * wiki - page revisions list (#7369) + * Display original author and URL information when showing migrated issues/comments (#7352) + * Refactor filetype is not allowed errors (#7309) + * switch to use gliderlabs/ssh for builtin server (#7250) + * Remove settting dependency on modules/session (#7237) + * Move all mail related codes from models to services/mailer (#7200) + * Support git.PATH entry in app.ini (#6772) + * Support setting cookie domain (#6288) + * Move migrating repository from frontend to backend (#6200) + * Delete releases attachments if release is deleted (#6068) +* SECURITY + * Ignore mentions for users with no access (#8395) + * Be more strict with git arguments (#7715) + * reserve .well-known username (#7637) +* TRANSLATION + * Latvian translation for home page (#8468) + * Add home template italian translation (#8352) + * fix misprint (#7452) +* BUILD + * use go 1.13 (#8088) +* MISC + * add file line count info on UI (#8396) + * Make issues page left menu 100% width and add reponame as title attribute (#8359) + * [arc-green] white on hover for active menu items (#8344) + * Move ref (branch or tag) location on issue list page (#8157) + * apply emoji on dashboard issue list labels (#8156) + * 1148: Take up the full width when viewing the diff in split view. (#8114) + * Display description of 'make this repo private' as help text, not as tooltip (#8097) + * Fixes deformed emoji in pull request reviews (#8047) + * Add strike to old header on comment (#8046) + * Add tooltip for the visibility checkbox in /repo/create (#8025) + * Update github.com/lafriks/xormstore and tidy up mod.go (#8020) + * keep blame view buttons sequence consistent with normal view when view a file (#8007) + * Use "Pull Request" instead of "Merge Request" (#8003) + * Move line number to :before attr to hide from search on browser (#8002) + * Changed black color to white for (read) number label on issue list page (#8000) + * [Branch View] show "New Pull Request" Button only if posible (#7977) + * Fix hook problem by only setting the git environment variables if we are passed them (#7854) + * Prevent Commit Status and Message From Overflowing On Branch Page (#7800) + * Fix global search result CSS, misc CSS tweaks (#7789) + * Tweak label border CSS (#7739) + * Fix create menu item widths (#7708) + * Extract the username and password from the mirror url (#7651) + * [Branch View] Delete duplicate protection symbol (#7624) + * [Branch View] Delete Table Header (#7622) + * [Branch View] icons to buttons (#7602) + * update js dependencies (#7462) + * Add Extra Info to Branches Page (#7461) + * Bump lodash from 4.17.11 to 4.17.14 (#7459) + * wiki history improvements (#7391) + * ui fixes - compare view and archieved repo issues (#7345) + * dark theme scrollbars (#7269) + * wiki - editor - add buttons 'inline code', 'empty checkbox', 'checked checkbox' (#7243) + * Fix Statuses API only shows first 10 statuses: Add paging and extend API GetCommitStatuses (#7141) + ## [1.9.4](https://github.com/go-gitea/gitea/releases/tag/v1.9.4) - 2019-10-08 * BUGFIXES * Highlight issue references (#8101) (#8404) @@ -122,20 +381,20 @@ been added to each release, please refer to the [blog](https://blog.gitea.io). * Move add to hook queue for created repo to outside xorm session. (#7682) (#7675) * Show protection symbol if needed on default branch (#7660) (#7668) * Hide delete/restore button on archived repos (#7660) - * Fix bug on migrating milestone from github (#7665) (#7666) + * Fix bug on migrating milestone from github (#7665) (#7666) * Use flex to fix floating paginate (#7656) (#7662) * Change length of some repository's columns (#7652) (#7655) * Fix wrong email when use gitea as OAuth2 provider (#7640) (#7647) - * Fix syntax highlight initialization (#7617) (#7626) + * Fix syntax highlight initialization (#7617) (#7626) * Fix bug create/edit wiki pages when code master branch protected (#7580) (#7623) * Fix panic on push at #7611 (#7615) (#7618) - * Handle ErrUserProhibitLogin in http git (#7586, #7591) (#7590) + * Handle ErrUserProhibitLogin in http git (#7586, #7591) (#7590) * Fix color of split-diff view in dark theme (#7587) (#7589) - * Fix file header overflow in file and blame views (#7562) (#7579) + * Fix file header overflow in file and blame views (#7562) (#7579) * Malformed URLs in API git/commits response (#7565) (#7567) * Fix empty commits now showing in repo overview (#7521) (#7563) - * Fix repository's pull request count error (#7518) (#7524) - * Remove duplicated webhook trigger (#7511) (#7516) + * Fix repository's pull request count error (#7518) (#7524) + * Remove duplicated webhook trigger (#7511) (#7516) * Handles all redirects for Web UI File CRUD (#7478) (#7507) * Fix regex for issues in commit messages (#7444) (#7466) * cmd/serv: actually exit after fatal errors (#7458) (#7460) @@ -736,7 +995,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io). ## [1.7.5](https://github.com/go-gitea/gitea/releases/tag/v1.7.5) - 2019-03-27 * BUGFIXES * Fix unitTypeCode not being used in accessLevelUnit (#6419) (#6423) - * Fix bug where manifest.json was being requested without cookies and continuously creating new sessions (#6372) (#6383) + * Fix bug where manifest.json was being requested without cookies and continuously creating new sessions (#6372) (#6383) * Fix ParsePatch function to work with quoted diff --git strings (#6323) (#6332) ## [1.7.4](https://github.com/go-gitea/gitea/releases/tag/v1.7.4) - 2019-03-12 From 30835226207f9a618bb2d4956fb209b1dbe099e6 Mon Sep 17 00:00:00 2001 From: Lauris BH Date: Tue, 15 Oct 2019 00:02:16 +0300 Subject: [PATCH 086/173] Starting v1.11.0 development From 086bfb8b4b655f46ac9471cbea9df70e912c315d Mon Sep 17 00:00:00 2001 From: jaqra <48099350+jaqra@users.noreply.github.com> Date: Tue, 15 Oct 2019 00:38:35 +0300 Subject: [PATCH 087/173] Add pagination to commit graph page (#8360) Fixes #8308 --- models/graph.go | 3 ++- models/graph_test.go | 2 +- routers/repo/commit.go | 6 ++++-- templates/repo/graph.tmpl | 1 + 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/models/graph.go b/models/graph.go index 5f68abaf7470d..0efb51b3fc38c 100644 --- a/models/graph.go +++ b/models/graph.go @@ -30,7 +30,7 @@ type GraphItem struct { type GraphItems []GraphItem // GetCommitGraph return a list of commit (GraphItems) from all branches -func GetCommitGraph(r *git.Repository) (GraphItems, error) { +func GetCommitGraph(r *git.Repository, page int) (GraphItems, error) { var CommitGraph []GraphItem @@ -43,6 +43,7 @@ func GetCommitGraph(r *git.Repository) (GraphItems, error) { "-C", "-M", fmt.Sprintf("-n %d", setting.UI.GraphMaxCommitNum), + fmt.Sprintf("--skip=%d", setting.UI.GraphMaxCommitNum*(page-1)), "--date=iso", fmt.Sprintf("--pretty=format:%s", format), ) diff --git a/models/graph_test.go b/models/graph_test.go index 5c78e3877b576..c1f0bc90d954d 100644 --- a/models/graph_test.go +++ b/models/graph_test.go @@ -19,7 +19,7 @@ func BenchmarkGetCommitGraph(b *testing.B) { } for i := 0; i < b.N; i++ { - graph, err := GetCommitGraph(currentRepo) + graph, err := GetCommitGraph(currentRepo, 1) if err != nil { b.Error("Could get commit graph") } diff --git a/routers/repo/commit.go b/routers/repo/commit.go index 3cedf70319e0b..550e4c3a9cd6d 100644 --- a/routers/repo/commit.go +++ b/routers/repo/commit.go @@ -91,7 +91,9 @@ func Graph(ctx *context.Context) { return } - graph, err := models.GetCommitGraph(ctx.Repo.GitRepo) + page := ctx.QueryInt("page") + + graph, err := models.GetCommitGraph(ctx.Repo.GitRepo, page) if err != nil { ctx.ServerError("GetCommitGraph", err) return @@ -103,8 +105,8 @@ func Graph(ctx *context.Context) { ctx.Data["CommitCount"] = commitsCount ctx.Data["Branch"] = ctx.Repo.BranchName ctx.Data["RequireGitGraph"] = true + ctx.Data["Page"] = context.NewPagination(int(commitsCount), setting.UI.GraphMaxCommitNum, page, 5) ctx.HTML(200, tplGraph) - } // SearchCommits render commits filtered by keyword diff --git a/templates/repo/graph.tmpl b/templates/repo/graph.tmpl index 2e8d0b5d91de1..20fe3d1527499 100644 --- a/templates/repo/graph.tmpl +++ b/templates/repo/graph.tmpl @@ -37,4 +37,5 @@
+{{template "base/paginate" .}} {{template "base/footer" .}} From b6ef539ef46b728736764899a05be8236ca0c306 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Mon, 14 Oct 2019 21:39:15 +0000 Subject: [PATCH 088/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_de-DE.ini | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index c038444f6278f..6ea29efe76de0 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -314,6 +314,7 @@ team_no_units_error=Das Team muss auf mindestens einen Bereich Zugriff haben. email_been_used=Die E-Mail-Adresse wird bereits verwendet. openid_been_used=Die OpenID-Adresse „%s“ wird bereits verwendet. username_password_incorrect=Benutzername oder Passwort ist falsch. +password_complexity=Das Passwort erfüllt nicht die Komplexitätsanforderungen. enterred_invalid_repo_name=Der eingegebenen Repository-Name ist falsch. enterred_invalid_owner_name=Der Name des neuen Besitzers ist ungültig. enterred_invalid_password=Das eingegebene Passwort ist falsch. @@ -632,6 +633,8 @@ migrate.lfs_mirror_unsupported=Spiegeln von LFS-Objekten wird nicht unterstützt migrate.migrate_items_options=Wenn du von GitHub migrierst und einen Benutzernamen eingegeben hast, werden die Migrationsoptionen angezeigt. migrated_from=Migriert von %[2]s migrated_from_fake=Migriert von %[1]s +migrate.migrating=Migriere von %s ... +migrate.migrating_failed=Migrieren von %s fehlgeschlagen. mirror_from=Mirror von forked_from=geforkt von @@ -839,6 +842,10 @@ issues.create_comment=Kommentieren issues.closed_at=`hat %[2]s geschlossen` issues.reopened_at=`hat %[2]s wieder geöffnet` issues.commit_ref_at=`hat dieses Issue %[2]s aus einem Commit referenziert` +issues.ref_issue_at=`hat dieses Issue %[1]s referenziert` +issues.ref_pull_at=`hat diesen Pull-Request %[1]s referenziert` +issues.ref_issue_ext_at=`hat dieses Issue %[2]s von %[1]s referenziert` +issues.ref_pull_ext_at=`hat diesen Pull-Request %[2]s von %[1]s referenziert` issues.poster=Ersteller issues.collaborator=Mitarbeiter issues.owner=Besitzer From 0be992a1e26f61a182113266a2eb34f77b87f9b4 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 15 Oct 2019 06:05:57 +0800 Subject: [PATCH 089/173] Make static resouces web browser cache time customized on app.ini (#8442) * make static resouces web browser cache time customized on app.ini * Update docs/content/doc/advanced/config-cheat-sheet.en-us.md Co-Authored-By: zeripath * Update custom/conf/app.ini.sample Co-Authored-By: Antoine GIRARD * fix docs --- custom/conf/app.ini.sample | 2 ++ docs/content/doc/advanced/config-cheat-sheet.en-us.md | 1 + docs/content/doc/advanced/config-cheat-sheet.zh-cn.md | 1 + modules/setting/setting.go | 2 ++ routers/routes/routes.go | 8 ++++---- 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index 79d9960052490..442ac4b5bb9df 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -243,6 +243,8 @@ LFS_CONTENT_PATH = data/lfs LFS_JWT_SECRET = ; LFS authentication validity period (in time.Duration), pushes taking longer than this may fail. LFS_HTTP_AUTH_EXPIRY = 20m +; Static resources, includes resources on custom/, public/ and all uploaded avatars web browser cache time, default is 6h +STATIC_CACHE_TIME = 6h ; Define allowed algorithms and their minimum key length (use -1 to disable a type) [ssh.minimum_key_sizes] diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 100bb229ee6ab..6313e705d4c0d 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -140,6 +140,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `CERT_FILE`: **custom/https/cert.pem**: Cert file path used for HTTPS. - `KEY_FILE`: **custom/https/key.pem**: Key file path used for HTTPS. - `STATIC_ROOT_PATH`: **./**: Upper level of template and static files path. +- `STATIC_CACHE_TIME`: **6h**: Web browser cache time for static resources on `custom/`, `public/` and all uploaded avatars. - `ENABLE_GZIP`: **false**: Enables application-level GZIP support. - `LANDING_PAGE`: **home**: Landing page for unauthenticated users \[home, explore\]. - `LFS_START_SERVER`: **false**: Enables git-lfs support. diff --git a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md index ab73e2059eca0..a0e33c6370226 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md +++ b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md @@ -65,6 +65,7 @@ menu: - `CERT_FILE`: 启用HTTPS的证书文件。 - `KEY_FILE`: 启用HTTPS的密钥文件。 - `STATIC_ROOT_PATH`: 存放模板和静态文件的根目录,默认是 Gitea 的根目录。 +- `STATIC_CACHE_TIME`: **6h**: 静态资源文件,包括 `custom/`, `public/` 和所有上传的头像的浏览器缓存时间。 - `ENABLE_GZIP`: 启用应用级别的 GZIP 压缩。 - `LANDING_PAGE`: 未登录用户的默认页面,可选 `home` 或 `explore`。 - `LFS_START_SERVER`: 是否启用 git-lfs 支持. 可以为 `true` 或 `false`, 默认是 `false`。 diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 278ed4b107e98..629a89766f7a7 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -87,6 +87,7 @@ var ( CertFile string KeyFile string StaticRootPath string + StaticCacheTime time.Duration EnableGzip bool LandingPageURL LandingPage UnixSocketPermission uint32 @@ -607,6 +608,7 @@ func NewContext() { OfflineMode = sec.Key("OFFLINE_MODE").MustBool() DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool() StaticRootPath = sec.Key("STATIC_ROOT_PATH").MustString(AppWorkPath) + StaticCacheTime = sec.Key("STATIC_CACHE_TIME").MustDuration(6 * time.Hour) AppDataPath = sec.Key("APP_DATA_PATH").MustString(path.Join(AppWorkPath, "data")) EnableGzip = sec.Key("ENABLE_GZIP").MustBool() EnablePprof = sec.Key("ENABLE_PPROF").MustBool(false) diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 8dfcdb9c9b64c..0db0af43f0bd9 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -139,14 +139,14 @@ func NewMacaron() *macaron.Macaron { m.Use(public.Custom( &public.Options{ SkipLogging: setting.DisableRouterLog, - ExpiresAfter: time.Hour * 6, + ExpiresAfter: setting.StaticCacheTime, }, )) m.Use(public.Static( &public.Options{ Directory: path.Join(setting.StaticRootPath, "public"), SkipLogging: setting.DisableRouterLog, - ExpiresAfter: time.Hour * 6, + ExpiresAfter: setting.StaticCacheTime, }, )) m.Use(public.StaticHandler( @@ -154,7 +154,7 @@ func NewMacaron() *macaron.Macaron { &public.Options{ Prefix: "avatars", SkipLogging: setting.DisableRouterLog, - ExpiresAfter: time.Hour * 6, + ExpiresAfter: setting.StaticCacheTime, }, )) m.Use(public.StaticHandler( @@ -162,7 +162,7 @@ func NewMacaron() *macaron.Macaron { &public.Options{ Prefix: "repo-avatars", SkipLogging: setting.DisableRouterLog, - ExpiresAfter: time.Hour * 6, + ExpiresAfter: setting.StaticCacheTime, }, )) From 733c898a907b23fa9e0c1bf108be5c5d9f9f7eb0 Mon Sep 17 00:00:00 2001 From: 6543 <24977596+6543@users.noreply.github.com> Date: Tue, 15 Oct 2019 00:40:17 +0200 Subject: [PATCH 090/173] [Branch View] Add Included TAG (#8449) * included message * add property IsIncluded * Add Orange Lable --- options/locale/locale_en-US.ini | 2 ++ routers/repo/branch.go | 4 ++++ templates/repo/branch/list.tmpl | 6 +++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 4a92b080300b1..b5a3d8c5924fd 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1453,6 +1453,8 @@ branch.restore_failed = Failed to restore branch '%s'. branch.protected_deletion_failed = Branch '%s' is protected. It cannot be deleted. branch.restore = Restore Branch '%s' branch.download = Download Branch '%s' +branch.included_desc = This branch is part of the default branch +branch.included = Included topic.manage_topics = Manage Topics topic.done = Done diff --git a/routers/repo/branch.go b/routers/repo/branch.go index 5d78518491dfa..0c06de3ea6317 100644 --- a/routers/repo/branch.go +++ b/routers/repo/branch.go @@ -28,6 +28,7 @@ type Branch struct { Commit *git.Commit IsProtected bool IsDeleted bool + IsIncluded bool DeletedBranch *models.DeletedBranch CommitsAhead int CommitsBehind int @@ -203,10 +204,13 @@ func loadBranches(ctx *context.Context) []*Branch { } } + isIncluded := divergence.Ahead == 0 && ctx.Repo.Repository.DefaultBranch != branchName + branches[i] = &Branch{ Name: branchName, Commit: commit, IsProtected: isProtected, + IsIncluded: isIncluded, CommitsAhead: divergence.Ahead, CommitsBehind: divergence.Behind, LatestPullRequest: pr, diff --git a/templates/repo/branch/list.tmpl b/templates/repo/branch/list.tmpl index 9c53f4e67a36d..26493298da4a3 100644 --- a/templates/repo/branch/list.tmpl +++ b/templates/repo/branch/list.tmpl @@ -75,7 +75,11 @@

- + - + diff --git a/public/vendor/plugins/codemirror/addon/comment/comment.js b/public/vendor/plugins/codemirror/addon/comment/comment.js new file mode 100644 index 0000000000000..8394e85a4daad --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/comment/comment.js @@ -0,0 +1,209 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var noOptions = {}; + var nonWS = /[^\s\u00a0]/; + var Pos = CodeMirror.Pos; + + function firstNonWS(str) { + var found = str.search(nonWS); + return found == -1 ? 0 : found; + } + + CodeMirror.commands.toggleComment = function(cm) { + cm.toggleComment(); + }; + + CodeMirror.defineExtension("toggleComment", function(options) { + if (!options) options = noOptions; + var cm = this; + var minLine = Infinity, ranges = this.listSelections(), mode = null; + for (var i = ranges.length - 1; i >= 0; i--) { + var from = ranges[i].from(), to = ranges[i].to(); + if (from.line >= minLine) continue; + if (to.line >= minLine) to = Pos(minLine, 0); + minLine = from.line; + if (mode == null) { + if (cm.uncomment(from, to, options)) mode = "un"; + else { cm.lineComment(from, to, options); mode = "line"; } + } else if (mode == "un") { + cm.uncomment(from, to, options); + } else { + cm.lineComment(from, to, options); + } + } + }); + + // Rough heuristic to try and detect lines that are part of multi-line string + function probablyInsideString(cm, pos, line) { + return /\bstring\b/.test(cm.getTokenTypeAt(Pos(pos.line, 0))) && !/^[\'\"\`]/.test(line) + } + + function getMode(cm, pos) { + var mode = cm.getMode() + return mode.useInnerComments === false || !mode.innerMode ? mode : cm.getModeAt(pos) + } + + CodeMirror.defineExtension("lineComment", function(from, to, options) { + if (!options) options = noOptions; + var self = this, mode = getMode(self, from); + var firstLine = self.getLine(from.line); + if (firstLine == null || probablyInsideString(self, from, firstLine)) return; + + var commentString = options.lineComment || mode.lineComment; + if (!commentString) { + if (options.blockCommentStart || mode.blockCommentStart) { + options.fullLines = true; + self.blockComment(from, to, options); + } + return; + } + + var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1); + var pad = options.padding == null ? " " : options.padding; + var blankLines = options.commentBlankLines || from.line == to.line; + + self.operation(function() { + if (options.indent) { + var baseString = null; + for (var i = from.line; i < end; ++i) { + var line = self.getLine(i); + var whitespace = line.slice(0, firstNonWS(line)); + if (baseString == null || baseString.length > whitespace.length) { + baseString = whitespace; + } + } + for (var i = from.line; i < end; ++i) { + var line = self.getLine(i), cut = baseString.length; + if (!blankLines && !nonWS.test(line)) continue; + if (line.slice(0, cut) != baseString) cut = firstNonWS(line); + self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut)); + } + } else { + for (var i = from.line; i < end; ++i) { + if (blankLines || nonWS.test(self.getLine(i))) + self.replaceRange(commentString + pad, Pos(i, 0)); + } + } + }); + }); + + CodeMirror.defineExtension("blockComment", function(from, to, options) { + if (!options) options = noOptions; + var self = this, mode = getMode(self, from); + var startString = options.blockCommentStart || mode.blockCommentStart; + var endString = options.blockCommentEnd || mode.blockCommentEnd; + if (!startString || !endString) { + if ((options.lineComment || mode.lineComment) && options.fullLines != false) + self.lineComment(from, to, options); + return; + } + if (/\bcomment\b/.test(self.getTokenTypeAt(Pos(from.line, 0)))) return + + var end = Math.min(to.line, self.lastLine()); + if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end; + + var pad = options.padding == null ? " " : options.padding; + if (from.line > end) return; + + self.operation(function() { + if (options.fullLines != false) { + var lastLineHasText = nonWS.test(self.getLine(end)); + self.replaceRange(pad + endString, Pos(end)); + self.replaceRange(startString + pad, Pos(from.line, 0)); + var lead = options.blockCommentLead || mode.blockCommentLead; + if (lead != null) for (var i = from.line + 1; i <= end; ++i) + if (i != end || lastLineHasText) + self.replaceRange(lead + pad, Pos(i, 0)); + } else { + self.replaceRange(endString, to); + self.replaceRange(startString, from); + } + }); + }); + + CodeMirror.defineExtension("uncomment", function(from, to, options) { + if (!options) options = noOptions; + var self = this, mode = getMode(self, from); + var end = Math.min(to.ch != 0 || to.line == from.line ? to.line : to.line - 1, self.lastLine()), start = Math.min(from.line, end); + + // Try finding line comments + var lineString = options.lineComment || mode.lineComment, lines = []; + var pad = options.padding == null ? " " : options.padding, didSomething; + lineComment: { + if (!lineString) break lineComment; + for (var i = start; i <= end; ++i) { + var line = self.getLine(i); + var found = line.indexOf(lineString); + if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1; + if (found == -1 && nonWS.test(line)) break lineComment; + if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment; + lines.push(line); + } + self.operation(function() { + for (var i = start; i <= end; ++i) { + var line = lines[i - start]; + var pos = line.indexOf(lineString), endPos = pos + lineString.length; + if (pos < 0) continue; + if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length; + didSomething = true; + self.replaceRange("", Pos(i, pos), Pos(i, endPos)); + } + }); + if (didSomething) return true; + } + + // Try block comments + var startString = options.blockCommentStart || mode.blockCommentStart; + var endString = options.blockCommentEnd || mode.blockCommentEnd; + if (!startString || !endString) return false; + var lead = options.blockCommentLead || mode.blockCommentLead; + var startLine = self.getLine(start), open = startLine.indexOf(startString) + if (open == -1) return false + var endLine = end == start ? startLine : self.getLine(end) + var close = endLine.indexOf(endString, end == start ? open + startString.length : 0); + var insideStart = Pos(start, open + 1), insideEnd = Pos(end, close + 1) + if (close == -1 || + !/comment/.test(self.getTokenTypeAt(insideStart)) || + !/comment/.test(self.getTokenTypeAt(insideEnd)) || + self.getRange(insideStart, insideEnd, "\n").indexOf(endString) > -1) + return false; + + // Avoid killing block comments completely outside the selection. + // Positions of the last startString before the start of the selection, and the first endString after it. + var lastStart = startLine.lastIndexOf(startString, from.ch); + var firstEnd = lastStart == -1 ? -1 : startLine.slice(0, from.ch).indexOf(endString, lastStart + startString.length); + if (lastStart != -1 && firstEnd != -1 && firstEnd + endString.length != from.ch) return false; + // Positions of the first endString after the end of the selection, and the last startString before it. + firstEnd = endLine.indexOf(endString, to.ch); + var almostLastStart = endLine.slice(to.ch).lastIndexOf(startString, firstEnd - to.ch); + lastStart = (firstEnd == -1 || almostLastStart == -1) ? -1 : to.ch + almostLastStart; + if (firstEnd != -1 && lastStart != -1 && lastStart != to.ch) return false; + + self.operation(function() { + self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)), + Pos(end, close + endString.length)); + var openEnd = open + startString.length; + if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length; + self.replaceRange("", Pos(start, open), Pos(start, openEnd)); + if (lead) for (var i = start + 1; i <= end; ++i) { + var line = self.getLine(i), found = line.indexOf(lead); + if (found == -1 || nonWS.test(line.slice(0, found))) continue; + var foundEnd = found + lead.length; + if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length; + self.replaceRange("", Pos(i, found), Pos(i, foundEnd)); + } + }); + return true; + }); +}); diff --git a/public/vendor/plugins/codemirror/addon/comment/continuecomment.js b/public/vendor/plugins/codemirror/addon/comment/continuecomment.js new file mode 100644 index 0000000000000..a5f957b73b306 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/comment/continuecomment.js @@ -0,0 +1,78 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + function continueComment(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + var ranges = cm.listSelections(), mode, inserts = []; + for (var i = 0; i < ranges.length; i++) { + var pos = ranges[i].head + if (!/\bcomment\b/.test(cm.getTokenTypeAt(pos))) return CodeMirror.Pass; + var modeHere = cm.getModeAt(pos) + if (!mode) mode = modeHere; + else if (mode != modeHere) return CodeMirror.Pass; + + var insert = null; + if (mode.blockCommentStart && mode.blockCommentContinue) { + var line = cm.getLine(pos.line).slice(0, pos.ch) + var end = line.lastIndexOf(mode.blockCommentEnd), found + if (end != -1 && end == pos.ch - mode.blockCommentEnd.length) { + // Comment ended, don't continue it + } else if ((found = line.lastIndexOf(mode.blockCommentStart)) > -1 && found > end) { + insert = line.slice(0, found) + if (/\S/.test(insert)) { + insert = "" + for (var j = 0; j < found; ++j) insert += " " + } + } else if ((found = line.indexOf(mode.blockCommentContinue)) > -1 && !/\S/.test(line.slice(0, found))) { + insert = line.slice(0, found) + } + if (insert != null) insert += mode.blockCommentContinue + } + if (insert == null && mode.lineComment && continueLineCommentEnabled(cm)) { + var line = cm.getLine(pos.line), found = line.indexOf(mode.lineComment); + if (found > -1) { + insert = line.slice(0, found); + if (/\S/.test(insert)) insert = null; + else insert += mode.lineComment + line.slice(found + mode.lineComment.length).match(/^\s*/)[0]; + } + } + if (insert == null) return CodeMirror.Pass; + inserts[i] = "\n" + insert; + } + + cm.operation(function() { + for (var i = ranges.length - 1; i >= 0; i--) + cm.replaceRange(inserts[i], ranges[i].from(), ranges[i].to(), "+insert"); + }); + } + + function continueLineCommentEnabled(cm) { + var opt = cm.getOption("continueComments"); + if (opt && typeof opt == "object") + return opt.continueLineComment !== false; + return true; + } + + CodeMirror.defineOption("continueComments", null, function(cm, val, prev) { + if (prev && prev != CodeMirror.Init) + cm.removeKeyMap("continueComment"); + if (val) { + var key = "Enter"; + if (typeof val == "string") + key = val; + else if (typeof val == "object" && val.key) + key = val.key; + var map = {name: "continueComment"}; + map[key] = continueComment; + cm.addKeyMap(map); + } + }); +}); diff --git a/public/vendor/plugins/codemirror/addon/dialog/dialog.css b/public/vendor/plugins/codemirror/addon/dialog/dialog.css new file mode 100644 index 0000000000000..677c078387dc8 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/dialog/dialog.css @@ -0,0 +1,32 @@ +.CodeMirror-dialog { + position: absolute; + left: 0; right: 0; + background: inherit; + z-index: 15; + padding: .1em .8em; + overflow: hidden; + color: inherit; +} + +.CodeMirror-dialog-top { + border-bottom: 1px solid #eee; + top: 0; +} + +.CodeMirror-dialog-bottom { + border-top: 1px solid #eee; + bottom: 0; +} + +.CodeMirror-dialog input { + border: none; + outline: none; + background: transparent; + width: 20em; + color: inherit; + font-family: monospace; +} + +.CodeMirror-dialog button { + font-size: 70%; +} diff --git a/public/vendor/plugins/codemirror/addon/dialog/dialog.js b/public/vendor/plugins/codemirror/addon/dialog/dialog.js new file mode 100644 index 0000000000000..23b06a8323e35 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/dialog/dialog.js @@ -0,0 +1,161 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// Open simple dialogs on top of an editor. Relies on dialog.css. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + function dialogDiv(cm, template, bottom) { + var wrap = cm.getWrapperElement(); + var dialog; + dialog = wrap.appendChild(document.createElement("div")); + if (bottom) + dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom"; + else + dialog.className = "CodeMirror-dialog CodeMirror-dialog-top"; + + if (typeof template == "string") { + dialog.innerHTML = template; + } else { // Assuming it's a detached DOM element. + dialog.appendChild(template); + } + CodeMirror.addClass(wrap, 'dialog-opened'); + return dialog; + } + + function closeNotification(cm, newVal) { + if (cm.state.currentNotificationClose) + cm.state.currentNotificationClose(); + cm.state.currentNotificationClose = newVal; + } + + CodeMirror.defineExtension("openDialog", function(template, callback, options) { + if (!options) options = {}; + + closeNotification(this, null); + + var dialog = dialogDiv(this, template, options.bottom); + var closed = false, me = this; + function close(newVal) { + if (typeof newVal == 'string') { + inp.value = newVal; + } else { + if (closed) return; + closed = true; + CodeMirror.rmClass(dialog.parentNode, 'dialog-opened'); + dialog.parentNode.removeChild(dialog); + me.focus(); + + if (options.onClose) options.onClose(dialog); + } + } + + var inp = dialog.getElementsByTagName("input")[0], button; + if (inp) { + inp.focus(); + + if (options.value) { + inp.value = options.value; + if (options.selectValueOnOpen !== false) { + inp.select(); + } + } + + if (options.onInput) + CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);}); + if (options.onKeyUp) + CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);}); + + CodeMirror.on(inp, "keydown", function(e) { + if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; } + if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) { + inp.blur(); + CodeMirror.e_stop(e); + close(); + } + if (e.keyCode == 13) callback(inp.value, e); + }); + + if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close); + } else if (button = dialog.getElementsByTagName("button")[0]) { + CodeMirror.on(button, "click", function() { + close(); + me.focus(); + }); + + if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close); + + button.focus(); + } + return close; + }); + + CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) { + closeNotification(this, null); + var dialog = dialogDiv(this, template, options && options.bottom); + var buttons = dialog.getElementsByTagName("button"); + var closed = false, me = this, blurring = 1; + function close() { + if (closed) return; + closed = true; + CodeMirror.rmClass(dialog.parentNode, 'dialog-opened'); + dialog.parentNode.removeChild(dialog); + me.focus(); + } + buttons[0].focus(); + for (var i = 0; i < buttons.length; ++i) { + var b = buttons[i]; + (function(callback) { + CodeMirror.on(b, "click", function(e) { + CodeMirror.e_preventDefault(e); + close(); + if (callback) callback(me); + }); + })(callbacks[i]); + CodeMirror.on(b, "blur", function() { + --blurring; + setTimeout(function() { if (blurring <= 0) close(); }, 200); + }); + CodeMirror.on(b, "focus", function() { ++blurring; }); + } + }); + + /* + * openNotification + * Opens a notification, that can be closed with an optional timer + * (default 5000ms timer) and always closes on click. + * + * If a notification is opened while another is opened, it will close the + * currently opened one and open the new one immediately. + */ + CodeMirror.defineExtension("openNotification", function(template, options) { + closeNotification(this, close); + var dialog = dialogDiv(this, template, options && options.bottom); + var closed = false, doneTimer; + var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000; + + function close() { + if (closed) return; + closed = true; + clearTimeout(doneTimer); + CodeMirror.rmClass(dialog.parentNode, 'dialog-opened'); + dialog.parentNode.removeChild(dialog); + } + + CodeMirror.on(dialog, 'click', function(e) { + CodeMirror.e_preventDefault(e); + close(); + }); + + if (duration) + doneTimer = setTimeout(close, duration); + + return close; + }); +}); diff --git a/public/vendor/plugins/codemirror/addon/display/autorefresh.js b/public/vendor/plugins/codemirror/addon/display/autorefresh.js new file mode 100644 index 0000000000000..37014dc31db5d --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/display/autorefresh.js @@ -0,0 +1,47 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")) + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod) + else // Plain browser env + mod(CodeMirror) +})(function(CodeMirror) { + "use strict" + + CodeMirror.defineOption("autoRefresh", false, function(cm, val) { + if (cm.state.autoRefresh) { + stopListening(cm, cm.state.autoRefresh) + cm.state.autoRefresh = null + } + if (val && cm.display.wrapper.offsetHeight == 0) + startListening(cm, cm.state.autoRefresh = {delay: val.delay || 250}) + }) + + function startListening(cm, state) { + function check() { + if (cm.display.wrapper.offsetHeight) { + stopListening(cm, state) + if (cm.display.lastWrapHeight != cm.display.wrapper.clientHeight) + cm.refresh() + } else { + state.timeout = setTimeout(check, state.delay) + } + } + state.timeout = setTimeout(check, state.delay) + state.hurry = function() { + clearTimeout(state.timeout) + state.timeout = setTimeout(check, 50) + } + CodeMirror.on(window, "mouseup", state.hurry) + CodeMirror.on(window, "keyup", state.hurry) + } + + function stopListening(_cm, state) { + clearTimeout(state.timeout) + CodeMirror.off(window, "mouseup", state.hurry) + CodeMirror.off(window, "keyup", state.hurry) + } +}); diff --git a/public/vendor/plugins/codemirror/addon/display/fullscreen.css b/public/vendor/plugins/codemirror/addon/display/fullscreen.css new file mode 100644 index 0000000000000..437acd89be8c3 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/display/fullscreen.css @@ -0,0 +1,6 @@ +.CodeMirror-fullscreen { + position: fixed; + top: 0; left: 0; right: 0; bottom: 0; + height: auto; + z-index: 9; +} diff --git a/public/vendor/plugins/codemirror/addon/display/fullscreen.js b/public/vendor/plugins/codemirror/addon/display/fullscreen.js new file mode 100644 index 0000000000000..eda7300f123df --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/display/fullscreen.js @@ -0,0 +1,41 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("fullScreen", false, function(cm, val, old) { + if (old == CodeMirror.Init) old = false; + if (!old == !val) return; + if (val) setFullscreen(cm); + else setNormal(cm); + }); + + function setFullscreen(cm) { + var wrap = cm.getWrapperElement(); + cm.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset, + width: wrap.style.width, height: wrap.style.height}; + wrap.style.width = ""; + wrap.style.height = "auto"; + wrap.className += " CodeMirror-fullscreen"; + document.documentElement.style.overflow = "hidden"; + cm.refresh(); + } + + function setNormal(cm) { + var wrap = cm.getWrapperElement(); + wrap.className = wrap.className.replace(/\s*CodeMirror-fullscreen\b/, ""); + document.documentElement.style.overflow = ""; + var info = cm.state.fullScreenRestore; + wrap.style.width = info.width; wrap.style.height = info.height; + window.scrollTo(info.scrollLeft, info.scrollTop); + cm.refresh(); + } +}); diff --git a/public/vendor/plugins/codemirror/addon/display/panel.js b/public/vendor/plugins/codemirror/addon/display/panel.js new file mode 100644 index 0000000000000..5faf1d560eb91 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/display/panel.js @@ -0,0 +1,127 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + CodeMirror.defineExtension("addPanel", function(node, options) { + options = options || {}; + + if (!this.state.panels) initPanels(this); + + var info = this.state.panels; + var wrapper = info.wrapper; + var cmWrapper = this.getWrapperElement(); + var replace = options.replace instanceof Panel && !options.replace.cleared; + + if (options.after instanceof Panel && !options.after.cleared) { + wrapper.insertBefore(node, options.before.node.nextSibling); + } else if (options.before instanceof Panel && !options.before.cleared) { + wrapper.insertBefore(node, options.before.node); + } else if (replace) { + wrapper.insertBefore(node, options.replace.node); + info.panels++; + options.replace.clear(); + } else if (options.position == "bottom") { + wrapper.appendChild(node); + } else if (options.position == "before-bottom") { + wrapper.insertBefore(node, cmWrapper.nextSibling); + } else if (options.position == "after-top") { + wrapper.insertBefore(node, cmWrapper); + } else { + wrapper.insertBefore(node, wrapper.firstChild); + } + + var height = (options && options.height) || node.offsetHeight; + this._setSize(null, info.heightLeft -= height); + if (!replace) { + info.panels++; + } + if (options.stable && isAtTop(this, node)) + this.scrollTo(null, this.getScrollInfo().top + height) + + return new Panel(this, node, options, height); + }); + + function Panel(cm, node, options, height) { + this.cm = cm; + this.node = node; + this.options = options; + this.height = height; + this.cleared = false; + } + + Panel.prototype.clear = function() { + if (this.cleared) return; + this.cleared = true; + var info = this.cm.state.panels; + this.cm._setSize(null, info.heightLeft += this.height); + if (this.options.stable && isAtTop(this.cm, this.node)) + this.cm.scrollTo(null, this.cm.getScrollInfo().top - this.height) + info.wrapper.removeChild(this.node); + if (--info.panels == 0) removePanels(this.cm); + }; + + Panel.prototype.changed = function(height) { + var newHeight = height == null ? this.node.offsetHeight : height; + var info = this.cm.state.panels; + this.cm._setSize(null, info.heightLeft -= (newHeight - this.height)); + this.height = newHeight; + }; + + function initPanels(cm) { + var wrap = cm.getWrapperElement(); + var style = window.getComputedStyle ? window.getComputedStyle(wrap) : wrap.currentStyle; + var height = parseInt(style.height); + var info = cm.state.panels = { + setHeight: wrap.style.height, + heightLeft: height, + panels: 0, + wrapper: document.createElement("div") + }; + wrap.parentNode.insertBefore(info.wrapper, wrap); + var hasFocus = cm.hasFocus(); + info.wrapper.appendChild(wrap); + if (hasFocus) cm.focus(); + + cm._setSize = cm.setSize; + if (height != null) cm.setSize = function(width, newHeight) { + if (newHeight == null) return this._setSize(width, newHeight); + info.setHeight = newHeight; + if (typeof newHeight != "number") { + var px = /^(\d+\.?\d*)px$/.exec(newHeight); + if (px) { + newHeight = Number(px[1]); + } else { + info.wrapper.style.height = newHeight; + newHeight = info.wrapper.offsetHeight; + info.wrapper.style.height = ""; + } + } + cm._setSize(width, info.heightLeft += (newHeight - height)); + height = newHeight; + }; + } + + function removePanels(cm) { + var info = cm.state.panels; + cm.state.panels = null; + + var wrap = cm.getWrapperElement(); + info.wrapper.parentNode.replaceChild(wrap, info.wrapper); + wrap.style.height = info.setHeight; + cm.setSize = cm._setSize; + cm.setSize(); + } + + function isAtTop(cm, dom) { + for (var sibling = dom.nextSibling; sibling; sibling = sibling.nextSibling) + if (sibling == cm.getWrapperElement()) return true + return false + } +}); diff --git a/public/vendor/plugins/codemirror/addon/display/placeholder.js b/public/vendor/plugins/codemirror/addon/display/placeholder.js new file mode 100644 index 0000000000000..4eabe3d9012d7 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/display/placeholder.js @@ -0,0 +1,63 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + CodeMirror.defineOption("placeholder", "", function(cm, val, old) { + var prev = old && old != CodeMirror.Init; + if (val && !prev) { + cm.on("blur", onBlur); + cm.on("change", onChange); + cm.on("swapDoc", onChange); + onChange(cm); + } else if (!val && prev) { + cm.off("blur", onBlur); + cm.off("change", onChange); + cm.off("swapDoc", onChange); + clearPlaceholder(cm); + var wrapper = cm.getWrapperElement(); + wrapper.className = wrapper.className.replace(" CodeMirror-empty", ""); + } + + if (val && !cm.hasFocus()) onBlur(cm); + }); + + function clearPlaceholder(cm) { + if (cm.state.placeholder) { + cm.state.placeholder.parentNode.removeChild(cm.state.placeholder); + cm.state.placeholder = null; + } + } + function setPlaceholder(cm) { + clearPlaceholder(cm); + var elt = cm.state.placeholder = document.createElement("pre"); + elt.style.cssText = "height: 0; overflow: visible"; + elt.style.direction = cm.getOption("direction"); + elt.className = "CodeMirror-placeholder CodeMirror-line-like"; + var placeHolder = cm.getOption("placeholder") + if (typeof placeHolder == "string") placeHolder = document.createTextNode(placeHolder) + elt.appendChild(placeHolder) + cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild); + } + + function onBlur(cm) { + if (isEmpty(cm)) setPlaceholder(cm); + } + function onChange(cm) { + var wrapper = cm.getWrapperElement(), empty = isEmpty(cm); + wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : ""); + + if (empty) setPlaceholder(cm); + else clearPlaceholder(cm); + } + + function isEmpty(cm) { + return (cm.lineCount() === 1) && (cm.getLine(0) === ""); + } +}); diff --git a/public/vendor/plugins/codemirror/addon/display/rulers.js b/public/vendor/plugins/codemirror/addon/display/rulers.js new file mode 100644 index 0000000000000..0bb83bb0228db --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/display/rulers.js @@ -0,0 +1,51 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("rulers", false, function(cm, val) { + if (cm.state.rulerDiv) { + cm.state.rulerDiv.parentElement.removeChild(cm.state.rulerDiv) + cm.state.rulerDiv = null + cm.off("refresh", drawRulers) + } + if (val && val.length) { + cm.state.rulerDiv = cm.display.lineSpace.parentElement.insertBefore(document.createElement("div"), cm.display.lineSpace) + cm.state.rulerDiv.className = "CodeMirror-rulers" + drawRulers(cm) + cm.on("refresh", drawRulers) + } + }); + + function drawRulers(cm) { + cm.state.rulerDiv.textContent = "" + var val = cm.getOption("rulers"); + var cw = cm.defaultCharWidth(); + var left = cm.charCoords(CodeMirror.Pos(cm.firstLine(), 0), "div").left; + cm.state.rulerDiv.style.minHeight = (cm.display.scroller.offsetHeight + 30) + "px"; + for (var i = 0; i < val.length; i++) { + var elt = document.createElement("div"); + elt.className = "CodeMirror-ruler"; + var col, conf = val[i]; + if (typeof conf == "number") { + col = conf; + } else { + col = conf.column; + if (conf.className) elt.className += " " + conf.className; + if (conf.color) elt.style.borderColor = conf.color; + if (conf.lineStyle) elt.style.borderLeftStyle = conf.lineStyle; + if (conf.width) elt.style.borderLeftWidth = conf.width; + } + elt.style.left = (left + col * cw) + "px"; + cm.state.rulerDiv.appendChild(elt) + } + } +}); diff --git a/public/vendor/plugins/codemirror/addon/edit/closebrackets.js b/public/vendor/plugins/codemirror/addon/edit/closebrackets.js new file mode 100644 index 0000000000000..4415c39381f46 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/edit/closebrackets.js @@ -0,0 +1,191 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + var defaults = { + pairs: "()[]{}''\"\"", + closeBefore: ")]}'\":;>", + triples: "", + explode: "[]{}" + }; + + var Pos = CodeMirror.Pos; + + CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + cm.removeKeyMap(keyMap); + cm.state.closeBrackets = null; + } + if (val) { + ensureBound(getOption(val, "pairs")) + cm.state.closeBrackets = val; + cm.addKeyMap(keyMap); + } + }); + + function getOption(conf, name) { + if (name == "pairs" && typeof conf == "string") return conf; + if (typeof conf == "object" && conf[name] != null) return conf[name]; + return defaults[name]; + } + + var keyMap = {Backspace: handleBackspace, Enter: handleEnter}; + function ensureBound(chars) { + for (var i = 0; i < chars.length; i++) { + var ch = chars.charAt(i), key = "'" + ch + "'" + if (!keyMap[key]) keyMap[key] = handler(ch) + } + } + ensureBound(defaults.pairs + "`") + + function handler(ch) { + return function(cm) { return handleChar(cm, ch); }; + } + + function getConfig(cm) { + var deflt = cm.state.closeBrackets; + if (!deflt || deflt.override) return deflt; + var mode = cm.getModeAt(cm.getCursor()); + return mode.closeBrackets || deflt; + } + + function handleBackspace(cm) { + var conf = getConfig(cm); + if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass; + + var pairs = getOption(conf, "pairs"); + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) return CodeMirror.Pass; + var around = charsAround(cm, ranges[i].head); + if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass; + } + for (var i = ranges.length - 1; i >= 0; i--) { + var cur = ranges[i].head; + cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1), "+delete"); + } + } + + function handleEnter(cm) { + var conf = getConfig(cm); + var explode = conf && getOption(conf, "explode"); + if (!explode || cm.getOption("disableInput")) return CodeMirror.Pass; + + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) return CodeMirror.Pass; + var around = charsAround(cm, ranges[i].head); + if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass; + } + cm.operation(function() { + var linesep = cm.lineSeparator() || "\n"; + cm.replaceSelection(linesep + linesep, null); + cm.execCommand("goCharLeft"); + ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + var line = ranges[i].head.line; + cm.indentLine(line, null, true); + cm.indentLine(line + 1, null, true); + } + }); + } + + function contractSelection(sel) { + var inverted = CodeMirror.cmpPos(sel.anchor, sel.head) > 0; + return {anchor: new Pos(sel.anchor.line, sel.anchor.ch + (inverted ? -1 : 1)), + head: new Pos(sel.head.line, sel.head.ch + (inverted ? 1 : -1))}; + } + + function handleChar(cm, ch) { + var conf = getConfig(cm); + if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass; + + var pairs = getOption(conf, "pairs"); + var pos = pairs.indexOf(ch); + if (pos == -1) return CodeMirror.Pass; + + var closeBefore = getOption(conf,"closeBefore"); + + var triples = getOption(conf, "triples"); + + var identical = pairs.charAt(pos + 1) == ch; + var ranges = cm.listSelections(); + var opening = pos % 2 == 0; + + var type; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i], cur = range.head, curType; + var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1)); + if (opening && !range.empty()) { + curType = "surround"; + } else if ((identical || !opening) && next == ch) { + if (identical && stringStartsAfter(cm, cur)) + curType = "both"; + else if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch) + curType = "skipThree"; + else + curType = "skip"; + } else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 && + cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch) { + if (cur.ch > 2 && /\bstring/.test(cm.getTokenTypeAt(Pos(cur.line, cur.ch - 2)))) return CodeMirror.Pass; + curType = "addFour"; + } else if (identical) { + var prev = cur.ch == 0 ? " " : cm.getRange(Pos(cur.line, cur.ch - 1), cur) + if (!CodeMirror.isWordChar(next) && prev != ch && !CodeMirror.isWordChar(prev)) curType = "both"; + else return CodeMirror.Pass; + } else if (opening && (next.length === 0 || /\s/.test(next) || closeBefore.indexOf(next) > -1)) { + curType = "both"; + } else { + return CodeMirror.Pass; + } + if (!type) type = curType; + else if (type != curType) return CodeMirror.Pass; + } + + var left = pos % 2 ? pairs.charAt(pos - 1) : ch; + var right = pos % 2 ? ch : pairs.charAt(pos + 1); + cm.operation(function() { + if (type == "skip") { + cm.execCommand("goCharRight"); + } else if (type == "skipThree") { + for (var i = 0; i < 3; i++) + cm.execCommand("goCharRight"); + } else if (type == "surround") { + var sels = cm.getSelections(); + for (var i = 0; i < sels.length; i++) + sels[i] = left + sels[i] + right; + cm.replaceSelections(sels, "around"); + sels = cm.listSelections().slice(); + for (var i = 0; i < sels.length; i++) + sels[i] = contractSelection(sels[i]); + cm.setSelections(sels); + } else if (type == "both") { + cm.replaceSelection(left + right, null); + cm.triggerElectric(left + right); + cm.execCommand("goCharLeft"); + } else if (type == "addFour") { + cm.replaceSelection(left + left + left + left, "before"); + cm.execCommand("goCharRight"); + } + }); + } + + function charsAround(cm, pos) { + var str = cm.getRange(Pos(pos.line, pos.ch - 1), + Pos(pos.line, pos.ch + 1)); + return str.length == 2 ? str : null; + } + + function stringStartsAfter(cm, pos) { + var token = cm.getTokenAt(Pos(pos.line, pos.ch + 1)) + return /\bstring/.test(token.type) && token.start == pos.ch && + (pos.ch == 0 || !/\bstring/.test(cm.getTokenTypeAt(pos))) + } +}); diff --git a/public/vendor/plugins/codemirror/addon/edit/closetag.js b/public/vendor/plugins/codemirror/addon/edit/closetag.js new file mode 100644 index 0000000000000..4f5aae49d9dc6 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/edit/closetag.js @@ -0,0 +1,184 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +/** + * Tag-closer extension for CodeMirror. + * + * This extension adds an "autoCloseTags" option that can be set to + * either true to get the default behavior, or an object to further + * configure its behavior. + * + * These are supported options: + * + * `whenClosing` (default true) + * Whether to autoclose when the '/' of a closing tag is typed. + * `whenOpening` (default true) + * Whether to autoclose the tag when the final '>' of an opening + * tag is typed. + * `dontCloseTags` (default is empty tags for HTML, none for XML) + * An array of tag names that should not be autoclosed. + * `indentTags` (default is block tags for HTML, none for XML) + * An array of tag names that should, when opened, cause a + * blank line to be added inside the tag, and the blank line and + * closing line to be indented. + * `emptyTags` (default is none) + * An array of XML tag names that should be autoclosed with '/>'. + * + * See demos/closetag.html for a usage example. + */ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../fold/xml-fold")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../fold/xml-fold"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) { + if (old != CodeMirror.Init && old) + cm.removeKeyMap("autoCloseTags"); + if (!val) return; + var map = {name: "autoCloseTags"}; + if (typeof val != "object" || val.whenClosing) + map["'/'"] = function(cm) { return autoCloseSlash(cm); }; + if (typeof val != "object" || val.whenOpening) + map["'>'"] = function(cm) { return autoCloseGT(cm); }; + cm.addKeyMap(map); + }); + + var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", + "source", "track", "wbr"]; + var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4", + "h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"]; + + function autoCloseGT(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + var ranges = cm.listSelections(), replacements = []; + var opt = cm.getOption("autoCloseTags"); + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) return CodeMirror.Pass; + var pos = ranges[i].head, tok = cm.getTokenAt(pos); + var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; + var tagInfo = inner.mode.xmlCurrentTag && inner.mode.xmlCurrentTag(state) + var tagName = tagInfo && tagInfo.name + if (!tagName) return CodeMirror.Pass + + var html = inner.mode.configuration == "html"; + var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose); + var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent); + + if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch); + var lowerTagName = tagName.toLowerCase(); + // Don't process the '>' at the end of an end-tag or self-closing tag + if (!tagName || + tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) || + tok.type == "tag" && tagInfo.close || + tok.string.indexOf("/") == (tok.string.length - 1) || // match something like + dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 || + closingTagExists(cm, inner.mode.xmlCurrentContext && inner.mode.xmlCurrentContext(state) || [], tagName, pos, true)) + return CodeMirror.Pass; + + var emptyTags = typeof opt == "object" && opt.emptyTags; + if (emptyTags && indexOf(emptyTags, tagName) > -1) { + replacements[i] = { text: "/>", newPos: CodeMirror.Pos(pos.line, pos.ch + 2) }; + continue; + } + + var indent = indentTags && indexOf(indentTags, lowerTagName) > -1; + replacements[i] = {indent: indent, + text: ">" + (indent ? "\n\n" : "") + "", + newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)}; + } + + var dontIndentOnAutoClose = (typeof opt == "object" && opt.dontIndentOnAutoClose); + for (var i = ranges.length - 1; i >= 0; i--) { + var info = replacements[i]; + cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert"); + var sel = cm.listSelections().slice(0); + sel[i] = {head: info.newPos, anchor: info.newPos}; + cm.setSelections(sel); + if (!dontIndentOnAutoClose && info.indent) { + cm.indentLine(info.newPos.line, null, true); + cm.indentLine(info.newPos.line + 1, null, true); + } + } + } + + function autoCloseCurrent(cm, typingSlash) { + var ranges = cm.listSelections(), replacements = []; + var head = typingSlash ? "/" : "") replacement += ">"; + replacements[i] = replacement; + } + cm.replaceSelections(replacements); + ranges = cm.listSelections(); + if (!dontIndentOnAutoClose) { + for (var i = 0; i < ranges.length; i++) + if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line) + cm.indentLine(ranges[i].head.line); + } + } + + function autoCloseSlash(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + return autoCloseCurrent(cm, true); + } + + CodeMirror.commands.closeTag = function(cm) { return autoCloseCurrent(cm); }; + + function indexOf(collection, elt) { + if (collection.indexOf) return collection.indexOf(elt); + for (var i = 0, e = collection.length; i < e; ++i) + if (collection[i] == elt) return i; + return -1; + } + + // If xml-fold is loaded, we use its functionality to try and verify + // whether a given tag is actually unclosed. + function closingTagExists(cm, context, tagName, pos, newTag) { + if (!CodeMirror.scanForClosingTag) return false; + var end = Math.min(cm.lastLine() + 1, pos.line + 500); + var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end); + if (!nextClose || nextClose.tag != tagName) return false; + // If the immediate wrapping context contains onCx instances of + // the same tag, a closing tag only exists if there are at least + // that many closing tags of that type following. + var onCx = newTag ? 1 : 0 + for (var i = context.length - 1; i >= 0; i--) { + if (context[i] == tagName) ++onCx + else break + } + pos = nextClose.to; + for (var i = 1; i < onCx; i++) { + var next = CodeMirror.scanForClosingTag(cm, pos, null, end); + if (!next || next.tag != tagName) return false; + pos = next.to; + } + return true; + } +}); diff --git a/public/vendor/plugins/codemirror/addon/edit/continuelist.js b/public/vendor/plugins/codemirror/addon/edit/continuelist.js new file mode 100644 index 0000000000000..fb5f03735d880 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/edit/continuelist.js @@ -0,0 +1,99 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var listRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]\s|[*+-]\s|(\d+)([.)]))(\s*)/, + emptyListRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]|[*+-]|(\d+)[.)])(\s*)$/, + unorderedListRE = /[*+-]\s/; + + CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + var ranges = cm.listSelections(), replacements = []; + for (var i = 0; i < ranges.length; i++) { + var pos = ranges[i].head; + + // If we're not in Markdown mode, fall back to normal newlineAndIndent + var eolState = cm.getStateAfter(pos.line); + var inner = CodeMirror.innerMode(cm.getMode(), eolState); + if (inner.mode.name !== "markdown") { + cm.execCommand("newlineAndIndent"); + return; + } else { + eolState = inner.state; + } + + var inList = eolState.list !== false; + var inQuote = eolState.quote !== 0; + + var line = cm.getLine(pos.line), match = listRE.exec(line); + var cursorBeforeBullet = /^\s*$/.test(line.slice(0, pos.ch)); + if (!ranges[i].empty() || (!inList && !inQuote) || !match || cursorBeforeBullet) { + cm.execCommand("newlineAndIndent"); + return; + } + if (emptyListRE.test(line)) { + if (!/>\s*$/.test(line)) cm.replaceRange("", { + line: pos.line, ch: 0 + }, { + line: pos.line, ch: pos.ch + 1 + }); + replacements[i] = "\n"; + } else { + var indent = match[1], after = match[5]; + var numbered = !(unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0); + var bullet = numbered ? (parseInt(match[3], 10) + 1) + match[4] : match[2].replace("x", " "); + replacements[i] = "\n" + indent + bullet + after; + + if (numbered) incrementRemainingMarkdownListNumbers(cm, pos); + } + } + + cm.replaceSelections(replacements); + }; + + // Auto-updating Markdown list numbers when a new item is added to the + // middle of a list + function incrementRemainingMarkdownListNumbers(cm, pos) { + var startLine = pos.line, lookAhead = 0, skipCount = 0; + var startItem = listRE.exec(cm.getLine(startLine)), startIndent = startItem[1]; + + do { + lookAhead += 1; + var nextLineNumber = startLine + lookAhead; + var nextLine = cm.getLine(nextLineNumber), nextItem = listRE.exec(nextLine); + + if (nextItem) { + var nextIndent = nextItem[1]; + var newNumber = (parseInt(startItem[3], 10) + lookAhead - skipCount); + var nextNumber = (parseInt(nextItem[3], 10)), itemNumber = nextNumber; + + if (startIndent === nextIndent && !isNaN(nextNumber)) { + if (newNumber === nextNumber) itemNumber = nextNumber + 1; + if (newNumber > nextNumber) itemNumber = newNumber + 1; + cm.replaceRange( + nextLine.replace(listRE, nextIndent + itemNumber + nextItem[4] + nextItem[5]), + { + line: nextLineNumber, ch: 0 + }, { + line: nextLineNumber, ch: nextLine.length + }); + } else { + if (startIndent.length > nextIndent.length) return; + // This doesn't run if the next line immediatley indents, as it is + // not clear of the users intention (new indented item or same level) + if ((startIndent.length < nextIndent.length) && (lookAhead === 1)) return; + skipCount += 1; + } + } + } while (nextItem); + } +}); diff --git a/public/vendor/plugins/codemirror/addon/edit/matchbrackets.js b/public/vendor/plugins/codemirror/addon/edit/matchbrackets.js new file mode 100644 index 0000000000000..2a147282c458d --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/edit/matchbrackets.js @@ -0,0 +1,150 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + var ie_lt8 = /MSIE \d/.test(navigator.userAgent) && + (document.documentMode == null || document.documentMode < 8); + + var Pos = CodeMirror.Pos; + + var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<", "<": ">>", ">": "<<"}; + + function bracketRegex(config) { + return config && config.bracketRegex || /[(){}[\]]/ + } + + function findMatchingBracket(cm, where, config) { + var line = cm.getLineHandle(where.line), pos = where.ch - 1; + var afterCursor = config && config.afterCursor + if (afterCursor == null) + afterCursor = /(^| )cm-fat-cursor($| )/.test(cm.getWrapperElement().className) + var re = bracketRegex(config) + + // A cursor is defined as between two characters, but in in vim command mode + // (i.e. not insert mode), the cursor is visually represented as a + // highlighted box on top of the 2nd character. Otherwise, we allow matches + // from before or after the cursor. + var match = (!afterCursor && pos >= 0 && re.test(line.text.charAt(pos)) && matching[line.text.charAt(pos)]) || + re.test(line.text.charAt(pos + 1)) && matching[line.text.charAt(++pos)]; + if (!match) return null; + var dir = match.charAt(1) == ">" ? 1 : -1; + if (config && config.strict && (dir > 0) != (pos == where.ch)) return null; + var style = cm.getTokenTypeAt(Pos(where.line, pos + 1)); + + var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config); + if (found == null) return null; + return {from: Pos(where.line, pos), to: found && found.pos, + match: found && found.ch == match.charAt(0), forward: dir > 0}; + } + + // bracketRegex is used to specify which type of bracket to scan + // should be a regexp, e.g. /[[\]]/ + // + // Note: If "where" is on an open bracket, then this bracket is ignored. + // + // Returns false when no bracket was found, null when it reached + // maxScanLines and gave up + function scanForBracket(cm, where, dir, style, config) { + var maxScanLen = (config && config.maxScanLineLength) || 10000; + var maxScanLines = (config && config.maxScanLines) || 1000; + + var stack = []; + var re = bracketRegex(config) + var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1) + : Math.max(cm.firstLine() - 1, where.line - maxScanLines); + for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) { + var line = cm.getLine(lineNo); + if (!line) continue; + var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1; + if (line.length > maxScanLen) continue; + if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0); + for (; pos != end; pos += dir) { + var ch = line.charAt(pos); + if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) { + var match = matching[ch]; + if (match && (match.charAt(1) == ">") == (dir > 0)) stack.push(ch); + else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch}; + else stack.pop(); + } + } + } + return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null; + } + + function matchBrackets(cm, autoclear, config) { + // Disable brace matching in long lines, since it'll cause hugely slow updates + var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000; + var marks = [], ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, config); + if (match && cm.getLine(match.from.line).length <= maxHighlightLen) { + var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket"; + marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style})); + if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen) + marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style})); + } + } + + if (marks.length) { + // Kludge to work around the IE bug from issue #1193, where text + // input stops going to the textare whever this fires. + if (ie_lt8 && cm.state.focused) cm.focus(); + + var clear = function() { + cm.operation(function() { + for (var i = 0; i < marks.length; i++) marks[i].clear(); + }); + }; + if (autoclear) setTimeout(clear, 800); + else return clear; + } + } + + function doMatchBrackets(cm) { + cm.operation(function() { + if (cm.state.matchBrackets.currentlyHighlighted) { + cm.state.matchBrackets.currentlyHighlighted(); + cm.state.matchBrackets.currentlyHighlighted = null; + } + cm.state.matchBrackets.currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets); + }); + } + + CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + cm.off("cursorActivity", doMatchBrackets); + if (cm.state.matchBrackets && cm.state.matchBrackets.currentlyHighlighted) { + cm.state.matchBrackets.currentlyHighlighted(); + cm.state.matchBrackets.currentlyHighlighted = null; + } + } + if (val) { + cm.state.matchBrackets = typeof val == "object" ? val : {}; + cm.on("cursorActivity", doMatchBrackets); + } + }); + + CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);}); + CodeMirror.defineExtension("findMatchingBracket", function(pos, config, oldConfig){ + // Backwards-compatibility kludge + if (oldConfig || typeof config == "boolean") { + if (!oldConfig) { + config = config ? {strict: true} : null + } else { + oldConfig.strict = config + config = oldConfig + } + } + return findMatchingBracket(this, pos, config) + }); + CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){ + return scanForBracket(this, pos, dir, style, config); + }); +}); diff --git a/public/vendor/plugins/codemirror/addon/edit/matchtags.js b/public/vendor/plugins/codemirror/addon/edit/matchtags.js new file mode 100644 index 0000000000000..2203d9390dfd4 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/edit/matchtags.js @@ -0,0 +1,66 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../fold/xml-fold")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../fold/xml-fold"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("matchTags", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + cm.off("cursorActivity", doMatchTags); + cm.off("viewportChange", maybeUpdateMatch); + clear(cm); + } + if (val) { + cm.state.matchBothTags = typeof val == "object" && val.bothTags; + cm.on("cursorActivity", doMatchTags); + cm.on("viewportChange", maybeUpdateMatch); + doMatchTags(cm); + } + }); + + function clear(cm) { + if (cm.state.tagHit) cm.state.tagHit.clear(); + if (cm.state.tagOther) cm.state.tagOther.clear(); + cm.state.tagHit = cm.state.tagOther = null; + } + + function doMatchTags(cm) { + cm.state.failedTagMatch = false; + cm.operation(function() { + clear(cm); + if (cm.somethingSelected()) return; + var cur = cm.getCursor(), range = cm.getViewport(); + range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to); + var match = CodeMirror.findMatchingTag(cm, cur, range); + if (!match) return; + if (cm.state.matchBothTags) { + var hit = match.at == "open" ? match.open : match.close; + if (hit) cm.state.tagHit = cm.markText(hit.from, hit.to, {className: "CodeMirror-matchingtag"}); + } + var other = match.at == "close" ? match.open : match.close; + if (other) + cm.state.tagOther = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"}); + else + cm.state.failedTagMatch = true; + }); + } + + function maybeUpdateMatch(cm) { + if (cm.state.failedTagMatch) doMatchTags(cm); + } + + CodeMirror.commands.toMatchingTag = function(cm) { + var found = CodeMirror.findMatchingTag(cm, cm.getCursor()); + if (found) { + var other = found.at == "close" ? found.open : found.close; + if (other) cm.extendSelection(other.to, other.from); + } + }; +}); diff --git a/public/vendor/plugins/codemirror/addon/edit/trailingspace.js b/public/vendor/plugins/codemirror/addon/edit/trailingspace.js new file mode 100644 index 0000000000000..c39c310a99572 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/edit/trailingspace.js @@ -0,0 +1,27 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + CodeMirror.defineOption("showTrailingSpace", false, function(cm, val, prev) { + if (prev == CodeMirror.Init) prev = false; + if (prev && !val) + cm.removeOverlay("trailingspace"); + else if (!prev && val) + cm.addOverlay({ + token: function(stream) { + for (var l = stream.string.length, i = l; i && /\s/.test(stream.string.charAt(i - 1)); --i) {} + if (i > stream.pos) { stream.pos = i; return null; } + stream.pos = l; + return "trailingspace"; + }, + name: "trailingspace" + }); + }); +}); diff --git a/public/vendor/plugins/codemirror/addon/fold/brace-fold.js b/public/vendor/plugins/codemirror/addon/fold/brace-fold.js new file mode 100644 index 0000000000000..654d1fb691249 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/fold/brace-fold.js @@ -0,0 +1,105 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("fold", "brace", function(cm, start) { + var line = start.line, lineText = cm.getLine(line); + var tokenType; + + function findOpening(openCh) { + for (var at = start.ch, pass = 0;;) { + var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1); + if (found == -1) { + if (pass == 1) break; + pass = 1; + at = lineText.length; + continue; + } + if (pass == 1 && found < start.ch) break; + tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1)); + if (!/^(comment|string)/.test(tokenType)) return found + 1; + at = found - 1; + } + } + + var startToken = "{", endToken = "}", startCh = findOpening("{"); + if (startCh == null) { + startToken = "[", endToken = "]"; + startCh = findOpening("["); + } + + if (startCh == null) return; + var count = 1, lastLine = cm.lastLine(), end, endCh; + outer: for (var i = line; i <= lastLine; ++i) { + var text = cm.getLine(i), pos = i == line ? startCh : 0; + for (;;) { + var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos); + if (nextOpen < 0) nextOpen = text.length; + if (nextClose < 0) nextClose = text.length; + pos = Math.min(nextOpen, nextClose); + if (pos == text.length) break; + if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) { + if (pos == nextOpen) ++count; + else if (!--count) { end = i; endCh = pos; break outer; } + } + ++pos; + } + } + if (end == null || line == end) return; + return {from: CodeMirror.Pos(line, startCh), + to: CodeMirror.Pos(end, endCh)}; +}); + +CodeMirror.registerHelper("fold", "import", function(cm, start) { + function hasImport(line) { + if (line < cm.firstLine() || line > cm.lastLine()) return null; + var start = cm.getTokenAt(CodeMirror.Pos(line, 1)); + if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1)); + if (start.type != "keyword" || start.string != "import") return null; + // Now find closing semicolon, return its position + for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) { + var text = cm.getLine(i), semi = text.indexOf(";"); + if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)}; + } + } + + var startLine = start.line, has = hasImport(startLine), prev; + if (!has || hasImport(startLine - 1) || ((prev = hasImport(startLine - 2)) && prev.end.line == startLine - 1)) + return null; + for (var end = has.end;;) { + var next = hasImport(end.line + 1); + if (next == null) break; + end = next.end; + } + return {from: cm.clipPos(CodeMirror.Pos(startLine, has.startCh + 1)), to: end}; +}); + +CodeMirror.registerHelper("fold", "include", function(cm, start) { + function hasInclude(line) { + if (line < cm.firstLine() || line > cm.lastLine()) return null; + var start = cm.getTokenAt(CodeMirror.Pos(line, 1)); + if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1)); + if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8; + } + + var startLine = start.line, has = hasInclude(startLine); + if (has == null || hasInclude(startLine - 1) != null) return null; + for (var end = startLine;;) { + var next = hasInclude(end + 1); + if (next == null) break; + ++end; + } + return {from: CodeMirror.Pos(startLine, has + 1), + to: cm.clipPos(CodeMirror.Pos(end))}; +}); + +}); diff --git a/public/vendor/plugins/codemirror/addon/fold/comment-fold.js b/public/vendor/plugins/codemirror/addon/fold/comment-fold.js new file mode 100644 index 0000000000000..836101d8b02ef --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/fold/comment-fold.js @@ -0,0 +1,59 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerGlobalHelper("fold", "comment", function(mode) { + return mode.blockCommentStart && mode.blockCommentEnd; +}, function(cm, start) { + var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd; + if (!startToken || !endToken) return; + var line = start.line, lineText = cm.getLine(line); + + var startCh; + for (var at = start.ch, pass = 0;;) { + var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1); + if (found == -1) { + if (pass == 1) return; + pass = 1; + at = lineText.length; + continue; + } + if (pass == 1 && found < start.ch) return; + if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1))) && + (found == 0 || lineText.slice(found - endToken.length, found) == endToken || + !/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found))))) { + startCh = found + startToken.length; + break; + } + at = found - 1; + } + + var depth = 1, lastLine = cm.lastLine(), end, endCh; + outer: for (var i = line; i <= lastLine; ++i) { + var text = cm.getLine(i), pos = i == line ? startCh : 0; + for (;;) { + var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos); + if (nextOpen < 0) nextOpen = text.length; + if (nextClose < 0) nextClose = text.length; + pos = Math.min(nextOpen, nextClose); + if (pos == text.length) break; + if (pos == nextOpen) ++depth; + else if (!--depth) { end = i; endCh = pos; break outer; } + ++pos; + } + } + if (end == null || line == end && endCh == startCh) return; + return {from: CodeMirror.Pos(line, startCh), + to: CodeMirror.Pos(end, endCh)}; +}); + +}); diff --git a/public/vendor/plugins/codemirror/addon/fold/foldcode.js b/public/vendor/plugins/codemirror/addon/fold/foldcode.js new file mode 100644 index 0000000000000..e146fb9f3ee94 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/fold/foldcode.js @@ -0,0 +1,152 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function doFold(cm, pos, options, force) { + if (options && options.call) { + var finder = options; + options = null; + } else { + var finder = getOption(cm, options, "rangeFinder"); + } + if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0); + var minSize = getOption(cm, options, "minFoldSize"); + + function getRange(allowFolded) { + var range = finder(cm, pos); + if (!range || range.to.line - range.from.line < minSize) return null; + var marks = cm.findMarksAt(range.from); + for (var i = 0; i < marks.length; ++i) { + if (marks[i].__isFold && force !== "fold") { + if (!allowFolded) return null; + range.cleared = true; + marks[i].clear(); + } + } + return range; + } + + var range = getRange(true); + if (getOption(cm, options, "scanUp")) while (!range && pos.line > cm.firstLine()) { + pos = CodeMirror.Pos(pos.line - 1, 0); + range = getRange(false); + } + if (!range || range.cleared || force === "unfold") return; + + var myWidget = makeWidget(cm, options); + CodeMirror.on(myWidget, "mousedown", function(e) { + myRange.clear(); + CodeMirror.e_preventDefault(e); + }); + var myRange = cm.markText(range.from, range.to, { + replacedWith: myWidget, + clearOnEnter: getOption(cm, options, "clearOnEnter"), + __isFold: true + }); + myRange.on("clear", function(from, to) { + CodeMirror.signal(cm, "unfold", cm, from, to); + }); + CodeMirror.signal(cm, "fold", cm, range.from, range.to); + } + + function makeWidget(cm, options) { + var widget = getOption(cm, options, "widget"); + if (typeof widget == "string") { + var text = document.createTextNode(widget); + widget = document.createElement("span"); + widget.appendChild(text); + widget.className = "CodeMirror-foldmarker"; + } else if (widget) { + widget = widget.cloneNode(true) + } + return widget; + } + + // Clumsy backwards-compatible interface + CodeMirror.newFoldFunction = function(rangeFinder, widget) { + return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); }; + }; + + // New-style interface + CodeMirror.defineExtension("foldCode", function(pos, options, force) { + doFold(this, pos, options, force); + }); + + CodeMirror.defineExtension("isFolded", function(pos) { + var marks = this.findMarksAt(pos); + for (var i = 0; i < marks.length; ++i) + if (marks[i].__isFold) return true; + }); + + CodeMirror.commands.toggleFold = function(cm) { + cm.foldCode(cm.getCursor()); + }; + CodeMirror.commands.fold = function(cm) { + cm.foldCode(cm.getCursor(), null, "fold"); + }; + CodeMirror.commands.unfold = function(cm) { + cm.foldCode(cm.getCursor(), null, "unfold"); + }; + CodeMirror.commands.foldAll = function(cm) { + cm.operation(function() { + for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++) + cm.foldCode(CodeMirror.Pos(i, 0), null, "fold"); + }); + }; + CodeMirror.commands.unfoldAll = function(cm) { + cm.operation(function() { + for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++) + cm.foldCode(CodeMirror.Pos(i, 0), null, "unfold"); + }); + }; + + CodeMirror.registerHelper("fold", "combine", function() { + var funcs = Array.prototype.slice.call(arguments, 0); + return function(cm, start) { + for (var i = 0; i < funcs.length; ++i) { + var found = funcs[i](cm, start); + if (found) return found; + } + }; + }); + + CodeMirror.registerHelper("fold", "auto", function(cm, start) { + var helpers = cm.getHelpers(start, "fold"); + for (var i = 0; i < helpers.length; i++) { + var cur = helpers[i](cm, start); + if (cur) return cur; + } + }); + + var defaultOptions = { + rangeFinder: CodeMirror.fold.auto, + widget: "\u2194", + minFoldSize: 0, + scanUp: false, + clearOnEnter: true + }; + + CodeMirror.defineOption("foldOptions", null); + + function getOption(cm, options, name) { + if (options && options[name] !== undefined) + return options[name]; + var editorOptions = cm.options.foldOptions; + if (editorOptions && editorOptions[name] !== undefined) + return editorOptions[name]; + return defaultOptions[name]; + } + + CodeMirror.defineExtension("foldOption", function(options, name) { + return getOption(this, options, name); + }); +}); diff --git a/public/vendor/plugins/codemirror/addon/fold/foldgutter.css b/public/vendor/plugins/codemirror/addon/fold/foldgutter.css new file mode 100644 index 0000000000000..ad19ae2d3ee19 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/fold/foldgutter.css @@ -0,0 +1,20 @@ +.CodeMirror-foldmarker { + color: blue; + text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px; + font-family: arial; + line-height: .3; + cursor: pointer; +} +.CodeMirror-foldgutter { + width: .7em; +} +.CodeMirror-foldgutter-open, +.CodeMirror-foldgutter-folded { + cursor: pointer; +} +.CodeMirror-foldgutter-open:after { + content: "\25BE"; +} +.CodeMirror-foldgutter-folded:after { + content: "\25B8"; +} diff --git a/public/vendor/plugins/codemirror/addon/fold/foldgutter.js b/public/vendor/plugins/codemirror/addon/fold/foldgutter.js new file mode 100644 index 0000000000000..e57a1df35d7ec --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/fold/foldgutter.js @@ -0,0 +1,151 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("./foldcode")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "./foldcode"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("foldGutter", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + cm.clearGutter(cm.state.foldGutter.options.gutter); + cm.state.foldGutter = null; + cm.off("gutterClick", onGutterClick); + cm.off("changes", onChange); + cm.off("viewportChange", onViewportChange); + cm.off("fold", onFold); + cm.off("unfold", onFold); + cm.off("swapDoc", onChange); + } + if (val) { + cm.state.foldGutter = new State(parseOptions(val)); + updateInViewport(cm); + cm.on("gutterClick", onGutterClick); + cm.on("changes", onChange); + cm.on("viewportChange", onViewportChange); + cm.on("fold", onFold); + cm.on("unfold", onFold); + cm.on("swapDoc", onChange); + } + }); + + var Pos = CodeMirror.Pos; + + function State(options) { + this.options = options; + this.from = this.to = 0; + } + + function parseOptions(opts) { + if (opts === true) opts = {}; + if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter"; + if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open"; + if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded"; + return opts; + } + + function isFolded(cm, line) { + var marks = cm.findMarks(Pos(line, 0), Pos(line + 1, 0)); + for (var i = 0; i < marks.length; ++i) { + if (marks[i].__isFold) { + var fromPos = marks[i].find(-1); + if (fromPos && fromPos.line === line) + return marks[i]; + } + } + } + + function marker(spec) { + if (typeof spec == "string") { + var elt = document.createElement("div"); + elt.className = spec + " CodeMirror-guttermarker-subtle"; + return elt; + } else { + return spec.cloneNode(true); + } + } + + function updateFoldInfo(cm, from, to) { + var opts = cm.state.foldGutter.options, cur = from; + var minSize = cm.foldOption(opts, "minFoldSize"); + var func = cm.foldOption(opts, "rangeFinder"); + cm.eachLine(from, to, function(line) { + var mark = null; + if (isFolded(cm, cur)) { + mark = marker(opts.indicatorFolded); + } else { + var pos = Pos(cur, 0); + var range = func && func(cm, pos); + if (range && range.to.line - range.from.line >= minSize) + mark = marker(opts.indicatorOpen); + } + cm.setGutterMarker(line, opts.gutter, mark); + ++cur; + }); + } + + function updateInViewport(cm) { + var vp = cm.getViewport(), state = cm.state.foldGutter; + if (!state) return; + cm.operation(function() { + updateFoldInfo(cm, vp.from, vp.to); + }); + state.from = vp.from; state.to = vp.to; + } + + function onGutterClick(cm, line, gutter) { + var state = cm.state.foldGutter; + if (!state) return; + var opts = state.options; + if (gutter != opts.gutter) return; + var folded = isFolded(cm, line); + if (folded) folded.clear(); + else cm.foldCode(Pos(line, 0), opts); + } + + function onChange(cm) { + var state = cm.state.foldGutter; + if (!state) return; + var opts = state.options; + state.from = state.to = 0; + clearTimeout(state.changeUpdate); + state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600); + } + + function onViewportChange(cm) { + var state = cm.state.foldGutter; + if (!state) return; + var opts = state.options; + clearTimeout(state.changeUpdate); + state.changeUpdate = setTimeout(function() { + var vp = cm.getViewport(); + if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) { + updateInViewport(cm); + } else { + cm.operation(function() { + if (vp.from < state.from) { + updateFoldInfo(cm, vp.from, state.from); + state.from = vp.from; + } + if (vp.to > state.to) { + updateFoldInfo(cm, state.to, vp.to); + state.to = vp.to; + } + }); + } + }, opts.updateViewportTimeSpan || 400); + } + + function onFold(cm, from) { + var state = cm.state.foldGutter; + if (!state) return; + var line = from.line; + if (line >= state.from && line < state.to) + updateFoldInfo(cm, line, line + 1); + } +}); diff --git a/public/vendor/plugins/codemirror/addon/fold/indent-fold.js b/public/vendor/plugins/codemirror/addon/fold/indent-fold.js new file mode 100644 index 0000000000000..0cc1126440377 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/fold/indent-fold.js @@ -0,0 +1,48 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +function lineIndent(cm, lineNo) { + var text = cm.getLine(lineNo) + var spaceTo = text.search(/\S/) + if (spaceTo == -1 || /\bcomment\b/.test(cm.getTokenTypeAt(CodeMirror.Pos(lineNo, spaceTo + 1)))) + return -1 + return CodeMirror.countColumn(text, null, cm.getOption("tabSize")) +} + +CodeMirror.registerHelper("fold", "indent", function(cm, start) { + var myIndent = lineIndent(cm, start.line) + if (myIndent < 0) return + var lastLineInFold = null + + // Go through lines until we find a line that definitely doesn't belong in + // the block we're folding, or to the end. + for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) { + var indent = lineIndent(cm, i) + if (indent == -1) { + } else if (indent > myIndent) { + // Lines with a greater indent are considered part of the block. + lastLineInFold = i; + } else { + // If this line has non-space, non-comment content, and is + // indented less or equal to the start line, it is the start of + // another block. + break; + } + } + if (lastLineInFold) return { + from: CodeMirror.Pos(start.line, cm.getLine(start.line).length), + to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length) + }; +}); + +}); diff --git a/public/vendor/plugins/codemirror/addon/fold/markdown-fold.js b/public/vendor/plugins/codemirror/addon/fold/markdown-fold.js new file mode 100644 index 0000000000000..6a551786d19d2 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/fold/markdown-fold.js @@ -0,0 +1,49 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("fold", "markdown", function(cm, start) { + var maxDepth = 100; + + function isHeader(lineNo) { + var tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0)); + return tokentype && /\bheader\b/.test(tokentype); + } + + function headerLevel(lineNo, line, nextLine) { + var match = line && line.match(/^#+/); + if (match && isHeader(lineNo)) return match[0].length; + match = nextLine && nextLine.match(/^[=\-]+\s*$/); + if (match && isHeader(lineNo + 1)) return nextLine[0] == "=" ? 1 : 2; + return maxDepth; + } + + var firstLine = cm.getLine(start.line), nextLine = cm.getLine(start.line + 1); + var level = headerLevel(start.line, firstLine, nextLine); + if (level === maxDepth) return undefined; + + var lastLineNo = cm.lastLine(); + var end = start.line, nextNextLine = cm.getLine(end + 2); + while (end < lastLineNo) { + if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break; + ++end; + nextLine = nextNextLine; + nextNextLine = cm.getLine(end + 2); + } + + return { + from: CodeMirror.Pos(start.line, firstLine.length), + to: CodeMirror.Pos(end, cm.getLine(end).length) + }; +}); + +}); diff --git a/public/vendor/plugins/codemirror/addon/fold/xml-fold.js b/public/vendor/plugins/codemirror/addon/fold/xml-fold.js new file mode 100644 index 0000000000000..13bc3838b2a26 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/fold/xml-fold.js @@ -0,0 +1,184 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var Pos = CodeMirror.Pos; + function cmp(a, b) { return a.line - b.line || a.ch - b.ch; } + + var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD"; + var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; + var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g"); + + function Iter(cm, line, ch, range) { + this.line = line; this.ch = ch; + this.cm = cm; this.text = cm.getLine(line); + this.min = range ? Math.max(range.from, cm.firstLine()) : cm.firstLine(); + this.max = range ? Math.min(range.to - 1, cm.lastLine()) : cm.lastLine(); + } + + function tagAt(iter, ch) { + var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch)); + return type && /\btag\b/.test(type); + } + + function nextLine(iter) { + if (iter.line >= iter.max) return; + iter.ch = 0; + iter.text = iter.cm.getLine(++iter.line); + return true; + } + function prevLine(iter) { + if (iter.line <= iter.min) return; + iter.text = iter.cm.getLine(--iter.line); + iter.ch = iter.text.length; + return true; + } + + function toTagEnd(iter) { + for (;;) { + var gt = iter.text.indexOf(">", iter.ch); + if (gt == -1) { if (nextLine(iter)) continue; else return; } + if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; } + var lastSlash = iter.text.lastIndexOf("/", gt); + var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt)); + iter.ch = gt + 1; + return selfClose ? "selfClose" : "regular"; + } + } + function toTagStart(iter) { + for (;;) { + var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1; + if (lt == -1) { if (prevLine(iter)) continue; else return; } + if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; } + xmlTagStart.lastIndex = lt; + iter.ch = lt; + var match = xmlTagStart.exec(iter.text); + if (match && match.index == lt) return match; + } + } + + function toNextTag(iter) { + for (;;) { + xmlTagStart.lastIndex = iter.ch; + var found = xmlTagStart.exec(iter.text); + if (!found) { if (nextLine(iter)) continue; else return; } + if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; } + iter.ch = found.index + found[0].length; + return found; + } + } + function toPrevTag(iter) { + for (;;) { + var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1; + if (gt == -1) { if (prevLine(iter)) continue; else return; } + if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; } + var lastSlash = iter.text.lastIndexOf("/", gt); + var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt)); + iter.ch = gt + 1; + return selfClose ? "selfClose" : "regular"; + } + } + + function findMatchingClose(iter, tag) { + var stack = []; + for (;;) { + var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0); + if (!next || !(end = toTagEnd(iter))) return; + if (end == "selfClose") continue; + if (next[1]) { // closing tag + for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) { + stack.length = i; + break; + } + if (i < 0 && (!tag || tag == next[2])) return { + tag: next[2], + from: Pos(startLine, startCh), + to: Pos(iter.line, iter.ch) + }; + } else { // opening tag + stack.push(next[2]); + } + } + } + function findMatchingOpen(iter, tag) { + var stack = []; + for (;;) { + var prev = toPrevTag(iter); + if (!prev) return; + if (prev == "selfClose") { toTagStart(iter); continue; } + var endLine = iter.line, endCh = iter.ch; + var start = toTagStart(iter); + if (!start) return; + if (start[1]) { // closing tag + stack.push(start[2]); + } else { // opening tag + for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) { + stack.length = i; + break; + } + if (i < 0 && (!tag || tag == start[2])) return { + tag: start[2], + from: Pos(iter.line, iter.ch), + to: Pos(endLine, endCh) + }; + } + } + } + + CodeMirror.registerHelper("fold", "xml", function(cm, start) { + var iter = new Iter(cm, start.line, 0); + for (;;) { + var openTag = toNextTag(iter) + if (!openTag || iter.line != start.line) return + var end = toTagEnd(iter) + if (!end) return + if (!openTag[1] && end != "selfClose") { + var startPos = Pos(iter.line, iter.ch); + var endPos = findMatchingClose(iter, openTag[2]); + return endPos && cmp(endPos.from, startPos) > 0 ? {from: startPos, to: endPos.from} : null + } + } + }); + CodeMirror.findMatchingTag = function(cm, pos, range) { + var iter = new Iter(cm, pos.line, pos.ch, range); + if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return; + var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch); + var start = end && toTagStart(iter); + if (!end || !start || cmp(iter, pos) > 0) return; + var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]}; + if (end == "selfClose") return {open: here, close: null, at: "open"}; + + if (start[1]) { // closing tag + return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"}; + } else { // opening tag + iter = new Iter(cm, to.line, to.ch, range); + return {open: here, close: findMatchingClose(iter, start[2]), at: "open"}; + } + }; + + CodeMirror.findEnclosingTag = function(cm, pos, range, tag) { + var iter = new Iter(cm, pos.line, pos.ch, range); + for (;;) { + var open = findMatchingOpen(iter, tag); + if (!open) break; + var forward = new Iter(cm, pos.line, pos.ch, range); + var close = findMatchingClose(forward, open.tag); + if (close) return {open: open, close: close}; + } + }; + + // Used by addon/edit/closetag.js + CodeMirror.scanForClosingTag = function(cm, pos, name, end) { + var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null); + return findMatchingClose(iter, name); + }; +}); diff --git a/public/vendor/plugins/codemirror/addon/hint/anyword-hint.js b/public/vendor/plugins/codemirror/addon/hint/anyword-hint.js new file mode 100644 index 0000000000000..d27a9ec018415 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/hint/anyword-hint.js @@ -0,0 +1,41 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var WORD = /[\w$]+/, RANGE = 500; + + CodeMirror.registerHelper("hint", "anyword", function(editor, options) { + var word = options && options.word || WORD; + var range = options && options.range || RANGE; + var cur = editor.getCursor(), curLine = editor.getLine(cur.line); + var end = cur.ch, start = end; + while (start && word.test(curLine.charAt(start - 1))) --start; + var curWord = start != end && curLine.slice(start, end); + + var list = options && options.list || [], seen = {}; + var re = new RegExp(word.source, "g"); + for (var dir = -1; dir <= 1; dir += 2) { + var line = cur.line, endLine = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir; + for (; line != endLine; line += dir) { + var text = editor.getLine(line), m; + while (m = re.exec(text)) { + if (line == cur.line && m[0] === curWord) continue; + if ((!curWord || m[0].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, m[0])) { + seen[m[0]] = true; + list.push(m[0]); + } + } + } + } + return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)}; + }); +}); diff --git a/public/vendor/plugins/codemirror/addon/hint/css-hint.js b/public/vendor/plugins/codemirror/addon/hint/css-hint.js new file mode 100644 index 0000000000000..6cdf728195b9c --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/hint/css-hint.js @@ -0,0 +1,60 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../../mode/css/css")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../../mode/css/css"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var pseudoClasses = {link: 1, visited: 1, active: 1, hover: 1, focus: 1, + "first-letter": 1, "first-line": 1, "first-child": 1, + before: 1, after: 1, lang: 1}; + + CodeMirror.registerHelper("hint", "css", function(cm) { + var cur = cm.getCursor(), token = cm.getTokenAt(cur); + var inner = CodeMirror.innerMode(cm.getMode(), token.state); + if (inner.mode.name != "css") return; + + if (token.type == "keyword" && "!important".indexOf(token.string) == 0) + return {list: ["!important"], from: CodeMirror.Pos(cur.line, token.start), + to: CodeMirror.Pos(cur.line, token.end)}; + + var start = token.start, end = cur.ch, word = token.string.slice(0, end - start); + if (/[^\w$_-]/.test(word)) { + word = ""; start = end = cur.ch; + } + + var spec = CodeMirror.resolveMode("text/css"); + + var result = []; + function add(keywords) { + for (var name in keywords) + if (!word || name.lastIndexOf(word, 0) == 0) + result.push(name); + } + + var st = inner.state.state; + if (st == "pseudo" || token.type == "variable-3") { + add(pseudoClasses); + } else if (st == "block" || st == "maybeprop") { + add(spec.propertyKeywords); + } else if (st == "prop" || st == "parens" || st == "at" || st == "params") { + add(spec.valueKeywords); + add(spec.colorKeywords); + } else if (st == "media" || st == "media_parens") { + add(spec.mediaTypes); + add(spec.mediaFeatures); + } + + if (result.length) return { + list: result, + from: CodeMirror.Pos(cur.line, start), + to: CodeMirror.Pos(cur.line, end) + }; + }); +}); diff --git a/public/vendor/plugins/codemirror/addon/hint/html-hint.js b/public/vendor/plugins/codemirror/addon/hint/html-hint.js new file mode 100644 index 0000000000000..d0cca4f6a205f --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/hint/html-hint.js @@ -0,0 +1,350 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("./xml-hint")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "./xml-hint"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var langs = "ab aa af ak sq am ar an hy as av ae ay az bm ba eu be bn bh bi bs br bg my ca ch ce ny zh cv kw co cr hr cs da dv nl dz en eo et ee fo fj fi fr ff gl ka de el gn gu ht ha he hz hi ho hu ia id ie ga ig ik io is it iu ja jv kl kn kr ks kk km ki rw ky kv kg ko ku kj la lb lg li ln lo lt lu lv gv mk mg ms ml mt mi mr mh mn na nv nb nd ne ng nn no ii nr oc oj cu om or os pa pi fa pl ps pt qu rm rn ro ru sa sc sd se sm sg sr gd sn si sk sl so st es su sw ss sv ta te tg th ti bo tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa cy wo fy xh yi yo za zu".split(" "); + var targets = ["_blank", "_self", "_top", "_parent"]; + var charsets = ["ascii", "utf-8", "utf-16", "latin1", "latin1"]; + var methods = ["get", "post", "put", "delete"]; + var encs = ["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"]; + var media = ["all", "screen", "print", "embossed", "braille", "handheld", "print", "projection", "screen", "tty", "tv", "speech", + "3d-glasses", "resolution [>][<][=] [X]", "device-aspect-ratio: X/Y", "orientation:portrait", + "orientation:landscape", "device-height: [X]", "device-width: [X]"]; + var s = { attrs: {} }; // Simple tag, reused for a whole lot of tags + + var data = { + a: { + attrs: { + href: null, ping: null, type: null, + media: media, + target: targets, + hreflang: langs + } + }, + abbr: s, + acronym: s, + address: s, + applet: s, + area: { + attrs: { + alt: null, coords: null, href: null, target: null, ping: null, + media: media, hreflang: langs, type: null, + shape: ["default", "rect", "circle", "poly"] + } + }, + article: s, + aside: s, + audio: { + attrs: { + src: null, mediagroup: null, + crossorigin: ["anonymous", "use-credentials"], + preload: ["none", "metadata", "auto"], + autoplay: ["", "autoplay"], + loop: ["", "loop"], + controls: ["", "controls"] + } + }, + b: s, + base: { attrs: { href: null, target: targets } }, + basefont: s, + bdi: s, + bdo: s, + big: s, + blockquote: { attrs: { cite: null } }, + body: s, + br: s, + button: { + attrs: { + form: null, formaction: null, name: null, value: null, + autofocus: ["", "autofocus"], + disabled: ["", "autofocus"], + formenctype: encs, + formmethod: methods, + formnovalidate: ["", "novalidate"], + formtarget: targets, + type: ["submit", "reset", "button"] + } + }, + canvas: { attrs: { width: null, height: null } }, + caption: s, + center: s, + cite: s, + code: s, + col: { attrs: { span: null } }, + colgroup: { attrs: { span: null } }, + command: { + attrs: { + type: ["command", "checkbox", "radio"], + label: null, icon: null, radiogroup: null, command: null, title: null, + disabled: ["", "disabled"], + checked: ["", "checked"] + } + }, + data: { attrs: { value: null } }, + datagrid: { attrs: { disabled: ["", "disabled"], multiple: ["", "multiple"] } }, + datalist: { attrs: { data: null } }, + dd: s, + del: { attrs: { cite: null, datetime: null } }, + details: { attrs: { open: ["", "open"] } }, + dfn: s, + dir: s, + div: s, + dl: s, + dt: s, + em: s, + embed: { attrs: { src: null, type: null, width: null, height: null } }, + eventsource: { attrs: { src: null } }, + fieldset: { attrs: { disabled: ["", "disabled"], form: null, name: null } }, + figcaption: s, + figure: s, + font: s, + footer: s, + form: { + attrs: { + action: null, name: null, + "accept-charset": charsets, + autocomplete: ["on", "off"], + enctype: encs, + method: methods, + novalidate: ["", "novalidate"], + target: targets + } + }, + frame: s, + frameset: s, + h1: s, h2: s, h3: s, h4: s, h5: s, h6: s, + head: { + attrs: {}, + children: ["title", "base", "link", "style", "meta", "script", "noscript", "command"] + }, + header: s, + hgroup: s, + hr: s, + html: { + attrs: { manifest: null }, + children: ["head", "body"] + }, + i: s, + iframe: { + attrs: { + src: null, srcdoc: null, name: null, width: null, height: null, + sandbox: ["allow-top-navigation", "allow-same-origin", "allow-forms", "allow-scripts"], + seamless: ["", "seamless"] + } + }, + img: { + attrs: { + alt: null, src: null, ismap: null, usemap: null, width: null, height: null, + crossorigin: ["anonymous", "use-credentials"] + } + }, + input: { + attrs: { + alt: null, dirname: null, form: null, formaction: null, + height: null, list: null, max: null, maxlength: null, min: null, + name: null, pattern: null, placeholder: null, size: null, src: null, + step: null, value: null, width: null, + accept: ["audio/*", "video/*", "image/*"], + autocomplete: ["on", "off"], + autofocus: ["", "autofocus"], + checked: ["", "checked"], + disabled: ["", "disabled"], + formenctype: encs, + formmethod: methods, + formnovalidate: ["", "novalidate"], + formtarget: targets, + multiple: ["", "multiple"], + readonly: ["", "readonly"], + required: ["", "required"], + type: ["hidden", "text", "search", "tel", "url", "email", "password", "datetime", "date", "month", + "week", "time", "datetime-local", "number", "range", "color", "checkbox", "radio", + "file", "submit", "image", "reset", "button"] + } + }, + ins: { attrs: { cite: null, datetime: null } }, + kbd: s, + keygen: { + attrs: { + challenge: null, form: null, name: null, + autofocus: ["", "autofocus"], + disabled: ["", "disabled"], + keytype: ["RSA"] + } + }, + label: { attrs: { "for": null, form: null } }, + legend: s, + li: { attrs: { value: null } }, + link: { + attrs: { + href: null, type: null, + hreflang: langs, + media: media, + sizes: ["all", "16x16", "16x16 32x32", "16x16 32x32 64x64"] + } + }, + map: { attrs: { name: null } }, + mark: s, + menu: { attrs: { label: null, type: ["list", "context", "toolbar"] } }, + meta: { + attrs: { + content: null, + charset: charsets, + name: ["viewport", "application-name", "author", "description", "generator", "keywords"], + "http-equiv": ["content-language", "content-type", "default-style", "refresh"] + } + }, + meter: { attrs: { value: null, min: null, low: null, high: null, max: null, optimum: null } }, + nav: s, + noframes: s, + noscript: s, + object: { + attrs: { + data: null, type: null, name: null, usemap: null, form: null, width: null, height: null, + typemustmatch: ["", "typemustmatch"] + } + }, + ol: { attrs: { reversed: ["", "reversed"], start: null, type: ["1", "a", "A", "i", "I"] } }, + optgroup: { attrs: { disabled: ["", "disabled"], label: null } }, + option: { attrs: { disabled: ["", "disabled"], label: null, selected: ["", "selected"], value: null } }, + output: { attrs: { "for": null, form: null, name: null } }, + p: s, + param: { attrs: { name: null, value: null } }, + pre: s, + progress: { attrs: { value: null, max: null } }, + q: { attrs: { cite: null } }, + rp: s, + rt: s, + ruby: s, + s: s, + samp: s, + script: { + attrs: { + type: ["text/javascript"], + src: null, + async: ["", "async"], + defer: ["", "defer"], + charset: charsets + } + }, + section: s, + select: { + attrs: { + form: null, name: null, size: null, + autofocus: ["", "autofocus"], + disabled: ["", "disabled"], + multiple: ["", "multiple"] + } + }, + small: s, + source: { attrs: { src: null, type: null, media: null } }, + span: s, + strike: s, + strong: s, + style: { + attrs: { + type: ["text/css"], + media: media, + scoped: null + } + }, + sub: s, + summary: s, + sup: s, + table: s, + tbody: s, + td: { attrs: { colspan: null, rowspan: null, headers: null } }, + textarea: { + attrs: { + dirname: null, form: null, maxlength: null, name: null, placeholder: null, + rows: null, cols: null, + autofocus: ["", "autofocus"], + disabled: ["", "disabled"], + readonly: ["", "readonly"], + required: ["", "required"], + wrap: ["soft", "hard"] + } + }, + tfoot: s, + th: { attrs: { colspan: null, rowspan: null, headers: null, scope: ["row", "col", "rowgroup", "colgroup"] } }, + thead: s, + time: { attrs: { datetime: null } }, + title: s, + tr: s, + track: { + attrs: { + src: null, label: null, "default": null, + kind: ["subtitles", "captions", "descriptions", "chapters", "metadata"], + srclang: langs + } + }, + tt: s, + u: s, + ul: s, + "var": s, + video: { + attrs: { + src: null, poster: null, width: null, height: null, + crossorigin: ["anonymous", "use-credentials"], + preload: ["auto", "metadata", "none"], + autoplay: ["", "autoplay"], + mediagroup: ["movie"], + muted: ["", "muted"], + controls: ["", "controls"] + } + }, + wbr: s + }; + + var globalAttrs = { + accesskey: ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], + "class": null, + contenteditable: ["true", "false"], + contextmenu: null, + dir: ["ltr", "rtl", "auto"], + draggable: ["true", "false", "auto"], + dropzone: ["copy", "move", "link", "string:", "file:"], + hidden: ["hidden"], + id: null, + inert: ["inert"], + itemid: null, + itemprop: null, + itemref: null, + itemscope: ["itemscope"], + itemtype: null, + lang: ["en", "es"], + spellcheck: ["true", "false"], + autocorrect: ["true", "false"], + autocapitalize: ["true", "false"], + style: null, + tabindex: ["1", "2", "3", "4", "5", "6", "7", "8", "9"], + title: null, + translate: ["yes", "no"], + onclick: null, + rel: ["stylesheet", "alternate", "author", "bookmark", "help", "license", "next", "nofollow", "noreferrer", "prefetch", "prev", "search", "tag"] + }; + function populate(obj) { + for (var attr in globalAttrs) if (globalAttrs.hasOwnProperty(attr)) + obj.attrs[attr] = globalAttrs[attr]; + } + + populate(s); + for (var tag in data) if (data.hasOwnProperty(tag) && data[tag] != s) + populate(data[tag]); + + CodeMirror.htmlSchema = data; + function htmlHint(cm, options) { + var local = {schemaInfo: data}; + if (options) for (var opt in options) local[opt] = options[opt]; + return CodeMirror.hint.xml(cm, local); + } + CodeMirror.registerHelper("hint", "html", htmlHint); +}); diff --git a/public/vendor/plugins/codemirror/addon/hint/javascript-hint.js b/public/vendor/plugins/codemirror/addon/hint/javascript-hint.js new file mode 100644 index 0000000000000..96a7fe01c2495 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/hint/javascript-hint.js @@ -0,0 +1,157 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + var Pos = CodeMirror.Pos; + + function forEach(arr, f) { + for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); + } + + function arrayContains(arr, item) { + if (!Array.prototype.indexOf) { + var i = arr.length; + while (i--) { + if (arr[i] === item) { + return true; + } + } + return false; + } + return arr.indexOf(item) != -1; + } + + function scriptHint(editor, keywords, getToken, options) { + // Find the token at the cursor + var cur = editor.getCursor(), token = getToken(editor, cur); + if (/\b(?:string|comment)\b/.test(token.type)) return; + var innerMode = CodeMirror.innerMode(editor.getMode(), token.state); + if (innerMode.mode.helperType === "json") return; + token.state = innerMode.state; + + // If it's not a 'word-style' token, ignore the token. + if (!/^[\w$_]*$/.test(token.string)) { + token = {start: cur.ch, end: cur.ch, string: "", state: token.state, + type: token.string == "." ? "property" : null}; + } else if (token.end > cur.ch) { + token.end = cur.ch; + token.string = token.string.slice(0, cur.ch - token.start); + } + + var tprop = token; + // If it is a property, find out what it is a property of. + while (tprop.type == "property") { + tprop = getToken(editor, Pos(cur.line, tprop.start)); + if (tprop.string != ".") return; + tprop = getToken(editor, Pos(cur.line, tprop.start)); + if (!context) var context = []; + context.push(tprop); + } + return {list: getCompletions(token, context, keywords, options), + from: Pos(cur.line, token.start), + to: Pos(cur.line, token.end)}; + } + + function javascriptHint(editor, options) { + return scriptHint(editor, javascriptKeywords, + function (e, cur) {return e.getTokenAt(cur);}, + options); + }; + CodeMirror.registerHelper("hint", "javascript", javascriptHint); + + function getCoffeeScriptToken(editor, cur) { + // This getToken, it is for coffeescript, imitates the behavior of + // getTokenAt method in javascript.js, that is, returning "property" + // type and treat "." as indepenent token. + var token = editor.getTokenAt(cur); + if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') { + token.end = token.start; + token.string = '.'; + token.type = "property"; + } + else if (/^\.[\w$_]*$/.test(token.string)) { + token.type = "property"; + token.start++; + token.string = token.string.replace(/\./, ''); + } + return token; + } + + function coffeescriptHint(editor, options) { + return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options); + } + CodeMirror.registerHelper("hint", "coffeescript", coffeescriptHint); + + var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " + + "toUpperCase toLowerCase split concat match replace search").split(" "); + var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " + + "lastIndexOf every some filter forEach map reduce reduceRight ").split(" "); + var funcProps = "prototype apply call bind".split(" "); + var javascriptKeywords = ("break case catch class const continue debugger default delete do else export extends false finally for function " + + "if in import instanceof new null return super switch this throw true try typeof var void while with yield").split(" "); + var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " + + "if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" "); + + function forAllProps(obj, callback) { + if (!Object.getOwnPropertyNames || !Object.getPrototypeOf) { + for (var name in obj) callback(name) + } else { + for (var o = obj; o; o = Object.getPrototypeOf(o)) + Object.getOwnPropertyNames(o).forEach(callback) + } + } + + function getCompletions(token, context, keywords, options) { + var found = [], start = token.string, global = options && options.globalScope || window; + function maybeAdd(str) { + if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str); + } + function gatherCompletions(obj) { + if (typeof obj == "string") forEach(stringProps, maybeAdd); + else if (obj instanceof Array) forEach(arrayProps, maybeAdd); + else if (obj instanceof Function) forEach(funcProps, maybeAdd); + forAllProps(obj, maybeAdd) + } + + if (context && context.length) { + // If this is a property, see if it belongs to some object we can + // find in the current environment. + var obj = context.pop(), base; + if (obj.type && obj.type.indexOf("variable") === 0) { + if (options && options.additionalContext) + base = options.additionalContext[obj.string]; + if (!options || options.useGlobalScope !== false) + base = base || global[obj.string]; + } else if (obj.type == "string") { + base = ""; + } else if (obj.type == "atom") { + base = 1; + } else if (obj.type == "function") { + if (global.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') && + (typeof global.jQuery == 'function')) + base = global.jQuery(); + else if (global._ != null && (obj.string == '_') && (typeof global._ == 'function')) + base = global._(); + } + while (base != null && context.length) + base = base[context.pop().string]; + if (base != null) gatherCompletions(base); + } else { + // If not, just look in the global object and any local scope + // (reading into JS mode internals to get at the local and global variables) + for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name); + for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name); + if (!options || options.useGlobalScope !== false) + gatherCompletions(global); + forEach(keywords, maybeAdd); + } + return found; + } +}); diff --git a/public/vendor/plugins/codemirror/addon/hint/show-hint.css b/public/vendor/plugins/codemirror/addon/hint/show-hint.css new file mode 100644 index 0000000000000..5617ccca2bdf3 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/hint/show-hint.css @@ -0,0 +1,36 @@ +.CodeMirror-hints { + position: absolute; + z-index: 10; + overflow: hidden; + list-style: none; + + margin: 0; + padding: 2px; + + -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + box-shadow: 2px 3px 5px rgba(0,0,0,.2); + border-radius: 3px; + border: 1px solid silver; + + background: white; + font-size: 90%; + font-family: monospace; + + max-height: 20em; + overflow-y: auto; +} + +.CodeMirror-hint { + margin: 0; + padding: 0 4px; + border-radius: 2px; + white-space: pre; + color: black; + cursor: pointer; +} + +li.CodeMirror-hint-active { + background: #08f; + color: white; +} diff --git a/public/vendor/plugins/codemirror/addon/hint/show-hint.js b/public/vendor/plugins/codemirror/addon/hint/show-hint.js new file mode 100644 index 0000000000000..d70b2ab17344f --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/hint/show-hint.js @@ -0,0 +1,460 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var HINT_ELEMENT_CLASS = "CodeMirror-hint"; + var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active"; + + // This is the old interface, kept around for now to stay + // backwards-compatible. + CodeMirror.showHint = function(cm, getHints, options) { + if (!getHints) return cm.showHint(options); + if (options && options.async) getHints.async = true; + var newOpts = {hint: getHints}; + if (options) for (var prop in options) newOpts[prop] = options[prop]; + return cm.showHint(newOpts); + }; + + CodeMirror.defineExtension("showHint", function(options) { + options = parseOptions(this, this.getCursor("start"), options); + var selections = this.listSelections() + if (selections.length > 1) return; + // By default, don't allow completion when something is selected. + // A hint function can have a `supportsSelection` property to + // indicate that it can handle selections. + if (this.somethingSelected()) { + if (!options.hint.supportsSelection) return; + // Don't try with cross-line selections + for (var i = 0; i < selections.length; i++) + if (selections[i].head.line != selections[i].anchor.line) return; + } + + if (this.state.completionActive) this.state.completionActive.close(); + var completion = this.state.completionActive = new Completion(this, options); + if (!completion.options.hint) return; + + CodeMirror.signal(this, "startCompletion", this); + completion.update(true); + }); + + CodeMirror.defineExtension("closeHint", function() { + if (this.state.completionActive) this.state.completionActive.close() + }) + + function Completion(cm, options) { + this.cm = cm; + this.options = options; + this.widget = null; + this.debounce = 0; + this.tick = 0; + this.startPos = this.cm.getCursor("start"); + this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length; + + var self = this; + cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); }); + } + + var requestAnimationFrame = window.requestAnimationFrame || function(fn) { + return setTimeout(fn, 1000/60); + }; + var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout; + + Completion.prototype = { + close: function() { + if (!this.active()) return; + this.cm.state.completionActive = null; + this.tick = null; + this.cm.off("cursorActivity", this.activityFunc); + + if (this.widget && this.data) CodeMirror.signal(this.data, "close"); + if (this.widget) this.widget.close(); + CodeMirror.signal(this.cm, "endCompletion", this.cm); + }, + + active: function() { + return this.cm.state.completionActive == this; + }, + + pick: function(data, i) { + var completion = data.list[i]; + if (completion.hint) completion.hint(this.cm, data, completion); + else this.cm.replaceRange(getText(completion), completion.from || data.from, + completion.to || data.to, "complete"); + CodeMirror.signal(data, "pick", completion); + this.close(); + }, + + cursorActivity: function() { + if (this.debounce) { + cancelAnimationFrame(this.debounce); + this.debounce = 0; + } + + var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line); + if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch || + pos.ch < this.startPos.ch || this.cm.somethingSelected() || + (!pos.ch || this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) { + this.close(); + } else { + var self = this; + this.debounce = requestAnimationFrame(function() {self.update();}); + if (this.widget) this.widget.disable(); + } + }, + + update: function(first) { + if (this.tick == null) return + var self = this, myTick = ++this.tick + fetchHints(this.options.hint, this.cm, this.options, function(data) { + if (self.tick == myTick) self.finishUpdate(data, first) + }) + }, + + finishUpdate: function(data, first) { + if (this.data) CodeMirror.signal(this.data, "update"); + + var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle); + if (this.widget) this.widget.close(); + + this.data = data; + + if (data && data.list.length) { + if (picked && data.list.length == 1) { + this.pick(data, 0); + } else { + this.widget = new Widget(this, data); + CodeMirror.signal(data, "shown"); + } + } + } + }; + + function parseOptions(cm, pos, options) { + var editor = cm.options.hintOptions; + var out = {}; + for (var prop in defaultOptions) out[prop] = defaultOptions[prop]; + if (editor) for (var prop in editor) + if (editor[prop] !== undefined) out[prop] = editor[prop]; + if (options) for (var prop in options) + if (options[prop] !== undefined) out[prop] = options[prop]; + if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos) + return out; + } + + function getText(completion) { + if (typeof completion == "string") return completion; + else return completion.text; + } + + function buildKeyMap(completion, handle) { + var baseMap = { + Up: function() {handle.moveFocus(-1);}, + Down: function() {handle.moveFocus(1);}, + PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);}, + PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);}, + Home: function() {handle.setFocus(0);}, + End: function() {handle.setFocus(handle.length - 1);}, + Enter: handle.pick, + Tab: handle.pick, + Esc: handle.close + }; + + var mac = /Mac/.test(navigator.platform); + + if (mac) { + baseMap["Ctrl-P"] = function() {handle.moveFocus(-1);}; + baseMap["Ctrl-N"] = function() {handle.moveFocus(1);}; + } + + var custom = completion.options.customKeys; + var ourMap = custom ? {} : baseMap; + function addBinding(key, val) { + var bound; + if (typeof val != "string") + bound = function(cm) { return val(cm, handle); }; + // This mechanism is deprecated + else if (baseMap.hasOwnProperty(val)) + bound = baseMap[val]; + else + bound = val; + ourMap[key] = bound; + } + if (custom) + for (var key in custom) if (custom.hasOwnProperty(key)) + addBinding(key, custom[key]); + var extra = completion.options.extraKeys; + if (extra) + for (var key in extra) if (extra.hasOwnProperty(key)) + addBinding(key, extra[key]); + return ourMap; + } + + function getHintElement(hintsElement, el) { + while (el && el != hintsElement) { + if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el; + el = el.parentNode; + } + } + + function Widget(completion, data) { + this.completion = completion; + this.data = data; + this.picked = false; + var widget = this, cm = completion.cm; + var ownerDocument = cm.getInputField().ownerDocument; + var parentWindow = ownerDocument.defaultView || ownerDocument.parentWindow; + + var hints = this.hints = ownerDocument.createElement("ul"); + var theme = completion.cm.options.theme; + hints.className = "CodeMirror-hints " + theme; + this.selectedHint = data.selectedHint || 0; + + var completions = data.list; + for (var i = 0; i < completions.length; ++i) { + var elt = hints.appendChild(ownerDocument.createElement("li")), cur = completions[i]; + var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS); + if (cur.className != null) className = cur.className + " " + className; + elt.className = className; + if (cur.render) cur.render(elt, data, cur); + else elt.appendChild(ownerDocument.createTextNode(cur.displayText || getText(cur))); + elt.hintId = i; + } + + var container = completion.options.container || ownerDocument.body; + var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null); + var left = pos.left, top = pos.bottom, below = true; + var offsetLeft = 0, offsetTop = 0; + if (container !== ownerDocument.body) { + // We offset the cursor position because left and top are relative to the offsetParent's top left corner. + var isContainerPositioned = ['absolute', 'relative', 'fixed'].indexOf(parentWindow.getComputedStyle(container).position) !== -1; + var offsetParent = isContainerPositioned ? container : container.offsetParent; + var offsetParentPosition = offsetParent.getBoundingClientRect(); + var bodyPosition = ownerDocument.body.getBoundingClientRect(); + offsetLeft = (offsetParentPosition.left - bodyPosition.left - offsetParent.scrollLeft); + offsetTop = (offsetParentPosition.top - bodyPosition.top - offsetParent.scrollTop); + } + hints.style.left = (left - offsetLeft) + "px"; + hints.style.top = (top - offsetTop) + "px"; + + // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. + var winW = parentWindow.innerWidth || Math.max(ownerDocument.body.offsetWidth, ownerDocument.documentElement.offsetWidth); + var winH = parentWindow.innerHeight || Math.max(ownerDocument.body.offsetHeight, ownerDocument.documentElement.offsetHeight); + container.appendChild(hints); + var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH; + var scrolls = hints.scrollHeight > hints.clientHeight + 1 + var startScroll = cm.getScrollInfo(); + + if (overlapY > 0) { + var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top); + if (curTop - height > 0) { // Fits above cursor + hints.style.top = (top = pos.top - height - offsetTop) + "px"; + below = false; + } else if (height > winH) { + hints.style.height = (winH - 5) + "px"; + hints.style.top = (top = pos.bottom - box.top - offsetTop) + "px"; + var cursor = cm.getCursor(); + if (data.from.ch != cursor.ch) { + pos = cm.cursorCoords(cursor); + hints.style.left = (left = pos.left - offsetLeft) + "px"; + box = hints.getBoundingClientRect(); + } + } + } + var overlapX = box.right - winW; + if (overlapX > 0) { + if (box.right - box.left > winW) { + hints.style.width = (winW - 5) + "px"; + overlapX -= (box.right - box.left) - winW; + } + hints.style.left = (left = pos.left - overlapX - offsetLeft) + "px"; + } + if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling) + node.style.paddingRight = cm.display.nativeBarWidth + "px" + + cm.addKeyMap(this.keyMap = buildKeyMap(completion, { + moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); }, + setFocus: function(n) { widget.changeActive(n); }, + menuSize: function() { return widget.screenAmount(); }, + length: completions.length, + close: function() { completion.close(); }, + pick: function() { widget.pick(); }, + data: data + })); + + if (completion.options.closeOnUnfocus) { + var closingOnBlur; + cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); }); + cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); }); + } + + cm.on("scroll", this.onScroll = function() { + var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect(); + var newTop = top + startScroll.top - curScroll.top; + var point = newTop - (parentWindow.pageYOffset || (ownerDocument.documentElement || ownerDocument.body).scrollTop); + if (!below) point += hints.offsetHeight; + if (point <= editor.top || point >= editor.bottom) return completion.close(); + hints.style.top = newTop + "px"; + hints.style.left = (left + startScroll.left - curScroll.left) + "px"; + }); + + CodeMirror.on(hints, "dblclick", function(e) { + var t = getHintElement(hints, e.target || e.srcElement); + if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();} + }); + + CodeMirror.on(hints, "click", function(e) { + var t = getHintElement(hints, e.target || e.srcElement); + if (t && t.hintId != null) { + widget.changeActive(t.hintId); + if (completion.options.completeOnSingleClick) widget.pick(); + } + }); + + CodeMirror.on(hints, "mousedown", function() { + setTimeout(function(){cm.focus();}, 20); + }); + + CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]); + return true; + } + + Widget.prototype = { + close: function() { + if (this.completion.widget != this) return; + this.completion.widget = null; + this.hints.parentNode.removeChild(this.hints); + this.completion.cm.removeKeyMap(this.keyMap); + + var cm = this.completion.cm; + if (this.completion.options.closeOnUnfocus) { + cm.off("blur", this.onBlur); + cm.off("focus", this.onFocus); + } + cm.off("scroll", this.onScroll); + }, + + disable: function() { + this.completion.cm.removeKeyMap(this.keyMap); + var widget = this; + this.keyMap = {Enter: function() { widget.picked = true; }}; + this.completion.cm.addKeyMap(this.keyMap); + }, + + pick: function() { + this.completion.pick(this.data, this.selectedHint); + }, + + changeActive: function(i, avoidWrap) { + if (i >= this.data.list.length) + i = avoidWrap ? this.data.list.length - 1 : 0; + else if (i < 0) + i = avoidWrap ? 0 : this.data.list.length - 1; + if (this.selectedHint == i) return; + var node = this.hints.childNodes[this.selectedHint]; + if (node) node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, ""); + node = this.hints.childNodes[this.selectedHint = i]; + node.className += " " + ACTIVE_HINT_ELEMENT_CLASS; + if (node.offsetTop < this.hints.scrollTop) + this.hints.scrollTop = node.offsetTop - 3; + else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) + this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3; + CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node); + }, + + screenAmount: function() { + return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1; + } + }; + + function applicableHelpers(cm, helpers) { + if (!cm.somethingSelected()) return helpers + var result = [] + for (var i = 0; i < helpers.length; i++) + if (helpers[i].supportsSelection) result.push(helpers[i]) + return result + } + + function fetchHints(hint, cm, options, callback) { + if (hint.async) { + hint(cm, callback, options) + } else { + var result = hint(cm, options) + if (result && result.then) result.then(callback) + else callback(result) + } + } + + function resolveAutoHints(cm, pos) { + var helpers = cm.getHelpers(pos, "hint"), words + if (helpers.length) { + var resolved = function(cm, callback, options) { + var app = applicableHelpers(cm, helpers); + function run(i) { + if (i == app.length) return callback(null) + fetchHints(app[i], cm, options, function(result) { + if (result && result.list.length > 0) callback(result) + else run(i + 1) + }) + } + run(0) + } + resolved.async = true + resolved.supportsSelection = true + return resolved + } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) { + return function(cm) { return CodeMirror.hint.fromList(cm, {words: words}) } + } else if (CodeMirror.hint.anyword) { + return function(cm, options) { return CodeMirror.hint.anyword(cm, options) } + } else { + return function() {} + } + } + + CodeMirror.registerHelper("hint", "auto", { + resolve: resolveAutoHints + }); + + CodeMirror.registerHelper("hint", "fromList", function(cm, options) { + var cur = cm.getCursor(), token = cm.getTokenAt(cur) + var term, from = CodeMirror.Pos(cur.line, token.start), to = cur + if (token.start < cur.ch && /\w/.test(token.string.charAt(cur.ch - token.start - 1))) { + term = token.string.substr(0, cur.ch - token.start) + } else { + term = "" + from = cur + } + var found = []; + for (var i = 0; i < options.words.length; i++) { + var word = options.words[i]; + if (word.slice(0, term.length) == term) + found.push(word); + } + + if (found.length) return {list: found, from: from, to: to}; + }); + + CodeMirror.commands.autocomplete = CodeMirror.showHint; + + var defaultOptions = { + hint: CodeMirror.hint.auto, + completeSingle: true, + alignWithWord: true, + closeCharacters: /[\s()\[\]{};:>,]/, + closeOnUnfocus: true, + completeOnSingleClick: true, + container: null, + customKeys: null, + extraKeys: null + }; + + CodeMirror.defineOption("hintOptions", null); +}); diff --git a/public/vendor/plugins/codemirror/addon/hint/sql-hint.js b/public/vendor/plugins/codemirror/addon/hint/sql-hint.js new file mode 100644 index 0000000000000..444eba8b15142 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/hint/sql-hint.js @@ -0,0 +1,304 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../../mode/sql/sql")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../../mode/sql/sql"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var tables; + var defaultTable; + var keywords; + var identifierQuote; + var CONS = { + QUERY_DIV: ";", + ALIAS_KEYWORD: "AS" + }; + var Pos = CodeMirror.Pos, cmpPos = CodeMirror.cmpPos; + + function isArray(val) { return Object.prototype.toString.call(val) == "[object Array]" } + + function getKeywords(editor) { + var mode = editor.doc.modeOption; + if (mode === "sql") mode = "text/x-sql"; + return CodeMirror.resolveMode(mode).keywords; + } + + function getIdentifierQuote(editor) { + var mode = editor.doc.modeOption; + if (mode === "sql") mode = "text/x-sql"; + return CodeMirror.resolveMode(mode).identifierQuote || "`"; + } + + function getText(item) { + return typeof item == "string" ? item : item.text; + } + + function wrapTable(name, value) { + if (isArray(value)) value = {columns: value} + if (!value.text) value.text = name + return value + } + + function parseTables(input) { + var result = {} + if (isArray(input)) { + for (var i = input.length - 1; i >= 0; i--) { + var item = input[i] + result[getText(item).toUpperCase()] = wrapTable(getText(item), item) + } + } else if (input) { + for (var name in input) + result[name.toUpperCase()] = wrapTable(name, input[name]) + } + return result + } + + function getTable(name) { + return tables[name.toUpperCase()] + } + + function shallowClone(object) { + var result = {}; + for (var key in object) if (object.hasOwnProperty(key)) + result[key] = object[key]; + return result; + } + + function match(string, word) { + var len = string.length; + var sub = getText(word).substr(0, len); + return string.toUpperCase() === sub.toUpperCase(); + } + + function addMatches(result, search, wordlist, formatter) { + if (isArray(wordlist)) { + for (var i = 0; i < wordlist.length; i++) + if (match(search, wordlist[i])) result.push(formatter(wordlist[i])) + } else { + for (var word in wordlist) if (wordlist.hasOwnProperty(word)) { + var val = wordlist[word] + if (!val || val === true) + val = word + else + val = val.displayText ? {text: val.text, displayText: val.displayText} : val.text + if (match(search, val)) result.push(formatter(val)) + } + } + } + + function cleanName(name) { + // Get rid name from identifierQuote and preceding dot(.) + if (name.charAt(0) == ".") { + name = name.substr(1); + } + // replace doublicated identifierQuotes with single identifierQuotes + // and remove single identifierQuotes + var nameParts = name.split(identifierQuote+identifierQuote); + for (var i = 0; i < nameParts.length; i++) + nameParts[i] = nameParts[i].replace(new RegExp(identifierQuote,"g"), ""); + return nameParts.join(identifierQuote); + } + + function insertIdentifierQuotes(name) { + var nameParts = getText(name).split("."); + for (var i = 0; i < nameParts.length; i++) + nameParts[i] = identifierQuote + + // doublicate identifierQuotes + nameParts[i].replace(new RegExp(identifierQuote,"g"), identifierQuote+identifierQuote) + + identifierQuote; + var escaped = nameParts.join("."); + if (typeof name == "string") return escaped; + name = shallowClone(name); + name.text = escaped; + return name; + } + + function nameCompletion(cur, token, result, editor) { + // Try to complete table, column names and return start position of completion + var useIdentifierQuotes = false; + var nameParts = []; + var start = token.start; + var cont = true; + while (cont) { + cont = (token.string.charAt(0) == "."); + useIdentifierQuotes = useIdentifierQuotes || (token.string.charAt(0) == identifierQuote); + + start = token.start; + nameParts.unshift(cleanName(token.string)); + + token = editor.getTokenAt(Pos(cur.line, token.start)); + if (token.string == ".") { + cont = true; + token = editor.getTokenAt(Pos(cur.line, token.start)); + } + } + + // Try to complete table names + var string = nameParts.join("."); + addMatches(result, string, tables, function(w) { + return useIdentifierQuotes ? insertIdentifierQuotes(w) : w; + }); + + // Try to complete columns from defaultTable + addMatches(result, string, defaultTable, function(w) { + return useIdentifierQuotes ? insertIdentifierQuotes(w) : w; + }); + + // Try to complete columns + string = nameParts.pop(); + var table = nameParts.join("."); + + var alias = false; + var aliasTable = table; + // Check if table is available. If not, find table by Alias + if (!getTable(table)) { + var oldTable = table; + table = findTableByAlias(table, editor); + if (table !== oldTable) alias = true; + } + + var columns = getTable(table); + if (columns && columns.columns) + columns = columns.columns; + + if (columns) { + addMatches(result, string, columns, function(w) { + var tableInsert = table; + if (alias == true) tableInsert = aliasTable; + if (typeof w == "string") { + w = tableInsert + "." + w; + } else { + w = shallowClone(w); + w.text = tableInsert + "." + w.text; + } + return useIdentifierQuotes ? insertIdentifierQuotes(w) : w; + }); + } + + return start; + } + + function eachWord(lineText, f) { + var words = lineText.split(/\s+/) + for (var i = 0; i < words.length; i++) + if (words[i]) f(words[i].replace(/[,;]/g, '')) + } + + function findTableByAlias(alias, editor) { + var doc = editor.doc; + var fullQuery = doc.getValue(); + var aliasUpperCase = alias.toUpperCase(); + var previousWord = ""; + var table = ""; + var separator = []; + var validRange = { + start: Pos(0, 0), + end: Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).length) + }; + + //add separator + var indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV); + while(indexOfSeparator != -1) { + separator.push(doc.posFromIndex(indexOfSeparator)); + indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV, indexOfSeparator+1); + } + separator.unshift(Pos(0, 0)); + separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length)); + + //find valid range + var prevItem = null; + var current = editor.getCursor() + for (var i = 0; i < separator.length; i++) { + if ((prevItem == null || cmpPos(current, prevItem) > 0) && cmpPos(current, separator[i]) <= 0) { + validRange = {start: prevItem, end: separator[i]}; + break; + } + prevItem = separator[i]; + } + + if (validRange.start) { + var query = doc.getRange(validRange.start, validRange.end, false); + + for (var i = 0; i < query.length; i++) { + var lineText = query[i]; + eachWord(lineText, function(word) { + var wordUpperCase = word.toUpperCase(); + if (wordUpperCase === aliasUpperCase && getTable(previousWord)) + table = previousWord; + if (wordUpperCase !== CONS.ALIAS_KEYWORD) + previousWord = word; + }); + if (table) break; + } + } + return table; + } + + CodeMirror.registerHelper("hint", "sql", function(editor, options) { + tables = parseTables(options && options.tables) + var defaultTableName = options && options.defaultTable; + var disableKeywords = options && options.disableKeywords; + defaultTable = defaultTableName && getTable(defaultTableName); + keywords = getKeywords(editor); + identifierQuote = getIdentifierQuote(editor); + + if (defaultTableName && !defaultTable) + defaultTable = findTableByAlias(defaultTableName, editor); + + defaultTable = defaultTable || []; + + if (defaultTable.columns) + defaultTable = defaultTable.columns; + + var cur = editor.getCursor(); + var result = []; + var token = editor.getTokenAt(cur), start, end, search; + if (token.end > cur.ch) { + token.end = cur.ch; + token.string = token.string.slice(0, cur.ch - token.start); + } + + if (token.string.match(/^[.`"\w@]\w*$/)) { + search = token.string; + start = token.start; + end = token.end; + } else { + start = end = cur.ch; + search = ""; + } + if (search.charAt(0) == "." || search.charAt(0) == identifierQuote) { + start = nameCompletion(cur, token, result, editor); + } else { + var objectOrClass = function(w, className) { + if (typeof w === "object") { + w.className = className; + } else { + w = { text: w, className: className }; + } + return w; + }; + addMatches(result, search, defaultTable, function(w) { + return objectOrClass(w, "CodeMirror-hint-table CodeMirror-hint-default-table"); + }); + addMatches( + result, + search, + tables, function(w) { + return objectOrClass(w, "CodeMirror-hint-table"); + } + ); + if (!disableKeywords) + addMatches(result, search, keywords, function(w) { + return objectOrClass(w.toUpperCase(), "CodeMirror-hint-keyword"); + }); + } + + return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)}; + }); +}); diff --git a/public/vendor/plugins/codemirror/addon/hint/xml-hint.js b/public/vendor/plugins/codemirror/addon/hint/xml-hint.js new file mode 100644 index 0000000000000..7575b3707e1b0 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/hint/xml-hint.js @@ -0,0 +1,123 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var Pos = CodeMirror.Pos; + + function matches(hint, typed, matchInMiddle) { + if (matchInMiddle) return hint.indexOf(typed) >= 0; + else return hint.lastIndexOf(typed, 0) == 0; + } + + function getHints(cm, options) { + var tags = options && options.schemaInfo; + var quote = (options && options.quoteChar) || '"'; + var matchInMiddle = options && options.matchInMiddle; + if (!tags) return; + var cur = cm.getCursor(), token = cm.getTokenAt(cur); + if (token.end > cur.ch) { + token.end = cur.ch; + token.string = token.string.slice(0, cur.ch - token.start); + } + var inner = CodeMirror.innerMode(cm.getMode(), token.state); + if (!inner.mode.xmlCurrentTag) return + var result = [], replaceToken = false, prefix; + var tag = /\btag\b/.test(token.type) && !/>$/.test(token.string); + var tagName = tag && /^\w/.test(token.string), tagStart; + + if (tagName) { + var before = cm.getLine(cur.line).slice(Math.max(0, token.start - 2), token.start); + var tagType = /<\/$/.test(before) ? "close" : /<$/.test(before) ? "open" : null; + if (tagType) tagStart = token.start - (tagType == "close" ? 2 : 1); + } else if (tag && token.string == "<") { + tagType = "open"; + } else if (tag && token.string == ""); + } else { + // Attribute completion + var curTag = tagInfo && tags[tagInfo.name], attrs = curTag && curTag.attrs; + var globalAttrs = tags["!attrs"]; + if (!attrs && !globalAttrs) return; + if (!attrs) { + attrs = globalAttrs; + } else if (globalAttrs) { // Combine tag-local and global attributes + var set = {}; + for (var nm in globalAttrs) if (globalAttrs.hasOwnProperty(nm)) set[nm] = globalAttrs[nm]; + for (var nm in attrs) if (attrs.hasOwnProperty(nm)) set[nm] = attrs[nm]; + attrs = set; + } + if (token.type == "string" || token.string == "=") { // A value + var before = cm.getRange(Pos(cur.line, Math.max(0, cur.ch - 60)), + Pos(cur.line, token.type == "string" ? token.start : token.end)); + var atName = before.match(/([^\s\u00a0=<>\"\']+)=$/), atValues; + if (!atName || !attrs.hasOwnProperty(atName[1]) || !(atValues = attrs[atName[1]])) return; + if (typeof atValues == 'function') atValues = atValues.call(this, cm); // Functions can be used to supply values for autocomplete widget + if (token.type == "string") { + prefix = token.string; + var n = 0; + if (/['"]/.test(token.string.charAt(0))) { + quote = token.string.charAt(0); + prefix = token.string.slice(1); + n++; + } + var len = token.string.length; + if (/['"]/.test(token.string.charAt(len - 1))) { + quote = token.string.charAt(len - 1); + prefix = token.string.substr(n, len - 2); + } + if (n) { // an opening quote + var line = cm.getLine(cur.line); + if (line.length > token.end && line.charAt(token.end) == quote) token.end++; // include a closing quote + } + replaceToken = true; + } + for (var i = 0; i < atValues.length; ++i) if (!prefix || matches(atValues[i], prefix, matchInMiddle)) + result.push(quote + atValues[i] + quote); + } else { // An attribute name + if (token.type == "attribute") { + prefix = token.string; + replaceToken = true; + } + for (var attr in attrs) if (attrs.hasOwnProperty(attr) && (!prefix || matches(attr, prefix, matchInMiddle))) + result.push(attr); + } + } + return { + list: result, + from: replaceToken ? Pos(cur.line, tagStart == null ? token.start : tagStart) : cur, + to: replaceToken ? Pos(cur.line, token.end) : cur + }; + } + + CodeMirror.registerHelper("hint", "xml", getHints); +}); diff --git a/public/vendor/plugins/codemirror/addon/lint/coffeescript-lint.js b/public/vendor/plugins/codemirror/addon/lint/coffeescript-lint.js new file mode 100644 index 0000000000000..a54c7035160d1 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/lint/coffeescript-lint.js @@ -0,0 +1,47 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// Depends on coffeelint.js from http://www.coffeelint.org/js/coffeelint.js + +// declare global: coffeelint + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("lint", "coffeescript", function(text) { + var found = []; + if (!window.coffeelint) { + if (window.console) { + window.console.error("Error: window.coffeelint not defined, CodeMirror CoffeeScript linting cannot run."); + } + return found; + } + var parseError = function(err) { + var loc = err.lineNumber; + found.push({from: CodeMirror.Pos(loc-1, 0), + to: CodeMirror.Pos(loc, 0), + severity: err.level, + message: err.message}); + }; + try { + var res = coffeelint.lint(text); + for(var i = 0; i < res.length; i++) { + parseError(res[i]); + } + } catch(e) { + found.push({from: CodeMirror.Pos(e.location.first_line, 0), + to: CodeMirror.Pos(e.location.last_line, e.location.last_column), + severity: 'error', + message: e.message}); + } + return found; +}); + +}); diff --git a/public/vendor/plugins/codemirror/addon/lint/css-lint.js b/public/vendor/plugins/codemirror/addon/lint/css-lint.js new file mode 100644 index 0000000000000..6058a73eb134e --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/lint/css-lint.js @@ -0,0 +1,40 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// Depends on csslint.js from https://github.com/stubbornella/csslint + +// declare global: CSSLint + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("lint", "css", function(text, options) { + var found = []; + if (!window.CSSLint) { + if (window.console) { + window.console.error("Error: window.CSSLint not defined, CodeMirror CSS linting cannot run."); + } + return found; + } + var results = CSSLint.verify(text, options), messages = results.messages, message = null; + for ( var i = 0; i < messages.length; i++) { + message = messages[i]; + var startLine = message.line -1, endLine = message.line -1, startCol = message.col -1, endCol = message.col; + found.push({ + from: CodeMirror.Pos(startLine, startCol), + to: CodeMirror.Pos(endLine, endCol), + message: message.message, + severity : message.type + }); + } + return found; +}); + +}); diff --git a/public/vendor/plugins/codemirror/addon/lint/html-lint.js b/public/vendor/plugins/codemirror/addon/lint/html-lint.js new file mode 100644 index 0000000000000..5295c33331085 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/lint/html-lint.js @@ -0,0 +1,59 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// Depends on htmlhint.js from http://htmlhint.com/js/htmlhint.js + +// declare global: HTMLHint + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("htmlhint")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "htmlhint"], mod); + else // Plain browser env + mod(CodeMirror, window.HTMLHint); +})(function(CodeMirror, HTMLHint) { + "use strict"; + + var defaultRules = { + "tagname-lowercase": true, + "attr-lowercase": true, + "attr-value-double-quotes": true, + "doctype-first": false, + "tag-pair": true, + "spec-char-escape": true, + "id-unique": true, + "src-not-empty": true, + "attr-no-duplication": true + }; + + CodeMirror.registerHelper("lint", "html", function(text, options) { + var found = []; + if (HTMLHint && !HTMLHint.verify) { + if(typeof HTMLHint.default !== 'undefined') { + HTMLHint = HTMLHint.default; + } else { + HTMLHint = HTMLHint.HTMLHint; + } + } + if (!HTMLHint) HTMLHint = window.HTMLHint; + if (!HTMLHint) { + if (window.console) { + window.console.error("Error: HTMLHint not found, not defined on window, or not available through define/require, CodeMirror HTML linting cannot run."); + } + return found; + } + var messages = HTMLHint.verify(text, options && options.rules || defaultRules); + for (var i = 0; i < messages.length; i++) { + var message = messages[i]; + var startLine = message.line - 1, endLine = message.line - 1, startCol = message.col - 1, endCol = message.col; + found.push({ + from: CodeMirror.Pos(startLine, startCol), + to: CodeMirror.Pos(endLine, endCol), + message: message.message, + severity : message.type + }); + } + return found; + }); +}); diff --git a/public/vendor/plugins/codemirror/addon/lint/javascript-lint.js b/public/vendor/plugins/codemirror/addon/lint/javascript-lint.js new file mode 100644 index 0000000000000..cc132d7f8250d --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/lint/javascript-lint.js @@ -0,0 +1,63 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + // declare global: JSHINT + + function validator(text, options) { + if (!window.JSHINT) { + if (window.console) { + window.console.error("Error: window.JSHINT not defined, CodeMirror JavaScript linting cannot run."); + } + return []; + } + if (!options.indent) // JSHint error.character actually is a column index, this fixes underlining on lines using tabs for indentation + options.indent = 1; // JSHint default value is 4 + JSHINT(text, options, options.globals); + var errors = JSHINT.data().errors, result = []; + if (errors) parseErrors(errors, result); + return result; + } + + CodeMirror.registerHelper("lint", "javascript", validator); + + function parseErrors(errors, output) { + for ( var i = 0; i < errors.length; i++) { + var error = errors[i]; + if (error) { + if (error.line <= 0) { + if (window.console) { + window.console.warn("Cannot display JSHint error (invalid line " + error.line + ")", error); + } + continue; + } + + var start = error.character - 1, end = start + 1; + if (error.evidence) { + var index = error.evidence.substring(start).search(/.\b/); + if (index > -1) { + end += index; + } + } + + // Convert to format expected by validation service + var hint = { + message: error.reason, + severity: error.code ? (error.code.startsWith('W') ? "warning" : "error") : "error", + from: CodeMirror.Pos(error.line - 1, start), + to: CodeMirror.Pos(error.line - 1, end) + }; + + output.push(hint); + } + } + } +}); diff --git a/public/vendor/plugins/codemirror/addon/lint/json-lint.js b/public/vendor/plugins/codemirror/addon/lint/json-lint.js new file mode 100644 index 0000000000000..ac1d6ec28c825 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/lint/json-lint.js @@ -0,0 +1,40 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// Depends on jsonlint.js from https://github.com/zaach/jsonlint + +// declare global: jsonlint + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("lint", "json", function(text) { + var found = []; + if (!window.jsonlint) { + if (window.console) { + window.console.error("Error: window.jsonlint not defined, CodeMirror JSON linting cannot run."); + } + return found; + } + // for jsonlint's web dist jsonlint is exported as an object with a single property parser, of which parseError + // is a subproperty + var jsonlint = window.jsonlint.parser || window.jsonlint + jsonlint.parseError = function(str, hash) { + var loc = hash.loc; + found.push({from: CodeMirror.Pos(loc.first_line - 1, loc.first_column), + to: CodeMirror.Pos(loc.last_line - 1, loc.last_column), + message: str}); + }; + try { jsonlint.parse(text); } + catch(e) {} + return found; +}); + +}); diff --git a/public/vendor/plugins/codemirror/addon/lint/lint.css b/public/vendor/plugins/codemirror/addon/lint/lint.css new file mode 100644 index 0000000000000..f097cfe345a57 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/lint/lint.css @@ -0,0 +1,73 @@ +/* The lint marker gutter */ +.CodeMirror-lint-markers { + width: 16px; +} + +.CodeMirror-lint-tooltip { + background-color: #ffd; + border: 1px solid black; + border-radius: 4px 4px 4px 4px; + color: black; + font-family: monospace; + font-size: 10pt; + overflow: hidden; + padding: 2px 5px; + position: fixed; + white-space: pre; + white-space: pre-wrap; + z-index: 100; + max-width: 600px; + opacity: 0; + transition: opacity .4s; + -moz-transition: opacity .4s; + -webkit-transition: opacity .4s; + -o-transition: opacity .4s; + -ms-transition: opacity .4s; +} + +.CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning { + background-position: left bottom; + background-repeat: repeat-x; +} + +.CodeMirror-lint-mark-error { + background-image: + url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==") + ; +} + +.CodeMirror-lint-mark-warning { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII="); +} + +.CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning { + background-position: center center; + background-repeat: no-repeat; + cursor: pointer; + display: inline-block; + height: 16px; + width: 16px; + vertical-align: middle; + position: relative; +} + +.CodeMirror-lint-message-error, .CodeMirror-lint-message-warning { + padding-left: 18px; + background-position: top left; + background-repeat: no-repeat; +} + +.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII="); +} + +.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII="); +} + +.CodeMirror-lint-marker-multiple { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC"); + background-repeat: no-repeat; + background-position: right bottom; + width: 100%; height: 100%; +} diff --git a/public/vendor/plugins/codemirror/addon/lint/lint.js b/public/vendor/plugins/codemirror/addon/lint/lint.js new file mode 100644 index 0000000000000..aa75ba0e8aac6 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/lint/lint.js @@ -0,0 +1,252 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + var GUTTER_ID = "CodeMirror-lint-markers"; + + function showTooltip(e, content) { + var tt = document.createElement("div"); + tt.className = "CodeMirror-lint-tooltip"; + tt.appendChild(content.cloneNode(true)); + document.body.appendChild(tt); + + function position(e) { + if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position); + tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px"; + tt.style.left = (e.clientX + 5) + "px"; + } + CodeMirror.on(document, "mousemove", position); + position(e); + if (tt.style.opacity != null) tt.style.opacity = 1; + return tt; + } + function rm(elt) { + if (elt.parentNode) elt.parentNode.removeChild(elt); + } + function hideTooltip(tt) { + if (!tt.parentNode) return; + if (tt.style.opacity == null) rm(tt); + tt.style.opacity = 0; + setTimeout(function() { rm(tt); }, 600); + } + + function showTooltipFor(e, content, node) { + var tooltip = showTooltip(e, content); + function hide() { + CodeMirror.off(node, "mouseout", hide); + if (tooltip) { hideTooltip(tooltip); tooltip = null; } + } + var poll = setInterval(function() { + if (tooltip) for (var n = node;; n = n.parentNode) { + if (n && n.nodeType == 11) n = n.host; + if (n == document.body) return; + if (!n) { hide(); break; } + } + if (!tooltip) return clearInterval(poll); + }, 400); + CodeMirror.on(node, "mouseout", hide); + } + + function LintState(cm, options, hasGutter) { + this.marked = []; + this.options = options; + this.timeout = null; + this.hasGutter = hasGutter; + this.onMouseOver = function(e) { onMouseOver(cm, e); }; + this.waitingFor = 0 + } + + function parseOptions(_cm, options) { + if (options instanceof Function) return {getAnnotations: options}; + if (!options || options === true) options = {}; + return options; + } + + function clearMarks(cm) { + var state = cm.state.lint; + if (state.hasGutter) cm.clearGutter(GUTTER_ID); + for (var i = 0; i < state.marked.length; ++i) + state.marked[i].clear(); + state.marked.length = 0; + } + + function makeMarker(labels, severity, multiple, tooltips) { + var marker = document.createElement("div"), inner = marker; + marker.className = "CodeMirror-lint-marker-" + severity; + if (multiple) { + inner = marker.appendChild(document.createElement("div")); + inner.className = "CodeMirror-lint-marker-multiple"; + } + + if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) { + showTooltipFor(e, labels, inner); + }); + + return marker; + } + + function getMaxSeverity(a, b) { + if (a == "error") return a; + else return b; + } + + function groupByLine(annotations) { + var lines = []; + for (var i = 0; i < annotations.length; ++i) { + var ann = annotations[i], line = ann.from.line; + (lines[line] || (lines[line] = [])).push(ann); + } + return lines; + } + + function annotationTooltip(ann) { + var severity = ann.severity; + if (!severity) severity = "error"; + var tip = document.createElement("div"); + tip.className = "CodeMirror-lint-message-" + severity; + if (typeof ann.messageHTML != 'undefined') { + tip.innerHTML = ann.messageHTML; + } else { + tip.appendChild(document.createTextNode(ann.message)); + } + return tip; + } + + function lintAsync(cm, getAnnotations, passOptions) { + var state = cm.state.lint + var id = ++state.waitingFor + function abort() { + id = -1 + cm.off("change", abort) + } + cm.on("change", abort) + getAnnotations(cm.getValue(), function(annotations, arg2) { + cm.off("change", abort) + if (state.waitingFor != id) return + if (arg2 && annotations instanceof CodeMirror) annotations = arg2 + cm.operation(function() {updateLinting(cm, annotations)}) + }, passOptions, cm); + } + + function startLinting(cm) { + var state = cm.state.lint, options = state.options; + /* + * Passing rules in `options` property prevents JSHint (and other linters) from complaining + * about unrecognized rules like `onUpdateLinting`, `delay`, `lintOnChange`, etc. + */ + var passOptions = options.options || options; + var getAnnotations = options.getAnnotations || cm.getHelper(CodeMirror.Pos(0, 0), "lint"); + if (!getAnnotations) return; + if (options.async || getAnnotations.async) { + lintAsync(cm, getAnnotations, passOptions) + } else { + var annotations = getAnnotations(cm.getValue(), passOptions, cm); + if (!annotations) return; + if (annotations.then) annotations.then(function(issues) { + cm.operation(function() {updateLinting(cm, issues)}) + }); + else cm.operation(function() {updateLinting(cm, annotations)}) + } + } + + function updateLinting(cm, annotationsNotSorted) { + clearMarks(cm); + var state = cm.state.lint, options = state.options; + + var annotations = groupByLine(annotationsNotSorted); + + for (var line = 0; line < annotations.length; ++line) { + var anns = annotations[line]; + if (!anns) continue; + + var maxSeverity = null; + var tipLabel = state.hasGutter && document.createDocumentFragment(); + + for (var i = 0; i < anns.length; ++i) { + var ann = anns[i]; + var severity = ann.severity; + if (!severity) severity = "error"; + maxSeverity = getMaxSeverity(maxSeverity, severity); + + if (options.formatAnnotation) ann = options.formatAnnotation(ann); + if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann)); + + if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, { + className: "CodeMirror-lint-mark-" + severity, + __annotation: ann + })); + } + + if (state.hasGutter) + cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1, + state.options.tooltips)); + } + if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm); + } + + function onChange(cm) { + var state = cm.state.lint; + if (!state) return; + clearTimeout(state.timeout); + state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500); + } + + function popupTooltips(annotations, e) { + var target = e.target || e.srcElement; + var tooltip = document.createDocumentFragment(); + for (var i = 0; i < annotations.length; i++) { + var ann = annotations[i]; + tooltip.appendChild(annotationTooltip(ann)); + } + showTooltipFor(e, tooltip, target); + } + + function onMouseOver(cm, e) { + var target = e.target || e.srcElement; + if (!/\bCodeMirror-lint-mark-/.test(target.className)) return; + var box = target.getBoundingClientRect(), x = (box.left + box.right) / 2, y = (box.top + box.bottom) / 2; + var spans = cm.findMarksAt(cm.coordsChar({left: x, top: y}, "client")); + + var annotations = []; + for (var i = 0; i < spans.length; ++i) { + var ann = spans[i].__annotation; + if (ann) annotations.push(ann); + } + if (annotations.length) popupTooltips(annotations, e); + } + + CodeMirror.defineOption("lint", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + clearMarks(cm); + if (cm.state.lint.options.lintOnChange !== false) + cm.off("change", onChange); + CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver); + clearTimeout(cm.state.lint.timeout); + delete cm.state.lint; + } + + if (val) { + var gutters = cm.getOption("gutters"), hasLintGutter = false; + for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true; + var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter); + if (state.options.lintOnChange !== false) + cm.on("change", onChange); + if (state.options.tooltips != false && state.options.tooltips != "gutter") + CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver); + + startLinting(cm); + } + }); + + CodeMirror.defineExtension("performLint", function() { + if (this.state.lint) startLinting(this); + }); +}); diff --git a/public/vendor/plugins/codemirror/addon/lint/yaml-lint.js b/public/vendor/plugins/codemirror/addon/lint/yaml-lint.js new file mode 100644 index 0000000000000..b4ac5abc4ec27 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/lint/yaml-lint.js @@ -0,0 +1,41 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +// Depends on js-yaml.js from https://github.com/nodeca/js-yaml + +// declare global: jsyaml + +CodeMirror.registerHelper("lint", "yaml", function(text) { + var found = []; + if (!window.jsyaml) { + if (window.console) { + window.console.error("Error: window.jsyaml not defined, CodeMirror YAML linting cannot run."); + } + return found; + } + try { jsyaml.loadAll(text); } + catch(e) { + var loc = e.mark, + // js-yaml YAMLException doesn't always provide an accurate lineno + // e.g., when there are multiple yaml docs + // --- + // --- + // foo:bar + from = loc ? CodeMirror.Pos(loc.line, loc.column) : CodeMirror.Pos(0, 0), + to = from; + found.push({ from: from, to: to, message: e.message }); + } + return found; +}); + +}); diff --git a/public/vendor/plugins/codemirror/addon/merge/merge.css b/public/vendor/plugins/codemirror/addon/merge/merge.css new file mode 100644 index 0000000000000..dadd7f59c788f --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/merge/merge.css @@ -0,0 +1,119 @@ +.CodeMirror-merge { + position: relative; + border: 1px solid #ddd; + white-space: pre; +} + +.CodeMirror-merge, .CodeMirror-merge .CodeMirror { + height: 350px; +} + +.CodeMirror-merge-2pane .CodeMirror-merge-pane { width: 47%; } +.CodeMirror-merge-2pane .CodeMirror-merge-gap { width: 6%; } +.CodeMirror-merge-3pane .CodeMirror-merge-pane { width: 31%; } +.CodeMirror-merge-3pane .CodeMirror-merge-gap { width: 3.5%; } + +.CodeMirror-merge-pane { + display: inline-block; + white-space: normal; + vertical-align: top; +} +.CodeMirror-merge-pane-rightmost { + position: absolute; + right: 0px; + z-index: 1; +} + +.CodeMirror-merge-gap { + z-index: 2; + display: inline-block; + height: 100%; + -moz-box-sizing: border-box; + box-sizing: border-box; + overflow: hidden; + border-left: 1px solid #ddd; + border-right: 1px solid #ddd; + position: relative; + background: #f8f8f8; +} + +.CodeMirror-merge-scrolllock-wrap { + position: absolute; + bottom: 0; left: 50%; +} +.CodeMirror-merge-scrolllock { + position: relative; + left: -50%; + cursor: pointer; + color: #555; + line-height: 1; +} +.CodeMirror-merge-scrolllock:after { + content: "\21db\00a0\00a0\21da"; +} +.CodeMirror-merge-scrolllock.CodeMirror-merge-scrolllock-enabled:after { + content: "\21db\21da"; +} + +.CodeMirror-merge-copybuttons-left, .CodeMirror-merge-copybuttons-right { + position: absolute; + left: 0; top: 0; + right: 0; bottom: 0; + line-height: 1; +} + +.CodeMirror-merge-copy { + position: absolute; + cursor: pointer; + color: #44c; + z-index: 3; +} + +.CodeMirror-merge-copy-reverse { + position: absolute; + cursor: pointer; + color: #44c; +} + +.CodeMirror-merge-copybuttons-left .CodeMirror-merge-copy { left: 2px; } +.CodeMirror-merge-copybuttons-right .CodeMirror-merge-copy { right: 2px; } + +.CodeMirror-merge-r-inserted, .CodeMirror-merge-l-inserted { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12MwuCXy3+CWyH8GBgYGJgYkAABZbAQ9ELXurwAAAABJRU5ErkJggg==); + background-position: bottom left; + background-repeat: repeat-x; +} + +.CodeMirror-merge-r-deleted, .CodeMirror-merge-l-deleted { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12M4Kyb2/6yY2H8GBgYGJgYkAABURgPz6Ks7wQAAAABJRU5ErkJggg==); + background-position: bottom left; + background-repeat: repeat-x; +} + +.CodeMirror-merge-r-chunk { background: #ffffe0; } +.CodeMirror-merge-r-chunk-start { border-top: 1px solid #ee8; } +.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #ee8; } +.CodeMirror-merge-r-connect { fill: #ffffe0; stroke: #ee8; stroke-width: 1px; } + +.CodeMirror-merge-l-chunk { background: #eef; } +.CodeMirror-merge-l-chunk-start { border-top: 1px solid #88e; } +.CodeMirror-merge-l-chunk-end { border-bottom: 1px solid #88e; } +.CodeMirror-merge-l-connect { fill: #eef; stroke: #88e; stroke-width: 1px; } + +.CodeMirror-merge-l-chunk.CodeMirror-merge-r-chunk { background: #dfd; } +.CodeMirror-merge-l-chunk-start.CodeMirror-merge-r-chunk-start { border-top: 1px solid #4e4; } +.CodeMirror-merge-l-chunk-end.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #4e4; } + +.CodeMirror-merge-collapsed-widget:before { + content: "(...)"; +} +.CodeMirror-merge-collapsed-widget { + cursor: pointer; + color: #88b; + background: #eef; + border: 1px solid #ddf; + font-size: 90%; + padding: 0 3px; + border-radius: 4px; +} +.CodeMirror-merge-collapsed-line .CodeMirror-gutter-elt { display: none; } diff --git a/public/vendor/plugins/codemirror/addon/merge/merge.js b/public/vendor/plugins/codemirror/addon/merge/merge.js new file mode 100644 index 0000000000000..8296540a05c3d --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/merge/merge.js @@ -0,0 +1,1002 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// declare global: diff_match_patch, DIFF_INSERT, DIFF_DELETE, DIFF_EQUAL + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); // Note non-packaged dependency diff_match_patch + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "diff_match_patch"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + var Pos = CodeMirror.Pos; + var svgNS = "http://www.w3.org/2000/svg"; + + function DiffView(mv, type) { + this.mv = mv; + this.type = type; + this.classes = type == "left" + ? {chunk: "CodeMirror-merge-l-chunk", + start: "CodeMirror-merge-l-chunk-start", + end: "CodeMirror-merge-l-chunk-end", + insert: "CodeMirror-merge-l-inserted", + del: "CodeMirror-merge-l-deleted", + connect: "CodeMirror-merge-l-connect"} + : {chunk: "CodeMirror-merge-r-chunk", + start: "CodeMirror-merge-r-chunk-start", + end: "CodeMirror-merge-r-chunk-end", + insert: "CodeMirror-merge-r-inserted", + del: "CodeMirror-merge-r-deleted", + connect: "CodeMirror-merge-r-connect"}; + } + + DiffView.prototype = { + constructor: DiffView, + init: function(pane, orig, options) { + this.edit = this.mv.edit; + ;(this.edit.state.diffViews || (this.edit.state.diffViews = [])).push(this); + this.orig = CodeMirror(pane, copyObj({value: orig, readOnly: !this.mv.options.allowEditingOriginals}, copyObj(options))); + if (this.mv.options.connect == "align") { + if (!this.edit.state.trackAlignable) this.edit.state.trackAlignable = new TrackAlignable(this.edit) + this.orig.state.trackAlignable = new TrackAlignable(this.orig) + } + this.lockButton.title = this.edit.phrase("Toggle locked scrolling"); + + this.orig.state.diffViews = [this]; + var classLocation = options.chunkClassLocation || "background"; + if (Object.prototype.toString.call(classLocation) != "[object Array]") classLocation = [classLocation] + this.classes.classLocation = classLocation + + this.diff = getDiff(asString(orig), asString(options.value), this.mv.options.ignoreWhitespace); + this.chunks = getChunks(this.diff); + this.diffOutOfDate = this.dealigned = false; + this.needsScrollSync = null + + this.showDifferences = options.showDifferences !== false; + }, + registerEvents: function(otherDv) { + this.forceUpdate = registerUpdate(this); + setScrollLock(this, true, false); + registerScroll(this, otherDv); + }, + setShowDifferences: function(val) { + val = val !== false; + if (val != this.showDifferences) { + this.showDifferences = val; + this.forceUpdate("full"); + } + } + }; + + function ensureDiff(dv) { + if (dv.diffOutOfDate) { + dv.diff = getDiff(dv.orig.getValue(), dv.edit.getValue(), dv.mv.options.ignoreWhitespace); + dv.chunks = getChunks(dv.diff); + dv.diffOutOfDate = false; + CodeMirror.signal(dv.edit, "updateDiff", dv.diff); + } + } + + var updating = false; + function registerUpdate(dv) { + var edit = {from: 0, to: 0, marked: []}; + var orig = {from: 0, to: 0, marked: []}; + var debounceChange, updatingFast = false; + function update(mode) { + updating = true; + updatingFast = false; + if (mode == "full") { + if (dv.svg) clear(dv.svg); + if (dv.copyButtons) clear(dv.copyButtons); + clearMarks(dv.edit, edit.marked, dv.classes); + clearMarks(dv.orig, orig.marked, dv.classes); + edit.from = edit.to = orig.from = orig.to = 0; + } + ensureDiff(dv); + if (dv.showDifferences) { + updateMarks(dv.edit, dv.diff, edit, DIFF_INSERT, dv.classes); + updateMarks(dv.orig, dv.diff, orig, DIFF_DELETE, dv.classes); + } + + if (dv.mv.options.connect == "align") + alignChunks(dv); + makeConnections(dv); + if (dv.needsScrollSync != null) syncScroll(dv, dv.needsScrollSync) + + updating = false; + } + function setDealign(fast) { + if (updating) return; + dv.dealigned = true; + set(fast); + } + function set(fast) { + if (updating || updatingFast) return; + clearTimeout(debounceChange); + if (fast === true) updatingFast = true; + debounceChange = setTimeout(update, fast === true ? 20 : 250); + } + function change(_cm, change) { + if (!dv.diffOutOfDate) { + dv.diffOutOfDate = true; + edit.from = edit.to = orig.from = orig.to = 0; + } + // Update faster when a line was added/removed + setDealign(change.text.length - 1 != change.to.line - change.from.line); + } + function swapDoc() { + dv.diffOutOfDate = true; + dv.dealigned = true; + update("full"); + } + dv.edit.on("change", change); + dv.orig.on("change", change); + dv.edit.on("swapDoc", swapDoc); + dv.orig.on("swapDoc", swapDoc); + if (dv.mv.options.connect == "align") { + CodeMirror.on(dv.edit.state.trackAlignable, "realign", setDealign) + CodeMirror.on(dv.orig.state.trackAlignable, "realign", setDealign) + } + dv.edit.on("viewportChange", function() { set(false); }); + dv.orig.on("viewportChange", function() { set(false); }); + update(); + return update; + } + + function registerScroll(dv, otherDv) { + dv.edit.on("scroll", function() { + syncScroll(dv, true) && makeConnections(dv); + }); + dv.orig.on("scroll", function() { + syncScroll(dv, false) && makeConnections(dv); + if (otherDv) syncScroll(otherDv, true) && makeConnections(otherDv); + }); + } + + function syncScroll(dv, toOrig) { + // Change handler will do a refresh after a timeout when diff is out of date + if (dv.diffOutOfDate) { + if (dv.lockScroll && dv.needsScrollSync == null) dv.needsScrollSync = toOrig + return false + } + dv.needsScrollSync = null + if (!dv.lockScroll) return true; + var editor, other, now = +new Date; + if (toOrig) { editor = dv.edit; other = dv.orig; } + else { editor = dv.orig; other = dv.edit; } + // Don't take action if the position of this editor was recently set + // (to prevent feedback loops) + if (editor.state.scrollSetBy == dv && (editor.state.scrollSetAt || 0) + 250 > now) return false; + + var sInfo = editor.getScrollInfo(); + if (dv.mv.options.connect == "align") { + targetPos = sInfo.top; + } else { + var halfScreen = .5 * sInfo.clientHeight, midY = sInfo.top + halfScreen; + var mid = editor.lineAtHeight(midY, "local"); + var around = chunkBoundariesAround(dv.chunks, mid, toOrig); + var off = getOffsets(editor, toOrig ? around.edit : around.orig); + var offOther = getOffsets(other, toOrig ? around.orig : around.edit); + var ratio = (midY - off.top) / (off.bot - off.top); + var targetPos = (offOther.top - halfScreen) + ratio * (offOther.bot - offOther.top); + + var botDist, mix; + // Some careful tweaking to make sure no space is left out of view + // when scrolling to top or bottom. + if (targetPos > sInfo.top && (mix = sInfo.top / halfScreen) < 1) { + targetPos = targetPos * mix + sInfo.top * (1 - mix); + } else if ((botDist = sInfo.height - sInfo.clientHeight - sInfo.top) < halfScreen) { + var otherInfo = other.getScrollInfo(); + var botDistOther = otherInfo.height - otherInfo.clientHeight - targetPos; + if (botDistOther > botDist && (mix = botDist / halfScreen) < 1) + targetPos = targetPos * mix + (otherInfo.height - otherInfo.clientHeight - botDist) * (1 - mix); + } + } + + other.scrollTo(sInfo.left, targetPos); + other.state.scrollSetAt = now; + other.state.scrollSetBy = dv; + return true; + } + + function getOffsets(editor, around) { + var bot = around.after; + if (bot == null) bot = editor.lastLine() + 1; + return {top: editor.heightAtLine(around.before || 0, "local"), + bot: editor.heightAtLine(bot, "local")}; + } + + function setScrollLock(dv, val, action) { + dv.lockScroll = val; + if (val && action != false) syncScroll(dv, DIFF_INSERT) && makeConnections(dv); + (val ? CodeMirror.addClass : CodeMirror.rmClass)(dv.lockButton, "CodeMirror-merge-scrolllock-enabled"); + } + + // Updating the marks for editor content + + function removeClass(editor, line, classes) { + var locs = classes.classLocation + for (var i = 0; i < locs.length; i++) { + editor.removeLineClass(line, locs[i], classes.chunk); + editor.removeLineClass(line, locs[i], classes.start); + editor.removeLineClass(line, locs[i], classes.end); + } + } + + function clearMarks(editor, arr, classes) { + for (var i = 0; i < arr.length; ++i) { + var mark = arr[i]; + if (mark instanceof CodeMirror.TextMarker) + mark.clear(); + else if (mark.parent) + removeClass(editor, mark, classes); + } + arr.length = 0; + } + + // FIXME maybe add a margin around viewport to prevent too many updates + function updateMarks(editor, diff, state, type, classes) { + var vp = editor.getViewport(); + editor.operation(function() { + if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) { + clearMarks(editor, state.marked, classes); + markChanges(editor, diff, type, state.marked, vp.from, vp.to, classes); + state.from = vp.from; state.to = vp.to; + } else { + if (vp.from < state.from) { + markChanges(editor, diff, type, state.marked, vp.from, state.from, classes); + state.from = vp.from; + } + if (vp.to > state.to) { + markChanges(editor, diff, type, state.marked, state.to, vp.to, classes); + state.to = vp.to; + } + } + }); + } + + function addClass(editor, lineNr, classes, main, start, end) { + var locs = classes.classLocation, line = editor.getLineHandle(lineNr); + for (var i = 0; i < locs.length; i++) { + if (main) editor.addLineClass(line, locs[i], classes.chunk); + if (start) editor.addLineClass(line, locs[i], classes.start); + if (end) editor.addLineClass(line, locs[i], classes.end); + } + return line; + } + + function markChanges(editor, diff, type, marks, from, to, classes) { + var pos = Pos(0, 0); + var top = Pos(from, 0), bot = editor.clipPos(Pos(to - 1)); + var cls = type == DIFF_DELETE ? classes.del : classes.insert; + function markChunk(start, end) { + var bfrom = Math.max(from, start), bto = Math.min(to, end); + for (var i = bfrom; i < bto; ++i) + marks.push(addClass(editor, i, classes, true, i == start, i == end - 1)); + // When the chunk is empty, make sure a horizontal line shows up + if (start == end && bfrom == end && bto == end) { + if (bfrom) + marks.push(addClass(editor, bfrom - 1, classes, false, false, true)); + else + marks.push(addClass(editor, bfrom, classes, false, true, false)); + } + } + + var chunkStart = 0, pending = false; + for (var i = 0; i < diff.length; ++i) { + var part = diff[i], tp = part[0], str = part[1]; + if (tp == DIFF_EQUAL) { + var cleanFrom = pos.line + (startOfLineClean(diff, i) ? 0 : 1); + moveOver(pos, str); + var cleanTo = pos.line + (endOfLineClean(diff, i) ? 1 : 0); + if (cleanTo > cleanFrom) { + if (pending) { markChunk(chunkStart, cleanFrom); pending = false } + chunkStart = cleanTo; + } + } else { + pending = true + if (tp == type) { + var end = moveOver(pos, str, true); + var a = posMax(top, pos), b = posMin(bot, end); + if (!posEq(a, b)) + marks.push(editor.markText(a, b, {className: cls})); + pos = end; + } + } + } + if (pending) markChunk(chunkStart, pos.line + 1); + } + + // Updating the gap between editor and original + + function makeConnections(dv) { + if (!dv.showDifferences) return; + + if (dv.svg) { + clear(dv.svg); + var w = dv.gap.offsetWidth; + attrs(dv.svg, "width", w, "height", dv.gap.offsetHeight); + } + if (dv.copyButtons) clear(dv.copyButtons); + + var vpEdit = dv.edit.getViewport(), vpOrig = dv.orig.getViewport(); + var outerTop = dv.mv.wrap.getBoundingClientRect().top + var sTopEdit = outerTop - dv.edit.getScrollerElement().getBoundingClientRect().top + dv.edit.getScrollInfo().top + var sTopOrig = outerTop - dv.orig.getScrollerElement().getBoundingClientRect().top + dv.orig.getScrollInfo().top; + for (var i = 0; i < dv.chunks.length; i++) { + var ch = dv.chunks[i]; + if (ch.editFrom <= vpEdit.to && ch.editTo >= vpEdit.from && + ch.origFrom <= vpOrig.to && ch.origTo >= vpOrig.from) + drawConnectorsForChunk(dv, ch, sTopOrig, sTopEdit, w); + } + } + + function getMatchingOrigLine(editLine, chunks) { + var editStart = 0, origStart = 0; + for (var i = 0; i < chunks.length; i++) { + var chunk = chunks[i]; + if (chunk.editTo > editLine && chunk.editFrom <= editLine) return null; + if (chunk.editFrom > editLine) break; + editStart = chunk.editTo; + origStart = chunk.origTo; + } + return origStart + (editLine - editStart); + } + + // Combines information about chunks and widgets/markers to return + // an array of lines, in a single editor, that probably need to be + // aligned with their counterparts in the editor next to it. + function alignableFor(cm, chunks, isOrig) { + var tracker = cm.state.trackAlignable + var start = cm.firstLine(), trackI = 0 + var result = [] + for (var i = 0;; i++) { + var chunk = chunks[i] + var chunkStart = !chunk ? 1e9 : isOrig ? chunk.origFrom : chunk.editFrom + for (; trackI < tracker.alignable.length; trackI += 2) { + var n = tracker.alignable[trackI] + 1 + if (n <= start) continue + if (n <= chunkStart) result.push(n) + else break + } + if (!chunk) break + result.push(start = isOrig ? chunk.origTo : chunk.editTo) + } + return result + } + + // Given information about alignable lines in two editors, fill in + // the result (an array of three-element arrays) to reflect the + // lines that need to be aligned with each other. + function mergeAlignable(result, origAlignable, chunks, setIndex) { + var rI = 0, origI = 0, chunkI = 0, diff = 0 + outer: for (;; rI++) { + var nextR = result[rI], nextO = origAlignable[origI] + if (!nextR && nextO == null) break + + var rLine = nextR ? nextR[0] : 1e9, oLine = nextO == null ? 1e9 : nextO + while (chunkI < chunks.length) { + var chunk = chunks[chunkI] + if (chunk.origFrom <= oLine && chunk.origTo > oLine) { + origI++ + rI-- + continue outer; + } + if (chunk.editTo > rLine) { + if (chunk.editFrom <= rLine) continue outer; + break + } + diff += (chunk.origTo - chunk.origFrom) - (chunk.editTo - chunk.editFrom) + chunkI++ + } + if (rLine == oLine - diff) { + nextR[setIndex] = oLine + origI++ + } else if (rLine < oLine - diff) { + nextR[setIndex] = rLine + diff + } else { + var record = [oLine - diff, null, null] + record[setIndex] = oLine + result.splice(rI, 0, record) + origI++ + } + } + } + + function findAlignedLines(dv, other) { + var alignable = alignableFor(dv.edit, dv.chunks, false), result = [] + if (other) for (var i = 0, j = 0; i < other.chunks.length; i++) { + var n = other.chunks[i].editTo + while (j < alignable.length && alignable[j] < n) j++ + if (j == alignable.length || alignable[j] != n) alignable.splice(j++, 0, n) + } + for (var i = 0; i < alignable.length; i++) + result.push([alignable[i], null, null]) + + mergeAlignable(result, alignableFor(dv.orig, dv.chunks, true), dv.chunks, 1) + if (other) + mergeAlignable(result, alignableFor(other.orig, other.chunks, true), other.chunks, 2) + + return result + } + + function alignChunks(dv, force) { + if (!dv.dealigned && !force) return; + if (!dv.orig.curOp) return dv.orig.operation(function() { + alignChunks(dv, force); + }); + + dv.dealigned = false; + var other = dv.mv.left == dv ? dv.mv.right : dv.mv.left; + if (other) { + ensureDiff(other); + other.dealigned = false; + } + var linesToAlign = findAlignedLines(dv, other); + + // Clear old aligners + var aligners = dv.mv.aligners; + for (var i = 0; i < aligners.length; i++) + aligners[i].clear(); + aligners.length = 0; + + var cm = [dv.edit, dv.orig], scroll = []; + if (other) cm.push(other.orig); + for (var i = 0; i < cm.length; i++) + scroll.push(cm[i].getScrollInfo().top); + + for (var ln = 0; ln < linesToAlign.length; ln++) + alignLines(cm, linesToAlign[ln], aligners); + + for (var i = 0; i < cm.length; i++) + cm[i].scrollTo(null, scroll[i]); + } + + function alignLines(cm, lines, aligners) { + var maxOffset = 0, offset = []; + for (var i = 0; i < cm.length; i++) if (lines[i] != null) { + var off = cm[i].heightAtLine(lines[i], "local"); + offset[i] = off; + maxOffset = Math.max(maxOffset, off); + } + for (var i = 0; i < cm.length; i++) if (lines[i] != null) { + var diff = maxOffset - offset[i]; + if (diff > 1) + aligners.push(padAbove(cm[i], lines[i], diff)); + } + } + + function padAbove(cm, line, size) { + var above = true; + if (line > cm.lastLine()) { + line--; + above = false; + } + var elt = document.createElement("div"); + elt.className = "CodeMirror-merge-spacer"; + elt.style.height = size + "px"; elt.style.minWidth = "1px"; + return cm.addLineWidget(line, elt, {height: size, above: above, mergeSpacer: true, handleMouseEvents: true}); + } + + function drawConnectorsForChunk(dv, chunk, sTopOrig, sTopEdit, w) { + var flip = dv.type == "left"; + var top = dv.orig.heightAtLine(chunk.origFrom, "local", true) - sTopOrig; + if (dv.svg) { + var topLpx = top; + var topRpx = dv.edit.heightAtLine(chunk.editFrom, "local", true) - sTopEdit; + if (flip) { var tmp = topLpx; topLpx = topRpx; topRpx = tmp; } + var botLpx = dv.orig.heightAtLine(chunk.origTo, "local", true) - sTopOrig; + var botRpx = dv.edit.heightAtLine(chunk.editTo, "local", true) - sTopEdit; + if (flip) { var tmp = botLpx; botLpx = botRpx; botRpx = tmp; } + var curveTop = " C " + w/2 + " " + topRpx + " " + w/2 + " " + topLpx + " " + (w + 2) + " " + topLpx; + var curveBot = " C " + w/2 + " " + botLpx + " " + w/2 + " " + botRpx + " -1 " + botRpx; + attrs(dv.svg.appendChild(document.createElementNS(svgNS, "path")), + "d", "M -1 " + topRpx + curveTop + " L " + (w + 2) + " " + botLpx + curveBot + " z", + "class", dv.classes.connect); + } + if (dv.copyButtons) { + var copy = dv.copyButtons.appendChild(elt("div", dv.type == "left" ? "\u21dd" : "\u21dc", + "CodeMirror-merge-copy")); + var editOriginals = dv.mv.options.allowEditingOriginals; + copy.title = dv.edit.phrase(editOriginals ? "Push to left" : "Revert chunk"); + copy.chunk = chunk; + copy.style.top = (chunk.origTo > chunk.origFrom ? top : dv.edit.heightAtLine(chunk.editFrom, "local") - sTopEdit) + "px"; + + if (editOriginals) { + var topReverse = dv.edit.heightAtLine(chunk.editFrom, "local") - sTopEdit; + var copyReverse = dv.copyButtons.appendChild(elt("div", dv.type == "right" ? "\u21dd" : "\u21dc", + "CodeMirror-merge-copy-reverse")); + copyReverse.title = "Push to right"; + copyReverse.chunk = {editFrom: chunk.origFrom, editTo: chunk.origTo, + origFrom: chunk.editFrom, origTo: chunk.editTo}; + copyReverse.style.top = topReverse + "px"; + dv.type == "right" ? copyReverse.style.left = "2px" : copyReverse.style.right = "2px"; + } + } + } + + function copyChunk(dv, to, from, chunk) { + if (dv.diffOutOfDate) return; + var origStart = chunk.origTo > from.lastLine() ? Pos(chunk.origFrom - 1) : Pos(chunk.origFrom, 0) + var origEnd = Pos(chunk.origTo, 0) + var editStart = chunk.editTo > to.lastLine() ? Pos(chunk.editFrom - 1) : Pos(chunk.editFrom, 0) + var editEnd = Pos(chunk.editTo, 0) + var handler = dv.mv.options.revertChunk + if (handler) + handler(dv.mv, from, origStart, origEnd, to, editStart, editEnd) + else + to.replaceRange(from.getRange(origStart, origEnd), editStart, editEnd) + } + + // Merge view, containing 0, 1, or 2 diff views. + + var MergeView = CodeMirror.MergeView = function(node, options) { + if (!(this instanceof MergeView)) return new MergeView(node, options); + + this.options = options; + var origLeft = options.origLeft, origRight = options.origRight == null ? options.orig : options.origRight; + + var hasLeft = origLeft != null, hasRight = origRight != null; + var panes = 1 + (hasLeft ? 1 : 0) + (hasRight ? 1 : 0); + var wrap = [], left = this.left = null, right = this.right = null; + var self = this; + + if (hasLeft) { + left = this.left = new DiffView(this, "left"); + var leftPane = elt("div", null, "CodeMirror-merge-pane CodeMirror-merge-left"); + wrap.push(leftPane); + wrap.push(buildGap(left)); + } + + var editPane = elt("div", null, "CodeMirror-merge-pane CodeMirror-merge-editor"); + wrap.push(editPane); + + if (hasRight) { + right = this.right = new DiffView(this, "right"); + wrap.push(buildGap(right)); + var rightPane = elt("div", null, "CodeMirror-merge-pane CodeMirror-merge-right"); + wrap.push(rightPane); + } + + (hasRight ? rightPane : editPane).className += " CodeMirror-merge-pane-rightmost"; + + wrap.push(elt("div", null, null, "height: 0; clear: both;")); + + var wrapElt = this.wrap = node.appendChild(elt("div", wrap, "CodeMirror-merge CodeMirror-merge-" + panes + "pane")); + this.edit = CodeMirror(editPane, copyObj(options)); + + if (left) left.init(leftPane, origLeft, options); + if (right) right.init(rightPane, origRight, options); + if (options.collapseIdentical) + this.editor().operation(function() { + collapseIdenticalStretches(self, options.collapseIdentical); + }); + if (options.connect == "align") { + this.aligners = []; + alignChunks(this.left || this.right, true); + } + if (left) left.registerEvents(right) + if (right) right.registerEvents(left) + + + var onResize = function() { + if (left) makeConnections(left); + if (right) makeConnections(right); + }; + CodeMirror.on(window, "resize", onResize); + var resizeInterval = setInterval(function() { + for (var p = wrapElt.parentNode; p && p != document.body; p = p.parentNode) {} + if (!p) { clearInterval(resizeInterval); CodeMirror.off(window, "resize", onResize); } + }, 5000); + }; + + function buildGap(dv) { + var lock = dv.lockButton = elt("div", null, "CodeMirror-merge-scrolllock"); + var lockWrap = elt("div", [lock], "CodeMirror-merge-scrolllock-wrap"); + CodeMirror.on(lock, "click", function() { setScrollLock(dv, !dv.lockScroll); }); + var gapElts = [lockWrap]; + if (dv.mv.options.revertButtons !== false) { + dv.copyButtons = elt("div", null, "CodeMirror-merge-copybuttons-" + dv.type); + CodeMirror.on(dv.copyButtons, "click", function(e) { + var node = e.target || e.srcElement; + if (!node.chunk) return; + if (node.className == "CodeMirror-merge-copy-reverse") { + copyChunk(dv, dv.orig, dv.edit, node.chunk); + return; + } + copyChunk(dv, dv.edit, dv.orig, node.chunk); + }); + gapElts.unshift(dv.copyButtons); + } + if (dv.mv.options.connect != "align") { + var svg = document.createElementNS && document.createElementNS(svgNS, "svg"); + if (svg && !svg.createSVGRect) svg = null; + dv.svg = svg; + if (svg) gapElts.push(svg); + } + + return dv.gap = elt("div", gapElts, "CodeMirror-merge-gap"); + } + + MergeView.prototype = { + constructor: MergeView, + editor: function() { return this.edit; }, + rightOriginal: function() { return this.right && this.right.orig; }, + leftOriginal: function() { return this.left && this.left.orig; }, + setShowDifferences: function(val) { + if (this.right) this.right.setShowDifferences(val); + if (this.left) this.left.setShowDifferences(val); + }, + rightChunks: function() { + if (this.right) { ensureDiff(this.right); return this.right.chunks; } + }, + leftChunks: function() { + if (this.left) { ensureDiff(this.left); return this.left.chunks; } + } + }; + + function asString(obj) { + if (typeof obj == "string") return obj; + else return obj.getValue(); + } + + // Operations on diffs + var dmp; + function getDiff(a, b, ignoreWhitespace) { + if (!dmp) dmp = new diff_match_patch(); + + var diff = dmp.diff_main(a, b); + // The library sometimes leaves in empty parts, which confuse the algorithm + for (var i = 0; i < diff.length; ++i) { + var part = diff[i]; + if (ignoreWhitespace ? !/[^ \t]/.test(part[1]) : !part[1]) { + diff.splice(i--, 1); + } else if (i && diff[i - 1][0] == part[0]) { + diff.splice(i--, 1); + diff[i][1] += part[1]; + } + } + return diff; + } + + function getChunks(diff) { + var chunks = []; + if (!diff.length) return chunks; + var startEdit = 0, startOrig = 0; + var edit = Pos(0, 0), orig = Pos(0, 0); + for (var i = 0; i < diff.length; ++i) { + var part = diff[i], tp = part[0]; + if (tp == DIFF_EQUAL) { + var startOff = !startOfLineClean(diff, i) || edit.line < startEdit || orig.line < startOrig ? 1 : 0; + var cleanFromEdit = edit.line + startOff, cleanFromOrig = orig.line + startOff; + moveOver(edit, part[1], null, orig); + var endOff = endOfLineClean(diff, i) ? 1 : 0; + var cleanToEdit = edit.line + endOff, cleanToOrig = orig.line + endOff; + if (cleanToEdit > cleanFromEdit) { + if (i) chunks.push({origFrom: startOrig, origTo: cleanFromOrig, + editFrom: startEdit, editTo: cleanFromEdit}); + startEdit = cleanToEdit; startOrig = cleanToOrig; + } + } else { + moveOver(tp == DIFF_INSERT ? edit : orig, part[1]); + } + } + if (startEdit <= edit.line || startOrig <= orig.line) + chunks.push({origFrom: startOrig, origTo: orig.line + 1, + editFrom: startEdit, editTo: edit.line + 1}); + return chunks; + } + + function endOfLineClean(diff, i) { + if (i == diff.length - 1) return true; + var next = diff[i + 1][1]; + if ((next.length == 1 && i < diff.length - 2) || next.charCodeAt(0) != 10) return false; + if (i == diff.length - 2) return true; + next = diff[i + 2][1]; + return (next.length > 1 || i == diff.length - 3) && next.charCodeAt(0) == 10; + } + + function startOfLineClean(diff, i) { + if (i == 0) return true; + var last = diff[i - 1][1]; + if (last.charCodeAt(last.length - 1) != 10) return false; + if (i == 1) return true; + last = diff[i - 2][1]; + return last.charCodeAt(last.length - 1) == 10; + } + + function chunkBoundariesAround(chunks, n, nInEdit) { + var beforeE, afterE, beforeO, afterO; + for (var i = 0; i < chunks.length; i++) { + var chunk = chunks[i]; + var fromLocal = nInEdit ? chunk.editFrom : chunk.origFrom; + var toLocal = nInEdit ? chunk.editTo : chunk.origTo; + if (afterE == null) { + if (fromLocal > n) { afterE = chunk.editFrom; afterO = chunk.origFrom; } + else if (toLocal > n) { afterE = chunk.editTo; afterO = chunk.origTo; } + } + if (toLocal <= n) { beforeE = chunk.editTo; beforeO = chunk.origTo; } + else if (fromLocal <= n) { beforeE = chunk.editFrom; beforeO = chunk.origFrom; } + } + return {edit: {before: beforeE, after: afterE}, orig: {before: beforeO, after: afterO}}; + } + + function collapseSingle(cm, from, to) { + cm.addLineClass(from, "wrap", "CodeMirror-merge-collapsed-line"); + var widget = document.createElement("span"); + widget.className = "CodeMirror-merge-collapsed-widget"; + widget.title = cm.phrase("Identical text collapsed. Click to expand."); + var mark = cm.markText(Pos(from, 0), Pos(to - 1), { + inclusiveLeft: true, + inclusiveRight: true, + replacedWith: widget, + clearOnEnter: true + }); + function clear() { + mark.clear(); + cm.removeLineClass(from, "wrap", "CodeMirror-merge-collapsed-line"); + } + if (mark.explicitlyCleared) clear(); + CodeMirror.on(widget, "click", clear); + mark.on("clear", clear); + CodeMirror.on(widget, "click", clear); + return {mark: mark, clear: clear}; + } + + function collapseStretch(size, editors) { + var marks = []; + function clear() { + for (var i = 0; i < marks.length; i++) marks[i].clear(); + } + for (var i = 0; i < editors.length; i++) { + var editor = editors[i]; + var mark = collapseSingle(editor.cm, editor.line, editor.line + size); + marks.push(mark); + mark.mark.on("clear", clear); + } + return marks[0].mark; + } + + function unclearNearChunks(dv, margin, off, clear) { + for (var i = 0; i < dv.chunks.length; i++) { + var chunk = dv.chunks[i]; + for (var l = chunk.editFrom - margin; l < chunk.editTo + margin; l++) { + var pos = l + off; + if (pos >= 0 && pos < clear.length) clear[pos] = false; + } + } + } + + function collapseIdenticalStretches(mv, margin) { + if (typeof margin != "number") margin = 2; + var clear = [], edit = mv.editor(), off = edit.firstLine(); + for (var l = off, e = edit.lastLine(); l <= e; l++) clear.push(true); + if (mv.left) unclearNearChunks(mv.left, margin, off, clear); + if (mv.right) unclearNearChunks(mv.right, margin, off, clear); + + for (var i = 0; i < clear.length; i++) { + if (clear[i]) { + var line = i + off; + for (var size = 1; i < clear.length - 1 && clear[i + 1]; i++, size++) {} + if (size > margin) { + var editors = [{line: line, cm: edit}]; + if (mv.left) editors.push({line: getMatchingOrigLine(line, mv.left.chunks), cm: mv.left.orig}); + if (mv.right) editors.push({line: getMatchingOrigLine(line, mv.right.chunks), cm: mv.right.orig}); + var mark = collapseStretch(size, editors); + if (mv.options.onCollapse) mv.options.onCollapse(mv, line, size, mark); + } + } + } + } + + // General utilities + + function elt(tag, content, className, style) { + var e = document.createElement(tag); + if (className) e.className = className; + if (style) e.style.cssText = style; + if (typeof content == "string") e.appendChild(document.createTextNode(content)); + else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]); + return e; + } + + function clear(node) { + for (var count = node.childNodes.length; count > 0; --count) + node.removeChild(node.firstChild); + } + + function attrs(elt) { + for (var i = 1; i < arguments.length; i += 2) + elt.setAttribute(arguments[i], arguments[i+1]); + } + + function copyObj(obj, target) { + if (!target) target = {}; + for (var prop in obj) if (obj.hasOwnProperty(prop)) target[prop] = obj[prop]; + return target; + } + + function moveOver(pos, str, copy, other) { + var out = copy ? Pos(pos.line, pos.ch) : pos, at = 0; + for (;;) { + var nl = str.indexOf("\n", at); + if (nl == -1) break; + ++out.line; + if (other) ++other.line; + at = nl + 1; + } + out.ch = (at ? 0 : out.ch) + (str.length - at); + if (other) other.ch = (at ? 0 : other.ch) + (str.length - at); + return out; + } + + // Tracks collapsed markers and line widgets, in order to be able to + // accurately align the content of two editors. + + var F_WIDGET = 1, F_WIDGET_BELOW = 2, F_MARKER = 4 + + function TrackAlignable(cm) { + this.cm = cm + this.alignable = [] + this.height = cm.doc.height + var self = this + cm.on("markerAdded", function(_, marker) { + if (!marker.collapsed) return + var found = marker.find(1) + if (found != null) self.set(found.line, F_MARKER) + }) + cm.on("markerCleared", function(_, marker, _min, max) { + if (max != null && marker.collapsed) + self.check(max, F_MARKER, self.hasMarker) + }) + cm.on("markerChanged", this.signal.bind(this)) + cm.on("lineWidgetAdded", function(_, widget, lineNo) { + if (widget.mergeSpacer) return + if (widget.above) self.set(lineNo - 1, F_WIDGET_BELOW) + else self.set(lineNo, F_WIDGET) + }) + cm.on("lineWidgetCleared", function(_, widget, lineNo) { + if (widget.mergeSpacer) return + if (widget.above) self.check(lineNo - 1, F_WIDGET_BELOW, self.hasWidgetBelow) + else self.check(lineNo, F_WIDGET, self.hasWidget) + }) + cm.on("lineWidgetChanged", this.signal.bind(this)) + cm.on("change", function(_, change) { + var start = change.from.line, nBefore = change.to.line - change.from.line + var nAfter = change.text.length - 1, end = start + nAfter + if (nBefore || nAfter) self.map(start, nBefore, nAfter) + self.check(end, F_MARKER, self.hasMarker) + if (nBefore || nAfter) self.check(change.from.line, F_MARKER, self.hasMarker) + }) + cm.on("viewportChange", function() { + if (self.cm.doc.height != self.height) self.signal() + }) + } + + TrackAlignable.prototype = { + signal: function() { + CodeMirror.signal(this, "realign") + this.height = this.cm.doc.height + }, + + set: function(n, flags) { + var pos = -1 + for (; pos < this.alignable.length; pos += 2) { + var diff = this.alignable[pos] - n + if (diff == 0) { + if ((this.alignable[pos + 1] & flags) == flags) return + this.alignable[pos + 1] |= flags + this.signal() + return + } + if (diff > 0) break + } + this.signal() + this.alignable.splice(pos, 0, n, flags) + }, + + find: function(n) { + for (var i = 0; i < this.alignable.length; i += 2) + if (this.alignable[i] == n) return i + return -1 + }, + + check: function(n, flag, pred) { + var found = this.find(n) + if (found == -1 || !(this.alignable[found + 1] & flag)) return + if (!pred.call(this, n)) { + this.signal() + var flags = this.alignable[found + 1] & ~flag + if (flags) this.alignable[found + 1] = flags + else this.alignable.splice(found, 2) + } + }, + + hasMarker: function(n) { + var handle = this.cm.getLineHandle(n) + if (handle.markedSpans) for (var i = 0; i < handle.markedSpans.length; i++) + if (handle.markedSpans[i].marker.collapsed && handle.markedSpans[i].to != null) + return true + return false + }, + + hasWidget: function(n) { + var handle = this.cm.getLineHandle(n) + if (handle.widgets) for (var i = 0; i < handle.widgets.length; i++) + if (!handle.widgets[i].above && !handle.widgets[i].mergeSpacer) return true + return false + }, + + hasWidgetBelow: function(n) { + if (n == this.cm.lastLine()) return false + var handle = this.cm.getLineHandle(n + 1) + if (handle.widgets) for (var i = 0; i < handle.widgets.length; i++) + if (handle.widgets[i].above && !handle.widgets[i].mergeSpacer) return true + return false + }, + + map: function(from, nBefore, nAfter) { + var diff = nAfter - nBefore, to = from + nBefore, widgetFrom = -1, widgetTo = -1 + for (var i = 0; i < this.alignable.length; i += 2) { + var n = this.alignable[i] + if (n == from && (this.alignable[i + 1] & F_WIDGET_BELOW)) widgetFrom = i + if (n == to && (this.alignable[i + 1] & F_WIDGET_BELOW)) widgetTo = i + if (n <= from) continue + else if (n < to) this.alignable.splice(i--, 2) + else this.alignable[i] += diff + } + if (widgetFrom > -1) { + var flags = this.alignable[widgetFrom + 1] + if (flags == F_WIDGET_BELOW) this.alignable.splice(widgetFrom, 2) + else this.alignable[widgetFrom + 1] = flags & ~F_WIDGET_BELOW + } + if (widgetTo > -1 && nAfter) + this.set(from + nAfter, F_WIDGET_BELOW) + } + } + + function posMin(a, b) { return (a.line - b.line || a.ch - b.ch) < 0 ? a : b; } + function posMax(a, b) { return (a.line - b.line || a.ch - b.ch) > 0 ? a : b; } + function posEq(a, b) { return a.line == b.line && a.ch == b.ch; } + + function findPrevDiff(chunks, start, isOrig) { + for (var i = chunks.length - 1; i >= 0; i--) { + var chunk = chunks[i]; + var to = (isOrig ? chunk.origTo : chunk.editTo) - 1; + if (to < start) return to; + } + } + + function findNextDiff(chunks, start, isOrig) { + for (var i = 0; i < chunks.length; i++) { + var chunk = chunks[i]; + var from = (isOrig ? chunk.origFrom : chunk.editFrom); + if (from > start) return from; + } + } + + function goNearbyDiff(cm, dir) { + var found = null, views = cm.state.diffViews, line = cm.getCursor().line; + if (views) for (var i = 0; i < views.length; i++) { + var dv = views[i], isOrig = cm == dv.orig; + ensureDiff(dv); + var pos = dir < 0 ? findPrevDiff(dv.chunks, line, isOrig) : findNextDiff(dv.chunks, line, isOrig); + if (pos != null && (found == null || (dir < 0 ? pos > found : pos < found))) + found = pos; + } + if (found != null) + cm.setCursor(found, 0); + else + return CodeMirror.Pass; + } + + CodeMirror.commands.goNextDiff = function(cm) { + return goNearbyDiff(cm, 1); + }; + CodeMirror.commands.goPrevDiff = function(cm) { + return goNearbyDiff(cm, -1); + }; +}); diff --git a/public/vendor/plugins/codemirror/addon/mode/loadmode.js b/public/vendor/plugins/codemirror/addon/mode/loadmode.js index 10117ec22f250..4ce716a012216 100644 --- a/public/vendor/plugins/codemirror/addon/mode/loadmode.js +++ b/public/vendor/plugins/codemirror/addon/mode/loadmode.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: http://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/public/vendor/plugins/codemirror/addon/mode/multiplex.js b/public/vendor/plugins/codemirror/addon/mode/multiplex.js index 3d8b34c452013..93fd9a5a461f0 100644 --- a/public/vendor/plugins/codemirror/addon/mode/multiplex.js +++ b/public/vendor/plugins/codemirror/addon/mode/multiplex.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: http://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS @@ -50,7 +50,15 @@ CodeMirror.multiplexingMode = function(outer /*, others */) { if (found == stream.pos) { if (!other.parseDelimiters) stream.match(other.open); state.innerActive = other; - state.inner = CodeMirror.startState(other.mode, outer.indent ? outer.indent(state.outer, "") : 0); + + // Get the outer indent, making sure to handle CodeMirror.Pass + var outerIndent = 0; + if (outer.indent) { + var possibleOuterIndent = outer.indent(state.outer, "", ""); + if (possibleOuterIndent !== CodeMirror.Pass) outerIndent = possibleOuterIndent; + } + + state.inner = CodeMirror.startState(other.mode, outerIndent); return other.delimStyle && (other.delimStyle + " " + other.delimStyle + "-open"); } else if (found != -1 && found < cutOff) { cutOff = found; @@ -88,10 +96,10 @@ CodeMirror.multiplexingMode = function(outer /*, others */) { } }, - indent: function(state, textAfter) { + indent: function(state, textAfter, line) { var mode = state.innerActive ? state.innerActive.mode : outer; if (!mode.indent) return CodeMirror.Pass; - return mode.indent(state.innerActive ? state.inner : state.outer, textAfter); + return mode.indent(state.innerActive ? state.inner : state.outer, textAfter, line); }, blankLine: function(state) { @@ -104,7 +112,7 @@ CodeMirror.multiplexingMode = function(outer /*, others */) { var other = others[i]; if (other.open === "\n") { state.innerActive = other; - state.inner = CodeMirror.startState(other.mode, mode.indent ? mode.indent(state.outer, "") : 0); + state.inner = CodeMirror.startState(other.mode, mode.indent ? mode.indent(state.outer, "", "") : 0); } } } else if (state.innerActive.close === "\n") { diff --git a/public/vendor/plugins/codemirror/addon/mode/multiplex_test.js b/public/vendor/plugins/codemirror/addon/mode/multiplex_test.js index 24e5e670de1e5..c51cad45d5031 100644 --- a/public/vendor/plugins/codemirror/addon/mode/multiplex_test.js +++ b/public/vendor/plugins/codemirror/addon/mode/multiplex_test.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: http://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/LICENSE (function() { CodeMirror.defineMode("markdown_with_stex", function(){ diff --git a/public/vendor/plugins/codemirror/addon/mode/overlay.js b/public/vendor/plugins/codemirror/addon/mode/overlay.js index e1b9ed37530ad..016e3c28ccc1f 100644 --- a/public/vendor/plugins/codemirror/addon/mode/overlay.js +++ b/public/vendor/plugins/codemirror/addon/mode/overlay.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: http://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/LICENSE // Utility function that allows modes to be combined. The mode given // as the base argument takes care of most of the normal mode @@ -68,16 +68,21 @@ CodeMirror.overlayMode = function(base, overlay, combine) { else return state.overlayCur; }, - indent: base.indent && function(state, textAfter) { - return base.indent(state.base, textAfter); + indent: base.indent && function(state, textAfter, line) { + return base.indent(state.base, textAfter, line); }, electricChars: base.electricChars, innerMode: function(state) { return {state: state.base, mode: base}; }, blankLine: function(state) { - if (base.blankLine) base.blankLine(state.base); - if (overlay.blankLine) overlay.blankLine(state.overlay); + var baseToken, overlayToken; + if (base.blankLine) baseToken = base.blankLine(state.base); + if (overlay.blankLine) overlayToken = overlay.blankLine(state.overlay); + + return overlayToken == null ? + baseToken : + (combine && baseToken != null ? baseToken + " " + overlayToken : overlayToken); } }; }; diff --git a/public/vendor/plugins/codemirror/addon/mode/simple.js b/public/vendor/plugins/codemirror/addon/mode/simple.js index df663365e8c23..655f9914757c3 100644 --- a/public/vendor/plugins/codemirror/addon/mode/simple.js +++ b/public/vendor/plugins/codemirror/addon/mode/simple.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: http://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS @@ -77,6 +77,7 @@ function asToken(val) { if (!val) return null; + if (val.apply) return val if (typeof val == "string") return val.replace(/\./g, " "); var result = []; for (var i = 0; i < val.length; i++) @@ -133,17 +134,19 @@ state.indent.push(stream.indentation() + config.indentUnit); if (rule.data.dedent) state.indent.pop(); - if (matches.length > 2) { + var token = rule.token + if (token && token.apply) token = token(matches) + if (matches.length > 2 && rule.token && typeof rule.token != "string") { state.pending = []; for (var j = 2; j < matches.length; j++) if (matches[j]) state.pending.push({text: matches[j], token: rule.token[j - 1]}); stream.backUp(matches[0].length - (matches[1] ? matches[1].length : 0)); - return rule.token[0]; - } else if (rule.token && rule.token.join) { - return rule.token[0]; + return token[0]; + } else if (token && token.join) { + return token[0]; } else { - return rule.token; + return token; } } } diff --git a/public/vendor/plugins/codemirror/addon/runmode/colorize.js b/public/vendor/plugins/codemirror/addon/runmode/colorize.js new file mode 100644 index 0000000000000..3be5411506ed8 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/runmode/colorize.js @@ -0,0 +1,40 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("./runmode")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "./runmode"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var isBlock = /^(p|li|div|h\\d|pre|blockquote|td)$/; + + function textContent(node, out) { + if (node.nodeType == 3) return out.push(node.nodeValue); + for (var ch = node.firstChild; ch; ch = ch.nextSibling) { + textContent(ch, out); + if (isBlock.test(node.nodeType)) out.push("\n"); + } + } + + CodeMirror.colorize = function(collection, defaultMode) { + if (!collection) collection = document.body.getElementsByTagName("pre"); + + for (var i = 0; i < collection.length; ++i) { + var node = collection[i]; + var mode = node.getAttribute("data-lang") || defaultMode; + if (!mode) continue; + + var text = []; + textContent(node, text); + node.innerHTML = ""; + CodeMirror.runMode(text.join(""), mode, node); + + node.className += " cm-s-default"; + } + }; +}); diff --git a/public/vendor/plugins/codemirror/addon/runmode/runmode-standalone.js b/public/vendor/plugins/codemirror/addon/runmode/runmode-standalone.js new file mode 100644 index 0000000000000..745eaf8440fd6 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/runmode/runmode-standalone.js @@ -0,0 +1,158 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +window.CodeMirror = {}; + +(function() { +"use strict"; + +function splitLines(string){ return string.split(/\r?\n|\r/); }; + +function StringStream(string) { + this.pos = this.start = 0; + this.string = string; + this.lineStart = 0; +} +StringStream.prototype = { + eol: function() {return this.pos >= this.string.length;}, + sol: function() {return this.pos == 0;}, + peek: function() {return this.string.charAt(this.pos) || null;}, + next: function() { + if (this.pos < this.string.length) + return this.string.charAt(this.pos++); + }, + eat: function(match) { + var ch = this.string.charAt(this.pos); + if (typeof match == "string") var ok = ch == match; + else var ok = ch && (match.test ? match.test(ch) : match(ch)); + if (ok) {++this.pos; return ch;} + }, + eatWhile: function(match) { + var start = this.pos; + while (this.eat(match)){} + return this.pos > start; + }, + eatSpace: function() { + var start = this.pos; + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; + return this.pos > start; + }, + skipToEnd: function() {this.pos = this.string.length;}, + skipTo: function(ch) { + var found = this.string.indexOf(ch, this.pos); + if (found > -1) {this.pos = found; return true;} + }, + backUp: function(n) {this.pos -= n;}, + column: function() {return this.start - this.lineStart;}, + indentation: function() {return 0;}, + match: function(pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; + var substr = this.string.substr(this.pos, pattern.length); + if (cased(substr) == cased(pattern)) { + if (consume !== false) this.pos += pattern.length; + return true; + } + } else { + var match = this.string.slice(this.pos).match(pattern); + if (match && match.index > 0) return null; + if (match && consume !== false) this.pos += match[0].length; + return match; + } + }, + current: function(){return this.string.slice(this.start, this.pos);}, + hideFirstChars: function(n, inner) { + this.lineStart += n; + try { return inner(); } + finally { this.lineStart -= n; } + }, + lookAhead: function() { return null } +}; +CodeMirror.StringStream = StringStream; + +CodeMirror.startState = function (mode, a1, a2) { + return mode.startState ? mode.startState(a1, a2) : true; +}; + +var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {}; +CodeMirror.defineMode = function (name, mode) { + if (arguments.length > 2) + mode.dependencies = Array.prototype.slice.call(arguments, 2); + modes[name] = mode; +}; +CodeMirror.defineMIME = function (mime, spec) { mimeModes[mime] = spec; }; +CodeMirror.resolveMode = function(spec) { + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { + spec = mimeModes[spec]; + } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { + spec = mimeModes[spec.name]; + } + if (typeof spec == "string") return {name: spec}; + else return spec || {name: "null"}; +}; +CodeMirror.getMode = function (options, spec) { + spec = CodeMirror.resolveMode(spec); + var mfactory = modes[spec.name]; + if (!mfactory) throw new Error("Unknown mode: " + spec); + return mfactory(options, spec); +}; +CodeMirror.registerHelper = CodeMirror.registerGlobalHelper = Math.min; +CodeMirror.defineMode("null", function() { + return {token: function(stream) {stream.skipToEnd();}}; +}); +CodeMirror.defineMIME("text/plain", "null"); + +CodeMirror.runMode = function (string, modespec, callback, options) { + var mode = CodeMirror.getMode({ indentUnit: 2 }, modespec); + + if (callback.nodeType == 1) { + var tabSize = (options && options.tabSize) || 4; + var node = callback, col = 0; + node.innerHTML = ""; + callback = function (text, style) { + if (text == "\n") { + node.appendChild(document.createElement("br")); + col = 0; + return; + } + var content = ""; + // replace tabs + for (var pos = 0; ;) { + var idx = text.indexOf("\t", pos); + if (idx == -1) { + content += text.slice(pos); + col += text.length - pos; + break; + } else { + col += idx - pos; + content += text.slice(pos, idx); + var size = tabSize - col % tabSize; + col += size; + for (var i = 0; i < size; ++i) content += " "; + pos = idx + 1; + } + } + + if (style) { + var sp = node.appendChild(document.createElement("span")); + sp.className = "cm-" + style.replace(/ +/g, " cm-"); + sp.appendChild(document.createTextNode(content)); + } else { + node.appendChild(document.createTextNode(content)); + } + }; + } + + var lines = splitLines(string), state = (options && options.state) || CodeMirror.startState(mode); + for (var i = 0, e = lines.length; i < e; ++i) { + if (i) callback("\n"); + var stream = new CodeMirror.StringStream(lines[i]); + if (!stream.string && mode.blankLine) mode.blankLine(state); + while (!stream.eol()) { + var style = mode.token(stream, state); + callback(stream.current(), style, i, stream.start, state); + stream.start = stream.pos; + } + } +}; +})(); diff --git a/public/vendor/plugins/codemirror/addon/runmode/runmode.js b/public/vendor/plugins/codemirror/addon/runmode/runmode.js new file mode 100644 index 0000000000000..eb4cadf5b441c --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/runmode/runmode.js @@ -0,0 +1,72 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.runMode = function(string, modespec, callback, options) { + var mode = CodeMirror.getMode(CodeMirror.defaults, modespec); + var ie = /MSIE \d/.test(navigator.userAgent); + var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9); + + if (callback.appendChild) { + var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize; + var node = callback, col = 0; + node.innerHTML = ""; + callback = function(text, style) { + if (text == "\n") { + // Emitting LF or CRLF on IE8 or earlier results in an incorrect display. + // Emitting a carriage return makes everything ok. + node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text)); + col = 0; + return; + } + var content = ""; + // replace tabs + for (var pos = 0;;) { + var idx = text.indexOf("\t", pos); + if (idx == -1) { + content += text.slice(pos); + col += text.length - pos; + break; + } else { + col += idx - pos; + content += text.slice(pos, idx); + var size = tabSize - col % tabSize; + col += size; + for (var i = 0; i < size; ++i) content += " "; + pos = idx + 1; + } + } + + if (style) { + var sp = node.appendChild(document.createElement("span")); + sp.className = "cm-" + style.replace(/ +/g, " cm-"); + sp.appendChild(document.createTextNode(content)); + } else { + node.appendChild(document.createTextNode(content)); + } + }; + } + + var lines = CodeMirror.splitLines(string), state = (options && options.state) || CodeMirror.startState(mode); + for (var i = 0, e = lines.length; i < e; ++i) { + if (i) callback("\n"); + var stream = new CodeMirror.StringStream(lines[i]); + if (!stream.string && mode.blankLine) mode.blankLine(state); + while (!stream.eol()) { + var style = mode.token(stream, state); + callback(stream.current(), style, i, stream.start, state); + stream.start = stream.pos; + } + } +}; + +}); diff --git a/public/vendor/plugins/codemirror/addon/runmode/runmode.node.js b/public/vendor/plugins/codemirror/addon/runmode/runmode.node.js new file mode 100644 index 0000000000000..53b6994c28f8a --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/runmode/runmode.node.js @@ -0,0 +1,197 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +/* Just enough of CodeMirror to run runMode under node.js */ + +function splitLines(string){return string.split(/\r\n?|\n/);}; + +// Counts the column offset in a string, taking tabs into account. +// Used mostly to find indentation. +var countColumn = exports.countColumn = function(string, end, tabSize, startIndex, startValue) { + if (end == null) { + end = string.search(/[^\s\u00a0]/); + if (end == -1) end = string.length; + } + for (var i = startIndex || 0, n = startValue || 0;;) { + var nextTab = string.indexOf("\t", i); + if (nextTab < 0 || nextTab >= end) + return n + (end - i); + n += nextTab - i; + n += tabSize - (n % tabSize); + i = nextTab + 1; + } +}; + +function StringStream(string, tabSize, context) { + this.pos = this.start = 0; + this.string = string; + this.tabSize = tabSize || 8; + this.lastColumnPos = this.lastColumnValue = 0; + this.lineStart = 0; + this.context = context +}; + +StringStream.prototype = { + eol: function() {return this.pos >= this.string.length;}, + sol: function() {return this.pos == this.lineStart;}, + peek: function() {return this.string.charAt(this.pos) || undefined;}, + next: function() { + if (this.pos < this.string.length) + return this.string.charAt(this.pos++); + }, + eat: function(match) { + var ch = this.string.charAt(this.pos); + if (typeof match == "string") var ok = ch == match; + else var ok = ch && (match.test ? match.test(ch) : match(ch)); + if (ok) {++this.pos; return ch;} + }, + eatWhile: function(match) { + var start = this.pos; + while (this.eat(match)){} + return this.pos > start; + }, + eatSpace: function() { + var start = this.pos; + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; + return this.pos > start; + }, + skipToEnd: function() {this.pos = this.string.length;}, + skipTo: function(ch) { + var found = this.string.indexOf(ch, this.pos); + if (found > -1) {this.pos = found; return true;} + }, + backUp: function(n) {this.pos -= n;}, + column: function() { + if (this.lastColumnPos < this.start) { + this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue); + this.lastColumnPos = this.start; + } + return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); + }, + indentation: function() { + return countColumn(this.string, null, this.tabSize) - + (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); + }, + match: function(pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; + var substr = this.string.substr(this.pos, pattern.length); + if (cased(substr) == cased(pattern)) { + if (consume !== false) this.pos += pattern.length; + return true; + } + } else { + var match = this.string.slice(this.pos).match(pattern); + if (match && match.index > 0) return null; + if (match && consume !== false) this.pos += match[0].length; + return match; + } + }, + current: function(){return this.string.slice(this.start, this.pos);}, + hideFirstChars: function(n, inner) { + this.lineStart += n; + try { return inner(); } + finally { this.lineStart -= n; } + }, + lookAhead: function(n) { + var line = this.context.line + n + return line >= this.context.lines.length ? null : this.context.lines[line] + } +}; +exports.StringStream = StringStream; + +exports.startState = function(mode, a1, a2) { + return mode.startState ? mode.startState(a1, a2) : true; +}; + +var modes = exports.modes = {}, mimeModes = exports.mimeModes = {}; +exports.defineMode = function(name, mode) { + if (arguments.length > 2) + mode.dependencies = Array.prototype.slice.call(arguments, 2); + modes[name] = mode; +}; +exports.defineMIME = function(mime, spec) { mimeModes[mime] = spec; }; + +exports.defineMode("null", function() { + return {token: function(stream) {stream.skipToEnd();}}; +}); +exports.defineMIME("text/plain", "null"); + +exports.resolveMode = function(spec) { + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { + spec = mimeModes[spec]; + } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { + spec = mimeModes[spec.name]; + } + if (typeof spec == "string") return {name: spec}; + else return spec || {name: "null"}; +}; + +function copyObj(obj, target, overwrite) { + if (!target) target = {}; + for (var prop in obj) + if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) + target[prop] = obj[prop]; + return target; +} + +// This can be used to attach properties to mode objects from +// outside the actual mode definition. +var modeExtensions = exports.modeExtensions = {}; +exports.extendMode = function(mode, properties) { + var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}); + copyObj(properties, exts); +}; + +exports.getMode = function(options, spec) { + var spec = exports.resolveMode(spec); + var mfactory = modes[spec.name]; + if (!mfactory) return exports.getMode(options, "text/plain"); + var modeObj = mfactory(options, spec); + if (modeExtensions.hasOwnProperty(spec.name)) { + var exts = modeExtensions[spec.name]; + for (var prop in exts) { + if (!exts.hasOwnProperty(prop)) continue; + if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop]; + modeObj[prop] = exts[prop]; + } + } + modeObj.name = spec.name; + if (spec.helperType) modeObj.helperType = spec.helperType; + if (spec.modeProps) for (var prop in spec.modeProps) + modeObj[prop] = spec.modeProps[prop]; + + return modeObj; +}; + +exports.innerMode = function(mode, state) { + var info; + while (mode.innerMode) { + info = mode.innerMode(state); + if (!info || info.mode == mode) break; + state = info.state; + mode = info.mode; + } + return info || {mode: mode, state: state}; +} + +exports.registerHelper = exports.registerGlobalHelper = Math.min; + +exports.runMode = function(string, modespec, callback, options) { + var mode = exports.getMode({indentUnit: 2}, modespec); + var lines = splitLines(string), state = (options && options.state) || exports.startState(mode); + var context = {lines: lines, line: 0} + for (var i = 0, e = lines.length; i < e; ++i, ++context.line) { + if (i) callback("\n"); + var stream = new exports.StringStream(lines[i], 4, context); + if (!stream.string && mode.blankLine) mode.blankLine(state); + while (!stream.eol()) { + var style = mode.token(stream, state); + callback(stream.current(), style, i, stream.start, state); + stream.start = stream.pos; + } + } +}; + +require.cache[require.resolve("../../lib/codemirror")] = require.cache[require.resolve("./runmode.node")]; +require.cache[require.resolve("../../addon/runmode/runmode")] = require.cache[require.resolve("./runmode.node")]; diff --git a/public/vendor/plugins/codemirror/addon/scroll/annotatescrollbar.js b/public/vendor/plugins/codemirror/addon/scroll/annotatescrollbar.js new file mode 100644 index 0000000000000..9fe61ec1ff6e5 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/scroll/annotatescrollbar.js @@ -0,0 +1,122 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineExtension("annotateScrollbar", function(options) { + if (typeof options == "string") options = {className: options}; + return new Annotation(this, options); + }); + + CodeMirror.defineOption("scrollButtonHeight", 0); + + function Annotation(cm, options) { + this.cm = cm; + this.options = options; + this.buttonHeight = options.scrollButtonHeight || cm.getOption("scrollButtonHeight"); + this.annotations = []; + this.doRedraw = this.doUpdate = null; + this.div = cm.getWrapperElement().appendChild(document.createElement("div")); + this.div.style.cssText = "position: absolute; right: 0; top: 0; z-index: 7; pointer-events: none"; + this.computeScale(); + + function scheduleRedraw(delay) { + clearTimeout(self.doRedraw); + self.doRedraw = setTimeout(function() { self.redraw(); }, delay); + } + + var self = this; + cm.on("refresh", this.resizeHandler = function() { + clearTimeout(self.doUpdate); + self.doUpdate = setTimeout(function() { + if (self.computeScale()) scheduleRedraw(20); + }, 100); + }); + cm.on("markerAdded", this.resizeHandler); + cm.on("markerCleared", this.resizeHandler); + if (options.listenForChanges !== false) + cm.on("changes", this.changeHandler = function() { + scheduleRedraw(250); + }); + } + + Annotation.prototype.computeScale = function() { + var cm = this.cm; + var hScale = (cm.getWrapperElement().clientHeight - cm.display.barHeight - this.buttonHeight * 2) / + cm.getScrollerElement().scrollHeight + if (hScale != this.hScale) { + this.hScale = hScale; + return true; + } + }; + + Annotation.prototype.update = function(annotations) { + this.annotations = annotations; + this.redraw(); + }; + + Annotation.prototype.redraw = function(compute) { + if (compute !== false) this.computeScale(); + var cm = this.cm, hScale = this.hScale; + + var frag = document.createDocumentFragment(), anns = this.annotations; + + var wrapping = cm.getOption("lineWrapping"); + var singleLineH = wrapping && cm.defaultTextHeight() * 1.5; + var curLine = null, curLineObj = null; + function getY(pos, top) { + if (curLine != pos.line) { + curLine = pos.line; + curLineObj = cm.getLineHandle(curLine); + } + if ((curLineObj.widgets && curLineObj.widgets.length) || + (wrapping && curLineObj.height > singleLineH)) + return cm.charCoords(pos, "local")[top ? "top" : "bottom"]; + var topY = cm.heightAtLine(curLineObj, "local"); + return topY + (top ? 0 : curLineObj.height); + } + + var lastLine = cm.lastLine() + if (cm.display.barWidth) for (var i = 0, nextTop; i < anns.length; i++) { + var ann = anns[i]; + if (ann.to.line > lastLine) continue; + var top = nextTop || getY(ann.from, true) * hScale; + var bottom = getY(ann.to, false) * hScale; + while (i < anns.length - 1) { + if (anns[i + 1].to.line > lastLine) break; + nextTop = getY(anns[i + 1].from, true) * hScale; + if (nextTop > bottom + .9) break; + ann = anns[++i]; + bottom = getY(ann.to, false) * hScale; + } + if (bottom == top) continue; + var height = Math.max(bottom - top, 3); + + var elt = frag.appendChild(document.createElement("div")); + elt.style.cssText = "position: absolute; right: 0px; width: " + Math.max(cm.display.barWidth - 1, 2) + "px; top: " + + (top + this.buttonHeight) + "px; height: " + height + "px"; + elt.className = this.options.className; + if (ann.id) { + elt.setAttribute("annotation-id", ann.id); + } + } + this.div.textContent = ""; + this.div.appendChild(frag); + }; + + Annotation.prototype.clear = function() { + this.cm.off("refresh", this.resizeHandler); + this.cm.off("markerAdded", this.resizeHandler); + this.cm.off("markerCleared", this.resizeHandler); + if (this.changeHandler) this.cm.off("changes", this.changeHandler); + this.div.parentNode.removeChild(this.div); + }; +}); diff --git a/public/vendor/plugins/codemirror/addon/scroll/scrollpastend.js b/public/vendor/plugins/codemirror/addon/scroll/scrollpastend.js new file mode 100644 index 0000000000000..2ed9d95e84488 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/scroll/scrollpastend.js @@ -0,0 +1,48 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("scrollPastEnd", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + cm.off("change", onChange); + cm.off("refresh", updateBottomMargin); + cm.display.lineSpace.parentNode.style.paddingBottom = ""; + cm.state.scrollPastEndPadding = null; + } + if (val) { + cm.on("change", onChange); + cm.on("refresh", updateBottomMargin); + updateBottomMargin(cm); + } + }); + + function onChange(cm, change) { + if (CodeMirror.changeEnd(change).line == cm.lastLine()) + updateBottomMargin(cm); + } + + function updateBottomMargin(cm) { + var padding = ""; + if (cm.lineCount() > 1) { + var totalH = cm.display.scroller.clientHeight - 30, + lastLineH = cm.getLineHandle(cm.lastLine()).height; + padding = (totalH - lastLineH) + "px"; + } + if (cm.state.scrollPastEndPadding != padding) { + cm.state.scrollPastEndPadding = padding; + cm.display.lineSpace.parentNode.style.paddingBottom = padding; + cm.off("refresh", updateBottomMargin); + cm.setSize(); + cm.on("refresh", updateBottomMargin); + } + } +}); diff --git a/public/vendor/plugins/codemirror/addon/scroll/simplescrollbars.css b/public/vendor/plugins/codemirror/addon/scroll/simplescrollbars.css new file mode 100644 index 0000000000000..5eea7aa1b3c55 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/scroll/simplescrollbars.css @@ -0,0 +1,66 @@ +.CodeMirror-simplescroll-horizontal div, .CodeMirror-simplescroll-vertical div { + position: absolute; + background: #ccc; + -moz-box-sizing: border-box; + box-sizing: border-box; + border: 1px solid #bbb; + border-radius: 2px; +} + +.CodeMirror-simplescroll-horizontal, .CodeMirror-simplescroll-vertical { + position: absolute; + z-index: 6; + background: #eee; +} + +.CodeMirror-simplescroll-horizontal { + bottom: 0; left: 0; + height: 8px; +} +.CodeMirror-simplescroll-horizontal div { + bottom: 0; + height: 100%; +} + +.CodeMirror-simplescroll-vertical { + right: 0; top: 0; + width: 8px; +} +.CodeMirror-simplescroll-vertical div { + right: 0; + width: 100%; +} + + +.CodeMirror-overlayscroll .CodeMirror-scrollbar-filler, .CodeMirror-overlayscroll .CodeMirror-gutter-filler { + display: none; +} + +.CodeMirror-overlayscroll-horizontal div, .CodeMirror-overlayscroll-vertical div { + position: absolute; + background: #bcd; + border-radius: 3px; +} + +.CodeMirror-overlayscroll-horizontal, .CodeMirror-overlayscroll-vertical { + position: absolute; + z-index: 6; +} + +.CodeMirror-overlayscroll-horizontal { + bottom: 0; left: 0; + height: 6px; +} +.CodeMirror-overlayscroll-horizontal div { + bottom: 0; + height: 100%; +} + +.CodeMirror-overlayscroll-vertical { + right: 0; top: 0; + width: 6px; +} +.CodeMirror-overlayscroll-vertical div { + right: 0; + width: 100%; +} diff --git a/public/vendor/plugins/codemirror/addon/scroll/simplescrollbars.js b/public/vendor/plugins/codemirror/addon/scroll/simplescrollbars.js new file mode 100644 index 0000000000000..750a2bd399d39 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/scroll/simplescrollbars.js @@ -0,0 +1,152 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function Bar(cls, orientation, scroll) { + this.orientation = orientation; + this.scroll = scroll; + this.screen = this.total = this.size = 1; + this.pos = 0; + + this.node = document.createElement("div"); + this.node.className = cls + "-" + orientation; + this.inner = this.node.appendChild(document.createElement("div")); + + var self = this; + CodeMirror.on(this.inner, "mousedown", function(e) { + if (e.which != 1) return; + CodeMirror.e_preventDefault(e); + var axis = self.orientation == "horizontal" ? "pageX" : "pageY"; + var start = e[axis], startpos = self.pos; + function done() { + CodeMirror.off(document, "mousemove", move); + CodeMirror.off(document, "mouseup", done); + } + function move(e) { + if (e.which != 1) return done(); + self.moveTo(startpos + (e[axis] - start) * (self.total / self.size)); + } + CodeMirror.on(document, "mousemove", move); + CodeMirror.on(document, "mouseup", done); + }); + + CodeMirror.on(this.node, "click", function(e) { + CodeMirror.e_preventDefault(e); + var innerBox = self.inner.getBoundingClientRect(), where; + if (self.orientation == "horizontal") + where = e.clientX < innerBox.left ? -1 : e.clientX > innerBox.right ? 1 : 0; + else + where = e.clientY < innerBox.top ? -1 : e.clientY > innerBox.bottom ? 1 : 0; + self.moveTo(self.pos + where * self.screen); + }); + + function onWheel(e) { + var moved = CodeMirror.wheelEventPixels(e)[self.orientation == "horizontal" ? "x" : "y"]; + var oldPos = self.pos; + self.moveTo(self.pos + moved); + if (self.pos != oldPos) CodeMirror.e_preventDefault(e); + } + CodeMirror.on(this.node, "mousewheel", onWheel); + CodeMirror.on(this.node, "DOMMouseScroll", onWheel); + } + + Bar.prototype.setPos = function(pos, force) { + if (pos < 0) pos = 0; + if (pos > this.total - this.screen) pos = this.total - this.screen; + if (!force && pos == this.pos) return false; + this.pos = pos; + this.inner.style[this.orientation == "horizontal" ? "left" : "top"] = + (pos * (this.size / this.total)) + "px"; + return true + }; + + Bar.prototype.moveTo = function(pos) { + if (this.setPos(pos)) this.scroll(pos, this.orientation); + } + + var minButtonSize = 10; + + Bar.prototype.update = function(scrollSize, clientSize, barSize) { + var sizeChanged = this.screen != clientSize || this.total != scrollSize || this.size != barSize + if (sizeChanged) { + this.screen = clientSize; + this.total = scrollSize; + this.size = barSize; + } + + var buttonSize = this.screen * (this.size / this.total); + if (buttonSize < minButtonSize) { + this.size -= minButtonSize - buttonSize; + buttonSize = minButtonSize; + } + this.inner.style[this.orientation == "horizontal" ? "width" : "height"] = + buttonSize + "px"; + this.setPos(this.pos, sizeChanged); + }; + + function SimpleScrollbars(cls, place, scroll) { + this.addClass = cls; + this.horiz = new Bar(cls, "horizontal", scroll); + place(this.horiz.node); + this.vert = new Bar(cls, "vertical", scroll); + place(this.vert.node); + this.width = null; + } + + SimpleScrollbars.prototype.update = function(measure) { + if (this.width == null) { + var style = window.getComputedStyle ? window.getComputedStyle(this.horiz.node) : this.horiz.node.currentStyle; + if (style) this.width = parseInt(style.height); + } + var width = this.width || 0; + + var needsH = measure.scrollWidth > measure.clientWidth + 1; + var needsV = measure.scrollHeight > measure.clientHeight + 1; + this.vert.node.style.display = needsV ? "block" : "none"; + this.horiz.node.style.display = needsH ? "block" : "none"; + + if (needsV) { + this.vert.update(measure.scrollHeight, measure.clientHeight, + measure.viewHeight - (needsH ? width : 0)); + this.vert.node.style.bottom = needsH ? width + "px" : "0"; + } + if (needsH) { + this.horiz.update(measure.scrollWidth, measure.clientWidth, + measure.viewWidth - (needsV ? width : 0) - measure.barLeft); + this.horiz.node.style.right = needsV ? width + "px" : "0"; + this.horiz.node.style.left = measure.barLeft + "px"; + } + + return {right: needsV ? width : 0, bottom: needsH ? width : 0}; + }; + + SimpleScrollbars.prototype.setScrollTop = function(pos) { + this.vert.setPos(pos); + }; + + SimpleScrollbars.prototype.setScrollLeft = function(pos) { + this.horiz.setPos(pos); + }; + + SimpleScrollbars.prototype.clear = function() { + var parent = this.horiz.node.parentNode; + parent.removeChild(this.horiz.node); + parent.removeChild(this.vert.node); + }; + + CodeMirror.scrollbarModel.simple = function(place, scroll) { + return new SimpleScrollbars("CodeMirror-simplescroll", place, scroll); + }; + CodeMirror.scrollbarModel.overlay = function(place, scroll) { + return new SimpleScrollbars("CodeMirror-overlayscroll", place, scroll); + }; +}); diff --git a/public/vendor/plugins/codemirror/addon/search/jump-to-line.js b/public/vendor/plugins/codemirror/addon/search/jump-to-line.js new file mode 100644 index 0000000000000..1f3526d2470f4 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/search/jump-to-line.js @@ -0,0 +1,50 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// Defines jumpToLine command. Uses dialog.js if present. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../dialog/dialog")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../dialog/dialog"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function dialog(cm, text, shortText, deflt, f) { + if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true}); + else f(prompt(shortText, deflt)); + } + + function getJumpDialog(cm) { + return cm.phrase("Jump to line:") + ' ' + cm.phrase("(Use line:column or scroll% syntax)") + ''; + } + + function interpretLine(cm, string) { + var num = Number(string) + if (/^[-+]/.test(string)) return cm.getCursor().line + num + else return num - 1 + } + + CodeMirror.commands.jumpToLine = function(cm) { + var cur = cm.getCursor(); + dialog(cm, getJumpDialog(cm), cm.phrase("Jump to line:"), (cur.line + 1) + ":" + cur.ch, function(posStr) { + if (!posStr) return; + + var match; + if (match = /^\s*([\+\-]?\d+)\s*\:\s*(\d+)\s*$/.exec(posStr)) { + cm.setCursor(interpretLine(cm, match[1]), Number(match[2])) + } else if (match = /^\s*([\+\-]?\d+(\.\d+)?)\%\s*/.exec(posStr)) { + var line = Math.round(cm.lineCount() * Number(match[1]) / 100); + if (/^[-+]/.test(match[1])) line = cur.line + line + 1; + cm.setCursor(line - 1, cur.ch); + } else if (match = /^\s*\:?\s*([\+\-]?\d+)\s*/.exec(posStr)) { + cm.setCursor(interpretLine(cm, match[1]), cur.ch); + } + }); + }; + + CodeMirror.keyMap["default"]["Alt-G"] = "jumpToLine"; +}); diff --git a/public/vendor/plugins/codemirror/addon/search/match-highlighter.js b/public/vendor/plugins/codemirror/addon/search/match-highlighter.js new file mode 100644 index 0000000000000..b344ac79e2402 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/search/match-highlighter.js @@ -0,0 +1,165 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// Highlighting text that matches the selection +// +// Defines an option highlightSelectionMatches, which, when enabled, +// will style strings that match the selection throughout the +// document. +// +// The option can be set to true to simply enable it, or to a +// {minChars, style, wordsOnly, showToken, delay} object to explicitly +// configure it. minChars is the minimum amount of characters that should be +// selected for the behavior to occur, and style is the token style to +// apply to the matches. This will be prefixed by "cm-" to create an +// actual CSS class name. If wordsOnly is enabled, the matches will be +// highlighted only if the selected text is a word. showToken, when enabled, +// will cause the current token to be highlighted when nothing is selected. +// delay is used to specify how much time to wait, in milliseconds, before +// highlighting the matches. If annotateScrollbar is enabled, the occurences +// will be highlighted on the scrollbar via the matchesonscrollbar addon. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("./matchesonscrollbar")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "./matchesonscrollbar"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var defaults = { + style: "matchhighlight", + minChars: 2, + delay: 100, + wordsOnly: false, + annotateScrollbar: false, + showToken: false, + trim: true + } + + function State(options) { + this.options = {} + for (var name in defaults) + this.options[name] = (options && options.hasOwnProperty(name) ? options : defaults)[name] + this.overlay = this.timeout = null; + this.matchesonscroll = null; + this.active = false; + } + + CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + removeOverlay(cm); + clearTimeout(cm.state.matchHighlighter.timeout); + cm.state.matchHighlighter = null; + cm.off("cursorActivity", cursorActivity); + cm.off("focus", onFocus) + } + if (val) { + var state = cm.state.matchHighlighter = new State(val); + if (cm.hasFocus()) { + state.active = true + highlightMatches(cm) + } else { + cm.on("focus", onFocus) + } + cm.on("cursorActivity", cursorActivity); + } + }); + + function cursorActivity(cm) { + var state = cm.state.matchHighlighter; + if (state.active || cm.hasFocus()) scheduleHighlight(cm, state) + } + + function onFocus(cm) { + var state = cm.state.matchHighlighter + if (!state.active) { + state.active = true + scheduleHighlight(cm, state) + } + } + + function scheduleHighlight(cm, state) { + clearTimeout(state.timeout); + state.timeout = setTimeout(function() {highlightMatches(cm);}, state.options.delay); + } + + function addOverlay(cm, query, hasBoundary, style) { + var state = cm.state.matchHighlighter; + cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style)); + if (state.options.annotateScrollbar && cm.showMatchesOnScrollbar) { + var searchFor = hasBoundary ? new RegExp("\\b" + query.replace(/[\\\[.+*?(){|^$]/g, "\\$&") + "\\b") : query; + state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, false, + {className: "CodeMirror-selection-highlight-scrollbar"}); + } + } + + function removeOverlay(cm) { + var state = cm.state.matchHighlighter; + if (state.overlay) { + cm.removeOverlay(state.overlay); + state.overlay = null; + if (state.matchesonscroll) { + state.matchesonscroll.clear(); + state.matchesonscroll = null; + } + } + } + + function highlightMatches(cm) { + cm.operation(function() { + var state = cm.state.matchHighlighter; + removeOverlay(cm); + if (!cm.somethingSelected() && state.options.showToken) { + var re = state.options.showToken === true ? /[\w$]/ : state.options.showToken; + var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start; + while (start && re.test(line.charAt(start - 1))) --start; + while (end < line.length && re.test(line.charAt(end))) ++end; + if (start < end) + addOverlay(cm, line.slice(start, end), re, state.options.style); + return; + } + var from = cm.getCursor("from"), to = cm.getCursor("to"); + if (from.line != to.line) return; + if (state.options.wordsOnly && !isWord(cm, from, to)) return; + var selection = cm.getRange(from, to) + if (state.options.trim) selection = selection.replace(/^\s+|\s+$/g, "") + if (selection.length >= state.options.minChars) + addOverlay(cm, selection, false, state.options.style); + }); + } + + function isWord(cm, from, to) { + var str = cm.getRange(from, to); + if (str.match(/^\w+$/) !== null) { + if (from.ch > 0) { + var pos = {line: from.line, ch: from.ch - 1}; + var chr = cm.getRange(pos, from); + if (chr.match(/\W/) === null) return false; + } + if (to.ch < cm.getLine(from.line).length) { + var pos = {line: to.line, ch: to.ch + 1}; + var chr = cm.getRange(to, pos); + if (chr.match(/\W/) === null) return false; + } + return true; + } else return false; + } + + function boundariesAround(stream, re) { + return (!stream.start || !re.test(stream.string.charAt(stream.start - 1))) && + (stream.pos == stream.string.length || !re.test(stream.string.charAt(stream.pos))); + } + + function makeOverlay(query, hasBoundary, style) { + return {token: function(stream) { + if (stream.match(query) && + (!hasBoundary || boundariesAround(stream, hasBoundary))) + return style; + stream.next(); + stream.skipTo(query.charAt(0)) || stream.skipToEnd(); + }}; + } +}); diff --git a/public/vendor/plugins/codemirror/addon/search/matchesonscrollbar.css b/public/vendor/plugins/codemirror/addon/search/matchesonscrollbar.css new file mode 100644 index 0000000000000..77932cc9081a3 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/search/matchesonscrollbar.css @@ -0,0 +1,8 @@ +.CodeMirror-search-match { + background: gold; + border-top: 1px solid orange; + border-bottom: 1px solid orange; + -moz-box-sizing: border-box; + box-sizing: border-box; + opacity: .5; +} diff --git a/public/vendor/plugins/codemirror/addon/search/matchesonscrollbar.js b/public/vendor/plugins/codemirror/addon/search/matchesonscrollbar.js new file mode 100644 index 0000000000000..8a4a82758495b --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/search/matchesonscrollbar.js @@ -0,0 +1,97 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("./searchcursor"), require("../scroll/annotatescrollbar")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "./searchcursor", "../scroll/annotatescrollbar"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineExtension("showMatchesOnScrollbar", function(query, caseFold, options) { + if (typeof options == "string") options = {className: options}; + if (!options) options = {}; + return new SearchAnnotation(this, query, caseFold, options); + }); + + function SearchAnnotation(cm, query, caseFold, options) { + this.cm = cm; + this.options = options; + var annotateOptions = {listenForChanges: false}; + for (var prop in options) annotateOptions[prop] = options[prop]; + if (!annotateOptions.className) annotateOptions.className = "CodeMirror-search-match"; + this.annotation = cm.annotateScrollbar(annotateOptions); + this.query = query; + this.caseFold = caseFold; + this.gap = {from: cm.firstLine(), to: cm.lastLine() + 1}; + this.matches = []; + this.update = null; + + this.findMatches(); + this.annotation.update(this.matches); + + var self = this; + cm.on("change", this.changeHandler = function(_cm, change) { self.onChange(change); }); + } + + var MAX_MATCHES = 1000; + + SearchAnnotation.prototype.findMatches = function() { + if (!this.gap) return; + for (var i = 0; i < this.matches.length; i++) { + var match = this.matches[i]; + if (match.from.line >= this.gap.to) break; + if (match.to.line >= this.gap.from) this.matches.splice(i--, 1); + } + var cursor = this.cm.getSearchCursor(this.query, CodeMirror.Pos(this.gap.from, 0), {caseFold: this.caseFold, multiline: this.options.multiline}); + var maxMatches = this.options && this.options.maxMatches || MAX_MATCHES; + while (cursor.findNext()) { + var match = {from: cursor.from(), to: cursor.to()}; + if (match.from.line >= this.gap.to) break; + this.matches.splice(i++, 0, match); + if (this.matches.length > maxMatches) break; + } + this.gap = null; + }; + + function offsetLine(line, changeStart, sizeChange) { + if (line <= changeStart) return line; + return Math.max(changeStart, line + sizeChange); + } + + SearchAnnotation.prototype.onChange = function(change) { + var startLine = change.from.line; + var endLine = CodeMirror.changeEnd(change).line; + var sizeChange = endLine - change.to.line; + if (this.gap) { + this.gap.from = Math.min(offsetLine(this.gap.from, startLine, sizeChange), change.from.line); + this.gap.to = Math.max(offsetLine(this.gap.to, startLine, sizeChange), change.from.line); + } else { + this.gap = {from: change.from.line, to: endLine + 1}; + } + + if (sizeChange) for (var i = 0; i < this.matches.length; i++) { + var match = this.matches[i]; + var newFrom = offsetLine(match.from.line, startLine, sizeChange); + if (newFrom != match.from.line) match.from = CodeMirror.Pos(newFrom, match.from.ch); + var newTo = offsetLine(match.to.line, startLine, sizeChange); + if (newTo != match.to.line) match.to = CodeMirror.Pos(newTo, match.to.ch); + } + clearTimeout(this.update); + var self = this; + this.update = setTimeout(function() { self.updateAfterChange(); }, 250); + }; + + SearchAnnotation.prototype.updateAfterChange = function() { + this.findMatches(); + this.annotation.update(this.matches); + }; + + SearchAnnotation.prototype.clear = function() { + this.cm.off("change", this.changeHandler); + this.annotation.clear(); + }; +}); diff --git a/public/vendor/plugins/codemirror/addon/search/search.js b/public/vendor/plugins/codemirror/addon/search/search.js new file mode 100644 index 0000000000000..cecdd52ea1cf0 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/search/search.js @@ -0,0 +1,260 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// Define search commands. Depends on dialog.js or another +// implementation of the openDialog method. + +// Replace works a little oddly -- it will do the replace on the next +// Ctrl-G (or whatever is bound to findNext) press. You prevent a +// replace by making sure the match is no longer selected when hitting +// Ctrl-G. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function searchOverlay(query, caseInsensitive) { + if (typeof query == "string") + query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g"); + else if (!query.global) + query = new RegExp(query.source, query.ignoreCase ? "gi" : "g"); + + return {token: function(stream) { + query.lastIndex = stream.pos; + var match = query.exec(stream.string); + if (match && match.index == stream.pos) { + stream.pos += match[0].length || 1; + return "searching"; + } else if (match) { + stream.pos = match.index; + } else { + stream.skipToEnd(); + } + }}; + } + + function SearchState() { + this.posFrom = this.posTo = this.lastQuery = this.query = null; + this.overlay = null; + } + + function getSearchState(cm) { + return cm.state.search || (cm.state.search = new SearchState()); + } + + function queryCaseInsensitive(query) { + return typeof query == "string" && query == query.toLowerCase(); + } + + function getSearchCursor(cm, query, pos) { + // Heuristic: if the query string is all lowercase, do a case insensitive search. + return cm.getSearchCursor(query, pos, {caseFold: queryCaseInsensitive(query), multiline: true}); + } + + function persistentDialog(cm, text, deflt, onEnter, onKeyDown) { + cm.openDialog(text, onEnter, { + value: deflt, + selectValueOnOpen: true, + closeOnEnter: false, + onClose: function() { clearSearch(cm); }, + onKeyDown: onKeyDown + }); + } + + function dialog(cm, text, shortText, deflt, f) { + if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true}); + else f(prompt(shortText, deflt)); + } + + function confirmDialog(cm, text, shortText, fs) { + if (cm.openConfirm) cm.openConfirm(text, fs); + else if (confirm(shortText)) fs[0](); + } + + function parseString(string) { + return string.replace(/\\([nrt\\])/g, function(match, ch) { + if (ch == "n") return "\n" + if (ch == "r") return "\r" + if (ch == "t") return "\t" + if (ch == "\\") return "\\" + return match + }) + } + + function parseQuery(query) { + var isRE = query.match(/^\/(.*)\/([a-z]*)$/); + if (isRE) { + try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); } + catch(e) {} // Not a regular expression after all, do a string search + } else { + query = parseString(query) + } + if (typeof query == "string" ? query == "" : query.test("")) + query = /x^/; + return query; + } + + function startSearch(cm, state, query) { + state.queryText = query; + state.query = parseQuery(query); + cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query)); + state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query)); + cm.addOverlay(state.overlay); + if (cm.showMatchesOnScrollbar) { + if (state.annotate) { state.annotate.clear(); state.annotate = null; } + state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query)); + } + } + + function doSearch(cm, rev, persistent, immediate) { + var state = getSearchState(cm); + if (state.query) return findNext(cm, rev); + var q = cm.getSelection() || state.lastQuery; + if (q instanceof RegExp && q.source == "x^") q = null + if (persistent && cm.openDialog) { + var hiding = null + var searchNext = function(query, event) { + CodeMirror.e_stop(event); + if (!query) return; + if (query != state.queryText) { + startSearch(cm, state, query); + state.posFrom = state.posTo = cm.getCursor(); + } + if (hiding) hiding.style.opacity = 1 + findNext(cm, event.shiftKey, function(_, to) { + var dialog + if (to.line < 3 && document.querySelector && + (dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) && + dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top) + (hiding = dialog).style.opacity = .4 + }) + }; + persistentDialog(cm, getQueryDialog(cm), q, searchNext, function(event, query) { + var keyName = CodeMirror.keyName(event) + var extra = cm.getOption('extraKeys'), cmd = (extra && extra[keyName]) || CodeMirror.keyMap[cm.getOption("keyMap")][keyName] + if (cmd == "findNext" || cmd == "findPrev" || + cmd == "findPersistentNext" || cmd == "findPersistentPrev") { + CodeMirror.e_stop(event); + startSearch(cm, getSearchState(cm), query); + cm.execCommand(cmd); + } else if (cmd == "find" || cmd == "findPersistent") { + CodeMirror.e_stop(event); + searchNext(query, event); + } + }); + if (immediate && q) { + startSearch(cm, state, q); + findNext(cm, rev); + } + } else { + dialog(cm, getQueryDialog(cm), "Search for:", q, function(query) { + if (query && !state.query) cm.operation(function() { + startSearch(cm, state, query); + state.posFrom = state.posTo = cm.getCursor(); + findNext(cm, rev); + }); + }); + } + } + + function findNext(cm, rev, callback) {cm.operation(function() { + var state = getSearchState(cm); + var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo); + if (!cursor.find(rev)) { + cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0)); + if (!cursor.find(rev)) return; + } + cm.setSelection(cursor.from(), cursor.to()); + cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20); + state.posFrom = cursor.from(); state.posTo = cursor.to(); + if (callback) callback(cursor.from(), cursor.to()) + });} + + function clearSearch(cm) {cm.operation(function() { + var state = getSearchState(cm); + state.lastQuery = state.query; + if (!state.query) return; + state.query = state.queryText = null; + cm.removeOverlay(state.overlay); + if (state.annotate) { state.annotate.clear(); state.annotate = null; } + });} + + + function getQueryDialog(cm) { + return '' + cm.phrase("Search:") + ' ' + cm.phrase("(Use /re/ syntax for regexp search)") + ''; + } + function getReplaceQueryDialog(cm) { + return ' ' + cm.phrase("(Use /re/ syntax for regexp search)") + ''; + } + function getReplacementQueryDialog(cm) { + return '' + cm.phrase("With:") + ' '; + } + function getDoReplaceConfirm(cm) { + return '' + cm.phrase("Replace?") + ' '; + } + + function replaceAll(cm, query, text) { + cm.operation(function() { + for (var cursor = getSearchCursor(cm, query); cursor.findNext();) { + if (typeof query != "string") { + var match = cm.getRange(cursor.from(), cursor.to()).match(query); + cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];})); + } else cursor.replace(text); + } + }); + } + + function replace(cm, all) { + if (cm.getOption("readOnly")) return; + var query = cm.getSelection() || getSearchState(cm).lastQuery; + var dialogText = '' + (all ? cm.phrase("Replace all:") : cm.phrase("Replace:")) + ''; + dialog(cm, dialogText + getReplaceQueryDialog(cm), dialogText, query, function(query) { + if (!query) return; + query = parseQuery(query); + dialog(cm, getReplacementQueryDialog(cm), cm.phrase("Replace with:"), "", function(text) { + text = parseString(text) + if (all) { + replaceAll(cm, query, text) + } else { + clearSearch(cm); + var cursor = getSearchCursor(cm, query, cm.getCursor("from")); + var advance = function() { + var start = cursor.from(), match; + if (!(match = cursor.findNext())) { + cursor = getSearchCursor(cm, query); + if (!(match = cursor.findNext()) || + (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return; + } + cm.setSelection(cursor.from(), cursor.to()); + cm.scrollIntoView({from: cursor.from(), to: cursor.to()}); + confirmDialog(cm, getDoReplaceConfirm(cm), cm.phrase("Replace?"), + [function() {doReplace(match);}, advance, + function() {replaceAll(cm, query, text)}]); + }; + var doReplace = function(match) { + cursor.replace(typeof query == "string" ? text : + text.replace(/\$(\d)/g, function(_, i) {return match[i];})); + advance(); + }; + advance(); + } + }); + }); + } + + CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);}; + CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);}; + CodeMirror.commands.findPersistentNext = function(cm) {doSearch(cm, false, true, true);}; + CodeMirror.commands.findPersistentPrev = function(cm) {doSearch(cm, true, true, true);}; + CodeMirror.commands.findNext = doSearch; + CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);}; + CodeMirror.commands.clearSearch = clearSearch; + CodeMirror.commands.replace = replace; + CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);}; +}); diff --git a/public/vendor/plugins/codemirror/addon/search/searchcursor.js b/public/vendor/plugins/codemirror/addon/search/searchcursor.js new file mode 100644 index 0000000000000..aae36dfe5316d --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/search/searchcursor.js @@ -0,0 +1,293 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")) + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod) + else // Plain browser env + mod(CodeMirror) +})(function(CodeMirror) { + "use strict" + var Pos = CodeMirror.Pos + + function regexpFlags(regexp) { + var flags = regexp.flags + return flags != null ? flags : (regexp.ignoreCase ? "i" : "") + + (regexp.global ? "g" : "") + + (regexp.multiline ? "m" : "") + } + + function ensureFlags(regexp, flags) { + var current = regexpFlags(regexp), target = current + for (var i = 0; i < flags.length; i++) if (target.indexOf(flags.charAt(i)) == -1) + target += flags.charAt(i) + return current == target ? regexp : new RegExp(regexp.source, target) + } + + function maybeMultiline(regexp) { + return /\\s|\\n|\n|\\W|\\D|\[\^/.test(regexp.source) + } + + function searchRegexpForward(doc, regexp, start) { + regexp = ensureFlags(regexp, "g") + for (var line = start.line, ch = start.ch, last = doc.lastLine(); line <= last; line++, ch = 0) { + regexp.lastIndex = ch + var string = doc.getLine(line), match = regexp.exec(string) + if (match) + return {from: Pos(line, match.index), + to: Pos(line, match.index + match[0].length), + match: match} + } + } + + function searchRegexpForwardMultiline(doc, regexp, start) { + if (!maybeMultiline(regexp)) return searchRegexpForward(doc, regexp, start) + + regexp = ensureFlags(regexp, "gm") + var string, chunk = 1 + for (var line = start.line, last = doc.lastLine(); line <= last;) { + // This grows the search buffer in exponentially-sized chunks + // between matches, so that nearby matches are fast and don't + // require concatenating the whole document (in case we're + // searching for something that has tons of matches), but at the + // same time, the amount of retries is limited. + for (var i = 0; i < chunk; i++) { + if (line > last) break + var curLine = doc.getLine(line++) + string = string == null ? curLine : string + "\n" + curLine + } + chunk = chunk * 2 + regexp.lastIndex = start.ch + var match = regexp.exec(string) + if (match) { + var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n") + var startLine = start.line + before.length - 1, startCh = before[before.length - 1].length + return {from: Pos(startLine, startCh), + to: Pos(startLine + inside.length - 1, + inside.length == 1 ? startCh + inside[0].length : inside[inside.length - 1].length), + match: match} + } + } + } + + function lastMatchIn(string, regexp) { + var cutOff = 0, match + for (;;) { + regexp.lastIndex = cutOff + var newMatch = regexp.exec(string) + if (!newMatch) return match + match = newMatch + cutOff = match.index + (match[0].length || 1) + if (cutOff == string.length) return match + } + } + + function searchRegexpBackward(doc, regexp, start) { + regexp = ensureFlags(regexp, "g") + for (var line = start.line, ch = start.ch, first = doc.firstLine(); line >= first; line--, ch = -1) { + var string = doc.getLine(line) + if (ch > -1) string = string.slice(0, ch) + var match = lastMatchIn(string, regexp) + if (match) + return {from: Pos(line, match.index), + to: Pos(line, match.index + match[0].length), + match: match} + } + } + + function searchRegexpBackwardMultiline(doc, regexp, start) { + regexp = ensureFlags(regexp, "gm") + var string, chunk = 1 + for (var line = start.line, first = doc.firstLine(); line >= first;) { + for (var i = 0; i < chunk; i++) { + var curLine = doc.getLine(line--) + string = string == null ? curLine.slice(0, start.ch) : curLine + "\n" + string + } + chunk *= 2 + + var match = lastMatchIn(string, regexp) + if (match) { + var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n") + var startLine = line + before.length, startCh = before[before.length - 1].length + return {from: Pos(startLine, startCh), + to: Pos(startLine + inside.length - 1, + inside.length == 1 ? startCh + inside[0].length : inside[inside.length - 1].length), + match: match} + } + } + } + + var doFold, noFold + if (String.prototype.normalize) { + doFold = function(str) { return str.normalize("NFD").toLowerCase() } + noFold = function(str) { return str.normalize("NFD") } + } else { + doFold = function(str) { return str.toLowerCase() } + noFold = function(str) { return str } + } + + // Maps a position in a case-folded line back to a position in the original line + // (compensating for codepoints increasing in number during folding) + function adjustPos(orig, folded, pos, foldFunc) { + if (orig.length == folded.length) return pos + for (var min = 0, max = pos + Math.max(0, orig.length - folded.length);;) { + if (min == max) return min + var mid = (min + max) >> 1 + var len = foldFunc(orig.slice(0, mid)).length + if (len == pos) return mid + else if (len > pos) max = mid + else min = mid + 1 + } + } + + function searchStringForward(doc, query, start, caseFold) { + // Empty string would match anything and never progress, so we + // define it to match nothing instead. + if (!query.length) return null + var fold = caseFold ? doFold : noFold + var lines = fold(query).split(/\r|\n\r?/) + + search: for (var line = start.line, ch = start.ch, last = doc.lastLine() + 1 - lines.length; line <= last; line++, ch = 0) { + var orig = doc.getLine(line).slice(ch), string = fold(orig) + if (lines.length == 1) { + var found = string.indexOf(lines[0]) + if (found == -1) continue search + var start = adjustPos(orig, string, found, fold) + ch + return {from: Pos(line, adjustPos(orig, string, found, fold) + ch), + to: Pos(line, adjustPos(orig, string, found + lines[0].length, fold) + ch)} + } else { + var cutFrom = string.length - lines[0].length + if (string.slice(cutFrom) != lines[0]) continue search + for (var i = 1; i < lines.length - 1; i++) + if (fold(doc.getLine(line + i)) != lines[i]) continue search + var end = doc.getLine(line + lines.length - 1), endString = fold(end), lastLine = lines[lines.length - 1] + if (endString.slice(0, lastLine.length) != lastLine) continue search + return {from: Pos(line, adjustPos(orig, string, cutFrom, fold) + ch), + to: Pos(line + lines.length - 1, adjustPos(end, endString, lastLine.length, fold))} + } + } + } + + function searchStringBackward(doc, query, start, caseFold) { + if (!query.length) return null + var fold = caseFold ? doFold : noFold + var lines = fold(query).split(/\r|\n\r?/) + + search: for (var line = start.line, ch = start.ch, first = doc.firstLine() - 1 + lines.length; line >= first; line--, ch = -1) { + var orig = doc.getLine(line) + if (ch > -1) orig = orig.slice(0, ch) + var string = fold(orig) + if (lines.length == 1) { + var found = string.lastIndexOf(lines[0]) + if (found == -1) continue search + return {from: Pos(line, adjustPos(orig, string, found, fold)), + to: Pos(line, adjustPos(orig, string, found + lines[0].length, fold))} + } else { + var lastLine = lines[lines.length - 1] + if (string.slice(0, lastLine.length) != lastLine) continue search + for (var i = 1, start = line - lines.length + 1; i < lines.length - 1; i++) + if (fold(doc.getLine(start + i)) != lines[i]) continue search + var top = doc.getLine(line + 1 - lines.length), topString = fold(top) + if (topString.slice(topString.length - lines[0].length) != lines[0]) continue search + return {from: Pos(line + 1 - lines.length, adjustPos(top, topString, top.length - lines[0].length, fold)), + to: Pos(line, adjustPos(orig, string, lastLine.length, fold))} + } + } + } + + function SearchCursor(doc, query, pos, options) { + this.atOccurrence = false + this.doc = doc + pos = pos ? doc.clipPos(pos) : Pos(0, 0) + this.pos = {from: pos, to: pos} + + var caseFold + if (typeof options == "object") { + caseFold = options.caseFold + } else { // Backwards compat for when caseFold was the 4th argument + caseFold = options + options = null + } + + if (typeof query == "string") { + if (caseFold == null) caseFold = false + this.matches = function(reverse, pos) { + return (reverse ? searchStringBackward : searchStringForward)(doc, query, pos, caseFold) + } + } else { + query = ensureFlags(query, "gm") + if (!options || options.multiline !== false) + this.matches = function(reverse, pos) { + return (reverse ? searchRegexpBackwardMultiline : searchRegexpForwardMultiline)(doc, query, pos) + } + else + this.matches = function(reverse, pos) { + return (reverse ? searchRegexpBackward : searchRegexpForward)(doc, query, pos) + } + } + } + + SearchCursor.prototype = { + findNext: function() {return this.find(false)}, + findPrevious: function() {return this.find(true)}, + + find: function(reverse) { + var result = this.matches(reverse, this.doc.clipPos(reverse ? this.pos.from : this.pos.to)) + + // Implements weird auto-growing behavior on null-matches for + // backwards-compatiblity with the vim code (unfortunately) + while (result && CodeMirror.cmpPos(result.from, result.to) == 0) { + if (reverse) { + if (result.from.ch) result.from = Pos(result.from.line, result.from.ch - 1) + else if (result.from.line == this.doc.firstLine()) result = null + else result = this.matches(reverse, this.doc.clipPos(Pos(result.from.line - 1))) + } else { + if (result.to.ch < this.doc.getLine(result.to.line).length) result.to = Pos(result.to.line, result.to.ch + 1) + else if (result.to.line == this.doc.lastLine()) result = null + else result = this.matches(reverse, Pos(result.to.line + 1, 0)) + } + } + + if (result) { + this.pos = result + this.atOccurrence = true + return this.pos.match || true + } else { + var end = Pos(reverse ? this.doc.firstLine() : this.doc.lastLine() + 1, 0) + this.pos = {from: end, to: end} + return this.atOccurrence = false + } + }, + + from: function() {if (this.atOccurrence) return this.pos.from}, + to: function() {if (this.atOccurrence) return this.pos.to}, + + replace: function(newText, origin) { + if (!this.atOccurrence) return + var lines = CodeMirror.splitLines(newText) + this.doc.replaceRange(lines, this.pos.from, this.pos.to, origin) + this.pos.to = Pos(this.pos.from.line + lines.length - 1, + lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0)) + } + } + + CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) { + return new SearchCursor(this.doc, query, pos, caseFold) + }) + CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) { + return new SearchCursor(this, query, pos, caseFold) + }) + + CodeMirror.defineExtension("selectMatches", function(query, caseFold) { + var ranges = [] + var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold) + while (cur.findNext()) { + if (CodeMirror.cmpPos(cur.to(), this.getCursor("to")) > 0) break + ranges.push({anchor: cur.from(), head: cur.to()}) + } + if (ranges.length) + this.setSelections(ranges, 0) + }) +}); diff --git a/public/vendor/plugins/codemirror/addon/selection/active-line.js b/public/vendor/plugins/codemirror/addon/selection/active-line.js new file mode 100644 index 0000000000000..c7b14ce07fb1a --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/selection/active-line.js @@ -0,0 +1,72 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + var WRAP_CLASS = "CodeMirror-activeline"; + var BACK_CLASS = "CodeMirror-activeline-background"; + var GUTT_CLASS = "CodeMirror-activeline-gutter"; + + CodeMirror.defineOption("styleActiveLine", false, function(cm, val, old) { + var prev = old == CodeMirror.Init ? false : old; + if (val == prev) return + if (prev) { + cm.off("beforeSelectionChange", selectionChange); + clearActiveLines(cm); + delete cm.state.activeLines; + } + if (val) { + cm.state.activeLines = []; + updateActiveLines(cm, cm.listSelections()); + cm.on("beforeSelectionChange", selectionChange); + } + }); + + function clearActiveLines(cm) { + for (var i = 0; i < cm.state.activeLines.length; i++) { + cm.removeLineClass(cm.state.activeLines[i], "wrap", WRAP_CLASS); + cm.removeLineClass(cm.state.activeLines[i], "background", BACK_CLASS); + cm.removeLineClass(cm.state.activeLines[i], "gutter", GUTT_CLASS); + } + } + + function sameArray(a, b) { + if (a.length != b.length) return false; + for (var i = 0; i < a.length; i++) + if (a[i] != b[i]) return false; + return true; + } + + function updateActiveLines(cm, ranges) { + var active = []; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i]; + var option = cm.getOption("styleActiveLine"); + if (typeof option == "object" && option.nonEmpty ? range.anchor.line != range.head.line : !range.empty()) + continue + var line = cm.getLineHandleVisualStart(range.head.line); + if (active[active.length - 1] != line) active.push(line); + } + if (sameArray(cm.state.activeLines, active)) return; + cm.operation(function() { + clearActiveLines(cm); + for (var i = 0; i < active.length; i++) { + cm.addLineClass(active[i], "wrap", WRAP_CLASS); + cm.addLineClass(active[i], "background", BACK_CLASS); + cm.addLineClass(active[i], "gutter", GUTT_CLASS); + } + cm.state.activeLines = active; + }); + } + + function selectionChange(cm, sel) { + updateActiveLines(cm, sel.ranges); + } +}); diff --git a/public/vendor/plugins/codemirror/addon/selection/mark-selection.js b/public/vendor/plugins/codemirror/addon/selection/mark-selection.js new file mode 100644 index 0000000000000..adfaa62d1a619 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/selection/mark-selection.js @@ -0,0 +1,119 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// Because sometimes you need to mark the selected *text*. +// +// Adds an option 'styleSelectedText' which, when enabled, gives +// selected text the CSS class given as option value, or +// "CodeMirror-selectedtext" when the value is not a string. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("styleSelectedText", false, function(cm, val, old) { + var prev = old && old != CodeMirror.Init; + if (val && !prev) { + cm.state.markedSelection = []; + cm.state.markedSelectionStyle = typeof val == "string" ? val : "CodeMirror-selectedtext"; + reset(cm); + cm.on("cursorActivity", onCursorActivity); + cm.on("change", onChange); + } else if (!val && prev) { + cm.off("cursorActivity", onCursorActivity); + cm.off("change", onChange); + clear(cm); + cm.state.markedSelection = cm.state.markedSelectionStyle = null; + } + }); + + function onCursorActivity(cm) { + if (cm.state.markedSelection) + cm.operation(function() { update(cm); }); + } + + function onChange(cm) { + if (cm.state.markedSelection && cm.state.markedSelection.length) + cm.operation(function() { clear(cm); }); + } + + var CHUNK_SIZE = 8; + var Pos = CodeMirror.Pos; + var cmp = CodeMirror.cmpPos; + + function coverRange(cm, from, to, addAt) { + if (cmp(from, to) == 0) return; + var array = cm.state.markedSelection; + var cls = cm.state.markedSelectionStyle; + for (var line = from.line;;) { + var start = line == from.line ? from : Pos(line, 0); + var endLine = line + CHUNK_SIZE, atEnd = endLine >= to.line; + var end = atEnd ? to : Pos(endLine, 0); + var mark = cm.markText(start, end, {className: cls}); + if (addAt == null) array.push(mark); + else array.splice(addAt++, 0, mark); + if (atEnd) break; + line = endLine; + } + } + + function clear(cm) { + var array = cm.state.markedSelection; + for (var i = 0; i < array.length; ++i) array[i].clear(); + array.length = 0; + } + + function reset(cm) { + clear(cm); + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) + coverRange(cm, ranges[i].from(), ranges[i].to()); + } + + function update(cm) { + if (!cm.somethingSelected()) return clear(cm); + if (cm.listSelections().length > 1) return reset(cm); + + var from = cm.getCursor("start"), to = cm.getCursor("end"); + + var array = cm.state.markedSelection; + if (!array.length) return coverRange(cm, from, to); + + var coverStart = array[0].find(), coverEnd = array[array.length - 1].find(); + if (!coverStart || !coverEnd || to.line - from.line <= CHUNK_SIZE || + cmp(from, coverEnd.to) >= 0 || cmp(to, coverStart.from) <= 0) + return reset(cm); + + while (cmp(from, coverStart.from) > 0) { + array.shift().clear(); + coverStart = array[0].find(); + } + if (cmp(from, coverStart.from) < 0) { + if (coverStart.to.line - from.line < CHUNK_SIZE) { + array.shift().clear(); + coverRange(cm, from, coverStart.to, 0); + } else { + coverRange(cm, from, coverStart.from, 0); + } + } + + while (cmp(to, coverEnd.to) < 0) { + array.pop().clear(); + coverEnd = array[array.length - 1].find(); + } + if (cmp(to, coverEnd.to) > 0) { + if (to.line - coverEnd.from.line < CHUNK_SIZE) { + array.pop().clear(); + coverRange(cm, coverEnd.from, to); + } else { + coverRange(cm, coverEnd.to, to); + } + } + } +}); diff --git a/public/vendor/plugins/codemirror/addon/selection/selection-pointer.js b/public/vendor/plugins/codemirror/addon/selection/selection-pointer.js new file mode 100644 index 0000000000000..f0bd61a33eb2b --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/selection/selection-pointer.js @@ -0,0 +1,98 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("selectionPointer", false, function(cm, val) { + var data = cm.state.selectionPointer; + if (data) { + CodeMirror.off(cm.getWrapperElement(), "mousemove", data.mousemove); + CodeMirror.off(cm.getWrapperElement(), "mouseout", data.mouseout); + CodeMirror.off(window, "scroll", data.windowScroll); + cm.off("cursorActivity", reset); + cm.off("scroll", reset); + cm.state.selectionPointer = null; + cm.display.lineDiv.style.cursor = ""; + } + if (val) { + data = cm.state.selectionPointer = { + value: typeof val == "string" ? val : "default", + mousemove: function(event) { mousemove(cm, event); }, + mouseout: function(event) { mouseout(cm, event); }, + windowScroll: function() { reset(cm); }, + rects: null, + mouseX: null, mouseY: null, + willUpdate: false + }; + CodeMirror.on(cm.getWrapperElement(), "mousemove", data.mousemove); + CodeMirror.on(cm.getWrapperElement(), "mouseout", data.mouseout); + CodeMirror.on(window, "scroll", data.windowScroll); + cm.on("cursorActivity", reset); + cm.on("scroll", reset); + } + }); + + function mousemove(cm, event) { + var data = cm.state.selectionPointer; + if (event.buttons == null ? event.which : event.buttons) { + data.mouseX = data.mouseY = null; + } else { + data.mouseX = event.clientX; + data.mouseY = event.clientY; + } + scheduleUpdate(cm); + } + + function mouseout(cm, event) { + if (!cm.getWrapperElement().contains(event.relatedTarget)) { + var data = cm.state.selectionPointer; + data.mouseX = data.mouseY = null; + scheduleUpdate(cm); + } + } + + function reset(cm) { + cm.state.selectionPointer.rects = null; + scheduleUpdate(cm); + } + + function scheduleUpdate(cm) { + if (!cm.state.selectionPointer.willUpdate) { + cm.state.selectionPointer.willUpdate = true; + setTimeout(function() { + update(cm); + cm.state.selectionPointer.willUpdate = false; + }, 50); + } + } + + function update(cm) { + var data = cm.state.selectionPointer; + if (!data) return; + if (data.rects == null && data.mouseX != null) { + data.rects = []; + if (cm.somethingSelected()) { + for (var sel = cm.display.selectionDiv.firstChild; sel; sel = sel.nextSibling) + data.rects.push(sel.getBoundingClientRect()); + } + } + var inside = false; + if (data.mouseX != null) for (var i = 0; i < data.rects.length; i++) { + var rect = data.rects[i]; + if (rect.left <= data.mouseX && rect.right >= data.mouseX && + rect.top <= data.mouseY && rect.bottom >= data.mouseY) + inside = true; + } + var cursor = inside ? data.value : ""; + if (cm.display.lineDiv.style.cursor != cursor) + cm.display.lineDiv.style.cursor = cursor; + } +}); diff --git a/public/vendor/plugins/codemirror/addon/tern/tern.css b/public/vendor/plugins/codemirror/addon/tern/tern.css new file mode 100644 index 0000000000000..c4b8a2f77e983 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/tern/tern.css @@ -0,0 +1,87 @@ +.CodeMirror-Tern-completion { + padding-left: 22px; + position: relative; + line-height: 1.5; +} +.CodeMirror-Tern-completion:before { + position: absolute; + left: 2px; + bottom: 2px; + border-radius: 50%; + font-size: 12px; + font-weight: bold; + height: 15px; + width: 15px; + line-height: 16px; + text-align: center; + color: white; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.CodeMirror-Tern-completion-unknown:before { + content: "?"; + background: #4bb; +} +.CodeMirror-Tern-completion-object:before { + content: "O"; + background: #77c; +} +.CodeMirror-Tern-completion-fn:before { + content: "F"; + background: #7c7; +} +.CodeMirror-Tern-completion-array:before { + content: "A"; + background: #c66; +} +.CodeMirror-Tern-completion-number:before { + content: "1"; + background: #999; +} +.CodeMirror-Tern-completion-string:before { + content: "S"; + background: #999; +} +.CodeMirror-Tern-completion-bool:before { + content: "B"; + background: #999; +} + +.CodeMirror-Tern-completion-guess { + color: #999; +} + +.CodeMirror-Tern-tooltip { + border: 1px solid silver; + border-radius: 3px; + color: #444; + padding: 2px 5px; + font-size: 90%; + font-family: monospace; + background-color: white; + white-space: pre-wrap; + + max-width: 40em; + position: absolute; + z-index: 10; + -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + box-shadow: 2px 3px 5px rgba(0,0,0,.2); + + transition: opacity 1s; + -moz-transition: opacity 1s; + -webkit-transition: opacity 1s; + -o-transition: opacity 1s; + -ms-transition: opacity 1s; +} + +.CodeMirror-Tern-hint-doc { + max-width: 25em; + margin-top: -3px; +} + +.CodeMirror-Tern-fname { color: black; } +.CodeMirror-Tern-farg { color: #70a; } +.CodeMirror-Tern-farg-current { text-decoration: underline; } +.CodeMirror-Tern-type { color: #07c; } +.CodeMirror-Tern-fhint-guess { opacity: .7; } diff --git a/public/vendor/plugins/codemirror/addon/tern/tern.js b/public/vendor/plugins/codemirror/addon/tern/tern.js new file mode 100644 index 0000000000000..253309d678fd4 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/tern/tern.js @@ -0,0 +1,718 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// Glue code between CodeMirror and Tern. +// +// Create a CodeMirror.TernServer to wrap an actual Tern server, +// register open documents (CodeMirror.Doc instances) with it, and +// call its methods to activate the assisting functions that Tern +// provides. +// +// Options supported (all optional): +// * defs: An array of JSON definition data structures. +// * plugins: An object mapping plugin names to configuration +// options. +// * getFile: A function(name, c) that can be used to access files in +// the project that haven't been loaded yet. Simply do c(null) to +// indicate that a file is not available. +// * fileFilter: A function(value, docName, doc) that will be applied +// to documents before passing them on to Tern. +// * switchToDoc: A function(name, doc) that should, when providing a +// multi-file view, switch the view or focus to the named file. +// * showError: A function(editor, message) that can be used to +// override the way errors are displayed. +// * completionTip: Customize the content in tooltips for completions. +// Is passed a single argument—the completion's data as returned by +// Tern—and may return a string, DOM node, or null to indicate that +// no tip should be shown. By default the docstring is shown. +// * typeTip: Like completionTip, but for the tooltips shown for type +// queries. +// * responseFilter: A function(doc, query, request, error, data) that +// will be applied to the Tern responses before treating them +// +// +// It is possible to run the Tern server in a web worker by specifying +// these additional options: +// * useWorker: Set to true to enable web worker mode. You'll probably +// want to feature detect the actual value you use here, for example +// !!window.Worker. +// * workerScript: The main script of the worker. Point this to +// wherever you are hosting worker.js from this directory. +// * workerDeps: An array of paths pointing (relative to workerScript) +// to the Acorn and Tern libraries and any Tern plugins you want to +// load. Or, if you minified those into a single script and included +// them in the workerScript, simply leave this undefined. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + // declare global: tern + + CodeMirror.TernServer = function(options) { + var self = this; + this.options = options || {}; + var plugins = this.options.plugins || (this.options.plugins = {}); + if (!plugins.doc_comment) plugins.doc_comment = true; + this.docs = Object.create(null); + if (this.options.useWorker) { + this.server = new WorkerServer(this); + } else { + this.server = new tern.Server({ + getFile: function(name, c) { return getFile(self, name, c); }, + async: true, + defs: this.options.defs || [], + plugins: plugins + }); + } + this.trackChange = function(doc, change) { trackChange(self, doc, change); }; + + this.cachedArgHints = null; + this.activeArgHints = null; + this.jumpStack = []; + + this.getHint = function(cm, c) { return hint(self, cm, c); }; + this.getHint.async = true; + }; + + CodeMirror.TernServer.prototype = { + addDoc: function(name, doc) { + var data = {doc: doc, name: name, changed: null}; + this.server.addFile(name, docValue(this, data)); + CodeMirror.on(doc, "change", this.trackChange); + return this.docs[name] = data; + }, + + delDoc: function(id) { + var found = resolveDoc(this, id); + if (!found) return; + CodeMirror.off(found.doc, "change", this.trackChange); + delete this.docs[found.name]; + this.server.delFile(found.name); + }, + + hideDoc: function(id) { + closeArgHints(this); + var found = resolveDoc(this, id); + if (found && found.changed) sendDoc(this, found); + }, + + complete: function(cm) { + cm.showHint({hint: this.getHint}); + }, + + showType: function(cm, pos, c) { showContextInfo(this, cm, pos, "type", c); }, + + showDocs: function(cm, pos, c) { showContextInfo(this, cm, pos, "documentation", c); }, + + updateArgHints: function(cm) { updateArgHints(this, cm); }, + + jumpToDef: function(cm) { jumpToDef(this, cm); }, + + jumpBack: function(cm) { jumpBack(this, cm); }, + + rename: function(cm) { rename(this, cm); }, + + selectName: function(cm) { selectName(this, cm); }, + + request: function (cm, query, c, pos) { + var self = this; + var doc = findDoc(this, cm.getDoc()); + var request = buildRequest(this, doc, query, pos); + var extraOptions = request.query && this.options.queryOptions && this.options.queryOptions[request.query.type] + if (extraOptions) for (var prop in extraOptions) request.query[prop] = extraOptions[prop]; + + this.server.request(request, function (error, data) { + if (!error && self.options.responseFilter) + data = self.options.responseFilter(doc, query, request, error, data); + c(error, data); + }); + }, + + destroy: function () { + closeArgHints(this) + if (this.worker) { + this.worker.terminate(); + this.worker = null; + } + } + }; + + var Pos = CodeMirror.Pos; + var cls = "CodeMirror-Tern-"; + var bigDoc = 250; + + function getFile(ts, name, c) { + var buf = ts.docs[name]; + if (buf) + c(docValue(ts, buf)); + else if (ts.options.getFile) + ts.options.getFile(name, c); + else + c(null); + } + + function findDoc(ts, doc, name) { + for (var n in ts.docs) { + var cur = ts.docs[n]; + if (cur.doc == doc) return cur; + } + if (!name) for (var i = 0;; ++i) { + n = "[doc" + (i || "") + "]"; + if (!ts.docs[n]) { name = n; break; } + } + return ts.addDoc(name, doc); + } + + function resolveDoc(ts, id) { + if (typeof id == "string") return ts.docs[id]; + if (id instanceof CodeMirror) id = id.getDoc(); + if (id instanceof CodeMirror.Doc) return findDoc(ts, id); + } + + function trackChange(ts, doc, change) { + var data = findDoc(ts, doc); + + var argHints = ts.cachedArgHints; + if (argHints && argHints.doc == doc && cmpPos(argHints.start, change.to) >= 0) + ts.cachedArgHints = null; + + var changed = data.changed; + if (changed == null) + data.changed = changed = {from: change.from.line, to: change.from.line}; + var end = change.from.line + (change.text.length - 1); + if (change.from.line < changed.to) changed.to = changed.to - (change.to.line - end); + if (end >= changed.to) changed.to = end + 1; + if (changed.from > change.from.line) changed.from = change.from.line; + + if (doc.lineCount() > bigDoc && change.to - changed.from > 100) setTimeout(function() { + if (data.changed && data.changed.to - data.changed.from > 100) sendDoc(ts, data); + }, 200); + } + + function sendDoc(ts, doc) { + ts.server.request({files: [{type: "full", name: doc.name, text: docValue(ts, doc)}]}, function(error) { + if (error) window.console.error(error); + else doc.changed = null; + }); + } + + // Completion + + function hint(ts, cm, c) { + ts.request(cm, {type: "completions", types: true, docs: true, urls: true}, function(error, data) { + if (error) return showError(ts, cm, error); + var completions = [], after = ""; + var from = data.start, to = data.end; + if (cm.getRange(Pos(from.line, from.ch - 2), from) == "[\"" && + cm.getRange(to, Pos(to.line, to.ch + 2)) != "\"]") + after = "\"]"; + + for (var i = 0; i < data.completions.length; ++i) { + var completion = data.completions[i], className = typeToIcon(completion.type); + if (data.guess) className += " " + cls + "guess"; + completions.push({text: completion.name + after, + displayText: completion.displayName || completion.name, + className: className, + data: completion}); + } + + var obj = {from: from, to: to, list: completions}; + var tooltip = null; + CodeMirror.on(obj, "close", function() { remove(tooltip); }); + CodeMirror.on(obj, "update", function() { remove(tooltip); }); + CodeMirror.on(obj, "select", function(cur, node) { + remove(tooltip); + var content = ts.options.completionTip ? ts.options.completionTip(cur.data) : cur.data.doc; + if (content) { + tooltip = makeTooltip(node.parentNode.getBoundingClientRect().right + window.pageXOffset, + node.getBoundingClientRect().top + window.pageYOffset, content); + tooltip.className += " " + cls + "hint-doc"; + } + }); + c(obj); + }); + } + + function typeToIcon(type) { + var suffix; + if (type == "?") suffix = "unknown"; + else if (type == "number" || type == "string" || type == "bool") suffix = type; + else if (/^fn\(/.test(type)) suffix = "fn"; + else if (/^\[/.test(type)) suffix = "array"; + else suffix = "object"; + return cls + "completion " + cls + "completion-" + suffix; + } + + // Type queries + + function showContextInfo(ts, cm, pos, queryName, c) { + ts.request(cm, queryName, function(error, data) { + if (error) return showError(ts, cm, error); + if (ts.options.typeTip) { + var tip = ts.options.typeTip(data); + } else { + var tip = elt("span", null, elt("strong", null, data.type || "not found")); + if (data.doc) + tip.appendChild(document.createTextNode(" — " + data.doc)); + if (data.url) { + tip.appendChild(document.createTextNode(" ")); + var child = tip.appendChild(elt("a", null, "[docs]")); + child.href = data.url; + child.target = "_blank"; + } + } + tempTooltip(cm, tip, ts); + if (c) c(); + }, pos); + } + + // Maintaining argument hints + + function updateArgHints(ts, cm) { + closeArgHints(ts); + + if (cm.somethingSelected()) return; + var state = cm.getTokenAt(cm.getCursor()).state; + var inner = CodeMirror.innerMode(cm.getMode(), state); + if (inner.mode.name != "javascript") return; + var lex = inner.state.lexical; + if (lex.info != "call") return; + + var ch, argPos = lex.pos || 0, tabSize = cm.getOption("tabSize"); + for (var line = cm.getCursor().line, e = Math.max(0, line - 9), found = false; line >= e; --line) { + var str = cm.getLine(line), extra = 0; + for (var pos = 0;;) { + var tab = str.indexOf("\t", pos); + if (tab == -1) break; + extra += tabSize - (tab + extra) % tabSize - 1; + pos = tab + 1; + } + ch = lex.column - extra; + if (str.charAt(ch) == "(") {found = true; break;} + } + if (!found) return; + + var start = Pos(line, ch); + var cache = ts.cachedArgHints; + if (cache && cache.doc == cm.getDoc() && cmpPos(start, cache.start) == 0) + return showArgHints(ts, cm, argPos); + + ts.request(cm, {type: "type", preferFunction: true, end: start}, function(error, data) { + if (error || !data.type || !(/^fn\(/).test(data.type)) return; + ts.cachedArgHints = { + start: start, + type: parseFnType(data.type), + name: data.exprName || data.name || "fn", + guess: data.guess, + doc: cm.getDoc() + }; + showArgHints(ts, cm, argPos); + }); + } + + function showArgHints(ts, cm, pos) { + closeArgHints(ts); + + var cache = ts.cachedArgHints, tp = cache.type; + var tip = elt("span", cache.guess ? cls + "fhint-guess" : null, + elt("span", cls + "fname", cache.name), "("); + for (var i = 0; i < tp.args.length; ++i) { + if (i) tip.appendChild(document.createTextNode(", ")); + var arg = tp.args[i]; + tip.appendChild(elt("span", cls + "farg" + (i == pos ? " " + cls + "farg-current" : ""), arg.name || "?")); + if (arg.type != "?") { + tip.appendChild(document.createTextNode(":\u00a0")); + tip.appendChild(elt("span", cls + "type", arg.type)); + } + } + tip.appendChild(document.createTextNode(tp.rettype ? ") ->\u00a0" : ")")); + if (tp.rettype) tip.appendChild(elt("span", cls + "type", tp.rettype)); + var place = cm.cursorCoords(null, "page"); + var tooltip = ts.activeArgHints = makeTooltip(place.right + 1, place.bottom, tip) + setTimeout(function() { + tooltip.clear = onEditorActivity(cm, function() { + if (ts.activeArgHints == tooltip) closeArgHints(ts) }) + }, 20) + } + + function parseFnType(text) { + var args = [], pos = 3; + + function skipMatching(upto) { + var depth = 0, start = pos; + for (;;) { + var next = text.charAt(pos); + if (upto.test(next) && !depth) return text.slice(start, pos); + if (/[{\[\(]/.test(next)) ++depth; + else if (/[}\]\)]/.test(next)) --depth; + ++pos; + } + } + + // Parse arguments + if (text.charAt(pos) != ")") for (;;) { + var name = text.slice(pos).match(/^([^, \(\[\{]+): /); + if (name) { + pos += name[0].length; + name = name[1]; + } + args.push({name: name, type: skipMatching(/[\),]/)}); + if (text.charAt(pos) == ")") break; + pos += 2; + } + + var rettype = text.slice(pos).match(/^\) -> (.*)$/); + + return {args: args, rettype: rettype && rettype[1]}; + } + + // Moving to the definition of something + + function jumpToDef(ts, cm) { + function inner(varName) { + var req = {type: "definition", variable: varName || null}; + var doc = findDoc(ts, cm.getDoc()); + ts.server.request(buildRequest(ts, doc, req), function(error, data) { + if (error) return showError(ts, cm, error); + if (!data.file && data.url) { window.open(data.url); return; } + + if (data.file) { + var localDoc = ts.docs[data.file], found; + if (localDoc && (found = findContext(localDoc.doc, data))) { + ts.jumpStack.push({file: doc.name, + start: cm.getCursor("from"), + end: cm.getCursor("to")}); + moveTo(ts, doc, localDoc, found.start, found.end); + return; + } + } + showError(ts, cm, "Could not find a definition."); + }); + } + + if (!atInterestingExpression(cm)) + dialog(cm, "Jump to variable", function(name) { if (name) inner(name); }); + else + inner(); + } + + function jumpBack(ts, cm) { + var pos = ts.jumpStack.pop(), doc = pos && ts.docs[pos.file]; + if (!doc) return; + moveTo(ts, findDoc(ts, cm.getDoc()), doc, pos.start, pos.end); + } + + function moveTo(ts, curDoc, doc, start, end) { + doc.doc.setSelection(start, end); + if (curDoc != doc && ts.options.switchToDoc) { + closeArgHints(ts); + ts.options.switchToDoc(doc.name, doc.doc); + } + } + + // The {line,ch} representation of positions makes this rather awkward. + function findContext(doc, data) { + var before = data.context.slice(0, data.contextOffset).split("\n"); + var startLine = data.start.line - (before.length - 1); + var start = Pos(startLine, (before.length == 1 ? data.start.ch : doc.getLine(startLine).length) - before[0].length); + + var text = doc.getLine(startLine).slice(start.ch); + for (var cur = startLine + 1; cur < doc.lineCount() && text.length < data.context.length; ++cur) + text += "\n" + doc.getLine(cur); + if (text.slice(0, data.context.length) == data.context) return data; + + var cursor = doc.getSearchCursor(data.context, 0, false); + var nearest, nearestDist = Infinity; + while (cursor.findNext()) { + var from = cursor.from(), dist = Math.abs(from.line - start.line) * 10000; + if (!dist) dist = Math.abs(from.ch - start.ch); + if (dist < nearestDist) { nearest = from; nearestDist = dist; } + } + if (!nearest) return null; + + if (before.length == 1) + nearest.ch += before[0].length; + else + nearest = Pos(nearest.line + (before.length - 1), before[before.length - 1].length); + if (data.start.line == data.end.line) + var end = Pos(nearest.line, nearest.ch + (data.end.ch - data.start.ch)); + else + var end = Pos(nearest.line + (data.end.line - data.start.line), data.end.ch); + return {start: nearest, end: end}; + } + + function atInterestingExpression(cm) { + var pos = cm.getCursor("end"), tok = cm.getTokenAt(pos); + if (tok.start < pos.ch && tok.type == "comment") return false; + return /[\w)\]]/.test(cm.getLine(pos.line).slice(Math.max(pos.ch - 1, 0), pos.ch + 1)); + } + + // Variable renaming + + function rename(ts, cm) { + var token = cm.getTokenAt(cm.getCursor()); + if (!/\w/.test(token.string)) return showError(ts, cm, "Not at a variable"); + dialog(cm, "New name for " + token.string, function(newName) { + ts.request(cm, {type: "rename", newName: newName, fullDocs: true}, function(error, data) { + if (error) return showError(ts, cm, error); + applyChanges(ts, data.changes); + }); + }); + } + + function selectName(ts, cm) { + var name = findDoc(ts, cm.doc).name; + ts.request(cm, {type: "refs"}, function(error, data) { + if (error) return showError(ts, cm, error); + var ranges = [], cur = 0; + var curPos = cm.getCursor(); + for (var i = 0; i < data.refs.length; i++) { + var ref = data.refs[i]; + if (ref.file == name) { + ranges.push({anchor: ref.start, head: ref.end}); + if (cmpPos(curPos, ref.start) >= 0 && cmpPos(curPos, ref.end) <= 0) + cur = ranges.length - 1; + } + } + cm.setSelections(ranges, cur); + }); + } + + var nextChangeOrig = 0; + function applyChanges(ts, changes) { + var perFile = Object.create(null); + for (var i = 0; i < changes.length; ++i) { + var ch = changes[i]; + (perFile[ch.file] || (perFile[ch.file] = [])).push(ch); + } + for (var file in perFile) { + var known = ts.docs[file], chs = perFile[file];; + if (!known) continue; + chs.sort(function(a, b) { return cmpPos(b.start, a.start); }); + var origin = "*rename" + (++nextChangeOrig); + for (var i = 0; i < chs.length; ++i) { + var ch = chs[i]; + known.doc.replaceRange(ch.text, ch.start, ch.end, origin); + } + } + } + + // Generic request-building helper + + function buildRequest(ts, doc, query, pos) { + var files = [], offsetLines = 0, allowFragments = !query.fullDocs; + if (!allowFragments) delete query.fullDocs; + if (typeof query == "string") query = {type: query}; + query.lineCharPositions = true; + if (query.end == null) { + query.end = pos || doc.doc.getCursor("end"); + if (doc.doc.somethingSelected()) + query.start = doc.doc.getCursor("start"); + } + var startPos = query.start || query.end; + + if (doc.changed) { + if (doc.doc.lineCount() > bigDoc && allowFragments !== false && + doc.changed.to - doc.changed.from < 100 && + doc.changed.from <= startPos.line && doc.changed.to > query.end.line) { + files.push(getFragmentAround(doc, startPos, query.end)); + query.file = "#0"; + var offsetLines = files[0].offsetLines; + if (query.start != null) query.start = Pos(query.start.line - -offsetLines, query.start.ch); + query.end = Pos(query.end.line - offsetLines, query.end.ch); + } else { + files.push({type: "full", + name: doc.name, + text: docValue(ts, doc)}); + query.file = doc.name; + doc.changed = null; + } + } else { + query.file = doc.name; + } + for (var name in ts.docs) { + var cur = ts.docs[name]; + if (cur.changed && cur != doc) { + files.push({type: "full", name: cur.name, text: docValue(ts, cur)}); + cur.changed = null; + } + } + + return {query: query, files: files}; + } + + function getFragmentAround(data, start, end) { + var doc = data.doc; + var minIndent = null, minLine = null, endLine, tabSize = 4; + for (var p = start.line - 1, min = Math.max(0, p - 50); p >= min; --p) { + var line = doc.getLine(p), fn = line.search(/\bfunction\b/); + if (fn < 0) continue; + var indent = CodeMirror.countColumn(line, null, tabSize); + if (minIndent != null && minIndent <= indent) continue; + minIndent = indent; + minLine = p; + } + if (minLine == null) minLine = min; + var max = Math.min(doc.lastLine(), end.line + 20); + if (minIndent == null || minIndent == CodeMirror.countColumn(doc.getLine(start.line), null, tabSize)) + endLine = max; + else for (endLine = end.line + 1; endLine < max; ++endLine) { + var indent = CodeMirror.countColumn(doc.getLine(endLine), null, tabSize); + if (indent <= minIndent) break; + } + var from = Pos(minLine, 0); + + return {type: "part", + name: data.name, + offsetLines: from.line, + text: doc.getRange(from, Pos(endLine, end.line == endLine ? null : 0))}; + } + + // Generic utilities + + var cmpPos = CodeMirror.cmpPos; + + function elt(tagname, cls /*, ... elts*/) { + var e = document.createElement(tagname); + if (cls) e.className = cls; + for (var i = 2; i < arguments.length; ++i) { + var elt = arguments[i]; + if (typeof elt == "string") elt = document.createTextNode(elt); + e.appendChild(elt); + } + return e; + } + + function dialog(cm, text, f) { + if (cm.openDialog) + cm.openDialog(text + ": ", f); + else + f(prompt(text, "")); + } + + // Tooltips + + function tempTooltip(cm, content, ts) { + if (cm.state.ternTooltip) remove(cm.state.ternTooltip); + var where = cm.cursorCoords(); + var tip = cm.state.ternTooltip = makeTooltip(where.right + 1, where.bottom, content); + function maybeClear() { + old = true; + if (!mouseOnTip) clear(); + } + function clear() { + cm.state.ternTooltip = null; + if (tip.parentNode) fadeOut(tip) + clearActivity() + } + var mouseOnTip = false, old = false; + CodeMirror.on(tip, "mousemove", function() { mouseOnTip = true; }); + CodeMirror.on(tip, "mouseout", function(e) { + var related = e.relatedTarget || e.toElement + if (!related || !CodeMirror.contains(tip, related)) { + if (old) clear(); + else mouseOnTip = false; + } + }); + setTimeout(maybeClear, ts.options.hintDelay ? ts.options.hintDelay : 1700); + var clearActivity = onEditorActivity(cm, clear) + } + + function onEditorActivity(cm, f) { + cm.on("cursorActivity", f) + cm.on("blur", f) + cm.on("scroll", f) + cm.on("setDoc", f) + return function() { + cm.off("cursorActivity", f) + cm.off("blur", f) + cm.off("scroll", f) + cm.off("setDoc", f) + } + } + + function makeTooltip(x, y, content) { + var node = elt("div", cls + "tooltip", content); + node.style.left = x + "px"; + node.style.top = y + "px"; + document.body.appendChild(node); + return node; + } + + function remove(node) { + var p = node && node.parentNode; + if (p) p.removeChild(node); + } + + function fadeOut(tooltip) { + tooltip.style.opacity = "0"; + setTimeout(function() { remove(tooltip); }, 1100); + } + + function showError(ts, cm, msg) { + if (ts.options.showError) + ts.options.showError(cm, msg); + else + tempTooltip(cm, String(msg), ts); + } + + function closeArgHints(ts) { + if (ts.activeArgHints) { + if (ts.activeArgHints.clear) ts.activeArgHints.clear() + remove(ts.activeArgHints) + ts.activeArgHints = null + } + } + + function docValue(ts, doc) { + var val = doc.doc.getValue(); + if (ts.options.fileFilter) val = ts.options.fileFilter(val, doc.name, doc.doc); + return val; + } + + // Worker wrapper + + function WorkerServer(ts) { + var worker = ts.worker = new Worker(ts.options.workerScript); + worker.postMessage({type: "init", + defs: ts.options.defs, + plugins: ts.options.plugins, + scripts: ts.options.workerDeps}); + var msgId = 0, pending = {}; + + function send(data, c) { + if (c) { + data.id = ++msgId; + pending[msgId] = c; + } + worker.postMessage(data); + } + worker.onmessage = function(e) { + var data = e.data; + if (data.type == "getFile") { + getFile(ts, data.name, function(err, text) { + send({type: "getFile", err: String(err), text: text, id: data.id}); + }); + } else if (data.type == "debug") { + window.console.log(data.message); + } else if (data.id && pending[data.id]) { + pending[data.id](data.err, data.body); + delete pending[data.id]; + } + }; + worker.onerror = function(e) { + for (var id in pending) pending[id](e); + pending = {}; + }; + + this.addFile = function(name, text) { send({type: "add", name: name, text: text}); }; + this.delFile = function(name) { send({type: "del", name: name}); }; + this.request = function(body, c) { send({type: "req", body: body}, c); }; + } +}); diff --git a/public/vendor/plugins/codemirror/addon/tern/worker.js b/public/vendor/plugins/codemirror/addon/tern/worker.js new file mode 100644 index 0000000000000..e134ad47d6483 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/tern/worker.js @@ -0,0 +1,44 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// declare global: tern, server + +var server; + +this.onmessage = function(e) { + var data = e.data; + switch (data.type) { + case "init": return startServer(data.defs, data.plugins, data.scripts); + case "add": return server.addFile(data.name, data.text); + case "del": return server.delFile(data.name); + case "req": return server.request(data.body, function(err, reqData) { + postMessage({id: data.id, body: reqData, err: err && String(err)}); + }); + case "getFile": + var c = pending[data.id]; + delete pending[data.id]; + return c(data.err, data.text); + default: throw new Error("Unknown message type: " + data.type); + } +}; + +var nextId = 0, pending = {}; +function getFile(file, c) { + postMessage({type: "getFile", name: file, id: ++nextId}); + pending[nextId] = c; +} + +function startServer(defs, plugins, scripts) { + if (scripts) importScripts.apply(null, scripts); + + server = new tern.Server({ + getFile: getFile, + async: true, + defs: defs, + plugins: plugins + }); +} + +this.console = { + log: function(v) { postMessage({type: "debug", message: v}); } +}; diff --git a/public/vendor/plugins/codemirror/addon/wrap/hardwrap.js b/public/vendor/plugins/codemirror/addon/wrap/hardwrap.js new file mode 100644 index 0000000000000..29cc15f01fd94 --- /dev/null +++ b/public/vendor/plugins/codemirror/addon/wrap/hardwrap.js @@ -0,0 +1,145 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var Pos = CodeMirror.Pos; + + function findParagraph(cm, pos, options) { + var startRE = options.paragraphStart || cm.getHelper(pos, "paragraphStart"); + for (var start = pos.line, first = cm.firstLine(); start > first; --start) { + var line = cm.getLine(start); + if (startRE && startRE.test(line)) break; + if (!/\S/.test(line)) { ++start; break; } + } + var endRE = options.paragraphEnd || cm.getHelper(pos, "paragraphEnd"); + for (var end = pos.line + 1, last = cm.lastLine(); end <= last; ++end) { + var line = cm.getLine(end); + if (endRE && endRE.test(line)) { ++end; break; } + if (!/\S/.test(line)) break; + } + return {from: start, to: end}; + } + + function findBreakPoint(text, column, wrapOn, killTrailingSpace) { + var at = column + while (at < text.length && text.charAt(at) == " ") at++ + for (; at > 0; --at) + if (wrapOn.test(text.slice(at - 1, at + 1))) break; + for (var first = true;; first = false) { + var endOfText = at; + if (killTrailingSpace) + while (text.charAt(endOfText - 1) == " ") --endOfText; + if (endOfText == 0 && first) at = column; + else return {from: endOfText, to: at}; + } + } + + function wrapRange(cm, from, to, options) { + from = cm.clipPos(from); to = cm.clipPos(to); + var column = options.column || 80; + var wrapOn = options.wrapOn || /\s\S|-[^\.\d]/; + var killTrailing = options.killTrailingSpace !== false; + var changes = [], curLine = "", curNo = from.line; + var lines = cm.getRange(from, to, false); + if (!lines.length) return null; + var leadingSpace = lines[0].match(/^[ \t]*/)[0]; + if (leadingSpace.length >= column) column = leadingSpace.length + 1 + + for (var i = 0; i < lines.length; ++i) { + var text = lines[i], oldLen = curLine.length, spaceInserted = 0; + if (curLine && text && !wrapOn.test(curLine.charAt(curLine.length - 1) + text.charAt(0))) { + curLine += " "; + spaceInserted = 1; + } + var spaceTrimmed = ""; + if (i) { + spaceTrimmed = text.match(/^\s*/)[0]; + text = text.slice(spaceTrimmed.length); + } + curLine += text; + if (i) { + var firstBreak = curLine.length > column && leadingSpace == spaceTrimmed && + findBreakPoint(curLine, column, wrapOn, killTrailing); + // If this isn't broken, or is broken at a different point, remove old break + if (!firstBreak || firstBreak.from != oldLen || firstBreak.to != oldLen + spaceInserted) { + changes.push({text: [spaceInserted ? " " : ""], + from: Pos(curNo, oldLen), + to: Pos(curNo + 1, spaceTrimmed.length)}); + } else { + curLine = leadingSpace + text; + ++curNo; + } + } + while (curLine.length > column) { + var bp = findBreakPoint(curLine, column, wrapOn, killTrailing); + changes.push({text: ["", leadingSpace], + from: Pos(curNo, bp.from), + to: Pos(curNo, bp.to)}); + curLine = leadingSpace + curLine.slice(bp.to); + ++curNo; + } + } + if (changes.length) cm.operation(function() { + for (var i = 0; i < changes.length; ++i) { + var change = changes[i]; + if (change.text || CodeMirror.cmpPos(change.from, change.to)) + cm.replaceRange(change.text, change.from, change.to); + } + }); + return changes.length ? {from: changes[0].from, to: CodeMirror.changeEnd(changes[changes.length - 1])} : null; + } + + CodeMirror.defineExtension("wrapParagraph", function(pos, options) { + options = options || {}; + if (!pos) pos = this.getCursor(); + var para = findParagraph(this, pos, options); + return wrapRange(this, Pos(para.from, 0), Pos(para.to - 1), options); + }); + + CodeMirror.commands.wrapLines = function(cm) { + cm.operation(function() { + var ranges = cm.listSelections(), at = cm.lastLine() + 1; + for (var i = ranges.length - 1; i >= 0; i--) { + var range = ranges[i], span; + if (range.empty()) { + var para = findParagraph(cm, range.head, {}); + span = {from: Pos(para.from, 0), to: Pos(para.to - 1)}; + } else { + span = {from: range.from(), to: range.to()}; + } + if (span.to.line >= at) continue; + at = span.from.line; + wrapRange(cm, span.from, span.to, {}); + } + }); + }; + + CodeMirror.defineExtension("wrapRange", function(from, to, options) { + return wrapRange(this, from, to, options || {}); + }); + + CodeMirror.defineExtension("wrapParagraphsInRange", function(from, to, options) { + options = options || {}; + var cm = this, paras = []; + for (var line = from.line; line <= to.line;) { + var para = findParagraph(cm, Pos(line, 0), options); + paras.push(para); + line = para.to; + } + var madeChange = false; + if (paras.length) cm.operation(function() { + for (var i = paras.length - 1; i >= 0; --i) + madeChange = madeChange || wrapRange(cm, Pos(paras[i].from, 0), Pos(paras[i].to - 1), options); + }); + return madeChange; + }); +}); diff --git a/public/vendor/plugins/codemirror/mode/apl/apl.js b/public/vendor/plugins/codemirror/mode/apl/apl.js index caafe4e913526..b1955f6c94268 100644 --- a/public/vendor/plugins/codemirror/mode/apl/apl.js +++ b/public/vendor/plugins/codemirror/mode/apl/apl.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: http://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/public/vendor/plugins/codemirror/mode/apl/index.html b/public/vendor/plugins/codemirror/mode/apl/index.html index 53dda6b58695c..56ab02ffbac4f 100644 --- a/public/vendor/plugins/codemirror/mode/apl/index.html +++ b/public/vendor/plugins/codemirror/mode/apl/index.html @@ -12,7 +12,7 @@ .CodeMirror { border: 2px inset #dee; } IS NULL" to WHERE whatever condiBean is given. - // See https://github.com/go-xorm/xorm/issues/179 + // See https://gitea.com/xorm/xorm/issues/179 if col := table.DeletedColumn(); col != nil && !session.statement.unscoped { // tag "deleted" is enabled var colName = session.engine.Quote(col.Name) if addedTableName { diff --git a/vendor/github.com/go-xorm/xorm/session_get.go b/vendor/xorm.io/xorm/session_get.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/session_get.go rename to vendor/xorm.io/xorm/session_get.go diff --git a/vendor/github.com/go-xorm/xorm/session_insert.go b/vendor/xorm.io/xorm/session_insert.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/session_insert.go rename to vendor/xorm.io/xorm/session_insert.go diff --git a/vendor/github.com/go-xorm/xorm/session_iterate.go b/vendor/xorm.io/xorm/session_iterate.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/session_iterate.go rename to vendor/xorm.io/xorm/session_iterate.go diff --git a/vendor/github.com/go-xorm/xorm/session_query.go b/vendor/xorm.io/xorm/session_query.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/session_query.go rename to vendor/xorm.io/xorm/session_query.go diff --git a/vendor/github.com/go-xorm/xorm/session_raw.go b/vendor/xorm.io/xorm/session_raw.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/session_raw.go rename to vendor/xorm.io/xorm/session_raw.go diff --git a/vendor/github.com/go-xorm/xorm/session_schema.go b/vendor/xorm.io/xorm/session_schema.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/session_schema.go rename to vendor/xorm.io/xorm/session_schema.go diff --git a/vendor/github.com/go-xorm/xorm/session_stats.go b/vendor/xorm.io/xorm/session_stats.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/session_stats.go rename to vendor/xorm.io/xorm/session_stats.go diff --git a/vendor/github.com/go-xorm/xorm/session_tx.go b/vendor/xorm.io/xorm/session_tx.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/session_tx.go rename to vendor/xorm.io/xorm/session_tx.go diff --git a/vendor/github.com/go-xorm/xorm/session_update.go b/vendor/xorm.io/xorm/session_update.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/session_update.go rename to vendor/xorm.io/xorm/session_update.go diff --git a/vendor/github.com/go-xorm/xorm/statement.go b/vendor/xorm.io/xorm/statement.go similarity index 99% rename from vendor/github.com/go-xorm/xorm/statement.go rename to vendor/xorm.io/xorm/statement.go index ae396c4bae4dd..67e352136f60a 100644 --- a/vendor/github.com/go-xorm/xorm/statement.go +++ b/vendor/xorm.io/xorm/statement.go @@ -149,8 +149,12 @@ func (statement *Statement) And(query interface{}, args ...interface{}) *Stateme cond := builder.Expr(query.(string), args...) statement.cond = statement.cond.And(cond) case map[string]interface{}: - cond := builder.Eq(query.(map[string]interface{})) - statement.cond = statement.cond.And(cond) + queryMap := query.(map[string]interface{}) + newMap := make(map[string]interface{}) + for k, v := range queryMap { + newMap[statement.Engine.Quote(k)] = v + } + statement.cond = statement.cond.And(builder.Eq(newMap)) case builder.Cond: cond := query.(builder.Cond) statement.cond = statement.cond.And(cond) diff --git a/vendor/github.com/go-xorm/xorm/statement_args.go b/vendor/xorm.io/xorm/statement_args.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/statement_args.go rename to vendor/xorm.io/xorm/statement_args.go diff --git a/vendor/github.com/go-xorm/xorm/statement_columnmap.go b/vendor/xorm.io/xorm/statement_columnmap.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/statement_columnmap.go rename to vendor/xorm.io/xorm/statement_columnmap.go diff --git a/vendor/github.com/go-xorm/xorm/statement_exprparam.go b/vendor/xorm.io/xorm/statement_exprparam.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/statement_exprparam.go rename to vendor/xorm.io/xorm/statement_exprparam.go diff --git a/vendor/github.com/go-xorm/xorm/statement_quote.go b/vendor/xorm.io/xorm/statement_quote.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/statement_quote.go rename to vendor/xorm.io/xorm/statement_quote.go diff --git a/vendor/github.com/go-xorm/xorm/syslogger.go b/vendor/xorm.io/xorm/syslogger.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/syslogger.go rename to vendor/xorm.io/xorm/syslogger.go diff --git a/vendor/github.com/go-xorm/xorm/tag.go b/vendor/xorm.io/xorm/tag.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/tag.go rename to vendor/xorm.io/xorm/tag.go diff --git a/vendor/github.com/go-xorm/xorm/test_mssql.sh b/vendor/xorm.io/xorm/test_mssql.sh similarity index 100% rename from vendor/github.com/go-xorm/xorm/test_mssql.sh rename to vendor/xorm.io/xorm/test_mssql.sh diff --git a/vendor/github.com/go-xorm/xorm/test_mssql_cache.sh b/vendor/xorm.io/xorm/test_mssql_cache.sh similarity index 100% rename from vendor/github.com/go-xorm/xorm/test_mssql_cache.sh rename to vendor/xorm.io/xorm/test_mssql_cache.sh diff --git a/vendor/github.com/go-xorm/xorm/test_mymysql.sh b/vendor/xorm.io/xorm/test_mymysql.sh similarity index 100% rename from vendor/github.com/go-xorm/xorm/test_mymysql.sh rename to vendor/xorm.io/xorm/test_mymysql.sh diff --git a/vendor/github.com/go-xorm/xorm/test_mymysql_cache.sh b/vendor/xorm.io/xorm/test_mymysql_cache.sh similarity index 100% rename from vendor/github.com/go-xorm/xorm/test_mymysql_cache.sh rename to vendor/xorm.io/xorm/test_mymysql_cache.sh diff --git a/vendor/github.com/go-xorm/xorm/test_mysql.sh b/vendor/xorm.io/xorm/test_mysql.sh similarity index 100% rename from vendor/github.com/go-xorm/xorm/test_mysql.sh rename to vendor/xorm.io/xorm/test_mysql.sh diff --git a/vendor/github.com/go-xorm/xorm/test_mysql_cache.sh b/vendor/xorm.io/xorm/test_mysql_cache.sh similarity index 100% rename from vendor/github.com/go-xorm/xorm/test_mysql_cache.sh rename to vendor/xorm.io/xorm/test_mysql_cache.sh diff --git a/vendor/github.com/go-xorm/xorm/test_postgres.sh b/vendor/xorm.io/xorm/test_postgres.sh similarity index 100% rename from vendor/github.com/go-xorm/xorm/test_postgres.sh rename to vendor/xorm.io/xorm/test_postgres.sh diff --git a/vendor/github.com/go-xorm/xorm/test_postgres_cache.sh b/vendor/xorm.io/xorm/test_postgres_cache.sh similarity index 100% rename from vendor/github.com/go-xorm/xorm/test_postgres_cache.sh rename to vendor/xorm.io/xorm/test_postgres_cache.sh diff --git a/vendor/github.com/go-xorm/xorm/test_sqlite.sh b/vendor/xorm.io/xorm/test_sqlite.sh similarity index 100% rename from vendor/github.com/go-xorm/xorm/test_sqlite.sh rename to vendor/xorm.io/xorm/test_sqlite.sh diff --git a/vendor/github.com/go-xorm/xorm/test_sqlite_cache.sh b/vendor/xorm.io/xorm/test_sqlite_cache.sh similarity index 100% rename from vendor/github.com/go-xorm/xorm/test_sqlite_cache.sh rename to vendor/xorm.io/xorm/test_sqlite_cache.sh diff --git a/vendor/github.com/go-xorm/xorm/test_tidb.sh b/vendor/xorm.io/xorm/test_tidb.sh similarity index 100% rename from vendor/github.com/go-xorm/xorm/test_tidb.sh rename to vendor/xorm.io/xorm/test_tidb.sh diff --git a/vendor/github.com/go-xorm/xorm/transaction.go b/vendor/xorm.io/xorm/transaction.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/transaction.go rename to vendor/xorm.io/xorm/transaction.go diff --git a/vendor/github.com/go-xorm/xorm/types.go b/vendor/xorm.io/xorm/types.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/types.go rename to vendor/xorm.io/xorm/types.go diff --git a/vendor/github.com/go-xorm/xorm/xorm.go b/vendor/xorm.io/xorm/xorm.go similarity index 99% rename from vendor/github.com/go-xorm/xorm/xorm.go rename to vendor/xorm.io/xorm/xorm.go index 26d00d264da93..e1c83b56f23d3 100644 --- a/vendor/github.com/go-xorm/xorm/xorm.go +++ b/vendor/xorm.io/xorm/xorm.go @@ -20,7 +20,7 @@ import ( const ( // Version show the xorm's version - Version string = "0.7.0.0504" + Version string = "0.8.0.1015" ) func regDrvsNDialects() bool { From 115a1cc6807d9de475a3794ef2ad8e56b3c1c5a3 Mon Sep 17 00:00:00 2001 From: zeripath Date: Fri, 18 Oct 2019 00:51:31 +0100 Subject: [PATCH 121/173] Fix building from source docs to ref AppWorkPath (#8567) The current source docs reference AppWorkDir instead of AppWorkPath --- docs/content/doc/installation/from-source.en-us.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/content/doc/installation/from-source.en-us.md b/docs/content/doc/installation/from-source.en-us.md index 9455f93d80c2a..25ed5b790a212 100644 --- a/docs/content/doc/installation/from-source.en-us.md +++ b/docs/content/doc/installation/from-source.en-us.md @@ -118,12 +118,12 @@ launched manually from command line, it can be killed by pressing `Ctrl + C`. ./gitea web ``` -## Changing the default CustomPath, CustomConf and AppWorkDir +## Changing the default CustomPath, CustomConf and AppWorkPath Gitea will search for a number of things from the `CustomPath`. By default this is the `custom/` directory in the current working directory when running Gitea. It will also look for its configuration file `CustomConf` in `$CustomPath/conf/app.ini`, and will use the -current working directory as the relative base path `AppWorkDir` for a number configurable +current working directory as the relative base path `AppWorkPath` for a number configurable values. These values, although useful when developing, may conflict with downstream users preferences. @@ -134,7 +134,7 @@ using the `LDFLAGS` environment variable for `make`. The appropriate settings ar * To set the `CustomPath` use `LDFLAGS="-X \"code.gitea.io/gitea/modules/setting.CustomPath=custom-path\""` * For `CustomConf` you should use `-X \"code.gitea.io/gitea/modules/setting.CustomConf=conf.ini\"` -* For `AppWorkDir` you should use `-X \"code.gitea.io/gitea/modules/setting.AppWorkDir=working-directory\"` +* For `AppWorkPath` you should use `-X \"code.gitea.io/gitea/modules/setting.AppWorkPath=working-path\"` Add as many of the strings with their preceding `-X` to the `LDFLAGS` variable and run `make build` with the appropriate `TAGS` as above. From 37028f0e4ee379438b40c2b44cc714f3ae1d0087 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Thu, 17 Oct 2019 23:53:45 +0000 Subject: [PATCH 122/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_de-DE.ini | 12 ++++++++ options/locale/locale_tr-TR.ini | 50 ++++++++++++++++----------------- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 256b23b20c7dc..c8765127392b4 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -725,6 +725,8 @@ editor.file_editing_no_longer_exists=Die bearbeitete Datei „%s“ existiert ni editor.file_deleting_no_longer_exists=Die Datei '%s' existiert in diesem Repository nicht mehr. editor.file_changed_while_editing=Der Inhalt der Datei hat sich seit dem Beginn der Bearbeitung geändert. Hier klicken, um die Änderungen anzusehen, oder Änderungen erneut comitten, um sie zu überschreiben. editor.file_already_exists=Eine Datei mit dem Namen „%s“ ist bereits in diesem Repository vorhanden. +editor.commit_empty_file_header=Leere Datei committen +editor.commit_empty_file_text=Die Datei, die du gerade commitest ist leer! Fortfahren? editor.no_changes_to_show=Keine Änderungen vorhanden. editor.fail_to_update_file=Fehler beim Ändern/Erstellen der Datei „%s“. Fehler: %v editor.add_subdir=Verzeichnis erstellen… @@ -1331,6 +1333,7 @@ settings.protect_merge_whitelist_committers_desc=Erlaube Nutzern oder Teams auf settings.protect_merge_whitelist_users=Nutzer, die mergen dürfen: settings.protect_merge_whitelist_teams=Teams, die mergen dürfen: settings.protect_check_status_contexts=Statusprüfungen aktivieren +settings.protect_check_status_contexts_desc=Statusprüfungen vor dem Zusammenführen erforderlich. Wähle aus, welche Statusprüfungen durchgeführt werden müssen, bevor Branches zu einem Zweig zusammengeführt werden können, der dieser Regel entspricht. Wenn aktiviert, müssen Bestätigungen zuerst auf einen anderen Zweig verschoben werden, dann nach bestandener Statusprüfung zusammengeführt oder direkt auf einen Zweig verschoben werden, der dieser Regel entspricht. Wenn keine Kontext ausgewählt ist, muss der letzte Commit unabhängig vom Kontext erfolgreich sein. settings.protect_check_status_contexts_list=Statusprüfungen, die in der letzten Woche für dieses Repository gefunden wurden settings.protect_required_approvals=Erforderliche Zustimmungen: settings.protect_required_approvals_desc=Erlaube das Zusammenführen des Pull-Requests nur bei ausreichend positiven Zustimmungen von dafür freigeschalteten Nutzern oder Teams. @@ -1368,6 +1371,10 @@ diff.parent=Ursprung diff.commit=Commit diff.git-notes=Hinweise diff.data_not_available=Keine Diff-Daten verfügbar +diff.options_button=Diff-Optionen +diff.show_diff_stats=Statistiken anzeigen +diff.download_patch=Patch-Datei herunterladen +diff.download_diff=Vergleichs-Datei herunterladen diff.show_split_view=Geteilte Ansicht diff.show_unified_view=Gesamtansicht diff.whitespace_button=Leerzeichen @@ -1450,6 +1457,8 @@ branch.restore_failed=Wiederherstellung des Branches „%s“ fehlgeschlagen. branch.protected_deletion_failed=Branch „%s“ ist geschützt und kann nicht gelöscht werden. branch.restore=Branch „%s“ wiederherstellen branch.download=Branch „%s“ herunterladen +branch.included_desc=Dieser Branch ist im Standard-Branch enthalten +branch.included=Enthalten topic.manage_topics=Themen verwalten topic.done=Fertig @@ -1966,12 +1975,15 @@ mark_as_unread=Als ungelesen markieren mark_all_as_read=Alle als gelesen markieren [gpg] +default_key=Mit Standardschlüssel signiert error.extract_sign=Die Signatur konnte nicht extrahiert werden error.generate_hash=Es konnte kein Hash vom Commit generiert werden error.no_committer_account=Es ist kein Account mit der E-Mail-Adresse des Committers verbunden error.no_gpg_keys_found=Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden error.not_signed_commit=Kein signierter Commit error.failed_retrieval_gpg_keys=Fehler beim Abrufen eines Keys des Commiter-Kontos +error.probable_bad_signature=WARNHINWEIS! Obwohl es einen Schlüssel mit dieser ID in der Datenbank gibt, wird dieser Commit nicht verifiziert! Dieser Commit ist nicht vertrauenswürdig. +error.probable_bad_default_signature=WARNHINWEIS! Obwohl der Standardschlüssel diese ID hat, wird der Commit nicht verifiziert! Dieser Commit ist NICHT vertrauenswürdig. [units] error.no_unit_allowed_repo=Du hast keine Berechtigung, um auf irgendeinen Bereich dieses Repositories zuzugreifen. diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index 0434fbd404abd..72ce12f63aa3f 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -66,7 +66,7 @@ forks=Çatallar activities=Aktiviteler pull_requests=Değişiklik İsteği -issues=Sorunlar +issues=Konular cancel=İptal @@ -455,11 +455,11 @@ unbind=Bağlantıyı Kaldır unbind_success=Sosyal hesabın bağlantısı Gitea hesabınızdan kaldırılmıştır. manage_access_token=Erişim Jetonlarını Yönet -generate_new_token=Yeni Erişim Anahtarı Üret +generate_new_token=Yeni Jeton Üret tokens_desc=Bu jetonlar Gitea API'sini kullanarak hesabınıza erişim sağlar. new_token_desc=Jeton kullanan uygulamalar hesabınıza tam erişime sahiptir. -token_name=Erişim Anahtarı İsmi -generate_token=Erişim Anahtarı Üret +token_name=Jeton İsmi +generate_token=Jeton Üret generate_token_success=Yeni bir jeton oluşturuldu. Tekrar gösterilmeyeceği için şimdi kopyalayın. delete_token=Sil access_token_deletion=Erişim Jetonunu Sil @@ -616,7 +616,7 @@ tree=Ağaç filter_branch_and_tag=Dal veya biçim imini filtrele branches=Dallar tags=Biçim İmleri -issues=Sorunlar +issues=Konular pulls=Değişiklik İstekleri labels=Etiketler milestones=Kilometre Taşları @@ -698,7 +698,7 @@ ext_issues=Dışsal Konular ext_issues.desc=Dışsal konu takip sistemine bağla. issues.desc=Hata raporlarını, görevleri ve kilometre taşlarını yönetmenizi sağlar. -issues.new=Yeni Sorun +issues.new=Yeni Konu issues.new.title_empty=Başlık boş olamaz issues.new.labels=Etiketler issues.new.no_label=Etiket Yok @@ -712,7 +712,7 @@ issues.new.assignees=Atananlar issues.new.clear_assignees=Atamaları Temizle issues.new.no_assignees=Atanan Kişi Yok issues.no_ref=Bölüm/Etiket Belirtilmedi -issues.create=Sorun Oluştur +issues.create=Konu Oluştur issues.new_label=Yeni Etiket issues.new_label_placeholder=Etiket adı issues.new_label_desc_placeholder=Açıklama @@ -743,7 +743,7 @@ issues.filter_milestone_no_select=Tüm kilometre taşları issues.filter_assignee=Atanan issues.filter_assginee_no_select=Tüm atananlar issues.filter_type=Tür -issues.filter_type.all_issues=Tüm Sorunlar +issues.filter_type.all_issues=Tüm Konular issues.filter_type.assigned_to_you=Size atanan issues.filter_type.created_by_you=Sizin oluşturduklarınız issues.filter_type.mentioning_you=Sizden bahsedilen @@ -788,7 +788,7 @@ issues.reopen_comment_issue=Yorum Yap ve Yeniden Aç issues.create_comment=Yorum yap issues.closed_at=`%[2]s kapattı` issues.reopened_at=`%[2]s yeniden açtı` -issues.commit_ref_at=`%[2]s işlemesinde bu sorunu işaret etti` +issues.commit_ref_at=`%[2]s işlemesinde bu konuyu işaret etti` issues.ref_issue_at=`bu konudan bahsetti %[1]s` issues.ref_pull_at=`bu değişiklik isteğinden bahsetti %[1]s` issues.ref_issue_ext_at=`%[1]s'den bu konuya değinildi %[2]s` @@ -804,7 +804,7 @@ issues.label_title=Etiket adı issues.label_description=Etiket açıklaması issues.label_color=Etiket rengi issues.label_count=%d etiket -issues.label_open_issues=%d açık sorun +issues.label_open_issues=%d açık konu issues.label_edit=Düzenle issues.label_delete=Sil issues.label_modify=Etiketi Düzenle @@ -879,23 +879,23 @@ issues.dependency.remove=Kaldır issues.dependency.remove_info=Bu bağımlılığı kaldır issues.dependency.added_dependency=`%[2]s yeni bir bağımlık ekledi %[3]s` issues.dependency.removed_dependency=`%[2]s bir bağımlılığı kaldırdı %[3]s` -issues.dependency.issue_closing_blockedby=Bu değişiklik isteğinin kapatılması aşağıdaki sorunlar nedeniyle engelleniyor -issues.dependency.pr_closing_blockedby=Bu sorunun kapatılması aşağıdaki sorunlar nedeniyle engelleniyor -issues.dependency.issue_close_blocks=Bu sorun aşağıdaki sorunların kapatılmasını engelliyor +issues.dependency.issue_closing_blockedby=Bu değişiklik isteğinin kapatılması aşağıdaki konular nedeniyle engelleniyor +issues.dependency.pr_closing_blockedby=Bu konunun kapatılması aşağıdaki konular tarafından engelleniyor +issues.dependency.issue_close_blocks=Bu konu aşağıdaki konuların kapatılmasını engelliyor issues.dependency.pr_close_blocks=Bu değişiklik isteği aşağıdaki sorunların kapatılmasını engelliyor -issues.dependency.issue_close_blocked=Kapatmadan önce bu sorunu engelleyen tüm sorunları kapatmanız gerekir. -issues.dependency.pr_close_blocked=Birleştirme işleminden önce, bu değişiklik isteğini engelleyen tüm sorunları kapatmanız gerekir. +issues.dependency.issue_close_blocked=Kapatmadan önce bu konuyu engelleyen tüm konuları kapatmanız gerekir. +issues.dependency.pr_close_blocked=Birleştirme işleminden önce, bu değişiklik isteğini engelleyen tüm konuları kapatmanız gerekir. issues.dependency.blocks_short=Engeller issues.dependency.blocked_by_short=Bağımlılıklar issues.dependency.remove_header=Bağımlılığı Kaldır issues.dependency.issue_remove_text=Bu işlem, bu konudaki bağımlılığı kaldıracaktır. Devam edilsin mi? issues.dependency.pr_remove_text=Bu işlem, bu değişiklik isteğindeki bağımlılığı kaldıracaktır. Devam edilsin mi? issues.dependency.setting=Konular ve Değişiklik İstekleri İçin Bağımlılıkları Etkinleştir -issues.dependency.add_error_same_issue=Bir sorunu kendine bağımlı yapamazsınız. -issues.dependency.add_error_dep_issue_not_exist=Bağımlı sorun mevcut değil. +issues.dependency.add_error_same_issue=Bir konuyu kendine bağımlı yapamazsınız. +issues.dependency.add_error_dep_issue_not_exist=Bağımlı konu mevcut değil. issues.dependency.add_error_dep_not_exist=Bağımlılık mevcut değil. issues.dependency.add_error_dep_exists=Bağımlılık zaten var. -issues.dependency.add_error_cannot_create_circular=Birbirini engelleyen iki sorunla bir bağımlılık oluşturamazsınız. +issues.dependency.add_error_cannot_create_circular=Birbirini engelleyen iki konu arasında bağımlılık oluşturamazsınız. issues.dependency.add_error_dep_not_same_repo=Her iki konu da aynı depoda olmalıdır. issues.review.self.approval=Kendi değişiklik isteğinizi onaylayamazsınız. issues.review.self.rejection=Kendi değişiklik isteğinizde değişiklik isteyemezsiniz. @@ -976,8 +976,8 @@ milestones.filter_sort.closest_due_date=En yakın zamanı gelmiş tarih milestones.filter_sort.furthest_due_date=En uzak zamanı gelmiş tarih milestones.filter_sort.least_complete=En az tamamlama milestones.filter_sort.most_complete=En çok tamamlama -milestones.filter_sort.most_issues=En çok sorun -milestones.filter_sort.least_issues=En az sorun +milestones.filter_sort.most_issues=En çok konu +milestones.filter_sort.least_issues=En az konu ext_wiki=Harici Wiki ext_wiki.desc=Harici bir wiki'ye bağlantı. @@ -1569,7 +1569,7 @@ repos.private=Özel repos.watches=İzlemeler repos.stars=Yıldızlar repos.forks=Çatallar -repos.issues=Sorunlar +repos.issues=Konular repos.size=Boyut hooks.add_webhook=Varsayılan Web İstemcisi Ekle @@ -1772,13 +1772,13 @@ notices.delete_success=Sistem bildirimleri silindi. create_repo=depo %s oluşturuldu rename_repo=%[1]s olan depo adını %[3]s buna çevirdi commit_repo=%[4]s deposunda %[3]s dalını itti -create_issue=`%s#%[2]s sorununu açtı` -close_issue=`%s#%[2]s sorununu kapattı` -reopen_issue=`%s#%[2]s sorununu tekrar açtı` +create_issue=`%s#%[2]s konusunu açtı` +close_issue=`%s#%[2]s konusunu kapattı` +reopen_issue=`%s#%[2]s konusunu tekrar açtı` create_pull_request=`%s#%[2]s değişiklik isteğini oluşturdu` close_pull_request=`%s#%[2]s değişiklik isteğini kapattı` reopen_pull_request=`%s#%[2]s değişiklik isteğini tekrar açtı` -comment_issue=`%s#%[2]s sorununa yorum yazdı` +comment_issue=`%s#%[2]s konusuna yorum yazdı` merge_pull_request=`%s#%[2]s değişim isteğini birleştirdi` transfer_repo=depo %s %s'a aktarıldı push_tag=%[3]s deposuna %[2]s etiketi itildi From 17c96ee52b11fe24de66e2ce4f3711d835f49094 Mon Sep 17 00:00:00 2001 From: Wenxuan Zhao Date: Thu, 17 Oct 2019 23:58:36 -0700 Subject: [PATCH 123/173] Allow more than 255 characters for tokens in external_login_user table (#8554) Signed-off-by: Wenxuan Zhao --- models/external_login_user.go | 6 +++--- models/migrations/migrations.go | 2 ++ models/migrations/v101.go | 19 +++++++++++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 models/migrations/v101.go diff --git a/models/external_login_user.go b/models/external_login_user.go index f6357b8274f13..265d855ccf0e6 100644 --- a/models/external_login_user.go +++ b/models/external_login_user.go @@ -28,9 +28,9 @@ type ExternalLoginUser struct { Description string AvatarURL string Location string - AccessToken string - AccessTokenSecret string - RefreshToken string + AccessToken string `xorm:"TEXT"` + AccessTokenSecret string `xorm:"TEXT"` + RefreshToken string `xorm:"TEXT"` ExpiresAt time.Time } diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index ef4f5b823f37d..19b1095cd3444 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -256,6 +256,8 @@ var migrations = []Migration{ NewMigration("add task table and status column for repository table", addTaskTable), // v100 -> v101 NewMigration("update migration repositories' service type", updateMigrationServiceTypes), + // v101 -> v102 + NewMigration("change length of some external login users columns", changeSomeColumnsLengthOfExternalLoginUser), } // Migrate database to current version diff --git a/models/migrations/v101.go b/models/migrations/v101.go new file mode 100644 index 0000000000000..9ef82a2933b19 --- /dev/null +++ b/models/migrations/v101.go @@ -0,0 +1,19 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package migrations + +import ( + "xorm.io/xorm" +) + +func changeSomeColumnsLengthOfExternalLoginUser(x *xorm.Engine) error { + type ExternalLoginUser struct { + AccessToken string `xorm:"TEXT"` + AccessTokenSecret string `xorm:"TEXT"` + RefreshToken string `xorm:"TEXT"` + } + + return x.Sync2(new(ExternalLoginUser)) +} From d44053eeda9128fb2e8f74205db6b998e7820fa2 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Fri, 18 Oct 2019 07:00:14 +0000 Subject: [PATCH 124/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_ja-JP.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 385d803d93afc..6a4eee6424562 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -1458,7 +1458,7 @@ branch.protected_deletion_failed=ブランチ '%s' は保護されています branch.restore=ブランチ '%s' の復元 branch.download=ブランチ '%s' をダウンロード branch.included_desc=このブランチはデフォルトブランチに含まれています -branch.included=Included +branch.included=埋没 topic.manage_topics=トピックの管理 topic.done=完了 From 7c4c01c0fda90d94cf3785f27b505d9fc502fee6 Mon Sep 17 00:00:00 2001 From: John Olheiser <42128690+jolheiser@users.noreply.github.com> Date: Fri, 18 Oct 2019 03:33:19 -0500 Subject: [PATCH 125/173] Fix review webhooks (#8570) Signed-off-by: jolheiser --- models/webhook_discord.go | 12 ++++++++++- routers/repo/pull_review.go | 4 ++-- services/pull/review.go | 40 +++++++++++++++++++++++++------------ 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/models/webhook_discord.go b/models/webhook_discord.go index d7a2de0d1168e..0b190495f2251 100644 --- a/models/webhook_discord.go +++ b/models/webhook_discord.go @@ -413,7 +413,17 @@ func getDiscordPullRequestApprovalPayload(p *api.PullRequestPayload, meta *Disco title = fmt.Sprintf("[%s] Pull request review %s: #%d %s", p.Repository.FullName, action, p.Index, p.PullRequest.Title) text = p.PullRequest.Body - color = warnColor + + switch event { + case HookEventPullRequestApproved: + color = successColor + case HookEventPullRequestRejected: + color = failedColor + case HookEventPullRequestComment: + fallthrough + default: + color = warnColor + } } return &DiscordPayload{ diff --git a/routers/repo/pull_review.go b/routers/repo/pull_review.go index 5eb0dfe9a73d8..7d030988fd93a 100644 --- a/routers/repo/pull_review.go +++ b/routers/repo/pull_review.go @@ -157,7 +157,7 @@ func SubmitReview(ctx *context.Context, form auth.SubmitReviewForm) { return } // No current review. Create a new one! - if review, err = models.CreateReview(models.CreateReviewOptions{ + if review, err = pull_service.CreateReview(models.CreateReviewOptions{ Type: reviewType, Issue: issue, Reviewer: ctx.User, @@ -169,7 +169,7 @@ func SubmitReview(ctx *context.Context, form auth.SubmitReviewForm) { } else { review.Content = form.Content review.Type = reviewType - if err = models.UpdateReview(review); err != nil { + if err = pull_service.UpdateReview(review); err != nil { ctx.ServerError("UpdateReview", err) return } diff --git a/services/pull/review.go b/services/pull/review.go index 3fdfaaff84995..261c2d32d2cab 100644 --- a/services/pull/review.go +++ b/services/pull/review.go @@ -17,9 +17,23 @@ func CreateReview(opts models.CreateReviewOptions) (*models.Review, error) { return nil, err } + return review, reviewHook(review) +} + +// UpdateReview updates a review +func UpdateReview(review *models.Review) error { + err := models.UpdateReview(review) + if err != nil { + return err + } + + return reviewHook(review) +} + +func reviewHook(review *models.Review) error { var reviewHookType models.HookEventType - switch opts.Type { + switch review.Type { case models.ReviewTypeApprove: reviewHookType = models.HookEventPullRequestApproved case models.ReviewTypeComment: @@ -28,30 +42,30 @@ func CreateReview(opts models.CreateReviewOptions) (*models.Review, error) { reviewHookType = models.HookEventPullRequestRejected default: // unsupported review webhook type here - return review, nil + return nil } - pr := opts.Issue.PullRequest + pr := review.Issue.PullRequest if err := pr.LoadIssue(); err != nil { - return nil, err + return err } - mode, err := models.AccessLevel(opts.Issue.Poster, opts.Issue.Repo) + mode, err := models.AccessLevel(review.Issue.Poster, review.Issue.Repo) if err != nil { - return nil, err + return err } - if err := models.PrepareWebhooks(opts.Issue.Repo, reviewHookType, &api.PullRequestPayload{ + if err := models.PrepareWebhooks(review.Issue.Repo, reviewHookType, &api.PullRequestPayload{ Action: api.HookIssueSynchronized, - Index: opts.Issue.Index, + Index: review.Issue.Index, PullRequest: pr.APIFormat(), - Repository: opts.Issue.Repo.APIFormat(mode), - Sender: opts.Reviewer.APIFormat(), + Repository: review.Issue.Repo.APIFormat(mode), + Sender: review.Reviewer.APIFormat(), }); err != nil { - return nil, err + return err } - go models.HookQueue.Add(opts.Issue.Repo.ID) + go models.HookQueue.Add(review.Issue.Repo.ID) - return review, nil + return nil } From fecd8f949dedac0751db99dec590ff12ae56818d Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Fri, 18 Oct 2019 08:35:26 +0000 Subject: [PATCH 126/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_tr-TR.ini | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index 72ce12f63aa3f..d1160340f2a3b 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -1736,6 +1736,7 @@ config.log_config=Log Yapılandırması config.log_mode=Log Modu config.macaron_log_mode=Macaron Günlük Kipi config.own_named_logger=Adlandırılmış Günlük Kaydedicisi +config.routes_to_default_logger=Varsayılan Günlük Kaydedicisine Yönlendirir config.router_log_mode=Yönlendirici Günlük Kipi config.disabled_logger=Devre Dışı config.access_log_mode=Erişim Günlüğü Kipi @@ -1787,6 +1788,7 @@ delete_branch=%[3]s deposundan %[2]s dalı silindi compare_commits=%d işlemeyi karşılaştır compare_commits_general=İşlemeleri karşılaştır mirror_sync_push=işlemeler yansıdan %[4]s deposundaki %[3]s dalına eşitlendi +mirror_sync_delete=%[3]s adresindeki %[2]s referansı eşitlendi ve silindi [tool] ago=%s önce @@ -1828,12 +1830,15 @@ mark_as_unread=Okunmadı olarak işaretle mark_all_as_read=Tümünü okundu olarak işaretle [gpg] +default_key=Varsayılan anahtarla imzalanmış error.extract_sign=İmza çıkarılamadı error.generate_hash=İşlemenin sağlama kodu oluşturulamadı error.no_committer_account=İşleme yapanın e-posta adresine bağlı hesap yok error.no_gpg_keys_found=Veri tabanında bu imza için bilinen anahtar bulunamadı error.not_signed_commit=İmzalı bir işleme değil error.failed_retrieval_gpg_keys=İşleme yapanın hesabına bağlı herhangi bir anahtar alınamadı +error.probable_bad_signature=UYARI! Veritabanında bu kimliğe sahip bir anahtar olmasına rağmen, bu işlemeyi doğrulamaz! Bu işleme ŞÜPHELİDİR. +error.probable_bad_default_signature=UYARI! Varsayılan anahtarın bu kimliği olmasına rağmen, bu işlemeyi doğrulamaz! Bu işleme ŞÜPHELİDİR. [units] error.no_unit_allowed_repo=Bu deponun hiçbir bölümüne erişme izniniz yok. From 945f121262ef5a393d9530b62a82b2c141bbe21c Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 18 Oct 2019 19:13:31 +0800 Subject: [PATCH 127/173] Fix bug on pull requests when transfer head repository (#8564) * fix bug on pull requests when transfer head repository * add migration and fix lint * fix tests and add a cache check on LoadBaseRepo --- models/fixtures/pull_request.yml | 3 --- models/migrations/migrations.go | 2 ++ models/migrations/v102.go | 15 +++++++++++ models/pull.go | 46 ++++++++++++++++++++++---------- models/pull_test.go | 14 ---------- models/user.go | 4 --- modules/migrations/gitea.go | 15 +++++------ routers/api/v1/repo/pull.go | 19 +++++++------ routers/repo/pull.go | 31 +++++++++++---------- services/pull/merge.go | 11 +++++--- 10 files changed, 87 insertions(+), 73 deletions(-) create mode 100644 models/migrations/v102.go diff --git a/models/fixtures/pull_request.yml b/models/fixtures/pull_request.yml index baaaf6bb8a6da..505584ea18dae 100644 --- a/models/fixtures/pull_request.yml +++ b/models/fixtures/pull_request.yml @@ -6,7 +6,6 @@ index: 2 head_repo_id: 1 base_repo_id: 1 - head_user_name: user1 head_branch: branch1 base_branch: master merge_base: 1234567890abcdef @@ -21,7 +20,6 @@ index: 3 head_repo_id: 1 base_repo_id: 1 - head_user_name: user1 head_branch: branch2 base_branch: master merge_base: fedcba9876543210 @@ -35,7 +33,6 @@ index: 1 head_repo_id: 11 base_repo_id: 10 - head_user_name: user13 head_branch: branch2 base_branch: master merge_base: 0abcb056019adb83 diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 19b1095cd3444..8064eccfc17e2 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -258,6 +258,8 @@ var migrations = []Migration{ NewMigration("update migration repositories' service type", updateMigrationServiceTypes), // v101 -> v102 NewMigration("change length of some external login users columns", changeSomeColumnsLengthOfExternalLoginUser), + // v102 -> v103 + NewMigration("update migration repositories' service type", dropColumnHeadUserNameOnPullRequest), } // Migrate database to current version diff --git a/models/migrations/v102.go b/models/migrations/v102.go new file mode 100644 index 0000000000000..74e8574ec320a --- /dev/null +++ b/models/migrations/v102.go @@ -0,0 +1,15 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package migrations + +import ( + "xorm.io/xorm" +) + +func dropColumnHeadUserNameOnPullRequest(x *xorm.Engine) error { + sess := x.NewSession() + defer sess.Close() + return dropTableColumns(sess, "pull_request", "head_user_name") +} diff --git a/models/pull.go b/models/pull.go index 817ea09ccad60..a3554a1b3da89 100644 --- a/models/pull.go +++ b/models/pull.go @@ -66,7 +66,6 @@ type PullRequest struct { HeadRepo *Repository `xorm:"-"` BaseRepoID int64 `xorm:"INDEX"` BaseRepo *Repository `xorm:"-"` - HeadUserName string HeadBranch string BaseBranch string ProtectedBranch *ProtectedBranch `xorm:"-"` @@ -79,6 +78,15 @@ type PullRequest struct { MergedUnix timeutil.TimeStamp `xorm:"updated INDEX"` } +// MustHeadUserName returns the HeadRepo's username if failed return blank +func (pr *PullRequest) MustHeadUserName() string { + if err := pr.LoadHeadRepo(); err != nil { + log.Error("LoadHeadRepo: %v", err) + return "" + } + return pr.HeadRepo.MustOwnerName() +} + // Note: don't try to get Issue because will end up recursive querying. func (pr *PullRequest) loadAttributes(e Engine) (err error) { if pr.HasMerged && pr.Merger == nil { @@ -102,6 +110,10 @@ func (pr *PullRequest) LoadAttributes() error { // LoadBaseRepo loads pull request base repository from database func (pr *PullRequest) LoadBaseRepo() error { if pr.BaseRepo == nil { + if pr.HeadRepoID == pr.BaseRepoID && pr.HeadRepo != nil { + pr.BaseRepo = pr.HeadRepo + return nil + } var repo Repository if has, err := x.ID(pr.BaseRepoID).Get(&repo); err != nil { return err @@ -113,6 +125,24 @@ func (pr *PullRequest) LoadBaseRepo() error { return nil } +// LoadHeadRepo loads pull request head repository from database +func (pr *PullRequest) LoadHeadRepo() error { + if pr.HeadRepo == nil { + if pr.HeadRepoID == pr.BaseRepoID && pr.BaseRepo != nil { + pr.HeadRepo = pr.BaseRepo + return nil + } + var repo Repository + if has, err := x.ID(pr.HeadRepoID).Get(&repo); err != nil { + return err + } else if !has { + return ErrRepoNotExist{ID: pr.BaseRepoID} + } + pr.HeadRepo = &repo + } + return nil +} + // LoadIssue loads issue information from database func (pr *PullRequest) LoadIssue() (err error) { return pr.loadIssue(x) @@ -152,7 +182,7 @@ func (pr *PullRequest) GetDefaultMergeMessage() string { return "" } } - return fmt.Sprintf("Merge branch '%s' of %s/%s into %s", pr.HeadBranch, pr.HeadUserName, pr.HeadRepo.Name, pr.BaseBranch) + return fmt.Sprintf("Merge branch '%s' of %s/%s into %s", pr.HeadBranch, pr.MustHeadUserName(), pr.HeadRepo.Name, pr.BaseBranch) } // GetDefaultSquashMessage returns default message used when squash and merging pull request @@ -1072,18 +1102,6 @@ func (prs PullRequestList) InvalidateCodeComments(doer *User, repo *git.Reposito return prs.invalidateCodeComments(x, doer, repo, branch) } -// ChangeUsernameInPullRequests changes the name of head_user_name -func ChangeUsernameInPullRequests(oldUserName, newUserName string) error { - pr := PullRequest{ - HeadUserName: strings.ToLower(newUserName), - } - _, err := x. - Cols("head_user_name"). - Where("head_user_name = ?", strings.ToLower(oldUserName)). - Update(pr) - return err -} - // checkAndUpdateStatus checks if pull request is possible to leaving checking status, // and set to be either conflict or mergeable. func (pr *PullRequest) checkAndUpdateStatus() { diff --git a/models/pull_test.go b/models/pull_test.go index df051d51bceac..8e2436b1a2e65 100644 --- a/models/pull_test.go +++ b/models/pull_test.go @@ -232,20 +232,6 @@ func TestPullRequestList_LoadAttributes(t *testing.T) { // TODO TestAddTestPullRequestTask -func TestChangeUsernameInPullRequests(t *testing.T) { - assert.NoError(t, PrepareTestDatabase()) - const newUsername = "newusername" - assert.NoError(t, ChangeUsernameInPullRequests("user1", newUsername)) - - prs := make([]*PullRequest, 0, 10) - assert.NoError(t, x.Where("head_user_name = ?", newUsername).Find(&prs)) - assert.Len(t, prs, 2) - for _, pr := range prs { - assert.Equal(t, newUsername, pr.HeadUserName) - } - CheckConsistencyFor(t, &PullRequest{}) -} - func TestPullRequest_IsWorkInProgress(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) diff --git a/models/user.go b/models/user.go index c393d8dce500c..a3679c9a5b01f 100644 --- a/models/user.go +++ b/models/user.go @@ -994,10 +994,6 @@ func ChangeUserName(u *User, newUserName string) (err error) { return ErrUserAlreadyExist{newUserName} } - if err = ChangeUsernameInPullRequests(u.Name, newUserName); err != nil { - return fmt.Errorf("ChangeUsernameInPullRequests: %v", err) - } - // Do not fail if directory does not exist if err = os.Rename(UserPath(u.Name), UserPath(newUserName)); err != nil && !os.IsNotExist(err) { return fmt.Errorf("Rename user directory: %v", err) diff --git a/modules/migrations/gitea.go b/modules/migrations/gitea.go index 2452a7a88322f..a095751c6b1c1 100644 --- a/modules/migrations/gitea.go +++ b/modules/migrations/gitea.go @@ -579,14 +579,13 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR } var pullRequest = models.PullRequest{ - HeadRepoID: g.repo.ID, - HeadBranch: head, - HeadUserName: g.repoOwner, - BaseRepoID: g.repo.ID, - BaseBranch: pr.Base.Ref, - MergeBase: pr.Base.SHA, - Index: pr.Number, - HasMerged: pr.Merged, + HeadRepoID: g.repo.ID, + HeadBranch: head, + BaseRepoID: g.repo.ID, + BaseBranch: pr.Base.Ref, + MergeBase: pr.Base.SHA, + Index: pr.Number, + HasMerged: pr.Merged, Issue: &issue, } diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index 978c8a3f1f491..16ddd10c60f49 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -190,7 +190,7 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption ) // Get repo/branch information - headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch := parseCompareInfo(ctx, form) + _, headRepo, headGitRepo, compareInfo, baseBranch, headBranch := parseCompareInfo(ctx, form) if ctx.Written() { return } @@ -265,15 +265,14 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption DeadlineUnix: deadlineUnix, } pr := &models.PullRequest{ - HeadRepoID: headRepo.ID, - BaseRepoID: repo.ID, - HeadUserName: headUser.Name, - HeadBranch: headBranch, - BaseBranch: baseBranch, - HeadRepo: headRepo, - BaseRepo: repo, - MergeBase: compareInfo.MergeBase, - Type: models.PullRequestGitea, + HeadRepoID: headRepo.ID, + BaseRepoID: repo.ID, + HeadBranch: headBranch, + BaseBranch: baseBranch, + HeadRepo: headRepo, + BaseRepo: repo, + MergeBase: compareInfo.MergeBase, + Type: models.PullRequestGitea, } // Get all assignee IDs diff --git a/routers/repo/pull.go b/routers/repo/pull.go index 8b97e55670987..4001e3a4f80e7 100644 --- a/routers/repo/pull.go +++ b/routers/repo/pull.go @@ -272,12 +272,12 @@ func checkPullInfo(ctx *context.Context) *models.Issue { } func setMergeTarget(ctx *context.Context, pull *models.PullRequest) { - if ctx.Repo.Owner.Name == pull.HeadUserName { + if ctx.Repo.Owner.Name == pull.MustHeadUserName() { ctx.Data["HeadTarget"] = pull.HeadBranch } else if pull.HeadRepo == nil { - ctx.Data["HeadTarget"] = pull.HeadUserName + ":" + pull.HeadBranch + ctx.Data["HeadTarget"] = pull.MustHeadUserName() + ":" + pull.HeadBranch } else { - ctx.Data["HeadTarget"] = pull.HeadUserName + "/" + pull.HeadRepo.Name + ":" + pull.HeadBranch + ctx.Data["HeadTarget"] = pull.MustHeadUserName() + "/" + pull.HeadRepo.Name + ":" + pull.HeadBranch } ctx.Data["BaseTarget"] = pull.BaseBranch } @@ -440,7 +440,7 @@ func ViewPullCommits(ctx *context.Context) { ctx.NotFound("ViewPullCommits", nil) return } - ctx.Data["Username"] = pull.HeadUserName + ctx.Data["Username"] = pull.MustHeadUserName() ctx.Data["Reponame"] = pull.HeadRepo.Name commits = prInfo.Commits } @@ -512,7 +512,7 @@ func ViewPullFiles(ctx *context.Context) { return } - headRepoPath := models.RepoPath(pull.HeadUserName, pull.HeadRepo.Name) + headRepoPath := pull.HeadRepo.RepoPath() headGitRepo, err := git.OpenRepository(headRepoPath) if err != nil { @@ -531,8 +531,8 @@ func ViewPullFiles(ctx *context.Context) { endCommitID = headCommitID gitRepo = headGitRepo - headTarget = path.Join(pull.HeadUserName, pull.HeadRepo.Name) - ctx.Data["Username"] = pull.HeadUserName + headTarget = path.Join(pull.MustHeadUserName(), pull.HeadRepo.Name) + ctx.Data["Username"] = pull.MustHeadUserName() ctx.Data["Reponame"] = pull.HeadRepo.Name } @@ -754,15 +754,14 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm) Content: form.Content, } pullRequest := &models.PullRequest{ - HeadRepoID: headRepo.ID, - BaseRepoID: repo.ID, - HeadUserName: headUser.Name, - HeadBranch: headBranch, - BaseBranch: baseBranch, - HeadRepo: headRepo, - BaseRepo: repo, - MergeBase: prInfo.MergeBase, - Type: models.PullRequestGitea, + HeadRepoID: headRepo.ID, + BaseRepoID: repo.ID, + HeadBranch: headBranch, + BaseBranch: baseBranch, + HeadRepo: headRepo, + BaseRepo: repo, + MergeBase: prInfo.MergeBase, + Type: models.PullRequestGitea, } // FIXME: check error in the case two people send pull request at almost same time, give nice error prompt // instead of 500. diff --git a/services/pull/merge.go b/services/pull/merge.go index 0d762dbc30d02..5eb8eaa4d4701 100644 --- a/services/pull/merge.go +++ b/services/pull/merge.go @@ -71,7 +71,7 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor } }() - headRepoPath := models.RepoPath(pr.HeadUserName, pr.HeadRepo.Name) + headRepoPath := pr.HeadRepo.RepoPath() if err := git.InitRepository(tmpBasePath, false); err != nil { return fmt.Errorf("git init: %v", err) @@ -306,14 +306,17 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor } } - headUser, err := models.GetUserByName(pr.HeadUserName) + var headUser *models.User + err = pr.HeadRepo.GetOwner() if err != nil { if !models.IsErrUserNotExist(err) { - log.Error("Can't find user: %s for head repository - %v", pr.HeadUserName, err) + log.Error("Can't find user: %d for head repository - %v", pr.HeadRepo.OwnerID, err) return err } - log.Error("Can't find user: %s for head repository - defaulting to doer: %s - %v", pr.HeadUserName, doer.Name, err) + log.Error("Can't find user: %d for head repository - defaulting to doer: %s - %v", pr.HeadRepo.OwnerID, doer.Name, err) headUser = doer + } else { + headUser = pr.HeadRepo.Owner } env = models.FullPushingEnvironment( From 23045c7d534619fa31213409fcf5587265bc86b7 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Fri, 18 Oct 2019 11:15:16 +0000 Subject: [PATCH 128/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_tr-TR.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index d1160340f2a3b..a54e3cd70e7fa 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -632,7 +632,7 @@ video_not_supported_in_browser=Tarayıcınız HTML5 'video' etiketini desteklemi audio_not_supported_in_browser=Tarayıcınız HTML5 'audio' etiketini desteklemiyor. stored_lfs=Git LFS ile depolandı commit_graph=İşleme Grafiği -blame=Bahset +blame=Suçlama normal_view=Normal Görünüm line=satır lines=satır From 05e437f8fd29d078af4148f3b2debcb789d8bfac Mon Sep 17 00:00:00 2001 From: Nicholas Smith Date: Fri, 18 Oct 2019 11:26:13 -0500 Subject: [PATCH 129/173] Remove arrows on numeric inputs (#8516) * Nothing needs the arrows for input, especially 2FA * Moved into LESS --- public/css/index.css | 2 ++ public/less/_form.less | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/public/css/index.css b/public/css/index.css index 6fdcb5c225835..7c881bb2741b4 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -396,6 +396,8 @@ i.icon.centerlock{top:1.5em} .user.activate form .inline.field>label,.user.forgot.password form .inline.field>label,.user.reset.password form .inline.field>label,.user.signin form .inline.field>label,.user.signup form .inline.field>label{width:200px} @media only screen and (max-width:768px){.user.activate form .inline.field>label,.user.activate form input,.user.forgot.password form .inline.field>label,.user.forgot.password form input,.user.reset.password form .inline.field>label,.user.reset.password form input,.user.signin form .inline.field>label,.user.signin form input,.user.signup form .inline.field>label,.user.signup form input{width:100%!important} } +.user.activate form input[type=number],.user.forgot.password form input[type=number],.user.reset.password form input[type=number],.user.signin form input[type=number],.user.signup form input[type=number]{-moz-appearance:textfield} +.user.activate form input::-webkit-inner-spin-button,.user.activate form input::-webkit-outer-spin-button,.user.forgot.password form input::-webkit-inner-spin-button,.user.forgot.password form input::-webkit-outer-spin-button,.user.reset.password form input::-webkit-inner-spin-button,.user.reset.password form input::-webkit-outer-spin-button,.user.signin form input::-webkit-inner-spin-button,.user.signin form input::-webkit-outer-spin-button,.user.signup form input::-webkit-inner-spin-button,.user.signup form input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0} .repository.new.fork form,.repository.new.migrate form,.repository.new.repo form{margin:auto} .repository.new.fork form .ui.message,.repository.new.migrate form .ui.message,.repository.new.repo form .ui.message{text-align:center} @media only screen and (min-width:768px){.repository.new.fork form,.repository.new.migrate form,.repository.new.repo form{width:800px!important} diff --git a/public/less/_form.less b/public/less/_form.less index c1a4f80c1005f..2f37666fb63ea 100644 --- a/public/less/_form.less +++ b/public/less/_form.less @@ -140,6 +140,16 @@ width: 100% !important; } } + + input[type=number] { + -moz-appearance: textfield; + } + + input::-webkit-outer-spin-button, + input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; + } } } From 0a004a69cdcad2fa13d3d314cb984718c88a2940 Mon Sep 17 00:00:00 2001 From: John Olheiser <42128690+jolheiser@users.noreply.github.com> Date: Fri, 18 Oct 2019 17:42:04 -0500 Subject: [PATCH 130/173] Improve webhooks (#8583) * Improve webhooks Signed-off-by: jolheiser * Update MSTeams and ReviewPayload comment Signed-off-by: jolheiser * Add repo.FullName to comments Signed-off-by: jolheiser --- models/webhook_dingtalk.go | 24 +++++-- models/webhook_discord.go | 114 ++++++++++++++++++++-------------- models/webhook_msteams.go | 107 +++++++++++++++++++------------ modules/structs/hook.go | 8 +++ services/comments/comments.go | 3 + services/pull/review.go | 5 +- 6 files changed, 167 insertions(+), 94 deletions(-) diff --git a/models/webhook_dingtalk.go b/models/webhook_dingtalk.go index 6a4bdaf06e9b9..1c6c0a83b8b3f 100644 --- a/models/webhook_dingtalk.go +++ b/models/webhook_dingtalk.go @@ -183,22 +183,36 @@ func getDingtalkIssuesPayload(p *api.IssuePayload) (*DingtalkPayload, error) { } func getDingtalkIssueCommentPayload(p *api.IssueCommentPayload) (*DingtalkPayload, error) { - title := fmt.Sprintf("#%d %s", p.Issue.Index, p.Issue.Title) + title := fmt.Sprintf("#%d: %s", p.Issue.Index, p.Issue.Title) url := fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, CommentHashTag(p.Comment.ID)) var content string switch p.Action { case api.HookIssueCommentCreated: - title = "New comment: " + title + if p.IsPull { + title = "New comment on pull request " + title + } else { + title = "New comment on issue " + title + } content = p.Comment.Body case api.HookIssueCommentEdited: - title = "Comment edited: " + title + if p.IsPull { + title = "Comment edited on pull request " + title + } else { + title = "Comment edited on issue " + title + } content = p.Comment.Body case api.HookIssueCommentDeleted: - title = "Comment deleted: " + title + if p.IsPull { + title = "Comment deleted on pull request " + title + } else { + title = "Comment deleted on issue " + title + } url = fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Issue.Index) content = p.Comment.Body } + title = fmt.Sprintf("[%s] %s", p.Repository.FullName, title) + return &DingtalkPayload{ MsgType: "actionCard", ActionCard: dingtalk.ActionCard{ @@ -282,7 +296,7 @@ func getDingtalkPullRequestApprovalPayload(p *api.PullRequestPayload, event Hook } title = fmt.Sprintf("[%s] Pull request review %s : #%d %s", p.Repository.FullName, action, p.Index, p.PullRequest.Title) - text = p.PullRequest.Body + text = p.Review.Content } diff --git a/models/webhook_discord.go b/models/webhook_discord.go index 0b190495f2251..32039edc9d5ae 100644 --- a/models/webhook_discord.go +++ b/models/webhook_discord.go @@ -75,9 +75,14 @@ func color(clr string) int { } var ( - successColor = color("1ac600") - warnColor = color("ffd930") - failedColor = color("ff3232") + greenColor = color("1ac600") + greenColorLight = color("bfe5bf") + yellowColor = color("ffd930") + greyColor = color("4f545c") + purpleColor = color("7289da") + orangeColor = color("eb6420") + orangeColorLight = color("e68d60") + redColor = color("ff3232") ) // SetSecret sets the discord secret @@ -104,7 +109,7 @@ func getDiscordCreatePayload(p *api.CreatePayload, meta *DiscordMeta) (*DiscordP { Title: title, URL: p.Repo.HTMLURL + "/src/" + refName, - Color: successColor, + Color: greenColor, Author: DiscordEmbedAuthor{ Name: p.Sender.UserName, URL: setting.AppURL + p.Sender.UserName, @@ -127,7 +132,7 @@ func getDiscordDeletePayload(p *api.DeletePayload, meta *DiscordMeta) (*DiscordP { Title: title, URL: p.Repo.HTMLURL + "/src/" + refName, - Color: warnColor, + Color: redColor, Author: DiscordEmbedAuthor{ Name: p.Sender.UserName, URL: setting.AppURL + p.Sender.UserName, @@ -149,7 +154,7 @@ func getDiscordForkPayload(p *api.ForkPayload, meta *DiscordMeta) (*DiscordPaylo { Title: title, URL: p.Repo.HTMLURL, - Color: successColor, + Color: greenColor, Author: DiscordEmbedAuthor{ Name: p.Sender.UserName, URL: setting.AppURL + p.Sender.UserName, @@ -199,7 +204,7 @@ func getDiscordPushPayload(p *api.PushPayload, meta *DiscordMeta) (*DiscordPaylo Title: title, Description: text, URL: titleLink, - Color: successColor, + Color: greenColor, Author: DiscordEmbedAuthor{ Name: p.Sender.UserName, URL: setting.AppURL + p.Sender.UserName, @@ -218,48 +223,48 @@ func getDiscordIssuesPayload(p *api.IssuePayload, meta *DiscordMeta) (*DiscordPa case api.HookIssueOpened: title = fmt.Sprintf("[%s] Issue opened: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) text = p.Issue.Body - color = warnColor + color = orangeColor case api.HookIssueClosed: title = fmt.Sprintf("[%s] Issue closed: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) - color = failedColor + color = redColor text = p.Issue.Body case api.HookIssueReOpened: title = fmt.Sprintf("[%s] Issue re-opened: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) text = p.Issue.Body - color = warnColor + color = yellowColor case api.HookIssueEdited: title = fmt.Sprintf("[%s] Issue edited: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) text = p.Issue.Body - color = warnColor + color = yellowColor case api.HookIssueAssigned: title = fmt.Sprintf("[%s] Issue assigned to %s: #%d %s", p.Repository.FullName, p.Issue.Assignee.UserName, p.Index, p.Issue.Title) text = p.Issue.Body - color = successColor + color = greenColor case api.HookIssueUnassigned: title = fmt.Sprintf("[%s] Issue unassigned: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) text = p.Issue.Body - color = warnColor + color = yellowColor case api.HookIssueLabelUpdated: title = fmt.Sprintf("[%s] Issue labels updated: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) text = p.Issue.Body - color = warnColor + color = yellowColor case api.HookIssueLabelCleared: title = fmt.Sprintf("[%s] Issue labels cleared: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) text = p.Issue.Body - color = warnColor + color = yellowColor case api.HookIssueSynchronized: title = fmt.Sprintf("[%s] Issue synchronized: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) text = p.Issue.Body - color = warnColor + color = yellowColor case api.HookIssueMilestoned: title = fmt.Sprintf("[%s] Issue milestone: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) text = p.Issue.Body - color = warnColor + color = yellowColor case api.HookIssueDemilestoned: title = fmt.Sprintf("[%s] Issue clear milestone: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) text = p.Issue.Body - color = warnColor + color = yellowColor } return &DiscordPayload{ @@ -282,26 +287,41 @@ func getDiscordIssuesPayload(p *api.IssuePayload, meta *DiscordMeta) (*DiscordPa } func getDiscordIssueCommentPayload(p *api.IssueCommentPayload, discord *DiscordMeta) (*DiscordPayload, error) { - title := fmt.Sprintf("#%d %s", p.Issue.Index, p.Issue.Title) + title := fmt.Sprintf("#%d: %s", p.Issue.Index, p.Issue.Title) url := fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, CommentHashTag(p.Comment.ID)) content := "" var color int switch p.Action { case api.HookIssueCommentCreated: - title = "New comment: " + title + if p.IsPull { + title = "New comment on pull request " + title + color = greenColorLight + } else { + title = "New comment on issue " + title + color = orangeColorLight + } content = p.Comment.Body - color = successColor case api.HookIssueCommentEdited: - title = "Comment edited: " + title + if p.IsPull { + title = "Comment edited on pull request " + title + } else { + title = "Comment edited on issue " + title + } content = p.Comment.Body - color = warnColor + color = yellowColor case api.HookIssueCommentDeleted: - title = "Comment deleted: " + title + if p.IsPull { + title = "Comment deleted on pull request " + title + } else { + title = "Comment deleted on issue " + title + } url = fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Issue.Index) content = p.Comment.Body - color = warnColor + color = redColor } + title = fmt.Sprintf("[%s] %s", p.Repository.FullName, title) + return &DiscordPayload{ Username: discord.Username, AvatarURL: discord.IconURL, @@ -328,24 +348,24 @@ func getDiscordPullRequestPayload(p *api.PullRequestPayload, meta *DiscordMeta) case api.HookIssueOpened: title = fmt.Sprintf("[%s] Pull request opened: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) text = p.PullRequest.Body - color = warnColor + color = greenColor case api.HookIssueClosed: if p.PullRequest.HasMerged { title = fmt.Sprintf("[%s] Pull request merged: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) - color = successColor + color = purpleColor } else { title = fmt.Sprintf("[%s] Pull request closed: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) - color = failedColor + color = redColor } text = p.PullRequest.Body case api.HookIssueReOpened: title = fmt.Sprintf("[%s] Pull request re-opened: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) text = p.PullRequest.Body - color = warnColor + color = yellowColor case api.HookIssueEdited: title = fmt.Sprintf("[%s] Pull request edited: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) text = p.PullRequest.Body - color = warnColor + color = yellowColor case api.HookIssueAssigned: list := make([]string, len(p.PullRequest.Assignees)) for i, user := range p.PullRequest.Assignees { @@ -355,31 +375,31 @@ func getDiscordPullRequestPayload(p *api.PullRequestPayload, meta *DiscordMeta) strings.Join(list, ", "), p.Index, p.PullRequest.Title) text = p.PullRequest.Body - color = successColor + color = greenColor case api.HookIssueUnassigned: title = fmt.Sprintf("[%s] Pull request unassigned: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) text = p.PullRequest.Body - color = warnColor + color = yellowColor case api.HookIssueLabelUpdated: title = fmt.Sprintf("[%s] Pull request labels updated: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) text = p.PullRequest.Body - color = warnColor + color = yellowColor case api.HookIssueLabelCleared: title = fmt.Sprintf("[%s] Pull request labels cleared: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) text = p.PullRequest.Body - color = warnColor + color = yellowColor case api.HookIssueSynchronized: title = fmt.Sprintf("[%s] Pull request synchronized: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) text = p.PullRequest.Body - color = warnColor + color = yellowColor case api.HookIssueMilestoned: title = fmt.Sprintf("[%s] Pull request milestone: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) text = p.PullRequest.Body - color = warnColor + color = yellowColor case api.HookIssueDemilestoned: title = fmt.Sprintf("[%s] Pull request clear milestone: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) text = p.PullRequest.Body - color = warnColor + color = yellowColor } return &DiscordPayload{ @@ -412,17 +432,17 @@ func getDiscordPullRequestApprovalPayload(p *api.PullRequestPayload, meta *Disco } title = fmt.Sprintf("[%s] Pull request review %s: #%d %s", p.Repository.FullName, action, p.Index, p.PullRequest.Title) - text = p.PullRequest.Body + text = p.Review.Content switch event { case HookEventPullRequestApproved: - color = successColor + color = greenColor case HookEventPullRequestRejected: - color = failedColor + color = redColor case HookEventPullRequestComment: - fallthrough + color = greyColor default: - color = warnColor + color = yellowColor } } @@ -452,10 +472,10 @@ func getDiscordRepositoryPayload(p *api.RepositoryPayload, meta *DiscordMeta) (* case api.HookRepoCreated: title = fmt.Sprintf("[%s] Repository created", p.Repository.FullName) url = p.Repository.HTMLURL - color = successColor + color = greenColor case api.HookRepoDeleted: title = fmt.Sprintf("[%s] Repository deleted", p.Repository.FullName) - color = warnColor + color = redColor } return &DiscordPayload{ @@ -483,15 +503,15 @@ func getDiscordReleasePayload(p *api.ReleasePayload, meta *DiscordMeta) (*Discor case api.HookReleasePublished: title = fmt.Sprintf("[%s] Release created", p.Release.TagName) url = p.Release.URL - color = successColor + color = greenColor case api.HookReleaseUpdated: title = fmt.Sprintf("[%s] Release updated", p.Release.TagName) url = p.Release.URL - color = successColor + color = yellowColor case api.HookReleaseDeleted: title = fmt.Sprintf("[%s] Release deleted", p.Release.TagName) url = p.Release.URL - color = successColor + color = redColor } return &DiscordPayload{ diff --git a/models/webhook_msteams.go b/models/webhook_msteams.go index bdbcdbc9d361f..e8cdcca3ca210 100644 --- a/models/webhook_msteams.go +++ b/models/webhook_msteams.go @@ -74,7 +74,7 @@ func getMSTeamsCreatePayload(p *api.CreatePayload) (*MSTeamsPayload, error) { return &MSTeamsPayload{ Type: "MessageCard", Context: "https://schema.org/extensions", - ThemeColor: fmt.Sprintf("%x", successColor), + ThemeColor: fmt.Sprintf("%x", greenColor), Title: title, Summary: title, Sections: []MSTeamsSection{ @@ -117,7 +117,7 @@ func getMSTeamsDeletePayload(p *api.DeletePayload) (*MSTeamsPayload, error) { return &MSTeamsPayload{ Type: "MessageCard", Context: "https://schema.org/extensions", - ThemeColor: fmt.Sprintf("%x", warnColor), + ThemeColor: fmt.Sprintf("%x", yellowColor), Title: title, Summary: title, Sections: []MSTeamsSection{ @@ -159,7 +159,7 @@ func getMSTeamsForkPayload(p *api.ForkPayload) (*MSTeamsPayload, error) { return &MSTeamsPayload{ Type: "MessageCard", Context: "https://schema.org/extensions", - ThemeColor: fmt.Sprintf("%x", successColor), + ThemeColor: fmt.Sprintf("%x", greenColor), Title: title, Summary: title, Sections: []MSTeamsSection{ @@ -228,7 +228,7 @@ func getMSTeamsPushPayload(p *api.PushPayload) (*MSTeamsPayload, error) { return &MSTeamsPayload{ Type: "MessageCard", Context: "https://schema.org/extensions", - ThemeColor: fmt.Sprintf("%x", successColor), + ThemeColor: fmt.Sprintf("%x", greenColor), Title: title, Summary: title, Sections: []MSTeamsSection{ @@ -272,48 +272,48 @@ func getMSTeamsIssuesPayload(p *api.IssuePayload) (*MSTeamsPayload, error) { case api.HookIssueOpened: title = fmt.Sprintf("[%s] Issue opened: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) text = p.Issue.Body - color = warnColor + color = orangeColor case api.HookIssueClosed: title = fmt.Sprintf("[%s] Issue closed: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) - color = failedColor + color = redColor text = p.Issue.Body case api.HookIssueReOpened: title = fmt.Sprintf("[%s] Issue re-opened: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) text = p.Issue.Body - color = warnColor + color = yellowColor case api.HookIssueEdited: title = fmt.Sprintf("[%s] Issue edited: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) text = p.Issue.Body - color = warnColor + color = yellowColor case api.HookIssueAssigned: title = fmt.Sprintf("[%s] Issue assigned to %s: #%d %s", p.Repository.FullName, p.Issue.Assignee.UserName, p.Index, p.Issue.Title) text = p.Issue.Body - color = successColor + color = greenColor case api.HookIssueUnassigned: title = fmt.Sprintf("[%s] Issue unassigned: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) text = p.Issue.Body - color = warnColor + color = yellowColor case api.HookIssueLabelUpdated: title = fmt.Sprintf("[%s] Issue labels updated: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) text = p.Issue.Body - color = warnColor + color = yellowColor case api.HookIssueLabelCleared: title = fmt.Sprintf("[%s] Issue labels cleared: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) text = p.Issue.Body - color = warnColor + color = yellowColor case api.HookIssueSynchronized: title = fmt.Sprintf("[%s] Issue synchronized: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) text = p.Issue.Body - color = warnColor + color = yellowColor case api.HookIssueMilestoned: title = fmt.Sprintf("[%s] Issue milestone: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) text = p.Issue.Body - color = warnColor + color = yellowColor case api.HookIssueDemilestoned: title = fmt.Sprintf("[%s] Issue clear milestone: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) text = p.Issue.Body - color = warnColor + color = yellowColor } return &MSTeamsPayload{ @@ -356,26 +356,41 @@ func getMSTeamsIssuesPayload(p *api.IssuePayload) (*MSTeamsPayload, error) { } func getMSTeamsIssueCommentPayload(p *api.IssueCommentPayload) (*MSTeamsPayload, error) { - title := fmt.Sprintf("#%d %s", p.Issue.Index, p.Issue.Title) + title := fmt.Sprintf("#%d: %s", p.Issue.Index, p.Issue.Title) url := fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, CommentHashTag(p.Comment.ID)) content := "" var color int switch p.Action { case api.HookIssueCommentCreated: - title = "New comment: " + title + if p.IsPull { + title = "New comment on pull request " + title + color = greenColorLight + } else { + title = "New comment on issue " + title + color = orangeColorLight + } content = p.Comment.Body - color = successColor case api.HookIssueCommentEdited: - title = "Comment edited: " + title + if p.IsPull { + title = "Comment edited on pull request " + title + } else { + title = "Comment edited on issue " + title + } content = p.Comment.Body - color = warnColor + color = yellowColor case api.HookIssueCommentDeleted: - title = "Comment deleted: " + title + if p.IsPull { + title = "Comment deleted on pull request " + title + } else { + title = "Comment deleted on issue " + title + } url = fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Issue.Index) content = p.Comment.Body - color = warnColor + color = redColor } + title = fmt.Sprintf("[%s] %s", p.Repository.FullName, title) + return &MSTeamsPayload{ Type: "MessageCard", Context: "https://schema.org/extensions", @@ -422,24 +437,24 @@ func getMSTeamsPullRequestPayload(p *api.PullRequestPayload) (*MSTeamsPayload, e case api.HookIssueOpened: title = fmt.Sprintf("[%s] Pull request opened: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) text = p.PullRequest.Body - color = warnColor + color = greenColor case api.HookIssueClosed: if p.PullRequest.HasMerged { title = fmt.Sprintf("[%s] Pull request merged: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) - color = successColor + color = purpleColor } else { title = fmt.Sprintf("[%s] Pull request closed: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) - color = failedColor + color = redColor } text = p.PullRequest.Body case api.HookIssueReOpened: title = fmt.Sprintf("[%s] Pull request re-opened: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) text = p.PullRequest.Body - color = warnColor + color = yellowColor case api.HookIssueEdited: title = fmt.Sprintf("[%s] Pull request edited: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) text = p.PullRequest.Body - color = warnColor + color = yellowColor case api.HookIssueAssigned: list := make([]string, len(p.PullRequest.Assignees)) for i, user := range p.PullRequest.Assignees { @@ -449,31 +464,31 @@ func getMSTeamsPullRequestPayload(p *api.PullRequestPayload) (*MSTeamsPayload, e strings.Join(list, ", "), p.Index, p.PullRequest.Title) text = p.PullRequest.Body - color = successColor + color = greenColor case api.HookIssueUnassigned: title = fmt.Sprintf("[%s] Pull request unassigned: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) text = p.PullRequest.Body - color = warnColor + color = yellowColor case api.HookIssueLabelUpdated: title = fmt.Sprintf("[%s] Pull request labels updated: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) text = p.PullRequest.Body - color = warnColor + color = yellowColor case api.HookIssueLabelCleared: title = fmt.Sprintf("[%s] Pull request labels cleared: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) text = p.PullRequest.Body - color = warnColor + color = yellowColor case api.HookIssueSynchronized: title = fmt.Sprintf("[%s] Pull request synchronized: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) text = p.PullRequest.Body - color = warnColor + color = yellowColor case api.HookIssueMilestoned: title = fmt.Sprintf("[%s] Pull request milestone: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) text = p.PullRequest.Body - color = warnColor + color = yellowColor case api.HookIssueDemilestoned: title = fmt.Sprintf("[%s] Pull request clear milestone: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) text = p.PullRequest.Body - color = warnColor + color = yellowColor } return &MSTeamsPayload{ @@ -526,8 +541,18 @@ func getMSTeamsPullRequestApprovalPayload(p *api.PullRequestPayload, event HookE } title = fmt.Sprintf("[%s] Pull request review %s: #%d %s", p.Repository.FullName, action, p.Index, p.PullRequest.Title) - text = p.PullRequest.Body - color = warnColor + text = p.Review.Content + + switch event { + case HookEventPullRequestApproved: + color = greenColor + case HookEventPullRequestRejected: + color = redColor + case HookEventPullRequestComment: + color = greyColor + default: + color = yellowColor + } } return &MSTeamsPayload{ @@ -576,10 +601,10 @@ func getMSTeamsRepositoryPayload(p *api.RepositoryPayload) (*MSTeamsPayload, err case api.HookRepoCreated: title = fmt.Sprintf("[%s] Repository created", p.Repository.FullName) url = p.Repository.HTMLURL - color = successColor + color = greenColor case api.HookRepoDeleted: title = fmt.Sprintf("[%s] Repository deleted", p.Repository.FullName) - color = warnColor + color = yellowColor } return &MSTeamsPayload{ @@ -623,15 +648,15 @@ func getMSTeamsReleasePayload(p *api.ReleasePayload) (*MSTeamsPayload, error) { case api.HookReleasePublished: title = fmt.Sprintf("[%s] Release created", p.Release.TagName) url = p.Release.URL - color = successColor + color = greenColor case api.HookReleaseUpdated: title = fmt.Sprintf("[%s] Release updated", p.Release.TagName) url = p.Release.URL - color = successColor + color = greenColor case api.HookReleaseDeleted: title = fmt.Sprintf("[%s] Release deleted", p.Release.TagName) url = p.Release.URL - color = successColor + color = greenColor } return &MSTeamsPayload{ diff --git a/modules/structs/hook.go b/modules/structs/hook.go index 2c923d36c518c..e03644290466a 100644 --- a/modules/structs/hook.go +++ b/modules/structs/hook.go @@ -236,6 +236,7 @@ type IssueCommentPayload struct { Changes *ChangesPayload `json:"changes,omitempty"` Repository *Repository `json:"repository"` Sender *User `json:"sender"` + IsPull bool `json:"is_pull"` } // SetSecret modifies the secret of the IssueCommentPayload @@ -419,6 +420,7 @@ type PullRequestPayload struct { PullRequest *PullRequest `json:"pull_request"` Repository *Repository `json:"repository"` Sender *User `json:"sender"` + Review *ReviewPayload `json:"review"` } // SetSecret modifies the secret of the PullRequestPayload. @@ -431,6 +433,12 @@ func (p *PullRequestPayload) JSONPayload() ([]byte, error) { return json.MarshalIndent(p, "", " ") } +// ReviewPayload FIXME +type ReviewPayload struct { + Type string `json:"type"` + Content string `json:"content"` +} + //__________ .__ __ //\______ \ ____ ______ ____ _____|__|/ |_ ___________ ___.__. // | _// __ \\____ \ / _ \/ ___/ \ __\/ _ \_ __ < | | diff --git a/services/comments/comments.go b/services/comments/comments.go index e8448e9065ef4..010c0aaac7b98 100644 --- a/services/comments/comments.go +++ b/services/comments/comments.go @@ -38,6 +38,7 @@ func CreateIssueComment(doer *models.User, repo *models.Repository, issue *model Comment: comment.APIFormat(), Repository: repo.APIFormat(mode), Sender: doer.APIFormat(), + IsPull: issue.IsPull, }); err != nil { log.Error("PrepareWebhooks [comment_id: %d]: %v", comment.ID, err) } else { @@ -128,6 +129,7 @@ func UpdateComment(c *models.Comment, doer *models.User, oldContent string) erro }, Repository: c.Issue.Repo.APIFormat(mode), Sender: doer.APIFormat(), + IsPull: c.Issue.IsPull, }); err != nil { log.Error("PrepareWebhooks [comment_id: %d]: %v", c.ID, err) } else { @@ -162,6 +164,7 @@ func DeleteComment(comment *models.Comment, doer *models.User) error { Comment: comment.APIFormat(), Repository: comment.Issue.Repo.APIFormat(mode), Sender: doer.APIFormat(), + IsPull: comment.Issue.IsPull, }); err != nil { log.Error("PrepareWebhooks [comment_id: %d]: %v", comment.ID, err) } else { diff --git a/services/pull/review.go b/services/pull/review.go index 261c2d32d2cab..3388e4bb56301 100644 --- a/services/pull/review.go +++ b/services/pull/review.go @@ -55,13 +55,16 @@ func reviewHook(review *models.Review) error { if err != nil { return err } - if err := models.PrepareWebhooks(review.Issue.Repo, reviewHookType, &api.PullRequestPayload{ Action: api.HookIssueSynchronized, Index: review.Issue.Index, PullRequest: pr.APIFormat(), Repository: review.Issue.Repo.APIFormat(mode), Sender: review.Reviewer.APIFormat(), + Review: &api.ReviewPayload{ + Type: string(reviewHookType), + Content: review.Content, + }, }); err != nil { return err } From 240f46a4220d9b8d38d084dca4ff47d442c12f9c Mon Sep 17 00:00:00 2001 From: John Olheiser <42128690+jolheiser@users.noreply.github.com> Date: Sat, 19 Oct 2019 04:01:33 -0500 Subject: [PATCH 131/173] Fix template error on account page (#8562) --- routers/user/setting/account.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/user/setting/account.go b/routers/user/setting/account.go index e7de2dffd40b4..73799c8bd72e9 100644 --- a/routers/user/setting/account.go +++ b/routers/user/setting/account.go @@ -28,7 +28,6 @@ func Account(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("settings") ctx.Data["PageIsSettingsAccount"] = true ctx.Data["Email"] = ctx.User.Email - ctx.Data["EmailNotificationsPreference"] = ctx.User.EmailNotifications() loadAccountData(ctx) @@ -230,4 +229,5 @@ func loadAccountData(ctx *context.Context) { return } ctx.Data["Emails"] = emails + ctx.Data["EmailNotificationsPreference"] = ctx.User.EmailNotifications() } From 280f4bebbf5883eef94d8a84b21575393ae5e0e1 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 19 Oct 2019 17:48:29 +0800 Subject: [PATCH 132/173] Move issue label operations to issue service package (#8553) * Move issue label operations to issue service package * fix test * fix fmt --- models/issue.go | 88 ----------------------------- models/issue_test.go | 47 ---------------- routers/api/v1/repo/issue_label.go | 2 +- routers/repo/issue_label.go | 4 +- services/issue/label.go | 90 ++++++++++++++++++++++++++++++ services/issue/label_test.go | 59 ++++++++++++++++++++ services/issue/main_test.go | 16 ++++++ 7 files changed, 168 insertions(+), 138 deletions(-) create mode 100644 services/issue/label_test.go create mode 100644 services/issue/main_test.go diff --git a/models/issue.go b/models/issue.go index 525152552cff7..688a412d8c370 100644 --- a/models/issue.go +++ b/models/issue.go @@ -428,52 +428,6 @@ func (issue *Issue) HasLabel(labelID int64) bool { return issue.hasLabel(x, labelID) } -func (issue *Issue) sendLabelUpdatedWebhook(doer *User) { - var err error - - if err = issue.loadRepo(x); err != nil { - log.Error("loadRepo: %v", err) - return - } - - if err = issue.loadPoster(x); err != nil { - log.Error("loadPoster: %v", err) - return - } - - mode, _ := AccessLevel(issue.Poster, issue.Repo) - if issue.IsPull { - if err = issue.loadPullRequest(x); err != nil { - log.Error("loadPullRequest: %v", err) - return - } - if err = issue.PullRequest.LoadIssue(); err != nil { - log.Error("LoadIssue: %v", err) - return - } - err = PrepareWebhooks(issue.Repo, HookEventPullRequest, &api.PullRequestPayload{ - Action: api.HookIssueLabelUpdated, - Index: issue.Index, - PullRequest: issue.PullRequest.APIFormat(), - Repository: issue.Repo.APIFormat(AccessModeNone), - Sender: doer.APIFormat(), - }) - } else { - err = PrepareWebhooks(issue.Repo, HookEventIssues, &api.IssuePayload{ - Action: api.HookIssueLabelUpdated, - Index: issue.Index, - Issue: issue.APIFormat(), - Repository: issue.Repo.APIFormat(mode), - Sender: doer.APIFormat(), - }) - } - if err != nil { - log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err) - } else { - go HookQueue.Add(issue.RepoID) - } -} - // ReplyReference returns tokenized address to use for email reply headers func (issue *Issue) ReplyReference() string { var path string @@ -490,30 +444,10 @@ func (issue *Issue) addLabel(e *xorm.Session, label *Label, doer *User) error { return newIssueLabel(e, issue, label, doer) } -// AddLabel adds a new label to the issue. -func (issue *Issue) AddLabel(doer *User, label *Label) error { - if err := NewIssueLabel(issue, label, doer); err != nil { - return err - } - - issue.sendLabelUpdatedWebhook(doer) - return nil -} - func (issue *Issue) addLabels(e *xorm.Session, labels []*Label, doer *User) error { return newIssueLabels(e, issue, labels, doer) } -// AddLabels adds a list of new labels to the issue. -func (issue *Issue) AddLabels(doer *User, labels []*Label) error { - if err := NewIssueLabels(issue, labels, doer); err != nil { - return err - } - - issue.sendLabelUpdatedWebhook(doer) - return nil -} - func (issue *Issue) getLabels(e Engine) (err error) { if len(issue.Labels) > 0 { return nil @@ -530,28 +464,6 @@ func (issue *Issue) removeLabel(e *xorm.Session, doer *User, label *Label) error return deleteIssueLabel(e, issue, label, doer) } -// RemoveLabel removes a label from issue by given ID. -func (issue *Issue) RemoveLabel(doer *User, label *Label) error { - if err := issue.loadRepo(x); err != nil { - return err - } - - perm, err := GetUserRepoPermission(issue.Repo, doer) - if err != nil { - return err - } - if !perm.CanWriteIssuesOrPulls(issue.IsPull) { - return ErrLabelNotExist{} - } - - if err := DeleteIssueLabel(issue, label, doer); err != nil { - return err - } - - issue.sendLabelUpdatedWebhook(doer) - return nil -} - func (issue *Issue) clearLabels(e *xorm.Session, doer *User) (err error) { if err = issue.getLabels(e); err != nil { return fmt.Errorf("getLabels: %v", err) diff --git a/models/issue_test.go b/models/issue_test.go index 0be3f68808254..7614c2f55449b 100644 --- a/models/issue_test.go +++ b/models/issue_test.go @@ -84,53 +84,6 @@ func TestGetParticipantsByIssueID(t *testing.T) { checkParticipants(1, []int{5}) } -func TestIssue_AddLabel(t *testing.T) { - var tests = []struct { - issueID int64 - labelID int64 - doerID int64 - }{ - {1, 2, 2}, // non-pull-request, not-already-added label - {1, 1, 2}, // non-pull-request, already-added label - {2, 2, 2}, // pull-request, not-already-added label - {2, 1, 2}, // pull-request, already-added label - } - for _, test := range tests { - assert.NoError(t, PrepareTestDatabase()) - issue := AssertExistsAndLoadBean(t, &Issue{ID: test.issueID}).(*Issue) - label := AssertExistsAndLoadBean(t, &Label{ID: test.labelID}).(*Label) - doer := AssertExistsAndLoadBean(t, &User{ID: test.doerID}).(*User) - assert.NoError(t, issue.AddLabel(doer, label)) - AssertExistsAndLoadBean(t, &IssueLabel{IssueID: test.issueID, LabelID: test.labelID}) - } -} - -func TestIssue_AddLabels(t *testing.T) { - var tests = []struct { - issueID int64 - labelIDs []int64 - doerID int64 - }{ - {1, []int64{1, 2}, 2}, // non-pull-request - {1, []int64{}, 2}, // non-pull-request, empty - {2, []int64{1, 2}, 2}, // pull-request - {2, []int64{}, 1}, // pull-request, empty - } - for _, test := range tests { - assert.NoError(t, PrepareTestDatabase()) - issue := AssertExistsAndLoadBean(t, &Issue{ID: test.issueID}).(*Issue) - labels := make([]*Label, len(test.labelIDs)) - for i, labelID := range test.labelIDs { - labels[i] = AssertExistsAndLoadBean(t, &Label{ID: labelID}).(*Label) - } - doer := AssertExistsAndLoadBean(t, &User{ID: test.doerID}).(*User) - assert.NoError(t, issue.AddLabels(doer, labels)) - for _, labelID := range test.labelIDs { - AssertExistsAndLoadBean(t, &IssueLabel{IssueID: test.issueID, LabelID: labelID}) - } - } -} - func TestIssue_ClearLabels(t *testing.T) { var tests = []struct { issueID int64 diff --git a/routers/api/v1/repo/issue_label.go b/routers/api/v1/repo/issue_label.go index 7bd76c24c23cf..e41c1512e2cae 100644 --- a/routers/api/v1/repo/issue_label.go +++ b/routers/api/v1/repo/issue_label.go @@ -117,7 +117,7 @@ func AddIssueLabels(ctx *context.APIContext, form api.IssueLabelsOption) { return } - if err = issue.AddLabels(ctx.User, labels); err != nil { + if err = issue_service.AddLabels(issue, ctx.User, labels); err != nil { ctx.Error(500, "AddLabels", err) return } diff --git a/routers/repo/issue_label.go b/routers/repo/issue_label.go index 53c37e2e9762f..02568f77a6dc2 100644 --- a/routers/repo/issue_label.go +++ b/routers/repo/issue_label.go @@ -162,14 +162,14 @@ func UpdateIssueLabel(ctx *context.Context) { if action == "attach" { for _, issue := range issues { - if err = issue.AddLabel(ctx.User, label); err != nil { + if err = issue_service.AddLabel(issue, ctx.User, label); err != nil { ctx.ServerError("AddLabel", err) return } } } else { for _, issue := range issues { - if err = issue.RemoveLabel(ctx.User, label); err != nil { + if err = issue_service.RemoveLabel(issue, ctx.User, label); err != nil { ctx.ServerError("RemoveLabel", err) return } diff --git a/services/issue/label.go b/services/issue/label.go index 4af8c2b97e04a..b393e5d38c9c4 100644 --- a/services/issue/label.go +++ b/services/issue/label.go @@ -6,9 +6,57 @@ package issue import ( "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/notification" + api "code.gitea.io/gitea/modules/structs" ) +func sendLabelUpdatedWebhook(issue *models.Issue, doer *models.User) { + var err error + + if err = issue.LoadRepo(); err != nil { + log.Error("LoadRepo: %v", err) + return + } + + if err = issue.LoadPoster(); err != nil { + log.Error("LoadPoster: %v", err) + return + } + + mode, _ := models.AccessLevel(issue.Poster, issue.Repo) + if issue.IsPull { + if err = issue.LoadPullRequest(); err != nil { + log.Error("loadPullRequest: %v", err) + return + } + if err = issue.PullRequest.LoadIssue(); err != nil { + log.Error("LoadIssue: %v", err) + return + } + err = models.PrepareWebhooks(issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{ + Action: api.HookIssueLabelUpdated, + Index: issue.Index, + PullRequest: issue.PullRequest.APIFormat(), + Repository: issue.Repo.APIFormat(models.AccessModeNone), + Sender: doer.APIFormat(), + }) + } else { + err = models.PrepareWebhooks(issue.Repo, models.HookEventIssues, &api.IssuePayload{ + Action: api.HookIssueLabelUpdated, + Index: issue.Index, + Issue: issue.APIFormat(), + Repository: issue.Repo.APIFormat(mode), + Sender: doer.APIFormat(), + }) + } + if err != nil { + log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err) + } else { + go models.HookQueue.Add(issue.RepoID) + } +} + // ClearLabels clears all of an issue's labels func ClearLabels(issue *models.Issue, doer *models.User) (err error) { if err = issue.ClearLabels(doer); err != nil { @@ -19,3 +67,45 @@ func ClearLabels(issue *models.Issue, doer *models.User) (err error) { return nil } + +// AddLabel adds a new label to the issue. +func AddLabel(issue *models.Issue, doer *models.User, label *models.Label) error { + if err := models.NewIssueLabel(issue, label, doer); err != nil { + return err + } + + sendLabelUpdatedWebhook(issue, doer) + return nil +} + +// AddLabels adds a list of new labels to the issue. +func AddLabels(issue *models.Issue, doer *models.User, labels []*models.Label) error { + if err := models.NewIssueLabels(issue, labels, doer); err != nil { + return err + } + + sendLabelUpdatedWebhook(issue, doer) + return nil +} + +// RemoveLabel removes a label from issue by given ID. +func RemoveLabel(issue *models.Issue, doer *models.User, label *models.Label) error { + if err := issue.LoadRepo(); err != nil { + return err + } + + perm, err := models.GetUserRepoPermission(issue.Repo, doer) + if err != nil { + return err + } + if !perm.CanWriteIssuesOrPulls(issue.IsPull) { + return models.ErrLabelNotExist{} + } + + if err := models.DeleteIssueLabel(issue, label, doer); err != nil { + return err + } + + sendLabelUpdatedWebhook(issue, doer) + return nil +} diff --git a/services/issue/label_test.go b/services/issue/label_test.go new file mode 100644 index 0000000000000..065202894320a --- /dev/null +++ b/services/issue/label_test.go @@ -0,0 +1,59 @@ +// 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 issue + +import ( + "testing" + + "code.gitea.io/gitea/models" + "github.com/stretchr/testify/assert" +) + +func TestIssue_AddLabels(t *testing.T) { + var tests = []struct { + issueID int64 + labelIDs []int64 + doerID int64 + }{ + {1, []int64{1, 2}, 2}, // non-pull-request + {1, []int64{}, 2}, // non-pull-request, empty + {2, []int64{1, 2}, 2}, // pull-request + {2, []int64{}, 1}, // pull-request, empty + } + for _, test := range tests { + assert.NoError(t, models.PrepareTestDatabase()) + issue := models.AssertExistsAndLoadBean(t, &models.Issue{ID: test.issueID}).(*models.Issue) + labels := make([]*models.Label, len(test.labelIDs)) + for i, labelID := range test.labelIDs { + labels[i] = models.AssertExistsAndLoadBean(t, &models.Label{ID: labelID}).(*models.Label) + } + doer := models.AssertExistsAndLoadBean(t, &models.User{ID: test.doerID}).(*models.User) + assert.NoError(t, AddLabels(issue, doer, labels)) + for _, labelID := range test.labelIDs { + models.AssertExistsAndLoadBean(t, &models.IssueLabel{IssueID: test.issueID, LabelID: labelID}) + } + } +} + +func TestIssue_AddLabel(t *testing.T) { + var tests = []struct { + issueID int64 + labelID int64 + doerID int64 + }{ + {1, 2, 2}, // non-pull-request, not-already-added label + {1, 1, 2}, // non-pull-request, already-added label + {2, 2, 2}, // pull-request, not-already-added label + {2, 1, 2}, // pull-request, already-added label + } + for _, test := range tests { + assert.NoError(t, models.PrepareTestDatabase()) + issue := models.AssertExistsAndLoadBean(t, &models.Issue{ID: test.issueID}).(*models.Issue) + label := models.AssertExistsAndLoadBean(t, &models.Label{ID: test.labelID}).(*models.Label) + doer := models.AssertExistsAndLoadBean(t, &models.User{ID: test.doerID}).(*models.User) + assert.NoError(t, AddLabel(issue, doer, label)) + models.AssertExistsAndLoadBean(t, &models.IssueLabel{IssueID: test.issueID, LabelID: test.labelID}) + } +} diff --git a/services/issue/main_test.go b/services/issue/main_test.go new file mode 100644 index 0000000000000..b056678a42261 --- /dev/null +++ b/services/issue/main_test.go @@ -0,0 +1,16 @@ +// Copyright 2019 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 issue + +import ( + "path/filepath" + "testing" + + "code.gitea.io/gitea/models" +) + +func TestMain(m *testing.M) { + models.MainTest(m, filepath.Join("..", "..")) +} From 5a62ae5cbf47cf6537f6c95aba4b1d04dea5f5af Mon Sep 17 00:00:00 2001 From: zeripath Date: Sat, 19 Oct 2019 15:27:15 +0100 Subject: [PATCH 133/173] Add setting to disable BASIC authentication (#8586) Closes #8561. --- custom/conf/app.ini.sample | 6 +++++- docs/content/doc/advanced/config-cheat-sheet.en-us.md | 4 ++++ modules/auth/auth.go | 3 +++ modules/setting/service.go | 2 ++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index e4e791d4a7e9d..c08dd62e7d28f 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -436,6 +436,10 @@ ALLOW_ONLY_EXTERNAL_REGISTRATION = false REQUIRE_SIGNIN_VIEW = false ; Mail notification ENABLE_NOTIFY_MAIL = false +; This setting enables gitea to be signed in with HTTP BASIC Authentication using the user's password +; If you set this to false you will not be able to access the tokens endpoints on the API with your password +; Please note that setting this to false will not disable OAuth Basic or Basic authentication using a token +ENABLE_BASIC_AUTHENTICATION = true ; More detail: https://github.com/gogits/gogs/issues/165 ENABLE_REVERSE_PROXY_AUTHENTICATION = false ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = false @@ -866,6 +870,6 @@ TOKEN = QUEUE_TYPE = channel ; Task queue length, available only when `QUEUE_TYPE` is `channel`. QUEUE_LENGTH = 1000 -; Task queue connction string, available only when `QUEUE_TYPE` is `redis`. +; Task queue connction string, available only when `QUEUE_TYPE` is `redis`. ; If there is a password of redis, use `addrs=127.0.0.1:6379 password=123 db=0`. QUEUE_CONN_STR = "addrs=127.0.0.1:6379 db=0" diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 0df88c23e8622..678f8df2382d3 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -265,6 +265,10 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `REQUIRE_SIGNIN_VIEW`: **false**: Enable this to force users to log in to view any page. - `ENABLE_NOTIFY_MAIL`: **false**: Enable this to send e-mail to watchers of a repository when something happens, like creating issues. Requires `Mailer` to be enabled. +- `ENABLE_BASIC_AUTHENTICATION`: **true**: Disable this to disallow authenticaton using HTTP + BASIC and the user's password. Please note if you disable this you will not be able to access the + tokens API endpoints using a password. Further, this only disables BASIC authentication using the + password - not tokens or OAuth Basic. - `ENABLE_REVERSE_PROXY_AUTHENTICATION`: **false**: Enable this to allow reverse proxy authentication. - `ENABLE_REVERSE_PROXY_AUTO_REGISTRATION`: **false**: Enable this to allow auto-registration for reverse authentication. diff --git a/modules/auth/auth.go b/modules/auth/auth.go index 624bb15cbf6e4..1ba149f0f875c 100644 --- a/modules/auth/auth.go +++ b/modules/auth/auth.go @@ -224,6 +224,9 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool) } if u == nil { + if !setting.Service.EnableBasicAuth { + return nil, false + } u, err = models.UserSignIn(uname, passwd) if err != nil { if !models.IsErrUserNotExist(err) { diff --git a/modules/setting/service.go b/modules/setting/service.go index 905b1326f78d6..dea4081ee8703 100644 --- a/modules/setting/service.go +++ b/modules/setting/service.go @@ -23,6 +23,7 @@ var Service struct { ShowRegistrationButton bool RequireSignInView bool EnableNotifyMail bool + EnableBasicAuth bool EnableReverseProxyAuth bool EnableReverseProxyAutoRegister bool EnableReverseProxyEmail bool @@ -60,6 +61,7 @@ func newService() { Service.EmailDomainWhitelist = sec.Key("EMAIL_DOMAIN_WHITELIST").Strings(",") Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!(Service.DisableRegistration || Service.AllowOnlyExternalRegistration)) Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool() + Service.EnableBasicAuth = sec.Key("ENABLE_BASIC_AUTHENTICATION").MustBool(true) Service.EnableReverseProxyAuth = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION").MustBool() Service.EnableReverseProxyAutoRegister = sec.Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool() Service.EnableReverseProxyEmail = sec.Key("ENABLE_REVERSE_PROXY_EMAIL").MustBool() From b2b9bdaf2647d33d40ca6bf993c8691121912a4d Mon Sep 17 00:00:00 2001 From: Jonas Franz Date: Sat, 19 Oct 2019 17:38:49 +0200 Subject: [PATCH 134/173] Fix #8582 by handling empty repos (#8587) * Fix #8582 by handling empty repos Signed-off-by: Jonas Franz * Fix tests Signed-off-by: Jonas Franz --- modules/repofiles/content.go | 3 +++ modules/repofiles/content_test.go | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/modules/repofiles/content.go b/modules/repofiles/content.go index 9637658e78b92..d7d43ef9d1661 100644 --- a/modules/repofiles/content.go +++ b/modules/repofiles/content.go @@ -38,6 +38,9 @@ func (ct *ContentType) String() string { // GetContentsOrList gets the meta data of a file's contents (*ContentsResponse) if treePath not a tree // directory, otherwise a listing of file contents ([]*ContentsResponse). Ref can be a branch, commit or tag func GetContentsOrList(repo *models.Repository, treePath, ref string) (interface{}, error) { + if repo.IsEmpty { + return make([]interface{}, 0), nil + } if ref == "" { ref = repo.DefaultBranch } diff --git a/modules/repofiles/content_test.go b/modules/repofiles/content_test.go index ef6c5eafc22e9..cd98c54ea69f6 100644 --- a/modules/repofiles/content_test.go +++ b/modules/repofiles/content_test.go @@ -190,3 +190,19 @@ func TestGetContentsOrListErrors(t *testing.T) { assert.Nil(t, fileContentResponse) }) } + +func TestGetContentsOrListOfEmptyRepos(t *testing.T) { + models.PrepareTestEnv(t) + ctx := test.MockContext(t, "user2/repo15") + ctx.SetParams(":id", "15") + test.LoadRepo(t, ctx, 15) + test.LoadUser(t, ctx, 2) + test.LoadGitRepo(t, ctx) + repo := ctx.Repo.Repository + + t.Run("empty repo", func(t *testing.T) { + contents, err := GetContentsOrList(repo, "", "") + assert.NoError(t, err) + assert.Empty(t, contents) + }) +} From 85609efaad1016f0279ef7396ac804279ace4731 Mon Sep 17 00:00:00 2001 From: Antoine GIRARD Date: Sat, 19 Oct 2019 23:14:38 +0200 Subject: [PATCH 135/173] Display Gitea logo in Readme (#8592) * readme: add gitea logo * Update README.md * Update README.md * Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 76feebdbe72a5..96f755107a3cd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [简体中文](https://github.com/go-gitea/gitea/blob/master/README_ZH.md) -# Gitea - Git with a cup of tea +

logo Gitea - Git with a cup of tea

[![Build Status](https://drone.gitea.io/api/badges/go-gitea/gitea/status.svg)](https://drone.gitea.io/go-gitea/gitea) [![Join the Discord chat at https://discord.gg/NsatcWJ](https://img.shields.io/discord/322538954119184384.svg)](https://discord.gg/NsatcWJ) From f37b87f81e7686fc1d130ddb5e727c9328ed3659 Mon Sep 17 00:00:00 2001 From: Konrad Pozniak Date: Sun, 20 Oct 2019 07:39:35 +0200 Subject: [PATCH 136/173] Improve german translation of homepage (#8549) I'm a native speaker, it looks much better this way --- templates/home.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/home.tmpl b/templates/home.tmpl index d31094a5b2f9d..b553e7cd9f900 100644 --- a/templates/home.tmpl +++ b/templates/home.tmpl @@ -28,7 +28,7 @@ Plattformübergreifend

- Gitea läuft überall. Go kompiliert für: Windows, macOS, Linux, ARM, etc. Wähle dasjenige System, was dir am meisten gefällt! + Gitea läuft überall, wo Go kompiliert: Windows, macOS, Linux, ARM, etc. Wähle das System, das dir am meisten gefällt!

From 3b379691fa2ccade5d536f17b6438cf5f8344fae Mon Sep 17 00:00:00 2001 From: 6543 <24977596+6543@users.noreply.github.com> Date: Sun, 20 Oct 2019 11:06:53 +0200 Subject: [PATCH 137/173] move translation to crowdin (#8596) --- options/locale/locale_en-US.ini | 13 +- templates/home.tmpl | 491 +++----------------------------- 2 files changed, 46 insertions(+), 458 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 4923f2f88400d..7b65de6addea4 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1,5 +1,3 @@ -app_desc = A painless, self-hosted Git service - home = Home dashboard = Dashboard explore = Explore @@ -75,6 +73,17 @@ write = Write preview = Preview loading = Loading… +[startpage] +app_desc = A painless, self-hosted Git service +install = Easy to install +install_desc = Simply run the binary for your platform. Or ship Gitea with Docker or Vagrant, or get it packaged. +platform = Cross-platform +platform_desc = Gitea runs anywhere Go can compile for: Windows, macOS, Linux, ARM, etc. Choose the one you love! +lightweight = Lightweight +lightweight_desc = Gitea has low minimal requirements and can run on an inexpensive Raspberry Pi. Save your machine energy! +license = Open Source +license_desc = Go get code.gitea.io/gitea! Join us by contributing to make this project even better. Don't be shy to be a contributor! + [install] install = Installation title = Initial Configuration diff --git a/templates/home.tmpl b/templates/home.tmpl index b553e7cd9f900..2c7b9e0d61d8a 100644 --- a/templates/home.tmpl +++ b/templates/home.tmpl @@ -9,466 +9,45 @@

{{AppName}}

-

{{.i18n.Tr "app_desc"}}

+

{{.i18n.Tr "startpage.app_desc"}}

- {{if eq .Lang "de-DE"}} -
-
-

- Einfach zu installieren -

-

- Starte einfach die Anwendung für deine Plattform. Gitea gibt es auch für Docker, Vagrant oder als Installationspaket. -

-
-
-

- Plattformübergreifend -

-

- Gitea läuft überall, wo Go kompiliert: Windows, macOS, Linux, ARM, etc. Wähle das System, das dir am meisten gefällt! -

-
-
-
-
-

- Leichtgewicht -

-

- Gitea hat minimale Systemanforderungen und kann selbst auf einem günstigen und stromsparenden Raspberry Pi betrieben werden. -

-
-
-

- Quelloffen -

-

- Der komplette Code befindet sich auf GitHub! Unterstütze uns bei der Verbesserung dieses Projekts. Trau dich! -

-
-
- {{else if eq .Lang "zh-TW"}} -
-
-

- 易安裝 -

-

- 直接用 執行檔安裝,還可以透過 DockerVagrant,以及 套件安装。 -

-
-
-

- 跨平台 -

-

- Gitea 可以運作在任何 Go 語言能夠編譯的平台: Windows, macOS, Linux, ARM 等等。挑一個您喜歡的就好。 -

-
-
-
-
-

- 輕量級 -

-

- 一個便宜的樹莓派 Raspberry Pi 就可以滿足 Gitea 的最低系統需求,節省機器資源! -

-
-
-

- 開源化 -

-

- 所有程式碼都在 GitHub 上,加入我們讓 Gitea 更好,別害羞,你可以做到的。 -

-
-
- {{else if eq .Lang "zh-CN"}} -
-
-

- 易安装 -

-

- 您除了可以根据操作系统平台通过 二进制运行,还可以通过 DockerVagrant,以及 包管理 安装。 -

-
-
-

- 跨平台 -

-

- 任何 Go 语言 支持的平台都可以运行 Gitea,包括 Windows、Mac、Linux 以及 ARM。挑一个您喜欢的就行! -

-
-
-
-
-

- 轻量级 -

-

- 一个廉价的树莓派的配置足以满足 Gitea 的最低系统硬件要求。最大程度上节省您的服务器资源! -

-
-
-

- 开源化 -

-

- 所有的代码都开源在 GitHub 上,赶快加入我们来共同发展这个伟大的项目!还等什么?成为贡献者吧! -

-
-
- {{else if eq .Lang "fr-FR"}} -
-
-

- Facile à installer -

-

- Il suffit de lancer l'exécutable correspondant à votre système. - Ou d'utiliser Gitea avec Docker ou - Vagrant - ou en l'installant depuis un package. -

-
-
-

- Multi-plateforme -

-

- Gitea tourne partout où Go peut être compilé : Windows, macOS, Linux, ARM, etc. Choisissez votre préféré ! -

-
-
-
-
-

- Léger -

-

- Gitea utilise peu de ressources. Il peut même tourner sur un Raspberry Pi très bon marché. Économisez l'énergie de vos serveurs ! -

-
-
-

- Open Source -

-

- Toutes les sources sont sur GitHub ! Rejoignez-nous et contribuez à rendre ce projet encore meilleur. -

-
-
- {{else if eq .Lang "es-ES"}} -
-
-

- Fácil de instalar -

-

- Simplemente arranca el binario para tu plataforma. O usa Gitea con Docker o Vagrant, o utilice el paquete. -

-
-
-

- Multiplatforma -

-

- Gitea funciona en cualquier parte, Go puede compilarse en: Windows, macOS, Linux, ARM, etc. !Elige tu favorita! -

-
-
-
-
-

- Ligero -

-

- Gitea tiene pocos requisitos y puede funcionar en una Raspberry Pi barata. !Ahorra energía! -

-
-
-

- Open Source -

-

- ¡Está todo en GitHub! Uniros contribuyendo a hacer este proyecto todavía mejor. ¡No seas tímido y colabora! -

-
-
- {{else if eq .Lang "pt-BR"}} -
-
-

- Fácil de instalar -

-

- Simplesmente rode o executável para o seu sistema operacional. Ou obtenha o Gitea com o Docker ou Vagrant, ou baixe o pacote. -

-
-
-

- Multi-plataforma -

-

- Gitea roda em qualquer sistema operacional em que Go consegue compilar: Windows, macOS, Linux, ARM, etc. Escolha qual você gosta mais! -

-
-
-
-
-

- Leve e rápido -

-

- Gitea utiliza poucos recursos e consegue mesmo rodar no barato Raspberry Pi. Economize energia elétrica da sua máquina! -

-
-
-

- Código aberto -

-

- Está tudo no GitHub! Contribua e torne este projeto ainda melhor. Não tenha vergonha de contribuir! -

-
-
- {{else if eq .Lang "ru-RU"}} -
-
-

- Простой в установке -

-

- Просто запустите исполняемый файл для вашей платформы. Иcпользуйте Gitea с Docker или Vagrant, или загрузите пакет. -

-
-
-

- Кроссплатформенный -

-

- Gitea работает на любой операционной системе, которая может компилировать Go: Windows, macOS, Linux, ARM и т. д. Выбирайте, что вам больше нравится! -

-
-
-
-
-

- Легковесный -

-

- Gitea имеет низкие системные требования и может работать на недорогом Raspberry Pi. Экономьте энергию вашей машины! -

-
-
-

- Открытый исходный код -

-

- Всё это на GitHub! Присоединяйтесь к нам, внося вклад, чтобы сделать этот проект еще лучше. Не бойтесь помогать! -

-
-
- {{else if eq .Lang "nl-NL"}} -
-
-

- Makkelijk te installeren -

-

- Je hoeft alleen maar de binary uit te voeren. Of gebruik Gitea met Docker, Vagrant, of download een installatiepakket. -

-
-
-

- Cross-platform -

-

- Gitea werkt op alles waar Go op kan compileren: Windows, macOS, Linux, ARM, etc. Kies het platform dat bij je past! -

-
-
-
-
-

- Lichtgewicht -

-

- Gitea heeft hele lage systeemeisen, je kunt Gitea al draaien op een goedkope Raspberry Pi. -

-
-
-

- Open Source -

-

- Alles staat op GitHub! Help ons door mee te bouwen aan Gitea, samen maken we dit project nog beter. Aarzel dus niet om een bijdrage te leveren! -

-
-
- {{else if eq .Lang "cs-CZ"}} -
-
-

- Jednoduchá na instalaci -

-

- Jednoduše spusťte binárku pro vaší platformu. Je také k dispozici pro Docker nebo Vagrant, nebo ji získejte z balíčku. -

-
-
-

- Multiplatformní -

-

- Gitea běží všude, kde Go může kompilovat: Windows, macOS, Linux, ARM, atd. Vyberte si ten, který milujete! -

-
-
-
-
-

- Lehká -

-

- Gitea má minimální požadavky a může běžet na Raspberry Pi. Šetřete energii vašeho stroje! -

-
-
-

- Open Source -

-

- Vše je na GitHubu! Připojte se tím, že přispějete a uděláte tento projekt ještě lepší. Nestyďte se být přispěvatel! -

-
-
- {{else if eq .Lang "it-IT"}} -
-
-

- Facile da installare -

-

- Semplicemente avvia l'eseguibile per la tua piattaforma. Oppure avvia Gitea con Docker o con Vagrant, oppure ottienilo pacchettizzato. -

-
-
-

- Multipiattaforma -

-

- Gitea funziona ovunque Go possa essere compilato: Windows, macOS, Linux, ARM, etc. Scegli ciò che ami! -

-
-
-
-
-

- Leggero -

-

- Gitea ha requisiti minimi bassi e può funzionare su un economico Raspberry Pi. Risparmia l'energia della tua macchina! -

-
-
-

- Open Source -

-

-Ottieni code.gitea.io/gitea! -Partecipa per contribuire -a rendere questo progetto ancora migliore. -Non aver paura di diventare un collaboratore! -

-
-
- {{else if eq .Lang "lv-LV"}} -
-
-

- Vienkārši instalējams -

-

- Nepieciešams tikai palaist izpildāmo failu vajadzīgajai platformai. Vai izmantot Docker vai Vagrant, vai izmantot pakotni. -

-
-
-

- Pieejama dažādām platformām -

-

- Gitea iespējams uzstādīt jebkur, kam Go var nokompilēt: Windows, macOS, Linux, ARM utt. Izvēlies to, kas tev patīk! -

-
-
-
-
-

- Viegla -

-

- Gitea ir miminālas prasības un to var darbināt uz nedārga Raspberry Pi datora. Ietaupi savai ierīcei jaudu! -

-
-
-

- Arvērtā pirmkoda -

-

-Iegūsti code.gitea.io/gitea! -Pievienojies un palīdzi uzlabot, -lai padarītu šo projektu vēl labāku! -Nekautrējies un līdzdarbojies! -

-
-
- {{else}} -
-
-

- Easy to install -

-

- Simply run the binary for your platform. Or ship Gitea with Docker or Vagrant, or get it packaged. -

-
-
-

- Cross-platform -

-

- Gitea runs anywhere Go can compile for: Windows, macOS, Linux, ARM, etc. Choose the one you love! -

-
+
+
+

+ {{.i18n.Tr "startpage.install"}} +

+

+ {{.i18n.Tr "startpage.install_desc" | Str2html}} +

+
+
+

+ {{.i18n.Tr "startpage.platform"}} +

+

+ {{.i18n.Tr "startpage.platform_desc" | Str2html}} +

-
-
-

- Lightweight -

-

- Gitea has low minimal requirements and can run on an inexpensive Raspberry Pi. Save your machine energy! -

-
-
-

- Open Source -

-

-Go get code.gitea.io/gitea! -Join us by contributing -to make this project even better. -Don't be shy to be a contributor! -

-
+
+
+
+

+ {{.i18n.Tr "startpage.lightweight"}} +

+

+ {{.i18n.Tr "startpage.lightweight_desc" | Str2html}} +

+
+
+

+ {{.i18n.Tr "startpage.license"}} +

+

+ {{.i18n.Tr "startpage.license_desc" | Str2html}} +

- {{end}} +
{{template "base/footer" .}} From bcd96421dd7d06047578787cc0a6764843e2513b Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 20 Oct 2019 13:41:24 +0200 Subject: [PATCH 138/173] webhook: set Content-Type for application/x-www-form-urlencoded (#8599) This header is missing since switching http client from GiteaServer (`code.gitea.io/gitea/modules/httplib`) to Go-http-client/1.1 (`net.http`). The header [was added by default](https://github.com/go-gitea/gitea/blob/release/v1.8/modules/httplib/httplib.go#L301) by the former, but this is no longer true with `net.http`, so it needs to be done explicitly: Ref: https://github.com/go-gitea/gitea/issues/7700 --- models/webhook.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/models/webhook.go b/models/webhook.go index f657c187928c6..6f2162c799d2d 100644 --- a/models/webhook.go +++ b/models/webhook.go @@ -833,6 +833,8 @@ func (t *HookTask) deliver() error { return err } + + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") } case http.MethodGet: u, err := url.Parse(t.URL) From 85e419076117573b84440650ac0959771a618d80 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sun, 20 Oct 2019 11:44:44 +0000 Subject: [PATCH 139/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_bg-BG.ini | 3 ++- options/locale/locale_cs-CZ.ini | 4 ++-- options/locale/locale_de-DE.ini | 4 ++-- options/locale/locale_es-ES.ini | 4 ++-- options/locale/locale_fa-IR.ini | 4 ++-- options/locale/locale_fi-FI.ini | 4 ++-- options/locale/locale_fr-FR.ini | 4 ++-- options/locale/locale_hu-HU.ini | 3 ++- options/locale/locale_id-ID.ini | 4 ++-- options/locale/locale_it-IT.ini | 4 ++-- options/locale/locale_ja-JP.ini | 4 ++-- options/locale/locale_ko-KR.ini | 3 ++- options/locale/locale_lt-LT.ini | 3 ++- options/locale/locale_lv-LV.ini | 4 ++-- options/locale/locale_ml-IN.ini | 1 + options/locale/locale_nb-NO.ini | 4 ++-- options/locale/locale_nl-NL.ini | 4 ++-- options/locale/locale_nn-NO.ini | 1 + options/locale/locale_no-NO.ini | 3 ++- options/locale/locale_pl-PL.ini | 4 ++-- options/locale/locale_pt-BR.ini | 4 ++-- options/locale/locale_ru-RU.ini | 4 ++-- options/locale/locale_sr-SP.ini | 3 ++- options/locale/locale_sv-SE.ini | 4 ++-- options/locale/locale_tr-TR.ini | 4 ++-- options/locale/locale_uk-UA.ini | 4 ++-- options/locale/locale_vi-VN.ini | 1 + options/locale/locale_zh-CN.ini | 4 ++-- options/locale/locale_zh-HK.ini | 3 ++- options/locale/locale_zh-TW.ini | 4 ++-- 30 files changed, 57 insertions(+), 47 deletions(-) diff --git a/options/locale/locale_bg-BG.ini b/options/locale/locale_bg-BG.ini index 8055ca8a0c4e4..40dabfae9f38f 100644 --- a/options/locale/locale_bg-BG.ini +++ b/options/locale/locale_bg-BG.ini @@ -1,4 +1,3 @@ - home=Начало dashboard=Табло explore=Каталог @@ -40,6 +39,8 @@ issues=Задачи cancel=Отказ +[startpage] + [install] install=Инсталация db_title=Настройки на базата данни diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index e7d0fb0cf777c..54fe2a14e9cc2 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -1,5 +1,3 @@ -app_desc=Snadno přístupný vlastní Git - home=Domů dashboard=Přehled explore=Procházet @@ -75,6 +73,8 @@ write=Zapsat preview=Náhled loading=Načítá se… +[startpage] + [install] install=Instalace title=Výchozí konfigurace diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index c8765127392b4..c95322df54266 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -1,5 +1,3 @@ -app_desc=Ein einfacher, selbst gehosteter Git-Service - home=Startseite dashboard=Übersicht explore=Erkunden @@ -75,6 +73,8 @@ write=Verfassen preview=Vorschau loading=Laden… +[startpage] + [install] install=Installation title=Erstkonfiguration diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index 9ef6ba13e9d3d..52d3842ec80ee 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -1,5 +1,3 @@ -app_desc=Un servicio de Git auto alojado y sin complicaciones - home=Inicio dashboard=Panel de control explore=Explorar @@ -75,6 +73,8 @@ write=Escribir preview=Vista previa loading=Cargando… +[startpage] + [install] install=Instalación title=Configuración inicial diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini index fcd1f588840bb..ee8e190053fbe 100644 --- a/options/locale/locale_fa-IR.ini +++ b/options/locale/locale_fa-IR.ini @@ -1,5 +1,3 @@ -app_desc=یک سرویس گیت بی‌درد سر و راحت - home=خانه dashboard=میز کار explore=گشت‌و‌گذار @@ -75,6 +73,8 @@ write=نوشتن preview=پیش نمایش loading=بارگذاری… +[startpage] + [install] install=نصب و راه اندازی title=تنظیمات اولیه diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini index 1c7ae76df2830..75a80de528065 100644 --- a/options/locale/locale_fi-FI.ini +++ b/options/locale/locale_fi-FI.ini @@ -1,5 +1,3 @@ -app_desc=Ongelmaton, itsehostattu Git-palvelu - home=Etusivu dashboard=Kojelauta explore=Tutki @@ -61,6 +59,8 @@ issues=Ongelmat cancel=Peruuta +[startpage] + [install] install=Asennus title=Alkuperäiset asetukset diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index b003a7fa385dd..18c21982eca16 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -1,5 +1,3 @@ -app_desc=Un service Git auto-hébergé sans prise de tête - home=Accueil dashboard=Tableau de bord explore=Explorateur @@ -75,6 +73,8 @@ write=Écrire preview=Aperçu loading=Chargement… +[startpage] + [install] install=Installation title=Configuration initiale diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini index b87e22ed460d3..2d90909d1e7e9 100644 --- a/options/locale/locale_hu-HU.ini +++ b/options/locale/locale_hu-HU.ini @@ -1,4 +1,3 @@ - home=Főoldal dashboard=Műszerfal explore=Felfedezés @@ -50,6 +49,8 @@ issues=Hibajegyek cancel=Mégse +[startpage] + [install] install=Telepítés db_title=Adatbázis beállítások diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini index 64e68baa1a755..bd7d0eeb63451 100644 --- a/options/locale/locale_id-ID.ini +++ b/options/locale/locale_id-ID.ini @@ -1,5 +1,3 @@ -app_desc=Sebuah layanan Git hosting pribadi yang mudah - home=Beranda dashboard=Dasbor explore=Jelajahi @@ -64,6 +62,8 @@ issues=Masalah cancel=Batal +[startpage] + [install] install=Pemasangan title=Konfigurasi Awal diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index 0038b7fa80d81..7829406297364 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -1,5 +1,3 @@ -app_desc=Un servizio auto-ospitato per Git pronto all'uso - home=Home dashboard=Pannello di controllo explore=Esplora @@ -64,6 +62,8 @@ issues=Problemi cancel=Annulla +[startpage] + [install] install=Installazione title=Configurazione Iniziale diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 6a4eee6424562..91e9d3d652b4d 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -1,5 +1,3 @@ -app_desc=痛みのない、自己ホスト型のGitサービス - home=ホーム dashboard=ダッシュボード explore=エクスプローラー @@ -75,6 +73,8 @@ write=書き込み preview=プレビュー loading=読み込み中… +[startpage] + [install] install=インストール title=初期設定 diff --git a/options/locale/locale_ko-KR.ini b/options/locale/locale_ko-KR.ini index a1b6e6e751127..f0ce4cdb30e53 100644 --- a/options/locale/locale_ko-KR.ini +++ b/options/locale/locale_ko-KR.ini @@ -1,4 +1,3 @@ - home=홈 dashboard=대시보드 explore=탐색 @@ -45,6 +44,8 @@ issues=이슈들 cancel=취소 +[startpage] + [install] install=설치 db_title=데이터베이스 설정 diff --git a/options/locale/locale_lt-LT.ini b/options/locale/locale_lt-LT.ini index b0597cd1c3e1e..b23bf5808db7f 100644 --- a/options/locale/locale_lt-LT.ini +++ b/options/locale/locale_lt-LT.ini @@ -1,4 +1,3 @@ - home=Pagrindinis dashboard=Skydelis explore=Naršyti @@ -38,6 +37,8 @@ issues=Problemos cancel=Atšaukti +[startpage] + [install] install=Diegimas db_title=Duombazės nustatymai diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index fad6b50ba0692..7d4f125f3be92 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -1,5 +1,3 @@ -app_desc=Viegli uzstādāms Git serviss - home=Sākums dashboard=Infopanelis explore=Izpētīt @@ -75,6 +73,8 @@ write=Rakstīt preview=Priekšskatītījums loading=Notiek ielāde… +[startpage] + [install] install=Instalācija title=Sākotnējā konfigurācija diff --git a/options/locale/locale_ml-IN.ini b/options/locale/locale_ml-IN.ini index f2571ce9c07d2..35af054c15240 100644 --- a/options/locale/locale_ml-IN.ini +++ b/options/locale/locale_ml-IN.ini @@ -6,6 +6,7 @@ +[startpage] [install] diff --git a/options/locale/locale_nb-NO.ini b/options/locale/locale_nb-NO.ini index 763bfec6a6208..d83f5829dee9c 100644 --- a/options/locale/locale_nb-NO.ini +++ b/options/locale/locale_nb-NO.ini @@ -1,5 +1,3 @@ -app_desc=En smertefri Git-tjeneste du kan kjøre selv - home=Startside dashboard=Skrivebord explore=Utforsk @@ -75,6 +73,8 @@ write=Skriv preview=Forhåndsvis loading=Laster inn… +[startpage] + [install] install=Installasjon title=Standard konfigurasjon diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini index c0a26798ff0d8..66f8efe031118 100644 --- a/options/locale/locale_nl-NL.ini +++ b/options/locale/locale_nl-NL.ini @@ -1,5 +1,3 @@ -app_desc=Een eenvoudige, self-hosted Git service - home=Beginscherm dashboard=Overzicht explore=Verkennen @@ -75,6 +73,8 @@ write=Schrijf preview=Voorbeeld loading=Laden… +[startpage] + [install] install=Installatie title=Initiële configuratie diff --git a/options/locale/locale_nn-NO.ini b/options/locale/locale_nn-NO.ini index f2571ce9c07d2..35af054c15240 100644 --- a/options/locale/locale_nn-NO.ini +++ b/options/locale/locale_nn-NO.ini @@ -6,6 +6,7 @@ +[startpage] [install] diff --git a/options/locale/locale_no-NO.ini b/options/locale/locale_no-NO.ini index 79198d129bd52..326ee445e5811 100644 --- a/options/locale/locale_no-NO.ini +++ b/options/locale/locale_no-NO.ini @@ -1,4 +1,3 @@ - home=Startside dashboard=Skrivebord explore=Utforsk @@ -36,6 +35,8 @@ issues=Problemer cancel=Avbryt +[startpage] + [install] install=Installasjon db_title=Databaseinnstillinger diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini index fa998c8f6577a..f899616f69e1b 100644 --- a/options/locale/locale_pl-PL.ini +++ b/options/locale/locale_pl-PL.ini @@ -1,5 +1,3 @@ -app_desc=Bezbolesna usługa Git na własnym serwerze - home=Strona główna dashboard=Pulpit explore=Odkrywaj @@ -75,6 +73,8 @@ write=Napisz preview=Podgląd loading=Ładowanie… +[startpage] + [install] install=Instalacja title=Wstępna konfiguracja diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 9f3419b8c89a7..3c441f5a1721c 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -1,5 +1,3 @@ -app_desc=Um serviço de hospedagem Git amigável - home=Página inicial dashboard=Painel explore=Explorar @@ -75,6 +73,8 @@ write=Escrever preview=Pré-visualização loading=Carregando… +[startpage] + [install] install=Instalação title=Configuração inicial diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index a46a79089d66f..d8af5274a0331 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -1,5 +1,3 @@ -app_desc=Удобная служба для собственного Git-репозитория - home=Главная dashboard=Панель управления explore=Обзор @@ -75,6 +73,8 @@ write=Редактирование preview=Предпросмотр loading=Загрузка… +[startpage] + [install] install=Установка title=Начальная конфигурация diff --git a/options/locale/locale_sr-SP.ini b/options/locale/locale_sr-SP.ini index fc55a9ca53548..a4072b7dfaf71 100644 --- a/options/locale/locale_sr-SP.ini +++ b/options/locale/locale_sr-SP.ini @@ -1,4 +1,3 @@ - home=Почетна dashboard=Контролни панел explore=Преглед @@ -36,6 +35,8 @@ issues=Дискусије cancel=Откажи +[startpage] + [install] install=Инсталација db_title=Подешавања базе diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini index 33737c5e03381..37d6621642bdb 100644 --- a/options/locale/locale_sv-SE.ini +++ b/options/locale/locale_sv-SE.ini @@ -1,5 +1,3 @@ -app_desc=En smidig, självhostad Git-tjänst - home=Startsida dashboard=Instrumentpanel explore=Utforska @@ -71,6 +69,8 @@ cancel=Avbryt preview=Förhandsgranska loading=Laddar… +[startpage] + [install] install=Installation title=Ursprunglig konfiguration diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index a54e3cd70e7fa..6cc6c28dfe797 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -1,5 +1,3 @@ -app_desc=Zahmetsiz, kendi sunucunuzda barındırabileceğiniz Git hizmeti - home=Ana Sayfa dashboard=Pano explore=Keşfet @@ -74,6 +72,8 @@ write=Yaz preview=Önizleme loading=Yükleniyor… +[startpage] + [install] install=Kurulum title=Başlangıç Yapılandırması diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini index 79f2d281e8c35..51e52b27852bd 100644 --- a/options/locale/locale_uk-UA.ini +++ b/options/locale/locale_uk-UA.ini @@ -1,5 +1,3 @@ -app_desc=Зручний сервіс, власного Git хостингу - home=Головна dashboard=Панель управління explore=Огляд @@ -75,6 +73,8 @@ write=Писати preview=Попередній перегляд loading=Завантаження… +[startpage] + [install] install=Встановлення title=Початкова конфігурація diff --git a/options/locale/locale_vi-VN.ini b/options/locale/locale_vi-VN.ini index f2571ce9c07d2..35af054c15240 100644 --- a/options/locale/locale_vi-VN.ini +++ b/options/locale/locale_vi-VN.ini @@ -6,6 +6,7 @@ +[startpage] [install] diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 6d93894f6dd9d..d8e8649504224 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -1,5 +1,3 @@ -app_desc=一款极易搭建的自助 Git 服务 - home=首页 dashboard=首页 explore=探索 @@ -75,6 +73,8 @@ write=撰写 preview=预览 loading=正在加载... +[startpage] + [install] install=安装页面 title=初始配置 diff --git a/options/locale/locale_zh-HK.ini b/options/locale/locale_zh-HK.ini index 6fec7954fbf1b..43e9b3eea525f 100644 --- a/options/locale/locale_zh-HK.ini +++ b/options/locale/locale_zh-HK.ini @@ -1,4 +1,3 @@ - home=首頁 dashboard=控制面版 explore=探索 @@ -43,6 +42,8 @@ issues=問題 cancel=取消 +[startpage] + [install] install=安裝頁面 db_title=資料庫設定 diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini index f164a604cf649..de787b6b4793d 100644 --- a/options/locale/locale_zh-TW.ini +++ b/options/locale/locale_zh-TW.ini @@ -1,5 +1,3 @@ -app_desc=一個無痛、自託管的 Git 服務 - home=首頁 dashboard=控制面版 explore=探索 @@ -64,6 +62,8 @@ issues=問題 cancel=取消 +[startpage] + [install] install=安裝頁面 title=初始設定 From 2657e718b6a74775fd52709fb8b3bed0f9eabe49 Mon Sep 17 00:00:00 2001 From: David Svantesson Date: Sun, 20 Oct 2019 20:31:07 +0200 Subject: [PATCH 140/173] Basic Design guidelines (describing different parts of the code) (#8601) * Design guidelines with description of different parts of code * Better readability with code parts in bold. --- CONTRIBUTING.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 95799e92b36e4..93083dc491fb5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,6 +11,7 @@ - [Translation](#translation) - [Code review](#code-review) - [Styleguide](#styleguide) + - [Design guideline](#design-guideline) - [Developer Certificate of Origin (DCO)](#developer-certificate-of-origin-dco) - [Release Cycle](#release-cycle) - [Maintainers](#maintainers) @@ -118,6 +119,8 @@ An exception are the tools to build the CSS and images. - To build Images: ImageMagick, inkscape and zopflipng binaries must be available in your `PATH` to run `make generate-images`. +For more details on how to generate files, build and test Gitea, see the [hacking instructions](https://docs.gitea.io/en-us/hacking-on-gitea/) + ## Code review Changes to Gitea must be reviewed before they are accepted—no matter who @@ -157,6 +160,22 @@ import ( ) ``` +## Design guideline + +To maintain understandable code and avoid circular dependencies it is important to have a good structure of the code. The gitea code is divided into the following parts: + +- **integration:** Integrations tests +- **models:** Contains the data structures used by xorm to construct database tables. It also contains supporting functions to query and update the database. Dependecies to other code in Gitea should be avoided although some modules might be needed (for example for logging). +- **models/fixtures:** Sample model data used in integration tests. +- **models/migrations:** Handling of database migrations between versions. PRs that changes a database structure shall also have a migration step. +- **modules:** Different modules to handle specific functionality in Gitea. +- **public:** Frontend files (javascript, images, css, etc.) +- **routers:** Handling of server requests. As it uses other Gitea packages to serve the request, other packages (models, modules or services) shall not depend on routers +- **services:** Support functions for common routing operations. Uses models and modules to handle the request. +- **templates:** Golang templates for generating the html output. +- **vendor:** External code that Gitea depends on. + + ## Developer Certificate of Origin (DCO) We consider the act of contributing to the code by submitting a Pull From c8f3146cd52887c0bdd815ad0bdeb954b242c8fc Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sun, 20 Oct 2019 18:32:35 +0000 Subject: [PATCH 141/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_de-DE.ini | 11 ++++++++++- options/locale/locale_es-ES.ini | 12 ++++++++++++ options/locale/locale_fr-FR.ini | 32 ++++++++++++++++++++++++++++++++ options/locale/locale_ja-JP.ini | 1 + options/locale/locale_zh-CN.ini | 21 +++++++++++++++++++++ 5 files changed, 76 insertions(+), 1 deletion(-) diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index c95322df54266..d12539fdca645 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -50,7 +50,7 @@ new_mirror=Neuer Mirror new_fork=Neuer Fork new_org=Neue Organisation manage_org=Organisationen verwalten -admin_panel=Website-Administration +admin_panel=Administration account_settings=Kontoeinstellungen settings=Einstellungen your_profile=Profil @@ -74,6 +74,15 @@ preview=Vorschau loading=Laden… [startpage] +app_desc=Ein einfacher, selbst gehosteter Git-Service +install=Einfach zu installieren +install_desc=Starte einfach die Anwendung für deine Plattform. Gitea gibt es auch für Docker, Vagrant oder als Installationspaket. +platform=Plattformübergreifend +platform_desc=Gitea läuft überall, wo Go kompiliert: Windows, macOS, Linux, ARM, etc. Wähle das System, das dir am meisten gefällt! +lightweight=Leichtgewicht +lightweight_desc=Gitea hat minimale Systemanforderungen und kann selbst auf einem günstigen und stromsparenden Raspberry Pi betrieben werden! +license=Quelloffen +license_desc=Der komplette Code befindet sich auf GitHub! Unterstütze uns bei der Verbesserung dieses Projekts. Trau dich! [install] install=Installation diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index 52d3842ec80ee..c9a3284fbfac6 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -74,6 +74,15 @@ preview=Vista previa loading=Cargando… [startpage] +app_desc=Un servicio de Git autoalojado y sin complicaciones +install=Fácil de instalar +install_desc=Simplemente arranca el binario para tu plataforma. O usa Gitea con Docker o Vagrant, o utilice el paquete. +platform=Multiplatforma +platform_desc=Gitea funciona en cualquier platforma Go puede compilarlo en: Windows, macOS, Linux, ARM, etc. ¡Elige tu favorita! +lightweight=Ligero +lightweight_desc=Gitea tiene pocos requisitos y puede funcionar en una Raspberry Pi barata. ¡Ahorra energía! +license=Código abierto +license_desc=¡Está todo en GitHub! Uniros contribuyendo a hacer este proyecto todavía mejor. ¡No seas tímido y colabora! [install] install=Instalación @@ -1975,12 +1984,15 @@ mark_as_unread=Marcar como no leído mark_all_as_read=Marcar todo como leído [gpg] +default_key=Firmado con clave predeterminada error.extract_sign=Error al extraer la firma error.generate_hash=Error al generar hash of commit error.no_committer_account=Ninguna cuenta vinculada a la dirección de correo electrónico del committer error.no_gpg_keys_found=No se encontró ninguna clave conocida en la base de datos para esta firma error.not_signed_commit=No es un commit firmado error.failed_retrieval_gpg_keys=No se pudo recuperar cualquier clave adjunta a la cuenta del committer +error.probable_bad_signature=¡ADVERTENCIA! ¡Hay una clave con este ID en la base de datos, pero esa clave no verifica este commit! Este commit es SOSPECHOSO. +error.probable_bad_default_signature=¡ADVERTENCIA! ¡La clave por defecto tiene este ID pero esa clave no verifica este commit! Este commit es SOSPECHOSO. [units] error.no_unit_allowed_repo=No tiene permisos para acceder a ninguna sección de este repositorio. diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index 18c21982eca16..9ec8644e55dc5 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -74,6 +74,13 @@ preview=Aperçu loading=Chargement… [startpage] +app_desc=Un service Git auto-hébergé sans prise de tête +install=Facile à installer +install_desc=Il suffit de lancer l'exécutable correspondant à votre système. Ou d'utiliser Gitea avec Docker ou Vagrant ou en l'installant depuis un package. +platform=Multi-plateforme +platform_desc=Gitea tourne partout où Go peut être compilé : Windows, macOS, Linux, ARM, etc. Choisissez votre préféré ! +lightweight=Léger +license=Open Source [install] install=Installation @@ -299,6 +306,7 @@ max_size_error=` %s caractères maximum ` email_error=` adresse e-mail invalide ` url_error=` URL invalide ` include_error=`doit contenir la sous-chaîne '%s'.` +glob_pattern_error=` le motif de développement est invalide : %s.` unknown_error=Erreur inconnue : captcha_incorrect=Le code CAPTCHA est incorrect. password_not_match=Les mots de passe ne correspondent pas. @@ -313,10 +321,12 @@ team_no_units_error=Autoriser l’accès à au moins une section du dépôt. email_been_used=Cette adresse e-mail est déjà utilisée. openid_been_used=Adresse OpenID '%s' déjà utilisée. username_password_incorrect=Identifiant ou mot de passe invalide. +password_complexity=Le mot de passe ne respecte pas les exigences de complexité. enterred_invalid_repo_name=Le nom de dépôt saisi est incorrect. enterred_invalid_owner_name=Le nom du nouveau propriétaire est invalide. enterred_invalid_password=Le mot de passe saisi est incorrect. user_not_exist=Cet utilisateur n'existe pas. +team_not_exist=L'équipe n'existe pas. last_org_owner=Vous ne pouvez pas supprimer le dernier utilisateur de l’équipe « propriétaires ». Il doit y avoir au moins un propriétaire dans chaque équipe. cannot_add_org_to_team=Une organisation ne peut être ajoutée comme membre d'une équipe. @@ -557,6 +567,7 @@ delete_account_title=Supprimer un compte delete_account_desc=Êtes-vous sûr de vouloir supprimer définitivement ce compte ? email_notifications.enable=Activer les notifications par e-mail +email_notifications.onmention=N'envoyer un e-mail que si vous êtes mentionné email_notifications.disable=Désactiver les notifications par email email_notifications.submit=Définir la préférence e-mail @@ -565,6 +576,7 @@ owner=Propriétaire repo_name=Nom du dépôt repo_name_helper=Idéalement, le nom d'un dépôt devrait être court, mémorisable et unique. visibility=Visibilité +visibility_description=Seul le propriétaire ou les membres de l'organisation s'ils ont des droits, seront en mesure de le voir. visibility_helper=Rendre le dépôt privé visibility_helper_forced=L'administrateur de votre serveur impose que les nouveaux dépôts soient privés. visibility_fork_helper=(Changer ceci affectera toutes les bifurcations.) @@ -587,6 +599,7 @@ mirror_prune_desc=Supprimer les références externes obsolètes mirror_interval=Intervalle de synchronisation ('h', 'm', et 's' sont des unités valides), 0 pour désactiver. mirror_interval_invalid=L'intervalle de synchronisation est invalide. mirror_address=Cloner depuis une URL +mirror_address_desc=Mettez les identifiants requis dans la section Autorisation de Clonage. mirror_address_url_invalid=L'url fournie est invalide. Vous devez échapper tous les composants de l'url correctement. mirror_address_protocol_invalid=L'url fournie est invalide. Seuls les protocoles http(s):// ou git:// peuvent être la source du miroir. mirror_last_synced=Dernière synchronisation @@ -625,6 +638,8 @@ migrate.lfs_mirror_unsupported=La synchronisation des objets LFS n'est pas suppo migrate.migrate_items_options=Quand vous migrez depuis github, saisissez un nom d'utilisateur et des options de migration seront affichées. migrated_from=Migré de %[2]s migrated_from_fake=Migré de %[1]s +migrate.migrating=Migration de %s ... +migrate.migrating_failed=La migration de %s a échoué. mirror_from=miroir de forked_from=bifurqué depuis @@ -673,6 +688,8 @@ stored_lfs=Stocké avec Git LFS commit_graph=Graphique des révisions blame=Annotations normal_view=Vue normale +line=ligne +lines=lignes editor.new_file=Nouveau fichier editor.upload_file=Téléverser un fichier @@ -698,6 +715,7 @@ editor.delete=Supprimer '%s' editor.commit_message_desc=Ajouter une description détaillée facultative… editor.commit_directly_to_this_branch=Soumettre directement dans la branche %s. editor.create_new_branch=Créer une nouvelle branche pour cette révision et envoyer une nouvelle demande d'ajout. +editor.create_new_branch_np=Créer une nouvelle branche pour cette révision. editor.propose_file_change=Proposer une modification du fichier editor.new_branch_name_desc=Nouveau nom de la branche… editor.cancel=Annuler @@ -973,6 +991,8 @@ pulls.cannot_merge_work_in_progress=Cette demande d'ajout est marquée comme en pulls.data_broken=Cette demande de fusion est impossible par manque d'informations de bifurcation. pulls.files_conflicted=Cette demande d'ajout contient des modifications en conflit avec la branche ciblée. pulls.is_checking=Vérification des conflits de fusion en cours. Réessayez dans quelques instants. +pulls.required_status_check_failed=Certains contrôles requis n'ont pas réussi. +pulls.required_status_check_administrator=En tant qu'administrateur, vous pouvez toujours fusionner cette requête de pull. pulls.blocked_by_approvals=Cette demande d'ajout n'a pas assez d'approbation. %d sur %d approbations accordées. pulls.can_auto_merge_desc=Cette demande d'ajout peut être fusionnée automatiquement. pulls.cannot_auto_merge_desc=Cette demande de fusion ne peut être appliquée automatiquement en raison de conflits de fusion. @@ -980,6 +1000,7 @@ pulls.cannot_auto_merge_helper=Fusionner manuellement pour résoudre les conflit pulls.no_merge_desc=Cette demande de fusion ne peut être appliquée directement car toutes les options de fusion du dépôt sont désactivées. pulls.no_merge_helper=Activez des options de fusion dans les paramètres du dépôt ou fusionnez la demande manuellement. pulls.no_merge_wip=Cette demande d'ajout ne peut pas être fusionnée car elle est marquée comme en cours de chantier. +pulls.no_merge_status_check=Cette demande de pull ne peut pas être fusionnée car tous les contrôles de statut requis ne sont pas réussis. pulls.merge_pull_request=Fusionner la demande d'ajout pulls.rebase_merge_pull_request=Rebase et fusionner pulls.rebase_merge_commit_pull_request=Rebase et Fusion (--no-ff) @@ -1121,6 +1142,7 @@ settings.collaboration=Collaborateurs settings.collaboration.admin=Administrateur settings.collaboration.write=Écriture settings.collaboration.read=Lecture +settings.collaboration.owner=Propriétaire settings.collaboration.undefined=Indéfini settings.hooks=Déclencheurs Web settings.githooks=Déclencheurs Git @@ -1129,7 +1151,9 @@ settings.mirror_settings=Réglages Miroir settings.sync_mirror=Synchroniser maintenant settings.mirror_sync_in_progress=La synchronisation est en cours. Revenez dans une minute. settings.email_notifications.enable=Activer les notifications par e-mail +settings.email_notifications.onmention=N'envoyer un e-mail que si vous êtes mentionné settings.email_notifications.disable=Désactiver les notifications par e-mail +settings.email_notifications.submit=Définir la préférence e-mail settings.site=Site Web settings.update_settings=Valider settings.advanced_settings=Paramètres avancés @@ -1200,6 +1224,11 @@ settings.collaborator_deletion_desc=La suppression d'un collaborateur révoque s settings.remove_collaborator_success=Le collaborateur a été retiré. settings.search_user_placeholder=Rechercher un utilisateur… settings.org_not_allowed_to_be_collaborator=Les organisations ne peuvent être ajoutées en tant que collaborateur. +settings.change_team_access_not_allowed=La modification de l'accès de l'équipe au dépôt a été limitée au propriétaire de l'organisation +settings.team_not_in_organization=L'équipe n'est pas dans la même organisation que le dépôt +settings.add_team_duplicate=L'équipe a déjà le dépôt +settings.add_team_success=L'équipe a maintenant accès au dépôt. +settings.remove_team_success=L'accès de l'équipe au dépôt a été supprimé. settings.add_webhook=Ajouter un déclencheur Web settings.add_webhook.invalid_channel_name=Le nom du canal Webhook ne peut pas être vide et ne peut pas contenir seulement un caractère #. settings.hooks_desc=Les Webhooks font automatiquement des requêtes HTTP POST à un serveur lorsque certains événements Gitea se déclenchent. Lire la suite dans le guide des Webhooks. @@ -1249,6 +1278,8 @@ settings.event_pull_request=Demande d'ajout settings.event_pull_request_desc=Demande d'ajout ouverte, fermée, réouverte, éditée, approuvée, rejetée, commentaire revu, assigné, non attribué, étiquette mise à jour, effacée ou synchronisée. settings.event_push=Pousser settings.event_push_desc=Git push vers un dépôt. +settings.branch_filter=Filtre de branche +settings.branch_filter_desc=Liste blanche pour les évènements de poussage, de création et de suppression de branche, spécifiés par un motif de développement. Si ce champ est vide ou vaut *, ces évènements sont rapportés pour toutes les branches . Voir la documentation pour la syntaxe sur github.com/gobwas/glob. Exemples : master, {master,release*}. settings.event_repository=Dépôt settings.event_repository_desc=Dépôt créé ou supprimé. settings.active=Actif @@ -1299,6 +1330,7 @@ settings.protect_merge_whitelist_committers=Activer la liste blanche pour la fus settings.protect_merge_whitelist_committers_desc=N'autoriser que les utilisateurs et les équipes en liste blanche d'appliquer les demandes de fusion sur cette branche. settings.protect_merge_whitelist_users=Utilisateurs en liste blanche de fusion : settings.protect_merge_whitelist_teams=Équipes en liste blanche de fusion : +settings.protect_check_status_contexts=Activer le Contrôle Qualité settings.protect_required_approvals=Agréments nécessaires : settings.protect_required_approvals_desc=N'autoriser la fusion qu'avec suffisamment de revues positives d'utilisateurs ou équipes sur liste blanche. settings.protect_approvals_whitelist_users=Réviseurs sur liste blanche : diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 91e9d3d652b4d..5416dcf547641 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -74,6 +74,7 @@ preview=プレビュー loading=読み込み中… [startpage] +app_desc=痛みのない、自己ホスト型のGitサービス [install] install=インストール diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index d8e8649504224..ee09ea196a107 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -74,6 +74,15 @@ preview=预览 loading=正在加载... [startpage] +app_desc=一款极易搭建的自助 Git 服务 +install=易安装 +install_desc=您除了可以根据操作系统平台通过 二进制运行,还可以通过 DockerVagrant,以及 包管理 安装。 +platform=跨平台 +platform_desc=任何 Go 语言 支持的平台都可以运行 Gitea,包括 Windows、Mac、Linux 以及 ARM。挑一个您喜欢的就行! +lightweight=轻量级 +lightweight_desc=一个廉价的树莓派的配置足以满足 Gitea 的最低系统硬件要求。最大程度上节省您的服务器资源! +license=开源化 +license_desc=所有的代码都开源在 GitHub 上,赶快加入我们来共同发展这个伟大的项目!还等什么?成为贡献者吧! [install] install=安装页面 @@ -314,6 +323,7 @@ team_no_units_error=至少选择一项仓库单元。 email_been_used=该电子邮件地址已在使用中。 openid_been_used=OpenID 地址 '%s' 已被使用。 username_password_incorrect=用户名或密码不正确。 +password_complexity=密码未达到复杂程度要求 enterred_invalid_repo_name=输入的仓库名称不正确 enterred_invalid_owner_name=新的所有者名称无效。 enterred_invalid_password=输入的密码不正确 @@ -724,6 +734,8 @@ editor.file_editing_no_longer_exists=正在编辑的文件 '%s' 已不存在。 editor.file_deleting_no_longer_exists=仓库中不存在将被删除的文件‘%s’。 editor.file_changed_while_editing=文件内容在您进行编辑时已经发生变动。单击此处 查看变动的具体内容,或者 再次提交 覆盖已发生的变动。 editor.file_already_exists=此仓库已经存在名为 '%s' 的文件。 +editor.commit_empty_file_header=提交一个空文件 +editor.commit_empty_file_text=您要提交的文件是空的,继续吗? editor.no_changes_to_show=没有可以显示的变更。 editor.fail_to_update_file=更新/创建文件 '%s' 时发生错误:%v editor.add_subdir=添加目录 @@ -1368,6 +1380,10 @@ diff.parent=父节点 diff.commit=当前提交 diff.git-notes=Notes diff.data_not_available=比较内容不可用 +diff.options_button=Diff 选项 +diff.show_diff_stats=显示统计 +diff.download_patch=下载 Patch 文件 +diff.download_diff=下载 Diff 文件 diff.show_split_view=分列视图 diff.show_unified_view=合并视图 diff.whitespace_button=空白符号 @@ -1450,6 +1466,8 @@ branch.restore_failed=未能还原分支%s。 branch.protected_deletion_failed=分支 '%s' 已被保护,不可删除。 branch.restore=恢复分支 '%s' branch.download=下载分支 '%s' +branch.included_desc=此分支是默认分支的一部分 +branch.included=已包含 topic.manage_topics=管理主题 topic.done=保存 @@ -1966,12 +1984,15 @@ mark_as_unread=标记为未读 mark_all_as_read=全部标记为已读 [gpg] +default_key=使用默认密钥签名 error.extract_sign=无法提取签名 error.generate_hash=无法生成提交的哈希 error.no_committer_account=没有帐户链接到提交者的电子邮件 error.no_gpg_keys_found=找不到此签名对应的密钥 error.not_signed_commit=未签名的提交 error.failed_retrieval_gpg_keys=找不到任何与该提交者账号相关的密钥 +error.probable_bad_signature=警告!虽然数据库中有一个此ID的密钥,但它没有验证此提交!此提交是有疑问的。 +error.probable_bad_default_signature=警告!虽然默认密钥拥有此ID,但它没有验证此提交!此提交是有疑问的。 [units] error.no_unit_allowed_repo=您没有被允许访问此仓库的任何单元。 From 28f60bb5cb24c71fdbefe16c2d86943fb4cf8a08 Mon Sep 17 00:00:00 2001 From: zeripath Date: Sun, 20 Oct 2019 23:26:36 +0100 Subject: [PATCH 142/173] Ensure default gpg settings not nil and found commits have reference to repo (#8604) * Ensure defaultGPGSettings not nil * Ensure that coerced commits gain a reference to the repo * Add warning if trying to get defaultgpgsetting on an unattached commit --- models/gpg_key.go | 2 ++ modules/git/commit_info.go | 1 + 2 files changed, 3 insertions(+) diff --git a/models/gpg_key.go b/models/gpg_key.go index 9b690475bd52a..58eaa61e223e1 100644 --- a/models/gpg_key.go +++ b/models/gpg_key.go @@ -682,6 +682,8 @@ func ParseCommitWithSignature(c *git.Commit) *CommitVerification { defaultGPGSettings, err := c.GetRepositoryDefaultPublicGPGKey(false) if err != nil { log.Error("Error getting default public gpg key: %v", err) + } else if defaultGPGSettings == nil { + log.Warn("Unable to get defaultGPGSettings for unattached commit: %s", c.ID.String()) } else if defaultGPGSettings.Sign { if commitVerification := verifyWithGPGSettings(defaultGPGSettings, sig, c.Signature.Payload, committer, keyID); commitVerification != nil { if commitVerification.Reason == BadSignature { diff --git a/modules/git/commit_info.go b/modules/git/commit_info.go index d8bf88a47cd43..e74ddbfb053fa 100644 --- a/modules/git/commit_info.go +++ b/modules/git/commit_info.go @@ -72,6 +72,7 @@ func (tes Entries) GetCommitsInfo(commit *Commit, treePath string, cache LastCom treeCommit = commit } else if rev, ok := revs[""]; ok { treeCommit = convertCommit(rev) + treeCommit.repo = commit.repo } return commitsInfo, treeCommit, nil } From 481c66a91f01ebbc3ebecab1c010791e232bb2ca Mon Sep 17 00:00:00 2001 From: George Harvey <11440490+HarvsG@users.noreply.github.com> Date: Mon, 21 Oct 2019 07:54:18 +0100 Subject: [PATCH 143/173] Allows external rendering of other filetypes 2 (#8300) * allow external rendering of other filetypes fixes #4996 and #7614 allows rendering of non-tex files, or otherwise accounted for filetypes * Moves flie-size check before read() And performs gofmt -s * Only reads if markType is detected --- routers/repo/view.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/routers/repo/view.go b/routers/repo/view.go index c4e6a69220aaa..a2e431e43597b 100644 --- a/routers/repo/view.go +++ b/routers/repo/view.go @@ -346,6 +346,20 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st ctx.Data["IsAudioFile"] = true case base.IsImageFile(buf): ctx.Data["IsImageFile"] = true + default: + if fileSize >= setting.UI.MaxDisplayFileSize { + ctx.Data["IsFileTooLarge"] = true + break + } + + if markupType := markup.Type(blob.Name()); markupType != "" { + d, _ := ioutil.ReadAll(dataRc) + buf = append(buf, d...) + ctx.Data["IsMarkup"] = true + ctx.Data["MarkupType"] = markupType + ctx.Data["FileContent"] = string(markup.Render(blob.Name(), buf, path.Dir(treeLink), ctx.Repo.Repository.ComposeMetas())) + } + } if ctx.Repo.CanEnableEditor() { From b539a6e6e34c62c606a3d1fc5b2786f4cfd91a3d Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Mon, 21 Oct 2019 06:58:59 +0000 Subject: [PATCH 144/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_tr-TR.ini | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index 6cc6c28dfe797..e2d8fb417ae05 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -73,6 +73,14 @@ preview=Önizleme loading=Yükleniyor… [startpage] +app_desc=Zahmetsiz, kendi sunucunuzda barındırabileceğiniz Git servisi +install=Kurulumu kolay +install_desc=Basitçe, platformunuz için uygun program dosyasını çalıştırın. Ya da Gitea'yı Docker veya Vagrant ile sunun, ya da paketlenmiş olarak edinin. +platform=Farklı platformlarda çalışablir +platform_desc=Gitea Go ile derleme yapılabilecek her yerde çalışmaktadır: Windows, macOS, Linux, ARM, vb. Hangisini seviyorsanız onu seçin! +lightweight=Hafif +lightweight_desc=Gitea'nın minimal gereksinimleri çok düşüktür ve ucuz bir Raspberry Pi üzerinde çalışabilmektedir. Makine enerjinizden tasarruf edin! +license=Açık Kaynak [install] install=Kurulum @@ -112,6 +120,7 @@ domain_helper=SSH kopyalama URL'leri için alan adı veya sunucu adresi. ssh_port=SSH Sunucu Portu http_port=Gitea HTTP Dinleme Portu http_port_helper=Gitea'nın web sunucusunun dinleyeceği port numarası. +app_url=Gitea Kök URL log_root_path=Günlük Dosyaları Yolu log_root_path_helper=Günlük dosyaları bu dizine kaydedilecektir. @@ -149,6 +158,7 @@ test_git_failed='git' komut testi başarısız: %v sqlite3_not_available=Bu Gieta sürümü SQLite3 desteklemiyor. Lütfen %s adresinden resmi çalışır sürümü ('gobuild' sürümünü değil) indirin. invalid_db_setting=Veritabanı ayarları geçersiz: %v invalid_repo_path=Depo kök dizini geçersiz: %v +run_user_not_match='Birlikte çalıştır' kullanıcı adı şimdiki kullanıcı adından farklıdır: %s -> %s save_config_failed=%v Yapılandırması kaydedilirken hata oluştu invalid_admin_setting=Yönetici hesap ayarları geçersiz: %v install_success=Hoşgeldiniz! Gitea'yı seçtiğiniz için teşekkür ederiz. Eğlenin ve kendinize iyi bakın! @@ -157,6 +167,8 @@ default_keep_email_private=E-posta adreslerini varsayılan olarak gizle default_keep_email_private_popup=Yeni kullanıcı hesaplarının e-posta adreslerini varsayılan olarak gizle. default_allow_create_organization=Varsayılan Olarak Organizasyon Oluşturmaya İzin Ver default_allow_create_organization_popup=Varsayılan olarak yeni kullanıcı hesaplarının organizasyon oluşturmasına izin ver. +default_enable_timetracking=Varsayılan Olarak Zaman Takibini Etkinleştir +default_enable_timetracking_popup=Yeni depolar için zaman takibini varsayılan olarak etkinleştir. no_reply_address=Gizlenecek E-Posta Alan Adı no_reply_address_helper=Gizlenmiş e-posta adresine sahip kullanıcılar için alan adı. Örneğin 'ali' kullanıcı adı, gizlenmiş e-postalar için alan adı 'yanityok.ornek.org' olarak ayarlandığında Git günlüğüne 'ali@yanityok.ornek.org' olarak kaydedilecektir. @@ -203,6 +215,8 @@ allow_password_change=Kullanıcıyı parola değiştirmeye zorla (önerilen) reset_password_mail_sent_prompt=%s adresine bir onay e-postası gönderildi. Hesap kurtarma işlemini tamamlamak için lütfen gelen kutunuzu sonraki %s içinde kontrol edin. active_your_account=Hesabınızı Aktifleştirin account_activated=Hesap etkinleştirildi +prohibit_login=Oturum Açma Yasağı +prohibit_login_desc=Hesabınız ile oturum açmanız yasaklanmış, lütfen site yöneticinizle iletişime geçin. resent_limit_prompt=Zaten bir doğrulama e-postası talep ettiniz. Lütfen 3 dakika bekleyip tekrar deneyin. has_unconfirmed_mail=Merhaba %s, doğrulanmamış bir e-posta adresin var (%s). Bir doğrulama e-postası almadıysanız ya da yenisine ihtiyacınız varsa lütfen aşağıdaki düğmeye tıklayın. resend_mail=Doğrulama e-postasını tekrar almak için buraya tıklayın @@ -1123,10 +1137,13 @@ settings.transfer_notices_1=- Bireysel bir kullanıcıya aktarırsanız depoya e settings.transfer_form_title=Onaylamak için depo adını girin: settings.wiki_delete=Wiki Verisini Sil settings.wiki_delete_desc=Depo wiki verilerini silmek kalıcıdır ve geri alınamaz. +settings.wiki_delete_notices_1=- Bu işlem, %s için depo wiki'sini kalıcı olarak siler ve devre dışı bırakır. settings.confirm_wiki_delete=Wiki Verisini Sil settings.wiki_deletion_success=Depo wiki verisi silindi. settings.delete=Bu Depoyu Sil +settings.delete_desc=Bir depoyu silmek kalıcıdır ve geri alınamaz. settings.delete_notices_1=- Bu işlem geri ALINAMAZ. +settings.delete_notices_fork_1=- Silme işleminden sonra bu deponun çatalları bağımsız hale gelecektir. settings.deletion_success=Depo silindi. settings.update_settings_success=Depo ayarları güncellendi. settings.transfer_owner=Yeni Sahip @@ -1147,7 +1164,9 @@ settings.change_team_access_not_allowed=Depo için takım erişimini değiştirm settings.team_not_in_organization=Takım, depo ile aynı organizasyonda değil settings.add_team_duplicate=Takım zaten bu depoya sahip settings.add_team_success=Takım artık bu depoya erişebilir. +settings.remove_team_success=Takımın depoya erişimi kaldırıldı. settings.add_webhook=Web İsteği Ekle +settings.add_webhook.invalid_channel_name=Web istemci kanal adı boş olamaz ve yalnızca bir # karakteri içeremez. settings.hooks_desc=Web istemcileri, belirli Gitea olayları tetiklendiğinde otomatik olarak bir sunucuya HTTP POST isteği yapar. Web istekleri kılavuzundan daha fazla bilgi edinebilirsiniz. settings.webhook_deletion=Web İsteğini Sil settings.webhook_deletion_desc=Bir web isteğini kaldırmak, ayarlarını ve teslimat geçmişini siler. Devam edilsin mi? @@ -1308,6 +1327,7 @@ diff.comment.add_review_comment=Yorum ekle diff.comment.start_review=İncelemeye başla diff.comment.reply=Yanıtla diff.review=İncele +diff.review.header=İnceleme gönder diff.review.comment=Yorum Yap diff.review.approve=Onayla diff.review.reject=Değişiklik iste @@ -1684,17 +1704,22 @@ config.disable_key_size_check=Minimum Anahtar Uzunluğu Kontrolünü Devre Dış config.enable_captcha=CAPTCHA'yı Etkinleştir config.active_code_lives=Kod Yaşamlarını Aktifleştir config.default_keep_email_private=E-posta Adreslerini Varsayılan Olarak Gizle +config.default_visibility_organization=Yeni organizasyonlar için varsayılan görünürlük +config.default_enable_dependencies=Konu Bağımlılıklarını Varsayılan Olarak Etkinleştir config.webhook_config=Web İstekleri Yapılandırması config.queue_length=Kuyruk Uzunluğu config.deliver_timeout=Dağıtım Zaman Aşımı config.skip_tls_verify=TLS Doğrulamasını Geç +config.mailer_config=SMTP Mailer Yapılandırması config.mailer_enabled=Aktif config.mailer_disable_helo=HELO'yu Devre Dışı Bırak config.mailer_name=İsim config.mailer_host=Sunucu config.mailer_user=Kullanıcı +config.mailer_use_sendmail=Sendmail Kullan +config.mailer_sendmail_path=Sendmail Yolu config.send_test_mail=Test E-postası Gönder config.test_mail_failed='%s' adresine test e-postası gönderilemedi: %v config.test_mail_sent='%s' adresine bir test e-postası gönderildi. @@ -1717,6 +1742,7 @@ config.session_life_time=Oturum Yaşam Zamanı config.https_only=Yalnız HTTPS config.cookie_life_time=Çerez Yaşam Zamanı +config.picture_config=Resim ve Avatar Yapılandırması config.picture_service=Resim Servisi config.disable_gravatar=Gravatar Hizmet Dışı From b1c1e1549b50bbd5929e2c4dd72a1dbf4b511b50 Mon Sep 17 00:00:00 2001 From: 6543 <24977596+6543@users.noreply.github.com> Date: Mon, 21 Oct 2019 09:51:24 +0200 Subject: [PATCH 145/173] Ensure that diff stats can scroll independently of the diff (#8581) This PR ensures that once opened the diff stats detail box can be scrolled independently of the diff on the compare page. Fixes #5532 Details: * make diff-detail-box the main container * move file diff at the same level as diff-stats * make diff-view options sticy again * make diff-stats scroll if to mouch * rm useless css info * less: mv diff-stats to own class * use new css class * cleanup less file * diff-counter: margin-right: 15px; * make CI work * make numbers colorful * add sign (-/+) to numbers --- public/css/index.css | 7 +- public/less/_repository.less | 43 +++-- templates/repo/diff/box.tmpl | 345 +++++++++++++++++------------------ 3 files changed, 205 insertions(+), 190 deletions(-) diff --git a/public/css/index.css b/public/css/index.css index 7c881bb2741b4..03a199d0b9af4 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -667,8 +667,6 @@ i.icon.centerlock{top:1.5em} .repository #commits-table td.sha .sha.label.isSigned.isVerified:hover,.repository #repo-files-table .sha.label.isSigned.isVerified:hover{background:rgba(33,186,69,.3)!important} .repository .diff-detail-box{padding:7px 0;background:#fff;line-height:30px} .repository .diff-detail-box>div:after{clear:both;content:"";display:block} -.repository .diff-detail-box ol{clear:both;padding-left:0;margin-top:5px;margin-bottom:28px} -.repository .diff-detail-box ol li{list-style:none;padding-bottom:4px;margin-bottom:4px;border-bottom:1px dashed #ddd;padding-left:6px} .repository .diff-detail-box span.status{display:inline-block;width:12px;height:12px;margin-right:8px;vertical-align:middle} .repository .diff-detail-box span.status.modify{background-color:#f0db88} .repository .diff-detail-box span.status.add{background-color:#b4e2b4} @@ -705,6 +703,11 @@ i.icon.centerlock{top:1.5em} .repository .diff-file-box.file-content{clear:right} .repository .diff-file-box.file-content img{max-width:100%;padding:5px 5px 0 5px} .repository .diff-file-box.file-content img.emoji{padding:0} +.repository .diff-stats{clear:both;margin-bottom:5px;max-height:400px;overflow:auto;padding-left:0} +.repository .diff-stats li{list-style:none;padding-bottom:4px;margin-bottom:4px;border-bottom:1px dashed #ddd;padding-left:6px} +.repository .diff-stats .diff-counter{margin-right:15px} +.repository .diff-stats .diff-counter .del{color:red} +.repository .diff-stats .diff-counter .add{color:green} .repository .repo-search-result{padding-top:10px;padding-bottom:10px} .repository .repo-search-result .lines-num a{color:inherit} .repository.quickstart .guide .item{padding:1em} diff --git a/public/less/_repository.less b/public/less/_repository.less index 3586eeccf0a60..33ee5761c40dc 100644 --- a/public/less/_repository.less +++ b/public/less/_repository.less @@ -1246,21 +1246,6 @@ display: block; } - ol { - clear: both; - padding-left: 0; - margin-top: 5px; - margin-bottom: 28px; - - li { - list-style: none; - padding-bottom: 4px; - margin-bottom: 4px; - border-bottom: 1px dashed #dddddd; - padding-left: 6px; - } - } - span.status { display: inline-block; width: 12px; @@ -1475,6 +1460,34 @@ } } + .diff-stats { + + clear: both; + margin-bottom: 5px; + max-height: 400px; + overflow: auto; + padding-left: 0; + + li { + list-style: none; + padding-bottom: 4px; + margin-bottom: 4px; + border-bottom: 1px dashed #dddddd; + padding-left: 6px; + } + + .diff-counter { + margin-right: 15px; + + .del { + color: red; + } + .add { + color: green; + } + } + } + .repo-search-result { padding-top: 10px; padding-bottom: 10px; diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl index 0179af2a515f0..a12fc9bd4b71e 100644 --- a/templates/repo/diff/box.tmpl +++ b/templates/repo/diff/box.tmpl @@ -16,8 +16,8 @@

{{.i18n.Tr "repo.diff.data_not_available"}}

{{else}} -
-
+
+
{{.i18n.Tr "repo.diff.stats_desc" .Diff.NumFiles .Diff.TotalAddition .Diff.TotalDeletion | Str2html}}
@@ -32,17 +32,17 @@ {{end}}
-
    +
      {{range .Diff.Files}}
    1. {{if not .IsBin}} - {{.Addition}} + +{{.Addition}}
      - {{.Deletion}} + -{{.Deletion}} {{else}} {{$.i18n.Tr "repo.diff.bin"}} {{end}} @@ -53,188 +53,187 @@
    2. {{end}}
    -
- - {{range $i, $file := .Diff.Files}} - {{if $file.IsIncomplete}} -
-

-
- {{if not $file.IsRenamed}} - + {{.Addition}} - -
-
-
- - {{.Deletion}} - {{end}} -
- {{$file.Name}} -
{{$.i18n.Tr "repo.diff.file_suppressed"}}
- {{if not $file.IsSubmodule}} - {{if $file.IsDeleted}} - {{$.i18n.Tr "repo.diff.view_file"}} - {{else}} - {{$.i18n.Tr "repo.diff.view_file"}} - {{end}} - {{end}} -

-
- {{else}} -
-

-
- {{if $file.IsBin}} - {{$.i18n.Tr "repo.diff.bin"}} - {{else if not $file.IsRenamed}} - + {{.Addition}} - -
-
-
- - {{.Deletion}} - {{end}} -
- {{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}}{{if .IsLFSFile}} ({{$.i18n.Tr "repo.stored_lfs"}}){{end}} - {{if not $file.IsSubmodule}} - {{if $file.IsDeleted}} - {{$.i18n.Tr "repo.diff.view_file"}} - {{else}} - {{$.i18n.Tr "repo.diff.view_file"}} + {{range $i, $file := .Diff.Files}} + {{if $file.IsIncomplete}} +
+

+
+ {{if not $file.IsRenamed}} + + {{.Addition}} + +
+
+
+ - {{.Deletion}} + {{end}} +
+ {{$file.Name}} +
{{$.i18n.Tr "repo.diff.file_suppressed"}}
+ {{if not $file.IsSubmodule}} + {{if $file.IsDeleted}} + {{$.i18n.Tr "repo.diff.view_file"}} + {{else}} + {{$.i18n.Tr "repo.diff.view_file"}} + {{end}} {{end}} - {{end}} -

-
- {{if ne $file.Type 4}} - {{$isImage := false}} - {{if $file.IsDeleted}} - {{$isImage = (call $.IsImageFileInBase $file.Name)}} - {{else}} - {{$isImage = (call $.IsImageFileInHead $file.Name)}} +

+
+ {{else}} +
+

+
+ {{if $file.IsBin}} + {{$.i18n.Tr "repo.diff.bin"}} + {{else if not $file.IsRenamed}} + + {{.Addition}} + +
+
+
+ - {{.Deletion}} + {{end}} +
+ {{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}}{{if .IsLFSFile}} ({{$.i18n.Tr "repo.stored_lfs"}}){{end}} + {{if not $file.IsSubmodule}} + {{if $file.IsDeleted}} + {{$.i18n.Tr "repo.diff.view_file"}} + {{else}} + {{$.i18n.Tr "repo.diff.view_file"}} + {{end}} {{end}} -
-

- {{ $oldImageExists := (call .root.FileExistsInBaseCommit .file.OldName) }} - {{if $oldImageExists}} + {{if or .file.IsDeleted (not .file.IsCreated)}} {{end}} - - - + {{if or .file.IsCreated (not .file.IsDeleted)}} + + + + {{end}}
- {{.root.i18n.Tr "repo.diff.file_image_width"}}: {{$imageInfoBase.Width}} + {{if $imageInfoBase }} + {{ $classWidth := "" }} + {{ $classHeight := "" }} + {{ $classByteSize := "" }} + {{if $imageInfoHead}} + {{if not (eq $imageInfoBase.Width $imageInfoHead.Width)}} + {{ $classWidth = "red" }} + {{end}} + {{if not (eq $imageInfoBase.Height $imageInfoHead.Height)}} + {{ $classHeight = "red" }} + {{end}} + {{if not (eq $imageInfoBase.ByteSize $imageInfoHead.ByteSize)}} + {{ $classByteSize = "red" }} + {{end}} + {{end}} + {{.root.i18n.Tr "repo.diff.file_image_width"}}: {{$imageInfoBase.Width}}  |  - {{.root.i18n.Tr "repo.diff.file_image_height"}}: {{$imageInfoBase.Height}} + {{.root.i18n.Tr "repo.diff.file_image_height"}}: {{$imageInfoBase.Height}}  |  - {{.root.i18n.Tr "repo.diff.file_byte_size"}}: {{FileSize $imageInfoBase.ByteSize}} + {{.root.i18n.Tr "repo.diff.file_byte_size"}}: {{FileSize $imageInfoBase.ByteSize}} + {{end}} - {{.root.i18n.Tr "repo.diff.file_image_width"}}: {{$imageInfoHead.Width}} + {{if $imageInfoHead }} + {{ $classWidth := "" }} + {{ $classHeight := "" }} + {{ $classByteSize := "" }} + {{if $imageInfoBase}} + {{if not (eq $imageInfoBase.Width $imageInfoHead.Width)}} + {{ $classWidth = "green" }} + {{end}} + {{if not (eq $imageInfoBase.Height $imageInfoHead.Height)}} + {{ $classHeight = "green" }} + {{end}} + {{if not (eq $imageInfoBase.ByteSize $imageInfoHead.ByteSize)}} + {{ $classByteSize = "green" }} + {{end}} + {{end}} + {{.root.i18n.Tr "repo.diff.file_image_width"}}: {{$imageInfoHead.Width}}  |  - {{.root.i18n.Tr "repo.diff.file_image_height"}}: {{$imageInfoHead.Height}} + {{.root.i18n.Tr "repo.diff.file_image_height"}}: {{$imageInfoHead.Height}}  |  - {{.root.i18n.Tr "repo.diff.file_byte_size"}}: {{FileSize $imageInfoHead.ByteSize}} + {{.root.i18n.Tr "repo.diff.file_byte_size"}}: {{FileSize $imageInfoHead.ByteSize}} + {{end}}
{{if not .LatestPullRequest}} - {{if and (not .IsDeleted) $.AllowsPulls (gt .CommitsAhead 0)}} + {{if .IsIncluded}} + + {{$.i18n.Tr "repo.branch.included"}} + + {{else if and (not .IsDeleted) $.AllowsPulls (gt .CommitsAhead 0)}} From 8ad26976114c4fed6269a40e52632d065167bd20 Mon Sep 17 00:00:00 2001 From: David Svantesson Date: Tue, 15 Oct 2019 02:55:21 +0200 Subject: [PATCH 091/173] Recalculate repository access only for specific user (#8481) * Recalculate repository access only for specific user Signed-off-by: David Svantesson * Handle user repositories as well, and only add access if minimum mode * Need to get repo owner to check if organization --- models/access.go | 49 ++++++++++++++++++++++++++++++++++++ models/org_team.go | 4 +-- models/repo_collaboration.go | 19 +++++++++----- 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/models/access.go b/models/access.go index 3cdfc62f2179f..213efe08a6808 100644 --- a/models/access.go +++ b/models/access.go @@ -246,6 +246,55 @@ func (repo *Repository) recalculateTeamAccesses(e Engine, ignTeamID int64) (err return repo.refreshAccesses(e, accessMap) } +// recalculateUserAccess recalculates new access for a single user +// Usable if we know access only affected one user +func (repo *Repository) recalculateUserAccess(e Engine, uid int64) (err error) { + minMode := AccessModeRead + if !repo.IsPrivate { + minMode = AccessModeWrite + } + + accessMode := AccessModeNone + collaborator, err := repo.getCollaboration(e, uid) + if err != nil { + return err + } else if collaborator != nil { + accessMode = collaborator.Mode + } + + if err = repo.getOwner(e); err != nil { + return err + } else if repo.Owner.IsOrganization() { + var teams []Team + if err := e.Join("INNER", "team_repo", "team_repo.team_id = team.id"). + Join("INNER", "team_user", "team_user.team_id = team.id"). + Where("team.org_id = ?", repo.OwnerID). + And("team_repo.repo_id=?", repo.ID). + And("team_user.uid=?", uid). + Find(&teams); err != nil { + return err + } + + for _, t := range teams { + if t.IsOwnerTeam() { + t.Authorize = AccessModeOwner + } + + accessMode = maxAccessMode(accessMode, t.Authorize) + } + } + + // Delete old user accesses and insert new one for repository. + if _, err = e.Delete(&Access{RepoID: repo.ID, UserID: uid}); err != nil { + return fmt.Errorf("delete old user accesses: %v", err) + } else if accessMode >= minMode { + if _, err = e.Insert(&Access{RepoID: repo.ID, UserID: uid, Mode: accessMode}); err != nil { + return fmt.Errorf("insert new user accesses: %v", err) + } + } + return nil +} + func (repo *Repository) recalculateAccesses(e Engine) error { if repo.Owner.IsOrganization() { return repo.recalculateTeamAccesses(e, 0) diff --git a/models/org_team.go b/models/org_team.go index 9170ea2c2af88..10d53e3a860e0 100644 --- a/models/org_team.go +++ b/models/org_team.go @@ -723,7 +723,7 @@ func AddTeamMember(team *Team, userID int64) error { // Give access to team repositories. for _, repo := range team.Repos { - if err := repo.recalculateTeamAccesses(sess, 0); err != nil { + if err := repo.recalculateUserAccess(sess, userID); err != nil { return err } if setting.Service.AutoWatchNewRepos { @@ -768,7 +768,7 @@ func removeTeamMember(e *xorm.Session, team *Team, userID int64) error { // Delete access to team repositories. for _, repo := range team.Repos { - if err := repo.recalculateTeamAccesses(e, 0); err != nil { + if err := repo.recalculateUserAccess(e, userID); err != nil { return err } diff --git a/models/repo_collaboration.go b/models/repo_collaboration.go index 40ddf6a28cfec..3d6447c1963b3 100644 --- a/models/repo_collaboration.go +++ b/models/repo_collaboration.go @@ -41,12 +41,7 @@ func (repo *Repository) AddCollaborator(u *User) error { return err } - if repo.Owner.IsOrganization() { - err = repo.recalculateTeamAccesses(sess, 0) - } else { - err = repo.recalculateAccesses(sess) - } - if err != nil { + if err = repo.recalculateUserAccess(sess, u.ID); err != nil { return fmt.Errorf("recalculateAccesses 'team=%v': %v", repo.Owner.IsOrganization(), err) } @@ -89,6 +84,18 @@ func (repo *Repository) GetCollaborators() ([]*Collaborator, error) { return repo.getCollaborators(x) } +func (repo *Repository) getCollaboration(e Engine, uid int64) (*Collaboration, error) { + collaboration := &Collaboration{ + RepoID: repo.ID, + UserID: uid, + } + has, err := e.Get(collaboration) + if !has { + collaboration = nil + } + return collaboration, err +} + func (repo *Repository) isCollaborator(e Engine, userID int64) (bool, error) { return e.Get(&Collaboration{RepoID: repo.ID, UserID: userID}) } From cea8ea5ae64bbb287ed7011c6fc2e51ccdfb9cb3 Mon Sep 17 00:00:00 2001 From: guillep2k <18600385+guillep2k@users.noreply.github.com> Date: Mon, 14 Oct 2019 22:31:09 -0300 Subject: [PATCH 092/173] Support inline rendering of CUSTOM_URL_SCHEMES (#8496) * Support inline rendering of CUSTOM_URL_SCHEMES * Fix lint * Add tests * Fix lint --- modules/markup/html.go | 26 ++++++++++++++++++++++++++ modules/markup/html_test.go | 19 +++++++++++++++++++ modules/markup/markup.go | 4 ++++ modules/markup/sanitizer.go | 28 +++++++++++++++++----------- 4 files changed, 66 insertions(+), 11 deletions(-) diff --git a/modules/markup/html.go b/modules/markup/html.go index fc823b1f308ab..1ff7a41cbb0dd 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -92,6 +92,32 @@ func getIssueFullPattern() *regexp.Regexp { return issueFullPattern } +// CustomLinkURLSchemes allows for additional schemes to be detected when parsing links within text +func CustomLinkURLSchemes(schemes []string) { + schemes = append(schemes, "http", "https") + withAuth := make([]string, 0, len(schemes)) + validScheme := regexp.MustCompile(`^[a-z]+$`) + for _, s := range schemes { + if !validScheme.MatchString(s) { + continue + } + without := false + for _, sna := range xurls.SchemesNoAuthority { + if s == sna { + without = true + break + } + } + if without { + s += ":" + } else { + s += "://" + } + withAuth = append(withAuth, s) + } + linkRegex, _ = xurls.StrictMatchingScheme(strings.Join(withAuth, "|")) +} + // IsSameDomain checks if given url string has the same hostname as current Gitea instance func IsSameDomain(s string) bool { if strings.HasPrefix(s, "/") { diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go index 66e56f71a74d3..91ef320b40927 100644 --- a/modules/markup/html_test.go +++ b/modules/markup/html_test.go @@ -89,6 +89,11 @@ func TestRender_links(t *testing.T) { } // Text that should be turned into URL + defaultCustom := setting.Markdown.CustomURLSchemes + setting.Markdown.CustomURLSchemes = []string{"ftp", "magnet"} + ReplaceSanitizer() + CustomLinkURLSchemes(setting.Markdown.CustomURLSchemes) + test( "https://www.example.com", `

https://www.example.com

`) @@ -131,6 +136,12 @@ func TestRender_links(t *testing.T) { test( "https://username:password@gitea.com", `

https://username:password@gitea.com

`) + test( + "ftp://gitea.com/file.txt", + `

ftp://gitea.com/file.txt

`) + test( + "magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&dn=download", + `

magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&dn=download

`) // Test that should *not* be turned into URL test( @@ -154,6 +165,14 @@ func TestRender_links(t *testing.T) { test( "www", `

www

`) + test( + "ftps://gitea.com", + `

ftps://gitea.com

`) + + // Restore previous settings + setting.Markdown.CustomURLSchemes = defaultCustom + ReplaceSanitizer() + CustomLinkURLSchemes(setting.Markdown.CustomURLSchemes) } func TestRender_email(t *testing.T) { diff --git a/modules/markup/markup.go b/modules/markup/markup.go index dc43b533c022a..008b21ab977a3 100644 --- a/modules/markup/markup.go +++ b/modules/markup/markup.go @@ -9,12 +9,16 @@ import ( "strings" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" ) // Init initialize regexps for markdown parsing func Init() { getIssueFullPattern() NewSanitizer() + if len(setting.Markdown.CustomURLSchemes) > 0 { + CustomLinkURLSchemes(setting.Markdown.CustomURLSchemes) + } // since setting maybe changed extensions, this will reload all parser extensions mapping extParsers = make(map[string]Parser) diff --git a/modules/markup/sanitizer.go b/modules/markup/sanitizer.go index fd6f90b2ab1bf..f873e8105e659 100644 --- a/modules/markup/sanitizer.go +++ b/modules/markup/sanitizer.go @@ -28,20 +28,26 @@ var sanitizer = &Sanitizer{} // entire application lifecycle. func NewSanitizer() { sanitizer.init.Do(func() { - sanitizer.policy = bluemonday.UGCPolicy() - // We only want to allow HighlightJS specific classes for code blocks - sanitizer.policy.AllowAttrs("class").Matching(regexp.MustCompile(`^language-\w+$`)).OnElements("code") + ReplaceSanitizer() + }) +} - // Checkboxes - sanitizer.policy.AllowAttrs("type").Matching(regexp.MustCompile(`^checkbox$`)).OnElements("input") - sanitizer.policy.AllowAttrs("checked", "disabled").OnElements("input") +// ReplaceSanitizer replaces the current sanitizer to account for changes in settings +func ReplaceSanitizer() { + sanitizer = &Sanitizer{} + sanitizer.policy = bluemonday.UGCPolicy() + // We only want to allow HighlightJS specific classes for code blocks + sanitizer.policy.AllowAttrs("class").Matching(regexp.MustCompile(`^language-\w+$`)).OnElements("code") - // Custom URL-Schemes - sanitizer.policy.AllowURLSchemes(setting.Markdown.CustomURLSchemes...) + // Checkboxes + sanitizer.policy.AllowAttrs("type").Matching(regexp.MustCompile(`^checkbox$`)).OnElements("input") + sanitizer.policy.AllowAttrs("checked", "disabled").OnElements("input") - // Allow keyword markup - sanitizer.policy.AllowAttrs("class").Matching(regexp.MustCompile(`^` + keywordClass + `$`)).OnElements("span") - }) + // Custom URL-Schemes + sanitizer.policy.AllowURLSchemes(setting.Markdown.CustomURLSchemes...) + + // Allow keyword markup + sanitizer.policy.AllowAttrs("class").Matching(regexp.MustCompile(`^` + keywordClass + `$`)).OnElements("span") } // Sanitize takes a string that contains a HTML fragment or document and applies policy whitelist. From ebe8ff782fd56378e9946b716fd7e95babf67411 Mon Sep 17 00:00:00 2001 From: Benson Muite Date: Tue, 15 Oct 2019 05:39:55 +0300 Subject: [PATCH 093/173] Update config-cheat-sheet.en-us.md (#8497) * Update config-cheat-sheet.en-us.md Add more information on configuring URI hyperlink rendering for Markdown. * Update config-cheat-sheet.en-us.md Update description as suggested by @guillep2k * Update docs/content/doc/advanced/config-cheat-sheet.en-us.md Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> --- docs/content/doc/advanced/config-cheat-sheet.en-us.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 6313e705d4c0d..29a971da12d68 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -108,6 +108,9 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. ## Markdown (`markdown`) - `ENABLE_HARD_LINE_BREAK`: **false**: Enable Markdown's hard line break extension. +- `CUSTOM_URL_SCHEMES`: Use a comma separated list (ftp,git,svn) to indicate additional + URL hyperlinks to be rendered in Markdown. URLs beginning in http and https are + always displayed ## Server (`server`) From 34fb9d68a5567423ddde736ff42f9780f4048366 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 15 Oct 2019 11:28:40 +0800 Subject: [PATCH 094/173] Move AddTestPullRequestTask to pull service package from models (#8324) * move AddTestPullRequestTask to pull service package from models * fix fmt --- models/pull.go | 87 ------------------------------------ modules/repofiles/update.go | 3 +- routers/repo/pull.go | 2 +- services/pull/merge.go | 2 +- services/pull/pull.go | 88 +++++++++++++++++++++++++++++++++++++ 5 files changed, 92 insertions(+), 90 deletions(-) diff --git a/models/pull.go b/models/pull.go index ff1f7b773b2b1..962e433fb0759 100644 --- a/models/pull.go +++ b/models/pull.go @@ -1072,93 +1072,6 @@ func (prs PullRequestList) InvalidateCodeComments(doer *User, repo *git.Reposito return prs.invalidateCodeComments(x, doer, repo, branch) } -func addHeadRepoTasks(prs []*PullRequest) { - for _, pr := range prs { - log.Trace("addHeadRepoTasks[%d]: composing new test task", pr.ID) - if err := pr.UpdatePatch(); err != nil { - log.Error("UpdatePatch: %v", err) - continue - } else if err := pr.PushToBaseRepo(); err != nil { - log.Error("PushToBaseRepo: %v", err) - continue - } - - pr.AddToTaskQueue() - } -} - -// AddTestPullRequestTask adds new test tasks by given head/base repository and head/base branch, -// and generate new patch for testing as needed. -func AddTestPullRequestTask(doer *User, repoID int64, branch string, isSync bool) { - log.Trace("AddTestPullRequestTask [head_repo_id: %d, head_branch: %s]: finding pull requests", repoID, branch) - prs, err := GetUnmergedPullRequestsByHeadInfo(repoID, branch) - if err != nil { - log.Error("Find pull requests [head_repo_id: %d, head_branch: %s]: %v", repoID, branch, err) - return - } - - if isSync { - requests := PullRequestList(prs) - if err = requests.LoadAttributes(); err != nil { - log.Error("PullRequestList.LoadAttributes: %v", err) - } - if invalidationErr := checkForInvalidation(requests, repoID, doer, branch); invalidationErr != nil { - log.Error("checkForInvalidation: %v", invalidationErr) - } - if err == nil { - for _, pr := range prs { - pr.Issue.PullRequest = pr - if err = pr.Issue.LoadAttributes(); err != nil { - log.Error("LoadAttributes: %v", err) - continue - } - if err = PrepareWebhooks(pr.Issue.Repo, HookEventPullRequest, &api.PullRequestPayload{ - Action: api.HookIssueSynchronized, - Index: pr.Issue.Index, - PullRequest: pr.Issue.PullRequest.APIFormat(), - Repository: pr.Issue.Repo.APIFormat(AccessModeNone), - Sender: doer.APIFormat(), - }); err != nil { - log.Error("PrepareWebhooks [pull_id: %v]: %v", pr.ID, err) - continue - } - go HookQueue.Add(pr.Issue.Repo.ID) - } - } - - } - - addHeadRepoTasks(prs) - - log.Trace("AddTestPullRequestTask [base_repo_id: %d, base_branch: %s]: finding pull requests", repoID, branch) - prs, err = GetUnmergedPullRequestsByBaseInfo(repoID, branch) - if err != nil { - log.Error("Find pull requests [base_repo_id: %d, base_branch: %s]: %v", repoID, branch, err) - return - } - for _, pr := range prs { - pr.AddToTaskQueue() - } -} - -func checkForInvalidation(requests PullRequestList, repoID int64, doer *User, branch string) error { - repo, err := GetRepositoryByID(repoID) - if err != nil { - return fmt.Errorf("GetRepositoryByID: %v", err) - } - gitRepo, err := git.OpenRepository(repo.RepoPath()) - if err != nil { - return fmt.Errorf("git.OpenRepository: %v", err) - } - go func() { - err := requests.InvalidateCodeComments(doer, gitRepo, branch) - if err != nil { - log.Error("PullRequestList.InvalidateCodeComments: %v", err) - } - }() - return nil -} - // ChangeUsernameInPullRequests changes the name of head_user_name func ChangeUsernameInPullRequests(oldUserName, newUserName string) error { pr := PullRequest{ diff --git a/modules/repofiles/update.go b/modules/repofiles/update.go index 1a1fe6c389f48..8a1e51730bcc5 100644 --- a/modules/repofiles/update.go +++ b/modules/repofiles/update.go @@ -19,6 +19,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" + pull_service "code.gitea.io/gitea/services/pull" stdcharset "golang.org/x/net/html/charset" "golang.org/x/text/transform" @@ -498,7 +499,7 @@ func PushUpdate(repo *models.Repository, branch string, opts models.PushUpdateOp log.Trace("TriggerTask '%s/%s' by %s", repo.Name, branch, pusher.Name) - go models.AddTestPullRequestTask(pusher, repo.ID, branch, true) + go pull_service.AddTestPullRequestTask(pusher, repo.ID, branch, true) if opts.RefFullName == git.BranchPrefix+repo.DefaultBranch { models.UpdateRepoIndexer(repo) diff --git a/routers/repo/pull.go b/routers/repo/pull.go index 7af01c46ba660..8b97e55670987 100644 --- a/routers/repo/pull.go +++ b/routers/repo/pull.go @@ -820,7 +820,7 @@ func TriggerTask(ctx *context.Context) { log.Trace("TriggerTask '%s/%s' by %s", repo.Name, branch, pusher.Name) go models.HookQueue.Add(repo.ID) - go models.AddTestPullRequestTask(pusher, repo.ID, branch, true) + go pull_service.AddTestPullRequestTask(pusher, repo.ID, branch, true) ctx.Status(202) } diff --git a/services/pull/merge.go b/services/pull/merge.go index e83784f31ebdb..355d6dd9110b4 100644 --- a/services/pull/merge.go +++ b/services/pull/merge.go @@ -50,7 +50,7 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor } defer func() { - go models.AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false) + go AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false) }() // Clone base repo. diff --git a/services/pull/pull.go b/services/pull/pull.go index 0dbd8fcd1a148..3c584fce74844 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -8,6 +8,7 @@ import ( "fmt" "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" api "code.gitea.io/gitea/modules/structs" ) @@ -47,3 +48,90 @@ func NewPullRequest(repo *models.Repository, pull *models.Issue, labelIDs []int6 return nil } + +func checkForInvalidation(requests models.PullRequestList, repoID int64, doer *models.User, branch string) error { + repo, err := models.GetRepositoryByID(repoID) + if err != nil { + return fmt.Errorf("GetRepositoryByID: %v", err) + } + gitRepo, err := git.OpenRepository(repo.RepoPath()) + if err != nil { + return fmt.Errorf("git.OpenRepository: %v", err) + } + go func() { + err := requests.InvalidateCodeComments(doer, gitRepo, branch) + if err != nil { + log.Error("PullRequestList.InvalidateCodeComments: %v", err) + } + }() + return nil +} + +func addHeadRepoTasks(prs []*models.PullRequest) { + for _, pr := range prs { + log.Trace("addHeadRepoTasks[%d]: composing new test task", pr.ID) + if err := pr.UpdatePatch(); err != nil { + log.Error("UpdatePatch: %v", err) + continue + } else if err := pr.PushToBaseRepo(); err != nil { + log.Error("PushToBaseRepo: %v", err) + continue + } + + pr.AddToTaskQueue() + } +} + +// AddTestPullRequestTask adds new test tasks by given head/base repository and head/base branch, +// and generate new patch for testing as needed. +func AddTestPullRequestTask(doer *models.User, repoID int64, branch string, isSync bool) { + log.Trace("AddTestPullRequestTask [head_repo_id: %d, head_branch: %s]: finding pull requests", repoID, branch) + prs, err := models.GetUnmergedPullRequestsByHeadInfo(repoID, branch) + if err != nil { + log.Error("Find pull requests [head_repo_id: %d, head_branch: %s]: %v", repoID, branch, err) + return + } + + if isSync { + requests := models.PullRequestList(prs) + if err = requests.LoadAttributes(); err != nil { + log.Error("PullRequestList.LoadAttributes: %v", err) + } + if invalidationErr := checkForInvalidation(requests, repoID, doer, branch); invalidationErr != nil { + log.Error("checkForInvalidation: %v", invalidationErr) + } + if err == nil { + for _, pr := range prs { + pr.Issue.PullRequest = pr + if err = pr.Issue.LoadAttributes(); err != nil { + log.Error("LoadAttributes: %v", err) + continue + } + if err = models.PrepareWebhooks(pr.Issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{ + Action: api.HookIssueSynchronized, + Index: pr.Issue.Index, + PullRequest: pr.Issue.PullRequest.APIFormat(), + Repository: pr.Issue.Repo.APIFormat(models.AccessModeNone), + Sender: doer.APIFormat(), + }); err != nil { + log.Error("PrepareWebhooks [pull_id: %v]: %v", pr.ID, err) + continue + } + go models.HookQueue.Add(pr.Issue.Repo.ID) + } + } + + } + + addHeadRepoTasks(prs) + + log.Trace("AddTestPullRequestTask [base_repo_id: %d, base_branch: %s]: finding pull requests", repoID, branch) + prs, err = models.GetUnmergedPullRequestsByBaseInfo(repoID, branch) + if err != nil { + log.Error("Find pull requests [base_repo_id: %d, base_branch: %s]: %v", repoID, branch, err) + return + } + for _, pr := range prs { + pr.AddToTaskQueue() + } +} From 20477a69ea123a7800ebf94bfd2225eb9ae90e8f Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 15 Oct 2019 13:03:05 +0800 Subject: [PATCH 095/173] Move clearlabels from models to issue service (#8326) * move clearlabels from models to issue service * improve code * Apply suggestions from code review Co-Authored-By: zeripath --- models/issue.go | 34 ------------- modules/notification/notification.go | 2 + modules/notification/webhook/webhook.go | 67 +++++++++++++++++++++++++ routers/api/v1/repo/issue_label.go | 3 +- routers/repo/issue_label.go | 3 +- services/issue/label.go | 21 ++++++++ 6 files changed, 94 insertions(+), 36 deletions(-) create mode 100644 modules/notification/webhook/webhook.go create mode 100644 services/issue/label.go diff --git a/models/issue.go b/models/issue.go index fc675a3ffbe2a..90925f92f5979 100644 --- a/models/issue.go +++ b/models/issue.go @@ -596,40 +596,6 @@ func (issue *Issue) ClearLabels(doer *User) (err error) { if err = sess.Commit(); err != nil { return fmt.Errorf("Commit: %v", err) } - sess.Close() - - if err = issue.LoadPoster(); err != nil { - return fmt.Errorf("loadPoster: %v", err) - } - - mode, _ := AccessLevel(issue.Poster, issue.Repo) - if issue.IsPull { - err = issue.PullRequest.LoadIssue() - if err != nil { - log.Error("LoadIssue: %v", err) - return - } - err = PrepareWebhooks(issue.Repo, HookEventPullRequest, &api.PullRequestPayload{ - Action: api.HookIssueLabelCleared, - Index: issue.Index, - PullRequest: issue.PullRequest.APIFormat(), - Repository: issue.Repo.APIFormat(mode), - Sender: doer.APIFormat(), - }) - } else { - err = PrepareWebhooks(issue.Repo, HookEventIssues, &api.IssuePayload{ - Action: api.HookIssueLabelCleared, - Index: issue.Index, - Issue: issue.APIFormat(), - Repository: issue.Repo.APIFormat(mode), - Sender: doer.APIFormat(), - }) - } - if err != nil { - log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err) - } else { - go HookQueue.Add(issue.RepoID) - } return nil } diff --git a/modules/notification/notification.go b/modules/notification/notification.go index e0de88346d75f..06220ecb04019 100644 --- a/modules/notification/notification.go +++ b/modules/notification/notification.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/modules/notification/indexer" "code.gitea.io/gitea/modules/notification/mail" "code.gitea.io/gitea/modules/notification/ui" + "code.gitea.io/gitea/modules/notification/webhook" ) var ( @@ -27,6 +28,7 @@ func init() { RegisterNotifier(ui.NewNotifier()) RegisterNotifier(mail.NewNotifier()) RegisterNotifier(indexer.NewNotifier()) + RegisterNotifier(webhook.NewNotifier()) } // NotifyCreateIssueComment notifies issue comment related message to notifiers diff --git a/modules/notification/webhook/webhook.go b/modules/notification/webhook/webhook.go new file mode 100644 index 0000000000000..33adfaa739ba7 --- /dev/null +++ b/modules/notification/webhook/webhook.go @@ -0,0 +1,67 @@ +// Copyright 2019 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 webhook + +import ( + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/notification/base" + api "code.gitea.io/gitea/modules/structs" +) + +type webhookNotifier struct { + base.NullNotifier +} + +var ( + _ base.Notifier = &webhookNotifier{} +) + +// NewNotifier create a new webhookNotifier notifier +func NewNotifier() base.Notifier { + return &webhookNotifier{} +} + +func (m *webhookNotifier) NotifyIssueClearLabels(doer *models.User, issue *models.Issue) { + if err := issue.LoadPoster(); err != nil { + log.Error("loadPoster: %v", err) + return + } + + if err := issue.LoadRepo(); err != nil { + log.Error("LoadRepo: %v", err) + return + } + + mode, _ := models.AccessLevel(issue.Poster, issue.Repo) + var err error + if issue.IsPull { + if err = issue.LoadPullRequest(); err != nil { + log.Error("LoadPullRequest: %v", err) + return + } + + err = models.PrepareWebhooks(issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{ + Action: api.HookIssueLabelCleared, + Index: issue.Index, + PullRequest: issue.PullRequest.APIFormat(), + Repository: issue.Repo.APIFormat(mode), + Sender: doer.APIFormat(), + }) + } else { + err = models.PrepareWebhooks(issue.Repo, models.HookEventIssues, &api.IssuePayload{ + Action: api.HookIssueLabelCleared, + Index: issue.Index, + Issue: issue.APIFormat(), + Repository: issue.Repo.APIFormat(mode), + Sender: doer.APIFormat(), + }) + } + if err != nil { + log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err) + } else { + go models.HookQueue.Add(issue.RepoID) + } +} diff --git a/routers/api/v1/repo/issue_label.go b/routers/api/v1/repo/issue_label.go index e66bc35e90b42..7bd76c24c23cf 100644 --- a/routers/api/v1/repo/issue_label.go +++ b/routers/api/v1/repo/issue_label.go @@ -9,6 +9,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" + issue_service "code.gitea.io/gitea/services/issue" ) // ListIssueLabels list all the labels of an issue @@ -314,7 +315,7 @@ func ClearIssueLabels(ctx *context.APIContext) { return } - if err := issue.ClearLabels(ctx.User); err != nil { + if err := issue_service.ClearLabels(issue, ctx.User); err != nil { ctx.Error(500, "ClearLabels", err) return } diff --git a/routers/repo/issue_label.go b/routers/repo/issue_label.go index 452a0a4c0c3ee..53c37e2e9762f 100644 --- a/routers/repo/issue_label.go +++ b/routers/repo/issue_label.go @@ -10,6 +10,7 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" + issue_service "code.gitea.io/gitea/services/issue" ) const ( @@ -132,7 +133,7 @@ func UpdateIssueLabel(ctx *context.Context) { switch action := ctx.Query("action"); action { case "clear": for _, issue := range issues { - if err := issue.ClearLabels(ctx.User); err != nil { + if err := issue_service.ClearLabels(issue, ctx.User); err != nil { ctx.ServerError("ClearLabels", err) return } diff --git a/services/issue/label.go b/services/issue/label.go new file mode 100644 index 0000000000000..4af8c2b97e04a --- /dev/null +++ b/services/issue/label.go @@ -0,0 +1,21 @@ +// Copyright 2019 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 issue + +import ( + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/notification" +) + +// ClearLabels clears all of an issue's labels +func ClearLabels(issue *models.Issue, doer *models.User) (err error) { + if err = issue.ClearLabels(doer); err != nil { + return + } + + notification.NotifyIssueClearLabels(doer, issue) + + return nil +} From 6fa14ac3c82433f7f9bff4f4fe2ec6e33deb82ec Mon Sep 17 00:00:00 2001 From: Benson Muite Date: Tue, 15 Oct 2019 10:14:58 +0300 Subject: [PATCH 096/173] Update app.ini.sample (#8498) * Update app.ini.sample Give further information on hyperlink rendering in Markdown * Update app.ini.sample Follow feedback from @guillep2k for CUSTOM_URL in markdown to indicate http and https are always rendered as links. * Update custom/conf/app.ini.sample Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Update custom/conf/app.ini.sample Co-Authored-By: Antoine GIRARD --- custom/conf/app.ini.sample | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index 442ac4b5bb9df..5ee2162ba355e 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -141,8 +141,9 @@ KEYWORDS = go,git,self-hosted,gitea [markdown] ; Enable hard line break extension ENABLE_HARD_LINE_BREAK = false -; List of custom URL-Schemes that are allowed as links when rendering Markdown -; for example git,magnet +; Comma separated list of custom URL-Schemes that are allowed as links when rendering Markdown +; for example git,magnet,ftp (more at https://en.wikipedia.org/wiki/List_of_URI_schemes) +; URLs starting with http and https are always displayed, whatever is put in this entry. CUSTOM_URL_SCHEMES = ; List of file extensions that should be rendered/edited as Markdown ; Separate the extensions with a comma. To render files without any extension as markdown, just put a comma @@ -826,4 +827,4 @@ QUEUE_TYPE = channel QUEUE_LENGTH = 1000 ; Task queue connction string, available only when `QUEUE_TYPE` is `redis`. ; If there is a password of redis, use `addrs=127.0.0.1:6379 password=123 db=0`. -QUEUE_CONN_STR = "addrs=127.0.0.1:6379 db=0" \ No newline at end of file +QUEUE_CONN_STR = "addrs=127.0.0.1:6379 db=0" From 1e9b33052553bb546ca526f04816579e2853c8da Mon Sep 17 00:00:00 2001 From: "oscar.lofwenhamn" <44643697+oscarlofwenhamn@users.noreply.github.com> Date: Tue, 15 Oct 2019 10:40:42 +0200 Subject: [PATCH 097/173] Update CodeMirror to version 5.49.0 (#8381) * Update CodeMirror to version 5.49.0 * Update CodeMirror versions in librejs and VERSIONS --- public/vendor/VERSIONS | 2 +- public/vendor/librejs.html | 4 +- .../codemirror/addon/comment/comment.js | 209 ++++ .../addon/comment/continuecomment.js | 78 ++ .../codemirror/addon/dialog/dialog.css | 32 + .../plugins/codemirror/addon/dialog/dialog.js | 161 +++ .../codemirror/addon/display/autorefresh.js | 47 + .../codemirror/addon/display/fullscreen.css | 6 + .../codemirror/addon/display/fullscreen.js | 41 + .../plugins/codemirror/addon/display/panel.js | 127 +++ .../codemirror/addon/display/placeholder.js | 63 ++ .../codemirror/addon/display/rulers.js | 51 + .../codemirror/addon/edit/closebrackets.js | 191 ++++ .../plugins/codemirror/addon/edit/closetag.js | 184 +++ .../codemirror/addon/edit/continuelist.js | 99 ++ .../codemirror/addon/edit/matchbrackets.js | 150 +++ .../codemirror/addon/edit/matchtags.js | 66 ++ .../codemirror/addon/edit/trailingspace.js | 27 + .../codemirror/addon/fold/brace-fold.js | 105 ++ .../codemirror/addon/fold/comment-fold.js | 59 + .../plugins/codemirror/addon/fold/foldcode.js | 152 +++ .../codemirror/addon/fold/foldgutter.css | 20 + .../codemirror/addon/fold/foldgutter.js | 151 +++ .../codemirror/addon/fold/indent-fold.js | 48 + .../codemirror/addon/fold/markdown-fold.js | 49 + .../plugins/codemirror/addon/fold/xml-fold.js | 184 +++ .../codemirror/addon/hint/anyword-hint.js | 41 + .../plugins/codemirror/addon/hint/css-hint.js | 60 + .../codemirror/addon/hint/html-hint.js | 350 ++++++ .../codemirror/addon/hint/javascript-hint.js | 157 +++ .../codemirror/addon/hint/show-hint.css | 36 + .../codemirror/addon/hint/show-hint.js | 460 ++++++++ .../plugins/codemirror/addon/hint/sql-hint.js | 304 +++++ .../plugins/codemirror/addon/hint/xml-hint.js | 123 ++ .../addon/lint/coffeescript-lint.js | 47 + .../plugins/codemirror/addon/lint/css-lint.js | 40 + .../codemirror/addon/lint/html-lint.js | 59 + .../codemirror/addon/lint/javascript-lint.js | 63 ++ .../codemirror/addon/lint/json-lint.js | 40 + .../plugins/codemirror/addon/lint/lint.css | 73 ++ .../plugins/codemirror/addon/lint/lint.js | 252 +++++ .../codemirror/addon/lint/yaml-lint.js | 41 + .../plugins/codemirror/addon/merge/merge.css | 119 ++ .../plugins/codemirror/addon/merge/merge.js | 1002 +++++++++++++++++ .../plugins/codemirror/addon/mode/loadmode.js | 2 +- .../codemirror/addon/mode/multiplex.js | 18 +- .../codemirror/addon/mode/multiplex_test.js | 2 +- .../plugins/codemirror/addon/mode/overlay.js | 15 +- .../plugins/codemirror/addon/mode/simple.js | 15 +- .../codemirror/addon/runmode/colorize.js | 40 + .../addon/runmode/runmode-standalone.js | 158 +++ .../codemirror/addon/runmode/runmode.js | 72 ++ .../codemirror/addon/runmode/runmode.node.js | 197 ++++ .../addon/scroll/annotatescrollbar.js | 122 ++ .../codemirror/addon/scroll/scrollpastend.js | 48 + .../addon/scroll/simplescrollbars.css | 66 ++ .../addon/scroll/simplescrollbars.js | 152 +++ .../codemirror/addon/search/jump-to-line.js | 50 + .../addon/search/match-highlighter.js | 165 +++ .../addon/search/matchesonscrollbar.css | 8 + .../addon/search/matchesonscrollbar.js | 97 ++ .../plugins/codemirror/addon/search/search.js | 260 +++++ .../codemirror/addon/search/searchcursor.js | 293 +++++ .../codemirror/addon/selection/active-line.js | 72 ++ .../addon/selection/mark-selection.js | 119 ++ .../addon/selection/selection-pointer.js | 98 ++ .../plugins/codemirror/addon/tern/tern.css | 87 ++ .../plugins/codemirror/addon/tern/tern.js | 718 ++++++++++++ .../plugins/codemirror/addon/tern/worker.js | 44 + .../plugins/codemirror/addon/wrap/hardwrap.js | 145 +++ .../vendor/plugins/codemirror/mode/apl/apl.js | 2 +- .../plugins/codemirror/mode/apl/index.html | 2 +- .../codemirror/mode/asciiarmor/asciiarmor.js | 3 +- .../codemirror/mode/asciiarmor/index.html | 4 +- .../plugins/codemirror/mode/asn.1/asn.1.js | 2 +- .../plugins/codemirror/mode/asn.1/index.html | 5 +- .../codemirror/mode/asterisk/asterisk.js | 30 +- .../codemirror/mode/asterisk/index.html | 5 +- .../codemirror/mode/brainfuck/brainfuck.js | 2 +- .../codemirror/mode/brainfuck/index.html | 2 +- .../plugins/codemirror/mode/clike/clike.js | 235 ++-- .../plugins/codemirror/mode/clike/index.html | 34 +- .../plugins/codemirror/mode/clike/scala.html | 2 +- .../plugins/codemirror/mode/clike/test.js | 124 +- .../codemirror/mode/clojure/clojure.js | 534 +++++---- .../codemirror/mode/clojure/index.html | 96 +- .../plugins/codemirror/mode/clojure/test.js | 384 +++++++ .../plugins/codemirror/mode/cmake/cmake.js | 2 +- .../plugins/codemirror/mode/cmake/index.html | 2 +- .../plugins/codemirror/mode/cobol/cobol.js | 2 +- .../plugins/codemirror/mode/cobol/index.html | 2 +- .../mode/coffeescript/coffeescript.js | 6 +- .../codemirror/mode/coffeescript/index.html | 4 +- .../codemirror/mode/commonlisp/commonlisp.js | 5 +- .../codemirror/mode/commonlisp/index.html | 2 +- .../codemirror/mode/crystal/crystal.js | 90 +- .../codemirror/mode/crystal/index.html | 19 +- .../vendor/plugins/codemirror/mode/css/css.js | 76 +- .../plugins/codemirror/mode/css/gss.html | 5 +- .../plugins/codemirror/mode/css/gss_test.js | 2 +- .../plugins/codemirror/mode/css/index.html | 4 +- .../plugins/codemirror/mode/css/less.html | 6 +- .../plugins/codemirror/mode/css/less_test.js | 10 +- .../plugins/codemirror/mode/css/scss.html | 3 +- .../plugins/codemirror/mode/css/scss_test.js | 12 +- .../plugins/codemirror/mode/css/test.js | 59 +- .../plugins/codemirror/mode/cypher/cypher.js | 12 +- .../plugins/codemirror/mode/cypher/index.html | 5 +- .../plugins/codemirror/mode/cypher/test.js | 37 + public/vendor/plugins/codemirror/mode/d/d.js | 11 +- .../plugins/codemirror/mode/d/index.html | 2 +- .../vendor/plugins/codemirror/mode/d/test.js | 11 + .../plugins/codemirror/mode/dart/dart.js | 15 +- .../plugins/codemirror/mode/dart/index.html | 2 +- .../plugins/codemirror/mode/diff/diff.js | 2 +- .../plugins/codemirror/mode/diff/index.html | 2 +- .../plugins/codemirror/mode/django/django.js | 2 +- .../plugins/codemirror/mode/django/index.html | 4 +- .../codemirror/mode/dockerfile/dockerfile.js | 170 ++- .../codemirror/mode/dockerfile/index.html | 4 +- .../codemirror/mode/dockerfile/test.js | 128 +++ .../vendor/plugins/codemirror/mode/dtd/dtd.js | 2 +- .../plugins/codemirror/mode/dtd/index.html | 4 +- .../plugins/codemirror/mode/dylan/dylan.js | 20 +- .../plugins/codemirror/mode/dylan/index.html | 4 +- .../plugins/codemirror/mode/dylan/test.js | 2 +- .../plugins/codemirror/mode/ebnf/ebnf.js | 2 +- .../plugins/codemirror/mode/ebnf/index.html | 4 +- .../vendor/plugins/codemirror/mode/ecl/ecl.js | 2 +- .../plugins/codemirror/mode/ecl/index.html | 2 +- .../plugins/codemirror/mode/eiffel/eiffel.js | 2 +- .../plugins/codemirror/mode/eiffel/index.html | 2 +- .../vendor/plugins/codemirror/mode/elm/elm.js | 4 +- .../plugins/codemirror/mode/elm/index.html | 4 +- .../plugins/codemirror/mode/erlang/erlang.js | 7 +- .../plugins/codemirror/mode/erlang/index.html | 4 +- .../plugins/codemirror/mode/factor/factor.js | 52 +- .../plugins/codemirror/mode/factor/index.html | 2 +- .../vendor/plugins/codemirror/mode/fcl/fcl.js | 2 +- .../plugins/codemirror/mode/fcl/index.html | 2 +- .../plugins/codemirror/mode/forth/forth.js | 2 +- .../plugins/codemirror/mode/forth/index.html | 2 +- .../codemirror/mode/fortran/fortran.js | 2 +- .../codemirror/mode/fortran/index.html | 4 +- .../vendor/plugins/codemirror/mode/gas/gas.js | 2 +- .../plugins/codemirror/mode/gas/index.html | 2 +- .../vendor/plugins/codemirror/mode/gfm/gfm.js | 9 +- .../plugins/codemirror/mode/gfm/index.html | 51 +- .../plugins/codemirror/mode/gfm/test.js | 94 +- .../codemirror/mode/gherkin/gherkin.js | 2 +- .../codemirror/mode/gherkin/index.html | 2 +- .../vendor/plugins/codemirror/mode/go/go.js | 12 +- .../plugins/codemirror/mode/go/index.html | 2 +- .../plugins/codemirror/mode/groovy/groovy.js | 13 +- .../plugins/codemirror/mode/groovy/index.html | 2 +- .../plugins/codemirror/mode/haml/haml.js | 2 +- .../plugins/codemirror/mode/haml/index.html | 2 +- .../plugins/codemirror/mode/haml/test.js | 2 +- .../codemirror/mode/handlebars/handlebars.js | 12 +- .../codemirror/mode/handlebars/index.html | 5 +- .../mode/haskell-literate/haskell-literate.js | 2 +- .../mode/haskell-literate/index.html | 2 +- .../codemirror/mode/haskell/haskell.js | 21 +- .../codemirror/mode/haskell/index.html | 4 +- .../plugins/codemirror/mode/haxe/haxe.js | 4 +- .../plugins/codemirror/mode/haxe/index.html | 4 +- .../mode/htmlembedded/htmlembedded.js | 11 +- .../codemirror/mode/htmlembedded/index.html | 4 +- .../codemirror/mode/htmlmixed/htmlmixed.js | 14 +- .../codemirror/mode/htmlmixed/index.html | 33 +- .../plugins/codemirror/mode/http/http.js | 2 +- .../plugins/codemirror/mode/http/index.html | 4 +- .../vendor/plugins/codemirror/mode/idl/idl.js | 2 +- .../plugins/codemirror/mode/idl/index.html | 5 +- .../vendor/plugins/codemirror/mode/index.html | 9 +- .../codemirror/mode/javascript/index.html | 4 +- .../codemirror/mode/javascript/javascript.js | 505 ++++++--- .../codemirror/mode/javascript/json-ld.html | 4 +- .../codemirror/mode/javascript/test.js | 310 ++++- .../mode/javascript/typescript.html | 21 +- .../plugins/codemirror/mode/jinja2/index.html | 4 +- .../plugins/codemirror/mode/jinja2/jinja2.js | 10 +- .../plugins/codemirror/mode/jsx/index.html | 6 +- .../vendor/plugins/codemirror/mode/jsx/jsx.js | 9 +- .../plugins/codemirror/mode/jsx/test.js | 24 +- .../plugins/codemirror/mode/julia/index.html | 5 +- .../plugins/codemirror/mode/julia/julia.js | 307 ++--- .../codemirror/mode/livescript/index.html | 2 +- .../codemirror/mode/livescript/livescript.js | 4 +- .../plugins/codemirror/mode/lua/index.html | 4 +- .../vendor/plugins/codemirror/mode/lua/lua.js | 2 +- .../codemirror/mode/markdown/index.html | 94 +- .../codemirror/mode/markdown/markdown.js | 379 ++++--- .../plugins/codemirror/mode/markdown/test.js | 425 ++++++- .../codemirror/mode/mathematica/index.html | 2 +- .../mode/mathematica/mathematica.js | 6 +- .../plugins/codemirror/mode/mbox/index.html | 2 +- .../plugins/codemirror/mode/mbox/mbox.js | 2 +- public/vendor/plugins/codemirror/mode/meta.js | 50 +- .../plugins/codemirror/mode/mirc/index.html | 3 +- .../plugins/codemirror/mode/mirc/mirc.js | 4 +- .../plugins/codemirror/mode/mllike/index.html | 21 +- .../plugins/codemirror/mode/mllike/mllike.js | 246 +++- .../codemirror/mode/modelica/index.html | 2 +- .../codemirror/mode/modelica/modelica.js | 2 +- .../plugins/codemirror/mode/mscgen/index.html | 4 +- .../plugins/codemirror/mode/mscgen/mscgen.js | 16 +- .../codemirror/mode/mscgen/mscgen_test.js | 13 +- .../codemirror/mode/mscgen/msgenny_test.js | 10 +- .../plugins/codemirror/mode/mscgen/xu_test.js | 28 +- .../plugins/codemirror/mode/mumps/index.html | 4 +- .../plugins/codemirror/mode/mumps/mumps.js | 2 +- .../plugins/codemirror/mode/nginx/index.html | 6 +- .../plugins/codemirror/mode/nginx/nginx.js | 2 +- .../plugins/codemirror/mode/nsis/index.html | 2 +- .../plugins/codemirror/mode/nsis/nsis.js | 24 +- .../codemirror/mode/ntriples/index.html | 37 +- .../codemirror/mode/ntriples/ntriples.js | 17 +- .../plugins/codemirror/mode/octave/index.html | 5 +- .../plugins/codemirror/mode/octave/octave.js | 14 +- .../plugins/codemirror/mode/oz/index.html | 6 +- .../vendor/plugins/codemirror/mode/oz/oz.js | 4 +- .../plugins/codemirror/mode/pascal/index.html | 4 +- .../plugins/codemirror/mode/pascal/pascal.js | 20 +- .../plugins/codemirror/mode/pegjs/index.html | 4 +- .../plugins/codemirror/mode/pegjs/pegjs.js | 2 +- .../plugins/codemirror/mode/perl/index.html | 4 +- .../plugins/codemirror/mode/perl/perl.js | 2 +- .../plugins/codemirror/mode/php/index.html | 4 +- .../vendor/plugins/codemirror/mode/php/php.js | 12 +- .../plugins/codemirror/mode/php/test.js | 2 +- .../plugins/codemirror/mode/pig/index.html | 2 +- .../vendor/plugins/codemirror/mode/pig/pig.js | 2 +- .../codemirror/mode/powershell/index.html | 3 +- .../codemirror/mode/powershell/powershell.js | 8 +- .../codemirror/mode/powershell/test.js | 12 +- .../codemirror/mode/properties/index.html | 2 +- .../codemirror/mode/properties/properties.js | 2 +- .../codemirror/mode/protobuf/index.html | 44 +- .../codemirror/mode/protobuf/protobuf.js | 5 +- .../codemirror/mode/{jade => pug}/index.html | 20 +- .../mode/{jade/jade.js => pug/pug.js} | 7 +- .../plugins/codemirror/mode/puppet/index.html | 2 +- .../plugins/codemirror/mode/puppet/puppet.js | 2 +- .../plugins/codemirror/mode/python/index.html | 15 +- .../plugins/codemirror/mode/python/python.js | 155 ++- .../plugins/codemirror/mode/python/test.js | 18 +- .../plugins/codemirror/mode/q/index.html | 4 +- public/vendor/plugins/codemirror/mode/q/q.js | 16 +- .../plugins/codemirror/mode/r/index.html | 67 +- public/vendor/plugins/codemirror/mode/r/r.js | 64 +- .../codemirror/mode/rpm/changes/index.html | 4 +- .../plugins/codemirror/mode/rpm/index.html | 4 +- .../vendor/plugins/codemirror/mode/rpm/rpm.js | 2 +- .../plugins/codemirror/mode/rst/index.html | 4 +- .../vendor/plugins/codemirror/mode/rst/rst.js | 2 +- .../plugins/codemirror/mode/ruby/index.html | 2 +- .../plugins/codemirror/mode/ruby/ruby.js | 67 +- .../plugins/codemirror/mode/ruby/test.js | 11 +- .../plugins/codemirror/mode/rust/index.html | 4 +- .../plugins/codemirror/mode/rust/rust.js | 3 +- .../plugins/codemirror/mode/rust/test.js | 2 +- .../plugins/codemirror/mode/sas/index.html | 4 +- .../vendor/plugins/codemirror/mode/sas/sas.js | 98 +- .../plugins/codemirror/mode/sass/index.html | 6 +- .../plugins/codemirror/mode/sass/sass.js | 98 +- .../plugins/codemirror/mode/sass/test.js | 122 ++ .../plugins/codemirror/mode/scheme/index.html | 2 +- .../plugins/codemirror/mode/scheme/scheme.js | 28 +- .../plugins/codemirror/mode/shell/index.html | 4 +- .../plugins/codemirror/mode/shell/shell.js | 83 +- .../plugins/codemirror/mode/shell/test.js | 17 +- .../plugins/codemirror/mode/sieve/index.html | 2 +- .../plugins/codemirror/mode/sieve/sieve.js | 4 +- .../plugins/codemirror/mode/slim/index.html | 2 +- .../plugins/codemirror/mode/slim/slim.js | 2 +- .../plugins/codemirror/mode/slim/test.js | 2 +- .../codemirror/mode/smalltalk/index.html | 2 +- .../codemirror/mode/smalltalk/smalltalk.js | 2 +- .../plugins/codemirror/mode/smarty/index.html | 4 +- .../plugins/codemirror/mode/smarty/smarty.js | 6 +- .../plugins/codemirror/mode/solr/index.html | 4 +- .../plugins/codemirror/mode/solr/solr.js | 6 +- .../plugins/codemirror/mode/soy/index.html | 4 +- .../vendor/plugins/codemirror/mode/soy/soy.js | 356 +++++- .../plugins/codemirror/mode/soy/test.js | 204 ++++ .../plugins/codemirror/mode/sparql/index.html | 2 +- .../plugins/codemirror/mode/sparql/sparql.js | 4 +- .../codemirror/mode/spreadsheet/index.html | 4 +- .../mode/spreadsheet/spreadsheet.js | 2 +- .../plugins/codemirror/mode/sql/index.html | 13 +- .../vendor/plugins/codemirror/mode/sql/sql.js | 193 +++- .../plugins/codemirror/mode/stex/index.html | 8 +- .../plugins/codemirror/mode/stex/stex.js | 21 +- .../plugins/codemirror/mode/stex/test.js | 11 +- .../plugins/codemirror/mode/stylus/index.html | 2 +- .../plugins/codemirror/mode/stylus/stylus.js | 18 +- .../plugins/codemirror/mode/swift/index.html | 60 +- .../plugins/codemirror/mode/swift/swift.js | 115 +- .../plugins/codemirror/mode/swift/test.js | 162 +++ .../plugins/codemirror/mode/tcl/index.html | 2 +- .../vendor/plugins/codemirror/mode/tcl/tcl.js | 2 +- .../codemirror/mode/textile/index.html | 2 +- .../plugins/codemirror/mode/textile/test.js | 6 +- .../codemirror/mode/textile/textile.js | 4 +- .../codemirror/mode/tiddlywiki/index.html | 4 +- .../codemirror/mode/tiddlywiki/tiddlywiki.js | 4 +- .../plugins/codemirror/mode/tiki/index.html | 6 +- .../plugins/codemirror/mode/tiki/tiki.js | 18 +- .../plugins/codemirror/mode/toml/index.html | 4 +- .../plugins/codemirror/mode/toml/toml.js | 2 +- .../codemirror/mode/tornado/index.html | 4 +- .../codemirror/mode/tornado/tornado.js | 2 +- .../plugins/codemirror/mode/troff/index.html | 2 +- .../plugins/codemirror/mode/troff/troff.js | 2 +- .../codemirror/mode/ttcn-cfg/index.html | 5 +- .../codemirror/mode/ttcn-cfg/ttcn-cfg.js | 2 +- .../plugins/codemirror/mode/ttcn/index.html | 5 +- .../plugins/codemirror/mode/ttcn/ttcn.js | 2 +- .../plugins/codemirror/mode/turtle/index.html | 3 +- .../plugins/codemirror/mode/turtle/turtle.js | 2 +- .../plugins/codemirror/mode/twig/index.html | 4 +- .../plugins/codemirror/mode/twig/twig.js | 4 +- .../plugins/codemirror/mode/vb/index.html | 85 +- .../vendor/plugins/codemirror/mode/vb/vb.js | 17 +- .../codemirror/mode/vbscript/index.html | 4 +- .../codemirror/mode/vbscript/vbscript.js | 2 +- .../codemirror/mode/velocity/index.html | 2 +- .../codemirror/mode/velocity/velocity.js | 4 +- .../codemirror/mode/verilog/index.html | 4 +- .../plugins/codemirror/mode/verilog/test.js | 2 +- .../codemirror/mode/verilog/verilog.js | 410 ++++--- .../plugins/codemirror/mode/vhdl/index.html | 4 +- .../plugins/codemirror/mode/vhdl/vhdl.js | 2 +- .../plugins/codemirror/mode/vue/index.html | 4 +- .../vendor/plugins/codemirror/mode/vue/vue.js | 24 +- .../plugins/codemirror/mode/webidl/index.html | 4 +- .../plugins/codemirror/mode/webidl/webidl.js | 2 +- .../plugins/codemirror/mode/xml/index.html | 4 +- .../plugins/codemirror/mode/xml/test.js | 2 +- .../vendor/plugins/codemirror/mode/xml/xml.js | 23 +- .../plugins/codemirror/mode/xquery/index.html | 5 +- .../plugins/codemirror/mode/xquery/test.js | 12 +- .../plugins/codemirror/mode/xquery/xquery.js | 59 +- .../plugins/codemirror/mode/yacas/index.html | 2 +- .../plugins/codemirror/mode/yacas/yacas.js | 4 +- .../mode/yaml-frontmatter/index.html | 2 +- .../mode/yaml-frontmatter/yaml-frontmatter.js | 2 +- .../plugins/codemirror/mode/yaml/index.html | 2 +- .../plugins/codemirror/mode/yaml/yaml.js | 7 +- .../plugins/codemirror/mode/z80/index.html | 4 +- .../vendor/plugins/codemirror/mode/z80/z80.js | 2 +- 352 files changed, 14596 insertions(+), 2422 deletions(-) create mode 100644 public/vendor/plugins/codemirror/addon/comment/comment.js create mode 100644 public/vendor/plugins/codemirror/addon/comment/continuecomment.js create mode 100644 public/vendor/plugins/codemirror/addon/dialog/dialog.css create mode 100644 public/vendor/plugins/codemirror/addon/dialog/dialog.js create mode 100644 public/vendor/plugins/codemirror/addon/display/autorefresh.js create mode 100644 public/vendor/plugins/codemirror/addon/display/fullscreen.css create mode 100644 public/vendor/plugins/codemirror/addon/display/fullscreen.js create mode 100644 public/vendor/plugins/codemirror/addon/display/panel.js create mode 100644 public/vendor/plugins/codemirror/addon/display/placeholder.js create mode 100644 public/vendor/plugins/codemirror/addon/display/rulers.js create mode 100644 public/vendor/plugins/codemirror/addon/edit/closebrackets.js create mode 100644 public/vendor/plugins/codemirror/addon/edit/closetag.js create mode 100644 public/vendor/plugins/codemirror/addon/edit/continuelist.js create mode 100644 public/vendor/plugins/codemirror/addon/edit/matchbrackets.js create mode 100644 public/vendor/plugins/codemirror/addon/edit/matchtags.js create mode 100644 public/vendor/plugins/codemirror/addon/edit/trailingspace.js create mode 100644 public/vendor/plugins/codemirror/addon/fold/brace-fold.js create mode 100644 public/vendor/plugins/codemirror/addon/fold/comment-fold.js create mode 100644 public/vendor/plugins/codemirror/addon/fold/foldcode.js create mode 100644 public/vendor/plugins/codemirror/addon/fold/foldgutter.css create mode 100644 public/vendor/plugins/codemirror/addon/fold/foldgutter.js create mode 100644 public/vendor/plugins/codemirror/addon/fold/indent-fold.js create mode 100644 public/vendor/plugins/codemirror/addon/fold/markdown-fold.js create mode 100644 public/vendor/plugins/codemirror/addon/fold/xml-fold.js create mode 100644 public/vendor/plugins/codemirror/addon/hint/anyword-hint.js create mode 100644 public/vendor/plugins/codemirror/addon/hint/css-hint.js create mode 100644 public/vendor/plugins/codemirror/addon/hint/html-hint.js create mode 100644 public/vendor/plugins/codemirror/addon/hint/javascript-hint.js create mode 100644 public/vendor/plugins/codemirror/addon/hint/show-hint.css create mode 100644 public/vendor/plugins/codemirror/addon/hint/show-hint.js create mode 100644 public/vendor/plugins/codemirror/addon/hint/sql-hint.js create mode 100644 public/vendor/plugins/codemirror/addon/hint/xml-hint.js create mode 100644 public/vendor/plugins/codemirror/addon/lint/coffeescript-lint.js create mode 100644 public/vendor/plugins/codemirror/addon/lint/css-lint.js create mode 100644 public/vendor/plugins/codemirror/addon/lint/html-lint.js create mode 100644 public/vendor/plugins/codemirror/addon/lint/javascript-lint.js create mode 100644 public/vendor/plugins/codemirror/addon/lint/json-lint.js create mode 100644 public/vendor/plugins/codemirror/addon/lint/lint.css create mode 100644 public/vendor/plugins/codemirror/addon/lint/lint.js create mode 100644 public/vendor/plugins/codemirror/addon/lint/yaml-lint.js create mode 100644 public/vendor/plugins/codemirror/addon/merge/merge.css create mode 100644 public/vendor/plugins/codemirror/addon/merge/merge.js create mode 100644 public/vendor/plugins/codemirror/addon/runmode/colorize.js create mode 100644 public/vendor/plugins/codemirror/addon/runmode/runmode-standalone.js create mode 100644 public/vendor/plugins/codemirror/addon/runmode/runmode.js create mode 100644 public/vendor/plugins/codemirror/addon/runmode/runmode.node.js create mode 100644 public/vendor/plugins/codemirror/addon/scroll/annotatescrollbar.js create mode 100644 public/vendor/plugins/codemirror/addon/scroll/scrollpastend.js create mode 100644 public/vendor/plugins/codemirror/addon/scroll/simplescrollbars.css create mode 100644 public/vendor/plugins/codemirror/addon/scroll/simplescrollbars.js create mode 100644 public/vendor/plugins/codemirror/addon/search/jump-to-line.js create mode 100644 public/vendor/plugins/codemirror/addon/search/match-highlighter.js create mode 100644 public/vendor/plugins/codemirror/addon/search/matchesonscrollbar.css create mode 100644 public/vendor/plugins/codemirror/addon/search/matchesonscrollbar.js create mode 100644 public/vendor/plugins/codemirror/addon/search/search.js create mode 100644 public/vendor/plugins/codemirror/addon/search/searchcursor.js create mode 100644 public/vendor/plugins/codemirror/addon/selection/active-line.js create mode 100644 public/vendor/plugins/codemirror/addon/selection/mark-selection.js create mode 100644 public/vendor/plugins/codemirror/addon/selection/selection-pointer.js create mode 100644 public/vendor/plugins/codemirror/addon/tern/tern.css create mode 100644 public/vendor/plugins/codemirror/addon/tern/tern.js create mode 100644 public/vendor/plugins/codemirror/addon/tern/worker.js create mode 100644 public/vendor/plugins/codemirror/addon/wrap/hardwrap.js create mode 100644 public/vendor/plugins/codemirror/mode/clojure/test.js create mode 100644 public/vendor/plugins/codemirror/mode/cypher/test.js create mode 100644 public/vendor/plugins/codemirror/mode/d/test.js create mode 100644 public/vendor/plugins/codemirror/mode/dockerfile/test.js rename public/vendor/plugins/codemirror/mode/{jade => pug}/index.html (76%) rename public/vendor/plugins/codemirror/mode/{jade/jade.js => pug/pug.js} (98%) create mode 100644 public/vendor/plugins/codemirror/mode/sass/test.js create mode 100644 public/vendor/plugins/codemirror/mode/soy/test.js create mode 100644 public/vendor/plugins/codemirror/mode/swift/test.js diff --git a/public/vendor/VERSIONS b/public/vendor/VERSIONS index 6c5f10424fbe6..8afae309fe795 100644 --- a/public/vendor/VERSIONS +++ b/public/vendor/VERSIONS @@ -42,7 +42,7 @@ File(s): /vendor/plugins/jquery.minicolors/jquery.minicolors.min.js Version: 2.2.3 File(s): /vendor/plugins/codemirror/ -Version: 5.17.0 +Version: 5.49.0 File(s): /vendor/plugins/simplemde/simplemde.min.js Version: 1.10.1 diff --git a/public/vendor/librejs.html b/public/vendor/librejs.html index c17c2f14e86c4..336cdbb7215d7 100644 --- a/public/vendor/librejs.html +++ b/public/vendor/librejs.html @@ -93,12 +93,12 @@
loadmode.js Expatcodemirror-5.17.0.tar.gzcodemirror-5.49.0.tar.gz
meta.js Expatcodemirror-5.17.0.tar.gzcodemirror-5.49.0.tar.gz
simplemde.min.js - + {{ShortSha .ID.String}} {{if .Signature}}
{{if .Verification.Verified}} - + {{if ne .Verification.SigningUser.ID 0}} + + {{else}} + + + + + {{end}} + {{else if .Verification.Warning}} + {{else}} {{end}} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index d8750d8bcce46..5be36d23be94c 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -5140,6 +5140,42 @@ } } }, + "/repos/{owner}/{repo}/signing-key.gpg": { + "get": { + "produces": [ + "text/plain" + ], + "tags": [ + "repository" + ], + "summary": "Get signing-key.gpg for given repository", + "operationId": "repoSigningKey", + "parameters": [ + { + "type": "string", + "description": "owner of the repo", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repo", + "name": "repo", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "GPG armored public key", + "schema": { + "type": "string" + } + } + } + } + }, "/repos/{owner}/{repo}/stargazers": { "get": { "produces": [ @@ -5691,6 +5727,26 @@ } } }, + "/signing-key.gpg": { + "get": { + "produces": [ + "text/plain" + ], + "tags": [ + "miscellaneous" + ], + "summary": "Get default signing-key.gpg", + "operationId": "getSigningKey", + "responses": { + "200": { + "description": "GPG armored public key", + "schema": { + "type": "string" + } + } + } + } + }, "/teams/{id}": { "get": { "produces": [ @@ -9525,6 +9581,9 @@ "type": "string", "x-go-name": "Signature" }, + "signer": { + "$ref": "#/definitions/PayloadUser" + }, "verified": { "type": "boolean", "x-go-name": "Verified" From d4cd4ed4422be222088dd8535a228b906f43fdc2 Mon Sep 17 00:00:00 2001 From: zeripath Date: Wed, 16 Oct 2019 16:43:44 +0100 Subject: [PATCH 114/173] Restrict modules/graceful to non-windows build and shim the IsChild marker (#8537) --- modules/graceful/cleanup.go | 2 ++ modules/graceful/graceful_windows.go | 11 +++++++++++ modules/graceful/net.go | 2 ++ modules/graceful/restart.go | 2 ++ modules/graceful/server.go | 2 ++ modules/graceful/server_hooks.go | 2 ++ modules/graceful/server_http.go | 2 ++ modules/graceful/server_signals.go | 2 ++ 8 files changed, 25 insertions(+) create mode 100644 modules/graceful/graceful_windows.go diff --git a/modules/graceful/cleanup.go b/modules/graceful/cleanup.go index 1de087a999179..84355a9a70a26 100644 --- a/modules/graceful/cleanup.go +++ b/modules/graceful/cleanup.go @@ -1,3 +1,5 @@ +// +build !windows + // Copyright 2019 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. diff --git a/modules/graceful/graceful_windows.go b/modules/graceful/graceful_windows.go new file mode 100644 index 0000000000000..753db87133a50 --- /dev/null +++ b/modules/graceful/graceful_windows.go @@ -0,0 +1,11 @@ +// +build windows + +// Copyright 2019 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. +// This code is heavily inspired by the archived gofacebook/gracenet/net.go handler + +package graceful + +// This file contains shims for windows builds +const IsChild = false diff --git a/modules/graceful/net.go b/modules/graceful/net.go index f2612e21bef98..af484641c6e58 100644 --- a/modules/graceful/net.go +++ b/modules/graceful/net.go @@ -1,3 +1,5 @@ +// +build !windows + // Copyright 2019 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. diff --git a/modules/graceful/restart.go b/modules/graceful/restart.go index 33b3c4d417b4a..5cba0581a56c7 100644 --- a/modules/graceful/restart.go +++ b/modules/graceful/restart.go @@ -1,3 +1,5 @@ +// +build !windows + // Copyright 2019 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. diff --git a/modules/graceful/server.go b/modules/graceful/server.go index efe8b264b313d..abe1b3d6d0887 100644 --- a/modules/graceful/server.go +++ b/modules/graceful/server.go @@ -1,3 +1,5 @@ +// +build !windows + // Copyright 2019 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. diff --git a/modules/graceful/server_hooks.go b/modules/graceful/server_hooks.go index a80d955556489..b8ca20ddf509f 100644 --- a/modules/graceful/server_hooks.go +++ b/modules/graceful/server_hooks.go @@ -1,3 +1,5 @@ +// +build !windows + // Copyright 2019 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. diff --git a/modules/graceful/server_http.go b/modules/graceful/server_http.go index 1052637d5e74a..446f0f55519f8 100644 --- a/modules/graceful/server_http.go +++ b/modules/graceful/server_http.go @@ -1,3 +1,5 @@ +// +build !windows + // Copyright 2019 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. diff --git a/modules/graceful/server_signals.go b/modules/graceful/server_signals.go index ea76b5509c739..d0013b77af052 100644 --- a/modules/graceful/server_signals.go +++ b/modules/graceful/server_signals.go @@ -1,3 +1,5 @@ +// +build !windows + // Copyright 2019 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. From de4f10be86b207b087ba9781c628fe3d7b059f7b Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 16 Oct 2019 21:28:41 +0200 Subject: [PATCH 115/173] Allow committing / adding empty files using the web ui (#8420) (#8532) * Allow committing / adding empty files from the web ui (#8420) Signed-off-by: LukBukkit * Add a modal to confirm the commit of an empty file Signed-off-by: LukBukkit --- modules/auth/repo_form.go | 2 +- options/locale/locale_en-US.ini | 2 ++ public/js/index.js | 14 +++++++++++++- templates/repo/editor/edit.tmpl | 25 +++++++++++++++++++++++-- 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/modules/auth/repo_form.go b/modules/auth/repo_form.go index 8d10fc1570d3d..5a8ac5934f6d3 100644 --- a/modules/auth/repo_form.go +++ b/modules/auth/repo_form.go @@ -557,7 +557,7 @@ func (f *NewWikiForm) Validate(ctx *macaron.Context, errs binding.Errors) bindin // EditRepoFileForm form for changing repository file type EditRepoFileForm struct { TreePath string `binding:"Required;MaxSize(500)"` - Content string `binding:"Required"` + Content string CommitSummary string `binding:"MaxSize(100)"` CommitMessage string CommitChoice string `binding:"Required;MaxSize(50)"` diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 4d73d91aa26d9..4923f2f88400d 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -726,6 +726,8 @@ editor.file_editing_no_longer_exists = The file being edited, '%s', no longer ex editor.file_deleting_no_longer_exists = The file being deleted, '%s', no longer exists in this repository. editor.file_changed_while_editing = The file contents have changed since you started editing. Click here to see them or Commit Changes again to overwrite them. editor.file_already_exists = A file named '%s' already exists in this repository. +editor.commit_empty_file_header = Commit an empty file +editor.commit_empty_file_text = The file you're about commit is empty. Proceed? editor.no_changes_to_show = There are no changes to show. editor.fail_to_update_file = Failed to update/create file '%s' with error: %v editor.add_subdir = Add a directory… diff --git a/public/js/index.js b/public/js/index.js index 11b2e75f2dfcc..a903b219e7127 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -262,7 +262,7 @@ function initRepoStatusChecker() { location.reload(); return } - + setTimeout(function () { initRepoStatusChecker() }, 2000); @@ -1571,6 +1571,18 @@ function initEditor() { codeMirrorEditor.setOption("tabSize", editorconfig.tab_width || 4); }); }).trigger('keyup'); + + $('#commit-button').click(function (event) { + // A modal which asks if an empty file should be committed + if ($editArea.val().length === 0) { + $('#edit-empty-content-modal').modal({ + onApprove: function () { + $('.edit.form').submit(); + } + }).modal('show'); + event.preventDefault(); + } + }); } function initOrganization() { diff --git a/templates/repo/editor/edit.tmpl b/templates/repo/editor/edit.tmpl index 134dc818d40bc..d0ba1becc8068 100644 --- a/templates/repo/editor/edit.tmpl +++ b/templates/repo/editor/edit.tmpl @@ -39,8 +39,7 @@ data-url="{{.Repository.APIURL}}/markdown" data-context="{{.RepoLink}}" data-markdown-file-exts="{{.MarkdownFileExts}}" - data-line-wrap-extensions="{{.LineWrapExtensions}}" - required> + data-line-wrap-extensions="{{.LineWrapExtensions}}"> {{.FileContent}}
@@ -53,5 +52,27 @@ {{template "repo/editor/commit_form" .}}
+ + + + {{template "base/footer" .}} From c748deef33df6169c5ec3490a4ccd0b58aad5da0 Mon Sep 17 00:00:00 2001 From: Antoine GIRARD Date: Thu, 17 Oct 2019 02:15:02 +0200 Subject: [PATCH 116/173] don't ignore error message (#8550) --- routers/api/v1/repo/file.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go index f213737d54505..f1a61bb0be04d 100644 --- a/routers/api/v1/repo/file.go +++ b/routers/api/v1/repo/file.go @@ -136,7 +136,7 @@ func GetEditorconfig(ctx *context.APIContext) { } fileName := ctx.Params("filename") - def, _ := ec.GetDefinitionForFilename(fileName) + def, err := ec.GetDefinitionForFilename(fileName) if def == nil { ctx.NotFound(err) return From c43feedb96bd0ccf238bea59803ea412108b4000 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Thu, 17 Oct 2019 00:17:55 +0000 Subject: [PATCH 117/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_es-ES.ini | 2 ++ options/locale/locale_pt-BR.ini | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index 8d2e9d3ce07fb..9ef6ba13e9d3d 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -725,6 +725,8 @@ editor.file_editing_no_longer_exists=El archivo que está editando, '%s', ya no editor.file_deleting_no_longer_exists=El archivo que se está eliminando, '%s', ya no existe en este repositorio. editor.file_changed_while_editing=Desde que comenzó a editar, el contenido del archivo ha sido cambiado. Clic aquí para ver qué ha cambiado o presione confirmar de nuevo para sobrescribir los cambios. editor.file_already_exists=Ya existe un archivo con nombre '%s' en este repositorio. +editor.commit_empty_file_header=Commit un archivo vacío +editor.commit_empty_file_text=El archivo que estás tratando de commit está vacío. ¿Proceder? editor.no_changes_to_show=No existen cambios para mostrar. editor.fail_to_update_file=Error al actualizar/crear el archivo '%s', error: %v editor.add_subdir=Añadir un directorio… diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 790117ef98f44..9f3419b8c89a7 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -725,6 +725,8 @@ editor.file_editing_no_longer_exists=O arquivo que está sendo editado, '%s', n editor.file_deleting_no_longer_exists=O arquivo a ser excluído, '%s', não existe mais neste repositório. editor.file_changed_while_editing=O conteúdo do arquivo mudou desde que você começou a editar. Clique aqui para ver o que foi editado ou clique em Aplicar commit das alterações novamemente para sobreescrever estas alterações. editor.file_already_exists=Um arquivo com nome '%s' já existe neste repositório. +editor.commit_empty_file_header=Fazer commit de um arquivo vazio +editor.commit_empty_file_text=O arquivo que você está prestes fazer commit está vazio. Continuar? editor.no_changes_to_show=Nenhuma alteração a mostrar. editor.fail_to_update_file=Houve erro ao criar ou atualizar arquivo '%s': %v editor.add_subdir=Adicionar um subdiretório... @@ -1973,12 +1975,15 @@ mark_as_unread=Marcar como não lida mark_all_as_read=Marcar todas como lidas [gpg] +default_key=Assinado com a chave padrão error.extract_sign=Falha ao extrair assinatura error.generate_hash=Falha ao gerar hash de commit error.no_committer_account=Nenhuma conta vinculada ao e-mail do autor do commit error.no_gpg_keys_found=Nenhuma chave conhecida encontrada para esta assinatura no banco de dados error.not_signed_commit=Não é um commit assinado error.failed_retrieval_gpg_keys=Falha em obter qualquer chave anexada à conta do autor do commit +error.probable_bad_signature=AVISO! Embora exista uma chave com este ID no banco de dados, ela não verifica este commit! Este commit é SUSPEITO. +error.probable_bad_default_signature=AVISO! Embora a chave padrão tenha este ID, ela não verifica este commit! Este commit é SUSPEITO. [units] error.no_unit_allowed_repo=Você não tem permissão para acessar nenhuma seção deste repositório. From cf42cb0ae63c733f93b48a868873c8cd5a2b90bb Mon Sep 17 00:00:00 2001 From: Wenxuan Zhao Date: Wed, 16 Oct 2019 19:06:28 -0700 Subject: [PATCH 118/173] Allow externalID to be UUID (#8551) Signed-off-by: Wenxuan Zhao --- models/external_login_user.go | 2 +- models/issue.go | 2 +- models/issue_comment.go | 2 +- models/release.go | 2 +- modules/migrations/update.go | 8 +------- services/externalaccount/user.go | 6 +----- 6 files changed, 6 insertions(+), 16 deletions(-) diff --git a/models/external_login_user.go b/models/external_login_user.go index 59c37321844f5..f6357b8274f13 100644 --- a/models/external_login_user.go +++ b/models/external_login_user.go @@ -168,7 +168,7 @@ func FindExternalUsersByProvider(opts FindExternalUserOptions) ([]ExternalLoginU } // UpdateMigrationsByType updates all migrated repositories' posterid from gitServiceType to replace originalAuthorID to posterID -func UpdateMigrationsByType(tp structs.GitServiceType, externalUserID, userID int64) error { +func UpdateMigrationsByType(tp structs.GitServiceType, externalUserID string, userID int64) error { if err := UpdateIssuesMigrationsByType(tp, externalUserID, userID); err != nil { return err } diff --git a/models/issue.go b/models/issue.go index 6503a0618fb06..c55e96168fdc5 100644 --- a/models/issue.go +++ b/models/issue.go @@ -1936,7 +1936,7 @@ func (issue *Issue) ResolveMentionsByVisibility(ctx DBContext, doer *User, menti } // UpdateIssuesMigrationsByType updates all migrated repositories' issues from gitServiceType to replace originalAuthorID to posterID -func UpdateIssuesMigrationsByType(gitServiceType structs.GitServiceType, originalAuthorID, posterID int64) error { +func UpdateIssuesMigrationsByType(gitServiceType structs.GitServiceType, originalAuthorID string, posterID int64) error { _, err := x.Table("issue"). Where("repo_id IN (SELECT id FROM repository WHERE original_service_type = ?)", gitServiceType). And("original_author_id = ?", originalAuthorID). diff --git a/models/issue_comment.go b/models/issue_comment.go index ccf239d60002e..ffc3c006f5788 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -1046,7 +1046,7 @@ func FetchCodeComments(issue *Issue, currentUser *User) (CodeComments, error) { } // UpdateCommentsMigrationsByType updates comments' migrations information via given git service type and original id and poster id -func UpdateCommentsMigrationsByType(tp structs.GitServiceType, originalAuthorID, posterID int64) error { +func UpdateCommentsMigrationsByType(tp structs.GitServiceType, originalAuthorID string, posterID int64) error { _, err := x.Table("comment"). Where(builder.In("issue_id", builder.Select("issue.id"). diff --git a/models/release.go b/models/release.go index 03685e0a44c79..f43d81d822687 100644 --- a/models/release.go +++ b/models/release.go @@ -369,7 +369,7 @@ func SyncReleasesWithTags(repo *Repository, gitRepo *git.Repository) error { } // UpdateReleasesMigrationsByType updates all migrated repositories' releases from gitServiceType to replace originalAuthorID to posterID -func UpdateReleasesMigrationsByType(gitServiceType structs.GitServiceType, originalAuthorID, posterID int64) error { +func UpdateReleasesMigrationsByType(gitServiceType structs.GitServiceType, originalAuthorID string, posterID int64) error { _, err := x.Table("release"). Where("repo_id IN (SELECT id FROM repository WHERE original_service_type = ?)", gitServiceType). And("original_author_id = ?", originalAuthorID). diff --git a/modules/migrations/update.go b/modules/migrations/update.go index df626ddd955e9..d1465b2baf36c 100644 --- a/modules/migrations/update.go +++ b/modules/migrations/update.go @@ -5,8 +5,6 @@ package migrations import ( - "strconv" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/structs" @@ -40,11 +38,7 @@ func updateMigrationPosterIDByGitService(tp structs.GitServiceType) error { } for _, user := range users { - externalUserID, err := strconv.ParseInt(user.ExternalID, 10, 64) - if err != nil { - log.Warn("Parse externalUser %#v 's userID failed: %v", user, err) - continue - } + externalUserID := user.ExternalID if err := models.UpdateMigrationsByType(tp, externalUserID, user.UserID); err != nil { log.Error("UpdateMigrationsByType type %s external user id %v to local user id %v failed: %v", tp.Name(), user.ExternalID, user.UserID, err) } diff --git a/services/externalaccount/user.go b/services/externalaccount/user.go index 800546f123114..45773fdb127d2 100644 --- a/services/externalaccount/user.go +++ b/services/externalaccount/user.go @@ -5,7 +5,6 @@ package externalaccount import ( - "strconv" "strings" "code.gitea.io/gitea/models" @@ -45,10 +44,7 @@ func LinkAccountToUser(user *models.User, gothUser goth.User) error { return err } - externalID, err := strconv.ParseInt(externalLoginUser.ExternalID, 10, 64) - if err != nil { - return err - } + externalID := externalLoginUser.ExternalID var tp structs.GitServiceType for _, s := range structs.SupportedFullGitService { From ae132632a9847c3d304b3bb7b8481a1d0320ab20 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Thu, 17 Oct 2019 02:10:15 +0000 Subject: [PATCH 119/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_ja-JP.ini | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 0e52fb0a4815e..385d803d93afc 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -725,6 +725,8 @@ editor.file_editing_no_longer_exists=編集中のファイル '%s' が、もう editor.file_deleting_no_longer_exists=削除しようとしたファイル '%s' が、すでにリポジトリ内にありません。 editor.file_changed_while_editing=あなたが編集を開始したあと、ファイルの内容が変更されました。 ここをクリックして何が変更されたか確認するか、もう一度"変更をコミット"をクリックして上書きします。 editor.file_already_exists=ファイル '%s' は、このリポジトリに既に存在します。 +editor.commit_empty_file_header=空ファイルのコミット +editor.commit_empty_file_text=コミットしようとしているファイルは空です。 続行しますか? editor.no_changes_to_show=表示する変更箇所はありません。 editor.fail_to_update_file=ファイル '%s' を作成または変更できませんでした: %v editor.add_subdir=ディレクトリを追加… @@ -1455,6 +1457,8 @@ branch.restore_failed=ブランチ '%s' の復元に失敗しました。 branch.protected_deletion_failed=ブランチ '%s' は保護されています。 削除できません。 branch.restore=ブランチ '%s' の復元 branch.download=ブランチ '%s' をダウンロード +branch.included_desc=このブランチはデフォルトブランチに含まれています +branch.included=Included topic.manage_topics=トピックの管理 topic.done=完了 @@ -1971,12 +1975,15 @@ mark_as_unread=未読にする mark_all_as_read=すべて既読にする [gpg] +default_key=デフォルト鍵で署名 error.extract_sign=署名の抽出に失敗しました error.generate_hash=コミットのハッシュ生成に失敗しました error.no_committer_account=コミッターのメールアドレスに関連付けられたアカウントが存在しません error.no_gpg_keys_found=この署名に対応する既知のキーがデータベースに存在しません error.not_signed_commit=署名されたコミットではありません error.failed_retrieval_gpg_keys=コミッターのアカウントに登録されたキーを取得できませんでした +error.probable_bad_signature=警告! このIDの鍵はデータベースに登録されていますが、その鍵でコミットの検証が通りません! これは疑わしいコミットです。 +error.probable_bad_default_signature=警告! これはデフォルト鍵のIDですが、デフォルト鍵ではコミットの検証が通りません! これは疑わしいコミットです。 [units] error.no_unit_allowed_repo=このリポジトリのどのセクションにもアクセスが許可されていません。 From d151503d3428d61b5b3cb27ddbe849d3a6f288eb Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 17 Oct 2019 17:26:49 +0800 Subject: [PATCH 120/173] Upgrade xorm to v0.8.0 (#8536) --- contrib/pr/checkout.go | 2 +- go.mod | 4 +- go.sum | 18 ++---- integrations/migration-test/migration_test.go | 2 +- models/attachment.go | 2 +- models/commit_status.go | 2 +- models/gpg_key.go | 2 +- models/issue.go | 2 +- models/issue_assignees.go | 2 +- models/issue_comment.go | 2 +- models/issue_label.go | 2 +- models/issue_milestone.go | 2 +- models/issue_reaction.go | 2 +- models/issue_tracked_time.go | 2 +- models/issue_user.go | 2 +- models/issue_xref.go | 2 +- models/lfs_lock.go | 2 +- models/login_source.go | 2 +- models/migrate.go | 2 +- models/migrations/migrations.go | 2 +- models/migrations/v100.go | 2 +- models/migrations/v13.go | 2 +- models/migrations/v14.go | 2 +- models/migrations/v15.go | 2 +- models/migrations/v16.go | 2 +- models/migrations/v17.go | 2 +- models/migrations/v18.go | 2 +- models/migrations/v19.go | 2 +- models/migrations/v20.go | 2 +- models/migrations/v21.go | 2 +- models/migrations/v22.go | 2 +- models/migrations/v23.go | 2 +- models/migrations/v24.go | 2 +- models/migrations/v25.go | 2 +- models/migrations/v26.go | 2 +- models/migrations/v27.go | 2 +- models/migrations/v28.go | 2 +- models/migrations/v29.go | 2 +- models/migrations/v30.go | 2 +- models/migrations/v31.go | 2 +- models/migrations/v32.go | 2 +- models/migrations/v33.go | 2 +- models/migrations/v34.go | 2 +- models/migrations/v35.go | 2 +- models/migrations/v36.go | 2 +- models/migrations/v37.go | 2 +- models/migrations/v38.go | 2 +- models/migrations/v39.go | 2 +- models/migrations/v40.go | 2 +- models/migrations/v41.go | 2 +- models/migrations/v45.go | 2 +- models/migrations/v46.go | 2 +- models/migrations/v47.go | 2 +- models/migrations/v48.go | 2 +- models/migrations/v49.go | 2 +- models/migrations/v50.go | 2 +- models/migrations/v51.go | 2 +- models/migrations/v52.go | 2 +- models/migrations/v53.go | 2 +- models/migrations/v54.go | 2 +- models/migrations/v55.go | 2 +- models/migrations/v56.go | 2 +- models/migrations/v57.go | 2 +- models/migrations/v58.go | 2 +- models/migrations/v59.go | 2 +- models/migrations/v60.go | 2 +- models/migrations/v61.go | 2 +- models/migrations/v62.go | 2 +- models/migrations/v63.go | 2 +- models/migrations/v64.go | 2 +- models/migrations/v65.go | 2 +- models/migrations/v66.go | 2 +- models/migrations/v67.go | 2 +- models/migrations/v68.go | 2 +- models/migrations/v69.go | 2 +- models/migrations/v70.go | 2 +- models/migrations/v71.go | 2 +- models/migrations/v72.go | 2 +- models/migrations/v73.go | 2 +- models/migrations/v74.go | 2 +- models/migrations/v75.go | 2 +- models/migrations/v76.go | 2 +- models/migrations/v77.go | 2 +- models/migrations/v78.go | 2 +- models/migrations/v79.go | 2 +- models/migrations/v80.go | 2 +- models/migrations/v81.go | 2 +- models/migrations/v82.go | 2 +- models/migrations/v83.go | 2 +- models/migrations/v84.go | 2 +- models/migrations/v85.go | 2 +- models/migrations/v86.go | 2 +- models/migrations/v87.go | 2 +- models/migrations/v88.go | 2 +- models/migrations/v89.go | 2 +- models/migrations/v90.go | 2 +- models/migrations/v91.go | 2 +- models/migrations/v92.go | 2 +- models/migrations/v93.go | 2 +- models/migrations/v94.go | 2 +- models/migrations/v95.go | 2 +- models/migrations/v96.go | 2 +- models/migrations/v97.go | 2 +- models/migrations/v98.go | 2 +- models/migrations/v99.go | 2 +- models/models.go | 2 +- models/oauth2_application.go | 2 +- models/org.go | 2 +- models/org_team.go | 2 +- models/pull.go | 2 +- models/repo.go | 2 +- models/repo_activity.go | 2 +- models/repo_mirror.go | 2 +- models/repo_unit.go | 2 +- models/review.go | 2 +- models/ssh_key.go | 2 +- models/unit_tests.go | 2 +- models/user.go | 2 +- modules/auth/oauth2/oauth2.go | 2 +- routers/install.go | 2 +- vendor/github.com/go-xorm/xorm/go.mod | 20 ------- vendor/github.com/lafriks/xormstore/go.mod | 3 +- vendor/github.com/lafriks/xormstore/go.sum | 25 +------- .../github.com/lafriks/xormstore/xormstore.go | 2 +- vendor/modules.txt | 6 +- .../go-xorm => xorm.io}/xorm/.drone.yml | 60 ++----------------- .../go-xorm => xorm.io}/xorm/.gitignore | 0 .../go-xorm => xorm.io}/xorm/CONTRIBUTING.md | 4 +- .../go-xorm => xorm.io}/xorm/LICENSE | 0 .../go-xorm => xorm.io}/xorm/README.md | 14 ++--- .../go-xorm => xorm.io}/xorm/README_CN.md | 14 ++--- .../go-xorm => xorm.io}/xorm/cache_lru.go | 0 .../xorm/cache_memory_store.go | 0 .../go-xorm => xorm.io}/xorm/context_cache.go | 0 .../go-xorm => xorm.io}/xorm/convert.go | 0 .../go-xorm => xorm.io}/xorm/dialect_mssql.go | 0 .../go-xorm => xorm.io}/xorm/dialect_mysql.go | 0 .../xorm/dialect_oracle.go | 0 .../xorm/dialect_postgres.go | 0 .../xorm/dialect_sqlite3.go | 0 .../go-xorm => xorm.io}/xorm/doc.go | 2 +- .../go-xorm => xorm.io}/xorm/engine.go | 0 .../go-xorm => xorm.io}/xorm/engine_cond.go | 0 .../xorm/engine_context.go | 0 .../go-xorm => xorm.io}/xorm/engine_group.go | 0 .../xorm/engine_group_policy.go | 0 .../go-xorm => xorm.io}/xorm/engine_table.go | 0 .../go-xorm => xorm.io}/xorm/error.go | 0 .../go-xorm => xorm.io}/xorm/gen_reserved.sh | 0 vendor/xorm.io/xorm/go.mod | 15 +++++ .../go-xorm => xorm.io}/xorm/go.sum | 37 +++--------- .../go-xorm => xorm.io}/xorm/helpers.go | 0 .../go-xorm => xorm.io}/xorm/helpler_time.go | 0 .../go-xorm => xorm.io}/xorm/interface.go | 0 .../go-xorm => xorm.io}/xorm/json.go | 0 .../go-xorm => xorm.io}/xorm/logger.go | 0 .../go-xorm => xorm.io}/xorm/pg_reserved.txt | 0 .../go-xorm => xorm.io}/xorm/processors.go | 0 .../go-xorm => xorm.io}/xorm/rows.go | 0 .../go-xorm => xorm.io}/xorm/session.go | 0 .../go-xorm => xorm.io}/xorm/session_cols.go | 0 .../go-xorm => xorm.io}/xorm/session_cond.go | 0 .../xorm/session_context.go | 0 .../xorm/session_convert.go | 10 ++++ .../xorm/session_delete.go | 0 .../go-xorm => xorm.io}/xorm/session_exist.go | 0 .../go-xorm => xorm.io}/xorm/session_find.go | 2 +- .../go-xorm => xorm.io}/xorm/session_get.go | 0 .../xorm/session_insert.go | 0 .../xorm/session_iterate.go | 0 .../go-xorm => xorm.io}/xorm/session_query.go | 0 .../go-xorm => xorm.io}/xorm/session_raw.go | 0 .../xorm/session_schema.go | 0 .../go-xorm => xorm.io}/xorm/session_stats.go | 0 .../go-xorm => xorm.io}/xorm/session_tx.go | 0 .../xorm/session_update.go | 0 .../go-xorm => xorm.io}/xorm/statement.go | 8 ++- .../xorm/statement_args.go | 0 .../xorm/statement_columnmap.go | 0 .../xorm/statement_exprparam.go | 0 .../xorm/statement_quote.go | 0 .../go-xorm => xorm.io}/xorm/syslogger.go | 0 .../go-xorm => xorm.io}/xorm/tag.go | 0 .../go-xorm => xorm.io}/xorm/test_mssql.sh | 0 .../xorm/test_mssql_cache.sh | 0 .../go-xorm => xorm.io}/xorm/test_mymysql.sh | 0 .../xorm/test_mymysql_cache.sh | 0 .../go-xorm => xorm.io}/xorm/test_mysql.sh | 0 .../xorm/test_mysql_cache.sh | 0 .../go-xorm => xorm.io}/xorm/test_postgres.sh | 0 .../xorm/test_postgres_cache.sh | 0 .../go-xorm => xorm.io}/xorm/test_sqlite.sh | 0 .../xorm/test_sqlite_cache.sh | 0 .../go-xorm => xorm.io}/xorm/test_tidb.sh | 0 .../go-xorm => xorm.io}/xorm/transaction.go | 0 .../go-xorm => xorm.io}/xorm/types.go | 0 .../go-xorm => xorm.io}/xorm/xorm.go | 2 +- 197 files changed, 191 insertions(+), 291 deletions(-) delete mode 100644 vendor/github.com/go-xorm/xorm/go.mod rename vendor/{github.com/go-xorm => xorm.io}/xorm/.drone.yml (94%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/.gitignore (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/CONTRIBUTING.md (89%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/LICENSE (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/README.md (95%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/README_CN.md (95%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/cache_lru.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/cache_memory_store.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/context_cache.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/convert.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/dialect_mssql.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/dialect_mysql.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/dialect_oracle.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/dialect_postgres.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/dialect_sqlite3.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/doc.go (99%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/engine.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/engine_cond.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/engine_context.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/engine_group.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/engine_group_policy.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/engine_table.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/error.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/gen_reserved.sh (100%) create mode 100644 vendor/xorm.io/xorm/go.mod rename vendor/{github.com/go-xorm => xorm.io}/xorm/go.sum (83%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/helpers.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/helpler_time.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/interface.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/json.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/logger.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/pg_reserved.txt (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/processors.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/rows.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/session.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/session_cols.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/session_cond.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/session_context.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/session_convert.go (98%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/session_delete.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/session_exist.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/session_find.go (99%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/session_get.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/session_insert.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/session_iterate.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/session_query.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/session_raw.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/session_schema.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/session_stats.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/session_tx.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/session_update.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/statement.go (99%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/statement_args.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/statement_columnmap.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/statement_exprparam.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/statement_quote.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/syslogger.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/tag.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/test_mssql.sh (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/test_mssql_cache.sh (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/test_mymysql.sh (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/test_mymysql_cache.sh (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/test_mysql.sh (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/test_mysql_cache.sh (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/test_postgres.sh (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/test_postgres_cache.sh (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/test_sqlite.sh (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/test_sqlite_cache.sh (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/test_tidb.sh (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/transaction.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/types.go (100%) rename vendor/{github.com/go-xorm => xorm.io}/xorm/xorm.go (99%) diff --git a/contrib/pr/checkout.go b/contrib/pr/checkout.go index 490d6760c83d8..9c063572950e8 100644 --- a/contrib/pr/checkout.go +++ b/contrib/pr/checkout.go @@ -27,13 +27,13 @@ import ( "code.gitea.io/gitea/routers" "code.gitea.io/gitea/routers/routes" - "github.com/go-xorm/xorm" context2 "github.com/gorilla/context" "github.com/unknwon/com" "gopkg.in/src-d/go-git.v4" "gopkg.in/src-d/go-git.v4/config" "gopkg.in/src-d/go-git.v4/plumbing" "gopkg.in/testfixtures.v2" + "xorm.io/xorm" ) var codeFilePath = "contrib/pr/checkout.go" diff --git a/go.mod b/go.mod index f3ee20acf4aa8..e1bbd9ac89d73 100644 --- a/go.mod +++ b/go.mod @@ -44,7 +44,6 @@ require ( github.com/go-redis/redis v6.15.2+incompatible github.com/go-sql-driver/mysql v1.4.1 github.com/go-swagger/go-swagger v0.20.1 - github.com/go-xorm/xorm v0.7.9 github.com/gobwas/glob v0.2.3 github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 @@ -60,7 +59,7 @@ require ( github.com/klauspost/compress v0.0.0-20161025140425-8df558b6cb6f github.com/klauspost/cpuid v0.0.0-20160302075316-09cded8978dc // indirect github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6 // indirect - github.com/lafriks/xormstore v1.3.1 + github.com/lafriks/xormstore v1.3.2 github.com/lib/pq v1.2.0 github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 github.com/lunny/levelqueue v0.0.0-20190217115915-02b525a4418e @@ -118,4 +117,5 @@ require ( strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 xorm.io/builder v0.3.6 xorm.io/core v0.7.2 + xorm.io/xorm v0.8.0 ) diff --git a/go.sum b/go.sum index c4317af9e2c6c..2eeaa79810c0f 100644 --- a/go.sum +++ b/go.sum @@ -89,8 +89,6 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/chaseadamsio/goorgeous v0.0.0-20170901132237-098da33fde5f h1:REH9VH5ubNR0skLaOxK7TRJeRbE2dDfvaouQo8FsRcA= github.com/chaseadamsio/goorgeous v0.0.0-20170901132237-098da33fde5f/go.mod h1:6QaC0vFoKWYDth94dHFNgRT2YkT5FHdQp/Yx15aAAi0= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/corbym/gocrest v1.0.3 h1:gwEdq6RkTmq+09CTuM29DfKOCtZ7G7bcyxs3IZ6EVdU= github.com/corbym/gocrest v1.0.3/go.mod h1:maVFL5lbdS2PgfOQgGRWDYTeunSWQeiEgoNdTABShCs= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -241,11 +239,8 @@ github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013 h1:l github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013/go.mod h1:b65mBPzqzZWxOZGxSWrqs4GInLIn+u99Q9q7p+GKni0= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= -github.com/go-xorm/xorm v0.7.9 h1:LZze6n1UvRmM5gpL9/U9Gucwqo6aWlFVlfcHKH10qA0= -github.com/go-xorm/xorm v0.7.9/go.mod h1:XiVxrMMIhFkwSkh96BW7PACl7UhLtx2iJIHMdmjh5sQ= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 h1:deE7ritpK04PgtpyVOS2TYcQEld9qLCD5b5EbVNOuLA= github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561/go.mod h1:YgYOrVn3Nj9Tq0EvjmFbphRytDj7JNRoWSStJZWDJTQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -329,9 +324,6 @@ github.com/issue9/assert v1.3.2 h1:IaTa37u4m1fUuTH9K9ldO5IONKVDXjLiUO1T9vj0OF0= github.com/issue9/assert v1.3.2/go.mod h1:9Ger+iz8X7r1zMYYwEhh++2wMGWcNN2oVI+zIQXxcio= github.com/issue9/identicon v0.0.0-20160320065130-d36b54562f4c h1:A/PDn117UYld5mlxe58EpMguqpkeTMw5/FCo0ZPS/Ko= github.com/issue9/identicon v0.0.0-20160320065130-d36b54562f4c/go.mod h1:5mTb/PQNkqmq2x3IxlQZE0aSnTksJg7fg/oWmJ5SKXQ= -github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= -github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= -github.com/jackc/pgx v3.6.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4= github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d h1:ig/iUfDDg06RVW8OMby+GrmW6K2nPO3AFHlEIdvJSd4= github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= @@ -376,8 +368,8 @@ github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lafriks/xormstore v1.3.1 h1:KpzRUamSV3zmA85Kzw+PZOU9wgMbYsNzuDzLuBMbxpA= -github.com/lafriks/xormstore v1.3.1/go.mod h1:qALRD4Vto2Ic7/A5eplMpu5V62mugtSqFysRwz8FETs= +github.com/lafriks/xormstore v1.3.2 h1:hqi3F8s/B4rz8GuEZZDuHuOxRjeuOpEI/cC7vcnWwH4= +github.com/lafriks/xormstore v1.3.2/go.mod h1:mVNIwIa25QIr8rfR7YlVjrqN/apswHkVdtLCyVYBzXw= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -503,8 +495,6 @@ github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b h1:4kg1wyftSKxLtnPAvcRWakIPpokB9w780/KwrNLnfPA= github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= github.com/shurcooL/sanitized_anchor_name v0.0.0-20160918041101-1dba4b3954bc h1:3wIrJvFb3Pf6B/2mDBnN1G5IfUVev4X5apadQlWOczE= @@ -811,7 +801,7 @@ strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 h1:mUcz5b3 strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY= xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8= xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU= -xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb h1:msX3zG3BPl8Ti+LDzP33/9K7BzO/WqFXk610K1kYKfo= -xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM= xorm.io/core v0.7.2 h1:mEO22A2Z7a3fPaZMk6gKL/jMD80iiyNwRrX5HOv3XLw= xorm.io/core v0.7.2/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM= +xorm.io/xorm v0.8.0 h1:iALxgJrX8O00f8Jk22GbZwPmxJNgssV5Mv4uc2HL9PM= +xorm.io/xorm v0.8.0/go.mod h1:ZkJLEYLoVyg7amJK/5r779bHyzs2AU8f8VMiP6BM7uY= diff --git a/integrations/migration-test/migration_test.go b/integrations/migration-test/migration_test.go index 3b47f0d7fc0d5..8dc366dc3f3e3 100644 --- a/integrations/migration-test/migration_test.go +++ b/integrations/migration-test/migration_test.go @@ -23,8 +23,8 @@ import ( "code.gitea.io/gitea/modules/charset" "code.gitea.io/gitea/modules/setting" - "github.com/go-xorm/xorm" "github.com/stretchr/testify/assert" + "xorm.io/xorm" ) var currentEngine *xorm.Engine diff --git a/models/attachment.go b/models/attachment.go index a9032f1a86ab6..f585bda8cb7b1 100644 --- a/models/attachment.go +++ b/models/attachment.go @@ -14,8 +14,8 @@ import ( api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" - "github.com/go-xorm/xorm" gouuid "github.com/satori/go.uuid" + "xorm.io/xorm" ) // Attachment represent a attachment of issue/comment/release. diff --git a/models/commit_status.go b/models/commit_status.go index 6f6cbc387f11c..4e0f8166f392a 100644 --- a/models/commit_status.go +++ b/models/commit_status.go @@ -16,7 +16,7 @@ import ( api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) // CommitStatusState holds the state of a Status diff --git a/models/gpg_key.go b/models/gpg_key.go index 5cfe67435e416..9b690475bd52a 100644 --- a/models/gpg_key.go +++ b/models/gpg_key.go @@ -20,10 +20,10 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" - "github.com/go-xorm/xorm" "github.com/keybase/go-crypto/openpgp" "github.com/keybase/go-crypto/openpgp/armor" "github.com/keybase/go-crypto/openpgp/packet" + "xorm.io/xorm" ) // GPGKey represents a GPG key. diff --git a/models/issue.go b/models/issue.go index c55e96168fdc5..525152552cff7 100644 --- a/models/issue.go +++ b/models/issue.go @@ -19,9 +19,9 @@ import ( "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" - "github.com/go-xorm/xorm" "github.com/unknwon/com" "xorm.io/builder" + "xorm.io/xorm" ) // Issue represents an issue or pull request of repository. diff --git a/models/issue_assignees.go b/models/issue_assignees.go index 1f504a9950a82..00ee4988605e8 100644 --- a/models/issue_assignees.go +++ b/models/issue_assignees.go @@ -10,7 +10,7 @@ import ( "code.gitea.io/gitea/modules/log" api "code.gitea.io/gitea/modules/structs" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) // IssueAssignees saves all issue assignees diff --git a/models/issue_comment.go b/models/issue_comment.go index ffc3c006f5788..d7128bdbac3d7 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -18,9 +18,9 @@ import ( api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" - "github.com/go-xorm/xorm" "github.com/unknwon/com" "xorm.io/builder" + "xorm.io/xorm" ) // CommentType defines whether a comment is just a simple comment, an action (like close) or a reference. diff --git a/models/issue_label.go b/models/issue_label.go index dab5ba2827c70..2b77c4bc35a11 100644 --- a/models/issue_label.go +++ b/models/issue_label.go @@ -13,8 +13,8 @@ import ( api "code.gitea.io/gitea/modules/structs" - "github.com/go-xorm/xorm" "xorm.io/builder" + "xorm.io/xorm" ) var labelColorPattern = regexp.MustCompile("#([a-fA-F0-9]{6})") diff --git a/models/issue_milestone.go b/models/issue_milestone.go index 1587e5e341c7f..d32cb3c7d1f4a 100644 --- a/models/issue_milestone.go +++ b/models/issue_milestone.go @@ -12,7 +12,7 @@ import ( "code.gitea.io/gitea/modules/timeutil" "xorm.io/builder" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) // Milestone represents a milestone of repository. diff --git a/models/issue_reaction.go b/models/issue_reaction.go index ab644b4b3eaf9..4596d32d06a79 100644 --- a/models/issue_reaction.go +++ b/models/issue_reaction.go @@ -11,8 +11,8 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" - "github.com/go-xorm/xorm" "xorm.io/builder" + "xorm.io/xorm" ) // Reaction represents a reactions on issues and comments. diff --git a/models/issue_tracked_time.go b/models/issue_tracked_time.go index f9313b76537e5..f616836c85e17 100644 --- a/models/issue_tracked_time.go +++ b/models/issue_tracked_time.go @@ -10,8 +10,8 @@ import ( "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" - "github.com/go-xorm/xorm" "xorm.io/builder" + "xorm.io/xorm" ) // TrackedTime represents a time that was spent for a specific issue. diff --git a/models/issue_user.go b/models/issue_user.go index d55a0dc2fb85d..6974a4d3cc1fa 100644 --- a/models/issue_user.go +++ b/models/issue_user.go @@ -7,7 +7,7 @@ package models import ( "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) // IssueUser represents an issue-user relation. diff --git a/models/issue_xref.go b/models/issue_xref.go index 141a7e0e8cc71..4b01022bc5753 100644 --- a/models/issue_xref.go +++ b/models/issue_xref.go @@ -8,8 +8,8 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/references" - "github.com/go-xorm/xorm" "github.com/unknwon/com" + "xorm.io/xorm" ) type crossReference struct { diff --git a/models/lfs_lock.go b/models/lfs_lock.go index 7ea1dc866095b..ba1a4528153b9 100644 --- a/models/lfs_lock.go +++ b/models/lfs_lock.go @@ -14,7 +14,7 @@ import ( "code.gitea.io/gitea/modules/log" api "code.gitea.io/gitea/modules/structs" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) // LFSLock represents a git lfs lock of repository. diff --git a/models/login_source.go b/models/login_source.go index 9381ed034f409..ce03c4154f6d4 100644 --- a/models/login_source.go +++ b/models/login_source.go @@ -21,9 +21,9 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" - "github.com/go-xorm/xorm" "github.com/unknwon/com" "xorm.io/core" + "xorm.io/xorm" ) // LoginType represents an login type. diff --git a/models/migrate.go b/models/migrate.go index 85be3a312c1f8..53838fd65e742 100644 --- a/models/migrate.go +++ b/models/migrate.go @@ -4,7 +4,7 @@ package models -import "github.com/go-xorm/xorm" +import "xorm.io/xorm" // InsertMilestones creates milestones of repository. func InsertMilestones(ms ...*Milestone) (err error) { diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 60a416c6e92ea..ef4f5b823f37d 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -21,10 +21,10 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - "github.com/go-xorm/xorm" gouuid "github.com/satori/go.uuid" "github.com/unknwon/com" ini "gopkg.in/ini.v1" + "xorm.io/xorm" ) const minDBVersion = 4 diff --git a/models/migrations/v100.go b/models/migrations/v100.go index ac3b73e2ad2a9..6a4e98af1f6e9 100644 --- a/models/migrations/v100.go +++ b/models/migrations/v100.go @@ -9,7 +9,7 @@ import ( "strings" "time" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func updateMigrationServiceTypes(x *xorm.Engine) error { diff --git a/models/migrations/v13.go b/models/migrations/v13.go index 8b6b38cadf8e1..3c35b66ab9d61 100644 --- a/models/migrations/v13.go +++ b/models/migrations/v13.go @@ -9,8 +9,8 @@ import ( "fmt" "strings" - "github.com/go-xorm/xorm" "github.com/unknwon/com" + "xorm.io/xorm" ) func ldapUseSSLToSecurityProtocol(x *xorm.Engine) error { diff --git a/models/migrations/v14.go b/models/migrations/v14.go index 392f9fdba6796..675c7459dd5b9 100644 --- a/models/migrations/v14.go +++ b/models/migrations/v14.go @@ -7,7 +7,7 @@ package migrations import ( "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func setCommentUpdatedWithCreated(x *xorm.Engine) (err error) { diff --git a/models/migrations/v15.go b/models/migrations/v15.go index 3492a7190b3cb..8872f1e946c84 100644 --- a/models/migrations/v15.go +++ b/models/migrations/v15.go @@ -7,7 +7,7 @@ package migrations import ( "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func createAllowCreateOrganizationColumn(x *xorm.Engine) error { diff --git a/models/migrations/v16.go b/models/migrations/v16.go index 5b8ec19d32783..a849205b55ebc 100644 --- a/models/migrations/v16.go +++ b/models/migrations/v16.go @@ -10,7 +10,7 @@ import ( "code.gitea.io/gitea/modules/markup" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) // Enumerate all the unit types diff --git a/models/migrations/v17.go b/models/migrations/v17.go index 2986badc97943..2907b009dba33 100644 --- a/models/migrations/v17.go +++ b/models/migrations/v17.go @@ -8,7 +8,7 @@ import ( "fmt" "time" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func setProtectedBranchUpdatedWithCreated(x *xorm.Engine) (err error) { diff --git a/models/migrations/v18.go b/models/migrations/v18.go index 3b3cd23ccfe0d..66a1de3499f37 100644 --- a/models/migrations/v18.go +++ b/models/migrations/v18.go @@ -7,7 +7,7 @@ package migrations import ( "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) // ExternalLoginUser makes the connecting between some existing user and additional external login sources diff --git a/models/migrations/v19.go b/models/migrations/v19.go index 7728f5add6ec9..349d5850aa7bc 100644 --- a/models/migrations/v19.go +++ b/models/migrations/v19.go @@ -13,8 +13,8 @@ import ( "code.gitea.io/gitea/modules/setting" - "github.com/go-xorm/xorm" "github.com/unknwon/com" + "xorm.io/xorm" ) func generateAndMigrateGitHooks(x *xorm.Engine) (err error) { diff --git a/models/migrations/v20.go b/models/migrations/v20.go index ded99e09ce147..0897eada745be 100644 --- a/models/migrations/v20.go +++ b/models/migrations/v20.go @@ -16,7 +16,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func useNewNameAvatars(x *xorm.Engine) error { diff --git a/models/migrations/v21.go b/models/migrations/v21.go index 65cae2ac03f7b..2750725760015 100644 --- a/models/migrations/v21.go +++ b/models/migrations/v21.go @@ -11,8 +11,8 @@ import ( "code.gitea.io/gitea/modules/setting" - "github.com/go-xorm/xorm" "github.com/unknwon/com" + "xorm.io/xorm" ) const ( diff --git a/models/migrations/v22.go b/models/migrations/v22.go index faac74343b5e6..eb37aec17fd16 100644 --- a/models/migrations/v22.go +++ b/models/migrations/v22.go @@ -13,8 +13,8 @@ import ( "code.gitea.io/gitea/modules/setting" - "github.com/go-xorm/xorm" "github.com/unknwon/com" + "xorm.io/xorm" ) func generateAndMigrateWikiGitHooks(x *xorm.Engine) (err error) { diff --git a/models/migrations/v23.go b/models/migrations/v23.go index 4aadf7ef0d950..50dc6cd2c7e67 100644 --- a/models/migrations/v23.go +++ b/models/migrations/v23.go @@ -7,7 +7,7 @@ package migrations import ( "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) // UserOpenID is the list of all OpenID identities of a user. diff --git a/models/migrations/v24.go b/models/migrations/v24.go index 076c710cc33a8..20791d79813da 100644 --- a/models/migrations/v24.go +++ b/models/migrations/v24.go @@ -7,7 +7,7 @@ package migrations import ( "time" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func changeGPGKeysColumns(x *xorm.Engine) error { diff --git a/models/migrations/v25.go b/models/migrations/v25.go index a8d746590a466..da74e27c2863a 100644 --- a/models/migrations/v25.go +++ b/models/migrations/v25.go @@ -7,7 +7,7 @@ package migrations import ( "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addUserOpenIDShow(x *xorm.Engine) error { diff --git a/models/migrations/v26.go b/models/migrations/v26.go index 04277191f5ed9..03ce2ef94b5dc 100644 --- a/models/migrations/v26.go +++ b/models/migrations/v26.go @@ -16,8 +16,8 @@ import ( "code.gitea.io/gitea/modules/setting" - "github.com/go-xorm/xorm" "github.com/unknwon/com" + "xorm.io/xorm" ) func generateAndMigrateGitHookChains(x *xorm.Engine) (err error) { diff --git a/models/migrations/v27.go b/models/migrations/v27.go index 12e5fbcdbfe23..2bba0b7412eee 100644 --- a/models/migrations/v27.go +++ b/models/migrations/v27.go @@ -11,7 +11,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func convertIntervalToDuration(x *xorm.Engine) (err error) { diff --git a/models/migrations/v28.go b/models/migrations/v28.go index a30cbf2afbe4f..587e944ce64e5 100644 --- a/models/migrations/v28.go +++ b/models/migrations/v28.go @@ -14,7 +14,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addRepoSize(x *xorm.Engine) (err error) { diff --git a/models/migrations/v29.go b/models/migrations/v29.go index eadb0f3d87a23..ea70a2dd774c2 100644 --- a/models/migrations/v29.go +++ b/models/migrations/v29.go @@ -7,7 +7,7 @@ package migrations import ( "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) // CommitStatus see models/status.go diff --git a/models/migrations/v30.go b/models/migrations/v30.go index 90047df8b6fac..5acdc5dac7977 100644 --- a/models/migrations/v30.go +++ b/models/migrations/v30.go @@ -7,7 +7,7 @@ package migrations import ( "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addExternalLoginUserPK(x *xorm.Engine) error { diff --git a/models/migrations/v31.go b/models/migrations/v31.go index d6cea4c51b0b5..b3aef0d6659d7 100644 --- a/models/migrations/v31.go +++ b/models/migrations/v31.go @@ -8,8 +8,8 @@ import ( "fmt" "time" - "github.com/go-xorm/xorm" "xorm.io/core" + "xorm.io/xorm" ) func addLoginSourceSyncEnabledColumn(x *xorm.Engine) error { diff --git a/models/migrations/v32.go b/models/migrations/v32.go index d209fc34f65f9..f5c021cccff4a 100644 --- a/models/migrations/v32.go +++ b/models/migrations/v32.go @@ -4,7 +4,7 @@ package migrations -import "github.com/go-xorm/xorm" +import "xorm.io/xorm" func addUnitsToRepoTeam(x *xorm.Engine) error { type Team struct { diff --git a/models/migrations/v33.go b/models/migrations/v33.go index 566951db9622c..625c5f4a53324 100644 --- a/models/migrations/v33.go +++ b/models/migrations/v33.go @@ -10,7 +10,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func removeActionColumns(x *xorm.Engine) error { diff --git a/models/migrations/v34.go b/models/migrations/v34.go index 258da41c04092..26f0f565f7303 100644 --- a/models/migrations/v34.go +++ b/models/migrations/v34.go @@ -5,7 +5,7 @@ package migrations import ( - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) // Team see models/team.go diff --git a/models/migrations/v35.go b/models/migrations/v35.go index 7746663a40a8a..d5059c7998424 100644 --- a/models/migrations/v35.go +++ b/models/migrations/v35.go @@ -7,7 +7,7 @@ package migrations import ( "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addCommentIDToAction(x *xorm.Engine) error { diff --git a/models/migrations/v36.go b/models/migrations/v36.go index 06f76a26d6637..729019925ea26 100644 --- a/models/migrations/v36.go +++ b/models/migrations/v36.go @@ -7,7 +7,7 @@ package migrations import ( "code.gitea.io/gitea/models" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func regenerateGitHooks36(x *xorm.Engine) (err error) { diff --git a/models/migrations/v37.go b/models/migrations/v37.go index 00653a780d4ae..29e1c966f3ede 100644 --- a/models/migrations/v37.go +++ b/models/migrations/v37.go @@ -7,7 +7,7 @@ package migrations import ( "html" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func unescapeUserFullNames(x *xorm.Engine) (err error) { diff --git a/models/migrations/v38.go b/models/migrations/v38.go index 6060b70fe870f..4e4e6628d3484 100644 --- a/models/migrations/v38.go +++ b/models/migrations/v38.go @@ -9,8 +9,8 @@ import ( "code.gitea.io/gitea/models" - "github.com/go-xorm/xorm" "xorm.io/core" + "xorm.io/xorm" ) func removeCommitsUnitType(x *xorm.Engine) (err error) { diff --git a/models/migrations/v39.go b/models/migrations/v39.go index 1312cb33134b5..f3b32ea873d20 100644 --- a/models/migrations/v39.go +++ b/models/migrations/v39.go @@ -11,7 +11,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) // ReleaseV39 describes the added field for Release diff --git a/models/migrations/v40.go b/models/migrations/v40.go index fffe158bf9beb..944377ce9bff9 100644 --- a/models/migrations/v40.go +++ b/models/migrations/v40.go @@ -7,7 +7,7 @@ package migrations import ( "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func fixProtectedBranchCanPushValue(x *xorm.Engine) error { diff --git a/models/migrations/v41.go b/models/migrations/v41.go index 4de3ad4e99575..928bb1cd3fcbf 100644 --- a/models/migrations/v41.go +++ b/models/migrations/v41.go @@ -7,7 +7,7 @@ package migrations import ( "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func removeDuplicateUnitTypes(x *xorm.Engine) error { diff --git a/models/migrations/v45.go b/models/migrations/v45.go index 99baff2c8b30e..eb346d7b3a872 100644 --- a/models/migrations/v45.go +++ b/models/migrations/v45.go @@ -8,7 +8,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func removeIndexColumnFromRepoUnitTable(x *xorm.Engine) (err error) { diff --git a/models/migrations/v46.go b/models/migrations/v46.go index b6dd059c94e2a..3d9c1329d8fb9 100644 --- a/models/migrations/v46.go +++ b/models/migrations/v46.go @@ -5,7 +5,7 @@ package migrations import ( - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func removeOrganizationWatchRepo(x *xorm.Engine) error { diff --git a/models/migrations/v47.go b/models/migrations/v47.go index 7a217e6f018ab..81f92e2f5aa2a 100644 --- a/models/migrations/v47.go +++ b/models/migrations/v47.go @@ -7,7 +7,7 @@ package migrations import ( "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addDeletedBranch(x *xorm.Engine) (err error) { diff --git a/models/migrations/v48.go b/models/migrations/v48.go index 6cea66b5ac9d7..6365feba896f9 100644 --- a/models/migrations/v48.go +++ b/models/migrations/v48.go @@ -7,7 +7,7 @@ package migrations import ( "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addRepoIndexerStatus(x *xorm.Engine) error { diff --git a/models/migrations/v49.go b/models/migrations/v49.go index 9e98de5cf20df..4776125137668 100644 --- a/models/migrations/v49.go +++ b/models/migrations/v49.go @@ -10,7 +10,7 @@ import ( "code.gitea.io/gitea/modules/setting" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addTimetracking(x *xorm.Engine) error { diff --git a/models/migrations/v50.go b/models/migrations/v50.go index 23b1bb526eb16..ddc378b432aea 100644 --- a/models/migrations/v50.go +++ b/models/migrations/v50.go @@ -10,7 +10,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func migrateProtectedBranchStruct(x *xorm.Engine) error { diff --git a/models/migrations/v51.go b/models/migrations/v51.go index 85e903bbe7d5c..8dadcf334905c 100644 --- a/models/migrations/v51.go +++ b/models/migrations/v51.go @@ -8,7 +8,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/log" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addDefaultValueToUserProhibitLogin(x *xorm.Engine) (err error) { diff --git a/models/migrations/v52.go b/models/migrations/v52.go index ab57d27de0bc5..6547698d5be7a 100644 --- a/models/migrations/v52.go +++ b/models/migrations/v52.go @@ -10,7 +10,7 @@ import ( "code.gitea.io/gitea/models" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addLFSLock(x *xorm.Engine) error { diff --git a/models/migrations/v53.go b/models/migrations/v53.go index 7437cace251e5..a3068cdb00066 100644 --- a/models/migrations/v53.go +++ b/models/migrations/v53.go @@ -7,7 +7,7 @@ package migrations import ( "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addReactions(x *xorm.Engine) error { diff --git a/models/migrations/v54.go b/models/migrations/v54.go index 5194624f69b3f..af1e287419a81 100644 --- a/models/migrations/v54.go +++ b/models/migrations/v54.go @@ -9,7 +9,7 @@ import ( "code.gitea.io/gitea/modules/timeutil" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addPullRequestOptions(x *xorm.Engine) error { diff --git a/models/migrations/v55.go b/models/migrations/v55.go index c20c51616e7c6..a259e4f001446 100644 --- a/models/migrations/v55.go +++ b/models/migrations/v55.go @@ -9,7 +9,7 @@ import ( "code.gitea.io/gitea/models" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addModeToDeploKeys(x *xorm.Engine) error { diff --git a/models/migrations/v56.go b/models/migrations/v56.go index 79f8ce0ba5c0f..4e1cafcca2590 100644 --- a/models/migrations/v56.go +++ b/models/migrations/v56.go @@ -5,7 +5,7 @@ package migrations import ( - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func removeIsOwnerColumnFromOrgUser(x *xorm.Engine) (err error) { diff --git a/models/migrations/v57.go b/models/migrations/v57.go index fe4bf6b0ee736..6c0ab6f4960d9 100644 --- a/models/migrations/v57.go +++ b/models/migrations/v57.go @@ -9,7 +9,7 @@ import ( "code.gitea.io/gitea/modules/timeutil" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addIssueClosedTime(x *xorm.Engine) error { diff --git a/models/migrations/v58.go b/models/migrations/v58.go index 6ec24b08c8b4f..0fa3bcfe2d939 100644 --- a/models/migrations/v58.go +++ b/models/migrations/v58.go @@ -7,7 +7,7 @@ package migrations import ( "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addLabelsDescriptions(x *xorm.Engine) error { diff --git a/models/migrations/v59.go b/models/migrations/v59.go index 0a05495e7667d..d442f2569ee09 100644 --- a/models/migrations/v59.go +++ b/models/migrations/v59.go @@ -7,7 +7,7 @@ package migrations import ( "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addProtectedBranchMergeWhitelist(x *xorm.Engine) error { diff --git a/models/migrations/v60.go b/models/migrations/v60.go index 13ec38241a166..6482e8e4a58cf 100644 --- a/models/migrations/v60.go +++ b/models/migrations/v60.go @@ -7,7 +7,7 @@ package migrations import ( "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addFsckEnabledToRepo(x *xorm.Engine) error { diff --git a/models/migrations/v61.go b/models/migrations/v61.go index 8d9b7e2d23398..13affaf068d4c 100644 --- a/models/migrations/v61.go +++ b/models/migrations/v61.go @@ -12,7 +12,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addSizeToAttachment(x *xorm.Engine) error { diff --git a/models/migrations/v62.go b/models/migrations/v62.go index 0c2966854b379..e7f6cf6890385 100644 --- a/models/migrations/v62.go +++ b/models/migrations/v62.go @@ -7,7 +7,7 @@ package migrations import ( "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addLastUsedPasscodeTOTP(x *xorm.Engine) error { diff --git a/models/migrations/v63.go b/models/migrations/v63.go index 6e7d940edc706..62e8a299f6a9c 100644 --- a/models/migrations/v63.go +++ b/models/migrations/v63.go @@ -7,7 +7,7 @@ package migrations import ( "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addLanguageSetting(x *xorm.Engine) error { diff --git a/models/migrations/v64.go b/models/migrations/v64.go index 00637ca0461b8..623cceddbc507 100644 --- a/models/migrations/v64.go +++ b/models/migrations/v64.go @@ -7,7 +7,7 @@ package migrations import ( "code.gitea.io/gitea/modules/timeutil" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addMultipleAssignees(x *xorm.Engine) error { diff --git a/models/migrations/v65.go b/models/migrations/v65.go index cc199d34e25b3..a87f8bc76c65a 100644 --- a/models/migrations/v65.go +++ b/models/migrations/v65.go @@ -3,7 +3,7 @@ package migrations import ( "code.gitea.io/gitea/modules/timeutil" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addU2FReg(x *xorm.Engine) error { diff --git a/models/migrations/v66.go b/models/migrations/v66.go index 43acfb4ea56f9..8e9df97feac34 100644 --- a/models/migrations/v66.go +++ b/models/migrations/v66.go @@ -7,7 +7,7 @@ package migrations import ( "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addLoginSourceIDToPublicKeyTable(x *xorm.Engine) error { diff --git a/models/migrations/v67.go b/models/migrations/v67.go index 6cf3dd4d19310..dee744e4d36e1 100644 --- a/models/migrations/v67.go +++ b/models/migrations/v67.go @@ -9,7 +9,7 @@ import ( "code.gitea.io/gitea/modules/setting" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func removeStaleWatches(x *xorm.Engine) error { diff --git a/models/migrations/v68.go b/models/migrations/v68.go index d9e80ca80eb4f..41c1f8f71d551 100644 --- a/models/migrations/v68.go +++ b/models/migrations/v68.go @@ -11,7 +11,7 @@ import ( "code.gitea.io/gitea/modules/log" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) var topicPattern = regexp.MustCompile(`^[a-z0-9][a-z0-9-]*$`) diff --git a/models/migrations/v69.go b/models/migrations/v69.go index 9a6e42e712ddf..a08747edff675 100644 --- a/models/migrations/v69.go +++ b/models/migrations/v69.go @@ -7,7 +7,7 @@ package migrations import ( "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func moveTeamUnitsToTeamUnitTable(x *xorm.Engine) error { diff --git a/models/migrations/v70.go b/models/migrations/v70.go index 4ce1d4ee53620..ef8dd85d6d5f7 100644 --- a/models/migrations/v70.go +++ b/models/migrations/v70.go @@ -10,7 +10,7 @@ import ( "code.gitea.io/gitea/modules/setting" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addIssueDependencies(x *xorm.Engine) (err error) { diff --git a/models/migrations/v71.go b/models/migrations/v71.go index 004f0a3f512d5..0b6aff61b2595 100644 --- a/models/migrations/v71.go +++ b/models/migrations/v71.go @@ -11,8 +11,8 @@ import ( "code.gitea.io/gitea/modules/generate" "code.gitea.io/gitea/modules/timeutil" - "github.com/go-xorm/xorm" "golang.org/x/crypto/pbkdf2" + "xorm.io/xorm" ) func addScratchHash(x *xorm.Engine) error { diff --git a/models/migrations/v72.go b/models/migrations/v72.go index c99b46afd2c75..612f58aab5ef5 100644 --- a/models/migrations/v72.go +++ b/models/migrations/v72.go @@ -9,7 +9,7 @@ import ( "code.gitea.io/gitea/modules/timeutil" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addReview(x *xorm.Engine) error { diff --git a/models/migrations/v73.go b/models/migrations/v73.go index 1265b4519ee7c..0c06e2ba5cfd8 100644 --- a/models/migrations/v73.go +++ b/models/migrations/v73.go @@ -5,7 +5,7 @@ package migrations import ( - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addMustChangePassword(x *xorm.Engine) error { diff --git a/models/migrations/v74.go b/models/migrations/v74.go index 66e958c7fa89a..f3b38418b752e 100644 --- a/models/migrations/v74.go +++ b/models/migrations/v74.go @@ -4,7 +4,7 @@ package migrations -import "github.com/go-xorm/xorm" +import "xorm.io/xorm" func addApprovalWhitelistsToProtectedBranches(x *xorm.Engine) error { type ProtectedBranch struct { diff --git a/models/migrations/v75.go b/models/migrations/v75.go index 58d1d34c98634..208153b9b0df7 100644 --- a/models/migrations/v75.go +++ b/models/migrations/v75.go @@ -5,8 +5,8 @@ package migrations import ( - "github.com/go-xorm/xorm" "xorm.io/builder" + "xorm.io/xorm" ) func clearNonusedData(x *xorm.Engine) error { diff --git a/models/migrations/v76.go b/models/migrations/v76.go index e1fd6f100b985..545bff64c5535 100644 --- a/models/migrations/v76.go +++ b/models/migrations/v76.go @@ -9,7 +9,7 @@ import ( "code.gitea.io/gitea/modules/timeutil" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addPullRequestRebaseWithMerge(x *xorm.Engine) error { diff --git a/models/migrations/v77.go b/models/migrations/v77.go index c564d4cf549f0..d62fbe7fb6f09 100644 --- a/models/migrations/v77.go +++ b/models/migrations/v77.go @@ -5,7 +5,7 @@ package migrations import ( - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addUserDefaultTheme(x *xorm.Engine) error { diff --git a/models/migrations/v78.go b/models/migrations/v78.go index 8082996b6fa98..e4274ca60576b 100644 --- a/models/migrations/v78.go +++ b/models/migrations/v78.go @@ -5,7 +5,7 @@ package migrations import ( - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func renameRepoIsBareToIsEmpty(x *xorm.Engine) error { diff --git a/models/migrations/v79.go b/models/migrations/v79.go index e246393957b60..3c3e77b8dbaf7 100644 --- a/models/migrations/v79.go +++ b/models/migrations/v79.go @@ -7,7 +7,7 @@ package migrations import ( "code.gitea.io/gitea/modules/setting" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addCanCloseIssuesViaCommitInAnyBranch(x *xorm.Engine) error { diff --git a/models/migrations/v80.go b/models/migrations/v80.go index d9040da6018ae..3c1b3315cf6f8 100644 --- a/models/migrations/v80.go +++ b/models/migrations/v80.go @@ -4,7 +4,7 @@ package migrations -import "github.com/go-xorm/xorm" +import "xorm.io/xorm" func addIsLockedToIssues(x *xorm.Engine) error { // Issue see models/issue.go diff --git a/models/migrations/v81.go b/models/migrations/v81.go index 48e96508d9cfb..271d479a645b6 100644 --- a/models/migrations/v81.go +++ b/models/migrations/v81.go @@ -7,7 +7,7 @@ package migrations import ( "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func changeU2FCounterType(x *xorm.Engine) error { diff --git a/models/migrations/v82.go b/models/migrations/v82.go index eb73f1834371f..3fb4b6c59e6b8 100644 --- a/models/migrations/v82.go +++ b/models/migrations/v82.go @@ -10,7 +10,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/git" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func fixReleaseSha1OnReleaseTable(x *xorm.Engine) error { diff --git a/models/migrations/v83.go b/models/migrations/v83.go index cdc59292abb49..6707dbdf812bf 100644 --- a/models/migrations/v83.go +++ b/models/migrations/v83.go @@ -7,7 +7,7 @@ package migrations import ( "code.gitea.io/gitea/modules/timeutil" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addUploaderIDForAttachment(x *xorm.Engine) error { diff --git a/models/migrations/v84.go b/models/migrations/v84.go index 4acb94b9ceace..baab29fcd706e 100644 --- a/models/migrations/v84.go +++ b/models/migrations/v84.go @@ -5,7 +5,7 @@ package migrations import ( - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addGPGKeyImport(x *xorm.Engine) error { diff --git a/models/migrations/v85.go b/models/migrations/v85.go index 6066d5ebe9e3d..8c92f10b6ed99 100644 --- a/models/migrations/v85.go +++ b/models/migrations/v85.go @@ -11,7 +11,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/timeutil" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func hashAppToken(x *xorm.Engine) error { diff --git a/models/migrations/v86.go b/models/migrations/v86.go index 492a08c71eb53..39c196ca6a37d 100644 --- a/models/migrations/v86.go +++ b/models/migrations/v86.go @@ -5,7 +5,7 @@ package migrations import ( - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addHTTPMethodToWebhook(x *xorm.Engine) error { diff --git a/models/migrations/v87.go b/models/migrations/v87.go index c8c7011a08a9e..6b5af5be3367d 100644 --- a/models/migrations/v87.go +++ b/models/migrations/v87.go @@ -5,7 +5,7 @@ package migrations import ( - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addAvatarFieldToRepository(x *xorm.Engine) error { diff --git a/models/migrations/v88.go b/models/migrations/v88.go index fef425db0ac91..7318995a8cac8 100644 --- a/models/migrations/v88.go +++ b/models/migrations/v88.go @@ -8,7 +8,7 @@ import ( "crypto/sha1" "fmt" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func hashContext(context string) string { diff --git a/models/migrations/v89.go b/models/migrations/v89.go index 83d0b1a8b9f50..a972b07b6de1f 100644 --- a/models/migrations/v89.go +++ b/models/migrations/v89.go @@ -4,7 +4,7 @@ package migrations -import "github.com/go-xorm/xorm" +import "xorm.io/xorm" func addOriginalMigrationInfo(x *xorm.Engine) error { // Issue see models/issue.go diff --git a/models/migrations/v90.go b/models/migrations/v90.go index 09aceae2f9e4a..72f7534dc879a 100644 --- a/models/migrations/v90.go +++ b/models/migrations/v90.go @@ -4,7 +4,7 @@ package migrations -import "github.com/go-xorm/xorm" +import "xorm.io/xorm" func changeSomeColumnsLengthOfRepo(x *xorm.Engine) error { type Repository struct { diff --git a/models/migrations/v91.go b/models/migrations/v91.go index fea71b5d3b1d9..3c49d9b96ae81 100644 --- a/models/migrations/v91.go +++ b/models/migrations/v91.go @@ -4,7 +4,7 @@ package migrations -import "github.com/go-xorm/xorm" +import "xorm.io/xorm" func addIndexOnRepositoryAndComment(x *xorm.Engine) error { type Repository struct { diff --git a/models/migrations/v92.go b/models/migrations/v92.go index 090332f151f0d..7ad5118176e40 100644 --- a/models/migrations/v92.go +++ b/models/migrations/v92.go @@ -5,8 +5,8 @@ package migrations import ( - "github.com/go-xorm/xorm" "xorm.io/builder" + "xorm.io/xorm" ) func removeLingeringIndexStatus(x *xorm.Engine) error { diff --git a/models/migrations/v93.go b/models/migrations/v93.go index 0b0441cd5df6e..0cb9d6631fcf7 100644 --- a/models/migrations/v93.go +++ b/models/migrations/v93.go @@ -4,7 +4,7 @@ package migrations -import "github.com/go-xorm/xorm" +import "xorm.io/xorm" func addEmailNotificationEnabledToUser(x *xorm.Engine) error { // User see models/user.go diff --git a/models/migrations/v94.go b/models/migrations/v94.go index 5fe8c3fa12d26..8c1e33b647ca1 100644 --- a/models/migrations/v94.go +++ b/models/migrations/v94.go @@ -4,7 +4,7 @@ package migrations -import "github.com/go-xorm/xorm" +import "xorm.io/xorm" func addStatusCheckColumnsForProtectedBranches(x *xorm.Engine) error { type ProtectedBranch struct { diff --git a/models/migrations/v95.go b/models/migrations/v95.go index f6e4e41c4886f..94787f75010dd 100644 --- a/models/migrations/v95.go +++ b/models/migrations/v95.go @@ -4,7 +4,7 @@ package migrations -import "github.com/go-xorm/xorm" +import "xorm.io/xorm" func addCrossReferenceColumns(x *xorm.Engine) error { // Comment see models/comment.go diff --git a/models/migrations/v96.go b/models/migrations/v96.go index 34f67534c267c..b8eb201591399 100644 --- a/models/migrations/v96.go +++ b/models/migrations/v96.go @@ -10,7 +10,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/setting" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func deleteOrphanedAttachments(x *xorm.Engine) error { diff --git a/models/migrations/v97.go b/models/migrations/v97.go index fa542f2ccd5fa..8e58886e2e5ac 100644 --- a/models/migrations/v97.go +++ b/models/migrations/v97.go @@ -4,7 +4,7 @@ package migrations -import "github.com/go-xorm/xorm" +import "xorm.io/xorm" func addRepoAdminChangeTeamAccessColumnForUser(x *xorm.Engine) error { type User struct { diff --git a/models/migrations/v98.go b/models/migrations/v98.go index 3b9fdbb1c5982..617e1ec3d7d6d 100644 --- a/models/migrations/v98.go +++ b/models/migrations/v98.go @@ -4,7 +4,7 @@ package migrations -import "github.com/go-xorm/xorm" +import "xorm.io/xorm" func addOriginalAuthorOnMigratedReleases(x *xorm.Engine) error { type Release struct { diff --git a/models/migrations/v99.go b/models/migrations/v99.go index 3eb287af6c960..00b4509721e7f 100644 --- a/models/migrations/v99.go +++ b/models/migrations/v99.go @@ -8,7 +8,7 @@ import ( "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) func addTaskTable(x *xorm.Engine) error { diff --git a/models/models.go b/models/models.go index ea550cb839fed..0454ec6add497 100644 --- a/models/models.go +++ b/models/models.go @@ -14,8 +14,8 @@ import ( // Needed for the MySQL driver _ "github.com/go-sql-driver/mysql" - "github.com/go-xorm/xorm" "xorm.io/core" + "xorm.io/xorm" // Needed for the Postgresql driver _ "github.com/lib/pq" diff --git a/models/oauth2_application.go b/models/oauth2_application.go index 46355a0b3f229..4df207ae16850 100644 --- a/models/oauth2_application.go +++ b/models/oauth2_application.go @@ -16,10 +16,10 @@ import ( "code.gitea.io/gitea/modules/timeutil" "github.com/dgrijalva/jwt-go" - "github.com/go-xorm/xorm" uuid "github.com/satori/go.uuid" "github.com/unknwon/com" "golang.org/x/crypto/bcrypt" + "xorm.io/xorm" ) // OAuth2Application represents an OAuth2 client (RFC 6749) diff --git a/models/org.go b/models/org.go index ca3bce81a1c19..2cc302dac60ea 100644 --- a/models/org.go +++ b/models/org.go @@ -14,9 +14,9 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" - "github.com/go-xorm/xorm" "github.com/unknwon/com" "xorm.io/builder" + "xorm.io/xorm" ) // IsOwnedBy returns true if given user is in the owner team. diff --git a/models/org_team.go b/models/org_team.go index 10d53e3a860e0..a7a179f1044f9 100644 --- a/models/org_team.go +++ b/models/org_team.go @@ -14,8 +14,8 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - "github.com/go-xorm/xorm" "xorm.io/builder" + "xorm.io/xorm" ) const ownerTeamName = "Owners" diff --git a/models/pull.go b/models/pull.go index 962e433fb0759..817ea09ccad60 100644 --- a/models/pull.go +++ b/models/pull.go @@ -25,8 +25,8 @@ import ( "code.gitea.io/gitea/modules/sync" "code.gitea.io/gitea/modules/timeutil" - "github.com/go-xorm/xorm" "github.com/unknwon/com" + "xorm.io/xorm" ) var pullRequestQueue = sync.NewUniqueQueue(setting.Repository.PullRequestQueueLength) diff --git a/models/repo.go b/models/repo.go index 06708d24ab3c7..3b5395ce16409 100644 --- a/models/repo.go +++ b/models/repo.go @@ -37,11 +37,11 @@ import ( "code.gitea.io/gitea/modules/sync" "code.gitea.io/gitea/modules/timeutil" - "github.com/go-xorm/xorm" "github.com/mcuadros/go-version" "github.com/unknwon/com" ini "gopkg.in/ini.v1" "xorm.io/builder" + "xorm.io/xorm" ) var repoWorkingPool = sync.NewExclusivePool() diff --git a/models/repo_activity.go b/models/repo_activity.go index 04612ae1efca0..aa5c2217e03e6 100644 --- a/models/repo_activity.go +++ b/models/repo_activity.go @@ -11,7 +11,7 @@ import ( "code.gitea.io/gitea/modules/git" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) // ActivityAuthorData represents statistical git commit count data diff --git a/models/repo_mirror.go b/models/repo_mirror.go index 4e91ea296a593..aa0ec26808ee8 100644 --- a/models/repo_mirror.go +++ b/models/repo_mirror.go @@ -11,7 +11,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/timeutil" - "github.com/go-xorm/xorm" + "xorm.io/xorm" ) // Mirror represents mirror information of a repository. diff --git a/models/repo_unit.go b/models/repo_unit.go index 2fc1c40fa23e2..a6162a65e516b 100644 --- a/models/repo_unit.go +++ b/models/repo_unit.go @@ -9,9 +9,9 @@ import ( "code.gitea.io/gitea/modules/timeutil" - "github.com/go-xorm/xorm" "github.com/unknwon/com" "xorm.io/core" + "xorm.io/xorm" ) // RepoUnit describes all units of a repository diff --git a/models/review.go b/models/review.go index 454d16ee88065..58660b2e3d061 100644 --- a/models/review.go +++ b/models/review.go @@ -10,9 +10,9 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/timeutil" - "github.com/go-xorm/xorm" "xorm.io/builder" "xorm.io/core" + "xorm.io/xorm" ) // ReviewType defines the sort of feedback a review gives diff --git a/models/ssh_key.go b/models/ssh_key.go index d1132bf0c61a0..69699f24c1d9b 100644 --- a/models/ssh_key.go +++ b/models/ssh_key.go @@ -28,10 +28,10 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" - "github.com/go-xorm/xorm" "github.com/unknwon/com" "golang.org/x/crypto/ssh" "xorm.io/builder" + "xorm.io/xorm" ) const ( diff --git a/models/unit_tests.go b/models/unit_tests.go index b53302dad4bae..eb4da37fe5132 100644 --- a/models/unit_tests.go +++ b/models/unit_tests.go @@ -17,11 +17,11 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/setting" - "github.com/go-xorm/xorm" "github.com/stretchr/testify/assert" "github.com/unknwon/com" "gopkg.in/testfixtures.v2" "xorm.io/core" + "xorm.io/xorm" ) // NonexistentID an ID that will never exist diff --git a/models/user.go b/models/user.go index 030e23c383afb..c393d8dce500c 100644 --- a/models/user.go +++ b/models/user.go @@ -33,7 +33,6 @@ import ( "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" - "github.com/go-xorm/xorm" "github.com/unknwon/com" "golang.org/x/crypto/argon2" "golang.org/x/crypto/bcrypt" @@ -41,6 +40,7 @@ import ( "golang.org/x/crypto/scrypt" "golang.org/x/crypto/ssh" "xorm.io/builder" + "xorm.io/xorm" ) // UserType defines the user type diff --git a/modules/auth/oauth2/oauth2.go b/modules/auth/oauth2/oauth2.go index 242254e600d8b..20dfb15e813e3 100644 --- a/modules/auth/oauth2/oauth2.go +++ b/modules/auth/oauth2/oauth2.go @@ -11,7 +11,6 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - "github.com/go-xorm/xorm" "github.com/lafriks/xormstore" "github.com/markbates/goth" "github.com/markbates/goth/gothic" @@ -26,6 +25,7 @@ import ( "github.com/markbates/goth/providers/openidConnect" "github.com/markbates/goth/providers/twitter" "github.com/satori/go.uuid" + "xorm.io/xorm" ) var ( diff --git a/routers/install.go b/routers/install.go index 8f3d0d5ae6900..53880d2c463b1 100644 --- a/routers/install.go +++ b/routers/install.go @@ -20,9 +20,9 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/user" - "github.com/go-xorm/xorm" "github.com/unknwon/com" "gopkg.in/ini.v1" + "xorm.io/xorm" ) const ( diff --git a/vendor/github.com/go-xorm/xorm/go.mod b/vendor/github.com/go-xorm/xorm/go.mod deleted file mode 100644 index 1ab39831a81e9..0000000000000 --- a/vendor/github.com/go-xorm/xorm/go.mod +++ /dev/null @@ -1,20 +0,0 @@ -module github.com/go-xorm/xorm - -go 1.11 - -require ( - github.com/cockroachdb/apd v1.1.0 // indirect - github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 - github.com/go-sql-driver/mysql v1.4.1 - github.com/gofrs/uuid v3.2.0+incompatible // indirect - github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect - github.com/jackc/pgx v3.6.0+incompatible - github.com/lib/pq v1.0.0 - github.com/mattn/go-sqlite3 v1.10.0 - github.com/pkg/errors v0.8.1 // indirect - github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 // indirect - github.com/stretchr/testify v1.4.0 - github.com/ziutek/mymysql v1.5.4 - xorm.io/builder v0.3.6 - xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb -) diff --git a/vendor/github.com/lafriks/xormstore/go.mod b/vendor/github.com/lafriks/xormstore/go.mod index 1a68ce65136e3..8a7528ee788d0 100644 --- a/vendor/github.com/lafriks/xormstore/go.mod +++ b/vendor/github.com/lafriks/xormstore/go.mod @@ -5,15 +5,14 @@ go 1.11 require ( github.com/denisenkom/go-mssqldb v0.0.0-20190924004331-208c0a498538 github.com/go-sql-driver/mysql v1.4.1 - github.com/go-xorm/xorm v0.7.9 github.com/gorilla/context v1.1.1 github.com/gorilla/securecookie v1.1.1 github.com/gorilla/sessions v1.2.0 - github.com/kr/pretty v0.1.0 // indirect github.com/lib/pq v1.2.0 github.com/mattn/go-sqlite3 v1.11.0 golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad // indirect google.golang.org/appengine v1.6.4 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect xorm.io/core v0.7.2 + xorm.io/xorm v0.8.0 ) diff --git a/vendor/github.com/lafriks/xormstore/go.sum b/vendor/github.com/lafriks/xormstore/go.sum index d3dc6aee6282d..9d0273a87c382 100644 --- a/vendor/github.com/lafriks/xormstore/go.sum +++ b/vendor/github.com/lafriks/xormstore/go.sum @@ -1,6 +1,5 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU= cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= @@ -10,8 +9,6 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -29,9 +26,6 @@ github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= -github.com/go-xorm/xorm v0.7.9 h1:LZze6n1UvRmM5gpL9/U9Gucwqo6aWlFVlfcHKH10qA0= -github.com/go-xorm/xorm v0.7.9/go.mod h1:XiVxrMMIhFkwSkh96BW7PACl7UhLtx2iJIHMdmjh5sQ= -github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= @@ -43,7 +37,6 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -57,9 +50,6 @@ github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYb github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= -github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= -github.com/jackc/pgx v3.6.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -70,11 +60,9 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= @@ -86,8 +74,6 @@ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -98,13 +84,10 @@ github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -113,7 +96,6 @@ github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wK go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad h1:5E5raQxcv+6CZ11RrBYQe5WRbUIWpScjh0kvHZkZIrQ= @@ -149,7 +131,6 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -160,7 +141,6 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.4 h1:WiKh4+/eMB2HaY7QhCfW/R7MuRAoA8QMCSJA6jP5/fo= @@ -172,7 +152,6 @@ google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -186,7 +165,7 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8= xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU= -xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb h1:msX3zG3BPl8Ti+LDzP33/9K7BzO/WqFXk610K1kYKfo= -xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM= xorm.io/core v0.7.2 h1:mEO22A2Z7a3fPaZMk6gKL/jMD80iiyNwRrX5HOv3XLw= xorm.io/core v0.7.2/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM= +xorm.io/xorm v0.8.0 h1:iALxgJrX8O00f8Jk22GbZwPmxJNgssV5Mv4uc2HL9PM= +xorm.io/xorm v0.8.0/go.mod h1:ZkJLEYLoVyg7amJK/5r779bHyzs2AU8f8VMiP6BM7uY= diff --git a/vendor/github.com/lafriks/xormstore/xormstore.go b/vendor/github.com/lafriks/xormstore/xormstore.go index 85be25225e6f6..e095508243cc8 100644 --- a/vendor/github.com/lafriks/xormstore/xormstore.go +++ b/vendor/github.com/lafriks/xormstore/xormstore.go @@ -44,7 +44,7 @@ import ( "github.com/lafriks/xormstore/util" - "github.com/go-xorm/xorm" + "xorm.io/xorm" "github.com/gorilla/context" "github.com/gorilla/securecookie" "github.com/gorilla/sessions" diff --git a/vendor/modules.txt b/vendor/modules.txt index 91f7fce0d9fb5..e24275236a458 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -191,8 +191,6 @@ github.com/go-swagger/go-swagger/cmd/swagger/commands/initcmd github.com/go-swagger/go-swagger/codescan github.com/go-swagger/go-swagger/generator github.com/go-swagger/go-swagger/scan -# github.com/go-xorm/xorm v0.7.9 -github.com/go-xorm/xorm # github.com/gobwas/glob v0.2.3 github.com/gobwas/glob github.com/gobwas/glob/compiler @@ -274,7 +272,7 @@ github.com/klauspost/crc32 github.com/kr/pretty # github.com/kr/text v0.1.0 github.com/kr/text -# github.com/lafriks/xormstore v1.3.1 +# github.com/lafriks/xormstore v1.3.2 github.com/lafriks/xormstore github.com/lafriks/xormstore/util # github.com/lib/pq v1.2.0 @@ -609,3 +607,5 @@ strk.kbt.io/projects/go/libravatar xorm.io/builder # xorm.io/core v0.7.2 xorm.io/core +# xorm.io/xorm v0.8.0 +xorm.io/xorm diff --git a/vendor/github.com/go-xorm/xorm/.drone.yml b/vendor/xorm.io/xorm/.drone.yml similarity index 94% rename from vendor/github.com/go-xorm/xorm/.drone.yml rename to vendor/xorm.io/xorm/.drone.yml index b162d7c8a4ff3..c373975df670e 100644 --- a/vendor/github.com/go-xorm/xorm/.drone.yml +++ b/vendor/xorm.io/xorm/.drone.yml @@ -6,28 +6,11 @@ platform: os: linux arch: amd64 -clone: - disable: true - workspace: base: /go - path: src/github.com/go-xorm/xorm + path: src/gitea.com/xorm/xorm steps: -- name: git - pull: default - image: plugins/git:next - settings: - depth: 50 - tags: true - -- name: init_postgres - pull: default - image: postgres:9.5 - commands: - - "until psql -U postgres -d xorm_test -h pgsql \\\n -c \"SELECT 1;\" >/dev/null 2>&1; do sleep 1; done\n" - - "psql -U postgres -d xorm_test -h pgsql \\\n -c \"create schema xorm;\"\n" - - name: build pull: default image: golang:1.10 @@ -186,28 +169,11 @@ platform: os: linux arch: amd64 -clone: - disable: true - workspace: base: /go - path: src/github.com/go-xorm/xorm + path: src/gitea.com/xorm/xorm steps: -- name: git - pull: default - image: plugins/git:next - settings: - depth: 50 - tags: true - -- name: init_postgres - pull: default - image: postgres:9.5 - commands: - - "until psql -U postgres -d xorm_test -h pgsql \\\n -c \"SELECT 1;\" >/dev/null 2>&1; do sleep 1; done\n" - - "psql -U postgres -d xorm_test -h pgsql \\\n -c \"create schema xorm;\"\n" - - name: build pull: default image: golang:1.11 @@ -406,20 +372,11 @@ platform: os: linux arch: amd64 -clone: - disable: true - workspace: base: /go - path: src/github.com/go-xorm/xorm + path: src/gitea.com/xorm/xorm steps: -- name: git - pull: default - image: plugins/git:next - settings: - depth: 50 - tags: true - name: build pull: default @@ -618,20 +575,11 @@ platform: os: linux arch: amd64 -clone: - disable: true - workspace: base: /go - path: src/github.com/go-xorm/xorm + path: src/gitea.com/xorm/xorm steps: -- name: git - pull: default - image: plugins/git:next - settings: - depth: 50 - tags: true - name: build pull: default diff --git a/vendor/github.com/go-xorm/xorm/.gitignore b/vendor/xorm.io/xorm/.gitignore similarity index 100% rename from vendor/github.com/go-xorm/xorm/.gitignore rename to vendor/xorm.io/xorm/.gitignore diff --git a/vendor/github.com/go-xorm/xorm/CONTRIBUTING.md b/vendor/xorm.io/xorm/CONTRIBUTING.md similarity index 89% rename from vendor/github.com/go-xorm/xorm/CONTRIBUTING.md rename to vendor/xorm.io/xorm/CONTRIBUTING.md index 37f4bc5fa8837..442aa4d3112d9 100644 --- a/vendor/github.com/go-xorm/xorm/CONTRIBUTING.md +++ b/vendor/xorm.io/xorm/CONTRIBUTING.md @@ -32,10 +32,10 @@ proposed functionality. We appreciate any bug reports, but especially ones with self-contained (doesn't depend on code outside of xorm), minimal (can't be simplified further) test cases. It's especially helpful if you can submit a pull -request with just the failing test case(you can find some example test file like [session_get_test.go](https://github.com/go-xorm/xorm/blob/master/session_get_test.go)). +request with just the failing test case(you can find some example test file like [session_get_test.go](https://gitea.com/xorm/xorm/src/branch/master/session_get_test.go)). If you implements a new database interface, you maybe need to add a test_.sh file. -For example, [mysql_test.go](https://github.com/go-xorm/xorm/blob/master/test_mysql.sh) +For example, [mysql_test.go](https://gitea.com/xorm/xorm/src/branch/master/test_mysql.sh) ### New functionality diff --git a/vendor/github.com/go-xorm/xorm/LICENSE b/vendor/xorm.io/xorm/LICENSE similarity index 100% rename from vendor/github.com/go-xorm/xorm/LICENSE rename to vendor/xorm.io/xorm/LICENSE diff --git a/vendor/github.com/go-xorm/xorm/README.md b/vendor/xorm.io/xorm/README.md similarity index 95% rename from vendor/github.com/go-xorm/xorm/README.md rename to vendor/xorm.io/xorm/README.md index 62b40ba3046ac..17a6ed37fffdc 100644 --- a/vendor/github.com/go-xorm/xorm/README.md +++ b/vendor/xorm.io/xorm/README.md @@ -1,11 +1,11 @@ # xorm -[中文](https://github.com/go-xorm/xorm/blob/master/README_CN.md) +[中文](https://gitea.com/xorm/xorm/src/branch/master/README_CN.md) Xorm is a simple and powerful ORM for Go. -[![CircleCI](https://circleci.com/gh/go-xorm/xorm.svg?style=shield)](https://circleci.com/gh/go-xorm/xorm) [![codecov](https://codecov.io/gh/go-xorm/xorm/branch/master/graph/badge.svg)](https://codecov.io/gh/go-xorm/xorm) -[![](https://goreportcard.com/badge/github.com/go-xorm/xorm)](https://goreportcard.com/report/github.com/go-xorm/xorm) +[![Build Status](https://drone.gitea.com/api/badges/xorm/xorm/status.svg)](https://drone.gitea.com/xorm/xorm) [![](http://gocover.io/_badge/xorm.io/xorm)](https://gocover.io/xorm.io/xorm) +[![](https://goreportcard.com/badge/xorm.io/xorm)](https://goreportcard.com/report/xorm.io/xorm) [![Join the chat at https://img.shields.io/discord/323460943201959939.svg](https://img.shields.io/discord/323460943201959939.svg)](https://discord.gg/HuR2CF3) ## Features @@ -56,13 +56,13 @@ Drivers for Go's sql package which currently support database/sql includes: ## Installation - go get github.com/go-xorm/xorm + go get xorm.io/xorm ## Documents * [Manual](http://xorm.io/docs) -* [GoDoc](http://godoc.org/github.com/go-xorm/xorm) +* [GoDoc](http://godoc.org/xorm.io/xorm) ## Quick Start @@ -337,7 +337,7 @@ if _, err := session.Exec("delete from userinfo where username = ?", user2.Usern return nil ``` -* Transation should on one go routine. There is transaction and resue session memory +* Transation should be on one go routine. There is transaction and resue session memory ```Go session := engine.NewSession() @@ -419,7 +419,7 @@ res, err := engine.Transaction(func(session *xorm.Session) (interface{}, error) ## Contributing -If you want to pull request, please see [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md). And we also provide [Xorm on Google Groups](https://groups.google.com/forum/#!forum/xorm) to discuss. +If you want to pull request, please see [CONTRIBUTING](https://gitea.com/xorm/xorm/src/branch/master/CONTRIBUTING.md). And we also provide [Xorm on Google Groups](https://groups.google.com/forum/#!forum/xorm) to discuss. ## Credits diff --git a/vendor/github.com/go-xorm/xorm/README_CN.md b/vendor/xorm.io/xorm/README_CN.md similarity index 95% rename from vendor/github.com/go-xorm/xorm/README_CN.md rename to vendor/xorm.io/xorm/README_CN.md index 0cec6ed5c6f6d..644bdc0b63a33 100644 --- a/vendor/github.com/go-xorm/xorm/README_CN.md +++ b/vendor/xorm.io/xorm/README_CN.md @@ -1,11 +1,11 @@ # xorm -[English](https://github.com/go-xorm/xorm/blob/master/README.md) +[English](https://gitea.com/xorm/xorm/src/branch/master/README.md) xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。 -[![CircleCI](https://circleci.com/gh/go-xorm/xorm.svg?style=shield)](https://circleci.com/gh/go-xorm/xorm) [![codecov](https://codecov.io/gh/go-xorm/xorm/branch/master/graph/badge.svg)](https://codecov.io/gh/go-xorm/xorm) -[![](https://goreportcard.com/badge/github.com/go-xorm/xorm)](https://goreportcard.com/report/github.com/go-xorm/xorm) +[![Build Status](https://drone.gitea.com/api/badges/xorm/builder/status.svg)](https://drone.gitea.com/xorm/builder) [![](http://gocover.io/_badge/xorm.io/xorm)](https://gocover.io/xorm.io/xorm) +[![](https://goreportcard.com/badge/xorm.io/xorm)](https://goreportcard.com/report/xorm.io/xorm) [![Join the chat at https://img.shields.io/discord/323460943201959939.svg](https://img.shields.io/discord/323460943201959939.svg)](https://discord.gg/HuR2CF3) ## 特性 @@ -56,15 +56,13 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作 ## 安装 - go get github.com/go-xorm/xorm + go get xorm.io/xorm ## 文档 * [操作指南](http://xorm.io/docs) -* [GoWalker代码文档](http://gowalker.org/github.com/go-xorm/xorm) - -* [Godoc代码文档](http://godoc.org/github.com/go-xorm/xorm) +* [Godoc代码文档](http://godoc.org/xorm.io/xorm) # 快速开始 @@ -414,7 +412,7 @@ res, err := engine.Transaction(func(session *xorm.Session) (interface{}, error) ## 贡献 -如果您也想为Xorm贡献您的力量,请查看 [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md)。您也可以加入QQ群 技术帮助和讨论。 +如果您也想为Xorm贡献您的力量,请查看 [CONTRIBUTING](https://gitea.com/xorm/xorm/src/branch/master/CONTRIBUTING.md)。您也可以加入QQ群 技术帮助和讨论。 群一:280360085 (已满) 群二:795010183 diff --git a/vendor/github.com/go-xorm/xorm/cache_lru.go b/vendor/xorm.io/xorm/cache_lru.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/cache_lru.go rename to vendor/xorm.io/xorm/cache_lru.go diff --git a/vendor/github.com/go-xorm/xorm/cache_memory_store.go b/vendor/xorm.io/xorm/cache_memory_store.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/cache_memory_store.go rename to vendor/xorm.io/xorm/cache_memory_store.go diff --git a/vendor/github.com/go-xorm/xorm/context_cache.go b/vendor/xorm.io/xorm/context_cache.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/context_cache.go rename to vendor/xorm.io/xorm/context_cache.go diff --git a/vendor/github.com/go-xorm/xorm/convert.go b/vendor/xorm.io/xorm/convert.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/convert.go rename to vendor/xorm.io/xorm/convert.go diff --git a/vendor/github.com/go-xorm/xorm/dialect_mssql.go b/vendor/xorm.io/xorm/dialect_mssql.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/dialect_mssql.go rename to vendor/xorm.io/xorm/dialect_mssql.go diff --git a/vendor/github.com/go-xorm/xorm/dialect_mysql.go b/vendor/xorm.io/xorm/dialect_mysql.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/dialect_mysql.go rename to vendor/xorm.io/xorm/dialect_mysql.go diff --git a/vendor/github.com/go-xorm/xorm/dialect_oracle.go b/vendor/xorm.io/xorm/dialect_oracle.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/dialect_oracle.go rename to vendor/xorm.io/xorm/dialect_oracle.go diff --git a/vendor/github.com/go-xorm/xorm/dialect_postgres.go b/vendor/xorm.io/xorm/dialect_postgres.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/dialect_postgres.go rename to vendor/xorm.io/xorm/dialect_postgres.go diff --git a/vendor/github.com/go-xorm/xorm/dialect_sqlite3.go b/vendor/xorm.io/xorm/dialect_sqlite3.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/dialect_sqlite3.go rename to vendor/xorm.io/xorm/dialect_sqlite3.go diff --git a/vendor/github.com/go-xorm/xorm/doc.go b/vendor/xorm.io/xorm/doc.go similarity index 99% rename from vendor/github.com/go-xorm/xorm/doc.go rename to vendor/xorm.io/xorm/doc.go index a687e69476853..9620bca19faee 100644 --- a/vendor/github.com/go-xorm/xorm/doc.go +++ b/vendor/xorm.io/xorm/doc.go @@ -10,7 +10,7 @@ Installation Make sure you have installed Go 1.6+ and then: - go get github.com/go-xorm/xorm + go get xorm.io/xorm Create Engine diff --git a/vendor/github.com/go-xorm/xorm/engine.go b/vendor/xorm.io/xorm/engine.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/engine.go rename to vendor/xorm.io/xorm/engine.go diff --git a/vendor/github.com/go-xorm/xorm/engine_cond.go b/vendor/xorm.io/xorm/engine_cond.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/engine_cond.go rename to vendor/xorm.io/xorm/engine_cond.go diff --git a/vendor/github.com/go-xorm/xorm/engine_context.go b/vendor/xorm.io/xorm/engine_context.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/engine_context.go rename to vendor/xorm.io/xorm/engine_context.go diff --git a/vendor/github.com/go-xorm/xorm/engine_group.go b/vendor/xorm.io/xorm/engine_group.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/engine_group.go rename to vendor/xorm.io/xorm/engine_group.go diff --git a/vendor/github.com/go-xorm/xorm/engine_group_policy.go b/vendor/xorm.io/xorm/engine_group_policy.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/engine_group_policy.go rename to vendor/xorm.io/xorm/engine_group_policy.go diff --git a/vendor/github.com/go-xorm/xorm/engine_table.go b/vendor/xorm.io/xorm/engine_table.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/engine_table.go rename to vendor/xorm.io/xorm/engine_table.go diff --git a/vendor/github.com/go-xorm/xorm/error.go b/vendor/xorm.io/xorm/error.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/error.go rename to vendor/xorm.io/xorm/error.go diff --git a/vendor/github.com/go-xorm/xorm/gen_reserved.sh b/vendor/xorm.io/xorm/gen_reserved.sh similarity index 100% rename from vendor/github.com/go-xorm/xorm/gen_reserved.sh rename to vendor/xorm.io/xorm/gen_reserved.sh diff --git a/vendor/xorm.io/xorm/go.mod b/vendor/xorm.io/xorm/go.mod new file mode 100644 index 0000000000000..6d8b58f41a29f --- /dev/null +++ b/vendor/xorm.io/xorm/go.mod @@ -0,0 +1,15 @@ +module xorm.io/xorm + +go 1.11 + +require ( + github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 + github.com/go-sql-driver/mysql v1.4.1 + github.com/kr/pretty v0.1.0 // indirect + github.com/lib/pq v1.0.0 + github.com/mattn/go-sqlite3 v1.10.0 + github.com/stretchr/testify v1.4.0 + github.com/ziutek/mymysql v1.5.4 + xorm.io/builder v0.3.6 + xorm.io/core v0.7.2 +) diff --git a/vendor/github.com/go-xorm/xorm/go.sum b/vendor/xorm.io/xorm/go.sum similarity index 83% rename from vendor/github.com/go-xorm/xorm/go.sum rename to vendor/xorm.io/xorm/go.sum index cf637a8e064f3..2102cc5b7af01 100644 --- a/vendor/github.com/go-xorm/xorm/go.sum +++ b/vendor/xorm.io/xorm/go.sum @@ -10,8 +10,6 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -28,15 +26,12 @@ github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= -github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= -github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= @@ -48,15 +43,16 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51 github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= -github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= -github.com/jackc/pgx v3.6.0+incompatible h1:bJeo4JdVbDAW8KB2m8XkFeo8CPipREoG37BwEoKGz+Q= -github.com/jackc/pgx v3.6.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= @@ -69,8 +65,6 @@ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -81,8 +75,6 @@ github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -98,8 +90,6 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -112,34 +102,25 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -164,9 +145,5 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8= xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU= -xorm.io/core v0.7.0 h1:hKxuOKWZNeiFQsSuGet/KV8HZ788hclvAl+7azx3tkM= -xorm.io/core v0.7.0/go.mod h1:TuOJjIVa7e3w/rN8tDcAvuLBMtwzdHPbyOzE6Gk1EUI= -xorm.io/core v0.7.1 h1:I6x6Q6dYb67aDEoYFWr2t8UcKIYjJPyCHS+aXuj5V0Y= -xorm.io/core v0.7.1/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM= -xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb h1:msX3zG3BPl8Ti+LDzP33/9K7BzO/WqFXk610K1kYKfo= -xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM= +xorm.io/core v0.7.2 h1:mEO22A2Z7a3fPaZMk6gKL/jMD80iiyNwRrX5HOv3XLw= +xorm.io/core v0.7.2/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM= diff --git a/vendor/github.com/go-xorm/xorm/helpers.go b/vendor/xorm.io/xorm/helpers.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/helpers.go rename to vendor/xorm.io/xorm/helpers.go diff --git a/vendor/github.com/go-xorm/xorm/helpler_time.go b/vendor/xorm.io/xorm/helpler_time.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/helpler_time.go rename to vendor/xorm.io/xorm/helpler_time.go diff --git a/vendor/github.com/go-xorm/xorm/interface.go b/vendor/xorm.io/xorm/interface.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/interface.go rename to vendor/xorm.io/xorm/interface.go diff --git a/vendor/github.com/go-xorm/xorm/json.go b/vendor/xorm.io/xorm/json.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/json.go rename to vendor/xorm.io/xorm/json.go diff --git a/vendor/github.com/go-xorm/xorm/logger.go b/vendor/xorm.io/xorm/logger.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/logger.go rename to vendor/xorm.io/xorm/logger.go diff --git a/vendor/github.com/go-xorm/xorm/pg_reserved.txt b/vendor/xorm.io/xorm/pg_reserved.txt similarity index 100% rename from vendor/github.com/go-xorm/xorm/pg_reserved.txt rename to vendor/xorm.io/xorm/pg_reserved.txt diff --git a/vendor/github.com/go-xorm/xorm/processors.go b/vendor/xorm.io/xorm/processors.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/processors.go rename to vendor/xorm.io/xorm/processors.go diff --git a/vendor/github.com/go-xorm/xorm/rows.go b/vendor/xorm.io/xorm/rows.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/rows.go rename to vendor/xorm.io/xorm/rows.go diff --git a/vendor/github.com/go-xorm/xorm/session.go b/vendor/xorm.io/xorm/session.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/session.go rename to vendor/xorm.io/xorm/session.go diff --git a/vendor/github.com/go-xorm/xorm/session_cols.go b/vendor/xorm.io/xorm/session_cols.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/session_cols.go rename to vendor/xorm.io/xorm/session_cols.go diff --git a/vendor/github.com/go-xorm/xorm/session_cond.go b/vendor/xorm.io/xorm/session_cond.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/session_cond.go rename to vendor/xorm.io/xorm/session_cond.go diff --git a/vendor/github.com/go-xorm/xorm/session_context.go b/vendor/xorm.io/xorm/session_context.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/session_context.go rename to vendor/xorm.io/xorm/session_context.go diff --git a/vendor/github.com/go-xorm/xorm/session_convert.go b/vendor/xorm.io/xorm/session_convert.go similarity index 98% rename from vendor/github.com/go-xorm/xorm/session_convert.go rename to vendor/xorm.io/xorm/session_convert.go index caff5d2624a62..7f11354d5e490 100644 --- a/vendor/github.com/go-xorm/xorm/session_convert.go +++ b/vendor/xorm.io/xorm/session_convert.go @@ -84,6 +84,10 @@ func (session *Session) byte2Time(col *core.Column, data []byte) (outTime time.T return session.str2Time(col, string(data)) } +var ( + nullFloatType = reflect.TypeOf(sql.NullFloat64{}) +) + // convert a db data([]byte) to a field value func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value, data []byte) error { if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok { @@ -583,6 +587,12 @@ func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Val t := fieldValue.Convert(core.TimeType).Interface().(time.Time) tf := session.engine.formatColTime(col, t) return tf, nil + } else if fieldType.ConvertibleTo(nullFloatType) { + t := fieldValue.Convert(nullFloatType).Interface().(sql.NullFloat64) + if !t.Valid { + return nil, nil + } + return t.Float64, nil } if !col.SQLType.IsJson() { diff --git a/vendor/github.com/go-xorm/xorm/session_delete.go b/vendor/xorm.io/xorm/session_delete.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/session_delete.go rename to vendor/xorm.io/xorm/session_delete.go diff --git a/vendor/github.com/go-xorm/xorm/session_exist.go b/vendor/xorm.io/xorm/session_exist.go similarity index 100% rename from vendor/github.com/go-xorm/xorm/session_exist.go rename to vendor/xorm.io/xorm/session_exist.go diff --git a/vendor/github.com/go-xorm/xorm/session_find.go b/vendor/xorm.io/xorm/session_find.go similarity index 99% rename from vendor/github.com/go-xorm/xorm/session_find.go rename to vendor/xorm.io/xorm/session_find.go index 6b8aa469dbc50..e16ae54c94083 100644 --- a/vendor/github.com/go-xorm/xorm/session_find.go +++ b/vendor/xorm.io/xorm/session_find.go @@ -110,7 +110,7 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{}) } } else { // !oinume! Add "
- - {{if $isImage}} - {{template "repo/diff/image_diff" dict "file" . "root" $}} - {{else}} - {{if $.IsSplitStyle}} - {{$highlightClass := $file.GetHighlightClass}} - {{range $j, $section := $file.Sections}} - {{range $k, $line := $section.Lines}} - - - - - - - - - {{if gt (len $line.Comments) 0}} - - - - +
{{if $line.LeftIdx}}{{end}}{{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 2))}}+{{end}}{{if $line.LeftIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}{{if $line.RightIdx}}{{end}}{{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 3))}}+{{end}}{{if $line.RightIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}
- {{if eq $line.GetCommentSide "previous"}} -
-
- - {{ template "repo/diff/comments" dict "root" $ "comments" $line.Comments}} - + +
+ {{if ne $file.Type 4}} + {{$isImage := false}} + {{if $file.IsDeleted}} + {{$isImage = (call $.IsImageFileInBase $file.Name)}} + {{else}} + {{$isImage = (call $.IsImageFileInHead $file.Name)}} + {{end}} +
+ + + {{if $isImage}} + {{template "repo/diff/image_diff" dict "file" . "root" $}} + {{else}} + {{if $.IsSplitStyle}} + {{$highlightClass := $file.GetHighlightClass}} + {{range $j, $section := $file.Sections}} + {{range $k, $line := $section.Lines}} + + + + + + + + + {{if gt (len $line.Comments) 0}} + + + + - - - + + + - + {{end}} + + + {{end}} {{end}} {{end}} + {{else}} + {{template "repo/diff/section_unified" dict "file" . "root" $}} {{end}} - {{else}} - {{template "repo/diff/section_unified" dict "file" . "root" $}} {{end}} - {{end}} - -
{{if $line.LeftIdx}}{{end}}{{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 2))}}+{{end}}{{if $line.LeftIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}{{if $line.RightIdx}}{{end}}{{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 3))}}+{{end}}{{if $line.RightIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}
+ {{if eq $line.GetCommentSide "previous"}} +
+
+ + {{ template "repo/diff/comments" dict "root" $ "comments" $line.Comments}} + +
+ {{template "repo/diff/comment_form_datahandler" dict "reply" (index $line.Comments 0).ReviewID "hidden" true "root" $ "comment" (index $line.Comments 0)}}
- {{template "repo/diff/comment_form_datahandler" dict "reply" (index $line.Comments 0).ReviewID "hidden" true "root" $ "comment" (index $line.Comments 0)}} - - {{end}} -
- {{if eq $line.GetCommentSide "proposed"}} -
-
- - {{ template "repo/diff/comments" dict "root" $ "comments" $line.Comments}} - + {{end}} +
+ {{if eq $line.GetCommentSide "proposed"}} +
+
+ + {{ template "repo/diff/comments" dict "root" $ "comments" $line.Comments}} + +
+ {{template "repo/diff/comment_form_datahandler" dict "reply" (index $line.Comments 0).ReviewID "hidden" true "root" $ "comment" (index $line.Comments 0)}}
- {{template "repo/diff/comment_form_datahandler" dict "reply" (index $line.Comments 0).ReviewID "hidden" true "root" $ "comment" (index $line.Comments 0)}} - - {{end}} -
-
- {{end}} +
+
+ {{end}} +
-
+ {{end}} +
{{end}} -
- {{end}} - {{if .Diff.IsIncomplete}} -
-

- {{$.i18n.Tr "repo.diff.too_many_files"}} -

-
- {{end}} + {{if .Diff.IsIncomplete}} +
+

+ {{$.i18n.Tr "repo.diff.too_many_files"}} +

+
+ {{end}} - {{if not $.Repository.IsArchived}} -
- {{template "repo/diff/new_comment" dict "root" .}} -
-
-
- -
- -
-
- {{$.i18n.Tr "loading"}} -
-
-
{{.i18n.Tr "repo.issues.cancel"}}
-
{{.i18n.Tr "repo.issues.save"}}
-
-
-
- {{end}} + {{if not $.Repository.IsArchived}} +
+ {{template "repo/diff/new_comment" dict "root" .}} +
+
+
+ +
+ +
+
+ {{$.i18n.Tr "loading"}} +
+
+
{{.i18n.Tr "repo.issues.cancel"}}
+
{{.i18n.Tr "repo.issues.save"}}
+
+
+
+ {{end}} - {{if .IsSplitStyle}} - - {{end}} + + {{end}} +
{{end}} From 0bfe5eb10b1953cb1f85f7a7b6eb5f24724b8021 Mon Sep 17 00:00:00 2001 From: zeripath Date: Mon, 21 Oct 2019 09:21:45 +0100 Subject: [PATCH 146/173] Allow Protected Branches to Whitelist Deploy Keys (#8483) Add an option to protected branches to add writing deploy keys to the whitelist for pushing. Please note this is technically a breaking change: previously if the owner of a repository was on the whitelist then any writing deploy key was effectively on the whitelist. This option will now need to be set if that is desired. Closes #8472 Details: * Allow Protected Branches to Whitelist Deploy Keys * Add migration * Ensure that IsDeployKey is set to false on the http pushes * add not null default false --- cmd/hook.go | 2 ++ cmd/serv.go | 2 ++ models/branches.go | 1 + models/migrations/migrations.go | 2 ++ models/migrations/v103.go | 18 ++++++++++++++++++ models/update.go | 2 ++ modules/auth/repo_form.go | 1 + modules/private/hook.go | 4 +++- options/locale/locale_en-US.ini | 1 + routers/private/hook.go | 8 +++++++- routers/repo/http.go | 1 + routers/repo/setting_protected_branch.go | 1 + templates/repo/settings/protected_branch.tmpl | 7 +++++++ 13 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 models/migrations/v103.go diff --git a/cmd/hook.go b/cmd/hook.go index f5b7962aabd42..f07568dd8b20d 100644 --- a/cmd/hook.go +++ b/cmd/hook.go @@ -66,6 +66,7 @@ func runHookPreReceive(c *cli.Context) error { reponame := os.Getenv(models.EnvRepoName) userID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64) prID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchPRID), 10, 64) + isDeployKey, _ := strconv.ParseBool(os.Getenv(models.EnvIsDeployKey)) buf := bytes.NewBuffer(nil) scanner := bufio.NewScanner(os.Stdin) @@ -98,6 +99,7 @@ func runHookPreReceive(c *cli.Context) error { GitObjectDirectory: os.Getenv(private.GitObjectDirectory), GitQuarantinePath: os.Getenv(private.GitQuarantinePath), ProtectedBranchID: prID, + IsDeployKey: isDeployKey, }) switch statusCode { case http.StatusInternalServerError: diff --git a/cmd/serv.go b/cmd/serv.go index 6533b0371c999..1ac6b21e53c13 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -191,6 +191,8 @@ func runServ(c *cli.Context) error { os.Setenv(models.EnvPusherID, strconv.FormatInt(results.UserID, 10)) os.Setenv(models.ProtectedBranchRepoID, strconv.FormatInt(results.RepoID, 10)) os.Setenv(models.ProtectedBranchPRID, fmt.Sprintf("%d", 0)) + os.Setenv(models.EnvIsDeployKey, fmt.Sprintf("%t", results.IsDeployKey)) + os.Setenv(models.EnvKeyID, fmt.Sprintf("%d", results.KeyID)) //LFS token authentication if verb == lfsAuthenticateVerb { diff --git a/models/branches.go b/models/branches.go index fa8beb866c9b1..c5f227f1e5a1e 100644 --- a/models/branches.go +++ b/models/branches.go @@ -34,6 +34,7 @@ type ProtectedBranch struct { WhitelistUserIDs []int64 `xorm:"JSON TEXT"` WhitelistTeamIDs []int64 `xorm:"JSON TEXT"` EnableMergeWhitelist bool `xorm:"NOT NULL DEFAULT false"` + WhitelistDeployKeys bool `xorm:"NOT NULL DEFAULT false"` MergeWhitelistUserIDs []int64 `xorm:"JSON TEXT"` MergeWhitelistTeamIDs []int64 `xorm:"JSON TEXT"` EnableStatusCheck bool `xorm:"NOT NULL DEFAULT false"` diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 8064eccfc17e2..8b1329ea68a7f 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -260,6 +260,8 @@ var migrations = []Migration{ NewMigration("change length of some external login users columns", changeSomeColumnsLengthOfExternalLoginUser), // v102 -> v103 NewMigration("update migration repositories' service type", dropColumnHeadUserNameOnPullRequest), + // v103 -> v104 + NewMigration("Add WhitelistDeployKeys to protected branch", addWhitelistDeployKeysToBranches), } // Migrate database to current version diff --git a/models/migrations/v103.go b/models/migrations/v103.go new file mode 100644 index 0000000000000..fed025c5cdf07 --- /dev/null +++ b/models/migrations/v103.go @@ -0,0 +1,18 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package migrations + +import ( + "xorm.io/xorm" +) + +func addWhitelistDeployKeysToBranches(x *xorm.Engine) error { + type ProtectedBranch struct { + ID int64 + WhitelistDeployKeys bool `xorm:"NOT NULL DEFAULT false"` + } + + return x.Sync2(new(ProtectedBranch)) +} diff --git a/models/update.go b/models/update.go index c6ea1a845e6cc..5e941c22c465c 100644 --- a/models/update.go +++ b/models/update.go @@ -22,6 +22,8 @@ const ( EnvPusherName = "GITEA_PUSHER_NAME" EnvPusherEmail = "GITEA_PUSHER_EMAIL" EnvPusherID = "GITEA_PUSHER_ID" + EnvKeyID = "GITEA_KEY_ID" + EnvIsDeployKey = "GITEA_IS_DEPLOY_KEY" ) // CommitToPushCommit transforms a git.Commit to PushCommit type. diff --git a/modules/auth/repo_form.go b/modules/auth/repo_form.go index 5a8ac5934f6d3..2280666114d52 100644 --- a/modules/auth/repo_form.go +++ b/modules/auth/repo_form.go @@ -152,6 +152,7 @@ type ProtectBranchForm struct { EnableWhitelist bool WhitelistUsers string WhitelistTeams string + WhitelistDeployKeys bool EnableMergeWhitelist bool MergeWhitelistUsers string MergeWhitelistTeams string diff --git a/modules/private/hook.go b/modules/private/hook.go index 67496b5132aae..cc9703cc77ecf 100644 --- a/modules/private/hook.go +++ b/modules/private/hook.go @@ -31,11 +31,12 @@ type HookOptions struct { GitAlternativeObjectDirectories string GitQuarantinePath string ProtectedBranchID int64 + IsDeployKey bool } // HookPreReceive check whether the provided commits are allowed func HookPreReceive(ownerName, repoName string, opts HookOptions) (int, string) { - reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/pre-receive/%s/%s?old=%s&new=%s&ref=%s&userID=%d&gitObjectDirectory=%s&gitAlternativeObjectDirectories=%s&gitQuarantinePath=%s&prID=%d", + reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/pre-receive/%s/%s?old=%s&new=%s&ref=%s&userID=%d&gitObjectDirectory=%s&gitAlternativeObjectDirectories=%s&gitQuarantinePath=%s&prID=%d&isDeployKey=%t", url.PathEscape(ownerName), url.PathEscape(repoName), url.QueryEscape(opts.OldCommitID), @@ -46,6 +47,7 @@ func HookPreReceive(ownerName, repoName string, opts HookOptions) (int, string) url.QueryEscape(opts.GitAlternativeObjectDirectories), url.QueryEscape(opts.GitQuarantinePath), opts.ProtectedBranchID, + opts.IsDeployKey, ) resp, err := newInternalRequest(reqURL, "GET").Response() diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 7b65de6addea4..eb38a777c82f0 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1334,6 +1334,7 @@ settings.protect_this_branch = Enable Branch Protection settings.protect_this_branch_desc = Prevent deletion and disable any Git pushing to the branch. settings.protect_whitelist_committers = Enable Push Whitelist settings.protect_whitelist_committers_desc = Allow whitelisted users or teams to push to this branch (but not force push). +settings.protect_whitelist_deploy_keys = Whitelist deploy keys with write access to push settings.protect_whitelist_users = Whitelisted users for pushing: settings.protect_whitelist_search_users = Search users… settings.protect_whitelist_teams = Whitelisted teams for pushing: diff --git a/routers/private/hook.go b/routers/private/hook.go index 1f6ab2f673206..074e3aef1919b 100644 --- a/routers/private/hook.go +++ b/routers/private/hook.go @@ -33,6 +33,7 @@ func HookPreReceive(ctx *macaron.Context) { gitAlternativeObjectDirectories := ctx.QueryTrim("gitAlternativeObjectDirectories") gitQuarantinePath := ctx.QueryTrim("gitQuarantinePath") prID := ctx.QueryInt64("prID") + isDeployKey := ctx.QueryBool("isDeployKey") branchName := strings.TrimPrefix(refFullName, git.BranchPrefix) repo, err := models.GetRepositoryByOwnerAndName(ownerName, repoName) @@ -95,7 +96,12 @@ func HookPreReceive(ctx *macaron.Context) { } } - canPush := protectBranch.CanUserPush(userID) + canPush := false + if isDeployKey { + canPush = protectBranch.WhitelistDeployKeys + } else { + canPush = protectBranch.CanUserPush(userID) + } if !canPush && prID > 0 { pr, err := models.GetPullRequestByID(prID) if err != nil { diff --git a/routers/repo/http.go b/routers/repo/http.go index 09dd8205852cf..d41c63ba3560c 100644 --- a/routers/repo/http.go +++ b/routers/repo/http.go @@ -263,6 +263,7 @@ func HTTP(ctx *context.Context) { models.EnvPusherName + "=" + authUser.Name, models.EnvPusherID + fmt.Sprintf("=%d", authUser.ID), models.ProtectedBranchRepoID + fmt.Sprintf("=%d", repo.ID), + models.EnvIsDeployKey + "=false", } if !authUser.KeepEmailPrivate { diff --git a/routers/repo/setting_protected_branch.go b/routers/repo/setting_protected_branch.go index 2a8502e6f4584..bc4d7c3a9e9ee 100644 --- a/routers/repo/setting_protected_branch.go +++ b/routers/repo/setting_protected_branch.go @@ -213,6 +213,7 @@ func SettingsProtectedBranchPost(ctx *context.Context, f auth.ProtectBranchForm) protectBranch.EnableStatusCheck = f.EnableStatusCheck protectBranch.StatusCheckContexts = f.StatusCheckContexts + protectBranch.WhitelistDeployKeys = f.WhitelistDeployKeys protectBranch.RequiredApprovals = f.RequiredApprovals if strings.TrimSpace(f.ApprovalsWhitelistUsers) != "" { diff --git a/templates/repo/settings/protected_branch.tmpl b/templates/repo/settings/protected_branch.tmpl index 067d1d97613ec..a50765c4b4794 100644 --- a/templates/repo/settings/protected_branch.tmpl +++ b/templates/repo/settings/protected_branch.tmpl @@ -59,6 +59,13 @@ {{end}} +
+
+
+ + +
+
From bfdcedfe89323b6ce1f0e3cf90a9816a4b669044 Mon Sep 17 00:00:00 2001 From: yan Date: Mon, 21 Oct 2019 19:02:51 +0800 Subject: [PATCH 147/173] fix emoji panel be removed bug in issue page, when the sub issue summit the duplicate emoji (#8609) --- public/js/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/index.js b/public/js/index.js index a903b219e7127..e9a4bcaac1de1 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -306,7 +306,7 @@ function initReactionSelector(parent) { if (resp && (resp.html || resp.empty)) { const content = $(vm).closest('.content'); let react = content.find('.segment.reactions'); - if (react.length > 0) { + if (!resp.empty && react.length > 0) { react.remove(); } if (!resp.empty) { From 969a540ce2f905d0a417c9707ac3337ba9242ac3 Mon Sep 17 00:00:00 2001 From: David Svantesson Date: Mon, 21 Oct 2019 15:36:09 +0200 Subject: [PATCH 148/173] Add id references on all events to allow linking to it (#8608) --- .../repo/issue/view_content/comments.tmpl | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index e3ea9ba822bc6..5a3d4026c6db5 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -73,7 +73,7 @@
{{else if eq .Type 1}} -
+
@@ -81,7 +81,7 @@ {{.Poster.GetDisplayName}} {{$.i18n.Tr "repo.issues.reopened_at" .EventTag $createdStr | Safe}}
{{else if eq .Type 2}} -
+
@@ -89,7 +89,7 @@ {{.Poster.GetDisplayName}} {{$.i18n.Tr "repo.issues.closed_at" .EventTag $createdStr | Safe}}
{{else if or (eq .Type 3) (eq .Type 5) (eq .Type 6)}} - {{else if eq .Type 4}} -
+ {{else if eq .Type 7}} {{if .Label}} -
+ {{end}} {{else if eq .Type 8}} -
+ {{else if eq .Type 9}} -
+
{{if gt .AssigneeID 0}} {{if .RemovedAssignee}} @@ -181,7 +181,7 @@ {{end}}
{{else if eq .Type 10}} -
+ {{else if eq .Type 11}} -
+ {{else if eq .Type 12}} -
+
@@ -209,7 +209,7 @@ {{.Poster.GetDisplayName}} {{$.i18n.Tr "repo.issues.start_tracking_history" $createdStr | Safe}}
{{else if eq .Type 13}} - {{else if eq .Type 14}} - {{else if eq .Type 15}} -
+
@@ -242,7 +242,7 @@ {{.Poster.GetDisplayName}} {{$.i18n.Tr "repo.issues.cancel_tracking_history" $createdStr | Safe}}
{{else if eq .Type 16}} -
+ {{else if eq .Type 17}} -
+ {{else if eq .Type 18}} -
+ {{else if eq .Type 19}} - {{else if eq .Type 20}} -
+ {{else if eq .Type 23}} -
+ {{else if eq .Type 24}} -
+
From 41c7aa5a3ae7ac0e568ad2267ed76fd0681d0489 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Mon, 21 Oct 2019 13:41:05 +0000 Subject: [PATCH 149/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_es-ES.ini | 1 + options/locale/locale_pt-BR.ini | 1 + 2 files changed, 2 insertions(+) diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index c9a3284fbfac6..d9e18977b4c4a 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -1333,6 +1333,7 @@ settings.protect_this_branch=Activar protección de rama settings.protect_this_branch_desc=Prevenir eliminar y desactivar hacer git push en esta rama. settings.protect_whitelist_committers=Activar lista blanca para hacer push settings.protect_whitelist_committers_desc=Permitir hacer push en esta rama a los usuarios o equipos en la lista blanca (pero no hacer push forzado). +settings.protect_whitelist_deploy_keys=Poner en la lista blanca las claves de despliegue permitidas hacer push settings.protect_whitelist_users=Usuarios en la lista blanca para hacer push: settings.protect_whitelist_search_users=Buscar usuarios… settings.protect_whitelist_teams=Equipos en la lista blanca para hacer push: diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 3c441f5a1721c..4b0cc9c8d93ac 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -1324,6 +1324,7 @@ settings.protect_this_branch=Habilitar proteção de branch settings.protect_this_branch_desc=Prevenir exclusão e desabilitar qualquer push neste branch. settings.protect_whitelist_committers=Habilitar controle de permissão de push settings.protect_whitelist_committers_desc=Permitir que usuários ou times realizem push neste branch (exceto push forçado). +settings.protect_whitelist_deploy_keys=Lista de chaves de implantação com acesso de escrita para realizar push settings.protect_whitelist_users=Usuários com permissão para realizar push: settings.protect_whitelist_search_users=Pesquisar usuários... settings.protect_whitelist_teams=Equipes com permissão para realizar push: From b59a9053941b2762f0dc514fdb05b51d74784b5b Mon Sep 17 00:00:00 2001 From: zeripath Date: Mon, 21 Oct 2019 21:19:53 +0100 Subject: [PATCH 150/173] Update heatmap fixtures to restore tests (#8615) * Update heatmap fixtures to restore tests * Add hint to check the fixture age on fail --- integrations/api_user_heatmap_test.go | 2 +- models/fixtures/action.yml | 2 +- models/user_heatmap_test.go | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/integrations/api_user_heatmap_test.go b/integrations/api_user_heatmap_test.go index 5245bb0a265e7..2e2636ce94d2d 100644 --- a/integrations/api_user_heatmap_test.go +++ b/integrations/api_user_heatmap_test.go @@ -26,7 +26,7 @@ func TestUserHeatmap(t *testing.T) { var heatmap []*models.UserHeatmapData DecodeJSON(t, resp, &heatmap) var dummyheatmap []*models.UserHeatmapData - dummyheatmap = append(dummyheatmap, &models.UserHeatmapData{Timestamp: 1540080000, Contributions: 1}) + dummyheatmap = append(dummyheatmap, &models.UserHeatmapData{Timestamp: 1571616000, Contributions: 1}) assert.Equal(t, dummyheatmap, heatmap) } diff --git a/models/fixtures/action.yml b/models/fixtures/action.yml index 34a1a8b2be027..e8a6d531f2b33 100644 --- a/models/fixtures/action.yml +++ b/models/fixtures/action.yml @@ -5,7 +5,7 @@ act_user_id: 2 repo_id: 2 is_private: true - created_unix: 1540139562 + created_unix: 1571686356 - id: 2 diff --git a/models/user_heatmap_test.go b/models/user_heatmap_test.go index a71202d85716e..f882b3524733d 100644 --- a/models/user_heatmap_test.go +++ b/models/user_heatmap_test.go @@ -17,7 +17,7 @@ func TestGetUserHeatmapDataByUser(t *testing.T) { CountResult int JSONResult string }{ - {2, 1, `[{"timestamp":1540080000,"contributions":1}]`}, + {2, 1, `[{"timestamp":1571616000,"contributions":1}]`}, {3, 0, `[]`}, } // Prepare @@ -41,7 +41,7 @@ func TestGetUserHeatmapDataByUser(t *testing.T) { // Get the heatmap and compare heatmap, err := GetUserHeatmapDataByUser(user) assert.NoError(t, err) - assert.Equal(t, len(actions), len(heatmap)) + assert.Equal(t, len(actions), len(heatmap), "invalid action count: did the test data became too old?") assert.Equal(t, tc.CountResult, len(heatmap)) //Test JSON rendering From 73f8069249f2b88bbe42a8fc3db06f0e91719200 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Mon, 21 Oct 2019 20:22:31 +0000 Subject: [PATCH 151/173] [skip ci] Updated translations via Crowdin --- options/locale/locale_es-ES.ini | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index d9e18977b4c4a..b31151ac9c8ac 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -1309,20 +1309,20 @@ settings.add_discord_hook_desc=Integrar Discord en su repositor settings.add_dingtalk_hook_desc=Integrar Dingtalk en su repositorio. settings.add_telegram_hook_desc=Integrar Telegrama en tu repositorio. settings.add_msteams_hook_desc=Integrar Microsoft Teams en tu repositorio. -settings.deploy_keys=Claves de Despliegue -settings.add_deploy_key=Añadir Clave de Despliegue -settings.deploy_key_desc=Las claves de despliegue tienen acceso de sólo lectura al repositorio. +settings.deploy_keys=Claves de Implementación +settings.add_deploy_key=Añadir Clave de Implementación +settings.deploy_key_desc=Las claves de implementación tienen acceso de sólo lectura al repositorio. settings.is_writable=Habilitar acceso de escritura -settings.is_writable_info=Permitir que esta clave de despliegue pueda hacer push a este repositorio. -settings.no_deploy_keys=Aún no existen claves de despliegue. +settings.is_writable_info=Permitir que esta clave de implementación pueda hacer push a este repositorio. +settings.no_deploy_keys=Aún no existen claves de implementación. settings.title=Título settings.deploy_key_content=Contenido -settings.key_been_used=Una clave de despliegue con contenido idéntico ya se encuentra en uso. -settings.key_name_used=Ya existe una clave de despliegue con el mismo nombre. -settings.add_key_success=La clave de despliegue '%s' ha sido añadida. -settings.deploy_key_deletion=Eliminar clave de despliegue -settings.deploy_key_deletion_desc=Eliminar una clave de despliegue revocará el acceso de la misma a este repositorio. ¿Continuar? -settings.deploy_key_deletion_success=La clave de despliegue ha sido eliminada. +settings.key_been_used=Una clave de implementación con contenido idéntico ya se encuentra en uso. +settings.key_name_used=Ya existe una clave de implementación con el mismo nombre. +settings.add_key_success=La clave de implementación '%s' ha sido añadida. +settings.deploy_key_deletion=Eliminar clave de implementación +settings.deploy_key_deletion_desc=Eliminar una clave de implementación revocará el acceso de la misma a este repositorio. ¿Continuar? +settings.deploy_key_deletion_success=La clave de implementación ha sido eliminada. settings.branches=Ramas settings.protected_branch=Protección de rama settings.protected_branch_can_push=¿Permitir hacer push? @@ -1333,7 +1333,7 @@ settings.protect_this_branch=Activar protección de rama settings.protect_this_branch_desc=Prevenir eliminar y desactivar hacer git push en esta rama. settings.protect_whitelist_committers=Activar lista blanca para hacer push settings.protect_whitelist_committers_desc=Permitir hacer push en esta rama a los usuarios o equipos en la lista blanca (pero no hacer push forzado). -settings.protect_whitelist_deploy_keys=Poner en la lista blanca las claves de despliegue permitidas hacer push +settings.protect_whitelist_deploy_keys=Poner en lista blanca las claves de implementación con permisos de hacer push settings.protect_whitelist_users=Usuarios en la lista blanca para hacer push: settings.protect_whitelist_search_users=Buscar usuarios… settings.protect_whitelist_teams=Equipos en la lista blanca para hacer push: From d8161ee3fd5d2991f70523b03421af4e6cf5b513 Mon Sep 17 00:00:00 2001 From: zeripath Date: Mon, 21 Oct 2019 22:20:47 +0100 Subject: [PATCH 152/173] Expose db.SetMaxOpenConns and allow non MySQL dbs to set conn pool params (#8528) * Expose db.SetMaxOpenConns and allow other dbs to set their connection params * Add note about port exhaustion Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> --- custom/conf/app.ini.sample | 10 ++++++---- .../doc/advanced/config-cheat-sheet.en-us.md | 8 ++++++-- models/models.go | 8 +++----- modules/setting/database.go | 14 +++++++++----- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index c08dd62e7d28f..337676016476d 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -317,10 +317,12 @@ LOG_SQL = true DB_RETRIES = 10 ; Backoff time per DB retry (time.Duration) DB_RETRY_BACKOFF = 3s -; Max idle database connections on connnection pool, default is 0 -MAX_IDLE_CONNS = 0 -; Database connection max life time, default is 3s +; Max idle database connections on connnection pool, default is 2 +MAX_IDLE_CONNS = 2 +; Database connection max life time, default is 0 or 3s mysql (See #6804 & #7071 for reasoning) CONN_MAX_LIFETIME = 3s +; Database maximum number of open connections, default is 0 meaning no maximum +MAX_OPEN_CONNS = 0 [indexer] ; Issue indexer type, currently support: bleve or db, default is bleve @@ -870,6 +872,6 @@ TOKEN = QUEUE_TYPE = channel ; Task queue length, available only when `QUEUE_TYPE` is `channel`. QUEUE_LENGTH = 1000 -; Task queue connction string, available only when `QUEUE_TYPE` is `redis`. +; Task queue connection string, available only when `QUEUE_TYPE` is `redis`. ; If there is a password of redis, use `addrs=127.0.0.1:6379 password=123 db=0`. QUEUE_CONN_STR = "addrs=127.0.0.1:6379 db=0" diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 678f8df2382d3..f99e9f661aeb6 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -192,8 +192,12 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `LOG_SQL`: **true**: Log the executed SQL. - `DB_RETRIES`: **10**: How many ORM init / DB connect attempts allowed. - `DB_RETRY_BACKOFF`: **3s**: time.Duration to wait before trying another ORM init / DB connect attempt, if failure occured. -- `MAX_IDLE_CONNS` **0**: Max idle database connections on connnection pool, default is 0 -- `CONN_MAX_LIFETIME` **3s**: Database connection max lifetime +- `MAX_OPEN_CONNS` **0**: Database maximum open connections - default is 0, meaning there is no limit. +- `MAX_IDLE_CONNS` **2**: Max idle database connections on connnection pool, default is 2 - this will be capped to `MAX_OPEN_CONNS`. +- `CONN_MAX_LIFETIME` **0 or 3s**: Sets the maximum amount of time a DB connection may be reused - default is 0, meaning there is no limit (except on MySQL where it is 3s - see #6804 & #7071). + +Please see #8540 & #8273 for further discussion of the appropriate values for `MAX_OPEN_CONNS`, `MAX_IDLE_CONNS` & `CONN_MAX_LIFETIME` and their +relation to port exhaustion. ## Indexer (`indexer`) diff --git a/models/models.go b/models/models.go index 0454ec6add497..854cb33b147fe 100644 --- a/models/models.go +++ b/models/models.go @@ -157,11 +157,9 @@ func SetEngine() (err error) { // so use log file to instead print to stdout. x.SetLogger(NewXORMLogger(setting.Database.LogSQL)) x.ShowSQL(setting.Database.LogSQL) - if setting.Database.UseMySQL { - x.SetMaxIdleConns(setting.Database.MaxIdleConns) - x.SetConnMaxLifetime(setting.Database.ConnMaxLifetime) - } - + x.SetMaxOpenConns(setting.Database.MaxOpenConns) + x.SetMaxIdleConns(setting.Database.MaxIdleConns) + x.SetConnMaxLifetime(setting.Database.ConnMaxLifetime) return nil } diff --git a/modules/setting/database.go b/modules/setting/database.go index 2cac4824dfbcd..8c49ba3c5a179 100644 --- a/modules/setting/database.go +++ b/modules/setting/database.go @@ -42,12 +42,11 @@ var ( DBConnectRetries int DBConnectBackoff time.Duration MaxIdleConns int + MaxOpenConns int ConnMaxLifetime time.Duration IterateBufferSize int }{ - Timeout: 500, - MaxIdleConns: 0, - ConnMaxLifetime: 3 * time.Second, + Timeout: 500, } ) @@ -80,8 +79,13 @@ func InitDBConfig() { Database.Charset = sec.Key("CHARSET").In("utf8", []string{"utf8", "utf8mb4"}) Database.Path = sec.Key("PATH").MustString(filepath.Join(AppDataPath, "gitea.db")) Database.Timeout = sec.Key("SQLITE_TIMEOUT").MustInt(500) - Database.MaxIdleConns = sec.Key("MAX_IDLE_CONNS").MustInt(0) - Database.ConnMaxLifetime = sec.Key("CONN_MAX_LIFE_TIME").MustDuration(3 * time.Second) + Database.MaxIdleConns = sec.Key("MAX_IDLE_CONNS").MustInt(2) + if Database.UseMySQL { + Database.ConnMaxLifetime = sec.Key("CONN_MAX_LIFE_TIME").MustDuration(3 * time.Second) + } else { + Database.ConnMaxLifetime = sec.Key("CONN_MAX_LIFE_TIME").MustDuration(0) + } + Database.MaxOpenConns = sec.Key("MAX_OPEN_CONNS").MustInt(0) Database.IterateBufferSize = sec.Key("ITERATE_BUFFER_SIZE").MustInt(50) Database.LogSQL = sec.Key("LOG_SQL").MustBool(true) From 2f9a66a76c73f8fa03147d47efb338798b68c3a5 Mon Sep 17 00:00:00 2001 From: zeripath Date: Mon, 21 Oct 2019 23:23:35 +0100 Subject: [PATCH 153/173] Prevent .code-view from overriding font on icon fonts (#8614) --- public/css/index.css | 2 +- public/less/_base.less | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/css/index.css b/public/css/index.css index 03a199d0b9af4..9292604422dd1 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -243,7 +243,7 @@ i.icon.centerlock{top:1.5em} .lines-commit .ui.avatar.image{height:18px;width:18px} .lines-code .bottom-line,.lines-commit .bottom-line,.lines-num .bottom-line{border-bottom:1px solid #eaecef} .code-view{overflow:auto;overflow-x:auto;overflow-y:hidden} -.code-view *{font-size:12px;font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;line-height:20px} +.code-view :not(.fa):not(.octicon):not(.icon){font-size:12px;font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;line-height:20px} .code-view table{width:100%} .code-view .active{background:#fff866} .markdown:not(code){overflow:hidden;font-size:16px;line-height:1.6!important;word-wrap:break-word} diff --git a/public/less/_base.less b/public/less/_base.less index 62b2084a3b3d7..1a386f17b0cec 100644 --- a/public/less/_base.less +++ b/public/less/_base.less @@ -1063,7 +1063,7 @@ i.icon.centerlock { overflow-x: auto; overflow-y: hidden; - * { + *:not(.fa):not(.octicon):not(.icon) { font-size: 12px; font-family: @monospaced-fonts, monospace; line-height: 20px; From d0c7a08d751bd068e557efe56683b999d29eb910 Mon Sep 17 00:00:00 2001 From: Lukas Date: Tue, 22 Oct 2019 01:45:53 +0200 Subject: [PATCH 154/173] Correct some outdated statements in the contributing guidelines (#8612) * More information for drone-cli in CONTRIBUTING.md * Increases the version of drone-cli to 1.2.0 * Adds a note for the Docker Toolbox on Windows Signed-off-by: LukBukkit * Fix the url for the blog repository (now on gitea.com) Signed-off-by: LukBukkit --- CONTRIBUTING.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 93083dc491fb5..04ffebe62877c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -72,13 +72,15 @@ Here's how to run the test suite: - Install the correct version of the drone-cli package. As of this writing, the correct drone-cli version is - [1.1.0](https://docs.drone.io/cli/install/). + [1.2.0](https://docs.drone.io/cli/install/). - Ensure you have enough free disk space. You will need at least 15-20 Gb of free disk space to hold all of the containers drone creates (a default AWS or GCE disk size won't work -- see [#6243](https://github.com/go-gitea/gitea/issues/6243)). - Change into the base directory of your copy of the gitea repository, and run `drone exec --event pull_request`. +- At the moment `drone exec` doesn't support the Docker Toolbox on Windows 10 + (see [drone-cli#135](https://github.com/drone/drone-cli/issues/135)) The drone version, command line, and disk requirements do change over time (see [#4053](https://github.com/go-gitea/gitea/issues/4053) and @@ -302,7 +304,7 @@ be reviewed by two maintainers and must pass the automatic tests. * Add a tag as `git tag -s -F release.notes v$vmaj.$vmin.$`, release.notes file could be a temporary file to only include the changelog this version which you added to `CHANGELOG.md`. * And then push the tag as `git push origin v$vmaj.$vmin.$`. Drone CI will automatically created a release and upload all the compiled binary. (But currently it didn't add the release notes automatically. Maybe we should fix that.) * If needed send PR for changelog on branch `master`. -* Send PR to [blog repository](https://github.com/go-gitea/blog) announcing the release. +* Send PR to [blog repository](https://gitea.com/gitea/blog) announcing the release. ## Copyright From 00629fea95970e99ba5ef05954bbad0804805df6 Mon Sep 17 00:00:00 2001 From: Jakob Ackermann Date: Tue, 22 Oct 2019 14:11:01 +0200 Subject: [PATCH 155/173] [assets] configurable URL for static resources (#7911) * static url * add cors support for static resources * [assets] work on the migration to configurable url for assets Signed-off-by: Jakob Ackermann * [misc] fix whitespace Signed-off-by: Jakob Ackermann * [assets] fix the loading of the manifest.json It is generated dynamically, and as such can not be served by the cdn. Signed-off-by: Jakob Ackermann * Revert "add cors support for static resources" This reverts commit 42f964fd181dbb8b139808b9be623470d4f0e40f Signed-off-by: Jakob Ackermann * [docs] add the STATIC_URL_PREFIX option Signed-off-by: Jakob Ackermann * [docs] reverse-proxy: nginx: add two setups for STATIC_URL_PREFIX Signed-off-by: Jakob Ackermann * [assets] migrate the url of a new asset to the static url prefix REF: f2a3abc683ad4b2177b7c7c6160a2c0b4316120a Signed-off-by: Jakob Ackermann --- custom/conf/app.ini.sample | 2 + .../doc/advanced/config-cheat-sheet.en-us.md | 7 ++ .../doc/usage/reverse-proxies.en-us.md | 68 +++++++++++++++++ modules/setting/setting.go | 4 +- modules/templates/helper.go | 3 + templates/admin/hook_new.tmpl | 14 ++-- templates/base/footer.tmpl | 46 +++++------ templates/base/footer_content.tmpl | 2 +- templates/base/head.tmpl | 44 +++++------ templates/base/head_navbar.tmpl | 2 +- templates/home.tmpl | 2 +- templates/org/settings/hook_new.tmpl | 14 ++-- templates/pwa/manifest_json.tmpl | 10 +-- templates/pwa/serviceworker_js.tmpl | 76 +++++++++---------- templates/repo/migrating.tmpl | 2 +- templates/repo/settings/webhook/list.tmpl | 14 ++-- templates/repo/settings/webhook/new.tmpl | 14 ++-- templates/repo/view_file.tmpl | 2 +- templates/status/404.tmpl | 2 +- templates/status/500.tmpl | 2 +- templates/swagger/ui.tmpl | 10 +-- 21 files changed, 211 insertions(+), 129 deletions(-) diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index 337676016476d..f0204bb06ea09 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -185,6 +185,8 @@ FILE_EXTENSIONS = .md,.markdown,.mdown,.mkd PROTOCOL = http DOMAIN = localhost ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/ +; when STATIC_URL_PREFIX is empty it will follow APP_URL +STATIC_URL_PREFIX = ; The address to listen on. Either a IPv4/IPv6 address or the path to a unix socket. HTTP_ADDR = 0.0.0.0 HTTP_PORT = 3000 diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index f99e9f661aeb6..c2744b295859c 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -138,6 +138,13 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `ROOT_URL`: **%(PROTOCOL)s://%(DOMAIN)s:%(HTTP\_PORT)s/**: Overwrite the automatically generated public URL. This is useful if the internal and the external URL don't match (e.g. in Docker). +- `STATIC_URL_PREFIX`: **\**: + Overwrite this option to request static resources from a different URL. + This includes CSS files, images, JS files and web fonts. + Avatar images are dynamic resources and still served by gitea. + The option can be just a different path, as in `/static`, or another domain, as in `https://cdn.example.com`. + Requests are then made as `%(ROOT_URL)s/static/css/index.css` and `https://cdn.example.com/css/index.css` respective. + The static files are located in the `public/` directory of the gitea source repository. - `HTTP_ADDR`: **0.0.0.0**: HTTP listen address. - If `PROTOCOL` is set to `fcgi`, Gitea will listen for FastCGI requests on TCP socket defined by `HTTP_ADDR` and `HTTP_PORT` configuration settings. diff --git a/docs/content/doc/usage/reverse-proxies.en-us.md b/docs/content/doc/usage/reverse-proxies.en-us.md index 47a5b955729d5..55c8bb9710f79 100644 --- a/docs/content/doc/usage/reverse-proxies.en-us.md +++ b/docs/content/doc/usage/reverse-proxies.en-us.md @@ -44,6 +44,74 @@ server { Then set `[server] ROOT_URL = http://git.example.com/git/` in your configuration. +## Using Nginx as a reverse proxy and serve static resources directly +We can tune the performance in splitting requests into categories static and dynamic. + +CSS files, JavaScript files, images and web fonts are static content. +The front page, a repository view or issue list is dynamic content. + +Nginx can serve static resources directly and proxy only the dynamic requests to gitea. +Nginx is optimized for serving static content, while the proxying of large responses might be the opposite of that + (see https://serverfault.com/q/587386). + +Download a snap shot of the gitea source repository to `/path/to/gitea/`. + +We are only interested in the `public/` directory and you can delete the rest. + +Depending on the scale of your user base, you might want to split the traffic to two distinct servers, + or use a cdn for the static files. + +### using a single node and a single domain + +Set `[server] STATIC_URL_PREFIX = /_/static` in your configuration. + +``` +server { + listen 80; + server_name git.example.com; + + location /_/static { + alias /path/to/gitea/public; + } + + location / { + proxy_pass http://localhost:3000; + } +} +``` + +### using two nodes and two domains + +Set `[server] STATIC_URL_PREFIX = http://cdn.example.com/gitea` in your configuration. + +``` +# application server running gitea +server { + listen 80; + server_name git.example.com; + + location / { + proxy_pass http://localhost:3000; + } +} +``` + +``` +# static content delivery server +server { + listen 80; + server_name cdn.example.com; + + location /gitea { + alias /path/to/gitea/public; + } + + location / { + return 404; + } +} +``` + ## Using Apache HTTPD as a reverse proxy If you want Apache HTTPD to serve your Gitea instance, you can add the following to your Apache HTTPD configuration (usually located at `/etc/apache2/httpd.conf` in Ubuntu): diff --git a/modules/setting/setting.go b/modules/setting/setting.go index d05c52fea04f6..f3dd45d7bf966 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -99,6 +99,7 @@ var ( LetsEncryptEmail string GracefulRestartable bool GracefulHammerTime time.Duration + StaticURLPrefix string SSH = struct { Disabled bool `ini:"DISABLE_SSH"` @@ -573,7 +574,7 @@ func NewContext() { defaultAppURL += ":" + HTTPPort } AppURL = sec.Key("ROOT_URL").MustString(defaultAppURL) - AppURL = strings.TrimRight(AppURL, "/") + "/" + AppURL = strings.TrimSuffix(AppURL, "/") + "/" // Check if has app suburl. appURL, err := url.Parse(AppURL) @@ -583,6 +584,7 @@ func NewContext() { // Suburl should start with '/' and end without '/', such as '/{subpath}'. // This value is empty if site does not have sub-url. AppSubURL = strings.TrimSuffix(appURL.Path, "/") + StaticURLPrefix = strings.TrimSuffix(sec.Key("STATIC_URL_PREFIX").MustString(AppSubURL), "/") AppSubURLDepth = strings.Count(AppSubURL, "/") // Check if Domain differs from AppURL domain than update it to AppURL's domain // TODO: Can be replaced with url.Hostname() when minimal GoLang version is 1.8 diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 9bb803c01047f..b5287bf971301 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -48,6 +48,9 @@ func NewFuncMap() []template.FuncMap { "AppSubUrl": func() string { return setting.AppSubURL }, + "StaticUrlPrefix": func() string { + return setting.StaticURLPrefix + }, "AppUrl": func() string { return setting.AppURL }, diff --git a/templates/admin/hook_new.tmpl b/templates/admin/hook_new.tmpl index c047efe9a26e8..2292377f6eec2 100644 --- a/templates/admin/hook_new.tmpl +++ b/templates/admin/hook_new.tmpl @@ -11,19 +11,19 @@ {{end}}
{{if eq .HookType "gitea"}} - + {{else if eq .HookType "gogs"}} - + {{else if eq .HookType "slack"}} - + {{else if eq .HookType "discord"}} - + {{else if eq .HookType "dingtalk"}} - + {{else if eq .HookType "telegram"}} - + {{else if eq .HookType "msteams"}} - + {{end}}
diff --git a/templates/base/footer.tmpl b/templates/base/footer.tmpl index 13718620da0ec..7185b20377796 100644 --- a/templates/base/footer.tmpl +++ b/templates/base/footer.tmpl @@ -12,38 +12,38 @@ {{template "base/footer_content" .}} - - - + + + {{if .RequireSimpleMDE}} - - - + + + {{end}} {{if .RequireGitGraph}} - - + + {{end}} {{if .RequireHighlightJS}} - + {{end}} {{if .RequireMinicolors}} - + {{end}} {{if .RequireDatetimepicker}} - + {{end}} {{if .RequireDropzone}} - + {{end}} {{if .RequireU2F}} - + {{end}} {{if .EnableCaptcha}} {{if eq .CaptchaType "recaptcha"}} @@ -51,7 +51,7 @@ {{end}} {{end}} {{if .RequireTribute}} - + {{end}} - - - + + + - - + + {{if .EnableHeatmap}} - - + + diff --git a/templates/base/footer_content.tmpl b/templates/base/footer_content.tmpl index 6f680d4cb893d..364e58a3d03df 100644 --- a/templates/base/footer_content.tmpl +++ b/templates/base/footer_content.tmpl @@ -16,7 +16,7 @@ {{end}}
- JavaScript licenses + JavaScript licenses {{if .EnableSwagger}}API{{end}} {{.i18n.Tr "website"}} {{if (or .ShowFooterVersion .PageIsAdmin)}}{{GoVer}}{{end}} diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl index 7cdfdd34bea85..ae2b6b954d601 100644 --- a/templates/base/head.tmpl +++ b/templates/base/head.tmpl @@ -70,35 +70,35 @@ THE SOFTWARE. --- Licensing information for additional javascript libraries can be found at: - {{AppSubUrl}}/vendor/librejs.html + {{StaticUrlPrefix}}/vendor/librejs.html @licend The above is the entire license notice for the JavaScript code in this page. */`}} - - - - - + + + + + {{if .RequireSimpleMDE}} - + {{end}} {{if .RequireGitGraph}} - + {{end}} {{if .RequireTribute}} - + {{end}} - - + +