datadog-ci 1.30.0 → 1.32.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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -2
  3. data/ext/datadog_ci_native/ci.c +1 -1
  4. data/ext/datadog_ci_native/iseq_collector.c +1 -1
  5. data/ext/datadog_ci_native/iseq_collector.h +1 -1
  6. data/lib/datadog/ci/configuration/components.rb +15 -2
  7. data/lib/datadog/ci/configuration/settings.rb +21 -0
  8. data/lib/datadog/ci/contrib/minitest/helpers.rb +5 -2
  9. data/lib/datadog/ci/contrib/minitest/run_method_capture.rb +47 -0
  10. data/lib/datadog/ci/contrib/minitest/test.rb +72 -14
  11. data/lib/datadog/ci/ext/environment/providers/jenkins.rb +2 -1
  12. data/lib/datadog/ci/ext/test_discovery.rb +3 -1
  13. data/lib/datadog/ci/ext/test_optimization_cache.rb +31 -0
  14. data/lib/datadog/ci/git/tree_uploader.rb +6 -3
  15. data/lib/datadog/ci/remote/component.rb +4 -4
  16. data/lib/datadog/ci/remote/library_settings.rb +7 -1
  17. data/lib/datadog/ci/test_impact_analysis/component.rb +5 -65
  18. data/lib/datadog/ci/test_management/component.rb +4 -14
  19. data/lib/datadog/ci/test_optimization_cache/component.rb +82 -0
  20. data/lib/datadog/ci/test_optimization_cache/locator.rb +96 -0
  21. data/lib/datadog/ci/test_optimization_cache/null_component.rb +32 -0
  22. data/lib/datadog/ci/test_optimization_cache/readers/base.rb +39 -0
  23. data/lib/datadog/ci/test_optimization_cache/readers/legacy.rb +74 -0
  24. data/lib/datadog/ci/test_optimization_cache/readers/missing.rb +33 -0
  25. data/lib/datadog/ci/test_optimization_cache/readers/v1.rb +56 -0
  26. data/lib/datadog/ci/test_tracing/component.rb +4 -11
  27. data/lib/datadog/ci/test_tracing/serializers/base.rb +4 -1
  28. data/lib/datadog/ci/test_tracing/serializers/meta_truncation.rb +23 -0
  29. data/lib/datadog/ci/test_tracing/transport.rb +10 -7
  30. data/lib/datadog/ci/utils/json.rb +23 -0
  31. data/lib/datadog/ci/utils/stateful.rb +18 -20
  32. data/lib/datadog/ci/utils/test_run.rb +0 -6
  33. data/lib/datadog/ci/version.rb +1 -1
  34. metadata +12 -2
  35. data/lib/datadog/ci/ext/dd_test.rb +0 -18
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../ext/test_optimization_cache"
4
+ require_relative "locator"
5
+ require_relative "readers/legacy"
6
+ require_relative "readers/missing"
7
+ require_relative "readers/v1"
8
+
9
+ module Datadog
10
+ module CI
11
+ module TestOptimizationCache
12
+ class Component
13
+ READER_BY_MANIFEST_VERSION = {
14
+ Ext::TestOptimizationCache::SUPPORTED_MANIFEST_VERSION => Readers::V1
15
+ }.freeze
16
+
17
+ def initialize(manifest_file:, runfiles_dir:, runfiles_manifest_file:, test_srcdir:)
18
+ @locator = Locator.new(
19
+ manifest_file: manifest_file,
20
+ runfiles_dir: runfiles_dir,
21
+ runfiles_manifest_file: runfiles_manifest_file,
22
+ test_srcdir: test_srcdir
23
+ )
24
+ @reader = build_reader
25
+ end
26
+
27
+ def cache_available?
28
+ @reader.available?
29
+ end
30
+
31
+ def load_settings
32
+ @reader.load_settings
33
+ end
34
+
35
+ def load_known_tests
36
+ @reader.load_known_tests
37
+ end
38
+
39
+ def load_test_management
40
+ @reader.load_test_management
41
+ end
42
+
43
+ def load_skippable_tests
44
+ @reader.load_skippable_tests
45
+ end
46
+
47
+ def shutdown!
48
+ end
49
+
50
+ private
51
+
52
+ def build_reader
53
+ manifest_path = @locator.manifest_path
54
+
55
+ if manifest_path
56
+ version = @locator.manifest_version(manifest_path)
57
+ reader_class = READER_BY_MANIFEST_VERSION[version] if version
58
+ if reader_class
59
+ test_optimization_path = File.dirname(manifest_path)
60
+ reader = reader_class.new(test_optimization_path)
61
+ return reader if reader.available?
62
+
63
+ Datadog.logger.debug do
64
+ "Test Optimization cache settings file not found under #{test_optimization_path}"
65
+ end
66
+ return Readers::Missing.new
67
+ end
68
+
69
+ Datadog.logger.debug do
70
+ "Unsupported Test Optimization cache manifest version #{version.inspect} at #{manifest_path}"
71
+ end
72
+ return Readers::Missing.new
73
+ end
74
+
75
+ return Readers::Legacy.new if Dir.exist?(Ext::TestOptimizationCache::TESTOPTIMIZATION_CACHE_PATH)
76
+
77
+ Readers::Missing.new
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../ext/test_optimization_cache"
4
+
5
+ module Datadog
6
+ module CI
7
+ module TestOptimizationCache
8
+ class Locator
9
+ RUNFILES_MANIFEST_SEPARATOR = " "
10
+
11
+ def initialize(manifest_file:, runfiles_dir:, runfiles_manifest_file:, test_srcdir:)
12
+ @manifest_file = manifest_file
13
+ @runfiles_dir = runfiles_dir
14
+ @runfiles_manifest_file = runfiles_manifest_file
15
+ @test_srcdir = test_srcdir
16
+ @manifest_versions = {}
17
+ end
18
+
19
+ def manifest_path
20
+ return @manifest_path if defined?(@manifest_path)
21
+
22
+ local_manifest = File.join(Ext::TestOptimizationCache::PLAN_FOLDER, Ext::TestOptimizationCache::MANIFEST_FILE_NAME)
23
+ if File.exist?(local_manifest)
24
+ @manifest_path = local_manifest
25
+ return @manifest_path
26
+ end
27
+
28
+ manifest_file = @manifest_file
29
+ if manifest_file && !manifest_file.empty?
30
+ env_path = resolve_bazel_runfile_path(manifest_file)
31
+ if File.exist?(env_path)
32
+ @manifest_path = env_path
33
+ return @manifest_path
34
+ end
35
+ end
36
+
37
+ @manifest_path = nil
38
+ end
39
+
40
+ def manifest_version(manifest_path)
41
+ return @manifest_versions[manifest_path] if @manifest_versions.key?(manifest_path)
42
+
43
+ @manifest_versions[manifest_path] = File.read(manifest_path).delete_prefix("\uFEFF").strip
44
+ rescue => e
45
+ Datadog.logger.debug { "Failed to read Test Optimization cache manifest #{manifest_path}: #{e.message}" }
46
+ @manifest_versions[manifest_path] = nil
47
+ end
48
+
49
+ def resolve_bazel_runfile_path(path)
50
+ return path if File.exist?(path)
51
+
52
+ runfiles_dir = @runfiles_dir
53
+ if runfiles_dir && !runfiles_dir.empty?
54
+ candidate = File.join(runfiles_dir, path)
55
+ return candidate if File.exist?(candidate)
56
+ end
57
+
58
+ manifest_candidate = resolve_bazel_runfile_path_from_manifest(path)
59
+ return manifest_candidate if manifest_candidate
60
+
61
+ test_srcdir = @test_srcdir
62
+ if test_srcdir && !test_srcdir.empty?
63
+ candidate = File.join(test_srcdir, path)
64
+ return candidate if File.exist?(candidate)
65
+ end
66
+
67
+ path
68
+ end
69
+
70
+ # Bazel can provide runfiles through a manifest file instead of a directory tree.
71
+ # Each line maps a logical runfile path to the actual path on disk.
72
+ def resolve_bazel_runfile_path_from_manifest(path)
73
+ runfiles_manifest = @runfiles_manifest_file
74
+ return nil if runfiles_manifest.nil? || runfiles_manifest.empty?
75
+ return nil unless File.exist?(runfiles_manifest)
76
+
77
+ File.foreach(runfiles_manifest) do |line|
78
+ separator_index = line.index(RUNFILES_MANIFEST_SEPARATOR)
79
+ next unless separator_index&.positive?
80
+ next unless line[0...separator_index] == path
81
+
82
+ resolved_path = line[(separator_index + 1)..]
83
+ return resolved_path.strip if resolved_path
84
+ end
85
+
86
+ nil
87
+ rescue => e
88
+ Datadog.logger.debug do
89
+ "Failed to resolve Test Optimization cache manifest from #{runfiles_manifest}: #{e.message}"
90
+ end
91
+ nil
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module CI
5
+ module TestOptimizationCache
6
+ class NullComponent
7
+ def cache_available?
8
+ false
9
+ end
10
+
11
+ def load_settings
12
+ nil
13
+ end
14
+
15
+ def load_known_tests
16
+ nil
17
+ end
18
+
19
+ def load_test_management
20
+ nil
21
+ end
22
+
23
+ def load_skippable_tests
24
+ nil
25
+ end
26
+
27
+ def shutdown!
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../utils/json"
4
+
5
+ module Datadog
6
+ module CI
7
+ module TestOptimizationCache
8
+ module Readers
9
+ class Base
10
+ def available?
11
+ true
12
+ end
13
+
14
+ def load_settings
15
+ raise NotImplementedError, "#{self.class} must implement #load_settings"
16
+ end
17
+
18
+ def load_known_tests
19
+ raise NotImplementedError, "#{self.class} must implement #load_known_tests"
20
+ end
21
+
22
+ def load_test_management
23
+ raise NotImplementedError, "#{self.class} must implement #load_test_management"
24
+ end
25
+
26
+ def load_skippable_tests
27
+ raise NotImplementedError, "#{self.class} must implement #load_skippable_tests"
28
+ end
29
+
30
+ private
31
+
32
+ def read_json_file(file_path)
33
+ Utils::Json.read_file(file_path)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../ext/test"
4
+ require_relative "../../ext/test_optimization_cache"
5
+ require_relative "base"
6
+
7
+ module Datadog
8
+ module CI
9
+ module TestOptimizationCache
10
+ module Readers
11
+ class Legacy < Base
12
+ def load_settings
13
+ load_legacy_json(Ext::TestOptimizationCache::SETTINGS_FILE_NAME)
14
+ end
15
+
16
+ def load_known_tests
17
+ payload = load_legacy_json(Ext::TestOptimizationCache::KNOWN_TESTS_FILE_NAME)
18
+ backend_response(payload) if payload
19
+ end
20
+
21
+ def load_test_management
22
+ payload = load_legacy_json(Ext::TestOptimizationCache::LEGACY_TEST_MANAGEMENT_TESTS_FILE_NAME)
23
+ backend_response(payload) if payload
24
+ end
25
+
26
+ def load_skippable_tests
27
+ payload = load_legacy_json(Ext::TestOptimizationCache::SKIPPABLE_TESTS_FILE_NAME)
28
+ skippable_tests_response(payload) if payload
29
+ end
30
+
31
+ private
32
+
33
+ def load_legacy_json(file_name)
34
+ read_json_file(File.join(Ext::TestOptimizationCache::TESTOPTIMIZATION_CACHE_PATH, file_name))
35
+ end
36
+
37
+ def backend_response(payload)
38
+ {
39
+ "data" => {
40
+ "attributes" => payload
41
+ }
42
+ }
43
+ end
44
+
45
+ def skippable_tests_response(payload)
46
+ skippable_tests = payload.fetch("skippableTests", {}) || {}
47
+
48
+ data = skippable_tests.each_value.flat_map do |tests_hash|
49
+ tests_hash.each_value.flat_map do |test_configs|
50
+ test_configs.map do |test_config|
51
+ {
52
+ "type" => Ext::Test::ITR_TEST_SKIPPING_MODE,
53
+ "attributes" => {
54
+ "suite" => test_config["suite"],
55
+ "name" => test_config["name"],
56
+ "parameters" => test_config["parameters"]
57
+ }
58
+ }
59
+ end
60
+ end
61
+ end
62
+
63
+ {
64
+ "meta" => {
65
+ "correlation_id" => payload["correlationId"]
66
+ },
67
+ "data" => data
68
+ }
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Datadog
6
+ module CI
7
+ module TestOptimizationCache
8
+ module Readers
9
+ class Missing < Base
10
+ def available?
11
+ false
12
+ end
13
+
14
+ def load_settings
15
+ nil
16
+ end
17
+
18
+ def load_known_tests
19
+ nil
20
+ end
21
+
22
+ def load_test_management
23
+ nil
24
+ end
25
+
26
+ def load_skippable_tests
27
+ nil
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../ext/test_optimization_cache"
4
+ require_relative "base"
5
+
6
+ module Datadog
7
+ module CI
8
+ module TestOptimizationCache
9
+ module Readers
10
+ class V1 < Base
11
+ def initialize(test_optimization_path)
12
+ @test_optimization_path = test_optimization_path
13
+ end
14
+
15
+ def available?
16
+ File.exist?(settings_file_path)
17
+ end
18
+
19
+ def load_settings
20
+ load_http_json(Ext::TestOptimizationCache::SETTINGS_FILE_NAME)
21
+ end
22
+
23
+ def load_known_tests
24
+ load_http_json(Ext::TestOptimizationCache::KNOWN_TESTS_FILE_NAME)
25
+ end
26
+
27
+ def load_test_management
28
+ load_http_json(Ext::TestOptimizationCache::TEST_MANAGEMENT_FILE_NAME)
29
+ end
30
+
31
+ def load_skippable_tests
32
+ load_http_json(Ext::TestOptimizationCache::SKIPPABLE_TESTS_FILE_NAME)
33
+ end
34
+
35
+ private
36
+
37
+ def load_http_json(file_name)
38
+ read_json_file(File.join(http_cache_path, file_name))
39
+ end
40
+
41
+ def settings_file_path
42
+ File.join(http_cache_path, Ext::TestOptimizationCache::SETTINGS_FILE_NAME)
43
+ end
44
+
45
+ def http_cache_path
46
+ File.join(
47
+ @test_optimization_path,
48
+ Ext::TestOptimizationCache::CACHE_FOLDER_NAME,
49
+ Ext::TestOptimizationCache::HTTP_CACHE_FOLDER_NAME
50
+ )
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -225,28 +225,21 @@ module Datadog
225
225
  end
