magi 0.0.6 → 0.0.7

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: 7b4d28573a8ed0497572635a79c1430e27e61e50
4
- data.tar.gz: 108e5eca7dd38c7edde9527ebb4cd7efda53412c
3
+ metadata.gz: 2db7f5dff13d75dd26fc1c8440bbb8cb68b51c92
4
+ data.tar.gz: 10ca4a6e4a4619df58bbc5a2f3c741c113cbf629
5
5
  SHA512:
6
- metadata.gz: ff4eca110f647870737e4ec032819f0b2919e7f70551f92f17f279e78ea312b203da5e5927caedbd582ccdf10e8e362b7b949cb4d4ccb09978312a9c1dbc7fe7
7
- data.tar.gz: 5080f4adeae11f1bb33e8e31d7a9910b62e1de6d787d07ce7ff581993f8d45bdabd3cdb7d94c6bb95c72e724b53901b0ade57cdeb90c437c8d7cafa51f1b86f9
6
+ metadata.gz: a637eed71179f9ccda64cc6185d439f3ee432413da2e8448bd48b38bbe4e733191312368c934634316ba85d3128c390109af6eaa161a1646d7371b68f1c22aa4
7
+ data.tar.gz: 705a9126445b1f52b78b957718e3484937366b5d03f69c8dc7f5e316d1db4add2fc86ca4eca850a6acf1606738c9ca7c221acdc3100dbd51c6c0e232d08bfcda
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ require "pathname"
2
+
1
3
  source "https://rubygems.org"
2
4
 
3
5
  gemspec
@@ -27,3 +29,8 @@ group :assets do
27
29
  gem "coffee-rails", "~> 3.2.1"
28
30
  gem "uglifier", ">= 1.0.3"
29
31
  end
32
+
33
+ # Put Gemfile in plugins/:name/Gemfile to use arbitrary gems in your plugin.
34
+ Pathname.glob("plugins/*/Gemfile").each do |pathname|
35
+ eval(pathname.read)
36
+ end
data/README.md CHANGED
@@ -25,8 +25,6 @@ Magi is just a rails application with some middlewares.
25
25
 
26
26
  ## Todo
27
27
  * async update by ajax
28
- * plugin system
29
- * git integration
30
28
  * command-line options
31
29
 
32
30
  ## API
@@ -16,7 +16,7 @@ class BuildsController < ApplicationController
16
16
  end
17
17
 
18
18
  def create
19
- resource = @job.enqueue
19
+ resource = @job.enqueue_without_before_enqueues
20
20
  respond_with resource, location: [@job, resource]
21
21
  end
22
22
 
data/app/models/build.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  class Build < ActiveRecord::Base
2
- extend Magi::Proprietary
2
+ include Magi::Proprietary
3
3
 
4
4
  attr_accessible :finished_at, :started_at, :output, :properties, :status
5
5
 
data/app/models/job.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  class Job < ActiveRecord::Base
2
- extend Magi::Proprietary
2
+ include Magi::Proprietary
3
3
 
4
4
  attr_accessible :name, :properties
5
5
 
@@ -20,24 +20,40 @@ class Job < ActiveRecord::Base
20
20
  new.update_attributes_with_properties(params)
21
21
  end
22
22
 
23
- def enqueue_with_before_hooks
24
- select(&:scheduled?).each(&:enqueue_with_before_hooks)
23
+ def scheduled
24
+ select(&:scheduled?)
25
25
  end
26
26
 
27
- def before_hook(&block)
28
- before_hooks << block
27
+ def before_enqueue(&block)
28
+ before_enqueues << block
29
29
  end
30
30
 
31
- def before_hooks
32
- @before_hooks ||= []
31
+ def before_enqueues
32
+ @before_enqueues ||= []
33
33
  end
34
34
 
35
- def after_hook(&block)
36
- after_hooks << block
35
+ def after_enqueue(&block)
36
+ after_enqueues << block
37
37
  end
38
38
 
39
- def after_hooks
40
- @after_hooks ||= []
39
+ def after_enqueues
40
+ @after_enqueues ||= []
41
+ end
42
+
43
+ def before_execute(&block)
44
+ before_executes << block
45
+ end
46
+
47
+ def before_executes
48
+ @before_executes ||= []
49
+ end
50
+
51
+ def after_execute(&block)
52
+ after_executes << block
53
+ end
54
+
55
+ def after_executes
56
+ @after_executes ||= []
41
57
  end
42
58
  end
43
59
 
@@ -59,9 +75,19 @@ class Job < ActiveRecord::Base
59
75
  builds.create.tap(&:enqueue)
60
76
  end
61
77
 
62
- def enqueue_with_before_hooks
63
- enqueue if execute_before_hooks
78
+ def enqueue_with_before_enqueues
79
+ if self.class.before_enqueues.all? {|hook| instance_exec(&hook) != false }
80
+ enqueue_without_before_enqueues
81
+ end
64
82
  end
83
+ alias_method_chain :enqueue, :before_enqueues
84
+
85
+ def enqueue_with_after_enqueues
86
+ enqueue_without_after_enqueues.tap do
87
+ self.class.after_enqueues.all? {|hook| instance_exec(&hook) != false }
88
+ end
89
+ end
90
+ alias_method_chain :enqueue, :after_enqueues
65
91
 
66
92
  def status_name
67
93
  last_finished_build.try(:status_name) || "unfinished"
@@ -82,24 +108,32 @@ class Job < ActiveRecord::Base
82
108
  tap(&:save)
83
109
  end
84
110
 
111
+ def workspace
112
+ @workspace ||= Magi::Workspace.new(workspace_path)
113
+ end
114
+
85
115
  private
86
116
 
87
- def execute
88
- Magi::Executer.execute(script)
117
+ def workspace_path
118
+ Magi.workspace.path + "jobs/#{id}"
89
119
  end
90
120
 
91
- def execute_with_after_hooks
92
- execute_without_after_hooks.tap { execute_after_hooks }
121
+ def execute
122
+ workspace.chdir { Magi::Executer.execute(script) }
93
123
  end
94
- alias_method_chain :execute, :after_hooks
95
124
 
96
- def execute_before_hooks
97
- self.class.before_hooks.all? {|hook| instance_exec(&hook) != false }
125
+ def execute_with_before_executes
126
+ self.class.before_executes.all? {|hook| instance_exec(&hook) != false }
127
+ execute_without_before_executes
98
128
  end
129
+ alias_method_chain :execute, :before_executes
99
130
 
100
- def execute_after_hooks
101
- self.class.after_hooks.all? {|hook| instance_exec(&hook) != false }
131
+ def execute_with_after_executes
132
+ execute_without_after_executes.tap do
133
+ self.class.after_executes.all? {|hook| instance_exec(&hook) != false }
134
+ end
102
135
  end
136
+ alias_method_chain :execute, :after_executes
103
137
 
104
138
  def raise_script_not_found
105
139
  raise ScriptNotFound, 'You must set properties["script"]'
@@ -3,7 +3,7 @@ class JobEnqueueWorker
3
3
 
4
4
  class << self
5
5
  def perform(id)
6
- Job.find(id).enqueue_with_before_hooks
6
+ Job.find(id).enqueue
7
7
  end
8
8
 
9
9
  def perform_async(id)
data/lib/magi/command.rb CHANGED
@@ -8,7 +8,7 @@
8
8
  # # Invokes "setup" command to set up your database.
9
9
  # Magi::Command.call(["setup"])
10
10
  #
11
- # # Invokes "start" command to start redis, rails, and sidekiq processes.
11
+ # # Invokes "start" command to start the processes.
12
12
  # Magi::Command.call(["start"])
13
13
  #
14
14
  module Magi
@@ -43,11 +43,19 @@ module Magi
43
43
  end
44
44
 
45
45
  def start
46
- system("cd #{root_path} && foreman start")
46
+ system(env, "cd #{root_path} && foreman start")
47
47
  end
48
48
 
49
49
  def root_path
50
50
  File.expand_path("../../..", __FILE__)
51
51
  end
52
+
53
+ def workspace_path
54
+ Dir.pwd
55
+ end
56
+
57
+ def env
58
+ { "WORKSPACE_PATH" => workspace_path }
59
+ end
52
60
  end
53
61
  end
@@ -1,13 +1,21 @@
1
1
  module Magi
2
2
  class PluginManager
3
- def plugins_directory
4
- @plugins_directory ||= Rails.root + "plugins"
3
+ def plugins_directories
4
+ [Rails.root + "plugins", Pathname.pwd + "plugins"].uniq
5
5
  end
