2021-05-24 05:33:45 +03:00
package commands
import (
"fmt"
"path/filepath"
"strconv"
2021-06-16 14:44:15 +03:00
"github.com/hasura/graphql-engine/cli/v2"
2022-11-03 10:36:28 +03:00
"github.com/hasura/graphql-engine/cli/v2/internal/errors"
2021-12-23 18:58:53 +03:00
"github.com/hasura/graphql-engine/cli/v2/internal/metadatautil"
2021-06-16 14:44:15 +03:00
"github.com/hasura/graphql-engine/cli/v2/migrate"
mig "github.com/hasura/graphql-engine/cli/v2/migrate/cmd"
"github.com/hasura/graphql-engine/cli/v2/util"
2021-05-24 05:33:45 +03:00
"github.com/spf13/cobra"
)
func newMigrateDeleteCmd ( ec * cli . ExecutionContext ) * cobra . Command {
opts := & MigrateDeleteOptions {
EC : ec ,
}
migrateDeleteCmd := & cobra . Command {
Use : "delete" ,
Short : "(PREVIEW) clear migrations from local project and server" ,
2022-12-30 06:50:48 +03:00
Long : "This command deletes migrations from the local project and the server. You can delete all migrations or a specific migration version by passing in the appropriate flags and values." ,
2021-05-24 05:33:45 +03:00
Example : `
# Usage to delete a version :
2021-06-22 14:15:22 +03:00
hasura migrate delete -- version < version_delete > -- database - name < database - name >
2021-05-24 05:33:45 +03:00
# Usage to delete all versions
2021-06-22 14:15:22 +03:00
hasura migrate delete -- all -- database - name < database - name > ` ,
2021-05-24 05:33:45 +03:00
SilenceUsage : true ,
PreRunE : func ( cmd * cobra . Command , args [ ] string ) error {
2022-11-03 10:36:28 +03:00
op := genOpName ( cmd , "PreRunE" )
2021-05-24 05:33:45 +03:00
ec . Logger . Warn ( "[PREVIEW] this command is in preview. usage may change in future\n" )
2021-12-23 18:58:53 +03:00
if err := validateConfigV3FlagsWithAll ( cmd , ec ) ; err != nil {
2022-11-03 10:36:28 +03:00
return errors . E ( op , err )
2021-05-24 05:33:45 +03:00
}
if ! cmd . Flags ( ) . Changed ( "all" ) && ! cmd . Flags ( ) . Changed ( "version" ) {
2022-11-03 10:36:28 +03:00
return errors . E ( op , fmt . Errorf ( "at least one flag [--all , --version] should be set" ) )
2021-05-24 05:33:45 +03:00
}
if cmd . Flags ( ) . Changed ( "all" ) && cmd . Flags ( ) . Changed ( "version" ) {
2022-11-03 10:36:28 +03:00
return errors . E ( op , fmt . Errorf ( "only one of [--all , --version] should be set" ) )
2021-05-24 05:33:45 +03:00
}
2021-06-22 14:15:22 +03:00
return nil
} ,
RunE : func ( cmd * cobra . Command , args [ ] string ) error {
2022-11-03 10:36:28 +03:00
op := genOpName ( cmd , "RunE" )
2021-06-22 14:15:22 +03:00
// exit if user inputs n for clearing migrations
2022-12-07 06:00:52 +03:00
if cmd . Flags ( ) . Changed ( "all" ) && ! opts . Force && opts . EC . IsTerminal {
2021-05-24 05:33:45 +03:00
confirmation , err := util . GetYesNoPrompt ( "clear all migrations of database and it's history on the server?" )
if err != nil {
2022-11-03 10:36:28 +03:00
return errors . E ( op , fmt . Errorf ( "error getting user input: %w" , err ) )
2021-05-24 05:33:45 +03:00
}
2021-09-07 16:33:58 +03:00
if ! confirmation {
2021-05-24 05:33:45 +03:00
return nil
}
}
2021-06-22 14:15:22 +03:00
2022-12-07 06:00:52 +03:00
if ec . AllDatabases && ! opts . Force {
2021-12-23 18:58:53 +03:00
confirmation , err := util . GetYesNoPrompt ( "clear all mentioned migrations of all databases and it's history on the server?" )
2021-05-24 05:33:45 +03:00
if err != nil {
2022-11-03 10:36:28 +03:00
return errors . E ( op , fmt . Errorf ( "error getting user input: %w" , err ) )
2021-12-23 18:58:53 +03:00
}
if ! confirmation {
return nil
2021-05-24 05:33:45 +03:00
}
}
2021-12-23 18:58:53 +03:00
if err := opts . Run ( ) ; err != nil {
2022-11-03 10:36:28 +03:00
return errors . E ( op , fmt . Errorf ( "operation failed: %w" , err ) )
2021-05-24 05:33:45 +03:00
}
return nil
} ,
}
f := migrateDeleteCmd . Flags ( )
2022-12-07 06:00:52 +03:00
f . Uint64Var ( & opts . Version , "version" , 0 , "deletes the specified version in migrations" )
f . BoolVar ( & opts . All , "all" , false , "clears all migrations for selected database" )
f . BoolVar ( & opts . Force , "force" , false , "when set executes operation without any confirmation" )
f . BoolVar ( & opts . OnlyServer , "server" , false , "to reset migrations only on server" )
2021-05-24 05:33:45 +03:00
return migrateDeleteCmd
}
type MigrateDeleteOptions struct {
2021-06-22 14:15:22 +03:00
EC * cli . ExecutionContext
2022-12-07 06:00:52 +03:00
Version uint64
All bool
Force bool
OnlyServer bool
2021-05-24 05:33:45 +03:00
Source cli . Source
}
func ( o * MigrateDeleteOptions ) Run ( ) error {
2022-11-03 10:36:28 +03:00
var op errors . Op = "commands.MigrateDeleteOptions.Run"
2021-12-23 18:58:53 +03:00
o . EC . Spin ( "Removing migrations" )
defer o . EC . Spinner . Stop ( )
2022-12-07 06:00:52 +03:00
if o . EC . AllDatabases {
2021-12-23 18:58:53 +03:00
sourcesAndKind , err := metadatautil . GetSourcesAndKind ( o . EC . APIClient . V1Metadata . ExportMetadata )
if err != nil {
2022-11-03 10:36:28 +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 )
err := o . RunOnSource ( )
if err != nil {
2023-01-09 11:01:49 +03:00
return errors . E ( op , fmt . Errorf ( "error while deleting status for database '%s': %v" , o . Source . Name , err ) )
2021-12-23 18:58:53 +03:00
}
}
return nil
}
2022-12-07 06:00:52 +03:00
o . Source = o . EC . Source
2022-11-03 10:36:28 +03:00
if err := o . RunOnSource ( ) ; err != nil {
return errors . E ( op , err )
}
return nil
2021-12-23 18:58:53 +03:00
}
func ( o * MigrateDeleteOptions ) RunOnSource ( ) error {
2022-11-03 10:36:28 +03:00
var op errors . Op = "commands.MigrateDeleteOptions.RunOnSource"
2021-05-24 05:33:45 +03:00
o . EC . Spin ( "Deleting migration..." )
migrateDrv , err := migrate . NewMigrate ( o . EC , true , o . Source . Name , o . Source . Kind )
if err != nil {
2022-11-03 10:36:28 +03:00
return errors . E ( op , fmt . Errorf ( "error in creation of new migrate instance %w" , err ) )
2021-05-24 05:33:45 +03:00
}
status , err := migrateDrv . GetStatus ( )
if err != nil {
2022-11-03 10:36:28 +03:00
return errors . E ( op , fmt . Errorf ( "error while retrieving migration status %w" , err ) )
2021-05-24 05:33:45 +03:00
}
2021-06-22 14:15:22 +03:00
// sourceVersions migration versions in source to be deleted similarly with serverVersions
var sourceVersions , serverVersions [ ] uint64
2022-12-07 06:00:52 +03:00
if ! o . All {
2021-06-22 14:15:22 +03:00
// if o.version isn't present on source and on server return error version isn't present.
2022-12-07 06:00:52 +03:00
if _ , ok := status . Migrations [ o . Version ] ; ! ok {
return errors . E ( op , fmt . Errorf ( "version %v not found" , o . Version ) )
2021-05-24 05:33:45 +03:00
}
2022-12-07 06:00:52 +03:00
sourceVersions = [ ] uint64 { o . Version }
serverVersions = [ ] uint64 { o . Version }
} else if o . All {
2021-05-24 05:33:45 +03:00
for k , v := range status . Migrations {
if v . IsApplied {
serverVersions = append ( serverVersions , k )
}
if v . IsPresent {
sourceVersions = append ( sourceVersions , k )
}
}
2021-06-22 14:15:22 +03:00
}
// resets the migrations on server
err = migrateDrv . RemoveVersions ( serverVersions )
if err != nil {
2022-11-03 10:36:28 +03:00
return errors . E ( op , fmt . Errorf ( "error removing migration from server: %w" , err ) )
2021-06-22 14:15:22 +03:00
}
// removes the migrations on source
2022-12-07 06:00:52 +03:00
if ! o . OnlyServer {
2021-05-24 05:33:45 +03:00
err = DeleteVersions ( o . EC , sourceVersions , o . Source )
if err != nil {
2022-11-03 10:36:28 +03:00
return errors . E ( op , fmt . Errorf ( "error removing migrations from project: %w" , err ) )
2021-05-24 05:33:45 +03:00
}
}
2021-10-13 17:38:07 +03:00
o . EC . Spinner . Stop ( )
2021-05-24 05:33:45 +03:00
o . EC . Logger . Infof ( "Deleted migrations" )
return nil
}
func DeleteVersions ( ec * cli . ExecutionContext , versions [ ] uint64 , source cli . Source ) error {
2022-11-03 10:36:28 +03:00
var op errors . Op = "commands.DeleteVersions"
2021-05-24 05:33:45 +03:00
for _ , v := range versions {
delOptions := mig . CreateOptions {
Version : strconv . FormatUint ( v , 10 ) ,
Directory : filepath . Join ( ec . MigrationDir , source . Name ) ,
}
err := delOptions . Delete ( )
if err != nil {
2022-11-03 10:36:28 +03:00
return errors . E ( op , fmt . Errorf ( "unable to delete migrations from project for: %v : %w" , v , err ) )
2021-05-24 05:33:45 +03:00
}
}
return nil
}