You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by kw...@apache.org on 2022/01/05 16:08:13 UTC

[jackrabbit-filevault-jenkins-lib] branch feature/JCRVLT-580-parameterize-maven-version updated: allow to configure each stage separately

This is an automated email from the ASF dual-hosted git repository.

kwin pushed a commit to branch feature/JCRVLT-580-parameterize-maven-version
in repository https://gitbox.apache.org/repos/asf/jackrabbit-filevault-jenkins-lib.git


The following commit(s) were added to refs/heads/feature/JCRVLT-580-parameterize-maven-version by this push:
     new 93b2933  allow to configure each stage separately
93b2933 is described below

commit 93b293391215c1621a6f4d23a5d6f9d9c9a3dc87
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Wed Jan 5 17:07:43 2022 +0100

    allow to configure each stage separately
---
 .gitignore                                         |   3 +
 .../vault/AsfCloudbeesJenkinsEnvironment.groovy    |  49 ++++++
 .../apache/jackrabbit/vault/PipelineSupport.groovy |  86 ++++++++++
 vars/fileVaultMavenStdBuild.groovy                 | 188 ---------------------
 vars/vaultPipeline.groovy                          |  38 +++++
 vars/vaultStageBuild.groovy                        |  80 +++++++++
 vars/vaultStageDeploy.groovy                       |  48 ++++++
 vars/vaultStageIT.groovy                           |  49 ++++++
 8 files changed, 353 insertions(+), 188 deletions(-)

diff --git a/.gitignore b/.gitignore
index d8fe4fa..0accafe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,4 @@
 /.project
