checkoff 0.42.0 → 0.44.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: 83cd30ff493ada586596020db325eed63c9e4c24919e34c7e9926c0f9bedf51f
4
- data.tar.gz: fee54feaa76dafc06dba69267f4ea6a7b2877e68df6af43738468e65cca552b6
3
+ metadata.gz: 413eeaac4e3e2a4784e5fca4930fed96beedd594b87f1c8d80460aabe4ee1dd3
4
+ data.tar.gz: 4127604e8d5c3605d49c2fda86fe0c0e1bed95aaeadfc493d8a2b02c19bed94d
5
5
  SHA512:
6
- metadata.gz: 7d4cb677d35d91830b2aa6145d40a74ebb1e34ddd9a1e17203ef62ac66afb30a3a864924462de263ff663d33cc561272143fd1b0ab45e9499c4f42e2dad97840
7
- data.tar.gz: b074ac5d6a2675e801b52e96d8453847607bf0e523a5988a50456258f1a668319846c8c1f965eadb09409f83b82d23b1262935c2606bab175de0664c7af2077a
6
+ metadata.gz: 001c49dab8df9d273f2c395dd422509afa82c856712b7dfef9b7c65bf7f23c7d3ada832d32e888b188d38751716ee7e54c8d144b4575cd2de384946002ae6fc5
7
+ data.tar.gz: a10f6ee8a33870277503458dc19809e642d837899c31c1698ba04942356386fe09c713643db3f3694eca7d5495c43fe13c93d2ae7785e3ad383aeed88651e2f0
data/Gemfile.lock CHANGED
@@ -12,7 +12,7 @@ GIT
12
12
  PATH
13
13
  remote: .
14
14
  specs:
15
- checkoff (0.42.0)
15
+ checkoff (0.44.0)
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 (7.0.5)
25
+ activesupport (7.0.5.1)
26
26
  concurrent-ruby (~> 1.0, >= 1.0.2)
27
27
  i18n (>= 1.6, < 2)
28
28
  minitest (>= 5.1)
@@ -8,19 +8,27 @@ module Checkoff
8
8
  # Use the provided config from a YAML file, and fall back to env
9
9
  # variable if it's not populated for a key'
10
10
  class EnvFallbackConfigLoader
11
+ # @param config [Hash<Symbol, Object>]
12
+ # @param sym [Symbol]
13
+ # @param yaml_filename [String]
11
14
  def initialize(config, sym, yaml_filename)
12
15
  @config = config
13
16
  @envvar_prefix = sym.upcase
14
17
  @yaml_filename = yaml_filename
15
18
  end
16
19
 
20
+ # @param key [Symbol]
21
+ # @return [Object]
17
22
  def [](key)
18
23
  config_value = @config[key]
19
24
  return config_value unless config_value.nil?
20
25
 
26
+ # @sg-ignore
21
27
  ENV.fetch(envvar_name(key), nil)
22
28
  end
23
29
 
30
+ # @param key [Symbol]
31
+ # @return [Object]
24
32
  def fetch(key)
25
33
  out = self[key]
26
34
  return out unless out.nil?
@@ -31,6 +39,8 @@ module Checkoff
31
39
 
32
40
  private
33
41
 
42
+ # @param key [Symbol]
43
+ # @return [String]
34
44
  def envvar_name(key)
35
45
  "#{@envvar_prefix}__#{key.upcase}"
36
46
  end
@@ -39,7 +49,8 @@ module Checkoff
39
49
  # Load configuration file
40
50
  class ConfigLoader
41
51
  class << self
42
- # @return EnvFallbackConfigLoader
52
+ # @sg-ignore
53
+ # @return [Hash<Symbol, Object>]
43
54
  def load(sym)
44
55
  yaml_result = load_yaml_file(sym)
45
56
  EnvFallbackConfigLoader.new(yaml_result, sym, yaml_filename(sym))
@@ -47,13 +58,18 @@ module Checkoff
47
58
 
48
59
  private
49
60
 
61
+ # @param sym [Symbol]
62
+ # @return [Hash<[String, Symbol], Object>]
50
63
  def load_yaml_file(sym)
51
64
  filename = yaml_filename(sym)
52
65
  return {} unless File.exist?(filename)
53
66
 
67
+ # @sg-ignore
54
68
  YAML.load_file(filename).with_indifferent_access
55
69
  end
56
70
 
71
+ # @param sym [Symbol]
72
+ # @return [String]
57
73
  def yaml_filename(sym)
58
74
  file = "#{sym}.yml"
59
75
  File.expand_path("~/.#{file}")
@@ -101,7 +101,7 @@ module Checkoff
101
101
  def pull_custom_field_by_name(task, custom_field_name)
102
102
  custom_fields = task.custom_fields
103
103
  if custom_fields.nil?
