spectracer 1.0.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.
- checksums.yaml +7 -0
- data/AGENTS.md +93 -0
- data/CHANGELOG.md +17 -0
- data/LICENSE.txt +21 -0
- data/README.md +177 -0
- data/lib/spectacle.default.yml +15 -0
- data/lib/spectracer/core/paths.rb +46 -0
- data/lib/spectracer/core/spec_selector.rb +28 -0
- data/lib/spectracer/integrations/minitest.rb +55 -0
- data/lib/spectracer/integrations/railtie.rb +13 -0
- data/lib/spectracer/integrations/rspec.rb +30 -0
- data/lib/spectracer/io/command_runner.rb +25 -0
- data/lib/spectracer/io/config_loader.rb +56 -0
- data/lib/spectracer/io/dependency_store.rb +61 -0
- data/lib/spectracer/io/git_adapter.rb +58 -0
- data/lib/spectracer/logger.rb +38 -0
- data/lib/spectracer/orchestrators/dependency_collector.rb +54 -0
- data/lib/spectracer/orchestrators/dependency_tracer.rb +71 -0
- data/lib/spectracer/orchestrators/spec_run_determiner.rb +64 -0
- data/lib/spectracer/providers/git_changed_files.rb +40 -0
- data/lib/spectracer/providers/repository.rb +15 -0
- data/lib/spectracer/tasks/spectacle.rake +37 -0
- data/lib/spectracer/version.rb +5 -0
- data/lib/spectracer.rb +43 -0
- data/sig/spectracer.rbs +195 -0
- metadata +86 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "git"
|
|
4
|
+
|
|
5
|
+
module Spectracer
|
|
6
|
+
module IO
|
|
7
|
+
class GitAdapter
|
|
8
|
+
def initialize(working_dir: Dir.pwd, logger: nil)
|
|
9
|
+
@working_dir = working_dir
|
|
10
|
+
@logger = logger
|
|
11
|
+
@git = nil
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def repository_root
|
|
15
|
+
git.dir.path
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def current_branch
|
|
19
|
+
git.current_branch
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def commit_sha(ref)
|
|
23
|
+
git.object(ref).sha
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def changed_files_in_commit(sha)
|
|
27
|
+
commit = git.object(sha)
|
|
28
|
+
return [] unless commit.respond_to?(:diff_parent)
|
|
29
|
+
|
|
30
|
+
commit.diff_parent.stats[:files].keys
|
|
31
|
+
rescue Git::Error => e
|
|
32
|
+
@logger&.warn("Failed to get changed files for commit #{sha}: #{e.message}")
|
|
33
|
+
[]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def changed_files_against(target_branch, cached: false)
|
|
37
|
+
target_ref = "origin/#{target_branch}"
|
|
38
|
+
|
|
39
|
+
diff = if cached
|
|
40
|
+
git.diff(target_ref, "HEAD")
|
|
41
|
+
else
|
|
42
|
+
git.diff(target_ref)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
diff.stats[:files].keys
|
|
46
|
+
rescue Git::Error => e
|
|
47
|
+
@logger&.warn("Failed to diff against #{target_branch}: #{e.message}")
|
|
48
|
+
[]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def git
|
|
54
|
+
@git ||= Git.open(@working_dir, log: nil)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Spectracer
|
|
4
|
+
class Logger
|
|
5
|
+
LEVELS = {debug: 0, info: 1, warn: 2, error: 3}.freeze
|
|
6
|
+
|
|
7
|
+
def initialize(output: $stderr, level: :info, enabled: false)
|
|
8
|
+
@output = output
|
|
9
|
+
@level = LEVELS.fetch(level, 1)
|
|
10
|
+
@enabled = enabled
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def debug(message)
|
|
14
|
+
log(:debug, message)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def info(message)
|
|
18
|
+
log(:info, message)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def warn(message)
|
|
22
|
+
log(:warn, message)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def error(message)
|
|
26
|
+
log(:error, message)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def log(level, message)
|
|
32
|
+
return unless @enabled
|
|
33
|
+
return if LEVELS[level] < @level
|
|
34
|
+
|
|
35
|
+
@output.puts "[Spectracer] #{level.upcase}: #{message}"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Spectracer
|
|
4
|
+
module Orchestrators
|
|
5
|
+
class DependencyCollector
|
|
6
|
+
def initialize(
|
|
7
|
+
paths: Spectracer::Core::Paths.new,
|
|
8
|
+
store: Spectracer::IO::DependencyStore.new,
|
|
9
|
+
logger: nil
|
|
10
|
+
)
|
|
11
|
+
@paths = paths
|
|
12
|
+
@store = store
|
|
13
|
+
@logger = logger
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.collect!(...)
|
|
17
|
+
new(...).collect!
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def collect!
|
|
21
|
+
inverse_deps = build_inverse_dependencies
|
|
22
|
+
|
|
23
|
+
inverse_deps.each_value(&:sort!)
|
|
24
|
+
|
|
25
|
+
@store.write(inverse_deps, @paths.collected_dependencies_file)
|
|
26
|
+
|
|
27
|
+
nil
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def build_inverse_dependencies
|
|
33
|
+
inverse = Hash.new { |h, k| h[k] = [] }
|
|
34
|
+
|
|
35
|
+
artifact_files.each do |file|
|
|
36
|
+
@logger&.debug("Processing artifact: #{file}")
|
|
37
|
+
data = @store.read(file)
|
|
38
|
+
|
|
39
|
+
data.each do |spec_file, dependencies|
|
|
40
|
+
dependencies.each do |dep|
|
|
41
|
+
inverse[dep] << spec_file unless inverse[dep].include?(spec_file)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
inverse
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def artifact_files
|
|
50
|
+
@store.glob(@paths.spec_artifacts_download_glob)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Spectracer
|
|
4
|
+
module Orchestrators
|
|
5
|
+
class DependencyTracer
|
|
6
|
+
def initialize(
|
|
7
|
+
paths: Spectracer::Core::Paths.new,
|
|
8
|
+
store: Spectracer::IO::DependencyStore.new,
|
|
9
|
+
repository: Spectracer::Providers::Repository.new,
|
|
10
|
+
logger: nil
|
|
11
|
+
)
|
|
12
|
+
@paths = paths
|
|
13
|
+
@store = store
|
|
14
|
+
@repository = repository
|
|
15
|
+
@logger = logger
|
|
16
|
+
@current_spec_file = nil
|
|
17
|
+
@spec_file_dependencies = Hash.new { |h, k| h[k] = Set.new }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
attr_writer :current_spec_file
|
|
21
|
+
|
|
22
|
+
def with_tracing(&block)
|
|
23
|
+
tracepoint.enable
|
|
24
|
+
block.call
|
|
25
|
+
ensure
|
|
26
|
+
tracepoint.disable
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def write_output!
|
|
30
|
+
output = build_output
|
|
31
|
+
|
|
32
|
+
if output.empty?
|
|
33
|
+
@logger&.debug("No dependencies found.")
|
|
34
|
+
return
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
@store.write(output, @paths.spec_artifact_output_file)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def tracepoint
|
|
43
|
+
@tracepoint ||= TracePoint.new(:call) do |tp|
|
|
44
|
+
path = tp.path
|
|
45
|
+
next unless path.start_with?(repository_root)
|
|
46
|
+
next if @current_spec_file.nil?
|
|
47
|
+
|
|
48
|
+
file_path = normalize_path(path)
|
|
49
|
+
next if @current_spec_file == file_path
|
|
50
|
+
|
|
51
|
+
@spec_file_dependencies[@current_spec_file].add(file_path)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def repository_root
|
|
56
|
+
@repository_root ||= @repository.root
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def normalize_path(path)
|
|
60
|
+
@paths.normalize(path, repo_root: repository_root)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def build_output
|
|
64
|
+
@spec_file_dependencies.each_with_object({}) do |(spec_file, files), acc|
|
|
65
|
+
next if files.empty?
|
|
66
|
+
acc[spec_file] = files.to_a.sort
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Spectracer
|
|
4
|
+
module Orchestrators
|
|
5
|
+
class SpecRunDeterminer
|
|
6
|
+
def initialize(
|
|
7
|
+
paths: Spectracer::Core::Paths.new,
|
|
8
|
+
store: Spectracer::IO::DependencyStore.new,
|
|
9
|
+
config_loader: Spectracer::IO::ConfigLoader.new,
|
|
10
|
+
changed_files_provider: Spectracer::Providers::GitChangedFiles.new,
|
|
11
|
+
selector: Spectracer::Core::SpecSelector.new,
|
|
12
|
+
logger: nil
|
|
13
|
+
)
|
|
14
|
+
@paths = paths
|
|
15
|
+
@store = store
|
|
16
|
+
@config_loader = config_loader
|
|
17
|
+
@changed_files_provider = changed_files_provider
|
|
18
|
+
@selector = selector
|
|
19
|
+
@logger = logger
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.determine!(...)
|
|
23
|
+
new(...).determine!
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def determine!
|
|
27
|
+
dependencies = load_dependencies
|
|
28
|
+
config = @config_loader.load
|
|
29
|
+
changed_files = @changed_files_provider.call
|
|
30
|
+
|
|
31
|
+
log_debug_info(config, changed_files)
|
|
32
|
+
|
|
33
|
+
@selector.call(
|
|
34
|
+
changed_files: changed_files,
|
|
35
|
+
inverse_deps: dependencies,
|
|
36
|
+
globs: config[:globs],
|
|
37
|
+
on_empty: config[:on_empty_spec_set]
|
|
38
|
+
)
|
|
39
|
+
rescue => e
|
|
40
|
+
@logger&.error("Error determining specs: #{e.message}")
|
|
41
|
+
@logger&.error(e.backtrace&.join("\n"))
|
|
42
|
+
nil
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def load_dependencies
|
|
48
|
+
deps_file = @paths.collected_dependencies_file
|
|
49
|
+
|
|
50
|
+
unless File.exist?(deps_file)
|
|
51
|
+
@logger&.debug("No dependencies file found at #{deps_file.inspect}")
|
|
52
|
+
return {}
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
@store.read(deps_file)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def log_debug_info(config, changed_files)
|
|
59
|
+
@logger&.debug("Configuration: #{config.inspect}")
|
|
60
|
+
@logger&.debug("Changed files: #{changed_files.inspect}")
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Spectracer
|
|
4
|
+
module Providers
|
|
5
|
+
class GitChangedFiles
|
|
6
|
+
def initialize(git_adapter: Spectracer::IO::GitAdapter.new, env: ENV, logger: nil)
|
|
7
|
+
@git_adapter = git_adapter
|
|
8
|
+
@env = env
|
|
9
|
+
@logger = logger
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def call
|
|
13
|
+
default_branch = @env.fetch("BUILDKITE_PIPELINE_DEFAULT_BRANCH", "main")
|
|
14
|
+
current_branch = @env.fetch("BUILDKITE_BRANCH") { @git_adapter.current_branch }
|
|
15
|
+
|
|
16
|
+
files = if current_branch == default_branch
|
|
17
|
+
changed_files_for_latest_commit(current_branch)
|
|
18
|
+
else
|
|
19
|
+
changed_files_against_default_branch(default_branch)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
@logger&.debug("Changed files: #{files.inspect}")
|
|
23
|
+
files
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def changed_files_for_latest_commit(branch)
|
|
29
|
+
sha = @git_adapter.commit_sha(branch)
|
|
30
|
+
@logger&.debug("Latest commit SHA: #{sha}")
|
|
31
|
+
|
|
32
|
+
@git_adapter.changed_files_in_commit(sha)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def changed_files_against_default_branch(default_branch)
|
|
36
|
+
@git_adapter.changed_files_against(default_branch, cached: true)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Spectracer
|
|
4
|
+
module Providers
|
|
5
|
+
class Repository
|
|
6
|
+
def initialize(git_adapter: Spectracer::IO::GitAdapter.new)
|
|
7
|
+
@git_adapter = git_adapter
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def root
|
|
11
|
+
@root ||= @git_adapter.repository_root
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
namespace :spectracer do
|
|
4
|
+
desc "Install Spectracer configuration file"
|
|
5
|
+
task :install do
|
|
6
|
+
config_path = Spectracer::IO::ConfigLoader::FILE_PATH
|
|
7
|
+
|
|
8
|
+
if File.exist?(config_path)
|
|
9
|
+
warn "Spectracer is already installed."
|
|
10
|
+
exit 0
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
warn "Creating '#{config_path}' file."
|
|
14
|
+
|
|
15
|
+
default_content = File.read(Spectracer::IO::ConfigLoader::DEFAULT_FILE_PATH)
|
|
16
|
+
File.write(config_path, default_content)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
desc "Collect spec dependencies from tracing artifacts"
|
|
20
|
+
task :collect_dependencies do
|
|
21
|
+
logger = Spectracer::Logger.new(
|
|
22
|
+
enabled: ENV["WITH_SPECTACLE_DEBUG"] == "true",
|
|
23
|
+
level: :debug
|
|
24
|
+
)
|
|
25
|
+
Spectracer::Orchestrators::DependencyCollector.collect!(logger: logger)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
desc "Print the list of specs to run based on changed files"
|
|
29
|
+
task :spec_determiner do
|
|
30
|
+
logger = Spectracer::Logger.new(
|
|
31
|
+
enabled: ENV["WITH_SPECTACLE_DEBUG"] == "true",
|
|
32
|
+
level: :debug
|
|
33
|
+
)
|
|
34
|
+
result = Spectracer::Orchestrators::SpecRunDeterminer.determine!(logger: logger)
|
|
35
|
+
$stdout.puts "'#{result}'"
|
|
36
|
+
end
|
|
37
|
+
end
|
data/lib/spectracer.rb
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "spectracer/version"
|
|
4
|
+
require_relative "spectracer/logger"
|
|
5
|
+
|
|
6
|
+
require_relative "spectracer/core/paths"
|
|
7
|
+
require_relative "spectracer/core/spec_selector"
|
|
8
|
+
|
|
9
|
+
require_relative "spectracer/io/command_runner"
|
|
10
|
+
require_relative "spectracer/io/dependency_store"
|
|
11
|
+
require_relative "spectracer/io/config_loader"
|
|
12
|
+
require_relative "spectracer/io/git_adapter"
|
|
13
|
+
|
|
14
|
+
require_relative "spectracer/providers/repository"
|
|
15
|
+
require_relative "spectracer/providers/git_changed_files"
|
|
16
|
+
|
|
17
|
+
require_relative "spectracer/orchestrators/dependency_tracer"
|
|
18
|
+
require_relative "spectracer/orchestrators/dependency_collector"
|
|
19
|
+
require_relative "spectracer/orchestrators/spec_run_determiner"
|
|
20
|
+
|
|
21
|
+
require_relative "spectracer/integrations/rspec"
|
|
22
|
+
require_relative "spectracer/integrations/minitest"
|
|
23
|
+
require_relative "spectracer/integrations/railtie" if defined?(Rails)
|
|
24
|
+
|
|
25
|
+
module Spectracer
|
|
26
|
+
class Error < StandardError; end
|
|
27
|
+
|
|
28
|
+
class << self
|
|
29
|
+
def logger
|
|
30
|
+
@logger ||= Logger.new(
|
|
31
|
+
enabled: ENV["WITH_SPECTRACER_DEBUG"] == "true",
|
|
32
|
+
level: :debug
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def paths
|
|
37
|
+
@paths ||= Core::Paths.new
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
Spectracer::Integrations::RSpec.install!
|
|
43
|
+
Spectracer::Integrations::Minitest.install!
|
data/sig/spectracer.rbs
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
module Spectracer
|
|
2
|
+
VERSION: String
|
|
3
|
+
|
|
4
|
+
class Error < StandardError
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def self.logger: () -> Logger
|
|
8
|
+
def self.paths: () -> Core::Paths
|
|
9
|
+
|
|
10
|
+
class Logger
|
|
11
|
+
LEVELS: Hash[Symbol, Integer]
|
|
12
|
+
|
|
13
|
+
def initialize: (?output: IO, ?level: Symbol, ?enabled: bool) -> void
|
|
14
|
+
def debug: (String message) -> void
|
|
15
|
+
def info: (String message) -> void
|
|
16
|
+
def warn: (String message) -> void
|
|
17
|
+
def error: (String message) -> void
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def log: (Symbol level, String message) -> void
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
module Core
|
|
25
|
+
class Paths
|
|
26
|
+
DEFAULT_OUTPUT_DIR: String
|
|
27
|
+
|
|
28
|
+
def initialize: (?env: Hash[String, String?]) -> void
|
|
29
|
+
def build_id: () -> String
|
|
30
|
+
def job_id: () -> String
|
|
31
|
+
def output_directory: () -> String
|
|
32
|
+
def spec_artifact_output_file: () -> String
|
|
33
|
+
def spec_artifacts_download_glob: () -> String
|
|
34
|
+
def collected_dependencies_file: () -> String
|
|
35
|
+
def normalize: (String file_path, repo_root: String) -> String
|
|
36
|
+
def strip_dot_prefix: (String path) -> String
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class SpecSelector
|
|
40
|
+
def call: (
|
|
41
|
+
changed_files: Array[String],
|
|
42
|
+
inverse_deps: Hash[String, Array[String]],
|
|
43
|
+
globs: Hash[String, String],
|
|
44
|
+
on_empty: String
|
|
45
|
+
) -> String
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
module IO
|
|
50
|
+
class CommandRunner
|
|
51
|
+
def initialize: (?logger: Logger?) -> void
|
|
52
|
+
def run: (String command) -> String
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
class DependencyStore
|
|
56
|
+
def initialize: (?logger: Logger?) -> void
|
|
57
|
+
def read: (String file_path) -> Hash[String, untyped]
|
|
58
|
+
def write: (Hash[String, untyped] data, String file_path) -> void
|
|
59
|
+
def glob: (String pattern) -> Array[String]
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def read_gzipped_json: (String file_path) -> Hash[String, untyped]
|
|
64
|
+
def read_json: (String file_path) -> Hash[String, untyped]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
class ConfigLoader
|
|
68
|
+
FILE_PATH: String
|
|
69
|
+
DEFAULT_FILE_PATH: String
|
|
70
|
+
|
|
71
|
+
def initialize: (?logger: Logger?) -> void
|
|
72
|
+
def load: () -> Hash[Symbol, untyped]
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
def load_raw_config: () -> Hash[String, untyped]?
|
|
77
|
+
def parse_config: (Hash[String, untyped] raw) -> Hash[Symbol, untyped]
|
|
78
|
+
def resolve_templates: (String template, Hash[String, String] defaults) -> String
|
|
79
|
+
def default_config: () -> Hash[Symbol, untyped]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
class GitAdapter
|
|
83
|
+
def initialize: (?working_dir: String, ?logger: Logger?) -> void
|
|
84
|
+
def repository_root: () -> String
|
|
85
|
+
def current_branch: () -> String
|
|
86
|
+
def commit_sha: (String ref) -> String
|
|
87
|
+
def changed_files_in_commit: (String sha) -> Array[String]
|
|
88
|
+
def changed_files_against: (String target_branch, ?cached: bool) -> Array[String]
|
|
89
|
+
|
|
90
|
+
private
|
|
91
|
+
|
|
92
|
+
def git: () -> untyped
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
module Providers
|
|
97
|
+
class Repository
|
|
98
|
+
def initialize: (?git_adapter: IO::GitAdapter) -> void
|
|
99
|
+
def root: () -> String
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
class GitChangedFiles
|
|
103
|
+
def initialize: (
|
|
104
|
+
?git_adapter: IO::GitAdapter,
|
|
105
|
+
?env: Hash[String, String?],
|
|
106
|
+
?logger: Logger?
|
|
107
|
+
) -> void
|
|
108
|
+
def call: () -> Array[String]
|
|
109
|
+
|
|
110
|
+
private
|
|
111
|
+
|
|
112
|
+
def changed_files_for_latest_commit: (String branch) -> Array[String]
|
|
113
|
+
def changed_files_against_default_branch: (String default_branch) -> Array[String]
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
module Orchestrators
|
|
118
|
+
class DependencyTracer
|
|
119
|
+
attr_writer current_spec_file: String?
|
|
120
|
+
|
|
121
|
+
def initialize: (
|
|
122
|
+
?paths: Core::Paths,
|
|
123
|
+
?store: IO::DependencyStore,
|
|
124
|
+
?repository: Providers::Repository,
|
|
125
|
+
?logger: Logger?
|
|
126
|
+
) -> void
|
|
127
|
+
def with_tracing: () { () -> void } -> void
|
|
128
|
+
def write_output!: () -> void
|
|
129
|
+
|
|
130
|
+
private
|
|
131
|
+
|
|
132
|
+
def tracepoint: () -> TracePoint
|
|
133
|
+
def repository_root: () -> String
|
|
134
|
+
def normalize_path: (String path) -> String
|
|
135
|
+
def build_output: () -> Hash[String, Array[String]]
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
class DependencyCollector
|
|
139
|
+
def initialize: (
|
|
140
|
+
?paths: Core::Paths,
|
|
141
|
+
?store: IO::DependencyStore,
|
|
142
|
+
?logger: Logger?
|
|
143
|
+
) -> void
|
|
144
|
+
def self.collect!: (**untyped) -> nil
|
|
145
|
+
def collect!: () -> nil
|
|
146
|
+
|
|
147
|
+
private
|
|
148
|
+
|
|
149
|
+
def build_inverse_dependencies: () -> Hash[String, Array[String]]
|
|
150
|
+
def artifact_files: () -> Array[String]
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
class SpecRunDeterminer
|
|
154
|
+
def initialize: (
|
|
155
|
+
?paths: Core::Paths,
|
|
156
|
+
?store: IO::DependencyStore,
|
|
157
|
+
?config_loader: IO::ConfigLoader,
|
|
158
|
+
?changed_files_provider: Providers::GitChangedFiles,
|
|
159
|
+
?selector: Core::SpecSelector,
|
|
160
|
+
?logger: Logger?
|
|
161
|
+
) -> void
|
|
162
|
+
def self.determine!: (**untyped) -> String?
|
|
163
|
+
def determine!: () -> String?
|
|
164
|
+
|
|
165
|
+
private
|
|
166
|
+
|
|
167
|
+
def load_dependencies: () -> Hash[String, Array[String]]
|
|
168
|
+
def log_debug_info: (Hash[Symbol, untyped] config, Array[String] changed_files) -> void
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
module Integrations
|
|
173
|
+
module RSpec
|
|
174
|
+
def self.install!: () -> void
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
module Minitest
|
|
178
|
+
attr_accessor self.tracer: Orchestrators::DependencyTracer?
|
|
179
|
+
|
|
180
|
+
def self.install!: () -> void
|
|
181
|
+
|
|
182
|
+
module RunPatch
|
|
183
|
+
def run: (?Array[String] args) -> untyped
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
module TestCasePlugin
|
|
187
|
+
def before_setup: () -> void
|
|
188
|
+
def run: () -> untyped
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
class Railtie < Rails::Railtie
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|