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.

59c721d26b/models/user/user.go (L65-L66)

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/10673
Reviewed-by: Gusted <gusted@noreply.codeberg.org>
Co-authored-by: limiting-factor <limiting-factor@posteo.com>
Co-committed-by: limiting-factor <limiting-factor@posteo.com>
This commit is contained in:
limiting-factor 2026-01-13 16:59:56 +01:00 committed by Gusted
commit a71392c6aa
39 changed files with 348 additions and 194 deletions

View file

@ -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)

View file

@ -2552,7 +2552,7 @@ LEVEL = Info
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[F3]
;[f3]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;

6
go.mod
View file

@ -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

8
go.sum
View file

@ -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=

View file

@ -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 {

View file

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

View file

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

View file

@ -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{}
}

View file

@ -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{}
}

View file

@ -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)

View file

@ -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{}
}

View file

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

View file

@ -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 }

View file

@ -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,

View file

@ -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{}
}

View file

@ -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{}
}

View file

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

View file

@ -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{}
}

View file

@ -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{}
}

View file

@ -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{}
}

View file

@ -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,

View file

@ -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{}
}

View file

@ -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)

View file

@ -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{}
}

View file

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

View file

@ -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{}
}

View file

@ -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{}
}

View file

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

View file

@ -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

View file

@ -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),

View file

@ -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{}
}

View file

@ -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{}
}

View file

@ -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
}

View file

@ -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{}
}

View file

@ -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))

View file

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

View file

@ -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{}
}

View file

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

View file

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