Merge branch 'master' into update_api_messages

Conflicts:
	CHANGELOG
This commit is contained in:
Marin Jankovski 2015-01-07 12:30:08 +01:00
commit 1fbeaa0684
52 changed files with 529 additions and 393 deletions

View file

@ -1 +1 @@
2.1.5
2.2.0

View file

@ -5,21 +5,23 @@ v 7.7.0
-
-
- Mention notification level
-
-
- Markdown preview in wiki (Yuriy Glukhov)
- Raise group avatar filesize limit to 200kb
- OAuth applications feature
-
-
- Show user SSH keys in admin area
- Developer can push to protected branches option
- Set project path instead of project name in create form
-
-
- New side navigation
- Updates to the messages returned by API (sponsored by O'Reilly Media)
- New UI layout with side navigation
-
-
-
- Add alert message in case of outdated browser (IE < 10)
-
- Added API support for sorting projects
- Update gitlab_git to version 7.0.0.rc13
v 7.6.0
- Fork repository to groups
@ -45,8 +47,15 @@ v 7.6.0
- Possibility to create Milestones or Labels when Issues are disabled
- Fix bug with showing gpg signature in tag
v 7.5.3
- Bump gitlab_git to 7.0.0.rc12 (includes Rugged 0.21.2)
v 7.5.2
- Don't log Sidekiq arguments by default
- Fix restore of wiki repositories from backups
v 7.5.1
- Add missing timestamps to 'members' table
v 7.5.0
- API: Add support for Hipchat (Kevin Houdebert)

View file

@ -37,7 +37,7 @@ gem "browser"
# Extracting information from a git repository
# Provide access to Gitlab::Git library
gem "gitlab_git", '7.0.0.rc12'
gem "gitlab_git", '7.0.0.rc13'
# Ruby/Rack Git Smart-HTTP Server Handler
gem 'gitlab-grack', '~> 2.0.0.pre', require: 'grack'
@ -95,7 +95,7 @@ gem "github-markup"
gem 'redcarpet', '~> 3.1.2'
gem 'RedCloth'
gem 'rdoc', '~>3.6'
gem 'org-ruby', '= 0.9.9'
gem 'org-ruby', '= 0.9.12'
gem 'creole', '~>0.3.6'
gem 'wikicloth', '=0.8.1'
gem 'asciidoctor', '= 0.1.4'

View file

@ -124,7 +124,7 @@ GEM
equalizer (0.0.8)
erubis (2.7.0)
escape_utils (0.2.4)
eventmachine (1.0.3)
eventmachine (1.0.4)
excon (0.32.1)
execjs (2.0.2)
expression_parser (0.9.0)
@ -183,7 +183,7 @@ GEM
mime-types (~> 1.19)
gitlab_emoji (0.0.1.1)
emoji (~> 1.0.1)
gitlab_git (7.0.0.rc12)
gitlab_git (7.0.0.rc13)
activesupport (~> 4.0)
charlock_holmes (~> 0.6)
gitlab-linguist (~> 3.0)
@ -280,7 +280,7 @@ GEM
kaminari (0.15.1)
actionpack (>= 3.0.0)
activesupport (>= 3.0.0)
kgio (2.8.1)
kgio (2.9.2)
launchy (2.4.2)
addressable (~> 2.3)
letter_opener (1.1.2)
@ -343,7 +343,7 @@ GEM
omniauth-twitter (1.0.1)
multi_json (~> 1.3)
omniauth-oauth (~> 1.0)
org-ruby (0.9.9)
org-ruby (0.9.12)
rubypants (~> 0.2)
orm_adapter (0.5.0)
pg (0.15.1)
@ -409,7 +409,7 @@ GEM
activesupport (= 4.1.1)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
raindrops (0.12.0)
raindrops (0.13.0)
rake (10.3.2)
raphael-rails (2.1.2)
rb-fsevent (0.9.3)
@ -643,7 +643,7 @@ DEPENDENCIES
gitlab-grack (~> 2.0.0.pre)
gitlab-linguist (~> 3.0.0)
gitlab_emoji (~> 0.0.1.1)
gitlab_git (= 7.0.0.rc12)
gitlab_git (= 7.0.0.rc13)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (= 1.2.0)
gollum-lib (~> 3.0.0)
@ -677,7 +677,7 @@ DEPENDENCIES
omniauth-kerberos
omniauth-shibboleth
omniauth-twitter
org-ruby (= 0.9.9)
org-ruby (= 0.9.12)
pg
poltergeist (~> 1.5.1)
pry

View file

@ -292,11 +292,17 @@ table {
.dashboard-intro-icon {
float: left;
text-align: center;
font-size: 32px;
color: #AAA;
padding: 5px 0;
width: 50px;
min-height: 100px;
width: 60px;
}
.dashboard-intro-text {
display: inline-block;
margin-left: -60px;
padding-left: 60px;
width: 100%;
}
.broadcast-message {

View file

@ -31,7 +31,12 @@ fieldset legend {
margin-bottom: 18px;
background-color: whitesmoke;
border-top: 1px solid #e5e5e5;
padding-left: 17%;
}
@media (min-width: $screen-sm-min) {
.form-actions {
padding-left: 17%;
}
}
label {
@ -88,7 +93,8 @@ label {
@include box-shadow(none);
}
.issuable-description {
.issuable-description,
.wiki-content {
margin-top: 35px;
}

View file

@ -65,6 +65,7 @@
.edit_note,
.issuable-description,
.milestone-description,
.wiki-content,
.merge-request-form {
.nav-tabs {
margin-bottom: 0;

View file

@ -145,8 +145,12 @@
* Last push widget
*/
.event-last-push {
overflow: auto;
.event-last-push-text {
@include str-truncated(75%);
@include str-truncated(100%);
float:left;
margin-right: -150px;
padding-right: 150px;
line-height: 24px;
}
}

View file

@ -11,10 +11,27 @@
}
}
.accept-group {
label {
margin: 5px;
.accept-merge-holder {
margin-top: 5px;
.accept-action {
display: inline-block;
.accept_merge_request {
padding: 10px 20px;
}
}
.accept-control {
display: inline-block;
margin-left: 20px;
padding: 10px 0;
line-height: 20px;
font-weight: bold;
.checkbox {
margin: 0;
}
}
}
}
@ -170,7 +187,3 @@
.merge-request-show-labels .label {
padding: 6px 10px;
}
.mr-commits .commit {
padding: 10px 15px;
}

View file

@ -11,7 +11,7 @@ class Projects::MilestonesController < Projects::ApplicationController
respond_to :html
def index
@milestones = case params[:f]
@milestones = case params[:state]
when 'all'; @project.milestones.order("state, due_date DESC")
when 'closed'; @project.milestones.closed.order("due_date DESC")
else @project.milestones.active.order("due_date ASC")

View file

@ -4,6 +4,8 @@ module DashboardHelper
sort: params[:sort],
scope: params[:scope],
group: params[:group],
tag: params[:tag],
visibility_level: params[:visibility_level],
}
options = exist_opts.merge(options)

View file

@ -33,18 +33,6 @@ module GroupsHelper
title
end
def group_filter_path(entity, options={})
exist_opts = {
status: params[:status]
}
options = exist_opts.merge(options)
path = request.path
path << "?#{options.to_param}"
path
end
def group_settings_page?
if current_controller?('groups')
current_action?('edit') || current_action?('projects')

View file

@ -0,0 +1,9 @@
module MilestonesHelper
def milestones_filter_path(opts = {})
if @project
project_milestones_path(@project, opts)
elsif @group
group_milestones_path(@group, opts)
end
end
end

View file

@ -174,7 +174,7 @@ class Event < ActiveRecord::Base
def valid_push?
data[:ref] && ref_name.present?
rescue => ex
rescue
false
end

View file

@ -21,7 +21,7 @@ class Group < Namespace
has_many :users, through: :group_members
validate :avatar_type, if: ->(user) { user.avatar_changed? }
validates :avatar, file_size: { maximum: 100.kilobytes.to_i }
validates :avatar, file_size: { maximum: 200.kilobytes.to_i }
mount_uploader :avatar, AttachmentUploader

View file

@ -189,7 +189,9 @@ class MergeRequest < ActiveRecord::Base
end
def automerge!(current_user, commit_message = nil)
MergeRequests::AutoMergeService.new.execute(self, current_user, commit_message)
MergeRequests::AutoMergeService.
new(target_project, current_user).
execute(self, commit_message)
end
def open?

View file

@ -35,7 +35,7 @@ class HipchatService < Service
{ type: 'text', name: 'token', placeholder: '' },
{ type: 'text', name: 'room', placeholder: '' },
{ type: 'text', name: 'server',
placeholder: 'Leave blank for default. https://chat.hipchat.com' }
placeholder: 'Leave blank for default. https://hipchat.example.com' }
]
end
@ -47,7 +47,7 @@ class HipchatService < Service
def gate
options = { api_version: 'v2' }
options[:server_url] = server unless server.nil?
options[:server_url] = server unless server.blank?
@gate ||= HipChat::Client.new(token, options)
end

View file

@ -5,15 +5,16 @@ module MergeRequests
# mark merge request as merged and execute all hooks and notifications
# Called when you do merge via GitLab UI
class AutoMergeService < BaseMergeService
def execute(merge_request, current_user, commit_message)
def execute(merge_request, commit_message)
merge_request.lock_mr
if Gitlab::Satellite::MergeAction.new(current_user, merge_request).merge!(commit_message)
merge_request.merge
notification.merge_mr(merge_request, current_user)
notification_service.merge_mr(merge_request, current_user)
create_merge_event(merge_request, current_user)
execute_project_hooks(merge_request)
create_note(merge_request)
execute_hooks(merge_request)
true
else

View file

@ -1,21 +1,10 @@
module MergeRequests
class BaseMergeService
class BaseMergeService < MergeRequests::BaseService
private
def notification
NotificationService.new
end
def create_merge_event(merge_request, current_user)
EventCreateService.new.merge_mr(merge_request, current_user)
end
def execute_project_hooks(merge_request)
if merge_request.project
hook_data = merge_request.to_hook_data(current_user)
merge_request.project.execute_hooks(hook_data, :merge_request_hooks)
end
end
end
end

View file

@ -13,7 +13,7 @@ module MergeRequests
merge_request.target_branch ||= merge_request.target_project.default_branch
unless merge_request.target_branch && merge_request.source_branch
return build_failed(merge_request, "You must select source and target branches")
return build_failed(merge_request, nil)
end
# Generate suggested MR title based on source branch name
@ -59,7 +59,7 @@ module MergeRequests
end
def build_failed(merge_request, message)
merge_request.errors.add(:base, message)
merge_request.errors.add(:base, message) unless message.nil?
merge_request.compare_commits = []
merge_request.can_be_created = false
merge_request

View file

@ -6,12 +6,13 @@ module MergeRequests
# Called when you do merge via command line and push code
# to target branch
class MergeService < BaseMergeService
def execute(merge_request, current_user, commit_message)
def execute(merge_request, commit_message)
merge_request.merge
notification.merge_mr(merge_request, current_user)
notification_service.merge_mr(merge_request, current_user)
create_merge_event(merge_request, current_user)
execute_project_hooks(merge_request)
create_note(merge_request)
execute_hooks(merge_request)
true
rescue

View file

@ -32,7 +32,9 @@ module MergeRequests
merge_requests.uniq.select(&:source_project).each do |merge_request|
MergeRequests::MergeService.new.execute(merge_request, @current_user, nil)
MergeRequests::MergeService.
new(merge_request.target_project, @current_user).
execute(merge_request, nil)
end
end

View file

@ -1,55 +1,100 @@
%fieldset
%ul.nav.nav-pills.nav-stacked
= nav_tab :scope, nil do
= link_to projects_dashboard_filter_path(scope: nil) do
All
%span.pull-right
= current_user.authorized_projects.count
= nav_tab :scope, 'personal' do
= link_to projects_dashboard_filter_path(scope: 'personal') do
Personal
%span.pull-right
= current_user.personal_projects.count
= nav_tab :scope, 'joined' do
= link_to projects_dashboard_filter_path(scope: 'joined') do
Joined
%span.pull-right
= current_user.authorized_projects.joined(current_user).count
= nav_tab :scope, 'owned' do
= link_to projects_dashboard_filter_path(scope: 'owned') do
Owned
%span.pull-right
= current_user.owned_projects.count
.dash-projects-filters.append-bottom-20
.pull-left.append-right-20
%ul.nav.nav-pills.nav-compact
= nav_tab :scope, nil do
= link_to projects_dashboard_filter_path(scope: nil) do
All
= nav_tab :scope, 'personal' do
= link_to projects_dashboard_filter_path(scope: 'personal') do
Personal
= nav_tab :scope, 'joined' do
= link_to projects_dashboard_filter_path(scope: 'joined') do
Joined
= nav_tab :scope, 'owned' do
= link_to projects_dashboard_filter_path(scope: 'owned') do
Owned
%fieldset
%legend Visibility
%ul.nav.nav-pills.nav-stacked.nav-small.visibility-filter
- Gitlab::VisibilityLevel.values.each do |level|
%li{ class: (level.to_s == params[:visibility_level]) ? 'active' : 'light' }
= link_to projects_dashboard_filter_path(visibility_level: level) do
= visibility_level_icon(level)
= visibility_level_label(level)
.dropdown.inline.append-right-10
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
%i.fa.fa-globe
%span.light Visibility:
- if params[:visibility_level].present?
= visibility_level_label(params[:visibility_level].to_i)
- else
Any
%b.caret
%ul.dropdown-menu
%li
= link_to projects_dashboard_filter_path(visibility_level: nil) do
Any
- Gitlab::VisibilityLevel.values.each do |level|
%li{ class: (level.to_s == params[:visibility_level]) ? 'active' : 'light' }
= link_to projects_dashboard_filter_path(visibility_level: level) do
= visibility_level_icon(level)
= visibility_level_label(level)
- if @groups.present?
%fieldset
%legend Groups
%ul.nav.nav-pills.nav-stacked.nav-small
- @groups.each do |group|
%li{ class: (group.name == params[:group]) ? 'active' : 'light' }
= link_to projects_dashboard_filter_path(group: group.name) do
%i.fa.fa-folder-o
= group.name
%small.pull-right
= group.projects.count
- if @groups.present?
.dropdown.inline.append-right-10
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
%i.fa.fa-group
%span.light Group:
- if params[:group].present?
= Group.find_by(name: params[:group]).name
- else
Any
%b.caret
%ul.dropdown-menu
%li
= link_to projects_dashboard_filter_path(group: nil) do
Any
- @groups.each do |group|
%li{ class: (group.name == params[:group]) ? 'active' : 'light' }
= link_to projects_dashboard_filter_path(group: group.name) do
= group.name
%small.pull-right
= group.projects.count
- if @tags.present?
%fieldset
%legend Tags
%ul.nav.nav-pills.nav-stacked.nav-small
- @tags.each do |tag|
%li{ class: (tag.name == params[:tag]) ? 'active' : 'light' }
= link_to projects_dashboard_filter_path(scope: params[:scope], tag: tag.name) do
%i.fa.fa-tag
= tag.name
- if @tags.present?
.dropdown.inline.append-right-10
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
%i.fa.fa-tags
%span.light Tags:
- if params[:tag].present?
= params[:tag]
- else
Any
%b.caret
%ul.dropdown-menu
%li
= link_to projects_dashboard_filter_path(tag: nil) do
Any
- @tags.each do |tag|
%li{ class: (tag.name == params[:tag]) ? 'active' : 'light' }
= link_to projects_dashboard_filter_path(tag: tag.name) do
%i.fa.fa-tag
= tag.name
.pull-right
.dropdown.inline
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
%span.light sort:
- if @sort.present?
= @sort.humanize
- else
Name
%b.caret
%ul.dropdown-menu
%li
= link_to projects_dashboard_filter_path(sort: nil) do
Name
= link_to projects_dashboard_filter_path(sort: 'newest') do
= sort_title_recently_created
= link_to projects_dashboard_filter_path(sort: 'oldest') do
= sort_title_oldest_created
= link_to projects_dashboard_filter_path(sort: 'recently_updated') do
= sort_title_recently_updated
= link_to projects_dashboard_filter_path(sort: 'last_updated') do
= sort_title_oldest_updated

View file

@ -4,7 +4,7 @@
%div
.dashboard-intro-icon
%i.fa.fa-bookmark-o
%div
.dashboard-intro-text
%p.slead
You don't have access to any projects right now.
%br
@ -24,7 +24,7 @@
%div
.dashboard-intro-icon
%i.fa.fa-users
%div
.dashboard-intro-text
%p.slead
You can create a group for several dependent projects.
%br
@ -38,7 +38,7 @@
%div
.dashboard-intro-icon
%i.fa.fa-globe
%div
.dashboard-intro-text
%p.slead
There are
%strong= @publicish_project_count

View file

@ -1,5 +1,5 @@
xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlnsmedia" => "http://search.yahoo.com/mrss/" do
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
xml.title "#{current_user.name} issues"
xml.link href: issues_dashboard_url(:atom, private_token: current_user.private_token), rel: "self", type: "application/atom+xml"
xml.link href: issues_dashboard_url(private_token: current_user.private_token), rel: "alternate", type: "text/html"

View file

@ -1,76 +1,54 @@
%h3.page-title
My Projects
.pull-right
.dropdown.inline
%a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
%span.light sort:
- if @sort.present?
= @sort.humanize
- else
Name
%b.caret
%ul.dropdown-menu
%li
= link_to projects_dashboard_filter_path(sort: nil) do
Name
= link_to projects_dashboard_filter_path(sort: 'newest') do
= sort_title_recently_created
= link_to projects_dashboard_filter_path(sort: 'oldest') do
= sort_title_oldest_created
= link_to projects_dashboard_filter_path(sort: 'recently_updated') do
= sort_title_recently_updated
= link_to projects_dashboard_filter_path(sort: 'last_updated') do
= sort_title_oldest_updated
%p.light
All projects you have access to are listed here. Public projects are not included here unless you are a member
%hr
.row
.col-md-3.hidden-sm.hidden-xs.side-filters
= render "projects_filter"
.col-md-9
%ul.bordered-list.my-projects.top-list
- @projects.each do |project|
%li.my-project-row
%h4.project-title
.project-access-icon
= visibility_level_icon(project.visibility_level)
= link_to project_path(project), class: dom_class(project) do
= project.name_with_namespace
.side-filters
= render "projects_filter"
.dash-projects
%ul.bordered-list.my-projects.top-list
- @projects.each do |project|
%li.my-project-row
%h4.project-title
.project-access-icon
= visibility_level_icon(project.visibility_level)
= link_to project_path(project), class: dom_class(project) do
= project.name_with_namespace
- if project.forked_from_project
&nbsp;
%small
%i.fa.fa-code-fork
Forked from:
= link_to project.forked_from_project.name_with_namespace, project_path(project.forked_from_project)
- if project.forked_from_project
&nbsp;
%small
%i.fa.fa-code-fork
Forked from:
= link_to project.forked_from_project.name_with_namespace, project_path(project.forked_from_project)
- if current_user.can_leave_project?(project)
.pull-right
= link_to leave_project_team_members_path(project), data: { confirm: "Leave project?"}, method: :delete, remote: true, class: "btn-tiny btn remove-row", title: 'Leave project' do
%i.fa.fa-sign-out
Leave
.project-info
- if current_user.can_leave_project?(project)
.pull-right
- if project.archived?
%span.label
%i.fa.fa-archive
Archived
- project.tags.each do |tag|
%span.label.label-info
%i.fa.fa-tag
= tag.name
- if project.description.present?
%p= truncate project.description, length: 100
.last-activity
%span.light Last activity:
%span.date= project_last_activity(project)
= link_to leave_project_team_members_path(project), data: { confirm: "Leave project?"}, method: :delete, remote: true, class: "btn-tiny btn remove-row", title: 'Leave project' do
%i.fa.fa-sign-out
Leave
.project-info
.pull-right
- if project.archived?
%span.label
%i.fa.fa-archive
Archived
- project.tags.each do |tag|
%span.label.label-info
%i.fa.fa-tag
= tag.name
- if project.description.present?
%p= truncate project.description, length: 100
.last-activity
%span.light Last activity:
%span.date= project_last_activity(project)
- if @projects.blank?
%li
.nothing-here-block There are no projects here.
.bottom
= paginate @projects, theme: "gitlab"
- if @projects.blank?
%li
.nothing-here-block There are no projects here.
.bottom
= paginate @projects, theme: "gitlab"

View file

@ -1,5 +1,5 @@
xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlnsmedia" => "http://search.yahoo.com/mrss/" do
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
xml.title "Dashboard feed#{" - #{current_user.name}" if current_user.name.present?}"
xml.link href: dashboard_url(:atom), rel: "self", type: "application/atom+xml"
xml.link href: dashboard_url, rel: "alternate", type: "text/html"

View file

@ -1,12 +0,0 @@
= form_tag group_filter_path(entity), method: 'get' do
%fieldset
%ul.nav.nav-pills.nav-stacked
%li{class: ("active" if (params[:status] == 'active' || !params[:status]))}
= link_to group_filter_path(entity, status: 'active') do
Active
%li{class: ("active" if params[:status] == 'closed')}
= link_to group_filter_path(entity, status: 'closed') do
Closed
%li{class: ("active" if params[:status] == 'all')}
= link_to group_filter_path(entity, status: 'all') do
All

View file

@ -9,42 +9,38 @@
%hr
.row
.fixed.sidebar-expand-button.hidden-lg.hidden-md
%i.fa.fa-list.fa-2x
.col-md-3.responsive-side
= render 'groups/filter', entity: 'milestone'
.col-md-9
.panel.panel-default
%ul.well-list
- if @group_milestones.blank?
%li
.nothing-here-block No milestones to show
- else
- @group_milestones.each do |milestone|
%li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone.milestones.first) }
.pull-right
- if can?(current_user, :manage_group, @group)
- if milestone.closed?
= link_to 'Reopen Milestone', group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-small btn-grouped btn-reopen"
- else
= link_to 'Close Milestone', group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-small btn-close"
%h4
= link_to_gfm truncate(milestone.title, length: 100), group_milestone_path(@group, milestone.safe_title, title: milestone.title)
= render 'shared/milestones_filter'
.milestones
.panel.panel-default
%ul.well-list
- if @group_milestones.blank?
%li
.nothing-here-block No milestones to show
- else
- @group_milestones.each do |milestone|
%li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone.milestones.first) }
.pull-right
- if can?(current_user, :manage_group, @group)
- if milestone.closed?
= link_to 'Reopen Milestone', group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-small btn-grouped btn-reopen"
- else
= link_to 'Close Milestone', group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-small btn-close"
%h4
= link_to_gfm truncate(milestone.title, length: 100), group_milestone_path(@group, milestone.safe_title, title: milestone.title)
%div
%div
%div
= link_to group_milestone_path(@group, milestone.safe_title, title: milestone.title) do
= pluralize milestone.issue_count, 'Issue'
&nbsp;
= link_to group_milestone_path(@group, milestone.safe_title, title: milestone.title) do
= pluralize milestone.merge_requests_count, 'Merge Request'
&nbsp;
%span.light #{milestone.percent_complete}% complete
.progress.progress-info
.progress-bar{style: "width: #{milestone.percent_complete}%;"}
%div
%br
- milestone.projects.each do |project|
%span.label.label-default
= project.name
= paginate @group_milestones, theme: "gitlab"
= link_to group_milestone_path(@group, milestone.safe_title, title: milestone.title) do
= pluralize milestone.issue_count, 'Issue'
&nbsp;
= link_to group_milestone_path(@group, milestone.safe_title, title: milestone.title) do
= pluralize milestone.merge_requests_count, 'Merge Request'
&nbsp;
%span.light #{milestone.percent_complete}% complete
.progress.progress-info
.progress-bar{style: "width: #{milestone.percent_complete}%;"}
%div
%br
- milestone.projects.each do |project|
%span.label.label-default
= project.name
= paginate @group_milestones, theme: "gitlab"

View file

@ -1,5 +1,5 @@
xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlnsmedia" => "http://search.yahoo.com/mrss/" do
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
xml.title "Group feed - #{@group.name}"
xml.link href: group_path(@group, :atom), rel: "self", type: "application/atom+xml"
xml.link href: group_path(@group), rel: "alternate", type: "text/html"

View file

@ -52,10 +52,11 @@
- else
%span.light No open milestones available.
&nbsp;
= link_to 'Create new milestone', new_project_milestone_path(issuable.project), target: :blank
- if can? current_user, :admin_milestone, issuable.project
= link_to 'Create new milestone', new_project_milestone_path(issuable.project), target: :blank
.form-group
= f.label :label_ids, class: 'control-label' do
%i.icon-tag
%i.fa.fa-tag
Labels
.col-sm-10
- if issuable.project.labels.any?
@ -64,9 +65,15 @@
- else
%span.light No labels yet.
&nbsp;
= link_to 'Create new label', new_project_label_path(issuable.project), target: :blank
- if can? current_user, :admin_label, issuable.project
= link_to 'Create new label', new_project_label_path(issuable.project), target: :blank
.form-actions
- if !issuable.project.empty_repo? && contribution_guide_url(issuable.project) && !issuable.persisted?
%p
Please review the
%strong #{link_to 'guidelines for contribution', contribution_guide_url(issuable.project)}
to this repository.
- if issuable.new_record?
= f.submit "Submit new #{issuable.class.model_name.human.downcase}", class: 'btn btn-create'
- else

