checkoff 0.5.3 → 0.8.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: 7c4947b2573662cc82bf0fd8652c9efc13169326fb70952e3794aecd3a071a1c
4
- data.tar.gz: 97d4f7ec0a0781a62750462fc0a7428980f06a6d084c029b832897f854fd3d32
3
+ metadata.gz: 834d9600b69c5f79ba30cbf22a79c66d0a277d517cafe6c2aee32de1c63bb533
4
+ data.tar.gz: 5cb97edadfd9aca288f6f1e5d95400c0e291306ffd2f3a76ad003560539b88cb
5
5
  SHA512:
6
- metadata.gz: 02e3a309b680887411309fa3f33d8f14a325889f1bfbf5c18790cec9ab20aa80a0e71ab38fdcfa7eefe523474dd2a56bf0443b3523fc0cb0bd90719dd380fcf9
7
- data.tar.gz: 22f2339cda88ee9ee63d6009e945d29bf2a7d9b552b0eae3d2a39892bc1f85e3ce373afd341fde97d24719ad89fbf804250fd4450761a4920ab00bc0e17b465d
6
+ metadata.gz: 83050b84c4cc44b0c5992174cfe8f837f985dd361627ed60e81466f9cb14713b87d14508c9d46d997e9887c8944557252a64bd79f3354c04285c852758fd5021
7
+ data.tar.gz: '083875c0f26f4309170d036ccec8dc3bb970ddf276916f1744ac0bd1285055de662ac7b29054bceba10fe82baba0ef319731ab32de522fb773a3af824ba687c1'
data/.envrc ADDED
@@ -0,0 +1,2 @@
1
+ PATH_add bin
2
+ eval $(with-op op-env sh)
data/.overcommit.yml ADDED
@@ -0,0 +1,40 @@
1
+ # Use this file to configure the Overcommit hooks you wish to use. This will
2
+ # extend the default configuration defined in:
3
+ # https://github.com/sds/overcommit/blob/master/config/default.yml
4
+ #
5
+ # At the topmost level of this YAML file is a key representing type of hook
6
+ # being run (e.g. pre-commit, commit-msg, etc.). Within each type you can
7
+ # customize each hook, such as whether to only run it on certain files (via
8
+ # `include`), whether to only display output if it fails (via `quiet`), etc.
9
+ #
10
+ # For a complete list of hooks, see:
11
+ # https://github.com/sds/overcommit/tree/master/lib/overcommit/hook
12
+ #
13
+ # For a complete list of options that you can use to customize hooks, see:
14
+ # https://github.com/sds/overcommit#configuration
15
+ #
16
+ # Uncomment the following lines to make the configuration take effect.
17
+
18
+ PreCommit:
19
+ RuboCop:
20
+ enabled: true
21
+ on_warn: fail # Treat all warnings as failures
22
+ #
23
+ # TrailingWhitespace:
24
+ # enabled: true
25
+ # exclude:
26
+ # - '**/db/structure.sql' # Ignore trailing whitespace in generated files
27
+ #
28
+ #PostCheckout:
29
+ # ALL: # Special hook name that customizes all hooks of this type
30
+ # quiet: true # Change all post-checkout hooks to only display output on failure
31
+ #
32
+ # IndexTags:
33
+ # enabled: true # Generate a tags file with `ctags` each time HEAD changes
34
+
35
+ PrePush:
36
+ Minitest:
37
+ command: ['ruby', '-Ilib:test/unit:lib/checkoff', '-rbundler/setup', '-rminitest', "-e 'exit! Minitest.run'"]
38
+ include:
39
+ - 'test/unit/**/test*.rb'
40
+ enabled: true
data/.rubocop.yml CHANGED
@@ -194,7 +194,9 @@ RSpec/StubbedMock: # (new in 1.44)
194
194
  Enabled: true
195
195
 
196
196
  AllCops:
197
- TargetRubyVersion: 2.6
197
+ TargetRubyVersion: 2.5
198
+ Exclude:
199
+ - 'bin/*'
198
200
 
199
201
  require:
200
202
  - rubocop-rspec
data/.travis.yml CHANGED
@@ -10,8 +10,13 @@ rvm:
10
10
  # checking for main() in -lstdc++... RuntimeError: The compiler failed to generate
11
11
  # https://travis-ci.com/apiology/pronto-punchlist/jobs/264907931
12
12
  # - jruby-head
