Consolidated ASP Classic MVC framework from best components
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

325 lignes
9.7KB

  1. <#
  2. Deploy asp-territory to an existing IIS site, locally or over SSH.
  3. Remote mode:
  4. - Copies this script to the remote Windows host with scp
  5. - Executes it remotely via ssh in -RunRemoteCore mode
  6. - Preserves the remote site's current DB path unless -DbPath is passed
  7. - Can run standard migrations and an optional legacy migration script
  8. Local / remote core behavior:
  9. - Infers IIS site/app pool/work dir from the existing site when possible
  10. - Stops the site/app pool while deploying
  11. - Clones/pulls and hard-resets to origin/<Branch>
  12. - Points IIS at <WorkDir>\public
  13. - Reapplies the effective DB path in public\web.config
  14. - Grants IIS AppPool rights to the DB folder
  15. - Runs migrations
  16. - Restarts the site/app pool and smoke tests key routes
  17. #>
  18. param(
  19. [string]$Repo = 'git@onefortheroadgit.sytes.net:dcovington/asp-classic-unified-framework.git',
  20. [string]$Branch = 'main',
  21. [string]$SiteName = 'ttasp',
  22. [string]$AppPool = '',
  23. [string]$WorkDir = '',
  24. [string]$PublicDir = '',
  25. [string]$BaseUrl = '',
  26. [string]$DbPath = '',
  27. [switch]$RunMigrations = $true,
  28. [switch]$SkipLegacyIsBusinessMigration,
  29. [string]$LegacyMigrationScript = 'scripts\migrate_isbusiness_to_households.vbs',
  30. [switch]$UseRemoteSsh,
  31. [string]$RemoteTarget = '',
  32. [int]$RemotePort = 22,
  33. [string]$SshExe = 'ssh',
  34. [string]$ScpExe = 'scp',
  35. [switch]$RunRemoteCore
  36. )
  37. $ErrorActionPreference = 'Stop'
  38. function Ensure-Dir {
  39. param([string]$Path)
  40. if([string]::IsNullOrWhiteSpace($Path)){ return }
  41. if(!(Test-Path $Path)){
  42. New-Item -ItemType Directory -Force -Path $Path | Out-Null
  43. }
  44. }
  45. function Ensure-Command {
  46. param([string]$Name)
  47. if(!(Get-Command $Name -ErrorAction SilentlyContinue)){
  48. throw "$Name not found on PATH"
  49. }
  50. }
  51. function Get-DefaultRemoteTargetFromInfo {
  52. $infoPath = Join-Path $PSScriptRoot 'depolyinfo.txt'
  53. if(!(Test-Path $infoPath)){ return '' }
  54. $sshLine = Get-Content $infoPath | Where-Object { $_ -match '^\s*ssh\s+' } | Select-Object -First 1
  55. if([string]::IsNullOrWhiteSpace($sshLine)){ return '' }
  56. return ($sshLine -replace '^\s*ssh\s+', '').Trim()
  57. }
  58. function ConvertTo-PowerShellLiteral {
  59. param([AllowNull()][string]$Value)
  60. if($null -eq $Value){ return "''" }
  61. return "'" + ($Value -replace "'", "''") + "'"
  62. }
  63. function ConvertTo-CmdDoubleQuoted {
  64. param([AllowNull()][string]$Value)
  65. if($null -eq $Value){ return '""' }
  66. return '"' + ($Value -replace '"', '""') + '"'
  67. }
  68. function Get-DataSourceFromConfig {
  69. param([string]$ConfigPath)
  70. if(!(Test-Path $ConfigPath)){ return '' }
  71. $raw = Get-Content $ConfigPath -Raw
  72. $match = [regex]::Match($raw, 'Data Source=([^;]+);', [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
  73. if($match.Success){
  74. return $match.Groups[1].Value.Trim()
  75. }
  76. return ''
  77. }
  78. function Set-DataSourceInConfig {
  79. param(
  80. [string]$ConfigPath,
  81. [string]$EffectiveDbPath
  82. )
  83. if(!(Test-Path $ConfigPath)){ return }
  84. $raw = Get-Content $ConfigPath -Raw
  85. $updated = [regex]::Replace(
  86. $raw,
  87. 'Data Source=[^;]*;',
  88. ('Data Source=' + $EffectiveDbPath + ';'),
  89. [System.Text.RegularExpressions.RegexOptions]::IgnoreCase
  90. )
  91. if($updated -ne $raw){
  92. Set-Content -Path $ConfigPath -Value $updated -Encoding UTF8
  93. Write-Host "Updated ConnectionString Data Source to $EffectiveDbPath"
  94. }
  95. }
  96. function Get-BaseUrlFromSite {
  97. param($Site)
  98. $httpBind = $Site.Bindings.Collection | Where-Object { $_.protocol -eq 'http' } | Select-Object -First 1
  99. if($httpBind){
  100. $parts = $httpBind.bindingInformation.Split(':')
  101. $port = $parts[1]
  102. if([string]::IsNullOrWhiteSpace($port)){ $port = '80' }
  103. return ('http://127.0.0.1:' + $port)
  104. }
  105. return 'http://127.0.0.1'
  106. }
  107. function Invoke-DeployCore {
  108. Ensure-Command git
  109. Import-Module WebAdministration
  110. $site = Get-Website -Name $SiteName
  111. if(!$site){ throw "IIS site not found: $SiteName" }
  112. if([string]::IsNullOrWhiteSpace($AppPool)){
  113. $AppPool = $site.applicationPool
  114. }
  115. if([string]::IsNullOrWhiteSpace($PublicDir)){
  116. $PublicDir = $site.physicalPath
  117. }
  118. if([string]::IsNullOrWhiteSpace($WorkDir)){
  119. $pd = [Environment]::ExpandEnvironmentVariables($PublicDir)
  120. $pd = $pd.Trim().Trim('"')
  121. $pd = $pd.TrimEnd('\','/')
  122. if((Split-Path $pd -Leaf).ToLower() -eq 'public'){
  123. $WorkDir = Split-Path $pd -Parent
  124. } else {
  125. $WorkDir = $pd
  126. }
  127. }
  128. if([string]::IsNullOrWhiteSpace($BaseUrl)){
  129. $BaseUrl = Get-BaseUrlFromSite -Site $site
  130. }
  131. $currentPublicDir = $PublicDir
  132. $currentConfigPath = Join-Path $currentPublicDir 'web.config'
  133. $effectiveDbPath = $DbPath
  134. if([string]::IsNullOrWhiteSpace($effectiveDbPath)){
  135. $effectiveDbPath = Get-DataSourceFromConfig -ConfigPath $currentConfigPath
  136. }
  137. if([string]::IsNullOrWhiteSpace($effectiveDbPath)){
  138. throw 'No database path was provided and no existing Data Source could be read from the current web.config'
  139. }
  140. Write-Host "Stopping IIS site $SiteName and app pool $AppPool"
  141. try { Stop-Website -Name $SiteName } catch { }
  142. try { Stop-WebAppPool -Name $AppPool } catch { }
  143. Ensure-Dir (Split-Path $WorkDir -Parent)
  144. if((Test-Path $WorkDir) -and !(Test-Path (Join-Path $WorkDir '.git'))){
  145. $bak = ($WorkDir.TrimEnd('\') + '_pre_git_' + (Get-Date -Format 'yyyyMMdd_HHmmss'))
  146. Write-Host "Existing non-git folder detected. Moving to $bak"
  147. Move-Item -Force $WorkDir $bak
  148. }
  149. if(!(Test-Path $WorkDir)){
  150. Write-Host "Cloning $Repo -> $WorkDir"
  151. git clone $Repo $WorkDir
  152. }
  153. Push-Location $WorkDir
  154. try {
  155. Write-Host "Updating to origin/$Branch"
  156. git fetch origin
  157. git checkout $Branch
  158. & git reset --hard ("origin/" + $Branch)
  159. } finally {
  160. Pop-Location
  161. }
  162. if((Split-Path $WorkDir -Leaf).ToLower() -eq 'public'){
  163. $WorkDir = Split-Path $WorkDir -Parent
  164. }
  165. $PublicDir = Join-Path $WorkDir 'public'
  166. $cfg = Join-Path $PublicDir 'web.config'
  167. Set-ItemProperty ('IIS:\Sites\' + $SiteName) -Name physicalPath -Value $PublicDir
  168. Set-ItemProperty ('IIS:\Sites\' + $SiteName) -Name applicationPool -Value $AppPool
  169. Set-ItemProperty ('IIS:\AppPools\' + $AppPool) -Name processModel.identityType -Value NetworkService
  170. Set-DataSourceInConfig -ConfigPath $cfg -EffectiveDbPath $effectiveDbPath
  171. $dbFolder = Split-Path $effectiveDbPath -Parent
  172. if(!(Test-Path $dbFolder)){
  173. Ensure-Dir $dbFolder
  174. }
  175. icacls $dbFolder /grant ("IIS AppPool\" + $AppPool + ":(OI)(CI)(M)") /T | Out-Null
  176. Push-Location $WorkDir
  177. try {
  178. if($RunMigrations){
  179. Write-Host 'Running standard migrations'
  180. cscript //nologo scripts\runMigrations.vbs up
  181. }
  182. if(-not $SkipLegacyIsBusinessMigration){
  183. $legacyPath = Join-Path $WorkDir $LegacyMigrationScript
  184. if(!(Test-Path $legacyPath)){
  185. throw "Legacy migration script not found: $legacyPath"
  186. }
  187. Write-Host 'Running legacy IsBusiness migration'
  188. cscript //nologo $legacyPath $effectiveDbPath
  189. }
  190. } finally {
  191. Pop-Location
  192. }
  193. if((Get-WebAppPoolState -Name $AppPool).Value -eq 'Started'){
  194. Restart-WebAppPool -Name $AppPool
  195. } else {
  196. Start-WebAppPool -Name $AppPool
  197. }
  198. Start-Website $SiteName
  199. Start-Sleep -Seconds 1
  200. $paths = @('/','/territories','/households','/householder-names')
  201. foreach($path in $paths){
  202. $url = $BaseUrl + $path
  203. $response = Invoke-WebRequest -UseBasicParsing -Uri $url -TimeoutSec 30
  204. Write-Host ("OK " + $path + ' -> ' + $response.StatusCode)
  205. }
  206. Write-Host 'Deploy complete.'
  207. }
  208. if($UseRemoteSsh -and !$RunRemoteCore -and [string]::IsNullOrWhiteSpace($RemoteTarget)){
  209. $RemoteTarget = Get-DefaultRemoteTargetFromInfo
  210. }
  211. if($UseRemoteSsh -and !$RunRemoteCore -and -not [string]::IsNullOrWhiteSpace($RemoteTarget)){
  212. Ensure-Command $SshExe
  213. Ensure-Command $ScpExe
  214. $remoteScriptPath = 'C:\Windows\Temp\deploy-test-territory-git.ps1'
  215. $scpDestination = "${RemoteTarget}:C:/Windows/Temp/deploy-test-territory-git.ps1"
  216. Write-Host "Copying deploy script to $RemoteTarget"
  217. & $ScpExe -P $RemotePort $PSCommandPath $scpDestination
  218. if($LASTEXITCODE -ne 0){ throw 'scp failed' }
  219. $remoteCommand = New-Object System.Collections.Generic.List[string]
  220. @(
  221. 'powershell',
  222. '-NoProfile',
  223. '-ExecutionPolicy', 'Bypass',
  224. '-File', (ConvertTo-CmdDoubleQuoted $remoteScriptPath),
  225. '-RunRemoteCore',
  226. '-Repo', (ConvertTo-CmdDoubleQuoted $Repo),
  227. '-Branch', (ConvertTo-CmdDoubleQuoted $Branch),
  228. '-SiteName', (ConvertTo-CmdDoubleQuoted $SiteName)
  229. ) | ForEach-Object { [void]$remoteCommand.Add($_) }
  230. if(-not [string]::IsNullOrWhiteSpace($AppPool)){
  231. [void]$remoteCommand.Add('-AppPool')
  232. [void]$remoteCommand.Add((ConvertTo-CmdDoubleQuoted $AppPool))
  233. }
  234. if(-not [string]::IsNullOrWhiteSpace($WorkDir)){
  235. [void]$remoteCommand.Add('-WorkDir')
  236. [void]$remoteCommand.Add((ConvertTo-CmdDoubleQuoted $WorkDir))
  237. }
  238. if(-not [string]::IsNullOrWhiteSpace($PublicDir)){
  239. [void]$remoteCommand.Add('-PublicDir')
  240. [void]$remoteCommand.Add((ConvertTo-CmdDoubleQuoted $PublicDir))
  241. }
  242. if(-not [string]::IsNullOrWhiteSpace($BaseUrl)){
  243. [void]$remoteCommand.Add('-BaseUrl')
  244. [void]$remoteCommand.Add((ConvertTo-CmdDoubleQuoted $BaseUrl))
  245. }
  246. if(-not [string]::IsNullOrWhiteSpace($DbPath)){
  247. [void]$remoteCommand.Add('-DbPath')
  248. [void]$remoteCommand.Add((ConvertTo-CmdDoubleQuoted $DbPath))
  249. }
  250. if(-not [string]::IsNullOrWhiteSpace($LegacyMigrationScript)){
  251. [void]$remoteCommand.Add('-LegacyMigrationScript')
  252. [void]$remoteCommand.Add((ConvertTo-CmdDoubleQuoted $LegacyMigrationScript))
  253. }
  254. if($RunMigrations){ $remoteCommand += '-RunMigrations' }
  255. if($SkipLegacyIsBusinessMigration){ $remoteCommand += '-SkipLegacyIsBusinessMigration' }
  256. Write-Host "Executing remote deploy on $RemoteTarget"
  257. & $SshExe -p $RemotePort $RemoteTarget ($remoteCommand -join ' ')
  258. if($LASTEXITCODE -ne 0){ throw 'remote deploy failed' }
  259. exit 0
  260. }
  261. Invoke-DeployCore

Powered by TurnKey Linux.