knapsack_pro 5.1.1 → 5.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 58063b1846ea84151755a05ad9f4cca8297246b78ff0c47d140576cb0d32e19c
4
- data.tar.gz: bf36f5e4232ae62eb835dea8f6aeb0d767f5bef88e7aabf7fea2508c8017068a
3
+ metadata.gz: f00531028caf0501edea4bf33df1bd81fe7ec9fbc888875797289f488e51851e
4
+ data.tar.gz: dbe2e29cdb257ef772348653e40bcccc0ae4d70e8fc0fdd72fd26193784a60b7
5
5
  SHA512:
6
- metadata.gz: 756a63cd54c3e35e60cd09ba057c026d5ab279dab5bdd295bccfb49c6f235f68835e956171a19d9a8c5ca21db46de204e22867c879dae331fe482ffefe906189
7
- data.tar.gz: 54e7d11084f8eab1ace9e225f0a1455dd9b391f33742cafa475b2ce144024f8509d7afcb0915f663784f0ead5407b7accee33d90acb19c44a6ab845c8507e0b5
6
+ metadata.gz: 8ac1af3bf5eff25233ddb17294c56d9de6c9ec0d94c6412182a69ce2f4c04082eb705b0f204e42a342486c2001862171503d6726012421b336fe25c851e103c8
7
+ data.tar.gz: 52d4b68c5793defaf162659597d63afa7461964c78e6b78385ffe21af5cdf529124a15c9d5d96f2ca7216e175daa8b9aa6d2b04698e23c59b2a71b6603b13318
@@ -0,0 +1,11 @@
1
+ # To get started with Dependabot version updates, you'll need to specify which
2
+ # package ecosystems to update and where the package manifests are located.
3
+ # Please see the documentation for all configuration options:
4
+ # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5
+
6
+ version: 2
7
+ updates:
8
+ - package-ecosystem: "bundler"
9
+ directory: "/"
10
+ schedule:
11
+ interval: "weekly"
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ### 5.2.0
4
+
5
+ * Send authors to the API
6
+
7
+ https://github.com/KnapsackPro/knapsack_pro-ruby/pull/208
8
+
9
+ https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v5.1.2...v5.2.0
10
+
11
+ ### 5.1.2
12
+
13
+ * Fix broken RSpec split by test examples feature when `SPEC_OPTS` is set in Queue Mode. Ignore `SPEC_OPTS` when generating test examples report for slow test files.
14
+
15
+ https://github.com/KnapsackPro/knapsack_pro-ruby/pull/191
16
+
17
+ https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v5.1.1...v5.1.2
18
+
3
19
  ### 5.1.1
4
20
 
5
21
  * Use `KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true` as default value in Queue Mode for GitLab CI
@@ -16,6 +16,8 @@ module KnapsackPro
16
16
  :node_index => args.fetch(:node_index),
17
17
  :ci_build_id => KnapsackPro::Config::Env.ci_node_build_id,
18
18
  :user_seat => KnapsackPro::Config::Env.masked_user_seat,
19
+ :build_author => KnapsackPro::RepositoryAdapters::GitAdapter.new.build_author,
20
+ :commit_authors => KnapsackPro::RepositoryAdapters::GitAdapter.new.commit_authors,
19
21
  }
20
22
 
21
23
  unless request_hash[:cache_read_attempt]
@@ -17,6 +17,8 @@ module KnapsackPro
17
17
  :node_index => args.fetch(:node_index),
18
18
  :node_build_id => KnapsackPro::Config::Env.ci_node_build_id,
19
19
  :user_seat => KnapsackPro::Config::Env.masked_user_seat,
20
+ :build_author => KnapsackPro::RepositoryAdapters::GitAdapter.new.build_author,
21
+ :commit_authors => KnapsackPro::RepositoryAdapters::GitAdapter.new.commit_authors,
20
22
  }
21
23
 
22
24
  if request_hash[:can_initialize_queue] && !request_hash[:attempt_connect_to_queue]
@@ -67,7 +67,7 @@ module KnapsackPro
67
67
  def masked_user_seat
68
68
  return unless user_seat
69
69
 
70
- user_seat.gsub(/(?<=\w{2})[a-zA-Z]/, "*")
70
+ KnapsackPro::MaskString.call(user_seat)
71
71
  end
72
72
 
73
73
  def test_file_pattern
