forgejo/services/f3/driver/project.go
Earl Warren cfefe2b6c9
chore(refactor): split repo_service.ForkRepository in two
ForkRepository performs two different functions:

* The fork itself, if it does not already exist
* Updates and notifications after the fork is performed

The function is split to reflect that and otherwise unmodified.

The two function are given different names to:

* clarify which integration tests provides coverage
* distinguish it from the notification method by the same name
2024-08-11 12:40:34 +02:00

189 lines
5.1 KiB
Go

// Copyright Earl Warren <contact@earl-warren.org>
// Copyright Loïc Dachary <loic@dachary.org>
// SPDX-License-Identifier: MIT
package driver
import (
"context"
"fmt"
"strings"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
repo_service "code.gitea.io/gitea/services/repository"
"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_util "code.forgejo.org/f3/gof3/v3/util"
)
var _ f3_tree.ForgeDriverInterface = &project{}
type project struct {
common
forgejoProject *repo_model.Repository
forked *f3.Reference
}
func (o *project) SetNative(project any) {
o.forgejoProject = project.(*repo_model.Repository)
}
func (o *project) GetNativeID() string {
return fmt.Sprintf("%d", o.forgejoProject.ID)
}
func (o *project) NewFormat() f3.Interface {
node := o.GetNode()
return node.GetTree().(f3_tree.TreeInterface).NewFormat(node.GetKind())
}
func (o *project) setForkedReference(ctx context.Context) {
if !o.forgejoProject.IsFork {
return
}
if err := o.forgejoProject.GetBaseRepo(ctx); err != nil {
panic(fmt.Errorf("GetBaseRepo %v %w", o.forgejoProject, err))
}
forkParent := o.forgejoProject.BaseRepo
if err := forkParent.LoadOwner(ctx); err != nil {
panic(fmt.Errorf("LoadOwner %v %w", forkParent, err))
}
owners := "users"
if forkParent.Owner.IsOrganization() {
owners = "organizations"
}
o.forked = f3_tree.NewProjectReference(owners, fmt.Sprintf("%d", forkParent.Owner.ID), fmt.Sprintf("%d", forkParent.ID))
}
func (o *project) ToFormat() f3.Interface {
if o.forgejoProject == nil {
return o.NewFormat()
}
return &f3.Project{
Common: f3.NewCommon(fmt.Sprintf("%d", o.forgejoProject.ID)),
Name: o.forgejoProject.Name,
IsPrivate: o.forgejoProject.IsPrivate,
IsMirror: o.forgejoProject.IsMirror,
Description: o.forgejoProject.Description,
DefaultBranch: o.forgejoProject.DefaultBranch,
Forked: o.forked,
}
}
func (o *project) FromFormat(content f3.Interface) {
project := content.(*f3.Project)
o.forgejoProject = &repo_model.Repository{
ID: f3_util.ParseInt(project.GetID()),
Name: project.Name,
IsPrivate: project.IsPrivate,
IsMirror: project.IsMirror,
Description: project.Description,
DefaultBranch: project.DefaultBranch,
}
if project.Forked != nil {
o.forgejoProject.IsFork = true
o.forgejoProject.ForkID = project.Forked.GetIDAsInt()
}
o.forked = project.Forked
}
func (o *project) Get(ctx context.Context) bool {
node := o.GetNode()
o.Trace("%s", node.GetID())
id := f3_util.ParseInt(string(node.GetID()))
u, err := repo_model.GetRepositoryByID(ctx, id)
if repo_model.IsErrRepoNotExist(err) {
return false
}
if err != nil {
panic(fmt.Errorf("project %v %w", id, err))
}
o.forgejoProject = u
o.setForkedReference(ctx)
return true
}
func (o *project) Patch(ctx context.Context) {
o.Trace("%d", o.forgejoProject.ID)
o.forgejoProject.LowerName = strings.ToLower(o.forgejoProject.Name)
if err := repo_model.UpdateRepositoryCols(ctx, o.forgejoProject,
"description",
"name",
"lower_name",
); err != nil {
panic(fmt.Errorf("UpdateRepositoryCols: %v %v", o.forgejoProject, err))
}
}
func (o *project) Put(ctx context.Context) generic.NodeID {
node := o.GetNode()
o.Trace("%s", node.GetID())
ownerID := f3_tree.GetOwnerID(o.GetNode())
owner, err := user_model.GetUserByID(ctx, ownerID)
if err != nil {
panic(fmt.Errorf("GetUserByID %v %w", ownerID, err))
}
doer, err := user_model.GetAdminUser(ctx)
if err != nil {
panic(fmt.Errorf("GetAdminUser %w", err))
}
if o.forked == nil {
repo, err := repo_service.CreateRepositoryDirectly(ctx, doer, owner, repo_service.CreateRepoOptions{
Name: o.forgejoProject.Name,
Description: o.forgejoProject.Description,
IsPrivate: o.forgejoProject.IsPrivate,
DefaultBranch: o.forgejoProject.DefaultBranch,
})
if err != nil {
panic(err)
}
o.forgejoProject = repo
o.Trace("project created %d", o.forgejoProject.ID)
} else {
if err = o.forgejoProject.GetBaseRepo(ctx); err != nil {
panic(fmt.Errorf("GetBaseRepo %v %w", o.forgejoProject, err))
}
if err = o.forgejoProject.BaseRepo.LoadOwner(ctx); err != nil {
panic(fmt.Errorf("LoadOwner %v %w", o.forgejoProject.BaseRepo, err))
}
repo, err := repo_service.ForkRepositoryIfNotExists(ctx, doer, owner, repo_service.ForkRepoOptions{
BaseRepo: o.forgejoProject.BaseRepo,
Name: o.forgejoProject.Name,
Description: o.forgejoProject.Description,
})
if err != nil {
panic(err)
}
o.forgejoProject = repo
o.Trace("project created %d", o.forgejoProject.ID)
}
return generic.NodeID(fmt.Sprintf("%d", o.forgejoProject.ID))
}
func (o *project) Delete(ctx context.Context) {
node := o.GetNode()
o.Trace("%s", node.GetID())
doer, err := user_model.GetAdminUser(ctx)
if err != nil {
panic(fmt.Errorf("GetAdminUser %w", err))
}
if err := repo_service.DeleteRepository(ctx, doer, o.forgejoProject, true); err != nil {
panic(err)
}
}
func newProject() generic.NodeDriverInterface {
return &project{}
}