From 929d638b4a7595b87c1a88e641896582e653ec57 Mon Sep 17 00:00:00 2001 From: Amit Saha Date: Fri, 15 Aug 2025 02:27:40 +0000 Subject: [PATCH] init --- go.mod | 1 + main.go | 40 ++++++++++++++++++++++++++++++-------- yaml_cli.go | 41 +++++++++++++++++++++++++++++++++++++++ yaml_config.go | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ yaml_validate.go | 34 ++++++++++++++++++++++++++++++++ 5 files changed, 158 insertions(+), 8 deletions(-) create mode 100644 yaml_cli.go create mode 100644 yaml_config.go create mode 100644 yaml_validate.go diff --git a/go.mod b/go.mod index 6b9fc0b..a2fa06a 100644 --- a/go.mod +++ b/go.mod @@ -37,4 +37,5 @@ require ( golang.org/x/sys v0.34.0 // indirect golang.org/x/term v0.33.0 // indirect golang.org/x/time v0.12.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/main.go b/main.go index 640a17e..3e13fc8 100644 --- a/main.go +++ b/main.go @@ -25,20 +25,44 @@ var knownServices = map[string]string{ func main() { - c, err := initConfig(os.Args[1:]) - if err != nil { - log.Fatal(err) + args := os.Args[1:] + if len(args) > 0 { + switch args[0] { + case "create-config": + handleCreateConfig(args[1:]) + return + case "validate-config": + handleValidateConfig(args[1:]) + return + case "help", "--help", "-h": + printCreateConfigUsage() + return + } } - err = validateConfig(c) - if err != nil { - log.Fatal(err) + + var c *appConfig + if _, err := os.Stat("gitbackup.yml"); err == nil { + c, err = LoadYAMLConfig("gitbackup.yml") + if err != nil { + log.Fatalf("Failed to load gitbackup.yml: %v", err) + } + if err := validateYAMLConfig("gitbackup.yml"); err != nil { + log.Fatalf("Config validation failed: %v", err) + } + } else { + c, err = initConfig(args) + if err != nil { + log.Fatal(err) + } + err = validateConfig(c) + if err != nil { + log.Fatal(err) + } } client := newClient(c.service, c.gitHostURL) var executionErr error - // TODO implement validation of options so that we don't - // allow multiple operations at one go if c.githubListUserMigrations { handleGithubListUserMigrations(client, c) } else if c.githubCreateUserMigration { diff --git a/yaml_cli.go b/yaml_cli.go new file mode 100644 index 0000000..ddf2ce0 --- /dev/null +++ b/yaml_cli.go @@ -0,0 +1,41 @@ +package main + +import ( + "fmt" + "os" +) + +func printCreateConfigUsage() { + fmt.Println(`Usage: + gitbackup create-config [path] + gitbackup validate-config [path] + + [path] is optional, defaults to ./gitbackup.yml +`) +} + +func handleCreateConfig(args []string) { + path := "gitbackup.yml" + if len(args) > 0 { + path = args[0] + } + err := WriteSampleYAMLConfig(path) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to create config: %v\n", err) + os.Exit(1) + } + fmt.Printf("Sample config written to %s\n", path) +} + +func handleValidateConfig(args []string) { + path := "gitbackup.yml" + if len(args) > 0 { + path = args[0] + } + err := validateYAMLConfig(path) + if err != nil { + fmt.Fprintf(os.Stderr, "Config validation failed: %v\n", err) + os.Exit(1) + } + fmt.Println("Config is valid.") +} diff --git a/yaml_config.go b/yaml_config.go new file mode 100644 index 0000000..0f47ea2 --- /dev/null +++ b/yaml_config.go @@ -0,0 +1,50 @@ +package main + +import ( + "os" + "gopkg.in/yaml.v3" +) + +func LoadYAMLConfig(path string) (*appConfig, error) { + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer f.Close() + + var c appConfig + dec := yaml.NewDecoder(f) + if err := dec.Decode(&c); err != nil { + return nil, err + } + return &c, nil +} + +func WriteSampleYAMLConfig(path string) error { + c := appConfig{ + service: "github", + gitHostURL: "github.com", + backupDir: "./backup", + ignorePrivate: false, + ignoreFork: false, + useHTTPSClone: true, + bare: false, + githubRepoType: "all", + githubNamespaceWhitelist: []string{"user1", "org2"}, + githubCreateUserMigration: false, + githubCreateUserMigrationRetry: true, + githubCreateUserMigrationRetryMax: 5, + githubListUserMigrations: false, + githubWaitForMigrationComplete: true, + gitlabProjectVisibility: "internal", + gitlabProjectMembershipType: "all", + } + f, err := os.Create(path) + if err != nil { + return err + } + defer f.Close() + enc := yaml.NewEncoder(f) + defer enc.Close() + return enc.Encode(c) +} diff --git a/yaml_validate.go b/yaml_validate.go new file mode 100644 index 0000000..4cf7535 --- /dev/null +++ b/yaml_validate.go @@ -0,0 +1,34 @@ +package main + +import ( + "fmt" + "os" +) + +func validateYAMLConfig(path string) error { + c, err := LoadYAMLConfig(path) + if err != nil { + return fmt.Errorf("failed to load config: %w", err) + } + // Validate required fields + if _, ok := knownServices[c.service]; !ok { + return fmt.Errorf("invalid service: %s", c.service) + } + // Check env vars for secrets (example: GITHUB_TOKEN) + if c.service == "github" { + if os.Getenv("GITHUB_TOKEN") == "" { + return fmt.Errorf("GITHUB_TOKEN environment variable not set") + } + } + if c.service == "gitlab" { + if os.Getenv("GITLAB_TOKEN") == "" { + return fmt.Errorf("GITLAB_TOKEN environment variable not set") + } + } + if c.service == "bitbucket" { + if os.Getenv("BITBUCKET_TOKEN") == "" { + return fmt.Errorf("BITBUCKET_TOKEN environment variable not set") + } + } + return nil +}