firespring_dev_commands 2.5.0.pre.alpha.3 → 3.0.0.pre.alpha.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/lib/firespring_dev_commands/audit/report.rb +9 -2
  3. data/lib/firespring_dev_commands/aws/account.rb +3 -7
  4. data/lib/firespring_dev_commands/aws/login.rb +0 -20
  5. data/lib/firespring_dev_commands/bloom_growth/rock.rb +34 -0
  6. data/lib/firespring_dev_commands/bloom_growth/seat.rb +16 -0
  7. data/lib/firespring_dev_commands/bloom_growth/user.rb +43 -0
  8. data/lib/firespring_dev_commands/bloom_growth.rb +132 -0
  9. data/lib/firespring_dev_commands/common.rb +11 -22
  10. data/lib/firespring_dev_commands/coverage/base.rb +21 -0
  11. data/lib/firespring_dev_commands/coverage/cobertura.rb +86 -0
  12. data/lib/firespring_dev_commands/coverage/none.rb +25 -0
  13. data/lib/firespring_dev_commands/docker.rb +23 -25
  14. data/lib/firespring_dev_commands/node.rb +13 -12
  15. data/lib/firespring_dev_commands/php.rb +13 -9
  16. data/lib/firespring_dev_commands/platform.rb +1 -1
  17. data/lib/firespring_dev_commands/ruby.rb +19 -7
  18. data/lib/firespring_dev_commands/target_process/query.rb +30 -4
  19. data/lib/firespring_dev_commands/target_process.rb +3 -1
  20. data/lib/firespring_dev_commands/templates/aws.rb +0 -2
  21. data/lib/firespring_dev_commands/templates/base_interface.rb +2 -2
  22. data/lib/firespring_dev_commands/templates/docker/application.rb +2 -2
  23. data/lib/firespring_dev_commands/templates/docker/node/application.rb +47 -10
  24. data/lib/firespring_dev_commands/templates/docker/php/application.rb +39 -16
  25. data/lib/firespring_dev_commands/templates/docker/ruby/application.rb +44 -8
  26. data/lib/firespring_dev_commands/version.rb +1 -1
  27. data/lib/firespring_dev_commands.rb +1 -1
  28. metadata +42 -35
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4d6edfc008b5f1864dfdb75300af7ea5afe3a9d3fb52ee6ed35918cda8467594
4
- data.tar.gz: efe9ca062f154d384179159ec94ea30eeaf005fbc6894562cb3a1ff1fbe64ff2
3
+ metadata.gz: 72bba6fb9e4d227bad3c551b1ac78eb42819178141353aefbf9a6186bd986175
4
+ data.tar.gz: d7f127460c9daedbe0bfe7e5902cc40196cd8e383a29c971ae0241ae76978f28
5
5
  SHA512:
6
- metadata.gz: 5a852876ecd2168c3899d3ae3bdb05a7874da0dbb63d8ddfc65c8c248a5534065789107cae2265a0b732f7012911094574c8a52136afb6a9a68c048be8ee786c
7
- data.tar.gz: 24b8762a98e1a89c6e0b36949960250fdebb0f65dabccd187296dec51daadced45d5e6ef4b9e5345740f99f2339e0329823b98c6a466a9e222a801f426cda45d
6
+ metadata.gz: 10690a7a9e253d00f7ca60d36358893248cd111a07b28918564b1dd79e2f19dcf77ea5d980c905005d05c1f2ed8aba395c595c3af3426c76c431062405f3eb86
7
+ data.tar.gz: 369af054ddaaeaae52e347ec02a49b26edff5f2b9c1b88c39c4b7061c68ec64ad091d052b193828034bd2f3d6165550fc920f752524ccbe70c8dc828d71beec1
@@ -3,11 +3,12 @@ module Dev
3
3
  class Audit
4
4
  # The class containing standardized information about an audit report
5
5
  class Report
6
- attr_accessor :items, :min_severity, :ignorelist, :filtered_items
6
+ attr_accessor :items, :min_severity, :error_on_unknown, :ignorelist, :filtered_items
7
7
 
8
8
  def initialize(
9
9
  items,
10
10
  min_severity: ENV.fetch('MIN_SEVERITY', nil),
11
+ error_on_unknown: ENV.fetch('ERROR_ON_UNKNOWN', nil),
11
12
  ignorelist: ENV['IGNORELIST'].to_s.split(/\s*,\s*/)
12
13
  )
13
14
  # Items should be an array of Item objects
@@ -15,12 +16,18 @@ module Dev
15
16
  raise 'items must all be report items' unless @items.all?(Dev::Audit::Report::Item)
16
17
 
17
18
  @min_severity = min_severity || Level::HIGH
19
+ @error_on_unknown = error_on_unknown
18
20
  @ignorelist = Array(ignorelist).compact
19
21
  end
20
22
 
21
23
  # Get all severities greater than or equal to the minimum severity
22
24
  def desired_severities
23
- LEVELS.slice(LEVELS.find_index(min_severity)..-1)
25
+ max_severity = if error_on_unknown.to_s.strip == 'true'
26
+ -1
27
+ else
28
+ -2
29
+ end
30
+ LEVELS.slice(LEVELS.find_index(min_severity)..max_severity)
24
31
  end
25
32
 
26
33
  # Run the filters against the report items and filter out any which should be excluded
@@ -3,8 +3,7 @@ module Dev
3
3
  # Class containing useful methods for interacting with the Aws account
4
4
  class Account
5
5
  # Config object for setting top level Aws account config options
6
- # TODO: registry is deprecated and should be removed on the next major release
7
- Config = Struct.new(:root, :children, :default, :registry, :ecr_registry_ids, :login_to_account_ecr_registry, :default_login_role_name)
6
+ Config = Struct.new(:root, :children, :default, :ecr_registry_ids, :login_to_account_ecr_registry, :default_login_role_name)
8
7
 
9
8
  # Instantiates a new top level config object if one hasn't already been created
10
9
  # Yields that config object to any given block
@@ -28,8 +27,7 @@ module Dev
28
27
  IniFile.new(filename: CONFIG_FILE, default: 'default')
29
28
  end
30
29
 
31
- # TODO: registry is deprecated and should be removed on the next major release
32
- attr_accessor :root, :children, :default, :registry, :ecr_registry_ids
30
+ attr_accessor :root, :children, :default, :ecr_registry_ids
33
31
 
34
32
  # Instantiate an account object
35
33
  # Requires that root account and at least one child account have been configured
@@ -44,11 +42,9 @@ module Dev
44
42
  @default = self.class.config.default
45
43
 
46
44
  # Create the ecr registry list based off several possible configuration values
47
- @ecr_registry_ids = [self.class.config.registry]
45
+ @ecr_registry_ids = Array(self.class.config.ecr_registry_ids)
48
46
  @ecr_registry_ids << Dev::Aws::Profile.new.current if self.class.config.login_to_account_ecr_registry
49
- @ecr_registry_ids.concat(Array(self.class.config.ecr_registry_ids))
50
47
  @ecr_registry_ids = @ecr_registry_ids.flatten.compact.reject(&:empty?).uniq
51
- @registry = @ecr_registry_ids.first
52
48
  end
53
49
 
54
50
  # Returns all configured account information objects
@@ -116,17 +116,6 @@ module Dev
116
116
  ENV['ECR_REGISTRY'] ||= registry
117
117
  end
118
118
 
119
- # Authroizes the docker cli to pull/push images from the Aws container registry
120
- # (e.g. if docker compose needs to pull an image)
121
- # @deprecated Please use {Dev::Aws::Login#registry_login!} instead
122
- def docker_login!(registry_id: nil, region: nil)
123
- registry_id ||= Dev::Aws::Account.new.ecr_registry_ids.first
124
- region ||= Dev::Aws::Credentials.new.logged_in_region || Dev::Aws::DEFAULT_REGION
125
- warn '[DEPRECATION] `Dev::Aws::Login#docker_login!` is deprecated. Please use `Dev::Aws::Login#registry_login!` instead.'
126
- docker_cli_login!(registry: "#{registry_id}.dkr.ecr.#{region}.amazonaws.com", region:)
127
- puts
128
- end
129
-
130
119
  # Authroizes the docker cli to pull/push images from the Aws container registry
131
120
  # (e.g. if docker compose needs to pull an image)
132
121
  private def docker_cli_login!(registry:, region:)
@@ -137,15 +126,6 @@ module Dev
137
126
  Dev::Common.new.run_command([login_cmd])
138
127
  end
139
128
 
140
- # Authroizes the docker ruby library to pull/push images from the Aws container registry
141
- # @deprecated Please use {Dev::Aws::Login#registry_login!} instead
142
- def ecr_login!(registry_id: nil, region: nil)
143
- registry_id ||= Dev::Aws::Account.new.ecr_registry_ids.first
144
- region ||= Dev::Aws::Credentials.new.logged_in_region || Dev::Aws::DEFAULT_REGION
145
- warn '[DEPRECATION] `Dev::Aws::Login#ecr_login!` is deprecated. Please use `Dev::Aws::Login#registry_login!` instead.'
146
- docker_lib_login!(registry_id:, region:)
147
- end
148
-
149
129
  # Authroizes the docker ruby library to pull/push images from the Aws container registry
150
130
  private def docker_lib_login!(registry_id:, region:)
151
131
  # Grab your authentication token from AWS ECR
@@ -0,0 +1,34 @@
1
+ module Dev
2
+ class BloomGrowth
3
+ # Class containing rock information
4
+ class Rock
5
+ attr_accessor :data, :id, :type, :name, :owner, :complete, :completion_id, :created, :due
6
+ attr_reader :state
7
+
8
+ def initialize(data)
9
+ @data = data
10
+ @id = data['Id']
11
+ @type = data['Type']
12
+ @name = data['Name'].to_s.strip
13
+ @owner = User.new(data['Owner']) if data['Owner']
14
+ @complete = data['Complete']
15
+ @completion_id = data['Completion']
16
+ @created = Time.parse(data['CreateTime']) if data['CreateTime']
17
+ @due = Time.parse(data['DueDate']) if data['DueDate']
18
+ @archived = data['Archived']
19
+ end
20
+
21
+ # Convert the completion_id bloom growth gives us into a text version
22
+ def state
23
+ case completion_id
24
+ when 0
25
+ 'Off Track'
26
+ when 1
27
+ 'On Track'
28
+ when 2
29
+ 'Complete'
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,16 @@
1
+ module Dev
2
+ class BloomGrowth
3
+ # Class containing seat information
4
+ class Seat
5
+ attr_accessor :data, :id, :type, :name
6
+
7
+ def initialize(data)
8
+ @data = data
9
+ position = data.dig('Group', 'Position')
10
+ @id = position&.fetch('Id')
11
+ @type = position&.fetch('Type')
12
+ @name = position&.fetch('Name').to_s.strip
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,43 @@
1
+ module Dev
2
+ class BloomGrowth
3
+ # Class containing user information
4
+ class User
5
+ attr_accessor :data, :id, :type, :name, :rocks, :direct_reports, :seats
6
+
7
+ def initialize(data)
8
+ @data = data
9
+ @id = data['Id']
10
+ @type = data['Type']
11
+ @name = data['Name'].to_s.strip
12
+ @rocks = nil
13
+ @direct_reports = nil
14
+ @seats = nil
15
+ end
16
+
17
+ def rocks
18
+ @rocks ||= [].tap do |ary|
19
+ Dev::BloomGrowth.new.get("/api/v1/rocks/user/#{id}") do |data|
20
+ ary << Rock.new(data)
21
+ end
22
+ end
23
+ end
24
+
25
+ def direct_reports
26
+ @direct_reports ||= [].tap do |ary|
27
+ Dev::BloomGrowth.new.get("/api/v1/users/#{id}/directreports") do |data|
28
+ ary << User.new(data)
29
+ end
30
+ end
31
+ end
32
+
33
+ def seats
34
+ @seats ||= [].tap do |ary|
35
+ Dev::BloomGrowth.new.get("/api/v1/users/#{id}/seats") do |data|
36
+ ary << Seat.new(data)
37
+ puts ary.last.inspect
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,132 @@
1
+ require 'net/http'
2
+
3
+ module Dev
4
+ # Class for interacting with the Bloom Growth api
5
+ class BloomGrowth
6
+ # The config file to try to load credentials from
7
+ CONFIG_FILE = "#{Dir.home}/.env.bloom".freeze
8
+
9
+ # The text of the username variable key
10
+ BLOOM_USERNAME = 'BLOOM_USERNAME'.freeze
11
+
12
+ # The text of the password variable key
13
+ BLOOM_PASSWORD = 'BLOOM_PASSWORD'.freeze
14
+
15
+ # The text of the token variable key
16
+ BLOOM_TOKEN = 'BLOOM_TOKEN'.freeze
17
+
18
+ # The text of the url variable key
19
+ BLOOM_URL = 'BLOOM_URL'.freeze
20
+
21
+ # Config object for setting top level bloom growth config options
22
+ Config = Struct.new(:username, :password, :url, :http_debug) do
23
+ def initialize
24
+ Dotenv.load(CONFIG_FILE) if File.exist?(CONFIG_FILE)
25
+
26
+ self.username = ENV.fetch(BLOOM_USERNAME, nil)
27
+ self.password = ENV.fetch(BLOOM_PASSWORD, nil)
28
+ self.url = ENV.fetch(BLOOM_URL, 'https://app.bloomgrowth.com')
29
+ self.http_debug = false
30
+ end
31
+ end
32
+
33
+ class << self
34
+ # Instantiates a new top level config object if one hasn't already been created
35
+ # Yields that config object to any given block
36
+ # Returns the resulting config object
37
+ def config
38
+ @config ||= Config.new
39
+ yield(@config) if block_given?
40
+ @config
41
+ end
42
+
43
+ # Alias the config method to configure for a slightly clearer access syntax
44
+ alias_method :configure, :config
45
+ end
46
+
47
+ attr_accessor :username, :password, :url, :token, :client, :default_headers
48
+
49
+ # Initialize a new target process client using the given inputs
50
+ def initialize(username: self.class.config.username, password: self.class.config.password, url: self.class.config.url)
51
+ raise 'username is required' if username.to_s.strip.empty?
52
+ raise 'password is required' if password.to_s.strip.empty?
53
+ raise 'url is required' if url.to_s.strip.empty?
54
+
55
+ @username = username
56
+ @password = password
57
+ @url = url
58
+ uri = URI.parse(@url)
59
+ @client = Net::HTTP.new(uri.host, uri.port)
60
+ @client.use_ssl = true
61
+ @client.verify_mode = OpenSSL::SSL::VERIFY_PEER
62
+ @client.set_debug_output(LOG) if self.class.config.http_debug
63
+ @default_headers = {
64
+ 'authorization' => "Bearer #{token}",
65
+ 'content-type' => 'application/json',
66
+ 'accept' => 'application/json'
67
+ }
68
+ end
69
+
70
+ # Method for getting a bearer token for the bloom growth api. There are a couple of possible logic paths
71
+ # - If a token has already been defined, use it
72
+ # - If a token is found in the ENV, use it
73
+ # - Otherwise, use the username and passowrd that has been configured to request a new token from bloom
74
+ def token
75
+ @token ||= ENV.fetch(BLOOM_TOKEN, nil)
76
+
77
+ unless @token
78
+ response = post(
79
+ '/Token',
80
+ {
81
+ grant_type: 'password',
82
+ userName: username,
83
+ password:
84
+ },
85
+ headers: {
86
+ 'content-type' => 'application/json',
87
+ 'accept' => 'application/json'
88
+ }
89
+ )
90
+ # TODO: Should we look at https://github.com/DannyBen/lightly for caching the token?
91
+ @token = ENV[BLOOM_TOKEN] = response['access_token']
92
+ LOG.info("Retrieved BloomGrowth token. Expires on #{Time.now + response['expires_in']}")
93
+ end
94
+
95
+ @token
96
+ end
97
+
98
+ # Return all user objects visible to the logged in user
99
+ def visible_users(&)
100
+ [].tap do |ary|
101
+ get('/api/v1/users/mineviewable') do |user_data|
102
+ ary << User.new(user_data)
103
+ end
104
+ ary.each(&)
105
+ end
106
+ end
107
+
108
+ # Perform a get request to the given path using the given query
109
+ # Call the given block (if present) with each piece of data
110
+ # Return all pieces of data
111
+ def get(path, query_string: nil, headers: default_headers, &)
112
+ url = path
113
+ url << "?#{URI.encode_www_form(query_string)}" unless query_string.to_s.strip.empty?
114
+
115
+ response = client.request_get(url, headers)
116
+ raise "Error querying #{url} [#{query_string}]: #{response.inspect}" unless response.response.is_a?(Net::HTTPSuccess)
117
+
118
+ JSON.parse(response.body).each(&)
119
+ nil
120
+ end
121
+
122
+ # Perform a post request to the given path using the gien data
123
+ # Return the parsed json body
124
+ def post(path, data, headers: default_headers)
125
+ data = data.to_json unless data.is_a?(String)
126
+ response = client.request_post(path, data, headers)
127
+ raise "Error querying #{url}/#{path}: #{response.inspect}" unless response.response.is_a?(Net::HTTPSuccess)
128
+
129
+ JSON.parse(response.body)
130
+ end
131
+ end
132
+ end
@@ -37,28 +37,6 @@ module Dev
37
37
  output
38
38
  end
39
39
 
40
- # Wraps a block of code in a y/n question.
41
- # If the user answers 'y' then the block is executed.
42
- # If the user answers 'n' then the block is skipped.
43
- # @deprecated Please use {Common#when_confirmed} instead
44
- def with_confirmation(message, default = 'y', color_message: true)
45
- message = "\n #{message}" << '? '.light_green
46
- message = message.light_green if color_message
47
- print message
48
- print '('.light_green << 'y'.light_yellow << '/'.light_green << 'n'.light_yellow << ') '.light_green
49
-
50
- answer = default
51
- answer = $stdin.gets unless ENV['NON_INTERACTIVE'] == 'true'
52
-
53
- unless answer.strip.casecmp('y').zero?
54
- puts "\n Cancelled.\n".light_yellow
55
- exit 1
56
- end
57
- puts
58
-
59
- yield
60
- end
61
-
62
40
  # Exits unless the user confirms they want to continue
63
41
  # If the user answers 'y' then the code will continue
64
42
  # All other inputs cause the code to exit
@@ -187,5 +165,16 @@ module Dev
187
165
  return false
188
166
  end
189
167
  end
168
+
169
+ # Print the given filesize using the most appropriate units
170
+ def filesize(size)
171
+ return '0.0 B' if size.to_i.zero?
172
+
173
+ units = %w(B KB MB GB TB Pb EB)
174
+ exp = (Math.log(size) / Math.log(1024)).to_i
175
+ exp = 6 if exp > 6
176
+
177
+ format('%.1f %s', size.to_f / (1024**exp), units[exp])
178
+ end
190
179
  end
191
180
  end
@@ -0,0 +1,21 @@
1
+ module Dev
2
+ module Coverage
3
+ class Base
4
+ def php_options
5
+ raise 'not implemented'
6
+ end
7
+
8
+ def node_options
9
+ raise 'not implemented'
10
+ end
11
+
12
+ def ruby_options
13
+ raise 'not implemented'
14
+ end
15
+
16
+ def check(*)
17
+ raise 'not implemented'
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,86 @@
1
+ module Dev
2
+ # Module containing different classes for interfacing with coverage files
3
+ module Coverage
4
+ # Class for checking code coverage using cobertura
5
+ class Cobertura < Base
6
+ attr_reader :local_filename, :container_filename, :filename, :threshold, :exclude
7
+
8
+ def initialize(filename: File.join('coverage', 'cobertura.xml'), threshold: nil, container_path: nil, local_path: nil, exclude: nil)
9
+ super()
10
+
11
+ @filename = filename
12
+ @local_filename = File.join(local_path || '.', @filename)
13
+ @container_filename = File.join(container_path || '.', @filename)
14
+ @threshold = threshold
15
+ @exclude = (exclude || []).map do |it|
16
+ next it if it.is_a?(Regex)
17
+
18
+ Regex.new(it)
19
+ end
20
+ end
21
+
22
+ # Remove any previous versions of the local file that will be output
23
+ # return the phpunit options needed to regenerate the cobertura xml file
24
+ def php_options
25
+ # Remove any previous coverage info
26
+ FileUtils.rm_f(local_filename, verbose: true)
27
+
28
+ # Return the needed php commands to generate the cobertura report
29
+ %W(--coverage-cobertura #{container_filename})
30
+ end
31
+
32
+ # Parse the cobertura file and check the lines missed against the desired threshold
33
+ def check(application: nil)
34
+ # If an application has been specified and the file does not exist locally, attempt to copy it back from the docker container
35
+ if application && !File.exist?(local_filename)
36
+ container = Dev::Docker::Compose.new.container_by_name(application)
37
+ Dev::Docker.new.copy_from_container(container, container_filename, local_filename, required: true)
38
+ end
39
+
40
+ report = Ox.load(File.read(local_filename))
41
+ total_missed = report.coverage.locate('packages/package').sum { |package| parse_package_missed(package) }
42
+ puts "Lines missing coverage was #{total_missed}"
43
+ puts "Configured threshold was #{threshold}" if threshold
44
+ raise 'Code coverage not met' if threshold && total_missed > threshold
45
+ end
46
+
47
+ # Go through the package and add up all of the lines that were missed
48
+ # Ignore if the file was in the exlude list
49
+ private def parse_package_missed(package)
50
+ filename = package.attributes[:name]
51
+ return if exclude.any? { |it| it.match(filename) }
52
+
53
+ missed = 0
54
+ lines_processed = Set.new
55
+ package.locate('classes/class/lines/line').each do |line|
56
+ # Don't count lines multiple times
57
+ line_number = line.attributes[:number]
58
+ next if lines_processed.include?(line_number)
59
+
60
+ lines_processed << line_number
61
+ missed += 1 unless line.attributes[:hits].to_i.positive?
62
+ end
63
+ total = lines_processed.length
64
+
65
+ sanity_check_coverage_against_cobertura_values(package, missed, total)
66
+ missed
67
+ end
68
+
69
+ # Calculate the coverage percent based off the numbers we got and compare to the
70
+ # value cobertura reported. This is meant as a sanity check that we are reading the data correctly
71
+ # TODO: This should be removed after the above logic has been vetted
72
+ private def sanity_check_coverage_against_cobertura_values(package, missed, total)
73
+ line_rate = package.attributes[:'line-rate']
74
+ cobertura_reported_coverage = line_rate.to_f
75
+ cobertura_reported_precision = line_rate.split('.').last.length
76
+
77
+ file_coverage = 0.0
78
+ file_coverage = ((total - missed).to_f / total).round(cobertura_reported_precision) if total.positive?
79
+ return if file_coverage == cobertura_reported_coverage
80
+
81
+ filename = package.attributes[:name]
82
+ puts "WARNINNG: #{filename} coverage (#{file_coverage}) differed from what cobertura reported (#{cobertura_reported_coverage})"
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,25 @@
1
+ module Dev
2
+ module Coverage
3
+ class None < Base
4
+ def initialize(*)
5
+ super()
6
+ end
7
+
8
+ def php_options
9
+ []
10
+ end
11
+
12
+ def node_options
13
+ []
14
+ end
15
+
16
+ def ruby_options
17
+ []
18
+ end
19
+
20
+ def check(*)
21
+ # Nothing to do here
22
+ end
23
+ end
24
+ end
25
+ end
@@ -77,6 +77,22 @@ module Dev
77
77
  _prune('volumes', opts:)
78
78
  end
79
79
 
80
+ def prune_project_volumes(project_name:)
81
+ project_name = project_name.to_s.strip
82
+ raise 'No project name defined' if project_name.empty?
83
+
84
+ ::Docker::Volume.all.each do |volume|
85
+ next unless volume.info['Name'].start_with?(project_name)
86
+
87
+ begin
88
+ volume.remove
89
+ LOG.info "Removed volume #{volume.id[0, 12]}"
90
+ rescue => e
91
+ LOG.error "Error removing volume #{volume.id[0, 12]}: #{e}"
92
+ end
93
+ end
94
+ end
95
+
80
96
  # Prunes/removes all unused images
81
97
  def prune_images
82
98
  _prune('images')
@@ -103,18 +119,7 @@ module Dev
103
119
  LOG.info "\nDeleted #{type.capitalize}"
104
120
  deleted_items = info["#{type}Deleted"] || []
105
121
  deleted_items.each { |it| LOG.info " #{it}" }
106
- LOG.info "Total reclaimed space: #{filesize(info['SpaceReclaimed'])}"
107
- end
108
-
109
- # Print the given filesize using the most appropriate units
110
- private def filesize(size)
111
- return '0.0 B' if size.to_i.zero?
112
-
113
- units = %w(B KB MB GB TB Pb EB)
114
- exp = (Math.log(size) / Math.log(1024)).to_i
115
- exp = 6 if exp > 6
116
-
117
- format('%.1f %s', size.to_f / (1024**exp), units[exp])
122
+ LOG.info "Total reclaimed space: #{Dev::Common.new.filesize(info['SpaceReclaimed'])}"
118
123
  end
119
124
 
120
125
  # Remove docker images with the "force" option set to true
@@ -124,22 +129,14 @@ module Dev
124
129
  ::Docker::Image.remove(images[0].id, force: true) unless images.empty?
125
130
  end
126
131
 
127
- # Calls the docker compose method with the given inputs
128
- # @deprecated Please use {Docker::Compose#container_by_name} instead
129
- def container_by_name(service_name, prefix = nil, status: [Docker::Status::RUNNING])
130
- warn '[DEPRECATION] `Docker#container_by_name` is deprecated. Please use `Docker::Compose#container_by_name` instead.'
131
- Docker::Compose.new.container_by_name(service_name, prefix, status)
132
- end
133
-
134
- # Calls the docker compose method with the given inputs
135
- # @deprecated Please use {Docker::Compose#mapped_public_port} instead
136
- def mapped_public_port(name, private_port)
137
- warn '[DEPRECATION] `Docker#mapped_public_port` is deprecated. Please use `Docker::Compose#mapped_public_port` instead.'
138
- Docker::Compose.new.mapped_public_port(name, private_port)
132
+ # Gets the default working dir of the container
133
+ def working_dir(container)
134
+ container.json['Config']['WorkingDir']
139
135
  end
140
136
 
141
137
  # Copies the source path on your local machine to the destination path on the container
142
138
  def copy_to_container(container, source_path, dest_path)
139
+ dest_path = File.join(working_dir(container), dest_path) unless dest_path.start_with?(File::SEPARATOR)
143
140
  LOG.info "Copying #{source_path} to #{dest_path}... "
144
141
 
145
142
  container.archive_in(source_path, dest_path, overwrite: true)
@@ -154,6 +151,7 @@ module Dev
154
151
  # Copies the source path on the container to the destination path on your local machine
155
152
  # If required is set to true, the command will fail if the source path does not exist on the container
156
153
  def copy_from_container(container, source_path, dest_path, required: true)
154
+ source_path = File.join(working_dir(container), source_path) unless source_path.start_with?(File::SEPARATOR)
157
155
  LOG.info "Copying #{source_path} to #{dest_path}... "
158
156
 
159
157
  tar = StringIO.new
@@ -205,7 +203,7 @@ module Dev
205
203
  arch = "#{arch}/#{variant}" if variant
206
204
  id = image.info&.dig('id')&.split(':')&.last&.slice(0..11)
207
205
  created = timesince(Time.at(image.info&.dig('Created')))
208
- size = filesize(image.info&.dig('Size'))
206
+ size = Dev::Common.new.filesize(image.info&.dig('Size'))
209
207
 
210
208
  repo_urls = image.info&.dig('RepoTags')
211
209
  repo_urls ||= ["#{image.info&.dig('RepoDigests')&.first&.split(':')&.first&.split('@')&.first}:<none>"]