{"id":13879860,"url":"https://github.com/ridgepole/ridgepole","last_synced_at":"2025-05-13T17:07:17.774Z","repository":{"id":37049671,"uuid":"21319293","full_name":"ridgepole/ridgepole","owner":"ridgepole","description":"Ridgepole is a tool to manage DB schema.  It defines DB schema using Rails DSL, and updates DB schema according to DSL. (like Chef/Puppet)","archived":false,"fork":false,"pushed_at":"2025-05-12T02:59:13.000Z","size":1854,"stargazers_count":1075,"open_issues_count":7,"forks_count":127,"subscribers_count":29,"default_branch":"3.0","last_synced_at":"2025-05-12T03:44:34.519Z","etag":null,"topics":["activerecord","mysql","postgresql","rails","ruby"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ridgepole.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2014-06-29T08:12:33.000Z","updated_at":"2025-05-12T02:59:16.000Z","dependencies_parsed_at":"2024-02-24T14:31:36.179Z","dependency_job_id":"0379b461-69f4-414d-9ae0-eb0b673626b1","html_url":"https://github.com/ridgepole/ridgepole","commit_stats":{"total_commits":1220,"total_committers":54,"mean_commits":22.59259259259259,"dds":0.7057377049180328,"last_synced_commit":"8900b42eba153dc0da302a52561c5bedf1f47738"},"previous_names":["winebarrel/ridgepole"],"tags_count":203,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ridgepole%2Fridgepole","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ridgepole%2Fridgepole/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ridgepole%2Fridgepole/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ridgepole%2Fridgepole/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ridgepole","download_url":"https://codeload.github.com/ridgepole/ridgepole/tar.gz/refs/heads/3.0","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253990466,"owners_count":21995774,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activerecord","mysql","postgresql","rails","ruby"],"created_at":"2024-08-06T08:02:36.261Z","updated_at":"2025-05-13T17:07:17.703Z","avatar_url":"https://github.com/ridgepole.png","language":"Ruby","readme":"# Ridgepole\n\nRidgepole is a tool to manage DB schema.\n\nIt defines DB schema using [Rails DSL](http://guides.rubyonrails.org/migrations.html#types-of-schema-dumps), and updates DB schema according to DSL.\n(like Chef/Puppet)\n\n[![Gem Version](https://badge.fury.io/rb/ridgepole.svg)](https://badge.fury.io/rb/ridgepole)\n[![test](https://github.com/ridgepole/ridgepole/actions/workflows/test.yml/badge.svg)](https://github.com/ridgepole/ridgepole/actions/workflows/test.yml)\n[![Coverage Status](https://coveralls.io/repos/github/ridgepole/ridgepole/badge.svg?branch=3.0)](https://coveralls.io/github/ridgepole/ridgepole?branch=3.0)\n\n\u003e [!note]\n\u003e * ridgepole v3.0.0\n\u003e   * Support Rails 8.0 (cf. https://github.com/ridgepole/ridgepole/pull/504)\n\u003e * ridgepole v2.0.0\n\u003e   * Support Trilogy (cf. https://github.com/ridgepole/ridgepole/pull/447)\n\u003e   * Support Rails 7.1 (cf. https://github.com/ridgepole/ridgepole/pull/441)\n\u003e   * Drop support AcriveRecord 6.0 (cf. https://github.com/ridgepole/ridgepole/pull/440)\n\u003e * Drop support ActiveRecord 5.x in ridgepole v1.2.0.\n\u003e * Partitioning is no longer supported in ridgepole v1.1.0.\n\u003e * ActiveRecord 7.x has some incompatible changes. If you get unintended differences in `datetime` columns consider changing `precision`:\n\u003e   * Add `precision: nil` for columns that previously had no `precision` specified (cf. https://github.com/ridgepole/ridgepole/issues/381)\n\u003e   * Remove `precision: 6` from columns that previously had `precision: 6` specified explicitly (cf. https://github.com/ridgepole/ridgepole/issues/406)\n\u003e * For ActiveRecord 7.x series, please use AcriveRecord 7.0.2 or higher / Ridgepole 1.0.3 or higher.\n\u003e   * cf. https://github.com/ridgepole/ridgepole/pull/380\n\u003e * ActiveRecord 6.1 is supported in ridgepole v0.9, but the ActiveRecord dump has been changed, so there is a difference between ActiveRecord 5.x/6.0 format.\n\u003e   * **If you use ActiveRecord 6.1, please modify Schemafile format**.\n\u003e   * cf. https://github.com/ridgepole/ridgepole/pull/323\n\u003e * `DROP TABLE` is skipped by default in v1.0 and later versions.\n\u003e   * If you want to `DROP TABLE`, please pass `--drop-table`.\n\u003e   * cf. https://github.com/ridgepole/ridgepole/pull/363\n\u003e * In Rails 7.0, the output of dumper is different from Rails 6.\n\u003e   * cf. https://github.com/rails/rails/issues/43909\n\u003e   * cf. https://github.com/rails/rails/commit/c2a6f618d22cca4d9b7be7fa7652e7aac509350c#diff-55f41513f027a3d219629f475f03c2d1105ca55c5093d691e1b3dc4710c6cc0b\n\u003e * SQLite does not support.\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n    gem 'ridgepole'\n\nAnd then execute:\n\n    $ bundle install\n\nOr install it yourself as:\n\n    $ gem install ridgepole\n\n## Help\n```\nUsage: ridgepole [options]\n    -c, --config CONF_OR_FILE\n    -E, --env ENVIRONMENT\n    -s, --spec-name SPEC_NAME\n    -a, --apply\n    -m, --merge\n    -f, --file SCHEMAFILE\n        --dry-run\n        --table-options OPTIONS\n        --table-hash-options OPTIONS\n        --alter-extra ALTER_SPEC\n        --external-script SCRIPT\n        --bulk-change\n        --default-bool-limit LIMIT\n        --default-int-limit LIMIT\n        --default-bigint-limit LIMIT\n        --default-float-limit LIMIT\n        --default-string-limit LIMIT\n        --default-text-limit LIMIT\n        --default-binary-limit LIMIT\n        --pre-query QUERY\n        --post-query QUERY\n    -e, --export\n        --split\n        --split-with-dir\n    -d, --diff DSL1 DSL2\n        --with-apply\n    -o, --output SCHEMAFILE\n    -t, --tables TABLES\n        --ignore-tables REGEX_LIST\n        --dump-without-table-options\n        --dump-with-default-fk-name\n        --index-removed-drop-column\n        --drop-table\n        --drop-table-only\n        --mysql-change-table-options\n        --mysql-change-table-comment\n        --check-relation-type DEF_PK\n        --ignore-table-comment\n        --skip-column-comment-change\n        --allow-pk-change\n        --create-table-with-index\n        --mysql-dump-auto-increment\n    -r, --require LIBS\n        --log-file LOG_FILE\n        --verbose\n        --debug\n        --[no-]color\n    -v, --version\n    -h, --help\n```\n\n## Usage\n\n```sh\n$ git init\nInitialized empty Git repository in ...\n\n$ cat config.yml\nadapter: mysql2\nencoding: utf8\ndatabase: blog\nusername: root\n\n$ ridgepole -c config.yml --export -o Schemafile\n# or `ridgepole -c '{adapter: mysql2, database: blog}' ...`\n# or `ridgepole -c 'mysql2://root:pass@127.0.0.1:3306/blog' ...`\n# or `export DB_URL='mysql2://...'; ridgepole -c env:DB_URL ...`\nExport Schema to `Schemafile`\n\n$ cat Schemafile\ncreate_table \"articles\", force: :cascade do |t|\n  t.string   \"title\"\n  t.text     \"text\"\n  t.datetime \"created_at\"\n  t.datetime \"updated_at\"\nend\n\n$ git add .\n$ git commit -m 'first commit'  -a\n[master (root-commit) a6c2d31] first commit\n 2 files changed, 10 insertions(+)\n create mode 100644 Schemafile\n create mode 100644 config.yml\n\n$ vi Schemafile\n$ git diff\ndiff --git a/Schemafile b/Schemafile\nindex f5848b9..c266fed 100644\n--- a/Schemafile\n+++ b/Schemafile\n@@ -1,6 +1,7 @@\n create_table \"articles\", force: :cascade do |t|\n   t.string   \"title\"\n   t.text     \"text\"\n+  t.text     \"author\"\n   t.datetime \"created_at\"\n   t.datetime \"updated_at\"\n end\n\n$ ridgepole -c config.yml --apply --dry-run\nApply `Schemafile` (dry-run)\nadd_column(\"articles\", \"author\", :text, {:after=\u003e\"text\"})\n\n# ALTER TABLE `articles` ADD `author` text AFTER `text`\n\n$ ridgepole -c config.yml --apply\nApply `Schemafile`\n-- add_column(\"articles\", \"author\", :text, {:after=\u003e\"text\"})\n   -\u003e 0.0202s\n```\n\n## Rename\n```ruby\ncreate_table \"articles\", force: :cascade do |t|\n  t.string   \"title\"\n  t.text     \"desc\", renamed_from: \"text\"\n  t.text     \"author\"\n  t.datetime \"created_at\"\n  t.datetime \"updated_at\"\nend\n\ncreate_table \"user_comments\", force: :cascade, renamed_from: \"comments\" do |t|\n  t.string   \"commenter\"\n  t.text     \"body\"\n  t.integer  \"article_id\"\n  t.datetime \"created_at\"\n  t.datetime \"updated_at\"\nend\n```\n\n## Foreign Key\n```ruby\ncreate_table \"parent\", force: :cascade do |t|\nend\n\ncreate_table \"child\", id: false, force: :cascade do |t|\n  t.bigint \"id\"\n  t.bigint \"parent_id\"\nend\n\nadd_index \"child\", [\"parent_id\"], name: \"par_ind\", using: :btree\n\nadd_foreign_key \"child\", \"parent\", name: \"child_ibfk_1\"\n```\n\n## Ignore Column/Index/FK\n\n```ruby\ncreate_table \"articles\", force: :cascade do |t|\n  t.string   \"title\", ignore: true # All changes are ignored\n  t.text     \"desc\", renamed_from: \"text\"\n  t.text     \"author\"\n  t.datetime \"created_at\"\n  t.datetime \"updated_at\"\nend\n```\n\n## Collation/Charset\n\n```ruby\ncreate_table \"articles\", force: :cascade, options: \"ENGINE=InnoDB DEFAULT CHARSET=utf8\" do |t|\n  t.string   \"title\",                    collation: \"ascii_bin\"\n  t.text     \"text\",       null: false,  collation: \"utf8mb4_bin\"\n  t.datetime \"created_at\"\n  t.datetime \"updated_at\"\nend\n```\n\nCharset:\n\nactiverecord 5.0.0 and activerecord-mysql-awesome dumps a collation rather than charset because it does not determine the default collation for charset. Specifying a collation for each column would work if it is possible.\n\nSee `mysql\u003e show character set;` to find charset / collation pair for your system.\n\n## Generated Column (MySQL)\n\nThere should be NO extra white spaces in the expression (such as after comma).\nQuotes in expression may cause the operations failure with MySQL 8.0.\n\n```ruby\ncreate_table \"users\", force: :cascade do |t|\n  t.string   \"last_name\"\n  t.string   \"first_name\"\n  t.virtual  \"full_name\", type: :string, as: \"concat(`last_name`,' ',`first_name`)\", stored: true\nend\n```\n\n## Execute\n```ruby\ncreate_table \"authors\", force: :cascade do |t|\n  t.string \"name\", null: false\nend\n\ncreate_table \"books\", force: :cascade do |t|\n  t.string  \"title\",     null: false\n  t.integer \"author_id\", null: false\nend\n\nadd_index \"books\", [\"author_id\"], name: \"idx_author_id\", using: :btree\n\nexecute(\"ALTER TABLE books ADD CONSTRAINT fk_author FOREIGN KEY (author_id) REFERENCES authors (id)\") do |c|\n  # Execute SQL only if there is no foreign key\n  c.raw_connection.query(\u003c\u003c-SQL).each.size.zero?\n    SELECT 1 FROM information_schema.key_column_usage\n     WHERE TABLE_SCHEMA = 'bookshelf'\n       AND CONSTRAINT_NAME = 'fk_author' LIMIT 1\n  SQL\nend\n```\n\n## Diff\n```sh\n$ ridgepole --diff file1.schema file2.schema\nadd_column(\"articles\", \"author\", :text, {:after=\u003e\"title\"})\nrename_column(\"articles\", \"text\", \"desc\")\n\n# You can apply to the database the difference:\n# $ ridgepole -c config.yml --diff file1.schema file2.schema --with-apply\n```\n\nYou can also compare databases and files.\n\n```sh\n$ ridgepole --diff config.yml file1.schema\nremove_column(\"articles\", \"author\")\n```\n\n## Execute SQL using external script\n\n```sh\n$ cat test.sh\n#!/bin/sh\nSQL=\"$1\"\nCONFIG_JSON=\"$2\"\necho \"$SQL\" | mysql -u root my_db\n\n$ ridgepole -c config.yml --apply --external-script ./test.sh\n```\n\n## Add extra statement to ALTER\n\n```sh\n$ ridgepole -a -c database.yml --alter-extra=\"LOCK=NONE\" --debug\nApply `Schemafile`\n...\n-- add_column(\"dept_manager\", \"to_date2\", :date, {:null=\u003efalse, :after=\u003e\"from_date\"})\n   (42.2ms)  ALTER TABLE `dept_manager` ADD `to_date2` date NOT NULL AFTER `from_date`,LOCK=NONE\n   -\u003e 0.0428s\n-- remove_column(\"dept_manager\", \"to_date\")\n   (46.9ms)  ALTER TABLE `dept_manager` DROP `to_date`,LOCK=NONE\n   -\u003e 0.0471s\n```\n\n## Relation column type check\n\n```ruby\ncreate_table \"employees\", force: :cascade do |t|\n  t.integer \"emp_no\", null: false\n  t.string  \"first_name\", limit: 14, null: false\n  t.string  \"last_name\", limit: 16, null: false\nend\n\ncreate_table \"dept_manager\", force: :cascade do |t|\n  t.integer \"employee_id\"\n  t.string  \"dept_no\", limit: 4, null: false\nend\n```\n\n```sh\n$ ridgepole -a -c database.yml --check-relation-type bigint # default primary key type (e.g. bigint for MySQL)\nApply `Schemafile`\n...\n[WARNING] Relation column type is different.\n              employees.id: bigint\n  dept_manager.employee_id: integer\n...\n```\n\n## Run tests\n\n\n```sh\ndocker compose up -d\nbundle install\nbundle exec appraisal install\nbundle exec appraisal activerecord-7.0 rake\n# POSTGRESQL=1 bundle exec appraisal activerecord-7.0 rake\n# MYSQL80=1 bundle exec appraisal activerecord-7.0 rake\n```\n\n\u003e [!note]\n\u003e mysql-client/postgresql-client is required for testing.\n\n## Demo\n\n* [asciinema.org/a/9349](https://asciinema.org/a/9349)\n* [asciinema.org/a/11788](https://asciinema.org/a/11788)\n\n## Example project\n\n* https://github.com/winebarrel/ridgepole-example\n  * https://github.com/winebarrel/ridgepole-example/pull/1\n  * https://github.com/winebarrel/ridgepole-example/pull/2\n","funding_links":[],"categories":["Ruby"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fridgepole%2Fridgepole","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fridgepole%2Fridgepole","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fridgepole%2Fridgepole/lists"}