Skip to content

Instantly share code, notes, and snippets.

@MorrisJobke
Created May 8, 2019 13:34
Show Gist options
  • Select an option

  • Save MorrisJobke/ab0cd0c899d691384c67f7f4523e32de to your computer and use it in GitHub Desktop.

Select an option

Save MorrisJobke/ab0cd0c899d691384c67f7f4523e32de to your computer and use it in GitHub Desktop.

Revisions

  1. MorrisJobke created this gist May 8, 2019.
    121 changes: 121 additions & 0 deletions drone-cleanup.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,121 @@
    <?php
    /*
    Script that cleans up old builds of all repos of a drone server.
    Dependencies:
    $ # having PHP and composer installed
    $ composer require "guzzlehttp/guzzle=^6.3"
    Configuration:
    $ export DRONE_SERVER=https://drone.example.com
    $ export DRONE_TOKEN=yourDroneToken
    $ export DRONE_RETENTION_DAYS=60 # optional - by default this is 31
    Usage:
    $ php cleanup.php
    */

    require 'vendor/autoload.php';

    if (!getenv('DRONE_SERVER')) {
    echo "Please set environment variable DRONE_SERVER.\n";
    exit;
    }
    if (!getenv('DRONE_TOKEN')) {
    echo "Please set environment variable DRONE_TOKEN.\n";
    exit;
    }
    $RETENTION_DAYS = 31;
    if (getenv('DRONE_RETENTION_DAYS')) {
    $RETENTION_DAYS = getenv('DRONE_RETENTION_DAYS');
    }

    $DRONE_URL = getenv('DRONE_SERVER');
    $DRONE_TOKEN = getenv('DRONE_TOKEN');

    $client = new GuzzleHttp\Client([
    'headers' => [
    'Authorization' => 'Bearer ' . $DRONE_TOKEN,
    ],
    'base_uri' => $DRONE_URL,
    ]);

    function getRepos(\GuzzleHttp\Client $client): array {
    $res = $client->request('GET', '/api/user/repos');

    if ($res->getStatusCode() !== 200) {
    throw new \Exception('Non-200 status code');
    }

    $repos = json_decode($res->getBody(), true);
    $reposToCheck = [];

    foreach ($repos as $repo) {
    if ($repo['counter'] === 0) {
    continue;
    }
    $reposToCheck[] = $repo['slug'];
    }

    return $reposToCheck;
    }
    function getBuildNumber(\GuzzleHttp\Client $client, string $slug, int $days): int {

    $oneMonthAgo = time() - (60 * 60 * 24 * $days);

    $page = 1;
    $buildNumber = 0;
    do {
    $res = $client->request('GET', '/api/repos/' . $slug . '/builds?page=' . $page);
    $builds = json_decode($res->getBody(), true);

    $count = count($builds);
    if ($count !== 0 && $builds[$count - 1]['started'] < $oneMonthAgo) {
    foreach ($builds as $build) {
    if ($build['started'] < $oneMonthAgo) {
    $buildNumber = $build['number'];
    break;
    }
    }
    }

    $page += 1;

    } while ($count !== 0 && $buildNumber === 0);

    return $buildNumber;
    }

    echo "Fetching repos ...\n";
    $repos = getRepos($client);

    echo count($repos) . " repos found.\n";

    echo "Fetching builds older than $RETENTION_DAYS days.\n";

    foreach ($repos as $slug) {
    $buildNumber = getBuildNumber($client, $slug, $RETENTION_DAYS);

    if ($buildNumber !== 0) {
    echo "Deleting builds from $slug before or equal to $buildNumber\n";

    // deletion is based on "before NUMBER" so we add one, to delete the entry that is older than a month as well
    $buildNumber += 1;
    $res = $client->request('DELETE', "api/repos/$slug/builds?before=$buildNumber");

    if ($res->getStatusCode() !== 204) {
    "deletion of $slug with before=$buildNumber failed\n";
    echo $res->getBody();
    echo "\n\n";
    }
    } else {
    echo "Nothing to delete from $slug.\n";
    }
    }

    echo "Done.\n";