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
Adds Rails::Command::NotesCommand
and makes rake notes
use it under the hood
#33220
Conversation
Thanks for the pull request, and welcome! The Rails team is excited to review your changes, and you should hear from @sgrif (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. This repository is being automatically checked for code quality issues using Code Climate. You can see results for this analysis in the PR status below. Newly introduced issues should be fixed before a Pull Request is considered ready to review. Please see the contribution instructions for more information. |
12ab484
to
7f05fec
Compare
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 have a few comments, which many of them are just wording improvements. I like the direction of your patch, so I hope my comments won't discourage you from pushing this patch to merge. Thank you very much.
guides/source/command_line.md
Outdated
`bin/rails notes` will search through your code for comments beginning with FIXME, OPTIMIZE, or TODO. The search is done in files with extension `.builder`, `.rb`, `.rake`, `.yml`, `.yaml`, `.ruby`, `.css`, `.js`, and `.erb` for both default and custom annotations. | ||
`bin/rails notes` searches through your code for comments beginning with a specific keyword. You can refer to `bin/rails notes --help` for information about usage. | ||
|
||
By default it will search in app, config, db, lib and test directories for FIXME, OPTIMIZE, and TODO annotations in files with extension `.builder`, `.rb`, `.rake`, `.yml`, `.yaml`, `.ruby`, `.css`, `.js`, and `.erb`. |
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.
Some copywriting suggestion,
-
I think we need a comma after
By default
By default, it will ...
-
Please follow Oxford comma rule
app, config, db, lib, and test directories
-
I'm not sure if we need to put those directory name in backticks or not. Do you mind verifying from previous documetations?
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.
Based on http://guides.rubyonrails.org/engines.html app
directory seems to be using backticks. (I also am using backticks for the same directory list a few sentences later. Talk about lacking consistency here 😉)
I'll update
guides/source/command_line.md
Outdated
``` | ||
|
||
If you are looking for a specific annotation, say FIXME, you can use `bin/rails notes:fixme`. Note that you have to lower case the annotation's name. | ||
You can pass it specific annotations by using the `--annotations` argument. By default, it will search for FIXME, OPTIMIZE, and TODO. |
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 the first it
is an error here:
You can pass specific annotations
guides/source/command_line.md
Outdated
You can also use custom annotations in your code and list them using `bin/rails notes:custom` by specifying the annotation using an environment variable `ANNOTATION`. | ||
#### Directories | ||
|
||
It can be passed specific directories in which to execute the search by using the `--directories` argument. By default, it will search in `app`, `config`, `db`, `lib`, and `test` directories. |
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 don't think this reads very smooth. What do you think about rewriting it to something like
You can limit the search to be within specific directories by using `--directories` argument. By default ...
guides/source/command_line.md
Outdated
NOTE. When using specific annotations and custom annotations, the annotation name (FIXME, BUG etc) is not displayed in the output lines. | ||
|
||
By default, `rails notes` will look in the `app`, `config`, `db`, `lib`, and `test` directories. If you would like to search other directories, you can configure them using `config.annotations.register_directories` option. | ||
You can add support for additional directories using `config.annotations.register_directories` which receives a list of directory names. |
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 we can be more clear that user can add additional directories to the defaults.
You can add more default directories to search from by using `config.annotations.register_directories`
def perform(*) | ||
require_application_and_environment! | ||
|
||
annotations = options.fetch(:annotations) |
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 fetch
is not necessary here? options[:annotations]
should be fine since we don't set fallback value.
require_application_and_environment! | ||
|
||
annotations = options.fetch(:annotations) | ||
tag = true if annotations.length > 1 |
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.
We can actually remove trailing if and just set the returning boolean value, I think:
tag = (annotations.length > 1)
|
||
annotations = options.fetch(:annotations) | ||
tag = true if annotations.length > 1 | ||
directories = options.fetch(:directories, nil) |
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 believe we can also use options[:directories]
here since it will fallback to nil
by default.
end | ||
end | ||
|
||
def notes_task_deprecation_warning | ||
ActiveSupport::Deprecation.warn("This command is deprecated and will be removed in the next Rails version. \nRefer to `rails notes --help` for more information.\n\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.
-
Do you mind revising the wording a bit?
This rake task is deprecated and will be removed in the next version of Rails.
-
I'm also not sure about the deprecation timeline for this, so maybe @matthewd or @rafaelfranca can help. I wonder if we should even say "in the next major version of Rails" or something.
end | ||
end | ||
|
||
def notes_task_deprecation_warning |
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'm pretty sure that this is gong to add the methods on the global namespace, which is probably not the right thing to do. Do you mind moving this into, say, Rails::SourceAnnotationExtractor:: Annotation.display_rake_task_warning
or something?
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 it is added to the global namespace 😢 . That's why I was so specific in my method name but I like your idea of moving it to Rails::SourceAnnotationExtractor:: Annotation
. I'll do that 👌
ActiveSupport::Deprecation.warn("This command is deprecated and will be removed in the next Rails version. \nRefer to `rails notes --help` for more information.\n\n") | ||
end | ||
|
||
def notes_task_options(additional_options = []) |
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 needs to be moved as well.
Consequently, I suspect we'll need to teach the new command how to read rake-style options (while showing a deprecation message)... and then the rake task can be a straight pass-through invocation. |
bbccc2a
to
5f9a2e8
Compare
@matthewd The only place these changes are breaking the current Should I add support for |
Ah, okay, cool.
A quick GitHub-wide code search says "maybe yes" to me. (Looking at those, widespread use of forms like |
# Used in annotations.rake | ||
#:nodoc: | ||
def self.notes_task_deprecation_warning | ||
ActiveSupport::Deprecation.warn("This rake task is deprecated and will be removed in the next version of Rails. \nRefer to `rails notes --help` for more information.\n\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.
You can put Rails 6.1 here.
I'll make some changes to make sure The thing we need to be aware here is that we lose the ability to dynamically add more directories entirely from the command line which could be considered a regression. When searching for If their use case is not covered by that deprecation warning, we can add an option to
Anyway, I understand it's not a majority case so I'll get rid of
I'm not sure I understand what the purpose of --skip-defaults would be in this case. Without default it would search in no directories for no annotations which would be pretty pointless. But maybe I'm misunderstanding something :) |
bfa562b
to
454608e
Compare
I got rid of the I also updated the description of this PR to reflect the change in approach. It should be good to go now and fully backward compatible. |
Hi, Also what do you think about having the command |
@nicolas-brousse My guess it that it's too usage specific to be added to the Rails framework. I think a more generic approach would be to add support for enhancing / hooking into a specific |
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.
Thanks, @anniecodes! Nice that we'll finally have a command with such great noteriety 😄
task annotation.downcase.intern do | ||
Rails::SourceAnnotationExtractor.enumerate annotation | ||
Rails::SourceAnnotationExtractor::Annotation.notes_task_deprecation_warning | ||
Rails::Command.invoke :notes, ["--annotations", annotation] |
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.
In the future we'd want to the command infrastructure to support: Rails::Command.invoke :notes, annotations: annotation
Reverting back to a CLI-like argument passing is ridiculous when we're already in Ruby 😄
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.
Agreed. I'll look into adding support for it in a follow up PR. Any reasons why it doesn't support that already?
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.
We haven't had a lot of command invocations from the Ruby side internally in Rails yet, so I just never got to it.
But when we eventually want to expose commands to apps, running them from other commands in a nicer way is the way to go.
railties/test/commands/notes_test.rb
Outdated
|
||
add_to_config "config.annotations.register_directories \"spec\"" | ||
|
||
expected_output = [ |
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.
Would these be clearer with squiggly heredocs?
assert_equal <<~OUTPUT, run_notes_command
db/some_seeds.rb:
…
OUTPUT
|
||
def source_annotation_directories | ||
ENV["SOURCE_ANNOTATION_DIRECTORIES"] | ||
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.
I'd move the split
to here (and replace || ""
with to_s
).
It makes sense that a ENV["SOURCE_ANNOTATION_DIRECTORIES"]
returns a string or nil, but it doesn't make sense that a Ruby method named such does. That would be an empty array at worst.
Then display_deprecation_warning
can do:
if source_annotation_directories.empty?
say …
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.
I like that. I'll update.
def display_deprecation_warning | ||
return unless source_annotation_directories | ||
say ActiveSupport::Deprecation.warn("`SOURCE_ANNOTATION_DIRECTORIES` will be deprecated in Rails 6.1. You can add default directories by using config.annotations.register_directories instead.") | ||
say "\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.
Can't remember, do we even need to pass a newline in here? Or would say
just do it for us?
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.
You're right. say
adds the extra line without need to be passed \n
. I'll modify
a4f958a
to
0996fda
Compare
* Get rid of references to rake notes in the documentation * Get rid of references to environement variables used in SourceAnnotationExtractor * Updates the command line guide to reflect the new rails notes API
annotations = options[:annotations] | ||
tag = (annotations.length > 1) | ||
|
||
Rails::SourceAnnotationExtractor.enumerate annotations.join("|"), tag: tag, dirs: directories |
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.
@kaspth @rafaelfranca I realized I can't use say
here or it ends up printing the result of that method which is an array of all the files on top of the desired output which is coming from a bunch of puts
inside that module. This is not optimal as I'm outputting from a bunch of different places.
I really feel like we should only allow one way to output from a Rails::Command
. Having this mix of ways to output could end up biting us later if we wanted to output the result in another place than stdout
. It also bypasses the formatting options coming from Thor's say
.
I don't think it's worth bloating this PR more than it already is but do you think it would be worth having a follow up PR making enumerate
return a string we can output with say
here or are we ok with having outputs coming from both puts
and say
across different modules?
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 having puts
littered throughout a helper class is because Rake might be cumbersome to communicate back and forth with (or it just doesn't feel nice to do so).
I like to think of commands as similar to controllers. Where controllers are traffic cops for HTTP params and how to respond over HTTP (or whatever), commands are traffic cops for IO in/out and more in that CLI vein. The latest exploration of that was in the server command, where we moved some printing out of Rails::Server and into the command.
I really feel like we should only allow one way to output from a Rails::Command.
Perhaps that might be too restrictive. Perhaps there's a worthy experiment in seeing what executing a command within a context where puts
and print
are overriden, so we can capture whatever a helper object will output. Otherwise we might have to pass an IO object around everywhere.
I find say
annoying enough as is. It's too close to puts
to seem worth writing it, so perhaps we should rename it to something more context appropriate.
There could perhaps also be something about doing ActiveSupport::Notifications
so you could do log subscribing on commands.
I don't think it's worth bloating this PR more than it already is but do you think it would be worth having a follow up PR making enumerate return a string we can output with say here or are we ok with having outputs coming from both puts and say across different modules?
Perhaps. There's definitely something about how it's best to communicate between a command and its collaborator objects that could be teased out here.
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 is good to merge, but will let @rafaelfranca @kaspth pull the trigger.
|
||
def display_deprecation_warning | ||
return if source_annotation_directories.empty? | ||
say ActiveSupport::Deprecation.warn("`SOURCE_ANNOTATION_DIRECTORIES` will be deprecated in Rails 6.1. You can add default directories by using config.annotations.register_directories instead.") |
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.
Out of curiosity why is the say
necessary here? Shouldn't we leave the Deprecation behavior decide what to do when a deprecation is triggered?
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.
True, that's probably not needed. Let's remove it, then I'll merge 👍
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.
If I get rid of the say
here, it doesn't output in the console which I don't think is what we want.
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.
The user of the app is up to decide whether he wants to output deprecation. (By default it's gonna log in the console, but we shouldn't bypass the setting)
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.
ohhh interesting. TIL. ok I'll make the change then.
* It is called with `rails notes` * It defaults to displaying [OPTIMIZE, FIXME and TODO] annotations * It accepts custom annotations by using `rails notes -a CUSTOM_ANNOTATION OTHER_ANNOTATION` * It defaults to look for annotations in [app config db lib test] as dictated by SourceAnnotationExtractor * It supports ENV["SOURCE_ANNOTATION_DIRECTORIES"] but adds a deprecation warning and recommends using register_directories instead
* Require the application and environnement in the notes command in order to load the config files * Adds tests for both register_directories and register_extensions added to a config file
* Invokes the notes Rails::Command and passes the rake task ENV variables as annotations options to it * Adds a deprecation warning for unsupported commands * Gets rid of reference to ENV["SOURCE_ANNOTATION_DIRECTORIES"] in SourceAnnotationExtractor since its now dealt with in the NotesCommand * Gets rid of rake desc for each rake notes task so they are not documented while using `rails -T` or `rails --help`
app_file "config/initializers/some_initializer.rb", "# TODO: note in config directory" | ||
app_file "db/some_seeds.rb", "# FIXME: note in db directory" | ||
app_file "lib/some_file.rb", "# TODO: note in lib directory" | ||
app_file "test/some_test.rb", 1000.times.map { "" }.join("\n") << "# FIXME: note in test 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.
Got curious here and experimented in my console. 1000.times.map { "" }.join("\n")
could be cut down to just "\n" * 1000
.
So this works
app_file "test/some_test.rb", "\n" * 1000 << "# FIXME: note in test 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.
You're right. I just copied some test cases from the rake notes
tests 😅. To be real I could also cut it down to just a 2 or 3 digits number since it's mostly for testing the indentation/alignment of the line number as well as the annotation parsing more than one line per file. I'll put up a quick PR for it since it's a little overkill right now.
Nice! 💪 |
I think would be great to add changelog entries in railties/CHANGELOG.md about:
|
* SOURCE_ANNOTATION_DIRECTORIES deprecation * Deprecation of `rake notes`, use `rails notes` instead * Deprecation of `rails notes:custom ANNOTATION=custom`, `rails notes:optimize`, `rails notes:todo`, and `rails notes:fixme` in favor of passing `-annotations` or `-a` to `rails notes` * They have all been deprecrated in rails#33220
Summary
This PR adds a new
NotesCommand
following the pattern forRails::Commands
.rake notes
is modified to call that new command under the hood with a deprecation warning when called with the old API.API Changes
Environment variables used in the
rake
task are changed to use console options in the new API.rails notes
rails notes
rails notes:custom ANNOTATION=custom
rails notes --annotations custom
Ability to register additional default directories and extensions by using
config.annotations.register_directories
andconfig.annotations.register_extensions
has been left unchanged.Backward compatibility / Future deprecation
The commands are fully backward compatible with
SOURCE_ANNOTATION_DIRECTORIES=other_folder,spec
environment variable but display a deprecation warning for it pointing to usingconfig.annotations.register_directories
instead.The old
rails notes:custom
,rails notes:fixme
,rails notes:todo
,rails notes:optimize
are marked as deprecated.Calling any notes command with
rake
instead ofrails
is also marked as deprecated