summaryrefslogtreecommitdiff
path: root/app/models
diff options
context:
space:
mode:
Diffstat (limited to 'app/models')
-rw-r--r--app/models/event.rb50
-rw-r--r--app/models/event_for_migration.rb5
-rw-r--r--app/models/push_event.rb126
-rw-r--r--app/models/push_event_payload.rb22
4 files changed, 202 insertions, 1 deletions
diff --git a/app/models/event.rb b/app/models/event.rb
index 8d93a228494..a598eb08e82 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -48,6 +48,7 @@ class Event < ActiveRecord::Base
belongs_to :author, class_name: "User"
belongs_to :project
belongs_to :target, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
+ has_one :push_event_payload, foreign_key: :event_id
# For Hash only
serialize :data # rubocop:disable Cop/ActiveRecordSerialize
@@ -55,6 +56,7 @@ class Event < ActiveRecord::Base
# Callbacks
after_create :reset_project_activity
after_create :set_last_repository_updated_at, if: :push?
+ after_create :replicate_event_for_push_events_migration
# Scopes
scope :recent, -> { reorder(id: :desc) }
@@ -64,10 +66,36 @@ class Event < ActiveRecord::Base
where(project_id: projects.pluck(:id)).recent
end
- scope :with_associations, -> { includes(:author, :project, project: :namespace).preload(:target) }
+ scope :with_associations, -> do
+ # We're using preload for "push_event_payload" as otherwise the association
+ # is not always available (depending on the query being built).
+ includes(:author, :project, project: :namespace)
+ .preload(:target, :push_event_payload)
+ end
+
scope :for_milestone_id, ->(milestone_id) { where(target_type: "Milestone", target_id: milestone_id) }
+ self.inheritance_column = 'action'
+
class << self
+ def find_sti_class(action)
+ if action.to_i == PUSHED
+ PushEvent
+ else
+ Event
+ end
+ end
+
+ def subclass_from_attributes(attrs)
+ # Without this Rails will keep calling this method on the returned class,
+ # resulting in an infinite loop.
+ return unless self == Event
+
+ action = attrs.with_indifferent_access[inheritance_column].to_i
+
+ PushEvent if action == PUSHED
+ end
+
# Update Gitlab::ContributionsCalendar#activity_dates if this changes
def contributions
where("action = ? OR (target_type IN (?) AND action IN (?)) OR (target_type = ? AND action = ?)",
@@ -290,6 +318,16 @@ class Event < ActiveRecord::Base
@commits ||= (data[:commits] || []).reverse
end
+ def commit_title
+ commit = commits.last
+
+ commit[:message] if commit
+ end
+
+ def commit_id
+ commit_to || commit_from
+ end
+
def commits_count
data[:total_commits_count] || commits.count || 0
end
@@ -385,6 +423,16 @@ class Event < ActiveRecord::Base
user ? author_id == user.id : false
end
+ # We're manually replicating data into the new table since database triggers
+ # are not dumped to db/schema.rb. This could mean that a new installation
+ # would not have the triggers in place, thus losing events data in GitLab
+ # 10.0.
+ def replicate_event_for_push_events_migration
+ new_attributes = attributes.with_indifferent_access.except(:title, :data)
+
+ EventForMigration.create!(new_attributes)
+ end
+
private
def recent_update?
diff --git a/app/models/event_for_migration.rb b/app/models/event_for_migration.rb
new file mode 100644
index 00000000000..a1672da5eec
--- /dev/null
+++ b/app/models/event_for_migration.rb
@@ -0,0 +1,5 @@
+# This model is used to replicate events between the old "events" table and the
+# new "events_for_migration" table that will replace "events" in GitLab 10.0.
+class EventForMigration < ActiveRecord::Base
+ self.table_name = 'events_for_migration'
+end
diff --git a/app/models/push_event.rb b/app/models/push_event.rb
new file mode 100644
index 00000000000..3f1ff979de6
--- /dev/null
+++ b/app/models/push_event.rb
@@ -0,0 +1,126 @@
+class PushEvent < Event
+ # This validation exists so we can't accidentally use PushEvent with a
+ # different "action" value.
+ validate :validate_push_action
+
+ # Authors are required as they're used to display who pushed data.
+ #
+ # We're just validating the presence of the ID here as foreign key constraints
+ # should ensure the ID points to a valid user.
+ validates :author_id, presence: true
+
+ # The project is required to build links to commits, commit ranges, etc.
+ #
+ # We're just validating the presence of the ID here as foreign key constraints
+ # should ensure the ID points to a valid project.
+ validates :project_id, presence: true
+
+ # The "data" field must not be set for push events since it's not used and a
+ # waste of space.
+ validates :data, absence: true
+
+ # These fields are also not used for push events, thus storing them would be a
+ # waste.
+ validates :target_id, absence: true
+ validates :target_type, absence: true
+
+ def self.sti_name
+ PUSHED
+ end
+
+ def push?
+ true
+ end
+
+ def push_with_commits?
+ !!(commit_from && commit_to)
+ end
+
+ def tag?
+ return super unless push_event_payload
+
+ push_event_payload.tag?
+ end
+
+ def branch?
+ return super unless push_event_payload
+
+ push_event_payload.branch?
+ end
+
+ def valid_push?
+ return super unless push_event_payload
+
+ push_event_payload.ref.present?
+ end
+
+ def new_ref?
+ return super unless push_event_payload
+
+ push_event_payload.created?
+ end
+
+ def rm_ref?
+ return super unless push_event_payload
+
+ push_event_payload.removed?
+ end
+
+ def commit_from
+ return super unless push_event_payload
+
+ push_event_payload.commit_from
+ end
+
+ def commit_to
+ return super unless push_event_payload
+
+ push_event_payload.commit_to
+ end
+
+ def ref_name
+ return super unless push_event_payload
+
+ push_event_payload.ref
+ end
+
+ def ref_type
+ return super unless push_event_payload
+
+ push_event_payload.ref_type
+ end
+
+ def branch_name
+ return super unless push_event_payload
+
+ ref_name
+ end
+
+ def tag_name
+ return super unless push_event_payload
+
+ ref_name
+ end
+
+ def commit_title
+ return super unless push_event_payload
+
+ push_event_payload.commit_title
+ end
+
+ def commit_id
+ commit_to || commit_from
+ end
+
+ def commits_count
+ return super unless push_event_payload
+
+ push_event_payload.commit_count
+ end
+
+ def validate_push_action
+ return if action == PUSHED
+
+ errors.add(:action, "the action #{action.inspect} is not valid")
+ end
+end
diff --git a/app/models/push_event_payload.rb b/app/models/push_event_payload.rb
new file mode 100644
index 00000000000..6cdb1cd4fe9
--- /dev/null
+++ b/app/models/push_event_payload.rb
@@ -0,0 +1,22 @@
+class PushEventPayload < ActiveRecord::Base
+ include ShaAttribute
+
+ belongs_to :event, inverse_of: :push_event_payload
+
+ validates :event_id, :commit_count, :action, :ref_type, presence: true
+ validates :commit_title, length: { maximum: 70 }
+
+ sha_attribute :commit_from
+ sha_attribute :commit_to
+
+ enum action: {
+ created: 0,
+ removed: 1,
+ pushed: 2
+ }
+
+ enum ref_type: {
+ branch: 0,
+ tag: 1
+ }
+end