smart_todo 1.9.2 → 1.10.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: beb68e6ca2807c8c2fb782fb34109d5abe45f3e306cab7ad2f34b211f6a250aa
4
- data.tar.gz: cc9978ba39c42bf194de59836c945197d066537187e34285857758bfcaf63ed5
3
+ metadata.gz: eed299ced3a12723ccf8cb775ea33b3ce784b1c05c18ced890b3c8b184c0124e
4
+ data.tar.gz: a2e1ff5973fb8b1b7b40ee700a56acbee6c6c30df0c23e16e8c9505fe24af8ba
5
5
  SHA512:
6
- metadata.gz: 580080fabbbcc83ad8f372e56b5d4c2238688fc4617edd1501ac3032ddd61497db9e9c2a648f7a7b32acdda27790fa63fe0eb5c5c08d8b97c2e72116f2868f92
7
- data.tar.gz: 6593132b64a848caa0205518b8c2124d04e6099b225af92e18ff997b5d204c1518c70c556280b766f3d6ea639bf9d4b44460152230f37baeda08f49f707bc889
6
+ metadata.gz: a36e6f20daabc1e3cdd74d8c5b63fd6284e0581de67b769dbeea5c97948f438cddefae166cf8c260d11237e6fbb22beeab9e0da1b0c069277f10c7d4ac1468ba
7
+ data.tar.gz: e020e58592618dd6567d8031dfe4c5c8c77bc7ccb372d7de2060c98f13ef072eaf31a01e16d2e9bc07118ea8553b2d716c95df19a0aed105b45baea1c6bf2406
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- smart_todo (1.9.2)
4
+ smart_todo (1.10.0)
5
5
  prism (~> 1.0)
6
6
 
7
7
  GEM
@@ -66,6 +66,9 @@ module SmartTodo
66
66
  opts.on("--dispatcher DISPATCHER") do |dispatcher|
67
67
  @options[:dispatcher] = dispatcher
68
68
  end
69
+ opts.on("--repo [REPO]", "Repository name to include in notifications") do |repo|
70
+ @options[:repo] = repo || File.basename(Dir.pwd)
71
+ end
69
72
  end
70
73
  end
71
74
 
@@ -2,6 +2,9 @@
2
2
 
3
3
  module SmartTodo
4
4
  class CommentParser
5
+ SUPPORTED_TAGS = ["TODO", "FIXME", "OPTIMIZE"].freeze
6
+ TAG_PATTERN = /^#\s(#{SUPPORTED_TAGS.join("|")})\(/
7
+
5
8
  attr_reader :todos
6
9
 
7
10
  def initialize
@@ -54,7 +57,7 @@ module SmartTodo
54
57
 
55
58
  source = comment.location.slice
56
59
 
