Commit c70dcd29 authored by Marin Jankovski's avatar Marin Jankovski

Merge branch 'master' into move_external_issue_tracker_away_from_yml_config

parents a720dde6 25a5c848
...@@ -11,16 +11,17 @@ v 7.8.0 ...@@ -11,16 +11,17 @@ v 7.8.0
- -
- -
- -
- Allow more variations for commit messages closing issues (Julien Bianchi and 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)
- -
- -
- -
- -
- - Upgrade Sidekiq gem to version 3.3.0
- - Stop git zombie creation during force push check
-
-
- -
- -
- Fix commits pagination - Fix commits pagination
...@@ -47,16 +48,22 @@ v 7.8.0 ...@@ -47,16 +48,22 @@ v 7.8.0
- -
- -
- -
- Add a new API function that retrieves all issues assigned to a single milestone (Justin Whear and Hannes Rosenögger)
- -
- -
- -
- -
- -
- -
- API: Add support for editing an existing project (Mika Mäenpää and Hannes Rosenögger)
- -
- -
- -
-
v 7.7.1
- Improve mention autocomplete performance
- Show setup instructions for GitHub import if disabled
- Allow use http for OAuth applications
v 7.7.0 v 7.7.0
- Import from GitHub.com feature - Import from GitHub.com feature
......
...@@ -118,7 +118,7 @@ gem "acts-as-taggable-on" ...@@ -118,7 +118,7 @@ gem "acts-as-taggable-on"
# Background jobs # Background jobs
gem 'slim' gem 'slim'
gem 'sinatra', require: nil gem 'sinatra', require: nil
gem 'sidekiq', '2.17.8' gem 'sidekiq', '~> 3.3'
# HTTP requests # HTTP requests
gem "httparty" gem "httparty"
......
...@@ -62,8 +62,8 @@ GEM ...@@ -62,8 +62,8 @@ GEM
activemodel (>= 3.2.0) activemodel (>= 3.2.0)
activesupport (>= 3.2.0) activesupport (>= 3.2.0)
json (>= 1.7) json (>= 1.7)
celluloid (0.15.2) celluloid (0.16.0)
timers (~> 1.1.0) timers (~> 4.0.0)
charlock_holmes (0.6.9.4) charlock_holmes (0.6.9.4)
cliver (0.3.2) cliver (0.3.2)
code_analyzer (0.4.3) code_analyzer (0.4.3)
...@@ -244,6 +244,7 @@ GEM ...@@ -244,6 +244,7 @@ GEM
hike (1.2.3) hike (1.2.3)
hipchat (1.4.0) hipchat (1.4.0)
httparty httparty
hitimes (1.2.2)
html-pipeline (1.11.0) html-pipeline (1.11.0)
activesupport (>= 2) activesupport (>= 2)
nokogiri (~> 1.4) nokogiri (~> 1.4)
...@@ -495,12 +496,12 @@ GEM ...@@ -495,12 +496,12 @@ GEM
sexp_processor (4.4.0) sexp_processor (4.4.0)
shoulda-matchers (2.1.0) shoulda-matchers (2.1.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
sidekiq (2.17.8) sidekiq (3.3.0)
celluloid (= 0.15.2) celluloid (>= 0.16.0)
connection_pool (~> 2.0) connection_pool (>= 2.0.0)
json json
redis (~> 3.1) redis (>= 3.0.6)
redis-namespace (~> 1.3) redis-namespace (>= 1.3.1)
simple_oauth (0.1.9) simple_oauth (0.1.9)
simplecov (0.9.0) simplecov (0.9.0)
docile (~> 1.1.0) docile (~> 1.1.0)
...@@ -555,7 +556,8 @@ GEM ...@@ -555,7 +556,8 @@ GEM
thor (0.19.1) thor (0.19.1)
thread_safe (0.3.4) thread_safe (0.3.4)
tilt (1.4.1) tilt (1.4.1)
timers (1.1.0) timers (4.0.1)
hitimes
timfel-krb5-auth (0.8) timfel-krb5-auth (0.8)
tinder (1.9.3) tinder (1.9.3)
eventmachine (~> 1.0) eventmachine (~> 1.0)
...@@ -716,7 +718,7 @@ DEPENDENCIES ...@@ -716,7 +718,7 @@ DEPENDENCIES
semantic-ui-sass (~> 0.16.1.0) semantic-ui-sass (~> 0.16.1.0)
settingslogic settingslogic
shoulda-matchers (~> 2.1.0) shoulda-matchers (~> 2.1.0)
sidekiq (= 2.17.8) sidekiq (~> 3.3)
simplecov simplecov
sinatra sinatra
six six
......
app/assets/images/bg-header.png

210 Bytes | W: | H:

app/assets/images/bg-header.png

90 Bytes | W: | H:

app/assets/images/bg-header.png
app/assets/images/bg-header.png
app/assets/images/bg-header.png
app/assets/images/bg-header.png
  • 2-up
  • Swipe
  • Onion skin
app/assets/images/bg_fallback.png

2.91 KB | W: | H:

app/assets/images/bg_fallback.png

167 Bytes | W: | H:

app/assets/images/bg_fallback.png
app/assets/images/bg_fallback.png
app/assets/images/bg_fallback.png
app/assets/images/bg_fallback.png
  • 2-up
  • Swipe
  • Onion skin
app/assets/images/brand_logo.png

31.4 KB | W: | H:

app/assets/images/brand_logo.png

26.4 KB | W: | H:

app/assets/images/brand_logo.png
app/assets/images/brand_logo.png
app/assets/images/brand_logo.png
app/assets/images/brand_logo.png
  • 2-up
  • Swipe
  • Onion skin
app/assets/images/chosen-sprite.png

396 Bytes | W: | H:

app/assets/images/chosen-sprite.png

367 Bytes | W: | H:

app/assets/images/chosen-sprite.png
app/assets/images/chosen-sprite.png
app/assets/images/chosen-sprite.png
app/assets/images/chosen-sprite.png
  • 2-up
  • Swipe
  • Onion skin
app/assets/images/diff_note_add.png

691 Bytes | W: | H:

app/assets/images/diff_note_add.png

418 Bytes | W: | H:

app/assets/images/diff_note_add.png
app/assets/images/diff_note_add.png
app/assets/images/diff_note_add.png
app/assets/images/diff_note_add.png
  • 2-up
  • Swipe
  • Onion skin
app/assets/images/icon-link.png

1019 Bytes | W: | H:

app/assets/images/icon-link.png

726 Bytes | W: | H:

app/assets/images/icon-link.png
app/assets/images/icon-link.png
app/assets/images/icon-link.png
app/assets/images/icon-link.png
  • 2-up
  • Swipe
  • Onion skin
app/assets/images/icon-search.png

331 Bytes | W: | H:

app/assets/images/icon-search.png

222 Bytes | W: | H:

app/assets/images/icon-search.png
app/assets/images/icon-search.png
app/assets/images/icon-search.png
app/assets/images/icon-search.png
  • 2-up
  • Swipe
  • Onion skin
app/assets/images/icon_sprite.png

2.72 KB | W: | H:

app/assets/images/icon_sprite.png

2.57 KB | W: | H:

app/assets/images/icon_sprite.png
app/assets/images/icon_sprite.png
app/assets/images/icon_sprite.png
app/assets/images/icon_sprite.png
  • 2-up
  • Swipe
  • Onion skin
app/assets/images/images.png

6.49 KB | W: | H:

app/assets/images/images.png

5.71 KB | W: | H:

app/assets/images/images.png
app/assets/images/images.png
app/assets/images/images.png
app/assets/images/images.png
  • 2-up
  • Swipe
  • Onion skin
app/assets/images/logo-black.png

2.73 KB | W: | H:

app/assets/images/logo-black.png

2.55 KB | W: | H:

app/assets/images/logo-black.png
app/assets/images/logo-black.png
app/assets/images/logo-black.png
app/assets/images/logo-black.png
  • 2-up
  • Swipe
  • Onion skin
app/assets/images/logo-white.png

7.33 KB | W: | H:

app/assets/images/logo-white.png

7.16 KB | W: | H:

app/assets/images/logo-white.png
app/assets/images/logo-white.png
app/assets/images/logo-white.png
app/assets/images/logo-white.png
  • 2-up
  • Swipe
  • Onion skin
app/assets/images/move.png

260 Bytes | W: | H:

app/assets/images/move.png

197 Bytes | W: | H:

app/assets/images/move.png
app/assets/images/move.png
app/assets/images/move.png
app/assets/images/move.png
  • 2-up
  • Swipe
  • Onion skin
app/assets/images/no_avatar.png

704 Bytes | W: | H:

app/assets/images/no_avatar.png

621 Bytes | W: | H:

app/assets/images/no_avatar.png
app/assets/images/no_avatar.png
app/assets/images/no_avatar.png
app/assets/images/no_avatar.png
  • 2-up
  • Swipe
  • Onion skin
app/assets/images/no_group_avatar.png

4.77 KB | W: | H:

app/assets/images/no_group_avatar.png

942 Bytes | W: | H:

app/assets/images/no_group_avatar.png
app/assets/images/no_group_avatar.png
app/assets/images/no_group_avatar.png
app/assets/images/no_group_avatar.png
  • 2-up
  • Swipe
  • Onion skin
app/assets/images/slider_handles.png

4.03 KB | W: | H:

app/assets/images/slider_handles.png

1.34 KB | W: | H:

app/assets/images/slider_handles.png
app/assets/images/slider_handles.png
app/assets/images/slider_handles.png
app/assets/images/slider_handles.png
  • 2-up
  • Swipe
  • Onion skin
app/assets/images/switch_icon.png

1.17 KB | W: | H:

app/assets/images/switch_icon.png

231 Bytes | W: | H:

app/assets/images/switch_icon.png
app/assets/images/switch_icon.png
app/assets/images/switch_icon.png
app/assets/images/switch_icon.png
  • 2-up
  • Swipe
  • Onion skin
app/assets/images/trans_bg.gif

50 Bytes | W: | H:

app/assets/images/trans_bg.gif

49 Bytes | W: | H:

app/assets/images/trans_bg.gif
app/assets/images/trans_bg.gif
app/assets/images/trans_bg.gif
app/assets/images/trans_bg.gif
  • 2-up
  • Swipe
  • Onion skin
...@@ -74,24 +74,18 @@ window.disableButtonIfEmptyField = (field_selector, button_selector) -> ...@@ -74,24 +74,18 @@ window.disableButtonIfEmptyField = (field_selector, button_selector) ->
# Disable button if any input field with given selector is empty # Disable button if any input field with given selector is empty
window.disableButtonIfAnyEmptyField = (form, form_selector, button_selector) -> window.disableButtonIfAnyEmptyField = (form, form_selector, button_selector) ->
closest_submit = form.find(button_selector) closest_submit = form.find(button_selector)
empty = false updateButtons = ->
form.find('input').filter(form_selector).each -> filled = true
empty = true if rstrip($(this).val()) is ""
if empty
closest_submit.disable()
else
closest_submit.enable()
form.keyup ->
empty = false
form.find('input').filter(form_selector).each -> form.find('input').filter(form_selector).each ->
empty = true if rstrip($(this).val()) is "" filled = rstrip($(this).val()) != "" || !$(this).attr('required')
if empty if filled
closest_submit.disable()
else
closest_submit.enable() closest_submit.enable()
else
closest_submit.disable()
updateButtons()
form.keyup(updateButtons)
window.sanitize = (str) -> window.sanitize = (str) ->
return str.replace(/<(?:.|\n)*?>/gm, '') return str.replace(/<(?:.|\n)*?>/gm, '')
......
...@@ -2,8 +2,9 @@ ...@@ -2,8 +2,9 @@
float: left; float: left;
margin-right: 12px; margin-right: 12px;
width: 40px; width: 40px;
padding: 1px; height: 40px;
@include border-radius(4px); padding: 0;
@include border-radius($avatar_radius);
&.avatar-inline { &.avatar-inline {
float: none; float: none;
......
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
background: #fff; background: #fff;
color: #737881; color: #737881;
float: left; float: left;
@include border-radius(40px); @include border-radius($avatar_radius);
@include box-shadow(0 0 0 3px #EEE); @include box-shadow(0 0 0 3px #EEE);
overflow: hidden; overflow: hidden;
...@@ -58,6 +58,10 @@ ...@@ -58,6 +58,10 @@
padding: 10px 15px; padding: 10px 15px;
margin-left: 60px; margin-left: 60px;
img {
max-width: 100%;
}
&:after { &:after {
content: ''; content: '';
display: block; display: block;
......
...@@ -128,3 +128,7 @@ a:focus { ...@@ -128,3 +128,7 @@ a:focus {
textarea.js-gfm-input { textarea.js-gfm-input {
font-family: $monospace_font; font-family: $monospace_font;
} }
.strikethrough {
text-decoration: line-through;
}
\ No newline at end of file
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* General Colors * General Colors
*/ */
$style_color: #474D57; $style_color: #474D57;
$hover: #FFECDB; $hover: #FFF3EB;
$box_bg: #F9F9F9; $box_bg: #F9F9F9;
/* /*
...@@ -56,4 +56,6 @@ $list-font-size: 15px; ...@@ -56,4 +56,6 @@ $list-font-size: 15px;
/** /**
* Sidebar navigation width * Sidebar navigation width
*/ */
$sidebar_width: 240px; $sidebar_width: 230px;
$avatar_radius: 50%;
...@@ -101,7 +101,6 @@ ...@@ -101,7 +101,6 @@
.commit-title { .commit-title {
margin: 0; margin: 0;
font-size: 20px;
} }
.commit-description { .commit-description {
......
...@@ -140,7 +140,7 @@ header { ...@@ -140,7 +140,7 @@ header {
img { img {
width: 26px; width: 26px;
height: 26px; height: 26px;
@include border-radius(4px); @include border-radius($avatar_radius);
} }
} }
......
...@@ -52,6 +52,10 @@ ...@@ -52,6 +52,10 @@
} }
} }
img {
max-width: 100%;
}
.note_text { .note_text {
width: 100%; width: 100%;
} }
......
...@@ -102,12 +102,3 @@ ...@@ -102,12 +102,3 @@
} }
} }
} }
.profile-groups-avatars {
margin: 0 5px 10px 0;
img {
width: 50px;
height: 50px;
}
}
...@@ -49,7 +49,7 @@ class ApplicationController < ActionController::Base ...@@ -49,7 +49,7 @@ class ApplicationController < ActionController::Base
end end
def authenticate_user!(*args) def authenticate_user!(*args)
# If user is not signe-in and tries to access root_path - redirect him to landing page # If user is not signed-in and tries to access root_path - redirect him to landing page
if current_application_settings.home_page_url.present? if current_application_settings.home_page_url.present?
if current_user.nil? && controller_name == 'dashboard' && action_name == 'show' if current_user.nil? && controller_name == 'dashboard' && action_name == 'show'
redirect_to current_application_settings.home_page_url and return redirect_to current_application_settings.home_page_url and return
......
...@@ -63,11 +63,11 @@ class GithubImportsController < ApplicationController ...@@ -63,11 +63,11 @@ class GithubImportsController < ApplicationController
def github_auth def github_auth
if current_user.github_access_token.blank? if current_user.github_access_token.blank?
go_to_gihub_for_permissions go_to_github_for_permissions
end end
end end
def go_to_gihub_for_permissions def go_to_github_for_permissions
redirect_to client.auth_code.authorize_url({ redirect_to client.auth_code.authorize_url({
redirect_uri: callback_github_import_url, redirect_uri: callback_github_import_url,
scope: "repo, user, user:email" scope: "repo, user, user:email"
...@@ -75,6 +75,6 @@ class GithubImportsController < ApplicationController ...@@ -75,6 +75,6 @@ class GithubImportsController < ApplicationController
end end
def github_unauthorized def github_unauthorized
go_to_gihub_for_permissions go_to_github_for_permissions
end end
end end
...@@ -12,6 +12,7 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -12,6 +12,7 @@ class Projects::CommitController < Projects::ApplicationController
@line_notes = @project.notes.for_commit_id(commit.id).inline @line_notes = @project.notes.for_commit_id(commit.id).inline
@branches = @project.repository.branch_names_contains(commit.id) @branches = @project.repository.branch_names_contains(commit.id)
@tags = @project.repository.tag_names_contains(commit.id)
@diffs = @commit.diffs @diffs = @commit.diffs
@note = @project.build_commit_note(commit) @note = @project.build_commit_note(commit)
@notes_count = @project.notes.for_commit_id(commit.id).count @notes_count = @project.notes.for_commit_id(commit.id).count
......
...@@ -233,13 +233,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -233,13 +233,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
def allowed_to_push_code?(project, branch) def allowed_to_push_code?(project, branch)
action = if project.protected_branch?(branch) ::Gitlab::GitAccess.can_push_to_branch?(current_user, project, branch)
:push_code_to_protected_branches
else
:push_code
end
can?(current_user, action, project)
end end
def merge_request_params def merge_request_params
......
...@@ -41,9 +41,9 @@ class Projects::RefsController < Projects::ApplicationController ...@@ -41,9 +41,9 @@ class Projects::RefsController < Projects::ApplicationController
@path = params[:path] @path = params[:path]
contents = [] contents = []
contents += tree.trees contents.push(*tree.trees)
contents += tree.blobs contents.push(*tree.blobs)
contents += tree.submodules contents.push(*tree.submodules)
@logs = contents[@offset, @limit].to_a.map do |content| @logs = contents[@offset, @limit].to_a.map do |content|
file = @path ? File.join(@path, content.name) : content.name file = @path ? File.join(@path, content.name) : content.name
......
...@@ -101,11 +101,20 @@ class ProjectsController < ApplicationController ...@@ -101,11 +101,20 @@ class ProjectsController < ApplicationController
def autocomplete_sources def autocomplete_sources
note_type = params['type'] note_type = params['type']
note_id = params['type_id'] note_id = params['type_id']
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: Emoji.names.map { |e| { name: e, path: view_context.image_url("emoji/#{e}.png") } }, emojis: emojis,
issues: @project.issues.select([:iid, :title, :description]), issues: autocomplete.issues,
mergerequests: @project.merge_requests.select([:iid, :title, :description]), mergerequests: autocomplete.merge_requests,
members: participants members: participants
} }
......
...@@ -11,12 +11,7 @@ module BranchesHelper ...@@ -11,12 +11,7 @@ module BranchesHelper
def can_push_branch?(project, branch_name) def can_push_branch?(project, branch_name)
return false unless project.repository.branch_names.include?(branch_name) return false unless project.repository.branch_names.include?(branch_name)
action = if project.protected_branch?(branch_name)
:push_code_to_protected_branches ::Gitlab::GitAccess.can_push_to_branch?(current_user, project, branch_name)
else
:push_code
end
current_user.can?(action, project)
end end
end end
...@@ -44,7 +44,7 @@ module CommitsHelper ...@@ -44,7 +44,7 @@ module CommitsHelper
parts = @path.split('/') parts = @path.split('/')
parts.each_with_index do |part, i| parts.each_with_index do |part, i|
crumbs += content_tag(:li) do crumbs << content_tag(:li) do
# The text is just the individual part, but the link needs all the parts before it # The text is just the individual part, but the link needs all the parts before it
link_to part, project_commits_path(@project, tree_join(@ref, parts[0..i].join('/'))) link_to part, project_commits_path(@project, tree_join(@ref, parts[0..i].join('/')))
end end
...@@ -62,7 +62,27 @@ module CommitsHelper ...@@ -62,7 +62,27 @@ module CommitsHelper
# Returns the sorted alphabetically links to branches, separated by a comma # Returns the sorted alphabetically links to branches, separated by a comma
def commit_branches_links(project, branches) def commit_branches_links(project, branches)
branches.sort.map { |branch| link_to(branch, project_tree_path(project, branch)) }.join(", ").html_safe branches.sort.map do |branch|
link_to(project_tree_path(project, branch)) do
content_tag :span, class: 'label label-gray' do
content_tag(:i, nil, class: 'fa fa-code-fork') + ' ' +
branch
end
end
end.join(" ").html_safe
end
# Returns the sorted links to tags, separated by a comma
def commit_tags_links(project, tags)
sorted = VersionSorter.rsort(tags)
sorted.map do |tag|
link_to(project_commits_path(project, project.repository.find_tag(tag).name)) do
content_tag :span, class: 'label label-gray' do
content_tag(:i, nil, class: 'fa fa-tag') + ' ' +
tag
end
end
end.join(" ").html_safe
end end
def link_to_browse_code(project, commit) def link_to_browse_code(project, commit)
......
...@@ -135,4 +135,19 @@ module DiffHelper ...@@ -135,4 +135,19 @@ module DiffHelper
'Side-by-side' 'Side-by-side'
end end
end end
def submodule_link(blob, ref)
tree, commit = submodule_links(blob, ref)
commit_id = if commit.nil?
blob.id[0..10]
else
link_to "#{blob.id[0..10]}", commit
end
[
content_tag(:span, link_to(truncate(blob.name, length: 40), tree)),
'@',
content_tag(:span, commit_id, class: 'monospace'),
].join(' ').html_safe
end
end end
module GraphHelper module GraphHelper
def get_refs(repo, commit) def get_refs(repo, commit)
refs = "" refs = ""
refs += commit.ref_names(repo).join(" ") refs << commit.ref_names(repo).join(' ')
# append note count # append note count
refs += "[#{@graph.notes[commit.id]}]" if @graph.notes[commit.id] > 0 refs << "[#{@graph.notes[commit.id]}]" if @graph.notes[commit.id] > 0
refs refs
end end
......
...@@ -74,7 +74,7 @@ module ProjectsHelper ...@@ -74,7 +74,7 @@ module ProjectsHelper
def link_to_toggle_star(title, starred, signed_in) def link_to_toggle_star(title, starred, signed_in)
cls = 'star-btn' cls = 'star-btn'
cls += ' disabled' unless signed_in cls << ' disabled' unless signed_in
toggle_html = content_tag('span', class: 'toggle') do toggle_html = content_tag('span', class: 'toggle') do
toggle_text = if starred toggle_text = if starred
......
...@@ -2,8 +2,8 @@ module SubmoduleHelper ...@@ -2,8 +2,8 @@ module SubmoduleHelper
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
# links to files listing for submodule if submodule is a project on this server # links to files listing for submodule if submodule is a project on this server
def submodule_links(submodule_item) def submodule_links(submodule_item, ref = nil)
url = @repository.submodule_url_for(@ref, submodule_item.path) url = @repository.submodule_url_for(ref, submodule_item.path)
return url, nil unless url =~ /([^\/:]+\/[^\/]+\.git)\Z/ return url, nil unless url =~ /([^\/:]+\/[^\/]+\.git)\Z/
......
...@@ -6,7 +6,7 @@ module TagsHelper ...@@ -6,7 +6,7 @@ module TagsHelper
def tag_list(project) def tag_list(project)
html = '' html = ''
project.tag_list.each do |tag| project.tag_list.each do |tag|
html += link_to tag, tag_path(tag) html << link_to(tag, tag_path(tag))
end end
html.html_safe html.html_safe
......
...@@ -10,13 +10,16 @@ module TreeHelper ...@@ -10,13 +10,16 @@ module TreeHelper
tree = "" tree = ""
# Render folders if we have any # Render folders if we have any
tree += render partial: 'projects/tree/tree_item', collection: folders, locals: {type: 'folder'} if folders.present? tree << render(partial: 'projects/tree/tree_item', collection: folders,
locals: { type: 'folder' }) if folders.present?
# Render files if we have any # Render files if we have any
tree += render partial: 'projects/tree/blob_item', collection: files, locals: {type: 'file'} if files.present? tree << render(partial: 'projects/tree/blob_item', collection: files,
locals: { type: 'file' }) if files.present?
# Render submodules if we have any # Render submodules if we have any
tree += render partial: 'projects/tree/submodule_item', collection: submodules if submodules.present? tree << render(partial: 'projects/tree/submodule_item',
collection: submodules) if submodules.present?
tree.html_safe tree.html_safe
end end
...@@ -58,11 +61,7 @@ module TreeHelper ...@@ -58,11 +61,7 @@ module TreeHelper
ref ||= @ref ref ||= @ref
return false unless project.repository.branch_names.include?(ref) return false unless project.repository.branch_names.include?(ref)
if project.protected_branch? ref ::Gitlab::GitAccess.can_push_to_branch?(current_user, project, ref)
can?(current_user, :push_code_to_protected_branches, project)
else
can?(current_user, :push_code, project)
end
end end
def edit_blob_link(project, ref, path, options = {}) def edit_blob_link(project, ref, path, options = {})
...@@ -113,7 +112,7 @@ module TreeHelper ...@@ -113,7 +112,7 @@ module TreeHelper
tree_join(@ref, file) tree_join(@ref, file)
end end
# returns the relative path of the first subdir that doesn't have only one directory descendand # returns the relative path of the first subdir that doesn't have only one directory descendant
def flatten_tree(tree) def flatten_tree(tree)
subtree = Gitlab::Git::Tree.where(@repository, @commit.id, tree.path) subtree = Gitlab::Git::Tree.where(@repository, @commit.id, tree.path)
if subtree.count == 1 && subtree.first.dir? if subtree.count == 1 && subtree.first.dir?
......
...@@ -56,7 +56,7 @@ module Emails ...@@ -56,7 +56,7 @@ module Emails
end end
end end
# Over rides default behavour to show source/target # Over rides default behaviour to show source/target
# Formats arguments into a String suitable for use as an email subject # Formats arguments into a String suitable for use as an email subject
# #
# extra - Extra Strings to be inserted into the subject # extra - Extra Strings to be inserted into the subject
......
...@@ -26,8 +26,8 @@ class Notify < ActionMailer::Base ...@@ -26,8 +26,8 @@ class Notify < ActionMailer::Base
delay_for(2.seconds) delay_for(2.seconds)
end end
def test_email(recepient_email, subject, body) def test_email(recipient_email, subject, body)
mail(to: recepient_email, mail(to: recipient_email,
subject: subject, subject: subject,
body: body.html_safe, body: body.html_safe,
content_type: 'text/html' content_type: 'text/html'
......
...@@ -73,28 +73,28 @@ class Ability ...@@ -73,28 +73,28 @@ class Ability
# Rules based on role in project # Rules based on role in project
if team.master?(user) if team.master?(user)
rules += project_master_rules rules.push(*project_master_rules)
elsif team.developer?(user) elsif team.developer?(user)
rules += project_dev_rules rules.push(*project_dev_rules)
elsif team.reporter?(user) elsif team.reporter?(user)
rules += project_report_rules rules.push(*project_report_rules)
elsif team.guest?(user) elsif team.guest?(user)
rules += project_guest_rules rules.push(*project_guest_rules)
end end
if project.public? || project.internal? if project.public? || project.internal?
rules += public_project_rules rules.push(*public_project_rules)
end end
if project.owner == user || user.admin? if project.owner == user || user.admin?
rules += project_admin_rules rules.push(*project_admin_rules)
end end
if project.group && project.group.has_owner?(user) if project.group && project.group.has_owner?(user)
rules += project_admin_rules rules.push(*project_admin_rules)
end end
if project.archived? if project.archived?
...@@ -193,17 +193,17 @@ class Ability ...@@ -193,17 +193,17 @@ class Ability
# Only group masters and group owners can create new projects in group # Only group masters and group owners can create new projects in group
if group.has_master?(user) || group.has_owner?(user) || user.admin? if group.has_master?(user) || group.has_owner?(user) || user.admin?
rules += [ rules.push(*[
:create_projects, :create_projects,
] ])
end end
# Only group owner and administrators can manage group # Only group owner and administrators can manage group
if group.has_owner?(user) || user.admin? if group.has_owner?(user) || user.admin?
rules += [ rules.push(*[
:manage_group, :manage_group,
:manage_namespace :manage_namespace
] ])
end end
rules.flatten rules.flatten
...@@ -214,10 +214,10 @@ class Ability ...@@ -214,10 +214,10 @@ class Ability
# Only namespace owner and administrators can manage it # Only namespace owner and administrators can manage it
if namespace.owner == user || user.admin? if namespace.owner == user || user.admin?
rules += [ rules.push(*[
:create_projects, :create_projects,
:manage_namespace :manage_namespace
] ])
end end
rules.flatten rules.flatten
......
# == Schema Information
#
# Table name: application_settings
#
# id :integer not null, primary key
# default_projects_limit :integer
# signup_enabled :boolean
# signin_enabled :boolean
# gravatar_enabled :boolean
# sign_in_text :text
# created_at :datetime
# updated_at :datetime
# home_page_url :string(255)
#
class ApplicationSetting < ActiveRecord::Base class ApplicationSetting < ActiveRecord::Base
validates :home_page_url, allow_blank: true, validates :home_page_url, allow_blank: true,
format: { with: URI::regexp(%w(http https)), message: "should be a valid url" }, format: { with: URI::regexp(%w(http https)), message: "should be a valid url" },
......
...@@ -88,7 +88,7 @@ module Issuable ...@@ -88,7 +88,7 @@ module Issuable
# Return the number of -1 comments (downvotes) # Return the number of -1 comments (downvotes)
def downvotes def downvotes
notes.select(&:downvote?).size filter_superceded_votes(notes.select(&:downvote?), notes).size
end end
def downvotes_in_percent def downvotes_in_percent
...@@ -101,7 +101,7 @@ module Issuable ...@@ -101,7 +101,7 @@ module Issuable
# Return the number of +1 comments (upvotes) # Return the number of +1 comments (upvotes)
def upvotes def upvotes
notes.select(&:upvote?).size filter_superceded_votes(notes.select(&:upvote?), notes).size
end end
def upvotes_in_percent def upvotes_in_percent
...@@ -124,10 +124,12 @@ module Issuable ...@@ -124,10 +124,12 @@ module Issuable
users << assignee if is_assigned? users << assignee if is_assigned?
mentions = [] mentions = []
mentions << self.mentioned_users mentions << self.mentioned_users
notes.each do |note| notes.each do |note|
users << note.author users << note.author
mentions << note.mentioned_users mentions << note.mentioned_users
end end
users.concat(mentions.reduce([], :|)).uniq users.concat(mentions.reduce([], :|)).uniq
end end
...@@ -149,9 +151,23 @@ module Issuable ...@@ -149,9 +151,23 @@ module Issuable
def add_labels_by_names(label_names) def add_labels_by_names(label_names)
label_names.each do |label_name| label_names.each do |label_name|
label = project.labels.create_with( label = project.labels.create_with(color: Label::DEFAULT_COLOR).
color: Label::DEFAULT_COLOR).find_or_create_by(title: label_name.strip) find_or_create_by(title: label_name.strip)
self.labels << label self.labels << label
end end
end end
private
def filter_superceded_votes(votes, notes)
filteredvotes = [] + votes
votes.each do |vote|
if vote.superceded?(notes)
filteredvotes.delete(vote)
end
end
filteredvotes
end
end end
...@@ -50,7 +50,7 @@ module Mentionable ...@@ -50,7 +50,7 @@ module Mentionable
matches.each do |match| matches.each do |match|
identifier = match.delete "@" identifier = match.delete "@"
if identifier == "all" if identifier == "all"
users += project.team.members.flatten users.push(*project.team.members.flatten)
else else
id = User.find_by(username: identifier).try(:id) id = User.find_by(username: identifier).try(:id)
users << User.find(id) unless id.blank? users << User.find(id) unless id.blank?
......
# == Schema Information
#
# Table name: identities
#
# id :integer not null, primary key
# extern_uid :string(255)
# provider :string(255)
# user_id :integer
#
class Identity < ActiveRecord::Base class Identity < ActiveRecord::Base
belongs_to :user belongs_to :user
validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider} validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider}
end end
\ No newline at end of file
...@@ -19,7 +19,7 @@ class Key < ActiveRecord::Base ...@@ -19,7 +19,7 @@ class Key < ActiveRecord::Base
belongs_to :user belongs_to :user
before_validation :strip_white_space, :generate_fingerpint before_validation :strip_white_space, :generate_fingerprint
validates :title, presence: true, length: { within: 0..255 } validates :title, presence: true, length: { within: 0..255 }
validates :key, presence: true, length: { within: 0..5000 }, format: { with: /\A(ssh|ecdsa)-.*\Z/ }, uniqueness: true validates :key, presence: true, length: { within: 0..5000 }, format: { with: /\A(ssh|ecdsa)-.*\Z/ }, uniqueness: true
...@@ -76,7 +76,7 @@ class Key < ActiveRecord::Base ...@@ -76,7 +76,7 @@ class Key < ActiveRecord::Base
private private
def generate_fingerpint def generate_fingerprint
self.fingerprint = nil self.fingerprint = nil
return unless key.present? return unless key.present?
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
# iid :integer # iid :integer
# description :text # description :text
# position :integer default(0) # position :integer default(0)
# locked_at :datetime
# #
require Rails.root.join("app/models/commit") require Rails.root.join("app/models/commit")
...@@ -250,7 +251,8 @@ class MergeRequest < ActiveRecord::Base ...@@ -250,7 +251,8 @@ class MergeRequest < ActiveRecord::Base
def closes_issues def closes_issues
if target_branch == project.default_branch if target_branch == project.default_branch
issues = commits.flat_map { |c| c.closes_issues(project) } issues = commits.flat_map { |c| c.closes_issues(project) }
issues += Gitlab::ClosingIssueExtractor.closed_by_message_in_project(description, project) issues.push(*Gitlab::ClosingIssueExtractor.
closed_by_message_in_project(description, project))
issues.uniq.sort_by(&:id) issues.uniq.sort_by(&:id)
else else
[] []
...@@ -330,7 +332,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -330,7 +332,7 @@ class MergeRequest < ActiveRecord::Base
end end
# Return array of possible target branches # Return array of possible target branches
# dependes on target project of MR # depends on target project of MR
def target_branches def target_branches
if target_project.nil? if target_project.nil?
[] []
...@@ -340,7 +342,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -340,7 +342,7 @@ class MergeRequest < ActiveRecord::Base
end end
# Return array of possible source branches # Return array of possible source branches
# dependes on source project of MR # depends on source project of MR
def source_branches def source_branches
if source_project.nil? if source_project.nil?
[] []
......
...@@ -84,7 +84,7 @@ module Network ...@@ -84,7 +84,7 @@ module Network
skip += self.class.max_count skip += self.class.max_count
end end
else else
# Cant't find the target commit in the repo. # Can't find the target commit in the repo.
offset = 0 offset = 0
end end
end end
...@@ -226,7 +226,7 @@ module Network ...@@ -226,7 +226,7 @@ module Network
reserved = [] reserved = []
for day in time_range for day in time_range
reserved += @reserved[day] reserved.push(*@reserved[day])
end end
reserved.uniq! reserved.uniq!
......
...@@ -459,6 +459,26 @@ class Note < ActiveRecord::Base ...@@ -459,6 +459,26 @@ class Note < ActiveRecord::Base
) )
end end
def superceded?(notes)
return false unless vote?
notes.each do |note|
next if note == self
if note.vote? &&
self[:author_id] == note[:author_id] &&
self[:created_at] <= note[:created_at]
return true
end
end
false
end
def vote?
upvote? || downvote?
end
def votable? def votable?
for_issue? || (for_merge_request? && !for_diff_line?) for_issue? || (for_merge_request? && !for_diff_line?)
end end
...@@ -480,7 +500,7 @@ class Note < ActiveRecord::Base ...@@ -480,7 +500,7 @@ class Note < ActiveRecord::Base
end end
# FIXME: Hack for polymorphic associations with STI # FIXME: Hack for polymorphic associations with STI
# For more information wisit http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#label-Polymorphic+Associations # For more information visit http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#label-Polymorphic+Associations
def noteable_type=(sType) def noteable_type=(sType)
super(sType.to_s.classify.constantize.base_class.to_s) super(sType.to_s.classify.constantize.base_class.to_s)
end end
......
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
# import_status :string(255) # import_status :string(255)
# repository_size :float default(0.0) # repository_size :float default(0.0)
# star_count :integer default(0), not null # star_count :integer default(0), not null
# import_type :string(255)
# import_source :string(255)
# #
class Project < ActiveRecord::Base class Project < ActiveRecord::Base
...@@ -174,7 +176,7 @@ class Project < ActiveRecord::Base ...@@ -174,7 +176,7 @@ class Project < ActiveRecord::Base
def publicish(user) def publicish(user)
visibility_levels = [Project::PUBLIC] visibility_levels = [Project::PUBLIC]
visibility_levels += [Project::INTERNAL] if user visibility_levels << Project::INTERNAL if user
where(visibility_level: visibility_levels) where(visibility_level: visibility_levels)
end end
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
#
class BambooService < CiService class BambooService < CiService
include HTTParty include HTTParty
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
#
class TeamcityService < CiService class TeamcityService < CiService
include HTTParty include HTTParty
......
...@@ -160,7 +160,7 @@ class ProjectTeam ...@@ -160,7 +160,7 @@ class ProjectTeam
end end
user_ids = project_members.pluck(:user_id) user_ids = project_members.pluck(:user_id)
user_ids += group_members.pluck(:user_id) if group user_ids.push(*group_members.pluck(:user_id)) if group
User.where(id: user_ids) User.where(id: user_ids)
end end
......
...@@ -2,11 +2,12 @@ ...@@ -2,11 +2,12 @@
# #
# Table name: protected_branches # Table name: protected_branches
# #
# id :integer not null, primary key # id :integer not null, primary key
# project_id :integer not null # project_id :integer not null
# name :string(255) not null # name :string(255) not null
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# developers_can_push :boolean default(FALSE), not null
# #
class ProtectedBranch < ActiveRecord::Base class ProtectedBranch < ActiveRecord::Base
......
...@@ -312,4 +312,21 @@ class Repository ...@@ -312,4 +312,21 @@ class Repository
[] []
end end
end end
def tag_names_contains(sha)
args = %W(git tag --contains #{sha})
names = Gitlab::Popen.popen(args, path_to_repo).first
if names.respond_to?(:split)
names = names.split("\n").map(&:strip)
names.each do |name|
name.slice! '* '
end
names
else
[]
end
end
end end
...@@ -26,8 +26,6 @@ ...@@ -26,8 +26,6 @@
# bio :string(255) # bio :string(255)
# failed_attempts :integer default(0) # failed_attempts :integer default(0)
# locked_at :datetime # locked_at :datetime
# extern_uid :string(255)
# provider :string(255)
# username :string(255) # username :string(255)
# can_create_group :boolean default(TRUE), not null # can_create_group :boolean default(TRUE), not null
# can_create_team :boolean default(TRUE), not null # can_create_team :boolean default(TRUE), not null
...@@ -36,7 +34,6 @@ ...@@ -36,7 +34,6 @@
# notification_level :integer default(1), not null # notification_level :integer default(1), not null
# password_expires_at :datetime # password_expires_at :datetime
# created_by_id :integer # created_by_id :integer
# last_credential_check_at :datetime
# avatar :string(255) # avatar :string(255)
# confirmation_token :string(255) # confirmation_token :string(255)
# confirmed_at :datetime # confirmed_at :datetime
...@@ -44,6 +41,8 @@ ...@@ -44,6 +41,8 @@
# unconfirmed_email :string(255) # unconfirmed_email :string(255)
# hide_no_ssh_key :boolean default(FALSE) # hide_no_ssh_key :boolean default(FALSE)
# website_url :string(255) default(""), not null # website_url :string(255) default(""), not null
# last_credential_check_at :datetime
# github_access_token :string(255)
# #
require 'carrierwave/orm/activerecord' require 'carrierwave/orm/activerecord'
...@@ -298,8 +297,8 @@ class User < ActiveRecord::Base ...@@ -298,8 +297,8 @@ class User < ActiveRecord::Base
def authorized_projects def authorized_projects
@authorized_projects ||= begin @authorized_projects ||= begin
project_ids = personal_projects.pluck(:id) project_ids = personal_projects.pluck(:id)
project_ids += groups_projects.pluck(:id) project_ids.push(*groups_projects.pluck(:id))
project_ids += projects.pluck(:id).uniq project_ids.push(*projects.pluck(:id).uniq)
Project.where(id: project_ids).joins(:namespace).order('namespaces.name ASC') Project.where(id: project_ids).joins(:namespace).order('namespaces.name ASC')
end end
end end
...@@ -497,7 +496,7 @@ class User < ActiveRecord::Base ...@@ -497,7 +496,7 @@ class User < ActiveRecord::Base
def avatar_url(size = nil) def avatar_url(size = nil)
if avatar.present? if avatar.present?
[gitlab_config.url, avatar.url].join("/") [gitlab_config.url, avatar.url].join
else else
GravatarService.new.execute(email, size) GravatarService.new.execute(email, size)
end end
......
...@@ -3,11 +3,7 @@ require_relative "base_service" ...@@ -3,11 +3,7 @@ require_relative "base_service"
module Files module Files
class CreateService < BaseService class CreateService < BaseService
def execute def execute
allowed = if project.protected_branch?(ref) allowed = Gitlab::GitAccess.can_push_to_branch?(current_user, project, ref)
can?(current_user, :push_code_to_protected_branches, project)
else
can?(current_user, :push_code, project)
end
unless allowed unless allowed
return error("You are not allowed to create file in this branch") return error("You are not allowed to create file in this branch")
......
...@@ -3,11 +3,7 @@ require_relative "base_service" ...@@ -3,11 +3,7 @@ require_relative "base_service"
module Files module Files
class DeleteService < BaseService class DeleteService < BaseService
def execute def execute
allowed = if project.protected_branch?(ref) allowed = ::Gitlab::GitAccess.can_push_to_branch?(current_user, project, ref)
can?(current_user, :push_code_to_protected_branches, project)
else
can?(current_user, :push_code, project)
end
unless allowed unless allowed
return error("You are not allowed to push into this branch") return error("You are not allowed to push into this branch")
......
...@@ -3,11 +3,7 @@ require_relative "base_service" ...@@ -3,11 +3,7 @@ require_relative "base_service"
module Files module Files
class UpdateService < BaseService class UpdateService < BaseService
def execute def execute
allowed = if project.protected_branch?(ref) allowed = ::Gitlab::GitAccess.can_push_to_branch?(current_user, project, ref)
can?(current_user, :push_code_to_protected_branches, project)
else
can?(current_user, :push_code, project)
end
unless allowed unless allowed
return error("You are not allowed to push into this branch") return error("You are not allowed to push into this branch")
......
...@@ -242,7 +242,7 @@ class NotificationService ...@@ -242,7 +242,7 @@ class NotificationService
users users
end end
# Build a list of users based on group notifcation settings # Build a list of users based on group notification settings
def select_users_group_setting(project, project_members, global_setting, users_global_level_watch) def select_users_group_setting(project, project_members, global_setting, users_global_level_watch)
uids = users_group_notification(project, Notification::N_WATCH) uids = users_group_notification(project, Notification::N_WATCH)
......
...@@ -13,7 +13,7 @@ module Oauth2::AccessTokenValidationService ...@@ -13,7 +13,7 @@ module Oauth2::AccessTokenValidationService
elsif token.revoked? elsif token.revoked?
return REVOKED return REVOKED
elsif !self.sufficent_scope?(token, scopes) elsif !self.sufficient_scope?(token, scopes)
return INSUFFICIENT_SCOPE return INSUFFICIENT_SCOPE
else else
...@@ -24,7 +24,7 @@ module Oauth2::AccessTokenValidationService ...@@ -24,7 +24,7 @@ module Oauth2::AccessTokenValidationService
protected protected
# True if the token's scope is a superset of required scopes, # True if the token's scope is a superset of required scopes,
# or the required scopes is empty. # or the required scopes is empty.
def sufficent_scope?(token, scopes) def sufficient_scope?(token, scopes)
if scopes.blank? if scopes.blank?
# if no any scopes required, the scopes of token is sufficient. # if no any scopes required, the scopes of token is sufficient.
return true return true
......
module Projects
class AutocompleteService < BaseService
def initialize(project)
@project = project
end
def issues
@project.issues.opened.select([:iid, :title, :description])
end
def merge_requests
@project.merge_requests.opened.select([:iid, :title, :description])
end
end
end
...@@ -7,7 +7,7 @@ module Projects ...@@ -7,7 +7,7 @@ module Projects
def execute def execute
@project = Project.new(params) @project = Project.new(params)
# Reset visibility levet if is not allowed to set it # Reset visibility level if is not allowed to set it
unless Gitlab::VisibilityLevel.allowed_for?(current_user, params[:visibility_level]) unless Gitlab::VisibilityLevel.allowed_for?(current_user, params[:visibility_level])
@project.visibility_level = default_features.visibility_level @project.visibility_level = default_features.visibility_level
end end
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
= radio_button_tag :notification_level, Notification::N_MENTION, @notification.mention?, class: 'trigger-submit' = radio_button_tag :notification_level, Notification::N_MENTION, @notification.mention?, class: 'trigger-submit'
.level-title .level-title
Mention Mention
%p You will receive notifications only for comments where you was @mentioned %p You will receive notifications only for comments in which you were @mentioned
.radio .radio
= label_tag nil, class: '' do = label_tag nil, class: '' do
......
%div#github_import_modal.modal.hide
.modal-dialog
.modal-content
.modal-header
%a.close{href: "#", "data-dismiss" => "modal"} ×
%h3 GitHub OAuth import
.modal-body
You need to setup integration with GitHub first.
= link_to 'How to setup integration with GitHub', 'https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/integration/github.md'
:javascript
$(function(){
var import_modal = $('#github_import_modal').modal({modal: true, show:false});
$('.how_to_import_link').bind("click", function(e){
e.preventDefault();
import_modal.show();
});
$('.modal-header .close').bind("click", function(){
import_modal.hide();
})
})
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
%h3.page-title %h3.page-title
%i.fa.fa-code-fork %i.fa.fa-code-fork
New branch New branch
= form_tag project_branches_path, method: :post, class: "form-horizontal" do = form_tag project_branches_path, method: :post, id: "new-branch-form", class: "form-horizontal" do
.form-group .form-group
= label_tag :branch_name, 'Name for new branch', class: 'control-label' = label_tag :branch_name, 'Name for new branch', class: 'control-label'
.col-sm-10 .col-sm-10
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
= link_to 'Cancel', project_branches_path(@project), class: 'btn btn-cancel' = link_to 'Cancel', project_branches_path(@project), class: 'btn btn-cancel'
:javascript :javascript
disableButtonIfAnyEmptyField($("#new-branch-form"), ".form-control", ".btn-create");
var availableTags = #{@project.repository.ref_names.to_json}; var availableTags = #{@project.repository.ref_names.to_json};
$("#ref").autocomplete({ $("#ref").autocomplete({
......
...@@ -37,18 +37,23 @@ ...@@ -37,18 +37,23 @@
- @commit.parents.each do |parent| - @commit.parents.each do |parent|
= link_to parent.short_id, project_commit_path(@project, parent) = link_to parent.short_id, project_commit_path(@project, parent)
- if @branches.any? .commit-info-row
.commit-info-row - if @branches.any?
%span.cgray
Exists in
%span %span
- branch = commit_default_branch(@project, @branches) - branch = commit_default_branch(@project, @branches)
= link_to(branch, project_tree_path(@project, branch)) = link_to(project_tree_path(@project, branch)) do
- if @branches.any? %span.label.label-gray
and in %i.fa.fa-code-fork
= link_to("#{pluralize(@branches.count, "other branch")}", "#", class: "js-details-expand") = branch
- if @branches.any? || @tags.any?
= link_to("#", class: "js-details-expand") do
%span.label.label-gray
\...
%span.js-details-content.hide %span.js-details-content.hide
= commit_branches_links(@project, @branches) - if @branches.any?
= commit_branches_links(@project, @branches)
- if @tags.any?
= commit_tags_links(@project, @tags)
.commit-box .commit-box
%h3.commit-title %h3.commit-title
......
...@@ -9,6 +9,9 @@ ...@@ -9,6 +9,9 @@
.diff-btn-group .diff-btn-group
- if @commit.parent_ids.present? - if @commit.parent_ids.present?
= view_file_btn(@commit.parent_id, diff_file, project) = view_file_btn(@commit.parent_id, diff_file, project)
- elsif diff_file.diff.submodule?
- submodule_item = project.repository.blob_at(@commit.id, diff_file.file_path)
= submodule_link(submodule_item, @commit.id)
- else - else
- if diff_file.renamed_file - if diff_file.renamed_file
%span= "#{diff_file.old_path} renamed to #{diff_file.new_path}" %span= "#{diff_file.old_path} renamed to #{diff_file.new_path}"
......
.append-bottom-10 .append-bottom-10
.check-all-holder .check-all-holder
= check_box_tag "check_all_issues", nil, false, class: "check_all_issues left" = check_box_tag "check_all_issues", nil, false, class: "check_all_issues left", disabled: !can?(current_user, :modify_issue, @project)
= render 'shared/issuable_filter' = render 'shared/issuable_filter'
.clearfix .clearfix
......
...@@ -3,21 +3,21 @@ ...@@ -3,21 +3,21 @@
%i.fa.fa-check %i.fa.fa-check
%span CI build passed %span CI build passed
for #{@merge_request.last_commit_short_sha}. for #{@merge_request.last_commit_short_sha}.
= link_to "Build page", ci_build_details_path(@merge_request) = link_to "Build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink"
.ci_widget.ci-failed{style: "display:none"} .ci_widget.ci-failed{style: "display:none"}
%i.fa.fa-times %i.fa.fa-times
%span CI build failed %span CI build failed
for #{@merge_request.last_commit_short_sha}. for #{@merge_request.last_commit_short_sha}.
= link_to "Build page", ci_build_details_path(@merge_request) = link_to "Build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink"
- [:running, :pending].each do |status| - [:running, :pending].each do |status|
.ci_widget{class: "ci-#{status}", style: "display:none"} .ci_widget{class: "ci-#{status}", style: "display:none"}
%i.fa.fa-clock-o %i.fa.fa-clock-o
%span CI build #{status} %span CI build #{status}
for #{@merge_request.last_commit_short_sha}. for #{@merge_request.last_commit_short_sha}.
= link_to "Build page", ci_build_details_path(@merge_request) = link_to "Build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink"
.ci_widget .ci_widget
%i.fa.fa-spinner %i.fa.fa-spinner
......
...@@ -12,6 +12,6 @@ ...@@ -12,6 +12,6 @@
Failed to remove source branch '#{@merge_request.source_branch}' Failed to remove source branch '#{@merge_request.source_branch}'
.remove_source_branch_in_progress.hide .remove_source_branch_in_progress.hide
%i.fa.fa-refresh.fa-spin %i.fa.fa-spinner.fa-spin
&nbsp; &nbsp;
Removing source branch '#{@merge_request.source_branch}'. Please wait. Page will be automatically reloaded. &nbsp; Removing source branch '#{@merge_request.source_branch}'. Please wait. Page will be automatically reloaded. &nbsp;
...@@ -40,13 +40,18 @@ ...@@ -40,13 +40,18 @@
The import will time out after 4 minutes. For big repositories, use a clone/push combination. The import will time out after 4 minutes. For big repositories, use a clone/push combination.
For SVN repositories, check #{link_to "this migrating from SVN doc.", "http://doc.gitlab.com/ce/workflow/migrating_from_svn.html"} For SVN repositories, check #{link_to "this migrating from SVN doc.", "http://doc.gitlab.com/ce/workflow/migrating_from_svn.html"}
- if github_import_enabled? .project-import.form-group
.project-import.form-group .col-sm-2
.col-sm-2 .col-sm-10
.col-sm-10 - if github_import_enabled?
= link_to status_github_import_path do = link_to status_github_import_path do
%i.fa.fa-github %i.fa.fa-github
Import projects from GitHub Import projects from GitHub
- else
= link_to '#', class: 'how_to_import_link light' do
%i.fa.fa-github
Import projects from GitHub
= render 'github_import_modal'
%hr.prepend-botton-10 %hr.prepend-botton-10
......
...@@ -28,14 +28,24 @@ ...@@ -28,14 +28,24 @@
%span.note-last-update %span.note-last-update
= note_timestamp(note) = note_timestamp(note)
- if note.upvote? - if note.superceded?(@notes)
%span.vote.upvote.label.label-success - if note.upvote?
%i.fa.fa-thumbs-up %span.vote.upvote.label.label-gray.strikethrough
\+1 %i.fa.fa-thumbs-up
- if note.downvote? \+1
%span.vote.downvote.label.label-danger - if note.downvote?
%i.fa.fa-thumbs-down %span.vote.downvote.label.label-gray.strikethrough
\-1 %i.fa.fa-thumbs-down
\-1
- else
- if note.upvote?
%span.vote.upvote.label.label-success
%i.fa.fa-thumbs-up
\+1
- if note.downvote?
%span.vote.downvote.label.label-danger
%i.fa.fa-thumbs-down
\-1
.note-body .note-body
......
...@@ -68,11 +68,11 @@ ...@@ -68,11 +68,11 @@
- @project.ci_services.each do |ci_service| - @project.ci_services.each do |ci_service|
- if ci_service.active? && ci_service.respond_to?(:builds_path) - if ci_service.active? && ci_service.respond_to?(:builds_path)
- if ci_service.respond_to?(:status_img_path) - if ci_service.respond_to?(:status_img_path)
= link_to ci_service.builds_path do = link_to ci_service.builds_path, :'data-no-turbolink' => 'data-no-turbolink' do
= image_tag ci_service.status_img_path, alt: "build status" = image_tag ci_service.status_img_path, alt: "build status"
- else - else
%span.light CI provided by %span.light CI provided by
= link_to ci_service.title, ci_service.builds_path = link_to ci_service.title, ci_service.builds_path, :'data-no-turbolink' => 'data-no-turbolink'
- if readme - if readme
.tab-pane#tab-readme .tab-pane#tab-readme
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
%h3.page-title %h3.page-title
%i.fa.fa-code-fork %i.fa.fa-code-fork
New tag New tag
= form_tag project_tags_path, method: :post, class: "form-horizontal" do = form_tag project_tags_path, method: :post, id: "new-tag-form", class: "form-horizontal" do
.form-group .form-group
= label_tag :tag_name, 'Name for new tag', class: 'control-label' = label_tag :tag_name, 'Name for new tag', class: 'control-label'
.col-sm-10 .col-sm-10
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
= link_to 'Cancel', project_tags_path(@project), class: 'btn btn-cancel' = link_to 'Cancel', project_tags_path(@project), class: 'btn btn-cancel'
:javascript :javascript
disableButtonIfAnyEmptyField($("#new-tag-form"), ".form-control", ".btn-create");
var availableTags = #{@project.repository.ref_names.to_json}; var availableTags = #{@project.repository.ref_names.to_json};
$("#ref").autocomplete({ $("#ref").autocomplete({
......
- tree, commit = submodule_links(submodule_item)
%tr{ class: "tree-item" } %tr{ class: "tree-item" }
%td.tree-item-file-name %td.tree-item-file-name
%i.fa.fa-archive %i.fa.fa-archive
%span = submodule_link(submodule_item, @ref)
= link_to truncate(submodule_item.name, length: 40), tree
@
%span.monospace
- if commit.nil?
#{truncate_sha(submodule_item.id)}
- else
= link_to "#{truncate_sha(submodule_item.id)}", commit
%td %td
%td.hidden-xs %td.hidden-xs
- groups.each do |group| .clearfix
= link_to group, class: 'profile-groups-avatars', :title => group.name do - groups.each do |group|
- image_tag group_icon(group.path) = link_to group, class: 'profile-groups-avatars', title: group.name do
= image_tag group_icon(group.path), class: 'avatar s40'
...@@ -12,11 +12,11 @@ module Gitlab ...@@ -12,11 +12,11 @@ module Gitlab
# -- all .rb files in that directory are automatically loaded. # -- all .rb files in that directory are automatically loaded.
# Custom directories with classes and modules you want to be autoloadable. # Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += %W(#{config.root}/lib config.autoload_paths.push(*%W(#{config.root}/lib
#{config.root}/app/models/hooks #{config.root}/app/models/hooks
#{config.root}/app/models/concerns #{config.root}/app/models/concerns
#{config.root}/app/models/project_services #{config.root}/app/models/project_services
#{config.root}/app/models/members) #{config.root}/app/models/members))
# Only load the plugins named here, in the order given (default is alphabetical). # Only load the plugins named here, in the order given (default is alphabetical).
# :all can be used as a placeholder for all plugins not explicitly named. # :all can be used as a placeholder for all plugins not explicitly named.
...@@ -31,7 +31,7 @@ module Gitlab ...@@ -31,7 +31,7 @@ module Gitlab
config.encoding = "utf-8" config.encoding = "utf-8"
# Configure sensitive parameters which will be filtered from the log file. # Configure sensitive parameters which will be filtered from the log file.
config.filter_parameters += [:password] config.filter_parameters.push(*[:password])
# Enable escaping HTML in JSON. # Enable escaping HTML in JSON.
config.active_support.escape_html_entities_in_json = true config.active_support.escape_html_entities_in_json = true
......
...@@ -60,7 +60,7 @@ production: &base ...@@ -60,7 +60,7 @@ production: &base
## Users can create accounts ## Users can create accounts
# This also allows normal users to sign up for accounts themselves # This also allows normal users to sign up for accounts themselves
# default: false - By default GitLab administrators must create all new accounts # default: true - By default users can sign up themselves
# signup_enabled: true # signup_enabled: true
## Standard login settings ## Standard login settings
...@@ -77,7 +77,7 @@ production: &base ...@@ -77,7 +77,7 @@ production: &base
# This happens when the commit is pushed or merged into the default branch of a project. # This happens when the commit is pushed or merged into the default branch of a project.
# When not specified the default issue_closing_pattern as specified below will be used. # When not specified the default issue_closing_pattern as specified below will be used.
# Tip: you can test your closing pattern at http://rubular.com # Tip: you can test your closing pattern at http://rubular.com
# issue_closing_pattern: '([Cc]lose[sd]|[Ff]ixe[sd]) #(\d+)' # issue_closing_pattern: '((?:[Cc]los(?:e[sd]|ing)|[Ff]ix(?:e[sd]|ing)?) +(?:(?:issues? +)?#\d+(?:(?:, *| +and +)?))+)'
## Default project features settings ## Default project features settings
default_projects_features: default_projects_features:
......
...@@ -109,7 +109,7 @@ Settings.gitlab['signup_enabled'] ||= true if Settings.gitlab['signup_enabled']. ...@@ -109,7 +109,7 @@ Settings.gitlab['signup_enabled'] ||= true if Settings.gitlab['signup_enabled'].
Settings.gitlab['signin_enabled'] ||= true if Settings.gitlab['signin_enabled'].nil? Settings.gitlab['signin_enabled'] ||= true if Settings.gitlab['signin_enabled'].nil?
Settings.gitlab['restricted_visibility_levels'] = Settings.send(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], []) Settings.gitlab['restricted_visibility_levels'] = Settings.send(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], [])
Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil? Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil?
Settings.gitlab['issue_closing_pattern'] = '([Cc]lose[sd]|[Ff]ixe[sd]) #(\d+)' if Settings.gitlab['issue_closing_pattern'].nil? Settings.gitlab['issue_closing_pattern'] = '((?:[Cc]los(?:e[sd]|ing)|[Ff]ix(?:e[sd]|ing)?) +(?:(?:issues? +)?#\d+(?:(?:, *| +and +)?))+)' if Settings.gitlab['issue_closing_pattern'].nil?
Settings.gitlab['default_projects_features'] ||= {} Settings.gitlab['default_projects_features'] ||= {}
Settings.gitlab['webhook_timeout'] ||= 10 Settings.gitlab['webhook_timeout'] ||= 10
Settings.gitlab.default_projects_features['issues'] = true if Settings.gitlab.default_projects_features['issues'].nil? Settings.gitlab.default_projects_features['issues'] = true if Settings.gitlab.default_projects_features['issues'].nil?
......
...@@ -36,6 +36,12 @@ Doorkeeper.configure do ...@@ -36,6 +36,12 @@ Doorkeeper.configure do
# Issue access tokens with refresh token (disabled by default) # Issue access tokens with refresh token (disabled by default)
use_refresh_token use_refresh_token
# Forces the usage of the HTTPS protocol in non-native redirect uris (enabled
# by default in non-development environments). OAuth2 delegates security in
# communication to the HTTPS protocol so it is wise to keep this enabled.
#
force_ssl_in_redirect_uri false
# Provide support for an owner to be assigned to each registered application (disabled by default) # Provide support for an owner to be assigned to each registered application (disabled by default)
# Optional parameter :confirmation => true (default false) if you want to enforce ownership of # Optional parameter :confirmation => true (default false) if you want to enforce ownership of
# a registered application # a registered application
......
...@@ -72,3 +72,16 @@ Parameters: ...@@ -72,3 +72,16 @@ Parameters:
- `description` (optional) - The description of a milestone - `description` (optional) - The description of a milestone
- `due_date` (optional) - The due date of the milestone - `due_date` (optional) - The due date of the milestone
- `state_event` (optional) - The state event of the milestone (close|activate) - `state_event` (optional) - The state event of the milestone (close|activate)
## Get all issues assigned to a single milestone
Gets all issues assigned to a single project milestone.
```
GET /projects/:id/milestones/:milestone_id/issues
```
Parameters:
- `id` (required) - The ID of a project
- `milestone_id` (required) - The ID of a project milestone
...@@ -287,6 +287,31 @@ Parameters: ...@@ -287,6 +287,31 @@ Parameters:
- `visibility_level` (optional) - `visibility_level` (optional)
- `import_url` (optional) - `import_url` (optional)
### Edit project
Updates an existing project
```
PUT /projects/:id
```
Parameters:
- `id` (required) - The ID of a project
- `name` (optional) - project name
- `path` (optional) - repository name for project
- `description` (optional) - short project description
- `default_branch` (optional)
- `issues_enabled` (optional)
- `merge_requests_enabled` (optional)
- `wiki_enabled` (optional)
- `snippets_enabled` (optional)
- `public` (optional) - if `true` same as setting visibility_level = 20
- `visibility_level` (optional)
On success, method returns 200 with the updated project. If parameters are
invalid, 400 is returned.
### Fork project ### Fork project
Forks a project into the user namespace of the authenticated user. Forks a project into the user namespace of the authenticated user.
......
...@@ -108,7 +108,7 @@ In other repositories, such as gitlab-shell you can also use `IO.popen`. ...@@ -108,7 +108,7 @@ In other repositories, such as gitlab-shell you can also use `IO.popen`.
```ruby ```ruby
# Safe IO.popen example # Safe IO.popen example
logs = IO.popen(%W(git log), chdir: repo_dir).read logs = IO.popen(%W(git log), chdir: repo_dir) { |p| p.read }
``` ```
Note that unlike `Gitlab::Popen.popen`, `IO.popen` does not capture standard error. Note that unlike `Gitlab::Popen.popen`, `IO.popen` does not capture standard error.
......
...@@ -167,13 +167,9 @@ module API ...@@ -167,13 +167,9 @@ module API
put ":id/merge_request/:merge_request_id/merge" do put ":id/merge_request/:merge_request_id/merge" do
merge_request = user_project.merge_requests.find(params[:merge_request_id]) merge_request = user_project.merge_requests.find(params[:merge_request_id])
action = if user_project.protected_branch?(merge_request.target_branch) allowed = ::Gitlab::GitAccess.can_push_to_branch?(current_user, user_project, merge_request.target_branch)
:push_code_to_protected_branches
else
:push_code
end
if can?(current_user, action, user_project) if allowed
if merge_request.unchecked? if merge_request.unchecked?
merge_request.check_if_can_be_merged merge_request.check_if_can_be_merged
end end
......
...@@ -75,6 +75,21 @@ module API ...@@ -75,6 +75,21 @@ module API
render_api_error!("Failed to update milestone #{milestone.errors.messages}", 400) render_api_error!("Failed to update milestone #{milestone.errors.messages}", 400)
end end
end end
# Get all issues for a single project milestone
#
# Parameters:
# id (required) - The ID of a project
# milestone_id (required) - The ID of a project milestone
# Example Request:
# GET /projects/:id/milestones/:milestone_id/issues
get ":id/milestones/:milestone_id/issues" do
authorize! :read_milestone, user_project
@milestone = user_project.milestones.find(params[:milestone_id])
present paginate(@milestone.issues), with: Entities::Issue
end
end end
end end
end end
...@@ -200,6 +200,49 @@ module API ...@@ -200,6 +200,49 @@ module API
end end
end end
# Update an existing project
#
# Parameters:
# id (required) - the id of a project
# name (optional) - name of a project
# path (optional) - path of a project
# description (optional) - short project description
# issues_enabled (optional)
# merge_requests_enabled (optional)
# wiki_enabled (optional)
# snippets_enabled (optional)
# public (optional) - if true same as setting visibility_level = 20
# visibility_level (optional) - visibility level of a project
# Example Request
# PUT /projects/:id
put ':id' do
attrs = attributes_for_keys [:name,
:path,
:description,
:default_branch,
:issues_enabled,
:merge_requests_enabled,
:wiki_enabled,
:snippets_enabled,
:public,
:visibility_level]
attrs = map_public_to_visibility_level(attrs)
authorize_admin_project
authorize! :rename_project, user_project if attrs[:name].present?
if attrs[:visibility_level].present?
authorize! :change_visibility_level, user_project
end
::Projects::UpdateService.new(user_project,
current_user, attrs).execute
if user_project.valid?
present user_project, with: Entities::Project
else
render_validation_error!(user_project)
end
end
# Remove project # Remove project
# #
# Parameters: # Parameters:
......
...@@ -3,14 +3,19 @@ module Gitlab ...@@ -3,14 +3,19 @@ module Gitlab
ISSUE_CLOSING_REGEX = Regexp.new(Gitlab.config.gitlab.issue_closing_pattern) ISSUE_CLOSING_REGEX = Regexp.new(Gitlab.config.gitlab.issue_closing_pattern)
def self.closed_by_message_in_project(message, project) def self.closed_by_message_in_project(message, project)
md = ISSUE_CLOSING_REGEX.match(message) issues = []
if md
extractor = Gitlab::ReferenceExtractor.new unless message.nil?
extractor.analyze(md[0], project) md = message.scan(ISSUE_CLOSING_REGEX)
extractor.issues_for(project)
else md.each do |ref|
[] extractor = Gitlab::ReferenceExtractor.new
extractor.analyze(ref[0], project)
issues += extractor.issues_for(project)
end
end end
issues.uniq
end end
end end
end end
...@@ -4,7 +4,7 @@ module Gitlab ...@@ -4,7 +4,7 @@ module Gitlab
return false if project.empty_repo? return false if project.empty_repo?
if oldrev != Gitlab::Git::BLANK_SHA && newrev != Gitlab::Git::BLANK_SHA if oldrev != Gitlab::Git::BLANK_SHA && newrev != Gitlab::Git::BLANK_SHA
missed_refs = IO.popen(%W(git --git-dir=#{project.repository.path_to_repo} rev-list #{oldrev} ^#{newrev})).read missed_refs, _ = Gitlab::Popen.popen(%W(git --git-dir=#{project.repository.path_to_repo} rev-list #{oldrev} ^#{newrev}))
missed_refs.split("\n").size > 0 missed_refs.split("\n").size > 0
else else
false false
......
...@@ -5,6 +5,15 @@ module Gitlab ...@@ -5,6 +5,15 @@ module Gitlab
attr_reader :params, :project, :git_cmd, :user attr_reader :params, :project, :git_cmd, :user
def self.can_push_to_branch?(user, project, ref)
if project.protected_branch?(ref) &&
!(project.developers_can_push_to_protected_branch?(ref) && project.team.developer?(user))
user.can?(:push_code_to_protected_branches, project)
else
user.can?(:push_code, project)
end
end
def check(actor, cmd, project, changes = nil) def check(actor, cmd, project, changes = nil)
case cmd case cmd
when *DOWNLOAD_COMMANDS when *DOWNLOAD_COMMANDS
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
# iid :integer # iid :integer
# description :text # description :text
# position :integer default(0) # position :integer default(0)
# locked_at :datetime
# #
FactoryGirl.define do FactoryGirl.define do
......
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
# import_status :string(255) # import_status :string(255)
# repository_size :float default(0.0) # repository_size :float default(0.0)
# star_count :integer default(0), not null # star_count :integer default(0), not null
# import_type :string(255)
# import_source :string(255)
# #
FactoryGirl.define do FactoryGirl.define do
......
...@@ -73,7 +73,7 @@ describe ApplicationHelper do ...@@ -73,7 +73,7 @@ describe ApplicationHelper 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("/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
......
require 'spec_helper'
describe Gitlab::ClosingIssueExtractor do
let(:project) { create(:project) }
let(:issue) { create(:issue, project: project) }
let(:iid1) { issue.iid }
describe :closed_by_message_in_project do
context 'with a single reference' do
it do
message = "Awesome commit (Closes ##{iid1})"
subject.closed_by_message_in_project(message, project).should == [issue]
end
it do
message = "Awesome commit (closes ##{iid1})"
subject.closed_by_message_in_project(message, project).should == [issue]
end
it do
message = "Closed ##{iid1}"
subject.closed_by_message_in_project(message, project).should == [issue]
end
it do
message = "closed ##{iid1}"
subject.closed_by_message_in_project(message, project).should == [issue]
end
it do
message = "Awesome commit (fixes ##{iid1})"
subject.closed_by_message_in_project(message, project).should == [issue]
end
it do
message = "Awesome commit (fix ##{iid1})"
subject.closed_by_message_in_project(message, project).should == [issue]
end
end
context 'with multiple references' do
let(:other_issue) { create(:issue, project: project) }
let(:third_issue) { create(:issue, project: project) }
let(:iid2) { other_issue.iid }
let(:iid3) { third_issue.iid }
it 'fetches issues in single line message' do
message = "Closes ##{iid1} and fix ##{iid2}"
subject.closed_by_message_in_project(message, project).
should == [issue, other_issue]
end
it 'fetches comma-separated issues references in single line message' do
message = "Closes ##{iid1}, closes ##{iid2}"
subject.closed_by_message_in_project(message, project).
should == [issue, other_issue]
end
it 'fetches comma-separated issues numbers in single line message' do
message = "Closes ##{iid1}, ##{iid2} and ##{iid3}"
subject.closed_by_message_in_project(message, project).
should == [issue, other_issue, third_issue]
end
it 'fetches issues in multi-line message' do
message = "Awesome commit (closes ##{iid1})\nAlso fixes ##{iid2}"
subject.closed_by_message_in_project(message, project).
should == [issue, other_issue]
end
it 'fetches issues in hybrid message' do
message = "Awesome commit (closes ##{iid1})\n"\
"Also fixing issues ##{iid2}, ##{iid3} and #4"
subject.closed_by_message_in_project(message, project).
should == [issue, other_issue, third_issue]
end
end
end
end
...@@ -5,6 +5,68 @@ describe Gitlab::GitAccess do ...@@ -5,6 +5,68 @@ describe Gitlab::GitAccess do
let(:project) { create(:project) } let(:project) { create(:project) }
let(:user) { create(:user) } let(:user) { create(:user) }
describe 'can_push_to_branch?' do
describe 'push to none protected branch' do
it "returns true if user is a master" do
project.team << [user, :master]
Gitlab::GitAccess.can_push_to_branch?(user, project, "random_branch").should be_true
end
it "returns true if user is a developer" do
project.team << [user, :developer]
Gitlab::GitAccess.can_push_to_branch?(user, project, "random_branch").should be_true
end
it "returns false if user is a reporter" do
project.team << [user, :reporter]
Gitlab::GitAccess.can_push_to_branch?(user, project, "random_branch").should be_false
end
end
describe 'push to protected branch' do
before do
@branch = create :protected_branch, project: project
end
it "returns true if user is a master" do
project.team << [user, :master]
Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name).should be_true
end
it "returns false if user is a developer" do
project.team << [user, :developer]
Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name).should be_false
end
it "returns false if user is a reporter" do
project.team << [user, :reporter]
Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name).should be_false
end
end
describe 'push to protected branch if allowed for developers' do
before do
@branch = create :protected_branch, project: project, developers_can_push: true
end
it "returns true if user is a master" do
project.team << [user, :master]
Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name).should be_true
end
it "returns true if user is a developer" do
project.team << [user, :developer]
Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name).should be_true
end
it "returns false if user is a reporter" do
project.team << [user, :reporter]
Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name).should be_false
end
end
end
describe 'download_access_check' do describe 'download_access_check' do
describe 'master permissions' do describe 'master permissions' do
before { project.team << [user, :master] } before { project.team << [user, :master] }
......
...@@ -20,11 +20,17 @@ describe Issue, 'Votes' do ...@@ -20,11 +20,17 @@ describe Issue, 'Votes' do
issue.upvotes.should == 1 issue.upvotes.should == 1
end end
it "should recognize multiple +1 notes" do it 'should recognize multiple +1 notes' do
add_note "+1 This is awesome" add_note '+1 This is awesome', create(:user)
add_note "+1 I want this" add_note '+1 I want this', create(:user)
issue.upvotes.should == 2 issue.upvotes.should == 2
end end
it 'should not count 2 +1 votes from the same user' do
add_note '+1 This is awesome'
add_note '+1 I want this'
issue.upvotes.should == 1
end
end end
describe "#downvotes" do describe "#downvotes" do
...@@ -45,8 +51,8 @@ describe Issue, 'Votes' do ...@@ -45,8 +51,8 @@ describe Issue, 'Votes' do
end end
it "should recognize multiple -1 notes" do it "should recognize multiple -1 notes" do
add_note "-1 This is bad" add_note('-1 This is bad', create(:user))
add_note "-1 Away with this" add_note('-1 Away with this', create(:user))
issue.downvotes.should == 2 issue.downvotes.should == 2
end end
end end
...@@ -73,11 +79,17 @@ describe Issue, 'Votes' do ...@@ -73,11 +79,17 @@ describe Issue, 'Votes' do
end end
it "should recognize multiple notes" do it "should recognize multiple notes" do
add_note "+1 This is awesome" add_note('+1 This is awesome', create(:user))
add_note "-1 This is bad" add_note('-1 This is bad', create(:user))
add_note "+1 I want this" add_note('+1 I want this', create(:user))
issue.votes_count.should == 3 issue.votes_count.should == 3
end end
it 'should not count 2 -1 votes from the same user' do
add_note '-1 This is suspicious'
add_note '-1 This is bad'
issue.votes_count.should == 1
end
end end
describe "#upvotes_in_percent" do describe "#upvotes_in_percent" do
...@@ -90,17 +102,17 @@ describe Issue, 'Votes' do ...@@ -90,17 +102,17 @@ describe Issue, 'Votes' do
issue.upvotes_in_percent.should == 100 issue.upvotes_in_percent.should == 100
end end
it "should count multiple +1 notes as 100%" do it 'should count multiple +1 notes as 100%' do
add_note "+1 This is awesome" add_note('+1 This is awesome', create(:user))
add_note "+1 I want this" add_note('+1 I want this', create(:user))
issue.upvotes_in_percent.should == 100 issue.upvotes_in_percent.should == 100
end end
it "should count fractions for multiple +1 and -1 notes correctly" do it 'should count fractions for multiple +1 and -1 notes correctly' do
add_note "+1 This is awesome" add_note('+1 This is awesome', create(:user))
add_note "+1 I want this" add_note('+1 I want this', create(:user))
add_note "-1 This is bad" add_note('-1 This is bad', create(:user))
add_note "+1 me too" add_note('+1 me too', create(:user))
issue.upvotes_in_percent.should == 75 issue.upvotes_in_percent.should == 75
end end
end end
...@@ -115,22 +127,59 @@ describe Issue, 'Votes' do ...@@ -115,22 +127,59 @@ describe Issue, 'Votes' do
issue.downvotes_in_percent.should == 100 issue.downvotes_in_percent.should == 100
end end
it "should count multiple -1 notes as 100%" do it 'should count multiple -1 notes as 100%' do
add_note "-1 This is bad" add_note('-1 This is bad', create(:user))
add_note "-1 Away with this" add_note('-1 Away with this', create(:user))
issue.downvotes_in_percent.should == 100 issue.downvotes_in_percent.should == 100
end end
it "should count fractions for multiple +1 and -1 notes correctly" do it 'should count fractions for multiple +1 and -1 notes correctly' do
add_note "+1 This is awesome" add_note('+1 This is awesome', create(:user))
add_note "+1 I want this" add_note('+1 I want this', create(:user))
add_note "-1 This is bad" add_note('-1 This is bad', create(:user))
add_note "+1 me too" add_note('+1 me too', create(:user))
issue.downvotes_in_percent.should == 25 issue.downvotes_in_percent.should == 25
end end
end end
def add_note(text) describe '#filter_superceded_votes' do
issue.notes << create(:note, note: text, project: issue.project)
it 'should count a users vote only once amongst multiple votes' do
add_note('-1 This needs work before I will accept it')
add_note('+1 I want this', create(:user))
add_note('+1 This is is awesome', create(:user))
add_note('+1 this looks good now')
add_note('+1 This is awesome', create(:user))
add_note('+1 me too', create(:user))
issue.downvotes.should == 0
issue.upvotes.should == 5
end
it 'should count each users vote only once' do
add_note '-1 This needs work before it will be accepted'
add_note '+1 I like this'
add_note '+1 I still like this'
add_note '+1 I really like this'
add_note '+1 Give me this now!!!!'
p issue.downvotes.should == 0
p issue.upvotes.should == 1
end
it 'should count a users vote only once without caring about comments' do
add_note '-1 This needs work before it will be accepted'
add_note 'Comment 1'
add_note 'Another comment'
add_note '+1 vote'
add_note 'final comment'
p issue.downvotes.should == 0
p issue.upvotes.should == 1
end
end
def add_note(text, author = issue.author)
created_at = Time.now - 1.hour + Note.count.seconds
issue.notes << create(:note, note: text, project: issue.project,
author_id: author.id, created_at: created_at)
end end
end end
# == Schema Information
#
# Table name: application_settings
#
# id :integer not null, primary key
# default_projects_limit :integer
# signup_enabled :boolean
# signin_enabled :boolean
# gravatar_enabled :boolean
# sign_in_text :text
# created_at :datetime
# updated_at :datetime
# home_page_url :string(255)
#
require 'spec_helper' require 'spec_helper'
describe ApplicationSetting, models: true do describe ApplicationSetting, models: true do
......
...@@ -57,16 +57,12 @@ eos ...@@ -57,16 +57,12 @@ eos
let(:other_issue) { create :issue, project: other_project } let(:other_issue) { create :issue, project: other_project }
it 'detects issues that this commit is marked as closing' do it 'detects issues that this commit is marked as closing' do
stub_const('Gitlab::ClosingIssueExtractor::ISSUE_CLOSING_REGEX',
/Fixes #\d+/)
commit.stub(safe_message: "Fixes ##{issue.iid}") commit.stub(safe_message: "Fixes ##{issue.iid}")
commit.closes_issues(project).should == [issue] commit.closes_issues(project).should == [issue]
end end
it 'does not detect issues from other projects' do it 'does not detect issues from other projects' do
ext_ref = "#{other_project.path_with_namespace}##{other_issue.iid}" ext_ref = "#{other_project.path_with_namespace}##{other_issue.iid}"
stub_const('Gitlab::ClosingIssueExtractor::ISSUE_CLOSING_REGEX',
/^([Cc]loses|[Ff]ixes)/)
commit.stub(safe_message: "Fixes #{ext_ref}") commit.stub(safe_message: "Fixes #{ext_ref}")
commit.closes_issues(project).should be_empty commit.closes_issues(project).should be_empty
end end
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
# iid :integer # iid :integer
# description :text # description :text
# position :integer default(0) # position :integer default(0)
# locked_at :datetime
# #
require 'spec_helper' require 'spec_helper'
......
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
# import_status :string(255) # import_status :string(255)
# repository_size :float default(0.0) # repository_size :float default(0.0)
# star_count :integer default(0), not null # star_count :integer default(0), not null
# import_type :string(255)
# import_source :string(255)
# #
require 'spec_helper' require 'spec_helper'
......
...@@ -2,11 +2,12 @@ ...@@ -2,11 +2,12 @@
# #
# Table name: protected_branches # Table name: protected_branches
# #
# id :integer not null, primary key # id :integer not null, primary key
# project_id :integer not null # project_id :integer not null
# name :string(255) not null # name :string(255) not null
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# developers_can_push :boolean default(FALSE), not null
# #
require 'spec_helper' require 'spec_helper'
......
...@@ -26,8 +26,6 @@ ...@@ -26,8 +26,6 @@
# bio :string(255) # bio :string(255)
# failed_attempts :integer default(0) # failed_attempts :integer default(0)
# locked_at :datetime # locked_at :datetime
# extern_uid :string(255)
# provider :string(255)
# username :string(255) # username :string(255)
# can_create_group :boolean default(TRUE), not null # can_create_group :boolean default(TRUE), not null
# can_create_team :boolean default(TRUE), not null # can_create_team :boolean default(TRUE), not null
...@@ -36,7 +34,6 @@ ...@@ -36,7 +34,6 @@
# notification_level :integer default(1), not null # notification_level :integer default(1), not null
# password_expires_at :datetime # password_expires_at :datetime
# created_by_id :integer # created_by_id :integer
# last_credential_check_at :datetime
# avatar :string(255) # avatar :string(255)
# confirmation_token :string(255) # confirmation_token :string(255)
# confirmed_at :datetime # confirmed_at :datetime
...@@ -44,6 +41,8 @@ ...@@ -44,6 +41,8 @@
# unconfirmed_email :string(255) # unconfirmed_email :string(255)
# hide_no_ssh_key :boolean default(FALSE) # hide_no_ssh_key :boolean default(FALSE)
# website_url :string(255) default(""), not null # website_url :string(255) default(""), not null
# last_credential_check_at :datetime
# github_access_token :string(255)
# #
require 'spec_helper' require 'spec_helper'
......
...@@ -8,48 +8,48 @@ describe API::API, api: true do ...@@ -8,48 +8,48 @@ describe API::API, api: true do
before { project.team << [user, :developer] } before { project.team << [user, :developer] }
describe "GET /projects/:id/milestones" do describe 'GET /projects/:id/milestones' do
it "should return project milestones" do it 'should return project milestones' do
get api("/projects/#{project.id}/milestones", user) get api("/projects/#{project.id}/milestones", user)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
json_response.first['title'].should == milestone.title json_response.first['title'].should == milestone.title
end end
it "should return a 401 error if user not authenticated" do it 'should return a 401 error if user not authenticated' do
get api("/projects/#{project.id}/milestones") get api("/projects/#{project.id}/milestones")
response.status.should == 401 response.status.should == 401
end end
end end
describe "GET /projects/:id/milestones/:milestone_id" do describe 'GET /projects/:id/milestones/:milestone_id' do
it "should return a project milestone by id" do it 'should return a project milestone by id' do
get api("/projects/#{project.id}/milestones/#{milestone.id}", user) get api("/projects/#{project.id}/milestones/#{milestone.id}", user)
response.status.should == 200 response.status.should == 200
json_response['title'].should == milestone.title json_response['title'].should == milestone.title
json_response['iid'].should == milestone.iid json_response['iid'].should == milestone.iid
end end
it "should return 401 error if user not authenticated" do it 'should return 401 error if user not authenticated' do
get api("/projects/#{project.id}/milestones/#{milestone.id}") get api("/projects/#{project.id}/milestones/#{milestone.id}")
response.status.should == 401 response.status.should == 401
end end
it "should return a 404 error if milestone id not found" do it 'should return a 404 error if milestone id not found' do
get api("/projects/#{project.id}/milestones/1234", user) get api("/projects/#{project.id}/milestones/1234", user)
response.status.should == 404 response.status.should == 404
end end
end end
describe "POST /projects/:id/milestones" do describe 'POST /projects/:id/milestones' do
it "should create a new project milestone" do it 'should create a new project milestone' do
post api("/projects/#{project.id}/milestones", user), title: 'new milestone' post api("/projects/#{project.id}/milestones", user), title: 'new milestone'
response.status.should == 201 response.status.should == 201
json_response['title'].should == 'new milestone' json_response['title'].should == 'new milestone'
json_response['description'].should be_nil json_response['description'].should be_nil
end end
it "should create a new project milestone with description and due date" do it 'should create a new project milestone with description and due date' do
post api("/projects/#{project.id}/milestones", user), post api("/projects/#{project.id}/milestones", user),
title: 'new milestone', description: 'release', due_date: '2013-03-02' title: 'new milestone', description: 'release', due_date: '2013-03-02'
response.status.should == 201 response.status.should == 201
...@@ -57,29 +57,29 @@ describe API::API, api: true do ...@@ -57,29 +57,29 @@ describe API::API, api: true do
json_response['due_date'].should == '2013-03-02' json_response['due_date'].should == '2013-03-02'
end end
it "should return a 400 error if title is missing" do it 'should return a 400 error if title is missing' do
post api("/projects/#{project.id}/milestones", user) post api("/projects/#{project.id}/milestones", user)
response.status.should == 400 response.status.should == 400
end end
end end
describe "PUT /projects/:id/milestones/:milestone_id" do describe 'PUT /projects/:id/milestones/:milestone_id' do
it "should update a project milestone" do it 'should update a project milestone' do
put api("/projects/#{project.id}/milestones/#{milestone.id}", user), put api("/projects/#{project.id}/milestones/#{milestone.id}", user),
title: 'updated title' title: 'updated title'
response.status.should == 200 response.status.should == 200
json_response['title'].should == 'updated title' json_response['title'].should == 'updated title'
end end
it "should return a 404 error if milestone id not found" do it 'should return a 404 error if milestone id not found' do
put api("/projects/#{project.id}/milestones/1234", user), put api("/projects/#{project.id}/milestones/1234", user),
title: 'updated title' title: 'updated title'
response.status.should == 404 response.status.should == 404
end end
end end
describe "PUT /projects/:id/milestones/:milestone_id to close milestone" do describe 'PUT /projects/:id/milestones/:milestone_id to close milestone' do
it "should update a project milestone" do it 'should update a project milestone' do
put api("/projects/#{project.id}/milestones/#{milestone.id}", user), put api("/projects/#{project.id}/milestones/#{milestone.id}", user),
state_event: 'close' state_event: 'close'
response.status.should == 200 response.status.should == 200
...@@ -88,12 +88,29 @@ describe API::API, api: true do ...@@ -88,12 +88,29 @@ describe API::API, api: true do
end end
end end
describe "PUT /projects/:id/milestones/:milestone_id to test observer on close" do describe 'PUT /projects/:id/milestones/:milestone_id to test observer on close' do
it "should create an activity event when an milestone is closed" do it 'should create an activity event when an milestone is closed' do
Event.should_receive(:create) Event.should_receive(:create)
put api("/projects/#{project.id}/milestones/#{milestone.id}", user), put api("/projects/#{project.id}/milestones/#{milestone.id}", user),
state_event: 'close' state_event: 'close'
end end
end end
describe 'GET /projects/:id/milestones/:milestone_id/issues' do
before do
milestone.issues << create(:issue)
end
it 'should return project issues for a particular milestone' do
get api("/projects/#{project.id}/milestones/#{milestone.id}/issues", user)
response.status.should == 200
json_response.should be_an Array
json_response.first['milestone']['title'].should == milestone.title
end
it 'should return a 401 error if user not authenticated' do
get api("/projects/#{project.id}/milestones/#{milestone.id}/issues")
response.status.should == 401
end
end
end end
# -*- coding: utf-8 -*-
require 'spec_helper' require 'spec_helper'
describe API::API, api: true do describe API::API, api: true do
...@@ -12,43 +13,67 @@ describe API::API, api: true do ...@@ -12,43 +13,67 @@ describe API::API, api: true do
let(:snippet) { create(:project_snippet, author: user, project: project, title: 'example') } let(:snippet) { create(:project_snippet, author: user, project: project, title: 'example') }
let(:project_member) { create(:project_member, user: user, project: project, access_level: ProjectMember::MASTER) } let(:project_member) { create(:project_member, user: user, project: project, access_level: ProjectMember::MASTER) }
let(:project_member2) { create(:project_member, user: user3, project: project, access_level: ProjectMember::DEVELOPER) } let(:project_member2) { create(:project_member, user: user3, project: project, access_level: ProjectMember::DEVELOPER) }
let(:user4) { create(:user) }
let(:project3) do
create(:project,
name: 'second_project',
path: 'second_project',
creator_id: user.id,
namespace: user.namespace,
merge_requests_enabled: false,
issues_enabled: false, wiki_enabled: false,
snippets_enabled: false, visibility_level: 0)
end
let(:project_member3) do
create(:project_member,
user: user4,
project: project3,
access_level: ProjectMember::MASTER)
end
let(:project4) do
create(:project,
name: 'third_project',
path: 'third_project',
creator_id: user4.id,
namespace: user4.namespace)
end
describe "GET /projects" do describe 'GET /projects' do
before { project } before { project }
context "when unauthenticated" do context 'when unauthenticated' do
it "should return authentication error" do it 'should return authentication error' do
get api("/projects") get api('/projects')
response.status.should == 401 response.status.should == 401
end end
end end
context "when authenticated" do context 'when authenticated' do
it "should return an array of projects" do it 'should return an array of projects' do
get api("/projects", user) get api('/projects', user)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
json_response.first['name'].should == project.name json_response.first['name'].should == project.name
json_response.first['owner']['username'].should == user.username json_response.first['owner']['username'].should == user.username
end end
context "and using search" do context 'and using search' do
it "should return searched project" do it 'should return searched project' do
get api("/projects", user), { search: project.name } get api('/projects', user), { search: project.name }
response.status.should eq(200) response.status.should eq(200)
json_response.should be_an Array json_response.should be_an Array
json_response.length.should eq(1) json_response.length.should eq(1)
end end
end end
context "and using sorting" do context 'and using sorting' do
before do before do
project2 project2
project3 project3
end end
it "should return the correct order when sorted by id" do it 'should return the correct order when sorted by id' do
get api("/projects", user), { order_by: 'id', sort: 'desc'} get api('/projects', user), { order_by: 'id', sort: 'desc'}
response.status.should eq(200) response.status.should eq(200)
json_response.should be_an Array json_response.should be_an Array
json_response.first['id'].should eq(project3.id) json_response.first['id'].should eq(project3.id)
...@@ -57,26 +82,26 @@ describe API::API, api: true do ...@@ -57,26 +82,26 @@ describe API::API, api: true do
end end
end end
describe "GET /projects/all" do describe 'GET /projects/all' do
before { project } before { project }
context "when unauthenticated" do context 'when unauthenticated' do
it "should return authentication error" do it 'should return authentication error' do
get api("/projects/all") get api('/projects/all')
response.status.should == 401 response.status.should == 401
end end
end end
context "when authenticated as regular user" do context 'when authenticated as regular user' do
it "should return authentication error" do it 'should return authentication error' do
get api("/projects/all", user) get api('/projects/all', user)
response.status.should == 403 response.status.should == 403
end end
end end
context "when authenticated as admin" do context 'when authenticated as admin' do
it "should return an array of all projects" do it 'should return an array of all projects' do
get api("/projects/all", admin) get api('/projects/all', admin)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
project_name = project.name project_name = project.name
...@@ -92,59 +117,59 @@ describe API::API, api: true do ...@@ -92,59 +117,59 @@ describe API::API, api: true do
end end
end end
describe "POST /projects" do describe 'POST /projects' do
context "maximum number of projects reached" do context 'maximum number of projects reached' do
before do before do
(1..user2.projects_limit).each do |project| (1..user2.projects_limit).each do |project|
post api("/projects", user2), name: "foo#{project}" post api('/projects', user2), name: "foo#{project}"
end end
end end
it "should not create new project" do it 'should not create new project' do
expect { expect {
post api("/projects", user2), name: 'foo' post api('/projects', user2), name: 'foo'
}.to change {Project.count}.by(0) }.to change {Project.count}.by(0)
end end
end end
it "should create new project without path" do it 'should create new project without path' do
expect { post api("/projects", user), name: 'foo' }.to change {Project.count}.by(1) expect { post api('/projects', user), name: 'foo' }.to change {Project.count}.by(1)
end end
it "should not create new project without name" do it 'should not create new project without name' do
expect { post api("/projects", user) }.to_not change {Project.count} expect { post api('/projects', user) }.to_not change {Project.count}
end end
it "should return a 400 error if name not given" do it 'should return a 400 error if name not given' do
post api("/projects", user) post api('/projects', user)
response.status.should == 400 response.status.should == 400
end end
it "should create last project before reaching project limit" do it 'should create last project before reaching project limit' do
(1..user2.projects_limit-1).each { |p| post api("/projects", user2), name: "foo#{p}" } (1..user2.projects_limit-1).each { |p| post api('/projects', user2), name: "foo#{p}" }
post api("/projects", user2), name: "foo" post api('/projects', user2), name: 'foo'
response.status.should == 201 response.status.should == 201
end end
it "should respond with 201 on success" do it 'should respond with 201 on success' do
post api("/projects", user), name: 'foo' post api('/projects', user), name: 'foo'
response.status.should == 201 response.status.should == 201
end end
it "should respond with 400 if name is not given" do it 'should respond with 400 if name is not given' do
post api("/projects", user) post api('/projects', user)
response.status.should == 400 response.status.should == 400
end end
it "should return a 403 error if project limit reached" do it 'should return a 403 error if project limit reached' do
(1..user.projects_limit).each do |p| (1..user.projects_limit).each do |p|
post api("/projects", user), name: "foo#{p}" post api('/projects', user), name: "foo#{p}"
end end
post api("/projects", user), name: 'bar' post api('/projects', user), name: 'bar'
response.status.should == 403 response.status.should == 403
end end
it "should assign attributes to project" do it 'should assign attributes to project' do
project = attributes_for(:project, { project = attributes_for(:project, {
path: 'camelCasePath', path: 'camelCasePath',
description: Faker::Lorem.sentence, description: Faker::Lorem.sentence,
...@@ -153,69 +178,69 @@ describe API::API, api: true do ...@@ -153,69 +178,69 @@ describe API::API, api: true do
wiki_enabled: false wiki_enabled: false
}) })
post api("/projects", user), project post api('/projects', user), project
project.each_pair do |k,v| project.each_pair do |k,v|
json_response[k.to_s].should == v json_response[k.to_s].should == v
end end
end end
it "should set a project as public" do it 'should set a project as public' do
project = attributes_for(:project, :public) project = attributes_for(:project, :public)
post api("/projects", user), project post api('/projects', user), project
json_response['public'].should be_true json_response['public'].should be_true
json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC
end end
it "should set a project as public using :public" do it 'should set a project as public using :public' do
project = attributes_for(:project, { public: true }) project = attributes_for(:project, { public: true })
post api("/projects", user), project post api('/projects', user), project
json_response['public'].should be_true json_response['public'].should be_true
json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC
end end
it "should set a project as internal" do it 'should set a project as internal' do
project = attributes_for(:project, :internal) project = attributes_for(:project, :internal)
post api("/projects", user), project post api('/projects', user), project
json_response['public'].should be_false json_response['public'].should be_false
json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL
end end
it "should set a project as internal overriding :public" do it 'should set a project as internal overriding :public' do
project = attributes_for(:project, :internal, { public: true }) project = attributes_for(:project, :internal, { public: true })
post api("/projects", user), project post api('/projects', user), project
json_response['public'].should be_false json_response['public'].should be_false
json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL
end end
it "should set a project as private" do it 'should set a project as private' do
project = attributes_for(:project, :private) project = attributes_for(:project, :private)
post api("/projects", user), project post api('/projects', user), project
json_response['public'].should be_false json_response['public'].should be_false
json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE
end end
it "should set a project as private using :public" do it 'should set a project as private using :public' do
project = attributes_for(:project, { public: false }) project = attributes_for(:project, { public: false })
post api("/projects", user), project post api('/projects', user), project
json_response['public'].should be_false json_response['public'].should be_false
json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE
end end
end end
describe "POST /projects/user/:id" do describe 'POST /projects/user/:id' do
before { project } before { project }
before { admin } before { admin }
it "should create new project without path" do it 'should create new project without path' do
expect { post api("/projects/user/#{user.id}", admin), name: 'foo' }.to change {Project.count}.by(1) expect { post api("/projects/user/#{user.id}", admin), name: 'foo' }.to change {Project.count}.by(1)
end end
it "should not create new project without name" do it 'should not create new project without name' do
expect { post api("/projects/user/#{user.id}", admin) }.to_not change {Project.count} expect { post api("/projects/user/#{user.id}", admin) }.to_not change {Project.count}
end end
it "should respond with 201 on success" do it 'should respond with 201 on success' do
post api("/projects/user/#{user.id}", admin), name: 'foo' post api("/projects/user/#{user.id}", admin), name: 'foo'
response.status.should == 201 response.status.should == 201
end end
...@@ -235,7 +260,7 @@ describe API::API, api: true do ...@@ -235,7 +260,7 @@ describe API::API, api: true do
] ]
end end
it "should assign attributes to project" do it 'should assign attributes to project' do
project = attributes_for(:project, { project = attributes_for(:project, {
description: Faker::Lorem.sentence, description: Faker::Lorem.sentence,
issues_enabled: false, issues_enabled: false,
...@@ -251,42 +276,42 @@ describe API::API, api: true do ...@@ -251,42 +276,42 @@ describe API::API, api: true do
end end
end end
it "should set a project as public" do it 'should set a project as public' do
project = attributes_for(:project, :public) project = attributes_for(:project, :public)
post api("/projects/user/#{user.id}", admin), project post api("/projects/user/#{user.id}", admin), project
json_response['public'].should be_true json_response['public'].should be_true
json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC
end end
it "should set a project as public using :public" do it 'should set a project as public using :public' do
project = attributes_for(:project, { public: true }) project = attributes_for(:project, { public: true })
post api("/projects/user/#{user.id}", admin), project post api("/projects/user/#{user.id}", admin), project
json_response['public'].should be_true json_response['public'].should be_true
json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC
end end
it "should set a project as internal" do it 'should set a project as internal' do
project = attributes_for(:project, :internal) project = attributes_for(:project, :internal)
post api("/projects/user/#{user.id}", admin), project post api("/projects/user/#{user.id}", admin), project
json_response['public'].should be_false json_response['public'].should be_false
json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL
end end
it "should set a project as internal overriding :public" do it 'should set a project as internal overriding :public' do
project = attributes_for(:project, :internal, { public: true }) project = attributes_for(:project, :internal, { public: true })
post api("/projects/user/#{user.id}", admin), project post api("/projects/user/#{user.id}", admin), project
json_response['public'].should be_false json_response['public'].should be_false
json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL
end end
it "should set a project as private" do it 'should set a project as private' do
project = attributes_for(:project, :private) project = attributes_for(:project, :private)
post api("/projects/user/#{user.id}", admin), project post api("/projects/user/#{user.id}", admin), project
json_response['public'].should be_false json_response['public'].should be_false
json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE
end end
it "should set a project as private using :public" do it 'should set a project as private using :public' do
project = attributes_for(:project, { public: false }) project = attributes_for(:project, { public: false })
post api("/projects/user/#{user.id}", admin), project post api("/projects/user/#{user.id}", admin), project
json_response['public'].should be_false json_response['public'].should be_false
...@@ -294,30 +319,30 @@ describe API::API, api: true do ...@@ -294,30 +319,30 @@ describe API::API, api: true do
end end
end end
describe "GET /projects/:id" do describe 'GET /projects/:id' do
before { project } before { project }
before { project_member } before { project_member }
it "should return a project by id" do it 'should return a project by id' do
get api("/projects/#{project.id}", user) get api("/projects/#{project.id}", user)
response.status.should == 200 response.status.should == 200
json_response['name'].should == project.name json_response['name'].should == project.name
json_response['owner']['username'].should == user.username json_response['owner']['username'].should == user.username
end end
it "should return a project by path name" do it 'should return a project by path name' do
get api("/projects/#{project.id}", user) get api("/projects/#{project.id}", user)
response.status.should == 200 response.status.should == 200
json_response['name'].should == project.name json_response['name'].should == project.name
end end
it "should return a 404 error if not found" do it 'should return a 404 error if not found' do
get api("/projects/42", user) get api('/projects/42', user)
response.status.should == 404 response.status.should == 404
json_response['message'].should == '404 Project Not Found' json_response['message'].should == '404 Project Not Found'
end end
it "should return a 404 error if user is not a member" do it 'should return a 404 error if user is not a member' do
other_user = create(:user) other_user = create(:user)
get api("/projects/#{project.id}", other_user) get api("/projects/#{project.id}", other_user)
response.status.should == 404 response.status.should == 404
...@@ -331,8 +356,8 @@ describe API::API, api: true do ...@@ -331,8 +356,8 @@ describe API::API, api: true do
end end
it { response.status.should == 200 } it { response.status.should == 200 }
it { json_response['permissions']["project_access"]["access_level"].should == Gitlab::Access::MASTER } it { json_response['permissions']['project_access']['access_level'].should == Gitlab::Access::MASTER }
it { json_response['permissions']["group_access"].should be_nil } it { json_response['permissions']['group_access'].should be_nil }
end end
context 'group project' do context 'group project' do
...@@ -343,16 +368,16 @@ describe API::API, api: true do ...@@ -343,16 +368,16 @@ describe API::API, api: true do
end end
it { response.status.should == 200 } it { response.status.should == 200 }
it { json_response['permissions']["project_access"].should be_nil } it { json_response['permissions']['project_access'].should be_nil }
it { json_response['permissions']["group_access"]["access_level"].should == Gitlab::Access::OWNER } it { json_response['permissions']['group_access']['access_level'].should == Gitlab::Access::OWNER }
end end
end end
end end
describe "GET /projects/:id/events" do describe 'GET /projects/:id/events' do
before { project_member } before { project_member }
it "should return a project events" do it 'should return a project events' do
get api("/projects/#{project.id}/events", user) get api("/projects/#{project.id}/events", user)
response.status.should == 200 response.status.should == 200
json_event = json_response.first json_event = json_response.first
...@@ -362,23 +387,23 @@ describe API::API, api: true do ...@@ -362,23 +387,23 @@ describe API::API, api: true do
json_event['author_username'].should == user.username json_event['author_username'].should == user.username
end end
it "should return a 404 error if not found" do it 'should return a 404 error if not found' do
get api("/projects/42/events", user) get api('/projects/42/events', user)
response.status.should == 404 response.status.should == 404
json_response['message'].should == '404 Project Not Found' json_response['message'].should == '404 Project Not Found'
end end
it "should return a 404 error if user is not a member" do it 'should return a 404 error if user is not a member' do
other_user = create(:user) other_user = create(:user)
get api("/projects/#{project.id}/events", other_user) get api("/projects/#{project.id}/events", other_user)
response.status.should == 404 response.status.should == 404
end end
end end
describe "GET /projects/:id/snippets" do describe 'GET /projects/:id/snippets' do
before { snippet } before { snippet }
it "should return an array of project snippets" do it 'should return an array of project snippets' do
get api("/projects/#{project.id}/snippets", user) get api("/projects/#{project.id}/snippets", user)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
...@@ -386,48 +411,48 @@ describe API::API, api: true do ...@@ -386,48 +411,48 @@ describe API::API, api: true do
end end
end end
describe "GET /projects/:id/snippets/:snippet_id" do describe 'GET /projects/:id/snippets/:snippet_id' do
it "should return a project snippet" do it 'should return a project snippet' do
get api("/projects/#{project.id}/snippets/#{snippet.id}", user) get api("/projects/#{project.id}/snippets/#{snippet.id}", user)
response.status.should == 200 response.status.should == 200
json_response['title'].should == snippet.title json_response['title'].should == snippet.title
end end
it "should return a 404 error if snippet id not found" do it 'should return a 404 error if snippet id not found' do
get api("/projects/#{project.id}/snippets/1234", user) get api("/projects/#{project.id}/snippets/1234", user)
response.status.should == 404 response.status.should == 404
end end
end end
describe "POST /projects/:id/snippets" do describe 'POST /projects/:id/snippets' do
it "should create a new project snippet" do it 'should create a new project snippet' do
post api("/projects/#{project.id}/snippets", user), post api("/projects/#{project.id}/snippets", user),
title: 'api test', file_name: 'sample.rb', code: 'test' title: 'api test', file_name: 'sample.rb', code: 'test'
response.status.should == 201 response.status.should == 201
json_response['title'].should == 'api test' json_response['title'].should == 'api test'
end end
it "should return a 400 error if title is not given" do it 'should return a 400 error if title is not given' do
post api("/projects/#{project.id}/snippets", user), post api("/projects/#{project.id}/snippets", user),
file_name: 'sample.rb', code: 'test' file_name: 'sample.rb', code: 'test'
response.status.should == 400 response.status.should == 400
end end
it "should return a 400 error if file_name not given" do it 'should return a 400 error if file_name not given' do
post api("/projects/#{project.id}/snippets", user), post api("/projects/#{project.id}/snippets", user),
title: 'api test', code: 'test' title: 'api test', code: 'test'
response.status.should == 400 response.status.should == 400
end end
it "should return a 400 error if code not given" do it 'should return a 400 error if code not given' do
post api("/projects/#{project.id}/snippets", user), post api("/projects/#{project.id}/snippets", user),
title: 'api test', file_name: 'sample.rb' title: 'api test', file_name: 'sample.rb'
response.status.should == 400 response.status.should == 400
end end
end end
describe "PUT /projects/:id/snippets/:shippet_id" do describe 'PUT /projects/:id/snippets/:shippet_id' do
it "should update an existing project snippet" do it 'should update an existing project snippet' do
put api("/projects/#{project.id}/snippets/#{snippet.id}", user), put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
code: 'updated code' code: 'updated code'
response.status.should == 200 response.status.should == 200
...@@ -435,7 +460,7 @@ describe API::API, api: true do ...@@ -435,7 +460,7 @@ describe API::API, api: true do
snippet.reload.content.should == 'updated code' snippet.reload.content.should == 'updated code'
end end
it "should update an existing project snippet with new title" do it 'should update an existing project snippet with new title' do
put api("/projects/#{project.id}/snippets/#{snippet.id}", user), put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
title: 'other api test' title: 'other api test'
response.status.should == 200 response.status.should == 200
...@@ -443,10 +468,10 @@ describe API::API, api: true do ...@@ -443,10 +468,10 @@ describe API::API, api: true do
end end
end end
describe "DELETE /projects/:id/snippets/:snippet_id" do describe 'DELETE /projects/:id/snippets/:snippet_id' do
before { snippet } before { snippet }
it "should delete existing project snippet" do it 'should delete existing project snippet' do
expect { expect {
delete api("/projects/#{project.id}/snippets/#{snippet.id}", user) delete api("/projects/#{project.id}/snippets/#{snippet.id}", user)
}.to change { Snippet.count }.by(-1) }.to change { Snippet.count }.by(-1)
...@@ -459,13 +484,13 @@ describe API::API, api: true do ...@@ -459,13 +484,13 @@ describe API::API, api: true do
end end
end end
describe "GET /projects/:id/snippets/:snippet_id/raw" do describe 'GET /projects/:id/snippets/:snippet_id/raw' do
it "should get a raw project snippet" do it 'should get a raw project snippet' do
get api("/projects/#{project.id}/snippets/#{snippet.id}/raw", user) get api("/projects/#{project.id}/snippets/#{snippet.id}/raw", user)
response.status.should == 200 response.status.should == 200
end end
it "should return a 404 error if raw project snippet not found" do it 'should return a 404 error if raw project snippet not found' do
get api("/projects/#{project.id}/snippets/5555/raw", user) get api("/projects/#{project.id}/snippets/5555/raw", user)
response.status.should == 404 response.status.should == 404
end end
...@@ -475,10 +500,10 @@ describe API::API, api: true do ...@@ -475,10 +500,10 @@ describe API::API, api: true do
let(:deploy_keys_project) { create(:deploy_keys_project, project: project) } let(:deploy_keys_project) { create(:deploy_keys_project, project: project) }
let(:deploy_key) { deploy_keys_project.deploy_key } let(:deploy_key) { deploy_keys_project.deploy_key }
describe "GET /projects/:id/keys" do describe 'GET /projects/:id/keys' do
before { deploy_key } before { deploy_key }
it "should return array of ssh keys" do it 'should return array of ssh keys' do
get api("/projects/#{project.id}/keys", user) get api("/projects/#{project.id}/keys", user)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
...@@ -486,22 +511,22 @@ describe API::API, api: true do ...@@ -486,22 +511,22 @@ describe API::API, api: true do
end end
end end
describe "GET /projects/:id/keys/:key_id" do describe 'GET /projects/:id/keys/:key_id' do
it "should return a single key" do it 'should return a single key' do
get api("/projects/#{project.id}/keys/#{deploy_key.id}", user) get api("/projects/#{project.id}/keys/#{deploy_key.id}", user)
response.status.should == 200 response.status.should == 200
json_response['title'].should == deploy_key.title json_response['title'].should == deploy_key.title
end end
it "should return 404 Not Found with invalid ID" do it 'should return 404 Not Found with invalid ID' do
get api("/projects/#{project.id}/keys/404", user) get api("/projects/#{project.id}/keys/404", user)
response.status.should == 404 response.status.should == 404
end end
end end
describe "POST /projects/:id/keys" do describe 'POST /projects/:id/keys' do
it "should not create an invalid ssh key" do it 'should not create an invalid ssh key' do
post api("/projects/#{project.id}/keys", user), { title: "invalid key" } post api("/projects/#{project.id}/keys", user), { title: 'invalid key' }
response.status.should == 400 response.status.should == 400
json_response['message']['key'].should == [ json_response['message']['key'].should == [
'can\'t be blank', 'can\'t be blank',
...@@ -519,7 +544,7 @@ describe API::API, api: true do ...@@ -519,7 +544,7 @@ describe API::API, api: true do
] ]
end end
it "should create new ssh key" do it 'should create new ssh key' do
key_attrs = attributes_for :key key_attrs = attributes_for :key
expect { expect {
post api("/projects/#{project.id}/keys", user), key_attrs post api("/projects/#{project.id}/keys", user), key_attrs
...@@ -527,16 +552,16 @@ describe API::API, api: true do ...@@ -527,16 +552,16 @@ describe API::API, api: true do
end end
end end
describe "DELETE /projects/:id/keys/:key_id" do describe 'DELETE /projects/:id/keys/:key_id' do
before { deploy_key } before { deploy_key }
it "should delete existing key" do it 'should delete existing key' do
expect { expect {
delete api("/projects/#{project.id}/keys/#{deploy_key.id}", user) delete api("/projects/#{project.id}/keys/#{deploy_key.id}", user)
}.to change{ project.deploy_keys.count }.by(-1) }.to change{ project.deploy_keys.count }.by(-1)
end end
it "should return 404 Not Found with invalid ID" do it 'should return 404 Not Found with invalid ID' do
delete api("/projects/#{project.id}/keys/404", user) delete api("/projects/#{project.id}/keys/404", user)
response.status.should == 404 response.status.should == 404
end end
...@@ -547,7 +572,7 @@ describe API::API, api: true do ...@@ -547,7 +572,7 @@ describe API::API, api: true do
let(:project_fork_target) { create(:project) } let(:project_fork_target) { create(:project) }
let(:project_fork_source) { create(:project, :public) } let(:project_fork_source) { create(:project, :public) }
describe "POST /projects/:id/fork/:forked_from_id" do describe 'POST /projects/:id/fork/:forked_from_id' do
let(:new_project_fork_source) { create(:project, :public) } let(:new_project_fork_source) { create(:project, :public) }
it "shouldn't available for non admin users" do it "shouldn't available for non admin users" do
...@@ -555,7 +580,7 @@ describe API::API, api: true do ...@@ -555,7 +580,7 @@ describe API::API, api: true do
response.status.should == 403 response.status.should == 403
end end
it "should allow project to be forked from an existing project" do it 'should allow project to be forked from an existing project' do
project_fork_target.forked?.should_not be_true project_fork_target.forked?.should_not be_true
post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin) post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
response.status.should == 201 response.status.should == 201
...@@ -565,12 +590,12 @@ describe API::API, api: true do ...@@ -565,12 +590,12 @@ describe API::API, api: true do
project_fork_target.forked?.should be_true project_fork_target.forked?.should be_true
end end
it "should fail if forked_from project which does not exist" do it 'should fail if forked_from project which does not exist' do
post api("/projects/#{project_fork_target.id}/fork/9999", admin) post api("/projects/#{project_fork_target.id}/fork/9999", admin)
response.status.should == 404 response.status.should == 404
end end
it "should fail with 409 if already forked" do it 'should fail with 409 if already forked' do
post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin) post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
project_fork_target.reload project_fork_target.reload
project_fork_target.forked_from_project.id.should == project_fork_source.id project_fork_target.forked_from_project.id.should == project_fork_source.id
...@@ -582,14 +607,14 @@ describe API::API, api: true do ...@@ -582,14 +607,14 @@ describe API::API, api: true do
end end
end end
describe "DELETE /projects/:id/fork" do describe 'DELETE /projects/:id/fork' do
it "shouldn't available for non admin users" do it "shouldn't available for non admin users" do
delete api("/projects/#{project_fork_target.id}/fork", user) delete api("/projects/#{project_fork_target.id}/fork", user)
response.status.should == 403 response.status.should == 403
end end
it "should make forked project unforked" do it 'should make forked project unforked' do
post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin) post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
project_fork_target.reload project_fork_target.reload
project_fork_target.forked_from_project.should_not be_nil project_fork_target.forked_from_project.should_not be_nil
...@@ -601,7 +626,7 @@ describe API::API, api: true do ...@@ -601,7 +626,7 @@ describe API::API, api: true do
project_fork_target.forked?.should_not be_true project_fork_target.forked?.should_not be_true
end end
it "should be idempotent if not forked" do it 'should be idempotent if not forked' do
project_fork_target.forked_from_project.should be_nil project_fork_target.forked_from_project.should be_nil
delete api("/projects/#{project_fork_target.id}/fork", admin) delete api("/projects/#{project_fork_target.id}/fork", admin)
response.status.should == 200 response.status.should == 200
...@@ -610,7 +635,7 @@ describe API::API, api: true do ...@@ -610,7 +635,7 @@ describe API::API, api: true do
end end
end end
describe "GET /projects/search/:query" do describe 'GET /projects/search/:query' do
let!(:query) { 'query'} let!(:query) { 'query'}
let!(:search) { create(:empty_project, name: query, creator_id: user.id, namespace: user.namespace) } let!(:search) { create(:empty_project, name: query, creator_id: user.id, namespace: user.namespace) }
let!(:pre) { create(:empty_project, name: "pre_#{query}", creator_id: user.id, namespace: user.namespace) } let!(:pre) { create(:empty_project, name: "pre_#{query}", creator_id: user.id, namespace: user.namespace) }
...@@ -622,15 +647,15 @@ describe API::API, api: true do ...@@ -622,15 +647,15 @@ describe API::API, api: true do
let!(:public) { create(:empty_project, :public, name: "public #{query}") } let!(:public) { create(:empty_project, :public, name: "public #{query}") }
let!(:unfound_public) { create(:empty_project, :public, name: 'unfound public') } let!(:unfound_public) { create(:empty_project, :public, name: 'unfound public') }
context "when unauthenticated" do context 'when unauthenticated' do
it "should return authentication error" do it 'should return authentication error' do
get api("/projects/search/#{query}") get api("/projects/search/#{query}")
response.status.should == 401 response.status.should == 401
end end
end end
context "when authenticated" do context 'when authenticated' do
it "should return an array of projects" do it 'should return an array of projects' do
get api("/projects/search/#{query}",user) get api("/projects/search/#{query}",user)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
...@@ -639,8 +664,8 @@ describe API::API, api: true do ...@@ -639,8 +664,8 @@ describe API::API, api: true do
end end
end end
context "when authenticated as a different user" do context 'when authenticated as a different user' do
it "should return matching public projects" do it 'should return matching public projects' do
get api("/projects/search/#{query}", user2) get api("/projects/search/#{query}", user2)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
...@@ -650,9 +675,121 @@ describe API::API, api: true do ...@@ -650,9 +675,121 @@ describe API::API, api: true do
end end
end end
describe "DELETE /projects/:id" do describe 'PUT /projects/:id̈́' do
context "when authenticated as user" do before { project }
it "should remove project" do before { user }
before { user3 }
before { user4 }
before { project3 }
before { project4 }
before { project_member3 }
before { project_member2 }
context 'when unauthenticated' do
it 'should return authentication error' do
project_param = { name: 'bar' }
put api("/projects/#{project.id}"), project_param
response.status.should == 401
end
end
context 'when authenticated as project owner' do
it 'should update name' do
project_param = { name: 'bar' }
put api("/projects/#{project.id}", user), project_param
response.status.should == 200
project_param.each_pair do |k, v|
json_response[k.to_s].should == v
end
end
it 'should update visibility_level' do
project_param = { visibility_level: 20 }
put api("/projects/#{project3.id}", user), project_param
response.status.should == 200
project_param.each_pair do |k, v|
json_response[k.to_s].should == v
end
end
it 'should not update name to existing name' do
project_param = { name: project3.name }
put api("/projects/#{project.id}", user), project_param
response.status.should == 400
json_response['message']['name'].should == ['has already been taken']
end
it 'should update path & name to existing path & name in different namespace' do
project_param = { path: project4.path, name: project4.name }
put api("/projects/#{project3.id}", user), project_param
response.status.should == 200
project_param.each_pair do |k, v|
json_response[k.to_s].should == v
end
end
end
context 'when authenticated as project master' do
it 'should update path' do
project_param = { path: 'bar' }
put api("/projects/#{project3.id}", user4), project_param
response.status.should == 200
project_param.each_pair do |k, v|
json_response[k.to_s].should == v
end
end
it 'should update other attributes' do
project_param = { issues_enabled: true,
wiki_enabled: true,
snippets_enabled: true,
merge_requests_enabled: true,
description: 'new description' }
put api("/projects/#{project3.id}", user4), project_param
response.status.should == 200
project_param.each_pair do |k, v|
json_response[k.to_s].should == v
end
end
it 'should not update path to existing path' do
project_param = { path: project.path }
put api("/projects/#{project3.id}", user4), project_param
response.status.should == 400
json_response['message']['path'].should == ['has already been taken']
end
it 'should not update name' do
project_param = { name: 'bar' }
put api("/projects/#{project3.id}", user4), project_param
response.status.should == 403
end
it 'should not update visibility_level' do
project_param = { visibility_level: 20 }
put api("/projects/#{project3.id}", user4), project_param
response.status.should == 403
end
end
context 'when authenticated as project developer' do
it 'should not update other attributes' do
project_param = { path: 'bar',
issues_enabled: true,
wiki_enabled: true,
snippets_enabled: true,
merge_requests_enabled: true,
description: 'new description' }
put api("/projects/#{project.id}", user3), project_param
response.status.should == 403
end
end
end
describe 'DELETE /projects/:id' do
context 'when authenticated as user' do
it 'should remove project' do
expect(GitlabShellWorker).to( expect(GitlabShellWorker).to(
receive(:perform_async).with(:remove_repository, receive(:perform_async).with(:remove_repository,
/#{project.path_with_namespace}/) /#{project.path_with_namespace}/)
...@@ -662,32 +799,32 @@ describe API::API, api: true do ...@@ -662,32 +799,32 @@ describe API::API, api: true do
response.status.should == 200 response.status.should == 200
end end
it "should not remove a project if not an owner" do it 'should not remove a project if not an owner' do
user3 = create(:user) user3 = create(:user)
project.team << [user3, :developer] project.team << [user3, :developer]
delete api("/projects/#{project.id}", user3) delete api("/projects/#{project.id}", user3)
response.status.should == 403 response.status.should == 403
end end
it "should not remove a non existing project" do it 'should not remove a non existing project' do
delete api("/projects/1328", user) delete api('/projects/1328', user)
response.status.should == 404 response.status.should == 404
end end
it "should not remove a project not attached to user" do it 'should not remove a project not attached to user' do
delete api("/projects/#{project.id}", user2) delete api("/projects/#{project.id}", user2)
response.status.should == 404 response.status.should == 404
end end
end end
context "when authenticated as admin" do context 'when authenticated as admin' do
it "should remove any existing project" do it 'should remove any existing project' do
delete api("/projects/#{project.id}", admin) delete api("/projects/#{project.id}", admin)
response.status.should == 200 response.status.should == 200
end end
it "should not remove a non existing project" do it 'should not remove a non existing project' do
delete api("/projects/1328", admin) delete api('/projects/1328', admin)
response.status.should == 404 response.status.should == 404
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment