jenkinsci / ghprb-plugin

github pull requests builder plugin for Jenkins
https://plugins.jenkins.io/ghprb/
MIT License
506 stars 612 forks source link

Replay in pr-builder pipeline doesn't update GitHub PR status OR restarting a pipeline stage will not update pull request status #756

Open amleszk opened 5 years ago

amleszk commented 5 years ago

Re-opening because the issue https://github.com/jenkinsci/ghprb-plugin/issues/674 still occurs. and the solution did not work. Can someone please provide detailed steps if this is fixed? Thank you!

A Little more background:

We are using Github pull request builder to poll a private GitHub repository and using Jenkins pipeline script to execute a multiple-stage pipeline build. When triggering a build via GitHub, the checks are updated on the pull request correctly but when restarting the pipeline the checks on the PR are not updated.

We need this to work because sometimes tests get re-tried and disabled a second time. and we do not want to re-run the entire pipeline

The ghprb config is not using web hooks but instead polling the repository

amleszk commented 5 years ago

After working on this issue for a while and much Google searching I found an alternative which is to manually send status updates to GitHub in the pipeline - using this as a guide https://github.com/KostyaSha/github-integration-plugin/issues/102#issuecomment-299641073 . I have attached a full pipeline example below to help any other poor developers who encounter this issue. Took me all day to figure it out, pipelines are very difficult

// Manages communication with github for reporting important status
// events. Relies on Github integration plugin https://github.com/jenkinsci/github-plugin
class GithubStatus {

    // Repository to send status e.g: '/username/repo'
    String ghprbGhRepository

    // Commit hash to send status e.g: `909b76f97e`
    String ghprbActualCommit

    // Build url send status e.g: `https://jenkins/build/123`
    String BUILD_URL

    // Set pending status for this pull request
    def setPending(script) {
        this.setBuildStatusStep(script, "In Progress", "PENDING")
    }

    // Set failed status for this pull request
    def setFailed(script) {
        this.setBuildStatusStep(script, "Complete", "FAILURE")
    }

    // Set success status for this pull request
    def setSuccess(script) {
        this.setBuildStatusStep(script, "Complete", "SUCCESS")
    }

    // Manually set PR status via GitHub integration plugin. Manual status updates are needed
    // Due to pipeline stage retries not propagating updates back to Github automatically
    // https://github.com/KostyaSha/github-integration-plugin/issues/102#issuecomment-299641073
    def setBuildStatusStep(script, String message, String state) {
        def commitContextName = "Jenkins Build and Test"
        script.step([
            $class: "GitHubCommitStatusSetter",
            reposSource: [$class: "ManuallyEnteredRepositorySource", url: "https://github.com/${this.ghprbGhRepository}"],
            contextSource: [$class: "ManuallyEnteredCommitContextSource", context: commitContextName],
            errorHandlers: [[$class: "ChangingBuildStatusErrorHandler", result: "UNSTABLE"]],
            commitShaSource: [$class: "ManuallyEnteredShaSource", sha: this.ghprbActualCommit],
            statusBackrefSource: [$class: "ManuallyEnteredBackrefSource", backref: "${this.BUILD_URL}flowGraphTable/"],
            statusResultSource: [$class: "ConditionalStatusResultSource", results: [[$class: "AnyBuildResult", message: message, state: state]] ]
        ])
    }
}
def githubStatus = new GithubStatus(
                        ghprbGhRepository: env.ghprbGhRepository,
                        ghprbActualCommit: env.ghprbActualCommit,
                        BUILD_URL: env.BUILD_URL
                    )

pipeline {
    agent any
    stages {
        stage ('A') {
            steps {
                node('node') {
                    script {
                        githubStatus.setPending(this)
                    }
                }
            }
        }

        stage ('Test distribute') {
            steps {
                script {
                    githubStatus.setPending(this)
                }
            }
        }
    }
    post {
        success {
            node('master') {
                script {
                    githubStatus.setSuccess(this)
                }
            }
        }
        unsuccessful {
            node('master') {
                script {
                    githubStatus.setFailed(this)
                }
            }
        }
    }
}
gill-0 commented 4 years ago

You can trigger the change to the pr manually by clicking release change in the upper right hand corner of the pipeline execution

anton-mesnyankin commented 3 years ago

@amleszk . thank you for your code, it helped me a lot. A note for future readers: also don't forget to make sure that 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