Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-39482

GitHub commit status not working with GitHubCommitStatusSetter on first build of branch in multi-branch pipeline

    • Icon: Bug Bug
    • Resolution: Won't Fix
    • Icon: Major Major
    • github-plugin
    • None
    • Jenkins 2.19.2, GitHub plugin 1.22.3

      In a multi-branch pipeline, I am using the GitHubCommitStatusSetter step in several places to set custom commit status. These calls do not work the first time the branch is built by Jenkins. Subsequent builds work correctly.

      Jenkinsfile

      step([$class: 'GitHubCommitStatusSetter', contextSource: [$class: 'ManuallyEnteredCommitContextSource', context: 'pylint'], statusResultSource: [$class: 'ConditionalStatusResultSource', results: [[$class: 'AnyBuildResult', state: 'SUCCESS', message: "Succeeded"]]]])
      

      First build log – failing:

      [pylint] [Set GitHub commit status (universal)] SUCCESS on repos [] (sha:c119d83) with context:pylint
      

      All future builds – working:

      [pylint] [Set GitHub commit status (universal)] SUCCESS on repos [GHRepository@68adaba[description=RepoDescription,homepage=https://filtered,name=reponame,license=<null>,fork=false,watchers=1,forks=0,size=23027,milestones={},language=Python,commits={},source=<null>,parent=<null>,url=https://filtered,id=115]] (sha:c119d83) with context:pylint
      [pylint] Setting commit status on GitHub for https://filtered/commit/c119d83bbab1635708c95e800a6eb4052d8a787c
      

          [JENKINS-39482] GitHub commit status not working with GitHubCommitStatusSetter on first build of branch in multi-branch pipeline

          Tony Arous added a comment -

          Unfortunately, this doesn't work for on-premise GitHub Enterprise.

          Tony Arous added a comment - Unfortunately, this doesn't work for on-premise GitHub Enterprise.

          xianjun zhu added a comment -

          Hey Tony,
          We are using Github Enterprise, I can verify it works for Github Enterprise. In my example above, I replace our GHE repo link with a github.com link.

          xianjun zhu added a comment - Hey Tony, We are using Github Enterprise, I can verify it works for Github Enterprise. In my example above, I replace our GHE repo link with a github.com link.

          Peter Springsteen added a comment - - edited

          I am seeing the same general behavior as Tony's first run...for every run.

          Tested on:

          • Jenkins: 2.19.1
          • – github-plugin: 1.26.0
          • Jenkins: 2.32.2
          • – github-plugin: 1.26.0
            Using:
          • Public & Enterprise GitHub
          • Webhooks, pull requests, manual builds

          Since the default activity is to resolve any repos, I checked to see if it was picking up on any repos, which it was:
          Picks up on multiple repos because of Global Shared Pipeline Library getting pulled from GitHub
          Jenkins Log

          Feb 15, 2017 10:51:18 PM FINEST org.jenkinsci.plugins.github.status.sources.AnyDefinedRepositorySource repos
          repositories source=repo-name-contributor value=[GitHubRepositoryName[host=github.com,username=psprings,repository=jenkins-pipeline-helpers-lib], GitHubRepositoryName[host={{ENTERPRISEGITURL}},username={{ENTERPRISEGITORG}},repository={{ENTERPRISEGITREPO}}]]
          

          But the output did not reflect any repos:
          Pipeline Console Text

          [Pipeline] step
          [Set GitHub commit status (universal)] PENDING on repos [] (sha:6f85cd0) with context:ci/jenkins/foo
          

          So I tried manually setting the repo url as per xianju's suggestion, and got the same result (although overriding the sha worked just fine).
          Jenkinsfile snippet

          step([
                  $class: "GitHubCommitStatusSetter",
                  commitShaSource: [$class: "ManuallyEnteredShaSource", sha: gitCommit],
                  //reposSource: [$class: "AnyDefinedRepositorySource"],
                  reposSource: [$class: "ManuallyEnteredRepositorySource", url: "https://enterprisegithuburl.com/Org/Repo" ],
                  contextSource: [$class: "ManuallyEnteredCommitContextSource", context: "ci/jenkins/foo" ],
                  errorHandlers: [[$class: "ChangingBuildStatusErrorHandler", result: "UNSTABLE"]],
                  statusResultSource: [ $class: "ConditionalStatusResultSource", results: [
                      [$class: "AnyBuildResult", message: message, state: state]] ]
                ]);
          

          A status message is set by the GitHub Branch Source plugin if the build passes/fails, but would like more granular commit statuses.

          Any thoughts/suggestions?

          Peter Springsteen added a comment - - edited I am seeing the same general behavior as Tony's first run...for every run. Tested on: Jenkins: 2.19.1 – github-plugin: 1.26.0 Jenkins: 2.32.2 – github-plugin: 1.26.0 Using: Public & Enterprise GitHub Webhooks, pull requests, manual builds Since the default activity is to resolve any repos, I checked to see if it was picking up on any repos, which it was: Picks up on multiple repos because of Global Shared Pipeline Library getting pulled from GitHub Jenkins Log Feb 15, 2017 10:51:18 PM FINEST org.jenkinsci.plugins.github.status.sources.AnyDefinedRepositorySource repos repositories source=repo-name-contributor value=[GitHubRepositoryName[host=github.com,username=psprings,repository=jenkins-pipeline-helpers-lib], GitHubRepositoryName[host={{ENTERPRISEGITURL}},username={{ENTERPRISEGITORG}},repository={{ENTERPRISEGITREPO}}]] But the output did not reflect any repos: Pipeline Console Text [Pipeline] step [Set GitHub commit status (universal)] PENDING on repos [] (sha:6f85cd0) with context:ci/jenkins/foo So I tried manually setting the repo url as per xianju's suggestion, and got the same result (although overriding the sha worked just fine). Jenkinsfile snippet step([ $class: "GitHubCommitStatusSetter" , commitShaSource: [$class: "ManuallyEnteredShaSource" , sha: gitCommit], //reposSource: [$class: "AnyDefinedRepositorySource" ], reposSource: [$class: "ManuallyEnteredRepositorySource" , url: "https: //enterprisegithuburl.com/Org/Repo" ], contextSource: [$class: "ManuallyEnteredCommitContextSource" , context: "ci/jenkins/foo" ], errorHandlers: [[$class: "ChangingBuildStatusErrorHandler" , result: "UNSTABLE" ]], statusResultSource: [ $class: "ConditionalStatusResultSource" , results: [ [$class: "AnyBuildResult" , message: message, state: state]] ] ]); A status message is set by the GitHub Branch Source plugin if the build passes/fails, but would like more granular commit statuses. Any thoughts/suggestions?

          xianjun zhu added a comment -

          @peter Not sure if I understand your granular commit status correct, in our build, we do set different status to github PR commit based on the progress of CI build.

          So following my previous example, we wrapped each workflow step with `buildStep` function below, it will set the commit in PR as `PENDING` before each step, set it to `FAILURE` if fails. If the whole build is successful, then set the status to `SUCCESS`

          node('a_node') {
              buildStep('Checkout'){
                  checkout scm
              }
          
              buildStep('step 1'){
                      sh '''echo "step 1"
                      '''
              }
          
              setBuildStatus("Build complete", "SUCCESS");
          }
          
          void buildStep(String message, Closure closure) {
            stage(message);
            try {
              setBuildStatus(message, "PENDING");
              closure();
            } catch (Exception e) {
              setBuildStatus(message, "FAILURE");
            }
          }
          
          void setBuildStatus(String message, String state) {
            step([
                $class: "GitHubCommitStatusSetter",
                reposSource: [$class: "ManuallyEnteredRepositorySource", url: "https://github.com/my-org/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]] ]
            ]);
          }
          

          xianjun zhu added a comment - @peter Not sure if I understand your granular commit status correct, in our build, we do set different status to github PR commit based on the progress of CI build. So following my previous example, we wrapped each workflow step with `buildStep` function below, it will set the commit in PR as `PENDING` before each step, set it to `FAILURE` if fails. If the whole build is successful, then set the status to `SUCCESS` node( 'a_node' ) { buildStep( 'Checkout' ){ checkout scm } buildStep( 'step 1' ){ sh '''echo "step 1" ''' } setBuildStatus( "Build complete" , "SUCCESS" ); } void buildStep( String message, Closure closure) { stage(message); try { setBuildStatus(message, "PENDING" ); closure(); } catch (Exception e) { setBuildStatus(message, "FAILURE" ); } } void setBuildStatus( String message, String state) { step([ $class: "GitHubCommitStatusSetter" , reposSource: [$class: "ManuallyEnteredRepositorySource" , url: "https: //github.com/my-org/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]] ] ]); }

          Peter Springsteen added a comment - - edited

          killuazhu thanks for providing the code snippet. Let me clarify about the "granularity" comment. I mean tying stages to statuses for a given GitHub commit. Your example takes a similar approach to the GitHub Branch Source plugin's GitHubBuildStatusNotification class, whereby the final build status of the run (holistically) is tied to a single status for a given commit. What I would like to do is to tie each stage to a separate status.

          So, your code snippet would be modified to be something like (untested pseudocode)

          node('a_node') {
              buildStep('Checkout'){
                  checkout scm
              }
          
              buildStep('step 1'){
                      sh '''echo "step 1"
                      '''
              }
          }
          
          void buildStep(String context, Closure closure) {
            stage(context);
            try {
              setBuildStatus(context, "In progress...", "PENDING");
              closure();
            } catch (Exception e) {
              setBuildStatus(context, e.take(140), "FAILURE");
            }
            setBuildStatus(context, "Success", "SUCCESS");
          }
          
          
          // Updated to account for context
          void setBuildStatus(String context, String message, String state) {
            context = context ?: "ci/jenkins/build-status"
            step([
                $class: "GitHubCommitStatusSetter",
                reposSource: [$class: "ManuallyEnteredRepositorySource", url: "https://github.com/my-org/my-repo"],
                contextSource: [$class: "ManuallyEnteredCommitContextSource", context: context],
                errorHandlers: [[$class: "ChangingBuildStatusErrorHandler", result: "UNSTABLE"]],
                statusResultSource: [ $class: "ConditionalStatusResultSource", results: [[$class: "AnyBuildResult", message: message, state: state]] ]
            ]);
          }
          

          So the resulting status array would be something like:
          GET /repos/:owner/:repo/commits/:ref/statuses

          {
            "state": "failure",
            "statuses": [
              {
                "url": "https://...bfb1bf",
                "id": 899209,
                "state": "success",
                "description": "Success",
                "target_url": "http://...../job/PR-25/27/display/redirect",
                "context": "Checkout",
                "created_at": "2017-02-15T20:05:36Z",
                "updated_at": "2017-02-15T20:05:36Z"
              },
              {
                "url": "https://...bfb1bf",
                "id": 899210,
                "state": "failure",
                "description": "Error executing echo",
                "target_url": "http://...../job/PR-25/27/display/redirect",
                "context": "step 1",
                "created_at": "2017-02-15T20:05:36Z",
                "updated_at": "2017-02-15T20:05:36Z"
              }
            ],
            "sha": "...777bfb1bf",
          

          I could facilitate this with direct API calls to GitHub, but would prefer a more Pipeline native approach.

          Peter Springsteen added a comment - - edited killuazhu thanks for providing the code snippet. Let me clarify about the "granularity" comment. I mean tying stages to statuses for a given GitHub commit. Your example takes a similar approach to the GitHub Branch Source plugin's GitHubBuildStatusNotification class, whereby the final build status of the run (holistically) is tied to a single status for a given commit. What I would like to do is to tie each stage to a separate status. So, your code snippet would be modified to be something like (untested pseudocode) node( 'a_node' ) { buildStep( 'Checkout' ){ checkout scm } buildStep( 'step 1' ){ sh '''echo "step 1" ''' } } void buildStep( String context, Closure closure) { stage(context); try { setBuildStatus(context, "In progress..." , "PENDING" ); closure(); } catch (Exception e) { setBuildStatus(context, e.take(140), "FAILURE" ); } setBuildStatus(context, "Success" , "SUCCESS" ); } // Updated to account for context void setBuildStatus( String context, String message, String state) { context = context ?: "ci/jenkins/build-status" step([ $class: "GitHubCommitStatusSetter" , reposSource: [$class: "ManuallyEnteredRepositorySource" , url: "https: //github.com/my-org/my-repo" ], contextSource: [$class: "ManuallyEnteredCommitContextSource" , context: context], errorHandlers: [[$class: "ChangingBuildStatusErrorHandler" , result: "UNSTABLE" ]], statusResultSource: [ $class: "ConditionalStatusResultSource" , results: [[$class: "AnyBuildResult" , message: message, state: state]] ] ]); } So the resulting status array would be something like: GET /repos/:owner/:repo/commits/:ref/statuses { "state": "failure", "statuses": [ { "url": "https://...bfb1bf", "id": 899209, "state": "success", "description": "Success", "target_url": "http://...../job/PR-25/27/display/redirect", "context": "Checkout", "created_at": "2017-02-15T20:05:36Z", "updated_at": "2017-02-15T20:05:36Z" }, { "url": "https://...bfb1bf", "id": 899210, "state": "failure", "description": "Error executing echo", "target_url": "http://...../job/PR-25/27/display/redirect", "context": "step 1", "created_at": "2017-02-15T20:05:36Z", "updated_at": "2017-02-15T20:05:36Z" } ], "sha": "...777bfb1bf", I could facilitate this with direct API calls to GitHub, but would prefer a more Pipeline native approach.

          Please read docs for pipeline plugin. On first run there is no information about git (pipeline doesn't provide it)

          Hello lanwen , I don't understand your sentence, nor why you closed the ticket as won't fix.
          This is a major issue. In many cases, the branch will only be built once.
          I understand that it's a Pipeline / SCM plugin issue at root, maybe already fixed. See for instance https://issues.jenkins-ci.org/browse/JENKINS-41795
          So, won't the current issue require a fix to follow the API changes?
          Thanks

          Julien Carsique added a comment - Please read docs for pipeline plugin. On first run there is no information about git (pipeline doesn't provide it) Hello lanwen , I don't understand your sentence, nor why you closed the ticket as won't fix. This is a major issue. In many cases, the branch will only be built once. I understand that it's a Pipeline / SCM plugin issue at root, maybe already fixed. See for instance https://issues.jenkins-ci.org/browse/JENKINS-41795 So, won't the current issue require a fix to follow the API changes? Thanks

          JENKINS-41795 is not related to this issue.

          How it works with defaults - pipeline is a just text for jenkins and jenkins knows nothing about content of the script before first evaluation.
          Status step tries to find defined repos with dedicated jenkins api. But when jenkins dont know about script content - it can't provide info about repos to the status setter step.

          As a workaround for short-living jobs you can define repo with manual provider (as in Peter Springsteen's example)

          Kirill Merkushev added a comment - JENKINS-41795 is not related to this issue. How it works with defaults - pipeline is a just text for jenkins and jenkins knows nothing about content of the script before first evaluation. Status step tries to find defined repos with dedicated jenkins api. But when jenkins dont know about script content - it can't provide info about repos to the status setter step. As a workaround for short-living jobs you can define repo with manual provider (as in Peter Springsteen's example)

          Denys Digtiar added a comment -

          FYI, I raised JENKINS-43182

          Denys Digtiar added a comment - FYI, I raised JENKINS-43182

          Note: The GitHubCommitStatusSetter requires that the Git Server is defined under *Manage Jenkins > Configure System > GitHub > GitHub Servers*. Otherwise the GitHubCommitStatusSetter is not able to resolve the repository name properly and you would see an empty list of repos:

          [...]
          [Set GitHub commit status (universal)] PENDING on repos [] (sha:xxxxxxx) with context:test/mycontext
          [...]
          

          Allan BURDAJEWICZ added a comment - Note: The GitHubCommitStatusSetter requires that the Git Server is defined under * Manage Jenkins > Configure System > GitHub > GitHub Servers *. Otherwise the GitHubCommitStatusSetter is not able to resolve the repository name properly and you would see an empty list of repos : [...] [Set GitHub commit status (universal)] PENDING on repos [] (sha:xxxxxxx) with context:test/mycontext [...]

          JP Strydom added a comment -

          JP Strydom added a comment - [This] ( https://issues.jenkins-ci.org/browse/JENKINS-39482?focusedCommentId=288123&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-288123 ) solution used to work for me until I started getting this error: ERROR: [GitHub Commit Status Setter] - Cannot retrieve Git metadata for the build, setting build result to UNSTABLE I tried [this] ( https://issues.jenkins-ci.org/browse/JENKINS-54249?page=com.atlassian.jira.plugin.system.issuetabpanels%3Aall-tabpanel ) solution but it didn't work. You can read more about the error [here] ( https://issues.jenkins-ci.org/browse/JENKINS-54249?focusedCommentId=359516&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-359516 )

            lanwen Kirill Merkushev
            tonyarous Tony Arous
            Votes:
            0 Vote for this issue
            Watchers:
            11 Start watching this issue

              Created:
              Updated:
              Resolved: