summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVinnie Okada <vokada@mrvinn.com>2015-03-24 20:03:22 -0600
committerVinnie Okada <vokada@mrvinn.com>2015-03-24 20:03:22 -0600
commit057c8c344b6518cb50b81607e0f88734fc164a9e (patch)
tree996afee0c0f33bd6308f83b330a179dc29dfb48a
parent637ca0b388382112850fd3052a961bb07db34d14 (diff)
parentb9372c999707558b695fa401b4f660a3d38fce86 (diff)
downloadgitlab-ce-057c8c344b6518cb50b81607e0f88734fc164a9e.tar.gz
Merge branch 'master' into markdown-tags
-rw-r--r--CHANGELOG15
-rw-r--r--Gemfile.lock4
-rw-r--r--app/assets/javascripts/calendar.js.coffee5
-rw-r--r--app/assets/javascripts/dispatcher.js.coffee1
-rw-r--r--app/assets/javascripts/merge_request.js.coffee9
-rw-r--r--app/assets/javascripts/project_users_select.js.coffee7
-rw-r--r--app/assets/stylesheets/generic/calendar.scss21
-rw-r--r--app/assets/stylesheets/pages/diff.scss10
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss21
-rw-r--r--app/assets/stylesheets/themes/ui_blue.scss2
-rw-r--r--app/controllers/admin/services_controller.rb4
-rw-r--r--app/controllers/users_controller.rb60
-rw-r--r--app/helpers/issues_helper.rb13
-rw-r--r--app/helpers/projects_helper.rb4
-rw-r--r--app/helpers/search_helper.rb6
-rw-r--r--app/mailers/emails/projects.rb70
-rw-r--r--app/models/concerns/taskable.rb2
-rw-r--r--app/models/event.rb6
-rw-r--r--app/models/merge_request.rb9
-rw-r--r--app/models/note.rb1
-rw-r--r--app/models/project_contributions.rb32
-rw-r--r--app/models/project_services/emails_on_push_service.rb10
-rw-r--r--app/models/repository.rb35
-rw-r--r--app/models/user.rb8
-rw-r--r--app/services/issues/bulk_update_service.rb6
-rw-r--r--app/services/issues/update_service.rb3
-rw-r--r--app/services/merge_requests/refresh_service.rb12
-rw-r--r--app/services/merge_requests/update_service.rb3
-rw-r--r--app/views/admin/broadcast_messages/index.html.haml6
-rw-r--r--app/views/admin/services/_form.html.haml13
-rw-r--r--app/views/devise/mailer/confirmation_instructions.html.erb2
-rw-r--r--app/views/devise/mailer/reset_password_instructions.html.erb2
-rw-r--r--app/views/devise/mailer/unlock_instructions.html.erb2
-rw-r--r--app/views/devise/passwords/edit.html.haml2
-rw-r--r--app/views/devise/registrations/edit.html.erb4
-rw-r--r--app/views/help/ui.html.haml2
-rw-r--r--app/views/layouts/_head_panel.html.haml2
-rw-r--r--app/views/layouts/nav/_project.html.haml22
-rw-r--r--app/views/notify/repository_push_email.html.haml115
-rw-r--r--app/views/notify/repository_push_email.text.haml80
-rw-r--r--app/views/profiles/history.html.haml2
-rw-r--r--app/views/profiles/keys/index.html.haml2
-rw-r--r--app/views/projects/_home_panel.html.haml2
-rw-r--r--app/views/projects/commits/_commit.html.haml2
-rw-r--r--app/views/projects/diffs/_file.html.haml13
-rw-r--r--app/views/projects/diffs/_text_file.html.haml2
-rw-r--r--app/views/projects/issues/_issue.html.haml5
-rw-r--r--app/views/projects/labels/_form.html.haml4
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml5
-rw-r--r--app/views/projects/merge_requests/_show.html.haml2
-rw-r--r--app/views/projects/milestones/show.html.haml11
-rw-r--r--app/views/projects/notes/_discussion.html.haml3
-rw-r--r--app/views/projects/notes/_note.html.haml6
-rw-r--r--app/views/projects/notes/discussions/_diff.html.haml14
-rw-r--r--app/views/snippets/current_user_index.html.haml2
-rw-r--r--app/views/snippets/index.html.haml4
-rw-r--r--app/views/snippets/show.html.haml2
-rw-r--r--app/views/users/_projects.html.haml2
-rw-r--r--app/views/users/calendar.html.haml5
-rw-r--r--app/views/users/calendar_activities.html.haml54
-rw-r--r--app/views/users/show.html.haml3
-rw-r--r--app/workers/emails_on_push_worker.rb45
-rw-r--r--config/gitlab.yml.example3
-rw-r--r--config/initializers/1_settings.rb1
-rw-r--r--db/migrate/20150324155957_set_incorrect_assignee_id_to_null.rb6
-rw-r--r--db/schema.rb2
-rw-r--r--docker/Dockerfile2
-rw-r--r--features/admin/settings.feature7
-rw-r--r--features/steps/admin/settings.rb29
-rw-r--r--features/steps/user.rb33
-rw-r--r--features/user.feature9
-rw-r--r--lib/api/branches.rb3
-rw-r--r--lib/gitlab/backend/grack_auth.rb45
-rw-r--r--lib/gitlab/backend/rack_attack_helpers.rb31
-rw-r--r--lib/gitlab/commits_calendar.rb41
-rw-r--r--lib/gitlab/contributions_calendar.rb56
-rw-r--r--lib/gitlab/ldap/person.rb1
-rw-r--r--lib/gitlab/markdown.rb5
-rw-r--r--lib/gitlab/project_search_results.rb2
-rw-r--r--spec/controllers/users_controller_spec.rb21
-rw-r--r--spec/helpers/gitlab_markdown_helper_spec.rb11
-rw-r--r--spec/lib/gitlab/backend/grack_auth_spec.rb52
-rw-r--r--spec/lib/gitlab/backend/rack_attack_helpers_spec.rb35
-rw-r--r--spec/mailers/notify_spec.rb98
-rw-r--r--spec/models/repository_spec.rb45
85 files changed, 829 insertions, 530 deletions
diff --git a/CHANGELOG b/CHANGELOG
index af0f330884a..217f327a09a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,12 +2,14 @@ Please view this file on the master branch, on stable branches it's out of date.
v 7.10.0 (unreleased)
- Allow HTML tags in Markdown input
+ - Include missing events and fix save functionality in admin service template settings form (Stan Hu)
- Fix "Import projects from" button to show the correct instructions (Stan Hu)
- Fix dots in Wiki slugs causing errors (Stan Hu)
- Fix OAuth2 issue importing a new project from GitHub and GitLab (Stan Hu)
- Update poltergeist to version 1.6.0 to support PhantomJS 2.0 (Zeger-Jan van de Weg)
- Fix cross references when usernames, milestones, or project names contain underscores (Stan Hu)
- Disable reference creation for comments surrounded by code/preformatted blocks (Stan Hu)
+ - Reduce Rack Attack false positives causing 403 errors during HTTP authentication (Stan Hu)
- enable line wrapping per default and remove the checkbox to toggle it (Hannes Rosenögger)
- extend the commit calendar to show the actual commits made on a date (Hannes Rosenögger)
- Fix a link in the patch update guide
@@ -17,6 +19,7 @@ v 7.10.0 (unreleased)
- Add changelog, license and contribution guide links to project sidebar.
- Improve diff UI
- Fix alignment of navbar toggle button (Cody Mize)
+ - Fix checkbox rendering for nested task lists
- Identical look of selectboxes in UI
- Move "Import existing repository by URL" option to button.
- Improve error message when save profile has error.
@@ -28,8 +31,17 @@ v 7.10.0 (unreleased)
- Restrict permissions on backup files
- Improve oauth accounts UI in profile page
- Add ability to unlink connected accounts
+ - Replace commits calendar with faster contribution calendar that includes issues and merge requests
+ - Add inifinite scroll to user page activity
+ - Don't show commit comment button when user is not signed in.
+ - Don't include system notes in issue/MR comment count.
+ - Don't mark merge request as updated when merge status relative to target branch changes.
+ - Link note avatar to user.
v 7.9.0
+ - Send EmailsOnPush email when branch or tag is created or deleted.
+
+v 7.9.0 (unreleased)
- Add HipChat integration documentation (Stan Hu)
- Update documentation for object_kind field in Webhook push and tag push Webhooks (Stan Hu)
- Fix broken email images (Hannes Rosenögger)
@@ -146,7 +158,6 @@ v 7.8.0
- Add API endpoint to fetch all changes on a MergeRequest (Jeroen van Baarsen)
- View note image attachments in new tab when clicked instead of downloading them
- Improve sorting logic in UI and API. Explicitly define what sorting method is used by default
- - Allow more variations for commit messages closing issues (Julien Bianchi and Hannes Rosenögger)
- Fix overflow at sidebar when have several items
- Add notes for label changes in issue and merge requests
- Show tags in commit view (Hannes Rosenögger)
@@ -168,7 +179,7 @@ v 7.8.0
- Add a commit calendar to the user profile (Hannes Rosenögger)
- Submit comment on command-enter
- Notify all members of a group when that group is mentioned in a comment, for example: `@gitlab-org` or `@sales`.
- - Extend issue clossing pattern to include "Resolve", "Resolves", "Resolved", "Resolving" and "Close"
+ - Extend issue clossing pattern to include "Resolve", "Resolves", "Resolved", "Resolving" and "Close" (Julien Bianchi and Hannes Rosenögger)
- Fix long broadcast message cut-off on left sidebar (Visay Keo)
- Add Project Avatars (Steven Thonus and Hannes Rosenögger)
- Password reset token validity increased from 2 hours to 2 days since it is also send on account creation.
diff --git a/Gemfile.lock b/Gemfile.lock
index 4f1cab43dd5..7da4d3c3583 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -188,7 +188,7 @@ GEM
dotenv (>= 0.7)
thor (>= 0.13.6)
formatador (0.2.4)
- gemnasium-gitlab-service (0.2.5)
+ gemnasium-gitlab-service (0.2.4)
rugged (~> 0.21)
gemojione (2.0.0)
json
@@ -516,7 +516,7 @@ GEM
rubyntlm (0.5.0)
rubypants (0.2.0)
rugged (0.21.4)
- rugments (1.0.0.beta5)
+ rugments (1.0.0.beta6)
safe_yaml (0.9.7)
sanitize (2.1.0)
nokogiri (>= 1.4.4)
diff --git a/app/assets/javascripts/calendar.js.coffee b/app/assets/javascripts/calendar.js.coffee
index 2891a48e249..d08ef9361a6 100644
--- a/app/assets/javascripts/calendar.js.coffee
+++ b/app/assets/javascripts/calendar.js.coffee
@@ -7,7 +7,7 @@ class @calendar
constructor: (timestamps, starting_year, starting_month, calendar_activities_path) ->
cal = new CalHeatMap()
cal.init
- itemName: ["commit"]
+ itemName: ["contribution"]
data: timestamps
start: new Date(starting_year, starting_month)
domainLabelFormat: "%b"
@@ -27,7 +27,6 @@ class @calendar
legendCellPadding: 3
onClick: (date, count) ->
formated_date = date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate()
- $(".calendar_commit_activity").fadeOut 400
$.ajax
url: calendar_activities_path
data:
@@ -36,6 +35,4 @@ class @calendar
dataType: "html"
success: (data) ->
$(".user-calendar-activities").html data
- $(".calendar_commit_activity").find(".js-toggle-content").hide()
- $(".calendar_commit_activity").fadeIn 400
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index edf482f33d8..deabaf8a784 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -97,6 +97,7 @@ class Dispatcher
new ProjectFork()
when 'users:show'
new User()
+ new Activities()
switch path.first()
when 'admin'
diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee
index 09c202e42a5..6127d2bb480 100644
--- a/app/assets/javascripts/merge_request.js.coffee
+++ b/app/assets/javascripts/merge_request.js.coffee
@@ -113,8 +113,14 @@ class @MergeRequest
allowed_states = ["failed", "canceled", "running", "pending", "success"]
if state in allowed_states
$('.ci_widget.ci-' + state).show()
+ switch state
+ when "failed", "canceled"
+ @setMergeButtonClass('btn-danger')
+ when "running", "pending"
+ @setMergeButtonClass('btn-warning')
else
$('.ci_widget.ci-error').show()
+ @setMergeButtonClass('btn-danger')
showCiCoverage: (coverage) ->
cov_html = $('<span>')
@@ -144,6 +150,9 @@ class @MergeRequest
this.$('.merge-in-progress').hide()
this.$('.automerge_widget.already_cannot_be_merged').show()
+ setMergeButtonClass: (css_class) ->
+ $('.accept_merge_request').removeClass("btn-create").addClass(css_class)
+
mergeInProgress: ->
$.ajax
type: 'GET'
diff --git a/app/assets/javascripts/project_users_select.js.coffee b/app/assets/javascripts/project_users_select.js.coffee
index e22c7c11f1c..80ab1a61ab9 100644
--- a/app/assets/javascripts/project_users_select.js.coffee
+++ b/app/assets/javascripts/project_users_select.js.coffee
@@ -25,7 +25,7 @@ class @ProjectUsersSelect
initSelection: (element, callback) ->
id = $(element).val()
- if id isnt ""
+ if id != "" && id != "-1"
Api.user(id, callback)
@@ -44,10 +44,7 @@ class @ProjectUsersSelect
else
avatar = gon.default_avatar_url
- if user.id == ''
- avatarMarkup = ''
- else
- avatarMarkup = "<div class='user-image'><img class='avatar s24' src='#{avatar}'></div>"
+ avatarMarkup = "<div class='user-image'><img class='avatar s24' src='#{avatar}'></div>"
"<div class='user-result'>
#{avatarMarkup}
diff --git a/app/assets/stylesheets/generic/calendar.scss b/app/assets/stylesheets/generic/calendar.scss
index e2ab7fc51a5..a36fefe22c5 100644
--- a/app/assets/stylesheets/generic/calendar.scss
+++ b/app/assets/stylesheets/generic/calendar.scss
@@ -1,21 +1,8 @@
.user-calendar-activities {
-
- .calendar_commit_activity {
- padding: 5px 0 0;
- }
-
.calendar_onclick_hr {
padding: 0;
margin: 10px 0;
}
-
- .calendar_commit_date {
- color: #999;
- }
-
- .calendar_activity_summary {
- font-size: 14px;
- }
.str-truncated {
max-width: 70%;
@@ -31,14 +18,6 @@
background-color: #ddd;
}
}
-
- .commit-row-message {
- color: #333;
- &:hover {
- color: #444;
- text-decoration: underline;
- }
- }
}
/**
* This overwrites the default values of the cal-heatmap gem
diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss
index 7b7bb88bc20..af6ea58382f 100644
--- a/app/assets/stylesheets/pages/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -15,6 +15,11 @@
word-break: break-all;
margin-right: 200px;
display: block;
+
+ .file-mode {
+ margin-left: 10px;
+ color: #777;
+ }
}
.diff-btn-group {
@@ -34,11 +39,6 @@
font-family: $monospace_font;
font-size: smaller;
}
-
- .file-mode {
- font-family: $monospace_font;
- margin-left: 10px;
- }
}
.diff-content {
overflow: auto;
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index d8fe339b7b3..8abd4207beb 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -137,30 +137,15 @@
background-color: #F1FAF1;
}
- &.ci-pending {
- color: #548;
- border-color: #548;
- background-color: #F4F1FA;
- }
-
+ &.ci-pending,
&.ci-running {
color: $gl-warning;
border-color: $gl-warning;
background-color: #FAF5F1;
}
- &.ci-failed {
- color: $gl-danger;
- border-color: $gl-danger;
- background-color: #FAF1F1;
- }
-
- &.ci-canceled {
- color: $gl-warning;
- border-color: $gl-danger;
- background-color: #FAF5F1;
- }
-
+ &.ci-failed,
+ &.ci-canceled,
&.ci-error {
color: $gl-danger;
border-color: $gl-danger;
diff --git a/app/assets/stylesheets/themes/ui_blue.scss b/app/assets/stylesheets/themes/ui_blue.scss
index cb7980b5a07..e223058be8b 100644
--- a/app/assets/stylesheets/themes/ui_blue.scss
+++ b/app/assets/stylesheets/themes/ui_blue.scss
@@ -1,5 +1,5 @@
/**
- * Modern GitLab UI theme
+ * Blue GitLab UI theme
*/
.ui_blue {
@include dark-theme(#BECDE9, #2980b9, #1970a9, #096099);
diff --git a/app/controllers/admin/services_controller.rb b/app/controllers/admin/services_controller.rb
index 44a3f1379d8..76a938c5fe4 100644
--- a/app/controllers/admin/services_controller.rb
+++ b/app/controllers/admin/services_controller.rb
@@ -46,7 +46,9 @@ class Admin::ServicesController < Admin::ApplicationController
:user_key, :device, :priority, :sound, :bamboo_url, :username, :password,
:build_key, :server, :teamcity_url, :build_type,
:description, :issues_url, :new_issue_url, :restrict_to_branch,
- :send_from_committer_email, :disable_diffs
+ :send_from_committer_email, :disable_diffs,
+ :push_events, :tag_push_events, :note_events, :issues_events,
+ :merge_requests_events
])
end
end
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 68130eb128c..679d6897ce9 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -4,10 +4,7 @@ class UsersController < ApplicationController
layout :determine_layout
def show
- @contributed_projects = Project.
- where(id: authorized_projects_ids & @user.contributed_projects_ids).
- in_group_namespace.
- includes(:namespace).
+ @contributed_projects = contributed_projects.joined(@user).
reject(&:forked?)
@projects = @user.personal_projects.
@@ -16,24 +13,26 @@ class UsersController < ApplicationController
# Collect only groups common for both users
@groups = @user.groups & GroupsFinder.new.execute(current_user)
- # Get user activity feed for projects common for both users
- @events = @user.recent_events.
- where(project_id: authorized_projects_ids).
- with_associations.limit(30)
-
@title = @user.name
@title_url = user_path(@user)
respond_to do |format|
format.html
- format.atom { render layout: false }
+
+ format.atom do
+ load_events
+ render layout: false
+ end
+
+ format.json do
+ load_events
+ pager_json("events/_events", @events.count)
+ end
end
end
def calendar
- projects = Project.where(id: authorized_projects_ids & @user.contributed_projects_ids)
-
- calendar = Gitlab::CommitsCalendar.new(projects, @user)
+ calendar = contributions_calendar
@timestamps = calendar.timestamps
@starting_year = calendar.starting_year
@starting_month = calendar.starting_month
@@ -42,20 +41,13 @@ class UsersController < ApplicationController
end
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 date
- @calendar_activities = Gitlab::CommitsCalendar.get_commits_for_date(projects, @user, date)
- else
- @calendar_activities = {}
+ if @calendar_date
+ @events = contributions_calendar.events_by_date(@calendar_date)
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
@@ -82,4 +74,24 @@ class UsersController < ApplicationController
@authorized_projects_ids ||=
ProjectsFinder.new.execute(current_user).pluck(:id)
end
+
+ def contributed_projects
+ @contributed_projects = Project.
+ where(id: authorized_projects_ids & @user.contributed_projects_ids).
+ includes(:namespace)
+ end
+
+ def contributions_calendar
+ @contributions_calendar ||= Gitlab::ContributionsCalendar.
+ new(contributed_projects.reject(&:forked?), @user)
+ end
+
+ def load_events
+ # Get user activity feed for projects common for both users
+ @events = @user.recent_events.
+ where(project_id: authorized_projects_ids).
+ with_associations
+
+ @events = @events.limit(20).offset(params[:offset] || 0)
+ end
end
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 15c5dcb6a25..a4bd4d30215 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -58,22 +58,11 @@ module IssuesHelper
end
def bulk_update_milestone_options
- options_for_select(['None (backlog)']) +
+ options_for_select([['None (backlog)', -1]]) +
options_from_collection_for_select(project_active_milestones, 'id',
'title', params[:milestone_id])
end
- def bulk_update_assignee_options(project = @project)
- options_for_select(['None (unassigned)']) +
- options_from_collection_for_select(project.team.members, 'id',
- 'name', params[:assignee_id])
- end
-
- def assignee_options(object, project = @project)
- options_from_collection_for_select(project.team.members.sort_by(&:name),
- 'id', 'name', object.assignee_id)
- end
-
def milestone_options(object)
options_from_collection_for_select(object.project.milestones.active,
'id', 'title', object.milestone_id)
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index a14277180c7..7bf51b5b8e8 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -146,6 +146,10 @@ module ProjectsHelper
nav_tabs << feature if project.send :"#{feature}_enabled"
end
+ if project.issues_enabled || project.merge_requests_enabled
+ nav_tabs << [:milestones, :labels]
+ end
+
nav_tabs.flatten
end
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index 7d3fcfa7037..c31a556ff7b 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -23,9 +23,9 @@ module SearchHelper
# Autocomplete results for various settings pages
def default_autocomplete
[
- { label: "My Profile settings", url: profile_path },
- { label: "My SSH Keys", url: profile_keys_path },
- { label: "My Dashboard", url: root_path },
+ { label: "Profile settings", url: profile_path },
+ { label: "SSH Keys", url: profile_keys_path },
+ { label: "Dashboard", url: root_path },
{ label: "Admin Section", url: admin_root_path },
]
end
diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb
index b55129de292..3cd812825e2 100644
--- a/app/mailers/emails/projects.rb
+++ b/app/mailers/emails/projects.rb
@@ -16,31 +16,69 @@ module Emails
subject: subject("Project was moved"))
end
- def repository_push_email(project_id, recipient, author_id, branch, compare, reverse_compare = false, send_from_committer_email = false, disable_diffs = false)
+ def repository_push_email(project_id, recipient, author_id: nil,
+ ref: nil,
+ action: nil,
+ compare: nil,
+ reverse_compare: false,
+ send_from_committer_email: false,
+ disable_diffs: false)
+ unless author_id && ref && action
+ raise ArgumentError, "missing keywords: author_id, ref, action"
+ end
+
@project = Project.find(project_id)
@author = User.find(author_id)
@reverse_compare = reverse_compare
@compare = compare
- @commits = Commit.decorate(compare.commits)
- @diffs = compare.diffs
- @branch = Gitlab::Git.ref_name(branch)
+ @ref_name = Gitlab::Git.ref_name(ref)
+ @ref_type = Gitlab::Git.tag_ref?(ref) ? "tag" : "branch"
+ @action = action
@disable_diffs = disable_diffs
- @subject = "[#{@project.path_with_namespace}][#{@branch}] "
+ if @compare
+ @commits = Commit.decorate(compare.commits)
+ @diffs = compare.diffs
+ end
+
+ @action_name =
+ case action
+ when :create
+ "pushed new"
+ when :delete
+ "deleted"
+ else
+ "pushed to"
+ end
+
+ @subject = "[#{@project.path_with_namespace}]"
+ @subject << "[#{@ref_name}]" if action == :push
+ @subject << " "
+
+ if action == :push
+ if @commits.length > 1
+ @target_url = namespace_project_compare_url(@project.namespace,
+ @project,
+ from: Commit.new(@compare.base),
+ to: Commit.new(@compare.head))
+ @subject << "Deleted " if @reverse_compare
+ @subject << "#{@commits.length} commits: #{@commits.first.title}"
+ else
+ @target_url = namespace_project_commit_url(@project.namespace,
+ @project, @commits.first)
- if @commits.length > 1
- @target_url = namespace_project_compare_url(@project.namespace,
- @project,
- from: Commit.new(@compare.base),
- to: Commit.new(@compare.head))
- @subject << "Deleted " if @reverse_compare
- @subject << "#{@commits.length} commits: #{@commits.first.title}"
+ @subject << "Deleted 1 commit: " if @reverse_compare
+ @subject << @commits.first.title
+ end
else
- @target_url = namespace_project_commit_url(@project.namespace,
- @project, @commits.first)
+ unless action == :delete
+ @target_url = namespace_project_tree_url(@project.namespace,
+ @project, @ref_name)
+ end
- @subject << "Deleted 1 commit: " if @reverse_compare
- @subject << @commits.first.title
+ subject_action = @action_name.dup
+ subject_action[0] = subject_action[0].capitalize
+ @subject << "#{subject_action} #{@ref_type} #{@ref_name}"
end
@disable_footer = true
diff --git a/app/models/concerns/taskable.rb b/app/models/concerns/taskable.rb
index 410e8dc820b..bbb3b301a9f 100644
--- a/app/models/concerns/taskable.rb
+++ b/app/models/concerns/taskable.rb
@@ -5,7 +5,7 @@
# Used by MergeRequest and Issue
module Taskable
TASK_PATTERN_MD = /^(?<bullet> *[*-] *)\[(?<checked>[ xX])\]/.freeze
- TASK_PATTERN_HTML = /^<li>\[(?<checked>[ xX])\]/.freeze
+ TASK_PATTERN_HTML = /^<li>(?<p_tag>\s*<p>)?\[(?<checked>[ xX])\]/.freeze
# Change the state of a task list item for this Taskable. Edit the object's
# description by finding the nth task item and changing its checkbox
diff --git a/app/models/event.rb b/app/models/event.rb
index 2103a48a71b..57f6d5cd4e0 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -55,6 +55,12 @@ class Event < ActiveRecord::Base
order('id DESC').limit(100).
update_all(updated_at: Time.now)
end
+
+ def contributions
+ where("action = ? OR (target_type in (?) AND action in (?))",
+ Event::PUSHED, ["MergeRequest", "Issue"],
+ [Event::CREATED, Event::CLOSED, Event::MERGED])
+ end
end
def proper?
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 798306f6dcc..5634f9a686e 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -105,6 +105,15 @@ class MergeRequest < ActiveRecord::Base
state :unchecked
state :can_be_merged
state :cannot_be_merged
+
+ around_transition do |merge_request, transition, block|
+ merge_request.record_timestamps = false
+ begin
+ block.call
+ ensure
+ merge_request.record_timestamps = true
+ end
+ end
end
validates :source_project, presence: true, unless: :allow_broken
diff --git a/app/models/note.rb b/app/models/note.rb
index 27b583a869a..e86160e7cd9 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -48,6 +48,7 @@ class Note < ActiveRecord::Base
scope :inline, ->{ where("line_code IS NOT NULL") }
scope :not_inline, ->{ where(line_code: [nil, '']) }
scope :system, ->{ where(system: true) }
+ scope :user, ->{ where(system: false) }
scope :common, ->{ where(noteable_type: ["", nil]) }
scope :fresh, ->{ order(created_at: :asc, id: :asc) }
scope :inc_author_project, ->{ includes(:project, :author) }
diff --git a/app/models/project_contributions.rb b/app/models/project_contributions.rb
deleted file mode 100644
index bfe9928b158..00000000000
--- a/app/models/project_contributions.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-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
diff --git a/app/models/project_services/emails_on_push_service.rb b/app/models/project_services/emails_on_push_service.rb
index acb5e7f1af5..6f6e5950aab 100644
--- a/app/models/project_services/emails_on_push_service.rb
+++ b/app/models/project_services/emails_on_push_service.rb
@@ -36,13 +36,19 @@ class EmailsOnPushService < Service
end
def supported_events
- %w(push)
+ %w(push tag_push)
end
def execute(push_data)
return unless supported_events.include?(push_data[:object_kind])
- EmailsOnPushWorker.perform_async(project_id, recipients, push_data, send_from_committer_email?, disable_diffs?)
+ EmailsOnPushWorker.perform_async(
+ project_id,
+ recipients,
+ push_data,
+ send_from_committer_email: send_from_committer_email?,
+ disable_diffs: disable_diffs?
+ )
end
def send_from_committer_email?
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 082ad7a0c6a..77765cae1a0 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -149,41 +149,6 @@ class Repository
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
@lookup_cache ||= {}
end
diff --git a/app/models/user.rb b/app/models/user.rb
index ba325132df8..979150b4d68 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -110,6 +110,7 @@ class User < ActiveRecord::Base
has_many :notes, dependent: :destroy, foreign_key: :author_id
has_many :merge_requests, dependent: :destroy, foreign_key: :author_id
has_many :events, dependent: :destroy, foreign_key: :author_id, class_name: "Event"
+ has_many :subscriptions, dependent: :destroy
has_many :recent_events, -> { order "id DESC" }, foreign_key: :author_id, class_name: "Event"
has_many :assigned_issues, dependent: :destroy, foreign_key: :assignee_id, class_name: "Issue"
has_many :assigned_merge_requests, dependent: :destroy, foreign_key: :assignee_id, class_name: "MergeRequest"
@@ -603,13 +604,10 @@ class User < ActiveRecord::Base
end
def contributed_projects_ids
- Event.where(author_id: self).
+ Event.contributions.where(author_id: self).
where("created_at > ?", Time.now - 1.year).
- where("action = :pushed OR (target_type = 'MergeRequest' AND action = :created)",
- pushed: Event::PUSHED, created: Event::CREATED).
reorder(project_id: :desc).
select(:project_id).
- uniq
- .map(&:project_id)
+ uniq.map(&:project_id)
end
end
diff --git a/app/services/issues/bulk_update_service.rb b/app/services/issues/bulk_update_service.rb
index c7cd20b6b60..eb07413ee94 100644
--- a/app/services/issues/bulk_update_service.rb
+++ b/app/services/issues/bulk_update_service.rb
@@ -4,9 +4,9 @@ module Issues
issues_ids = params.delete(:issues_ids).split(",")
issue_params = params
- issue_params.delete(:state_event) unless issue_params[:state_event].present?
- issue_params.delete(:milestone_id) unless issue_params[:milestone_id].present?
- issue_params.delete(:assignee_id) unless issue_params[:assignee_id].present?
+ issue_params.delete(:state_event) unless issue_params[:state_event].present?
+ issue_params.delete(:milestone_id) unless issue_params[:milestone_id].present?
+ issue_params.delete(:assignee_id) unless issue_params[:assignee_id].present?
issues = Issue.where(id: issues_ids)
issues.each do |issue|
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index c61d67a7893..3371fe7d5ef 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -14,6 +14,9 @@ module Issues
issue.update_nth_task(params[:task_num].to_i, false)
end
+ params[:assignee_id] = "" if params[:assignee_id] == "-1"
+ params[:milestone_id] = "" if params[:milestone_id] == "-1"
+
old_labels = issue.labels.to_a
if params.present? && issue.update_attributes(params.except(:state_event,
diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb
index 7eef2c2d6a5..e9b526d1fb7 100644
--- a/app/services/merge_requests/refresh_service.rb
+++ b/app/services/merge_requests/refresh_service.rb
@@ -53,7 +53,7 @@ module MergeRequests
if merge_request.source_branch == @branch_name || force_push?
merge_request.reload_code
- update_merge_request(merge_request)
+ merge_request.mark_as_unchecked
else
mr_commit_ids = merge_request.commits.map(&:id)
push_commit_ids = @commits.map(&:id)
@@ -61,20 +61,14 @@ module MergeRequests
if matches.any?
merge_request.reload_code
- update_merge_request(merge_request)
+ merge_request.mark_as_unchecked
else
- update_merge_request(merge_request)
+ merge_request.mark_as_unchecked
end
end
end
end
- def update_merge_request(merge_request)
- MergeRequests::UpdateService.new(
- merge_request.target_project,
- @current_user, merge_status: 'unchecked').execute(merge_request)
- end
-
# Add comment about pushing new commits to merge requests
def comment_mr_with_commits
merge_requests = @project.origin_merge_requests.opened.where(source_branch: @branch_name).to_a
diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb
index 870b50bb60d..0ac6dfea6fd 100644
--- a/app/services/merge_requests/update_service.rb
+++ b/app/services/merge_requests/update_service.rb
@@ -23,6 +23,9 @@ module MergeRequests
merge_request.update_nth_task(params[:task_num].to_i, false)
end
+ params[:assignee_id] = "" if params[:assignee_id] == "-1"
+ params[:milestone_id] = "" if params[:milestone_id] == "-1"
+
old_labels = merge_request.labels.to_a
if params.present? && merge_request.update_attributes(
diff --git a/app/views/admin/broadcast_messages/index.html.haml b/app/views/admin/broadcast_messages/index.html.haml
index c0afaf16d8f..7e29311bf42 100644
--- a/app/views/admin/broadcast_messages/index.html.haml
+++ b/app/views/admin/broadcast_messages/index.html.haml
@@ -21,13 +21,11 @@
.form-group.js-toggle-colors-container.hide
= f.label :color, "Background Color", class: 'control-label'
.col-sm-10
- = f.text_field :color, placeholder: "#AA33EE", class: "form-control"
- .light 6 character hex values starting with a # sign.
+ = f.color_field :color, value: "#AA33EE", class: "form-control"
.form-group.js-toggle-colors-container.hide
= f.label :font, "Font Color", class: 'control-label'
.col-sm-10
- = f.text_field :font, placeholder: "#224466", class: "form-control"
- .light 6 character hex values starting with a # sign.
+ = f.color_field :font, value: "#224466", class: "form-control"
.form-group
= f.label :starts_at, class: 'control-label'
.col-sm-10.datetime-controls
diff --git a/app/views/admin/services/_form.html.haml b/app/views/admin/services/_form.html.haml
index a953833b37c..18b7e8ba270 100644
--- a/app/views/admin/services/_form.html.haml
+++ b/app/views/admin/services/_form.html.haml
@@ -14,6 +14,11 @@
= preserve do
= markdown @service.help
+ .form-group
+ = f.label :active, "Active", class: "control-label"
+ .col-sm-10
+ = f.check_box :active
+
- if @service.supported_events.length > 1
.form-group
= f.label :url, "Trigger", class: 'control-label'
@@ -34,6 +39,14 @@
%strong Tag push events
%p.light
This url will be triggered when a new tag is pushed to the repository
+ - if @service.supported_events.include?("note")
+ %div
+ = f.check_box :note_events, class: 'pull-left'
+ .prepend-left-20
+ = f.label :note_events, class: 'list-label' do
+ %strong Comments
+ %p.light
+ This url will be triggered when someone adds a comment
- if @service.supported_events.include?("issue")
%div
= f.check_box :issues_events, class: 'pull-left'
diff --git a/app/views/devise/mailer/confirmation_instructions.html.erb b/app/views/devise/mailer/confirmation_instructions.html.erb
index cb1291cf3bf..c6fa8f0ee36 100644
--- a/app/views/devise/mailer/confirmation_instructions.html.erb
+++ b/app/views/devise/mailer/confirmation_instructions.html.erb
@@ -6,4 +6,4 @@
<p>You can confirm your account through the link below:</p>
<% end %>
-<p><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></p>
+<p><%= link_to 'Confirm your account', confirmation_url(@resource, confirmation_token: @token) %></p>
diff --git a/app/views/devise/mailer/reset_password_instructions.html.erb b/app/views/devise/mailer/reset_password_instructions.html.erb
index 7913e88beb6..23b31da92d8 100644
--- a/app/views/devise/mailer/reset_password_instructions.html.erb
+++ b/app/views/devise/mailer/reset_password_instructions.html.erb
@@ -2,7 +2,7 @@
<p>Someone has requested a link to change your password, and you can do this through the link below.</p>
-<p><%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %></p>
+<p><%= link_to 'Change your password', edit_password_url(@resource, reset_password_token: @token) %></p>
<p>If you didn't request this, please ignore this email.</p>
<p>Your password won't change until you access the link above and create a new one.</p>
diff --git a/app/views/devise/mailer/unlock_instructions.html.erb b/app/views/devise/mailer/unlock_instructions.html.erb
index 8c2a4f0c2d9..79d6c761d8f 100644
--- a/app/views/devise/mailer/unlock_instructions.html.erb
+++ b/app/views/devise/mailer/unlock_instructions.html.erb
@@ -4,4 +4,4 @@
<p>Click the link below to unlock your account:</p>
-<p><%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %></p>
+<p><%= link_to 'Unlock your account', unlock_url(@resource, unlock_token: @token) %></p>
diff --git a/app/views/devise/passwords/edit.html.haml b/app/views/devise/passwords/edit.html.haml
index 0640739b5d7..56048e99c17 100644
--- a/app/views/devise/passwords/edit.html.haml
+++ b/app/views/devise/passwords/edit.html.haml
@@ -11,7 +11,7 @@
%div
= f.password_field :password_confirmation, class: "form-control bottom", placeholder: "Confirm new password", required: true
.clearfix
- = f.submit "Change my password", class: "btn btn-primary"
+ = f.submit "Change your password", class: "btn btn-primary"
.clearfix.prepend-top-20
%p
diff --git a/app/views/devise/registrations/edit.html.erb b/app/views/devise/registrations/edit.html.erb
index b11817af95d..f379e71ae5b 100644
--- a/app/views/devise/registrations/edit.html.erb
+++ b/app/views/devise/registrations/edit.html.erb
@@ -21,8 +21,8 @@
<div><%= f.submit "Update", class: "input_button" %></div>
<% end %>
-<h3>Cancel my account</h3>
+<h3>Cancel your account</h3>
-<p>Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %>.</p>
+<p>Unhappy? <%= link_to "Cancel your account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %>.</p>
<%= link_to "Back", :back %>
diff --git a/app/views/help/ui.html.haml b/app/views/help/ui.html.haml
index ed03f885dcd..246a6c1bdfd 100644
--- a/app/views/help/ui.html.haml
+++ b/app/views/help/ui.html.haml
@@ -53,7 +53,7 @@
%code .panel .well-list
.panel.panel-default
- .panel-heading My list
+ .panel-heading Your list
%ul.well-list
%li
One item
diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml
index fc8a487ece7..b1c2e1a7b19 100644
--- a/app/views/layouts/_head_panel.html.haml
+++ b/app/views/layouts/_head_panel.html.haml
@@ -25,7 +25,7 @@
= link_to explore_root_path, title: "Explore", class: 'has_bottom_tooltip', 'data-original-title' => 'Public area' do
%i.fa.fa-globe
%li
- = link_to user_snippets_path(current_user), title: "My snippets", class: 'has_bottom_tooltip', 'data-original-title' => 'My snippets' do
+ = link_to user_snippets_path(current_user), title: "Your snippets", class: 'has_bottom_tooltip', 'data-original-title' => 'Your snippets' do
%i.fa.fa-clipboard
- if current_user.is_admin?
%li
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index 91cae2b572c..52681865d64 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -44,11 +44,12 @@
%span
Graphs
- = nav_link(controller: :milestones) do
- = link_to namespace_project_milestones_path(@project.namespace, @project), title: 'Milestones' do
- %i.fa.fa-clock-o
- %span
- Milestones
+ - if project_nav_tab? :milestones
+ = nav_link(controller: :milestones) do
+ = link_to namespace_project_milestones_path(@project.namespace, @project), title: 'Milestones' do
+ %i.fa.fa-clock-o
+ %span
+ Milestones
- if project_nav_tab? :issues
= nav_link(controller: :issues) do
@@ -67,11 +68,12 @@
Merge Requests
%span.count.merge_counter= @project.merge_requests.opened.count
- = nav_link(controller: :labels) do
- = link_to namespace_project_labels_path(@project.namespace, @project), title: 'Labels' do
- %i.fa.fa-tags
- %span
- Labels
+ - if project_nav_tab? :labels
+ = nav_link(controller: :labels) do
+ = link_to namespace_project_labels_path(@project.namespace, @project), title: 'Labels' do
+ %i.fa.fa-tags
+ %span
+ Labels
- if project_nav_tab? :wiki
= nav_link(controller: :wikis) do
diff --git a/app/views/notify/repository_push_email.html.haml b/app/views/notify/repository_push_email.html.haml
index 039b92df2be..bbf7004c906 100644
--- a/app/views/notify/repository_push_email.html.haml
+++ b/app/views/notify/repository_push_email.html.haml
@@ -1,66 +1,67 @@
-%h3 #{@author.name} pushed to #{@branch} at #{link_to @project.name_with_namespace, namespace_project_url(@project.namespace, @project)}
+%h3 #{@author.name} #{@action_name} #{@ref_type} #{@ref_name} at #{link_to @project.name_with_namespace, namespace_project_url(@project.namespace, @project)}
-- if @reverse_compare
- %p
- %strong WARNING:
- The push did not contain any new commits, but force pushed to delete the commits and changes below.
+- if @compare
+ - if @reverse_compare
+ %p
+ %strong WARNING:
+ The push did not contain any new commits, but force pushed to delete the commits and changes below.
-%h4
- = @reverse_compare ? "Deleted commits:" : "Commits:"
+ %h4
+ = @reverse_compare ? "Deleted commits:" : "Commits:"
-%ul
- - @commits.each do |commit|
- %li
- %strong #{link_to commit.short_id, namespace_project_commit_url(@project.namespace, @project, commit)}
- %div
- %span by #{commit.author_name}
- %i at #{commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ")}
- %pre.commit-message
- = commit.safe_message
+ %ul
+ - @commits.each do |commit|
+ %li
+ %strong #{link_to commit.short_id, namespace_project_commit_url(@project.namespace, @project, commit)}
+ %div
+ %span by #{commit.author_name}
+ %i at #{commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ")}
+ %pre.commit-message
+ = commit.safe_message
-%h4 #{pluralize @diffs.count, "changed file"}:
+ %h4 #{pluralize @diffs.count, "changed file"}:
-%ul
- - @diffs.each_with_index do |diff, i|
- %li.file-stats
- %a{href: "#{@target_url if @disable_diffs}#diff-#{i}" }
- - if diff.deleted_file
- %span.deleted-file
- &minus;
+ %ul
+ - @diffs.each_with_index do |diff, i|
+ %li.file-stats
+ %a{href: "#{@target_url if @disable_diffs}#diff-#{i}" }
+ - if diff.deleted_file
+ %span.deleted-file
+ &minus;
+ = diff.old_path
+ - elsif diff.renamed_file
= diff.old_path
- - elsif diff.renamed_file
- = diff.old_path
- &rarr;
- = diff.new_path
- - elsif diff.new_file
- %span.new-file
- &plus;
+ &rarr;
= diff.new_path
- - else
- = diff.new_path
-
-- unless @disable_diffs
- %h4 Changes:
- - @diffs.each_with_index do |diff, i|
- %li{id: "diff-#{i}"}
- %a{href: @target_url + "#diff-#{i}"}
- - if diff.deleted_file
- %strong
- = diff.old_path
- deleted
- - elsif diff.renamed_file
- %strong
- = diff.old_path
- &rarr;
- %strong
+ - elsif diff.new_file
+ %span.new-file
+ &plus;
+ = diff.new_path
+ - else
= diff.new_path
- - else
- %strong
- = diff.new_path
- %hr
- %pre
- = color_email_diff(diff.diff)
- %br
-- if @compare.timeout
- %h5 Huge diff. To prevent performance issues changes are hidden
+ - unless @disable_diffs
+ %h4 Changes:
+ - @diffs.each_with_index do |diff, i|
+ %li{id: "diff-#{i}"}
+ %a{href: @target_url + "#diff-#{i}"}
+ - if diff.deleted_file
+ %strong
+ = diff.old_path
+ deleted
+ - elsif diff.renamed_file
+ %strong
+ = diff.old_path
+ &rarr;
+ %strong
+ = diff.new_path
+ - else
+ %strong
+ = diff.new_path
+ %hr
+ %pre
+ = color_email_diff(diff.diff)
+ %br
+
+ - if @compare.timeout
+ %h5 Huge diff. To prevent performance issues changes are hidden
diff --git a/app/views/notify/repository_push_email.text.haml b/app/views/notify/repository_push_email.text.haml
index 8d67a42234e..97a176ed2a3 100644
--- a/app/views/notify/repository_push_email.text.haml
+++ b/app/views/notify/repository_push_email.text.haml
@@ -1,47 +1,49 @@
-#{@author.name} pushed to #{@branch} at #{@project.name_with_namespace}
-\
-\
-- if @reverse_compare
- WARNING: The push did not contain any new commits, but force pushed to delete the commits and changes below.
+#{@author.name} #{@action_name} #{@ref_type} #{@ref_name} at #{@project.name_with_namespace}
+- if @compare
\
\
-= @reverse_compare ? "Deleted commits:" : "Commits:"
-- @commits.each do |commit|
- #{commit.short_id} by #{commit.author_name} at #{commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ")}
- #{commit.safe_message}
- \- - - - -
-\
-\
-#{pluralize @diffs.count, "changed file"}:
-\
-- @diffs.each do |diff|
- - if diff.deleted_file
- \- − #{diff.old_path}
- - elsif diff.renamed_file
- \- #{diff.old_path} → #{diff.new_path}
- - elsif diff.new_file
- \- + #{diff.new_path}
- - else
- \- #{diff.new_path}
-- unless @disable_diffs
+ - if @reverse_compare
+ WARNING: The push did not contain any new commits, but force pushed to delete the commits and changes below.
+ \
+ \
+ = @reverse_compare ? "Deleted commits:" : "Commits:"
+ - @commits.each do |commit|
+ #{commit.short_id} by #{commit.author_name} at #{commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ")}
+ #{commit.safe_message}
+ \- - - - -
+ \
\
+ #{pluralize @diffs.count, "changed file"}:
\
- Changes:
- @diffs.each do |diff|
- \
- \=====================================
- if diff.deleted_file
- #{diff.old_path} deleted
+ \- − #{diff.old_path}
- elsif diff.renamed_file
- #{diff.old_path} → #{diff.new_path}
+ \- #{diff.old_path} → #{diff.new_path}
+ - elsif diff.new_file
+ \- + #{diff.new_path}
- else
- = diff.new_path
- \=====================================
- != diff.diff
-- if @compare.timeout
- \
- \
- Huge diff. To prevent performance issues it was hidden
-\
-\
-View it on GitLab: #{@target_url}
+ \- #{diff.new_path}
+ - unless @disable_diffs
+ \
+ \
+ Changes:
+ - @diffs.each do |diff|
+ \
+ \=====================================
+ - if diff.deleted_file
+ #{diff.old_path} deleted
+ - elsif diff.renamed_file
+ #{diff.old_path} → #{diff.new_path}
+ - else
+ = diff.new_path
+ \=====================================
+ != diff.diff
+ - if @compare.timeout
+ \
+ \
+ Huge diff. To prevent performance issues it was hidden
+ - if @target_url
+ \
+ \
+ View it on GitLab: #{@target_url}
diff --git a/app/views/profiles/history.html.haml b/app/views/profiles/history.html.haml
index 9cafe03b8b3..b1ab433f48f 100644
--- a/app/views/profiles/history.html.haml
+++ b/app/views/profiles/history.html.haml
@@ -1,5 +1,5 @@
%h3.page-title
- My Account History
+ Your Account History
%p.light
All events created by your account are listed below.
%hr
diff --git a/app/views/profiles/keys/index.html.haml b/app/views/profiles/keys/index.html.haml
index 965d5e032f9..0904c50c88b 100644
--- a/app/views/profiles/keys/index.html.haml
+++ b/app/views/profiles/keys/index.html.haml
@@ -3,8 +3,6 @@
.pull-right
= link_to "Add SSH Key", new_profile_key_path, class: "btn btn-new"
%p.light
- My SSH keys: #{@keys.count}
- %br
Before you can add an SSH key you need to
= link_to "generate it.", help_page_path("ssh", "README")
%hr
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index c0e13e67be3..a295a0d6cdc 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -19,7 +19,7 @@
.fork-buttons
- if current_user && can?(current_user, :fork_project, @project) && @project.namespace != current_user.namespace
- if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2
- = link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: 'Go to my fork' do
+ = link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: 'Go to your fork' do
= link_to_toggle_fork
- else
= link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project" do
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index 4c853f577e9..c6026f96804 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -13,7 +13,7 @@
- note_count = @note_counts.fetch(commit.id, 0)
- else
- notes = project.notes.for_commit_id(commit.id)
- - note_count = notes.count
+ - note_count = notes.user.count
- if note_count > 0
%span.light
diff --git a/app/views/projects/diffs/_file.html.haml b/app/views/projects/diffs/_file.html.haml
index 860ab096341..672a6635321 100644
--- a/app/views/projects/diffs/_file.html.haml
+++ b/app/views/projects/diffs/_file.html.haml
@@ -13,12 +13,13 @@
- submodule_item = project.repository.blob_at(@commit.id, diff_file.file_path)
= submodule_link(submodule_item, @commit.id)
- else
- - if diff_file.renamed_file
- %span= "#{diff_file.old_path} renamed to #{diff_file.new_path}"
- - else
- %span= diff_file.new_path
- - if diff_file.mode_changed?
- %span.file-mode= "#{diff_file.diff.a_mode} → #{diff_file.diff.b_mode}"
+ %span
+ - if diff_file.renamed_file
+ = "#{diff_file.old_path} renamed to #{diff_file.new_path}"
+ - else
+ = diff_file.new_path
+ - if diff_file.mode_changed?
+ %span.file-mode= "#{diff_file.diff.a_mode} → #{diff_file.diff.b_mode}"
.diff-btn-group
- if blob.text?
diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml
index b1c987563f1..e691db9c08e 100644
--- a/app/views/projects/diffs/_text_file.html.haml
+++ b/app/views/projects/diffs/_text_file.html.haml
@@ -16,7 +16,7 @@
- else
%td.old_line
= link_to raw(type == "new" ? "&nbsp;" : line_old), "##{line_code}", id: line_code
- - if @comments_allowed
+ - if @comments_allowed && can?(current_user, :write_note, @project)
= link_to_new_diff_note(line_code)
%td.new_line{data: {linenumber: line.new_pos}}
= link_to raw(type == "old" ? "&nbsp;" : line.new_pos) , "##{line_code}", id: line_code
diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml
index 7b06fe72882..998e74d12cf 100644
--- a/app/views/projects/issues/_issue.html.haml
+++ b/app/views/projects/issues/_issue.html.haml
@@ -10,11 +10,12 @@
- if issue.closed?
%span
CLOSED
- - if issue.notes.any?
+ - note_count = issue.notes.user.count
+ - if note_count > 0
&nbsp;
%span
%i.fa.fa-comments
- = issue.notes.count
+ = note_count
.issue-info
= link_to "##{issue.iid}", issue_path(issue), class: "light"
diff --git a/app/views/projects/labels/_form.html.haml b/app/views/projects/labels/_form.html.haml
index 2305fce112e..ad993db6c0b 100644
--- a/app/views/projects/labels/_form.html.haml
+++ b/app/views/projects/labels/_form.html.haml
@@ -16,9 +16,9 @@
.col-sm-10
.input-group
.input-group-addon.label-color-preview &nbsp;
- = f.color_field :color, placeholder: "#AA33EE", class: "form-control"
+ = f.color_field :color, value: "#AA33EE", class: "form-control"
.help-block
- 6 character hex values starting with a # sign.
+ Choose any color.
%br
Or you can choose one of suggested colors below
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index ecbff722b42..4f30d1e69f7 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -16,11 +16,12 @@
%span.label-branch<
%i.fa.fa-code-fork
%span= merge_request.target_branch
- - if merge_request.notes.any?
+ - note_count = merge_request.mr_and_commit_notes.user.count
+ - if note_count > 0
&nbsp;
%span
%i.fa.fa-comments
- = merge_request.mr_and_commit_notes.count
+ = note_count
.merge-request-info
= link_to "##{merge_request.iid}", merge_request_path(merge_request), class: "light"
- if merge_request.assignee
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index ca4ceecb225..a74aede4e6b 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -40,7 +40,7 @@
= link_to merge_request_path(@merge_request) do
%i.fa.fa-comments
Discussion
- %span.badge= @merge_request.mr_and_commit_notes.count
+ %span.badge= @merge_request.mr_and_commit_notes.user.count
%li.commits-tab{data: {action: 'commits'}}
= link_to merge_request_path(@merge_request), title: 'Commits' do
%i.fa.fa-history
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index 110d8967342..25cc0030965 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -60,11 +60,12 @@
Participants
%span.badge= @users.count
- .pull-right
- = link_to new_namespace_project_issue_path(@project.namespace, @project, issue: { milestone_id: @milestone.id }), class: "btn btn-grouped", title: "New Issue" do
- %i.fa.fa-plus
- New Issue
- = link_to 'Browse Issues', namespace_project_issues_path(@milestone.project.namespace, @milestone.project, milestone_id: @milestone.id), class: "btn edit-milestone-link btn-grouped"
+ - if @project.issues_enabled
+ .pull-right
+ = link_to new_namespace_project_issue_path(@project.namespace, @project, issue: { milestone_id: @milestone.id }), class: "btn btn-grouped", title: "New Issue" do
+ %i.fa.fa-plus
+ New Issue
+ = link_to 'Browse Issues', namespace_project_issues_path(@milestone.project.namespace, @milestone.project, milestone_id: @milestone.id), class: "btn edit-milestone-link btn-grouped"
.tab-content
.tab-pane.active#tab-issues
diff --git a/app/views/projects/notes/_discussion.html.haml b/app/views/projects/notes/_discussion.html.haml
index f4c6fad2fed..3561ca49f81 100644
--- a/app/views/projects/notes/_discussion.html.haml
+++ b/app/views/projects/notes/_discussion.html.haml
@@ -2,7 +2,8 @@
.timeline-entry
.timeline-entry-inner
.timeline-icon
- = image_tag avatar_icon(note.author_email), class: "avatar s40"
+ = link_to user_path(note.author) do
+ = image_tag avatar_icon(note.author_email), class: "avatar s40"
.timeline-content
- if note.for_merge_request?
- if note.outdated?
diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml
index f3d00a6f06d..71bdf5c8f2a 100644
--- a/app/views/projects/notes/_note.html.haml
+++ b/app/views/projects/notes/_note.html.haml
@@ -4,7 +4,8 @@
- if note.system
%span.fa.fa-circle
- else
- = image_tag avatar_icon(note.author_email), class: "avatar s40"
+ = link_to user_path(note.author) do
+ = image_tag avatar_icon(note.author_email), class: "avatar s40"
.timeline-content
.note-header
.note-actions
@@ -21,7 +22,8 @@
%i.fa.fa-trash-o.cred
Remove
- if note.system
- = image_tag avatar_icon(note.author_email), class: "avatar s16"
+ = link_to user_path(note.author) do
+ = image_tag avatar_icon(note.author_email), class: "avatar s16"
= link_to_member(@project, note.author, avatar: false)
%span.author-username
= '@' + note.author.username
diff --git a/app/views/projects/notes/discussions/_diff.html.haml b/app/views/projects/notes/discussions/_diff.html.haml
index f717c77a898..711aa39101b 100644
--- a/app/views/projects/notes/discussions/_diff.html.haml
+++ b/app/views/projects/notes/discussions/_diff.html.haml
@@ -2,13 +2,13 @@
- if diff
.diff-file
.diff-header
- - if diff.deleted_file
- %span= diff.old_path
- - else
- %span= diff.new_path
- - if diff.a_mode && diff.b_mode && diff.a_mode != diff.b_mode
- %span.file-mode= "#{diff.a_mode} → #{diff.b_mode}"
- %br/
+ %span
+ - if diff.deleted_file
+ = diff.old_path
+ - else
+ = diff.new_path
+ - if diff.a_mode && diff.b_mode && diff.a_mode != diff.b_mode
+ %span.file-mode= "#{diff.a_mode} → #{diff.b_mode}"
.diff-content
%table
- note.truncated_diff_lines.each do |line|
diff --git a/app/views/snippets/current_user_index.html.haml b/app/views/snippets/current_user_index.html.haml
index b2b7ea4df0e..0df5ade500d 100644
--- a/app/views/snippets/current_user_index.html.haml
+++ b/app/views/snippets/current_user_index.html.haml
@@ -1,5 +1,5 @@
%h3.page-title
- My Snippets
+ Your Snippets
.pull-right
= link_to new_snippet_path, class: "btn btn-new btn-grouped", title: "New Snippet" do
Add new snippet
diff --git a/app/views/snippets/index.html.haml b/app/views/snippets/index.html.haml
index 0d71c41e2e7..5cd8ae26cf9 100644
--- a/app/views/snippets/index.html.haml
+++ b/app/views/snippets/index.html.haml
@@ -2,12 +2,12 @@
Public snippets
.pull-right
-
+
- if current_user
= link_to new_snippet_path, class: "btn btn-new btn-grouped", title: "New Snippet" do
Add new snippet
= link_to user_snippets_path(current_user), class: "btn btn-grouped" do
- My snippets
+ Your snippets
%p.light
Public snippets created by you and other users are listed here
diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml
index edfa2092df9..55a990c94ed 100644
--- a/app/views/snippets/show.html.haml
+++ b/app/views/snippets/show.html.haml
@@ -23,7 +23,7 @@
.back-link
- if @snippet.author == current_user
= link_to user_snippets_path(current_user) do
- &larr; my snippets
+ &larr; your snippets
- else
= link_to snippets_path do
&larr; discover snippets
diff --git a/app/views/users/_projects.html.haml b/app/views/users/_projects.html.haml
index 6c7779be30e..b7383d5594e 100644
--- a/app/views/users/_projects.html.haml
+++ b/app/views/users/_projects.html.haml
@@ -1,5 +1,5 @@
- if @contributed_projects.present?
- .panel.panel-default
+ .panel.panel-default.contributed-projects
.panel-heading Projects contributed to
= render 'shared/projects_list',
projects: @contributed_projects.sort_by(&:star_count).reverse,
diff --git a/app/views/users/calendar.html.haml b/app/views/users/calendar.html.haml
index d113ceeb753..488f49267c7 100644
--- a/app/views/users/calendar.html.haml
+++ b/app/views/users/calendar.html.haml
@@ -1,4 +1,7 @@
-%h4 Commits calendar
+%h4
+ Contributions calendar
+ .pull-right
+ %small Issues, merge requests and push events
#cal-heatmap.calendar
:javascript
new calendar(
diff --git a/app/views/users/calendar_activities.html.haml b/app/views/users/calendar_activities.html.haml
index 7c0cecfadb5..027a93a75fc 100644
--- a/app/views/users/calendar_activities.html.haml
+++ b/app/views/users/calendar_activities.html.haml
@@ -1,33 +1,23 @@
-.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
+%h4.prepend-top-20
+ %span.light Contributions for
+ %strong #{@calendar_date.to_s(:short)}
+
+%ul.bordered-list
+ - @events.sort_by(&:created_at).each do |event|
+ %li
+ %span.light
+ %i.fa.fa-clock-o
+ = event.created_at.to_s(:time)
+ - if event.push?
+ #{event.action_name} #{event.ref_type} #{event.ref_name}
+ - else
+ = event_action_name(event)
+ - if event.target
+ %strong= link_to "##{event.target_iid}", [event.project.namespace.becomes(Namespace), event.project, event.target]
+
+ at
%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
+ - if event.project
+ = link_to_project event.project
+ - else
+ = event.project_name
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index fd96020d129..0653fb871ae 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -40,7 +40,8 @@
%strong
%i.fa.fa-rss
- = render @events
+ .content_list
+ = spinner
%aside.col-md-4
= render 'profile', user: @user
= render 'projects'
diff --git a/app/workers/emails_on_push_worker.rb b/app/workers/emails_on_push_worker.rb
index e59ca81defe..89fa2117dd2 100644
--- a/app/workers/emails_on_push_worker.rb
+++ b/app/workers/emails_on_push_worker.rb
@@ -1,40 +1,49 @@
class EmailsOnPushWorker
include Sidekiq::Worker
- def perform(project_id, recipients, push_data, send_from_committer_email = false, disable_diffs = false)
+ def perform(project_id, recipients, push_data, send_from_committer_email: false, disable_diffs: false)
project = Project.find(project_id)
before_sha = push_data["before"]
after_sha = push_data["after"]
- branch = push_data["ref"]
+ ref = push_data["ref"]
author_id = push_data["user_id"]
- if Gitlab::Git.blank_ref?(before_sha) || Gitlab::Git.blank_ref?(after_sha)
- # skip if new branch was pushed or branch was removed
- return true
- end
+ action =
+ if Gitlab::Git.blank_ref?(before_sha)
+ :create
+ elsif Gitlab::Git.blank_ref?(after_sha)
+ :delete
+ else
+ :push
+ end
- compare = Gitlab::Git::Compare.new(project.repository.raw_repository, before_sha, after_sha)
+ compare = nil
+ reverse_compare = false
+ if action == :push
+ compare = Gitlab::Git::Compare.new(project.repository.raw_repository, before_sha, after_sha)
- return false if compare.same
+ return false if compare.same
- if compare.commits.empty?
- compare = Gitlab::Git::Compare.new(project.repository.raw_repository, after_sha, before_sha)
+ if compare.commits.empty?
+ compare = Gitlab::Git::Compare.new(project.repository.raw_repository, after_sha, before_sha)
- reverse_compare = true
+ reverse_compare = true
- return false if compare.commits.empty?
+ return false if compare.commits.empty?
+ end
end
recipients.split(" ").each do |recipient|
Notify.repository_push_email(
project_id,
recipient,
- author_id,
- branch,
- compare,
- reverse_compare,
- send_from_committer_email,
- disable_diffs
+ author_id: author_id,
+ ref: ref,
+ action: action,
+ compare: compare,
+ reverse_compare: reverse_compare,
+ send_from_committer_email: send_from_committer_email,
+ disable_diffs: disable_diffs
).deliver
end
ensure
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index a85db10e019..c4a0fefb7ab 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -285,6 +285,9 @@ production: &base
rack_attack:
git_basic_auth:
+ # Rack Attack IP banning enabled
+ # enabled: true
+ #
# Whitelist requests from 127.0.0.1 for web proxies (NGINX/Apache) with incorrect headers
# ip_whitelist: ["127.0.0.1"]
#
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 70af7a829c4..15c1ae9466f 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -183,6 +183,7 @@ Settings['extra'] ||= Settingslogic.new({})
#
Settings['rack_attack'] ||= Settingslogic.new({})
Settings.rack_attack['git_basic_auth'] ||= Settingslogic.new({})
+Settings.rack_attack.git_basic_auth['enabled'] = true if Settings.rack_attack.git_basic_auth['enabled'].nil?
Settings.rack_attack.git_basic_auth['ip_whitelist'] ||= %w{127.0.0.1}
Settings.rack_attack.git_basic_auth['maxretry'] ||= 10
Settings.rack_attack.git_basic_auth['findtime'] ||= 1.minute
diff --git a/db/migrate/20150324155957_set_incorrect_assignee_id_to_null.rb b/db/migrate/20150324155957_set_incorrect_assignee_id_to_null.rb
new file mode 100644
index 00000000000..42dc8173e46
--- /dev/null
+++ b/db/migrate/20150324155957_set_incorrect_assignee_id_to_null.rb
@@ -0,0 +1,6 @@
+class SetIncorrectAssigneeIdToNull < ActiveRecord::Migration
+ def up
+ execute "UPDATE issues SET assignee_id = NULL WHERE assignee_id = -1"
+ execute "UPDATE merge_requests SET assignee_id = NULL WHERE assignee_id = -1"
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index e1a5b70532a..4a445ae5832 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20150320234437) do
+ActiveRecord::Schema.define(version: 20150324155957) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 4eb280f9554..f34cbc38a54 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -11,7 +11,7 @@ RUN apt-get update -q \
# If the Omnibus package version below is outdated please contribute a merge request to update it.
# If you run GitLab Enterprise Edition point it to a location where you have downloaded it.
RUN TMP_FILE=$(mktemp); \
- wget -q -O $TMP_FILE https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab_7.8.3-omnibus-1_amd64.deb \
+ wget -q -O $TMP_FILE https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab_7.9.0-omnibus.2-1_amd64.deb \
&& dpkg -i $TMP_FILE \
&& rm -f $TMP_FILE
diff --git a/features/admin/settings.feature b/features/admin/settings.feature
index 8fdf0575c2c..52e47307b23 100644
--- a/features/admin/settings.feature
+++ b/features/admin/settings.feature
@@ -7,3 +7,10 @@ Feature: Admin Settings
Scenario: Change application settings
When I modify settings and save form
Then I should see application settings saved
+
+ Scenario: Change Slack Service Template settings
+ When I click on "Service Templates"
+ And I click on "Slack" service
+ Then I check all events and submit form
+ And I should see service template settings saved
+ And I should see all checkboxes checked
diff --git a/features/steps/admin/settings.rb b/features/steps/admin/settings.rb
index c2d0d2a3fa3..87d4e969ff5 100644
--- a/features/steps/admin/settings.rb
+++ b/features/steps/admin/settings.rb
@@ -15,4 +15,33 @@ class Spinach::Features::AdminSettings < Spinach::FeatureSteps
current_application_settings.home_page_url.should == 'https://about.gitlab.com/'
page.should have_content 'Application settings saved successfully'
end
+
+ step 'I click on "Service Templates"' do
+ click_link 'Service Templates'
+ end
+
+ step 'I click on "Slack" service' do
+ click_link 'Slack'
+ end
+
+ step 'I check all events and submit form' do
+ page.check('Active')
+ page.check('Push events')
+ page.check('Tag push events')
+ page.check('Comments')
+ page.check('Issues events')
+ page.check('Merge Request events')
+ fill_in 'Webhook', with: "http://localhost"
+ click_on 'Save'
+ end
+
+ step 'I should see service template settings saved' do
+ page.should have_content 'Application settings saved successfully'
+ end
+
+ step 'I should see all checkboxes checked' do
+ all('input[type=checkbox]').each do |checkbox|
+ checkbox.should be_checked
+ end
+ end
end
diff --git a/features/steps/user.rb b/features/steps/user.rb
index d6f05ecb2c7..10cae692a88 100644
--- a/features/steps/user.rb
+++ b/features/steps/user.rb
@@ -7,4 +7,37 @@ class Spinach::Features::User < Spinach::FeatureSteps
step 'I should see user "John Doe" page' do
expect(title).to match(/^\s*John Doe/)
end
+
+ step '"John Doe" has contributions' do
+ user = User.find_by(name: 'John Doe')
+ project = contributed_project
+
+ # Issue controbution
+ issue_params = { title: 'Bug in old browser' }
+ Issues::CreateService.new(project, user, issue_params).execute
+
+ # Push code contribution
+ push_params = {
+ project: project,
+ action: Event::PUSHED,
+ author_id: user.id,
+ data: { commit_count: 3 }
+ }
+
+ Event.create(push_params)
+ end
+
+ step 'I should see contributed projects' do
+ within '.contributed-projects' do
+ page.should have_content(@contributed_project.name)
+ end
+ end
+
+ step 'I should see contributions calendar' do
+ page.should have_css('.cal-heatmap-container')
+ end
+
+ def contributed_project
+ @contributed_project ||= create(:project, :public)
+ end
end
diff --git a/features/user.feature b/features/user.feature
index a2167935fd2..69618e929c4 100644
--- a/features/user.feature
+++ b/features/user.feature
@@ -67,3 +67,12 @@ Feature: User
And I should see project "Enterprise"
And I should not see project "Internal"
And I should not see project "Community"
+
+ @javascript
+ Scenario: "John Doe" contribution profile
+ Given I sign in as a user
+ And "John Doe" has contributions
+ When I visit user "John Doe" page
+ Then I should see user "John Doe" page
+ And I should see contributed projects
+ And I should see contributions calendar
diff --git a/lib/api/branches.rb b/lib/api/branches.rb
index b52d786e020..edfdf842f85 100644
--- a/lib/api/branches.rb
+++ b/lib/api/branches.rb
@@ -1,4 +1,5 @@
require 'mime/types'
+require 'uri'
module API
# Projects API
@@ -103,7 +104,7 @@ module API
delete ":id/repository/branches/:branch" do
authorize_push_project
result = DeleteBranchService.new(user_project, current_user).
- execute(params[:branch])
+ execute(URI.unescape(params[:branch]))
if result[:status] == :success
{
diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb
index ee877e099b1..ffe4565ef1e 100644
--- a/lib/gitlab/backend/grack_auth.rb
+++ b/lib/gitlab/backend/grack_auth.rb
@@ -1,3 +1,4 @@
+require_relative 'rack_attack_helpers'
require_relative 'shell_env'
module Grack
@@ -85,25 +86,41 @@ module Grack
user = oauth_access_token_check(login, password)
end
- return user if user.present?
-
- # At this point, we know the credentials were wrong. We let Rack::Attack
- # know there was a failed authentication attempt from this IP. This
- # information is stored in the Rails cache (Redis) and will be used by
- # the Rack::Attack middleware to decide whether to block requests from
- # this IP.
+ # If the user authenticated successfully, we reset the auth failure count
+ # from Rack::Attack for that IP. A client may attempt to authenticate
+ # with a username and blank password first, and only after it receives
+ # a 401 error does it present a password. Resetting the count prevents
+ # false positives from occurring.
+ #
+ # Otherwise, we let Rack::Attack know there was a failed authentication
+ # attempt from this IP. This information is stored in the Rails cache
+ # (Redis) and will be used by the Rack::Attack middleware to decide
+ # whether to block requests from this IP.
config = Gitlab.config.rack_attack.git_basic_auth
- Rack::Attack::Allow2Ban.filter(@request.ip, config) do
- # Unless the IP is whitelisted, return true so that Allow2Ban
- # increments the counter (stored in Rails.cache) for the IP
- if config.ip_whitelist.include?(@request.ip)
- false
+
+ if config.enabled
+ if user
+ # A successful login will reset the auth failure count from this IP
+ Rack::Attack::Allow2Ban.reset(@request.ip, config)
else
- true
+ banned = Rack::Attack::Allow2Ban.filter(@request.ip, config) do
+ # Unless the IP is whitelisted, return true so that Allow2Ban
+ # increments the counter (stored in Rails.cache) for the IP
+ if config.ip_whitelist.include?(@request.ip)
+ false
+ else
+ true
+ end
+ end
+
+ if banned
+ Rails.logger.info "IP #{@request.ip} failed to login " \
+ "as #{login} but has been temporarily banned from Git auth"
+ end
end
end
- nil # No user was found
+ user
end
def authorized_request?
diff --git a/lib/gitlab/backend/rack_attack_helpers.rb b/lib/gitlab/backend/rack_attack_helpers.rb
new file mode 100644
index 00000000000..8538f3f6eca
--- /dev/null
+++ b/lib/gitlab/backend/rack_attack_helpers.rb
@@ -0,0 +1,31 @@
+# rack-attack v4.2.0 doesn't yet support clearing of keys.
+# Taken from https://github.com/kickstarter/rack-attack/issues/113
+class Rack::Attack::Allow2Ban
+ def self.reset(discriminator, options)
+ findtime = options[:findtime] or raise ArgumentError, "Must pass findtime option"
+
+ cache.reset_count("#{key_prefix}:count:#{discriminator}", findtime)
+ cache.delete("#{key_prefix}:ban:#{discriminator}")
+ end
+end
+
+class Rack::Attack::Cache
+ def reset_count(unprefixed_key, period)
+ epoch_time = Time.now.to_i
+ # Add 1 to expires_in to avoid timing error: http://git.io/i1PHXA
+ expires_in = period - (epoch_time % period) + 1
+ key = "#{(epoch_time / period).to_i}:#{unprefixed_key}"
+ delete(key)
+ end
+
+ def delete(unprefixed_key)
+ store.delete("#{prefix}:#{unprefixed_key}")
+ end
+end
+
+class Rack::Attack::StoreProxy::RedisStoreProxy
+ def delete(key, options={})
+ self.del(key)
+ rescue Redis::BaseError
+ end
+end
diff --git a/lib/gitlab/commits_calendar.rb b/lib/gitlab/commits_calendar.rb
deleted file mode 100644
index 8963d346b6f..00000000000
--- a/lib/gitlab/commits_calendar.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-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
diff --git a/lib/gitlab/contributions_calendar.rb b/lib/gitlab/contributions_calendar.rb
new file mode 100644
index 00000000000..3fd0823df06
--- /dev/null
+++ b/lib/gitlab/contributions_calendar.rb
@@ -0,0 +1,56 @@
+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.reorder(nil).contributions.where(author_id: user.id).
+ where("created_at > ?", date_from).where(project_id: projects).
+ group('date(created_at)').
+ select('date(created_at), count(id) as total_amount').
+ map(&:attributes)
+
+ 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
+ day_events = events.find { |day_events| day_events["date"] == date }
+
+ if day_events
+ @timestamps[date_id] = day_events["total_amount"]
+ end
+ end
+
+ @timestamps
+ end
+
+ def events_by_date(date)
+ events = Event.contributions.where(author_id: user.id).
+ 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
+ end
+end
diff --git a/lib/gitlab/ldap/person.rb b/lib/gitlab/ldap/person.rb
index 3c426179375..b81f3e8e8f5 100644
--- a/lib/gitlab/ldap/person.rb
+++ b/lib/gitlab/ldap/person.rb
@@ -14,7 +14,6 @@ module Gitlab
end
def self.find_by_dn(dn, adapter)
- dn = Net::LDAP::Filter.escape(dn)
adapter.user('dn', dn)
end
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index 11da4be4022..41bb8d08924 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -368,11 +368,12 @@ module Gitlab
# ActiveSupport::SafeBuffer, hence the `String.new`
String.new(text).gsub(Taskable::TASK_PATTERN_HTML) do
checked = $LAST_MATCH_INFO[:checked].downcase == 'x'
+ p_tag = $LAST_MATCH_INFO[:p_tag]
if checked
- "#{li_tag}#{checked_box}"
+ "#{li_tag}#{p_tag}#{checked_box}"
else
- "#{li_tag}#{unchecked_box}"
+ "#{li_tag}#{p_tag}#{unchecked_box}"
end
end
end
diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb
index 8b85f3da83f..0dab7bcfa4d 100644
--- a/lib/gitlab/project_search_results.rb
+++ b/lib/gitlab/project_search_results.rb
@@ -67,7 +67,7 @@ module Gitlab
end
def notes
- Note.where(project_id: limit_project_ids).search(query).order('updated_at DESC')
+ Note.where(project_id: limit_project_ids).user.search(query).order('updated_at DESC')
end
def limit_project_ids
diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb
index 7962bcdde71..d47a37914df 100644
--- a/spec/controllers/users_controller_spec.rb
+++ b/spec/controllers/users_controller_spec.rb
@@ -25,34 +25,21 @@ describe UsersController do
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' }
+ let!(:project) { create(:project) }
+ let!(:user) { create(:user) }
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'
+ get :calendar_activities, username: 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
+ get :calendar_activities, username: user.username
expect(response).to render_template('calendar_activities')
end
end
diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb
index 3a884d39bf1..c631acc591d 100644
--- a/spec/helpers/gitlab_markdown_helper_spec.rb
+++ b/spec/helpers/gitlab_markdown_helper_spec.rb
@@ -847,6 +847,17 @@ EOT
)
end
+ it 'should render checkboxes for nested tasks' do
+ rendered_text = markdown(@source_text_asterisk, parse_tasks: true)
+
+ expect(rendered_text).to match(
+ /<input.*checkbox.*valid unchecked nested task/
+ )
+ expect(rendered_text).to match(
+ /<input.*checkbox.*valid checked nested task/
+ )
+ end
+
it 'should not be confused by whitespace before bullets' do
rendered_text_asterisk = markdown(@source_text_asterisk,
parse_tasks: true)
diff --git a/spec/lib/gitlab/backend/grack_auth_spec.rb b/spec/lib/gitlab/backend/grack_auth_spec.rb
index 768312f0028..d0aad54f677 100644
--- a/spec/lib/gitlab/backend/grack_auth_spec.rb
+++ b/spec/lib/gitlab/backend/grack_auth_spec.rb
@@ -6,7 +6,7 @@ describe Grack::Auth do
let(:app) { lambda { |env| [200, {}, "Success!"] } }
let!(:auth) { Grack::Auth.new(app) }
- let(:env) {
+ let(:env) {
{
"rack.input" => "",
"REQUEST_METHOD" => "GET",
@@ -85,6 +85,17 @@ describe Grack::Auth do
it "responds with status 401" do
expect(status).to eq(401)
end
+
+ context "when the user is IP banned" do
+ before do
+ expect(Rack::Attack::Allow2Ban).to receive(:filter).and_return(true)
+ allow_any_instance_of(Rack::Request).to receive(:ip).and_return('1.2.3.4')
+ end
+
+ it "responds with status 401" do
+ expect(status).to eq(401)
+ end
+ end
end
context "when authentication succeeds" do
@@ -109,10 +120,49 @@ describe Grack::Auth do
end
context "when the user isn't blocked" do
+ before do
+ expect(Rack::Attack::Allow2Ban).to receive(:reset)
+ end
+
it "responds with status 200" do
expect(status).to eq(200)
end
end
+
+ context "when blank password attempts follow a valid login" do
+ let(:options) { Gitlab.config.rack_attack.git_basic_auth }
+ let(:maxretry) { options[:maxretry] - 1 }
+ let(:ip) { '1.2.3.4' }
+
+ before do
+ allow_any_instance_of(Rack::Request).to receive(:ip).and_return(ip)
+ Rack::Attack::Allow2Ban.reset(ip, options)
+ end
+
+ after do
+ Rack::Attack::Allow2Ban.reset(ip, options)
+ end
+
+ def attempt_login(include_password)
+ password = include_password ? user.password : ""
+ env["HTTP_AUTHORIZATION"] = ActionController::HttpAuthentication::Basic.encode_credentials(user.username, password)
+ Grack::Auth.new(app)
+ auth.call(env).first
+ end
+
+ it "repeated attempts followed by successful attempt" do
+ for n in 0..maxretry do
+ expect(attempt_login(false)).to eq(401)
+ end
+
+ expect(attempt_login(true)).to eq(200)
+ expect(Rack::Attack::Allow2Ban.send(:banned?, ip)).to eq(nil)
+
+ for n in 0..maxretry do
+ expect(attempt_login(false)).to eq(401)
+ end
+ end
+ end
end
context "when the user doesn't have access to the project" do
diff --git a/spec/lib/gitlab/backend/rack_attack_helpers_spec.rb b/spec/lib/gitlab/backend/rack_attack_helpers_spec.rb
new file mode 100644
index 00000000000..2ac496fd669
--- /dev/null
+++ b/spec/lib/gitlab/backend/rack_attack_helpers_spec.rb
@@ -0,0 +1,35 @@
+require "spec_helper"
+
+describe 'RackAttackHelpers' do
+ describe 'reset' do
+ let(:discriminator) { 'test-key'}
+ let(:maxretry) { 5 }
+ let(:period) { 1.minute }
+ let(:options) { { findtime: period, bantime: 60, maxretry: maxretry } }
+
+ def do_filter
+ for i in 1..maxretry - 1 do
+ status = Rack::Attack::Allow2Ban.filter(discriminator, options) { true }
+ expect(status).to eq(false)
+ end
+ end
+
+ def do_reset
+ Rack::Attack::Allow2Ban.reset(discriminator, options)
+ end
+
+ before do
+ do_reset
+ end
+
+ after do
+ do_reset
+ end
+
+ it 'user is not banned after n - 1 retries' do
+ do_filter
+ do_reset
+ do_filter
+ end
+ end
+end
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index e3a3b542358..ba42f9e5c70 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -640,6 +640,100 @@ describe Notify do
end
end
+ describe 'email on push for a created branch' do
+ let(:example_site_path) { root_path }
+ let(:user) { create(:user) }
+ let(:tree_path) { namespace_project_tree_path(project.namespace, project, "master") }
+
+ subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/heads/master', action: :create) }
+
+ it 'is sent as the author' do
+ sender = subject.header[:from].addrs[0]
+ expect(sender.display_name).to eq(user.name)
+ expect(sender.address).to eq(gitlab_sender)
+ end
+
+ it 'is sent to recipient' do
+ is_expected.to deliver_to 'devs@company.name'
+ end
+
+ it 'has the correct subject' do
+ is_expected.to have_subject /Pushed new branch master/
+ end
+
+ it 'contains a link to the branch' do
+ is_expected.to have_body_text /#{tree_path}/
+ end
+ end
+
+ describe 'email on push for a created tag' do
+ let(:example_site_path) { root_path }
+ let(:user) { create(:user) }
+ let(:tree_path) { namespace_project_tree_path(project.namespace, project, "v1.0") }
+
+ subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/tags/v1.0', action: :create) }
+
+ it 'is sent as the author' do
+ sender = subject.header[:from].addrs[0]
+ expect(sender.display_name).to eq(user.name)
+ expect(sender.address).to eq(gitlab_sender)
+ end
+
+ it 'is sent to recipient' do
+ is_expected.to deliver_to 'devs@company.name'
+ end
+
+ it 'has the correct subject' do
+ is_expected.to have_subject /Pushed new tag v1\.0/
+ end
+
+ it 'contains a link to the tag' do
+ is_expected.to have_body_text /#{tree_path}/
+ end
+ end
+
+ describe 'email on push for a deleted branch' do
+ let(:example_site_path) { root_path }
+ let(:user) { create(:user) }
+
+ subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/heads/master', action: :delete) }
+
+ it 'is sent as the author' do
+ sender = subject.header[:from].addrs[0]
+ expect(sender.display_name).to eq(user.name)
+ expect(sender.address).to eq(gitlab_sender)
+ end
+
+ it 'is sent to recipient' do
+ is_expected.to deliver_to 'devs@company.name'
+ end
+
+ it 'has the correct subject' do
+ is_expected.to have_subject /Deleted branch master/
+ end
+ end
+
+ describe 'email on push for a deleted tag' do
+ let(:example_site_path) { root_path }
+ let(:user) { create(:user) }
+
+ subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/tags/v1.0', action: :delete) }
+
+ it 'is sent as the author' do
+ sender = subject.header[:from].addrs[0]
+ expect(sender.display_name).to eq(user.name)
+ expect(sender.address).to eq(gitlab_sender)
+ end
+
+ it 'is sent to recipient' do
+ is_expected.to deliver_to 'devs@company.name'
+ end
+
+ it 'has the correct subject' do
+ is_expected.to have_subject /Deleted tag v1\.0/
+ end
+ end
+
describe 'email on push with multiple commits' do
let(:example_site_path) { root_path }
let(:user) { create(:user) }
@@ -648,7 +742,7 @@ describe Notify do
let(:diff_path) { namespace_project_compare_path(project.namespace, project, from: Commit.new(compare.base), to: Commit.new(compare.head)) }
let(:send_from_committer_email) { false }
- subject { Notify.repository_push_email(project.id, 'devs@company.name', user.id, 'master', compare, false, send_from_committer_email) }
+ subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/heads/master', action: :push, compare: compare, reverse_compare: false, send_from_committer_email: send_from_committer_email) }
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
@@ -736,7 +830,7 @@ describe Notify do
let(:commits) { Commit.decorate(compare.commits) }
let(:diff_path) { namespace_project_commit_path(project.namespace, project, commits.first) }
- subject { Notify.repository_push_email(project.id, 'devs@company.name', user.id, 'master', compare) }
+ subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/heads/master', action: :push, compare: compare) }
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 0e3e0b167d7..f41e5a97ca3 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -13,47 +13,16 @@ describe Repository do
it { is_expected.not_to include('fix') }
end
- describe :last_commit_for_path do
- subject { repository.last_commit_for_path(sample_commit.id, '.gitignore').id }
-
- it { is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') }
- end
-
- context :timestamps_by_user_log do
- before do
- Date.stub(:today).and_return(Date.new(2015, 03, 01))
- end
-
- describe 'single e-mail for user' do
- let(:user) { create(:user, email: sample_commit.author_email) }
-
- subject { repository.timestamps_by_user_log(user) }
+ describe :tag_names_contains do
+ subject { repository.tag_names_contains(sample_commit.id) }
- it { is_expected.to eq(['2014-08-06', '2014-07-31', '2014-07-31']) }
- end
-
- describe 'multiple emails for user' do
- let(:email_alias) { create(:email, email: another_sample_commit.author_email) }
- let(:user) { create(:user, email: sample_commit.author_email, emails: [email_alias]) }
-
- subject { repository.timestamps_by_user_log(user) }
-
- it { is_expected.to eq(['2015-01-10', '2014-08-06', '2014-07-31', '2014-07-31']) }
- end
+ it { is_expected.to include('v1.1.0') }
+ it { is_expected.not_to include('v1.0.0') }
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)) }
+ describe :last_commit_for_path do
+ subject { repository.last_commit_for_path(sample_commit.id, '.gitignore').id }
- it 'contains the exepected commits' do
- expect(subject.flatten.map(&:id)).to eq([commit1, commit2])
- end
- end
+ it { is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') }
end
end