sfctl 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "sfctl"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ lib_path = File.expand_path('../lib', __dir__)
5
+ $:.unshift(lib_path) if !$:.include?(lib_path)
6
+ require 'sfctl/cli'
7
+
8
+ Signal.trap('INT') do
9
+ warn("\n#{caller.join("\n")}: interrupted")
10
+ exit(1)
11
+ end
12
+
13
+ begin
14
+ Sfctl::CLI.start
15
+ rescue Sfctl::CLI::Error => err
16
+ puts "ERROR: #{err.message}"
17
+ exit 1
18
+ end
@@ -0,0 +1,5 @@
1
+ require 'sfctl/version'
2
+
3
+ module Sfctl
4
+ class Error < StandardError; end
5
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require 'pastel'
5
+ require 'tty-font'
6
+
7
+ module Sfctl
8
+ # Handle the application command line parsing
9
+ # and the dispatch to various command objects
10
+ #
11
+ # @api public
12
+ class CLI < Thor
13
+ # Error raised by this runner
14
+ Error = Class.new(StandardError)
15
+
16
+ def help(*args)
17
+ font = TTY::Font.new(:standard)
18
+ pastel = Pastel.new(enabled: !options['no-color'])
19
+ puts pastel.yellow(font.write('sfctl'))
20
+ super
21
+ end
22
+
23
+ class_option :"no-color", type: :boolean, default: false, desc: 'Disable colorization in output'
24
+ class_option :"starfish-host", type: :string, default: 'https://starfish.team',
25
+ desc: 'The starfish API endpoint',
26
+ banner: 'HOST'
27
+
28
+ desc 'version', 'sfctl version'
29
+ def version
30
+ require_relative 'version'
31
+ puts "v#{Sfctl::VERSION}"
32
+ end
33
+ map %w[--version -v] => :version
34
+
35
+ require_relative 'commands/time'
36
+ register Sfctl::Commands::Time, 'time', 'time [SUBCOMMAND]', 'Time reports'
37
+
38
+ require_relative 'commands/account'
39
+ register Sfctl::Commands::Account, 'account', 'account [SUBCOMMAND]', 'Account information for Starfish.team'
40
+
41
+ require_relative 'commands/auth'
42
+ register Sfctl::Commands::Auth, 'auth', 'auth [SUBCOMMAND]', 'Authentication with Starfish.team'
43
+ end
44
+ end
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require 'tty-config'
5
+
6
+ module Sfctl
7
+ class Command
8
+ extend Forwardable
9
+
10
+ CONFIG_FILENAME = '.sfctl'
11
+ CONFIG_PATH = "#{Dir.home}/#{CONFIG_FILENAME}"
12
+ LINK_CONFIG_FILENAME = '.sflink'
13
+ LINK_CONFIG_PATH = "#{Dir.home}/#{LINK_CONFIG_FILENAME}"
14
+
15
+ TOGGL_PROVIDER = 'toggl'
16
+ PROVIDERS_LIST = [
17
+ TOGGL_PROVIDER
18
+ ].freeze
19
+
20
+ def_delegators :command, :run
21
+
22
+ # Main configuration
23
+ # @api public
24
+ def config
25
+ @config ||= begin
26
+ config = TTY::Config.new
27
+ config.append_path Dir.home
28
+ config
29
+ end
30
+ end
31
+
32
+ def save_config!
33
+ config.write(CONFIG_PATH, format: :yaml, force: true)
34
+ end
35
+
36
+ def read_config
37
+ config.read(CONFIG_PATH, format: :yaml)
38
+ end
39
+
40
+ def access_token
41
+ read_config['access_token']
42
+ end
43
+
44
+ def config_present?(output)
45
+ read_config
46
+ rescue TTY::Config::ReadError
47
+ output.puts Pastel.new(enabled: !@options['no-color']).red('Please authentificate before continue.')
48
+ false
49
+ end
50
+
51
+ def read_link_config
52
+ config.read(LINK_CONFIG_PATH, format: :yaml)
53
+ end
54
+
55
+ def save_link_config!
56
+ config.write(LINK_CONFIG_PATH, format: :yaml, force: true)
57
+ end
58
+
59
+ def link_config_present?(output)
60
+ read_link_config
61
+ rescue TTY::Config::ReadError
62
+ output.puts Pastel.new(enabled: !@options['no-color']).red('Please initialize time before continue.')
63
+ false
64
+ end
65
+
66
+ # Execute this command
67
+ #
68
+ # @api public
69
+ def execute(*)
70
+ raise(
71
+ NotImplementedError,
72
+ "#{self.class}##{__method__} must be implemented"
73
+ )
74
+ end
75
+
76
+ # The external commands runner
77
+ #
78
+ # @see http://www.rubydoc.info/gems/tty-command
79
+ #
80
+ # @api public
81
+ def command(**options)
82
+ require 'tty-command'
83
+ TTY::Command.new(options)
84
+ end
85
+
86
+ # The cursor movement
87
+ #
88
+ # @see http://www.rubydoc.info/gems/tty-cursor
89
+ #
90
+ # @api public
91
+ # def cursor
92
+ # require 'tty-cursor'
93
+ # TTY::Cursor
94
+ # end
95
+
96
+ # Open a file or text in the user's preferred editor
97
+ #
98
+ # @see http://www.rubydoc.info/gems/tty-editor
99
+ #
100
+ # @api public
101
+ # def editor
102
+ # require 'tty-editor'
103
+ # TTY::Editor
104
+ # end
105
+
106
+ # Terminal output paging
107
+ #
108
+ # @see http://www.rubydoc.info/gems/tty-pager
109
+ #
110
+ # @api public
111
+ # def pager(**options)
112
+ # require 'tty-pager'
113
+ # TTY::Pager.new(options)
114
+ # end
115
+
116
+ # Terminal platform and OS properties
117
+ #
118
+ # @see http://www.rubydoc.info/gems/tty-pager
119
+ #
120
+ # @api public
121
+ # def platform
122
+ # require 'tty-platform'
123
+ # TTY::Platform.new
124
+ # end
125
+
126
+ # The interactive prompt
127
+ #
128
+ # @see http://www.rubydoc.info/gems/tty-prompt
129
+ #
130
+ # @api public
131
+ # def prompt(**options)
132
+ # require 'tty-prompt'
133
+ # TTY::Prompt.new(options)
134
+ # end
135
+
136
+ # Get terminal screen properties
137
+ #
138
+ # @see http://www.rubydoc.info/gems/tty-screen
139
+ #
140
+ # @api public
141
+ # def screen
142
+ # require 'tty-screen'
143
+ # TTY::Screen
144
+ # end
145
+
146
+ # The unix which utility
147
+ #
148
+ # @see http://www.rubydoc.info/gems/tty-which
149
+ #
150
+ # @api public
151
+ # def which(*args)
152
+ # require 'tty-which'
153
+ # TTY::Which.which(*args)
154
+ # end
155
+
156
+ # Check if executable exists
157
+ #
158
+ # @see http://www.rubydoc.info/gems/tty-which
159
+ #
160
+ # @api public
161
+ # def exec_exist?(*args)
162
+ # require 'tty-which'
163
+ # TTY::Which.exist?(*args)
164
+ # end
165
+ end
166
+ end
@@ -0,0 +1,34 @@
1
+ require 'thor'
2
+
3
+ module Sfctl
4
+ module Commands
5
+ class Account < Thor
6
+ namespace :account
7
+
8
+ desc 'assignments', 'This command will list all of your assignments that are currently active.'
9
+ method_option :help, aliases: '-h', type: :boolean,
10
+ desc: 'Display usage information'
11
+ method_option :all, aliases: '-a', type: :boolean, default: false,
12
+ desc: 'If you want to read all assignments you have to provide this flag'
13
+ def assignments(*)
14
+ if options[:help]
15
+ invoke :help, ['assignments']
16
+ else
17
+ require_relative 'account/assignments'
18
+ Sfctl::Commands::Account::Assignments.new(options).execute
19
+ end
20
+ end
21
+
22
+ desc 'info', 'This will read your profile data and give you an overview of your account.'
23
+ method_option :help, aliases: '-h', type: :boolean
24
+ def info(*)
25
+ if options[:help]
26
+ invoke :help, ['info']
27
+ else
28
+ require_relative 'account/info'
29
+ Sfctl::Commands::Account::Info.new(options).execute
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,52 @@
1
+ require 'pastel'
2
+ require 'tty-table'
3
+ require_relative '../../command'
4
+ require_relative '../../starfish'
5
+
6
+ module Sfctl
7
+ module Commands
8
+ class Account
9
+ class Assignments < 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
+ return unless config_present?(output)
17
+
18
+ success, data = Starfish.account_assignments(@options['starfish-host'], @options['all'], access_token)
19
+
20
+ unless success
21
+ output.puts @pastel.red('Something went wrong. Unable to fetch assignments')
22
+ return
23
+ end
24
+
25
+ print_assignments(data['assignments'], output)
26
+ end
27
+
28
+ private
29
+
30
+ def rows(assignment)
31
+ [[
32
+ <<~HEREDOC
33
+ Service: #{assignment['service']}
34
+ Start: #{assignment['start_date']}
35
+ End: #{assignment['end_date']}
36
+ Budget: #{assignment['budget']} #{assignment['unit']}
37
+ HEREDOC
38
+ ]]
39
+ end
40
+
41
+ def print_assignments(assignments, output)
42
+ assignments.each do |assignment|
43
+ header = ["Assignment: #{assignment['name']}"]
44
+ table = ::TTY::Table.new header: header, rows: rows(assignment)
45
+ output.print table.render(:unicode, padding: [0, 1], multiline: true)
46
+ output.puts
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,40 @@
1
+ require 'pastel'
2
+ require 'tty-table'
3
+ require_relative '../../command'
4
+ require_relative '../../starfish'
5
+
6
+ module Sfctl
7
+ module Commands
8
+ class Account
9
+ class Info < 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
+ return unless config_present?(output)
17
+
18
+ success, info = Starfish.account_info(@options['starfish-host'], access_token)
19
+
20
+ unless success
21
+ output.puts @pastel.red('Something went wrong. Unable to fetch account info')
22
+ return
23
+ end
24
+
25
+ print_table(info, output)
26
+ end
27
+
28
+ private
29
+
30
+ def print_table(info, output)
31
+ header = info.keys
32
+ rows = [info.values]
33
+ table = ::TTY::Table.new header: header, rows: rows
34
+ output.print table.render(:unicode, padding: [0, 1])
35
+ output.puts
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,35 @@
1
+ require 'thor'
2
+
3
+ module Sfctl
4
+ module Commands
5
+ class Auth < Thor
6
+ namespace :auth
7
+
8
+ desc 'bye', 'Log out by either removing the config file.'
9
+ method_option :help, aliases: '-h', type: :boolean, desc: '...'
10
+ def bye(*)
11
+ if options[:help]
12
+ invoke :help, ['bye']
13
+ else
14
+ require_relative 'auth/bye'
15
+ Sfctl::Commands::Auth::Bye.new(options).execute
16
+ end
17
+ end
18
+
19
+ desc 'init [TOKEN]', 'Authenticate with Starfish.team'
20
+ long_desc <<~HEREDOC
21
+ Before you can use sfctl, you need to authenticate with Starfish.team by providing an access token,
22
+ which can be created on the profile page of your account.
23
+ HEREDOC
24
+ method_option :help, aliases: '-h', type: :boolean
25
+ def init(access_token)
26
+ if options[:help]
27
+ invoke :help, ['init']
28
+ else
29
+ require_relative 'auth/init'
30
+ Sfctl::Commands::Auth::Init.new(access_token, options).execute
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../command'
4
+ require 'tty-prompt'
5
+ require 'tty-file'
6
+
7
+ module Sfctl
8
+ module Commands
9
+ class Auth
10
+ class Bye < Sfctl::Command
11
+ def initialize(*); end
12
+
13
+ def execute(*)
14
+ prompt = ::TTY::Prompt.new
15
+ reset_config! if prompt.yes?('Are you sure?')
16
+ end
17
+
18
+ private
19
+
20
+ def reset_config!
21
+ ::TTY::File.remove_file CONFIG_PATH
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end