travis-backup 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/README.md +14 -4
  4. data/lib/backup/load_from_files.rb +245 -0
  5. data/lib/backup/remove_orphans.rb +81 -50
  6. data/lib/backup/remove_specified/remove_heavy_data.rb +99 -0
  7. data/lib/backup/remove_specified/remove_with_all_dependencies.rb +51 -0
  8. data/lib/backup/remove_specified/shared.rb +20 -0
  9. data/lib/backup/remove_specified.rb +68 -0
  10. data/lib/backup/save_file.rb +43 -0
  11. data/lib/backup/save_id_hash_to_file.rb +33 -0
  12. data/lib/backup/save_nullified_rels_to_file.rb +29 -0
  13. data/lib/config.rb +37 -7
  14. data/lib/dry_run_reporter.rb +18 -4
  15. data/lib/id_hash.rb +97 -0
  16. data/lib/ids_of_all_dependencies.rb +330 -0
  17. data/lib/model.rb +77 -0
  18. data/lib/models/abuse.rb +9 -0
  19. data/lib/models/annotation.rb +8 -0
  20. data/lib/models/branch.rb +9 -1
  21. data/lib/models/broadcast.rb +8 -0
  22. data/lib/models/build.rb +23 -3
  23. data/lib/models/commit.rb +8 -1
  24. data/lib/models/cron.rb +2 -1
  25. data/lib/models/email.rb +8 -0
  26. data/lib/models/invoice.rb +8 -0
  27. data/lib/models/job.rb +10 -2
  28. data/lib/models/log.rb +1 -1
  29. data/lib/models/membership.rb +9 -0
  30. data/lib/models/message.rb +8 -0
  31. data/lib/models/organization.rb +15 -1
  32. data/lib/models/owner_group.rb +8 -0
  33. data/lib/models/permission.rb +9 -0
  34. data/lib/models/pull_request.rb +5 -1
  35. data/lib/models/queueable_job.rb +8 -0
  36. data/lib/models/repository.rb +16 -3
  37. data/lib/models/request.rb +11 -1
  38. data/lib/models/ssl_key.rb +2 -1
  39. data/lib/models/stage.rb +4 -1
  40. data/lib/models/star.rb +9 -0
  41. data/lib/models/subscription.rb +9 -0
  42. data/lib/models/tag.rb +7 -1
  43. data/lib/models/token.rb +8 -0
  44. data/lib/models/trial.rb +9 -0
  45. data/lib/models/trial_allowance.rb +9 -0
  46. data/lib/models/user.rb +33 -1
  47. data/lib/models/user_beta_feature.rb +8 -0
  48. data/lib/nullify_dependencies.rb +42 -0
  49. data/lib/travis-backup.rb +29 -5
  50. data/travis-backup.gemspec +1 -1
  51. metadata +35 -9
  52. data/lib/backup/remove_old.rb +0 -204
  53. data/lib/models/model.rb +0 -8
@@ -1,10 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'models/model'
3
+ require 'model'
4
4
  require 'models/repository'
5
5
 
6
6
  class Request < Model
7
+ belongs_to :owner, polymorphic: true
8
+ belongs_to :sender, polymorphic: true
7
9
  belongs_to :repository
10
+ belongs_to :branch
11
+ belongs_to :pull_request
12
+ belongs_to :tag
13
+ belongs_to :commit
14
+ has_many :abuses
15
+ has_many :messages, as: :subject
16
+ has_many :jobs, as: :source
17
+ has_many :builds
8
18
 
9
19
  self.table_name = 'requests'
10
20
  end
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'models/model'
3
+ require 'model'
4
4
 
5
5
  class SslKey < Model
6
+ belongs_to :repository
6
7
  self.table_name = 'ssl_keys'
7
8
  end
data/lib/models/stage.rb CHANGED
@@ -1,7 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'models/model'
3
+ require 'model'
4
4
 
5
5
  class Stage < Model
6
+ belongs_to :build
7
+ has_many :jobs
8
+
6
9
  self.table_name = 'stages'
7
10
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'model'
4
+
5
+ class Star < Model
6
+ belongs_to :repository
7
+ belongs_to :user
8
+ self.table_name = 'stars'
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'model'
4
+
5
+ class Subscription < Model
6
+ belongs_to :owner, polymorphic: true
7
+ has_many :invoices
8
+ self.table_name = 'subscriptions'
9
+ end
data/lib/models/tag.rb CHANGED
@@ -1,7 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'models/model'
3
+ require 'model'
4
4
 
5
5
  class Tag < Model
6
+ belongs_to :last_build, foreign_key: :last_build_id, class_name: 'Build'
7
+ belongs_to :repository
8
+ has_many :builds
9
+ has_many :commits
10
+ has_many :requests
11
+
6
12
  self.table_name = 'tags'
7
13
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'model'
4
+
5
+ class Token < Model
6
+ belongs_to :user
7
+ self.table_name = 'tokens'
8
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'model'
4
+
5
+ class Trial < Model
6
+ belongs_to :owner, polymorphic: true
7
+ has_many :trial_allowances
8
+ self.table_name = 'trials'
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'model'
4
+
5
+ class TrialAllowance < Model
6
+ belongs_to :creator, polymorphic: true
7
+ belongs_to :trial
8
+ self.table_name = 'trial_allowances'
9
+ end
data/lib/models/user.rb CHANGED
@@ -1,7 +1,39 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'models/model'
3
+ require 'model'
4
+ require 'models/abuse'
5
+ require 'models/subscription'
6
+ require 'models/owner_group'
7
+ require 'models/trial'
8
+ require 'models/trial_allowance'
9
+ require 'models/broadcast'
10
+ require 'models/star'
11
+ require 'models/permission'
12
+ require 'models/token'
13
+ require 'models/email'
14
+ require 'models/membership'
15
+ require 'models/user_beta_feature'
4
16
 
5
17
  class User < Model
18
+ has_many :builds_for_that_this_user_is_owner, as: :owner, class_name: 'Build'
19
+ has_many :builds_for_that_this_user_is_sender, as: :sender, class_name: 'Build'
20
+ has_many :repositories, as: :owner
21
+ has_many :jobs, as: :owner
22
+ has_many :requests_for_that_this_user_is_owner, as: :owner, class_name: 'Request'
23
+ has_many :abuses, as: :owner
24
+ has_many :subscriptions, as: :owner
25
+ has_many :owner_groups, as: :owner
26
+ has_many :trials, as: :owner
27
+ has_many :trial_allowances, as: :creator
28
+ has_many :broadcasts, as: :recipient
29
+ has_many :requests_for_that_this_user_is_sender, as: :sender, class_name: 'Request'
30
+
31
+ has_many :stars
32
+ has_many :permissions
33
+ has_many :tokens
34
+ has_many :emails
35
+ has_many :memberships
36
+ has_many :user_beta_features
37
+
6
38
  self.table_name = 'users'
7
39
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'model'
4
+
5
+ class UserBetaFeature < Model
6
+ belongs_to :user
7
+ self.table_name = 'user_beta_features'
8
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NullifyDependencies
4
+ def nullify_dependencies(dependencies_symbols_to_nullify)
5
+ dependencies_symbols_to_nullify.map do |symbol|
6
+ dependencies = self.send(symbol) # e.g. build.tags_for_that_this_build_is_last
7
+
8
+ dependencies.map do |entry|
9
+ foreign_key = self.class.reflect_on_association(symbol).foreign_key.to_sym
10
+ entry.update(foreign_key => nil) # e.g. tag.update(last_build_id: nil)
11
+ {
12
+ related_table: entry.class.table_name,
13
+ foreign_key: foreign_key,
14
+ parent_id: self.id,
15
+ related_id: entry.id
16
+ }
17
+ end
18
+ end.flatten
19
+ end
20
+
21
+ def nullify_all_dependencies
22
+ nullify_dependencies(symbols_of_all_direct_dependencies)
23
+ end
24
+
25
+ def nullify_default_dependencies
26
+ nullify_dependencies(default_dependencies_symbols_to_nullify)
27
+ end
28
+
29
+ def default_dependencies_symbols_to_nullify
30
+ self.class.default_dependencies_symbols_to_nullify
31
+ end
32
+
33
+ def self.default_dependencies_symbols_to_nullify
34
+ raise "self.default_dependencies_symbols_to_nullify not implemented in the #{self.class} class"
35
+ end
36
+
37
+ def default_dependencies_to_nullify
38
+ default_dependencies_symbols_to_nullify.map do |symbol|
39
+ self.send(symbol).to_a
40
+ end.flatten(1)
41
+ end
42
+ end
data/lib/travis-backup.rb CHANGED
@@ -5,19 +5,41 @@ require 'active_support/time'
5
5
  require 'config'
6
6
  require 'db_helper'
7
7
  require 'dry_run_reporter'
8
+ require 'models/abuse'
9
+ require 'models/annotation'
8
10
  require 'models/repository'
9
- require 'models/log'
10
11
  require 'models/branch'
11
- require 'models/tag'
12
+ require 'models/broadcast'
13
+ require 'models/build'
12
14
  require 'models/commit'
13
15
  require 'models/cron'
16
+ require 'models/email'
17
+ require 'models/invoice'
18
+ require 'models/job'
19
+ require 'models/log'
20
+ require 'models/membership'
21
+ require 'models/message'
22
+ require 'models/organization'
23
+ require 'models/owner_group'
24
+ require 'models/permission'
14
25
  require 'models/pull_request'
15
- require 'models/ssl_key'
26
+ require 'models/queueable_job'
27
+ require 'models/repository'
16
28
  require 'models/request'
29
+ require 'models/ssl_key'
17
30
  require 'models/stage'
31
+ require 'models/star'
32
+ require 'models/subscription'
33
+ require 'models/tag'
34
+ require 'models/token'
35
+ require 'models/trial_allowance'
36
+ require 'models/trial'
37
+ require 'models/user_beta_feature'
38
+ require 'models/user'
18
39
  require 'backup/move_logs'
19
40
  require 'backup/remove_orphans'
20
- require 'backup/remove_old'
41
+ require 'backup/load_from_files'
42
+ require 'backup/remove_specified'
21
43
 
22
44
  # main travis-backup class
23
45
  class Backup
@@ -39,10 +61,12 @@ class Backup
39
61
  def run(args={})
40
62
  if @config.move_logs
41
63
  Backup::MoveLogs.new(@config, @db_helper, @dry_run_reporter).run
64
+ elsif @config.load_from_files
65
+ Backup::LoadFromFiles.new(@config, @dry_run_reporter).run
42
66
  elsif @config.remove_orphans
43
67
  Backup::RemoveOrphans.new(@config, @dry_run_reporter).run
44
68
  else
45
- Backup::RemoveOld.new(@config, @dry_run_reporter).run(args)
69
+ Backup::RemoveSpecified.new(@config, @dry_run_reporter).run(args)
46
70
  end
47
71
 
48
72
  @dry_run_reporter.print_report if @config.dry_run
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'travis-backup'
3
- s.version = '0.2.1'
3
+ s.version = '0.3.0'
4
4
  s.summary = 'Travis CI backup tool'
5
5
  s.authors = ['Karol Selak']
6
6
  s.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: travis-backup
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Karol Selak
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-04 00:00:00.000000000 Z
11
+ date: 2021-12-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -210,13 +210,13 @@ description:
210
210
  email:
211
211
  executables:
212
212
  - setup
213
- - rails
213
+ - console
214
+ - rake
215
+ - travis_backup
214
216
  - spring
215
- - yarn
217
+ - rails
216
218
  - bundle
217
- - travis_backup
218
- - rake
219
- - console
219
+ - yarn
220
220
  extensions: []
221
221
  extra_rdoc_files: []
222
222
  files:
@@ -260,27 +260,53 @@ files:
260
260
  - config/spring.rb
261
261
  - db/schema.sql
262
262
  - dump/.keep
263
+ - lib/backup/load_from_files.rb
263
264
  - lib/backup/move_logs.rb
264
- - lib/backup/remove_old.rb
265
265
  - lib/backup/remove_orphans.rb
266
+ - lib/backup/remove_specified.rb
267
+ - lib/backup/remove_specified/remove_heavy_data.rb
268
+ - lib/backup/remove_specified/remove_with_all_dependencies.rb
269
+ - lib/backup/remove_specified/shared.rb
270
+ - lib/backup/save_file.rb
271
+ - lib/backup/save_id_hash_to_file.rb
272
+ - lib/backup/save_nullified_rels_to_file.rb
266
273
  - lib/config.rb
267
274
  - lib/db_helper.rb
268
275
  - lib/dry_run_reporter.rb
276
+ - lib/id_hash.rb
277
+ - lib/ids_of_all_dependencies.rb
278
+ - lib/model.rb
279
+ - lib/models/abuse.rb
280
+ - lib/models/annotation.rb
269
281
  - lib/models/branch.rb
282
+ - lib/models/broadcast.rb
270
283
  - lib/models/build.rb
271
284
  - lib/models/commit.rb
272
285
  - lib/models/cron.rb
286
+ - lib/models/email.rb
287
+ - lib/models/invoice.rb
273
288
  - lib/models/job.rb
274
289
  - lib/models/log.rb
275
- - lib/models/model.rb
290
+ - lib/models/membership.rb
291
+ - lib/models/message.rb
276
292
  - lib/models/organization.rb
293
+ - lib/models/owner_group.rb
294
+ - lib/models/permission.rb
277
295
  - lib/models/pull_request.rb
296
+ - lib/models/queueable_job.rb
278
297
  - lib/models/repository.rb
279
298
  - lib/models/request.rb
280
299
  - lib/models/ssl_key.rb
281
300
  - lib/models/stage.rb
301
+ - lib/models/star.rb
302
+ - lib/models/subscription.rb
282
303
  - lib/models/tag.rb
304
+ - lib/models/token.rb
305
+ - lib/models/trial.rb
306
+ - lib/models/trial_allowance.rb
283
307
  - lib/models/user.rb
308
+ - lib/models/user_beta_feature.rb
309
+ - lib/nullify_dependencies.rb
284
310
  - lib/travis-backup.rb
285
311
  - log/.keep
286
312
  - package.json
@@ -1,204 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Backup
4
- class RemoveOld
5
- attr_reader :config
6
-
7
- def initialize(config, dry_run_reporter=nil)
8
- @config = config
9
- @dry_run_reporter = dry_run_reporter
10
- end
11
-
12
- def dry_run_report
13
- @dry_run_reporter.report
14
- end
15
-
16
- def run(args={})
17
- user_id = args[:user_id] || @config.user_id
18
- repo_id = args[:repo_id] || @config.repo_id
19
- org_id = args[:org_id] || @config.org_id
20
-
21
- if user_id
22
- process_repos_for_owner(user_id, 'User')
23
- elsif org_id
24
- process_repos_for_owner(org_id, 'Organization')
25
- elsif repo_id
26
- process_repo_with_id(repo_id)
27
- else
28
- process_all_repos
29
- end
30
- end
31
-
32
- def process_repos_for_owner(owner_id, owner_type)
33
- Repository.where('owner_id = ? and owner_type = ?', owner_id, owner_type).order(:id).each do |repository|
34
- process_repo(repository)
35
- end
36
- end
37
-
38
- def process_repo_with_id(repo_id)
39
- process_repo(Repository.find(repo_id))
40
- end
41
-
42
- def process_all_repos
43
- Repository.order(:id).each do |repository|
44
- process_repo(repository)
45
- end
46
- end
47
-
48
- def process_repo(repository)
49
- process_repo_builds(repository)
50
- process_repo_requests(repository)
51
- end
52
-
53
- def process_repo_builds(repository) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
54
- threshold = @config.threshold.to_i.months.ago.to_datetime
55
- current_build_id = repository.current_build_id || -1
56
- repository.builds.where('created_at < ? and id != ?', threshold, current_build_id)
57
- .in_batches(of: @config.limit.to_i).map do |builds_batch|
58
- if @config.if_backup
59
- file_prefix = "repository_#{repository.id}"
60
- save_and_destroy_builds_batch(builds_batch, file_prefix)
61
- else
62
- destroy_builds_batch(builds_batch)
63
- end
64
- end.compact.reduce(&:&)
65
- end
66
-
67
- def process_repo_requests(repository)
68
- threshold = @config.threshold.to_i.months.ago.to_datetime
69
- repository.requests.where('created_at < ?', threshold)
70
- .in_batches(of: @config.limit.to_i).map do |requests_batch|
71
- @config.if_backup ? save_and_destroy_requests_batch(requests_batch, repository) : destroy_requests_batch(requests_batch)
72
- end.compact
73
- end
74
-
75
- private
76
-
77
- def save_and_destroy_builds_batch(builds_batch, file_prefix)
78
- builds_export = builds_batch.map(&:attributes)
79
-
80
- dependencies_saved = builds_batch.map do |build|
81
- save_build_jobs_and_logs(build, file_prefix)
82
- end.reduce(&:&)
83
-
84
- if dependencies_saved
85
- file_name = "#{file_prefix}_builds_#{builds_batch.first.id}-#{builds_batch.last.id}.json"
86
- pretty_json = JSON.pretty_generate(builds_export)
87
- save_file(file_name, pretty_json) ? destroy_builds_batch(builds_batch) : false
88
- else
89
- false
90
- end
91
- end
92
-
93
- def save_build_jobs_and_logs(build, file_prefix)
94
- build.jobs.in_batches(of: @config.limit.to_i).map do |jobs_batch|
95
- file_prefix = "#{file_prefix}_build_#{build.id}"
96
- save_jobs_batch(jobs_batch, file_prefix)
97
- end.compact.reduce(&:&)
98
- end
99
-
100
- def save_jobs_batch(jobs_batch, file_prefix)
101
- jobs_export = jobs_batch.map(&:attributes)
102
-
103
- logs_saved = jobs_batch.map do |job|
104
- save_job_logs(job, file_prefix)
105
- end.reduce(&:&)
106
-
107
- if logs_saved
108
- file_name = "#{file_prefix}_jobs_#{jobs_batch.first.id}-#{jobs_batch.last.id}.json"
109
- pretty_json = JSON.pretty_generate(jobs_export)
110
- save_file(file_name, pretty_json)
111
- else
112
- false
113
- end
114
- end
115
-
116
- def save_job_logs(job, file_prefix)
117
- job.logs.in_batches(of: @config.limit.to_i).map do |logs_batch|
118
- file_prefix = "#{file_prefix}_job_#{job.id}"
119
- save_logs_batch(logs_batch, file_prefix)
120
- end.compact.reduce(&:&)
121
- end
122
-
123
- def save_logs_batch(logs_batch, file_prefix)
124
- logs_export = logs_batch.map(&:attributes)
125
- file_name = "#{file_prefix}_logs_#{logs_batch.first.id}-#{logs_batch.last.id}.json"
126
- pretty_json = JSON.pretty_generate(logs_export)
127
- save_file(file_name, pretty_json)
128
- end
129
-
130
- def destroy_builds_batch(builds_batch)
131
- return destroy_builds_batch_dry(builds_batch) if @config.dry_run
132
-
133
- builds_batch.each(&:destroy)
134
- end
135
-
136
- def destroy_builds_batch_dry(builds_batch)
137
- @dry_run_reporter.add_to_report(:builds, *builds_batch.map(&:id))
138
-
139
- jobs_ids = builds_batch.map do |build|
140
- build.jobs.map(&:id) || []
141
- end.flatten
142
-
143
- @dry_run_reporter.add_to_report(:jobs, *jobs_ids)
144
-
145
- logs_ids = builds_batch.map do |build|
146
- build.jobs.map do |job|
147
- job.logs.map(&:id) || []
148
- end.flatten || []
149
- end.flatten
150
-
151
- @dry_run_reporter.add_to_report(:logs, *logs_ids)
152
- end
153
-
154
- def save_and_destroy_requests_batch(requests_batch, repository)
155
- requests_export = export_requests(requests_batch)
156
- file_name = "repository_#{repository.id}_requests_#{requests_batch.first.id}-#{requests_batch.last.id}.json"
157
- pretty_json = JSON.pretty_generate(requests_export)
158
- if save_file(file_name, pretty_json)
159
- destroy_requests_batch(requests_batch)
160
- end
161
- requests_export
162
- end
163
-
164
- def destroy_requests_batch(requests_batch)
165
- return destroy_requests_batch_dry(requests_batch) if @config.dry_run
166
-
167
- requests_batch.each(&:destroy)
168
- end
169
-
170
- def destroy_requests_batch_dry(requests_batch)
171
- @dry_run_reporter.add_to_report(:requests, *requests_batch.map(&:id))
172
- end
173
-
174
- def save_file(file_name, content) # rubocop:disable Metrics/MethodLength
175
- return true if @config.dry_run
176
-
177
- saved = false
178
- begin
179
- unless File.directory?(@config.files_location)
180
- FileUtils.mkdir_p(@config.files_location)
181
- end
182
-
183
- File.open(file_path(file_name), 'w') do |file|
184
- file.write(content)
185
- file.close
186
- saved = true
187
- end
188
- rescue => e
189
- print "Failed to save #{file_name}, error: #{e.inspect}\n"
190
- end
191
- saved
192
- end
193
-
194
- def file_path(file_name)
195
- "#{@config.files_location}/#{file_name}"
196
- end
197
-
198
- def export_requests(requests)
199
- requests.map do |request|
200
- request.attributes
201
- end
202
- end
203
- end
204
- end
data/lib/models/model.rb DELETED
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_record'
4
-
5
- # Model class
6
- class Model < ActiveRecord::Base
7
- self.abstract_class = true
8
- end