checkoff 0.256.0 → 0.258.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/lib/checkoff/attachments.rb +12 -11
  3. data/lib/checkoff/cli.rb +11 -14
  4. data/lib/checkoff/clients.rb +2 -2
  5. data/lib/checkoff/custom_fields.rb +9 -7
  6. data/lib/checkoff/internal/asana_event_enrichment.rb +17 -11
  7. data/lib/checkoff/internal/asana_event_filter.rb +4 -0
  8. data/lib/checkoff/internal/config_loader.rb +2 -2
  9. data/lib/checkoff/internal/logging.rb +2 -2
  10. data/lib/checkoff/internal/search_url/custom_field_param_converter.rb +8 -7
  11. data/lib/checkoff/internal/search_url/custom_field_variant.rb +2 -0
  12. data/lib/checkoff/internal/search_url/date_param_converter.rb +8 -2
  13. data/lib/checkoff/internal/search_url/parser.rb +7 -5
  14. data/lib/checkoff/internal/search_url/results_merger.rb +1 -2
  15. data/lib/checkoff/internal/search_url/simple_param_converter.rb +13 -4
  16. data/lib/checkoff/internal/selector_classes/common/function_evaluator.rb +3 -0
  17. data/lib/checkoff/internal/selector_classes/common.rb +14 -30
  18. data/lib/checkoff/internal/selector_classes/function_evaluator.rb +13 -2
  19. data/lib/checkoff/internal/selector_classes/project/function_evaluator.rb +9 -0
  20. data/lib/checkoff/internal/selector_classes/project.rb +6 -13
  21. data/lib/checkoff/internal/selector_classes/section/function_evaluator.rb +6 -3
  22. data/lib/checkoff/internal/selector_classes/section.rb +2 -4
  23. data/lib/checkoff/internal/selector_classes/task.rb +42 -16
  24. data/lib/checkoff/internal/selector_evaluator.rb +4 -6
  25. data/lib/checkoff/internal/task_timing.rb +6 -5
  26. data/lib/checkoff/internal/thread_local.rb +2 -1
  27. data/lib/checkoff/my_tasks.rb +3 -1
  28. data/lib/checkoff/portfolios.rb +1 -1
  29. data/lib/checkoff/projects.rb +4 -3
  30. data/lib/checkoff/sections.rb +7 -11
  31. data/lib/checkoff/subtasks.rb +2 -1
  32. data/lib/checkoff/tags.rb +3 -2
  33. data/lib/checkoff/task_searches.rb +6 -3
  34. data/lib/checkoff/task_selectors.rb +3 -3
  35. data/lib/checkoff/tasks.rb +10 -9
  36. data/lib/checkoff/timelines.rb +21 -5
  37. data/lib/checkoff/timing.rb +4 -8
  38. data/lib/checkoff/version.rb +1 -1
  39. data/lib/checkoff/workspaces.rb +5 -2
  40. data/rbi/checkoff.rbi +145 -104
  41. data/sig/checkoff.rbs +110 -97
  42. metadata +2 -2
@@ -122,8 +122,7 @@ module Checkoff
122
122
  only_uncompleted: true,
123
123
  extra_fields: [])
124
124
  thread_local = Checkoff::Internal::ThreadLocal.new
125
- # @type [String]
126
- # @sg-ignore
125
+ # @type [String, nil]
127
126
  task_gid = thread_local.with_thread_local_variable(:suppress_asana_webhook_watch_creation,
128
127
  true) do
129
128
  gid_for_task(workspace_name, project_name, section_name, task_name)
@@ -179,9 +178,10 @@ module Checkoff
179
178
  # @param name [String]
180
179
  # @param workspace_gid [String]
181
180
  # @param assignee_gid [String]
182
- # @sg-ignore
183
181
  #
184
182
  # @return [Asana::Resources::Task]
183
+ # @sg-ignore @asana_task.create return type could not be inferred — calling a class method
184
+ # through a Class<T>-typed ivar is a known Solargraph dispatch limitation
185
185
  def add_task(name,
186
186
  workspace_gid: @workspaces.default_workspace_gid,
187
187
  assignee_gid: default_assignee_gid)
@@ -201,10 +201,10 @@ module Checkoff
201
201
 
202
202
  # True if any of the task's dependencies are marked incomplete
203
203
  #
204
- # @sg-ignore
205
204
  # Include 'dependencies.gid' in extra_fields of task passed in.
206
205
  #
207
206
  # @param task [Asana::Resources::Task]
207
+ # @return [Boolean]
208
208
  def incomplete_dependencies?(task)
209
209
  # Avoid a redundant fetch. Unfortunately, Ruby SDK allows
210
210
  # dependencies to be fetched along with other attributes--but
@@ -214,14 +214,13 @@ module Checkoff
214
214
  #
215
215
  # https://github.com/Asana/ruby-asana/issues/125
216
216
 
217
- # @type [Enumerable<Asana::Resources::Task>, nil]
217
+ # @type [Array<Hash>]
218
218
  dependencies = task.instance_variable_get(:@dependencies) || []
219
219
 
220
220
  dependencies.any? do |parent_task_info|
