feat: publish app delivery branches
This commit is contained in:
parent
72fbbca0ac
commit
a45618d704
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/Pingu-Studio/MaidnCLI/internal/bootstrap"
|
||||
"github.com/Pingu-Studio/MaidnCLI/internal/config"
|
||||
"github.com/Pingu-Studio/MaidnCLI/internal/forgejo"
|
||||
"github.com/Pingu-Studio/MaidnCLI/internal/openbao"
|
||||
"github.com/Pingu-Studio/MaidnCLI/internal/ui"
|
||||
"github.com/spf13/cobra"
|
||||
|
|
@ -17,6 +18,7 @@ var bootstrapYes bool
|
|||
var bootstrapPromptDemocraticCSI bool
|
||||
var bootstrapPromptOperationalSecrets bool
|
||||
var bootstrapInitializeOpenBaoRecovery bool
|
||||
var bootstrapPublishAppFrom string
|
||||
|
||||
var bootstrapCmd = &cobra.Command{
|
||||
Use: "bootstrap",
|
||||
|
|
@ -33,11 +35,34 @@ func init() {
|
|||
bootstrapCmd.Flags().BoolVar(&bootstrapPromptDemocraticCSI, "prompt-democratic-csi", false, "Prompt for and save Democratic CSI settings in --config")
|
||||
bootstrapCmd.Flags().BoolVar(&bootstrapPromptOperationalSecrets, "prompt-operational-secrets", false, "Prompt for and encrypt operational secrets for --config")
|
||||
bootstrapCmd.Flags().BoolVar(&bootstrapInitializeOpenBaoRecovery, "initialize-openbao-recovery", false, "Create and save a separate OpenBao recovery age identity for --config")
|
||||
bootstrapCmd.Flags().StringVar(&bootstrapPublishAppFrom, "publish-app-from", "", "Push this app checkout's current branch and create a Forgejo delivery PR")
|
||||
}
|
||||
|
||||
func runBootstrap(cmd *cobra.Command, args []string) error {
|
||||
var cfg config.Config
|
||||
var err error
|
||||
if bootstrapPublishAppFrom != "" {
|
||||
if bootstrapConfigPath == "" {
|
||||
return fmt.Errorf("--publish-app-from requires --config")
|
||||
}
|
||||
cfg, err = config.Load(bootstrapConfigPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
branch, err := forgejo.CurrentBranch(bootstrapPublishAppFrom)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
owner, repo, err := forgejo.RepositoryFromURL(cfg.Delivery.AppRepoURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
manager := forgejo.NewRepoManager(cfg.Git.BaseURL, cfg.Git.Token, owner, cfg.Git.Username, "", "", cfg.Delivery.AppRepoRef, "")
|
||||
if err := manager.PushBranch(bootstrapPublishAppFrom, cfg.Delivery.AppRepoURL, branch); err != nil {
|
||||
return err
|
||||
}
|
||||
return manager.CreatePullRequest(repo, "feat: migrate delivery to Tekton", branch, cfg.Delivery.AppRepoRef)
|
||||
}
|
||||
|
||||
if bootstrapConfigPath != "" {
|
||||
if bootstrapPromptDemocraticCSI || bootstrapPromptOperationalSecrets || bootstrapInitializeOpenBaoRecovery {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
|
@ -163,7 +164,11 @@ func (rm *RepoManager) setupRepository(repoURL, repoName string, existing bool,
|
|||
}
|
||||
|
||||
func (rm *RepoManager) createMigrationPullRequest(repo, branch string) error {
|
||||
body, err := json.Marshal(pullRequestRequest{Title: "feat: bootstrap Maidn CI/CD structure", Head: branch, Base: rm.Branch})
|
||||
return rm.CreatePullRequest(repo, "feat: bootstrap Maidn CI/CD structure", branch, rm.Branch)
|
||||
}
|
||||
|
||||
func (rm *RepoManager) CreatePullRequest(repo, title, head, base string) error {
|
||||
body, err := json.Marshal(pullRequestRequest{Title: title, Head: head, Base: base})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -177,6 +182,40 @@ func (rm *RepoManager) createMigrationPullRequest(repo, branch string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (rm *RepoManager) PushBranch(dir, repoURL, branch string) error {
|
||||
cleanupAskPass, environment, err := rm.gitEnvironment(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cleanupAskPass()
|
||||
return runGit(dir, environment, "push", repoURL, "HEAD:refs/heads/"+branch)
|
||||
}
|
||||
|
||||
func CurrentBranch(dir string) (string, error) {
|
||||
command := exec.Command("git", "branch", "--show-current")
|
||||
command.Dir = dir
|
||||
branch, err := command.Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if value := strings.TrimSpace(string(branch)); value != "" {
|
||||
return value, nil
|
||||
}
|
||||
return "", fmt.Errorf("source repository is in detached HEAD state")
|
||||
}
|
||||
|
||||
func RepositoryFromURL(repoURL string) (string, string, error) {
|
||||
parsed, err := url.Parse(repoURL)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
parts := strings.Split(strings.Trim(strings.TrimSuffix(parsed.Path, ".git"), "/"), "/")
|
||||
if len(parts) < 2 || parts[len(parts)-2] == "" || parts[len(parts)-1] == "" {
|
||||
return "", "", fmt.Errorf("invalid Forgejo repository URL")
|
||||
}
|
||||
return parts[len(parts)-2], parts[len(parts)-1], nil
|
||||
}
|
||||
|
||||
func (rm *RepoManager) EnsureWebhook(repo, webhookURL, authorization string) error {
|
||||
if webhookURL == "" || authorization == "" {
|
||||
return fmt.Errorf("Forgejo webhook URL and authorization are required")
|
||||
|
|
|
|||
|
|
@ -82,6 +82,13 @@ func TestEnsureWebhookCreatesMissingWebhook(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestRepositoryFromURL(t *testing.T) {
|
||||
owner, repo, err := RepositoryFromURL("https://git.example.test/team/app.git")
|
||||
if err != nil || owner != "team" || repo != "app" {
|
||||
t.Fatalf("RepositoryFromURL() = (%q, %q, %v)", owner, repo, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoExistsReturnsFalseOnNotFound(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||||
writer.WriteHeader(http.StatusNotFound)
|
||||
|
|
|
|||
Loading…
Reference in a new issue