diff --git a/pkg/providers/gitea/gitea.go b/pkg/providers/gitea/gitea.go index 9081b8c..b92a114 100644 --- a/pkg/providers/gitea/gitea.go +++ b/pkg/providers/gitea/gitea.go @@ -5,7 +5,10 @@ package gitea import ( + "bytes" "context" + "encoding/base64" + "errors" "fmt" "code.gitea.io/sdk/gitea" @@ -88,6 +91,33 @@ 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 { + var content []byte + buffer := bytes.NewBuffer(content) + + for _, m := range obj.Spec.Maintainers { + 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: 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) + } + } + return nil } diff --git a/pkg/providers/gogit/gogit.go b/pkg/providers/gogit/gogit.go index 3ee0620..2f98585 100644 --- a/pkg/providers/gogit/gogit.go +++ b/pkg/providers/gogit/gogit.go @@ -6,7 +6,9 @@ package gogit import ( "context" + "errors" "fmt" + "strings" "github.com/fluxcd/go-git-providers/gitprovider" deliveryv1alpha1 "github.com/open-component-model/git-controller/apis/delivery/v1alpha1" @@ -37,15 +39,29 @@ 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 { + if cerr := repo.Delete(ctx); cerr != nil { + err = errors.Join(err, cerr) + } + + 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 +69,14 @@ 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 { + if cerr := repo.Delete(ctx); cerr != nil { + err = errors.Join(err, cerr) + } + + return fmt.Errorf("failed to add CODEOWNERS file: %w", err) + } + logger.Info("successfully created organization repository", "domain", domain, "repository", spec.RepositoryName) } default: @@ -84,15 +108,29 @@ 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 { + if cerr := repo.Delete(ctx); cerr != nil { + err = errors.Join(err, cerr) + } + + 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 +138,14 @@ 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 { + if cerr := repo.Delete(ctx); cerr != nil { + err = errors.Join(err, cerr) + } + + return fmt.Errorf("failed to add CODEOWNERS file: %w", err) + } + logger.Info("successfully created user repository", "domain", domain, "repository", spec.RepositoryName) } default: @@ -194,3 +240,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 +}