Jenkinsfile 14.5 KB
Newer Older
1
2
3
import org.apache.tools.ant.types.selectors.SelectorUtils
import org.jenkinsci.plugins.pipeline.modeldefinition.Utils

4
5
6
/*
** Variables.
*/
7
def serie = '21.10'
8
9
10
def stableBranch = "${serie}.x"
def devBranch = "dev-${serie}.x"
env.REF_BRANCH = stableBranch
11
env.PROJECT='centreon-web'
12
13
if (env.BRANCH_NAME.startsWith('release-')) {
  env.BUILD = 'RELEASE'
14
15
  env.DELIVERY_STAGE = 'Delivery to testing'
  env.DOCKER_STAGE = 'Docker packaging'
16
} else if (env.BRANCH_NAME == stableBranch) {
17
  env.BUILD = 'REFERENCE'
18
19
  env.DELIVERY_STAGE = 'Delivery to canary'
  env.DOCKER_STAGE = 'Docker packaging with canary rpms'
20
} else if (env.BRANCH_NAME == devBranch) {
21
  env.BUILD = 'QA'
22
23
  env.DELIVERY_STAGE = 'Delivery to unstable'
  env.DOCKER_STAGE = 'Docker packaging with unstable rpms'
24
25
} else {
  env.BUILD = 'CI'
26
27
  env.DELIVERY_STAGE = 'Delivery to canary'
  env.DOCKER_STAGE = 'Docker packaging with canary rpms'
28
}
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

def buildBranch = env.BRANCH_NAME
if (env.CHANGE_BRANCH) {
  buildBranch = env.CHANGE_BRANCH
}

def backendFiles = [
  'Jenkinsfile',
  'sonar-project.properties',
  '**/*.php',
  'www/**/*.js',
  '**/*.sh',
  'composer.*',
  'symfony.lock',
  '.env*',
  'behat.yml',
  'ruleset.xml',
  'phpstan.neon',
  'bin/*',
  'config/*',
  'cron/*',
  'doc/*',
  'features/*',
  'lang/*',
  'lib/*',
  'tests/*'
]
def frontendFiles = [
  'Jenkinsfile',
  'sonar-project.properties',
  'www/front_src/*',
  'packag*.json',
  'webpack*',
  'babel.config.js',
  'jest.config.js',
  'setupTest.js',
  'tsconfig.json',
  '.prettierrc.js',
  '.eslint*',
  '.csslintrc',
  '**/*.ts',
  '**/*.tsx',
  '**/*.jsx',
  'lang/*'
]
def hasFrontendChanges = true
def hasBackendChanges = true
76
def apiFeatureFiles = []
77
def featureFiles = []
78
79
80
81
82
83
def acceptanceTag = ""

/*
** Functions
*/
def isStableBuild() {
84
  return ((env.BUILD == 'REFERENCE') || (env.BUILD == 'QA'))
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
}

def hasChanges(patterns) {
  if (isStableBuild()) {
    return true
  }

  def isMatching = false

  sh "git config --add remote.origin.fetch +refs/heads/${env.REF_BRANCH}:refs/remotes/origin/${env.REF_BRANCH}"
  sh "git fetch --no-tags"
  sh "git config user.name none"
  sh "git config user.email none"
  sh "git pull --rebase origin ${env.REF_BRANCH} || git rebase --abort || true"
  def diffFiles = sh(script: "git diff --name-only origin/${env.REF_BRANCH} --", returnStdout: true).trim().split()

  for (file in diffFiles) {
    for (pattern in patterns) {
      if (SelectorUtils.match(pattern, file)) {
        isMatching = true
      }
    }
  }

  return isMatching
}

112
def checkoutCentreonBuild() {
113
  dir('centreon-build') {
114
115
116
117
118
    checkout resolveScm(source: [$class: 'GitSCMSource',
      remote: 'https://github.com/centreon/centreon-build.git',
      credentialsId: 'technique-ci',
      traits: [[$class: 'jenkins.plugins.git.traits.BranchDiscoveryTrait']]],
      targets: [BRANCH_NAME, 'master'])
119
120
  }
}
121
122
123
124

