Skip to content

Commit

Permalink
Added a new option to ignore files using regular expressions (#43)
Browse files Browse the repository at this point in the history
  • Loading branch information
NikkelM authored Feb 10, 2024
1 parent 4685562 commit d320424
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 28 deletions.
10 changes: 6 additions & 4 deletions .github/config.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
todo-pr-checker:
# When should comments be posted?
post_comment: 'items_found'
# If multiline comments should also be searched for action items
# This may result in some false positives or negatives if the opening or closing lines of a comment are not in the diff
enable_multiline_comments: false
# Files that get matched by any of these regular expressions will be ignored
ignore_files: null
# What action items should be looked for (setting this will the overwrite default values)
action_items: ['TODO', 'FIXME', 'BUG']
# Languages/file types to add. At least either the line comment or both block comment definitions are required.
Expand All @@ -14,4 +13,7 @@ todo-pr-checker:
['.py', '#']
]
# Whether or not searching for action items should be case sensitive
case_sensitive: false
case_sensitive: false
# If multiline comments should also be searched for action items
# This may result in some false positives or negatives if the opening or closing lines of a comment are not in the diff
enable_multiline_comments: false
6 changes: 6 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ Metrics/MethodLength:
Metrics/BlockLength:
Enabled: false

Metrics/BlockNesting:
Max: 4

Metrics/AbcSize:
Enabled: false

Expand All @@ -25,3 +28,6 @@ Metrics/PerceivedComplexity:

Style/MethodCallWithoutArgsParentheses:
Enabled: false

Style/RescueModifier:
Enabled: false
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

<!--Releasenotes start-->
- The app will now always include the results of the action item search in the check run summary.
- Added an option that allows you to ignore files that match a specific pattern.
- Added an option to enable multiline block comments. This option is disabled by default, as it may cause the app to incorrectly identify action items.
- If the app encounters an error while the check is running, the check will now be concluded as neutral and the error message will be included in the check run summary.
- Fixed a bug where setting one of the values of the `add_languages` option to `null` would cause the app to not accept any new languages.
Expand Down
1 change: 0 additions & 1 deletion POSTINSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,3 @@ I hope that you'll find it useful and that it will help you and your team keep t
Hosting and maintaining this app unfortunately is not free, so I appreciate your contribution to help keep it running - consider buying me a [coffee](https://ko-fi.com/nikkelm) or [sponsoring](https://github.com/sponsors/NikkelM) this project.

Please also take a look at the [project readme](https://github.com/NikkelM/Todo-PR-Checker/blob/main/README.md) to learn how to configure the app to match your needs through a `.github/config.yml` file, and feel free to reach out and open an issue if you have any questions or need help.

7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,11 @@ To get started, you can copy the `.github/config.yml` file from this repository
| Option | Possible Values | Description | Default |
| --- | --- | --- | --- |
| `post_comment` | `items_found`, `always`, `never` | Controls when the app should post a comment. By default, a comment is only posted if an action item has been found. If set to `never`, the check will still fail. If set to `always`, the app will post a comment that all action items have been resolved if none are found. | `items_found` |
| `enable_multiline_comments` | `true`, `false` | Whether or not looking for action items in multiline block comments is enabled or not. When enabled, the app *may* incorrectly mark action items in your Pull Request if at least one of the opening or closing line of the block comment (e.g. `*/` and `/*` in JavaScript) are not included in the Pull Request diff, which causes them to not be found by the app. For multiline comments to always work, you must ensure that both the opening and closing characters are included in the diff. Action items located on the first line of a block comment will always be detected, even if this option is disabled. | `false` |
| `action_items` | `string[]` | A list of action items to look for in code comments. If you set this option, the default values will be overwritten, so you must include them in your list to use them. | `['TODO', 'FIXME', 'BUG']` |
| `ignore_files` | `string[]`, maximum 7 entries | A list of glob patterns to specify files that should be ignored during the check. You may specify up to 7 patterns. The pattern matching logic used is the same as for `.gitignore` files. | `null` |
| `action_items` | `string[]`, maximum 15 entries | A list of action items to look for in code comments. If you set this option, the default values will be overwritten, so you must include them in your list to use them. By default, action items are case insensitive. You may specify up to 15 items. | `['TODO', 'FIXME', 'BUG']` |
| `add_languages` | `[string[file_type, line_start, block_start, block_end]]`</br>Example: `[['js', '//', '/*', '*,'], ['css', null, '/*', '*/'], ['.py', '#']]`, maximum 10 entries | A list of a list of programming languages to add support for. This list will be added to the already supported languages. If you define a language that is already supported, the default values will be overwritten. `file_type` must be the extension of the file (e.g. `js`) and may start with a `.`. You may omit the block comment definitions if the file type does not support block comments. If you want to omit the definition of a line comment, you must set `line_start` to `null`. If defining `block_start`, `block_end` must also be defined. You may specify up to 10 new file types. *The file types shown in the example are already natively supported by the app.* | `null` |
| `case_sensitive` | `true`, `false` | Controls whether the app should look for action items in a case-sensitive manner. | `false` |
| `add_languages` | `[string[file_type, line_start, block_start, block_end]]`</br>Example: `[['js', '//', '/*', '*,'], ['css', null, '/*', '*/'], ['.py', '#']]` | A list of a list of programming languages to add support for. This list will be added to the already supported languages. If you define a language that is already supported, the default values will be overwritten. `file_type` must be the extension of the file (e.g. `js`) and may start with a `.`. You may omit the block comment definitions if the file type does not support block comments. If you want to omit the definition of a line comment, you must set `line_start` to `null`. If defining `block_start`, `block_end` must also be defined. *The file types shown in the example are already natively supported by the app.* | `null` |
| `enable_multiline_comments` | `true`, `false` | Whether or not looking for action items in multiline block comments is enabled or not. When enabled, the app *may* incorrectly mark action items in your Pull Request if at least one of the opening or closing line of the block comment (e.g. `*/` and `/*` in JavaScript) are not included in the Pull Request diff, which causes them to not be found by the app. For multiline comments to always work, you must ensure that both the opening and closing characters are included in the diff. Action items located on the first line of a block comment will always be detected, even if this option is disabled. | `false` |

<details>
<summary>Expand me to see the currently supported file types:</summary>
Expand Down
57 changes: 40 additions & 17 deletions app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,21 +101,23 @@ def initiate_check_run

# Get the options for the app from the `.github/config.yml` file in the repository
app_options = get_app_options(full_repo_name, @payload['check_run']['head_sha'])
# logger.debug app_options

# Get a list of changed lines in the Pull request, grouped by their file name and associated with a line number
changes = get_pull_request_changes(full_repo_name, pull_number)
changes = get_pull_request_changes(full_repo_name, pull_number, app_options['ignore_files'])

# Filter the changed lines for only those that contain action items ("Todos"), and group them by file
todo_changes = check_for_todos(changes, app_options)

# If the app has previously created a comment on the Pull Request, fetch it
app_comment = fetch_app_comment(full_repo_name, pull_number)
comment_footer = "\n----\nDid I do good? Let me know by [helping maintain this app](https://github.com/sponsors/NikkelM)!"

# If any action items were found, create/update a comment on the Pull Request with embedded links to the relevant lines
if todo_changes.any?
# If the user has enabled post_comment in the options
if app_options['post_comment'] != 'never'
check_run_title, comment_summary, comment_body, comment_footer = create_pr_comment_from_changes(todo_changes, full_repo_name).values_at(:title, :summary, :body, :footer)
check_run_title, comment_summary, comment_body = create_pr_comment_from_changes(todo_changes, full_repo_name).values_at(:title, :summary, :body)

# Post or update the comment with the found action items
if app_comment
Expand Down Expand Up @@ -168,15 +170,18 @@ def get_app_options(full_repo_name, head_sha)
'enable_multiline_comments' => true,
'action_items' => %w[todo fixme bug],
'case_sensitive' => false,
'add_languages' => []
'add_languages' => [],
'ignore_files' => []
}

accepted_option_values = {
'post_comment' => ->(value) { %w[items_found always never].include?(value) },
'enable_multiline_comments' => ->(value) { [true, false].include?(value) },
'action_items' => ->(value) { value.is_a?(Array) },
'action_items' => ->(value) { value.is_a?(Array) && (0..15).include?(value.size) },
'case_sensitive' => ->(value) { [true, false].include?(value) },
'add_languages' => ->(value) { value.is_a?(Array) && value.all? { |v| v.is_a?(Array) && (2..4).include?(v.size) && v.all? { |i| i.is_a?(String) || i.nil? } } }
'add_languages' => ->(value) { value.is_a?(Array) && (1..10).include?(value.size) && value.all? { |v| v.is_a?(Array) && (2..4).include?(v.size) && v.all? { |i| i.is_a?(String) || i.nil? } } },
# The regex checks if the given input is a valid .gitignore pattern
'ignore_files' => ->(value) { value.is_a?(Array) && (1..7).include?(value.size) && value.all? { |v| v.is_a?(String) && %r{\A(/?(\*\*/)?[\w*\[\]{}?\.\/-]+(/\*\*)?/?)\Z}.match?(v) } }
}

file = @installation_client.contents(full_repo_name, path: '.github/config.yml', ref: head_sha)
Expand All @@ -198,28 +203,47 @@ def get_app_options(full_repo_name, head_sha)
end

# (4) Retrieves all changes in a pull request from the GitHub API and formats them to be usable by the app
def get_pull_request_changes(full_repo_name, pull_number)
def get_pull_request_changes(full_repo_name, pull_number, ignore_files_regex)
diff = @installation_client.pull_request(full_repo_name, pull_number, accept: 'application/vnd.github.diff')

ignore_files_regex.map! do |pattern|
pattern.gsub!('.', '\.')
pattern.gsub!('*', '.*')
pattern.gsub!('/', '\/')
Regexp.new(pattern)
end

current_file = ''
line_number = 0
changes = {}

diff.each_line do |line|
# This is the most common case, indicating a line was added to the file
if line.start_with?('+') && !line.start_with?('+++')
diff_enum = diff.each_line
line = diff_enum.next rescue nil
loop do
break if line.nil?

if line.start_with?('+++')
while line&.start_with?('+++')
current_file = line[6..].strip
if ignore_files_regex.any? { |pattern| pattern.match?(current_file) }
loop do
line = diff_enum.next rescue nil
break if line.nil? || line.start_with?('+++')
end
else
changes[current_file] = []
break
end
end
break if line.nil?
elsif line.start_with?('+')
changes[current_file] << { line: line_number, text: line[1..] }
# Lines that start with @@ contain the the starting line and its length for a new block of changes, for the old and new file respectively
elsif line.start_with?('@@')
line_number = line.split()[2].split(',')[0].to_i - 1
# Lines that start with +++ contain the new name of the file, which is the one we want to link to in the comment
elsif line.start_with?('+++')
current_file = line[6..].strip
changes[current_file] = []
end

# We count the line numbers for lines in the new file, which means we need to exclude unchanged lines, and the special "no newline" line
line_number += 1 unless line.start_with?('-') || line.chomp == '\ No newline at end of file'
line = diff_enum.next rescue nil
end

changes
Expand Down Expand Up @@ -347,9 +371,8 @@ def create_pr_comment_from_changes(todo_changes, full_repo_name)
end
end
end
comment_footer = "\n----\nDid I do good? Let me know by [helping maintain this app](https://github.com/sponsors/NikkelM)!"

{ title: check_run_title, summary: comment_summary, body: comment_body, footer: comment_footer }
{ title: check_run_title, summary: comment_summary, body: comment_body }
end

# (8) If the app has already created a comment on the Pull Request, return a reference to it, otherwise return nil
Expand Down
4 changes: 2 additions & 2 deletions validation/validation.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// TODO: Alerts in this file: ? if multiline comments, 1 if standalone_items, 5 else
// TODO: Alerts in this file: ? if multiline comments, 1 if standalone_items, 6 else
let a = "todo";
//TODO: Alert
let b = "todo";
// TODO Alert
let c = "todo";
/* TODO: Alert */
/* TODO: Alert */
let d = "todo";
/* TODO: Alert
let alertThis = "TODO";
Expand Down
2 changes: 1 addition & 1 deletion version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# frozen_string_literal: true

VERSION = '1.2.0'
VERSION = '1.3.0'

0 comments on commit d320424

Please sign in to comment.