diff --git a/cmd/init.go b/cmd/init.go new file mode 100644 index 00000000..fd9b9ef6 --- /dev/null +++ b/cmd/init.go @@ -0,0 +1,25 @@ +package cmd + +import ( + "github.com/rs/zerolog/log" + "github.com/spf13/cobra" + + "github.com/mykso/myks/internal/myks" +) + +func init() { + cmd := &cobra.Command{ + Use: "init", + Short: "Initialize new myks project", + Long: "Initialize new myks project", + Run: func(cmd *cobra.Command, args []string) { + g := myks.New(".") + + if err := g.Bootstrap(); err != nil { + log.Fatal().Err(err).Msg("Failed to initialize project") + } + }, + } + + rootCmd.AddCommand(cmd) +} diff --git a/internal/myks/assets/env-data.ytt.yaml b/internal/myks/assets/env-data.ytt.yaml new file mode 100644 index 00000000..170cb9b9 --- /dev/null +++ b/internal/myks/assets/env-data.ytt.yaml @@ -0,0 +1,25 @@ +#! This file define a schema for all ytt data files. It can also contain default values. +#! Top-level keys are scopes, e.g. application, argocd, environment, helm. +#! Content of the `application` scope can be freely modified. More scopes can be added. +#! The `environment`, `helm` and `argocd` scopes are used by myks and should not be modified. +#! However, more keys can be added to these scopes. + +#@data/values-schema +--- +#! Add here any application-specific data. +application: {} +environment: + #! Unique identifier of the environment, required by myks. + #@schema/validation min_len=1 + id: "" +#! Configuration of the step that renders Helm charts. +helm: + #! Used by myks. + #! If true, adds `--include-crds` flag to `helm template`. + includeCRDs: true + #! Used by myks. + #! If defined, passed as a value of `--kube-version` for `helm template`. + kubeVersion: "" + #! Used by myks. + #! If defined, passed as a value of `--namespace` for `helm template`. + namespace: "" diff --git a/internal/myks/globe.go b/internal/myks/globe.go index 1ecdee15..77c44fb0 100644 --- a/internal/myks/globe.go +++ b/internal/myks/globe.go @@ -1,6 +1,7 @@ package myks import ( + _ "embed" "fmt" "io" "io/fs" @@ -11,6 +12,9 @@ import ( "github.com/rs/zerolog/log" ) +//go:embed assets/env-data.ytt.yaml +var dataSchema []byte + // Define the main structure type Globe struct { /// Globe configuration @@ -132,6 +136,57 @@ func (g *Globe) SyncAndRender() error { }) } +// Bootstrap creates the initial directory structure and files +func (g *Globe) Bootstrap() error { + return g.createBaseFileStructure() +} + +func (g *Globe) createBaseFileStructure() error { + envDir := filepath.Join(g.RootDir, g.EnvironmentBaseDir) + protoDir := filepath.Join(g.RootDir, g.PrototypesDir) + renderedDir := filepath.Join(g.RootDir, g.RenderedDir) + dataSchemaFile := filepath.Join(envDir, g.EnvironmentDataFileName) + + log.Debug(). + Str("environments directory", envDir). + Str("prototypes directory", protoDir). + Str("rendered directory", renderedDir). + Str("data schema file", dataSchemaFile). + Msg("Creating base file structure") + + notCleanErr := fmt.Errorf("Target directory is not clean, aborting") + + if _, err := os.Stat(envDir); err == nil { + return notCleanErr + } + if err := os.MkdirAll(envDir, 0o755); err != nil { + return err + } + + if _, err := os.Stat(protoDir); err == nil { + return notCleanErr + } + if err := os.MkdirAll(protoDir, 0o755); err != nil { + return err + } + + if _, err := os.Stat(renderedDir); err == nil { + return notCleanErr + } + if err := os.MkdirAll(renderedDir, 0o755); err != nil { + return err + } + + if _, err := os.Stat(dataSchemaFile); err == nil { + return notCleanErr + } + if err := os.WriteFile(dataSchemaFile, dataSchema, 0o644); err != nil { + return err + } + + return nil +} + func (g *Globe) collectEnvironments(searchPaths []string) { if len(searchPaths) == 0 { searchPaths = []string{g.EnvironmentBaseDir}