/*
** Pipeline code.
*/
Zakaria Guennoune's avatar
Zakaria Guennoune committed
125
stage('Deliver sources') {
126
127
128
  node {
    dir('centreon-web') {
      checkout scm
129
130
131
132
      if (!isStableBuild()) {
        hasFrontendChanges = hasChanges(frontendFiles)
        hasBackendChanges = hasChanges(backendFiles)
      }
133
    }
134

135
    checkoutCentreonBuild()
136

137
    // git repository is stored for the Sonar analysis below.
138
139
    sh 'tar czf centreon-web-git.tar.gz centreon-web'
    stash name: 'git-sources', includes: 'centreon-web-git.tar.gz'
140

141
    // resuming process
142
    sh "./centreon-build/jobs/web/${serie}/mon-web-source.sh"
143
144
145
    source = readProperties file: 'source.properties'
    env.VERSION = "${source.VERSION}"
    env.RELEASE = "${source.RELEASE}"
146
    stash name: 'tar-sources', includes: "centreon-web-${env.VERSION}.tar.gz"
147
    stash name: 'cypress-node-modules', includes: "cypress-node-modules.tar.gz"
148
    stash name: 'vendor', includes: 'vendor.tar.gz'
149
    stash name: 'node_modules', includes: 'node_modules.tar.gz'
150
    stash name: 'api-doc', includes: 'centreon-api-v21.10.html'
151
152
153
154
155
    publishHTML([
      allowMissing: false,
      keepAll: true,
      reportDir: 'summary',
      reportFiles: 'index.html',
156
      reportName: 'Centreon Build Artifacts',
157
158
      reportTitles: ''
    ])
159
160
161
162
163
164
165

    // get api feature files
    apiFeatureFiles = sh(
      script: 'find centreon-web/tests/api/features -type f -name "*.feature" -printf "%P\n" | sort',
      returnStdout: true
    ).split()

166
167
168
169
170
171
    // get tests E2E feature files
    e2eFeatureFiles = sh(
      script: 'find centreon-web/tests/e2e/cypress/integration -type f -name "*.feature" -printf "%P\n" | sort',
      returnStdout: true
    ).split()

172
    //FIXME : reintegrate ldap features after fixing them
173
    featureFiles = sh(
174
      script: "rm centreon-web/features/Ldap*.feature && find centreon-web/features -type f -name '*.feature' | sed -e 's#centreon-web/features/##g' | sort",
175
176
      returnStdout: true
    ).split()
177
178
179
180
  }
}

