Skip to content

Commit

Permalink
Merge branch 'skip-migration-command' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
aleksanderaleksic committed Apr 28, 2021
2 parents cdc17e7 + a7b4e59 commit d18131c
Show file tree
Hide file tree
Showing 10 changed files with 219 additions and 9 deletions.
4 changes: 3 additions & 1 deletion command/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ package command
import "github.com/urfave/cli/v2"

// Version is a version number.
var version = "0.1.6"
var version = "0.1.7"

func GetApp() *cli.App {
var applyCommand = ApplyCommand{}
var planCommand = PlanCommand{}
var revertCommand = RevertCommand{}
var skipCommand = SkipCommand{}

return &cli.App{
Version: version,
Expand All @@ -35,6 +36,7 @@ func GetApp() *cli.App {
applyCommand.GetCLICommand(),
planCommand.GetCLICommand(),
revertCommand.GetCLICommand(),
skipCommand.GetCLICommand(),
},
}
}
88 changes: 88 additions & 0 deletions command/skip.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package command

import (
"fmt"
"github.com/aleksanderaleksic/tgmigrate/common"
"github.com/aleksanderaleksic/tgmigrate/config"
"github.com/aleksanderaleksic/tgmigrate/history"
"github.com/aleksanderaleksic/tgmigrate/migration"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/urfave/cli/v2"
)

type SkipCommand struct {
Skipper *migration.Skipper
}

func (command *SkipCommand) GetCLICommand() *cli.Command {
cmd := cli.Command{
Name: "skip",
Aliases: nil,
Usage: "Skips the provided migration",
UsageText: "",
Description: "This is useful if a migration is not able to complete successfully",
ArgsUsage: "",
Category: "",
BashComplete: nil,
Before: command.initialize,
After: nil,
Action: command.run,
OnUsageError: nil,
Subcommands: nil,
Flags: nil,
SkipFlagParsing: false,
HideHelp: false,
HideHelpCommand: false,
Hidden: false,
UseShortOptionHandling: false,
HelpName: "",
CustomHelpTemplate: "",
}
return &cmd
}

func (command *SkipCommand) run(c *cli.Context) error {
migrationFileName := c.Args().First()
if migrationFileName == "" {
return fmt.Errorf("must include the migration file name as argument")
}
return command.Skipper.Skip(migrationFileName)
}

func (command *SkipCommand) initialize(c *cli.Context) error {
cfg, err := config.GetConfigFile(c)
if err != nil {
return err
}

chc := common.Cache{
ConfigFilePath: cfg.Path,
}

ctx := common.Context{
SkipUserInteraction: c.Bool("y"),
DryRun: false,
}

historyInterface, err := history.GetHistoryInterface(*cfg, ctx, chc)
if err != nil {
return err
}

s3Cfg := cfg.State.Config.(*config.S3StateConfig)
awsSession, err := getAwsSession(s3Cfg.Region, s3Cfg.AssumeRole)
if err != nil {
return err
}

skipper := migration.Skipper{
Context: &ctx,
Config: cfg,
HistoryInterface: historyInterface,
S3StateClient: s3.New(awsSession),
}

command.Skipper = &skipper

return nil
}
6 changes: 6 additions & 0 deletions history/history.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ import (

type History interface {
IsMigrationApplied(hash string) (bool, error)
ShouldMigrationBeApplied(migrationName string) (bool, error)
InitializeHistory() (*StorageHistory, error)
StoreAppliedMigration(migration *AppliedStorageHistoryObject)
StoreSkippedMigration(migration *SkippedStorageHistoryObject)
StoreFailedMigration(migration *FailedStorageHistoryObject)
RemoveAppliedMigration(migrationName string)
WriteToStorage() error
Expand Down Expand Up @@ -130,6 +132,10 @@ func (s *StorageHistory) storeFailedMigration(migration *FailedStorageHistoryObj
migration.Failed = common.JSONTime(time.Now())
s.FailedMigrations = append(s.FailedMigrations, *migration)
}
func (s *StorageHistory) storeSkippedMigration(migration *SkippedStorageHistoryObject) {
migration.Skipped = common.JSONTime(time.Now())
s.SkippedMigrations = append(s.SkippedMigrations, *migration)
}

func writeToStorage(historyPath string, storageHistory StorageHistory) error {
return writeStorageHistory(historyPath, storageHistory)
Expand Down
12 changes: 12 additions & 0 deletions history/s3_history.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ func (h S3History) IsMigrationApplied(hash string) (bool, error) {
return false, nil
}

func (h S3History) ShouldMigrationBeApplied(migrationName string) (bool, error) {
for _, m := range h.StorageHistory.SkippedMigrations {
if m.Name == migrationName {
return false, nil
}
}
return true, nil
}

func (h *S3History) InitializeHistory() (*StorageHistory, error) {
historyPath := h.getHistoryStoragePath()
s3Path := "s3://" + filepath.Join(h.S3StorageConfig.Bucket, filepath.Dir(h.S3StorageConfig.Key))
Expand All @@ -50,6 +59,9 @@ func (h S3History) StoreAppliedMigration(migration *AppliedStorageHistoryObject)
func (h S3History) StoreFailedMigration(migration *FailedStorageHistoryObject) {
h.StorageHistory.storeFailedMigration(migration)
}
func (h S3History) StoreSkippedMigration(migration *SkippedStorageHistoryObject) {
h.StorageHistory.storeSkippedMigration(migration)
}

func (h S3History) RemoveAppliedMigration(migrationName string) {
for index, migration := range h.StorageHistory.AppliedMigration {
Expand Down
20 changes: 14 additions & 6 deletions history/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ const StorageHistoryVersion = "v1"
const StorageHistoryObjectVersion = "v1"

type StorageHistory struct {
SchemaVersion string `json:"schema_version"`
AppliedMigration []AppliedStorageHistoryObject `json:"applied_migration"`
FailedMigrations []FailedStorageHistoryObject `json:"failed_migration"`
SchemaVersion string `json:"schema_version"`
AppliedMigration []AppliedStorageHistoryObject `json:"applied_migration"`
SkippedMigrations []SkippedStorageHistoryObject `json:"skipped_migration"`
FailedMigrations []FailedStorageHistoryObject `json:"failed_migration"`
}

type AppliedStorageHistoryObject struct {
Expand All @@ -29,11 +30,18 @@ type FailedStorageHistoryObject struct {
Name string `json:"name"`
}

type SkippedStorageHistoryObject struct {
SchemaVersion string `json:"schema_version"`
Skipped common.JSONTime `json:"skipped"`
Name string `json:"name"`
}

func EmptyStorageHistory() StorageHistory {
return StorageHistory{
SchemaVersion: StorageHistoryVersion,
AppliedMigration: []AppliedStorageHistoryObject{},
FailedMigrations: []FailedStorageHistoryObject{},
SchemaVersion: StorageHistoryVersion,
AppliedMigration: []AppliedStorageHistoryObject{},
SkippedMigrations: []SkippedStorageHistoryObject{},
FailedMigrations: []FailedStorageHistoryObject{},
}
}

Expand Down
3 changes: 2 additions & 1 deletion migration/migration_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,13 @@ func (r Runner) getMigrationsToBeApplied(migrationFiles []File, environment *str
continue
}

shouldBeApplied, _ := r.HistoryInterface.ShouldMigrationBeApplied(migration.Metadata.FileName)
isApplied, err := r.HistoryInterface.IsMigrationApplied(migration.Metadata.FileHash)
if err != nil {
return nil, err
}

if !isApplied {
if !isApplied && shouldBeApplied {
migrationsToBeApplied = append(migrationsToBeApplied, migration)
}
}
Expand Down
62 changes: 62 additions & 0 deletions migration/migration_skipper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package migration

import (
"fmt"
"github.com/aleksanderaleksic/tgmigrate/common"
"github.com/aleksanderaleksic/tgmigrate/config"
"github.com/aleksanderaleksic/tgmigrate/history"
"github.com/aws/aws-sdk-go/service/s3"
)

type Skipper struct {
Context *common.Context
Config *config.Config
S3StateClient *s3.S3
HistoryInterface history.History
}

func (r Skipper) Skip(migrationName string) error {
hist, err := r.HistoryInterface.InitializeHistory()
if err != nil {
return err
}

migrationFiles, err := GetMigrationFiles(r.Config.AbsoluteMigrationDir)
if err != nil {
return fmt.Errorf("could not get migration files from '%s', error: %s", r.Config.AbsoluteMigrationDir, err)
}
migrationFile := getMigration(migrationName, migrationFiles)
if migrationFile == nil {
return fmt.Errorf("migration file with name: '%s' was not found", migrationName)
}

for _, m := range hist.AppliedMigration {
if m.Name == migrationName {
return fmt.Errorf("migration file with name: '%s' is already applied", migrationName)
}
}
for _, m := range hist.SkippedMigrations {
if m.Name == migrationName {
return fmt.Errorf("migration file with name: '%s' is already skipped", migrationName)
}
}

r.HistoryInterface.StoreSkippedMigration(&history.SkippedStorageHistoryObject{
SchemaVersion: history.StorageHistoryObjectVersion,
Skipped: common.JSONTime{},
Name: migrationName,
})

r.HistoryInterface.WriteToStorage()

return nil
}

func getMigration(migrationName string, migrations *[]File) *File {
for _, migration := range *migrations {
if migration.Metadata.FileName == migrationName {
return &migration
}
}
return nil
}
6 changes: 5 additions & 1 deletion test/data/e2e/.tgmigrate_cache/history/history.json
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
{"schema_version":"v1","applied_migration":[],"failed_migration":[]}
{
"schema_version": "v1",
"applied_migration": [],
"failed_migration": []
}
27 changes: 27 additions & 0 deletions test/mock/history_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added tgmigrate
Binary file not shown.

0 comments on commit d18131c

Please sign in to comment.