veksel 0.1.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 91758ab594f11138bbfb291449ca7a89e5de19e6cee85e024a2bb03b7c3056d1
4
- data.tar.gz: 28935ca101031e85fa0a86e5163408b5fc5cf2c25a8cea9b3c351901a04e96cd
3
+ metadata.gz: 5ea3fcb9a16045af635f30b41e951e002e82d3f9de54c2b015f183069bf96a27
4
+ data.tar.gz: db4756858dac59fe8e26b67c9d0498aa5bf34eae6c88b4cadc61b1cd326b4c4d
5
5
  SHA512:
6
- metadata.gz: 22592284f0ad8be05605deaed84019da1a8b3c136cd8a1492680a6a83424ad3307193c74b44c5c581fadf9f63efe66e848c0b1f2b7933748c2215f937bf334ff
7
- data.tar.gz: 1ed0d8d73e466a24e2cac00a4d334cfb834a3df7c03a621c34015dc05172c0abb8088c70984614d9dd0e4cf7e77fa2f37c5e72756c4ed0336ae8e521c61b2dc5
6
+ metadata.gz: 2b10cd547c563757d88b93e8293b1e3243d1d962708729c6faf1b90e16b8b75de89b52dff3e74d45b9a36ff470fbc6ddb20fdd922fae2c20aa23f9dfaac526e7
7
+ data.tar.gz: 23ddfb9527f9ebbee6f6e91bc01553261f0985170ac27aeef8d9717c6d307fd111c5d00b620d04a7043092a7d8f0ff7c2c2be67450003f69286b034a09b3467b
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
- Change the following line in `config/database.yml`
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
- ```yaml
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
- Checkout a new branch and run `bin/rails veksel:fork`. A new database with a suffix matching your branch name will be created.
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:clean Delete forked databases
22
- veksel:fork Fork the database from the main branch
23
- veksel:list List forked databases
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
- bin/rails veksel:fork
37
+ bundle exec veksel fork
33
38
  ```
34
39
 
35
40
  ## Installation
@@ -58,6 +63,31 @@ $ gem install veksel
58
63
  - Explicit/optional branching
59
64
  - Other database drivers
60
65
 
66
+ ## Publishing
67
+
68
+ Veksel is published and distributed on [rubygems](https://rubygems.org).
69
+
70
+ To publish a new version:
71
+
72
+ ```shell
73
+ # Update changelog, review manually before committing
74
+ conventional-changelog -p conventionalcommits -i CHANGELOG.md -s
75
+ git commit -m 'chore(release): x.y.z'
76
+ git push origin
77
+ git tag vx.y.z
78
+ git push origin vx.y.z
79
+
80
+ # Build and push gem
81
+ gem build
82
+ gem push veksel-x.y.z.gem
83
+
84
+ # Upload the veksel-x-y-z.gem file to the Github release page
85
+ ```
86
+
87
+ ## Sponsors
88
+
89
+ Veksel is sponsored by [Skalar](https://github.com/Skalar)
90
+
61
91
  ## License
62
92
 
63
93
  Veksel is licensed under MIT.
data/bin/veksel CHANGED
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
- require 'veksel'
2
+ require 'veksel/cli'
3
3
 
4
4
  case ARGV[0]
5
5
  when 'suffix'
6
- print Veksel.suffix
6
+ Veksel::CLI.suffix
7
+ when 'fork'
8
+ Veksel::CLI.fork
7
9
  end
@@ -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: ['db:create', 'veksel:precreate'] do
16
- next if Veksel.skip_fork?
17
- require 'veksel/commands/fork'
3
+ task :fork do
4
+ require 'veksel/cli'
18
5
 
19
- db = ActiveRecord::Base.configurations.find_db_config('development')
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,28 @@
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
+ require 'fileutils'
17
+
18
+ config = Psych.safe_load(File.read('config/database.yml'), aliases: true)['development'].transform_keys(&:to_sym)
19
+ target_database = config[:database] + Veksel.suffix
20
+ db = OpenStruct.new(configuration_hash: config, database: target_database)
21
+ Veksel::Commands::Fork.new(db).perform
22
+
23
+ duration = ((Time.now.to_f - t1) * 1000).to_i
24
+ FileUtils.touch('tmp/restart.txt')
25
+ puts "Forked database in #{duration.to_i}ms"
26
+ end
27
+ end
28
+ end
@@ -15,9 +15,8 @@ module Veksel
15
15
  def perform
16
16
  return if pg_cluster.target_populated?(target_db)
17
17
 
18
- ActiveSupport::Notifications.instrument "veksel.fork", source: source_db, target: target_db do
19
- pg_cluster.transfer(from: source_db, to: target_db)
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
@@ -15,14 +15,12 @@ module Veksel
15
15
  end
16
16
  end
17
17
 
18
- def transfer(from:, to:)
19
- r, w = IO.pipe(autoclose: true)
20
- spawn(pg_env, "pg_dump #{pg_connection_args(from)} --format=c", out: w)
21
- pid_psql = spawn(pg_env, "pg_restore --single-transaction --exit-on-error #{pg_connection_args(to)}", in: r)
22
- unless Process::Status.wait(pid_psql).success?
23
- # TODO: Write error log to a tempfile inside the tmp directory of the current directory
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:)
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Veksel
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.1"
3
3
  end
data/lib/veksel.rb CHANGED
@@ -15,7 +15,7 @@ module Veksel
15
15
  end
16
16
 
17
17
  def skip_fork?
18
- suffix.blank?
18
+ suffix.to_s.strip.empty?
19
19
  end
20
20
 
21
21
  def suffix
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.1.0
4
+ version: 0.2.1
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-27 00:00:00.000000000 Z
11
+ date: 2024-03-10 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: '6'
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: '6'
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