try {
181
  stage('Unit tests // Sonar analysis // RPMs Packaging') {
182
183
184
185
186
    parallel 'frontend': {
      if (!hasFrontendChanges) {
        Utils.markStageSkippedForConditional('frontend')
      } else {
        node {
187
          checkoutCentreonBuild()
188
189
190
          unstash 'tar-sources'
          unstash 'node_modules'
          sh "./centreon-build/jobs/web/${serie}/mon-web-unittest.sh frontend"
191
192
193
194
195
196
197
198
          recordIssues(
            referenceJobName: "centreon-web/${env.REF_BRANCH}",
            enabledForFailure: true,
            failOnError: true,
            qualityGates: [[threshold: 1, type: 'NEW', unstable: false]],
            tool: esLint(id: 'eslint', name: 'eslint', pattern: 'codestyle-fe.xml'),
            trendChartType: 'NONE'
          )
199
          junit 'ut-fe.xml'
200
201
          stash name: 'ut-fe.xml', includes: 'ut-fe.xml'
          stash name: 'codestyle-fe.xml', includes: 'codestyle-fe.xml'
202
203
204
205
206
207
208
209
        }
      }
    },
    'backend': {
      if (!hasBackendChanges) {
        Utils.markStageSkippedForConditional('backend')
      } else {
        node {
210
          checkoutCentreonBuild()      
211
212
213
          unstash 'tar-sources'
          unstash 'vendor'
          sh "./centreon-build/jobs/web/${serie}/mon-web-unittest.sh backend"
214
215
216
217
          //Recording issues in Jenkins job
          recordIssues(
            referenceJobName: "centreon-web/${env.REF_BRANCH}",
            enabledForFailure: true,
218
            qualityGates: [[threshold: 100, type: 'DELTA', unstable: false]],
219
220
221
222
223
224
            tool: phpCodeSniffer(id: 'phpcs', name: 'phpcs', pattern: 'codestyle-be.xml'),
            trendChartType: 'NONE'
          )
          recordIssues(
            referenceJobName: "centreon-web/${env.REF_BRANCH}",
            enabledForFailure: true,
225
            qualityGates: [[threshold: 100, type: 'DELTA', unstable: false]],
226
227
228
            tool: phpStan(id: 'phpstan', name: 'phpstan', pattern: 'phpstan.xml'),
            trendChartType: 'NONE'
          )
229
          junit 'ut-be.xml'
230
231
232
233
          stash name: 'ut-be.xml', includes: 'ut-be.xml'
          stash name: 'coverage-be.xml', includes: 'coverage-be.xml'
          stash name: 'codestyle-be.xml', includes: 'codestyle-be.xml'
          stash name: 'phpstan.xml', includes: 'phpstan.xml'
234
235
236
237
        }
      }
    },
    'sonar': {
238
      node {
239
        // Run sonarQube analysis
240
        checkoutCentreonBuild()
241
        unstash 'git-sources'
242
243
        unstash 'vendor'
        unstash 'node_modules'
244
        sh 'rm -rf centreon-web && tar xzf centreon-web-git.tar.gz'
245
246
        sh 'rm -rf centreon-web/vendor && tar xzf vendor.tar.gz -C centreon-web'
        sh 'rm -rf centreon-web/node_modules && tar xzf node_modules.tar.gz -C centreon-web'
247
248
        withSonarQubeEnv('SonarQubeDev') {
          sh "./centreon-build/jobs/web/${serie}/mon-web-analysis.sh"
249
        }
250
        // sonarQube step to get qualityGate result
251
252
253
254
255
        timeout(time: 10, unit: 'MINUTES') {
          def qualityGate = waitForQualityGate()
          if (qualityGate.status != 'OK') {
            error "Pipeline aborted due to quality gate failure: ${qualityGate.status}"
          }
256
257
258
259
        }
        if ((currentBuild.result ?: 'SUCCESS') != 'SUCCESS') {
          error("Quality gate failure: ${qualityGate.status}.");
        }
260
      }
261
262
263
    },
    'rpm packaging centos7': {
      node {
264
        checkoutCentreonBuild()
265
266
267
268
269
270
        unstash 'tar-sources'
        sh "./centreon-build/jobs/web/${serie}/mon-web-package.sh centos7"
        archiveArtifacts artifacts: "rpms-centos7.tar.gz"
        stash name: "rpms-centos7", includes: 'output/noarch/*.rpm'
        sh 'rm -rf output'
      }
271
    }
272
273
274
275
276
277
278
279
280
281
//    'rpm packaging centos8': {
//      node {
//        checkoutCentreonBuild()           
//        unstash 'tar-sources'
//        sh "./centreon-build/jobs/web/${serie}/mon-web-package.sh centos8"
//        archiveArtifacts artifacts: "rpms-centos8.tar.gz"
//        stash name: "rpms-centos8", includes: 'output/noarch/*.rpm'
//        sh 'rm -rf output'
//      }
//    }
282
    if ((currentBuild.result ?: 'SUCCESS') != 'SUCCESS') {
283
      error('Unit tests // RPM Packaging Failure');
284
285
286
287
    }
  }


288
289
  stage('Violations to Github') {
    node {
290
      if (env.CHANGE_ID) { // pull request to comment with coding style issues
291
292
293
294
295
296
297
298
299
        if (hasBackendChanges) {
          unstash 'codestyle-be.xml'
          unstash 'phpstan.xml'
        }

        if (hasFrontendChanges) {
          unstash 'codestyle-fe.xml'
        }

300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
        ViolationsToGitHub([
          repositoryName: 'centreon',
          pullRequestId: env.CHANGE_ID,
          createSingleFileComments: true,
          commentOnlyChangedContent: true,
          commentOnlyChangedFiles: true,
          keepOldComments: false,
          commentTemplate: "**{{violation.severity}}**: {{violation.message}}",
          violationConfigs: [
            [parser: 'CHECKSTYLE', pattern: '.*/codestyle-be.xml$', reporter: 'Checkstyle'],
            [parser: 'CHECKSTYLE', pattern: '.*/phpstan.xml$', reporter: 'Checkstyle'],
            [parser: 'CHECKSTYLE', pattern: '.*/codestyle-fe.xml$', reporter: 'Checkstyle']
          ]
        ])
      }
315
    }
316
    if ((currentBuild.result ?: 'SUCCESS') != 'SUCCESS') {
317
      error("Reports stage failure");
318
    }
319
320
  }

321
322
323
324
325
326
  stage("$DELIVERY_STAGE") {
    node {
      checkoutCentreonBuild()    
      sh 'rm -rf output'
      unstash 'tar-sources'
      unstash 'api-doc'
327
      // unstash 'rpms-centos8'
328
329
      unstash 'rpms-centos7'
      sh "./centreon-build/jobs/web/${serie}/mon-web-delivery.sh"
330
    }
331
332
    if ((currentBuild.result ?: 'SUCCESS') != 'SUCCESS') {
      error('Delivery stage failure');
Zakaria Guennoune's avatar
Zakaria Guennoune committed
333
334
    }
  }
335
  
336
337
  stage("$DOCKER_STAGE") {
    def parallelSteps = [:]
338
339
    // def osBuilds = isStableBuild() ? ['centos7', 'centos8'] : ['centos7']
    def osBuilds = ['centos7']
340
341
342
343
344
345
    for (x in osBuilds) {
      def osBuild = x
      parallelSteps[osBuild] = {
        node {
          checkoutCentreonBuild()
          sh "./centreon-build/jobs/web/${serie}/mon-web-bundle.sh ${osBuild}"
Zakaria Guennoune's avatar
Zakaria Guennoune committed
346
347
348
        }
      }
    }
349
350
351
    parallel parallelSteps
    if ((currentBuild.result ?: 'SUCCESS') != 'SUCCESS') {
      error('Bundle stage failure.');
Zakaria Guennoune's avatar
Zakaria Guennoune committed
352
353
354
    }
  }

355
  stage('API // E2E // Lighthouse CI') {
356
357
    parallel 'API Tests': {
      if (hasBackendChanges) {
358
        def parallelSteps = [:]
359
        for (x in apiFeatureFiles) {
360
361
362
          def feature = x
          parallelSteps[feature] = {
            node {
Zakaria Guennoune's avatar
Zakaria Guennoune committed
363
              checkoutCentreonBuild()
364
365
366
              unstash 'tar-sources'
              unstash 'vendor'
              def acceptanceStatus = sh(
367
                script: "./centreon-build/jobs/web/${serie}/mon-web-api-integration-test.sh centos7 tests/api/features/${feature}",
368
369
370
371
372
                returnStatus: true
              )
              junit 'xunit-reports/**/*.xml'
              if ((currentBuild.result == 'UNSTABLE') || (acceptanceStatus != 0))
                currentBuild.result = 'FAILURE'
373
              archiveArtifacts allowEmptyArchive: true, artifacts: 'api-integration-test-logs/*.txt'
374
375
376
            }
          }
        }
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
        parallel parallelSteps
      }
    },
    'E2E tests': {
      def parallelSteps = [:]
      for (x in e2eFeatureFiles) {
        def feature = x
        parallelSteps[feature] = {
          node {
            checkoutCentreonBuild()
            unstash 'tar-sources'
            unstash 'cypress-node-modules'
            timeout(time: 10, unit: 'MINUTES') {
              def acceptanceStatus = sh(script: "./centreon-build/jobs/web/${serie}/mon-web-e2e-test.sh centos7 tests/e2e/cypress/integration/${feature}", returnStatus: true)
              junit 'centreon-web*/tests/e2e/cypress/results/reports/junit-report.xml'
              if ((currentBuild.result == 'UNSTABLE') || (acceptanceStatus != 0))
                currentBuild.result = 'FAILURE'
                archiveArtifacts allowEmptyArchive: true, artifacts: 'centreon-web*/tests/e2e/cypress/results/**/*.mp4, centreon-web*/tests/e2e/cypress/results/**/*.png'
            }
          }
        }
      }
      parallel parallelSteps
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
    },
    'Lighthouse CI': {
      if (hasFrontendChanges) {
        node {
          checkoutCentreonBuild();
          unstash 'tar-sources'
          sh "./centreon-build/jobs/web/${serie}/mon-web-lighthouse-ci.sh centos7"
          publishHTML([
            allowMissing: false,
            keepAll: true,
            reportDir: "$PROJECT-$VERSION/.lighthouseci",
            reportFiles: 'lighthouseci-index.html',
            reportName: 'Centreon Web Performances',
            reportTitles: ''
          ])
        }
      }
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
    }
  }
  
  stage('Acceptance tests') {
    if (hasBackendChanges || hasFrontendChanges) {
      def atparallelSteps = [:]
      for (x in featureFiles) {
        def feature = x
        atparallelSteps[feature] = {
          node {
            checkoutCentreonBuild()     
            unstash 'tar-sources'
            unstash 'vendor'
            def acceptanceStatus = sh(
              script: "./centreon-build/jobs/web/${serie}/mon-web-acceptance.sh centos7 features/${feature} ${acceptanceTag}",
              returnStatus: true
            )
            junit 'xunit-reports/**/*.xml'
            if ((currentBuild.result == 'UNSTABLE') || (acceptanceStatus != 0))
              currentBuild.result = 'FAILURE'
            archiveArtifacts allowEmptyArchive: true, artifacts: 'acceptance-logs/*.txt, acceptance-logs/*.png, acceptance-logs/*.flv'
          }
        }
440
441
442
443
      }
      parallel atparallelSteps
      if ((currentBuild.result ?: 'SUCCESS') != 'SUCCESS') {
        error('Critical tests stage failure');
444
      }
445
    }
446
  }
447
} catch(e) {
448
  if (isStableBuild()) {
449
450
451
452
453
    slackSend channel: "#monitoring-metrology",
        color: "#F30031",
        message: "*FAILURE*: `CENTREON WEB` <${env.BUILD_URL}|build #${env.BUILD_NUMBER}> on branch ${env.BRANCH_NAME}\n" +
            "*COMMIT*: <https://github.com/centreon/centreon/commit/${source.COMMIT}|here> by ${source.COMMITTER}\n" +
            "*INFO*: ${e}"
454
  }
455
456

  currentBuild.result = 'FAILURE'
457
}