3

我正在尝试使用 Heroku 的 CI 来运行我的 Rails 应用程序的测试,但是在尝试加载我的structure.sql文件时遇到了问题。

-----> Preparing test database
       Running: rake db:schema:load_if_ruby
       db:schema:load_if_ruby completed (3.24s)
       Running: rake db:structure:load_if_sql
       psql:/app/db/structure.sql:28: ERROR:  must be owner of extension plpgsql
       rake aborted!
       failed to execute:
       psql -v ON_ERROR_STOP=1 -q -f /app/db/structure.sql d767koa0m1kne1
       Please check the output above for any errors and make sure that `psql` is installed in your PATH and has proper permissions.
       /app/vendor/bundle/ruby/2.4.0/gems/activerecord-5.1.1/lib/active_record/tasks/postgresql_database_tasks.rb:108:in `run_cmd'
       /app/vendor/bundle/ruby/2.4.0/gems/activerecord-5.1.1/lib/active_record/tasks/postgresql_database_tasks.rb:80:in `structure_load'
       /app/vendor/bundle/ruby/2.4.0/gems/activerecord-5.1.1/lib/active_record/tasks/database_tasks.rb:223:in `structure_load'
       /app/vendor/bundle/ruby/2.4.0/gems/activerecord-5.1.1/lib/active_record/tasks/database_tasks.rb:236:in `load_schema'
       /app/vendor/bundle/ruby/2.4.0/gems/activerecord-5.1.1/lib/active_record/tasks/database_tasks.rb:255:in `block in load_schema_current'
       /app/vendor/bundle/ruby/2.4.0/gems/activerecord-5.1.1/lib/active_record/tasks/database_tasks.rb:304:in `block in each_current_configuration'
       /app/vendor/bundle/ruby/2.4.0/gems/activerecord-5.1.1/lib/active_record/tasks/database_tasks.rb:303:in `each'
       /app/vendor/bundle/ruby/2.4.0/gems/activerecord-5.1.1/lib/active_record/tasks/database_tasks.rb:303:in `each_current_configuration'
       /app/vendor/bundle/ruby/2.4.0/gems/activerecord-5.1.1/lib/active_record/tasks/database_tasks.rb:254:in `load_schema_current'
       /app/vendor/bundle/ruby/2.4.0/gems/activerecord-5.1.1/lib/active_record/railties/databases.rake:290:in `block (3 levels) in <top (required)>'
       /app/vendor/bundle/ruby/2.4.0/gems/activerecord-5.1.1/lib/active_record/railties/databases.rake:294:in `block (3 levels) in <top (required)>'
       /app/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/exe/rake:27:in `<top (required)>'
       Tasks: TOP => db:structure:load
       (See full trace by running task with --trace)
 !
 !     Could not prepare database for test
 !

这里的相关行是:

psql:/app/db/structure.sql:28: 错误: 必须是扩展 plpgsql rake 的所有者已中止!

Structure.sql 包含这一行:

COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';

关于如何在 Heroku 的 CI 上工作的任何想法?

4

4 回答 4

11

最终覆盖db:structure:dump以删除COMMENT ON ...语句:

namespace :db do
  namespace :structure do
    task dump: [:environment, :load_config] do
      filename = ENV["SCHEMA"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "structure.sql")
      sql = File.read(filename).each_line.grep_v(/\ACOMMENT ON EXTENSION.+/).join

      File.write(filename, sql)
    end
  end
end
于 2017-05-24T23:55:39.037 回答
5

另一种解决方法是添加类似

if Rails.env.development?
  ActiveRecord::Tasks::DatabaseTasks.structure_load_flags = ["-v", "ON_ERROR_STOP=0"]
end

在执行之前的初始化/任务管道中的任何位置db:structure:load

于 2018-06-18T18:50:39.707 回答
2

如果 Kyle 的解决方案还不够,并且错误不仅仅是由对扩展的注释引起的,而是由实际的扩展安装引起的,您仍然可以采取艰难的方式并将其添加到初始化程序中:

# This is a temporary workaround for the Rails issue #29049.
# It could be safely removed when the PR #29110 got merged and released
# to use instead IGNORE_PG_LOAD_ERRORS=1.

module ActiveRecord
   module Tasks
     class PostgreSQLDatabaseTasks
       ON_ERROR_STOP_1 = 'ON_ERROR_STOP=0'.freeze
     end
   end
end

注意:这不是 Heroku 特有的,而是更广泛的 Rails 5.1 问题

于 2017-09-27T04:42:42.527 回答
1

这个问题有两种解决方案。首先,如前所述,禁用该ON_ERROR_STOP功能。无论环境如何,它都会有所帮助。自定义 rake 任务:

namespace :db do
  namespace :structure do
      # This little task is a workaround for a problem introduced in Rails5. Most specificaly here
      # https://github.com/rails/rails/blob/5-1-stable/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb#L77
      # When psql encounters an error during loading of the structure it exits at once with error code 1.
      # And this happens on heroku. It renders review apps and heroku CI unusable if you use a structure instead of a schema.
      # Why?
      # Our `db/structure.sql` contains entries like `CREATE EXTENSION` or `COMMENT ON EXTENSION`.
      # Zylion of extensions on heroku are loaded in template0, so "our" db also has them, but because of that
      # only a superuser (or owner of template0) has access to them - not our heroku db user. For that reason
      # we can neither create an extension (it already exists, but that is not a problem, because dump contains IF NOT EXIST)
      # nor comment on it (and comments don't have IF NOT EXIST directive). And that's an error which could be safely ignored
      # but which stops loading of the rest of the structure.
      desc "Disable exit-on-error behaviour when loading db structure in postgresql"
      task disable_errors: :environment do
        ActiveRecord::Tasks::DatabaseTasks.structure_load_flags = ["-v", "ON_ERROR_STOP=0"]
      end
    end
  end


# And use it like so:
bin/rails db:structure:disable_errors db:structure:load

在我看来,如果仅涉及 Heroku,则另一种选择是在in-dyno计划中使用 PostgreSQL(https://devcenter.heroku.com/articles/heroku-ci-in-dyno-databases),这基本上是一个数据库实例位于测功机中,因此我们可以完全访问它。此外,测试套件应该明显更快,因为我们使用本地主机连接,而不是通过网络连接。要启用它,请将您的app.json内容更改为具有如下条目:

{
  "environments": {
    "test": {
      "addons": [
        "heroku-postgresql:in-dyno"
      ]
    }
  }
}
于 2018-12-20T09:59:25.923 回答