knapsack_pro 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -3
- data/CHANGELOG.md +4 -0
- data/README.md +368 -4
- data/bin/knapsack_pro +20 -0
- data/circle.yml +2 -0
- data/knapsack_pro.gemspec +6 -1
- data/lib/knapsack_pro.rb +74 -0
- data/lib/knapsack_pro/adapters/base_adapter.rb +30 -0
- data/lib/knapsack_pro/adapters/cucumber_adapter.rb +40 -0
- data/lib/knapsack_pro/adapters/minitest_adapter.rb +52 -0
- data/lib/knapsack_pro/adapters/rspec_adapter.rb +48 -0
- data/lib/knapsack_pro/allocator.rb +40 -0
- data/lib/knapsack_pro/allocator_builder.rb +40 -0
- data/lib/knapsack_pro/client/api/action.rb +17 -0
- data/lib/knapsack_pro/client/api/v1/base.rb +15 -0
- data/lib/knapsack_pro/client/api/v1/build_distributions.rb +29 -0
- data/lib/knapsack_pro/client/api/v1/build_subsets.rb +29 -0
- data/lib/knapsack_pro/client/connection.rb +94 -0
- data/lib/knapsack_pro/config/ci/base.rb +22 -0
- data/lib/knapsack_pro/config/ci/buildkite.rb +27 -0
- data/lib/knapsack_pro/config/ci/circle.rb +29 -0
- data/lib/knapsack_pro/config/ci/semaphore.rb +28 -0
- data/lib/knapsack_pro/config/env.rb +111 -0
- data/lib/knapsack_pro/logger_wrapper.rb +15 -0
- data/lib/knapsack_pro/presenter.rb +25 -0
- data/lib/knapsack_pro/report.rb +20 -0
- data/lib/knapsack_pro/repository_adapter_initiator.rb +12 -0
- data/lib/knapsack_pro/repository_adapters/base_adapter.rb +14 -0
- data/lib/knapsack_pro/repository_adapters/env_adapter.rb +13 -0
- data/lib/knapsack_pro/repository_adapters/git_adapter.rb +19 -0
- data/lib/knapsack_pro/runners/base_runner.rb +31 -0
- data/lib/knapsack_pro/runners/cucumber_runner.rb +16 -0
- data/lib/knapsack_pro/runners/minitest_runner.rb +26 -0
- data/lib/knapsack_pro/runners/rspec_runner.rb +16 -0
- data/lib/knapsack_pro/task_loader.rb +11 -0
- data/lib/knapsack_pro/test_file_cleaner.rb +7 -0
- data/lib/knapsack_pro/test_file_finder.rb +33 -0
- data/lib/knapsack_pro/test_file_pattern.rb +7 -0
- data/lib/knapsack_pro/test_file_presenter.rb +11 -0
- data/lib/knapsack_pro/test_flat_distributor.rb +84 -0
- data/lib/knapsack_pro/tracker.rb +64 -0
- data/lib/knapsack_pro/version.rb +1 -1
- data/lib/tasks/cucumber.rake +7 -0
- data/lib/tasks/minitest.rake +7 -0
- data/lib/tasks/rspec.rake +7 -0
- data/spec/fixtures/vcr_cassettes/api/v1/build_distributions/subset/invalid_test_suite_token.yml +50 -0
- data/spec/fixtures/vcr_cassettes/api/v1/build_distributions/subset/success.yml +52 -0
- data/spec/fixtures/vcr_cassettes/api/v1/build_subsets/create/invalid_test_suite_token.yml +50 -0
- data/spec/fixtures/vcr_cassettes/api/v1/build_subsets/create/success.yml +50 -0
- data/spec/integration/api/build_distributions_subset_spec.rb +74 -0
- data/spec/integration/api/build_subsets_create_spec.rb +76 -0
- data/spec/knapsack_pro/adapters/base_adapter_spec.rb +63 -0
- data/spec/knapsack_pro/adapters/cucumber_adapter_spec.rb +71 -0
- data/spec/knapsack_pro/adapters/minitest_adapter_spec.rb +107 -0
- data/spec/knapsack_pro/adapters/rspec_adapter_spec.rb +94 -0
- data/spec/knapsack_pro/allocator_builder_spec.rb +45 -0
- data/spec/knapsack_pro/allocator_spec.rb +80 -0
- data/spec/knapsack_pro/client/api/action_spec.rb +17 -0
- data/spec/knapsack_pro/client/api/v1/base_spec.rb +2 -0
- data/spec/knapsack_pro/client/api/v1/build_distributions_spec.rb +35 -0
- data/spec/knapsack_pro/client/api/v1/build_subsets_spec.rb +35 -0
- data/spec/knapsack_pro/client/connection_spec.rb +138 -0
- data/spec/knapsack_pro/config/ci/base_spec.rb +7 -0
- data/spec/knapsack_pro/config/ci/buildkite_spec.rb +74 -0
- data/spec/knapsack_pro/config/ci/circle_spec.rb +74 -0
- data/spec/knapsack_pro/config/ci/semaphore_spec.rb +74 -0
- data/spec/knapsack_pro/config/env_spec.rb +368 -0
- data/spec/knapsack_pro/logger_wrapper_spec.rb +15 -0
- data/spec/knapsack_pro/presenter_spec.rb +57 -0
- data/spec/knapsack_pro/report_spec.rb +68 -0
- data/spec/knapsack_pro/repository_adapter_initiator_spec.rb +21 -0
- data/spec/knapsack_pro/repository_adapters/base_adapter_spec.rb +13 -0
- data/spec/knapsack_pro/repository_adapters/env_adapter_spec.rb +27 -0
- data/spec/knapsack_pro/repository_adapters/git_adapter_spec.rb +27 -0
- data/spec/knapsack_pro/runners/base_runner_spec.rb +61 -0
- data/spec/knapsack_pro/runners/cucumber_runner_spec.rb +47 -0
- data/spec/knapsack_pro/runners/minitest_runner_spec.rb +34 -0
- data/spec/knapsack_pro/runners/rspec_runner_spec.rb +49 -0
- data/spec/knapsack_pro/task_loader_spec.rb +14 -0
- data/spec/knapsack_pro/test_file_cleaner_spec.rb +11 -0
- data/spec/knapsack_pro/test_file_finder_spec.rb +35 -0
- data/spec/knapsack_pro/test_file_pattern_spec.rb +23 -0
- data/spec/knapsack_pro/test_file_presenter_spec.rb +22 -0
- data/spec/knapsack_pro/test_flat_distributor_spec.rb +60 -0
- data/spec/knapsack_pro/tracker_spec.rb +102 -0
- data/spec/knapsack_pro_spec.rb +56 -0
- data/spec/spec_helper.rb +11 -1
- data/spec/support/fakes/cucumber.rb +12 -0
- data/spec/support/fakes/minitest.rb +12 -0
- data/spec/support/shared_examples/adapter.rb +17 -0
- data/spec_fake/controllers/users_controller_spec.rb +0 -0
- data/spec_fake/models/admin_spec.rb +0 -0
- data/spec_fake/models/user_spec.rb +0 -0
- data/spec_fake/spec_helper.rb +0 -0
- data/test_fake/a_test.rb +0 -0
- data/test_fake/b_test.rb +0 -0
- metadata +212 -12
- data/Gemfile.lock +0 -69
- data/spec/knapsack_spec.rb +0 -3
@@ -0,0 +1,94 @@
|
|
1
|
+
module KnapsackPro
|
2
|
+
module Client
|
3
|
+
class Connection
|
4
|
+
TIMEOUT = 15
|
5
|
+
|
6
|
+
def initialize(action)
|
7
|
+
@action = action
|
8
|
+
end
|
9
|
+
|
10
|
+
def call
|
11
|
+
send(action.http_method)
|
12
|
+
end
|
13
|
+
|
14
|
+
def success?
|
15
|
+
!!response
|
16
|
+
end
|
17
|
+
|
18
|
+
def errors?
|
19
|
+
!!(response && (response['errors'] || response['error']))
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
attr_reader :action, :response
|
25
|
+
|
26
|
+
def logger
|
27
|
+
KnapsackPro.logger
|
28
|
+
end
|
29
|
+
|
30
|
+
def endpoint
|
31
|
+
KnapsackPro::Config::Env.endpoint
|
32
|
+
end
|
33
|
+
|
34
|
+
def endpoint_url
|
35
|
+
endpoint + action.endpoint_path
|
36
|
+
end
|
37
|
+
|
38
|
+
def request_hash
|
39
|
+
action
|
40
|
+
.request_hash
|
41
|
+
.merge({
|
42
|
+
test_suite_token: test_suite_token
|
43
|
+
})
|
44
|
+
end
|
45
|
+
|
46
|
+
def request_body
|
47
|
+
request_hash.to_json
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_suite_token
|
51
|
+
KnapsackPro::Config::Env.test_suite_token
|
52
|
+
end
|
53
|
+
|
54
|
+
def json_headers
|
55
|
+
{
|
56
|
+
'Content-Type' => 'application/json',
|
57
|
+
'Accept' => 'application/json'
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def parse_response(body)
|
62
|
+
return '' if body == '' || body.nil?
|
63
|
+
JSON.parse(body)
|
64
|
+
rescue JSON::ParserError
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
|
68
|
+
def post
|
69
|
+
uri = URI.parse(endpoint_url)
|
70
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
71
|
+
http.use_ssl = (uri.scheme == 'https')
|
72
|
+
http.open_timeout = TIMEOUT
|
73
|
+
http.read_timeout = TIMEOUT
|
74
|
+
|
75
|
+
http_response = http.post(uri.path, request_body, json_headers)
|
76
|
+
@response = parse_response(http_response.body)
|
77
|
+
|
78
|
+
request_uuid = http_response.header['X-Request-Id']
|
79
|
+
|
80
|
+
logger.info("API request UUID: #{request_uuid}")
|
81
|
+
logger.info('API response:')
|
82
|
+
if errors?
|
83
|
+
logger.error(response)
|
84
|
+
else
|
85
|
+
logger.info(response)
|
86
|
+
end
|
87
|
+
|
88
|
+
response
|
89
|
+
rescue Errno::ECONNREFUSED, EOFError, Net::OpenTimeout, Net::ReadTimeout => e
|
90
|
+
logger.warn(e.inspect)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module KnapsackPro
|
2
|
+
module Config
|
3
|
+
module CI
|
4
|
+
class Buildkite < Base
|
5
|
+
def node_total
|
6
|
+
ENV['BUILDKITE_PARALLEL_JOB_COUNT']
|
7
|
+
end
|
8
|
+
|
9
|
+
def node_index
|
10
|
+
ENV['BUILDKITE_PARALLEL_JOB']
|
11
|
+
end
|
12
|
+
|
13
|
+
def commit_hash
|
14
|
+
ENV['BUILDKITE_COMMIT']
|
15
|
+
end
|
16
|
+
|
17
|
+
def branch
|
18
|
+
ENV['BUILDKITE_BRANCH']
|
19
|
+
end
|
20
|
+
|
21
|
+
def project_dir
|
22
|
+
ENV['BUILDKITE_BUILD_CHECKOUT_PATH']
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module KnapsackPro
|
2
|
+
module Config
|
3
|
+
module CI
|
4
|
+
class Circle < Base
|
5
|
+
def node_total
|
6
|
+
ENV['CIRCLE_NODE_TOTAL']
|
7
|
+
end
|
8
|
+
|
9
|
+
def node_index
|
10
|
+
ENV['CIRCLE_NODE_INDEX']
|
11
|
+
end
|
12
|
+
|
13
|
+
def commit_hash
|
14
|
+
ENV['CIRCLE_SHA1']
|
15
|
+
end
|
16
|
+
|
17
|
+
def branch
|
18
|
+
ENV['CIRCLE_BRANCH']
|
19
|
+
end
|
20
|
+
|
21
|
+
def project_dir
|
22
|
+
project_repo_name = ENV['CIRCLE_PROJECT_REPONAME']
|
23
|
+
"/home/ubuntu/#{project_repo_name}" if project_repo_name
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module KnapsackPro
|
2
|
+
module Config
|
3
|
+
module CI
|
4
|
+
class Semaphore < Base
|
5
|
+
def node_total
|
6
|
+
ENV['SEMAPHORE_THREAD_COUNT']
|
7
|
+
end
|
8
|
+
|
9
|
+
def node_index
|
10
|
+
index = ENV['SEMAPHORE_CURRENT_THREAD']
|
11
|
+
index.to_i - 1 if index
|
12
|
+
end
|
13
|
+
|
14
|
+
def commit_hash
|
15
|
+
ENV['REVISION']
|
16
|
+
end
|
17
|
+
|
18
|
+
def branch
|
19
|
+
ENV['BRANCH_NAME']
|
20
|
+
end
|
21
|
+
|
22
|
+
def project_dir
|
23
|
+
ENV['SEMAPHORE_PROJECT_DIR']
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module KnapsackPro
|
2
|
+
module Config
|
3
|
+
class Env
|
4
|
+
class << self
|
5
|
+
def ci_node_total
|
6
|
+
(ENV['KNAPSACK_PRO_CI_NODE_TOTAL'] ||
|
7
|
+
ci_env_for(:node_total) ||
|
8
|
+
1).to_i
|
9
|
+
end
|
10
|
+
|
11
|
+
def ci_node_index
|
12
|
+
(ENV['KNAPSACK_PRO_CI_NODE_INDEX'] ||
|
13
|
+
ci_env_for(:node_index) ||
|
14
|
+
0).to_i
|
15
|
+
end
|
16
|
+
|
17
|
+
def commit_hash
|
18
|
+
ENV['KNAPSACK_PRO_COMMIT_HASH'] ||
|
19
|
+
ci_env_for(:commit_hash)
|
20
|
+
end
|
21
|
+
|
22
|
+
def branch
|
23
|
+
ENV['KNAPSACK_PRO_BRANCH'] ||
|
24
|
+
ci_env_for(:branch)
|
25
|
+
end
|
26
|
+
|
27
|
+
def project_dir
|
28
|
+
ENV['KNAPSACK_PRO_PROJECT_DIR'] ||
|
29
|
+
ci_env_for(:project_dir)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_file_pattern
|
33
|
+
ENV['KNAPSACK_PRO_TEST_FILE_PATTERN']
|
34
|
+
end
|
35
|
+
|
36
|
+
def repository_adapter
|
37
|
+
ENV['KNAPSACK_PRO_REPOSITORY_ADAPTER']
|
38
|
+
end
|
39
|
+
|
40
|
+
def recording_enabled
|
41
|
+
ENV['KNAPSACK_PRO_RECORDING_ENABLED']
|
42
|
+
end
|
43
|
+
|
44
|
+
def recording_enabled?
|
45
|
+
recording_enabled == 'true'
|
46
|
+
end
|
47
|
+
|
48
|
+
def endpoint
|
49
|
+
env_name = 'KNAPSACK_PRO_ENDPOINT'
|
50
|
+
return ENV[env_name] if ENV[env_name]
|
51
|
+
|
52
|
+
case mode
|
53
|
+
when :development
|
54
|
+
'http://api.knapsackpro.dev:3000'
|
55
|
+
when :test
|
56
|
+
'http://api-staging.knapsackpro.com'
|
57
|
+
when :production
|
58
|
+
'http://api.knapsackpro.com'
|
59
|
+
else
|
60
|
+
required_env(env_name)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_suite_token
|
65
|
+
required_env('KNAPSACK_PRO_TEST_SUITE_TOKEN')
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_suite_token_rspec
|
69
|
+
ENV['KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC']
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_suite_token_minitest
|
73
|
+
ENV['KNAPSACK_PRO_TEST_SUITE_TOKEN_MINITEST']
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_suite_token_cucumber
|
77
|
+
ENV['KNAPSACK_PRO_TEST_SUITE_TOKEN_CUCUMBER']
|
78
|
+
end
|
79
|
+
|
80
|
+
def mode
|
81
|
+
mode = ENV['KNAPSACK_PRO_MODE']
|
82
|
+
return :production if mode.nil?
|
83
|
+
mode = mode.to_sym
|
84
|
+
if [:development, :test, :production].include?(mode)
|
85
|
+
mode
|
86
|
+
else
|
87
|
+
raise ArgumentError.new('Wrong mode name')
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def ci_env_for(env_name)
|
92
|
+
value = nil
|
93
|
+
ci_list = KnapsackPro::Config::CI.constants - [:Base]
|
94
|
+
ci_list.each do |ci_name|
|
95
|
+
ci_class = Object.const_get("KnapsackPro::Config::CI::#{ci_name}")
|
96
|
+
ci = ci_class.new
|
97
|
+
value = ci.send(env_name)
|
98
|
+
break unless value.nil?
|
99
|
+
end
|
100
|
+
value
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def required_env(env_name)
|
106
|
+
ENV[env_name] || raise("Missing environment variable #{env_name}")
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module KnapsackPro
|
2
|
+
class LoggerWrapper
|
3
|
+
def initialize(logger)
|
4
|
+
@logger = ::ActiveSupport::TaggedLogging.new(logger)
|
5
|
+
end
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
attr_reader :logger
|
10
|
+
|
11
|
+
def method_missing(m, *args, &block)
|
12
|
+
logger.tagged('knapsack_pro') { logger.send(m, *args, &block) }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module KnapsackPro
|
2
|
+
class Presenter
|
3
|
+
class << self
|
4
|
+
def global_time
|
5
|
+
global_time = pretty_seconds(KnapsackPro.tracker.global_time)
|
6
|
+
"Global time execution for tests: #{global_time}"
|
7
|
+
end
|
8
|
+
|
9
|
+
def pretty_seconds(seconds)
|
10
|
+
sign = ''
|
11
|
+
|
12
|
+
if seconds < 0
|
13
|
+
seconds = seconds*-1
|
14
|
+
sign = '-'
|
15
|
+
end
|
16
|
+
|
17
|
+
return "#{sign}#{seconds}s" if seconds.abs < 1
|
18
|
+
|
19
|
+
time = Time.at(seconds).gmtime.strftime('%Hh %Mm %Ss')
|
20
|
+
time_without_zeros = time.gsub(/00(h|m|s)/, '').strip
|
21
|
+
sign + time_without_zeros
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module KnapsackPro
|
2
|
+
class Report
|
3
|
+
def self.save
|
4
|
+
repository_adapter = KnapsackPro::RepositoryAdapterInitiator.call
|
5
|
+
action = KnapsackPro::Client::API::V1::BuildSubsets.create(
|
6
|
+
commit_hash: repository_adapter.commit_hash,
|
7
|
+
branch: repository_adapter.branch,
|
8
|
+
node_total: KnapsackPro::Config::Env.ci_node_total,
|
9
|
+
node_index: KnapsackPro::Config::Env.ci_node_index,
|
10
|
+
test_files: KnapsackPro.tracker.to_a,
|
11
|
+
)
|
12
|
+
connection = KnapsackPro::Client::Connection.new(action)
|
13
|
+
response = connection.call
|
14
|
+
if connection.success?
|
15
|
+
raise ArgumentError.new(response) if connection.errors?
|
16
|
+
KnapsackPro.logger.info('Saved time execution report on API server.')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module KnapsackPro
|
2
|
+
class RepositoryAdapterInitiator
|
3
|
+
def self.call
|
4
|
+
case KnapsackPro::Config::Env.repository_adapter
|
5
|
+
when 'git'
|
6
|
+
KnapsackPro::RepositoryAdapters::GitAdapter.new
|
7
|
+
else
|
8
|
+
KnapsackPro::RepositoryAdapters::EnvAdapter.new
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module KnapsackPro
|
2
|
+
module RepositoryAdapters
|
3
|
+
class GitAdapter < BaseAdapter
|
4
|
+
def commit_hash
|
5
|
+
`git -C "#{working_dir}" rev-parse HEAD`.strip
|
6
|
+
end
|
7
|
+
|
8
|
+
def branch
|
9
|
+
`git -C "#{working_dir}" rev-parse --abbrev-ref HEAD`.strip
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def working_dir
|
15
|
+
KnapsackPro::Config::Env.project_dir
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|