-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use .knapsack_pro
directory for temporary files instead of the tmp
directory in the user's project directory
#155
Conversation
… way error will be more explicit when the report is missing.
.knapsack_pro
directory for temporary files instead of the tmp
folder in the user project folder
…ting might be a very narrow tests list. Most likely, you run only tests with a specified tag, and the number of test files with the tag was lower than the number of parallel CI nodes.
rspec --seed 62479
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding some questions and comments
CHANGELOG.md
Outdated
@@ -1,5 +1,13 @@ | |||
# Change Log | |||
|
|||
### 3.1.0 | |||
|
|||
* Use `.knapsack_pro` directory for temporary files instead of the `tmp` folder in the user project folder |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should read user's project
. I would also change "folder" to "directory" (despite the duplication).
@@ -39,14 +39,14 @@ def self.verify_bind_method_called | |||
puts "\n\n" | |||
KnapsackPro.logger.error('-'*10 + ' Configuration error ' + '-'*50) | |||
KnapsackPro.logger.error("You forgot to call #{self}.bind method in your test runner configuration file. It is needed to record test files time execution. Please follow the installation guide to configure your project properly https://docs.knapsackpro.com/knapsack_pro-ruby/guide/") | |||
KnapsackPro.logger.error("If you already have #{self}.bind method added and you still see this error then one of your tests must had to delete tmp/knapsack_pro directory from the disk accidentally. Please ensure you do not remove tmp/knapsack_pro directory: https://knapsackpro.com/faq/question/why-all-test-files-have-01s-time-execution-for-my-ci-build-in-user-dashboard") | |||
KnapsackPro.logger.error("If you already have #{self}.bind method added and you still see this error then one of your tests must had to delete .knapsack_pro directory from the disk accidentally. Please ensure you do not remove .knapsack_pro directory: https://knapsackpro.com/faq/question/why-all-test-files-have-01s-time-execution-for-my-ci-build-in-user-dashboard") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pretty sure "must had to delete" is ungrammatical. How about "must have deleted"?
Also, I think we are missing "the" in "the .knapsack_pro directory" (2 occurrences)
end | ||
|
||
def ensure_temp_directory_exists | ||
unless File.exists?(gitignore_file_path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is deprecated in ruby 2.7.1, and doesn't exist in ruby 3.0.2. There is an #exist? method, but I'm not sure if they are effectively the same.
I was dealing with ensuring a directory exists in my past side-project. I looked up the code and noticed I was using the Dir
class instead. I don't remember offhand why I chose it over File
- you probably know the difference better. With Dir
you can also create the directory.
In case it's helpful to you, here is how I handled a similar case back then:
create_needed_dirs!
def create_needed_dirs!
create!('foo')
create!('bar')
end
def create!(directory)
return false if Dir.exist?(directory)
Dir.mkdir(directory) && true
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. I've used File.exist?
in the whole codebase.
temp_files.temp_directory_path | ||
end | ||
|
||
def ensure_temp_directory_exists |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to keep this method and the #temp_directory_path
a part of the public interface of this class? From a quick glance, it seems that only the class method is being called from outside? 🤔 It's also the only one that's being (directly) tested in the spec.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I move code to private
section:
private
def ensure_temp_directory_exists
unless File.exists?(gitignore_file_path)
create_temp_directory
create_gitignore_file
end
end
# relative to the directory where you run knapsack_pro gem (user's project)
def temp_directory_path
'.knapsack_pro'
end
then I get error:
$ rspec ./spec/knapsack_pro/config/temp_files_spec.rb
Randomized with seed 3043
KnapsackPro::Config::TempFiles
.temp_directory_path
.gitignore file has content (FAILED - 1)
creates .gitignore file (FAILED - 2)
returns temporary directory path (FAILED - 3)
Failures:
1) KnapsackPro::Config::TempFiles.temp_directory_path .gitignore file has content
Failure/Error: temp_files.ensure_temp_directory_exists
NoMethodError:
private method `ensure_temp_directory_exists' called for #<KnapsackPro::Config::TempFiles:0x00007f911c9ed6d0>
# ./lib/knapsack_pro/config/temp_files.rb:8:in `temp_directory_path'
# ./spec/knapsack_pro/config/temp_files_spec.rb:5:in `block (3 levels) in <top (required)>'
# ./spec/knapsack_pro/config/temp_files_spec.rb:18:in `block (3 levels) in <top (required)>'
# /Users/artur/.rvm/gems/ruby-3.0.2/gems/webmock-3.13.0/lib/webmock/rspec.rb:37:in `block (2 levels) in <top (required)>'
When I move code to protected
I get error as well:
1) KnapsackPro::Config::TempFiles.temp_directory_path creates .gitignore file
Failure/Error: temp_files.ensure_temp_directory_exists
NoMethodError:
protected method `ensure_temp_directory_exists' called for #<KnapsackPro::Config::TempFiles:0x00007fbb43a47c88>
# ./lib/knapsack_pro/config/temp_files.rb:8:in `temp_directory_path'
# ./spec/knapsack_pro/config/temp_files_spec.rb:5:in `block (3 levels) in <top (required)>'
# ./spec/knapsack_pro/config/temp_files_spec.rb:13:in `block (3 levels) in <top (required)>'
# /Users/artur/.rvm/gems/ruby-3.0.2/gems/webmock-3.13.0/lib/webmock/rspec.rb:37:in `block (2 levels) in <top (required)>'
We call the following methods in class method temp_directory_path
so they probably must be public.
temp_files.ensure_temp_directory_exists
temp_files.temp_directory_path
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is because we are trying to access the private method from outside the object.
If we are adamant about the public method remaining a class method, we could change all the other methods to be private class methods.
end | ||
|
||
def gitignore_file_content | ||
"# This directory is used by knapsack_pro gem for temporary files during tests runtime.\n" << |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that "for storing temporary files" sounds more proper.
lib/knapsack_pro/tracker.rb
Outdated
@@ -110,6 +110,7 @@ def save_prerun_tests_report(hash) | |||
end | |||
|
|||
def read_prerun_tests_report | |||
raise "Report #{prerun_tests_report_path} doest not exist on the disk. Most likely, it was removed accidentally. Please report the bug to the support team." unless File.exists?(prerun_tests_report_path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can add a link here, or at least specify that we mean the Knapsack support team?
end | ||
|
||
it 'creates .gitignore file' do | ||
expect(File.exists?(gitignore_file_path)).to be false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI there is a nice DSL for expectations like that https://relishapp.com/rspec/rspec-expectations/v/2-0/docs/matchers/expect-change
e.g. expect{Counter.increment}.to change{Counter.count}.from(0).to(1)
(just wanted to share this in case you forgot about it, the current one is cool by all means)
expect(File.exists?(gitignore_file_path)).to be true | ||
end | ||
|
||
it '.gitignore file has content' do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do I understand correctly that the most important line in the file's content is the one with the asterisk (*
)? If so, then maybe it'd be better to check the inclusion of it instead?
@@ -67,7 +67,7 @@ | |||
|
|||
context 'when json report does not exist' do | |||
it do | |||
expect { subject }.to raise_error(RuntimeError, 'Report with slow test files was not generated yet. If you have enabled split by test cases https://github.com/KnapsackPro/knapsack_pro-ruby#split-test-files-by-test-cases and you see this error it means that your tests accidentally cleaned up tmp/knapsack_pro directory. Please do not remove this directory during tests runtime!') | |||
expect { subject }.to raise_error(RuntimeError, 'Report with slow test files was not generated yet. If you have enabled split by test cases https://github.com/KnapsackPro/knapsack_pro-ruby#split-test-files-by-test-cases and you see this error it means that your tests accidentally cleaned up .knapsack_pro directory. Please do not remove this directory during tests runtime!') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestions for the error msg:
"The report with slow test files"
I would surround the url with the parens so that it doesn't disrupt the sentence.
"the .knapsack_pro directory"
module KnapsackPro | ||
module Config | ||
class TempFiles | ||
def self.temp_directory_path |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you considered separating the ensuring the temp directory exists from returning the path? Or maybe memoizing the result or sth?
Do you think there is a way to do this check once at some point, or would it always be succeptible to errors?
The reason I'm wondering about this is that it seems that we are using this .temp_directory_path
method in many places to just get the correct path, but each time we do this it would now trigger an I/O read operation. Would be great to avoid that if it's avoidable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking about it and I decided that checking if file exists on the disk is good enough. We already do some IO operations in queue mode like saving reports and it shouldn't have significant impact on performance.
If I add memorization to class method then this causes random tests failures depending on the order of tests executed because class method memorization is preserved for each call of class method.
For instance I could do:
def self.temp_directory_path
@temp_directory_path ||=
begin
temp_files = new
temp_files.ensure_temp_directory_exists
temp_files.temp_directory_path
end
end
and then when I run tests I get randomly different tests failures:
[14:47:44] artur@Artur-MBP: ~/Documents/github/knapsack-pro/knapsack_pro-ruby temporary-files-directory! ruby-3.0.2
$ rspec ./spec/knapsack_pro/config/temp_files_spec.rb
Randomized with seed 42508
KnapsackPro::Config::TempFiles
.temp_directory_path
.gitignore file has content
returns temporary directory path
creates .gitignore file (FAILED - 1)
Failures:
1) KnapsackPro::Config::TempFiles.temp_directory_path creates .gitignore file
Failure/Error: expect(File.exist?(gitignore_file_path)).to be true
expected true
got false
# ./spec/knapsack_pro/config/temp_files_spec.rb:14:in `block (3 levels) in <top (required)>'
# /Users/artur/.rvm/gems/ruby-3.0.2/gems/webmock-3.13.0/lib/webmock/rspec.rb:37:in `block (2 levels) in <top (required)>'
Finished in 0.02793 seconds (files took 0.53206 seconds to load)
3 examples, 1 failure
Failed examples:
rspec ./spec/knapsack_pro/config/temp_files_spec.rb:11 # KnapsackPro::Config::TempFiles.temp_directory_path creates .gitignore file
Randomized with seed 42508
[14:47:46] artur@Artur-MBP: ~/Documents/github/knapsack-pro/knapsack_pro-ruby temporary-files-directory! ruby-3.0.2
$ rspec ./spec/knapsack_pro/config/temp_files_spec.rb
Randomized with seed 56734
KnapsackPro::Config::TempFiles
.temp_directory_path
returns temporary directory path
.gitignore file has content (FAILED - 1)
creates .gitignore file (FAILED - 2)
Failures:
1) KnapsackPro::Config::TempFiles.temp_directory_path .gitignore file has content
Failure/Error: expect(File.read(gitignore_file_path)).to include '# This directory is used by knapsack_pro gem for storing temporary files during tests runtime'
Errno::ENOENT:
No such file or directory @ rb_sysopen - .knapsack_pro/.gitignore
# ./spec/knapsack_pro/config/temp_files_spec.rb:19:in `read'
# ./spec/knapsack_pro/config/temp_files_spec.rb:19:in `block (3 levels) in <top (required)>'
# /Users/artur/.rvm/gems/ruby-3.0.2/gems/webmock-3.13.0/lib/webmock/rspec.rb:37:in `block (2 levels) in <top (required)>'
2) KnapsackPro::Config::TempFiles.temp_directory_path creates .gitignore file
Failure/Error: expect(File.exist?(gitignore_file_path)).to be true
expected true
got false
# ./spec/knapsack_pro/config/temp_files_spec.rb:14:in `block (3 levels) in <top (required)>'
# /Users/artur/.rvm/gems/ruby-3.0.2/gems/webmock-3.13.0/lib/webmock/rspec.rb:37:in `block (2 levels) in <top (required)>'
Finished in 0.01396 seconds (files took 0.39825 seconds to load)
3 examples, 2 failures
Failed examples:
rspec ./spec/knapsack_pro/config/temp_files_spec.rb:17 # KnapsackPro::Config::TempFiles.temp_directory_path .gitignore file has content
rspec ./spec/knapsack_pro/config/temp_files_spec.rb:11 # KnapsackPro::Config::TempFiles.temp_directory_path creates .gitignore file
Randomized with seed 56734
I could disable memorization with custom argument def self.temp_directory_path(cached: true)
. For the test environment I could usecache: false
but I'm not sure if this is good idea to change method behaviour only to make tests pass :/
.knapsack_pro
directory for temporary files instead of the tmp
folder in the user project folder.knapsack_pro
directory for temporary files instead of the tmp
directory in the user's project directory
…xists! method expect(KnapsackPro::Config::TempFiles).to receive(:ensure_temp_directory_exists!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well done 👍
Added a few comments about minor things.
expect(File.read(gitignore_file_path)).to include '# This directory is used by knapsack_pro gem for storing temporary files during tests runtime' | ||
expect(File.read(gitignore_file_path)).to include '# Ignore all files, and do not commit this directory into your repository.' | ||
expect(File.read(gitignore_file_path)).to include '# Learn more at https://knapsackpro.com' | ||
expect(File.read(gitignore_file_path)).to include '*' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we test it in a way that will ensure this is a whole line containing just the asterisk? Currently as I understand it, any asterisk anywhere in the file would make this expectation pass. Business-wise we need more than that.
And if we are testing for the line with the asterisk, then maybe we could improve the example description to reflect that (maybe just updating it so that it mentions "correct content" or sth like that is good enough?)
BTW, I'd be fine with removing all of the other expectations (checking for the commented out content), as I don't think they add much.
@@ -67,7 +67,7 @@ | |||
|
|||
context 'when json report does not exist' do | |||
it do | |||
expect { subject }.to raise_error(RuntimeError, 'Report with slow test files was not generated yet. If you have enabled split by test cases https://github.com/KnapsackPro/knapsack_pro-ruby#split-test-files-by-test-cases and you see this error it means that your tests accidentally cleaned up tmp/knapsack_pro directory. Please do not remove this directory during tests runtime!') | |||
expect { subject }.to raise_error(RuntimeError, 'Report with slow test files was not generated yet. If you have enabled split by test cases https://github.com/KnapsackPro/knapsack_pro-ruby#split-test-files-by-test-cases and you see this error it means that your tests accidentally cleaned up the .knapsack_pro directory. Please do not remove this directory during tests runtime!') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
gramatically, this should read "has not been generated yet"
I would also say either "The report" or "A report" depending on what makes more sense.
|
||
private | ||
|
||
def self.create_temp_directory |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would personally add a bang to this name and the one on L31 as well.
Problem
So far knapsack_pro gem generated temporary files in the
tmp/knapsack_pro
directory but people sometimes have RSpec hooks to clean up thetmp
folder in their project. This leads to removing files generated by knapsack_pro gem.Solution
Use a different directory for temporary files. knapsack_pro gem will generate files in the
.knapsack_pro
directory in the user project folder..knapsack_pro
folder will be ignored by git out of the box because we generate.knapsack_pro/.gitignore
file that ignores all content in the.knapsack_pro
folder.