checkoff 0.14.0 → 0.15.2

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: 8750481397466c5207deda9bf852bc119c9ca347bd61ef97bdd8bd8b945d12f2
4
- data.tar.gz: c65a0b1e37ef29fce62dbfe7cbfa5e92bcbc16dd0f8ff9be3a230a93840ce975
3
+ metadata.gz: 10f4779f3bcd067c2bbb80ed9ddea16121a5d26a2a9ee9f95ea6ca43c1931c9c
4
+ data.tar.gz: 3ab265436a93926f0903aa97f792034f773b81c2e28fea7e4f5a49e4746aa62c
5
5
  SHA512:
6
- metadata.gz: 4e16e2aa1b336c7ef2213d19ea1301bd8c9c6c631957d58e063fdf6a3f278521ba77590aec15c661b4c6a908aa77fee7b9593551df9062edb3ce1c4a19c7cb46
7
- data.tar.gz: 4dc5118ce5b1ef2a6eabf3e71ee494a05beed7c4135162200fbfc258147f81b62eaf218e9666a2132c04d1abb18d745a76c388fe058b5829de528b51dc2bf9ab
6
+ metadata.gz: 6870f522f4b5b3a0dedd97126f784e38e4dc86bb0de81c466ec353db66d4be4cf06c3a0f24d9f33790711322faf8440f4d783d3d4759083191579ce2970e8e47
7
+ data.tar.gz: 382a46c341315009e55ab0f3606c51bf8eaa2dcaf9c2a475c831a9a216cdb7fec4c5d2c1d7bbff95408ce17f512b2481dcc56417749ad246d057a05b2041cab1
data/Gemfile.lock CHANGED
@@ -1,9 +1,9 @@
1
1
  GIT
2
2
  remote: https://github.com/apiology/ruby-asana
3
- revision: 83732f040728a4ef1cfc9ed61f65878dbee6aa23
3
+ revision: ab9393136d9ca59b75e42a661fdddc1c65c8f7c3
4
4
  branch: checkoff_fixes
5
5
  specs:
6
- asana (0.10.4)
6
+ asana (0.10.6)
7
7
  faraday (~> 1.0)
8
8
  faraday_middleware (~> 1.0)
9
9
  faraday_middleware-multi_json (~> 0.0)
@@ -12,7 +12,7 @@ GIT
12
12
  PATH
13
13
  remote: .
14
14
  specs:
15
- checkoff (0.14.0)
15
+ checkoff (0.15.2)
16
16
  activesupport
17
17
  asana (> 0.10.0)
18
18
  cache_method
@@ -22,7 +22,7 @@ PATH
22
22
  GEM
23
23
  remote: https://rubygems.org/
24
24
  specs:
25
- activesupport (6.1.4)
25
+ activesupport (6.1.4.1)
26
26
  concurrent-ruby (~> 1.0, >= 1.0.2)
27
27
  i18n (>= 1.6, < 2)
28
28
  minitest (>= 5.1)
data/Makefile CHANGED
@@ -23,9 +23,11 @@ requirements_dev.txt.installed: requirements_dev.txt
23
23
 
24
24
  pip_install: requirements_dev.txt.installed ## Install Python dependencies
25
25
 
26
- Gemfile.lock:
27
- bundle install
26
+ # bundle install doesn't get run here so that we can catch it below in
27
+ # fresh-checkout and fresh-rbenv cases
28
+ Gemfile.lock: Gemfile
28
29
 
30
+ # Ensure any Gemfile.lock changes ensure a bundle is installed.
29
31
  Gemfile.lock.installed: Gemfile.lock
30
32
  bundle install
31
33
  touch Gemfile.lock.installed
@@ -37,9 +39,11 @@ clear_metrics: ## remove or reset result artifacts created by tests and quality
37
39
 
38
40
  clean: clear_metrics ## remove all built artifacts
39
41
 
40
- quality: ## run precommit quality checks
42
+ overcommit: ## run precommit quality checks
41
43
  bundle exec overcommit --run
42
44
 