+/bin/
+/.settings
+/.classpath
\ No newline at end of file
diff --git a/src/org/apache/jackrabbit/vault/AsfCloudbeesJenkinsEnvironment.groovy b/src/org/apache/jackrabbit/vault/AsfCloudbeesJenkinsEnvironment.groovy
new file mode 100644
index 0000000..0ca356b
--- /dev/null
+++ b/src/org/apache/jackrabbit/vault/AsfCloudbeesJenkinsEnvironment.groovy
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.jackrabbit.vault
+
+class AsfCloudbeesJenkinsEnvironment {
+    
+    // always major.minor.qualifier version parts or just one (which means latest of that major version)
+    public static String getMavenLabel(boolean isWindows, String mavenVersion) {
+        final String versionLabel
+        if (mavenVersion ==~ /\d+/) {
+            versionLabel = "${mavenVersion}_latest"
+        } else if (mavenVersion ==~ /\d+\.\d+\.\d+/) {
+            // make sure it
+            final String suffix
+            if (isWindows) {
+                suffix = "_windows"
+            } else {
+                suffix = ""
+            }
+            versionLabel = "${mavenVersion}${suffix}"
+        } else {
+            throw new IllegalArgumentException('mavenVersion must be either one integer or three integers separated by dot')
+        }
+        // valid installation names in https://cwiki.apache.org/confluence/display/INFRA/Maven+Installation+Matrix and https://github.com/apache/infrastructure-p6/blob/production/modules/jenkins_client_master/files/hudson.tasks.Maven.xml
+        return "maven_${versionLabel}"
+    }
+
+    public static String getJdkLabel(int jdkVersion) {
+        // https://cwiki.apache.org/confluence/display/INFRA/JDK+Installation+Matrix
+        def availableJDKs = [ 8: 'jdk_1.8_latest', 9: 'jdk_1.9_latest', 10: 'jdk_10_latest', 11: 'jdk_11_latest', 12: 'jdk_12_latest', 13: 'jdk_13_latest', 14: 'jdk_14_latest', 15: 'jdk_15_latest', 16: 'jdk_16_latest', 17: 'jdk_17_latest', 18: 'jdk_18_latest', 19: 'jdk_19_latest']
+        return availableJDKs[jdkVersion]
+    }
+}
diff --git a/src/org/apache/jackrabbit/vault/PipelineSupport.groovy b/src/org/apache/jackrabbit/vault/PipelineSupport.groovy
new file mode 100644
index 0000000..add73ee
--- /dev/null
+++ b/src/org/apache/jackrabbit/vault/PipelineSupport.groovy
@@ -0,0 +1,86 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.jackrabbit.vault
+
+/**
+ * Singleton class encapsulating information about main build environment and some helper methods.
+ */
+class PipelineSupport implements Serializable {
+    
+    static PipelineSupport INSTANCE;
+    
+    static createInstance(String mainNodeLabel, int mainJdkVersion, String mainMavenVersion, boolean isOnMainBranch) {
+        INSTANCE = new PipelineSupport(mainNodeLabel, mainJdkVersion, mainMavenVersion, isOnMainBranch)
+    }
+
+    static PipelineSupport getInstance() {
+        if (INSTANCE == null) {
+            throw new IllegalStateException("createInstance has not been called before, not wrapped in vaultPipeline step?")
+        }
+        return INSTANCE;
+    }
+
+    private final String mainNodeLabel;
+    private final String mainJdkVersion;
+    private final String mainMavenVersion;
+    private final boolean isOnMainBranch;
+
+    PipelineSupport(String mainNodeLabel, int mainJdkVersion, String mainMavenVersion, boolean isOnMainBranch) {
+        this.mainNodeLabel = mainNodeLabel
+        this.mainJdkVersion = mainJdkVersion;
+        this.mainMavenVersion = mainMavenVersion
+        this.isOnMainBranch = isOnMainBranch
+    }
+
+    def executeMaven(pipeline, String mavenArguments, boolean enablePublishers) {
+        executeMaven(pipeline, mainJdkVersion, mainMavenVersion)
+    }
+
+    static def executeMaven(pipeline, String jdkVersion, String mavenVersion, String mavenArguments, boolean enablePublishers) {
+        pipeline.withMaven(
+            maven: AsfCloudbeesJenkinsEnvironment.getJdkLabel(mavenVersion),
+            jdk: AsfCloudbeesJenkinsEnvironment.getMavenLabel(jdkVersion),
+            mavenLocalRepo: '.repository',
+            publisherStrategy: enablePublishers?'IMPLICIT':'EXPLICIT') {
+            if (pipeline.isUnix()) {
+                pipeline.sh "mvn -B ${mavenArguments}"
+            } else {
+                pipeline.bat "mvn -B ${mavenArguments}"
+            }
+        }
+    }
+
+    def stagesForMainAndAdditional(Set<String> nodeLabels, Set<Integer> jdkVersions, Set<String> mavenVersions, Closure closure) {
+        stagesFor(nodeLabels.plus(mainNodeLabel), jdkVersions.plus(mainJdkVersion), mavenVersions.plus(mainMavenVersion), closure)
+    }
+
+    private def stagesFor(Set<String> nodeLabels, Set<String> jdkVersions, Set<String> mavenVersions, Closure closure) {
+        def stageMap = [:]
+        
+        for (nodeLabel in nodeLabels) {
+            for (jdkVersion in jdkVersions) {
+                for (mavenVersion in mavenVersions) {
+                    boolean isMainBuild = (nodeLabel == mainNodeLabel && jdkVersion == mainJdkVersion && mavenVersion == mainMavenVersion)
+                    stageMap["JDK ${jdkVersion}, ${nodeLabel}, Maven ${mavenVersion} ${isMainBuild ? ' (Main)' : ''}"] = closure(jdkVersion, nodeLabel, mavenVersion, isMainBuild)
+                }
+            }
+        }
+        return stageMap
+    }
+}
diff --git a/vars/fileVaultMavenStdBuild.groovy b/vars/fileVaultMavenStdBuild.groovy
deleted file mode 100644
index 55c2afc..0000000
--- a/vars/fileVaultMavenStdBuild.groovy
+++ /dev/null
@@ -1,188 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-def isOnMainBranch() {
-    return env.BRANCH_NAME == 'master'
-}
-
-def executeMaven(String jdkLabel, String mavenArguments, String publisherStrategy) {
-    executeMaven(jdkLabel, getMavenLabel('3'), mavenArguments, publisherStrategy)
-}
-
-def executeMaven(String jdkLabel, String mavenLabel, String mavenArguments, String publisherStrategy) {
-    withMaven(
-        maven: mavenLabel,
-        jdk: jdkLabel,
-        mavenLocalRepo: '.repository',
-        publisherStrategy: publisherStrategy) {
-        if (isUnix()) {
-            sh "mvn -B ${mavenArguments}"
-        } else {
-            bat "mvn -B ${mavenArguments}"
-        }
-    }
-}
-
-// always major.minor.qualifier version parts or just one (which means latest of that major version)
-String getMavenLabel(String mavenVersion) {
-    final String versionLabel
-    if (mavenVersion ==~ /\d+/) {
-        versionLabel = "${mavenVersion}_latest"
-    } else if (mavenVersion ==~ /\d+\.\d+\.\d+/) {
-        // make sure it
-        final String suffix
-        if (isUnix()) {
-            suffix = ""
-        } else {
-            suffix = "_windows"
-        }
-        versionLabel = "${mavenVersion}${suffix}"
-    } else {
-        error('mavenVersion must be either one integer or three integers separated by dot')
-    }
-    // valid installation names in https://cwiki.apache.org/confluence/display/INFRA/Maven+Installation+Matrix and https://github.com/apache/infrastructure-p6/blob/production/modules/jenkins_client_master/files/hudson.tasks.Maven.xml
-    return "maven_${versionLabel}"
-}
-
-def buildStage(final String jdkLabel, final String nodeLabel, final String mavenVersion, final boolean isMainBuild, final String sonarProjectKey) {
-    return {
-        final String wagonPluginGav = "org.codehaus.mojo:wagon-maven-plugin:2.0.2"
-        final String sonarPluginGav = "org.sonarsource.scanner.maven:sonar-maven-plugin:3.9.1.2184"
-        node(label: nodeLabel) {
-            stage("${isMainBuild ? 'Main ' : ''}Maven Build (JDK ${jdkLabel}, Maven ${mavenVersion}, ${nodeLabel})") {
-                timeout(60) {
-                    final String mavenLabel = getMavenLabel(mavenVersion) // this requires a node context
-                    echo "Running on node ${env.NODE_NAME}"
-                    checkout scm
-                    try {
-                        String mavenArguments
-                        if (isMainBuild) {
-                            String localRepoPath = "${env.WORKSPACE}/local-snapshots-dir"
-                            // Make sure the directory is wiped.
-                            dir(localRepoPath) {
-                                deleteDir()
-                            }
-                            mavenArguments = "-U clean site deploy -DskipITs -DaltDeploymentRepository=snapshot-repo::default::file:${localRepoPath} -Pjacoco-report -Dlogback.configurationFile=vault-core/src/test/resources/logback-only-errors.xml"
-                        } else {
-                            mavenArguments = '-U clean package site'
-                        }
-                        executeMaven(jdkLabel, mavenLabel, mavenArguments, 'IMPLICIT')
-                        if (isMainBuild) {
-                            // stash the integration test classes for later execution
-                            stash name: 'integration-test-classes', includes: '**/target/test-classes/**'
-                            if (isOnMainBranch()) {
-                                // Stash the build results so we can deploy them on another node
-                                stash name: 'local-snapshots-dir', includes: 'local-snapshots-dir/**'
-                            }
-                        }
-                    } finally {
-                        junit '**/target/surefire-reports/**/*.xml'
-                    }
-                }
-            }
-            /*
-            if (isMainBuild) {
-                stage("SonarCloud Analysis") {
-                    timeout(60) {
-                        withCredentials([string(credentialsId: 'sonarcloud-filevault-token', variable: 'SONAR_TOKEN')]) {
-                            String mavenArguments = "${sonarPluginGav}:sonar -Dsonar.host.url=https://sonarcloud.io -Dsonar.organization=apache -Dsonar.projectKey=${sonarProjectKey}"
-                            executeMaven(jdkLabel, mavenArguments, 'EXPLICIT')
-                        }
-                    }
-                }
-            }*/
-        }
-        if (isMainBuild && isOnMainBranch()) {
-            stage("Deployment") {
-                node('nexus-deploy') {
-                    timeout(60) {
-                        // Nexus deployment needs pom.xml
-                        checkout scm
-                        // Unstash the previously stashed build results.
-                        unstash name: 'local-snapshots-dir'
-                        // https://www.mojohaus.org/wagon-maven-plugin/merge-maven-repos-mojo.html
-                        String mavenArguments = "${wagonPluginGav}:merge-maven-repos -Dwagon.target=https://repository.apache.org/content/repositories/snapshots -Dwagon.targetId=apache.snapshots.https -Dwagon.source=file:${env.WORKSPACE}/local-snapshots-dir"
-                        executeMaven(jdkLabel, mavenArguments, 'EXPLICIT')
-                    }
-                }
-            }
-        }
-    }
-}
-
-def stageIT(final String jdkLabel, final String nodeLabel, final String mavenVersion) {
-    stage("Run Integration Tests") {
-        node(nodeLabel) {
-            timeout(60) {
-                // running ITs needs pom.xml
-                checkout scm
-                // Unstash the previously stashed build results.
-                unstash name: 'integration-test-classes'
-                try {
-                    final String mavenLabel = getMavenLabel(mavenVersion) // this requires a node context
-                    // populate test source directory
-                    String mavenArguments = '-X failsafe:integration-test failsafe:verify'
-                    executeMaven(jdkLabel, mavenLabel, mavenArguments, 'EXPLICIT')
-                } finally {
-                    junit '**/target/failsafe-reports*/**/*.xml'
-                }
-            }
-        }
-    }
-}
-
-def stagesFor(List<Integer> jdkVersions, int mainJdkVersion, List<String> nodeLabels, String mainNodeLabel, List<String> mavenVersions, String mainMavenVersion, String sonarProjectKey) {
-    def stageMap = [:]
-    // https://cwiki.apache.org/confluence/display/INFRA/JDK+Installation+Matrix
-    def availableJDKs = [ 8: 'jdk_1.8_latest', 9: 'jdk_1.9_latest', 10: 'jdk_10_latest', 11: 'jdk_11_latest', 12: 'jdk_12_latest', 13: 'jdk_13_latest', 14: 'jdk_14_latest', 15: 'jdk_15_latest', 16: 'jdk_16_latest', 17: 'jdk_17_latest', 18: 'jdk_18_latest', 19: 'jdk_19_latest']
-    
-    for (nodeLabel in nodeLabels) {
-        for (jdkVersion in jdkVersions) {
-            final String jdkLabel = availableJDKs[jdkVersion]
-            for (mavenVersion in mavenVersions) {
-                boolean isMainBuild = (jdkVersion == mainJdkVersion && nodeLabel == mainNodeLabel && mainMavenVersion == mavenVersion)
-                stageMap["JDK ${jdkVersion}, ${nodeLabel}, Maven ${mavenVersion} ${isMainBuild ? ' (Main)' : ''}"] = buildStage(jdkLabel, nodeLabel, mavenVersion, isMainBuild, sonarProjectKey)
-            }
-        }
-    }
-    return stageMap
-}
-
-// valid node labels in https://cwiki.apache.org/confluence/display/INFRA/ci-builds.apache.org
-def call(List<Integer> jdkVersions, int mainJdkVersion, List<String> nodeLabels, String mainNodeLabel, String sonarProjectKey) {
-    call(jdkVersions, mainJdkVersion, nodeLabels, mainNodeLabel, ["3"], "3", sonarProjectKey)
-}
-
-def call(List<Integer> jdkVersions, int mainJdkVersion, List<String> nodeLabels, String mainNodeLabel, List<String> mavenVersions, String mainMavenVersion, String sonarProjectKey) {
-    // adjust some job properties (https://www.jenkins.io/doc/pipeline/steps/workflow-multibranch/#properties-set-job-properties)
-    def buildProperties = []
-    if (isOnMainBranch()) {
-      // set build retention time first
-      buildProperties.add(buildDiscarder(logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '5', daysToKeepStr: '15', numToKeepStr: '10')))
-      // ensure a build is done every month
-      buildProperties.add(pipelineTriggers([cron('@monthly')]))
-    } else {
-      buildProperties.add(buildDiscarder(logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '2', daysToKeepStr: '7', numToKeepStr: '3')))
-    }
-    properties(buildProperties)
-    parallel stagesFor(jdkVersions, mainJdkVersion, nodeLabels, mainNodeLabel, mavenVersions, mainMavenVersion, sonarProjectKey)
-    // TODO: trigger ITs separately
-    stageIT('jdk_1.8_latest', mainNodeLabel, '3.3.9')
-    // finally do deploy
-}
diff --git a/vars/vaultPipeline.groovy b/vars/vaultPipeline.groovy
new file mode 100644
index 0000000..abbcbea
--- /dev/null
+++ b/vars/vaultPipeline.groovy
@@ -0,0 +1,38 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.jackrabbit.vault.PipelineSupport
+
+
+// valid node labels in https://cwiki.apache.org/confluence/display/INFRA/ci-builds.apache.org
+def call(String mainNodeLabel, int mainJdkVersion, String mainMavenVersion) {
+    // adjust some job properties (https://www.jenkins.io/doc/pipeline/steps/workflow-multibranch/#properties-set-job-properties)
+    def buildProperties = []
+    if (isOnMainBranch()) {
+      // set build retention time first
+      buildProperties.add(buildDiscarder(logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '5', daysToKeepStr: '15', numToKeepStr: '10')))
+      // ensure a build is done every month
+      buildProperties.add(pipelineTriggers([cron('@monthly')]))
+    } else {
+      buildProperties.add(buildDiscarder(logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '2', daysToKeepStr: '7', numToKeepStr: '3')))
+    }
+    properties(buildProperties)
+    PipelineSupport.createInstance(mainNodeLabel, mainJdkVersion, mainMavenVersion, env.BRANCH_NAME == 'master');
+}
+
diff --git a/vars/vaultStageBuild.groovy b/vars/vaultStageBuild.groovy
new file mode 100644
index 0000000..8ed04e7
--- /dev/null
+++ b/vars/vaultStageBuild.groovy
@@ -0,0 +1,80 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.jackrabbit.vault.PipelineSupport
+
+
+def buildStage(final PipelineSupport pipelineSupport, final String nodeLabel, final int jdkVersion, final String mavenVersion, final boolean isMainBuild, final String sonarProjectKey) {
+    return {
+        final String wagonPluginGav = "org.codehaus.mojo:wagon-maven-plugin:2.0.2"
+        final String sonarPluginGav = "org.sonarsource.scanner.maven:sonar-maven-plugin:3.9.1.2184"
+        node(label: nodeLabel) {
+            stage("${isMainBuild ? 'Main ' : ''}Maven Build (JDK ${jdkVersion}, Maven ${mavenVersion}, ${nodeLabel})") {
+                timeout(60) {
+                    echo "Running on node ${env.NODE_NAME}"
+                    checkout scm
+                    try {
+                        String mavenArguments
+                        if (isMainBuild) {
+                            String localRepoPath = "${env.WORKSPACE}/local-snapshots-dir"
+                            // Make sure the directory is wiped.
+                            dir(localRepoPath) {
+                                deleteDir()
+                            }
+                            // main build with IT for properly calculating coverage
+                            mavenArguments = "-U clean site deploy -DaltDeploymentRepository=snapshot-repo::default::file:${localRepoPath} -Pjacoco-report -Dlogback.configurationFile=vault-core/src/test/resources/logback-only-errors.xml"
+                        } else {
+                            mavenArguments = '-U clean package site' // without executing ITs
+                        }
+                        PipelineSupport.executeMaven(this, jdkVersion, mavenVersion, mavenArguments, true)
+                        if (isMainBuild) {
+                            // stash the integration test classes for later execution
+                            stash name: 'integration-test-classes', includes: '**/target/test-classes/**'
+                            if (pipelineSupport.isOnMainBranch) {
+                                // Stash the build results so we can deploy them on another node
+                                stash name: 'local-snapshots-dir', includes: 'local-snapshots-dir/**'
+                            }
+                        }
+                    } finally {
+                        junit '**/target/surefire-reports/**/*.xml'
+                    }
+                }
+            }
+            /*
+            if (isMainBuild) {
+                stage("SonarCloud Analysis") {
+                    timeout(60) {
+                        withCredentials([string(credentialsId: 'sonarcloud-filevault-token', variable: 'SONAR_TOKEN')]) {
+                            String mavenArguments = "${sonarPluginGav}:sonar -Dsonar.host.url=https://sonarcloud.io -Dsonar.organization=apache -Dsonar.projectKey=${sonarProjectKey}"
+                            executeMaven(jdkLabel, mavenArguments, 'EXPLICIT')
+                        }
+                    }
+                }
+            }*/
+        }
+    }
+}
+
+// valid node labels in https://cwiki.apache.org/confluence/display/INFRA/ci-builds.apache.org
+def call(List<String> additionalNodeLabels, List<Integer> additionalJdkVersions, List<String> additionalMavenVersions) {
+    PipelineSupport pipelineSupport = PipelineSupport.getInstance()
+    parallel pipelineSupport.stagesForMainAndAdditional(additionalJdkVersions, additionalNodeLabels, additionalMavenVersions, 
+        { String nodeLabel, int jdkVersion, String mavenVersion -> buildStage(pipelineSupport, nodeLabel, jdkVersion, mavenVersion, sonarProjectKey }
+    
+}
diff --git a/vars/vaultStageDeploy.groovy b/vars/vaultStageDeploy.groovy
new file mode 100644
index 0000000..54ee295
--- /dev/null
+++ b/vars/vaultStageDeploy.groovy
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.jackrabbit.vault.PipelineSupport
+
+
+def deployStage(final PipelineSupport pipelineSupport) {
+    return {
+        final String wagonPluginGav = "org.codehaus.mojo:wagon-maven-plugin:2.0.2"
+        final String sonarPluginGav = "org.sonarsource.scanner.maven:sonar-maven-plugin:3.9.1.2184"
+        if (isMainBuild && pipelineSupport.isOnMainBranch) {
+            stage("Deployment") {
+                node('nexus-deploy') {
+                    timeout(60) {
+                        // Nexus deployment needs pom.xml
+                        checkout scm
+                        // Unstash the previously stashed build results.
+                        unstash name: 'local-snapshots-dir'
+                        // https://www.mojohaus.org/wagon-maven-plugin/merge-maven-repos-mojo.html
+                        String mavenArguments = "${wagonPluginGav}:merge-maven-repos -Dwagon.target=https://repository.apache.org/content/repositories/snapshots -Dwagon.targetId=apache.snapshots.https -Dwagon.source=file:${env.WORKSPACE}/local-snapshots-dir"
+                        pipelineSupport.executeMaven(this, mavenArguments, false)
+                    }
+                }
+            }
+        }
+    }
+}
+
+def call() {
+    PipelineSupport pipelineSupport = PipelineSupport.getInstance()
+    deployStage(pipelineSupport).call()
+}
\ No newline at end of file
diff --git a/vars/vaultStageIT.groovy b/vars/vaultStageIT.groovy
new file mode 100644
index 0000000..5bfeda2
--- /dev/null
+++ b/vars/vaultStageIT.groovy
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.jackrabbit.vault.PipelineSupport
+
+def integrationTestStage(final PipelineSupport pipelineSupport, final String nodeLabel, final int jdkVersion, final String mavenVersion, final boolean isMainBuild) {
+    stage("Run Integration Tests") {
+        node(nodeLabel) {
+            timeout(60) {
+                // running ITs needs pom.xml
+                checkout scm
+                // Unstash the previously stashed build results.
+                unstash name: 'integration-test-classes'
+                try {
+                    // populate test source directory
+                    String mavenArguments = '-X failsafe:integration-test failsafe:verify'
+                    pipelineSupport.executeMaven(this, jdkVersion, mavenVersion, mavenArguments, false)
+                } finally {
+                    junit '**/target/failsafe-reports*/**/*.xml'
+                }
+            }
+        }
+    }
+}
+
+
+// valid node labels in https://cwiki.apache.org/confluence/display/INFRA/ci-builds.apache.org
+def call(List<String> additionalNodeLabels, List<Integer> additionalJdkVersions, List<String> additionalMavenVersions) {
+    PipelineSupport pipelineSupport = PipelineSupport.getInstance()
+    parallel pipelineSupport.stagesFor(additionalJdkVersions, additionalNodeLabels, additionalMavenVersions, 
+        {String nodeLabel, int jdkVersion, String mavenVersion, boolean isMainBuild -> integrationTestStage(pipelineSupport, nodeLabel, jdkVersion, mavenVersion, isMainBuild}
+    
+}