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());
|
|
}
|
|
?>
|