OSDN Git Service

Event entity created
authorDmitriy Zaporozhets <dzaporozhets@sphereconsultinginc.com>
Tue, 28 Feb 2012 18:09:23 +0000 (20:09 +0200)
committerDmitriy Zaporozhets <dzaporozhets@sphereconsultinginc.com>
Wed, 29 Feb 2012 09:15:58 +0000 (11:15 +0200)
Observe issue, merge request, note creation - create event
register push event

16 files changed:
app/models/activity_observer.rb [new file with mode: 0644]
app/models/event.rb [new file with mode: 0644]
app/models/project.rb
app/models/users_project.rb
app/models/wiki.rb
app/workers/post_receive.rb
config/application.rb
db/migrate/20120228130210_create_events.rb [new file with mode: 0644]
db/migrate/20120228134252_add_action_to_event.rb [new file with mode: 0644]
db/schema.rb
spec/factories.rb
spec/models/activity_observer_spec.rb [new file with mode: 0644]
spec/models/event_spec.rb [new file with mode: 0644]
spec/models/project_hooks_spec.rb [new file with mode: 0644]
spec/models/project_spec.rb
spec/models/users_project_spec.rb

diff --git a/app/models/activity_observer.rb b/app/models/activity_observer.rb
new file mode 100644 (file)
index 0000000..4656416
--- /dev/null
@@ -0,0 +1,12 @@
+class ActivityObserver < ActiveRecord::Observer
+  observe :issue, :merge_request, :note
+
+  def after_create(record)
+    Event.create(
+      :project => record.project,
+      :target_id => record.id,
+      :target_type => record.class.name,
+      :action => Event.determine_action(record)
+    )
+  end
+end
diff --git a/app/models/event.rb b/app/models/event.rb
new file mode 100644 (file)
index 0000000..5cb7524
--- /dev/null
@@ -0,0 +1,36 @@
+class Event < ActiveRecord::Base
+  Created   = 1
+  Updated   = 2
+  Closed    = 3
+  Reopened  = 4
+  Pushed    = 5
+  Commented = 6
+
+  belongs_to :project
+  belongs_to :target, :polymorphic => true
+
+  serialize :data
+
+  def self.determine_action(record)
+    if [Issue, MergeRequest].include? record.class
+      Event::Created
+    elsif record.kind_of? Note
+      Event::Commented
+    end
+  end
+end
+# == Schema Information
+#
+# Table name: events
+#
+#  id          :integer         not null, primary key
+#  target_type :string(255)
+#  target_id   :integer
+#  title       :string(255)
+#  data        :text
+#  project_id  :integer
+#  created_at  :datetime        not null
+#  updated_at  :datetime        not null
+#  action      :integer
+#
+
index b59dcd8..4d1d4e7 100644 (file)
@@ -3,6 +3,7 @@ require "grit"
 class Project < ActiveRecord::Base
   belongs_to :owner, :class_name => "User"
 
+  has_many :events, :dependent => :destroy
   has_many :merge_requests, :dependent => :destroy
   has_many :issues, :dependent => :destroy, :order => "position"
   has_many :users_projects, :dependent => :destroy
@@ -89,6 +90,16 @@ class Project < ActiveRecord::Base
     [GIT_HOST['host'], code].join("/")
   end
 
+  def observe_push(oldrev, newrev, ref)
+    data = web_hook_data(oldrev, newrev, ref)
+
+    Event.create(
+      :project => self,
+      :action => Event::Pushed,
+      :data => data
+    )
+  end
+
   def execute_web_hooks(oldrev, newrev, ref)
     ref_parts = ref.split('/')
 
@@ -96,6 +107,7 @@ class Project < ActiveRecord::Base
     return if ref_parts[1] !~ /heads/ || oldrev == "00000000000000000000000000000000"
 
     data = web_hook_data(oldrev, newrev, ref)
+
     web_hooks.each { |web_hook| web_hook.execute(data) }
   end
 
@@ -364,5 +376,6 @@ end
 #  issues_enabled         :boolean         default(TRUE), not null
 #  wall_enabled           :boolean         default(TRUE), not null
 #  merge_requests_enabled :boolean         default(TRUE), not null
+#  wiki_enabled           :boolean         default(TRUE), not null
 #
 
index bc62522..726a85a 100644 (file)
@@ -80,7 +80,6 @@ end
 #  project_id     :integer         not null
 #  created_at     :datetime
 #  updated_at     :datetime
-#  repo_access    :integer         default(0), not null
 #  project_access :integer         default(0), not null
 #
 
index 62ac4cb..ad3e4a3 100644 (file)
@@ -31,3 +31,17 @@ class Wiki < ActiveRecord::Base
 
   end
 end
+# == Schema Information
+#
+# Table name: wikis
+#
+#  id         :integer         not null, primary key
+#  title      :string(255)
+#  content    :text
+#  project_id :integer
+#  created_at :datetime        not null
+#  updated_at :datetime        not null
+#  slug       :string(255)
+#  user_id    :integer
+#
+
index 922a66e..81654df 100644 (file)
@@ -5,6 +5,7 @@ class PostReceive
     project = Project.find_by_path(reponame)
     return false if project.nil?
 
+    project.observe_push(oldrev, newrev, ref)
     project.execute_web_hooks(oldrev, newrev, ref)
   end
 end
index bdd5bbf..a3ef29c 100644 (file)
@@ -23,7 +23,7 @@ module Gitlab
     # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
 
     # Activate observers that should always be running.
-    config.active_record.observers = :mailer_observer
+    config.active_record.observers = :mailer_observer, :activity_observer
 
     # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
     # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
diff --git a/db/migrate/20120228130210_create_events.rb b/db/migrate/20120228130210_create_events.rb
new file mode 100644 (file)
index 0000000..c01f557
--- /dev/null
@@ -0,0 +1,14 @@
+class CreateEvents < ActiveRecord::Migration
+  def change
+    create_table :events do |t|
+      t.string :target_type, :null => true
+      t.integer :target_id, :null => true
+
+      t.string :title, :null => true
+      t.text :data, :null => true
+      t.integer :project_id, :null => true
+
+      t.timestamps
+    end
+  end
+end
diff --git a/db/migrate/20120228134252_add_action_to_event.rb b/db/migrate/20120228134252_add_action_to_event.rb
new file mode 100644 (file)
index 0000000..aade3d9
--- /dev/null
@@ -0,0 +1,5 @@
+class AddActionToEvent < ActiveRecord::Migration
+  def change
+    add_column :events, :action, :integer, :null => true
+  end
+end
index c32df7e..a0baf8e 100644 (file)
 #
 # It's strongly recommended to check this file into your version control system.
 
-ActiveRecord::Schema.define(:version => 20120219193300) do
+ActiveRecord::Schema.define(:version => 20120228134252) do
+
+  create_table "events", :force => true do |t|
+    t.string   "target_type"
+    t.integer  "target_id"
+    t.string   "title"
+    t.text     "data"
+    t.integer  "project_id"
+    t.datetime "created_at",  :null => false
+    t.datetime "updated_at",  :null => false
+    t.integer  "action"
+  end
 
   create_table "issues", :force => true do |t|
     t.string   "title"
index 6d7a4cb..2ca8d76 100644 (file)
@@ -32,10 +32,14 @@ end
 
 Factory.add(:issue, Issue) do |obj|
   obj.title = Faker::Lorem.sentence
+  obj.author = Factory :user
+  obj.assignee = Factory :user
 end
 
 Factory.add(:merge_request, MergeRequest) do |obj|
   obj.title = Faker::Lorem.sentence
+  obj.author = Factory :user
+  obj.assignee = Factory :user
   obj.source_branch = "master"
   obj.target_branch = "master"
   obj.closed = false
@@ -64,3 +68,8 @@ Factory.add(:wikis, WebHook) do |obj|
   obj.title = Faker::Lorem.sentence
   obj.content = Faker::Lorem.sentence
 end