226
226
 
227
227
  def restore_state_from_datadog_test_runner
228
- Datadog.logger.debug { "Restoring known tests from DDTest cache" }
228
+ Datadog.logger.debug { "Restoring known tests from Test Optimization cache" }
229
229
 
230
- known_tests_data = load_json(Ext::DDTest::KNOWN_TESTS_FILE_NAME)
230
+ known_tests_data = load_cached_known_tests
231
231
  if known_tests_data.nil?
232
232
  Datadog.logger.debug { "Restoring known tests failed, will request again" }
233
233
  return false
234
234
  end
235
235
 
236
- Datadog.logger.debug { "Restored known tests from DDTest: #{known_tests_data}" }
237
-
238
- # Use the KnownTests class method to parse the JSON data
239
- known_tests_data = {
240
- "data" => {
241
- "attributes" => known_tests_data
242
- }
243
- }
236
+ Datadog.logger.debug { "Restored known tests from Test Optimization: #{known_tests_data}" }
244
237
 
245
238
  @known_tests = KnownTests::Response.from_json(known_tests_data).tests
246
239
  @known_tests_enabled = !@known_tests.empty?
247
240
 
248
241
  unless @known_tests_enabled
249
- Datadog.logger.debug("Empty set of known tests from the DDTest cache file")
242
+ Datadog.logger.debug("Empty set of known tests from the Test Optimization cache file")
250
243
  end
251
244
 
252
245
  Datadog.logger.debug { "Found [#{@known_tests.size}] known tests from context" }
@@ -3,6 +3,7 @@
3
3
  require "set"
4
4
 
5
5
  require_relative "../../ext/test"
6
+ require_relative "meta_truncation"
6
7
 
7
8
  module Datadog
8
9
  module CI
@@ -29,7 +30,9 @@ module Datadog
29
30
  @span = span
30
31
  @options = options
31
32
 
32
- @meta = @span.meta.reject { |key, _| Ext::Test::TRANSIENT_TAGS.include?(key) }
33
+ @meta = MetaTruncation.truncate_string_values(
34
+ @span.meta.reject { |key, _| Ext::Test::TRANSIENT_TAGS.include?(key) }
35
+ )
33
36
 
34
37
  @errors = {}
35
38
  @validated = false
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module CI
5
+ module TestTracing
6
+ module Serializers
7
+ module MetaTruncation
8
+ MAX_META_STRING_LENGTH = 5000
9
+
10
+ def self.truncate_value(value)
11
+ return value unless value.is_a?(String) && value.length > MAX_META_STRING_LENGTH
12
+
13
+ value[0, MAX_META_STRING_LENGTH]
14
+ end
15
+
16
+ def self.truncate_string_values(tags)
17
+ tags.transform_values { |value| truncate_value(value) }
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -5,6 +5,7 @@ require "datadog/core/telemetry/logging"
5
5
  require "datadog/core/utils/only_once"
6
6
 
7
7
  require_relative "serializers/factories/test_level"
8
+ require_relative "serializers/meta_truncation"
8
9
 
9
10
  require_relative "../ext/app_types"
10
11
  require_relative "../ext/telemetry"
@@ -105,17 +106,17 @@ module Datadog
105
106
 
106
107
  if dd_env
107
108
  packer.write("env")
108
- packer.write(dd_env)
109
+ packer.write(Serializers::MetaTruncation.truncate_value(dd_env))
109
110
  end
110
111
 
111
112
  packer.write("runtime-id")
112
- packer.write(Datadog::Core::Environment::Identity.id)
113
+ packer.write(Serializers::MetaTruncation.truncate_value(Datadog::Core::Environment::Identity.id))
113
114
 
114
115
  packer.write("language")
115
- packer.write(Datadog::Core::Environment::Identity.lang)
116
+ packer.write(Serializers::MetaTruncation.truncate_value(Datadog::Core::Environment::Identity.lang))
116
117
 
117
118
  packer.write("library_version")
118
- packer.write(Datadog::CI::VERSION::STRING)
119
+ packer.write(Serializers::MetaTruncation.truncate_value(Datadog::CI::VERSION::STRING))
119
120
 
120
121
  library_capabilities_tags = Ext::Test::LibraryCapabilities::CAPABILITY_VERSIONS
121
122
 
@@ -124,14 +125,16 @@ module Datadog
124
125
  packer.write_map_header(2 + library_capabilities_tags.count)
125
126
 
126
127
  packer.write(Ext::Test::TAG_TEST_SESSION_NAME)
127
- packer.write(test_tracing&.logical_test_session_name)
128
+ packer.write(Serializers::MetaTruncation.truncate_value(test_tracing&.logical_test_session_name))
128
129
 
129
130
  packer.write(Ext::Test::TAG_USER_PROVIDED_TEST_SERVICE)
130
- packer.write(Utils::Configuration.service_name_provided_by_user?.to_s)
131
+ packer.write(
132
+ Serializers::MetaTruncation.truncate_value(Utils::Configuration.service_name_provided_by_user?.to_s)
133
+ )
131
134
 
132
135
  library_capabilities_tags.each do |tag, value|
133
136
  packer.write(tag)
134
- packer.write(value)
137
+ packer.write(Serializers::MetaTruncation.truncate_value(value))
135
138
  end
136
139
  end
137
140
 
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module Datadog
6
+ module CI
7
+ module Utils
8
+ module Json
9
+ def self.read_file(file_path)
10
+ unless File.exist?(file_path)
11
+ Datadog.logger.debug { "JSON file not found: #{file_path}" }
12
+ return nil
13
+ end
14
+
15
+ JSON.parse(File.read(file_path))
16
+ rescue JSON::ParserError, SystemCallError => e
17
+ Datadog.logger.debug { "Failed to load JSON file #{file_path}: #{e.message}" }
18
+ nil
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,9 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "json"
4
3
  require_relative "file_storage"
5
- require_relative "test_run"
6
- require_relative "../ext/dd_test"
7
4
 
8
5
  module Datadog
9
6
  module CI
@@ -22,9 +19,8 @@ module Datadog
22
19
 
23
20
  # Load component state
24
21
  def load_component_state
25
- # Check for DDTest cache first
26
- if TestRun.test_optimization_data_cached?
27
- Datadog.logger.debug { "DDTest cache found" }
22
+ if test_optimization_cache.cache_available?
23
+ Datadog.logger.debug { "Test Optimization cache found" }
28
24
  return true if restore_state_from_datadog_test_runner
29
25
  end
30
26
 
@@ -60,22 +56,24 @@ module Datadog
60
56
  false
61
57
  end
62
58
 
63
- def load_json(file_name)
64
- file_path = File.join(Ext::DDTest::TESTOPTIMIZATION_CACHE_PATH, file_name)
59
+ def load_cached_settings
60
+ test_optimization_cache.load_settings
61
+ end
65
62
 
66
- unless File.exist?(file_path)
67
- Datadog.logger.debug { "JSON file not found: #{file_path}" }
68
- return nil
69
- end
63
+ def load_cached_known_tests
64
+ test_optimization_cache.load_known_tests
65
+ end
66
+
67
+ def load_cached_test_management
68
+ test_optimization_cache.load_test_management
69
+ end
70
+
71
+ def load_cached_skippable_tests
72
+ test_optimization_cache.load_skippable_tests
73
+ end
70
74
 
71
- content = File.read(file_path)
72
- JSON.parse(content)
73
- rescue JSON::ParserError => e
74
- Datadog.logger.debug { "Failed to parse JSON file #{file_path}: #{e.message}" }
75
- nil
76
- rescue => e
77
- Datadog.logger.debug { "Failed to load JSON file #{file_path}: #{e.message}" }
78
- nil
75
+ def test_optimization_cache
76
+ Datadog.send(:components).test_optimization_cache
79
77
  end
80
78
  end
81
79
  end
@@ -2,8 +2,6 @@
2
2
 
3
3
  require "etc"
4
4
 
5
- require_relative "../ext/dd_test"
6
-
7
5
  module Datadog
8
6
  module CI
9
7
  module Utils
@@ -44,10 +42,6 @@ module Datadog
44
42
 
45
43
  @virtual_cpu_count = ::Etc.nprocessors
46
44
  end
47
-
48
- def self.test_optimization_data_cached?
49
- Dir.exist?(Ext::DDTest::TESTOPTIMIZATION_CACHE_PATH)
50
- end
51
45
  end
52
46
  end
53
47
  end
@@ -4,7 +4,7 @@ module Datadog
4
4
  module CI
5
5
  module VERSION
6
6
  MAJOR = 1
7
- MINOR = 30
7
+ MINOR = 32
8
8
  PATCH = 0
9
9
  PRE = nil
10
10
  BUILD = nil