I am triggering a parameterized Jenkins from from outside of jenkins via a http POST request:
I have enabled in the job configuration that the job can be triggered f
Update:
The other answer was added ~8 months after mine. I was unaware of the location header in the response at the time. That does sound like a good option for some cases. That said, based on the caveats in the answer and the comments (especially around parameterized builds), it appears that this answer still has some utility for some cases.
Original answer:
Unfortunately, they don't make this as straightforward as it could be. i.e. by, say, returning a JSON response with information like an id.
However, I believe a solid, though certainly non-trivial, workaround to that would be to leverage the cause parameter in the URL you use to trigger the build, and within that cause, add unique text that you can later parse to determine that you triggered it from your automation.
To further uniqueify the specific job, in case multiple are running around the same time, even from your automation, also include a unique ID of some type (it could simply be a sequence ID from your RDBMS or similar) inside of the cause parameter.
Then, you can use the JSON API to get information about the job you're remotely triggering. Again, it's somewhat indirect, but doable:
Hit a URL of the form:
http://<server>:<port>/job/<jobname>/lastBuild/api/json
You can add ?pretty=true
to pretty-print it within the browser for better human readability.
That will get you the JSON of the last build. It will contain the causes attribute within the actions attribute, and in there (in another nested attribute named shortDescription) you would find the cause parameter you added, if this was one of the builds you triggered.
You could parse out both the special static text, and your generated ID to see if they match. If they do, you can then get the Jenkins id out of the JSON as well (search for buildNumber, which is nested).
If that build is either not triggered by your automation at all, or was, but the ID doesn't match, you can repeat the process for the N - 1 build until you find what you're looking for.
That JSON would be of the form:
http://<server>:<port>/job/<jobname>/<buildNumber>/api/json
Since Jenkins 1.519, enqueuing a build responds with a URL in the Location
, pointing you to an item in the build queue:
$ nc localhost 8666
POST /jenkins/job/morgRemote/buildWithParameters?jenkins_status=1&jenkins_sleep=20&token=morgRemote HTTP/1.1
Host: localhost:8666
HTTP/1.1 201 Created
Location: http://localhost:8666/jenkins/queue/item/39/
Content-Length: 0
Server: Jetty(winstone-2.8)
Now if you add api/json
(or api/xml
and so on) to the end of it (so in this example it would be http://localhost:8666/jenkins/queue/item/39/api/json
) then you will get a document that will contain build id for the given job. For json the retrieved object has executable
attribute, which in turn has number
and url
attributes. number
is the build id for the given job (35 here) and url
is the jenkins build page url.
{
"actions" : [
{
"parameters" : [
{
"name" : "jenkins_status",
"value" : "1"
},
{
"name" : "jenkins_sleep",
"value" : "20"
}
]
},
{
"causes" : [
{
"shortDescription" : "Started by remote host 127.0.0.1",
"addr" : "127.0.0.1",
"note" : null
}
]
}
],
"blocked" : false,
"buildable" : false,
"id" : 39,
"inQueueSince" : 1423993879845,
"params" : "\njenkins_status=1\njenkins_sleep=20",
"stuck" : false,
"task" : {
"name" : "morgRemote",
"url" : "http://localhost:8666/jenkins/job/morgRemote/",
"color" : "red"
},
"url" : "queue/item/39/",
"why" : null,
"cancelled" : false,
"executable" : {
"number" : 35,
"url" : "http://localhost:8666/jenkins/job/morgRemote/35/"
}
}
be aware of 2 things:
executable
and canceled
attributes will be missing and why
will be not null. You can change this behavior in "Advanced Project Options" of your job config by modifying "Quiet period" setting or in the jenkins global configuration.:
...
"url" : "queue/item/39/",
"why" : "In the quiet period. Expires in 2.4 sec",
"timestamp" : 1423993879845
}
Wanted to add to morgwai answer using the Location header.
I just solved this problem. The key after the Location header is to poll the job queue entry till it has an 'executable' entry that gives the job number that has been started.
I give the full answer to a similar question that I saw first that did not completely answer the problem:
https://stackoverflow.com/a/48531874/9291603
JSON from Jenkins job queue entry with the executable entry:
{
"_class": "hudson.model.Queue$LeftItem",
"actions": [
{
"_class": "hudson.model.CauseAction",
"causes": [
{
"_class": "hudson.model.Cause$RemoteCause",
"addr": "10.20.30.60",
"note": null,
"shortDescription": "Started by remote host 10.20.30.60"
}
]
}
],
"blocked": false,
"buildable": false,
"cancelled": false,
"executable": {
"_class": "org.jenkinsci.plugins.workflow.job.WorkflowRun",
"number": 45,
"url": "http://192.168.115.187:8080/job/rf_systest/45/"
},
"id": 95,
"inQueueSince": 1517342648136,
"params": "",
"stuck": false,
"task": {
"_class": "org.jenkinsci.plugins.workflow.job.WorkflowJob",
"color": "blue_anime",
"name": "rf_systest",
"url": "http://192.168.115.187:8080/job/rf_systest/"
},
"url": "queue/item/95/",
"why": null
}
Turns out builds have the original queue ID. Furthermore you can query for only the build with your queue Id and poll it until you get a result because 404 should normally imply it is queued.
Pull the Queue ID off the Location header, e.g. 39
/jenkins/queue/item/39/
Repeatedly query for a build with that queue number until you get an answer
"http://{jenkins}job/{job}/api/xml?tree=builds[number,queueId]&xpath=//build[queueId=\"{queueId}\"]";
<build>
<number>411</number>
<queueId>39</queueId>
</build>
From this result you can pull the build number with the xpath /build/number/text()
(Note I could not use &xpath=//build[queueId={queueId}]/number/text()
in the url because "primitive XPath result sets forbidden; implement jenkins.security.SecureRequester"
)
It is equally as lame as polling the queue api for an "executable" build. One advantage is the endpoint will persist longer - until the build is deleted, compared to an arbitrary time (which seems to be about 5 minutes).
I was able to use Java Jenkins api to achieve what you are looking for. https://github.com/jenkinsci/java-client-api
Sample Code:
JenkinsServer jenkinsServer = new JenkinsServer(newURI("http://yourJenkinsServer:8080/"));
JobWithDetails smokeTestJob = jenkinsServer.getJob("YourJobName");
Map<String,String> jobParams = new HashMap<String,String>();
QueueReference queueReference = smokeTestJob.build(jobParams);
do {
Thread.sleep(2000L);
queueItem = jenkinsServer.getQueueItem(queueReference);
log("Job still in queue"+queueItem.getExecutable());
} while (queueItem.getExecutable() == null);
Build build = jenkinsServer.getBuild(queueItem);
while(build.details().isBuilding()){
log("Job still running");
Thread.sleep(10000L);
}
log("Result="+build.details().getResult());