diff --git a/.editorconfig b/.editorconfig index 601dc00b4b..2ef5c541af 100644 --- a/.editorconfig +++ b/.editorconfig @@ -27,3 +27,10 @@ indent_size = 2 [build/premake/premake5/**] ignore = true + +[*.Jenkinsfile] +indent_size = 4 +# Jenkins recommends using spaces for indentation. See: +# https://wiki.jenkins.io/display/JENKINS/Code+Style+Guidelines +# Additionally, our linter npm-groovy-lint does not support tabs. +indent_style = space \ No newline at end of file diff --git a/.gitea/workflows/lint.yml b/.gitea/workflows/lint.yml index cd72e27ef3..59daf5616c 100644 --- a/.gitea/workflows/lint.yml +++ b/.gitea/workflows/lint.yml @@ -59,3 +59,19 @@ jobs: - name: Check for issues with copyright run: ./source/tools/lint/copyright/copyright.sh --from ${{ env.BASE_SHA }} --to ${{ env.HEAD_SHA }} + + jenkinsfiles: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install npm-groovy-lint + run: npm install -g npm-groovy-lint + + - name: Check for issues with jenkins files + run: ./source/tools/lint/jenkinsfiles/jenkinsfiles.sh --from ${{ env.BASE_SHA }} --to ${{ env.HEAD_SHA }} diff --git a/.groovylintrc.json b/.groovylintrc.json new file mode 100644 index 0000000000..83ee7f9a18 --- /dev/null +++ b/.groovylintrc.json @@ -0,0 +1,15 @@ +{ + "extends": "recommended-jenkinsfile", + "rules": { + "formatting.LineLength": { + "length": 300, + "severity": "info" + }, + "size.NestedBlockDepth": { + "maxNestedBlockDepth": 15 + }, + "formatting.DuplicateNumberLiteral": "off", + "formatting.DuplicateMapLiteral": "off", + "formatting.DuplicateStringLiteral": "off" + } +} \ No newline at end of file diff --git a/build/jenkins/pipelines/bundles.Jenkinsfile b/build/jenkins/pipelines/bundles.Jenkinsfile index 580a17473b..a2ae01079f 100644 --- a/build/jenkins/pipelines/bundles.Jenkinsfile +++ b/build/jenkins/pipelines/bundles.Jenkinsfile @@ -18,133 +18,133 @@ // This pipeline is used to generate bundles (Windows installer, macOS package, and source tarballs). pipeline { - agent { - node { - label 'macOSAgentVentura' - } - } + agent { + node { + label 'macOSAgentVentura' + } + } - // Archive the installer for public download; keep only the latest one. - options { - buildDiscarder logRotator(artifactNumToKeepStr: '1') - skipDefaultCheckout true - } + // Archive the installer for public download; keep only the latest one. + options { + buildDiscarder logRotator(artifactNumToKeepStr: '1') + skipDefaultCheckout true + } - parameters { - string(name: 'BUNDLE_VERSION', defaultValue: '0.28.0dev', description: 'Bundle Version') - booleanParam(name: 'DO_GZIP', defaultValue: true, description: 'Create .gz unix tarballs as well as .xz') - } + parameters { + string(name: 'BUNDLE_VERSION', defaultValue: '0.28.0dev', description: 'Bundle Version') + booleanParam(name: 'DO_GZIP', defaultValue: true, description: 'Create .gz unix tarballs as well as .xz') + } - environment { - MIN_OSX_VERSION = "10.15" - } + environment { + MIN_OSX_VERSION = '10.15' + } - stages { - stage("Checkout Nightly Build") { - steps { - checkout changelog: false, poll: false, scm: [ - $class: 'SubversionSCM', - locations: [[local: '.', remote: 'https://svn.wildfiregames.com/nightly-build/trunk']], - quietOperation: false, - workspaceUpdater: [$class: 'UpdateWithCleanUpdater']] - sh "svn cleanup" - } - } + stages { + stage('Checkout Nightly Build') { + steps { + checkout changelog: false, poll: false, scm: [ + $class: 'SubversionSCM', + locations: [[local: '.', remote: 'https://svn.wildfiregames.com/nightly-build/trunk']], + quietOperation: false, + workspaceUpdater: [$class: 'UpdateWithCleanUpdater']] + sh 'svn cleanup' + } + } - stage("Compile Native macOS Executable") { - steps { - sh "cd libraries/ && MIN_OSX_VERSION=${env.MIN_OSX_VERSION} ./build-macos-libs.sh ${JOBS} --force-rebuild" - sh "cd build/workspaces/ && ./update-workspaces.sh --macosx-version-min=${env.MIN_OSX_VERSION}" - sh "cd build/workspaces/gcc/ && make ${JOBS}" - sh "svn cleanup --remove-unversioned build" - sh "svn cleanup --remove-unversioned libraries" - } - } + stage('Compile Native macOS Executable') { + steps { + sh "cd libraries/ && MIN_OSX_VERSION=${env.MIN_OSX_VERSION} ./build-macos-libs.sh ${JOBS} --force-rebuild" + sh "cd build/workspaces/ && ./update-workspaces.sh --macosx-version-min=${env.MIN_OSX_VERSION}" + sh "cd build/workspaces/gcc/ && make ${JOBS}" + sh 'svn cleanup --remove-unversioned build' + sh 'svn cleanup --remove-unversioned libraries' + } + } - stage("Create Mod Archives") { - steps { - sh "source/tools/dist/build-archives.sh" - } - } + stage('Create Mod Archives') { + steps { + sh 'source/tools/dist/build-archives.sh' + } + } - stage("Create Native macOS Bundle") { - steps { - withCredentials([ - string(credentialsId: 'apple-keychain', variable: 'KEYCHAIN_PW'), - string(credentialsId: 'apple-signing', variable: 'SIGNKEY_SHA'), - usernamePassword(credentialsId: 'apple-notarization', passwordVariable: 'NOTARIZATION_PW', usernameVariable: 'NOTARIZATION_USER')]) - { - sh ''' - security unlock-keychain -p ${KEYCHAIN_PW} login.keychain - /opt/wfg/venv/bin/python3 source/tools/dist/build-osx-bundle.py \ - --min_osx=${MIN_OSX_VERSION} \ - -s ${SIGNKEY_SHA} \ - --notarytool_user=${NOTARIZATION_USER} \ - --notarytool_team=P7YF26GARW \ - --notarytool_password=${NOTARIZATION_PW} \ - ${BUNDLE_VERSION} - ''' - } - } - } + stage('Create Native macOS Bundle') { + steps { + withCredentials([ + string(credentialsId: 'apple-keychain', variable: 'KEYCHAIN_PW'), + string(credentialsId: 'apple-signing', variable: 'SIGNKEY_SHA'), + usernamePassword(credentialsId: 'apple-notarization', passwordVariable: 'NOTARIZATION_PW', usernameVariable: 'NOTARIZATION_USER')]) + { + sh ''' + security unlock-keychain -p ${KEYCHAIN_PW} login.keychain + /opt/wfg/venv/bin/python3 source/tools/dist/build-osx-bundle.py \ + --min_osx=${MIN_OSX_VERSION} \ + -s ${SIGNKEY_SHA} \ + --notarytool_user=${NOTARIZATION_USER} \ + --notarytool_team=P7YF26GARW \ + --notarytool_password=${NOTARIZATION_PW} \ + ${BUNDLE_VERSION} + ''' + } + } + } - stage("Compile Intel macOS Executable") { - environment { - ARCH = "x86_64" - HOSTTYPE = "x86_64" - } - steps { - sh "cd libraries/ && MIN_OSX_VERSION=${env.MIN_OSX_VERSION} ./build-macos-libs.sh ${JOBS} --force-rebuild" - sh "cd build/workspaces/ && ./update-workspaces.sh --macosx-version-min=${env.MIN_OSX_VERSION}" - sh "cd build/workspaces/gcc/ && make clean" - sh "cd build/workspaces/gcc/ && make ${JOBS}" - sh "svn cleanup --remove-unversioned build" - sh "svn cleanup --remove-unversioned libraries" - } - } + stage('Compile Intel macOS Executable') { + environment { + ARCH = 'x86_64' + HOSTTYPE = 'x86_64' + } + steps { + sh "cd libraries/ && MIN_OSX_VERSION=${env.MIN_OSX_VERSION} ./build-macos-libs.sh ${JOBS} --force-rebuild" + sh "cd build/workspaces/ && ./update-workspaces.sh --macosx-version-min=${env.MIN_OSX_VERSION}" + sh 'cd build/workspaces/gcc/ && make clean' + sh "cd build/workspaces/gcc/ && make ${JOBS}" + sh 'svn cleanup --remove-unversioned build' + sh 'svn cleanup --remove-unversioned libraries' + } + } - stage("Create Intel macOS Bundle") { - steps { - withCredentials([ - string(credentialsId: 'apple-keychain', variable: 'KEYCHAIN_PW'), - string(credentialsId: 'apple-signing', variable: 'SIGNKEY_SHA'), - usernamePassword(credentialsId: 'apple-notarization', passwordVariable: 'NOTARIZATION_PW', usernameVariable: 'NOTARIZATION_USER')]) - { - sh ''' - security unlock-keychain -p ${KEYCHAIN_PW} login.keychain - /opt/wfg/venv/bin/python3 source/tools/dist/build-osx-bundle.py \ - --architecture=x86_64 \ - --min_osx=${MIN_OSX_VERSION} \ - -s ${SIGNKEY_SHA} \ - --notarytool_user=${NOTARIZATION_USER} \ - --notarytool_team=P7YF26GARW \ - --notarytool_password=${NOTARIZATION_PW} \ - ${BUNDLE_VERSION} - ''' - } - } - } + stage('Create Intel macOS Bundle') { + steps { + withCredentials([ + string(credentialsId: 'apple-keychain', variable: 'KEYCHAIN_PW'), + string(credentialsId: 'apple-signing', variable: 'SIGNKEY_SHA'), + usernamePassword(credentialsId: 'apple-notarization', passwordVariable: 'NOTARIZATION_PW', usernameVariable: 'NOTARIZATION_USER')]) + { + sh ''' + security unlock-keychain -p ${KEYCHAIN_PW} login.keychain + /opt/wfg/venv/bin/python3 source/tools/dist/build-osx-bundle.py \ + --architecture=x86_64 \ + --min_osx=${MIN_OSX_VERSION} \ + -s ${SIGNKEY_SHA} \ + --notarytool_user=${NOTARIZATION_USER} \ + --notarytool_team=P7YF26GARW \ + --notarytool_password=${NOTARIZATION_PW} \ + ${BUNDLE_VERSION} + ''' + } + } + } - stage("Create Windows Installer & Tarballs") { - steps { - sh "BUNDLE_VERSION=${params.BUNDLE_VERSION} DO_GZIP=${params.DO_GZIP} source/tools/dist/build-unix-win32.sh" - } - } + stage('Create Windows Installer & Tarballs') { + steps { + sh "BUNDLE_VERSION=${params.BUNDLE_VERSION} DO_GZIP=${params.DO_GZIP} source/tools/dist/build-unix-win32.sh" + } + } - stage("Generate Signatures and Checksums") { - steps { - withCredentials([sshUserPrivateKey(credentialsId: 'minisign-releases-key', keyFileVariable: 'MINISIGN_KEY', passphraseVariable: 'MINISIGN_PASS')]) { - sh 'echo ${MINISIGN_PASS} | minisign -s ${MINISIGN_KEY} -Sm *.{dmg,exe,tar.gz,tar.xz}' - } - sh 'for file in *.{dmg,exe,tar.gz,tar.xz}; do md5sum "${file}" > "${file}".md5sum; done' - sh 'for file in *.{dmg,exe,tar.gz,tar.xz}; do sha1sum "${file}" > "${file}".sha1sum; done' - } - } - } + stage('Generate Signatures and Checksums') { + steps { + withCredentials([sshUserPrivateKey(credentialsId: 'minisign-releases-key', keyFileVariable: 'MINISIGN_KEY', passphraseVariable: 'MINISIGN_PASS')]) { + sh 'echo ${MINISIGN_PASS} | minisign -s ${MINISIGN_KEY} -Sm *.{dmg,exe,tar.gz,tar.xz}' + } + sh 'for file in *.{dmg,exe,tar.gz,tar.xz}; do md5sum "${file}" > "${file}".md5sum; done' + sh 'for file in *.{dmg,exe,tar.gz,tar.xz}; do sha1sum "${file}" > "${file}".sha1sum; done' + } + } + } - post { - success { - archiveArtifacts '*.dmg,*.exe,*.tar.gz,*.tar.xz,*.minisig,*.md5sum,*.sha1sum' - } - } + post { + success { + archiveArtifacts '*.dmg,*.exe,*.tar.gz,*.tar.xz,*.minisig,*.md5sum,*.sha1sum' + } + } } diff --git a/build/jenkins/pipelines/freeBSD.Jenkinsfile b/build/jenkins/pipelines/freeBSD.Jenkinsfile index 1384f6f6fb..039462fbc6 100644 --- a/build/jenkins/pipelines/freeBSD.Jenkinsfile +++ b/build/jenkins/pipelines/freeBSD.Jenkinsfile @@ -19,79 +19,81 @@ // Due to a compilation bug with SpiderMonkey, the game is only built with the release configuration. pipeline { - // Stop previous build in pull requests, but not in branches - options { disableConcurrentBuilds(abortPrevious: env.CHANGE_ID != null) } + // Stop previous build in pull requests, but not in branches + options { disableConcurrentBuilds(abortPrevious: env.CHANGE_ID != null) } - parameters { - booleanParam description: 'Non-incremental build', name: 'CLEANBUILD' - } + parameters { + booleanParam description: 'Non-incremental build', name: 'CLEANBUILD' + } - agent { - node { - label 'FreeBSDAgent' - customWorkspace 'workspace/clang17' - } - } - environment { - USE = 'iconv' - WX_CONFIG = '/usr/local/bin/wxgtk3u-3.0-config' - CXXFLAGS = '-stdlib=libc++ ' - LLVM_OBJDUMP = '/usr/bin/llvm-objdump' - } - stages { - stage ("Pre-build") { - steps { - discoverGitReferenceBuild() + agent { + node { + label 'FreeBSDAgent' + customWorkspace 'workspace/clang17' + } + } + environment { + USE = 'iconv' + WX_CONFIG = '/usr/local/bin/wxgtk3u-3.0-config' + CXXFLAGS = '-stdlib=libc++ ' + LLVM_OBJDUMP = '/usr/bin/llvm-objdump' + } + stages { + stage('Pre-build') { + steps { + discoverGitReferenceBuild() - sh "git lfs pull -I binaries/data/tests" - sh "git lfs pull -I \"binaries/data/mods/_test.*\"" + sh 'git lfs pull -I binaries/data/tests' + sh 'git lfs pull -I "binaries/data/mods/_test.*"' - sh "libraries/build-source-libs.sh ${JOBS} 2> freebsd-prebuild-errors.log" - sh "build/workspaces/update-workspaces.sh --jenkins-tests 2>> freebsd-prebuild-errors.log" + sh "libraries/build-source-libs.sh ${JOBS} 2> freebsd-prebuild-errors.log" + sh 'build/workspaces/update-workspaces.sh --jenkins-tests 2>> freebsd-prebuild-errors.log' - script { - if (params.CLEANBUILD) { - sh "cd build/workspaces/gcc/ && gmake clean config=release" - } - } - } - post { - failure { - echo (message: readFile (file: "freebsd-prebuild-errors.log")) - } - } - } + script { + if (params.CLEANBUILD) { + sh 'cd build/workspaces/gcc/ && gmake clean config=release' + } + } + } + post { + failure { + echo(message: readFile(file: 'freebsd-prebuild-errors.log')) + } + } + } - stage ("Release Build") { - steps { - sh "cd build/workspaces/gcc/ && gmake ${JOBS} config=release" - } - post { - failure { - script { if (!params.CLEANBUILD) { - build wait: false, job: "$JOB_NAME", parameters: [booleanParam(name: 'CLEANBUILD', value: true)] - }} - } - } - } + stage('Release Build') { + steps { + sh "cd build/workspaces/gcc/ && gmake ${JOBS} config=release" + } + post { + failure { + script { + if (!params.CLEANBUILD) { + build wait: false, job: "$JOB_NAME", parameters: [booleanParam(name: 'CLEANBUILD', value: true)] + } + } + } + } + } - stage ("Release Tests") { - steps { - timeout(time: 15) { - sh "cd binaries/system/ && ./test > cxxtest-release.xml" - } - } - post { - always { - junit 'binaries/system/cxxtest-release.xml' - } - } - } - } + stage('Release Tests') { + steps { + timeout(time: 15) { + sh 'cd binaries/system/ && ./test > cxxtest-release.xml' + } + } + post { + always { + junit 'binaries/system/cxxtest-release.xml' + } + } + } + } - post { - always { - recordIssues enabledForFailure: true, qualityGates: [[threshold: 1, type: 'NEW']], tool: clang() - } - } + post { + always { + recordIssues enabledForFailure: true, qualityGates: [[threshold: 1, type: 'NEW']], tool: clang() + } + } } diff --git a/build/jenkins/pipelines/linux.Jenkinsfile b/build/jenkins/pipelines/linux.Jenkinsfile index 18389f6d55..c93c8e60a5 100644 --- a/build/jenkins/pipelines/linux.Jenkinsfile +++ b/build/jenkins/pipelines/linux.Jenkinsfile @@ -17,172 +17,174 @@ // This pipeline builds the game on Linux (with minimum supported versions of GCC and clang) and runs tests. -def tc_getCC(tc) { - def map = ['gcc12': 'gcc-12', 'clang14': 'clang-14'] - return map[tc] +def tc_getCC(String tc) { + def map = ['gcc12': 'gcc-12', 'clang14': 'clang-14'] + return map[tc] } -def tc_getCXX(tc) { - def map = ['gcc12': 'g++-12', 'clang14': 'clang++-14'] - return map[tc] +def tc_getCXX(String tc) { + def map = ['gcc12': 'g++-12', 'clang14': 'clang++-14'] + return map[tc] } -def tc_getLDFLAGS(tc) { - def map = ['gcc12': '', 'clang14': '-fuse-ld=lld-14'] - return map[tc] +def tc_getLDFLAGS(String tc) { + def map = ['gcc12': '', 'clang14': '-fuse-ld=lld-14'] + return map[tc] } -def getParserConfig(tc, buildType) { - def config - if (tc.startsWith("gcc")) { - config = [ 'tool': 'gcc', 'name': 'GCC', 'id': 'gcc-' + buildType] - } else { - config = [ 'tool': 'clang', 'name': 'Clang', 'id': 'clang-' + buildType ] - } - if (buildType.matches("debug")) { - config['name'] += ' Debug Build' - } else { - config['name'] += ' Release Build' - } - return config +def getParserConfig(String tc, String buildType) { + def config + if (tc.startsWith('gcc')) { + config = [ 'tool': 'gcc', 'name': 'GCC', 'id': 'gcc-' + buildType] + } else { + config = [ 'tool': 'clang', 'name': 'Clang', 'id': 'clang-' + buildType ] + } + if (buildType.matches('debug')) { + config['name'] += ' Debug Build' + } else { + config['name'] += ' Release Build' + } + return config } pipeline { - // Stop previous build in pull requests, but not in branches - options { disableConcurrentBuilds(abortPrevious: env.CHANGE_ID != null) } + // Stop previous build in pull requests, but not in branches + options { disableConcurrentBuilds(abortPrevious: env.CHANGE_ID != null) } - parameters { - booleanParam description: 'Non-incremental build', name: 'CLEANBUILD' - } + parameters { + booleanParam description: 'Non-incremental build', name: 'CLEANBUILD' + } - agent none + agent none - stages { - stage("Linux Build") { - failFast true + stages { + stage('Linux Build') { + failFast true - matrix { - axes { - axis { - name 'JENKINS_COMPILER' - values 'gcc12', 'clang14' - } - axis { - name 'BUILD_TYPE' - values 'debug', 'release' - } - } + matrix { + axes { + axis { + name 'JENKINS_COMPILER' + values 'gcc12', 'clang14' + } + axis { + name 'BUILD_TYPE' + values 'debug', 'release' + } + } - environment { - CC = tc_getCC(env.JENKINS_COMPILER) - CXX = tc_getCXX(env.JENKINS_COMPILER) - LDFLAGS = tc_getLDFLAGS(env.JENKINS_COMPILER) - } + environment { + CC = tc_getCC(env.JENKINS_COMPILER) + CXX = tc_getCXX(env.JENKINS_COMPILER) + LDFLAGS = tc_getLDFLAGS(env.JENKINS_COMPILER) + } - stages { - stage("Checkout") { - agent { - node { - label "LinuxAgent" - customWorkspace "workspace/${JENKINS_COMPILER}-pch-${BUILD_TYPE}" - } - } + stages { + stage('Checkout') { + agent { + node { + label 'LinuxAgent' + customWorkspace "workspace/${JENKINS_COMPILER}-pch-${BUILD_TYPE}" + } + } - steps { - sh "git lfs fetch -I binaries/data/tests" - sh "git lfs checkout binaries/data/tests" - sh "git lfs fetch -I \"binaries/data/mods/_test.*\"" - sh "git lfs checkout binaries/data/mods/_test.*" - } - } + steps { + sh 'git lfs fetch -I binaries/data/tests' + sh 'git lfs checkout binaries/data/tests' + sh 'git lfs fetch -I "binaries/data/mods/_test.*"' + sh 'git lfs checkout binaries/data/mods/_test.*' + } + } - stage("Container") { - agent { - dockerfile { - label 'LinuxAgent' - customWorkspace "workspace/${JENKINS_COMPILER}-pch-${BUILD_TYPE}" - dir 'build/jenkins/dockerfiles' - filename 'debian-12.Dockerfile' - // Prevent Jenkins from running commands with the UID of the host's jenkins user - // https://stackoverflow.com/a/42822143 - args '-u root' - } - } + stage('Container') { + agent { + dockerfile { + label 'LinuxAgent' + customWorkspace "workspace/${JENKINS_COMPILER}-pch-${BUILD_TYPE}" + dir 'build/jenkins/dockerfiles' + filename 'debian-12.Dockerfile' + // Prevent Jenkins from running commands with the UID of the host's jenkins user + // https://stackoverflow.com/a/42822143 + args '-u root' + } + } - stages { - stage("Pre-build") { - steps { - sh "libraries/build-source-libs.sh ${JOBS} 2> ${JENKINS_COMPILER}-prebuild-errors.log" + stages { + stage('Pre-build') { + steps { + sh "libraries/build-source-libs.sh ${JOBS} 2> ${JENKINS_COMPILER}-prebuild-errors.log" - sh "build/workspaces/update-workspaces.sh --jenkins-tests 2>> ${JENKINS_COMPILER}-prebuild-errors.log" + sh "build/workspaces/update-workspaces.sh --jenkins-tests 2>> ${JENKINS_COMPILER}-prebuild-errors.log" - script { - if (params.CLEANBUILD) { - sh "make -C build/workspaces/gcc/ clean config=${BUILD_TYPE}" - } - } - } - post { - failure { - echo (message: readFile (file: "${JENKINS_COMPILER}-prebuild-errors.log")) - } - } - } + script { + if (params.CLEANBUILD) { + sh "make -C build/workspaces/gcc/ clean config=${BUILD_TYPE}" + } + } + } + post { + failure { + echo(message: readFile(file: "${JENKINS_COMPILER}-prebuild-errors.log")) + } + } + } - stage("Build") { - steps { - sh ''' - rm -f thepipe - mkfifo thepipe - tee build.log < thepipe & - make -C build/workspaces/gcc/ ${JOBS} config=${BUILD_TYPE} > thepipe 2>&1 - status=$? - rm thepipe - exit ${status} - ''' - } - post { - failure { - script { if (!params.CLEANBUILD) { - build wait: false, job: "$JOB_NAME", parameters: [booleanParam(name: 'CLEANBUILD', value: true)] - }} - } - always { - script { - def config = getParserConfig(env.JENKINS_COMPILER, env.BUILD_TYPE) - recordIssues( - tool: analysisParser( - analysisModelId: config['tool'], - name: config['name'], - id : config['id'], - pattern: "build.log" - ), - skipPublishingChecks: true, - enabledForFailure: true, - qualityGates: [[threshold: 1, type: 'TOTAL', criticality: 'FAILURE']] - ) - } - } - } - } + stage('Build') { + steps { + sh ''' + rm -f thepipe + mkfifo thepipe + tee build.log < thepipe & + make -C build/workspaces/gcc/ ${JOBS} config=${BUILD_TYPE} > thepipe 2>&1 + status=$? + rm thepipe + exit ${status} + ''' + } + post { + failure { + script { + if (!params.CLEANBUILD) { + build wait: false, job: "$JOB_NAME", parameters: [booleanParam(name: 'CLEANBUILD', value: true)] + } + } + } + always { + script { + def config = getParserConfig(env.JENKINS_COMPILER, env.BUILD_TYPE) + recordIssues( + tool: analysisParser( + analysisModelId: config['tool'], + name: config['name'], + id : config['id'], + pattern: 'build.log' + ), + skipPublishingChecks: true, + enabledForFailure: true, + qualityGates: [[threshold: 1, type: 'TOTAL', criticality: 'FAILURE']] + ) + } + } + } + } - stage("Test") { - steps { - timeout(time: 15) { - script { - def bin = env.BUILD_TYPE == "debug" ? "test_dbg" : "test" - sh "binaries/system/${bin} > cxxtest.xml" - } - } - } - post { - always { - junit(skipPublishingChecks: true, testResults: 'cxxtest.xml') - } - } - } - } - } - } - } - } - } + stage('Test') { + steps { + timeout(time: 15) { + script { + def bin = env.BUILD_TYPE == 'debug' ? 'test_dbg' : 'test' + sh "binaries/system/${bin} > cxxtest.xml" + } + } + } + post { + always { + junit(skipPublishingChecks: true, testResults: 'cxxtest.xml') + } + } + } + } + } + } + } + } + } } diff --git a/build/jenkins/pipelines/macOS.Jenkinsfile b/build/jenkins/pipelines/macOS.Jenkinsfile index 8c57fd8443..1db70f3a37 100644 --- a/build/jenkins/pipelines/macOS.Jenkinsfile +++ b/build/jenkins/pipelines/macOS.Jenkinsfile @@ -18,94 +18,96 @@ // This pipeline builds the game on macOS (which uses the clang-10 compiler) and runs tests. pipeline { - // Stop previous build in pull requests, but not in branches - options { disableConcurrentBuilds(abortPrevious: env.CHANGE_ID != null) } + // Stop previous build in pull requests, but not in branches + options { disableConcurrentBuilds(abortPrevious: env.CHANGE_ID != null) } - parameters { - booleanParam description: 'Non-incremental build', name: 'CLEANBUILD' - } + parameters { + booleanParam description: 'Non-incremental build', name: 'CLEANBUILD' + } - agent { - node { - label 'macOSAgentVentura' - customWorkspace 'workspace/clang13' - } - } + agent { + node { + label 'macOSAgentVentura' + customWorkspace 'workspace/clang13' + } + } - stages { - stage ("Pre-build") { - steps { - discoverGitReferenceBuild() + stages { + stage('Pre-build') { + steps { + discoverGitReferenceBuild() - sh "git lfs pull -I binaries/data/tests" - sh "git lfs pull -I \"binaries/data/mods/_test.*\"" + sh 'git lfs pull -I binaries/data/tests' + sh 'git lfs pull -I "binaries/data/mods/_test.*"' - sh "libraries/build-macos-libs.sh ${JOBS} 2> macos-prebuild-errors.log" - sh "build/workspaces/update-workspaces.sh --jenkins-tests 2>> macos-prebuild-errors.log" + sh "libraries/build-macos-libs.sh ${JOBS} 2> macos-prebuild-errors.log" + sh 'build/workspaces/update-workspaces.sh --jenkins-tests 2>> macos-prebuild-errors.log' - script { - if (params.CLEANBUILD) { - sh "cd build/workspaces/gcc/ && make clean config=debug" - sh "cd build/workspaces/gcc/ && make clean config=release" - } - } - } - post { - failure { - echo (message: readFile (file: "macos-prebuild-errors.log")) - } - } - } + script { + if (params.CLEANBUILD) { + sh 'cd build/workspaces/gcc/ && make clean config=debug' + sh 'cd build/workspaces/gcc/ && make clean config=release' + } + } + } + post { + failure { + echo(message: readFile(file: 'macos-prebuild-errors.log')) + } + } + } - stage("Debug Build") { - steps { - sh "cd build/workspaces/gcc/ && make ${JOBS} config=debug" - } - post { - failure { - script { if (!params.CLEANBUILD) { - build wait: false, job: "$JOB_NAME", parameters: [booleanParam(name: 'CLEANBUILD', value: true)] - }} - } - } - } + stage('Debug Build') { + steps { + sh "cd build/workspaces/gcc/ && make ${JOBS} config=debug" + } + post { + failure { + script { + if (!params.CLEANBUILD) { + build wait: false, job: "$JOB_NAME", parameters: [booleanParam(name: 'CLEANBUILD', value: true)] + } + } + } + } + } - stage("Debug Tests") { - steps { - timeout(time: 15) { - sh "cd binaries/system/ && ./test_dbg > cxxtest-debug.xml" - } - } - post { - always { - junit 'binaries/system/cxxtest-debug.xml' - } - } - } + stage('Debug Tests') { + steps { + timeout(time: 15) { + sh 'cd binaries/system/ && ./test_dbg > cxxtest-debug.xml' + } + } + post { + always { + junit 'binaries/system/cxxtest-debug.xml' + } + } + } - stage("Release Build") { - steps { - sh "cd build/workspaces/gcc/ && make ${JOBS} config=release" - } - } + stage('Release Build') { + steps { + sh "cd build/workspaces/gcc/ && make ${JOBS} config=release" + } + } - stage("Release Tests") { - steps { - timeout(time: 15) { - sh "cd binaries/system/ && ./test > cxxtest-release.xml" - } - } - post { - always { - junit 'binaries/system/cxxtest-release.xml' - } - } - } - } + stage('Release Tests') { + steps { + timeout(time: 15) { + sh 'cd binaries/system/ && ./test > cxxtest-release.xml' + } + } + post { + always { + junit 'binaries/system/cxxtest-release.xml' + } + } + } + } - post { - always { - recordIssues enabledForFailure: true, qualityGates: [[threshold: 1, type: 'NEW']], tool: clang() - } - } + post { + always { + recordIssues enabledForFailure: true, qualityGates: [[threshold: 1, type: 'NEW']], tool: clang() + } + } } diff --git a/build/jenkins/pipelines/nightly-build.Jenkinsfile b/build/jenkins/pipelines/nightly-build.Jenkinsfile index 2a34c25578..5420a30e2d 100644 --- a/build/jenkins/pipelines/nightly-build.Jenkinsfile +++ b/build/jenkins/pipelines/nightly-build.Jenkinsfile @@ -17,172 +17,175 @@ // This pipeline is used to generate the nightly builds. -def visualStudioPath = "\"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe\"" -def buildOptions = "/p:PlatformToolset=v141_xp /p:XPDeprecationWarning=false /t:pyrogenesis /t:AtlasUI %JOBS% /nologo -clp:Warningsonly -clp:ErrorsOnly" +def visualStudioPath = '"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe"' +def buildOptions = '/p:PlatformToolset=v141_xp /p:XPDeprecationWarning=false /t:pyrogenesis /t:AtlasUI %JOBS% /nologo -clp:Warningsonly -clp:ErrorsOnly' -def gitHash = "" +def gitHash = '' def buildSPIRV = false pipeline { - agent { - node { - label 'WindowsAgent' - customWorkspace 'workspace/nightly-build' - } - } + agent { + node { + label 'WindowsAgent' + customWorkspace 'workspace/nightly-build' + } + } - parameters { - booleanParam(name: 'NEW_REPO', defaultValue: false, description: 'If a brand new nightly repo is being generated, do not attempt to identify unchanged translations.') - stashedFile(name: 'spirv_rules', description: 'rules.json file for generation of SPIR-V shaders. Needed for a new repo, else the existing rules files will be used. Uploading a new rules file will force-rebuild the shaders.') - } + parameters { + booleanParam(name: 'NEW_REPO', defaultValue: false, description: 'If a brand new nightly repo is being generated, do not attempt to identify unchanged translations.') + stashedFile(name: 'spirv_rules', description: 'rules.json file for generation of SPIR-V shaders. Needed for a new repo, else the existing rules files will be used. Uploading a new rules file will force-rebuild the shaders.') + } - stages { - stage("Generate build version") { - steps { - checkout scmGit(branches: [[name: "${GIT_BRANCH}"]], extensions: [cleanAfterCheckout(), localBranch()]) - script { gitHash = bat(script:"@git rev-parse --short HEAD", returnStdout: true ).trim() } - bat "cd build\\build_version && build_version.bat" - } - } + stages { + stage('Generate build version') { + steps { + checkout scmGit(branches: [[name: "${GIT_BRANCH}"]], extensions: [cleanAfterCheckout(), localBranch()]) + script { gitHash = bat(script:'@git rev-parse --short HEAD', returnStdout: true).trim() } + bat 'cd build\\build_version && build_version.bat' + } + } - stage("Pull game assets") { - steps { - bat "git lfs pull" - } - } + stage('Pull game assets') { + steps { + bat 'git lfs pull' + } + } - stage("Check for shader changes") { - when { - anyOf { - changeset 'binaries/data/mods/**/shaders/**/*.xml' - changeset 'source/tools/spirv/compile.py' - } - } - steps { - script { buildSPIRV = true } - } - } + stage('Check for shader changes') { + when { + anyOf { + changeset 'binaries/data/mods/**/shaders/**/*.xml' + changeset 'source/tools/spirv/compile.py' + } + } + steps { + script { buildSPIRV = true } + } + } - stage ("Pre-build") { - steps { - bat "cd libraries && get-windows-libs.bat" - bat "(robocopy E:\\wxWidgets-3.2.6\\lib libraries\\win32\\wxwidgets\\lib /MIR /NDL /NJH /NJS /NP /NS /NC) ^& IF %ERRORLEVEL% LEQ 1 exit 0" - bat "(robocopy E:\\wxWidgets-3.2.6\\include libraries\\win32\\wxwidgets\\include /MIR /NDL /NJH /NJS /NP /NS /NC) ^& IF %ERRORLEVEL% LEQ 1 exit 0" - bat "cd build\\workspaces && update-workspaces.bat --without-pch --without-tests" - } - } + stage('Pre-build') { + steps { + bat 'cd libraries && get-windows-libs.bat' + bat '(robocopy E:\\wxWidgets-3.2.6\\lib libraries\\win32\\wxwidgets\\lib /MIR /NDL /NJH /NJS /NP /NS /NC) ^& IF %ERRORLEVEL% LEQ 1 exit 0' + bat '(robocopy E:\\wxWidgets-3.2.6\\include libraries\\win32\\wxwidgets\\include /MIR /NDL /NJH /NJS /NP /NS /NC) ^& IF %ERRORLEVEL% LEQ 1 exit 0' + bat 'cd build\\workspaces && update-workspaces.bat --without-pch --without-tests' + } + } - stage ("Build") { - steps { - bat("cd build\\workspaces\\vs2017 && ${visualStudioPath} pyrogenesis.sln /p:Configuration=Release ${buildOptions}") - } - } + stage('Build') { + steps { + bat("cd build\\workspaces\\vs2017 && ${visualStudioPath} pyrogenesis.sln /p:Configuration=Release ${buildOptions}") + } + } - stage("Generate entity XML schema") { - steps { - bat "cd binaries\\system && pyrogenesis.exe -mod=public -dumpSchema" - } - } + stage('Generate entity XML schema') { + steps { + bat 'cd binaries\\system && pyrogenesis.exe -mod=public -dumpSchema' + } + } - stage("Mirror to SVN") { - steps { - ws("workspace/nightly-svn") { - bat "svn co https://svn.wildfiregames.com/nightly-build/trunk ." - bat "svn revert -R ." - script { env.NIGHTLY_PATH = env.WORKSPACE } - } - bat """ - (robocopy . %NIGHTLY_PATH% ^ - /XD .git ^ - /XF .gitattributes ^ - /XF .gitignore ^ - /XD %cd%\\binaries\\system ^ - /XD %cd%\\build\\workspaces\\vs2017 ^ - /XD %cd%\\libraries\\source\\.svn ^ - /XD %cd%\\libraries\\win32\\.svn ^ - /XD %cd%\\libraries\\win32\\wxwidgets\\include ^ - /XD %cd%\\libraries\\win32\\wxwidgets\\lib ^ - /XD .svn ^ - /XD %NIGHTLY_PATH%\\binaries\\data\\mods\\mod\\shaders\\spirv ^ - /XD %NIGHTLY_PATH%\\binaries\\data\\mods\\public\\shaders\\spirv ^ - /XF %NIGHTLY_PATH%\\source\\tools\\spirv\\rules.json ^ - /XF %NIGHTLY_PATH%\\binaries\\data\\mods\\public\\gui\\credits\\texts\\translators.json ^ - /MIR /NDL /NJH /NJS /NP /NS /NC) ^& IF %ERRORLEVEL% LEQ 1 exit 0 - """ - bat """ - (robocopy binaries\\system ..\\nightly-svn\\binaries\\system ^ - /XF *.exp ^ - /XF *.lib ^ - /MIR /NDL /NJH /NJS /NP /NS /NC) ^& IF %ERRORLEVEL% LEQ 1 exit 0 - """ - } - } + stage('Mirror to SVN') { + steps { + ws('workspace/nightly-svn') { + bat 'svn co https://svn.wildfiregames.com/nightly-build/trunk .' + bat 'svn revert -R .' + script { env.NIGHTLY_PATH = env.WORKSPACE } + } + bat ''' + (robocopy . %NIGHTLY_PATH% ^ + /XD .git ^ + /XF .gitattributes ^ + /XF .gitignore ^ + /XD %cd%\\binaries\\system ^ + /XD %cd%\\build\\workspaces\\vs2017 ^ + /XD %cd%\\libraries\\source\\.svn ^ + /XD %cd%\\libraries\\win32\\.svn ^ + /XD %cd%\\libraries\\win32\\wxwidgets\\include ^ + /XD %cd%\\libraries\\win32\\wxwidgets\\lib ^ + /XD .svn ^ + /XD %NIGHTLY_PATH%\\binaries\\data\\mods\\mod\\shaders\\spirv ^ + /XD %NIGHTLY_PATH%\\binaries\\data\\mods\\public\\shaders\\spirv ^ + /XF %NIGHTLY_PATH%\\source\\tools\\spirv\\rules.json ^ + /XF %NIGHTLY_PATH%\\binaries\\data\\mods\\public\\gui\\credits\\texts\\translators.json ^ + /MIR /NDL /NJH /NJS /NP /NS /NC) ^& IF %ERRORLEVEL% LEQ 1 exit 0 + ''' + bat ''' + (robocopy binaries\\system ..\\nightly-svn\\binaries\\system ^ + /XF *.exp ^ + /XF *.lib ^ + /MIR /NDL /NJH /NJS /NP /NS /NC) ^& IF %ERRORLEVEL% LEQ 1 exit 0 + ''' + } + } - stage("Check-in SPIR-V rules") { - when { - expression { env.spirv_rules_FILENAME } - } - steps { - ws("workspace/nightly-svn") { - unstash 'spirv_rules' - bat "move spirv_rules source\\tools\\spirv\\rules.json" - } - script { buildSPIRV = true } - } - } + stage('Check-in SPIR-V rules') { + when { + expression { env.spirv_rules_FILENAME } + } + steps { + ws('workspace/nightly-svn') { + unstash 'spirv_rules' + bat 'move spirv_rules source\\tools\\spirv\\rules.json' + } + script { buildSPIRV = true } + } + } - stage("Recompile SPIR-V shaders") { - when { - expression { buildSPIRV } - } - steps { - ws("workspace/nightly-svn") { - bat "del /s /q binaries\\data\\mods\\mod\\shaders\\spirv" - bat "del /s /q binaries\\data\\mods\\public\\shaders\\spirv" - bat "python source/tools/spirv/compile.py -d binaries/data/mods/mod binaries/data/mods/mod source/tools/spirv/rules.json binaries/data/mods/mod" - bat "python source/tools/spirv/compile.py -d binaries/data/mods/mod binaries/data/mods/public source/tools/spirv/rules.json binaries/data/mods/public" - } - } - } + stage('Recompile SPIR-V shaders') { + when { + expression { buildSPIRV } + } + steps { + ws('workspace/nightly-svn') { + bat 'del /s /q binaries\\data\\mods\\mod\\shaders\\spirv' + bat 'del /s /q binaries\\data\\mods\\public\\shaders\\spirv' + bat 'python source/tools/spirv/compile.py -d binaries/data/mods/mod binaries/data/mods/mod source/tools/spirv/rules.json binaries/data/mods/mod' + bat 'python source/tools/spirv/compile.py -d binaries/data/mods/mod binaries/data/mods/public source/tools/spirv/rules.json binaries/data/mods/public' + } + } + } - stage("Update translations") { - steps { - ws("workspace/nightly-svn") { - bat "cd source\\tools\\i18n && python update_templates.py" - withCredentials([string(credentialsId: 'TX_TOKEN', variable: 'TX_TOKEN')]) { - bat "cd source\\tools\\i18n && python pull_translations.py" - } - bat "cd source\\tools\\i18n && python generate_debug_translation.py --long" - bat "cd source\\tools\\i18n && python clean_translation_files.py" - script { if (!params.NEW_REPO) { - bat "python source\\tools\\i18n\\check_diff.py --verbose" - }} - bat "cd source\\tools\\i18n && python credit_translators.py" - } - } - } + stage('Update translations') { + steps { + ws('workspace/nightly-svn') { + bat 'cd source\\tools\\i18n && python update_templates.py' + withCredentials([string(credentialsId: 'TX_TOKEN', variable: 'TX_TOKEN')]) { + bat 'cd source\\tools\\i18n && python pull_translations.py' + } + bat 'cd source\\tools\\i18n && python generate_debug_translation.py --long' + bat 'cd source\\tools\\i18n && python clean_translation_files.py' + script { + if (!params.NEW_REPO) { + bat 'python source\\tools\\i18n\\check_diff.py --verbose' + } + } + bat 'cd source\\tools\\i18n && python credit_translators.py' + } + } + } - stage("Commit") { - steps { - ws("workspace/nightly-svn") { - bat "(for /F \"tokens=* delims=? \" %%A in ('svn status ^| findstr /R \"^?\"') do (svn add \"%%A\")) || (echo No new files found) ^& exit 0" - bat "(for /F \"tokens=* delims=! \" %%A in ('svn status ^| findstr /R \"^!\"') do (svn delete \"%%A\")) || (echo No deleted files found) ^& exit 0" - bat "for /R %%F in (*.sh) do (svn propset svn:executable ON %%F)" - withCredentials([usernamePassword(credentialsId: 'nightly-autobuild', passwordVariable: 'SVNPASS', usernameVariable: 'SVNUSER')]) { - script { env.GITHASH = gitHash - bat 'svn commit --username %SVNUSER% --password %SVNPASS% --no-auth-cache --non-interactive -m "Nightly build for %GITHASH% (%DATE%)"' - } - } - } - } - } - } + stage('Commit') { + steps { + ws('workspace/nightly-svn') { + bat "(for /F \"tokens=* delims=? \" %%A in ('svn status ^| findstr /R \"^?\"') do (svn add \"%%A\")) || (echo No new files found) ^& exit 0" + bat "(for /F \"tokens=* delims=! \" %%A in ('svn status ^| findstr /R \"^!\"') do (svn delete \"%%A\")) || (echo No deleted files found) ^& exit 0" + bat 'for /R %%F in (*.sh) do (svn propset svn:executable ON %%F)' + withCredentials([usernamePassword(credentialsId: 'nightly-autobuild', passwordVariable: 'SVNPASS', usernameVariable: 'SVNUSER')]) { + script { + env.GITHASH = gitHash + bat 'svn commit --username %SVNUSER% --password %SVNPASS% --no-auth-cache --non-interactive -m "Nightly build for %GITHASH% (%DATE%)"' + } + } + } + } + } + } - post { - always { - ws("workspace/nightly-svn") { - bat "svn cleanup" - } - } - } + post { + always { + ws('workspace/nightly-svn') { + bat 'svn cleanup' + } + } + } } diff --git a/build/jenkins/pipelines/static-analysis.Jenkinsfile b/build/jenkins/pipelines/static-analysis.Jenkinsfile index 61b347a3ac..b64ce3a770 100644 --- a/build/jenkins/pipelines/static-analysis.Jenkinsfile +++ b/build/jenkins/pipelines/static-analysis.Jenkinsfile @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2025 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,67 +18,67 @@ // This pipeline is used to build the documentation. pipeline { - agent { - node { - label 'LinuxSlave' - } - } - environment { - INFO_FILE = 'coverage.info' - REPORT_PATH = '../../../coverage-results/' - } - stages { - stage("Setup") { - steps { - sh "sudo zfs clone zpool0/gcc7@latest zpool0/docker-coverage" - } - } - stage("Build") { - steps { - ws("/zpool0/docker-coverage"){ - dir('build/workspaces/'){ - sh "./update-workspaces.sh -j1 --jenkins-tests --coverage" - dir('gcc/'){ - // Reset everything in case there were ever leftovers - sh "lcov --directory . --zerocounters" - sh "make -B -j1 test" - } - } - } - } - } - stage("Generation") { - steps { - ws("/zpool0/docker-coverage"){ - dir('build/workspaces/gcc'){ - // The executable must be launched from the same path - // as where it was built else nothing is generated. - sh "../../../binaries/system/test" - // Capture the symbols. - sh "lcov --directory . --capture --output-file ${INFO_FILE}" - // Remove things we don't need to analyze like external - // libraries or system ones. - sh "lcov --remove ${INFO_FILE} \"*/*/*/tests/*\" \"*/*/*/libraries/*\" \"/usr/*\" --output-file ${INFO_FILE}" - sh "mkdir -p ${REPORT_PATH}" - sh "genhtml --o ${REPORT_PATH} -t \"0 A.D. test coverage report\" --num-spaces 4 --demangle-cpp ${INFO_FILE}" - } - } - } - } - stage("Upload") { - steps { - ws("/zpool0/docker-coverage"){ - sh "rsync -airt --progress coverage-results/* docs.wildfiregames.com:~/www/coverage/" - } - } - } - } - post { - always { - ws("/zpool0/trunk") { - sleep 10 - sh "sudo zfs destroy zpool0/docker-coverage" - } - } - } + agent { + node { + label 'LinuxSlave' + } + } + environment { + INFO_FILE = 'coverage.info' + REPORT_PATH = '../../../coverage-results/' + } + stages { + stage('Setup') { + steps { + sh 'sudo zfs clone zpool0/gcc7@latest zpool0/docker-coverage' + } + } + stage('Build') { + steps { + ws('/zpool0/docker-coverage') { + dir('build/workspaces/') { + sh './update-workspaces.sh -j1 --jenkins-tests --coverage' + dir('gcc/') { + // Reset everything in case there were ever leftovers + sh 'lcov --directory . --zerocounters' + sh 'make -B -j1 test' + } + } + } + } + } + stage('Generation') { + steps { + ws('/zpool0/docker-coverage') { + dir('build/workspaces/gcc') { + // The executable must be launched from the same path + // as where it was built else nothing is generated. + sh '../../../binaries/system/test' + // Capture the symbols. + sh "lcov --directory . --capture --output-file ${INFO_FILE}" + // Remove things we don't need to analyze like external + // libraries or system ones. + sh "lcov --remove ${INFO_FILE} \"*/*/*/tests/*\" \"*/*/*/libraries/*\" \"/usr/*\" --output-file ${INFO_FILE}" + sh "mkdir -p ${REPORT_PATH}" + sh "genhtml --o ${REPORT_PATH} -t \"0 A.D. test coverage report\" --num-spaces 4 --demangle-cpp ${INFO_FILE}" + } + } + } + } + stage('Upload') { + steps { + ws('/zpool0/docker-coverage') { + sh 'rsync -airt --progress coverage-results/* docs.wildfiregames.com:~/www/coverage/' + } + } + } + } + post { + always { + ws('/zpool0/trunk') { + sleep 10 + sh 'sudo zfs destroy zpool0/docker-coverage' + } + } + } } diff --git a/build/jenkins/pipelines/technical-docs.Jenkinsfile b/build/jenkins/pipelines/technical-docs.Jenkinsfile index f319afaaa9..ed10820f88 100644 --- a/build/jenkins/pipelines/technical-docs.Jenkinsfile +++ b/build/jenkins/pipelines/technical-docs.Jenkinsfile @@ -18,56 +18,56 @@ // This pipeline is used to build the documentation. pipeline { - agent { - dockerfile { - label 'LinuxAgent' - customWorkspace 'workspace/technical-docs' - dir 'build/jenkins/dockerfiles' - filename 'docs-tools.Dockerfile' - // Prevent Jenkins from running commands with the UID of the host's jenkins user - // https://stackoverflow.com/a/42822143 - args '-u root' - } - } + agent { + dockerfile { + label 'LinuxAgent' + customWorkspace 'workspace/technical-docs' + dir 'build/jenkins/dockerfiles' + filename 'docs-tools.Dockerfile' + // Prevent Jenkins from running commands with the UID of the host's jenkins user + // https://stackoverflow.com/a/42822143 + args '-u root' + } + } - stages { - stage("Pull documentation assets") { - steps { - sh "git lfs pull -I docs/doxygen" - } - } + stages { + stage('Pull documentation assets') { + steps { + sh 'git lfs pull -I docs/doxygen' + } + } - stage("Engine docs") { - steps { - sh "cd docs/doxygen/ && cmake -S . -B build-docs && cmake --build build-docs" - } - } + stage('Engine docs') { + steps { + sh 'cd docs/doxygen/ && cmake -S . -B build-docs && cmake --build build-docs' + } + } - stage("Entity docs") { - steps { - sh "cd binaries/system/ && svn export --force https://svn.wildfiregames.com/nightly-build/trunk/binaries/system/entity.rng" - sh "cd source/tools/entdocs/ && ./build.sh" - sh "cd source/tools/entdocs/ && mv entity-docs.html nightly.html" - } - } + stage('Entity docs') { + steps { + sh 'cd binaries/system/ && svn export --force https://svn.wildfiregames.com/nightly-build/trunk/binaries/system/entity.rng' + sh 'cd source/tools/entdocs/ && ./build.sh' + sh 'cd source/tools/entdocs/ && mv entity-docs.html nightly.html' + } + } - stage("Template Analyzer") { - steps { - sh "cd source/tools/templatesanalyzer/ && python3 unit_tables.py" - sh "mv source/tools/templatesanalyzer/unit_summary_table.html source/tools/templatesanalyzer/index.html" - } - } + stage('Template Analyzer') { + steps { + sh 'cd source/tools/templatesanalyzer/ && python3 unit_tables.py' + sh 'mv source/tools/templatesanalyzer/unit_summary_table.html source/tools/templatesanalyzer/index.html' + } + } - stage("Upload") { - steps { - sshPublisher alwaysPublishFromMaster: true, failOnError: true, publishers: [ - sshPublisherDesc(configName: 'docs.wildfiregames.com', transfers: [ - sshTransfer(sourceFiles: 'docs/doxygen/output/html/**', removePrefix: 'docs/doxygen/output/html/', remoteDirectory: 'pyrogenesis'), - sshTransfer(sourceFiles: 'source/tools/entdocs/nightly.html', removePrefix: 'source/tools/entdocs', remoteDirectory: 'entity-docs'), - sshTransfer(sourceFiles: 'source/tools/templatesanalyzer/index.html', removePrefix: 'source/tools/templatesanalyzer', remoteDirectory: 'templatesanalyzer'), - ] - )] - } - } - } + stage('Upload') { + steps { + sshPublisher alwaysPublishFromMaster: true, failOnError: true, publishers: [ + sshPublisherDesc(configName: 'docs.wildfiregames.com', transfers: [ + sshTransfer(sourceFiles: 'docs/doxygen/output/html/**', removePrefix: 'docs/doxygen/output/html/', remoteDirectory: 'pyrogenesis'), + sshTransfer(sourceFiles: 'source/tools/entdocs/nightly.html', removePrefix: 'source/tools/entdocs', remoteDirectory: 'entity-docs'), + sshTransfer(sourceFiles: 'source/tools/templatesanalyzer/index.html', removePrefix: 'source/tools/templatesanalyzer', remoteDirectory: 'templatesanalyzer'), + ] + )] + } + } + } } diff --git a/build/jenkins/pipelines/windows.Jenkinsfile b/build/jenkins/pipelines/windows.Jenkinsfile index a7c7f1f9b2..cb89d52e92 100644 --- a/build/jenkins/pipelines/windows.Jenkinsfile +++ b/build/jenkins/pipelines/windows.Jenkinsfile @@ -17,95 +17,97 @@ // This pipeline builds the game on Windows (with the MSVC 15.0 compiler) and runs tests. -def visualStudioPath = "\"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe\"" -def buildOptions = "/p:PlatformToolset=v141_xp /p:XPDeprecationWarning=false /t:pyrogenesis /t:AtlasUI /t:test %JOBS% /nologo -clp:NoSummary" +def visualStudioPath = '"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe"' +def buildOptions = '/p:PlatformToolset=v141_xp /p:XPDeprecationWarning=false /t:pyrogenesis /t:AtlasUI /t:test %JOBS% /nologo -clp:NoSummary' pipeline { - // Stop previous build in pull requests, but not in branches - options { disableConcurrentBuilds(abortPrevious: env.CHANGE_ID != null) } + // Stop previous build in pull requests, but not in branches + options { disableConcurrentBuilds(abortPrevious: env.CHANGE_ID != null) } - parameters { - booleanParam description: 'Non-incremental build', name: 'CLEANBUILD' - } + parameters { + booleanParam description: 'Non-incremental build', name: 'CLEANBUILD' + } - agent { - node { - label 'WindowsAgent' - customWorkspace 'workspace/win32-pch' - } - } + agent { + node { + label 'WindowsAgent' + customWorkspace 'workspace/win32-pch' + } + } - stages { - stage ("Pre-build") { - steps { - discoverGitReferenceBuild() + stages { + stage('Pre-build') { + steps { + discoverGitReferenceBuild() - bat "git lfs pull -I binaries/data/tests" - bat "git lfs pull -I \"binaries/data/mods/_test.*\"" + bat 'git lfs pull -I binaries/data/tests' + bat 'git lfs pull -I "binaries/data/mods/_test.*"' - bat "cd libraries && get-windows-libs.bat" - bat "(robocopy /MIR /NDL /NJH /NJS /NP /NS /NC E:\\wxWidgets-3.2.6\\lib libraries\\win32\\wxwidgets\\lib) ^& IF %ERRORLEVEL% LEQ 1 exit 0" - bat "(robocopy /MIR /NDL /NJH /NJS /NP /NS /NC E:\\wxWidgets-3.2.6\\include libraries\\win32\\wxwidgets\\include) ^& IF %ERRORLEVEL% LEQ 1 exit 0" - bat "cd build\\workspaces && update-workspaces.bat --jenkins-tests" + bat 'cd libraries && get-windows-libs.bat' + bat '(robocopy /MIR /NDL /NJH /NJS /NP /NS /NC E:\\wxWidgets-3.2.6\\lib libraries\\win32\\wxwidgets\\lib) ^& IF %ERRORLEVEL% LEQ 1 exit 0' + bat '(robocopy /MIR /NDL /NJH /NJS /NP /NS /NC E:\\wxWidgets-3.2.6\\include libraries\\win32\\wxwidgets\\include) ^& IF %ERRORLEVEL% LEQ 1 exit 0' + bat 'cd build\\workspaces && update-workspaces.bat --jenkins-tests' - script { - if (params.CLEANBUILD) { - bat "cd build\\workspaces\\vs2017 && ${visualStudioPath} pyrogenesis.sln /p:Configuration=Debug /t:Clean" - bat "cd build\\workspaces\\vs2017 && ${visualStudioPath} pyrogenesis.sln /p:Configuration=Release /t:Clean" - } - } - } - } + script { + if (params.CLEANBUILD) { + bat "cd build\\workspaces\\vs2017 && ${visualStudioPath} pyrogenesis.sln /p:Configuration=Debug /t:Clean" + bat "cd build\\workspaces\\vs2017 && ${visualStudioPath} pyrogenesis.sln /p:Configuration=Release /t:Clean" + } + } + } + } - stage("Debug Build") { - steps { - bat "cd build\\workspaces\\vs2017 && ${visualStudioPath} pyrogenesis.sln /p:Configuration=Debug ${buildOptions}" - } - post { - failure { - script { if (!params.CLEANBUILD) { - build wait: false, job: "$JOB_NAME", parameters: [booleanParam(name: 'CLEANBUILD', value: true)] - }} - } - } - } + stage('Debug Build') { + steps { + bat "cd build\\workspaces\\vs2017 && ${visualStudioPath} pyrogenesis.sln /p:Configuration=Debug ${buildOptions}" + } + post { + failure { + script { + if (!params.CLEANBUILD) { + build wait: false, job: "$JOB_NAME", parameters: [booleanParam(name: 'CLEANBUILD', value: true)] + } + } + } + } + } - stage("Debug Tests") { - steps { - timeout(time: 15) { - bat "cd binaries\\system && test_dbg.exe > cxxtest-debug.xml" - } - } - post { - always { - junit 'binaries/system/cxxtest-debug.xml' - } - } - } + stage('Debug Tests') { + steps { + timeout(time: 15) { + bat 'cd binaries\\system && test_dbg.exe > cxxtest-debug.xml' + } + } + post { + always { + junit 'binaries/system/cxxtest-debug.xml' + } + } + } - stage ("Release Build") { - steps { - bat "cd build\\workspaces\\vs2017 && ${visualStudioPath} pyrogenesis.sln /p:Configuration=Release ${buildOptions}" - } - } + stage('Release Build') { + steps { + bat "cd build\\workspaces\\vs2017 && ${visualStudioPath} pyrogenesis.sln /p:Configuration=Release ${buildOptions}" + } + } - stage ("Release Tests") { - steps { - timeout(time: 5) { - bat "cd binaries\\system && test.exe > cxxtest-release.xml" - } - } - post { - always { - junit 'binaries/system/cxxtest-release.xml' - } - } - } - } + stage('Release Tests') { + steps { + timeout(time: 5) { + bat 'cd binaries\\system && test.exe > cxxtest-release.xml' + } + } + post { + always { + junit 'binaries/system/cxxtest-release.xml' + } + } + } + } - post { - always { - recordIssues enabledForFailure: true, qualityGates: [[threshold: 1, type: 'NEW']], tool: msBuild() - } - } + post { + always { + recordIssues enabledForFailure: true, qualityGates: [[threshold: 1, type: 'NEW']], tool: msBuild() + } + } } diff --git a/source/tools/lint/jenkinsfiles/jenkinsfiles.sh b/source/tools/lint/jenkinsfiles/jenkinsfiles.sh new file mode 100755 index 0000000000..f85ffeae63 --- /dev/null +++ b/source/tools/lint/jenkinsfiles/jenkinsfiles.sh @@ -0,0 +1,43 @@ +#!/bin/sh +set -e + +cd "$(dirname "$0")/../../../.." || exit 1 + +while [ "$#" -gt 0 ]; do + case "$1" in + --from) + from_commitish=$2 + shift + ;; + --to) + to_commitish=$2 + shift + ;; + -j*) ;; + *) + printf "Unknown option: %s\n\n" "$1" + exit 1 + ;; + esac + shift +done + +if [ -n "${from_commitish}" ]; then + if [ -n "${to_commitish}" ]; then + diff="${from_commitish}..${to_commitish}" + else + diff="${from_commitish}..$(git rev-parse HEAD)" + fi + printf "Running npm-groovy-lint linter for range\n%s\n\n" "${diff}" +fi + +if [ -n "${diff}" ]; then + git diff --name-status --no-renames "${diff}" | + awk '!/^D/{if ($2 ~ /(\.Jenkinsfile)$/) {print "./" $2}}' | + xargs -n 1 npm-groovy-lint -r .groovylintrc.json +else + echo "WARNING: running npm-groovy-lint linter without base commit, likely not what you want." + find "build/jenkins/pipelines" \( -name '*.Jenkinsfile' \) >npm-groovy-lint-file-list.txt + xargs -n 1 npm-groovy-lint -r .groovylintrc.json /dev/null; then + # shellcheck disable=SC2086 + ./jenkinsfiles/jenkinsfiles.sh ${args} || has_errors=true +else + echo "npm-groovy-lint not found in path" +fi + if command -v cppcheck >/dev/null; then # shellcheck disable=SC2086 ./cppcheck/cppcheck.sh ${args} || has_errors=true