@@ -0,0 +1,7 @@
1
+ module KnapsackPro
2
+ class MaskString
3
+ def self.call(string)
4
+ string.gsub(/(?<=\w{2})[a-zA-Z]/, "*")
5
+ end
6
+ end
7
+ end
@@ -14,8 +14,40 @@ module KnapsackPro
14
14
  str_branches.split("\n")
15
15
  end
16
16
 
17
+ def commit_authors
18
+ authors = git_commit_authors
19
+ .split("\n")
20
+ .map { |line| line.strip }
21
+ .map { |line| line.split("\t") }
22
+ .map do |commits, author|
23
+ { commits: commits.to_i, author: KnapsackPro::MaskString.call(author) }
24
+ end
25
+
26
+ raise if authors.empty?
27
+
28
+ authors
29
+ rescue Exception
30
+ []
31
+ end
32
+
33
+ def build_author
34
+ author = KnapsackPro::MaskString.call(git_build_author.strip)
35
+ raise if author.empty?
36
+ author
37
+ rescue Exception
38
+ "no git <no.git@example.com>"
39
+ end
40
+
17
41
  private
18
42
 
43
+ def git_commit_authors
44
+ `git fetch --shallow-since "1 month ago" >/dev/null 2>&1 && git shortlog --summary --email --since "one month ago"`
45
+ end
46
+
47
+ def git_build_author
48
+ `git log --format="%aN <%aE>" -1`
49
+ end
50
+
19
51
  def working_dir
20
52
  dir = KnapsackPro::Config::Env.project_dir
21
53
  File.expand_path(dir)
@@ -87,6 +87,7 @@ module KnapsackPro
87
87
  all_test_file_paths += test_file_paths
88
88
  cli_args = args + test_file_paths
89
89
 
90
+ ensure_spec_opts_have_rspec_queue_summary_formatter
90
91
  options = ::RSpec::Core::ConfigurationOptions.new(cli_args)
91
92
  rspec_runner = ::RSpec::Core::Runner.new(options)
92
93
 
@@ -113,6 +114,15 @@ module KnapsackPro
113
114
  end
114
115
  end
115
116
 
117
+ def self.ensure_spec_opts_have_rspec_queue_summary_formatter
118
+ spec_opts = ENV['SPEC_OPTS']
119
+
120
+ return unless spec_opts
121
+ return if spec_opts.include?(KnapsackPro::Formatters::RSpecQueueSummaryFormatter.to_s)
122
+
123
+ ENV['SPEC_OPTS'] = "#{spec_opts} --format #{KnapsackPro::Formatters::RSpecQueueSummaryFormatter.to_s}"
124
+ end
125
+
116
126
  private
117
127
 
118
128
  def self.adapter_class
@@ -1,3 +1,3 @@
1
1
  module KnapsackPro
2
- VERSION = '5.1.1'
2
+ VERSION = '5.2.0'
3
3
  end
data/lib/knapsack_pro.rb CHANGED
@@ -55,6 +55,7 @@ require_relative 'knapsack_pro/adapters/test_unit_adapter'
55
55
  require_relative 'knapsack_pro/adapters/spinach_adapter'
56
56
  require_relative 'knapsack_pro/allocator'
57
57
  require_relative 'knapsack_pro/queue_allocator'
58
+ require_relative 'knapsack_pro/mask_string'
58
59
  require_relative 'knapsack_pro/test_case_mergers/base_merger'
59
60
  require_relative 'knapsack_pro/test_case_mergers/rspec_merger'
60
61
  require_relative 'knapsack_pro/build_distribution_fetcher'
data/lib/tasks/rspec.rake CHANGED
@@ -7,6 +7,9 @@ namespace :knapsack_pro do
7
7
 
8
8
  desc "Generate JSON report for test suite based on default test pattern or based on defined pattern with ENV vars"
9
9
  task :rspec_test_example_detector do
10
+ # ignore the `SPEC_OPTS` options to not affect RSpec execution within this rake task
11
+ ENV.delete('SPEC_OPTS')
12
+
10
13
  detector = KnapsackPro::TestCaseDetectors::RSpecTestExampleDetector.new
11
14
  detector.generate_json_report
12
15
  end
@@ -8,6 +8,7 @@ describe KnapsackPro::Client::API::V1::BuildDistributions do
8
8
  let(:ci_build_id) { double }
9
9
  let(:masked_user_seat) { double }
10
10
  let(:test_files) { double }
11
+ let(:cache_read_attempt) { [false, true].sample }
11
12
 
12
13
  subject do
