checkoff 0.193.0 → 0.195.0

Sign up to get free protection for your applications and to get access to all the features.
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