-
Notifications
You must be signed in to change notification settings - Fork 0
/
Sql-Deploy.ps1
169 lines (143 loc) · 7.91 KB
/
Sql-Deploy.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
<#########################################################################################
Command line utility that can deploy a folder of SQL scripts.
The utility can be used to release all the scripts in the folder (e.g)
e.g. Release -Env QA -DeploymentRoot: "H:\Database\_Release\" -DeploymentFolder "2018\COLES PIC_Changes"
This is a step towards automating the release process.
Requirement:
# Specify path, environment(server, database, user, password) as parameters
# Run all \*.sql scripts in the specified path folder
# Log all output
# Exit on error and display clear error message. Also log error.
Additional requirement:
* Log each release to a database table, keyed by folder name. The folder name is the release name. This is a unique key
* Changes are detected by hashing the \*.sql files
* (If a release is changed and re-run , then a version number is incremented automatically??)
* Rollback. Run the scripts in a “Rollback” folder and update the status of the release to “rolled back”
* After the release, check-in the database schema changes by calling SQLCompare to compare the updated schema with a source control scripts folder.
Call GIT commit with the release folder name and version as a comment. Push the changes to the origin.
* The password and other environment parameters should be held in a config.json file.
The password should be stored encrypted. Hence the password is not required on the command line when invoking the deployment utility.
########################################################################################>
Param(
[Parameter(Mandatory=$true, Position=0, HelpMessage="Environment to deploy to?")][ValidateSet('dev','uat','qa','prod')]
[String]$EnvName,
[Parameter(Mandatory=$true, Position=1, HelpMessage="Root path of all deployment folders?")]
[String]$DeploymentRoot,
[Parameter(Mandatory=$true, Position=2, HelpMessage="Folder containing .sql scripts to deploy? (Relative to DeploymentRoot)")]
[String]$DeploymentFolder,
[Parameter(Mandatory=$false, Position=3, HelpMessage="Server name?")] # The following parameters mimic the SQLCMD.exe credentials parameters
[String]$S,
[Parameter(Mandatory=$false, Position=4, HelpMessage="Database name?")]
[String]$d,
[Parameter(Mandatory=$false, Position=5, HelpMessage="Use integrated security?")]
[Switch]$E,
[Parameter(Mandatory=$false, Position=6, HelpMessage="User name?")]
[String]$U,
[Parameter(Mandatory=$false, Position=7, HelpMessage="Password?")]
[String]$P,
[Parameter(Mandatory=$false, Position=8, HelpMessage="Remove deployment?")]
[Switch]$Remove
)
##############################################################################################################################################################
# Check parameters
##############################################################################################################################################################
#Write-Host $EnvName
#Write-Host $DeploymentRoot
#Write-Host $DeploymentFolder
if (-NOT (Test-Path $DeploymentRoot -PathType 'Container'))
{
Throw "$($DeploymentRoot) is not a valid folder."
}
$DeploymentFolder = $DeploymentFolder.TrimStart("\").TrimEnd("\")
$Path = Resolve-Path ($DeploymentRoot +"\" +$DeploymentFolder) -ErrorAction SilentlyContinue
if ($Path -eq $null)
{
Throw "$($DeploymentFolder) is not a valid deployment folder. DeploymentFolder must be a sub-folder relative to $DeploymentRoot."
}
if ($Remove) {
$Path = Resolve-Path ($DeploymentRoot +"\" +$DeploymentFolder+"\Remove") -ErrorAction SilentlyContinue
if ($Path -eq $null)
{
Throw "$($DeploymentFolder) does not have a sub-folder named ""Remove"". In order to remove a deployment, a sub-folder called ""Remove"" containing .sql scripts to remove the feature must be created under $DeploymentFolder."
}
}
##############################################################################################################################################################
# Load supporting modules
##############################################################################################################################################################
$scriptDir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
. $scriptDir\Get-SqlFilesHash.ps1
. $scriptDir\Config-Utils.ps1
. $scriptDir\Sql-Runner.ps1
##############################################################################################################################################################
# Check configuration
##############################################################################################################################################################
$config = (Get-ConfigAsDictionary)."$EnvName" # Configuration for the environment contains the connection details and credentials
if (($config -eq $null) -and ([String]::IsNullOrEmpty($S)) ) {
Throw "Environment $EnvName has not been configured. Either use Sql-Config.ps1 to set this up, or pass -S -d -U -P -E parameters instead"
}
if (($config -eq $null) ) {
$connectionHashTable = @{ S = $S }
}
else {
$connectionHashTable = Convert-Config-ToHashTable $config
}
if (![String]::IsNullOrEmpty($d)) {
$connectionHashTable.Remove("d")
$connectionHashTable.Add("d", $d)
}
if ($E -eq $true) {
$connectionHashTable.Remove("E")
$connectionHashTable.Add("E", $E)
}
if (![String]::IsNullOrEmpty($U)) {
$connectionHashTable.Remove("U")
$connectionHashTable.Add("U", $U)
}
if (![String]::IsNullOrEmpty($S)) {
$connectionHashTable.Remove("S")
$connectionHashTable.Add("S", $S)
}
if (![String]::IsNullOrEmpty($P)) {
$connectionHashTable.Remove("P")
$connectionHashTable.Add("P", $P)
}
##############################################################################################################################################################
# Do the work
##############################################################################################################################################################
Push-Location -Path $Path # make the folder that contains the .sql scripts the current folder
try {
$hashString = Get-SqlFilesHash -Path $Path # Hash of all .sql files in $Path
$connection = Get-SQLConnection @connectionHashTable
if (-not $Remove) {
if (!(Check-DeploymentRequired -Connection $connection -FeatureName $DeploymentFolder -HashString $hashString -ErrorAction stop))
{
Write-Host "Deployment of feature $($DeploymentFolder) already completed." -ForegroundColor Green
Exit
}
}
Notify-DeploymentStarting -Connection $connection -FeatureName $DeploymentFolder -HashString $hashString -Remove $Remove
$masterFileName = "_master.osql" # This is a temporary file containing the concatenation of all the release files in order (plus some pre and post sql commands)
Create-MasterFile -MasterFileName $masterFileName
$sqlcmdArgs0 = @{b=$true; i=$masterFileName; o=$($EnvName+'_master.log')} + $connectionHashTable
$sqlcmdArgs = Convert-HashTable-ToArray $sqlcmdArgs0 # Use normal array instead of hash table to pass arguments to .exe
#$sqlcmdArgs
&SqlCmd $sqlcmdArgs
Get-Content $($EnvName+'_master.log') # Output was re-directed to file
if ($LASTEXITCODE -ne 0)
{
Notify-DeploymentErrored -Connection $connection -FeatureName $DeploymentFolder -HashString $hashString -Remove $Remove
Throw "$(if ($Remove) {'Removal'} else {'Deployment'}) of feature $($DeploymentFolder) failed. Check the log file in the folder containing the .sql scripts"
}
else
{
Notify-DeploymentCompleted -Connection $connection -FeatureName $DeploymentFolder -HashString $hashString -Remove $Remove
Write-Host "$(if ($Remove) {'Removal'} else {'Deployment'}) of feature $($DeploymentFolder) succeeded." -ForegroundColor Green
}
}
catch {
# Do not continue after any error
throw
}
finally {
Pop-Location
}