Commit cb659e4c authored by Timm Drevensek's avatar Timm Drevensek

Merge branch 'master' into request/relative_submodules

Conflicts:
	CHANGELOG
parents ea82bcd3 3b0510a7
v 6.8.0
- Ability to at mention users that are participating in issue and merge req. discussion
- Enabled GZip Compression for assets in example Nginx, make sure that Nginx is compiled with --with-http_gzip_static_module flag (this is default in Ubuntu)
- Add support for relative submodules
- Make user search case-insensitive (Christopher Arnold)
- Remove omniauth-ldap nickname bug workaround
- Drop all tables before restoring a Postgres backup
- Make the repository downloads path configurable
- Create branches via API (sponsored by O'Reilly Media)
v 6.7.2
- Fix upgrader script
......
......@@ -63,10 +63,11 @@ If you can, please submit a merge request with the fix or improvements including
1. Add your changes to the [CHANGELOG](CHANGELOG)
1. If you have multiple commits please combine them into one commit by [squashing them](http://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)
1. Push the commit to your fork
1. Submit a merge request (MR)
1. Submit a merge request (MR) to the master branch
1. The MR title should describes the change you want to make
1. The MR description should give a motive for your change and the method you used to achieve it
1. If the MR changes the UI it should include before and after screenshots
1. If the MR changes CSS classes please include the list of affected pages `grep css-class ./app -R`
1. Link relevant [issues](https://gitlab.com/gitlab-org/gitlab-ce/issues) and/or [feature requests](http://feedback.gitlab.com/) from the merge request description and leave a comment on them with a link back to the MR
1. Be prepared to answer questions and incorporate feedback even if requests for this arrive weeks or months after your MR submittion
1. If your MR touches code that executes shell commands, make sure it adheres to the [shell command guidelines]( doc/development/shell_commands.md).
......
# A sample Guardfile
# More info at https://github.com/guard/guard#readme
guard 'rspec', :version => 2, :all_on_start => false, :all_after_pass => false do
guard 'rspec', cmd: "spring rspec", version: 2, all_on_start: false, all_after_pass: false do
watch(%r{^spec/.+_spec\.rb$})
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
watch(%r{^lib/api/(.+)\.rb$}) { |m| "spec/requests/api/#{m[1]}_spec.rb" }
......
......@@ -113,38 +113,10 @@ or start each component separately
Single Spinach test: bundle exec spinach features/project/issues/milestones.feature
### GitLab interfaces
### Documentation
* [GitLab API doc](doc/api/README.md) or see the [GitLab API website](http://api.gitlab.org/)
* [Rake tasks](doc/raketasks) including a [backup and restore procedure](doc/raketasks/backup_restore.md)
* [Directory structure](doc/install/structure.md)
* [Database installation](doc/install/databases.md)
* [Markdown specification](doc/markdown/markdown.md)
* [Security guide](doc/security/rack_attack.md) to throttle abusive requests
All documentation can be found on [doc.gitlab.com/ce/](http://doc.gitlab.com/ce/).
### Getting help
* [Maintenance policy](MAINTENANCE.md) specifies what versions are supported.
* [Troubleshooting guide](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide) contains solutions to common problems.
* [Mailing list](https://groups.google.com/forum/#!forum/gitlabhq) and [Stack Overflow](http://stackoverflow.com/questions/tagged/gitlab) are the best places to ask questions. For example you can use it if you have questions about: permission denied errors, invisible repos, can't clone/pull/push or with web hooks that don't fire. Please search for similar issues before posting your own, there's a good chance somebody else had the same issue you have now and has resolved it. There are a lot of helpful GitLab users there who may be able to help you quickly. If your particular issue turns out to be a bug, it will find its way from there to a fix.
* [Feature request forum](http://feedback.gitlab.com) is the place to propose and discuss new features for GitLab.
* [Contributing guide](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) describes how to submit merge requests and issues. Pull requests and issues not in line with the guidelines in this document will be closed.
* [Support subscription](http://www.gitlab.com/subscription/) connects you to the knowledge of GitLab experts that will resolve your issues and answer your questions.
* [Consultancy](http://www.gitlab.com/consultancy/) from the GitLab experts for installations, upgrades and customizations.
* [#gitlab IRC channel](http://www.freenode.net/) on Freenode to get in touch with other GitLab users and get help, it's managed by James Newton (newton), Drew Blessing (dblessing), and Sam Gleske (sag47).
* [Book](http://www.packtpub.com/gitlab-repository-management/book) written by GitLab enthusiast Jonathan M. Hethey is unofficial but it offers a good overview.
* [Gitter chat room](https://gitter.im/gitlabhq/gitlabhq#) here you can ask questions when you need help.
Please see [Getting help for GitLab](https://www.gitlab.com/getting-help/) on our website for the many options to get help.
......@@ -13,6 +13,12 @@
border-bottom: 1px solid #eee;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
&:after {
content: " ";
display: table;
clear: both;
}
&.disabled {
color: #888;
}
......@@ -46,6 +52,12 @@
.author { color: #999; }
.list-item-name {
float: left;
position: relative;
top: 3px;
}
p {
padding-top: 1px;
margin: 0;
......
......@@ -113,6 +113,5 @@
float: left;
margin-right: 3px;
color: #999;
margin-bottom: 10px;
width: 16px;
}
......@@ -62,6 +62,29 @@
font-size: 12px;
}
}
.text-file-parallel div {
display: inline-block;
padding-bottom: 16px;
}
.diff-side {
overflow-x: scroll;
width: 508px;
height: 700px;
}
.diff-side.diff-side-left{
overflow-y:hidden;
}
.diff-side table, td.diff-middle table {
height: 700px;
}
.diff-middle {
width: 114px;
vertical-align: top;
height: 700px;
overflow: hidden
}
.old_line, .new_line, .diff_line {
margin: 0px;
padding: 0px;
......@@ -125,8 +148,6 @@
}
&.parallel {
display: table-cell;
overflow: hidden;
width: 50%;
}
}
}
......
......@@ -16,11 +16,7 @@ class Projects::BranchesController < Projects::ApplicationController
end
def create
@repository.add_branch(params[:branch_name], params[:ref])
if new_branch = @repository.find_branch(params[:branch_name])
Event.create_ref_event(@project, current_user, new_branch, 'add')
end
CreateBranchService.new.execute(project, params[:branch_name], params[:ref], current_user)
redirect_to project_branches_path(@project)
end
......
......@@ -14,7 +14,7 @@ class Projects::RepositoriesController < Projects::ApplicationController
render_404 and return
end
storage_path = Rails.root.join("tmp", "repositories")
storage_path = Gitlab.config.gitlab.repository_downloads_path
file_path = @repository.archive_repo(params[:ref], storage_path, params[:format].downcase)
......
......@@ -105,8 +105,80 @@ module CommitsHelper
branches.sort.map { |branch| link_to(branch, project_tree_path(project, branch)) }.join(", ").html_safe
end
def get_old_file(project, commit, diff)
project.repository.blob_at(commit.parent_id, diff.old_path) if commit.parent_id
def parallel_diff_lines(project, commit, diff, file)
old_file = project.repository.blob_at(commit.parent_id, diff.old_path) if commit.parent_id
deleted_lines = {}
added_lines = {}
each_diff_line(diff, 0) do |line, type, line_code, line_new, line_old|
if type == "old"
deleted_lines[line_old] = { line_code: line_code, type: type, line: line }
elsif type == "new"
added_lines[line_new] = { line_code: line_code, type: type, line: line }
end
end
max_length = old_file ? old_file.sloc + added_lines.length : file.sloc
offset1 = 0
offset2 = 0
old_lines = []
new_lines = []
max_length.times do |line_index|
line_index1 = line_index - offset1
line_index2 = line_index - offset2
deleted_line = deleted_lines[line_index1 + 1]
added_line = added_lines[line_index2 + 1]
old_line = old_file.lines[line_index1] if old_file
new_line = file.lines[line_index2]
if deleted_line && added_line
elsif deleted_line
new_line = nil
offset2 += 1
elsif added_line
old_line = nil
offset1 += 1
end
old_lines[line_index] = DiffLine.new
new_lines[line_index] = DiffLine.new
# old
if line_index == 0 && diff.new_file
old_lines[line_index].type = :file_created
old_lines[line_index].content = 'File was created'
elsif deleted_line
old_lines[line_index].type = :deleted
old_lines[line_index].content = old_line
old_lines[line_index].num = line_index1 + 1
old_lines[line_index].code = deleted_line[:line_code]
elsif old_line
old_lines[line_index].type = :no_change
old_lines[line_index].content = old_line
old_lines[line_index].num = line_index1 + 1
else
old_lines[line_index].type = :added
end
# new
if line_index == 0 && diff.deleted_file
new_lines[line_index].type = :file_deleted
new_lines[line_index].content = "File was deleted"
elsif added_line
new_lines[line_index].type = :added
new_lines[line_index].num = line_index2 + 1
new_lines[line_index].content = new_line
new_lines[line_index].code = added_line[:line_code]
elsif new_line
new_lines[line_index].type = :no_change
new_lines[line_index].num = line_index2 + 1
new_lines[line_index].content = new_line
else
new_lines[line_index].type = :deleted
end
end
return old_lines, new_lines
end
protected
......
class DiffLine
attr_accessor :type, :content, :num, :code
end
......@@ -204,7 +204,7 @@ class User < ActiveRecord::Base
end
def search query
where("name LIKE :query OR email LIKE :query OR username LIKE :query", query: "%#{query}%")
where("lower(name) LIKE :query OR lower(email) LIKE :query OR lower(username) LIKE :query", query: "%#{query.downcase}%")
end
def by_username_or_id(name_or_id)
......
class CreateBranchService
def execute(project, branch_name, ref, current_user)
repository = project.repository
repository.add_branch(branch_name, ref)
new_branch = repository.find_branch(branch_name)
if new_branch
Event.create_ref_event(project, current_user, new_branch, 'add')
end
new_branch
end
end
......@@ -178,21 +178,41 @@ class NotificationService
# Get project users with WATCH notification level
def project_watchers(project)
project_watchers = []
member_methods = { project => :users_projects }
member_methods.merge!(project.group => :users_groups) if project.group
# Gather all user ids that have WATCH notification setting for project
project_notification_uids = project_notification_list(project, Notification::N_WATCH)
member_methods.each do |object, member_method|
# Get project notification settings since it has higher priority
user_ids = object.send(member_method).where(notification_level: Notification::N_WATCH).pluck(:user_id)
project_watchers += User.where(id: user_ids)
# Gather all user ids that have WATCH notification setting for group
group_notification_uids = group_notification_list(project, Notification::N_WATCH)
# next collect users who use global settings with watch state
user_ids = object.send(member_method).where(notification_level: Notification::N_GLOBAL).pluck(:user_id)
project_watchers += User.where(id: user_ids, notification_level: Notification::N_WATCH)
# Gather all user ids that have GLOBAL setting
global_notification_uids = global_notification_list(project)
project_and_group_uids = [project_notification_uids, group_notification_uids].flatten.uniq
group_and_project_watchers = User.where(id: project_and_group_uids)
# Find all users that have WATCH as their GLOBAL setting
global_watchers = User.where(id: global_notification_uids, notification_level: Notification::N_WATCH)
[group_and_project_watchers, global_watchers].flatten.uniq
end
def project_notification_list(project, notification_level)
project.users_projects.where(notification_level: notification_level).pluck(:user_id)
end
def group_notification_list(project, notification_level)
if project.group
project.group.users_groups.where(notification_level: notification_level).pluck(:user_id)
else
[]
end
end
project_watchers.uniq
def global_notification_list(project)
[
project_notification_list(project, Notification::N_GLOBAL),
group_notification_list(project, Notification::N_GLOBAL)
].flatten
end
# Remove users with disabled notifications from array
......
......@@ -70,6 +70,7 @@
- @group.users_groups.order('group_access DESC').each do |member|
- user = member.user
%li{class: dom_class(user)}
.list-item-name
%strong
= link_to user.name, admin_user_path(user)
%span.pull-right.light
......
......@@ -28,8 +28,10 @@
%ul.well-list
- @hooks.each do |hook|
%li
.list-item-name
= link_to admin_hook_path(hook) do
%strong= hook.url
.pull-right
= link_to 'Test Hook', admin_hook_test_path(hook), class: "btn btn-small"
= link_to 'Remove', admin_hook_path(hook), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-remove btn-small"
= link_to admin_hook_path(hook) do
%strong= hook.url
......@@ -44,6 +44,7 @@
%ul.well-list
- @projects.each do |project|
%li
.list-item-name
%span{ class: visibility_level_color(project.visibility_level) }
= visibility_level_icon(project.visibility_level)
= link_to project.name_with_namespace, [:admin, project]
......
......@@ -116,6 +116,7 @@
- @project.users_projects.each do |users_project|
- user = users_project.user
%li.users_project
.list-item-name
%strong
= link_to user.name, admin_user_path(user)
.pull-right
......
......@@ -36,6 +36,7 @@
%ul.well-list
- @users.each do |user|
%li
.list-item-name
- if user.blocked?
%i.icon-lock.cred
- else
......
......@@ -124,6 +124,7 @@
- @user.users_groups.each do |user_group|
- group = user_group.group
%li.users_group
%span{class: ("list-item-name" unless user_group.owner?)}
%strong= link_to group.name, admin_group_path(group)
.pull-right
%span.light= user_group.human_access
......
......@@ -73,6 +73,7 @@
%ul.well-list
- @group.projects.each do |project|
%li
.list-item-name
= visibility_level_icon(project.visibility_level)
= link_to project.name_with_namespace, project
.pull-right
......
......@@ -23,4 +23,4 @@
- if @project
You're receiving this notification because you are a member of the #{link_to @project.name_with_namespace, project_url(@project)} project team.
- if @target_url
#{link_to "View in GitLab", @target_url}
#{link_to "View it on GitLab", @target_url}
......@@ -7,7 +7,7 @@
%li
#{commit.short_id} - #{commit.title}
%h4 Diff:
%h4 Changes:
- @diffs.each do |diff|
%li
%strong
......@@ -23,6 +23,6 @@
%br
- if @compare.timeout
%h5 Huge diff. To prevent performance issues it was hidden
%h5 To prevent performance issues changes are hidden
- elsif @compare.commits_over_limit?
%h5 Diff for big amount of commits is disabled
%h5 Changes are not shown due to large amount of commits
......@@ -6,7 +6,7 @@ Commits:
#{commit.short_id} - #{truncate(commit.title, length: 40)}
\
\
Diff:
Changes:
- @diffs.each do |diff|
\
\=====================================
......@@ -22,4 +22,4 @@ Diff:
- if @compare.timeout
Huge diff. To prevent performance issues it was hidden
- elsif @compare.commits_over_limit?
Diff for big amount of commits is disabled
Changes are not shown due to large amount of commits
/ Side-by-side diff view
- old_file = get_old_file(project, @commit, diff)
- deleted_lines = {}
- added_lines = {}
- each_diff_line(diff, index) do |line, type, line_code, line_new, line_old, raw_line|
- if type == "old"
- deleted_lines[line_old] = { line_code: line_code, type: type, line: line }
- elsif type == "new"
- added_lines[line_new] = { line_code: line_code, type: type, line: line }
- max_length = old_file.sloc + added_lines.length if old_file
- max_length ||= file.sloc
- offset1 = 0
- offset2 = 0
- old_lines, new_lines = parallel_diff_lines(project, @commit, diff, file)
- num_lines = old_lines.length
%div.text-file-parallel
%table{ style: "table-layout: fixed;" }
- max_length.times do |line_index|
- line_index1 = line_index - offset1
- line_index2 = line_index - offset2
- deleted_line = deleted_lines[line_index1 + 1]
- added_line = added_lines[line_index2 + 1]
- old_line = old_file.lines[line_index1] if old_file
- new_line = file.lines[line_index2]
- if deleted_line && added_line
- elsif deleted_line
- new_line = nil
- offset2 += 1
- elsif added_line
- old_line = nil
- offset1 += 1
%div.diff-side.diff-side-left
%table
- old_lines.each do |line|
%tr.line_holder.parallel
- if line_index == 0 && diff.new_file
- if line.type == :file_created
%td.line_content.parallel= "File was created"
%td.old_line= ""
- elsif deleted_line
%td.line_content{class: "parallel noteable_line old #{deleted_line[:line_code]}", "line_code" => deleted_line[:line_code] }= old_line
%td.old_line.old
= line_index1 + 1
- if @comments_allowed
=# render "projects/notes/diff_note_link", line_code: deleted_line[:line_code]
- elsif old_line
%td.line_content.parallel= old_line
%td.old_line= line_index1 + 1
- elsif line.type == :deleted
%td.line_content{class: "parallel noteable_line old #{line.code}", "line_code" => line.code }= line.content
- else line.type == :no_change
%td.line_content.parallel= line.content
%div.diff-middle
%table
- num_lines.times do |index|
%tr
- if old_lines[index].type == :deleted
%td.old_line.old= old_lines[index].num
- else
%td.line_content.parallel= ""
%td.old_line= ""
%td.old_line= old_lines[index].num
%td.diff_line= ""
%td.diff_line=""
- if diff.deleted_file && line_index == 0
%td.new_line= ""
%td.line_content.parallel= "File was deleted"
- elsif added_line
%td.new_line.new
= line_index2 + 1
- if @comments_allowed
=# render "projects/notes/diff_note_link", line_code: added_line[:line_code]
%td.line_content{class: "parallel noteable_line new #{added_line[:line_code]}", "line_code" => added_line[:line_code] }= new_line
- elsif new_line
%td.new_line= line_index2 + 1
%td.line_content.parallel= new_line
- if new_lines[index].type == :added
%td.new_line.new= new_lines[index].num
- else
%td.new_line= ""
%td.line_content.parallel= ""
%td.new_line= new_lines[index].num
%div.diff-side.diff-side-right
%table
- new_lines.each do |line|
%tr.line_holder.parallel
- if line.type == :file_deleted
%td.line_content.parallel= "File was deleted"
- elsif line.type == :added
%td.line_content{class: "parallel noteable_line new #{line.code}", "line_code" => line.code }= line.content
- else line.type == :no_change
%td.line_content.parallel= line.content
:javascript
$('.diff-side-right').on('scroll', function(){
$('.diff-side-left, .diff-middle').scrollTop($(this).scrollTop());
$('.diff-side-left').scrollLeft($(this).scrollLeft());
});
- if @reply_allowed
- comments1 = []
- comments2 = []
- comments1 = @line_notes.select { |n| n.line_code == deleted_line[:line_code] }.sort_by(&:created_at) if deleted_line
- comments2 = @line_notes.select { |n| n.line_code == added_line[:line_code] }.sort_by(&:created_at) if added_line
- unless comments1.empty? && comments2.empty?
= render "projects/notes/diff_notes_with_reply_parallel", notes1: comments1, notes2: comments2, line1: deleted_line, line2: added_line
\ No newline at end of file
$('.diff-side-left').on('scroll', function(){
$('.diff-side-right, .diff-middle').scrollTop($(this).scrollTop()); // might never be relevant
$('.diff-side-right').scrollLeft($(this).scrollLeft());
});
- too_big = diff.diff.lines.count > 1000
- if too_big
%a.supp_diff_link Diff suppressed. Click to show
%a.supp_diff_link Changes suppressed. Click to show
%table.text-file{class: "#{'hide' if too_big}"}
- each_diff_line(diff, index) do |line, type, line_code, line_new, line_old, raw_line|
......
......@@ -18,17 +18,17 @@
- else
%ul.well-list= render Commit.decorate(@commits), project: @project
%h4 Diff
%h4 Changes
- if @diffs.present?
= render "projects/commits/diffs", diffs: @diffs, project: @project
- elsif @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
.bs-callout.bs-callout-danger
%h4 This comparison includes more than #{MergeRequestDiff::COMMITS_SAFE_SIZE} commits.
%p To preserve performance the line diff is not shown.
%p To preserve performance the line changes are not shown.
- elsif @timeout
.bs-callout.bs-callout-danger
%h4 Diff for this comparison is extremely large.
%p Use command line to browse diff for this comparison.
%h4 Number of changed files for this comparison is extremely large.
%p Use command line to browse through changes for this comparison.
- else
......
......@@ -2,7 +2,7 @@
Deploy key:
= @key.title
%small
created at
created on
= @key.created_at.stamp("Aug 21, 2011")
.back-link
= link_to project_deploy_keys_path(@project) do
......
%div.issue-form-holder
%h3.page-title= @issue.new_record? ? "New Issue" : "Edit Issue ##{@issue.iid}"
%hr
- if @repository.contribution_guide && !@issue.persisted?
- if !@repository.empty? && @repository.contribution_guide && !@issue.persisted?
- contribution_guide_url = project_blob_path(@project, tree_join(@repository.root_ref, @repository.contribution_guide.name))
.alert.alert-info.col-sm-10.col-sm-offset-2
="Please review the <strong>#{link_to "guidelines for contribution", contribution_guide_url}</strong> to this repository.".html_safe
......
......@@ -20,7 +20,7 @@
%li.diffs-tab{data: {action: 'diffs'}}
= link_to diffs_project_merge_request_path(@project, @merge_request) do
%i.icon-list-alt
Diff
Changes
- content_for :note_actions do
- if can?(current_user, :modify_merge_request, @merge_request)
......
......@@ -5,7 +5,7 @@
- else
.bs-callout.bs-callout-warning
%h4
Diff for this comparison is extremely large.
Changes view for this comparison is extremely large.
%p
You can
= link_to "download it", project_merge_request_path(@merge_request.source_project, @merge_request, format: :diff), class: "vlink"
......
......@@ -4,7 +4,10 @@
%strong Archived projects cannot be committed to!
- else
.bs-callout
%strong You don't have permission to merge this MR
.automerge_widget.cannot_be_merged.hide
%strong This can't be merged automatically, even if it could be merged you don't have the permission to do so.
.automerge_widget.can_be_merged.hide
%strong This can be merged automatically but you don't have the permission to do so.
- if @show_merge_controls
......
......@@ -2,6 +2,7 @@
- return unless user
- show_roles = true if show_roles.nil?
%li{class: "#{dom_class(member)} js-toggle-container", id: dom_id(member)}
%span{class: ("list-item-name" if show_controls)}
= image_tag avatar_icon(user.email, 16), class: "avatar s16"
%strong= user.name
%span.cgray= user.username
......
......@@ -76,6 +76,11 @@ production: &base
snippets: false
visibility_level: "private" # can be "private" | "internal" | "public"
## Repository downloads directory
# When a user clicks e.g. 'Download zip' on a project, a temporary zip file is created in the following directory.
# The default is 'tmp/repositories' relative to the root of the Rails app.
# repository_downloads_path: tmp/repositories
## External issues trackers
issues_tracker:
# redmine:
......
......@@ -97,6 +97,7 @@ Settings.gitlab.default_projects_features['wiki'] = true if Settings.g
Settings.gitlab.default_projects_features['wall'] = false if Settings.gitlab.default_projects_features['wall'].nil?
Settings.gitlab.default_projects_features['snippets'] = false if Settings.gitlab.default_projects_features['snippets'].nil?
Settings.gitlab.default_projects_features['visibility_level'] = Settings.send(:verify_constant, Gitlab::VisibilityLevel, Settings.gitlab.default_projects_features['visibility_level'], Gitlab::VisibilityLevel::PRIVATE)
Settings.gitlab['repository_downloads_path'] = File.absolute_path(Settings.gitlab['repository_downloads_path'] || 'tmp/repositories', Rails.root)
#
# Gravatar
......
## The GitLab Documentation covers the following subjects
+ [API](api/README.md)
+ [Development](development/README.md)
+ [Install](install/README.md)
+ [Integration](integration/external-issue-tracker.md)
+ [Legal](legal/README.md)
+ [Markdown](markdown/markdown.md)
+ [Permissions](permissions/permissions.md)
+ [Public access](public_access/public_access.md)
+ [Raketasks](raketasks/README.md)
+ [Release](release/README.md)
+ [Security](security/README.md)
+ [SSH](ssh/README.md)
+ [System hooks](system_hooks/system_hooks.md)
+ [Update](update/README.md)
+ [Web hooks](web_hooks/web_hooks.md)
+ [Workflow](workflow/workflow.md)
# GitLab API
## End-points
+ [Users](users.md)
+ [Session](session.md)
+ [Projects](projects.md)
+ [Project Snippets](project_snippets.md)
+ [Repositories](repositories.md)
+ [Repository Files](repository_files.md)
+ [Commits](commits.md)
+ [Branches](branches.md)
+ [Merge Requests](merge_requests.md)
+ [Issues](issues.md)
+ [Milestones](milestones.md)
+ [Notes](notes.md)
+ [Deploy Keys](deploy_keys.md)
+ [System Hooks](system_hooks.md)
+ [Groups](groups.md)
## Clients
+ [php-gitlab-api](https://github.com/m4tthumphrey/php-gitlab-api) - PHP
+ [Ruby Wrapper](https://github.com/NARKOZ/gitlab) - Ruby
+ [python-gitlab](https://github.com/Itxaka/python-gitlab) - Python
+ [java-gitlab-api](https://github.com/timols/java-gitlab-api) - Java
## Introduction
All API requests require authentication. You need to pass a `private_token` parameter by url or header. If passed as header, the header name must be "PRIVATE-TOKEN" (capital and with dash instead of underscore). You can find or reset your private token in your profile.
If no, or an invalid, `private_token` is provided then an error message will be returned with status code 401:
......@@ -103,6 +130,10 @@ When listing resources you can pass the following parameters:
+ `page` (default: `1`) - page number
+ `per_page` (default: `20`, max: `100`) - number of items to list per page
[Link headers](http://www.w3.org/wiki/LinkHeader) are send back with each response.
These have `rel` prev/next/first/last and contain the relevant url.
Please use these instead of generating your own urls.
## id vs iid
When you work with API you may notice two similar fields in api entites: id and iid.
......@@ -117,30 +148,3 @@ Issue
So if you want to get issue with api you use `http://host/api/v3/.../issues/:id.json`
But when you want to create a link to web page - use `http:://host/project/issues/:iid.json`
## Contents
+ [Users](users.md)
+ [Session](session.md)
+ [Projects](projects.md)
+ [Project Snippets](project_snippets.md)
+ [Repositories](repositories.md)
+ [Repository Files](repository_files.md)
+ [Commits](commits.md)
+ [Merge Requests](merge_requests.md)
+ [Issues](issues.md)
+ [Milestones](milestones.md)
+ [Notes](notes.md)
+ [Deploy Keys](deploy_keys.md)
+ [System Hooks](system_hooks.md)
+ [Groups](groups.md)
## Clients
+ [php-gitlab-api](https://github.com/m4tthumphrey/php-gitlab-api) - PHP
+ [Ruby Wrapper](https://github.com/NARKOZ/gitlab) - Ruby
+ [python-gitlab](https://github.com/Itxaka/python-gitlab) - Python
+ [java-gitlab-api](https://github.com/timols/java-gitlab-api) - Java
# Branches
## List repository branches
Get a list of repository branches from a project, sorted by name alphabetically.
```
GET /projects/:id/repository/branches
```
Parameters:
+ `id` (required) - The ID of a project
```json
[
{
"name": "master",
"commit": {
"id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
"parents": [
{
"id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
}
],
"tree": "46e82de44b1061621357f24c05515327f2795a95",
"message": "add projects API",
"author": {
"name": "John Smith",
"email": "john@example.com"
},
"committer": {
"name": "John Smith",
"email": "john@example.com"
},
"authored_date": "2012-06-27T05:51:39-07:00",
"committed_date": "2012-06-28T03:44:20-07:00"
},
"protected": true
}
]
```
## Get single repository branch
Get a single project repository branch.
```
GET /projects/:id/repository/branches/:branch
```
Parameters:
+ `id` (required) - The ID of a project
+ `branch` (required) - The name of the branch
```json
{
"name": "master",
"commit": {
"id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
"parents": [
{
"id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
}
],
"tree": "46e82de44b1061621357f24c05515327f2795a95",
"message": "add projects API",
"author": {
"name": "John Smith",
"email": "john@example.com"
},
"committer": {
"name": "John Smith",
"email": "john@example.com"
},
"authored_date": "2012-06-27T05:51:39-07:00",
"committed_date": "2012-06-28T03:44:20-07:00"
},
"protected": true
}
```
## Protect repository branch
Protects a single project repository branch. This is an idempotent function, protecting an already
protected repository branch still returns a `200 Ok` status code.
```
PUT /projects/:id/repository/branches/:branch/protect
```
Parameters:
+ `id` (required) - The ID of a project
+ `branch` (required) - The name of the branch
```json
{
"name": "master",
"commit": {
"id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
"parents": [
{
"id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
}
],
"tree": "46e82de44b1061621357f24c05515327f2795a95",
"message": "add projects API",
"author": {
"name": "John Smith",
"email": "john@example.com"
},
"committer": {
"name": "John Smith",
"email": "john@example.com"
},
"authored_date": "2012-06-27T05:51:39-07:00",
"committed_date": "2012-06-28T03:44:20-07:00"
},
"protected": true
}
```
## Unprotect repository branch
Unprotects a single project repository branch. This is an idempotent function, unprotecting an already
unprotected repository branch still returns a `200 Ok` status code.
```
PUT /projects/:id/repository/branches/:branch/unprotect
```
Parameters:
+ `id` (required) - The ID of a project
+ `branch` (required) - The name of the branch
```json
{
"name": "master",
"commit": {
"id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
"parents": [
{
"id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
}
],
"tree": "46e82de44b1061621357f24c05515327f2795a95",
"message": "add projects API",
"author": {
"name": "John Smith",
"email": "john@example.com"
},
"committer": {
"name": "John Smith",
"email": "john@example.com"
},
"authored_date": "2012-06-27T05:51:39-07:00",
"committed_date": "2012-06-28T03:44:20-07:00"
},
"protected": false
}
```
## Create repository branch
```
POST /projects/:id/repository/branches
```
Parameters:
+ `id` (required) - The ID of a project
+ `branch_name` (required) - The name of the branch
+ `ref` (required) - Create branch from commit sha or existing branch
```json
{
"name": "my-new-branch",
"commit": {
"id": "8848c0e90327a0b70f1865b843fb2fbfb9345e57",
"message": "Merge pull request #54 from brightbox/use_fog_brightbox_module\n\nUpdate to use fog-brightbox module",
"parent_ids": ["fff449e0bf453576f16c91d6544f00a2664009d8", "f93a93626fec20fd659f4ed3ab2e64019b6169ae"],
"authored_date": "2014-02-20T19:54:55+02:00",
"author_name": "john smith",
"author_email": "john@example.com",
"committed_date": "2014-02-20T19:54:55+02:00",
"committer_name": "john smith",
"committer_email": "john@example.com"
},
"protected": false
}
```
## List repository branches
Get a list of repository branches from a project, sorted by name alphabetically.
```
GET /projects/:id/repository/branches
```
Parameters:
+ `id` (required) - The ID of a project
```json
[
{
"name": "master",
"commit": {
"id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
"parents": [
{
"id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
}
],
"tree": "46e82de44b1061621357f24c05515327f2795a95",
"message": "add projects API",
"author": {
"name": "John Smith",
"email": "john@example.com"
},
"committer": {
"name": "John Smith",
"email": "john@example.com"
},
"authored_date": "2012-06-27T05:51:39-07:00",
"committed_date": "2012-06-28T03:44:20-07:00"
},
"protected": true
}
]
```
## Get single repository branch
Get a single project repository branch.
```
GET /projects/:id/repository/branches/:branch
```
Parameters:
+ `id` (required) - The ID of a project
+ `branch` (required) - The name of the branch
```json
{
"name": "master",
"commit": {
"id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
"parents": [
{
"id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
}
],
"tree": "46e82de44b1061621357f24c05515327f2795a95",
"message": "add projects API",
"author": {
"name": "John Smith",
"email": "john@example.com"
},
"committer": {
"name": "John Smith",
"email": "john@example.com"
},
"authored_date": "2012-06-27T05:51:39-07:00",
"committed_date": "2012-06-28T03:44:20-07:00"
},
"protected": true
}
```
## Protect repository branch
Protects a single project repository branch. This is an idempotent function, protecting an already
protected repository branch still returns a `200 Ok` status code.
```
PUT /projects/:id/repository/branches/:branch/protect
```
Parameters:
+ `id` (required) - The ID of a project
+ `branch` (required) - The name of the branch
```json
{
"name": "master",
"commit": {
"id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
"parents": [
{
"id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
}
],
"tree": "46e82de44b1061621357f24c05515327f2795a95",
"message": "add projects API",
"author": {
"name": "John Smith",
"email": "john@example.com"
},
"committer": {
"name": "John Smith",
"email": "john@example.com"
},
"authored_date": "2012-06-27T05:51:39-07:00",
"committed_date": "2012-06-28T03:44:20-07:00"
},
"protected": true
}
```
## Unprotect repository branch
Unprotects a single project repository branch. This is an idempotent function, unprotecting an already
unprotected repository branch still returns a `200 Ok` status code.
```
PUT /projects/:id/repository/branches/:branch/unprotect
```
Parameters:
+ `id` (required) - The ID of a project
+ `branch` (required) - The name of the branch
```json
{
"name": "master",
"commit": {
"id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
"parents": [
{
"id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
}
],
"tree": "46e82de44b1061621357f24c05515327f2795a95",
"message": "add projects API",
"author": {
"name": "John Smith",
"email": "john@example.com"
},
"committer": {
"name": "John Smith",
"email": "john@example.com"
},
"authored_date": "2012-06-27T05:51:39-07:00",
"committed_date": "2012-06-28T03:44:20-07:00"
},
"protected": false
}
```
## List project repository tags
Get a list of repository tags from a project, sorted by name in reverse alphabetical order.
......
......@@ -51,6 +51,10 @@ GET /users
]
```
You can search for a users by email or username with:
`/users?search=John`
Also see `def search query` in `app/models/user.rb`.
## Single user
......
+ [Architecture](architecture.md)
+ [Shell commands](shell_commands.md)
......@@ -28,7 +28,7 @@ To serve repositories over SSH there's an add-on application called gitlab-shell
## Components
![GitLab Diagram Overview](resources/gitlab_diagram_overview.png "GitLab Diagram Overview")
![GitLab Diagram Overview](resources/gitlab_diagram_overview.png)
A typical install of GitLab will be on Ubuntu Linux or RHEL/CentOS.
It uses Nginx or Apache as a web front end to proxypass the Unicorn web server.
......
+ [Installation](installation.md)
+ [Requirements](requirements.md)
+ [Structure](structure.md)
+ [Database MySQL](database_mysql.md)
......@@ -7,6 +7,9 @@ We do not recommend using MySQL due to various issues. For example, case [(in)se
# Install the database packages
sudo apt-get install -y mysql-server mysql-client libmysqlclient-dev
# Ensure you have MySQL version 5.5.14 or later
mysql --version
# Pick a database root password (can be anything), type it and press enter
# Retype the database root password and press enter
......@@ -23,6 +26,10 @@ We do not recommend using MySQL due to various issues. For example, case [(in)se
# change $password in the command below to a real password you pick
mysql> CREATE USER 'git'@'localhost' IDENTIFIED BY '$password';
# Ensure you can use the InnoDB engine which is necessary to support long indexes.
# If this fails, check your MySQL config files (e.g. `/etc/mysql/*.cnf`, `/etc/mysql/conf.d/*`) for the setting "innodb = off"
mysql> SET storage_engine=INNODB;
# Create the GitLab production database
mysql> CREATE DATABASE IF NOT EXISTS `gitlabhq_production` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`;
......
+ [Corporate contributor license agreement](corporate_contributor_license_agreement.md)
+ [Individual contributor license agreement](individual_contributor_license_agreement.md)
......@@ -38,7 +38,7 @@ If a user is a GitLab administrator they receive all permissions.
|------|-----|--------|---------|------|-----|
|Browse group|✓|✓|✓|✓|✓|
|Edit group|||||✓|
|create project in group|||||✓|
|Create project in group|||||✓|
|Manage group members|||||✓|
|Remove group|||||✓|
......
+ [Backup restore](backup_restore.md)
+ [Cleanup](cleanup.md)
+ [Features](features.md)
+ [Maintenance](maintenance.md)
+ [User management](user_management.md)
+ [Web hooks](web_hooks.md)
+ [Monthly](monthly.md)
+ [Security](security.md)
+ [Password length limits](password_length_limits.md)
+ [Rack attack](rack_attack.md)
+ [Deploy keys](deploy_keys.md)
+ [SSH](ssh.md)
......@@ -9,4 +9,4 @@ After this the machine that uses the corresponding private key has read-only acc
You can't add the same deploy key twice with the 'New Deploy Key' option.
If you want to add the same key to another project please enable it in the list that says 'Deploy keys from projects available to you'.
You need to be the owner of the deploy key to see it in this list.
All the deploy keys of all the projects you have access to are available. This project access can happen through being a direct member of the project or through a group. See `def accessible_deploy_keys` in `app/models/user.rb` for more information.
......@@ -140,3 +140,6 @@ Follow the [`upgrade guide from 5.4 to 6.0`](5.4-to-6.0.md), except for the data
cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
```
## Login issues after upgrade?
If running in https mode, be sure to read [Can't Verify csrf token authenticity](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide#cant-verify-csrf-token-authenticitycant-get-past-login-pageredirected-to-login-page)
+ [The indivual upgrade guides](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/update)
+ [Uprader](upgrader.md)
+ [Ruby](ruby.md)
+ [Patch versions](patch_versions.md)
+ [MySQL to PostgreSQL](mysql_to_postgresql.md)
......@@ -3,13 +3,14 @@
```bash
git clone git@example.com:project-name.git
```
2. Create branch with your feature
```bash
git checkout -b $feature_name
```
3. Write code. Comit changes
3. Write code. Commit changes
```bash
git commit -am "My feature is ready"
......@@ -21,6 +22,6 @@
git push origin $feature_name
```
5. Review your code on Commits page
5. Review your code on commits page
6. Create a merge request
7. Your team lead will review the code &amp; merge it to the main branch
......@@ -45,5 +45,6 @@ module API
mount Files
mount Commits
mount Namespaces
mount Branches
end
end
require 'mime/types'
module API
# Projects API
class Branches < Grape::API
before { authenticate! }
before { authorize! :download_code, user_project }
resource :projects do
# Get a project repository branches
#
# Parameters:
# id (required) - The ID of a project
# Example Request:
# GET /projects/:id/repository/branches
get ":id/repository/branches" do
present user_project.repo.heads.sort_by(&:name), with: Entities::RepoObject, project: user_project
end
# Get a single branch
#
# Parameters:
# id (required) - The ID of a project
# branch (required) - The name of the branch
# Example Request:
# GET /projects/:id/repository/branches/:branch
get ":id/repository/branches/:branch" do
@branch = user_project.repo.heads.find { |item| item.name == params[:branch] }
not_found!("Branch does not exist") if @branch.nil?
present @branch, with: Entities::RepoObject, project: user_project
end
# Protect a single branch
#
# Parameters:
# id (required) - The ID of a project
# branch (required) - The name of the branch
# Example Request:
# PUT /projects/:id/repository/branches/:branch/protect
put ":id/repository/branches/:branch/protect" do
authorize_admin_project
@branch = user_project.repository.find_branch(params[:branch])
not_found! unless @branch
protected_branch = user_project.protected_branches.find_by(name: @branch.name)
user_project.protected_branches.create(name: @branch.name) unless protected_branch
present @branch, with: Entities::RepoObject, project: user_project
end
# Unprotect a single branch
#
# Parameters:
# id (required) - The ID of a project
# branch (required) - The name of the branch
# Example Request:
# PUT /projects/:id/repository/branches/:branch/unprotect
put ":id/repository/branches/:branch/unprotect" do
authorize_admin_project
@branch = user_project.repository.find_branch(params[:branch])
not_found! unless @branch
protected_branch = user_project.protected_branches.find_by(name: @branch.name)
protected_branch.destroy if protected_branch
present @branch, with: Entities::RepoObject, project: user_project
end
# Create branch
#
# Parameters:
# id (required) - The ID of a project
# branch_name (required) - The name of the branch
# ref (required) - Create branch from commit sha or existing branch
# Example Request:
# POST /projects/:id/repository/branches
post ":id/repository/branches" do
authorize_push_project
@branch = CreateBranchService.new.execute(user_project, params[:branch_name], params[:ref], current_user)
present @branch, with: Entities::RepoObject, project: user_project
end
end
end
end
require 'mime/types'
module API
# Projects API
# Projects commits API
class Commits < Grape::API
before { authenticate! }
before { authorize! :download_code, user_project }
resource :projects do
helpers do
def handle_project_member_errors(errors)
if errors[:project_access].any?
error!(errors[:project_access], 422)
end
not_found!
end
end
# Get a project repository commits
#
# Parameters:
......
......@@ -56,8 +56,12 @@ module API
end
end
def paginate(object)
object.page(params[:page]).per(params[:per_page].to_i)
def paginate(relation)
per_page = params[:per_page].to_i
paginated = relation.page(params[:page]).per(per_page)
add_pagination_headers(paginated, per_page)
paginated
end
def authenticate!
......@@ -74,6 +78,10 @@ module API
end
end
def authorize_push_project
authorize! :push_code, user_project
end
def authorize_admin_project
authorize! :admin_project, user_project
end
......@@ -134,6 +142,18 @@ module API
private
def add_pagination_headers(paginated, per_page)
request_url = request.url.split('?').first
links = []
links << %(<#{request_url}?page=#{paginated.current_page - 1}&per_page=#{per_page}>; rel="prev") unless paginated.first_page?
links << %(<#{request_url}?page=#{paginated.current_page + 1}&per_page=#{per_page}>; rel="next") unless paginated.last_page?
links << %(<#{request_url}?page=1&per_page=#{per_page}>; rel="first")
links << %(<#{request_url}?page=#{paginated.total_pages}&per_page=#{per_page}>; rel="last")
header 'Link', links.join(', ')
end
def abilities
@abilities ||= begin
abilities = Six.new
......
......@@ -15,66 +15,6 @@ module API
not_found!
end
end
# Get a project repository branches
#
# Parameters:
# id (required) - The ID of a project
# Example Request:
# GET /projects/:id/repository/branches
get ":id/repository/branches" do
present user_project.repo.heads.sort_by(&:name), with: Entities::RepoObject, project: user_project
end
# Get a single branch
#
# Parameters:
# id (required) - The ID of a project
# branch (required) - The name of the branch
# Example Request:
# GET /projects/:id/repository/branches/:branch
get ":id/repository/branches/:branch" do
@branch = user_project.repo.heads.find { |item| item.name == params[:branch] }
not_found!("Branch does not exist") if @branch.nil?
present @branch, with: Entities::RepoObject, project: user_project
end
# Protect a single branch
#
# Parameters:
# id (required) - The ID of a project
# branch (required) - The name of the branch
# Example Request:
# PUT /projects/:id/repository/branches/:branch/protect
put ":id/repository/branches/:branch/protect" do
authorize_admin_project
@branch = user_project.repository.find_branch(params[:branch])
not_found! unless @branch
protected_branch = user_project.protected_branches.find_by(name: @branch.name)
user_project.protected_branches.create(name: @branch.name) unless protected_branch
present @branch, with: Entities::RepoObject, project: user_project
end
# Unprotect a single branch
#
# Parameters:
# id (required) - The ID of a project
# branch (required) - The name of the branch
# Example Request:
# PUT /projects/:id/repository/branches/:branch/unprotect
put ":id/repository/branches/:branch/unprotect" do
authorize_admin_project
@branch = user_project.repository.find_branch(params[:branch])
not_found! unless @branch
protected_branch = user_project.protected_branches.find_by(name: @branch.name)
protected_branch.destroy if protected_branch
present @branch, with: Entities::RepoObject, project: user_project
end
# Get a project repository tags
#
# Parameters:
......@@ -161,7 +101,7 @@ module API
repo = user_project.repository
ref = params[:sha]
format = params[:format]
storage_path = Rails.root.join("tmp", "repositories")
storage_path = Gitlab.config.gitlab.repository_downloads_path
file_path = repo.archive_repo(ref, storage_path, format)
if file_path && File.exists?(file_path)
......
......@@ -29,9 +29,10 @@ module Backup
print "Restoring MySQL database #{config['database']} ... "
system('mysql', *mysql_args, config['database'], in: db_file_name)
when "postgresql" then
puts "Destructively rebuilding database schema for RAILS_ENV #{Rails.env}"
Rake::Task["db:schema:load"].invoke
print "Restoring PostgreSQL database #{config['database']} ... "
# Drop all tables because PostgreSQL DB dumps do not contain DROP TABLE
# statements like MySQL.
Rake::Task["gitlab:db:drop_all_tables"].invoke
pg_env
system('psql', config['database'], '-f', db_file_name)
end
......
......@@ -81,16 +81,17 @@ module Gitlab
private
def find_by_uid(uid)
model.where(provider: provider, extern_uid: uid).last
def find_by_uid_and_provider
find_by_uid(uid)
end
def username
(auth.info.nickname || samaccountname).to_s.force_encoding("utf-8")
def find_by_uid(uid)
# LDAP distinguished name is case-insensitive
model.where("provider = ? and lower(extern_uid) = ?", provider, uid.downcase).last
end
def samaccountname
(auth.extra[:raw_info][:samaccountname] || []).first
def username
auth.info.nickname.to_s.force_encoding("utf-8")
end
def provider
......
......@@ -149,7 +149,7 @@ exit_if_not_running(){
}
## Starts Unicorn and Sidekiq if they're not running.
start() {
start_gitlab() {
check_stale_pids
if [ "$web_status" != "0" -a "$sidekiq_status" != "0" ]; then
......@@ -167,7 +167,7 @@ start() {
# Remove old socket if it exists
rm -f "$socket_path"/gitlab.socket 2>/dev/null
# Start the web server
RAILS_ENV=$RAILS_ENV script/web start &
RAILS_ENV=$RAILS_ENV script/web start
fi
# If sidekiq is already running, don't start it again.
......@@ -184,7 +184,7 @@ start() {
}
## Asks the Unicorn and the Sidekiq if they would be so kind as to stop, if not kills them.
stop() {
stop_gitlab() {
exit_if_not_running
if [ "$web_status" = "0" -a "$sidekiq_status" = "0" ]; then
......@@ -246,7 +246,7 @@ print_status() {
}
## Tells unicorn to reload it's config and Sidekiq to restart
reload(){
reload_gitlab(){
exit_if_not_running
if [ "$wpid" = "0" ];then
echo "The GitLab Unicorn Web server is not running thus its configuration can't be reloaded."
......@@ -263,12 +263,12 @@ reload(){
}
## Restarts Sidekiq and Unicorn.
restart(){
restart_gitlab(){
check_status
if [ "$web_status" = "0" -o "$sidekiq_status" = "0" ]; then
stop
stop_gitlab
fi
start
start_gitlab
}
......@@ -276,16 +276,16 @@ restart(){
case "$1" in
start)
start
start_gitlab
;;
stop)
stop
stop_gitlab
;;
restart)
restart
restart_gitlab
;;
reload|force-reload)
reload
reload_gitlab
;;
status)
print_status
......
......@@ -677,7 +677,20 @@ namespace :gitlab do
end
def filter
Net::LDAP::Filter.present?(ldap_config.uid)
uid_filter = Net::LDAP::Filter.present?(ldap_config.uid)
if user_filter
Net::LDAP::Filter.join(uid_filter, user_filter)
else
uid_filter
end
end
def user_filter
if ldap_config['user_filter'] && ldap_config.user_filter.present?
Net::LDAP::Filter.construct(ldap_config.user_filter)
else
nil
end
end
def ldap
......
namespace :gitlab do
namespace :db do
task drop_all_tables: :environment do
connection = ActiveRecord::Base.connection
connection.tables.each do |table|
connection.drop_table(table)
end
end
end
end
......@@ -292,6 +292,20 @@ describe User do
end
end
describe 'search' do
let(:user1) { create(:user, username: 'James', email: 'james@testing.com') }
let(:user2) { create(:user, username: 'jameson', email: 'jameson@example.com') }
it "should be case insensitive" do
User.search(user1.username.upcase).to_a.should == [user1]
User.search(user1.username.downcase).to_a.should == [user1]
User.search(user2.username.upcase).to_a.should == [user2]
User.search(user2.username.downcase).to_a.should == [user2]
User.search(user1.username.downcase).to_a.count.should == 2
User.search(user2.username.downcase).to_a.count.should == 1
end
end
describe 'by_username_or_id' do
let(:user1) { create(:user, username: 'foo') }
......
require 'spec_helper'
require 'mime/types'
describe API::API do
include ApiHelpers
before(:each) { enable_observers }
after(:each) {disable_observers}
let(:user) { create(:user) }
let(:user2) { create(:user) }
let!(:project) { create(:project, creator_id: user.id) }
let!(:master) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) }
let!(:guest) { create(:users_project, user: user2, project: project, project_access: UsersProject::GUEST) }
describe "GET /projects/:id/repository/branches" do
it "should return an array of project branches" do
get api("/projects/#{project.id}/repository/branches", user)
response.status.should == 200
json_response.should be_an Array
json_response.first['name'].should == project.repo.heads.sort_by(&:name).first.name
end
end
describe "GET /projects/:id/repository/branches/:branch" do
it "should return the branch information for a single branch" do
get api("/projects/#{project.id}/repository/branches/new_design", user)
response.status.should == 200
json_response['name'].should == 'new_design'
json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1'
json_response['protected'].should == false
end
it "should return a 403 error if guest" do
get api("/projects/#{project.id}/repository/branches", user2)
response.status.should == 403
end
it "should return a 404 error if branch is not available" do
get api("/projects/#{project.id}/repository/branches/unknown", user)
response.status.should == 404
end
end
describe "PUT /projects/:id/repository/branches/:branch/protect" do
it "should protect a single branch" do
put api("/projects/#{project.id}/repository/branches/new_design/protect", user)
response.status.should == 200
json_response['name'].should == 'new_design'
json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1'
json_response['protected'].should == true
end
it "should return a 404 error if branch not found" do
put api("/projects/#{project.id}/repository/branches/unknown/protect", user)
response.status.should == 404
end
it "should return a 403 error if guest" do
put api("/projects/#{project.id}/repository/branches/new_design/protect", user2)
response.status.should == 403
end
it "should return success when protect branch again" do
put api("/projects/#{project.id}/repository/branches/new_design/protect", user)
put api("/projects/#{project.id}/repository/branches/new_design/protect", user)
response.status.should == 200
end
end
describe "PUT /projects/:id/repository/branches/:branch/unprotect" do
it "should unprotect a single branch" do
put api("/projects/#{project.id}/repository/branches/new_design/unprotect", user)
response.status.should == 200
json_response['name'].should == 'new_design'
json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1'
json_response['protected'].should == false
end
it "should return success when unprotect branch" do
put api("/projects/#{project.id}/repository/branches/unknown/unprotect", user)
response.status.should == 404
end
it "should return success when unprotect branch again" do
put api("/projects/#{project.id}/repository/branches/new_design/unprotect", user)
put api("/projects/#{project.id}/repository/branches/new_design/unprotect", user)
response.status.should == 200
end
end
describe "POST /projects/:id/repository/branches" do
it "should create a new branch" do
post api("/projects/#{project.id}/repository/branches", user),
branch_name: 'new_design',
ref: '621491c677087aa243f165eab467bfdfbee00be1'
response.status.should == 201
json_response['name'].should == 'new_design'
json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1'
end
it "should deny for user without push access" do
post api("/projects/#{project.id}/repository/branches", user2),
branch_name: 'new_design',
ref: '621491c677087aa243f165eab467bfdfbee00be1'
response.status.should == 403
end
end
end
......@@ -25,6 +25,12 @@ describe API::API do
json_response.should be_an Array
json_response.first['title'].should == issue.title
end
it "should add pagination headers" do
get api("/issues?per_page=3", user)
response.headers['Link'].should ==
'<http://www.example.com/api/v3/issues?page=1&per_page=3>; rel="first", <http://www.example.com/api/v3/issues?page=1&per_page=3>; rel="last"'
end
end
end
......
......@@ -14,86 +14,6 @@ describe API::API do
before { project.team << [user, :reporter] }
describe "GET /projects/:id/repository/branches" do
it "should return an array of project branches" do
get api("/projects/#{project.id}/repository/branches", user)
response.status.should == 200
json_response.should be_an Array
json_response.first['name'].should == project.repo.heads.sort_by(&:name).first.name
end
end
describe "GET /projects/:id/repository/branches/:branch" do
it "should return the branch information for a single branch" do
get api("/projects/#{project.id}/repository/branches/new_design", user)
response.status.should == 200
json_response['name'].should == 'new_design'
json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1'
json_response['protected'].should == false
end
it "should return a 403 error if guest" do
get api("/projects/#{project.id}/repository/branches", user2)
response.status.should == 403
end
it "should return a 404 error if branch is not available" do
get api("/projects/#{project.id}/repository/branches/unknown", user)
response.status.should == 404
end
end
describe "PUT /projects/:id/repository/branches/:branch/protect" do
it "should protect a single branch" do
put api("/projects/#{project.id}/repository/branches/new_design/protect", user)
response.status.should == 200
json_response['name'].should == 'new_design'
json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1'
json_response['protected'].should == true
end
it "should return a 404 error if branch not found" do
put api("/projects/#{project.id}/repository/branches/unknown/protect", user)
response.status.should == 404
end
it "should return a 403 error if guest" do
put api("/projects/#{project.id}/repository/branches/new_design/protect", user2)
response.status.should == 403
end
it "should return success when protect branch again" do
put api("/projects/#{project.id}/repository/branches/new_design/protect", user)
put api("/projects/#{project.id}/repository/branches/new_design/protect", user)
response.status.should == 200
end
end
describe "PUT /projects/:id/repository/branches/:branch/unprotect" do
it "should unprotect a single branch" do
put api("/projects/#{project.id}/repository/branches/new_design/unprotect", user)
response.status.should == 200
json_response['name'].should == 'new_design'
json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1'
json_response['protected'].should == false
end
it "should return success when unprotect branch" do
put api("/projects/#{project.id}/repository/branches/unknown/unprotect", user)
response.status.should == 404
end
it "should return success when unprotect branch again" do
put api("/projects/#{project.id}/repository/branches/new_design/unprotect", user)
put api("/projects/#{project.id}/repository/branches/new_design/unprotect", user)
response.status.should == 200
end
end
describe "GET /projects/:id/repository/tags" do
it "should return an array of project tags" do
get api("/projects/#{project.id}/repository/tags", user)
......
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