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()) }