migrake 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES ADDED
@@ -0,0 +1,12 @@
1
+ 0.2.0 - April 15, 2012
2
+ ----------------------
3
+
4
+ - Refactored Store into FileSystemStore, make it swappable
5
+ - Added FileSystemStore#prepare
6
+ - Clean up the generated Rake tasks.
7
+ - Change Migrake::Runner.run to Migrake.run.
8
+
9
+ 0.1.0 - April 15, 2012
10
+ ----------------------
11
+
12
+ Initial release! :party:
data/README.md CHANGED
@@ -45,26 +45,37 @@ check that file, see which tasks in the set aren't in it, and will run those
45
45
  tasks (no order is guaranteed, if you need tasks to run in order, define the
46
46
  dependencies in the task themselves.)
47
47
 
48
- ## Overriding where to keep the MIGRAKE_STATUS file
48
+ ## Overriding the file where tasks are stored
49
49
 
50
50
  The file will be located, by default, at whichever directory `rake` is invoked
51
- from. In order to change that (for example, to put it in capistrano's `shared`
52
- directory), do either of the following:
51
+ from. In order to change the path to the file, you can do this:
53
52
 
54
- Define `Migrake.status_file_directory` before running the tasks (so, for
55
- example, at the top of your `migrake.rake`):
53
+ ``` ruby
54
+ Migrake.store = Migrake::FileSystemStore.new("./config/migrake")
55
+ ```
56
+
57
+ This *must* be called in your Rakefile before you define the tasks to be run by
58
+ `migrake`. Like this:
56
59
 
57
60
  ``` ruby
58
- Migrake.status_file_directory = File.expand_path("../tmp", __FILE__)
61
+ require "migrake"
62
+
63
+ Migrake.store = Migrake::FileSystemStore.new("./config/migrake")
64
+
65
+ migrake Set.new([
66
+ # ...
67
+ ])
59
68
  ```
60
69
 
61
- Or as an alternative, pass it as an environment variable to Rake:
70
+ As an alternative, you can make `MIGRAKE_STATUS_DIR` available to your
71
+ environment, and migrake will use a `MIGRAKE_STATUS` file in that directory.
62
72
 
63
73
  ``` shell
64
74
  MIGRAKE_STATUS_DIR=./some/path bundle exec rake migrake
65
75
  ```
66
76
 
67
- The latter lets you define it within the capistrano definition file, like this:
77
+ This is particularly useful to use with capistrano, since you probably want to
78
+ use cap's `shared` directory to store your migrake file. For example:
68
79
 
69
80
  ``` ruby
70
81
  namespace :deploy do
@@ -76,6 +87,17 @@ end
76
87
  after "deploy:migrations", "deploy:migrake"
77
88
  ```
78
89
 
90
+ ## Heroku and other environments where you can't easily write to the filesystem
91
+
92
+ The `FileSystemStore` is easily swappable. For the particular case of Heroku and
93
+ similar servers we provide the [Migrake::SQLStore][sql-store] gem, that
94
+ implements the storage API using a database table.
95
+
96
+ Writing a new storage engine should be trivial. Use either `FileSystemStore` or
97
+ `SQLStore` as an example.
98
+
99
+ [sql-store]: http://github.com/foca/migrake-sql_store
100
+
79
101
  ## Bootstrapping a new environment
80
102
 
81
103
  When you bootstrap a new environment you don't need to run migrake tasks that
data/lib/migrake.rb CHANGED
@@ -1,82 +1,30 @@
1
+ require "set"
1
2
  require "rake/task"
2
3
  require "migrake/dsl"
3
4
  require "migrake/version"
4
- require "yaml"
5
- require "set"
6
- require "pathname"
7
5
 
8
6
  module Migrake
9
- # Public: Change the directory where we keep the MIGRAKE_STATUS file.
10
- #
11
- # dir - A filesystem path.
12
- #
13
- # Returns the directory path.
14
- def self.status_file_directory=(dir)
15
- @status_dir = Pathname(dir)
7
+ class << self
8
+ # Public: Get/Set the store where Migrake checks for which tasks shouldn't
9
+ # be run. This should implement Migrake::FileSystemStore's interface.
10
+ attr_accessor :store
16
11
  end
17
12
 
18
- # Public: Get the directory where we keep the MIGRAKE_STATUS file. If no
19
- # directory is set, we will try to fetch it from the ENV, using the
20
- # MIGRAKE_STATUS_DIR environment variable. If that isn't set either, we
21
- # default to the working directory.
13
+ # Public: Run all the rake tasks in `set` that haven't been stored in
14
+ # `store`.
22
15
  #
23
- # Returns a Pathname.
24
- def self.status_file_directory
25
- @status_dir ||= Pathname(ENV.fetch("MIGRAKE_STATUS_DIR", Dir.pwd))
26
- end
27
-
28
- # The Runner is responsible for selecting the rake tasks to be run and run
29
- # them, unless they have already been run in this host.
30
- module Runner
31
- # Public: Run all the rake tasks in `set` that haven't been stored in
32
- # `store`.
33
- #
34
- # set - A Set with tasks to be run.
35
- # store - A Migrake::Store with the tasks that have already been run.
36
- #
37
- # Returns the Set of tasks that were run.
38
- def self.run(set, store)
39
- (set - store.all).each do |task|
40
- Rake::Task[task].invoke
41
- store.put(task)
42
- end
43
- end
44
- end
45
-
46
- # The Store handles the file where tasks that have already been run are stored
47
- # so they aren't run again.
48
- class Store
49
- # Public: Initialize the store.
50
- #
51
- # path - The path to the file where we store the information.
52
- def initialize(path)
53
- @path = path
54
- end
55
-
56
- # Public: Add one task to the store. This immediately writes the file to
57
- # disk, to preserve consistency.
58
- #
59
- # task - A string with a task's name.
60
- #
61
- # Returns nil.
62
- def put(task)
63
- write(all << task)
64
- end
65
-
66
- # Public: Load all the tasks from the store.
67
- #
68
- # Returns a Set.
69
- def all
70
- @all ||= YAML.load(@path.read) || Set.new
71
- end
72
-
73
- # Public: Write a whole set of tasks to the store, replacing what is in it.
74
- #
75
- # set - A Set of tasks.
76
- #
77
- # Returns nil.
78
- def write(set)
79
- @path.open("w+") { |f| f.puts YAML.dump(set) }
16
+ # set - A Set with tasks to be run.
17
+ # store - A Store (such as Migrake::FileSystemStore), to know which tasks
18
+ # have already been run.
19
+ #
20
+ # Returns the Set of tasks that were run.
21
+ def self.run(set, store)
22
+ (set - store.all).each do |task|
23
+ Rake::Task[task].invoke
24
+ store.put(task)
80
25
  end
81
26
  end
82
27
  end
28
+
29
+ # The FileSystemStore is the default store.
30
+ require "migrake/file_system_store"
data/lib/migrake/dsl.rb CHANGED
@@ -1,43 +1,32 @@
1
- require "migrake"
2
-
3
1
  module Migrake
4
2
  module DSL
5
3
  # Public: Define the rake tasks required to run migrake. This defines the
6
4
  # following tasks:
7
5
  #
8
- # - A task to create the `Migrake.status_file_directory` unless it exists.
9
- # - A task to create the MIGRAKE_STATUS file in the aforementioned
10
- # directory, unless it exists.
6
+ # - A task to ensure we can use whatever is defined as `Migrake.store`.
11
7
  # - A `migrake:ready` task to bootstrap new environments by writing all
12
8
  # the tasks to the store.
13
9
  # - The `migrake` task, that will run any tasks not run before.
14
10
  #
15
11
  # tasks - A Set of tasks to be run.
16
12
  #
17
- # Returns the `migrake` Rake::Task.
13
+ # Returns nothing.
18
14
  def migrake(tasks)
19
- dir = Migrake.status_file_directory
20
- status_file = dir.join("MIGRAKE_STATUS")
21
-
22
15
  namespace :migrake do
23
- directory dir.to_s
24
-
25
- file status_file.to_s => dir.to_s do
26
- touch status_file
27
- end
28
-
29
- task :run_tasks => status_file.to_s do
30
- Migrake::Runner.run(tasks, Migrake::Store.new(status_file))
16
+ task :check_store do
17
+ Migrake.store.prepare
31
18
  end
32
19
 
33
20
  desc "Tell migrake that all defined tasks have already been run"
34
- task :ready => status_file.to_s do
35
- Migrake::Store.new(status_file).write(tasks)
21
+ task ready: :check_store do
22
+ Migrake.store.write(tasks)
36
23
  end
37
24
  end
38
25
 
39
26
  desc "Run the tasks defined by migrake"
40
- task migrake: "migrake:run_tasks"
27
+ task migrake: "migrake:check_store" do
28
+ Migrake.run(tasks, Migrake.store)
29
+ end
41
30
  end
42
31
  end
43
32
  end
@@ -0,0 +1,55 @@
1
+ require "yaml"
2
+ require "pathname"
3
+ require "fileutils"
4
+
5
+ # The FileSystemStore handles the file where tasks that have already been run
6
+ # are stored so they aren't run again.
7
+ class Migrake::FileSystemStore
8
+ # Public: Initialize the store.
9
+ #
10
+ # path - The path to the file where we store the information. A Pathname of
11
+ # String should be provided.
12
+ def initialize(path)
13
+ @path = Pathname(path)
14
+ end
15
+
16
+ # Public: Ensure the file we use to store information exists.
17
+ #
18
+ # Returns nothing.
19
+ def prepare
20
+ FileUtils.mkdir_p @path.dirname
21
+ FileUtils.touch @path
22
+ end
23
+
24
+ # Public: Add one task to the store. This immediately writes the file to
25
+ # disk, to preserve consistency.
26
+ #
27
+ # task - A string with a task's name.
28
+ #
29
+ # Returns nothing.
30
+ def put(task)
31
+ write(all << task)
32
+ end
33
+
34
+ # Public: Load all the tasks from the store.
35
+ #
36
+ # Returns a Set.
37
+ def all
38
+ @all ||= YAML.load(@path.read) || Set.new
39
+ end
40
+
41
+ # Public: Write a whole set of tasks to the store, replacing what is in it.
42
+ #
43
+ # set - A Set of tasks.
44
+ #
45
+ # Returns nothing.
46
+ def write(set)
47
+ @path.open("w+") { |f| f.puts YAML.dump(set) }
48
+ end
49
+ end
50
+
51
+ # Automagic configuration. If this environment has a MIGRAKE_STATUS_DIR, use it
52
+ # for the MIGRAKE_STATUS file. If not, default to the current directory.
53
+ Migrake.store = Migrake::FileSystemStore.new(
54
+ Pathname(ENV.fetch("MIGRAKE_STATUS_DIR", Dir.pwd)).join("MIGRAKE_STATUS")
55
+ )
@@ -1,3 +1,3 @@
1
1
  module Migrake
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -1,22 +1,22 @@
1
1
  require_relative "test_helper"
2
2
  require "tempfile"
3
3
 
4
- describe Migrake::Store do
4
+ describe Migrake::FileSystemStore do
5
5
  it "can read a stored set" do
6
6
  set = Set.new(["a", "b", "c"])
7
7
  save_in_source set
8
8
 
9
- store = Migrake::Store.new(source)
9
+ store = Migrake::FileSystemStore.new(source)
10
10
  assert_equal set, store.all
11
11
  end
12
12
 
13
13
  it "an empty file means an empty set" do
14
- store = Migrake::Store.new(source)
14
+ store = Migrake::FileSystemStore.new(source)
15
15
  assert_equal Set.new, store.all
16
16
  end
17
17
 
18
18
  it "can add an entry to the store" do
19
- store = Migrake::Store.new(source)
19
+ store = Migrake::FileSystemStore.new(source)
20
20
  store.put("test")
21
21
 
22
22
  assert_equal Set.new(["test"]), store.all
@@ -25,7 +25,7 @@ describe Migrake::Store do
25
25
  it "can write a set replacing whatever is there on the file" do
26
26
  save_in_source Set.new(["d", "e", "f", "g"])
27
27
 
28
- store = Migrake::Store.new(source)
28
+ store = Migrake::FileSystemStore.new(source)
29
29
  store.write Set.new(["a", "b", "c"])
30
30
 
31
31
  assert_equal Set.new(["a", "b", "c"]), store.all
@@ -1,14 +1,14 @@
1
1
  require_relative "test_helper"
2
2
  require "rake"
3
3
 
4
- describe Migrake::Runner do
4
+ describe Migrake do
5
5
  it "runs tasks that aren't in the store" do
6
6
  define_tasks "a", "b", "c"
7
7
  define_store "a"
8
8
 
9
9
  expect_tasks_ran "b", "c"
10
10
 
11
- Migrake::Runner.run(Set.new(["a", "b", "c"]), store)
11
+ Migrake.run(Set.new(["a", "b", "c"]), store)
12
12
 
13
13
  store.verify
14
14
  end
@@ -18,7 +18,7 @@ describe Migrake::Runner do
18
18
  define_store "a", "b", "c"
19
19
  # setting no expectation for tasks run passes only if no tasks are run
20
20
 
21
- Migrake::Runner.run(Set.new(["a", "b", "c"]), store)
21
+ Migrake.run(Set.new(["a", "b", "c"]), store)
22
22
 
23
23
  store.verify
24
24
  end
@@ -29,7 +29,7 @@ describe Migrake::Runner do
29
29
 
30
30
  expect_tasks_ran "a"
31
31
 
32
- Migrake::Runner.run(Set.new(["a", "b", "c"]), store)
32
+ Migrake.run(Set.new(["a", "b", "c"]), store)
33
33
 
34
34
  store.verify
35
35
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: migrake
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2012-04-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
16
- requirement: &70142092483920 !ruby/object:Gem::Requirement
16
+ requirement: &70224747638560 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 0.9.2
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70142092483920
24
+ version_requirements: *70224747638560
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: minitest
27
- requirement: &70142092483500 !ruby/object:Gem::Requirement
27
+ requirement: &70224747638100 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70142092483500
35
+ version_requirements: *70224747638100
36
36
  description: Migrake allows you to run rake tasks that only need to be run once in
37
37
  a given environment each time you deploy
38
38
  email: hi@nicolassanguinetti.info
@@ -42,16 +42,18 @@ extra_rdoc_files: []
42
42
  files:
43
43
  - .gitignore
44
44
  - .travis.yml
45
+ - CHANGES
45
46
  - Gemfile
46
47
  - README.md
47
48
  - Rakefile
48
49
  - examples/Rakefile
49
50
  - lib/migrake.rb
50
51
  - lib/migrake/dsl.rb
52
+ - lib/migrake/file_system_store.rb
51
53
  - lib/migrake/version.rb
52
54
  - migrake.gemspec
53
- - test/runner_test.rb
54
- - test/store_test.rb
55
+ - test/file_system_store_test.rb
56
+ - test/migrake_test.rb
55
57
  - test/test_helper.rb
56
58
  homepage: http://github.com/foca/migrake
57
59
  licenses: []