abt-cli 0.0.21 → 0.0.22
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 +4 -4
- data/bin/abt +3 -3
- data/lib/abt.rb +6 -6
- data/lib/abt/ari.rb +1 -1
- data/lib/abt/ari_list.rb +1 -1
- data/lib/abt/base_command.rb +7 -7
- data/lib/abt/cli.rb +27 -40
- data/lib/abt/cli/arguments_parser.rb +5 -9
- data/lib/abt/cli/global_commands.rb +23 -0
- data/lib/abt/cli/global_commands/commands.rb +2 -2
- data/lib/abt/cli/global_commands/examples.rb +2 -2
- data/lib/abt/cli/global_commands/help.rb +2 -2
- data/lib/abt/cli/global_commands/readme.rb +2 -2
- data/lib/abt/cli/global_commands/share.rb +6 -6
- data/lib/abt/cli/global_commands/version.rb +2 -2
- data/lib/abt/cli/prompt.rb +51 -20
- data/lib/abt/docs.rb +39 -33
- data/lib/abt/docs/cli.rb +3 -3
- data/lib/abt/docs/markdown.rb +5 -5
- data/lib/abt/git_config.rb +4 -6
- data/lib/abt/providers/asana/api.rb +9 -9
- data/lib/abt/providers/asana/base_command.rb +8 -10
- data/lib/abt/providers/asana/commands/add.rb +13 -12
- data/lib/abt/providers/asana/commands/branch_name.rb +8 -8
- data/lib/abt/providers/asana/commands/clear.rb +7 -8
- data/lib/abt/providers/asana/commands/current.rb +14 -14
- data/lib/abt/providers/asana/commands/finalize.rb +11 -12
- data/lib/abt/providers/asana/commands/harvest_time_entry_data.rb +11 -11
- data/lib/abt/providers/asana/commands/init.rb +8 -41
- data/lib/abt/providers/asana/commands/pick.rb +17 -17
- data/lib/abt/providers/asana/commands/projects.rb +5 -5
- data/lib/abt/providers/asana/commands/share.rb +5 -5
- data/lib/abt/providers/asana/commands/start.rb +21 -20
- data/lib/abt/providers/asana/commands/tasks.rb +6 -6
- data/lib/abt/providers/asana/configuration.rb +25 -25
- data/lib/abt/providers/asana/path.rb +5 -5
- data/lib/abt/providers/devops/api.rb +12 -12
- data/lib/abt/providers/devops/base_command.rb +10 -10
- data/lib/abt/providers/devops/commands/boards.rb +5 -7
- data/lib/abt/providers/devops/commands/branch_name.rb +9 -9
- data/lib/abt/providers/devops/commands/clear.rb +7 -8
- data/lib/abt/providers/devops/commands/current.rb +17 -17
- data/lib/abt/providers/devops/commands/harvest_time_entry_data.rb +13 -13
- data/lib/abt/providers/devops/commands/init.rb +17 -13
- data/lib/abt/providers/devops/commands/pick.rb +11 -11
- data/lib/abt/providers/devops/commands/share.rb +5 -5
- data/lib/abt/providers/devops/commands/{work-items.rb → work_items.rb} +3 -3
- data/lib/abt/providers/devops/configuration.rb +19 -15
- data/lib/abt/providers/devops/path.rb +5 -4
- data/lib/abt/providers/git/commands/branch.rb +17 -19
- data/lib/abt/providers/harvest/api.rb +8 -8
- data/lib/abt/providers/harvest/base_command.rb +6 -8
- data/lib/abt/providers/harvest/commands/clear.rb +7 -8
- data/lib/abt/providers/harvest/commands/current.rb +13 -13
- data/lib/abt/providers/harvest/commands/init.rb +10 -38
- data/lib/abt/providers/harvest/commands/pick.rb +11 -11
- data/lib/abt/providers/harvest/commands/projects.rb +5 -5
- data/lib/abt/providers/harvest/commands/share.rb +5 -5
- data/lib/abt/providers/harvest/commands/start.rb +5 -3
- data/lib/abt/providers/harvest/commands/stop.rb +12 -12
- data/lib/abt/providers/harvest/commands/tasks.rb +7 -7
- data/lib/abt/providers/harvest/commands/track.rb +21 -20
- data/lib/abt/providers/harvest/configuration.rb +18 -18
- data/lib/abt/providers/harvest/path.rb +5 -5
- data/lib/abt/version.rb +1 -1
- metadata +6 -5
data/lib/abt/docs.rb
CHANGED
@@ -9,37 +9,39 @@ module Abt
|
|
9
9
|
class << self
|
10
10
|
def basic_examples
|
11
11
|
{
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
12
|
+
"Getting started:" => {
|
13
|
+
"abt init asana harvest" => "Setup asana and harvest project for local git repo",
|
14
|
+
"abt pick harvest" => "Pick harvest task. This will likely stay the same throughout the project",
|
15
|
+
"abt pick asana | abt start harvest" => "Pick asana task and start tracking time",
|
16
|
+
"abt stop harvest" => "Stop time tracker",
|
17
|
+
"abt start asana harvest" => "Continue working, e.g., after a break",
|
18
|
+
"abt finalize asana" => "Finalize the selected asana task"
|
19
19
|
}
|
20
20
|
}
|
21
21
|
end
|
22
22
|
|
23
|
-
def extended_examples
|
23
|
+
def extended_examples # rubocop:disable Metrics/MethodLength
|
24
24
|
{
|
25
|
-
|
26
|
-
|
27
|
-
'abt pick harvest -d | abt track harvest -c "Name of meeting"' =>
|
25
|
+
"Tracking meetings (without switching current task setting):" => {
|
26
|
+
"abt pick asana -d | abt track harvest" => "Track on asana meeting task",
|
27
|
+
'abt pick harvest -d | abt track harvest -c "Name of meeting"' => "Track on separate harvest-task"
|
28
28
|
},
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
"Many commands output ARIs that can be piped into other commands:" => {
|
30
|
+
"abt tasks asana | grep -i <name of task>" => nil,
|
31
|
+
"abt tasks asana | grep -i <name of task> | abt start" => nil
|
32
32
|
},
|
33
|
-
|
34
|
-
'abt share asana harvest | tr "\n" " "' =>
|
35
|
-
'abt share asana harvest | tr "\n" " " | pbcopy' =>
|
36
|
-
|
37
|
-
|
33
|
+
"Sharing ARIs:" => {
|
34
|
+
'abt share asana harvest | tr "\n" " "' => "Print current asana and harvest ARIs on a single line",
|
35
|
+
'abt share asana harvest | tr "\n" " " | pbcopy' => "Copy ARIs to clipboard (mac only)",
|
36
|
+
"abt start <ARIs from coworker>" => "Work on a task your coworker shared with you",
|
37
|
+
"abt current <ARIs from coworker> | abt start" => "Set task as current, then start it"
|
38
38
|
},
|
39
|
-
|
40
|
-
'abt start harvest -c "comment"' =>
|
41
|
-
'abt start harvest -c "comment" -- asana' =>
|
42
|
-
|
39
|
+
"Flags:" => {
|
40
|
+
'abt start harvest -c "comment"' => "Add command flags after ARIs",
|
41
|
+
'abt start harvest -c "comment" -- asana' =>
|
42
|
+
"Use -- to end a list of flags, so that it can be followed by another ARI",
|
43
|
+
'abt pick harvest | abt start -c "comment"' =>
|
44
|
+
"Flags placed directly after a command applies to the piped in ARI"
|
43
45
|
}
|
44
46
|
}
|
45
47
|
end
|
@@ -48,15 +50,7 @@ module Abt
|
|
48
50
|
@providers ||= begin
|
49
51
|
providers = {}
|
50
52
|
|
51
|
-
|
52
|
-
providers['Global'] = global_command_names.each_with_object({}) do |name, definition|
|
53
|
-
command_class = Abt::Cli.global_command_class(name)
|
54
|
-
full_name = "abt #{name}"
|
55
|
-
|
56
|
-
if command_class.respond_to?(:usage) && command_class.respond_to?(:description)
|
57
|
-
definition[full_name] = [command_class.usage, command_class.description]
|
58
|
-
end
|
59
|
-
end
|
53
|
+
providers["Global"] = global_command_definitions
|
60
54
|
|
61
55
|
Abt.schemes.sort.each_with_object(providers) do |scheme, definition|
|
62
56
|
definition[scheme] = command_definitions(scheme)
|
@@ -68,6 +62,18 @@ module Abt
|
|
68
62
|
|
69
63
|
private
|
70
64
|
|
65
|
+
def global_command_definitions
|
66
|
+
global_command_names = Abt::Cli::GlobalCommands.command_names
|
67
|
+
global_command_names.each_with_object({}) do |name, definition|
|
68
|
+
command_class = Abt::Cli::GlobalCommands.command_class(name)
|
69
|
+
full_name = "abt #{name}"
|
70
|
+
|
71
|
+
if command_class.respond_to?(:usage) && command_class.respond_to?(:description)
|
72
|
+
definition[full_name] = [command_class.usage.strip, command_class.description.strip]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
71
77
|
def command_definitions(scheme)
|
72
78
|
provider = Abt.scheme_provider(scheme)
|
73
79
|
provider.command_names.each_with_object({}) do |name, definition|
|
@@ -75,7 +81,7 @@ module Abt
|
|
75
81
|
full_name = "abt #{name} #{scheme}"
|
76
82
|
|
77
83
|
if command_class.respond_to?(:usage) && command_class.respond_to?(:description)
|
78
|
-
definition[full_name] = [command_class.usage, command_class.description]
|
84
|
+
definition[full_name] = [command_class.usage.strip, command_class.description.strip]
|
79
85
|
end
|
80
86
|
end
|
81
87
|
end
|
data/lib/abt/docs/cli.rb
CHANGED
@@ -45,14 +45,14 @@ module Abt
|
|
45
45
|
private
|
46
46
|
|
47
47
|
def usage_line
|
48
|
-
|
48
|
+
"abt <command> [<ARI>] [<options> --] [<ARI>] ..."
|
49
49
|
end
|
50
50
|
|
51
51
|
def formatted_examples(example_groups)
|
52
52
|
lines = []
|
53
53
|
|
54
54
|
example_groups.each_with_index do |(title, examples), index|
|
55
|
-
lines <<
|
55
|
+
lines << "" unless index.zero?
|
56
56
|
lines << title
|
57
57
|
|
58
58
|
max_length = examples.keys.map(&:length).max
|
@@ -68,7 +68,7 @@ module Abt
|
|
68
68
|
lines = []
|
69
69
|
|
70
70
|
Docs.providers.each_with_index do |(scheme, commands_definition), index|
|
71
|
-
lines <<
|
71
|
+
lines << "" unless index.zero?
|
72
72
|
lines << "#{inflector.humanize(scheme)}:"
|
73
73
|
|
74
74
|
max_length = commands_definition.keys.map(&:length).max
|
data/lib/abt/docs/markdown.rb
CHANGED
@@ -52,11 +52,11 @@ module Abt
|
|
52
52
|
|
53
53
|
examples = Docs.basic_examples.merge(Docs.extended_examples)
|
54
54
|
examples.each_with_index do |(title, commands), index|
|
55
|
-
lines <<
|
55
|
+
lines << "" unless index.zero?
|
56
56
|
lines << title
|
57
57
|
|
58
58
|
commands.each do |(command, description)|
|
59
|
-
formatted_description = description.nil? ?
|
59
|
+
formatted_description = description.nil? ? "" : ": #{description}"
|
60
60
|
lines << "- `#{command}`#{formatted_description}"
|
61
61
|
end
|
62
62
|
end
|
@@ -68,10 +68,10 @@ module Abt
|
|
68
68
|
lines = []
|
69
69
|
|
70
70
|
Docs.providers.each_with_index do |(scheme, commands), index|
|
71
|
-
lines <<
|
71
|
+
lines << "" unless index.zero?
|
72
72
|
lines << "### #{inflector.humanize(scheme)}"
|
73
|
-
lines <<
|
74
|
-
lines <<
|
73
|
+
lines << "| Command | Description |"
|
74
|
+
lines << "| :------ | :---------- |"
|
75
75
|
|
76
76
|
max_length = commands.values.map(&:first).map(&:length).max
|
77
77
|
|
data/lib/abt/git_config.rb
CHANGED
@@ -6,12 +6,10 @@ module Abt
|
|
6
6
|
|
7
7
|
class UnsafeNamespaceError < StandardError; end
|
8
8
|
|
9
|
-
def initialize(scope =
|
9
|
+
def initialize(scope = "local", namespace = "")
|
10
10
|
@namespace = namespace
|
11
11
|
|
12
|
-
unless %w[local global].include?
|
13
|
-
raise ArgumentError, 'scope must be "local" or "global"'
|
14
|
-
end
|
12
|
+
raise ArgumentError, 'scope must be "local" or "global"' unless %w[local global].include?(scope)
|
15
13
|
|
16
14
|
@scope = scope
|
17
15
|
end
|
@@ -50,7 +48,7 @@ module Abt
|
|
50
48
|
end
|
51
49
|
|
52
50
|
def clear(output: nil)
|
53
|
-
raise UnsafeNamespaceError,
|
51
|
+
raise UnsafeNamespaceError, "Keys can only be cleared within a namespace" if namespace.empty?
|
54
52
|
|
55
53
|
keys.each do |key|
|
56
54
|
output&.puts "Clearing #{scope}: #{key_with_namespace(key)}"
|
@@ -67,7 +65,7 @@ module Abt
|
|
67
65
|
def ensure_scope_available!
|
68
66
|
return if available?
|
69
67
|
|
70
|
-
raise StandardError,
|
68
|
+
raise StandardError, "Local configuration is not available outside a git repository"
|
71
69
|
end
|
72
70
|
|
73
71
|
def key_with_namespace(key)
|
@@ -4,8 +4,8 @@ module Abt
|
|
4
4
|
module Providers
|
5
5
|
module Asana
|
6
6
|
class Api
|
7
|
-
API_ENDPOINT =
|
8
|
-
VERBS =
|
7
|
+
API_ENDPOINT = "https://app.asana.com/api/1.0"
|
8
|
+
VERBS = [:get, :post, :put].freeze
|
9
9
|
|
10
10
|
attr_reader :access_token
|
11
11
|
|
@@ -15,7 +15,7 @@ module Abt
|
|
15
15
|
|
16
16
|
VERBS.each do |verb|
|
17
17
|
define_method(verb) do |*args|
|
18
|
-
request(verb, *args)[
|
18
|
+
request(verb, *args)["data"]
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -24,10 +24,10 @@ module Abt
|
|
24
24
|
|
25
25
|
loop do
|
26
26
|
result = request(:get, path, query.merge(limit: 100))
|
27
|
-
records += result[
|
28
|
-
break if result[
|
27
|
+
records += result["data"]
|
28
|
+
break if result["next_page"].nil?
|
29
29
|
|
30
|
-
path = result[
|
30
|
+
path = result["next_page"]["path"][1..-1]
|
31
31
|
end
|
32
32
|
|
33
33
|
records
|
@@ -40,15 +40,15 @@ module Abt
|
|
40
40
|
Oj.load(response.body)
|
41
41
|
else
|
42
42
|
error_class = Abt::HttpError.error_class_for_status(response.status)
|
43
|
-
encoded_response_body = response.body.force_encoding(
|
43
|
+
encoded_response_body = response.body.force_encoding("utf-8")
|
44
44
|
raise error_class, "Code: #{response.status}, body: #{encoded_response_body}"
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
48
|
def connection
|
49
49
|
@connection ||= Faraday.new(API_ENDPOINT) do |connection|
|
50
|
-
connection.headers[
|
51
|
-
connection.headers[
|
50
|
+
connection.headers["Authorization"] = "Bearer #{access_token}"
|
51
|
+
connection.headers["Content-Type"] = "application/json"
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
@@ -21,25 +21,23 @@ module Abt
|
|
21
21
|
private
|
22
22
|
|
23
23
|
def require_project!
|
24
|
-
abort
|
24
|
+
abort("No current/specified project. Did you initialize Asana?") if project_gid.nil?
|
25
25
|
end
|
26
26
|
|
27
27
|
def require_task!
|
28
|
-
if project_gid.nil?
|
29
|
-
|
30
|
-
end
|
31
|
-
abort 'No current/specified task. Did you pick an Asana task?' if task_gid.nil?
|
28
|
+
abort("No current/specified project. Did you initialize Asana and pick a task?") if project_gid.nil?
|
29
|
+
abort("No current/specified task. Did you pick an Asana task?") if task_gid.nil?
|
32
30
|
end
|
33
31
|
|
34
32
|
def print_project(project)
|
35
|
-
cli.print_ari(
|
36
|
-
warn
|
33
|
+
cli.print_ari("asana", project["gid"], project["name"])
|
34
|
+
warn(project["permalink_url"]) if project.key?("permalink_url") && cli.output.isatty
|
37
35
|
end
|
38
36
|
|
39
37
|
def print_task(project, task)
|
40
|
-
project = {
|
41
|
-
cli.print_ari(
|
42
|
-
warn
|
38
|
+
project = { "gid" => project } if project.is_a?(String)
|
39
|
+
cli.print_ari("asana", "#{project['gid']}/#{task['gid']}", task["name"])
|
40
|
+
warn(task["permalink_url"]) if task.key?("permalink_url") && cli.output.isatty
|
43
41
|
end
|
44
42
|
|
45
43
|
def api
|
@@ -6,22 +6,22 @@ module Abt
|
|
6
6
|
module Commands
|
7
7
|
class Add < BaseCommand
|
8
8
|
def self.usage
|
9
|
-
|
9
|
+
"abt add asana[:<project-gid>]"
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.description
|
13
|
-
|
13
|
+
"Create a new task for the current/specified Asana project"
|
14
14
|
end
|
15
15
|
|
16
16
|
def perform
|
17
17
|
require_project!
|
18
18
|
|
19
19
|
task
|
20
|
-
warn
|
20
|
+
warn("Task created")
|
21
21
|
|
22
22
|
if section
|
23
23
|
move_task
|
24
|
-
warn
|
24
|
+
warn("Moved to section: #{section['name']}")
|
25
25
|
end
|
26
26
|
|
27
27
|
print_task(project, task)
|
@@ -38,36 +38,37 @@ module Abt
|
|
38
38
|
projects: [project_gid]
|
39
39
|
}
|
40
40
|
}
|
41
|
-
api.post(
|
41
|
+
api.post("tasks", Oj.dump(body, mode: :json))
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
45
|
def move_task
|
46
|
-
body = { data: { task: task[
|
46
|
+
body = { data: { task: task["gid"] } }
|
47
47
|
body_json = Oj.dump(body, mode: :json)
|
48
48
|
api.post("sections/#{section['gid']}/addTask", body_json)
|
49
49
|
end
|
50
50
|
|
51
51
|
def name
|
52
|
-
@name ||= cli.prompt.text
|
52
|
+
@name ||= cli.prompt.text("Enter task description")
|
53
53
|
end
|
54
54
|
|
55
55
|
def notes
|
56
|
-
@notes ||= cli.prompt.text
|
56
|
+
@notes ||= cli.prompt.text("Enter task notes")
|
57
57
|
end
|
58
58
|
|
59
59
|
def project
|
60
|
-
@project ||= api.get("projects/#{project_gid}", opt_fields:
|
60
|
+
@project ||= api.get("projects/#{project_gid}", opt_fields: "name")
|
61
61
|
end
|
62
62
|
|
63
63
|
def section
|
64
|
-
@section ||= cli.prompt.choice
|
64
|
+
@section ||= cli.prompt.choice("Add to section?", sections,
|
65
|
+
nil_option: ["q", "Don't add to section"])
|
65
66
|
end
|
66
67
|
|
67
68
|
def sections
|
68
69
|
@sections ||= begin
|
69
|
-
warn
|
70
|
-
api.get_paged("projects/#{project_gid}/sections", opt_fields:
|
70
|
+
warn("Fetching sections...")
|
71
|
+
api.get_paged("projects/#{project_gid}/sections", opt_fields: "name")
|
71
72
|
end
|
72
73
|
end
|
73
74
|
end
|
@@ -6,11 +6,11 @@ module Abt
|
|
6
6
|
module Commands
|
7
7
|
class BranchName < BaseCommand
|
8
8
|
def self.usage
|
9
|
-
|
9
|
+
"abt branch-name asana[:<project-gid>/<task-gid>]"
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.description
|
13
|
-
|
13
|
+
"Suggest a git branch name for the current/specified task."
|
14
14
|
end
|
15
15
|
|
16
16
|
def perform
|
@@ -23,21 +23,21 @@ module Abt
|
|
23
23
|
private
|
24
24
|
|
25
25
|
def name
|
26
|
-
task[
|
26
|
+
task["name"].downcase.gsub(/[^\w]+/, "-").gsub(/(^-|-$)/, "")
|
27
27
|
end
|
28
28
|
|
29
29
|
def ensure_current_is_valid!
|
30
|
-
abort
|
30
|
+
abort("Invalid task gid: #{task_gid}") if task.nil?
|
31
31
|
|
32
|
-
return if task[
|
32
|
+
return if task["memberships"].any? { |m| m.dig("project", "gid") == project_gid }
|
33
33
|
|
34
|
-
abort
|
34
|
+
abort("Invalid or unmatching project gid: #{project_gid}")
|
35
35
|
end
|
36
36
|
|
37
37
|
def task
|
38
38
|
@task ||= begin
|
39
|
-
warn
|
40
|
-
api.get("tasks/#{task_gid}", opt_fields:
|
39
|
+
warn("Fetching task...")
|
40
|
+
api.get("tasks/#{task_gid}", opt_fields: "name,memberships.project")
|
41
41
|
rescue Abt::HttpError::NotFoundError
|
42
42
|
nil
|
43
43
|
end
|
@@ -6,29 +6,28 @@ module Abt
|
|
6
6
|
module Commands
|
7
7
|
class Clear < BaseCommand
|
8
8
|
def self.usage
|
9
|
-
|
9
|
+
"abt clear asana"
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.description
|
13
|
-
|
13
|
+
"Clear asana configuration"
|
14
14
|
end
|
15
15
|
|
16
16
|
def self.flags
|
17
17
|
[
|
18
|
-
[
|
19
|
-
|
18
|
+
["-g", "--global",
|
19
|
+
"Clear global instead of local asana configuration (credentials etc.)"],
|
20
|
+
["-a", "--all", "Clear all asana configuration"]
|
20
21
|
]
|
21
22
|
end
|
22
23
|
|
23
24
|
def perform
|
24
|
-
if flags[:global] && flags[:all]
|
25
|
-
abort('Flags --global and --all cannot be used at the same time')
|
26
|
-
end
|
25
|
+
abort("Flags --global and --all cannot be used at the same time") if flags[:global] && flags[:all]
|
27
26
|
|
28
27
|
config.clear_local unless flags[:global]
|
29
28
|
config.clear_global if flags[:global] || flags[:all]
|
30
29
|
|
31
|
-
warn
|
30
|
+
warn("Configuration cleared")
|
32
31
|
end
|
33
32
|
end
|
34
33
|
end
|
@@ -6,22 +6,22 @@ module Abt
|
|
6
6
|
module Commands
|
7
7
|
class Current < BaseCommand
|
8
8
|
def self.usage
|
9
|
-
|
9
|
+
"abt current asana[:<project-gid>[/<task-gid>]]"
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.description
|
13
|
-
|
13
|
+
"Get or set project and or task for current git repository"
|
14
14
|
end
|
15
15
|
|
16
16
|
def perform
|
17
|
-
abort
|
17
|
+
abort("Must be run inside a git repository") unless config.local_available?
|
18
18
|
|
19
19
|
require_project!
|
20
20
|
ensure_valid_configuration!
|
21
21
|
|
22
22
|
if path != config.path
|
23
23
|
config.path = path
|
24
|
-
warn
|
24
|
+
warn("Configuration updated")
|
25
25
|
end
|
26
26
|
|
27
27
|
print_configuration
|
@@ -34,25 +34,25 @@ module Abt
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def ensure_valid_configuration!
|
37
|
-
abort
|
38
|
-
abort
|
37
|
+
abort("Invalid project: #{project_gid}") if project.nil?
|
38
|
+
abort("Invalid task: #{task_gid}") if task_gid && task.nil?
|
39
39
|
end
|
40
40
|
|
41
41
|
def project
|
42
42
|
@project ||= begin
|
43
|
-
warn
|
44
|
-
api.get("projects/#{project_gid}", opt_fields:
|
45
|
-
|
46
|
-
|
43
|
+
warn("Fetching project...")
|
44
|
+
api.get("projects/#{project_gid}", opt_fields: "name,permalink_url")
|
45
|
+
rescue Abt::HttpError::NotFoundError
|
46
|
+
nil
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
50
|
def task
|
51
51
|
@task ||= begin
|
52
|
-
warn
|
53
|
-
api.get("tasks/#{task_gid}", opt_fields:
|
54
|
-
|
55
|
-
|
52
|
+
warn("Fetching task...")
|
53
|
+
api.get("tasks/#{task_gid}", opt_fields: "name,permalink_url")
|
54
|
+
rescue Abt::HttpError::NotFoundError
|
55
|
+
nil
|
56
56
|
end
|
57
57
|
end
|
58
58
|
end
|