capistrano-nomad 0.16.0 → 0.16.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40b9b44a616fbf4c542f561845ffb785aa73b476027f78ee227953b15ab326a4
4
- data.tar.gz: 9ebe475b0c6af2aee4c098536e9453fe231fcb7e9c86ce0b30e940ebc0f8d7f1
3
+ metadata.gz: 408063f04626ace5215b232901a72869fb5aabfe336017ce0e33aa1f1b53b02c
4
+ data.tar.gz: 4f3019490d7fa5042f1efe94ba7bedf1725fe3f25d391c19ae87fd45b051d79e
5
5
  SHA512:
6
- metadata.gz: 0e7c48930dbc272c34c48922a2b93bb67b78d4729f2e2ca4c4602e33ed9019834d0c65b2cffaafa5bcdd450aeef335a8df95628dceb385f322b36815d96ef0f9
7
- data.tar.gz: ca780918d90383b5232ff2c1c27e5d6ed65085358e475e7cf132fed07fd527f15fb6013fe732f9dc8cbdd9ebd179faacb751c73b0aa723aa0f377211169cb64a
6
+ metadata.gz: ae43c669814a9ba3ccd7462d4cd862b97cc79bdeefed86966fa251fbe45fa184cb8ac570b35bfd811907f1e276af4c6c6c6e3d57823c4fdea6922f891822b2c1
7
+ data.tar.gz: bb552095171a362745db10f63a45c3ca24ee9f7fb715d52738fa18802472798b695090a55a5d79bb5a7457dbad84d44e1b03b5112a132f7cdda1b0d1c8ca8051
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.16.2]
4
+
5
+ - Fail `upload_plan` and other plan operations when Nomad rejects a job or cannot determine the plan
6
+ - Keep successful plans with allocation changes successful despite Nomad's exit code 1
7
+ - Include CLI regression tests in the gem
8
+
9
+ ## [0.16.1]
10
+
11
+ - Pass every configured variable file to `nomad plan` and `nomad run`
12
+
3
13
  ## [0.16.0]
4
14
 
5
15
  - Add `:redeploy` task that stops job before performing a full deploy to ensure fresh allocations
data/Gemfile CHANGED
@@ -4,3 +4,5 @@ source "https://rubygems.org"
4
4
 
5
5
  # Specify your gem's dependencies in capistrano-nomad.gemspec
6
6
  gemspec
7
+
8
+ gem "minitest", "~> 5.0"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- capistrano-nomad (0.16.0)
4
+ capistrano-nomad (0.16.2)
5
5
  activesupport (<= 7.0.8)
6
6
  byebug
7
7
  capistrano (~> 3.0)
@@ -52,9 +52,11 @@ GEM
52
52
  PLATFORMS
53
53
  arm64-darwin-21
54
54
  arm64-darwin-23
55
+ x86_64-linux-gnu
55
56
 
56
57
  DEPENDENCIES
57
58
  capistrano-nomad!
59
+ minitest (~> 5.0)
58
60
 
59
61
  BUNDLED WITH
60
62
  2.4.20
data/README.md CHANGED
@@ -213,7 +213,9 @@ cap production nomad:version
213
213
 
214
214
  After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
215
215
 
