checkoff 0.5.5 → 0.10.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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +119 -12
  3. data/.envrc +2 -0
  4. data/.git-hooks/pre_commit/circle_ci.rb +21 -0
  5. data/.gitignore +50 -1
  6. data/.overcommit.yml +53 -0
  7. data/.rubocop.yml +64 -168
  8. data/.yamllint.yml +8 -0
  9. data/CODE_OF_CONDUCT.md +120 -36
  10. data/DEVELOPMENT.md +28 -0
  11. data/Gemfile.lock +130 -0
  12. data/{LICENSE.txt → LICENSE} +7 -6
  13. data/Makefile +48 -18
  14. data/README.md +15 -2
  15. data/Rakefile +2 -9
  16. data/bin/bump +29 -0
  17. data/bin/checkoff +29 -0
  18. data/bin/overcommit +29 -0
  19. data/bin/rake +29 -0
  20. data/checkoff.gemspec +9 -5
  21. data/coverage/.last_run.json +2 -1
  22. data/docs/cookiecutter_input.json +13 -0
  23. data/fix.sh +299 -0
  24. data/lib/checkoff/cli.rb +9 -1
  25. data/lib/checkoff/config_loader.rb +43 -3
  26. data/lib/checkoff/projects.rb +5 -5
  27. data/lib/checkoff/sections.rb +48 -11
  28. data/lib/checkoff/tasks.rb +1 -1
  29. data/lib/checkoff/version.rb +1 -1
  30. data/lib/checkoff/workspaces.rb +4 -3
  31. data/metrics/bigfiles_high_water_mark +1 -1
  32. data/metrics/rubocop_high_water_mark +1 -1
  33. data/{lib/tasks → rakelib}/ci.rake +0 -0
  34. data/{lib/tasks → rakelib}/clear_metrics.rake +1 -1
  35. data/{lib/tasks → rakelib}/default.rake +0 -0
  36. data/rakelib/gem_tasks.rake +3 -0
  37. data/{lib/tasks → rakelib}/localtest.rake +1 -1
  38. data/rakelib/overcommit.rake +6 -0
  39. data/rakelib/quality.rake +4 -0
  40. data/{lib/tasks → rakelib}/test.rake +0 -0
  41. data/rakelib/undercover.rake +8 -0
  42. data/requirements_dev.txt +2 -0
  43. metadata +93 -25
  44. data/.ruby-version +0 -1
  45. data/.travis.yml +0 -22
  46. data/lib/tasks/feature.rake +0 -9
  47. data/lib/tasks/quality.rake +0 -9
  48. data/lib/tasks/spec.rake +0 -9
data/lib/checkoff/cli.rb CHANGED
@@ -12,6 +12,7 @@ require_relative 'sections'
12
12
 
13
13
  module Checkoff
14
14
  # Provide ability for CLI to pull Asana items
15
+ # rubocop:disable Metrics/ClassLength
15
16
  class CLI
16
17
  attr_reader :sections, :stderr
17
18
 
@@ -86,6 +87,7 @@ module Checkoff
86
87
  subargs.task_name = args[2]
87
88
  end
88
89
 
90
+ # rubocop:disable Metrics/MethodLength
89
91
  def parse_args(args)
90
92
  mode = args[0]
91
93
  subargs = OpenStruct.new
@@ -99,6 +101,7 @@ module Checkoff
99
101
  end
100
102
  [mode, subargs]
101
103
  end
104
+ # rubocop:enable Metrics/MethodLength
102
105
 
103
106
  def output_help
104
107
  stderr.puts 'View tasks:'
@@ -110,7 +113,11 @@ module Checkoff
110
113
  end
111
114
 
112
115
  def view(workspace_name, project_name, section_name)
113
- project_name = project_name[1..-1].to_sym if project_name.start_with? ':'
116
+ if project_name.nil?
117
+ stderr.puts 'Please specify a project name'
118
+ exit(1)
119
+ end
120
+ project_name = project_name[1..].to_sym if project_name.start_with? ':'
114
121
  if section_name.nil?
115
122
  run_on_project(workspace_name, project_name)
116
123
  else
@@ -131,4 +138,5 @@ module Checkoff
131
138
  end
132
139
  end
133
140
  end
141
+ # rubocop:enable Metrics/ClassLength
134
142
  end
