Commit 9e5738b0 authored by Hannes Rosenögger's avatar Hannes Rosenögger

Extend the commit calendar to show the actual commits for a date

parent dbd347bf
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
v 7.10.0 (unreleased) v 7.10.0 (unreleased)
- extend the commit calendar to show the actual commits made on a date (Hannes Rosenögger)
- Add a service to support external wikis (Hannes Rosenögger) - Add a service to support external wikis (Hannes Rosenögger)
v 7.9.0 (unreleased) v 7.9.0 (unreleased)
......
...@@ -4,7 +4,7 @@ class @calendar ...@@ -4,7 +4,7 @@ class @calendar
day: "numeric" day: "numeric"
year: "numeric" year: "numeric"
constructor: (timestamps, starting_year, starting_month) -> constructor: (timestamps, starting_year, starting_month, calendar_activities_path) ->
cal = new CalHeatMap() cal = new CalHeatMap()
cal.init cal.init
itemName: ["commit"] itemName: ["commit"]
...@@ -26,5 +26,16 @@ class @calendar ...@@ -26,5 +26,16 @@ class @calendar
] ]
legendCellPadding: 3 legendCellPadding: 3
onClick: (date, count) -> onClick: (date, count) ->
return formated_date = date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate()
return $(".calendar_commit_activity").fadeOut 400
$.ajax
url: calendar_activities_path
data:
date: formated_date
cache: false
dataType: "html"
success: (data) ->
$(".user-calendar-activities").html data
$(".calendar_commit_activity").find(".js-toggle-content").hide()
$(".calendar_commit_activity").fadeIn 400
.calendar_onclick_placeholder { .user-calendar-activities {
padding: 0 0 2px 0;
} .calendar_commit_activity {
padding: 5px 0 0;
.calendar_commit_activity { }
padding: 5px 0 0;
} .calendar_onclick_hr {
padding: 0;
.calendar_onclick_second { margin: 10px 0;
font-size: 14px; }
display: block;
} .calendar_commit_date {
color: #999;
.calendar_onclick_hr { }
padding: 0;
margin: 10px 0; .calendar_activity_summary {
} font-size: 14px;
}
.calendar_commit_date { .str-truncated {
color: #999; max-width: 70%;
} }
.calendar_activity_summary { .text-expander {
font-size: 14px; background: #eee;
color: #555;
padding: 0 5px;
cursor: pointer;
margin-left: 4px;
&:hover {
background-color: #ddd;
}
}
.commit-row-message {
color: #333;
&:hover {
color: #444;
text-decoration: underline;
}
}
} }
/** /**
* This overwrites the default values of the cal-heatmap gem * This overwrites the default values of the cal-heatmap gem
*/ */
......
...@@ -32,6 +32,7 @@ class UsersController < ApplicationController ...@@ -32,6 +32,7 @@ class UsersController < ApplicationController
def calendar def calendar
projects = Project.where(id: authorized_projects_ids & @user.contributed_projects_ids) projects = Project.where(id: authorized_projects_ids & @user.contributed_projects_ids)
calendar = Gitlab::CommitsCalendar.new(projects, @user) calendar = Gitlab::CommitsCalendar.new(projects, @user)
@timestamps = calendar.timestamps @timestamps = calendar.timestamps
@starting_year = calendar.starting_year @starting_year = calendar.starting_year
...@@ -40,6 +41,24 @@ class UsersController < ApplicationController ...@@ -40,6 +41,24 @@ class UsersController < ApplicationController
render 'calendar', layout: false render 'calendar', layout: false
end end
def calendar_activities
projects = Project.where(id: authorized_projects_ids & @user.contributed_projects_ids)
date = Date.parse(params[:date]) rescue nil
if date
@calendar_activities = Gitlab::CommitsCalendar.get_commits_for_date(projects, @user, date)
else
@calendar_activities = {}
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
end
def determine_layout def determine_layout
if current_user if current_user
'navless' 'navless'
......
...@@ -17,6 +17,15 @@ class ProjectContributions ...@@ -17,6 +17,15 @@ class ProjectContributions
end end
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 def cache_key
"#{Date.today.to_s}-commits-log-#{project.id}-#{user.email}" "#{Date.today.to_s}-commits-log-#{project.id}-#{user.email}"
end end
......
...@@ -157,6 +157,20 @@ class Repository ...@@ -157,6 +157,20 @@ class Repository
end end
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) def commits_per_day_for_user(user)
timestamps_by_user_log(user). timestamps_by_user_log(user).
group_by { |commit_date| commit_date }. group_by { |commit_date| commit_date }.
......
...@@ -4,5 +4,6 @@ ...@@ -4,5 +4,6 @@
new calendar( new calendar(
#{@timestamps.to_json}, #{@timestamps.to_json},
#{@starting_year}, #{@starting_year},
#{@starting_month} #{@starting_month},
'#{user_calendar_activities_path}'
); );
.calendar_commit_activity
%hr
%h4
Commit Activity
%strong
- if @commit_count == 0
no
- else
= @commit_count
%span.calendar_commit_date
unique
= 'commit'.pluralize(@commit_count)
on
= @calendar_date.strftime("%b %d, %Y") rescue ''
-unless @commit_count == 0
%hr
- @calendar_activities.each do |project, commits|
- next if commits.empty?
%div.js-toggle-container
%strong
= pluralize(commits.count, 'commit')
in project
= link_to project.name_with_namespace, project_path(project)
%a.text-expander.js-toggle-button &hellip;
%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
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
.user-calendar .user-calendar
%h4.center.light %h4.center.light
%i.fa.fa-spinner.fa-spin %i.fa.fa-spinner.fa-spin
.user-calendar-activities
%hr %hr
%h4 %h4
User Activity User Activity
......
...@@ -198,7 +198,10 @@ Gitlab::Application.routes.draw do ...@@ -198,7 +198,10 @@ Gitlab::Application.routes.draw do
end end
get 'u/:username/calendar' => 'users#calendar', as: :user_calendar, get 'u/:username/calendar' => 'users#calendar', as: :user_calendar,
constraints: { username: /(?:[^.]|\.(?!atom$))+/, format: /atom/ } constraints: { username: /.*/ }
get 'u/:username/calendar_activities' => 'users#calendar_activities', as: :user_calendar_activities,
constraints: { username: /.*/ }
get '/u/:username' => 'users#show', as: :user, get '/u/:username' => 'users#show', as: :user,
constraints: { username: /(?:[^.]|\.(?!atom$))+/, format: /atom/ } constraints: { username: /(?:[^.]|\.(?!atom$))+/, format: /atom/ }
......
...@@ -458,7 +458,6 @@ ActiveRecord::Schema.define(version: 20150313012111) do ...@@ -458,7 +458,6 @@ ActiveRecord::Schema.define(version: 20150313012111) do
t.integer "notification_level", default: 1, null: false t.integer "notification_level", default: 1, null: false
t.datetime "password_expires_at" t.datetime "password_expires_at"
t.integer "created_by_id" t.integer "created_by_id"
t.datetime "last_credential_check_at"
t.string "avatar" t.string "avatar"
t.string "confirmation_token" t.string "confirmation_token"
t.datetime "confirmed_at" t.datetime "confirmed_at"
...@@ -466,6 +465,7 @@ ActiveRecord::Schema.define(version: 20150313012111) do ...@@ -466,6 +465,7 @@ ActiveRecord::Schema.define(version: 20150313012111) do
t.string "unconfirmed_email" t.string "unconfirmed_email"
t.boolean "hide_no_ssh_key", default: false t.boolean "hide_no_ssh_key", default: false
t.string "website_url", default: "", null: false t.string "website_url", default: "", null: false
t.datetime "last_credential_check_at"
t.string "github_access_token" t.string "github_access_token"
t.string "gitlab_access_token" t.string "gitlab_access_token"
t.string "notification_email" t.string "notification_email"
......
...@@ -22,6 +22,14 @@ module Gitlab ...@@ -22,6 +22,14 @@ module Gitlab
end end
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 def starting_year
(Time.now - 1.year).strftime("%Y") (Time.now - 1.year).strftime("%Y")
end end
......
require 'spec_helper' require 'spec_helper'
describe UsersController do describe UsersController do
let(:user) { create(:user, username: "user1", name: "User 1", email: "user1@gitlab.com") } let(:user) { create(:user, username: 'user1', name: 'User 1', email: 'user1@gitlab.com') }
before do before do
sign_in(user) sign_in(user)
end end
describe "GET #show" do describe 'GET #show' do
render_views render_views
it "renders the show template" do it 'renders the show template' do
get :show, username: user.username get :show, username: user.username
expect(response.status).to eq(200) expect(response.status).to eq(200)
expect(response).to render_template("show") expect(response).to render_template('show')
end end
end end
describe "GET #calendar" do describe 'GET #calendar' do
it "renders calendar" do it 'renders calendar' do
get :calendar, username: user.username get :calendar, username: user.username
expect(response).to render_template("calendar") expect(response).to render_template('calendar')
end end
end end
end
describe 'GET #calendar_activities' do
include RepoHelpers
let(:project) { create(:project) }
let(:calendar_user) { create(:user, email: sample_commit.author_email) }
let(:commit1) { '0ed8c6c6752e8c6ea63e7b92a517bf5ac1209c80' }
let(:commit2) { '7d3b0f7cff5f37573aea97cebfd5692ea1689924' }
before do
allow_any_instance_of(User).to receive(:contributed_projects_ids).and_return([project.id])
project.team << [user, :developer]
end
it 'assigns @commit_count' do
get :calendar_activities, username: calendar_user.username, date: '2014-07-31'
expect(assigns(:commit_count)).to eq(2)
end
it 'assigns @calendar_date' do
get :calendar_activities, username: calendar_user.username, date: '2014-07-31'
expect(assigns(:calendar_date)).to eq(Date.parse('2014-07-31'))
end
it 'assigns @calendar_activities' do
get :calendar_activities, username: calendar_user.username, date: '2014-07-31'
expect(assigns(:calendar_activities).values.flatten.map(&:id)).to eq([commit1, commit2])
end
it 'renders calendar_activities' do
get :calendar_activities, username: calendar_user.username
expect(response).to render_template('calendar_activities')
end
end
end
...@@ -29,7 +29,7 @@ describe Repository do ...@@ -29,7 +29,7 @@ describe Repository do
subject { repository.timestamps_by_user_log(user) } subject { repository.timestamps_by_user_log(user) }
it { is_expected.to eq(["2014-08-06", "2014-07-31", "2014-07-31"]) } it { is_expected.to eq(['2014-08-06', '2014-07-31', '2014-07-31']) }
end end
describe 'multiple emails for user' do describe 'multiple emails for user' do
...@@ -38,7 +38,22 @@ describe Repository do ...@@ -38,7 +38,22 @@ describe Repository do
subject { repository.timestamps_by_user_log(user) } subject { repository.timestamps_by_user_log(user) }
it { is_expected.to eq(["2015-01-10", "2014-08-06", "2014-07-31", "2014-07-31"]) } it { is_expected.to eq(['2015-01-10', '2014-08-06', '2014-07-31', '2014-07-31']) }
end
end
context :commits_by_user_on_date_log do
describe 'single e-mail for user' do
let(:user) { create(:user, email: sample_commit.author_email) }
let(:commit1) { '0ed8c6c6752e8c6ea63e7b92a517bf5ac1209c80' }
let(:commit2) { '7d3b0f7cff5f37573aea97cebfd5692ea1689924' }
subject { repository.commits_by_user_on_date_log(user,Date.new(2014, 07, 31)) }
it 'contains the exepected commits' do
expect(subject.flatten.map(&:id)).to eq([commit1, commit2])
end
end end
end 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