216
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
216
+ Run `bundle exec rake test` to test the generated Capistrano `upload_plan` task through the CLI. The tests use local transport and controlled Nomad exit codes. To also check rejection of invalid HCL with a real Nomad binary, run `NOMAD_REAL_BINARY=/path/to/nomad bundle exec rake test`.
217
+
218
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version in `capistrano-nomad.gemspec`, run `bundle install`, and update `CHANGELOG.md`. Run `bundle exec rake test` and commit the release changes. Then run `bundle exec rake release`, which creates the version tag, pushes the release commit and tag, and publishes the gem to [RubyGems](https://rubygems.org).
217
219
 
218
220
  ## Contributing
219
221
 
data/Rakefile CHANGED
@@ -1,4 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bundler/gem_tasks"
4
- task default: %i[]
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new do |task|
7
+ task.libs << "test"
8
+ task.pattern = "test/**/*_test.rb"
9
+ end
10
+
11
+ task default: :test
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "capistrano-nomad"
5
- spec.version = "0.16.0"
5
+ spec.version = "0.16.2"
6
6
  spec.authors = ["James Hu"]
7
7
 
8
8
  spec.summary = "Capistrano plugin for deploying and managing Nomad jobs"
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
18
18
  # Specify which files should be added to the gem when it is released. The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
19
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
20
20
  %x(git ls-files -z).split("\x0").reject do |f|
21
- (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
21
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
22
22
  end
23
23
  end
24
24
  spec.bindir = "exe"
@@ -138,6 +138,10 @@ def capistrano_nomad_build_release_var_file_path(name, **options)
138
138
  "#{release_path}#{capistrano_nomad_ensure_absolute_path(capistrano_nomad_build_base_var_file_path(name, **options))}"
139
139
  end
140
140
 
141
+ def capistrano_nomad_plan_command?(args)
142
+ args.first.to_s == "plan" || args.take(2).map(&:to_s) == ["job", "plan"]
143
+ end
144
+
141
145
  def capistrano_nomad_run_nomad_command(kind, *args)
142
146
  converted_args = args.each_with_object([]) do |arg, collection|
143
147
  # If hash then convert it as options
@@ -165,15 +169,25 @@ def capistrano_nomad_run_nomad_command(kind, *args)
165
169
  end
166
170
 
167
171
  with(env_vars) do
168
- # Ignore errors
169
- public_send(kind, :nomad, *converted_args, raise_on_non_zero_exit: false)
172
+ if capistrano_nomad_plan_command?(args)
173
+ # Nomad returns 1 for a successful plan with changes; all other nonzero exits are errors
174
+ public_send(kind, :nomad, *converted_args, '; status=$?; if [ "$status" -eq 1 ]; then exit 0; else exit "$status"; fi', raise_on_non_zero_exit: true)
175
+ else
176
+ # Ignore errors for commands other than plans
177
+ public_send(kind, :nomad, *converted_args, raise_on_non_zero_exit: false)
178
+ end
170
179
  end
171
180
  end
172
181
 
173
182
  def capistrano_nomad_execute_nomad_command(*args, **options)
174
183
  capistrano_nomad_run_remotely do |host|
175
- run_interactively(host) do
184
+ if capistrano_nomad_plan_command?(args)
185
+ # Use SSHKit's checked execution because the interactive backend does not raise on failure
176
186
  capistrano_nomad_run_nomad_command(:execute, *args, **options)
187
+ else
188
+ run_interactively(host) do
189
+ capistrano_nomad_run_nomad_command(:execute, *args, **options)
190
+ end
177
191
  end
178
192
  end
179
193
  end
@@ -328,6 +342,15 @@ def capistrano_nomad_fetch_job_var_files(name, **options)
328
342
  capistrano_nomad_fetch_job_options(name, :var_files, **options) || []
329
343
  end
330
344
 
345
+ # Build one command option per configured variable file so Nomad receives every file in order
346
+ def capistrano_nomad_build_job_var_file_options(name, **options)
347
+ capistrano_nomad_fetch_job_var_files(name, **options).map do |var_file|
348
+ {
349
+ var_file: capistrano_nomad_build_release_var_file_path(var_file, **options),
350
+ }
351
+ end
352
+ end
353
+
331
354
  def capistrano_nomad_fetch_jobs_names_by_namespace(**options)
332
355
  capistrano_nomad_ensure_options!(options)
333
356
  namespace = options[:namespace]
@@ -521,14 +544,19 @@ def capistrano_nomad_upload_jobs(names, **options)
521
544
  end
522
545
  end
523
546
 
547
+ # Plan each job with every configured variable file before the uploaded job path
524
548
  def capistrano_nomad_plan_jobs(names, **options)
525
549
  names.each do |name|
526
- args = [capistrano_nomad_build_release_job_path(name, **options)]
550
+ args = [
551
+ *capistrano_nomad_build_job_var_file_options(name, **options),
552
+ capistrano_nomad_build_release_job_path(name, **options),
553
+ ]
527
554
 
528
555
  capistrano_nomad_execute_nomad_command(:plan, *args)
529
556
  end
530
557
  end
531
558
 
559
+ # Run each job with all configured variable files while preserving the existing command options
532
560
  def capistrano_nomad_run_jobs(names, is_detached: true, **options)
533
561
  capistrano_nomad_ensure_options!(options)
534
562
 
@@ -541,13 +569,10 @@ def capistrano_nomad_run_jobs(names, is_detached: true, **options)
541
569
  preserve_counts: true,
542
570
  }
543
571
 
544
- capistrano_nomad_fetch_job_var_files(name, **options).each do |var_file|
545
- run_options[:var_file] = capistrano_nomad_build_release_var_file_path(var_file, **options)
546
- end
547
-
548
572
  capistrano_nomad_execute_nomad_command(
549
573
  :run,
550
574
  run_options,
575
+ *capistrano_nomad_build_job_var_file_options(name, **options),
551
576
  capistrano_nomad_build_release_job_path(name, **options),
552
577
  )
553
578
  end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "minitest/autorun"
4
+ require "fileutils"
5
+ require "open3"
6
+ require "tmpdir"
7
+
8
+ class UploadPlanTest < Minitest::Test
9
+ def test_upload_plan_succeeds_for_accepted_plans_and_fails_for_rejected_plans
10
+ Dir.mktmpdir("capistrano-nomad") do |root|
11
+ FileUtils.mkdir_p(["#{root}/config/deploy", "#{root}/nomad/jobs", "#{root}/bin"])
12
+ File.write("#{root}/Capfile", <<~RUBY)
13
+ require "capistrano/setup"
14
+ require "capistrano/deploy"
15
+ require "capistrano/nomad"
16
+ install_plugin Capistrano::Nomad
17
+ RUBY
18
+ File.write("#{root}/config/deploy.rb", <<~RUBY)
19
+ set :application, "plan-test"
20
+ set :deploy_to, #{"#{root}/remote".inspect}
21
+ set :root, #{root.inspect}
22
+ set :current_revision, "test"
23
+ set :nomad_docker_image_types, {}
24
+ SSHKit.config.command_map[:nomad] = #{"#{root}/bin/nomad".inspect}
25
+ nomad_job :example
26
+ RUBY
27
+ File.write("#{root}/config/deploy/test.rb", <<~RUBY)
28
+ server "localhost", roles: [:manager]
29
+ set :sshkit_backend, SSHKit::Backend::Local
30
+ RUBY
31
+ File.write("#{root}/bin/ssh", <<~SH)
32
+ #!/bin/sh
33
+ for argument do command="$argument"; done
34
+ exec /bin/sh -c "$command"
35
+ SH
36
+ FileUtils.chmod(0755, "#{root}/bin/ssh")
37
+ File.write("#{root}/bin/nomad", <<~SH)
38
+ #!/bin/sh
39
+ [ "$1" = plan ] || exit 99
40
+ cat "$2"
41
+ case "$NOMAD_TEST_EXIT" in
42
+ 0|1) echo 'Scheduler dry-run: accepted';;
43
+ *) echo 'Error determining plan results' >&2;;
44
+ esac
45
+ exit "$NOMAD_TEST_EXIT"
46
+ SH
47
+ FileUtils.chmod(0755, "#{root}/bin/nomad")
48
+
49
+ [0, 1, 255, 2].each do |exit_code|
50
+ job = exit_code < 2 ? 'job "example" {}' : 'job "example" {'
51
+ File.write("#{root}/nomad/jobs/example.hcl", job)
52
+ output, status = Open3.capture2e(
53
+ { "NOMAD_TEST_EXIT" => exit_code.to_s, "PATH" => "#{root}/bin:#{ENV.fetch("PATH")}" },
54
+ "bundle", "exec", "cap", "test", "nomad:example:upload_plan",
55
+ chdir: root,
56
+ )
57
+
58
+ assert_includes(output, job, output)
59
+ if exit_code < 2
60
+ assert(status.success?, output)
61
+ assert_includes(output, "Scheduler dry-run: accepted")
62
+ else
63
+ refute(status.success?, output)
64
+ assert_includes(output, "Error determining plan results")
65
+ end
66
+ end
67
+
68
+ if ENV["NOMAD_REAL_BINARY"]
69
+ FileUtils.cp(ENV.fetch("NOMAD_REAL_BINARY"), "#{root}/bin/nomad")
70
+ output, status = Open3.capture2e("bundle", "exec", "cap", "test", "nomad:example:upload_plan", chdir: root)
71
+
72
+ refute(status.success?, output)
73
+ assert_includes(output, "Error parsing job file")
74
+ end
75
+ end
76
+ end
77
+ 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.16.0
4
+ version: 0.16.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Hu
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-02-15 00:00:00.000000000 Z
11
+ date: 2026-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -130,6 +130,7 @@ files:
130
130
  - lib/capistrano/nomad/helpers/nomad.rb
131
131
  - lib/capistrano/nomad/scm/git_local.rb
132
132
  - lib/capistrano/nomad/tasks/nomad.rake
133
+ - test/upload_plan_test.rb
133
134
  homepage: https://github.com/axsuul/capistrano-nomad
134
135
  licenses:
135
136
  - MIT
@@ -152,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
152
153
  - !ruby/object:Gem::Version
153
154
  version: '0'
154
155
  requirements: []
155
- rubygems_version: 3.3.27
156
+ rubygems_version: 3.4.19
156
157
  signing_key:
157
158
  specification_version: 4
158
159
  summary: Capistrano plugin for deploying and managing Nomad jobs