Skip to content

Commit 942dfbd

Browse files
committed
feat: add rake task to clean overwritten pact publications and verifications
1 parent 4e42bfa commit 942dfbd

File tree

5 files changed

+222
-0
lines changed

5 files changed

+222
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
require 'date'
2+
require 'sequel'
3+
4+
module PactBroker
5+
module DB
6+
class DeleteOverwrittenData
7+
def self.call database_connection, options = {}
8+
new(database_connection, options).call
9+
end
10+
11+
def initialize database_connection, options = {}
12+
@db = database_connection
13+
@options = options
14+
@before = options[:before] || DateTime.now
15+
end
16+
17+
def call
18+
deleted_counts = {}
19+
kept_counts = {}
20+
21+
22+
deleted_counts.merge!(delete_overwritten_pact_publications)
23+
deleted_counts.merge!(delete_overwritten_verifications)
24+
deleted_counts.merge!(delete_orphan_pact_versions)
25+
26+
kept_counts[:pact_publications] = db[:pact_publications].count
27+
kept_counts[:verification_results] = db[:verifications].count
28+
kept_counts[:pact_versions] = db[:pact_versions].count
29+
30+
31+
{ deleted: deleted_counts, kept: kept_counts }
32+
end
33+
34+
private
35+
36+
attr_reader :db, :options, :before
37+
38+
def delete_webhook_data(triggered_webhook_ids)
39+
db[:webhook_executions].where(triggered_webhook_id: triggered_webhook_ids).delete
40+
db[:triggered_webhooks].where(id: triggered_webhook_ids).delete
41+
end
42+
43+
def delete_orphan_pact_versions
44+
referenced_pact_version_ids = db[:pact_publications].select(:pact_version_id).union(db[:verifications].select(:pact_version_id))
45+
pact_version_ids_to_delete = db[:pact_versions].where(id: referenced_pact_version_ids).invert
46+
deleted_counts = { pact_versions: pact_version_ids_to_delete.count }
47+
pact_version_ids_to_delete.delete
48+
deleted_counts
49+
end
50+
51+
def delete_overwritten_pact_publications
52+
pact_publication_ids_to_delete = db[:pact_publications]
53+
.select(:id)
54+
.where(id: db[:latest_pact_publication_ids_for_consumer_versions].select(:pact_publication_id))
55+
.invert
56+
.where(Sequel.lit('created_at < ?', before))
57+
58+
deleted_counts = { pact_publications: pact_publication_ids_to_delete.count }
59+
delete_webhook_data(db[:triggered_webhooks].where(pact_publication_id: pact_publication_ids_to_delete).select(:id))
60+
pact_publication_ids_to_delete.delete
61+
deleted_counts
62+
end
63+
64+
def delete_overwritten_verifications
65+
verification_ids = db[:verifications].select(:id)
66+
.where(id: db[:latest_verification_id_for_pact_version_and_provider_version].select(:verification_id))
67+
.invert
68+
.where(Sequel.lit('created_at < ?', before))
69+
deleted_counts = { verification_results: verification_ids.count }
70+
delete_webhook_data(db[:triggered_webhooks].where(verification_id: verification_ids).select(:id))
71+
verification_ids.delete
72+
deleted_counts
73+
end
74+
end
75+
end
76+
end

lib/pact_broker/tasks.rb

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require 'pact_broker/tasks/migration_task'
22
require 'pact_broker/tasks/data_migration_task'
3+
require 'pact_broker/tasks/delete_overwritten_data_task'
34
require 'pact_broker/tasks/version_task'
45
require 'pact_broker/tasks/clean_task'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
module PactBroker
2+
module DB
3+
class DeleteOverwrittenDataTask < ::Rake::TaskLib
4+
attr_accessor :database_connection
5+
attr_accessor :age_in_days
6+
7+
def initialize &block
8+
rake_task &block
9+
end
10+
11+
def rake_task &block
12+
namespace :pact_broker do
13+
namespace :db do
14+
desc "Delete overwritten pacts and verifications from database"
15+
task :delete_overwritten_data do | t, args |
16+
require 'pact_broker/db/delete_overwritten_data'
17+
require 'yaml'
18+
19+
instance_eval(&block)
20+
options = {}
21+
22+
if age_in_days
23+
options[:before] = (Date.today - age_in_days.to_i).to_datetime
24+
$stdout.puts "Deleting overwritten pact publications and verifications older than #{age_in_days} days"
25+
else
26+
$stdout.puts "Deleting overwritten pact publications and verifications"
27+
end
28+
29+
report = PactBroker::DB::DeleteOverwrittenData.call(database_connection, options)
30+
$stdout.puts report.to_yaml
31+
end
32+
end
33+
end
34+
end
35+
end
36+
end
37+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
require 'pact_broker/db/delete_overwritten_data'
2+
3+
module PactBroker
4+
module DB
5+
describe DeleteOverwrittenData do
6+
describe ".call" do
7+
let(:db) { PactBroker::DB.connection }
8+
subject { DeleteOverwrittenData.call(db, before: before_date) }
9+
let(:before_date) { nil }
10+
11+
context "when a pact is overwritten" do
12+
let!(:pact_to_delete) { td.create_everything_for_an_integration.and_return(:pact) }
13+
let!(:pact_to_keep) { td.revise_pact.and_return(:pact) }
14+
15+
16+
it "deletes the overwritten pact" do
17+
expect { subject }.to change{ db[:pact_publications].where(id: pact_to_delete.id).count }.by(-1)
18+
end
19+
20+
it "does not delete the most recent pact" do
21+
expect { subject }.to_not change{ db[:pact_publications].where(id: pact_to_keep.id).count }
22+
end
23+
24+
it "returns a report" do
25+
expect(subject[:deleted][:pact_publications]).to eq 1
26+
expect(subject[:kept][:pact_publications]).to eq 1
27+
end
28+
end
29+
30+
context "when a pact has multiple verifications" do
31+
let!(:verification_to_delete) do
32+
td.create_pact_with_hierarchy
33+
.create_verification(provider_version: "1", success: false)
34+
.and_return(:verification)
35+
end
36+
37+
let!(:verification_to_keep) { td.create_verification(provider_version: "1", number: 2, success: true).and_return(:verification) }
38+
39+
it "deletes the overwritten verification" do
40+
expect { subject }.to change{ db[:verifications].where(id: verification_to_delete.id).count }.by(-1)
41+
end
42+
43+
it "does not delete the most recent verification" do
44+
expect { subject }.to_not change{ db[:verifications].where(id: verification_to_keep.id).count }
45+
end
46+
47+
it "returns a report" do
48+
expect(subject[:deleted][:verification_results]).to eq 1
49+
expect(subject[:kept][:verification_results]).to eq 1
50+
end
51+
end
52+
53+
context "when a pact version is orphaned" do
54+
before do
55+
td.create_pact_with_verification.comment("this one will still have the verification, so can't be deleted")
56+
.revise_pact.comment("this one can be deleted")
57+
.revise_pact.comment("this one will still have a pact publication, so can't be deleted")
58+
end
59+
60+
it "is deleted" do
61+
expect { subject }.to change{ db[:pact_versions].count }.by(-1)
62+
end
63+
64+
it "returns a report" do
65+
expect(subject[:deleted][:pact_versions]).to eq 1
66+
expect(subject[:kept][:pact_versions]).to eq 2
67+
end
68+
end
69+
70+
context "when the pact publication is created after the before date" do
71+
before do
72+
td.set_now(before_date + 1)
73+
.create_pact_with_hierarchy
74+
.revise_pact
75+
end
76+
77+
let(:before_date) { DateTime.new(2010, 2, 5) }
78+
79+
it "doesn't delete the data" do
80+
expect { subject }.to_not change { db[:pact_publications].count }
81+
end
82+
end
83+
84+
context "when the verification is created after the before date" do
85+
before do
86+
td.set_now(before_date + 1)
87+
.create_pact_with_hierarchy
88+
.create_verification(provider_version: "1", success: false)
89+
.create_verification(provider_version: "1", success: true, number: 2)
90+
end
91+
92+
let(:before_date) { DateTime.new(2010, 2, 5) }
93+
94+
it "doesn't delete the data" do
95+
expect { subject }.to_not change { db[:verifications].count }
96+
end
97+
end
98+
end
99+
end
100+
end
101+
end

tasks/test_db.rake

+7
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,10 @@ PactBroker::DB::CleanTask.new do | task |
2323
require 'db'
2424
task.database_connection = DB::PACT_BROKER_DB
2525
end
26+
27+
PactBroker::DB::DeleteOverwrittenDataTask.new do | task |
28+
ENV['RACK_ENV'] ||= 'test'
29+
require 'db'
30+
task.database_connection = DB::PACT_BROKER_DB
31+
task.age_in_days = 7
32+
end

0 commit comments

Comments
 (0)