325 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			PHP
		
	
	
	
			
		
		
	
	
			325 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			PHP
		
	
	
	
| <?php
 | |
| include("token.php");
 | |
| include("functions.php");
 | |
| include("config.php");
 | |
| if (! isset($CI_TOKEN)) die("no token");
 | |
| const apiBase="https://circleci.com/api/v2/";
 | |
| const webApp="https://app.circleci.com/";
 | |
| const apiRepo="project/gh/#user#/#repo#";
 | |
| const workflowName="build-workflow";
 | |
| const jobName="pio-build";
 | |
| const defaultBranch='master';
 | |
| const defaultUser='wellenvogel';
 | |
| const defaultRepo='esp32-nmea2000';
 | |
| const TABLENAME="CIBUILDS";
 | |
| const KEEPINTERVAL="30"; //days
 | |
| 
 | |
| function getTokenHeaders(){
 | |
|     global $CI_TOKEN;
 | |
|     return array('Circle-Token'=>$CI_TOKEN);
 | |
| }
 | |
| function getPipeline($pipeline){
 | |
|     $url=apiBase."/pipeline/$pipeline";
 | |
|     $token=getTokenHeaders();
 | |
|     return getJson($url,$token,true);
 | |
| }
 | |
| function getWorkflow($pipeline,$workflowName){
 | |
|     $url=apiBase."/pipeline/$pipeline/workflow";
 | |
|     $token=getTokenHeaders();
 | |
|     $pstate=getJson($url,$token,true);
 | |
|     if (! isset($pstate['items'])){
 | |
|         throw new Exception("no workflows in pipeline");
 | |
|     }
 | |
|     foreach ($pstate['items'] as $workflow){
 | |
|         if (isset($workflow['name']) && $workflow['name'] == $workflowName){
 | |
|             if (!isset($workflow['id'])){
 | |
|                 throw new Exception("no workflow id found");
 | |
|             }
 | |
|             return $workflow;
 | |
|         }
 | |
|     }
 | |
|     throw new Exception("workflow $workflowName not found");
 | |
| }
 | |
| function getJob($pipeline,$workflow,$jobName){
 | |
|     $url=apiBase."/workflow/".$workflow."/job";
 | |
|     $token=getTokenHeaders();
 | |
|     $wstate=getJson($url,$token,true);
 | |
|     if (! isset($wstate['items'])){
 | |
|         throw new Exception("no jobs in workflow");
 | |
|     }
 | |
|     foreach ($wstate['items'] as $job){
 | |
|         if (isset($job['name']) && $job['name'] == $jobName){
 | |
|             if (! isset($job['id'])){
 | |
|                 throw new Exception("no job id found");
 | |
|             }
 | |
|             return $job;
 | |
|         }
 | |
|     }
 | |
|     throw new Exception("job $jobName not found");
 | |
| }
 | |
| function getJobStatus($pipeline,$wf=workflowName,$job=jobName){
 | |
|     $pstat=getPipeline($pipeline);
 | |
|     if (isset($pstat['error'])){
 | |
|         throw new Exception($pstat["error"]);
 | |
|     }
 | |
|     if (! isset($pstat['state'])){
 | |
|         throw new Exception("state not set");
 | |
|     }
 | |
|     if ($pstat['state'] != 'created'){
 | |
|         return $pstat;
 | |
|     }
 | |
|     $pipeline_id=$pstat['id'];
 | |
|     $pipeline_number=$pstat['number'];
 | |
|     $vcs=$pstat['vcs'];
 | |
|     $pstat=getWorkflow($pipeline,$wf);
 | |
|     $workflow_id=$pstat['id'];
 | |
|     $workflow_number=$pstat['workflow_number'];
 | |
|     $pstat=getJob($pipeline,$pstat['id'],$job);
 | |
|     $pstat['pipeline_id']=$pipeline_id;
 | |
|     $pstat['pipeline_number']=$pipeline_number;
 | |
|     $pstat['workflow_id']=$workflow_id;
 | |
|     $pstat['workflow_number']=$workflow_number;
 | |
|     if (isset($pstat['project_slug'])){
 | |
|         $pstat['status_url']=webApp."/pipelines/".
 | |
|             preg_replace('/^gh/','github',$pstat['project_slug'])."/".
 | |
|             $pipeline_number."/workflows/".$workflow_id."/jobs/".$pstat['job_number'];
 | |
|     }
 | |
|     $pstat['vcs']=$vcs;
 | |
|     return $pstat;
 | |
| }
 | |
| 
 | |
| function getArtifacts($job,$slug){
 | |
|     $url=apiBase."/project/$slug/$job/artifacts";
 | |
|     return getJson($url,getTokenHeaders(),true);
 | |
| }
 | |
| 
 | |
| function insertPipeline($id,$requestParam){
 | |
|     $database=openDb();
 | |
|     if (! isset($database)) return false;
 | |
|     $param=$requestParam['parameters'];
 | |
|     try {
 | |
|         $status='created';
 | |
|         $tag=null;
 | |
|         if (isset($requestParam['tag'])) $tag=$requestParam['tag'];
 | |
|         $stmt = $database->prepare("INSERT into " . TABLENAME .
 | |
|             "(id,status,config,environment,buildflags,tag) VALUES (?,?,?,?,?,?)");
 | |
|         $stmt->bind_param("ssssss",
 | |
|         $id,
 | |
|         $status,
 | |
|         $param['config'],
 | |
|         $param['environment'],
 | |
|         $param['build_flags'],
 | |
|         $tag);
 | |
|         $stmt->execute();
 | |
|         $database->query("DELETE from ". TABLENAME. " where timestamp < NOW() - interval ". KEEPINTERVAL. " DAY");
 | |
|         return true;
 | |
|     } catch (Exception $e) {
 | |
|         error_log("insert pipeline $id failed: $e");
 | |
|         return false;
 | |
|     }
 | |
| }
 | |
