Skip to content

Instantly share code, notes, and snippets.

@stephancom
Last active September 29, 2022 04:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stephancom/8d51297da75ec2323492a342752699bf to your computer and use it in GitHub Desktop.
Save stephancom/8d51297da75ec2323492a342752699bf to your computer and use it in GitHub Desktop.
guard for destructive rake tasks
# _ _ _ _
# __| | ___ ___| |_ _ __ _ _ ___| |_(_)_ _____
# / _` |/ _ \/ __| __| '__| | | |/ __| __| \ \ / / _ \
# | (_| | __/\__ \ |_| | | |_| | (__| |_| |\ V / __/
# \__,_|\___||___/\__|_| \__,_|\___|\__|_| \_/ \___|
# handy guard for destructive rake tasks
# just include this before any troublesome task
# typical usage:
# task :riskytask, [:destructive, :environment] do
# found here:
# http://technotes.iangreenleaf.com/posts/confirmation-for-destructive-rake-tasks.html
class Nope < RuntimeError; end
task :destructive do
puts 'This task is destructive! Are you sure you want to continue? [y/N]'
input = $stdin.gets.chomp
raise Nope unless input.casecmp('y').zero?
end
RSpec.describe 'rake destructive', type: :task do
around do |example|
suppress_stdout(&example)
end
it 'has no prerequisites' do
expect(task.prerequisites).to be_empty
end
describe 'warning message' do
around do |example|
fake_stdin('y', &example)
end
it 'should warn that the task is destructive' do
expect { task.execute }.to output(/destructive/).to_stdout
end
it 'should ask if the user wants to continue' do
expect { task.execute }.to output(/continue\?/).to_stdout
end
end
describe 'response to input' do
it 'succeeds when user says y' do
fake_stdin('y') do
expect { task.execute }.not_to raise_exception
end
end
it 'succeeds when user says Y (upper case)' do
fake_stdin('Y') do
expect { task.execute }.not_to raise_exception
end
end
it 'terminates when user says n' do
fake_stdin('n') do
expect { task.execute }.to raise_exception Nope
end
end
it 'terminates when user says N (upper case)' do
fake_stdin('n') do
expect { task.execute }.to raise_exception Nope
end
end
it 'terminates when user says neither y nor n' do
fake_stdin('meh') do
expect { task.execute }.to raise_exception Nope
end
end
end
end
# https://www.eliotsykes.com/test-rails-rake-tasks-with-rspec
require 'rake'
# Task names should be used in the top-level describe, with an optional
# "rake "-prefix for better documentation. Both of these will work:
#
# 1) describe "foo:bar" do ... end
#
# 2) describe "rake foo:bar" do ... end
#
# Favor including "rake "-prefix as in the 2nd example above as it produces
# doc output that makes it clear a rake task is under test and how it is
# invoked.
module TaskExampleGroup
extend ActiveSupport::Concern
included do
let(:task_name) { self.class.top_level_description.sub(/\Arake /, '') }
let(:tasks) { Rake::Task }
# Make the Rake task available as `task` in your examples:
subject(:task) { tasks[task_name] }
end
end
RSpec.configure do |config|
# Tag Rake specs with `:task` metadata or put them in the spec/tasks dir
config.define_derived_metadata(file_path: %r{/spec/tasks/}) do |metadata|
metadata[:type] = :task
end
config.include TaskExampleGroup, type: :task
config.before(:suite) do
Rails.application.load_tasks
end
end
@stephancom
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment