Jenkins Github plugin doesn't set status - github

I'm trying to set a github status from a Jenkins job. Jenkins returns a
[Set GitHub commit status (universal)] SUCCESS on repos [] (sha:9892fbd) with context:ci/jenkins/tests
... but the status isn't set when I query it with the REST API later.
There's the groovy code:
def getCommitHash() {
sh(script: """
git rev-parse HEAD
""", returnStdout: true).trim()
}
def setCountTestLocation(String location) {
url = "https://<internal github>/<org>/<repo>"
commitHash = getCommitHash()
print(url)
print(commitHash)
step([
$class: "GitHubCommitStatusSetter",
reposSource: [$class: "ManuallyEnteredRepositorySource", url: url],
contextSource: [$class: "ManuallyEnteredCommitContextSource", context: "ci/jenkins/tests"],
statusBackrefSource: [$class: "ManuallyEnteredBackrefSource", backref: location],
errorHandlers: [[$class: "ChangingBuildStatusErrorHandler", result: "UNSTABLE"]],
commitShaSource: [$class: "ManuallyEnteredShaSource", sha: commitHash],
statusResultSource: [ $class: "ConditionalStatusResultSource", results: [[$class: "AnyBuildResult", message: "Tests here!", state: "SUCCESS", location: location]] ]
]);
}

You repository hasn't been updated as it seems that repos were not properly set.
Plugin still reports success as it properly completed its run, but repo list is empty as evident in your message SUCCESS on repos [].

This issue can occur if you have not set up a "GitHub Server" config under the global Jenkins configs:
Manage Jenkins -> Configure System -> GitHub
You can find more details on how to set up a server configuration under the "Automatic Mode" section of the GitHub Plugin documentation:
https://wiki.jenkins-ci.org/display/JENKINS/GitHub+Plugin#GitHubPlugin-AutomaticMode%28Jenkinsmanageshooksforjobsbyitself%29

After much pain with the same issue and plugin, here is a fix not for this particular plugin, but rather a workaround that does not require a plugin and still solves the issue, using curl. You can add the following to your pipeline:
post {
success {
withCredentials([usernamePassword(credentialsId: 'your_credentials_id', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
sh 'curl -X POST --user $USERNAME:$PASSWORD --data "{\\"state\\": \\"success\\"}" --url $GITHUB_API_URL/statuses/$GIT_COMMIT'
}
}
failure {
withCredentials([usernamePassword(credentialsId: 'your_credentials_id', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
sh 'curl -X POST --user $USERNAME:$PASSWORD --data "{\\"state\\": \\"failure\\"}" --url $GITHUB_API_URL/statuses/$GIT_COMMIT'
}
}
}
Where the GITHUB_API_URL is usually constructed like so, for example in the environment directive:
environment {
GITHUB_API_URL='https://api.github.com/repos/organization_name/repo_name'
}
The credentialsId can be created and obtained from Jenkins -> Credentials

Related

Deploy docker image from Nexus registry

I have this Jenkinsfile which I want to use to build a pipeline:
pipeline {
agent any
environment {
NEXUS_VERSION = "nexus3"
NEXUS_PROTOCOL = "http"
NEXUS_URL = "you-ip-addr-here:8081"
NEXUS_REPOSITORY = "maven-nexus-repo"
NEXUS_CREDENTIAL_ID = "nexus-user-credentials"
}
stages {
stage('Download Helm Charts') {
steps {
sh "echo 'Downloading Helm Charts from Bitbucket repository...'"
// configure credentials under http://192.168.1.28:8080/user/test/credentials/ and put credentials ID
// not sure do I need to point the root folder of the Helm repository or only the single chart
checkout scmGit(
branches: [[name: 'master']],
userRemoteConfigs: [[credentialsId: 'c2672602-dfd5-4158-977c-5009065c867e',
url: 'http://192.168.1.30:7990/scm/jen/helm.git']])
}
}
stage('Test Kubernetes version') {
steps {
sh "echo 'Checking Kubernetes version..'"
// How to do remote test of kubernetes version
}
}
stage('Push Helm Charts to Kubernetes') {
steps {
sh "echo 'building..'"
// push here helm chart from Jenkins server to Kubernetes cluster
}
}
stage('Build Image') {
steps {
sh "echo 'building..'"
// configure credentials under http://192.168.1.28:8080/user/test/credentials/ and put credentials ID
git credentialsId: 'bitbucket-server:50001e738fa6dafbbe7e336853ced1fcbc284fb18ea8cda8b54dbfa3a7bc87b9', url: 'http://192.168.1.30:7990/scm/jen/spring-boot-microservice.git', branch: 'master'
// execute Java -jar ... and build docker image
./gradlew build && java -jar build/libs/gs-spring-boot-docker-0.1.0.jar
docker build -t springio/gs-spring-boot-docker .
}
}
stage('Push Image into Nexus registry') {
steps {
sh "echo 'building..'"
// push compiled docker image into Nexus repository
script {
pom = readMavenPom file: "pom.xml";
filesByGlob = findFiles(glob: "target/*.${pom.packaging}");
echo "${filesByGlob[0].name} ${filesByGlob[0].path} ${filesByGlob[0].directory} ${filesByGlob[0].length} ${filesByGlob[0].lastModified}"
artifactPath = filesByGlob[0].path;
artifactExists = fileExists artifactPath;
if(artifactExists) {
echo "*** File: ${artifactPath}, group: ${pom.groupId}, packaging: ${pom.packaging}, version ${pom.version}";
nexusArtifactUploader(
nexusVersion: NEXUS_VERSION,
protocol: NEXUS_PROTOCOL,
nexusUrl: NEXUS_URL,
groupId: pom.groupId,
version: pom.version,
repository: NEXUS_REPOSITORY,
credentialsId: NEXUS_CREDENTIAL_ID,
artifacts: [
[artifactId: pom.artifactId,
classifier: '',
file: artifactPath,
type: pom.packaging],
[artifactId: pom.artifactId,
classifier: '',
file: "pom.xml",
type: "pom"]
]
);
} else {
error "*** File: ${artifactPath}, could not be found";
}
}
}
}
stage('Deploy Image from Nexus registry into Kubernetes') {
steps {
sh "echo 'building..'"
}
}
stage('Test'){
steps {
sh "echo 'Testing...'"
// implement a check here is it deployed sucessfully
}
}
}
}
How I can deploy the docker image build by Jenkins server and pushed in Nexus repository? If possible I want to use service account with token?
Instead of using 'nexusArtifactUploader', why don´t you use docker push, like you do to build the image?
I guess nexusArtifactUploader uses Nexus API and doesn´t work with docker images, but you can access the registry using docker and the exposed port (defaults to 5000)
withCredentials([string(credentialsId: NEXUS_CREDENTIAL_ID, variable: 'registryToken')]) {
sh 'docker push --creds default:${registryToken} your-registry-url/image-name:image-tag'
}
You may also change docker build command to build the image using your registry name (or tag it after building, see How to push a docker image to a private repository)

How to create a tag for specific branch using Jenkinsfile

I have a scenario i need to build and push docker file only when tag is build from master branch.
stage('Tag') {
when {
expression { sh([returnStdout: true, script: 'echo $TAG_NAME | tr -d \'\n\'']) }
}
steps {
script {
echo "tag"
}
}
}
The above code will work.. If at all we create a tag for the develop branch or the test branch even though when condition is getting satisfied. can anyone help me how to over come this issue.
If it is of any help, this is an except of a sequential Jenkinsfile I use to tag branches on repos. It is a two stage process - find the current commit for the branch and then tag that:
steps.withCredentials([steps.usernamePassword(credentialsId: httpCredentials,
usernameVariable: 'GITHUB_USERNAME', passwordVariable: 'GITHUB_TOKEN')]) {
// Need to do this as a two stage activity (need commit sha) but *warning* this api assumes ref is a branch
def json_info = steps.sh(script: "curl -X GET -H \"Authorization: token \$GITHUB_TOKEN\" -H \"Accept: application/vnd.github.v3+json\" ${httpUrlForHost}/repos/${slugForRepo}/branches/${ref}",
returnStdout: true)
def branch_info = steps.readJSON text: json_info
def sha = branch_info?.commit?.sha
if (!sha) {
steps.error("Unexpected sha for branch ${ref} (${json_info})")
}
def jsonPayload = "{\"ref\":\"refs/tags/${new_tag}\",\"sha\":\"${sha}\"}"
steps.sh "curl -X POST -H \"Authorization: token \$GITHUB_TOKEN\" -H \"Accept: application/vnd.github.v3+json\" -d '${jsonPayload}' ${httpUrlForHost}/repos/${slugForRepo}/git/refs"
}

Jfrog REST API Jenkins Groovy status code: 404, reason phrase: Not Found

I have a Groovy script which is run in the Jenkins script console. The script uses the JFrog Rest API to run some queries. One of which returns: status code: 404, reason phrase: Not Found
CURL:
$ curl -X GET -H "X-JFrog-Art-Api:APIKey" https://OU.jfrog.io/OU/api/storage/test-repository/docker-log-gen/1.12/manifest.json?properties
{
"properties" : { ... },
"uri" : "https://OU.jfrog.io/artifactory/api/storage/test-repository/docker-log-gen/1.12/manifest.json"
}
WGET
$ wget --header="X-JFrog-Art-Api:APIKey" https://OU.jfrog.io/OU/api/storage/test-repository/docker-log-gen/1.12/manifest.json?properties
--2020-01-14 13:12:16-- https://OU.jfrog.io/OU/api/storage/test-repository/docker-log-gen/1.12/manifest.json?properties
HTTP request sent, awaiting response... 200 OK
Jenkins Groovy
def restClient = new RESTClient('https://OU.jfrog.io')
restClient.headers['X-JFrog-Art-Api'] = 'APIKey'
println(restClient.get(path: '/OU/api/storage/test-repository/docker-log-gen/1.12/manifest.json?properties', requestContentType: 'text/plain') )
groovyx.net.http.HttpResponseException: status code: 404, reason phrase: Not Found
Other rest calls (api/docker) are made prior to this one in the script and return successfully. I am unable to identify a cause for this response, as shown the command-line calls return the expected JSON.
Please help.
The part after the first question mark is not the URI path component.
println(restClient.get(path: '/OU/api/storage/test-repository/docker-log-gen/1.12/manifest.json', query: ['properties': ''] , requestContentType: 'text/plain').data.text )
{
"properties" : { ... },
"uri" : "https://OU.jfrog.io/artifactory/api/storage/test-repository/docker-log-gen/1.12/manifest.json"
}

How can cypress be made to work with aurelia with github actions and locally?

Ok, so I added cypress to aurelia during my configuration and it worked fine. When I went to set up cypress on github as just a command, I could not get it to recognize puppeteer as a browser. So instead I went and used the official github actions for cypress, and that works
- name: test
uses: cypress-io/github-action#v1
with:
start: yarn start
browser: ${{matrix.browser}}
record: true
env:
# pass the Dashboard record key as an environment variable
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
however I had to set my cypress.json as follows
{
"baseUrl": "http://localhost:8080",
"fixturesFolder": "test/e2e/fixtures",
"integrationFolder": "test/e2e/integration",
"pluginsFile": "test/e2e/plugins/index.js",
"screenshotsFolder": "test/e2e/screenshots",
"supportFile": "test/e2e/support/index.js",
"videosFolder": "test/e2e/videos",
"projectId": "..."
}
and now running yarn e2e doesn't work because there's no server stood up, as it's not doing it itself anymore via cypress.config.js
const CLIOptions = require( 'aurelia-cli').CLIOptions;
const aureliaConfig = require('./aurelia_project/aurelia.json');
const PORT = CLIOptions.getFlagValue('port') || aureliaConfig.platform.port;
const HOST = CLIOptions.getFlagValue('host') || aureliaConfig.platform.host;
module.exports = {
config: {
baseUrl: `http://${HOST}:${PORT}`,
fixturesFolder: 'test/e2e/fixtures',
integrationFolder: 'test/e2e/integration',
pluginsFile: 'test/e2e/plugins/index.js',
screenshotsFolder: 'test/e2e/screenshots',
supportFile: 'test/e2e/support/index.js',
videosFolder: 'test/e2e/videos'
}
};
how can I make it so that yarn e2e works as it previously did, and have it working on github?(I don't care which side of the equation is changed)
here's yarn e2e not sure what the au is doing under the hood.
"e2e": "au cypress",
Easiest way to achieve this, create a test/e2e/cypress-config.json
{
"baseUrl": "http://localhost:8080",
"fixturesFolder": "test/e2e/fixtures",
"integrationFolder": "test/e2e/integration",
"pluginsFile": "test/e2e/plugins/index.js",
"screenshotsFolder": "test/e2e/screenshots",
"supportFile": "test/e2e/support/index.js",
"videosFolder": "test/e2e/videos",
"projectId": "1234"
}
, and then setup the github action like this.
- name: test
uses: cypress-io/github-action#v1
with:
config-file: tests/e2e/cypress-config.json
start: yarn start
browser: ${{matrix.browser}}
record: true
env:
# pass the Dashboard record key as an environment variable
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
the path doesn't matter, just that you configure the same one. Just make sure it doesn't overlap with what aurelia wants.

How to run continuous integration in parallel across multiple Pull Requests?

I am testing use of Jenkins with Github pull request builder plugin I have successfully set up a toy project on Github and dev installation of Jenkins so that raising a PR, or pushing changes to a PR branch triggers a build. Mostly this works as required - a few things don't match preferred workflow, but the freedom from having to write and maintain our own plugin is a big deal.
I have one potential showstopper. The plugin queues up all pushes in all PRs it sees, and only ever seems to run a single job at a time, even with spare executors available. In the real world project, we may have 10 active PRs, each may get a few pushed updates in a day in response to QC comments, and the full CI run takes > 30 mins. However, we do have enough build executors provisioned to run multiple jobs at the same time.
I cannot see any way to configure the PR request builder to process multiple jobs at once on the same trigger, but I may be missing something basic elsewhere in Jenkins. Is there a way to do this, without needing to customise the plugin?
I have installed Jenkins ver. 1.649 on a new Ubuntu 14.04 server (on a VirtualBox guest) and followed the README in the ghprb plugin (currently version 1.30.5), including setting up a jenkins "bot" account on Github as a collaborator to run all the integration API calls to Github.
I was wondering what the behaviour would be if I cloned the job (create new item and "Copy existing item"), and may try that next, but I expect that will result in the same job being run multiple times for no benefit as opposed to interacting smartly with other jobs polling the same pool of PRs.
I have found the config setting whilst exploring more for the question.
It is really easy when you know which config item it is, but Jenkins has a lot of configuration to work through, especially when you are exploring the plugins.
The key thing is that the option to serve queued jobs in parallel (available executors allowing) is core Jenkins config, and not part of the Github PR builder.
So, just check the option Execute concurrent builds if necessary. This option should be found at the bottom of the first, untitled section of config. It is a really basic Jenkins option, that a newbie like me missed due to the mountain of other options.
May be it is too late to answer this question, but after few days of researching I figured out a way to create multiple jobs per PR in github.
The code I am showing here applies to github enterprise, but it works well enough for the general github(bitbucket) as well with a few tweaks in url and git command.
The mainline repository against which the PRs are created needs to have a file, I call it PRJob.groovy and contains
import groovy.json.JsonSlurper
gitUrl = GIT_URL
repoRestUrl = "${GITHUB_WEB_URL}/repos/${project}/${repo}"
def getJSON(url) {
def conn = (HttpURLConnection) new URL(url).openConnection()
conn.setRequestProperty("Authorization", "token ${OAUTH_TOKEN}");
return new JsonSlurper().parse(new InputStreamReader(conn.getInputStream()))
}
def createPipeline(name, description, branch, prId) {
return pipelineJob(name) {
delegate.description description
if (ENABLE_TRIGGERS == 'true') {
triggers {
cron 'H H/8 * * *'
scm 'H/5 * * * *'
}
}
quietPeriod(60)
environmentVariables {
env 'BRANCH_NAME', branch
env 'PULL_REQUEST', prId
env 'GITHUB_WEB_URL', GITHUB_WEB_URL
env 'OAUTH_TOKEN', OAUTH_TOKEN
env 'PROJECT', project
env 'REPO', repo
}
definition {
cpsScm {
scriptPath "Jenkinsfile"
scm {
git {
remote {
credentials "jenkins-ssh-key"
delegate.url gitUrl
if (prId != "") {
refspec "+refs/pull/${prId}/*:refs/remotes/origin/pr/${prId}/*"
}
}
delegate.branch branch
}
}
}
}
}
}
def createPRJobs() {
def prs = getJSON("${repoRestUrl}/pulls?state=open")
if (prs.size() == 0) {
def mergedPrs = getJSON("${repoRestUrl}/pulls?state=closed")
if (mergedPrs.size() == 0) {
throw new RuntimeException("No pull-requests found; auth token has likely expired")
}
}
prs.each { pr ->
def id = pr.get("number")
def title = pr.get("title")
def fromRef = pr.get("head")
def fromBranchName = fromRef.get("ref")
def prRepo = fromRef.get("repo")
def repoName = prRepo.get("name")
def prHref = pr.get("url")
createPipeline("${repo}-PR-${id}-${fromBranchName}",
"${prHref} Pull Request ${id}: ${title}", "origin/pr/${id}/head", id)
}
}
createPRJobs()
This creates 1 jenkins job per PR.
This relies on the project having a Jenkinsfile which can be picked up for running a peipeline job. A sample Jenkinsfile will look like below:
//Jenkinsfile for building and creating jobs
commitId = null
repoRestUrl = "${GITHUB_WEB_URL}/repos/${PROJECT}/${REPO}"
try{
stage('Install and Tests') {
runTest("Hello")
}
notify_github 'success'
}catch (Exception e) {
notify_github 'failure'
print e
throw e
}
def runTest(String someDummyVariable) {
node {
checkout scm
sh 'git clean -qdf'
if (env.PULL_REQUEST == ""){
sh 'git rev-parse --verify HEAD > commit.txt'
} else {
// We check out PR after it is merged with master, but we need to report the result against the commit before merge
sh "git rev-parse refs/remotes/origin/pr/${env.PULL_REQUEST}/head^{commit} > commit.txt"
}
commitId = readFile 'commit.txt'
echo commitId
sh 'rm -f commit.txt'
//Here goes your code for doing anything
sh 'echo "Hello World!!!!!"'
}
}
def http_post(url, rawJson) {
def conn = (HttpURLConnection) new URL(url).openConnection()
conn.setRequestProperty("Authorization", "token ${OAUTH_TOKEN}");
conn.doOutput = true
conn.requestMethod = "POST"
conn.setRequestProperty("Content-Type", "application/json")
def wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(rawJson);
wr.close()
def code = conn.getResponseCode()
if (code < 200 || code >= 300){
println 'Failed to post to ' + url
def es = conn.getErrorStream();
if (es != null) {
println es.getText()
}
}
}
def notify_github(state) {
http_post(
"${repoRestUrl}/statuses/${commitId}",
"""
{ "state": "${state}",
"target_url": "${env.BUILD_URL}",
"description": "Build Pipeline",
"context": "Build Pipeline"
}
"""
)
}
Hope this helps someone.