checkoff 0.10.0 → 0.11.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: 121d92b56f0936e25ff98efd5f601e9fea6cf6a71191f0ba7a2803785bcc1feb
4
- data.tar.gz: e3b871d18fa8263e0d61df92e22b59a369b5f78e527a8da57ac0fb472db5c34d
3
+ metadata.gz: 0f9082aa251f94c438c29019a88db01de1732564c237bb3dff8d4aef6ce8eea6
4
+ data.tar.gz: 90cc397c4381839ddc1ba55c0096e84e7baf735653d2aa46267a1e52dd684603
5
5
  SHA512:
6
- metadata.gz: '0862ee2cd9aababfb015020a1c55e6f7a5027bc001b2ec6317b661b7407fcb095bb981f7d44ad251a50166edf674bc798f3629b986cece29eb30286f7be09fd0'
7
- data.tar.gz: ebaed1748125699b93f3804ee79d2c33fdf560aa232e904a69fb1e55ad3520802096b35ea9a921e5b70c67f37a6c78ce3444606333e6ed81ca6f7e4912ae61b6
6
+ metadata.gz: 21438c7ac67f3e782a1fee1c7adae43baa13df126904668dc6784cfab27b57d4abea67380af34560ff834e6b6a00a1fcd50ce12f171781991c273cc8bd9ce10e
7
+ data.tar.gz: 863441bc08bd83be385bb8b5806ad37a720a421cdfab44efcb9c31e528b649ee11a6e0d392401e4fb2931ff4c6f4a7934d2b652df4fb200c8286bc758c9ad7ba
data/.circleci/config.yml CHANGED
@@ -19,7 +19,7 @@ commands:
19
19
  export PATH="${HOME}/.pyenv/bin:${PATH}"
20
20
  export PATH="${HOME}/.rbenv/bin:${HOME}/.rbenv/shims:${PATH}"
21
21
  export PATH="${HOME}/project/node_modules/.bin:${PATH}"
22
- eval "$(pyenv init -)"
22
+ eval "$(pyenv init --path)"
23
23
  eval "$(pyenv virtualenv-init -)"
24
24
  eval "$(rbenv init -)"
25
25
  export BUNDLE_PATH=vendor/bundle
@@ -97,11 +97,12 @@ jobs:
97
97
  steps:
98
98
  - set_up_environment
99
99
  - run_with_languages:
100
- label: Run tests
100
+ label: Test
101
101
  command: |
102
- make test
102
+ bundle exec rake citest
103
103
  # https://github.com/bluelabsio/records-mover/blob/master/Makefile#L25
104
104
  git status --porcelain coverage/.last_run.json
105
+ git diff coverage/.last_run.json
105
106
  test -z "$(git status --porcelain coverage/.last_run.json)"
106
107
 
107
108
  workflows:
data/.envrc CHANGED
@@ -1,2 +1,2 @@
1
1
  PATH_add bin
2
- eval $(with-op op-env sh -e ASANA__PERSONAL_ACCESS_TOKEN)
2
+ eval $(with-op op-env sh -e ASANA__PERSONAL_ACCESS_TOKEN -e ASANA__DEFAULT_ASSIGNEE_GID)
data/.gitignore CHANGED
@@ -58,4 +58,5 @@ requirements_dev.txt.installed
58
58
  /coverage/.resultset.json.lock
59
59
  /coverage/assets/
60
60
  /coverage/index.html
61
+ /coverage/lcov/
61
62
  /pkg
data/Gemfile.lock CHANGED
@@ -1,11 +1,12 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- checkoff (0.10.0)
4
+ checkoff (0.11.0)
5
5
  activesupport
6
6
  asana (> 0.10.0)
7
7
  cache_method
8
8
  dalli
9
+ gli
9
10
 
10
11
  GEM
11
12
  remote: https://rubygems.org/
@@ -27,15 +28,19 @@ GEM
27
28
  cache_method (0.2.7)
28
29
  cache (>= 0.2.1)
29
30
  childprocess (4.0.0)
30
- concurrent-ruby (1.1.8)
31
+ concurrent-ruby (1.1.9)
31
32
  dalli (2.7.11)
32
- docile (1.3.4)
33
- faraday (1.4.1)
33
+ docile (1.4.0)
34
+ faraday (1.4.2)
35
+ faraday-em_http (~> 1.0)
36
+ faraday-em_synchrony (~> 1.0)
34
37
  faraday-excon (~> 1.1)
35
38
  faraday-net_http (~> 1.0)
36
39
  faraday-net_http_persistent (~> 1.1)
37
40
  multipart-post (>= 1.2, < 3)
38
41
  ruby2_keywords (>= 0.0.4)
42
+ faraday-em_http (1.0.0)
43
+ faraday-em_synchrony (1.0.0)
39
44
  faraday-excon (1.1.0)
40
45
  faraday-net_http (1.0.1)
41
46
  faraday-net_http_persistent (1.1.0)
@@ -44,6 +49,7 @@ GEM
44
49
  faraday_middleware-multi_json (0.0.6)
45
50
  faraday_middleware
46
51
  multi_json
52
+ gli (2.20.0)
47
53
  i18n (1.8.10)
48
54
  concurrent-ruby (~> 1.0)
49
55
  imagen (0.1.8)
@@ -62,9 +68,10 @@ GEM
62
68
  multi_json (~> 1.3)
63
69
  multi_xml (~> 0.5)
64
70
  rack (>= 1.2, < 3)
65
- overcommit (0.57.0)
71
+ overcommit (0.58.0)
66
72
  childprocess (>= 0.6.3, < 5)
67
73
  iniparse (~> 1.4)
74
+ rexml (~> 3.2)
68
75
  parallel (1.20.1)
69
76
  parser (3.0.1.1)
70
77
  ast (~> 2.4.1)
@@ -73,7 +80,7 @@ GEM
73
80
  rake (13.0.3)
74
81
  regexp_parser (2.1.1)
75
82
  rexml (3.2.5)
76
- rubocop (1.14.0)
83
+ rubocop (1.15.0)
77
84
  parallel (~> 1.10)
78
85
  parser (>= 3.0.0.0)
79
86
  rainbow (>= 2.2.2, < 4.0)
@@ -96,6 +103,7 @@ GEM
96
103
  simplecov-html (~> 0.11)
97
104
  simplecov_json_formatter (~> 0.1)
98
105
  simplecov-html (0.12.3)
106
+ simplecov-lcov (0.8.0)
99
107
  simplecov_json_formatter (0.1.3)
100
108
  tzinfo (2.0.4)
101
109
  concurrent-ruby (~> 1.0)
@@ -118,13 +126,14 @@ DEPENDENCIES
118
126
  checkoff!
119
127
  minitest-profile
120
128
  mocha
121
- overcommit
129
+ overcommit (>= 0.58.0)
122
130
  rake (~> 13.0)
123
131
  rubocop
124
132
  rubocop-minitest
125
133
  rubocop-rake
126
134
  simplecov
135
+ simplecov-lcov
127
136
  undercover
128
137
 
129
138
  BUNDLED WITH
130
- 2.2.11
139
+ 2.2.19
data/Makefile CHANGED
@@ -1,4 +1,4 @@
1
- .PHONY: clean test help quality localtest spec feature
1
+ .PHONY: clean test help quality localtest
2
2
  .DEFAULT_GOAL := default
3
3
 
4
4
  define PRINT_HELP_PYSCRIPT
@@ -32,7 +32,10 @@ Gemfile.lock.installed: Gemfile.lock
32
32
 
33
33
  bundle_install: Gemfile.lock.installed ## Install Ruby dependencies
34
34
 
35
- clean: ## remove all built artifacts
35
+ clear_metrics: ## remove or reset result artifacts created by tests and quality tools
36
+ bundle exec rake clear_metrics
37
+
38
+ clean: clear_metrics ## remove all built artifacts
36
39
 
37
40
  quality: ## run precommit quality checks
38
41
  bundle exec overcommit --run
@@ -40,7 +43,8 @@ quality: ## run precommit quality checks
40
43
  test: ## Run lower-level tests
41
44
  @bundle exec rake test
42
45
 
43
- localtest: test quality feature ## run default local actions
46
+ localtest: ## run default local actions
47
+ @bundle exec rake localtest
44
48
 
45
49
  update_from_cookiecutter: ## Bring in changes from template project used to create this repo
46
50
  bundle exec overcommit --uninstall
data/checkoff.gemspec CHANGED
@@ -26,16 +26,21 @@ Gem::Specification.new do |spec|
26
26
  spec.add_runtime_dependency 'asana', '>0.10.0'
27
27
  spec.add_runtime_dependency 'cache_method'
28
28
  spec.add_runtime_dependency 'dalli'
29
+ spec.add_runtime_dependency 'gli'
29
30
 
30
31
  spec.add_development_dependency 'bump'
31
32
  spec.add_development_dependency 'bundler'
32
33
  spec.add_development_dependency 'minitest-profile'
33
34
  spec.add_development_dependency 'mocha'
34
- spec.add_development_dependency 'overcommit'
35
+ # 0.58.0 and 0.57.0 don't seem super compatible with signatures, and
36
+ # magit doesn't seem to want to use the bundled version at the moment,
37
+ # so let's favor the more recent version...
38
+ spec.add_development_dependency 'overcommit', ['>=0.58.0']
35
39
  spec.add_development_dependency 'rake', '~> 13.0'
36
40
  spec.add_development_dependency 'rubocop'
37
41
  spec.add_development_dependency 'rubocop-minitest'
38
42
  spec.add_development_dependency 'rubocop-rake'
39
43
  spec.add_development_dependency 'simplecov'
44
+ spec.add_development_dependency 'simplecov-lcov'
40
45
  spec.add_development_dependency 'undercover'
41
46
  end
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "result": {
3
- "line": 93.15,
4
- "branch": 61.66
3
+ "line": 94.61,
4
+ "branch": 71.42
5
5
  }
6
6
  }
data/exe/checkoff CHANGED
@@ -4,5 +4,4 @@
4
4
  require 'checkoff/cli'
5
5
 
