2010-09-02 12:21:56 +00:00
package Hydra::Controller::API ;
2013-02-25 21:04:10 +01:00
use utf8 ;
2010-09-02 12:21:56 +00:00
use strict ;
use warnings ;
2013-06-17 12:34:21 -04:00
use base 'Hydra::Base::Controller::REST' ;
2010-09-02 12:21:56 +00:00
use Hydra::Helper::Nix ;
use Hydra::Helper::CatalystUtils ;
use Hydra::Controller::Project ;
2013-02-26 01:14:50 +01:00
use JSON ;
2010-09-02 12:21:56 +00:00
use JSON::Any ;
use DateTime ;
2011-08-25 14:50:31 +00:00
use Digest::SHA qw( sha256_hex ) ;
2011-09-26 14:47:55 +00:00
use Text::Diff ;
use File::Slurp ;
2017-04-11 13:39:54 +02:00
use IPC::Run qw( run ) ;
2010-09-02 12:21:56 +00:00
2012-03-05 21:52:47 +01:00
2010-09-02 12:21:56 +00:00
sub api : Chained('/') PathPart('api') CaptureArgs(0) {
my ( $ self , $ c ) = @ _ ;
$ c - > response - > content_type ( 'application/json' ) ;
}
2012-03-05 21:52:47 +01:00
2010-09-02 12:21:56 +00:00
sub buildToHash {
my ( $ build ) = @ _ ;
my $ result = {
id = > $ build - > id ,
project = > $ build - > get_column ( "project" ) ,
jobset = > $ build - > get_column ( "jobset" ) ,
job = > $ build - > get_column ( "job" ) ,
system = > $ build - > system ,
nixname = > $ build - > nixname ,
finished = > $ build - > finished ,
timestamp = > $ build - > timestamp
} ;
2013-01-22 14:41:02 +01:00
if ( $ build - > finished ) {
2012-03-05 21:52:47 +01:00
$ result - > { 'buildstatus' } = $ build - > get_column ( "buildstatus" ) ;
2010-09-02 12:21:56 +00:00
} else {
$ result - > { 'priority' } = $ build - > get_column ( "priority" ) ;
}
2013-01-22 14:41:02 +01:00
2010-09-02 12:21:56 +00:00
return $ result ;
} ;
2012-03-05 21:52:47 +01:00
2010-09-02 12:21:56 +00:00
sub latestbuilds : Chained('api') PathPart('latestbuilds') Args(0) {
my ( $ self , $ c ) = @ _ ;
2012-03-05 21:52:47 +01:00
my $ nr = $ c - > request - > params - > { nr } ;
2010-09-02 12:21:56 +00:00
error ( $ c , "Parameter not defined!" ) if ! defined $ nr ;
2012-03-05 21:52:47 +01:00
my $ project = $ c - > request - > params - > { project } ;
my $ jobset = $ c - > request - > params - > { jobset } ;
my $ job = $ c - > request - > params - > { job } ;
my $ system = $ c - > request - > params - > { system } ;
2013-01-22 14:41:02 +01:00
2012-03-05 21:52:47 +01:00
my $ filter = { finished = > 1 } ;
2013-01-22 14:41:02 +01:00
$ filter - > { project } = $ project if ! $ project eq "" ;
$ filter - > { jobset } = $ jobset if ! $ jobset eq "" ;
$ filter - > { job } = $ job if ! $ job eq "" ;
$ filter - > { system } = $ system if ! $ system eq "" ;
2013-05-23 10:45:49 -04:00
my @ latest = $ c - > model ( 'DB::Builds' ) - > search ( $ filter , { rows = > $ nr , order_by = > [ "id DESC" ] } ) ;
2013-01-22 14:41:02 +01:00
2012-03-05 21:52:47 +01:00
my @ list ;
push @ list , buildToHash ( $ _ ) foreach @ latest ;
2013-01-22 14:41:02 +01:00
$ c - > stash - > { 'plain' } = {
data = > scalar ( JSON::Any - > objToJson ( \ @ list ) )
2010-09-02 12:21:56 +00:00
} ;
$ c - > forward ( 'Hydra::View::Plain' ) ;
}
2012-03-05 21:52:47 +01:00
2010-09-02 12:21:56 +00:00
sub jobsetToHash {
my ( $ jobset ) = @ _ ;
return {
2019-08-13 17:42:19 +02:00
project = > $ jobset - > get_column ( 'project' ) ,
2013-01-22 14:09:37 +01:00
name = > $ jobset - > name ,
2010-09-02 12:21:56 +00:00
nrscheduled = > $ jobset - > get_column ( "nrscheduled" ) ,
nrsucceeded = > $ jobset - > get_column ( "nrsucceeded" ) ,
nrfailed = > $ jobset - > get_column ( "nrfailed" ) ,
2019-08-16 16:03:01 +02:00
nrtotal = > $ jobset - > get_column ( "nrtotal" ) ,
lastcheckedtime = > $ jobset - > lastcheckedtime ,
starttime = > $ jobset - > starttime ,
checkinterval = > $ jobset - > checkinterval ,
triggertime = > $ jobset - > triggertime ,
fetcherrormsg = > $ jobset - > fetcherrormsg ,
2019-08-20 11:07:43 +02:00
errortime = > $ jobset - > errortime ,
2020-01-11 17:01:44 -08:00
haserrormsg = > defined ( $ jobset - > errormsg ) ? ( $ jobset - > errormsg eq "" ? JSON:: false : JSON:: true ) : JSON:: false
2010-09-02 12:21:56 +00:00
} ;
2013-01-22 14:41:02 +01:00
}
2010-09-02 12:21:56 +00:00
2012-03-05 21:52:47 +01:00
2010-09-02 12:21:56 +00:00
sub jobsets : Chained('api') PathPart('jobsets') Args(0) {
my ( $ self , $ c ) = @ _ ;
2012-03-05 21:52:47 +01:00
my $ projectName = $ c - > request - > params - > { project } ;
2010-09-02 12:21:56 +00:00
error ( $ c , "Parameter 'project' not defined!" ) if ! defined $ projectName ;
my $ project = $ c - > model ( 'DB::Projects' ) - > find ( $ projectName )
or notFound ( $ c , "Project $projectName doesn't exist." ) ;
my @ jobsets = jobsetOverview ( $ c , $ project ) ;
2013-01-22 14:41:02 +01:00
2012-03-05 21:52:47 +01:00
my @ list ;
push @ list , jobsetToHash ( $ _ ) foreach @ jobsets ;
2013-01-22 14:41:02 +01:00
$ c - > stash - > { 'plain' } = {
data = > scalar ( JSON::Any - > objToJson ( \ @ list ) )
2010-09-02 12:21:56 +00:00
} ;
$ c - > forward ( 'Hydra::View::Plain' ) ;
}
2012-03-05 21:52:47 +01:00
2010-09-02 12:21:56 +00:00
sub queue : Chained('api') PathPart('queue') Args(0) {
my ( $ self , $ c ) = @ _ ;
2012-03-05 21:52:47 +01:00
my $ nr = $ c - > request - > params - > { nr } ;
2010-09-02 12:21:56 +00:00
error ( $ c , "Parameter not defined!" ) if ! defined $ nr ;
2015-10-27 15:37:17 +01:00
my @ builds = $ c - > model ( 'DB::Builds' ) - > search ( { finished = > 0 } , { rows = > $ nr , order_by = > [ "priority DESC" , "id" ] } ) ;
2013-01-22 14:41:02 +01:00
2012-02-29 02:22:49 +01:00
my @ list ;
push @ list , buildToHash ( $ _ ) foreach @ builds ;
2013-01-22 14:41:02 +01:00
$ c - > stash - > { 'plain' } = {
data = > scalar ( JSON::Any - > objToJson ( \ @ list ) )
2010-09-02 12:21:56 +00:00
} ;
$ c - > forward ( 'Hydra::View::Plain' ) ;
}
2012-03-05 21:52:47 +01:00
2010-09-02 12:21:56 +00:00
sub nrqueue : Chained('api') PathPart('nrqueue') Args(0) {
my ( $ self , $ c ) = @ _ ;
2012-02-29 02:22:49 +01:00
my $ nrQueuedBuilds = $ c - > model ( 'DB::Builds' ) - > search ( { finished = > 0 } ) - > count ( ) ;
2013-01-22 14:41:02 +01:00
$ c - > stash - > { 'plain' } = {
2012-02-29 02:22:49 +01:00
data = > "$nrQueuedBuilds"
2010-09-02 12:21:56 +00:00
} ;
$ c - > forward ( 'Hydra::View::Plain' ) ;
}
2012-03-05 21:52:47 +01:00
2010-09-02 12:21:56 +00:00
sub nrbuilds : Chained('api') PathPart('nrbuilds') Args(0) {
my ( $ self , $ c ) = @ _ ;
2012-03-05 21:52:47 +01:00
my $ nr = $ c - > request - > params - > { nr } ;
my $ period = $ c - > request - > params - > { period } ;
2013-01-22 14:41:02 +01:00
2010-09-02 12:21:56 +00:00
error ( $ c , "Parameter not defined!" ) if ! defined $ nr || ! defined $ period ;
my $ base ;
2012-03-05 21:52:47 +01:00
my $ project = $ c - > request - > params - > { project } ;
my $ jobset = $ c - > request - > params - > { jobset } ;
my $ job = $ c - > request - > params - > { job } ;
my $ system = $ c - > request - > params - > { system } ;
2010-09-02 12:21:56 +00:00
2012-03-05 21:52:47 +01:00
my $ filter = { finished = > 1 } ;
2013-01-22 14:41:02 +01:00
$ filter - > { project } = $ project if ! $ project eq "" ;
$ filter - > { jobset } = $ jobset if ! $ jobset eq "" ;
$ filter - > { job } = $ job if ! $ job eq "" ;
$ filter - > { system } = $ system if ! $ system eq "" ;
2010-09-02 12:21:56 +00:00
$ base = 60 * 60 if ( $ period eq "hour" ) ;
$ base = 24 * 60 * 60 if ( $ period eq "day" ) ;
2013-01-22 14:41:02 +01:00
2012-03-05 21:52:47 +01:00
my @ stats = $ c - > model ( 'DB::Builds' ) - > search ( $ filter , { select = > [ { count = > "*" } ] , as = > [ "nr" ] , group_by = > [ "timestamp - timestamp % $base" ] , order_by = > "timestamp - timestamp % $base DESC" , rows = > $ nr } ) ;
my @ arr ;
push @ arr , int ( $ _ - > get_column ( "nr" ) ) foreach @ stats ;
2010-09-02 12:21:56 +00:00
@ arr = reverse ( @ arr ) ;
2013-01-22 14:41:02 +01:00
$ c - > stash - > { 'plain' } = {
data = > scalar ( JSON::Any - > objToJson ( \ @ arr ) )
2010-09-02 12:21:56 +00:00
} ;
$ c - > forward ( 'Hydra::View::Plain' ) ;
}
2012-03-05 21:52:47 +01:00
2017-05-05 15:58:38 +02:00
sub scmdiff : Path('/api/scmdiff') Args(0) {
2011-08-25 14:50:31 +00:00
my ( $ self , $ c ) = @ _ ;
2012-03-05 21:52:47 +01:00
my $ uri = $ c - > request - > params - > { uri } ;
my $ type = $ c - > request - > params - > { type } ;
my $ rev1 = $ c - > request - > params - > { rev1 } ;
my $ rev2 = $ c - > request - > params - > { rev2 } ;
2011-10-05 19:08:45 +00:00
2012-03-05 21:52:47 +01:00
die ( "invalid revisions: [$rev1] [$rev2]" ) if $ rev1 !~ m/^[a-zA-Z0-9_.]+$/ || $ rev2 !~ m/^[a-zA-Z0-9_.]+$/ ;
2011-08-25 14:50:31 +00:00
2013-05-25 15:36:58 -04:00
# FIXME: injection danger.
2011-08-25 14:50:31 +00:00
my $ diff = "" ;
2012-03-05 21:52:47 +01:00
if ( $ type eq "hg" ) {
2013-05-25 15:36:58 -04:00
my $ clonePath = getSCMCacheDir . "/hg/" . sha256_hex ( $ uri ) ;
2017-04-11 13:39:54 +02:00
die "repository '$uri' is not in the SCM cache\n" if ! - d $ clonePath ;
my $ out ;
run ( [ "hg" , "log" , "-R" , $ clonePath , "-r" , "reverse($rev1::$rev2) and not($rev1)" ] , \ undef , \ $ out )
or die "hg log failed" ;
$ diff . = $ out ;
run ( [ "hg" , "diff" , "-R" , $ clonePath , "-r" , "$rev1::$rev2" ] , \ undef , \ $ out )
or die "hg diff failed" ;
$ diff . = $ out ;
2011-08-25 14:50:31 +00:00
} elsif ( $ type eq "git" ) {
2013-05-25 15:36:58 -04:00
my $ clonePath = getSCMCacheDir . "/git/" . sha256_hex ( $ uri ) ;
2011-08-25 14:50:31 +00:00
die if ! - d $ clonePath ;
2013-01-22 14:09:37 +01:00
$ diff . = `(cd $clonePath; git log $rev1..$rev2)` ;
$ diff . = `(cd $clonePath; git diff $rev1..$rev2)` ;
2011-08-25 14:50:31 +00:00
}
$ c - > stash - > { 'plain' } = { data = > ( scalar $ diff ) || " " } ;
$ c - > forward ( 'Hydra::View::Plain' ) ;
}
2012-03-05 21:52:47 +01:00
2013-02-25 21:04:10 +01:00
sub triggerJobset {
2016-10-24 20:20:20 +02:00
my ( $ self , $ c , $ jobset , $ force ) = @ _ ;
2019-08-13 17:42:19 +02:00
print STDERR "triggering jobset " , $ jobset - > get_column ( 'project' ) . ":" . $ jobset - > name , "\n" ;
2013-02-25 21:04:10 +01:00
txn_do ( $ c - > model ( 'DB' ) - > schema , sub {
$ jobset - > update ( { triggertime = > time } ) ;
2016-10-24 20:20:20 +02:00
$ jobset - > update ( { forceeval = > 1 } ) if $ force ;
2013-02-25 21:04:10 +01:00
} ) ;
2019-08-13 17:42:19 +02:00
push @ { $ c - > { stash } - > { json } - > { jobsetsTriggered } } , $ jobset - > get_column ( 'project' ) . ":" . $ jobset - > name ;
2013-02-25 21:04:10 +01:00
}
sub push : Chained('api') PathPart('push') Args(0) {
my ( $ self , $ c ) = @ _ ;
$ c - > { stash } - > { json } - > { jobsetsTriggered } = [] ;
2013-05-02 11:21:43 -04:00
my $ force = exists $ c - > request - > query_params - > { force } ;
2013-02-26 00:38:18 +01:00
my @ jobsets = split /,/ , ( $ c - > request - > query_params - > { jobsets } // "" ) ;
2013-02-25 21:04:10 +01:00
foreach my $ s ( @ jobsets ) {
my ( $ p , $ j ) = parseJobsetName ( $ s ) ;
2013-02-26 01:45:59 +01:00
my $ jobset = $ c - > model ( 'DB::Jobsets' ) - > find ( $ p , $ j ) ;
2013-05-02 11:21:43 -04:00
next unless defined $ jobset && ( $ force || ( $ jobset - > project - > enabled && $ jobset - > enabled ) ) ;
2016-10-24 20:20:20 +02:00
triggerJobset ( $ self , $ c , $ jobset , $ force ) ;
2013-02-25 21:04:10 +01:00
}
2013-02-26 00:38:18 +01:00
my @ repos = split /,/ , ( $ c - > request - > query_params - > { repos } // "" ) ;
2013-02-25 21:04:10 +01:00
foreach my $ r ( @ repos ) {
2016-10-24 20:20:20 +02:00
triggerJobset ( $ self , $ c , $ _ , $ force ) foreach $ c - > model ( 'DB::Jobsets' ) - > search (
2013-02-25 21:04:10 +01:00
{ 'project.enabled' = > 1 , 'me.enabled' = > 1 } ,
{ join = > 'project'
, where = > \ [ 'exists (select 1 from JobsetInputAlts where project = me.project and jobset = me.name and value = ?)' , [ 'value' , $ r ] ]
} ) ;
}
2013-06-17 12:34:21 -04:00
$ self - > status_ok (
$ c ,
entity = > { jobsetsTriggered = > $ c - > stash - > { json } - > { jobsetsTriggered } }
) ;
2013-02-25 21:04:10 +01:00
}
2013-02-26 01:14:50 +01:00
sub push_github : Chained('api') PathPart('push-github') Args(0) {
my ( $ self , $ c ) = @ _ ;
$ c - > { stash } - > { json } - > { jobsetsTriggered } = [] ;
2013-03-04 15:25:23 +01:00
2016-06-14 10:36:43 +01:00
my $ in = $ c - > request - > { data } ;
2013-02-26 01:14:50 +01:00
my $ owner = $ in - > { repository } - > { owner } - > { name } or die ;
my $ repo = $ in - > { repository } - > { name } or die ;
print STDERR "got push from GitHub repository $owner/$repo\n" ;
2013-03-04 15:25:23 +01:00
2016-10-24 20:20:20 +02:00
triggerJobset ( $ self , $ c , $ _ , 0 ) foreach $ c - > model ( 'DB::Jobsets' ) - > search (
2013-02-26 01:14:50 +01:00
{ 'project.enabled' = > 1 , 'me.enabled' = > 1 } ,
{ join = > 'project'
2016-08-16 23:00:09 +01:00
, where = > \ [ 'exists (select 1 from JobsetInputAlts where project = me.project and jobset = me.name and value like ?)' , [ 'value' , "%github.com%$owner/$repo%" ] ]
2013-02-26 01:14:50 +01:00
} ) ;
2016-08-17 00:13:06 +02:00
$ c - > response - > body ( "" ) ;
2013-02-26 01:14:50 +01:00
}
2010-09-02 12:21:56 +00:00
1 ;