Using pg_partman with Rails and HerokuCI
I worked around this by installing pg_partman as part of the db:structure:load_if_sql
task when it detects its on HerokuCI with In-Dyno Postgres.
Rake::Task["db:structure:load_if_sql"].enhance [:install_pg_partman]private def heroku_ci? ENV["CI"]endprivate def in_dyno_postgres? File.exist?("/app/.indyno/vendor/postgresql")endprivate def install_pg_partman system './bin/install-pg-partman'endtask :install_pg_partman do # Heroku In-Dyno Postgres does not have pg_partman. if heroku_ci? && in_dyno_postgres? puts 'installing pg_partman' install_pg_partman endend
And bin/install-pg-partman
.
#!/bin/bashREPO_URL=${REPO_URL='https://github.com/pgpartman/pg_partman.git'}BUILD_DIR=${BUILD_DIR=tmp}PG_CONFIG=${PG_CONFIG='/app/.indyno/vendor/postgresql/bin/pg_config'}if [ ! -f "$PG_CONFIG" ]; then echo "Cannot find ${PG_CONFIG}" exit 1;ficd tmprm -rf pg_partmangit clone ${REPO_URL}cd pg_partmanmake install PG_CONFIG=${PG_CONFIG} NO_BGW=1
With tests.
require 'rails_helper'RSpec.describe 'rake install_pg_partman' do let(:task) { Rake::Task['install_pg_partman'] } before do # Otherwise if you call the same task twice it will think # it's already been done and skip it or re-raise the same exception. task.reenable end shared_context "with CI", temp_env: true do before { ENV["CI"] = "true" } end shared_context "with in-dyno postgres" do before { allow(File).to receive(:exist?) .with("/app/.indyno/vendor/postgresql") .and_return(true) } end shared_examples "it does not install" do it 'does not install' do expect(task).not_to receive(:install_pg_partman) task.invoke end end it 'is a prerequisite of db:structure:load_if_sql' do expect( Rake::Task["db:structure:load_if_sql"].prerequisite_tasks ).to include(task) end context 'no CI, no in-dyno postgres' do it_behaves_like 'it does not install' end context 'when in CI, but no in-dyno postgres' do include_context "with CI" it_behaves_like 'it does not install' end context 'with in-dyno postgres, but not in CI' do include_context "with in-dyno postgres" it_behaves_like 'it does not install' end context 'when in CI and with in-dyno postgres', temp_env: true do include_context "with CI" include_context "with in-dyno postgres" let(:pg_config_path) { "/does/not/exist/pg_config" } before { ENV["PG_CONFIG"] = pg_config_path } it 'tries to install' do expect(task.send(:heroku_ci?)).to be_truthy expect(task.send(:in_dyno_postgres?)).to be_truthy expect { task.invoke }.to output(/Cannot find #{pg_config_path}/).to_stdout_from_any_process end endend