checkoff 0.42.0 → 0.44.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: 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