capistrano-nomad 0.14.0 → 0.15.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.
- checksums.yaml +4 -4
- data/.opencode/commands/release.md +39 -0
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +1 -1
- data/README.md +8 -0
- data/capistrano-nomad.gemspec +1 -1
- data/lib/capistrano/nomad/helpers/base.rb +4 -0
- data/lib/capistrano/nomad/helpers/dsl.rb +6 -6
- data/lib/capistrano/nomad/helpers/nomad.rb +48 -2
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3d733a824e5d9c7403669bbf958bbd8ee0583fe9a054d45065fd1b71eec0941d
|
|
4
|
+
data.tar.gz: b5a12159f7bf4c6fa241732c21a732a60953dc548fcf2139b97f94348566a584
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7c97291b411d604e7308ed135548d4f3d092158b2ddec7a8675e5e4d1af29a1d66f8e7e9e181d4753dd5042d0ebf2c0ac609e9f03c4341a077b163e0b582835e
|
|
7
|
+
data.tar.gz: 6819e434bdde1b26b7c7f80d18ccdc23422f6fedb30c4b37f54657ba452b9bcc4309c34b744e9faab0e88df47a8b221e69fee9149a354a02dc956544b1a163e4
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Release a new version of the gem
|
|
3
|
+
agent: build
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Release a new version of the capistrano-nomad gem.
|
|
7
|
+
|
|
8
|
+
## Current State
|
|
9
|
+
|
|
10
|
+
Current version: !`grep -m1 'spec.version' capistrano-nomad.gemspec | sed 's/.*"\(.*\)"/\1/'`
|
|
11
|
+
|
|
12
|
+
Changes pending release:
|
|
13
|
+
!`sed -n '/## \[Unreleased\]/,/## \[/p' CHANGELOG.md | head -20`
|
|
14
|
+
|
|
15
|
+
## Steps to perform:
|
|
16
|
+
|
|
17
|
+
1. **Ask what version to release** (unless specified via arguments: $ARGUMENTS)
|
|
18
|
+
|
|
19
|
+
2. **Update the version** in `capistrano-nomad.gemspec` (line 5: `spec.version = "X.Y.Z"`)
|
|
20
|
+
|
|
21
|
+
3. **Update CHANGELOG.md**:
|
|
22
|
+
- Rename `[Unreleased]` section to the new version number (e.g., `## [0.15.0]`)
|
|
23
|
+
- Add a new empty `## [Unreleased]` section at the top
|
|
24
|
+
|
|
25
|
+
4. **Commit the version bump**:
|
|
26
|
+
```shell
|
|
27
|
+
git add capistrano-nomad.gemspec CHANGELOG.md
|
|
28
|
+
git commit -m "X.Y.Z"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
5. **Run the release command**:
|
|
32
|
+
```shell
|
|
33
|
+
bundle exec rake release
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
This will:
|
|
37
|
+
- Create a git tag for the version
|
|
38
|
+
- Push git commits and the created tag
|
|
39
|
+
- Push the `.gem` file to rubygems.org
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.15.0]
|
|
4
|
+
|
|
5
|
+
- Fix command escaping for console task to support complex commands with special characters using base64 encoding
|
|
6
|
+
|
|
7
|
+
## [0.14.1]
|
|
8
|
+
|
|
9
|
+
- Support for `IS_DETACHED` environment variable to run jobs in detached mode (e.g. `IS_DETACHED=true cap production nomad:app:deploy`)
|
|
10
|
+
|
|
3
11
|
## [0.14.0]
|
|
4
12
|
|
|
5
13
|
- `nomad:deploy` properly deploys all jobs across all namespaces now
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -174,6 +174,14 @@ cap production nomad:app:revert VERSION=4
|
|
|
174
174
|
cap production nomad:app:revert DOCKER_IMAGE=v1.4.4
|
|
175
175
|
```
|
|
176
176
|
|
|
177
|
+
Run jobs in detached mode (fire and forget)
|
|
178
|
+
|
|
179
|
+
```shell
|
|
180
|
+
IS_DETACHED=true cap production nomad:app:deploy
|
|
181
|
+
IS_DETACHED=true cap production nomad:app:run
|
|
182
|
+
IS_DETACHED=true cap production nomad:analytics:grafana:upload_run
|
|
183
|
+
```
|
|
184
|
+
|
|
177
185
|
Open job in web UI
|
|
178
186
|
|
|
179
187
|
```shell
|
data/capistrano-nomad.gemspec
CHANGED
|
@@ -88,12 +88,12 @@ def nomad_job(name, attributes = {})
|
|
|
88
88
|
|
|
89
89
|
desc("Run #{description_name} job")
|
|
90
90
|
task(:run) do
|
|
91
|
-
capistrano_nomad_run_jobs([name], namespace: namespace, is_detached:
|
|
91
|
+
capistrano_nomad_run_jobs([name], namespace: namespace, is_detached: capistrano_nomad_job_detached_overridden?)
|
|
92
92
|
end
|
|
93
93
|
|
|
94
94
|
desc("Purge and run #{description_name} job again")
|
|
95
95
|
task(:rerun) do
|
|
96
|
-
capistrano_nomad_rerun_jobs([name], namespace: namespace, is_detached:
|
|
96
|
+
capistrano_nomad_rerun_jobs([name], namespace: namespace, is_detached: capistrano_nomad_job_detached_overridden?)
|
|
97
97
|
end
|
|
98
98
|
|
|
99
99
|
desc("Upload and plan #{description_name} job")
|
|
@@ -103,17 +103,17 @@ def nomad_job(name, attributes = {})
|
|
|
103
103
|
|
|
104
104
|
desc("Upload and run #{description_name} job")
|
|
105
105
|
task(:upload_run) do
|
|
106
|
-
capistrano_nomad_upload_run_jobs([name], namespace: namespace, is_detached:
|
|
106
|
+
capistrano_nomad_upload_run_jobs([name], namespace: namespace, is_detached: capistrano_nomad_job_detached_overridden?)
|
|
107
107
|
end
|
|
108
108
|
|
|
109
109
|
desc("Upload and re-run #{description_name} job")
|
|
110
110
|
task(:upload_rerun) do
|
|
111
|
-
capistrano_nomad_upload_rerun_jobs([name], namespace: namespace, is_detached:
|
|
111
|
+
capistrano_nomad_upload_rerun_jobs([name], namespace: namespace, is_detached: capistrano_nomad_job_detached_overridden?)
|
|
112
112
|
end
|
|
113
113
|
|
|
114
114
|
desc("Deploy #{description_name} job")
|
|
115
115
|
task(:deploy) do
|
|
116
|
-
capistrano_nomad_deploy_jobs([name], namespace: namespace, is_detached:
|
|
116
|
+
capistrano_nomad_deploy_jobs([name], namespace: namespace, is_detached: capistrano_nomad_job_detached_overridden?)
|
|
117
117
|
end
|
|
118
118
|
|
|
119
119
|
desc("Start #{description_name} job")
|
|
@@ -142,7 +142,7 @@ def nomad_job(name, attributes = {})
|
|
|
142
142
|
|
|
143
143
|
desc("Purge #{description_name} job")
|
|
144
144
|
task(:purge) do
|
|
145
|
-
capistrano_nomad_purge_jobs([name], namespace: namespace, is_detached:
|
|
145
|
+
capistrano_nomad_purge_jobs([name], namespace: namespace, is_detached: capistrano_nomad_job_detached_overridden?)
|
|
146
146
|
end
|
|
147
147
|
|
|
148
148
|
desc("Display status of #{description_name} job")
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require "active_support/core_ext/string"
|
|
2
|
+
require "base64"
|
|
2
3
|
require "sshkit/interactive"
|
|
3
4
|
|
|
4
5
|
class CapistranoNomadErbNamespace
|
|
@@ -29,6 +30,48 @@ def capistrano_nomad_ensure_absolute_path(path)
|
|
|
29
30
|
path[0] == "/" ? path : "/#{path}"
|
|
30
31
|
end
|
|
31
32
|
|
|
33
|
+
# Escapes a command string for use with sshkit-interactive.
|
|
34
|
+
#
|
|
35
|
+
# sshkit-interactive wraps commands in '$SHELL -l -c "..."' and naively
|
|
36
|
+
# replaces all single quotes with \". This breaks commands that have
|
|
37
|
+
# content inside single quotes (e.g., bin/rails runner 'puts "hello"').
|
|
38
|
+
#
|
|
39
|
+
# This function pre-processes the command to handle single-quoted sections
|
|
40
|
+
# properly by:
|
|
41
|
+
# 1. Converting single quotes to escaped double quotes (\")
|
|
42
|
+
# 2. Escaping content inside those sections for double-quote context
|
|
43
|
+
# (backslashes become \\, double quotes become \\\")
|
|
44
|
+
#
|
|
45
|
+
# After this transformation, sshkit-interactive's gsub("'", '\\"') becomes
|
|
46
|
+
# a no-op since there are no single quotes left.
|
|
47
|
+
def capistrano_nomad_escape_command(command)
|
|
48
|
+
# Process single-quoted sections: 'content' -> \"escaped_content\"
|
|
49
|
+
command.gsub(/'([^']*)'/) do |_match|
|
|
50
|
+
content = Regexp.last_match(1)
|
|
51
|
+
|
|
52
|
+
# Escape for double-quote shell context:
|
|
53
|
+
# - Backslashes need to be doubled (\ -> \\)
|
|
54
|
+
# - Double quotes need to become \\\" to survive shell parsing
|
|
55
|
+
escaped_content = content
|
|
56
|
+
.gsub("\\", "\\\\\\\\")
|
|
57
|
+
.gsub('"', '\\\\\\\\\\\"')
|
|
58
|
+
|
|
59
|
+
'\"' + escaped_content + '\"'
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Escapes a command string for use with sshkit-interactive by base64 encoding.
|
|
64
|
+
#
|
|
65
|
+
# sshkit-interactive wraps commands in '$SHELL -l -c "..."' and naively
|
|
66
|
+
# replaces all single quotes with \". Base64 avoids all quoting issues by
|
|
67
|
+
# decoding the command inside the Nomad task and executing it with /bin/sh.
|
|
68
|
+
def capistrano_nomad_escape_command(command)
|
|
69
|
+
encoded_command = Base64.strict_encode64(command)
|
|
70
|
+
decoded_command = "printf\\ %s\\ #{encoded_command}\\ \\|\\ base64\\ -d\\ \\|\\ /bin/sh"
|
|
71
|
+
|
|
72
|
+
"/bin/sh -lc #{decoded_command}"
|
|
73
|
+
end
|
|
74
|
+
|
|
32
75
|
def capistrano_nomad_build_file_path(parent_path, basename, kind: nil, **options)
|
|
33
76
|
capistrano_nomad_ensure_options!(options)
|
|
34
77
|
namespace = options[:namespace]
|
|
@@ -189,6 +232,9 @@ end
|
|
|
189
232
|
def capistrano_nomad_exec_within_job(name, command, task: nil, **options)
|
|
190
233
|
capistrano_nomad_ensure_options!(options)
|
|
191
234
|
|
|
235
|
+
# Escape command for SSH transport via sshkit-interactive
|
|
236
|
+
escaped_command = capistrano_nomad_escape_command(command)
|
|
237
|
+
|
|
192
238
|
capistrano_nomad_run_remotely do
|
|
193
239
|
if (task_details = capistrano_nomad_find_job_task_details(name, task: task, **options))
|
|
194
240
|
capistrano_nomad_execute_nomad_command(
|
|
@@ -196,7 +242,7 @@ def capistrano_nomad_exec_within_job(name, command, task: nil, **options)
|
|
|
196
242
|
:exec,
|
|
197
243
|
options.merge(task: task_details[:name]),
|
|
198
244
|
task_details[:alloc_id],
|
|
199
|
-
|
|
245
|
+
escaped_command,
|
|
200
246
|
)
|
|
201
247
|
else
|
|
202
248
|
# If alloc can't be determined then choose at random
|
|
@@ -205,7 +251,7 @@ def capistrano_nomad_exec_within_job(name, command, task: nil, **options)
|
|
|
205
251
|
:exec,
|
|
206
252
|
options.merge(job: true),
|
|
207
253
|
task,
|
|
208
|
-
|
|
254
|
+
escaped_command,
|
|
209
255
|
)
|
|
210
256
|
end
|
|
211
257
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: capistrano-nomad
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.15.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- James Hu
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-01-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -114,6 +114,7 @@ executables: []
|
|
|
114
114
|
extensions: []
|
|
115
115
|
extra_rdoc_files: []
|
|
116
116
|
files:
|
|
117
|
+
- ".opencode/commands/release.md"
|
|
117
118
|
- CHANGELOG.md
|
|
118
119
|
- Gemfile
|
|
119
120
|
- Gemfile.lock
|