├── .gitignore ├── .ruby-gemset ├── .ruby-version ├── Gemfile ├── Guardfile ├── MIT-License ├── README.md ├── Rakefile ├── lib ├── pgbackups-archive.rb ├── pgbackups-archive │ ├── job.rb │ ├── railtie.rb │ ├── storage.rb │ └── version.rb └── tasks │ ├── pgbackups_archive.rake │ └── test.rake ├── pgbackups-archive.gemspec └── test ├── ci ├── before_script.sh └── ci_runner.sh ├── lib └── pgbackups-archive │ ├── job_test.rb │ └── storage_test.rb ├── support └── mocha.rb └── test_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.gem 3 | coverage 4 | /Gemfile.lock 5 | -------------------------------------------------------------------------------- /.ruby-gemset: -------------------------------------------------------------------------------- 1 | pgbackups-archive 2 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | ruby-2.3.1 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gemspec 4 | -------------------------------------------------------------------------------- /Guardfile: -------------------------------------------------------------------------------- 1 | guard "minitest" do 2 | # with Minitest::Spec 3 | watch(%r|^test/(.*)_test\.rb$|) 4 | watch(%r|^lib/(.*)([^/]+)\.rb$|) { |m| "test/#{m[1]}#{m[2]}_test.rb" } 5 | watch(%r|^test/test_helper\.rb$|) { "test" } 6 | watch(%r|^test/support/|) { "test" } 7 | end 8 | -------------------------------------------------------------------------------- /MIT-License: -------------------------------------------------------------------------------- 1 | Copyright 2015 Kenny Johnston 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pgbackups-archive 2 | 3 | [![Gem Version](https://badge.fury.io/rb/pgbackups-archive.svg)](http://badge.fury.io/rb/pgbackups-archive) 4 | [![Code Climate](https://codeclimate.com/github/kjohnston/pgbackups-archive/badges/gpa.svg)](https://codeclimate.com/github/kjohnston/pgbackups-archive) 5 | 6 | A means of automating Heroku PGBackups and archiving them to Amazon S3. 7 | 8 | ## This Project is No Longer Active 9 | 10 | As of June 29, 2018, Heroku has [yanked](https://rubygems.org/gems/heroku/versions) the older versions of the [Heroku Legacy CLI](https://github.com/heroku/legacy-cli) that the `pgbackups-archive` gem depends on. As a result, you should discontinue use of `pgbackups-archive`. 11 | 12 | If you're looking for a similar means of replicating Heroku database backups to Amazon S3, please see the [heroku-database-backups](https://github.com/kbaum/heroku-database-backups) project. 13 | 14 | 15 | ## Overview 16 | 17 | The `pgbackups:archive` rake task this gem provides will capture a Heroku PGBackup, wait for it to complete, then store it within the Amazon S3 bucket you specify. This rake task can be scheduled via the Heroku Scheduler, thus producing automated, offsite, backups. 18 | 19 | This gem doesn't interfere with or utilze automated backups, so feel free to schedule those with the `pg:backups schedule` command as you desire. 20 | 21 | You can configure how many manual backups (created by you or this gem) you'd like to keep at the Heroku PGBackups level to ensure there is always space to capture a new backup. 22 | 23 | You can configure retention settings at the Amazon S3 bucket level from within the AWS Console if you like. 24 | 25 | ## Use 26 | 27 | ### Install the gem 28 | 29 | Add the gem to your Gemfile and bundle: 30 | 31 | gem "pgbackups-archive" 32 | bundle install 33 | 34 | ### Install Heroku Scheduler add-on 35 | 36 | heroku addons:create scheduler 37 | 38 | ### Setup an AWS IAM user, S3 bucket and policy 39 | 40 | A good security measure would be to use a dedicated set of AWS credentials with a security policy only allowing access to the bucket you're specifying. See this Pro Tip on [Assigning an AWS IAM user access to a single S3 bucket](http://coderwall.com/p/dwhlma). 41 | 42 | ### Apply Environment Variables 43 | 44 | # Required 45 | heroku config:add HEROKU_API_KEY="collaborator-api-key" 46 | heroku config:add PGBACKUPS_APP="myapp" 47 | heroku config:add PGBACKUPS_AWS_ACCESS_KEY_ID="XXX" 48 | heroku config:add PGBACKUPS_AWS_SECRET_ACCESS_KEY="YYY" 49 | heroku config:add PGBACKUPS_BUCKET="myapp-backups" 50 | heroku config:add PGBACKUPS_REGION="us-west-2" 51 | 52 | # Optional: If you wish to backup a database other than the one that 53 | # DATABASE_URL points to, set this to the name of the variable for that 54 | # database (useful for follower databases). 55 | heroku config:add PGBACKUPS_DATABASE="HEROKU_POSTGRESQL_BLACK_URL" 56 | 57 | ### Add the rake task to scheduler 58 | 59 | heroku addons:open scheduler 60 | 61 | Then specify `rake pgbackups:archive` as a task you would like to run at any of the available intervals. 62 | 63 | In case you would like to make backups at different intervals simply "protect" a daily task using a bash if-statement, for example to run a task every 1st day in a month: 64 | 65 | if [ "$(date +%d)" = 01 ]; then rake pgbackups:archive; fi 66 | 67 | ### Loading the Rake task 68 | 69 | If you're using this gem in a Rails 3+ app the rake task will be automatically loaded via a Railtie. 70 | 71 | If you're using this gem with a Rails 2 app, or non-Rails app, add the following to your Rakefile: 72 | 73 | ```ruby 74 | require "pgbackups-archive" 75 | ``` 76 | 77 | ## Testing 78 | 79 | To run the test suite, use the `guard` command and save a file or hit enter to run the full suite. 80 | 81 | Use the [pgbackups-archive-dummy](https://github.com/kjohnston/pgbackups-archive-dummy) test harness to setup a dummy database on Heroku to test against. 82 | 83 | ## Disclaimer 84 | 85 | I shouldn't have to say this, but I will. Your backups are your responsibility. Take charge of ensuring that they run, archive and can be restored periodically as expected. Don't rely on Heroku, this gem, or anything else out there to substitute for a regimented database backup and restore testing strategy. 86 | 87 | ## Contributing 88 | 89 | 1. Fork it 90 | 2. Create your feature branch (`git checkout -b my-new-feature`) 91 | 3. Commit your changes (`git commit -am 'Added some feature'`) 92 | 4. Push to the branch (`git push origin my-new-feature`) 93 | 5. Create a Pull Request 94 | 95 | ## Contributors 96 | 97 | Many thanks go to the following who have contributed to making this gem even better: 98 | 99 | * Robert Bousquet ([@bousquet](https://github.com/bousquet)) 100 | * Autoload rake task into Rails 2.x once the gem has been loaded 101 | * Daniel Morrison ([@danielmorrison](https://github.com/danielmorrison)) 102 | * Ruby 1.8-compatible hash syntax 103 | * Karl Baum ([@kbaum](https://github.com/kbaum)) 104 | * Custom setting for database to backup 105 | * Streaming support to handle large backup files 106 | * Conroy Whitney ([@conroywhitney](https://github.com/conroywhitney)) 107 | * Use S3 server-side encryption by default 108 | * Chris Gaffney ([@gaffneyc](https://github.com/gaffneyc)) 109 | * Switch from fog to fog-aws 110 | * Gem config improvements 111 | * Juraj Masar ([@jurajmasar](https://github.com/jurajmasar)) 112 | * Fix for reading env var 113 | * Cutom multipart chunk size 114 | * Jan Stastny ([@jstastny](https://github.com/jstastny)) 115 | * Custom multipart chunk size 116 | 117 | ## License 118 | 119 | * Freely distributable and licensed under the [MIT license](http://kjohnston.mit-license.org/license.html). 120 | * Copyright (c) 2012-2016 [Kenny Johnston](https://github.com/kjohnston) 121 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | 3 | require "bundler/gem_tasks" 4 | 5 | load "tasks/pgbackups_archive.rake" 6 | 7 | require "rake/testtask" 8 | 9 | Rake::TestTask.new(:test) do |t| 10 | t.libs << "lib" 11 | t.libs << "test" 12 | t.pattern = "test/**/*_test.rb" 13 | t.verbose = false 14 | end 15 | 16 | task default: :test 17 | -------------------------------------------------------------------------------- /lib/pgbackups-archive.rb: -------------------------------------------------------------------------------- 1 | module PgbackupsArchive 2 | require "pgbackups-archive/job" 3 | require "pgbackups-archive/railtie" 4 | require "pgbackups-archive/storage" 5 | end 6 | -------------------------------------------------------------------------------- /lib/pgbackups-archive/job.rb: -------------------------------------------------------------------------------- 1 | require "heroku/command/pg" 2 | require "heroku/command/pg_backups" 3 | require "heroku/api" 4 | require "tmpdir" 5 | 6 | class PgbackupsArchive::Job 7 | 8 | attr_reader :client 9 | attr_accessor :backup_url, :created_at 10 | 11 | def self.call 12 | new.call 13 | end 14 | 15 | def initialize(attrs={}) 16 | Heroku::Command.load 17 | @client = Heroku::Command::Pg.new([], :app => ENV["PGBACKUPS_APP"]) 18 | end 19 | 20 | def call 21 | # expire # Disabled b/c Heroku seems to be keeping only 2 on its own 22 | capture 23 | download 24 | archive 25 | delete 26 | end 27 | 28 | def archive 29 | if PgbackupsArchive::Storage.new(key, file).store 30 | client.display "Backup archived" 31 | end 32 | end 33 | 34 | def capture 35 | attachment = client.send(:generate_resolver).resolve(database) 36 | backup = client.send(:hpg_client, attachment).backups_capture 37 | client.send(:poll_transfer, "backup", backup[:uuid]) 38 | 39 | self.created_at = backup[:created_at] 40 | 41 | self.backup_url = Heroku::Client::HerokuPostgresqlApp 42 | .new(ENV["PGBACKUPS_APP"]).transfers_public_url(backup[:num])[:url] 43 | end 44 | 45 | def delete 46 | File.delete(temp_file) 47 | end 48 | 49 | def download 50 | File.open(temp_file, "wb") do |output| 51 | streamer = lambda do |chunk, remaining_bytes, total_bytes| 52 | output.write chunk 53 | end 54 | 55 | # https://github.com/excon/excon/issues/475 56 | Excon.get backup_url, 57 | :response_block => streamer, 58 | :omit_default_port => true 59 | end 60 | end 61 | 62 | def expire 63 | transfers = client.send(:hpg_app_client, ENV["PGBACKUPS_APP"]).transfers 64 | .select { |b| b[:from_type] == "pg_dump" && b[:to_type] == "gof3r" } 65 | .sort_by { |b| b[:created_at] } 66 | 67 | if transfers.size > pgbackups_to_keep 68 | backup_id = "b%03d" % transfers.first[:num] 69 | backup_num = client.send(:backup_num, backup_id) 70 | 71 | expire_backup(backup_num) 72 | 73 | client.display "Backup #{backup_id} expired" 74 | end 75 | end 76 | 77 | private 78 | 79 | def expire_backup(backup_num) 80 | client.send(:hpg_app_client, ENV["PGBACKUPS_APP"]) 81 | .transfers_delete(backup_num) 82 | end 83 | 84 | def database 85 | ENV["PGBACKUPS_DATABASE"] || "DATABASE_URL" 86 | end 87 | 88 | def environment 89 | defined?(Rails) ? Rails.env : nil 90 | end 91 | 92 | def file 93 | File.open(temp_file, "r") 94 | end 95 | 96 | def key 97 | timestamp = created_at.gsub(/\/|\:|\.|\s/, "-").concat(".dump") 98 | ["pgbackups", environment, timestamp].compact.join("/") 99 | end 100 | 101 | def pgbackups_to_keep 102 | ENV["PGBACKUPS_KEEP"] ? ENV["PGBACKUPS_KEEP"].to_i : 30 103 | end 104 | 105 | def temp_file 106 | "#{Dir.tmpdir}/pgbackup" 107 | end 108 | 109 | end 110 | -------------------------------------------------------------------------------- /lib/pgbackups-archive/railtie.rb: -------------------------------------------------------------------------------- 1 | if defined?(Rails) 2 | if Rails.version < "3" 3 | load "tasks/pgbackups_archive.rake" 4 | else 5 | module PgbackupsArchive 6 | class Railtie < Rails::Railtie 7 | rake_tasks do 8 | load "tasks/pgbackups_archive.rake" 9 | end 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/pgbackups-archive/storage.rb: -------------------------------------------------------------------------------- 1 | require "fog/aws" 2 | require "open-uri" 3 | 4 | class PgbackupsArchive::Storage 5 | 6 | def initialize(key, file) 7 | @key = key 8 | @file = file 9 | end 10 | 11 | def connection 12 | Fog::Storage.new({ 13 | :provider => "AWS", 14 | :aws_access_key_id => ENV["PGBACKUPS_AWS_ACCESS_KEY_ID"], 15 | :aws_secret_access_key => ENV["PGBACKUPS_AWS_SECRET_ACCESS_KEY"], 16 | :region => ENV["PGBACKUPS_REGION"], 17 | :persistent => false 18 | }) 19 | end 20 | 21 | def bucket 22 | connection.directories.get ENV["PGBACKUPS_BUCKET"] 23 | end 24 | 25 | def store 26 | options = {:key => @key, :body => @file, :public => false, :encryption => "AES256"} 27 | 28 | if ENV["PGBACKUPS_MULTIPART_CHUNK_SIZE"] 29 | options.merge!(:multipart_chunk_size => ENV["PGBACKUPS_MULTIPART_CHUNK_SIZE"].to_i) 30 | end 31 | 32 | bucket.files.create(options) 33 | end 34 | 35 | end 36 | -------------------------------------------------------------------------------- /lib/pgbackups-archive/version.rb: -------------------------------------------------------------------------------- 1 | module PgbackupsArchive 2 | VERSION = "1.1.0" 3 | end 4 | -------------------------------------------------------------------------------- /lib/tasks/pgbackups_archive.rake: -------------------------------------------------------------------------------- 1 | namespace :pgbackups do 2 | 3 | desc "Capture a Heroku PGBackups backup and archive it to Amazon S3." 4 | task :archive do 5 | PgbackupsArchive::Job.call 6 | end 7 | 8 | end 9 | -------------------------------------------------------------------------------- /lib/tasks/test.rake: -------------------------------------------------------------------------------- 1 | require "rake/testtask" 2 | 3 | task default: :test 4 | 5 | Rake::TestTask.new(:test) do |t| 6 | t.libs << "lib" 7 | t.libs << "test" 8 | t.pattern = "test/**/*_test.rb" 9 | t.verbose = false 10 | end 11 | -------------------------------------------------------------------------------- /pgbackups-archive.gemspec: -------------------------------------------------------------------------------- 1 | $:.push File.expand_path("../lib", __FILE__) 2 | 3 | require "pgbackups-archive/version" 4 | 5 | Gem::Specification.new do |s| 6 | s.name = "pgbackups-archive" 7 | s.version = PgbackupsArchive::VERSION 8 | s.platform = Gem::Platform::RUBY 9 | s.authors = ["Kenny Johnston"] 10 | s.email = ["kjohnston.ca@gmail.com"] 11 | s.homepage = "http://github.com/kjohnston/pgbackups-archive" 12 | s.summary = %q{Automates archival of Heroku PGBackups to S3} 13 | s.description = %q{A means of automating Heroku PGBackups and archiving them to Amazon S3.} 14 | s.license = "MIT" 15 | 16 | s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] 17 | s.test_files = Dir["test/**/*"] 18 | 19 | # Heroku PGBackups launched when 3.28.6 shipped (replacing older PG Backups). 20 | # v3.33 changes its internal API to v4. 21 | s.add_runtime_dependency "heroku", ">= 3.28.6", "<= 3.32" 22 | s.add_runtime_dependency "heroku-api", "~> 0.3.23" 23 | 24 | s.add_runtime_dependency "fog-aws" 25 | s.add_runtime_dependency "rake" 26 | 27 | s.add_development_dependency "bundler" 28 | s.add_development_dependency "guard", "~> 2.12", "~> 2.12.5" 29 | s.add_development_dependency "guard-minitest", "~> 2.3", ">= 2.3.2" 30 | s.add_development_dependency "minitest-rails", "~> 2.1", ">= 2.1.0" 31 | s.add_development_dependency "mocha", "~> 1.1", ">= 1.1.0" 32 | s.add_development_dependency "simplecov", "~> 0.9", ">= 0.9.1" 33 | end 34 | -------------------------------------------------------------------------------- /test/ci/before_script.sh: -------------------------------------------------------------------------------- 1 | # Add instructions to execute before your CI run here. 2 | # 3 | # The following is used for testing a Rails Engine with a dummy test app. 4 | # 5 | # cd test/dummy 6 | # RAILS_ENV=test bundle exec rake db:setup 7 | -------------------------------------------------------------------------------- /test/ci/ci_runner.sh: -------------------------------------------------------------------------------- 1 | engine=$(ruby -e 'puts RUBY_ENGINE') 2 | 3 | case $engine in 4 | "ruby" ) 5 | bundle exec rake test && bundle exec cane;; 6 | * ) 7 | bundle exec rake test;; 8 | esac 9 | -------------------------------------------------------------------------------- /test/lib/pgbackups-archive/job_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | describe PgbackupsArchive::Job do 4 | 5 | describe ".call" do 6 | it { PgbackupsArchive::Job.must_respond_to(:call) } 7 | end 8 | 9 | describe "instance methods" do 10 | before do 11 | @app = "foobar" 12 | ENV["PGBACKUPS_APP"] = @app 13 | @job = PgbackupsArchive::Job.new 14 | @client = @job.client 15 | @backup_url = "https://raw.githubusercontent.com/kjohnston/pgbackups-archive/master/pgbackups-archive.gemspec" 16 | @created_at = Time.now 17 | end 18 | 19 | describe "#initialize" do 20 | it do 21 | @client.must_be_kind_of(Heroku::Command::Pg) 22 | @client.options[:app].must_equal @app 23 | end 24 | end 25 | 26 | describe "#call" do 27 | before do 28 | @job.expects(:capture) 29 | @job.expects(:download) 30 | @job.expects(:archive) 31 | @job.expects(:delete) 32 | end 33 | 34 | it { @job.call } 35 | end 36 | 37 | describe "#archive" do 38 | before do 39 | @key = "some-key" 40 | @file = "some-file" 41 | @job.stubs(:key).returns(@key) 42 | @job.stubs(:file).returns(@file) 43 | 44 | PgbackupsArchive::Storage.expects(:new).with(@key, @file) 45 | .returns(mock(store: true)) 46 | 47 | @client.expects(:display) 48 | end 49 | 50 | it { @job.archive } 51 | end 52 | 53 | describe "#capture" do 54 | before do 55 | @client.stubs(:generate_resolver).returns(mock(:resolve)) 56 | @client.stubs(:hpg_client) 57 | .returns( 58 | mock(backups_capture: { 59 | uuid: "baz", 60 | num: "10", 61 | created_at: @created_at } 62 | ) 63 | ) 64 | @client.stubs(:poll_transfer) 65 | 66 | Heroku::Client::HerokuPostgresqlApp.expects(:new).with(@app) 67 | .returns(mock(transfers_public_url: { url: @backup_url })) 68 | end 69 | 70 | it do 71 | @job.capture 72 | @job.created_at.must_equal @created_at 73 | @job.backup_url.must_equal @backup_url 74 | end 75 | end 76 | 77 | describe "#delete" do 78 | it do 79 | @temp_file = @job.send(:temp_file) 80 | File.write(@temp_file, "content") 81 | File.exist?(@temp_file).must_equal true 82 | @job.delete 83 | File.exist?(@temp_file).must_equal false 84 | end 85 | end 86 | 87 | describe "#download" do 88 | before { @job.backup_url = @backup_url } 89 | 90 | it do 91 | @job.download 92 | @job.send(:file).read.must_match(/Gem::Specification/) 93 | end 94 | end 95 | 96 | describe "#expire" do 97 | before do 98 | @transfers = [ 99 | { from_type: "pg_dump", to_type: "gof3r", created_at: Date.today, num: 20 }, 100 | { from_type: "pg_dump", to_type: "gof3r", created_at: Date.today-2, num: 17 }, 101 | { from_type: "pg_dump", to_type: "gof3r", created_at: Date.today-1, num: 18 }, 102 | { from_type: "pg_dump", to_type: "foo", created_at: Date.today-1, num: 19 } 103 | ] 104 | 105 | @client.expects(:hpg_app_client).with(@app).returns(mock(transfers: @transfers)) 106 | end 107 | 108 | describe "when slots are available" do 109 | it "does not expire a backup" do 110 | @job.expire 111 | end 112 | end 113 | 114 | describe "when a slot needs to be freed" do 115 | before do 116 | ENV["PGBACKUPS_KEEP"] = "2" 117 | @client.expects(:backup_num).with("b017").returns("017") 118 | @job.expects(:expire_backup).with("017") 119 | @client.expects(:display) 120 | end 121 | 122 | it "expires a backup" do 123 | @job.expire 124 | end 125 | end 126 | end 127 | 128 | end 129 | 130 | end 131 | -------------------------------------------------------------------------------- /test/lib/pgbackups-archive/storage_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | describe PgbackupsArchive::Storage do 4 | before do 5 | Fog.mock! 6 | 7 | @connection = Fog::Storage.new( 8 | provider: "AWS", 9 | aws_access_key_id: "XXX", 10 | aws_secret_access_key: "YYY" 11 | ) 12 | @bucket = @connection.directories.create(key: "someapp-backups") 13 | @key = "pgbackups/test/2012-08-02-12-00-00.dump" 14 | @file = "test" 15 | @storage = PgbackupsArchive::Storage.new(@key, @file) 16 | 17 | @storage.stubs(:connection).returns(@connection) 18 | @storage.stubs(:bucket).returns(@bucket) 19 | end 20 | 21 | it "should create a fog connection" do 22 | @storage.connection.class.must_equal Fog::Storage::AWS::Mock 23 | end 24 | 25 | it "should create a fog directory" do 26 | @storage.bucket.class.must_equal Fog::Storage::AWS::Directory 27 | end 28 | 29 | it "should create a fog file" do 30 | @storage.store.class.must_equal Fog::Storage::AWS::File 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /test/support/mocha.rb: -------------------------------------------------------------------------------- 1 | require "mocha/setup" 2 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | Dir[File.dirname(__FILE__) + "/../lib/**/*.rb"].each { |f| require f } 2 | 3 | IS_RAKE_TASK = (!! ($0 =~ /rake/)) 4 | 5 | if IS_RAKE_TASK 6 | require "simplecov" 7 | SimpleCov.start "rails" do 8 | add_filter "db" 9 | add_filter "test" 10 | add_filter "config" 11 | end 12 | end 13 | 14 | require "minitest/autorun" 15 | require "minitest/pride" 16 | 17 | Dir[File.join("./test/support/**/*.rb")].sort.each { |f| require f } 18 | --------------------------------------------------------------------------------