github.com/verrazzano/verrazzano@v1.7.1/ci/cron/Jenkinsfile (about)

     1  // Copyright (c) 2023, Oracle and/or its affiliates.
     2  // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
     3  
     4  import groovy.transform.Field
     5  
     6  @Field
     7  def GIT_COMMIT_TO_USE = ""
     8  @Field
     9  def LAST_CLEAN_PERIODIC_COMMIT = ""
    10  @Field
    11  def LAST_PERIODIC_RUN_COMMIT = ""
    12  @Field
    13  def VERRAZZANO_DEV_VERSION = ""
    14  @Field
    15  def periodicsUpToDate              = false // If true, indicates that the periodics already passed at the latest commit
    16  @Field
    17  def periodicsUpToDateFailed        = false // If true, indicates that the periodics already ran and failed at the latest commit
    18  
    19  // Non Fields
    20  def branchSpecificSchedule = getCronSchedule()
    21  
    22  pipeline {
    23      options {
    24          timeout(time: 12, unit: 'HOURS')
    25          skipDefaultCheckout true
    26          disableConcurrentBuilds()
    27          timestamps ()
    28      }
    29  
    30      agent {
    31         docker {
    32              image "${RUNNER_DOCKER_IMAGE}"
    33              args "${RUNNER_DOCKER_ARGS}"
    34              registryUrl "${RUNNER_DOCKER_REGISTRY_URL}"
    35              registryCredentialsId 'ocir-pull-and-push-account'
    36              label "pipeline-job-large"
    37          }
    38      }
    39  
    40      triggers {
    41          cron(branchSpecificSchedule)
    42      }
    43  
    44      parameters {
    45              booleanParam (description: 'Skip test execution (for debugging)', name: 'DRY_RUN', defaultValue: false)
    46          }
    47  
    48      environment {
    49          OCI_CLI_AUTH = "instance_principal"
    50          OCI_OS_NAMESPACE = credentials('oci-os-namespace')
    51  
    52          CLEAN_BRANCH_NAME = "${env.BRANCH_NAME.replace("/", "%2F")}"
    53  
    54          STABLE_COMMIT_OS_LOCATION = "${CLEAN_BRANCH_NAME}/last-stable-commit.txt"
    55          LAST_PERIODIC_OS_LOCATION = "${CLEAN_BRANCH_NAME}/last-periodic-run-commit.txt"
    56          CLEAN_PERIODIC_OS_LOCATION = "${CLEAN_BRANCH_NAME}-last-clean-periodic-test/verrazzano_periodic-commit.txt"
    57  
    58          STABLE_COMMIT_LOCATION = "${WORKSPACE}/last-stable-commit.txt"
    59          LAST_PERIODIC_LOCATION = "${WORKSPACE}/last-periodic-run-commit.txt"
    60          CLEAN_PERIODIC_LOCATION = "${WORKSPACE}/last-clean-periodic-commit.txt"
    61  
    62          OCI_OS_REGION = "us-phoenix-1"
    63      }
    64  
    65      stages {
    66          stage('Check last clean periodic') {
    67              steps {
    68                  sh """
    69                      oci --region us-phoenix-1 os object get --namespace ${OCI_OS_NAMESPACE} -bn ${OCI_OS_BUCKET} --name ${STABLE_COMMIT_OS_LOCATION} --file ${STABLE_COMMIT_LOCATION}
    70                  """
    71  
    72                  script {
    73                      // Check if there is already a clean periodic run at this commit already, and set the display name if
    74                      // it already is tested, or if doing a special run type (dry run, etc...)
    75                      preliminaryChecks()
    76                  }
    77              }
    78          }
    79  
    80          stage('Clean workspace and checkout') {
    81              when {
    82                  allOf {
    83                      expression { return runPipeline() }
    84                  }
    85              }
    86                  steps {
    87                      script {
    88                          cleanWorkspaceAndCheckout()
    89                      }
    90                  }
    91          }
    92  
    93          stage ('Run Periodic Test Suite') {
    94              when {
    95                  allOf {
    96                      expression { return runPipeline() }
    97                  }
    98              }
    99  
   100              steps {
   101                  script {
   102                      echo("Running periodics with commit ${GIT_COMMIT_TO_USE}")
   103                      build job: "/verrazzano-periodic-triggered-tests/${CLEAN_BRANCH_NAME}", wait: true
   104                  }
   105              }
   106          }
   107      }
   108  }
   109  
   110  def cleanWorkspaceAndCheckout() {
   111      scmCheckout()
   112      def props = readProperties file: '.verrazzano-development-version'
   113      VERRAZZANO_DEV_VERSION = props['verrazzano-development-version']
   114      TIMESTAMP = sh(returnStdout: true, script: "date +%Y%m%d%H%M%S").trim()
   115      SHORT_COMMIT_HASH = sh(returnStdout: true, script: "git rev-parse --short=8 HEAD").trim()
   116      // update the description with some meaningful info
   117      currentBuild.description = SHORT_COMMIT_HASH + " : " + env.GIT_COMMIT
   118  }
   119  
   120  // Preliminary job checks and display updates
   121  def preliminaryChecks() {
   122      // Get the last stable commit ID to pass the triggered tests
   123      def stableCommitProps = readProperties file: "${STABLE_COMMIT_LOCATION}"
   124      GIT_COMMIT_TO_USE = stableCommitProps['git-commit']
   125      echo "Last stable commit: ${GIT_COMMIT_TO_USE}"
   126  
   127      LAST_CLEAN_PERIODIC_COMMIT=getLastPeriodicRunCommit()
   128      echo "Last clean periodics commit: ${LAST_CLEAN_PERIODIC_COMMIT}"
   129  
   130      if (LAST_CLEAN_PERIODIC_COMMIT == GIT_COMMIT_TO_USE) {
   131          // If we had a clean periodic run and the commit hasn't changed
   132          periodicsUpToDate = true
   133      } else {
   134          // Check if we are still at the same commit previously run (if so we know it wasn't clean and it failed in some way)
   135          LAST_PERIODIC_RUN_COMMIT=getLastPeriodicRunCommit()
   136          if (LAST_PERIODIC_RUN_COMMIT != null && LAST_PERIODIC_RUN_COMMIT == GIT_COMMIT_TO_USE) {
   137              periodicsUpToDateFailed = true
   138          }
   139      }
   140  }
   141  
   142  // Returns the last run commit for the periodics, or null if the commit file does not exist yet.
   143  // - fails the pipeline if any error other than 404 is returned by the OCI CLI
   144  def getLastPeriodicRunCommit() {
   145      lastPeriodicCommitCommandOutput = sh (
   146          label: "Get last clean periodic commit ID",
   147          script: "oci --region us-phoenix-1 os object get --namespace ${OCI_OS_NAMESPACE} -bn ${OCI_OS_BUCKET} --name ${LAST_PERIODIC_OS_LOCATION} --file ${LAST_PERIODIC_LOCATION} 2>&1 || true",
   148          returnStdout: true
   149          ).trim()
   150      echo "command out: ${lastPeriodicCommitCommandOutput}"
   151      if (lastPeriodicCommitCommandOutput.length() > 0) {
   152          // We can get warning messages here as well even when the command succeeded, so be more precise on the checking
   153          if (lastPeriodicCommitCommandOutput =~ /(.*)status(.*)\d{1,4}(.*)/) {
   154              // If we think we had a status: NNN, we ignore 404 and fail for others
   155              assert lastPeriodicCommitCommandOutput =~ /(.*)status(.*)404(.*)/ : "An unexpected error occurred getting last periodic commit from ObjectStore: ${lastPeriodicCommitCommandOutput}"
   156          } else {
   157              // If we got here, we have some message that may or may not be an error. If we don't see the file, we assume it was an error
   158              sh """
   159                  if [ ! -f ${LAST_PERIODIC_LOCATION} ]; then
   160                      echo "An unexpected error occurred getting last periodic run commit from ObjectStore: ${lastPeriodicCommitCommandOutput}"
   161                      exit 1
   162                  fi
   163              """
   164          }
   165      }
   166      // Get the commit ID for the last known clean pass of the Periodic tests
   167      def lastPeriodicsCommitProps = readProperties file: "${LAST_PERIODIC_LOCATION}"
   168      return lastPeriodicsCommitProps['git-commit']
   169  }
   170  
   171  def scmCheckout() {
   172      echo "${NODE_LABELS}"
   173      echo "Specific GIT commit was not specified, use current head"
   174      def scmInfo = checkout([
   175          $class: 'GitSCM',
   176          branches: [[name: env.BRANCH_NAME]],
   177          doGenerateSubmoduleConfigurations: false,
   178          extensions: [],
   179          submoduleCfg: [],
   180          userRemoteConfigs: [[url: env.SCM_VERRAZZANO_GIT_URL]]])
   181      env.GIT_COMMIT = scmInfo.GIT_COMMIT
   182      env.GIT_BRANCH = scmInfo.GIT_BRANCH
   183      echo "SCM checkout of ${env.GIT_BRANCH} at ${env.GIT_COMMIT}"
   184  }
   185  
   186  // Checks all the conditions gating test execution and collates the result
   187  def runPipeline() {
   188    return ! periodicsUpToDate && ! periodicsUpToDateFailed && ! params.DRY_RUN
   189  }
   190  
   191  def getCronSchedule() {
   192      if (env.BRANCH_NAME.equals("master")) {
   193          // scheduled for every 6 hours
   194          return "H */6 * * *"
   195      } else if (env.BRANCH_NAME.startsWith("release-")) {
   196          return "H */6 * * *"
   197      }
   198      return ""
   199  }