2018-06-24 16:40:48 +03:00
package commands
import (
2018-07-06 08:06:27 +03:00
"bytes"
"fmt"
"text/tabwriter"
2018-06-24 16:40:48 +03:00
2022-11-03 08:54:29 +03:00
"github.com/hasura/graphql-engine/cli/v2/internal/errors"
2021-06-18 09:24:16 +03:00
"github.com/hasura/graphql-engine/cli/v2/internal/hasura"
2021-12-23 18:58:53 +03:00
"github.com/hasura/graphql-engine/cli/v2/internal/metadatautil"
2021-06-18 09:24:16 +03:00
2021-06-16 14:44:15 +03:00
"github.com/hasura/graphql-engine/cli/v2/util"
2020-06-03 14:19:36 +03:00
2021-06-16 14:44:15 +03:00
"github.com/hasura/graphql-engine/cli/v2"
"github.com/hasura/graphql-engine/cli/v2/migrate"
2018-06-24 16:40:48 +03:00
"github.com/spf13/cobra"
)
2018-06-28 11:36:25 +03:00
func newMigrateStatusCmd ( ec * cli . ExecutionContext ) * cobra . Command {
2020-02-24 19:14:46 +03:00
opts := & MigrateStatusOptions {
2021-12-23 18:58:53 +03:00
EC : ec ,
StatusOpts : make ( StatusOptions ) ,
2018-06-24 16:40:48 +03:00
}
migrateStatusCmd := & cobra . Command {
2020-02-24 19:14:46 +03:00
Use : "status" ,
Short : "Display current status of migrations on a database" ,
2022-12-30 06:50:48 +03:00
Long : "When running this command, the CLI will allow you to select which database - or all - to run the status command on. The CLI will return the current status of migrations on the selected database(s), including the version, name, source, database, and status." ,
2019-12-12 08:16:36 +03:00
Example : ` # Use with admin secret :
hasura migrate status -- admin - secret "<your-admin-secret>"
# Check status on a different server :
hasura migrate status -- endpoint "<endpoint>" ` ,
2018-06-24 16:40:48 +03:00
SilenceUsage : true ,
2021-04-01 15:58:24 +03:00
PreRunE : func ( cmd * cobra . Command , args [ ] string ) error {
2022-11-03 08:54:29 +03:00
var op = genOpName ( cmd , "PreRunE" )
if err := validateConfigV3FlagsWithAll ( cmd , ec ) ; err != nil {
return errors . E ( op , err )
}
return nil
2021-04-01 15:58:24 +03:00
} ,
2018-06-24 16:40:48 +03:00
RunE : func ( cmd * cobra . Command , args [ ] string ) error {
2022-11-03 08:54:29 +03:00
var op = genOpName ( cmd , "RunE" )
2021-12-23 18:58:53 +03:00
if err := opts . Run ( ) ; err != nil {
2022-11-03 08:54:29 +03:00
return errors . E ( op , err )
2018-07-06 08:06:27 +03:00
}
2021-12-23 18:58:53 +03:00
buf := printStatus ( opts . StatusOpts )
2021-07-16 08:26:00 +03:00
fmt . Fprintf ( ec . Stdout , "%s" , buf )
2018-07-06 08:06:27 +03:00
return nil
2018-06-24 16:40:48 +03:00
} ,
}
return migrateStatusCmd
}
2021-12-23 18:58:53 +03:00
func ( o * MigrateStatusOptions ) Run ( ) error {
2022-11-03 08:54:29 +03:00
var op errors . Op = "commands.MigrateStatusOptions.Run"
2021-12-23 18:58:53 +03:00
o . EC . Spin ( "Fetching migration status..." )
defer o . EC . Spinner . Stop ( )
if ec . AllDatabases {
sourcesAndKind , err := metadatautil . GetSourcesAndKind ( o . EC . APIClient . V1Metadata . ExportMetadata )
if err != nil {
2022-11-03 08:54:29 +03:00
return errors . E ( op , fmt . Errorf ( "got error while getting the sources list : %v" , err ) )
2021-12-23 18:58:53 +03:00
}
for _ , source := range sourcesAndKind {
o . Source = cli . Source ( source )
status , err := o . RunOnSource ( )
if err != nil {
2023-01-09 11:01:49 +03:00
return errors . E ( op , fmt . Errorf ( "error getting status for database '%s': %v" , o . Source . Name , err ) )
2021-12-23 18:58:53 +03:00
}
o . StatusOpts [ o . Source ] = status
}
2022-11-03 08:54:29 +03:00
return nil
2021-12-23 18:58:53 +03:00
}
o . Source = ec . Source
status , err := o . RunOnSource ( )
if err != nil {
2023-01-09 11:01:49 +03:00
return errors . E ( op , fmt . Errorf ( "error getting status for database '%s': %v" , o . Source . Name , err ) )
2021-12-23 18:58:53 +03:00
}
o . StatusOpts [ o . Source ] = status
2022-11-03 08:54:29 +03:00
return nil
2021-12-23 18:58:53 +03:00
}
type StatusOptions map [ cli . Source ] * migrate . Status
2020-02-24 19:14:46 +03:00
type MigrateStatusOptions struct {
2021-12-23 18:58:53 +03:00
EC * cli . ExecutionContext
Source cli . Source
StatusOpts StatusOptions
2018-06-24 16:40:48 +03:00
}
2021-12-23 18:58:53 +03:00
func ( o * MigrateStatusOptions ) RunOnSource ( ) ( * migrate . Status , error ) {
2022-11-03 08:54:29 +03:00
var op errors . Op = "commands.MigrateStatusOptions.RunOnSource"
2021-06-18 09:24:16 +03:00
if o . EC . Config . Version <= cli . V2 {
o . Source . Name = ""
o . Source . Kind = hasura . SourceKindPG
}
2021-03-08 14:59:35 +03:00
migrateDrv , err := migrate . NewMigrate ( o . EC , true , o . Source . Name , o . Source . Kind )
2018-06-24 16:40:48 +03:00
if err != nil {
2022-11-03 08:54:29 +03:00
return nil , errors . E ( op , err )
2018-06-24 16:40:48 +03:00
}
2018-07-09 16:47:38 +03:00
status , err := executeStatus ( migrateDrv )
2018-06-28 11:36:57 +03:00
if err != nil {
2022-11-03 08:54:29 +03:00
return nil , errors . E ( op , fmt . Errorf ( "cannot fetch migrate status: %w" , err ) )
2018-06-28 11:36:57 +03:00
}
2018-07-06 08:06:27 +03:00
return status , nil
}
2021-12-23 18:58:53 +03:00
func printStatus ( statusOpts StatusOptions ) * bytes . Buffer {
2018-07-06 08:06:27 +03:00
out := new ( tabwriter . Writer )
buf := & bytes . Buffer { }
out . Init ( buf , 0 , 8 , 2 , ' ' , 0 )
w := util . NewPrefixWriter ( out )
2021-12-23 18:58:53 +03:00
for source , status := range statusOpts {
if source . Name != "" {
w . Write ( util . LEVEL_0 , fmt . Sprintf ( "\nDatabase: %s\n" , source . Name ) )
}
w . Write ( util . LEVEL_0 , "VERSION\tNAME\tSOURCE STATUS\tDATABASE STATUS\n" )
for _ , version := range status . Index {
w . Write ( util . LEVEL_0 , "%d\t%s\t%s\t%s\n" ,
version ,
status . Migrations [ version ] . Name ,
convertBool ( status . Migrations [ version ] . IsPresent ) ,
convertBool ( status . Migrations [ version ] . IsApplied ) ,
)
}
2018-07-06 08:06:27 +03:00
}
out . Flush ( )
2018-08-21 21:37:47 +03:00
return buf
2018-07-06 08:06:27 +03:00
}
func convertBool ( ok bool ) string {
switch ok {
case true :
return "Present"
case false :
return "Not Present"
}
return ""
2018-06-24 16:40:48 +03:00
}