Skip to content

Commit

Permalink
schema/plan/approve: distinct action for approve the plan
Browse files Browse the repository at this point in the history
  • Loading branch information
giautm committed Sep 18, 2024
1 parent c58bc5e commit a05facf
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 32 deletions.
105 changes: 73 additions & 32 deletions atlasaction/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,11 @@ const (
CmdMigrateDown = "migrate/down"
CmdMigrateTest = "migrate/test"
// Declarative workflow Commands
CmdSchemaPush = "schema/push"
CmdSchemaTest = "schema/test"
CmdSchemaPlan = "schema/plan"
CmdSchemaApply = "schema/apply"
CmdSchemaPush = "schema/push"
CmdSchemaTest = "schema/test"
CmdSchemaPlan = "schema/plan"
CmdSchemaPlanApprove = "schema/plan/approve"
CmdSchemaApply = "schema/apply"
)

// Run runs the action based on the command name.
Expand Down Expand Up @@ -183,6 +184,8 @@ func (a *Actions) Run(ctx context.Context, act string) error {
return a.SchemaTest(ctx)
case CmdSchemaPlan:
return a.SchemaPlan(ctx)
case CmdSchemaPlanApprove:
return a.SchemaPlanApprove(ctx)
case CmdSchemaApply:
return a.SchemaApply(ctx)
default:
Expand Down Expand Up @@ -492,8 +495,11 @@ func (a *Actions) SchemaTest(ctx context.Context) error {
// SchemaPlan runs the GitHub Action for "ariga/atlas-action/schema/plan"
func (a *Actions) SchemaPlan(ctx context.Context) error {
tc, err := a.GetTriggerContext()
if err != nil {
switch {
case err != nil:
return fmt.Errorf("unable to get the trigger context: %w", err)
case tc.PullRequest == nil:
return fmt.Errorf("the action should be run in a pull request context")
}
var plan *atlasexec.SchemaPlan
params := &atlasexec.SchemaPlanListParams{
Expand All @@ -517,29 +523,8 @@ func (a *Actions) SchemaPlan(ctx context.Context) error {
}
// There are existing plans.
return fmt.Errorf("found multiple schema plans, please approve or delete the existing plans")
// Branch context with no plan
case tc.PullRequest == nil && len(planFiles) == 0:
a.Infof("No schema plan found")
return nil
// Branch context with pending plan
case tc.PullRequest == nil && len(planFiles) == 1:
result, err := a.Atlas.SchemaPlanApprove(ctx, &atlasexec.SchemaPlanApproveParams{
ConfigURL: params.ConfigURL,
Env: params.Env,
Vars: params.Vars,
URL: planFiles[0].URL,
})
if err != nil {
return fmt.Errorf("failed to approve the schema plan: %w", err)
}
// Successfully approved the plan.
a.Infof("Schema plan approved successfully: %s", result.Link)
a.SetOutput("link", result.Link)
a.SetOutput("plan", result.URL)
a.SetOutput("status", result.Status)
return nil
// PR context and existing plan
case tc.PullRequest != nil && len(planFiles) == 1:
case len(planFiles) == 1:
a.Infof("Schema plan already exists, linting the plan %q", planFiles[0].Name)
plan, err = a.Atlas.SchemaPlanLint(ctx, &atlasexec.SchemaPlanLintParams{
ConfigURL: params.ConfigURL,
Expand All @@ -555,12 +540,8 @@ func (a *Actions) SchemaPlan(ctx context.Context) error {
if err != nil {
return fmt.Errorf("failed to get the schema plan: %w", err)
}
// FIXME(giautm): Remove this workaround after fixing the schema URL issue.
plan.File.URL = planFiles[0].URL
plan.File.Link = planFiles[0].Link
plan.File.Status = "PENDING"
// PR context and no existing plan
case tc.PullRequest != nil && len(planFiles) == 0:
case len(planFiles) == 0:
name := a.GetInput("name")
runPlan:
// Dry run if the name is not provided.
Expand Down Expand Up @@ -621,6 +602,66 @@ func (a *Actions) SchemaPlan(ctx context.Context) error {
return nil
}

// SchemaPlanApprove runs the GitHub Action for "ariga/atlas-action/schema/plan/approve"
func (a *Actions) SchemaPlanApprove(ctx context.Context) error {
tc, err := a.GetTriggerContext()
switch {
case err != nil:
return fmt.Errorf("unable to get the trigger context: %w", err)
case tc.PullRequest != nil:
return fmt.Errorf("the action should be run in a branch context")
}
params := &atlasexec.SchemaPlanApproveParams{
ConfigURL: a.GetInput("config"),
Env: a.GetInput("env"),
Vars: a.GetVarsInput("vars"),
URL: a.GetInput("plan"),
}
if params.URL == "" {
a.Infof("No plan URL provided, searching for the pending plan")
switch planFiles, err := a.Atlas.SchemaPlanList(ctx, &atlasexec.SchemaPlanListParams{
ConfigURL: params.ConfigURL,
Env: params.Env,
Vars: params.Vars,
Context: a.GetRunContext(ctx, tc),
Repo: a.GetInput("schema-name"),
DevURL: a.GetInput("dev-url"),
From: a.GetArrayInput("from"),
To: a.GetArrayInput("to"),
Pending: true,
}); {
case err != nil:
return fmt.Errorf("failed to list schema plans: %w", err)
// Multiple existing plans.
case len(planFiles) > 1:
for _, f := range planFiles {
a.Infof("Found schema plan: %s", f.URL)
}
// There are existing plans.
return fmt.Errorf("found multiple schema plans, please approve or delete the existing plans")
// Branch context with no plan
case len(planFiles) == 0:
a.Infof("No schema plan found")
return nil
// Branch context with pending plan
case len(planFiles) == 1:
params.URL = planFiles[0].URL
default:
return fmt.Errorf("unexpected context, please contact the atlas team")
}
}
result, err := a.Atlas.SchemaPlanApprove(ctx, params)
if err != nil {
return fmt.Errorf("failed to approve the schema plan: %w", err)
}
// Successfully approved the plan.
a.Infof("Schema plan approved successfully: %s", result.Link)
a.SetOutput("link", result.Link)
a.SetOutput("plan", result.URL)
a.SetOutput("status", result.Status)
return nil
}

// SchemaApply runs the GitHub Action for "ariga/atlas-action/schema/apply"
func (a *Actions) SchemaApply(ctx context.Context) error {
params := &atlasexec.SchemaApplyParams{
Expand Down
53 changes: 53 additions & 0 deletions schema/plan/approve/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: 'Schema Plan Approve'
description: 'Plan a declarative migration to move from the current state to the desired state'
branding:
icon: database
author: 'Ariga'
inputs:
working-directory:
description: Atlas working directory, default is project root
required: false
config:
description: |
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).
required: false
env:
description: The environment to use from the Atlas configuration file. For example, `dev`.
required: false
vars:
description: |
A JSON object containing variables to be used in the Atlas configuration file.
For example, `{"var1": "value1", "var2": "value2"}`.
required: false
dev-url:
description: |
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).
required: false
plan:
description: |
The URL of the plan to be approved. For example, `atlas://<schema>/plans/<id>`.
required: false
schema-name:
description: The name (slug) of the project in Atlas Cloud.
required: false
from:
description: |
URL(s) of the current schema state.
required: false
to:
description: |
URL(s) of the desired schema state.
required: false
outputs:
plan:
description: The plan to be applied or generated. (ig. `atlas://<schema>/plans/<id>`)
link: # id of the output
description: Link to the schema plan on Atlas.
status:
description: The status of the plan. (ig. `PENDING`, `APPROVED`)
runs:
using: node20
main: index.js
1 change: 1 addition & 0 deletions schema/plan/approve/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require('../../../shim/dist')('schema/plan/approve')

0 comments on commit a05facf

Please sign in to comment.