Files
PowderCoatingLogix/Jenkinsfile
T
spouliot 3803d16731 Fix prod Jenkins pipeline: add tests, restart, and health check stage
- Add Test stage (unit tests only) before migrations so bad code fails fast
- Add az webapp restart after async deploy to ensure new code is loaded
- Add Health Check stage that polls app for up to 3 minutes post-deploy
- Restore xcopy of wwwroot (needed for linux-x64 publish on Windows)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 21:44:51 -04:00

112 lines
4.3 KiB
Groovy

pipeline {
agent { label 'appdev' }
options {
disableConcurrentBuilds()
timestamps()
}
environment {
PATH = "C:\\Program Files\\Microsoft SDKs\\Azure\\CLI2\\wbin;${env.PATH}"
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Restore & Build') {
steps {
bat 'dotnet restore PowderCoatingApp.sln'
bat 'dotnet build PowderCoatingApp.sln -c Release --no-restore'
}
}
stage('Test') {
steps {
bat 'dotnet test tests\\PowderCoating.UnitTests --no-build -c Release --logger "trx;LogFileName=results.trx" --results-directory TestResults'
}
post {
always {
junit testResults: 'TestResults/*.trx', allowEmptyResults: true
}
}
}
stage('Run Migrations') {
steps {
bat 'dotnet tool install --global dotnet-ef 2>nul || dotnet tool update --global dotnet-ef 2>nul'
withCredentials([string(credentialsId: 'pcl-prod-sql', variable: 'SQL_CONN')]) {
bat '"%USERPROFILE%\\.dotnet\\tools\\dotnet-ef.exe" database update --project src\\PowderCoating.Infrastructure --startup-project src\\PowderCoating.Web --configuration Release --no-build --context ApplicationDbContext --connection "%SQL_CONN%"'
}
}
}
stage('Publish') {
steps {
bat 'dotnet publish src\\PowderCoating.Web\\PowderCoating.Web.csproj -c Release -r linux-x64 --self-contained false -o publish'
bat 'xcopy /E /Y /I src\\PowderCoating.Web\\wwwroot publish\\wwwroot\\'
}
}
stage('Deploy to Azure') {
steps {
bat 'powershell -Command "Add-Type -Assembly System.IO.Compression.FileSystem; if (Test-Path deploy.zip) { Remove-Item deploy.zip }; [System.IO.Compression.ZipFile]::CreateFromDirectory(\'publish\', \'deploy.zip\')"'
withCredentials([azureServicePrincipal(
credentialsId: 'azure-pcl',
subscriptionIdVariable: 'AZ_SUB_ID',
clientIdVariable: 'AZ_CLIENT_ID',
clientSecretVariable: 'AZ_CLIENT_SECRET',
tenantIdVariable: 'AZ_TENANT_ID'
)]) {
bat 'az login --service-principal -u "%AZ_CLIENT_ID%" -p "%AZ_CLIENT_SECRET%" --tenant "%AZ_TENANT_ID%" --output none'
bat 'az account set --subscription "%AZ_SUB_ID%"'
bat 'az webapp deploy --resource-group rg-powdercoatinglogix-prod --name linuxpcl --src-path deploy.zip --type zip --async true'
bat 'az webapp restart --resource-group rg-powdercoatinglogix-prod --name linuxpcl'
bat 'az logout'
}
}
}
stage('Health Check') {
steps {
powershell '''
$url = "https://linuxpcl.azurewebsites.net/"
$timeout = 180
$elapsed = 0
Write-Host "Polling $url for up to $timeout seconds..."
do {
Start-Sleep -Seconds 10
$elapsed += 10
try {
$r = Invoke-WebRequest $url -UseBasicParsing -TimeoutSec 10
if ($r.StatusCode -lt 400) {
Write-Host "App responded HTTP $($r.StatusCode) after ${elapsed}s"
exit 0
}
} catch {
Write-Host "[${elapsed}s] Not yet responding: $_"
}
} while ($elapsed -lt $timeout)
Write-Error "App did not come healthy within $timeout seconds"
exit 1
'''
}
}
}
post {
success {
echo "Production deployment #${BUILD_NUMBER} completed successfully."
}
failure {
echo "Pipeline #${BUILD_NUMBER} FAILED — review the stage logs above."
}
always {
cleanWs()
}
}
}