checkoff 0.193.0 → 0.195.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: 740a4435d472d0e2034b946c694abd1f40e91bcbf874380ca43de89e82bbdb8e
4
- data.tar.gz: 7e41942a46e0dc7ad297a1ce4379fab954a2d3831c223c4a99801cd9567ecb70
3
+ metadata.gz: c777dc82cc51fd0ec445c1413fc6f33ed37e98b8a41026446cec61f800ec0417
4
+ data.tar.gz: bb7edb3ed4eb31a171cd4204a338ea56b6097a4cee8bf299e451ee7ecf342e59
5
5
  SHA512:
6
- metadata.gz: c96bb1cc1df2d2874eecb23c8328bb48ea7b5401188dd072dfba815d908965316a9c8062879d61ce6a949b1adfd635db54c6d0a6b436678f0202ad1121072562
7
- data.tar.gz: c3b68ef7459b67ccfa436788730b22e01139a12f05d8507b386d3813e0f172e0ff20109ddd2ae2355660c1fe51b9080344e264351a0d79eba1ff6967ece439f7
6
+ metadata.gz: 794bf6eba0270a4cb002421f2e0857b20268d348bec359dc5d1363f345a60f385d1dea1cf26f0530cabd015e1f06b4b037ca54b342174ac5415c1f93eed3afa7
7
+ data.tar.gz: c9263dd810014f080b6d52c6954dd86aca9f837b88e10c711be154c49f7652cdba92303d462bee08a1c25a2f34b3ef3b85a14557410892c052916ea82a7eb098
data/Gemfile.lock CHANGED
@@ -12,7 +12,7 @@ GIT
12
12
  PATH
13
13
  remote: .
14
14
  specs:
15
- checkoff (0.193.0)
15
+ checkoff (0.195.0)
16
16
  activesupport
17
17
  asana (> 0.10.0)
18
18
  cache_method
@@ -130,11 +130,11 @@ GEM
130
130
  multi_xml (0.6.0)
131
131
  multipart-post (2.3.0)
132
132
  mutex_m (0.2.0)
133
- nokogiri (1.15.5-arm64-darwin)
133
+ nokogiri (1.16.2-arm64-darwin)
134
134
  racc (~> 1.4)
135
- nokogiri (1.15.5-x86_64-darwin)
135
+ nokogiri (1.16.2-x86_64-darwin)
136
136
  racc (~> 1.4)
137
- nokogiri (1.15.5-x86_64-linux)
137
+ nokogiri (1.16.2-x86_64-linux)
138
138
  racc (~> 1.4)
139
139
  oauth2 (1.4.11)
140
140
  faraday (>= 0.17.3, < 3.0)
@@ -18,6 +18,7 @@ module Checkoff
18
18
  # @param tasks [Checkoff::Tasks]
19
19
  # @param sections [Checkoff::Sections]
20
20
  # @param projects [Checkoff::Projects]
21
+ # @param resources [Checkoff::Resources]
21
22
  # @param clients [Checkoff::Clients]
22
23
  # @param client [Asana::Client]
23
24
  # @param asana_event_enrichment [Checkoff::Internal::AsanaEventEnrichment]
@@ -26,12 +27,14 @@ module Checkoff
26
27
  tasks: Checkoff::Tasks.new(config: config),
27
28
  sections: Checkoff::Sections.new(config: config),
28
29
  projects: Checkoff::Projects.new(config: config),
30
+ resources: Checkoff::Resources.new(config: config),
29
31
  clients: Checkoff::Clients.new(config: config),
30
32
  client: clients.client)
31
33
  @workspaces = workspaces
32
34
  @tasks = tasks
33
35
  @sections = sections
34
36
  @projects = projects
37
+ @resources = resources
35
38
  @client = client
36
39
  end
37
40
 
@@ -86,13 +89,9 @@ module Checkoff
86
89
  #
87
90
  # @return [Array<([String, nil], [String,nil])>]
88
91
  def enrich_gid(gid, resource_type: nil)
