From e447cdc803904b8ea12b36c6463e7bc33817cad0 Mon Sep 17 00:00:00 2001 From: Scott Pouliot Date: Mon, 4 May 2026 21:29:18 -0400 Subject: [PATCH] Rewrite Jenkinsfile for Windows appdev agent (bat, az CLI, EF direct update) --- Jenkinsfile | 160 ++++++++++------------------------------------------ 1 file changed, 30 insertions(+), 130 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index b7ff8c5..93bcc42 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,154 +1,54 @@ pipeline { - agent any + agent { label 'appdev' } - // No triggers — start this pipeline manually from the Jenkins UI only. - - environment { - DOTNET_CLI_HOME = '/tmp/dotnet_cli_home' - WEB_PROJECT = 'src/PowderCoating.Web/PowderCoating.Web.csproj' - INFRA_PROJECT = 'src/PowderCoating.Infrastructure/PowderCoating.Infrastructure.csproj' - PUBLISH_DIR = "${WORKSPACE}/publish" - DEPLOY_ZIP = "${WORKSPACE}/deploy_${BUILD_NUMBER}.zip" - MIGRATION_SQL = "${WORKSPACE}/migration_${BUILD_NUMBER}.sql" + options { + disableConcurrentBuilds() + timestamps() } stages { - stage('Checkout') { steps { - checkout([ - $class: 'GitSCM', - branches: [[name: 'refs/heads/master']], - userRemoteConfigs: scm.userRemoteConfigs - ]) - echo "Building commit: ${GIT_COMMIT}" + checkout scm } } - stage('Build & Test') { + stage('Restore & Build') { steps { - sh 'dotnet restore' - sh 'dotnet build --no-restore -c Release' - sh ''' - dotnet test --no-build -c Release \ - --logger "trx;LogFileName=results.trx" \ - --results-directory TestResults - ''' + bat 'dotnet restore PowderCoatingApp.sln' + bat 'dotnet build PowderCoatingApp.sln -c Release --no-restore' } - 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 { - sh """ - dotnet publish '${WEB_PROJECT}' \ - -c Release --no-build \ - -o '${PUBLISH_DIR}' - """ + bat 'dotnet publish src\\PowderCoating.Web\\PowderCoating.Web.csproj -c Release --no-build -o publish' } } - // Generates an idempotent SQL migration script (no live DB connection required). - // The script checks which migrations have already been applied before running each one. - stage('Generate Migration Script') { + stage('Deploy to Azure') { steps { - sh """ - dotnet ef migrations script \ - --idempotent \ - --output '${MIGRATION_SQL}' \ - --project '${INFRA_PROJECT}' \ - --startup-project '${WEB_PROJECT}' \ - --context ApplicationDbContext \ - --no-build - """ - archiveArtifacts artifacts: "migration_${BUILD_NUMBER}.sql", fingerprint: true - echo "Migration script archived — review it in the Jenkins build artifacts before this pipeline runs next time." - } - } - - stage('Apply Migration to Azure SQL') { - steps { - withCredentials([ - string(credentialsId: 'PCL_SQL_SERVER', variable: 'SQL_SERVER'), - string(credentialsId: 'PCL_SQL_DATABASE', variable: 'SQL_DATABASE'), - string(credentialsId: 'PCL_SQL_USER', variable: 'SQL_USER'), - string(credentialsId: 'PCL_SQL_PASSWORD', variable: 'SQL_PASSWORD') - ]) { - sh ''' - echo "Applying migration to ${SQL_SERVER}/${SQL_DATABASE} ..." - /opt/mssql-tools18/bin/sqlcmd \ - -S "${SQL_SERVER}" \ - -d "${SQL_DATABASE}" \ - -U "${SQL_USER}" \ - -P "${SQL_PASSWORD}" \ - -C \ - -b \ - -i "${MIGRATION_SQL}" - echo "Migration applied successfully." - ''' - } - } - } - - stage('Deploy to Azure App Service') { - steps { - withCredentials([ - string(credentialsId: 'PCL_AZURE_CLIENT_ID', variable: 'AZ_CLIENT_ID'), - string(credentialsId: 'PCL_AZURE_CLIENT_SECRET', variable: 'AZ_CLIENT_SECRET'), - string(credentialsId: 'PCL_AZURE_TENANT_ID', variable: 'AZ_TENANT_ID'), - string(credentialsId: 'PCL_AZURE_SUBSCRIPTION_ID', variable: 'AZ_SUBSCRIPTION_ID'), - string(credentialsId: 'PCL_AZURE_RESOURCE_GROUP', variable: 'AZ_RG'), - string(credentialsId: 'PCL_AZURE_APP_NAME', variable: 'AZ_APP') - ]) { - sh ''' - az login --service-principal \ - --username "$AZ_CLIENT_ID" \ - --password "$AZ_CLIENT_SECRET" \ - --tenant "$AZ_TENANT_ID" \ - --output none - - az account set --subscription "$AZ_SUBSCRIPTION_ID" - - echo "Packaging deployment artifact ..." - cd "$PUBLISH_DIR" - zip -r "$DEPLOY_ZIP" . - - echo "Pushing ZIP to ${AZ_APP} ..." - az webapp deployment source config-zip \ - --resource-group "$AZ_RG" \ - --name "$AZ_APP" \ - --src "$DEPLOY_ZIP" - - az logout - echo "Deploy complete." - ''' - } - } - } - - stage('Smoke Test') { - steps { - withCredentials([ - string(credentialsId: 'PCL_AZURE_APP_NAME', variable: 'AZ_APP') - ]) { - sh ''' - APP_URL="https://${AZ_APP}.azurewebsites.net" - echo "Smoke-testing ${APP_URL} ..." - HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \ - --max-time 45 --retry 3 --retry-delay 10 \ - "${APP_URL}") - echo "HTTP status: ${HTTP_STATUS}" - # 200 = OK, 302 = redirect to login (both are healthy) - if [ "$HTTP_STATUS" != "200" ] && [ "$HTTP_STATUS" != "302" ]; then - echo "SMOKE TEST FAILED — got HTTP ${HTTP_STATUS}" - exit 1 - fi - echo "Smoke test passed." - ''' + bat 'powershell -Command "Compress-Archive -Path publish\\* -DestinationPath deploy.zip -Force"' + 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' + bat 'az logout' } } } @@ -156,7 +56,7 @@ pipeline { post { success { - echo "Production deployment #${BUILD_NUMBER} (${GIT_COMMIT}) completed successfully." + echo "Production deployment #${BUILD_NUMBER} completed successfully." } failure { echo "Pipeline #${BUILD_NUMBER} FAILED — review the stage logs above."