104
- raise "custom fields not found on task - did you add 'custom_field' in your extra_fields argument?"
104
+ raise "custom fields not found on task - did you add 'custom_fields' in your extra_fields argument?"
105
105
  end
106
106
 
107
107
  # @sg-ignore
@@ -339,6 +339,30 @@ module Checkoff
339
339
  end
340
340
  end
341
341
 
342
+ # :custom_field_greater_than_or_equal_to_n_days_from_now function
343
+ class CustomFieldGreaterThanOrEqualToNDaysFromNowFunctionEvaluator < FunctionEvaluator
344
+ def matches?
345
+ fn?(task_selector, :custom_field_greater_than_or_equal_to_n_days_from_now)
346
+ end
347
+
348
+ def evaluate_arg?(_index)
349
+ false
350
+ end
351
+
352
+ # @param task [Asana::Resources::Task]
353
+ # @param custom_field_name [String]
354
+ # @param num_days [Integer]
355
+ # @return [Boolean]
356
+ def evaluate(task, custom_field_name, num_days)
357
+ custom_field = pull_custom_field_by_name_or_raise(task, custom_field_name)
358
+
359
+ time_str = custom_field.fetch('display_value')
360
+ time = Time.parse(time_str)
361
+ n_days_from_now = (Time.now + (num_days * 24 * 60 * 60))
362
+ time >= n_days_from_now
363
+ end
364
+ end
365
+
342
366
  # String literals
343
367
  class StringLiteralEvaluator < FunctionEvaluator
344
368
  def matches?
@@ -376,6 +400,7 @@ module Checkoff
376
400
  DuePFunctionEvaluator,
377
401
  DueDateSetPFunctionEvaluator,
378
402
  CustomFieldLessThanNDaysFromNowFunctionEvaluator,
403
+ CustomFieldGreaterThanOrEqualToNDaysFromNowFunctionEvaluator,
379
404
  StringLiteralEvaluator,
380
405
  ].freeze
381
406
 
@@ -27,6 +27,17 @@ module Checkoff
27
27
 
28
28
  include Asana::Resources::ResponseHelper
29
29
 