45
+ quality: overcommit ## run precommit quality checks
46
+
43
47
  test: ## Run lower-level tests
44
48
  @bundle exec rake test
45
49
 
data/README.md CHANGED
@@ -4,12 +4,28 @@ Command-line and gem client for Asana (unofficial)
4
4
 
5
5
  ## Using
6
6
 
7
- ```
7
+ ```sh
8
8
  $ checkoff --help
9
- View tasks:
10
- checkoff view workspace project [section]
9
+ NAME
10
+ checkoff - Command-line client for Asana (unofficial)
11
+
12
+
13
+ SYNOPSIS
14
+ checkoff [global options] command [command options] [arguments...]
15
+
11
16
 
12
- 'project' can be set to a project name, or :my_tasks for your user task list.
17
+
18
+ GLOBAL OPTIONS
19
+ --help - Show this message
20
+
21
+
22
+
23
+ COMMANDS
24
+ help - Shows a list of commands or help for one command
25
+ mv - Move tasks from one section to another within a project
26
+ quickadd - Add a short task to Asana
27
+ view - Output representation of Asana tasks
28
+ $
13
29
  ```
14
30
 
15
31
  Let's say we have a project like this:
@@ -18,7 +34,7 @@ Let's say we have a project like this:
18
34
 
19
35
  Checkoff outputs things in JSON. 'jq' is a great tool to use in combination:
20
36
 
21
- ```
37
+ ```sh
22
38
  $ checkoff view 'Personal Projects' 'Create demo'
23
39
  {"":[{"name":"This is a task that doesn't belong to any sections."}],"Write it:":[{"name":"Write something"}],"Publish to github:":[{"name":"git push!"}],"Make sure it looks OK!:":[{"name":"Looks it up in your browser..."}]}
24
40
  $
@@ -52,7 +68,7 @@ $ checkoff view 'Personal Projects' 'Create demo' | jq
52
68
 
53
69
  You can drill down into a section on the command line:
54
70
 
55
- ```
71
+ ```sh
56
72
  $ checkoff view 'Personal Projects' 'Create demo' 'Publish to github:'
57
73
  [{"name":"git push!"}]
58
74
  ```
@@ -71,12 +87,17 @@ $ checkoff view 'Personal Projects' 'Create demo' | jq 'to_entries | map(.value)
71
87
 
72
88
  And even gather counts for project metrics:
73
89
 
74
- ```bash
90
+ ```sh
75
91
  $ checkoff view 'Personal Projects' 'Create demo' | jq 'to_entries | map(.value) | flatten | map(.name) | length'
76
92
  4
77
93
  $
78
94
  ```
79
95
 
96
+ ## Naming things
97
+
98
+ Since checkoff looks up things by their name, if you have two things
99
+ with the same name, you're probably going to have a bad time.
100
+
80
101
  ## Caching
81
102
 
82
103
  Note that I don't know of a way through the Asana API to target
@@ -94,7 +115,7 @@ clear the cache.
94
115
 
95
116
  This will work under OS X:
96
117
 
97
- ```bash
118
+ ```sh
98
119
  brew install memcached
99
120
  ln -sfv /usr/local/opt/memcached/*.plist ~/Library/LaunchAgents
100
121
  launchctl load ~/Library/LaunchAgents/homebrew.mxcl.memcached.plist
@@ -103,7 +124,8 @@ gem install checkoff
103
124
 
104
125
  ## Configuring
105
126
 
106
- You'll need to create a file called `.asana.yml` in your home directory, that looks like this:
127
+ You'll need to create a file called `.asana.yml` in your home
128
+ directory, that looks like this:
107
129
 
108
130
  ```yaml
109
131
  ---
@@ -129,7 +151,7 @@ Alternately you can set environment variables to match - e.g., `ASANA__PERSONAL_
129
151
 
130
152
  ## Developing
131
153
 
132
- ```bash
154
+ ```sh
133
155
  bundle install
134
156
  bundle exec exe/checkoff --help
135
157
  ```
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "result": {
3
- "line": 99.73,
4
- "branch": 94.44
3
+ "line": 99.78,
4
+ "branch": 95.34
5
5
  }
6
6
  }
data/fix.sh CHANGED
@@ -127,10 +127,33 @@ ensure_bundle() {
127
127
  bundler_version=$(bundle --version | cut -d ' ' -f3)
128
128
  bundler_version_major=$(cut -d. -f1 <<< "${bundler_version}")
129
129
  bundler_version_minor=$(cut -d. -f2 <<< "${bundler_version}")
130
+ bundler_version_patch=$(cut -d. -f3 <<< "${bundler_version}")
130
131
  # Version 2.1 of bundler seems to have some issues with nokogiri:
131
132
  #
132
133
  # https://app.asana.com/0/1107901397356088/1199504270687298
133
- if [ "${bundler_version_major}" == 2 ] && [ "${bundler_version_minor}" -lt 2 ]
134
+
135
+ # Version 2.2.22 of bundler comes with a fix to ensure the 'bundle
136
+ # update --conservative' flag works as expected - important when
137
+ # doing a 'bundle update' on a about-to-be-published gem after
138
+ # bumping a gem version.
139
+ need_better_bundler=false
140
+ if [ "${bundler_version_major}" -lt 2 ]
141
+ then
142
+ need_better_bundler=true
143
+ elif [ "${bundler_version_major}" -eq 2 ]
144
+ then
145
+ if [ "${bundler_version_minor}" -lt 2 ]
146
+ then
147
+ need_better_bundler=true
148
+ elif [ "${bundler_version_minor}" -eq 2 ]
149
+ then
150
+ if [ "${bundler_version_patch}" -lt 22 ]
151
+ then
152
+ need_better_bundler=true
153
+ fi
154
+ fi
155
+ fi
156
+ if [ "${need_better_bundler}" = true ]
134
157
  then
135
158
  gem install --no-document bundler
136
159
  fi
@@ -143,7 +166,13 @@ ensure_bundle() {
143
166
  # re-resolve and consider the new platform when picking gems, all
144
167
  # without needing to have a machine that matches PLATFORM handy to
145
168
  # install those platform-specific gems on.'
146
- grep x86_64-darwin-20 Gemfile.lock >/dev/null 2>&1 || bundle lock --add-platform x86_64-darwin-20 x86_64-linux
169
+ #
170
+ # This affects nokogiri, which will try to reinstall itself in
171
+ # Docker builds where it's already installed if this is not run.
172
+ for platform in x86_64-darwin-20 x86_64-linux
173
+ do
174
+ grep "${platform:?}" Gemfile.lock >/dev/null 2>&1 || bundle lock --add-platform "${platform:?}"
175
+ done
147
176
  }
148
177
 
149
178
  set_ruby_local_version() {
data/lib/checkoff/cli.rb CHANGED
@@ -211,7 +211,7 @@ module Checkoff
211
211
  end
212
212
 
213
213
  def run
214
- workspace = @workspaces.workspace_by_name(workspace_name)
214
+ workspace = @workspaces.workspace_or_raise(workspace_name)
215
215
  @tasks.add_task(task_name,
216
216
  workspace_gid: workspace.gid)
217
217
  end
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # frozen_string_literal: true
4
+
5
+ require 'forwardable'
6
+ require_relative 'config_loader'
7
+ require 'asana'
8
+
9
+ # https://developers.asana.com/docs/clients
10
+
11
+ module Checkoff
12
+ # Pulls a configured Asana client object which can be used to access the API
13
+ class Clients
14
+ MINUTE = 60
15
+ HOUR = MINUTE * 60
16
+ DAY = 24 * HOUR
17
+ REALLY_LONG_CACHE_TIME = HOUR * 1
18
+ LONG_CACHE_TIME = MINUTE * 15
19
+ SHORT_CACHE_TIME = MINUTE
20
+
21
+ def initialize(config: Checkoff::ConfigLoader.load(:asana),
22
+ asana_client_class: Asana::Client)
23
+ @config = config
24
+ @asana_client_class = asana_client_class
25
+ end
26
+
27
+ def client
28
+ @client ||= @asana_client_class.new do |c|
29
+ c.authentication :access_token, @config.fetch(:personal_access_token)
30
+ c.default_headers 'asana-enable' => 'string_ids,new_sections'
31
+ c.default_headers 'asana-disable' => 'new_user_task_lists'
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ attr_reader :workspaces
38
+
39
+ # bundle exec ./clients.rb
40
+ # :nocov:
41
+ class << self
42
+ def run
43
+ clients = Checkoff::Clients.new
44
+ client = clients.client
45
+ puts "Results: #{client}"
46
+ end
47
+ end
48
+ # :nocov:
49
+ end
50
+ end
51
+
52
+ # :nocov:
53
+ abs_program_name = File.expand_path($PROGRAM_NAME)
54
+ Checkoff::Clients.run if abs_program_name == __FILE__
55
+ # :nocov:
@@ -0,0 +1,85 @@
1
+ #!/bin/bash -eu
2
+
3
+ set -o pipefail
4
+
5
+ underscored_plural_name="${1:?underscored plural name of entities minus .rb}"
6
+ # Sorry, shellcheck, I can't express 'end of line' in a simple variable search and replace
7
+ # shellcheck disable=SC2001
8
+ underscored_singular_name=$(sed -e 's/s$//g' <<< "${underscored_plural_name}")
9
+ kabob_case_plural_name=${underscored_plural_name/_/-}
10
+ class_name="${2:?class name without Checkoff:: prefix}"
11
+
12
+ cat > "${underscored_plural_name}.rb" << EOF
13
+ #!/usr/bin/env ruby
14
+
15
+ # frozen_string_literal: true
16
+
17
+ require 'forwardable'
18
+ require 'cache_method'
19
+ require_relative 'config_loader'
20
+ require_relative 'workspaces'
21
+ require_relative 'clients'
22
+
23
+ # https://developers.asana.com/docs/${kabob_case_plural_name}
24
+
25
+ module Checkoff
26
+ class ${class_name}
27
+ MINUTE = 60
28
+ HOUR = MINUTE * 60
29
+ DAY = 24 * HOUR
30
+ REALLY_LONG_CACHE_TIME = HOUR * 1
31
+ LONG_CACHE_TIME = MINUTE * 15
32
+ SHORT_CACHE_TIME = MINUTE
33
+
34
+ def initialize(config: Checkoff::ConfigLoader.load(:asana),
35
+ workspaces: Checkoff::Workspaces.new(config: config),
36
+ clients: Checkoff::Clients.new(config: config),
37
+ client: clients.client)
38
+ @workspaces = workspaces
39
+ @client = client
40
+ end
41
+
42
+ def ${underscored_singular_name}_or_raise(workspace_name, ${underscored_singular_name}_name)
43
+ ${underscored_singular_name} = ${underscored_singular_name}(workspace_name, ${underscored_singular_name}_name)
44
+ raise "Could not find ${underscored_singular_name} #{${underscored_singular_name}_name} under workspace #{workspace_name}." if ${underscored_singular_name}.nil?
45
+
46
+ ${underscored_singular_name}
47
+ end
48
+ cache_method :${underscored_singular_name}_or_raise, LONG_CACHE_TIME
49
+
50
+ def ${underscored_singular_name}(workspace_name, ${underscored_singular_name}_name)
51
+ workspace = workspaces.workspace_or_raise(workspace_name)
52
+ ${underscored_plural_name} = client.${underscored_plural_name}.get_${underscored_plural_name}_for_workspace(workspace_gid: workspace.gid)
53
+ ${underscored_plural_name}.find { |${underscored_singular_name}| ${underscored_singular_name}.name == ${underscored_singular_name}_name }
54
+ end
55
+ cache_method :${underscored_singular_name}, LONG_CACHE_TIME
56
+
57
+ private
58
+
59
+ attr_reader :workspaces, :client
60
+
61
+ # bundle exec ./${underscored_plural_name}.rb
62
+ # :nocov:
63
+ class << self
64
+ def run
65
+ workspace_name = ARGV[0] || raise('Please pass workspace name as first argument')
66
+ ${underscored_singular_name}_name = ARGV[1] || raise('Please pass ${underscored_singular_name} name as second argument')
67
+ ${underscored_plural_name} = Checkoff::${class_name}.new
68
+ ${underscored_singular_name} = ${underscored_plural_name}.${underscored_singular_name}_or_raise(workspace_name, ${underscored_singular_name}_name)
69
+ puts "Results: #{${underscored_singular_name}}"
70
+ end
71
+ end
72
+ # :nocov:
73
+ end
74
+ end
75
+
76
+ # :nocov:
77
+ abs_program_name = File.expand_path(\$PROGRAM_NAME)
78
+ Checkoff::${class_name}.run if abs_program_name == __FILE__
79
+ # :nocov:
80
+ EOF
81
+
82
+ chmod +x "${underscored_plural_name}.rb"
83
+ git add "${underscored_plural_name}.rb"
84
+
85
+ echo "You can start by running 'bundle exec ./${underscored_plural_name}.rb' and tweaking from there"
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # frozen_string_literal: true
4
+
5
+ require 'forwardable'
6
+ require 'cache_method'
7
+ require_relative 'config_loader'
8
+ require_relative 'workspaces'
9
+ require_relative 'clients'
10
+
11
+ # https://developers.asana.com/docs/custom-fields
12
+
13
+ module Checkoff
14
+ # Work with custom fields in Asana
15
+ class CustomFields
16
+ MINUTE = 60
17
+ HOUR = MINUTE * 60
18
+ DAY = 24 * HOUR
19
+ REALLY_LONG_CACHE_TIME = HOUR * 1
20
+ LONG_CACHE_TIME = MINUTE * 15
21
+ SHORT_CACHE_TIME = MINUTE
22
+
23
+ def initialize(config: Checkoff::ConfigLoader.load(:asana),
24
+ workspaces: Checkoff::Workspaces.new(config: config),
25
+ clients: Checkoff::Clients.new(config: config),
26
+ client: clients.client)
27
+ @workspaces = workspaces
28
+ @client = client
29
+ end
30
+
31
+ def custom_field_or_raise(workspace_name, custom_field_name)
32
+ custom_field = custom_field(workspace_name, custom_field_name)
33
+ raise "Could not find custom_field #{custom_field_name} under workspace #{workspace_name}." if custom_field.nil?
34
+
35
+ custom_field
36
+ end
37
+ cache_method :custom_field_or_raise, LONG_CACHE_TIME
38
+
39
+ def custom_field(workspace_name, custom_field_name)
40
+ workspace = workspaces.workspace_or_raise(workspace_name)
41
+ custom_fields = client.custom_fields.get_custom_fields_for_workspace(workspace_gid: workspace.gid)
42
+ custom_fields.find { |custom_field| custom_field.name == custom_field_name }
43
+ end
44
+ cache_method :custom_field, LONG_CACHE_TIME
45
+
46
+ private
47
+
48
+ attr_reader :workspaces, :client
49
+
50
+ # bundle exec ./custom_fields.rb
51
+ # :nocov:
52
+ class << self
53
+ def run
54
+ workspace_name = ARGV[0] || raise('Please pass workspace name as first argument')
55
+ custom_field_name = ARGV[1] || raise('Please pass custom_field name as second argument')
56
+ custom_fields = Checkoff::CustomFields.new
57
+ custom_field = custom_fields.custom_field_or_raise(workspace_name, custom_field_name)
58
+ puts "Results: #{custom_field}"
59
+ end
60
+ end
61
+ # :nocov:
62
+ end
63
+ end
64
+
65
+ # :nocov:
66
+ abs_program_name = File.expand_path($PROGRAM_NAME)
67
+ Checkoff::CustomFields.run if abs_program_name == __FILE__
68
+ # :nocov:
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'config_loader'
4
-
4
+ require_relative 'workspaces'
5
+ require_relative 'clients'
5
6
  require 'cache_method'
6
7
  require 'asana'
7
8
 
@@ -23,16 +24,12 @@ module Checkoff
23
24
  SHORT_CACHE_TIME = MINUTE * 5
24
25
 
25
26
  def initialize(config: Checkoff::ConfigLoader.load(:asana),
26
- asana_client: Asana::Client,
27
- workspaces: Checkoff::Workspaces.new(config: config))
27
+ workspaces: Checkoff::Workspaces.new(config: config),
28
+ clients: Checkoff::Clients.new(config: config),
29
+ client: clients.client)
28
30
  @config = config
29
- @asana_client = asana_client
30
31
  @workspaces = workspaces
31
- end
32
-
33
- # Returns Asana Ruby API Client object
34
- def client
35
- @workspaces.client
32
+ @client = client
36
33
  end
37
34
 
38
35
  # Default options used in Asana API to pull taskso
@@ -84,20 +81,22 @@ module Checkoff
84
81
 
85
82
  private
86
83
 
84
+ attr_reader :client
85
+
87
86
  def projects
88
87
  client.projects
89
88
  end
90
89
  cache_method :projects, LONG_CACHE_TIME
91
90
 
92
91
  def projects_by_workspace_name(workspace_name)
93
- workspace = @workspaces.workspace_by_name(workspace_name)
92
+ workspace = @workspaces.workspace_or_raise(workspace_name)
94
93
  raise "Could not find workspace named #{workspace_name}" unless workspace
95
94
 
96
95
  projects.find_by_workspace(workspace: workspace.gid)
97
96
  end
98
97
 
99
98
  def my_tasks(workspace_name)
100
- workspace = @workspaces.workspace_by_name(workspace_name)
99
+ workspace = @workspaces.workspace_or_raise(workspace_name)
101
100
  result = client.user_task_lists.get_user_task_list_for_user(user_gid: 'me',
102
101
  workspace: workspace.gid)
103
102
  gid = result.gid
@@ -1,6 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'forwardable'
4
+ require_relative 'projects'
5
+ require_relative 'workspaces'
6
+ require_relative 'clients'
4
7
 
5
8
  module Checkoff
6
9
  # Query different sections of Asana projects
@@ -16,10 +19,13 @@ module Checkoff
16
19
  def initialize(config: Checkoff::ConfigLoader.load(:asana),
17
20
  projects: Checkoff::Projects.new(config: config),
18
21
  workspaces: Checkoff::Workspaces.new(config: config),
22
+ clients: Checkoff::Clients.new(config: config),
23
+ client: clients.client,
19
24
  time: Time)
20
25
  @projects = projects
21
26
  @workspaces = workspaces
22
27
  @time = time
28
+ @client = client
23
29
  end
24
30
 
25
31
  # Returns a list of Asana API section objects for a given project
@@ -72,6 +78,8 @@ module Checkoff
72
78
 
73
79
  private
74
80
 
81
+ attr_reader :client
82
+
75
83
  # Given a project object, pull all tasks, then provide a Hash of
76
84
  # tasks with section name -> task list of the uncompleted tasks
77
85
  def tasks_by_section_for_project(project)
@@ -80,8 +88,6 @@ module Checkoff
80
88
  by_section(active_tasks, project.gid)
81
89
  end
82
90
 
83
- def_delegators :@projects, :client
84
-
85
91
  # Given a list of tasks, pull a Hash of tasks with section name -> task list
86
92
  def by_section(tasks, project_gid)
87
93
  by_section = {}
@@ -97,7 +103,7 @@ module Checkoff
97
103
  raise "Could not find task in project_gid #{project_gid}: #{task}" if membership.nil?
98
104
 
99
105
  current_section = membership['section']['name']
100
- current_section = nil if current_section == '(no section)'
106
+ current_section = nil if ['(no section)', 'Untitled section'].include?(current_section)
101
107
  by_section[current_section] ||= []
102
108
  by_section[current_section] << task
103
109
  end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'forwardable'
4
+ require_relative 'config_loader'
5
+ require_relative 'projects'
4
6
 
5
7
  module Checkoff
6
8
  # Query different subtasks of Asana tasks
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # frozen_string_literal: true
4
+
5
+ require 'forwardable'
6
+ require 'cache_method'
7
+ require_relative 'config_loader'
8
+ require_relative 'workspaces'
9
+ require_relative 'clients'
10
+
11
+ # https://developers.asana.com/docs/tags
12
+
13
+ module Checkoff
14
+ # Work with tags in Asana
15
+ class Tags
16
+ MINUTE = 60
17
+ HOUR = MINUTE * 60
18
+ DAY = 24 * HOUR
19
+ REALLY_LONG_CACHE_TIME = HOUR * 1
20
+ LONG_CACHE_TIME = MINUTE * 15
21
+ SHORT_CACHE_TIME = MINUTE
22
+
23
+ def initialize(config: Checkoff::ConfigLoader.load(:asana),
24
+ workspaces: Checkoff::Workspaces.new(config: config),
25
+ clients: Checkoff::Clients.new(config: config),
26
+ client: clients.client)
27
+ @workspaces = workspaces
28
+ @client = client
29
+ end
30
+
31
+ def tag_or_raise(workspace_name, tag_name)
32
+ tag = tag(workspace_name, tag_name)
33
+ raise "Could not find tag #{tag_name} under workspace #{workspace_name}." if tag.nil?
34
+
35
+ tag
36
+ end
37
+ cache_method :tag_or_raise, LONG_CACHE_TIME
38
+
39
+ def tag(workspace_name, tag_name)
40
+ workspace = workspaces.workspace_or_raise(workspace_name)
41
+ tags = client.tags.get_tags_for_workspace(workspace_gid: workspace.gid)
42
+ tags.find { |tag| tag.name == tag_name }
43
+ end
44
+ cache_method :tag, LONG_CACHE_TIME
45
+
46
+ private
47
+
48
+ attr_reader :workspaces, :client
49
+
50
+ # bundle exec ./tags.rb
51
+ # :nocov:
52
+ class << self
53
+ def run
54
+ workspace_name = ARGV[0] || raise('Please pass workspace name as first argument')
55
+ tag_name = ARGV[1] || raise('Please pass tag name as second argument')
56
+ tags = Checkoff::Tags.new
57
+ tag = tags.tag_or_raise(workspace_name, tag_name)
58
+ puts "Results: #{tag}"
59
+ end
60
+ end
61
+ # :nocov:
62
+ end
63
+ end
64
+
65
+ # :nocov:
66
+ abs_program_name = File.expand_path($PROGRAM_NAME)
67
+ Checkoff::Tags.run if abs_program_name == __FILE__
68
+ # :nocov:
@@ -16,10 +16,25 @@ module Checkoff
16
16
 
17
17
  def initialize(config: Checkoff::ConfigLoader.load(:asana),
18
18
  sections: Checkoff::Sections.new(config: config),
19
+ clients: Checkoff::Clients.new(config: config),
20
+ client: clients.client,
21
+ time_class: Time,
19
22
  asana_task: Asana::Resources::Task)
20
23
  @config = config
21
24
  @sections = sections
25
+ @time_class = time_class
22
26
  @asana_task = asana_task
27
+ @client = client
28
+ end
29
+
30
+ def task_ready?(task)
31
+ return false if incomplete_dependencies?(task)
32
+
33
+ due = due_time(task)
34
+
35
+ return true if due.nil?
36
+
37
+ due < @time_class.now
23
38
  end
24
39
 
25
40
  # Pull a specific task by name
@@ -52,9 +67,7 @@ module Checkoff
52
67
 
53
68
  private
54
69
 
55
- def client
56
- @sections.client
57
- end
70
+ attr_reader :client
58
71
 
59
72
  def projects
60
73
  @projects ||= @sections.projects
@@ -63,5 +76,21 @@ module Checkoff
63
76
  def default_assignee_gid
64
77
  @config.fetch(:default_assignee_gid)
65
78
  end
79
+
80
+ def due_time(task)
81
+ return @time_class.parse(task.due_at) if task.due_at
82
+ return @time_class.parse(task.due_on) if task.due_on
83
+
84
+ nil
85
+ end
86
+
87
+ def incomplete_dependencies?(task)
88
+ task.dependencies.any? do |parent_task_info|
89
+ parent_task_gid = parent_task_info.gid
90
+ parent_task = @asana_task.find_by_id(client, parent_task_gid,
91
+ options: { fields: ['completed'] })
92
+ !parent_task.completed
93
+ end
94
+ end
66
95
  end
67
96
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Checkoff
4
4
  # Version of library
5
- VERSION = '0.14.0'
5
+ VERSION = '0.15.2'
6
6
  end
@@ -1,32 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'forwardable'
4
+ require 'cache_method'
5
+ require_relative 'config_loader'
6
+ require_relative 'clients'
7
+
8
+ # https://developers.asana.com/docs/workspaces
9
+
3
10
  module Checkoff
4
11
  # Query different workspaces of Asana projects
5
12
  class Workspaces
13
+ MINUTE = 60
14
+ HOUR = MINUTE * 60
15
+ DAY = 24 * HOUR
16
+ REALLY_LONG_CACHE_TIME = HOUR * 1
17
+ LONG_CACHE_TIME = MINUTE * 15
18
+ SHORT_CACHE_TIME = MINUTE
19
+
6
20
  def initialize(config: Checkoff::ConfigLoader.load(:asana),
7
- asana_client: Asana::Client)
21
+ clients: Checkoff::Clients.new(config: config),
22
+ client: clients.client)
8
23
  @config = config
