From 6fd41d855e5838a6a308aab49be58c2f096f2f50 Mon Sep 17 00:00:00 2001 From: Gergely Brautigam <182850+Skarlso@users.noreply.github.com> Date: Tue, 18 Apr 2023 15:24:05 +0200 Subject: [PATCH 1/2] feat: adding CODEOWNERS file using maintainers --- pkg/providers/gitea/gitea.go | 21 +++++++++++ pkg/providers/gogit/gogit.go | 72 ++++++++++++++++++++++++++++++++++-- 2 files changed, 89 insertions(+), 4 deletions(-) diff --git a/pkg/providers/gitea/gitea.go b/pkg/providers/gitea/gitea.go index 9081b8c..2b7ba3a 100644 --- a/pkg/providers/gitea/gitea.go +++ b/pkg/providers/gitea/gitea.go @@ -7,6 +7,7 @@ package gitea import ( "context" "fmt" + "strings" "code.gitea.io/sdk/gitea" v1 "k8s.io/api/core/v1" @@ -88,6 +89,26 @@ func (c *Client) CreateRepository(ctx context.Context, obj mpasv1alpha1.Reposito return fmt.Errorf("failed to create repositroy: %w", err) } + if len(obj.Spec.Maintainers) != 0 { + content := strings.Builder{} + + for _, m := range obj.Spec.Maintainers { + _, _ = content.WriteString(fmt.Sprintf("%s\n", m)) + } + + _, _, err := client.CreateFile(obj.Spec.Owner, obj.Spec.RepositoryName, "CODEOWNERS", gitea.CreateFileOptions{ + FileOptions: gitea.FileOptions{ + Message: "Adding CODEOWNERS file.", + BranchName: "main", + }, + Content: content.String(), + }) + + if err != nil { + return fmt.Errorf("failed to add CODEOWNERS file: %w", err) + } + } + return nil } diff --git a/pkg/providers/gogit/gogit.go b/pkg/providers/gogit/gogit.go index 3ee0620..a5e802c 100644 --- a/pkg/providers/gogit/gogit.go +++ b/pkg/providers/gogit/gogit.go @@ -7,6 +7,7 @@ package gogit import ( "context" "fmt" + "strings" "github.com/fluxcd/go-git-providers/gitprovider" deliveryv1alpha1 "github.com/open-component-model/git-controller/apis/delivery/v1alpha1" @@ -37,15 +38,25 @@ func CreateOrganizationRepository(ctx context.Context, gc gitprovider.Client, do Visibility: &visibility, } + createOpts, err := gitprovider.MakeRepositoryCreateOptions(&gitprovider.RepositoryCreateOptions{AutoInit: gitprovider.BoolVar(true)}) + if err != nil { + return fmt.Errorf("failed to create _create_ options for repository: %w", err) + } + switch spec.ExistingRepositoryPolicy { case mpasv1alpha1.ExistingRepositoryPolicyFail: - if _, err := gc.OrgRepositories().Create(ctx, ref, info); err != nil { + repo, err := gc.OrgRepositories().Create(ctx, ref, info, &createOpts) + if err != nil { return fmt.Errorf("failed to create repository: %w", err) } + if err := createCodeownersFile(ctx, repo, spec.Maintainers); err != nil { + return fmt.Errorf("failed to add CODEOWNERS file: %w", err) + } + logger.Info("successfully created organization repository", "domain", domain, "repository", spec.RepositoryName) case mpasv1alpha1.ExistingRepositoryPolicyAdopt: - _, created, err := gc.OrgRepositories().Reconcile(ctx, ref, info) + repo, created, err := gc.OrgRepositories().Reconcile(ctx, ref, info, &createOpts) if err != nil { return fmt.Errorf("failed to reconcile repository: %w", err) } @@ -53,6 +64,10 @@ func CreateOrganizationRepository(ctx context.Context, gc gitprovider.Client, do if !created { logger.Info("using existing repository", "domain", domain, "repository", spec.RepositoryName) } else { + if err := createCodeownersFile(ctx, repo, spec.Maintainers); err != nil { + return fmt.Errorf("failed to add CODEOWNERS file: %w", err) + } + logger.Info("successfully created organization repository", "domain", domain, "repository", spec.RepositoryName) } default: @@ -84,15 +99,25 @@ func CreateUserRepository(ctx context.Context, gc gitprovider.Client, domain str Visibility: &visibility, } + createOpts, err := gitprovider.MakeRepositoryCreateOptions(&gitprovider.RepositoryCreateOptions{AutoInit: gitprovider.BoolVar(true)}) + if err != nil { + return fmt.Errorf("failed to create _create_ options for repository: %w", err) + } + switch spec.ExistingRepositoryPolicy { case mpasv1alpha1.ExistingRepositoryPolicyFail: - if _, err := gc.UserRepositories().Create(ctx, ref, info); err != nil { + repo, err := gc.UserRepositories().Create(ctx, ref, info, &createOpts) + if err != nil { return fmt.Errorf("failed to create repository: %w", err) } + if err := createCodeownersFile(ctx, repo, spec.Maintainers); err != nil { + return fmt.Errorf("failed to add CODEOWNERS file: %w", err) + } + logger.Info("successfully created user repository", "domain", domain, "repository", spec.RepositoryName) case mpasv1alpha1.ExistingRepositoryPolicyAdopt: - _, created, err := gc.UserRepositories().Reconcile(ctx, ref, info) + repo, created, err := gc.UserRepositories().Reconcile(ctx, ref, info, &createOpts) if err != nil { return fmt.Errorf("failed to reconcile repository: %w", err) } @@ -100,6 +125,10 @@ func CreateUserRepository(ctx context.Context, gc gitprovider.Client, domain str if !created { logger.Info("using existing repository", "domain", domain, "repository", spec.RepositoryName) } else { + if err := createCodeownersFile(ctx, repo, spec.Maintainers); err != nil { + return fmt.Errorf("failed to add CODEOWNERS file: %w", err) + } + logger.Info("successfully created user repository", "domain", domain, "repository", spec.RepositoryName) } default: @@ -194,3 +223,38 @@ func CreateUserPullRequest(ctx context.Context, gc gitprovider.Client, domain, b return nil } + +// Repositories groups together a common functionality of both repository types. +type Repositories interface { + Commits() gitprovider.CommitClient +} + +func createCodeownersFile(ctx context.Context, repo Repositories, maintainers []string) error { + if len(maintainers) == 0 { + return nil + } + + logger := log.FromContext(ctx) + + content := strings.Builder{} + + for _, m := range maintainers { + _, _ = content.WriteString(fmt.Sprintf("%s\n", m)) + } + + files := []gitprovider.CommitFile{ + { + Path: gitprovider.StringVar("CODEOWNERS"), + Content: gitprovider.StringVar(content.String()), + }, + } + + commit, err := repo.Commits().Create(ctx, "main", "adding CODEOWNERS", files) + if err != nil { + return fmt.Errorf("failed to create CODEOWNERS file: %w", err) + } + + logger.Info("successfully added CODEOWNERS", "url", commit.Get().URL) + + return nil +} From bfb00ec368031616658c74cdc2ecb0ff4bef17e9 Mon Sep 17 00:00:00 2001 From: Gergely Brautigam <182850+Skarlso@users.noreply.github.com> Date: Wed, 19 Apr 2023 09:36:27 +0200 Subject: [PATCH 2/2] delete the repository if codeowners file failed to be added --- pkg/providers/gitea/gitea.go | 17 +++++++++++++---- pkg/providers/gogit/gogit.go | 17 +++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/pkg/providers/gitea/gitea.go b/pkg/providers/gitea/gitea.go index 2b7ba3a..b92a114 100644 --- a/pkg/providers/gitea/gitea.go +++ b/pkg/providers/gitea/gitea.go @@ -5,9 +5,11 @@ package gitea import ( + "bytes" "context" + "encoding/base64" + "errors" "fmt" - "strings" "code.gitea.io/sdk/gitea" v1 "k8s.io/api/core/v1" @@ -90,21 +92,28 @@ func (c *Client) CreateRepository(ctx context.Context, obj mpasv1alpha1.Reposito } if len(obj.Spec.Maintainers) != 0 { - content := strings.Builder{} + var content []byte + buffer := bytes.NewBuffer(content) for _, m := range obj.Spec.Maintainers { - _, _ = content.WriteString(fmt.Sprintf("%s\n", m)) + buffer.WriteString(m) } + encoded := base64.StdEncoding.EncodeToString(buffer.Bytes()) + _, _, err := client.CreateFile(obj.Spec.Owner, obj.Spec.RepositoryName, "CODEOWNERS", gitea.CreateFileOptions{ FileOptions: gitea.FileOptions{ Message: "Adding CODEOWNERS file.", BranchName: "main", }, - Content: content.String(), + Content: encoded, }) if err != nil { + if _, derr := client.DeleteRepo(obj.Spec.Owner, obj.Spec.RepositoryName); derr != nil { + err = errors.Join(err, derr) + } + return fmt.Errorf("failed to add CODEOWNERS file: %w", err) } } diff --git a/pkg/providers/gogit/gogit.go b/pkg/providers/gogit/gogit.go index a5e802c..2f98585 100644 --- a/pkg/providers/gogit/gogit.go +++ b/pkg/providers/gogit/gogit.go @@ -6,6 +6,7 @@ package gogit import ( "context" + "errors" "fmt" "strings" @@ -51,6 +52,10 @@ func CreateOrganizationRepository(ctx context.Context, gc gitprovider.Client, do } if err := createCodeownersFile(ctx, repo, spec.Maintainers); err != nil { + if cerr := repo.Delete(ctx); cerr != nil { + err = errors.Join(err, cerr) + } + return fmt.Errorf("failed to add CODEOWNERS file: %w", err) } @@ -65,6 +70,10 @@ func CreateOrganizationRepository(ctx context.Context, gc gitprovider.Client, do logger.Info("using existing repository", "domain", domain, "repository", spec.RepositoryName) } else { if err := createCodeownersFile(ctx, repo, spec.Maintainers); err != nil { + if cerr := repo.Delete(ctx); cerr != nil { + err = errors.Join(err, cerr) + } + return fmt.Errorf("failed to add CODEOWNERS file: %w", err) } @@ -112,6 +121,10 @@ func CreateUserRepository(ctx context.Context, gc gitprovider.Client, domain str } if err := createCodeownersFile(ctx, repo, spec.Maintainers); err != nil { + if cerr := repo.Delete(ctx); cerr != nil { + err = errors.Join(err, cerr) + } + return fmt.Errorf("failed to add CODEOWNERS file: %w", err) } @@ -126,6 +139,10 @@ func CreateUserRepository(ctx context.Context, gc gitprovider.Client, domain str logger.Info("using existing repository", "domain", domain, "repository", spec.RepositoryName) } else { if err := createCodeownersFile(ctx, repo, spec.Maintainers); err != nil { + if cerr := repo.Delete(ctx); cerr != nil { + err = errors.Join(err, cerr) + } + return fmt.Errorf("failed to add CODEOWNERS file: %w", err) }