View file

@ -7,5 +7,5 @@
%p= pluralize(commits.count, 'commit')
.col-md-10
%ul.bordered-list
= render commits, project: @project
= render commits, project: project
%hr.lists-separator

View file

@ -13,7 +13,7 @@
= commits_breadcrumbs
%div{id: dom_id(@project)}
#commits-list= render "commits"
#commits-list= render "commits", project: @project
.clear
= spinner

View file

@ -4,7 +4,7 @@
.diff-file{id: "diff-#{i}", data: {blob_diff_path: blob_diff_path }}
.diff-header{id: "file-path-#{hexdigest(diff_file.new_path || diff_file.old_path)}"}
- if diff_file.deleted_file
%span= diff_file.old_path
%span="#{diff_file.old_path} deleted"
.diff-btn-group
- if @commit.parent_ids.present?

View file

@ -1,12 +1,6 @@
%div.issue-form-holder
%h3.page-title= @issue.new_record? ? "New Issue" : "Edit Issue ##{@issue.iid}"
%hr
- if @repository.exists? && !@repository.empty? && @repository.contribution_guide && !@issue.persisted?
- contribution_guide_url = project_blob_path(@project, tree_join(@repository.root_ref, @repository.contribution_guide.name))
.row
.col-sm-10.col-sm-offset-2
.alert.alert-info
= "Please review the <strong>#{link_to "guidelines for contribution", contribution_guide_url}</strong> to this repository.".html_safe
= form_for [@project, @issue], html: { class: 'form-horizontal issue-form gfm-form' } do |f|
= render 'projects/issuable_form', f: f, issuable: @issue

