rockette 0.0.2 → 0.0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0f2bd092666b9d3952a13d9009337006088e6953db8f418274bf645ba98ea99c
4
- data.tar.gz: ed1e3372aae98f79c10845c67a726a8b83a7cf7bd68edf6d8b7ef2fe382feea2
3
+ metadata.gz: 1685044bb3c16dc23e0d91b6a056c58b26828385fb015f3bb9798d33b9fb5c3f
4
+ data.tar.gz: 260ad666d3d0bebac6a4d50739184eaccc5d40b0141e67051bec26bcd7c4ef79
5
5
  SHA512:
6
- metadata.gz: ea97f6f7946d19d31879ce554d825ed2303ccf511761645529e0213df1cdfdb0ce5b18fb94dd493fa21597703bef54575b6fdd2254c0582f3c36a1089a00d028
7
- data.tar.gz: ff75dcaf8d481ff7f2a63e4212634dec0e2e60172b6da158cd9dc5f8d51505f9daa6c0a26a0097113ffec2216d72b3b7aef505a8fb5521afce9e549df93571a2
6
+ metadata.gz: ccd3c264a613d1f283470b98940c31e052f27700bffcb5eaf735537343ad6232301b0187e89a6e465d6eb2e91dcf8aada0a4e6594aca6bd399da330e6e050159
7
+ data.tar.gz: 7cf907bcbe33ecf78cee5e2e641c0f72096142a18b4894fff42ea00fdd38f516d9ea33bf160ba2c152d2bca7209bc000af4b530d49ec76260a2ef9ee049afc74
data/.rubocop.yml CHANGED
@@ -12,3 +12,6 @@ Style/StringLiteralsInInterpolation:
12
12
 
13
13
  Layout/LineLength:
14
14
  Max: 120
15
+
16
+ Metrics/MethodLength:
17
+ Max: 20
data/CHANGELOG.md CHANGED
@@ -16,4 +16,14 @@
16
16
 
17
17
  - Add copy switch to deploy command
18
18
  - Use file name passed via -f switch
19
- - Try to find export file and let caller know if file not found
19
+ - Try to find export file and let caller know if file not found
20
+
21
+ ## [0.0.3] - In progress
22
+
23
+ - Improved handling of copy and file switches
24
+ - Check /usr/app for Docker
25
+ - Add interactive mode
26
+ - Add configuration option to interactive mode
27
+ - Add resource viewer mode to interactive
28
+ - Add exporter option to interactive
29
+ - Add deployer mode to interactive
data/Gemfile.lock CHANGED
@@ -1,9 +1,16 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rockette (0.0.1)
4
+ rockette (0.0.2)
5
+ pastel (~> 0.0)
5
6
  rest-client (~> 2.0)
6
7
  thor (~> 1.0)
8
+ tty-config (~> 0.0)
9
+ tty-editor (~> 0.0)
10
+ tty-font (~> 0.0)
11
+ tty-prompt (~> 0.0)
12
+ tty-spinner (~> 0.0)
13
+ tty-table (~> 0.0)
7
14
 
8
15
  GEM
9
16
  remote: https://rubygems.org/
@@ -18,12 +25,14 @@ GEM
18
25
  method_source (1.0.0)
19
26
  mime-types (3.3.1)
20
27
  mime-types-data (~> 3.2015)
21
- mime-types-data (3.2021.0212)
28
+ mime-types-data (3.2021.0225)
22
29
  minitest (5.14.4)
23
30
  netrc (0.11.0)
24
31
  parallel (1.20.1)
25
32
  parser (3.0.0.0)
26
33
  ast (~> 2.4.1)
34
+ pastel (0.8.0)
35
+ tty-color (~> 0.5)
27
36
  pry (0.14.0)
28
37
  coderay (~> 1.1)
29
38
  method_source (~> 1.0)
@@ -36,7 +45,7 @@ GEM
36
45
  mime-types (>= 1.16, < 4.0)
37
46
  netrc (~> 0.8)
38
47
  rexml (3.2.4)
39
- rubocop (1.10.0)
48
+ rubocop (1.11.0)
40
49
  parallel (~> 1.10)
41
50
  parser (>= 3.0.0.0)
42
51
  rainbow (>= 2.2.2, < 4.0)
@@ -48,14 +57,40 @@ GEM
48
57
  rubocop-ast (1.4.1)
49
58
  parser (>= 2.7.1.5)
50
59
  ruby-progressbar (1.11.0)