| function updatePipeline($id,$status,$tag=null){
 | |
|     $database=openDb();
 | |
|     if (! isset($database)) return false;
 | |
|     try{
 | |
|         $stmt=null;
 | |
|         if ($tag != null){
 | |
|             $stmt=$database->prepare("UPDATE ".TABLENAME." SET status=?,tag=? where id=? and ( status <> ? or tag <> ?)");
 | |
|             $stmt->bind_param("sssss",$status,$tag,$id,$status,$tag);
 | |
|             $stmt->execute();
 | |
|         }
 | |
|         else{
 | |
|             $stmt=$database->prepare("UPDATE ".TABLENAME." SET status=? where id=? AND status <> ?");
 | |
|             $stmt->bind_param("sss",$status,$id,$status);
 | |
|             $stmt->execute();
 | |
|         }
 | |
| 
 | |
|     }catch (Exception $e){
 | |
|         error_log("update pipeline $id failed: $e");
 | |
|         return false;
 | |
|     }
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| function findPipeline($param)
 | |
| {
 | |
|     $database=openDb();
 | |
|     if (!isset($database))
 | |
|         return false;
 | |
|     try {
 | |
|         $stmt = null;
 | |
|         $database->query("DELETE from ". TABLENAME. " where timestamp < NOW() - interval ". KEEPINTERVAL. " DAY");
 | |
|         if (isset($param['tag'])) {
 | |
|             $stmt = $database->prepare("SELECT id,UNIX_TIMESTAMP(timestamp) from " . TABLENAME .
 | |
|                 " where status IN('success','running','created') and environment=? and buildflags=? and tag=? order by timestamp desc");
 | |
|             $stmt->bind_param("sss", $param['environment'], $param['buildflags'], $param['tag']);
 | |
|         } else {
 | |
|             $stmt = $database->prepare("SELECT id,UNIX_TIMESTAMP(timestamp) from " . TABLENAME .
 | |
|                 " where status IN('success','running','created') and environment=? and buildflags=? order by timestamp desc");
 | |
|             $stmt->bind_param("ss", $param['environment'], $param['buildflags']);
 | |
|         }
 | |
|         $stmt->execute();
 | |
|         $id=null;
 | |
|         $timestamp=null;
 | |
|         $stmt->bind_result($id,$timestamp);
 | |
|         if ($stmt->fetch()){
 | |
|             return array('pipeline'=>$id,'timestamp'=>$timestamp);
 | |
|         }
 | |
|         return false;
 | |
|     } catch (Exception $e) {
 | |
|         error_log("find pipeline failed: $e");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
| }
 | |
| 
 | |
| function getArtifactsForPipeline($pipeline,$wf=workflowName,$job=jobName){
 | |
|     $jstat=getJobStatus($pipeline,$wf,$job);
 | |
|     if (! isset($jstat['job_number'])){
 | |
|         throw new Exception("no job number");
 | |
|     }
 | |
|     if (! isset($jstat['status'])){
 | |
|         throw new Exception("no job status");
 | |
|     }
 | |
|     if ($jstat['status'] != 'success'){
 | |
|         throw new Exception("invalid job status ".$jstat['status']);
 | |
|     }
 | |
|     $astat=getArtifacts($jstat['job_number'],$jstat['project_slug']);
 | |
|     return $astat;
 | |
| }
 | |
| try {
 | |
|     if (isset($_REQUEST['api'])) {
 | |
|         $action = $_REQUEST['api'];
 | |
|         header("Content-Type: application/json");
 | |
|         $par = array();
 | |
|         if ($action == 'status') {
 | |
|             addVars(
 | |
|                 $par,
 | |
|                 ['pipeline', 'workflow', 'job'],
 | |
|                 array('workflow' => workflowName, 'job' => jobName)
 | |
|             );
 | |
|             try {
 | |
|                 $pstat = getJobStatus($par['pipeline'], $par['workflow'], $par['job']);
 | |
|                 if (isset($pstat['vcs'])){
 | |
|                     updatePipeline($par['pipeline'],$pstat['status'],$pstat['vcs']['revision']);
 | |
|                 }
 | |
|                 else{
 | |
|                     updatePipeline($par['pipeline'],$pstat['status']);
 | |
|                 }
 | |
|                 echo (json_encode($pstat));
 | |
|             } catch (Exception $e) {
 | |
|                 $rt = array('status' => 'error', 'error' => $e->getMessage());
 | |
|                 echo (json_encode($rt));
 | |
|             }
 | |
|             exit(0);
 | |
|         }
 | |
|         if ($action == 'artifacts') {
 | |
|             addVars(
 | |
|                 $par,
 | |
|                 ['pipeline', 'workflow', 'job'],
 | |
|                 array('workflow' => workflowName, 'job' => jobName)
 | |
|             );
 | |
|             try {
 | |
|                 $astat = getArtifactsForPipeline($par['pipeline'], $par['workflow'], $par['job']);
 | |
|                 echo (json_encode($astat));
 | |
|             } catch (Exception $e) {
 | |
|                 echo (json_encode(array('status' => 'error', 'error' => $e->getMessage())));
 | |
|             }
 | |
|             exit(0);
 | |
|         }
 | |
|         if ($action == 'pipeline'){
 | |
|             addVars(
 | |
|                 $par,
 | |
|                 ['number','user','repo'],
 | |
|                 array('user'=>defaultUser,'repo'=>defaultRepo)
 | |
|             );
 | |
|             $url=apiBase."/".replaceVars(apiRepo,fillUserAndRepo(null,$par))."/pipeline/".$par['number'];
 | |
|             $rt=getJson($url,getTokenHeaders(),true);
 | |
|             echo(json_encode($rt));
 | |
|             exit(0);
 | |
|         }
 | |
|         if ($action == 'pipelineuuid'){
 | |
|             addVars(
 | |
|                 $par,
 | |
|                 ['pipeline']
 | |
|             );
 | |
|             $url=apiBase."/pipeline/".$par['pipeline'];
 | |
|             $rt=getJson($url,getTokenHeaders(),true);
 | |
|             echo(json_encode($rt));
 | |
|             exit(0);
 | |
|         }
 | |
|         if ($action == 'start'){
 | |
|             addVars(
 | |
|                 $par,
 | |
|                 ['environment','buildflags','config','suffix','user','repo'],
 | |
|                 array('suffix'=>'',
 | |
|                     'config'=>'{}',
 | |
|                     'user'=>defaultUser,
 | |
|                     'repo'=>defaultRepo,
 | |
|                     'buildflags'=>''
 | |
|                     )
 | |
|             );
 | |
|             $requestParam=array(
 | |
|                 'parameters'=> array(
 | |
|                     'run_build'=>true,
 | |
|                     'environment'=>$par['environment'],
 | |
|                     'suffix'=>$par['suffix'],
 | |
|                     'config'=>$par['config'],
 | |
|                     'build_flags'=>$par['buildflags']
 | |
|                 )
 | |
|             );
 | |
|             if (isset($_REQUEST['tag'])){
 | |
|                 $requestParam['tag']=safeName($_REQUEST['tag']);
 | |
|             }
 | |
|             else{
 | |
|                 $requestParam['branch']=defaultBranch;
 | |
|             }
 | |
|             $userRepo=fillUserAndRepo(null,$par);
 | |
|             $url=apiBase."/".replaceVars(apiRepo,$userRepo)."/pipeline";
 | |
|             $rt=getJson($url,getTokenHeaders(),true,$requestParam);
 | |
|             insertPipeline($rt['id'],$requestParam);
 | |
|             echo (json_encode($rt));
 | |
|             exit(0);
 | |
|         }
 | |
|         throw new Exception("invalid api $action");
 | |
|     }
 | |
|     if (isset($_REQUEST['download'])) {
 | |
|         $pipeline = $_REQUEST['download'];
 | |
|         $par = array('pipeline' => $pipeline);
 | |
|         addVars(
 | |
|             $par,
 | |
|             ['workflow', 'job'],
 | |
|             array('workflow' => workflowName, 'job' => jobName)
 | |
|         );
 | |
|         $astat = getArtifactsForPipeline($par['pipeline'], $par['workflow'], $par['job']);
 | |
|         if (!isset($astat['items']) || count($astat['items']) < 1) {
 | |
|             die("no artifacts for job");
 | |
|         }
 | |
|         $dlurl = $astat['items'][0]['url'];
 | |
|         #echo("DL: $dlurl\n");
 | |
|         header('Content-Disposition: attachment; filename="'.$astat['items'][0]['path'].'"');
 | |
|         proxy($dlurl);
 | |
|         exit(0);
 | |
|     }
 | |
|     if (isset($_REQUEST['find'])){
 | |
|         $par=array();
 | |
|         addVars($par,['environment','buildflags']);
 | |
|         if (isset($_REQUEST['tag'])) $par['tag']=$_REQUEST['tag'];
 | |
|         $rt=findPipeline($par);
 | |
|         header("Content-Type: application/json");
 | |
|         if (!$rt){
 | |
|             $rt=array();
 | |
|         }
 | |
|         $rt['status']='OK';
 | |
|         echo(json_encode($rt));
 | |
|         exit(0);
 | |
|     }
 | |
|     die("no action");
 | |
| } catch (HTTPErrorException $h) {
 | |
|     header($_SERVER['SERVER_PROTOCOL'] . " " . $h->code . " " . $h->getMessage());
 | |
|     die($h->getMessage());
 | |
| } catch (Exception $e) {
 | |
|     header($_SERVER['SERVER_PROTOCOL'] . ' 500 ' . $e->getMessage());
 | |
|     die($e->getMessage());
 | |
| }
 | |
| ?>
 |