Skip to content
Permalink
Browse files

Add Jenkins building with bash wrapper

  • Loading branch information
filip-stenstrom committed May 3, 2019
1 parent a23909f commit 61832a39bc7d871e650cd858ac44a50f3bd74d84
@@ -0,0 +1,10 @@
install-*
testlogs-*
build-*
!build.sh
Dockerfiles/
doc/
Jenkinsfile.groovy
.git*
CMakeCache.txt

@@ -0,0 +1,3 @@
Test/FMI1/fmi1_logger_test_output.txt text eol=lf

*.sh text eol=lf
@@ -0,0 +1,6 @@
build-*/
install-*/
testlogs-*/
CMakeFiles/
ThirdParty/winflexbison/
doc/
@@ -0,0 +1,9 @@
FROM fmil_linux64:latest

RUN apt-get update && apt-get install -y \
doxygen

WORKDIR build-doc
RUN cmake -DFMILIB_INSTALL_PREFIX="../install-documentation" ".."
WORKDIR ..

@@ -0,0 +1,12 @@
FROM fmil_ubuntu16:latest

# Copied this from P500, because I think Jenkins can't clean up properly
# otherwise:
# Add jenkins owner and run as jenkins
RUN groupadd -g 999 jenkins && \
useradd -r -u 999 -g jenkins jenkins

WORKDIR /fmil/project

COPY . .

@@ -0,0 +1,5 @@
FROM ubuntu:16.04

RUN apt-get update && apt-get install -y \
build-essential \
cmake
@@ -0,0 +1,17 @@
#!/bin/bash

# Build base image
file_base="$(dirname $0)/Dockerfile_ubuntu16_base"
tag_base='fmil_ubuntu16:latest'
docker build -f $file_base -t $tag_base .

# Build FMIL image from base
file_linux64="$(dirname $0)/Dockerfile_fmil_linux64"
tag_linux64='fmil_linux64'
docker build -f $file_linux64 -t $tag_linux64 .

# Build FMIL image from base
file_doc="$(dirname $0)/Dockerfile_fmil_documentation"
tag_doc='fmil_documentation'
docker build -f $file_doc -t $tag_doc .

@@ -0,0 +1,115 @@
#!/bin/bash

# NOTE: This file must be called from <repo-root>! Otherwise the Docker
# context will be incorrect.

set -o errexit
set -o pipefail
set -o nounset
# set -o xtrace

function print_usage() {
echo "Usage:"
echo "This script must be run from <repo-root>"
printf "\targ1:\t\ttarget {linux64, documentation}\n"
printf "\targ2...:\tmake targets for linux64 [test, install]\n"
}

function log() {
echo "${0}: $1"
}

function printerr() {
echo "${0}: $1" >&2
}

function cmd_linux64() {
local make_targets=$@
local cmd=(
"set -o errexit;" \
"chmod u+x ./build.sh;" \
"./build.sh linux64 ${make_targets};" \
)
for make_target in "$@"; do
if [[ "$make_target" == 'install' ]]; then
cmd+=("cp -r install-linux64 /artifacts;")
elif [[ "$make_target" == 'test' ]]; then
cmd+=("cp -r testlogs-linux64 /artifacts;")
else
printerr "Internal error: unexpected execution path:$LINENO"
exit 1
fi
done

echo "${cmd[*]}"
}

function cmd_documentation() {
local cmd=(
"set -o errexit;" \
"cd build-doc;" \
"make doc;" \
"cp -r ../install-documentation/doc/ /artifacts" \
)
echo "${cmd[*]}"
}

# Validate args
target="$1"
make_targets="${@:2}"

