knapsack_pro 8.1.3 → 8.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 +4 -4
- data/.circleci/config.yml +0 -2
- data/CHANGELOG.md +10 -0
- data/README.md +36 -0
- data/distroless/Dockerfile +37 -0
- data/lib/knapsack_pro/adapters/rspec_adapter.rb +5 -5
- data/lib/knapsack_pro/repository_adapters/git_adapter.rb +21 -6
- data/lib/knapsack_pro/runners/spinach_runner.rb +5 -3
- data/lib/knapsack_pro/version.rb +1 -1
- data/lib/tasks/queue/cucumber.rake +1 -1
- data/lib/tasks/queue/minitest.rake +1 -1
- data/lib/tasks/queue/rspec.rake +1 -1
- data/spec/knapsack_pro/adapters/rspec_adapter_spec.rb +30 -11
- data/spec/knapsack_pro/runners/spinach_runner_spec.rb +7 -30
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d8372acfe13485ea86eeb30fdd524624cfbe05a374e4c6671048f898ecb5e94
|
4
|
+
data.tar.gz: 56df068506c0271ee9b55e92a7659dd1176bbfd7eef716f17f5ac9e67cd003cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac7bff173d40c9c83aa0d1a1053890d216e4939970af363415a5462264bd7c07fd95afe5e61c00930669f3f1b6ccee678762763bb6b5066b2923db7307afc48c
|
7
|
+
data.tar.gz: 27488c936d5cea663853d319a4564476568abe774ecaa91a2eb7f83e168ac4c1221091fb6969ac4b44d383673a30c4b141591051ba81987f95af75fb066c95bb
|
data/.circleci/config.yml
CHANGED
@@ -357,7 +357,6 @@ jobs:
|
|
357
357
|
KNAPSACK_PRO_ENDPOINT: https://api-staging.knapsackpro.com
|
358
358
|
KNAPSACK_PRO_TEST_SUITE_TOKEN_MINITEST: $KNAPSACK_PRO_TEST_SUITE_TOKEN_MINITEST
|
359
359
|
KNAPSACK_PRO_RSPEC_DISABLED: true
|
360
|
-
EXTRA_TEST_FILES_DELAY: 10
|
361
360
|
- image: cimg/postgres:14.7
|
362
361
|
environment:
|
363
362
|
POSTGRES_DB: rails-app-with-knapsack_pro_test
|
@@ -404,7 +403,6 @@ jobs:
|
|
404
403
|
KNAPSACK_PRO_ENDPOINT: https://api-staging.knapsackpro.com
|
405
404
|
KNAPSACK_PRO_TEST_SUITE_TOKEN_MINITEST: $KNAPSACK_PRO_TEST_SUITE_TOKEN_MINITEST
|
406
405
|
KNAPSACK_PRO_RSPEC_DISABLED: true
|
407
|
-
EXTRA_TEST_FILES_DELAY: 10
|
408
406
|
- image: cimg/postgres:14.7
|
409
407
|
environment:
|
410
408
|
POSTGRES_DB: rails-app-with-knapsack_pro_test
|
data/CHANGELOG.md
CHANGED
@@ -2,10 +2,20 @@
|
|
2
2
|
|
3
3
|
### UNRELEASED
|
4
4
|
|
5
|
+
### 8.2.0
|
6
|
+
|
7
|
+
* Avoid needing a shell to support Distroless Container Images (in most cases)
|
8
|
+
|
9
|
+
https://github.com/KnapsackPro/knapsack_pro-ruby/pull/299
|
10
|
+
|
11
|
+
https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v8.1.3...v8.2.0
|
12
|
+
|
5
13
|
### 8.1.3
|
6
14
|
|
7
15
|
* Update `changelog_uri` in gemspec
|
8
16
|
|
17
|
+
https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v8.1.2...v8.1.3
|
18
|
+
|
9
19
|
### 8.1.2
|
10
20
|
|
11
21
|
* Allow running RSpec with `--force-color` (and the default Split by Test Examples)
|
data/README.md
CHANGED
@@ -72,6 +72,42 @@ bin/test
|
|
72
72
|
|
73
73
|
Scripted tests can be found in the [Rails App With Knapsack Pro repository](https://github.com/KnapsackPro/rails-app-with-knapsack_pro/blob/master/bin/knapsack_pro_all.rb).
|
74
74
|
|
75
|
+
### Distroless Container Images
|
76
|
+
|
77
|
+
Ensure that Knapsack Pro is written in a way that supports Distroless Container Images. Avoid using a shell when calling methods like [`Kernel.system`](https://rubyapi.org/3.4/o/kernel#method-i-system) or [`Kernel.exec`](https://rubyapi.org/3.4/o/kernel#method-i-exec).
|
78
|
+
|
79
|
+
✅ Good - shell is not required
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
cmd = 'bundle exec rake knapsack_pro:something'
|
83
|
+
Kernel.system({ 'RAILS_ENV' => 'test' }, cmd)
|
84
|
+
|
85
|
+
cmd = ['bundle', 'exec', 'rake', 'knapsack_pro:example']
|
86
|
+
Kernel.system({ 'RAILS_ENV' => 'test' }, *cmd)
|
87
|
+
```
|
88
|
+
|
89
|
+
⛔️ Bad - shell is required
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
# Avoid embedding environment variables in the command string
|
93
|
+
cmd = 'RAILS_ENV=test bundle exec rake knapsack_pro:something'
|
94
|
+
Kernel.system(cmd)
|
95
|
+
|
96
|
+
# Avoid output redirection
|
97
|
+
cmd = 'program 2>/dev/null'
|
98
|
+
Kernel.system(cmd)
|
99
|
+
|
100
|
+
# Avoid using the pipe operator
|
101
|
+
cmd = 'program1 | program2'
|
102
|
+
Kernel.system(cmd)
|
103
|
+
```
|
104
|
+
|
105
|
+
Use [Dockerfile](distroless/Dockerfile) to test if the code requires a shell:
|
106
|
+
|
107
|
+
```bash
|
108
|
+
docker build -t test -f distroless/Dockerfile . && docker run --rm -it test
|
109
|
+
```
|
110
|
+
|
75
111
|
### Publishing
|
76
112
|
|
77
113
|
1. Move the changes listed in the `UNRELEASED` section of the `CHANGELOG.md` to the proper version
|
@@ -0,0 +1,37 @@
|
|
1
|
+
FROM cgr.dev/chainguard/ruby:latest-dev AS builder
|
2
|
+
|
3
|
+
WORKDIR /build
|
4
|
+
RUN <<RUN
|
5
|
+
cat <<GEMFILE > Gemfile
|
6
|
+
source "https://rubygems.org"
|
7
|
+
GEMFILE
|
8
|
+
|
9
|
+
gem install bundler
|
10
|
+
bundle config set --local path vendor/bundle
|
11
|
+
bundle install
|
12
|
+
RUN
|
13
|
+
|
14
|
+
RUN <<RUN
|
15
|
+
cat <<RAKEFILE > Rakefile
|
16
|
+
RAKEFILE
|
17
|
+
|
18
|
+
mkdir bin
|
19
|
+
cat <<CI > bin/ci
|
20
|
+
ENV['PATH'] =+ "#{Gem.user_dir}/bin"
|
21
|
+
require 'bundler/setup'
|
22
|
+
|
23
|
+
success = Kernel.system({ 'RAILS_ENV' => 'test' }, 'bundle --version') # ✅
|
24
|
+
raise "The command failed!" unless success
|
25
|
+
|
26
|
+
success = Kernel.system({ 'RAILS_ENV' => 'test' }, 'bundle --version 2>/dev/null') # ⛔️
|
27
|
+
raise "The command failed!" unless success
|
28
|
+
|
29
|
+
CI
|
30
|
+
RUN
|
31
|
+
|
32
|
+
FROM cgr.dev/chainguard/ruby:latest
|
33
|
+
|
34
|
+
WORKDIR /app
|
35
|
+
COPY --from=builder /home/nonroot/.local /home/nonroot/.local
|
36
|
+
COPY --from=builder /build /app
|
37
|
+
CMD ["bin/ci"]
|
@@ -24,14 +24,14 @@ module KnapsackPro
|
|
24
24
|
KnapsackPro.logger.info("Generating RSpec test examples JSON report for slow test files to prepare it to be split by test examples (by individual test cases). Thanks to that, a single slow test file can be split across parallel CI nodes. Analyzing #{slow_test_files.size} slow test files.")
|
25
25
|
|
26
26
|
# generate the RSpec JSON report in a separate process to not pollute the RSpec state
|
27
|
+
envs = {'RACK_ENV' => 'test', 'RAILS_ENV' => 'test'}
|
27
28
|
cmd = [
|
28
|
-
'RACK_ENV=test',
|
29
|
-
'RAILS_ENV=test',
|
30
29
|
KnapsackPro::Config::Env.rspec_test_example_detector_prefix,
|
31
|
-
'rake knapsack_pro:rspec_test_example_detector'
|
30
|
+
'rake knapsack_pro:rspec_test_example_detector'
|
32
31
|
].join(' ')
|
33
|
-
unless Kernel.system(cmd)
|
34
|
-
|
32
|
+
unless Kernel.system(envs, cmd)
|
33
|
+
inline_cmd = envs.map { _1.join('=') }.join(' ') + ' ' + cmd
|
34
|
+
raise "Could not generate JSON report for RSpec. Rake task failed when running #{inline_cmd}"
|
35
35
|
end
|
36
36
|
|
37
37
|
# read the JSON report
|
@@ -44,26 +44,41 @@ module KnapsackPro
|
|
44
44
|
|
45
45
|
def git_commit_authors
|
46
46
|
if KnapsackPro::Config::Env.ci? && shallow_repository?
|
47
|
-
command = 'git fetch --shallow-since "one month ago" --quiet
|
47
|
+
command = 'git fetch --shallow-since "one month ago" --quiet'
|
48
48
|
begin
|
49
49
|
Timeout.timeout(5) do
|
50
|
-
|
50
|
+
Kernel.system(command, out: File::NULL, err: File::NULL)
|
51
51
|
end
|
52
52
|
rescue Timeout::Error
|
53
53
|
KnapsackPro.logger.debug("Skip the `#{command}` command because it took too long.")
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
-
|
57
|
+
IO.pipe do |log_r, log_w|
|
58
|
+
Kernel.system('git log --since "one month ago"', out: log_w, err: File::NULL)
|
59
|
+
log_w.close
|
60
|
+
IO.pipe do |shortlog_r, shortlog_w|
|
61
|
+
Kernel.system('git shortlog --summary --email', in: log_r, out: shortlog_w, err: File::NULL)
|
62
|
+
shortlog_w.close
|
63
|
+
shortlog_r.read
|
64
|
+
end
|
65
|
+
end
|
58
66
|
end
|
59
67
|
|
60
68
|
def git_build_author
|
61
|
-
|
69
|
+
IO.pipe do |r, w|
|
70
|
+
Kernel.system('git log --format="%aN <%aE>" -1', out: w, err: File::NULL)
|
71
|
+
w.close
|
72
|
+
r.read
|
73
|
+
end
|
62
74
|
end
|
63
75
|
|
64
76
|
def shallow_repository?
|
65
|
-
|
66
|
-
|
77
|
+
IO.pipe do |r, w|
|
78
|
+
Kernel.system('git rev-parse --is-shallow-repository', out: w, err: File::NULL)
|
79
|
+
w.close
|
80
|
+
r.read.strip == 'true'
|
81
|
+
end
|
67
82
|
end
|
68
83
|
|
69
84
|
def working_dir
|
@@ -15,10 +15,12 @@ module KnapsackPro
|
|
15
15
|
|
16
16
|
KnapsackPro.tracker.set_prerun_tests(runner.test_file_paths)
|
17
17
|
|
18
|
-
cmd = %Q[
|
18
|
+
cmd = %Q[bundle exec spinach #{args} --features_path #{runner.test_dir} -- #{runner.stringify_test_file_paths}]
|
19
19
|
|
20
|
-
Kernel.
|
21
|
-
|
20
|
+
Kernel.exec({
|
21
|
+
'KNAPSACK_PRO_REGULAR_MODE_ENABLED' => 'true',
|
22
|
+
'KNAPSACK_PRO_TEST_SUITE_TOKEN' => ENV['KNAPSACK_PRO_TEST_SUITE_TOKEN']
|
23
|
+
}, cmd)
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
data/lib/knapsack_pro/version.rb
CHANGED
@@ -5,7 +5,7 @@ require 'knapsack_pro'
|
|
5
5
|
namespace :knapsack_pro do
|
6
6
|
namespace :queue do
|
7
7
|
task :cucumber, [:cucumber_args] do |_, args|
|
8
|
-
Kernel.exec(
|
8
|
+
Kernel.exec({ 'RAILS_ENV' => 'test', 'RACK_ENV' => 'test' }, $PROGRAM_NAME, "knapsack_pro:queue:cucumber_go[#{args[:cucumber_args]}]")
|
9
9
|
end
|
10
10
|
|
11
11
|
task :cucumber_go, [:cucumber_args] do |_, args|
|
@@ -5,7 +5,7 @@ require 'knapsack_pro'
|
|
5
5
|
namespace :knapsack_pro do
|
6
6
|
namespace :queue do
|
7
7
|
task :minitest, [:minitest_args] do |_, args|
|
8
|
-
Kernel.exec(
|
8
|
+
Kernel.exec({ 'RAILS_ENV' => 'test', 'RACK_ENV' => 'test' }, $PROGRAM_NAME, "knapsack_pro:queue:minitest_go[#{args[:minitest_args]}]")
|
9
9
|
end
|
10
10
|
|
11
11
|
task :minitest_go, [:minitest_args] do |_, args|
|
data/lib/tasks/queue/rspec.rake
CHANGED
@@ -5,7 +5,7 @@ require 'knapsack_pro'
|
|
5
5
|
namespace :knapsack_pro do
|
6
6
|
namespace :queue do
|
7
7
|
task :rspec, [:rspec_args] do |_, args|
|
8
|
-
Kernel.exec(
|
8
|
+
Kernel.exec({ 'RAILS_ENV' => 'test', 'RACK_ENV' => 'test' }, $PROGRAM_NAME, "knapsack_pro:queue:rspec_go[#{args[:rspec_args]}]")
|
9
9
|
end
|
10
10
|
|
11
11
|
task :rspec_go, [:rspec_args] do |_, args|
|
@@ -57,19 +57,36 @@ describe KnapsackPro::Adapters::RSpecAdapter do
|
|
57
57
|
|
58
58
|
subject { described_class.test_file_cases_for(slow_test_files) }
|
59
59
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
60
|
+
context 'when the rake task to detect RSpec test examples succeeded' do
|
61
|
+
it 'returns test example paths for slow test files' do
|
62
|
+
logger = instance_double(Logger)
|
63
|
+
allow(KnapsackPro).to receive(:logger).and_return(logger)
|
64
|
+
allow(logger).to receive(:info)
|
65
|
+
|
66
|
+
cmd = 'bundle exec rake knapsack_pro:rspec_test_example_detector'
|
67
|
+
env = { 'RACK_ENV' => 'test', 'RAILS_ENV' => 'test' }
|
68
|
+
expect(Kernel).to receive(:system).with(env, cmd).and_return(true)
|
69
|
+
|
70
|
+
rspec_test_example_detector = instance_double(KnapsackPro::TestCaseDetectors::RSpecTestExampleDetector)
|
71
|
+
expect(KnapsackPro::TestCaseDetectors::RSpecTestExampleDetector).to receive(:new).and_return(rspec_test_example_detector)
|
72
|
+
|
73
|
+
test_file_example_paths = double
|
74
|
+
expect(rspec_test_example_detector).to receive(:test_file_example_paths).and_return(test_file_example_paths)
|
75
|
+
|
76
|
+
expect(subject).to eq test_file_example_paths
|
64
77
|
|
65
|
-
|
66
|
-
|
78
|
+
expect(logger).to have_received(:info).with("Generating RSpec test examples JSON report for slow test files to prepare it to be split by test examples (by individual test cases). Thanks to that, a single slow test file can be split across parallel CI nodes. Analyzing 5 slow test files.")
|
79
|
+
end
|
67
80
|
end
|
68
81
|
|
69
|
-
context 'when
|
70
|
-
|
82
|
+
context 'when KNAPSACK_PRO_RSPEC_TEST_EXAMPLE_DETECTOR_PREFIX is set with a custom environment variable' do
|
83
|
+
it 'calls Kernel.system using a single command including ENVs that is passed to a shell (does not work in a distroless environment)' do
|
84
|
+
stub_const('ENV', { 'KNAPSACK_PRO_RSPEC_TEST_EXAMPLE_DETECTOR_PREFIX' => 'CUSTOM_ENV_VAR=123 bundle exec' })
|
85
|
+
|
86
|
+
cmd = 'CUSTOM_ENV_VAR=123 bundle exec rake knapsack_pro:rspec_test_example_detector'
|
87
|
+
env = { 'RACK_ENV' => 'test', 'RAILS_ENV' => 'test' }
|
88
|
+
expect(Kernel).to receive(:system).with(env, cmd).and_return(true)
|
71
89
|
|
72
|
-
it 'returns test example paths for slow test files' do
|
73
90
|
rspec_test_example_detector = instance_double(KnapsackPro::TestCaseDetectors::RSpecTestExampleDetector)
|
74
91
|
expect(KnapsackPro::TestCaseDetectors::RSpecTestExampleDetector).to receive(:new).and_return(rspec_test_example_detector)
|
75
92
|
|
@@ -81,9 +98,11 @@ describe KnapsackPro::Adapters::RSpecAdapter do
|
|
81
98
|
end
|
82
99
|
|
83
100
|
context 'when the rake task to detect RSpec test examples failed' do
|
84
|
-
let(:cmd_result) { false }
|
85
|
-
|
86
101
|
it do
|
102
|
+
cmd = 'bundle exec rake knapsack_pro:rspec_test_example_detector'
|
103
|
+
env = { 'RACK_ENV' => 'test', 'RAILS_ENV' => 'test' }
|
104
|
+
expect(Kernel).to receive(:system).with(env, cmd).and_return(false)
|
105
|
+
|
87
106
|
expect { subject }.to raise_error(RuntimeError, 'Could not generate JSON report for RSpec. Rake task failed when running RACK_ENV=test RAILS_ENV=test bundle exec rake knapsack_pro:rspec_test_example_detector')
|
88
107
|
end
|
89
108
|
end
|
@@ -19,8 +19,8 @@ describe KnapsackPro::Runners::SpinachRunner do
|
|
19
19
|
|
20
20
|
context 'when test files were returned by Knapsack Pro API' do
|
21
21
|
let(:test_file_paths) { ['features/a.feature', 'features/b.feature'] }
|
22
|
-
let(:stringify_test_file_paths) { test_file_paths.join(' ') }
|
23
22
|
let(:test_dir) { 'fake-test-dir' }
|
23
|
+
let(:stringify_test_file_paths) { test_file_paths.join(' ') }
|
24
24
|
let(:runner) do
|
25
25
|
instance_double(described_class,
|
26
26
|
test_dir: test_dir,
|
@@ -30,42 +30,19 @@ describe KnapsackPro::Runners::SpinachRunner do
|
|
30
30
|
end
|
31
31
|
let(:child_status) { double }
|
32
32
|
|
33
|
-
|
33
|
+
it do
|
34
34
|
expect(KnapsackPro::Adapters::SpinachAdapter).to receive(:verify_bind_method_called)
|
35
35
|
|
36
36
|
tracker = instance_double(KnapsackPro::Tracker)
|
37
37
|
expect(KnapsackPro).to receive(:tracker).and_return(tracker)
|
38
38
|
expect(tracker).to receive(:set_prerun_tests).with(test_file_paths)
|
39
39
|
|
40
|
-
expect(Kernel).to receive(:
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
after { subject }
|
46
|
-
|
47
|
-
context 'when command exit with success code' do
|
48
|
-
let(:exitstatus) { 0 }
|
40
|
+
expect(Kernel).to receive(:exec).with(
|
41
|
+
{ 'KNAPSACK_PRO_REGULAR_MODE_ENABLED' => 'true', 'KNAPSACK_PRO_TEST_SUITE_TOKEN' => 'spinach-token' },
|
42
|
+
'bundle exec spinach --custom-arg --features_path fake-test-dir -- features/a.feature features/b.feature'
|
43
|
+
)
|
49
44
|
|
50
|
-
|
51
|
-
expect(child_status).to receive(:exitstatus).and_return(exitstatus)
|
52
|
-
end
|
53
|
-
|
54
|
-
it do
|
55
|
-
expect(Kernel).not_to receive(:exit)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
context 'when command exit without success code' do
|
60
|
-
let(:exitstatus) { 1 }
|
61
|
-
|
62
|
-
before do
|
63
|
-
expect(child_status).to receive(:exitstatus).twice.and_return(exitstatus)
|
64
|
-
end
|
65
|
-
|
66
|
-
it do
|
67
|
-
expect(Kernel).to receive(:exit).with(exitstatus)
|
68
|
-
end
|
45
|
+
subject
|
69
46
|
end
|
70
47
|
end
|
71
48
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: knapsack_pro
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 8.
|
4
|
+
version: 8.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ArturT
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-05-
|
10
|
+
date: 2025-05-21 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: rake
|
@@ -216,6 +216,7 @@ files:
|
|
216
216
|
- Rakefile
|
217
217
|
- bin/knapsack_pro
|
218
218
|
- bin/test
|
219
|
+
- distroless/Dockerfile
|
219
220
|
- knapsack_pro.gemspec
|
220
221
|
- lib/knapsack_pro.rb
|
221
222
|
- lib/knapsack_pro/adapters/base_adapter.rb
|