View file

@ -9,74 +9,103 @@
%span.pull-right
= link_to 'Change branches', new_project_merge_request_path(@project)
= form_for [@project, @merge_request], html: { class: "merge-request-form gfm-form" } do |f|
.panel.panel-default
.panel-body
.form-group
.light
= f.label :title do
Title *
= f.text_field :title, class: "form-control input-lg js-gfm-input", maxlength: 255, rows: 5, required: true
.form-group
.light
= f.label :description, "Description"
= form_for [@project, @merge_request], html: { class: "merge-request-form form-horizontal gfm-form" } do |f|
.merge-request-form-info
.form-group
= f.label :title, class: 'control-label' do
%strong Title *
.col-sm-10
= f.text_field :title, maxlength: 255, autofocus: true, class: 'form-control pad js-gfm-input', required: true
.form-group.issuable-description
= f.label :description, 'Description', class: 'control-label'
.col-sm-10
= render layout: 'projects/md_preview' do
= render 'projects/zen', f: f, attr: :description,
classes: 'description form-control'
.clearfix.hint
.pull-left Description is parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'}.
.pull-right Attach images (JPG, PNG, GIF) by dragging & dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }.
.error-alert
.form-group
.issue-assignee
= f.label :assignee_id do
%i.fa.fa-user
Assign to
%div
= project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control', selected: @merge_request.assignee_id, project_id: @merge_request.target_project_id)
&nbsp;
= link_to 'Assign to me', '#', class: 'btn assign-to-me-link'
.form-group
.issue-milestone
= f.label :milestone_id do
%i.fa.fa-clock-o
Milestone
%div= f.select(:milestone_id, milestone_options(@merge_request), { include_blank: "Select milestone" }, {class: 'select2'})
.form-group
= f.label :label_ids do
%i.fa.fa-tag
Labels
%div
= f.collection_select :label_ids, @merge_request.target_project.labels.all, :id, :name, { selected: @merge_request.label_ids }, multiple: true, class: 'select2'
= render 'projects/zen', f: f, attr: :description, classes: 'description form-control'
.panel-footer
.col-sm-12-hint
.pull-left
Parsed with
#{link_to 'Gitlab Flavored Markdown', help_page_path('markdown', 'markdown'), target: '_blank'}.
.pull-right
Attach images (JPG, PNG, GIF) by dragging &amp; dropping
or #{link_to 'selecting them', '#', class: 'markdown-selector'}.
.clearfix
.error-alert
%hr
.form-group
.issue-assignee
= f.label :assignee_id, class: 'control-label' do
%i.fa.fa-user
Assign to
.col-sm-10
= project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control', selected: @merge_request.assignee_id, project_id: @merge_request.target_project_id)
&nbsp;
= link_to 'Assign to me', '#', class: 'btn assign-to-me-link'
.form-group
.issue-milestone
= f.label :milestone_id, class: 'control-label' do
%i.fa.fa-clock-o
Milestone
.col-sm-10
- if milestone_options(@merge_request).present?
= f.select(:milestone_id, milestone_options(@merge_request), {include_blank: 'Select milestone'}, {class: 'select2'})
- else
%span.light No open milestones available.
&nbsp;
- if can? current_user, :admin_milestone, @merge_request.target_project
= link_to 'Create new milestone', new_project_milestone_path(@merge_request.target_project), target: :blank
.form-group
= f.label :label_ids, class: 'control-label' do
%i.fa.fa-tag
Labels
.col-sm-10
- if @merge_request.target_project.labels.any?
= f.collection_select :label_ids, @merge_request.target_project.labels.all, :id, :name, {selected: @merge_request.label_ids}, multiple: true, class: 'select2'
- else
%span.light No labels yet.
&nbsp;
- if can? current_user, :admin_label, @merge_request.target_project
= link_to 'Create new label', new_project_label_path(@merge_request.target_project), target: :blank
.form-actions
- if contribution_guide_url(@target_project)
%p
Please review the
%strong #{link_to "guidelines for contribution", contribution_guide_url(@target_project)}
%strong #{link_to 'guidelines for contribution', contribution_guide_url(@target_project)}
to this repository.
= f.hidden_field :source_project_id
= f.hidden_field :source_branch
= f.hidden_field :target_project_id
= f.hidden_field :target_branch
= f.hidden_field :source_branch
= f.submit 'Submit merge request', class: "btn btn-create"
= f.submit 'Submit merge request', class: 'btn btn-create'
.mr-compare
= render "projects/commits/commit_list"
%h4 Changes
- if @diffs.present?
= render "projects/diffs/diffs", diffs: @diffs, project: @project
- elsif @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
.bs-callout.bs-callout-danger
%h4 This comparison includes more than #{MergeRequestDiff::COMMITS_SAFE_SIZE} commits.
%p To preserve performance the line changes are not shown.
- else
.bs-callout.bs-callout-danger
%h4 This comparison includes huge diff.
%p To preserve performance the line changes are not shown.
.mr-compare.merge-request
%ul.nav.nav-tabs.merge-request-tabs
%li.commits-tab{data: {action: 'commits'}}
= link_to url_for(params) do
%i.fa.fa-history
Commits
%span.badge= @commits.size
%li.diffs-tab{data: {action: 'diffs'}}
= link_to url_for(params) do
%i.fa.fa-list-alt
Changes
%span.badge= @diffs.size
.commits.tab-content
= render "projects/commits/commits", project: @project
.diffs.tab-content
- if @diffs.present?
= render "projects/diffs/diffs", diffs: @diffs, project: @project
- elsif @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
.bs-callout.bs-callout-danger
%h4 This comparison includes more than #{MergeRequestDiff::COMMITS_SAFE_SIZE} commits.
%p To preserve performance the line changes are not shown.
- else
.bs-callout.bs-callout-danger
%h4 This comparison includes a huge diff.
%p To preserve performance the line changes are not shown.
:javascript
$('.assign-to-me-link').on('click', function(e){
@ -85,3 +114,9 @@
});
window.project_image_path_upload = "#{upload_image_project_path @project}";
:javascript
var merge_request
merge_request = new MergeRequest({
action: 'commits'
});

