提交 635ebac6 编写于 作者: D Dmitriy Zaporozhets

Merge branch 'master' into mwessel/gitlab-ce-configure-protection

此差异已折叠。
......@@ -25,10 +25,10 @@ v 7.8.0
- Upgrade Sidekiq gem to version 3.3.0
- Stop git zombie creation during force push check
- Show success/error messages for test setting button in services
-
- Added Rubocop for code style checks
- Fix commits pagination
-
-
- Async load a branch information at the commit page
-
- Allow configuring protection of the default branch upon first push (Marco Wessel)
-
......@@ -55,15 +55,20 @@ v 7.8.0
- Add a new API function that retrieves all issues assigned to a single milestone (Justin Whear and Hannes Rosenögger)
-
-
-
-
- API: Access groups with their path (Julien Bianchi)
- Added link to milestone and keeping resource context on smaller viewports for issues and merge requests (Jason Blanchard)
-
-
- API: Add support for editing an existing project (Mika Mäenpää and Hannes Rosenögger)
-
-
-
- When test web hook - show error message instead of 500 error page if connection to hook url was reset
- Added support for firing system hooks on group create/destroy and adding/removing users to group (Boyan Tabakov)
- Added persistent collapse button for left side nav bar (Jason Blanchard)
v 7.7.2
- Update GitLab Shell to version 2.4.2 that fixes a bug when developers can push to protected branch
- Fix issue when LDAP user can't login with existing GitLab account
v 7.7.1
- Improve mention autocomplete performance
......
......@@ -206,8 +206,6 @@ group :development do
gem 'better_errors'
gem 'binding_of_caller'
gem 'rails_best_practices'
# Docs generator
gem "sdoc"
......@@ -217,11 +215,12 @@ end
group :development, :test do
gem 'coveralls', require: false
gem 'rubocop', '0.28.0', require: false
# gem 'rails-dev-tweaks'
gem 'spinach-rails'
gem "rspec-rails"
gem "capybara", '~> 2.2.1'
gem "pry"
gem "pry-rails"
gem "awesome_print"
gem "database_cleaner"
gem "launchy"
......@@ -254,7 +253,7 @@ end
group :test do
gem "simplecov", require: false
gem "shoulda-matchers", "~> 2.1.0"
gem "shoulda-matchers", "~> 2.7.0"
gem 'email_spec'
gem "webmock"
gem 'test_after_commit'
......
......@@ -37,6 +37,9 @@ GEM
rake (>= 0.8.7)
arel (5.0.1.20140414130214)
asciidoctor (0.1.4)
ast (2.0.0)
astrolabe (1.3.0)
parser (>= 2.2.0.pre.3, < 3.0)
attr_required (1.0.0)
awesome_print (1.2.0)
axiom-types (0.0.5)
......@@ -67,8 +70,6 @@ GEM
timers (~> 4.0.0)
charlock_holmes (0.6.9.4)
cliver (0.3.2)
code_analyzer (0.4.3)
sexp_processor
coderay (1.1.0)
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
......@@ -260,7 +261,7 @@ GEM
multi_xml (>= 0.5.2)
httpauth (0.2.1)
httpclient (2.5.3.3)
i18n (0.6.11)
i18n (0.7.0)
ice_nine (0.10.0)
jasmine (2.0.2)
jasmine-core (~> 2.0.0)
......@@ -279,7 +280,7 @@ GEM
turbolinks
jquery-ui-rails (4.2.1)
railties (>= 3.2.16)
json (1.8.1)
json (1.8.2)
jwt (0.1.13)
multi_json (>= 1.5)
kaminari (0.15.1)
......@@ -353,6 +354,8 @@ GEM
org-ruby (0.9.12)
rubypants (~> 0.2)
orm_adapter (0.5.0)
parser (2.2.0.2)
ast (>= 1.1, < 3.0)
pg (0.15.1)
phantomjs (1.9.2.0)
poltergeist (1.5.1)
......@@ -362,10 +365,13 @@ GEM
websocket-driver (>= 0.2.0)
polyglot (0.3.4)
posix-spawn (0.3.9)
powerpack (0.0.9)
pry (0.9.12.4)
coderay (~> 1.0)
method_source (~> 0.8)
slop (~> 3.4)
pry-rails (0.3.2)
pry (>= 0.9.10)
pyu-ruby-sasl (0.0.3.3)
quiet_assets (1.0.2)
railties (>= 3.1, < 5.0)
......@@ -402,20 +408,12 @@ GEM
sprockets-rails (~> 2.0)
rails_autolink (1.1.6)
rails (> 3.1)
rails_best_practices (1.14.4)
activesupport
awesome_print
code_analyzer (>= 0.4.3)
colored
erubis
i18n
require_all
ruby-progressbar
railties (4.1.1)
actionpack (= 4.1.1)
activesupport (= 4.1.1)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rainbow (2.0.0)
raindrops (0.13.0)
rake (10.3.2)
raphael-rails (2.1.2)
......@@ -446,7 +444,6 @@ GEM
redis (>= 2.2)
ref (1.0.5)
request_store (1.0.5)
require_all (1.3.2)
rest-client (1.6.7)
mime-types (>= 1.16)
rinku (1.7.3)
......@@ -466,7 +463,13 @@ GEM
rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0)
rspec-mocks (~> 2.14.0)
ruby-progressbar (1.2.0)
rubocop (0.28.0)
astrolabe (~> 1.3)
parser (>= 2.2.0.pre.7, < 3.0)
powerpack (~> 0.0.6)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.4)
ruby-progressbar (1.7.1)
rubyntlm (0.4.0)
rubypants (0.2.0)
rugged (0.21.2)
......@@ -494,8 +497,7 @@ GEM
semantic-ui-sass (1.8.0.0)
sass (~> 3.2)
settingslogic (2.0.9)
sexp_processor (4.4.0)
shoulda-matchers (2.1.0)
shoulda-matchers (2.7.0)
activesupport (>= 3.0.0)
sidekiq (3.3.0)
celluloid (>= 0.16.0)
......@@ -518,7 +520,7 @@ GEM
slim (2.0.2)
temple (~> 0.6.6)
tilt (>= 1.3.3, < 2.1)
slop (3.4.7)
slop (3.6.0)
spinach (0.8.7)
colorize (= 0.5.8)
gherkin-ruby (>= 0.3.1)
......@@ -694,7 +696,7 @@ DEPENDENCIES
org-ruby (= 0.9.12)
pg
poltergeist (~> 1.5.1)
pry
pry-rails
quiet_assets (~> 1.0.1)
rack-attack
rack-cors
......@@ -702,7 +704,6 @@ DEPENDENCIES
rack-oauth2 (~> 1.0.5)
rails (~> 4.1.0)
rails_autolink (~> 1.1)
rails_best_practices
raphael-rails (~> 2.1.2)
rb-fsevent
rb-inotify
......@@ -711,6 +712,7 @@ DEPENDENCIES
redis-rails
request_store
rspec-rails
rubocop (= 0.28.0)
rugments
sanitize (~> 2.0)
sass-rails (~> 4.0.2)
......@@ -719,7 +721,7 @@ DEPENDENCIES
select2-rails
semantic-ui-sass (~> 1.8.0)
settingslogic
shoulda-matchers (~> 2.1.0)
shoulda-matchers (~> 2.7.0)
sidekiq (~> 3.3)
simplecov
sinatra
......
......@@ -9,8 +9,6 @@ class @calendar
cal.init
itemName: ["commit"]
data: timestamps
domain: "year"
subDomain: "month"
start: new Date(starting_year, starting_month)
domainLabelFormat: "%b"
id: "cal-heatmap"
......
......@@ -24,3 +24,18 @@ $ ->
$(window).resize ->
responsive_resize()
return
$(document).on("click", '.toggle-nav-collapse', (e) ->
e.preventDefault()
collapsed = 'page-sidebar-collapsed'
expanded = 'page-sidebar-expanded'
if $('.page-with-sidebar').hasClass(collapsed)
$('.page-with-sidebar').removeClass(collapsed).addClass(expanded)
$('.toggle-nav-collapse i').removeClass('fa-angle-right').addClass('fa-angle-left')
$.cookie("collapsed_nav", "false", { path: '/' })
else
$('.page-with-sidebar').removeClass(expanded).addClass(collapsed)
$('.toggle-nav-collapse i').removeClass('fa-angle-left').addClass('fa-angle-right')
$.cookie("collapsed_nav", "true", { path: '/' })
)
......@@ -15,6 +15,10 @@
&.s24 { margin-right: 4px; }
}
&.avatar-tile {
@include border-radius(0px);
}
&.s16 { width: 16px; height: 16px; margin-right: 6px; }
&.s24 { width: 24px; height: 24px; margin-right: 8px; }
&.s26 { width: 26px; height: 26px; margin-right: 8px; }
......
......@@ -97,7 +97,17 @@
.dash-project-avatar {
float: left;
.avatar {
margin-top: -8px;
margin-left: -15px;
@include border-radius(0px);
}
.identicon {
line-height: 40px;
}
}
.dash-project-access-icon {
float: left;
margin-right: 5px;
......
......@@ -40,12 +40,12 @@
font-size: $code_font_size;
.old {
span.idiff {
background-color: #F99;
background-color: #f8cbcb;
}
}
.new {
span.idiff {
background-color: #8F8;
background-color: #a6f3a6;
}
}
.unfold {
......@@ -84,7 +84,7 @@
padding: 0px;
border: none;
background: #F5F5F5;
color: #666;
color: rgba(0,0,0,0.3);
padding: 0px 5px;
border-right: 1px solid #ccc;
text-align: right;
......@@ -96,7 +96,7 @@
float: left;
width: 35px;
font-weight: normal;
color: #666;
color: rgba(0,0,0,0.3);
&:hover {
text-decoration: underline;
}
......@@ -114,13 +114,13 @@
.line_holder {
&.old .old_line,
&.old .new_line {
background: #FCC;
border-color: #E7BABA;
background: #ffdddd;
border-color: #f1c0c0;
}
&.new .old_line,
&.new .new_line {
background: #CFC;
border-color: #B9ECB9;
background: #dbffdb;
border-color: #c1e9c1;
}
}
.line_content {
......@@ -129,10 +129,10 @@
padding: 0px 0.5em;
border: none;
&.new {
background: #CFD;
background: #eaffea;
}
&.old {
background: #FDD;
background: #ffecec;
}
&.matched {
color: #ccc;
......
.page-with-sidebar {
background: #F5F5F5;
......@@ -101,9 +99,7 @@
}
@mixin expanded-sidebar {
.page-with-sidebar {
padding-left: $sidebar_width;
}
padding-left: $sidebar_width;
.sidebar-wrapper {
width: $sidebar_width;
......@@ -122,9 +118,7 @@
}
@mixin folded-sidebar {
.page-with-sidebar {
padding-left: 50px;
}
padding-left: 50px;
.sidebar-wrapper {
width: 52px;
......@@ -150,10 +144,33 @@
}
}
.collapse-nav a {
position: fixed;
bottom: 15px;
padding: 10px;
background: #DDD;
}
@media (max-width: $screen-md-max) {
@include folded-sidebar;
.page-sidebar-collapsed {
@include folded-sidebar;
}
.page-sidebar-expanded {
@include folded-sidebar;
}
.collapse-nav {
display: none;
}
}
@media(min-width: $screen-md-max) {
@include expanded-sidebar;
.page-sidebar-collapsed {
@include folded-sidebar;
}
.page-sidebar-expanded {
@include expanded-sidebar;
}
}
......@@ -23,7 +23,7 @@ class GithubImportsController < ApplicationController
end
def jobs
jobs = current_user.created_projects.where(import_type: "github").to_json(:only => [:id, :import_status])
jobs = current_user.created_projects.where(import_type: "github").to_json(only: [:id, :import_status])
render json: jobs
end
......@@ -58,7 +58,7 @@ class GithubImportsController < ApplicationController
def octo_client
Octokit.auto_paginate = true
@octo_client ||= Octokit::Client.new(:access_token => current_user.github_access_token)
@octo_client ||= Octokit::Client.new(access_token: current_user.github_access_token)
end
def github_auth
......
......@@ -15,4 +15,3 @@ class NamespacesController < ApplicationController
end
end
end
......@@ -59,8 +59,7 @@ class Projects::BlobController < Projects::ApplicationController
def preview
@content = params[:content]
diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3',
include_diff_info: true)
diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3', include_diff_info: true)
@diff_lines = Gitlab::Diff::Parser.new.parse(diffy.diff.scan(/.*\n/))
render layout: false
......
......@@ -11,8 +11,6 @@ class Projects::CommitController < Projects::ApplicationController
return git_not_found! unless @commit
@line_notes = @project.notes.for_commit_id(commit.id).inline
@branches = @project.repository.branch_names_contains(commit.id)
@tags = @project.repository.tag_names_contains(commit.id)
@diffs = @commit.diffs
@note = @project.build_commit_note(commit)
@notes_count = @project.notes.for_commit_id(commit.id).count
......@@ -31,6 +29,12 @@ class Projects::CommitController < Projects::ApplicationController
end
end
def branches
@branches = @project.repository.branch_names_contains(commit.id)
@tags = @project.repository.tag_names_contains(commit.id)
render layout: false
end
def commit
@commit ||= @project.repository.commit(params[:id])
end
......
......@@ -35,4 +35,3 @@ class Projects::RawController < Projects::ApplicationController
end
end
end
......@@ -31,10 +31,10 @@ class Projects::RefsController < Projects::ApplicationController
def logs_tree
@offset = if params[:offset].present?
params[:offset].to_i
else
0
end
params[:offset].to_i
else
0
end
@limit = 25
......
......@@ -16,16 +16,16 @@ class Projects::WikisController < Projects::ApplicationController
if @page
render 'show'
elsif file = @project_wiki.find_file(params[:id], params[:version_id])
if file.on_disk?
send_file file.on_disk_path, disposition: 'inline'
else
send_data(
file.raw_data,
type: file.mime_type,
disposition: 'inline',
filename: file.name
)
end
if file.on_disk?
send_file file.on_disk_path, disposition: 'inline'
else
send_data(
file.raw_data,
type: file.mime_type,
disposition: 'inline',
filename: file.name
)
end
else
return render('empty') unless can?(current_user, :write_wiki, @project)
@page = WikiPage.new(@project_wiki)
......
......@@ -27,7 +27,7 @@ class SnippetsController < ApplicationController
@snippets = SnippetsFinder.new.execute(current_user, {
filter: :by_user,
user: @user,
scope: params[:scope]}).
scope: params[:scope] }).
page(params[:page]).per(20)
if @user == current_user
......
......@@ -28,13 +28,10 @@ class UsersController < ApplicationController
def calendar
visible_projects = ProjectsFinder.new.execute(current_user)
# Get user repositories and collect timestamps for commits
user_repositories = visible_projects.map(&:repository)
calendar = Gitlab::CommitsCalendar.new(user_repositories, @user)
calendar = Gitlab::CommitsCalendar.new(visible_projects, @user)
@timestamps = calendar.timestamps
@starting_year = (Time.now - 1.year).strftime("%Y")
@starting_month = Date.today.strftime("%m").to_i
@starting_year = calendar.starting_year
@starting_month = calendar.starting_month
render 'calendar', layout: false
end
......
......@@ -7,18 +7,19 @@ class NotesFinder
# Default to 0 to remain compatible with old clients
last_fetched_at = Time.at(params.fetch(:last_fetched_at, 0).to_i)
notes = case target_type
when "commit"
project.notes.for_commit_id(target_id).not_inline.fresh
when "issue"
project.issues.find(target_id).notes.inc_author.fresh
when "merge_request"
project.merge_requests.find(target_id).mr_and_commit_notes.inc_author.fresh
when "snippet", "project_snippet"
project.snippets.find(target_id).notes.fresh
else
raise 'invalid target_type'
end
notes =
case target_type
when "commit"
project.notes.for_commit_id(target_id).not_inline.fresh
when "issue"
project.issues.find(target_id).notes.inc_author.fresh
when "merge_request"
project.merge_requests.find(target_id).mr_and_commit_notes.inc_author.fresh
when "snippet", "project_snippet"
project.snippets.find(target_id).notes.fresh
else
raise 'invalid target_type'
end
# Use overlapping intervals to avoid worrying about race conditions
notes.where('updated_at > ?', last_fetched_at - FETCH_OVERLAP)
......
......@@ -40,7 +40,7 @@ class SnippetsFinder
when 'are_public' then
snippets.are_public
else
snippets
snippets
end
else
snippets.public_and_internal
......
......@@ -75,10 +75,10 @@ module ApplicationHelper
options[:class] ||= ''
options[:class] << ' identicon'
bg_key = project.id % 7
style = "background-color: ##{ allowed_colors.values[bg_key] }; color: #555"
content_tag(:div, class: options[:class],
style: "background-color: ##{ allowed_colors.values[bg_key] }; color: #555") do
project.name[0, 1].upcase
content_tag(:div, class: options[:class], style: style) do
project.name[0, 1].upcase
end
end
......@@ -247,15 +247,6 @@ module ApplicationHelper
Gitlab::MarkdownHelper.gitlab_markdown?(filename)
end
def spinner(text = nil, visible = false)
css_class = 'loading'
css_class << ' hide' unless visible
content_tag :div, class: css_class do
content_tag(:i, nil, class: 'fa fa-spinner fa-spin') + text
end
end
def link_to(name = nil, options = nil, html_options = nil, &block)
begin
uri = URI(options)
......@@ -324,4 +315,12 @@ module ApplicationHelper
profile_key_path(key)
end
end
def nav_sidebar_class
if nav_menu_collapsed?
"page-sidebar-collapsed"
else
"page-sidebar-expanded"
end
end
end
......@@ -65,8 +65,7 @@ module CommitsHelper
branches.sort.map do |branch|
link_to(project_tree_path(project, branch)) do
content_tag :span, class: 'label label-gray' do
content_tag(:i, nil, class: 'fa fa-code-fork') + ' ' +
branch
icon('code-fork') + ' ' + branch
end
end
end.join(" ").html_safe
......@@ -78,8 +77,7 @@ module CommitsHelper
sorted.map do |tag|
link_to(project_commits_path(project, project.repository.find_tag(tag).name)) do
content_tag :span, class: 'label label-gray' do
content_tag(:i, nil, class: 'fa fa-tag') + ' ' +
tag
icon('tag') + ' ' + tag
end
end
end.join(" ").html_safe
......@@ -114,12 +112,13 @@ module CommitsHelper
person_name = user.nil? ? source_name : user.name
person_email = user.nil? ? source_email : user.email
text = if options[:avatar]
avatar = image_tag(avatar_icon(person_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "")
%Q{#{avatar} <span class="commit-#{options[:source]}-name">#{person_name}</span>}
else
person_name
end
text =
if options[:avatar]
avatar = image_tag(avatar_icon(person_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "")
%Q{#{avatar} <span class="commit-#{options[:source]}-name">#{person_name}</span>}
else
person_name
end
options = {
class: "commit-#{options[:source]}-link has_tooltip",
......
module CompareHelper
def compare_to_mr_button?
@project.merge_requests_enabled &&
params[:from].present? &&
params[:from].present? &&
params[:to].present? &&
@repository.branch_names.include?(params[:from]) &&
@repository.branch_names.include?(params[:to]) &&
......@@ -10,6 +10,6 @@ module CompareHelper
end
def compare_mr_path
new_project_merge_request_path(@project, merge_request: {source_branch: params[:to], target_branch: params[:from]})
new_project_merge_request_path(@project, merge_request: { source_branch: params[:to], target_branch: params[:from] })
end
end
......@@ -31,7 +31,7 @@ module EmailsHelper
end
def add_email_highlight_css
Rugments::Themes::Github.render(:scope => '.highlight')
Rugments::Themes::Github.render(scope: '.highlight')
end
def color_email_diff(diffcontent)
......
......@@ -27,18 +27,17 @@ module EventsHelper
content_tag :li, class: "filter_icon #{active}" do
link_to request.path, class: 'has_tooltip event_filter_link', id: "#{key}_event_filter", 'data-original-title' => tooltip do
content_tag(:i, nil, class: icon_for_event[key]) +
content_tag(:span, ' ' + tooltip)
icon(icon_for_event[key]) + content_tag(:span, ' ' + tooltip)
end
end
end
def icon_for_event
{
EventFilter.push => 'fa fa-upload',
EventFilter.merged => 'fa fa-check-square-o',
EventFilter.comments => 'fa fa-comments',
EventFilter.team => 'fa fa-user',
EventFilter.push => 'upload',
EventFilter.merged => 'check-square-o',
EventFilter.comments => 'comments',
EventFilter.team => 'user',
}
end
......
module IconsHelper
# Creates an icon tag given icon name(s) and possible icon modifiers.
#
# Right now this method simply delegates directly to `fa_icon` from the
# font-awesome-rails gem, but should we ever use a different icon pack in the
# future we won't have to change hundreds of method calls.
def icon(names, options = {})
fa_icon(names, options)
end
def spinner(text = nil, visible = false)
css_class = 'loading'
css_class << ' hide' unless visible
content_tag :div, class: css_class do
icon('spinner spin') + text
end
end
def boolean_to_icon(value)
if value.to_s == "true"
content_tag :i, nil, class: 'fa fa-circle cgreen'
icon('circle', class: 'cgreen')
else
content_tag :i, nil, class: 'fa fa-power-off clgray'
icon('power-off', class: 'clgray')
end
end
def public_icon
content_tag :i, nil, class: 'fa fa-globe'
icon('globe')
end
def internal_icon
content_tag :i, nil, class: 'fa fa-shield'
icon('shield')
end
def private_icon
content_tag :i, nil, class: 'fa fa-lock'
icon('lock')
end
end
......@@ -49,7 +49,7 @@ module IssuesHelper
ts << capture_haml do
haml_tag :span do
haml_concat '&middot;'
haml_concat '<i class="fa fa-edit" title="edited"></i> '
haml_concat icon('edit', title: 'edited')
haml_concat time_ago_with_tooltip(issue.updated_at, 'bottom', 'issue_edited_ago')
end
end
......
......@@ -15,11 +15,13 @@ module MergeRequestsHelper
end
def new_mr_from_push_event(event, target_project)
return :merge_request => {
source_project_id: event.project.id,
target_project_id: target_project.id,
source_branch: event.branch_name,
target_branch: target_project.repository.root_ref
return {
merge_request: {
source_project_id: event.project.id,
target_project_id: target_project.id,
source_branch: event.branch_name,
target_branch: target_project.repository.root_ref
}
}
end
......
module NavHelper
def nav_menu_collapsed?
cookies[:collapsed_nav] == 'true'
end
end
module NotesHelper
# Helps to distinguish e.g. commit notes in mr notes list
# Helps to distinguish e.g. commit notes in mr notes list
def note_for_main_target?(note)
(@noteable.class.name == note.noteable_type && !note.for_diff_line?)
end
......@@ -22,7 +22,7 @@ module NotesHelper
ts << capture_haml do
haml_tag :span do
haml_concat '&middot;'
haml_concat '<i class="fa fa-edit" title="edited"></i> '
haml_concat icon('edit', title: 'edited')
haml_concat time_ago_with_tooltip(note.updated_at, 'bottom', 'note_edited_ago')
end
end
......@@ -57,7 +57,7 @@ module NotesHelper
button_tag(class: 'btn add-diff-note js-add-diff-note-button',
data: data,
title: 'Add a comment to this line') do
content_tag :i, nil, class: 'fa fa-comment-o'
icon('comment-o')
end
end
......@@ -74,7 +74,7 @@ module NotesHelper
button_tag class: 'btn reply-btn js-discussion-reply-button',
data: data, title: 'Add a reply' do
link_text = content_tag(:i, nil, class: 'fa fa-comment')
link_text = icon('comment')
link_text << ' Reply'
end
end
......
module NotificationsHelper
def notification_icon(notification)
if notification.disabled?
content_tag :i, nil, class: 'fa fa-volume-off ns-mute'
icon('volume-off', class: 'ns-mute')
elsif notification.participating?
content_tag :i, nil, class: 'fa fa-volume-down ns-part'
icon('volume-down', class: 'ns-part')
elsif notification.watch?
content_tag :i, nil, class: 'fa fa-volume-up ns-watch'
icon('volume-up', class: 'ns-watch')
else
content_tag :i, nil, class: 'fa fa-circle-o ns-default'
icon('circle-o', class: 'ns-default')
end
end
end
......@@ -83,7 +83,7 @@ module ProjectsHelper
' Star'
end
content_tag('i', ' ', class: 'fa fa-star') + toggle_text
icon('star') + toggle_text
end
count_html = content_tag('span', class: 'count') do
......@@ -95,7 +95,7 @@ module ProjectsHelper
class: cls,
method: :post,
remote: true,
data: {type: 'json'}
data: { type: 'json' }
}
......@@ -107,7 +107,7 @@ module ProjectsHelper
end
def link_to_toggle_fork
out = content_tag(:i, '', class: 'fa fa-code-fork')
out = icon('code-fork')
out << ' Fork'
out << content_tag(:span, class: 'count') do
@project.forks_count.to_s
......@@ -254,4 +254,3 @@ module ProjectsHelper
enabled_oauth_providers.include?(:github)
end
end
......@@ -90,7 +90,7 @@ module TabHelper
return "active" if current_page?(controller: "/projects", action: :edit, id: @project)
if ['services', 'hooks', 'deploy_keys', 'team_members', 'protected_branches'].include? controller.controller_name
"active"
"active"
end
end
......
......@@ -38,13 +38,8 @@ module TreeHelper
#
# type - String type of the tree item; either 'folder' or 'file'
def tree_icon(type)
icon_class = if type == 'folder'
'fa fa-folder'
else
'fa fa-file-o'
end
content_tag :i, nil, class: icon_class
icon_class = type == 'folder' ? 'folder' : 'file-o'
icon(icon_class)
end
def tree_hex_class(content)
......
......@@ -15,7 +15,8 @@
#
class ApplicationSetting < ActiveRecord::Base
validates :home_page_url, allow_blank: true,
validates :home_page_url,
allow_blank: true,
format: { with: URI::regexp(%w(http https)), message: "should be a valid url" },
if: :home_page_url_column_exist
......
......@@ -88,11 +88,12 @@ class Commit
# cut off, ellipses (`&hellp;`) are prepended to the commit message.
def description
title_end = safe_message.index("\n")
@description ||= if (!title_end && safe_message.length > 100) || (title_end && title_end > 100)
"&hellip;".html_safe << safe_message[80..-1]
else
safe_message.split("\n", 2)[1].try(:chomp)
end
@description ||=
if (!title_end && safe_message.length > 100) || (title_end && title_end > 100)
"&hellip;".html_safe << safe_message[80..-1]
else
safe_message.split("\n", 2)[1].try(:chomp)
end
end
def description?
......
......@@ -44,11 +44,11 @@ class WebHook < ActiveRecord::Base
}
WebHook.post(post_url,
body: data.to_json,
headers: {"Content-Type" => "application/json"},
headers: { "Content-Type" => "application/json" },
verify: false,
basic_auth: auth)
end
rescue SocketError, Errno::ECONNREFUSED, Net::OpenTimeout => e
rescue SocketError, Errno::ECONNRESET, Errno::ECONNREFUSED, Net::OpenTimeout => e
logger.error("WebHook Error => #{e}")
false
end
......
......@@ -11,5 +11,5 @@
class Identity < ActiveRecord::Base
belongs_to :user
validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider}
validates :extern_uid, allow_blank: true, uniqueness: { scope: :provider }
end
......@@ -76,7 +76,7 @@ class MergeRequest < ActiveRecord::Base
merge_request.save
end
after_transition :locked => (any - :locked) do |merge_request, transition|
after_transition locked: (any - :locked) do |merge_request, transition|
merge_request.locked_at = nil
merge_request.save
end
......
......@@ -20,15 +20,20 @@ class Namespace < ActiveRecord::Base
belongs_to :owner, class_name: "User"
validates :owner, presence: true, unless: ->(n) { n.type == "Group" }
validates :name, presence: true, uniqueness: true,
length: { within: 0..255 },
format: { with: Gitlab::Regex.name_regex,
message: Gitlab::Regex.name_regex_message }
validates :name,
presence: true, uniqueness: true,
length: { within: 0..255 },
format: { with: Gitlab::Regex.name_regex,
message: Gitlab::Regex.name_regex_message }
validates :description, length: { within: 0..255 }
validates :path, uniqueness: { case_sensitive: false }, presence: true, length: { within: 1..255 },
exclusion: { in: Gitlab::Blacklist.path },
format: { with: Gitlab::Regex.path_regex,
message: Gitlab::Regex.path_regex_message }
validates :path,
uniqueness: { case_sensitive: false },
presence: true,
length: { within: 1..255 },
exclusion: { in: Gitlab::Blacklist.path },
format: { with: Gitlab::Regex.path_regex,
message: Gitlab::Regex.path_regex_message }
delegate :name, to: :owner, allow_nil: true, prefix: true
......
......@@ -14,7 +14,7 @@
# merge_requests_enabled :boolean default(TRUE), not null
# wiki_enabled :boolean default(TRUE), not null
# namespace_id :integer
# issues_tracker :string(255) default('gitlab'), not null
# issues_tracker :string(255) default("gitlab"), not null
# issues_tracker_id :string(255)
# snippets_enabled :boolean default(TRUE), not null
# last_activity_at :datetime
......@@ -108,13 +108,17 @@ class Project < ActiveRecord::Base
# Validations
validates :creator, presence: true, on: :create
validates :description, length: { maximum: 2000 }, allow_blank: true
validates :name, presence: true, length: { within: 0..255 },
format: { with: Gitlab::Regex.project_name_regex,
message: Gitlab::Regex.project_regex_message }
validates :path, presence: true, length: { within: 0..255 },
exclusion: { in: Gitlab::Blacklist.path },
format: { with: Gitlab::Regex.path_regex,
message: Gitlab::Regex.path_regex_message }
validates :name,
presence: true,
length: { within: 0..255 },
format: { with: Gitlab::Regex.project_name_regex,
message: Gitlab::Regex.project_regex_message }
validates :path,
presence: true,
length: { within: 0..255 },
exclusion: { in: Gitlab::Blacklist.path },
format: { with: Gitlab::Regex.path_regex,
message: Gitlab::Regex.path_regex_message }
validates :issues_enabled, :merge_requests_enabled,
:wiki_enabled, inclusion: { in: [true, false] }
validates :visibility_level,
......@@ -156,22 +160,22 @@ class Project < ActiveRecord::Base
end
event :import_finish do
transition :started => :finished
transition started: :finished
end
event :import_fail do
transition :started => :failed
transition started: :failed
end
event :import_retry do
transition :failed => :started
transition failed: :started
end
state :started
state :finished
state :failed
after_transition any => :started, :do => :add_import_job
after_transition any => :started, do: :add_import_job
end
class << self
......
class ProjectContributions
attr_reader :project, :user
def initialize(project, user)
@project, @user = project, user
end
def commits_log
repository = project.repository
if !repository.exists? || repository.empty?
return {}
end
Rails.cache.fetch(cache_key) do
repository.commits_per_day_for_user(user)
end
end
def cache_key
"#{Date.today.to_s}-commits-log-#{project.id}-#{user.email}"
end
end
......@@ -17,13 +17,19 @@ class BambooService < CiService
prop_accessor :bamboo_url, :build_key, :username, :password
validates :bamboo_url, presence: true,
format: { with: URI::regexp }, if: :activated?
validates :bamboo_url,
presence: true,
format: { with: URI::regexp },
if: :activated?
validates :build_key, presence: true, if: :activated?
validates :username, presence: true,
if: ->(service) { service.password? }, if: :activated?
validates :password, presence: true,
if: ->(service) { service.username? }, if: :activated?
validates :username,
presence: true,
if: ->(service) { service.password? },
if: :activated?
validates :password,
presence: true,
if: ->(service) { service.username? },
if: :activated?
attr_accessor :response
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
#
class CustomIssueTrackerService < IssueTrackerService
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
......@@ -27,8 +41,8 @@ class CustomIssueTrackerService < IssueTrackerService
{ type: 'text', name: 'title', placeholder: title },
{ type: 'text', name: 'description', placeholder: description },
{ type: 'text', name: 'project_url', placeholder: 'Project url' },
{ type: 'text', name: 'issues_url', placeholder: 'Issue url'},
{ type: 'text', name: 'new_issue_url', placeholder: 'New Issue url'}
{ type: 'text', name: 'issues_url', placeholder: 'Issue url' },
{ type: 'text', name: 'new_issue_url', placeholder: 'New Issue url' }
]
end
......
......@@ -81,7 +81,7 @@ class GitlabCiService < CiService
def fields
[
{ type: 'text', name: 'token', placeholder: 'GitLab CI project specific token' },
{ type: 'text', name: 'project_url', placeholder: 'http://ci.gitlabhq.com/projects/3'}
{ type: 'text', name: 'project_url', placeholder: 'http://ci.gitlabhq.com/projects/3' }
]
end
end
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
#
class GitlabIssueTrackerService < IssueTrackerService
include Rails.application.routes.url_helpers
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
#
class IssueTrackerService < Service
validates :project_url, :issues_url, :new_issue_url, presence: true, if: :activated?
......@@ -30,8 +44,8 @@ class IssueTrackerService < Service
[
{ type: 'text', name: 'description', placeholder: description },
{ type: 'text', name: 'project_url', placeholder: 'Project url' },
{ type: 'text', name: 'issues_url', placeholder: 'Issue url'},
{ type: 'text', name: 'new_issue_url', placeholder: 'New Issue url'}
{ type: 'text', name: 'issues_url', placeholder: 'Issue url' },
{ type: 'text', name: 'new_issue_url', placeholder: 'New Issue url' }
]
end
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
#
class JiraService < IssueTrackerService
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
#
class RedmineService < IssueTrackerService
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
......
......@@ -17,13 +17,16 @@ class TeamcityService < CiService
prop_accessor :teamcity_url, :build_type, :username, :password
validates :teamcity_url, presence: true,
format: { with: URI::regexp }, if: :activated?
validates :teamcity_url,
presence: true,
format: { with: URI::regexp }, if: :activated?
validates :build_type, presence: true, if: :activated?
validates :username, presence: true,
if: ->(service) { service.password? }, if: :activated?
validates :password, presence: true,
if: ->(service) { service.username? }, if: :activated?
validates :username,
presence: true,
if: ->(service) { service.password? }, if: :activated?
validates :password,
presence: true,
if: ->(service) { service.username? }, if: :activated?
attr_accessor :response
......
......@@ -136,7 +136,7 @@ class ProjectWiki
def commit_details(action, message = nil, title = nil)
commit_message = message || default_message(action, title)
{email: @user.email, name: @user.name, message: commit_message}
{ email: @user.email, name: @user.name, message: commit_message }
end
def default_message(action, title)
......
......@@ -30,7 +30,7 @@ class Repository
commit = Gitlab::Git::Commit.find(raw_repository, id)
commit = Commit.new(commit) if commit
commit
rescue Rugged::OdbError => ex
rescue Rugged::OdbError
nil
end
......@@ -61,25 +61,25 @@ class Repository
end
def add_branch(branch_name, ref)
Rails.cache.delete(cache_key(:branch_names))
cache.expire(:branch_names)
gitlab_shell.add_branch(path_with_namespace, branch_name, ref)
end
def add_tag(tag_name, ref, message = nil)
Rails.cache.delete(cache_key(:tag_names))
cache.expire(:tag_names)
gitlab_shell.add_tag(path_with_namespace, tag_name, ref, message)
end
def rm_branch(branch_name)
Rails.cache.delete(cache_key(:branch_names))
cache.expire(:branch_names)
gitlab_shell.rm_branch(path_with_namespace, branch_name)
end
def rm_tag(tag_name)
Rails.cache.delete(cache_key(:tag_names))
cache.expire(:tag_names)
gitlab_shell.rm_tag(path_with_namespace, tag_name)
end
......@@ -97,19 +97,15 @@ class Repository
end
def branch_names
Rails.cache.fetch(cache_key(:branch_names)) do
raw_repository.branch_names
end
cache.fetch(:branch_names) { raw_repository.branch_names }
end
def tag_names
Rails.cache.fetch(cache_key(:tag_names)) do
raw_repository.tag_names
end
cache.fetch(:tag_names) { raw_repository.tag_names }
end
def commit_count
Rails.cache.fetch(cache_key(:commit_count)) do
cache.fetch(:commit_count) do
begin
raw_repository.commit_count(self.root_ref)
rescue
......@@ -121,26 +117,19 @@ class Repository
# Return repo size in megabytes
# Cached in redis
def size
Rails.cache.fetch(cache_key(:size)) do
raw_repository.size
end
cache.fetch(:size) { raw_repository.size }
end
def expire_cache
Rails.cache.delete(cache_key(:size))
Rails.cache.delete(cache_key(:branch_names))
Rails.cache.delete(cache_key(:tag_names))
Rails.cache.delete(cache_key(:commit_count))
Rails.cache.delete(cache_key(:graph_log))
Rails.cache.delete(cache_key(:readme))
Rails.cache.delete(cache_key(:version))
Rails.cache.delete(cache_key(:contribution_guide))
%i(size branch_names tag_names commit_count graph_log
readme version contribution_guide).each do |key|
cache.expire(key)
end
end
def graph_log
Rails.cache.fetch(cache_key(:graph_log)) do
commits = raw_repository.log(limit: 6000,
skip_merges: true,
cache.fetch(:graph_log) do
commits = raw_repository.log(limit: 6000, skip_merges: true,
ref: root_ref)
commits.map do |rugged_commit|
......@@ -176,10 +165,6 @@ class Repository
end
end
def cache_key(type)
"#{type}:#{path_with_namespace}"
end
def method_missing(m, *args, &block)
raw_repository.send(m, *args, &block)
end
......@@ -199,13 +184,11 @@ class Repository
end
def readme
Rails.cache.fetch(cache_key(:readme)) do
tree(:head).readme
end
cache.fetch(:readme) { tree(:head).readme }
end
def version
Rails.cache.fetch(cache_key(:version)) do
cache.fetch(:version) do
tree(:head).blobs.find do |file|
file.name.downcase == 'version'
end
......@@ -213,9 +196,7 @@ class Repository
end
def contribution_guide
Rails.cache.fetch(cache_key(:contribution_guide)) do
tree(:head).contribution_guide
end
cache.fetch(:contribution_guide) { tree(:head).contribution_guide }
end
def head_commit
......@@ -351,4 +332,10 @@ class Repository
[]
end
end
private
def cache
@cache ||= RepositoryCache.new(path_with_namespace)
end
end
......@@ -29,9 +29,11 @@ class Snippet < ActiveRecord::Base
validates :author, presence: true
validates :title, presence: true, length: { within: 0..255 }
validates :file_name, presence: true, length: { within: 0..255 },
format: { with: Gitlab::Regex.path_regex,
message: Gitlab::Regex.path_regex_message }
validates :file_name,
presence: true,
length: { within: 0..255 },
format: { with: Gitlab::Regex.path_regex,
message: Gitlab::Regex.path_regex_message }
validates :content, presence: true
validates :visibility_level, inclusion: { in: Gitlab::VisibilityLevel.values }
......
......@@ -113,13 +113,15 @@ class User < ActiveRecord::Base
# Validations
#
validates :name, presence: true
validates :email, presence: true, email: {strict_mode: true}, uniqueness: true
validates :email, presence: true, email: { strict_mode: true }, uniqueness: true
validates :bio, length: { maximum: 255 }, allow_blank: true
validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0}
validates :username, presence: true, uniqueness: { case_sensitive: false },
exclusion: { in: Gitlab::Blacklist.path },
format: { with: Gitlab::Regex.username_regex,
message: Gitlab::Regex.username_regex_message }
validates :projects_limit, presence: true, numericality: { greater_than_or_equal_to: 0 }
validates :username,
presence: true,
uniqueness: { case_sensitive: false },
exclusion: { in: Gitlab::Blacklist.path },
format: { with: Gitlab::Regex.username_regex,
message: Gitlab::Regex.username_regex_message }
validates :notification_level, inclusion: { in: Notification.notification_levels }, presence: true
validate :namespace_uniq, if: ->(user) { user.username_changed? }
......
......@@ -43,7 +43,7 @@ class WikiPage
@attributes[:slug]
end
alias :to_param :slug
alias_method :to_param, :slug
# The formatted title of this page.
def title
......
......@@ -38,4 +38,4 @@ module Oauth2::AccessTokenValidationService
end
end
end
end
\ No newline at end of file
end
......@@ -14,14 +14,14 @@ module Projects
uploader.store!(image)
link = {
'alt' => File.basename(alt, '.*'),
'url' => File.join(@root_url, uploader.url)
'url' => File.join(@root_url, uploader.url)
}
else
link = nil
end
end
protected
protected
def upload_path
base_dir = FileUploader.generate_dir
......
......@@ -5,11 +5,12 @@ module Projects
end
def execute(note_type, note_id)
participating = if note_type && note_id
participants_in(note_type, note_id)
else
[]
end
participating =
if note_type && note_id
participants_in(note_type, note_id)
else
[]
end
team_members = sorted(@project.team.members)
participants = all_members + team_members + participating
participants.uniq
......
......@@ -10,7 +10,8 @@
- groups.each do |group|
%li.group-row
= link_to group_path(id: group.path), class: dom_class(group) do
= image_tag group_icon(group.path), class: "avatar s24"
.dash-project-avatar
= image_tag group_icon(group.path), class: "avatar s40"
%span.group-name.filter-title
= truncate(group.name, length: 35)
%span.arrow
......
= link_to project_path(project), class: dom_class(project) do
.dash-project-avatar
= project_icon(project.to_param, alt: '', class: 'avatar s40')
.dash-project-access-icon
= visibility_level_icon(project.visibility_level)
.dash-project-avatar
= project_icon(project.to_param, alt: '', class: 'avatar s24')
%span.str-truncated
%span.namespace-name
- if project.namespace
......
......@@ -12,10 +12,10 @@
- projects.each do |project|
%li.project-row
= link_to project_path(project), class: dom_class(project) do
.dash-project-avatar
= project_icon(project.to_param, alt: '', class: 'avatar s40')
.dash-project-access-icon
= visibility_level_icon(project.visibility_level)
.dash-project-avatar
= project_icon(project.to_param, alt: '', class: 'avatar s24')
%span.str-truncated
%span.project-name
= project.name
......
.dashboard
%div
= image_tag group_icon(@group.path), class: "avatar s90"
= image_tag group_icon(@group.path), class: "avatar avatar-tile s90"
.clearfix
%h2
= @group.name
......
- if nav_menu_collapsed?
= link_to icon('angle-right'), '#', class: 'toggle-nav-collapse'
- else
= link_to icon('angle-left'), '#', class: 'toggle-nav-collapse'
- if defined?(sidebar)
.page-with-sidebar
.page-with-sidebar{ class: nav_sidebar_class }
= render "layouts/broadcast"
.sidebar-wrapper
= render(sidebar)
.collapse-nav
= render partial: 'layouts/collapse_button'
.content-wrapper
.container-fluid
.content
......
......@@ -37,23 +37,8 @@
- @commit.parents.each do |parent|
= link_to parent.short_id, project_commit_path(@project, parent)
.commit-info-row
- if @branches.any?
%span
- branch = commit_default_branch(@project, @branches)
= link_to(project_tree_path(@project, branch)) do
%span.label.label-gray
%i.fa.fa-code-fork
= branch
- if @branches.any? || @tags.any?
= link_to("#", class: "js-details-expand") do
%span.label.label-gray
\...
%span.js-details-content.hide
- if @branches.any?
= commit_branches_links(@project, @branches)
- if @tags.any?
= commit_tags_links(@project, @tags)
.commit-info-row.branches
%i.fa.fa-spinner.fa-spin
.commit-box
%h3.commit-title
......@@ -61,3 +46,7 @@
- if @commit.description.present?
%pre.commit-description
= preserve(gfm(escape_once(@commit.description)))
:coffeescript
$ ->
$(".commit-info-row.branches").load("#{branches_project_commit_path(@project, @commit.id)}")
\ No newline at end of file
- if @branches.any?
%span
- branch = commit_default_branch(@project, @branches)
= link_to(project_tree_path(@project, branch)) do
%span.label.label-gray
%i.fa.fa-code-fork
= branch
- if @branches.any? || @tags.any?
= link_to("#", class: "js-details-expand") do
%span.label.label-gray
\...
%span.js-details-content.hide
- if @branches.any?
= commit_branches_links(@project, @branches)
- if @tags.any?
= commit_tags_links(@project, @tags)
\ No newline at end of file
......@@ -10,7 +10,7 @@
You can
= link_to project_new_blob_path(@project, 'master'), class: 'btn btn-new btn-lg' do
add a file
&nbsp;or push it via command line.
&nbsp;or do a push via the command line.
%h4
%strong Command line instructions
......
......@@ -13,7 +13,7 @@
= link_to_member(@project, participant, name: false, size: 24)
.voting_notes#notes= render "projects/notes/notes_with_form"
.col-md-3.hidden-sm.hidden-xs
.col-md-3
%div
.clearfix
%span.slead.has_tooltip{:"data-original-title" => 'Cross-project reference'}
......
......@@ -2,23 +2,21 @@
%div.prepend-top-20
%p
Assignee:
- if issue.assignee
= link_to_member(@project, @issue.assignee)
- else
none
- if can?(current_user, :modify_issue, @issue)
= project_users_select_tag('issue[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: @issue.assignee_id)
- elsif issue.assignee
= link_to_member(@project, @issue.assignee)
- else
None
%div.prepend-top-20
%p
Milestone:
- if issue.milestone
#{link_to @issue.milestone.title, project_milestone_path(@project, @issue.milestone)}
- else
none
- if can?(current_user, :modify_issue, @issue)
= f.select(:milestone_id, milestone_options(@issue), { include_blank: "Select milestone" }, {class: 'select2 select2-compact js-select2 js-milestone'})
= hidden_field_tag :issue_context
= f.submit class: 'btn'
- elsif issue.milestone
= link_to project_milestone_path(@project, @issue.milestone) do
= @issue.milestone.title
- else
None
......@@ -3,8 +3,15 @@
:plain
$("##{dom_id(@issue)}").fadeOut();
- elsif params[:issue_context]
$('.context').html("#{escape_javascript(render partial: 'issue_context', locals: { issue: @issue })}");
$('.context').effect('highlight');
- if @issue.milestone
$('.milestone-nav-link').replaceWith("<span class='milestone-nav-link'>| <span class='light'>Milestone</span> #{escape_javascript(link_to @issue.milestone.title, project_milestone_path(@issue.project, @issue.milestone))}</span>")
- else
$('.milestone-nav-link').html('')
$('select.select2').select2({width: 'resolve', dropdownAutoWidth: true})
$('.edit-issue.inline-update input[type="submit"]').hide();
new ProjectUsersSelect();
new Issue();
......@@ -9,7 +9,7 @@
.col-md-9
= render "projects/merge_requests/show/participants"
= render "projects/notes/notes_with_form"
.col-md-3.hidden-sm.hidden-xs
.col-md-3
.clearfix
%span.slead.has_tooltip{:"data-original-title" => 'Cross-project reference'}
= cross_project_reference(@project, @merge_request)
......@@ -18,7 +18,7 @@
%cite.cgray
= render partial: 'projects/merge_requests/show/context', locals: { merge_request: @merge_request }
%hr
.votes-holder.hidden-sm.hidden-xs
.votes-holder
%h6 Votes
#votes= render 'votes/votes_block', votable: @merge_request
......
......@@ -2,22 +2,22 @@
%div.prepend-top-20
%p
Assignee:
- if @merge_request.assignee
= link_to_member(@project, @merge_request.assignee)
- else
none
- if can?(current_user, :modify_merge_request, @merge_request)
= project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: @merge_request.assignee_id)
- elsif merge_request.assignee
= link_to_member(@project, @merge_request.assignee)
- else
None
%div.prepend-top-20
%p
Milestone:
- if @merge_request.milestone
%span.back-to-milestone
#{link_to @merge_request.milestone.title, project_milestone_path(@project, @merge_request.milestone)}
- else
none
- if can?(current_user, :modify_merge_request, @merge_request)
= f.select(:milestone_id, milestone_options(@merge_request), { include_blank: "Select milestone" }, {class: 'select2 select2-compact js-select2 js-milestone'})
= hidden_field_tag :merge_request_context
= f.submit class: 'btn'
- elsif merge_request.milestone
= link_to merge_request.milestone.title, project_milestone_path
- else
None
- if params[:merge_request_context]
$('.context').html("#{escape_javascript(render partial: 'projects/merge_requests/show/context', locals: { issue: @issue })}");
$('.context').effect('highlight');
new ProjectUsersSelect();
$('select.select2').select2({width: 'resolve', dropdownAutoWidth: true});
merge_request = new MergeRequest();
.clearfix
- groups.each do |group|
= link_to group, class: 'profile-groups-avatars', title: group.name do
= image_tag group_icon(group.path), class: 'avatar avatar-inline s40'
= link_to group, class: 'profile-groups-avatars inline', title: group.name do
= image_tag group_icon(group.path), class: 'avatar avatar-tile s40'
%h4 Calendar:
%h4 Calendar
#cal-heatmap.calendar
:javascript
new calendar(
......
.row
.col-md-8
%h3.page-title
= image_tag avatar_icon(@user.email, 90), class: "avatar s90", alt: ''
= image_tag avatar_icon(@user.email, 90), class: "avatar avatar-tile s90", alt: ''
= @user.name
- if @user == current_user
.pull-right
......@@ -15,7 +15,7 @@
.clearfix
- if @groups.any?
%h4 Groups:
%h4 Groups
= render 'groups', groups: @groups
%hr
......@@ -24,7 +24,7 @@
%i.fa.fa-spinner.fa-spin
%hr
%h4
User Activity:
User Activity
- if current_user
%span.rss-icon.pull-right
......
......@@ -70,7 +70,10 @@ module Gitlab
config.middleware.use Rack::Cors do
allow do
origins '*'
resource '/api/*', headers: :any, methods: [:get, :post, :options, :put, :delete]
resource '/api/*',
headers: :any,
methods: [:get, :post, :options, :put, :delete],
expose: ['Link']
end
end
......
......@@ -149,7 +149,7 @@ Settings.gitlab_shell['ssh_path_prefix'] ||= Settings.send(:build_gitlab_shell_s
Settings['backup'] ||= Settingslogic.new({})
Settings.backup['keep_time'] ||= 0
Settings.backup['path'] = File.expand_path(Settings.backup['path'] || "tmp/backups/", Rails.root)
Settings.backup['upload'] ||= Settingslogic.new({'remote_directory' => nil, 'connection' => nil})
Settings.backup['upload'] ||= Settingslogic.new({ 'remote_directory' => nil, 'connection' => nil })
# Convert upload connection settings to use symbol keys, to make Fog happy
if Settings.backup['upload']['connection']
Settings.backup['upload']['connection'] = Hash[Settings.backup['upload']['connection'].map { |k, v| [k.to_sym, v] }]
......
......@@ -9,4 +9,4 @@ if Gitlab::LDAP::Config.enabled?
server = Gitlab.config.ldap.servers.values.first
alias_method server['provider_name'], :ldap
end
end
\ No newline at end of file
end
......@@ -42,11 +42,12 @@ module ActsAsTaggableOn::Taggable
elsif options.delete(:any)
# get tags, drop out if nothing returned (we need at least one)
tags = if options.delete(:wild)
ActsAsTaggableOn::Tag.named_like_any(tag_list)
else
ActsAsTaggableOn::Tag.named_any(tag_list)
end
tags =
if options.delete(:wild)
ActsAsTaggableOn::Tag.named_like_any(tag_list)
else
ActsAsTaggableOn::Tag.named_any(tag_list)
end
return empty_result unless tags.length > 0
......@@ -68,12 +69,12 @@ module ActsAsTaggableOn::Taggable
select_clause = "DISTINCT #{table_name}.*" unless context and tag_types.one?
if owned_by
tagging_join << " AND " +
sanitize_sql([
"#{taggings_alias}.tagger_id = ? AND #{taggings_alias}.tagger_type = ?",
owned_by.id,
owned_by.class.base_class.to_s
])
tagging_join << " AND " +
sanitize_sql([
"#{taggings_alias}.tagger_id = ? AND #{taggings_alias}.tagger_type = ?",
owned_by.id,
owned_by.class.base_class.to_s
])
end
joins << tagging_join
......@@ -92,12 +93,12 @@ module ActsAsTaggableOn::Taggable
tagging_join << " AND " + sanitize_sql(["#{taggings_alias}.context = ?", context.to_s]) if context
if owned_by
tagging_join << " AND " +
sanitize_sql([
"#{taggings_alias}.tagger_id = ? AND #{taggings_alias}.tagger_type = ?",
owned_by.id,
owned_by.class.base_class.to_s
])
tagging_join << " AND " +
sanitize_sql([
"#{taggings_alias}.tagger_id = ? AND #{taggings_alias}.tagger_type = ?",
owned_by.id,
owned_by.class.base_class.to_s
])
end
joins << tagging_join
......
......@@ -12,22 +12,30 @@ if File.exists?(aws_file)
aws_secret_access_key: AWS_CONFIG['secret_access_key'], # required
region: AWS_CONFIG['region'], # optional, defaults to 'us-east-1'
}
config.fog_directory = AWS_CONFIG['bucket'] # required
config.fog_public = false # optional, defaults to true
config.fog_attributes = {'Cache-Control'=>'max-age=315576000'} # optional, defaults to {}
config.fog_authenticated_url_expiration = 1 << 29 # optional time (in seconds) that authenticated urls will be valid.
# when fog_public is false and provider is AWS or Google, defaults to 600
# required
config.fog_directory = AWS_CONFIG['bucket']
# optional, defaults to true
config.fog_public = false
# optional, defaults to {}
config.fog_attributes = { 'Cache-Control'=>'max-age=315576000' }
# optional time (in seconds) that authenticated urls will be valid.
# when fog_public is false and provider is AWS or Google, defaults to 600
config.fog_authenticated_url_expiration = 1 << 29
end
# Mocking Fog requests, based on: https://github.com/carrierwaveuploader/carrierwave/wiki/How-to%3A-Test-Fog-based-uploaders
if Rails.env.test?
Fog.mock!
connection = ::Fog::Storage.new(
:aws_access_key_id => AWS_CONFIG['access_key_id'],
:aws_secret_access_key => AWS_CONFIG['secret_access_key'],
:provider => 'AWS',
:region => AWS_CONFIG['region']
aws_access_key_id: AWS_CONFIG['access_key_id'],
aws_secret_access_key: AWS_CONFIG['secret_access_key'],
provider: 'AWS',
region: AWS_CONFIG['region']
)
connection.directories.create(:key => AWS_CONFIG['bucket'])
connection.directories.create(key: AWS_CONFIG['bucket'])
end
end
......@@ -43,10 +43,10 @@ Doorkeeper.configure do
force_ssl_in_redirect_uri false
# Provide support for an owner to be assigned to each registered application (disabled by default)
# Optional parameter :confirmation => true (default false) if you want to enforce ownership of
# Optional parameter confirmation: true (default false) if you want to enforce ownership of
# a registered application
# Note: you must also run the rails g doorkeeper:application_owner generator to provide the necessary support
enable_application_owner :confirmation => false
enable_application_owner confirmation: false
# Define access token scopes for your provider
# For more information go to
......
......@@ -16,4 +16,4 @@ end
if File.exist?(Gitlab.config.gitlab_shell.path) && !File.exist?(gitlab_shell_symlink)
FileUtils.symlink(secret_file, gitlab_shell_symlink)
end
\ No newline at end of file
end
......@@ -3,9 +3,9 @@ require 'api/api'
Gitlab::Application.routes.draw do
use_doorkeeper do
controllers :applications => 'oauth/applications',
:authorized_applications => 'oauth/authorized_applications',
:authorizations => 'oauth/authorizations'
controllers applications: 'oauth/applications',
authorized_applications: 'oauth/authorized_applications',
authorizations: 'oauth/authorizations'
end
#
# Search
......@@ -177,7 +177,7 @@ Gitlab::Application.routes.draw do
#
# Groups Area
#
resources :groups, constraints: {id: /(?:[^.]|\.(?!atom$))+/, format: /atom/} do
resources :groups, constraints: { id: /(?:[^.]|\.(?!atom$))+/, format: /atom/ } do
member do
get :issues
get :merge_requests
......@@ -215,40 +215,44 @@ Gitlab::Application.routes.draw do
scope module: :projects do
# Blob routes:
get '/new/:id', to: 'blob#new', constraints: {id: /.+/}, as: 'new_blob'
post '/create/:id', to: 'blob#create', constraints: {id: /.+/}, as: 'create_blob'
get '/edit/:id', to: 'blob#edit', constraints: {id: /.+/}, as: 'edit_blob'
put '/update/:id', to: 'blob#update', constraints: {id: /.+/}, as: 'update_blob'
post '/preview/:id', to: 'blob#preview', constraints: {id: /.+/}, as: 'preview_blob'
get '/new/:id', to: 'blob#new', constraints: { id: /.+/ }, as: 'new_blob'
post '/create/:id', to: 'blob#create', constraints: { id: /.+/ }, as: 'create_blob'
get '/edit/:id', to: 'blob#edit', constraints: { id: /.+/ }, as: 'edit_blob'
put '/update/:id', to: 'blob#update', constraints: { id: /.+/ }, as: 'update_blob'
post '/preview/:id', to: 'blob#preview', constraints: { id: /.+/ }, as: 'preview_blob'
resources :blob, only: [:show, :destroy], constraints: { id: /.+/, format: false } do
get :diff, on: :member
end
resources :raw, only: [:show], constraints: {id: /.+/}
resources :tree, only: [:show], constraints: {id: /.+/, format: /(html|js)/ }
resources :raw, only: [:show], constraints: { id: /.+/ }
resources :tree, only: [:show], constraints: { id: /.+/, format: /(html|js)/ }
resource :avatar, only: [:show, :destroy]
resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/}
resources :commits, only: [:show], constraints: {id: /(?:[^.]|\.(?!atom$))+/, format: /atom/}
resources :commit, only: [:show], constraints: { id: /[[:alnum:]]{6,40}/ } do
get :branches, on: :member
end
resources :commits, only: [:show], constraints: { id: /(?:[^.]|\.(?!atom$))+/, format: /atom/ }
resources :compare, only: [:index, :create]
resources :blame, only: [:show], constraints: {id: /.+/}
resources :network, only: [:show], constraints: {id: /(?:[^.]|\.(?!json$))+/, format: /json/}
resources :graphs, only: [:show], constraints: {id: /(?:[^.]|\.(?!json$))+/, format: /json/} do
resources :blame, only: [:show], constraints: { id: /.+/ }
resources :network, only: [:show], constraints: { id: /(?:[^.]|\.(?!json$))+/, format: /json/ }
resources :graphs, only: [:show], constraints: { id: /(?:[^.]|\.(?!json$))+/, format: /json/ } do
member do
get :commits
end
end
get '/compare/:from...:to' => 'compare#show', :as => 'compare',
:constraints => {from: /.+/, to: /.+/}
:constraints => { from: /.+/, to: /.+/ }
resources :snippets, constraints: {id: /\d+/} do
resources :snippets, constraints: { id: /\d+/ } do
member do
get 'raw'
end
end
resources :wikis, only: [:show, :edit, :destroy, :create], constraints: {id: /[a-zA-Z.0-9_\-\/]+/} do
resources :wikis, only: [:show, :edit, :destroy, :create], constraints: { id: /[a-zA-Z.0-9_\-\/]+/ } do
collection do
get :pages
put ':id' => 'wikis#update'
......@@ -275,7 +279,7 @@ Gitlab::Application.routes.draw do
end
end
resources :deploy_keys, constraints: {id: /\d+/} do
resources :deploy_keys, constraints: { id: /\d+/ } do
member do
put :enable
put :disable
......@@ -294,16 +298,14 @@ Gitlab::Application.routes.draw do
member do
# tree viewer logs
get 'logs_tree', constraints: { id: Gitlab::Regex.git_reference_regex }
get 'logs_tree/:path' => 'refs#logs_tree',
as: :logs_file,
constraints: {
id: Gitlab::Regex.git_reference_regex,
path: /.*/
}
get 'logs_tree/:path' => 'refs#logs_tree', as: :logs_file, constraints: {
id: Gitlab::Regex.git_reference_regex,
path: /.*/
}
end
end
resources :merge_requests, constraints: {id: /\d+/}, except: [:destroy] do
resources :merge_requests, constraints: { id: /\d+/ }, except: [:destroy] do
member do
get :diffs
post :automerge
......@@ -318,27 +320,27 @@ Gitlab::Application.routes.draw do
end
end
resources :hooks, only: [:index, :create, :destroy], constraints: {id: /\d+/} do
resources :hooks, only: [:index, :create, :destroy], constraints: { id: /\d+/ } do
member do
get :test
end
end
resources :team, controller: 'team_members', only: [:index]
resources :milestones, except: [:destroy], constraints: {id: /\d+/} do
resources :milestones, except: [:destroy], constraints: { id: /\d+/ } do
member do
put :sort_issues
put :sort_merge_requests
end
end
resources :labels, constraints: {id: /\d+/} do
resources :labels, constraints: { id: /\d+/ } do
collection do
post :generate
end
end
resources :issues, constraints: {id: /\d+/}, except: [:destroy] do
resources :issues, constraints: { id: /\d+/ }, except: [:destroy] do
collection do
post :bulk_update
end
......@@ -355,7 +357,7 @@ Gitlab::Application.routes.draw do
end
end
resources :notes, only: [:index, :create, :destroy, :update], constraints: {id: /\d+/} do
resources :notes, only: [:index, :create, :destroy, :update], constraints: { id: /\d+/ } do
member do
delete :delete_attachment
end
......@@ -364,7 +366,7 @@ Gitlab::Application.routes.draw do
end
end
get ':id' => 'namespaces#show', constraints: {id: /(?:[^.]|\.(?!atom$))+/, format: /atom/}
get ':id' => 'namespaces#show', constraints: { id: /(?:[^.]|\.(?!atom$))+/, format: /atom/ }
root to: 'dashboard#show'
end
......@@ -20,7 +20,7 @@ GET /groups
]
```
You can search for groups by name or path with: `/groups?search=Rails`
You can search for groups by name or path, see below.
## Details of a group
......@@ -32,7 +32,7 @@ GET /groups/:id
Parameters:
- `id` (required) - The ID of a group
- `id` (required) - The ID or path of a group
## New group
......@@ -58,7 +58,7 @@ POST /groups/:id/projects/:project_id
Parameters:
- `id` (required) - The ID of a group
- `id` (required) - The ID or path of a group
- `project_id` (required) - The ID of a project
## Remove group
......@@ -71,7 +71,27 @@ DELETE /groups/:id
Parameters:
- `id` (required) - The ID of a user group
- `id` (required) - The ID or path of a user group
## Search for group
Get all groups that match your string in their name or path.
```
GET /groups?search=foobar
```
```json
[
{
"id": 1,
"name": "Foobar Group",
"path": "foo-bar",
"owner_id": 18,
"description": "An interesting group"
}
]
```
## Group members
......@@ -128,7 +148,7 @@ POST /groups/:id/members
Parameters:
- `id` (required) - The ID of a group
- `id` (required) - The ID or path of a group
- `user_id` (required) - The ID of a user to add
- `access_level` (required) - Project access level
......@@ -142,5 +162,5 @@ DELETE /groups/:id/members/:user_id
Parameters:
- `id` (required) - The ID of a user group
- `id` (required) - The ID or path of a user group
- `user_id` (required) - The ID of a group member
......@@ -278,7 +278,7 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
GitLab Shell is an SSH access and repository management software developed specially for GitLab.
# Run the installation task for gitlab-shell (replace `REDIS_URL` if needed):
sudo -u git -H bundle exec rake gitlab:shell:install[v2.4.1] REDIS_URL=unix:/var/run/redis/redis.sock RAILS_ENV=production
sudo -u git -H bundle exec rake gitlab:shell:install[v2.4.2] REDIS_URL=unix:/var/run/redis/redis.sock RAILS_ENV=production
# By default, the gitlab-shell config is generated from your main GitLab config.
# You can review (and modify) the gitlab-shell config as follows:
......
......@@ -19,19 +19,26 @@ your repositories are located by looking at `config/gitlab.yml` under the `gitla
New folder needs to have git user ownership and read/write/execute access for git user and its group:
```
$ mkdir new_group
$ chown git:git new_group
$ chmod 770 new_group
sudo -u git mkdir /var/opt/gitlab/git-data/repositories/new_group
```
If you are using an installation from source, replace `/var/opt/gitlab/git-data`
with `/home/git`.
### Copy your bare repositories inside this newly created folder:
```
$ cp -r /old/git/foo.git/ /home/git/repositories/new_group/
sudo cp -r /old/git/foo.git /var/opt/gitlab/git-data/repositories/new_group/
# Do this once when you are done copying git repositories
sudo chown -R git:git /var/opt/gitlab/git-data/repositories/new_group/
```
`foo.git` needs to be owned by the git user and git users group.
If you are using an installation from source, replace `/var/opt/gitlab/git-data`
with `/home/git`.
### Run the command below depending on your type of installation:
#### Omnibus Installation
......
......@@ -89,6 +89,9 @@ sudo apt-get install logrotate
# Install pkg-config and cmake, which is needed for the latest versions of rugged
sudo apt-get install pkg-config cmake
# Install Kerberos header files, which are needed for GitLab EE Kerberos support
sudo apt-get install libkrb5-dev
```
## 5. Configure Redis to use sockets
......
......@@ -37,7 +37,7 @@ sudo -u git -H git checkout 7-7-stable-ee
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch
sudo -u git -H git checkout v2.4.1
sudo -u git -H git checkout v2.4.2
```
### 4. Install libs, migrations, etc.
......
......@@ -10,3 +10,4 @@
- [Migrating from SVN to GitLab](migrating_from_svn.md)
- [Project importing from GitHub to GitLab](import_projects_from_github.md)
- [Protected branches](protected_branches.md)
- [Web Editor](web_editor.md)
# GitLab Web Editor
In GitLab you can create new files and edit existing files using our web editor.
This is especially useful if you don't have access to a command line or you just want to do a quick fix.
You can easily access the web editor, depending on the context.
Let's start from newly created project.
Click on `Add a file`
to create the first file and open it in the web editor.
![web editor 1](web_editor/empty_project.png)
Fill in a file name, some content, a commit message and press the commit button.
The file will be saved to the repository.
![web editor 2](web_editor/new_file.png)
You can edit any text file in a repository by pressing the edit button, when
viewing the file.
![web editor 3](web_editor/show_file.png)
Editing a file is almost the same as creating a new file,
with as addition the ability to preview your changes in a separate tab.
![web editor 3](web_editor/edit_file.png)
......@@ -11,7 +11,7 @@ RUN apt-get update -q \
# If the Omnibus package version below is outdated please contribute a merge request to update it.
# If you run GitLab Enterprise Edition point it to a location where you have downloaded it.
RUN TMP_FILE=$(mktemp); \
wget -q -O $TMP_FILE https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab_7.7.1-omnibus.5.4.1.ci-1_amd64.deb \
wget -q -O $TMP_FILE https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab_7.7.2-omnibus.5.4.2.ci-1_amd64.deb \
&& dpkg -i $TMP_FILE \
&& rm -f $TMP_FILE
......
......@@ -34,7 +34,7 @@ Feature: Project Source Browse Files
Then I am redirected to the new file
And I should see its new content
@javascript
@javascript @tricky
Scenario: I can create file in empty repo
Given I own an empty project
And I visit my empty project page
......
......@@ -6,7 +6,7 @@ module API
version 'v3', using: :path
rescue_from ActiveRecord::RecordNotFound do
rack_response({'message' => '404 Not found'}.to_json, 404)
rack_response({ 'message' => '404 Not found' }.to_json, 404)
end
rescue_from :all do |exception|
......@@ -19,7 +19,7 @@ module API
message << " " << trace.join("\n ")
API.logger.add Logger::FATAL, message
rack_response({'message' => '500 Internal Server Error'}, 500)
rack_response({ 'message' => '500 Internal Server Error' }, 500)
end
format :json
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册