Revision control
++ #!/usr/bin/perl -w
++ # Copyright (C) 2017 The Qt Company Ltd.
++ # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
++
++
++ use strict;
++ use warnings;
++ use Cwd;
++ use Cwd qw(abs_path);
++ use JSON::PP;
++ use LWP::UserAgent;
++ use Pod::Usage;
++ use Getopt::Long;
++ use Time::Out qw(timeout) ;
++ use LWP::UserAgent;
++
++ # call
++ # perl jenkins_job_trigger.pl -forcesuccess -u http://qt-dev-ci.ci.local -j Remotely_triggered -a 'token=REMOTE_TOKEN&MY_BRANCH=simo'
++
++ # Params
++ my $jenkins = "http://qt-dev-ci.ci.local";
++ my $job = "Remotely_triggered";
++ my $job_params = "";
++ $job_params = "$ENV{'PUBLISHER_PARAMS'}" if (defined $ENV{'PUBLISHER_PARAMS'});
++ $jenkins = "$ENV{'PUBLISHER_JENKINS'}" if (defined $ENV{'PUBLISHER_JENKINS'});
++ $job = "$ENV{'PUBLISHER_JOB'}" if (defined $ENV{'PUBLISHER_JOB'});
++ my $verbose = 0;
++ my $fire_and_forget = 0;
++ my $forcesuccess = 0;
++ my $max_runtime = 60; # hour by default
++ my $credentials = "";
++ my $jenkins_with_token = "";
++
++ GetOptions('h|help' => sub { pod2usage(1) }
++ , 'v|verbose' => sub { $verbose = 1 }
++ , 'forcesuccess' => sub { $forcesuccess = 1 }
++ , 'u|url=s' => \$jenkins
++ , 'j|job=s' => \$job
++ , 'a|job_args=s' => \$job_params # Argments when trigering jenkins job
++ , 'runtime=i' => \$max_runtime # in minutes
++ , 't|token=s' => \$credentials
++ , 'fireandforget|faf' => sub{ $fire_and_forget = 1 }
++ ) or pod2usage(1);
++
++ # If we are triggerin job which requires authetication, we need
++ # to keep the token private
++ if ($credentials ne "") {
++ open (my $FILE, "<", $credentials) or die "Can't open $credentials \n";
++ my @lines = <$FILE>;
++ my $user = $lines[0];
++ $user =~ s/\R//g;
++ my $token = $lines[1];
++ $token =~ s/\R//g;
++ close $FILE;
++ die "Invalid user credentials in $credentials file\n" if ($user eq"" || $token eq "");
++
++ my $cmd = "echo ${jenkins} | cut -d/ -f 3";
++ my $base_url = qx(${cmd});
++ $jenkins_with_token = "http://".$user.":".$token."\@".$base_url;
++ $jenkins_with_token =~ s/\R//g;
++ $jenkins = $jenkins_with_token;
++ }
++ # print params
++ # TODO make printable url, one without user:token, we don't want to share all secrets
++ my $public_url = "http://hidden.jenkins.server";
++ print " --> JENKINS : $public_url \n" if ($verbose);
++ print " --> PARAMS : $job_params \n" if ($verbose);
++ print " --> JOB : $job \n" if ($verbose);
++
++ ## Start selected build
++ sub start_build {
++ my $job_url = $jenkins."/job/".$job."/buildWithParameters\?".$job_params;
++ $job_url =~ s/"//g;
++ my $ua = LWP::UserAgent->new;
++ $ua->agent("RemoteTrigger/0.1 ");
++ my $req = HTTP::Request->new(GET => $job_url);
++ my $ret = $ua->request($req);
++ if (!$ret->is_success) {
++ print "Triggering $job failed\n";
++ exit -1;
++ }
++ print "Job URL was $public_url/job/$job/buildWithParameters?$job_params\n" if ($verbose);
++ print "Jenkins url params was $jenkins\n" if ($verbose);
++ print "Job params were $job_params\n" if ($verbose);
++ print "Job was $job\n" if ($verbose);
++ print "GET return was $ret\n" if ($verbose);
++ return;
++ }
++
++ ## Read from json api, where are we and what is going on
++ sub wait_for_me {
++ my $json_url = shift; #$jenkins."/job/".$job."/api/json";
++ my $state = shift;
++ my $ua = LWP::UserAgent->new;
++ my $req = HTTP::Request->new(GET => $json_url);
++ my $json = JSON::PP->new;
++ my $still_doing = 1;
++ my $data = "";
++ my $sleeptime = 2;
++ $sleeptime = 2 if ($state eq 'building'); # building takes longest
++
++ print "Start state \"$state\"\n";
++ while ($still_doing) {
++ sleep($sleeptime) if ($state ne 'result'); # no need to sleep if just checking result
++ my $resp = $ua->request($req);
++ if ($resp->is_success) {
++ my $message = $resp->decoded_content;
++ } else {
++ print "HTTP GET error code: ", $resp->code, "\n";
++ # Most likely we will fail die to this
++ return -1;
++ }
++ $data = $json->decode($resp->decoded_content);
++ print " Still \"$state\" \n" if ($state ne 'result');
++ $still_doing = $data->{$state};
++ $still_doing = 0 if ($state eq 'result');
++ }
++
++ if ($state eq 'result') {
++ print "Done state \"$state\" and result was $data->{$state}\n";
++ if ($data->{$state} ne "SUCCESS") {
++ return -1;
++ }
++ } else {
++ print "Done state \"$state\"\n";
++ }
++ return 1;
++ }
++
++ ## running
++ sub run {
++ start_build();
++ exit 0 if ($fire_and_forget); # no need to wait for exit nor build status
++ my $next = 1;
++ my $runtime = $max_runtime*60;
++ #make sure we will exit eventually, not to break whole job
++ timeout $runtime => sub {
++ $next = wait_for_me($jenkins."/job/".$job."/api/json","inQueue");
++ $next = wait_for_me($jenkins."/job/".$job."/lastBuild/api/json","building") if ($next == 1);
++ $next = wait_for_me($jenkins."/job/".$job."/lastBuild/api/json","result") if ($next == 1);
++ };
++ # timeout
++ if ($@) {
++ print "$public_url/job/$job. timed out \n";
++ $next = -1;
++ }
++ if ($next == -1) {
++ #make it possible to force to succeed
++ if ($forcesuccess == 1) {
++ print "Normally I would now fail, but I was forced to succeed\n";
++ exit 0;
++ } else {
++ print "Failure\n";
++ exit -1;
++ }
++ }
++ exit 0;
++ }
++
++ run() unless caller;
++
++
++ __END__
++
++ =head1 NAME
++
++ Script to execute job and wait for its result in remote jenkins.
++ If run without options, it will try to trigger dummy project on dev-ci.
++
++ =head1 SYNOPSIS
++
++ jenkins_job_trigger.pl [options]
++
++ =head1 OPTIONS
++
++ =item B<-u Remote_jenkins' URL>
++
++ URL to remote jenkins, default is Qt-project's dev-ci. Same as PUBLISHER_JENKINS
++ env variable. If -u option is givesn, env variable is not used.
++
++ =item B<-t Path to token file >
++
++ Path to file which contains jenkins' user name and its
++ secret token. The file should contain two lines:
++ user
++ token
++
++ =item B<-j job_name>
++
++ Name of the remote job. Same PUBLISHER_JOB env variable.
++ If -j is given env varible is not used.
++
++ =item B<-a Parameters for the job>
++
++ Parameters for the jenkins job. Same as PUBLISHER_PARAMS env variable.
++ If -a is given PUBLISHER_PARAMS env varible is not used.
++
++ =item B<-runtime Time in minutes>
++
++ Maximum runtime of remote job.
++
++ =item B<-forcesuccess>
++
++ Force successful exit in if the remotely triggered job fails.
++
++ =item B<-fireandforget|-faf>
++
++ Exit right after launching the remote job.
++
++ =item B<-v>
++
++ Print more logs.
++
++ =back
++
++ =head1 DESCRIPTION
++
++ Script to execute job and wait for its result in remote jenkins.
++
++ =cut