13
- - ruby-head
13
+
14
+ # These are currently pending ruby-asana fixes:
15
+ #
16
+ # https://github.com/Asana/ruby-asana/pull/99
17
+ #
18
+ # - ruby-head
19
+ # - ruby-3.0
14
20
  - ruby-2.7
15
21
  - ruby-2.6
16
22
  - ruby-2.5
17
- - ruby-2.4
data/README.md CHANGED
@@ -126,6 +126,8 @@ my_tasks:
126
126
  personal_access_token: 'some_big_long_string_from_asana.com_here'
127
127
  ```
128
128
 
129
+ Alternately you can set environment variables to match - e.g., `ASANA__PERSONAL_ACCESS_TOKEN`
130
+
129
131
  ## Developing
130
132
 
131
133
  ```bash
data/bin/checkoff ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'checkoff' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("checkoff", "checkoff")
data/checkoff.gemspec CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
13
13
  spec.summary = 'Command-line and gem client for Asana (unofficial)'
14
14
  spec.homepage = 'http://github.com/apiology/checkoff'
15
15
  spec.license = 'MIT'
16
- spec.required_ruby_version = '>= 2.6'
16
+ spec.required_ruby_version = '>= 2.5'
17
17
 
18
18
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
19
  f.match(%r{^(test|spec|features)/})
@@ -30,6 +30,7 @@ Gem::Specification.new do |spec|
30
30
  spec.add_development_dependency 'bundler'
31
31
  spec.add_development_dependency 'minitest-profile'
32
32
  spec.add_development_dependency 'mocha'
33
+ spec.add_development_dependency 'overcommit'
33
34
  spec.add_development_dependency 'quality', '~> 38'
34
35
  spec.add_development_dependency 'rake', '~> 13.0'
35
36
  spec.add_development_dependency 'rspec', '>=3.4'
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "result": {
3
- "covered_percent": 83.74
3
+ "covered_percent": 89.61
4
4
  }
5
5
  }
data/lib/checkoff/cli.rb CHANGED
@@ -110,7 +110,11 @@ module Checkoff
110
110
  end
111
111
 
112
112
  def view(workspace_name, project_name, section_name)
113
- project_name = project_name[1..].to_sym if project_name.start_with? ':'
113
+ if project_name.nil?
114
+ stderr.puts 'Please specify a project name'
115
+ exit(1)
116
+ end
117
+ project_name = project_name[1..-1].to_sym if project_name.start_with? ':'
114
118
  if section_name.nil?
115
119
  run_on_project(workspace_name, project_name)
116
120
  else
@@ -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,8 +49,8 @@ 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?
52
+ my_tasks = @config.fetch(:my_tasks)
53
+ gid = my_tasks[workspace_name] unless my_tasks.nil?
54
54
  raise "Please define [:my_tasks][#{workspace_name}] in config file" if my_tasks.nil? || gid.nil?
55
55
 
56
56
  projects.find_by_id(gid)
@@ -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
@@ -11,22 +11,24 @@ module Checkoff
11
11
 
12
12
  extend Forwardable
13
13
 
14
- attr_reader :projects, :time
14
+ attr_reader :projects, :workspaces, :time
15
15
 
16
16
  def initialize(config: Checkoff::ConfigLoader.load(:asana),
17
17
  projects: Checkoff::Projects.new(config: config),
18
+ workspaces: Checkoff::Workspaces.new(config: config),
18
19
  time: Time)
19
20
  @projects = projects
21
+ @workspaces = workspaces
20
22
  @time = time
21
23
  end
22
24
 
23
25
  def_delegators :@projects, :client
24
26
 
25
27
  def file_task_by_section(by_section, task, project_gid)
26
- membership = task.memberships.find { |m| m.project.gid == project_gid }
28
+ membership = task.memberships.find { |m| m['project']['gid'] == project_gid }
27
29
  raise "Could not find task in project_gid #{project_gid}: #{task}" if membership.nil?
28
30
 
29
- current_section = membership.section.name
31
+ current_section = membership['section']['name']
30
32
  current_section = nil if current_section == '(no section)'
31
33
  by_section[current_section] ||= []
32
34
  by_section[current_section] << task
@@ -41,6 +43,12 @@ module Checkoff
41
43
  end
42
44
  cache_method :by_section, LONG_CACHE_TIME
43
45
 
46
+ def legacy_tasks_by_section_for_project(project)
47
+ raw_tasks = projects.tasks_from_project(project)
48
+ active_tasks = projects.active_tasks(raw_tasks)
49
+ legacy_by_section(active_tasks)
50
+ end
51
+
44
52
  def tasks_by_section_for_project(project)
