239 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			239 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
	define("MICOBU_BASE", "/opt/micobu/rootfs/home/builduser/artefacts");
 | 
						|
	define("MICOBU_BASE_LINK", "./artefacts");
 | 
						|
 | 
						|
	class micobu_build {
 | 
						|
		public $hash;
 | 
						|
		public $result;
 | 
						|
		public $time_start;
 | 
						|
		public $time_stop;
 | 
						|
		public $project;
 | 
						|
	}
 | 
						|
	class micobu_project {
 | 
						|
		public $name;
 | 
						|
		public $builds;
 | 
						|
	}
 | 
						|
 | 
						|
	function glob_sorted_mtime($dir) {
 | 
						|
		$ar = [];
 | 
						|
		array_multisort(array_map('filemtime', ($files = glob("$dir/*", GLOB_ONLYDIR))), SORT_DESC, $files);
 | 
						|
		foreach($files as $filename)
 | 
						|
		{
 | 
						|
			$ar[] = $filename;
 | 
						|
		}
 | 
						|
		return $ar;
 | 
						|
	}
 | 
						|
 | 
						|
	function scan_build(&$project, $hash) {
 | 
						|
		$build = new micobu_build();
 | 
						|
 | 
						|
		$build->hash = $hash;
 | 
						|
		$build->result = -1;
 | 
						|
		$build->project = $project;
 | 
						|
 | 
						|
		$file = MICOBU_BASE . "/". $project->name . "/" . $hash . "/meta.json";
 | 
						|
		if (file_exists($file)) {
 | 
						|
			$json = json_decode(file_get_contents($file));
 | 
						|
			$build->hash = $json->hash;
 | 
						|
			$build->result = $json->result;
 | 
						|
			$build->time_start = $json->time_start;
 | 
						|
			$build->time_stop = $json->time_stop;
 | 
						|
			$build->description = $json->description;
 | 
						|
		}
 | 
						|
 | 
						|
		return $build;
 | 
						|
	}
 | 
						|
 | 
						|
	function scan_project($name) {
 | 
						|
		$project = new micobu_project();
 | 
						|
		$project->name = $name;
 | 
						|
		$project->builds = array();
 | 
						|
 | 
						|
		$dirs = glob_sorted_mtime(MICOBU_BASE . "/" . $name);
 | 
						|
		foreach ($dirs as $dir) {
 | 
						|
			$hash = basename($dir);
 | 
						|
			$project->builds += array($hash => scan_build($project, $hash));
 | 
						|
		}
 | 
						|
 | 
						|
		return $project;
 | 
						|
	}
 | 
						|
 | 
						|
	function micobu_scan() {
 | 
						|
		$projects = array();
 | 
						|
		foreach (glob(MICOBU_BASE . "/*", GLOB_ONLYDIR) as $project_path) {
 | 
						|
			$project_name = basename($project_path);
 | 
						|
			$projects += array($project_name => scan_project($project_name));
 | 
						|
		}
 | 
						|
		return $projects;
 | 
						|
	}
 | 
						|
 | 
						|
	function micobu_get_trend($project) {
 | 
						|
		foreach ($project->builds as $build) {
 | 
						|
			if ($build->result > 0)
 | 
						|
				return "<span title='failed'>❌</span>";
 | 
						|
			else
 | 
						|
				return "<span title='success'>✅</span>";
 | 
						|
		}
 | 
						|
		return "⌛";
 | 
						|
		return "🔼";
 | 
						|
		return "❗";
 | 
						|
	}
 | 
						|
 | 
						|
	function micobu_get_build_icon($build, $verbose = false) {
 | 
						|
		$verb = ($verbose ? ($build->result > 0 ? " Build failed with return code " . $build->result : " Build succeeded") : "");
 | 
						|
		if ($build->result > 0)
 | 
						|
			return "<span title='Build failed with return code $build->result'>❌</span>$verb";
 | 
						|
		else
 | 
						|
			return "<span title='Build succeeded'>✅</span>";
 | 
						|
	}
 | 
						|
 | 
						|
	function micobu_get_build_time($build) {
 | 
						|
		return gmdate("i\m s\s", $build->time_stop - $build->time_start);
 | 
						|
	}
 | 
						|
 | 
						|
	function micobu_get_weblink($build, $filename) {
 | 
						|
		return MICOBU_BASE_LINK . "/" . $build->project->name . "/" . $build->hash . "/" . $filename;
 | 
						|
	}
 | 
						|
 | 
						|
	function micobu_get_dl_buttons($build) {
 | 
						|
		return "<a title='Show log file' href='" . micobu_get_weblink($build, "log.txt") . "'>📰</a> <a title='Show meta info' href='" . micobu_get_weblink($build, "meta.json") . "'>🛈</a> <a title='Show artefacts' href='" . micobu_get_weblink($build, "") . "'>📂</a>";
 | 
						|
	}
 | 
						|
 | 
						|
	$projects = micobu_scan();
 | 
						|
 | 
						|
	if (isset($_GET['p'])) {
 | 
						|
		$selected_project = $_GET['p'];
 | 
						|
		preg_match("/^[_\-A-Za-z0-9]{1,20}$/", $selected_project, $matches);
 | 
						|
		if (!$matches)
 | 
						|
			die("Invalid request.");
 | 
						|
		if (!isset($projects[$selected_project]))
 | 
						|
			die("Invalid project.");
 | 
						|
 | 
						|
		if (isset($_GET['h'])) {
 | 
						|
			$selected_hash = $_GET['h'];
 | 
						|
			preg_match("/^[_\-A-Za-z0-9]{1,40}$/", $selected_hash, $matches);
 | 
						|
			if (!$matches)
 | 
						|
				die("Invalid request.");
 | 
						|
			if (!isset($projects[$selected_project]->builds[$selected_hash]))
 | 
						|
				die("Invalid hash.");
 | 
						|
		}
 | 
						|
	}
 | 
						|