89
- %w[task section project].each do |resource_type_to_try|
90
- next unless [resource_type_to_try, nil].include?(resource_type)
91
-
92
- name = method(:"enrich_#{resource_type_to_try}_gid").call(gid)
93
- return [name, resource_type_to_try] if name
94
- end
95
- [nil, nil]
92
+ # @sg-ignore
93
+ resource, resource_type = resources.resource_by_gid(gid, resource_type: resource_type)
94
+ [resource&.name, resource_type]
96
95
  end
97
96
 
98
97
  # @param filter [Hash{String => String}]
@@ -108,30 +107,6 @@ module Checkoff
108
107
  filter['checkoff:enriched:parent.resource_type'] = resource_type if resource_type
109
108
  end
110
109
 
111
- # @param gid [String]
112
- #
113
- # @return [String, nil]
114
- def enrich_task_gid(gid)
115
- task = tasks.task_by_gid(gid, only_uncompleted: false)
116
- task&.name
117
- end
118
-
119
- # @param section_gid [String]
120
- #
121
- # @return [String, nil]
122
- def enrich_section_gid(section_gid)
123
- section = sections.section_by_gid(section_gid)
124
- section&.name
125
- end
126
-
127
- # @param project_gid [String]
128
- #
129
- # @return [String, nil]
130
- def enrich_project_gid(project_gid)
131
- project = projects.project_by_gid(project_gid)
132
- project&.name
133
- end
134
-
135
110
  # @param filter [Hash{String => String}]
136
111
  #
137
112
  # @return [void]
@@ -151,7 +126,8 @@ module Checkoff
151
126
  section_gid = filter['checkoff:fetched.section.gid']
152
127
  return unless section_gid
153
128
 
154
- name = enrich_section_gid(section_gid)
129
+ section = sections.section_by_gid(section_gid)
130
+ name = section&.name
155
131
  filter['checkoff:enriched:fetched.section.name'] = name if name
156
132
  end
157
133
 
@@ -208,6 +184,9 @@ module Checkoff
208
184
  # @return [Checkoff::Workspaces]
209
185
  attr_reader :workspaces
210
186
 
187
+ # @return [Checkoff::Resources]
188
+ attr_reader :resources
189
+
211
190
  # @return [Asana::Client]
212
191
  attr_reader :client
213
192
  end
@@ -52,17 +52,46 @@ module Checkoff
52
52
  @timing = timing
53
53
  end
54
54
 
55
+ # @param extra_fields [Array<String>]
56
+ #
57
+ # @return [Array<String>]
58
+ def task_fields(extra_fields: [])
59
+ (%w[name completed_at start_at start_on due_at due_on tags
60
+ memberships.project.gid memberships.project.name
61
+ memberships.section.name dependencies] + extra_fields).sort.uniq
62
+ end
63
+
55
64
  # Default options used in Asana API to pull tasks
65
+ #
66
+ # @param extra_fields [Array<String>]
67
+ # @param [Boolean] only_uncompleted
68
+ #
56
69
  # @return [Hash<Symbol, Object>]
