You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
flux2/pkg/git/provider_gitlab.go

148 lines
3.7 KiB
Go

package git
import (
"context"
"fmt"
"github.com/xanzy/go-gitlab"
)
// GitLabProvider represents a GitLab API wrapper
type GitLabProvider struct {
IsPrivate bool
IsPersonal bool
}
const (
GitLabTokenName = "GITLAB_TOKEN"
GitLabDefaultHostname = "gitlab.com"
)
func (p *GitLabProvider) newClient(r *Repository) (*gitlab.Client, error) {
gl, err := gitlab.NewClient(r.Token)
if err != nil {
return nil, err
}
if r.Host != GitLabDefaultHostname {
gl, err = gitlab.NewClient(r.Token, gitlab.WithBaseURL(fmt.Sprintf("https://%s/api/v4", r.Host)))
if err != nil {
return nil, err
}
}
return gl, nil
}
// CreateRepository returns false if the repository already exists
func (p *GitLabProvider) CreateRepository(ctx context.Context, r *Repository) (bool, error) {
gl, err := p.newClient(r)
if err != nil {
return false, fmt.Errorf("client error: %w", err)
}
var id *int
if !p.IsPersonal {
groups, _, err := gl.Groups.ListGroups(&gitlab.ListGroupsOptions{Search: gitlab.String(r.Owner)}, gitlab.WithContext(ctx))
if err != nil {
return false, fmt.Errorf("list groups error: %w", err)
}
if len(groups) > 0 {
id = &groups[0].ID
}
}
visibility := gitlab.PublicVisibility
if p.IsPrivate {
visibility = gitlab.PrivateVisibility
}
projects, _, err := gl.Projects.ListProjects(&gitlab.ListProjectsOptions{Search: gitlab.String(r.Name)}, gitlab.WithContext(ctx))
if err != nil {
return false, fmt.Errorf("list projects error: %w", err)
}
if len(projects) == 0 {
p := &gitlab.CreateProjectOptions{
Name: gitlab.String(r.Name),
NamespaceID: id,
Visibility: &visibility,
InitializeWithReadme: gitlab.Bool(true),
}
_, _, err := gl.Projects.CreateProject(p)
if err != nil {
return false, fmt.Errorf("create project error: %w", err)
}
return true, nil
}
return false, nil
}
// AddTeam returns false if the team is already assigned to the repository
func (p *GitLabProvider) AddTeam(ctx context.Context, r *Repository, name, permission string) (bool, error) {
return false, nil
}
// AddDeployKey returns false if the key exists and the content is the same
func (p *GitLabProvider) AddDeployKey(ctx context.Context, r *Repository, key, keyName string) (bool, error) {
gl, err := p.newClient(r)
if err != nil {
return false, fmt.Errorf("client error: %w", err)
}
// list deploy keys
var projId int
projects, _, err := gl.Projects.ListProjects(&gitlab.ListProjectsOptions{Search: gitlab.String(r.Name)}, gitlab.WithContext(ctx))
if err != nil {
return false, fmt.Errorf("list projects error: %w", err)
}
if len(projects) > 0 {
projId = projects[0].ID
} else {
return false, fmt.Errorf("no project found")
}
// check if the key exists
keys, _, err := gl.DeployKeys.ListProjectDeployKeys(projId, &gitlab.ListProjectDeployKeysOptions{})
if err != nil {
return false, fmt.Errorf("list keys error: %w", err)
}
shouldCreateKey := true
var existingKey *gitlab.DeployKey
for _, k := range keys {
if k.Title == keyName {
if k.Key != key {
existingKey = k
} else {
shouldCreateKey = false
}
break
}
}
// delete existing key if the value differs
if existingKey != nil {
_, err := gl.DeployKeys.DeleteDeployKey(projId, existingKey.ID, gitlab.WithContext(ctx))
if err != nil {
return false, fmt.Errorf("delete key error: %w", err)
}
}
// create key
if shouldCreateKey {
_, _, err := gl.DeployKeys.AddDeployKey(projId, &gitlab.AddDeployKeyOptions{
Title: gitlab.String(keyName),
Key: gitlab.String(key),
CanPush: gitlab.Bool(false),
}, gitlab.WithContext(ctx))
if err != nil {
return false, fmt.Errorf("add key error: %w", err)
}
return true, nil
}
return false, nil
}