30
+ # @!parse
31
+ # extend CacheMethod::ClassMethods
32
+
33
+ # @param config [Hash<Symbol, Object>]
34
+ # @param workspaces [Checkoff::Workspaces]
35
+ # @param task_selectors [Checkoff::TaskSelectors]
36
+ # @param projects [Checkoff::Projects]
37
+ # @param clients [Checkoff::Clients]
38
+ # @param client [Asana::Client]
39
+ # @param search_url_parser [Checkoff::Internal::SearchUrl::Parser]
40
+ # @param asana_resources_collection_class [Class<Asana::Resources::Collection>]
30
41
  def initialize(config: Checkoff::Internal::ConfigLoader.load(:asana),
31
42
  workspaces: Checkoff::Workspaces.new(config: config),
32
43
  task_selectors: Checkoff::TaskSelectors.new(config: config),
@@ -49,6 +60,7 @@ module Checkoff
49
60
  # @return [Array<Asana::Resources::Task>]
50
61
  def task_search(workspace_name, url, extra_fields: [])
51
62
  workspace = workspaces.workspace_or_raise(workspace_name)
63
+ # @sg-ignore
52
64
  api_params, task_selector = @search_url_parser.convert_params(url)
53
65
  path = "/workspaces/#{workspace.gid}/tasks/search"
54
66
  options = calculate_api_options(extra_fields)
@@ -76,8 +88,13 @@ module Checkoff
76
88
  # bundle exec ./task_searches.rb
77
89
  # :nocov:
78
90
  class << self
91
+ # @return [void]
79
92
  def run
93
+ # @sg-ignore
94
+ # @type [String]
80
95
  workspace_name = ARGV[0] || raise('Please pass workspace name as first argument')
96
+ # @sg-ignore
97
+ # @type [String]
81
98
  url = ARGV[1] || raise('Please pass task search URL as second argument')
82
99
  task_searches = Checkoff::TaskSearches.new
83
100
  task_search = task_searches.task_search(workspace_name, url)
@@ -86,7 +103,14 @@ module Checkoff
86
103
  end
87
104
  # :nocov:
88
105
 
89
- attr_reader :task_selectors, :projects, :workspaces, :client
106
+ # @return [Checkoff::TaskSelectors]
107
+ attr_reader :task_selectors
108
+ # @return [Checkoff::Projects]
109
+ attr_reader :projects
110
+ # @return [Checkoff::Workspaces]
111
+ attr_reader :workspaces
112
+ # @return [Asana::Client]
113
+ attr_reader :client
90
114
  end
91
115
  end
92
116
 
@@ -4,25 +4,25 @@
4
4
 
5
5
  require_relative 'sections'
6
6
  require_relative 'workspaces'
7
+ require_relative 'internal/config_loader'
7
8
  require 'asana'
8
9
 
9
10
  module Checkoff
10
11
  # Pull tasks from Asana
11
12
  class Tasks
12
13
  MINUTE = 60
13
- # @sg-ignore
14
14
  HOUR = MINUTE * 60
15
15
  DAY = 24 * HOUR
16
16
  REALLY_LONG_CACHE_TIME = HOUR
17
- # @sg-ignore
18
17
  LONG_CACHE_TIME = MINUTE * 15
19
- # @sg-ignore
20
18
  SHORT_CACHE_TIME = MINUTE * 5
21
19
 
20
+ # @param config [Hash<Symbol, Object>]
22
21
  # @param client [Asana::Client]
23
22
  # @param workspaces [Checkoff::Workspaces]
24
- # @param time_class [Class<Time>]
25
23
  # @param sections [Checkoff::Sections]
24
+ # @param time_class [Class<Time>]
25
+ # @param asana_task [Class<Asana::Resources::Task>]
26
26
  def initialize(config: Checkoff::Internal::ConfigLoader.load(:asana),
27
27
  client: Checkoff::Clients.new(config: config).client,
28
28
  workspaces: Checkoff::Workspaces.new(config: config,
@@ -39,8 +39,10 @@ module Checkoff
39
39
  @workspaces = workspaces
40
40
  end
41
41
 
42
- def task_ready?(task)
43
- return false if incomplete_dependencies?(task)
42
+ # @param task [Asana::Resources::Task]
43
+ # @param ignore_dependencies [Boolean]
44
+ def task_ready?(task, ignore_dependencies: false)
45
+ return false if !ignore_dependencies && incomplete_dependencies?(task)
44
46
 
45
47
  due = due_time(task)
46
48
 
@@ -50,11 +52,19 @@ module Checkoff
50
52
  end
51
53
 
52
54
  # Pull a specific task by name
55
+ # @param workspace_name [String]
56
+ # @param project_name [String, Symbol]
57
+ # @param section_name [String, nil, Symbol]
58
+ # @param task_name [String]
59
+ # @param only_uncompleted [Boolean]
60
+ # @param extra_fields [Array<String>]
61
+ # @sg-ignore
53
62
  # @return [Asana::Resources::Task, nil]
54
63
  def task(workspace_name, project_name, task_name,
55
64
  section_name: :unspecified,
56
65
  only_uncompleted: true,
57
66
  extra_fields: [])
67
+ # @sg-ignore
58
68
  tasks = tasks_from_section(workspace_name,
59
69
  project_name,
60
70
  section_name: section_name,
@@ -74,6 +84,7 @@ module Checkoff
74
84
  client.tasks.find_by_id(task_gid, options: options)
75
85
  end
76
86
 
87
+ # @param name [String]
77
88
  # @param workspace_gid [String]
78
89
  # @param assignee_gid [String]
79
90
  # @return [Asana::Resources::Task]
@@ -85,13 +96,19 @@ module Checkoff
85
96
  workspace: workspace_gid, name: name)
86
97
  end
87
98
 
88
- # Return an end-user URL to the task in question
99
+ # @param task [Asana::Resources::Task]
100
+ # @return [String] end-user URL to the task in question
89
101
  def url_of_task(task)
90
102
  "https://app.asana.com/0/0/#{task.gid}/f"
91
103
  end
92
104
 
93
105
  private
94
106
 
107
+ # @param workspace_name [String]
108
+ # @param project_name [String, Symbol]
109
+ # @param section_name [String, nil, :unspecified]
110
+ # @param only_uncompleted [Boolean]
111
+ # @param extra_fields [Array<String>]
95
112
  # @return [Array<Asana::Resources::Task>]
96
113
  def tasks_from_section(workspace_name, project_name,
97
114
  section_name:,
@@ -109,6 +126,7 @@ module Checkoff
109
126
  end
110
127
  end
111
128
 
129
+ # @return [Asana::Client]
112
130
  attr_reader :client
113
131
 
114
132
  # @return [Checkoff::Projects]
@@ -131,6 +149,7 @@ module Checkoff
131
149
  nil
132
150
  end
133
151
 
152
+ # @param task [Asana::Resources::Task]
134
153
  def incomplete_dependencies?(task)
135
154
  # Avoid a redundant fetch. Unfortunately, Ruby SDK allows
136
155
  # dependencies to be fetched along with other attributes--but
@@ -3,5 +3,5 @@
3
3
  # Command-line and gem client for Asana (unofficial)
4
4
  module Checkoff
5
5
  # Version of library
6
- VERSION = '0.42.0'
6
+ VERSION = '0.44.0'
7
7
  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.42.0
4
+ version: 0.44.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: 2023-06-23 00:00:00.000000000 Z
11
+ date: 2023-06-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport