Skip to content

Commit

Permalink
feat: add hydra migrate status subcommand (#3579)
Browse files Browse the repository at this point in the history
  • Loading branch information
alnr committed Jul 25, 2023
1 parent 425c977 commit 749eb8d
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 6 deletions.
65 changes: 59 additions & 6 deletions cmd/cli/handler_migrate.go
Expand Up @@ -13,7 +13,9 @@ import (
"path/filepath"
"regexp"
"strings"
"time"

"github.com/ory/x/popx"
"github.com/ory/x/servicelocatorx"

"github.com/pkg/errors"
Expand All @@ -28,6 +30,7 @@ import (

"github.com/ory/hydra/v2/driver"
"github.com/ory/hydra/v2/driver/config"
"github.com/ory/hydra/v2/persistence"
"github.com/ory/x/flagx"
)

Expand Down Expand Up @@ -259,7 +262,7 @@ func (h *MigrateHandler) MigrateGen(cmd *cobra.Command, args []string) {
os.Exit(0)
}

func (h *MigrateHandler) MigrateSQL(cmd *cobra.Command, args []string) (err error) {
func makePersister(cmd *cobra.Command, args []string) (p persistence.Persister, err error) {
var d driver.Registry

if flagx.MustGetBool(cmd, "read-from-env") {
Expand All @@ -275,16 +278,16 @@ func (h *MigrateHandler) MigrateSQL(cmd *cobra.Command, args []string) (err erro
driver.SkipNetworkInit(),
})
if err != nil {
return err
return nil, err
}
if len(d.Config().DSN()) == 0 {
_, _ = fmt.Fprintln(cmd.ErrOrStderr(), "When using flag -e, environment variable DSN must be set.")
return cmdx.FailSilently(cmd)
return nil, cmdx.FailSilently(cmd)
}
} else {
if len(args) != 1 {
_, _ = fmt.Fprintln(cmd.ErrOrStderr(), "Please provide the database URL.")
return cmdx.FailSilently(cmd)
return nil, cmdx.FailSilently(cmd)
}
d, err = driver.New(
cmd.Context(),
Expand All @@ -300,11 +303,17 @@ func (h *MigrateHandler) MigrateSQL(cmd *cobra.Command, args []string) (err erro
driver.SkipNetworkInit(),
})
if err != nil {
return err
return nil, err
}
}
return d.Persister(), nil
}

p := d.Persister()
func (h *MigrateHandler) MigrateSQL(cmd *cobra.Command, args []string) (err error) {
p, err := makePersister(cmd, args)
if err != nil {
return err
}
conn := p.Connection(context.Background())
if conn == nil {
_, _ = fmt.Fprintln(cmd.ErrOrStderr(), "Migrations can only be executed against a SQL-compatible driver but DSN is not a SQL source.")
Expand Down Expand Up @@ -349,3 +358,47 @@ func (h *MigrateHandler) MigrateSQL(cmd *cobra.Command, args []string) (err erro
_, _ = fmt.Fprintln(cmd.OutOrStdout(), "Successfully applied migrations!")
return nil
}

func (h *MigrateHandler) MigrateStatus(cmd *cobra.Command, args []string) error {
p, err := makePersister(cmd, args)
if err != nil {
return err
}
conn := p.Connection(context.Background())
if conn == nil {
_, _ = fmt.Fprintln(cmd.ErrOrStderr(), "Migrations can only be checked against a SQL-compatible driver but DSN is not a SQL source.")
return cmdx.FailSilently(cmd)
}

if err := conn.Open(); err != nil {
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Could not open the database connection:\n%+v\n", err)
return cmdx.FailSilently(cmd)
}

block := flagx.MustGetBool(cmd, "block")
ctx := cmd.Context()
s, err := p.MigrationStatus(ctx)
if err != nil {
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Could not get migration status: %+v\n", err)
return cmdx.FailSilently(cmd)
}

for block && s.HasPending() {
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "Waiting for migrations to finish...\n")
for _, m := range s {
if m.State == popx.Pending {
_, _ = fmt.Fprintf(cmd.OutOrStdout(), " - %s\n", m.Name)
}
}
time.Sleep(time.Second)
s, err = p.MigrationStatus(ctx)
if err != nil {
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Could not get migration status: %+v\n", err)
return cmdx.FailSilently(cmd)
}
}

cmdx.PrintTable(cmd, s)
return nil

}
27 changes: 27 additions & 0 deletions cmd/migrate_status.go
@@ -0,0 +1,27 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0

package cmd

import (
"github.com/ory/x/configx"
"github.com/ory/x/servicelocatorx"

"github.com/spf13/cobra"

"github.com/ory/hydra/v2/cmd/cli"
"github.com/ory/hydra/v2/driver"
)

func NewMigrateStatusCmd(slOpts []servicelocatorx.Option, dOpts []driver.OptionsModifier, cOpts []configx.OptionModifier) *cobra.Command {
cmd := &cobra.Command{
Use: "status",
Short: "Get the current migration status",
RunE: cli.NewHandler(slOpts, dOpts, cOpts).Migration.MigrateStatus,
}

cmd.Flags().BoolP("read-from-env", "e", false, "If set, reads the database connection string from the environment variable DSN or config file key dsn.")
cmd.Flags().Bool("block", false, "Block until all migrations have been applied")

return cmd
}
1 change: 1 addition & 0 deletions cmd/root.go
Expand Up @@ -73,6 +73,7 @@ func RegisterCommandRecursive(parent *cobra.Command, slOpts []servicelocatorx.Op
migrateCmd := NewMigrateCmd()
migrateCmd.AddCommand(NewMigrateGenCmd())
migrateCmd.AddCommand(NewMigrateSqlCmd(slOpts, dOpts, cOpts))
migrateCmd.AddCommand(NewMigrateStatusCmd(slOpts, dOpts, cOpts))

serveCmd := NewServeCmd()
serveCmd.AddCommand(NewServeAdminCmd(slOpts, dOpts, cOpts))
Expand Down

0 comments on commit 749eb8d

Please sign in to comment.