57
- def task_options
58
- {
70
+ def task_options(extra_fields: [], only_uncompleted: false)
71
+ options = {
59
72
  per_page: 100,
60
73
  options: {
61
- fields: %w[name completed_at start_at start_on due_at due_on tags
62
- memberships.project.gid memberships.project.name
63
- memberships.section.name dependencies],
74
+ fields: task_fields(extra_fields: extra_fields),
64
75
  },
65
76
  }
77
+ options[:completed_since] = '9999-12-01' if only_uncompleted
78
+ options
79
+ end
80
+
81
+ # @param extra_project_fields [Array<String>]
82
+ #
83
+ # @return [Array<String>]
84
+ def project_fields(extra_project_fields: [])
85
+ (%w[name custom_fields] + extra_project_fields).sort.uniq
86
+ end
87
+
88
+ # Default options used in Asana API to pull projects
89
+ #
90
+ # @param extra_project_fields [Array<String>]
91
+ #
92
+ # @return [Hash<Symbol, Object>]
93
+ def project_options(extra_project_fields: [])
94
+ { fields: project_fields(extra_project_fields: extra_project_fields) }
66
95
  end
67
96
 
68
97
  # pulls an Asana API project class given a name
@@ -103,7 +132,7 @@ module Checkoff
103
132
  #
104
133
  # @return [Asana::Resources::Project,nil]
105
134
  def project_by_gid(gid, extra_fields: [])
106
- projects.find_by_id(gid, options: { fields: %w[name] + extra_fields })
135
+ projects.find_by_id(gid, options: project_options(extra_project_fields: extra_fields))
107
136
  rescue Asana::Errors::NotFound => e
108
137
  debug e
109
138
  nil
@@ -142,10 +171,8 @@ module Checkoff
142
171
  def tasks_from_project_gid(project_gid,
143
172
  only_uncompleted: true,
144
173
  extra_fields: [])
145
- options = task_options
146
- options[:completed_since] = '9999-12-01' if only_uncompleted
174
+ options = task_options(extra_fields: extra_fields, only_uncompleted: only_uncompleted)
147
175
  options[:project] = project_gid
148
- options[:options][:fields] += extra_fields
149
176
  # Note: 30 minute cache time on a raw Enumerable from SDK gives
150
177
  # 'Your pagination token has expired' errors. So we go ahead
151
178
  # and eagerly evaluate here so we can enjoy the cache.
@@ -158,11 +185,12 @@ module Checkoff
158
185
  # @return [Enumerable<Asana::Resources::Project>]
159
186
  def projects_by_workspace_name(workspace_name, extra_fields: [])
160
187
  workspace = @workspaces.workspace_or_raise(workspace_name)
161
- options = { fields: %w[name] + extra_fields }
162
188
  # 15 minute cache resulted in 'Your pagination token has
163
189
  # expired', so let's cache this a super long time and force
164
190
  # evaluation
165
- projects.find_by_workspace(workspace: workspace.gid, per_page: 100, options: options).to_a
191
+ projects.find_by_workspace(workspace: workspace.gid,
192
+ per_page: 100,
193
+ options: project_options(extra_project_fields: extra_fields)).to_a
166
194
  end
167
195
  cache_method :projects_by_workspace_name, REALLY_LONG_CACHE_TIME
168
196
 
@@ -0,0 +1,131 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # frozen_string_literal: true
4
+
5
+ require 'forwardable'
6
+ require 'cache_method'
7
+ require_relative 'internal/config_loader'
8
+ require_relative 'workspaces'
9
+ require_relative 'clients'
10
+
11
+ # https://developers.asana.com/reference/resources
12
+
13
+ module Checkoff
14
+ # Deal with Asana resources across different resource types
15
+ class Resources
16
+ # @!parse
17
+ # extend CacheMethod::ClassMethods
18
+
19
+ MINUTE = 60
20
+ private_constant :MINUTE
21
+ HOUR = MINUTE * 60
22
+ private_constant :HOUR
23
+ DAY = 24 * HOUR
24
+ private_constant :DAY
25
+ REALLY_LONG_CACHE_TIME = HOUR * 1
26
+ private_constant :REALLY_LONG_CACHE_TIME
27
+ LONG_CACHE_TIME = MINUTE * 15
28
+ private_constant :LONG_CACHE_TIME
29
+ SHORT_CACHE_TIME = MINUTE
30
+ private_constant :SHORT_CACHE_TIME
31
+
32
+ # @param config [Hash]
33
+ # @param workspaces [Checkoff::Workspaces]
34
+ # @param tasks [Checkoff::Tasks]
35
+ # @param sections [Checkoff::Sections]
36
+ # @param projects [Checkoff::Projects]
37
+ # @param clients [Checkoff::Clients]
38
+ # @param client [Asana::Client]
39
+ def initialize(config: Checkoff::Internal::ConfigLoader.load(:asana),
40
+ workspaces: Checkoff::Workspaces.new(config: config),
41
+ tasks: Checkoff::Tasks.new(config: config),
42
+ sections: Checkoff::Sections.new(config: config),
43
+ projects: Checkoff::Projects.new(config: config),
44
+ clients: Checkoff::Clients.new(config: config),
45
+ client: clients.client)
46
+ @workspaces = workspaces
47
+ @tasks = tasks
48
+ @sections = sections
49
+ @projects = projects
50
+ @client = client
51
+ end
52
+
53
+ # Attempt to look up a GID, even in situations where we don't
54
+ # have a resource type provided.
55
+ #
56
+ # @param gid [String]
57
+ # @param resource_type [String,nil]
58
+ #
59
+ # @return [Array<([Asana::Resource, nil], [String,nil])>]
60
+ def resource_by_gid(gid, resource_type: nil)
61
+ %w[task section project].each do |resource_type_to_try|
62
+ next unless [resource_type_to_try, nil].include?(resource_type)
63
+
64
+ resource = method(:"fetch_#{resource_type_to_try}_gid").call(gid)
65
+ return [resource, resource_type_to_try] if resource
66
+ end
67
+ [nil, nil]
68
+ end
69
+
70
+ private
71
+
72
+ # @param gid [String]
73
+ #
74
+ # @return [Asana::Resources::Task, nil]
75
+ def fetch_task_gid(gid)
76
+ tasks.task_by_gid(gid, only_uncompleted: false)
77
+ end
78
+
79
+ # @param section_gid [String]
80
+ #
81
+ # @return [Asana::Resources::Section, nil]
82
+ def fetch_section_gid(section_gid)
83
+ sections.section_by_gid(section_gid)
84
+ end
85
+
86
+ # @param project_gid [String]
87
+ #
88
+ # @return [Asana::Resources::Project, nil]
89
+ def fetch_project_gid(project_gid)
90
+ projects.project_by_gid(project_gid)
91
+ end
92
+
93
+ # @return [Checkoff::Workspaces]
94
+ attr_reader :workspaces
95
+
96
+ # @return [Checkoff::Projects]
97
+ attr_reader :projects
98
+
99
+ # @return [Checkoff::Sections]
100
+ attr_reader :sections
101
+
102
+ # @return [Checkoff::Tasks]
103
+ attr_reader :tasks
104
+
105
+ # @return [Asana::Client]
106
+ attr_reader :client
107
+
108
+ # bundle exec ./resources.rb
109
+ # :nocov:
110
+ class << self
111
+ # @return [void]
112
+ def run
113
+ # # @sg-ignore
114
+ # # @type [String]
115
+ # workspace_name = ARGV[0] || raise('Please pass workspace name as first argument')
116
+ # # @sg-ignore
117
+ # # @type [String]
118
+ # resource_name = ARGV[1] || raise('Please pass resource name as second argument')
119
+ # resources = Checkoff::Resources.new
120
+ # resource = resources.resource_or_raise(workspace_name, resource_name)
121
+ # puts "Results: #{resource}"
122
+ end
123
+ end
124
+ # :nocov:
125
+ end
126
+ end
127
+
128
+ # :nocov:
129
+ abs_program_name = File.expand_path($PROGRAM_NAME)
130
+ Checkoff::Resources.run if abs_program_name == File.expand_path(__FILE__)
131
+ # :nocov:
@@ -106,9 +106,8 @@ module Checkoff
106
106
  def tasks_by_section_gid(section_gid,
107
107
  only_uncompleted: true,
108
108
  extra_fields: [])
109
- options = projects.task_options
110
- options[:options][:fields] += extra_fields
111
- options[:completed_since] = '9999-12-01' if only_uncompleted
109
+ options = projects.task_options(extra_fields: extra_fields,
110
+ only_uncompleted: only_uncompleted)
112
111
  client.tasks.get_tasks(section: section_gid, **options)
113
112
  end
114
113
 
@@ -127,9 +126,8 @@ module Checkoff
127
126
  only_uncompleted: true,
128
127
  extra_fields: [])
