# Automatically deleting GitHub workflow runs when branches are deleted

If you use GitHub Actions, you probably faced the obstacle of deleting workflow runs manually that belonged to long gone branches. So what usually happens is you create a feature branch for example, do your magic there and if you use CI/CD pipelines, probably more than one workflow run will be associated to your branch. Now when you merge it, even if you set the branch to be automatically deleted after merge to main, the workflow runs remain. And after several branches, this pollutes your Actions overview potentially with several hundreds of superfluous workflow runs.

Official GitHub documentation only has description of how to manually delete a workflow run [here](https://docs.github.com/en/actions/managing-workflow-runs/deleting-a-workflow-run) but I wanted an automated way to do it and although I found some actions on [GitHub Marketplace](https://github.com/marketplace?type=actions), I wanted a simple and lightweight solution.

## **GitHub API**

So why not do it programmatically ourselves? We can use [GitHub API](https://docs.github.com/en/rest) for that, but there are multiple versions of it, more specifically the

* free (free / pro / team version)
    

and

* enterprise
    

versions. We need the API to interact with the workflow runs, which is described [here](https://docs.github.com/en/rest/actions/workflow-runs) for the free versions. If you are using enterprise, please select appropriate version in the version selector of the header.

## **curl**

We can use the GitHub API with a well-known CLI tool called [curl](https://curl.se/). It is a command-line tool that lets you send and receive data from servers on the internet, like a Swiss Army knife for making web requests. With curl, you can fetch web pages, download files, interact with APIs, and more, all without needing a graphical web browser. It's a versatile tool used by developers, sysadmins, and anyone who needs to work with web services directly from the command line

Thus using this tool we can send an HTTP DELETE request to the GitHub API to delete workflow runs.

## **The solution**

Define a workflow under `.github/workflows` folder which will run when a branch is deleted. Let’s call it `delete_branch.yml`.

```yaml
name: Delete branch
on: delete
jobs:
  delete_workflow_runs:
    runs-on: ubuntu-latest
    steps:
      - name: Delete workflow runs for deleted branch
        id: delete-workflow-runs-for-deleted-branch
        if: github.event.ref_type == 'branch'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GITHUB_BRANCH: ${{ github.event.ref }}
          GITHUB_REPOSITORY_URL: ${{ github.event.repository.url }}
        run: |
          echo "Deleting workflow runs for deleted branch ${GITHUB_BRANCH}"
          # Here we have to call GitHub API and process its response
```

We need to call the GitHub API with the branch name that is about to be deleted. It will return a lot of information about it, including the workflow runs.

```bash
curl -s -H "Authorization: Bearer ${GITHUB_TOKEN}" ${GITHUB_REPOSITORY_URL}/actions/runs?branch=${GITHUB_BRANCH}
```

Now all we have to do is to get only that portion of the information and parse it for the workflow run identifiers. A simple tool called `jq` comes in handy to process the response we get. It is a lightweight command line JSON processor tool. You can filter / transform / slice or map JSON data with it. Now to get the workflow runs[,](https://curl.se/) you need to filter for the key `workflow_runs`:

```bash
curl -s -H "Authorization: Bearer ${GITHUB_TOKEN}" ${GITHUB_REPOSITORY_URL}/actions/runs?branch=${GITHUB_BRANCH} | jq '.workflow_runs'
```

Then, you need to iterate over the result array:

```bash
curl -s -H "Authorization: Bearer ${GITHUB_TOKEN}" ${GITHUB_REPOSITORY_URL}/actions/runs?branch=${GITHUB_BRANCH} | jq '.workflow_runs | .[]'
```

And select the id key from each item in the array:

```bash
curl -s -H "Authorization: Bearer ${GITHUB_TOKEN}" ${GITHUB_REPOSITORY_URL}/actions/runs?branch=${GITHUB_BRANCH} | jq '.workflow_runs | .[] |  .id'
```

To delete an actual workflow run via GitHub, you need to execute this command with curl:

```bash
curl -s -X DELETE -H "Authorization: Bearer ${GITHUB_TOKEN}" ${GITHUB_REPOSITORY_URL}/actions/runs/${workflow_run_id}
```

Now that we have every step, we can chain these and create a for loop to delete all workflow runs:

```bash
for id in $(curl -s -H "Authorization: Bearer ${GITHUB_TOKEN}" ${GITHUB_REPOSITORY_URL}/actions/runs?branch=${GITHUB_BRANCH} | jq '.workflow_runs | .[] |  .id'); do
    curl -s -X DELETE -H "Authorization: Bearer ${GITHUB_TOKEN}" ${GITHUB_REPOSITORY_URL}/actions/runs/${id}
    echo "Deleted workflow run ${id}"
done
```

## **TL;DR**

Using `curl` to interact with the GitHub API you can query the workflow runs associated to a branch and then delete them one by one if the branch gets deleted.

The final solution looks like this:

```yaml
name: Delete branch
on: delete
jobs:
  delete_workflow_runs:
    runs-on: ubuntu-latest
    steps:
      - name: Delete workflow runs for deleted branch
        id: delete-workflow-runs-for-deleted-branch
        if: github.event.ref_type == 'branch'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GITHUB_BRANCH: ${{ github.event.ref }}
          GITHUB_REPOSITORY_URL: ${{ github.event.repository.url }}
        run: |
          echo "Deleting workflow runs for deleted branch ${GITHUB_BRANCH}"
          for id in $(curl -s -H "Authorization: Bearer ${GITHUB_TOKEN}" ${GITHUB_REPOSITORY_URL}/actions/runs?branch=${GITHUB_BRANCH} | jq '.workflow_runs | .[] |  .id'); do
            curl -s -X DELETE -H "Authorization: Bearer ${GITHUB_TOKEN}" ${GITHUB_REPOSITORY_URL}/actions/runs/${id}
            echo "Deleted workflow run ${id}"
          done
```
