From a71392c6aad72f90c7243c92b8ce112c4a94da81 Mon Sep 17 00:00:00 2001 From: limiting-factor Date: Tue, 13 Jan 2026 16:59:56 +0100 Subject: [PATCH] chore: update gof3/v3 v3.11.15 (#10673) Update the Forgejo driver for gof3 with modifications for non-backward compatible changes. The changes are isolated behind the f3.Enable flag and not yet functional. The purpose of this upgrade is to not drift from the gof3 implementation while the work continues. The `fix: include remote users when counting users` commit is a functional change to Forgejo itself but does not change the behavior because the remote users are only created in fixtures or by F3. https://codeberg.org/forgejo/forgejo/src/commit/59c721d26b1a01e6e6ca812b63066a33e7e5e4da/models/user/user.go#L65-L66 Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/10673 Reviewed-by: Gusted Co-authored-by: limiting-factor Co-committed-by: limiting-factor --- cmd/forgejo/f3.go | 7 ++- custom/conf/app.example.ini | 2 +- go.mod | 6 +- go.sum | 8 +-- models/user/user.go | 2 +- modules/setting/f3.go | 17 +++++- modules/setting/f3_test.go | 74 ++++++++++++++++++++++++ services/f3/driver/attachment.go | 11 ++-- services/f3/driver/attachments.go | 15 ++--- services/f3/driver/comment.go | 13 ++++- services/f3/driver/comments.go | 18 ++++-- services/f3/driver/common.go | 10 ++-- services/f3/driver/forge.go | 9 ++- services/f3/driver/issue.go | 8 +-- services/f3/driver/issues.go | 10 ++-- services/f3/driver/labels.go | 10 ++-- services/f3/driver/main_test.go | 5 ++ services/f3/driver/milestones.go | 10 ++-- services/f3/driver/organizations.go | 19 ++++-- services/f3/driver/projects.go | 16 +++-- services/f3/driver/pullrequest.go | 14 ++--- services/f3/driver/pullrequests.go | 10 ++-- services/f3/driver/reaction.go | 11 ++-- services/f3/driver/reactions.go | 19 +++--- services/f3/driver/release.go | 2 +- services/f3/driver/releases.go | 10 ++-- services/f3/driver/repositories.go | 14 ++--- services/f3/driver/repository.go | 8 ++- services/f3/driver/review.go | 4 +- services/f3/driver/reviewcomment.go | 2 +- services/f3/driver/reviewcomments.go | 10 ++-- services/f3/driver/reviews.go | 12 ++-- services/f3/driver/tests/options.go | 3 +- services/f3/driver/topics.go | 8 +-- services/f3/driver/tree.go | 62 ++++++++++---------- services/f3/driver/user.go | 22 ++++++- services/f3/driver/users.go | 19 ++++-- tests/integration/api_nodeinfo_test.go | 2 +- tests/integration/cmd_forgejo_f3_test.go | 40 +++++-------- 39 files changed, 348 insertions(+), 194 deletions(-) create mode 100644 modules/setting/f3_test.go diff --git a/cmd/forgejo/f3.go b/cmd/forgejo/f3.go index c4aafeac58..2d1b617e46 100644 --- a/cmd/forgejo/f3.go +++ b/cmd/forgejo/f3.go @@ -24,7 +24,6 @@ import ( ) func CmdF3(ctx context.Context) *cli.Command { - ctx = f3_logger.ContextSetLogger(ctx, util.NewF3Logger(nil, log.GetLogger(log.DEFAULT))) return &cli.Command{ Name: "f3", Usage: "F3", @@ -38,7 +37,9 @@ func SubcmdF3Mirror(ctx context.Context) *cli.Command { mirrorCmd := f3_cmd.CreateCmdMirror() mirrorCmd.Before = prepareWorkPathAndCustomConf(ctx) f3Action := mirrorCmd.Action - mirrorCmd.Action = func(ctx context.Context, cli *cli.Command) error { return runMirror(ctx, cli, f3Action) } + mirrorCmd.Action = func(ctx context.Context, cli *cli.Command) error { + return runMirror(ctx, cli, f3Action) + } return mirrorCmd } @@ -67,6 +68,8 @@ func runMirror(ctx context.Context, c *cli.Command, action cli.ActionFunc) error if err := models.Init(ctx); err != nil { return err } + + ctx = f3_logger.ContextSetLogger(ctx, util.NewF3Logger(nil, log.GetLogger(log.DEFAULT))) } err := action(ctx, c) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index f9c7a666ce..01d02700b2 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -2552,7 +2552,7 @@ LEVEL = Info ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;[F3] +;[f3] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; diff --git a/go.mod b/go.mod index 73bd2fb3ef..2c1303e9a0 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.25.0 toolchain go1.25.5 require ( - code.forgejo.org/f3/gof3/v3 v3.11.1 + code.forgejo.org/f3/gof3/v3 v3.11.15 code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251 code.forgejo.org/forgejo/actions-proto v0.6.0 code.forgejo.org/forgejo/go-rpmutils v1.0.0 @@ -63,7 +63,7 @@ require ( github.com/google/uuid v1.6.0 github.com/gorilla/feeds v1.2.0 github.com/gorilla/sessions v1.4.0 - github.com/hashicorp/go-version v1.7.0 + github.com/hashicorp/go-version v1.8.0 github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/huandu/xstrings v1.5.0 github.com/inbucket/html2text v0.9.0 @@ -94,7 +94,7 @@ require ( github.com/stretchr/testify v1.11.1 github.com/syndtr/goleveldb v1.0.0 github.com/ulikunitz/xz v0.5.15 - github.com/urfave/cli/v3 v3.5.0 + github.com/urfave/cli/v3 v3.6.1 github.com/valyala/fastjson v1.6.7 github.com/yohcop/openid-go v1.0.1 github.com/yuin/goldmark v1.7.16 diff --git a/go.sum b/go.sum index 8374c80201..1102d28d07 100644 --- a/go.sum +++ b/go.sum @@ -16,8 +16,8 @@ cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2k cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -code.forgejo.org/f3/gof3/v3 v3.11.1 h1:c0vE8XvqpbXuSv8gzttn96k5T2FQi0u9bYnux46qSAs= -code.forgejo.org/f3/gof3/v3 v3.11.1/go.mod h1:1p2UKrqZiwxKneQF2DKrMnc403YIgR/lfcfvadZtmDs= +code.forgejo.org/f3/gof3/v3 v3.11.15 h1:/EzJWRQUhVVia1EmCWRZHCuW8qdAX1DEXY0M1n0mECc= +code.forgejo.org/f3/gof3/v3 v3.11.15/go.mod h1:k99wl7QiI9LjS3qEd1RXLdcZPE3wZP5gkVhy8/WhzJ4= code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251 h1:HTZl3CBk3ABNYtFI6TPLvJgGKFIhKT5CBk0sbOtkDKU= code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:PphB88CPbx601QrWPMZATeorACeVmQlyv3u+uUMbSaM= code.forgejo.org/forgejo/actions-proto v0.6.0 h1:dw1Dogk9A4V/yrLVkhe9dSZPsqNAIkI1kCXPSqG3tZA= @@ -660,8 +660,8 @@ github.com/tinylib/msgp v1.3.0/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57 github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/urfave/cli/v3 v3.5.0 h1:qCuFMmdayTF3zmjG8TSsoBzrDqszNrklYg2x3g4MSgw= -github.com/urfave/cli/v3 v3.5.0/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= +github.com/urfave/cli/v3 v3.6.1 h1:j8Qq8NyUawj/7rTYdBGrxcH7A/j7/G8Q5LhWEW4G3Mo= +github.com/urfave/cli/v3 v3.6.1/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= github.com/valyala/fastjson v1.6.7 h1:ZE4tRy0CIkh+qDc5McjatheGX2czdn8slQjomexVpBM= github.com/valyala/fastjson v1.6.7/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= diff --git a/models/user/user.go b/models/user/user.go index f871284890..c78d396f39 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -888,7 +888,7 @@ func CountUsers(ctx context.Context, opts *CountUserFilter) int64 { func countUsers(ctx context.Context, opts *CountUserFilter) int64 { sess := db.GetEngine(ctx) cond := builder.NewCond() - cond = cond.And(builder.Eq{"type": UserTypeIndividual}) + cond = cond.And(builder.In("type", UserTypeIndividual, UserTypeRemoteUser)) if opts != nil { if opts.LastLoginSince != nil { diff --git a/modules/setting/f3.go b/modules/setting/f3.go index 31d12294b8..2412938a49 100644 --- a/modules/setting/f3.go +++ b/modules/setting/f3.go @@ -3,6 +3,9 @@ package setting import ( + "os" + "path/filepath" + "forgejo.org/modules/log" ) @@ -10,8 +13,10 @@ import ( var ( F3 = struct { Enabled bool + Path string }{ Enabled: false, + Path: "f3", } ) @@ -20,7 +25,17 @@ func LoadF3Setting() { } func loadF3From(rootCfg ConfigProvider) { - if err := rootCfg.Section("F3").MapTo(&F3); err != nil { + if err := rootCfg.Section("f3").MapTo(&F3); err != nil { log.Fatal("Failed to map F3 settings: %v", err) } + + if !filepath.IsAbs(F3.Path) { + F3.Path = filepath.Join(AppDataPath, F3.Path) + } else { + F3.Path = filepath.Clean(F3.Path) + } + + if err := os.MkdirAll(F3.Path, os.ModePerm); err != nil { + log.Fatal("Failed to create F3 path %s: %v", F3.Path, err) + } } diff --git a/modules/setting/f3_test.go b/modules/setting/f3_test.go new file mode 100644 index 0000000000..76c4fe015c --- /dev/null +++ b/modules/setting/f3_test.go @@ -0,0 +1,74 @@ +// Copyright 2024 The Forgejo Authors. +// SPDX-License-Identifier: GPLv3-or-later + +package setting + +import ( + "fmt" + "testing" + + "forgejo.org/modules/test" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestSettingF3(t *testing.T) { + restoreF3 := test.MockProtect(&F3) + restoreAppDataPath := test.MockProtect(&AppDataPath) + restore := func() { + restoreF3() + restoreAppDataPath() + } + defer restore() + + t.Run("enabled", func(t *testing.T) { + restore() + cfg, err := NewConfigProviderFromData(` +[f3] +ENABLED = true +`) + require.NoError(t, err) + loadF3From(cfg) + assert.True(t, F3.Enabled) + assert.DirExists(t, F3.Path) + }) + + t.Run("disabled by default", func(t *testing.T) { + restore() + cfg, err := NewConfigProviderFromData(` +[f3] +`) + require.NoError(t, err) + loadF3From(cfg) + assert.False(t, F3.Enabled) + }) + + t.Run("default f3 path", func(t *testing.T) { + restore() + cfg, err := NewConfigProviderFromData(` +[f3] +ENABLED = true +`) + require.NoError(t, err) + AppDataPath = t.TempDir() + loadF3From(cfg) + assert.Equal(t, AppDataPath+"/f3", F3.Path) + assert.DirExists(t, F3.Path) + }) + + t.Run("absolute f3 path", func(t *testing.T) { + restore() + other := t.TempDir() + cfg, err := NewConfigProviderFromData(fmt.Sprintf(` +[f3] +ENABLED = true +PATH = %[1]s +`, other)) + require.NoError(t, err) + AppDataPath = t.TempDir() + loadF3From(cfg) + assert.Equal(t, other, F3.Path) + assert.DirExists(t, F3.Path) + }) +} diff --git a/services/f3/driver/attachment.go b/services/f3/driver/attachment.go index 298119664a..7d0bb7d733 100644 --- a/services/f3/driver/attachment.go +++ b/services/f3/driver/attachment.go @@ -21,8 +21,9 @@ import ( "code.forgejo.org/f3/gof3/v3/f3" f3_id "code.forgejo.org/f3/gof3/v3/id" + f3_kind "code.forgejo.org/f3/gof3/v3/kind" f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3" - "code.forgejo.org/f3/gof3/v3/tree/generic" + f3_tree_generic "code.forgejo.org/f3/gof3/v3/tree/generic" f3_util "code.forgejo.org/f3/gof3/v3/util" "github.com/google/uuid" ) @@ -145,11 +146,11 @@ func (o *attachment) Put(ctx context.Context) f3_id.NodeID { attachableID := f3_tree.GetAttachableID(o.GetNode()) switch attachable.GetKind() { - case f3_tree.KindRelease: + case f3_kind.KindRelease: o.forgejoAttachment.ReleaseID = attachableID - case f3_tree.KindComment: + case f3_kind.KindComment: o.forgejoAttachment.CommentID = attachableID - case f3_tree.KindIssue, f3_tree.KindPullRequest: + case f3_kind.KindIssue, f3_kind.KindPullRequest: o.forgejoAttachment.IssueID = attachableID default: panic(fmt.Errorf("unexpected type %s", attachable.GetKind())) @@ -180,6 +181,6 @@ func (o *attachment) Delete(ctx context.Context) { } } -func newAttachment() generic.NodeDriverInterface { +func newAttachment() f3_tree_generic.NodeDriverInterface { return &attachment{} } diff --git a/services/f3/driver/attachments.go b/services/f3/driver/attachments.go index 392afda52c..5b9880683f 100644 --- a/services/f3/driver/attachments.go +++ b/services/f3/driver/attachments.go @@ -11,17 +11,18 @@ import ( issues_model "forgejo.org/models/issues" repo_model "forgejo.org/models/repo" + f3_kind "code.forgejo.org/f3/gof3/v3/kind" f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3" - "code.forgejo.org/f3/gof3/v3/tree/generic" + f3_tree_generic "code.forgejo.org/f3/gof3/v3/tree/generic" ) type attachments struct { container } -func (o *attachments) ListPage(ctx context.Context, page int) generic.ChildrenSlice { +func (o *attachments) ListPage(ctx context.Context, node f3_tree_generic.NodeInterface, _ f3_tree_generic.ListOptions, page int) f3_tree_generic.ChildrenList { if page > 1 { - return generic.NewChildrenSlice(0) + return f3_tree_generic.NewChildrenList(0) } attachable := f3_tree.GetAttachable(o.GetNode()) @@ -30,7 +31,7 @@ func (o *attachments) ListPage(ctx context.Context, page int) generic.ChildrenSl var attachments []*repo_model.Attachment switch attachable.GetKind() { - case f3_tree.KindRelease: + case f3_kind.KindRelease: release, err := repo_model.GetReleaseByID(ctx, attachableID) if err != nil { panic(fmt.Errorf("GetReleaseByID %v %w", attachableID, err)) @@ -42,7 +43,7 @@ func (o *attachments) ListPage(ctx context.Context, page int) generic.ChildrenSl attachments = release.Attachments - case f3_tree.KindComment: + case f3_kind.KindComment: comment, err := issues_model.GetCommentByID(ctx, attachableID) if err != nil { panic(fmt.Errorf("GetCommentByID %v %w", attachableID, err)) @@ -54,7 +55,7 @@ func (o *attachments) ListPage(ctx context.Context, page int) generic.ChildrenSl attachments = comment.Attachments - case f3_tree.KindIssue, f3_tree.KindPullRequest: + case f3_kind.KindIssue, f3_kind.KindPullRequest: repoID := f3_tree.GetProjectID(o.GetNode()) issue, err := issues_model.GetIssueByIndex(ctx, repoID, attachableID) if err != nil { @@ -74,6 +75,6 @@ func (o *attachments) ListPage(ctx context.Context, page int) generic.ChildrenSl return f3_tree.ConvertListed(ctx, o.GetNode(), f3_tree.ConvertToAny(attachments...)...) } -func newAttachments() generic.NodeDriverInterface { +func newAttachments() f3_tree_generic.NodeDriverInterface { return &attachments{} } diff --git a/services/f3/driver/comment.go b/services/f3/driver/comment.go index bd924930b5..cdb08247e1 100644 --- a/services/f3/driver/comment.go +++ b/services/f3/driver/comment.go @@ -47,7 +47,7 @@ func (o *comment) ToFormat() f3.Interface { } return &f3.Comment{ Common: f3.NewCommon(fmt.Sprintf("%d", o.forgejoComment.ID)), - PosterID: f3_tree.NewUserReference(o.forgejoComment.Poster.ID), + PosterID: f3_tree.NewUserReference(f3_util.ToString(o.forgejoComment.Poster.ID)), Content: o.forgejoComment.Content, Created: o.forgejoComment.CreatedUnix.AsTime(), Updated: o.forgejoComment.UpdatedUnix.AsTime(), @@ -59,6 +59,7 @@ func (o *comment) FromFormat(content f3.Interface) { o.forgejoComment = &issues_model.Comment{ ID: f3_util.ParseInt(comment.GetID()), + Type: issues_model.CommentTypeComment, PosterID: comment.PosterID.GetIDAsInt(), Poster: &user_model.User{ ID: comment.PosterID.GetIDAsInt(), @@ -98,7 +99,15 @@ func (o *comment) Patch(ctx context.Context) { func (o *comment) Put(ctx context.Context) f3_id.NodeID { node := o.GetNode() - o.Trace("%s", node.GetID()) + + issueIndex := f3_tree.GetCommentableID(node) + repositoryID := f3_tree.GetProjectID(node) + + issue, err := issues_model.GetIssueByIndex(ctx, repositoryID, issueIndex) + if issues_model.IsErrIssueNotExist(err) { + panic(fmt.Errorf("issue index %d not found in repository id %d", issueIndex, repositoryID)) + } + o.forgejoComment.IssueID = issue.ID sess := db.GetEngine(ctx) diff --git a/services/f3/driver/comments.go b/services/f3/driver/comments.go index d8c84e290c..a0763240ed 100644 --- a/services/f3/driver/comments.go +++ b/services/f3/driver/comments.go @@ -12,18 +12,18 @@ import ( issues_model "forgejo.org/models/issues" f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3" - "code.forgejo.org/f3/gof3/v3/tree/generic" + f3_tree_generic "code.forgejo.org/f3/gof3/v3/tree/generic" ) type comments struct { container } -func (o *comments) ListPage(ctx context.Context, page int) generic.ChildrenSlice { +func (o *comments) ListPage(ctx context.Context, node f3_tree_generic.NodeInterface, _ f3_tree_generic.ListOptions, page int) f3_tree_generic.ChildrenList { pageSize := o.getPageSize() - project := f3_tree.GetProjectID(o.GetNode()) - commentable := f3_tree.GetCommentableID(o.GetNode()) + project := f3_tree.GetProjectID(node) + commentable := f3_tree.GetCommentableID(node) issue, err := issues_model.GetIssueByIndex(ctx, project, commentable) if err != nil { @@ -41,9 +41,15 @@ func (o *comments) ListPage(ctx context.Context, page int) generic.ChildrenSlice panic(fmt.Errorf("error while listing comments: %v", err)) } - return f3_tree.ConvertListed(ctx, o.GetNode(), f3_tree.ConvertToAny(forgejoComments...)...) + for _, forgejoComment := range forgejoComments { + if err := forgejoComment.LoadPoster(ctx); err != nil { + panic(fmt.Errorf("LoadPoster %+v %w", *forgejoComment, err)) + } + } + + return f3_tree.ConvertListed(ctx, node, f3_tree.ConvertToAny(forgejoComments...)...) } -func newComments() generic.NodeDriverInterface { +func newComments() f3_tree_generic.NodeDriverInterface { return &comments{} } diff --git a/services/f3/driver/common.go b/services/f3/driver/common.go index 4c5dfd8b1a..8ce6bd25b4 100644 --- a/services/f3/driver/common.go +++ b/services/f3/driver/common.go @@ -8,19 +8,19 @@ import ( "context" f3_kind "code.forgejo.org/f3/gof3/v3/kind" - "code.forgejo.org/f3/gof3/v3/tree/generic" + f3_tree_generic "code.forgejo.org/f3/gof3/v3/tree/generic" ) type common struct { - generic.NullDriver + f3_tree_generic.NullDriver } func (o *common) GetHelper() any { panic("not implemented") } -func (o *common) ListPage(ctx context.Context, page int) generic.ChildrenSlice { - return generic.NewChildrenSlice(0) +func (o *common) ListPage(ctx context.Context, node f3_tree_generic.NodeInterface, _ f3_tree_generic.ListOptions, page int) f3_tree_generic.ChildrenList { + return f3_tree_generic.NewChildrenList(0) } func (o *common) GetNativeID() string { @@ -30,7 +30,7 @@ func (o *common) GetNativeID() string { func (o *common) SetNative(native any) { } -func (o *common) getTree() generic.TreeInterface { +func (o *common) getTree() f3_tree_generic.TreeInterface { return o.GetNode().GetTree() } diff --git a/services/f3/driver/forge.go b/services/f3/driver/forge.go index 03acb41450..0910666877 100644 --- a/services/f3/driver/forge.go +++ b/services/f3/driver/forge.go @@ -13,7 +13,6 @@ import ( "code.forgejo.org/f3/gof3/v3/f3" f3_id "code.forgejo.org/f3/gof3/v3/id" f3_kind "code.forgejo.org/f3/gof3/v3/kind" - f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3" "code.forgejo.org/f3/gof3/v3/tree/generic" "code.forgejo.org/f3/gof3/v3/util" ) @@ -37,17 +36,17 @@ func (o *forge) getOwnersKind(ctx context.Context, id string) f3_kind.Kind { if err != nil { panic(fmt.Errorf("user_repo.GetUserByID: %w", err)) } - kind = f3_tree.KindUsers + kind = f3_kind.KindUsers if user.IsOrganization() { - kind = f3_tree.KindOrganization + kind = f3_kind.KindOrganization } o.ownersKind[id] = kind } return kind } -func (o *forge) getOwnersPath(ctx context.Context, id string) f3_tree.Path { - return f3_tree.NewPathFromString("/").SetForge().SetOwners(o.getOwnersKind(ctx, id)) +func (o *forge) getOwnersPath(ctx context.Context, id string) generic.Path { + return generic.NewNodePathFromString("/").SetForge().SetOwners(o.getOwnersKind(ctx, id)) } func (o *forge) Equals(context.Context, generic.NodeInterface) bool { return true } diff --git a/services/f3/driver/issue.go b/services/f3/driver/issue.go index 6308c4cc2d..3869a53e8f 100644 --- a/services/f3/driver/issue.go +++ b/services/f3/driver/issue.go @@ -51,23 +51,23 @@ func (o *issue) ToFormat() f3.Interface { milestone := &f3.Reference{} if o.forgejoIssue.Milestone != nil { - milestone = f3_tree.NewIssueMilestoneReference(o.forgejoIssue.Milestone.ID) + milestone = f3_tree.NewIssueMilestoneReference(f3_util.ToString(o.forgejoIssue.Milestone.ID)) } assignees := make([]*f3.Reference, 0, len(o.forgejoIssue.Assignees)) for _, assignee := range o.forgejoIssue.Assignees { - assignees = append(assignees, f3_tree.NewUserReference(assignee.ID)) + assignees = append(assignees, f3_tree.NewUserReference(f3_util.ToString(assignee.ID))) } labels := make([]*f3.Reference, 0, len(o.forgejoIssue.Labels)) for _, label := range o.forgejoIssue.Labels { - labels = append(labels, f3_tree.NewIssueLabelReference(label.ID)) + labels = append(labels, f3_tree.NewIssueLabelReference(f3_util.ToString(label.ID))) } return &f3.Issue{ Title: o.forgejoIssue.Title, Common: f3.NewCommon(o.GetNativeID()), - PosterID: f3_tree.NewUserReference(o.forgejoIssue.Poster.ID), + PosterID: f3_tree.NewUserReference(f3_util.ToString(o.forgejoIssue.Poster.ID)), Assignees: assignees, Labels: labels, Content: o.forgejoIssue.Content, diff --git a/services/f3/driver/issues.go b/services/f3/driver/issues.go index dd6828dc86..9442a09d59 100644 --- a/services/f3/driver/issues.go +++ b/services/f3/driver/issues.go @@ -12,17 +12,17 @@ import ( issues_model "forgejo.org/models/issues" f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3" - "code.forgejo.org/f3/gof3/v3/tree/generic" + f3_tree_generic "code.forgejo.org/f3/gof3/v3/tree/generic" ) type issues struct { container } -func (o *issues) ListPage(ctx context.Context, page int) generic.ChildrenSlice { +func (o *issues) ListPage(ctx context.Context, node f3_tree_generic.NodeInterface, _ f3_tree_generic.ListOptions, page int) f3_tree_generic.ChildrenList { pageSize := o.getPageSize() - project := f3_tree.GetProjectID(o.GetNode()) + project := f3_tree.GetProjectID(node) forgejoIssues, err := issues_model.Issues(ctx, &issues_model.IssuesOptions{ Paginator: &db.ListOptions{Page: page, PageSize: pageSize}, @@ -32,9 +32,9 @@ func (o *issues) ListPage(ctx context.Context, page int) generic.ChildrenSlice { panic(fmt.Errorf("error while listing issues: %v", err)) } - return f3_tree.ConvertListed(ctx, o.GetNode(), f3_tree.ConvertToAny(forgejoIssues...)...) + return f3_tree.ConvertListed(ctx, node, f3_tree.ConvertToAny(forgejoIssues...)...) } -func newIssues() generic.NodeDriverInterface { +func newIssues() f3_tree_generic.NodeDriverInterface { return &issues{} } diff --git a/services/f3/driver/labels.go b/services/f3/driver/labels.go index 4f705ed206..a86e1f686a 100644 --- a/services/f3/driver/labels.go +++ b/services/f3/driver/labels.go @@ -12,26 +12,26 @@ import ( issues_model "forgejo.org/models/issues" f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3" - "code.forgejo.org/f3/gof3/v3/tree/generic" + f3_tree_generic "code.forgejo.org/f3/gof3/v3/tree/generic" ) type labels struct { container } -func (o *labels) ListPage(ctx context.Context, page int) generic.ChildrenSlice { +func (o *labels) ListPage(ctx context.Context, node f3_tree_generic.NodeInterface, _ f3_tree_generic.ListOptions, page int) f3_tree_generic.ChildrenList { pageSize := o.getPageSize() - project := f3_tree.GetProjectID(o.GetNode()) + project := f3_tree.GetProjectID(node) forgejoLabels, err := issues_model.GetLabelsByRepoID(ctx, project, "", db.ListOptions{Page: page, PageSize: pageSize}) if err != nil { panic(fmt.Errorf("error while listing labels: %v", err)) } - return f3_tree.ConvertListed(ctx, o.GetNode(), f3_tree.ConvertToAny(forgejoLabels...)...) + return f3_tree.ConvertListed(ctx, node, f3_tree.ConvertToAny(forgejoLabels...)...) } -func newLabels() generic.NodeDriverInterface { +func newLabels() f3_tree_generic.NodeDriverInterface { return &labels{} } diff --git a/services/f3/driver/main_test.go b/services/f3/driver/main_test.go index 838baa760b..69ef829599 100644 --- a/services/f3/driver/main_test.go +++ b/services/f3/driver/main_test.go @@ -8,6 +8,7 @@ import ( "testing" "forgejo.org/models/unittest" + "forgejo.org/modules/log" "forgejo.org/modules/setting" "forgejo.org/modules/test" driver_options "forgejo.org/services/f3/driver/options" @@ -25,6 +26,10 @@ import ( func TestF3(t *testing.T) { require.NoError(t, unittest.PrepareTestDatabase()) defer test.MockVariableValue(&setting.SSH.RootPath, t.TempDir())() + log.SetConsoleLogger(log.DEFAULT, "console", log.TRACE) + defer func() { + log.SetConsoleLogger(log.DEFAULT, "console", log.INFO) + }() tests_f3.ForgeCompliance(t, driver_options.Name) } diff --git a/services/f3/driver/milestones.go b/services/f3/driver/milestones.go index cf0b70c158..ad672acbd8 100644 --- a/services/f3/driver/milestones.go +++ b/services/f3/driver/milestones.go @@ -12,17 +12,17 @@ import ( issues_model "forgejo.org/models/issues" f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3" - "code.forgejo.org/f3/gof3/v3/tree/generic" + f3_tree_generic "code.forgejo.org/f3/gof3/v3/tree/generic" ) type milestones struct { container } -func (o *milestones) ListPage(ctx context.Context, page int) generic.ChildrenSlice { +func (o *milestones) ListPage(ctx context.Context, node f3_tree_generic.NodeInterface, _ f3_tree_generic.ListOptions, page int) f3_tree_generic.ChildrenList { pageSize := o.getPageSize() - project := f3_tree.GetProjectID(o.GetNode()) + project := f3_tree.GetProjectID(node) forgejoMilestones, err := db.Find[issues_model.Milestone](ctx, issues_model.FindMilestoneOptions{ ListOptions: db.ListOptions{Page: page, PageSize: pageSize}, @@ -32,9 +32,9 @@ func (o *milestones) ListPage(ctx context.Context, page int) generic.ChildrenSli panic(fmt.Errorf("error while listing milestones: %v", err)) } - return f3_tree.ConvertListed(ctx, o.GetNode(), f3_tree.ConvertToAny(forgejoMilestones...)...) + return f3_tree.ConvertListed(ctx, node, f3_tree.ConvertToAny(forgejoMilestones...)...) } -func newMilestones() generic.NodeDriverInterface { +func newMilestones() f3_tree_generic.NodeDriverInterface { return &milestones{} } diff --git a/services/f3/driver/organizations.go b/services/f3/driver/organizations.go index eca6bfb9d4..b557ad8337 100644 --- a/services/f3/driver/organizations.go +++ b/services/f3/driver/organizations.go @@ -12,16 +12,17 @@ import ( org_model "forgejo.org/models/organization" user_model "forgejo.org/models/user" + "code.forgejo.org/f3/gof3/v3/f3" f3_id "code.forgejo.org/f3/gof3/v3/id" f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3" - "code.forgejo.org/f3/gof3/v3/tree/generic" + f3_tree_generic "code.forgejo.org/f3/gof3/v3/tree/generic" ) type organizations struct { container } -func (o *organizations) ListPage(ctx context.Context, page int) generic.ChildrenSlice { +func (o *organizations) ListPage(ctx context.Context, node f3_tree_generic.NodeInterface, _ f3_tree_generic.ListOptions, page int) f3_tree_generic.ChildrenList { sess := db.GetEngine(ctx) if page != 0 { sess = db.SetSessionPagination(sess, &db.ListOptions{Page: page, PageSize: o.getPageSize()}) @@ -34,18 +35,26 @@ func (o *organizations) ListPage(ctx context.Context, page int) generic.Children panic(fmt.Errorf("error while listing organizations: %v", err)) } - return f3_tree.ConvertListed(ctx, o.GetNode(), f3_tree.ConvertToAny(organizations...)...) + return f3_tree.ConvertListed(ctx, node, f3_tree.ConvertToAny(organizations...)...) +} + +func (o *organizations) LookupMappedID(ctx context.Context, id f3_id.NodeID, f f3.Interface) f3_id.NodeID { + organization := f.(*f3.Organization) + return o.GetIDFromName(ctx, organization.Name) } func (o *organizations) GetIDFromName(ctx context.Context, name string) f3_id.NodeID { organization, err := org_model.GetOrgByName(ctx, name) + if org_model.IsErrOrgNotExist(err) { + return f3_id.NilID + } if err != nil { - panic(fmt.Errorf("GetOrganizationByName: %v", err)) + panic(fmt.Errorf("GetOrgByName(%s): %v", name, err)) } return f3_id.NewNodeID(organization.ID) } -func newOrganizations() generic.NodeDriverInterface { +func newOrganizations() f3_tree_generic.NodeDriverInterface { return &organizations{} } diff --git a/services/f3/driver/projects.go b/services/f3/driver/projects.go index 0c76854f43..071dd000dc 100644 --- a/services/f3/driver/projects.go +++ b/services/f3/driver/projects.go @@ -11,15 +11,21 @@ import ( "forgejo.org/models/db" repo_model "forgejo.org/models/repo" + "code.forgejo.org/f3/gof3/v3/f3" f3_id "code.forgejo.org/f3/gof3/v3/id" f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3" - "code.forgejo.org/f3/gof3/v3/tree/generic" + f3_tree_generic "code.forgejo.org/f3/gof3/v3/tree/generic" ) type projects struct { container } +func (o *projects) LookupMappedID(ctx context.Context, id f3_id.NodeID, f f3.Interface) f3_id.NodeID { + project := f.(*f3.Project) + return o.GetIDFromName(ctx, project.Name) +} + func (o *projects) GetIDFromName(ctx context.Context, name string) f3_id.NodeID { owner := f3_tree.GetOwnerName(o.GetNode()) forgejoProject, err := repo_model.GetRepositoryByOwnerAndName(ctx, owner, name) @@ -34,10 +40,10 @@ func (o *projects) GetIDFromName(ctx context.Context, name string) f3_id.NodeID return f3_id.NewNodeID(forgejoProject.ID) } -func (o *projects) ListPage(ctx context.Context, page int) generic.ChildrenSlice { +func (o *projects) ListPage(ctx context.Context, node f3_tree_generic.NodeInterface, _ f3_tree_generic.ListOptions, page int) f3_tree_generic.ChildrenList { pageSize := o.getPageSize() - owner := f3_tree.GetOwner(o.GetNode()) + owner := f3_tree.GetOwner(node) forgejoProjects, _, err := repo_model.SearchRepository(ctx, &repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{Page: page, PageSize: pageSize}, @@ -48,9 +54,9 @@ func (o *projects) ListPage(ctx context.Context, page int) generic.ChildrenSlice panic(fmt.Errorf("error while listing projects: %v", err)) } - return f3_tree.ConvertListed(ctx, o.GetNode(), f3_tree.ConvertToAny(forgejoProjects...)...) + return f3_tree.ConvertListed(ctx, node, f3_tree.ConvertToAny(forgejoProjects...)...) } -func newProjects() generic.NodeDriverInterface { +func newProjects() f3_tree_generic.NodeDriverInterface { return &projects{} } diff --git a/services/f3/driver/pullrequest.go b/services/f3/driver/pullrequest.go index 664ee6b13b..3300042895 100644 --- a/services/f3/driver/pullrequest.go +++ b/services/f3/driver/pullrequest.go @@ -19,7 +19,7 @@ import ( "code.forgejo.org/f3/gof3/v3/f3" f3_id "code.forgejo.org/f3/gof3/v3/id" - f3_path "code.forgejo.org/f3/gof3/v3/path" + f3_kind "code.forgejo.org/f3/gof3/v3/kind" f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3" "code.forgejo.org/f3/gof3/v3/tree/generic" f3_util "code.forgejo.org/f3/gof3/v3/util" @@ -53,17 +53,17 @@ func (o *pullRequest) repositoryToReference(ctx context.Context, repository *rep if repository == nil { panic("unexpected nil repository") } - forge := o.getTree().GetRoot().GetChild(f3_id.NewNodeID(f3_tree.KindForge)).GetDriver().(*forge) + forge := o.getTree().GetRoot().GetChild(f3_id.NewNodeID(f3_kind.KindForge)).GetDriver().(*forge) owners := forge.getOwnersPath(ctx, fmt.Sprintf("%d", repository.OwnerID)) - return f3_tree.NewRepositoryReference(owners.String(), repository.OwnerID, repository.ID) + return f3_tree.NewRepositoryReference(owners.String(), f3_util.ToString(repository.OwnerID), f3_util.ToString(repository.ID), f3.RepositoryNameDefault) } func (o *pullRequest) referenceToRepository(reference *f3.Reference) int64 { var project int64 - if reference.Get() == "../../repository/vcs" { + if reference.Get() == "../../repositories/vcs" { project = f3_tree.GetProjectID(o.GetNode()) } else { - p := f3_tree.ToPath(f3_path.PathAbsolute(generic.NewElementNode, o.GetNode().GetCurrentPath().String(), reference.Get())) + p := generic.PathAbsolute(generic.NewNode, o.GetNode().GetCurrentPath().String(), reference.Get()) o.Trace("%v %v", o.GetNode().GetCurrentPath().String(), p) _, project = p.OwnerAndProjectID() } @@ -77,7 +77,7 @@ func (o *pullRequest) ToFormat() f3.Interface { var milestone *f3.Reference if o.forgejoPullRequest.Milestone != nil { - milestone = f3_tree.NewIssueMilestoneReference(o.forgejoPullRequest.Milestone.ID) + milestone = f3_tree.NewIssueMilestoneReference(f3_util.ToString(o.forgejoPullRequest.Milestone.ID)) } var mergedTime *time.Time @@ -125,7 +125,7 @@ func (o *pullRequest) ToFormat() f3.Interface { return &f3.PullRequest{ Common: f3.NewCommon(o.GetNativeID()), - PosterID: f3_tree.NewUserReference(o.forgejoPullRequest.Poster.ID), + PosterID: f3_tree.NewUserReference(f3_util.ToString(o.forgejoPullRequest.Poster.ID)), Title: o.forgejoPullRequest.Title, Content: o.forgejoPullRequest.Content, Milestone: milestone, diff --git a/services/f3/driver/pullrequests.go b/services/f3/driver/pullrequests.go index 227171994c..1d88aeb850 100644 --- a/services/f3/driver/pullrequests.go +++ b/services/f3/driver/pullrequests.go @@ -13,17 +13,17 @@ import ( "forgejo.org/modules/optional" f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3" - "code.forgejo.org/f3/gof3/v3/tree/generic" + f3_tree_generic "code.forgejo.org/f3/gof3/v3/tree/generic" ) type pullRequests struct { container } -func (o *pullRequests) ListPage(ctx context.Context, page int) generic.ChildrenSlice { +func (o *pullRequests) ListPage(ctx context.Context, node f3_tree_generic.NodeInterface, _ f3_tree_generic.ListOptions, page int) f3_tree_generic.ChildrenList { pageSize := o.getPageSize() - project := f3_tree.GetProjectID(o.GetNode()) + project := f3_tree.GetProjectID(node) forgejoPullRequests, err := issues_model.Issues(ctx, &issues_model.IssuesOptions{ Paginator: &db.ListOptions{Page: page, PageSize: pageSize}, @@ -34,9 +34,9 @@ func (o *pullRequests) ListPage(ctx context.Context, page int) generic.ChildrenS panic(fmt.Errorf("error while listing pullRequests: %v", err)) } - return f3_tree.ConvertListed(ctx, o.GetNode(), f3_tree.ConvertToAny(forgejoPullRequests...)...) + return f3_tree.ConvertListed(ctx, node, f3_tree.ConvertToAny(forgejoPullRequests...)...) } -func newPullRequests() generic.NodeDriverInterface { +func newPullRequests() f3_tree_generic.NodeDriverInterface { return &pullRequests{} } diff --git a/services/f3/driver/reaction.go b/services/f3/driver/reaction.go index b959206074..bafab55898 100644 --- a/services/f3/driver/reaction.go +++ b/services/f3/driver/reaction.go @@ -14,6 +14,7 @@ import ( "code.forgejo.org/f3/gof3/v3/f3" f3_id "code.forgejo.org/f3/gof3/v3/id" + f3_kind "code.forgejo.org/f3/gof3/v3/kind" f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3" "code.forgejo.org/f3/gof3/v3/tree/generic" f3_util "code.forgejo.org/f3/gof3/v3/util" @@ -46,7 +47,7 @@ func (o *reaction) ToFormat() f3.Interface { } return &f3.Reaction{ Common: f3.NewCommon(fmt.Sprintf("%d", o.forgejoReaction.ID)), - UserID: f3_tree.NewUserReference(o.forgejoReaction.User.ID), + UserID: f3_tree.NewUserReference(f3_util.ToString(o.forgejoReaction.User.ID)), Content: o.forgejoReaction.Type, } } @@ -89,7 +90,7 @@ func (o *reaction) Patch(ctx context.Context) { } func (o *reaction) Put(ctx context.Context) f3_id.NodeID { - o.Trace("%v", o.forgejoReaction.User) + o.Trace("%+v", o.forgejoReaction.User) sess := db.GetEngine(ctx) @@ -97,20 +98,20 @@ func (o *reaction) Put(ctx context.Context) f3_id.NodeID { reactionableID := f3_tree.GetReactionableID(o.GetNode()) switch reactionable.GetKind() { - case f3_tree.KindIssue, f3_tree.KindPullRequest: + case f3_kind.KindIssue, f3_kind.KindPullRequest: project := f3_tree.GetProjectID(o.GetNode()) issue, err := issues_model.GetIssueByIndex(ctx, project, reactionableID) if err != nil { panic(fmt.Errorf("GetIssueByIndex %v %w", reactionableID, err)) } o.forgejoReaction.IssueID = issue.ID - case f3_tree.KindComment: + case f3_kind.KindComment: o.forgejoReaction.CommentID = reactionableID default: panic(fmt.Errorf("unexpected type %v", reactionable.GetKind())) } - o.Trace("%v", o.forgejoReaction) + o.Trace("%+v", o.forgejoReaction) if _, err := sess.Insert(o.forgejoReaction); err != nil { panic(err) diff --git a/services/f3/driver/reactions.go b/services/f3/driver/reactions.go index a546927b92..8e8ff14014 100644 --- a/services/f3/driver/reactions.go +++ b/services/f3/driver/reactions.go @@ -11,8 +11,9 @@ import ( "forgejo.org/models/db" issues_model "forgejo.org/models/issues" + f3_kind "code.forgejo.org/f3/gof3/v3/kind" f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3" - "code.forgejo.org/f3/gof3/v3/tree/generic" + f3_tree_generic "code.forgejo.org/f3/gof3/v3/tree/generic" "xorm.io/builder" ) @@ -20,23 +21,23 @@ type reactions struct { container } -func (o *reactions) ListPage(ctx context.Context, page int) generic.ChildrenSlice { +func (o *reactions) ListPage(ctx context.Context, node f3_tree_generic.NodeInterface, _ f3_tree_generic.ListOptions, page int) f3_tree_generic.ChildrenList { pageSize := o.getPageSize() - reactionable := f3_tree.GetReactionable(o.GetNode()) - reactionableID := f3_tree.GetReactionableID(o.GetNode()) + reactionable := f3_tree.GetReactionable(node) + reactionableID := f3_tree.GetReactionableID(node) sess := db.GetEngine(ctx) cond := builder.NewCond() switch reactionable.GetKind() { - case f3_tree.KindIssue, f3_tree.KindPullRequest: - project := f3_tree.GetProjectID(o.GetNode()) + case f3_kind.KindIssue, f3_kind.KindPullRequest: + project := f3_tree.GetProjectID(node) issue, err := issues_model.GetIssueByIndex(ctx, project, reactionableID) if err != nil { panic(fmt.Errorf("GetIssueByIndex %v %w", reactionableID, err)) } cond = cond.And(builder.Eq{"reaction.issue_id": issue.ID}) - case f3_tree.KindComment: + case f3_kind.KindComment: cond = cond.And(builder.Eq{"reaction.comment_id": reactionableID}) default: panic(fmt.Errorf("unexpected type %v", reactionable.GetKind())) @@ -51,9 +52,9 @@ func (o *reactions) ListPage(ctx context.Context, page int) generic.ChildrenSlic panic(fmt.Errorf("error while listing reactions: %v", err)) } - return f3_tree.ConvertListed(ctx, o.GetNode(), f3_tree.ConvertToAny(reactions...)...) + return f3_tree.ConvertListed(ctx, node, f3_tree.ConvertToAny(reactions...)...) } -func newReactions() generic.NodeDriverInterface { +func newReactions() f3_tree_generic.NodeDriverInterface { return &reactions{} } diff --git a/services/f3/driver/release.go b/services/f3/driver/release.go index df38bd8bc0..e66cd9d026 100644 --- a/services/f3/driver/release.go +++ b/services/f3/driver/release.go @@ -56,7 +56,7 @@ func (o *release) ToFormat() f3.Interface { Body: o.forgejoRelease.Note, Draft: o.forgejoRelease.IsDraft, Prerelease: o.forgejoRelease.IsPrerelease, - PublisherID: f3_tree.NewUserReference(o.forgejoRelease.Publisher.ID), + PublisherID: f3_tree.NewUserReference(f3_util.ToString(o.forgejoRelease.Publisher.ID)), Created: o.forgejoRelease.CreatedUnix.AsTime(), } } diff --git a/services/f3/driver/releases.go b/services/f3/driver/releases.go index a631c0b60e..cea5666071 100644 --- a/services/f3/driver/releases.go +++ b/services/f3/driver/releases.go @@ -12,17 +12,17 @@ import ( repo_model "forgejo.org/models/repo" f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3" - "code.forgejo.org/f3/gof3/v3/tree/generic" + f3_tree_generic "code.forgejo.org/f3/gof3/v3/tree/generic" ) type releases struct { container } -func (o *releases) ListPage(ctx context.Context, page int) generic.ChildrenSlice { +func (o *releases) ListPage(ctx context.Context, node f3_tree_generic.NodeInterface, _ f3_tree_generic.ListOptions, page int) f3_tree_generic.ChildrenList { pageSize := o.getPageSize() - project := f3_tree.GetProjectID(o.GetNode()) + project := f3_tree.GetProjectID(node) forgejoReleases, err := db.Find[repo_model.Release](ctx, repo_model.FindReleasesOptions{ ListOptions: db.ListOptions{Page: page, PageSize: pageSize}, @@ -34,9 +34,9 @@ func (o *releases) ListPage(ctx context.Context, page int) generic.ChildrenSlice panic(fmt.Errorf("error while listing releases: %v", err)) } - return f3_tree.ConvertListed(ctx, o.GetNode(), f3_tree.ConvertToAny(forgejoReleases...)...) + return f3_tree.ConvertListed(ctx, node, f3_tree.ConvertToAny(forgejoReleases...)...) } -func newReleases() generic.NodeDriverInterface { +func newReleases() f3_tree_generic.NodeDriverInterface { return &releases{} } diff --git a/services/f3/driver/repositories.go b/services/f3/driver/repositories.go index 03daf35e58..8e9f9347a3 100644 --- a/services/f3/driver/repositories.go +++ b/services/f3/driver/repositories.go @@ -9,28 +9,28 @@ import ( "code.forgejo.org/f3/gof3/v3/f3" f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3" - "code.forgejo.org/f3/gof3/v3/tree/generic" + f3_tree_generic "code.forgejo.org/f3/gof3/v3/tree/generic" ) type repositories struct { container } -func (o *repositories) ListPage(ctx context.Context, page int) generic.ChildrenSlice { - children := generic.NewChildrenSlice(0) +func (o *repositories) ListPage(ctx context.Context, node f3_tree_generic.NodeInterface, _ f3_tree_generic.ListOptions, page int) f3_tree_generic.ChildrenList { + children := f3_tree_generic.NewChildrenList(0) if page > 1 { return children } names := []string{f3.RepositoryNameDefault} - project := f3_tree.GetProject(o.GetNode()).ToFormat().(*f3.Project) + project := f3_tree.GetProject(node).ToFormat().(*f3.Project) if project.HasWiki { - names = append(names, f3.RepositoryNameWiki) + names = append(names, RepositoryNameWiki) } - return f3_tree.ConvertListed(ctx, o.GetNode(), f3_tree.ConvertToAny(names...)...) + return f3_tree.ConvertListed(ctx, node, f3_tree.ConvertToAny(names...)...) } -func newRepositories() generic.NodeDriverInterface { +func newRepositories() f3_tree_generic.NodeDriverInterface { return &repositories{} } diff --git a/services/f3/driver/repository.go b/services/f3/driver/repository.go index 3cd9aa7f2e..e198fa695e 100644 --- a/services/f3/driver/repository.go +++ b/services/f3/driver/repository.go @@ -76,10 +76,12 @@ func (o *repository) SetFetchFunc(fetchFunc func(ctx context.Context, destinatio o.f.FetchFunc = fetchFunc } +const RepositoryNameWiki = "vcs.wiki" + func (o *repository) getURL() string { owner := f3_tree.GetOwnerName(o.GetNode()) repoName := f3_tree.GetProjectName(o.GetNode()) - if o.f.GetID() == f3.RepositoryNameWiki { + if o.f.GetID() == RepositoryNameWiki { repoName += ".wiki" } return repo_model.RepoPath(owner, repoName) @@ -89,6 +91,10 @@ func (o *repository) GetRepositoryURL() string { return o.getURL() } +func (o *repository) Delete(ctx context.Context) { + o.Trace("ignore attempt to delete repository") +} + func (o *repository) GetRepositoryPushURL() string { return o.getURL() } diff --git a/services/f3/driver/review.go b/services/f3/driver/review.go index f4f5ff44b8..c291482618 100644 --- a/services/f3/driver/review.go +++ b/services/f3/driver/review.go @@ -48,7 +48,7 @@ func (o *review) ToFormat() f3.Interface { review := &f3.Review{ Common: f3.NewCommon(o.GetNativeID()), - ReviewerID: f3_tree.NewUserReference(o.forgejoReview.ReviewerID), + ReviewerID: f3_tree.NewUserReference(f3_util.ToString(o.forgejoReview.ReviewerID)), Official: o.forgejoReview.Official, CommitID: o.forgejoReview.CommitID, Content: o.forgejoReview.Content, @@ -71,7 +71,7 @@ func (o *review) ToFormat() f3.Interface { } if o.forgejoReview.Reviewer != nil { - review.ReviewerID = f3_tree.NewUserReference(o.forgejoReview.Reviewer.ID) + review.ReviewerID = f3_tree.NewUserReference(f3_util.ToString(o.forgejoReview.Reviewer.ID)) } return review diff --git a/services/f3/driver/reviewcomment.go b/services/f3/driver/reviewcomment.go index 22759b6df3..64279d0324 100644 --- a/services/f3/driver/reviewcomment.go +++ b/services/f3/driver/reviewcomment.go @@ -57,7 +57,7 @@ func (o *reviewComment) ToFormat() f3.Interface { return &f3.ReviewComment{ Common: f3.NewCommon(o.GetNativeID()), - PosterID: f3_tree.NewUserReference(o.forgejoReviewComment.Poster.ID), + PosterID: f3_tree.NewUserReference(f3_util.ToString(o.forgejoReviewComment.Poster.ID)), Content: o.forgejoReviewComment.Content, TreePath: o.forgejoReviewComment.TreePath, DiffHunk: patch2diff(o.forgejoReviewComment.PatchQuoted), diff --git a/services/f3/driver/reviewcomments.go b/services/f3/driver/reviewcomments.go index 2aa4dea22c..a9f6f03774 100644 --- a/services/f3/driver/reviewcomments.go +++ b/services/f3/driver/reviewcomments.go @@ -12,17 +12,17 @@ import ( issues_model "forgejo.org/models/issues" f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3" - "code.forgejo.org/f3/gof3/v3/tree/generic" + f3_tree_generic "code.forgejo.org/f3/gof3/v3/tree/generic" ) type reviewComments struct { container } -func (o *reviewComments) ListPage(ctx context.Context, page int) generic.ChildrenSlice { +func (o *reviewComments) ListPage(ctx context.Context, node f3_tree_generic.NodeInterface, _ f3_tree_generic.ListOptions, page int) f3_tree_generic.ChildrenList { pageSize := o.getPageSize() - id := f3_tree.GetReviewID(o.GetNode()) + id := f3_tree.GetReviewID(node) sess := db.GetEngine(ctx). Table("comment"). @@ -35,9 +35,9 @@ func (o *reviewComments) ListPage(ctx context.Context, page int) generic.Childre panic(fmt.Errorf("error while listing reviewComments: %v", err)) } - return f3_tree.ConvertListed(ctx, o.GetNode(), f3_tree.ConvertToAny(forgejoReviewComments...)...) + return f3_tree.ConvertListed(ctx, node, f3_tree.ConvertToAny(forgejoReviewComments...)...) } -func newReviewComments() generic.NodeDriverInterface { +func newReviewComments() f3_tree_generic.NodeDriverInterface { return &reviewComments{} } diff --git a/services/f3/driver/reviews.go b/services/f3/driver/reviews.go index 7c3dcb37de..1a94803862 100644 --- a/services/f3/driver/reviews.go +++ b/services/f3/driver/reviews.go @@ -12,18 +12,18 @@ import ( issues_model "forgejo.org/models/issues" f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3" - "code.forgejo.org/f3/gof3/v3/tree/generic" + f3_tree_generic "code.forgejo.org/f3/gof3/v3/tree/generic" ) type reviews struct { container } -func (o *reviews) ListPage(ctx context.Context, page int) generic.ChildrenSlice { +func (o *reviews) ListPage(ctx context.Context, node f3_tree_generic.NodeInterface, _ f3_tree_generic.ListOptions, page int) f3_tree_generic.ChildrenList { pageSize := o.getPageSize() - project := f3_tree.GetProjectID(o.GetNode()) - pullRequest := f3_tree.GetPullRequestID(o.GetNode()) + project := f3_tree.GetProjectID(node) + pullRequest := f3_tree.GetPullRequestID(node) issue, err := issues_model.GetIssueByIndex(ctx, project, pullRequest) if err != nil { @@ -41,9 +41,9 @@ func (o *reviews) ListPage(ctx context.Context, page int) generic.ChildrenSlice panic(fmt.Errorf("error while listing reviews: %v", err)) } - return f3_tree.ConvertListed(ctx, o.GetNode(), f3_tree.ConvertToAny(forgejoReviews...)...) + return f3_tree.ConvertListed(ctx, node, f3_tree.ConvertToAny(forgejoReviews...)...) } -func newReviews() generic.NodeDriverInterface { +func newReviews() f3_tree_generic.NodeDriverInterface { return &reviews{} } diff --git a/services/f3/driver/tests/options.go b/services/f3/driver/tests/options.go index f61b10c9ef..a3fc199a50 100644 --- a/services/f3/driver/tests/options.go +++ b/services/f3/driver/tests/options.go @@ -16,6 +16,7 @@ import ( func newTestOptions(_ *testing.T) options.Interface { o := options.GetFactory(driver_options.Name)().(*driver_options.Options) - o.SetLogger(util.NewF3Logger(nil, forgejo_log.GetLogger(forgejo_log.DEFAULT))) + l := forgejo_log.GetLogger(forgejo_log.DEFAULT) + o.SetLogger(util.NewF3Logger(nil, l)) return o } diff --git a/services/f3/driver/topics.go b/services/f3/driver/topics.go index 38f03dbd2d..5c2f7753b3 100644 --- a/services/f3/driver/topics.go +++ b/services/f3/driver/topics.go @@ -12,14 +12,14 @@ import ( repo_model "forgejo.org/models/repo" f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3" - "code.forgejo.org/f3/gof3/v3/tree/generic" + f3_tree_generic "code.forgejo.org/f3/gof3/v3/tree/generic" ) type topics struct { container } -func (o *topics) ListPage(ctx context.Context, page int) generic.ChildrenSlice { +func (o *topics) ListPage(ctx context.Context, node f3_tree_generic.NodeInterface, _ f3_tree_generic.ListOptions, page int) f3_tree_generic.ChildrenList { pageSize := o.getPageSize() sess := db.GetEngine(ctx) @@ -33,9 +33,9 @@ func (o *topics) ListPage(ctx context.Context, page int) generic.ChildrenSlice { panic(fmt.Errorf("error while listing topics: %v", err)) } - return f3_tree.ConvertListed(ctx, o.GetNode(), f3_tree.ConvertToAny(topics...)...) + return f3_tree.ConvertListed(ctx, node, f3_tree.ConvertToAny(topics...)...) } -func newTopics() generic.NodeDriverInterface { +func newTopics() f3_tree_generic.NodeDriverInterface { return &topics{} } diff --git a/services/f3/driver/tree.go b/services/f3/driver/tree.go index fe11b15f6e..573f75c457 100644 --- a/services/f3/driver/tree.go +++ b/services/f3/driver/tree.go @@ -27,67 +27,67 @@ func (o *treeDriver) Init() { func (o *treeDriver) Factory(ctx context.Context, kind f3_kind.Kind) generic.NodeDriverInterface { switch kind { - case f3_tree.KindForge: + case f3_kind.KindForge: return newForge() - case f3_tree.KindOrganizations: + case f3_kind.KindOrganizations: return newOrganizations() - case f3_tree.KindOrganization: + case f3_kind.KindOrganization: return newOrganization() - case f3_tree.KindUsers: + case f3_kind.KindUsers: return newUsers() - case f3_tree.KindUser: + case f3_kind.KindUser: return newUser() - case f3_tree.KindProjects: + case f3_kind.KindProjects: return newProjects() - case f3_tree.KindProject: + case f3_kind.KindProject: return newProject() - case f3_tree.KindIssues: + case f3_kind.KindIssues: return newIssues() - case f3_tree.KindIssue: + case f3_kind.KindIssue: return newIssue() - case f3_tree.KindComments: + case f3_kind.KindComments: return newComments() - case f3_tree.KindComment: + case f3_kind.KindComment: return newComment() - case f3_tree.KindAttachments: + case f3_kind.KindAttachments: return newAttachments() - case f3_tree.KindAttachment: + case f3_kind.KindAttachment: return newAttachment() - case f3_tree.KindLabels: + case f3_kind.KindLabels: return newLabels() - case f3_tree.KindLabel: + case f3_kind.KindLabel: return newLabel() - case f3_tree.KindReactions: + case f3_kind.KindReactions: return newReactions() - case f3_tree.KindReaction: + case f3_kind.KindReaction: return newReaction() - case f3_tree.KindReviews: + case f3_kind.KindReviews: return newReviews() - case f3_tree.KindReview: + case f3_kind.KindReview: return newReview() - case f3_tree.KindReviewComments: + case f3_kind.KindReviewComments: return newReviewComments() - case f3_tree.KindReviewComment: + case f3_kind.KindReviewComment: return newReviewComment() - case f3_tree.KindMilestones: + case f3_kind.KindMilestones: return newMilestones() - case f3_tree.KindMilestone: + case f3_kind.KindMilestone: return newMilestone() - case f3_tree.KindPullRequests: + case f3_kind.KindPullRequests: return newPullRequests() - case f3_tree.KindPullRequest: + case f3_kind.KindPullRequest: return newPullRequest() - case f3_tree.KindReleases: + case f3_kind.KindReleases: return newReleases() - case f3_tree.KindRelease: + case f3_kind.KindRelease: return newRelease() - case f3_tree.KindTopics: + case f3_kind.KindTopics: return newTopics() - case f3_tree.KindTopic: + case f3_kind.KindTopic: return newTopic() - case f3_tree.KindRepositories: + case f3_kind.KindRepositories: return newRepositories() - case f3_tree.KindRepository: + case f3_kind.KindRepository: return newRepository(ctx) case f3_kind.KindRoot: return newRoot(o.GetTree().(f3_tree.TreeInterface).NewFormat(kind)) diff --git a/services/f3/driver/user.go b/services/f3/driver/user.go index bf8bfaf9c9..d100234fbc 100644 --- a/services/f3/driver/user.go +++ b/services/f3/driver/user.go @@ -28,6 +28,19 @@ type user struct { forgejoUser *user_model.User } +const fakeEmailSuffix = ".fakeemail" + +func fromFakeEmail(mail string) string { + return strings.TrimSuffix(mail, fakeEmailSuffix) +} + +func toFakeEmail(mail string) string { + if !strings.HasSuffix(mail, fakeEmailSuffix) { + return mail + fakeEmailSuffix + } + return mail +} + func getSystemUserByName(name string) *user_model.User { switch name { case user_model.GhostUserName: @@ -90,6 +103,7 @@ func (o *user) Get(ctx context.Context) bool { if err != nil { panic(fmt.Errorf("user %v %w", id, err)) } + u.Email = fromFakeEmail(u.Email) o.forgejoUser = u return true } @@ -103,7 +117,8 @@ func (o *user) Put(ctx context.Context) f3_id.NodeID { } o.forgejoUser.LowerName = strings.ToLower(o.forgejoUser.Name) - o.Trace("%v", *o.forgejoUser) + o.forgejoUser.Email = toFakeEmail(o.forgejoUser.Email) + o.Trace("%+v", *o.forgejoUser) overwriteDefault := &user_model.CreateUserOverwriteOptions{ IsActive: optional.Some(true), } @@ -119,6 +134,11 @@ func (o *user) Delete(ctx context.Context) { node := o.GetNode() o.Trace("%s", node.GetID()) + if o.forgejoUser.ID == 1 && o.forgejoUser.IsAdmin { + o.Debug("silently ignore a request to delete the admin user with ID 1 because it is assumed to be required: %+v", o.forgejoUser.Type) + return + } + if err := user_service.DeleteUser(ctx, o.forgejoUser, true); err != nil { panic(err) } diff --git a/services/f3/driver/users.go b/services/f3/driver/users.go index cb413ae05d..bee664e42c 100644 --- a/services/f3/driver/users.go +++ b/services/f3/driver/users.go @@ -11,16 +11,17 @@ import ( "forgejo.org/models/db" user_model "forgejo.org/models/user" + "code.forgejo.org/f3/gof3/v3/f3" f3_id "code.forgejo.org/f3/gof3/v3/id" f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3" - "code.forgejo.org/f3/gof3/v3/tree/generic" + f3_tree_generic "code.forgejo.org/f3/gof3/v3/tree/generic" ) type users struct { container } -func (o *users) ListPage(ctx context.Context, page int) generic.ChildrenSlice { +func (o *users) ListPage(ctx context.Context, node f3_tree_generic.NodeInterface, _ f3_tree_generic.ListOptions, page int) f3_tree_generic.ChildrenList { sess := db.GetEngine(ctx).In("type", user_model.UserTypeIndividual, user_model.UserTypeRemoteUser) if page != 0 { sess = db.SetSessionPagination(sess, &db.ListOptions{Page: page, PageSize: o.getPageSize()}) @@ -32,18 +33,26 @@ func (o *users) ListPage(ctx context.Context, page int) generic.ChildrenSlice { panic(fmt.Errorf("error while listing users: %v", err)) } - return f3_tree.ConvertListed(ctx, o.GetNode(), f3_tree.ConvertToAny(users...)...) + return f3_tree.ConvertListed(ctx, node, f3_tree.ConvertToAny(users...)...) +} + +func (o *users) LookupMappedID(ctx context.Context, id f3_id.NodeID, f f3.Interface) f3_id.NodeID { + user := f.(*f3.User) + return o.GetIDFromName(ctx, user.UserName) } func (o *users) GetIDFromName(ctx context.Context, name string) f3_id.NodeID { user, err := user_model.GetUserByName(ctx, name) + if user_model.IsErrUserNotExist(err) { + return f3_id.NilID + } if err != nil { - panic(fmt.Errorf("GetUserByName: %v", err)) + panic(fmt.Errorf("GetUserByName(%s): %v", name, err)) } return f3_id.NewNodeID(user.ID) } -func newUsers() generic.NodeDriverInterface { +func newUsers() f3_tree_generic.NodeDriverInterface { return &users{} } diff --git a/tests/integration/api_nodeinfo_test.go b/tests/integration/api_nodeinfo_test.go index cafdc1a7cc..ab7709d603 100644 --- a/tests/integration/api_nodeinfo_test.go +++ b/tests/integration/api_nodeinfo_test.go @@ -29,7 +29,7 @@ func TestNodeinfo(t *testing.T) { DecodeJSON(t, resp, &nodeinfo) assert.True(t, nodeinfo.OpenRegistrations) assert.Equal(t, "forgejo", nodeinfo.Software.Name) - assert.Equal(t, 29, nodeinfo.Usage.Users.Total) + assert.Equal(t, 30, nodeinfo.Usage.Users.Total) assert.Equal(t, 23, nodeinfo.Usage.LocalPosts) assert.Equal(t, 4, nodeinfo.Usage.LocalComments) } diff --git a/tests/integration/cmd_forgejo_f3_test.go b/tests/integration/cmd_forgejo_f3_test.go index 19390eec90..ac5e8922df 100644 --- a/tests/integration/cmd_forgejo_f3_test.go +++ b/tests/integration/cmd_forgejo_f3_test.go @@ -24,6 +24,7 @@ import ( f3_generic "code.forgejo.org/f3/gof3/v3/tree/generic" f3_tests "code.forgejo.org/f3/gof3/v3/tree/tests/f3" f3_tests_forge "code.forgejo.org/f3/gof3/v3/tree/tests/f3/forge" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/urfave/cli/v3" ) @@ -61,14 +62,14 @@ func TestF3_CmdMirror_LocalForgejo(t *testing.T) { ctx := t.Context() - mirrorOptions := f3_tests_forge.GetFactory(options.Name)().NewOptions(t) + mirrorForge := f3_tests_forge.GetFactory(options.Name)() + mirrorOptions := mirrorForge.NewOptions(t) mirrorTree := f3_generic.GetFactory("f3")(ctx, mirrorOptions) fixtureOptions := f3_tests_forge.GetFactory(f3_filesystem_options.Name)().NewOptions(t) fixtureTree := f3_generic.GetFactory("f3")(ctx, fixtureOptions) log := fixtureTree.GetLogger() - creator := f3_tests.NewCreator(t, "CmdMirrorLocalForgejo", log) log.Trace("======= build fixture") @@ -77,9 +78,10 @@ func TestF3_CmdMirror_LocalForgejo(t *testing.T) { fixtureUserID := "userID01" fixtureProjectID := "projectID01" + creator := f3_tests.NewCreator(t, "CMFixture", fixtureTree) userFormat := creator.GenerateUser() userFormat.SetID(fixtureUserID) - users := fixtureTree.MustFind(f3_generic.NewPathFromString("/forge/users")) + users := fixtureTree.MustFind(f3_generic.NewNodePathFromString("/forge/users")) user := users.CreateChild(ctx) user.FromFormat(userFormat) user.Upsert(ctx) @@ -87,7 +89,7 @@ func TestF3_CmdMirror_LocalForgejo(t *testing.T) { projectFormat := creator.GenerateProject() projectFormat.SetID(fixtureProjectID) - projects := user.MustFind(f3_generic.NewPathFromString("projects")) + projects := f3_generic.MustFind(user, f3_generic.NewNodePathFromString("projects")) project := projects.CreateChild(ctx) project.FromFormat(projectFormat) project.Upsert(ctx) @@ -98,25 +100,8 @@ func TestF3_CmdMirror_LocalForgejo(t *testing.T) { log.Trace("======= create mirror") - var toPath string - var projects f3_generic.NodeInterface - { - userFormat := creator.GenerateUser() - users := mirrorTree.MustFind(f3_generic.NewPathFromString("/forge/users")) - user := users.CreateChild(ctx) - user.FromFormat(userFormat) - user.Upsert(ctx) - require.Equal(t, user.GetID(), users.GetIDFromName(ctx, userFormat.UserName)) - - projectFormat := creator.GenerateProject() - projects = user.MustFind(f3_generic.NewPathFromString("projects")) - project := projects.CreateChild(ctx) - project.FromFormat(projectFormat) - project.Upsert(ctx) - require.Equal(t, project.GetID(), projects.GetIDFromName(ctx, projectFormat.Name)) - - toPath = fmt.Sprintf("/forge/users/%s/projects/%s", userFormat.UserName, projectFormat.Name) - } + otherProjectName := "otherproject" + toPath := "/forge/users/otheruser/projects/" + otherProjectName log.Trace("======= mirror %s => %s", fromPath, toPath) output, err := runApp(ctx, @@ -131,7 +116,10 @@ func TestF3_CmdMirror_LocalForgejo(t *testing.T) { require.NoError(t, err) log.Trace("======= assert") require.Contains(t, output, fmt.Sprintf("mirror %s", fromPath)) - projects.List(ctx) - require.NotEmpty(t, projects.GetChildren()) - log.Trace("======= project %s", projects.GetChildren()[0]) + project := f3_generic.NilNode + mirrorTree.ApplyAndGet(ctx, f3_generic.NewNodePathFromString(toPath), f3_generic.NewApplyOptions(func(ctx context.Context, parent, p f3_generic.Path, node f3_generic.NodeInterface) { + project = node + })) + require.NotEqual(t, f3_generic.NilNode, project) + assert.Equal(t, otherProjectName, project.GetName()) }