Commit 64891c6c authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Replace commits calendar with contributions calendar

* count opening of issues and merge requests
* dont trigger git repository - use events from database
* much-much faster since does not affected by repository size
parent 29f6b01d
...@@ -7,7 +7,7 @@ class @calendar ...@@ -7,7 +7,7 @@ class @calendar
constructor: (timestamps, starting_year, starting_month, calendar_activities_path) -> constructor: (timestamps, starting_year, starting_month, calendar_activities_path) ->
cal = new CalHeatMap() cal = new CalHeatMap()
cal.init cal.init
itemName: ["commit"] itemName: ["contribution"]
data: timestamps data: timestamps
start: new Date(starting_year, starting_month) start: new Date(starting_year, starting_month)
domainLabelFormat: "%b" domainLabelFormat: "%b"
......
...@@ -31,9 +31,7 @@ class UsersController < ApplicationController ...@@ -31,9 +31,7 @@ class UsersController < ApplicationController
end end
def calendar def calendar
projects = Project.where(id: authorized_projects_ids & @user.contributed_projects_ids) calendar = contributions_calendar
calendar = Gitlab::CommitsCalendar.new(projects, @user)
@timestamps = calendar.timestamps @timestamps = calendar.timestamps
@starting_year = calendar.starting_year @starting_year = calendar.starting_year
@starting_month = calendar.starting_month @starting_month = calendar.starting_month
...@@ -42,20 +40,13 @@ class UsersController < ApplicationController ...@@ -42,20 +40,13 @@ class UsersController < ApplicationController
end end
def calendar_activities def calendar_activities
projects = Project.where(id: authorized_projects_ids & @user.contributed_projects_ids) @calendar_date = Date.parse(params[:date]) rescue nil
@events = []
date = Date.parse(params[:date]) rescue nil if @calendar_date
if date @events = contributions_calendar.events_by_date(@calendar_date)
@calendar_activities = Gitlab::CommitsCalendar.get_commits_for_date(projects, @user, date)
else
@calendar_activities = {}
end end
# get the total number of unique commits
@commit_count = @calendar_activities.values.flatten.map(&:id).uniq.count
@calendar_date = date
render 'calendar_activities', layout: false render 'calendar_activities', layout: false
end end
...@@ -82,4 +73,14 @@ class UsersController < ApplicationController ...@@ -82,4 +73,14 @@ class UsersController < ApplicationController
@authorized_projects_ids ||= @authorized_projects_ids ||=
ProjectsFinder.new.execute(current_user).pluck(:id) ProjectsFinder.new.execute(current_user).pluck(:id)
end end
def contributed_projects
@contributed_projects = Project.
where(id: authorized_projects_ids & @user.contributed_projects_ids).reject(&:forked?)
end
def contributions_calendar
@contributions_calendar ||= Gitlab::ContributionsCalendar.
new(contributed_projects, @user)
end
end end
class ProjectContributions
attr_reader :project, :user
def initialize(project, user)
@project, @user = project, user
end
def commits_log
repository = project.repository
if !repository.exists? || repository.empty?
return {}
end
Rails.cache.fetch(cache_key) do
repository.commits_per_day_for_user(user)
end
end
def user_commits_on_date(date)
repository = @project.repository
if !repository.exists? || repository.empty?
return []
end
commits = repository.commits_by_user_on_date_log(@user, date)
end
def cache_key
"#{Date.today.to_s}-commits-log-#{project.id}-#{user.email}"
end
end
...@@ -149,41 +149,6 @@ class Repository ...@@ -149,41 +149,6 @@ class Repository
end end
end end
def timestamps_by_user_log(user)
author_emails = '(' + user.all_emails.map{ |e| Regexp.escape(e) }.join('|') + ')'
args = %W(git log -E --author=#{author_emails} --since=#{(Date.today - 1.year).to_s} --branches --pretty=format:%cd --date=short)
dates = Gitlab::Popen.popen(args, path_to_repo).first.split("\n")
if dates.present?
dates
else
[]
end
end
def commits_by_user_on_date_log(user, date)
# format the date string for git
start_date = date.strftime("%Y-%m-%d 00:00:00")
end_date = date.strftime("%Y-%m-%d 23:59:59")
author_emails = '(' + user.all_emails.map{ |e| Regexp.escape(e) }.join('|') + ')'
args = %W(git log -E --author=#{author_emails} --after=#{start_date.to_s} --until=#{end_date.to_s} --branches --pretty=format:%h)
commits = Gitlab::Popen.popen(args, path_to_repo).first.split("\n")
commits.map! do |commit_id|
commit(commit_id)
end
end
def commits_per_day_for_user(user)
timestamps_by_user_log(user).
group_by { |commit_date| commit_date }.
inject({}) do |hash, (timestamp_date, commits)|
hash[timestamp_date] = commits.count
hash
end
end
def lookup_cache def lookup_cache
@lookup_cache ||= {} @lookup_cache ||= {}
end end
......
%h4 Commits calendar %h4 Contributions calendar
#cal-heatmap.calendar #cal-heatmap.calendar
:javascript :javascript
new calendar( new calendar(
......
.calendar_commit_activity .calendar_commit_activity
%hr %h4.prepend-top-20
%h4 %span.light Contributions for
Commit Activity %strong #{@calendar_date.to_s(:short)}
%strong
- if @commit_count == 0 %ul.bordered-list
no - @events.sort_by(&:created_at).each do |event|
- else %li
= @commit_count %span.light
%span.calendar_commit_date %i.fa.fa-clock-o
unique = event.created_at.to_s(:time)
= 'commit'.pluralize(@commit_count) - if event.push? && event.commits_count > 0
on pushed #{event.commits_count} commits to
= @calendar_date.strftime("%b %d, %Y") rescue '' - else
-unless @commit_count == 0 = event_action_name(event)
%hr - if event.target
- @calendar_activities.each do |project, commits| %strong= link_to "##{event.target_iid}", [event.project.namespace.becomes(Namespace), event.project, event.target]
- next if commits.empty? at
%div.js-toggle-container
%strong %strong
= pluralize(commits.count, 'commit') - if event.project
in project = link_to_project event.project
= link_to project.name_with_namespace, project_path(project) - else
%a.text-expander.js-toggle-button &hellip; = event.project_name
%hr
%div.js-toggle-content
- commits.each do |commit|
%span.monospace
= commit.committed_date.strftime("%H:%M")
= link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id"
= link_to commit.message, namespace_project_commit_path(project.namespace, project, commit), class: "commit-row-message str-truncated"
%br
%hr
module Gitlab
class CommitsCalendar
attr_reader :timestamps
def initialize(projects, user)
@timestamps = {}
date_timestamps = []
projects.reject(&:forked?).each do |project|
date_timestamps << ProjectContributions.new(project, user).commits_log
end
# Sumarrize commits from all projects per days
date_timestamps = date_timestamps.inject do |collection, date|
collection.merge(date) { |k, old_v, new_v| old_v + new_v }
end
date_timestamps ||= []
date_timestamps.each do |date, commits|
timestamp = Date.parse(date).to_time.to_i.to_s rescue nil
@timestamps[timestamp] = commits if timestamp
end
end
def self.get_commits_for_date(projects, user, date)
user_commits = {}
projects.reject(&:forked?).each do |project|
user_commits[project] = ProjectContributions.new(project, user).user_commits_on_date(date)
end
user_commits
end
def starting_year
(Time.now - 1.year).strftime("%Y")
end
def starting_month
Date.today.strftime("%m").to_i
end
end
end
module Gitlab
class ContributionsCalendar
attr_reader :timestamps, :projects, :user
def initialize(projects, user)
@projects = projects
@user = user
end
def timestamps
return @timestamps if @timestamps.present?
@timestamps = {}
date_from = 1.year.ago
date_to = Date.today
events = Event.where(author_id: user.id).where(action: event_type).
where("created_at > ?", date_from).where(project_id: projects)
grouped_events = events.to_a.group_by { |event| event.created_at.to_date.to_s }
dates = (1.year.ago.to_date..(Date.today + 1.day)).to_a
dates.each do |date|
date_id = date.to_time.to_i.to_s
@timestamps[date_id] = 0
if grouped_events.has_key?(date.to_s)
grouped_events[date.to_s].each do |event|
if event.created_at.to_date == date
if event.issue? || event.merge_request?
@timestamps[date_id] += 1
elsif event.push?
@timestamps[date_id] += event.commits_count
end
end
end
end
end
@timestamps
end
def events_by_date(date)
events = Event.where(author_id: user.id).where(action: event_type).
where("created_at > ? AND created_at < ?", date.beginning_of_day, date.end_of_day).
where(project_id: projects)
events.select do |event|
event.push? || event.issue? || event.merge_request?
end
end
def starting_year
(Time.now - 1.year).strftime("%Y")
end
def starting_month
Date.today.strftime("%m").to_i
end
def event_type
[Event::PUSHED, Event::CREATED, Event::CLOSED, Event::MERGED]
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment