firespring_dev_commands 2.1.22 → 2.1.23

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e072ae981046f7bdcd86b078617c9503a5d72ac2b21c2fdfce1c5c51ee8eae5b
4
- data.tar.gz: b98bf6d2bb8c8c9598e5a124f9f10ba0c9c94c384e6065a7dafa1a9cefb5aff2
3
+ metadata.gz: e63ba948a4c8c755d644d4e651f14cd354b0b8086447134da735c9dfb1425b3d
4
+ data.tar.gz: 4ffa7a76482a10e277f0c2be17f28dcbabe4eb9f9dbf21f49420d11329444beb
5
5
  SHA512:
6
- metadata.gz: 17ded1bd8523d1d695935404d604f66d724c9b032585f4d36d16f30a51485d73154438d8d37c2eb9a38a1a48c1d7e95bd21bb76290f893c9a43f4926b886bdf5
7
- data.tar.gz: a971fca800581cd4ee592e9da0605c9f7c3c43702ce22ae7070c81f27ff796553eea5a8ce083d2380421019999d6af768c5df44aa9eaf73affe20d7c54817126
6
+ metadata.gz: 842d17d7290d5a1537766d76bb3c6935b57b19826fa70387af69730af796f684c50a05a85faebc04522da83a7368b128bf433ea6bd3d51c043da8472143f4233
7
+ data.tar.gz: ffb4634e2a02c33ea2e16fb53785d0c72eec929ce439c86bea9b9ea98adb8e75689e25c614d495e5857b6e6fa8f7725621ac9bf9f430c38a5094653de8aaff64
@@ -0,0 +1,13 @@
1
+ module Dev
2
+ module Coverage
3
+ class Base
4
+ def php_options
5
+ raise 'not implemented'
6
+ end
7
+
8
+ def check(*)
9
+ raise 'not implemented'
10
+ end
11
+ end
12
+ end
13
+ 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,17 @@
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 check(*)
13
+ puts 'Coverage not configured'
14
+ end
15
+ end
16
+ end
17
+ end
@@ -138,8 +138,14 @@ module Dev
138
138
  Docker::Compose.new.mapped_public_port(name, private_port)
139
139
  end
140
140
 
141
+ # Gets the default working dir of the container
142
+ def working_dir(container)
143
+ container.json['Config']['WorkingDir']
144
+ end
145
+
141
146
  # Copies the source path on your local machine to the destination path on the container
142
147
  def copy_to_container(container, source_path, dest_path)
148
+ dest_path = File.join(working_dir(container), dest_path) unless dest_path.start_with?(File::SEPARATOR)
143
149
  LOG.info "Copying #{source_path} to #{dest_path}... "
144
150
 
145
151
  container.archive_in(source_path, dest_path, overwrite: true)
@@ -154,6 +160,7 @@ module Dev
154
160
  # Copies the source path on the container to the destination path on your local machine
155
161
  # If required is set to true, the command will fail if the source path does not exist on the container
156
162
  def copy_from_container(container, source_path, dest_path, required: true)
163
+ source_path = File.join(working_dir(container), source_path) unless source_path.start_with?(File::SEPARATOR)
157
164
  LOG.info "Copying #{source_path} to #{dest_path}... "
158
165
 
159
166
  tar = StringIO.new
@@ -8,11 +8,12 @@ module Dev
8
8
  DEFAULT_PACKAGE_FILE = 'composer.json'.freeze
9
9
 
10
10
  # Config object for setting top level git config options
11
- Config = Struct.new(:container_path, :local_path, :package_file) do
11
+ Config = Struct.new(:container_path, :local_path, :package_file, :coverage) do
12
12
  def initialize
13
13
  self.container_path = DEFAULT_PATH
14
14
  self.local_path = DEV_COMMANDS_ROOT_DIR
15
15
  self.package_file = DEFAULT_PACKAGE_FILE
16
+ self.coverage = nil
16
17
  end
17
18
  end
18
19
 
@@ -30,12 +31,14 @@ module Dev
30
31
  alias_method :configure, :config
31
32
  end
32
33
 
33
- attr_accessor :container_path, :local_path, :package_file
34
+ attr_accessor :container_path, :local_path, :package_file, :coverage
34
35
 
35
- def initialize(container_path: nil, local_path: nil, package_file: nil)
36
+ def initialize(container_path: nil, local_path: nil, package_file: nil, coverage: nil)
36
37
  @container_path = container_path || self.class.config.container_path
37
38
  @local_path = local_path || self.class.config.local_path
38
39
  @package_file = package_file || self.class.config.package_file
40
+ @coverage = coverage || Dev::Coverage::None.new
41
+ raise 'coverage must be an instance of the base class' unless @coverage.is_a?(Dev::Coverage::Base)
39
42
  end
40
43
 
41
44
  # The base npm command that is the starting point for all subsequent commands
@@ -93,10 +96,16 @@ module Dev
93
96
  def test_command
94
97
  test = []
95
98
  test << './vendor/bin/phpunit'
99
+ test.concat(coverage.php_options) if coverage
96
100
  test.concat(Dev::Common.new.tokenize(ENV['OPTS'].to_s))
97
101
  test
98
102
  end
99
103
 
104
+ # Run the check to ensure code coverage meets the desired threshold
105
+ def check_test_coverage(application:)
106
+ coverage.check(application:)
107
+ end
108
+
100
109
  # Build the php fast test command
101
110
  def test_fast_command(processes = 4)
102
111
  test = []
@@ -20,10 +20,12 @@ module Dev
20
20
  container_path: nil,
21
21
  local_path: nil,
22
22
  start_container_dependencies_on_test: true,
23
+ coverage: nil,
23
24
  exclude: []
24
25
  )
25
- @php = Dev::Php.new(container_path:, local_path:)
26
+ @php = Dev::Php.new(container_path:, local_path:, coverage:)
26
27
  @start_container_dependencies_on_test = start_container_dependencies_on_test
28
+
27
29
  super(application, exclude:)
28
30
  end
29
31
 
@@ -133,6 +135,7 @@ module Dev
133
135
  options = []
134
136
  options << '-T' if Dev::Common.new.running_codebuild?
135
137
  Dev::Docker::Compose.new(services: application, options:).exec(*php.test_command)
138
+ php.check_test_coverage(application:)
136
139
  end
137
140
  end
138
141
  end
@@ -6,6 +6,6 @@ module Dev
6
6
  # Use 'v.v.v.pre.alpha.v' for pre-release vesions
7
7
  # Use 'v.v.v.beta.v for beta versions
8
8
  # Use semantic versioning for any releases (https://semver.org/)
9
- VERSION = '2.1.22'.freeze
9
+ VERSION = '2.1.23'.freeze
10
10
  end
11
11
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: firespring_dev_commands
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.22
4
+ version: 2.1.23
5
5
  platform: ruby
6
6
  authors:
7
7
  - Firespring
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-04 00:00:00.000000000 Z
11
+ date: 2024-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -333,6 +333,9 @@ files:
333
333
  - lib/firespring_dev_commands/bloom_growth/user.rb
334
334
  - lib/firespring_dev_commands/boolean.rb
335
335
  - lib/firespring_dev_commands/common.rb
336
+ - lib/firespring_dev_commands/coverage/base.rb
337
+ - lib/firespring_dev_commands/coverage/cobertura.rb
338
+ - lib/firespring_dev_commands/coverage/none.rb
336
339
  - lib/firespring_dev_commands/daterange.rb
337
340
  - lib/firespring_dev_commands/docker.rb
338
341
  - lib/firespring_dev_commands/docker/compose.rb