Deleting GitHub Actions artifacts using the GitHub REST API

  • Gérald Barré

GitHub Actions supports sharing data between jobs in any workflow as artifacts. This is very convenient but the storage is limited (or you have to pay for it). If you use too much storage, you may get one of those notifications:

You've used 75% of included services for GitHub Storage (GitHub Actions and Packages)

One way to free storage space is to delete GitHub Actions artifacts. You can do it manually, but this is tedious if you have lots of workflow runs. The easiest way is to create a script that deletes all artifacts automatically. You can use the GitHub API to list all artifacts and then delete them.

Let's create a new .NET console application

Shell
dotnet new console
C#
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json.Serialization;

// https://github.com/settings/tokens/new
const string GithubToken = "ghp_***";

// TODO List the project that contains artifacts
var projects = new[]
{
    "meziantou/project1",
    "meziantou/project2",
    "meziantou/project3",
};

using var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.github.v3+json"));
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("token", GithubToken);
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "ArtifactsCleaner/1.0");
httpClient.BaseAddress = new Uri("https://api.github.com");

foreach (var project in projects)
{
    // Get all project's artifacts
    var artifacts = new List<Artifact>();
    var pageIndex = 1;
    var pageSize = 100;
    Artifacts page;
    do
    {
        var url = $"/repos/{project}/actions/artifacts?per_page={pageSize}&page={pageIndex}";
        page = await httpClient.GetFromJsonAsync<Artifacts>(url);
        artifacts.AddRange(page.Items);
        pageIndex++;
    } while (page.Items.Length >= pageSize);

    // Delete artifacts older than 1 day
    foreach (var item in artifacts)
    {
        if (!item.Expired && item.CreatedAt < DateTime.UtcNow.AddDays(-1))
        {
            var deleteUrl = $"repos/{project}/actions/artifacts/{item.Id}";
            try
            {
                Console.WriteLine(deleteUrl);
                await httpClient.DeleteAsync(deleteUrl);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }
    }
}

record Artifacts([property: JsonPropertyName("artifacts")] Artifact[] Items);

record Artifact(
    int Id,
    bool Expired,
    [property: JsonPropertyName("created_at")] DateTime CreatedAt);

Once you have deleted the oldest artifacts, be sure to edit your workflow to automatically delete artifacts after several days by setting the retention-days property:

YAML
  - uses: actions/upload-artifact@v2
    with:
      name: demo
      path: '**/*.txt'
      retention-days: 3

You can also change this value in the settings of the project or of the organization:

#Additionnal resources

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?Buy Me A Coffee