Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
51e6eada
Commit
51e6eada
authored
Feb 05, 2019
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add coverage report to build pipeline
parent
13095ce9
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
186 additions
and
76 deletions
+186
-76
Jenkinsfile
Jenkinsfile
+186
-76
No files found.
Jenkinsfile
View file @
51e6eada
#
!
/usr/
bin
/
env
groovy
#
!
/usr/
bin
/
env
groovy
// Default CMake flags for most builds (except coverage).
// Default CMake flags for release builds.
defaultBuildFlags
=
[
defaultReleaseBuildFlags
=
[
'CAF_MORE_WARNINGS:BOOL=yes'
,
'CAF_ENABLE_RUNTIME_CHECKS:BOOL=yes'
,
'CAF_ENABLE_RUNTIME_CHECKS:BOOL=yes'
,
'CAF_NO_OPENCL:BOOL=yes'
,
'CAF_NO_OPENCL:BOOL=yes'
,
'CAF_INSTALL_UNIT_TESTS:BOOL=yes'
,
]
]
// CMake flags for release builds.
// Default CMake flags for debug builds.
releaseBuildFlags
=
defaultBuildFlags
+
[
defaultDebugBuildFlags
=
defaultReleaseBuildFlags
+
[
]
// CMake flags for debug builds.
debugBuildFlags
=
defaultBuildFlags
+
[
'CAF_ENABLE_RUNTIME_CHECKS:BOOL=yes'
,
'CAF_ENABLE_RUNTIME_CHECKS:BOOL=yes'
,
'CAF_ENABLE_ADDRESS_SANITIZER:BOOL=yes'
,
'CAF_LOG_LEVEL:STRING=TRACE'
,
'CAF_LOG_LEVEL:STRING=TRACE'
,
]
]
// CMake flags for macOS builds only.
defaultBuildFlags
=
[
macBuildFlags
=
[
debug:
defaultDebugBuildFlags
,
'OPENSSL_ROOT_DIR=/usr/local/opt/openssl'
,
release:
defaultReleaseBuildFlags
,
'OPENSSL_INCLUDE_DIR=/usr/local/opt/openssl/include'
,
]
// CMake flags by OS and build type.
buildFlags
=
[
macOS:
[
debug:
defaultDebugBuildFlags
+
[
'OPENSSL_ROOT_DIR=/usr/local/opt/openssl'
,
'OPENSSL_INCLUDE_DIR=/usr/local/opt/openssl/include'
,
],
release:
defaultReleaseBuildFlags
+
[
'OPENSSL_ROOT_DIR=/usr/local/opt/openssl'
,
'OPENSSL_INCLUDE_DIR=/usr/local/opt/openssl/include'
,
],
],
Windows:
[
debug:
defaultDebugBuildFlags
+
[
'CAF_BUILD_STATIC_ONLY:BOOL=yes'
,
],
release:
defaultReleaseBuildFlags
+
[
'CAF_BUILD_STATIC_ONLY:BOOL=yes'
,
],
],
]
]
// Our build matrix. The keys are the operating system labels and the values
// Our build matrix. The keys are the operating system labels and the values
// are lists of tool labels.
// are lists of tool labels.
buildMatrix
=
[
buildMatrix
=
[
// Debug builds with ASAN + logging for various OS/compiler combinations.
[
'Linux'
,
[
[
'Linux'
,
[
builds:
[
'debug'
],
builds:
[
'debug'
],
tools:
[
'gcc4.8'
,
'gcc4.9'
,
'gcc5'
,
'gcc6'
,
'gcc7'
,
'gcc8'
],
tools:
[
'gcc4.8'
,
'gcc4.9'
,
'gcc5'
,
'gcc6'
,
'gcc7'
],
cmakeArgs:
debugBuildFlags
,
]],
]],
[
'
macOS
'
,
[
[
'
Linux
'
,
[
builds:
[
'debug'
],
builds:
[
'debug'
],
tools:
[
'
clang
'
],
tools:
[
'
gcc8
'
],
cmakeArgs:
debugBuildFlags
+
macBuildFlags
,
extraSteps:
[
'coverageReport'
]
,
]],
]],
// One release build per supported OS. FreeBSD and Windows have the least
// testing outside Jenkins, so we also explicitly schedule debug builds.
[
'Linux'
,
[
[
'Linux'
,
[
builds:
[
'release'
],
builds:
[
'release'
],
tools:
[
'gcc8'
,
'clang'
],
tools:
[
'gcc8'
,
'clang'
],
cmakeArgs:
releaseBuildFlags
,
]],
]],
[
'macOS'
,
[
[
'macOS'
,
[
builds:
[
'release'
],
builds:
[
'
debug'
,
'
release'
],
tools:
[
'clang'
],
tools:
[
'clang'
],
cmakeArgs:
releaseBuildFlags
+
macBuildFlags
,
]],
]],
[
'FreeBSD'
,
[
[
'FreeBSD'
,
[
builds:
[
'debug'
],
// no release build for now, because it takes 1h
builds:
[
'debug'
],
// no release build for now, because it takes 1h
tools:
[
'clang'
],
tools:
[
'clang'
],
cmakeArgs:
debugBuildFlags
,
]],
]],
[
'Windows'
,
[
[
'Windows'
,
[
builds:
[
'debug'
,
'release'
],
// TODO: debug build currently broken
//builds: ['debug', 'release'],
builds:
[
'release'
],
tools:
[
'msvc'
],
tools:
[
'msvc'
],
cmakeArgs:
[
'CAF_BUILD_STATIC_ONLY:BOOL=yes'
,
'CAF_ENABLE_RUNTIME_CHECKS:BOOL=yes'
,
'CAF_NO_OPENCL:BOOL=yes'
,
],
]],
// One Additional build for coverage reports.
/* TODO: this build exhausts all storage on the node and is temporarily
* disabled until resolving the issue
['Linux', [
builds: ['debug'],
tools: ['gcc8 && gcovr'],
extraSteps: ['coverageReport'],
cmakeArgs: [
'CAF_ENABLE_GCOV:BOOL=yes',
'CAF_NO_EXCEPTIONS:BOOL=yes',
'CAF_FORCE_NO_EXCEPTIONS:BOOL=yes',
],
]],
]],
*/
]
]
// Optional environment variables for combinations of labels.
// Optional environment variables for combinations of labels.
...
@@ -86,28 +78,87 @@ buildEnvironments = [
...
@@ -86,28 +78,87 @@ buildEnvironments = [
'Linux && clang'
:
[
'CXX=clang++'
],
'Linux && clang'
:
[
'CXX=clang++'
],
]
]
// Called *after* a build succeeded.
// Adds additional context information to commits on GitHub.
def
coverageReport
()
{
def
setBuildStatus
(
context
,
state
,
message
)
{
echo
"set ${context} result for commit ${env.GIT_COMMIT} to $state: $message"
step
([
$class
:
'GitHubCommitStatusSetter'
,
commitShaSource:
[
$class
:
'ManuallyEnteredShaSource'
,
sha:
env
.
GIT_COMMIT
,
],
reposSource:
[
$class
:
'ManuallyEnteredRepositorySource'
,
url:
env
.
GIT_URL
,
],
contextSource:
[
$class
:
'ManuallyEnteredCommitContextSource'
,
context:
context
,
],
errorHandlers:
[[
$class
:
'ChangingBuildStatusErrorHandler'
,
result:
'SUCCESS'
,
]],
statusResultSource:
[
$class
:
'ConditionalStatusResultSource'
,
results:
[[
$class
:
'AnyBuildResult'
,
state:
state
,
message:
message
,
]]
],
]);
}
// Creates coverage reports via the Cobertura plugin.
def
coverageReport
(
buildId
)
{
echo
"Create coverage report for build ID $buildId"
// Paths we wish to ignore in the coverage report.
def
installDir
=
"$WORKSPACE/$buildId"
def
excludePaths
=
[
"/usr/"
,
"$WORKSPACE/caf-sources/examples"
,
"$WORKSPACE/caf-sources/tools"
,
"$WORKSPACE/caf-sources/libcaf_test"
,
"$WORKSPACE/caf-sources/libcaf_core/test"
,
"$WORKSPACE/caf-sources/libcaf_io/test"
,
"$WORKSPACE/caf-sources/libcaf_openssl/test"
,
"$WORKSPACE/caf-sources/libcaf_opencl"
,
"$WORKSPACE/caf-sources/libcaf_core/caf/scheduler/profiled_coordinator.hpp"
,
]
def
excludePathsStr
=
excludePaths
.
join
(
','
)
dir
(
'caf-sources'
)
{
dir
(
'caf-sources'
)
{
sh
'gcovr -e examples -e tools -e libcaf_test -e ".*/test/.*" -e libcaf_core/caf/scheduler/profiled_coordinator.hpp -x -r . > coverage.xml'
try
{
archiveArtifacts
'**/coverage.xml'
withEnv
([
'ASAN_OPTIONS=verify_asan_link_order=false:detect_leaks=0'
])
{
cobertura
([
sh
"""
autoUpdateHealth:
false
,
kcov --exclude-path=$excludePathsStr kcov-result ./build/caf-test &> kcov_output.txt
autoUpdateStability:
false
,
find . -name 'coverage.json' -exec mv {} result.json \\;
coberturaReportFile:
'**/coverage.xml'
,
"""
conditionalCoverageTargets:
'70, 0, 0'
,
}
failUnhealthy:
false
,
stash
includes:
'result.json'
,
name:
'coverage-result'
failUnstable:
false
,
archiveArtifacts
'**/cobertura.xml'
lineCoverageTargets:
'80, 0, 0'
,
cobertura
([
maxNumberOfBuilds:
0
,
autoUpdateHealth:
false
,
methodCoverageTargets:
'80, 0, 0'
,
autoUpdateStability:
false
,
onlyStable:
false
,
coberturaReportFile:
'**/cobertura.xml'
,
sourceEncoding:
'ASCII'
,
conditionalCoverageTargets:
'70, 0, 0'
,
zoomCoverageChart:
false
,
failUnhealthy:
false
,
])
failUnstable:
false
,
lineCoverageTargets:
'80, 0, 0'
,
maxNumberOfBuilds:
0
,
methodCoverageTargets:
'80, 0, 0'
,
onlyStable:
false
,
sourceEncoding:
'ASCII'
,
zoomCoverageChart:
false
,
])
}
catch
(
Exception
e
)
{
echo
"exception: $e"
archiveArtifacts
'kcov_output.txt'
}
}
}
}
}
// Wraps `cmakeBuild`.
def
cmakeSteps
(
buildType
,
cmakeArgs
,
buildId
)
{
def
cmakeSteps
(
buildType
,
cmakeArgs
,
buildId
)
{
def
installDir
=
"$WORKSPACE/$buildId"
def
installDir
=
"$WORKSPACE/$buildId"
dir
(
'caf-sources'
)
{
dir
(
'caf-sources'
)
{
...
@@ -126,11 +177,17 @@ def cmakeSteps(buildType, cmakeArgs, buildId) {
...
@@ -126,11 +177,17 @@ def cmakeSteps(buildType, cmakeArgs, buildId) {
]],
]],
])
])
// Run unit tests.
// Run unit tests.
ctest
([
try
{
arguments:
'--output-on-failure'
,
ctest
([
installation:
'cmake in search path'
,
arguments:
'--output-on-failure'
,
workingDir:
'build'
,
installation:
'cmake in search path'
,
])
workingDir:
'build'
,
])
writeFile
file:
"${buildId}.success"
,
text:
"success\n"
}
catch
(
Exception
)
{
writeFile
file:
"${buildId}.failure"
,
text:
"failure\n"
}
stash
includes:
"${buildId}.*"
,
name:
buildId
}
}
// Only generate artifacts for the master branch.
// Only generate artifacts for the master branch.
if
(
PrettyJobBaseName
==
'master'
)
{
if
(
PrettyJobBaseName
==
'master'
)
{
...
@@ -157,15 +214,14 @@ def buildSteps(buildType, cmakeArgs, buildId) {
...
@@ -157,15 +214,14 @@ def buildSteps(buildType, cmakeArgs, buildId) {
}
}
}
else
{
}
else
{
echo
"Unix build on $NODE_NAME"
echo
"Unix build on $NODE_NAME"
withEnv
([
"label_exp="
+
STAGE_NAME
.
toLowerCase
(),
withEnv
([
"label_exp="
+
STAGE_NAME
.
toLowerCase
(),
"ASAN_OPTIONS=detect_leaks=0"
])
{
"ASAN_OPTIONS=detect_leaks=0"
])
{
cmakeSteps
(
buildType
,
cmakeArgs
,
buildId
)
cmakeSteps
(
buildType
,
cmakeArgs
,
buildId
)
}
}
}
}
}
}
// Builds a stage for given builds. Results in a parallel stage `if builds.size() > 1`.
// Builds a stage for given builds. Results in a parallel stage `if builds.size() > 1`.
def
makeBuildStages
(
matrixIndex
,
builds
,
lblExpr
,
settings
)
{
def
makeBuildStages
(
matrixIndex
,
os
,
builds
,
lblExpr
,
settings
)
{
builds
.
collectEntries
{
buildType
->
builds
.
collectEntries
{
buildType
->
def
id
=
"$matrixIndex $lblExpr: $buildType"
def
id
=
"$matrixIndex $lblExpr: $buildType"
[
[
...
@@ -176,8 +232,8 @@ def makeBuildStages(matrixIndex, builds, lblExpr, settings) {
...
@@ -176,8 +232,8 @@ def makeBuildStages(matrixIndex, builds, lblExpr, settings) {
try
{
try
{
def
buildId
=
"${lblExpr}_${buildType}"
.
replace
(
' && '
,
'_'
)
def
buildId
=
"${lblExpr}_${buildType}"
.
replace
(
' && '
,
'_'
)
withEnv
(
buildEnvironments
[
lblExpr
]
?:
[])
{
withEnv
(
buildEnvironments
[
lblExpr
]
?:
[])
{
buildSteps
(
buildType
,
settings
[
'cmakeArgs'
],
buildId
)
buildSteps
(
buildType
,
(
buildFlags
[
os
]
?:
defaultBuildFlags
)[
buildType
],
buildId
)
(
settings
[
'extraSteps'
]
?:
[]).
each
{
fun
->
"$fun"
()
}
(
settings
[
'extraSteps'
]
?:
[]).
each
{
fun
->
"$fun"
(
buildId
)
}
}
}
}
finally
{
}
finally
{
cleanWs
()
cleanWs
()
...
@@ -191,7 +247,7 @@ def makeBuildStages(matrixIndex, builds, lblExpr, settings) {
...
@@ -191,7 +247,7 @@ def makeBuildStages(matrixIndex, builds, lblExpr, settings) {
pipeline
{
pipeline
{
options
{
options
{
buildDiscarder
(
logRotator
(
numToKeepStr:
'
50'
,
artifactNumToKeepStr:
'10
'
))
buildDiscarder
(
logRotator
(
numToKeepStr:
'
20'
,
artifactNumToKeepStr:
'5
'
))
}
}
agent
none
agent
none
environment
{
environment
{
...
@@ -208,7 +264,16 @@ pipeline {
...
@@ -208,7 +264,16 @@ pipeline {
dir
(
'caf-sources'
)
{
dir
(
'caf-sources'
)
{
checkout
scm
checkout
scm
sh
'./scripts/get-release-version.sh'
sh
'./scripts/get-release-version.sh'
/// We really don't need to copy the .git folder around.
dir
(
'.git'
)
{
deleteDir
()
}
}
}
zip
([
archive:
true
,
dir:
'caf-sources'
,
zipFile:
'sources.zip'
,
])
stash
includes:
'caf-sources/**'
,
name:
'caf-sources'
stash
includes:
'caf-sources/**'
,
name:
'caf-sources'
}
}
}
}
...
@@ -224,13 +289,58 @@ pipeline {
...
@@ -224,13 +289,58 @@ pipeline {
def
matrixIndex
=
"[$index:$toolIndex]"
def
matrixIndex
=
"[$index:$toolIndex]"
def
builds
=
settings
[
'builds'
]
def
builds
=
settings
[
'builds'
]
def
labelExpr
=
"$os && $tool"
def
labelExpr
=
"$os && $tool"
xs
<<
makeBuildStages
(
matrixIndex
,
builds
,
labelExpr
,
settings
)
xs
<<
makeBuildStages
(
matrixIndex
,
os
,
builds
,
labelExpr
,
settings
)
}
}
}
}
parallel
xs
parallel
xs
}
}
}
}
}
}
stage
(
'Check Test Results'
)
{
agent
{
label
'master'
}
steps
{
script
{
dir
(
'tmp'
)
{
// Compute the list of all build IDs.
def
buildIds
=
[]
buildMatrix
.
each
{
entry
->
def
(
os
,
settings
)
=
entry
settings
[
'tools'
].
each
{
tool
->
settings
[
'builds'
].
each
{
buildIds
<<
"${os}_${tool}_${it}"
}
}
}
// Compute how many tests have succeeded
def
builds
=
buildIds
.
size
()
def
successes
=
buildIds
.
inject
(
0
)
{
result
,
buildId
->
try
{
unstash
buildId
}
catch
(
Exception
)
{
}
result
+
(
fileExists
(
"${buildId}.success"
)
?
1
:
0
)
}
echo
"$successes unit tests tests of $builds were successful"
if
(
builds
==
successes
)
{
setBuildStatus
(
'unit-tests'
,
'SUCCESS'
,
'All builds passed the unit tests'
)
}
else
{
def
failures
=
builds
-
successes
setBuildStatus
(
'unit-tests'
,
'FAILURE'
,
"$failures/$builds builds failed to run the unit tests"
)
}
// Get the coverage result.
try
{
unstash
'coverage-result'
if
(
fileExists
(
'result.json'
))
{
def
resultJson
=
readJSON
file:
'result.json'
setBuildStatus
(
'coverage'
,
'SUCCESS'
,
resultJson
[
'percent_covered'
]
+
'% coverage'
)
}
else
{
setBuildStatus
(
'coverage'
,
'FAILURE'
,
'Unable to get coverage report'
)
}
}
catch
(
Exception
)
{
setBuildStatus
(
'coverage'
,
'FAILURE'
,
'Unable to generate coverage report'
)
}
}
}
}
}
stage
(
'Documentation'
)
{
stage
(
'Documentation'
)
{
agent
{
label
'pandoc'
}
agent
{
label
'pandoc'
}
steps
{
steps
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment