checkoff 0.265.0 → 0.267.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 +1 -1
- data/lib/checkoff/custom_fields.rb +2 -2
- data/lib/checkoff/internal/memberships.rb +25 -0
- data/lib/checkoff/internal/search_url/custom_field_variant.rb +1 -1
- data/lib/checkoff/internal/selector_classes/task.rb +16 -4
- data/lib/checkoff/portfolios.rb +1 -2
- data/lib/checkoff/sections.rb +27 -3
- data/lib/checkoff/tags.rb +1 -1
- data/lib/checkoff/task_searches.rb +4 -1
- data/lib/checkoff/tasks.rb +8 -2
- data/lib/checkoff/timelines.rb +9 -7
- data/lib/checkoff/version.rb +1 -1
- data/rbi/checkoff.rbi +55 -233
- data/sig/checkoff.rbs +87 -291
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cbab55444b46fb8c7b10d95bb86294e10d19f6f28ecf909d9362e2e814bcc24e
|
|
4
|
+
data.tar.gz: be2e338d41917f0207fd8e0fc363a83ae1f567f11b32a1b1aacb7db60a23f01a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5eaea449f58a098495c90e20a120a7b04daa06e94520861f842283169f756fab5f4601d4d09341408d64a162705c3119d60ad123c9dd0db78f38dbb44fc17f81
|
|
7
|
+
data.tar.gz: 54061f77cb640e118d6f613170407e0284d011cddfa8591776de716cf315eb80c1110b1f156314429697ca350d9156d974e70f5ed0be59703a6b2079b23ae909
|
data/lib/checkoff/attachments.rb
CHANGED
|
@@ -166,7 +166,7 @@ module Checkoff
|
|
|
166
166
|
# https://github.com/Asana/ruby-asana/blob/master/lib/asana/resource_includes/response_helper.rb#L7
|
|
167
167
|
# @param response [Asana::HttpClient::Response]
|
|
168
168
|
#
|
|
169
|
-
# @return [Array
|
|
169
|
+
# @return [Array(Hash, Hash)]
|
|
170
170
|
def parse(response)
|
|
171
171
|
data = response.body.fetch('data') do
|
|
172
172
|
raise("Unexpected response body: #{response.body}")
|
|
@@ -91,7 +91,7 @@ module Checkoff
|
|
|
91
91
|
# @param custom_field_name [String]
|
|
92
92
|
# @return [Hash{String => Object}, nil]
|
|
93
93
|
def resource_custom_field_by_name(resource, custom_field_name)
|
|
94
|
-
# @type [Array<Hash{String => Object}
|
|
94
|
+
# @type [Array<Hash{String => Object}>, nil]
|
|
95
95
|
custom_fields = resource.custom_fields
|
|
96
96
|
if custom_fields.nil?
|
|
97
97
|
raise "custom fields not found on resource - did you add 'custom_fields' in your extra_fields argument?"
|
|
@@ -117,7 +117,7 @@ module Checkoff
|
|
|
117
117
|
# @param custom_field_gid [String]
|
|
118
118
|
# @return [Hash{String => Object}]
|
|
119
119
|
def resource_custom_field_by_gid_or_raise(resource, custom_field_gid)
|
|
120
|
-
# @type [Array<Hash{String => Object}
|
|
120
|
+
# @type [Array<Hash{String => Object}>, nil]
|
|
121
121
|
custom_fields = resource.custom_fields
|
|
122
122
|
if custom_fields.nil?
|
|
123
123
|
raise "Could not find custom_fields under project (was 'custom_fields' included in 'extra_fields'?)"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Checkoff
|
|
5
|
+
module Internal
|
|
6
|
+
# Reads the project/section memberships of an Asana task
|
|
7
|
+
class Memberships
|
|
8
|
+
# Asana returns nil for memberships unless they were requested via
|
|
9
|
+
# 'fields' / extra_fields; raise a clear error instead.
|
|
10
|
+
#
|
|
11
|
+
# @param task [Asana::Resources::Task]
|
|
12
|
+
#
|
|
13
|
+
# @return [Array<Hash{String => Hash{String => String}}>]
|
|
14
|
+
def memberships_or_raise(task)
|
|
15
|
+
memberships = task.memberships
|
|
16
|
+
if memberships.nil?
|
|
17
|
+
raise "memberships not found on task #{task.gid} - " \
|
|
18
|
+
"did you add 'memberships' in your extra_fields argument?"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
memberships
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -190,7 +190,7 @@ module Checkoff
|
|
|
190
190
|
|
|
191
191
|
empty_task_selector = []
|
|
192
192
|
if selected_options.length == 1
|
|
193
|
-
[{ "custom_fields.#{gid}.value" => selected_options
|
|
193
|
+
[{ "custom_fields.#{gid}.value" => selected_options.fetch(0) },
|
|
194
194
|
empty_task_selector]
|
|
195
195
|
else
|
|
196
196
|
# As of 2023-01,
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
require_relative 'task/function_evaluator'
|
|
5
5
|
require 'checkoff/internal/task_timing'
|
|
6
|
+
require 'checkoff/internal/memberships'
|
|
6
7
|
|
|
7
8
|
module Checkoff
|
|
8
9
|
module SelectorClasses
|
|
@@ -98,7 +99,7 @@ module Checkoff
|
|
|
98
99
|
# @param project_name [String]
|
|
99
100
|
# @return [Boolean]
|
|
100
101
|
def evaluate(task, project_name)
|
|
101
|
-
project_names = task.
|
|
102
|
+
project_names = Checkoff::Internal::Memberships.new.memberships_or_raise(task).map do |membership|
|
|
102
103
|
membership.fetch('project').fetch('name')
|
|
103
104
|
end
|
|
104
105
|
project_names.include?(project_name)
|
|
@@ -242,10 +243,21 @@ module Checkoff
|
|
|
242
243
|
end
|
|
243
244
|
return true if stories.empty? # no stories == infinitely old!
|
|
244
245
|
|
|
245
|
-
last_story =
|
|
246
|
-
last_story_created_at = Time.parse(last_story.created_at)
|
|
246
|
+
last_story = stories.last
|
|
247
247
|
n_days_ago = Time.at(Time.now.to_i - (num_days * 86_400))
|
|
248
|
-
|
|
248
|
+
# @sg-ignore https://github.com/apiology/solargraph/pull/175
|
|
249
|
+
created_time(last_story) < n_days_ago
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
private
|
|
253
|
+
|
|
254
|
+
# @param story [Asana::Resources::Story]
|
|
255
|
+
# @return [Time]
|
|
256
|
+
def created_time(story)
|
|
257
|
+
created_at = story.created_at
|
|
258
|
+
raise "Story #{story.gid} has no created_at" if created_at.nil?
|
|
259
|
+
|
|
260
|
+
Time.parse(created_at)
|
|
249
261
|
end
|
|
250
262
|
end
|
|
251
263
|
|
data/lib/checkoff/portfolios.rb
CHANGED
|
@@ -78,9 +78,8 @@ module Checkoff
|
|
|
78
78
|
def portfolio_by_gid(portfolio_gid,
|
|
79
79
|
extra_fields: [])
|
|
80
80
|
options = {
|
|
81
|
-
fields: ['name'],
|
|
81
|
+
fields: ['name'] + extra_fields,
|
|
82
82
|
}
|
|
83
|
-
options[:fields] += extra_fields
|
|
84
83
|
client.portfolios.find_by_id(portfolio_gid, options:)
|
|
85
84
|
end
|
|
86
85
|
cache_method :portfolio_by_gid, SHORT_CACHE_TIME
|
data/lib/checkoff/sections.rb
CHANGED
|
@@ -7,6 +7,7 @@ require_relative 'workspaces'
|
|
|
7
7
|
require_relative 'clients'
|
|
8
8
|
require_relative 'my_tasks'
|
|
9
9
|
require_relative 'internal/logging'
|
|
10
|
+
require_relative 'internal/memberships'
|
|
10
11
|
|
|
11
12
|
module Checkoff
|
|
12
13
|
# Query different sections of Asana projects
|
|
@@ -186,7 +187,8 @@ module Checkoff
|
|
|
186
187
|
#
|
|
187
188
|
# @return [Asana::Resources::Section, nil]
|
|
188
189
|
def previous_section(section)
|
|
189
|
-
|
|
190
|
+
project = section_project_or_raise(section)
|
|
191
|
+
project_sections = sections_by_project_gid(project.fetch('gid'))
|
|
190
192
|
|
|
191
193
|
# @type [Array<Asana::Resources::Section>]
|
|
192
194
|
project_sections_arr = project_sections.to_a
|
|
@@ -232,10 +234,27 @@ module Checkoff
|
|
|
232
234
|
|
|
233
235
|
include Logging
|
|
234
236
|
|
|
237
|
+
# Asana returns nil for a section's project unless it was requested
|
|
238
|
+
# via 'fields' / extra_fields; raise a clear error instead.
|
|
239
|
+
#
|
|
240
|
+
# @param section [Asana::Resources::Section]
|
|
241
|
+
#
|
|
242
|
+
# @return [Hash{String => String}]
|
|
243
|
+
def section_project_or_raise(section)
|
|
244
|
+
# @type [Hash{String => String}, nil]
|
|
245
|
+
project = section.project
|
|
246
|
+
if project.nil?
|
|
247
|
+
raise "project not found on section #{section.gid} - " \
|
|
248
|
+
"did you add 'project' in your extra_fields argument?"
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
project
|
|
252
|
+
end
|
|
253
|
+
|
|
235
254
|
# https://github.com/Asana/ruby-asana/blob/master/lib/asana/resource_includes/response_helper.rb#L7
|
|
236
255
|
# @param response [Asana::HttpClient::Response]
|
|
237
256
|
#
|
|
238
|
-
# @return [Array
|
|
257
|
+
# @return [Array(Hash, Hash)]
|
|
239
258
|
def parse(response)
|
|
240
259
|
data = response.body.fetch('data') do
|
|
241
260
|
raise("Unexpected response body: #{response.body}")
|
|
@@ -282,7 +301,7 @@ module Checkoff
|
|
|
282
301
|
# @param project_gid [String]
|
|
283
302
|
# @return [void]
|
|
284
303
|
def file_task_by_section(by_section, task, project_gid)
|
|
285
|
-
membership = task.
|
|
304
|
+
membership = memberships.memberships_or_raise(task).find do |m|
|
|
286
305
|
m.fetch('project')['gid'] == project_gid
|
|
287
306
|
end
|
|
288
307
|
raise "Could not find task in project_gid #{project_gid}: #{task}" if membership.nil?
|
|
@@ -309,5 +328,10 @@ module Checkoff
|
|
|
309
328
|
end
|
|
310
329
|
project
|
|
311
330
|
end
|
|
331
|
+
|
|
332
|
+
# @return [Checkoff::Internal::Memberships]
|
|
333
|
+
def memberships
|
|
334
|
+
@memberships ||= Checkoff::Internal::Memberships.new
|
|
335
|
+
end
|
|
312
336
|
end
|
|
313
337
|
end
|
data/lib/checkoff/tags.rb
CHANGED
|
@@ -123,7 +123,7 @@ module Checkoff
|
|
|
123
123
|
#
|
|
124
124
|
# @param response [Asana::HttpClient::Response]
|
|
125
125
|
#
|
|
126
|
-
# @return [Array<Hash
|
|
126
|
+
# @return [Array(Array<Hash>, Hash)]
|
|
127
127
|
def parse(response)
|
|
128
128
|
data = response.body.fetch('data')
|
|
129
129
|
extra = response.body.except('data')
|
|
@@ -171,7 +171,10 @@ module Checkoff
|
|
|
171
171
|
|
|
172
172
|
break if oldest.nil?
|
|
173
173
|
|
|
174
|
-
|
|
174
|
+
oldest_created_at = oldest.created_at
|
|
175
|
+
raise "Task #{oldest.gid} has no created_at" if oldest_created_at.nil?
|
|
176
|
+
|
|
177
|
+
new_api_params['created_at.before'] = oldest_created_at
|
|
175
178
|
|
|
176
179
|
tasks.concat(task_batch.to_a)
|
|
177
180
|
end
|
data/lib/checkoff/tasks.rb
CHANGED
|
@@ -10,6 +10,7 @@ require_relative 'workspaces'
|
|
|
10
10
|
require_relative 'internal/config_loader'
|
|
11
11
|
require_relative 'internal/task_timing'
|
|
12
12
|
require_relative 'internal/task_hashes'
|
|
13
|
+
require_relative 'internal/memberships'
|
|
13
14
|
require_relative 'internal/logging'
|
|
14
15
|
require_relative 'internal/thread_local'
|
|
15
16
|
require 'asana'
|
|
@@ -297,7 +298,7 @@ module Checkoff
|
|
|
297
298
|
portfolio_name,
|
|
298
299
|
workspace_name: T.must(@workspaces.default_workspace.name))
|
|
299
300
|
portfolio_projects = @portfolios.projects_in_portfolio(workspace_name, portfolio_name)
|
|
300
|
-
task.
|
|
301
|
+
memberships.memberships_or_raise(task).any? do |membership|
|
|
301
302
|
project_gid = membership.fetch('project').fetch('gid')
|
|
302
303
|
portfolio_projects.any? { |portfolio_project| portfolio_project.gid == project_gid }
|
|
303
304
|
end
|
|
@@ -315,7 +316,7 @@ module Checkoff
|
|
|
315
316
|
portfolio_projects = @portfolios.projects_in_portfolio(workspace_name, portfolio_name)
|
|
316
317
|
portfolio_project_gids = portfolio_projects.map(&:gid)
|
|
317
318
|
seen = T.let(false, T::Boolean)
|
|
318
|
-
task.
|
|
319
|
+
memberships.memberships_or_raise(task).each do |membership|
|
|
319
320
|
project_gid = membership.fetch('project').fetch('gid')
|
|
320
321
|
next unless portfolio_project_gids.include?(project_gid)
|
|
321
322
|
return true if seen
|
|
@@ -344,6 +345,11 @@ module Checkoff
|
|
|
344
345
|
@task_hashes ||= Checkoff::Internal::TaskHashes.new
|
|
345
346
|
end
|
|
346
347
|
|
|
348
|
+
# @return [Checkoff::Internal::Memberships]
|
|
349
|
+
def memberships
|
|
350
|
+
@memberships ||= Checkoff::Internal::Memberships.new
|
|
351
|
+
end
|
|
352
|
+
|
|
347
353
|
# @param workspace_name [String, Symbol]
|
|
348
354
|
# @param project_name [String, Symbol]
|
|
349
355
|
# @param section_name [String, nil, Symbol] - :unspecified
|
data/lib/checkoff/timelines.rb
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
require 'forwardable'
|
|
7
7
|
require 'cache_method'
|
|
8
8
|
require_relative 'internal/config_loader'
|
|
9
|
+
require_relative 'internal/memberships'
|
|
9
10
|
require_relative 'workspaces'
|
|
10
11
|
require_relative 'clients'
|
|
11
12
|
|
|
@@ -73,9 +74,7 @@ module Checkoff
|
|
|
73
74
|
end
|
|
74
75
|
|
|
75
76
|
all_dependent_task_gids = nil
|
|
76
|
-
|
|
77
|
-
memberships = task.memberships
|
|
78
|
-
memberships.all? do |membership_data|
|
|
77
|
+
memberships.memberships_or_raise(task).all? do |membership_data|
|
|
79
78
|
# @type [Hash{String => Object}]
|
|
80
79
|
md = membership_data
|
|
81
80
|
unless limit_to_portfolio_name.nil?
|
|
@@ -110,9 +109,7 @@ module Checkoff
|
|
|
110
109
|
end
|
|
111
110
|
|
|
112
111
|
all_dependent_milestones = nil
|
|
113
|
-
|
|
114
|
-
memberships = task.memberships
|
|
115
|
-
memberships.all? do |membership_data|
|
|
112
|
+
memberships.memberships_or_raise(task).all? do |membership_data|
|
|
116
113
|
# @type [Hash{String => Object}]
|
|
117
114
|
md = membership_data
|
|
118
115
|
unless limit_to_portfolio_name.nil?
|
|
@@ -132,7 +129,7 @@ module Checkoff
|
|
|
132
129
|
end
|
|
133
130
|
|
|
134
131
|
all_dependent_milestones.any? do |milestone|
|
|
135
|
-
milestone.
|
|
132
|
+
memberships.memberships_or_raise(milestone).any? do |milestone_membership_data|
|
|
136
133
|
milestone_membership_data.fetch('project').fetch('gid') == project_gid
|
|
137
134
|
end
|
|
138
135
|
end
|
|
@@ -176,6 +173,11 @@ module Checkoff
|
|
|
176
173
|
# @return [Asana::Client]
|
|
177
174
|
attr_reader :client
|
|
178
175
|
|
|
176
|
+
# @return [Checkoff::Internal::Memberships]
|
|
177
|
+
def memberships
|
|
178
|
+
@memberships ||= Checkoff::Internal::Memberships.new
|
|
179
|
+
end
|
|
180
|
+
|
|
179
181
|
# bundle exec ./timelines.rb
|
|
180
182
|
# :nocov:
|
|
181
183
|
class << self
|
data/lib/checkoff/version.rb
CHANGED