checkoff 0.258.0 → 0.260.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 +14 -15
- data/lib/checkoff/cli.rb +7 -12
- data/lib/checkoff/clients.rb +0 -2
- data/lib/checkoff/custom_fields.rb +13 -24
- data/lib/checkoff/internal/asana_event_enrichment.rb +11 -21
- data/lib/checkoff/internal/asana_event_filter.rb +1 -5
- data/lib/checkoff/internal/config_loader.rb +0 -2
- data/lib/checkoff/internal/logging.rb +0 -2
- data/lib/checkoff/internal/project_hashes.rb +5 -4
- data/lib/checkoff/internal/search_url/custom_field_param_converter.rb +9 -10
- data/lib/checkoff/internal/search_url/custom_field_variant.rb +7 -2
- data/lib/checkoff/internal/search_url/date_param_converter.rb +13 -10
- data/lib/checkoff/internal/search_url/parser.rb +2 -7
- data/lib/checkoff/internal/search_url/simple_param_converter.rb +1 -4
- data/lib/checkoff/internal/section_selector_evaluator.rb +1 -1
- data/lib/checkoff/internal/selector_classes/common/function_evaluator.rb +2 -2
- data/lib/checkoff/internal/selector_classes/common.rb +2 -3
- data/lib/checkoff/internal/selector_classes/function_evaluator.rb +9 -4
- data/lib/checkoff/internal/selector_classes/project/function_evaluator.rb +2 -2
- data/lib/checkoff/internal/selector_classes/project.rb +0 -1
- data/lib/checkoff/internal/selector_classes/section/function_evaluator.rb +2 -2
- data/lib/checkoff/internal/selector_classes/section.rb +1 -2
- data/lib/checkoff/internal/selector_classes/task/function_evaluator.rb +2 -2
- data/lib/checkoff/internal/selector_classes/task.rb +2 -26
- data/lib/checkoff/internal/selector_evaluator.rb +6 -5
- data/lib/checkoff/internal/task_hashes.rb +17 -9
- data/lib/checkoff/internal/task_timing.rb +0 -4
- data/lib/checkoff/internal/thread_local.rb +0 -2
- data/lib/checkoff/monkeypatches/resource_marshalling.rb +3 -3
- data/lib/checkoff/my_tasks.rb +1 -4
- data/lib/checkoff/portfolios.rb +0 -1
- data/lib/checkoff/project_selectors.rb +1 -1
- data/lib/checkoff/projects.rb +19 -8
- data/lib/checkoff/resources.rb +14 -3
- data/lib/checkoff/sections.rb +9 -9
- data/lib/checkoff/subtasks.rb +1 -2
- data/lib/checkoff/tags.rb +3 -4
- data/lib/checkoff/task_searches.rb +1 -8
- data/lib/checkoff/task_selectors.rb +25 -12
- data/lib/checkoff/tasks.rb +6 -14
- data/lib/checkoff/timelines.rb +3 -20
- data/lib/checkoff/timing.rb +1 -2
- data/lib/checkoff/version.rb +1 -1
- data/lib/checkoff/workspaces.rb +1 -7
- data/rbi/checkoff.rbi +92 -146
- data/sig/checkoff.rbs +79 -153
- 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: e08117848a46a27ffee42a7936ada4febefdda2c2d9a44ae0160dcdfa89989b8
|
|
4
|
+
data.tar.gz: a8573c8961ab241c73425008c5c9a44f03c6038a4a3ad791b3154b505cd4ee22
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 43b8c4f4ff4d1fcd48a98d0fe2b7fdc6332ab29e83b81f2dad3a9a9ec3628f3c106c4ea518ae81b0e9edc882bf9618396b547c099e6dc1fb22f76d5c91ed6cd5
|
|
7
|
+
data.tar.gz: 2da763b8482d3e7a6f7e8fe8b912ef2c8175d6843da3019fc10a7aae9ea94d3978a9ed789763f5fee8d7755200f80bd04268b332ab74b2865fd6303823c99e34
|
data/lib/checkoff/attachments.rb
CHANGED
|
@@ -85,9 +85,10 @@ module Checkoff
|
|
|
85
85
|
# @return [Object]
|
|
86
86
|
def download_uri(uri, verify_mode: OpenSSL::SSL::VERIFY_PEER, &block)
|
|
87
87
|
out = nil
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
#
|
|
88
|
+
host = uri.host || raise("URI has no host: #{uri}")
|
|
89
|
+
Net::HTTP.start(host, uri.port, use_ssl: uri.scheme == 'https', verify_mode:) do |http|
|
|
90
|
+
# @sg-ignore tool-limitation:pr-1290-follow-up
|
|
91
|
+
# https://github.com/castwide/solargraph/pull/1290#issuecomment-5272957964
|
|
91
92
|
http.request(Net::HTTP::Get.new(uri)) do |response|
|
|
92
93
|
raise("Unexpected response code: #{response.code}") unless response.code == '200'
|
|
93
94
|
|
|
@@ -108,7 +109,6 @@ module Checkoff
|
|
|
108
109
|
def write_tempfile_from_response(response)
|
|
109
110
|
Tempfile.create('checkoff') do |tempfile|
|
|
110
111
|
tempfile.binmode
|
|
111
|
-
# @sg-ignore Unresolved call to read_body on #read_body
|
|
112
112
|
response.read_body do |chunk|
|
|
113
113
|
tempfile.write(chunk)
|
|
114
114
|
end
|
|
@@ -128,16 +128,15 @@ module Checkoff
|
|
|
128
128
|
def create_attachment_from_downloaded_url!(url, resource, attachment_name:,
|
|
129
129
|
verify_mode: OpenSSL::SSL::VERIFY_PEER)
|
|
130
130
|
uri = URI(url)
|
|
131
|
-
|
|
131
|
+
# @type [String]
|
|
132
|
+
resolved_attachment_name = attachment_name || File.basename(uri.path || '')
|
|
132
133
|
download_uri(uri, verify_mode:) do |tempfile|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
# @sg-ignore same attachment_name/content_type narrowing gap as above
|
|
140
|
-
resource.attach(filename: attachment_name, mime: content_type,
|
|
134
|
+
content_type = content_type_from_filename(resolved_attachment_name)
|
|
135
|
+
content_type ||= content_type_from_filename(uri.path || '')
|
|
136
|
+
# neither the attachment name nor the URL's path has a MIME-recognizable extension
|
|
137
|
+
content_type ||= 'application/octet-stream'
|
|
138
|
+
|
|
139
|
+
resource.attach(filename: resolved_attachment_name, mime: content_type,
|
|
141
140
|
io: tempfile)
|
|
142
141
|
end
|
|
143
142
|
end
|
|
@@ -196,8 +195,8 @@ module Checkoff
|
|
|
196
195
|
tasks = Checkoff::Tasks.new
|
|
197
196
|
attachments = Checkoff::Attachments.new
|
|
198
197
|
task = tasks.task_by_gid(gid)
|
|
199
|
-
|
|
200
|
-
|
|
198
|
+
raise "Could not find task #{gid}" if task.nil?
|
|
199
|
+
|
|
201
200
|
attachment = attachments.create_attachment_from_url!(url, task)
|
|
202
201
|
puts "Results: #{attachment.inspect}"
|
|
203
202
|
end
|
data/lib/checkoff/cli.rb
CHANGED
|
@@ -161,7 +161,7 @@ module Checkoff
|
|
|
161
161
|
# @param workspace_name [String]
|
|
162
162
|
# @param project_name [String, Symbol]
|
|
163
163
|
# @param section_name [String, Symbol, nil]
|
|
164
|
-
# @param task_name [String,
|
|
164
|
+
# @param task_name [String, nil]
|
|
165
165
|
# @param config [Checkoff::Internal::EnvFallbackConfigLoader, Hash]
|
|
166
166
|
# @param projects [Checkoff::Projects]
|
|
167
167
|
# @param sections [Checkoff::Sections]
|
|
@@ -192,7 +192,6 @@ module Checkoff
|
|
|
192
192
|
elsif task_name.nil?
|
|
193
193
|
run_on_section(workspace_name, project_name, section_name)
|
|
194
194
|
else
|
|
195
|
-
# @sg-ignore task_name.nil? above isn't inferred as narrowing the task_name accessor's return
|
|
196
195
|
run_on_task(workspace_name, project_name, section_name, task_name)
|
|
197
196
|
end
|
|
198
197
|
end
|
|
@@ -243,7 +242,6 @@ module Checkoff
|
|
|
243
242
|
task = tasks.task(workspace.to_s, project, task_name, section_name: section)
|
|
244
243
|
raise "Task not found: #{task_name}" if task.nil?
|
|
245
244
|
|
|
246
|
-
# @sg-ignore nil check above is not flow-sensitive
|
|
247
245
|
task_to_hash(task).to_json
|
|
248
246
|
end
|
|
249
247
|
|
|
@@ -311,8 +309,9 @@ module Checkoff
|
|
|
311
309
|
desc 'Add a short task to Asana'
|
|
312
310
|
arg 'workspace'
|
|
313
311
|
arg 'task_name'
|
|
312
|
+
# @param c [GLI::Command]
|
|
314
313
|
command :quickadd do |c|
|
|
315
|
-
# @
|
|
314
|
+
# @param args [Array<String>]
|
|
316
315
|
c.action do |_global_options, _options, args|
|
|
317
316
|
workspace_name = args.fetch(0)
|
|
318
317
|
task_name = args.fetch(1)
|
|
@@ -326,8 +325,9 @@ module Checkoff
|
|
|
326
325
|
arg 'project'
|
|
327
326
|
arg 'section', :optional
|
|
328
327
|
arg 'task_name', :optional
|
|
328
|
+
# @param c [GLI::Command]
|
|
329
329
|
command :view do |c|
|
|
330
|
-
# @
|
|
330
|
+
# @param args [Array<String>]
|
|
331
331
|
c.action do |_global_options, _options, args|
|
|
332
332
|
workspace_name = args.fetch(0)
|
|
333
333
|
project_name = args.fetch(1)
|
|
@@ -341,38 +341,33 @@ module Checkoff
|
|
|
341
341
|
desc 'Move tasks from one section to another within a project'
|
|
342
342
|
|
|
343
343
|
# rubocop:disable Metrics/BlockLength
|
|
344
|
+
# @param c [GLI::Command]
|
|
344
345
|
command :mv do |c|
|
|
345
|
-
# @sg-ignore GLI's DSL block methods (c.flag/c.action) aren't resolved
|
|
346
346
|
c.flag :from_workspace,
|
|
347
347
|
type: String,
|
|
348
348
|
default_value: :default_workspace,
|
|
349
349
|
desc: 'Workspace to move tasks from'
|
|
350
|
-
# @sg-ignore GLI's DSL block methods (c.flag/c.action) aren't resolved
|
|
351
350
|
c.flag :from_project,
|
|
352
351
|
type: String,
|
|
353
352
|
required: true,
|
|
354
353
|
desc: 'Project to move tasks from'
|
|
355
|
-
# @sg-ignore GLI's DSL block methods (c.flag/c.action) aren't resolved
|
|
356
354
|
c.flag :from_section,
|
|
357
355
|
type: String,
|
|
358
356
|
default_value: :all_sections,
|
|
359
357
|
desc: 'Section to move tasks from'
|
|
360
|
-
# @sg-ignore GLI's DSL block methods (c.flag/c.action) aren't resolved
|
|
361
358
|
c.flag :to_workspace,
|
|
362
359
|
type: String,
|
|
363
360
|
default_value: :source_workspace,
|
|
364
361
|
desc: 'Workspace to move tasks to'
|
|
365
|
-
# @sg-ignore GLI's DSL block methods (c.flag/c.action) aren't resolved
|
|
366
362
|
c.flag :to_project,
|
|
367
363
|
type: String,
|
|
368
364
|
default_value: :source_project,
|
|
369
365
|
desc: 'Section to move tasks to'
|
|
370
|
-
# @sg-ignore GLI's DSL block methods (c.flag/c.action) aren't resolved
|
|
371
366
|
c.flag :to_section,
|
|
372
367
|
type: String,
|
|
373
368
|
default_value: :source_section,
|
|
374
369
|
desc: 'Section to move tasks to'
|
|
375
|
-
# @
|
|
370
|
+
# @param options [Hash]
|
|
376
371
|
c.action do |_global_options, options, _args|
|
|
377
372
|
from_workspace = options.fetch('from_workspace')
|
|
378
373
|
from_project = options.fetch('from_project')
|
data/lib/checkoff/clients.rb
CHANGED
|
@@ -30,9 +30,7 @@ module Checkoff
|
|
|
30
30
|
# @return [Asana::Client]
|
|
31
31
|
def client
|
|
32
32
|
@client ||= @asana_client_class.new do |c|
|
|
33
|
-
# @sg-ignore Unresolved call to authentication — gem config DSL block, not covered by annotations
|
|
34
33
|
c.authentication :access_token, @config.fetch(:personal_access_token)
|
|
35
|
-
# @sg-ignore Unresolved call to default_headers — gem config DSL block, not covered by annotations
|
|
36
34
|
c.default_headers 'asana-enable' =>
|
|
37
35
|
'new_project_templates,new_user_task_lists,new_memberships,new_goal_memberships'
|
|
38
36
|
end
|
|
@@ -41,7 +41,6 @@ module Checkoff
|
|
|
41
41
|
# @param custom_field_name [String]
|
|
42
42
|
#
|
|
43
43
|
# @return [Asana::Resources::CustomField]
|
|
44
|
-
# @sg-ignore nil check above is not flow-sensitive
|
|
45
44
|
def custom_field_or_raise(workspace_name, custom_field_name)
|
|
46
45
|
cf = custom_field(workspace_name, custom_field_name)
|
|
47
46
|
raise "Could not find custom_field #{custom_field_name} under workspace #{workspace_name}." if cf.nil?
|
|
@@ -79,40 +78,32 @@ module Checkoff
|
|
|
79
78
|
# @param resource [Asana::Resources::Project,Asana::Resources::Task]
|
|
80
79
|
# @param custom_field_name [String]
|
|
81
80
|
# @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.
|
|
85
81
|
def resource_custom_field_values_names_by_name(resource, custom_field_name)
|
|
86
82
|
custom_field = resource_custom_field_by_name(resource, custom_field_name)
|
|
87
83
|
return [] if custom_field.nil?
|
|
88
84
|
|
|
89
85
|
resource_custom_field_enum_values(custom_field).flat_map do |enum_value|
|
|
90
|
-
|
|
91
|
-
[]
|
|
92
|
-
else
|
|
93
|
-
[enum_value.fetch('name')]
|
|
94
|
-
end
|
|
86
|
+
[enum_value.fetch('name')]
|
|
95
87
|
end
|
|
96
88
|
end
|
|
97
89
|
|
|
98
90
|
# @param resource [Asana::Resources::Task,Asana::Resources::Project]
|
|
99
91
|
# @param custom_field_name [String]
|
|
100
|
-
# @return [Hash, nil]
|
|
92
|
+
# @return [Hash{String => Object}, nil]
|
|
101
93
|
def resource_custom_field_by_name(resource, custom_field_name)
|
|
102
|
-
# @type [Array<Hash>]
|
|
94
|
+
# @type [Array<Hash{String => Object}>]
|
|
103
95
|
custom_fields = resource.custom_fields
|
|
104
96
|
if custom_fields.nil?
|
|
105
97
|
raise "custom fields not found on resource - did you add 'custom_fields' in your extra_fields argument?"
|
|
106
98
|
end
|
|
107
99
|
|
|
108
|
-
# @type [Hash, nil]
|
|
100
|
+
# @type [Hash{String => Object}, nil]
|
|
109
101
|
custom_fields.find { |field| field.fetch('name') == custom_field_name }
|
|
110
102
|
end
|
|
111
103
|
|
|
112
104
|
# @param resource [Asana::Resources::Task,Asana::Resources::Project]
|
|
113
105
|
# @param custom_field_name [String]
|
|
114
|
-
# @return [Hash]
|
|
115
|
-
# @sg-ignore nil check above is not flow-sensitive
|
|
106
|
+
# @return [Hash{String => Object}]
|
|
116
107
|
def resource_custom_field_by_name_or_raise(resource, custom_field_name)
|
|
117
108
|
custom_field = resource_custom_field_by_name(resource, custom_field_name)
|
|
118
109
|
if custom_field.nil?
|
|
@@ -124,16 +115,15 @@ module Checkoff
|
|
|
124
115
|
|
|
125
116
|
# @param resource [Asana::Resources::Project,Asana::Resources::Task]
|
|
126
117
|
# @param custom_field_gid [String]
|
|
127
|
-
# @return [Hash]
|
|
128
|
-
# @sg-ignore nil check above is not flow-sensitive
|
|
118
|
+
# @return [Hash{String => Object}]
|
|
129
119
|
def resource_custom_field_by_gid_or_raise(resource, custom_field_gid)
|
|
130
|
-
# @type [Array<Hash>]
|
|
120
|
+
# @type [Array<Hash{String => Object}>]
|
|
131
121
|
custom_fields = resource.custom_fields
|
|
132
122
|
if custom_fields.nil?
|
|
133
123
|
raise "Could not find custom_fields under project (was 'custom_fields' included in 'extra_fields'?)"
|
|
134
124
|
end
|
|
135
125
|
|
|
136
|
-
# @type [Hash, nil]
|
|
126
|
+
# @type [Hash{String => Object}, nil]
|
|
137
127
|
matched_custom_field = custom_fields.find { |data| data.fetch('gid') == custom_field_gid }
|
|
138
128
|
if matched_custom_field.nil?
|
|
139
129
|
raise "Could not find custom field with gid #{custom_field_gid} " \
|
|
@@ -145,12 +135,11 @@ module Checkoff
|
|
|
145
135
|
|
|
146
136
|
private
|
|
147
137
|
|
|
148
|
-
#
|
|
138
|
+
# rubocop:disable Layout/LineLength, YARD/TagTypeSyntax
|
|
139
|
+
# @param custom_field [Hash{"resource_subtype" => String} & Hash{"enum_value" => Hash} & Hash{"multi_enum_values" => Array<Hash>}]
|
|
149
140
|
#
|
|
150
|
-
# @return [Array<Hash>]
|
|
151
|
-
#
|
|
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.
|
|
141
|
+
# @return [Array<Hash{"gid" => String} & Hash{"name" => String}>]
|
|
142
|
+
# rubocop:enable Layout/LineLength, YARD/TagTypeSyntax
|
|
154
143
|
def resource_custom_field_enum_values(custom_field)
|
|
155
144
|
resource_subtype = custom_field.fetch('resource_subtype')
|
|
156
145
|
case resource_subtype
|
|
@@ -163,7 +152,7 @@ module Checkoff
|
|
|
163
152
|
end
|
|
164
153
|
end
|
|
165
154
|
|
|
166
|
-
# @param custom_field [Hash]
|
|
155
|
+
# @param custom_field [Hash{String => Object}]
|
|
167
156
|
# @param enum_value [Hash{String => String}, nil]
|
|
168
157
|
# @return [Array<String>]
|
|
169
158
|
def find_gids(custom_field, enum_value)
|
|
@@ -69,16 +69,14 @@ module Checkoff
|
|
|
69
69
|
#
|
|
70
70
|
# @return [void]
|
|
71
71
|
def enrich_webhook_subscription!(webhook_subscription)
|
|
72
|
-
webhook_subscription
|
|
72
|
+
return if webhook_subscription.nil?
|
|
73
|
+
|
|
74
|
+
webhook_subscription.fetch('filters', nil)&.map! do |filter|
|
|
73
75
|
enrich_filter(filter)
|
|
74
76
|
end
|
|
75
|
-
resource = webhook_subscription
|
|
77
|
+
resource = webhook_subscription.fetch('resource', nil)
|
|
76
78
|
name, resource_type = enrich_gid(resource) if resource
|
|
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
|
|
80
79
|
webhook_subscription['checkoff:enriched:name'] = name if name
|
|
81
|
-
# @sg-ignore same nil-safety gap as above
|
|
82
80
|
webhook_subscription['checkoff:enriched:resource_type'] = resource_type if resource_type
|
|
83
81
|
end
|
|
84
82
|
|
|
@@ -100,8 +98,8 @@ module Checkoff
|
|
|
100
98
|
#
|
|
101
99
|
# @return [void]
|
|
102
100
|
def enrich_filter_parent_gid!(filter)
|
|
103
|
-
parent_gid =
|
|
104
|
-
return unless parent_gid
|
|
101
|
+
parent_gid = filter['checkoff:parent.gid']
|
|
102
|
+
return unless parent_gid.is_a?(String)
|
|
105
103
|
|
|
106
104
|
name, resource_type = enrich_gid(parent_gid)
|
|
107
105
|
filter['checkoff:enriched:parent.name'] = name if name
|
|
@@ -112,9 +110,9 @@ module Checkoff
|
|
|
112
110
|
#
|
|
113
111
|
# @return [void]
|
|
114
112
|
def enrich_filter_resource!(filter)
|
|
115
|
-
resource_gid =
|
|
113
|
+
resource_gid = filter['checkoff:resource.gid']
|
|
116
114
|
|
|
117
|
-
return unless resource_gid
|
|
115
|
+
return unless resource_gid.is_a?(String)
|
|
118
116
|
|
|
119
117
|
task = tasks.task_by_gid(resource_gid)
|
|
120
118
|
task_name = task&.name
|
|
@@ -125,8 +123,8 @@ module Checkoff
|
|
|
125
123
|
#
|
|
126
124
|
# @return [void]
|
|
127
125
|
def enrich_filter_section!(filter)
|
|
128
|
-
section_gid =
|
|
129
|
-
return unless section_gid
|
|
126
|
+
section_gid = filter['checkoff:fetched.section.gid']
|
|
127
|
+
return unless section_gid.is_a?(String)
|
|
130
128
|
|
|
131
129
|
section = sections.section_by_gid(section_gid)
|
|
132
130
|
name = section&.name
|
|
@@ -143,12 +141,8 @@ module Checkoff
|
|
|
143
141
|
return unless parent
|
|
144
142
|
|
|
145
143
|
# @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
144
|
resource_type = parent.fetch('resource_type')
|
|
149
145
|
# @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
|
|
152
146
|
gid = parent.fetch('gid')
|
|
153
147
|
name, _resource_type = enrich_gid(gid, resource_type:)
|
|
154
148
|
parent['checkoff:enriched:name'] = name if name
|
|
@@ -161,15 +155,11 @@ module Checkoff
|
|
|
161
155
|
# @return [void]
|
|
162
156
|
def enrich_event_resource!(asana_event)
|
|
163
157
|
# @type [Hash{String => String}]
|
|
164
|
-
resource =
|
|
158
|
+
resource = asana_event['resource']
|
|
165
159
|
# @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
|
|
168
160
|
resource_type = resource.fetch('resource_type')
|
|
169
161
|
|
|
170
162
|
# @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
|
|
173
163
|
gid = resource.fetch('gid')
|
|
174
164
|
|
|
175
165
|
name, _resource_type = enrich_gid(gid, resource_type:)
|
|
@@ -52,7 +52,7 @@ module Checkoff
|
|
|
52
52
|
|
|
53
53
|
private
|
|
54
54
|
|
|
55
|
-
# @param filter [Hash]
|
|
55
|
+
# @param filter [Hash{String => String, Array<String>}]
|
|
56
56
|
# @param asana_event [Hash]
|
|
57
57
|
# @param failures [Array<String>]
|
|
58
58
|
#
|
|
@@ -122,8 +122,6 @@ 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
|
|
127
125
|
resource_type = resource.fetch('resource_type')
|
|
128
126
|
unless resource_type == 'task'
|
|
129
127
|
raise "Teach me how to check #{key.inspect} on resource type #{resource_type.inspect}"
|
|
@@ -133,8 +131,6 @@ module Checkoff
|
|
|
133
131
|
options = {
|
|
134
132
|
fields:,
|
|
135
133
|
}
|
|
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
|
|
138
134
|
@client.tasks.find_by_id(task_gid, options:)
|
|
139
135
|
rescue Asana::Errors::NotFound
|
|
140
136
|
nil
|
|
@@ -20,12 +20,10 @@ module Checkoff
|
|
|
20
20
|
|
|
21
21
|
# @param key [Symbol]
|
|
22
22
|
# @return [Object]
|
|
23
|
-
# @sg-ignore return type could not be inferred — cascades from the ENV.fetch RBS gap below
|
|
24
23
|
def [](key)
|
|
25
24
|
config_value = @config[key]
|
|
26
25
|
return config_value unless config_value.nil?
|
|
27
26
|
|
|
28
|
-
# @sg-ignore Unresolved call to fetch on RBS::Unnamed::ENVClass, Class<ENV>
|
|
29
27
|
ENV.fetch(envvar_name(key), nil)
|
|
30
28
|
end
|
|
31
29
|
|
|
@@ -57,10 +57,8 @@ module Logging
|
|
|
57
57
|
private
|
|
58
58
|
|
|
59
59
|
# @return [Symbol]
|
|
60
|
-
# @sg-ignore return type could not be inferred — cascades from the ENV.fetch RBS gap below
|
|
61
60
|
def log_level
|
|
62
61
|
# rubocop:disable Style/RedundantFetchBlock
|
|
63
|
-
# @sg-ignore Unresolved call to fetch on RBS::Unnamed::ENVClass, Class<ENV>
|
|
64
62
|
ENV.fetch('LOG_LEVEL') { 'INFO' }.downcase.to_sym
|
|
65
63
|
# rubocop:enable Style/RedundantFetchBlock
|
|
66
64
|
end
|
|
@@ -10,9 +10,10 @@ module Checkoff
|
|
|
10
10
|
def initialize(_deps = {}); end
|
|
11
11
|
|
|
12
12
|
# @param project_obj [Asana::Resources::Project]
|
|
13
|
-
# @param project [String,
|
|
13
|
+
# @param project [String, :not_specified, :my_tasks, nil] - a String is a
|
|
14
|
+
# project name
|
|
14
15
|
#
|
|
15
|
-
# @return [Hash]
|
|
16
|
+
# @return [Hash{String => Object}]
|
|
16
17
|
def project_to_h(project_obj, project: :not_specified)
|
|
17
18
|
project = project_obj.name if project == :not_specified
|
|
18
19
|
project_hash = { **project_obj.to_h, 'project' => project }
|
|
@@ -26,8 +27,8 @@ module Checkoff
|
|
|
26
27
|
# @param project_hash [Hash]
|
|
27
28
|
# @return [void]
|
|
28
29
|
def unwrap_custom_fields(project_hash)
|
|
29
|
-
# @type [Array<Hash>,nil]
|
|
30
|
-
custom_fields = project_hash
|
|
30
|
+
# @type [Array<Hash{String => Object}>,nil]
|
|
31
|
+
custom_fields = project_hash['custom_fields']
|
|
31
32
|
|
|
32
33
|
return if custom_fields.nil?
|
|
33
34
|
|
|
@@ -41,7 +41,7 @@ module Checkoff
|
|
|
41
41
|
end.transform_values(&:to_h)
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
# @type [Hash{String => Class<CustomFieldVariant>}]
|
|
44
|
+
# @type [Hash{String => Class<CustomFieldVariant::CustomFieldVariant>}]
|
|
45
45
|
VARIANTS = {
|
|
46
46
|
'is' => CustomFieldVariant::Is,
|
|
47
47
|
'no_value' => CustomFieldVariant::NoValue,
|
|
@@ -59,20 +59,15 @@ 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 `unless variant_class.nil?` return value isn't inferred as the declared tuple type
|
|
63
62
|
def convert_single_custom_field_params(gid, single_custom_field_params)
|
|
64
63
|
variant_key = "custom_field_#{gid}.variant"
|
|
65
64
|
variant = single_custom_field_params.fetch(variant_key)
|
|
66
65
|
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
|
|
69
66
|
raise "Teach me how to handle #{variant_key} = #{variant}" unless variant.length == 1
|
|
70
67
|
|
|
71
|
-
# @type [Class<CustomFieldVariant>, nil]
|
|
72
|
-
# @sg-ignore variant.length == 1 guard above isn't inferred as narrowing variant[0] to non-nil
|
|
68
|
+
# @type [Class<CustomFieldVariant::CustomFieldVariant>, nil]
|
|
73
69
|
variant_class = VARIANTS[variant[0]]
|
|
74
70
|
# @type [Array(Hash{String => String}, Array<Symbol, Array>)]
|
|
75
|
-
# @sg-ignore `unless variant_class.nil?` isn't inferred as narrowing the receiver in the same statement
|
|
76
71
|
return variant_class.new(gid, remaining_params).convert unless variant_class.nil?
|
|
77
72
|
|
|
78
73
|
raise "Teach me how to handle #{variant_key} = #{variant}"
|
|
@@ -80,10 +75,14 @@ module Checkoff
|
|
|
80
75
|
|
|
81
76
|
# @param key [String]
|
|
82
77
|
# @return [String]
|
|
83
|
-
# @sg-ignore split(...)[n]'s nilable Array indexing isn't inferred as the declared String return
|
|
84
78
|
def gid_from_custom_field_key(key)
|
|
85
|
-
|
|
86
|
-
key.
|
|
79
|
+
gid_and_suffix = key.split('_')[2]
|
|
80
|
+
raise "Unexpected custom field param key: #{key}" if gid_and_suffix.nil?
|
|
81
|
+
|
|
82
|
+
gid = gid_and_suffix.split('.')[0]
|
|
83
|
+
raise "Unexpected custom field param key: #{key}" if gid.nil?
|
|
84
|
+
|
|
85
|
+
gid
|
|
87
86
|
end
|
|
88
87
|
|
|
89
88
|
# @return [Hash{String => Array<String>}]
|
|
@@ -15,6 +15,13 @@ module Checkoff
|
|
|
15
15
|
@remaining_params = T.let(remaining_params, T::Hash[String, T::Array[String]])
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
+
# Implemented by every subclass.
|
|
19
|
+
#
|
|
20
|
+
# @return [Array(Hash{String => String}, Array<Symbol, Array>)]
|
|
21
|
+
def convert
|
|
22
|
+
raise NotImplementedError
|
|
23
|
+
end
|
|
24
|
+
|
|
18
25
|
private
|
|
19
26
|
|
|
20
27
|
# @return [String]
|
|
@@ -37,8 +44,6 @@ module Checkoff
|
|
|
37
44
|
case remaining_params.keys
|
|
38
45
|
when [param_name]
|
|
39
46
|
# @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
|
|
42
47
|
param_values = remaining_params.fetch(param_name)
|
|
43
48
|
unless param_values.length == 1
|
|
44
49
|
raise "Teach me how to handle these remaining keys for #{param_name}: #{remaining_params}"
|
|
@@ -15,7 +15,6 @@ module Checkoff
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
# @return [Array(Hash{String => String}, Array<Symbol, Array>)]
|
|
18
|
-
# @sg-ignore out can genuinely be nil if none of the 3 known prefixes matched; relies on the raise above it
|
|
19
18
|
def convert
|
|
20
19
|
return [{}, []] if date_url_params.empty?
|
|
21
20
|
|
|
@@ -30,11 +29,19 @@ module Checkoff
|
|
|
30
29
|
|
|
31
30
|
raise "Teach me to handle these parameters: #{date_url_params.inspect}" unless date_url_params.empty?
|
|
32
31
|
|
|
33
|
-
out
|
|
32
|
+
ensure_matched!(out)
|
|
34
33
|
end
|
|
35
34
|
|
|
36
35
|
private
|
|
37
36
|
|
|
37
|
+
# @param out [Array(Hash{String => String}, Array<Symbol, Array>), nil]
|
|
38
|
+
# @return [Array(Hash{String => String}, Array<Symbol, Array>)]
|
|
39
|
+
def ensure_matched!(out)
|
|
40
|
+
return out if out
|
|
41
|
+
|
|
42
|
+
raise "no date param matched a known prefix: #{date_url_params.inspect}"
|
|
43
|
+
end
|
|
44
|
+
|
|
38
45
|
# @param prefix [String]
|
|
39
46
|
# @return [Array(Hash{String => String}, Array<Symbol, Array>)]
|
|
40
47
|
def convert_for_prefix(prefix)
|
|
@@ -130,19 +137,17 @@ module Checkoff
|
|
|
130
137
|
|
|
131
138
|
# @param param_key [String]
|
|
132
139
|
# @return [String]
|
|
133
|
-
# @sg-ignore value.length == 1 guard above isn't inferred as narrowing value[0] to non-nil
|
|
134
140
|
def get_single_param(param_key)
|
|
135
141
|
raise "Expected #{param_key} to have at least one value" unless date_url_params.key? param_key
|
|
136
142
|
|
|
137
143
|
value = date_url_params.fetch(param_key)
|
|
138
144
|
|
|
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
|
|
141
145
|
raise "Expected #{param_key} to have one value" if value.length != 1
|
|
142
146
|
|
|
143
|
-
|
|
144
|
-
#
|
|
145
|
-
|
|
147
|
+
single_value = value[0]
|
|
148
|
+
raise "Expected #{param_key} to have a non-nil value" if single_value.nil?
|
|
149
|
+
|
|
150
|
+
single_value
|
|
146
151
|
end
|
|
147
152
|
|
|
148
153
|
# @param prefix [String]
|
|
@@ -158,8 +163,6 @@ module Checkoff
|
|
|
158
163
|
def validate_unit_is_day!(prefix)
|
|
159
164
|
unit = date_url_params.fetch("#{prefix}.unit").fetch(0)
|
|
160
165
|
|
|
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
|
|
163
166
|
raise "Teach me how to handle other time units: #{unit}" unless unit == 'day'
|
|
164
167
|
end
|
|
165
168
|
|
|
@@ -24,10 +24,8 @@ module Checkoff
|
|
|
24
24
|
# @param url [String]
|
|
25
25
|
# @return [Array(Hash{String => String}, Array)]
|
|
26
26
|
def convert_params(url)
|
|
27
|
-
#
|
|
28
|
-
|
|
29
|
-
# gap, flagging for the follow-up code PR rather than silently asserting non-nil
|
|
30
|
-
url_params = CGI.parse(URI.parse(url).query)
|
|
27
|
+
# URI#query is nil for a URL with no query string; CGI.parse('') correctly yields {}
|
|
28
|
+
url_params = CGI.parse(URI.parse(url).query || '')
|
|
31
29
|
custom_field_params, date_url_params, simple_url_params = partition_url_params(url_params)
|
|
32
30
|
custom_field_args, custom_field_task_selector = convert_custom_field_params(custom_field_params)
|
|
33
31
|
date_url_args, date_task_selector = convert_date_params(date_url_params)
|
|
@@ -61,11 +59,8 @@ module Checkoff
|
|
|
61
59
|
# @return [Array(Hash{String => Array<String>}, Hash{String => Array<String>}, Hash{String => Array<String>})]
|
|
62
60
|
def partition_url_params(url_params)
|
|
63
61
|
groups = T.let(url_params.to_a.group_by do |key, _values|
|
|
64
|
-
# @sg-ignore Unresolved call to start_with? — T.let wrapping this
|
|
65
|
-
# chained group_by block seems to block block-param inference
|
|
66
62
|
if key.start_with? 'custom_field_'
|
|
67
63
|
:custom_field
|
|
68
|
-
# @sg-ignore Unresolved call to include? — same T.let/block-param gap
|
|
69
64
|
elsif key.include? '_date'
|
|
70
65
|
:date
|
|
71
66
|
else
|
|
@@ -34,7 +34,6 @@ module Checkoff
|
|
|
34
34
|
public
|
|
35
35
|
|
|
36
36
|
# @return [Array<String>]
|
|
37
|
-
# @sg-ignore abstract method always raises; declared type documents the override contract, not this body
|
|
38
37
|
def convert
|
|
39
38
|
raise 'Implement me!'
|
|
40
39
|
end
|
|
@@ -242,7 +241,7 @@ module Checkoff
|
|
|
242
241
|
entry
|
|
243
242
|
end
|
|
244
243
|
# @type [Hash{String => String}]
|
|
245
|
-
out =
|
|
244
|
+
out = arr_of_tuples.to_h
|
|
246
245
|
unless out.include? 'sort_by'
|
|
247
246
|
# keep results consistent between calls; API using default
|
|
248
247
|
# sort_by does not seem to be.
|
|
@@ -277,8 +276,6 @@ module Checkoff
|
|
|
277
276
|
# @return [Array<String>] the converted params, as an alternating key/value flat array
|
|
278
277
|
def convert_arg(key, values)
|
|
279
278
|
# @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
|
|
282
279
|
clazz = ARGS.fetch(key)
|
|
283
280
|
# @type [SimpleParam::SimpleParam]
|
|
284
281
|
obj = clazz.new(key:, values:)
|
|
@@ -8,7 +8,7 @@ module Checkoff
|
|
|
8
8
|
module Common
|
|
9
9
|
# Base class to evaluate a project selector function given fully evaluated arguments
|
|
10
10
|
class FunctionEvaluator < ::Checkoff::SelectorClasses::FunctionEvaluator
|
|
11
|
-
# @param selector [Array
|
|
11
|
+
# @param selector [Array<Symbol, Array>, Symbol]
|
|
12
12
|
# @param custom_fields [Checkoff::CustomFields]
|
|
13
13
|
# @param _kwargs [Hash]
|
|
14
14
|
def initialize(selector:, custom_fields:, **_kwargs)
|
|
@@ -22,7 +22,7 @@ module Checkoff
|
|
|
22
22
|
|
|
23
23
|
private
|
|
24
24
|
|
|
25
|
-
# @return [Array
|
|
25
|
+
# @return [Array<Symbol, Array>, Symbol]
|
|
26
26
|
attr_reader :selector
|
|
27
27
|
end
|
|
28
28
|
end
|