View file

@ -42,7 +42,7 @@
%span.badge= @merge_request.mr_and_commit_notes.count
%li.commits-tab{data: {action: 'commits'}}
= link_to project_merge_request_path(@project, @merge_request), title: 'Commits' do
%i.fa.fa-database
%i.fa.fa-history
Commits
%span.badge= @commits.size
%li.diffs-tab{data: {action: 'diffs'}}

View file

@ -1,30 +1 @@
- if @commits.present?
.panel.panel-default
.panel-heading
%i.fa.fa-list
Commits (#{@commits.count})
.commits.mr-commits
- if @commits.count > 8
%ul.first-commits.well-list
- @commits.first(8).each do |commit|
= render "projects/commits/commit", commit: commit, project: @merge_request.source_project
%li.bottom
8 of #{@commits.count} commits displayed.
%strong
%a.show-all-commits Click here to show all
- if @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
%ul.all-commits.hide.well-list
- @commits.first(MergeRequestDiff::COMMITS_SAFE_SIZE).each do |commit|
= render "projects/commits/inline_commit", commit: commit, project: @merge_request.source_project
%li
other #{@commits.size - MergeRequestDiff::COMMITS_SAFE_SIZE} commits hidden to prevent performance issues.
- else
%ul.all-commits.hide.well-list
- @commits.each do |commit|
= render "projects/commits/inline_commit", commit: commit, project: @merge_request.source_project
- else
%ul.well-list
- @commits.each do |commit|
= render "projects/commits/commit", commit: commit, project: @merge_request.source_project
= render "projects/commits/commits", project: @merge_request.source_project

View file

@ -13,25 +13,22 @@
.automerge_widget.can_be_merged.hide
.clearfix
= form_for [:automerge, @project, @merge_request], remote: true, method: :post do |f|
%h4
You can accept this request automatically.
.accept-merge-holder.clearfix
.accept-group
.pull-left
= f.submit "Accept Merge Request", class: "btn btn-create accept_merge_request"
- if can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) && !@merge_request.for_fork?
.remove_branch_holder.pull-left
= label_tag :should_remove_source_branch, class: "checkbox" do
= check_box_tag :should_remove_source_branch
Remove source-branch
.js-toggle-container
%label
%i.fa.fa-edit
= link_to "modify merge commit message", "#", class: "modify-merge-commit-link js-toggle-button", title: "Modify merge commit message"
.js-toggle-content.hide
= render 'shared/commit_message_container', params: params,
text: @merge_request.merge_commit_message,
rows: 14, hint: true
.accept-merge-holder.clearfix.js-toggle-container
.accept-action
= f.submit "Accept Merge Request", class: "btn btn-create accept_merge_request"
- if can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) && !@merge_request.for_fork?
.accept-control
= label_tag :should_remove_source_branch, class: "checkbox" do
= check_box_tag :should_remove_source_branch
Remove source-branch
.accept-control
= link_to "#", class: "modify-merge-commit-link js-toggle-button", title: "Modify merge commit message" do
%i.fa.fa-edit
Modify commit message
.js-toggle-content.hide.prepend-top-20
= render 'shared/commit_message_container', params: params,
text: @merge_request.merge_commit_message,
rows: 14, hint: true
%hr
.light

View file

@ -7,27 +7,15 @@
%i.fa.fa-plus
New Milestone
.row
.fixed.sidebar-expand-button.hidden-lg.hidden-md.hidden-xs
%i.fa.fa-list.fa-2x
.col-md-3.responsive-side
%ul.nav.nav-pills.nav-stacked
%li{class: ("active" if (params[:f] == "active" || !params[:f]))}
= link_to project_milestones_path(@project, f: "active") do
Active
%li{class: ("active" if params[:f] == "closed")}
= link_to project_milestones_path(@project, f: "closed") do
Closed
%li{class: ("active" if params[:f] == "all")}
= link_to project_milestones_path(@project, f: "all") do
All
.col-md-9
.panel.panel-default
%ul.well-list
= render @milestones
= render 'shared/milestones_filter'
- if @milestones.blank?
%li
.nothing-here-block No milestones to show
.milestones
.panel.panel-default
%ul.well-list
= render @milestones
= paginate @milestones, theme: "gitlab"
- if @milestones.blank?
%li
.nothing-here-block No milestones to show
= paginate @milestones, theme: "gitlab"

View file

@ -19,13 +19,15 @@
%code [Link Title](page-slug)
\.
.form-group
.form-group.wiki-content
= f.label :content, class: 'control-label'
.col-sm-10
= render 'projects/zen', f: f, attr: :content, classes: 'description form-control'
.col-sm-12.hint
.pull-left Wiki content is parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'}
.pull-right Attach images (JPG, PNG, GIF) by dragging & dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }.
= render layout: 'projects/md_preview' do
= render 'projects/zen', f: f, attr: :content, classes: 'description form-control'
.col-sm-12.hint
.pull-left Wiki content is parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'}
.pull-right Attach images (JPG, PNG, GIF) by dragging &amp; dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }.
.clearfix
.error-alert
.form-group

