From 3a1c94799be10b839fcc2e3aeb83e1431302066d Mon Sep 17 00:00:00 2001 From: Ronen Lubin <63970571+ronenlu@users.noreply.github.com> Date: Mon, 6 May 2024 10:08:50 +0300 Subject: [PATCH] gen: ask user if he manages single schema or multiple (#329) --- gen/gen.go | 1 + gen/gen_test.go | 5 + gen/services.tmpl | 24 +++ gen/testdata/clickhouse.yml | 4 +- gen/testdata/mariadb.yml | 4 +- gen/testdata/mysql.yml | 4 +- gen/testdata/mysql_schema_scope.yml | 53 ++++++ gen/testdata/postgres.yml | 4 +- gen/testdata/postgres_schema_scope.yml | 53 ++++++ main.go | 24 +-- main_test.go | 251 +++++++++++++++---------- prompt.go | 18 ++ 12 files changed, 322 insertions(+), 123 deletions(-) create mode 100644 gen/testdata/mysql_schema_scope.yml create mode 100644 gen/testdata/postgres_schema_scope.yml diff --git a/gen/gen.go b/gen/gen.go index 988cd07..226f32f 100644 --- a/gen/gen.go +++ b/gen/gen.go @@ -21,6 +21,7 @@ type ( ConfigPath string Env string CreateDevURL bool + SchemaScope bool } ) diff --git a/gen/gen_test.go b/gen/gen_test.go index aadb469..90b76fa 100644 --- a/gen/gen_test.go +++ b/gen/gen_test.go @@ -23,6 +23,7 @@ func TestGen(t *testing.T) { SecretName: "ATLAS_CLOUD_TOKEN", Driver: name, CreateDevURL: true, + SchemaScope: false, } if strings.Contains(name, "atlas_config") { cfg.Driver = strings.Split(name, "_")[0] @@ -30,6 +31,10 @@ func TestGen(t *testing.T) { cfg.Env = "dev" cfg.CreateDevURL = false } + if strings.Contains(name, "schema_scope") { + cfg.Driver = strings.Split(name, "_")[0] + cfg.SchemaScope = true + } actual, err := Generate(cfg) require.NoError(t, err) require.Equal(t, strings.TrimSpace(string(expected)), strings.TrimSpace(string(actual))) diff --git a/gen/services.tmpl b/gen/services.tmpl index 07bfe69..1f85ad7 100644 --- a/gen/services.tmpl +++ b/gen/services.tmpl @@ -85,18 +85,42 @@ {{- define "UseServices" }} {{- if eq .Driver "mysql" -}} + {{- if .SchemaScope -}} dev-url: 'mysql://root:pass@localhost:3306/dev' + {{- else -}} + dev-url: 'mysql://root:pass@localhost:3306' + {{- end -}} {{- else if eq .Driver "postgres" -}} + {{- if .SchemaScope -}} dev-url: 'postgres://postgres:pass@localhost:5432/dev?search_path=public&sslmode=disable' + {{- else -}} + dev-url: 'postgres://postgres:pass@localhost:5432/dev?sslmode=disable' + {{- end -}} {{- else if eq .Driver "postgis" -}} + {{- if .SchemaScope -}} + dev-url: 'docker://postgis/latest/postgres?search_path=public' + {{- else -}} dev-url: 'docker://postgis/latest/dev' + {{- end -}} {{- else if eq .Driver "mariadb" -}} + {{- if .SchemaScope -}} dev-url: 'maria://root:pass@localhost:3306/dev' + {{- else -}} + dev-url: 'maria://root:pass@localhost:3306' + {{- end -}} {{- else if eq .Driver "sqlite" -}} dev-url: 'sqlite://dev?mode=memory' {{- else if eq .Driver "clickhouse" -}} + {{- if .SchemaScope -}} dev-url: 'clickhouse://root:pass@localhost:9000/test' + {{- else -}} + dev-url: 'clickhouse://root:pass@localhost:9000' + {{- end -}} {{- else if eq .Driver "mssql" -}} + {{- if .SchemaScope -}} + dev-url: 'sqlserver://sa:P@ssw0rd0995@localhost:1433/test?mode=schema' + {{- else -}} dev-url: 'sqlserver://sa:P@ssw0rd0995@localhost:1433/test' + {{- end -}} {{- end -}} {{- end -}} \ No newline at end of file diff --git a/gen/testdata/clickhouse.yml b/gen/testdata/clickhouse.yml index 4cae5de..622a5af 100644 --- a/gen/testdata/clickhouse.yml +++ b/gen/testdata/clickhouse.yml @@ -43,7 +43,7 @@ jobs: with: dir: 'file://migrations' dir-name: 'name' - dev-url: 'clickhouse://root:pass@localhost:9000/test' + dev-url: 'clickhouse://root:pass@localhost:9000' env: GITHUB_TOKEN: ${{ github.token }} - uses: ariga/atlas-action/migrate/push@v1 @@ -51,4 +51,4 @@ jobs: with: dir: 'file://migrations' dir-name: 'name' - dev-url: 'clickhouse://root:pass@localhost:9000/test' + dev-url: 'clickhouse://root:pass@localhost:9000' diff --git a/gen/testdata/mariadb.yml b/gen/testdata/mariadb.yml index 1ddf9ac..1da5473 100644 --- a/gen/testdata/mariadb.yml +++ b/gen/testdata/mariadb.yml @@ -42,7 +42,7 @@ jobs: with: dir: 'file://migrations' dir-name: 'name' - dev-url: 'maria://root:pass@localhost:3306/dev' + dev-url: 'maria://root:pass@localhost:3306' env: GITHUB_TOKEN: ${{ github.token }} - uses: ariga/atlas-action/migrate/push@v1 @@ -50,4 +50,4 @@ jobs: with: dir: 'file://migrations' dir-name: 'name' - dev-url: 'maria://root:pass@localhost:3306/dev' + dev-url: 'maria://root:pass@localhost:3306' diff --git a/gen/testdata/mysql.yml b/gen/testdata/mysql.yml index 81ef522..58589a5 100644 --- a/gen/testdata/mysql.yml +++ b/gen/testdata/mysql.yml @@ -42,7 +42,7 @@ jobs: with: dir: 'file://migrations' dir-name: 'name' - dev-url: 'mysql://root:pass@localhost:3306/dev' + dev-url: 'mysql://root:pass@localhost:3306' env: GITHUB_TOKEN: ${{ github.token }} - uses: ariga/atlas-action/migrate/push@v1 @@ -50,4 +50,4 @@ jobs: with: dir: 'file://migrations' dir-name: 'name' - dev-url: 'mysql://root:pass@localhost:3306/dev' + dev-url: 'mysql://root:pass@localhost:3306' diff --git a/gen/testdata/mysql_schema_scope.yml b/gen/testdata/mysql_schema_scope.yml new file mode 100644 index 0000000..81ef522 --- /dev/null +++ b/gen/testdata/mysql_schema_scope.yml @@ -0,0 +1,53 @@ +name: Atlas +on: + push: + branches: + - master + paths: + - .github/workflows/ci-atlas.yaml + - 'migrations/*' + pull_request: + paths: + - 'migrations/*' +# Permissions to write comments on the pull request. +permissions: + contents: read + pull-requests: write +jobs: + atlas: + services: + # Spin up a mysql:8 container to be used as the dev-database for analysis. + mysql: + image: mysql:8 + env: + MYSQL_DATABASE: dev + MYSQL_ROOT_PASSWORD: pass + ports: + - 3306:3306 + options: >- + --health-cmd "mysqladmin ping -ppass" + --health-interval 10s + --health-start-period 10s + --health-timeout 5s + --health-retries 10 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - uses: ariga/setup-atlas@v0 + with: + cloud-token: ${{ secrets.ATLAS_CLOUD_TOKEN }} + - uses: ariga/atlas-action/migrate/lint@v1 + with: + dir: 'file://migrations' + dir-name: 'name' + dev-url: 'mysql://root:pass@localhost:3306/dev' + env: + GITHUB_TOKEN: ${{ github.token }} + - uses: ariga/atlas-action/migrate/push@v1 + if: github.ref == 'refs/heads/master' + with: + dir: 'file://migrations' + dir-name: 'name' + dev-url: 'mysql://root:pass@localhost:3306/dev' diff --git a/gen/testdata/postgres.yml b/gen/testdata/postgres.yml index 467a1e7..447ec35 100644 --- a/gen/testdata/postgres.yml +++ b/gen/testdata/postgres.yml @@ -42,7 +42,7 @@ jobs: with: dir: 'file://migrations' dir-name: 'name' - dev-url: 'postgres://postgres:pass@localhost:5432/dev?search_path=public&sslmode=disable' + dev-url: 'postgres://postgres:pass@localhost:5432/dev?sslmode=disable' env: GITHUB_TOKEN: ${{ github.token }} - uses: ariga/atlas-action/migrate/push@v1 @@ -50,4 +50,4 @@ jobs: with: dir: 'file://migrations' dir-name: 'name' - dev-url: 'postgres://postgres:pass@localhost:5432/dev?search_path=public&sslmode=disable' + dev-url: 'postgres://postgres:pass@localhost:5432/dev?sslmode=disable' diff --git a/gen/testdata/postgres_schema_scope.yml b/gen/testdata/postgres_schema_scope.yml new file mode 100644 index 0000000..467a1e7 --- /dev/null +++ b/gen/testdata/postgres_schema_scope.yml @@ -0,0 +1,53 @@ +name: Atlas +on: + push: + branches: + - master + paths: + - .github/workflows/ci-atlas.yaml + - 'migrations/*' + pull_request: + paths: + - 'migrations/*' +# Permissions to write comments on the pull request. +permissions: + contents: read + pull-requests: write +jobs: + atlas: + services: + # Spin up a postgres:15 container to be used as the dev-database for analysis. + postgres: + image: postgres:15 + env: + POSTGRES_DB: dev + POSTGRES_PASSWORD: pass + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-start-period 10s + --health-timeout 5s + --health-retries 5 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - uses: ariga/setup-atlas@v0 + with: + cloud-token: ${{ secrets.ATLAS_CLOUD_TOKEN }} + - uses: ariga/atlas-action/migrate/lint@v1 + with: + dir: 'file://migrations' + dir-name: 'name' + dev-url: 'postgres://postgres:pass@localhost:5432/dev?search_path=public&sslmode=disable' + env: + GITHUB_TOKEN: ${{ github.token }} + - uses: ariga/atlas-action/migrate/push@v1 + if: github.ref == 'refs/heads/master' + with: + dir: 'file://migrations' + dir-name: 'name' + dev-url: 'postgres://postgres:pass@localhost:5432/dev?search_path=public&sslmode=disable' diff --git a/main.go b/main.go index 3ed0cbc..cc071ac 100644 --- a/main.go +++ b/main.go @@ -52,17 +52,18 @@ var cli struct { // InitActionCmd is the command for initializing a new Atlas CI workflow. type InitActionCmd struct { - DirPath string `arg:"" optional:"" type:"-path" help:"Path inside repository containing the migration files."` - Driver string `enum:"mysql,postgres,postgis,mariadb,sqlite,mssql,clickhouse" default:"mysql" help:"Driver of the migration directory (mysql,postgres,postgis,mariadb,sqlite,mssql,clickhouse)."` - Token string `short:"t" help:"Atlas authentication token."` - Repo string `short:"R" help:"GitHub repository owner/name, defaults to the current repository."` - ConfigPath string `optional:"" help:"Path to atlas.hcl configuration file."` - ConfigEnv string `optional:"" help:"The environment to use from the Atlas configuration file."` - HasDevURL bool `optional:"" help:"Whether the environment config has a dev_url attribute." default:"false"` - DirName string `optional:"" help:"Name of target migration directory in Atlas Cloud."` - Replace bool `optional:"" help:"Replace existing Atlas CI workflow."` - stdin io.ReadCloser `hidden:""` - cloudURL string `hidden:""` + DirPath string `arg:"" optional:"" type:"-path" help:"Path inside repository containing the migration files."` + Driver string `enum:"mysql,postgres,postgis,mariadb,sqlite,mssql,clickhouse" default:"mysql" help:"Driver of the migration directory (mysql,postgres,postgis,mariadb,sqlite,mssql,clickhouse)."` + Token string `short:"t" help:"Atlas authentication token."` + Repo string `short:"R" help:"GitHub repository owner/name, defaults to the current repository."` + ConfigPath string `optional:"" help:"Path to atlas.hcl configuration file."` + ConfigEnv string `optional:"" help:"The environment to use from the Atlas configuration file."` + HasDevURL bool `optional:"" help:"Whether the environment config has a dev_url attribute." default:"false"` + SchemaScope bool `optional:"" help:"Limit the scope of the work done by Atlas (inspection, diffing, etc.) to one schema."` + DirName string `optional:"" help:"Name of target migration directory in Atlas Cloud."` + Replace bool `optional:"" help:"Replace existing Atlas CI workflow."` + stdin io.ReadCloser `hidden:""` + cloudURL string `hidden:""` } func (i *InitActionCmd) Help() string { @@ -139,6 +140,7 @@ func (i *InitActionCmd) Run(ctx context.Context, client *githubClient, current r ConfigPath: i.ConfigPath, Env: i.ConfigEnv, CreateDevURL: !i.HasDevURL, + SchemaScope: i.SchemaScope, } if err = repo.AddAtlasYAML(ctx, cfg, branchName, commitMsg, i.Replace); err != nil { return err diff --git a/main_test.go b/main_test.go index 6e034c7..df4e83e 100644 --- a/main_test.go +++ b/main_test.go @@ -167,60 +167,68 @@ func TestRunInitActionCmd(t *testing.T) { { name: "all arg and flags supplied", cmd: &InitActionCmd{ - DirPath: "migrations", - DirName: "name", - Driver: "mysql", - Token: "token", + DirPath: "migrations", + DirName: "name", + Driver: "mysql", + Token: "token", + SchemaScope: true, }, expected: &InitActionCmd{ - DirPath: "migrations", - DirName: "name", - Driver: "mysql", - Token: "token", + DirPath: "migrations", + DirName: "name", + Driver: "mysql", + Token: "token", + SchemaScope: true, }, }, { name: "no dir path and driver supplied", cmd: &InitActionCmd{ - Token: "token", - DirName: "name", + Token: "token", + DirName: "name", + SchemaScope: true, }, prompt: "\n\n", expected: &InitActionCmd{ - DirPath: "migrations", - DirName: "name", - Driver: "mysql", - Token: "token", + DirPath: "migrations", + DirName: "name", + Driver: "mysql", + Token: "token", + SchemaScope: true, }, }, { name: "no dir path supplied, choose manual dir path", cmd: &InitActionCmd{ - Token: "token", - DirName: "name", + Token: "token", + DirName: "name", + SchemaScope: true, }, // enter, arrow key down, enter, `dir/migrations`, enter prompt: "\n\x1b[B\n`dir/migrations`\n\n", expected: &InitActionCmd{ - DirPath: "`dir/migrations`", - DirName: "name", - Driver: "mysql", - Token: "token", + DirPath: "`dir/migrations`", + DirName: "name", + Driver: "mysql", + Token: "token", + SchemaScope: true, }, }, { name: "no dir name supplied use cloud dir name", cmd: &InitActionCmd{ - DirPath: "migrations", - Driver: "mysql", - Token: "token", + DirPath: "migrations", + Driver: "mysql", + Token: "token", + SchemaScope: true, }, prompt: "\n\n", expected: &InitActionCmd{ - DirPath: "migrations", - DirName: "name", - Driver: "mysql", - Token: "token", + DirPath: "migrations", + DirName: "name", + Driver: "mysql", + Token: "token", + SchemaScope: true, }, }, { @@ -245,61 +253,52 @@ func TestRunInitActionCmd(t *testing.T) { { name: "single dir in organization", cmd: &InitActionCmd{ - DirPath: "migrations", - Driver: "mysql", - Token: "token", + DirPath: "migrations", + Driver: "mysql", + Token: "token", + SchemaScope: true, }, expected: &InitActionCmd{ - DirPath: "migrations", - DirName: "name", - Driver: "mysql", - Token: "token", + DirPath: "migrations", + DirName: "name", + Driver: "mysql", + Token: "token", + SchemaScope: true, }, }, { name: "multiple dirs in organization", cmd: &InitActionCmd{ - DirPath: "migrations", - Driver: "mysql", - Token: "multiple", + DirPath: "migrations", + Driver: "mysql", + Token: "multiple", + SchemaScope: true, }, // use arrow key down and then enter prompt: "\x1b[B\n\n", expected: &InitActionCmd{ - DirPath: "migrations", - DirName: "name2", - Driver: "mysql", - Token: "multiple", - }, - }, - { - name: "provide directory name", - cmd: &InitActionCmd{ - DirPath: "migrations", - Driver: "mysql", - DirName: "name", - Token: "multiple", - }, - expected: &InitActionCmd{ - DirPath: "migrations", - DirName: "name", - Driver: "mysql", - Token: "multiple", + DirPath: "migrations", + DirName: "name2", + Driver: "mysql", + Token: "multiple", + SchemaScope: true, }, }, { name: "no token flag supplied", cmd: &InitActionCmd{ - DirPath: "migrations", - DirName: "name", - Driver: "mysql", + DirPath: "migrations", + DirName: "name", + Driver: "mysql", + SchemaScope: true, }, prompt: "token\n", expected: &InitActionCmd{ - DirPath: "migrations", - DirName: "name", - Driver: "mysql", - Token: "token", + DirPath: "migrations", + DirName: "name", + Driver: "mysql", + Token: "token", + SchemaScope: true, }, }, { @@ -337,18 +336,20 @@ func TestRunInitActionCmd(t *testing.T) { client: createGHClient(&mockService{}, &mockService{}), prompt: "my token\n", cmd: &InitActionCmd{ - DirPath: "migrations", - DirName: "name", - Driver: "mysql", - Token: "token", - Replace: true, + DirPath: "migrations", + DirName: "name", + Driver: "mysql", + Token: "token", + Replace: true, + SchemaScope: true, }, expected: &InitActionCmd{ - DirPath: "migrations", - DirName: "name", - Driver: "mysql", - Token: "token", - Replace: true, + DirPath: "migrations", + DirName: "name", + Driver: "mysql", + Token: "token", + Replace: true, + SchemaScope: true, }, }, { @@ -363,21 +364,23 @@ func TestRunInitActionCmd(t *testing.T) { &mockService{hasHclFile: true}), cmd: &InitActionCmd{ - DirPath: "migrations", - DirName: "name", - Driver: "mysql", - Token: "token", + DirPath: "migrations", + DirName: "name", + Driver: "mysql", + Token: "token", + SchemaScope: true, }, // arrow key down and then enter prompt: "\x1b[B\n\n", expected: &InitActionCmd{ - DirPath: "migrations", - DirName: "name", - Driver: "mysql", - Token: "token", - ConfigPath: "", - ConfigEnv: "", - HasDevURL: false, + DirPath: "migrations", + DirName: "name", + Driver: "mysql", + Token: "token", + ConfigPath: "", + ConfigEnv: "", + HasDevURL: false, + SchemaScope: true, }, }, { @@ -392,20 +395,22 @@ func TestRunInitActionCmd(t *testing.T) { &mockService{hasHclFile: true}), cmd: &InitActionCmd{ - DirPath: "migrations", - DirName: "name", - Driver: "mysql", - Token: "token", + DirPath: "migrations", + DirName: "name", + Driver: "mysql", + Token: "token", + SchemaScope: true, }, prompt: "\n\n", expected: &InitActionCmd{ - DirPath: "migrations", - DirName: "name", - Driver: "mysql", - Token: "token", - ConfigPath: "atlas.hcl", - ConfigEnv: "local", - HasDevURL: true, + DirPath: "migrations", + DirName: "name", + Driver: "mysql", + Token: "token", + ConfigPath: "atlas.hcl", + ConfigEnv: "local", + HasDevURL: true, + SchemaScope: true, }, }, { @@ -419,22 +424,59 @@ func TestRunInitActionCmd(t *testing.T) { }`}, &mockService{hasHclFile: true}), + cmd: &InitActionCmd{ + DirPath: "migrations", + DirName: "name", + Driver: "mysql", + Token: "token", + SchemaScope: true, + }, + // arrow key down and then enter + prompt: "\x1b[B\n\n", + expected: &InitActionCmd{ + DirPath: "migrations", + DirName: "name", + Driver: "mysql", + Token: "token", + ConfigPath: "", + ConfigEnv: "", + HasDevURL: false, + SchemaScope: true, + }, + }, + { + name: "select single schema scope", cmd: &InitActionCmd{ DirPath: "migrations", DirName: "name", Driver: "mysql", Token: "token", }, - // arrow key down and then enter + prompt: "\n", + expected: &InitActionCmd{ + DirPath: "migrations", + DirName: "name", + Driver: "mysql", + Token: "token", + SchemaScope: true, + }, + }, + { + name: "select multiple schemas scope", + cmd: &InitActionCmd{ + DirPath: "migrations", + DirName: "name", + Driver: "mysql", + Token: "token", + }, + // arrow key down, enter prompt: "\x1b[B\n\n", expected: &InitActionCmd{ - DirPath: "migrations", - DirName: "name", - Driver: "mysql", - Token: "token", - ConfigPath: "", - ConfigEnv: "", - HasDevURL: false, + DirPath: "migrations", + DirName: "name", + Driver: "mysql", + Token: "token", + SchemaScope: false, }, }, } @@ -466,7 +508,7 @@ func TestRunInitActionCmd(t *testing.T) { } } -func requireCommandsEqual(t *testing.T, a, b *InitActionCmd) { +func requireCommandsEqual(t *testing.T, a, b *InitActionCmd) { require.Equal(t, a.DirPath, b.DirPath) require.Equal(t, a.DirName, b.DirName) require.Equal(t, a.Driver, b.Driver) @@ -475,4 +517,5 @@ func requireCommandsEqual(t *testing.T, a, b *InitActionCmd) { require.Equal(t, a.ConfigEnv, b.ConfigEnv) require.Equal(t, a.HasDevURL, b.HasDevURL) require.Equal(t, a.Replace, b.Replace) + require.Equal(t, a.SchemaScope, b.SchemaScope) } diff --git a/prompt.go b/prompt.go index a2b2de4..3251f95 100644 --- a/prompt.go +++ b/prompt.go @@ -66,6 +66,24 @@ func (i *InitActionCmd) setParams(ctx context.Context, dirs []string, configs [] return err } } + // sqlite has only one schema + if !i.SchemaScope && i.Driver != "sqlite" { + prompt := promptui.Select{ + Label: "Do you manage a single schema or multiple? (used to limit the scope of the work done by Atlas)", + Stdin: i.stdin, + Items: []string{"single", "multiple"}, + } + _, ans, err := prompt.Run() + if err != nil { + return err + } + switch ans { + case "single": + i.SchemaScope = true + case "multiple": + i.SchemaScope = false + } + } if i.Token == "" { prompt := promptui.Prompt{ Label: "Enter Atlas Cloud token",