checkoff 0.11.1 → 0.12.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/Gemfile.lock +11 -7
- data/README.md +1 -1
- data/coverage/.last_run.json +2 -2
- data/lib/checkoff/projects.rb +11 -10
- data/lib/checkoff/sections.rb +43 -117
- data/lib/checkoff/tasks.rb +0 -4
- data/lib/checkoff/version.rb +1 -1
- 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: 28bce7b1402a371b87f03a468cb1678cd02f7631a2a8f195a544b2bccc4af26e
|
4
|
+
data.tar.gz: f645e96e4526173f33e7b3140d9fec84b59330a4050819467a4456f0b9e10679
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1503cc4b41f8297a806b57311c2f7f3e0e6d7b93027109125c985b4dba056e2709fdcec43d5ca312f9778ba044d67c28e8a5c055a692b7067ebf442491de912e
|
7
|
+
data.tar.gz: 1b30b11537a9608e84ec1434c67a47579e0d6d2a8a88ee79084de24efc39c18e8b10fc1af5be5ccf7b4aac17509b4b16d540d2f4f2304b61f3100b0006ff2af4
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
checkoff (0.
|
4
|
+
checkoff (0.12.0)
|
5
5
|
activesupport
|
6
6
|
asana (> 0.10.0)
|
7
7
|
cache_method
|
@@ -11,7 +11,7 @@ PATH
|
|
11
11
|
GEM
|
12
12
|
remote: https://rubygems.org/
|
13
13
|
specs:
|
14
|
-
activesupport (6.1.
|
14
|
+
activesupport (6.1.4)
|
15
15
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
16
16
|
i18n (>= 1.6, < 2)
|
17
17
|
minitest (>= 5.1)
|
@@ -31,25 +31,29 @@ GEM
|
|
31
31
|
concurrent-ruby (1.1.9)
|
32
32
|
dalli (2.7.11)
|
33
33
|
docile (1.4.0)
|
34
|
-
faraday (1.
|
34
|
+
faraday (1.5.1)
|
35
35
|
faraday-em_http (~> 1.0)
|
36
36
|
faraday-em_synchrony (~> 1.0)
|
37
37
|
faraday-excon (~> 1.1)
|
38
|
+
faraday-httpclient (~> 1.0.1)
|
38
39
|
faraday-net_http (~> 1.0)
|
39
40
|
faraday-net_http_persistent (~> 1.1)
|
41
|
+
faraday-patron (~> 1.0)
|
40
42
|
multipart-post (>= 1.2, < 3)
|
41
43
|
ruby2_keywords (>= 0.0.4)
|
42
44
|
faraday-em_http (1.0.0)
|
43
45
|
faraday-em_synchrony (1.0.0)
|
44
46
|
faraday-excon (1.1.0)
|
47
|
+
faraday-httpclient (1.0.1)
|
45
48
|
faraday-net_http (1.0.1)
|
46
|
-
faraday-net_http_persistent (1.
|
49
|
+
faraday-net_http_persistent (1.2.0)
|
50
|
+
faraday-patron (1.0.0)
|
47
51
|
faraday_middleware (1.0.0)
|
48
52
|
faraday (~> 1.0)
|
49
53
|
faraday_middleware-multi_json (0.0.6)
|
50
54
|
faraday_middleware
|
51
55
|
multi_json
|
52
|
-
gli (2.20.
|
56
|
+
gli (2.20.1)
|
53
57
|
i18n (1.8.10)
|
54
58
|
concurrent-ruby (~> 1.0)
|
55
59
|
imagen (0.1.8)
|
@@ -96,7 +100,7 @@ GEM
|
|
96
100
|
rubocop-rake (0.5.1)
|
97
101
|
rubocop
|
98
102
|
ruby-progressbar (1.11.0)
|
99
|
-
ruby2_keywords (0.0.
|
103
|
+
ruby2_keywords (0.0.5)
|
100
104
|
rugged (1.1.0)
|
101
105
|
simplecov (0.21.2)
|
102
106
|
docile (~> 1.1)
|
@@ -136,4 +140,4 @@ DEPENDENCIES
|
|
136
140
|
undercover
|
137
141
|
|
138
142
|
BUNDLED WITH
|
139
|
-
2.2.
|
143
|
+
2.2.24
|
data/README.md
CHANGED
@@ -12,7 +12,7 @@ $ checkoff --help
|
|
12
12
|
View tasks:
|
13
13
|
checkoff view workspace project [section]
|
14
14
|
|
15
|
-
'project' can be set to a project name, or :my_tasks
|
15
|
+
'project' can be set to a project name, or :my_tasks for your user task list.
|
16
16
|
```
|
17
17
|
|
18
18
|
Let's say we have a project like this:
|
data/coverage/.last_run.json
CHANGED
data/lib/checkoff/projects.rb
CHANGED
@@ -35,6 +35,17 @@ module Checkoff
|
|
35
35
|
@workspaces.client
|
36
36
|
end
|
37
37
|
|
38
|
+
# Default options used in Asana API to pull taskso
|
39
|
+
def task_options
|
40
|
+
{
|
41
|
+
per_page: 100,
|
42
|
+
options: {
|
43
|
+
fields: %w[name completed_at due_at due_on tags
|
44
|
+
memberships.project.gid memberships.section.name dependencies],
|
45
|
+
},
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
38
49
|
# pulls an Asana API project class given a name
|
39
50
|
def project(workspace_name, project_name)
|
40
51
|
if project_name.is_a?(Symbol) && project_name.to_s.start_with?('my_tasks')
|
@@ -84,15 +95,5 @@ module Checkoff
|
|
84
95
|
gid = result.gid
|
85
96
|
projects.find_by_id(gid)
|
86
97
|
end
|
87
|
-
|
88
|
-
def task_options
|
89
|
-
{
|
90
|
-
per_page: 100,
|
91
|
-
options: {
|
92
|
-
fields: %w[name completed_at due_at due_on assignee_status tags
|
93
|
-
memberships.project.gid memberships.section.name dependencies],
|
94
|
-
},
|
95
|
-
}
|
96
|
-
end
|
97
98
|
end
|
98
99
|
end
|
data/lib/checkoff/sections.rb
CHANGED
@@ -4,7 +4,6 @@ require 'forwardable'
|
|
4
4
|
|
5
5
|
module Checkoff
|
6
6
|
# Query different sections of Asana projects
|
7
|
-
# rubocop:disable Metrics/ClassLength
|
8
7
|
class Sections
|
9
8
|
MINUTE = 60
|
10
9
|
LONG_CACHE_TIME = MINUTE * 15
|
@@ -23,118 +22,74 @@ module Checkoff
|
|
23
22
|
@time = time
|
24
23
|
end
|
25
24
|
|
26
|
-
#
|
27
|
-
def
|
28
|
-
|
29
|
-
|
30
|
-
file_task_by_section(by_section, task, project_gid)
|
31
|
-
end
|
32
|
-
by_section
|
33
|
-
end
|
34
|
-
cache_method :by_section, LONG_CACHE_TIME
|
35
|
-
|
36
|
-
# Given a project object, pull all tasks, then provide a Hash of
|
37
|
-
# tasks with section name -> task list of the uncompleted tasks
|
38
|
-
def tasks_by_section_for_project(project)
|
39
|
-
raw_tasks = projects.tasks_from_project(project)
|
40
|
-
active_tasks = projects.active_tasks(raw_tasks)
|
41
|
-
by_section(active_tasks, project.gid)
|
25
|
+
# Returns a list of Asana API section objects for a given project
|
26
|
+
def sections_or_raise(workspace_name, project_name)
|
27
|
+
project = project_or_raise(workspace_name, project_name)
|
28
|
+
client.sections.get_sections_for_project(project_gid: project.gid)
|
42
29
|
end
|
43
30
|
|
44
31
|
# Given a workspace name and project name, then provide a Hash of
|
45
32
|
# tasks with section name -> task list of the uncompleted tasks
|
46
33
|
def tasks_by_section(workspace_name, project_name)
|
47
34
|
project = project_or_raise(workspace_name, project_name)
|
48
|
-
|
49
|
-
when :my_tasks, :my_tasks_new, :my_tasks_today, :my_tasks_upcoming
|
50
|
-
user_task_list_by_section(workspace_name, project_name)
|
51
|
-
else
|
52
|
-
tasks_by_section_for_project(project)
|
53
|
-
end
|
35
|
+
tasks_by_section_for_project(project)
|
54
36
|
end
|
55
37
|
cache_method :tasks_by_section, SHORT_CACHE_TIME
|
56
38
|
|
57
39
|
# XXX: Rename to section_tasks
|
58
40
|
#
|
59
41
|
# Pulls task objects from a specified section
|
60
|
-
def tasks(workspace_name, project_name, section_name
|
61
|
-
|
42
|
+
def tasks(workspace_name, project_name, section_name,
|
43
|
+
only_uncompleted: true,
|
44
|
+
extra_fields: [])
|
45
|
+
section = section_or_raise(workspace_name, project_name, section_name)
|
46
|
+
options = projects.task_options
|
47
|
+
# asana-0.10.3 gem doesn't support per_page - not sure if API
|
48
|
+
# itself does
|
49
|
+
options.delete(:per_page)
|
50
|
+
options[:options][:fields] += extra_fields
|
51
|
+
client.tasks.get_tasks_for_section(section_gid: section.gid,
|
52
|
+
**options).to_a
|
62
53
|
end
|
63
54
|
cache_method :tasks, SHORT_CACHE_TIME
|
64
55
|
|
65
56
|
# Pulls just names of tasks from a given section.
|
66
57
|
def section_task_names(workspace_name, project_name, section_name)
|
67
58
|
tasks = tasks(workspace_name, project_name, section_name)
|
68
|
-
if tasks.nil?
|
69
|
-
by_section = tasks_by_section(workspace_name, project_name)
|
70
|
-
desc = "#{workspace_name} | #{project_name} | #{section_name}"
|
71
|
-
raise "Could not find task names for #{desc}. " \
|
72
|
-
"Valid sections: #{by_section.keys}"
|
73
|
-
end
|
74
59
|
tasks.map(&:name)
|
75
60
|
end
|
76
61
|
cache_method :section_task_names, SHORT_CACHE_TIME
|
77
62
|
|
78
|
-
# returns if a task's due field is at or before the current date/time
|
79
|
-
def task_due?(task)
|
80
|
-
if task.due_at
|
81
|
-
Time.parse(task.due_at) <= time.now
|
82
|
-
elsif task.due_on
|
83
|
-
Date.parse(task.due_on) <= time.today
|
84
|
-
else
|
85
|
-
true # set a due date if you don't want to do this now
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
63
|
private
|
90
64
|
|
91
|
-
|
92
|
-
|
93
|
-
def
|
94
|
-
membership = task.memberships.find { |m| m['project']['gid'] == project_gid }
|
95
|
-
raise "Could not find task in project_gid #{project_gid}: #{task}" if membership.nil?
|
96
|
-
|
97
|
-
current_section = membership['section']['name']
|
98
|
-
current_section = nil if current_section == '(no section)'
|
99
|
-
by_section[current_section] ||= []
|
100
|
-
by_section[current_section] << task
|
101
|
-
end
|
102
|
-
|
103
|
-
def legacy_tasks_by_section_for_project(project)
|
65
|
+
# Given a project object, pull all tasks, then provide a Hash of
|
66
|
+
# tasks with section name -> task list of the uncompleted tasks
|
67
|
+
def tasks_by_section_for_project(project)
|
104
68
|
raw_tasks = projects.tasks_from_project(project)
|
105
69
|
active_tasks = projects.active_tasks(raw_tasks)
|
106
|
-
|
70
|
+
by_section(active_tasks, project.gid)
|
107
71
|
end
|
108
72
|
|
109
|
-
|
110
|
-
if task.name =~ /:$/
|
111
|
-
current_section = task.name
|
112
|
-
by_section[current_section] = []
|
113
|
-
else
|
114
|
-
by_section[current_section] ||= []
|
115
|
-
by_section[current_section] << task
|
116
|
-
end
|
117
|
-
[current_section, by_section]
|
118
|
-
end
|
73
|
+
def_delegators :@projects, :client
|
119
74
|
|
120
|
-
|
121
|
-
|
75
|
+
# Given a list of tasks, pull a Hash of tasks with section name -> task list
|
76
|
+
def by_section(tasks, project_gid)
|
122
77
|
by_section = {}
|
123
78
|
tasks.each do |task|
|
124
|
-
|
125
|
-
legacy_file_task_by_section(current_section, by_section, task)
|
79
|
+
file_task_by_section(by_section, task, project_gid)
|
126
80
|
end
|
127
81
|
by_section
|
128
82
|
end
|
83
|
+
cache_method :by_section, LONG_CACHE_TIME
|
129
84
|
|
130
|
-
def
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
85
|
+
def file_task_by_section(by_section, task, project_gid)
|
86
|
+
membership = task.memberships.find { |m| m['project']['gid'] == project_gid }
|
87
|
+
raise "Could not find task in project_gid #{project_gid}: #{task}" if membership.nil?
|
88
|
+
|
89
|
+
current_section = membership['section']['name']
|
90
|
+
current_section = nil if current_section == '(no section)'
|
91
|
+
by_section[current_section] ||= []
|
92
|
+
by_section[current_section] << task
|
138
93
|
end
|
139
94
|
|
140
95
|
def project_or_raise(workspace_name, project_name)
|
@@ -146,49 +101,20 @@ module Checkoff
|
|
146
101
|
project
|
147
102
|
end
|
148
103
|
|
149
|
-
def
|
150
|
-
|
151
|
-
|
152
|
-
raise NotImplementedError, 'Section-based user task lists not yet supported'
|
104
|
+
def section(workspace_name, project_name, section_name)
|
105
|
+
sections = sections_or_raise(workspace_name, project_name)
|
106
|
+
sections.find { |section| section.name.chomp(':') == section_name.chomp(':') }
|
153
107
|
end
|
154
108
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
}.freeze
|
160
|
-
|
161
|
-
def user_task_list_by_section(workspace_name, project_name)
|
162
|
-
verify_legacy_user_task_list!(workspace_name)
|
163
|
-
|
164
|
-
project = projects.project(workspace_name, project_name)
|
165
|
-
if project_name == :my_tasks
|
166
|
-
legacy_tasks_by_section_for_project(project)
|
167
|
-
else
|
168
|
-
legacy_tasks_by_section_for_project_and_assignee_status(project,
|
169
|
-
ASSIGNEE_STATUS_BY_PROJECT_NAME.fetch(project_name))
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
def user_task_list_migrated_to_real_sections?(workspace_name)
|
174
|
-
workspace = workspaces.workspace_by_name(workspace_name)
|
175
|
-
result = client.user_task_lists.get_user_task_list_for_user(user_gid: 'me',
|
176
|
-
workspace: workspace.gid)
|
177
|
-
result.migration_status != 'not_migrated'
|
178
|
-
end
|
109
|
+
def section_or_raise(workspace_name, project_name, section_name)
|
110
|
+
section = section(workspace_name, project_name, section_name)
|
111
|
+
if section.nil?
|
112
|
+
valid_sections = sections_or_raise(workspace_name, project_name).map(&:name)
|
179
113
|
|
180
|
-
|
181
|
-
|
182
|
-
by_section.flat_map do |section_name, tasks|
|
183
|
-
task_names = tasks.map(&:name)
|
184
|
-
if section_name.nil?
|
185
|
-
task_names
|
186
|
-
else
|
187
|
-
[section_name, task_names]
|
188
|
-
end
|
114
|
+
raise "Could not find section #{section_name} under project #{project_name} " \
|
115
|
+
"under workspace #{workspace_name}. Valid sections: #{valid_sections}"
|
189
116
|
end
|
117
|
+
section
|
190
118
|
end
|
191
|
-
cache_method :project_task_names, SHORT_CACHE_TIME
|
192
119
|
end
|
193
|
-
# rubocop:enable Metrics/ClassLength
|
194
120
|
end
|
data/lib/checkoff/tasks.rb
CHANGED
data/lib/checkoff/version.rb
CHANGED
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.
|
4
|
+
version: 0.12.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: 2021-
|
11
|
+
date: 2021-07-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|