Adding upstream version 3.10.8.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
37e9b6d587
commit
03bfe4079e
356 changed files with 28857 additions and 0 deletions
84
forges/gitlab/common.go
Normal file
84
forges/gitlab/common.go
Normal file
|
@ -0,0 +1,84 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/id"
|
||||
"code.forgejo.org/f3/gof3/v3/kind"
|
||||
options_http "code.forgejo.org/f3/gof3/v3/options/http"
|
||||
f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3"
|
||||
"code.forgejo.org/f3/gof3/v3/tree/generic"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
"gitlab.com/gitlab-org/api/client-go"
|
||||
)
|
||||
|
||||
type common struct {
|
||||
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) getTree() generic.TreeInterface {
|
||||
return o.GetNode().GetTree()
|
||||
}
|
||||
|
||||
func (o *common) getPageSize() int {
|
||||
return o.getTreeDriver().GetPageSize()
|
||||
}
|
||||
|
||||
func (o *common) getF3Tree() f3_tree.TreeInterface {
|
||||
return o.getTree().(f3_tree.TreeInterface)
|
||||
}
|
||||
|
||||
func (o *common) getKind() kind.Kind {
|
||||
return o.GetNode().GetKind()
|
||||
}
|
||||
|
||||
func (o *common) getChildDriver(kind kind.Kind) generic.NodeDriverInterface {
|
||||
return o.GetNode().GetChild(id.NewNodeID(kind)).GetDriver()
|
||||
}
|
||||
|
||||
func (o *common) isContainer() bool {
|
||||
return o.getF3Tree().IsContainer(o.getKind())
|
||||
}
|
||||
|
||||
func (o *common) getURL() string {
|
||||
return o.getTreeDriver().options.GetURL()
|
||||
}
|
||||
|
||||
func (o *common) getPushURL() string {
|
||||
return o.getTreeDriver().options.GetPushURL()
|
||||
}
|
||||
|
||||
func (o *common) getNewMigrationHTTPClient() options_http.NewMigrationHTTPClientFun {
|
||||
return o.getTreeDriver().options.GetNewMigrationHTTPClient()
|
||||
}
|
||||
|
||||
func (o *common) getTreeDriver() *treeDriver {
|
||||
return o.GetTreeDriver().(*treeDriver)
|
||||
}
|
||||
|
||||
func (o *common) getIsAdmin() bool {
|
||||
return o.getTreeDriver().GetIsAdmin()
|
||||
}
|
||||
|
||||
func (o *common) getClient() *gitlab.Client {
|
||||
return o.getTreeDriver().GetClient()
|
||||
}
|
||||
|
||||
func (o *common) getVersion() *version.Version {
|
||||
return o.getTreeDriver().GetVersion()
|
||||
}
|
||||
|
||||
func (o *common) IsNull() bool { return false }
|
43
forges/gitlab/container.go
Normal file
43
forges/gitlab/container.go
Normal file
|
@ -0,0 +1,43 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/f3"
|
||||
"code.forgejo.org/f3/gof3/v3/id"
|
||||
f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3"
|
||||
)
|
||||
|
||||
type container struct {
|
||||
common
|
||||
}
|
||||
|
||||
func (o *container) NewFormat() f3.Interface {
|
||||
node := o.GetNode()
|
||||
return node.GetTree().(f3_tree.TreeInterface).NewFormat(node.GetKind())
|
||||
}
|
||||
|
||||
func (o *container) ToFormat() f3.Interface {
|
||||
return o.NewFormat()
|
||||
}
|
||||
|
||||
func (o *container) FromFormat(content f3.Interface) {
|
||||
}
|
||||
|
||||
func (o *container) Get(context.Context) bool { return true }
|
||||
|
||||
func (o *container) Put(ctx context.Context) id.NodeID {
|
||||
return o.upsert(ctx)
|
||||
}
|
||||
|
||||
func (o *container) Patch(ctx context.Context) {
|
||||
o.upsert(ctx)
|
||||
}
|
||||
|
||||
func (o *container) upsert(context.Context) id.NodeID {
|
||||
return id.NewNodeID(o.getKind())
|
||||
}
|
46
forges/gitlab/forge.go
Normal file
46
forges/gitlab/forge.go
Normal file
|
@ -0,0 +1,46 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/f3"
|
||||
"code.forgejo.org/f3/gof3/v3/id"
|
||||
"code.forgejo.org/f3/gof3/v3/kind"
|
||||
"code.forgejo.org/f3/gof3/v3/tree/generic"
|
||||
)
|
||||
|
||||
type forge struct {
|
||||
common
|
||||
|
||||
ownersKind map[string]kind.Kind
|
||||
}
|
||||
|
||||
func newForge() generic.NodeDriverInterface {
|
||||
return &forge{
|
||||
ownersKind: make(map[string]kind.Kind),
|
||||
}
|
||||
}
|
||||
|
||||
func (o *forge) Equals(context.Context, generic.NodeInterface) bool { return true }
|
||||
func (o *forge) Get(context.Context) bool { return true }
|
||||
func (o *forge) Put(context.Context) id.NodeID { return id.NewNodeID("forge") }
|
||||
func (o *forge) Patch(context.Context) {}
|
||||
func (o *forge) Delete(context.Context) {}
|
||||
func (o *forge) NewFormat() f3.Interface { return &f3.Forge{} }
|
||||
func (o *forge) FromFormat(f3.Interface) {}
|
||||
|
||||
func (o *forge) ToFormat() f3.Interface {
|
||||
return &f3.Forge{
|
||||
Common: f3.NewCommon("forge"),
|
||||
URL: o.String(),
|
||||
}
|
||||
}
|
||||
|
||||
func (o *forge) String() string {
|
||||
options := o.GetTreeDriver().(*treeDriver).options
|
||||
return options.ForgeAuth.GetURL()
|
||||
}
|
16
forges/gitlab/main.go
Normal file
16
forges/gitlab/main.go
Normal file
|
@ -0,0 +1,16 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
gitlab_options "code.forgejo.org/f3/gof3/v3/forges/gitlab/options"
|
||||
"code.forgejo.org/f3/gof3/v3/options"
|
||||
f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
f3_tree.RegisterForgeFactory(gitlab_options.Name, newTreeDriver)
|
||||
options.RegisterFactory(gitlab_options.Name, newOptions)
|
||||
}
|
16
forges/gitlab/options.go
Normal file
16
forges/gitlab/options.go
Normal file
|
@ -0,0 +1,16 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
gitlab_options "code.forgejo.org/f3/gof3/v3/forges/gitlab/options"
|
||||
"code.forgejo.org/f3/gof3/v3/options"
|
||||
)
|
||||
|
||||
func newOptions() options.Interface {
|
||||
o := &gitlab_options.Options{}
|
||||
o.SetName(gitlab_options.Name)
|
||||
return o
|
||||
}
|
9
forges/gitlab/options/name.go
Normal file
9
forges/gitlab/options/name.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package options
|
||||
|
||||
const (
|
||||
Name = "gitlab"
|
||||
)
|
33
forges/gitlab/options/options.go
Normal file
33
forges/gitlab/options/options.go
Normal file
|
@ -0,0 +1,33 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package options
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/forges/helpers/auth"
|
||||
"code.forgejo.org/f3/gof3/v3/options"
|
||||
options_http "code.forgejo.org/f3/gof3/v3/options/http"
|
||||
"code.forgejo.org/f3/gof3/v3/options/logger"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
options.Options
|
||||
logger.OptionsLogger
|
||||
auth.ForgeAuth
|
||||
options_http.Implementation
|
||||
|
||||
Version string
|
||||
}
|
||||
|
||||
func (o *Options) FromFlags(ctx context.Context, c *cli.Command, prefix string) {
|
||||
o.ForgeAuth.FromFlags(ctx, c, prefix)
|
||||
}
|
||||
|
||||
func (o *Options) GetFlags(prefix, category string) []cli.Flag {
|
||||
return o.ForgeAuth.GetFlags(prefix, category)
|
||||
}
|
121
forges/gitlab/organization.go
Normal file
121
forges/gitlab/organization.go
Normal file
|
@ -0,0 +1,121 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// Copyright twenty-panda <twenty-panda@posteo.com>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/f3"
|
||||
"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"
|
||||
"code.forgejo.org/f3/gof3/v3/util"
|
||||
|
||||
"gitlab.com/gitlab-org/api/client-go"
|
||||
)
|
||||
|
||||
type organization struct {
|
||||
common
|
||||
forgejoOrganization *gitlab.Group
|
||||
}
|
||||
|
||||
var _ f3_tree.ForgeDriverInterface = &organization{}
|
||||
|
||||
func newOrganization() generic.NodeDriverInterface {
|
||||
return &organization{}
|
||||
}
|
||||
|
||||
func (o *organization) SetNative(organization any) {
|
||||
o.forgejoOrganization = organization.(*gitlab.Group)
|
||||
}
|
||||
|
||||
func (o *organization) GetNativeID() string {
|
||||
return fmt.Sprintf("%d", o.forgejoOrganization.ID)
|
||||
}
|
||||
|
||||
func (o *organization) NewFormat() f3.Interface {
|
||||
node := o.GetNode()
|
||||
return node.GetTree().(f3_tree.TreeInterface).NewFormat(node.GetKind())
|
||||
}
|
||||
|
||||
func (o *organization) ToFormat() f3.Interface {
|
||||
if o.forgejoOrganization == nil {
|
||||
return o.NewFormat()
|
||||
}
|
||||
return &f3.Organization{
|
||||
Common: f3.NewCommon(fmt.Sprintf("%d", o.forgejoOrganization.ID)),
|
||||
Name: o.forgejoOrganization.Name,
|
||||
FullName: o.forgejoOrganization.Description,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *organization) FromFormat(content f3.Interface) {
|
||||
organization := content.(*f3.Organization)
|
||||
o.forgejoOrganization = &gitlab.Group{
|
||||
ID: int(util.ParseInt(organization.GetID())),
|
||||
Name: organization.Name,
|
||||
Path: organization.Name,
|
||||
Description: organization.FullName,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *organization) Get(ctx context.Context) bool {
|
||||
node := o.GetNode()
|
||||
o.Trace("%s", node.GetID())
|
||||
|
||||
organization, resp, err := o.getClient().Groups.GetGroup(node.GetID().Int(), &gitlab.GetGroupOptions{})
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
return false
|
||||
}
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("organization %v %w", o, err))
|
||||
}
|
||||
o.forgejoOrganization = organization
|
||||
return true
|
||||
}
|
||||
|
||||
func (o *organization) Patch(context.Context) {
|
||||
node := o.GetNode()
|
||||
o.Trace("%s", node.GetID())
|
||||
_, _, err := o.getClient().Groups.UpdateGroup(o.forgejoOrganization.Name, &gitlab.UpdateGroupOptions{
|
||||
Description: &o.forgejoOrganization.Description,
|
||||
})
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("UpdateGroup %v %w", o, err))
|
||||
}
|
||||
}
|
||||
|
||||
func (o *organization) Put(context.Context) id.NodeID {
|
||||
node := o.GetNode()
|
||||
o.Trace("%s", node.GetID())
|
||||
|
||||
organization, _, err := o.getClient().Groups.CreateGroup(&gitlab.CreateGroupOptions{
|
||||
Name: &o.forgejoOrganization.Name,
|
||||
Path: &o.forgejoOrganization.Name,
|
||||
Description: &o.forgejoOrganization.Description,
|
||||
})
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("CreateGroup %v %w", o, err))
|
||||
}
|
||||
o.forgejoOrganization = organization
|
||||
o.Trace("%s", organization)
|
||||
return id.NewNodeID(o.GetNativeID())
|
||||
}
|
||||
|
||||
func (o *organization) Delete(ctx context.Context) {
|
||||
node := o.GetNode()
|
||||
o.Trace("%s", node.GetID())
|
||||
|
||||
permanentlyRemove := true
|
||||
_, err := o.getClient().Groups.DeleteGroup(o.forgejoOrganization.Name, &gitlab.DeleteGroupOptions{
|
||||
PermanentlyRemove: &permanentlyRemove,
|
||||
})
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("DeleteGroup %v %w", o, err))
|
||||
}
|
||||
}
|
56
forges/gitlab/organizations.go
Normal file
56
forges/gitlab/organizations.go
Normal file
|
@ -0,0 +1,56 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// Copyright twenty-panda <twenty-panda@posteo.com>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"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"
|
||||
|
||||
"gitlab.com/gitlab-org/api/client-go"
|
||||
)
|
||||
|
||||
type organizations struct {
|
||||
container
|
||||
}
|
||||
|
||||
func (o *organizations) listOrganizationsPage(ctx context.Context, page int) []*gitlab.Group {
|
||||
pageSize := o.getPageSize()
|
||||
|
||||
var organizationFounds []*gitlab.Group
|
||||
var err error
|
||||
organizationFounds, _, err = o.getClient().Groups.ListGroups(&gitlab.ListGroupsOptions{
|
||||
ListOptions: gitlab.ListOptions{Page: page, PerPage: pageSize},
|
||||
})
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("error while listing organizations: %v", err))
|
||||
}
|
||||
|
||||
return organizationFounds
|
||||
}
|
||||
|
||||
func (o *organizations) ListPage(ctx context.Context, page int) generic.ChildrenSlice {
|
||||
return f3_tree.ConvertListed(ctx, o.GetNode(), f3_tree.ConvertToAny(o.listOrganizationsPage(ctx, page)...)...)
|
||||
}
|
||||
|
||||
func (o *organizations) GetIDFromName(ctx context.Context, name string) id.NodeID {
|
||||
organization, resp, err := o.getClient().Groups.GetGroup(name, &gitlab.GetGroupOptions{})
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
return id.NilID
|
||||
}
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("organization %v %w", o, err))
|
||||
}
|
||||
return id.NewNodeID(organization.ID)
|
||||
}
|
||||
|
||||
func newOrganizations() generic.NodeDriverInterface {
|
||||
return &organizations{}
|
||||
}
|
18
forges/gitlab/projects.go
Normal file
18
forges/gitlab/projects.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// Copyright twenty-panda <twenty-panda@posteo.com>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"code.forgejo.org/f3/gof3/v3/tree/generic"
|
||||
)
|
||||
|
||||
type projects struct {
|
||||
container
|
||||
}
|
||||
|
||||
func newProjects() generic.NodeDriverInterface {
|
||||
return &projects{}
|
||||
}
|
42
forges/gitlab/root.go
Normal file
42
forges/gitlab/root.go
Normal file
|
@ -0,0 +1,42 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/f3"
|
||||
"code.forgejo.org/f3/gof3/v3/id"
|
||||
"code.forgejo.org/f3/gof3/v3/tree/generic"
|
||||
)
|
||||
|
||||
type root struct {
|
||||
generic.NullDriver
|
||||
|
||||
content f3.Interface
|
||||
}
|
||||
|
||||
func newRoot(content f3.Interface) generic.NodeDriverInterface {
|
||||
return &root{
|
||||
content: content,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *root) FromFormat(content f3.Interface) {
|
||||
o.content = content
|
||||
}
|
||||
|
||||
func (o *root) ToFormat() f3.Interface {
|
||||
return o.content
|
||||
}
|
||||
|
||||
func (o *root) Get(context.Context) bool { return true }
|
||||
|
||||
func (o *root) Put(context.Context) id.NodeID {
|
||||
return id.NilID
|
||||
}
|
||||
|
||||
func (o *root) Patch(context.Context) {
|
||||
}
|
16
forges/gitlab/tests/init.go
Normal file
16
forges/gitlab/tests/init.go
Normal file
|
@ -0,0 +1,16 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package tests
|
||||
|
||||
import (
|
||||
gitlab_options "code.forgejo.org/f3/gof3/v3/forges/gitlab/options"
|
||||
tests_forge "code.forgejo.org/f3/gof3/v3/tree/tests/f3/forge"
|
||||
)
|
||||
|
||||
func init() {
|
||||
tests_forge.RegisterFactory(gitlab_options.Name, func() tests_forge.Interface {
|
||||
return newForgeTest(gitlab_options.Name)
|
||||
})
|
||||
}
|
57
forges/gitlab/tests/new.go
Normal file
57
forges/gitlab/tests/new.go
Normal file
|
@ -0,0 +1,57 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package tests
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/kind"
|
||||
"code.forgejo.org/f3/gof3/v3/options"
|
||||
f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3"
|
||||
tests_forge "code.forgejo.org/f3/gof3/v3/tree/tests/f3/forge"
|
||||
)
|
||||
|
||||
type forgeTest struct {
|
||||
tests_forge.Base
|
||||
}
|
||||
|
||||
func (o *forgeTest) NewOptions(t *testing.T) options.Interface {
|
||||
return newTestOptions(t, o.Base.GetName())
|
||||
}
|
||||
|
||||
func (o *forgeTest) GetNameExceptions() []string {
|
||||
return []string{tests_forge.ComplianceNameForkedPullRequest}
|
||||
}
|
||||
|
||||
func (o *forgeTest) GetKindExceptions() []kind.Kind {
|
||||
return []kind.Kind{
|
||||
f3_tree.KindAssets,
|
||||
f3_tree.KindComments,
|
||||
f3_tree.KindIssues,
|
||||
f3_tree.KindLabels,
|
||||
f3_tree.KindMilestones,
|
||||
f3_tree.KindProjects,
|
||||
f3_tree.KindPullRequests,
|
||||
f3_tree.KindReactions,
|
||||
f3_tree.KindReleases,
|
||||
f3_tree.KindRepositories,
|
||||
f3_tree.KindReviews,
|
||||
f3_tree.KindReviewComments,
|
||||
f3_tree.KindTopics,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *forgeTest) GetNonTestUsers() []string {
|
||||
return []string{
|
||||
GetFixtureUsername(),
|
||||
"ghost",
|
||||
}
|
||||
}
|
||||
|
||||
func newForgeTest(name string) tests_forge.Interface {
|
||||
t := &forgeTest{}
|
||||
t.SetName(name)
|
||||
return t
|
||||
}
|
60
forges/gitlab/tests/testhelpers.go
Normal file
60
forges/gitlab/tests/testhelpers.go
Normal file
|
@ -0,0 +1,60 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package tests
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
gitlab_options "code.forgejo.org/f3/gof3/v3/forges/gitlab/options"
|
||||
"code.forgejo.org/f3/gof3/v3/forges/helpers/auth"
|
||||
"code.forgejo.org/f3/gof3/v3/logger"
|
||||
"code.forgejo.org/f3/gof3/v3/options"
|
||||
)
|
||||
|
||||
func GetFixtureURL(name string) string {
|
||||
upperName := strings.ToUpper(name)
|
||||
hostPort := os.Getenv("GOF3_" + upperName + "_HOST_PORT")
|
||||
if hostPort == "" {
|
||||
return ""
|
||||
}
|
||||
return "http://" + hostPort
|
||||
}
|
||||
|
||||
func GetFixtureUsername() string {
|
||||
user := os.Getenv("GITLAB_TEST_USER")
|
||||
if user == "" {
|
||||
user = "root"
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
func GetFixturePassword() string {
|
||||
password := os.Getenv("GITLAB_TEST_PASSWORD")
|
||||
if password == "" {
|
||||
password = "Wrobyak4"
|
||||
}
|
||||
return password
|
||||
}
|
||||
|
||||
func newTestOptions(t *testing.T, name string) options.Interface {
|
||||
t.Helper()
|
||||
url := GetFixtureURL(name)
|
||||
if url == "" {
|
||||
t.Skip("test server is not up")
|
||||
}
|
||||
forgeAuth := auth.NewForgeAuth()
|
||||
forgeAuth.SetURL(url)
|
||||
forgeAuth.SetUsername(GetFixtureUsername())
|
||||
forgeAuth.SetPassword(GetFixturePassword())
|
||||
o := options.GetFactory(gitlab_options.Name)().(*gitlab_options.Options)
|
||||
o.ForgeAuth = forgeAuth
|
||||
l := logger.NewLogger()
|
||||
l.SetLevel(logger.Trace)
|
||||
o.OptionsLogger.SetLogger(l)
|
||||
|
||||
return o
|
||||
}
|
18
forges/gitlab/topics.go
Normal file
18
forges/gitlab/topics.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// Copyright twenty-panda <twenty-panda@posteo.com>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"code.forgejo.org/f3/gof3/v3/tree/generic"
|
||||
)
|
||||
|
||||
type topics struct {
|
||||
container
|
||||
}
|
||||
|
||||
func newTopics() generic.NodeDriverInterface {
|
||||
return &topics{}
|
||||
}
|
213
forges/gitlab/tree.go
Normal file
213
forges/gitlab/tree.go
Normal file
|
@ -0,0 +1,213 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
gitlab_options "code.forgejo.org/f3/gof3/v3/forges/gitlab/options"
|
||||
"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"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
"gitlab.com/gitlab-org/api/client-go"
|
||||
)
|
||||
|
||||
type treeDriver struct {
|
||||
generic.NullTreeDriver
|
||||
|
||||
user *gitlab.User
|
||||
client *gitlab.Client
|
||||
options *gitlab_options.Options
|
||||
version *version.Version
|
||||
}
|
||||
|
||||
func (o *treeDriver) GetClient() *gitlab.Client {
|
||||
return o.client
|
||||
}
|
||||
|
||||
func (o *treeDriver) GetIsAdmin() bool {
|
||||
return o.user.IsAdmin
|
||||
}
|
||||
|
||||
func (o *treeDriver) SetIsAdmin() {
|
||||
user, _, err := o.client.Users.CurrentUser()
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("Failed to get information about the user for: %s. Error: %v", o.options.GetURL(), err))
|
||||
}
|
||||
o.user = user
|
||||
o.options.SetUsername(user.Username)
|
||||
}
|
||||
|
||||
var (
|
||||
ForgejoVersion700 = version.Must(version.NewVersion("7.0.0")) // 1.22
|
||||
ForgejoVersion600 = version.Must(version.NewVersion("6.0.0")) // 1.21
|
||||
ForgejoVersion500 = version.Must(version.NewVersion("5.0.0")) // 1.20.1
|
||||
ForgejoVersion501 = version.Must(version.NewVersion("5.0.1")) // 1.20.2
|
||||
ForgejoVersion502 = version.Must(version.NewVersion("5.0.2")) // 1.20.3
|
||||
ForgejoVersion503 = version.Must(version.NewVersion("5.0.3")) // 1.20.4
|
||||
ForgejoVersion504 = version.Must(version.NewVersion("5.0.4")) // 1.20.5
|
||||
ForgejoVersion4 = version.Must(version.NewVersion("4.0.0")) // 1.19
|
||||
|
||||
ForgejoVersionNotFound = version.Must(version.NewVersion("1.0.0"))
|
||||
)
|
||||
|
||||
func (o *treeDriver) GetVersion() *version.Version {
|
||||
o.SetVersion()
|
||||
return o.version
|
||||
}
|
||||
|
||||
func (o *treeDriver) SetVersion() {
|
||||
if o.version != nil {
|
||||
return
|
||||
}
|
||||
client := &http.Client{}
|
||||
url := fmt.Sprintf("%s/api/forgejo/v1/version", o.options.GetURL())
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("while getting %s %w", url, err))
|
||||
}
|
||||
|
||||
switch resp.StatusCode {
|
||||
case http.StatusNotFound:
|
||||
o.version = ForgejoVersionNotFound
|
||||
case http.StatusOK:
|
||||
v := struct{ Version string }{}
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("reading response body %+v %w", resp, err))
|
||||
}
|
||||
if err := json.Unmarshal(body, &v); err != nil {
|
||||
panic(fmt.Errorf("decoding JSON response from %s %s %w", url, string(body), err))
|
||||
}
|
||||
o.version = version.Must(version.NewVersion(v.Version))
|
||||
default:
|
||||
panic(fmt.Errorf("unexpected status code fetching %s %d %v", url, resp.StatusCode, resp))
|
||||
}
|
||||
}
|
||||
|
||||
func (o *treeDriver) maybeSudo(uid interface{}) []gitlab.RequestOptionFunc {
|
||||
if !o.GetIsAdmin() {
|
||||
return []gitlab.RequestOptionFunc{}
|
||||
}
|
||||
if name, ok := uid.(string); ok && name == o.options.GetUsername() {
|
||||
return []gitlab.RequestOptionFunc{}
|
||||
}
|
||||
return []gitlab.RequestOptionFunc{
|
||||
gitlab.WithSudo(uid),
|
||||
}
|
||||
}
|
||||
|
||||
func (o *treeDriver) Init() {
|
||||
o.NullTreeDriver.Init()
|
||||
|
||||
var err error
|
||||
var client *gitlab.Client
|
||||
if o.options.GetToken() != "" {
|
||||
o.Debug("Connecting to %s with token", o.options.GetURL())
|
||||
client, err = gitlab.NewClient(o.options.GetToken(), gitlab.WithBaseURL(o.options.GetURL()), gitlab.WithHTTPClient(o.options.GetNewMigrationHTTPClient()()))
|
||||
} else {
|
||||
o.Debug("Connecting to %s as user %s", o.options.GetURL(), o.options.GetUsername())
|
||||
client, err = gitlab.NewBasicAuthClient(o.options.GetUsername(), o.options.GetPassword(), gitlab.WithBaseURL(o.options.GetURL()), gitlab.WithHTTPClient(o.options.GetNewMigrationHTTPClient()()))
|
||||
}
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("Failed to create Forgejo client for: %s. Error: %v", o.options.GetURL(), err))
|
||||
}
|
||||
o.client = client
|
||||
|
||||
o.SetIsAdmin()
|
||||
if o.GetIsAdmin() {
|
||||
o.Debug("Connected as admin")
|
||||
} else {
|
||||
o.Debug("Connected as regular user")
|
||||
}
|
||||
}
|
||||
|
||||
func newTreeDriver(tree generic.TreeInterface, anyOptions any) generic.TreeDriverInterface {
|
||||
driver := &treeDriver{
|
||||
options: anyOptions.(*gitlab_options.Options),
|
||||
}
|
||||
driver.SetTree(tree)
|
||||
driver.Init()
|
||||
return driver
|
||||
}
|
||||
|
||||
func (o *treeDriver) Factory(ctx context.Context, k kind.Kind) generic.NodeDriverInterface {
|
||||
switch k {
|
||||
case f3_tree.KindForge:
|
||||
return newForge()
|
||||
case f3_tree.KindOrganizations:
|
||||
return newOrganizations()
|
||||
case f3_tree.KindOrganization:
|
||||
return newOrganization()
|
||||
case f3_tree.KindUsers:
|
||||
return newUsers()
|
||||
case f3_tree.KindUser:
|
||||
return newUser()
|
||||
case f3_tree.KindProjects:
|
||||
return newProjects()
|
||||
// case f3_tree.KindProject:
|
||||
// return newProject()
|
||||
// case f3_tree.KindIssues:
|
||||
// return newIssues()
|
||||
// case f3_tree.KindIssue:
|
||||
// return newIssue()
|
||||
// case f3_tree.KindComments:
|
||||
// return newComments()
|
||||
// case f3_tree.KindComment:
|
||||
// return newComment()
|
||||
// case f3_tree.KindAssets:
|
||||
// return newAssets()
|
||||
// case f3_tree.KindAsset:
|
||||
// return newAsset()
|
||||
// case f3_tree.KindLabels:
|
||||
// return newLabels()
|
||||
// case f3_tree.KindLabel:
|
||||
// return newLabel()
|
||||
// case f3_tree.KindReactions:
|
||||
// return newReactions()
|
||||
// case f3_tree.KindReaction:
|
||||
// return newReaction()
|
||||
// case f3_tree.KindReviews:
|
||||
// return newReviews()
|
||||
// case f3_tree.KindReview:
|
||||
// return newReview()
|
||||
// case f3_tree.KindReviewComments:
|
||||
// return newReviewComments()
|
||||
// case f3_tree.KindReviewComment:
|
||||
// return newReviewComment()
|
||||
// case f3_tree.KindMilestones:
|
||||
// return newMilestones()
|
||||
// case f3_tree.KindMilestone:
|
||||
// return newMilestone()
|
||||
// case f3_tree.KindPullRequests:
|
||||
// return newPullRequests()
|
||||
// case f3_tree.KindPullRequest:
|
||||
// return newPullRequest()
|
||||
// case f3_tree.KindReleases:
|
||||
// return newReleases()
|
||||
// case f3_tree.KindRelease:
|
||||
// return newRelease()
|
||||
case f3_tree.KindTopics:
|
||||
return newTopics()
|
||||
// case f3_tree.KindRepositories:
|
||||
// return newRepositories()
|
||||
// case f3_tree.KindRepository:
|
||||
// return newRepository(ctx)
|
||||
case kind.KindRoot:
|
||||
return newRoot(o.GetTree().(f3_tree.TreeInterface).NewFormat(k))
|
||||
default:
|
||||
panic(fmt.Errorf("unexpected kind %s", k))
|
||||
}
|
||||
}
|
157
forges/gitlab/user.go
Normal file
157
forges/gitlab/user.go
Normal file
|
@ -0,0 +1,157 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// Copyright twenty-panda <twenty-panda@posteo.com>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/f3"
|
||||
"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"
|
||||
"code.forgejo.org/f3/gof3/v3/util"
|
||||
|
||||
"gitlab.com/gitlab-org/api/client-go"
|
||||
)
|
||||
|
||||
type user struct {
|
||||
common
|
||||
gitlabUser *gitlab.User
|
||||
Password string
|
||||
}
|
||||
|
||||
var _ f3_tree.ForgeDriverInterface = &user{}
|
||||
|
||||
func newUser() generic.NodeDriverInterface {
|
||||
return &user{}
|
||||
}
|
||||
|
||||
func (o *user) SetNative(user any) {
|
||||
o.gitlabUser = user.(*gitlab.User)
|
||||
}
|
||||
|
||||
func (o *user) GetNativeID() string {
|
||||
return fmt.Sprintf("%d", o.gitlabUser.ID)
|
||||
}
|
||||
|
||||
func (o *user) NewFormat() f3.Interface {
|
||||
node := o.GetNode()
|
||||
return node.GetTree().(f3_tree.TreeInterface).NewFormat(node.GetKind())
|
||||
}
|
||||
|
||||
func (o *user) ToFormat() f3.Interface {
|
||||
if o.gitlabUser == nil {
|
||||
return o.NewFormat()
|
||||
}
|
||||
return &f3.User{
|
||||
Common: f3.NewCommon(fmt.Sprintf("%d", o.gitlabUser.ID)),
|
||||
UserName: o.gitlabUser.Username,
|
||||
Name: o.gitlabUser.Name,
|
||||
Email: o.gitlabUser.Email,
|
||||
IsAdmin: o.gitlabUser.IsAdmin,
|
||||
Password: o.Password,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *user) FromFormat(content f3.Interface) {
|
||||
user := content.(*f3.User)
|
||||
o.gitlabUser = &gitlab.User{
|
||||
ID: int(util.ParseInt(user.GetID())),
|
||||
Username: user.UserName,
|
||||
Name: user.Name,
|
||||
Email: user.Email,
|
||||
IsAdmin: user.IsAdmin,
|
||||
}
|
||||
o.Password = user.Password
|
||||
}
|
||||
|
||||
func (o *user) Get(ctx context.Context) bool {
|
||||
node := o.GetNode()
|
||||
o.Trace("%s", node.GetID())
|
||||
if node.GetID() == id.NilID {
|
||||
panic("GetID() == 0")
|
||||
}
|
||||
user, resp, err := o.getClient().Users.GetUser(node.GetID().Int(), gitlab.GetUsersOptions{})
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
return false
|
||||
}
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("user %v %w", o, err))
|
||||
}
|
||||
o.gitlabUser = user
|
||||
return true
|
||||
}
|
||||
|
||||
func (o *user) Patch(context.Context) {
|
||||
}
|
||||
|
||||
func (o *user) Put(context.Context) id.NodeID {
|
||||
skipConfirmation := true
|
||||
|
||||
if o.Password == "" {
|
||||
o.Password = util.RandSeq(30)
|
||||
}
|
||||
|
||||
u, _, err := o.getClient().Users.CreateUser(&gitlab.CreateUserOptions{
|
||||
Username: &o.gitlabUser.Username,
|
||||
Name: &o.gitlabUser.Name,
|
||||
Email: &o.gitlabUser.Email,
|
||||
Password: &o.Password,
|
||||
Admin: &o.gitlabUser.IsAdmin,
|
||||
SkipConfirmation: &skipConfirmation,
|
||||
})
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("%v: %w", o.gitlabUser, err))
|
||||
}
|
||||
o.gitlabUser = u
|
||||
o.Trace("%s %d", o.gitlabUser.Username, o.gitlabUser.ID)
|
||||
return id.NewNodeID(u.ID)
|
||||
}
|
||||
|
||||
func (o *user) deleteUser(ctx context.Context) int {
|
||||
u := fmt.Sprintf("users/%d", o.gitlabUser.ID)
|
||||
|
||||
type deleteUserOptions struct {
|
||||
HardDelete *bool `url:"hard_delete,omitempty" json:"hard_delete,omitempty"`
|
||||
}
|
||||
|
||||
hardDelete := true
|
||||
req, err := o.getClient().NewRequest(http.MethodDelete, u, &deleteUserOptions{
|
||||
HardDelete: &hardDelete,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("NewRequest: %v %v: %w", o.gitlabUser.ID, o.gitlabUser.Username, err))
|
||||
}
|
||||
resp, err := o.getClient().Do(req, nil)
|
||||
if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusNotFound {
|
||||
panic(fmt.Errorf("unexpected status code: %v %v: %v %w", o.gitlabUser.ID, o.gitlabUser.Username, resp.StatusCode, err))
|
||||
}
|
||||
if resp.StatusCode != http.StatusNotFound && err != nil {
|
||||
panic(fmt.Errorf("Do: %v %v: %w", o.gitlabUser.ID, o.gitlabUser.Username, err))
|
||||
}
|
||||
return resp.StatusCode
|
||||
}
|
||||
|
||||
func (o *user) Delete(ctx context.Context) {
|
||||
o.Trace("%s %d", o.gitlabUser.Username, o.gitlabUser.ID)
|
||||
statusCode := o.deleteUser(ctx)
|
||||
if statusCode != http.StatusNoContent {
|
||||
panic(fmt.Errorf("expected user deletion to return 204 but got %d", statusCode))
|
||||
}
|
||||
loop := 100
|
||||
for i := 0; i < loop; i++ {
|
||||
if o.deleteUser(ctx) == http.StatusNotFound {
|
||||
o.Trace("user deletion complete")
|
||||
return
|
||||
}
|
||||
o.Trace("waiting for asynchronous user deletion (%d/%d)", i, loop)
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
o.Trace("user still present after %d attempts", loop)
|
||||
}
|
50
forges/gitlab/users.go
Normal file
50
forges/gitlab/users.go
Normal file
|
@ -0,0 +1,50 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"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"
|
||||
|
||||
"gitlab.com/gitlab-org/api/client-go"
|
||||
)
|
||||
|
||||
type users struct {
|
||||
container
|
||||
}
|
||||
|
||||
func (o *users) ListPage(ctx context.Context, page int) generic.ChildrenSlice {
|
||||
pageSize := o.getPageSize()
|
||||
|
||||
userFounds, _, err := o.getClient().Users.ListUsers(&gitlab.ListUsersOptions{
|
||||
ListOptions: gitlab.ListOptions{Page: page, PerPage: pageSize},
|
||||
})
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("error while listing users: %v", err))
|
||||
}
|
||||
|
||||
return f3_tree.ConvertListed(ctx, o.GetNode(), f3_tree.ConvertToAny(userFounds...)...)
|
||||
}
|
||||
|
||||
func (o *users) GetIDFromName(ctx context.Context, name string) id.NodeID {
|
||||
users, _, err := o.getClient().Users.ListUsers(&gitlab.ListUsersOptions{Username: &name})
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("user %v %w", o, err))
|
||||
}
|
||||
if len(users) == 0 {
|
||||
return id.NilID
|
||||
} else if len(users) > 1 {
|
||||
panic(fmt.Errorf("user %v found multiple users %v", name, users))
|
||||
}
|
||||
return id.NewNodeID(users[0].ID)
|
||||
}
|
||||
|
||||
func newUsers() generic.NodeDriverInterface {
|
||||
return &users{}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue