Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return non-zero exit codes when something goes wrong (WIP) #54

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/pulsar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module Pulsar
require 'fileutils'

require 'pulsar/context_error'
require 'pulsar/executor'
require 'pulsar/validator'
require 'pulsar/interactors/cleanup'
require 'pulsar/interactors/create_run_dirs'
Expand Down
13 changes: 13 additions & 0 deletions lib/pulsar/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

module Pulsar
class CLI < Thor
def self.exit_on_failure?; true; end

map %w[--version -v] => :__print_version

desc 'install [DIRECTORY]', 'Install initial repository in DIRECTORY'
Expand All @@ -20,9 +22,11 @@ def install(directory = './pulsar-conf')

if result.success?
puts 'Successfully created intial repo!'
exit_with_status 0
else
puts 'Failed to create intial repo.'
puts result.error
exit_with_status result.error.is_a?(Pulsar::ContextError) ? result.error.exit_code : 1
end
end

Expand All @@ -40,9 +44,11 @@ def list
result.applications.each do |app, stages|
puts "#{app}: #{stages.join(', ')}"
end
exit_with_status 0
else
puts 'Failed to list application and environments.'
puts result.error
exit_with_status result.error.is_a?(Pulsar::ContextError) ? result.error.exit_code : 1
end
end

Expand All @@ -62,19 +68,26 @@ def deploy(application, environment)

if result.success?
puts "Deployed #{application} on #{environment}!"
exit_with_status 0
else
puts "Failed to deploy #{application} on #{environment}."
puts result.error
exit_with_status result.error.is_a?(Pulsar::ContextError) ? result.error.exit_code : 1
end
end

desc "--version, -v", "print the version"
def __print_version
puts Pulsar::VERSION
exit_with_status 0
end

private

def exit_with_status(status)
exit status
end

def load_config
Dotenv.load(PULSAR_CONF) # Load configurations for Pulsar
end
Expand Down
6 changes: 6 additions & 0 deletions lib/pulsar/context_error.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
module Pulsar
class ContextError < StandardError
attr_reader :exit_code
def initialize(obj, exit_code)
super obj
@exit_code = exit_code
end

def to_s
backtrace ? backtrace.unshift(super).join("\n") : super
end
Expand Down
18 changes: 18 additions & 0 deletions lib/pulsar/executor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
require 'open3'

module Pulsar
module Executor
def self.sh(cmd)
stdin_stream, stdout_stream, stderr_stream, wait_thr = Open3.popen3(cmd)
stdout = stdout_stream.gets(nil) || ""
stderr = stderr_stream.gets(nil) || ""
stdout_stream.close
stderr_stream.gets(nil)
stderr_stream.close
stdin_stream.close
exit_code = wait_thr.value
yield exit_code, stdout, stderr if block_given?
{ status: exit_code.exitstatus, output: stdout + stderr }
end
end
end
2 changes: 1 addition & 1 deletion lib/pulsar/validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def validate_context!
end

def context_fail!(msg)
context.fail! error: Pulsar::ContextError.new(msg)
context.fail! error: Pulsar::ContextError.new(msg, 1)
end

def validable_properties
Expand Down
51 changes: 33 additions & 18 deletions spec/features/deploy_spec.rb
Original file line number Diff line number Diff line change
@@ -1,40 +1,44 @@
require 'spec_helper'

RSpec.describe 'Deploy' do
subject { -> { command } }
subject { command_output }

let(:command) do
`DRY_RUN=true #{RSpec.configuration.pulsar_command} deploy #{options} #{arguments}`
Pulsar::Executor.sh("DRY_RUN=true #{RSpec.configuration.pulsar_command} deploy #{options} #{arguments}")
end

let(:repo) { RSpec.configuration.pulsar_conf_path }
let(:options) { "--conf-repo #{repo}" }
let(:app) { 'blog' }
let(:environment) { 'production' }
let(:arguments) { "#{app} #{environment}" }
let(:command_output) { command[:output] }
let(:exit_status) { command[:status] }
let(:repo) { RSpec.configuration.pulsar_conf_path }
let(:options) { "--conf-repo #{repo}" }
let(:app) { 'blog' }
let(:environment) { 'production' }
let(:arguments) { "#{app} #{environment}" }

context 'via a subcommand named deploy' do
let(:error) { /Could not find command/ }

it { is_expected.not_to output(error).to_stderr_from_any_process }
it { is_expected.not_to match(error) }
it { expect(exit_status).to eq(0) }
end

context 'requires a --conf-repo option' do
let(:options) { nil }
let(:error) { /No value provided for required options '--conf-repo'/ }

it { is_expected.to output(error).to_stderr_from_any_process }
it { is_expected.to match(error) }

context 'can be specified via the alias -c' do
let(:options) { "-c #{repo}" }

it { is_expected.not_to output(error).to_stderr_from_any_process }
it { is_expected.not_to match(error) }
it { expect(exit_status).to eq(0) }
end

context 'can be specified via the environment variable PULSAR_CONF_REPO' do
before { ENV['PULSAR_CONF_REPO'] = repo }

it { is_expected.not_to output(error).to_stderr_from_any_process }
it { is_expected.not_to match(error) }
it { expect(exit_status).to eq(0) }
end
end

Expand All @@ -43,11 +47,12 @@
let(:environment) { nil }
let(:error) { /Usage: "pulsar deploy APPLICATION ENVIRONMENT"/ }

it { is_expected.to output(error).to_stderr_from_any_process }
it { is_expected.to match(error) }
it { expect(exit_status).to eq(1) }
end

context 'when succeeds' do
subject { command }
subject { command_output }

context 'deploys an application on a environment in the pulsar configuration' do
let(:output) { "Deployed blog on production!\n" }
Expand All @@ -60,11 +65,12 @@
end

it { is_expected.to match(output) }
it { expect(exit_status).to eq(0) }

context 'leaves the tmp folder empty' do
subject { Dir.glob("#{Pulsar::PULSAR_TMP}/*") }

before { command }
before { command_output }

it { is_expected.to be_empty }
end
Expand All @@ -77,11 +83,12 @@
let(:output) { "Deployed your_app on staging!\n" }

it { is_expected.to match(output) }
it { expect(exit_status).to eq(0) }

context 'leaves the tmp folder empty' do
subject { Dir.glob("#{Pulsar::PULSAR_TMP}/*") }

before { command }
before { command_output }

it { is_expected.to be_empty }
end
Expand All @@ -94,11 +101,12 @@
let(:output) { "Deployed your_app on staging!\n" }

it { is_expected.to match(output) }
it { expect(exit_status).to eq(0) }

context 'leaves the tmp folder empty' do
subject { Dir.glob("#{Pulsar::PULSAR_TMP}/*") }

before { command }
before { command_output }

it { is_expected.to be_empty }
end
Expand All @@ -107,31 +115,35 @@
end

context 'when fails' do
subject { command }
subject { command_output }

context 'because of wrong directory' do
let(:repo) { './some-wrong-directory' }

it { is_expected.to match("Failed to deploy blog on production.\n") }
it { expect(exit_status).to eq(1) }
end

context 'because of empty directory' do
let(:repo) { RSpec.configuration.pulsar_empty_conf_path }

it { is_expected.to match("Failed to deploy blog on production.\n") }
it { is_expected.to match "No application found on repository #{RSpec.configuration.pulsar_empty_conf_path}\n" }
it { expect(exit_status).to eq(1) }
end

context 'because Bundler failed' do
let(:repo) { RSpec.configuration.pulsar_wrong_bundle_conf_path }

it { is_expected.to match("Failed to deploy blog on production.\n") }
it { expect(exit_status).to eq(1) }
end

context 'because Capistrano failed' do
let(:repo) { RSpec.configuration.pulsar_wrong_cap_conf_path }

it { is_expected.to match("Failed to deploy blog on production.\n") }
it { expect(exit_status).to eq(1) }
end

context 'because the application does not exists in the repository' do
Expand All @@ -140,6 +152,7 @@
let(:environment) { 'staging' }

it { is_expected.to match("The application foobuzz does not exist in your repository") }
it { expect(exit_status).to eq(1) }
end

context 'because the environment does not exists for the application' do
Expand All @@ -148,11 +161,13 @@
let(:environment) { 'foobuzz' }

it { is_expected.to match("The application blog does not have an environment called foobuzz") }
it { expect(exit_status).to eq(1) }

context 'but \'no application error\' message takes precedence' do
let(:app) { 'foobuzz' }

it { is_expected.to match("The application foobuzz does not exist in your repository") }
it { expect(exit_status).to eq(1) }
end
end
end
Expand Down
18 changes: 12 additions & 6 deletions spec/features/install_spec.rb
Original file line number Diff line number Diff line change
@@ -1,34 +1,39 @@
require 'spec_helper'

RSpec.describe 'Install' do
subject { command }
subject { command_output }

let(:command) do
`#{RSpec.configuration.pulsar_command} install #{arguments}`
Pulsar::Executor.sh("#{RSpec.configuration.pulsar_command} install #{arguments}")
end
let(:command_output) { command[:output] }
let(:exit_status) { command[:status] }

let(:arguments) { nil }

context 'via a subcommand named install' do
subject { -> { command } }
subject { -> { command_output } }

let(:error) { /Could not find command/ }

it { is_expected.not_to output(error).to_stderr_from_any_process }
it { expect(exit_status).to eq(0) }
end

context 'when succeeds' do
it { is_expected.to eql "Successfully created intial repo!\n" }

context 'creates a directory' do
subject { -> { command } }
subject { -> { command_output } }

it { expect(exit_status).to eq(0) }

context 'with the basic configuration' do
subject(:initial_pulsar_repo) do
Dir.entries('./../../../lib/pulsar/generators/initial_repo/')
end

before { command }
before { command_output }

it 'contains the initial directory structure' do
is_expected.to eql Dir.entries('./pulsar-conf')
Expand Down Expand Up @@ -58,9 +63,10 @@
it { is_expected.to match "Failed to create intial repo.\n" }

context 'does not create a directory' do
subject { -> { command } }
subject { -> { command_output } }

it { is_expected.not_to change { File.exist?('./my-dir') }.from(false) }
it { expect(exit_status).to eq(1) }
end
end
end
Loading