129
128
  section = section_or_raise(workspace_name, project_name, section_name)
130
- options = projects.task_options
131
- options[:options][:fields] += extra_fields
132
- options[:completed_since] = '9999-12-01' if only_uncompleted
129
+ options = projects.task_options(extra_fields: extra_fields,
130
+ only_uncompleted: only_uncompleted)
133
131
  # Note: 30 minute cache time on a raw Enumerable from SDK gives
134
132
  # 'Your pagination token has expired' errors. So we go ahead
135
133
  # and eagerly evaluate here so we can enjoy the cache.
@@ -73,12 +73,9 @@ module Checkoff
73
73
  extra_fields: [],
74
74
  only_uncompleted: true)
75
75
  # @type [Hash]
76
- options = projects.task_options.fetch(:options, {})
77
- options[:fields] += extra_fields
78
- options[:fields] += %w[is_rendered_as_separator]
79
- options[:fields].uniq!
80
-
81
- options[:completed_since] = '9999-12-01' if only_uncompleted
76
+ all_options = projects.task_options(extra_fields: extra_fields + %w[is_rendered_as_separator],
77
+ only_uncompleted: only_uncompleted)
78
+ options = all_options.fetch(:options, {})
82
79
  client.tasks.get_subtasks_for_task(task_gid: task_gid,
83
80
  # per_page: 100, # stub doesn't have this arg available
84
81
  options: options)