@@ -4,12 +4,52 @@ require 'yaml'
4
4
  require 'active_support/core_ext/hash'
5
5
 
6
6
  module Checkoff
7
+ # Use the provided config from a YAML file, and fall back to env
8
+ # variable if it's not populated for a key'
9
+ class EnvFallbackConfigLoader
10
+ def initialize(config, sym, yaml_filename)
11
+ @config = config
12
+ @envvar_prefix = sym.upcase
13
+ @yaml_filename = yaml_filename
14
+ end
15
+
16
+ def envvar_name(key)
17
+ "#{@envvar_prefix}__#{key.upcase}"
18
+ end
19
+
20
+ def [](key)
21
+ config_value = @config[key]
22
+ return config_value unless config_value.nil?
23
+
24
+ ENV[envvar_name(key)]
25
+ end
26
+
27
+ def fetch(key)
28
+ out = self[key]
29
+ return out unless out.nil?
30
+
31
+ raise KeyError,
32
+ "Please configure either the #{key} key in #{@yaml_filename} or set #{envvar_name(key)}"
33
+ end
34
+ end
35
+
7
36
  # Load configuration file
8
37
  class ConfigLoader
9
- def self.load(sym)
38
+ def self.yaml_filename(sym)
10
39
  file = "#{sym}.yml"
11
- YAML.load_file(File.expand_path("~/.#{file}"))
12
- .with_indifferent_access
40
+ File.expand_path("~/.#{file}")
41
+ end
42
+
43
+ def self.load_yaml_file(sym)
44
+ filename = yaml_filename(sym)
45
+ return {} unless File.exist?(filename)
46
+
47
+ YAML.load_file(filename).with_indifferent_access
48
+ end
49
+
50
+ def self.load(sym)
51
+ yaml_result = load_yaml_file(sym)
52
+ EnvFallbackConfigLoader.new(yaml_result, sym, yaml_filename(sym))
13
53
  end
14
54
  end
15
55
  end
@@ -49,10 +49,10 @@ module Checkoff
49
49
  end
50
50
 
51
51
  def my_tasks(workspace_name)
52
- my_tasks = @config[:my_tasks]
53
- gid = @config[:my_tasks][workspace_name] unless my_tasks.nil?
54
- raise "Please define [:my_tasks][#{workspace_name}] in config file" if my_tasks.nil? || gid.nil?
55
-
52
+ workspace = @workspaces.workspace_by_name(workspace_name)
53
+ result = client.user_task_lists.get_user_task_list_for_user(user_gid: 'me',
54
+ workspace: workspace.gid)
55
+ gid = result.gid
56
56
  projects.find_by_id(gid)
57
57
  end
58
58
 
@@ -77,7 +77,7 @@ module Checkoff
77
77
  per_page: 100,
78
78
  options: {
79
79
  fields: %w[name completed_at due_at due_on assignee_status tags
80
- memberships.project.gid memberships.section.name],
80
+ memberships.project.gid memberships.section.name dependencies],
81
81
  },
82
82
  }
83
83
  end
@@ -4,6 +4,7 @@ require 'forwardable'
4
4
 
5
5
  module Checkoff
6
6
  # Query different sections of Asana projects
7
+ # rubocop:disable Metrics/ClassLength
7
8
  class Sections
8
9
  MINUTE = 60
9
10
  LONG_CACHE_TIME = MINUTE * 15
@@ -11,12 +12,14 @@ module Checkoff
11
12
 
12
13
  extend Forwardable
13
14
 
14
- attr_reader :projects, :time
15
+ attr_reader :projects, :workspaces, :time
15
16
 
16
17
  def initialize(config: Checkoff::ConfigLoader.load(:asana),
17
18
  projects: Checkoff::Projects.new(config: config),
19
+ workspaces: Checkoff::Workspaces.new(config: config),
18
20
  time: Time)
19
21
  @projects = projects
22
+ @workspaces = workspaces
20
23
  @time = time
21
24
  end
22
25
 
@@ -41,6 +44,12 @@ module Checkoff
41
44
  end
42
45
  cache_method :by_section, LONG_CACHE_TIME
43
46
 