45
53
  raw_tasks = projects.tasks_from_project(project)
46
54
  active_tasks = projects.active_tasks(raw_tasks)
@@ -68,8 +76,8 @@ module Checkoff
68
76
  by_section
69
77
  end
70
78
 
71
- def tasks_by_section_for_project_and_assignee_status(project,
72
- assignee_status)
79
+ def legacy_tasks_by_section_for_project_and_assignee_status(project,
80
+ assignee_status)
73
81
  raw_tasks = projects.tasks_from_project(project)
74
82
  by_assignee_status =
75
83
  projects.active_tasks(raw_tasks)
@@ -87,15 +95,40 @@ module Checkoff
87
95
  project
88
96
  end
89
97
 
98
+ def verify_legacy_user_task_list!(workspace_name)
99
+ return unless user_task_list_migrated_to_real_sections?(workspace_name)
100
+
101
+ raise NotImplementedError, 'Section-based user task lists not yet supported'
102
+ end
103
+
104
+ ASSIGNEE_STATUS_BY_PROJECT_NAME = {
105
+ my_tasks_new: 'inbox',
106
+ my_tasks_today: 'today',
107
+ my_tasks_upcoming: 'upcoming',
108
+ }.freeze
109
+
110
+ def user_task_list_by_section(workspace_name, project_name)
111
+ verify_legacy_user_task_list!(workspace_name)
112
+
113
+ if project_name == :my_tasks
114
+ legacy_tasks_by_section_for_project(project_name)
115
+ else
116
+ legacy_tasks_by_section_for_project_and_assignee_status(project_name,
117
+ ASSIGNEE_STATUS_BY_PROJECT_NAME.fetch(project_name))
118
+ end
119
+ end
120
+
90
121
  def tasks_by_section(workspace_name, project_name)
91
122
  project = project_or_raise(workspace_name, project_name)
92
123
  case project_name
124
+ when :my_tasks
125
+ user_task_list_by_section(workspace_name, project_name)
93
126
  when :my_tasks_new
94
- tasks_by_section_for_project_and_assignee_status(project, 'inbox')
127
+ user_task_list_by_section(workspace_name, project_name)
95
128
  when :my_tasks_today
96
- tasks_by_section_for_project_and_assignee_status(project, 'today')
129
+ user_task_list_by_section(workspace_name, project_name)
97
130
  when :my_tasks_upcoming
98
- tasks_by_section_for_project_and_assignee_status(project, 'upcoming')
131
+ user_task_list_by_section(workspace_name, project_name)
99
132
  else
100
133
  tasks_by_section_for_project(project)
101
134
  end
@@ -120,6 +153,13 @@ module Checkoff
120
153
  end
121
154
  cache_method :section_task_names, SHORT_CACHE_TIME
122
155
 
156
+ def user_task_list_migrated_to_real_sections?(workspace_name)
157
+ workspace = workspaces.workspace_by_name(workspace_name)
158
+ result = client.user_task_lists.get_user_task_list_for_user(user_gid: 'me',
159
+ workspace: workspace.gid)
160
+ result.migration_status != 'not_migrated'
161
+ end
162
+
123
163
  def task_due?(task)
124
164
  if task.due_at
125
165
  Time.parse(task.due_at) <= time.now
@@ -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.3'
4
+ VERSION = '0.8.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
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.3
4
+ version: 0.8.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-19 00:00:00.000000000 Z
11
+ date: 2021-03-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: overcommit
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: quality
113
127
  requirement: !ruby/object:Gem::Requirement
@@ -173,7 +187,9 @@ extensions: []
173
187
  extra_rdoc_files: []
174
188
  files:
175
189
  - ".circleci/config.yml"
190
+ - ".envrc"
176
191
  - ".gitignore"
192
+ - ".overcommit.yml"
177
193
  - ".rubocop.yml"
178
194
  - ".ruby-version"
179
195
  - ".travis.yml"
@@ -183,6 +199,7 @@ files:
183
199
  - Makefile
184
200
  - README.md
185
201
  - Rakefile
202
+ - bin/checkoff
186
203
  - bin/console
187
204
  - bin/setup
188
205
  - checkoff.gemspec
@@ -235,7 +252,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
235
252
  requirements:
236
253
  - - ">="
237
254
  - !ruby/object:Gem::Version
238
- version: '2.6'
255
+ version: '2.5'
239
256
  required_rubygems_version: !ruby/object:Gem::Requirement
240
257
  requirements:
241
258
  - - ">="