if [[ $# -lt 1 ]] || [[ $# -gt 3 ]]; then
printerr "Error: invalid amount of args"
print_usage
exit 1
elif [[ ! -e $(pwd)/Dockerfiles/run.sh ]]; then
# Checks that the user runs from the repo root
printerr "Error: script ran from invalid path"
print_usage
exit 1
fi

if [[ "$target" != "linux64" ]] && [[ "$target" != "documentation" ]]; then
printerr "Error: Invalid target: '${target}'"
print_usage
exit 1
fi

for make_target in ${make_targets}; do
if [[ $make_target != "test" ]] && [[ $make_target != "install" ]]; then
printerr "Error: Invalid make target: '${make_target}'"
print_usage
exit 1
fi
done


# Actual script begins here:
if [[ $target == "linux64" ]]; then
# Double slash '//bin/bash' is necessary, because (at least) git-bash
# expands the path incorrectly otherwise. Same applies for '/$(pwd)'.
cmd="$(cmd_linux64 $make_targets)"
echo "Running command in docker: ${cmd}"
docker run -v "/$(pwd):/artifacts" fmil_linux64:latest \
"//bin/bash" -c "${cmd}"

# Uncomment for interactive debugging:
# winpty docker run -v "/$(pwd):/artifacts" -it fmil_linux64:latest

elif [[ $target == "documentation" ]]; then
cmd="$(cmd_documentation)"
echo "Running command in docker: ${cmd}"
docker run -v "/$(pwd):/artifacts" fmil_documentation:latest \
"//bin/bash" -c "${cmd}"

# Uncomment for interactive debugging:
# winpty docker run -v "/$(pwd):/artifacts" -it fmil_documentation:latest

else
printerr "Error: Invalid arg1"
print_usage
exit 1
fi

log "Docker run successful!"

@@ -0,0 +1,185 @@
// Node requirements:
// VisualStudio2010: C compiler
// OCT-SDK-1.4: CMake, msys
// docker: docker

def Config = [
'win64': [
node: 'VisualStudio2010 && OCT-SDK-1.4'
],
'win64_static_runtime': [
node: 'VisualStudio2010 && OCT-SDK-1.4'
],
'linux64': [
node: 'docker'
],
'documentation': [
node: 'docker'
]
]

def version = '2.0.3-SNAPSHOT'

// Loads the 'signBinaries' function
library 'ModelonCommon@trunk'

def tasks = [:]
for (target_temp in ['win64', 'win64_static_runtime', 'linux64']) {
def target = target_temp // bind variable before use in closure
tasks[target] = {
node(Config[target].node) {
def testLogDir = "testlogs-${target}"
def installDir = "install-${target}"

stage("Checkout: ${target}") {
checkout scm
}

stage("Build: ${target}") {
build(target)
}

stage("Test: ${target}") {
test(target, testLogDir)
}

stage("Sign: ${target}") {
dir("${installDir}/lib") {
// Seems like .so files are not allowed to be signed,
// so just signing the .dll for now.
signFiles(target, "*.dll")
}
}

stage("Archive: ${target}") {
archiveArtifacts(artifacts: "${installDir}/**")
archiveArtifacts(artifacts: "${testLogDir}/**")
}
}
}
}
tasks['documentation'] = {
def target = 'documentation'
node(Config[target].node) {

stage("Checkout: doc") {
checkout scm
}

stage("Build: doc") {
build(target)
}

stage("Archive: doc") {
archiveArtifacts(artifacts: "doc/**")
}
}
}

parallel tasks

def build(target) {
if (target == 'win64' || target == 'win64_static_runtime') {
bat """
:: Add msys to path
set PATH=%DARWIN_SDK_HOME%\\MinGW\\msys\\1.0\\bin;%PATH%
:: Add cmake to path
set PATH=%DARWIN_SDK_HOME%\\CMake\\bin;%PATH%
:: Call bash which now is on top of PATH
call bash ./build.sh ${target} install
"""
} else if (target == 'linux64' || target == 'documentation') {
sh """
# Fix permissions
chmod u+x ./Dockerfiles/build_images.sh
chmod u+x ./Dockerfiles/run.sh
# Build images
./Dockerfiles/build_images.sh
# Run the build-script inside the image, and copy artifacts to
# repo root.
./Dockerfiles/run.sh ${target} install
"""
} else {
error(message: "Invalid target: ${target}")
}
}

def test(target, testLogDir) {
def cmd_test = "ctest -C MinSizeRel"
def returnStatus
if (target == 'win64' || target == 'win64_static_runtime') {
returnStatus = bat(returnStatus: true, script: """
:: Add msys to path
set PATH=%DARWIN_SDK_HOME%\\MinGW\\msys\\1.0\\bin;%PATH%
:: Add cmake to path
set PATH=%DARWIN_SDK_HOME%\\CMake\\bin;%PATH%
:: Call bash which now is on top of PATH
call bash ./build.sh ${target} test
""")
} else if (target == 'linux64') {
returnStatus = sh(returnStatus: true, script: """
# Fix permissions
chmod u+x ./Dockerfiles/build_images.sh
chmod u+x ./Dockerfiles/run.sh
# Build images
./Dockerfiles/build_images.sh
# Run the build-script inside the image, and copy artifacts to
# repo root
./Dockerfiles/run.sh ${target} test
""")
} else {
error(message: "Invalid target: ${target}")
}
if (returnStatus != 0) {
setBuildStatus('UNSTABLE', "Test failure. Exit code from ctest: ${returnStatus}")
}

dir(testLogDir) {
if (fileExists("LastTestsFailed.log")) {
setBuildStatus('UNSTABLE', "Failing tests: ${testLogDir}/LastTestsFailed.log)")
}
if (!fileExists("LastTest.log")) {
setBuildStatus('UNSTABLE', 'Test log is missing')
}
}
}

/**
* Signs the files that match the glob expressions.
*
* param globExpressions:
* vararg of globExpressions that are evaluated from the current directory
* param prefix:
* used to create a unique intermediate stash (needed for signing),
* and to be displayed in the signBinaries step description
*/
def signFiles(prefix, Object... globExpressions) {
for (glob in globExpressions) {
for (file in findFiles(glob: glob)) {
def fname = file.toString()
def nameUnsigned = "${prefix}_${fname}_unsigned"
def nameSigned = "${prefix}_${fname}_signed"
stash(name: nameUnsigned, includes: file.toString())
signBinaries(nameUnsigned, nameSigned, "Sign binaries: ${fname} (${prefix})")

// Replace the old file with the signed one
deleteFile(fname)
unstash(nameSigned)
}
}
}

def deleteFile(filename) {
bat "del ${filename}"
}

def setBuildStatus(status, msg) {
currentBuild.result = status
println("Build result manually set to ${status}. Reason:\n${msg}")
}

0 comments on commit 61832a3

Please sign in to comment.
You can’t perform that action at this time.