?>
 | 
						|
 | 
						|
<!DOCTYPE html>
 | 
						|
<html>
 | 
						|
	<!--
 | 
						|
		Hi there, curious person!
 | 
						|
 | 
						|
		This is the source code of Micobu's web dashboard.
 | 
						|
		You can find more information on this system on:
 | 
						|
		  https://git.notsyncing.net/markus/micobu
 | 
						|
	-->
 | 
						|
	<head>
 | 
						|
		<style>
 | 
						|
			body {
 | 
						|
				font-family: sans-serif;
 | 
						|
				background-color: #111;
 | 
						|
				color: #CCC;
 | 
						|
			}
 | 
						|
			table {
 | 
						|
				background-color: #222;
 | 
						|
				border-radius: 8px;
 | 
						|
				font-size: 20pt;
 | 
						|
				border: 1px solid black;
 | 
						|
				width: 100%;
 | 
						|
			}
 | 
						|
			tr:hover {
 | 
						|
				background-color: #555;
 | 
						|
			}
 | 
						|
			td {
 | 
						|
				border: 1px dotted black;
 | 
						|
			}
 | 
						|
			a {
 | 
						|
				color: inherit;
 | 
						|
				text-decoration: none;
 | 
						|
			}
 | 
						|
			.footer {
 | 
						|
				margin: 8px;
 | 
						|
				color: #666;
 | 
						|
				text-align: right;
 | 
						|
			}
 | 
						|
			.logframe {
 | 
						|
				width: 98vw;
 | 
						|
				margin-left: auto;
 | 
						|
				margin-right: auto;
 | 
						|
			}
 | 
						|
			.log {
 | 
						|
				font-size: 14pt;
 | 
						|
				font-family: monospace;
 | 
						|
				white-space: pre;
 | 
						|
				overflow-x: scroll;
 | 
						|
			}
 | 
						|
			.tdnohighlight:hover {
 | 
						|
				background-color: #222;
 | 
						|
			}
 | 
						|
		</style>
 | 
						|
		<script>
 | 
						|
			function escapeHtml(text) {
 | 
						|
				var map = {
 | 
						|
					'&': '&',
 | 
						|
					'<': '<',
 | 
						|
					'>': '>',
 | 
						|
					'"': '"',
 | 
						|
					"'": '''
 | 
						|
				};
 | 
						|
				return text.replace(/[&<>"']/g, function(m) { return map[m]; });
 | 
						|
			}
 | 
						|
		</script>
 | 
						|
	</head>
 | 
						|
	<body>
 | 
						|
<?php
 | 
						|
	$dpath = (isset($selected_project) ? " / <a href='?p=$selected_project'>$selected_project</a>" : "");
 | 
						|
	$dpath .= (isset($selected_hash) ? " / $selected_hash" : "");
 | 
						|
	echo "<h1><a href='?'>Micobu CI Dashboard</a>$dpath</h1>";
 | 
						|
?>
 | 
						|
		<div>
 | 
						|
<?php
 | 
						|
	if (isset($selected_hash)) {
 | 
						|
		//var_dump($projects[$selected_project]->builds[$selected_hash]);
 | 
						|
		$build = $projects[$selected_project]->builds[$selected_hash];
 | 
						|
		echo "<table>";
 | 
						|
		echo "<tr><td>Build status</td><td>" . micobu_get_build_icon($build, true). "</td></tr>";
 | 
						|
		echo "<tr><td>Build time</td><td>" . micobu_get_build_time($build) . "</td></tr>";
 | 
						|
		echo "<tr><td>Commit info</td><td>" . $build->hash . " (" . $build->description . ")</td></tr>";
 | 
						|
		echo "<tr><td>Download</td><td>" . micobu_get_dl_buttons($build) . "</td></tr>";
 | 
						|
?>
 | 
						|
<tr><td class="tdnohighlight" colspan=2><hr></td></tr>
 | 
						|
<tr><td class="tdnohighlight" colspan=2><div class='logframe'><div class='log' id='buildlog'>Loading log...</div></div></td></tr>
 | 
						|
<script>
 | 
						|
	var xhttp_ps = new XMLHttpRequest();
 | 
						|
	xhttp_ps.onreadystatechange = function() {
 | 
						|
		if (this.readyState == 4)
 | 
						|
			document.getElementById("buildlog").innerHTML = (this.status == 200 ? escapeHtml(xhttp_ps.responseText) : "Error loading log.");
 | 
						|
	};
 | 
						|
	xhttp_ps.open("GET", "<?php echo MICOBU_BASE_LINK . "/$selected_project/$selected_hash/log.txt"; ?>", true);
 | 
						|
	xhttp_ps.send();
 | 
						|
</script>
 | 
						|
<?php
 | 
						|
		echo "</table>";
 | 
						|
	} else if (isset($selected_project)) {
 | 
						|
		echo "<table>";
 | 
						|
		foreach ($projects[$selected_project]->builds as $hash => $build) {
 | 
						|
			echo "<tr><td><a href='?p=$selected_project&h=$hash'>" . date(DATE_RFC2822, $build->time_start) . "</a></td><td>" . micobu_get_build_icon($build) . "</td><td><a title='$build->hash'href='?p=$selected_project&h=$hash'>" . $build->description . "</a></td><td>" . micobu_get_dl_buttons($build) . "</td></tr>";
 | 
						|
		}
 | 
						|
		echo "</table>";
 | 
						|
	} else {
 | 
						|
		echo "<table>";
 | 
						|
		foreach ($projects as $project) {
 | 
						|
			echo "<tr><td><a href='?p=" . $project->name ."'>" . $project->name . "</a></td><td>" . micobu_get_trend($project) . "</td></tr>";
 | 
						|
		}
 | 
						|
		echo "</table>";
 | 
						|
	}
 | 
						|
?>
 | 
						|
		</div>
 | 
						|
		<div class="footer">
 | 
						|
<?php
 | 
						|
	echo "Processed " . count($projects) . " repositories in " . round((microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"]) * 1000, 1) . " ms.";
 | 
						|
?>
 | 
						|
		</div>
 |