diff --git a/.drone.yml b/.drone.yml index c72c4226d..086c19627 100644 --- a/.drone.yml +++ b/.drone.yml @@ -554,7 +554,7 @@ steps: # TODO: We should probably build all dependencies into a test image - name: test-e2e - image: mcr.microsoft.com/playwright:v1.23.1-focal + image: mcr.microsoft.com/playwright:v1.24.0-focal commands: - curl -sLO https://go.dev/dl/go1.18.linux-amd64.tar.gz && tar -C /usr/local -xzf go1.18.linux-amd64.tar.gz - groupadd --gid 1001 gitea && useradd -m --gid 1001 --uid 1001 gitea diff --git a/go.mod b/go.mod index 0e93ea443..e684cca13 100644 --- a/go.mod +++ b/go.mod @@ -54,7 +54,7 @@ require ( github.com/google/uuid v1.3.0 github.com/gorilla/feeds v1.1.1 github.com/gorilla/sessions v1.2.1 - github.com/hashicorp/go-version v1.4.0 + github.com/hashicorp/go-version v1.5.0 github.com/hashicorp/golang-lru v0.5.4 github.com/huandu/xstrings v1.3.2 github.com/jaytaylor/html2text v0.0.0-20211105163654-bc68cce691ba @@ -103,6 +103,7 @@ require ( gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/ini.v1 v1.67.0 gopkg.in/yaml.v2 v2.4.0 + lab.forgefriends.org/friendlyforgeformat/gof3 v0.0.0-20220906040547-8d2ab6ab8462 mvdan.cc/xurls/v2 v2.4.0 strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 xorm.io/builder v0.3.11 @@ -157,6 +158,7 @@ require ( github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davidmz/go-pageant v1.0.2 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dlclark/regexp2 v1.7.0 // indirect github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect @@ -191,6 +193,7 @@ require ( github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.0.1 // indirect github.com/google/certificate-transparency-go v1.1.2-0.20210511102531-373a877eec92 // indirect + github.com/google/go-cmp v0.5.8 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/gorilla/handlers v1.5.1 // indirect @@ -281,6 +284,7 @@ require ( go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.8.0 // indirect go.uber.org/zap v1.23.0 // indirect + golang.org/x/exp v0.0.0-20220516143420-24438e51023a // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect google.golang.org/appengine v1.6.7 // indirect @@ -294,6 +298,10 @@ require ( sigs.k8s.io/yaml v1.2.0 // indirect ) +//replace lab.forgefriends.org/friendlyforgeformat/gof3 => ../../gof3 + +replace code.gitea.io/sdk/gitea => gitea.com/earl-warren/go-sdk/gitea v0.15.1-0.20220821233938-49e74ff9d331 + replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1 replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0 diff --git a/go.sum b/go.sum index 78b1df2c2..fc4f01712 100644 --- a/go.sum +++ b/go.sum @@ -64,12 +64,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= -code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= code.gitea.io/gitea-vet v0.2.2-0.20220122151748-48ebc902541b h1:uv9a8eGSdQ8Dr4HyUcuHFfDsk/QuwO+wf+Y99RYdxY0= code.gitea.io/gitea-vet v0.2.2-0.20220122151748-48ebc902541b/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= -code.gitea.io/sdk/gitea v0.11.3/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY= -code.gitea.io/sdk/gitea v0.15.1 h1:WJreC7YYuxbn0UDaPuWIe/mtiNKTvLN8MLkaw71yx/M= -code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA= codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570 h1:TXbikPqa7YRtfU9vS6QJBg77pUvbEb6StRdZO8t1bEY= codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570/go.mod h1:IIAjsijsd8q1isWX8MACefDEgTQslQ4stk2AeeTt3kM= contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= @@ -81,6 +77,8 @@ contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcig dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg= git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs= +gitea.com/earl-warren/go-sdk/gitea v0.15.1-0.20220821233938-49e74ff9d331 h1:BZ8FPrsODvJeyT7AYK3JTqLK8qWLK4i+drUxqRs77Q4= +gitea.com/earl-warren/go-sdk/gitea v0.15.1-0.20220821233938-49e74ff9d331/go.mod h1:aRmrQC3CAHdJAU1LQt0C9zqzqI8tUB/5oQtNE746aYE= gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb h1:Yy0Bxzc8R2wxiwXoG/rECGplJUSpXqCsog9PuJFgiHs= gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb/go.mod h1:77TZu701zMXWJFvB8gvTbQ92zQ3DQq/H7l5wAEjQRKc= gitea.com/go-chi/cache v0.0.0-20210110083709-82c4c9ce2d5e/go.mod h1:k2V/gPDEtXGjjMGuBJiapffAXTv76H4snSmlJRLUhH0= @@ -369,6 +367,8 @@ github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2 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= +github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0= +github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= @@ -481,6 +481,7 @@ github.com/go-enry/go-enry/v2 v2.8.2 h1:uiGmC+3K8sVd/6DOe2AOJEOihJdqda83nPyJNtMR github.com/go-enry/go-enry/v2 v2.8.2/go.mod h1:GVzIiAytiS5uT/QiuakK7TF1u4xDab87Y8V5EJRpsIQ= github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo= github.com/go-enry/go-oniguruma v1.2.1/go.mod h1:bWDhYP+S6xZQgiRL7wlTScFYBe023B6ilRZbCAD5Hf4= +github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM= github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e h1:oRq/fiirun5HqlEWMLIcDmLpIELlG4iGbd0s8iqgPi8= github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM= github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= @@ -1588,12 +1589,14 @@ golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= @@ -1609,6 +1612,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= +golang.org/x/exp v0.0.0-20220516143420-24438e51023a h1:tiLLxEjKNE6Hrah/Dp/cyHvsyjDLcMFSocOHO5XDmOM= +golang.org/x/exp v0.0.0-20220516143420-24438e51023a/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -2241,6 +2246,8 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.1.4/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +lab.forgefriends.org/friendlyforgeformat/gof3 v0.0.0-20220906040547-8d2ab6ab8462 h1:uMa75Zn1Dgne2mPpO7JWsq5KgyyNandRoIq5KedaGk0= +lab.forgefriends.org/friendlyforgeformat/gof3 v0.0.0-20220906040547-8d2ab6ab8462/go.mod h1:JOIXqRVTbUrY0e7nPUHFklu7gScEhioF7YD7Gfd5/4c= lukechampine.com/uint128 v1.1.1 h1:pnxCASz787iMf+02ssImqk6OLt+Z5QHMoZyUXR4z6JU= lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.33.6/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 997899a90..486c427b0 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -866,7 +866,7 @@ mirror_prune_desc=删除过时的远程跟踪引用 mirror_interval=镜像间隔 (有效的时间单位是 'h', 'm', 's')。0 禁用自动定期同步 (最短间隔: %s) mirror_interval_invalid=镜像间隔无效。 mirror_sync_on_commit=推送提交时同步 -mirror_address=从URL克隆 +mirror_address=从 URL 克隆 mirror_address_desc=在授权框中输入必要的凭据。 mirror_address_url_invalid=URL无效。请检查您所输入的URL是否正确。 mirror_address_protocol_invalid=提供的 url 无效。只能从 http(s):// 或 git:// 位置进行镜像。 diff --git a/services/f3/driver/driver.go b/services/f3/driver/driver.go new file mode 100644 index 000000000..dd1ce49f3 --- /dev/null +++ b/services/f3/driver/driver.go @@ -0,0 +1,104 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. +package driver + +import ( + "context" + "fmt" + + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/services/migrations" + + "lab.forgefriends.org/friendlyforgeformat/gof3" + "lab.forgefriends.org/friendlyforgeformat/gof3/forges/common" + "lab.forgefriends.org/friendlyforgeformat/gof3/forges/driver" + "lab.forgefriends.org/friendlyforgeformat/gof3/format" +) + +type Options struct { + gof3.Options + + Doer *user_model.User +} + +type Gitea struct { + perPage int + ctx context.Context + options *Options +} + +func (o *Gitea) GetPerPage() int { + return o.perPage +} + +func (o *Gitea) GetOptions() gof3.OptionsInterface { + return o.options +} + +func (o *Gitea) SetOptions(options gof3.OptionsInterface) { + var ok bool + o.options, ok = options.(*Options) + if !ok { + panic(fmt.Errorf("unexpected type %T", options)) + } +} + +func (o *Gitea) Init(options gof3.OptionsInterface) { + o.SetOptions(options) + o.perPage = 100 +} + +func (o *Gitea) GetDirectory() string { + return o.options.GetDirectory() +} + +func (o *Gitea) GetDoer() *user_model.User { + return o.options.Doer +} + +func (o *Gitea) GetNewMigrationHTTPClient() gof3.NewMigrationHTTPClientFun { + return migrations.NewMigrationHTTPClient +} + +func (o *Gitea) SupportGetRepoComments() bool { + return false +} + +func (o *Gitea) SetContext(ctx context.Context) { + o.ctx = ctx +} + +func (o *Gitea) GetProvider(name string) common.ProviderInterface { + switch name { + case driver.ProviderUser: + return &driver.Provider[UserProvider, *UserProvider, User, *User, format.User, *format.User]{Impl: &UserProvider{g: o}} + case driver.ProviderProject: + return &driver.ProviderWithParentOne[ProjectProvider, *ProjectProvider, Project, *Project, format.Project, *format.Project, User, *User]{Impl: &ProjectProvider{g: o}} + // case driver.ProviderMilestone: + // return &driver.ProviderWithParentOneTwo[MilestoneProvider, *MilestoneProvider, Milestone, *Milestone, format.Milestone, *format.Milestone, User, *User, Project, *Project]{Impl: &MilestoneProvider{g: o}} + // case driver.ProviderIssue: + // return &driver.ProviderWithParentOneTwo[IssueProvider, *IssueProvider, Issue, *Issue, format.Issue, *format.Issue, User, *User, Project, *Project]{Impl: &IssueProvider{g: o}} + // case driver.ProviderPullRequest: + // return &driver.ProviderWithParentOneTwo[PullRequestProvider, *PullRequestProvider, PullRequest, *PullRequest, format.PullRequest, *format.PullRequest, User, *User, Project, *Project]{Impl: &PullRequestProvider{g: o}} + // case driver.ProviderReview: + // return &driver.ProviderWithParentOneTwoThree[ReviewProvider, *ReviewProvider, Review, *Review, format.Review, *format.Review, User, *User, Project, *Project, PullRequest, *PullRequest]{Impl: &ReviewProvider{g: o}} + // case driver.ProviderRepository: + // return &driver.ProviderWithParentOneTwo[RepositoryProvider, *RepositoryProvider, Repository, *Repository, format.Repository, *format.Repository, User, *User, Project, *Project]{Impl: &RepositoryProvider{g: o}} + // case driver.ProviderTopic: + // return &driver.ProviderWithParentOneTwo[TopicProvider, *TopicProvider, Topic, *Topic, format.Topic, *format.Topic, User, *User, Project, *Project]{Impl: &TopicProvider{g: o}} + // case driver.ProviderLabel: + // return &driver.ProviderWithParentOneTwo[LabelProvider, *LabelProvider, Label, *Label, format.Label, *format.Label, User, *User, Project, *Project]{Impl: &LabelProvider{g: o}} + // case driver.ProviderRelease: + // return &driver.ProviderWithParentOneTwo[ReleaseProvider, *ReleaseProvider, Release, *Release, format.Release, *format.Release, User, *User, Project, *Project]{Impl: &ReleaseProvider{g: o}} + // case driver.ProviderAsset: + // return &driver.ProviderWithParentOneTwoThree[AssetProvider, *AssetProvider, Asset, *Asset, format.ReleaseAsset, *format.ReleaseAsset, User, *User, Project, *Project, Release, *Release]{Impl: &AssetProvider{g: o}} + // case driver.ProviderComment: + // return &driver.ProviderWithParentOneTwoThreeInterface[CommentProvider, *CommentProvider, Comment, *Comment, format.Comment, *format.Comment, User, *User, Project, *Project]{Impl: &CommentProvider{g: o}} + default: + panic(fmt.Sprintf("unknown provider name %s", name)) + } +} + +func (o Gitea) Finish() { +} diff --git a/services/f3/driver/project.go b/services/f3/driver/project.go new file mode 100644 index 000000000..b7f1e969e --- /dev/null +++ b/services/f3/driver/project.go @@ -0,0 +1,151 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. +package driver + +import ( + "fmt" + + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + repo_module "code.gitea.io/gitea/modules/repository" + repo_service "code.gitea.io/gitea/services/repository" + "lab.forgefriends.org/friendlyforgeformat/gof3/format" + f3_util "lab.forgefriends.org/friendlyforgeformat/gof3/util" +) + +type Project struct { + repo_model.Repository +} + +func ProjectConverter(f *repo_model.Repository) *Project { + return &Project{ + Repository: *f, + } +} + +func (o Project) GetID() int64 { + return o.ID +} + +func (o *Project) SetID(id int64) { + o.ID = id +} + +func (o *Project) IsNil() bool { + return o.ID == 0 +} + +func (o *Project) Equals(other *Project) bool { + return (o.Name == other.Name) +} + +func (o *Project) ToFormat() *format.Project { + return &format.Project{ + Common: format.Common{Index: o.ID}, + Name: o.Name, + Owner: o.Owner.Name, + IsPrivate: o.IsPrivate, + Description: o.Description, + CloneURL: repo_model.ComposeHTTPSCloneURL(o.Owner.Name, o.Name), + OriginalURL: o.OriginalURL, + DefaultBranch: o.DefaultBranch, + } +} + +func (o *Project) FromFormat(project *format.Project) { + *o = Project{ + Repository: repo_model.Repository{ + ID: project.Index, + Name: project.Name, + Owner: &user_model.User{ + Name: project.Owner, + }, + IsPrivate: project.IsPrivate, + Description: project.Description, + OriginalURL: project.OriginalURL, + DefaultBranch: project.DefaultBranch, + }, + } +} + +type ProjectProvider struct { + g *Gitea +} + +func (o *ProjectProvider) ToFormat(project *Project) *format.Project { + return project.ToFormat() +} + +func (o *ProjectProvider) FromFormat(p *format.Project) *Project { + var project Project + project.FromFormat(p) + return &project +} + +func (o *ProjectProvider) GetObjects(user *User, page int) []*Project { + repoList, _, err := repo_model.GetUserRepositories(&repo_model.SearchRepoOptions{ + ListOptions: db.ListOptions{Page: page, PageSize: o.g.perPage}, + Actor: &user.User, + Private: true, + }) + if err != nil { + panic(fmt.Errorf("error while listing projects: %T %v", err, err)) + } + if err := repoList.LoadAttributes(); err != nil { + panic(nil) + } + return f3_util.ConvertMap[*repo_model.Repository, *Project](([]*repo_model.Repository)(repoList), ProjectConverter) +} + +func (o *ProjectProvider) ProcessObject(user *User, project *Project) { +} + +func (o *ProjectProvider) Get(user *User, exemplar *Project) *Project { + var project *repo_model.Repository + var err error + if exemplar.GetID() > 0 { + project, err = repo_model.GetRepositoryByIDCtx(o.g.ctx, exemplar.GetID()) + } else if exemplar.Name != "" { + project, err = repo_model.GetRepositoryByName(user.GetID(), exemplar.Name) + } else { + panic("GetID() == 0 and ProjectName == \"\"") + } + if repo_model.IsErrRepoNotExist(err) { + return &Project{} + } + if err != nil { + panic(fmt.Errorf("project %v %w", exemplar, err)) + } + return ProjectConverter(project) +} + +func (o *ProjectProvider) Put(user *User, project *Project) *Project { + repo, err := repo_module.CreateRepository(o.g.GetDoer(), &user.User, repo_module.CreateRepoOptions{ + Name: project.Name, + Description: project.Description, + OriginalURL: project.OriginalURL, + IsPrivate: project.IsPrivate, + }) + if err != nil { + panic(err) + } + return o.Get(user, ProjectConverter(repo)) +} + +func (o *ProjectProvider) Delete(user *User, project *Project) *Project { + if project.IsNil() { + return project + } + if project.ID > 0 { + project = o.Get(user, project) + } + if !project.IsNil() { + err := repo_service.DeleteRepository(o.g.ctx, o.g.GetDoer(), &project.Repository, true) + if err != nil { + panic(err) + } + } + return project +} diff --git a/services/f3/driver/user.go b/services/f3/driver/user.go new file mode 100644 index 000000000..a9c826227 --- /dev/null +++ b/services/f3/driver/user.go @@ -0,0 +1,132 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. +package driver + +import ( + "fmt" + + "code.gitea.io/gitea/models/db" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/util" + user_service "code.gitea.io/gitea/services/user" + "lab.forgefriends.org/friendlyforgeformat/gof3/format" + f3_util "lab.forgefriends.org/friendlyforgeformat/gof3/util" +) + +type User struct { + user_model.User +} + +func UserConverter(f *user_model.User) *User { + return &User{ + User: *f, + } +} + +func (o User) GetID() int64 { + return o.ID +} + +func (o *User) SetID(id int64) { + o.ID = id +} + +func (o *User) IsNil() bool { + return o.ID == 0 +} + +func (o *User) Equals(other *User) bool { + return (o.Name == other.Name) +} + +func (o *User) ToFormat() *format.User { + return &format.User{ + Common: format.Common{Index: o.ID}, + UserName: o.Name, + Name: o.FullName, + Email: o.Email, + Password: o.Passwd, + } +} + +func (o *User) FromFormat(user *format.User) { + *o = User{ + User: user_model.User{ + ID: user.Index, + Name: user.UserName, + FullName: user.Name, + Email: user.Email, + Passwd: user.Password, + }, + } +} + +type UserProvider struct { + g *Gitea +} + +func (o *UserProvider) ToFormat(user *User) *format.User { + return user.ToFormat() +} + +func (o *UserProvider) FromFormat(p *format.User) *User { + var user User + user.FromFormat(p) + return &user +} + +func (o *UserProvider) GetObjects(page int) []*User { + users, _, err := user_model.SearchUsers(&user_model.SearchUserOptions{ + Actor: o.g.GetDoer(), + Type: user_model.UserTypeIndividual, + ListOptions: db.ListOptions{Page: page, PageSize: o.g.perPage}, + }) + if err != nil { + panic(fmt.Errorf("error while listing users: %v", err)) + } + return f3_util.ConvertMap[*user_model.User, *User](users, UserConverter) +} + +func (o *UserProvider) ProcessObject(user *User) { +} + +func (o *UserProvider) Get(exemplar *User) *User { + var user *user_model.User + var err error + if exemplar.GetID() > 0 { + user, err = user_model.GetUserByIDCtx(o.g.ctx, exemplar.GetID()) + } else if exemplar.Name != "" { + user, err = user_model.GetUserByName(o.g.ctx, exemplar.Name) + } else { + panic("GetID() == 0 and UserName == \"\"") + } + if user_model.IsErrUserNotExist(err) { + return &User{} + } + if err != nil { + panic(fmt.Errorf("user %v %w", exemplar, err)) + } + return UserConverter(user) +} + +func (o *UserProvider) Put(user *User) *User { + overwriteDefault := &user_model.CreateUserOverwriteOptions{ + IsActive: util.OptionalBoolTrue, + } + err := user_model.CreateUser(&user.User, overwriteDefault) + if err != nil { + panic(err) + } + return o.Get(user) +} + +func (o *UserProvider) Delete(user *User) *User { + u := o.Get(user) + if !u.IsNil() { + if err := user_service.DeleteUser(o.g.ctx, &user.User, true); err != nil { + panic(err) + } + } + return u +} diff --git a/services/f3/f3.go b/services/f3/f3.go new file mode 100644 index 000000000..33efac50a --- /dev/null +++ b/services/f3/f3.go @@ -0,0 +1,27 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. +package f3 + +import ( + "code.gitea.io/gitea/modules/log" + base "code.gitea.io/gitea/modules/migration" + + "lab.forgefriends.org/friendlyforgeformat/gof3" +) + +func ToF3Logger(messenger base.Messenger) gof3.Logger { + if messenger == nil { + messenger = func(string, ...interface{}) {} + } + return gof3.Logger{ + Message: messenger, + Trace: log.Trace, + Debug: log.Debug, + Info: log.Info, + Warn: log.Warn, + Error: log.Error, + Critical: log.Critical, + Fatal: log.Fatal, + } +} diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index fd1b60bef..69af36ac6 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -73,32 +73,33 @@ {{end}} {{svg "octicon-file-moved" 15}} - {{if or .CanAddFile .CanUploadFile}} - - {{end}} - {{else}} + {{if .CanUploadFile}} + + {{.locale.Tr "repo.editor.upload_file"}} + + {{end}} + {{if .CanAddFile}} + + {{.locale.Tr "repo.editor.patch"}} + + {{end}} + {{end}} + + {{svg "octicon-triangle-down" 14 "dropdown icon"}} + + {{end}} + {{if ne $n 0}} {{EllipsisString .Repository.Name 30}}{{range $i, $v := .TreeNames}}/{{if eq $i $l}}{{EllipsisString $v 30}}{{else}}{{$p := index $.Paths $i}}{{EllipsisString $v 30}}{{end}}{{end}} {{end}} diff --git a/tests/integration/f3_test.go b/tests/integration/f3_test.go new file mode 100644 index 000000000..7a827ddbd --- /dev/null +++ b/tests/integration/f3_test.go @@ -0,0 +1,81 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package integration + +import ( + "context" + "net/url" + "testing" + + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/setting" + f3_driver "code.gitea.io/gitea/services/f3/driver" + "lab.forgefriends.org/friendlyforgeformat/gof3" + f3_forges "lab.forgefriends.org/friendlyforgeformat/gof3/forges" + f3_gitea "lab.forgefriends.org/friendlyforgeformat/gof3/forges/gitea" + + "github.com/stretchr/testify/assert" +) + +func TestF3(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + AllowLocalNetworks := setting.Migrations.AllowLocalNetworks + setting.Migrations.AllowLocalNetworks = true + AppVer := setting.AppVer + // Gitea SDK (go-sdk) need to parse the AppVer from server response, so we must set it to a valid version string. + setting.AppVer = "1.16.0" + defer func() { + setting.Migrations.AllowLocalNetworks = AllowLocalNetworks + setting.AppVer = AppVer + }() + + // + // Step 1: create a fixture + // + fixture := f3_forges.NewFixture(t, f3_forges.FixtureF3Factory) + fixture.NewUser() + + // + // Step 2: mirror the fixture into Gitea + // + doer, err := user_model.GetAdminUser() + assert.NoError(t, err) + + giteaLocal := f3_forges.NewForgeRootFromDriver(&f3_driver.Gitea{}, &f3_driver.Options{ + Options: gof3.Options{ + Configuration: gof3.Configuration{ + Directory: t.TempDir(), + }, + Features: gof3.AllFeatures, + }, + Doer: doer, + }) + giteaLocal.SetContext(context.Background()) + giteaLocal.Forge.Mirror(fixture.GetForge()) + + // + // Step 3: mirror Gitea into F3 + // + adminUsername := "user1" + giteaAPI := f3_forges.NewForgeRootFromDriver(&f3_gitea.Gitea{}, &f3_gitea.Options{ + Options: gof3.Options{ + Configuration: gof3.Configuration{ + URL: setting.AppURL, + Directory: t.TempDir(), + }, + Features: gof3.AllFeatures, + }, + AuthToken: getUserToken(t, adminUsername), + }) + giteaAPI.SetContext(context.Background()) + + f3 := f3_forges.FixtureNewF3Forge(t, nil) + f3.Forge.Mirror(giteaAPI.Forge) + + // + // Step 4: verify the fixture and F3 are equivalent + // + }) +}