View file

@ -0,0 +1,16 @@
.fixed.sidebar-expand-button.hidden-lg.hidden-md
%i.fa.fa-list.fa-2x
.responsive-side.milestones-filters.append-bottom-10
%ul.nav.nav-pills.nav-compact
%li{class: ("active" if params[:state].blank? || params[:state] == 'opened')}
= link_to milestones_filter_path(state: 'opened') do
%i.fa.fa-exclamation-circle
Open
%li{class: ("active" if params[:state] == 'closed')}
= link_to milestones_filter_path(state: 'closed') do
%i.fa.fa-check-circle
Closed
%li{class: ("active" if params[:state] == 'all')}
= link_to milestones_filter_path(state: 'all') do
%i.fa.fa-compass
All

View file

@ -1,5 +1,5 @@
xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlnsmedia" => "http://search.yahoo.com/mrss/" do
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
xml.title "Activity feed for #{@user.name}"
xml.link href: user_url(@user, :atom), rel: "self", type: "application/atom+xml"
xml.link href: user_url(@user), rel: "alternate", type: "text/html"

View file

@ -1,3 +1,4 @@
# GitLab operations
- [Sidekiq MemoryKiller](sidekiq_memory_killer.md)
- [Cleaning up Redis sessions](cleaning_up_redis_sessions.md)

View file

