schema_dev 0.1.5 → 0.1.6

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
  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