checkoff 0.5.3 → 0.8.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: 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
  - - ">="