Skip to content

Instantly share code, notes, and snippets.

@jkoop
Last active May 31, 2022 19:26
Show Gist options
  • Save jkoop/afc386f5742c2b61bf9657577b974449 to your computer and use it in GitHub Desktop.
Save jkoop/afc386f5742c2b61bf9657577b974449 to your computer and use it in GitHub Desktop.
Burndown chart for GitLab milestones with basic tier
<!-- https://gist.github.com/jkoop/afc386f5742c2b61bf9657577b974449 -->
<?php if (isset($_GET['access_token']) && isset($_GET['project_id']) && isset($_GET['milestone_name'])) : ?>
<meta http-equiv="refresh" content="3600"> <!-- refresh every 1 hour -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdn.jsdelivr.net/npm/chart.js@^3"></script>
<script src="https://cdn.jsdelivr.net/npm/moment@^2"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment@^1"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-annotation@^1/dist/chartjs-plugin-annotation.min.js"></script>
<div id="canvas_parent" style="position:absolute;left:0;top:0;width:100vw;height:100vh">
<canvas id="chart" style="position:absolute;left:0;top:0;width:100%;height:100%"></canvas>
</div>
<script>
stats = <?php
$response = file_get_contents('https://gitlab.com/api/v4/projects/' . $_GET['project_id'] . '/issues?access_token=' . $_GET['access_token'] . '&milestone=' . urlencode($_GET['milestone_name']));
$issues = json_decode($response);
if (!$issues) {
echo '[];';
echo 'document.getElementById("canvas_parent").innerText = ' . json_encode("Hint: https://gitlab.com/-/profile/personal_access_tokens\nGot response: $response") . ';';
echo 'document.getElementById("canvas_parent").style.top = "50px";';
echo 'document.getElementById("canvas_parent").style.height = "calc(100vh - 50px)";';
echo 'document.getElementById("canvas_parent").style.fontFamily = "monospace";';
}
$events = [
// ['date' => 1234567890, 'diff' => (1 | -1)],
// ...
];
foreach ($issues as $issue) {
$events[] = [
'date' => strtotime($issue->created_at),
'diff' => 1,
];
if (isset($issue->closed_at)) {
$events[] = [
'date' => strtotime($issue->closed_at),
'diff' => -1,
];
}
}
sort($events);
$burndown = [
// ['date' => 1234567890, 'total_open' => 123],
// ...
];
foreach ($events as $event) {
$burndown[] = [
'date' => $event['date'] * 1000, // for javascript
'total_open' => ($burndown[count($burndown) - 1] ?? ['total_open' => 0])['total_open'] + $event['diff'],
];
}
echo json_encode($burndown);
?>;
</script>
<script>
var ctx = document.getElementById('chart').getContext('2d');
var chart = new Chart(ctx, {
type: 'line',
maintainAspectRatio: false,
animations: {
duration: 0,
},
data: {
labels: stats.map(stat => stat.date),
datasets: [{
label: <?= json_encode('Issues open - ' . $_GET['milestone_name']) ?>,
data: stats.map(stat => stat.total_open),
backgroundColor: '#f333',
borderColor: '#f33',
borderWidth: 1,
fill: 'start',
stepped: true,
}]
},
options: {
scales: {
x: {
type: 'time',
time: {
displayFormats: {
hour: 'MMM D ha',
},
},
max: <?= time() * 1000 ?>,
},
y: {
min: 0,
},
},
},
});
</script>
<?php endif ?>
<form style="position:relative">
<input name="access_token" placeholder="Personal Access Token (aaaaaaaaaaaaaaaaaaaaaaaaaa)" value="<?= htmlentities($_GET['access_token'] ?? '') ?>" />
<input name="project_id" placeholder="Project ID (11111111)" type="number" value="<?= htmlentities($_GET['project_id'] ?? '') ?>" />
<input name="milestone_name" placeholder="Milestone Name (Write tests)" value="<?= htmlentities($_GET['milestone_name'] ?? '') ?>" />
<button>Go!</button>
</form>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment