Merge branch 'master' into request/relative_submodules
Conflicts: CHANGELOG
This commit is contained in:
commit
cb659e4c5a
69 changed files with 862 additions and 541 deletions
|
@ -1,7 +1,11 @@
|
|||
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).
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# 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" }
|
||||
|
|
34
README.md
34
README.md
|
@ -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
|
||||
|
|
3
app/models/diff_line.rb
Normal file
3
app/models/diff_line.rb
Normal file
|
@ -0,0 +1,3 @@
|
|||
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)
|
||||
|
|
13
app/services/create_branch_service.rb
Normal file
13
app/services/create_branch_service.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
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,8 +70,9 @@
|
|||
- @group.users_groups.order('group_access DESC').each do |member|
|
||||
- user = member.user
|
||||
%li{class: dom_class(user)}
|
||||
%strong
|
||||
= link_to user.name, admin_user_path(user)
|
||||
.list-item-name
|
||||
%strong
|
||||
= link_to user.name, admin_user_path(user)
|
||||
%span.pull-right.light
|
||||
= member.human_access
|
||||
= link_to group_users_group_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
|
||||
|
|
|
@ -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,9 +44,10 @@
|
|||
%ul.well-list
|
||||
- @projects.each do |project|
|
||||
%li
|
||||
%span{ class: visibility_level_color(project.visibility_level) }
|
||||
= visibility_level_icon(project.visibility_level)
|
||||
= link_to project.name_with_namespace, [:admin, project]
|
||||
.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]
|
||||
.pull-right
|
||||
%span.label.label-gray
|
||||
= repository_size(project)
|
||||
|
|
|
@ -116,8 +116,9 @@
|
|||
- @project.users_projects.each do |users_project|
|
||||
- user = users_project.user
|
||||
%li.users_project
|
||||
%strong
|
||||
= link_to user.name, admin_user_path(user)
|
||||
.list-item-name
|
||||
%strong
|
||||
= link_to user.name, admin_user_path(user)
|
||||
.pull-right
|
||||
- if users_project.owner?
|
||||
%span.light Owner
|
||||
|
|
|
@ -36,15 +36,16 @@
|
|||
%ul.well-list
|
||||
- @users.each do |user|
|
||||
%li
|
||||
- if user.blocked?
|
||||
%i.icon-lock.cred
|
||||
- else
|
||||
%i.icon-user.cgreen
|
||||
= link_to user.name, [:admin, user]
|
||||
- if user.admin?
|
||||
%strong.cred (Admin)
|
||||
- if user == current_user
|
||||
%span.cred It's you!
|
||||
.list-item-name
|
||||
- if user.blocked?
|
||||
%i.icon-lock.cred
|
||||
- else
|
||||
%i.icon-user.cgreen
|
||||
= link_to user.name, [:admin, user]
|
||||
- if user.admin?
|
||||
%strong.cred (Admin)
|
||||
- if user == current_user
|
||||
%span.cred It's you!
|
||||
.pull-right
|
||||
%span.light
|
||||
%i.icon-envelope
|
||||
|
|
|
@ -124,7 +124,8 @@
|
|||
- @user.users_groups.each do |user_group|
|
||||
- group = user_group.group
|
||||
%li.users_group
|
||||
%strong= link_to group.name, admin_group_path(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
|
||||
- unless user_group.owner?
|
||||
|
|
|
@ -73,8 +73,9 @@
|
|||
%ul.well-list
|
||||
- @group.projects.each do |project|
|
||||
%li
|
||||
= visibility_level_icon(project.visibility_level)
|
||||
= link_to project.name_with_namespace, project
|
||||
.list-item-name
|
||||
= visibility_level_icon(project.visibility_level)
|
||||
= link_to project.name_with_namespace, project
|
||||
.pull-right
|
||||
= link_to 'Members', project_team_index_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
|
||||
= link_to 'Edit', edit_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,75 +1,55 @@
|
|||
/ 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]
|
||||
%div.diff-side.diff-side-left
|
||||
%table
|
||||
- old_lines.each do |line|
|
||||
|
||||
- if deleted_line && added_line
|
||||
- elsif deleted_line
|
||||
- new_line = nil
|
||||
- offset2 += 1
|
||||
- elsif added_line
|
||||
- old_line = nil
|
||||
- offset1 += 1
|
||||
%tr.line_holder.parallel
|
||||
- if line.type == :file_created
|
||||
%td.line_content.parallel= "File was created"
|
||||
- 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
|
||||
|
||||
%tr.line_holder.parallel
|
||||
- if line_index == 0 && diff.new_file
|
||||
%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
|
||||
- else
|
||||
%td.line_content.parallel= ""
|
||||
%td.old_line= ""
|
||||
%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.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
|
||||
- else
|
||||
%td.new_line= ""
|
||||
%td.line_content.parallel= ""
|
||||
- if new_lines[index].type == :added
|
||||
%td.new_line.new= new_lines[index].num
|
||||
- else
|
||||
%td.new_line= new_lines[index].num
|
||||
|
||||
- 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
|
||||
%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());
|
||||
});
|
||||
|
||||
$('.diff-side-left').on('scroll', function(){
|
||||
$('.diff-side-right, .diff-middle').scrollTop($(this).scrollTop()); // might never be relevant
|
||||
$('.diff-side-right').scrollLeft($(this).scrollLeft());
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
%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,11 +2,12 @@
|
|||
- return unless user
|
||||
- show_roles = true if show_roles.nil?
|
||||
%li{class: "#{dom_class(member)} js-toggle-container", id: dom_id(member)}
|
||||
= image_tag avatar_icon(user.email, 16), class: "avatar s16"
|
||||
%strong= user.name
|
||||
%span.cgray= user.username
|
||||
- if user == current_user
|
||||
%span.label.label-success It's you
|
||||
%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
|
||||
- if user == current_user
|
||||
%span.label.label-success It's you
|
||||
|
||||
- if show_roles
|
||||
%span.pull-right
|
||||
|
@ -22,7 +23,7 @@
|
|||
- else
|
||||
= link_to group_users_group_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
|
||||
%i.icon-minus.icon-white
|
||||
|
||||
|
||||
.edit-member.hide.js-toggle-content
|
||||
= form_for [@group, member], remote: true do |f|
|
||||
.alert.prepend-top-20
|
||||
|
|
|
@ -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
|
||||
|
|
18
doc/README.md
Normal file
18
doc/README.md
Normal file
|
@ -0,0 +1,18 @@
|
|||
## 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)
|
|
@ -1,5 +1,32 @@
|
|||
# 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
|
||||
|
|
198
doc/api/branches.md
Normal file
198
doc/api/branches.md
Normal file
|
@ -0,0 +1,198 @@
|
|||
# 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
|
||||
}
|
||||
```
|
|
@ -1,170 +1,3 @@
|
|||
## 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
|
||||
|
||||
|
|
2
doc/development/README.md
Normal file
2
doc/development/README.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
+ [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.
|
||||
|
@ -180,4 +180,4 @@ bundle exec rake gitlab:check RAILS_ENV=production
|
|||
```
|
||||
|
||||
Note: It is recommended to log into the `git` user using `sudo -i -u git` or `sudo su - git`.
|
||||
While the sudo commands provided by gitlabhq work in Ubuntu they do not always work in RHEL.
|
||||
While the sudo commands provided by gitlabhq work in Ubuntu they do not always work in RHEL.
|
4
doc/install/README.md
Normal file
4
doc/install/README.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
+ [Installation](installation.md)
|
||||
+ [Requirements](requirements.md)
|
||||
+ [Structure](structure.md)
|
||||
+ [Database MySQL](database_mysql.md)
|
|
@ -6,6 +6,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`;
|
||||
|
||||
|
|
2
doc/legal/README.md
Normal file
2
doc/legal/README.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
+ [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|||||✓|
|
||||
|
||||
|
|
6
doc/raketasks/README.md
Normal file
6
doc/raketasks/README.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
+ [Backup restore](backup_restore.md)
|
||||
+ [Cleanup](cleanup.md)
|
||||
+ [Features](features.md)
|
||||
+ [Maintenance](maintenance.md)
|
||||
+ [User management](user_management.md)
|
||||
+ [Web hooks](web_hooks.md)
|
2
doc/release/README.md
Normal file
2
doc/release/README.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
+ [Monthly](monthly.md)
|
||||
+ [Security](security.md)
|
2
doc/security/README.md
Normal file
2
doc/security/README.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
+ [Password length limits](password_length_limits.md)
|
||||
+ [Rack attack](rack_attack.md)
|
2
doc/ssh/README.md
Normal file
2
doc/ssh/README.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
+ [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)
|
||||
|
|
5
doc/update/README.md
Normal file
5
doc/update/README.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
+ [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,24 +3,25 @@
|
|||
```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"
|
||||
```
|
||||
|
||||
4. Push your branch to GitLab
|
||||
|
||||
|
||||
```bash
|
||||
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 & merge it to the main branch
|
||||
|
|
|
@ -45,5 +45,6 @@ module API
|
|||
mount Files
|
||||
mount Commits
|
||||
mount Namespaces
|
||||
mount Branches
|
||||
end
|
||||
end
|
||||
|
|
85
lib/api/branches.rb
Normal file
85
lib/api/branches.rb
Normal file
|
@ -0,0 +1,85 @@
|
|||
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
|
|
@ -1,21 +1,12 @@
|
|||
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_and_provider
|
||||
find_by_uid(uid)
|
||||
end
|
||||
|
||||
def find_by_uid(uid)
|
||||
model.where(provider: provider, extern_uid: uid).last
|
||||
# LDAP distinguished name is case-insensitive
|
||||
model.where("provider = ? and lower(extern_uid) = ?", provider, uid.downcase).last
|
||||
end
|
||||
|
||||
def username
|
||||
(auth.info.nickname || samaccountname).to_s.force_encoding("utf-8")
|
||||
end
|
||||
|
||||
def samaccountname
|
||||
(auth.extra[:raw_info][:samaccountname] || []).first
|
||||
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
|
||||
|
|
10
lib/tasks/gitlab/db/drop_all_tables.rake
Normal file
10
lib/tasks/gitlab/db/drop_all_tables.rake
Normal file
|
@ -0,0 +1,10 @@
|
|||
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') }
|
||||
|
||||
|
|
115
spec/requests/api/branches_spec.rb
Normal file
115
spec/requests/api/branches_spec.rb
Normal file
|
@ -0,0 +1,115 @@
|
|||
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)
|
||||
|
|
Loading…
Reference in a new issue