Add a Jenkinsfile linter

This commit is contained in:
Stan 2025-05-08 18:53:20 +02:00
parent 1adab34511
commit 934ca601d7
No known key found for this signature in database
GPG key ID: 244943DFF8370D60
13 changed files with 850 additions and 751 deletions

View file

@ -27,3 +27,10 @@ indent_size = 2
[build/premake/premake5/**] [build/premake/premake5/**]
ignore = true 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

View file

@ -59,3 +59,19 @@ jobs:
- name: Check for issues with copyright - name: Check for issues with copyright
run: ./source/tools/lint/copyright/copyright.sh --from ${{ env.BASE_SHA }} --to ${{ env.HEAD_SHA }} 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 }}

15
.groovylintrc.json Normal file
View file

@ -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"
}
}

View file

@ -18,133 +18,133 @@
// This pipeline is used to generate bundles (Windows installer, macOS package, and source tarballs). // This pipeline is used to generate bundles (Windows installer, macOS package, and source tarballs).
pipeline { pipeline {
agent { agent {
node { node {
label 'macOSAgentVentura' label 'macOSAgentVentura'
} }
} }
// Archive the installer for public download; keep only the latest one. // Archive the installer for public download; keep only the latest one.
options { options {
buildDiscarder logRotator(artifactNumToKeepStr: '1') buildDiscarder logRotator(artifactNumToKeepStr: '1')
skipDefaultCheckout true skipDefaultCheckout true
} }
parameters { parameters {
string(name: 'BUNDLE_VERSION', defaultValue: '0.28.0dev', description: 'Bundle Version') 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') booleanParam(name: 'DO_GZIP', defaultValue: true, description: 'Create .gz unix tarballs as well as .xz')
} }
environment { environment {
MIN_OSX_VERSION = "10.15" MIN_OSX_VERSION = '10.15'
} }
stages { stages {
stage("Checkout Nightly Build") { stage('Checkout Nightly Build') {
steps { steps {
checkout changelog: false, poll: false, scm: [ checkout changelog: false, poll: false, scm: [
$class: 'SubversionSCM', $class: 'SubversionSCM',
locations: [[local: '.', remote: 'https://svn.wildfiregames.com/nightly-build/trunk']], locations: [[local: '.', remote: 'https://svn.wildfiregames.com/nightly-build/trunk']],
quietOperation: false, quietOperation: false,
workspaceUpdater: [$class: 'UpdateWithCleanUpdater']] workspaceUpdater: [$class: 'UpdateWithCleanUpdater']]
sh "svn cleanup" sh 'svn cleanup'
} }
} }
stage("Compile Native macOS Executable") { stage('Compile Native macOS Executable') {
steps { steps {
sh "cd libraries/ && MIN_OSX_VERSION=${env.MIN_OSX_VERSION} ./build-macos-libs.sh ${JOBS} --force-rebuild" 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/ && ./update-workspaces.sh --macosx-version-min=${env.MIN_OSX_VERSION}"
sh "cd build/workspaces/gcc/ && make ${JOBS}" sh "cd build/workspaces/gcc/ && make ${JOBS}"
sh "svn cleanup --remove-unversioned build" sh 'svn cleanup --remove-unversioned build'
sh "svn cleanup --remove-unversioned libraries" sh 'svn cleanup --remove-unversioned libraries'
} }
} }
stage("Create Mod Archives") { stage('Create Mod Archives') {
steps { steps {
sh "source/tools/dist/build-archives.sh" sh 'source/tools/dist/build-archives.sh'
} }
} }
stage("Create Native macOS Bundle") { stage('Create Native macOS Bundle') {
steps { steps {
withCredentials([ withCredentials([
string(credentialsId: 'apple-keychain', variable: 'KEYCHAIN_PW'), string(credentialsId: 'apple-keychain', variable: 'KEYCHAIN_PW'),
string(credentialsId: 'apple-signing', variable: 'SIGNKEY_SHA'), string(credentialsId: 'apple-signing', variable: 'SIGNKEY_SHA'),
usernamePassword(credentialsId: 'apple-notarization', passwordVariable: 'NOTARIZATION_PW', usernameVariable: 'NOTARIZATION_USER')]) usernamePassword(credentialsId: 'apple-notarization', passwordVariable: 'NOTARIZATION_PW', usernameVariable: 'NOTARIZATION_USER')])
{ {
sh ''' sh '''
security unlock-keychain -p ${KEYCHAIN_PW} login.keychain security unlock-keychain -p ${KEYCHAIN_PW} login.keychain
/opt/wfg/venv/bin/python3 source/tools/dist/build-osx-bundle.py \ /opt/wfg/venv/bin/python3 source/tools/dist/build-osx-bundle.py \
--min_osx=${MIN_OSX_VERSION} \ --min_osx=${MIN_OSX_VERSION} \
-s ${SIGNKEY_SHA} \ -s ${SIGNKEY_SHA} \
--notarytool_user=${NOTARIZATION_USER} \ --notarytool_user=${NOTARIZATION_USER} \
--notarytool_team=P7YF26GARW \ --notarytool_team=P7YF26GARW \
--notarytool_password=${NOTARIZATION_PW} \ --notarytool_password=${NOTARIZATION_PW} \
${BUNDLE_VERSION} ${BUNDLE_VERSION}
''' '''
} }
} }
} }
stage("Compile Intel macOS Executable") { stage('Compile Intel macOS Executable') {
environment { environment {
ARCH = "x86_64" ARCH = 'x86_64'
HOSTTYPE = "x86_64" HOSTTYPE = 'x86_64'
} }
steps { steps {
sh "cd libraries/ && MIN_OSX_VERSION=${env.MIN_OSX_VERSION} ./build-macos-libs.sh ${JOBS} --force-rebuild" 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/ && ./update-workspaces.sh --macosx-version-min=${env.MIN_OSX_VERSION}"
sh "cd build/workspaces/gcc/ && make clean" sh 'cd build/workspaces/gcc/ && make clean'
sh "cd build/workspaces/gcc/ && make ${JOBS}" sh "cd build/workspaces/gcc/ && make ${JOBS}"
sh "svn cleanup --remove-unversioned build" sh 'svn cleanup --remove-unversioned build'
sh "svn cleanup --remove-unversioned libraries" sh 'svn cleanup --remove-unversioned libraries'
} }
} }
stage("Create Intel macOS Bundle") { stage('Create Intel macOS Bundle') {
steps { steps {
withCredentials([ withCredentials([
string(credentialsId: 'apple-keychain', variable: 'KEYCHAIN_PW'), string(credentialsId: 'apple-keychain', variable: 'KEYCHAIN_PW'),
string(credentialsId: 'apple-signing', variable: 'SIGNKEY_SHA'), string(credentialsId: 'apple-signing', variable: 'SIGNKEY_SHA'),
usernamePassword(credentialsId: 'apple-notarization', passwordVariable: 'NOTARIZATION_PW', usernameVariable: 'NOTARIZATION_USER')]) usernamePassword(credentialsId: 'apple-notarization', passwordVariable: 'NOTARIZATION_PW', usernameVariable: 'NOTARIZATION_USER')])
{ {
sh ''' sh '''
security unlock-keychain -p ${KEYCHAIN_PW} login.keychain security unlock-keychain -p ${KEYCHAIN_PW} login.keychain
/opt/wfg/venv/bin/python3 source/tools/dist/build-osx-bundle.py \ /opt/wfg/venv/bin/python3 source/tools/dist/build-osx-bundle.py \
--architecture=x86_64 \ --architecture=x86_64 \
--min_osx=${MIN_OSX_VERSION} \ --min_osx=${MIN_OSX_VERSION} \
-s ${SIGNKEY_SHA} \ -s ${SIGNKEY_SHA} \
--notarytool_user=${NOTARIZATION_USER} \ --notarytool_user=${NOTARIZATION_USER} \
--notarytool_team=P7YF26GARW \ --notarytool_team=P7YF26GARW \
--notarytool_password=${NOTARIZATION_PW} \ --notarytool_password=${NOTARIZATION_PW} \
${BUNDLE_VERSION} ${BUNDLE_VERSION}
''' '''
} }
} }
} }
stage("Create Windows Installer & Tarballs") { stage('Create Windows Installer & Tarballs') {
steps { steps {
sh "BUNDLE_VERSION=${params.BUNDLE_VERSION} DO_GZIP=${params.DO_GZIP} source/tools/dist/build-unix-win32.sh" sh "BUNDLE_VERSION=${params.BUNDLE_VERSION} DO_GZIP=${params.DO_GZIP} source/tools/dist/build-unix-win32.sh"
} }
} }
stage("Generate Signatures and Checksums") { stage('Generate Signatures and Checksums') {
steps { steps {
withCredentials([sshUserPrivateKey(credentialsId: 'minisign-releases-key', keyFileVariable: 'MINISIGN_KEY', passphraseVariable: 'MINISIGN_PASS')]) { 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 '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 md5sum "${file}" > "${file}".md5sum; done'
sh 'for file in *.{dmg,exe,tar.gz,tar.xz}; do sha1sum "${file}" > "${file}".sha1sum; done' sh 'for file in *.{dmg,exe,tar.gz,tar.xz}; do sha1sum "${file}" > "${file}".sha1sum; done'
} }
} }
} }
post { post {
success { success {
archiveArtifacts '*.dmg,*.exe,*.tar.gz,*.tar.xz,*.minisig,*.md5sum,*.sha1sum' archiveArtifacts '*.dmg,*.exe,*.tar.gz,*.tar.xz,*.minisig,*.md5sum,*.sha1sum'
} }
} }
} }

View file

@ -19,79 +19,81 @@
// Due to a compilation bug with SpiderMonkey, the game is only built with the release configuration. // Due to a compilation bug with SpiderMonkey, the game is only built with the release configuration.
pipeline { pipeline {
// Stop previous build in pull requests, but not in branches // Stop previous build in pull requests, but not in branches
options { disableConcurrentBuilds(abortPrevious: env.CHANGE_ID != null) } options { disableConcurrentBuilds(abortPrevious: env.CHANGE_ID != null) }
parameters { parameters {
booleanParam description: 'Non-incremental build', name: 'CLEANBUILD' booleanParam description: 'Non-incremental build', name: 'CLEANBUILD'
} }
agent { agent {
node { node {
label 'FreeBSDAgent' label 'FreeBSDAgent'
customWorkspace 'workspace/clang17' customWorkspace 'workspace/clang17'
} }
} }
environment { environment {
USE = 'iconv' USE = 'iconv'
WX_CONFIG = '/usr/local/bin/wxgtk3u-3.0-config' WX_CONFIG = '/usr/local/bin/wxgtk3u-3.0-config'
CXXFLAGS = '-stdlib=libc++ ' CXXFLAGS = '-stdlib=libc++ '
LLVM_OBJDUMP = '/usr/bin/llvm-objdump' LLVM_OBJDUMP = '/usr/bin/llvm-objdump'
} }
stages { stages {
stage ("Pre-build") { stage('Pre-build') {
steps { steps {
discoverGitReferenceBuild() discoverGitReferenceBuild()
sh "git lfs pull -I binaries/data/tests" sh 'git lfs pull -I binaries/data/tests'
sh "git lfs pull -I \"binaries/data/mods/_test.*\"" sh 'git lfs pull -I "binaries/data/mods/_test.*"'
sh "libraries/build-source-libs.sh ${JOBS} 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" sh 'build/workspaces/update-workspaces.sh --jenkins-tests 2>> freebsd-prebuild-errors.log'
script { script {
if (params.CLEANBUILD) { if (params.CLEANBUILD) {
sh "cd build/workspaces/gcc/ && gmake clean config=release" sh 'cd build/workspaces/gcc/ && gmake clean config=release'
} }
} }
} }
post { post {
failure { failure {
echo (message: readFile (file: "freebsd-prebuild-errors.log")) echo(message: readFile(file: 'freebsd-prebuild-errors.log'))
} }
} }
} }
stage ("Release Build") { stage('Release Build') {
steps { steps {
sh "cd build/workspaces/gcc/ && gmake ${JOBS} config=release" sh "cd build/workspaces/gcc/ && gmake ${JOBS} config=release"
} }
post { post {
failure { failure {
script { if (!params.CLEANBUILD) { script {
build wait: false, job: "$JOB_NAME", parameters: [booleanParam(name: 'CLEANBUILD', value: true)] if (!params.CLEANBUILD) {
}} build wait: false, job: "$JOB_NAME", parameters: [booleanParam(name: 'CLEANBUILD', value: true)]
} }
} }
} }
}
}
stage ("Release Tests") { stage('Release Tests') {
steps { steps {
timeout(time: 15) { timeout(time: 15) {
sh "cd binaries/system/ && ./test > cxxtest-release.xml" sh 'cd binaries/system/ && ./test > cxxtest-release.xml'
} }
} }
post { post {
always { always {
junit 'binaries/system/cxxtest-release.xml' junit 'binaries/system/cxxtest-release.xml'
} }
} }
} }
} }
post { post {
always { always {
recordIssues enabledForFailure: true, qualityGates: [[threshold: 1, type: 'NEW']], tool: clang() recordIssues enabledForFailure: true, qualityGates: [[threshold: 1, type: 'NEW']], tool: clang()
} }
} }
} }

View file

@ -17,172 +17,174 @@
// This pipeline builds the game on Linux (with minimum supported versions of GCC and clang) and runs tests. // This pipeline builds the game on Linux (with minimum supported versions of GCC and clang) and runs tests.
def tc_getCC(tc) { def tc_getCC(String tc) {
def map = ['gcc12': 'gcc-12', 'clang14': 'clang-14'] def map = ['gcc12': 'gcc-12', 'clang14': 'clang-14']
return map[tc] return map[tc]
} }
def tc_getCXX(tc) { def tc_getCXX(String tc) {
def map = ['gcc12': 'g++-12', 'clang14': 'clang++-14'] def map = ['gcc12': 'g++-12', 'clang14': 'clang++-14']
return map[tc] return map[tc]
} }
def tc_getLDFLAGS(tc) { def tc_getLDFLAGS(String tc) {
def map = ['gcc12': '', 'clang14': '-fuse-ld=lld-14'] def map = ['gcc12': '', 'clang14': '-fuse-ld=lld-14']
return map[tc] return map[tc]
} }
def getParserConfig(tc, buildType) { def getParserConfig(String tc, String buildType) {
def config def config
if (tc.startsWith("gcc")) { if (tc.startsWith('gcc')) {
config = [ 'tool': 'gcc', 'name': 'GCC', 'id': 'gcc-' + buildType] config = [ 'tool': 'gcc', 'name': 'GCC', 'id': 'gcc-' + buildType]
} else { } else {
config = [ 'tool': 'clang', 'name': 'Clang', 'id': 'clang-' + buildType ] config = [ 'tool': 'clang', 'name': 'Clang', 'id': 'clang-' + buildType ]
} }
if (buildType.matches("debug")) { if (buildType.matches('debug')) {
config['name'] += ' Debug Build' config['name'] += ' Debug Build'
} else { } else {
config['name'] += ' Release Build' config['name'] += ' Release Build'
} }
return config return config
} }
pipeline { pipeline {
// Stop previous build in pull requests, but not in branches // Stop previous build in pull requests, but not in branches
options { disableConcurrentBuilds(abortPrevious: env.CHANGE_ID != null) } options { disableConcurrentBuilds(abortPrevious: env.CHANGE_ID != null) }
parameters { parameters {
booleanParam description: 'Non-incremental build', name: 'CLEANBUILD' booleanParam description: 'Non-incremental build', name: 'CLEANBUILD'
} }
agent none agent none
stages { stages {
stage("Linux Build") { stage('Linux Build') {
failFast true failFast true
matrix { matrix {
axes { axes {
axis { axis {
name 'JENKINS_COMPILER' name 'JENKINS_COMPILER'
values 'gcc12', 'clang14' values 'gcc12', 'clang14'
} }
axis { axis {
name 'BUILD_TYPE' name 'BUILD_TYPE'
values 'debug', 'release' values 'debug', 'release'
} }
} }
environment { environment {
CC = tc_getCC(env.JENKINS_COMPILER) CC = tc_getCC(env.JENKINS_COMPILER)
CXX = tc_getCXX(env.JENKINS_COMPILER) CXX = tc_getCXX(env.JENKINS_COMPILER)
LDFLAGS = tc_getLDFLAGS(env.JENKINS_COMPILER) LDFLAGS = tc_getLDFLAGS(env.JENKINS_COMPILER)
} }
stages { stages {
stage("Checkout") { stage('Checkout') {
agent { agent {
node { node {
label "LinuxAgent" label 'LinuxAgent'
customWorkspace "workspace/${JENKINS_COMPILER}-pch-${BUILD_TYPE}" customWorkspace "workspace/${JENKINS_COMPILER}-pch-${BUILD_TYPE}"
} }
} }
steps { steps {
sh "git lfs fetch -I binaries/data/tests" sh 'git lfs fetch -I binaries/data/tests'
sh "git lfs checkout binaries/data/tests" sh 'git lfs checkout binaries/data/tests'
sh "git lfs fetch -I \"binaries/data/mods/_test.*\"" sh 'git lfs fetch -I "binaries/data/mods/_test.*"'
sh "git lfs checkout binaries/data/mods/_test.*" sh 'git lfs checkout binaries/data/mods/_test.*'
} }
} }
stage("Container") { stage('Container') {
agent { agent {
dockerfile { dockerfile {
label 'LinuxAgent' label 'LinuxAgent'
customWorkspace "workspace/${JENKINS_COMPILER}-pch-${BUILD_TYPE}" customWorkspace "workspace/${JENKINS_COMPILER}-pch-${BUILD_TYPE}"
dir 'build/jenkins/dockerfiles' dir 'build/jenkins/dockerfiles'
filename 'debian-12.Dockerfile' filename 'debian-12.Dockerfile'
// Prevent Jenkins from running commands with the UID of the host's jenkins user // Prevent Jenkins from running commands with the UID of the host's jenkins user
// https://stackoverflow.com/a/42822143 // https://stackoverflow.com/a/42822143
args '-u root' args '-u root'
} }
} }
stages { stages {
stage("Pre-build") { stage('Pre-build') {
steps { steps {
sh "libraries/build-source-libs.sh ${JOBS} 2> ${JENKINS_COMPILER}-prebuild-errors.log" 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 { script {
if (params.CLEANBUILD) { if (params.CLEANBUILD) {
sh "make -C build/workspaces/gcc/ clean config=${BUILD_TYPE}" sh "make -C build/workspaces/gcc/ clean config=${BUILD_TYPE}"
} }
} }
} }
post { post {
failure { failure {
echo (message: readFile (file: "${JENKINS_COMPILER}-prebuild-errors.log")) echo(message: readFile(file: "${JENKINS_COMPILER}-prebuild-errors.log"))
} }
} }
} }
stage("Build") { stage('Build') {
steps { steps {
sh ''' sh '''
rm -f thepipe rm -f thepipe
mkfifo thepipe mkfifo thepipe
tee build.log < thepipe & tee build.log < thepipe &
make -C build/workspaces/gcc/ ${JOBS} config=${BUILD_TYPE} > thepipe 2>&1 make -C build/workspaces/gcc/ ${JOBS} config=${BUILD_TYPE} > thepipe 2>&1
status=$? status=$?
rm thepipe rm thepipe
exit ${status} exit ${status}
''' '''
} }
post { post {
failure { failure {
script { if (!params.CLEANBUILD) { script {
build wait: false, job: "$JOB_NAME", parameters: [booleanParam(name: 'CLEANBUILD', value: true)] 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) always {
recordIssues( script {
tool: analysisParser( def config = getParserConfig(env.JENKINS_COMPILER, env.BUILD_TYPE)
analysisModelId: config['tool'], recordIssues(
name: config['name'], tool: analysisParser(
id : config['id'], analysisModelId: config['tool'],
pattern: "build.log" name: config['name'],
), id : config['id'],
skipPublishingChecks: true, pattern: 'build.log'
enabledForFailure: true, ),
qualityGates: [[threshold: 1, type: 'TOTAL', criticality: 'FAILURE']] skipPublishingChecks: true,
) enabledForFailure: true,
} qualityGates: [[threshold: 1, type: 'TOTAL', criticality: 'FAILURE']]
} )
} }
} }
}
}
stage("Test") { stage('Test') {
steps { steps {
timeout(time: 15) { timeout(time: 15) {
script { script {
def bin = env.BUILD_TYPE == "debug" ? "test_dbg" : "test" def bin = env.BUILD_TYPE == 'debug' ? 'test_dbg' : 'test'
sh "binaries/system/${bin} > cxxtest.xml" sh "binaries/system/${bin} > cxxtest.xml"
} }
} }
} }
post { post {
always { always {
junit(skipPublishingChecks: true, testResults: 'cxxtest.xml') junit(skipPublishingChecks: true, testResults: 'cxxtest.xml')
} }
} }
} }
} }
} }
} }
} }
} }
} }
} }

View file

@ -18,94 +18,96 @@
// This pipeline builds the game on macOS (which uses the clang-10 compiler) and runs tests. // This pipeline builds the game on macOS (which uses the clang-10 compiler) and runs tests.
pipeline { pipeline {
// Stop previous build in pull requests, but not in branches // Stop previous build in pull requests, but not in branches
options { disableConcurrentBuilds(abortPrevious: env.CHANGE_ID != null) } options { disableConcurrentBuilds(abortPrevious: env.CHANGE_ID != null) }
parameters { parameters {
booleanParam description: 'Non-incremental build', name: 'CLEANBUILD' booleanParam description: 'Non-incremental build', name: 'CLEANBUILD'
} }
agent { agent {
node { node {
label 'macOSAgentVentura' label 'macOSAgentVentura'
customWorkspace 'workspace/clang13' customWorkspace 'workspace/clang13'
} }
} }
stages { stages {
stage ("Pre-build") { stage('Pre-build') {
steps { steps {
discoverGitReferenceBuild() discoverGitReferenceBuild()
sh "git lfs pull -I binaries/data/tests" sh 'git lfs pull -I binaries/data/tests'
sh "git lfs pull -I \"binaries/data/mods/_test.*\"" sh 'git lfs pull -I "binaries/data/mods/_test.*"'
sh "libraries/build-macos-libs.sh ${JOBS} 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" sh 'build/workspaces/update-workspaces.sh --jenkins-tests 2>> macos-prebuild-errors.log'
script { script {
if (params.CLEANBUILD) { if (params.CLEANBUILD) {
sh "cd build/workspaces/gcc/ && make clean config=debug" sh 'cd build/workspaces/gcc/ && make clean config=debug'
sh "cd build/workspaces/gcc/ && make clean config=release" sh 'cd build/workspaces/gcc/ && make clean config=release'
} }
} }
} }
post { post {
failure { failure {
echo (message: readFile (file: "macos-prebuild-errors.log")) echo(message: readFile(file: 'macos-prebuild-errors.log'))
} }
} }
} }
stage("Debug Build") { stage('Debug Build') {
steps { steps {
sh "cd build/workspaces/gcc/ && make ${JOBS} config=debug" sh "cd build/workspaces/gcc/ && make ${JOBS} config=debug"
} }
post { post {
failure { failure {
script { if (!params.CLEANBUILD) { script {
build wait: false, job: "$JOB_NAME", parameters: [booleanParam(name: 'CLEANBUILD', value: true)] if (!params.CLEANBUILD) {
}} build wait: false, job: "$JOB_NAME", parameters: [booleanParam(name: 'CLEANBUILD', value: true)]
} }
} }
} }
}
}
stage("Debug Tests") { stage('Debug Tests') {
steps { steps {
timeout(time: 15) { timeout(time: 15) {
sh "cd binaries/system/ && ./test_dbg > cxxtest-debug.xml" sh 'cd binaries/system/ && ./test_dbg > cxxtest-debug.xml'
} }
} }
post { post {
always { always {
junit 'binaries/system/cxxtest-debug.xml' junit 'binaries/system/cxxtest-debug.xml'
} }
} }
} }
stage("Release Build") { stage('Release Build') {
steps { steps {
sh "cd build/workspaces/gcc/ && make ${JOBS} config=release" sh "cd build/workspaces/gcc/ && make ${JOBS} config=release"
} }
} }
stage("Release Tests") { stage('Release Tests') {
steps { steps {
timeout(time: 15) { timeout(time: 15) {
sh "cd binaries/system/ && ./test > cxxtest-release.xml" sh 'cd binaries/system/ && ./test > cxxtest-release.xml'
} }
} }
post { post {
always { always {
junit 'binaries/system/cxxtest-release.xml' junit 'binaries/system/cxxtest-release.xml'
} }
} }
} }
} }
post { post {
always { always {
recordIssues enabledForFailure: true, qualityGates: [[threshold: 1, type: 'NEW']], tool: clang() recordIssues enabledForFailure: true, qualityGates: [[threshold: 1, type: 'NEW']], tool: clang()
} }
} }
} }

View file

@ -17,172 +17,175 @@
// This pipeline is used to generate the nightly builds. // 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 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 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 def buildSPIRV = false
pipeline { pipeline {
agent { agent {
node { node {
label 'WindowsAgent' label 'WindowsAgent'
customWorkspace 'workspace/nightly-build' customWorkspace 'workspace/nightly-build'
} }
} }
parameters { parameters {
booleanParam(name: 'NEW_REPO', defaultValue: false, description: 'If a brand new nightly repo is being generated, do not attempt to identify unchanged translations.') 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.') 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 { stages {
stage("Generate build version") { stage('Generate build version') {
steps { steps {
checkout scmGit(branches: [[name: "${GIT_BRANCH}"]], extensions: [cleanAfterCheckout(), localBranch()]) checkout scmGit(branches: [[name: "${GIT_BRANCH}"]], extensions: [cleanAfterCheckout(), localBranch()])
script { gitHash = bat(script:"@git rev-parse --short HEAD", returnStdout: true ).trim() } script { gitHash = bat(script:'@git rev-parse --short HEAD', returnStdout: true).trim() }
bat "cd build\\build_version && build_version.bat" bat 'cd build\\build_version && build_version.bat'
} }
} }
stage("Pull game assets") { stage('Pull game assets') {
steps { steps {
bat "git lfs pull" bat 'git lfs pull'
} }
} }
stage("Check for shader changes") { stage('Check for shader changes') {
when { when {
anyOf { anyOf {
changeset 'binaries/data/mods/**/shaders/**/*.xml' changeset 'binaries/data/mods/**/shaders/**/*.xml'
changeset 'source/tools/spirv/compile.py' changeset 'source/tools/spirv/compile.py'
} }
} }
steps { steps {
script { buildSPIRV = true } script { buildSPIRV = true }
} }
} }
stage ("Pre-build") { stage('Pre-build') {
steps { steps {
bat "cd libraries && get-windows-libs.bat" 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\\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 '(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" bat 'cd build\\workspaces && update-workspaces.bat --without-pch --without-tests'
} }
} }
stage ("Build") { stage('Build') {
steps { steps {
bat("cd build\\workspaces\\vs2017 && ${visualStudioPath} pyrogenesis.sln /p:Configuration=Release ${buildOptions}") bat("cd build\\workspaces\\vs2017 && ${visualStudioPath} pyrogenesis.sln /p:Configuration=Release ${buildOptions}")
} }
} }
stage("Generate entity XML schema") { stage('Generate entity XML schema') {
steps { steps {
bat "cd binaries\\system && pyrogenesis.exe -mod=public -dumpSchema" bat 'cd binaries\\system && pyrogenesis.exe -mod=public -dumpSchema'
} }
} }
stage("Mirror to SVN") { stage('Mirror to SVN') {
steps { steps {
ws("workspace/nightly-svn") { ws('workspace/nightly-svn') {
bat "svn co https://svn.wildfiregames.com/nightly-build/trunk ." bat 'svn co https://svn.wildfiregames.com/nightly-build/trunk .'
bat "svn revert -R ." bat 'svn revert -R .'
script { env.NIGHTLY_PATH = env.WORKSPACE } script { env.NIGHTLY_PATH = env.WORKSPACE }
} }
bat """ bat '''
(robocopy . %NIGHTLY_PATH% ^ (robocopy . %NIGHTLY_PATH% ^
/XD .git ^ /XD .git ^
/XF .gitattributes ^ /XF .gitattributes ^
/XF .gitignore ^ /XF .gitignore ^
/XD %cd%\\binaries\\system ^ /XD %cd%\\binaries\\system ^
/XD %cd%\\build\\workspaces\\vs2017 ^ /XD %cd%\\build\\workspaces\\vs2017 ^
/XD %cd%\\libraries\\source\\.svn ^ /XD %cd%\\libraries\\source\\.svn ^
/XD %cd%\\libraries\\win32\\.svn ^ /XD %cd%\\libraries\\win32\\.svn ^
/XD %cd%\\libraries\\win32\\wxwidgets\\include ^ /XD %cd%\\libraries\\win32\\wxwidgets\\include ^
/XD %cd%\\libraries\\win32\\wxwidgets\\lib ^ /XD %cd%\\libraries\\win32\\wxwidgets\\lib ^
/XD .svn ^ /XD .svn ^
/XD %NIGHTLY_PATH%\\binaries\\data\\mods\\mod\\shaders\\spirv ^ /XD %NIGHTLY_PATH%\\binaries\\data\\mods\\mod\\shaders\\spirv ^
/XD %NIGHTLY_PATH%\\binaries\\data\\mods\\public\\shaders\\spirv ^ /XD %NIGHTLY_PATH%\\binaries\\data\\mods\\public\\shaders\\spirv ^
/XF %NIGHTLY_PATH%\\source\\tools\\spirv\\rules.json ^ /XF %NIGHTLY_PATH%\\source\\tools\\spirv\\rules.json ^
/XF %NIGHTLY_PATH%\\binaries\\data\\mods\\public\\gui\\credits\\texts\\translators.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 /MIR /NDL /NJH /NJS /NP /NS /NC) ^& IF %ERRORLEVEL% LEQ 1 exit 0
""" '''
bat """ bat '''
(robocopy binaries\\system ..\\nightly-svn\\binaries\\system ^ (robocopy binaries\\system ..\\nightly-svn\\binaries\\system ^
/XF *.exp ^ /XF *.exp ^
/XF *.lib ^ /XF *.lib ^
/MIR /NDL /NJH /NJS /NP /NS /NC) ^& IF %ERRORLEVEL% LEQ 1 exit 0 /MIR /NDL /NJH /NJS /NP /NS /NC) ^& IF %ERRORLEVEL% LEQ 1 exit 0
""" '''
} }
} }
stage("Check-in SPIR-V rules") { stage('Check-in SPIR-V rules') {
when { when {
expression { env.spirv_rules_FILENAME } expression { env.spirv_rules_FILENAME }
} }
steps { steps {
ws("workspace/nightly-svn") { ws('workspace/nightly-svn') {
unstash 'spirv_rules' unstash 'spirv_rules'
bat "move spirv_rules source\\tools\\spirv\\rules.json" bat 'move spirv_rules source\\tools\\spirv\\rules.json'
} }
script { buildSPIRV = true } script { buildSPIRV = true }
} }
} }
stage("Recompile SPIR-V shaders") { stage('Recompile SPIR-V shaders') {
when { when {
expression { buildSPIRV } expression { buildSPIRV }
} }
steps { steps {
ws("workspace/nightly-svn") { ws('workspace/nightly-svn') {
bat "del /s /q binaries\\data\\mods\\mod\\shaders\\spirv" bat 'del /s /q binaries\\data\\mods\\mod\\shaders\\spirv'
bat "del /s /q binaries\\data\\mods\\public\\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/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" 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") { stage('Update translations') {
steps { steps {
ws("workspace/nightly-svn") { ws('workspace/nightly-svn') {
bat "cd source\\tools\\i18n && python update_templates.py" bat 'cd source\\tools\\i18n && python update_templates.py'
withCredentials([string(credentialsId: 'TX_TOKEN', variable: 'TX_TOKEN')]) { withCredentials([string(credentialsId: 'TX_TOKEN', variable: 'TX_TOKEN')]) {
bat "cd source\\tools\\i18n && python pull_translations.py" 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 generate_debug_translation.py --long'
bat "cd source\\tools\\i18n && python clean_translation_files.py" bat 'cd source\\tools\\i18n && python clean_translation_files.py'
script { if (!params.NEW_REPO) { script {
bat "python source\\tools\\i18n\\check_diff.py --verbose" if (!params.NEW_REPO) {
}} bat 'python source\\tools\\i18n\\check_diff.py --verbose'
bat "cd source\\tools\\i18n && python credit_translators.py" }
} }
} bat 'cd source\\tools\\i18n && python credit_translators.py'
} }
}
}
stage("Commit") { stage('Commit') {
steps { steps {
ws("workspace/nightly-svn") { 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 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 /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)" bat 'for /R %%F in (*.sh) do (svn propset svn:executable ON %%F)'
withCredentials([usernamePassword(credentialsId: 'nightly-autobuild', passwordVariable: 'SVNPASS', usernameVariable: 'SVNUSER')]) { withCredentials([usernamePassword(credentialsId: 'nightly-autobuild', passwordVariable: 'SVNPASS', usernameVariable: 'SVNUSER')]) {
script { env.GITHASH = gitHash script {
bat 'svn commit --username %SVNUSER% --password %SVNPASS% --no-auth-cache --non-interactive -m "Nightly build for %GITHASH% (%DATE%)"' env.GITHASH = gitHash
} bat 'svn commit --username %SVNUSER% --password %SVNPASS% --no-auth-cache --non-interactive -m "Nightly build for %GITHASH% (%DATE%)"'
} }
} }
} }
} }
} }
}
post { post {
always { always {
ws("workspace/nightly-svn") { ws('workspace/nightly-svn') {
bat "svn cleanup" bat 'svn cleanup'
} }
} }
} }
} }

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games. /* Copyright (C) 2025 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 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. // This pipeline is used to build the documentation.
pipeline { pipeline {
agent { agent {
node { node {
label 'LinuxSlave' label 'LinuxSlave'
} }
} }
environment { environment {
INFO_FILE = 'coverage.info' INFO_FILE = 'coverage.info'
REPORT_PATH = '../../../coverage-results/' REPORT_PATH = '../../../coverage-results/'
} }
stages { stages {
stage("Setup") { stage('Setup') {
steps { steps {
sh "sudo zfs clone zpool0/gcc7@latest zpool0/docker-coverage" sh 'sudo zfs clone zpool0/gcc7@latest zpool0/docker-coverage'
} }
} }
stage("Build") { stage('Build') {
steps { steps {
ws("/zpool0/docker-coverage"){ ws('/zpool0/docker-coverage') {
dir('build/workspaces/'){ dir('build/workspaces/') {
sh "./update-workspaces.sh -j1 --jenkins-tests --coverage" sh './update-workspaces.sh -j1 --jenkins-tests --coverage'
dir('gcc/'){ dir('gcc/') {
// Reset everything in case there were ever leftovers // Reset everything in case there were ever leftovers
sh "lcov --directory . --zerocounters" sh 'lcov --directory . --zerocounters'
sh "make -B -j1 test" sh 'make -B -j1 test'
} }
} }
} }
} }
} }
stage("Generation") { stage('Generation') {
steps { steps {
ws("/zpool0/docker-coverage"){ ws('/zpool0/docker-coverage') {
dir('build/workspaces/gcc'){ dir('build/workspaces/gcc') {
// The executable must be launched from the same path // The executable must be launched from the same path
// as where it was built else nothing is generated. // as where it was built else nothing is generated.
sh "../../../binaries/system/test" sh '../../../binaries/system/test'
// Capture the symbols. // Capture the symbols.
sh "lcov --directory . --capture --output-file ${INFO_FILE}" sh "lcov --directory . --capture --output-file ${INFO_FILE}"
// Remove things we don't need to analyze like external // Remove things we don't need to analyze like external
// libraries or system ones. // libraries or system ones.
sh "lcov --remove ${INFO_FILE} \"*/*/*/tests/*\" \"*/*/*/libraries/*\" \"/usr/*\" --output-file ${INFO_FILE}" sh "lcov --remove ${INFO_FILE} \"*/*/*/tests/*\" \"*/*/*/libraries/*\" \"/usr/*\" --output-file ${INFO_FILE}"
sh "mkdir -p ${REPORT_PATH}" sh "mkdir -p ${REPORT_PATH}"
sh "genhtml --o ${REPORT_PATH} -t \"0 A.D. test coverage report\" --num-spaces 4 --demangle-cpp ${INFO_FILE}" sh "genhtml --o ${REPORT_PATH} -t \"0 A.D. test coverage report\" --num-spaces 4 --demangle-cpp ${INFO_FILE}"
} }
} }
} }
} }
stage("Upload") { stage('Upload') {
steps { steps {
ws("/zpool0/docker-coverage"){ ws('/zpool0/docker-coverage') {
sh "rsync -airt --progress coverage-results/* docs.wildfiregames.com:~/www/coverage/" sh 'rsync -airt --progress coverage-results/* docs.wildfiregames.com:~/www/coverage/'
} }
} }
} }
} }
post { post {
always { always {
ws("/zpool0/trunk") { ws('/zpool0/trunk') {
sleep 10 sleep 10
sh "sudo zfs destroy zpool0/docker-coverage" sh 'sudo zfs destroy zpool0/docker-coverage'
} }
} }
} }
} }

View file

@ -18,56 +18,56 @@
// This pipeline is used to build the documentation. // This pipeline is used to build the documentation.
pipeline { pipeline {
agent { agent {
dockerfile { dockerfile {
label 'LinuxAgent' label 'LinuxAgent'
customWorkspace 'workspace/technical-docs' customWorkspace 'workspace/technical-docs'
dir 'build/jenkins/dockerfiles' dir 'build/jenkins/dockerfiles'
filename 'docs-tools.Dockerfile' filename 'docs-tools.Dockerfile'
// Prevent Jenkins from running commands with the UID of the host's jenkins user // Prevent Jenkins from running commands with the UID of the host's jenkins user
// https://stackoverflow.com/a/42822143 // https://stackoverflow.com/a/42822143
args '-u root' args '-u root'
} }
} }
stages { stages {
stage("Pull documentation assets") { stage('Pull documentation assets') {
steps { steps {
sh "git lfs pull -I docs/doxygen" sh 'git lfs pull -I docs/doxygen'
} }
} }
stage("Engine docs") { stage('Engine docs') {
steps { steps {
sh "cd docs/doxygen/ && cmake -S . -B build-docs && cmake --build build-docs" sh 'cd docs/doxygen/ && cmake -S . -B build-docs && cmake --build build-docs'
} }
} }
stage("Entity docs") { stage('Entity docs') {
steps { steps {
sh "cd binaries/system/ && svn export --force https://svn.wildfiregames.com/nightly-build/trunk/binaries/system/entity.rng" 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/ && ./build.sh'
sh "cd source/tools/entdocs/ && mv entity-docs.html nightly.html" sh 'cd source/tools/entdocs/ && mv entity-docs.html nightly.html'
} }
} }
stage("Template Analyzer") { stage('Template Analyzer') {
steps { steps {
sh "cd source/tools/templatesanalyzer/ && python3 unit_tables.py" sh 'cd source/tools/templatesanalyzer/ && python3 unit_tables.py'
sh "mv source/tools/templatesanalyzer/unit_summary_table.html source/tools/templatesanalyzer/index.html" sh 'mv source/tools/templatesanalyzer/unit_summary_table.html source/tools/templatesanalyzer/index.html'
} }
} }
stage("Upload") { stage('Upload') {
steps { steps {
sshPublisher alwaysPublishFromMaster: true, failOnError: true, publishers: [ sshPublisher alwaysPublishFromMaster: true, failOnError: true, publishers: [
sshPublisherDesc(configName: 'docs.wildfiregames.com', transfers: [ sshPublisherDesc(configName: 'docs.wildfiregames.com', transfers: [
sshTransfer(sourceFiles: 'docs/doxygen/output/html/**', removePrefix: 'docs/doxygen/output/html/', remoteDirectory: 'pyrogenesis'), 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/entdocs/nightly.html', removePrefix: 'source/tools/entdocs', remoteDirectory: 'entity-docs'),
sshTransfer(sourceFiles: 'source/tools/templatesanalyzer/index.html', removePrefix: 'source/tools/templatesanalyzer', remoteDirectory: 'templatesanalyzer'), sshTransfer(sourceFiles: 'source/tools/templatesanalyzer/index.html', removePrefix: 'source/tools/templatesanalyzer', remoteDirectory: 'templatesanalyzer'),
] ]
)] )]
} }
} }
} }
} }

View file

@ -17,95 +17,97 @@
// This pipeline builds the game on Windows (with the MSVC 15.0 compiler) and runs tests. // 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 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 buildOptions = '/p:PlatformToolset=v141_xp /p:XPDeprecationWarning=false /t:pyrogenesis /t:AtlasUI /t:test %JOBS% /nologo -clp:NoSummary'
pipeline { pipeline {
// Stop previous build in pull requests, but not in branches // Stop previous build in pull requests, but not in branches
options { disableConcurrentBuilds(abortPrevious: env.CHANGE_ID != null) } options { disableConcurrentBuilds(abortPrevious: env.CHANGE_ID != null) }
parameters { parameters {
booleanParam description: 'Non-incremental build', name: 'CLEANBUILD' booleanParam description: 'Non-incremental build', name: 'CLEANBUILD'
} }
agent { agent {
node { node {
label 'WindowsAgent' label 'WindowsAgent'
customWorkspace 'workspace/win32-pch' customWorkspace 'workspace/win32-pch'
} }
} }
stages { stages {
stage ("Pre-build") { stage('Pre-build') {
steps { steps {
discoverGitReferenceBuild() discoverGitReferenceBuild()
bat "git lfs pull -I binaries/data/tests" bat 'git lfs pull -I binaries/data/tests'
bat "git lfs pull -I \"binaries/data/mods/_test.*\"" bat 'git lfs pull -I "binaries/data/mods/_test.*"'
bat "cd libraries && get-windows-libs.bat" 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\\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 '(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 build\\workspaces && update-workspaces.bat --jenkins-tests'
script { script {
if (params.CLEANBUILD) { 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=Debug /t:Clean"
bat "cd build\\workspaces\\vs2017 && ${visualStudioPath} pyrogenesis.sln /p:Configuration=Release /t:Clean" bat "cd build\\workspaces\\vs2017 && ${visualStudioPath} pyrogenesis.sln /p:Configuration=Release /t:Clean"
} }
} }
} }
} }
stage("Debug Build") { stage('Debug Build') {
steps { steps {
bat "cd build\\workspaces\\vs2017 && ${visualStudioPath} pyrogenesis.sln /p:Configuration=Debug ${buildOptions}" bat "cd build\\workspaces\\vs2017 && ${visualStudioPath} pyrogenesis.sln /p:Configuration=Debug ${buildOptions}"
} }
post { post {
failure { failure {
script { if (!params.CLEANBUILD) { script {
build wait: false, job: "$JOB_NAME", parameters: [booleanParam(name: 'CLEANBUILD', value: true)] if (!params.CLEANBUILD) {
}} build wait: false, job: "$JOB_NAME", parameters: [booleanParam(name: 'CLEANBUILD', value: true)]
} }
} }
} }
}
}
stage("Debug Tests") { stage('Debug Tests') {
steps { steps {
timeout(time: 15) { timeout(time: 15) {
bat "cd binaries\\system && test_dbg.exe > cxxtest-debug.xml" bat 'cd binaries\\system && test_dbg.exe > cxxtest-debug.xml'
} }
} }
post { post {
always { always {
junit 'binaries/system/cxxtest-debug.xml' junit 'binaries/system/cxxtest-debug.xml'
} }
} }
} }
stage ("Release Build") { stage('Release Build') {
steps { steps {
bat "cd build\\workspaces\\vs2017 && ${visualStudioPath} pyrogenesis.sln /p:Configuration=Release ${buildOptions}" bat "cd build\\workspaces\\vs2017 && ${visualStudioPath} pyrogenesis.sln /p:Configuration=Release ${buildOptions}"
} }
} }
stage ("Release Tests") { stage('Release Tests') {
steps { steps {
timeout(time: 5) { timeout(time: 5) {
bat "cd binaries\\system && test.exe > cxxtest-release.xml" bat 'cd binaries\\system && test.exe > cxxtest-release.xml'
} }
} }
post { post {
always { always {
junit 'binaries/system/cxxtest-release.xml' junit 'binaries/system/cxxtest-release.xml'
} }
} }
} }
} }
post { post {
always { always {
recordIssues enabledForFailure: true, qualityGates: [[threshold: 1, type: 'NEW']], tool: msBuild() recordIssues enabledForFailure: true, qualityGates: [[threshold: 1, type: 'NEW']], tool: msBuild()
} }
} }
} }

View file

@ -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 <npm-groovy-lint-file-list.txt
rm npm-groovy-lint-file-list.txt
fi

View file

@ -23,6 +23,13 @@ done
has_errors=false has_errors=false
if command -v npm-groovy-lint >/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 if command -v cppcheck >/dev/null; then
# shellcheck disable=SC2086 # shellcheck disable=SC2086
./cppcheck/cppcheck.sh ${args} || has_errors=true ./cppcheck/cppcheck.sh ${args} || has_errors=true