properties([ buildDiscarder(logRotator(numToKeepStr: '20')) ]) def writeBuildMetadata() { nodejs(nodeJSInstallationName: 'Node23') { if (isUnix()) { sh ''' node -e "const fs = require('fs'); fs.writeFileSync('src/buildInfo.json', JSON.stringify({ buildNumber: process.env.BUILD_NUMBER || 'dev' }, null, 2) + '\\n');" ''' } else { bat ''' node -e "const fs = require('fs'); fs.writeFileSync('src/buildInfo.json', JSON.stringify({ buildNumber: process.env.BUILD_NUMBER || 'dev' }, null, 2) + '\\n');" ''' } } } def buildLinux() { node('ubuntu') { try { stage('Checkout (Ubuntu)') { checkout scm } stage('Setup Node.js (Ubuntu)') { nodejs(nodeJSInstallationName: 'Node23') { sh 'node -v' sh 'pnpm -v' } } stage('Install Dependencies (Ubuntu)') { nodejs(nodeJSInstallationName: 'Node23') { sh 'pnpm install --frozen-lockfile --production=false' } } stage('Write Build Metadata (Ubuntu)') { writeBuildMetadata() } stage('Build (Ubuntu)') { nodejs(nodeJSInstallationName: 'Node23') { sh "VITE_BUILD_NUMBER=${env.BUILD_NUMBER} NODE_ENV=production pnpm build:linux" } } stage('Archive Artifacts (Ubuntu)') { archiveArtifacts artifacts: 'app_dist/**/*.deb, app_dist/**/*.rpm', fingerprint: true } } finally { cleanWs() } } } def buildOnLabel(label, buildCommand) { return { node(label) { stage("Checkout (${label})") { checkout scm } stage("Setup Node.js (${label})") { nodejs(nodeJSInstallationName: 'Node23') { if (isUnix()) { sh 'node -v' sh 'pnpm -v' } else { bat 'node -v' bat 'pnpm -v' } } } stage("Install Dependencies (${label})") { nodejs(nodeJSInstallationName: 'Node23') { if (isUnix()) { sh 'pnpm install --frozen-lockfile --production=false' } else { bat 'pnpm install --frozen-lockfile --production=false' } } } stage("Write Build Metadata (${label})") { writeBuildMetadata() } stage("Build (${label})") { nodejs(nodeJSInstallationName: 'Node23') { if (isUnix()) { sh "VITE_BUILD_NUMBER=${env.BUILD_NUMBER} NODE_ENV=production ${buildCommand}" } else { bat "set VITE_BUILD_NUMBER=${env.BUILD_NUMBER} && set NODE_ENV=production && ${buildCommand}" } } } stage("Archive Artifacts (${label})") { archiveArtifacts artifacts: 'app_dist/**/farmcontrol-server-*.dmg, app_dist/**/farmcontrol-server-*.exe, app_dist/**/farmcontrol-server-*.pkg, app_dist/**/farmcontrol-server-*.msi', fingerprint: true } } } } def setBuildNameFromPackageVersion() { node('ubuntu') { stage('Set Build Name') { checkout scm def version nodejs(nodeJSInstallationName: 'Node23') { version = sh( script: "node -p \"require('./package.json').version\"", returnStdout: true ).trim() } def buildName = "v${version}-b${env.BUILD_NUMBER}" currentBuild.displayName = buildName echo "Build name set to: ${buildName}" } } } try { setBuildNameFromPackageVersion() parallel( 'Windows Build': buildOnLabel('windows', 'pnpm build:electron'), 'MacOS Build': buildOnLabel('macos', 'pnpm build:electron:mac'), 'Ubuntu Build': { buildLinux() } ) echo 'All parallel stages completed successfully!' } catch (Exception e) { echo "Pipeline failed: ${e.message}" throw e }