60
+ strings (0.2.1)
61
+ strings-ansi (~> 0.2)
62
+ unicode-display_width (>= 1.5, < 3.0)
63
+ unicode_utils (~> 1.4)
64
+ strings-ansi (0.2.0)
51
65
  thor (1.1.0)
66
+ tty-color (0.6.0)
67
+ tty-config (0.4.0)
68
+ tty-cursor (0.7.1)
69
+ tty-editor (0.6.0)
70
+ tty-prompt (~> 0.22)
71
+ tty-font (0.5.0)
72
+ tty-prompt (0.23.0)
73
+ pastel (~> 0.8)
74
+ tty-reader (~> 0.8)
75
+ tty-reader (0.9.0)
76
+ tty-cursor (~> 0.7)
77
+ tty-screen (~> 0.8)
78
+ wisper (~> 2.0)
79
+ tty-screen (0.8.1)
80
+ tty-spinner (0.9.3)
81
+ tty-cursor (~> 0.7)
82
+ tty-table (0.12.0)
83
+ pastel (~> 0.8)
84
+ strings (~> 0.2.0)
85
+ tty-screen (~> 0.8)
52
86
  unf (0.1.4)
53
87
  unf_ext
54
88
  unf_ext (0.0.7.7)
55
89
  unicode-display_width (2.0.0)
90
+ unicode_utils (1.4.0)
91
+ wisper (2.0.1)
56
92
 
57
93
  PLATFORMS
58
- ruby
59
94
  x86_64-darwin-19
60
95
 
61
96
  DEPENDENCIES
data/exe/rockette CHANGED
@@ -3,23 +3,6 @@
3
3
 
4
4
  require "rockette"
5
5
 
6
- app_path = File.join(Dir.home, ".rockette")
7
- lib_path = File.expand_path("../lib", __dir__)
8
- tem_path = File.expand_path("../templates", __dir__)
9
- $LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path)
10
-
11
- Dir.mkdir(app_path) unless File.exist?(app_path)
12
- unless File.exist?(File.join(app_path, "config.yml"))
13
- template = File.read(File.join(tem_path, "config.yml.erb"))
14
- data = ERB.new(template).result(binding)
15
- File.write(File.join(app_path, "config.yml"), data)
16
- end
17
- Dir.mkdir(File.join(app_path, "exports")) unless File.exist?(File.join(app_path, "exports"))
18
-
19
- CONF = Psych.load(File.read(File.join(app_path, "config.yml")))
20
- ENV["THOR_SILENCE_DEPRECATION"] = "true"
21
- EXPORT_DIR = File.join(app_path, "exports")
22
-
23
6
  Signal.trap("INT") do
24
7
  warn("\n#{caller.join("\n")}: interrupted")
25
8
  exit(1)
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "json"
5
+ require "pastel"
6
+ require "psych"
7
+ require "rest-client"
8
+ require "thor"
9
+ require "tty-config"
10
+ require "tty-editor"
11
+ require "tty-font"
12
+ require "tty-prompt"
13
+ require "tty-spinner"
14
+ require "tty-table"
15
+ require_relative "rockette/cli"
16
+ require_relative "rockette/controller"
17
+ require_relative "rockette/rester"
18
+ require_relative "rockette/text_helper"
19
+ require_relative "rockette/version"
data/lib/rockette.rb CHANGED
@@ -1,91 +1,35 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "erb"
4
- require "json"
5
- require "psych"
6
- require "rest-client"
7
- require "thor"
8
- require_relative "rockette/cli"
9
- require_relative "rockette/text_helper"
10
- require_relative "rockette/version"
3
+ require_relative "requirements"
4
+
5
+ # Set paths
6
+ APP_PATH = if File.exist?(File.join("usr", "app")) # Why Docker, why?
7
+ File.join("usr", "app", ".rockette")
8
+ elsif File.exist?(Dir.home)
9
+ File.join(Dir.home, ".rockette")
10
+ else
11
+ no_rockette_dir
12
+ end
13
+ lib_path = File.expand_path("../lib", __dir__)
14
+ tem_path = File.expand_path("../templates", __dir__)
15
+ $LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path)
16
+
17
+ # Create directories and config file if needed
18
+ Dir.mkdir(APP_PATH) unless File.exist?(APP_PATH)
19
+ unless File.exist?(File.join(APP_PATH, "config.yml"))
20
+ template = File.read(File.join(tem_path, "config.yml.erb"))
21
+ data = ERB.new(template).result(binding)
22
+ File.write(File.join(APP_PATH, "config.yml"), data)
23
+ end
24
+ Dir.mkdir(File.join(APP_PATH, "exports")) unless File.exist?(File.join(APP_PATH, "exports"))
25
+
26
+ # Set config and export directory paths
27
+ CONF = File.join(APP_PATH, "config.yml")
28
+ ENV["THOR_SILENCE_DEPRECATION"] = "true"
29
+ EXPORT_DIR = File.join(APP_PATH, "exports")
11
30
 
