sfctl 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.buildkite/hooks/pre-command +5 -0
- data/.buildkite/pipeline.yml +9 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.rubocop.yml +76 -0
- data/.tool-versions +1 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +40 -0
- data/Gemfile.lock +186 -0
- data/README.md +276 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/sfctl +18 -0
- data/lib/sfctl.rb +5 -0
- data/lib/sfctl/cli.rb +44 -0
- data/lib/sfctl/command.rb +166 -0
- data/lib/sfctl/commands/account.rb +34 -0
- data/lib/sfctl/commands/account/assignments.rb +52 -0
- data/lib/sfctl/commands/account/info.rb +40 -0
- data/lib/sfctl/commands/auth.rb +35 -0
- data/lib/sfctl/commands/auth/bye.rb +26 -0
- data/lib/sfctl/commands/auth/init.rb +53 -0
- data/lib/sfctl/commands/time.rb +52 -0
- data/lib/sfctl/commands/time/connections.rb +33 -0
- data/lib/sfctl/commands/time/connections/add.rb +84 -0
- data/lib/sfctl/commands/time/connections/get.rb +53 -0
- data/lib/sfctl/commands/time/init.rb +23 -0
- data/lib/sfctl/commands/time/providers.rb +44 -0
- data/lib/sfctl/commands/time/providers/get.rb +41 -0
- data/lib/sfctl/commands/time/providers/set.rb +58 -0
- data/lib/sfctl/commands/time/providers/unset.rb +43 -0
- data/lib/sfctl/commands/time/sync.rb +215 -0
- data/lib/sfctl/starfish.rb +51 -0
- data/lib/sfctl/templates/.gitkeep +1 -0
- data/lib/sfctl/toggl.rb +27 -0
- data/lib/sfctl/version.rb +3 -0
- data/scripts/test.sh +8 -0
- data/sfctl.gemspec +28 -0
- metadata +84 -0
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -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__)
|
data/bin/setup
ADDED
data/exe/sfctl
ADDED
@@ -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
|
data/lib/sfctl.rb
ADDED
data/lib/sfctl/cli.rb
ADDED
@@ -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
|