minestrone 0.0.1 → 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 +4 -4
- data/CHANGELOG.md +56 -0
- data/Gemfile +1 -1
- data/LICENSE.txt +2 -1
- data/README.md +13 -2
- data/SECURITY.md +16 -0
- data/bin/capify +19 -18
- data/docs/lib-codebase-map.md +11 -9
- data/lib/minestrone/configuration/actions/file_transfer.rb +2 -0
- data/lib/minestrone/configuration/variables.rb +21 -0
- data/lib/minestrone/recipes/deploy/assets.rb +11 -14
- data/lib/minestrone/recipes/deploy/bundler.rb +6 -6
- data/lib/minestrone/recipes/deploy.rb +44 -170
- data/lib/minestrone/version.rb +1 -1
- data/minestrone.gemspec +27 -15
- data/test/configuration/actions/file_transfer_test.rb +6 -0
- data/test/configuration/variables_test.rb +54 -0
- metadata +42 -69
- data/lib/minestrone/recipes/templates/maintenance.rhtml +0 -53
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e3c8964c359e7dabb2d3d14bd09a093d4d4bbabbb8ce75bf47e2949eb2e711ea
|
|
4
|
+
data.tar.gz: 8772884a6badaf622abc7b794c5dc971bbab040fc403537402cfade082014a66
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7c5aff5e3ac5ab932ac0d9f1adaf88b8fbdc646ee5056e219858a3c85574f90a60882aa35c9c38df1c293101eec28d91afbb844b2e9bb9cea13417ee12cebfd0
|
|
7
|
+
data.tar.gz: 587306f72ed2e29c81c29593e5a7cf7c765a184544b37fa94bbd5b45d0c1334bed073ed1928a38c539e737b220246c4506fa7ec8c06cfc044042ec8ca4a4a7af
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
## [0.0.3] - 2026-10-24
|
|
2
|
+
|
|
3
|
+
- updated `capify` script to generate an updated and simplified deploy config
|
|
4
|
+
- bumped up `net-ssh`, `net-scp` and `net-sftp` required versions
|
|
5
|
+
- bumped up required Ruby version to 3.3+
|
|
6
|
+
- `ed25519` and `bcrypt_pbkdf` don't need to be separately included in the Gemfile
|
|
7
|
+
|
|
8
|
+
## [0.0.2] - 2026-07-26
|
|
9
|
+
|
|
10
|
+
- added `upload_file` as an alias for `upload` (which in deploy tasks is shadowed by the `deploy:upload` task)
|
|
11
|
+
- added `append` & `remove` for adding/removing to array variables (from Capistrano 3)
|
|
12
|
+
- renamed `_cset` to `set_if_empty` and made it a public API (also from Capistrano 3)
|
|
13
|
+
- in migration and assets tasks, use `RACK_ENV` instead of `RAILS_ENV`, unless `rails_env` is explicitly defined (Rails also accepts `RACK_ENV`, but Sinatra/Rack doesn't accept `RAILS_ENV`)
|
|
14
|
+
- `:use_sudo` is now disabled by default
|
|
15
|
+
- renamed `version_dir` to `releases_dir` for consistency
|
|
16
|
+
- removed `:maintenance_basename`, `:maintenance_template_path` and the maintenance page tasks `deploy:web:disable` / `deploy:web:enable`
|
|
17
|
+
- removed `deploy:cold`, `deploy:start` and `deploy:stop` tasks
|
|
18
|
+
- removed `:normalize_asset_timestamps` and `:public_children`
|
|
19
|
+
|
|
20
|
+
## Minestrone [0.0.1] - 2026-05-25
|
|
21
|
+
|
|
22
|
+
Changes from Capistrano 2.15.11:
|
|
23
|
+
|
|
24
|
+
Removed:
|
|
25
|
+
|
|
26
|
+
* server roles, multiple servers and "primary" server designation – you only define a single server hostname and everything happens there (`server` method in the DSL only accepts a single string + options, `role` is gone)
|
|
27
|
+
* support for any parallel execution
|
|
28
|
+
* multiple stages
|
|
29
|
+
* SCM handlers other than `:git` and `:none`
|
|
30
|
+
* most deploy strategies – only `:remote_cache` and `:copy` are left
|
|
31
|
+
* support for SSH gateways
|
|
32
|
+
* password authentication for SSH and Git
|
|
33
|
+
* REPL shell
|
|
34
|
+
* code supporting ancient versions of Ruby, Rails or Rake, or very old Capistrano API
|
|
35
|
+
* Windows support code
|
|
36
|
+
|
|
37
|
+
Changed:
|
|
38
|
+
|
|
39
|
+
* project name
|
|
40
|
+
* default deploy path is `/var/www/#{application}`
|
|
41
|
+
* `deploy:cleanup` now runs automatically, with 5 last releases
|
|
42
|
+
* bumped up minimum Ruby version to 3.0
|
|
43
|
+
* various refactoring and formatting changes
|
|
44
|
+
|
|
45
|
+
Added:
|
|
46
|
+
|
|
47
|
+
* `ENV['SERVER']` for overriding the host the tasks run on (`HOSTS` still works, but only accepts one hostname)
|
|
48
|
+
* set up CI on GitHub
|
|
49
|
+
* added `frozen_string_literal` directives everywhere
|
|
50
|
+
* added `benchmark` and `logger` to dependencies in gemspec
|
|
51
|
+
* added `deploy/bundler` recipe for Bundler integration
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
## Capistrano 2.15.11 - 2023-06-17
|
|
55
|
+
|
|
56
|
+
Previous changelog available [here](https://github.com/capistrano/capistrano/blob/v2.15.11/CHANGELOG).
|
data/Gemfile
CHANGED
data/LICENSE.txt
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
MIT License (MIT)
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2012-2020 Tom Clements, Lee Hambley
|
|
4
3
|
Copyright (c) 2005-2007 Jamis Buck <jamis@37signals.com>
|
|
4
|
+
Copyright (c) 2012-2020 Tom Clements, Lee Hambley
|
|
5
|
+
Copyright (c) 2026 Jakub Suder
|
|
5
6
|
|
|
6
7
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
8
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
|
@@ -19,14 +19,25 @@ Minestrone is a tool for deploying Ruby applications to a server, based on the c
|
|
|
19
19
|
* REPL shell
|
|
20
20
|
* legacy SCMs – only `:git` and `:none` are left
|
|
21
21
|
* most deploy strategies – only `:remote_cache` and `:copy` are left
|
|
22
|
-
*
|
|
22
|
+
* maintenance page tasks
|
|
23
|
+
* normalizing asset timestamps
|
|
24
|
+
* `deploy:cold`, `deploy:start` and `deploy:stop` tasks
|
|
25
|
+
* any legacy/deprecated code from Capistrano 1.x era or for ancient versions of Ruby or Rails
|
|
23
26
|
|
|
24
27
|
|
|
25
28
|
### Other API changes
|
|
26
29
|
|
|
27
30
|
* default deploy path is `/var/www/#{application}`
|
|
28
31
|
* `server` method in the DSL only accepts a single string + options
|
|
29
|
-
*
|
|
32
|
+
* `:use_sudo` is false by default
|
|
33
|
+
* `deploy:cleanup` runs automatically, with 5 last releases
|
|
34
|
+
* `deploy/bundler` recipe handles Bundler integration
|
|
35
|
+
* migration & asset tasks set a `RACK_ENV` instead of `RAILS_ENV` (which Rails also accepts), unless `:rails_env` is explicitly defined
|
|
36
|
+
* added `upload_file` as alias for `upload`
|
|
37
|
+
* added `append` and `remove` for adding/removing items from array variables
|
|
38
|
+
* renamed `_cset` to `set_if_empty`
|
|
39
|
+
* Ruby 3.3+ is required
|
|
40
|
+
* `ed25519` and `bcrypt_pbkdf` don't need to be separately included in the Gemfile
|
|
30
41
|
|
|
31
42
|
|
|
32
43
|
### Project status
|
data/SECURITY.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## How To Report a Vulnerability
|
|
4
|
+
|
|
5
|
+
If you find a potential vulnerability in one of my projects, it's recommended not to report it through a standard publicly-readable issue report, in order to avoid giving possible clues to any potential attackers who could abuse it before it's fixed (see: ["Just a rumour of a bug is enough to find a security exploit these days"](https://anil.recoil.org/notes/rumour-is-the-exploit)).
|
|
6
|
+
|
|
7
|
+
You can use one of these to contact me instead:
|
|
8
|
+
|
|
9
|
+
- [@mackuba.eu](https://bsky.app/profile/did:plc:oio4hkxaop4ao4wz2pp3f4cr) on Bluesky (my DMs should be open, or mention me discretely with a request for contact)
|
|
10
|
+
- [@mackuba@martianbase.net](https://martianbase.net/@mackuba) on Mastodon (my personal instance)
|
|
11
|
+
- email: mackuba `@` protonmail.ch (optionally with [this PGP key](https://mail-api.proton.me/pks/lookup?op=get&search=mackuba@protonmail.ch))
|
|
12
|
+
- ["Report a vulnerability"](https://github.com/mackuba/minestrone/security/advisories/new) form on GitHub
|
|
13
|
+
|
|
14
|
+
I do not check my Twitter/X or LinkedIn accounts regularly.
|
|
15
|
+
|
|
16
|
+
Note: please don't submit AI-reported issues that have not been verified manually :)
|
data/bin/capify
CHANGED
|
@@ -32,39 +32,40 @@ end
|
|
|
32
32
|
|
|
33
33
|
def unindent(string)
|
|
34
34
|
indentation = string[/\A\s*/]
|
|
35
|
-
string.strip.gsub(/^#{indentation}/, "")
|
|
35
|
+
string.strip.gsub(/^#{indentation}/, "") + "\n"
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
files = {
|
|
39
39
|
"Capfile" => unindent(<<-FILE),
|
|
40
|
-
|
|
41
40
|
load 'deploy'
|
|
42
41
|
load 'deploy/bundler'
|
|
43
42
|
|
|
44
|
-
# Uncomment if you are using Rails
|
|
43
|
+
# Uncomment if you are using Rails asset pipeline
|
|
45
44
|
# load 'deploy/assets'
|
|
46
45
|
|
|
47
46
|
load 'config/deploy'
|
|
48
47
|
FILE
|
|
49
48
|
|
|
50
|
-
"config/deploy.rb" =>
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
# set :scm, :git # :git is the default, or set :none to disable
|
|
49
|
+
"config/deploy.rb" => unindent(<<-FILE),
|
|
50
|
+
server "host.example.com"
|
|
54
51
|
|
|
55
|
-
|
|
52
|
+
set :application, "set your application name here"
|
|
53
|
+
set :repository, "set your git repository URL here"
|
|
56
54
|
|
|
57
|
-
# if
|
|
58
|
-
#
|
|
55
|
+
# customize if needed
|
|
56
|
+
# set :keep_releases, 5
|
|
57
|
+
# set :rake, "RACK_ENV=production bundle exec rake"
|
|
58
|
+
# append :shared_children, "data"
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
60
|
+
namespace :deploy do
|
|
61
|
+
task :restart do
|
|
62
|
+
# implement depending on the Ruby app server you use
|
|
63
|
+
# e.g. for Passenger:
|
|
64
|
+
# run "touch \#{current_path}/tmp/restart.txt"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
FILE
|
|
68
|
+
}
|
|
68
69
|
|
|
69
70
|
base = ARGV.shift
|
|
70
71
|
|
data/docs/lib-codebase-map.md
CHANGED
|
@@ -23,7 +23,7 @@ Built-in recipes live under `lib/minestrone/recipes`. The deploy recipe composes
|
|
|
23
23
|
| `lib/minestrone/cli/options.rb` | `Minestrone::CLI::Options` | Defines `OptionParser` switches, default config discovery, environment variable extraction, and simple value coercion for `-s` and `-S`. | Mixed into `CLI`; requires `optparse`; uses `Logger`, `Version`, `CLI.password_prompt` |
|
|
24
24
|
| `lib/minestrone/command.rb` | `Minestrone::Command` | Single-session remote command runner. Opens one SSH command channel, handles stdout/stderr callbacks, optional pty, environment injection, placeholder replacement, and remote command errors. | `errors`, `processable`, `Configuration.default_io_proc`, SSH session from `connections` |
|
|
25
25
|
| `lib/minestrone/configuration.rb` | `Minestrone::Configuration` | Central DSL object. Owns logger/debug/dry-run state, explicitly calls each included module's initialization hook, mixes in all configuration and action modules, and unblocks namespace method shadowing. | `logger`; all `configuration/*`; `configuration/actions/*` |
|
|
26
|
-
| `lib/minestrone/configuration/actions/file_transfer.rb` | `Minestrone::Configuration::Actions::FileTransfer` | Adds `put`, `get`, `upload`, `download`, and `transfer` DSL actions. Delegates actual work to `Minestrone::Transfer`. | `transfer`, `Connections#execute_on_server`, `Connections#session`, `run` |
|
|
26
|
+
| `lib/minestrone/configuration/actions/file_transfer.rb` | `Minestrone::Configuration::Actions::FileTransfer` | Adds `put`, `get`, `upload`/`upload_file`, `download`, and `transfer` DSL actions. `upload_file` avoids ambiguity with the `deploy:upload` task. Delegates actual work to `Minestrone::Transfer`. | `transfer`, `Connections#execute_on_server`, `Connections#session`, `run` |
|
|
27
27
|
| `lib/minestrone/configuration/actions/inspect.rb` | `Minestrone::Configuration::Actions::Inspect` | Adds `stream` and `capture` actions for running commands and consuming streamed or captured single-server output. | `errors`, `Invocation#invoke_command`, `sudo` |
|
|
28
28
|
| `lib/minestrone/configuration/actions/invocation.rb` | `Minestrone::Configuration::Actions::Invocation` | Adds `run`, `invoke_command`, `sudo`, command defaults, sudo prompt handling, and debug prompting. Converts DSL command calls into sequential `Command` execution. | `command`, `Servers#active_server`, `Connections#execute_on_server`, `CLI.debug_prompt`, `Variables` |
|
|
29
29
|
| `lib/minestrone/configuration/alias_task.rb` | `Minestrone::Configuration::AliasTask` | Adds `alias_task`, duplicating an existing task under a new name. | `Namespaces#find_task`, `#define_task`, `NoSuchTaskError` |
|
|
@@ -33,15 +33,16 @@ Built-in recipes live under `lib/minestrone/recipes`. The deploy recipe composes
|
|
|
33
33
|
| `lib/minestrone/configuration/loading.rb` | `Minestrone::Configuration::Loading`, `Loading::ClassMethods` | Loads recipes from files, strings, or procs. Provides a Minestrone-aware `require` that lets multiple configuration instances reload recipe DSL effects. | Used by `CLI`, recipes, extensions |
|
|
34
34
|
| `lib/minestrone/configuration/log_formatters.rb` | `Minestrone::Configuration::LogFormatters` | DSL for adding logger formatters and disabling formatting. | `logger` |
|
|
35
35
|
| `lib/minestrone/configuration/namespaces.rb` | `Minestrone::Configuration::Namespaces`, `Namespaces::Namespace`, `Kernel.method_added` hook | Implements `namespace`, `task`, `desc`, task lookup, namespace lookup, default tasks, and nested namespace forwarding to parent configuration. | `task_definition`, `alias_task`, `execution` |
|
|
36
|
-
| `lib/minestrone/configuration/servers.rb` | `Minestrone::Configuration::Servers` | Adds the single-host `server` DSL and resolves the configured server, with `
|
|
37
|
-
| `lib/minestrone/configuration/variables.rb` | `Minestrone::Configuration::Variables` | Configuration variables with lazy proc evaluation, reset/unset, `fetch`, `[]`, and variable-backed `method_missing`. | Used by nearly every DSL and recipe file |
|
|
36
|
+
| `lib/minestrone/configuration/servers.rb` | `Minestrone::Configuration::Servers` | Adds the single-host `server` DSL and resolves the configured server, with `SERVER` as the preferred environment override and `HOSTS` as a compatibility fallback. | `ServerDefinition`, `errors` |
|
|
37
|
+
| `lib/minestrone/configuration/variables.rb` | `Minestrone::Configuration::Variables` | Configuration variables with lazy proc evaluation, conditional defaults through `set_if_empty`, array updates through `append`/`remove`, reset/unset, `fetch`, `[]`, and variable-backed `method_missing`. | Used by nearly every DSL and recipe file |
|
|
38
38
|
| `lib/minestrone/errors.rb` | `Minestrone::Error`, `CaptureError`, `NoSuchTaskError`, `NoMatchingServersError`, `RemoteError`, `ConnectionError`, `TransferError`, `CommandError`, `LocalArgumentError` | Shared exception hierarchy. Remote errors carry affected hosts. | Used by command, transfer, connections, execution, recipes, deploy adapters |
|
|
39
39
|
| `lib/minestrone/ext/string.rb` | reopens `String` | Adds `String#compact`, collapsing whitespace. Used to make heredoc shell commands one line. | Used by deploy assets and recipe command heredocs |
|
|
40
40
|
| `lib/minestrone/extensions.rb` | `Minestrone::ExtensionProxy`, `Minestrone::EXTENSIONS`, plugin methods | Plugin registration system. Adds proxy methods to `Configuration` instances and delegates unknown plugin method calls back to the configuration. | `Configuration`, `Error` |
|
|
41
41
|
| `lib/minestrone/logger.rb` | `Minestrone::Logger` | Level-based logger with TTY color/style formatters, timestamp/prepend/append/replace support, and default formatter registration. | Used by `Configuration`, CLI options, command/transfer/strategy/scm code |
|
|
42
42
|
| `lib/minestrone/processable.rb` | `Minestrone::Processable`, `Processable::SessionAssociation` | Shared single-session Net::SSH event loop helper. Preprocesses/postprocesses the session with `IO.select` and associates raised errors with that session. | Included by `Command`, `Transfer` |
|
|
43
|
-
| `lib/minestrone/recipes/deploy.rb` | recipe methods and tasks only | Primary deployment recipe. Defines deploy
|
|
43
|
+
| `lib/minestrone/recipes/deploy.rb` | recipe methods and tasks only | Primary deployment recipe. Defines deploy defaults, helpers (`scm_default`, `depend`, `with_env`, `r_env`, `run_locally`, `try_sudo`, `try_runner`), and tasks for setup, update, update_code, symlinks, upload, restart hooks, rollback, migrations, cleanup, checks, and pending diff/log. Defaults to Git when `.git` exists and `none` otherwise. | `deploy/scm`, `deploy/strategy`, `dependencies`, `Command`/`Transfer` through configuration actions |
|
|
44
44
|
| `lib/minestrone/recipes/deploy/assets.rb` | recipe methods and tasks only | Rails asset-pipeline extension. Hooks into deploy lifecycle to symlink shared assets, precompile, maintain manifest mtimes, clean expired assets, clean all assets, and roll back manifests. | Loads `deploy`; `json`, `yaml` via deploy, `Set` via deploy, `String#compact`, callbacks/tasks/actions |
|
|
45
|
+
| `lib/minestrone/recipes/deploy/bundler.rb` | recipe methods and tasks only | Bundler integration. Configures bundle defaults, makes Rake run through Bundler, installs gems into the shared bundle path during deployment, and symlinks that path into each release. | Loads `deploy`; deploy variables, callbacks/tasks/actions |
|
|
45
46
|
| `lib/minestrone/recipes/deploy/dependencies.rb` | `Minestrone::Deploy::Dependencies` | Aggregates local and remote dependency checks and reports pass/fail. | `local_dependency`, `remote_dependency` |
|
|
46
47
|
| `lib/minestrone/recipes/deploy/local_dependency.rb` | `Minestrone::Deploy::LocalDependency` | Checks local command availability in `PATH`. | Used by `Dependencies`, `Strategy::Copy#check!` |
|
|
47
48
|
| `lib/minestrone/recipes/deploy/remote_dependency.rb` | `Minestrone::Deploy::RemoteDependency` | Checks remote directories, files, writability, commands, gems, deb/rpm packages, and expected command output. | `errors`, `Configuration#invoke_command`, `CommandError` |
|
|
@@ -54,12 +55,11 @@ Built-in recipes live under `lib/minestrone/recipes`. The deploy recipe composes
|
|
|
54
55
|
| `lib/minestrone/recipes/deploy/strategy/copy.rb` | `Minestrone::Deploy::Strategy::Copy`, `Copy::Compression` | Local-copy strategy. Checks out/export locally or refreshes a local cache, optionally builds, excludes files, archives, uploads, extracts remotely, and cleans staging artifacts. | `strategy/base`, `fileutils`, `tempfile`, `LocalDependency`, `FileTransfer#upload`, SCM local proxy |
|
|
55
56
|
| `lib/minestrone/recipes/deploy/strategy/remote_cache.rb` | `Minestrone::Deploy::Strategy::RemoteCache` | Remote strategy maintaining a shared cached checkout under `shared_path`, then copying/rsyncing it to each release. Handles SCM prompt filtering and writes `REVISION`. | `strategy/base`, SCM `sync`/`checkout`/`handle_data`, remote `rsync` when exclusions exist |
|
|
56
57
|
| `lib/minestrone/recipes/standard.rb` | recipe tasks only | Standard recipe loaded by CLI. Defines `invoke` for one-off remote commands. | `configuration/actions/invocation` |
|
|
57
|
-
| `lib/minestrone/recipes/templates/maintenance.rhtml` | none | ERB/XHTML maintenance-page template used by `deploy:web:disable`. | Read by `recipes/deploy.rb` |
|
|
58
58
|
| `lib/minestrone/server_definition.rb` | `Minestrone::ServerDefinition` | Parses and stores `user@host:port` plus server options. Provides comparison, equality/hash, default user, and string rendering. | Used by `Servers`, `SSH`, `Connections` |
|
|
59
59
|
| `lib/minestrone/ssh.rb` | `Minestrone::SSH`, `SSH::Server` | SSH connection helper. Applies the originating `ServerDefinition` to the Net::SSH session and builds public-key-only connection options. | `net/ssh`, `ServerDefinition` |
|
|
60
60
|
| `lib/minestrone/task_definition.rb` | `Minestrone::TaskDefinition` | Stores task metadata: name, namespace, options, body, description, and rollback behavior. Formats descriptions and computes fully qualified names. | `server_definition`; used by `configuration/namespaces` and `execution` |
|
|
61
61
|
| `lib/minestrone/transfer.rb` | `Minestrone::Transfer`, `Transfer::SFTPTransferWrapper` | Single-session upload/download engine over SFTP or SCP. Normalizes host placeholders and IOs, tracks transfer failure, delegates event processing to `Processable`, and raises `TransferError`. | `net/scp`, `net/sftp`, `processable`, `errors`, SSH session |
|
|
62
|
-
| `lib/minestrone/version.rb` | `Minestrone::Version`, `Minestrone::VERSION` | Version constants and string rendering for Minestrone
|
|
62
|
+
| `lib/minestrone/version.rb` | `Minestrone::Version`, `Minestrone::VERSION` | Version constants and string rendering for Minestrone 0.0.2. | Used by CLI `--version` |
|
|
63
63
|
|
|
64
64
|
## Dependency Graph
|
|
65
65
|
|
|
@@ -105,6 +105,7 @@ flowchart TD
|
|
|
105
105
|
deploy_recipe --> strategy_factory["Deploy::Strategy factory"]
|
|
106
106
|
deploy_recipe --> config
|
|
107
107
|
assets_recipe["recipes/deploy/assets.rb"] --> deploy_recipe
|
|
108
|
+
bundler_recipe["recipes/deploy/bundler.rb"] --> deploy_recipe
|
|
108
109
|
|
|
109
110
|
scm_factory --> scm_base["SCM::Base"]
|
|
110
111
|
scm_base --> scm_adapters["Git, None"]
|
|
@@ -137,7 +138,8 @@ These are the code-level edges visible from `require` and `load`, excluding Ruby
|
|
|
137
138
|
| `lib/minestrone/configuration/namespaces.rb` | `minestrone/configuration/alias_task`, `minestrone/task_definition` |
|
|
138
139
|
| `lib/minestrone/configuration/servers.rb` | `minestrone/server_definition`, `minestrone/errors` |
|
|
139
140
|
| `lib/minestrone/recipes/deploy.rb` | `minestrone/recipes/deploy/scm`, `minestrone/recipes/deploy/strategy` |
|
|
140
|
-
| `lib/minestrone/recipes/deploy/assets.rb` | `load 'deploy'` unless `
|
|
141
|
+
| `lib/minestrone/recipes/deploy/assets.rb` | `load 'deploy'` unless the `try_sudo` deploy helper already exists |
|
|
142
|
+
| `lib/minestrone/recipes/deploy/bundler.rb` | `load 'deploy'` unless the `try_sudo` deploy helper already exists |
|
|
141
143
|
| `lib/minestrone/recipes/deploy/dependencies.rb` | `minestrone/recipes/deploy/local_dependency`, `minestrone/recipes/deploy/remote_dependency` |
|
|
142
144
|
| `lib/minestrone/recipes/deploy/remote_dependency.rb` | `minestrone/errors` |
|
|
143
145
|
| `lib/minestrone/recipes/deploy/scm.rb` | dynamically `minestrone/recipes/deploy/scm/<name>` |
|
|
@@ -154,9 +156,9 @@ These are the code-level edges visible from `require` and `load`, excluding Ruby
|
|
|
154
156
|
|
|
155
157
|
- `Configuration` is the central dependency hub. Most recipe and strategy code calls into it through DSL methods mixed in from its modules.
|
|
156
158
|
- `Command` and `Transfer` depend on `Processable` because they share the same single-session Net::SSH event-loop pattern.
|
|
157
|
-
- `ServerDefinition` is the single configured server identity object. It carries host/user/port/options into the `
|
|
159
|
+
- `ServerDefinition` is the single configured server identity object. It carries host/user/port/options into the `SERVER`/`HOSTS` override path, SSH connection setup, command placeholders, transfer logging, and error reporting.
|
|
158
160
|
- `Callbacks` wraps `Execution#invoke_task_directly`; task lifecycle hooks therefore apply to all direct task execution paths, including CLI actions and recipe-invoked task aliases.
|
|
159
161
|
- `Deploy::SCM` and `Deploy::Strategy` are factories. They load adapter files by name and instantiate classes from generated constant names.
|
|
160
162
|
- SCM adapters generally do not execute commands. They return shell command strings and prompt handlers. Strategies decide whether those commands run locally, remotely, through caches, or through uploaded archives.
|
|
161
163
|
- `Strategy::Copy` is the main bridge from local SCM commands to remote deployment: it uses the SCM's local proxy, local filesystem staging, compression utilities, `upload`, and remote decompression.
|
|
162
|
-
- `recipes/deploy/assets.rb`
|
|
164
|
+
- `recipes/deploy/assets.rb` and `recipes/deploy/bundler.rb` are not class extensions. They are recipes that mutate the current configuration by setting defaults, registering callbacks, adding helper methods, and defining deployment tasks.
|
|
@@ -36,6 +36,13 @@ module Minestrone
|
|
|
36
36
|
|
|
37
37
|
alias :[]= :set
|
|
38
38
|
|
|
39
|
+
# Sets a variable only when it has not already been defined. Existing
|
|
40
|
+
# values, including nil and false, are preserved. Accepts either a value
|
|
41
|
+
# or a block, following the same rules as #set.
|
|
42
|
+
def set_if_empty(variable, *args, &block)
|
|
43
|
+
set(variable, *args, &block) unless exists?(variable)
|
|
44
|
+
end
|
|
45
|
+
|
|
39
46
|
# Removes any trace of the given variable.
|
|
40
47
|
def unset(variable)
|
|
41
48
|
sym = variable.to_sym
|
|
@@ -43,6 +50,20 @@ module Minestrone
|
|
|
43
50
|
@variables.delete(sym)
|
|
44
51
|
end
|
|
45
52
|
|
|
53
|
+
# Appends one or more values to an array variable. Missing variables are
|
|
54
|
+
# treated as empty arrays, and existing scalar values are wrapped in an
|
|
55
|
+
# array before the new values are appended.
|
|
56
|
+
def append(variable, *values)
|
|
57
|
+
set(variable, Array(fetch(variable, [])).concat(values))
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Removes all occurrences of the given values from an array variable.
|
|
61
|
+
# Missing variables are treated as empty arrays, and existing scalar
|
|
62
|
+
# values are wrapped in an array before removal.
|
|
63
|
+
def remove(variable, *values)
|
|
64
|
+
set(variable, Array(fetch(variable, [])) - values)
|
|
65
|
+
end
|
|
66
|
+
|
|
46
67
|
# Returns true if the variable has been defined, and false otherwise.
|
|
47
68
|
def exists?(variable)
|
|
48
69
|
@variables.key?(variable.to_sym)
|
|
@@ -2,15 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
require 'json'
|
|
4
4
|
|
|
5
|
-
load 'deploy' unless defined?(
|
|
5
|
+
load 'deploy' unless defined?(try_sudo)
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
_cset :normalize_asset_timestamps, false
|
|
7
|
+
set_if_empty :asset_env, "RAILS_GROUPS=assets"
|
|
8
|
+
set_if_empty :assets_prefix, "assets"
|
|
9
|
+
set_if_empty :shared_assets_prefix, "assets"
|
|
10
|
+
set_if_empty :expire_assets_after, (3600 * 24 * 7)
|
|
11
|
+
set_if_empty(:asset_manifest_prefix) { (`sprockets -v`.chomp < "3.0" ? "manifest" : ".sprockets-manifest") rescue "manifest" }
|
|
14
12
|
|
|
15
13
|
before 'deploy:finalize_update', 'deploy:assets:symlink'
|
|
16
14
|
after 'deploy:update_code', 'deploy:assets:precompile'
|
|
@@ -57,13 +55,12 @@ namespace :deploy do
|
|
|
57
55
|
asset_env variable. The defaults are:
|
|
58
56
|
|
|
59
57
|
set :rake, "rake"
|
|
60
|
-
set :
|
|
58
|
+
set :rack_env, "production"
|
|
61
59
|
set :asset_env, "RAILS_GROUPS=assets"
|
|
62
60
|
DESC
|
|
63
61
|
task :precompile do
|
|
64
62
|
run <<-CMD.compact
|
|
65
|
-
cd -- #{latest_release} &&
|
|
66
|
-
RAILS_ENV=#{rails_env.to_s.shellescape} #{asset_env} #{rake} assets:precompile
|
|
63
|
+
cd -- #{latest_release} && #{r_env} #{asset_env} #{rake} assets:precompile
|
|
67
64
|
CMD
|
|
68
65
|
|
|
69
66
|
if capture("ls -1 #{shared_path.shellescape}/#{shared_assets_prefix}/#{asset_manifest_prefix}* | wc -l").to_i > 1
|
|
@@ -112,11 +109,11 @@ namespace :deploy do
|
|
|
112
109
|
asset_env variable. The defaults are:
|
|
113
110
|
|
|
114
111
|
set :rake, "rake"
|
|
115
|
-
set :
|
|
112
|
+
set :rack_env, "production"
|
|
116
113
|
set :asset_env, "RAILS_GROUPS=assets"
|
|
117
114
|
DESC
|
|
118
115
|
task :clean do
|
|
119
|
-
run "cd #{latest_release} && #{rake}
|
|
116
|
+
run "cd #{latest_release} && #{rake} #{r_env} #{asset_env} assets:clean"
|
|
120
117
|
end
|
|
121
118
|
|
|
122
119
|
desc <<-DESC
|
|
@@ -186,7 +183,7 @@ namespace :deploy do
|
|
|
186
183
|
run <<-CMD.compact
|
|
187
184
|
cd -- #{previous_release.shellescape} &&
|
|
188
185
|
cp -f -- #{previous_manifest.shellescape} #{restored_manifest_path.shellescape} &&
|
|
189
|
-
[ -z "$(#{rake} -P | grep assets:precompile:nondigest)" ] || #{rake}
|
|
186
|
+
[ -z "$(#{rake} -P | grep assets:precompile:nondigest)" ] || #{rake} #{r_env} #{asset_env} assets:precompile:nondigest
|
|
190
187
|
CMD
|
|
191
188
|
end
|
|
192
189
|
end
|
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
# https://github.com/ruby/rubygems/blob/master/bundler/lib/bundler/minestrone.rb
|
|
5
5
|
# and https://github.com/minestrone/bundler
|
|
6
6
|
|
|
7
|
-
load 'deploy' unless defined?(
|
|
7
|
+
load 'deploy' unless defined?(try_sudo)
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
set_if_empty :bundle_env, ''
|
|
10
|
+
set_if_empty :bundle_cmd, 'bundle'
|
|
11
|
+
set_if_empty(:bundle_path) { "#{shared_path}/bundle" }
|
|
12
|
+
set_if_empty :bundle_without, [:development, :test]
|
|
13
|
+
set_if_empty :bundle_flags, '--quiet'
|
|
14
14
|
|
|
15
15
|
set(:rake) { "#{bundle_cmd} exec rake" }
|
|
16
16
|
|
|
@@ -7,35 +7,29 @@ require "yaml"
|
|
|
7
7
|
require "minestrone/recipes/deploy/scm"
|
|
8
8
|
require "minestrone/recipes/deploy/strategy"
|
|
9
9
|
|
|
10
|
-
def _cset(name, *args, &block)
|
|
11
|
-
unless exists?(name)
|
|
12
|
-
set(name, *args, &block)
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
10
|
# =========================================================================
|
|
17
11
|
# These variables MUST be set in the client capfiles. If they are not set,
|
|
18
12
|
# the deploy will fail with an error.
|
|
19
13
|
# =========================================================================
|
|
20
14
|
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
set_if_empty(:application) { abort "Please specify the name of your application, set :application, 'foo'" }
|
|
16
|
+
set_if_empty(:repository) { abort "Please specify the repository that houses your application's code, set :repository, 'foo'" }
|
|
23
17
|
|
|
24
18
|
# =========================================================================
|
|
25
19
|
# These variables may be set in the client capfile if their default values
|
|
26
20
|
# are not sufficient.
|
|
27
21
|
# =========================================================================
|
|
28
22
|
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
set_if_empty(:scm) { scm_default }
|
|
24
|
+
set_if_empty :deploy_via, :remote_cache
|
|
31
25
|
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
set_if_empty(:deploy_to) { "/var/www/#{application}" }
|
|
27
|
+
set_if_empty(:revision) { source.head }
|
|
34
28
|
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
set_if_empty :rack_env, "production"
|
|
30
|
+
set_if_empty :rake, "rake"
|
|
37
31
|
|
|
38
|
-
|
|
32
|
+
set_if_empty :keep_releases, 5
|
|
39
33
|
|
|
40
34
|
# =========================================================================
|
|
41
35
|
# These variables should NOT be changed unless you are very confident in
|
|
@@ -43,43 +37,40 @@ _cset :keep_releases, 5
|
|
|
43
37
|
# changes if you do decide to muck with these!
|
|
44
38
|
# =========================================================================
|
|
45
39
|
|
|
46
|
-
|
|
47
|
-
|
|
40
|
+
set_if_empty(:source) { Minestrone::Deploy::SCM.new(scm, self) }
|
|
41
|
+
set_if_empty(:real_revision) { source.local.query_revision(revision) { |cmd| with_env("LC_ALL", "C") { run_locally(cmd) } } }
|
|
48
42
|
|
|
49
|
-
|
|
43
|
+
set_if_empty(:strategy) { Minestrone::Deploy::Strategy.new(deploy_via, self) }
|
|
50
44
|
|
|
51
45
|
# If overriding release name, please also select an appropriate setting for :releases below.
|
|
52
|
-
|
|
46
|
+
set_if_empty(:release_name) { set :deploy_timestamped, true; Time.now.utc.strftime("%Y%m%d%H%M%S") }
|
|
53
47
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
48
|
+
set_if_empty :releases_dir, "releases"
|
|
49
|
+
set_if_empty :shared_dir, "shared"
|
|
50
|
+
set_if_empty :shared_children, %w(public/system log tmp/pids)
|
|
51
|
+
set_if_empty :current_dir, "current"
|
|
58
52
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
53
|
+
set_if_empty(:releases_path) { File.join(deploy_to, releases_dir) }
|
|
54
|
+
set_if_empty(:shared_path) { File.join(deploy_to, shared_dir) }
|
|
55
|
+
set_if_empty(:current_path) { File.join(deploy_to, current_dir) }
|
|
56
|
+
set_if_empty(:release_path) { File.join(releases_path, release_name) }
|
|
63
57
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
58
|
+
set_if_empty(:releases) { capture("#{try_sudo} ls -x #{releases_path}").split.sort }
|
|
59
|
+
set_if_empty(:current_release) { releases.length > 0 ? File.join(releases_path, releases.last) : nil }
|
|
60
|
+
set_if_empty(:previous_release) { releases.length > 1 ? File.join(releases_path, releases[-2]) : nil }
|
|
67
61
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
62
|
+
set_if_empty(:current_revision) { capture("#{try_sudo} cat #{current_path}/REVISION").chomp }
|
|
63
|
+
set_if_empty(:latest_revision) { capture("#{try_sudo} cat #{current_release}/REVISION").chomp }
|
|
64
|
+
set_if_empty(:previous_revision) { capture("#{try_sudo} cat #{previous_release}/REVISION").chomp if previous_release }
|
|
71
65
|
|
|
72
|
-
|
|
66
|
+
set_if_empty(:run_method) { fetch(:use_sudo, false) ? :sudo : :run }
|
|
73
67
|
|
|
74
68
|
# some tasks, like symlink, need to always point at the latest release, but
|
|
75
69
|
# they can also (occassionally) be called standalone. In the standalone case,
|
|
76
70
|
# the timestamped release_path will be inaccurate, since the directory won't
|
|
77
71
|
# actually exist. This variable lets tasks like symlink work either in the
|
|
78
72
|
# standalone case, or during deployment.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
_cset :maintenance_basename, "maintenance"
|
|
82
|
-
_cset(:maintenance_template_path) { File.join(__dir__, "templates", "maintenance.rhtml") }
|
|
73
|
+
set_if_empty(:latest_release) { exists?(:deploy_timestamped) ? release_path : current_release }
|
|
83
74
|
|
|
84
75
|
# =========================================================================
|
|
85
76
|
# These are helper methods that will be available to your recipes.
|
|
@@ -109,6 +100,15 @@ ensure
|
|
|
109
100
|
ENV[name] = saved
|
|
110
101
|
end
|
|
111
102
|
|
|
103
|
+
def r_env
|
|
104
|
+
if rails_env = fetch(:rails_env, nil)
|
|
105
|
+
"RAILS_ENV=#{rails_env.to_s.shellescape}"
|
|
106
|
+
else
|
|
107
|
+
rack_env = fetch(:rack_env, "production")
|
|
108
|
+
"RACK_ENV=#{rack_env.to_s.shellescape}"
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
112
|
# Logs the command then executes it locally. Returns the command output as a string.
|
|
113
113
|
def run_locally(cmd)
|
|
114
114
|
if dry_run
|
|
@@ -179,10 +179,7 @@ end
|
|
|
179
179
|
|
|
180
180
|
namespace :deploy do
|
|
181
181
|
desc <<-DESC
|
|
182
|
-
Deploys your project. This calls both `update' and `restart'.
|
|
183
|
-
this will generally only work for applications that have already been deployed \
|
|
184
|
-
once. For a "cold" deploy, you'll want to take a look at the `deploy:cold' \
|
|
185
|
-
task, which handles the cold start specifically.
|
|
182
|
+
Deploys your project. This calls both `update' and `restart'.
|
|
186
183
|
DESC
|
|
187
184
|
|
|
188
185
|
task :default do
|
|
@@ -253,14 +250,9 @@ namespace :deploy do
|
|
|
253
250
|
task with your own environment's requirements.
|
|
254
251
|
|
|
255
252
|
This task will make the release group-writable (if the :group_writable \
|
|
256
|
-
variable is set to true, which is the default)
|
|
253
|
+
variable is set to true, which is the default) and will set up \
|
|
257
254
|
symlinks to the shared directory for the log, system, and tmp/pids \
|
|
258
|
-
directories
|
|
259
|
-
public/stylesheets, and public/javascripts so that the times are \
|
|
260
|
-
consistent (so that asset timestamping works). This touch process \
|
|
261
|
-
is only carried out if the :normalize_asset_timestamps variable is \
|
|
262
|
-
set to true, which is the default. The asset directories can be overridden \
|
|
263
|
-
using the :public_children variable.
|
|
255
|
+
directories.
|
|
264
256
|
DESC
|
|
265
257
|
|
|
266
258
|
task :finalize_update do
|
|
@@ -286,18 +278,6 @@ namespace :deploy do
|
|
|
286
278
|
end
|
|
287
279
|
|
|
288
280
|
run commands.join(' && ') if commands.any?
|
|
289
|
-
|
|
290
|
-
if fetch(:normalize_asset_timestamps, true)
|
|
291
|
-
stamp = Time.now.utc.strftime("%Y%m%d%H%M.%S")
|
|
292
|
-
|
|
293
|
-
asset_paths = fetch(:public_children, %w(images stylesheets javascripts)).
|
|
294
|
-
map { |p| "#{latest_release}/public/#{p}" }.
|
|
295
|
-
map { |p| p.shellescape }
|
|
296
|
-
|
|
297
|
-
if asset_paths.any?
|
|
298
|
-
run("find #{asset_paths.join(" ")} -exec touch -t #{stamp} -- {} ';'; true", :env => { "TZ" => "UTC" })
|
|
299
|
-
end
|
|
300
|
-
end
|
|
301
281
|
end
|
|
302
282
|
|
|
303
283
|
desc <<-DESC
|
|
@@ -418,14 +398,13 @@ namespace :deploy do
|
|
|
418
398
|
rake executable by setting the rake variable. The defaults are:
|
|
419
399
|
|
|
420
400
|
set :rake, "rake"
|
|
421
|
-
set :
|
|
401
|
+
set :rack_env, "production"
|
|
422
402
|
set :migrate_env, ""
|
|
423
403
|
set :migrate_target, :latest
|
|
424
404
|
DESC
|
|
425
405
|
|
|
426
406
|
task :migrate do
|
|
427
407
|
rake = fetch(:rake, "rake")
|
|
428
|
-
rails_env = fetch(:rails_env, "production")
|
|
429
408
|
migrate_env = fetch(:migrate_env, "")
|
|
430
409
|
migrate_target = fetch(:migrate_target, :latest)
|
|
431
410
|
|
|
@@ -435,7 +414,7 @@ namespace :deploy do
|
|
|
435
414
|
else raise ArgumentError, "unknown migration target #{migrate_target.inspect}"
|
|
436
415
|
end
|
|
437
416
|
|
|
438
|
-
run "cd #{directory} && #{
|
|
417
|
+
run "cd #{directory} && #{r_env} #{migrate_env} #{rake} db:migrate"
|
|
439
418
|
end
|
|
440
419
|
|
|
441
420
|
desc <<-DESC
|
|
@@ -458,9 +437,7 @@ namespace :deploy do
|
|
|
458
437
|
desc <<-DESC
|
|
459
438
|
Clean up old releases. By default, the last 5 releases are kept on each \
|
|
460
439
|
server (though you can change this with the keep_releases variable). All \
|
|
461
|
-
other deployed revisions are removed from the server.
|
|
462
|
-
will use sudo to clean up the old releases, but if sudo is not available \
|
|
463
|
-
for your environment, set the :use_sudo variable to false instead.
|
|
440
|
+
other deployed revisions are removed from the server.
|
|
464
441
|
DESC
|
|
465
442
|
|
|
466
443
|
task :cleanup do
|
|
@@ -511,38 +488,6 @@ namespace :deploy do
|
|
|
511
488
|
end
|
|
512
489
|
end
|
|
513
490
|
|
|
514
|
-
desc <<-DESC
|
|
515
|
-
Deploys and starts a `cold' application. This is useful if you have not \
|
|
516
|
-
deployed your application before, or if your application is (for some \
|
|
517
|
-
other reason) not currently running. It will deploy the code, run any \
|
|
518
|
-
pending migrations, and then instead of invoking `deploy:restart', it will \
|
|
519
|
-
invoke `deploy:start' to fire up the application servers.
|
|
520
|
-
DESC
|
|
521
|
-
|
|
522
|
-
task :cold do
|
|
523
|
-
update
|
|
524
|
-
migrate
|
|
525
|
-
start
|
|
526
|
-
end
|
|
527
|
-
|
|
528
|
-
desc <<-DESC
|
|
529
|
-
Blank task exists as a hook into which to install your own environment \
|
|
530
|
-
specific behaviour.
|
|
531
|
-
DESC
|
|
532
|
-
|
|
533
|
-
task :start do
|
|
534
|
-
# Empty Task to overload with your platform specifics
|
|
535
|
-
end
|
|
536
|
-
|
|
537
|
-
desc <<-DESC
|
|
538
|
-
Blank task exists as a hook into which to install your own environment \
|
|
539
|
-
specific behaviour.
|
|
540
|
-
DESC
|
|
541
|
-
|
|
542
|
-
task :stop do
|
|
543
|
-
# Empty Task to overload with your platform specifics
|
|
544
|
-
end
|
|
545
|
-
|
|
546
491
|
namespace :pending do
|
|
547
492
|
desc <<-DESC
|
|
548
493
|
Displays the `diff' since your last deploy. This is useful if you want \
|
|
@@ -565,75 +510,4 @@ namespace :deploy do
|
|
|
565
510
|
system(source.local.log(from))
|
|
566
511
|
end
|
|
567
512
|
end
|
|
568
|
-
|
|
569
|
-
namespace :web do
|
|
570
|
-
desc <<-DESC
|
|
571
|
-
Present a maintenance page to visitors. Disables your application's web \
|
|
572
|
-
interface by writing a "#{maintenance_basename}.html" file to the web server. The \
|
|
573
|
-
server must be configured to detect the presence of this file, and if \
|
|
574
|
-
it is present, always display it instead of performing the request.
|
|
575
|
-
|
|
576
|
-
By default, the maintenance page will just say the site is down for \
|
|
577
|
-
"maintenance", and will be back "shortly", but you can customize the \
|
|
578
|
-
page by specifying the REASON and UNTIL environment variables:
|
|
579
|
-
|
|
580
|
-
$ min deploy:web:disable \\
|
|
581
|
-
REASON="hardware upgrade" \\
|
|
582
|
-
UNTIL="12pm Central Time"
|
|
583
|
-
|
|
584
|
-
You can use a different template for the maintenance page by setting the \
|
|
585
|
-
:maintenance_template_path variable in your deploy.rb file. The template file \
|
|
586
|
-
should either be a plaintext or an erb file.
|
|
587
|
-
|
|
588
|
-
Further customization will require that you write your own task.
|
|
589
|
-
DESC
|
|
590
|
-
|
|
591
|
-
task :disable do
|
|
592
|
-
require 'erb'
|
|
593
|
-
on_rollback { run "rm -f #{shared_path}/system/#{maintenance_basename}.html" }
|
|
594
|
-
|
|
595
|
-
warn <<-EOHTACCESS
|
|
596
|
-
|
|
597
|
-
# Please add something like this to your site's Apache htaccess to redirect users to the maintenance page.
|
|
598
|
-
# More Info: http://www.shiftcommathree.com/articles/make-your-rails-maintenance-page-respond-with-a-503
|
|
599
|
-
|
|
600
|
-
ErrorDocument 503 /system/#{maintenance_basename}.html
|
|
601
|
-
RewriteEngine On
|
|
602
|
-
RewriteCond %{REQUEST_URI} !\.(css|gif|jpg|png)$
|
|
603
|
-
RewriteCond %{DOCUMENT_ROOT}/system/#{maintenance_basename}.html -f
|
|
604
|
-
RewriteCond %{SCRIPT_FILENAME} !#{maintenance_basename}.html
|
|
605
|
-
RewriteRule ^.*$ - [redirect=503,last]
|
|
606
|
-
|
|
607
|
-
# Or if you are using Nginx add this to your server config:
|
|
608
|
-
|
|
609
|
-
if (-f $document_root/system/maintenance.html) {
|
|
610
|
-
return 503;
|
|
611
|
-
}
|
|
612
|
-
error_page 503 @maintenance;
|
|
613
|
-
location @maintenance {
|
|
614
|
-
rewrite ^(.*)$ /system/maintenance.html break;
|
|
615
|
-
break;
|
|
616
|
-
}
|
|
617
|
-
EOHTACCESS
|
|
618
|
-
|
|
619
|
-
reason = ENV['REASON']
|
|
620
|
-
deadline = ENV['UNTIL']
|
|
621
|
-
|
|
622
|
-
template = File.read(maintenance_template_path)
|
|
623
|
-
result = ERB.new(template).result(binding)
|
|
624
|
-
|
|
625
|
-
put result, "#{shared_path}/system/#{maintenance_basename}.html", :mode => 0644
|
|
626
|
-
end
|
|
627
|
-
|
|
628
|
-
desc <<-DESC
|
|
629
|
-
Makes the application web-accessible again. Removes the \
|
|
630
|
-
"#{maintenance_basename}.html" page generated by deploy:web:disable, which (if your \
|
|
631
|
-
web server is configured correctly) will make your application \
|
|
632
|
-
web-accessible again.
|
|
633
|
-
DESC
|
|
634
|
-
|
|
635
|
-
task :enable do
|
|
636
|
-
run "rm -f #{shared_path}/system/#{maintenance_basename}.html"
|
|
637
|
-
end
|
|
638
|
-
end
|
|
639
513
|
end
|
data/lib/minestrone/version.rb
CHANGED
data/minestrone.gemspec
CHANGED
|
@@ -1,32 +1,44 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
require "minestrone/version"
|
|
3
|
+
require_relative 'lib/minestrone/version'
|
|
5
4
|
|
|
6
5
|
Gem::Specification.new do |spec|
|
|
7
6
|
spec.name = "minestrone"
|
|
8
7
|
spec.version = Minestrone::Version.to_s
|
|
9
8
|
spec.platform = Gem::Platform::RUBY
|
|
10
9
|
spec.authors = ["Jamis Buck", "Lee Hambley", "Kuba Suder"]
|
|
11
|
-
|
|
12
|
-
spec.summary = "
|
|
13
|
-
spec.description =
|
|
10
|
+
|
|
11
|
+
spec.summary = "Simple deployment tool for Ruby apps (based on Capistrano)"
|
|
12
|
+
spec.description = %(
|
|
13
|
+
Minestrone is a simplified fork of old Capistrano from before the 3.0 rewrite. It retains most of the old, simpler API,
|
|
14
|
+
while also removing some more advanced features, and focusing on the relatively simplest but common scenario of a single
|
|
15
|
+
production server. It also removes a lot of old cruft, support for less commonly used or less recommended things,
|
|
16
|
+
and modernizes some of the code.
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
spec.homepage = "https://github.com/mackuba/minestrone"
|
|
20
|
+
spec.license = "MIT"
|
|
21
|
+
|
|
22
|
+
spec.metadata = {
|
|
23
|
+
"bug_tracker_uri" => "https://github.com/mackuba/minestrone/issues",
|
|
24
|
+
"changelog_uri" => "https://github.com/mackuba/minestrone/blob/master/CHANGELOG.md",
|
|
25
|
+
"source_code_uri" => "https://github.com/mackuba/minestrone",
|
|
26
|
+
"rubygems_mfa_required" => "true"
|
|
27
|
+
}
|
|
28
|
+
|
|
14
29
|
spec.files = `git ls-files`.split("\n")
|
|
15
|
-
spec.
|
|
16
|
-
spec.executables = `git ls-files -- bin/*`.split("\n").map { |file| File.basename(file) }
|
|
30
|
+
spec.executables = ['min', 'capify']
|
|
17
31
|
spec.require_paths = ["lib"]
|
|
18
32
|
spec.extra_rdoc_files = [
|
|
19
33
|
"README.md"
|
|
20
34
|
]
|
|
21
35
|
|
|
22
|
-
spec.required_ruby_version = ">= 3.
|
|
36
|
+
spec.required_ruby_version = ">= 3.3.0"
|
|
23
37
|
|
|
24
38
|
spec.add_dependency 'benchmark', '~> 0.5'
|
|
25
|
-
spec.add_dependency 'highline', '
|
|
26
|
-
spec.add_dependency 'net-ssh', '
|
|
27
|
-
spec.add_dependency 'net-sftp', '
|
|
28
|
-
spec.add_dependency 'net-scp', '
|
|
29
|
-
|
|
30
|
-
# used silently by net-ssh but undeclared
|
|
31
|
-
spec.add_dependency 'logger'
|
|
39
|
+
spec.add_dependency 'highline', '~> 3.0'
|
|
40
|
+
spec.add_dependency 'net-ssh', '~> 8.0'
|
|
41
|
+
spec.add_dependency 'net-sftp', '~> 4.0'
|
|
42
|
+
spec.add_dependency 'net-scp', '~> 4.0'
|
|
43
|
+
spec.add_dependency 'bcrypt_pbkdf', '~> 1.1'
|
|
32
44
|
end
|
|
@@ -47,6 +47,12 @@ class ConfigurationActionsFileTransferTest < Test::Unit::TestCase
|
|
|
47
47
|
@config.upload("testl.txt", "testr.txt", :mode => "g+w", :foo => "bar")
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
+
def test_upload_file_should_alias_upload
|
|
51
|
+
@config.expects(:transfer).with(:up, "testl.txt", "testr.txt", { :foo => "bar" })
|
|
52
|
+
@config.expects(:run).with("chmod 775 testr.txt", { :foo => "bar" })
|
|
53
|
+
@config.upload_file("testl.txt", "testr.txt", :mode => 0775, :foo => "bar")
|
|
54
|
+
end
|
|
55
|
+
|
|
50
56
|
def test_download_should_delegate_to_transfer
|
|
51
57
|
@config.expects(:transfer).with(:down, "testr.txt", "testl.txt", { :foo => "bar" })
|
|
52
58
|
@config.download("testr.txt", "testl.txt", :foo => "bar")
|
|
@@ -96,6 +96,60 @@ class ConfigurationVariablesTest < Test::Unit::TestCase
|
|
|
96
96
|
end
|
|
97
97
|
end
|
|
98
98
|
|
|
99
|
+
def test_set_if_empty_should_set_missing_variable
|
|
100
|
+
@config.set_if_empty :sample, :value
|
|
101
|
+
assert_equal :value, @config.fetch(:sample)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def test_set_if_empty_should_accept_lazy_block
|
|
105
|
+
@config.set_if_empty(:sample) { :value }
|
|
106
|
+
assert_instance_of Proc, @config.variables[:sample]
|
|
107
|
+
assert_equal :value, @config.fetch(:sample)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def test_set_if_empty_should_not_replace_existing_false_or_nil
|
|
111
|
+
@config.set :false_value, false
|
|
112
|
+
@config.set :nil_value, nil
|
|
113
|
+
|
|
114
|
+
@config.set_if_empty :false_value, :replacement
|
|
115
|
+
replacement_called = false
|
|
116
|
+
@config.set_if_empty(:nil_value) { replacement_called = true }
|
|
117
|
+
|
|
118
|
+
assert_equal false, @config.fetch(:false_value)
|
|
119
|
+
assert_nil @config.fetch(:nil_value)
|
|
120
|
+
assert_equal false, replacement_called
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def test_append_should_add_values_to_missing_or_existing_array
|
|
124
|
+
@config.append :missing, :one, :two
|
|
125
|
+
@config.set :existing, [:one]
|
|
126
|
+
@config.append :existing, :two, :three
|
|
127
|
+
|
|
128
|
+
assert_equal [:one, :two], @config.fetch(:missing)
|
|
129
|
+
assert_equal [:one, :two, :three], @config.fetch(:existing)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def test_append_should_wrap_existing_scalar_var_in_array
|
|
133
|
+
@config.set :sample, :one
|
|
134
|
+
@config.append :sample, :two
|
|
135
|
+
assert_equal [:one, :two], @config.fetch(:sample)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def test_remove_should_remove_values_from_missing_or_existing_array
|
|
139
|
+
@config.remove :missing, :one
|
|
140
|
+
@config.set :existing, [:one, :two, :one, :three]
|
|
141
|
+
@config.remove :existing, :one, :three
|
|
142
|
+
|
|
143
|
+
assert_equal [], @config.fetch(:missing)
|
|
144
|
+
assert_equal [:two], @config.fetch(:existing)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def test_remove_should_wrap_existing_scalar
|
|
148
|
+
@config.set :sample, :one
|
|
149
|
+
@config.remove :sample, :two
|
|
150
|
+
assert_equal [:one], @config.fetch(:sample)
|
|
151
|
+
end
|
|
152
|
+
|
|
99
153
|
def test_unset_should_remove_variable_from_hash
|
|
100
154
|
@config.set :sample, :value
|
|
101
155
|
assert @config.variables.key?(:sample)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: minestrone
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jamis Buck
|
|
@@ -29,74 +29,78 @@ dependencies:
|
|
|
29
29
|
name: highline
|
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
|
31
31
|
requirements:
|
|
32
|
-
- - "
|
|
32
|
+
- - "~>"
|
|
33
33
|
- !ruby/object:Gem::Version
|
|
34
|
-
version: '0'
|
|
34
|
+
version: '3.0'
|
|
35
35
|
type: :runtime
|
|
36
36
|
prerelease: false
|
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
|
38
38
|
requirements:
|
|
39
|
-
- - "
|
|
39
|
+
- - "~>"
|
|
40
40
|
- !ruby/object:Gem::Version
|
|
41
|
-
version: '0'
|
|
41
|
+
version: '3.0'
|
|
42
42
|
- !ruby/object:Gem::Dependency
|
|
43
43
|
name: net-ssh
|
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
|
45
45
|
requirements:
|
|
46
|
-
- - "
|
|
46
|
+
- - "~>"
|
|
47
47
|
- !ruby/object:Gem::Version
|
|
48
|
-
version: '
|
|
48
|
+
version: '8.0'
|
|
49
49
|
type: :runtime
|
|
50
50
|
prerelease: false
|
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
|
52
52
|
requirements:
|
|
53
|
-
- - "
|
|
53
|
+
- - "~>"
|
|
54
54
|
- !ruby/object:Gem::Version
|
|
55
|
-
version: '
|
|
55
|
+
version: '8.0'
|
|
56
56
|
- !ruby/object:Gem::Dependency
|
|
57
57
|
name: net-sftp
|
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
|
59
59
|
requirements:
|
|
60
|
-
- - "
|
|
60
|
+
- - "~>"
|
|
61
61
|
- !ruby/object:Gem::Version
|
|
62
|
-
version: '
|
|
62
|
+
version: '4.0'
|
|
63
63
|
type: :runtime
|
|
64
64
|
prerelease: false
|
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
|
66
66
|
requirements:
|
|
67
|
-
- - "
|
|
67
|
+
- - "~>"
|
|
68
68
|
- !ruby/object:Gem::Version
|
|
69
|
-
version: '
|
|
69
|
+
version: '4.0'
|
|
70
70
|
- !ruby/object:Gem::Dependency
|
|
71
71
|
name: net-scp
|
|
72
72
|
requirement: !ruby/object:Gem::Requirement
|
|
73
73
|
requirements:
|
|
74
|
-
- - "
|
|
74
|
+
- - "~>"
|
|
75
75
|
- !ruby/object:Gem::Version
|
|
76
|
-
version: '
|
|
76
|
+
version: '4.0'
|
|
77
77
|
type: :runtime
|
|
78
78
|
prerelease: false
|
|
79
79
|
version_requirements: !ruby/object:Gem::Requirement
|
|
80
80
|
requirements:
|
|
81
|
-
- - "
|
|
81
|
+
- - "~>"
|
|
82
82
|
- !ruby/object:Gem::Version
|
|
83
|
-
version: '
|
|
83
|
+
version: '4.0'
|
|
84
84
|
- !ruby/object:Gem::Dependency
|
|
85
|
-
name:
|
|
85
|
+
name: bcrypt_pbkdf
|
|
86
86
|
requirement: !ruby/object:Gem::Requirement
|
|
87
87
|
requirements:
|
|
88
|
-
- - "
|
|
88
|
+
- - "~>"
|
|
89
89
|
- !ruby/object:Gem::Version
|
|
90
|
-
version: '
|
|
90
|
+
version: '1.1'
|
|
91
91
|
type: :runtime
|
|
92
92
|
prerelease: false
|
|
93
93
|
version_requirements: !ruby/object:Gem::Requirement
|
|
94
94
|
requirements:
|
|
95
|
-
- - "
|
|
95
|
+
- - "~>"
|
|
96
96
|
- !ruby/object:Gem::Version
|
|
97
|
-
version: '
|
|
98
|
-
description: Minestrone is a
|
|
99
|
-
|
|
97
|
+
version: '1.1'
|
|
98
|
+
description: "\n Minestrone is a simplified fork of old Capistrano from before
|
|
99
|
+
the 3.0 rewrite. It retains most of the old, simpler API,\n while also removing
|
|
100
|
+
some more advanced features, and focusing on the relatively simplest but common
|
|
101
|
+
scenario of a single\n production server. It also removes a lot of old cruft,
|
|
102
|
+
support for less commonly used or less recommended things,\n and modernizes some
|
|
103
|
+
of the code.\n "
|
|
100
104
|
executables:
|
|
101
105
|
- capify
|
|
102
106
|
- min
|
|
@@ -106,10 +110,12 @@ extra_rdoc_files:
|
|
|
106
110
|
files:
|
|
107
111
|
- ".github/workflows/main.yml"
|
|
108
112
|
- ".gitignore"
|
|
113
|
+
- CHANGELOG.md
|
|
109
114
|
- Gemfile
|
|
110
115
|
- LICENSE.txt
|
|
111
116
|
- README.md
|
|
112
117
|
- Rakefile
|
|
118
|
+
- SECURITY.md
|
|
113
119
|
- bin/capify
|
|
114
120
|
- bin/min
|
|
115
121
|
- docs/lib-codebase-map.md
|
|
@@ -154,7 +160,6 @@ files:
|
|
|
154
160
|
- lib/minestrone/recipes/deploy/strategy/copy.rb
|
|
155
161
|
- lib/minestrone/recipes/deploy/strategy/remote_cache.rb
|
|
156
162
|
- lib/minestrone/recipes/standard.rb
|
|
157
|
-
- lib/minestrone/recipes/templates/maintenance.rhtml
|
|
158
163
|
- lib/minestrone/server_definition.rb
|
|
159
164
|
- lib/minestrone/ssh.rb
|
|
160
165
|
- lib/minestrone/task_definition.rb
|
|
@@ -198,9 +203,14 @@ files:
|
|
|
198
203
|
- test/transfer_test.rb
|
|
199
204
|
- test/utils.rb
|
|
200
205
|
- test/version_test.rb
|
|
201
|
-
homepage:
|
|
202
|
-
licenses:
|
|
203
|
-
|
|
206
|
+
homepage: https://github.com/mackuba/minestrone
|
|
207
|
+
licenses:
|
|
208
|
+
- MIT
|
|
209
|
+
metadata:
|
|
210
|
+
bug_tracker_uri: https://github.com/mackuba/minestrone/issues
|
|
211
|
+
changelog_uri: https://github.com/mackuba/minestrone/blob/master/CHANGELOG.md
|
|
212
|
+
source_code_uri: https://github.com/mackuba/minestrone
|
|
213
|
+
rubygems_mfa_required: 'true'
|
|
204
214
|
rdoc_options: []
|
|
205
215
|
require_paths:
|
|
206
216
|
- lib
|
|
@@ -208,51 +218,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
208
218
|
requirements:
|
|
209
219
|
- - ">="
|
|
210
220
|
- !ruby/object:Gem::Version
|
|
211
|
-
version: 3.
|
|
221
|
+
version: 3.3.0
|
|
212
222
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
213
223
|
requirements:
|
|
214
224
|
- - ">="
|
|
215
225
|
- !ruby/object:Gem::Version
|
|
216
226
|
version: '0'
|
|
217
227
|
requirements: []
|
|
218
|
-
rubygems_version: 4.0.
|
|
228
|
+
rubygems_version: 4.0.23
|
|
219
229
|
specification_version: 4
|
|
220
|
-
summary:
|
|
221
|
-
test_files:
|
|
222
|
-
- test/cli/execute_test.rb
|
|
223
|
-
- test/cli/help_test.rb
|
|
224
|
-
- test/cli/options_test.rb
|
|
225
|
-
- test/cli/ui_test.rb
|
|
226
|
-
- test/cli_test.rb
|
|
227
|
-
- test/command_test.rb
|
|
228
|
-
- test/configuration/actions/file_transfer_test.rb
|
|
229
|
-
- test/configuration/actions/inspect_test.rb
|
|
230
|
-
- test/configuration/actions/invocation_test.rb
|
|
231
|
-
- test/configuration/alias_task_test.rb
|
|
232
|
-
- test/configuration/callbacks_test.rb
|
|
233
|
-
- test/configuration/connections_test.rb
|
|
234
|
-
- test/configuration/execution_test.rb
|
|
235
|
-
- test/configuration/loading_test.rb
|
|
236
|
-
- test/configuration/namespace_dsl_test.rb
|
|
237
|
-
- test/configuration/servers_test.rb
|
|
238
|
-
- test/configuration/variables_test.rb
|
|
239
|
-
- test/configuration_test.rb
|
|
240
|
-
- test/deploy/local_dependency_test.rb
|
|
241
|
-
- test/deploy/remote_dependency_test.rb
|
|
242
|
-
- test/deploy/scm/base_test.rb
|
|
243
|
-
- test/deploy/scm/git_test.rb
|
|
244
|
-
- test/deploy/scm/none_test.rb
|
|
245
|
-
- test/deploy/strategy/copy_test.rb
|
|
246
|
-
- test/extensions_test.rb
|
|
247
|
-
- test/fixtures/cli_integration.rb
|
|
248
|
-
- test/fixtures/config.rb
|
|
249
|
-
- test/fixtures/custom.rb
|
|
250
|
-
- test/logger_formatting_test.rb
|
|
251
|
-
- test/logger_test.rb
|
|
252
|
-
- test/recipes_test.rb
|
|
253
|
-
- test/server_definition_test.rb
|
|
254
|
-
- test/ssh_test.rb
|
|
255
|
-
- test/task_definition_test.rb
|
|
256
|
-
- test/transfer_test.rb
|
|
257
|
-
- test/utils.rb
|
|
258
|
-
- test/version_test.rb
|
|
230
|
+
summary: Simple deployment tool for Ruby apps (based on Capistrano)
|
|
231
|
+
test_files: []
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
3
|
-
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
4
|
-
|
|
5
|
-
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
6
|
-
|
|
7
|
-
<head>
|
|
8
|
-
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
|
|
9
|
-
<title>System down for maintenance</title>
|
|
10
|
-
|
|
11
|
-
<style type="text/css">
|
|
12
|
-
div.outer {
|
|
13
|
-
position: absolute;
|
|
14
|
-
left: 50%;
|
|
15
|
-
top: 50%;
|
|
16
|
-
width: 500px;
|
|
17
|
-
height: 300px;
|
|
18
|
-
margin-left: -260px;
|
|
19
|
-
margin-top: -150px;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.DialogBody {
|
|
23
|
-
margin: 0;
|
|
24
|
-
padding: 10px;
|
|
25
|
-
text-align: left;
|
|
26
|
-
border: 1px solid #ccc;
|
|
27
|
-
border-right: 1px solid #999;
|
|
28
|
-
border-bottom: 1px solid #999;
|
|
29
|
-
background-color: #fff;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
body { background-color: #fff; }
|
|
33
|
-
</style>
|
|
34
|
-
</head>
|
|
35
|
-
|
|
36
|
-
<body>
|
|
37
|
-
|
|
38
|
-
<div class="outer">
|
|
39
|
-
<div class="DialogBody" style="text-align: center;">
|
|
40
|
-
<div style="text-align: center; width: 200px; margin: 0 auto;">
|
|
41
|
-
<p style="color: red; font-size: 16px; line-height: 20px;">
|
|
42
|
-
The system is down for <%= reason ? reason : "maintenance" %>
|
|
43
|
-
as of <%= Time.now.strftime("%H:%M %Z") %>.
|
|
44
|
-
</p>
|
|
45
|
-
<p style="color: #666;">
|
|
46
|
-
It'll be back <%= deadline ? deadline : "shortly" %>.
|
|
47
|
-
</p>
|
|
48
|
-
</div>
|
|
49
|
-
</div>
|
|
50
|
-
</div>
|
|
51
|
-
|
|
52
|
-
</body>
|
|
53
|
-
</html>
|