139 lines
4.2 KiB
Go
139 lines
4.2 KiB
Go
package forgejo
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/Pingu-Studio/MaidnCLI/internal/utils"
|
|
)
|
|
|
|
type RepoManager struct {
|
|
BaseURL string
|
|
Token string
|
|
Owner string
|
|
Username string
|
|
ManifestsRepoName string
|
|
FluxRepoName string
|
|
}
|
|
|
|
type createRepoRequest struct {
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
Private bool `json:"private"`
|
|
AutoInit bool `json:"auto_init"`
|
|
DefaultBranch string `json:"default_branch"`
|
|
}
|
|
|
|
func NewRepoManager(baseURL, token, owner, username, manifestsRepo, fluxRepo string) *RepoManager {
|
|
return &RepoManager{
|
|
BaseURL: strings.TrimRight(baseURL, "/"),
|
|
Token: token,
|
|
Owner: owner,
|
|
Username: username,
|
|
ManifestsRepoName: manifestsRepo,
|
|
FluxRepoName: fluxRepo,
|
|
}
|
|
}
|
|
|
|
func (rm *RepoManager) InitializeAll(createRepo func(string) error, createFlux func(string) error) error {
|
|
if err := rm.ensureRepo(rm.ManifestsRepoName, "Centralized deployment manifests for Flux CD", createRepo); err != nil {
|
|
return err
|
|
}
|
|
if err := rm.ensureRepo(rm.FluxRepoName, "Flux CD cluster configurations", createFlux); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (rm *RepoManager) ensureRepo(name, description string, createStructure func(string) error) error {
|
|
repoURL := fmt.Sprintf("%s/%s/%s.git", rm.BaseURL, rm.Owner, name)
|
|
apiURL := fmt.Sprintf("%s/api/v1/repos/%s/%s", rm.BaseURL, rm.Owner, name)
|
|
if err := rm.apiRequest(http.MethodGet, apiURL, nil); err != nil {
|
|
createURL := fmt.Sprintf("%s/api/v1/orgs/%s/repos", rm.BaseURL, rm.Owner)
|
|
if rm.Owner == rm.Username {
|
|
createURL = fmt.Sprintf("%s/api/v1/user/repos", rm.BaseURL)
|
|
}
|
|
body, _ := json.Marshal(createRepoRequest{Name: name, Description: description, Private: true, AutoInit: false, DefaultBranch: "main"})
|
|
if apiErr := rm.apiRequest(http.MethodPost, createURL, body); apiErr != nil {
|
|
return apiErr
|
|
}
|
|
}
|
|
return rm.setupRepository(repoURL, name, createStructure)
|
|
}
|
|
|
|
func (rm *RepoManager) setupRepository(repoURL, repoName string, createStructure func(string) error) error {
|
|
tempDir, err := os.MkdirTemp("", "repo-setup-*")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer os.RemoveAll(tempDir)
|
|
if err := utils.RunCommand("git", "clone", repoURL, tempDir); err != nil {
|
|
return err
|
|
}
|
|
if err := utils.RunCommandInDir(tempDir, "git", "checkout", "-B", "main"); err != nil {
|
|
return err
|
|
}
|
|
if err := createStructure(tempDir); err != nil {
|
|
return err
|
|
}
|
|
return commitAndPush(tempDir, repoName)
|
|
}
|
|
|
|
func commitAndPush(tempDir, repoName string) error {
|
|
utils.RunCommandInDir(tempDir, "git", "config", "user.name", "Maidn")
|
|
utils.RunCommandInDir(tempDir, "git", "config", "user.email", "maidn@free-maidn.com")
|
|
utils.RunCommandInDir(tempDir, "git", "add", ".")
|
|
statusCmd := exec.Command("git", "status", "--porcelain")
|
|
statusCmd.Dir = tempDir
|
|
output, _ := statusCmd.Output()
|
|
if len(output) == 0 {
|
|
return nil
|
|
}
|
|
if err := utils.RunCommandInDir(tempDir, "git", "commit", "-m", "feat: initialize repository structure for CI/CD"); err != nil {
|
|
return err
|
|
}
|
|
if err := utils.RunCommandInDir(tempDir, "git", "push", "origin", "main"); err != nil {
|
|
return err
|
|
}
|
|
fmt.Printf("[SUCCESS] Changes pushed to %s successfully.\n", repoName)
|
|
return nil
|
|
}
|
|
|
|
func (rm *RepoManager) apiRequest(method, endpoint string, body []byte) error {
|
|
client := http.Client{Timeout: 15 * time.Second}
|
|
request, err := http.NewRequest(method, endpoint, bytes.NewReader(body))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
request.Header.Set("Authorization", "token "+rm.Token)
|
|
request.Header.Set("Content-Type", "application/json")
|
|
response, err := client.Do(request)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer response.Body.Close()
|
|
if response.StatusCode >= 300 {
|
|
return fmt.Errorf("forgejo returned %s for %s", response.Status, endpoint)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func FluxSourceURL(baseURL, owner, repo string) string {
|
|
return fmt.Sprintf("%s/%s/%s.git", strings.TrimRight(baseURL, "/"), owner, repo)
|
|
}
|
|
|
|
func CloneURL(baseURL, owner, repo string) string {
|
|
return fmt.Sprintf("%s/%s/%s.git", strings.TrimRight(baseURL, "/"), owner, repo)
|
|
}
|
|
|
|
func RepoPath(parent, dirName string) string {
|
|
return filepath.Join(parent, dirName)
|
|
}
|