data/lib/checkoff/tags.rb CHANGED
@@ -36,7 +36,8 @@ module Checkoff
36
36
  extra_fields: [])
37
37
  tag = tag_or_raise(workspace_name, tag_name)
38
38
 
39
- options = build_task_options(projects.task_options, extra_fields, only_uncompleted)
39
+ options = projects.task_options(extra_fields: extra_fields,
40
+ only_uncompleted: only_uncompleted)
40
41
 
41
42
  params = build_params(options)
42
43
 
@@ -65,12 +66,6 @@ module Checkoff
65
66
 
66
67
  attr_reader :workspaces, :projects, :client
67
68
 
68
- def build_task_options(task_options, extra_fields, only_uncompleted)
69
- task_options[:options][:fields] += extra_fields
70
- task_options[:completed_since] = '9999-12-01' if only_uncompleted
71
- task_options
72
- end
73
-
74
69
  def build_params(options)
75
70
  { limit: options[:per_page], completed_since: options[:completed_since] }.reject do |_, v|
76
71
  v.nil? || Array(v).empty?
@@ -193,10 +193,8 @@ module Checkoff
193
193
  # @return [Hash<Symbol, Object>]
194
194
  def calculate_api_options(extra_fields)
195
195
  # @type [Hash<Symbol, Object>]
196
- options = projects.task_options[:options]
197
- options[:fields] += ['custom_fields']
198
- options[:fields] += extra_fields
199
- options
196
+ all_options = projects.task_options(extra_fields: ['custom_fields'] + extra_fields)
197
+ all_options[:options]
200
198
  end
201
199
 
202
200
  # bundle exec ./task_searches.rb
@@ -156,10 +156,12 @@ module Checkoff
156
156
  def task_by_gid(task_gid,
157
157
  extra_fields: [],
158
158
  only_uncompleted: true)
159
+ # @type [Hash{Symbol => Object}]
160
+ all_options = projects.task_options(extra_fields: extra_fields,
161
+ only_uncompleted: only_uncompleted)
159
162
  # @type [Hash]
160
- options = projects.task_options.fetch(:options, {})
161
- options[:fields] += extra_fields
162
- options[:completed_since] = '9999-12-01' if only_uncompleted
163
+ options = all_options.fetch(:options, {})
164
+ options[:completed_since] = all_options[:completed_since] unless all_options[:completed_since].nil?
163
165
  client.tasks.find_by_id(task_gid, options: options)
164
166
  rescue Asana::Errors::NotFound => e
165
167
  debug e
@@ -3,5 +3,5 @@
3
3
  # Command-line and gem client for Asana (unofficial)
4
4
  module Checkoff
5
5
  # Version of library
6
- VERSION = '0.193.0'
6
+ VERSION = '0.195.0'
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: checkoff
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.193.0
4
+ version: 0.195.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vince Broz
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-02-13 00:00:00.000000000 Z
11
+ date: 2024-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -170,6 +170,7 @@ files:
170
170
  - lib/checkoff/portfolios.rb
171
171
  - lib/checkoff/project_selectors.rb
172
172
  - lib/checkoff/projects.rb
173
+ - lib/checkoff/resources.rb
173
174
  - lib/checkoff/section_selectors.rb
174
175
  - lib/checkoff/sections.rb
175
176
  - lib/checkoff/subtasks.rb