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.
- checksums.yaml +4 -4
- data/lib/checkoff/attachments.rb +12 -11
- data/lib/checkoff/cli.rb +11 -14
- data/lib/checkoff/clients.rb +2 -2
- data/lib/checkoff/custom_fields.rb +9 -7
- data/lib/checkoff/internal/asana_event_enrichment.rb +17 -11
- data/lib/checkoff/internal/asana_event_filter.rb +4 -0
- data/lib/checkoff/internal/config_loader.rb +2 -2
- data/lib/checkoff/internal/logging.rb +2 -2
- data/lib/checkoff/internal/search_url/custom_field_param_converter.rb +8 -7
- data/lib/checkoff/internal/search_url/custom_field_variant.rb +2 -0
- data/lib/checkoff/internal/search_url/date_param_converter.rb +8 -2
- data/lib/checkoff/internal/search_url/parser.rb +7 -5
- data/lib/checkoff/internal/search_url/results_merger.rb +1 -2
- data/lib/checkoff/internal/search_url/simple_param_converter.rb +13 -4
- data/lib/checkoff/internal/selector_classes/common/function_evaluator.rb +3 -0
- data/lib/checkoff/internal/selector_classes/common.rb +14 -30
- data/lib/checkoff/internal/selector_classes/function_evaluator.rb +13 -2
- data/lib/checkoff/internal/selector_classes/project/function_evaluator.rb +9 -0
- data/lib/checkoff/internal/selector_classes/project.rb +6 -13
- data/lib/checkoff/internal/selector_classes/section/function_evaluator.rb +6 -3
- data/lib/checkoff/internal/selector_classes/section.rb +2 -4
- data/lib/checkoff/internal/selector_classes/task.rb +42 -16
- data/lib/checkoff/internal/selector_evaluator.rb +4 -6
- data/lib/checkoff/internal/task_timing.rb +6 -5
- data/lib/checkoff/internal/thread_local.rb +2 -1
- data/lib/checkoff/my_tasks.rb +3 -1
- data/lib/checkoff/portfolios.rb +1 -1
- data/lib/checkoff/projects.rb +4 -3
- data/lib/checkoff/sections.rb +7 -11
- data/lib/checkoff/subtasks.rb +2 -1
- data/lib/checkoff/tags.rb +3 -2
- data/lib/checkoff/task_searches.rb +6 -3
- data/lib/checkoff/task_selectors.rb +3 -3
- data/lib/checkoff/tasks.rb +10 -9
- data/lib/checkoff/timelines.rb +21 -5
- data/lib/checkoff/timing.rb +4 -8
- data/lib/checkoff/version.rb +1 -1
- data/lib/checkoff/workspaces.rb +5 -2
- data/rbi/checkoff.rbi +145 -104
- data/sig/checkoff.rbs +110 -97
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cacf5e2fbe9fab040accd8cd51804fcf3f07cf0e6f050c93ecbe2da2c930bdc5
|
|
4
|
+
data.tar.gz: ebfe6f20e1be062a918afac5a4703df7a0d5205c69cb8d0479d5f6427c467767
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cddee9806d41d98908eca0331b3b52ee84b45968e419aad7b8817003389418f65e9536b02c2db20b2368796b447046b7093819b094ba01dcd7c59875eb404562
|
|
7
|
+
data.tar.gz: 82b6db32f7d6ad50d287da1fba1a537468f94aa283d60358fcf4a03953df86c41dc00da2dd514cfdbd838bd5ce2209f11e97966f00814e27fe1640cf8ad41cb3
|
data/lib/checkoff/attachments.rb
CHANGED
|
@@ -54,7 +54,7 @@ module Checkoff
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
# @param url [String]
|
|
57
|
-
# @param resource [Asana::Resources::
|
|
57
|
+
# @param resource [Asana::Resources::Task]
|
|
58
58
|
# @param attachment_name [String,nil]
|
|
59
59
|
# @param just_the_url [Boolean]
|
|
60
60
|
# @param verify_mode [Integer] - e.g., OpenSSL::SSL::VERIFY_NONE or OpenSSL::SSL::VERIFY_PEER
|
|
@@ -79,15 +79,15 @@ module Checkoff
|
|
|
79
79
|
# extension as the URL using Net::HTTP, raising an exception if
|
|
80
80
|
# not succesful
|
|
81
81
|
#
|
|
82
|
-
# @param uri [URI]
|
|
82
|
+
# @param uri [URI::Generic]
|
|
83
83
|
# @param verify_mode [Integer] - e.g., OpenSSL::SSL::VERIFY_NONE,OpenSSL::SSL::VERIFY_PEER
|
|
84
84
|
#
|
|
85
85
|
# @return [Object]
|
|
86
86
|
def download_uri(uri, verify_mode: OpenSSL::SSL::VERIFY_PEER, &block)
|
|
87
87
|
out = nil
|
|
88
|
-
# @sg-ignore
|
|
89
88
|
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https', verify_mode:) do |http|
|
|
90
|
-
# @sg-ignore
|
|
89
|
+
# @sg-ignore Unresolved constant Net::HTTP::Get / Unresolved call to request —
|
|
90
|
+
# stdlib RBS gap on Net::HTTP block param types
|
|
91
91
|
http.request(Net::HTTP::Get.new(uri)) do |response|
|
|
92
92
|
raise("Unexpected response code: #{response.code}") unless response.code == '200'
|
|
93
93
|
|
|
@@ -120,7 +120,7 @@ module Checkoff
|
|
|
120
120
|
end
|
|
121
121
|
|
|
122
122
|
# @param url [String]
|
|
123
|
-
# @param resource [Asana::Resources::
|
|
123
|
+
# @param resource [Asana::Resources::Task]
|
|
124
124
|
# @param attachment_name [String,nil]
|
|
125
125
|
# @param verify_mode [Integer] - e.g., OpenSSL::SSL::VERIFY_NONE,OpenSSL::SSL::VERIFY_PEER
|
|
126
126
|
#
|
|
@@ -130,25 +130,25 @@ module Checkoff
|
|
|
130
130
|
uri = URI(url)
|
|
131
131
|
attachment_name ||= File.basename(uri.path)
|
|
132
132
|
download_uri(uri, verify_mode:) do |tempfile|
|
|
133
|
-
# @sg-ignore
|
|
133
|
+
# @sg-ignore attachment_name reassignment above isn't narrowed from the declared
|
|
134
|
+
# [String, nil] param type — needs a fresh typed local, deferred to a follow-up code PR
|
|
134
135
|
content_type ||= content_type_from_filename(attachment_name)
|
|
135
|
-
# @sg-ignore
|
|
136
|
+
# @sg-ignore URI::Generic#path can be nil
|
|
136
137
|
content_type ||= content_type_from_filename(uri.path)
|
|
137
138
|
|
|
138
|
-
# @sg-ignore
|
|
139
|
+
# @sg-ignore same attachment_name/content_type narrowing gap as above
|
|
139
140
|
resource.attach(filename: attachment_name, mime: content_type,
|
|
140
141
|
io: tempfile)
|
|
141
142
|
end
|
|
142
143
|
end
|
|
143
144
|
|
|
144
145
|
# @param url [String]
|
|
145
|
-
# @param resource [Asana::Resources::
|
|
146
|
+
# @param resource [Asana::Resources::Task]
|
|
146
147
|
# @param attachment_name [String,nil]
|
|
147
148
|
#
|
|
148
149
|
# @return [Asana::Resources::Attachment]
|
|
149
150
|
def create_attachment_from_url_alone!(url, resource, attachment_name:)
|
|
150
151
|
with_params = {
|
|
151
|
-
# @sg-ignore
|
|
152
152
|
'parent' => resource.gid,
|
|
153
153
|
'url' => url,
|
|
154
154
|
'resource_subtype' => 'external',
|
|
@@ -196,7 +196,8 @@ module Checkoff
|
|
|
196
196
|
tasks = Checkoff::Tasks.new
|
|
197
197
|
attachments = Checkoff::Attachments.new
|
|
198
198
|
task = tasks.task_by_gid(gid)
|
|
199
|
-
# @sg-ignore
|
|
199
|
+
# @sg-ignore task_by_gid can return nil; needs a raise-if-nil guard, deferred to a
|
|
200
|
+
# follow-up code PR
|
|
200
201
|
attachment = attachments.create_attachment_from_url!(url, task)
|
|
201
202
|
puts "Results: #{attachment.inspect}"
|
|
202
203
|
end
|
data/lib/checkoff/cli.rb
CHANGED
|
@@ -29,7 +29,6 @@ module Checkoff
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
@from_workspace_name = from_workspace_arg
|
|
32
|
-
# @sg-ignore
|
|
33
32
|
@from_project_name = project_arg_to_name(from_project_arg)
|
|
34
33
|
@from_section_name = from_section_arg
|
|
35
34
|
end
|
|
@@ -41,7 +40,6 @@ module Checkoff
|
|
|
41
40
|
if to_project_arg == :source_project
|
|
42
41
|
from_project_name
|
|
43
42
|
else
|
|
44
|
-
# @sg-ignore
|
|
45
43
|
project_arg_to_name(to_project_arg)
|
|
46
44
|
end
|
|
47
45
|
end
|
|
@@ -146,7 +144,7 @@ module Checkoff
|
|
|
146
144
|
:to_workspace_name, :to_project_name, :to_section_name,
|
|
147
145
|
:projects, :sections
|
|
148
146
|
|
|
149
|
-
# @param project_arg [String]
|
|
147
|
+
# @param project_arg [Symbol, String]
|
|
150
148
|
# @return [Symbol, String]
|
|
151
149
|
def project_arg_to_name(project_arg)
|
|
152
150
|
arg = project_arg.to_s
|
|
@@ -194,7 +192,7 @@ module Checkoff
|
|
|
194
192
|
elsif task_name.nil?
|
|
195
193
|
run_on_section(workspace_name, project_name, section_name)
|
|
196
194
|
else
|
|
197
|
-
# @sg-ignore
|
|
195
|
+
# @sg-ignore task_name.nil? above isn't inferred as narrowing the task_name accessor's return
|
|
198
196
|
run_on_task(workspace_name, project_name, section_name, task_name)
|
|
199
197
|
end
|
|
200
198
|
end
|
|
@@ -218,7 +216,6 @@ module Checkoff
|
|
|
218
216
|
# @return [String]
|
|
219
217
|
def run_on_project(workspace, project)
|
|
220
218
|
tasks_by_section =
|
|
221
|
-
# @sg-ignore
|
|
222
219
|
sections.tasks_by_section(workspace, project)
|
|
223
220
|
tasks_by_section.update(tasks_by_section) do |_key, tasks|
|
|
224
221
|
tasks_to_hash(tasks)
|
|
@@ -315,7 +312,7 @@ module Checkoff
|
|
|
315
312
|
arg 'workspace'
|
|
316
313
|
arg 'task_name'
|
|
317
314
|
command :quickadd do |c|
|
|
318
|
-
# @sg-ignore
|
|
315
|
+
# @sg-ignore GLI's DSL block methods (c.flag/c.action) aren't resolved
|
|
319
316
|
c.action do |_global_options, _options, args|
|
|
320
317
|
workspace_name = args.fetch(0)
|
|
321
318
|
task_name = args.fetch(1)
|
|
@@ -330,7 +327,7 @@ module Checkoff
|
|
|
330
327
|
arg 'section', :optional
|
|
331
328
|
arg 'task_name', :optional
|
|
332
329
|
command :view do |c|
|
|
333
|
-
# @sg-ignore
|
|
330
|
+
# @sg-ignore GLI's DSL block methods (c.flag/c.action) aren't resolved
|
|
334
331
|
c.action do |_global_options, _options, args|
|
|
335
332
|
workspace_name = args.fetch(0)
|
|
336
333
|
project_name = args.fetch(1)
|
|
@@ -345,37 +342,37 @@ module Checkoff
|
|
|
345
342
|
|
|
346
343
|
# rubocop:disable Metrics/BlockLength
|
|
347
344
|
command :mv do |c|
|
|
348
|
-
# @sg-ignore
|
|
345
|
+
# @sg-ignore GLI's DSL block methods (c.flag/c.action) aren't resolved
|
|
349
346
|
c.flag :from_workspace,
|
|
350
347
|
type: String,
|
|
351
348
|
default_value: :default_workspace,
|
|
352
349
|
desc: 'Workspace to move tasks from'
|
|
353
|
-
# @sg-ignore
|
|
350
|
+
# @sg-ignore GLI's DSL block methods (c.flag/c.action) aren't resolved
|
|
354
351
|
c.flag :from_project,
|
|
355
352
|
type: String,
|
|
356
353
|
required: true,
|
|
357
354
|
desc: 'Project to move tasks from'
|
|
358
|
-
# @sg-ignore
|
|
355
|
+
# @sg-ignore GLI's DSL block methods (c.flag/c.action) aren't resolved
|
|
359
356
|
c.flag :from_section,
|
|
360
357
|
type: String,
|
|
361
358
|
default_value: :all_sections,
|
|
362
359
|
desc: 'Section to move tasks from'
|
|
363
|
-
# @sg-ignore
|
|
360
|
+
# @sg-ignore GLI's DSL block methods (c.flag/c.action) aren't resolved
|
|
364
361
|
c.flag :to_workspace,
|
|
365
362
|
type: String,
|
|
366
363
|
default_value: :source_workspace,
|
|
367
364
|
desc: 'Workspace to move tasks to'
|
|
368
|
-
# @sg-ignore
|
|
365
|
+
# @sg-ignore GLI's DSL block methods (c.flag/c.action) aren't resolved
|
|
369
366
|
c.flag :to_project,
|
|
370
367
|
type: String,
|
|
371
368
|
default_value: :source_project,
|
|
372
369
|
desc: 'Section to move tasks to'
|
|
373
|
-
# @sg-ignore
|
|
370
|
+
# @sg-ignore GLI's DSL block methods (c.flag/c.action) aren't resolved
|
|
374
371
|
c.flag :to_section,
|
|
375
372
|
type: String,
|
|
376
373
|
default_value: :source_section,
|
|
377
374
|
desc: 'Section to move tasks to'
|
|
378
|
-
# @sg-ignore
|
|
375
|
+
# @sg-ignore GLI's DSL block methods (c.flag/c.action) aren't resolved
|
|
379
376
|
c.action do |_global_options, options, _args|
|
|
380
377
|
from_workspace = options.fetch('from_workspace')
|
|
381
378
|
from_project = options.fetch('from_project')
|
data/lib/checkoff/clients.rb
CHANGED
|
@@ -30,9 +30,9 @@ module Checkoff
|
|
|
30
30
|
# @return [Asana::Client]
|
|
31
31
|
def client
|
|
32
32
|
@client ||= @asana_client_class.new do |c|
|
|
33
|
-
# @sg-ignore
|
|
33
|
+
# @sg-ignore Unresolved call to authentication — gem config DSL block, not covered by annotations
|
|
34
34
|
c.authentication :access_token, @config.fetch(:personal_access_token)
|
|
35
|
-
# @sg-ignore
|
|
35
|
+
# @sg-ignore Unresolved call to default_headers — gem config DSL block, not covered by annotations
|
|
36
36
|
c.default_headers 'asana-enable' =>
|
|
37
37
|
'new_project_templates,new_user_task_lists,new_memberships,new_goal_memberships'
|
|
38
38
|
end
|
|
@@ -41,7 +41,7 @@ module Checkoff
|
|
|
41
41
|
# @param custom_field_name [String]
|
|
42
42
|
#
|
|
43
43
|
# @return [Asana::Resources::CustomField]
|
|
44
|
-
# @sg-ignore
|
|
44
|
+
# @sg-ignore nil check above is not flow-sensitive
|
|
45
45
|
def custom_field_or_raise(workspace_name, custom_field_name)
|
|
46
46
|
cf = custom_field(workspace_name, custom_field_name)
|
|
47
47
|
raise "Could not find custom_field #{custom_field_name} under workspace #{workspace_name}." if cf.nil?
|
|
@@ -78,8 +78,10 @@ module Checkoff
|
|
|
78
78
|
|
|
79
79
|
# @param resource [Asana::Resources::Project,Asana::Resources::Task]
|
|
80
80
|
# @param custom_field_name [String]
|
|
81
|
-
# @sg-ignore
|
|
82
81
|
# @return [Array<String>]
|
|
82
|
+
# @sg-ignore Declared return type Array<String> does not match inferred type Array,Array<Array> —
|
|
83
|
+
# fixing cleanly needs binding enum_value.fetch('name') to a typed local; leaving for a
|
|
84
|
+
# follow-up code PR to keep this one annotation-only.
|
|
83
85
|
def resource_custom_field_values_names_by_name(resource, custom_field_name)
|
|
84
86
|
custom_field = resource_custom_field_by_name(resource, custom_field_name)
|
|
85
87
|
return [] if custom_field.nil?
|
|
@@ -108,9 +110,9 @@ module Checkoff
|
|
|
108
110
|
end
|
|
109
111
|
|
|
110
112
|
# @param resource [Asana::Resources::Task,Asana::Resources::Project]
|
|
111
|
-
# @sg-ignore
|
|
112
113
|
# @param custom_field_name [String]
|
|
113
114
|
# @return [Hash]
|
|
115
|
+
# @sg-ignore nil check above is not flow-sensitive
|
|
114
116
|
def resource_custom_field_by_name_or_raise(resource, custom_field_name)
|
|
115
117
|
custom_field = resource_custom_field_by_name(resource, custom_field_name)
|
|
116
118
|
if custom_field.nil?
|
|
@@ -120,10 +122,10 @@ module Checkoff
|
|
|
120
122
|
custom_field
|
|
121
123
|
end
|
|
122
124
|
|
|
123
|
-
# @sg-ignore
|
|
124
125
|
# @param resource [Asana::Resources::Project,Asana::Resources::Task]
|
|
125
126
|
# @param custom_field_gid [String]
|
|
126
127
|
# @return [Hash]
|
|
128
|
+
# @sg-ignore nil check above is not flow-sensitive
|
|
127
129
|
def resource_custom_field_by_gid_or_raise(resource, custom_field_gid)
|
|
128
130
|
# @type [Array<Hash>]
|
|
129
131
|
custom_fields = resource.custom_fields
|
|
@@ -146,15 +148,15 @@ module Checkoff
|
|
|
146
148
|
# @param custom_field [Hash{String => Hash,Array<Hash>}]
|
|
147
149
|
#
|
|
148
150
|
# @return [Array<Hash>]
|
|
149
|
-
# @sg-ignore
|
|
151
|
+
# @sg-ignore Declared return type Array<Hash> does not match inferred type Array,Hash,Array<Hash> —
|
|
152
|
+
# fixing cleanly needs restructuring the case/when to bind each branch to a typed local; leaving
|
|
153
|
+
# for a follow-up code PR to keep this one annotation-only.
|
|
150
154
|
def resource_custom_field_enum_values(custom_field)
|
|
151
155
|
resource_subtype = custom_field.fetch('resource_subtype')
|
|
152
156
|
case resource_subtype
|
|
153
157
|
when 'enum'
|
|
154
|
-
# @type [Array<Hash>]
|
|
155
158
|
[custom_field.fetch('enum_value')]
|
|
156
159
|
when 'multi_enum'
|
|
157
|
-
# @type [Array<Hash>]
|
|
158
160
|
custom_field.fetch('multi_enum_values')
|
|
159
161
|
else
|
|
160
162
|
raise "Teach me how to handle resource_subtype #{resource_subtype}"
|
|
@@ -74,9 +74,11 @@ module Checkoff
|
|
|
74
74
|
end
|
|
75
75
|
resource = webhook_subscription&.fetch('resource', nil)
|
|
76
76
|
name, resource_type = enrich_gid(resource) if resource
|
|
77
|
-
# @sg-ignore
|
|
77
|
+
# @sg-ignore webhook_subscription is declared [Hash, nil] but this line assumes non-nil
|
|
78
|
+
# without the &. used elsewhere in this method — looks like a real nil-safety gap, not
|
|
79
|
+
# just a typing gap; flagging for the follow-up code PR rather than silently widening
|
|
78
80
|
webhook_subscription['checkoff:enriched:name'] = name if name
|
|
79
|
-
# @sg-ignore
|
|
81
|
+
# @sg-ignore same nil-safety gap as above
|
|
80
82
|
webhook_subscription['checkoff:enriched:resource_type'] = resource_type if resource_type
|
|
81
83
|
end
|
|
82
84
|
|
|
@@ -96,13 +98,11 @@ module Checkoff
|
|
|
96
98
|
|
|
97
99
|
# @param filter [Hash{String => String, Array<String>}]
|
|
98
100
|
#
|
|
99
|
-
# @
|
|
100
|
-
# @return [String, nil]
|
|
101
|
+
# @return [void]
|
|
101
102
|
def enrich_filter_parent_gid!(filter)
|
|
102
|
-
parent_gid = filter['checkoff:parent.gid']
|
|
103
|
+
parent_gid = T.cast(filter['checkoff:parent.gid'], T.nilable(String))
|
|
103
104
|
return unless parent_gid
|
|
104
105
|
|
|
105
|
-
# @sg-ignore
|
|
106
106
|
name, resource_type = enrich_gid(parent_gid)
|
|
107
107
|
filter['checkoff:enriched:parent.name'] = name if name
|
|
108
108
|
filter['checkoff:enriched:parent.resource_type'] = resource_type if resource_type
|
|
@@ -112,11 +112,10 @@ module Checkoff
|
|
|
112
112
|
#
|
|
113
113
|
# @return [void]
|
|
114
114
|
def enrich_filter_resource!(filter)
|
|
115
|
-
resource_gid = filter['checkoff:resource.gid']
|
|
115
|
+
resource_gid = T.cast(filter['checkoff:resource.gid'], T.nilable(String))
|
|
116
116
|
|
|
117
117
|
return unless resource_gid
|
|
118
118
|
|
|
119
|
-
# @sg-ignore
|
|
120
119
|
task = tasks.task_by_gid(resource_gid)
|
|
121
120
|
task_name = task&.name
|
|
122
121
|
filter['checkoff:enriched:resource.name'] = task_name if task_name
|
|
@@ -134,19 +133,22 @@ module Checkoff
|
|
|
134
133
|
filter['checkoff:enriched:fetched.section.name'] = name if name
|
|
135
134
|
end
|
|
136
135
|
|
|
137
|
-
# @param asana_event [Hash
|
|
136
|
+
# @param asana_event [Hash]
|
|
138
137
|
#
|
|
139
138
|
# @return [void]
|
|
140
139
|
def enrich_event_parent!(asana_event)
|
|
141
140
|
# @type [Hash{String => String }]
|
|
142
|
-
# @sg-ignore
|
|
143
141
|
parent = asana_event['parent']
|
|
144
142
|
|
|
145
143
|
return unless parent
|
|
146
144
|
|
|
147
145
|
# @type [String]
|
|
146
|
+
# @sg-ignore Hash#fetch generic<X> leak on rbs >= 4.1.0, fix in progress upstream
|
|
147
|
+
# https://github.com/castwide/solargraph/pull/1228
|
|
148
148
|
resource_type = parent.fetch('resource_type')
|
|
149
149
|
# @type [String]
|
|
150
|
+
# @sg-ignore Hash#fetch generic<X> leak on rbs >= 4.1.0, fix in progress upstream
|
|
151
|
+
# https://github.com/castwide/solargraph/pull/1228
|
|
150
152
|
gid = parent.fetch('gid')
|
|
151
153
|
name, _resource_type = enrich_gid(gid, resource_type:)
|
|
152
154
|
parent['checkoff:enriched:name'] = name if name
|
|
@@ -154,16 +156,20 @@ module Checkoff
|
|
|
154
156
|
nil
|
|
155
157
|
end
|
|
156
158
|
|
|
157
|
-
# @param asana_event [Hash
|
|
159
|
+
# @param asana_event [Hash]
|
|
158
160
|
#
|
|
159
161
|
# @return [void]
|
|
160
162
|
def enrich_event_resource!(asana_event)
|
|
161
163
|
# @type [Hash{String => String}]
|
|
162
164
|
resource = T.cast(asana_event['resource'], T::Hash[String, String])
|
|
163
165
|
# @type [String]
|
|
166
|
+
# @sg-ignore Hash#fetch generic<X> leak on rbs >= 4.1.0, fix in progress upstream
|
|
167
|
+
# https://github.com/castwide/solargraph/pull/1228
|
|
164
168
|
resource_type = resource.fetch('resource_type')
|
|
165
169
|
|
|
166
170
|
# @type [String]
|
|
171
|
+
# @sg-ignore Hash#fetch generic<X> leak on rbs >= 4.1.0, fix in progress upstream
|
|
172
|
+
# https://github.com/castwide/solargraph/pull/1228
|
|
167
173
|
gid = resource.fetch('gid')
|
|
168
174
|
|
|
169
175
|
name, _resource_type = enrich_gid(gid, resource_type:)
|
|
@@ -122,6 +122,8 @@ module Checkoff
|
|
|
122
122
|
# @type [Hash{String => String}]
|
|
123
123
|
resource = asana_event.fetch('resource')
|
|
124
124
|
# @type [String]
|
|
125
|
+
# @sg-ignore Hash#fetch generic<X> leak on rbs >= 4.1.0, fix in progress upstream
|
|
126
|
+
# https://github.com/castwide/solargraph/pull/1228
|
|
125
127
|
resource_type = resource.fetch('resource_type')
|
|
126
128
|
unless resource_type == 'task'
|
|
127
129
|
raise "Teach me how to check #{key.inspect} on resource type #{resource_type.inspect}"
|
|
@@ -131,6 +133,8 @@ module Checkoff
|
|
|
131
133
|
options = {
|
|
132
134
|
fields:,
|
|
133
135
|
}
|
|
136
|
+
# @sg-ignore Hash#fetch generic<X> leak on rbs >= 4.1.0, fix in progress upstream
|
|
137
|
+
# https://github.com/castwide/solargraph/pull/1228
|
|
134
138
|
@client.tasks.find_by_id(task_gid, options:)
|
|
135
139
|
rescue Asana::Errors::NotFound
|
|
136
140
|
nil
|
|
@@ -20,12 +20,12 @@ module Checkoff
|
|
|
20
20
|
|
|
21
21
|
# @param key [Symbol]
|
|
22
22
|
# @return [Object]
|
|
23
|
-
# @sg-ignore
|
|
23
|
+
# @sg-ignore return type could not be inferred — cascades from the ENV.fetch RBS gap below
|
|
24
24
|
def [](key)
|
|
25
25
|
config_value = @config[key]
|
|
26
26
|
return config_value unless config_value.nil?
|
|
27
27
|
|
|
28
|
-
# @sg-ignore
|
|
28
|
+
# @sg-ignore Unresolved call to fetch on RBS::Unnamed::ENVClass, Class<ENV>
|
|
29
29
|
ENV.fetch(envvar_name(key), nil)
|
|
30
30
|
end
|
|
31
31
|
|
|
@@ -57,10 +57,10 @@ module Logging
|
|
|
57
57
|
private
|
|
58
58
|
|
|
59
59
|
# @return [Symbol]
|
|
60
|
-
# @sg-ignore
|
|
60
|
+
# @sg-ignore return type could not be inferred — cascades from the ENV.fetch RBS gap below
|
|
61
61
|
def log_level
|
|
62
|
-
# @sg-ignore
|
|
63
62
|
# rubocop:disable Style/RedundantFetchBlock
|
|
63
|
+
# @sg-ignore Unresolved call to fetch on RBS::Unnamed::ENVClass, Class<ENV>
|
|
64
64
|
ENV.fetch('LOG_LEVEL') { 'INFO' }.downcase.to_sym
|
|
65
65
|
# rubocop:enable Style/RedundantFetchBlock
|
|
66
66
|
end
|
|
@@ -59,19 +59,20 @@ module Checkoff
|
|
|
59
59
|
# @param gid [String]
|
|
60
60
|
# @param single_custom_field_params [Hash{String => Array<String>}]
|
|
61
61
|
# @return [Array(Hash{String => String}, Array<Symbol, Array>)]
|
|
62
|
-
# @sg-ignore
|
|
62
|
+
# @sg-ignore `unless variant_class.nil?` return value isn't inferred as the declared tuple type
|
|
63
63
|
def convert_single_custom_field_params(gid, single_custom_field_params)
|
|
64
64
|
variant_key = "custom_field_#{gid}.variant"
|
|
65
65
|
variant = single_custom_field_params.fetch(variant_key)
|
|
66
66
|
remaining_params = single_custom_field_params.reject { |k, _v| k == variant_key }
|
|
67
|
+
# @sg-ignore Hash#fetch generic<X> leak on rbs >= 4.1.0, fix in progress upstream
|
|
68
|
+
# https://github.com/castwide/solargraph/pull/1228
|
|
67
69
|
raise "Teach me how to handle #{variant_key} = #{variant}" unless variant.length == 1
|
|
68
70
|
|
|
69
|
-
# @
|
|
70
|
-
# @
|
|
71
|
-
# @sg-ignore
|
|
71
|
+
# @type [Class<CustomFieldVariant>, nil]
|
|
72
|
+
# @sg-ignore variant.length == 1 guard above isn't inferred as narrowing variant[0] to non-nil
|
|
72
73
|
variant_class = VARIANTS[variant[0]]
|
|
73
74
|
# @type [Array(Hash{String => String}, Array<Symbol, Array>)]
|
|
74
|
-
# @sg-ignore
|
|
75
|
+
# @sg-ignore `unless variant_class.nil?` isn't inferred as narrowing the receiver in the same statement
|
|
75
76
|
return variant_class.new(gid, remaining_params).convert unless variant_class.nil?
|
|
76
77
|
|
|
77
78
|
raise "Teach me how to handle #{variant_key} = #{variant}"
|
|
@@ -79,9 +80,9 @@ module Checkoff
|
|
|
79
80
|
|
|
80
81
|
# @param key [String]
|
|
81
82
|
# @return [String]
|
|
82
|
-
# @sg-ignore
|
|
83
|
+
# @sg-ignore split(...)[n]'s nilable Array indexing isn't inferred as the declared String return
|
|
83
84
|
def gid_from_custom_field_key(key)
|
|
84
|
-
# @sg-ignore
|
|
85
|
+
# @sg-ignore split(...)[n] is nilable Array indexing; key's shape guarantees enough parts here
|
|
85
86
|
key.split('_')[2].split('.')[0]
|
|
86
87
|
end
|
|
87
88
|
|
|
@@ -37,6 +37,8 @@ module Checkoff
|
|
|
37
37
|
case remaining_params.keys
|
|
38
38
|
when [param_name]
|
|
39
39
|
# @type param_values [Array<String>]
|
|
40
|
+
# @sg-ignore Hash#fetch generic<X> leak on rbs >= 4.1.0, fix in progress upstream
|
|
41
|
+
# https://github.com/castwide/solargraph/pull/1228
|
|
40
42
|
param_values = remaining_params.fetch(param_name)
|
|
41
43
|
unless param_values.length == 1
|
|
42
44
|
raise "Teach me how to handle these remaining keys for #{param_name}: #{remaining_params}"
|
|
@@ -15,7 +15,7 @@ module Checkoff
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
# @return [Array(Hash{String => String}, Array<Symbol, Array>)]
|
|
18
|
-
# @sg-ignore
|
|
18
|
+
# @sg-ignore out can genuinely be nil if none of the 3 known prefixes matched; relies on the raise above it
|
|
19
19
|
def convert
|
|
20
20
|
return [{}, []] if date_url_params.empty?
|
|
21
21
|
|
|
@@ -129,15 +129,19 @@ module Checkoff
|
|
|
129
129
|
end
|
|
130
130
|
|
|
131
131
|
# @param param_key [String]
|
|
132
|
-
# @sg-ignore
|
|
133
132
|
# @return [String]
|
|
133
|
+
# @sg-ignore value.length == 1 guard above isn't inferred as narrowing value[0] to non-nil
|
|
134
134
|
def get_single_param(param_key)
|
|
135
135
|
raise "Expected #{param_key} to have at least one value" unless date_url_params.key? param_key
|
|
136
136
|
|
|
137
137
|
value = date_url_params.fetch(param_key)
|
|
138
138
|
|
|
139
|
+
# @sg-ignore Hash#fetch generic<X> leak on rbs >= 4.1.0, fix in progress upstream
|
|
140
|
+
# https://github.com/castwide/solargraph/pull/1228
|
|
139
141
|
raise "Expected #{param_key} to have one value" if value.length != 1
|
|
140
142
|
|
|
143
|
+
# @sg-ignore Hash#fetch generic<X> leak on rbs >= 4.1.0, fix in progress upstream
|
|
144
|
+
# https://github.com/castwide/solargraph/pull/1228
|
|
141
145
|
value[0]
|
|
142
146
|
end
|
|
143
147
|
|
|
@@ -154,6 +158,8 @@ module Checkoff
|
|
|
154
158
|
def validate_unit_is_day!(prefix)
|
|
155
159
|
unit = date_url_params.fetch("#{prefix}.unit").fetch(0)
|
|
156
160
|
|
|
161
|
+
# @sg-ignore Hash#fetch generic<X> leak on rbs >= 4.1.0, fix in progress upstream
|
|
162
|
+
# https://github.com/castwide/solargraph/pull/1228
|
|
157
163
|
raise "Teach me how to handle other time units: #{unit}" unless unit == 'day'
|
|
158
164
|
end
|
|
159
165
|
|
|
@@ -24,9 +24,10 @@ module Checkoff
|
|
|
24
24
|
# @param url [String]
|
|
25
25
|
# @return [Array(Hash{String => String}, Array)]
|
|
26
26
|
def convert_params(url)
|
|
27
|
-
# @sg-ignore
|
|
27
|
+
# @sg-ignore URI#query can be nil for a URL with no query string; CGI.parse expects
|
|
28
|
+
# String — looks like a real gap (unhandled no-query-string case), not just a typing
|
|
29
|
+
# gap, flagging for the follow-up code PR rather than silently asserting non-nil
|
|
28
30
|
url_params = CGI.parse(URI.parse(url).query)
|
|
29
|
-
# @sg-ignore
|
|
30
31
|
custom_field_params, date_url_params, simple_url_params = partition_url_params(url_params)
|
|
31
32
|
custom_field_args, custom_field_task_selector = convert_custom_field_params(custom_field_params)
|
|
32
33
|
date_url_args, date_task_selector = convert_date_params(date_url_params)
|
|
@@ -56,14 +57,15 @@ module Checkoff
|
|
|
56
57
|
CustomFieldParamConverter.new(custom_field_params:).convert
|
|
57
58
|
end
|
|
58
59
|
|
|
59
|
-
# @param url_params [Hash{String => String}]
|
|
60
|
+
# @param url_params [Hash{String => Array<String>}]
|
|
60
61
|
# @return [Array(Hash{String => Array<String>}, Hash{String => Array<String>}, Hash{String => Array<String>})]
|
|
61
62
|
def partition_url_params(url_params)
|
|
62
63
|
groups = T.let(url_params.to_a.group_by do |key, _values|
|
|
63
|
-
# @sg-ignore
|
|
64
|
+
# @sg-ignore Unresolved call to start_with? — T.let wrapping this
|
|
65
|
+
# chained group_by block seems to block block-param inference
|
|
64
66
|
if key.start_with? 'custom_field_'
|
|
65
67
|
:custom_field
|
|
66
|
-
# @sg-ignore
|
|
68
|
+
# @sg-ignore Unresolved call to include? — same T.let/block-param gap
|
|
67
69
|
elsif key.include? '_date'
|
|
68
70
|
:date
|
|
69
71
|
else
|
|
@@ -17,8 +17,7 @@ module Checkoff
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
# @param task_selectors [Array<Symbol, Array>]
|
|
20
|
-
# @return [Array(Symbol, Array, Array)]
|
|
21
|
-
# @sg-ignore
|
|
20
|
+
# @return [Symbol, Array, Array(Symbol, Array, Array)]
|
|
22
21
|
def self.merge_task_selectors(*task_selectors)
|
|
23
22
|
return [] if task_selectors.empty?
|
|
24
23
|
|
|
@@ -31,6 +31,16 @@ module Checkoff
|
|
|
31
31
|
end
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
+
public
|
|
35
|
+
|
|
36
|
+
# @return [Array<String>]
|
|
37
|
+
# @sg-ignore abstract method always raises; declared type documents the override contract, not this body
|
|
38
|
+
def convert
|
|
39
|
+
raise 'Implement me!'
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
34
44
|
# @return [String]
|
|
35
45
|
attr_reader :key
|
|
36
46
|
|
|
@@ -226,7 +236,6 @@ module Checkoff
|
|
|
226
236
|
# @return [Hash{String => String}] the converted params
|
|
227
237
|
def convert
|
|
228
238
|
# @type [Array<Array(String, String)>]
|
|
229
|
-
# @sg-ignore
|
|
230
239
|
arr_of_tuples = simple_url_params.to_a.flat_map do |key, values|
|
|
231
240
|
# @type
|
|
232
241
|
entry = convert_arg(key, values).each_slice(2).to_a
|
|
@@ -265,14 +274,14 @@ module Checkoff
|
|
|
265
274
|
# https://developers.asana.com/docs/search-tasks-in-a-workspace
|
|
266
275
|
# @param key [String] the name of the search url param
|
|
267
276
|
# @param values [Array<String>] the values of the search url param
|
|
268
|
-
# @
|
|
269
|
-
# @return [Hash{String => String}] the converted params
|
|
277
|
+
# @return [Array<String>] the converted params, as an alternating key/value flat array
|
|
270
278
|
def convert_arg(key, values)
|
|
271
279
|
# @type [Class<SimpleParam::SimpleParam>]
|
|
280
|
+
# @sg-ignore Hash#fetch generic<X> leak on rbs >= 4.1.0, fix in progress upstream
|
|
281
|
+
# https://github.com/castwide/solargraph/pull/1228
|
|
272
282
|
clazz = ARGS.fetch(key)
|
|
273
283
|
# @type [SimpleParam::SimpleParam]
|
|
274
284
|
obj = clazz.new(key:, values:)
|
|
275
|
-
# @sg-ignore
|
|
276
285
|
obj.convert
|
|
277
286
|
end
|
|
278
287
|
|