+
+Factory.add(:event, Event) do |obj|
+  obj.title = Faker::Lorem.sentence
+  obj.project = Factory(:project)
+end
diff --git a/spec/models/activity_observer_spec.rb b/spec/models/activity_observer_spec.rb
new file mode 100644 (file)
index 0000000..9cd0dfb
--- /dev/null
@@ -0,0 +1,44 @@
+require 'spec_helper'
+
+describe ActivityObserver do
+  let(:project)  { Factory :project } 
+
+  def self.it_should_be_valid_event
+    it { @event.should_not be_nil }
+    it { @event.project.should == project }
+  end
+
+  describe "Merge Request created" do 
+    before do 
+      @merge_request = Factory :merge_request, :project => project
+      @event = Event.last
+    end
+
+    it_should_be_valid_event
+    it { @event.action.should == Event::Created }
+    it { @event.target.should == @merge_request }
+  end
+
+  describe "Issue created" do 
+    before do 
+      @issue = Factory :issue, :project => project
+      @event = Event.last
+    end
+
+    it_should_be_valid_event
+    it { @event.action.should == Event::Created }
+    it { @event.target.should == @issue }
+  end
+
+  describe "Issue commented" do 
+    before do 
+      @issue = Factory :issue, :project => project
+      @note = Factory :note, :noteable => @issue, :project => project
+      @event = Event.last
+    end
+
+    it_should_be_valid_event
+    it { @event.action.should == Event::Commented }
+    it { @event.target.should == @note }
+  end
+end
diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb
new file mode 100644 (file)
index 0000000..50266fc
--- /dev/null
@@ -0,0 +1,32 @@
+# == Schema Information
+#
+# Table name: events
+#
+#  id          :integer         not null, primary key
+#  target_type :string(255)
+#  target_id   :integer
+#  title       :string(255)
+#  data        :text
+#  project_id  :integer
+#  created_at  :datetime        not null
+#  updated_at  :datetime        not null
+#  action      :integer
+#
+
+require 'spec_helper'
+
+describe Event do
+  describe "Associations" do
+    it { should belong_to(:project) }
+  end
+
+  describe "Creation" do
+    before do 
+      @event = Factory :event
+    end
+
+    it "should create a valid event" do 
+      @event.should be_valid
+    end
+  end
+end
diff --git a/spec/models/project_hooks_spec.rb b/spec/models/project_hooks_spec.rb
new file mode 100644 (file)
index 0000000..841c85b
--- /dev/null
@@ -0,0 +1,115 @@
+require 'spec_helper'
+
+describe Project, "Hooks" do
+  let(:project) { Factory :project }
+
+  describe "Post Receive Event" do 
+    it "should create push event" do 
+      oldrev, newrev, ref = '00000000000000000000000000000000', 'newrev', 'refs/heads/master'
+      project.observe_push(oldrev, newrev, ref)
+      event = Event.last
+
+      event.should_not be_nil
+      event.project.should == project
+      event.action.should == Event::Pushed
+      event.data == project.web_hook_data(oldrev, newrev, ref)
+    end
+  end
+
+  describe "Web hooks" do
+    context "with no web hooks" do
+      it "raises no errors" do
+        lambda {
+          project.execute_web_hooks('oldrev', 'newrev', 'ref')
+        }.should_not raise_error
+      end
+    end
+
+    context "with web hooks" do
+      before do
+        @webhook = Factory(:web_hook)
+        @webhook_2 = Factory(:web_hook)
+        project.web_hooks << [@webhook, @webhook_2]
+      end
+
+      it "executes multiple web hook" do
+        @webhook.should_receive(:execute).once
+        @webhook_2.should_receive(:execute).once
+
+        project.execute_web_hooks('oldrev', 'newrev', 'refs/heads/master')
+      end
+    end
+
+    context "does not execute web hooks" do
+      before do
+        @webhook = Factory(:web_hook)
+        project.web_hooks << [@webhook]
+      end
+
+      it "when pushing a branch for the first time" do
+        @webhook.should_not_receive(:execute)
+        project.execute_web_hooks('00000000000000000000000000000000', 'newrev', 'refs/heads/master')
+      end
+
+      it "when pushing tags" do
+        @webhook.should_not_receive(:execute)
+        project.execute_web_hooks('oldrev', 'newrev', 'refs/tags/v1.0.0')
+      end
+    end
+
+    context "when pushing new branches" do
+
+    end
+
+    context "when gathering commit data" do
+      before do
+        @oldrev, @newrev, @ref = project.fresh_commits(2).last.sha, project.fresh_commits(2).first.sha, 'refs/heads/master'
+        @commit = project.fresh_commits(2).first
+
+        # Fill nil/empty attributes
+        project.description = "This is a description"
+
+        @data = project.web_hook_data(@oldrev, @newrev, @ref)
+      end
+
+      subject { @data }
+
+      it { should include(before: @oldrev) }
+      it { should include(after: @newrev) }
+      it { should include(ref: @ref) }
+
+      context "with repository data" do
+        subject { @data[:repository] }
+
+        it { should include(name: project.name) }
+        it { should include(url: project.web_url) }
+        it { should include(description: project.description) }
+        it { should include(homepage: project.web_url) }
+        it { should include(private: project.private?) }
+      end
+
+      context "with commits" do
+        subject { @data[:commits] }
+
+        it { should be_an(Array) }
+        it { should have(1).element }
+
+        context "the commit" do
+          subject { @data[:commits].first }
+
+          it { should include(id: @commit.id) }
+          it { should include(message: @commit.safe_message) }
+          it { should include(timestamp: @commit.date.xmlschema) }
+          it { should include(url: "http://localhost/#{project.code}/commits/#{@commit.id}") }
+
+          context "with a author" do
+            subject { @data[:commits].first[:author] }
+
+            it { should include(name: @commit.author_name) }
+            it { should include(email: @commit.author_email) }
+          end
+        end
+      end
+    end
+  end
+end
index 437b139..f53b833 100644 (file)
@@ -2,6 +2,7 @@ require 'spec_helper'
 
 describe Project do
   describe "Associations" do