6
6
  CacheMethod.config.storage = Dalli::Client.new('memcached:11211')
7
- cli = Checkoff::CLI.new
8
- puts cli.run(ARGV)
7
+ exit(Checkoff::CheckoffGLIApp.run(ARGV))
data/fix.sh CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  set -o pipefail
4
4
 
5
+ apt_upgraded=0
6
+
7
+ update_apt() {
8
+ if [ "${apt_upgraded}" = 0 ]
9
+ then
10
+ sudo apt-get update -y
11
+ apt_upgraded=1
12
+ fi
13
+ }
14
+
5
15
  install_rbenv() {
6
16
  if [ "$(uname)" == "Darwin" ]
7
17
  then
@@ -77,6 +87,8 @@ ensure_dev_library() {
77
87
 
78
88
  ensure_ruby_build_requirements() {
79
89
  ensure_dev_library readline/readline.h readline libreadline-dev
90
+ ensure_dev_library zlib.h zlib zlib1g-dev
91
+ ensure_dev_library openssl/ssl.h openssl libssl-dev
80
92
  }
81
93
 
82
94
  # You can find out which feature versions are still supported / have
@@ -92,7 +104,17 @@ ensure_ruby_versions() {
92
104
 
93
105
  for ver in $ruby_versions
94
106
  do
95
- rbenv install -s "${ver}"
107
+ # These CFLAGS can be retired once 2.6.7 is no longer needed :
108
+ #
109
+ # https://github.com/rbenv/ruby-build/issues/1747
110
+ # https://github.com/rbenv/ruby-build/issues/1489
111
+ # https://bugs.ruby-lang.org/issues/17777
112
+ if [ "${ver}" == 2.6.7 ]
113
+ then
114
+ CFLAGS="-Wno-error=implicit-function-declaration" rbenv install -s "${ver}"
115
+ else
116
+ rbenv install -s "${ver}"
117
+ fi
96
118
  done
97
119
  }
98
120
 
@@ -101,7 +123,17 @@ ensure_bundle() {
101
123
  #
102
124
  # https://app.circleci.com/pipelines/github/apiology/source_finder/21/workflows/88db659f-a4f4-4751-abc0-46f5929d8e58/jobs/107
103
125
  set_rbenv_env_variables
104
- bundle --version >/dev/null 2>&1 || gem install bundler
126
+ bundle --version >/dev/null 2>&1 || gem install --no-document bundler
127
+ bundler_version=$(bundle --version | cut -d ' ' -f3)
128
+ bundler_version_major=$(cut -d. -f1 <<< "${bundler_version}")
129
+ bundler_version_minor=$(cut -d. -f2 <<< "${bundler_version}")
130
+ # Version 2.1 of bundler seems to have some issues with nokogiri:
131
+ #
132
+ # https://app.asana.com/0/1107901397356088/1199504270687298
133
+ if [ "${bundler_version_major}" == 2 ] && [ "${bundler_version_minor}" -lt 2 ]
134
+ then
135
+ gem install --no-document bundler
136
+ fi
105
137
  make bundle_install
106
138
  # https://bundler.io/v2.0/bundle_lock.html#SUPPORTING-OTHER-PLATFORMS
107
139
  #
@@ -138,8 +170,9 @@ WARNING: seems you still have not added 'pyenv' to the load path.
138
170
  # Load pyenv automatically by adding
139
171
  # the following to ~/.bashrc:
140
172
 
141
- export PATH="$HOME/.pyenv/bin:$PATH"
142
- eval "$(pyenv init -)"
173
+ export PYENV_ROOT="${HOME}/.pyenv"
174
+ export PATH="${PYENV_ROOT}/bin:$PATH"
175
+ eval "$(pyenv init --path)"
143
176
  eval "$(pyenv virtualenv-init -)"
144
177
  EOF
145
178
  fi
@@ -153,8 +186,9 @@ set_pyenv_env_variables() {
153
186
  #
154
187
  # https://app.circleci.com/pipelines/github/apiology/cookiecutter-pypackage/15/workflows/10506069-7662-46bd-b915-2992db3f795b/jobs/15
155
188
  set +u
156
- export PATH="${HOME}/.pyenv/bin:$PATH"
157
- eval "$(pyenv init -)"
189
+ export PYENV_ROOT="${HOME}/.pyenv"
190
+ export PATH="${PYENV_ROOT}/bin:$PATH"
191
+ eval "$(pyenv init --path)"
158
192
  eval "$(pyenv virtualenv-init -)"
159
193
  set -u
160
194
  }
@@ -179,7 +213,7 @@ install_package() {
179
213
  HOMEBREW_NO_AUTO_UPDATE=1 brew install "${homebrew_package}"
180
214
  elif type apt-get >/dev/null 2>&1
181
215
  then
182
- sudo apt-get update -y
216
+ update_apt
183
217
  sudo apt-get install -y "${apt_package}"
184
218
  else
185
219
  >&2 echo "Teach me how to install packages on this plaform"
@@ -192,6 +226,7 @@ ensure_python_build_requirements() {
192
226
  ensure_dev_library bzlib.h bzip2 libbz2-dev
193
227
  ensure_dev_library openssl/ssl.h openssl libssl-dev
194
228
  ensure_dev_library ffi.h libffi libffi-dev
229
+ ensure_dev_library sqlite3.h sqlite3 libsqlite3-dev
195
230
  }
196
231
 
197
232
  # You can find out which feature versions are still supported / have
data/lib/checkoff/cli.rb CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  require 'ostruct'
6
6
  require 'dalli'
7
+ require 'gli'
7
8
  require 'cache_method'
8
9
  require_relative 'workspaces'
9
10
  require_relative 'projects'
@@ -11,41 +12,44 @@ require_relative 'tasks'
11
12
  require_relative 'sections'
12
13
 
13
14
  module Checkoff
14
- # Provide ability for CLI to pull Asana items
15
- # rubocop:disable Metrics/ClassLength
16
- class CLI
17
- attr_reader :sections, :stderr
18
-
19
- def initialize(config: Checkoff::ConfigLoader.load(:asana),
20
- workspaces: Checkoff::Workspaces.new(config: config),
15
+ # CLI subcommand that shows tasks in JSON form
16
+ class ViewSubcommand
17
+ def initialize(workspace_name, project_name, section_name,
18
+ task_name,
19
+ config: Checkoff::ConfigLoader.load(:asana),
21
20
  projects: Checkoff::Projects.new(config: config),
22
21
  sections: Checkoff::Sections.new(config: config,
23
22
  projects: projects),
24
- tasks: Checkoff::Tasks.new(config: config),
25
- stderr: $stderr,
26
- kernel: Kernel)
27
- @workspaces = workspaces
28
- @projects = projects
23
+ tasks: Checkoff::Tasks.new(config: config,
24
+ sections: sections),
25
+ stderr: $stderr)
26
+ @workspace_name = workspace_name
27
+ @stderr = stderr
28
+ validate_and_assign_project_name(project_name)
29
+ @section_name = section_name
30
+ @task_name = task_name
29
31
  @sections = sections
30
32
  @tasks = tasks
31
- @kernel = kernel
32
- @stderr = stderr
33
33
  end
34
34
 
35
- def task_to_hash(task)
36
- task_out = {
37
- name: task.name,
38
- }
39
- if task.due_on
40
- task_out[:due] = task.due_on
41
- elsif task.due_at
42
- task_out[:due] = task.due_at
35
+ def run
36
+ if section_name.nil?
37
+ run_on_project(workspace_name, project_name)
38
+ elsif task_name.nil?
39
+ run_on_section(workspace_name, project_name, section_name)
40
+ else
41
+ run_on_task(workspace_name, project_name, section_name, task_name)
43
42
  end
44
- task_out
45
43
  end
46
44
 
47
- def tasks_to_hash(tasks)
48
- tasks.map { |task| task_to_hash(task) }
45
+ private
46
+
47
+ def validate_and_assign_project_name(project_name)
48
+ @project_name = if project_name.start_with? ':'
49
+ project_name[1..].to_sym
50
+ else
51
+ project_name
52
+ end
49
53
  end
50
54
 
51
55
  def run_on_project(workspace, project)
@@ -63,80 +67,89 @@ module Checkoff
63
67
  tasks_to_hash(tasks).to_json
64
68
  end
65
69
 
66
- def quickadd(workspace_name, task_name)
67
- workspace = @workspaces.workspace_by_name(workspace_name)
68
- @tasks.add_task(task_name,
69
- workspace_gid: workspace.gid)
70
+ def run_on_task(workspace, project, section, task_name)
71
+ section = nil if section == ''
72
+ task = tasks.task(workspace, project, task_name, section_name: section)
73
+ task_to_hash(task).to_json
70
74
  end
71
75
 
72
- def validate_args!(args)
73
- return unless args.length < 2 || !%w[view quickadd].include?(args[0])
74
-
75
- output_help
76
- exit(1)
76
+ def task_to_hash(task)
77
+ task_out = {
78
+ name: task.name,
79
+ }
80
+ if task.due_on
81
+ task_out[:due] = task.due_on
82
+ elsif task.due_at
83
+ task_out[:due] = task.due_at
84
+ end
85
+ task_out
77
86
  end
78
87
 
79
- def parse_view_args(subargs, args)
80
- subargs.workspace = args[1]
81
- subargs.project = args[2]
82
- subargs.section = args[3]
88
+ def tasks_to_hash(tasks)
89
+ tasks.map { |task| task_to_hash(task) }
83
90
  end
84
91
 
85
- def parse_quickadd_args(subargs, args)
86
- subargs.workspace = args[1]
87
- subargs.task_name = args[2]
88
- end
92
+ attr_reader :workspace_name, :project_name, :section_name, :task_name, :sections, :tasks, :stderr
93
+ end
89
94
 
90
- # rubocop:disable Metrics/MethodLength
91
- def parse_args(args)
92
- mode = args[0]
93
- subargs = OpenStruct.new
94
- case mode
95
- when 'view'
96
- parse_view_args(subargs, args)
97
- when 'quickadd'
98
- parse_quickadd_args(subargs, args)
99
- else
100
- raise
101
- end
102
- [mode, subargs]
95
+ # CLI subcommand that creates a task
96
+ class QuickaddSubcommand
97
+ def initialize(workspace_name, task_name,
98
+ config: Checkoff::ConfigLoader.load(:asana),
99
+ workspaces: Checkoff::Workspaces.new(config: config),
100
+ tasks: Checkoff::Tasks.new(config: config))
101
+ @workspace_name = workspace_name
102
+ @task_name = task_name
103
+ @workspaces = workspaces
104
+ @tasks = tasks
103
105
  end
104
- # rubocop:enable Metrics/MethodLength
105
-
106
- def output_help
107
- stderr.puts 'View tasks:'
108
- stderr.puts " #{$PROGRAM_NAME} view workspace project [section]"
109
- stderr.puts " #{$PROGRAM_NAME} quickadd workspace task_name"
110
- stderr.puts
111
- stderr.puts "'project' can be set to a project name, or :my_tasks, " \
112
- ":my_tasks_upcoming, :my_tasks_new, or :my_tasks_today"
106
+
107
+ def run
108
+ workspace = @workspaces.workspace_by_name(workspace_name)
109
+ @tasks.add_task(task_name,
110
+ workspace_gid: workspace.gid)
113
111
  end
114
112
 
115
- def view(workspace_name, project_name, section_name)
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? ':'
121
- if section_name.nil?
122
- run_on_project(workspace_name, project_name)
123
- else
124
- run_on_section(workspace_name, project_name, section_name)
113
+ private
114
+
115
+ attr_reader :workspace_name, :task_name
116
+ end
117
+
118
+ # Provide ability for CLI to pull Asana items
119
+ class CheckoffGLIApp
120
+ extend GLI::App
121
+
122
+ program_desc 'Command-line client for Asana (unofficial)'
123
+
124
+ subcommand_option_handling :normal
125
+ arguments :strict
126
+
127
+ desc 'Add a short task to Asana'
128
+ arg 'workspace'
129
+ arg 'task_name'
130
+ command :quickadd do |c|
131
+ c.action do |_global_options, _options, args|
132
+ workspace_name = args.fetch(0)
133
+ task_name = args.fetch(1)
134
+
135
+ QuickaddSubcommand.new(workspace_name, task_name).run
125
136
  end
126
137
  end
127
138
 
128
- def run(args)
129
- validate_args!(args)
130
- command, subargs = parse_args(args)
131
- case command
132
- when 'view'
133
- view(subargs.workspace, subargs.project, subargs.section)
134
- when 'quickadd'
135
- quickadd(subargs.workspace, subargs.task_name)
136
- else
137
- raise
139
+ desc 'Output representation of Asana tasks'
140
+ arg 'workspace'
141
+ arg 'project'
142
+ arg 'section', :optional
143
+ arg 'task_name', :optional
144
+ command :view do |c|
145
+ c.action do |_global_options, _options, args|
146
+ workspace_name = args.fetch(0)
147
+ project_name = args.fetch(1)
148
+ section_name = args[2]
149
+ task_name = args[3]
150
+
151
+ puts ViewSubcommand.new(workspace_name, project_name, section_name, task_name).run
138
152
  end
139
153
  end
140
154
  end
141
- # rubocop:enable Metrics/ClassLength
142
155
  end
@@ -13,10 +13,6 @@ module Checkoff
13
13
  @yaml_filename = yaml_filename
14
14
  end
15
15
 
16
- def envvar_name(key)
17
- "#{@envvar_prefix}__#{key.upcase}"
18
- end
19
-
20
16
  def [](key)
21
17
  config_value = @config[key]
22
18
  return config_value unless config_value.nil?
@@ -31,25 +27,35 @@ module Checkoff
31
27
  raise KeyError,
32
28
  "Please configure either the #{key} key in #{@yaml_filename} or set #{envvar_name(key)}"
33
29
  end
30
+
31
+ private
32
+
33
+ def envvar_name(key)
34
+ "#{@envvar_prefix}__#{key.upcase}"
35
+ end
34
36
  end
35
37
 
36
38
  # Load configuration file
37
39
  class ConfigLoader
38
- def self.yaml_filename(sym)
39
- file = "#{sym}.yml"
40
- File.expand_path("~/.#{file}")
41
- end
40
+ class << self
41
+ def load(sym)
42
+ yaml_result = load_yaml_file(sym)
43
+ EnvFallbackConfigLoader.new(yaml_result, sym, yaml_filename(sym))
44
+ end
42
45
 
43
- def self.load_yaml_file(sym)
44
- filename = yaml_filename(sym)
45
- return {} unless File.exist?(filename)
46
+ private
46
47
 
47
- YAML.load_file(filename).with_indifferent_access
48
- end
48
+ def load_yaml_file(sym)
49
+ filename = yaml_filename(sym)
50
+ return {} unless File.exist?(filename)
51
+
52
+ YAML.load_file(filename).with_indifferent_access
53
+ end
49
54
 
50
- def self.load(sym)
51
- yaml_result = load_yaml_file(sym)
52
- EnvFallbackConfigLoader.new(yaml_result, sym, yaml_filename(sym))
55
+ def yaml_filename(sym)
56
+ file = "#{sym}.yml"
57
+ File.expand_path("~/.#{file}")
58
+ end
53
59
  end
54
60
  end
55
61
  end
@@ -22,8 +22,6 @@ module Checkoff
22
22
  LONG_CACHE_TIME = MINUTE * 15
23
23
  SHORT_CACHE_TIME = MINUTE * 5
24
24
 
25
- # XXX: Move low-level functions private
26
-
27
25
  def initialize(config: Checkoff::ConfigLoader.load(:asana),
28
26
  asana_client: Asana::Client,
29
27
  workspaces: Checkoff::Workspaces.new(config: config))
@@ -32,10 +30,41 @@ module Checkoff
32
30
  @workspaces = workspaces
33
31
  end
34
32
 
33
+ # Returns Asana Ruby API Client object
35
34
  def client
36
35
  @workspaces.client
37
36
  end
38
37
 
38
+ # pulls an Asana API project class given a name
39
+ def project(workspace_name, project_name)
40
+ if project_name.is_a?(Symbol) && project_name.to_s.start_with?('my_tasks')
41
+ my_tasks(workspace_name)
42
+ else
43
+ projects = projects_by_workspace_name(workspace_name)
44
+ projects.find do |project|
45
+ project.name == project_name
46
+ end
47
+ end
48
+ end
49
+ cache_method :project, LONG_CACHE_TIME
50
+
51
+ # find uncompleted tasks in a list
52
+ def active_tasks(tasks)
53
+ tasks.select { |task| task.completed_at.nil? }
54
+ end
55
+
56
+ # pull task objects from a named project
57
+ def tasks_from_project(project, only_uncompleted: true, extra_fields: [])
58
+ options = task_options
59
+ options[:completed_since] = '9999-12-01' if only_uncompleted
60
+ options[:project] = project.gid
61
+ options[:options][:fields] += extra_fields
62
+ client.tasks.find_all(**options).to_a
63
+ end
64
+ cache_method :tasks_from_project, SHORT_CACHE_TIME
65
+
66
+ private
67
+
39
68
  def projects
40
69
  client.projects
41
70
  end
@@ -56,22 +85,6 @@ module Checkoff
56
85
  projects.find_by_id(gid)
57
86
  end
58
87
 
59
- def project(workspace_name, project_name)
60
- if project_name.is_a?(Symbol) && project_name.to_s.start_with?('my_tasks')
61
- my_tasks(workspace_name)
62
- else
63
- projects = projects_by_workspace_name(workspace_name)
64
- projects.find do |project|
65
- project.name == project_name
66
- end
67
- end
68
- end
69
- cache_method :project, LONG_CACHE_TIME
70
-
71
- def active_tasks(tasks)
72
- tasks.select { |task| task.completed_at.nil? }
73
- end
74
-
75
88
  def task_options
76
89
  {
77
90
  per_page: 100,
@@ -81,14 +94,5 @@ module Checkoff
81
94
  },
82
95
  }
83
96
  end
84
-
85
- def tasks_from_project(project, only_uncompleted: true, extra_fields: [])
86
- options = task_options
87
- options[:completed_since] = '9999-12-01' if only_uncompleted
88
- options[:project] = project.gid
89
- options[:options][:fields] += extra_fields
90
- client.tasks.find_all(**options).to_a
91
- end
92
- cache_method :tasks_from_project, SHORT_CACHE_TIME
93
97
  end
94
98
  end
@@ -23,6 +23,71 @@ module Checkoff
23
23
  @time = time
24
24
  end
25
25
 
26
+ # Given a list of tasks, pull a Hash of tasks with section name -> task list
27
+ def by_section(tasks, project_gid)
28
+ by_section = {}
29
+ tasks.each do |task|
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)
42
+ end
43
+
44
+ # Given a workspace name and project name, then provide a Hash of
45
+ # tasks with section name -> task list of the uncompleted tasks
46
+ def tasks_by_section(workspace_name, project_name)
47
+ project = project_or_raise(workspace_name, project_name)
48
+ case project_name
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
54
+ end
55
+ cache_method :tasks_by_section, SHORT_CACHE_TIME
56
+
57
+ # XXX: Rename to section_tasks
58
+ #
59
+ # Pulls task objects from a specified section
60
+ def tasks(workspace_name, project_name, section_name)
61
+ tasks_by_section(workspace_name, project_name).fetch(section_name, [])
62
+ end
63
+ cache_method :tasks, SHORT_CACHE_TIME
64
+
65
+ # Pulls just names of tasks from a given section.
66
+ def section_task_names(workspace_name, project_name, section_name)
67
+ 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
+ tasks.map(&:name)
75
+ end
76
+ cache_method :section_task_names, SHORT_CACHE_TIME
77
+
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
+ private
90
+
26
91
  def_delegators :@projects, :client
27
92
 
28
93
  def file_task_by_section(by_section, task, project_gid)
@@ -35,27 +100,12 @@ module Checkoff
35
100
  by_section[current_section] << task
36
101
  end
37
102
 
38
- def by_section(tasks, project_gid)
39
- by_section = {}
40
- tasks.each do |task|
41
- file_task_by_section(by_section, task, project_gid)
42
- end
43
- by_section
44
- end
45
- cache_method :by_section, LONG_CACHE_TIME
46
-
47
103
  def legacy_tasks_by_section_for_project(project)
48
104
  raw_tasks = projects.tasks_from_project(project)
49
105
  active_tasks = projects.active_tasks(raw_tasks)
50
106
  legacy_by_section(active_tasks)
51
107
  end
52
108
 
53
- def tasks_by_section_for_project(project)
54
- raw_tasks = projects.tasks_from_project(project)
55
- active_tasks = projects.active_tasks(raw_tasks)
56
- by_section(active_tasks, project.gid)
57
- end
58
-
59
109
  def legacy_file_task_by_section(current_section, by_section, task)
60
110
  if task.name =~ /:$/
61
111
  current_section = task.name
@@ -120,35 +170,6 @@ module Checkoff
120
170
  end
121
171
  end
122
172
 
123
- def tasks_by_section(workspace_name, project_name)
124
- project = project_or_raise(workspace_name, project_name)
125
- case project_name
126
- when :my_tasks, :my_tasks_new, :my_tasks_today, :my_tasks_upcoming
127
- user_task_list_by_section(workspace_name, project_name)
128
- else
129
- tasks_by_section_for_project(project)
130
- end
131
- end
132
- cache_method :tasks_by_section, SHORT_CACHE_TIME
133
-
134
- # XXX: Rename to section_tasks
135
- def tasks(workspace_name, project_name, section_name)
136
- tasks_by_section(workspace_name, project_name).fetch(section_name, [])
137
- end
138
- cache_method :tasks, SHORT_CACHE_TIME
139
-
140
- def section_task_names(workspace_name, project_name, section_name)
141
- tasks = tasks(workspace_name, project_name, section_name)
142
- if tasks.nil?
143
- by_section = tasks_by_section(workspace_name, project_name)
144
- desc = "#{workspace_name} | #{project_name} | #{section_name}"
145
- raise "Could not find task names for #{desc}. " \
146
- "Valid sections: #{by_section.keys}"
147
- end
148
- tasks.map(&:name)
149
- end
150
- cache_method :section_task_names, SHORT_CACHE_TIME
151
-
152
173
  def user_task_list_migrated_to_real_sections?(workspace_name)
153
174
  workspace = workspaces.workspace_by_name(workspace_name)
154
175
  result = client.user_task_lists.get_user_task_list_for_user(user_gid: 'me',
@@ -156,16 +177,6 @@ module Checkoff
156
177
  result.migration_status != 'not_migrated'
157
178
  end
158
179
 
159
- def task_due?(task)
160
- if task.due_at
161
- Time.parse(task.due_at) <= time.now
162
- elsif task.due_on
163
- Date.parse(task.due_on) <= time.today
164
- else
165
- true # set a due date if you don't want to do this now
166
- end
167
- end
168
-
169
180
  def project_task_names(workspace_name, project_name)
170
181
  by_section = tasks_by_section(workspace_name, project_name)
171
182
  by_section.flat_map do |section_name, tasks|
@@ -11,17 +11,7 @@ module Checkoff
11
11
 
12
12
  extend Forwardable
13
13
 
14
- def file_task_by_section(current_section, by_section, task)
15
- if task.name =~ /:$/
16
- current_section = task.name
17
- by_section[current_section] = []
18
- else
19
- by_section[current_section] ||= []
20
- by_section[current_section] << task
21
- end
22
- [current_section, by_section]
23
- end
24
-
14
+ # pulls a Hash of subtasks broken out by section
25
15
  def by_section(tasks)
26
16
  current_section = nil
27
17
  by_section = {}
@@ -37,5 +27,18 @@ module Checkoff
37
27
  task.subtasks(projects.task_options)
38
28
  end
39
29
  cache_method :raw_subtasks, LONG_CACHE_TIME
30
+
31
+ private
32
+
33
+ def file_task_by_section(current_section, by_section, task)
34
+ if task.name =~ /:$/
35
+ current_section = task.name
36
+ by_section[current_section] = []
37
+ else
38
+ by_section[current_section] ||= []
39
+ by_section[current_section] << task
40
+ end
41
+ [current_section, by_section]
42
+ end
40
43
  end
41
44
  end
@@ -5,7 +5,7 @@
5
5
  require_relative 'sections'
6
6
 
7
7
  module Checkoff
8
- # Pull things from 'my tasks' in Asana
8
+ # Pull tasks from Asana
9
9
  class Tasks
10
10
  MINUTE = 60
11
11
  HOUR = MINUTE * 60
@@ -22,6 +22,22 @@ module Checkoff
22
22
  @asana_task = asana_task
23
23
  end
24
24
 
25
+ # Pull a specific task by name
26
+ def task(workspace_name, project_name, task_name,
27
+ section_name: :unspecified,
28
+ only_uncompleted: true)
29
+ project = projects.project(workspace_name, project_name)
30
+ tasks = if section_name == :unspecified
31
+ projects.tasks_from_project(project,
32
+ only_uncompleted: only_uncompleted)
33
+ else
34
+ @sections.tasks(workspace_name, project_name, section_name)
35
+ end
36
+ tasks.find { |task| task.name == task_name }
37
+ end
38
+
39
+ private
40
+
25
41
  def client
26
42
  @sections.client
27
43
  end
@@ -30,13 +46,6 @@ module Checkoff
30
46
  @projects ||= @sections.projects
31
47
  end
32
48
 
33
- def task(workspace_name, project_name, task_name, only_uncompleted: true)
34
- project = projects.project(workspace_name, project_name)
35
- tasks = projects.tasks_from_project(project,
36
- only_uncompleted: only_uncompleted)
37
- tasks.find { |task| task.name == task_name }
38
- end
39
-
40
49
  def tasks_minus_sections(tasks)
41
50
  @sections.by_section(tasks).values.flatten
42
51
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Checkoff
4
- VERSION = '0.10.0'
4
+ # Version of library
5
+ VERSION = '0.11.0'
5
6
  end
@@ -9,6 +9,7 @@ module Checkoff
9
9
  @asana_client = asana_client
10
10
  end
11
11
 
12
+ # Returns Asana Ruby API Client object
12
13
  def client
13
14
  @client ||= @asana_client.new do |c|
14
15
  c.authentication :access_token, @config.fetch(:personal_access_token)
@@ -17,14 +18,17 @@ module Checkoff
17
18
  end
18
19
  end
19
20
 
20
- def default_workspace_gid
21
- @config.fetch(:default_workspace_gid)
22
- end
23
-
21
+ # Pulls an Asana workspace object
24
22
  def workspace_by_name(workspace_name)
25
23
  client.workspaces.find_all.find do |workspace|
26
24
  workspace.name == workspace_name
27
25
  end || raise("Could not find workspace named [#{workspace_name}]")
28
26
  end
27
+
28
+ private
29
+
30
+ def default_workspace_gid
31
+ @config.fetch(:default_workspace_gid)
32
+ end
29
33
  end
30
34
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  desc 'Run tasks to be done during a continuous integration (CI) build'
4
- task ci: :localtest
4
+ task citest: %i[clear_metrics test undercover]
@@ -1,8 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- desc 'Rebaseline quality thresholds to last commit'
3
+ desc 'Ensure that any locally ratcheted coverage metrics are cleared back ' \
4
+ 'to git baseline'
4
5
  task :clear_metrics do |_t|
5
6
  ret =
6
7
  system('git checkout coverage/.last_run.json')
7
8
  raise unless ret
9
+
10
+ # Without this old lines which are removed are still counted,
11
+ # leading to inconsistent coverage percentages between runs.
12
+ #
13
+ # need to save coverage/.last_run.json
14
+ ret =
15
+ system('rm -fr coverage/assets coverage/.*.json.lock coverage/lcov/* coverage/index.html coverage/.resultset.json')
16
+ raise unless ret
8
17
  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.10.0
4
+ version: 0.11.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-05-11 00:00:00.000000000 Z
11
+ date: 2021-06-10 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: gli
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
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: bump
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -128,14 +142,14 @@ dependencies:
128
142
  requirements:
129
143
  - - ">="
130
144
  - !ruby/object:Gem::Version
131
- version: '0'
145
+ version: 0.58.0
132
146
  type: :development
133
147
  prerelease: false
134
148
  version_requirements: !ruby/object:Gem::Requirement
135
149
  requirements:
136
150
  - - ">="
137
151
  - !ruby/object:Gem::Version
138
- version: '0'
152
+ version: 0.58.0
139
153
  - !ruby/object:Gem::Dependency
140
154
  name: rake
141
155
  requirement: !ruby/object:Gem::Requirement
@@ -206,6 +220,20 @@ dependencies:
206
220
  - - ">="
207
221
  - !ruby/object:Gem::Version
208
222
  version: '0'
223
+ - !ruby/object:Gem::Dependency
224
+ name: simplecov-lcov
225
+ requirement: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - ">="
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - ">="
235
+ - !ruby/object:Gem::Version
236
+ version: '0'
209
237
  - !ruby/object:Gem::Dependency
210
238
  name: undercover
211
239
  requirement: !ruby/object:Gem::Requirement
@@ -281,7 +309,7 @@ files:
281
309
  - metrics/rubocop_high_water_mark
282
310
  - metrics/scalastyle_high_water_mark
283
311
  - metrics/shellcheck_high_water_mark
284
- - rakelib/ci.rake
312
+ - rakelib/citest.rake
285
313
  - rakelib/clear_metrics.rake
286
314
  - rakelib/default.rake
287
315
  - rakelib/gem_tasks.rake
@@ -310,7 +338,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
310
338
  - !ruby/object:Gem::Version
311
339
  version: '0'
312
340
  requirements: []
313
- rubygems_version: 3.1.2
341
+ rubygems_version: 3.0.3.1
314
342
  signing_key:
315
343
  specification_version: 4
316
344
  summary: Command-line and gem client for Asana (unofficial)