6
6
 
7
7
  def load_plugins
8
- Dir.glob("#{plugins_directory}/*/*.rb").sort.each do |path|
9
- require path
10
- end
8
+ plugin_filepaths.each {|path| require path }
9
+ end
10
+
11
+ private
12
+
13
+ def plugin_filepaths
14
+ Dir.glob("#{plugins_directories_pattern}/*/*.rb").sort
15
+ end
16
+
17
+ def plugins_directories_pattern
18
+ plugins_directories.join(",")
11
19
  end
12
20
  end
13
21
  end
@@ -1,19 +1,30 @@
1
1
  module Magi
2
2
  module Proprietary
3
- def property(name)
4
- properties << name
3
+ extend ActiveSupport::Concern
5
4
 
6
- define_method(name) do
7
- properties[name.to_s]
5
+ def update_properties(properties)
6
+ properties.each do |key, value|
7
+ send("#{key}=", value)
8
8
  end
9
+ save
10
+ end
11
+
12
+ module ClassMethods
13
+ def property(name)
14
+ properties << name
15
+
16
+ define_method(name) do
17
+ properties[name.to_s]
18
+ end
9
19
 
10
- define_method("#{name}=") do |value|
11
- properties[name.to_s] = value
20
+ define_method("#{name}=") do |value|
21
+ properties[name.to_s] = value
22
+ end
12
23
  end
13
- end
14
24
 
15
- def properties
16
- @properties ||= []
25
+ def properties
26
+ @properties ||= []
27
+ end
17
28
  end
18
29
  end
19
30
  end
data/lib/magi/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Magi
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.7"
3
3
  end
@@ -0,0 +1,26 @@
1
+ module Magi
2
+ class Workspace
3
+ attr_reader :path
4
+
5
+ def initialize(path)
6
+ @path = Pathname.new(path)
7
+ end
8
+
9
+ def chdir
10
+ mkpath_unless_exist
11
+ Dir.chdir(path) { yield }
12
+ end
13
+
14
+ def mkpath_unless_exist
15
+ mkpath unless exist?
16
+ end
17
+
18
+ def mkpath
19
+ path.mkpath
20
+ end
21
+
22
+ def exist?
23
+ path.exist?
24
+ end
25
+ end
26
+ end
data/lib/magi.rb CHANGED
@@ -1,9 +1,22 @@
1
1
  require "magi/command"
2
2
  require "magi/plugin_manager"
3
3
  require "magi/version"
4
+ require "magi/workspace"
4
5
 
5
6
  module Magi
6
- def self.plugin_manager
7
- @plugin_manager ||= Magi::PluginManager.new
7
+ class << self
8
+ def workspace
9
+ @workspace ||= Magi::Workspace.new(workspace_path)
10
+ end
11
+
12
+ def plugin_manager
13
+ @plugin_manager ||= Magi::PluginManager.new
14
+ end
15
+
16
+ private
17
+
18
+ def workspace_path
19
+ ENV["WORKSPACE_PATH"] || "."
20
+ end
8
21
  end
9
22
  end
data/magi.gemspec CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.homepage = "https://github.com/r7kamura/magi"
13
13
  spec.license = "MIT"
14
14
 
15
- spec.files = Dir["{app,bin,config,db,lib,public,script,spec}/**/*"]
15
+ spec.files = Dir["{app,bin,config,db,lib,plugins,public,script,spec}/**/*"]
16
16
  spec.files += %w[
17
17
  Gemfile
18
18
  LICENSE.txt
@@ -0,0 +1,84 @@
1
+ require "open3"
2
+
3
+ module Magi
4
+ class Repository
5
+ attr_reader :job
6
+
7
+ def initialize(job)
8
+ @job = job
9
+ end
10
+
11
+ def clone
12
+ validate_existence_of_git_url
13
+ command("git clone #{job.git_url} #{job.workspace.path}")
14
+ end
15
+
16
+ def update
17
+ command("cd #{job.workspace.path} && git pull")
18
+ end
19
+
20
+ def revision
21
+ command("cd #{job.workspace.path} && git rev-parse HEAD").rstrip
22
+ end
23
+
24
+ def updated?
25
+ revision != job.last_finished_build.try(:revision)
26
+ end
27
+
28
+ def cloned?
29
+ job.workspace.path.join(".git").exist?
30
+ end
31
+
32
+ private
33
+
34
+ def command(script)
35
+ Open3.capture3(script)[0]
36
+ end
37
+
38
+ def validate_existence_of_git_url
39
+ raise GitUrlNotFound unless job.git_url
40
+ end
41
+
42
+ class GitUrlNotFound < StandardError
43
+ def message
44
+ "You must set `git_url`"
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ Job.class_eval do
51
+ property(:git_url)
52
+
53
+ before_enqueue do
54
+ if git_url.present?
55
+ repository.clone unless repository.cloned?
56
+ repository.update
57
+ repository.updated?
58
+ end
59
+ end
60
+
61
+ before_execute do
62
+ if git_url.present?
63
+ repository.clone unless repository.cloned?
64
+ end
65
+ end
66
+
67
+ after_execute do
68
+ if git_url.present?
69
+ current_build.update_revision
70
+ end
71
+ end
72
+
73
+ def repository
74
+ @repository ||= Magi::Repository.new(self)
75
+ end
76
+ end
77
+
78
+ Build.class_eval do
79
+ property(:revision)
80
+
81
+ def update_revision
82
+ update_properties(revision: job.repository.revision)
83
+ end
84
+ end
data/script/clock.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require File.expand_path("../../config/environment.rb", __FILE__)
2
2
 
3
3
  Clockwork.every(1.minute, "JobEnqueueWorker") do
4
- Job.enqueue_with_before_hooks
4
+ Job.scheduled.each(&:enqueue)
5
5
  end
@@ -2,11 +2,15 @@ require "spec_helper"
2
2
 
3
3
  describe Job do
4
4
  let(:job) do
5
- FactoryGirl.create(:job)
5
+ FactoryGirl.create(:job, properties: { "script" => "true" })
6
6
  end
7
7
 
8
8
  describe "#start" do
9
9
  context "without script" do
10
+ before do
11
+ job.script = nil
12
+ end
13
+
10
14
  it "raises Job::ScriptNotFound" do
11
15
  expect { job.start }.to raise_error(Job::ScriptNotFound)
12
16
  end
@@ -52,37 +56,35 @@ describe Job do
52
56
  end
53
57
  end
54
58
 
55
- describe "#enqueue_with_before_hooks" do
59
+ describe "#enqueue" do
56
60
  before do
57
- Job.before_hooks.clear
61
+ Job.before_enqueues.clear
58
62
  end
59
63
 
60
64
  after do
61
- Job.before_hooks.clear
65
+ Job.before_enqueues.clear
62
66
  end
63
67
 
64
68
  context "with successful hooks" do
65
69
  before do
66
- Job.before_hook { Job.hook_is_executed }
70
+ Job.before_enqueue { Job.hook_is_executed }
67
71
  end
68
72
 
69
73
  it "enqueues a new build" do
70
74
  Job.should_receive(:hook_is_executed)
71
- job.should_receive(:enqueue)
72
- job.enqueue_with_before_hooks
75
+ job.enqueue
73
76
  end
74
77
  end
75
78
 
76
79
  context "with failed hooks" do
77
80
  before do
78
- Job.before_hook { false }
79
- Job.before_hook { Job.hook_is_executed }
81
+ Job.before_enqueue { false }
82
+ Job.before_enqueue { Job.hook_is_executed }
80
83
  end
81
84
 
82
85
  it "stops at failed hook" do
83
86
  Job.should_not_receive(:hook_is_executed)
84
- job.should_not_receive(:enqueue)
85
- job.enqueue_with_before_hooks
87
+ job.enqueue
86
88
  end
87
89
  end
88
90
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: magi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryo Nakamura
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-06-11 00:00:00.000000000 Z
11
+ date: 2013-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: clockwork
@@ -308,8 +308,10 @@ files:
308
308
  - lib/magi/proprietary.rb
309
309
  - lib/magi/scheduler.rb
310
310
  - lib/magi/version.rb
311
+ - lib/magi/workspace.rb
311
312
  - lib/magi.rb
312
313
  - lib/tasks/resque.rake
314
+ - plugins/git/git.rb
313
315
  - public/404.html
314
316
  - public/422.html
315
317
  - public/500.html