diff --git a/internal/controller/atlasmigration_controller.go b/internal/controller/atlasmigration_controller.go index 8d4ba9d..13184a4 100644 --- a/internal/controller/atlasmigration_controller.go +++ b/internal/controller/atlasmigration_controller.go @@ -41,6 +41,8 @@ import ( "ariga.io/atlas/sql/migrate" dbv1alpha1 "github.com/ariga/atlas-operator/api/v1alpha1" "github.com/ariga/atlas-operator/internal/controller/watch" + "github.com/hashicorp/hcl/v2/hclwrite" + "github.com/zclconf/go-cty/cty" ) //+kubebuilder:rbac:groups=core,resources=configmaps;secrets,verbs=create;update;delete;get;list;watch @@ -562,7 +564,15 @@ func (d *migrationData) render(w io.Writer) error { default: return errors.New("migration directory is empty") } - return tmpl.ExecuteTemplate(w, "atlas_migration.tmpl", d) + f := hclwrite.NewFile() + fBody := f.Body() + for _, b := range d.asBlocks() { + fBody.AppendBlock(b) + } + if _, err := f.WriteTo(w); err != nil { + return err + } + return nil } // hasRemoteDir returns true if the given migration data has a remote directory @@ -573,6 +583,49 @@ func (c *migrationData) hasRemoteDir() bool { return c.RemoteDir != nil && c.RemoteDir.Name != "" } +// asBlocks returns the HCL blocks for the given migration data +func (d *migrationData) asBlocks() []*hclwrite.Block { + var blocks []*hclwrite.Block + if d.Cloud != nil { + atlas := hclwrite.NewBlock("atlas", nil) + cloud := atlas.Body().AppendNewBlock("cloud", nil).Body() + if d.Cloud.Token != "" { + cloud.SetAttributeValue("token", cty.StringVal(d.Cloud.Token)) + } + if d.Cloud.URL != "" { + cloud.SetAttributeValue("url", cty.StringVal(d.Cloud.URL)) + } + if d.Cloud.Repo != "" { + cloud.SetAttributeValue("project", cty.StringVal(d.Cloud.Repo)) + } + blocks = append(blocks, atlas) + } + env := hclwrite.NewBlock("env", []string{d.EnvName}) + blocks = append(blocks, env) + envBody := env.Body() + if d.URL != nil { + envBody.SetAttributeValue("url", cty.StringVal(d.URL.String())) + } + if d.DevURL != "" { + envBody.SetAttributeValue("dev", cty.StringVal(d.DevURL)) + } + migration := hclwrite.NewBlock("migration", nil) + envBody.AppendBlock(migration) + // env.migration + migrationBody := migration.Body() + migrationBody.SetAttributeValue("dir", cty.StringVal(d.DirURL())) + if d.ExecOrder != "" { + migrationBody.SetAttributeValue("exec_order", cty.StringVal(d.ExecOrder)) + } + if d.Baseline != "" { + migrationBody.SetAttributeValue("baseline", cty.StringVal(d.Baseline)) + } + if d.RevisionsSchema != "" { + migrationBody.SetAttributeValue("revisions_schema", cty.StringVal(d.RevisionsSchema)) + } + return blocks +} + func makeKeyLatest(resName string) string { // Inspired by the helm chart key format const storageKey = "io.atlasgo.db.v1" diff --git a/internal/controller/atlasmigration_controller_test.go b/internal/controller/atlasmigration_controller_test.go index 8f7b3f3..bef7dce 100644 --- a/internal/controller/atlasmigration_controller_test.go +++ b/internal/controller/atlasmigration_controller_test.go @@ -990,27 +990,28 @@ func TestWatcher_enabled(t *testing.T) { func TestDefaultTemplate(t *testing.T) { migrate := &migrationData{ - URL: must(url.Parse("sqlite://file2/?mode=memory")), - DevURL: "sqlite://dev/?mode=memory", + EnvName: defaultEnvName, + URL: must(url.Parse("sqlite://file2/?mode=memory")), + DevURL: "sqlite://dev/?mode=memory", Dir: must(memDir(map[string]string{ "1.sql": "CREATE TABLE foo (id INT PRIMARY KEY);", })), } var fileContent bytes.Buffer require.NoError(t, migrate.render(&fileContent)) - require.EqualValues(t, ` -env { - name = atlas.env - url = "sqlite://file2/?mode=memory" - dev = "sqlite://dev/?mode=memory" + require.EqualValues(t, `env "kubernetes" { + url = "sqlite://file2/?mode=memory" + dev = "sqlite://dev/?mode=memory" migration { dir = "file://migrations" } -}`, fileContent.String()) +} +`, fileContent.String()) } func TestBaselineTemplate(t *testing.T) { migrate := &migrationData{ + EnvName: defaultEnvName, URL: must(url.Parse("sqlite://file2/?mode=memory")), DevURL: "sqlite://dev/?mode=memory", Dir: must(memDir(map[string]string{})), @@ -1018,22 +1019,22 @@ func TestBaselineTemplate(t *testing.T) { } var fileContent bytes.Buffer require.NoError(t, migrate.render(&fileContent)) - require.EqualValues(t, ` -env { - name = atlas.env - url = "sqlite://file2/?mode=memory" - dev = "sqlite://dev/?mode=memory" + require.EqualValues(t, `env "kubernetes" { + url = "sqlite://file2/?mode=memory" + dev = "sqlite://dev/?mode=memory" migration { - dir = "file://migrations" + dir = "file://migrations" baseline = "20230412003626" } -}`, fileContent.String()) +} +`, fileContent.String()) } func TestCloudTemplate(t *testing.T) { migrate := &migrationData{ - URL: must(url.Parse("sqlite://file2/?mode=memory")), - DevURL: "sqlite://dev/?mode=memory", + EnvName: defaultEnvName, + URL: must(url.Parse("sqlite://file2/?mode=memory")), + DevURL: "sqlite://dev/?mode=memory", Cloud: &Cloud{ URL: "https://atlasgo.io/", Repo: "my-project", @@ -1046,22 +1047,21 @@ func TestCloudTemplate(t *testing.T) { } var fileContent bytes.Buffer require.NoError(t, migrate.render(&fileContent)) - require.EqualValues(t, ` -atlas { + require.EqualValues(t, `atlas { cloud { - token = "my-token" - url = "https://atlasgo.io/" + token = "my-token" + url = "https://atlasgo.io/" project = "my-project" } } -env { - name = atlas.env - url = "sqlite://file2/?mode=memory" - dev = "sqlite://dev/?mode=memory" +env "kubernetes" { + url = "sqlite://file2/?mode=memory" + dev = "sqlite://dev/?mode=memory" migration { dir = "atlas://my-remote-dir?tag=my-remote-tag" } -}`, fileContent.String()) +} +`, fileContent.String()) } func TestMigrationWithDeploymentContext(t *testing.T) {