12
31
  # APEX deployment
13
32
  module Rockette
14
33
  class Error < StandardError; end
15
-
16
- # rest-client calls with error handling and auto retries
17
- class Rester
18
- VERBS = {
19
- "delete" => :Delete,
20
- "get" => :Get,
21
- "post" => :Post,
22
- "put" => :Put
23
- }.freeze
24
-
25
- def initialize(headers: {}, meth: "Get", params: {}, url: "https://array/", config: {})
26
- @headers = headers
27
- @meth = meth
28
- @params = params
29
- @url = url
30
- @config = config
31
- @config["timeout"] = @config["timeout"] ||= 30
32
- end
33
-
34
- def make_call
35
- response = RestClient::Request.execute(headers: @headers,
36
- method: VERBS[@meth.downcase], payload: @params,
37
- timeout: @config["timeout"], url: @url, verify_ssl: false)
38
- rescue SocketError, IOError => e
39
- puts "#{e.class}: #{e.message}"
40
- nil
41
- rescue StandardError => e
42
- e.response
43
- else
44
- response
45
- end
46
-
47
- def cookie
48
- if @url =~ %r{auth/session}
49
- response = make_call
50
- raise "There was an issue getting a cookie!" unless response.code == 200
51
-
52
- (response.cookies.map { |key, val| "#{key}=#{val}" })[0]
53
- else
54
- error_text("cookie", @url.to_s, "auth/session")
55
- end
56
- end
57
-
58
- # use rest-client with retry
59
- def rest_try
60
- 3.times do |i|
61
- response = make_call
62
- unless response.nil?
63
- break response if (200..299).include? response.code
64
- break response if i > 1
65
- end
66
- puts "Failed #{@meth} on #{@url}, retry...#{i + 1}"
67
- sleep 3 unless i > 1
68
- return nil if i > 1 # Handles socket errors, etc. where there is no response.
69
- end
70
- end
71
-
72
- private
73
-
74
- def error_text(method_name, url, wanted)
75
- {
76
- "response" =>
77
- "ERROR: Wrong url for the #{method_name} method.\n"\
78
- "Sent: #{url}\n"\
79
- "Expected: \"#{wanted}\" as part of the url.",
80
- "status" => 400
81
- }
82
- end
83
-
84
- def responder(response)
85
- {
86
- "response" => JSON.parse(response.body),
87
- "status" => response.code.to_i
88
- }
89
- end
90
- end
34
+ # Code in lib/rockette
91
35
  end
data/lib/rockette/cli.rb CHANGED
@@ -18,10 +18,10 @@ module Rockette
18
18
  desc "deploy", "Deploy chosen export file to target APEX instance"
19
19
  method_option :help, aliases: "-h", type: :boolean,
20
20
  desc: "Display usage information"
21
- option :app_id, aliases: "-a", required: true,
22
- desc: "Provide an APEX application ID"
21
+ option :app_id, aliases: "-a", default: "0",
22
+ desc: "Update this App ID with export set by '-f' Leave off or pass '-c' to copy export to target"
23
23
  option :file, aliases: "-f", required: true,
24
- desc: "Provide an APEX application export file (.sql)"
24
+ desc: "Provide an APEX application export file (sql)"
25
25
  option :url, aliases: "-u", required: true,
26
26
  desc: "Provide a valid APEX deployment url"
27
27
  option :copy, aliases: "-c", required: false,
@@ -42,6 +42,9 @@ module Rockette
42
42
  desc: "Provide an APEX application ID"
43
43
  option :url, aliases: "-u", required: true,
44
44
  desc: "Provide a valid url"
45
+ option :file, aliases: "-f", required: false,
46
+ desc: "Save export with this file name"
47
+
45
48
  def export(*)
46
49
  if options[:help]
47
50
  invoke :help, ["export"]
@@ -51,9 +54,9 @@ module Rockette
51
54
  end
52
55
  end
53
56
 
54
- desc "config", "Command description..."
57
+ desc "config", "Set configuration options..."
55
58
  method_option :help, aliases: "-h", type: :boolean,
56
- desc: "Display usage information"
59
+ desc: "Not implemented yet..."
57
60
  def config(*)
58
61
  if options[:help]