47
+ def legacy_tasks_by_section_for_project(project)
48
+ raw_tasks = projects.tasks_from_project(project)
49
+ active_tasks = projects.active_tasks(raw_tasks)
50
+ legacy_by_section(active_tasks)
51
+ end
52
+
44
53
  def tasks_by_section_for_project(project)
45
54
  raw_tasks = projects.tasks_from_project(project)
46
55
  active_tasks = projects.active_tasks(raw_tasks)
@@ -68,12 +77,12 @@ module Checkoff
68
77
  by_section
69
78
  end
70
79
 
71
- def tasks_by_section_for_project_and_assignee_status(project,
72
- assignee_status)
80
+ def legacy_tasks_by_section_for_project_and_assignee_status(project,
81
+ assignee_status)
73
82
  raw_tasks = projects.tasks_from_project(project)
74
83
  by_assignee_status =
75
84
  projects.active_tasks(raw_tasks)
76
- .group_by(&:assignee_status)
85
+ .group_by(&:assignee_status)
77
86
  active_tasks = by_assignee_status[assignee_status]
78
87
  legacy_by_section(active_tasks)
79
88
  end
@@ -87,15 +96,35 @@ module Checkoff
87
96
  project
88
97
  end
89
98
 
99
+ def verify_legacy_user_task_list!(workspace_name)
100
+ return unless user_task_list_migrated_to_real_sections?(workspace_name)
101
+
102
+ raise NotImplementedError, 'Section-based user task lists not yet supported'
103
+ end
104
+
105
+ ASSIGNEE_STATUS_BY_PROJECT_NAME = {
106
+ my_tasks_new: 'inbox',
107
+ my_tasks_today: 'today',
108
+ my_tasks_upcoming: 'upcoming',
109
+ }.freeze
110
+
111
+ def user_task_list_by_section(workspace_name, project_name)
112
+ verify_legacy_user_task_list!(workspace_name)
113
+
114
+ project = projects.project(workspace_name, project_name)
115
+ if project_name == :my_tasks
116
+ legacy_tasks_by_section_for_project(project)
117
+ else
118
+ legacy_tasks_by_section_for_project_and_assignee_status(project,
119
+ ASSIGNEE_STATUS_BY_PROJECT_NAME.fetch(project_name))
120
+ end
121
+ end
122
+
90
123
  def tasks_by_section(workspace_name, project_name)
91
124
  project = project_or_raise(workspace_name, project_name)
92
125
  case project_name
93
- when :my_tasks_new
94
- tasks_by_section_for_project_and_assignee_status(project, 'inbox')
95
- when :my_tasks_today
96
- tasks_by_section_for_project_and_assignee_status(project, 'today')
97
- when :my_tasks_upcoming
98
- tasks_by_section_for_project_and_assignee_status(project, 'upcoming')
126
+ when :my_tasks, :my_tasks_new, :my_tasks_today, :my_tasks_upcoming
127
+ user_task_list_by_section(workspace_name, project_name)
99
128
  else
100
129
  tasks_by_section_for_project(project)
101
130
  end
@@ -104,7 +133,7 @@ module Checkoff
104
133
 
105
134
  # XXX: Rename to section_tasks
106
135
  def tasks(workspace_name, project_name, section_name)
107
- tasks_by_section(workspace_name, project_name)[section_name]
136
+ tasks_by_section(workspace_name, project_name).fetch(section_name, [])
108
137
  end
109
138
  cache_method :tasks, SHORT_CACHE_TIME
110
139
 
@@ -120,6 +149,13 @@ module Checkoff
120
149
  end
121
150
  cache_method :section_task_names, SHORT_CACHE_TIME
122
151
 
152
+ def user_task_list_migrated_to_real_sections?(workspace_name)
153
+ workspace = workspaces.workspace_by_name(workspace_name)
154
+ result = client.user_task_lists.get_user_task_list_for_user(user_gid: 'me',
155
+ workspace: workspace.gid)
156
+ result.migration_status != 'not_migrated'
157
+ end
158
+
123
159
  def task_due?(task)
124
160
  if task.due_at
125
161
  Time.parse(task.due_at) <= time.now
@@ -143,4 +179,5 @@ module Checkoff
143
179
  end
144
180
  cache_method :project_task_names, SHORT_CACHE_TIME
145
181
  end
182
+ # rubocop:enable Metrics/ClassLength
146
183
  end