+    it { should have_many(:events) }
     it { should have_many(:users) }
     it { should have_many(:users_projects) }
     it { should have_many(:issues) }
@@ -69,106 +70,6 @@ describe Project do
     end
   end
 
-  describe "web hooks" do
-    let(:project) { Factory :project }
-
-    context "with no web hooks" do
-      it "raises no errors" do
-        lambda {
-          project.execute_web_hooks('oldrev', 'newrev', 'ref')
-        }.should_not raise_error
-      end
-    end
-
-    context "with web hooks" do
-      before do
-        @webhook = Factory(:web_hook)
-        @webhook_2 = Factory(:web_hook)
-        project.web_hooks << [@webhook, @webhook_2]
-      end
-
-      it "executes multiple web hook" do
-        @webhook.should_receive(:execute).once
-        @webhook_2.should_receive(:execute).once
-
-        project.execute_web_hooks('oldrev', 'newrev', 'refs/heads/master')
-      end
-    end
-
-    context "does not execute web hooks" do
-      before do
-        @webhook = Factory(:web_hook)
-        project.web_hooks << [@webhook]
-      end
-
-      it "when pushing a branch for the first time" do
-        @webhook.should_not_receive(:execute)
-        project.execute_web_hooks('00000000000000000000000000000000', 'newrev', 'refs/heads/master')
-      end
-
-      it "when pushing tags" do
-        @webhook.should_not_receive(:execute)
-        project.execute_web_hooks('oldrev', 'newrev', 'refs/tags/v1.0.0')
-      end
-    end
-
-    context "when pushing new branches" do
-
-    end
-
-    context "when gathering commit data" do
-      before do
-        @oldrev, @newrev, @ref = project.fresh_commits(2).last.sha, project.fresh_commits(2).first.sha, 'refs/heads/master'
-        @commit = project.fresh_commits(2).first
-
-        # Fill nil/empty attributes
-        project.description = "This is a description"
-
-        @data = project.web_hook_data(@oldrev, @newrev, @ref)
-      end
-
-      subject { @data }
-
-      it { should include(before: @oldrev) }
-      it { should include(after: @newrev) }
-      it { should include(ref: @ref) }
-
-      context "with repository data" do
-        subject { @data[:repository] }
-
-        it { should include(name: project.name) }
-        it { should include(url: project.web_url) }
-        it { should include(description: project.description) }
-        it { should include(homepage: project.web_url) }
-        it { should include(private: project.private?) }
-      end
-
-      context "with commits" do
-        subject { @data[:commits] }
-
-        it { should be_an(Array) }
-        it { should have(1).element }
-
-        context "the commit" do
-          subject { @data[:commits].first }
-
-          it { should include(id: @commit.id) }
-          it { should include(message: @commit.safe_message) }
-          it { should include(timestamp: @commit.date.xmlschema) }
-          it { should include(url: "http://localhost/#{project.code}/commits/#{@commit.id}") }
-
-          context "with a author" do
-            subject { @data[:commits].first[:author] }
-
-            it { should include(name: @commit.author_name) }
-            it { should include(email: @commit.author_email) }
-          end
-        end
-      end
-
-    end
-  end
-
   describe "updates" do
     let(:project) { Factory :project }
 
@@ -303,5 +204,6 @@ end
 #  issues_enabled         :boolean         default(TRUE), not null
 #  wall_enabled           :boolean         default(TRUE), not null
 #  merge_requests_enabled :boolean         default(TRUE), not null
+#  wiki_enabled           :boolean         default(TRUE), not null
 #
 
index 41e36b5..85bc4d3 100644 (file)
@@ -25,7 +25,6 @@ end
 #  project_id     :integer         not null
 #  created_at     :datetime
 #  updated_at     :datetime
-#  repo_access    :integer         default(0), not null
 #  project_access :integer         default(0), not null
 #