Skip to content

Commit 049b572

Browse files
adds pagination
1 parent df2b0ca commit 049b572

File tree

3 files changed

+99
-33
lines changed

3 files changed

+99
-33
lines changed

Gemfile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,7 @@ gem "rspec"
1010
gem "sinatra-contrib", "~> 4.1"
1111
gem "sinatra"
1212

13-
gem "pry", "~> 0.15.2", :group => :development
13+
group :development do
14+
gem "pry", "~> 0.15.2"
15+
gem "pry-doc", "~> 1.6"
16+
end

Gemfile.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ GEM
2727
pry (0.15.2)
2828
coderay (~> 1.1)
2929
method_source (~> 1.0)
30+
pry-doc (1.6.0)
31+
pry (~> 0.11)
32+
yard (~> 0.9.11)
3033
public_suffix (6.0.2)
3134
puma (6.6.1)
3235
nio4r (~> 2.0)
@@ -74,6 +77,7 @@ GEM
7477
tilt (~> 2.0)
7578
tilt (2.6.1)
7679
uri (1.0.3)
80+
yard (0.9.37)
7781

7882
PLATFORMS
7983
aarch64-linux
@@ -82,6 +86,7 @@ PLATFORMS
8286
DEPENDENCIES
8387
octokit (~> 10.0)
8488
pry (~> 0.15.2)
89+
pry-doc (~> 1.6)
8590
puma
8691
rack-test
8792
rackup

app.rb

Lines changed: 90 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
require 'date'
22
require 'octokit'
3+
require 'faraday'
34
require 'sinatra'
45
require 'sinatra/json'
56

@@ -8,53 +9,110 @@
89
set :server_settings, timeout: 60
910
end
1011

11-
def has_permatag?(version, permatags)
12-
(version['metadata']['container']['tags'] & permatags).any?
12+
stack = Faraday::RackBuilder.new do |builder|
13+
builder.use Octokit::Middleware::FollowRedirects
14+
builder.use Octokit::Response::RaiseError
15+
builder.use Octokit::Response::FeedParser
16+
builder.response :logger, nil, { headers: true, bodies: true, errors: true } do |logger|
17+
logger.filter(/(Authorization: "(token|Bearer) )(\w+)/, '\1[REMOVED]')
18+
end
19+
builder.adapter Faraday.default_adapter
1320
end
21+
Octokit.middleware = stack
22+
23+
module Logging
24+
def logger
25+
Logging.logger
26+
end
1427

15-
def younger_than?(version, days_old)
16-
cutoff = Time.now - 60*60*24*days_old
17-
version['created_at'] > cutoff
28+
def self.logger
29+
@logger ||= Logger.new(STDOUT)
30+
end
1831
end
1932

20-
github = Octokit::Client.new(per_page: 100, auto_paginate: true)
33+
class RegistryPruner
34+
include Logging
2135

22-
get '/' do
23-
'Hello, world!'
24-
end
36+
attr_reader :github, :org
2537

26-
# Returns all container packages along with their pruning status, i.e. whether they can/can't be pruned and why
27-
get '/images' do
28-
packages = github.get('orgs/BerkeleyLibrary/packages', {package_type: :container})
29-
logger.info "Scanning #{packages.size} packages for prunable images: #{packages.collect(&:name).sort}"
38+
def initialize(github: nil, org: 'BerkeleyLibrary')
39+
@github = github || Octokit::Client.new(per_page: 100, auto_paginate: true)
40+
@org = org
41+
@inventory = nil
42+
end
3043

31-
prunables = [].tap do |sofar|
32-
packages.each do |pkg|
33-
logger.info "Determining prunable images for #{pkg.name}"
44+
def inventory
45+
@inventory ||= [].then { refresh_inventory! }
46+
end
3447

35-
next unless pkg.repository
48+
def prune!(days_old = 7)
49+
cutoff = Time.now - (60*60*24 * days_old)
3650

37-
permatags = %w(latest edge)
38-
permatags += github.branches(pkg.repository.full_name).collect(&:name)
39-
permatags += github.tags(pkg.repository.full_name).collect(&:name)
51+
inventory.each do |image|
52+
if image[:created_at] > cutoff
53+
logger.debug "SKIPPING: Image #{image[:package]}/#{image[:version]} created recently: #{image[:created_at]}"
54+
next
55+
end
56+
57+
permatags = image[:tags] & image[:repo_permatags]
58+
if permatags.any?
59+
logger.debug "SKIPPING: Image #{image[:package]}/#{image[:version]} has permatags: #{permatags.sort.join(', ')}"
60+
next
61+
end
4062

41-
github.get("orgs/#{pkg.owner.login}/packages/#{pkg.package_type}/#{pkg.name}/versions").each do |image|
42-
if has_permatag? image, permatags
43-
pruning_status = :permatagged
44-
elsif younger_than? image, 7
45-
pruning_status = :recent
63+
begin
64+
logger.debug("Deleting image: #{image[:url]}")
65+
github.delete image[:url], nil
66+
rescue Octokit::BadRequest => e
67+
logger.error(e)
68+
if e.message =~ /cannot be deleted/
69+
next
4670
else
47-
pruning_status = :prunable
71+
raise
4872
end
73+
end
74+
end
75+
end
4976

50-
sofar << {
51-
image: image.to_attrs,
52-
pruning_status: pruning_status,
53-
can_be_pruned: pruning_status == :prunable,
54-
}
77+
def refresh_inventory!
78+
@inventory = [].tap do |images|
79+
github.get("orgs/#{org}/packages", { package_type: :container }).each do |pkg|
80+
next unless pkg.repository
81+
82+
repo = pkg.repository.full_name
83+
repo_permatags = permatags_for(pkg)
84+
next_page = "orgs/#{org}/packages/container/#{pkg.name}/versions"
85+
86+
loop do
87+
github.get(next_page).each do |image|
88+
images << {
89+
url: "orgs/#{org}/packages/container/#{pkg.name}/versions/#{image.id}",
90+
package: pkg.name,
91+
version: image.id,
92+
created_at: image['created_at'],
93+
tags: image['metadata']['container']['tags'],
94+
repo:,
95+
repo_permatags:,
96+
}
97+
end
98+
next_page = github.last_response.rels[:next]&.href
99+
break if next_page.nil?
100+
end
55101
end
56102
end
57103
end
58104

59-
json prunables
105+
def permatags_for(pkg)
106+
%w(latest edge).tap do |permatags|
107+
permatags.concat github.branches(pkg.repository.full_name).collect(&:name)
108+
permatags.concat github.tags(pkg.repository.full_name).collect(&:name)
109+
permatags.sort!
110+
end
111+
end
112+
end
113+
114+
get '/images' do
115+
pruner = RegistryPruner.new
116+
inventory = pruner.inventory
117+
json({ inventory: })
60118
end

0 commit comments

Comments
 (0)