@@ -50,7 +50,7 @@ module Checkoff
50
50
  end
51
51
 
52
52
  def default_assignee_gid
53
- @config[:default_assignee_gid]
53
+ @config.fetch(:default_assignee_gid)
54
54
  end
55
55
  end
56
56
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Checkoff
4
- VERSION = '0.5.5'
4
+ VERSION = '0.10.0'
5
5
  end
@@ -11,19 +11,20 @@ module Checkoff
11
11
 
12
12
  def client
13
13
  @client ||= @asana_client.new do |c|
14
- c.authentication :access_token, @config[:personal_access_token]
14
+ c.authentication :access_token, @config.fetch(:personal_access_token)
15
15
  c.default_headers 'asana-enable' => 'string_ids,new_sections'
16
+ c.default_headers 'asana-disable' => 'new_user_task_lists'
16
17
  end
17
18
  end
18
19
 
19
20
  def default_workspace_gid
20
- @config[:default_workspace_gid]
21
+ @config.fetch(:default_workspace_gid)
21
22
  end
22
23
 
23
24
  def workspace_by_name(workspace_name)
24
25
  client.workspaces.find_all.find do |workspace|
25
26
  workspace.name == workspace_name
26
- end || raise("Could not find workspace #{workspace_name}")
27
+ end || raise("Could not find workspace named [#{workspace_name}]")
27
28
  end
28
29
  end
29
30
  end
@@ -1 +1 @@
1
- 414
1
+ 488
@@ -1 +1 @@
1
- 4
1
+ 6
File without changes
@@ -3,6 +3,6 @@
3
3
  desc 'Rebaseline quality thresholds to last commit'
4
4
  task :clear_metrics do |_t|
5
5
  ret =
6
- system('git checkout coverage/.last_run.json metrics/*_high_water_mark')
6
+ system('git checkout coverage/.last_run.json')
7
7
  raise unless ret
8
8
  end
File without changes
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  desc 'Standard build when running on a workstation'
4
- task localtest: %i[clear_metrics test quality]
4
+ task localtest: %i[clear_metrics test undercover quality]
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ desc 'Run overcommit on current code'
4
+ task :overcommit do
5
+ sh 'overcommit --run'
6
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ desc 'Run quality checks'
4
+ task quality: :overcommit
File without changes
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ desc 'Ensure PR changes are fully covered by tests'
4
+ task :undercover do |_t|
5
+ ret =
6
+ system('undercover --compare origin/main')
7
+ raise unless ret
8
+ end
@@ -0,0 +1,2 @@
1
+ pip==21.0.1
2
+ yamllint==1.26.0
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.5.5
4
+ version: 0.10.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: 2020-12-30 00:00:00.000000000 Z
11
+ date: 2021-05-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bump
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: bundler
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -109,19 +123,19 @@ dependencies:
109
123
  - !ruby/object:Gem::Version
110
124
  version: '0'
111
125
  - !ruby/object:Gem::Dependency
112
- name: quality
126
+ name: overcommit
113
127
  requirement: !ruby/object:Gem::Requirement
114
128
  requirements:
115
- - - "~>"
129
+ - - ">="
116
130
  - !ruby/object:Gem::Version
117
- version: '38'
131
+ version: '0'
118
132
  type: :development
119
133
  prerelease: false
120
134
  version_requirements: !ruby/object:Gem::Requirement
121
135
  requirements:
122
- - - "~>"
136
+ - - ">="
123
137
  - !ruby/object:Gem::Version
124
- version: '38'
138
+ version: '0'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: rake
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -137,19 +151,47 @@ dependencies:
137
151
  - !ruby/object:Gem::Version
138
152
  version: '13.0'
139
153
  - !ruby/object:Gem::Dependency
140
- name: rspec
154
+ name: rubocop
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: rubocop-minitest
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: rubocop-rake
141
183
  requirement: !ruby/object:Gem::Requirement
142
184
  requirements:
143
185
  - - ">="
144
186
  - !ruby/object:Gem::Version
145
- version: '3.4'
187
+ version: '0'
146
188
  type: :development
147
189
  prerelease: false
148
190
  version_requirements: !ruby/object:Gem::Requirement
149
191
  requirements:
150
192
  - - ">="
151
193
  - !ruby/object:Gem::Version