9
- @asana_client = asana_client
10
- end
11
-
12
- # Returns Asana Ruby API Client object
13
- def client
14
- @client ||= @asana_client.new do |c|
15
- c.authentication :access_token, @config.fetch(:personal_access_token)
16
- c.default_headers 'asana-enable' => 'string_ids,new_sections'
17
- c.default_headers 'asana-disable' => 'new_user_task_lists'
18
- end
24
+ @client = client
19
25
  end
20
26
 
21
27
  # Pulls an Asana workspace object
22
- def workspace_by_name(workspace_name)
28
+ def workspace(workspace_name)
23
29
  client.workspaces.find_all.find do |workspace|
24
30
  workspace.name == workspace_name
25
- end || raise("Could not find workspace named [#{workspace_name}]")
31
+ end
32
+ end
33
+
34
+ def workspace_or_raise(workspace_name)
35
+ workspace = workspace(workspace_name)
36
+ raise "Could not find workspace #{workspace_name}" if workspace.nil?
37
+
38
+ workspace
26
39
  end
27
40
 
28
41
  private
29
42
 
43
+ attr_reader :client
44
+
30
45
  def default_workspace_gid
31
46
  @config.fetch(:default_workspace_gid)
32
47
  end
data/lib/checkoff.rb CHANGED
@@ -6,3 +6,5 @@ require 'checkoff/projects'
6
6
  require 'checkoff/sections'
7
7
  require 'checkoff/subtasks'
8
8
  require 'checkoff/tasks'
9
+ require 'checkoff/custom_fields'
10
+ require 'checkoff/tags'
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.14.0
4
+ version: 0.15.2
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-08-03 00:00:00.000000000 Z
11
+ date: 2021-09-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -299,10 +299,14 @@ files:
299
299
  - fix.sh
300
300
  - lib/checkoff.rb
301
301
  - lib/checkoff/cli.rb
302
+ - lib/checkoff/clients.rb
302
303
  - lib/checkoff/config_loader.rb
304
+ - lib/checkoff/create-entity.sh
305
+ - lib/checkoff/custom_fields.rb
303
306
  - lib/checkoff/projects.rb
304
307
  - lib/checkoff/sections.rb
305
308
  - lib/checkoff/subtasks.rb
309
+ - lib/checkoff/tags.rb
306
310
  - lib/checkoff/tasks.rb
307
311
  - lib/checkoff/version.rb
308
312
  - lib/checkoff/workspaces.rb