files: // Process the github webhook and trigger tests or builds depending on the payload data
  
  node {
      stage "Check PR Action"
          // Parse json payload
          def test_key = "[test]"
          def slurper = new groovy.json.JsonSlurper()
          def jout = new groovy.json.JsonOutput()
          def webhook = slurper.parseText(payload)
          def trigger
          def pull_request
  
          // The following are the actions we should test:
          // "opened", "reopened", "synchronize"
          // We should build if the action is "closed" and the "merged" flag is true
          // The "edited" action is when a comment is edited, we don't care about that.
  
          // Additionally, to support re-testing via a comment made on the PR, we should test
          // on the following issue-only actions:
          // created, edited
          // These will requier some additional verification, as tests should only commence if
          // the comment was made on an open pull request and includes a certain phrase.
  
          // The following block determines the action (trigger) to take depending on the action field in the webhook
          def action = webhook.action
          echo "Webhook payload action: ${action}"
          if (action == "opened" || action == "reopened" || action == "synchronize") {
              echo "Pull request has been opened or modified, testing..."
              pull_request = webhook.pull_request
              trigger = "test"
          } else if (action == "closed" && webhook.pull_request.merged) {
              echo "Pull request has been merged, running builds..."
              pull_request = webhook.pull_request
              trigger = "build"
          } else if (action == "created" || action == "edited") {
              if (webhook.issue && webhook.issue.containsKey("pull_request")) {
                  body = webhook.comment.body
                  if (body.toLowerCase().contains(test_key)) {
                      echo "Pull request comment contains '${test_key}', running tests..."
                      // The webhook only contains the comment and issue details. We need to get the pull request
                      pr_json = get_pr(webhook.issue.pull_request.url)
                      pull_request = slurper.parseText(pr_json)
                      trigger = "test"
                  } else {
                      echo "Pull request comment does not contain '${test_key}'. Ignoring..."
                  }
              } else {
                  echo "Comment made on issue, not pull request. Ignoring..."
              }
          }
          echo "Trigger: ${trigger}"
  
          // Unset the pull request title and body in the pull request json and extract them into their own variables
          // This is done to avoid possible issues in parsing the json when unexpected characters are used in the title and body
          title = pull_request.title
          body = pull_request.body
          pull_request.title = ""
          pull_request.body = ""
  
          // Get sha and repo to submit pr update
          sha = pull_request.head.sha
          repo = pull_request.base.repo.full_name
  
          // Get the json string representation of the updated pull request data to pass to openshift
          pull_request_string = jout.toJson(pull_request)
  
          // These variables must be nullified as they are not serializable
          // See http://stackoverflow.com/questions/37864542/jenkins-pipeline-notserializableexception-groovy-json-internal-lazymap
          slurper = null
          jout = null
          webhook = null
          pull_request = null
  
      // From the determined trigger, initiate tests or builds
      if (trigger != "") {
          if (trigger == "test") {
              stage "Test Changes"
                  run_tests(pull_request_string, sha, repo)
          } else if (trigger == "build") {
              stage "Build RPMS"
                  echo "Starting Build"
                  // TODO this is not yet implemented
              stage "Deploy Updates"
                  echo "Deploying updated RPMs"
                  // TODO this is not yet implemented
          } else {
              echo "Trigger ${trigger} not recognized"
              currentBuild.result = 'FAILURE'
          }
      } else {
          echo "Webhook action, ${action}, does not justify running any jobs."
          currentBuild.result = 'SUCCESS'
      }
  }
  
  // Run pull request testing
  def run_tests(pull_request_string, sha, repo) {
      echo "Starting Tests"
      update_pr_status("pending", "Automated tests in progress", sha, repo)
      // TODO we could probably handle failures here a bit better
      // We should do a try/catch so that when the build fails, we update the PR with a failure statues.
      // If we do that, we need to make sure that the script only ever exits with a non-zero exit code when
      // a failure occurred and the PR was NOT updated with a failure status.
      try {
          openshiftBuild buildConfig: 'openshift-tools-test', env: [[ name: 'PULL_REQUEST', value: pull_request_string ], [ name: 'BUILD_URL', value: env.BUILD_URL ]], showBuildLogs: true
      } catch(Exception e) {
          println "Build failed in a way that likely didn't update PR status!"
          update_pr_status("failure", "Automated tests failed to run", sha, repo)
          currentBuild.result = 'FAILURE'
      }
  }
  
  // Update the status of a pull request
  def update_pr_status(state, text, sha, repo) {
      String token = new File('/openshift-ops-bot/token').text
      
      def target_url = env.BUILD_URL
      def urlString = "https://api.github.com/repos/" + repo + "/statuses/" + sha
      def url = new URL(urlString)
      def conn = url.openConnection()
      
      conn.setRequestMethod("POST")
      conn.setRequestProperty("Content-Type", "application/json")
      conn.setRequestProperty("Authorization", "token " + token)
      def data = '{"state": "' + state + '", "description": "' + text + '", "target_url": "' +
              target_url + '", "context": "jenkins-ci
  
  [... the rest is omitted ...]
files: jenkins/Jenkinsfile
files: // Process the github webhook and trigger tests or builds depending on the payload data
  
  node {
      stage "Check PR Action"
          // Parse json payload
          def test_key = "[test]"
          def slurper = new groovy.json.JsonSlurper()
          def webhook = slurper.parseText(payload)
          def trigger = ""
  
          // The following are the actions we should test:
          // "opened", "reopened", "synchronize"
          // We should build if the action is "closed" and the "merged" flag is true
          // The "edited" action is when a comment is edited, we don't care about that.
  
          // Additionally, to support re-testing via a comment made on the PR, we should test
          // on the following issue-only actions:
          // created, edited
          // These will requier some additional verification, as tests should only commence if
          // the comment was made on an open pull request and includes a certain phrase.
  
          def action = webhook.action
          echo "Webhook payload action: ${action}"
          if (action == "opened" || action == "reopened" || action == "synchronize") {
              echo "Pull request has been opened or modified, testing..."
              trigger = "test"
          } else if (action == "closed" && webhook.pull_request.merged) {
              echo "Pull request has been merged, running builds..."
              trigger = "build"
          } else if (action == "created" || action == "edited") {
              if (webhook.issue && webhook.issue.containsKey("pull_request")) {
                  body = webhook.comment.body
                  if (body.toLowerCase().contains(test_key)) {
                      echo "Pull request comment contains '${test_key}', running tests..."
                      trigger = "test"
                  } else {
                      echo "Pull request comment does not contain '${test_key}'. Ignoring..."
                  }
              } else {
                  echo "Comment made on issue, not pull request. Ignoring..."
              }
          }
          echo "Trigger: ${trigger}"
          // These variables must be nullified as they are not serializable
          // See http://stackoverflow.com/questions/37864542/jenkins-pipeline-notserializableexception-groovy-json-internal-lazymap
          slurper = null
          webhook = null
  
      if (trigger != "") {
          if (trigger == "test") {
              stage "Test Changes"
                  echo "Starting Tests"
                  openshiftBuild buildConfig: 'openshift-tools-test', env: [[ name: 'GITHUB_WEBHOOK_PAYLOAD', value: payload ], [ name: 'BUILD_URL', value: env.BUILD_URL ]], showBuildLogs: true
          } else if (trigger == "build") {
              stage "Build RPMS"
                  echo "Starting Build"
                  // TODO this is not yet implemented
              stage "Deploy Updates"
                  echo "Deploying updated RPMs"
                  // TODO this is not yet implemented
          } else {
              echo "Trigger ${trigger} not recognized"
              currentBuild.result = 'FAILURE'
          }
      } else {
          echo "Webhook action, ${action}, does not justify running any jobs."
          currentBuild.result = 'SUCCESS'
      }
  }
  
  
  [... the rest is omitted ...]
files: jenkins/Jenkinsfile
files: # OpenShift-Tools CI
  
  The files within this directory are used to set up automation around testing, building, and deploying changes to components in the openshift-tools repository.
  
  ### Using the CI as a developer
  Upon submitting a pull request, tests will automatically be started for the changes in the pull request as long as the user who opened the pull request is on the user or organization whitelist. There may be some delay between the tests starting and the pull request being updated as the docker build initialization can take some time. Once testing is completely, the pull request will be updated with the result. The last commit will be marked with success or failure and a link to the test output.
  
  To manually run tests for a pull request, a whitelisted user can comment the term `[test]` to initiate testing. Testing will also be initiated any time the pull request commits are updated.
  
  ### How it works
  When a pull request is submitted to the openshift-tools repository on github, a webhook starts a job on a persistent jenkins instance running in an openshift environment. The job is a simple jenkins pipeline using the `Jenkinsfile` in this directory. The pipeline determines the action to take based on the `action` field and some other details in the webhook. When a test is necessary, the jenkins pipeline starts a build on the openshift environment titled `openshift-tools-test` and outputs the build logs to the pipeline's logs.
  
  Tests will be run whenever a pull request is opened, reopened, or "synchronized" (a commit is added, subtracted, or amended). Tests can also be manually performed by commenting on the pull request with the term '[test]' with a whitelisted user.
  
  The `openshift-tools-test` build is defined in the `openshift-tools-pr-automation-template.json` template. The build mounts a secret containing the github bot user credentials, then starts a docker build using the Dockerfile `test/Dockerfile`. This build runs from the oso-host-monitoring container and clones the openshift-tools repository. Once the environment is set up, the build runs the `test/run_tests.py` script. This script merges in the changes defined in the github webhook payload and defines several environment variables for consumption by a suite of validators. Each `.py` or .sh` file in `test/validators` is run with these environment varibles.
  
  The script will then submit a comment to the pull request indiciating whether all of the validators passed or if one or more of them failed. The build will exist successfully if all validators pass. When the build completes, so does the jenkins pipeline. The build in jenkins is also marked as a success only if all validators pass.
  
  ### Requirements
  - An OpenShift instance running at least Openshift 3.2
  - Peristent storage configured and available to the user on Openshift
  - External access to apps running on the OpenShift instance (github has to be able to reach jenkins at a persistent address)
  - Access to configure github webhooks for the github repository
  
  ### Configuration
  1. In an openshift environment, deploy a persistent jenkins instance using the [jenkins-persistent template]( https://raw.githubusercontent.com/openshift/origin/master/examples/jenkins/jenkins-persistent-template.json). Pass the parameter `ENABLE_OAUTH=false` to disable OAUTH and set the default username and password to admin:password
  
  2. Deploy the builds and secrets in the openshift environment using the `openshift-tools-pr-automation-template.json` in this directory. A username and oauth token for a github user will be required. The user and org whitelists will need to be specified with at least one user or org that will be allowed to run tests.
  
  3. Add the openshift-ops-bot secret to the jenkins deployment to allow the jenkins pipeline access to the bots credentials. The pipeline needs this data to be mounted at /openshift-ops-bot to post the initial "tests pending" status update to pull requests:
  ```
  oc set volumes dc/jenkins --add -t secret --secret-name=openshift-ops-bot-secret -m /openshift-ops-bot
  ```
  
  4. Log into the jenkins instance using the default credentials. Navigate to 'Manage Jenkins' > 'Manage Users' and click the 'config' icon for the admin user. Change the admin users password to something much more secure.
  
  5. In jenkins, navigate to 'Manage Jenkins' > 'Configure Global Security'. Under 'Access Control' > 'Authorization', the radio button 'Matrix-based security' should be checked by default. In the matrix, select 'Read' access for the Anonymous group under 'Job'. Additionally, select 'Build' for the Anonymous group under 'Job'. This will allow github to post to jenkins via webhooks.
  
  6. Due to a [bug in jenkins](https://issues.jenkins-ci.org/browse/JENKINS-28466), it is necessary to navigate to 'Manage Jenkins' > 'Configure System' and hit 'Save'. If this is not done, certain environment variables, such as `BUILD_URL` will not be available to jenkins pipeline builds.
  
  7. In Jenkins, create a new jenkins pipeline job. Configure the following:
    1. Check the 'This project is parameterized' box and add a 'String Parameter' with the Name 'payload' (case-sensitive). Leave all other boxes empty.
    2. Under 'Build Triggers', check the 'Trigger builds remotely' checkbox and specify any string to use as the authorization token. This same token will be used later to configure the github webhook.
    3. Under 'Pipeline', you can either have jenkins pull the pipeline instructions Jenkinsfile from github, or you can copy and paste the Jenkinsfile contents from `jenkins/test/Jenkinsfile` into the text box. Grabbing the Jenkinsfile from Github will add 10-20 seconds to the build time. Select 'Pipeline script from SCM' as the pipeline definition. Choose 'Git' as the SCM and specify `https://github.com/openshift/openshift-tools` as the repository url. Leave the 'Branches to build' blank. For the 'Script path', set to 'jenkins/Jenkinsfile'
    4. Uncheck the
  
  [... the rest is omitted ...]
files: jenkins/README.md
files: # OpenShift-Tools CI
  
  The files within this directory are used to set up automation around testing, building, and deploying changes to components in the openshift-tools repository.
  
  ### Using the CI as a developer
  Upon submitting a pull request, tests will automatically be started for the changes in the pull request as long as the user who opened the pull request is on the user or organization whitelist. There may be some delay between the tests starting and the pull request being updated as the docker build initialization can take some time. Once testing is completely, the pull request will be updated with the result. The last commit will be marked with success or failure and a link to the test output.
  
  To manually run tests for a pull request, a whitelisted user can comment the term `[test]` to initiate testing. Testing will also be initiated any time the pull request commits are updated.
  
  ### How it works
  When a pull request is submitted to the openshift-tools repository on github, a webhook starts a job on a persistent jenkins instance running in an openshift environment. The job is a simple jenkins pipeline using the `Jenkinsfile` in this directory. The pipeline determines the action to take based on the `action` field and some other details in the webhook. When a test is necessary, the jenkins pipeline starts a build on the openshift environment titled `openshift-tools-test` and outputs the build logs to the pipeline's logs.
  
  Tests will be run whenever a pull request is opened, reopened, or "synchronized" (a commit is added, subtracted, or amended). Tests can also be manually performed by commenting on the pull request with the term '[test]' with a whitelisted user.
  
  The `openshift-tools-test` build is defined in the `openshift-tools-pr-automation-template.json` template. The build mounts a secret containing the github bot user credentials, then starts a docker build using the Dockerfile `test/Dockerfile`. This build runs from the oso-host-monitoring container and clones the openshift-tools repository. Once the environment is set up, the build runs the `test/run_tests.py` script. This script merges in the changes defined in the github webhook payload and defines several environment variables for consumption by a suite of validators. Each `.py` or .sh` file in `test/validators` is run with these environment varibles.
  
  The script will then submit a comment to the pull request indiciating whether all of the validators passed or if one or more of them failed. The build will exist successfully if all validators pass. When the build completes, so does the jenkins pipeline. The build in jenkins is also marked as a success only if all validators pass.
  
  ### Requirements
  - An OpenShift instance running at least Openshift 3.2
  - Peristent storage configured and available to the user on Openshift
  - External access to apps running on the OpenShift instance (github has to be able to reach jenkins at a persistent address)
  - Access to configure github webhooks for the github repository
  
  ### Configuration
  1. In an openshift environment, deploy a persistent jenkins instance using the [jenkins-persistent template]( https://raw.githubusercontent.com/openshift/origin/master/examples/jenkins/jenkins-persistent-template.json). Pass the parameter `ENABLE_OAUTH=false` to disable OAUTH and set the default username and password to admin:password
  
  2. Deploy the builds and secrets in the openshift environment using the `openshift-tools-pr-automation-template.json` in this directory. A username and oauth token for a github user will be required. The user and org whitelists will need to be specified with at least one user or org that will be allowed to run tests.
  
  3. Log into the jenkins instance using the default credentials. Navigate to 'Manage Jenkins' > 'Manage Users' and click the 'config' icon for the admin user. Change the admin users password to something much more secure.
  
  4. In jenkins, navigate to 'Manage Jenkins' > 'Configure Global Security'. Under 'Access Control' > 'Authorization', the radio button 'Matrix-based security' should be checked by default. In the matrix, select 'Read' access for the Anonymous group under 'Job'. Additionally, select 'Build' for the Anonymous group under 'Job'. This will allow github to post to jenkins via webhooks.
  
  5. Due to a [bug in jenkins](https://issues.jenkins-ci.org/browse/JENKINS-28466), it is necessary to navigate to 'Manage Jenkins' > 'Configure System' and hit 'Save'. If this is not done, certain environment variables, such as `BUILD_URL` will not be available to jenkins pipeline builds.
  
  6. In Jenkins, create a new jenkins pipeline job. Configure the following:
    1. Check the 'This project is parameterized' box and add a 'String Parameter' with the Name 'payload' (case-sensitive). Leave all other boxes empty.
    2. Under 'Build Triggers', check the 'Trigger builds remotely' checkbox and specify any string to use as the authorization token. This same token will be used later to configure the github webhook.
    3. Under 'Pipeline', you can either have jenkins pull the pipeline instructions Jenkinsfile from github, or you can copy and paste the Jenkinsfile contents from `jenkins/test/Jenkinsfile` into the text box. Grabbing the Jenkinsfile from Github will add 10-20 seconds to the build time. Select 'Pipeline script from SCM' as the pipeline definition. Choose 'Git' as the SCM and specify `https://github.com/openshift/openshift-tools` as the repository url. Leave the 'Branches to build' blank. For the 'Script path', set to 'jenkins/Jenkinsfile'
    4. Save the job
      
  7. In github, navigate to the settings for openshift-tools with administrator permissions. Under webhooks, create a new webhook and configure the following:
    1. The Payload URL will be the url of the jenkins build trigger configured earlier. Here is an example where 'someuniquestring' is specified as the build trigger token: `https://jenkins-exampleproject.example.com/job/job_name/buildWithParameters?token=
  
  [... the rest is omitted ...]
files: jenkins/README.md
files: """ Run all tests for openshift-tools repository """
  # This script expects a few environment variables to be defined:
  #    PULL_REQUEST - JSON represntation of the pull request to be tested
  #    PR_TITLE - Title of the pull request, extracted from pull request json for predictable json parsing
  #    PR_BODY - BODY of the pull request, extracted from pull request json for predictable json parsing
  #
  # The data expected in PULL_REQUEST is defined in the github api here:
  #    https://developer.github.com/v3/pulls/#get-a-single-pull-request
  # The same data is provided in the webhook, which is defined here:
  #    https://developer.github.com/v3/activity/events/types/#pullrequestevent
  #
  # The script will parse the provided pull request JSON and define a list of environment variables for
  # consumption by the validation scripts. Then, each *.py file in ./validators/ (minus specified exclusions)
  # will be run. The list of variables defined is below:
  #  Github stuff
  #    PRV_TITLE         Title of the pull request
  #    PRV_BODY          Description of the pull request
  #    PRV_PULL_ID       ID of the pull request
  #    PRV_PULL_URL      URL of the pull request
  #
  #  Base info
  #    PRV_BASE_SHA      SHA of the target being merged into
  #    PRV_BASE_REF      ref (usually branch name) of the base
  #    PRV_BASE_LABEL    Base label
  #    PRV_BASE_NAME     Full name of the base 'namespace/reponame'
  #
  #  Remote (or "head") info
  #    PRV_REMOTE_SHA    SHA of the branch being merged
  #    PRV_REMOTE_REF    ref (usually branch name) of the remote
  #    PRV_REMOTE_LABEL  Remote label
  #    PRV_REMOTE_NAME   Full name of the remote 'namespace/reponame'
  #    PRV_CURRENT_SHA   The SHA of the merge commit
  #
  #  Other info
  #    PRV_CHANGED_FILES List of files changed in the pull request
  #    PRV_COMMITS       List of commits in the pull request
  #
  
  # TODO:
  # - Handle failures better. Just exiting is not a good option, as it will likely leave the PR
  #    commit status in pending forever. We might be able to better handle this in the webhook now
  
  import os
  import json
  import subprocess
  import sys
  import fnmatch
  
  import github_helpers
  
  EXCLUDES = [
      "common.py",
      ".pylintrc"
  ]
  
  # The path set up in the Dockerfile
  WORK_DIR = "/validator/"
  # The absolute path to openshift-tools repo
  OPENSHIFT_TOOLS_PATH = WORK_DIR + "openshift-tools/"
  # The absolute path to the testing validator scripts
  VALIDATOR_PATH = OPENSHIFT_TOOLS_PATH + "jenkins/test/validators/"
  # Script location of unit tests
  UNIT_TEST_SCRIPT = OPENSHIFT_TOOLS_PATH + "jenkins/test/run_unit_tests.sh"
  # The absolute path to the ops-rpm repo
  OPS_RPM_PATH = WORK_DIR + "ops-rpm/"
  
  # The string to accept in PR comments to initiate testing by a whitelisted user
  TEST_STRING = "[test]"
  
  def run_cli_cmd(cmd, exit_on_fail=True, log_cmd=True):
      '''Run a command and return its output'''
      # Don't log the command if log_cmd=False to avoid exposing secrets in commands
      if log_cmd:
          print "> " + " ".join(cmd)
      proc = subprocess.Popen(cmd, bufsize=-1, stderr=subprocess.PIPE, stdout=subprocess.PIPE,
                              shell=False)
      stdout, stderr = proc.communicate()
      if proc.returncode != 0:
          # Don't log the command if log_cmd=False to avoid exposing secrets in commands
          if log_cmd:
              print "Unable to run " + " ".join(cmd) + " due to error: " + stderr
          else:
              print "Error running system command: " + stderr
          if exit_on_fail:
              sys.exit(proc.returncode)
          else:
              return False, stdout
      else:
          return True, stdout
  
  def assign_env(pull_request):
      '''Assign environment variables based on pull_request json data and other env variables'''
      # Github environment variables
      # Note that the PR title and body are special, as unexpected characters can cause issues
      # when parsing json. The jenkins pipeline should remove these from the pull request json
      # and set them in their own environment variables PR_TITLE and PR_BODY.
      # Additionally, encode to utf8 to support unicode characters in python 2.x
      os.environ["PRV_TITLE"] = os.getenv("PR_TITLE", "")#.encode('utf8')
      os.environ["PRV_BODY"] = os.getenv("PR_BODY", "")#.encode('utf8')
      os.environ["PRV_PULL_ID"] = pull_request["number"]
      os.environ["PRV_URL"] = pull_request["url"]
  
      # Base environment variables
      base = pull_request["base"]
      os.environ["PRV_BASE_SHA"] = base["sha"]
      os.environ["PRV_BASE_REF"] = base["ref"]
      os.environ["PRV_BASE_LABEL"] = base["label"]
      os.environ["PRV_BASE_NAME"] = base["repo"]["full_name"]
  
      # Remote environment variables
      head = pull_request["head"]
      os.environ["PRV_REMOTE_SHA"] = head["sha"]
      os.environ["PRV_REMOTE_REF"] = head["ref"]
      os.environ["PRV_REMOTE_LABEL"] = head["label"]
      os.environ["PRV_REMOTE_NAME"] = head["repo"]["full_name"]
  
      # Other helpful environment variables
      baserepo = base["repo
  
  [... the rest is omitted ...]
files: jenkins/test/run_tests.py
files: """ Run all tests for openshift-tools repository """
  # This script expects a single environment variable to be defined with a myriad of json data:
  #    GITHUB_WEBHOOK_PAYLOAD
  #
  # The data expected from this payload is that generated by the pull reqeust edit webhook,
  # defined here:
  #    https://developer.github.com/v3/activity/events/types/#pullrequestevent
  #
  # The script will parse the JSON and define a list of environment variables for consumption by
  # the validation scripts. Then, each *.py file in ./validators/ (minus specified exclusions)
  # will be run. The list of variables defined is below:
  #  Github stuff
  #    PRV_TITLE         Title of the pull request
  #    PRV_BODY          Description of the pull request
  #    PRV_PULL_ID       ID of the pull request
  #    PRV_PULL_URL      URL of the pull request
  #
  #  Base info
  #    PRV_BASE_SHA      SHA of the target being merged into
  #    PRV_BASE_REF      ref (usually branch name) of the base
  #    PRV_BASE_LABEL    Base label
  #    PRV_BASE_NAME     Full name of the base 'namespace/reponame'
  #
  #  Remote (or "head") info
  #    PRV_REMOTE_SHA    SHA of the branch being merged
  #    PRV_REMOTE_REF    ref (usually branch name) of the remote
  #    PRV_REMOTE_LABEL  Remote label
  #    PRV_REMOTE_NAME   Full name of the remote 'namespace/reponame'
  #    PRV_CURRENT_SHA   The SHA of the merge commit
  #
  #  Other info
  #    PRV_CHANGED_FILES List of files changed in the pull request
  #    PRV_COMMITS       List of commits in the pull request
  #
  
  # TODO:
  # - Handle failures better. Just exiting is not a good option, as it will likely leave the PR
  #    commit status in pending forever.
  
  import os
  import json
  import subprocess
  import sys
  import fnmatch
  import requests
  
  import github_helpers
  
  EXCLUDES = [
      "common.py",
      ".pylintrc"
  ]
  
  # The path set up in the Dockerfile
  WORK_DIR = "/validator/"
  # The absolute path to openshift-tools repo
  OPENSHIFT_TOOLS_PATH = WORK_DIR + "openshift-tools/"
  # The absolute path to the testing validator scripts
  VALIDATOR_PATH = OPENSHIFT_TOOLS_PATH + "jenkins/test/validators/"
  # Script location of unit tests
  UNIT_TEST_SCRIPT = OPENSHIFT_TOOLS_PATH + "jenkins/test/run_unit_tests.sh"
  # The absolute path to the ops-rpm repo
  OPS_RPM_PATH = WORK_DIR + "ops-rpm/"
  
  # The string to accept in PR comments to initiate testing by a whitelisted user
  TEST_STRING = "[test]"
  
  def run_cli_cmd(cmd, exit_on_fail=True, log_cmd=True):
      '''Run a command and return its output'''
      # Don't log the command if log_cmd=False to avoid exposing secrets in commands
      if log_cmd:
          print "> " + " ".join(cmd)
      proc = subprocess.Popen(cmd, bufsize=-1, stderr=subprocess.PIPE, stdout=subprocess.PIPE,
                              shell=False)
      stdout, stderr = proc.communicate()
      if proc.returncode != 0:
          # Don't log the command if log_cmd=False to avoid exposing secrets in commands
          if log_cmd:
              print "Unable to run " + " ".join(cmd) + " due to error: " + stderr
          else:
              print "Error running system command: " + stderr
          if exit_on_fail:
              sys.exit(proc.returncode)
          else:
              return False, stdout
      else:
          return True, stdout
  
  def assign_env(pull_request):
      '''Assign environment variables base don github webhook payload json data'''
      # Github environment variables
      # encode to utf8 to support unicode characters in python 2.x
      os.environ["PRV_TITLE"] = pull_request["title"].encode('utf8')
      # Handle pull request body in case it is empty
      # Also encode to utf8 to support unicde characters in python 2.x
      body = (pull_request["body"].encode('utf8') if pull_request["body"] is not None else "")
      os.environ["PRV_BODY"] = body
      os.environ["PRV_PULL_ID"] = pull_request["number"]
      os.environ["PRV_URL"] = pull_request["url"]
  
      # Base environment variables
      base = pull_request["base"]
      os.environ["PRV_BASE_SHA"] = base["sha"]
      os.environ["PRV_BASE_REF"] = base["ref"]
      os.environ["PRV_BASE_LABEL"] = base["label"]
      os.environ["PRV_BASE_NAME"] = base["repo"]["full_name"]
  
      # Remote environment variables
      head = pull_request["head"]
      os.environ["PRV_REMOTE_SHA"] = head["sha"]
      os.environ["PRV_REMOTE_REF"] = head["ref"]
      os.environ["PRV_REMOTE_LABEL"] = head["label"]
      os.environ["PRV_REMOTE_NAME"] = head["repo"]["full_name"]
  
      # Other helpful environment variables
      baserepo = base["repo"]["full_name"]
      prnum = pull_request["number"]
  
      # List of changed files
      changed_files = github_helpers.get_changed_files(baserepo, prnum)
      os.environ["PRV_CHANGED_FILES"] = ",".join(changed_files)
  
      # List of commits
      commits = github_helpers.get_commits(baserepo, prnum)
      os.environ["PRV_COMMITS"] = ",".join(commits)
  
  def merge_changes(pull_request):
      """ Merge
  
  [... the rest is omitted ...]
files: jenkins/test/run_tests.py