Home > Mobile >  Jenkinsfile with Dockerfile: How to call a method before the Docker image is built?
Jenkinsfile with Dockerfile: How to call a method before the Docker image is built?

Time:10-24

I have a Jenkinsfile that looks something like the following:

void setBuildStatus(String message, String state) {
  step([
      $class: "GitHubCommitStatusSetter",
      reposSource: [$class: "ManuallyEnteredRepositorySource", url: "https://github.com/my-user/my-repo"],
      contextSource: [$class: "ManuallyEnteredCommitContextSource", context: "ci/jenkins/build-status"],
      errorHandlers: [[$class: "ChangingBuildStatusErrorHandler", result: "UNSTABLE"]],
      statusResultSource: [ $class: "ConditionalStatusResultSource", results: [[$class: "AnyBuildResult", message: message, state: state]] ]
  ]);
}

pipeline {
  environment {
    DATABASE_URL = credentials('database-url')
  }
  agent {
    dockerfile {
      args '-e DATABASE_URL=$DATABASE_URL'
    }
  }
  stages {
    stage('test') {
      steps {
        setBuildStatus("Running rspec", "PENDING");
        sh 'bundle exec rspec'
      }   
    }
  }
  post {
    success {
        setBuildStatus("Build succeeded", "SUCCESS");
    }
    failure {
        setBuildStatus("Build failed", "FAILURE");
    }
  }
}

... and a Dockerfile that looks like this:

FROM ruby:2.6.7

WORKDIR /usr/src/app

# bundle install
RUN gem install bundler:2.2.26
COPY Gemfile Gemfile.lock ./
RUN bundle install --jobs 5

Which is pretty standard for a Ruby app.

This all works as expected: it sets the GitHub status to pending once the specs start to run and to Success or Failure when they're done. But if I change a gem it rebuilds the Docker image, which takes about 3:30 minutes on my Jenkins machine. During this time there's no update to GitHub's status, on GitHub it looks like nothing is happening.

Can I somehow call setBuildStatus("Starting build", "PENDING"); immediately when I enter the pipeline?

CodePudding user response:

You can probably do something like the one below. Simply create two stages, the first one will run on Any agent and just set the status, and the next stage will do the actual ruby-build.

pipeline {
  agent any
  environment {
    DATABASE_URL = credentials('database-url')
  }
  
  stages {
    stage('Set State') {
      steps {
        setBuildStatus("Build started", "PENDING");
      }   
    }
    stage('test') {
      agent {
        dockerfile {
          args '-e DATABASE_URL=$DATABASE_URL'
        }
      }
      steps {
        sh 'bundle exec rspec'
      }   
    }
  }
  post {
    success {
        setBuildStatus("Build succeeded", "SUCCESS");
    }
    failure {
        setBuildStatus("Build failed", "FAILURE");
    }
  }
}
  • Related