57
- if source.match?(/^#\sTODO\(/)
60
+ if source.match?(TAG_PATTERN)
58
61
  todos << current_todo if current_todo
59
62
  current_todo = Todo.new(source, filepath)
60
63
  elsif current_todo && (indent = source[/^#(\s*)/, 1].length) && (indent - current_todo.indent == 2)
@@ -68,7 +68,7 @@ module SmartTodo
68
68
  <<~EOM
69
69
  #{header}
70
70
 
71
- You have an assigned TODO in the `#{@file}` file.
71
+ You have an assigned TODO in the `#{@file}` file#{repo}.
72
72
  #{@event_message}
73
73
 
74
74
  Here is the associated comment on your TODO:
@@ -91,6 +91,15 @@ module SmartTodo
91
91
  def existing_user
92
92
  "Hello :wave:,"
93
93
  end
94
+
95
+ def repo
96
+ repo = @options[:repo]
97
+ return unless repo
98
+
99
+ unless repo.empty?
100
+ " in repository `#{repo}`"
101
+ end
102
+ end
94
103
  end
95
104
  end
96
105
  end
@@ -7,7 +7,8 @@ module SmartTodo
7
7
  class Slack < Base
8
8
  class << self
9
9
  def validate_options!(options)
10
- options[:slack_token] ||= ENV.fetch("SMART_TODO_SLACK_TOKEN") { raise(ArgumentError, "Missing :slack_token") }
10
+ options[:slack_token] ||= ENV.fetch("SMART_TODO_SLACK_TOKEN", "")
11
+ raise(ArgumentError, "Missing :slack_token") if options[:slack_token].empty?
11
12
 
12
13
  options.fetch(:fallback_channel) { raise(ArgumentError, "Missing :fallback_channel") }
13
14
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SmartTodo
4
- VERSION = "1.9.2"
4
+ VERSION = "1.10.0"
5
5
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "smart_todo"
4
+ require "date"
4
5
 
5
6
  module RuboCop
6
7
  module Cop
@@ -12,12 +13,20 @@ module RuboCop
12
13
  class SmartTodoCop < Base
13
14
  HELP = "For more info please look at https://github.com/Shopify/smart_todo/wiki/Syntax"
14
15
  MSG = "Don't write regular TODO comments. Write SmartTodo compatible syntax comments. #{HELP}"
16
+ INVESTIGATED_TAGS = ::SmartTodo::CommentParser::SUPPORTED_TAGS +
17
+ ::SmartTodo::CommentParser::SUPPORTED_TAGS.map(&:downcase)
18
+ TODO_PATTERN = /^#\s@?(#{INVESTIGATED_TAGS.join("|")})\b/
15
19
 
16
20
  # @param processed_source [RuboCop::ProcessedSource]
17
21
  # @return [void]
18
22
  def on_new_investigation
19
23
  processed_source.comments.each do |comment|
20
- next unless /^#\sTODO/.match?(comment.text)
24
+ next unless (match = TODO_PATTERN.match(comment.text))
25
+
26
+ if match[1] != match[1].upcase
27
+ add_offense(comment)
28
+ next
29
+ end
21
30
 
22
31
  metadata = metadata(comment.text)
23
32
 
@@ -25,10 +34,10 @@ module RuboCop
25
34
  add_offense(comment, message: "Invalid TODO format: #{metadata.errors.join(", ")}. #{HELP}")
26
35
  elsif !smart_todo?(metadata)
27
36
  add_offense(comment)
28
- elsif (methods = invalid_event_methods(metadata.events)).any?
29
- add_offense(comment, message: "Invalid event method(s): #{methods.join(", ")}. #{HELP}")
30
37
  elsif invalid_assignees(metadata.assignees).any?
31
38
  add_offense(comment, message: "Invalid event assignee. This method only accepts strings. #{HELP}")
39
+ elsif (invalid_events = validate_events(metadata.events)).any?
40
+ add_offense(comment, message: "#{invalid_events.join(". ")}. #{HELP}")
32
41
  end
33
42
  end
34
43
  end
@@ -49,17 +58,94 @@ module RuboCop
49
58
  metadata.assignees.any?
50
59
  end
51
60
 
52
- # @param metadata [Array<SmartTodo::Parser::MethodNode>]
53
- # @return [Array<String>]
54
- def invalid_event_methods(events)
55
- events.map(&:method_name).reject { |method| ::SmartTodo::Events.method_defined?(method) }
56
- end
57
-
58
61
  # @param assignees [Array]
59
62
  # @return [Array]
60
63
  def invalid_assignees(assignees)
61
64
  assignees.reject { |assignee| assignee.is_a?(String) }
62
65
  end
66
+
67
+ # @param events [Array<SmartTodo::Todo::CallNode>]
68
+ # @return [Array<String>]
69
+ def validate_events(events)
70
+ invalid_methods = events.map(&:method_name).reject { |method| ::SmartTodo::Events.method_defined?(method) }
71
+ return ["Invalid event method(s): #{invalid_methods.join(", ")}"] if invalid_methods.any?
72
+
73
+ events.map do |event|
74
+ send(validate_method(event.method_name), event.arguments)
75
+ end.compact
76
+ end
77
+
78
+ # @param event_type [Symbol]
79
+ # @return [String]
80
+ def validate_method(event_type)
81
+ "validate_#{event_type}_args"
82
+ end
83
+
84
+ # @param args [Array]
85
+ # @return [String, nil] Returns error message if date is invalid, nil if valid
86
+ def validate_date_args(args)
87
+ date = args.first
88
+ Date.parse(date)
89
+ nil
90
+ rescue ArgumentError, TypeError
91
+ "Invalid date format: #{date}"
92
+ end
93
+
94
+ # @param args [Array]
95
+ # @return [String, nil] Returns error message if arguments are invalid, nil if valid
96
+ def validate_issue_close_args(args)
97
+ validate_fixed_arity_args(args, 3, "issue_close", ["organization", "repo", "issue_number"])
98
+ end
99
+
100
+ # @param args [Array]
101
+ # @return [String, nil] Returns error message if arguments are invalid, nil if valid
102
+ def validate_pull_request_close_args(args)
103
+ validate_fixed_arity_args(args, 3, "pull_request_close", ["organization", "repo", "pr_number"])
104
+ end
105
+
106
+ # @param args [Array]
107
+ # @return [String, nil] Returns error message if arguments are invalid, nil if valid
108
+ def validate_gem_release_args(args)
109
+ validate_gem_args(args, "gem_release")
110
+ end
111
+
112
+ # @param args [Array]
113
+ # @return [String, nil] Returns error message if arguments are invalid, nil if valid
114
+ def validate_gem_bump_args(args)
115
+ validate_gem_args(args, "gem_bump")
116
+ end
117
+
118
+ # @param args [Array]
119
+ # @return [String, nil] Returns error message if arguments are invalid, nil if valid
120
+ def validate_ruby_version_args(args)
121
+ if args.empty?
122
+ "Invalid ruby_version event: Expected at least 1 argument (version requirement), got 0"
123
+ elsif !args.all? { |arg| arg.is_a?(String) }
124
+ "Invalid ruby_version event: Version requirements must be strings"
125
+ end
126
+ end
127
+
128
+ # Helper method for validating fixed arity events
129
+ def validate_fixed_arity_args(args, expected_count, event_name, arg_names)
130
+ if args.size != expected_count
131
+ message = "Invalid #{event_name} event: Expected #{expected_count} arguments "
132
+ message += "(#{arg_names.join(", ")}), got #{args.size}"
133
+ message
134
+ elsif !args.all? { |arg| arg.is_a?(String) }
135
+ "Invalid #{event_name} event: Arguments must be strings"
136
+ end
137
+ end
138
+
139
+ # Helper method for validating gem-related events
140
+ def validate_gem_args(args, event_name)
141
+ if args.empty?
142
+ "Invalid #{event_name} event: Expected at least 1 argument (gem_name), got 0"
143
+ elsif !args[0].is_a?(String)
144
+ "Invalid #{event_name} event: First argument (gem_name) must be a string"
145
+ elsif args.size > 1 && !args[1..].all? { |arg| arg.is_a?(String) }
146
+ "Invalid #{event_name} event: Version requirements must be strings"
147
+ end
148
+ end
63
149
  end
64
150
  end
65
151
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_todo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.2
4
+ version: 1.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-03-31 00:00:00.000000000 Z
10
+ date: 2025-04-08 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: prism