sfctl 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../command'
4
+ require_relative '../../starfish'
5
+ require 'pastel'
6
+ require 'tty-spinner'
7
+
8
+ module Sfctl
9
+ module Commands
10
+ class Auth
11
+ class Init < Sfctl::Command
12
+ def initialize(access_token, options)
13
+ @access_token = access_token
14
+ @options = options
15
+
16
+ @pastel = Pastel.new(enabled: !@options['no-color'])
17
+ end
18
+
19
+ def execute(output: $stdout)
20
+ spinner = ::TTY::Spinner.new('[:spinner] Checking token ...')
21
+ spinner.auto_spin
22
+ token_valid? ? update_config!(spinner, output) : render_error(spinner, output)
23
+ end
24
+
25
+ private
26
+
27
+ def token_valid?
28
+ Starfish.check_authorization(@options['starfish-host'], @access_token)
29
+ end
30
+
31
+ def token_accepted_message
32
+ @pastel.green('Credentials are accepted.')
33
+ end
34
+
35
+ def wrong_token_message
36
+ @pastel.red('Token is not accepted, please make sure you copy and paste it correctly.')
37
+ end
38
+
39
+ def update_config!(spinner, output)
40
+ config.set :access_token, value: @access_token
41
+ save_config!
42
+ spinner.success
43
+ output.puts token_accepted_message
44
+ end
45
+
46
+ def render_error(spinner, output)
47
+ spinner.error
48
+ output.puts wrong_token_message
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,52 @@
1
+ require 'thor'
2
+
3
+ module Sfctl
4
+ module Commands
5
+ class Time < Thor
6
+ namespace :time
7
+
8
+ desc 'sync', 'Synchronize data with providers.'
9
+ method_option :help, aliases: '-h', type: :boolean,
10
+ desc: 'Display usage information'
11
+ method_option :dry_run, aliases: '-dry-run', type: :boolean, default: false,
12
+ desc: 'Check the data first respectively prevent data from being overwritten'
13
+ method_option :touchy, aliases: '-touchy', type: :boolean, default: false,
14
+ desc: 'The synchronizsation will be skipped if there is preexisting data.'
15
+ long_desc <<~HEREDOC
16
+ It will gets for each assignment the next reporting segment from starfish.team
17
+ and loads the corresponding time reports from the provider.
18
+ HEREDOC
19
+ def sync(*)
20
+ if options[:help]
21
+ invoke :help, ['sync']
22
+ else
23
+ require_relative 'time/sync'
24
+ Sfctl::Commands::Time::Sync.new(options).execute
25
+ end
26
+ end
27
+
28
+ desc 'init',
29
+ 'You can use the following command to create a .sflink file that will store your project configuration.'
30
+ long_desc <<~HEREDOC
31
+ You can use the following command to create a .sflink file that will store your project configuration.\n
32
+ Although sensitive data is stored in the main .sfctl directory
33
+ we'd like to recommend to not add the .sflink file to your version control system.
34
+ HEREDOC
35
+ method_option :help, aliases: '-h', type: :boolean
36
+ def init(*)
37
+ if options[:help]
38
+ invoke :help, ['init']
39
+ else
40
+ require_relative 'time/init'
41
+ Sfctl::Commands::Time::Init.new(options).execute
42
+ end
43
+ end
44
+
45
+ require_relative 'time/providers'
46
+ register Sfctl::Commands::Time::Providers, 'providers', 'providers [SUBCOMMAND]', 'Manage providers.'
47
+
48
+ require_relative 'time/connections'
49
+ register Sfctl::Commands::Time::Connections, 'connections', 'connections [SUBCOMMAND]', 'Manage connections.'
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,33 @@
1
+ require 'thor'
2
+
3
+ module Sfctl
4
+ module Commands
5
+ class Time
6
+ class Connections < Thor
7
+ namespace :connections
8
+
9
+ desc 'add', 'This command will add a connection between a provider and an assignment.'
10
+ method_option :help, aliases: '-h', type: :boolean
11
+ def add(*)
12
+ if options[:help]
13
+ invoke :help, ['add']
14
+ else
15
+ require_relative 'connections/add'
16
+ Sfctl::Commands::Time::Connections::Add.new(options).execute
17
+ end
18
+ end
19
+
20
+ desc 'get', 'List all known connections in that project.'
21
+ method_option :help, aliases: '-h', type: :boolean
22
+ def get(*)
23
+ if options[:help]
24
+ invoke :help, ['get']
25
+ else
26
+ require_relative 'connections/get'
27
+ Sfctl::Commands::Time::Connections::Get.new(options).execute
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,84 @@
1
+ require 'pastel'
2
+ require 'tty-prompt'
3
+ require_relative '../../../command'
4
+ require_relative '../../../starfish'
5
+
6
+ module Sfctl
7
+ module Commands
8
+ class Time
9
+ class Connections
10
+ class Add < Sfctl::Command
11
+ def initialize(options)
12
+ @options = options
13
+ @pastel = Pastel.new(enabled: !@options['no-color'])
14
+ @prompt = ::TTY::Prompt.new
15
+ end
16
+
17
+ def execute(output: $stdout) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
18
+ return if !config_present?(output) || !link_config_present?(output)
19
+
20
+ ltoken = access_token
21
+ config.delete(:access_token)
22
+ success, data = Starfish.account_assignments(@options['starfish-host'], @options['all'], ltoken)
23
+ unless success
24
+ output.puts @pastel.red('Something went wrong. Unable to fetch assignments')
25
+ return
26
+ end
27
+
28
+ assignments = filter_assignments(data['assignments'])
29
+ if assignments.length.zero?
30
+ output.puts @pastel.yellow('All assignments already added.')
31
+ return
32
+ end
33
+
34
+ provider = @prompt.select('Select provider:', PROVIDERS_LIST)
35
+
36
+ assignment_name = select_assignment(assignments)
37
+
38
+ case provider
39
+ when TOGGL_PROVIDER
40
+ setup_toggl_connection!(assignment_name)
41
+ end
42
+
43
+ save_link_config!
44
+
45
+ output.puts @pastel.green('Connection successfully added.')
46
+ end
47
+
48
+ private
49
+
50
+ def select_assignment(assignments)
51
+ @prompt.select('Select assignment:') do |menu|
52
+ assignments.each.with_index do |asmnt, i|
53
+ menu.choice name: "#{i + 1}. #{asmnt['name']} / #{asmnt['service']}", value: asmnt['name']
54
+ end
55
+ end
56
+ end
57
+
58
+ def filter_assignments(list)
59
+ return list if config.fetch(:connections).nil?
60
+
61
+ added_assignments_name = config.fetch(:connections).keys
62
+ list.delete_if { |h| added_assignments_name.include?(h['name']) }
63
+ list
64
+ end
65
+
66
+ def setup_toggl_connection!(assignment_name)
67
+ workspace_id = @prompt.ask('Workspace ID (required):', required: true)
68
+ project_ids = @prompt.ask('Project IDs (required / comma separated):', required: true)
69
+ task_ids = @prompt.ask('Task IDs (optional / comma separated):') || ''
70
+ billable = @prompt.select('Billable? (required)', %w[yes no both])
71
+ rounding = @prompt.select('Rounding? (required)', %w[on off])
72
+
73
+ config.set("connections.#{assignment_name}.provider", value: TOGGL_PROVIDER)
74
+ config.set("connections.#{assignment_name}.workspace_id", value: workspace_id)
75
+ config.set("connections.#{assignment_name}.project_ids", value: project_ids)
76
+ config.set("connections.#{assignment_name}.task_ids", value: task_ids)
77
+ config.set("connections.#{assignment_name}.billable", value: billable)
78
+ config.set("connections.#{assignment_name}.rounding", value: rounding)
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,53 @@
1
+ require 'pastel'
2
+ require_relative '../../../command'
3
+
4
+ module Sfctl
5
+ module Commands
6
+ class Time
7
+ class Connections
8
+ class Get < Sfctl::Command
9
+ def initialize(options)
10
+ @options = options
11
+ @pastel = Pastel.new(enabled: !@options['no-color'])
12
+ end
13
+
14
+ def execute(output: $stdout)
15
+ read_link_config
16
+
17
+ if config.fetch(:connections).nil?
18
+ output.puts @pastel.yellow('You have no connections. Please add them before continue.')
19
+ return
20
+ end
21
+
22
+ print_connections(output)
23
+ rescue TTY::Config::ReadError
24
+ error_message = 'Please initialize time before continue and ensure that your account authenticated.'
25
+ output.puts @pastel.yellow(error_message)
26
+ end
27
+
28
+ private
29
+
30
+ def print_connections(output)
31
+ config.fetch(:connections).each_key do |assignment_name|
32
+ case config.fetch(:connections, assignment_name, :provider)
33
+ when TOGGL_PROVIDER
34
+ print_toggl_connection!(output, assignment_name)
35
+ end
36
+ end
37
+ end
38
+
39
+ def print_toggl_connection!(output, assignment_name)
40
+ output.puts "Connection: #{assignment_name}"
41
+ output.puts " provider: #{TOGGL_PROVIDER}"
42
+ output.puts " workspace_id: #{config.fetch(:connections, assignment_name, :workspace_id)}"
43
+ output.puts " project_ids: #{config.fetch(:connections, assignment_name, :project_ids)}"
44
+ output.puts " task_ids: #{config.fetch(:connections, assignment_name, :task_ids)}"
45
+ output.puts " billable: #{config.fetch(:connections, assignment_name, :billable)}"
46
+ output.puts " rounding: #{config.fetch(:connections, assignment_name, :rounding)}"
47
+ output.puts
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,23 @@
1
+ require_relative '../../command'
2
+
3
+ module Sfctl
4
+ module Commands
5
+ class Time
6
+ class Init < Sfctl::Command
7
+ def initialize(options)
8
+ @options = options
9
+
10
+ @pastel = Pastel.new(enabled: !@options['no-color'])
11
+ end
12
+
13
+ def execute(output: $stdout)
14
+ read_link_config
15
+ output.puts @pastel.yellow('.sflink is already created.')
16
+ rescue ::TTY::Config::ReadError
17
+ save_link_config!
18
+ output.puts @pastel.green('.sflink successfully created.')
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,44 @@
1
+ require 'thor'
2
+
3
+ module Sfctl
4
+ module Commands
5
+ class Time
6
+ class Providers < Thor
7
+ namespace :providers
8
+
9
+ desc 'set', 'Set the configuration required for the provider to authenticate a call to their API.'
10
+ method_option :help, aliases: '-h', type: :boolean
11
+ def set(*)
12
+ if options[:help]
13
+ invoke :help, ['set']
14
+ else
15
+ require_relative 'providers/set'
16
+ Sfctl::Commands::Time::Providers::Set.new(options).execute
17
+ end
18
+ end
19
+
20
+ desc 'unset', 'Unset the configuration of a provider.'
21
+ method_option :help, aliases: '-h', type: :boolean
22
+ def unset(*)
23
+ if options[:help]
24
+ invoke :help, ['unset']
25
+ else
26
+ require_relative 'providers/unset'
27
+ Sfctl::Commands::Time::Providers::Unset.new(options).execute
28
+ end
29
+ end
30
+
31
+ desc 'get', 'Read which providers are configured on your system.'
32
+ method_option :help, aliases: '-h', type: :boolean
33
+ def get(*)
34
+ if options[:help]
35
+ invoke :help, ['get']
36
+ else
37
+ require_relative 'providers/get'
38
+ Sfctl::Commands::Time::Providers::Get.new(options).execute
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,41 @@
1
+ require 'pastel'
2
+ require_relative '../../../command'
3
+
4
+ module Sfctl
5
+ module Commands
6
+ class Time
7
+ class Providers
8
+ class Get < Sfctl::Command
9
+ def initialize(options)
10
+ @options = options
11
+ @pastel = Pastel.new(enabled: !@options['no-color'])
12
+ end
13
+
14
+ def execute(output: $stdout)
15
+ read_link_config
16
+
17
+ PROVIDERS_LIST.each do |provider|
18
+ read(provider, output)
19
+ end
20
+ rescue TTY::Config::ReadError
21
+ output.puts @pastel.yellow('Please initialize time before continue.')
22
+ end
23
+
24
+ private
25
+
26
+ def read(provider, output)
27
+ info = config.fetch("providers.#{provider}")
28
+ if info.nil?
29
+ output.puts @pastel.yellow("Provider #{provider} is not set.")
30
+ else
31
+ output.puts "Provider: #{@pastel.cyan(provider)}"
32
+ info.each_key do |k|
33
+ output.puts " #{k.upcase}: #{info[k]}"
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,58 @@
1
+ require 'pastel'
2
+ require 'tty-prompt'
3
+ require_relative '../../../command'
4
+
5
+ module Sfctl
6
+ module Commands
7
+ class Time
8
+ class Providers
9
+ class Set < Sfctl::Command
10
+ def initialize(options)
11
+ @options = options
12
+ @pastel = Pastel.new(enabled: !@options['no-color'])
13
+ end
14
+
15
+ def execute(output: $stdout)
16
+ read_link_config
17
+
18
+ prompt = ::TTY::Prompt.new
19
+ provider = prompt.select('Setting up:', PROVIDERS_LIST)
20
+
21
+ !ask_for_replace(output, prompt) && return unless config.fetch("providers.#{TOGGL_PROVIDER}").nil?
22
+
23
+ case provider
24
+ when TOGGL_PROVIDER
25
+ setup_toggl_provider!(output, prompt)
26
+ end
27
+ rescue TTY::Config::ReadError
28
+ output.puts @pastel.yellow('Please initialize time before continue.')
29
+ end
30
+
31
+ private
32
+
33
+ def ask_for_replace(output, prompt)
34
+ output.puts @pastel.yellow('You already have a configuration for this provider.')
35
+ prompt.yes?('Do you want to replace it?')
36
+ end
37
+
38
+ def save_toggl_config!(output, access_token)
39
+ config.set("providers.#{TOGGL_PROVIDER}.access_token", value: access_token)
40
+ save_link_config!
41
+ output.puts @pastel.green('Everything saved.')
42
+ end
43
+
44
+ def setup_toggl_provider!(output, prompt)
45
+ output.puts
46
+ access_token = prompt.ask("Your access token at [#{@pastel.green(TOGGL_PROVIDER)}]:", required: true)
47
+ is_correct = prompt.yes?('Is that information correct?')
48
+ if is_correct
49
+ save_toggl_config!(output, access_token)
50
+ else
51
+ setup_toggl_provider!(output, prompt)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end