veksel 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +19 -10
- data/bin/veksel +4 -2
- data/lib/tasks/veksel_tasks.rake +3 -17
- data/lib/veksel/cli.rb +27 -0
- data/lib/veksel/commands/fork.rb +2 -3
- data/lib/veksel/pg_cluster.rb +6 -8
- data/lib/veksel/railtie.rb +18 -0
- data/lib/veksel/version.rb +1 -1
- data/lib/veksel.rb +1 -1
- metadata +5 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fefca18b79ef6e7d59bb87305e52f31c2b5016f960456a60855cfec795b5bcff
|
4
|
+
data.tar.gz: e0784682f14fdfd8e5e0c80f7b131f3f9d30db7c4f24f77bab82fd0aa00baeca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a601171ac3e739e271232190e6100b8dc9e5742165366827f7ef05c34301140e637fc81a4ec463b458b337f1a5cd62b593edc476160ce3381953fbe3c67a526
|
7
|
+
data.tar.gz: d01186ca6393d3e12d1c084a5711279a67e82ab5c0bcdb001f741f5f2bd83faab2fb2ff51722bff5c302fe64922a8b62ed433600b8d46d095cb5af768effee58
|
data/README.md
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/veksel.svg)](https://rubygems.org/gems/veksel)
|
2
|
+
[![Build status](https://github.com/theodorton/veksel/actions/workflows/test.yml/badge.svg?branch=main&event=push)](https://github.com/theodorton/veksel/actions?query=event%3Apush+branch%3Amain)
|
3
|
+
|
1
4
|
# Veksel: Database branching for Rails
|
2
5
|
|
3
6
|
Veksel keeps seperate databases for every branch in your development environment. This makes it easy to experiment with schema changes and data with less risk and avoid conflicting changes to `schema.rb` when branches have different sets of migrations. The inspiration for the gem came from [branch support in Neon](https://neon.tech/docs/manage/branches).
|
@@ -6,30 +9,32 @@ Postgresql is currently the only supported database driver.
|
|
6
9
|
|
7
10
|
## Usage
|
8
11
|
|
9
|
-
|
12
|
+
Out of the box, Veksel requires explicit invocation to work. Refer to [Git hook](#git-hook) below if you're interested in a more automated approach.
|
10
13
|
|
11
|
-
|
12
|
-
development:
|
13
|
-
database: your_app_development<%= `bundle exec veksel suffix` %>
|
14
|
-
```
|
14
|
+
Checkout a new branch and run `bundle exec veksel fork`. A new database with a suffix matching your branch name will be created and `tmp/restart.txt` will be touched so your application servers restart. Both database structure and contents will be copied from your primary development database and Veksel will tell Rails on boot that the forked database should be used.
|
15
15
|
|
16
|
-
|
16
|
+
When moving back to your `main` branch, run `touch tmp/restart.txt` to make Rails connect to default development database.
|
17
17
|
|
18
18
|
### Veksel tasks
|
19
19
|
|
20
|
+
The CLI supports the following commands
|
21
|
+
|
20
22
|
```
|
21
|
-
veksel
|
22
|
-
veksel
|
23
|
-
veksel
|
23
|
+
veksel fork Create a forked database
|
24
|
+
veksel clean Delete forked databases
|
25
|
+
veksel fork Fork the database from the main branch
|
26
|
+
veksel list List forked databases
|
24
27
|
```
|
25
28
|
|
29
|
+
You can also run the commands as rake tasks (e.g. `bin/rails veksel:list`), albeit with a penalty hit.
|
30
|
+
|
26
31
|
## Git hook
|
27
32
|
|
28
33
|
Add the following to `.git/hooks/post-checkout` to automatically fork your database when checking out a branch:
|
29
34
|
|
30
35
|
```
|
31
36
|
#!/bin/sh
|
32
|
-
|
37
|
+
bundle exec veksel fork
|
33
38
|
```
|
34
39
|
|
35
40
|
## Installation
|
@@ -58,6 +63,10 @@ $ gem install veksel
|
|
58
63
|
- Explicit/optional branching
|
59
64
|
- Other database drivers
|
60
65
|
|
66
|
+
## Sponsors
|
67
|
+
|
68
|
+
Veksel is sponsored by [Skalar](https://github.com/Skalar)
|
69
|
+
|
61
70
|
## License
|
62
71
|
|
63
72
|
Veksel is licensed under MIT.
|
data/bin/veksel
CHANGED
data/lib/tasks/veksel_tasks.rake
CHANGED
@@ -1,23 +1,9 @@
|
|
1
1
|
namespace :veksel do
|
2
|
-
task :precreate do
|
3
|
-
ActiveSupport::Notifications.subscribe "veksel.fork" do |*args|
|
4
|
-
event = ActiveSupport::Notifications::Event.new(*args)
|
5
|
-
puts "Forked database in #{event.duration.to_i}ms"
|
6
|
-
File.open("log/veksel.log", "a") do |f|
|
7
|
-
f.puts("Forked database in #{event.duration.to_i}ms")
|
8
|
-
f.puts(" Source: #{event.payload[:source]}")
|
9
|
-
f.puts(" Target: #{event.payload[:target]}")
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
2
|
desc "Fork the database from the main branch"
|
15
|
-
task fork
|
16
|
-
|
17
|
-
require 'veksel/commands/fork'
|
3
|
+
task :fork do
|
4
|
+
require 'veksel/cli'
|
18
5
|
|
19
|
-
|
20
|
-
Veksel::Commands::Fork.new(db).perform
|
6
|
+
Veksel::CLI.fork
|
21
7
|
end
|
22
8
|
|
23
9
|
desc "List forked databases"
|
data/lib/veksel/cli.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'veksel'
|
2
|
+
|
3
|
+
module Veksel
|
4
|
+
module CLI
|
5
|
+
def self.suffix
|
6
|
+
print Veksel.suffix
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.fork
|
10
|
+
return if Veksel.skip_fork?
|
11
|
+
t1 = Time.now.to_f
|
12
|
+
|
13
|
+
require 'veksel/commands/fork'
|
14
|
+
require 'psych'
|
15
|
+
require 'ostruct'
|
16
|
+
|
17
|
+
config = Psych.safe_load(File.read('config/database.yml'), aliases: true)['development'].transform_keys(&:to_sym)
|
18
|
+
target_database = config[:database] + Veksel.suffix
|
19
|
+
db = OpenStruct.new(configuration_hash: config, database: target_database)
|
20
|
+
Veksel::Commands::Fork.new(db).perform
|
21
|
+
|
22
|
+
duration = ((Time.now.to_f - t1) * 1000).to_i
|
23
|
+
FileUtils.touch('tmp/restart.txt')
|
24
|
+
puts "Forked database in #{duration.to_i}ms"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/veksel/commands/fork.rb
CHANGED
@@ -15,9 +15,8 @@ module Veksel
|
|
15
15
|
def perform
|
16
16
|
return if pg_cluster.target_populated?(target_db)
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
end
|
18
|
+
pg_cluster.kill_connection(source_db)
|
19
|
+
pg_cluster.create_database(target_db, template: source_db)
|
21
20
|
end
|
22
21
|
end
|
23
22
|
end
|
data/lib/veksel/pg_cluster.rb
CHANGED
@@ -15,14 +15,12 @@ module Veksel
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
raise "pg_restore failed with status #{status.exitstatus}"
|
25
|
-
end
|
18
|
+
def kill_connection(dbname)
|
19
|
+
system(pg_env, %[psql #{pg_connection_args('postgres')} -c "select pg_terminate_backend(pid) from pg_stat_activity where datname = '#{dbname}' and pid <> pg_backend_pid();"], exception: true, out: '/dev/null')
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_database(dbname, template:)
|
23
|
+
system(pg_env, %[createdb --no-password --template=#{template} #{dbname}], exception: true)
|
26
24
|
end
|
27
25
|
|
28
26
|
def list_databases(prefix:)
|
data/lib/veksel/railtie.rb
CHANGED
@@ -3,5 +3,23 @@ module Veksel
|
|
3
3
|
rake_tasks do
|
4
4
|
load "tasks/veksel_tasks.rake"
|
5
5
|
end
|
6
|
+
|
7
|
+
initializer "my_railtie.configure_rails_initialization", before: "active_record.initialize_database" do |app|
|
8
|
+
require 'veksel/pg_cluster'
|
9
|
+
require 'active_record/database_configurations'
|
10
|
+
|
11
|
+
ActiveRecord::DatabaseConfigurations.register_db_config_handler do |env_name, name, url, config|
|
12
|
+
next if url.present?
|
13
|
+
next unless env_name == 'development' || env_name == 'test'
|
14
|
+
|
15
|
+
if PgCluster.new(config).target_populated?("#{config[:database]}#{Veksel.suffix}")
|
16
|
+
ActiveRecord::DatabaseConfigurations::HashConfig.new(env_name, name, config.merge({
|
17
|
+
database: "#{config[:database]}#{Veksel.suffix}"
|
18
|
+
}))
|
19
|
+
else
|
20
|
+
ActiveRecord::DatabaseConfigurations::HashConfig.new(env_name, name, config)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
6
24
|
end
|
7
25
|
end
|
data/lib/veksel/version.rb
CHANGED
data/lib/veksel.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: veksel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Theodor Tonum
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-02-
|
11
|
+
date: 2024-02-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -16,7 +16,7 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 7.1.0
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
22
|
version: '8'
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
29
|
+
version: 7.1.0
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: '8'
|
@@ -58,20 +58,6 @@ dependencies:
|
|
58
58
|
- - ">="
|
59
59
|
- !ruby/object:Gem::Version
|
60
60
|
version: '0'
|
61
|
-
- !ruby/object:Gem::Dependency
|
62
|
-
name: appraisal
|
63
|
-
requirement: !ruby/object:Gem::Requirement
|
64
|
-
requirements:
|
65
|
-
- - ">="
|
66
|
-
- !ruby/object:Gem::Version
|
67
|
-
version: '0'
|
68
|
-
type: :development
|
69
|
-
prerelease: false
|
70
|
-
version_requirements: !ruby/object:Gem::Requirement
|
71
|
-
requirements:
|
72
|
-
- - ">="
|
73
|
-
- !ruby/object:Gem::Version
|
74
|
-
version: '0'
|
75
61
|
description: Seperate databases for every branch in your development environment
|
76
62
|
email:
|
77
63
|
- theodor@tonum.no
|
@@ -86,6 +72,7 @@ files:
|
|
86
72
|
- bin/veksel
|
87
73
|
- lib/tasks/veksel_tasks.rake
|
88
74
|
- lib/veksel.rb
|
75
|
+
- lib/veksel/cli.rb
|
89
76
|
- lib/veksel/commands/clean.rb
|
90
77
|
- lib/veksel/commands/fork.rb
|
91
78
|
- lib/veksel/pg_cluster.rb
|