Commit 0da59cb5 authored by Marin Jankovski's avatar Marin Jankovski

Merge branch 'master' into move_external_issue_tracker_away_from_yml_config

Conflicts:
	app/models/project.rb
	spec/models/project_spec.rb
parents 33913f9b e6b97d09
...@@ -3,7 +3,7 @@ Note: The upcoming release contains empty lines to reduce the number of merge co ...@@ -3,7 +3,7 @@ Note: The upcoming release contains empty lines to reduce the number of merge co
v 7.8.0 v 7.8.0
- Replace highlight.js with rouge-fork rugments (Stefan Tatschner) - Replace highlight.js with rouge-fork rugments (Stefan Tatschner)
- Make project search case insensitive (Hannes Rosenögger) - Make project search case insensitive (Hannes Rosenögger)
- - Include issue/mr participants in list of recipients for reassign/close/reopen emails
- Expose description in groups API - Expose description in groups API
- -
- -
...@@ -17,12 +17,12 @@ v 7.8.0 ...@@ -17,12 +17,12 @@ v 7.8.0
- Show tags in commit view (Hannes Rosenögger) - Show tags in commit view (Hannes Rosenögger)
- Only count a user's vote once on a merge request or issue (Michael Clarke) - Only count a user's vote once on a merge request or issue (Michael Clarke)
- -
- - Increate font size when browse source files and diffs
- - Create new file in empty repository using GitLab UI
- -
- Upgrade Sidekiq gem to version 3.3.0 - Upgrade Sidekiq gem to version 3.3.0
- Stop git zombie creation during force push check - Stop git zombie creation during force push check
- - Show success/error messages for test setting button in services
- -
- Fix commits pagination - Fix commits pagination
- -
...@@ -34,10 +34,10 @@ v 7.8.0 ...@@ -34,10 +34,10 @@ v 7.8.0
- -
- -
- -
- 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.
-
- -
- -
- -
......
...@@ -96,6 +96,7 @@ class Dispatcher ...@@ -96,6 +96,7 @@ class Dispatcher
new Profile() new Profile()
when 'projects' when 'projects'
new Project() new Project()
new ProjectAvatar()
switch path[1] switch path[1]
when 'edit' when 'edit'
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
......
class @ProjectAvatar
constructor: ->
$('.js-choose-project-avatar-button').bind 'click', ->
form = $(this).closest('form')
form.find('.js-project-avatar-input').click()
$('.js-project-avatar-input').bind 'change', ->
form = $(this).closest('form')
filename = $(this).val().replace(/^.*[\\\/]/, '')
form.find('.js-avatar-filename').text(filename)
...@@ -8,10 +8,11 @@ ...@@ -8,10 +8,11 @@
&.avatar-inline { &.avatar-inline {
float: none; float: none;
margin-left: 3px; margin-left: 4px;
margin-bottom: 2px;
&.s16 { margin-right: 2px; } &.s16 { margin-right: 4px; }
&.s24 { margin-right: 2px; } &.s24 { margin-right: 4px; }
} }
&.s16 { width: 16px; height: 16px; margin-right: 6px; } &.s16 { width: 16px; height: 16px; margin-right: 6px; }
...@@ -22,3 +23,16 @@ ...@@ -22,3 +23,16 @@
&.s90 { width: 90px; height: 90px; margin-right: 15px; } &.s90 { width: 90px; height: 90px; margin-right: 15px; }
&.s160 { width: 160px; height: 160px; margin-right: 20px; } &.s160 { width: 160px; height: 160px; margin-right: 20px; }
} }
.identicon {
text-align: center;
vertical-align: top;
&.s16 { font-size: 12px; line-height: 1.33; }
&.s24 { font-size: 14px; line-height: 1.8; }
&.s26 { font-size: 20px; line-height: 1.33; }
&.s32 { font-size: 24px; line-height: 1.33; }
&.s60 { font-size: 45px; line-height: 1.33; }
&.s90 { font-size: 68px; line-height: 1.33; }
&.s160 { font-size: 120px; line-height: 1.33; }
}
...@@ -173,6 +173,11 @@ ...@@ -173,6 +173,11 @@
margin-right: 0px; margin-right: 0px;
} }
} }
&.btn-lg {
font-size: 15px;
line-height: 1.4;
}
} }
.btn-block { .btn-block {
......
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
border: none; border: none;
border-radius: 0; border-radius: 0;
font-family: $monospace_font; font-family: $monospace_font;
font-size: 12px !important; font-size: $code_font_size !important;
line-height: 16px !important; line-height: $code_line_height !important;
margin: 0; margin: 0;
overflow: auto; overflow: auto;
overflow-y: hidden; overflow-y: hidden;
...@@ -38,8 +38,8 @@ ...@@ -38,8 +38,8 @@
a { a {
font-family: $monospace_font; font-family: $monospace_font;
display: block; display: block;
font-size: 12px !important; font-size: $code_font_size !important;
line-height: 16px !important; line-height: $code_line_height !important;
white-space: nowrap; white-space: nowrap;
i { i {
......
...@@ -59,3 +59,5 @@ $list-font-size: 15px; ...@@ -59,3 +59,5 @@ $list-font-size: 15px;
$sidebar_width: 230px; $sidebar_width: 230px;
$avatar_radius: 50%; $avatar_radius: 50%;
$code_font_size: 13px;
$code_line_height: 1.5;
...@@ -75,6 +75,9 @@ ...@@ -75,6 +75,9 @@
} }
} }
} }
.project-avatar {
float: left;
}
.project-description { .project-description {
overflow: hidden; overflow: hidden;
...@@ -92,8 +95,24 @@ ...@@ -92,8 +95,24 @@
} }
} }
.dash-project-avatar {
float: left;
}
.dash-project-access-icon { .dash-project-access-icon {
float: left; float: left;
margin-right: 3px; margin-right: 5px;
width: 16px; width: 16px;
} }
.dash-new-project {
background: $bg_success;
border: 1px solid $border_success;
a {
color: #FFF;
}
}
.dash-list .str-truncated {
max-width: 72%;
}
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
overflow-y: hidden; overflow-y: hidden;
background: #FFF; background: #FFF;
color: #333; color: #333;
font-size: 12px; font-size: $code_font_size;
.old { .old {
span.idiff { span.idiff {
background-color: #F99; background-color: #F99;
...@@ -64,8 +64,8 @@ ...@@ -64,8 +64,8 @@
margin: 0px; margin: 0px;
padding: 0px; padding: 0px;
td { td {
line-height: 18px; line-height: $code_line_height;
font-size: 12px; font-size: $code_font_size;
} }
} }
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
.project-home-panel { .project-home-panel {
margin-bottom: 15px; margin-bottom: 15px;
position: relative;
padding-left: 85px;
&.empty-project { &.empty-project {
border-bottom: 0px; border-bottom: 0px;
...@@ -23,6 +25,22 @@ ...@@ -23,6 +25,22 @@
margin-bottom: 0px; margin-bottom: 0px;
} }
.project-identicon-holder {
position: absolute;
left: 0;
.avatar {
width: 70px;
height: 70px;
@include border-radius(0px);
}
.identicon {
font-size: 45px;
line-height: 1.6;
}
}
.project-home-dropdown { .project-home-dropdown {
margin-left: 10px; margin-left: 10px;
float: right; float: right;
......
...@@ -5,12 +5,12 @@ class PasswordsController < Devise::PasswordsController ...@@ -5,12 +5,12 @@ class PasswordsController < Devise::PasswordsController
resource_found = resource_class.find_by_email(email) resource_found = resource_class.find_by_email(email)
if resource_found && resource_found.ldap_user? if resource_found && resource_found.ldap_user?
flash[:alert] = "Cannot reset password for LDAP user." flash[:alert] = "Cannot reset password for LDAP user."
respond_with({}, :location => after_sending_reset_password_instructions_path_for(resource_name)) and return respond_with({}, location: after_sending_reset_password_instructions_path_for(resource_name)) and return
end end
self.resource = resource_class.send_reset_password_instructions(resource_params) self.resource = resource_class.send_reset_password_instructions(resource_params)
if successfully_sent?(resource) if successfully_sent?(resource)
respond_with({}, :location => after_sending_reset_password_instructions_path_for(resource_name)) respond_with({}, location: after_sending_reset_password_instructions_path_for(resource_name))
else else
respond_with(resource) respond_with(resource)
end end
......
class Projects::AvatarsController < Projects::ApplicationController
layout 'project'
before_filter :project
def show
@blob = @project.repository.blob_at_branch('master', @project.avatar_in_git)
if @blob
headers['X-Content-Type-Options'] = 'nosniff'
send_data(
@blob.data,
type: @blob.mime_type,
disposition: 'inline',
filename: @blob.name
)
else
not_found!
end
end
def destroy
@project.remove_avatar!
@project.save
@project.reset_events_cache
redirect_to edit_project_path(@project)
end
end
class Projects::BaseTreeController < Projects::ApplicationController
include ExtractsPath
before_filter :authorize_download_code!
before_filter :require_non_empty_project
end
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
class Projects::BlameController < Projects::ApplicationController class Projects::BlameController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
# Authorize before_filter :assign_ref_vars
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
......
...@@ -2,16 +2,70 @@ ...@@ -2,16 +2,70 @@
class Projects::BlobController < Projects::ApplicationController class Projects::BlobController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
# Authorize # Raised when given an invalid file path
class InvalidPathError < StandardError; end
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project, except: [:new, :create]
before_filter :authorize_push_code!, only: [:destroy] before_filter :authorize_push_code!, only: [:destroy]
before_filter :assign_blob_vars
before_filter :commit, except: [:new, :create]
before_filter :blob, except: [:new, :create]
before_filter :from_merge_request, only: [:edit, :update]
before_filter :after_edit_path, only: [:edit, :update]
before_filter :require_branch_head, only: [:edit, :update]
def new
commit unless @repository.empty?
end
before_filter :blob def create
file_path = File.join(@path, File.basename(params[:file_name]))
result = Files::CreateService.new(@project, current_user, params, @ref, file_path).execute
if result[:status] == :success
flash[:notice] = "Your changes have been successfully committed"
redirect_to project_blob_path(@project, File.join(@ref, file_path))
else
flash[:alert] = result[:message]
render :new
end
end
def show def show
end end
def edit
@last_commit = Gitlab::Git::Commit.last_for_path(@repository, @ref, @path).sha
end
def update
result = Files::UpdateService.
new(@project, current_user, params, @ref, @path).execute
if result[:status] == :success
flash[:notice] = "Your changes have been successfully committed"
if from_merge_request
from_merge_request.reload_code
end
redirect_to after_edit_path
else
flash[:alert] = result[:message]
render :edit
end
end
def preview
@content = params[:content]
diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3',
include_diff_info: true)
@diff_lines = Gitlab::Diff::Parser.new.parse(diffy.diff.scan(/.*\n/))
render layout: false
end
def destroy def destroy
result = Files::DeleteService.new(@project, current_user, params, @ref, @path).execute result = Files::DeleteService.new(@project, current_user, params, @ref, @path).execute
...@@ -46,10 +100,44 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -46,10 +100,44 @@ class Projects::BlobController < Projects::ApplicationController
if @blob if @blob
@blob @blob
elsif tree.entries.any?
redirect_to project_tree_path(@project, File.join(@ref, @path)) and return
else else
if tree = @repository.tree(@commit.id, @path)
if tree.entries.any?
redirect_to project_tree_path(@project, File.join(@ref, @path)) and return
end
end
return not_found! return not_found!
end end
end end
def commit
@commit = @repository.commit(@ref)
return not_found! unless @commit
end
def assign_blob_vars
@id = params[:id]
@ref, @path = extract_ref(@id)
rescue InvalidPathError
not_found!
end
def after_edit_path
@after_edit_path ||=
if from_merge_request
diffs_project_merge_request_path(from_merge_request.target_project, from_merge_request) +
"#file-path-#{hexdigest(@path)}"
else
project_blob_path(@project, @id)
end
end
def from_merge_request
# If blob edit was initiated from merge request page
@from_merge_request ||= MergeRequest.find_by(id: params[:from_merge_request_id])
end
end end
...@@ -3,7 +3,7 @@ require "base64" ...@@ -3,7 +3,7 @@ require "base64"
class Projects::CommitsController < Projects::ApplicationController class Projects::CommitsController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
# Authorize before_filter :assign_ref_vars
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
......
class Projects::EditTreeController < Projects::BaseTreeController
before_filter :require_branch_head
before_filter :blob
before_filter :authorize_push_code!
before_filter :from_merge_request
before_filter :after_edit_path
def show
@last_commit = Gitlab::Git::Commit.last_for_path(@repository, @ref, @path).sha
end
def update
result = Files::UpdateService.
new(@project, current_user, params, @ref, @path).execute
if result[:status] == :success
flash[:notice] = "Your changes have been successfully committed"
if from_merge_request
from_merge_request.reload_code
end
redirect_to after_edit_path
else
flash[:alert] = result[:message]
render :show
end
end
def preview
@content = params[:content]
diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3',
include_diff_info: true)
@diff_lines = Gitlab::Diff::Parser.new.parse(diffy.diff.scan(/.*\n/))
render layout: false
end
private
def blob
@blob ||= @repository.blob_at(@commit.id, @path)
end
def after_edit_path
@after_edit_path ||=
if from_merge_request
diffs_project_merge_request_path(from_merge_request.target_project, from_merge_request) +
"#file-path-#{hexdigest(@path)}"
else
project_blob_path(@project, @id)
end
end
def from_merge_request
# If blob edit was initiated from merge request page
@from_merge_request ||= MergeRequest.find_by(id: params[:from_merge_request_id])
end
end
...@@ -2,7 +2,7 @@ class Projects::NetworkController < Projects::ApplicationController ...@@ -2,7 +2,7 @@ class Projects::NetworkController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
include ApplicationHelper include ApplicationHelper
# Authorize before_filter :assign_ref_vars
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
......
class Projects::NewTreeController < Projects::BaseTreeController
before_filter :require_branch_head
before_filter :authorize_push_code!
def show
end
def update
file_path = File.join(@path, File.basename(params[:file_name]))
result = Files::CreateService.new(@project, current_user, params, @ref, file_path).execute
if result[:status] == :success
flash[:notice] = "Your changes have been successfully committed"
redirect_to project_blob_path(@project, File.join(@ref, file_path))
else
flash[:alert] = result[:message]
render :show
end
end
end
...@@ -24,7 +24,7 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController ...@@ -24,7 +24,7 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController
) )
respond_to do |format| respond_to do |format|
format.json { render :json => protected_branch, status: :ok } format.json { render json: protected_branch, status: :ok }
end end
else else
respond_to do |format| respond_to do |format|
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
class Projects::RawController < Projects::ApplicationController class Projects::RawController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
# Authorize before_filter :assign_ref_vars
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
......
class Projects::RefsController < Projects::ApplicationController class Projects::RefsController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
# Authorize before_filter :assign_ref_vars
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
......
...@@ -29,9 +29,13 @@ class Projects::ServicesController < Projects::ApplicationController ...@@ -29,9 +29,13 @@ class Projects::ServicesController < Projects::ApplicationController
def test def test
data = Gitlab::PushDataBuilder.build_sample(project, current_user) data = Gitlab::PushDataBuilder.build_sample(project, current_user)
@service.execute(data) if @service.execute(data)
message = { notice: 'We sent a request to the provided URL' }
else
message = { alert: 'We tried to send a request to the provided URL but error occured' }
end
redirect_to :back redirect_to :back, message
end end
private private
......
# Controller for viewing a repository's file structure # Controller for viewing a repository's file structure
class Projects::TreeController < Projects::BaseTreeController class Projects::TreeController < Projects::ApplicationController
def show include ExtractsPath
before_filter :assign_ref_vars
before_filter :authorize_download_code!
before_filter :require_non_empty_project, except: [:new, :create]
def show
if tree.entries.empty? if tree.entries.empty?
if @repository.blob_at(@commit.id, @path) if @repository.blob_at(@commit.id, @path)
redirect_to project_blob_path(@project, File.join(@ref, @path)) and return redirect_to project_blob_path(@project, File.join(@ref, @path)) and return
......
...@@ -14,7 +14,7 @@ class ProjectsController < ApplicationController ...@@ -14,7 +14,7 @@ class ProjectsController < ApplicationController
end end
def edit def edit
render 'edit', layout: "project_settings" render 'edit', layout: 'project_settings'
end end
def create def create
...@@ -36,7 +36,7 @@ class ProjectsController < ApplicationController ...@@ -36,7 +36,7 @@ class ProjectsController < ApplicationController
format.html { redirect_to edit_project_path(@project), notice: 'Project was successfully updated.' } format.html { redirect_to edit_project_path(@project), notice: 'Project was successfully updated.' }
format.js format.js
else else
format.html { render "edit", layout: "project_settings" } format.html { render 'edit', layout: 'project_settings' }
format.js format.js
end end
end end
...@@ -66,17 +66,17 @@ class ProjectsController < ApplicationController ...@@ -66,17 +66,17 @@ class ProjectsController < ApplicationController
format.html do format.html do
if @project.repository_exists? if @project.repository_exists?
if @project.empty_repo? if @project.empty_repo?
render "projects/empty", layout: user_layout render 'projects/empty', layout: user_layout
else else
@last_push = current_user.recent_push(@project.id) if current_user @last_push = current_user.recent_push(@project.id) if current_user
render :show, layout: user_layout render :show, layout: user_layout
end end
else else
render "projects/no_repo", layout: user_layout render 'projects/no_repo', layout: user_layout
end end
end end
format.json { pager_json("events/_events", @events.count) } format.json { pager_json('events/_events', @events.count) }
end end
end end
...@@ -87,9 +87,9 @@ class ProjectsController < ApplicationController ...@@ -87,9 +87,9 @@ class ProjectsController < ApplicationController
respond_to do |format| respond_to do |format|
format.html do format.html do
flash[:alert] = "Project deleted." flash[:alert] = 'Project deleted.'
if request.referer.include?("/admin") if request.referer.include?('/admin')
redirect_to admin_projects_path redirect_to admin_projects_path
else else
redirect_to projects_dashboard_path redirect_to projects_dashboard_path
...@@ -104,22 +104,15 @@ class ProjectsController < ApplicationController ...@@ -104,22 +104,15 @@ class ProjectsController < ApplicationController
autocomplete = ::Projects::AutocompleteService.new(@project) autocomplete = ::Projects::AutocompleteService.new(@project)
participants = ::Projects::ParticipantsService.new(@project).execute(note_type, note_id) participants = ::Projects::ParticipantsService.new(@project).execute(note_type, note_id)
emojis = Emoji.names.map do |e|
{
name: e,
path: view_context.image_url("emoji/#{e}.png")
}
end
@suggestions = { @suggestions = {
emojis: emojis, emojis: autocomplete_emojis,
issues: autocomplete.issues, issues: autocomplete.issues,
mergerequests: autocomplete.merge_requests, mergerequests: autocomplete.merge_requests,
members: participants members: participants
} }
respond_to do |format| respond_to do |format|
format.json { render :json => @suggestions } format.json { render json: @suggestions }
end end
end end
...@@ -148,7 +141,7 @@ class ProjectsController < ApplicationController ...@@ -148,7 +141,7 @@ class ProjectsController < ApplicationController
if link_to_image if link_to_image
format.json { render json: { link: link_to_image } } format.json { render json: { link: link_to_image } }
else else
format.json { render json: "Invalid file.", status: :unprocessable_entity } format.json { render json: 'Invalid file.', status: :unprocessable_entity }
end end
end end
end end
...@@ -179,14 +172,25 @@ class ProjectsController < ApplicationController ...@@ -179,14 +172,25 @@ class ProjectsController < ApplicationController
end end
def user_layout def user_layout
current_user ? "projects" : "public_projects" current_user ? 'projects' : 'public_projects'
end end
def project_params def project_params
params.require(:project).permit( params.require(:project).permit(
:name, :path, :description, :issues_tracker, :tag_list, :name, :path, :description, :issues_tracker, :tag_list,
:issues_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id, :default_branch, :issues_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id, :default_branch,
:wiki_enabled, :visibility_level, :import_url, :last_activity_at, :namespace_id :wiki_enabled, :visibility_level, :import_url, :last_activity_at, :namespace_id, :avatar
) )
end end
def autocomplete_emojis
Rails.cache.fetch("autocomplete-emoji-#{Emoji::VERSION}") do
Emoji.names.map do |e|
{
name: e,
path: view_context.image_url("emoji/#{e}.png")
}
end
end
end
end end
...@@ -50,6 +50,38 @@ module ApplicationHelper ...@@ -50,6 +50,38 @@ module ApplicationHelper
args.any? { |v| v.to_s.downcase == action_name } args.any? { |v| v.to_s.downcase == action_name }
end end
def project_icon(project_id, options = {})
project = Project.find_with_namespace(project_id)
if project.avatar.present?
image_tag project.avatar.url, options
elsif project.avatar_in_git
image_tag project_avatar_path(project), options
else # generated icon
project_identicon(project, options)
end
end
def project_identicon(project, options = {})
allowed_colors = {
red: 'FFEBEE',
purple: 'F3E5F5',
indigo: 'E8EAF6',
blue: 'E3F2FD',
teal: 'E0F2F1',
orange: 'FBE9E7',
gray: 'EEEEEE'
}
options[:class] ||= ''
options[:class] << ' identicon'
bg_key = project.id % 7
content_tag(:div, class: options[:class],
style: "background-color: ##{ allowed_colors.values[bg_key] }; color: #555") do
project.name[0, 1].upcase
end
end
def group_icon(group_path) def group_icon(group_path)
group = Group.find_by(path: group_path) group = Group.find_by(path: group_path)
if group && group.avatar.present? if group && group.avatar.present?
...@@ -82,24 +114,24 @@ module ApplicationHelper ...@@ -82,24 +114,24 @@ module ApplicationHelper
if project.repo_exists? if project.repo_exists?
time_ago_with_tooltip(project.repository.commit.committed_date) time_ago_with_tooltip(project.repository.commit.committed_date)
else else
"Never" 'Never'
end end
rescue rescue
"Never" 'Never'
end end
def grouped_options_refs def grouped_options_refs
repository = @project.repository repository = @project.repository
options = [ options = [
["Branches", repository.branch_names], ['Branches', repository.branch_names],
["Tags", VersionSorter.rsort(repository.tag_names)] ['Tags', VersionSorter.rsort(repository.tag_names)]
] ]
# If reference is commit id - we should add it to branch/tag selectbox # If reference is commit id - we should add it to branch/tag selectbox
if(@ref && !options.flatten.include?(@ref) && if(@ref && !options.flatten.include?(@ref) &&
@ref =~ /^[0-9a-zA-Z]{6,52}$/) @ref =~ /^[0-9a-zA-Z]{6,52}$/)
options << ["Commit", [@ref]] options << ['Commit', [@ref]]
end end
grouped_options_for_select(options, @ref || @project.default_branch) grouped_options_for_select(options, @ref || @project.default_branch)
...@@ -161,7 +193,7 @@ module ApplicationHelper ...@@ -161,7 +193,7 @@ module ApplicationHelper
path = controller.controller_path.split('/') path = controller.controller_path.split('/')
namespace = path.first if path.second namespace = path.first if path.second
[namespace, controller.controller_name, controller.action_name].compact.join(":") [namespace, controller.controller_name, controller.action_name].compact.join(':')
end end
# shortcut for gitlab config # shortcut for gitlab config
...@@ -176,13 +208,13 @@ module ApplicationHelper ...@@ -176,13 +208,13 @@ module ApplicationHelper
def search_placeholder def search_placeholder
if @project && @project.persisted? if @project && @project.persisted?
"Search in this project" 'Search in this project'
elsif @snippet || @snippets || @show_snippets elsif @snippet || @snippets || @show_snippets
'Search snippets' 'Search snippets'
elsif @group && @group.persisted? elsif @group && @group.persisted?
"Search in this group" 'Search in this group'
else else
"Search" 'Search'
end end
end end
...@@ -193,7 +225,7 @@ module ApplicationHelper ...@@ -193,7 +225,7 @@ module ApplicationHelper
def time_ago_with_tooltip(date, placement = 'top', html_class = 'time_ago') def time_ago_with_tooltip(date, placement = 'top', html_class = 'time_ago')
capture_haml do capture_haml do
haml_tag :time, date.to_s, haml_tag :time, date.to_s,
class: html_class, datetime: date.getutc.iso8601, title: date.stamp("Aug 21, 2011 9:23pm"), class: html_class, datetime: date.getutc.iso8601, title: date.stamp('Aug 21, 2011 9:23pm'),
data: { toggle: 'tooltip', placement: placement } data: { toggle: 'tooltip', placement: placement }
haml_tag :script, "$('." + html_class + "').timeago().tooltip()" haml_tag :script, "$('." + html_class + "').timeago().tooltip()"
...@@ -216,8 +248,8 @@ module ApplicationHelper ...@@ -216,8 +248,8 @@ module ApplicationHelper
end end
def spinner(text = nil, visible = false) def spinner(text = nil, visible = false)
css_class = "loading" css_class = 'loading'
css_class << " hide" unless visible css_class << ' hide' unless visible
content_tag :div, class: css_class do content_tag :div, class: css_class do
content_tag(:i, nil, class: 'fa fa-spinner fa-spin') + text content_tag(:i, nil, class: 'fa fa-spinner fa-spin') + text
...@@ -234,17 +266,17 @@ module ApplicationHelper ...@@ -234,17 +266,17 @@ module ApplicationHelper
absolute_uri = nil absolute_uri = nil
end end
# Add "nofollow" only to external links # Add 'nofollow' only to external links
if host && host != Gitlab.config.gitlab.host && absolute_uri if host && host != Gitlab.config.gitlab.host && absolute_uri
if html_options if html_options
if html_options[:rel] if html_options[:rel]
html_options[:rel] << " nofollow" html_options[:rel] << ' nofollow'
else else
html_options.merge!(rel: "nofollow") html_options.merge!(rel: 'nofollow')
end end
else else
html_options = Hash.new html_options = Hash.new
html_options[:rel] = "nofollow" html_options[:rel] = 'nofollow'
end end
end end
......
...@@ -19,4 +19,42 @@ module BlobHelper ...@@ -19,4 +19,42 @@ module BlobHelper
def no_highlight_files def no_highlight_files
%w(credits changelog copying copyright license authors) %w(credits changelog copying copyright license authors)
end end
def edit_blob_link(project, ref, path, options = {})
blob =
begin
project.repository.blob_at(ref, path)
rescue
nil
end
if blob && blob.text?
text = 'Edit'
after = options[:after] || ''
from_mr = options[:from_merge_request_id]
link_opts = {}
link_opts[:from_merge_request_id] = from_mr if from_mr
cls = 'btn btn-small'
if allowed_tree_edit?(project, ref)
link_to text, project_edit_blob_path(project, tree_join(ref, path),
link_opts), class: cls
else
content_tag :span, text, class: cls + ' disabled'
end + after.html_safe
else
''
end
end
def leave_edit_message
"Leave edit mode?\nAll unsaved changes will be lost."
end
def editing_preview_title(filename)
if Gitlab::MarkdownHelper.previewable?(filename)
'Preview'
else
'Preview changes'
end
end
end end
...@@ -175,7 +175,11 @@ module ProjectsHelper ...@@ -175,7 +175,11 @@ module ProjectsHelper
"Issues - " + title "Issues - " + title
end end
elsif current_controller?(:blob) elsif current_controller?(:blob)
"#{@project.path}\/#{@blob.path} at #{@ref} - " + title if current_action?(:new) || current_action?(:create)
"New file at #{@ref}"
elsif @blob
"Edit file #{@blob.path} at #{@ref}"
end
elsif current_controller?(:commits) elsif current_controller?(:commits)
"Commits at #{@ref} - " + title "Commits at #{@ref} - " + title
elsif current_controller?(:merge_requests) elsif current_controller?(:merge_requests)
......
...@@ -64,32 +64,6 @@ module TreeHelper ...@@ -64,32 +64,6 @@ module TreeHelper
::Gitlab::GitAccess.can_push_to_branch?(current_user, project, ref) ::Gitlab::GitAccess.can_push_to_branch?(current_user, project, ref)
end end
def edit_blob_link(project, ref, path, options = {})
blob =
begin
project.repository.blob_at(ref, path)
rescue
nil
end
if blob && blob.text?
text = 'Edit'
after = options[:after] || ''
from_mr = options[:from_merge_request_id]
link_opts = {}
link_opts[:from_merge_request_id] = from_mr if from_mr
cls = 'btn btn-small'
if allowed_tree_edit?(project, ref)
link_to text, project_edit_tree_path(project, tree_join(ref, path),
link_opts), class: cls
else
content_tag :span, text, class: cls + ' disabled'
end + after.html_safe
else
''
end
end
def tree_breadcrumbs(tree, max_links = 2) def tree_breadcrumbs(tree, max_links = 2)
if @path.present? if @path.present?
part_path = "" part_path = ""
...@@ -121,16 +95,4 @@ module TreeHelper ...@@ -121,16 +95,4 @@ module TreeHelper
return tree.name return tree.name
end end
end end
def leave_edit_message
"Leave edit mode?\nAll unsaved changes will be lost."
end
def editing_preview_title(filename)
if Gitlab::MarkdownHelper.previewable?(filename)
'Preview'
else
'Diff'
end
end
end end
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
# merge_requests_enabled :boolean default(TRUE), not null # merge_requests_enabled :boolean default(TRUE), not null
# wiki_enabled :boolean default(TRUE), not null # wiki_enabled :boolean default(TRUE), not null
# namespace_id :integer # namespace_id :integer
# issues_tracker :string(255) default("gitlab"), not null # issues_tracker :string(255) default('gitlab'), not null
# issues_tracker_id :string(255) # issues_tracker_id :string(255)
# snippets_enabled :boolean default(TRUE), not null # snippets_enabled :boolean default(TRUE), not null
# last_activity_at :datetime # last_activity_at :datetime
...@@ -26,8 +26,12 @@ ...@@ -26,8 +26,12 @@
# star_count :integer default(0), not null # star_count :integer default(0), not null
# import_type :string(255) # import_type :string(255)
# import_source :string(255) # import_source :string(255)
# avatar :string(255)
# #
require 'carrierwave/orm/activerecord'
require 'file_size_validator'
class Project < ActiveRecord::Base class Project < ActiveRecord::Base
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
include Gitlab::VisibilityLevel include Gitlab::VisibilityLevel
...@@ -49,8 +53,8 @@ class Project < ActiveRecord::Base ...@@ -49,8 +53,8 @@ class Project < ActiveRecord::Base
attr_accessor :new_default_branch attr_accessor :new_default_branch
# Relations # Relations
belongs_to :creator, foreign_key: "creator_id", class_name: "User" belongs_to :creator, foreign_key: 'creator_id', class_name: 'User'
belongs_to :group, -> { where(type: Group) }, foreign_key: "namespace_id" belongs_to :group, -> { where(type: Group) }, foreign_key: 'namespace_id'
belongs_to :namespace belongs_to :namespace
has_one :last_event, -> {order 'events.created_at DESC'}, class_name: 'Event', foreign_key: 'project_id' has_one :last_event, -> {order 'events.created_at DESC'}, class_name: 'Event', foreign_key: 'project_id'
...@@ -75,19 +79,20 @@ class Project < ActiveRecord::Base ...@@ -75,19 +79,20 @@ class Project < ActiveRecord::Base
has_one :custom_issue_tracker_service, dependent: :destroy has_one :custom_issue_tracker_service, dependent: :destroy
has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id" has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id"
has_one :forked_from_project, through: :forked_project_link has_one :forked_from_project, through: :forked_project_link
# Merge Requests for target project should be removed with it # Merge Requests for target project should be removed with it
has_many :merge_requests, dependent: :destroy, foreign_key: "target_project_id" has_many :merge_requests, dependent: :destroy, foreign_key: 'target_project_id'
# Merge requests from source project should be kept when source project was removed # Merge requests from source project should be kept when source project was removed
has_many :fork_merge_requests, foreign_key: "source_project_id", class_name: MergeRequest has_many :fork_merge_requests, foreign_key: 'source_project_id', class_name: MergeRequest
has_many :issues, -> { order 'issues.state DESC, issues.created_at DESC' }, dependent: :destroy has_many :issues, -> { order 'issues.state DESC, issues.created_at DESC' }, dependent: :destroy
has_many :labels, dependent: :destroy has_many :labels, dependent: :destroy
has_many :services, dependent: :destroy has_many :services, dependent: :destroy
has_many :events, dependent: :destroy has_many :events, dependent: :destroy
has_many :milestones, dependent: :destroy has_many :milestones, dependent: :destroy
has_many :notes, dependent: :destroy has_many :notes, dependent: :destroy
has_many :snippets, dependent: :destroy, class_name: "ProjectSnippet" has_many :snippets, dependent: :destroy, class_name: 'ProjectSnippet'
has_many :hooks, dependent: :destroy, class_name: "ProjectHook" has_many :hooks, dependent: :destroy, class_name: 'ProjectHook'
has_many :protected_branches, dependent: :destroy has_many :protected_branches, dependent: :destroy
has_many :project_members, dependent: :destroy, as: :source, class_name: 'ProjectMember' has_many :project_members, dependent: :destroy, as: :source, class_name: 'ProjectMember'
has_many :users, through: :project_members has_many :users, through: :project_members
...@@ -119,22 +124,27 @@ class Project < ActiveRecord::Base ...@@ -119,22 +124,27 @@ class Project < ActiveRecord::Base
validates_uniqueness_of :name, scope: :namespace_id validates_uniqueness_of :name, scope: :namespace_id
validates_uniqueness_of :path, scope: :namespace_id validates_uniqueness_of :path, scope: :namespace_id
validates :import_url, validates :import_url,
format: { with: URI::regexp(%w(git http https)), message: "should be a valid url" }, format: { with: URI::regexp(%w(git http https)), message: 'should be a valid url' },
if: :import? if: :import?
validates :star_count, numericality: { greater_than_or_equal_to: 0 } validates :star_count, numericality: { greater_than_or_equal_to: 0 }
validate :check_limit, on: :create validate :check_limit, on: :create
validate :avatar_type,
if: ->(project) { project.avatar && project.avatar_changed? }
validates :avatar, file_size: { maximum: 200.kilobytes.to_i }
mount_uploader :avatar, AttachmentUploader
# Scopes # Scopes
scope :without_user, ->(user) { where("projects.id NOT IN (:ids)", ids: user.authorized_projects.map(&:id) ) } scope :without_user, ->(user) { where('projects.id NOT IN (:ids)', ids: user.authorized_projects.map(&:id) ) }
scope :without_team, ->(team) { team.projects.present? ? where("projects.id NOT IN (:ids)", ids: team.projects.map(&:id)) : scoped } scope :without_team, ->(team) { team.projects.present? ? where('projects.id NOT IN (:ids)', ids: team.projects.map(&:id)) : scoped }
scope :not_in_group, ->(group) { where("projects.id NOT IN (:ids)", ids: group.project_ids ) } scope :not_in_group, ->(group) { where('projects.id NOT IN (:ids)', ids: group.project_ids ) }
scope :in_team, ->(team) { where("projects.id IN (:ids)", ids: team.projects.map(&:id)) } scope :in_team, ->(team) { where('projects.id IN (:ids)', ids: team.projects.map(&:id)) }
scope :in_namespace, ->(namespace) { where(namespace_id: namespace.id) } scope :in_namespace, ->(namespace) { where(namespace_id: namespace.id) }
scope :in_group_namespace, -> { joins(:group) } scope :in_group_namespace, -> { joins(:group) }
scope :sorted_by_activity, -> { reorder("projects.last_activity_at DESC") } scope :sorted_by_activity, -> { reorder('projects.last_activity_at DESC') }
scope :sorted_by_stars, -> { reorder("projects.star_count DESC") } scope :sorted_by_stars, -> { reorder('projects.star_count DESC') }
scope :personal, ->(user) { where(namespace_id: user.namespace_id) } scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) } scope :joined, ->(user) { where('namespace_id != ?', user.namespace_id) }
scope :public_only, -> { where(visibility_level: Project::PUBLIC) } scope :public_only, -> { where(visibility_level: Project::PUBLIC) }
scope :public_and_internal_only, -> { where(visibility_level: Project.public_and_internal_levels) } scope :public_and_internal_only, -> { where(visibility_level: Project.public_and_internal_levels) }
scope :non_archived, -> { where(archived: false) } scope :non_archived, -> { where(archived: false) }
...@@ -185,26 +195,26 @@ class Project < ActiveRecord::Base ...@@ -185,26 +195,26 @@ class Project < ActiveRecord::Base
end end
def active def active
joins(:issues, :notes, :merge_requests).order("issues.created_at, notes.created_at, merge_requests.created_at DESC") joins(:issues, :notes, :merge_requests).order('issues.created_at, notes.created_at, merge_requests.created_at DESC')
end end
def search(query) def search(query)
joins(:namespace).where("projects.archived = ?", false). joins(:namespace).where('projects.archived = ?', false).
where("LOWER(projects.name) LIKE :query OR where('LOWER(projects.name) LIKE :query OR
LOWER(projects.path) LIKE :query OR LOWER(projects.path) LIKE :query OR
LOWER(namespaces.name) LIKE :query OR LOWER(namespaces.name) LIKE :query OR
LOWER(projects.description) LIKE :query", LOWER(projects.description) LIKE :query',
query: "%#{query.try(:downcase)}%") query: "%#{query.try(:downcase)}%")
end end
def search_by_title(query) def search_by_title(query)
where("projects.archived = ?", false).where("LOWER(projects.name) LIKE :query", query: "%#{query.downcase}%") where('projects.archived = ?', false).where('LOWER(projects.name) LIKE :query', query: "%#{query.downcase}%")
end end
def find_with_namespace(id) def find_with_namespace(id)
return nil unless id.include?("/") return nil unless id.include?('/')
id = id.split("/") id = id.split('/')
namespace = Namespace.find_by(path: id.first) namespace = Namespace.find_by(path: id.first)
return nil unless namespace return nil unless namespace
...@@ -222,7 +232,7 @@ class Project < ActiveRecord::Base ...@@ -222,7 +232,7 @@ class Project < ActiveRecord::Base
when 'recently_updated' then reorder('projects.updated_at DESC') when 'recently_updated' then reorder('projects.updated_at DESC')
when 'last_updated' then reorder('projects.updated_at ASC') when 'last_updated' then reorder('projects.updated_at ASC')
when 'largest_repository' then reorder('projects.repository_size DESC') when 'largest_repository' then reorder('projects.repository_size DESC')
else reorder("namespaces.path, projects.name ASC") else reorder('namespaces.path, projects.name ASC')
end end
end end
end end
...@@ -272,19 +282,19 @@ class Project < ActiveRecord::Base ...@@ -272,19 +282,19 @@ class Project < ActiveRecord::Base
end end
def to_param def to_param
namespace.path + "/" + path namespace.path + '/' + path
end end
def web_url def web_url
[gitlab_config.url, path_with_namespace].join("/") [gitlab_config.url, path_with_namespace].join('/')
end end
def web_url_without_protocol def web_url_without_protocol
web_url.split("://")[1] web_url.split('://')[1]
end end
def build_commit_note(commit) def build_commit_note(commit)
notes.new(commit_id: commit.id, noteable_type: "Commit") notes.new(commit_id: commit.id, noteable_type: 'Commit')
end end
def last_activity def last_activity
...@@ -357,6 +367,24 @@ class Project < ActiveRecord::Base ...@@ -357,6 +367,24 @@ class Project < ActiveRecord::Base
@ci_service ||= ci_services.select(&:activated?).first @ci_service ||= ci_services.select(&:activated?).first
end end
def avatar_type
unless self.avatar.image?
self.errors.add :avatar, 'only images allowed'
end
end
def avatar_in_git
@avatar_file ||= 'logo.png' if repository.blob_at_branch('master', 'logo.png')
@avatar_file ||= 'logo.jpg' if repository.blob_at_branch('master', 'logo.jpg')
@avatar_file ||= 'logo.gif' if repository.blob_at_branch('master', 'logo.gif')
@avatar_file
end
# For compatibility with old code
def code
path
end
def items_for(entity) def items_for(entity)
case entity case entity
when 'issue' then when 'issue' then
...@@ -379,7 +407,7 @@ class Project < ActiveRecord::Base ...@@ -379,7 +407,7 @@ class Project < ActiveRecord::Base
end end
def team_member_by_name_or_email(name = nil, email = nil) def team_member_by_name_or_email(name = nil, email = nil)
user = users.where("name like ? or email like ?", name, email).first user = users.where('name like ? or email like ?', name, email).first
project_members.where(user: user) if user project_members.where(user: user) if user
end end
...@@ -391,7 +419,7 @@ class Project < ActiveRecord::Base ...@@ -391,7 +419,7 @@ class Project < ActiveRecord::Base
def name_with_namespace def name_with_namespace
@name_with_namespace ||= begin @name_with_namespace ||= begin
if namespace if namespace
namespace.human_name + " / " + name namespace.human_name + ' / ' + name
else else
name name
end end
...@@ -426,7 +454,7 @@ class Project < ActiveRecord::Base ...@@ -426,7 +454,7 @@ class Project < ActiveRecord::Base
def valid_repo? def valid_repo?
repository.exists? repository.exists?
rescue rescue
errors.add(:path, "Invalid repository path") errors.add(:path, 'Invalid repository path')
false false
end end
...@@ -485,7 +513,7 @@ class Project < ActiveRecord::Base ...@@ -485,7 +513,7 @@ class Project < ActiveRecord::Base
end end
def http_url_to_repo def http_url_to_repo
[gitlab_config.url, "/", path_with_namespace, ".git"].join('') [gitlab_config.url, '/', path_with_namespace, '.git'].join('')
end end
# Check if current branch name is marked as protected in the system # Check if current branch name is marked as protected in the system
...@@ -548,6 +576,7 @@ class Project < ActiveRecord::Base ...@@ -548,6 +576,7 @@ class Project < ActiveRecord::Base
# Since we do cache @event we need to reset cache in special cases: # Since we do cache @event we need to reset cache in special cases:
# * when project was moved # * when project was moved
# * when project was renamed # * when project was renamed
# * when the project avatar changes
# Events cache stored like events/23-20130109142513. # Events cache stored like events/23-20130109142513.
# The cache key includes updated_at timestamp. # The cache key includes updated_at timestamp.
# Thus it will automatically generate a new fragment # Thus it will automatically generate a new fragment
...@@ -612,7 +641,7 @@ class Project < ActiveRecord::Base ...@@ -612,7 +641,7 @@ class Project < ActiveRecord::Base
if gitlab_shell.add_repository(path_with_namespace) if gitlab_shell.add_repository(path_with_namespace)
true true
else else
errors.add(:base, "Failed to create repository") errors.add(:base, 'Failed to create repository')
false false
end end
end end
...@@ -625,7 +654,7 @@ class Project < ActiveRecord::Base ...@@ -625,7 +654,7 @@ class Project < ActiveRecord::Base
ProjectWiki.new(self, self.owner).wiki ProjectWiki.new(self, self.owner).wiki
true true
rescue ProjectWiki::CouldNotCreateWikiError => ex rescue ProjectWiki::CouldNotCreateWikiError => ex
errors.add(:base, "Failed create wiki") errors.add(:base, 'Failed create wiki')
false false
end end
end end
...@@ -9,10 +9,6 @@ module Files ...@@ -9,10 +9,6 @@ module Files
return error("You are not allowed to create file in this branch") return error("You are not allowed to create file in this branch")
end end
unless repository.branch_names.include?(ref)
return error("You can only create files if you are on top of a branch")
end
file_name = File.basename(path) file_name = File.basename(path)
file_path = path file_path = path
...@@ -23,12 +19,21 @@ module Files ...@@ -23,12 +19,21 @@ module Files
) )
end end
blob = repository.blob_at_branch(ref, file_path) if project.empty_repo?
# everything is ok because repo does not have a commits yet
else
unless repository.branch_names.include?(ref)
return error("You can only create files if you are on top of a branch")
end
if blob blob = repository.blob_at_branch(ref, file_path)
return error("Your changes could not be committed, because file with such name exists")
if blob
return error("Your changes could not be committed, because file with such name exists")
end
end end
new_file_action = Gitlab::Satellite::NewFileAction.new(current_user, project, ref, file_path) new_file_action = Gitlab::Satellite::NewFileAction.new(current_user, project, ref, file_path)
created_successfully = new_file_action.commit!( created_successfully = new_file_action.commit!(
params[:content], params[:content],
......
...@@ -2,9 +2,9 @@ module Issues ...@@ -2,9 +2,9 @@ module Issues
class CloseService < Issues::BaseService class CloseService < Issues::BaseService
def execute(issue, commit = nil) def execute(issue, commit = nil)
if issue.close if issue.close
notification_service.close_issue(issue, current_user)
event_service.close_issue(issue, current_user) event_service.close_issue(issue, current_user)
create_note(issue, commit) create_note(issue, commit)
notification_service.close_issue(issue, current_user)
execute_hooks(issue, 'close') execute_hooks(issue, 'close')
end end
......
...@@ -23,8 +23,8 @@ module Issues ...@@ -23,8 +23,8 @@ module Issues
end end
if issue.previous_changes.include?('assignee_id') if issue.previous_changes.include?('assignee_id')
notification_service.reassigned_issue(issue, current_user)
create_assignee_note(issue) create_assignee_note(issue)
notification_service.reassigned_issue(issue, current_user)
end end
issue.notice_added_references(issue.project, current_user) issue.notice_added_references(issue.project, current_user)
......
...@@ -11,9 +11,9 @@ module MergeRequests ...@@ -11,9 +11,9 @@ module MergeRequests
if Gitlab::Satellite::MergeAction.new(current_user, merge_request).merge!(commit_message) if Gitlab::Satellite::MergeAction.new(current_user, merge_request).merge!(commit_message)
merge_request.merge merge_request.merge
notification_service.merge_mr(merge_request, current_user)
create_merge_event(merge_request, current_user) create_merge_event(merge_request, current_user)
create_note(merge_request) create_note(merge_request)
notification_service.merge_mr(merge_request, current_user)
execute_hooks(merge_request) execute_hooks(merge_request)
true true
......
...@@ -7,8 +7,8 @@ module MergeRequests ...@@ -7,8 +7,8 @@ module MergeRequests
if merge_request.close if merge_request.close
event_service.close_mr(merge_request, current_user) event_service.close_mr(merge_request, current_user)
notification_service.close_mr(merge_request, current_user)
create_note(merge_request) create_note(merge_request)
notification_service.close_mr(merge_request, current_user)
execute_hooks(merge_request, 'close') execute_hooks(merge_request, 'close')
end end
......
...@@ -9,9 +9,9 @@ module MergeRequests ...@@ -9,9 +9,9 @@ module MergeRequests
def execute(merge_request, commit_message) def execute(merge_request, commit_message)
merge_request.merge merge_request.merge
notification_service.merge_mr(merge_request, current_user)
create_merge_event(merge_request, current_user) create_merge_event(merge_request, current_user)
create_note(merge_request) create_note(merge_request)
notification_service.merge_mr(merge_request, current_user)
execute_hooks(merge_request, 'merge') execute_hooks(merge_request, 'merge')
true true
......
...@@ -3,8 +3,8 @@ module MergeRequests ...@@ -3,8 +3,8 @@ module MergeRequests
def execute(merge_request) def execute(merge_request)
if merge_request.reopen if merge_request.reopen
event_service.reopen_mr(merge_request, current_user) event_service.reopen_mr(merge_request, current_user)
notification_service.reopen_mr(merge_request, current_user)
create_note(merge_request) create_note(merge_request)
notification_service.reopen_mr(merge_request, current_user)
execute_hooks(merge_request, 'reopen') execute_hooks(merge_request, 'reopen')
merge_request.reload_code merge_request.reload_code
merge_request.mark_as_unchecked merge_request.mark_as_unchecked
......
...@@ -33,8 +33,8 @@ module MergeRequests ...@@ -33,8 +33,8 @@ module MergeRequests
end end
if merge_request.previous_changes.include?('assignee_id') if merge_request.previous_changes.include?('assignee_id')
notification_service.reassigned_merge_request(merge_request, current_user)
create_assignee_note(merge_request) create_assignee_note(merge_request)
notification_service.reassigned_merge_request(merge_request, current_user)
end end
merge_request.notice_added_references(merge_request.project, current_user) merge_request.notice_added_references(merge_request.project, current_user)
......
...@@ -314,15 +314,7 @@ class NotificationService ...@@ -314,15 +314,7 @@ class NotificationService
end end
def new_resource_email(target, project, method) def new_resource_email(target, project, method)
if target.respond_to?(:participants) recipients = build_recipients(target, project)
recipients = target.participants
else
recipients = []
end
recipients = reject_muted_users(recipients, project)
recipients = reject_mention_users(recipients, project)
recipients = recipients.concat(project_watchers(project)).uniq
recipients.delete(target.author) recipients.delete(target.author)
recipients.each do |recipient| recipients.each do |recipient|
...@@ -331,9 +323,7 @@ class NotificationService ...@@ -331,9 +323,7 @@ class NotificationService
end end
def close_resource_email(target, project, current_user, method) def close_resource_email(target, project, current_user, method)
recipients = reject_muted_users([target.author, target.assignee], project) recipients = build_recipients(target, project)
recipients = reject_mention_users(recipients, project)
recipients = recipients.concat(project_watchers(project)).uniq
recipients.delete(current_user) recipients.delete(current_user)
recipients.each do |recipient| recipients.each do |recipient|
...@@ -343,17 +333,7 @@ class NotificationService ...@@ -343,17 +333,7 @@ class NotificationService
def reassign_resource_email(target, project, current_user, method) def reassign_resource_email(target, project, current_user, method)
assignee_id_was = previous_record(target, "assignee_id") assignee_id_was = previous_record(target, "assignee_id")
recipients = build_recipients(target, project)
recipients = User.where(id: [target.assignee_id, assignee_id_was])
# Add watchers to email list
recipients = recipients.concat(project_watchers(project))
# reject users with disabled notifications
recipients = reject_muted_users(recipients, project)
recipients = reject_mention_users(recipients, project)
# Reject me from recipients if I reassign an item
recipients.delete(current_user) recipients.delete(current_user)
recipients.each do |recipient| recipients.each do |recipient|
...@@ -362,9 +342,7 @@ class NotificationService ...@@ -362,9 +342,7 @@ class NotificationService
end end
def reopen_resource_email(target, project, current_user, method, status) def reopen_resource_email(target, project, current_user, method, status)
recipients = reject_muted_users([target.author, target.assignee], project) recipients = build_recipients(target, project)
recipients = reject_mention_users(recipients, project)
recipients = recipients.concat(project_watchers(project)).uniq
recipients.delete(current_user) recipients.delete(current_user)
recipients.each do |recipient| recipients.each do |recipient|
...@@ -372,6 +350,20 @@ class NotificationService ...@@ -372,6 +350,20 @@ class NotificationService
end end
end end
def build_recipients(target, project)
recipients =
if target.respond_to?(:participants)
target.participants
else
[target.author, target.assignee]
end
recipients = reject_muted_users(recipients, project)
recipients = reject_mention_users(recipients, project)
recipients = recipients.concat(project_watchers(project)).uniq
recipients
end
def mailer def mailer
Notify.delay Notify.delay
end end
......
...@@ -5,11 +5,11 @@ module Projects ...@@ -5,11 +5,11 @@ module Projects
end end
def issues def issues
@project.issues.opened.select([:iid, :title, :description]) @project.issues.opened.select([:iid, :title])
end end
def merge_requests def merge_requests
@project.merge_requests.opened.select([:iid, :title, :description]) @project.merge_requests.opened.select([:iid, :title])
end end
end end
end end
...@@ -14,6 +14,9 @@ module Projects ...@@ -14,6 +14,9 @@ module Projects
project.name = @from_project.name project.name = @from_project.name
project.path = @from_project.path project.path = @from_project.path
project.creator = @current_user project.creator = @current_user
if @from_project.avatar.present? && @from_project.avatar.image?
project.avatar = @from_project.avatar
end
if namespace = @params[:namespace] if namespace = @params[:namespace]
project.namespace = namespace project.namespace = namespace
...@@ -39,16 +42,16 @@ module Projects ...@@ -39,16 +42,16 @@ module Projects
end end
#Now fork the repo #Now fork the repo
unless gitlab_shell.fork_repository(@from_project.path_with_namespace, project.namespace.path) unless gitlab_shell.fork_repository(@from_project.path_with_namespace, project.namespace.path)
raise "forking failed in gitlab-shell" raise 'forking failed in gitlab-shell'
end end
project.ensure_satellite_exists project.ensure_satellite_exists
end end
rescue => ex rescue => ex
project.errors.add(:base, "Fork transaction failed.") project.errors.add(:base, 'Fork transaction failed.')
project.destroy project.destroy
end end
else else
project.errors.add(:base, "Invalid fork destination") project.errors.add(:base, 'Invalid fork destination')
end end
project project
......
= link_to project_path(project), class: dom_class(project) do = link_to project_path(project), class: dom_class(project) do
.dash-project-access-icon .dash-project-access-icon
= visibility_level_icon(project.visibility_level) = visibility_level_icon(project.visibility_level)
.dash-project-avatar
= project_icon(project.to_param, alt: '', class: 'avatar s24')
%span.str-truncated %span.str-truncated
%span.namespace-name %span.namespace-name
- if project.namespace - if project.namespace
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
.input-group .input-group
= search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'dash-filter form-control' = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'dash-filter form-control'
- if current_user.can_create_project? - if current_user.can_create_project?
.input-group-addon .input-group-addon.dash-new-project
= link_to new_project_path, class: "" do = link_to new_project_path do
%strong New project %strong New project
%ul.well-list.dash-list %ul.well-list.dash-list
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
- @projects.each do |project| - @projects.each do |project|
%li.my-project-row %li.my-project-row
%h4.project-title %h4.project-title
.project-avatar
= project_icon(project.to_param, alt: '', class: 'avatar s60')
.project-access-icon .project-access-icon
= visibility_level_icon(project.visibility_level) = visibility_level_icon(project.visibility_level)
= link_to project_path(project), class: dom_class(project) do = link_to project_path(project), class: dom_class(project) do
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
= link_to project_path(project), class: dom_class(project) do = link_to project_path(project), class: dom_class(project) do
.dash-project-access-icon .dash-project-access-icon
= visibility_level_icon(project.visibility_level) = visibility_level_icon(project.visibility_level)
.dash-project-avatar
= project_icon(project.to_param, alt: '', class: 'avatar s24')
%span.str-truncated %span.str-truncated
%span.project-name %span.project-name
= project.name = project.name
......
- empty_repo = @project.empty_repo? - empty_repo = @project.empty_repo?
.project-home-panel{:class => ("empty-project" if empty_repo)} .project-home-panel{:class => ("empty-project" if empty_repo)}
.project-identicon-holder
= project_icon(@project.to_param, alt: '', class: 'avatar')
.project-home-row .project-home-row
.project-home-desc .project-home-desc
- if @project.description.present? - if @project.description.present?
......
.file-editor .file-editor
%ul.nav.nav-tabs.js-edit-mode %ul.nav.nav-tabs.js-edit-mode
%li.active %li.active
= link_to 'Edit', '#editor' = link_to '#editor' do
%i.fa.fa-edit
Edit file
%li %li
= link_to editing_preview_title(@blob.name), '#preview', 'data-preview-url' => preview_project_edit_tree_path(@project, @id) = link_to '#preview', 'data-preview-url' => project_preview_blob_path(@project, @id) do
%i.fa.fa-eye
= editing_preview_title(@blob.name)
= form_tag(project_edit_tree_path(@project, @id), method: :put, class: "form-horizontal") do = form_tag(project_update_blob_path(@project, @id), method: :put, class: "form-horizontal") do
= render 'projects/blob_editor', ref: @ref, path: @path, blob_data: @blob.data = render 'projects/blob_editor', ref: @ref, path: @path, blob_data: @blob.data
= render 'shared/commit_message_container', params: params, = render 'shared/commit_message_container', params: params,
placeholder: "Update #{@blob.name}" placeholder: "Update #{@blob.name}"
......
%h3.page-title New file %h3.page-title New file
%hr %hr
.file-editor .file-editor
= form_tag(project_new_tree_path(@project, @id), method: :put, class: 'form-horizontal form-new-file') do = form_tag(project_create_blob_path(@project, @id), method: :post, class: 'form-horizontal form-new-file') do
.form-group.commit_message-group .form-group.commit_message-group
= label_tag 'file_name', class: 'control-label' do = label_tag 'file_name', class: 'control-label' do
File name File name
......
...@@ -7,7 +7,8 @@ ...@@ -7,7 +7,8 @@
%p.light Some settings, such as "Transfer Project", are hidden inside the danger area below. %p.light Some settings, such as "Transfer Project", are hidden inside the danger area below.
%hr %hr
.panel-body .panel-body
= form_for @project, remote: true, html: { class: "edit_project form-horizontal" } do |f| = form_for @project, remote: true, html: { multipart: true, class: "edit_project form-horizontal" }, authenticity_token: true do |f|
%fieldset %fieldset
.form-group.project_name_holder .form-group.project_name_holder
= f.label :name, class: 'control-label' do = f.label :name, class: 'control-label' do
...@@ -71,6 +72,32 @@ ...@@ -71,6 +72,32 @@
= f.check_box :snippets_enabled = f.check_box :snippets_enabled
%span.descr Share code pastes with others out of git repository %span.descr Share code pastes with others out of git repository
%fieldset.features
%legend
Project avatar:
.form-group
.col-sm-2
.col-sm-10
- if @project.avatar?
= project_icon(@project.to_param, alt: '', class: 'avatar s160')
%p.light
- if @project.avatar_in_git
Project avatar in repository: #{ @project.avatar_in_git }
%p.light
- if @project.avatar?
You can change your project avatar here
- else
You can upload an project avatar here
%a.choose-btn.btn.btn-small.js-choose-project-avatar-button
%i.icon-paper-clip
%span Choose File ...
&nbsp;
%span.file_name.js-avatar-filename File name...
= f.file_field :avatar, class: "js-project-avatar-input hidden"
.light The maximum file size allowed is 200KB.
- if @project.avatar?
%hr
= link_to 'Remove avatar', project_avatar_path(@project), data: { confirm: "Project avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-small remove-avatar"
.form-actions .form-actions
= f.submit 'Save changes', class: "btn btn-save" = f.submit 'Save changes', class: "btn btn-save"
......
- if current_user && can?(current_user, :download_code, @project)
= render 'shared/no_ssh'
= render "home_panel" = render "home_panel"
.center.well
%h3
The repository for this project is empty
%p.lead
You can
= link_to project_new_blob_path(@project, 'master'), class: 'btn btn-new btn-lg' do
add a file
&nbsp;or push it via command line.
%h4
%strong Command line instructions
%div.git-empty %div.git-empty
%fieldset %fieldset
%legend Git global setup %legend Git global setup
......
%h3.page-title Project services %h3.page-title Project services
%p.light Project services allow you to integrate GitLab with other applications %p.light Project services allow you to integrate GitLab with other applications
%hr
%ul.bordered-list %table.table
%thead
%tr
%th
%th Service
%th Desription
%th Last edit
- @services.sort_by(&:title).each do |service| - @services.sort_by(&:title).each do |service|
%li %tr
%h4 %td
= boolean_to_icon service.activated?
%td
= link_to edit_project_service_path(@project, service.to_param) do = link_to edit_project_service_path(@project, service.to_param) do
= service.title %strong= service.title
.pull-right %td
= boolean_to_icon service.activated? = service.description
%p= service.description %td.light
= time_ago_in_words service.updated_at
ago
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
= link_to title, '#' = link_to title, '#'
- if current_user && can_push_branch?(@project, @ref) - if current_user && can_push_branch?(@project, @ref)
%li %li
= link_to project_new_tree_path(@project, @id), title: 'New file', id: 'new-file-link' do = link_to project_new_blob_path(@project, @id), title: 'New file', id: 'new-file-link' do
%small %small
%i.fa.fa-plus %i.fa.fa-plus
......
.clearfix .clearfix
- groups.each do |group| - groups.each do |group|
= link_to group, class: 'profile-groups-avatars', title: group.name do = link_to group, class: 'profile-groups-avatars', title: group.name do
= image_tag group_icon(group.path), class: 'avatar s40' = image_tag group_icon(group.path), class: 'avatar avatar-inline s40'
...@@ -145,7 +145,8 @@ Devise.setup do |config| ...@@ -145,7 +145,8 @@ Devise.setup do |config|
# Time interval you can reset your password with a reset password key. # Time interval you can reset your password with a reset password key.
# Don't put a too small interval or your users won't have the time to # Don't put a too small interval or your users won't have the time to
# change their passwords. # change their passwords.
config.reset_password_within = 2.hours # When someone else invites you to GitLab this time is also used so it should be pretty long.
config.reset_password_within = 2.days
# ==> Configuration for :encryptable # ==> Configuration for :encryptable
# Allow you to use another encryption algorithm besides bcrypt (default). You can use # Allow you to use another encryption algorithm besides bcrypt (default). You can use
......
...@@ -10,8 +10,8 @@ Gitlab::Application.routes.draw do ...@@ -10,8 +10,8 @@ Gitlab::Application.routes.draw do
# #
# Search # Search
# #
get 'search' => "search#show" get 'search' => 'search#show'
get 'search/autocomplete' => "search#autocomplete", as: :search_autocomplete get 'search/autocomplete' => 'search#autocomplete', as: :search_autocomplete
# API # API
API::API.logger Rails.logger API::API.logger Rails.logger
...@@ -20,9 +20,9 @@ Gitlab::Application.routes.draw do ...@@ -20,9 +20,9 @@ Gitlab::Application.routes.draw do
# Get all keys of user # Get all keys of user
get ':username.keys' => 'profiles/keys#get_keys' , constraints: { username: /.*/ } get ':username.keys' => 'profiles/keys#get_keys' , constraints: { username: /.*/ }
constraint = lambda { |request| request.env["warden"].authenticate? and request.env['warden'].user.admin? } constraint = lambda { |request| request.env['warden'].authenticate? and request.env['warden'].user.admin? }
constraints constraint do constraints constraint do
mount Sidekiq::Web, at: "/admin/sidekiq", as: :sidekiq mount Sidekiq::Web, at: '/admin/sidekiq', as: :sidekiq
end end
# Enable Grack support # Enable Grack support
...@@ -46,10 +46,10 @@ Gitlab::Application.routes.draw do ...@@ -46,10 +46,10 @@ Gitlab::Application.routes.draw do
# #
resources :snippets do resources :snippets do
member do member do
get "raw" get 'raw'
end end
end end
get "/s/:username" => "snippets#user_index", as: :user_snippets, constraints: { username: /.*/ } get '/s/:username' => 'snippets#user_index', as: :user_snippets, constraints: { username: /.*/ }
# #
# Github importer area # Github importer area
...@@ -61,7 +61,7 @@ Gitlab::Application.routes.draw do ...@@ -61,7 +61,7 @@ Gitlab::Application.routes.draw do
end end
# #
# Explroe area # Explore area
# #
namespace :explore do namespace :explore do
resources :projects, only: [:index] do resources :projects, only: [:index] do
...@@ -72,12 +72,12 @@ Gitlab::Application.routes.draw do ...@@ -72,12 +72,12 @@ Gitlab::Application.routes.draw do
end end
resources :groups, only: [:index] resources :groups, only: [:index]
root to: "projects#trending" root to: 'projects#trending'
end end
# Compatibility with old routing # Compatibility with old routing
get 'public' => "explore/projects#index" get 'public' => 'explore/projects#index'
get 'public/projects' => "explore/projects#index" get 'public/projects' => 'explore/projects#index'
# #
# Attachments serving # Attachments serving
...@@ -122,7 +122,7 @@ Gitlab::Application.routes.draw do ...@@ -122,7 +122,7 @@ Gitlab::Application.routes.draw do
resource :application_settings, only: [:show, :update] resource :application_settings, only: [:show, :update]
root to: "dashboard#index" root to: 'dashboard#index'
end end
# #
...@@ -163,7 +163,7 @@ Gitlab::Application.routes.draw do ...@@ -163,7 +163,7 @@ Gitlab::Application.routes.draw do
# #
# Dashboard Area # Dashboard Area
# #
resource :dashboard, controller: "dashboard", only: [:show] do resource :dashboard, controller: 'dashboard', only: [:show] do
member do member do
get :projects get :projects
get :issues get :issues
...@@ -194,12 +194,12 @@ Gitlab::Application.routes.draw do ...@@ -194,12 +194,12 @@ Gitlab::Application.routes.draw do
devise_for :users, controllers: { omniauth_callbacks: :omniauth_callbacks, registrations: :registrations , passwords: :passwords, sessions: :sessions, confirmations: :confirmations } devise_for :users, controllers: { omniauth_callbacks: :omniauth_callbacks, registrations: :registrations , passwords: :passwords, sessions: :sessions, confirmations: :confirmations }
devise_scope :user do devise_scope :user do
get "/users/auth/:provider/omniauth_error" => "omniauth_callbacks#omniauth_error", as: :omniauth_error get '/users/auth/:provider/omniauth_error' => 'omniauth_callbacks#omniauth_error', as: :omniauth_error
end end
# #
# Project Area # Project Area
# #
resources :projects, constraints: { id: /[a-zA-Z.0-9_\-]+\/[a-zA-Z.0-9_\-]+/ }, except: [:new, :create, :index], path: "/" do resources :projects, constraints: { id: /[a-zA-Z.0-9_\-]+\/[a-zA-Z.0-9_\-]+/ }, except: [:new, :create, :index], path: '/' do
member do member do
put :transfer put :transfer
post :archive post :archive
...@@ -211,16 +211,20 @@ Gitlab::Application.routes.draw do ...@@ -211,16 +211,20 @@ Gitlab::Application.routes.draw do
end end
scope module: :projects do scope module: :projects do
# Blob routes:
get '/new/:id', to: 'blob#new', constraints: {id: /.+/}, as: 'new_blob'
post '/create/:id', to: 'blob#create', constraints: {id: /.+/}, as: 'create_blob'
get '/edit/:id', to: 'blob#edit', constraints: {id: /.+/}, as: 'edit_blob'
put '/update/:id', to: 'blob#update', constraints: {id: /.+/}, as: 'update_blob'
post '/preview/:id', to: 'blob#preview', constraints: {id: /.+/}, as: 'preview_blob'
resources :blob, only: [:show, :destroy], constraints: { id: /.+/, format: false } do resources :blob, only: [:show, :destroy], constraints: { id: /.+/, format: false } do
get :diff, on: :member get :diff, on: :member
end end
resources :raw, only: [:show], constraints: {id: /.+/} resources :raw, only: [:show], constraints: {id: /.+/}
resources :tree, only: [:show], constraints: {id: /.+/, format: /(html|js)/ } resources :tree, only: [:show], constraints: {id: /.+/, format: /(html|js)/ }
resources :edit_tree, only: [:show, :update], constraints: { id: /.+/ }, path: 'edit' do resource :avatar, only: [:show, :destroy]
# Cannot be GET to differentiate from GET paths that end in preview.
post :preview, on: :member
end
resources :new_tree, only: [:show, :update], constraints: {id: /.+/}, path: 'new'
resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/} resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/}
resources :commits, only: [:show], constraints: {id: /(?:[^.]|\.(?!atom$))+/, format: /atom/} resources :commits, only: [:show], constraints: {id: /(?:[^.]|\.(?!atom$))+/, format: /atom/}
resources :compare, only: [:index, :create] resources :compare, only: [:index, :create]
...@@ -237,7 +241,7 @@ Gitlab::Application.routes.draw do ...@@ -237,7 +241,7 @@ Gitlab::Application.routes.draw do
resources :snippets, constraints: {id: /\d+/} do resources :snippets, constraints: {id: /\d+/} do
member do member do
get "raw" get 'raw'
end end
end end
...@@ -249,7 +253,7 @@ Gitlab::Application.routes.draw do ...@@ -249,7 +253,7 @@ Gitlab::Application.routes.draw do
end end
member do member do
get "history" get 'history'
end end
end end
...@@ -258,7 +262,7 @@ Gitlab::Application.routes.draw do ...@@ -258,7 +262,7 @@ Gitlab::Application.routes.draw do
resource :repository, only: [:show, :create] do resource :repository, only: [:show, :create] do
member do member do
get "archive", constraints: { format: Gitlab::Regex.archive_formats_regex } get 'archive', constraints: { format: Gitlab::Regex.archive_formats_regex }
end end
end end
...@@ -281,13 +285,13 @@ Gitlab::Application.routes.draw do ...@@ -281,13 +285,13 @@ Gitlab::Application.routes.draw do
resources :refs, only: [] do resources :refs, only: [] do
collection do collection do
get "switch" get 'switch'
end end
member do member do
# tree viewer logs # tree viewer logs
get "logs_tree", constraints: { id: Gitlab::Regex.git_reference_regex } get 'logs_tree', constraints: { id: Gitlab::Regex.git_reference_regex }
get "logs_tree/:path" => "refs#logs_tree", get 'logs_tree/:path' => 'refs#logs_tree',
as: :logs_file, as: :logs_file,
constraints: { constraints: {
id: Gitlab::Regex.git_reference_regex, id: Gitlab::Regex.git_reference_regex,
...@@ -353,10 +357,11 @@ Gitlab::Application.routes.draw do ...@@ -353,10 +357,11 @@ Gitlab::Application.routes.draw do
delete :delete_attachment delete :delete_attachment
end end
end end
end end
end end
get ':id' => "namespaces#show", constraints: {id: /(?:[^.]|\.(?!atom$))+/, format: /atom/} get ':id' => 'namespaces#show', constraints: {id: /(?:[^.]|\.(?!atom$))+/, format: /atom/}
root to: "dashboard#show" root to: 'dashboard#show'
end end
class AddAvatarToProjects < ActiveRecord::Migration
def change
add_column :projects, :avatar, :string
end
end
...@@ -327,6 +327,7 @@ ActiveRecord::Schema.define(version: 20150116234544) do ...@@ -327,6 +327,7 @@ ActiveRecord::Schema.define(version: 20150116234544) do
t.integer "star_count", default: 0, null: false t.integer "star_count", default: 0, null: false
t.string "import_type" t.string "import_type"
t.string "import_source" t.string "import_source"
t.string "avatar"
end end
add_index "projects", ["creator_id"], name: "index_projects_on_creator_id", using: :btree add_index "projects", ["creator_id"], name: "index_projects_on_creator_id", using: :btree
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
- [Public access](public_access/public_access.md) Learn how you can allow public and internal access to projects. - [Public access](public_access/public_access.md) Learn how you can allow public and internal access to projects.
- [SSH](ssh/README.md) Setup your ssh keys and deploy keys for secure access to your projects. - [SSH](ssh/README.md) Setup your ssh keys and deploy keys for secure access to your projects.
- [Web hooks](web_hooks/web_hooks.md) Let GitLab notify you when new code has been pushed to your project. - [Web hooks](web_hooks/web_hooks.md) Let GitLab notify you when new code has been pushed to your project.
- [Workflow](workflow/README.md) Learn how to get the maximum out of GitLab. - [Workflow](workflow/README.md) Using GitLab functionality and importing projects from GitHub and SVN.
## Administrator documentation ## Administrator documentation
......
...@@ -322,6 +322,31 @@ Parameters: ...@@ -322,6 +322,31 @@ Parameters:
- `title` (required) - new SSH Key's title - `title` (required) - new SSH Key's title
- `key` (required) - new SSH key - `key` (required) - new SSH key
```json
{
"created_at": "2015-01-21T17:44:33.512Z",
"key": "ssh-dss AAAAB3NzaC1kc3MAAACBAMLrhYgI3atfrSD6KDas1b/3n6R/HP+bLaHHX6oh+L1vg31mdUqK0Ac/NjZoQunavoyzqdPYhFz9zzOezCrZKjuJDS3NRK9rspvjgM0xYR4d47oNZbdZbwkI4cTv/gcMlquRy0OvpfIvJtjtaJWMwTLtM5VhRusRuUlpH99UUVeXAAAAFQCVyX+92hBEjInEKL0v13c/egDCTQAAAIEAvFdWGq0ccOPbw4f/F8LpZqvWDydAcpXHV3thwb7WkFfppvm4SZte0zds1FJ+Hr8Xzzc5zMHe6J4Nlay/rP4ewmIW7iFKNBEYb/yWa+ceLrs+TfR672TaAgO6o7iSRofEq5YLdwgrwkMmIawa21FrZ2D9SPao/IwvENzk/xcHu7YAAACAQFXQH6HQnxOrw4dqf0NqeKy1tfIPxYYUZhPJfo9O0AmBW2S36pD2l14kS89fvz6Y1g8gN/FwFnRncMzlLY/hX70FSc/3hKBSbH6C6j8hwlgFKfizav21eS358JJz93leOakJZnGb8XlWvz1UJbwCsnR2VEY8Dz90uIk1l/UqHkA= loic@call",
"title": "ABC",
"id": 4
}
```
Will return created key with status `201 Created` on success. If an
error occurs a `400 Bad Request` is returned with a message explaining the error:
```json
{
"message": {
"fingerprint": [
"has already been taken"
],
"key": [
"has already been taken"
]
}
}
```
## Add SSH key for user ## Add SSH key for user
Create new key owned by specified user. Available only for admin Create new key owned by specified user. Available only for admin
......
...@@ -18,4 +18,21 @@ Use the code below to show your public key. ...@@ -18,4 +18,21 @@ Use the code below to show your public key.
cat ~/.ssh/id_rsa.pub cat ~/.ssh/id_rsa.pub
``` ```
Copy-paste the key to the 'My SSH Keys' section under the 'SSH' tab in your user profile. Please copy the complete key starting with `ssh-` and ending with your username and host. Copy-paste the key to the 'My SSH Keys' section under the 'SSH' tab in your user profile. Please copy the complete key starting with `ssh-` and ending with your username and host.
Use code below to copy your public key to the clipboard. Depending on your OS you'll need to use a different command:
**Windows:**
```bash
clip < ~/.ssh/id_rsa.pub
```
**Mac:**
```bash
pbcopy < ~/.ssh/id_rsa.pub
```
**Linux (requires xclip):**
```bash
xclip -sel clip < ~/.ssh/id_rsa.pub
```
# Workflow # Workflow
- [Workflow](workflow.md) - [Feature branch workflow](workflow.md)
- [Project Features](project_features.md) - [Project Features](project_features.md)
- [Authorization for merge requests](authorization_for_merge_requests.md) - [Authorization for merge requests](authorization_for_merge_requests.md)
- [Groups](groups.md) - [Groups](groups.md)
......
# Workflow # Feature branch workflow
1. Clone project: 1. Clone project:
......
...@@ -5,6 +5,19 @@ Feature: Project ...@@ -5,6 +5,19 @@ Feature: Project
And project "Shop" has push event And project "Shop" has push event
And I visit project "Shop" page And I visit project "Shop" page
Scenario: I edit the project avatar
Given I visit edit project "Shop" page
When I change the project avatar
And I should see new project avatar
And I should see the "Remove avatar" button
Scenario: I remove the project avatar
Given I visit edit project "Shop" page
And I have an project avatar
When I remove my project avatar
Then I should see the default project avatar
And I should not see the "Remove avatar" button
@javascript @javascript
Scenario: I should see project activity Scenario: I should see project activity
When I visit project "Shop" page When I visit project "Shop" page
......
...@@ -17,17 +17,58 @@ class Spinach::Features::Project < Spinach::FeatureSteps ...@@ -17,17 +17,58 @@ class Spinach::Features::Project < Spinach::FeatureSteps
end end
step 'change project path settings' do step 'change project path settings' do
fill_in "project_path", with: "new-path" fill_in 'project_path', with: 'new-path'
click_button "Rename" click_button 'Rename'
end end
step 'I should see project with new path settings' do step 'I should see project with new path settings' do
project.path.should == "new-path" project.path.should == 'new-path'
end
step 'I change the project avatar' do
attach_file(
:project_avatar,
File.join(Rails.root, 'public', 'gitlab_logo.png')
)
click_button 'Save changes'
@project.reload
end
step 'I should see new project avatar' do
@project.avatar.should be_instance_of AttachmentUploader
url = @project.avatar.url
url.should == "/uploads/project/avatar/#{ @project.id }/gitlab_logo.png"
end
step 'I should see the "Remove avatar" button' do
page.should have_link('Remove avatar')
end
step 'I have an project avatar' do
attach_file(
:project_avatar,
File.join(Rails.root, 'public', 'gitlab_logo.png')
)
click_button 'Save changes'
@project.reload
end
step 'I remove my project avatar' do
click_link 'Remove avatar'
@project.reload
end
step 'I should see the default project avatar' do
@project.avatar?.should be_false
end
step 'I should not see the "Remove avatar" button' do
page.should_not have_link('Remove avatar')
end end
step 'I should see project "Shop" version' do step 'I should see project "Shop" version' do
within '.project-side' do within '.project-side' do
page.should have_content "Version: 6.7.0.pre" page.should have_content 'Version: 6.7.0.pre'
end end
end end
...@@ -45,12 +86,12 @@ class Spinach::Features::Project < Spinach::FeatureSteps ...@@ -45,12 +86,12 @@ class Spinach::Features::Project < Spinach::FeatureSteps
end end
step 'I should see project "Forum" README' do step 'I should see project "Forum" README' do
page.should have_link "README.md" page.should have_link 'README.md'
page.should have_content "Sample repo for testing gitlab features" page.should have_content 'Sample repo for testing gitlab features'
end end
step 'I should see project "Shop" README' do step 'I should see project "Shop" README' do
page.should have_link "README.md" page.should have_link 'README.md'
page.should have_content "testme" page.should have_content 'testme'
end end
end end
...@@ -78,7 +78,7 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps ...@@ -78,7 +78,7 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
end end
step 'I click link "Diff"' do step 'I click link "Diff"' do
click_link 'Diff' click_link 'Preview changes'
end end
step 'I click on "Commit Changes"' do step 'I click on "Commit Changes"' do
......
...@@ -284,11 +284,11 @@ module SharedPaths ...@@ -284,11 +284,11 @@ module SharedPaths
end end
step 'I am on the new file page' do step 'I am on the new file page' do
current_path.should eq(project_new_tree_path(@project, root_ref)) current_path.should eq(project_create_blob_path(@project, root_ref))
end end
step 'I am on the ".gitignore" edit file page' do step 'I am on the ".gitignore" edit file page' do
current_path.should eq(project_edit_tree_path( current_path.should eq(project_edit_blob_path(
@project, File.join(root_ref, '.gitignore'))) @project, File.join(root_ref, '.gitignore')))
end end
......
# Module providing methods for dealing with separating a tree-ish string and a # Module providing methods for dealing with separating a tree-ish string and a
# file path string when combined in a request parameter # file path string when combined in a request parameter
module ExtractsPath module ExtractsPath
extend ActiveSupport::Concern
# Raised when given an invalid file path # Raised when given an invalid file path
class InvalidPathError < StandardError; end class InvalidPathError < StandardError; end
included do
if respond_to?(:before_filter)
before_filter :assign_ref_vars
end
end
# Given a string containing both a Git tree-ish, such as a branch or tag, and # Given a string containing both a Git tree-ish, such as a branch or tag, and
# a filesystem path joined by forward slashes, attempts to separate the two. # a filesystem path joined by forward slashes, attempts to separate the two.
# #
......
...@@ -14,7 +14,14 @@ module Gitlab ...@@ -14,7 +14,14 @@ module Gitlab
prepare_satellite!(repo) prepare_satellite!(repo)
# create target branch in satellite at the corresponding commit from bare repo # create target branch in satellite at the corresponding commit from bare repo
repo.git.checkout({raise: true, timeout: true, b: true}, ref, "origin/#{ref}") current_ref =
if repo.commits.any?
repo.git.checkout({raise: true, timeout: true, b: true}, ref, "origin/#{ref}")
ref
else
# skip this step if we want to add first file to empty repo
Satellite::PARKING_BRANCH
end
file_path_in_satellite = File.join(repo.working_dir, file_path) file_path_in_satellite = File.join(repo.working_dir, file_path)
dir_name_in_satellite = File.dirname(file_path_in_satellite) dir_name_in_satellite = File.dirname(file_path_in_satellite)
...@@ -38,10 +45,9 @@ module Gitlab ...@@ -38,10 +45,9 @@ module Gitlab
# will raise CommandFailed when commit fails # will raise CommandFailed when commit fails
repo.git.commit(raise: true, timeout: true, a: true, m: commit_message) repo.git.commit(raise: true, timeout: true, a: true, m: commit_message)
# push commit back to bare repo # push commit back to bare repo
# will raise CommandFailed when push fails # will raise CommandFailed when push fails
repo.git.push({raise: true, timeout: true}, :origin, ref) repo.git.push({raise: true, timeout: true}, :origin, "#{current_ref}:#{ref}")
# everything worked # everything worked
true true
......
...@@ -6,15 +6,15 @@ describe ApplicationHelper do ...@@ -6,15 +6,15 @@ describe ApplicationHelper do
controller.stub(:controller_name).and_return('foo') controller.stub(:controller_name).and_return('foo')
end end
it "returns true when controller matches argument" do it 'returns true when controller matches argument' do
current_controller?(:foo).should be_true current_controller?(:foo).should be_true
end end
it "returns false when controller does not match argument" do it 'returns false when controller does not match argument' do
current_controller?(:bar).should_not be_true current_controller?(:bar).should_not be_true
end end
it "should take any number of arguments" do it 'should take any number of arguments' do
current_controller?(:baz, :bar).should_not be_true current_controller?(:baz, :bar).should_not be_true
current_controller?(:baz, :bar, :foo).should be_true current_controller?(:baz, :bar, :foo).should be_true
end end
...@@ -25,49 +25,71 @@ describe ApplicationHelper do ...@@ -25,49 +25,71 @@ describe ApplicationHelper do
allow(self).to receive(:action_name).and_return('foo') allow(self).to receive(:action_name).and_return('foo')
end end
it "returns true when action matches argument" do it 'returns true when action matches argument' do
current_action?(:foo).should be_true current_action?(:foo).should be_true
end end
it "returns false when action does not match argument" do it 'returns false when action does not match argument' do
current_action?(:bar).should_not be_true current_action?(:bar).should_not be_true
end end
it "should take any number of arguments" do it 'should take any number of arguments' do
current_action?(:baz, :bar).should_not be_true current_action?(:baz, :bar).should_not be_true
current_action?(:baz, :bar, :foo).should be_true current_action?(:baz, :bar, :foo).should be_true
end end
end end
describe "group_icon" do describe 'group_icon' do
avatar_file_path = File.join(Rails.root, 'public', 'gitlab_logo.png') avatar_file_path = File.join(Rails.root, 'public', 'gitlab_logo.png')
it "should return an url for the avatar" do it 'should return an url for the avatar' do
group = create(:group) group = create(:group)
group.avatar = File.open(avatar_file_path) group.avatar = File.open(avatar_file_path)
group.save! group.save!
group_icon(group.path).to_s.should match("/uploads/group/avatar/#{ group.id }/gitlab_logo.png") group_icon(group.path).to_s.should match("/uploads/group/avatar/#{ group.id }/gitlab_logo.png")
end end
it "should give default avatar_icon when no avatar is present" do it 'should give default avatar_icon when no avatar is present' do
group = create(:group) group = create(:group)
group.save! group.save!
group_icon(group.path).should match("group_avatar.png") group_icon(group.path).should match('group_avatar.png')
end end
end end
describe "avatar_icon" do describe 'project_icon' do
avatar_file_path = File.join(Rails.root, 'public', 'gitlab_logo.png') avatar_file_path = File.join(Rails.root, 'public', 'gitlab_logo.png')
it "should return an url for the avatar" do it 'should return an url for the avatar' do
project = create(:project)
project.avatar = File.open(avatar_file_path)
project.save!
project_icon(project.to_param).to_s.should ==
"<img alt=\"Gitlab logo\" src=\"/uploads/project/avatar/#{ project.id }/gitlab_logo.png\" />"
end
it 'should give uploaded icon when present' do
project = create(:project)
project.save!
Project.any_instance.stub(:avatar_in_git).and_return(true)
project_icon(project.to_param).to_s.should match(
image_tag(project_avatar_path(project)))
end
end
describe 'avatar_icon' do
avatar_file_path = File.join(Rails.root, 'public', 'gitlab_logo.png')
it 'should return an url for the avatar' do
user = create(:user) user = create(:user)
user.avatar = File.open(avatar_file_path) user.avatar = File.open(avatar_file_path)
user.save! user.save!
avatar_icon(user.email).to_s.should match("/uploads/user/avatar/#{ user.id }/gitlab_logo.png") avatar_icon(user.email).to_s.should match("/uploads/user/avatar/#{ user.id }/gitlab_logo.png")
end end
it "should return an url for the avatar with relative url" do it 'should return an url for the avatar with relative url' do
Gitlab.config.gitlab.stub(relative_url_root: "/gitlab") Gitlab.config.gitlab.stub(relative_url_root: '/gitlab')
Gitlab.config.gitlab.stub(url: Settings.send(:build_gitlab_url)) Gitlab.config.gitlab.stub(url: Settings.send(:build_gitlab_url))
user = create(:user) user = create(:user)
...@@ -76,58 +98,58 @@ describe ApplicationHelper do ...@@ -76,58 +98,58 @@ describe ApplicationHelper do
avatar_icon(user.email).to_s.should match("/gitlab/uploads/user/avatar/#{ user.id }/gitlab_logo.png") avatar_icon(user.email).to_s.should match("/gitlab/uploads/user/avatar/#{ user.id }/gitlab_logo.png")
end end
it "should call gravatar_icon when no avatar is present" do it 'should call gravatar_icon when no avatar is present' do
user = create(:user, email: 'test@example.com') user = create(:user, email: 'test@example.com')
user.save! user.save!
avatar_icon(user.email).to_s.should == "http://www.gravatar.com/avatar/55502f40dc8b7c769880b10874abc9d0?s=40&d=identicon" avatar_icon(user.email).to_s.should == 'http://www.gravatar.com/avatar/55502f40dc8b7c769880b10874abc9d0?s=40&d=identicon'
end end
end end
describe "gravatar_icon" do describe 'gravatar_icon' do
let(:user_email) { 'user@email.com' } let(:user_email) { 'user@email.com' }
it "should return a generic avatar path when Gravatar is disabled" do it 'should return a generic avatar path when Gravatar is disabled' do
ApplicationSetting.any_instance.stub(gravatar_enabled?: false) ApplicationSetting.any_instance.stub(gravatar_enabled?: false)
gravatar_icon(user_email).should match('no_avatar.png') gravatar_icon(user_email).should match('no_avatar.png')
end end
it "should return a generic avatar path when email is blank" do it 'should return a generic avatar path when email is blank' do
gravatar_icon('').should match('no_avatar.png') gravatar_icon('').should match('no_avatar.png')
end end
it "should return default gravatar url" do it 'should return default gravatar url' do
Gitlab.config.gitlab.stub(https: false) Gitlab.config.gitlab.stub(https: false)
gravatar_icon(user_email).should match('http://www.gravatar.com/avatar/b58c6f14d292556214bd64909bcdb118') gravatar_icon(user_email).should match('http://www.gravatar.com/avatar/b58c6f14d292556214bd64909bcdb118')
end end
it "should use SSL when appropriate" do it 'should use SSL when appropriate' do
Gitlab.config.gitlab.stub(https: true) Gitlab.config.gitlab.stub(https: true)
gravatar_icon(user_email).should match('https://secure.gravatar.com') gravatar_icon(user_email).should match('https://secure.gravatar.com')
end end
it "should return custom gravatar path when gravatar_url is set" do it 'should return custom gravatar path when gravatar_url is set' do
allow(self).to receive(:request).and_return(double(:ssl? => false)) allow(self).to receive(:request).and_return(double(:ssl? => false))
Gitlab.config.gravatar.stub(:plain_url).and_return('http://example.local/?s=%{size}&hash=%{hash}') Gitlab.config.gravatar.stub(:plain_url).and_return('http://example.local/?s=%{size}&hash=%{hash}')
gravatar_icon(user_email, 20).should == 'http://example.local/?s=20&hash=b58c6f14d292556214bd64909bcdb118' gravatar_icon(user_email, 20).should == 'http://example.local/?s=20&hash=b58c6f14d292556214bd64909bcdb118'
end end
it "should accept a custom size" do it 'should accept a custom size' do
allow(self).to receive(:request).and_return(double(:ssl? => false)) allow(self).to receive(:request).and_return(double(:ssl? => false))
gravatar_icon(user_email, 64).should match(/\?s=64/) gravatar_icon(user_email, 64).should match(/\?s=64/)
end end
it "should use default size when size is wrong" do it 'should use default size when size is wrong' do
allow(self).to receive(:request).and_return(double(:ssl? => false)) allow(self).to receive(:request).and_return(double(:ssl? => false))
gravatar_icon(user_email, nil).should match(/\?s=40/) gravatar_icon(user_email, nil).should match(/\?s=40/)
end end
it "should be case insensitive" do it 'should be case insensitive' do
allow(self).to receive(:request).and_return(double(:ssl? => false)) allow(self).to receive(:request).and_return(double(:ssl? => false))
gravatar_icon(user_email).should == gravatar_icon(user_email.upcase + " ") gravatar_icon(user_email).should == gravatar_icon(user_email.upcase + ' ')
end end
end end
describe "grouped_options_refs" do describe 'grouped_options_refs' do
# Override Rails' grouped_options_for_select helper since HTML is harder to work with # Override Rails' grouped_options_for_select helper since HTML is harder to work with
def grouped_options_for_select(options, *args) def grouped_options_for_select(options, *args)
options options
...@@ -140,17 +162,17 @@ describe ApplicationHelper do ...@@ -140,17 +162,17 @@ describe ApplicationHelper do
@project = create(:project) @project = create(:project)
end end
it "includes a list of branch names" do it 'includes a list of branch names' do
options[0][0].should == 'Branches' options[0][0].should == 'Branches'
options[0][1].should include('master', 'feature') options[0][1].should include('master', 'feature')
end end
it "includes a list of tag names" do it 'includes a list of tag names' do
options[1][0].should == 'Tags' options[1][0].should == 'Tags'
options[1][1].should include('v1.0.0','v1.1.0') options[1][1].should include('v1.0.0','v1.1.0')
end end
it "includes a specific commit ref if defined" do it 'includes a specific commit ref if defined' do
# Must be an instance variable # Must be an instance variable
@ref = '2ed06dc41dbb5936af845b87d79e05bbf24c73b8' @ref = '2ed06dc41dbb5936af845b87d79e05bbf24c73b8'
...@@ -158,26 +180,26 @@ describe ApplicationHelper do ...@@ -158,26 +180,26 @@ describe ApplicationHelper do
options[2][1].should == [@ref] options[2][1].should == [@ref]
end end
it "sorts tags in a natural order" do it 'sorts tags in a natural order' do
# Stub repository.tag_names to make sure we get some valid testing data # Stub repository.tag_names to make sure we get some valid testing data
expect(@project.repository).to receive(:tag_names).and_return(["v1.0.9", "v1.0.10", "v2.0", "v3.1.4.2", "v1.0.9a"]) expect(@project.repository).to receive(:tag_names).and_return(['v1.0.9', 'v1.0.10', 'v2.0', 'v3.1.4.2', 'v1.0.9a'])
options[1][1].should == ["v3.1.4.2", "v2.0", "v1.0.10", "v1.0.9a", "v1.0.9"] options[1][1].should == ['v3.1.4.2', 'v2.0', 'v1.0.10', 'v1.0.9a', 'v1.0.9']
end end
end end
describe "user_color_scheme_class" do describe 'user_color_scheme_class' do
context "with current_user is nil" do context 'with current_user is nil' do
it "should return a string" do it 'should return a string' do
allow(self).to receive(:current_user).and_return(nil) allow(self).to receive(:current_user).and_return(nil)
user_color_scheme_class.should be_kind_of(String) user_color_scheme_class.should be_kind_of(String)
end end
end end
context "with a current_user" do context 'with a current_user' do
(1..5).each do |color_scheme_id| (1..5).each do |color_scheme_id|
context "with color_scheme_id == #{color_scheme_id}" do context "with color_scheme_id == #{color_scheme_id}" do
it "should return a string" do it 'should return a string' do
current_user = double(:color_scheme_id => color_scheme_id) current_user = double(:color_scheme_id => color_scheme_id)
allow(self).to receive(:current_user).and_return(current_user) allow(self).to receive(:current_user).and_return(current_user)
user_color_scheme_class.should be_kind_of(String) user_color_scheme_class.should be_kind_of(String)
...@@ -187,43 +209,43 @@ describe ApplicationHelper do ...@@ -187,43 +209,43 @@ describe ApplicationHelper do
end end
end end
describe "simple_sanitize" do describe 'simple_sanitize' do
let(:a_tag) { '<a href="#">Foo</a>' } let(:a_tag) { '<a href="#">Foo</a>' }
it "allows the a tag" do it 'allows the a tag' do
simple_sanitize(a_tag).should == a_tag simple_sanitize(a_tag).should == a_tag
end end
it "allows the span tag" do it 'allows the span tag' do
input = '<span class="foo">Bar</span>' input = '<span class="foo">Bar</span>'
simple_sanitize(input).should == input simple_sanitize(input).should == input
end end
it "disallows other tags" do it 'disallows other tags' do
input = "<strike><b>#{a_tag}</b></strike>" input = "<strike><b>#{a_tag}</b></strike>"
simple_sanitize(input).should == a_tag simple_sanitize(input).should == a_tag
end end
end end
describe "link_to" do describe 'link_to' do
it "should not include rel=nofollow for internal links" do it 'should not include rel=nofollow for internal links' do
expect(link_to("Home", root_path)).to eq("<a href=\"/\">Home</a>") expect(link_to('Home', root_path)).to eq("<a href=\"/\">Home</a>")
end end
it "should include rel=nofollow for external links" do it 'should include rel=nofollow for external links' do
expect(link_to("Example", "http://www.example.com")).to eq("<a href=\"http://www.example.com\" rel=\"nofollow\">Example</a>") expect(link_to('Example', 'http://www.example.com')).to eq("<a href=\"http://www.example.com\" rel=\"nofollow\">Example</a>")
end end
it "should include re=nofollow for external links and honor existing html_options" do it 'should include re=nofollow for external links and honor existing html_options' do
expect( expect(
link_to("Example", "http://www.example.com", class: "toggle", data: {toggle: "dropdown"}) link_to('Example', 'http://www.example.com', class: 'toggle', data: {toggle: 'dropdown'})
).to eq("<a class=\"toggle\" data-toggle=\"dropdown\" href=\"http://www.example.com\" rel=\"nofollow\">Example</a>") ).to eq("<a class=\"toggle\" data-toggle=\"dropdown\" href=\"http://www.example.com\" rel=\"nofollow\">Example</a>")
end end
it "should include rel=nofollow for external links and preserver other rel values" do it 'should include rel=nofollow for external links and preserver other rel values' do
expect( expect(
link_to("Example", "http://www.example.com", rel: "noreferrer") link_to('Example', 'http://www.example.com', rel: 'noreferrer')
).to eq("<a href=\"http://www.example.com\" rel=\"noreferrer nofollow\">Example</a>") ).to eq("<a href=\"http://www.example.com\" rel=\"noreferrer nofollow\">Example</a>")
end end
end end
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
# merge_requests_enabled :boolean default(TRUE), not null # merge_requests_enabled :boolean default(TRUE), not null
# wiki_enabled :boolean default(TRUE), not null # wiki_enabled :boolean default(TRUE), not null
# namespace_id :integer # namespace_id :integer
# issues_tracker :string(255) default("gitlab"), not null # issues_tracker :string(255) default('gitlab'), not null
# issues_tracker_id :string(255) # issues_tracker_id :string(255)
# snippets_enabled :boolean default(TRUE), not null # snippets_enabled :boolean default(TRUE), not null
# last_activity_at :datetime # last_activity_at :datetime
...@@ -26,12 +26,13 @@ ...@@ -26,12 +26,13 @@
# star_count :integer default(0), not null # star_count :integer default(0), not null
# import_type :string(255) # import_type :string(255)
# import_source :string(255) # import_source :string(255)
# avatar :string(255)
# #
require 'spec_helper' require 'spec_helper'
describe Project do describe Project do
describe "Associations" do describe 'Associations' do
it { should belong_to(:group) } it { should belong_to(:group) }
it { should belong_to(:namespace) } it { should belong_to(:namespace) }
it { should belong_to(:creator).class_name('User') } it { should belong_to(:creator).class_name('User') }
...@@ -52,10 +53,10 @@ describe Project do ...@@ -52,10 +53,10 @@ describe Project do
it { should have_one(:pushover_service).dependent(:destroy) } it { should have_one(:pushover_service).dependent(:destroy) }
end end
describe "Mass assignment" do describe 'Mass assignment' do
end end
describe "Validation" do describe 'Validation' do
let!(:project) { create(:project) } let!(:project) { create(:project) }
it { should validate_presence_of(:name) } it { should validate_presence_of(:name) }
...@@ -70,7 +71,7 @@ describe Project do ...@@ -70,7 +71,7 @@ describe Project do
it { should ensure_length_of(:issues_tracker_id).is_within(0..255) } it { should ensure_length_of(:issues_tracker_id).is_within(0..255) }
it { should validate_presence_of(:namespace) } it { should validate_presence_of(:namespace) }
it "should not allow new projects beyond user limits" do it 'should not allow new projects beyond user limits' do
project2 = build(:project) project2 = build(:project)
project2.stub(:creator).and_return(double(can_create_project?: false, projects_limit: 0).as_null_object) project2.stub(:creator).and_return(double(can_create_project?: false, projects_limit: 0).as_null_object)
project2.should_not be_valid project2.should_not be_valid
...@@ -78,7 +79,7 @@ describe Project do ...@@ -78,7 +79,7 @@ describe Project do
end end
end end
describe "Respond to" do describe 'Respond to' do
it { should respond_to(:url_to_repo) } it { should respond_to(:url_to_repo) }
it { should respond_to(:repo_exists?) } it { should respond_to(:repo_exists?) }
it { should respond_to(:satellite) } it { should respond_to(:satellite) }
...@@ -89,27 +90,27 @@ describe Project do ...@@ -89,27 +90,27 @@ describe Project do
it { should respond_to(:path_with_namespace) } it { should respond_to(:path_with_namespace) }
end end
it "should return valid url to repo" do it 'should return valid url to repo' do
project = Project.new(path: "somewhere") project = Project.new(path: 'somewhere')
project.url_to_repo.should == Gitlab.config.gitlab_shell.ssh_path_prefix + "somewhere.git" project.url_to_repo.should == Gitlab.config.gitlab_shell.ssh_path_prefix + 'somewhere.git'
end end
it "returns the full web URL for this repo" do it 'returns the full web URL for this repo' do
project = Project.new(path: "somewhere") project = Project.new(path: 'somewhere')
project.web_url.should == "#{Gitlab.config.gitlab.url}/somewhere" project.web_url.should == "#{Gitlab.config.gitlab.url}/somewhere"
end end
it "returns the web URL without the protocol for this repo" do it 'returns the web URL without the protocol for this repo' do
project = Project.new(path: "somewhere") project = Project.new(path: 'somewhere')
project.web_url_without_protocol.should == "#{Gitlab.config.gitlab.url.split("://")[1]}/somewhere" project.web_url_without_protocol.should == "#{Gitlab.config.gitlab.url.split('://')[1]}/somewhere"
end end
describe "last_activity methods" do describe 'last_activity methods' do
let(:project) { create(:project) } let(:project) { create(:project) }
let(:last_event) { double(created_at: Time.now) } let(:last_event) { double(created_at: Time.now) }
describe "last_activity" do describe 'last_activity' do
it "should alias last_activity to last_event" do it 'should alias last_activity to last_event' do
project.stub(last_event: last_event) project.stub(last_event: last_event)
project.last_activity.should == last_event project.last_activity.should == last_event
end end
...@@ -134,13 +135,13 @@ describe Project do ...@@ -134,13 +135,13 @@ describe Project do
let(:prev_commit_id) { merge_request.commits.last.id } let(:prev_commit_id) { merge_request.commits.last.id }
let(:commit_id) { merge_request.commits.first.id } let(:commit_id) { merge_request.commits.first.id }
it "should close merge request if last commit from source branch was pushed to target branch" do it 'should close merge request if last commit from source branch was pushed to target branch' do
project.update_merge_requests(prev_commit_id, commit_id, "refs/heads/#{merge_request.target_branch}", key.user) project.update_merge_requests(prev_commit_id, commit_id, "refs/heads/#{merge_request.target_branch}", key.user)
merge_request.reload merge_request.reload
merge_request.merged?.should be_true merge_request.merged?.should be_true
end end
it "should update merge request commits with new one if pushed to source branch" do it 'should update merge request commits with new one if pushed to source branch' do
project.update_merge_requests(prev_commit_id, commit_id, "refs/heads/#{merge_request.source_branch}", key.user) project.update_merge_requests(prev_commit_id, commit_id, "refs/heads/#{merge_request.source_branch}", key.user)
merge_request.reload merge_request.reload
merge_request.last_commit.id.should == commit_id merge_request.last_commit.id.should == commit_id
...@@ -166,14 +167,14 @@ describe Project do ...@@ -166,14 +167,14 @@ describe Project do
@project = create(:project, name: 'gitlabhq', namespace: @group) @project = create(:project, name: 'gitlabhq', namespace: @group)
end end
it { @project.to_param.should == "gitlab/gitlabhq" } it { @project.to_param.should == 'gitlab/gitlabhq' }
end end
end end
describe :repository do describe :repository do
let(:project) { create(:project) } let(:project) { create(:project) }
it "should return valid repo" do it 'should return valid repo' do
project.repository.should be_kind_of(Repository) project.repository.should be_kind_of(Repository)
end end
end end
...@@ -184,15 +185,15 @@ describe Project do ...@@ -184,15 +185,15 @@ describe Project do
let(:not_existed_issue) { create(:issue) } let(:not_existed_issue) { create(:issue) }
let(:ext_project) { create(:redmine_project) } let(:ext_project) { create(:redmine_project) }
it "should be true or if used internal tracker and issue exists" do it 'should be true or if used internal tracker and issue exists' do
project.issue_exists?(existed_issue.iid).should be_true project.issue_exists?(existed_issue.iid).should be_true
end end
it "should be false or if used internal tracker and issue not exists" do it 'should be false or if used internal tracker and issue not exists' do
project.issue_exists?(not_existed_issue.iid).should be_false project.issue_exists?(not_existed_issue.iid).should be_false
end end
it "should always be true if used other tracker" do it 'should always be true if used other tracker' do
ext_project.issue_exists?(rand(100)).should be_true ext_project.issue_exists?(rand(100)).should be_true
end end
end end
...@@ -214,15 +215,15 @@ describe Project do ...@@ -214,15 +215,15 @@ describe Project do
let(:project) { create(:project) } let(:project) { create(:project) }
let(:ext_project) { create(:redmine_project) } let(:ext_project) { create(:redmine_project) }
it "should be true for projects with external issues tracker if issues enabled" do it 'should be true for projects with external issues tracker if issues enabled' do
ext_project.can_have_issues_tracker_id?.should be_true ext_project.can_have_issues_tracker_id?.should be_true
end end
it "should be false for projects with internal issue tracker if issues enabled" do it 'should be false for projects with internal issue tracker if issues enabled' do
project.can_have_issues_tracker_id?.should be_false project.can_have_issues_tracker_id?.should be_false
end end
it "should be always false if issues disabled" do it 'should be always false if issues disabled' do
project.issues_enabled = false project.issues_enabled = false
ext_project.issues_enabled = false ext_project.issues_enabled = false
...@@ -310,4 +311,18 @@ describe Project do ...@@ -310,4 +311,18 @@ describe Project do
expect(project.star_count).to eq(0) expect(project.star_count).to eq(0)
end end
end end
describe :avatar_type do
let(:project) { create(:project) }
it 'should be true if avatar is image' do
project.update_attribute(:avatar, 'uploads/avatar.png')
project.avatar_type.should be_true
end
it 'should be false if avatar is html page' do
project.update_attribute(:avatar, 'uploads/avatar.html')
project.avatar_type.should == ['only images allowed']
end
end
end end
...@@ -12,43 +12,43 @@ require 'spec_helper' ...@@ -12,43 +12,43 @@ require 'spec_helper'
# Examples # Examples
# #
# # Default behavior # # Default behavior
# it_behaves_like "RESTful project resources" do # it_behaves_like 'RESTful project resources' do
# let(:controller) { 'issues' } # let(:controller) { 'issues' }
# end # end
# #
# # Customizing actions # # Customizing actions
# it_behaves_like "RESTful project resources" do # it_behaves_like 'RESTful project resources' do
# let(:actions) { [:index] } # let(:actions) { [:index] }
# let(:controller) { 'issues' } # let(:controller) { 'issues' }
# end # end
shared_examples "RESTful project resources" do shared_examples 'RESTful project resources' do
let(:actions) { [:index, :create, :new, :edit, :show, :update, :destroy] } let(:actions) { [:index, :create, :new, :edit, :show, :update, :destroy] }
it "to #index" do it 'to #index' do
get("/gitlab/gitlabhq/#{controller}").should route_to("projects/#{controller}#index", project_id: 'gitlab/gitlabhq') if actions.include?(:index) get("/gitlab/gitlabhq/#{controller}").should route_to("projects/#{controller}#index", project_id: 'gitlab/gitlabhq') if actions.include?(:index)
end end
it "to #create" do it 'to #create' do
post("/gitlab/gitlabhq/#{controller}").should route_to("projects/#{controller}#create", project_id: 'gitlab/gitlabhq') if actions.include?(:create) post("/gitlab/gitlabhq/#{controller}").should route_to("projects/#{controller}#create", project_id: 'gitlab/gitlabhq') if actions.include?(:create)
end end
it "to #new" do it 'to #new' do
get("/gitlab/gitlabhq/#{controller}/new").should route_to("projects/#{controller}#new", project_id: 'gitlab/gitlabhq') if actions.include?(:new) get("/gitlab/gitlabhq/#{controller}/new").should route_to("projects/#{controller}#new", project_id: 'gitlab/gitlabhq') if actions.include?(:new)
end end
it "to #edit" do it 'to #edit' do
get("/gitlab/gitlabhq/#{controller}/1/edit").should route_to("projects/#{controller}#edit", project_id: 'gitlab/gitlabhq', id: '1') if actions.include?(:edit) get("/gitlab/gitlabhq/#{controller}/1/edit").should route_to("projects/#{controller}#edit", project_id: 'gitlab/gitlabhq', id: '1') if actions.include?(:edit)
end end
it "to #show" do it 'to #show' do
get("/gitlab/gitlabhq/#{controller}/1").should route_to("projects/#{controller}#show", project_id: 'gitlab/gitlabhq', id: '1') if actions.include?(:show) get("/gitlab/gitlabhq/#{controller}/1").should route_to("projects/#{controller}#show", project_id: 'gitlab/gitlabhq', id: '1') if actions.include?(:show)
end end
it "to #update" do it 'to #update' do
put("/gitlab/gitlabhq/#{controller}/1").should route_to("projects/#{controller}#update", project_id: 'gitlab/gitlabhq', id: '1') if actions.include?(:update) put("/gitlab/gitlabhq/#{controller}/1").should route_to("projects/#{controller}#update", project_id: 'gitlab/gitlabhq', id: '1') if actions.include?(:update)
end end
it "to #destroy" do it 'to #destroy' do
delete("/gitlab/gitlabhq/#{controller}/1").should route_to("projects/#{controller}#destroy", project_id: 'gitlab/gitlabhq', id: '1') if actions.include?(:destroy) delete("/gitlab/gitlabhq/#{controller}/1").should route_to("projects/#{controller}#destroy", project_id: 'gitlab/gitlabhq', id: '1') if actions.include?(:destroy)
end end
end end
...@@ -61,33 +61,33 @@ end ...@@ -61,33 +61,33 @@ end
# PUT /:id(.:format) projects#update # PUT /:id(.:format) projects#update
# DELETE /:id(.:format) projects#destroy # DELETE /:id(.:format) projects#destroy
# markdown_preview_project GET /:id/markdown_preview(.:format) projects#markdown_preview # markdown_preview_project GET /:id/markdown_preview(.:format) projects#markdown_preview
describe ProjectsController, "routing" do describe ProjectsController, 'routing' do
it "to #create" do it 'to #create' do
post("/projects").should route_to('projects#create') post('/projects').should route_to('projects#create')
end end
it "to #new" do it 'to #new' do
get("/projects/new").should route_to('projects#new') get('/projects/new').should route_to('projects#new')
end end
it "to #edit" do it 'to #edit' do
get("/gitlab/gitlabhq/edit").should route_to('projects#edit', id: 'gitlab/gitlabhq') get('/gitlab/gitlabhq/edit').should route_to('projects#edit', id: 'gitlab/gitlabhq')
end end
it "to #autocomplete_sources" do it 'to #autocomplete_sources' do
get('/gitlab/gitlabhq/autocomplete_sources').should route_to('projects#autocomplete_sources', id: "gitlab/gitlabhq") get('/gitlab/gitlabhq/autocomplete_sources').should route_to('projects#autocomplete_sources', id: 'gitlab/gitlabhq')
end end
it "to #show" do it 'to #show' do
get("/gitlab/gitlabhq").should route_to('projects#show', id: 'gitlab/gitlabhq') get('/gitlab/gitlabhq').should route_to('projects#show', id: 'gitlab/gitlabhq')
end end
it "to #update" do it 'to #update' do
put("/gitlab/gitlabhq").should route_to('projects#update', id: 'gitlab/gitlabhq') put('/gitlab/gitlabhq').should route_to('projects#update', id: 'gitlab/gitlabhq')
end end
it "to #destroy" do it 'to #destroy' do
delete("/gitlab/gitlabhq").should route_to('projects#destroy', id: 'gitlab/gitlabhq') delete('/gitlab/gitlabhq').should route_to('projects#destroy', id: 'gitlab/gitlabhq')
end end
it 'to #markdown_preview' do it 'to #markdown_preview' do
...@@ -103,16 +103,16 @@ end ...@@ -103,16 +103,16 @@ end
# edit_project_wiki GET /:project_id/wikis/:id/edit(.:format) projects/wikis#edit # edit_project_wiki GET /:project_id/wikis/:id/edit(.:format) projects/wikis#edit
# project_wiki GET /:project_id/wikis/:id(.:format) projects/wikis#show # project_wiki GET /:project_id/wikis/:id(.:format) projects/wikis#show
# DELETE /:project_id/wikis/:id(.:format) projects/wikis#destroy # DELETE /:project_id/wikis/:id(.:format) projects/wikis#destroy
describe Projects::WikisController, "routing" do describe Projects::WikisController, 'routing' do
it "to #pages" do it 'to #pages' do
get("/gitlab/gitlabhq/wikis/pages").should route_to('projects/wikis#pages', project_id: 'gitlab/gitlabhq') get('/gitlab/gitlabhq/wikis/pages').should route_to('projects/wikis#pages', project_id: 'gitlab/gitlabhq')
end end
it "to #history" do it 'to #history' do
get("/gitlab/gitlabhq/wikis/1/history").should route_to('projects/wikis#history', project_id: 'gitlab/gitlabhq', id: '1') get('/gitlab/gitlabhq/wikis/1/history').should route_to('projects/wikis#history', project_id: 'gitlab/gitlabhq', id: '1')
end end
it_behaves_like "RESTful project resources" do it_behaves_like 'RESTful project resources' do
let(:actions) { [:create, :edit, :show, :destroy] } let(:actions) { [:create, :edit, :show, :destroy] }
let(:controller) { 'wikis' } let(:controller) { 'wikis' }
end end
...@@ -122,45 +122,45 @@ end ...@@ -122,45 +122,45 @@ end
# tags_project_repository GET /:project_id/repository/tags(.:format) projects/repositories#tags # tags_project_repository GET /:project_id/repository/tags(.:format) projects/repositories#tags
# archive_project_repository GET /:project_id/repository/archive(.:format) projects/repositories#archive # archive_project_repository GET /:project_id/repository/archive(.:format) projects/repositories#archive
# edit_project_repository GET /:project_id/repository/edit(.:format) projects/repositories#edit # edit_project_repository GET /:project_id/repository/edit(.:format) projects/repositories#edit
describe Projects::RepositoriesController, "routing" do describe Projects::RepositoriesController, 'routing' do
it "to #archive" do it 'to #archive' do
get("/gitlab/gitlabhq/repository/archive").should route_to('projects/repositories#archive', project_id: 'gitlab/gitlabhq') get('/gitlab/gitlabhq/repository/archive').should route_to('projects/repositories#archive', project_id: 'gitlab/gitlabhq')
end end
it "to #archive format:zip" do it 'to #archive format:zip' do
get("/gitlab/gitlabhq/repository/archive.zip").should route_to('projects/repositories#archive', project_id: 'gitlab/gitlabhq', format: 'zip') get('/gitlab/gitlabhq/repository/archive.zip').should route_to('projects/repositories#archive', project_id: 'gitlab/gitlabhq', format: 'zip')
end end
it "to #archive format:tar.bz2" do it 'to #archive format:tar.bz2' do
get("/gitlab/gitlabhq/repository/archive.tar.bz2").should route_to('projects/repositories#archive', project_id: 'gitlab/gitlabhq', format: 'tar.bz2') get('/gitlab/gitlabhq/repository/archive.tar.bz2').should route_to('projects/repositories#archive', project_id: 'gitlab/gitlabhq', format: 'tar.bz2')
end end
it "to #show" do it 'to #show' do
get("/gitlab/gitlabhq/repository").should route_to('projects/repositories#show', project_id: 'gitlab/gitlabhq') get('/gitlab/gitlabhq/repository').should route_to('projects/repositories#show', project_id: 'gitlab/gitlabhq')
end end
end end
describe Projects::BranchesController, "routing" do describe Projects::BranchesController, 'routing' do
it "to #branches" do it 'to #branches' do
get("/gitlab/gitlabhq/branches").should route_to('projects/branches#index', project_id: 'gitlab/gitlabhq') get('/gitlab/gitlabhq/branches').should route_to('projects/branches#index', project_id: 'gitlab/gitlabhq')
delete("/gitlab/gitlabhq/branches/feature%2345").should route_to('projects/branches#destroy', project_id: 'gitlab/gitlabhq', id: 'feature#45') delete('/gitlab/gitlabhq/branches/feature%2345').should route_to('projects/branches#destroy', project_id: 'gitlab/gitlabhq', id: 'feature#45')
delete("/gitlab/gitlabhq/branches/feature%2B45").should route_to('projects/branches#destroy', project_id: 'gitlab/gitlabhq', id: 'feature+45') delete('/gitlab/gitlabhq/branches/feature%2B45').should route_to('projects/branches#destroy', project_id: 'gitlab/gitlabhq', id: 'feature+45')
delete("/gitlab/gitlabhq/branches/feature@45").should route_to('projects/branches#destroy', project_id: 'gitlab/gitlabhq', id: 'feature@45') delete('/gitlab/gitlabhq/branches/feature@45').should route_to('projects/branches#destroy', project_id: 'gitlab/gitlabhq', id: 'feature@45')
delete("/gitlab/gitlabhq/branches/feature%2345/foo/bar/baz").should route_to('projects/branches#destroy', project_id: 'gitlab/gitlabhq', id: 'feature#45/foo/bar/baz') delete('/gitlab/gitlabhq/branches/feature%2345/foo/bar/baz').should route_to('projects/branches#destroy', project_id: 'gitlab/gitlabhq', id: 'feature#45/foo/bar/baz')
delete("/gitlab/gitlabhq/branches/feature%2B45/foo/bar/baz").should route_to('projects/branches#destroy', project_id: 'gitlab/gitlabhq', id: 'feature+45/foo/bar/baz') delete('/gitlab/gitlabhq/branches/feature%2B45/foo/bar/baz').should route_to('projects/branches#destroy', project_id: 'gitlab/gitlabhq', id: 'feature+45/foo/bar/baz')
delete("/gitlab/gitlabhq/branches/feature@45/foo/bar/baz").should route_to('projects/branches#destroy', project_id: 'gitlab/gitlabhq', id: 'feature@45/foo/bar/baz') delete('/gitlab/gitlabhq/branches/feature@45/foo/bar/baz').should route_to('projects/branches#destroy', project_id: 'gitlab/gitlabhq', id: 'feature@45/foo/bar/baz')
end end
end end
describe Projects::TagsController, "routing" do describe Projects::TagsController, 'routing' do
it "to #tags" do it 'to #tags' do
get("/gitlab/gitlabhq/tags").should route_to('projects/tags#index', project_id: 'gitlab/gitlabhq') get('/gitlab/gitlabhq/tags').should route_to('projects/tags#index', project_id: 'gitlab/gitlabhq')
delete("/gitlab/gitlabhq/tags/feature%2345").should route_to('projects/tags#destroy', project_id: 'gitlab/gitlabhq', id: 'feature#45') delete('/gitlab/gitlabhq/tags/feature%2345').should route_to('projects/tags#destroy', project_id: 'gitlab/gitlabhq', id: 'feature#45')
delete("/gitlab/gitlabhq/tags/feature%2B45").should route_to('projects/tags#destroy', project_id: 'gitlab/gitlabhq', id: 'feature+45') delete('/gitlab/gitlabhq/tags/feature%2B45').should route_to('projects/tags#destroy', project_id: 'gitlab/gitlabhq', id: 'feature+45')
delete("/gitlab/gitlabhq/tags/feature@45").should route_to('projects/tags#destroy', project_id: 'gitlab/gitlabhq', id: 'feature@45') delete('/gitlab/gitlabhq/tags/feature@45').should route_to('projects/tags#destroy', project_id: 'gitlab/gitlabhq', id: 'feature@45')
delete("/gitlab/gitlabhq/tags/feature%2345/foo/bar/baz").should route_to('projects/tags#destroy', project_id: 'gitlab/gitlabhq', id: 'feature#45/foo/bar/baz') delete('/gitlab/gitlabhq/tags/feature%2345/foo/bar/baz').should route_to('projects/tags#destroy', project_id: 'gitlab/gitlabhq', id: 'feature#45/foo/bar/baz')
delete("/gitlab/gitlabhq/tags/feature%2B45/foo/bar/baz").should route_to('projects/tags#destroy', project_id: 'gitlab/gitlabhq', id: 'feature+45/foo/bar/baz') delete('/gitlab/gitlabhq/tags/feature%2B45/foo/bar/baz').should route_to('projects/tags#destroy', project_id: 'gitlab/gitlabhq', id: 'feature+45/foo/bar/baz')
delete("/gitlab/gitlabhq/tags/feature@45/foo/bar/baz").should route_to('projects/tags#destroy', project_id: 'gitlab/gitlabhq', id: 'feature@45/foo/bar/baz') delete('/gitlab/gitlabhq/tags/feature@45/foo/bar/baz').should route_to('projects/tags#destroy', project_id: 'gitlab/gitlabhq', id: 'feature@45/foo/bar/baz')
end end
end end
...@@ -172,8 +172,8 @@ end ...@@ -172,8 +172,8 @@ end
# project_deploy_key GET /:project_id/deploy_keys/:id(.:format) deploy_keys#show # project_deploy_key GET /:project_id/deploy_keys/:id(.:format) deploy_keys#show
# PUT /:project_id/deploy_keys/:id(.:format) deploy_keys#update # PUT /:project_id/deploy_keys/:id(.:format) deploy_keys#update
# DELETE /:project_id/deploy_keys/:id(.:format) deploy_keys#destroy # DELETE /:project_id/deploy_keys/:id(.:format) deploy_keys#destroy
describe Projects::DeployKeysController, "routing" do describe Projects::DeployKeysController, 'routing' do
it_behaves_like "RESTful project resources" do it_behaves_like 'RESTful project resources' do
let(:controller) { 'deploy_keys' } let(:controller) { 'deploy_keys' }
end end
end end
...@@ -181,8 +181,8 @@ end ...@@ -181,8 +181,8 @@ end
# project_protected_branches GET /:project_id/protected_branches(.:format) protected_branches#index # project_protected_branches GET /:project_id/protected_branches(.:format) protected_branches#index
# POST /:project_id/protected_branches(.:format) protected_branches#create # POST /:project_id/protected_branches(.:format) protected_branches#create
# project_protected_branch DELETE /:project_id/protected_branches/:id(.:format) protected_branches#destroy # project_protected_branch DELETE /:project_id/protected_branches/:id(.:format) protected_branches#destroy
describe Projects::ProtectedBranchesController, "routing" do describe Projects::ProtectedBranchesController, 'routing' do
it_behaves_like "RESTful project resources" do it_behaves_like 'RESTful project resources' do
let(:actions) { [:index, :create, :destroy] } let(:actions) { [:index, :create, :destroy] }
let(:controller) { 'protected_branches' } let(:controller) { 'protected_branches' }
end end
...@@ -191,21 +191,21 @@ end ...@@ -191,21 +191,21 @@ end
# switch_project_refs GET /:project_id/refs/switch(.:format) refs#switch # switch_project_refs GET /:project_id/refs/switch(.:format) refs#switch
# logs_tree_project_ref GET /:project_id/refs/:id/logs_tree(.:format) refs#logs_tree # logs_tree_project_ref GET /:project_id/refs/:id/logs_tree(.:format) refs#logs_tree
# logs_file_project_ref GET /:project_id/refs/:id/logs_tree/:path(.:format) refs#logs_tree # logs_file_project_ref GET /:project_id/refs/:id/logs_tree/:path(.:format) refs#logs_tree
describe Projects::RefsController, "routing" do describe Projects::RefsController, 'routing' do
it "to #switch" do it 'to #switch' do
get("/gitlab/gitlabhq/refs/switch").should route_to('projects/refs#switch', project_id: 'gitlab/gitlabhq') get('/gitlab/gitlabhq/refs/switch').should route_to('projects/refs#switch', project_id: 'gitlab/gitlabhq')
end end
it "to #logs_tree" do it 'to #logs_tree' do
get("/gitlab/gitlabhq/refs/stable/logs_tree").should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'stable') get('/gitlab/gitlabhq/refs/stable/logs_tree').should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'stable')
get("/gitlab/gitlabhq/refs/feature%2345/logs_tree").should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'feature#45') get('/gitlab/gitlabhq/refs/feature%2345/logs_tree').should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'feature#45')
get("/gitlab/gitlabhq/refs/feature%2B45/logs_tree").should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'feature+45') get('/gitlab/gitlabhq/refs/feature%2B45/logs_tree').should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'feature+45')
get("/gitlab/gitlabhq/refs/feature@45/logs_tree").should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'feature@45') get('/gitlab/gitlabhq/refs/feature@45/logs_tree').should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'feature@45')
get("/gitlab/gitlabhq/refs/stable/logs_tree/foo/bar/baz").should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'stable', path: 'foo/bar/baz') get('/gitlab/gitlabhq/refs/stable/logs_tree/foo/bar/baz').should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'stable', path: 'foo/bar/baz')
get("/gitlab/gitlabhq/refs/feature%2345/logs_tree/foo/bar/baz").should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'feature#45', path: 'foo/bar/baz') get('/gitlab/gitlabhq/refs/feature%2345/logs_tree/foo/bar/baz').should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'feature#45', path: 'foo/bar/baz')
get("/gitlab/gitlabhq/refs/feature%2B45/logs_tree/foo/bar/baz").should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'feature+45', path: 'foo/bar/baz') get('/gitlab/gitlabhq/refs/feature%2B45/logs_tree/foo/bar/baz').should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'feature+45', path: 'foo/bar/baz')
get("/gitlab/gitlabhq/refs/feature@45/logs_tree/foo/bar/baz").should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'feature@45', path: 'foo/bar/baz') get('/gitlab/gitlabhq/refs/feature@45/logs_tree/foo/bar/baz').should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'feature@45', path: 'foo/bar/baz')
get("/gitlab/gitlabhq/refs/stable/logs_tree/files.scss").should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'stable', path: 'files.scss') get('/gitlab/gitlabhq/refs/stable/logs_tree/files.scss').should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'stable', path: 'files.scss')
end end
end end
...@@ -221,36 +221,36 @@ end ...@@ -221,36 +221,36 @@ end
# project_merge_request GET /:project_id/merge_requests/:id(.:format) projects/merge_requests#show # project_merge_request GET /:project_id/merge_requests/:id(.:format) projects/merge_requests#show
# PUT /:project_id/merge_requests/:id(.:format) projects/merge_requests#update # PUT /:project_id/merge_requests/:id(.:format) projects/merge_requests#update
# DELETE /:project_id/merge_requests/:id(.:format) projects/merge_requests#destroy # DELETE /:project_id/merge_requests/:id(.:format) projects/merge_requests#destroy
describe Projects::MergeRequestsController, "routing" do describe Projects::MergeRequestsController, 'routing' do
it "to #diffs" do it 'to #diffs' do
get("/gitlab/gitlabhq/merge_requests/1/diffs").should route_to('projects/merge_requests#diffs', project_id: 'gitlab/gitlabhq', id: '1') get('/gitlab/gitlabhq/merge_requests/1/diffs').should route_to('projects/merge_requests#diffs', project_id: 'gitlab/gitlabhq', id: '1')
end end
it "to #automerge" do it 'to #automerge' do
post('/gitlab/gitlabhq/merge_requests/1/automerge').should route_to( post('/gitlab/gitlabhq/merge_requests/1/automerge').should route_to(
'projects/merge_requests#automerge', 'projects/merge_requests#automerge',
project_id: 'gitlab/gitlabhq', id: '1' project_id: 'gitlab/gitlabhq', id: '1'
) )
end end
it "to #automerge_check" do it 'to #automerge_check' do
get("/gitlab/gitlabhq/merge_requests/1/automerge_check").should route_to('projects/merge_requests#automerge_check', project_id: 'gitlab/gitlabhq', id: '1') get('/gitlab/gitlabhq/merge_requests/1/automerge_check').should route_to('projects/merge_requests#automerge_check', project_id: 'gitlab/gitlabhq', id: '1')
end end
it "to #branch_from" do it 'to #branch_from' do
get("/gitlab/gitlabhq/merge_requests/branch_from").should route_to('projects/merge_requests#branch_from', project_id: 'gitlab/gitlabhq') get('/gitlab/gitlabhq/merge_requests/branch_from').should route_to('projects/merge_requests#branch_from', project_id: 'gitlab/gitlabhq')
end end
it "to #branch_to" do it 'to #branch_to' do
get("/gitlab/gitlabhq/merge_requests/branch_to").should route_to('projects/merge_requests#branch_to', project_id: 'gitlab/gitlabhq') get('/gitlab/gitlabhq/merge_requests/branch_to').should route_to('projects/merge_requests#branch_to', project_id: 'gitlab/gitlabhq')
end end
it "to #show" do it 'to #show' do
get("/gitlab/gitlabhq/merge_requests/1.diff").should route_to('projects/merge_requests#show', project_id: 'gitlab/gitlabhq', id: '1', format: 'diff') get('/gitlab/gitlabhq/merge_requests/1.diff').should route_to('projects/merge_requests#show', project_id: 'gitlab/gitlabhq', id: '1', format: 'diff')
get("/gitlab/gitlabhq/merge_requests/1.patch").should route_to('projects/merge_requests#show', project_id: 'gitlab/gitlabhq', id: '1', format: 'patch') get('/gitlab/gitlabhq/merge_requests/1.patch').should route_to('projects/merge_requests#show', project_id: 'gitlab/gitlabhq', id: '1', format: 'patch')
end end
it_behaves_like "RESTful project resources" do it_behaves_like 'RESTful project resources' do
let(:controller) { 'merge_requests' } let(:controller) { 'merge_requests' }
let(:actions) { [:index, :create, :new, :edit, :show, :update] } let(:actions) { [:index, :create, :new, :edit, :show, :update] }
end end
...@@ -264,37 +264,37 @@ end ...@@ -264,37 +264,37 @@ end
# project_snippet GET /:project_id/snippets/:id(.:format) snippets#show # project_snippet GET /:project_id/snippets/:id(.:format) snippets#show
# PUT /:project_id/snippets/:id(.:format) snippets#update # PUT /:project_id/snippets/:id(.:format) snippets#update
# DELETE /:project_id/snippets/:id(.:format) snippets#destroy # DELETE /:project_id/snippets/:id(.:format) snippets#destroy
describe SnippetsController, "routing" do describe SnippetsController, 'routing' do
it "to #raw" do it 'to #raw' do
get("/gitlab/gitlabhq/snippets/1/raw").should route_to('projects/snippets#raw', project_id: 'gitlab/gitlabhq', id: '1') get('/gitlab/gitlabhq/snippets/1/raw').should route_to('projects/snippets#raw', project_id: 'gitlab/gitlabhq', id: '1')
end end
it "to #index" do it 'to #index' do
get("/gitlab/gitlabhq/snippets").should route_to("projects/snippets#index", project_id: 'gitlab/gitlabhq') get('/gitlab/gitlabhq/snippets').should route_to('projects/snippets#index', project_id: 'gitlab/gitlabhq')
end end
it "to #create" do it 'to #create' do
post("/gitlab/gitlabhq/snippets").should route_to("projects/snippets#create", project_id: 'gitlab/gitlabhq') post('/gitlab/gitlabhq/snippets').should route_to('projects/snippets#create', project_id: 'gitlab/gitlabhq')
end end
it "to #new" do it 'to #new' do
get("/gitlab/gitlabhq/snippets/new").should route_to("projects/snippets#new", project_id: 'gitlab/gitlabhq') get('/gitlab/gitlabhq/snippets/new').should route_to('projects/snippets#new', project_id: 'gitlab/gitlabhq')
end end
it "to #edit" do it 'to #edit' do
get("/gitlab/gitlabhq/snippets/1/edit").should route_to("projects/snippets#edit", project_id: 'gitlab/gitlabhq', id: '1') get('/gitlab/gitlabhq/snippets/1/edit').should route_to('projects/snippets#edit', project_id: 'gitlab/gitlabhq', id: '1')
end end
it "to #show" do it 'to #show' do
get("/gitlab/gitlabhq/snippets/1").should route_to("projects/snippets#show", project_id: 'gitlab/gitlabhq', id: '1') get('/gitlab/gitlabhq/snippets/1').should route_to('projects/snippets#show', project_id: 'gitlab/gitlabhq', id: '1')
end end
it "to #update" do it 'to #update' do
put("/gitlab/gitlabhq/snippets/1").should route_to("projects/snippets#update", project_id: 'gitlab/gitlabhq', id: '1') put('/gitlab/gitlabhq/snippets/1').should route_to('projects/snippets#update', project_id: 'gitlab/gitlabhq', id: '1')
end end
it "to #destroy" do it 'to #destroy' do
delete("/gitlab/gitlabhq/snippets/1").should route_to("projects/snippets#destroy", project_id: 'gitlab/gitlabhq', id: '1') delete('/gitlab/gitlabhq/snippets/1').should route_to('projects/snippets#destroy', project_id: 'gitlab/gitlabhq', id: '1')
end end
end end
...@@ -302,24 +302,24 @@ end ...@@ -302,24 +302,24 @@ end
# project_hooks GET /:project_id/hooks(.:format) hooks#index # project_hooks GET /:project_id/hooks(.:format) hooks#index
# POST /:project_id/hooks(.:format) hooks#create # POST /:project_id/hooks(.:format) hooks#create
# project_hook DELETE /:project_id/hooks/:id(.:format) hooks#destroy # project_hook DELETE /:project_id/hooks/:id(.:format) hooks#destroy
describe Projects::HooksController, "routing" do describe Projects::HooksController, 'routing' do
it "to #test" do it 'to #test' do
get("/gitlab/gitlabhq/hooks/1/test").should route_to('projects/hooks#test', project_id: 'gitlab/gitlabhq', id: '1') get('/gitlab/gitlabhq/hooks/1/test').should route_to('projects/hooks#test', project_id: 'gitlab/gitlabhq', id: '1')
end end
it_behaves_like "RESTful project resources" do it_behaves_like 'RESTful project resources' do
let(:actions) { [:index, :create, :destroy] } let(:actions) { [:index, :create, :destroy] }
let(:controller) { 'hooks' } let(:controller) { 'hooks' }
end end
end end
# project_commit GET /:project_id/commit/:id(.:format) commit#show {id: /[[:alnum:]]{6,40}/, project_id: /[^\/]+/} # project_commit GET /:project_id/commit/:id(.:format) commit#show {id: /[[:alnum:]]{6,40}/, project_id: /[^\/]+/}
describe Projects::CommitController, "routing" do describe Projects::CommitController, 'routing' do
it "to #show" do it 'to #show' do
get("/gitlab/gitlabhq/commit/4246fb").should route_to('projects/commit#show', project_id: 'gitlab/gitlabhq', id: '4246fb') get('/gitlab/gitlabhq/commit/4246fb').should route_to('projects/commit#show', project_id: 'gitlab/gitlabhq', id: '4246fb')
get("/gitlab/gitlabhq/commit/4246fb.diff").should route_to('projects/commit#show', project_id: 'gitlab/gitlabhq', id: '4246fb', format: 'diff') get('/gitlab/gitlabhq/commit/4246fb.diff').should route_to('projects/commit#show', project_id: 'gitlab/gitlabhq', id: '4246fb', format: 'diff')
get("/gitlab/gitlabhq/commit/4246fb.patch").should route_to('projects/commit#show', project_id: 'gitlab/gitlabhq', id: '4246fb', format: 'patch') get('/gitlab/gitlabhq/commit/4246fb.patch').should route_to('projects/commit#show', project_id: 'gitlab/gitlabhq', id: '4246fb', format: 'patch')
get("/gitlab/gitlabhq/commit/4246fbd13872934f72a8fd0d6fb1317b47b59cb5").should route_to('projects/commit#show', project_id: 'gitlab/gitlabhq', id: '4246fbd13872934f72a8fd0d6fb1317b47b59cb5') get('/gitlab/gitlabhq/commit/4246fbd13872934f72a8fd0d6fb1317b47b59cb5').should route_to('projects/commit#show', project_id: 'gitlab/gitlabhq', id: '4246fbd13872934f72a8fd0d6fb1317b47b59cb5')
end end
end end
...@@ -327,14 +327,14 @@ end ...@@ -327,14 +327,14 @@ end
# project_commits GET /:project_id/commits(.:format) commits#index # project_commits GET /:project_id/commits(.:format) commits#index
# POST /:project_id/commits(.:format) commits#create # POST /:project_id/commits(.:format) commits#create
# project_commit GET /:project_id/commits/:id(.:format) commits#show # project_commit GET /:project_id/commits/:id(.:format) commits#show
describe Projects::CommitsController, "routing" do describe Projects::CommitsController, 'routing' do
it_behaves_like "RESTful project resources" do it_behaves_like 'RESTful project resources' do
let(:actions) { [:show] } let(:actions) { [:show] }
let(:controller) { 'commits' } let(:controller) { 'commits' }
end end
it "to #show" do it 'to #show' do
get("/gitlab/gitlabhq/commits/master.atom").should route_to('projects/commits#show', project_id: 'gitlab/gitlabhq', id: "master", format: "atom") get('/gitlab/gitlabhq/commits/master.atom').should route_to('projects/commits#show', project_id: 'gitlab/gitlabhq', id: 'master', format: 'atom')
end end
end end
...@@ -345,8 +345,8 @@ end ...@@ -345,8 +345,8 @@ end
# project_team_member GET /:project_id/team_members/:id(.:format) team_members#show # project_team_member GET /:project_id/team_members/:id(.:format) team_members#show
# PUT /:project_id/team_members/:id(.:format) team_members#update # PUT /:project_id/team_members/:id(.:format) team_members#update
# DELETE /:project_id/team_members/:id(.:format) team_members#destroy # DELETE /:project_id/team_members/:id(.:format) team_members#destroy
describe Projects::TeamMembersController, "routing" do describe Projects::TeamMembersController, 'routing' do
it_behaves_like "RESTful project resources" do it_behaves_like 'RESTful project resources' do
let(:actions) { [:new, :create, :update, :destroy] } let(:actions) { [:new, :create, :update, :destroy] }
let(:controller) { 'team_members' } let(:controller) { 'team_members' }
end end
...@@ -359,17 +359,17 @@ end ...@@ -359,17 +359,17 @@ end
# project_milestone GET /:project_id/milestones/:id(.:format) milestones#show # project_milestone GET /:project_id/milestones/:id(.:format) milestones#show
# PUT /:project_id/milestones/:id(.:format) milestones#update # PUT /:project_id/milestones/:id(.:format) milestones#update
# DELETE /:project_id/milestones/:id(.:format) milestones#destroy # DELETE /:project_id/milestones/:id(.:format) milestones#destroy
describe Projects::MilestonesController, "routing" do describe Projects::MilestonesController, 'routing' do
it_behaves_like "RESTful project resources" do it_behaves_like 'RESTful project resources' do
let(:controller) { 'milestones' } let(:controller) { 'milestones' }
let(:actions) { [:index, :create, :new, :edit, :show, :update] } let(:actions) { [:index, :create, :new, :edit, :show, :update] }
end end
end end
# project_labels GET /:project_id/labels(.:format) labels#index # project_labels GET /:project_id/labels(.:format) labels#index
describe Projects::LabelsController, "routing" do describe Projects::LabelsController, 'routing' do
it "to #index" do it 'to #index' do
get("/gitlab/gitlabhq/labels").should route_to('projects/labels#index', project_id: 'gitlab/gitlabhq') get('/gitlab/gitlabhq/labels').should route_to('projects/labels#index', project_id: 'gitlab/gitlabhq')
end end
end end
...@@ -383,12 +383,12 @@ end ...@@ -383,12 +383,12 @@ end
# project_issue GET /:project_id/issues/:id(.:format) issues#show # project_issue GET /:project_id/issues/:id(.:format) issues#show
# PUT /:project_id/issues/:id(.:format) issues#update # PUT /:project_id/issues/:id(.:format) issues#update
# DELETE /:project_id/issues/:id(.:format) issues#destroy # DELETE /:project_id/issues/:id(.:format) issues#destroy
describe Projects::IssuesController, "routing" do describe Projects::IssuesController, 'routing' do
it "to #bulk_update" do it 'to #bulk_update' do
post("/gitlab/gitlabhq/issues/bulk_update").should route_to('projects/issues#bulk_update', project_id: 'gitlab/gitlabhq') post('/gitlab/gitlabhq/issues/bulk_update').should route_to('projects/issues#bulk_update', project_id: 'gitlab/gitlabhq')
end end
it_behaves_like "RESTful project resources" do it_behaves_like 'RESTful project resources' do
let(:controller) { 'issues' } let(:controller) { 'issues' }
let(:actions) { [:index, :create, :new, :edit, :show, :update] } let(:actions) { [:index, :create, :new, :edit, :show, :update] }
end end
...@@ -397,54 +397,50 @@ end ...@@ -397,54 +397,50 @@ end
# project_notes GET /:project_id/notes(.:format) notes#index # project_notes GET /:project_id/notes(.:format) notes#index
# POST /:project_id/notes(.:format) notes#create # POST /:project_id/notes(.:format) notes#create
# project_note DELETE /:project_id/notes/:id(.:format) notes#destroy # project_note DELETE /:project_id/notes/:id(.:format) notes#destroy
describe Projects::NotesController, "routing" do describe Projects::NotesController, 'routing' do
it_behaves_like "RESTful project resources" do it_behaves_like 'RESTful project resources' do
let(:actions) { [:index, :create, :destroy] } let(:actions) { [:index, :create, :destroy] }
let(:controller) { 'notes' } let(:controller) { 'notes' }
end end
end end
# project_blame GET /:project_id/blame/:id(.:format) blame#show {id: /.+/, project_id: /[^\/]+/} # project_blame GET /:project_id/blame/:id(.:format) blame#show {id: /.+/, project_id: /[^\/]+/}
describe Projects::BlameController, "routing" do describe Projects::BlameController, 'routing' do
it "to #show" do it 'to #show' do
get("/gitlab/gitlabhq/blame/master/app/models/project.rb").should route_to('projects/blame#show', project_id: 'gitlab/gitlabhq', id: 'master/app/models/project.rb') get('/gitlab/gitlabhq/blame/master/app/models/project.rb').should route_to('projects/blame#show', project_id: 'gitlab/gitlabhq', id: 'master/app/models/project.rb')
get("/gitlab/gitlabhq/blame/master/files.scss").should route_to('projects/blame#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss') get('/gitlab/gitlabhq/blame/master/files.scss').should route_to('projects/blame#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss')
end end
end end
# project_blob GET /:project_id/blob/:id(.:format) blob#show {id: /.+/, project_id: /[^\/]+/} # project_blob GET /:project_id/blob/:id(.:format) blob#show {id: /.+/, project_id: /[^\/]+/}
describe Projects::BlobController, "routing" do describe Projects::BlobController, 'routing' do
it "to #show" do it 'to #show' do
get("/gitlab/gitlabhq/blob/master/app/models/project.rb").should route_to('projects/blob#show', project_id: 'gitlab/gitlabhq', id: 'master/app/models/project.rb') get('/gitlab/gitlabhq/blob/master/app/models/project.rb').should route_to('projects/blob#show', project_id: 'gitlab/gitlabhq', id: 'master/app/models/project.rb')
get("/gitlab/gitlabhq/blob/master/app/models/compare.rb").should route_to('projects/blob#show', project_id: 'gitlab/gitlabhq', id: 'master/app/models/compare.rb') get('/gitlab/gitlabhq/blob/master/app/models/compare.rb').should route_to('projects/blob#show', project_id: 'gitlab/gitlabhq', id: 'master/app/models/compare.rb')
get("/gitlab/gitlabhq/blob/master/app/models/diff.js").should route_to('projects/blob#show', project_id: 'gitlab/gitlabhq', id: 'master/app/models/diff.js') get('/gitlab/gitlabhq/blob/master/app/models/diff.js').should route_to('projects/blob#show', project_id: 'gitlab/gitlabhq', id: 'master/app/models/diff.js')
get("/gitlab/gitlabhq/blob/master/files.scss").should route_to('projects/blob#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss') get('/gitlab/gitlabhq/blob/master/files.scss').should route_to('projects/blob#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss')
end end
end end
# project_tree GET /:project_id/tree/:id(.:format) tree#show {id: /.+/, project_id: /[^\/]+/} # project_tree GET /:project_id/tree/:id(.:format) tree#show {id: /.+/, project_id: /[^\/]+/}
describe Projects::TreeController, "routing" do describe Projects::TreeController, 'routing' do
it "to #show" do it 'to #show' do
get("/gitlab/gitlabhq/tree/master/app/models/project.rb").should route_to('projects/tree#show', project_id: 'gitlab/gitlabhq', id: 'master/app/models/project.rb') get('/gitlab/gitlabhq/tree/master/app/models/project.rb').should route_to('projects/tree#show', project_id: 'gitlab/gitlabhq', id: 'master/app/models/project.rb')
get("/gitlab/gitlabhq/tree/master/files.scss").should route_to('projects/tree#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss') get('/gitlab/gitlabhq/tree/master/files.scss').should route_to('projects/tree#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss')
end end
end end
describe Projects::EditTreeController, 'routing' do describe Projects::BlobController, 'routing' do
it 'to #show' do it 'to #edit' do
get('/gitlab/gitlabhq/edit/master/app/models/project.rb').should( get('/gitlab/gitlabhq/edit/master/app/models/project.rb').should(
route_to('projects/edit_tree#show', route_to('projects/blob#edit',
project_id: 'gitlab/gitlabhq', project_id: 'gitlab/gitlabhq',
id: 'master/app/models/project.rb')) id: 'master/app/models/project.rb'))
get('/gitlab/gitlabhq/edit/master/app/models/project.rb/preview').should(
route_to('projects/edit_tree#show',
project_id: 'gitlab/gitlabhq',
id: 'master/app/models/project.rb/preview'))
end end
it 'to #preview' do it 'to #preview' do
post('/gitlab/gitlabhq/edit/master/app/models/project.rb/preview').should( post('/gitlab/gitlabhq/preview/master/app/models/project.rb').should(
route_to('projects/edit_tree#preview', route_to('projects/blob#preview',
project_id: 'gitlab/gitlabhq', project_id: 'gitlab/gitlabhq',
id: 'master/app/models/project.rb')) id: 'master/app/models/project.rb'))
end end
...@@ -453,40 +449,48 @@ end ...@@ -453,40 +449,48 @@ end
# project_compare_index GET /:project_id/compare(.:format) compare#index {id: /[^\/]+/, project_id: /[^\/]+/} # project_compare_index GET /:project_id/compare(.:format) compare#index {id: /[^\/]+/, project_id: /[^\/]+/}
# POST /:project_id/compare(.:format) compare#create {id: /[^\/]+/, project_id: /[^\/]+/} # POST /:project_id/compare(.:format) compare#create {id: /[^\/]+/, project_id: /[^\/]+/}
# project_compare /:project_id/compare/:from...:to(.:format) compare#show {from: /.+/, to: /.+/, id: /[^\/]+/, project_id: /[^\/]+/} # project_compare /:project_id/compare/:from...:to(.:format) compare#show {from: /.+/, to: /.+/, id: /[^\/]+/, project_id: /[^\/]+/}
describe Projects::CompareController, "routing" do describe Projects::CompareController, 'routing' do
it "to #index" do it 'to #index' do
get("/gitlab/gitlabhq/compare").should route_to('projects/compare#index', project_id: 'gitlab/gitlabhq') get('/gitlab/gitlabhq/compare').should route_to('projects/compare#index', project_id: 'gitlab/gitlabhq')
end end
it "to #compare" do it 'to #compare' do
post("/gitlab/gitlabhq/compare").should route_to('projects/compare#create', project_id: 'gitlab/gitlabhq') post('/gitlab/gitlabhq/compare').should route_to('projects/compare#create', project_id: 'gitlab/gitlabhq')
end end
it "to #show" do it 'to #show' do
get("/gitlab/gitlabhq/compare/master...stable").should route_to('projects/compare#show', project_id: 'gitlab/gitlabhq', from: 'master', to: 'stable') get('/gitlab/gitlabhq/compare/master...stable').should route_to('projects/compare#show', project_id: 'gitlab/gitlabhq', from: 'master', to: 'stable')
get("/gitlab/gitlabhq/compare/issue/1234...stable").should route_to('projects/compare#show', project_id: 'gitlab/gitlabhq', from: 'issue/1234', to: 'stable') get('/gitlab/gitlabhq/compare/issue/1234...stable').should route_to('projects/compare#show', project_id: 'gitlab/gitlabhq', from: 'issue/1234', to: 'stable')
end end
end end
describe Projects::NetworkController, "routing" do describe Projects::NetworkController, 'routing' do
it "to #show" do it 'to #show' do
get("/gitlab/gitlabhq/network/master").should route_to('projects/network#show', project_id: 'gitlab/gitlabhq', id: 'master') get('/gitlab/gitlabhq/network/master').should route_to('projects/network#show', project_id: 'gitlab/gitlabhq', id: 'master')
get("/gitlab/gitlabhq/network/master.json").should route_to('projects/network#show', project_id: 'gitlab/gitlabhq', id: 'master', format: "json") get('/gitlab/gitlabhq/network/master.json').should route_to('projects/network#show', project_id: 'gitlab/gitlabhq', id: 'master', format: 'json')
end end
end end
describe Projects::GraphsController, "routing" do describe Projects::GraphsController, 'routing' do
it "to #show" do it 'to #show' do
get("/gitlab/gitlabhq/graphs/master").should route_to('projects/graphs#show', project_id: 'gitlab/gitlabhq', id: 'master') get('/gitlab/gitlabhq/graphs/master').should route_to('projects/graphs#show', project_id: 'gitlab/gitlabhq', id: 'master')
end end
end end
describe Projects::ForksController, "routing" do describe Projects::ForksController, 'routing' do
it "to #new" do it 'to #new' do
get("/gitlab/gitlabhq/fork/new").should route_to("projects/forks#new", project_id: 'gitlab/gitlabhq') get('/gitlab/gitlabhq/fork/new').should route_to('projects/forks#new', project_id: 'gitlab/gitlabhq')
end
it 'to #create' do
post('/gitlab/gitlabhq/fork').should route_to('projects/forks#create', project_id: 'gitlab/gitlabhq')
end end
end
it "to #create" do # project_avatar DELETE /project/avatar(.:format) projects/avatars#destroy
post("/gitlab/gitlabhq/fork").should route_to("projects/forks#create", project_id: 'gitlab/gitlabhq') describe Projects::AvatarsController, 'routing' do
it 'to #destroy' do
delete('/gitlab/gitlabhq/avatar').should route_to(
'projects/avatars#destroy', project_id: 'gitlab/gitlabhq')
end end
end end
...@@ -22,6 +22,7 @@ describe Issues::UpdateService do ...@@ -22,6 +22,7 @@ describe Issues::UpdateService do
} }
@issue = Issues::UpdateService.new(project, user, opts).execute(issue) @issue = Issues::UpdateService.new(project, user, opts).execute(issue)
@issue.reload
end end
it { @issue.should be_valid } it { @issue.should be_valid }
......
...@@ -21,12 +21,14 @@ describe MergeRequests::UpdateService do ...@@ -21,12 +21,14 @@ describe MergeRequests::UpdateService do
state_event: 'close' state_event: 'close'
} }
end end
let(:service) { MergeRequests::UpdateService.new(project, user, opts) } let(:service) { MergeRequests::UpdateService.new(project, user, opts) }
before do before do
service.stub(:execute_hooks) service.stub(:execute_hooks)
@merge_request = service.execute(merge_request) @merge_request = service.execute(merge_request)
@merge_request.reload
end end
it { @merge_request.should be_valid } it { @merge_request.should be_valid }
......
...@@ -187,7 +187,7 @@ describe NotificationService do ...@@ -187,7 +187,7 @@ describe NotificationService do
end end
describe 'Issues' do describe 'Issues' do
let(:issue) { create :issue, assignee: create(:user) } let(:issue) { create :issue, assignee: create(:user), description: 'cc @participant' }
before do before do
build_team(issue.project) build_team(issue.project)
...@@ -197,6 +197,7 @@ describe NotificationService do ...@@ -197,6 +197,7 @@ describe NotificationService do
it do it do
should_email(issue.assignee_id) should_email(issue.assignee_id)
should_email(@u_watcher.id) should_email(@u_watcher.id)
should_email(@u_participant_mentioned.id)
should_not_email(@u_mentioned.id) should_not_email(@u_mentioned.id)
should_not_email(@u_participating.id) should_not_email(@u_participating.id)
should_not_email(@u_disabled.id) should_not_email(@u_disabled.id)
...@@ -222,6 +223,7 @@ describe NotificationService do ...@@ -222,6 +223,7 @@ describe NotificationService do
it 'should email new assignee' do it 'should email new assignee' do
should_email(issue.assignee_id) should_email(issue.assignee_id)
should_email(@u_watcher.id) should_email(@u_watcher.id)
should_email(@u_participant_mentioned.id)
should_not_email(@u_participating.id) should_not_email(@u_participating.id)
should_not_email(@u_disabled.id) should_not_email(@u_disabled.id)
...@@ -242,6 +244,7 @@ describe NotificationService do ...@@ -242,6 +244,7 @@ describe NotificationService do
should_email(issue.assignee_id) should_email(issue.assignee_id)
should_email(issue.author_id) should_email(issue.author_id)
should_email(@u_watcher.id) should_email(@u_watcher.id)
should_email(@u_participant_mentioned.id)
should_not_email(@u_participating.id) should_not_email(@u_participating.id)
should_not_email(@u_disabled.id) should_not_email(@u_disabled.id)
...@@ -262,6 +265,7 @@ describe NotificationService do ...@@ -262,6 +265,7 @@ describe NotificationService do
should_email(issue.assignee_id) should_email(issue.assignee_id)
should_email(issue.author_id) should_email(issue.author_id)
should_email(@u_watcher.id) should_email(@u_watcher.id)
should_email(@u_participant_mentioned.id)
should_not_email(@u_participating.id) should_not_email(@u_participating.id)
should_not_email(@u_disabled.id) should_not_email(@u_disabled.id)
...@@ -404,6 +408,7 @@ describe NotificationService do ...@@ -404,6 +408,7 @@ describe NotificationService do
def build_team(project) def build_team(project)
@u_watcher = create(:user, notification_level: Notification::N_WATCH) @u_watcher = create(:user, notification_level: Notification::N_WATCH)
@u_participating = create(:user, notification_level: Notification::N_PARTICIPATING) @u_participating = create(:user, notification_level: Notification::N_PARTICIPATING)
@u_participant_mentioned = create(:user, username: 'participant', notification_level: Notification::N_PARTICIPATING)
@u_disabled = create(:user, notification_level: Notification::N_DISABLED) @u_disabled = create(:user, notification_level: Notification::N_DISABLED)
@u_mentioned = create(:user, username: 'mention', notification_level: Notification::N_MENTION) @u_mentioned = create(:user, username: 'mention', notification_level: Notification::N_MENTION)
@u_committer = create(:user, username: 'committer') @u_committer = create(:user, username: 'committer')
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment