Deleting pipelines in Gitlab 11.6

Gitlab 11.6.0 just released, and one of the new features is deleting a pipeline. Why might you want to delete a little bit of history? Well, perhaps you have inadvertently caused some private information to be printed (a password). Or perhaps you left Auto DevOps enabled and ended up with a whole slew of useless failures. Either way you want to go and delete the pipeline in question and all of its output, artifacts, etc. Well here's a quick 'hack' to achieve the goal.

You run it as 'python -t token -u url -g group -p project' and it will list all the pipeline id's. You can then run it with "-d '*'" to delete all of them, or "-d #,#,#..." to delete specific ones. You'll likely want 'pip install python-gitlab' first.

Its a quick and dirty hack, but it worked for me. YMMV.

#!/usr/bin/env python3
import gitlab
import argparse
import os
import requests
import sys

parser = argparse.ArgumentParser()
parser.add_argument('-u', '--url', help='API url', default=url)
parser.add_argument('-t', '--token', help='personal token', default=private_token)
parser.add_argument('-g', '--group', help='group', default=None, required=True)
parser.add_argument('-p', '--project', help='project', default=None, required=True)
parser.add_argument('-d', '--delete', help='delete id(s)', default=None)

args = parser.parse_args()

if args.delete:
    args.delete = args.delete.split(',')

gl = gitlab.Gitlab(args.url, args.token)

def find_group(gl, group):
    groups = gl.groups.list()
    for g in groups:
        if == group:
            return g
    return None

def find_subgroup(gl, group, subgroup):
    subgroups = group.subgroups.list()
    for sg in subgroups:
        if == subgroup:
            return sg;
    return None

# if project is of form x/y, then assume x is a subgroup
def find_project(gl, group, project_with_subgroup):
    pws = project_with_subgroup.split('/')
    if len(pws) == 2:
        subgroup = find_subgroup(gl, group, pws[0])
        project = pws[1]
        group = gl.groups.get(, lazy=True)
        project = pws[0]
    projects = group.projects.list()
    for p in projects:
        if == project:
            return p
    return None

group = find_group(gl,
gproject = find_project(gl, group, args.project)
if not gproject:
    print("Error: %s / %s does not exist" % (, args.project))

project = gl.projects.get(
pipelines = project.pipelines.list()
for pid in pipelines:
    pl = project.pipelines.get(
    if args.delete and (str( in args.delete or args.delete == ['*']):
        path = "%s/api/v4/projects/%s/pipelines/%s" % (args.url,,
        r = requests.delete(path, headers={'PRIVATE-TOKEN': args.token})
        print("%s %s %s -- DELETE" % (,, pl.status))
        print("%s %s %s" % (,, pl.status))


Tagged with: , ,
7 comments on “Deleting pipelines in Gitlab 11.6
  1. db Orondon says:

    Hi could you provide an example with “real” values for url/group/project I’m new to this

    I need to delete an orphan commit left after deleting an unmerged branch. Not sure how to do that yet, but via GUI under pipeline I can still see the reference to the commit where I’m showing a password.

    Thanks so much!

  2. db Niels J. says:

    Thanks for sharing this!

  3. db Hire Python Developer UK says:

    Thanks for sharing information.

  4. db Bill McCormick says:

    Traceback (most recent call last):
    File “./”, line 9, in
    parser.add_argument(‘-u’, ‘–url’, help=’API url’, default=url)
    NameError: name ‘url’ is not defined

    • db Bill McCormick says:

      I got past that last issue make default=None, but still 2 issues:

      1. If the project is not part of a group (like a private fork), the group cannot be specified.

      2. Not sure why, but when I did specify an existing group, it left many pipelines intact.

      • db db says:

        on the first, i had not thought of that
        on the 2nd, its probabily related to pagination in the pipeline.

        i’ll probably come back to this and make a more polished script on github.

Leave a Reply

Your email address will not be published. Required fields are marked *