diff --git a/Jenkinsfile b/Jenkinsfile
index 10ce12b72ec187c641a6164bccd5fd909aecf197..f68a7b1bb1950b10d660c9f7fa6fa07c80164164 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -1,47 +1,52 @@
 #!/usr/bin/env groovy
+def builders = [:]
+def helper = new ogs.helper()
 
-configure = null
-build = null
-post = null
-helper = null
-
-node('master') {
-    step([$class: 'GitHubSetCommitStatusBuilder', statusMessage: [content: 'Started Jenkins build']])
-    checkout scm
+builders['gcc'] = {
+    node('docker') {
+        dir('ogs') { checkout scm }
+        load 'ogs/scripts/jenkins/gcc.groovy'
+    }
+}
 
-    configure = load 'scripts/jenkins/lib/configure.groovy'
-    build     = load 'scripts/jenkins/lib/build.groovy'
-    post      = load 'scripts/jenkins/lib/post.groovy'
-    helper    = load 'scripts/jenkins/lib/helper.groovy'
+builders['msvc'] = {
+    node('win && conan') {
+        dir('ogs') { checkout scm }
+        load 'ogs/scripts/jenkins/msvc.groovy'
+    }
+}
 
-    def builders = [:]
-    builders['gcc'] = { load 'scripts/jenkins/gcc.groovy' }
-    builders['msvc'] = { load 'scripts/jenkins/msvc.groovy' }
-    builders['mac'] = { load 'scripts/jenkins/mac.groovy' }
+builders['mac'] = {
+    node('mac') {
+        dir('ogs') { checkout scm }
+        load 'ogs/scripts/jenkins/mac.groovy'
+    }
+}
 
-    if (helper.isRelease()) {
-        builders['msvc32'] = { load 'scripts/jenkins/msvc32.groovy' }
+if (helper.isRelease(this)) {
+    builders['msvc32'] = {
+        node('win && conan') {
+            dir('ogs') { checkout scm }
+            load 'ogs/scripts/jenkins/msvc32.groovy'
+        }
     }
-    if (helper.isOriginMaster()) {
-        builders['docs'] = { load 'scripts/jenkins/docs.groovy' }
+}
+if (helper.isOriginMaster(this)) {
+    builders['docs'] = {
+        node('docker') {
+            dir('ogs') { checkout scm }
+            load 'ogs/scripts/jenkins/docs.groovy'
+        }
     }
+}
 
-    parallel builders
+parallel builders
 
-    step([$class: 'GitHubCommitStatusSetter'])
+node { step([$class: 'GitHubCommitStatusSetter']) }
 
-    if (currentBuild.result == "SUCCESS" || currentBuild.result == "UNSTABLE") {
-        if (helper.isOriginMaster()) {
-            build job: 'OGS-6/clang-sanitizer', wait: false
-            build job: 'OGS-6/Deploy', wait: false
-        }
+if (currentBuild.result == "SUCCESS" || currentBuild.result == "UNSTABLE") {
+    if (helper.isOriginMaster(this)) {
+        build job: 'OGS-6/clang-sanitizer', wait: false
+        build job: 'OGS-6/Deploy', wait: false
     }
 }
-
-properties([[
-    $class: 'org.jenkinsci.plugins.workflow.job.properties.BuildDiscarderProperty',
-    strategy: [$class: 'LogRotator',
-    artifactDaysToKeepStr: '',
-    artifactNumToKeepStr: '5',
-    daysToKeepStr: '',
-    numToKeepStr: '25']]])
diff --git a/scripts/jenkins/clang.groovy b/scripts/jenkins/clang.groovy
index a9060b38e91239f3767e0b0017a75f0011f25692..35323f4aec63df66ec3f95a5aa343acd5657d757 100644
--- a/scripts/jenkins/clang.groovy
+++ b/scripts/jenkins/clang.groovy
@@ -1,13 +1,6 @@
-node('docker') {
-    stage 'Checkout (Clang)'
-    dir('ogs') {
-        checkout scm
-
-        configure = load 'scripts/jenkins/lib/configure.groovy'
-        build     = load 'scripts/jenkins/lib/build.groovy'
-        post      = load 'scripts/jenkins/lib/post.groovy'
-    }
+#!/usr/bin/env groovy
 
+node('docker') {
     def defaultDockerArgs = '-v /home/jenkins/.ccache:/usr/src/.ccache'
     def defaultCMakeOptions =
         '-DOGS_LIB_BOOST=System ' +
@@ -16,32 +9,37 @@ node('docker') {
         '-DOGS_UNDEFINED_BEHAVIOR_SANITIZER=ON ' +
         '-DOGS_BUILD_UTILS=ON'
 
+    def configure = new ogs.configure()
+    def build = new ogs.build()
+    def post = new ogs.post()
+    def helper = new ogs.helper()
+
+    stage('Checkout (Clang)') {
+        dir('ogs') { checkout scm }
+    }
+
     docker.image('ogs6/clang-base:latest').inside(defaultDockerArgs) {
-        stage 'Configure (Clang)'
-        configure.linux 'build', "${defaultCMakeOptions}"
+        stage('Configure (Clang)') {
+            configure.linux 'build', "${defaultCMakeOptions}"
+        }
         try {
-            stage 'Unit tests (Clang)'
-            build.linux 'build', 'tests', 'UBSAN_OPTIONS=print_stacktrace=1 make -j $(nproc)'
+            stage('Unit tests (Clang)') {
+                build.linux this, 'build', 'tests', 'UBSAN_OPTIONS=print_stacktrace=1 make -j $(nproc)'
+            }
         }
         catch(err) { echo "Clang sanitizer for unit tests failed!" }
 
         try {
-            stage 'End-to-end tests (Clang)'
-            build.linux 'build', 'ctest', 'UBSAN_OPTIONS=print_stacktrace=1 make -j $(nproc)'
+            stage('End-to-end tests (Clang)') {
+                build.linux this, 'build', 'ctest', 'UBSAN_OPTIONS=print_stacktrace=1 make -j $(nproc)'
+            }
         }
         catch(err) { echo "Clang sanitizer for end-to-end tests failed!" }
     }
 
-    stage 'Post (Clang)'
-    post.publishTestReports('build/Testing/**/*.xml','build/Tests/testrunner.xml',
-        'ogs/scripts/jenkins/clang-log-parser.rules')
-    post.cleanup()
+    stage('Post (Clang)') {
+        post.publishTestReports('build/Testing/**/*.xml','build/Tests/testrunner.xml',
+            'ogs/scripts/jenkins/clang-log-parser.rules')
+        post.cleanup()
+    }
 }
-
-properties([[
-    $class: 'org.jenkinsci.plugins.workflow.job.properties.BuildDiscarderProperty',
-    strategy: [$class: 'LogRotator',
-    artifactDaysToKeepStr: '',
-    artifactNumToKeepStr: '5',
-    daysToKeepStr: '',
-    numToKeepStr: '25']]])
diff --git a/scripts/jenkins/coverage.groovy b/scripts/jenkins/coverage.groovy
index 7086b147396ca544f4204e96d0a40a01ae303b03..848f2a513be17b5a84c19e7455c9bc8152020e53 100644
--- a/scripts/jenkins/coverage.groovy
+++ b/scripts/jenkins/coverage.groovy
@@ -2,33 +2,17 @@ defaultDockerArgs = '-v /home/jenkins/.ccache:/usr/src/.ccache'
 defaultCMakeOptions = '-DOGS_LIB_BOOST=System -DOGS_LIB_VTK=System'
 
 node('docker') {
-    stage 'Checkout'
-    checkout scm
+    def build = new ogs.build()
 
-    stage 'Build'
-    docker.image('ogs6/gcc-base:latest').inside(defaultDockerArgs) {
-        build 'build', '-DOGS_COVERAGE=ON',
-            'testrunner_coverage_cobertura ctest_coverage_cobertura'
-    }
-
-    archive 'build/*.xml'
-    // Report is published in a free-style child job
-}
+    stage('Checkout') { dir('ogs') { checkout scm } }
 
-def build(buildDir, cmakeOptions, target) {
-    sh "rm -rf ${buildDir} && mkdir ${buildDir}"
-
-    stage 'Configure'
-    sh "cd ${buildDir} && cmake ../ogs ${defaultCMakeOptions} ${cmakeOptions}"
+    stage('Build') {
+        docker.image('ogs6/gcc-base:latest').inside(defaultDockerArgs) {
+            build this, 'build', '-DOGS_COVERAGE=ON',
+                'testrunner_coverage_cobertura ctest_coverage_cobertura'
+        }
+    }
 
-    stage 'Build'
-    sh "cd ${buildDir} && make -j \$(nproc) ${target}"
+    archiveArtifacts 'build/*.xml'
+    // TODO: Report is published in a free-style child job
 }
-
-properties([[
-    $class: 'org.jenkinsci.plugins.workflow.job.properties.BuildDiscarderProperty',
-    strategy: [$class: 'LogRotator',
-    artifactDaysToKeepStr: '',
-    artifactNumToKeepStr: '1',
-    daysToKeepStr: '',
-    numToKeepStr: '5']]])
diff --git a/scripts/jenkins/deploy-post.groovy b/scripts/jenkins/deploy-post.groovy
index 72092dcaee969fa2bf585b6f97e5e36fb203f7bb..dcdd05162bc8abde9120dc2990c3697fd832f64c 100644
--- a/scripts/jenkins/deploy-post.groovy
+++ b/scripts/jenkins/deploy-post.groovy
@@ -1,23 +1,13 @@
 #!/usr/bin/env groovy
-
-node('master') {
-    stage 'Deploy S3 Info'
-    sh "curl 'https://svn.ufz.de:8443/job/OGS-6/job/Deploy/lastSuccessfulBuild/api/json?pretty=true&tree=actions" +
-        "[artifacts[*]],url' -g --insecure -o lastSuccessfulArtifacts.json"
-    archive 'lastSuccessfulArtifacts.json'
-    step([$class: 'S3BucketPublisher', dontWaitForConcurrentBuildCompletion: true, entries:
-        [[bucket: 'opengeosys', excludedFile: '', flatten: true, gzipFiles: false,
-            managedArtifacts: false, noUploadOnFailure: true, selectedRegion: 'eu-central-1',
-            sourceFile: "lastSuccessfulArtifacts.json", storageClass: 'STANDARD',
-            uploadFromSlave: true, useServerSideEncryption: false]], profileName: 'S3 UFZ',
-        userMetadata: [[key:
-            'Content-Type', value: 'Application/json']]])
+node {
+    stage('Deploy S3 Info') {
+        sh "curl 'https://svn.ufz.de:8443/job/OGS-6/job/Deploy/lastSuccessfulBuild/api/json?pretty=true&tree=actions" +
+            "[artifacts[*]],url' -g --insecure -o lastSuccessfulArtifacts.json"
+            archiveArtifacts 'lastSuccessfulArtifacts.json'
+        step([$class: 'S3BucketPublisher', dontWaitForConcurrentBuildCompletion: true, entries:
+            [[bucket: 'opengeosys', excludedFile: '', flatten: true, gzipFiles: false,
+                managedArtifacts: false, noUploadOnFailure: true, selectedRegion: 'eu-central-1',
+                sourceFile: "lastSuccessfulArtifacts.json", storageClass: 'STANDARD',
+                uploadFromSlave: true, useServerSideEncryption: false]], profileName: 'S3 UFZ',
+                userMetadata: [[key: 'Content-Type', value: 'Application/json']]])
 }
-
-properties([[
-    $class: 'org.jenkinsci.plugins.workflow.job.properties.BuildDiscarderProperty',
-    strategy: [$class: 'LogRotator',
-    artifactDaysToKeepStr: '',
-    artifactNumToKeepStr: '5',
-    daysToKeepStr: '',
-    numToKeepStr: '10']]])
diff --git a/scripts/jenkins/deploy.groovy b/scripts/jenkins/deploy.groovy
index 70255fbba9e18f3a9f1c6b4cad7134e890b23b90..3084b4ed067826a0d6a1a3012e1c7426bdf1181b 100644
--- a/scripts/jenkins/deploy.groovy
+++ b/scripts/jenkins/deploy.groovy
@@ -1,24 +1,16 @@
 #!/usr/bin/env groovy
-
-node('master') {
-    stage 'Deploy to S3'
-    deleteDir()
-    step([$class: 'CopyArtifact',
-        fingerprintArtifacts: true, flatten: true,
-        projectName: 'OGS-6/ufz/master',
-        selector: [$class: 'LastCompletedBuildSelector']])
-    s3upload('*')
-    build job: 'OGS-6/Deploy-Post', wait: false
+node {
+    stage('Deploy to S3') {
+        deleteDir()
+        step([$class: 'CopyArtifact',
+            fingerprintArtifacts: true, flatten: true,
+            projectName: 'OGS-6/ufz/master',
+            selector: [$class: 'LastCompletedBuildSelector']])
+            s3upload('*')
+        build job: 'OGS-6/Deploy-Post', wait: false
+    }
 }
 
-properties([[
-    $class: 'org.jenkinsci.plugins.workflow.job.properties.BuildDiscarderProperty',
-    strategy: [$class: 'LogRotator',
-    artifactDaysToKeepStr: '',
-    artifactNumToKeepStr: '5',
-    daysToKeepStr: '',
-    numToKeepStr: '10']]])
-
 def s3upload(files) {
     step([$class: 'S3BucketPublisher',
         dontWaitForConcurrentBuildCompletion: true, entries:
diff --git a/scripts/jenkins/docs.groovy b/scripts/jenkins/docs.groovy
index 629d86a8e3f3f42a8dd81bffa61c9d2df5420476..ab818b51ff4f68935bcf275cf187eb2c55708fe3 100644
--- a/scripts/jenkins/docs.groovy
+++ b/scripts/jenkins/docs.groovy
@@ -1,20 +1,23 @@
-node('docker') {
-    def defaultCMakeOptions =
-        '-DOGS_LIB_BOOST=System ' +
-        '-DOGS_LIB_VTK=System'
+def defaultCMakeOptions =
+    '-DOGS_LIB_BOOST=System ' +
+    '-DOGS_LIB_VTK=System'
 
-    stage 'Checkout (Docs)'
-    dir('ogs') { checkout scm }
+def configure = new ogs.configure()
+def build = new ogs.build()
+def post = new ogs.post()
+def helper = new ogs.helper()
 
-    docker.image('ogs6/gcc-base:16.04').inside() {
-        stage 'Configure (Docs)'
+docker.image('ogs6/gcc-base:16.04').inside() {
+    stage('Configure (Docs)') {
         configure.linux 'build', "${defaultCMakeOptions}"
+    }
 
-        stage 'Generate (Docs)'
+    stage('Generate (Docs)') {
         build.linux 'build', 'doc'
     }
+}
 
-    stage 'Reports (Docs)'
+stage('Reports (Docs)') {
     publishHTML(target: [allowMissing: false, alwaysLinkToLastBuild: false, keepAll: false,
         reportDir: 'build/docs', reportFiles: 'index.html', reportName: 'Doxygen'])
     step([$class: 'WarningsPublisher', canResolveRelativePaths: false,
@@ -22,9 +25,10 @@ node('docker') {
         defaultEncoding: '', excludePattern: '', healthy: '',
         includePattern: '', messagesPattern: '', unHealthy: '',
         unstableNewAll: '0', useStableBuildAsReference: true])
+}
 
-    if (helper.isOriginMaster()) {
-        stage 'Deploy (Docs)'
+if (helper.isOriginMaster(this)) {
+    stage('Deploy (Docs)') {
         sh 'rsync -a --delete --stats build/docs/ ' +
             'web@doxygen.opengeosys.org:/www/doxygenogs'
     }
diff --git a/scripts/jenkins/gcc.groovy b/scripts/jenkins/gcc.groovy
index 2fc08b4cac526800ae90c88c2d9d65bc5235da62..4e0c33820c6f0bcae024e5f3274ccf4d153a038f 100644
--- a/scripts/jenkins/gcc.groovy
+++ b/scripts/jenkins/gcc.groovy
@@ -1,36 +1,42 @@
-node('docker') {
-    def defaultDockerArgs = '-v /home/jenkins/.ccache:/usr/src/.ccache'
-    def defaultCMakeOptions =
-        '-DOGS_LIB_BOOST=System ' +
-        '-DOGS_LIB_VTK=System'
+def defaultDockerArgs = '-v /home/jenkins/.ccache:/usr/src/.ccache'
+def defaultCMakeOptions =
+    '-DOGS_LIB_BOOST=System ' +
+    '-DOGS_LIB_VTK=System'
 
-    stage 'Checkout (Linux-Docker)'
-    dir('ogs') { checkout scm }
+def configure = new ogs.configure()
+def build = new ogs.build()
+def post = new ogs.post()
+def helper = new ogs.helper()
 
-    docker.image('ogs6/gcc-gui:latest').inside(defaultDockerArgs) {
-        stage 'Configure (Linux-Docker)'
+docker.image('ogs6/gcc-gui:latest').inside(defaultDockerArgs) {
+    stage('Configure (Linux-Docker)') {
         configure.linux 'build', "${defaultCMakeOptions}"
+    }
 
-        stage 'CLI (Linux-Docker)'
-        build.linux 'build'
+    stage('CLI (Linux-Docker)') {
+        build.linux this, 'build'
+    }
 
-        stage 'Test (Linux-Docker)'
-        build.linux 'build', 'tests ctest'
+    stage('Test (Linux-Docker)') {
+        build.linux this, 'build', 'tests ctest'
+    }
 
-        stage 'Data Explorer (Linux-Docker)'
+    stage('Data Explorer (Linux-Docker)') {
         configure.linux 'build', "${defaultCMakeOptions} " +
             '-DOGS_BUILD_CLI=OFF -DOGS_BUILD_GUI=ON -DOGS_BUILD_UTILS=ON ' +
             '-DOGS_BUILD_TESTS=OFF -DOGS_BUILD_METIS=ON',
             'Unix Makefiles', null, true
-        build.linux 'build'
+        build.linux this, 'build'
     }
+}
 
-    if (helper.isRelease()) {
-        stage 'Release (Linux-Docker)'
-        archive 'build/*.tar.gz'
+if (helper.isRelease(this)) {
+    stage('Release (Linux-Docker)') {
+        archiveArtifacts 'build/*.tar.gz'
     }
+}
 
-    stage 'Post (Linux-Docker)'
+stage('Post (Linux-Docker)') {
     post.publishTestReports 'build/Testing/**/*.xml', 'build/Tests/testrunner.xml',
         'ogs/scripts/jenkins/clang-log-parser.rules'
     post.cleanup()
diff --git a/scripts/jenkins/lib/build.groovy b/scripts/jenkins/lib/build.groovy
deleted file mode 100644
index 2b4de04606062fe8d04b175d25b66f4addea556d..0000000000000000000000000000000000000000
--- a/scripts/jenkins/lib/build.groovy
+++ /dev/null
@@ -1,28 +0,0 @@
-def linux(buildDir, target = null, cmd = "make -j \$(nproc)") {
-    if (target == null) {
-        target = 'all'
-        if (helper.isRelease())
-            target = 'package'
-    }
-    sh "cd ${buildDir} && ${cmd} ${target}"
-}
-
-def win(buildDir, target = null) {
-    targetString = ""
-    if (target == null && helper.isRelease())
-        targetString = "--target package"
-    else if (target != null)
-        targetString = "--target ${target}"
-
-    vcvarsallParam = "amd64"
-    if (buildDir.endsWith("32"))
-        vcvarsallParam = "x86"
-
-    bat("""set path=%path:\"=%
-           call "%vs120comntools%..\\..\\VC\\vcvarsall.bat" ${vcvarsallParam}
-           cd ${buildDir}
-           cmake --build . --config Release ${targetString}""".stripIndent())
-}
-
-this.helper = load 'scripts/jenkins/lib/helper.groovy'
-return this;
diff --git a/scripts/jenkins/lib/configure.groovy b/scripts/jenkins/lib/configure.groovy
deleted file mode 100644
index 7852356d70ff16a8bd765ba948d6b8e040d0844d..0000000000000000000000000000000000000000
--- a/scripts/jenkins/lib/configure.groovy
+++ /dev/null
@@ -1,31 +0,0 @@
-def linux(buildDir, cmakeOptions, generator = 'Unix Makefiles', conan_args = null, keepBuildDir = false) {
-    if (keepBuildDir == false)
-        sh("""rm -rf ${buildDir}
-              mkdir ${buildDir}""".stripIndent())
-    if (conan_args != null)
-        sh("""cd ${buildDir}
-              conan install ../ogs ${conan_args}""".stripIndent())
-    sh """cd ${buildDir}
-          cmake ../ogs -G "${generator}" ${cmakeOptions}"""
-}
-
-def win(buildDir, cmakeOptions, generator, conan_args = null, keepBuildDir = false) {
-    if (keepBuildDir == false)
-        bat("""rd /S /Q ${buildDir}
-               mkdir ${buildDir}""".stripIndent())
-
-    if (conan_args != null)
-        bat("""cd ${buildDir}
-               conan install ../ogs ${conan_args}""".stripIndent())
-
-    vcvarsallParam = "amd64"
-        if (buildDir.endsWith("32"))
-            vcvarsallParam = "x86"
-
-    bat """set path=%path:\"=%
-           call "%vs120comntools%..\\..\\VC\\vcvarsall.bat" ${vcvarsallParam}
-           cd ${buildDir}
-           cmake ../ogs -G "${generator}" ${cmakeOptions}"""
-}
-
-return this;
diff --git a/scripts/jenkins/lib/helper.groovy b/scripts/jenkins/lib/helper.groovy
deleted file mode 100644
index 36db924ca35506fd409dbfe56e41d07aee481185..0000000000000000000000000000000000000000
--- a/scripts/jenkins/lib/helper.groovy
+++ /dev/null
@@ -1,31 +0,0 @@
-def isRelease () {
-    if (env.BRANCH_NAME == 'master' || env.BRANCH_NAME.contains('release'))
-        return true;
-    return false;
-}
-
-def isOriginMaster() {
-    if (env.BRANCH_NAME == 'master' && env.JOB_URL.contains('ufz'))
-        return true;
-    return  false;
-}
-
-def getEnv(arch = 'x64') {
-    if (env.NODE_NAME == 'visserv3')
-        qtdir = "C:\\libs\\qt\\4.8\\msvc2013-${arch}"
-    if (env.NODE_NAME == 'win1') {
-        if (arch == 'x32')
-            qtdir = "C:\\libs\\qt-4.8.7-x86-msvc2013\\qt-4.8.7-x86-msvc2013"
-        else
-            qtdir = "C:\\libs\\qt-4.8.7-${arch}-msvc2013\\qt-4.8.7-${arch}-msvc2013"
-    }
-
-    return [
-        "QTDIR=${qtdir}",
-        'Path=$Path;$QTDIR\\bin',
-        'CONAN_CMAKE_GENERATOR=Ninja',
-        "ARCH=${arch}"
-    ]
-}
-
-return this;
diff --git a/scripts/jenkins/lib/post.groovy b/scripts/jenkins/lib/post.groovy
deleted file mode 100644
index bd59addd0613d6be7b57201be900adac5f019921..0000000000000000000000000000000000000000
--- a/scripts/jenkins/lib/post.groovy
+++ /dev/null
@@ -1,25 +0,0 @@
-def publishTestReports(ctestPattern, gtestPattern, parseRulefile) {
-    step([$class: 'XUnitPublisher', testTimeMargin: '3000', thresholdMode: 1,
-        thresholds: [
-            [$class: 'FailedThreshold', failureNewThreshold: '', failureThreshold: '',
-                unstableNewThreshold: '', unstableThreshold: ''],
-            [$class: 'SkippedThreshold', failureNewThreshold: '', failureThreshold: '',
-                unstableNewThreshold: '', unstableThreshold: '']],
-        tools: [
-            [$class: 'CTestType', deleteOutputFiles: true, failIfNotNew: true, pattern:
-                "${ctestPattern}", skipNoTestFiles: true, stopProcessingIfError: true],
-            [$class: 'GoogleTestType', deleteOutputFiles: true, failIfNotNew: true, pattern:
-                "${gtestPattern}", skipNoTestFiles: true, stopProcessingIfError: true]]
-    ])
-
-    step([$class: 'LogParserPublisher', failBuildOnError: true, unstableOnWarning: false,
-        projectRulePath: "${parseRulefile}", useProjectRule: true])
-}
-
-def cleanup(directory = 'build') {
-    dir(directory) {
-        deleteDir()
-    }
-}
-
-return this;
diff --git a/scripts/jenkins/mac.groovy b/scripts/jenkins/mac.groovy
index 60f0994e05a4cd39b6619d9abf0b97d8490340c9..611a8e54b87fa55018ed63eec60f299c66eb16f7 100644
--- a/scripts/jenkins/mac.groovy
+++ b/scripts/jenkins/mac.groovy
@@ -1,37 +1,43 @@
-node('mac && conan') {
-    def defaultCMakeOptions =
-        '-DCMAKE_BUILD_TYPE=Release ' +
-        '-DOGS_CPU_ARCHITECTURE=core2 ' +
-        '-DOGS_LIB_BOOST=System' +
-        '-DOGS_LIB_VTK=System ' +
-        '-DOGS_DOWNLOAD_ADDITIONAL_CONTENT=ON ' +
-        '-DCMAKE_OSX_DEPLOYMENT_TARGET="10.11"'
+def defaultCMakeOptions =
+    '-DCMAKE_BUILD_TYPE=Release ' +
+    '-DOGS_CPU_ARCHITECTURE=core2 ' +
+    '-DOGS_LIB_BOOST=System' +
+    '-DOGS_LIB_VTK=System ' +
+    '-DOGS_DOWNLOAD_ADDITIONAL_CONTENT=ON ' +
+    '-DCMAKE_OSX_DEPLOYMENT_TARGET="10.11"'
 
-    stage 'Checkout (Mac)'
-    dir('ogs') { checkout scm }
+def configure = new ogs.configure()
+def build = new ogs.build()
+def post = new ogs.post()
+def helper = new ogs.helper()
 
-    stage 'Configure (Mac)'
+stage('Configure (Mac)') {
     configure.linux 'build', "${defaultCMakeOptions}", 'Ninja', ''
+}
 
-    stage 'CLI (Mac)'
-    build.linux 'build', null, 'ninja'
+stage('CLI (Mac)') {
+    build.linux this, 'build', null, 'ninja'
+}
 
-    stage 'Test (Mac)'
-    build.linux 'build', 'tests ctest', 'ninja'
+stage('Test (Mac)') {
+    build.linux this, 'build', 'tests ctest', 'ninja'
+}
 
-    stage 'Data Explorer (Mac)'
+stage('Data Explorer (Mac)') {
     configure.linux 'build', "${defaultCMakeOptions} " +
         '-DOGS_BUILD_GUI=ON -DOGS_BUILD_UTILS=ON -DOGS_BUILD_TESTS=OFF ' +
         '-DOGS_BUILD_METIS=ON',
         'Ninja', '', true
-    build.linux 'build', null, 'ninja'
+    build.linux this, 'build', null, 'ninja'
+}
 
-    if (helper.isRelease()) {
-        stage 'Release (Mac)'
-        archive 'build/*.tar.gz,build/*.dmg'
+if (helper.isRelease(this)) {
+    stage('Release (Mac)') {
+        archiveArtifacts 'build/*.tar.gz,build/*.dmg'
     }
+}
 
-    stage 'Post (Mac)'
+stage('Post (Mac)') {
     post.publishTestReports 'build/Testing/**/*.xml', 'build/Tests/testrunner.xml',
         'ogs/scripts/jenkins/msvc-log-parser.rules'
     post.cleanup()
diff --git a/scripts/jenkins/msvc.groovy b/scripts/jenkins/msvc.groovy
index 94b06ac1a1926ba634418dbbff319e86702408b7..aec58e08a9cef0a07baa6ea5149dd7e5d410c810 100644
--- a/scripts/jenkins/msvc.groovy
+++ b/scripts/jenkins/msvc.groovy
@@ -1,47 +1,53 @@
-node('win && conan') {
-    def defaultCMakeOptions =
-        '-DCMAKE_BUILD_TYPE=Release ' +
-        '-DOGS_LIB_BOOST=System ' +
-        '-DOGS_LIB_VTK=System ' +
-        '-DOGS_DOWNLOAD_ADDITIONAL_CONTENT=ON'
-
-    def guiCMakeOptions =
-        '-DOGS_BUILD_GUI=ON ' +
-        '-DOGS_BUILD_UTILS=ON ' +
-        '-DOGS_BUILD_TESTS=OFF ' +
-        '-DOGS_BUILD_SWMM=ON ' +
-        '-DOGS_BUILD_METIS=ON'
-
-    stage 'Checkout (Win)'
-    dir('ogs') { checkout scm }
-
-    withEnv(helper.getEnv()) {
-        stage 'Configure (Win)'
+
+def defaultCMakeOptions =
+    '-DCMAKE_BUILD_TYPE=Release ' +
+    '-DOGS_LIB_BOOST=System ' +
+    '-DOGS_LIB_VTK=System ' +
+    '-DOGS_DOWNLOAD_ADDITIONAL_CONTENT=ON'
+
+def guiCMakeOptions =
+    '-DOGS_BUILD_GUI=ON ' +
+    '-DOGS_BUILD_UTILS=ON ' +
+    '-DOGS_BUILD_TESTS=OFF ' +
+    '-DOGS_BUILD_SWMM=ON ' +
+    '-DOGS_BUILD_METIS=ON'
+
+def configure = new ogs.configure()
+def build = new ogs.build()
+def post = new ogs.post()
+def helper = new ogs.helper()
+
+withEnv(helper.getEnv(this)) {
+    stage('Configure (Win)') {
         configure.win 'build', "${defaultCMakeOptions}", 'Ninja',
-            '-u -s build_type=Release -s compiler="Visual Studio" -s compiler.version=12 -s ' +
-                'arch=x86_64'
+            '-u -s build_type=Release -s compiler="Visual Studio" ' +
+            '-s compiler.version=12 -s arch=x86_64'
+    }
 
-        stage 'CLI (Win)'
-        build.win 'build'
+    stage('CLI (Win)') {
+        build.win this, 'build'
+    }
 
-        stage 'Test (Win)'
-        build.win 'build', 'tests'
-        build.win 'build', 'ctest'
+    stage('Test (Win)') {
+        build.win this, 'build', 'tests'
+        build.win this, 'build', 'ctest'
+    }
 
-        stage 'Data Explorer (Win)'
+    stage('Data Explorer (Win)') {
         configure.win 'build', "${defaultCMakeOptions} ${guiCMakeOptions}",
-            'Ninja', '-u -s build_type=Release -s compiler="Visual Studio" -s compiler.version=12' +
-            ' -s arch=x86_64',
-            true
-        build.win 'build'
+            'Ninja', '-u -s build_type=Release -s compiler="Visual Studio" ' +
+            '-s compiler.version=12 -s arch=x86_64', true
+        build.win this, 'build'
     }
+}
 
-    if (helper.isRelease()) {
-        stage 'Release (Win)'
-        archive 'build/*.zip'
+if (helper.isRelease(this)) {
+    stage('Release (Win)') {
+        archiveArtifacts 'build/*.zip'
     }
+}
 
-    stage 'Post (Win)'
+stage('Post (Win)') {
     post.publishTestReports 'build/Testing/**/*.xml', 'build/Tests/testrunner.xml',
         'ogs/scripts/jenkins/msvc-log-parser.rules'
     post.cleanup()
diff --git a/scripts/jenkins/msvc32.groovy b/scripts/jenkins/msvc32.groovy
index 1fc87d8519f72b2d815bcceec4157e9044aa552f..633abcfc04704e8b2e2a259805fa16a17289b16f 100644
--- a/scripts/jenkins/msvc32.groovy
+++ b/scripts/jenkins/msvc32.groovy
@@ -1,23 +1,28 @@
-node('win && conan') {
-    def defaultCMakeOptions =
-        '-DCMAKE_BUILD_TYPE=Release ' +
-        '-DOGS_32_BIT=ON ' +
-        '-DOGS_LIB_BOOST=System ' +
-        '-DOGS_LIB_VTK=System ' +
-        '-DOGS_DOWNLOAD_ADDITIONAL_CONTENT=ON'
+def defaultCMakeOptions =
+    '-DCMAKE_BUILD_TYPE=Release ' +
+    '-DOGS_32_BIT=ON ' +
+    '-DOGS_LIB_BOOST=System ' +
+    '-DOGS_LIB_VTK=System ' +
+    '-DOGS_DOWNLOAD_ADDITIONAL_CONTENT=ON'
 
-    stage 'Checkout (Win)'
-    dir('ogs') { checkout scm }
+def configure = new ogs.configure()
+def build = new ogs.build()
+def post = new ogs.post()
+def helper = new ogs.helper()
 
-    stage 'Data Explorer 32-bit (Win)'
-    withEnv(helper.getEnv('x32')) {
+
+withEnv(helper.getEnv(this, 'x32')) {
+    stage('Data Explorer 32-bit (Win)') {
         configure.win 'build-32', "${defaultCMakeOptions} " +
             '-DOGS_BUILD_GUI=ON -DOGS_BUILD_UTILS=ON -DOGS_BUILD_TESTS=OFF ' +
             '-DOGS_BUILD_METIS=ON',
             'Ninja', '-u -s build_type=Release -s compiler="Visual ' +
             'Studio" -s compiler.version=12 -s arch=x86'
-        build.win 'build-32'
+        build.win this, 'build-32'
     }
-    archive 'build-32/*.zip'
+}
+
+stage('Post 32-bit (Win)') {
+    archiveArtifacts 'build-32/*.zip'
     post.cleanup('build-32')
 }