mimas 0.1.0

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.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/Gemfile +12 -0
  4. data/Gemfile.lock +106 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +346 -0
  7. data/Rakefile +4 -0
  8. data/bin/mimas +5 -0
  9. data/lib/mimas/archiver.rb +68 -0
  10. data/lib/mimas/base_command.rb +22 -0
  11. data/lib/mimas/cli.rb +22 -0
  12. data/lib/mimas/commands/console.rb +21 -0
  13. data/lib/mimas/commands/init.rb +63 -0
  14. data/lib/mimas/commands/install.rb +21 -0
  15. data/lib/mimas/commands/provision.rb +50 -0
  16. data/lib/mimas/commands/push.rb +28 -0
  17. data/lib/mimas/commands/setup/caddy.rb +18 -0
  18. data/lib/mimas/commands/setup/deploy_user.rb +16 -0
  19. data/lib/mimas/commands/setup/ruby.rb +17 -0
  20. data/lib/mimas/commands/setup.rb +10 -0
  21. data/lib/mimas/config.rb +124 -0
  22. data/lib/mimas/deployment/caddy.rb +39 -0
  23. data/lib/mimas/deployment/files.rb +51 -0
  24. data/lib/mimas/deployment/paths.rb +54 -0
  25. data/lib/mimas/deployment/ruby_app.rb +126 -0
  26. data/lib/mimas/deployment/static_site.rb +28 -0
  27. data/lib/mimas/deployment.rb +27 -0
  28. data/lib/mimas/hooks.rb +25 -0
  29. data/lib/mimas/plugins.rb +19 -0
  30. data/lib/mimas/scripts/configure_ruby.sh +19 -0
  31. data/lib/mimas/scripts/create_deploy_user.sh +30 -0
  32. data/lib/mimas/scripts/harden.sh +125 -0
  33. data/lib/mimas/scripts/install_caddy.sh +51 -0
  34. data/lib/mimas/scripts/install_ruby_prerequisites.sh +26 -0
  35. data/lib/mimas/server/caddy.rb +17 -0
  36. data/lib/mimas/server/console.rb +34 -0
  37. data/lib/mimas/server/deploy_user.rb +11 -0
  38. data/lib/mimas/server/harden.rb +20 -0
  39. data/lib/mimas/server/prerequisites.rb +25 -0
  40. data/lib/mimas/server/ruby.rb +37 -0
  41. data/lib/mimas/server.rb +37 -0
  42. data/lib/mimas/site.rb +24 -0
  43. data/lib/mimas/ssh.rb +78 -0
  44. data/lib/mimas/template.rb +28 -0
  45. data/lib/mimas/templates/Caddyfile.ruby.erb +12 -0
  46. data/lib/mimas/templates/Caddyfile.static.erb +15 -0
  47. data/lib/mimas/templates/caddy.service.erb +19 -0
  48. data/lib/mimas/templates/config.rb.erb +51 -0
  49. data/lib/mimas/templates/falcon.rb.erb +12 -0
  50. data/lib/mimas/templates/mimas.env.erb +2 -0
  51. data/lib/mimas/templates/puma.rb +11 -0
  52. data/lib/mimas/templates/systemd.service.erb +20 -0
  53. data/lib/mimas/terminal/ansi.rb +71 -0
  54. data/lib/mimas/terminal/printer.rb +14 -0
  55. data/lib/mimas/version.rb +3 -0
  56. data/lib/mimas.rb +48 -0
  57. data/mimas.gemspec +29 -0
  58. data/scripts/release +8 -0
  59. data/scripts/test +7 -0
  60. data/tmp/.keep +0 -0
  61. metadata +181 -0
@@ -0,0 +1,63 @@
1
+ module Mimas
2
+ module CLI
3
+ module Commands
4
+ class Init < BaseCommand
5
+ desc "Create the Mimas config file"
6
+
7
+ def call
8
+ say "Initialising Mimas. We need some information about your site."
9
+ say ""
10
+
11
+ say "Your site's domain will be the containing folder on the server."
12
+ domain = ask "What is your site's domain name?"
13
+ ip = ask "What is your production server's IP address?"
14
+ site_type = ask "Are you creating a \n 1. Ruby app \n 2. Static site \n (1 | 2)"
15
+ site_type = site_types[site_type]
16
+
17
+ app_server = nil
18
+ if site_type == :ruby
19
+ app_server = ask "Which Ruby application server are you using?"
20
+ app_server&.downcase!
21
+
22
+ unless ["falcon", "puma"].include?(app_server)
23
+ say "Mimas natively supports Falcon and Puma. To use other server, ensure you configure it to bind to a unix socket defined in `ENV['MIMAS_UNIX_SOCKET']`".white.bold
24
+ end
25
+ end
26
+
27
+ Dir.mkdir("deploy") unless Dir.exist? "deploy"
28
+
29
+ destination_dir = File.join(Dir.pwd, Mimas::Config::DEFAULT_DIRECTORY)
30
+
31
+ configrb = template("config.rb", ip: ip, domain: domain, site_type: site_type, app_server: app_server)
32
+ File.write(File.join(destination_dir, "mimas.rb"), configrb)
33
+
34
+ if site_type == :ruby
35
+ copy_file(destination_dir, "Caddyfile.ruby.erb", rename: "Caddyfile.erb")
36
+
37
+ if app_server == "falcon"
38
+ falconrb = template("falcon.rb", domain: domain)
39
+ File.write(File.join(destination_dir, "falcon.rb"), falconrb)
40
+ end
41
+
42
+ copy_file(destination_dir, "puma.rb") if app_server == "puma"
43
+ else
44
+ copy_file(destination_dir, "Caddyfile.static.erb", rename: "Caddyfile.erb")
45
+ end
46
+
47
+ Dir.mkdir("tmp") unless Dir.exist?("tmp")
48
+
49
+ say ""
50
+ say "Successfully created 'deploy/mimas.rb' and 'deploy/Caddyfile.erb'. Customise your deployment by editing these files."
51
+ say "Please ensure your DNS is correctly configured."
52
+ end
53
+
54
+ def site_types
55
+ {
56
+ "1" => :ruby,
57
+ "2" => :static
58
+ }
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,21 @@
1
+ module Mimas
2
+ module CLI
3
+ module Commands
4
+ class Install < BaseCommand
5
+ desc "Install a new version of Ruby on the server."
6
+
7
+ argument :ruby_version, required: true, desc: "The version of Ruby to install."
8
+ argument :server_name, required: true, desc: "The name of the server to install Ruby on"
9
+
10
+ example [
11
+ "4.0.5 production"
12
+ ]
13
+
14
+ def call(ruby_version:, server_name:)
15
+ server = Config.current.servers[server_name.to_sym]
16
+ server.install_ruby(version: ruby_version)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,50 @@
1
+ module Mimas
2
+ module CLI
3
+ module Commands
4
+ class Provision < BaseCommand
5
+ desc "Provision the remote server by applying security settings, creating users, and installing Caddy and Ruby. Requires root access."
6
+
7
+ argument :server_name, required: true, desc: "The name of the server to provision"
8
+
9
+ option :user, default: "admin", aliases: ["-u"], desc: "A user with sudo access"
10
+ option :skip_ruby, default: false, type: :flag, desc: "Skip the installation of Ruby and its prerequisites. Use when only serving static sites"
11
+
12
+ example [
13
+ "production # Provision the production server",
14
+ "production -u administrator # Specify the sudo user as 'administrator'",
15
+ "--skip-ruby # Skip Ruby and install only Caddy"
16
+ ]
17
+
18
+ def call(server_name:, **options)
19
+ server = Config.current.servers[server_name.to_sym]
20
+ sudo_user = options[:user]
21
+ skip_ruby = options[:skip_ruby]
22
+
23
+ server.harden
24
+
25
+ say "Waiting for server to come back online ..."
26
+ sleep 30
27
+
28
+ connection_retries = 0
29
+ begin
30
+ connection_retries += 1
31
+ Net::SSH.start(server.host, sudo_user, **server.ssh_options)&.close
32
+ rescue
33
+ sleep 5
34
+ retry if connection_retries < 5
35
+ say "Unable to re-connect to server."
36
+ say "Wait for the server to come online, then run `bin/mimas setup`"
37
+ end
38
+
39
+ server.setup_deploy_user(sudo_user: sudo_user)
40
+ server.install_caddy(sudo_user: sudo_user)
41
+
42
+ unless skip_ruby
43
+ server.install_ruby_prerequisites(sudo_user: sudo_user)
44
+ server.install_ruby
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,28 @@
1
+ module Mimas
2
+ module CLI
3
+ module Commands
4
+ class Push < BaseCommand
5
+ desc "Push your Ruby app to the server"
6
+
7
+ argument :server_name, required: true, desc: "The name of the server to push to"
8
+ argument :site, desc: "The site to push. Uses the default site if unspecified"
9
+
10
+ example [
11
+ "production # Push the default site to the production server",
12
+ "production app # Push the `:app` site to the production server"
13
+ ]
14
+
15
+ def call(server_name:, site: :default)
16
+ server = Config.current.servers[server_name.to_sym]
17
+ site = Config.current.sites[site.to_sym]
18
+
19
+ @hooks[:before_push].each { it.call }
20
+
21
+ Deployment.new(site: site, server: server).deploy
22
+
23
+ @hooks[:after_push].each { it.call }
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,18 @@
1
+ module Mimas
2
+ module CLI
3
+ module Commands
4
+ class Setup::Caddy < Setup
5
+ desc "Setup Caddy on a server"
6
+
7
+ option :user, default: "admin", aliases: ["-u"], desc: "A user with sudo access. Defaults to 'admin'"
8
+
9
+ def call(server_name:, **options)
10
+ server = Config.current.servers[server_name.to_sym]
11
+ sudo_user = options[:user]
12
+
13
+ server.install_caddy(sudo_user: sudo_user)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ module Mimas
2
+ module CLI
3
+ module Commands
4
+ class Setup::DeployUser < Setup
5
+ desc "Create a deployment user as defined in your config file on a server"
6
+
7
+ def call(server_name:, **options)
8
+ server = Config.current.servers[server_name.to_sym]
9
+ sudo_user = options[:user]
10
+
11
+ server.setup_deploy_user(sudo_user: sudo_user)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ module Mimas
2
+ module CLI
3
+ module Commands
4
+ class Setup::Ruby < Setup
5
+ desc "Install Ruby prerequisites and build a Ruby binary on a server"
6
+
7
+ def call(server_name:, **options)
8
+ server = Config.current.servers[server_name.to_sym]
9
+ sudo_user = options[:user]
10
+
11
+ server.install_ruby_prerequisites(sudo_user: sudo_user)
12
+ server.install_ruby
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,10 @@
1
+ module Mimas
2
+ module CLI
3
+ module Commands
4
+ class Setup < BaseCommand
5
+ argument :server_name, required: true, desc: "The name of the server to setup"
6
+ option :user, default: "admin", aliases: ["-u"], desc: "A user with sudo access"
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,124 @@
1
+ module Mimas
2
+ class Config
3
+ DEFAULT_DIRECTORY = "deploy"
4
+
5
+ def self.current
6
+ @current ||= load
7
+ end
8
+
9
+ def self.load(path = File.join(Dir.pwd, DEFAULT_DIRECTORY, "mimas.rb"))
10
+ if File.exist?(path)
11
+ source = File.read(path)
12
+ @current = build(source)
13
+ end
14
+ end
15
+
16
+ def self.open(&block)
17
+ DSL.new(&block).config
18
+ end
19
+
20
+ def self.build(source)
21
+ DSL.new(source).config
22
+ end
23
+
24
+ attr_reader :sites, :servers, :hooks
25
+
26
+ def initialize
27
+ @sites = {}
28
+ @servers = {}
29
+ @hooks = Hooks.new
30
+ end
31
+
32
+ def ruby_version
33
+ @ruby_version ||= begin
34
+ File.read(File.join(Dir.pwd, ".ruby-version")).chomp
35
+ rescue Errno::ENOENT
36
+ RUBY_VERSION
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ class DSL
43
+ attr_reader :config
44
+
45
+ def initialize(source = nil, &block)
46
+ @config = Config.new
47
+
48
+ if source
49
+ instance_eval(source)
50
+ else
51
+ instance_exec(&block)
52
+ end
53
+ end
54
+
55
+ def site(name = :default, &block)
56
+ name = name.to_sym
57
+ args = Site.evaluate(&block)
58
+ @config.sites[name] = Mimas::Site.new(name, args)
59
+ end
60
+
61
+ def server(name, &block)
62
+ name = name.to_sym
63
+ args = Options.evaluate(&block)
64
+ @config.servers[name] = Mimas::Server.new(name, args)
65
+ end
66
+
67
+ def hooks(&block)
68
+ @config.hooks.instance_exec(&block)
69
+ end
70
+ end
71
+
72
+ class Options
73
+ def self.evaluate(&block)
74
+ evaluator = self.new
75
+ evaluator.instance_exec(&block)
76
+ evaluator.options
77
+ end
78
+
79
+ attr_reader :options
80
+
81
+ def initialize
82
+ @options = {}
83
+ end
84
+
85
+ def method_missing(name, *args, &block)
86
+ if block
87
+ @options[name.to_sym] = block.call
88
+ else
89
+ @options[name.to_sym] = args.first
90
+ end
91
+ end
92
+ end
93
+
94
+ class Site < Options
95
+ def services(&block)
96
+ @options[:services] = Services.parse(&block)
97
+ end
98
+
99
+ def deploy(&block)
100
+ @options[:deploy] = block.call.to_s
101
+ end
102
+ end
103
+
104
+ class Services
105
+ def self.parse(&block)
106
+ services_parser = self.new
107
+ services_parser.instance_exec(&block)
108
+ services_parser.services
109
+ end
110
+
111
+ attr_reader :services
112
+ def initialize
113
+ @services = {}
114
+ end
115
+
116
+ def method_missing(name, *args, &block)
117
+ @services[name] = Options.evaluate do
118
+ instance_eval(&block)
119
+ end
120
+ @services[name][:name] = name
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,39 @@
1
+ module Mimas
2
+ class Deployment
3
+ module Caddy
4
+ def refreshing_caddy(session, &block)
5
+ session.run "mkdir -p #{remote_destination}"
6
+ session.upload StringIO.new(commit_hash), remote_destination.join("commit-sha")
7
+
8
+ remote_caddyfile = ""
9
+ begin
10
+ remote_caddyfile = session.run "cat #{caddyfile_path}", capture: true
11
+ rescue SSH::Session::NonZeroExitCode
12
+ # Ignore non-zero exit
13
+ end
14
+ caddyfile_modified = remote_caddyfile != caddyfile
15
+
16
+ if caddyfile_modified
17
+ say "Uploading new Caddyfile"
18
+ begin
19
+ session.upload StringIO.new(caddyfile), new_caddyfile_path
20
+ session.run "caddy validate --config #{new_caddyfile_path}", capture: true
21
+ say "New Caddyfile validated"
22
+ rescue SSH::Session::NonZeroExitCode
23
+ session.run "rm #{new_caddyfile_path}"
24
+ say caddyfile.bold.red
25
+ raise "Your Caddyfile is invalid"
26
+ end
27
+ end
28
+
29
+ yield
30
+
31
+ if caddyfile_modified
32
+ say "Updating Caddyfile and reloading Caddy"
33
+ session.run "mv #{new_caddyfile_path} #{caddyfile_path}"
34
+ session.run "sudo systemctl reload caddy"
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,51 @@
1
+ module Mimas
2
+ class Deployment
3
+ module Files
4
+ CADDYFILE_PATH = Pathname(Dir.pwd).join(Mimas::Config::DEFAULT_DIRECTORY)
5
+
6
+ def caddyfile
7
+ @caddyfile ||= begin
8
+ file_name = ["Caddyfile", site.name, "erb"].reject { it == :default }.join(".")
9
+ ERB.new(File.read(CADDYFILE_PATH.join(file_name)))
10
+ .result_with_hash(
11
+ site: site,
12
+ server: server,
13
+ domain: site.domain,
14
+ site_root: site_root,
15
+ unix_socket: unix_socket
16
+ )
17
+ end
18
+ end
19
+
20
+ def systemd_service_name(service, version: self.version)
21
+ return nil if site.static?
22
+
23
+ "#{site.domain}--#{service[:name]}--#{version}"
24
+ end
25
+
26
+ def systemd(service)
27
+ return nil if site.static?
28
+
29
+ template("systemd.service",
30
+ domain: site.domain,
31
+ version: version,
32
+ user: server.user,
33
+ site_root: site_root,
34
+ service_name: service[:name],
35
+ command: service[:command],
36
+ )
37
+ end
38
+
39
+ def mimas_env
40
+ return nil if site.static?
41
+
42
+ @mimas_env ||=
43
+ template("mimas.env", unix_socket: unix_socket, env: site.env)
44
+ end
45
+
46
+ def deploy_script
47
+ ".mimas_deploy.sh"
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,54 @@
1
+ module Mimas
2
+ class Deployment
3
+ module Paths
4
+ def remote_destination
5
+ @remote_destination ||= releases_path.join(version)
6
+ end
7
+
8
+ def archive_name
9
+ @archive_name ||= "#{site.name}--#{version}.tar.gz"
10
+ end
11
+
12
+ def archive_path
13
+ @archive_path ||= File.join(Dir.pwd, "tmp", archive_name)
14
+ end
15
+
16
+ def site_root
17
+ server.site_root(site)
18
+ end
19
+
20
+ def current_path
21
+ server.current_path(site)
22
+ end
23
+
24
+ def caddyfile_path
25
+ site_root.join("Caddyfile")
26
+ end
27
+
28
+ def new_caddyfile_path
29
+ site_root.join("Caddyfile.new")
30
+ end
31
+
32
+ def mimas_path
33
+ site_root.join("mimas")
34
+ end
35
+
36
+ def releases_path
37
+ site_root.join("releases")
38
+ end
39
+
40
+ def unix_socket(version: self.version)
41
+ return nil if site.static?
42
+ mimas_path.join("application--#{version}.sock")
43
+ end
44
+
45
+ def ruby_version
46
+ Config.current.ruby_version
47
+ end
48
+
49
+ def deploy_script_path
50
+ remote_destination.join(deploy_script)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,126 @@
1
+ module Mimas
2
+ class Deployment
3
+ module RubyApp
4
+ def deploy_ruby_app
5
+ say "Starting deployment for #{site.domain}"
6
+
7
+ archive(output: archive_path, files: site.files)
8
+
9
+ ssh(server) do |session|
10
+ begin
11
+ session.run "test -d ~/.rubies/ruby-#{ruby_version}"
12
+ say "Ruby #{ruby_version} found on the server..."
13
+ rescue SSH::Session::NonZeroExitCode
14
+ raise "Ruby version not installed on server"
15
+ end
16
+
17
+ # Create the release folder
18
+ session.run "mkdir -p #{releases_path}"
19
+
20
+ # Get expired releases. Mimas will only retain the last 5 releases.
21
+ releases = session.run "ls #{releases_path}", capture: true
22
+ expired_releases = releases.split("\n").sort.reverse.drop(5)
23
+
24
+ if expired_releases.any?
25
+ say "Deleting versions: #{expired_releases.join(", ")}"
26
+ session.run "cd #{releases_path} && rm -rf #{expired_releases.join(" ")}"
27
+ end
28
+
29
+ # Check `current` symlink to get currently live version
30
+ remote_current_path = session.run("readlink #{current_path}", capture: true, silent: true).chomp
31
+ remote_current_version = Pathname.new(remote_current_path).basename.to_s.chomp
32
+
33
+ say "Current live version is #{remote_current_version}" if remote_current_version.size > 0
34
+
35
+ # Make systemd path and the site's mimas folder
36
+ session.run "mkdir -p #{server.user_systemd_path}"
37
+ session.run "mkdir -p #{mimas_path}"
38
+
39
+ refreshing_caddy(session) do
40
+ # Upload the mimas.env and touch an `.env` file in the site's root
41
+ session.upload StringIO.new(mimas_env), mimas_path.join("mimas.env")
42
+ session.run "touch #{site_root.join(".env")}"
43
+
44
+ say "Uploading version: #{version}"
45
+ session.upload archive_path, "#{remote_destination}/"
46
+
47
+ say "Extracting version: #{version}"
48
+ session.run "cd #{remote_destination} && tar -xf #{archive_name} && rm #{archive_name}", capture: true
49
+
50
+ say "Running deploy script"
51
+ session.upload StringIO.new(site.deploy), deploy_script_path
52
+ session.run "cd #{remote_destination} && /usr/bin/env bash -l #{deploy_script}"
53
+ session.run "rm #{deploy_script_path}"
54
+
55
+ say "Setting current symlink"
56
+ session.run "ln -sfn #{remote_destination} #{current_path}"
57
+ say "Current symlink set"
58
+
59
+ site.services.each do |_, service|
60
+ say "Installing service: #{service[:name]}"
61
+ systemd_service_name = systemd_service_name(service)
62
+ system_contents = systemd(service)
63
+
64
+ session.upload StringIO.new(system_contents), server.user_systemd_path.join("#{systemd_service_name}.service")
65
+ session.run "systemctl --user enable --now #{systemd_service_name}", capture: true
66
+ say "Started #{service[:name]} service using as #{systemd_service_name}"
67
+
68
+ begin
69
+ say "Health checking new service"
70
+ session.run "curl --max-time 1 --silent --fail --unix-socket #{unix_socket} http://localhost#{site.healthcheck_path}", capture: true
71
+ say "Health check succeeded"
72
+ rescue SSH::Session::NonZeroExitCode => e
73
+ say "Health check failed".red
74
+ say e.to_s.red.bold
75
+ raise e
76
+ end
77
+ end
78
+ rescue Exception => e
79
+ say "Error raised during deploy: #{e}".red.bold
80
+
81
+ # Revert symlink if there's an existing live release, otherwise delete it
82
+ if remote_current_path.size > 0
83
+ say "Reverting symlink ..."
84
+ session.run "ln -sfn #{remote_current_path} #{current_path}"
85
+ else
86
+ say "Deleting symlink ..."
87
+ session.run "rm -f #{current_path}"
88
+ end
89
+
90
+ say "Deleting released files ..."
91
+
92
+ site.services.each do |_, service|
93
+ systemd_service_name = systemd_service_name(service)
94
+ session.run "systemctl --user stop #{systemd_service_name}", silent: true, capture: true
95
+ session.run "systemctl --user disable #{systemd_service_name}", silent: true, capture: true
96
+ session.run "rm #{server.user_systemd_path.join("#{systemd_service_name}.service")}", silent: true
97
+ end
98
+
99
+ session.run "rm -f #{unix_socket(version: version)}"
100
+ session.run "rm -f #{site_root.join("Caddyfile.new")}"
101
+ session.run "rm -rf #{remote_destination}"
102
+
103
+ exit 1
104
+ end
105
+
106
+ # Delete the old service if one exists, and the new service started up
107
+ if remote_current_version.size > 0
108
+ site.services.each do |_, service|
109
+ systemd_service_name = systemd_service_name(service, version: remote_current_version)
110
+
111
+ say "Stopping old service: #{systemd_service_name}"
112
+ session.run "systemctl --user stop #{systemd_service_name}"
113
+ session.run "systemctl --user disable #{systemd_service_name}"
114
+ session.run "rm #{server.user_systemd_path.join("#{systemd_service_name}.service")}"
115
+ say "#{systemd_service_name} stopped and deleted."
116
+ session.run "rm -f #{unix_socket(version: remote_current_version)}"
117
+ end
118
+ end
119
+
120
+ say "\n"
121
+ say "Deployment complete! #{version} is now live.".bold.white
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,28 @@
1
+ module Mimas
2
+ class Deployment
3
+ module StaticSite
4
+ def deploy_static_site
5
+ say "Starting deployment for #{site.domain}"
6
+
7
+ archive(root: site.root_dir, output: archive_path, archive_root: "root", glob: site.glob)
8
+
9
+ ssh(server) do |session|
10
+ refreshing_caddy(session) do
11
+ say "Uploading version: #{version}"
12
+ session.upload archive_path, "#{remote_destination}/"
13
+
14
+ say "Extracting version: #{version}"
15
+ session.run "cd #{remote_destination} && tar -xf #{archive_name} && rm #{archive_name}"
16
+
17
+ say "Updating current symlink"
18
+ session.run "ln -sfn #{remote_destination} #{current_path}"
19
+ say "Current symlink updated"
20
+ end
21
+ end
22
+
23
+ say "\n\n"
24
+ say "Deployment complete! #{version} is now live.".bold.white
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ module Mimas
2
+ class Deployment
3
+ include Terminal::Printer, Template, Archive, SSH
4
+
5
+ include Paths, Files
6
+ include StaticSite, RubyApp, Caddy
7
+
8
+ attr_reader :site, :server, :version, :commit_hash
9
+
10
+ def initialize(site:, server:)
11
+ @site = site
12
+ @server = server
13
+ @version = Time.now.utc.strftime("%Y%m%d%H%M%S")
14
+ @commit_hash = `git rev-parse HEAD`
15
+ end
16
+
17
+ def deploy
18
+ if site.static?
19
+ deploy_static_site
20
+ else
21
+ deploy_ruby_app
22
+ end
23
+ ensure
24
+ File.delete(archive_path)
25
+ end
26
+ end
27
+ end