152
- version: '3.4'
194
+ version: '0'
153
195
  - !ruby/object:Gem::Dependency
154
196
  name: simplecov
155
197
  requirement: !ruby/object:Gem::Requirement
@@ -164,6 +206,20 @@ dependencies:
164
206
  - - ">="
165
207
  - !ruby/object:Gem::Version
166
208
  version: '0'
209
+ - !ruby/object:Gem::Dependency
210
+ name: undercover
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - ">="
214
+ - !ruby/object:Gem::Version
215
+ version: '0'
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
167
223
  description:
168
224
  email:
169
225
  - vince@broz.cc
@@ -173,22 +229,32 @@ extensions: []
173
229
  extra_rdoc_files: []
174
230
  files:
175
231
  - ".circleci/config.yml"
232
+ - ".envrc"
233
+ - ".git-hooks/pre_commit/circle_ci.rb"
176
234
  - ".gitignore"
235
+ - ".overcommit.yml"
177
236
  - ".rubocop.yml"
178
- - ".ruby-version"
179
- - ".travis.yml"
237
+ - ".yamllint.yml"
180
238
  - CODE_OF_CONDUCT.md
239
+ - DEVELOPMENT.md
181
240
  - Gemfile
182
- - LICENSE.txt
241
+ - Gemfile.lock
242
+ - LICENSE
183
243
  - Makefile
184
244
  - README.md
185
245
  - Rakefile
246
+ - bin/bump
247
+ - bin/checkoff
186
248
  - bin/console
249
+ - bin/overcommit
250
+ - bin/rake
187
251
  - bin/setup
188
252
  - checkoff.gemspec
189
253
  - coverage/.last_run.json
254
+ - docs/cookiecutter_input.json
190
255
  - docs/example_project.png
191
256
  - exe/checkoff
257
+ - fix.sh
192
258
  - lib/checkoff.rb
193
259
  - lib/checkoff/cli.rb
194
260
  - lib/checkoff/config_loader.rb
@@ -198,14 +264,6 @@ files:
198
264
  - lib/checkoff/tasks.rb
199
265
  - lib/checkoff/version.rb
200
266
  - lib/checkoff/workspaces.rb
201
- - lib/tasks/ci.rake
202
- - lib/tasks/clear_metrics.rake
203
- - lib/tasks/default.rake
204
- - lib/tasks/feature.rake
205
- - lib/tasks/localtest.rake
206
- - lib/tasks/quality.rake
207
- - lib/tasks/spec.rake
208
- - lib/tasks/test.rake
209
267
  - metrics/bigfiles_high_water_mark
210
268
  - metrics/brakeman_high_water_mark
211
269
  - metrics/bundle-audit_high_water_mark
@@ -223,9 +281,19 @@ files:
223
281
  - metrics/rubocop_high_water_mark
224
282
  - metrics/scalastyle_high_water_mark
225
283
  - metrics/shellcheck_high_water_mark
226
- homepage: http://github.com/apiology/checkoff
284
+ - rakelib/ci.rake
285
+ - rakelib/clear_metrics.rake
286
+ - rakelib/default.rake
287
+ - rakelib/gem_tasks.rake
288
+ - rakelib/localtest.rake
289
+ - rakelib/overcommit.rake
290
+ - rakelib/quality.rake
291
+ - rakelib/test.rake
292
+ - rakelib/undercover.rake
293
+ - requirements_dev.txt
294
+ homepage: https://github.com/apiology/checkoff
227
295
  licenses:
228
- - MIT
296
+ - MIT license
229
297
  metadata: {}
230
298
  post_install_message:
231
299
  rdoc_options: []
@@ -235,14 +303,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
235
303
  requirements:
236
304
  - - ">="
237
305
  - !ruby/object:Gem::Version
238
- version: '2.5'
306
+ version: '2.6'
239
307
  required_rubygems_version: !ruby/object:Gem::Requirement
240
308
  requirements:
241
309
  - - ">="
242
310
  - !ruby/object:Gem::Version
243
311
  version: '0'
244
312
  requirements: []
245
- rubygems_version: 3.0.3
313
+ rubygems_version: 3.1.2
246
314
  signing_key:
247
315
  specification_version: 4
248
316
  summary: Command-line and gem client for Asana (unofficial)