#!/usr/bin/env python3 import os import sys import time import argparse import gitlab # Capture our command line parameters parser = argparse.ArgumentParser(description='Utility to cleanup a Gitlab Package Registry.') parser.add_argument('--project', type=str, required=True) arguments = parser.parse_args() # Retrieve the details of the package registry we will be cleaning up gitlabInstance = os.environ.pop('KDECI_GITLAB_SERVER') gitlabToken = os.environ.pop('KDECI_GITLAB_TOKEN') # Grab the Gitlab project we will be working on packageProject = arguments.project # Connect to Gitlab gitlabServer = gitlab.Gitlab( gitlabInstance, private_token=gitlabToken ) # Then retrieve our registry project remoteRegistry = gitlabServer.projects.get( packageProject ) # Start building up a list of known packages knownPackages = {} packagesToRemove = [] # Configuration - list of branches to always purge branchesToRemove = [ 'Plasma-6.0', 'Plasma-6.1', 'Plasma-6.2', 'Plasma-6.3', 'Plasma-6.4', 'Plasma-6.5', # Keep around for Kubuntu 26.04 LTS CI # 'Plasma-6.6', 'Frameworks-6.2', 'Frameworks-6.3', 'Frameworks-6.4', 'Frameworks-6.5', 'Frameworks-6.6', 'Frameworks-6.7', 'Frameworks-6.8', 'Frameworks-6.9', 'Frameworks-6.10', 'Frameworks-6.11', 'Frameworks-6.12', 'Frameworks-6.13', 'Frameworks-6.14', 'Frameworks-6.15', 'Frameworks-6.16', 'Frameworks-6.17', 'Frameworks-6.18', 'Frameworks-6.19', 'Frameworks-6.20', 'Frameworks-6.21', 'Frameworks-6.22', 'Frameworks-6.23', 'Frameworks-6.24', 'Frameworks-6.25', 'release-24.02', 'release-24.05', 'release-24.08', 'release-24.12', 'release-25.04', 'release-25.08', # Keep around for Kubuntu 26.04 LTS CI # 'release-25.12', ] # Configuration - list of Qt 5 package projects... packageProjectsForQt5 = [ 'teams/ci-artifacts/suse-qt5.15', ] # Configuration - list of Qt 6 package projects... packageProjectsForQt6 = [ 'teams/ci-artifacts/android-qt6.11', 'teams/ci-artifacts/freebsd150-qt6.10', 'teams/ci-artifacts/suse-qt6.10', 'teams/ci-artifacts/suse-qt6.11', 'teams/ci-artifacts/suse-qt6.10-static', 'teams/ci-artifacts/windows-qt6.11', 'teams/ci-artifacts/alpine-qt6.10-arm64', ] # Configuration - list of projects whose master is Qt 6 only now projectsWithQt6OnlyMaster = [ # Frameworks 'attica', 'baloo', 'bluez-qt', 'breeze-icons', 'extra-cmake-modules', 'frameworkintegration', 'kactivities', 'kactivities-stats', 'kapidox', 'karchive', 'kauth', 'kbookmarks', 'kcalendarcore', 'kcmutils', 'kcodecs', 'kcompletion', 'kconfig', 'kconfigwidgets', 'kcontacts', 'kcoreaddons', 'kcrash', 'kdav', 'kdbusaddons', 'kdeclarative', 'kded', 'kdelibs4support', 'kdesignerplugin', 'kdesu', 'kdewebkit', 'kdnssd', 'kdoctools', 'kemoticons', 'kfilemetadata', 'kglobalaccel', 'kguiaddons', 'kholidays', 'khtml', 'ki18n', 'kiconthemes', 'kidletime', 'kimageformats', 'kinit', 'kio', 'kirigami', 'kitemmodels', 'kitemviews', 'kjobwidgets', 'kjs', 'kjsembed', 'kmediaplayer', 'knewstuff', 'knotifications', 'knotifyconfig', 'kpackage', 'kparts', 'kpeople', 'kplotting', 'kpty', 'kquickcharts', 'kross', 'krunner', 'kservice', 'ktexteditor', 'ktextwidgets', 'kunitconversion', 'kwallet', 'kwayland', 'kwidgetsaddons', 'kwindowsystem', 'kxmlgui', 'kxmlrpcclient', 'modemmanager-qt', 'networkmanager-qt', 'oxygen-icons5', 'plasma-framework', 'prison', 'purpose', 'qqc2-desktop-style', 'solid', 'sonnet', 'syndication', 'syntax-highlighting', 'threadweaver', 'kuserfeedback' # Plasma 'bluedevil', 'drkonqi', 'kde-vdg-extras', 'kinfocenter', 'ksshaskpass', 'kwrited', 'libksysguard', 'pico-wizard', 'plasma-firewall', 'plasma-pa', 'plasma-thunderbolt', 'plasma5support', 'sddm-kcm', 'flatpak-kcm', 'kdecoration', 'kmenuedit', 'ksystemstats','lancelot', 'milou', 'plasma-vault', 'plymouth-kcm', 'kactivitymanagerd', 'kdeplasma-addons', 'kpipewire', 'kwallet-pam', 'plasma-browser-integration', 'plasma-mobile', 'plasma-sdk', 'polkit-kde-agent-1', 'systemsettings', 'kde-cli-tools', 'kgamma5', 'kscreen', 'layer-shell-qt', 'oxygen-gtk', 'plasma-desktop', 'plasma-nano', 'plasma-workspace', 'powerdevil', 'xdg-desktop-portal-kde', 'discover', 'kde-gtk-config', 'kglobalacceld', 'kscreenlocker', 'kwin', 'libkscreen', 'plasma-disks', 'plasma-nm', 'plasma-systemmonitor', 'plasma-workspace-wallpapers', 'qqc2-breeze-style', 'spectacle', # Gear and other applications 'accessibility-inspector', 'kmag', 'kmousetool', 'kmouth', 'kontrast', 'kwin-arhud-warping', 'kwin-blur-ng', 'kwin-gamepad', 'kwin-sharedtextures', 'kwin-zones', 'mbition-wayland-protocols', 'analitza', 'artikulate', 'blinken', 'cantor', 'gcompris', 'kalgebra', 'kalzium', 'kanagram', 'kbruch', 'kdeedu-data', 'kgeography', 'khangman', 'kig', 'kiten', 'klettres', 'kmplot', 'ktouch', 'kturtle', 'kwordquiz', 'labplot', 'libkeduvocdocument', 'marble', 'minuet', 'parley', 'rkward', 'rocs', 'step', 'arkade', 'atlantik', 'bomber', 'bovo', 'chessament', 'granatier', 'kajongg', 'kapman', 'katomic', 'kblackbox', 'kblocks', 'kbounce', 'kbreakout', 'kdiamond', 'kfourinline', 'kgoldrunner', 'kigo', 'killbots', 'kiriki', 'kjumpingcube', 'klickety', 'klines', 'kmahjongg', 'kmines', 'kmuddy', 'knavalbattle', 'knetwalk', 'knights', 'kolf', 'kollision', 'kolorfill', 'konquest', 'kpat', 'kretro', 'kreversi', 'kshisen', 'ksirk', 'ksnakeduel', 'kspaceduel', 'ksquares', 'ksudoku', 'ktuberling', 'kubrick', 'libkdegames', 'libkmahjongg', 'lskat', 'palapeli', 'picmi', 'skladnik', 'arianna', 'colord-kde', 'digikam', 'glaxnimate', 'gwenview', 'kamera', 'karp', 'kcolorchooser', 'kdegraphics-mobipocket', 'kdegraphics-thumbnailers', 'kdiagram', 'kgraphviewer', 'kimagemapeditor', 'kodaskanna', 'koko', 'kolourpaint', 'konvex', 'kooka', 'kphotoalbum', 'kruler', 'kseexpr', 'kuickshow', 'kxstitch', 'libkexiv2', 'libksane', 'okular', 'optiimage', 'peruse', 'pvfviewer', 'skanlite', 'svgpart', 'symboleditor', 'washipad', 'kde-linux', 'kdevelop', 'kdevelop-pg-qt', 'kdev-php', 'kdev-python', 'atcore', 'baloo-widgets', 'futuresql', 'kcgroups', 'kirigami-addons', 'kmoretools', 'kopeninghours', 'kosmindoormap', 'kpublictransport', 'kqtquickcharts', 'kquickimageeditor', 'ksanecore', 'ktextaddons', 'kunifiedpush', 'kweathercore', 'libtmdbqt', 'mpvqt', 'nongurigaeru', 'pulseaudio-qt', 'upnp-lib-qt', 'xdg-portal-test-kde', 'arca', 'buho', 'index-fm', 'maui-agenda', 'maui-booth', 'maui-clip', 'maui-communicator', 'maui-fiery', 'mauikit-accounts', 'mauikit-archiver', 'mauikit-calendar', 'mauikit-documents', 'mauikit-filebrowsing', 'mauikit', 'mauikit-imagetools', 'mauikit-terminal', 'mauikit-texteditor', 'mauiman', 'maui-pix', 'maui-shelf', 'maui-station', 'maui-strike', 'nota', 'paleta', 'vvave', 'amarok', 'audex', 'audiocd-kio', 'audiotube', 'dragon', 'elisa', 'ffmpegthumbs', 'hana', 'haruna', 'juk', 'k3b', 'kaffeine', 'kamoso', 'kasts', 'kdenlive', 'kmix', 'kwave', 'libkcddb', 'libkcompactdisc', 'plasmatube', 'rattlesnake', 'stopmotion', 'alligator', 'angelfish', 'falkon', 'kaccounts-integration', 'kaccounts-providers', 'kaidan', 'kdeconnect-kde', 'kdenetwork-filesharing', 'kget', 'kio-extras', 'kio-gdrive', 'kio-gopher', 'kio-s3', 'konqueror', 'konversation', 'krdc', 'krfb', 'ktorrent', 'libktorrent', 'neochat', 'ruqola', 'signon-kwallet-extension', 'smb4k', 'tokodon', 'alkimia', 'calligra', 'calligraplan', 'crow-translate', 'ghostwriter', 'kile', 'klevernotes', 'kmymoney', 'marknote', 'skrooge', 'tellico', 'kdesdk-devenv-dependencies', 'akonadi-calendar', 'akonadi-calendar-tools', 'akonadiclient', 'akonadiconsole', 'akonadi-contacts', 'akonadi', 'akonadi-import-wizard', 'akonadi-mime', 'akonadi-notes', 'akonadi-search', 'akregator', 'calendarsupport', 'eventviews', 'grantlee-editor', 'grantleetheme', 'incidenceeditor', 'itinerary', 'kaddressbook', 'kalarm', 'kcalutils', 'kdepim-addons', 'kdepim-runtime', 'khealthcertificate', 'kidentitymanagement', 'kimap', 'kitinerary', 'kjots', 'kldap', 'kleopatra', 'kmail-account-wizard', 'kmail', 'kmailtransport', 'kmbox', 'kmime', 'knotes', 'kontact', 'kontactinterface', 'korganizer', 'kpimtextedit', 'kpkpass', 'ksmtp', 'ktimetracker', 'ktnef', 'libgravatar', 'libkdepim', 'libkgapi', 'libkleo', 'libksieve', 'mailcommon', 'mailimporter', 'mbox-importer', 'merkuro', 'messagelib', 'mimetreeparser', 'pimcommon', 'pim-data-exporter', 'pim-sieve-editor', 'vakzination', 'zanshin', 'plasma-remotecontrollers', 'calindori', 'plasma-camera', 'plasma-dialer', 'plasma-mobile-sounds', 'plasma-phonebook', 'plasma-phone-settings', 'plasma-settings', 'qmlkonsole', 'spacebar', 'rolisteam-community-data', 'rolisteam-diceparser', 'rolisteam', 'rolisteam-packaging', 'clazy', 'dolphin-plugins', 'elf-dissector', 'eloquens', 'heaptrack', 'kapptemplate', 'kcachegrind', 'kde-dev-scripts', 'kde-dev-utils', 'kdesdk-kio', 'kdesdk-thumbnailers', 'kdesvn', 'kdiff3', 'kirigami-gallery', 'kompare', 'ktechlab', 'libkomparediff2', 'licentia', 'lokalize', 'massif-visualizer', 'poxml', 'distro-release-notifier', 'dolphin', 'kcm-grub2', 'kcron', 'kde-inotify-survey', 'khelpcenter', 'kio-fuse', 'kjournald', 'kpmcore', 'ksystemlog', 'liquidshell', 'melon', 'partitionmanager', 'systemdgenie', 'alpaka', 'ark', 'atelier', 'basket', 'fielding', 'filelight', 'francis', 'hash-o-matic', 'isoimagewriter', 'kaichat', 'kalk', 'kalm', 'kate', 'kbackup', 'kcalc', 'kcharselect', 'kclock', 'kdebugsettings', 'kdf', 'kdialog', 'keditbookmarks', 'keepsecret', 'keurocalc', 'keysmith', 'kfind', 'kgpg', 'kio-stash', 'klimbgrades', 'kmcpclientinspector', 'komodo', 'kongress', 'konsole', 'kookbook', 'kpublicalerts', 'krecorder', 'kregexpeditor', 'krename', 'kronometer', 'krusader', 'kteatime', 'ktimer', 'ktrip', 'kwalletmanager', 'kweather', 'markdownpart', 'notae', 'powerplant', 'qrca', 'rsibreak', 'skanpage', 'sweeper', 'symmy', 'telly-skout', 'toad', 'vail', 'yakuake', 'pumoku', ] # Configuration - list of projects to always remove projectsToAlwaysRemove = [ # QtWebKit is no longer supported 'kdewebkit', ] # Now that we have that setup, let's find out what packages our Gitlab package project knows about for package in remoteRegistry.packages.list( iterator=True ): # Grab the version (branch+timestamp) and break it out into the corresponding components # We use the version snapshotted at the time the package was created to ensure that we agree with the metadata file branch, timestamp = package.version.rsplit('-', 1) # Create the known package key - this is a combination of the identifier and the branch key = "{0}--{1}".format( package.name, branch ) # Prepare the details we want to keep... packageData = { 'package': package, 'identifier': package.name, 'branch': branch, 'timestamp': int(timestamp) } # Is this a project we should always be removing? if package.name in projectsToAlwaysRemove: # Then remove it packagesToRemove.append( packageData['package'] ) continue # Is this a stale branch we can let go of? if branch in branchesToRemove: # Then mark it for removal packagesToRemove.append( packageData['package'] ) continue # Is this a 'master' package in a Qt 5 repository? if arguments.project in packageProjectsForQt5 and package.name in projectsWithQt6OnlyMaster and branch == "master": # Then remove it too! packagesToRemove.append( packageData['package'] ) continue # Is this a 'kf5' package in a Qt 6 repository? if arguments.project in packageProjectsForQt6 and branch == "kf5": # Perform the removal packagesToRemove.append( packageData['package'] ) continue # Is this the first time we have seen this package key? if key not in knownPackages: # Then we can assume for now it is the newest version # Save it and continue knownPackages[ key ] = packageData continue # Now that we know this is not a unique package we need to determine if this one is newer or not # We can do this by comparing timestamps - if the known package is newer then it should be kept and this package removed if knownPackages[ key ]['timestamp'] > packageData['timestamp']: # This package is older than the known package, clean it up packagesToRemove.append( package ) continue # Looks like the currently known package is older # We therefore need to clean it up.... packagesToRemove.append( knownPackages[ key ]['package'] ) # Then register the new known package knownPackages[ key ] = packageData # Actually remove the packages we want to remove for package in packagesToRemove: # Let the user know print("Removing: " + package.name + " - " + package.version) # Action the removal package.delete() # Try not to overload Gitlab time.sleep(1) # For good user feedback, print a list of what we are retaining #for key, packageData in knownPackages.items(): # Print the details #print("Kept: " + packageData['identifier'] + " - " + packageData['branch'] + " - " + str(packageData['timestamp'])) # All done! sys.exit(0)