Жизненный цикл Maven в конвейере Дженкинса - как лучше разделить обязанности? - PullRequest
7 голосов
/ 15 марта 2019

При работе с 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

Но «развертывание» включает в себя все фазы жизненного цикла из

  • проверки
  • компиляции
  • проверки
  • пакета
  • проверки
  • install
  • deploy

Итак, я видел множество примеров из пиплайна, которые делают такие вещи, как

sh 'mvn clean compile'

и

sh 'mvn test'

, что приводит к повторению шага проверки и компиляции во второй раз и тратит впустую «время / ресурсы» таким образом.Эту проблему можно решить, выполнив

sh 'mvn surefire:test'

вместо повторного запуска всего жизненного цикла.

Поэтому мой вопрос - каков наилучший способ добиться хорошего баланса между этапами трубопровода Дженкинса?а мавен жизненный цикл?Для меня я вижу два пути:

  1. Разделение жизненных циклов maven на максимально возможное число этапов конвейера - что приведет к лучшей обратной связи с пользователем jenkins (см., Какой этап не пройден и т. Д.)
  2. Пусть maven сделает все и использует конвейер jenkins только для работы с результатами maven (т.е. анализирует результаты модульных тестов и т. Д.)

Или я что-то не так понял в практике CI / CD?

Ответы [ 2 ]

1 голос
/ 15 мая 2019

Через два месяца я думаю, что у меня есть хорошо сбалансированный конвейерный сценарий Jenkins, который не завершен, но работает стабильно на 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'
           }
         }
       }
     }

   }

 }

Надеюсь, это интересно для других разработчиков.

Я обновлю это здесь, когда значительно улучшу его с течением времени.

Для тех, кто также хочет увидеть pv maven вместе с Jenkinsfile, посмотрите мой небольшой пример проекта на github: TemplateEngine

1 голос
/ 15 марта 2019

Я думаю, что нет правильного ответа, но у нас сработал следующий пример.

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.
}

Итак, чтобы обернуть это:

  • Сбой быстро. Если в модульном тесте есть ошибки -> не удалось построить.
  • Построить только один раз. Используйте те же двоичные файлы для тестирования, развертывания / тестирования интеграции, загрузить в хранилище и т. д.
  • При том, что этапы являются логическими единицами, что дает вам достаточно отзывов, где искать ошибки.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...