Skip to content

Commit 4bf3afd

Browse files
authored
cmd/atlas/internal/cmdapi: support multi file schemas in project files (#943)
1 parent e2eac41 commit 4bf3afd

File tree

6 files changed

+88
-24
lines changed

6 files changed

+88
-24
lines changed

cmd/atlas/internal/cmdapi/migrate.go

+9-6
Original file line numberDiff line numberDiff line change
@@ -917,14 +917,17 @@ func migrateFlagsFromEnv(cmd *cobra.Command, _ []string) error {
917917
return err
918918
}
919919
// Transform "src" to a URL.
920-
toURL := activeEnv.Source
921-
if toURL != "" {
922-
if toURL, err = filepath.Abs(activeEnv.Source); err != nil {
923-
return fmt.Errorf("finding abs path to source: %q: %w", activeEnv.Source, err)
920+
srcs, err := activeEnv.Sources()
921+
if err != nil {
922+
return err
923+
}
924+
for i, s := range srcs {
925+
if s, err = filepath.Abs(s); err != nil {
926+
return fmt.Errorf("finding abs path to source: %q: %w", s, err)
924927
}
925-
toURL = "file://" + toURL
928+
srcs[i] = "file://" + s
926929
}
927-
if err := maySetFlag(cmd, migrateFlagTo, toURL); err != nil {
930+
if err := maySetFlag(cmd, migrateFlagTo, strings.Join(srcs, ",")); err != nil {
928931
return err
929932
}
930933
if s := "[" + strings.Join(activeEnv.Schemas, "") + "]"; len(activeEnv.Schemas) > 0 {

cmd/atlas/internal/cmdapi/project.go

+20-5
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ type MigrationDir struct {
4242
func (e *Env) asMap() (map[string]string, error) {
4343
m := make(map[string]string, len(e.Extra.Attrs))
4444
for _, attr := range e.Extra.Attrs {
45+
if attr.K == "src" {
46+
continue
47+
}
4548
if v, err := attr.String(); err == nil {
4649
m[attr.K] = v
4750
continue
@@ -66,9 +69,6 @@ type Env struct {
6669
// See: https://atlasgo.io/dev-database
6770
DevURL string `spec:"dev"`
6871

69-
// Path to the file containing the desired schema of the environment.
70-
Source string `spec:"src"`
71-
7272
// List of schemas in this database that are managed by Atlas.
7373
Schemas []string `spec:"schemas"`
7474

@@ -78,6 +78,21 @@ type Env struct {
7878
schemahcl.DefaultExtension
7979
}
8080

81+
// Sources returns the paths containing the Atlas schema.
82+
func (e *Env) Sources() ([]string, error) {
83+
attr, exists := e.Attr("src")
84+
if !exists {
85+
return nil, nil
86+
}
87+
if s, err := attr.String(); err == nil {
88+
return []string{s}, nil
89+
}
90+
if s, err := attr.Strings(); err == nil {
91+
return s, nil
92+
}
93+
return nil, fmt.Errorf("expected src to be either a string or a string array")
94+
}
95+
8196
var hclState = schemahcl.New(
8297
schemahcl.WithScopedEnums("env.migration_dir.format", formatAtlas, formatFlyway, formatLiquibase, formatGoose, formatGolangMigrate),
8398
)
@@ -108,8 +123,8 @@ func LoadEnv(path string, name string, opts ...LoadOption) (*Env, error) {
108123
if e.URL == "" {
109124
return nil, fmt.Errorf("no url set for env %q", e.Name)
110125
}
111-
if e.Source == "" {
112-
return nil, fmt.Errorf("no src set for env %q", e.Name)
126+
if _, err := e.Sources(); err != nil {
127+
return nil, err
113128
}
114129
projEnvs[e.Name] = e
115130
}

cmd/atlas/internal/cmdapi/project_test.go

+19-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ env "local" {
3737
integer = 42
3838
str = var.name
3939
}
40+
41+
env "multi" {
42+
url = "mysql://root:pass@localhost:3306/"
43+
src = [
44+
"./a.hcl",
45+
"./b.hcl",
46+
]
47+
}
4048
`
4149
err := os.WriteFile(filepath.Join(d, projectFileName), []byte(h), 0600)
4250
require.NoError(t, err)
@@ -52,7 +60,6 @@ env "local" {
5260
Name: "local",
5361
URL: "mysql://root:pass@localhost:3306/",
5462
DevURL: "docker://mysql/8",
55-
Source: "./app.hcl",
5663
Schemas: []string{"hello", "world"},
5764
MigrationDir: &MigrationDir{
5865
URL: "file://migrations",
@@ -63,11 +70,22 @@ env "local" {
6370
Attrs: []*schemahcl.Attr{
6471
{K: "bool", V: &schemahcl.LiteralValue{V: "true"}},
6572
{K: "integer", V: &schemahcl.LiteralValue{V: "42"}},
73+
{K: "src", V: &schemahcl.LiteralValue{V: `"./app.hcl"`}},
6674
{K: "str", V: &schemahcl.LiteralValue{V: `"hello"`}},
6775
},
6876
},
6977
},
7078
}, env)
79+
sources, err := env.Sources()
80+
require.NoError(t, err)
81+
require.EqualValues(t, []string{"./app.hcl"}, sources)
82+
})
83+
t.Run("multi", func(t *testing.T) {
84+
env, err := LoadEnv(path, "multi")
85+
require.NoError(t, err)
86+
srcs, err := env.Sources()
87+
require.NoError(t, err)
88+
require.EqualValues(t, []string{"./a.hcl", "./b.hcl"}, srcs)
7189
})
7290
t.Run("with input", func(t *testing.T) {
7391
env, err := LoadEnv(path, "local", WithInput(map[string]string{

cmd/atlas/internal/cmdapi/schema.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,11 @@ func schemaFlagsFromEnv(cmd *cobra.Command, _ []string) error {
203203
if err := maySetFlag(cmd, devURLFlag, activeEnv.DevURL); err != nil {
204204
return err
205205
}
206-
if err := maySetFlag(cmd, fileFlag, activeEnv.Source); err != nil {
206+
srcs, err := activeEnv.Sources()
207+
if err != nil {
208+
return err
209+
}
210+
if err := maySetFlag(cmd, fileFlag, strings.Join(srcs, "")); err != nil {
207211
return err
208212
}
209213
if s := strings.Join(activeEnv.Schemas, ""); len(activeEnv.Schemas) > 0 {

doc/md/cli/projects.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ environments when working with Atlas. A project file is a file named
1212
```hcl
1313
// Define an environment named "local"
1414
env "local" {
15-
// Declare where the schema definition file resides.
15+
// Declare where the schema definition resides.
16+
// Also supported:
17+
// src = "./dir/with/schema"
18+
// src = ["multi.hcl", "file.hcl"]
1619
src = "./project/schema.hcl"
1720
1821
// Define the URL of the database which is managed in

internal/integration/testdata/sqlite/cli-migrate-project-multifile.txt

+31-10
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
1-
exec mkdir migrations
21
atlas migrate diff --env local
32
cmpmig 0 diff.sql
43

5-
atlas migrate validate --env local
4+
# reset
5+
exec rm -rf migrations
66

7-
atlas migrate new 1 --env local
8-
cmpmig 1 empty.sql
9-
10-
exec touch migrations/2.sql
11-
! atlas migrate validate --env local
12-
stderr 'Error: checksum mismatch'
7+
atlas migrate diff --env src_list
8+
cmpmig 0 diff.sql
139

14-
atlas migrate hash --force --env local
15-
atlas migrate validate --env local
10+
# reset
11+
exec rm -rf migrations
1612

13+
atlas migrate diff --env single_elem
14+
cmpmig 0 diff.sql
1715
-- atlas.hcl --
1816
env "local" {
1917
url = "URL"
@@ -24,6 +22,29 @@ env "local" {
2422
format = atlas
2523
}
2624
}
25+
env "src_list" {
26+
url = "URL"
27+
dev = "sqlite://test?mode=memory&_fk=1"
28+
src = [
29+
"./schema/1.hcl",
30+
"./schema/2.hcl",
31+
]
32+
migration_dir {
33+
url = "file://migrations"
34+
format = atlas
35+
}
36+
}
37+
env "single_elem" {
38+
url = "URL"
39+
dev = "sqlite://test?mode=memory&_fk=1"
40+
src = [
41+
"./schema/",
42+
]
43+
migration_dir {
44+
url = "file://migrations"
45+
format = atlas
46+
}
47+
}
2748
-- schema/1.hcl --
2849
table "users" {
2950
schema = schema.main

0 commit comments

Comments
 (0)