diff options
Diffstat (limited to 'scripts/packages/automated_cleanup.rb')
-rwxr-xr-x | scripts/packages/automated_cleanup.rb | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/scripts/packages/automated_cleanup.rb b/scripts/packages/automated_cleanup.rb new file mode 100755 index 00000000000..2b5a0011079 --- /dev/null +++ b/scripts/packages/automated_cleanup.rb @@ -0,0 +1,126 @@ +#!/usr/bin/env ruby + +# frozen_string_literal: true + +require 'optparse' +require 'gitlab' + +module Packages + class AutomatedCleanup + PACKAGES_PER_PAGE = 100 + + # $GITLAB_PROJECT_PACKAGES_CLEANUP_API_TOKEN => `Packages Cleanup` project token + def initialize( + project_path: ENV['CI_PROJECT_PATH'], + gitlab_token: ENV['GITLAB_PROJECT_PACKAGES_CLEANUP_API_TOKEN'], + api_endpoint: ENV['CI_API_V4_URL'], + options: {} + ) + @project_path = project_path + @gitlab_token = gitlab_token + @api_endpoint = api_endpoint + @dry_run = options[:dry_run] + + puts "Dry-run mode." if dry_run + end + + def gitlab + @gitlab ||= begin + Gitlab.configure do |config| + config.endpoint = api_endpoint + config.private_token = gitlab_token + end + + Gitlab + end + end + + def perform_gitlab_package_cleanup!(package_name:, days_for_delete:) + puts "Checking for '#{package_name}' packages created at least #{days_for_delete} days ago..." + + gitlab.project_packages(project_path, + package_type: 'generic', + package_name: package_name, + per_page: PACKAGES_PER_PAGE).auto_paginate do |package| + next unless package.name == package_name # the search is fuzzy, so we better check the actual package name + + if old_enough(package, days_for_delete) && not_recently_downloaded(package, days_for_delete) + delete_package(package) + end + end + end + + private + + attr_reader :project_path, :gitlab_token, :api_endpoint, :dry_run + + def delete_package(package) + print_package_state(package) + gitlab.delete_project_package(project_path, package.id) unless dry_run + rescue Gitlab::Error::Forbidden + puts "Package #{package_full_name(package)} is forbidden: skipping it" + end + + def time_ago(days:) + Time.now - days * 24 * 3600 + end + + def old_enough(package, days_for_delete) + Time.parse(package.created_at) < time_ago(days: days_for_delete) + end + + def not_recently_downloaded(package, days_for_delete) + package.last_downloaded_at.nil? || + Time.parse(package.last_downloaded_at) < time_ago(days: days_for_delete) + end + + def print_package_state(package) + download_text = + if package.last_downloaded_at + "last downloaded on #{package.last_downloaded_at}" + else + "never downloaded" + end + + puts "\nPackage #{package_full_name(package)} (created on #{package.created_at}) was " \ + "#{download_text}: deleting it.\n" + end + + def package_full_name(package) + "'#{package.name}/#{package.version}'" + end + end +end + +def timed(task) + start = Time.now + yield(self) + puts "#{task} finished in #{Time.now - start} seconds.\n" +end + +if $PROGRAM_NAME == __FILE__ + options = { + dry_run: false + } + + OptionParser.new do |opts| + opts.on("-d", "--dry-run", "Whether to perform a dry-run or not.") do |value| + options[:dry_run] = true + end + + opts.on("-h", "--help", "Prints this help") do + puts opts + exit + end + end.parse! + + automated_cleanup = Packages::AutomatedCleanup.new(options: options) + + timed('"gitlab-workhorse" packages cleanup') do + automated_cleanup.perform_gitlab_package_cleanup!(package_name: 'gitlab-workhorse', days_for_delete: 30) + end + + timed('"assets" packages cleanup') do + automated_cleanup.perform_gitlab_package_cleanup!(package_name: 'assets', days_for_delete: 7) + end +end |