59
62
  invoke :help, ["config"]
@@ -62,5 +65,19 @@ module Rockette
62
65
  Rockette::Commands::Config.new(options).execute
63
66
  end
64
67
  end
68
+
69
+ desc "interactive", "Start Rockette in interactive mode"
70
+ method_option :help, aliases: "-h", type: :boolean,
71
+ desc: "'rockette' by itself will start interactive mode"
72
+ def interactive(*)
73
+ if options[:help]
74
+ invoke :help, ["interactive"]
75
+ else
76
+ require_relative "commands/interactive"
77
+ Rockette::Commands::Interactive.new(options).execute
78
+ end
79
+ end
80
+
81
+ default_task :interactive
65
82
  end
66
83
  end
@@ -12,7 +12,8 @@ module Rockette
12
12
  super()
13
13
  @options = options
14
14
  @filey = @options[:file]
15
- @body = CONF["deploy_body"]
15
+ @conf = Psych.load(File.read(CONF))
16
+ @body = @conf["deploy_body"]
16
17
  @body["app_id_src"] = "1" # @options[:app_id]
17
18
  @body["app_id_tgt"] = @options[:copy] ? 0 : @options[:app_id]
18
19
  @body["blob_url"] = @filey
@@ -34,7 +35,7 @@ module Rockette
34
35
  end
35
36
 
36
37
  def pusher
37
- push_hdrs = CONF["push_hdrs"]
38
+ push_hdrs = @conf["push_hdrs"]
38
39
  push_hdrs["file_name"] = @filey
39
40
  push_url = "#{@options[:url]}data_loader/blob"
40
41
  # Push the chosen export file to the target system
@@ -48,8 +48,9 @@ module Rockette
48
48
  sleep 1
49
49
  response = grabber
50
50
  # Write file if export was grabbed.
51
- File.open(File.join(EXPORT_DIR, @filey), "wb") { |file| file.write(response.body) }
52
- output.puts padder("Finished downloading #{@filey}. Have a good one!")
51
+ save_file = @options[:file] || @filey
52
+ File.open(File.join(EXPORT_DIR, save_file), "wb") { |file| file.write(response.body) }
53
+ output.puts padder("Finished downloading #{save_file}. Have a good one!")
53
54
  end
54
55
  end
