diff --git a/go.mod b/go.mod index bbbd8ad5ae..492a724f07 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.24 toolchain go1.24.3 require ( - code.forgejo.org/f3/gof3/v3 v3.10.8 + code.forgejo.org/f3/gof3/v3 v3.11.0 code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251 code.forgejo.org/forgejo/go-rpmutils v1.0.0 code.forgejo.org/forgejo/levelqueue v1.0.0 @@ -87,7 +87,7 @@ require ( github.com/prometheus/client_golang v1.21.1 github.com/redis/go-redis/v9 v9.8.0 github.com/robfig/cron/v3 v3.0.1 - github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 + github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92 github.com/stretchr/testify v1.10.0 diff --git a/go.sum b/go.sum index 7d3fedfc5e..709b0584f0 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= -code.forgejo.org/f3/gof3/v3 v3.10.8 h1:cL5XgOcKffqMdKDOqGCXfMc2OBX89xYvGSj2mz3E/VQ= -code.forgejo.org/f3/gof3/v3 v3.10.8/go.mod h1:ovgb7R8o7k6poQKQ+KWXHOD9uIoanB6tNSmA3kKOMCI= +code.forgejo.org/f3/gof3/v3 v3.11.0 h1:f/xToKwqTgxG6PYxvewywjDQyCcyHEEJ6sZqUitFsAE= +code.forgejo.org/f3/gof3/v3 v3.11.0/go.mod h1:4FaRUNSQGBiD1M0DuB0yNv+Z2wMtlOeckgygHSSq4KQ= 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/act v1.26.0 h1:6mTmoaw7d/WpYiw/Pw6AaypxFdgJog5OFi/PMEgEbxs= @@ -499,8 +499,8 @@ github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw= -github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= diff --git a/services/f3/driver/asset.go b/services/f3/driver/asset.go deleted file mode 100644 index c9d2ecdf2f..0000000000 --- a/services/f3/driver/asset.go +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright Earl Warren -// Copyright Loïc Dachary -// SPDX-License-Identifier: MIT - -package driver - -import ( - "context" - "crypto/sha256" - "encoding/hex" - "fmt" - "io" - "os" - - "forgejo.org/models/db" - repo_model "forgejo.org/models/repo" - user_model "forgejo.org/models/user" - "forgejo.org/modules/storage" - "forgejo.org/modules/timeutil" - "forgejo.org/services/attachment" - - "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_util "code.forgejo.org/f3/gof3/v3/util" - "github.com/google/uuid" -) - -var _ f3_tree.ForgeDriverInterface = &issue{} - -type asset struct { - common - - forgejoAsset *repo_model.Attachment - sha string - contentType string - downloadFunc f3.DownloadFuncType -} - -func (o *asset) SetNative(asset any) { - o.forgejoAsset = asset.(*repo_model.Attachment) -} - -func (o *asset) GetNativeID() string { - return fmt.Sprintf("%d", o.forgejoAsset.ID) -} - -func (o *asset) NewFormat() f3.Interface { - node := o.GetNode() - return node.GetTree().(f3_tree.TreeInterface).NewFormat(node.GetKind()) -} - -func (o *asset) ToFormat() f3.Interface { - if o.forgejoAsset == nil { - return o.NewFormat() - } - - return &f3.ReleaseAsset{ - Common: f3.NewCommon(o.GetNativeID()), - Name: o.forgejoAsset.Name, - ContentType: o.contentType, - Size: o.forgejoAsset.Size, - DownloadCount: o.forgejoAsset.DownloadCount, - Created: o.forgejoAsset.CreatedUnix.AsTime(), - SHA256: o.sha, - DownloadURL: o.forgejoAsset.DownloadURL(), - DownloadFunc: o.downloadFunc, - } -} - -func (o *asset) FromFormat(content f3.Interface) { - asset := content.(*f3.ReleaseAsset) - o.forgejoAsset = &repo_model.Attachment{ - ID: f3_util.ParseInt(asset.GetID()), - Name: asset.Name, - Size: asset.Size, - DownloadCount: asset.DownloadCount, - CreatedUnix: timeutil.TimeStamp(asset.Created.Unix()), - CustomDownloadURL: asset.DownloadURL, - } - o.contentType = asset.ContentType - o.sha = asset.SHA256 - o.downloadFunc = asset.DownloadFunc -} - -func (o *asset) Get(ctx context.Context) bool { - node := o.GetNode() - o.Trace("%s", node.GetID()) - - id := node.GetID().Int64() - - asset, err := repo_model.GetAttachmentByID(ctx, id) - if repo_model.IsErrAttachmentNotExist(err) { - return false - } - if err != nil { - panic(fmt.Errorf("asset %v %w", id, err)) - } - - o.forgejoAsset = asset - - path := o.forgejoAsset.RelativePath() - - { - f, err := storage.Attachments.Open(path) - if err != nil { - panic(err) - } - hasher := sha256.New() - if _, err := io.Copy(hasher, f); err != nil { - panic(fmt.Errorf("io.Copy to hasher: %v", err)) - } - o.sha = hex.EncodeToString(hasher.Sum(nil)) - } - - o.downloadFunc = func() io.ReadCloser { - o.Trace("download %s from copy stored in temporary file %s", o.forgejoAsset.DownloadURL, path) - f, err := os.Open(path) - if err != nil { - panic(err) - } - return f - } - return true -} - -func (o *asset) Patch(ctx context.Context) { - o.Trace("%d", o.forgejoAsset.ID) - if _, err := db.GetEngine(ctx).ID(o.forgejoAsset.ID).Cols("name").Update(o.forgejoAsset); err != nil { - panic(fmt.Errorf("UpdateAssetCols: %v %v", o.forgejoAsset, err)) - } -} - -func (o *asset) Put(ctx context.Context) f3_id.NodeID { - node := o.GetNode() - o.Trace("%s", node.GetID()) - - uploader, err := user_model.GetAdminUser(ctx) - if err != nil { - panic(fmt.Errorf("GetAdminUser %w", err)) - } - - o.forgejoAsset.UploaderID = uploader.ID - o.forgejoAsset.RepoID = f3_tree.GetProjectID(o.GetNode()) - o.forgejoAsset.ReleaseID = f3_tree.GetReleaseID(o.GetNode()) - o.forgejoAsset.UUID = uuid.New().String() - - download := o.downloadFunc() - defer download.Close() - - _, err = attachment.NewAttachment(ctx, o.forgejoAsset, download, o.forgejoAsset.Size) - if err != nil { - panic(err) - } - - o.Trace("asset created %d", o.forgejoAsset.ID) - return f3_id.NewNodeID(o.forgejoAsset.ID) -} - -func (o *asset) Delete(ctx context.Context) { - node := o.GetNode() - o.Trace("%s", node.GetID()) - - if err := repo_model.DeleteAttachment(ctx, o.forgejoAsset, true); err != nil { - panic(err) - } -} - -func newAsset() generic.NodeDriverInterface { - return &asset{} -} diff --git a/services/f3/driver/assets.go b/services/f3/driver/assets.go deleted file mode 100644 index 106d5029f3..0000000000 --- a/services/f3/driver/assets.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright Earl Warren -// Copyright Loïc Dachary -// SPDX-License-Identifier: MIT - -package driver - -import ( - "context" - "fmt" - - repo_model "forgejo.org/models/repo" - - f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3" - "code.forgejo.org/f3/gof3/v3/tree/generic" -) - -type assets struct { - container -} - -func (o *assets) ListPage(ctx context.Context, page int) generic.ChildrenSlice { - if page > 1 { - return generic.NewChildrenSlice(0) - } - - releaseID := f3_tree.GetReleaseID(o.GetNode()) - - release, err := repo_model.GetReleaseByID(ctx, releaseID) - if err != nil { - panic(fmt.Errorf("GetReleaseByID %v %w", releaseID, err)) - } - - if err := release.LoadAttributes(ctx); err != nil { - panic(fmt.Errorf("error while listing assets: %v", err)) - } - - return f3_tree.ConvertListed(ctx, o.GetNode(), f3_tree.ConvertToAny(release.Attachments...)...) -} - -func newAssets() generic.NodeDriverInterface { - return &assets{} -} diff --git a/services/f3/driver/attachment.go b/services/f3/driver/attachment.go new file mode 100644 index 0000000000..64c188d6e0 --- /dev/null +++ b/services/f3/driver/attachment.go @@ -0,0 +1,185 @@ +// Copyright Earl Warren +// Copyright Loïc Dachary +// SPDX-License-Identifier: MIT + +package driver + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "fmt" + "io" + "os" + + "forgejo.org/models/db" + repo_model "forgejo.org/models/repo" + user_model "forgejo.org/models/user" + "forgejo.org/modules/storage" + "forgejo.org/modules/timeutil" + forgejo_attachment "forgejo.org/services/attachment" + + "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_util "code.forgejo.org/f3/gof3/v3/util" + "github.com/google/uuid" +) + +var _ f3_tree.ForgeDriverInterface = &issue{} + +type attachment struct { + common + + forgejoAttachment *repo_model.Attachment + sha string + contentType string + downloadFunc f3.DownloadFuncType +} + +func (o *attachment) SetNative(attachment any) { + o.forgejoAttachment = attachment.(*repo_model.Attachment) +} + +func (o *attachment) GetNativeID() string { + return fmt.Sprintf("%d", o.forgejoAttachment.ID) +} + +func (o *attachment) NewFormat() f3.Interface { + node := o.GetNode() + return node.GetTree().(f3_tree.TreeInterface).NewFormat(node.GetKind()) +} + +func (o *attachment) ToFormat() f3.Interface { + if o.forgejoAttachment == nil { + return o.NewFormat() + } + + return &f3.Attachment{ + Common: f3.NewCommon(o.GetNativeID()), + Name: o.forgejoAttachment.Name, + ContentType: o.contentType, + Size: o.forgejoAttachment.Size, + DownloadCount: o.forgejoAttachment.DownloadCount, + Created: o.forgejoAttachment.CreatedUnix.AsTime(), + SHA256: o.sha, + DownloadURL: o.forgejoAttachment.DownloadURL(), + DownloadFunc: o.downloadFunc, + } +} + +func (o *attachment) FromFormat(content f3.Interface) { + attachment := content.(*f3.Attachment) + o.forgejoAttachment = &repo_model.Attachment{ + ID: f3_util.ParseInt(attachment.GetID()), + Name: attachment.Name, + Size: attachment.Size, + DownloadCount: attachment.DownloadCount, + CreatedUnix: timeutil.TimeStamp(attachment.Created.Unix()), + CustomDownloadURL: attachment.DownloadURL, + } + o.contentType = attachment.ContentType + o.sha = attachment.SHA256 + o.downloadFunc = attachment.DownloadFunc +} + +func (o *attachment) Get(ctx context.Context) bool { + node := o.GetNode() + o.Trace("%s", node.GetID()) + + id := node.GetID().Int64() + + attachment, err := repo_model.GetAttachmentByID(ctx, id) + if repo_model.IsErrAttachmentNotExist(err) { + return false + } + if err != nil { + panic(fmt.Errorf("attachment %v %w", id, err)) + } + + o.forgejoAttachment = attachment + + path := o.forgejoAttachment.RelativePath() + + { + f, err := storage.Attachments.Open(path) + if err != nil { + panic(err) + } + hasher := sha256.New() + if _, err := io.Copy(hasher, f); err != nil { + panic(fmt.Errorf("io.Copy to hasher: %v", err)) + } + o.sha = hex.EncodeToString(hasher.Sum(nil)) + } + + o.downloadFunc = func() io.ReadCloser { + o.Trace("download %s from copy stored in temporary file %s", o.forgejoAttachment.DownloadURL, path) + f, err := os.Open(path) + if err != nil { + panic(err) + } + return f + } + return true +} + +func (o *attachment) Patch(ctx context.Context) { + o.Trace("%d", o.forgejoAttachment.ID) + if _, err := db.GetEngine(ctx).ID(o.forgejoAttachment.ID).Cols("name").Update(o.forgejoAttachment); err != nil { + panic(fmt.Errorf("UpdateAttachmentCols: %v %v", o.forgejoAttachment, err)) + } +} + +func (o *attachment) Put(ctx context.Context) f3_id.NodeID { + node := o.GetNode() + o.Trace("%s", node.GetID()) + + uploader, err := user_model.GetAdminUser(ctx) + if err != nil { + panic(fmt.Errorf("GetAdminUser %w", err)) + } + + attachable := f3_tree.GetAttachable(o.GetNode()) + attachableID := f3_tree.GetAttachableID(o.GetNode()) + + switch attachable.GetKind() { + case f3_tree.KindRelease: + o.forgejoAttachment.ReleaseID = attachableID + case f3_tree.KindComment: + o.forgejoAttachment.CommentID = attachableID + case f3_tree.KindIssue, f3_tree.KindPullRequest: + o.forgejoAttachment.IssueID = attachableID + default: + panic(fmt.Errorf("unexpected type %s", attachable.GetKind())) + } + + o.forgejoAttachment.UploaderID = uploader.ID + o.forgejoAttachment.RepoID = f3_tree.GetProjectID(o.GetNode()) + o.forgejoAttachment.UUID = uuid.New().String() + + download := o.downloadFunc() + defer download.Close() + + _, err = forgejo_attachment.NewAttachment(ctx, o.forgejoAttachment, download, o.forgejoAttachment.Size) + if err != nil { + panic(err) + } + + o.Trace("attachment created %d", o.forgejoAttachment.ID) + return f3_id.NewNodeID(o.forgejoAttachment.ID) +} + +func (o *attachment) Delete(ctx context.Context) { + node := o.GetNode() + o.Trace("%s", node.GetID()) + + if err := repo_model.DeleteAttachment(ctx, o.forgejoAttachment, true); err != nil { + panic(err) + } +} + +func newAttachment() generic.NodeDriverInterface { + return &attachment{} +} diff --git a/services/f3/driver/attachments.go b/services/f3/driver/attachments.go new file mode 100644 index 0000000000..392afda52c --- /dev/null +++ b/services/f3/driver/attachments.go @@ -0,0 +1,79 @@ +// Copyright Earl Warren +// Copyright Loïc Dachary +// SPDX-License-Identifier: MIT + +package driver + +import ( + "context" + "fmt" + + issues_model "forgejo.org/models/issues" + repo_model "forgejo.org/models/repo" + + f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3" + "code.forgejo.org/f3/gof3/v3/tree/generic" +) + +type attachments struct { + container +} + +func (o *attachments) ListPage(ctx context.Context, page int) generic.ChildrenSlice { + if page > 1 { + return generic.NewChildrenSlice(0) + } + + attachable := f3_tree.GetAttachable(o.GetNode()) + attachableID := f3_tree.GetAttachableID(o.GetNode()) + + var attachments []*repo_model.Attachment + + switch attachable.GetKind() { + case f3_tree.KindRelease: + release, err := repo_model.GetReleaseByID(ctx, attachableID) + if err != nil { + panic(fmt.Errorf("GetReleaseByID %v %w", attachableID, err)) + } + + if err := release.LoadAttributes(ctx); err != nil { + panic(fmt.Errorf("error while listing attachments: %v", err)) + } + + attachments = release.Attachments + + case f3_tree.KindComment: + comment, err := issues_model.GetCommentByID(ctx, attachableID) + if err != nil { + panic(fmt.Errorf("GetCommentByID %v %w", attachableID, err)) + } + + if err := comment.LoadAttachments(ctx); err != nil { + panic(fmt.Errorf("error while listing attachments: %v", err)) + } + + attachments = comment.Attachments + + case f3_tree.KindIssue, f3_tree.KindPullRequest: + repoID := f3_tree.GetProjectID(o.GetNode()) + issue, err := issues_model.GetIssueByIndex(ctx, repoID, attachableID) + if err != nil { + panic(fmt.Errorf("GetIssueByID %v %w", attachableID, err)) + } + + if err := issue.LoadAttachments(ctx); err != nil { + panic(fmt.Errorf("error while listing attachments: %v", err)) + } + + attachments = issue.Attachments + + default: + panic(fmt.Errorf("unexpected type %s", attachable.GetKind())) + } + + return f3_tree.ConvertListed(ctx, o.GetNode(), f3_tree.ConvertToAny(attachments...)...) +} + +func newAttachments() generic.NodeDriverInterface { + return &attachments{} +} diff --git a/services/f3/driver/reaction.go b/services/f3/driver/reaction.go index 74c50b9d13..b959206074 100644 --- a/services/f3/driver/reaction.go +++ b/services/f3/driver/reaction.go @@ -89,7 +89,7 @@ func (o *reaction) Patch(ctx context.Context) { } func (o *reaction) Put(ctx context.Context) f3_id.NodeID { - o.Error("%v", o.forgejoReaction.User) + o.Trace("%v", o.forgejoReaction.User) sess := db.GetEngine(ctx) @@ -110,7 +110,7 @@ func (o *reaction) Put(ctx context.Context) f3_id.NodeID { panic(fmt.Errorf("unexpected type %v", reactionable.GetKind())) } - o.Error("%v", o.forgejoReaction) + o.Trace("%v", o.forgejoReaction) if _, err := sess.Insert(o.forgejoReaction); err != nil { panic(err) diff --git a/services/f3/driver/repository.go b/services/f3/driver/repository.go index e7f4e43723..3cd9aa7f2e 100644 --- a/services/f3/driver/repository.go +++ b/services/f3/driver/repository.go @@ -72,7 +72,7 @@ func (o *repository) upsert(ctx context.Context) f3_id.NodeID { return f3_id.NewNodeID(o.f.Name) } -func (o *repository) SetFetchFunc(fetchFunc func(ctx context.Context, destination string, internalRefs []string)) { +func (o *repository) SetFetchFunc(fetchFunc func(ctx context.Context, destination, internalRef string)) { o.f.FetchFunc = fetchFunc } @@ -93,10 +93,16 @@ func (o *repository) GetRepositoryPushURL() string { return o.getURL() } -func (o *repository) GetRepositoryInternalRefs() []string { - return []string{} +func (o *repository) GetRepositoryInternalRef() string { + return "" } +func (o *repository) GetPullRequestBranch(pr *f3.PullRequestBranch) *f3.PullRequestBranch { + panic("") +} +func (o *repository) CreatePullRequestBranch(pr *f3.PullRequestBranch) {} +func (o *repository) DeletePullRequestBranch(pr *f3.PullRequestBranch) {} + func newRepository(_ context.Context) generic.NodeDriverInterface { r := &repository{ f: &f3.Repository{}, diff --git a/services/f3/driver/tree.go b/services/f3/driver/tree.go index ff927df9d4..fe11b15f6e 100644 --- a/services/f3/driver/tree.go +++ b/services/f3/driver/tree.go @@ -49,10 +49,10 @@ func (o *treeDriver) Factory(ctx context.Context, kind f3_kind.Kind) generic.Nod return newComments() case f3_tree.KindComment: return newComment() - case f3_tree.KindAssets: - return newAssets() - case f3_tree.KindAsset: - return newAsset() + case f3_tree.KindAttachments: + return newAttachments() + case f3_tree.KindAttachment: + return newAttachment() case f3_tree.KindLabels: return newLabels() case f3_tree.KindLabel: