diff --git a/CHANGELOG.md b/CHANGELOG.md index e2c55420..78442389 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ +# 0.19.0 + +* `Checkpoint-Migration` will no longer delete migration scripts that have been pushed to the database. Instead it + will now export rows from the `rivet.Migrations` table and include them in the `schema.ps1` file. +* Added an `InitializeSchema` switch to the `Invoke-Rivet` script that is used to initialize database(s) with the + `schema.ps1` file that is generated from `Checkpoint-Migration`. + + # 0.18.0 * Fixed: Rivet doesn't use the CommandTimeout property in rivet.json configuration file. diff --git a/Rivet/Functions/Checkpoint-Migration.ps1 b/Rivet/Functions/Checkpoint-Migration.ps1 index 779db19b..01eb5e6f 100644 --- a/Rivet/Functions/Checkpoint-Migration.ps1 +++ b/Rivet/Functions/Checkpoint-Migration.ps1 @@ -46,34 +46,13 @@ function Checkpoint-Migration return } - $query = @" - SELECT CONCAT( FORMAT(ID, '00000000000000'), '_', Name) as MigrationFileName - FROM rivet.Migrations - WHERE ID > $($script:firstMigrationId) -"@ - - try - { - Connect-Database -SqlServerName $settings.SqlServerName ` - -Database $databaseItem.Name ` - -ConnectionTimeout $settings.ConnectionTimeout - - $pushedMigrations = Invoke-Query -Query $query - } - finally - { - Disconnect-Database - } - Write-Debug "Checkpoint-Migration: Exporting migration on database $($databaseItem.Name)" - $migration = Export-Migration -SqlServerName $settings.SqlServerName -Database $databaseItem.Name -ConfigFilePath $ConfigFilePath + $migration = Export-Migration -SqlServerName $settings.SqlServerName ` + -Database $databaseItem.Name ` + -ConfigFilePath $ConfigFilePath ` + -Checkpoint + $migration = $migration -join [Environment]::NewLine Set-Content -Path $OutputPath -Value $migration - - foreach( $migration in $pushedMigrations ) - { - $migrationFilePath = Join-Path -Path $databaseItem.MigrationsRoot -ChildPath "$($migration.MigrationFileName).ps1" - Remove-Item -Path $migrationFilePath - } } } diff --git a/Rivet/Functions/Export-Migration.ps1 b/Rivet/Functions/Export-Migration.ps1 index 38f329ea..59e8eb46 100644 --- a/Rivet/Functions/Export-Migration.ps1 +++ b/Rivet/Functions/Export-Migration.ps1 @@ -41,7 +41,10 @@ function Export-Migration # The path to the Rivet configuration file to load. Defaults to `rivet.json` in the current directory. [String] $ConfigFilePath, - [Switch] $NoProgress + [Switch] $NoProgress, + + # Checkpoints the current state of the database so that it can be re-created. + [Switch] $Checkpoint ) Set-StrictMode -Version 'Latest' @@ -1619,6 +1622,30 @@ where $exportedXmlSchemas[$ID] = $true } + $rivetMigrationsTableQuery = " + SELECT * + FROM rivet.Migrations + WHERE ID > $($script:firstMigrationId)" + + function Export-RivetMigrationsTable + { + [CmdletBinding()] + param() + + foreach( $row in $rivetMigrationsTableData ) + { + @" + Add-Row -SchemaName 'rivet' -TableName 'Migrations' -Column @{ + ID = '$($row.Id)'; + Name = '$($row.Name)'; + Who = '$($row.Who)'; + ComputerName = '$($row.ComputerName)'; + AtUtc = '$($row.AtUtc.ToString("MM/dd/yyyy HH:mm:ss.fffffff"))'; + } +"@ + } + } + function Push-PopOperation { param( @@ -1949,6 +1976,11 @@ where Export-DataType Export-Object Export-Index + if( $Checkpoint ) + { + $rivetMigrationsTableData = Invoke-Query -Query $rivetMigrationsTableQuery + Export-RivetMigrationsTable + } '}' '' 'function Pop-Migration' diff --git a/Rivet/Functions/Invoke-Rivet.ps1 b/Rivet/Functions/Invoke-Rivet.ps1 index 2aa7649f..3d4a1765 100644 --- a/Rivet/Functions/Invoke-Rivet.ps1 +++ b/Rivet/Functions/Invoke-Rivet.ps1 @@ -63,6 +63,7 @@ function Invoke-Rivet [Parameter(ParameterSetName='Redo')] [Parameter(ParameterSetName='DropDatabase')] [Parameter(ParameterSetName='Checkpoint')] + [Parameter(ParameterSetName='InitializeSchema')] [string[]] # The database(s) to migrate. Optional. Will operate on all databases otherwise. $Database, @@ -76,6 +77,7 @@ function Invoke-Rivet [Parameter(ParameterSetName='Redo')] [Parameter(ParameterSetName='DropDatabase')] [Parameter(ParameterSetName='Checkpoint')] + [Parameter(ParameterSetName='InitializeSchema')] [string] # The environment you're working in. Controls which settings Rivet loads from the `rivet.json` configuration file. $Environment, @@ -89,6 +91,7 @@ function Invoke-Rivet [Parameter(ParameterSetName='Redo')] [Parameter(ParameterSetName='DropDatabase')] [Parameter(ParameterSetName='Checkpoint')] + [Parameter(ParameterSetName='InitializeSchema')] [string] # The path to the Rivet configuration file. Default behavior is to look in the current directory for a `rivet.json` file. See `about_Rivet_Configuration` for more information. $ConfigFilePath, @@ -101,7 +104,12 @@ function Invoke-Rivet [Parameter(ParameterSetName='Checkpoint')] [Switch] # Checkpoints the current state of the database so that it can be re-created. - $Checkpoint + $Checkpoint, + + [Parameter(ParameterSetName='InitializeSchema')] + [Switch] + # Initializes the database, including baseline schema. Use the -Checkpoint switch to create a database baseline. + $InitializeSchema ) Set-StrictMode -Version 'Latest' @@ -193,6 +201,10 @@ Found no databases to migrate. This can be a few things: try { Initialize-Database -Configuration $settings + if( $InitializeSchema ) + { + continue + } $updateParams = @{ Path = $dbMigrationsPath; diff --git a/Rivet/Rivet.psd1 b/Rivet/Rivet.psd1 index ae1fc80b..f1e14d1f 100644 --- a/Rivet/Rivet.psd1 +++ b/Rivet/Rivet.psd1 @@ -11,7 +11,7 @@ RootModule = 'Rivet.psm1' # Version number of this module. - ModuleVersion = '0.18.0' + ModuleVersion = '0.19.0' # ID used to uniquely identify this module GUID = '8af34b47-259b-4630-a945-75d38c33b94d' diff --git a/Rivet/rivet.ps1 b/Rivet/rivet.ps1 index 82d66a34..281ac0b1 100644 --- a/Rivet/rivet.ps1 +++ b/Rivet/rivet.ps1 @@ -130,6 +130,7 @@ param( [Parameter(ParameterSetName='Redo')] [Parameter(ParameterSetName='DropDatabase')] [Parameter(ParameterSetName='Checkpoint')] + [Parameter(ParameterSetName='InitializeSchema')] [string[]] # The database(s) to migrate. Optional. Will operate on all databases otherwise. $Database, @@ -143,6 +144,7 @@ param( [Parameter(ParameterSetName='Redo')] [Parameter(ParameterSetName='DropDatabase')] [Parameter(ParameterSetName='Checkpoint')] + [Parameter(ParameterSetName='InitializeSchema')] [string] # The environment you're working in. Controls which settings Rivet loads from the `rivet.json` configuration file. $Environment, @@ -156,6 +158,7 @@ param( [Parameter(ParameterSetName='Redo')] [Parameter(ParameterSetName='DropDatabase')] [Parameter(ParameterSetName='Checkpoint')] + [Parameter(ParameterSetName='InitializeSchema')] [string] # The path to the Rivet configuration file. Default behavior is to look in the current directory for a `rivet.json` file. See `about_Rivet_Configuration` for more information. $ConfigFilePath, @@ -168,7 +171,12 @@ param( [Parameter(ParameterSetName='Checkpoint')] [Switch] # Checkpoints the current state of the database so that it can be re-created. - $Checkpoint + $Checkpoint, + + [Parameter(ParameterSetName='InitializeSchema')] + [Switch] + # Initializes the database, including baseline schema. Use the -Checkpoint switch to create a database baseline. + $InitializeSchema ) Set-StrictMode -Version Latest diff --git a/Test/Checkpoint-Migration.Tests.ps1 b/Test/Checkpoint-Migration.Tests.ps1 index a28568e9..75cf2c24 100644 --- a/Test/Checkpoint-Migration.Tests.ps1 +++ b/Test/Checkpoint-Migration.Tests.ps1 @@ -1,105 +1,98 @@ #Requires -Version 5.1 Set-StrictMode -Version 'Latest' -& (Join-Path -Path $PSScriptRoot -ChildPath 'Initialize-Test.ps1' -Resolve) +BeforeAll { + & (Join-Path -Path $PSScriptRoot -ChildPath 'Initialize-Test.ps1' -Resolve) -$checkpointedMigrations = [System.Collections.ArrayList]::new() -$migrationPaths = [System.Collections.ArrayList]::new() -$existingSchemaContents = @" -function Push-Migration -{ - Add-Table -Name 'Existing' -Column { - int 'ID' -Identity + $script:checkpointedMigrations = [System.Collections.ArrayList]::new() + $script:migrationPaths = [System.Collections.ArrayList]::new() + $script:database = [System.Collections.ArrayList]::new() + $existingSchemaContents = @" + function Push-Migration + { + Add-Table -Name 'Existing' -Column { + int 'ID' -Identity + } } -} -function Pop-Migration -{ - Remove-Table 'Existing' -} + function Pop-Migration + { + Remove-Table 'Existing' + } "@ -function Init -{ - $Global:Error.Clear() - $script:checkpointedMigrations = [System.Collections.ArrayList]::new() - $script:migrationPaths = [System.Collections.ArrayList]::new() - Start-RivetTest -} + function GivenMigrationContent + { + param( + [Parameter(Mandatory)] + [String] $Content, -function GivenMigrationContent -{ - param( - [Parameter(Mandatory)] - [String] $Content, + [String[]] $Database, - [String[]] $Database - ) + [String] $Name + ) - if(-not $Database ) - { - $Database = $RTDatabaseName + if(-not $Database ) + { + $Database = $RTDatabaseName + } + + foreach( $databaseName in $Database ) + { + $path = $Content | New-TestMigration -Name $Name -DatabaseName $databaseName + $script:migrationPaths.Add($path) + } } - foreach( $databaseName in $Database ) + function Reset { - $path = $Content | New-TestMigration -Name 'CheckpointMigration' -DatabaseName $databaseName - $script:migrationPaths.Add($path) - } -} + param( + ) -function Reset -{ - param( - [String[]] $Database - ) + $database = $script:database + if( -not $database ) + { + $database = $RTDatabaseName + } - if( -not $Database ) - { - $Database = $RTDatabaseName + foreach( $databaseItem in $database ) + { + Remove-RivetTestDatabase -Name $databaseItem + } } - foreach( $databaseItem in $Database ) + function ThenFailed { - Remove-RivetTestDatabase -Name $databaseItem - } -} - -function ThenFailed -{ - param( - [String] $WithError - ) + param( + [String] $WithError + ) - It ('should fail') { $Global:Error | Should -Match $WithError } -} -function ThenNoErrors -{ - It ('should not write any errors') { + function ThenNoErrors + { $Global:Error | Should -BeNullOrEmpty } -} -function ThenMigration -{ - param( - [Switch] $Not, + function ThenSchema + { + param( + [Switch] $Not, - [Parameter(Mandatory)] - [String] $HasContent, + [Parameter(Mandatory)] + [String] $HasContent, - [Parameter(Mandatory)] - [String[]] $Database - ) + [Parameter(Mandatory)] + [String[]] $Database, - foreach( $databaseItem in $Database ) - { - $migration = $script:checkpointedMigrations | Where-Object {$_.Database -eq $databaseItem} + [String[]] $ContainsRowsFor + ) + + foreach( $databaseItem in $Database ) + { + $migration = $script:checkpointedMigrations | Where-Object {$_.Database -eq $databaseItem} - It ('should checkpoint migration') { if( $Not ) { ($migration.Migration -join [Environment]::NewLine) | Should -Not -BeLike ('*{0}*' -f [wildcardpattern]::Escape($HasContent)) @@ -108,72 +101,89 @@ function ThenMigration { ($migration.Migration -join [Environment]::NewLine) | Should -BeLike ('*{0}*' -f [wildcardpattern]::Escape($HasContent)) } + + foreach( $row in $ContainsRowsFor ) + { + ($migration.Migration -join [Environment]::NewLine) | Should -BeLike ('*{0}*' -f [wildcardpattern]::Escape($row)) + } } } -} -function ThenSchemaFileRunnable -{ - foreach( $path in $script:migrationPaths ) + function ThenSchemaFileRunnable { - $databaseName = $path.Directory.Parent.Name - $schemaFilePath = Join-Path -Path (Split-Path $path) -ChildPath 'schema.ps1' - $schemaFileContents = Get-Content -Path $schemaFilePath - $checkpointedMigration = @{ - Database = $path.Directory.Parent.Name; - Migration = $schemaFileContents - } - $script:checkpointedMigrations.Add($checkpointedMigration) - It ('should export a runnable migration') { + foreach( $path in $script:migrationPaths ) + { + $databaseName = $path.Directory.Parent.Name + $schemaFilePath = Join-Path -Path (Split-Path $path) -ChildPath 'schema.ps1' + $schemaFileContents = Get-Content -Path $schemaFilePath + $checkpointedMigration = @{ + Database = $path.Directory.Parent.Name; + Migration = $schemaFileContents + } + $script:checkpointedMigrations.Add($checkpointedMigration) + Remove-RivetTestDatabase -Name $databaseName - # Now, check that the migration is runnable - Invoke-RTRivet -Push -Database $databaseName -ErrorAction Stop + # Now, check that the schema.ps1 script is runnable + Invoke-RTRivet -InitializeSchema -Database $databaseName -ErrorAction Stop Invoke-RTRivet -Pop -Database $databaseName -ErrorAction Stop } } -} -function WhenCheckpointingMigration -{ - [CmdletBinding()] - param( - [String[]] $Database, + function WhenCheckpointingMigration + { + [CmdletBinding()] + param( + [String[]] $Database, - [Switch] $Force, + [Switch] $Force, - [Switch] $ExistingSchemaFile, + [Switch] $ExistingSchemaFile, - [String[]] $Exclude - ) + [String[]] $Exclude + ) - if(-not $Database ) - { - $Database = $RTDatabaseName - } + if(-not $Database ) + { + $Database = $RTDatabaseName + } - if( $ExistingSchemaFile ) - { - foreach( $path in $script:migrationPaths ) + if( $ExistingSchemaFile ) { - Set-Content -Path (Join-Path -Path $path.Directory.FullName -ChildPath 'schema.ps1') -Value $existingSchemaContents + foreach( $path in $script:migrationPaths ) + { + Set-Content -Path (Join-Path -Path $path.Directory.FullName -ChildPath 'schema.ps1') -Value $existingSchemaContents + } } - } - foreach( $migration in $Exclude ) - { - $migrationPathToRemove = $script:migrationPaths | Where-Object {$_ -like $migration} - if( $migrationPathToRemove ) + foreach( $migration in $Exclude ) { - $script:migrationPaths.Remove($migrationPathToRemove) + $migrationPathToRemove = $script:migrationPaths | Where-Object {$_ -like $migration} + if( $migrationPathToRemove ) + { + $script:migrationPaths.Remove($migrationPathToRemove) + } } - } - Invoke-RTRivet -Checkpoint -Database $Database -Force:$Force + Invoke-RTRivet -Checkpoint -Database $Database -Force:$Force + } } -Describe 'Checkpoint-Migration.when there are multiple databases' { - Init - GivenMigrationContent -Content @' +Describe 'Checkpoint-Migration' { + BeforeEach { + $Global:Error.Clear() + $script:checkpointedMigrations = [System.Collections.ArrayList]::new() + $script:migrationPaths = [System.Collections.ArrayList]::new() + $script:database = [System.Collections.ArrayList]::new() + Start-RivetTest + } + + AfterEach { + Reset + } + + It 'should successfuly checkpoint migrations when there are multiple databases' { + $script:database = 'RivetTest', 'RivetTest2' + GivenMigrationContent -Name 'CheckpointMigration' -Content @' function Push-Migration { Add-Table -Name 'Replicated' -Column { @@ -189,27 +199,28 @@ function Pop-Migration Remove-Table 'Replicated' Remove-Table 'NotReplicated' } -'@ -Database ('RivetTest', 'RivetTest2') - Invoke-RTRivet -Push -Database ('RivetTest', 'RivetTest2') - WhenCheckpointingMigration -Database ('RivetTest', 'RivetTest2') - ThenSchemaFileRunnable - ThenMigration -HasContent @' +'@ -Database ($script:database) + Invoke-RTRivet -Push -Database ($script:database) + WhenCheckpointingMigration -Database ($script:database) + ThenSchemaFileRunnable + ThenSchema -HasContent @' Add-Table -Name 'Replicated' -Column { int 'ID' -Identity } -'@ -Database ('RivetTest', 'RivetTest2') - ThenMigration -HasContent @' +'@ -Database ($script:database) + ThenSchema -HasContent @' Add-Table -Name 'NotReplicated' -Column { int 'ID' -Identity -NotForReplication } -'@ -Database ('RivetTest', 'RivetTest2') - ThenNoErrors - Reset -Database ('RivetTest', 'RivetTest2') -} - -Describe 'Checkpoint-Migration.when schema.ps1 file already exists' { - Init - GivenMigrationContent @' +'@ -Database ($script:database) + ThenSchema -HasContent @' + Add-Row -SchemaName 'rivet' -TableName 'Migrations' -Column @{ +'@ -ContainsRowsFor 'CheckpointMigration' -Database ($script:database) + ThenNoErrors + } + + It 'should fail when schema.ps1 file already exists' { + GivenMigrationContent -Name 'CheckpointMigration' -Content @' function Push-Migration { Add-Table -Name 'NotReplicated' -Column { @@ -222,15 +233,13 @@ function Pop-Migration Remove-Table 'NotReplicated' } '@ - Invoke-RTRivet -Push -Database $RTDatabaseName - WhenCheckpointingMigration -ExistingSchemaFile -ErrorAction SilentlyContinue - ThenFailed -WithError 'schema.ps1" already exists.' - Reset -} - -Describe 'Checkpoint-Migration.when schema.ps1 file already exists but -Force switch is given' { - Init - GivenMigrationContent @' + Invoke-RTRivet -Push -Database $RTDatabaseName + WhenCheckpointingMigration -ExistingSchemaFile -ErrorAction SilentlyContinue + ThenFailed -WithError 'schema.ps1" already exists.' + } + + It 'should overwrite contents when schema.ps1 file already exists but -Force switch is given' { + GivenMigrationContent -Name 'CheckpointMigration' -Content @' function Push-Migration { Add-Table -Name 'NotReplicated' -Column { @@ -243,21 +252,22 @@ function Pop-Migration Remove-Table 'NotReplicated' } '@ - Invoke-RTRivet -Push -Database $RTDatabaseName - WhenCheckpointingMigration -ExistingSchemaFile -Force - ThenSchemaFileRunnable - ThenMigration -HasContent @' + Invoke-RTRivet -Push -Database $RTDatabaseName + WhenCheckpointingMigration -ExistingSchemaFile -Force + ThenSchemaFileRunnable + ThenSchema -HasContent @' Add-Table -Name 'NotReplicated' -Column { int 'ID' -Identity -NotForReplication } '@ -Database $RTDatabaseName - ThenNoErrors - Reset -} - -Describe 'Checkpoint-Migration.when checkpointing a migration' { - Init - GivenMigrationContent @' + ThenSchema -HasContent @' + Add-Row -SchemaName 'rivet' -TableName 'Migrations' -Column @{ +'@ -ContainsRowsFor 'CheckpointMigration' -Database $RTDatabaseName + ThenNoErrors + } + + It 'should pass when checkpointing a migration' { + GivenMigrationContent -Name 'CheckpointMigration' -Content @' function Push-Migration { Add-DataType -Name 'CID' -From 'char(8)' @@ -308,11 +318,11 @@ function Pop-Migration Remove-DataType 'CID' } '@ - Invoke-RTRivet -Push -Database $RTDatabaseName - WhenCheckpointingMigration - ThenSchemaFileRunnable - ThenMigration -Not -HasContent 'Add-Schema -Name ''dbo''' -Database $RTDatabaseName - ThenMigration -HasContent @' + Invoke-RTRivet -Push -Database $RTDatabaseName + WhenCheckpointingMigration + ThenSchemaFileRunnable + ThenSchema -Not -HasContent 'Add-Schema -Name ''dbo''' -Database $RTDatabaseName + ThenSchema -HasContent @' Add-Table -Name 'Migrations' -Description 'some table''s description' -Column { int 'ID' -Identity bigint 'BigID' -NotNull -Description 'some bigint column''s description' @@ -346,37 +356,38 @@ function Pop-Migration varchar 'ExplicitMaxSize' -Size 8000 } '@ -Database $RTDatabaseName - ThenMigration -HasContent @' + ThenSchema -HasContent @' Add-PrimaryKey -TableName 'Migrations' -ColumnName 'ID' -Name 'PK_Migrations' '@ -Database $RTDatabaseName - ThenMigration -HasContent @' + ThenSchema -HasContent @' Add-DefaultConstraint -TableName 'Migrations' -ColumnName 'AtUtc' -Name 'DF_Migrations_AtUtc' -Expression '(getutcdate())' '@ -Database $RTDatabaseName - ThenMigration -HasContent @' + ThenSchema -HasContent @' Add-CheckConstraint -TableName 'Migrations' -Name 'CK_Migrations_Name' -Expression '([Name]=''Fubar'')' '@ -Database $RTDatabaseName - ThenMigration -HasContent 'Add-CheckConstraint -TableName ''Migrations'' -Name ''CK_Migrations_Name2'' -Expression ''([Name]=''''Snafu'''')'' -NotForReplication -NoCheck' -Database $RTDatabaseName - ThenMigration -HasContent 'Add-Index -TableName ''Migrations'' -ColumnName ''BigID'' -Name ''IX_Migrations_BigID''' -Database $RTDatabaseName - ThenMigration -HasContent 'Add-UniqueKey -TableName ''Migrations'' -ColumnName ''Korean'' -Name ''AK_Migrations_Korean''' -Database $RTDatabaseName - ThenMigration -HasContent 'Add-Trigger -Name ''MigrationsTrigger'' -Definition @'' + ThenSchema -HasContent 'Add-CheckConstraint -TableName ''Migrations'' -Name ''CK_Migrations_Name2'' -Expression ''([Name]=''''Snafu'''')'' -NotForReplication -NoCheck' -Database $RTDatabaseName + ThenSchema -HasContent 'Add-Index -TableName ''Migrations'' -ColumnName ''BigID'' -Name ''IX_Migrations_BigID''' -Database $RTDatabaseName + ThenSchema -HasContent 'Add-UniqueKey -TableName ''Migrations'' -ColumnName ''Korean'' -Name ''AK_Migrations_Korean''' -Database $RTDatabaseName + ThenSchema -HasContent 'Add-Trigger -Name ''MigrationsTrigger'' -Definition @'' ON [dbo].[Migrations] for insert as select 1 ''@' -Database $RTDatabaseName + ThenSchema -HasContent @' + Add-Row -SchemaName 'rivet' -TableName 'Migrations' -Column @{ +'@ -ContainsRowsFor 'CheckpointMigration' -Database $RTDatabaseName + + ThenSchema -HasContent 'Remove-Table -Name ''Migrations''' -Database $RTDatabaseName + ThenSchema -Not -HasContent 'Remove-Schema' -Database $RTDatabaseName + ThenSchema -Not -HasContent 'Remove-PrimaryKey' -Database $RTDatabaseName + ThenSchema -Not -HasContent 'Remove-DefaultConstraint' -Database $RTDatabaseName + ThenSchema -Not -HasContent 'Remove-CheckConstraint' -Database $RTDatabaseName + ThenSchema -Not -HasContent 'Remove-Index' -Database $RTDatabaseName + ThenSchema -Not -HasContent 'Remove-UniqueKey' -Database $RTDatabaseName + ThenSchema -Not -HasContent 'Remove-Trigger' -Database $RTDatabaseName + ThenNoErrors + } - ThenMigration -HasContent 'Remove-Table -Name ''Migrations''' -Database $RTDatabaseName - ThenMigration -Not -HasContent 'Remove-Schema' -Database $RTDatabaseName - ThenMigration -Not -HasContent 'Remove-PrimaryKey' -Database $RTDatabaseName - ThenMigration -Not -HasContent 'Remove-DefaultConstraint' -Database $RTDatabaseName - ThenMigration -Not -HasContent 'Remove-CheckConstraint' -Database $RTDatabaseName - ThenMigration -Not -HasContent 'Remove-Index' -Database $RTDatabaseName - ThenMigration -Not -HasContent 'Remove-UniqueKey' -Database $RTDatabaseName - ThenMigration -Not -HasContent 'Remove-Trigger' -Database $RTDatabaseName - ThenNoErrors - Reset -} - -Describe 'Checkpoint-Migration.when there are multiple migrations but only one has been pushed' { - Init - GivenMigrationContent @' + It 'should only checkpoint pushed migrations when there are multiple migrations but only one has been pushed' { + GivenMigrationContent -Name 'CheckpointMigration' -Content @' function Push-Migration { Add-Table -Name 'Test1' -Column { @@ -389,8 +400,8 @@ function Pop-Migration Remove-Table 'Test1' } '@ - Invoke-RTRivet -Push -Database $RTDatabaseName - GivenMigrationContent @' + Invoke-RTRivet -Push -Database $RTDatabaseName + GivenMigrationContent -Name 'CheckpointMigration2' -Content @' function Push-Migration { Add-Table -Name 'Test2' -Column { @@ -403,26 +414,74 @@ function Pop-Migration Remove-Table 'Test2' } '@ - WhenCheckpointingMigration -Exclude $script:migrationPaths[1] - ThenSchemaFileRunnable - ThenMigration -HasContent @' + WhenCheckpointingMigration -Exclude $script:migrationPaths[1] + ThenSchemaFileRunnable + ThenSchema -HasContent @' Add-Table -Name 'Test1' -Column { int 'ID' -Identity } '@ -Database $RTDatabaseName - ThenMigration -Not -HasContent @' + ThenSchema -Not -HasContent @' Add-Table -Name 'Test2' -Column { int 'ID' -Identity } '@ -Database $RTDatabaseName - ThenNoErrors - Reset + ThenSchema -HasContent @' + Add-Row -SchemaName 'rivet' -TableName 'Migrations' -Column @{ +'@ -ContainsRowsFor 'CheckpointMigration' -Database $RTDatabaseName + ThenNoErrors + } + + It 'should only checkpoint all migrations when multiple migrations have been pushed' { + GivenMigrationContent -Name 'CheckpointMigration' -Content @' +function Push-Migration +{ + Add-Table -Name 'Test1' -Column { + int 'ID' -Identity + } +} + +function Pop-Migration +{ + Remove-Table 'Test1' +} +'@ + GivenMigrationContent -Name 'CheckpointMigration2' -Content @' +function Push-Migration +{ + Add-Table -Name 'Test2' -Column { + int 'ID' -Identity + } } -Describe 'Checkpoint-Migration.when no migrations have been pushed' { - Init - # Nothing to push here. Just running push here to initialize database with rivet.migrations table. - Invoke-RTRivet -Push -Database $RTDatabaseName - WhenCheckpointingMigration - ThenNoErrors +function Pop-Migration +{ + Remove-Table 'Test2' +} +'@ + Invoke-RTRivet -Push -Database $RTDatabaseName + WhenCheckpointingMigration -Exclude $script:migrationPaths[1] + ThenSchemaFileRunnable + ThenSchema -HasContent @' + Add-Table -Name 'Test1' -Column { + int 'ID' -Identity + } +'@ -Database $RTDatabaseName + ThenSchema -HasContent @' + Add-Table -Name 'Test2' -Column { + int 'ID' -Identity + } +'@ -Database $RTDatabaseName + ThenSchema -HasContent @' + Add-Row -SchemaName 'rivet' -TableName 'Migrations' -Column @{ +'@ -ContainsRowsFor 'CheckpointMigration', 'CheckpointMigration2' -Database $RTDatabaseName + ThenNoErrors + } + + It 'should do nothing when no migrations have been pushed' { + # Nothing to push here. Just running push here to initialize database with rivet.migrations table. + Invoke-RTRivet -Push -Database $RTDatabaseName + WhenCheckpointingMigration + ThenNoErrors + } } \ No newline at end of file diff --git a/Test/RivetTest/Functions/Invoke-Rivet.ps1 b/Test/RivetTest/Functions/Invoke-Rivet.ps1 index cf53298d..907d0c64 100644 --- a/Test/RivetTest/Functions/Invoke-Rivet.ps1 +++ b/Test/RivetTest/Functions/Invoke-Rivet.ps1 @@ -47,7 +47,12 @@ function Invoke-RTRivet [Parameter(ParameterSetName='Checkpoint')] [Switch] # Checkpoints the current state of the database so that it can be re-created. - $Checkpoint + $Checkpoint, + + [Parameter(ParameterSetName='InitializeSchema')] + [Switch] + # Initializes the database, including baseline schema. Use the -Checkpoint switch to create a database baseline. + $InitializeSchema ) Set-StrictMode -Version Latest diff --git a/Test/RivetTest/Functions/Start-RivetTest.ps1 b/Test/RivetTest/Functions/Start-RivetTest.ps1 index 2010dbd3..d3c68a01 100644 --- a/Test/RivetTest/Functions/Start-RivetTest.ps1 +++ b/Test/RivetTest/Functions/Start-RivetTest.ps1 @@ -24,7 +24,13 @@ function Start-RivetTest if( (Test-Pester) ) { - $script:RTTestRoot = Join-Path -Path $TestDrive.FullName -ChildPath ([IO.Path]::GetRandomFileName()) + $testDirectory = $TestDrive + if( $testDirectory | Get-Member -Name 'FullName' ) + { + $testDirectory = $testDirectory.FullName + } + + $script:RTTestRoot = Join-Path -Path $testDirectory -ChildPath ([IO.Path]::GetRandomFileName()) New-Item -Path $RTTestRoot -ItemType 'Directory' | Out-Null } else diff --git a/whiskey.yml b/whiskey.yml index eb235447..f7bec669 100644 --- a/whiskey.yml +++ b/whiskey.yml @@ -70,7 +70,108 @@ Build: - Pester4: Verbose: false # Rivet is super chatty with Verbose messages. - Script: Test\*.Tests.ps1 + Script: + - "Test\\Add-DataType.Tests.ps1" + - "Test\\Add-DefaultConstraint.Tests.ps1" + - "Test\\Add-Description.Tests.ps1" + - "Test\\Add-ForeignKey.Tests.ps1" + - "Test\\Add-Index.Tests.ps1" + - "Test\\Add-PrimaryKey.Tests.ps1" + - "Test\\Add-Table.Tests.ps1" + - "Test\\Add-UniqueKey.Tests.ps1" + - "Test\\bigint.Tests.ps1" + - "Test\\Columns.Tests.ps1" + - "Test\\Convert-Migration.Tests.ps1" + - "Test\\decimal.Tests.ps1" + - "Test\\Export-Migration.Tests.ps1" + - "Test\\Functions.Tests.ps1" + - "Test\\Get-Migration.Tests.ps1" + - "Test\\Get-RivetConfig.Tests.ps1" + - "Test\\Import-RivetPlugin.Tests.ps1" + - "Test\\Initialize-Database.Tests.ps1" + - "Test\\int.Tests.ps1" + - "Test\\Invoke-MigrationOperation.Tests.ps1" + - "Test\\Invoke-Query.Tests.ps1" + - "Test\\Invoke-Rivet.Tests.ps1" + - "Test\\Merge-Migration.Tests.ps1" + - "Test\\New-Migration.Tests.ps1" + - "Test\\Pop-Migration.Tests.ps1" + - "Test\\Remove-CheckConstraint.Tests.ps1" + - "Test\\Remove-DefaultConstraint.Tests.ps1" + - "Test\\Remove-Description.Tests.ps1" + - "Test\\Remove-ForeignKey.Tests.ps1" + - "Test\\Remove-Index.Tests.ps1" + - "Test\\Remove-PrimaryKey.Tests.ps1" + - "Test\\Remove-UniqueKey.Tests.ps1" + - "Test\\Rename-Datatype.Tests.ps1" + - "Test\\Rename-Object.Tests.ps1" + - "Test\\smallint.Tests.ps1" + - "Test\\Split-SqlBatchQuery.Tests.ps1" + - "Test\\tinyint.Tests.ps1" + - "Test\\Update-CodeObjectMetadata.Tests.ps1" + - "Test\\Update-Database.Tests.ps1" + - "Test\\Update-Description.Tests.ps1" + - "Test\\Update-Table.Tests.ps1" + - "Test\\varbinary.Tests.ps1" + - "Test\\varchar.Tests.ps1" + - "Test\\xml.Tests.ps1" + +- Pester: + AsJob: true + Configuration: + TestResult: + Enabled: true + OutputPath: .output\pester.xml + TestSuiteName: Rivet + Output: + Verbosity: Detailed + Run: + Path: Test\*.Tests.ps1 + ExcludePath: + - "*\\Test\\Add-DataType.Tests.ps1" + - "*\\Test\\Add-DefaultConstraint.Tests.ps1" + - "*\\Test\\Add-Description.Tests.ps1" + - "*\\Test\\Add-ForeignKey.Tests.ps1" + - "*\\Test\\Add-Index.Tests.ps1" + - "*\\Test\\Add-PrimaryKey.Tests.ps1" + - "*\\Test\\Add-Table.Tests.ps1" + - "*\\Test\\Add-UniqueKey.Tests.ps1" + - "*\\Test\\bigint.Tests.ps1" + - "*\\Test\\Columns.Tests.ps1" + - "*\\Test\\Convert-Migration.Tests.ps1" + - "*\\Test\\decimal.Tests.ps1" + - "*\\Test\\Export-Migration.Tests.ps1" + - "*\\Test\\Functions.Tests.ps1" + - "*\\Test\\Get-Migration.Tests.ps1" + - "*\\Test\\Get-RivetConfig.Tests.ps1" + - "*\\Test\\Import-RivetPlugin.Tests.ps1" + - "*\\Test\\Initialize-Database.Tests.ps1" + - "*\\Test\\int.Tests.ps1" + - "*\\Test\\Invoke-MigrationOperation.Tests.ps1" + - "*\\Test\\Invoke-Query.Tests.ps1" + - "*\\Test\\Invoke-Rivet.Tests.ps1" + - "*\\Test\\Merge-Migration.Tests.ps1" + - "*\\Test\\New-Migration.Tests.ps1" + - "*\\Test\\Pop-Migration.Tests.ps1" + - "*\\Test\\Remove-CheckConstraint.Tests.ps1" + - "*\\Test\\Remove-DefaultConstraint.Tests.ps1" + - "*\\Test\\Remove-Description.Tests.ps1" + - "*\\Test\\Remove-ForeignKey.Tests.ps1" + - "*\\Test\\Remove-Index.Tests.ps1" + - "*\\Test\\Remove-PrimaryKey.Tests.ps1" + - "*\\Test\\Remove-UniqueKey.Tests.ps1" + - "*\\Test\\Rename-Datatype.Tests.ps1" + - "*\\Test\\Rename-Object.Tests.ps1" + - "*\\Test\\smallint.Tests.ps1" + - "*\\Test\\Split-SqlBatchQuery.Tests.ps1" + - "*\\Test\\tinyint.Tests.ps1" + - "*\\Test\\Update-CodeObjectMetadata.Tests.ps1" + - "*\\Test\\Update-Database.Tests.ps1" + - "*\\Test\\Update-Description.Tests.ps1" + - "*\\Test\\Update-Table.Tests.ps1" + - "*\\Test\\varbinary.Tests.ps1" + - "*\\Test\\varchar.Tests.ps1" + - "*\\Test\\xml.Tests.ps1" - PowerShell: OnlyDuring: Build