rockette 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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