schema_dev 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b7390fc8e1c5cff8d04697e1110ee58bc6a11eaa
4
- data.tar.gz: 8f573ecb8ee744283534ba12dca609325985d449
3
+ metadata.gz: 32da67245032f4e8dda3169be236b050bcbfa230
4
+ data.tar.gz: 5c4863f4241688f83166c82d7e3357e06b80f8b6
5
5
  SHA512:
6
- metadata.gz: b770a4fd5e143dc40b8e619281c595e44bb047cd96f0e7cec4f38eb3b51a827136328a03fa703a0816876844579574f53003c4048fca977e5f3089ebccdd72bd
7
- data.tar.gz: 0a2686a017ae65bf1746187a796ebb99e4f10ea6951a82e34117a379388fd87ee63ee8c3cd10c89d565c7bfd3fece000740890174c48ca4eca75a6aace558276
6
+ metadata.gz: ee070648972f48f9ecea215559dd141d81d1d88a5b6b0ff14c29cf27a3bad69e660af2493296c518f5cd50547e207ca072ef3a794fbb3db345f6ecaced996a77
7
+ data.tar.gz: 5b6566b814e841dc3e1321c74a05ce77c9df92634cdc5e26c92936d70a97a9232666af72f0fadc72d5d0101681ba53edba95aaad1af852ea75ee8609b67c37b9
data/README.md CHANGED
@@ -1,15 +1,93 @@
1
1
  # SchemaDev
2
2
 
3
- Development tools for the SchemaPlus family of gems
3
+ [![Gem Version](https://badge.fury.io/rb/schema_dev.png)](http://badge.fury.io/rb/schema_dev)
4
+
5
+ Development tools for the SchemaPlus family of gems.
6
+
7
+ Provides support for working with multiple ruby versions, rails adapaters, and db versions. In particular provides a command `schema_dev` for running rspec (or whatever) on the matrix or a slice or element of it. It also auto-generates the `.travis.yml` file for [travis-ci](https://travis-ci.org) testing.
4
8
 
5
9
  ## Installation
6
10
 
7
- Include this as a development dependency in a .gemfile:
11
+ Include this as a development dependency in the client gem's `<ame>.gemfile`:
12
+
13
+ s.add_development_dependency "schema_dev"
14
+
15
+ ## Setup
16
+
17
+ #### `schema_dev.yml`
18
+
19
+ The client gem needs a file `schema_dev.yml` in it's root, which specifies the testing matrix, among other things.
20
+
21
+ * `ruby`: A single version of ruby, or a list of ruby versions.
22
+ * `rails`: A single version of rails, or a list of rails versions
23
+ * `db`: (Optional) The list of db adapters to test. Leave this out if the gem will hardwire its tests for a single adapter.
24
+ * `quick`: (Optional) Hash listing the version of ruby, rails, and db to use with `--quick` option. If not specified, the default is to use the last entry in each list.
25
+
26
+ #### Gemfiles
27
+
28
+ The client gem must organize its Gemfiles along the lines of:
29
+
30
+ gemfiles/rails-4.0/Gemfile.postgresql # if testing against multiple db adapter
31
+
32
+ gemfiles/Gemfile-rails.4.0 # if hardwired to a single db adapter
33
+
34
+ #### Rspec
35
+
36
+ The client gem should include this in its `spec/spec_helper`
37
+
38
+ require 'schema_dev/rspec'
39
+ SchemaDev::Rspec.setup_db # if testing against multiple dbs, the db will be filled in automatically
40
+ SchemaDev::Rspec.setup_db 'sqlite3' # to hardwire a single database
41
+
42
+ This will take care of connecting to the test database appropriately, and will set up logging to a file specific to the test matrix cell.
43
+
44
+ #### Rake
45
+
46
+ The client gem should include this in its `Rakefile`:
47
+
48
+ require 'schema_dev/tasks'
49
+
50
+ ### Ruby selection
51
+
52
+ You must have one of [chruby](https://github.com/postmodern/chruby), [rbenv](https://github.com/sstephenson/rbenv) or [rvm](http://rvm.io) installed and working. Within it, have available whichever ruby versions you want to test.
53
+
54
+ ### Database
55
+
56
+ Of course you must have installed whichever database(s) you want to test.
57
+
58
+ For PostgreSQL and MySQL the tests need a db user with permissions to create and access databases: The default username used by the specs is 'schema_plus' for both PostgreSQL and MySQL; you can change them via:
59
+
60
+ $ export POSTGRESQL_DB_USER = pgusername
61
+ $ export MYSQL_DB_USER = mysqlusername
62
+
63
+ For PostgreSQL and MySQL you must explicitly create the databases used by the tests:
64
+
65
+ $ rake create_databases # creates postgresql and/or mysql as needed
66
+
67
+ ## Running The Tests
68
+
69
+ In the root directory, you can run, e.g.,
70
+
71
+ $ schema_dev bundle install
72
+ $ schema_dev rspec
73
+
74
+ Which will run those commands over the whole matrix. You can also specify slices, via any combination of `--ruby`, `--rails` and (if the gem tests multiple dbs) `--db`
75
+
76
+ $ schema_dev rspec --ruby 2.1.3 --rails 4.0
77
+
78
+ For convenience you can also use `--quick` to run just one as specified in `schema_dev.yml`
79
+
80
+ If you want to pass extra arguments to a command, make sure to use `--` to avoid them being processed by `schema_dev`. e.g.
81
+
82
+ $ schema_dev rspec --quick -- -e 'select which spec'
83
+
84
+ For more info, see
8
85
 
9
- ```ruby
10
- s.add_development_dependency "schema_dev"
11
- ```
86
+ $ schema_dev help
87
+ $ schema_dev help rspec # etc.
12
88
 
13
- ## Usage
89
+ ## Generating `.travis.yml`
14
90
 
91
+ To keep things in sync `.travis.yml` gets automatically updated whenever you run `schema_dev matrix` or any of its shorthands. There's also a command to just explicitly update `.travis.yml`
15
92
 
93
+ $ schema_dev travis
@@ -2,8 +2,8 @@
2
2
 
3
3
  require 'active_support/core_ext/hash'
4
4
  require 'thor'
5
- require 'schema_dev/config'
6
- require 'schema_dev/runner'
5
+ require_relative '../lib/schema_dev/config'
6
+ require_relative '../lib/schema_dev/runner'
7
7
 
8
8
  $config = SchemaDev::Config.load
9
9
  $runner = SchemaDev::Runner.new($config)
@@ -18,6 +18,11 @@ class CLI < Thor
18
18
  method_option :db, type: :string, desc: "Only execute for the specified database" if $config.db?
19
19
  end
20
20
 
21
+ desc "update .travis.yml", "create .travis.yml based on schema_dev.yml values"
22
+ def travis
23
+ $runner.travis
24
+ end
25
+
21
26
  desc "run command", "run a command over the matrix"
22
27
  matrix_options
23
28
  def matrix(*args)
@@ -12,7 +12,7 @@ module SchemaDev
12
12
 
13
13
  class Config
14
14
 
15
- attr_accessor :quick, :db
15
+ attr_accessor :quick, :db, :ruby, :rails, :notify, :exclude
16
16
 
17
17
  def self._reset ; @@config = nil end # for use by rspec
18
18
 
@@ -20,23 +20,6 @@ module SchemaDev
20
20
  @@config ||= new((YAML.load Pathname.new(CONFIG_FILE).read).symbolize_keys)
21
21
  end
22
22
 
23
- class Tuple < KeyStruct[:ruby, :rails, :db]
24
- def match?(other)
25
- return false if self.ruby and other.ruby and self.ruby != other.ruby
26
- return false if self.rails and other.rails and self.rails != other.rails
27
- return false if self.db and other.db and self.db != other.db
28
- true
29
- end
30
-
31
- def match_any?(others)
32
- others.any?{|other| self.match? other}
33
- end
34
-
35
- def to_hash
36
- super.reject{ |k, val| val.nil? }
37
- end
38
- end
39
-
40
23
  def initialize(opts={}) # once we no longer support ruby 1.9.3, can switch to native keyword args
41
24
  opts = opts.keyword_args(ruby: :required, rails: :required, db: nil, exclude: nil, notify: nil, quick: nil)
42
25
  @ruby = Array.wrap(opts.ruby)
@@ -51,8 +34,12 @@ module SchemaDev
51
34
  @db.any?
52
35
  end
53
36
 
37
+ def dbms
38
+ @dbms ||= [:postgresql, :mysql].select{|dbm| @db.grep(/^#{dbm}/).any?}
39
+ end
40
+
54
41
  def matrix(opts={}) # once we no longer support ruby 1.9.3, can switch to native keyword args
55
- opts = opts.keyword_args(quick: false, ruby: nil, rails: nil, db: nil)
42
+ opts = opts.keyword_args(quick: false, ruby: nil, rails: nil, db: nil, excluded: nil)
56
43
  use_ruby = @ruby
57
44
  use_rails = @rails
58
45
  use_db = @db
@@ -65,12 +52,37 @@ module SchemaDev
65
52
  use_rails = Array.wrap(opts.rails) if opts.rails
66
53
  use_db = Array.wrap(opts.db) if opts.db
67
54
 
68
- @matrix ||= begin
69
- m = use_ruby.product(use_rails)
70
- m = m.product(use_db).map(&:flatten) if db?
71
- m = m.map { |_ruby, _rails, _db| Tuple.new(ruby: _ruby, rails: _rails, db: _db) }
72
- m.reject(&it.match_any?(@exclude)).map(&:to_hash)
73
- end
55
+ use_ruby = [nil] unless use_ruby.any?
56
+ use_rails = [nil] unless use_rails.any?
57
+
58
+ m = use_ruby.product(use_rails)
59
+ m = m.product(use_db).map(&:flatten) if use_db.any?
60
+ m = m.map { |_ruby, _rails, _db| Tuple.new(ruby: _ruby, rails: _rails, db: _db) }.compact
61
+ m = m.reject(&it.match_any?(@exclude)) unless opts.excluded == :none
62
+ m = m.map(&:to_hash)
63
+
64
+ if opts.excluded == :only
65
+ return matrix(opts.merge(excluded: :none)) - m
66
+ else
67
+ return m
68
+ end
69
+ end
70
+
71
+ class Tuple < KeyStruct[:ruby, :rails, :db]
72
+ def match?(other)
73
+ return false if self.ruby and other.ruby and self.ruby != other.ruby
74
+ return false if self.rails and other.rails and self.rails != other.rails
75
+ return false if self.db and other.db and self.db != other.db
76
+ true
77
+ end
78
+
79
+ def match_any?(others)
80
+ others.any?{|other| self.match? other}
81
+ end
82
+
83
+ def to_hash
84
+ super.reject{ |k, val| val.nil? }
85
+ end
74
86
  end
75
87
 
76
88
  end
@@ -4,7 +4,9 @@ module SchemaDev
4
4
  GEMFILES_DIR = "gemfiles"
5
5
 
6
6
  module GemfileSelector
7
- def self.gemfile(opts = {})
7
+ extend self
8
+
9
+ def gemfile(opts = {})
8
10
  opts = opts.keyword_args(rails: :required, db: nil)
9
11
  root = Pathname.new(GEMFILES_DIR)
10
12
  if opts.db
@@ -14,12 +16,12 @@ module SchemaDev
14
16
  end
15
17
  end
16
18
 
17
- def self.command(opts={})
19
+ def command(opts={})
18
20
  opts = opts.keyword_args(rails: :required, db: nil)
19
21
  "BUNDLE_GEMFILE=#{gemfile(rails: opts.rails, db: opts.db)}"
20
22
  end
21
23
 
22
- def self.infer_db
24
+ def infer_db
23
25
  (env = ENV['BUNDLE_GEMFILE']) =~ %r{rails.*/Gemfile[.](.*)}
24
26
  $1 or raise "Can't infer db: Env BUNDLE_GEMFILE=#{env.inspect}) isn't a schema_dev Gemfile path with db"
25
27
  end
@@ -7,8 +7,8 @@ module SchemaDev
7
7
  module Db
8
8
  extend self
9
9
 
10
- def setup(db = nil)
11
- @db = db || GemfileSelector.infer_db
10
+ def setup(_db = nil)
11
+ @db = _db || GemfileSelector.infer_db
12
12
  set_logger
13
13
  connect
14
14
  RSpec.configure do |config|
@@ -19,7 +19,7 @@ module SchemaDev
19
19
  config.filter_run_excluding :mysql => :skip if Helpers.mysql?
20
20
  config.filter_run_excluding :sqlite3 => :only unless Helpers.sqlite3?
21
21
  config.filter_run_excluding :sqlite3 => :skip if Helpers.sqlite3?
22
- end
22
+ end unless _db
23
23
  end
24
24
 
25
25
  def tmproot
@@ -1,6 +1,7 @@
1
1
  require 'shellwords'
2
2
 
3
3
  require_relative 'matrix_executor'
4
+ require_relative 'travis'
4
5
 
5
6
  module SchemaDev
6
7
  class Runner
@@ -8,7 +9,13 @@ module SchemaDev
8
9
  @config = config
9
10
  end
10
11
 
11
- def run(*args, dry_run: false, quick: false, ruby: nil, rails: nil, db: nil)
12
+ def travis
13
+ Travis.update(@config)
14
+ end
15
+
16
+ def run(*args, dry_run: false, quick: false, ruby: nil, rails: nil, db: nil, freshen: true)
17
+ self.travis if freshen
18
+
12
19
  matrix = MatrixExecutor.new @config.matrix(quick: quick, ruby: ruby, rails: rails, db: db)
13
20
 
14
21
  return true if matrix.run(Shellwords.join(args.flatten), dry_run: dry_run)
@@ -1,11 +1,9 @@
1
1
  require_relative 'config'
2
2
 
3
- config = SchemaDev::Config.load
3
+ dbms = SchemaDev::Config.load.dbms
4
4
 
5
5
  DATABASES = %w[schema_plus_test]
6
6
 
7
- dbms = [:postgresql, :mysql].select{|dbm| config.db.grep(/^#{dbm}/).any?}
8
-
9
7
  if dbms.any?
10
8
  {
11
9
  postgresql: { uservar: 'POSTGRESQL_DB_USER', defaultuser: 'schema_plus', create: "createdb -U '%{user}' %{dbname}", drop: "dropdb -U '%{user}' %{dbname}" },
@@ -0,0 +1,48 @@
1
+ require 'pathname'
2
+ require 'yaml'
3
+
4
+ module SchemaDev
5
+ TRAVIS_FILE = ".travis.yml"
6
+
7
+ module Travis
8
+ extend self
9
+
10
+ def build(config)
11
+ env = 'POSTGRESQL_DB_USER=postgres MYSQL_DB_USER="travis"'
12
+ gemfiles = config.matrix.map{|entry| GemfileSelector.gemfile(entry.slice(:rails, :db)).to_s}.uniq
13
+ exclude = config.matrix(excluded: :only).map { |entry| {}.tap {|ex|
14
+ ex["rvm"] = entry[:ruby]
15
+ ex["gemfile"] = GemfileSelector.gemfile(entry.slice(:rails, :db)).to_s
16
+ ex["env"] = env if config.dbms.any?
17
+ }}.reject{|ex| not gemfiles.include? ex["gemfile"]}
18
+
19
+ {}.tap { |travis|
20
+ travis["rvm"] = config.ruby.sort
21
+ travis["gemfile"] = gemfiles.sort
22
+ if config.dbms.any?
23
+ travis["before_script"] = 'bundle exec rake create_databases'
24
+ travis["after_script"] = 'bundle exec rake drop_databases'
25
+ travis["env"] = env
26
+ end
27
+ travis["notifications"] = { "email" => config.notify } if config.notify.any?
28
+ travis["matrix"] = { "exclude" => exclude.sort_by{|ex| [ex["rvm"], ex["gemfile"]]} } if exclude.any?
29
+ }
30
+ end
31
+
32
+ def update(config)
33
+ filepath = Pathname.new(TRAVIS_FILE)
34
+ newtravis = build(config)
35
+ oldtravis = YAML.load(filepath.read) rescue nil
36
+ if oldtravis != newtravis
37
+ header = <<-ENDYAML
38
+ # This file was auto-generated by the schema_dev tool, based on the data in
39
+ # ./schema_dev.yml
40
+ # Please do not edit this file; any changes will be overwritten next time
41
+ # schema_dev gets run.
42
+ ENDYAML
43
+ filepath.write header + newtravis.to_yaml
44
+ puts "* Updated #{filepath}"
45
+ end
46
+ end
47
+ end
48
+ end
@@ -1,3 +1,3 @@
1
1
  module SchemaDev
2
- VERSION = "0.1.5"
2
+ VERSION = "0.1.6"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: schema_dev
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - ronen barzel
@@ -161,6 +161,7 @@ files:
161
161
  - lib/schema_dev/ruby_selector.rb
162
162
  - lib/schema_dev/runner.rb
163
163
  - lib/schema_dev/tasks.rb
164
+ - lib/schema_dev/travis.rb
164
165
  - lib/schema_dev/version.rb
165
166
  - schema_dev.gemspec
166
167
  - schema_dev.yml