55
56
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../command"
4
+
5
+ module Rockette
6
+ module Commands
7
+ # Interactive Rockette
8
+ class Interactive < Rockette::Command
9
+ include TextHelper
10
+
11
+ def initialize(options)
12
+ super()
13
+ @options = options
14
+ end
15
+
16
+ def execute(input: $stdin, output: $stdout)
17
+ output.puts
18
+ check_input(input)
19
+ controller = Rockette::Controller.new
20
+ controller.launch!
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "controller/configurator"
4
+ require_relative "controller/deployer"
5
+ require_relative "controller/exporter"
6
+ require_relative "controller/viewer"
7
+ require_relative "text_helper"
8
+
9
+ module Rockette
10
+ MAIN_ACTIONS = { "🔭 View Resources" => 1, "🚀 Deploy" => 2, "📥 Export" => 3,
11
+ "🛠 Configure" => 4, "❌ Quit" => 5 }.freeze
12
+ # Manage Rockette in interactive mode
13
+ class Controller
14
+ def initialize
15
+ @conf = Psych.load(File.read(CONF))
16
+ @pastel = Pastel.new
17
+ @prompt = TTY::Prompt.new
18
+ end
19
+
20
+ def launch!
21
+ introduction
22
+
23
+ if @conf["rockette"]["check_for_url"] && @conf["rockette"]["controller_url"].length < 10
24
+ configurer = Rockette::Configurator.new
25
+ configurer.first_run
26
+ end
27
+
28
+ # input/action loop
29
+ loop do
30
+ action = actions
31
+ break if action == 5
32
+
33
+ do_action(action)
34
+ end
35
+ conclusion
36
+ end
37
+
38
+ private
39
+
40
+ def introduction
41
+ font = TTY::Font.new(:starwars)
42
+ puts "-" * 85
43
+ puts
44
+ puts @pastel.yellow(font.write("Rockette"))
45
+ puts
46
+ puts "-" * 85
47
+ puts "Rockette helps export and deploy APEX applications."
48
+ puts
49
+ end
50
+
51
+ def conclusion
52
+ puts
53
+ puts "-" * 85
54
+ puts @pastel.yellow("Have a good one!".upcase.center(85))
55
+ puts "-" * 85
56
+ puts
57
+ end
58
+
59
+ def actions
60
+ @prompt.select("What would you like to do?", MAIN_ACTIONS)
61
+ end
62
+
63
+ def do_action(action)
64
+ case action
65
+ when 1
66
+ viewer = Rockette::Viewer.new
67
+ viewer.launch!
68
+ when 2
69
+ deployer = Rockette::Deployer.new
70
+ deployer.launch!
71
+ when 3
72
+ exporter = Rockette::Exporter.new
73
+ exporter.launch!
74
+ when 4
75
+ configurer = Rockette::Configurator.new
76
+ configurer.launch!
77
+ else
78
+ puts "\nI don't understand that command.\n\n"
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../text_helper"
4
+
5
+ module Rockette
6
+ # Configure Rockette application
7
+ class Configurator
8
+ include TextHelper
9
+
10
+ attr_reader :config
11
+
12
+ def initialize
13
+ @config = TTY::Config.new
14
+ @config.append_path APP_PATH
15
+ @config.read
16
+
17
+ @pastel = Pastel.new
18
+ @prompt = TTY::Prompt.new
19
+ end
20
+
21
+ def self.config
22
+ @config ||= self.class.new.config
23
+ end
24
+
25
+ def launch!
26
+ puts
27
+ puts @pastel.yellow("Configure Rockette here. Choosing 'editor' will let you edit the config file directly.")
28
+ puts @pastel.yellow("Choose 'url' to enter a controller url, the api endpoint with your environments, etc.")
29
+ puts
30
+ # input/action loop
31
+ loop do
32
+ action = @prompt.select("What will it be?", %w[editor url back])
33
+ break if action == "back"
34
+
35
+ do_action(action)
36
+ end
37
+ end
38
+
39
+ def do_action(action)
40
+ case action
41
+ when "editor"
42
+ edit_config
43
+ when "url"
44
+ add_url
45
+ else
46
+ puts "\nI don't understand that command.\n\n"
47
+ end
48
+ end
49
+
50
+ def add_url
51
+ uri = @prompt.ask("Please enter APEX deployment URI (base path):") do |u|
52
+ u.validate(%r{^https://\w+.\w+})
53
+ end
54
+ @config.set(:rockette, :controller_url, value: uri)
55
+ @config.write(force: true)
56
+ refresh_conf
57
+ end
58
+
59
+ def edit_config
60
+ edit = TTY::Editor.open(CONF)
61
+ puts "There seems to have been an issue trying to open the file: #{CONF}" unless edit
62
+ refresh_conf if edit
63
+ end
64
+
65
+ def first_run
66
+ puts
67
+ puts "I see this is your first time running Rockette. Entering an APEX deployment"
68
+ puts "uri will allow me to discover more about your environments."
69
+ puts
70
+ response = @prompt.yes?("Would you like to enter a URI?")
71
+ if response == true
72
+ add_url
73
+ else
74
+ response = @prompt.yes?("Would you like to disable these checks in the future?")
75
+ @config.set(:rockette, :check_for_url, value: false) if response == true
76
+ end
77
+ @config.write(force: true) if response == true
78
+ refresh_conf
79
+ end
80
+
81
+ def refresh_conf
82
+ @config.read
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../text_helper"
4
+ require_relative "../commands/deploy"
5
+
6
+ module Rockette
7
+ # Push APEX application to target instance
8
+ class Deployer
9
+ include TextHelper
10
+
11
+ def initialize
12
+ @pastel = Pastel.new
13
+ @prompt = TTY::Prompt.new
14
+ @spinner = TTY::Spinner.new
15
+ end
16
+
17
+ def launch!
18
+ @conf = Psych.load(File.read(CONF))
19
+ intro_text
20
+
21
+ # input/action loop
22
+ loop do
23
+ actions = { "🛸 Add" => 1, "📝 Update" => 2, "⬅️ Go Back" => 3 }
24
+ response = @prompt.select("Add application or update an existing application?", actions)
25
+ break if response == 3
26
+
27
+ add_app if response == 1
28
+ updater if response == 2
29
+ end
30
+ puts
31
+ end
32
+
33
+ protected
34
+
35
+ def intro_text
36
+ puts
37
+ puts @pastel.yellow("These are the two available options:")
38
+ print "1. Add application to an APEX instance. "
39
+ print "It's #{@pastel.green.bold("generally safe and creates a new application")} from the export\n"
40
+ print "2. Update an existing application with your chosen export. "
41
+ print "#{@pastel.red.bold("Tread carefully")} with this option!\n"
42
+ puts
43
+ end
44
+
45
+ def add_app
46
+ puts padder("Let's choose an export to add")
47
+ file = choose_file
48
+ url = choose_env
49
+ puts padder("You chose to add #{file} to the environment at #{url}")
50
+ puts
51
+ return unless @prompt.yes?("Proceed with the deployment?")
52
+
53
+ options = Thor::CoreExt::HashWithIndifferentAccess.new "app_id" => "0", "url" => url, "file" => file,
54
+ "force" => true
55
+ Rockette::Commands::Deploy.new(options).execute
56
+ puts
57
+ end
58
+
59
+ def choose_app(apps_url)
60
+ apps = Rockette::Viewer.new.applications(apps_url)
61
+ list = list_builder(apps)
62
+ action = @prompt.slider("Application to update => ", list, default: 1)
63
+
64
+ apps[action - 1]
65
+ end
66
+
67
+ def choose_env
68
+ enviros = Rockette::Viewer.new.environments
69
+ list = list_builder(enviros)
70
+ action = @prompt.select("Which environment?", list)
71
+ enviros[action - 1]["deployment_api"]
72
+ end
73
+
74
+ def choose_file
75
+ list = Dir.children(EXPORT_DIR)
76
+ @prompt.select("Which export from #{EXPORT_DIR}?", list)
77
+ end
78
+
79
+ def list_builder(array)
80
+ names = [] # Start building selection list
81
+ if array[0].key?("name")
82
+ array.each { |n| names << n["name"] }
83
+ else
84
+ array.each { |n| names << "#{n["application_name"]} App ID: #{n["application_id"]}" }
85
+ end
86
+ names << "Go Back"
87
+ names.map.with_index { |n, x| [n, x + 1] }.to_h
88
+ end
89
+
90
+ def updater
91
+ puts padder("Please choose the export with your updated application code")
92
+ file = choose_file
93
+ url = choose_env
94
+ app = choose_app(url)
95
+ puts "Application: #{app["application_name"]} | App ID: #{app["application_id"]} | Env URI: #{url}"
96
+ puts "will be updated with the code from export: #{file}"
97
+ puts
98
+ return unless @prompt.yes?("Proceed with the deployment?")
99
+
100
+ options = Thor::CoreExt::HashWithIndifferentAccess.new "app_id" => app["application_id"], "url" => url,
101
+ "file" => file, "force" => true
102
+ Rockette::Commands::Deploy.new(options).execute
103
+ puts
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../text_helper"
4
+ require_relative "../commands/export"
5
+
6
+ module Rockette
7
+ # Export and download APEX application
8
+ class Exporter
9
+ include TextHelper
10
+
11
+ def initialize
12
+ @pastel = Pastel.new
13
+ @prompt = TTY::Prompt.new
14
+ @spinner = TTY::Spinner.new
15
+ end
16
+
17
+ def launch!
18
+ @conf = Psych.load(File.read(CONF))
19
+ puts padder("Choose an application to download.")
20
+ puts
21
+
22
+ # input/action loop
23
+ loop do
24
+ enviros = Rockette::Viewer.new.environments
25
+ list = list_builder(enviros)
26
+ action = @prompt.select("Which environment is the app found?", list)
27
+ break if action == list.length
28
+
29
+ apps_url = enviros[action - 1]["deployment_api"]
30
+ choose_app(apps_url)
31
+ end
32
+ end
33
+
34
+ def do_export(app_id, apps_url)
35
+ response = @prompt.yes?("Would you like to enter a filename for the export?")
36
+ if response == true
37
+ file = @prompt.ask("Please enter your desired filename:")
38
+ options = Thor::CoreExt::HashWithIndifferentAccess.new "app_id" => app_id, "url" => apps_url, "file" => file,
39
+ "force" => true
40
+ else
41
+ puts padder("Saving under default file name: f#{app_id}.sql")
42
+ options = Thor::CoreExt::HashWithIndifferentAccess.new "app_id" => app_id, "url" => apps_url, "force" => true
43
+ end
44
+ Rockette::Commands::Export.new(options).execute
45
+ puts
46
+ end
47
+
48
+ protected
49
+
50
+ def choose_app(apps_url)
51
+ loop do
52
+ apps = Rockette::Viewer.new.applications(apps_url)
53
+ list = list_builder(apps)
54
+ action = @prompt.slider("Download application => ", list, default: 1)
55
+ break if action == list.length
56
+
57
+ app_id = apps[action - 1]["application_id"]
58
+ do_export(app_id, apps_url)
59
+ end
60
+ end
61
+
62
+ def list_builder(array)
63
+ names = [] # Start building selection list
64
+ if array[0].key?("name")
65
+ array.each { |n| names << n["name"] }
66
+ else
67
+ array.each { |n| names << "#{n["application_name"]} App ID: #{n["application_id"]}" }
68
+ end
69
+ names << "Go Back"
70
+ names.map.with_index { |n, x| [n, x + 1] }.to_h
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../text_helper"
4
+
5
+ module Rockette
6
+ # View resources
7
+ class Viewer
8
+ include TextHelper
9
+
10
+ def initialize
11
+ @conf = Psych.load(File.read(CONF))
12
+ @pastel = Pastel.new
13
+ @prompt = TTY::Prompt.new
14
+ @spinner = TTY::Spinner.new # ("[:spinner] Loading APEX environments ...", format: pulse_2)
15
+ @view_actions = { "🏔 APEX Environments" => 1, "🎭 Registered Applications" => 2, "⬅️ Go Back" => 3 }
16
+ end
17
+
18
+ def launch!
19
+ puts padder("You can view environments or registered applications")
20
+ puts
21
+
22
+ # input/action loop
23
+ loop do
24
+ action = @prompt.select("Which would you like to see?", @view_actions)
25
+ break if action == 3
26
+
27
+ do_action(action)
28
+ end
29
+ end
30
+
31
+ def do_action(action)
32
+ case action
33
+ when 1
34
+ puts
35
+ environments unless @table_env
36
+ @spinner.auto_spin
37
+ sleep(1)
38
+ @spinner.stop
39
+ puts @table_env.render(:ascii)
40
+ puts
41
+ when 2
42
+ puts
43
+ registered unless @table_reg
44
+ puts @table_reg.render(:ascii)
45
+ puts
46
+ else
47
+ puts "\nI don't understand that command.\n\n"
48
+ end
49
+ end
50
+
51
+ def ape_e_i(uri)
52
+ response = Rester.new(url: uri).rest_try
53
+ bail unless response
54
+ abort padder("#{uri} didn't work. Received: #{response.code}") unless response.code == 200
55
+ response
56
+ end
57
+
58
+ def applications(url)
59
+ uri = "#{url}deploy/apps"
60
+ response = ape_e_i(uri)
61
+ JSON.parse(response.body)["items"]
62
+ end
63
+
64
+ def environments
65
+ uri = "#{@conf["rockette"]["controller_url"]}deploy/environments/"
66
+ response = ape_e_i(uri)
67
+ @table_env = TTY::Table.new(header: ["Environment Name", "API", "Domain", "Owner", "Workspace"])
68
+ items = JSON.parse(response.body)["items"]
69
+ items.each { |h| @table_env << [h["name"], h["deployment_api"], h["domain"], h["owner"], h["workspace"]] }
70
+ end
71
+
72
+ def registered
73
+ uri = "#{@conf["rockette"]["controller_url"]}deploy/registered_apps/"
74
+ response = ape_e_i(uri)
75
+ @table_reg = TTY::Table.new(header: ["Registered Name", "Source App ID", "Source URI", "Target App ID",
76
+ "Target URI"])
77
+ JSON.parse(response.body)["items"].each do |h|
78
+ @table_reg << [h["registered_name"], h["src_app_id"], h["src_url"], h["tgt_app_id"], h["tgt_url"]]
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rockette
4
+ # configurable rest-client calls with error handling and auto retries
5
+ class Rester
6
+ VERBS = {
7
+ "delete" => :Delete,
8
+ "get" => :Get,
9
+ "post" => :Post,
10
+ "put" => :Put
11
+ }.freeze
12
+
13
+ def initialize(headers: {}, meth: "Get", params: {}, url: "https://array/", config: {})
14
+ @headers = headers
15
+ @meth = meth
16
+ @params = params
17
+ @url = url
18
+ @config = config
19
+ @config["timeout"] = @config["timeout"] ||= 30
20
+ end
21
+
22
+ def make_call
23
+ response = RestClient::Request.execute(headers: @headers,
24
+ method: VERBS[@meth.downcase], payload: @params,
25
+ timeout: @config["timeout"], url: @url, verify_ssl: false)
26
+ rescue SocketError, IOError => e
27
+ puts "#{e.class}: #{e.message}"
28
+ nil
29
+ rescue StandardError => e
30
+ e.response
31
+ else
32
+ response
33
+ end
34
+
35
+ def cookie
36
+ if @url =~ %r{auth/session}
37
+ response = make_call
38
+ raise "There was an issue getting a cookie!" unless response.code == 200
39
+
40
+ (response.cookies.map { |key, val| "#{key}=#{val}" })[0]
41
+ else
42
+ error_text("cookie", @url.to_s, "auth/session")
43
+ end
44
+ end
45
+
46
+ # use rest-client with retry
47
+ def rest_try(tries = 3)
48
+ tries.times do |i|
49
+ response = make_call
50
+ unless response.nil?
51
+ break response if (200..299).include? response.code
52
+ break response if i > 1
53
+ end
54
+ puts "Failed #{@meth} on #{@url}, retry...#{i + 1}"
55
+ sleep 3 unless i > 1
56
+ return nil if i > 1 # Handles socket errors, etc. where there is no response.
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def error_text(method_name, url, wanted)
63
+ {
64
+ "response" =>
65
+ "ERROR: Wrong url for the #{method_name} method.\n"\
66
+ "Sent: #{url}\n"\
67
+ "Expected: \"#{wanted}\" as part of the url.",
68
+ "status" => 400
69
+ }
70
+ end
71
+
72
+ def responder(response)
73
+ {
74
+ "response" => JSON.parse(response.body),
75
+ "status" => response.code.to_i
76
+ }
77
+ end
78
+ end
79
+ end
@@ -19,6 +19,12 @@ module TextHelper
19
19
  exit
20
20
  end
21
21
 
22
+ def no_rockette_dir
23
+ puts "Unable to locate a suitable place for the .rockette directory."
24
+ puts "Please double check your home directory..."
25
+ exit
26
+ end
27
+
22
28
  def padder(str)
23
29
  "\n#{str}\n"
24
30
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rockette
4
- VERSION = "0.0.2"
4
+ VERSION = "0.0.3"
5
5
  end
data/rockette.gemspec CHANGED
@@ -32,10 +32,15 @@ Gem::Specification.new do |spec|
32
32
  # Dev dependencies
33
33
  spec.add_development_dependency "pry", "~> 0.0"
34
34
 
35
- # Uncomment to register a new dependency of your gem
35
+ # Dependencies
36
+ spec.add_dependency "pastel", "~> 0.0"
36
37
  spec.add_dependency "rest-client", "~> 2.0"
37
38
  spec.add_dependency "thor", "~> 1.0"
39
+ spec.add_dependency "tty-config", "~> 0.0"
40
+ spec.add_dependency "tty-editor", "~> 0.0"
41
+ spec.add_dependency "tty-font", "~> 0.0"
42
+ spec.add_dependency "tty-prompt", "~> 0.0"
43
+ spec.add_dependency "tty-spinner", "~> 0.0"
44
+ spec.add_dependency "tty-table", "~> 0.0"
38
45
 
39
- # For more information and examples about making a new gem, checkout our
40
- # guide at: https://bundler.io/guides/creating_gem.html
41
46
  end
@@ -15,3 +15,6 @@ deploy_body:
15
15
  app_id_src: ''
16
16
  app_id_tgt: ''
17
17
  blob_url: https://local.data_loader
18
+ rockette:
19
+ check_for_url: true
20
+ controller_url: ''
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rockette
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kody Wilson
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-03-18 00:00:00.000000000 Z
11
+ date: 2021-03-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pastel
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rest-client
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +66,90 @@ dependencies:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
68
  version: '1.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: tty-config
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: tty-editor
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: tty-font
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: tty-prompt
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: tty-spinner
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: tty-table
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '0.0'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '0.0'
55
153
  description: Rockette helps deploy and export APEX applications.
56
154
  email:
57
155
  - kodywilson@gmail.com
@@ -73,6 +171,7 @@ files:
73
171
  - bin/console
74
172
  - bin/setup
75
173
  - exe/rockette
174
+ - lib/requirements.rb
76
175
  - lib/rockette.rb
77
176
  - lib/rockette/cli.rb
78
177
  - lib/rockette/command.rb
@@ -80,6 +179,13 @@ files:
80
179
  - lib/rockette/commands/config.rb
81
180
  - lib/rockette/commands/deploy.rb
82
181
  - lib/rockette/commands/export.rb
182
+ - lib/rockette/commands/interactive.rb
183
+ - lib/rockette/controller.rb
184
+ - lib/rockette/controller/configurator.rb
185
+ - lib/rockette/controller/deployer.rb
186
+ - lib/rockette/controller/exporter.rb
187
+ - lib/rockette/controller/viewer.rb
188
+ - lib/rockette/rester.rb
83
189
  - lib/rockette/text_helper.rb
84
190
  - lib/rockette/version.rb
85
191
  - rockette.gemspec