13
14
  described_class.subset(
@@ -31,20 +32,9 @@ describe KnapsackPro::Client::API::V1::BuildDistributions do
31
32
 
32
33
  it 'does not send test_files among other params' do
33
34
  action = double
34
- expect(KnapsackPro::Client::API::Action).to receive(:new).with({
35
- endpoint_path: '/v1/build_distributions/subset',
36
- http_method: :post,
37
- request_hash: {
38
- fixed_test_suite_split: fixed_test_suite_split,
39
- cache_read_attempt: cache_read_attempt,
40
- commit_hash: commit_hash,
41
- branch: branch,
42
- node_total: node_total,
43
- node_index: node_index,
44
- ci_build_id: ci_build_id,
45
- user_seat: masked_user_seat,
46
- }
47
- }).and_return(action)
35
+ expect(KnapsackPro::Client::API::Action).to receive(:new).with(
36
+ hash_including(request_hash: hash_excluding(:test_files))
37
+ ).and_return(action)
48
38
  expect(subject).to eq action
49
39
  end
50
40
  end
@@ -54,24 +44,22 @@ describe KnapsackPro::Client::API::V1::BuildDistributions do
54
44
 
55
45
  it 'sends test_files among other params' do
56
46
  action = double
57
- expect(KnapsackPro::Client::API::Action).to receive(:new).with({
58
- endpoint_path: '/v1/build_distributions/subset',
59
- http_method: :post,
60
- request_hash: {
61
- fixed_test_suite_split: fixed_test_suite_split,
62
- cache_read_attempt: cache_read_attempt,
63
- commit_hash: commit_hash,
64
- branch: branch,
65
- node_total: node_total,
66
- node_index: node_index,
67
- ci_build_id: ci_build_id,
68
- user_seat: masked_user_seat,
69
- test_files: test_files
70
- }
71
- }).and_return(action)
47
+ expect(KnapsackPro::Client::API::Action).to receive(:new).with(
48
+ hash_including(request_hash: hash_including(test_files: test_files))
49
+ ).and_return(action)
72
50
  expect(subject).to eq action
73
51
  end
74
52
  end
53
+
54
+ it "sends authors" do
55
+ action = double
56
+
57
+ expect(KnapsackPro::Client::API::Action).to receive(:new).with(
58
+ hash_including(request_hash: hash_including(:build_author, :commit_authors))
59
+ ).and_return(action)
60
+
61
+ expect(subject).to eq action
62
+ end
75
63
  end
76
64
 
77
65
  describe '.last' do
@@ -8,6 +8,8 @@ describe KnapsackPro::Client::API::V1::Queues do
8
8
  let(:test_files) { double }
9
9
  let(:node_build_id) { double }
10
10
  let(:masked_user_seat) { double }
11
+ let(:can_initialize_queue) { [false, true].sample }
12
+ let(:attempt_connect_to_queue) { [false, true].sample }
11
13
 
12
14
  subject do
13
15
  described_class.queue(
@@ -33,21 +35,9 @@ describe KnapsackPro::Client::API::V1::Queues do
33
35
 
34
36
  it 'does not send test_files among other params' do
35
37
  action = double
36
- expect(KnapsackPro::Client::API::Action).to receive(:new).with({
37
- endpoint_path: '/v1/queues/queue',
38
- http_method: :post,
39
- request_hash: {
40
- fixed_queue_split: fixed_queue_split,
41
- can_initialize_queue: can_initialize_queue,
42
- attempt_connect_to_queue: attempt_connect_to_queue,
43
- commit_hash: commit_hash,
44
- branch: branch,
45
- node_total: node_total,
46
- node_index: node_index,
47
- node_build_id: node_build_id,
48
- user_seat: masked_user_seat,
49
- }
50
- }).and_return(action)
38
+ expect(KnapsackPro::Client::API::Action).to receive(:new).with(
39
+ hash_including(request_hash: hash_excluding(:test_files))
40
+ ).and_return(action)
51
41
  expect(subject).to eq action
52
42
  end
53
43
  end
@@ -58,22 +48,9 @@ describe KnapsackPro::Client::API::V1::Queues do
58
48
 
59
49
  it 'sends test_files among other params' do
60
50
  action = double
61
- expect(KnapsackPro::Client::API::Action).to receive(:new).with({
62
- endpoint_path: '/v1/queues/queue',
63
- http_method: :post,
64
- request_hash: {
65
- fixed_queue_split: fixed_queue_split,
66
- can_initialize_queue: can_initialize_queue,
67
- attempt_connect_to_queue: attempt_connect_to_queue,
68
- commit_hash: commit_hash,
69
- branch: branch,
70
- node_total: node_total,
71
- node_index: node_index,
72
- node_build_id: node_build_id,
73
- user_seat: masked_user_seat,
74
- test_files: test_files
75
- }
76
- }).and_return(action)
51
+ expect(KnapsackPro::Client::API::Action).to receive(:new).with(
52
+ hash_including(request_hash: hash_including(test_files: test_files))
53
+ ).and_return(action)
77
54
  expect(subject).to eq action
78
55
  end
79
56
  end
@@ -84,23 +61,21 @@ describe KnapsackPro::Client::API::V1::Queues do
84
61
 
85
62
  it 'does not send test_files among other params' do
86
63
  action = double
87
- expect(KnapsackPro::Client::API::Action).to receive(:new).with({
88
- endpoint_path: '/v1/queues/queue',
89
- http_method: :post,
90
- request_hash: {
91
- fixed_queue_split: fixed_queue_split,
92
- can_initialize_queue: can_initialize_queue,
93
- attempt_connect_to_queue: attempt_connect_to_queue,
94
- commit_hash: commit_hash,
95
- branch: branch,
96
- node_total: node_total,
97
- node_index: node_index,
98
- node_build_id: node_build_id,
99
- user_seat: masked_user_seat,
100
- }
101
- }).and_return(action)
64
+ expect(KnapsackPro::Client::API::Action).to receive(:new).with(
65
+ hash_including(request_hash: hash_excluding(:test_files))
66
+ ).and_return(action)
102
67
  expect(subject).to eq action
103
68
  end
104
69
  end
70
+
71
+ it "sends authors" do
72
+ action = double
73
+
74
+ expect(KnapsackPro::Client::API::Action).to receive(:new).with(
75
+ hash_including(request_hash: hash_including(:build_author, :commit_authors))
76
+ ).and_return(action)
77
+
78
+ expect(subject).to eq action
79
+ end
105
80
  end
106
81
  end
@@ -31,4 +31,76 @@ describe KnapsackPro::RepositoryAdapters::GitAdapter do
31
31
  it { expect(subject.include?('master')).to be true }
32
32
  it { expect(subject.include?(circle_branch)).to be true } if ENV['CIRCLECI']
33
33
  end
34
+
35
+ describe '#build_author' do
36
+ it "returns the masked build author" do
37
+ allow_any_instance_of(KnapsackPro::RepositoryAdapters::GitAdapter).to receive(:git_build_author).and_return(
38
+ "John Doe <john.doe@example.com>" + "\n"
39
+ )
40
+
41
+ subject = KnapsackPro::RepositoryAdapters::GitAdapter.new
42
+
43
+ expect(subject.build_author).to eq 'Jo** Do* <jo**.do*@ex*****.co*>'
44
+ end
45
+
46
+ context "when the command raises an exception" do
47
+ it "returns the no-git author" do
48
+ allow_any_instance_of(KnapsackPro::RepositoryAdapters::GitAdapter).to receive(:git_build_author).and_raise(Exception)
49
+
50
+ subject = KnapsackPro::RepositoryAdapters::GitAdapter.new
51
+
52
+ expect(subject.build_author).to eq "no git <no.git@example.com>"
53
+ end
54
+ end
55
+
56
+ context "when the command returns an empty string" do
57
+ it "returns the no-git author" do
58
+ allow_any_instance_of(KnapsackPro::RepositoryAdapters::GitAdapter).to receive(:git_build_author).and_return("")
59
+
60
+ subject = KnapsackPro::RepositoryAdapters::GitAdapter.new
61
+
62
+ expect(subject.build_author).to eq "no git <no.git@example.com>"
63
+ end
64
+ end
65
+ end
66
+
67
+ describe '#commit_authors' do
68
+ it "returns the masked commit authors" do
69
+ allow_any_instance_of(KnapsackPro::RepositoryAdapters::GitAdapter).to receive(:git_commit_authors).and_return([
70
+ " 5\t3v0k4 <riccardo@example.com>\n",
71
+ " 10\tArtur Nowak <artur@example.com>\n",
72
+ " 2\tRiccardo <riccardo@example.com>\n",
73
+ " 3 \tshadre <shadi@example.com>\n",
74
+ ].join(""))
75
+
76
+ subject = KnapsackPro::RepositoryAdapters::GitAdapter.new
77
+
78
+ expect(subject.commit_authors).to eq([
79
+ { commits: 5, author: "3v0*4 <ri******@ex*****.co*>" },
80
+ { commits: 10, author: "Ar*** No*** <ar***@ex*****.co*>" },
81
+ { commits: 2, author: "Ri****** <ri******@ex*****.co*>" },
82
+ { commits: 3, author: "sh**** <sh***@ex*****.co*>" },
83
+ ])
84
+ end
85
+
86
+ context "when the authors command raises an exception" do
87
+ it "returns []" do
88
+ allow_any_instance_of(KnapsackPro::RepositoryAdapters::GitAdapter).to receive(:git_commit_authors).and_raise(Exception)
89
+
90
+ subject = KnapsackPro::RepositoryAdapters::GitAdapter.new
91
+
92
+ expect(subject.commit_authors).to eq []
93
+ end
94
+ end
95
+
96
+ context "when the authors command returns an empty string" do
97
+ it "returns []" do
98
+ allow_any_instance_of(KnapsackPro::RepositoryAdapters::GitAdapter).to receive(:git_commit_authors).and_return("")
99
+
100
+ subject = KnapsackPro::RepositoryAdapters::GitAdapter.new
101
+
102
+ expect(subject.commit_authors).to eq []
103
+ end
104
+ end
105
+ end
34
106
  end
@@ -212,6 +212,7 @@ describe KnapsackPro::Runners::Queue::RSpecRunner do
212
212
  expect(tracker).to receive(:reset!)
213
213
  expect(tracker).to receive(:set_prerun_tests).with(test_file_paths)
214
214
 
215
+ expect(described_class).to receive(:ensure_spec_opts_have_rspec_queue_summary_formatter)
215
216
  options = double
216
217
  expect(RSpec::Core::ConfigurationOptions).to receive(:new).with([
217
218
  '--no-color',
@@ -339,4 +340,39 @@ describe KnapsackPro::Runners::Queue::RSpecRunner do
339
340
  end
340
341
  end
341
342
  end
343
+
344
+ describe '.ensure_spec_opts_have_rspec_queue_summary_formatter' do
345
+ subject { described_class.ensure_spec_opts_have_rspec_queue_summary_formatter }
346
+
347
+ context 'when `SPEC_OPTS` is set' do
348
+ context 'when `SPEC_OPTS` has RSpec Queue Summary Formatter' do
349
+ before do
350
+ stub_const('ENV', { 'SPEC_OPTS' => '--format json --format KnapsackPro::Formatters::RSpecQueueSummaryFormatter' })
351
+ end
352
+
353
+ it 'does nothing' do
354
+ subject
355
+ expect(ENV['SPEC_OPTS']).to eq '--format json --format KnapsackPro::Formatters::RSpecQueueSummaryFormatter'
356
+ end
357
+ end
358
+
359
+ context 'when `SPEC_OPTS` has no RSpec Queue Summary Formatter' do
360
+ before do
361
+ stub_const('ENV', { 'SPEC_OPTS' => '--format json' })
362
+ end
363
+
364
+ it 'adds RSpec Queue Summary Formatter to `SPEC_OPTS`' do
365
+ subject
366
+ expect(ENV['SPEC_OPTS']).to eq '--format json --format KnapsackPro::Formatters::RSpecQueueSummaryFormatter'
367
+ end
368
+ end
369
+ end
370
+
371
+ context 'when `SPEC_OPTS` is not set' do
372
+ it 'does nothing' do
373
+ subject
374
+ expect(ENV['SPEC_OPTS']).to be_nil
375
+ end
376
+ end
377
+ end
342
378
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knapsack_pro
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.1
4
+ version: 5.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ArturT
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-19 00:00:00.000000000 Z
11
+ date: 2023-07-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -192,6 +192,7 @@ files:
192
192
  - ".circleci/config.yml"
193
193
  - ".github/assets/install-button.png"
194
194
  - ".github/assets/knapsack-diamonds.png"
195
+ - ".github/dependabot.yml"
195
196
  - ".gitignore"
196
197
  - ".rspec"
197
198
  - CHANGELOG.md
@@ -244,6 +245,7 @@ files:
244
245
  - lib/knapsack_pro/formatters/rspec_queue_summary_formatter.rb
245
246
  - lib/knapsack_pro/hooks/queue.rb
246
247
  - lib/knapsack_pro/logger_wrapper.rb
248
+ - lib/knapsack_pro/mask_string.rb
247
249
  - lib/knapsack_pro/presenter.rb
248
250
  - lib/knapsack_pro/queue_allocator.rb
249
251
  - lib/knapsack_pro/queue_allocator_builder.rb