#!/usr/bin/env groovy pipeline { agent none options { buildDiscarder(logRotator(artifactDaysToKeepStr: '30', artifactNumToKeepStr: '20')) } stages { stage('Check pull request target') { when { changeRequest() } steps { script { if (env.CHANGE_TARGET == 'master') { throw "This pull request targets the wrong branch. Please reopen the pull request targetting the dev branch." } } } } stage('Build') { parallel { stage('Build Windows') { agent { docker { image 'krzysh/colobot-build:latest' } } steps { sh 'mkdir -p build/windows' dir('build/windows') { sh ''' # FIXME: without -lsetupapi linking sdl2 fails /opt/mxe/usr/bin/i686-w64-mingw32.static-cmake \ -DCMAKE_CXX_STANDARD_LIBRARIES="-lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 -lsetupapi" \ -DCMAKE_INSTALL_PREFIX=/install \ -DCMAKE_BUILD_TYPE=RelWithDebInfo -DDEV_BUILD=1 -DPORTABLE=1 -DTOOLS=1 -DTESTS=0 ../.. make rm -rf install DESTDIR=. make install ''' } } post { success { sh 'rm -f windows-debug.zip' zip zipFile: 'windows-debug.zip', archive: true, dir: 'build/windows/install' } } } stage('Build Linux') { agent { docker { image 'krzysh/colobot-build:latest' } } steps { sh 'mkdir -p build/linux' dir('build/linux') { sh ''' cmake \ -DCMAKE_INSTALL_PREFIX=/install -DCMAKE_SKIP_INSTALL_RPATH=ON \ -DCMAKE_BUILD_TYPE=RelWithDebInfo -DDEV_BUILD=1 -DPORTABLE=1 -DTOOLS=1 -DTESTS=1 -DDESKTOP=1 ../.. make rm -rf install DESTDIR=. make install patchelf --set-rpath '.' install/colobot ''' } } post { success { sh 'rm -f linux-debug.zip' dir('build/linux') { sh ''' # Clean up rm -rf squashfs-root rm -rf colobot.AppDir rm -rf appimage rm -f Colobot-x86_64.AppImage # Download app image tool wget -N https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage chmod +x linuxdeploy-x86_64.AppImage ./linuxdeploy-x86_64.AppImage --appimage-extract # Create AppImage NO_STRIP=1 ./squashfs-root/AppRun -e colobot --output appimage --appdir colobot.AppDir -d desktop/colobot.desktop -i ../../desktop/colobot.svg chmod +x Colobot-x86_64.AppImage # Prepare folder for zip mkdir -p appimage cp -rp install/data appimage/data cp -rp install/lang appimage/lang cp -p Colobot-x86_64.AppImage appimage/colobot ''' } zip zipFile: 'linux-debug.zip', archive: true, dir: 'build/linux/appimage' } } } } } stage('Generate docs') { agent { docker { image 'krzysh/colobot-build:latest' } } steps { dir('build/linux') { sh 'make doc' } } post { success { publishHTML([reportName: 'Doxygen', reportDir: 'build/linux/doc/html', reportFiles: 'index.html', reportTitles: '', allowMissing: false, alwaysLinkToLastBuild: false, keepAll: false]) } } } stage('Run tests') { agent { docker { image 'krzysh/colobot-build:latest' } } steps { dir('build/linux') { sh './colobot_ut --gtest_output=xml:gtestresults.xml || true' } step([$class: 'XUnitBuilder', testTimeMargin: '3000', thresholdMode: 1, thresholds: [[$class: 'FailedThreshold', failureNewThreshold: '', failureThreshold: '', unstableNewThreshold: '', unstableThreshold: '0'], [$class: 'SkippedThreshold', failureNewThreshold: '', failureThreshold: '', unstableNewThreshold: '', unstableThreshold: '']], tools: [[$class: 'GoogleTestType', deleteOutputFiles: true, failIfNotNew: true, pattern: 'build/linux/gtestresults.xml', skipNoTestFiles: false, stopProcessingIfError: true]]]) } // TODO: Maybe run Windows tests using wine as well? } stage('Run colobot-lint') { agent { label 'colobot-build' } environment { CC = '/usr/lib/llvm-3.6/bin/clang' CXX = '/usr/lib/llvm-3.6/bin/clang++' CLANG_PREFIX = '/usr/lib/llvm-3.6' } steps { copyArtifacts filter: 'build/colobot-lint,build/html_report.tar.gz,Tools/count_errors.py', fingerprintArtifacts: true, projectName: 'colobot/colobot-lint/master', selector: lastSuccessful(), target: 'colobot-lint' sh 'chmod +x colobot-lint/Tools/count_errors.py' // TODO: ??? sh 'mkdir -p build/lint' dir('build/lint') { // The cd is required here because /var/lib/jenkins is a symlink and colobot-lint breaks otherwise... sh 'cd $WORKSPACE/build/lint; cmake -DCOLOBOT_LINT_BUILD=1 -DTESTS=1 -DTOOLS=1 -DCMAKE_EXPORT_COMPILE_COMMANDS=1 $WORKSPACE' sh '''#!/bin/bash set -e +x # Run colobot-lint COLOBOT_DIR="$WORKSPACE" COLOBOT_BUILD_DIR="$WORKSPACE/build/lint" COLOBOT_LINT_BUILD_DIR="$WORKSPACE/colobot-lint/build" COLOBOT_LINT_REPORT_FILE="$WORKSPACE/build/lint/colobot_lint_report.xml" # CLANG_PREFIX="/usr/lib/llvm-3.6" # Set in top-level environment block cd "$COLOBOT_LINT_BUILD_DIR" chmod +x ./colobot-lint # Workaround for Clang not finding system headers rm -rf bin/ mkdir -p bin mv ./colobot-lint ./bin/ rm -f ./lib ln -s ${CLANG_PREFIX}/lib ./lib echo "Running colobot-lint" find "$WORKSPACE" \\( -wholename "$COLOBOT_DIR/src/*.cpp" \ -or -wholename "$COLOBOT_DIR/test/unit/*.cpp" \ -or -wholename "$COLOBOT_BUILD_DIR/fake_header_sources/src/*.cpp" \ -or -wholename "$COLOBOT_BUILD_DIR/fake_header_sources/test/unit/*.cpp" \\) \ -exec ./bin/colobot-lint \ -verbose \ -output-format xml \ -output-file "$COLOBOT_LINT_REPORT_FILE" \ -p "$COLOBOT_BUILD_DIR" \ -project-local-include-path "$COLOBOT_DIR/src" -project-local-include-path "$COLOBOT_BUILD_DIR/src" \ -license-template-file "$COLOBOT_DIR/LICENSE-HEADER.txt" \ {} + ''' sh '''#!/bin/bash set -e +x # Generate HTML report COLOBOT_LINT_BUILD_DIR="$WORKSPACE/colobot-lint/build" COLBOT_LINT_REPORT_FILE="$WORKSPACE/build/lint/colobot_lint_report.xml" HTML_REPORT_DIR="$WORKSPACE/build/lint/html_report" echo "Generating HTML report" cd "$COLOBOT_LINT_BUILD_DIR" rm -rf HtmlReport/ tar -zxf html_report.tar.gz HtmlReport/generate.py --xml-report "$COLBOT_LINT_REPORT_FILE" --output-dir "$HTML_REPORT_DIR" ''' script { retcode = sh script: '''#!/bin/bash set -e +x # Update stable/unstable build status ret=0 COLOBOT_LINT_REPORT_FILE="$WORKSPACE/build/lint/colobot_lint_report.xml" COLOBOT_LINT_DIR="$WORKSPACE/colobot-lint" OVERALL_STABLE_RULES=( "class naming" "code block placement" "compile error" # "compile warning" # "enum naming" # "function naming" "header file not self-contained" # "implicit bool cast" # "include style" # "inconsistent declaration parameter name" "license header" # "naked delete" # "naked new" # "old style function" "old-style null pointer" # "possible forward declaration" "undefined function" # "uninitialized field" # "uninitialized local variable" # "unused forward declaration" # "variable naming" "whitespace" ) echo "Checking rule stability (overall)" for ((i = 0; i < ${#OVERALL_STABLE_RULES[@]}; i++)); do rule="${OVERALL_STABLE_RULES[$i]}" count="$("$COLOBOT_LINT_DIR/Tools/count_errors.py" --rule-filter="$rule" --xml-report-file "$COLOBOT_LINT_REPORT_FILE")" if [ "$count" != "0" ]; then echo "UNSTABLE RULE: $rule ($count occurences)" ret=1 fi done STABLE_RULES_WITHOUT_CBOT=( "class naming" "code block placement" "compile error" "compile warning" # "enum naming" # "function naming" "header file not self-contained" # "implicit bool cast" "include style" "inconsistent declaration parameter name" "license header" "naked delete" "naked new" # "old style function" "old-style null pointer" # "possible forward declaration" "undefined function" "uninitialized field" # "uninitialized local variable" "unused forward declaration" # "variable naming" "whitespace" ) echo "Checking rule stability (without CBOT)" for ((i = 0; i < ${#STABLE_RULES_WITHOUT_CBOT[@]}; i++)); do rule="${STABLE_RULES_WITHOUT_CBOT[$i]}" count="$("$COLOBOT_LINT_DIR/Tools/count_errors.py" --rule-filter="$rule" --file-filter="-.*CBot.*" --xml-report-file "$COLOBOT_LINT_REPORT_FILE")" if [ "$count" != "0" ]; then echo "UNSTABLE RULE: $rule (without CBOT, $count occurences)" ret=1 fi done exit $ret ''', returnStatus: true if (retcode != 0) { currentBuild.result = 'UNSTABLE' } } } publishCppcheck pattern: 'build/lint/colobot_lint_report.xml' publishHTML([reportName: 'Colobot-lint HTML report', reportDir: 'build/lint/html_report', reportFiles: 'index.html', reportTitles: '', allowMissing: false, alwaysLinkToLastBuild: true, keepAll: true]) } } } }