Commit bf0de1a5 authored by Jan-Willem van der Meer's avatar Jan-Willem van der Meer

Merge remote-tracking branch 'origin/master' into feature-oauth-refactoring

parents b18d1c27 78ec7d9c
......@@ -5,6 +5,8 @@ targets:
debian-7: &wheezy
build_dependencies:
- libicu-dev
- cmake
- pkg-config
dependencies:
- libicu48
- libpcre3
......@@ -13,6 +15,8 @@ targets:
ubuntu-14.04:
build_dependencies:
- libicu-dev
- cmake
- pkg-config
dependencies:
- libicu52
- libpcre3
......@@ -20,6 +24,8 @@ targets:
centos-6:
build_dependencies:
- libicu-devel
- cmake
- pkgconfig
dependencies:
- libicu
- pcre
......
language: ruby
cache:
directories:
- vendor/bundle
env:
global:
- TRAVIS=true
matrix:
- TASK=spinach_project DB=mysql
- TASK=spinach_other DB=mysql
- TASK=spec:api DB=mysql
- TASK=spec:feature DB=mysql
- TASK=spec:other DB=mysql
- TASK=jasmine:ci DB=mysql
- TASK=spinach_project DB=postgresql
- TASK=spinach_other DB=postgresql
- TASK=spec:api DB=postgresql
- TASK=spec:feature DB=postgresql
- TASK=spec:other DB=postgresql
- TASK=jasmine:ci DB=postgresql
before_install:
- sudo apt-get install libicu-dev -y
install:
- "travis_retry bundle config build.nokogiri --use-system-libraries"
- "travis_retry bundle install --deployment --without production --retry 5"
branches:
only:
- 'master'
rvm:
- 2.0.0
services:
- redis-server
before_script:
- "cp config/database.yml.$DB config/database.yml"
- "cp config/gitlab.yml.example config/gitlab.yml"
- "bundle exec rake db:setup"
- "bundle exec rake db:seed_fu"
script: "bundle exec rake $TASK --trace"
notifications:
email: false
git:
depth: 10
......@@ -10,9 +10,26 @@ v 7.3.0
- Support Unix domain sockets for Redis
- Store session Redis keys in 'session:gitlab:' namespace
- Deprecate LDAP account takeover based on partial LDAP email / GitLab username match
- Use /bin/sh instead of Bash in bin/web, bin/background_jobs (Pavel Novitskiy)
- Keyboard shortcuts for productivity (Robert Schilling)
- API: filter issues by state (Julien Bianchi)
- API: filter issues by labels (Julien Bianchi)
- Add system hook for ssh key changes
- Add blob permalink link (Ciro Santilli)
- Create annotated tags through UI and API (Sean Edge)
- Snippets search (Charles Bushong)
- Comment new push to existing MR
- Add 'ci' to the blacklist of forbidden names
- Improve text filtering on issues page
- Comment & Close button
- Process git push --all much faster
- Don't allow edit of system notes
- Project wiki search (Ralf Seidler)
- Enabled Shibboleth authentication support (Matus Banas)
v 7.2.1
- Delete orphaned labels during label migration (James Brooks)
- Security: prevent XSS with stricter MIME types for raw repo files
v 7.2.0
- Explore page
......
......@@ -27,6 +27,7 @@ gem 'omniauth', "~> 1.1.3"
gem 'omniauth-google-oauth2'
gem 'omniauth-twitter'
gem 'omniauth-github'
gem 'omniauth-shibboleth'
# Extracting information from a git repository
# Provide access to Gitlab::Git library
......@@ -36,7 +37,7 @@ gem "gitlab_git", '~> 6.0'
gem 'gitlab-grack', '~> 2.0.0.pre', require: 'grack'
# LDAP Auth
gem 'gitlab_omniauth-ldap', '1.0.4', require: "omniauth-ldap"
gem 'gitlab_omniauth-ldap', '1.1.0', require: "omniauth-ldap"
# Git Wiki
gem 'gollum-lib', '~> 3.0.0'
......
......@@ -168,7 +168,7 @@ GEM
multi_json
gitlab-grack (2.0.0.pre)
rack (~> 1.5.1)
gitlab-grit (2.6.10)
gitlab-grit (2.6.11)
charlock_holmes (~> 0.6)
diff-lcs (~> 1.1)
mime-types (~> 1.15)
......@@ -186,8 +186,8 @@ GEM
gitlab-linguist (~> 3.0)
rugged (~> 0.21.0)
gitlab_meta (7.0)
gitlab_omniauth-ldap (1.0.4)
net-ldap (~> 0.3.1)
gitlab_omniauth-ldap (1.1.0)
net-ldap (~> 0.7.0)
omniauth (~> 1.0)
pyu-ruby-sasl (~> 0.0.3.1)
rubyntlm (~> 0.1.1)
......@@ -292,7 +292,7 @@ GEM
multi_xml (0.5.5)
multipart-post (1.2.0)
mysql2 (0.3.16)
net-ldap (0.3.1)
net-ldap (0.7.0)
net-scp (1.1.2)
net-ssh (>= 2.6.5)
net-ssh (2.8.0)
......@@ -321,6 +321,8 @@ GEM
omniauth-oauth2 (1.1.1)
oauth2 (~> 0.8.0)
omniauth (~> 1.0)
omniauth-shibboleth (1.1.1)
omniauth (>= 1.0.0)
omniauth-twitter (1.0.1)
multi_json (~> 1.3)
omniauth-oauth (~> 1.0)
......@@ -616,7 +618,7 @@ DEPENDENCIES
gitlab_emoji (~> 0.0.1.1)
gitlab_git (~> 6.0)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (= 1.0.4)
gitlab_omniauth-ldap (= 1.1.0)
gollum-lib (~> 3.0.0)
gon (~> 5.0.0)
grape (~> 0.6.1)
......@@ -644,6 +646,7 @@ DEPENDENCIES
omniauth-github
omniauth-google-oauth2
omniauth-twitter
omniauth-shibboleth
org-ruby
pg
poltergeist (~> 1.5.1)
......
......@@ -87,7 +87,7 @@ Please use ``` to format console output, logs, and code as it's very hard to rea
### Issue fixed in newer version
Thanks for the issue report. This issue has already been fixed in newer versions of GitLab. Due to the size of this project and our limited resources we are only able to support the latest stable release as outlined in our \[contributing guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#issue-tracker). In order to get this bug fix and enjoy many new features please \[upgrade\]\(https://github.com/gitlabhq/gitlabhq/tree/master/doc/update). If you still experience issues at that time please open a new issue following our issue tracker guidelines found in the \[contributing guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#issue-tracker-guidelines).
Thanks for the issue report. This issue has already been fixed in newer versions of GitLab. Due to the size of this project and our limited resources we are only able to support the latest stable release as outlined in our \[contributing guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#issue-tracker). In order to get this bug fix and enjoy many new features please \[upgrade\]\(https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/update). If you still experience issues at that time please open a new issue following our issue tracker guidelines found in the \[contributing guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#issue-tracker-guidelines).
### Improperly formatted merge request
......
# GitLab
# ![logo](https://about.gitlab.com/images/gitlab_logo.png) GitLab
## Open source software to collaborate on code
![logo](https://gitlab.com/gitlab-org/gitlab-ce/raw/master/public/gitlab_logo.png)
![animated-screenshots](https://gist.github.com/fnkr/2f9badd56bfe0ed04ee7/raw/4f48806fbae97f556c2f78d8c2d299c04500cb0d/compiled.gif)
![Animated screenshots](https://about.gitlab.com/images/animated/compiled.gif)
- Manage Git repositories with fine grained access controls that keep your code secure
- Perform code reviews and enhance collaboration with merge requests
......@@ -21,6 +19,8 @@
- [![build status](https://ci.gitlab.org/projects/1/status.png?ref=master)](https://ci.gitlab.org/projects/1?ref=master) on ci.gitlab.org (master branch)
- [![Build Status](https://semaphoreapp.com/api/v1/projects/2f1a5809-418b-4cc2-a1f4-819607579fe7/243338/badge.png)](https://semaphoreapp.com/gitlabhq/gitlabhq)
- [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq)
- [![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.png?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq)
......@@ -29,14 +29,14 @@
## Website
On [www.gitlab.com](https://www.gitlab.com/) you can find more information about:
On [about.gitlab.com](https://about.gitlab.com/) you can find more information about:
- [Subscriptions](https://www.gitlab.com/subscription/)
- [Consultancy](https://www.gitlab.com/consultancy/)
- [Community](https://www.gitlab.com/community/)
- [Hosted GitLab.com](https://www.gitlab.com/gitlab-com/) use GitLab as a free service
- [GitLab Enterprise Edition](https://www.gitlab.com/gitlab-ee/) with additional features aimed at larger organizations.
- [GitLab CI](https://www.gitlab.com/gitlab-ci/) a continuous integration (CI) server that is easy to integrate with GitLab.
- [Subscriptions](https://about.gitlab.com/subscription/)
- [Consultancy](https://about.gitlab.com/consultancy/)
- [Community](https://about.gitlab.com/community/)
- [Hosted GitLab.com](https://about.gitlab.com/gitlab-com/) use GitLab as a free service
- [GitLab Enterprise Edition](https://about.gitlab.com/gitlab-ee/) with additional features aimed at larger organizations.
- [GitLab CI](https://about.gitlab.com/gitlab-ci/) a continuous integration (CI) server that is easy to integrate with GitLab.
## Third-party applications
......@@ -61,11 +61,11 @@ These applications are maintained by contributors, GitLab B.V. does not offer su
## Installation
Please see [the installation page on the GitLab website](https://www.gitlab.com/installation/).
Please see [the installation page on the GitLab website](https://about.gitlab.com/installation/).
### New versions
Since 2011 a minor or major version of GitLab is released on the 22nd of every month. Patch and security releases come out when needed. New features are detailed on the [blog](https://www.gitlab.com/blog/) and in the [changelog](CHANGELOG). For more information about the release process see the release [documentation](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/release). Features that will likely be in the next releases can be found on the [feature request forum](http://feedback.gitlab.com/forums/176466-general) with the status [started](http://feedback.gitlab.com/forums/176466-general/status/796456) and [completed](http://feedback.gitlab.com/forums/176466-general/status/796457).
Since 2011 a minor or major version of GitLab is released on the 22nd of every month. Patch and security releases come out when needed. New features are detailed on the [blog](https://about.gitlab.com/blog/) and in the [changelog](CHANGELOG). For more information about the release process see the release [documentation](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/release). Features that will likely be in the next releases can be found on the [feature request forum](http://feedback.gitlab.com/forums/176466-general) with the status [started](http://feedback.gitlab.com/forums/176466-general/status/796456) and [completed](http://feedback.gitlab.com/forums/176466-general/status/796457).
### Upgrading
......@@ -85,7 +85,8 @@ Please login with `root` / `5iveL!fe`
## Install a development environment
We recommend setting up your development environment with [the cookbook](https://gitlab.com/gitlab-org/cookbook-gitlab/blob/master/README.md#installation). If you do not use the cookbook you might need to copy the example development unicorn configuration file
We recommend setting up your development environment with [the GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit).
If you do not use the development kit you might need to copy the example development unicorn configuration file
cp config/unicorn.rb.example.development config/unicorn.rb
......@@ -126,7 +127,7 @@ All documentation can be found on [doc.gitlab.com/ce/](http://doc.gitlab.com/ce/
## Getting help
Please see [Getting help for GitLab](https://www.gitlab.com/getting-help/) on our website for the many options to get help.
Please see [Getting help for GitLab](https://about.gitlab.com/getting-help/) on our website for the many options to get help.
## Is it any good?
......
......@@ -43,25 +43,31 @@
$(".selected_issue").bind "change", Issues.checkChanged
# Make sure we trigger ajax request only after user stop typing
initSearch: ->
form = $("#issue_search_form")
last_terms = ""
@timer = null
$("#issue_search").keyup ->
terms = $(this).val()
unless terms is last_terms
last_terms = terms
if terms.length >= 2 or terms.length is 0
$.ajax
type: "GET"
url: location.href
data: "issue_search=" + terms
complete: ->
$(".loading").hide()
success: (data) ->
$('.issues-holder').html(data.html)
Issues.reload()
dataType: "json"
clearTimeout(@timer);
@timer = setTimeout(Issues.filterResults, 500)
filterResults: =>
form = $("#issue_search_form")
search = $("#issue_search").val()
$('.issues-holder').css("opacity", '0.5')
issues_url = form.attr('action') + '? '+ form.serialize()
$.ajax
type: "GET"
url: form.attr('action')
data: form.serialize()
complete: ->
$('.issues-holder').css("opacity", '1.0')
success: (data) ->
$('.issues-holder').html(data.html)
# Change url so if user reload a page - search results are saved
History.replaceState {page: issues_url}, document.title, issues_url
Issues.reload()
dataType: "json"
checkChanged: ->
checked_issues = $(".selected_issue:checked")
......
......@@ -26,6 +26,7 @@ class Notes
# Reopen and close actions for Issue/MR combined with note form submit
$(document).on "click", ".js-note-target-reopen", @targetReopen
$(document).on "click", ".js-note-target-close", @targetClose
$(document).on "click", ".js-comment-button", @updateCloseButton
$(document).on "keyup", ".js-note-text", @updateTargetButtons
# remove a note (in general)
......@@ -496,6 +497,11 @@ class Notes
if noteText.trim().length > 0
form.submit()
updateCloseButton: (e) =>
textarea = $(e.target)
form = textarea.parents('form')
form.find('.js-note-target-close').text('Close')
updateTargetButtons: (e) =>
textarea = $(e.target)
form = textarea.parents('form')
......
......@@ -3,7 +3,7 @@
class @ShortcutsNavigation extends Shortcuts
constructor: ->
super()
Mousetrap.bind('g a', -> ShortcutsNavigation.findAndollowLink('.shortcuts-activity'))
Mousetrap.bind('g p', -> ShortcutsNavigation.findAndollowLink('.shortcuts-project'))
Mousetrap.bind('g f', -> ShortcutsNavigation.findAndollowLink('.shortcuts-tree'))
Mousetrap.bind('g c', -> ShortcutsNavigation.findAndollowLink('.shortcuts-commits'))
Mousetrap.bind('g n', -> ShortcutsNavigation.findAndollowLink('.shortcuts-network'))
......
......@@ -39,7 +39,7 @@
&:hover {
background: $hover;
border-bottom: 1px solid #ADF;
border-bottom: 1px solid darken($hover, 10%);
}
&:last-child {
......
......@@ -40,7 +40,7 @@ a {
outline: none;
color: $link_color;
&:hover {
text-decoration: none;
text-decoration: underline;
color: $link_hover_color;
}
......@@ -89,6 +89,8 @@ a:focus {
.wiki {
@include md-typography;
word-wrap: break-word;
/* Link to current header. */
h1, h2, h3, h4, h5, h6 {
position: relative;
......
......@@ -2,13 +2,13 @@
* General Colors
*/
$style_color: #474D57;
$hover: #D9EDF7;
$hover: #FFECDB;
/*
* Link colors
*/
$link_color: #446e9b;
$link_hover_color: #2FA0BB;
$link_hover_color: darken($link-color, 10%);
$btn-border: 1px solid #ccc;
......
......@@ -100,14 +100,9 @@
margin-right: 15px;
font-size: 20px;
margin-bottom: 15px;
border: 1px solid #EEE;
padding: 8px 12px;
border-radius: 50px;
background: #f5f5f5;
text-align: center;
i {
color: #BBB;
color: #888;
}
}
......
......@@ -17,9 +17,17 @@ class Projects::BranchesController < Projects::ApplicationController
end
def create
@branch = CreateBranchService.new.execute(project, params[:branch_name], params[:ref], current_user)
redirect_to project_tree_path(@project, @branch.name)
result = CreateBranchService.new.execute(project,
params[:branch_name],
params[:ref],
current_user)
if result[:status] == :success
@branch = result[:branch]
redirect_to project_tree_path(@project, @branch.name)
else
@error = result[:message]
render action: 'new'
end
end
def destroy
......
......@@ -31,7 +31,7 @@ class Projects::EditTreeController < Projects::BaseTreeController
diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3',
include_diff_info: true)
@diff = Gitlab::DiffParser.new(diffy.diff.scan(/.*\n/))
@diff_lines = Gitlab::Diff::Parser.new.parse(diffy.diff.scan(/.*\n/))
render layout: false
end
......
......@@ -52,7 +52,7 @@ class Projects::LabelsController < Projects::ApplicationController
respond_to do |format|
format.html { redirect_to project_labels_path(@project), notice: 'Label was removed' }
format.js { render nothing: true }
format.js
end
end
......
......@@ -13,10 +13,16 @@ class Projects::TagsController < Projects::ApplicationController
end
def create
@tag = CreateTagService.new.execute(@project, params[:tag_name],
params[:ref], current_user)
redirect_to project_tags_path(@project)
result = CreateTagService.new.execute(@project, params[:tag_name],
params[:ref], params[:message],
current_user)
if result[:status] == :success
@tag = result[:tag]
redirect_to project_tags_path(@project)
else
@error = result[:message]
render action: 'new'
end
end
def destroy
......
......@@ -103,7 +103,15 @@ class ProjectsController < ApplicationController
::Projects::DestroyService.new(@project, current_user, {}).execute
respond_to do |format|
format.html { redirect_to root_path }
format.html do
flash[:alert] = "Project deleted."
if request.referer.include?("/admin")
redirect_to admin_projects_path
else
redirect_to projects_dashboard_path
end
end
end
end
......
......@@ -5,15 +5,23 @@ class SearchController < ApplicationController
@project = Project.find_by(id: params[:project_id]) if params[:project_id].present?
@group = Group.find_by(id: params[:group_id]) if params[:group_id].present?
@scope = params[:scope]
@show_snippets = params[:snippets].eql? 'true'
@search_results = if @project
return access_denied! unless can?(current_user, :download_code, @project)
unless %w(blobs notes issues merge_requests).include?(@scope)
unless %w(blobs notes issues merge_requests wiki_blobs).
include?(@scope)
@scope = 'blobs'
end
Search::ProjectService.new(@project, current_user, params).execute
elsif @show_snippets
unless %w(snippet_blobs snippet_titles).include?(@scope)
@scope = 'snippet_blobs'
end
Search::SnippetService.new(current_user, params).execute
else
unless %w(projects issues merge_requests).include?(@scope)
@scope = 'projects'
......
......@@ -178,6 +178,8 @@ module ApplicationHelper
def search_placeholder
if @project && @project.persisted?
"Search in this project"
elsif @snippet || @snippets || @show_snippets
'Search snippets'
elsif @group && @group.persisted?
"Search in this group"
else
......
......@@ -16,38 +16,6 @@ module CommitsHelper
commit_person_link(commit, options.merge(source: :committer))
end
def each_diff_line(diff, index)
Gitlab::DiffParser.new(diff.diff.lines.to_a, diff.new_path)
.each do |full_line, type, line_code, line_new, line_old|
yield(full_line, type, line_code, line_new, line_old)
end
end
def each_diff_line_near(diff, index, expected_line_code)
max_number_of_lines = 16
prev_match_line = nil
prev_lines = []
each_diff_line(diff, index) do |full_line, type, line_code, line_new, line_old|
line = [full_line, type, line_code, line_new, line_old]
if line_code != expected_line_code
if type == "match"
prev_lines.clear
prev_match_line = line
else
prev_lines.push(line)
prev_lines.shift if prev_lines.length >= max_number_of_lines
end
else
yield(prev_match_line) if !prev_match_line.nil?
prev_lines.each { |ln| yield(ln) }
yield(line)
break
end
end
end
def image_diff_class(diff)
if diff.deleted_file
"deleted"
......@@ -63,14 +31,6 @@ module CommitsHelper
escape_javascript(render "projects/commits/#{template}", commit: commit, project: project) unless commit.nil?
end
def diff_line_content(line)
if line.blank?
" &nbsp;"
else
line
end
end
# Breadcrumb links for a Project and, if applicable, a tree path
def commits_breadcrumbs
return unless @project && @ref
......@@ -105,82 +65,6 @@ module CommitsHelper
branches.sort.map { |branch| link_to(branch, project_tree_path(project, branch)) }.join(", ").html_safe
end
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.loc, file.loc].max : file.loc
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
def link_to_browse_code(project, commit)
if current_controller?(:projects, :commits)
if @repo.blob_at(commit.id, @path)
......@@ -229,14 +113,6 @@ module CommitsHelper
end
end
def diff_file_mode_changed?(diff)
diff.a_mode && diff.b_mode && diff.a_mode != diff.b_mode
end
def unfold_bottom_class(bottom)
(bottom) ? 'js-unfold-bottom' : ''
end
def view_file_btn(commit_sha, diff, project)
link_to project_blob_path(project, tree_join(commit_sha, diff.new_path)),
class: 'btn btn-small view-file js-view-file' do
......
module DiffHelper
def safe_diff_files(diffs)
def allowed_diff_size
if diff_hard_limit_enabled?
diffs.first(Commit::DIFF_HARD_LIMIT_FILES)
Commit::DIFF_HARD_LIMIT_FILES
else
diffs.first(Commit::DIFF_SAFE_FILES)
Commit::DIFF_SAFE_FILES
end
end
def safe_diff_files(diffs)
diffs.first(allowed_diff_size).map do |diff|
Gitlab::Diff::File.new(diff)
end
end
def show_diff_size_warninig?(diffs)
safe_diff_files(diffs).size < diffs.size
def show_diff_size_warning?(diffs)
diffs.size > allowed_diff_size
end
def diff_hard_limit_enabled?
......@@ -19,4 +25,76 @@ module DiffHelper
false
end
end
def generate_line_code(file_path, line)
Gitlab::Diff::LineCode.generate(file_path, line.new_pos, line.old_pos)
end
def parallel_diff(diff_file, index)
lines = []
skip_next = false
# Building array of lines
#
# [left_type, left_line_number, left_line_content, line_code, right_line_type, right_line_number, right_line_content]
#
diff_file.diff_lines.each do |line|
full_line = line.text
type = line.type
line_code = generate_line_code(diff_file.file_path, line)
line_new = line.new_pos
line_old = line.old_pos
next_line = diff_file.next_line(line.index)
if next_line
next_type = next_line.type
next_line = next_line.text
end
line = [type, line_old, full_line, line_code, next_type, line_new]
if type == 'match' || type.nil?
# line in the right panel is the same as in the left one
line = [type, line_old, full_line, line_code, type, line_new, full_line]
lines.push(line)
elsif type == 'old'
if next_type == 'new'
# Left side has text removed, right side has text added
line.push(next_line)
lines.push(line)
skip_next = true
elsif next_type == 'old' || next_type.nil?
# Left side has text removed, right side doesn't have any change
line.pop # remove the newline
line.push(nil) # no line number on the right panel
line.push("&nbsp;") # empty line on the right panel
lines.push(line)
end
elsif type == 'new'
if skip_next
# Change has been already included in previous line so no need to do it again
skip_next = false
next
else
# Change is only on the right side, left side has no change
line = [nil, nil, "&nbsp;", line_code, type, line_new, full_line]
lines.push(line)
end
end
end
lines
end
def unfold_bottom_class(bottom)
(bottom) ? 'js-unfold-bottom' : ''
end
def diff_line_content(line)
if line.blank?
" &nbsp;"
else
line
end
end
end
......@@ -178,12 +178,6 @@ module Network
space = find_free_space(time_range, 2, space_base)
leaves.each do |l|
l.spaces << space
# Also add space to parent
l.parents(@map).each do |parent|
if 0 < parent.space && parent.space < space
parent.spaces << space
end
end
end
# and mark it as reserved
......
......@@ -117,6 +117,25 @@ class Note < ActiveRecord::Base
})
end
def create_new_commits_note(noteable, project, author, commits)
commits_text = ActionController::Base.helpers.pluralize(commits.size, 'new commit')
body = "Added #{commits_text}:\n\n"
commits.each do |commit|
message = "* #{commit.short_id} - #{commit.title}"
body << message
body << "\n"
end
create(
noteable: noteable,
project: project,
author: author,
note: body,
system: true
)
end
def discussions_from_notes(notes)
discussion_ids = []
discussions = []
......@@ -190,9 +209,10 @@ class Note < ActiveRecord::Base
noteable.diffs.each do |mr_diff|
next unless mr_diff.new_path == self.diff.new_path
Gitlab::DiffParser.new(mr_diff.diff.lines.to_a, mr_diff.new_path).
each do |full_line, type, line_code, line_new, line_old|
if full_line == diff_line
lines = Gitlab::Diff::Parser.new.parse(mr_diff.diff.lines.to_a)
lines.each do |line|
if line.text == diff_line
return true
end
end
......@@ -213,6 +233,14 @@ class Note < ActiveRecord::Base
diff.new_path if diff
end
def file_path
if diff.new_path.present?
diff.new_path
elsif diff.old_path.present?
diff.old_path
end
end
def diff_old_line
line_code.split('_')[1].to_i
end
......@@ -221,19 +249,49 @@ class Note < ActiveRecord::Base
line_code.split('_')[2].to_i
end
def generate_line_code(line)
Gitlab::Diff::LineCode.generate(file_path, line.new_pos, line.old_pos)
end
def diff_line
return @diff_line if @diff_line
if diff
Gitlab::DiffParser.new(diff.diff.lines.to_a, diff.new_path)
.each do |full_line, type, line_code, line_new, line_old|
@diff_line = full_line if line_code == self.line_code
diff_lines.each do |line|
if generate_line_code(line) == self.line_code
@diff_line = line.text
end
end
end
@diff_line
end
def truncated_diff_lines
max_number_of_lines = 16
prev_match_line = nil
prev_lines = []
diff_lines.each do |line|
if generate_line_code(line) != self.line_code
if line.type == "match"
prev_lines.clear
prev_match_line = line
else
prev_lines.push(line)
prev_lines.shift if prev_lines.length >= max_number_of_lines
end
else
prev_lines << line
return prev_lines
end
end
end
def diff_lines
@diff_lines ||= Gitlab::Diff::Parser.new.parse(diff.diff.lines.to_a)
end
def discussion_id
@discussion_id ||= Note.build_discussion_id(noteable_type, noteable_id || commit_id, line_code)
end
......
......@@ -70,7 +70,7 @@ class Project < ActiveRecord::Base
has_many :merge_requests, dependent: :destroy, foreign_key: "target_project_id"
# Merge requests from source project should be kept when source project was removed
has_many :fork_merge_requests, foreign_key: "source_project_id", class_name: MergeRequest
has_many :issues, -> { order "state DESC, created_at DESC" }, dependent: :destroy
has_many :issues, -> { order 'issues.state DESC, issues.created_at DESC' }, dependent: :destroy
has_many :labels, dependent: :destroy
has_many :services, dependent: :destroy
has_many :events, dependent: :destroy
......@@ -400,18 +400,35 @@ class Project < ActiveRecord::Base
def update_merge_requests(oldrev, newrev, ref, user)
return true unless ref =~ /heads/
branch_name = ref.gsub("refs/heads/", "")
c_ids = self.repository.commits_between(oldrev, newrev).map(&:id)
commits = self.repository.commits_between(oldrev, newrev)
c_ids = commits.map(&:id)
# Close merge requests
mrs = self.merge_requests.opened.where(target_branch: branch_name).to_a
mrs = mrs.select(&:last_commit).select { |mr| c_ids.include?(mr.last_commit.id) }
mrs.each { |merge_request| MergeRequests::MergeService.new.execute(merge_request, user, nil) }
mrs.uniq.each do |merge_request|
MergeRequests::MergeService.new.execute(merge_request, user, nil)
end
# Update code for merge requests into project between project branches
mrs = self.merge_requests.opened.by_branch(branch_name).to_a
# Update code for merge requests between project and project fork
mrs += self.fork_merge_requests.opened.by_branch(branch_name).to_a
mrs.each { |merge_request| merge_request.reload_code; merge_request.mark_as_unchecked }
mrs.uniq.each do |merge_request|
merge_request.reload_code
merge_request.mark_as_unchecked
end
# Add comment about pushing new commits to merge requests
mrs = self.merge_requests.opened.where(source_branch: branch_name).to_a
mrs += self.fork_merge_requests.opened.where(source_branch: branch_name).to_a
mrs.uniq.each do |merge_request|
Note.create_new_commits_note(merge_request, merge_request.project,
user, commits)
end
true
end
......
......@@ -5,21 +5,17 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# recipients :text
# api_key :string(255)
# properties :text
#
class AssemblaService < Service
include HTTParty
prop_accessor :token, :subdomain
validates :token, presence: true, if: :activated?
def title
......
......@@ -5,19 +5,15 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# recipients :text
# api_key :string(255)
# properties :text
#
class CampfireService < Service
prop_accessor :token, :subdomain, :room
validates :token, presence: true, if: :activated?
def title
......
......@@ -5,16 +5,11 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# recipients :text
# api_key :string(255)
# properties :text
#
# Base class for CI services
......
......@@ -5,19 +5,15 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# recipients :text
# api_key :string(255)
# properties :text
#
class EmailsOnPushService < Service
prop_accessor :recipients
validates :recipients, presence: true, if: :activated?
def title
......
......@@ -5,21 +5,17 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# recipients :text
# api_key :string(255)
# properties :text
#
require "flowdock-git-hook"
class FlowdockService < Service
prop_accessor :token
validates :token, presence: true, if: :activated?
def title
......
......@@ -5,21 +5,17 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# recipients :text
# api_key :string(255)
# properties :text
#
require "gemnasium/gitlab_service"
class GemnasiumService < Service
prop_accessor :token, :api_key
validates :token, :api_key, presence: true, if: :activated?
def title
......
......@@ -5,19 +5,15 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# recipients :text
# api_key :string(255)
# property :text
#
class GitlabCiService < CiService
prop_accessor :project_url, :token
validates :project_url, presence: true, if: :activated?
validates :token, presence: true, if: :activated?
......
......@@ -5,21 +5,17 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# recipients :text
# api_key :string(255)
# properties :text
#
class HipchatService < Service
MAX_COMMITS = 3
prop_accessor :token, :room
validates :token, presence: true, if: :activated?
def title
......
......@@ -5,21 +5,17 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# recipients :text
# api_key :string(255)
# properties :text
#
class PivotaltrackerService < Service
include HTTParty
prop_accessor :token
validates :token, presence: true, if: :activated?
def title
......
......@@ -5,19 +5,15 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# recipients :text
# api_key :string(255)
# properties :text
#
class SlackService < Service
prop_accessor :room, :subdomain, :token
validates :room, presence: true, if: :activated?
validates :subdomain, presence: true, if: :activated?
validates :token, presence: true, if: :activated?
......
......@@ -64,10 +64,10 @@ class Repository
gitlab_shell.add_branch(path_with_namespace, branch_name, ref)
end
def add_tag(tag_name, ref)
def add_tag(tag_name, ref, message = nil)
Rails.cache.delete(cache_key(:tag_names))
gitlab_shell.add_tag(path_with_namespace, tag_name, ref)
gitlab_shell.add_tag(path_with_namespace, tag_name, ref, message)
end
def rm_branch(branch_name)
......
......@@ -5,22 +5,19 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# recipients :text
# api_key :string(255)
#
# properties :text
# To add new service you should build a class inherited from Service
# and implement a set of methods
class Service < ActiveRecord::Base
serialize :properties, JSON
default_value_for :active, false
default_value_for :properties, {}
belongs_to :project
has_one :service_hook
......@@ -63,4 +60,20 @@ class Service < ActiveRecord::Base
def can_test?
!project.empty_repo?
end
# Provide convenient accessor methods
# for each serialized property.
def self.prop_accessor(*args)
args.each do |arg|
class_eval %{
def #{arg}
properties['#{arg}']
end
def #{arg}=(value)
self.properties['#{arg}'] = value
end
}
end
end
end
......@@ -65,4 +65,18 @@ class Snippet < ActiveRecord::Base
def expired?
expires_at && expires_at < Time.current
end
class << self
def search(query)
where('(title LIKE :query OR file_name LIKE :query)', query: "%#{query}%")
end
def search_code(query)
where('(content LIKE :query)', query: "%#{query}%")
end
def accessible_to(user)
where('private = ? OR author_id = ?', false, user)
end
end
end
class CreateBranchService
def execute(project, branch_name, ref, current_user)
valid_branch = Gitlab::GitRefValidator.validate(branch_name)
if valid_branch == false
return error('Branch name invalid')
end
repository = project.repository
existing_branch = repository.find_branch(branch_name)
if existing_branch
return error('Branch already exists')
end
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')
return success(new_branch)
else
return error('Invalid reference name')
end
end
def error(message)
{
message: message,
status: :error
}
end
new_branch
def success(branch)
{
branch: branch,
status: :success
}
end
end
class CreateTagService
def execute(project, tag_name, ref, current_user)
def execute(project, tag_name, ref, message, current_user)
valid_tag = Gitlab::GitRefValidator.validate(tag_name)
if valid_tag == false
return error('Tag name invalid')
end
repository = project.repository
repository.add_tag(tag_name, ref)
existing_tag = repository.find_tag(tag_name)
if existing_tag
return error('Tag already exists')
end
if message
message.gsub!(/^\s+|\s+$/, '')
end
repository.add_tag(tag_name, ref, message)
new_tag = repository.find_tag(tag_name)
if new_tag
Event.create_ref_event(project, current_user, new_tag, 'add', 'refs/tags')
return success(new_tag)
else
return error('Invalid reference name')
end
end
def error(message)
{
message: message,
status: :error
}
end
new_tag
def success(branch)
{
tag: branch,
status: :success
}
end
end
......@@ -5,21 +5,21 @@ class DeleteBranchService
# No such branch
unless branch
return error('No such branch')
return error('No such branch', 404)
end
if branch_name == repository.root_ref
return error('Cannot remove HEAD branch')
return error('Cannot remove HEAD branch', 405)
end
# Dont allow remove of protected branch
if project.protected_branch?(branch_name)
return error('Protected branch cant be removed')
return error('Protected branch cant be removed', 405)
end
# Dont allow user to remove branch if he is not allowed to push
unless current_user.can?(:push_code, project)
return error('You dont have push access to repo')
return error('You dont have push access to repo', 405)
end
if repository.rm_branch(branch_name)
......@@ -30,9 +30,10 @@ class DeleteBranchService
end
end
def error(message)
def error(message, return_code = 400)
{
message: message,
return_code: return_code,
state: :error
}
end
......
module Search
class SnippetService
attr_accessor :current_user, :params
def initialize(user, params)
@current_user, @params = user, params.dup
end
def execute
snippet_ids = Snippet.accessible_to(current_user).pluck(:id)
Gitlab::SnippetSearchResults.new(snippet_ids, params[:search])
end
end
end
......@@ -70,6 +70,14 @@
%strong.cred
No
%li
%span.light Current sign-in at:
%strong
- if @user.current_sign_in_at
= @user.current_sign_in_at.stamp("Nov 12, 2031")
- else
never
%li
%span.light Last sign-in at:
%strong
......
%li
.project-access-icon
= visibility_level_icon(project.visibility_level)
%h4.project-title
.project-access-icon
= visibility_level_icon(project.visibility_level)
= link_to project.name_with_namespace, project
.project-description
%h4.project-title
= link_to project.name_with_namespace, project
- if current_page?(starred_explore_projects_path)
%strong.pull-right
= pluralize project.star_count, 'star'
- if current_page?(starred_explore_projects_path)
%strong.pull-right
= pluralize project.star_count, 'star'
.project-info
- if project.description.present?
%p.project-description.str-truncated
= project.description
......
......@@ -78,9 +78,9 @@
%tr
%td.shortcut
.key g
.key a
.key p
%td
Go to the activity feed
Go to the project's activity feed
%tr
%td.shortcut
.key g
......
......@@ -5,6 +5,8 @@
- if @project && @project.persisted?
= hidden_field_tag :project_id, @project.id
= hidden_field_tag :search_code, true
- if @snippet || @snippets
= hidden_field_tag :snippets, true
= hidden_field_tag :repository_ref, @ref
= submit_tag 'Go' if ENV['RAILS_ENV'] == 'test'
.search-autocomplete-opts.hide{:'data-autocomplete-path' => search_autocomplete_path, :'data-autocomplete-project-id' => @project.try(:id), :'data-autocomplete-project-ref' => @ref }
......
%ul.project-navigation
= nav_link(path: 'projects#show', html_options: {class: "home"}) do
= link_to project_path(@project), title: 'Project', class: 'shortcuts-activity' do
= link_to project_path(@project), title: 'Project', class: 'shortcuts-project' do
Project
- if project_nav_tab? :files
= nav_link(controller: %w(tree blob blame edit_tree new_tree)) do
......
%p
Assignee changed
- if @previous_assignee
from
%strong #{@previous_assignee.name}
to
- if issuable.assignee_id
%strong #{issuable.assignee_name}
- else
%strong Unassigned
Reassigned <%= issuable.class.model_name.human.titleize %> <%= issuable.iid %>
<%= url_for([issuable.project, issuable, {only_path: false}]) %>
Assignee changed <%= "from #{@previous_assignee.name}" if @previous_assignee -%>
to <%= "#{issuable.assignee_id ? issuable.assignee_name : 'Unassigned'}" %>
%p
Assignee changed
- if @previous_assignee
from
%strong #{@previous_assignee.name}
to
- if @issue.assignee_id
%strong #{@issue.assignee_name}
- else
%strong Unassigned
= render 'reassigned_issuable_email', issuable: @issue
Reassigned Issue <%= @issue.iid %>
<%= url_for(project_issue_url(@issue.project, @issue)) %>
Assignee changed <%= "from #{@previous_assignee.name}" if @previous_assignee %> to <%= "#{@issue.assignee_id ? @issue.assignee_name : 'Unassigned'}" %>
<%= render 'reassigned_issuable_email', issuable: @issue %>
%p
Assignee changed
- if @previous_assignee
from
%strong #{@previous_assignee.name}
to
%strong #{@merge_request.assignee_name}
= render 'reassigned_issuable_email', issuable: @merge_request
Reassigned Merge Request #<%= @merge_request.iid %>
<%= url_for(project_merge_request_url(@merge_request.target_project, @merge_request)) %>
Assignee changed <%= "from #{@previous_assignee.name}" if @previous_assignee %> to <%= @merge_request.assignee_name %>
<%= render 'reassigned_issuable_email', issuable: @merge_request %>
.form-group
= f.label :title, class: 'control-label' do
%strong= 'Title *'
.col-sm-10
= f.text_field :title, maxlength: 255, autofocus: true,
class: 'form-control pad js-gfm-input', required: true
.form-group
= f.label :description, 'Description', class: 'control-label'
.col-sm-10
= f.text_area :description, rows: 14,
class: 'form-control js-gfm-input markdown-area'
.col-sm-12.hint
.pull-left
Parsed with
#{link_to 'GitLab Flavored Markdown', help_page_path('markdown', 'markdown'), target: '_blank'}.
.pull-right
Attach images (JPG, PNG, GIF) by dragging &amp; dropping
or #{link_to 'selecting them', '#', class: 'markdown-selector' }.
.clearfix
.error-alert
%hr
.form-group
.issue-assignee
= f.label :assignee_id, class: 'control-label' do
%i.icon-user
Assign to
.col-sm-10
= project_users_select_tag("#{issuable.class.model_name.param_key}[assignee_id]",
placeholder: 'Select a user', class: 'custom-form-control',
selected: issuable.assignee_id)
&nbsp;
= link_to 'Assign to me', '#', class: 'btn assign-to-me-link'
.form-group
.issue-milestone
= f.label :milestone_id, class: 'control-label' do
%i.icon-time
Milestone
.col-sm-10= f.select(:milestone_id, milestone_options(issuable),
{ include_blank: 'Select milestone' }, { class: 'select2' })
......@@ -13,6 +13,9 @@
- else
= link_to "blame", project_blame_path(@project, @id), class: "btn btn-small" unless @blob.empty?
= link_to "history", project_commits_path(@project, @id), class: "btn btn-small"
- if @ref != @commit.sha
= link_to 'permalink', project_blob_path(@project,
tree_join(@commit.sha, @path)), class: 'btn btn-small'
- if allowed_tree_edit?
= link_to '#modal-remove-blob', class: "remove-blob btn btn-small btn-remove", "data-toggle" => "modal" do
......
- if @lines.present?
- if @form.unfold? && @form.since != 1 && !@form.bottom?
%tr.line_holder{ id: @form.since }
= render "projects/commits/diffs/match_line", {line: @match_line,
= render "projects/diffs/match_line", {line: @match_line,
line_old: @form.since, line_new: @form.since, bottom: false}
- @lines.each_with_index do |line, index|
......@@ -15,5 +15,5 @@
- if @form.unfold? && @form.bottom? && @form.to < @blob.loc
%tr.line_holder{ id: @form.to }
= render "projects/commits/diffs/match_line", {line: @match_line,
= render "projects/diffs/match_line", {line: @match_line,
line_old: @form.to, line_new: @form.to, bottom: true}
......@@ -2,7 +2,7 @@
%li(class="js-branch-#{branch.name}")
%h4
= link_to project_tree_path(@project, branch.name) do
%strong= truncate(branch.name, length: 60)
%strong.str-truncated= branch.name
- if branch.name == @repository.root_ref
%span.label.label-info default
- if @project.protected_branch? branch.name
......
- if @error
.alert.alert-danger
%button{ type: "button", class: "close", "data-dismiss" => "alert"} &times;
= @error
%h3.page-title
%i.icon-code-fork
New branch
......@@ -5,11 +9,11 @@
.form-group
= label_tag :branch_name, 'Name for new branch', class: 'control-label'
.col-sm-10
= text_field_tag :branch_name, nil, placeholder: 'enter new branch name', required: true, tabindex: 1, class: 'form-control'
= text_field_tag :branch_name, params[:branch_name], placeholder: 'enter new branch name', required: true, tabindex: 1, class: 'form-control'
.form-group
= label_tag :ref, 'Create from', class: 'control-label'
.col-sm-10
= text_field_tag :ref, nil, placeholder: 'existing branch name, tag or commit SHA', required: true, tabindex: 2, class: 'form-control'
= text_field_tag :ref, params[:ref], placeholder: 'existing branch name, tag or commit SHA', required: true, tabindex: 2, class: 'form-control'
.form-actions
= submit_tag 'Create branch', class: 'btn btn-create', tabindex: 3
= link_to 'Cancel', project_branches_path(@project), class: 'btn btn-cancel'
......
= render "commit_box"
= render "projects/commits/diffs", diffs: @diffs, project: @project
= render "projects/diffs/diffs", diffs: @diffs, project: @project
= render "projects/notes/notes_with_form"
/ Side-by-side diff view
- old_lines, new_lines = parallel_diff_lines(project, @commit, diff, file)
- num_lines = old_lines.length
%div.text-file
%table
- num_lines.times do |index|
- new_line = new_lines[index]
- old_line = old_lines[index]
%tr.line_holder.parallel
-# For old line
- if old_line.type == :file_created
%td.old_line= old_line.num
%td.line_content.parallel= "File was created"
- elsif old_line.type == :deleted
%td.old_line.old= old_line.num
%td.line_content{class: "parallel noteable_line old #{old_line.code}", "line_code" => old_line.code}= old_line.content
- else old_line.type == :no_change
%td.old_line= old_line.num
%td.line_content.parallel= old_line.content
-# For new line
- if new_line.type == :file_deleted
%td.new_line= new_line.num
%td.line_content.parallel= "File was deleted"
- elsif new_line.type == :added
%td.new_line.new= new_line.num
%td.line_content{class: "parallel noteable_line new #{new_line.code}", "line_code" => new_line.code}= new_line.content
- else new_line.type == :no_change
%td.new_line= new_line.num
%td.line_content.parallel= new_line.content
- if @reply_allowed
- comments1 = @line_notes.select { |n| n.line_code == old_line.code }.sort_by(&:created_at)
- comments2 = @line_notes.select { |n| n.line_code == new_line.code }.sort_by(&:created_at)
- unless comments1.empty? and comments2.empty?
= render "projects/notes/diff_notes_with_reply_parallel", notes1: comments1, notes2: comments2
......@@ -18,7 +18,7 @@
- else
%ul.well-list= render Commit.decorate(@commits), project: @project
= render "projects/commits/diffs", diffs: @diffs, project: @project
= render "projects/diffs/diffs", diffs: @diffs, project: @project
- else
.light-well
......
.row
.col-md-8
= render 'projects/commits/diff_stats', diffs: diffs
= render 'projects/diffs/stats', diffs: diffs
.col-md-4
%ul.nav.nav-tabs
%li.pull-right{class: params[:view] == 'parallel' ? 'active' : ''}
......@@ -11,16 +11,17 @@
- params_copy[:view] = 'inline'
= link_to "Inline Diff", url_for(params_copy), {id: "commit-diff-viewtype"}
- if show_diff_size_warninig?(diffs)
= render 'projects/commits/diff_warning', diffs: diffs
- if show_diff_size_warning?(diffs)
= render 'projects/diffs/warning', diffs: diffs
.files
- safe_diff_files(diffs).each_with_index do |diff, i|
= render 'projects/commits/diff_file', diff: diff, i: i, project: project
- safe_diff_files(diffs).each_with_index do |diff_file, index|
= render 'projects/diffs/file', diff_file: diff_file, i: index, project: project
- if @diff_timeout
.alert.alert-danger
%h4
Failed to collect changes
%p
Maybe diff is really big and operation failed with timeout. Try to get diff localy
Maybe diff is really big and operation failed with timeout. Try to get diff locally
- file = project.repository.blob_for_diff(@commit, diff)
- return unless file
- blob_diff_path = diff_project_blob_path(project,
tree_join(@commit.id, diff.new_path))
- blob = project.repository.blob_for_diff(@commit, diff_file.diff)
- return unless blob
- blob_diff_path = diff_project_blob_path(project, tree_join(@commit.id, diff_file.file_path))
.diff-file{id: "diff-#{i}", data: {blob_diff_path: blob_diff_path }}
.diff-header{id: "file-path-#{hexdigest(diff.new_path || diff.old_path)}"}
- if diff.deleted_file
%span= diff.old_path
.diff-header{id: "file-path-#{hexdigest(diff_file.new_path || diff_file.old_path)}"}
- if diff_file.deleted_file
%span= diff_file.old_path
.diff-btn-group
- if @commit.parent_ids.present?
= view_file_btn(@commit.parent_id, diff, project)
= view_file_btn(@commit.parent_id, diff_file, project)
- else
%span= diff.new_path
- if diff_file_mode_changed?(diff)
%span= diff_file.new_path
- if diff_file.mode_changed?
%span.file-mode= "#{diff.a_mode}#{diff.b_mode}"
.diff-btn-group
%label
= check_box_tag nil, 1, false, class: "js-toggle-diff-line-wrap"
Wrap text
- unless params[:view] == 'parallel'
%label
= check_box_tag nil, 1, false, class: "js-toggle-diff-line-wrap"
Wrap text
&nbsp;
= link_to "#", class: "js-toggle-diff-comments btn btn-small" do
%i.icon-chevron-down
......@@ -26,23 +26,23 @@
&nbsp;
- if @merge_request && @merge_request.source_project
= link_to project_edit_tree_path(@merge_request.source_project, tree_join(@merge_request.source_branch, diff.new_path), from_merge_request_id: @merge_request.id), { class: 'btn btn-small' } do
= link_to project_edit_tree_path(@merge_request.source_project, tree_join(@merge_request.source_branch, diff_file.new_path), from_merge_request_id: @merge_request.id), { class: 'btn btn-small' } do
Edit
&nbsp;
= view_file_btn(@commit.id, diff, project)
= view_file_btn(@commit.id, diff_file, project)
.diff-content
-# Skipp all non non-supported blobs
- return unless file.respond_to?('text?')
- if file.text?
- return unless blob.respond_to?('text?')
- if blob.text?
- if params[:view] == 'parallel'
= render "projects/commits/parallel_view", diff: diff, project: project, file: file, index: i
= render "projects/diffs/parallel_view", diff_file: diff_file, project: project, blob: blob, index: i
- else
= render "projects/commits/text_file", diff: diff, index: i
- elsif file.image?
- old_file = project.repository.prev_blob_for_diff(@commit, diff)
= render "projects/commits/image", diff: diff, old_file: old_file, file: file, index: i
= render "projects/diffs/text_file", diff_file: diff_file, index: i
- elsif blob.image?
- old_file = project.repository.prev_blob_for_diff(@commit, diff_file)
= render "projects/diffs/image", diff_file: diff_file, old_file: old_file, file: blob, index: i
- else
.nothing-here-block No preview for this file type
- diff = diff_file.diff
- if diff.renamed_file || diff.new_file || diff.deleted_file
.image
%span.wrap
......
%td.old_line
%td.line_content.parallel.matched= line
%td.new_line
%td.line_content.parallel.matched= line
/ Side-by-side diff view
%div.text-file.diff-wrap-lines
%table
- parallel_diff(diff_file, index).each do |line|
- type_left = line[0]
- line_number_left = line[1]
- line_content_left = line[2]
- line_code = line[3]
- type_right = line[4]
- line_number_right = line[5]
- line_content_right = line[6]
%tr.line_holder.parallel{id: line_code}
- if type_left == 'match'
= render "projects/diffs/match_line_parallel", { line: line_content_left,
line_old: line_number_left, line_new: line_number_right }
- elsif type_left == 'old' || type_left.nil?
%td.old_line{class: "#{type_left}"}
= link_to raw(line_number_left), "##{line_code}", id: line_code
%td.line_content{class: "parallel noteable_line #{type_left} #{line_code}", "line_code" => line_code }= raw line_content_left
%td.new_line{ class: "#{type_right == 'new' ? 'new' : nil}", data: { linenumber: line_number_right }}
= link_to raw(line_number_right), "##{line_code}", id: line_code
%td.line_content.parallel{class: "noteable_line #{type_right == 'new' ? 'new' : nil} #{line_code}", "line_code" => line_code}= raw line_content_right
- if diff_file.diff.diff.blank? && diff_file.mode_changed?
.file-mode-changed
File mode changed
- too_big = diff.diff.lines.count > Commit::DIFF_SAFE_LINES
- too_big = diff_file.diff_lines.count > Commit::DIFF_SAFE_LINES
- if too_big
%a.supp_diff_link Changes suppressed. Click to show
%table.text-file{class: "#{'hide' if too_big}"}
- last_line = 0
- each_diff_line(diff, index) do |line, type, line_code, line_new, line_old, raw_line|
- last_line = line_new
- diff_file.diff_lines.each_with_index do |line, index|
- type = line.type
- last_line = line.new_pos
- line_code = generate_line_code(diff_file.file_path, line)
- line_old = line.old_pos
%tr.line_holder{ id: line_code, class: "#{type}" }
- if type == "match"
= render "projects/commits/diffs/match_line", {line: line,
line_old: line_old, line_new: line_new, bottom: false}
= render "projects/diffs/match_line", {line: line.text,
line_old: line_old, line_new: line.new_pos, bottom: false}
- else
%td.old_line
= link_to raw(type == "new" ? "&nbsp;" : line_old), "##{line_code}", id: line_code
- if @comments_allowed
= link_to_new_diff_note(line_code)
%td.new_line{data: {linenumber: line_new}}
= link_to raw(type == "old" ? "&nbsp;" : line_new) , "##{line_code}", id: line_code
%td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw diff_line_content(line)
%td.new_line{data: {linenumber: line.new_pos}}
= link_to raw(type == "old" ? "&nbsp;" : line.new_pos) , "##{line_code}", id: line_code
%td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw diff_line_content(line.text)
- if @reply_allowed
- comments = @line_notes.select { |n| n.line_code == line_code }.sort_by(&:created_at)
- unless comments.empty?
= render "projects/notes/diff_notes_with_reply", notes: comments, line: line
= render "projects/notes/diff_notes_with_reply", notes: comments, line: line.text
- if last_line > 0
= render "projects/commits/diffs/match_line", {line: "",
= render "projects/diffs/match_line", {line: "",
line_old: last_line, line_new: last_line, bottom: true}
- if diff.diff.blank? && diff_file_mode_changed?(diff)
- if diff_file.diff.blank? && diff_file.mode_changed?
.file-mode-changed
File mode changed
......@@ -14,6 +14,6 @@
= link_to "Email patch", project_merge_request_path(@project, @merge_request, format: :patch), class: "btn btn-warning btn-small"
%p
To preserve performance only
%strong #{safe_diff_files(diffs).size} of #{diffs.size}
%strong #{allowed_diff_size} of #{diffs.size}
files displayed.
%table.text-file
- each_diff_line(diff, 1) do |line, type, line_code, line_new, line_old, raw_line|
%tr.line_holder{ id: line_code, class: "#{type}" }
- if type == "match"
%td.old_line= "..."
%td.new_line= "..."
%td.line_content.matched= line
- else
%td.old_line
= link_to raw(type == "new" ? "&nbsp;" : line_old), "##{line_code}", id: line_code
%td.new_line= link_to raw(type == "old" ? "&nbsp;" : line_new) , "##{line_code}", id: line_code
%td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw diff_line_content(line)
......@@ -9,18 +9,17 @@
= raw render_markup(@blob.name, @content)
- else
.file-content.code
- unless @diff.empty?
- unless @diff_lines.empty?
%table.text-file
- @diff.each do |line, type, line_code, line_new, line_old, raw_line|
%tr.line_holder{ id: line_code, class: "#{type}" }
- if type == "match"
- @diff_lines.each do |line|
%tr.line_holder{ class: "#{line.type}" }
- if line.type == "match"
%td.old_line= "..."
%td.new_line= "..."
%td.line_content.matched= line
%td.line_content.matched= line.text
- else
%td.old_line
= link_to raw(type == "new" ? "&nbsp;" : line_old), "##{line_code}", id: line_code
%td.new_line= link_to raw(type == "old" ? "&nbsp;" : line_new) , "##{line_code}", id: line_code
%td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw diff_line_content(line)
%td.new_line
%td.line_content{class: "#{line.type}"}= raw diff_line_content(line.text)
- else
.nothing-here-block No changes.
......@@ -23,7 +23,7 @@
.col-sm-10
= f.text_field :import_url, class: 'form-control', placeholder: 'https://github.com/randx/six.git'
.bs-callout.bs-callout-info
This url must be publicly accessible or you can add a username and password like this: https://username:password@gitlab.com/company/project.git.
This URL must be publicly accessible or you can add a username and password like this: https://username:password@gitlab.com/company/project.git.
%br
The import will time out after 4 minutes. For big repositories, use a clone/push combination.
.form-actions
......
......@@ -16,37 +16,7 @@
- @issue.errors.full_messages.each do |msg|
%span= msg
%br
.form-group
= f.label :title, class: 'control-label' do
%strong= 'Title *'
.col-sm-10
= f.text_field :title, maxlength: 255, class: "form-control js-gfm-input", autofocus: true, required: true
.form-group
= f.label :description, 'Description', class: 'control-label'
.col-sm-10
= f.text_area :description, class: 'form-control js-gfm-input markdown-area', rows: 14
.col-sm-12.hint
.pull-left Issues are parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'}.
.pull-right Attach images (JPG, PNG, GIF) by dragging &amp; dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }.
.clearfix
.error-alert
%hr
.form-group
.issue-assignee
= f.label :assignee_id, class: 'control-label' do
%i.icon-user
Assign to
.col-sm-10
= project_users_select_tag('issue[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control', selected: @issue.assignee_id)
&nbsp;
= link_to 'Assign to me', '#', class: 'btn assign-to-me-link'
.form-group
.issue-milestone
= f.label :milestone_id, class: 'control-label' do
%i.icon-time
Milestone
.col-sm-10= f.select(:milestone_id, milestone_options(@issue), { include_blank: "Select milestone" }, {class: 'select2'})
= render 'projects/issuable_form', f: f, issuable: @issue
.form-group
= f.label :label_ids, class: 'control-label' do
%i.icon-tag
......
......@@ -24,7 +24,7 @@
%i.icon.icon-list
= form_tag project_issues_path(@project), method: :get, id: "issue_search_form", class: 'pull-left issue-search-form' do
.append-right-10.hidden-xs.hidden-sm
= search_field_tag :issue_search, nil, { placeholder: 'Filter by title or description', class: 'form-control issue_search search-text-input input-mn-300' }
= search_field_tag :issue_search, params[:issue_search], { placeholder: 'Filter by title or description', class: 'form-control issue_search search-text-input input-mn-300' }
= hidden_field_tag :state, params['state']
= hidden_field_tag :scope, params['scope']
= hidden_field_tag :assignee_id, params['assignee_id']
......
- if @project.labels.size == 0
$('.labels').load(document.URL + ' .light-well').hide().fadeIn(1000)
......@@ -7,11 +7,11 @@
Labels
%hr
- if @labels.present?
%ul.bordered-list.manage-labels-list
= render @labels
= paginate @labels, theme: 'gitlab'
- else
.light-well
.nothing-here-block Create first label or #{link_to 'generate', generate_project_labels_path(@project), method: :post} default set of labels
.labels
- if @labels.present?
%ul.bordered-list.manage-labels-list
= render @labels
= paginate @labels, theme: 'gitlab'
- else
.light-well
.nothing-here-block Create first label or #{link_to 'generate', generate_project_labels_path(@project), method: :post} default set of labels
......@@ -15,37 +15,7 @@
%div= msg
.merge-request-form-info
.form-group
= f.label :title, class: 'control-label' do
%strong= "Title *"
.col-sm-10= f.text_field :title, class: "form-control pad js-gfm-input", maxlength: 255, rows: 5, required: true
.form-group
= f.label :description, "Description", class: 'control-label'
.col-sm-10
= f.text_area :description, class: "form-control js-gfm-input markdown-area", rows: 14
.col-sm-12.hint
.pull-left Description is parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'}.
.pull-right Attach images (JPG, PNG, GIF) by dragging &amp; dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }.
.clearfix
.error-alert
%hr
.form-group
.issue-assignee
= f.label :assignee_id, class: 'control-label' do
%i.icon-user
Assign to
.col-sm-10
= project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control', selected: @merge_request.assignee_id)
&nbsp;
= link_to 'Assign to me', '#', class: 'btn assign-to-me-link'
.form-group
.issue-milestone
= f.label :milestone_id, class: 'control-label' do
%i.icon-time
Milestone
.col-sm-10= f.select(:milestone_id, milestone_options(@merge_request), { include_blank: "Select milestone" }, {class: 'select2'})
= render 'projects/issuable_form', f: f, issuable: @merge_request
.form-group
= f.label :label_ids, class: 'control-label' do
%i.icon-tag
......
......@@ -75,7 +75,7 @@
%h4 Changes
- if @diffs.present?
= render "projects/commits/diffs", diffs: @diffs, project: @project
= render "projects/diffs/diffs", diffs: @diffs, project: @project
- elsif @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
.bs-callout.bs-callout-danger
%h4 This comparison includes more than #{MergeRequestDiff::COMMITS_SAFE_SIZE} commits.
......
- if @merge_request_diff.collected?
= render "projects/commits/diffs", diffs: @merge_request.diffs, project: @merge_request.source_project
= render "projects/diffs/diffs", diffs: @merge_request.diffs, project: @merge_request.source_project
- elsif @merge_request_diff.empty?
.nothing-here-block Nothing to merge from #{@merge_request.source_branch} into #{@merge_request.target_branch}
- else
......
......@@ -48,9 +48,9 @@
.col-sm-10
= f.text_field :import_url, class: 'form-control', placeholder: 'https://github.com/randx/six.git'
.bs-callout.bs-callout-info
This url must be publicly accessible or you can add a username and password like this: https://username:password@gitlab.com/company/project.git.
This URL must be publicly accessible or you can add a username and password like this: https://username:password@gitlab.com/company/project.git.
%br
The import will time out after 2 minutes. For big repositories, use a clone/push combination.
The import will time out after 4 minutes. For big repositories, use a clone/push combination.
%hr
.form-group
......
- note = @project.notes.new(@comments_target.merge({ line_code: line_code }))
= link_to "",
"javascript:;",
class: "add-diff-note js-add-diff-note-button",
data: { noteable_type: note.noteable_type,
noteable_id: note.noteable_id,
commit_id: note.commit_id,
line_code: note.line_code,
discussion_id: note.discussion_id },
title: "Add a comment to this line"
......@@ -11,16 +11,17 @@
%br/
.diff-content
%table
- each_diff_line_near(diff, note.diff_file_index, note.line_code) do |line, type, line_code, line_new, line_old|
- note.truncated_diff_lines.each do |line|
- line_code = generate_line_code(note.file_path, line)
%tr.line_holder{ id: line_code }
- if type == "match"
- if line.type == "match"
%td.old_line= "..."
%td.new_line= "..."
%td.line_content.matched= line
%td.line_content.matched= line.text
- else
%td.old_line= raw(type == "new" ? "&nbsp;" : line_old)
%td.new_line= raw(type == "old" ? "&nbsp;" : line_new)
%td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw "#{line} &nbsp;"
%td.old_line= raw(line.type == "new" ? "&nbsp;" : line.old_pos)
%td.new_line= raw(line.type == "old" ? "&nbsp;" : line.new_pos)
%td.line_content{class: "noteable_line #{line.type} #{line_code}", "line_code" => line_code}= raw "#{line.text} &nbsp;"
- if line_code == note.line_code
= render "projects/notes/diff_notes_with_reply", notes: discussion_notes
- if @error
.alert.alert-danger
%button{ type: "button", class: "close", "data-dismiss" => "alert"} &times;
= @error
%h3.page-title
%i.icon-code-fork
New tag
......@@ -5,12 +9,17 @@
.form-group
= label_tag :tag_name, 'Name for new tag', class: 'control-label'
.col-sm-10
= text_field_tag :tag_name, nil, placeholder: 'v3.0.1', required: true, tabindex: 1, class: 'form-control'
= text_field_tag :tag_name, params[:tag_name], placeholder: 'v3.0.1', required: true, tabindex: 1, class: 'form-control'
.form-group
= label_tag :ref, 'Create from', class: 'control-label'
.col-sm-10
= text_field_tag :ref, nil, placeholder: 'master', required: true, tabindex: 2, class: 'form-control'
= text_field_tag :ref, params[:ref], placeholder: 'master', required: true, tabindex: 2, class: 'form-control'
.light Branch name or commit SHA
.form-group
= label_tag :message, 'Message', class: 'control-label'
.col-sm-10
= text_field_tag :message, nil, placeholder: 'Enter message.', required: false, tabindex: 3, class: 'form-control'
.light (Optional) Entering a message will create an annotated tag.
.form-actions
= submit_tag 'Create tag', class: 'btn btn-create', tabindex: 3
= link_to 'Cancel', project_tags_path(@project), class: 'btn btn-cancel'
......
......@@ -23,3 +23,9 @@
Comments
.pull-right
= @search_results.notes_count
%li{class: ("active" if @scope == 'wiki_blobs')}
= link_to search_filter_path(scope: 'wiki_blobs') do
Wiki
.pull-right
= @search_results.wiki_blobs_count
%h4
#{@search_results.total_count} results found
- if @project
for #{link_to @project.name_with_namespace, @project}
- elsif @group
for #{link_to @group.name, @group}
- unless @show_snippets
- if @project
for #{link_to @project.name_with_namespace, @project}
- elsif @group
for #{link_to @group.name, @group}
%hr
......@@ -11,6 +12,8 @@
.col-sm-3
- if @project
= render "project_filter"
- elsif @show_snippets
= render 'snippet_filter'
- else
= render "global_filter"
.col-sm-9
......
%ul.nav.nav-pills.nav-stacked.search-filter
%li{class: ("active" if @scope == 'snippet_blobs')}
= link_to search_filter_path(scope: 'snippet_blobs', snippets: true, group_id: nil, project_id: nil) do
%i.icon-code
Snippet Contents
.pull-right
= @search_results.snippet_blobs_count
%li{class: ("active" if @scope == 'snippet_titles')}
= link_to search_filter_path(scope: 'snippet_titles', snippets: true, group_id: nil, project_id: nil) do
%i.icon-book
Titles and Filenames
.pull-right
= @search_results.snippet_titles_count
.search-result-row
%span
= snippet_blob[:snippet_object].title
by
= link_to user_snippets_path(snippet_blob[:snippet_object].author) do
= image_tag avatar_icon(snippet_blob[:snippet_object].author_email), class: "avatar avatar-inline s16", alt: ''
= snippet_blob[:snippet_object].author_name
%span.light #{time_ago_with_tooltip(snippet_blob[:snippet_object].created_at)}
%h4.snippet-title
- snippet_path = reliable_snippet_path(snippet_blob[:snippet_object])
= link_to snippet_path do
.file-holder
.file-title
%i.icon-file
%strong= snippet_blob[:snippet_object].file_name
%span.options
.btn-group.tree-btn-group.pull-right
- if snippet_blob[:snippet_object].author == current_user
= link_to "Edit", edit_snippet_path(snippet_blob[:snippet_object]), class: "btn btn-tiny", title: 'Edit Snippet'
= link_to "Delete", snippet_path(snippet_blob[:snippet_object]), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-tiny", title: 'Delete Snippet'
= link_to "Raw", raw_snippet_path(snippet_blob[:snippet_object]), class: "btn btn-tiny", target: "_blank"
- if gitlab_markdown?(snippet_blob[:snippet_object].file_name)
.file-content.wiki
- snippet_blob[:snippet_chunks].each do |snippet|
- unless snippet[:data].empty?
= preserve do
= markdown(snippet[:data])
- else
.file-content.code
.nothing-here-block Empty file
- elsif markup?(snippet_blob[:snippet_object].file_name)
.file-content.wiki
- snippet_blob[:snippet_chunks].each do |snippet|
- unless snippet[:data].empty?
= render_markup(snippet_blob[:snippet_object].file_name, snippet[:data])
- else
.file-content.code
.nothing-here-block Empty file
- else
.file-content.code
%div.highlighted-data{class: user_color_scheme_class}
.line-numbers
- snippet_blob[:snippet_chunks].each do |snippet|
- unless snippet[:data].empty?
- snippet[:data].lines.to_a.size.times do |index|
- offset = defined?(snippet[:start_line]) ? snippet[:start_line] : 1
- i = index + offset
= link_to snippet_path+"#L#{i}", id: "L#{i}", rel: "#L#{i}" do
%i.icon-link
= i
- unless snippet == snippet_blob[:snippet_chunks].last
%a
= "."
.highlight.term
%pre
%code
- snippet_blob[:snippet_chunks].each do |snippet|
- unless snippet[:data].empty?
= snippet[:data]
- unless snippet == snippet_blob[:snippet_chunks].last
%a
= "..."
- else
.file-content.code
.nothing-here-block Empty file
.search-result-row
%h4.snippet-title.term
= link_to reliable_snippet_path(snippet_title) do
= truncate(snippet_title.title, length: 60)
- if snippet_title.private?
%span.label.label-gray
%i.icon-lock
private
%span.cgray.monospace.tiny.pull-right.term
= snippet_title.file_name
%small.pull-right.cgray
- if snippet_title.project_id?
= link_to snippet_title.project.name_with_namespace, project_path(snippet_title.project)
.snippet-info
= "##{snippet_title.id}"
%span
by
= link_to user_snippets_path(snippet_title.author) do
= image_tag avatar_icon(snippet_title.author_email), class: "avatar avatar-inline s16", alt: ''
= snippet_title.author_name
%span.light #{time_ago_with_tooltip(snippet_title.created_at)}
.blob-result
.file-holder
.file-title
= link_to project_wiki_path(@project, wiki_blob.filename) do
%i.icon-file
%strong
= wiki_blob.filename
.file-content.code.term
= render 'shared/file_hljs', blob: wiki_blob, first_line_number: wiki_blob.startline
......@@ -9,10 +9,12 @@
= submit_tag 'Search', class: "btn btn-create"
.form-group
.col-sm-2
.col-sm-10
= render 'filter', f: f
- unless params[:snippets].eql? 'true'
.col-sm-10
= render 'filter', f: f
= hidden_field_tag :project_id, params[:project_id]
= hidden_field_tag :group_id, params[:group_id]
= hidden_field_tag :snippets, params[:snippets]
= hidden_field_tag :scope, params[:scope]
.results.prepend-top-10
......
#!/usr/bin/env bash
#!/bin/sh
cd $(dirname $0)/..
app_root=$(pwd)
......@@ -6,22 +6,22 @@ sidekiq_pidfile="$app_root/tmp/pids/sidekiq.pid"
sidekiq_logfile="$app_root/log/sidekiq.log"
gitlab_user=$(ls -l config.ru | awk '{print $3}')
function warn
warn()
{
echo "$@" 1>&2
}
function stop
stop()
{
bundle exec sidekiqctl stop $sidekiq_pidfile >> $sidekiq_logfile 2>&1
}
function killall
killall()
{
pkill -u $gitlab_user -f 'sidekiq [0-9]'
}
function restart
restart()
{
if [ -f $sidekiq_pidfile ]; then
stop
......@@ -30,20 +30,20 @@ function restart
start_sidekiq -d -L $sidekiq_logfile
}
function start_no_deamonize
start_no_deamonize()
{
start_sidekiq
}
function start_sidekiq
start_sidekiq()
{
bundle exec sidekiq -q post_receive -q mailer -q system_hook -q project_web_hook -q gitlab_shell -q common -q default -e $RAILS_ENV -P $sidekiq_pidfile $@ >> $sidekiq_logfile 2>&1
}
function load_ok
load_ok()
{
sidekiq_pid=$(cat $sidekiq_pidfile)
if [[ -z $sidekiq_pid ]] ; then
if [ -z "$sidekiq_pid" ] ; then
warn "Could not find a PID in $sidekiq_pidfile"
exit 0
fi
......
#!/usr/bin/env bash
#!/bin/sh
cd $(dirname $0)/..
app_root=$(pwd)
......@@ -6,28 +6,28 @@ app_root=$(pwd)
unicorn_pidfile="$app_root/tmp/pids/unicorn.pid"
unicorn_config="$app_root/config/unicorn.rb"
function get_unicorn_pid
get_unicorn_pid()
{
local pid=$(cat $unicorn_pidfile)
if [ -z $pid ] ; then
if [ -z "$pid" ] ; then
echo "Could not find a PID in $unicorn_pidfile"
exit 1
fi
unicorn_pid=$pid
}
function start
start()
{
bundle exec unicorn_rails -D -c $unicorn_config -E $RAILS_ENV
}
function stop
stop()
{
get_unicorn_pid
kill -QUIT $unicorn_pid
}
function reload
reload()
{
get_unicorn_pid
kill -USR2 $unicorn_pid
......
......@@ -3,9 +3,11 @@
# # # # # # # # # # # # # # # # # #
#
# How to use:
# 1. copy file as gitlab.yml
# 2. Replace gitlab -> host with your domain
# 3. Replace gitlab -> email_from
# 1. Copy file as gitlab.yml
# 2. Update gitlab -> host with your fully qualified domain name
# 3. Update gitlab -> email_from
# 4. If you installed Git from source, change git -> bin_path to /usr/local/bin/git
# 5. Review this configuration file for other settings you may want to adjust
production: &base
#
......@@ -16,8 +18,8 @@ production: &base
gitlab:
## Web server settings (note: host is the FQDN, do not include http://)
host: localhost
port: 80
https: false
port: 80 # Set to 443 if using HTTPS, see installation.md#using-https for additional HTTPS configuration details
https: false # Set to true if using HTTPS, see installation.md#using-https for additional HTTPS configuration details
# Uncommment this line below if your ssh host is different from HTTP/HTTPS one
# (you'd obviously need to replace ssh.host_example.com with your own host).
......
......@@ -4,10 +4,10 @@ Sidekiq::Testing.inline! do
Gitlab::Seeder.quiet do
project_urls = [
'https://github.com/documentcloud/underscore.git',
'https://github.com/gitlabhq/gitlabhq.git',
'https://github.com/gitlabhq/gitlab-ci.git',
'https://github.com/gitlabhq/gitlab-shell.git',
'https://github.com/gitlabhq/testme.git',
'https://gitlab.com/gitlab-org/gitlab-ce.git',
'https://gitlab.com/gitlab-org/gitlab-ci.git',
'https://gitlab.com/gitlab-org/gitlab-shell.git',
'https://gitlab.com/gitlab-org/testme.git',
'https://github.com/twitter/flight.git',
'https://github.com/twitter/typeahead.js.git',
'https://github.com/h5bp/html5-boilerplate.git',
......
password = if ENV['GITLAB_ROOT_PASSWORD'].nil? || ENV['GITLAB_ROOT_PASSWORD'].empty?
"5iveL!fe"
else
ENV['GITLAB_ROOT_PASSWORD']
end
admin = User.create(
email: "admin@example.com",
name: "Administrator",
username: 'root',
password: "5iveL!fe",
password_confirmation: "5iveL!fe",
password: password,
password_confirmation: password,
password_expires_at: Time.now,
theme_id: Gitlab::Theme::MARS
......@@ -19,6 +25,6 @@ puts %q[
Administrator account created:
login.........root
password......5iveL!fe
password......#{password}
]
end
class MigrateToNewShell < ActiveRecord::Migration
def change
gitlab_shell_path = Gitlab.config.gitlab_shell.path
if system("#{gitlab_shell_path}/bin/create-hooks")
puts 'Repositories updated with new hooks'
else
raise 'Failed to rewrite gitlab-shell hooks in repositories'
end
end
end
class SerializeServiceProperties < ActiveRecord::Migration
def change
add_column :services, :properties, :text
associations =
{
AssemblaService: [:token, :subdomain],
CampfireService: [:token, :subdomain, :room],
EmailsOnPushService: [:recipients],
FlowdockService: [:token],
GemnasiumService: [:api_key, :token],
GitlabCiService: [:token, :project_url],
HipchatService: [:token, :room],
PivotaltrackerService: [:token],
SlackService: [:subdomain, :token, :room],
JenkinsService: [:token, :subdomain],
JiraService: [:project_url, :username, :password,
:api_version, :jira_issue_transition_id],
}
Service.all.each do |service|
associations[service.type.to_sym].each do |attribute|
service.send("#{attribute}=", service.attributes[attribute.to_s])
end
service.save!
end
remove_column :services, :project_url, :string
remove_column :services, :subdomain, :string
remove_column :services, :room, :string
remove_column :services, :recipients, :text
remove_column :services, :api_key, :string
remove_column :services, :token, :string
end
end
......@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20140730111702) do
ActiveRecord::Schema.define(version: 20140907220153) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......@@ -265,16 +265,11 @@ ActiveRecord::Schema.define(version: 20140730111702) do
create_table "services", force: true do |t|
t.string "type"
t.string "title"
t.string "token"
t.integer "project_id", null: false
t.integer "project_id", null: false
t.datetime "created_at"
t.datetime "updated_at"
t.boolean "active", default: false, null: false
t.string "project_url"
t.string "subdomain"
t.string "room"
t.text "recipients"
t.string "api_key"
t.boolean "active", default: false, null: false
t.text "properties"
end
add_index "services", ["project_id"], name: "index_services_on_project_id", using: :btree
......
......@@ -196,6 +196,8 @@ Parameters:
}
```
It return 200 if succeed or 400 if failed with error message explaining reason.
## Delete repository branch
```
......@@ -207,4 +209,5 @@ Parameters:
- `id` (required) - The ID of a project
- `branch` (required) - The name of the branch
It return 200 if succeed or 405 if failed with error message explaining reason.
It return 200 if succeed, 404 if the branch to be deleted does not exist
or 400 for other reasons. In case of an error, an explaining message is provided.
......@@ -9,11 +9,15 @@ Get all issues created by authenticated user. This function takes pagination par
GET /issues
GET /issues?state=opened
GET /issues?state=closed
GET /issues?labels=foo
GET /issues?labels=foo,bar
GET /issues?labels=foo,bar&state=opened
```
Parameters:
- `state` (optional) - Return `all` issues or just those that are `opened` or `closed`
- `labels` (optional) - Comma-separated list of label names
```json
[
......@@ -88,12 +92,16 @@ to return the list of project issues.
GET /projects/:id/issues
GET /projects/:id/issues?state=opened
GET /projects/:id/issues?state=closed
GET /projects/:id/issues?labels=foo
GET /projects/:id/issues?labels=foo,bar
GET /projects/:id/issues?labels=foo,bar&state=opened
```
Parameters:
- `id` (required) - The ID of a project
- `state` (optional) - Return `all` issues or just those that are `opened` or `closed`
- `labels` (optional) - Comma-separated list of label names
## Single issue
......
......@@ -248,6 +248,7 @@ POST /projects
Parameters:
- `name` (required) - new project name
- `path` (optional) - custom repository name for new project. By default generated based on name
- `namespace_id` (optional) - namespace for the new project (defaults to user)
- `description` (optional) - short project description
- `issues_enabled` (optional)
......
......@@ -50,6 +50,7 @@ Parameters:
- `id` (required) - The ID of a project
- `tag_name` (required) - The name of a tag
- `ref` (required) - Create tag using commit SHA, another tag name, or branch name.
- `message` (optional) - Creates annotated tag.
```json
[
......@@ -71,6 +72,9 @@ Parameters:
]
```
It returns 200 if the operation succeed. In case of an error,
405 with an explaining error message is returned.
## List repository tree
Get a list of repository files and directories in a project.
......
# Database Mysql
# Database MySQL
## Note
......@@ -12,16 +12,16 @@ We do not recommend using MySQL due to various issues. For example, case [(in)se
# 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
# Pick a MySQL root password (can be anything), type it and press enter
# Retype the MySQL root password and press enter
# Secure your installation.
# Secure your installation
sudo mysql_secure_installation
# Login to MySQL
mysql -u root -p
# Type the database root password
# Type the MySQL root password
# Create a user for GitLab
# do not type the 'mysql>', this is part of the prompt
......
......@@ -76,7 +76,7 @@ Is the system packaged Git too old? Remove it and compile from source.
# Install into /usr/local/bin
sudo make prefix=/usr/local install
# When editing config/gitlab.yml (Step 5), change the git bin_path to /usr/local/bin/git
# When editing config/gitlab.yml (Step 5), change the git -> bin_path to /usr/local/bin/git
**Note:** In order to receive mail notifications, make sure to install a mail server. By default, Debian is shipped with exim4 but this [has problems](https://github.com/gitlabhq/gitlabhq/issues/4866#issuecomment-32726573) while Ubuntu does not ship with one. The recommended mail server is postfix and you can install it with:
......@@ -153,12 +153,7 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
# Copy the example GitLab config
sudo -u git -H cp config/gitlab.yml.example config/gitlab.yml
# Make sure to change "localhost" to the fully-qualified domain name of your
# host serving GitLab where necessary
#
# If you want to use https make sure that you set `https` to `true`. See #using-https for all necessary details.
#
# If you installed Git from source, change the git bin_path to /usr/local/bin/git
# Update GitLab config file, follow the directions at top of file
sudo -u git -H editor config/gitlab.yml
# Make sure GitLab can write to the log/ and tmp/ directories
......@@ -196,6 +191,8 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
**Important Note:** Make sure to edit both `gitlab.yml` and `unicorn.rb` to match your setup.
**Note:** If you want to use HTTPS, see [Using HTTPS](#using-https) for the additional steps.
### Configure GitLab DB Settings
# PostgreSQL only:
......@@ -233,17 +230,12 @@ GitLab Shell is an SSH access and repository management software developed speci
# Run the installation task for gitlab-shell (replace `REDIS_URL` if needed):
sudo -u git -H bundle exec rake gitlab:shell:install[v1.9.7] REDIS_URL=redis://localhost:6379 RAILS_ENV=production
# By default, the gitlab-shell config is generated from your main gitlab config.
#
# Note: When using GitLab with HTTPS please change the following:
# - Provide paths to the certificates under `ca_file` and `ca_path` options.
# - The `gitlab_url` option must point to the https endpoint of GitLab.
# - In case you are using self signed certificate set `self_signed_cert` to `true`.
# See #using-https for all necessary details.
#
# By default, the gitlab-shell config is generated from your main GitLab config.
# You can review (and modify) the gitlab-shell config as follows:
sudo -u git -H editor /home/git/gitlab-shell/config.yml
**Note:** If you want to use HTTPS, see [Using HTTPS](#using-https) for the additional steps.
### Initialize Database and Activate Advanced Features
sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production
......@@ -252,6 +244,10 @@ GitLab Shell is an SSH access and repository management software developed speci
# When done you see 'Administrator account created:'
**Note:** You can set the Administrator password by supplying it in environmental variable `GITLAB_ROOT_PASSWORD`, eg.:
sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production GITLAB_ROOT_PASSWORD=newpassword
### Install Init Script
Download the init script (will be `/etc/init.d/gitlab`):
......@@ -309,14 +305,14 @@ Make sure to edit the config file to match your setup:
# domain name of your host serving GitLab.
sudo editor /etc/nginx/sites-available/gitlab
**Note:** If you want to use HTTPS, replace the `gitlab` Nginx config with `gitlab-ssl`. See [Using HTTPS](#using-https) for all necessary details.
**Note:** If you want to use HTTPS, replace the `gitlab` Nginx config with `gitlab-ssl`. See [Using HTTPS](#using-https) for HTTPS configuration details.
### Test Configuration
Validate your `gitlab` or `gitlab-ssl` Nginx config file with the following command:
sudo nginx -t
You should receive `syntax is okay` and `test is successful` messages. If you receive errors check your `gitlab` or `gitlab-ssl` Nginx config file for typos, etc. as indiciated in the error message given.
### Restart
......@@ -350,11 +346,30 @@ Visit YOUR_SERVER in your web browser for your first GitLab login. The setup has
### Using HTTPS
To recapitulate what is needed to use GitLab with HTTPS:
To use GitLab with HTTPS:
1. In `gitlab.yml`:
1. Set the `port` option in section 1 to `443`.
1. Set the `https` option in section 1 to `true`.
1. In the `config.yml` of gitlab-shell:
1. Set `gitlab_url` option to the HTTPS endpoint of GitLab (e.g. `https://git.example.com`).
1. Set the certificates using either the `ca_file` or `ca_path` option.
1. Use the `gitlab-ssl` Nginx example config instead of the `gitlab` config.
1. Update `YOUR_SERVER_FQDN`.
1. Update `ssl_certificate` and `ssl_certificate_key`.
1. Review the configuration file and consider applying other security and performance enhancing features.
Using a self-signed certificate is discouraged but if you must use it follow the normal directions then:
1. In `gitlab.yml` set the `https` option to `true`
1. In the `config.yml` of gitlab-shell set the relevant options (see the [install GitLab Shell section](#install-gitlab-shell) of this document).
1. Use the `gitlab-ssl` nginx example config instead of the `gitlab` config.
1. Generate a self-signed SSL certificate:
```
mkdir -p /etc/nginx/ssl/
cd /etc/nginx/ssl/
sudo openssl req -newkey rsa:2048 -x509 -nodes -days 3560 -out gitlab.crt -keyout gitlab.key
sudo chmod o-r gitlab.key
```
1. In the `config.yml` of gitlab-shell set `self_signed_cert` to `true`.
### Additional Markup Styles
......@@ -390,38 +405,4 @@ You can configure LDAP authentication in `config/gitlab.yml`. Please restart Git
### Using Custom Omniauth Providers
GitLab uses [Omniauth](http://www.omniauth.org/) for authentication and already ships with a few providers preinstalled (e.g. LDAP, GitHub, Twitter). But sometimes that is not enough and you need to integrate with other authentication solutions. For these cases you can use the Omniauth provider.
#### Steps
These steps are fairly general and you will need to figure out the exact details from the Omniauth provider's documentation.
- Stop GitLab:
sudo service gitlab stop
- Add the gem to your [Gemfile](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/Gemfile):
gem "omniauth-your-auth-provider"
- If you're using MySQL, install the new Omniauth provider gem by running the following command:
sudo -u git -H bundle install --without development test postgres --path vendor/bundle --no-deployment
- If you're using PostgreSQL, install the new Omniauth provider gem by running the following command:
sudo -u git -H bundle install --without development test mysql --path vendor/bundle --no-deployment
> These are the same commands you used in the [Install Gems section](#install-gems) with `--path vendor/bundle --no-deployment` instead of `--deployment`.
- Start GitLab:
sudo service gitlab start
#### Examples
If you have successfully set up a provider that is not shipped with GitLab itself, please let us know.
You can help others by reporting successful configurations and probably share a few insights or provide warnings for common errors or pitfalls by sharing your experience [in the public Wiki](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Custom-omniauth-provider-configurations).
While we can't officially support every possible authentication mechanism out there, we'd like to at least help those with special needs.
See the [omniauth integration document](doc/integration/omniauth.md)
......@@ -7,9 +7,9 @@
- Ubuntu
- Debian
- CentOS
- RedHat Enterprise Linux
- Scientific Linux
- Oracle Linux
- RedHat Enterprise Linux (please use the CentOS packages and instructions)
- Scientific Linux (please use the CentOS packages and instructions)
- Oracle Linux (please use the CentOS packages and instructions)
For the installations options please see [the installation page on the GitLab website](https://about.gitlab.com/installation/).
......
......@@ -50,6 +50,13 @@ Before configuring individual OmniAuth providers there are a few global settings
# - { name: 'github', app_id: 'YOUR APP ID',
# app_secret: 'YOUR APP SECRET',
# args: { scope: 'user:email' } }
# - {"name": 'shibboleth',
# args: { shib_session_id_field: "HTTP_SHIB_SESSION_ID",
# shib_application_id_field: "HTTP_SHIB_APPLICATION_ID",
# uid_field: "HTTP_EPPN",
# name_field: "HTTP_CN",
# info_fields: {"email": "HTTP_MAIL" } } }
```
1. Change `enabled` to `true`.
......@@ -69,6 +76,7 @@ Before configuring individual OmniAuth providers there are a few global settings
- [GitHub](github.md)
- [Google](google.md)
- [Shibboleth](shibboleth.md)
- [Twitter](twitter.md)
## Enable OmniAuth for an Existing User
......@@ -82,3 +90,41 @@ Existing users can enable OmniAuth for specific providers after the account is c
1. The user will be redirected to the provider. Once the user authorized GitLab they will be redirected back to GitLab.
The chosen OmniAuth provider is now active and can be used to sign in to GitLab from then on.
## Using Custom Omniauth Providers
GitLab uses [Omniauth](http://www.omniauth.org/) for authentication and already ships with a few providers preinstalled (e.g. LDAP, GitHub, Twitter). But sometimes that is not enough and you need to integrate with other authentication solutions. For these cases you can use the Omniauth provider.
### Steps
These steps are fairly general and you will need to figure out the exact details from the Omniauth provider's documentation.
- Stop GitLab:
sudo service gitlab stop
- Add the gem to your [Gemfile](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/Gemfile):
gem "omniauth-your-auth-provider"
- If you're using MySQL, install the new Omniauth provider gem by running the following command:
sudo -u git -H bundle install --without development test postgres --path vendor/bundle --no-deployment
- If you're using PostgreSQL, install the new Omniauth provider gem by running the following command:
sudo -u git -H bundle install --without development test mysql --path vendor/bundle --no-deployment
> These are the same commands you used in the [Install Gems section](#install-gems) with `--path vendor/bundle --no-deployment` instead of `--deployment`.
- Start GitLab:
sudo service gitlab start
### Examples
If you have successfully set up a provider that is not shipped with GitLab itself, please let us know.
You can help others by reporting successful configurations and probably share a few insights or provide warnings for common errors or pitfalls by sharing your experience [in the public Wiki](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Custom-omniauth-provider-configurations).
While we can't officially support every possible authentication mechanism out there, we'd like to at least help those with specific needs.
# Shibboleth OmniAuth Provider
This documentation is for enabling shibboleth with gitlab-omnibus package.
In order to enable Shibboleth support in gitlab we need to use Apache instead of Nginx (It may be possible to use Nginx, however I did not found way to easily configure nginx that is bundled in gitlab-omnibus package). Apache uses mod_shib2 module for shibboleth authentication and can pass attributes as headers to omniauth-shibboleth provider.
To enable the Shibboleth OmniAuth provider you must:
1. Configure Apache shibboleth module. Installation and configuration of module it self is out of scope of this document.
Check https://wiki.shibboleth.net/ for more info.
1. You can find Apache config in gitlab-reciepes (https://github.com/gitlabhq/gitlab-recipes/blob/master/web-server/apache/gitlab-ssl.conf)
Following changes are needed to enable shibboleth:
protect omniauth-shibboleth callback url:
```
<Location /users/auth/shibboleth/callback>
AuthType shibboleth
ShibRequestSetting requireSession 1
ShibUseHeaders On
require valid-user
</Location>
Alias /shibboleth-sp /usr/share/shibboleth
<Location /shibboleth-sp>
Satisfy any
</Location>
<Location /Shibboleth.sso>
SetHandler shib
</Location>
```
exclude shibboleth urls from rewriting, add "RewriteCond %{REQUEST_URI} !/Shibboleth.sso" and "RewriteCond %{REQUEST_URI} !/shibboleth-sp", config should look like this:
```
#apache equivalent of nginx try files
RewriteEngine on
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !/Shibboleth.sso
RewriteCond %{REQUEST_URI} !/shibboleth-sp
RewriteRule .* http://127.0.0.1:8080%{REQUEST_URI} [P,QSA]
RequestHeader set X_FORWARDED_PROTO 'https'
```
1. Edit /etc/gitlab/gitlab.rb configuration file, your shibboleth attributes should be in form of "HTTP_ATTRIBUTE" and you should addjust them to your need and environment. Add any other configuration you need.
File it should look like this:
```
external_url 'https://gitlab.example.com'
gitlab_rails['internal_api_url'] = 'https://gitlab.example.com'
# disable nginx
nginx['enable'] = false
gitlab_rails['omniauth_allow_single_sign_on'] = true
gitlab_rails['omniauth_block_auto_created_users'] = false
gitlab_rails['omniauth_enabled'] = true
gitlab_rails['omniauth_providers'] = [
{
"name" => 'shibboleth',
"args" => {
"shib_session_id_field" => "HTTP_SHIB_SESSION_ID",
"shib_application_id_field" => "HTTP_SHIB_APPLICATION_ID",
"uid_field" => 'HTTP_EPPN',
"name_field" => 'HTTP_CN',
"info_fields" => { "email" => 'HTTP_MAIL'}
}
}
]
```
1. Save changes and reconfigure gitlab:
```
sudo gitlab-ctl reconfigure
```
On the sign in page there should now be a "Sign in with: Shibboleth" icon below the regular sign in form. Click the icon to begin the authentication process. You will be redirected to IdP server (Depends on your Shibboleth module configuration). If everything goes well the user will be returned to GitLab and will be signed in.
......@@ -115,8 +115,10 @@ Checking GitLab ... Finished
This will create satellite repositories for all your projects.
If necessary, remove the `tmp/repo_satellites` directory and rerun the command below.
If necessary, remove the `repo_satellites` directory and rerun the commands below.
```
bundle exec rake gitlab:satellites:create RAILS_ENV=production
sudo -u git -H mkdir -p /home/git/gitlab-satellites
sudo -u git -H bundle exec rake gitlab:satellites:create RAILS_ENV=production
sudo chmod u+rwx,g=rx,o-rwx /home/git/gitlab-satellites
```
......@@ -107,11 +107,13 @@ List any major changes here, so the user is aware of them before starting to upg
Check if any of these changed since last release:
- <https://gitlab.com/gitlab-org/gitlab-ce/commits/master/lib/support/nginx/gitlab>
- <https://gitlab.com/gitlab-org/gitlab-ce/commits/master/lib/support/nginx/gitlab-ssl>
- <https://gitlab.com/gitlab-org/gitlab-shell/commits/master/config.yml.example>
- <https://gitlab.com/gitlab-org/gitlab-ce/commits/master/config/gitlab.yml.example>
- <https://gitlab.com/gitlab-org/gitlab-ce/commits/master/config/unicorn.rb.example>
- <https://gitlab.com/gitlab-org/gitlab-ce/commits/master/config/database.yml.mysql>
- <https://gitlab.com/gitlab-org/gitlab-ce/commits/master/config/database.yml.postgresql>
- <https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/initializers/rack_attack.rb.example>
#### 8. Need to update init script?
......
......@@ -10,7 +10,7 @@ GitLab 5.0 is affected by critical security vulnerability CVE-2013-4490.
- Self signed SSL certificates are not supported until GitLab 5.1
- **requires ruby1.9.3**
## 0. Stop gitlab
## 0. Stop GitLab
sudo service gitlab stop
......@@ -41,7 +41,7 @@ git checkout v1.1.0
# copy config
cp config.yml.example config.yml
# change url to gitlab instance
# change url to GitLab instance
# ! make sure url end with '/' like 'https://gitlab.example/'
vim config.yml
......@@ -49,14 +49,14 @@ vim config.yml
./support/rewrite-hooks.sh
# check ruby version for git user ( 1.9 required!! )
# gitlab shell requires system ruby 1.9
# GitLab shell requires system ruby 1.9
ruby -v
# exit from git user
exit
```
## 4. Copy gitlab instance to git user
## 4. Copy GitLab instance to git user
```bash
sudo cp -R /home/gitlab/gitlab /home/git/gitlab
......@@ -162,8 +162,43 @@ sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
```
**P.S. If everything works as expected you can remove gitlab user from system**
## 9. Cleanup
**If everything works as expected you can cleanup some old things**
Recommend you wait a bit and do a backup before completing the following.
```bash
# remove GitLab user from system
sudo userdel -r gitlab
cd /home/git
# cleanup .profile
## remove text from .profile added during gitolite installation:
## PATH=\$PATH:/home/git/bin
## export PATH
## to see what a clean .profile for new users on your system would look like see /etc/skel/.profile
sudo -u git -H vim .profile
# remove gitolite
sudo rm -R bin
sudo rm -Rf gitolite
sudo rm -R .gitolite
sudo rm .gitolite.rc
sudo rm -f gitlab.pub
sudo rm projects.list
# reset tmp folders
sudo service gitlab stop
cd /home/git/gitlab
sudo rm -R tmp
sudo -u git -H mkdir tmp
sudo chmod -R u+rwX tmp/
# reboot system
sudo reboot
# login, check that GitLab is running fine
cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
```
......@@ -135,7 +135,8 @@ git diff 6-0-stable:config/gitlab.yml.example 7-2-stable:config/gitlab.yml.examp
* Make `/home/git/gitlab/config/gitlab.yml` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-2-stable/config/gitlab.yml.example but with your settings.
* Make `/home/git/gitlab/config/unicorn.rb` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-2-stable/config/unicorn.rb.example but with your settings.
* Make `/home/git/gitlab-shell/config.yml` the same as https://gitlab.com/gitlab-org/gitlab-shell/blob/v1.9.7/config.yml.example but with your settings.
* Make `/etc/nginx/sites-available/nginx` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-2-stable/lib/support/nginx/gitlab but with your settings.
* HTTP setups: Make `/etc/nginx/sites-available/nginx` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-2-stable/lib/support/nginx/gitlab but with your settings.
* HTTPS setups: Make `/etc/nginx/sites-available/nginx-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-2-stable/lib/support/nginx/gitlab-ssl but with your settings.
* Copy rack attack middleware config
```bash
......
......@@ -105,6 +105,9 @@ There are new configuration options available for gitlab.yml. View them with the
git diff origin/6-9-stable:config/gitlab.yml.example origin/7-0-stable:config/gitlab.yml.example
```
* HTTP setups: Make `/etc/nginx/sites-available/nginx` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-0-stable/lib/support/nginx/gitlab but with your settings.
* HTTPS setups: Make `/etc/nginx/sites-available/nginx-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-0-stable/lib/support/nginx/gitlab-ssl but with your setting
### 7. Start application
sudo service gitlab start
......
......@@ -89,6 +89,9 @@ There are new configuration options available for gitlab.yml. View them with the
git diff 7-1-stable:config/gitlab.yml.example 7-2-stable:config/gitlab.yml.example
```
* HTTP setups: Make `/etc/nginx/sites-available/nginx` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-0-stable/lib/support/nginx/gitlab but with your settings.
* HTTPS setups: Make `/etc/nginx/sites-available/nginx-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-0-stable/lib/support/nginx/gitlab-ssl but with your setting
Update rack attack middleware config
```
......
# From 7.2 to 7.3
# GitLab 7.3 has not been released yet!
This document currently just serves as a place to keep track of updates that will be needed for the 7.3 update.
### Update config files
* HTTP setups: Make `/etc/nginx/sites-available/nginx` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-0-stable/lib/support/nginx/gitlab but with your settings.
* HTTPS setups: Make `/etc/nginx/sites-available/nginx-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-0-stable/lib/support/nginx/gitlab-ssl but with your setting
\ No newline at end of file
......@@ -21,6 +21,9 @@ sudo -u git psql -f databasename.psql -d gitlabhq_production
# Rebuild indexes (see below)
# Install gems for PostgreSQL (note: the line below states '--without ... mysql')
sudo -u git -H bundle install --without development test mysql --deployment
sudo service gitlab start
```
......
......@@ -15,7 +15,7 @@ Feature: Project Browse branches
Scenario: I create a branch
Given I visit project branches page
And I click new branch link
When I submit new branch form
And I submit new branch form
Then I should see new branch created
@javascript
......@@ -23,3 +23,21 @@ Feature: Project Browse branches
Given I visit project branches page
And I click branch 'improve/awesome' delete link
Then I should not see branch 'improve/awesome'
Scenario: I create a branch with invalid name
Given I visit project branches page
And I click new branch link
And I submit new branch form with invalid name
Then I should see new an error that branch is invalid
Scenario: I create a branch with invalid reference
Given I visit project branches page
And I click new branch link
And I submit new branch form with invalid reference
Then I should see new an error that ref is invalid
Scenario: I create a branch that already exists
Given I visit project branches page
And I click new branch link
And I submit new branch form with branch that already exists
Then I should see new an error that branch already exists
......@@ -7,5 +7,25 @@ Feature: Project Browse tags
Scenario: I can see all git tags
Then I should see "Shop" all tags list
Scenario: I create a tag
And I click new tag link
And I submit new tag form
Then I should see new tag created
Scenario: I create a tag with invalid name
And I click new tag link
And I submit new tag form with invalid name
Then I should see new an error that tag is invalid
Scenario: I create a tag with invalid reference
And I click new tag link
And I submit new tag form with invalid reference
Then I should see new an error that tag ref is invalid
Scenario: I create a tag that already exists
And I click new tag link
And I submit new tag form with tag that already exists
Then I should see new an error that tag already exists
# @wip
# Scenario: I can download project by tag
......@@ -24,6 +24,11 @@ Feature: Project Labels
When I remove label 'bug'
Then I should not see label 'bug'
@javascript
Scenario: I remove all labels
When I delete all labels
Then I should see labels help message
Scenario: I create a label with invalid color
Given I visit project "Shop" new label page
When I submit new label with invalid color
......
......@@ -44,3 +44,9 @@ Feature: Project shortcuts
Scenario: Navigate to wiki tab
Given I press "g" and "w"
Then the active main tab should be Wiki
@javascript
Scenario: Navigate to project feed
Given I visit my project's files page
Given I press "g" and "p"
Then the active main tab should be Home
......@@ -51,3 +51,15 @@ Feature: Project Browse files
Scenario: I can browse code with Browse Code
Given I click on history link
Then I see Browse code link
# Permalink
Scenario: I click on the permalink link from a branch ref
Given I click on ".gitignore" file in repo
And I click on permalink
Then I am redirected to the permalink URL
Scenario: I don't see the permalink link from a SHA ref
Given I visit project source page for "6d394385cf567f80a8fd85055db1ab4c5295806f"
And I click on ".gitignore" file in repo
Then I don't see the permalink link
@dashboard
Feature: Snippet Search
Background:
Given I sign in as a user
And I have public "Personal snippet one" snippet
And I have private "Personal snippet private" snippet
And I have a public many lined snippet
Scenario: I should see my public and private snippets
When I search for "snippet" in snippet titles
Then I should see "Personal snippet one" in results
And I should see "Personal snippet private" in results
Scenario: I should see three surrounding lines on either side of a matching snippet line
When I search for "line seven" in snippet contents
Then I should see "line four" in results
And I should see "line seven" in results
And I should see "line ten" in results
And I should not see "line three" in results
And I should not see "line eleven" in results
......@@ -38,10 +38,38 @@ class ProjectBrowseBranches < Spinach::FeatureSteps
click_button 'Create branch'
end
step 'I submit new branch form with invalid name' do
fill_in 'branch_name', with: '1.0 stable'
fill_in 'ref', with: 'master'
click_button 'Create branch'
end
step 'I submit new branch form with invalid reference' do
fill_in 'branch_name', with: 'foo'
fill_in 'ref', with: 'foo'
click_button 'Create branch'
end
step 'I submit new branch form with branch that already exists' do
fill_in 'branch_name', with: 'master'
fill_in 'ref', with: 'master'
click_button 'Create branch'
end
step 'I should see new branch created' do
within '.tree-ref-holder' do
page.should have_content 'deploy_keys'
end
page.should have_content 'deploy_keys'
end
step 'I should see new an error that branch is invalid' do
page.should have_content 'Branch name invalid'
end
step 'I should see new an error that ref is invalid' do
page.should have_content 'Invalid reference name'
end
step 'I should see new an error that branch already exists' do
page.should have_content 'Branch already exists'
end
step "I click branch 'improve/awesome' delete link" do
......
......@@ -90,4 +90,17 @@ class ProjectBrowseFiles < Spinach::FeatureSteps
page.should_not have_link 'Browse File »'
page.should_not have_link 'Browse Dir »'
end
step 'I click on permalink' do
click_link 'permalink'
end
step 'I am redirected to the permalink URL' do
expect(current_path).to eq(project_blob_path(
@project, @project.repository.commit.sha + '/.gitignore'))
end
step "I don't see the permalink link" do
expect(page).not_to have_link('permalink')
end
end
......@@ -3,8 +3,52 @@ class ProjectBrowseTags < Spinach::FeatureSteps
include SharedProject
include SharedPaths
Then 'I should see "Shop" all tags list' do
step 'I should see "Shop" all tags list' do
page.should have_content "Tags"
page.should have_content "v1.0.0"
end
step 'I click new tag link' do
click_link 'New tag'
end
step 'I submit new tag form' do
fill_in 'tag_name', with: 'v7.0'
fill_in 'ref', with: 'master'
click_button 'Create tag'
end
step 'I submit new tag form with invalid name' do
fill_in 'tag_name', with: 'v 1.0'
fill_in 'ref', with: 'master'
click_button 'Create tag'
end
step 'I submit new tag form with invalid reference' do
fill_in 'tag_name', with: 'foo'
fill_in 'ref', with: 'foo'
click_button 'Create tag'
end
step 'I submit new tag form with tag that already exists' do
fill_in 'tag_name', with: 'v1.0.0'
fill_in 'ref', with: 'master'
click_button 'Create tag'
end
step 'I should see new tag created' do
page.should have_content 'v7.0'
end
step 'I should see new an error that tag is invalid' do
page.should have_content 'Tag name invalid'
end
step 'I should see new an error that tag ref is invalid' do
page.should have_content 'Invalid reference name'
end
step 'I should see new an error that tag already exists' do
page.should have_content 'Tag already exists'
end
end
......@@ -74,34 +74,34 @@ class ProjectIssues < Spinach::FeatureSteps
end
Given 'I fill in issue search with "Re"' do
fill_in 'issue_search', with: "Re"
filter_issue "Re"
end
Given 'I fill in issue search with "Bu"' do
fill_in 'issue_search', with: "Bu"
filter_issue "Bu"
end
And 'I fill in issue search with ".3"' do
fill_in 'issue_search', with: ".3"
filter_issue ".3"
end
And 'I fill in issue search with "Something"' do
fill_in 'issue_search', with: "Something"
filter_issue "Something"
end
And 'I fill in issue search with ""' do
fill_in 'issue_search', with: ""
filter_issue ""
end
Given 'project "Shop" has milestone "v2.2"' do
project = Project.find_by(name: "Shop")
milestone = create(:milestone, title: "v2.2", project: project)
3.times { create(:issue, project: project, milestone: milestone) }
end
And 'project "Shop" has milestone "v3.0"' do
project = Project.find_by(name: "Shop")
milestone = create(:milestone, title: "v3.0", project: project)
3.times { create(:issue, project: project, milestone: milestone) }
......@@ -117,20 +117,20 @@ class ProjectIssues < Spinach::FeatureSteps
end
When 'I select first assignee from "Shop" project' do
project = Project.find_by(name: "Shop")
first_assignee = project.users.first
select first_assignee.name, from: "assignee_id"
end
Then 'I should see first assignee from "Shop" as selected assignee' do
issues_assignee_selector = "#issue_assignee_id_chzn > a"
project = Project.find_by(name: "Shop")
assignee_name = project.users.first.name
page.find(issues_assignee_selector).should have_content(assignee_name)
end
And 'project "Shop" have "Release 0.4" open issue' do
project = Project.find_by(name: "Shop")
create(:issue,
title: "Release 0.4",
project: project,
......@@ -140,7 +140,6 @@ class ProjectIssues < Spinach::FeatureSteps
end
And 'project "Shop" have "Tweet control" open issue' do
project = Project.find_by(name: "Shop")
create(:issue,
title: "Tweet control",
project: project,
......@@ -148,7 +147,6 @@ class ProjectIssues < Spinach::FeatureSteps
end
And 'project "Shop" have "Release 0.3" closed issue' do
project = Project.find_by(name: "Shop")
create(:closed_issue,
title: "Release 0.3",
project: project,
......@@ -189,25 +187,23 @@ class ProjectIssues < Spinach::FeatureSteps
end
step 'project \'Shop\' has issue \'Bugfix1\' with description: \'Description for issue1\'' do
project = Project.find_by(name: 'Shop')
issue = create(:issue, title: 'Bugfix1', description: 'Description for issue1', project: project)
end
step 'project \'Shop\' has issue \'Feature1\' with description: \'Feature submitted for issue1\'' do
project = Project.find_by(name: 'Shop')
issue = create(:issue, title: 'Feature1', description: 'Feature submitted for issue1', project: project)
end
step 'I fill in issue search with \'Description for issue1\'' do
fill_in 'issue_search', with: 'Description for issue'
filter_issue 'Description for issue'
end
step 'I fill in issue search with \'issue1\'' do
fill_in 'issue_search', with: 'issue1'
filter_issue 'issue1'
end
step 'I fill in issue search with \'Rock and roll\'' do
fill_in 'issue_search', with: 'Description for issue'
filter_issue 'Description for issue'
end
step 'I should see \'Bugfix1\' in issues' do
......@@ -221,4 +217,15 @@ class ProjectIssues < Spinach::FeatureSteps
step 'I should not see \'Bugfix1\' in issues' do
page.should_not have_content 'Bugfix1'
end
def filter_issue(text)
fill_in 'issue_search', with: text
# make sure AJAX request finished
URI.parse(current_url).request_uri == project_issues_path(project, issue_search: text)
end
def project
@project ||= Project.find_by(name: 'Shop')
end
end
......@@ -25,6 +25,22 @@ class ProjectLabels < Spinach::FeatureSteps
end
end
step 'I delete all labels' do
within '.labels' do
all('.btn-remove').each do |remove|
remove.click
sleep 0.05
end
end
end
step 'I should see labels help message' do
within '.labels' do
page.should have_content 'Create first label or generate default set of '\
'labels'
end
end
step 'I submit new label \'support\'' do
fill_in 'Title', with: 'support'
fill_in 'Background Color', with: '#F95610'
......
......@@ -269,6 +269,12 @@ module SharedPaths
visit project_tree_path(@project, "6d39438")
end
step 'I visit project source page for' \
' "6d394385cf567f80a8fd85055db1ab4c5295806f"' do
visit project_tree_path(@project,
'6d394385cf567f80a8fd85055db1ab4c5295806f')
end
step 'I visit project tags page' do
visit project_tags_path(@project)
end
......
require_relative 'active_tab'
module SharedProjectTab
include Spinach::DSL
include SharedActiveTab
......
module SharedSearch
include Spinach::DSL
def search_snippet_contents(query)
visit "/search?search=#{URI::encode(query)}&snippets=true&scope=snippet_blobs"
end
def search_snippet_titles(query)
visit "/search?search=#{URI::encode(query)}&snippets=true&scope=snippet_titles"
end
end
......@@ -18,4 +18,27 @@ module SharedSnippet
private: true,
author: current_user)
end
And 'I have a public many lined snippet' do
create(:personal_snippet,
title: 'Many lined snippet',
content: <<-END.gsub(/^\s+\|/, ''),
|line one
|line two
|line three
|line four
|line five
|line six
|line seven
|line eight
|line nine
|line ten
|line eleven
|line twelve
|line thirteen
|line fourteen
END
file_name: 'many_lined_snippet.rb',
private: true,
author: current_user)
end
end
class Spinach::Features::SnippetSearch < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
include SharedSnippet
include SharedUser
include SharedSearch
step 'I search for "snippet" in snippet titles' do
search_snippet_titles 'snippet'
end
step 'I search for "snippet private" in snippet titles' do
search_snippet_titles 'snippet private'
end
step 'I search for "line seven" in snippet contents' do
search_snippet_contents 'line seven'
end
step 'I should see "line seven" in results' do
page.should have_content 'line seven'
end
step 'I should see "line four" in results' do
page.should have_content 'line four'
end
step 'I should see "line ten" in results' do
page.should have_content 'line ten'
end
step 'I should not see "line eleven" in results' do
page.should_not have_content 'line eleven'
end
step 'I should not see "line three" in results' do
page.should_not have_content 'line three'
end
Then 'I should see "Personal snippet one" in results' do
page.should have_content 'Personal snippet one'
end
And 'I should see "Personal snippet private" in results' do
page.should have_content 'Personal snippet private'
end
Then 'I should not see "Personal snippet one" in results' do
page.should_not have_content 'Personal snippet one'
end
And 'I should not see "Personal snippet private" in results' do
page.should_not have_content 'Personal snippet private'
end
end
......@@ -80,9 +80,17 @@ module API
# 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
result = CreateBranchService.new.execute(user_project,
params[:branch_name],
params[:ref],
current_user)
if result[:status] == :success
present result[:branch],
with: Entities::RepoObject,
project: user_project
else
render_api_error!(result[:message], 400)
end
end
# Delete branch
......@@ -99,7 +107,7 @@ module API
if result[:state] == :success
true
else
render_api_error!(result[:message], 405)
render_api_error!(result[:message], result[:return_code])
end
end
end
......
......@@ -11,6 +11,10 @@ module API
else issues
end
end
def filter_issues_labels(issues, labels)
issues.includes(:labels).where("labels.title" => labels.split(','))
end
end
resource :issues do
......@@ -18,13 +22,22 @@ module API
#
# Parameters:
# state (optional) - Return "opened" or "closed" issues
#
# labels (optional) - Comma-separated list of label names
# Example Requests:
# GET /issues
# GET /issues?state=opened
# GET /issues?state=closed
# GET /issues?labels=foo
# GET /issues?labels=foo,bar
# GET /issues?labels=foo,bar&state=opened
get do
present paginate(filter_issues_state(current_user.issues, params['state'])), with: Entities::Issue
issues = current_user.issues
issues = filter_issues_state(issues, params[:state]) unless params[:state].nil?
issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil?
issues = issues.order('issues.id DESC')
present paginate(issues), with: Entities::Issue
end
end
......@@ -34,13 +47,23 @@ module API
# Parameters:
# id (required) - The ID of a project
# state (optional) - Return "opened" or "closed" issues
# labels (optional) - Comma-separated list of label names
#
# Example Requests:
# GET /projects/:id/issues
# GET /projects/:id/issues?state=opened
# GET /projects/:id/issues?state=closed
# GET /projects/:id/issues
# GET /projects/:id/issues?labels=foo
# GET /projects/:id/issues?labels=foo,bar
# GET /projects/:id/issues?labels=foo,bar&state=opened
get ":id/issues" do
present paginate(filter_issues_state(user_project.issues, params['state'])), with: Entities::Issue
issues = user_project.issues
issues = filter_issues_state(issues, params[:state]) unless params[:state].nil?
issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil?
issues = issues.order('issues.id DESC')
present paginate(issues), with: Entities::Issue
end
# Get a single project issue
......
......@@ -32,14 +32,23 @@ module API
# id (required) - The ID of a project
# tag_name (required) - The name of the tag
# ref (required) - Create tag from commit sha or branch
# message (optional) - Specifying a message creates an annotated tag.
# Example Request:
# POST /projects/:id/repository/tags
post ':id/repository/tags' do
authorize_push_project
@tag = CreateTagService.new.execute(user_project, params[:tag_name],
params[:ref], current_user)
present @tag, with: Entities::RepoObject, project: user_project
message = params[:message] || nil
result = CreateTagService.new.execute(user_project, params[:tag_name],
params[:ref], message,
current_user)
if result[:status] == :success
present result[:tag],
with: Entities::RepoObject,
project: user_project
else
render_api_error!(result[:message], 400)
end
end
# Get a project repository tree
......
......@@ -69,7 +69,7 @@ module Backup
end
print 'Put GitLab hooks in repositories dirs'.yellow
if system("#{Gitlab.config.gitlab_shell.path}/support/rewrite-hooks.sh", Gitlab.config.gitlab_shell.repos_path)
if system("#{Gitlab.config.gitlab_shell.path}/bin/create-hooks")
puts " [DONE]".green
else
puts " [FAILED]".red
......
......@@ -107,12 +107,17 @@ module Gitlab
# path - project path with namespace
# tag_name - new tag name
# ref - HEAD for new tag
# message - optional message for tag (annotated tag)
#
# Ex.
# add_tag("gitlab/gitlab-ci", "v4.0", "master")
# add_tag("gitlab/gitlab-ci", "v4.0", "master", "message")
#
def add_tag(path, tag_name, ref)
system "#{gitlab_shell_path}/bin/gitlab-projects", "create-tag", "#{path}.git", tag_name, ref
def add_tag(path, tag_name, ref, message = nil)
cmd = %W(#{gitlab_shell_path}/bin/gitlab-projects create-tag #{path}.git
#{tag_name} #{ref})
cmd << message unless message.nil? || message.empty?
system *cmd
end
# Remove repository tag
......
......@@ -27,6 +27,7 @@ module Gitlab
notes
unsubscribes
all
ci
)
end
end
......
module Gitlab
module Diff
class File
attr_reader :diff
delegate :new_file, :deleted_file, :renamed_file,
:old_path, :new_path, to: :diff, prefix: false
def initialize(diff)
@diff = diff
end
# Array of Gitlab::DIff::Line objects
def diff_lines
@lines ||= parser.parse(raw_diff.lines)
end
def mode_changed?
!!(diff.a_mode && diff.b_mode && diff.a_mode != diff.b_mode)
end
def parser
Gitlab::Diff::Parser.new
end
def raw_diff
diff.diff
end
def next_line(index)
diff_lines[index + 1]
end
def prev_line(index)
if index > 0
diff_lines[index - 1]
end
end
def file_path
if diff.new_path.present?
diff.new_path
elsif diff.old_path.present?
diff.old_path
end
end
end
end
end
module Gitlab
module Diff
class Line
attr_reader :type, :text, :index, :old_pos, :new_pos
def initialize(text, type, index, old_pos, new_pos)
@text, @type, @index = text, type, index
@old_pos, @new_pos = old_pos, new_pos
end
end
end
end
module Gitlab
module Diff
class LineCode
def self.generate(file_path, new_line_position, old_line_position)
"#{Digest::SHA1.hexdigest(file_path)}_#{old_line_position}_#{new_line_position}"
end
end
end
end
module Gitlab
module Diff
class Parser
include Enumerable
def parse(lines)
@lines = lines,
lines_obj = []
line_obj_index = 0
line_old = 1
line_new = 1
type = nil
lines_arr = ::Gitlab::InlineDiff.processing lines
lines_arr.each do |line|
raw_line = line.dup
next if filename?(line)
full_line = html_escape(line.gsub(/\n/, ''))
full_line = ::Gitlab::InlineDiff.replace_markers full_line
if line.match(/^@@ -/)
type = "match"
line_old = line.match(/\-[0-9]*/)[0].to_i.abs rescue 0
line_new = line.match(/\+[0-9]*/)[0].to_i.abs rescue 0
next if line_old == 1 && line_new == 1 #top of file
lines_obj << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new)
line_obj_index += 1
next
else
type = identification_type(line)
lines_obj << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new)
line_obj_index += 1
end
if line[0] == "+"
line_new += 1
elsif line[0] == "-"
line_old += 1
else
line_new += 1
line_old += 1
end
end
lines_obj
end
def empty?
@lines.empty?
end
private
def filename?(line)
line.start_with?('--- /dev/null', '+++ /dev/null', '--- a', '+++ b',
'--- /tmp/diffy', '+++ /tmp/diffy')
end
def identification_type(line)
if line[0] == "+"
"new"
elsif line[0] == "-"
"old"
else
nil
end
end
def html_escape str
replacements = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;', "'" => '&#39;' }
str.gsub(/[&"'><]/, replacements)
end
end
end
end
module Gitlab
class DiffParser
include Enumerable
attr_reader :lines, :new_path
def initialize(lines, new_path = '')
@lines = lines
@new_path = new_path
end
def each
line_old = 1
line_new = 1
type = nil
lines_arr = ::Gitlab::InlineDiff.processing lines
lines_arr.each do |line|
raw_line = line.dup
next if filename?(line)
full_line = html_escape(line.gsub(/\n/, ''))
full_line = ::Gitlab::InlineDiff.replace_markers full_line
if line.match(/^@@ -/)
type = "match"
line_old = line.match(/\-[0-9]*/)[0].to_i.abs rescue 0
line_new = line.match(/\+[0-9]*/)[0].to_i.abs rescue 0
next if line_old == 1 && line_new == 1 #top of file
yield(full_line, type, nil, line_new, line_old)
next
else
type = identification_type(line)
line_code = generate_line_code(new_path, line_new, line_old)
yield(full_line, type, line_code, line_new, line_old, raw_line)
end
if line[0] == "+"
line_new += 1
elsif line[0] == "-"
line_old += 1
else
line_new += 1
line_old += 1
end
end
end
def empty?
@lines.empty?
end
private
def filename?(line)
line.start_with?('--- /dev/null', '+++ /dev/null', '--- a', '+++ b',
'--- /tmp/diffy', '+++ /tmp/diffy')
end
def identification_type(line)
if line[0] == "+"
"new"
elsif line[0] == "-"
"old"
else
nil
end
end
def generate_line_code(path, line_new, line_old)
"#{Digest::SHA1.hexdigest(path)}_#{line_old}_#{line_new}"
end
def html_escape str
replacements = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;', "'" => '&#39;' }
str.gsub(/[&"'><]/, replacements)
end
end
end
module Gitlab
module GitRefValidator
extend self
# Validates a given name against the git reference specification
#
# Returns true for a valid reference name, false otherwise
def validate(ref_name)
system *%W(git check-ref-format refs/#{ref_name})
end
end
end
......@@ -192,8 +192,12 @@ module Gitlab
link_to("##{identifier}", url, options)
end
elsif project.issues_tracker == 'jira'
reference_jira_issue(identifier, project)
else
config = Gitlab.config
external_issue_tracker = config.issues_tracker[project.issues_tracker]
if external_issue_tracker.present?
reference_external_issue(identifier, external_issue_tracker, project)
end
end
end
......@@ -229,15 +233,15 @@ module Gitlab
end
end
def reference_jira_issue(identifier, project = @project)
url = url_for_issue(identifier)
title = Gitlab.config.issues_tracker[project.issues_tracker]["title"]
def reference_external_issue(identifier, issue_tracker, project = @project)
url = url_for_issue(identifier, project)
title = issue_tracker['title']
options = html_options.merge(
title: "Issue in #{title}",
class: "gfm gfm-issue #{html_options[:class]}"
)
link_to("#{identifier}", url, options)
link_to("##{identifier}", url, options)
end
end
end
......@@ -14,13 +14,16 @@ module Gitlab
notes.page(page).per(per_page)
when 'blobs'
Kaminari.paginate_array(blobs).page(page).per(per_page)
when 'wiki_blobs'
Kaminari.paginate_array(wiki_blobs).page(page).per(per_page)
else
super
end
end
def total_count
@total_count ||= issues_count + merge_requests_count + blobs_count + notes_count
@total_count ||= issues_count + merge_requests_count + blobs_count +
notes_count + wiki_blobs_count
end
def blobs_count
......@@ -31,6 +34,10 @@ module Gitlab
@notes_count ||= notes.count
end
def wiki_blobs_count
@wiki_blobs_count ||= wiki_blobs.count
end
private
def blobs
......@@ -41,6 +48,20 @@ module Gitlab
end
end
def wiki_blobs
if project.wiki_enabled?
wiki_repo = Repository.new(ProjectWiki.new(project).path_with_namespace)
if wiki_repo.exists?
wiki_repo.search_files(query)
else
[]
end
else
[]
end
end
def notes
Note.where(project_id: limit_project_ids).search(query).order('updated_at DESC')
end
......
module Gitlab
class SnippetSearchResults < SearchResults
attr_reader :limit_snippet_ids
def initialize(limit_snippet_ids, query)
@limit_snippet_ids = limit_snippet_ids
@query = query
end
def objects(scope, page = nil)
case scope
when 'snippet_titles'
Kaminari.paginate_array(snippet_titles).page(page).per(per_page)
when 'snippet_blobs'
Kaminari.paginate_array(snippet_blobs).page(page).per(per_page)
else
super
end
end
def total_count
@total_count ||= snippet_titles_count + snippet_blobs_count
end
def snippet_titles_count
@snippet_titles_count ||= snippet_titles.count
end
def snippet_blobs_count
@snippet_blobs_count ||= snippet_blobs.count
end
private
def snippet_titles
Snippet.where(id: limit_snippet_ids).search(query).order('updated_at DESC')
end
def snippet_blobs
search = Snippet.where(id: limit_snippet_ids).search_code(query)
search = search.order('updated_at DESC').to_a
snippets = []
search.each { |e| snippets << chunk_snippet(e) }
snippets
end
def default_scope
'snippet_blobs'
end
# Get an array of line numbers surrounding a matching
# line, bounded by min/max.
#
# @returns Array of line numbers
def bounded_line_numbers(line, min, max)
lower = line - surrounding_lines > min ? line - surrounding_lines : min
upper = line + surrounding_lines < max ? line + surrounding_lines : max
(lower..upper).to_a
end
# Returns a sorted set of lines to be included in a snippet preview.
# This ensures matching adjacent lines do not display duplicated
# surrounding code.
#
# @returns Array, unique and sorted.
def matching_lines(lined_content)
used_lines = []
lined_content.each_with_index do |line, line_number|
used_lines.concat bounded_line_numbers(
line_number,
0,
lined_content.size
) if line.include?(query)
end
used_lines.uniq.sort
end
# 'Chunkify' entire snippet. Splits the snippet data into matching lines +
# surrounding_lines() worth of unmatching lines.
#
# @returns a hash with {snippet_object, snippet_chunks:{data,start_line}}
def chunk_snippet(snippet)
lined_content = snippet.content.split("\n")
used_lines = matching_lines(lined_content)
snippet_chunk = []
snippet_chunks = []
snippet_start_line = 0
last_line = -1
# Go through each used line, and add consecutive lines as a single chunk
# to the snippet chunk array.
used_lines.each do |line_number|
if last_line < 0
# Start a new chunk.
snippet_start_line = line_number
snippet_chunk << lined_content[line_number]
elsif last_line == line_number - 1
# Consecutive line, continue chunk.
snippet_chunk << lined_content[line_number]
else
# Non-consecutive line, add chunk to chunk array.
snippet_chunks << {
data: snippet_chunk.join("\n"),
start_line: snippet_start_line + 1
}
# Start a new chunk.
snippet_chunk = [lined_content[line_number]]
snippet_start_line = line_number
end
last_line = line_number
end
# Add final chunk to chunk array
snippet_chunks << {
data: snippet_chunk.join("\n"),
start_line: snippet_start_line + 1
}
# Return snippet with chunk array
{ snippet_object: snippet, snippet_chunks: snippet_chunks }
end
# Defines how many unmatching lines should be
# included around the matching lines in a snippet
def surrounding_lines
3
end
end
end
......@@ -43,7 +43,7 @@ module Gitlab
end
def latest_version_raw
remote_tags, _ = Gitlab::Popen.popen(%W(git ls-remote --tags origin))
remote_tags, _ = Gitlab::Popen.popen(%W(git ls-remote --tags https://gitlab.com/gitlab-org/gitlab-ce.git))
git_tags = remote_tags.split("\n").grep(/tags\/v#{current_version.major}/)
git_tags = git_tags.select { |version| version =~ /v\d\.\d\.\d\Z/ }
last_tag = git_tags.last.match(/v\d\.\d\.\d/).to_s
......
......@@ -26,23 +26,12 @@
## [1] https://github.com/agentzh/chunkin-nginx-module#status
## [2] https://github.com/agentzh/chunkin-nginx-module
##
###################################
## SSL file editing ##
###################################
##
## Edit `gitlab-shell/config.yml`:
## 1) Set "gitlab_url" param in `gitlab-shell/config.yml` to `https://git.example.com`
## 2) Set "ca_file" to `/etc/nginx/ssl/gitlab.crt`
## 3) Set "self_signed_cert" to `true`
## Edit `gitlab/config/gitlab.yml`:
## 1) Define port for http "port: 443"
## 2) Enable https "https: true"
## 3) Update ssl for gravatar "ssl_url: https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=mm"
##
###################################
## SSL configuration ##
###################################
##
## See installation.md#using-https for additional HTTPS configuration details.
upstream gitlab {
server unix:/home/git/gitlab/tmp/sockets/gitlab.socket;
......@@ -76,7 +65,7 @@ server {
ssl_certificate /etc/nginx/ssl/gitlab.crt;
ssl_certificate_key /etc/nginx/ssl/gitlab.key;
ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4';
ssl_ciphers 'AES256+EECDH:AES256+EDH';
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_session_cache builtin:1000 shared:SSL:10m;
......@@ -87,6 +76,23 @@ server {
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
## [Optional] If your certficate has OCSP, enable OCSP stapling to reduce the overhead and latency of running SSL.
## Replace with your ssl_trusted_certificate. For more info see:
## - https://medium.com/devops-programming/4445f4862461
## - https://www.ruby-forum.com/topic/4419319
## - https://www.digitalocean.com/community/tutorials/how-to-configure-ocsp-stapling-on-apache-and-nginx
# ssl_stapling on;
# ssl_stapling_verify on;
# ssl_trusted_certificate /etc/nginx/ssl/stapling.trusted.crt;
# resolver 208.67.222.222 208.67.222.220 valid=300s; # Can change to your DNS resolver if desired
# resolver_timeout 10s;
## [Optional] Generate a stronger DHE parameter:
## cd /etc/ssl/certs
## sudo openssl dhparam -out dhparam.pem 4096
##
# ssl_dhparam /etc/ssl/certs/dhparam.pem;
## Individual nginx logs for this GitLab vhost
access_log /var/log/nginx/gitlab_access.log;
error_log /var/log/nginx/gitlab_error.log;
......
......@@ -322,7 +322,7 @@ namespace :gitlab do
"core.autocrlf" => "input"
}
correct_options = options.map do |name, value|
run(%W(git config --global --get #{name})).try(:squish) == value
run(%W(#{Gitlab.config.git.bin_path} config --global --get #{name})).try(:squish) == value
end
if correct_options.all?
......@@ -330,9 +330,9 @@ namespace :gitlab do
else
puts "no".red
try_fixing_it(
sudo_gitlab("git config --global user.name \"#{options["user.name"]}\""),
sudo_gitlab("git config --global user.email \"#{options["user.email"]}\""),
sudo_gitlab("git config --global core.autocrlf \"#{options["core.autocrlf"]}\"")
sudo_gitlab("\"#{Gitlab.config.git.bin_path}\" config --global user.name \"#{options["user.name"]}\""),
sudo_gitlab("\"#{Gitlab.config.git.bin_path}\" config --global user.email \"#{options["user.email"]}\""),
sudo_gitlab("\"#{Gitlab.config.git.bin_path}\" config --global core.autocrlf \"#{options["core.autocrlf"]}\"")
)
for_more_information(
see_installation_guide_section "GitLab"
......@@ -541,7 +541,7 @@ namespace :gitlab do
"sudo -u #{gitlab_shell_ssh_user} ln -sf #{gitlab_shell_hook_file} #{project_hook_file}"
)
for_more_information(
"#{gitlab_shell_path}/support/rewrite-hooks.sh"
"#{gitlab_shell_path}/bin/create-hooks"
)
fix_and_rerun
next
......@@ -556,7 +556,7 @@ namespace :gitlab do
"sudo -u #{gitlab_shell_ssh_user} ln -sf #{gitlab_shell_hook_file} #{project_hook_file}"
)
for_more_information(
"lib/support/rewrite-hooks.sh"
"#{gitlab_shell_path}/bin/create-hooks"
)
fix_and_rerun
end
......
......@@ -165,7 +165,6 @@ FactoryGirl.define do
factory :service do
type ""
title "GitLab CI"
token "x56olispAND34ng"
project
end
......
require 'spec_helper'
describe DiffHelper do
include RepoHelpers
let(:project) { create(:project) }
let(:commit) { project.repository.commit(sample_commit.id) }
let(:diff) { commit.diffs.first }
let(:diff_file) { Gitlab::Diff::File.new(diff) }
describe 'diff_hard_limit_enabled?' do
it 'should return true if param is provided' do
controller.stub(:params).and_return { { :force_show_diff => true } }
diff_hard_limit_enabled?.should be_true
end
it 'should return false if param is not provided' do
diff_hard_limit_enabled?.should be_false
end
end
describe 'allowed_diff_size' do
it 'should return hard limit for a diff if force diff is true' do
controller.stub(:params).and_return { { :force_show_diff => true } }
allowed_diff_size.should eq(1000)
end
it 'should return safe limit for a diff if force diff is false' do
allowed_diff_size.should eq(100)
end
end
describe 'parallel_diff' do
it 'should return an array of arrays containing the parsed diff' do
parallel_diff(diff_file, 0).should match_array(parallel_diff_result_array)
end
end
describe 'generate_line_code' do
it 'should generate correct line code' do
generate_line_code(diff_file.file_path, diff_file.diff_lines.first).should == '2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6'
end
end
describe 'unfold_bottom_class' do
it 'should return empty string when bottom line shouldnt be unfolded' do
unfold_bottom_class(false).should == ''
end
it 'should return js class when bottom lines should be unfolded' do
unfold_bottom_class(true).should == 'js-unfold-bottom'
end
end
describe 'diff_line_content' do
it 'should return non breaking space when line is empty' do
diff_line_content(nil).should eq(" &nbsp;")
end
it 'should return the line itself' do
diff_line_content(diff_file.diff_lines.first.text).should eq("@@ -6,12 +6,18 @@ module Popen")
diff_line_content(diff_file.diff_lines.first.type).should eq("match")
diff_line_content(diff_file.diff_lines.first.new_pos).should eq(6)
end
end
def parallel_diff_result_array
[
["match", 6, "@@ -6,12 +6,18 @@ module Popen", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6", "match", 6, "@@ -6,12 +6,18 @@ module Popen"],
[nil, 6, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6", nil, 6, " "],
[nil, 7, " def popen(cmd, path=nil)", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7", nil, 7, " def popen(cmd, path=nil)"],
[nil, 8, " unless cmd.is_a?(Array)", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8", nil, 8, " unless cmd.is_a?(Array)"],
["old", 9, "- raise <span class='idiff'></span>&quot;System commands must be given as an array of strings&quot;", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_9_9", "new", 9, "+ raise <span class='idiff'>RuntimeError, </span>&quot;System commands must be given as an array of strings&quot;"],
[nil, 10, " end", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10", nil, 10, " end"], [nil, 11, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_11_11", nil, 11, " "],
[nil, 12, " path ||= Dir.pwd", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_12_12", nil, 12, " path ||= Dir.pwd"],
["old", 13, "- vars = { &quot;PWD&quot; =&gt; path }", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_13_13", "old", nil, "&nbsp;"],
["old", 14, "- options = { chdir: path }", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_13", "new", 13, "+"],
[nil, nil, "&nbsp;", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_14", "new", 14, "+ vars = {"],
[nil, nil, "&nbsp;", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_15", "new", 15, "+ &quot;PWD&quot; =&gt; path"],
[nil, nil, "&nbsp;", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_16", "new", 16, "+ }"],
[nil, nil, "&nbsp;", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_17", "new", 17, "+"],
[nil, nil, "&nbsp;", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_18", "new", 18, "+ options = {"],
[nil, nil, "&nbsp;", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_19", "new", 19, "+ chdir: path"],
[nil, nil, "&nbsp;", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_20", "new", 20, "+ }"],
[nil, 15, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_21", nil, 21, " "],
[nil, 16, " unless File.directory?(path)", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_16_22", nil, 22, " unless File.directory?(path)"],
[nil, 17, " FileUtils.mkdir_p(path)", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_17_23", nil, 23, " FileUtils.mkdir_p(path)"],
["match", 19, "@@ -19,6 +25,7 @@ module Popen", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25", "match", 25, "@@ -19,6 +25,7 @@ module Popen"],
[nil, 19, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25", nil, 25, " "], [nil, 20, " @cmd_output = &quot;&quot;", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_20_26", nil, 26, " @cmd_output = &quot;&quot;"],
[nil, 21, " @cmd_status = 0", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_21_27", nil, 27, " @cmd_status = 0"],
[nil, nil, "&nbsp;", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_28", "new", 28, "+"],
[nil, 22, " Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_29", nil, 29, " Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|"],
[nil, 23, " @cmd_output &lt;&lt; stdout.read", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_23_30", nil, 30, " @cmd_output &lt;&lt; stdout.read"],
[nil, 24, " @cmd_output &lt;&lt; stderr.read", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_24_31", nil, 31, " @cmd_output &lt;&lt; stderr.read"]
]
end
end
require 'spec_helper'
describe Gitlab::GitRefValidator do
it { Gitlab::GitRefValidator.validate('feature/new').should be_true }
it { Gitlab::GitRefValidator.validate('implement_@all').should be_true }
it { Gitlab::GitRefValidator.validate('my_new_feature').should be_true }
it { Gitlab::GitRefValidator.validate('#1').should be_true }
it { Gitlab::GitRefValidator.validate('feature/~new/').should be_false }
it { Gitlab::GitRefValidator.validate('feature/^new/').should be_false }
it { Gitlab::GitRefValidator.validate('feature/:new/').should be_false }
it { Gitlab::GitRefValidator.validate('feature/?new/').should be_false }
it { Gitlab::GitRefValidator.validate('feature/*new/').should be_false }
it { Gitlab::GitRefValidator.validate('feature/[new/').should be_false }
it { Gitlab::GitRefValidator.validate('feature/new/').should be_false }
it { Gitlab::GitRefValidator.validate('feature/new.').should be_false }
it { Gitlab::GitRefValidator.validate('feature\@{').should be_false }
it { Gitlab::GitRefValidator.validate('feature\new').should be_false }
it { Gitlab::GitRefValidator.validate('feature//new').should be_false }
it { Gitlab::GitRefValidator.validate('feature new').should be_false }
end
require 'spec_helper'
describe Gitlab::Diff::File do
include RepoHelpers
let(:project) { create(:project) }
let(:commit) { project.repository.commit(sample_commit.id) }
let(:diff) { commit.diffs.first }
let(:diff_file) { Gitlab::Diff::File.new(diff) }
describe :diff_lines do
let(:diff_lines) { diff_file.diff_lines }
it { diff_lines.size.should == 30 }
it { diff_lines.first.should be_kind_of(Gitlab::Diff::Line) }
end
describe :mode_changed? do
it { diff_file.mode_changed?.should be_false }
end
end
require 'spec_helper'
describe Gitlab::Diff::Parser do
include RepoHelpers
let(:project) { create(:project) }
let(:commit) { project.repository.commit(sample_commit.id) }
let(:diff) { commit.diffs.first }
let(:parser) { Gitlab::Diff::Parser.new }
describe :parse do
let(:diff) do
<<eos
--- a/files/ruby/popen.rb
+++ b/files/ruby/popen.rb
@@ -6,12 +6,18 @@ module Popen
def popen(cmd, path=nil)
unless cmd.is_a?(Array)
- raise "System commands must be given as an array of strings"
+ raise RuntimeError, "System commands must be given as an array of strings"
end
path ||= Dir.pwd
- vars = { "PWD" => path }
- options = { chdir: path }
+
+ vars = {
+ "PWD" => path
+ }
+
+ options = {
+ chdir: path
+ }
unless File.directory?(path)
FileUtils.mkdir_p(path)
@@ -19,6 +25,7 @@ module Popen
@cmd_output = ""
@cmd_status = 0
+
Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|
@cmd_output << stdout.read
@cmd_output << stderr.read
eos
end
before do
@lines = parser.parse(diff.lines)
end
it { @lines.size.should == 30 }
describe 'lines' do
describe 'first line' do
let(:line) { @lines.first }
it { line.type.should == 'match' }
it { line.old_pos.should == 6 }
it { line.new_pos.should == 6 }
it { line.text.should == '@@ -6,12 +6,18 @@ module Popen' }
end
describe 'removal line' do
let(:line) { @lines[10] }
it { line.type.should == 'old' }
it { line.old_pos.should == 14 }
it { line.new_pos.should == 13 }
it { line.text.should == '- options = { chdir: path }' }
end
describe 'addition line' do
let(:line) { @lines[16] }
it { line.type.should == 'new' }
it { line.old_pos.should == 15 }
it { line.new_pos.should == 18 }
it { line.text.should == '+ options = {' }
end
describe 'unchanged line' do
let(:line) { @lines.last }
it { line.type.should == nil }
it { line.old_pos.should == 24 }
it { line.new_pos.should == 31 }
it { line.text.should == ' @cmd_output &lt;&lt; stderr.read' }
end
end
end
end
......@@ -5,16 +5,11 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# recipients :text
# api_key :string(255)
# properties :text
#
require 'spec_helper'
......
......@@ -5,16 +5,11 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# recipients :text
# api_key :string(255)
# properties :text
#
require 'spec_helper'
......
......@@ -5,16 +5,11 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# recipients :text
# api_key :string(255)
# properties :text
#
require 'spec_helper'
......
......@@ -5,16 +5,11 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# recipients :text
# api_key :string(255)
# properties :text
#
require 'spec_helper'
......
......@@ -5,16 +5,11 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# recipients :text
# api_key :string(255)
# properties :text
#
require 'spec_helper'
......
......@@ -5,16 +5,11 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# recipients :text
# api_key :string(255)
# properties :text
#
require 'spec_helper'
......
......@@ -94,22 +94,50 @@ describe API::API, api: true do
describe "POST /projects/:id/repository/branches" do
it "should create a new branch" do
post api("/projects/#{project.id}/repository/branches", user),
branch_name: branch_name,
ref: branch_sha
branch_name: 'feature1',
ref: branch_sha
response.status.should == 201
json_response['name'].should == branch_name
json_response['name'].should == 'feature1'
json_response['commit']['id'].should == branch_sha
end
it "should deny for user without push access" do
post api("/projects/#{project.id}/repository/branches", user2),
branch_name: branch_name,
ref: branch_sha
branch_name: branch_name,
ref: branch_sha
response.status.should == 403
end
it 'should return 400 if branch name is invalid' do
post api("/projects/#{project.id}/repository/branches", user),
branch_name: 'new design',
ref: branch_sha
response.status.should == 400
json_response['message'].should == 'Branch name invalid'
end
it 'should return 400 if branch already exists' do
post api("/projects/#{project.id}/repository/branches", user),
branch_name: 'new_design1',
ref: branch_sha
response.status.should == 201
post api("/projects/#{project.id}/repository/branches", user),
branch_name: 'new_design1',
ref: branch_sha
response.status.should == 400
json_response['message'].should == 'Branch already exists'
end
it 'should return 400 if ref name is invalid' do
post api("/projects/#{project.id}/repository/branches", user),
branch_name: 'new_design3',
ref: 'foo'
response.status.should == 400
json_response['message'].should == 'Invalid reference name'
end
end
describe "DELETE /projects/:id/repository/branches/:branch" do
......@@ -120,6 +148,11 @@ describe API::API, api: true do
response.status.should == 200
end
it 'should return 404 if branch not exists' do
delete api("/projects/#{project.id}/repository/branches/foobar", user)
response.status.should == 404
end
it "should remove protected branch" do
project.protected_branches.create(name: branch_name)
delete api("/projects/#{project.id}/repository/branches/#{branch_name}", user)
......
......@@ -9,6 +9,7 @@ describe API::API, api: true do
let!(:label) do
create(:label, title: 'label', color: '#FFAABB', project: project)
end
let!(:label_link) { create(:label_link, label: label, target: issue) }
before { project.team << [user, :reporter] }
......@@ -58,6 +59,45 @@ describe API::API, api: true do
json_response.first['id'].should == issue.id
json_response.second['id'].should == closed_issue.id
end
it 'should return an array of labeled issues' do
get api("/issues?labels=#{label.title}", user)
response.status.should == 200
json_response.should be_an Array
json_response.length.should == 1
json_response.first['labels'].should == [label.title]
end
it 'should return an array of labeled issues when at least one label matches' do
get api("/issues?labels=#{label.title},foo,bar", user)
response.status.should == 200
json_response.should be_an Array
json_response.length.should == 1
json_response.first['labels'].should == [label.title]
end
it 'should return an empty array if no issue matches labels' do
get api('/issues?labels=foo,bar', user)
response.status.should == 200
json_response.should be_an Array
json_response.length.should == 0
end
it 'should return an array of labeled issues matching given state' do
get api("/issues?labels=#{label.title}&state=opened", user)
response.status.should == 200
json_response.should be_an Array
json_response.length.should == 1
json_response.first['labels'].should == [label.title]
json_response.first['state'].should == 'opened'
end
it 'should return an empty array if no issue matches labels and state filters' do
get api("/issues?labels=#{label.title}&state=closed", user)
response.status.should == 200
json_response.should be_an Array
json_response.length.should == 0
end
end
end
......@@ -68,6 +108,29 @@ describe API::API, api: true do
json_response.should be_an Array
json_response.first['title'].should == issue.title
end
it 'should return an array of labeled project issues' do
get api("/projects/#{project.id}/issues?labels=#{label.title}", user)
response.status.should == 200
json_response.should be_an Array
json_response.length.should == 1
json_response.first['labels'].should == [label.title]
end
it 'should return an array of labeled project issues when at least one label matches' do
get api("/projects/#{project.id}/issues?labels=#{label.title},foo,bar", user)
response.status.should == 200
json_response.should be_an Array
json_response.length.should == 1
json_response.first['labels'].should == [label.title]
end
it 'should return an empty array if no project issue matches labels' do
get api("/projects/#{project.id}/issues?labels=foo,bar", user)
response.status.should == 200
json_response.should be_an Array
json_response.length.should == 0
end
end
describe "GET /projects/:id/issues/:issue_id" do
......@@ -182,7 +245,7 @@ describe API::API, api: true do
labels: 'label2', state_event: "close"
response.status.should == 200
json_response['labels'].should == ['label2']
json_response['labels'].should include 'label2'
json_response['state'].should eq "closed"
end
end
......
......@@ -114,6 +114,7 @@ describe API::API, api: true do
it "should assign attributes to project" do
project = attributes_for(:project, {
path: 'camelCasePath',
description: Faker::Lorem.sentence,
issues_enabled: false,
merge_requests_enabled: false,
......@@ -123,7 +124,6 @@ describe API::API, api: true do
post api("/projects", user), project
project.each_pair do |k,v|
next if k == :path
json_response[k.to_s].should == v
end
end
......
......@@ -23,22 +23,67 @@ describe API::API, api: true do
end
describe 'POST /projects/:id/repository/tags' do
it 'should create a new tag' do
post api("/projects/#{project.id}/repository/tags", user),
tag_name: 'v1.0.0',
ref: 'master'
response.status.should == 201
json_response['name'].should == 'v1.0.0'
context 'lightweight tags' do
it 'should create a new tag' do
post api("/projects/#{project.id}/repository/tags", user),
tag_name: 'v7.0.1',
ref: 'master'
response.status.should == 201
json_response['name'].should == 'v7.0.1'
end
end
# TODO: fix this test for CI
#context 'annotated tag' do
#it 'should create a new annotated tag' do
#post api("/projects/#{project.id}/repository/tags", user),
#tag_name: 'v7.1.0',
#ref: 'master',
#message: 'tag message'
#response.status.should == 201
#json_response['name'].should == 'v7.1.0'
# The message is not part of the JSON response.
# Additional changes to the gitlab_git gem may be required.
# json_response['message'].should == 'tag message'
#end
#end
it 'should deny for user without push access' do
post api("/projects/#{project.id}/repository/tags", user2),
tag_name: 'v1.0.0',
tag_name: 'v1.9.0',
ref: '621491c677087aa243f165eab467bfdfbee00be1'
response.status.should == 403
end
it 'should return 400 if tag name is invalid' do
post api("/projects/#{project.id}/repository/tags", user),
tag_name: 'v 1.0.0',
ref: 'master'
response.status.should == 400
json_response['message'].should == 'Tag name invalid'
end
it 'should return 400 if tag already exists' do
post api("/projects/#{project.id}/repository/tags", user),
tag_name: 'v8.0.0',
ref: 'master'
response.status.should == 201
post api("/projects/#{project.id}/repository/tags", user),
tag_name: 'v8.0.0',
ref: 'master'
response.status.should == 400
json_response['message'].should == 'Tag already exists'
end
it 'should return 400 if ref name is invalid' do
post api("/projects/#{project.id}/repository/tags", user),
tag_name: 'mytag',
ref: 'foo'
response.status.should == 400
json_response['message'].should == 'Invalid reference name'
end
end
describe "GET /projects/:id/repository/tree" do
......
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