@ -0,0 +1,52 @@
# Cleaning up stale Redis sessions
Since version 6.2, GitLab stores web user sessions as key-value pairs in Redis.
Prior to GitLab 7.3, user sessions did not automatically expire from Redis. If
you have been running a large GitLab server (thousands of users) since before
GitLab 7.3 we recommend cleaning up stale sessions to compact the Redis
database after you upgrade to GitLab 7.3. You can also perform a cleanup while
still running GitLab 7.2 or older, but in that case new stale sessions will
start building up again after you clean up.
In GitLab versions prior to 7.3.0, the session keys in Redis are 16-byte
hexadecimal values such as '976aa289e2189b17d7ef525a6702ace9'. Starting with
GitLab 7.3.0, the keys are
prefixed with 'session:gitlab:', so they would look like
'session:gitlab:976aa289e2189b17d7ef525a6702ace9'. Below we describe how to
remove the keys in the old format.
First we define a shell function with the proper Redis connection details.
```
rcli() {
# This example works for Omnibus installations of GitLab 7.3 or newer. For an
# installation from source you will have to change the socket path and the
# path to redis-cli.
sudo /opt/gitlab/embedded/bin/redis-cli -s /var/opt/gitlab/redis/redis.socket "$@"
}
# test the new shell function; the response should be PONG
rcli ping
```
Now we do a search to see if there are any session keys in the old format for
us to clean up.
```
# returns the number of old-format session keys in Redis
rcli keys '*' | grep '^[a-f0-9]\{32\}$' | wc -l
```
If the number is larger than zero, you can proceed to expire the keys from
Redis. If the number is zero there is nothing to clean up.
```
# Tell Redis to expire each matched key after 600 seconds.
rcli keys '*' | grep '^[a-f0-9]\{32\}$' | awk '{ print "expire", $0, 600 }' | rcli
# This will print '(integer) 1' for each key that gets expired.
```
Over the next 15 minutes (10 minutes expiry time plus 5 minutes Redis
background save interval) your Redis database will be compacted. If you are
still using GitLab 7.2, users who are not clicking around in GitLab during the
10 minute expiry window will be signed out of GitLab.

View file

@ -49,4 +49,4 @@ If a user is a GitLab administrator they receive all permissions.
| Manage group members | | | | | ✓ |
| Remove group | | | | | ✓ |
Any user can remove himself from a group, unless he is the last Owner of the group.
Any user can remove themselves from a group, unless they are the last Owner of the group.

View file

@ -50,6 +50,16 @@ Feature: Project Source Browse Files
And I click button "Edit"
Then I can edit code
Scenario: If the file is binary the edit link is hidden
Given I visit a binary file in the repo
Then I cannot see the edit button
Scenario: If I don't have edit permission the edit link is disabled
Given public project "Community"
And I visit project "Community" source page
And I click on ".gitignore" file in repo
Then The edit button is disabled
@javascript
Scenario: I can edit and commit file
Given I click on ".gitignore" file in repo

View file

@ -113,7 +113,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
click_link 'Commits'
end
within '.mr-commits' do
within '.commits' do
click_link Commit.truncate_sha(sample_commit.id)
end
end
@ -156,7 +156,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end
step 'merge request is mergeable' do
page.should have_content 'You can accept this request automatically'
page.should have_button 'Accept Merge Request'
end
step 'I modify merge commit message' do

View file

@ -48,6 +48,14 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
click_link 'Edit'
end
step 'I cannot see the edit button' do
page.should_not have_link 'edit'
end
step 'The edit button is disabled' do
page.should have_css '.disabled', text: 'Edit'
end
step 'I can edit code' do
set_new_content
evaluate_script('editor.getValue()').should == new_gitignore_content

View file

@ -183,6 +183,11 @@ module SharedPaths
visit project_tree_path(@project, root_ref)
end
step 'I visit a binary file in the repo' do
visit project_blob_path(@project, File.join(
root_ref, 'files/images/logo-black.png'))
end
step "I visit my project's commits page" do
visit project_commits_path(@project, root_ref, {limit: 5})
end
@ -385,6 +390,11 @@ module SharedPaths
visit project_path(project)
end
step 'I visit project "Community" source page' do
project = Project.find_by(name: 'Community')
visit project_tree_path(project, root_ref)
end
step 'I visit project "Internal" page' do
project = Project.find_by(name: "Internal")
visit project_path(project)

View file

@ -24,11 +24,12 @@ describe "User Feed", feature: true do
end
it "should have issue opened event" do
body.should have_content("#{user.name} opened issue ##{issue.iid}")
expect(body).to have_content("#{safe_name} opened issue ##{issue.iid}")
end
it "should have issue comment event" do
body.should have_content("#{user.name} commented on issue ##{issue.iid}")
expect(body).
to have_content("#{safe_name} commented on issue ##{issue.iid}")
end
end
end
@ -40,4 +41,8 @@ describe "User Feed", feature: true do
def note_event(note, user)
EventCreateService.new.leave_note(note, user)
end
def safe_name
html_escape(user.name)
end
end

View file

@ -47,10 +47,10 @@ describe MergeRequests::RefreshService do
reload_mrs
end
it { @merge_request.notes.should be_empty }
it { @merge_request.notes.last.note.should include('changed to merged') }
it { @merge_request.should be_merged }
it { @fork_merge_request.should be_merged }
it { @fork_merge_request.notes.should be_empty }
it { @fork_merge_request.notes.last.note.should include('changed to merged') }
end
context 'push to fork repo source branch' do
@ -61,7 +61,7 @@ describe MergeRequests::RefreshService do
it { @merge_request.notes.should be_empty }
it { @merge_request.should be_open }
it { @fork_merge_request.notes.should_not be_empty }
it { @fork_merge_request.notes.last.note.should include('new commit') }
it { @fork_merge_request.should be_open }
end
@ -84,7 +84,7 @@ describe MergeRequests::RefreshService do
reload_mrs
end
it { @merge_request.notes.should be_empty }
it { @merge_request.notes.last.note.should include('changed to merged') }
it { @merge_request.should be_merged }
it { @fork_merge_request.should be_open }
it { @fork_merge_request.notes.should be_empty }