221
221
  # the real bummer though is that asana doesn't let you fetch
222
222
  # the completion status of dependencies, so we need to do this
223
223
  # regardless:
224
- # @sg-ignore
225
224
  parent_task_gid = parent_task_info.fetch('gid')
226
225
 
227
226
  parent_task = task_by_gid(parent_task_gid, only_uncompleted: false)
@@ -299,7 +298,7 @@ module Checkoff
299
298
  # @sg-ignore Checkoff::Tasks#in_portfolio_named? return type could not be inferred
300
299
  def in_portfolio_named?(task,
301
300
  portfolio_name,
302
- workspace_name: @workspaces.default_workspace.name)
301
+ workspace_name: T.must(@workspaces.default_workspace.name))
303
302
  portfolio_projects = @portfolios.projects_in_portfolio(workspace_name, portfolio_name)
304
303
  T.cast(task.memberships.any? do |membership|
305
304
  m = T.cast(membership, T::Hash[String, T.untyped])
@@ -316,7 +315,7 @@ module Checkoff
316
315
  # @return [Boolean]
317
316
  def in_portfolio_more_than_once?(task,
318
317
  portfolio_name,
319
- workspace_name: @workspaces.default_workspace.name)
318
+ workspace_name: T.must(@workspaces.default_workspace.name))
320
319
  portfolio_projects = @portfolios.projects_in_portfolio(workspace_name, portfolio_name)
321
320
  portfolio_project_gids = portfolio_projects.map(&:gid)
322
321
  seen = T.let(false, T::Boolean)
@@ -387,7 +386,9 @@ module Checkoff
387
386
  end
388
387
 
389
388
  # @return [String]
390
- # @sg-ignore
389
+ # @sg-ignore @config.fetch return type could not be inferred — @config is intentionally
390
+ # dual-typed [Hash, EnvFallbackConfigLoader] throughout this codebase; Solargraph can't
391
+ # unify #fetch across that union
391
392
  def default_assignee_gid
392
393
  @config.fetch(:default_assignee_gid)
393
394
  end
@@ -54,10 +54,16 @@ module Checkoff
54
54
  memberships_data = task_data.fetch('memberships')
55
55
  memberships_data.all? do |membership_data|
56
56
  # @type [Hash{String => String}]
57
+ # @sg-ignore Hash#fetch generic<X> leak on rbs >= 4.1.0, fix in progress upstream
58
+ # https://github.com/castwide/solargraph/pull/1228
57
59
  section_data = membership_data.fetch('section')
58
60
  section_gid = section_data.fetch('gid')
61
+ # @sg-ignore Hash#fetch generic<X> leak on rbs >= 4.1.0, fix in progress upstream
62
+ # https://github.com/castwide/solargraph/pull/1228
59
63
  section = @sections.section_by_gid(section_gid)
60
- # @sg-ignore
64
+ # @sg-ignore section_by_gid can return nil on a gid lookup miss, and
65
+ # task_data_dependent_on_previous_section_last_milestone? dereferences it immediately
66
+ # without a nil guard — looks like a real gap, flagging for the follow-up code PR
61
67
  task_data_dependent_on_previous_section_last_milestone?(task_data, section)
62
68
  end
63
69
  end
@@ -67,7 +73,7 @@ module Checkoff
67
73
  # @return [Boolean]
68
74
  def last_task_milestone_depends_on_this_task?(task, limit_to_portfolio_name: nil)
69
75
  unless limit_to_portfolio_name.nil?
70
- limit_to_projects = @portfolios.projects_in_portfolio(@workspaces.default_workspace.name,
76
+ limit_to_projects = @portfolios.projects_in_portfolio(T.must(@workspaces.default_workspace.name),
71
77
  limit_to_portfolio_name)
72
78
  end
73
79
 
@@ -79,14 +85,20 @@ module Checkoff
79
85
  md = membership_data
80
86
  unless limit_to_portfolio_name.nil?
81
87
  # @type [Hash{String => Object}]
88
+ # @sg-ignore Hash#fetch generic<X> leak on rbs >= 4.1.0, fix in progress upstream
89
+ # https://github.com/castwide/solargraph/pull/1228
82
90
  project_data = md.fetch('project')
83
91
  project_gid = project_data.fetch('gid')
84
92
  next true unless limit_to_projects.map(&:gid).include? project_gid
85
93
  end
86
94
  # @type [Hash{String => Object}]
95
+ # @sg-ignore Hash#fetch generic<X> leak on rbs >= 4.1.0, fix in progress upstream
96
+ # https://github.com/castwide/solargraph/pull/1228
87
97
  section_data = md.fetch('section')
88
98
  section_gid = section_data.fetch('gid')
89
99
 
100
+ # @sg-ignore Hash#fetch generic<X> leak on rbs >= 4.1.0, fix in progress upstream
101
+ # https://github.com/castwide/solargraph/pull/1228
90
102
  last_milestone = last_milestone_in_section(section_gid)
91
103
 
92
104
  next false if last_milestone.nil?
@@ -95,7 +107,8 @@ module Checkoff
95
107
 
96
108
  all_dependent_task_gids ||= @tasks.all_dependent_tasks(task).map(&:gid)
97
109
 
98
- # @sg-ignore
110
+ # @sg-ignore all_dependent_task_gids is nil-initialized then set via ||= above, but
111
+ # Solargraph doesn't narrow it back to non-nil after the reassignment
99
112
  all_dependent_task_gids.include? last_milestone.gid
100
113
  end
101
114
  end
@@ -105,7 +118,7 @@ module Checkoff
105
118
  # @return [Boolean]
106
119
  def any_milestone_depends_on_this_task?(task, limit_to_portfolio_name: nil)
107
120
  unless limit_to_portfolio_name.nil?
108
- limit_to_projects = @portfolios.projects_in_portfolio(@workspaces.default_workspace.name,
121
+ limit_to_projects = @portfolios.projects_in_portfolio(T.must(@workspaces.default_workspace.name),
109
122
  limit_to_portfolio_name)
110
123
  end
111
124
 
@@ -117,6 +130,8 @@ module Checkoff
117
130
  md = membership_data
118
131
  unless limit_to_portfolio_name.nil?
119
132
  # @type [Hash{String => Object}]
133
+ # @sg-ignore Hash#fetch generic<X> leak on rbs >= 4.1.0, fix in progress upstream
134
+ # https://github.com/castwide/solargraph/pull/1228
120
135
  project_data = md.fetch('project')
121
136
  project_gid = project_data.fetch('gid')
122
137
  next true unless limit_to_projects.map(&:gid).include? project_gid
@@ -131,7 +146,8 @@ module Checkoff
131
146
  dependent_task.resource_subtype == 'milestone'
132
147
  end
133
148
 
134
- # @sg-ignore
149
+ # @sg-ignore all_dependent_milestones is nil-initialized then set via ||= above, but
150
+ # Solargraph doesn't narrow it back to non-nil after the reassignment
135
151
  all_dependent_milestones.any? do |milestone|
136
152
  milestone.memberships.any? do |milestone_membership_data|
137
153
  milestone_membership_data.fetch('project').fetch('gid') == project_gid
@@ -44,18 +44,15 @@ module Checkoff
44
44
 
45
45
  return next_week?(date_or_time) if period == :next_week
46
46
 
47
- # @sg-ignore
48
- return day_of_week?(date_or_time, period) if %i[monday tuesday wednesday thursday friday saturday
49
- sunday].include?(period)
47
+ return day_of_week?(date_or_time, T.cast(period, Symbol)) if %i[monday tuesday wednesday thursday friday
48
+ saturday sunday].include?(period)
50
49
 
51
50
  return true if period == :indefinite
52
51
 
53
52
  return now_or_before?(date_or_time) if period == :now_or_before
54
53
 
55
54
  if period.is_a?(Array)
56
- # @sg-ignore
57
- # @type [Symbol]
58
- period_name = period.first
55
+ period_name = T.cast(period.first, Symbol)
59
56
  args = period[1..]
60
57
 
61
58
  return compound_in_period?(date_or_time, period_name, *args)
@@ -209,7 +206,7 @@ module Checkoff
209
206
 
210
207
  # @param date_or_time [Date,Time,nil]
211
208
  # @param period_name [Symbol]
212
- # @param args [Object]
209
+ # @param args [Array<Object>]
213
210
  def compound_in_period?(date_or_time, period_name, *args)
214
211
  return less_than_n_days_ago?(date_or_time, *args) if period_name == :less_than_n_days_ago
215
212
 
@@ -225,7 +222,6 @@ module Checkoff
225
222
 
226
223
  return between_relative_days?(date_or_time, *args) if period_name == :between_relative_days
227
224
 
228
- # @sg-ignore
229
225
  raise "Teach me how to handle period [#{period_name.inspect}, #{args.map(&:inspect).join(', ')}]"
230
226
  end
231
227
 
@@ -4,5 +4,5 @@
4
4
  # Command-line and gem client for Asana (unofficial)
5
5
  module Checkoff
6
6
  # Version of library
7
- VERSION = '0.256.0'
7
+ VERSION = '0.258.0'
8
8
  end
@@ -44,7 +44,8 @@ module Checkoff
44
44
  cache_method :workspace, LONG_CACHE_TIME
45
45
 
46
46
  # @return [Asana::Resources::Workspace]
47
- # @sg-ignore
47
+ # @sg-ignore @asana_workspace.find_by_id return type could not be inferred — calling a
48
+ # class method through a Class<T>-typed ivar is a known Solargraph dispatch limitation
48
49
  def default_workspace
49
50
  @asana_workspace.find_by_id(client, default_workspace_gid)
50
51
  end
@@ -61,7 +62,9 @@ module Checkoff
61
62
  end
62
63
 
63
64
  # @return [String]
64
- # @sg-ignore
65
+ # @sg-ignore @config.fetch return type could not be inferred — @config is intentionally
66
+ # dual-typed [Hash, EnvFallbackConfigLoader] throughout this codebase; Solargraph can't
67
+ # unify #fetch across that union
65
68
  def default_workspace_gid
66
69
  @config.fetch(:default_workspace_gid)
67
70
  end