Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions .github/azure-devops/action/task.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"migrate test": "Migrate Test",
"monitor schema": "Atlas Schema Monitoring",
"schema apply": "Schema Apply",
"schema inspect": "Schema Inspect",
"schema lint": "Schema Lint",
"schema plan": "Schema Plan",
"schema plan approve": "Schema Plan Approve",
Expand Down Expand Up @@ -132,7 +133,7 @@
"label": "Exclude patterns",
"helpMarkDown": "List of glob patterns used to select which resources to filter in inspection\nsee: https://atlasgo.io/declarative/inspect#exclude-schemas\n",
"name": "exclude",
"visibleRule": "action == monitor schema || action == schema apply || action == schema plan || action == schema plan approve"
"visibleRule": "action == monitor schema || action == schema apply || action == schema inspect || action == schema plan || action == schema plan approve"
},
{
"type": "string",
Expand All @@ -144,6 +145,13 @@
"name": "exec_order",
"visibleRule": "action == migrate apply"
},
{
"type": "string",
"label": "Output format",
"helpMarkDown": "Go template to use to format the output. For example, `{{ sql . }}` outputs the schema as SQL.\n",
"name": "format",
"visibleRule": "action == schema inspect"
},
{
"type": "multiLine",
"label": "Current schema URL",
Expand Down Expand Up @@ -177,7 +185,7 @@
"label": "Include patterns",
"helpMarkDown": "List of glob patterns used to select which resources to keep in inspection\nsee: https://atlasgo.io/declarative/inspect#include-schemas\n",
"name": "include",
"visibleRule": "action == monitor schema || action == schema apply || action == schema plan || action == schema plan approve"
"visibleRule": "action == monitor schema || action == schema apply || action == schema inspect || action == schema plan || action == schema plan approve"
},
{
"type": "boolean",
Expand Down Expand Up @@ -243,7 +251,7 @@
"label": "Database schema(s)",
"helpMarkDown": "List of database schema(s). For example: `public`.\n",
"name": "schema",
"visibleRule": "action == schema apply || action == schema lint || action == schema plan || action == schema plan approve || action == schema push"
"visibleRule": "action == schema apply || action == schema inspect || action == schema lint || action == schema plan || action == schema plan approve || action == schema push"
},
{
"type": "string",
Expand Down Expand Up @@ -309,7 +317,7 @@
"label": "Target database URL",
"helpMarkDown": "The URL of the target database. For example: `mysql://root:pass@localhost:3306/dev`.\n",
"name": "url",
"visibleRule": "action == migrate apply || action == migrate down || action == monitor schema || action == schema apply || action == schema lint || action == schema push || action == schema test"
"visibleRule": "action == migrate apply || action == migrate down || action == monitor schema || action == schema apply || action == schema inspect || action == schema lint || action == schema push || action == schema test"
},
{
"type": "string",
Expand Down Expand Up @@ -337,35 +345,35 @@
"label": "Working directory",
"helpMarkDown": "Atlas working directory. Default is project root",
"name": "working_directory",
"visibleRule": "action == migrate apply || action == migrate autorebase || action == migrate diff || action == migrate down || action == migrate hash || action == migrate lint || action == migrate push || action == migrate test || action == schema apply || action == schema lint || action == schema plan || action == schema plan approve || action == schema push || action == schema test"
"visibleRule": "action == migrate apply || action == migrate autorebase || action == migrate diff || action == migrate down || action == migrate hash || action == migrate lint || action == migrate push || action == migrate test || action == schema apply || action == schema inspect || action == schema lint || action == schema plan || action == schema plan approve || action == schema push || action == schema test"
},
{
"type": "string",
"label": "Atlas config",
"helpMarkDown": "The URL of the Atlas configuration file. By default, Atlas will look for a file\nnamed `atlas.hcl` in the current directory. For example, `file://config/atlas.hcl`.\nLearn more about [Atlas configuration files](https://atlasgo.io/atlas-schema/projects).\n",
"name": "config",
"visibleRule": "action == migrate apply || action == migrate diff || action == migrate down || action == migrate hash || action == migrate lint || action == migrate push || action == migrate test || action == monitor schema || action == schema apply || action == schema lint || action == schema plan || action == schema plan approve || action == schema push || action == schema test"
"visibleRule": "action == migrate apply || action == migrate diff || action == migrate down || action == migrate hash || action == migrate lint || action == migrate push || action == migrate test || action == monitor schema || action == schema apply || action == schema inspect || action == schema lint || action == schema plan || action == schema plan approve || action == schema push || action == schema test"
},
{
"type": "string",
"label": "Environment",
"helpMarkDown": "The environment to use from the Atlas configuration file. For example, `dev`.\n",
"name": "env",
"visibleRule": "action == migrate apply || action == migrate diff || action == migrate down || action == migrate hash || action == migrate lint || action == migrate push || action == migrate test || action == monitor schema || action == schema apply || action == schema lint || action == schema plan || action == schema plan approve || action == schema push || action == schema test"
"visibleRule": "action == migrate apply || action == migrate diff || action == migrate down || action == migrate hash || action == migrate lint || action == migrate push || action == migrate test || action == monitor schema || action == schema apply || action == schema inspect || action == schema lint || action == schema plan || action == schema plan approve || action == schema push || action == schema test"
},
{
"type": "multiLine",
"label": "Variables",
"helpMarkDown": "A JSON object containing variables to be used in the Atlas configuration file.\nFor example, `{\"var1\": \"value1\", \"var2\": \"value2\"}`.\n",
"name": "vars",
"visibleRule": "action == migrate apply || action == migrate diff || action == migrate down || action == migrate lint || action == migrate push || action == migrate test || action == schema apply || action == schema lint || action == schema plan || action == schema plan approve || action == schema push || action == schema test"
"visibleRule": "action == migrate apply || action == migrate diff || action == migrate down || action == migrate lint || action == migrate push || action == migrate test || action == schema apply || action == schema inspect || action == schema lint || action == schema plan || action == schema plan approve || action == schema push || action == schema test"
},
{
"type": "string",
"label": "Dev database URL",
"helpMarkDown": "The URL of the dev-database to use for analysis. For example: `mysql://root:pass@localhost:3306/dev`.\nRead more about [dev-databases](https://atlasgo.io/concepts/dev-database).\n",
"name": "dev_url",
"visibleRule": "action == migrate diff || action == migrate down || action == migrate lint || action == migrate push || action == migrate test || action == schema apply || action == schema lint || action == schema plan || action == schema plan approve || action == schema push || action == schema test"
"visibleRule": "action == migrate diff || action == migrate down || action == migrate lint || action == migrate push || action == migrate test || action == schema apply || action == schema inspect || action == schema lint || action == schema plan || action == schema plan approve || action == schema push || action == schema test"
},
{
"name": "githubConnection",
Expand Down
43 changes: 43 additions & 0 deletions .github/workflows/ci-go.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,49 @@ jobs:
with:
script: |
core.setFailed('expected test to fail, but it did not')
schema-inspect:
runs-on: ubuntu-latest
env:
ATLAS_ACTION_LOCAL: 1
steps:
- uses: ariga/setup-atlas@v0
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version-file: go.mod
- run: go install ./cmd/atlas-action
env:
CGO_ENABLED: 0
- name: Create test database
run: |
sqlite3 atlasaction/testdata/inspect-test.db "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL);"
- id: inspect
uses: ./schema/inspect
with:
url: "sqlite://atlasaction/testdata/inspect-test.db"
- name: Verify schema output is non-empty
env:
SCHEMA: ${{ steps.inspect.outputs.schema }}
run: test -n "$SCHEMA"
- id: inspect_sql
uses: ./schema/inspect
with:
url: "sqlite://atlasaction/testdata/inspect-test.db"
format: "sql"
- name: Verify SQL format output
env:
SCHEMA: ${{ steps.inspect_sql.outputs.schema }}
run: |
printf '%s' "$SCHEMA" > got.sql
cat > expected.sql <<'EOF'
-- Create "users" table
CREATE TABLE `users` (
`id` integer NULL,
`name` text NOT NULL,
PRIMARY KEY (`id`)
);
EOF
diff expected.sql got.sql
migrate-down:
runs-on: ubuntu-latest
env:
Expand Down
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ To learn more about the recommended way to build workflows, read our guide on
| [ariga/atlas-action/migrate/test](#arigaatlas-actionmigratetest) | CI for database schema changes with Atlas |
| [ariga/atlas-action/monitor/schema](#arigaatlas-actionmonitorschema) | Sync the database schema to Atlas Cloud. |
| [ariga/atlas-action/schema/apply](#arigaatlas-actionschemaapply) | Applies schema changes to a target database |
| [ariga/atlas-action/schema/inspect](#arigaatlas-actionschemainspect) | Inspect a database schema |
| [ariga/atlas-action/schema/lint](#arigaatlas-actionschemalint) | Lint database schema with Atlas |
| [ariga/atlas-action/schema/plan](#arigaatlas-actionschemaplan) | Plan a declarative migration to move from the current state to the desired state |
| [ariga/atlas-action/schema/plan/approve](#arigaatlas-actionschemaplanapprove) | Approve a migration plan by its URL |
Expand Down Expand Up @@ -580,6 +581,33 @@ Apply a declarative migrations to a database.

* `error` - The error message if the action fails.

### `ariga/atlas-action/schema/inspect`

Inspect a database schema.

#### Inputs

* `url` - The URL of the database to inspect. For example: `mysql://root:pass@localhost:3306/db`.
* `exclude` - List of glob patterns used to select which resources to filter in inspection
see: https://atlasgo.io/declarative/inspect#exclude-schemas
* `format` - Go template to use to format the output. For example, `sql`.
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The format input description is inconsistent with the action metadata and test expectations: here it says the value is a Go template but the example uses sql (which is not a template). Please either change the example to a real template (e.g. {{ sql . }}) or explicitly document that sql is accepted as a shorthand that expands to that template.

Suggested change
* `format` - Go template to use to format the output. For example, `sql`.
* `format` - Go template to use to format the output. For example, `{{ sql . }}`.

Copilot uses AI. Check for mistakes.
* `include` - List of glob patterns used to select which resources to keep in inspection
see: https://atlasgo.io/declarative/inspect#include-schemas
* `schema` - List of database schema(s) to inspect. For example: `public`.
* `working-directory` - Atlas working directory. Default is project root
* `config` - The URL of the Atlas configuration file. By default, Atlas will look for a file
named `atlas.hcl` in the current directory. For example, `file://config/atlas.hcl`.
Learn more about [Atlas configuration files](https://atlasgo.io/atlas-schema/projects).
* `env` - The environment to use from the Atlas configuration file. For example, `dev`.
* `vars` - A JSON object containing variables to be used in the Atlas configuration file.
For example, `{"var1": "value1", "var2": "value2"}`.
* `dev-url` - The URL of the dev-database to use for analysis. For example: `mysql://root:pass@localhost:3306/dev`.
Read more about [dev-databases](https://atlasgo.io/concepts/dev-database).

#### Outputs

* `schema` - The inspected schema of the database.

### `ariga/atlas-action/schema/lint`

Lint database schema with Atlas.
Expand Down
2 changes: 1 addition & 1 deletion VERSION.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v1.14.2
v1.14.3
25 changes: 25 additions & 0 deletions atlasaction/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ const (
CmdSchemaPlan = "schema/plan"
CmdSchemaPlanApprove = "schema/plan/approve"
CmdSchemaApply = "schema/apply"
CmdSchemaInspect = "schema/inspect"
// Monitoring Commands
CmdMonitorSchema = "monitor/schema"
// Copilot Commands
Expand Down Expand Up @@ -387,6 +388,8 @@ func (a *Actions) Run(ctx context.Context, act string) error {
return a.SchemaPlanApprove(ctx)
case CmdSchemaApply:
return a.SchemaApply(ctx)
case CmdSchemaInspect:
return a.SchemaInspect(ctx)
case CmdMonitorSchema:
return a.MonitorSchema(ctx)
case CmdCopilot:
Expand Down Expand Up @@ -1006,6 +1009,28 @@ func (a *Actions) SchemaTest(ctx context.Context) error {
return nil
}

// SchemaInspect runs the GitHub Action for "ariga/atlas-action/schema/inspect"
func (a *Actions) SchemaInspect(ctx context.Context) error {
params := &atlasexec.SchemaInspectParams{
ConfigURL: a.GetConfigURL(),
DevURL: a.GetInput("dev-url"),
Env: a.GetInput("env"),
Exclude: a.GetArrayInput("exclude"),
Format: a.GetInput("format"),
Include: a.GetArrayInput("include"),
Schema: a.GetArrayInput("schema"),
URL: a.GetInput("url"),
Vars: a.GetVarsInput("vars"),
}
result, err := a.Atlas.SchemaInspect(ctx, params)
if err != nil {
return fmt.Errorf("`atlas schema inspect` completed with errors:\n%s", err)
}
a.SetOutput("schema", result)
a.Infof("`atlas schema inspect` completed successfully")
return nil
}

// SchemaPlan runs the GitHub Action for "ariga/atlas-action/schema/plan"
func (a *Actions) SchemaPlan(ctx context.Context) error {
tc, err := a.GetTriggerContext(ctx)
Expand Down
84 changes: 84 additions & 0 deletions atlasaction/action_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1389,6 +1389,90 @@ func TestSchemaTest(t *testing.T) {
})
}

func TestSchemaInspect(t *testing.T) {
t.Run("all inputs", func(t *testing.T) {
c, err := atlasexec.NewClient("", "./mock-atlas.sh")
require.NoError(t, err)
require.NoError(t, c.SetEnv(map[string]string{
"TEST_ARGS": "schema inspect --env test --config file://testdata/config/atlas.hcl --url sqlite://file?mode=memory --dev-url sqlite://dev?mode=memory --format {{ sql . }} --schema public,private --exclude internal --include users --var var1=value1 --var var2=value2",
"TEST_STDOUT": `CREATE TABLE users (id int NOT NULL);`,
}))
tt := newT(t, nil)
tt.cli = c
tt.setInput("url", "sqlite://file?mode=memory")
tt.setInput("dev-url", "sqlite://dev?mode=memory")
tt.setInput("format", "{{ sql . }}")
tt.setInput("config", "file://testdata/config/atlas.hcl")
tt.setInput("env", "test")
tt.setInput("schema", "public\nprivate")
tt.setInput("exclude", "internal")
tt.setInput("include", "users")
tt.setInput("vars", `{"var1": "value1", "var2": "value2"}`)
require.NoError(t, tt.newActs(t).SchemaInspect(context.Background()))
outputs, err := tt.outputs()
require.NoError(t, err)
require.Equal(t, "CREATE TABLE users (id int NOT NULL);", outputs["schema"])
})
t.Run("with mock atlas", func(t *testing.T) {
m := &mockAtlas{}
m.schemaInspect = func(_ context.Context, p *atlasexec.SchemaInspectParams) (string, error) {
require.Equal(t, "test", p.Env)
require.Equal(t, "file://testdata/config/atlas.hcl", p.ConfigURL)
require.Equal(t, "sqlite://file?mode=memory", p.DevURL)
require.Equal(t, "sqlite://db?mode=memory", p.URL)
require.Equal(t, "{{ sql . }}", p.Format)
require.Equal(t, []string{"public"}, p.Schema)
require.Equal(t, []string{"internal"}, p.Exclude)
require.Equal(t, []string{"users"}, p.Include)
return `CREATE TABLE users (id int NOT NULL);`, nil
}
act := &mockAction{
inputs: map[string]string{
"url": "sqlite://db?mode=memory",
"dev-url": "sqlite://file?mode=memory",
"format": "{{ sql . }}",
"schema": "public",
"exclude": "internal",
"include": "users",
"config": "file://testdata/config/atlas.hcl",
"env": "test",
"vars": `{"var1": "value1", "var2": "value2"}`,
},
output: map[string]string{},
logger: slog.New(slog.NewTextHandler(io.Discard, nil)),
}
a, err := atlasaction.New(
atlasaction.WithAction(act),
atlasaction.WithAtlas(m),
)
require.NoError(t, err)
err = a.SchemaInspect(context.Background())
require.NoError(t, err)
require.Equal(t, "CREATE TABLE users (id int NOT NULL);", act.output["schema"])
})
t.Run("error", func(t *testing.T) {
m := &mockAtlas{}
m.schemaInspect = func(_ context.Context, p *atlasexec.SchemaInspectParams) (string, error) {
return "", errors.New("connection refused")
}
act := &mockAction{
inputs: map[string]string{
"url": "sqlite://db?mode=memory",
},
output: map[string]string{},
logger: slog.New(slog.NewTextHandler(io.Discard, nil)),
}
a, err := atlasaction.New(
atlasaction.WithAction(act),
atlasaction.WithAtlas(m),
)
require.NoError(t, err)
err = a.SchemaInspect(context.Background())
require.ErrorContains(t, err, "connection refused")
require.Empty(t, act.output["schema"])
})
}

func TestMigrateE2E(t *testing.T) {
type (
pushDir struct {
Expand Down
27 changes: 27 additions & 0 deletions atlasaction/manifest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,33 @@ actions:
url:
type: string
description: The URL of the pushed schema version.
- id: schema/inspect
description: Inspect a database schema
name: Schema Inspect
inputs:
<<: *schemaInputs
url:
type: string
label: Database URL
description: |
The URL of the database to inspect. For example: `mysql://root:pass@localhost:3306/db`.
include: *inspectInclude
exclude: *inspectExclude
schema:
type: string
multiLine: true
label: Database schema(s)
description: |
List of database schema(s) to inspect. For example: `public`.
format:
type: string
label: Output format
description: |
Go template to use to format the output. For example, `{{ sql . }}` outputs the schema as SQL.
outputs:
schema:
type: string
description: The inspected schema of the database.
- id: schema/test
description: Run schema tests against the desired schema
name: Schema Test
Expand Down
29 changes: 29 additions & 0 deletions atlasaction/testdata/github/schema-inspect.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Mock the atlas command outputs
env ATLAS_PATH=$MOCK_ATLAS TEST_BATCH=./schema-inspect
# Setup the action input variables
env INPUT_CONFIG=file://testdata/config/atlas.hcl
env INPUT_ENV=test
env INPUT_VARS='{"var1":"value1","var2":"value2"}'
env INPUT_DEV-URL=sqlite://file?mode=memory
env INPUT_URL=sqlite://db?mode=memory
env INPUT_FORMAT=sql

atlas-action --action=schema/inspect
stdout '`atlas schema inspect` completed successfully'
output expected-output.txt

! atlas-action --action=schema/inspect
stdout '::error::`atlas schema inspect` completed with errors:%0AFailure'

-- expected-output.txt --
schema<<_GitHubActionsFileCommandDelimeter_
CREATE TABLE users (id int NOT NULL);
_GitHubActionsFileCommandDelimeter_
-- schema-inspect/1/args --
schema inspect --env test --config file://testdata/config/atlas.hcl --url sqlite://db?mode=memory --dev-url sqlite://file?mode=memory --format {{ sql . }} --var var1=value1 --var var2=value2
-- schema-inspect/1/stdout --
CREATE TABLE users (id int NOT NULL);
-- schema-inspect/2/args --
schema inspect --env test --config file://testdata/config/atlas.hcl --url sqlite://db?mode=memory --dev-url sqlite://file?mode=memory --format {{ sql . }} --var var1=value1 --var var2=value2
-- schema-inspect/2/stderr --
Failure
Loading
Loading