Jenkins管道中的Maven Lifecycle-如何最好地分开责任



与Jenkins 2(声明性的)管道和Maven一起工作时,我总是在如何组织管道中组织物品以使其可取消和灵活有问题。

在一侧,我想将管道分开为逻辑阶段,例如:

pipeline
 {
  stages
   {
    stage('Clean') {}
    stage('Build') {}
    stage('Test') {}
    stage('Sanity check') {}
    stage('Documentation') {}
    stage('Deploy - Test') {}
    stage('Selenium tests') {}
    stage('Deploy - Production') {}
    stage('Deliver') {}
   }
 }

另一方面,我有

运行的Maven
mvn clean deploy site

简单地我可以将Maven拆分为

mvn clean
mvn deploy
mvn site

但是"部署"包括

的所有生命周期阶段
  • 验证
  • 编译
  • 测试
  • 软件包
  • 验证
  • 安装
  • 部署

所以我看到了很多操作

的管道示例
sh 'mvn clean compile'

sh 'mvn test'

导致第二次重复验证和编译步骤,并以这种方式浪费"时间/资源"。这可以通过做

来解决
sh 'mvn surefire:test'

而不是再次运行整个生命周期。

所以我的问题是 - 哪种是在Jenkins Pipline阶段和Maven Lifececle之间取得良好平衡的最佳方法?对我来说,我看到了两种方法:

  1. 将Maven Lifecycles拆分为尽可能多的管道阶段 - 这将导致更好的Jenkins用户反馈(请参阅哪个阶段失败等)
  2. 让Maven尽一切努力并使用Jenkins管道来与Maven的结果一起工作(即分析单位测试结果等)

或我在CI/CD练习中错过了一些东西?

两个月后,我认为我有一个均衡的詹金斯管道脚本,但在Windows和Linux上的工作稳定。它避免了我见过的其他例子的陷阱。

Jenkinsfile

pipeline
 {
  agent any
  tools
   {
    maven 'Maven3'
    jdk 'JDK8'
   }
  options
   {
    buildDiscarder(logRotator(numToKeepStr: '4'))
    skipStagesAfterUnstable()
    disableConcurrentBuilds()
   }

  triggers
   {
    // MINUTE HOUR DOM MONTH DOW
    pollSCM('H 6-18/4 * * 1-5')
   }

  stages
   {
    stage('Clean')
     {
      steps
       {
        script
         {
          if (isUnix()) 
           {
            sh 'mvn --batch-mode clean'
           }
          else
           {
            bat 'mvn --batch-mode clean'
           }
         }
       }
     }
    stage('Build')
     {
      steps
       {
        script
         {
          if (isUnix()) 
           {
            sh 'mvn --batch-mode compile'
           }
          else
           {
            bat 'mvn --batch-mode compile'
           }
         }
       }
     }
    stage('UnitTests')
     {
      steps
       {
        script
         {
          if (isUnix()) 
           {
            sh 'mvn --batch-mode resources:testResources compiler:testCompile surefire:test'
           }
          else
           {
            bat 'mvn --batch-mode resources:testResources compiler:testCompile surefire:test'
           }
         }
       }
      post
       {
        always
         {
          junit testResults: 'target/surefire-reports/*.xml'
         }
       }
     }
    stage('Sanity check')
     {
      steps
       {
        script
         {
          if (isUnix()) 
           {
            sh 'mvn --batch-mode checkstyle:checkstyle pmd:pmd pmd:cpd com.github.spotbugs:spotbugs-maven-plugin:spotbugs'
           }
          else
           {
            bat 'mvn --batch-mode checkstyle:checkstyle pmd:pmd pmd:cpd com.github.spotbugs:spotbugs-maven-plugin:spotbugs'
           }
         }
       }
     }
    stage('Packaging')
     {
      steps
       {
        script
         {
          if (isUnix()) 
           {
            sh 'mvn --batch-mode jar:jar'
           }
          else
           {
            bat 'mvn --batch-mode jar:jar'
           }
         }
       }
     }
    stage('install local')
     {
      steps
       {
        script
         {
          if (isUnix()) 
           {
            sh 'mvn --batch-mode jar:jar source:jar install:install'
           }
          else
           {
            bat 'mvn --batch-mode jar:jar source:jar install:install' // maven-jar-plugin falseCreation default is false, so no doubled jar construction here, but required for maven-install-plugin internal data
           }
         }
       }
     }
    stage('Documentation')
     {
      steps
       {
        script
         {
          if (isUnix()) 
           {
            sh 'mvn --batch-mode site'
           }
          else
           {
            bat 'mvn --batch-mode site'
           }
         }
       }
      post
       {
        always
         {
          publishHTML(target: [reportName: 'Site', reportDir: 'target/site', reportFiles: 'index.html', keepAll: false])
         }
       }
     }
    stage('Deploy test')
     {
      steps
       {      
        script
         {
          if (isUnix()) 
           {
            // todo
           }
          else
           {
            bat returnStatus: true, script: 'sc stop Tomcat8'
            sleep(time:30, unit:"SECONDS")
            bat returnStatus: true, script: 'C:\scripts\clean.bat'
            bat returnStatus: true, script: 'robocopy "target" "C:\Program Files\Apache Software Foundation\Tomcat 9.0\webapps" Test.war'
            bat 'sc start Tomcat8'
            sleep(time:30, unit:"SECONDS")
           }
         }
       }
     }
    stage('Integration tests')
     {
      steps
       {
        script
         {
          if (isUnix()) 
           {
            sh 'mvn --batch-mode failsafe:integration-test failsafe:verify'
           }
          else
           {
            bat 'mvn --batch-mode failsafe:integration-test failsafe:verify'
           }
         }
       }
     }
   }
 }

希望这对外面的其他开发人员很有趣。

随着时间的流逝,我将在此处进行更新。

对于那些也希望看到Maven Pom和Jenkinsfile的人,请在Github上查看我的小型示例项目:TemplateEngine

我认为没有正确的答案,但是以下示例对我们有用。

stage('Build and Unit Test') {
    mvn clean deploy -> with unit tests, without integration tests, deploy local
    deploy local:
    You can define in a maven profile the distributionManagement like:
    <distributionManagement>
        <repository>
            <id>localFile</id>
            <url>file:target/repository/</url>
        </repository>
        <snapshotRepository>
            <id>localFile</id>
            <url>file:target/repository/</url>
        </snapshotRepository>
    </distributionManagement>
}   
stage('Pre Integration Tests') {
    The binaries are now in target/repository.
    From there you can use the binaries as you like.
    Copy them to a server, deploy them on an application server, etc.
}
stage('Integration Tests') {
    maven failsafe:integration-test failsafe:verify
    Already all tests are compiled, just execute them and verify the result.
}
stage('Deploy to Binary Repository (Nexus, Artifactory, etc)') {
    Now if everything is ok, finally upload the Binaries.
    For that we use wagon-maven-plugin
    So from target/repository the files are uploaded to the Binary Repository.
}

因此,将其结合起来:

  • 失败快。如果单元测试有错误 ->失败构建。
  • 仅构建一次。使用相同的二进制文件进行测试,部署/集成测试,上传到存储库等
  • 阶段是逻辑单位,这为您提供了足够的反馈在哪里寻找错误。

最新更新