8646fa83c8
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
122 lines
4.8 KiB
Groovy
122 lines
4.8 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 {
|
|
powershell '''
|
|
Add-Type -Assembly System.IO.Compression.FileSystem
|
|
if (Test-Path deploy.zip) { Remove-Item deploy.zip }
|
|
$publishDir = (Resolve-Path "publish").Path
|
|
$zip = [System.IO.Compression.ZipFile]::Open("deploy.zip", "Create")
|
|
Get-ChildItem -Path $publishDir -Recurse -File | ForEach-Object {
|
|
$entryName = $_.FullName.Substring($publishDir.Length + 1).Replace("\\", "/")
|
|
[System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zip, $_.FullName, $entryName, "Optimal") | Out-Null
|
|
}
|
|
$zip.Dispose()
|
|
Write-Host "deploy.zip created with forward-slash entry paths"
|
|
'''
|
|
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 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()
|
|
}
|
|
}
|
|
}
|