Merge branch 'master' into new-sidebar

Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>

Conflicts:
	app/controllers/snippets_controller.rb
This commit is contained in:
Dmitriy Zaporozhets 2015-04-23 12:08:03 +03:00
commit 71f6143552
No known key found for this signature in database
GPG Key ID: 161B5D6A44D3D88A
135 changed files with 3546 additions and 1475 deletions

View File

@ -954,7 +954,7 @@ Lint/Void:
Rails/ActionFilter:
Description: 'Enforces consistent use of action filter methods.'
Enabled: false
Enabled: true
Rails/DefaultScope:
Description: 'Checks if the argument passed to default_scope is a block.'

View File

@ -3,14 +3,16 @@ Please view this file on the master branch, on stable branches it's out of date.
v 7.11.0 (unreleased)
- Fix clone URL field and X11 Primary selection (Dmitry Medvinsky)
- Ignore invalid lines in .gitmodules
- Fix "Cannot move project" error message from popping up after a successful transfer (Stan Hu)
-
-
- Add "Reply quoting selected text" shortcut key (`r`)
-
-
-
-
-
- Improve new project command options (Ben Bodenmiller)
- Prevent sending empty messages to HipChat (Chulki Lee)
v 7.10.0 (unreleased)
- Ignore submodules that are defined in .gitmodules but are checked in as directories.
@ -38,7 +40,6 @@ v 7.10.0 (unreleased)
- Allow HTML tags in Markdown input
- Fix code unfold not working on Compare commits page (Stan Hu)
- Fix generating SSH key fingerprints with OpenSSH 6.8. (Sašo Stanovnik)
- Include missing events and fix save functionality in admin service template settings form (Stan Hu)
- Fix "Import projects from" button to show the correct instructions (Stan Hu)
- Fix dots in Wiki slugs causing errors (Stan Hu)
- Make maximum attachment size configurable via Application Settings (Stan Hu)

11
Gemfile
View File

@ -42,7 +42,7 @@ gem "browser"
gem "gitlab_git", '~> 7.1.10'
# Ruby/Rack Git Smart-HTTP Server Handler
gem 'gitlab-grack', '~> 2.0.0.rc2', require: 'grack'
gem 'gitlab-grack', '~> 2.0.2', require: 'grack'
# LDAP Auth
gem 'gitlab_omniauth-ldap', '1.2.1', require: "omniauth-ldap"
@ -88,7 +88,7 @@ gem "six"
gem "seed-fu"
# Markup pipeline for GitLab
gem 'html-pipeline-gitlab', '~> 0.1'
gem 'html-pipeline', '~> 1.11.0'
# Markdown to HTML
gem "github-markup"
@ -143,7 +143,7 @@ gem "redis-rails"
gem 'tinder', '~> 1.9.2'
# HipChat integration
gem "hipchat", "~> 1.4.0"
gem 'hipchat', '~> 1.5.0'
# Flowdock integration
gem "gitlab-flowdock-git-hook", "~> 0.4.2"
@ -251,12 +251,13 @@ group :development, :test do
# PhantomJS driver for Capybara
gem 'poltergeist', '~> 1.5.1'
gem 'jasmine', '2.0.2'
gem 'jasmine', '~> 2.2.0'
gem 'jasmine-rails'
gem "spring", '~> 1.3.1'
gem "spring-commands-rspec", '1.0.4'
gem "spring-commands-spinach", '1.0.0'
gem "byebug"
end

View File

@ -199,7 +199,7 @@ GEM
gitlab-flowdock-git-hook (0.4.2.2)
gitlab-grit (>= 2.4.1)
multi_json
gitlab-grack (2.0.0)
gitlab-grack (2.0.2)
rack (~> 1.5.1)
gitlab-grit (2.7.2)
charlock_holmes (~> 0.6)
@ -271,20 +271,15 @@ GEM
hashie (2.1.2)
highline (1.6.21)
hike (1.2.3)
hipchat (1.4.0)
hipchat (1.5.0)
httparty
mimemagic
hitimes (1.2.2)
html-pipeline (1.11.0)
activesupport (>= 2)
nokogiri (~> 1.4)
html-pipeline-gitlab (0.2.0)
actionpack (~> 4)
gitlab_emoji (~> 0.1)
html-pipeline (~> 1.11.0)
mime-types
sanitize (~> 2.1)
http_parser.rb (0.5.3)
httparty (0.13.0)
httparty (0.13.3)
json (~> 1.8)
multi_xml (>= 0.5.2)
httpauth (0.2.1)
@ -292,12 +287,17 @@ GEM
i18n (0.7.0)
ice_cube (0.11.1)
ice_nine (0.10.0)
jasmine (2.0.2)
jasmine-core (~> 2.0.0)
jasmine (2.2.0)
jasmine-core (~> 2.2)
phantomjs
rack (>= 1.2.1)
rake
jasmine-core (2.0.0)
jasmine-core (2.2.0)
jasmine-rails (0.10.8)
jasmine-core (>= 1.3, < 3.0)
phantomjs (>= 1.9)
railties (>= 3.2.0)
sprockets-rails
jquery-atwho-rails (0.3.3)
jquery-rails (3.1.0)
railties (>= 3.0, < 5.0)
@ -329,6 +329,7 @@ GEM
mime-types (>= 1.16, < 3)
method_source (0.8.2)
mime-types (1.25.1)
mimemagic (0.3.0)
mini_portile (0.6.1)
minitest (5.3.5)
mousetrap-rails (1.4.6)
@ -391,7 +392,7 @@ GEM
parser (2.2.0.2)
ast (>= 1.1, < 3.0)
pg (0.15.1)
phantomjs (1.9.2.0)
phantomjs (1.9.8.0)
poltergeist (1.5.1)
capybara (~> 2.1)
cliver (~> 0.3.1)
@ -700,7 +701,7 @@ DEPENDENCIES
gemnasium-gitlab-service (~> 0.2)
github-markup
gitlab-flowdock-git-hook (~> 0.4.2)
gitlab-grack (~> 2.0.0.rc2)
gitlab-grack (~> 2.0.2)
gitlab-linguist (~> 3.0.1)
gitlab_emoji (~> 0.1)
gitlab_git (~> 7.1.10)
@ -714,10 +715,11 @@ DEPENDENCIES
guard-rspec
guard-spinach
haml-rails
hipchat (~> 1.4.0)
html-pipeline-gitlab (~> 0.1)
hipchat (~> 1.5.0)
html-pipeline (~> 1.11.0)
httparty
jasmine (= 2.0.2)
jasmine (~> 2.2.0)
jasmine-rails
jquery-atwho-rails (~> 0.3.3)
jquery-rails
jquery-scrollto-rails

View File

@ -38,7 +38,7 @@
#= require shortcuts
#= require shortcuts_navigation
#= require shortcuts_dashboard_navigation
#= require shortcuts_issueable
#= require shortcuts_issuable
#= require shortcuts_network
#= require cal-heatmap
#= require_tree .
@ -173,6 +173,7 @@ $ ->
$(@).closest(".diff-file").find(".notes_holder").toggle()
e.preventDefault()
$(document).off "click", '.js-confirm-danger'
$(document).on "click", '.js-confirm-danger', (e) ->
e.preventDefault()
btn = $(e.target)

View File

@ -8,11 +8,13 @@ class @ConfirmDangerModal
submit = $('.js-confirm-danger-submit')
submit.disable()
$('.js-confirm-danger-input').off 'input'
$('.js-confirm-danger-input').on 'input', ->
if rstrip($(@).val()) is project_path
submit.enable()
else
submit.disable()
$('.js-confirm-danger-submit').off 'click'
$('.js-confirm-danger-submit').on 'click', =>
@form.submit()

View File

@ -22,7 +22,7 @@ class Dispatcher
shortcut_handler = new ShortcutsNavigation()
when 'projects:issues:show'
new Issue()
shortcut_handler = new ShortcutsIssueable()
shortcut_handler = new ShortcutsIssuable()
new ZenMode()
when 'projects:milestones:show'
new Milestone()
@ -47,7 +47,7 @@ class Dispatcher
new IssuableForm($('.merge-request-form'))
when 'projects:merge_requests:show'
new Diff()
shortcut_handler = new ShortcutsIssueable()
shortcut_handler = new ShortcutsIssuable()
new ZenMode()
when "projects:merge_requests:diffs"
new Diff()

View File

@ -0,0 +1,48 @@
#= require jquery
#= require mousetrap
#= require shortcuts_navigation
class @ShortcutsIssuable extends ShortcutsNavigation
constructor: (isMergeRequest) ->
super()
Mousetrap.bind('a', ->
$('.js-assignee').select2('open')
return false
)
Mousetrap.bind('m', ->
$('.js-milestone').select2('open')
return false
)
Mousetrap.bind('r', =>
@replyWithSelectedText()
return false
)
if isMergeRequest
@enabledHelp.push('.hidden-shortcut.merge_requests')
else
@enabledHelp.push('.hidden-shortcut.issues')
replyWithSelectedText: ->
if window.getSelection
selected = window.getSelection().toString()
replyField = $('.js-main-target-form #note_note')
return if selected.trim() == ""
# Put a '>' character before each non-empty line in the selection
quote = _.map selected.split("\n"), (val) ->
"> #{val}\n" if val.trim() != ''
# If replyField already has some content, add a newline before our quote
separator = replyField.val().trim() != "" and "\n" or ''
replyField.val (_, current) ->
current + separator + quote.join('') + "\n"
# Trigger autosave for the added text
replyField.trigger('input')
# Focus the input field
replyField.focus()

View File

@ -1,19 +0,0 @@
#= require shortcuts_navigation
class @ShortcutsIssueable extends ShortcutsNavigation
constructor: (isMergeRequest) ->
super()
Mousetrap.bind('a', ->
$('.js-assignee').select2('open')
return false
)
Mousetrap.bind('m', ->
$('.js-milestone').select2('open')
return false
)
if isMergeRequest
@enabledHelp.push('.hidden-shortcut.merge_reuests')
else
@enabledHelp.push('.hidden-shortcut.issues')

View File

@ -1,3 +1,7 @@
#= require d3
#= require jquery
#= require stat_graph_contributors_util
class @ContributorsStatGraph
init: (log) ->
@parsed_log = ContributorsStatGraphUtil.parse_log(log)

View File

@ -1,3 +1,7 @@
#= require d3
#= require jquery
#= require underscore
class @ContributorsGraph
MARGIN:
top: 20

View File

@ -3,7 +3,7 @@
# Automatically sets the layout and ensures an administrator is logged in
class Admin::ApplicationController < ApplicationController
layout 'admin'
before_filter :authenticate_admin!
before_action :authenticate_admin!
def authenticate_admin!
return render_404 unless current_user.is_admin?

View File

@ -1,5 +1,5 @@
class Admin::ApplicationSettingsController < Admin::ApplicationController
before_filter :set_application_setting
before_action :set_application_setting
def show
end

View File

@ -1,5 +1,5 @@
class Admin::BroadcastMessagesController < Admin::ApplicationController
before_filter :broadcast_messages
before_action :broadcast_messages
def index
@broadcast_message = BroadcastMessage.new

View File

@ -1,13 +1,13 @@
class Admin::DeployKeysController < Admin::ApplicationController
before_filter :deploy_keys, only: [:index]
before_filter :deploy_key, only: [:show, :destroy]
before_action :deploy_keys, only: [:index]
before_action :deploy_key, only: [:show, :destroy]
def index
end
def show
end
def new

View File

@ -1,5 +1,5 @@
class Admin::GroupsController < Admin::ApplicationController
before_filter :group, only: [:edit, :show, :update, :destroy, :project_update, :members_update]
before_action :group, only: [:edit, :show, :update, :destroy, :project_update, :members_update]
def index
@groups = Group.all

View File

@ -1,5 +1,5 @@
class Admin::KeysController < Admin::ApplicationController
before_filter :user, only: [:show, :destroy]
before_action :user, only: [:show, :destroy]
def show
@key = user.keys.find(params[:id])

View File

@ -1,7 +1,7 @@
class Admin::ProjectsController < Admin::ApplicationController
before_filter :project, only: [:show, :transfer]
before_filter :group, only: [:show, :transfer]
before_filter :repository, only: [:show, :transfer]
before_action :project, only: [:show, :transfer]
before_action :group, only: [:show, :transfer]
before_action :repository, only: [:show, :transfer]
def index
@projects = Project.all

View File

@ -1,5 +1,5 @@
class Admin::ServicesController < Admin::ApplicationController
before_filter :service, only: [:edit, :update]
before_action :service, only: [:edit, :update]
def index
@services = services_templates

View File

@ -1,5 +1,5 @@
class Admin::UsersController < Admin::ApplicationController
before_filter :user, only: [:show, :edit, :update, :destroy]
before_action :user, only: [:show, :edit, :update, :destroy]
def index
@users = User.order_name_asc.filter(params[:filter])

View File

@ -6,15 +6,15 @@ class ApplicationController < ActionController::Base
PER_PAGE = 20
before_filter :authenticate_user_from_token!
before_filter :authenticate_user!
before_filter :reject_blocked!
before_filter :check_password_expiration
before_filter :ldap_security_check
before_filter :default_headers
before_filter :add_gon_variables
before_filter :configure_permitted_parameters, if: :devise_controller?
before_filter :require_email, unless: :devise_controller?
before_action :authenticate_user_from_token!
before_action :authenticate_user!
before_action :reject_blocked!
before_action :check_password_expiration
before_action :ldap_security_check
before_action :default_headers
before_action :add_gon_variables
before_action :configure_permitted_parameters, if: :devise_controller?
before_action :require_email, unless: :devise_controller?
protect_from_forgery with: :exception

View File

@ -1,5 +1,5 @@
class Dashboard::MilestonesController < ApplicationController
before_filter :load_projects
before_action :load_projects
def index
project_milestones = case params[:state]

View File

@ -1,5 +1,5 @@
class Dashboard::ProjectsController < ApplicationController
before_filter :event_filter
before_action :event_filter
def starred
@projects = current_user.starred_projects

View File

@ -1,8 +1,8 @@
class DashboardController < ApplicationController
respond_to :html
before_filter :load_projects, except: [:projects]
before_filter :event_filter, only: :show
before_action :load_projects, except: [:projects]
before_action :event_filter, only: :show
def show
@projects = @projects.includes(:namespace)

View File

@ -1,5 +1,5 @@
class Explore::GroupsController < ApplicationController
skip_before_filter :authenticate_user!,
skip_before_action :authenticate_user!,
:reject_blocked, :set_current_user_for_observers
layout "explore"

View File

@ -1,5 +1,5 @@
class Explore::ProjectsController < ApplicationController
skip_before_filter :authenticate_user!,
skip_before_action :authenticate_user!,
:reject_blocked
layout 'explore'

View File

@ -1,10 +1,10 @@
class Groups::GroupMembersController < Groups::ApplicationController
skip_before_filter :authenticate_user!, only: [:index]
before_filter :group
skip_before_action :authenticate_user!, only: [:index]
before_action :group
# Authorize
before_filter :authorize_read_group!
before_filter :authorize_admin_group!, except: [:index, :leave]
before_action :authorize_read_group!
before_action :authorize_admin_group!, except: [:index, :leave]
layout :determine_layout
@ -49,7 +49,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
def resend_invite
redirect_path = group_group_members_path(@group)
@group_member = @group.group_members.find(params[:id])
if @group_member.invite?
@ -63,7 +63,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
def leave
@group_member = @group.group_members.where(user_id: current_user.id).first
if can?(current_user, :destroy_group_member, @group_member)
@group_member.destroy
redirect_to(dashboard_groups_path, notice: "You left #{group.name} group.")

View File

@ -1,7 +1,7 @@
class Groups::MilestonesController < ApplicationController
layout 'group'
before_filter :authorize_group_milestone!, only: :update
before_action :authorize_group_milestone!, only: :update
def index
project_milestones = case params[:state]

View File

@ -1,17 +1,17 @@
class GroupsController < Groups::ApplicationController
skip_before_filter :authenticate_user!, only: [:show, :issues, :merge_requests]
skip_before_action :authenticate_user!, only: [:show, :issues, :merge_requests]
respond_to :html
before_filter :group, except: [:new, :create]
before_action :group, except: [:new, :create]
# Authorize
before_filter :authorize_read_group!, except: [:new, :create]
before_filter :authorize_admin_group!, only: [:edit, :update, :destroy, :projects]
before_filter :authorize_create_group!, only: [:new, :create]
before_action :authorize_read_group!, except: [:new, :create]
before_action :authorize_admin_group!, only: [:edit, :update, :destroy, :projects]
before_action :authorize_create_group!, only: [:new, :create]
# Load group projects
before_filter :load_projects, except: [:new, :create, :projects, :edit, :update]
before_filter :event_filter, only: :show
before_filter :set_title, only: [:new, :create]
before_action :load_projects, except: [:new, :create, :projects, :edit, :update]
before_action :event_filter, only: :show
before_action :set_title, only: [:new, :create]
layout :determine_layout

View File

@ -1,15 +1,15 @@
class Import::BitbucketController < Import::BaseController
before_filter :verify_bitbucket_import_enabled
before_filter :bitbucket_auth, except: :callback
before_action :verify_bitbucket_import_enabled
before_action :bitbucket_auth, except: :callback
rescue_from OAuth::Error, with: :bitbucket_unauthorized
def callback
request_token = session.delete(:oauth_request_token)
request_token = session.delete(:oauth_request_token)
raise "Session expired!" if request_token.nil?
request_token.symbolize_keys!
access_token = client.get_token(request_token, params[:oauth_verifier], callback_import_bitbucket_url)
current_user.bitbucket_access_token = access_token.token
@ -21,7 +21,7 @@ class Import::BitbucketController < Import::BaseController
def status
@repos = client.projects
@already_added_projects = current_user.created_projects.where(import_type: "bitbucket")
already_added_projects_names = @already_added_projects.pluck(:import_source)
@ -41,7 +41,7 @@ class Import::BitbucketController < Import::BaseController
repo_owner = repo["owner"]
repo_owner = current_user.username if repo_owner == client.user["user"]["username"]
@target_namespace = params[:new_namespace].presence || repo_owner
namespace = get_or_create_namespace || (render and return)
unless Gitlab::BitbucketImport::KeyAdder.new(repo, current_user).execute

View File

@ -1,6 +1,6 @@
class Import::GithubController < Import::BaseController
before_filter :verify_github_import_enabled
before_filter :github_auth, except: :callback
before_action :verify_github_import_enabled
before_action :github_auth, except: :callback
rescue_from Octokit::Unauthorized, with: :github_unauthorized
@ -36,7 +36,7 @@ class Import::GithubController < Import::BaseController
repo_owner = repo.owner.login
repo_owner = current_user.username if repo_owner == client.user.login
@target_namespace = params[:new_namespace].presence || repo_owner
namespace = get_or_create_namespace || (render and return)
@project = Gitlab::GithubImport::ProjectCreator.new(repo, namespace, current_user).execute

View File

@ -1,6 +1,6 @@
class Import::GitlabController < Import::BaseController
before_filter :verify_gitlab_import_enabled
before_filter :gitlab_auth, except: :callback
before_action :verify_gitlab_import_enabled
before_action :gitlab_auth, except: :callback
rescue_from OAuth2::Error, with: :gitlab_unauthorized
@ -13,7 +13,7 @@ class Import::GitlabController < Import::BaseController
def status
@repos = client.projects
@already_added_projects = current_user.created_projects.where(import_type: "gitlab")
already_added_projects_names = @already_added_projects.pluck(:import_source)
@ -33,7 +33,7 @@ class Import::GitlabController < Import::BaseController
repo_owner = repo["namespace"]["path"]
repo_owner = current_user.username if repo_owner == client.user["username"]
@target_namespace = params[:new_namespace].presence || repo_owner
namespace = get_or_create_namespace || (render and return)
@project = Gitlab::GitlabImport::ProjectCreator.new(repo, namespace, current_user).execute

View File

@ -1,8 +1,8 @@
class Import::GoogleCodeController < Import::BaseController
before_filter :user_map, only: [:new_user_map, :create_user_map]
before_action :user_map, only: [:new_user_map, :create_user_map]
def new
end
def callback
@ -68,7 +68,7 @@ class Import::GoogleCodeController < Import::BaseController
def status
unless client.valid?
return redirect_to new_import_google_path
return redirect_to new_import_google_code_path
end
@repos = client.repos

View File

@ -1,6 +1,6 @@
class InvitesController < ApplicationController
before_filter :member
skip_before_filter :authenticate_user!, only: :decline
before_action :member
skip_before_action :authenticate_user!, only: :decline
respond_to :html
@ -24,7 +24,7 @@ class InvitesController < ApplicationController
if member.decline_invite!
label, _ = source_info(member.source)
path =
path =
if current_user
dashboard_path
else
@ -41,7 +41,7 @@ class InvitesController < ApplicationController
def member
return @member if defined?(@member)
@token = params[:id]
@member = Member.find_by_invite_token(@token)

View File

@ -1,5 +1,5 @@
class NamespacesController < ApplicationController
skip_before_filter :authenticate_user!
skip_before_action :authenticate_user!
def show
namespace = Namespace.find_by(path: params[:id])

View File

@ -1,5 +1,5 @@
class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
before_filter :authenticate_user!
before_action :authenticate_user!
layout "profile"
def index
@ -10,7 +10,7 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
@application = Doorkeeper::Application.new(application_params)
@application.owner = current_user
if @application.save
flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create])
redirect_to oauth_application_url(@application)

View File

@ -1,5 +1,5 @@
class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController
before_filter :authenticate_resource_owner!
before_action :authenticate_resource_owner!
layout "profile"
def new

View File

@ -1,6 +1,6 @@
class Profiles::KeysController < ApplicationController
layout "profile"
skip_before_filter :authenticate_user!, only: [:get_keys]
skip_before_action :authenticate_user!, only: [:get_keys]
def index
@keys = current_user.keys

View File

@ -1,11 +1,11 @@
class Profiles::PasswordsController < ApplicationController
layout :determine_layout
skip_before_filter :check_password_expiration, only: [:new, :create]
skip_before_action :check_password_expiration, only: [:new, :create]
before_filter :set_user
before_filter :set_title
before_filter :authorize_change_password!
before_action :set_user
before_action :set_title
before_action :authorize_change_password!
def new
end

View File

@ -1,9 +1,9 @@
class ProfilesController < ApplicationController
include ActionView::Helpers::SanitizeHelper
before_filter :user
before_filter :authorize_change_username!, only: :update_username
skip_before_filter :require_email, only: [:show, :update]
before_action :user
before_action :authorize_change_username!, only: :update_username
skip_before_action :require_email, only: [:show, :update]
layout 'profile'

View File

@ -1,6 +1,6 @@
class Projects::ApplicationController < ApplicationController
before_filter :project
before_filter :repository
before_action :project
before_action :repository
layout :determine_layout
def authenticate_user!

View File

@ -1,7 +1,7 @@
class Projects::AvatarsController < Projects::ApplicationController
layout 'project'
before_filter :project
before_action :project
def show
@blob = @project.repository.blob_at_branch('master', @project.avatar_in_git)

View File

@ -2,9 +2,9 @@
class Projects::BlameController < Projects::ApplicationController
include ExtractsPath
before_filter :require_non_empty_project
before_filter :assign_ref_vars
before_filter :authorize_download_code!
before_action :require_non_empty_project
before_action :assign_ref_vars
before_action :authorize_download_code!
def show
@blame = Gitlab::Git::Blame.new(@repository, @commit.id, @path)

View File

@ -6,15 +6,15 @@ class Projects::BlobController < Projects::ApplicationController
# Raised when given an invalid file path
class InvalidPathError < StandardError; end
before_filter :require_non_empty_project, except: [:new, :create]
before_filter :authorize_download_code!
before_filter :authorize_push_code!, only: [:destroy]
before_filter :assign_blob_vars
before_filter :commit, except: [:new, :create]
before_filter :blob, except: [:new, :create]
before_filter :from_merge_request, only: [:edit, :update]
before_filter :after_edit_path, only: [:edit, :update]
before_filter :require_branch_head, only: [:edit, :update]
before_action :require_non_empty_project, except: [:new, :create]
before_action :authorize_download_code!
before_action :authorize_push_code!, only: [:destroy]
before_action :assign_blob_vars
before_action :commit, except: [:new, :create]
before_action :blob, except: [:new, :create]
before_action :from_merge_request, only: [:edit, :update]
before_action :after_edit_path, only: [:edit, :update]
before_action :require_branch_head, only: [:edit, :update]
def new
commit unless @repository.empty?

View File

@ -1,9 +1,9 @@
class Projects::BranchesController < Projects::ApplicationController
include ActionView::Helpers::SanitizeHelper
# Authorize
before_filter :require_non_empty_project
before_filter :authorize_download_code!
before_filter :authorize_push_code!, only: [:create, :destroy]
before_action :require_non_empty_project
before_action :authorize_download_code!
before_action :authorize_push_code!, only: [:create, :destroy]
def index
@sort = params[:sort] || 'name'

View File

@ -3,9 +3,9 @@
# Not to be confused with CommitsController, plural.
class Projects::CommitController < Projects::ApplicationController
# Authorize
before_filter :require_non_empty_project
before_filter :authorize_download_code!
before_filter :commit
before_action :require_non_empty_project
before_action :authorize_download_code!
before_action :commit
def show
return git_not_found! unless @commit

View File

@ -3,9 +3,9 @@ require "base64"
class Projects::CommitsController < Projects::ApplicationController
include ExtractsPath
before_filter :require_non_empty_project
before_filter :assign_ref_vars
before_filter :authorize_download_code!
before_action :require_non_empty_project
before_action :assign_ref_vars
before_action :authorize_download_code!
def show
@repo = @project.repository

View File

@ -1,7 +1,7 @@
class Projects::CompareController < Projects::ApplicationController
# Authorize
before_filter :require_non_empty_project
before_filter :authorize_download_code!
before_action :require_non_empty_project
before_action :authorize_download_code!
def index
end

View File

@ -2,7 +2,7 @@ class Projects::DeployKeysController < Projects::ApplicationController
respond_to :html
# Authorize
before_filter :authorize_admin_project!
before_action :authorize_admin_project!
layout "project_settings"

View File

@ -1,7 +1,7 @@
class Projects::ForksController < Projects::ApplicationController
# Authorize
before_filter :require_non_empty_project
before_filter :authorize_download_code!
before_action :require_non_empty_project
before_action :authorize_download_code!
def new
@namespaces = current_user.manageable_namespaces

View File

@ -1,7 +1,7 @@
class Projects::GraphsController < Projects::ApplicationController
# Authorize
before_filter :require_non_empty_project
before_filter :authorize_download_code!
before_action :require_non_empty_project
before_action :authorize_download_code!
def show
respond_to do |format|

View File

@ -1,6 +1,6 @@
class Projects::HooksController < Projects::ApplicationController
# Authorize
before_filter :authorize_admin_project!
before_action :authorize_admin_project!
respond_to :html

View File

@ -1,8 +1,8 @@
class Projects::ImportsController < Projects::ApplicationController
# Authorize
before_filter :authorize_admin_project!
before_filter :require_no_repo
before_filter :redirect_if_progress, except: :show
before_action :authorize_admin_project!
before_action :require_no_repo
before_action :redirect_if_progress, except: :show
def new
end

View File

@ -1,18 +1,18 @@
class Projects::IssuesController < Projects::ApplicationController
before_filter :module_enabled
before_filter :issue, only: [:edit, :update, :show, :toggle_subscription]
before_action :module_enabled
before_action :issue, only: [:edit, :update, :show, :toggle_subscription]
# Allow read any issue
before_filter :authorize_read_issue!
before_action :authorize_read_issue!
# Allow write(create) issue
before_filter :authorize_write_issue!, only: [:new, :create]
before_action :authorize_write_issue!, only: [:new, :create]
# Allow modify issue
before_filter :authorize_modify_issue!, only: [:edit, :update]
before_action :authorize_modify_issue!, only: [:edit, :update]
# Allow issues bulk update
before_filter :authorize_admin_issues!, only: [:bulk_update]
before_action :authorize_admin_issues!, only: [:bulk_update]
respond_to :html
@ -99,7 +99,7 @@ class Projects::IssuesController < Projects::ApplicationController
def toggle_subscription
@issue.toggle_subscription(current_user)
render nothing: true
end

View File

@ -1,8 +1,8 @@
class Projects::LabelsController < Projects::ApplicationController
before_filter :module_enabled
before_filter :label, only: [:edit, :update, :destroy]
before_filter :authorize_labels!
before_filter :authorize_admin_labels!, except: [:index]
before_action :module_enabled
before_action :label, only: [:edit, :update, :destroy]
before_action :authorize_labels!
before_action :authorize_admin_labels!, except: [:index]
respond_to :js, :html

View File

@ -1,20 +1,20 @@
require 'gitlab/satellite/satellite'
class Projects::MergeRequestsController < Projects::ApplicationController
before_filter :module_enabled
before_filter :merge_request, only: [:edit, :update, :show, :diffs, :automerge, :automerge_check, :ci_status, :toggle_subscription]
before_filter :closes_issues, only: [:edit, :update, :show, :diffs]
before_filter :validates_merge_request, only: [:show, :diffs]
before_filter :define_show_vars, only: [:show, :diffs]
before_action :module_enabled
before_action :merge_request, only: [:edit, :update, :show, :diffs, :automerge, :automerge_check, :ci_status, :toggle_subscription]
before_action :closes_issues, only: [:edit, :update, :show, :diffs]
before_action :validates_merge_request, only: [:show, :diffs]
before_action :define_show_vars, only: [:show, :diffs]
# Allow read any merge_request
before_filter :authorize_read_merge_request!
before_action :authorize_read_merge_request!
# Allow write(create) merge_request
before_filter :authorize_write_merge_request!, only: [:new, :create]
before_action :authorize_write_merge_request!, only: [:new, :create]
# Allow modify merge_request
before_filter :authorize_modify_merge_request!, only: [:close, :edit, :update, :sort]
before_action :authorize_modify_merge_request!, only: [:close, :edit, :update, :sort]
def index
terms = params['issue_search']
@ -176,7 +176,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def toggle_subscription
@merge_request.toggle_subscription(current_user)
render nothing: true
end

View File

@ -1,12 +1,12 @@
class Projects::MilestonesController < Projects::ApplicationController
before_filter :module_enabled
before_filter :milestone, only: [:edit, :update, :destroy, :show, :sort_issues, :sort_merge_requests]
before_action :module_enabled
before_action :milestone, only: [:edit, :update, :destroy, :show, :sort_issues, :sort_merge_requests]
# Allow read any milestone
before_filter :authorize_read_milestone!
before_action :authorize_read_milestone!
# Allow admin milestone
before_filter :authorize_admin_milestone!, except: [:index, :show]
before_action :authorize_admin_milestone!, except: [:index, :show]
respond_to :html

View File

@ -2,9 +2,9 @@ class Projects::NetworkController < Projects::ApplicationController
include ExtractsPath
include ApplicationHelper
before_filter :require_non_empty_project
before_filter :assign_ref_vars
before_filter :authorize_download_code!
before_action :require_non_empty_project
before_action :assign_ref_vars
before_action :authorize_download_code!
def show
respond_to do |format|

View File

@ -1,9 +1,9 @@
class Projects::NotesController < Projects::ApplicationController
# Authorize
before_filter :authorize_read_note!
before_filter :authorize_write_note!, only: [:create]
before_filter :authorize_admin_note!, only: [:update, :destroy]
before_filter :find_current_user_notes, except: [:destroy, :delete_attachment]
before_action :authorize_read_note!
before_action :authorize_write_note!, only: [:create]
before_action :authorize_admin_note!, only: [:update, :destroy]
before_action :find_current_user_notes, except: [:destroy, :delete_attachment]
def index
current_fetched_at = Time.now.to_i

View File

@ -1,6 +1,6 @@
class Projects::ProjectMembersController < Projects::ApplicationController
# Authorize
before_filter :authorize_admin_project!, except: :leave
before_action :authorize_admin_project!, except: :leave
layout "project_settings"
@ -24,7 +24,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
users = @group.users.search(params[:search]).to_a
@group_members = @group_members.where(user_id: users)
end
@group_members = @group_members.order('access_level DESC').limit(20)
end
@ -62,7 +62,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
redirect_path = namespace_project_project_members_path(@project.namespace, @project)
@project_member = @project.project_members.find(params[:id])
if @project_member.invite?
@project_member.resend_invite

View File

@ -1,7 +1,7 @@
class Projects::ProtectedBranchesController < Projects::ApplicationController
# Authorize
before_filter :require_non_empty_project
before_filter :authorize_admin_project!
before_action :require_non_empty_project
before_action :authorize_admin_project!
layout "project_settings"

View File

@ -2,9 +2,9 @@
class Projects::RawController < Projects::ApplicationController
include ExtractsPath
before_filter :require_non_empty_project
before_filter :assign_ref_vars
before_filter :authorize_download_code!
before_action :require_non_empty_project
before_action :assign_ref_vars
before_action :authorize_download_code!
def show
@blob = @repository.blob_at(@commit.id, @path)

View File

@ -1,9 +1,9 @@
class Projects::RefsController < Projects::ApplicationController
include ExtractsPath
before_filter :require_non_empty_project
before_filter :assign_ref_vars
before_filter :authorize_download_code!
before_action :require_non_empty_project
before_action :assign_ref_vars
before_action :authorize_download_code!
def switch
respond_to do |format|

View File

@ -1,8 +1,8 @@
class Projects::RepositoriesController < Projects::ApplicationController
# Authorize
before_filter :require_non_empty_project, except: :create
before_filter :authorize_download_code!
before_filter :authorize_admin_project!, only: :create
before_action :require_non_empty_project, except: :create
before_action :authorize_download_code!
before_action :authorize_admin_project!, only: :create
def create
@project.create_repository

View File

@ -1,7 +1,7 @@
class Projects::ServicesController < Projects::ApplicationController
# Authorize
before_filter :authorize_admin_project!
before_filter :service, only: [:edit, :update, :test]
before_action :authorize_admin_project!
before_action :service, only: [:edit, :update, :test]
respond_to :html

View File

@ -1,18 +1,18 @@
class Projects::SnippetsController < Projects::ApplicationController
before_filter :module_enabled
before_filter :snippet, only: [:show, :edit, :destroy, :update, :raw]
before_action :module_enabled
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw]
# Allow read any snippet
before_filter :authorize_read_project_snippet!
before_action :authorize_read_project_snippet!
# Allow write(create) snippet
before_filter :authorize_write_project_snippet!, only: [:new, :create]
before_action :authorize_write_project_snippet!, only: [:new, :create]
# Allow modify snippet
before_filter :authorize_modify_project_snippet!, only: [:edit, :update]
before_action :authorize_modify_project_snippet!, only: [:edit, :update]
# Allow destroy snippet
before_filter :authorize_admin_project_snippet!, only: [:destroy]
before_action :authorize_admin_project_snippet!, only: [:destroy]
respond_to :html

View File

@ -1,9 +1,9 @@
class Projects::TagsController < Projects::ApplicationController
# Authorize
before_filter :require_non_empty_project
before_filter :authorize_download_code!
before_filter :authorize_push_code!, only: [:create]
before_filter :authorize_admin_project!, only: [:destroy]
before_action :require_non_empty_project
before_action :authorize_download_code!
before_action :authorize_push_code!, only: [:create]
before_action :authorize_admin_project!, only: [:destroy]
def index
sorted = VersionSorter.rsort(@repository.tag_names)

View File

@ -2,9 +2,9 @@
class Projects::TreeController < Projects::ApplicationController
include ExtractsPath
before_filter :require_non_empty_project, except: [:new, :create]
before_filter :assign_ref_vars
before_filter :authorize_download_code!
before_action :require_non_empty_project, except: [:new, :create]
before_action :assign_ref_vars
before_action :authorize_download_code!
def show
if tree.entries.empty?

View File

@ -1,11 +1,11 @@
class Projects::UploadsController < Projects::ApplicationController
layout 'project'
# We want to skip these filters for only the `show` action if `image?` is true,
# We want to skip these filters for only the `show` action if `image?` is true,
# but `skip_before_filter` doesn't work with both `only` and `if`, so we accomplish the same like this.
skipped_filters = [:authenticate_user!, :reject_blocked!, :project, :repository]
skip_before_filter *skipped_filters, only: [:show]
before_filter *skipped_filters, only: [:show], unless: :image?
skip_before_action *skipped_filters, only: [:show]
before_action *skipped_filters, only: [:show], unless: :image?
def create
link_to_file = ::Projects::UploadService.new(project, params[:file]).
@ -40,7 +40,7 @@ class Projects::UploadsController < Projects::ApplicationController
file_project = Project.find_with_namespace("#{namespace}/#{id}")
if file_project.nil?
@uploader = nil
@uploader = nil
return
end

View File

@ -1,10 +1,10 @@
require 'project_wiki'
class Projects::WikisController < Projects::ApplicationController
before_filter :authorize_read_wiki!
before_filter :authorize_write_wiki!, only: [:edit, :create, :history]
before_filter :authorize_admin_wiki!, only: :destroy
before_filter :load_project_wiki
before_action :authorize_read_wiki!
before_action :authorize_write_wiki!, only: [:edit, :create, :history]
before_action :authorize_admin_wiki!, only: :destroy
before_action :load_project_wiki
include WikiHelper
def pages

View File

@ -1,13 +1,13 @@
class ProjectsController < ApplicationController
prepend_before_filter :render_go_import, only: [:show]
skip_before_filter :authenticate_user!, only: [:show]
before_filter :project, except: [:new, :create]
before_filter :repository, except: [:new, :create]
skip_before_action :authenticate_user!, only: [:show]
before_action :project, except: [:new, :create]
before_action :repository, except: [:new, :create]
# Authorize
before_filter :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer, :archive, :unarchive]
before_filter :set_title, only: [:new, :create]
before_filter :event_filter, only: :show
before_action :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer, :archive, :unarchive]
before_action :set_title, only: [:new, :create]
before_action :event_filter, only: :show
layout 'navless', only: [:new, :create, :fork]

View File

@ -1,5 +1,5 @@
class RegistrationsController < Devise::RegistrationsController
before_filter :signup_enabled?
before_action :signup_enabled?
def new
redirect_to(new_user_session_path)

View File

@ -1,11 +1,15 @@
class SnippetsController < ApplicationController
before_filter :snippet, only: [:show, :edit, :destroy, :update, :raw]
before_filter :authorize_modify_snippet!, only: [:edit, :update]
before_filter :authorize_admin_snippet!, only: [:destroy]
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw]
before_filter :set_title
# Allow modify snippet
before_action :authorize_modify_snippet!, only: [:edit, :update]
skip_before_filter :authenticate_user!, only: [:index, :user_index, :show, :raw]
# Allow destroy snippet
before_action :authorize_admin_snippet!, only: [:destroy]
before_action :set_title
skip_before_action :authenticate_user!, only: [:index, :user_index, :show, :raw]
respond_to :html

View File

@ -1,6 +1,6 @@
class UploadsController < ApplicationController
skip_before_filter :authenticate_user!
before_filter :find_model, :authorize_access!
skip_before_action :authenticate_user!
before_action :find_model, :authorize_access!
def show
uploader = @model.send(upload_mount)
@ -28,7 +28,7 @@ class UploadsController < ApplicationController
end
def authorize_access!
authorized =
authorized =
case @model
when Project
can?(current_user, :read_project, @model)

View File

@ -1,6 +1,6 @@
class UsersController < ApplicationController
skip_before_filter :authenticate_user!
before_filter :set_user
skip_before_action :authenticate_user!
before_action :set_user
layout :determine_layout
def show

View File

@ -255,11 +255,15 @@ module ApplicationHelper
#
# Returns `html_options`, adding `rel: nofollow` for external links
def add_nofollow(link, html_options = {})
uri = URI(link)
begin
uri = URI(link)
if uri && uri.absolute? && uri.host != Gitlab.config.gitlab.host
rel = html_options.fetch(:rel, '')
html_options[:rel] = (rel + ' nofollow').strip
if uri && uri.absolute? && uri.host != Gitlab.config.gitlab.host
rel = html_options.fetch(:rel, '')
html_options[:rel] = (rel + ' nofollow').strip
end
rescue URI::Error
# noop
end
html_options

View File

@ -74,6 +74,7 @@ module GitlabMarkdownHelper
end
end
# TODO (rspeicher): This should be its own filter
def create_relative_links(text)
paths = extract_paths(text)

View File

@ -108,4 +108,7 @@ module IssuesHelper
xml.summary issue.title
end
end
# Required for Gitlab::Markdown::IssueReferenceFilter
module_function :url_for_issue, :title_for_issue
end

View File

@ -1,4 +1,6 @@
module LabelsHelper
include ActionView::Helpers::TagHelper
def project_label_names
@project.labels.pluck(:title)
end
@ -7,9 +9,13 @@ module LabelsHelper
label_color = label.color || Label::DEFAULT_COLOR
text_color = text_color_for_bg(label_color)
content_tag :span, class: 'label color-label', style: "background-color:#{label_color};color:#{text_color}" do
label.name
end
# Intentionally not using content_tag here so that this method can be called
# by LabelReferenceFilter
span = %(<span class="label color-label") +
%( style="background-color: #{label_color}; color: #{text_color}">) +
escape_once(label.name) + '</span>'
span.html_safe
end
def suggested_colors
@ -42,13 +48,16 @@ module LabelsHelper
r, g, b = bg_color.slice(1,7).scan(/.{2}/).map(&:hex)
if (r + g + b) > 500
"#333"
'#333333'
else
"#FFF"
'#FFFFFF'
end
end
def project_labels_options(project)
options_from_collection_for_select(project.labels, 'name', 'name', params[:label_name])
end
# Required for Gitlab::Markdown::LabelReferenceFilter
module_function :render_colored_label, :text_color_for_bg, :escape_once
end

View File

@ -27,7 +27,7 @@ class Label < ActiveRecord::Base
# Don't allow '?', '&', and ',' for label titles
validates :title,
presence: true,
format: { with: /\A[^&\?,&]+\z/ },
format: { with: /\A[^&\?,]+\z/ },
uniqueness: { scope: :project_id }
default_scope { order(title: :asc) }

View File

@ -50,8 +50,9 @@ class HipchatService < Service
def execute(data)
return unless supported_events.include?(data[:object_kind])
gate[room].send('GitLab', create_message(data))
message = create_message(data)
return unless message.present?
gate[room].send('GitLab', message)
end
private

View File

@ -3,7 +3,7 @@
%p #{@service.description} template
= form_for :service, url: admin_application_settings_service_path, method: :put, html: { class: 'form-horizontal fieldset-form' } do |f|
= form_for :service, url: admin_application_settings_service_path, method: :put, html: { class: 'form-horizontal fieldset-form' } do |form|
- if @service.errors.any?
#error_explanation
.alert.alert-danger
@ -15,80 +15,68 @@
= markdown @service.help
.form-group
= f.label :active, "Active", class: "control-label"
= form.label :active, "Active", class: "control-label"
.col-sm-10
= f.check_box :active
= form.check_box :active
- if @service.supported_events.length > 1
.form-group
= f.label :url, "Trigger", class: 'control-label'
= form.label :url, "Trigger", class: 'control-label'
.col-sm-10
- if @service.supported_events.include?("push")
%div
= f.check_box :push_events, class: 'pull-left'
= form.check_box :push_events, class: 'pull-left'
.prepend-left-20
= f.label :push_events, class: 'list-label' do
= form.label :push_events, class: 'list-label' do
%strong Push events
%p.light
This url will be triggered by a push to the repository
- if @service.supported_events.include?("tag_push")
%div
= f.check_box :tag_push_events, class: 'pull-left'
= form.check_box :tag_push_events, class: 'pull-left'
.prepend-left-20
= f.label :tag_push_events, class: 'list-label' do
= form.label :tag_push_events, class: 'list-label' do
%strong Tag push events
%p.light
This url will be triggered when a new tag is pushed to the repository
- if @service.supported_events.include?("note")
%div
= f.check_box :note_events, class: 'pull-left'
= form.check_box :note_events, class: 'pull-left'
.prepend-left-20
= f.label :note_events, class: 'list-label' do
= form.label :note_events, class: 'list-label' do
%strong Comments
%p.light
This url will be triggered when someone adds a comment
- if @service.supported_events.include?("issue")
%div
= f.check_box :issues_events, class: 'pull-left'
= form.check_box :issues_events, class: 'pull-left'
.prepend-left-20
= f.label :issues_events, class: 'list-label' do
= form.label :issues_events, class: 'list-label' do
%strong Issues events
%p.light
This url will be triggered when an issue is created
- if @service.supported_events.include?("merge_request")
%div
= f.check_box :merge_requests_events, class: 'pull-left'
= form.check_box :merge_requests_events, class: 'pull-left'
.prepend-left-20
= f.label :merge_requests_events, class: 'list-label' do
= form.label :merge_requests_events, class: 'list-label' do
%strong Merge Request events
%p.light
This url will be triggered when a merge request is created
- @service.fields.each do |field|
- name = field[:name]
- title = field[:title] || name.humanize
- value = @service.send(name) unless field[:type] == 'password'
- type = field[:type]
- placeholder = field[:placeholder]
- choices = field[:choices]
- default_choice = field[:default_choice]
- help = field[:help]
.form-group
= f.label name, title, class: "control-label"
.col-sm-10
- if type == 'text'
= f.text_field name, class: "form-control", placeholder: placeholder
- elsif type == 'textarea'
= f.text_area name, rows: 5, class: "form-control", placeholder: placeholder
- elsif type == 'checkbox'
= f.check_box name
- elsif type == 'select'
= f.select name, options_for_select(choices, value ? value : default_choice), {}, { class: "form-control" }
- elsif type == 'password'
= f.password_field name, class: 'form-control'
- if help
%span.help-block= help
- if type == 'fieldset'
- fields = field[:fields]
- legend = field[:legend]
%fieldset
%legend= legend
- fields.each do |subfield|
= render 'shared/field', form: form, field: subfield
- else
= render 'shared/field', form: form, field: field
.form-actions
= f.submit 'Save', class: 'btn btn-save'
= form.submit 'Save', class: 'btn btn-save'

View File

@ -187,7 +187,11 @@
%td.shortcut
.key m
%td Change milestone
%tbody{ class: 'hidden-shortcut merge_reuests', style: 'display:none' }
%tr
%td.shortcut
.key r
%td Reply (quoting selected text)
%tbody{ class: 'hidden-shortcut merge_requests', style: 'display:none' }
%tr
%th
%th Merge Requests
@ -199,6 +203,10 @@
%td.shortcut
.key m
%td Change milestone
%tr
%td.shortcut
.key r
%td Reply (quoting selected text)
:javascript

View File

@ -8,9 +8,31 @@
Customize how Google Code email addresses and usernames are imported into GitLab.
In the next step, you'll be able to select the projects you want to import.
%p
The user map is a JSON document mapping Google Code users (as keys) to the way they will be imported into GitLab (as values). By default the username is masked to ensure users' privacy.
%p
To map a Google Code user to a full name or GitLab user, simply replace the value, e.g. <code>"johnsmith@gmail.com": "John Smith"</code> or <code>"johnsmith@gmail.com": "@johnsmith"</code>. Be sure to preserve the surrounding double quotes and other punctuation.
The user map is a JSON document mapping the Google Code users that participated on your projects to the way their email addresses and usernames will be imported into GitLab. You can change this by changing the value on the right hand side of <code>:</code>. Be sure to preserve the surrounding double quotes, other punctuation and the email address or username on the left hand side.
%ul
%li
%strong Default: Directly import the Google Code email address or username
%p
<code>"johnsmith@example.com": "johnsm...@example.com"</code>
will add "By johnsm...@example.com" to all issues and comments originally created by johnsmith@example.com.
The email address or username is masked to ensure the user's privacy.
%li
%strong Map a Google Code user to a GitLab user
%p
<code>"johnsmith@example.com": "@johnsmith"</code>
will add "By <a href="#">@johnsmith</a>" to all issues and comments originally created by johnsmith@example.com,
and will set <a href="#">@johnsmith</a> as the assignee on all issues originally assigned to johnsmith@example.com.
%li
%strong Map a Google Code user to a full name
%p
<code>"johnsmith@example.com": "John Smith"</code>
will add "By John Smith" to all issues and comments originally created by johnsmith@example.com.
%li
%strong Map a Google Code user to a full email address
%p
<code>"johnsmith@example.com": "johnsmith@example.com"</code>
will add "By <a href="#">johnsmith@example.com</a>" to all issues and comments originally created by johnsmith@example.com.
By default, the email address or username is masked to ensure the user's privacy. Use this option if you want to show the full email address.
.form-group
.col-sm-12

View File

@ -9,5 +9,5 @@
%div
.md-write-holder
= yield
.md-preview-holder.hide
.md.md-preview-holder.hide
.js-md-preview{class: (preview_class if defined?(preview_class))}

View File

@ -82,12 +82,12 @@
.mr-compare.merge-request
%ul.nav.nav-tabs.merge-request-tabs
%li.commits-tab{data: {action: 'commits'}}
%li.commits-tab{data: {action: 'commits', toggle: 'tab'}}
= link_to url_for(params) do
%i.fa.fa-history
Commits
%span.badge= @commits.size
%li.diffs-tab{data: {action: 'diffs'}}
%li.diffs-tab{data: {action: 'diffs', toggle: 'tab'}}
= link_to url_for(params) do
%i.fa.fa-list-alt
Changes

View File

@ -10,7 +10,7 @@
%hr
= form_for(@service, as: :service, url: namespace_project_service_path(@project.namespace, @project, @service.to_param), method: :put, html: { class: 'form-horizontal' }) do |f|
= form_for(@service, as: :service, url: namespace_project_service_path(@project.namespace, @project, @service.to_param), method: :put, html: { class: 'form-horizontal' }) do |form|
- if @service.errors.any?
.alert.alert-danger
%ul
@ -23,83 +23,71 @@
= markdown @service.help
.form-group
= f.label :active, "Active", class: "control-label"
= form.label :active, "Active", class: "control-label"
.col-sm-10
= f.check_box :active
= form.check_box :active
- if @service.supported_events.length > 1
.form-group
= f.label :url, "Trigger", class: 'control-label'
= form.label :url, "Trigger", class: 'control-label'
.col-sm-10
- if @service.supported_events.include?("push")
%div
= f.check_box :push_events, class: 'pull-left'
= form.check_box :push_events, class: 'pull-left'
.prepend-left-20
= f.label :push_events, class: 'list-label' do
= form.label :push_events, class: 'list-label' do
%strong Push events
%p.light
This url will be triggered by a push to the repository
- if @service.supported_events.include?("tag_push")
%div
= f.check_box :tag_push_events, class: 'pull-left'
= form.check_box :tag_push_events, class: 'pull-left'
.prepend-left-20
= f.label :tag_push_events, class: 'list-label' do
= form.label :tag_push_events, class: 'list-label' do
%strong Tag push events
%p.light
This url will be triggered when a new tag is pushed to the repository
- if @service.supported_events.include?("note")
%div
= f.check_box :note_events, class: 'pull-left'
= form.check_box :note_events, class: 'pull-left'
.prepend-left-20
= f.label :note_events, class: 'list-label' do
= form.label :note_events, class: 'list-label' do
%strong Comments
%p.light
This url will be triggered when someone adds a comment
- if @service.supported_events.include?("issue")
%div
= f.check_box :issues_events, class: 'pull-left'
= form.check_box :issues_events, class: 'pull-left'
.prepend-left-20
= f.label :issues_events, class: 'list-label' do
= form.label :issues_events, class: 'list-label' do
%strong Issues events
%p.light
This url will be triggered when an issue is created
- if @service.supported_events.include?("merge_request")
%div
= f.check_box :merge_requests_events, class: 'pull-left'
= form.check_box :merge_requests_events, class: 'pull-left'
.prepend-left-20
= f.label :merge_requests_events, class: 'list-label' do
= form.label :merge_requests_events, class: 'list-label' do
%strong Merge Request events
%p.light
This url will be triggered when a merge request is created
- @service.fields.each do |field|
- name = field[:name]
- title = field[:title] || name.humanize
- value = service_field_value(field[:type], @service.send(name))
- type = field[:type]
- placeholder = field[:placeholder]
- choices = field[:choices]
- default_choice = field[:default_choice]
- help = field[:help]
.form-group
= f.label name, title, class: "control-label"
.col-sm-10
- if type == 'text'
= f.text_field name, class: "form-control", placeholder: placeholder
- elsif type == 'textarea'
= f.text_area name, rows: 5, class: "form-control", placeholder: placeholder
- elsif type == 'checkbox'
= f.check_box name
- elsif type == 'select'
= f.select name, options_for_select(choices, value ? value : default_choice), {}, { class: "form-control" }
- elsif type == 'password'
= f.password_field name, placeholder: value, class: 'form-control'
- if help
%span.help-block= help
- if type == 'fieldset'
- fields = field[:fields]
- legend = field[:legend]
%fieldset
%legend= legend
- fields.each do |subfield|
= render 'shared/field', form: form, field: subfield
- else
= render 'shared/field', form: form, field: field
.form-actions
= f.submit 'Save', class: 'btn btn-save'
= form.submit 'Save', class: 'btn btn-save'
&nbsp;
- if @service.valid? && @service.activated?
- disabled = @service.can_test? ? '':'disabled'

View File

@ -0,0 +1,24 @@
- name = field[:name]
- title = field[:title] || name.humanize
- value = service_field_value(field[:type], @service.send(name))
- type = field[:type]
- placeholder = field[:placeholder]
- choices = field[:choices]
- default_choice = field[:default_choice]
- help = field[:help]
.form-group
= form.label name, title, class: "control-label"
.col-sm-10
- if type == 'text'
= form.text_field name, class: "form-control", placeholder: placeholder
- elsif type == 'textarea'
= form.text_area name, rows: 5, class: "form-control", placeholder: placeholder
- elsif type == 'checkbox'
= form.check_box name
- elsif type == 'select'
= form.select name, options_for_select(choices, value ? value : default_choice), {}, { class: "form-control" }
- elsif type == 'password'
= form.password_field name, placeholder: value, class: 'form-control'
- if help
%span.help-block= help

View File

@ -2,6 +2,7 @@ require 'sidekiq/web'
require 'api/api'
Gitlab::Application.routes.draw do
mount JasmineRails::Engine => '/specs' if defined?(JasmineRails)
use_doorkeeper do
controllers applications: 'oauth/applications',
authorized_applications: 'oauth/authorized_applications',

View File

@ -470,7 +470,6 @@ ActiveRecord::Schema.define(version: 20150417122318) do
t.integer "notification_level", default: 1, null: false
t.datetime "password_expires_at"
t.integer "created_by_id"
t.datetime "last_credential_check_at"
t.string "avatar"
t.string "confirmation_token"
t.datetime "confirmed_at"
@ -478,6 +477,7 @@ ActiveRecord::Schema.define(version: 20150417122318) do
t.string "unconfirmed_email"
t.boolean "hide_no_ssh_key", default: false
t.string "website_url", default: "", null: false
t.datetime "last_credential_check_at"
t.string "github_access_token"
t.string "gitlab_access_token"
t.string "notification_email"

View File

@ -16,7 +16,7 @@ To enable Slack integration you must create an Incoming WebHooks integration on
1. Choose the channel name you want to send notifications to
1. Click **Add Incoming WebHooks Integration**Add Integrations.
1. Click **Add Incoming WebHooks Integration**
- Optional step; You can change bot's name and avatar by clicking modifying the bot name or avatar under **Integration Settings**.
1. Copy the **Webhook URL**, we'll need this later for GitLab.
@ -32,10 +32,15 @@ After Slack is ready we need to setup GitLab. Here are the steps to achieve this
1. Navigate to Settings -> Services -> Slack
1. Fill in your Slack details
1. Pick the triggers you want to activate
1. Fill in your Slack details
- Webhook: Paste the Webhook URL from the step above
- Username: Fill this in if you want to change the username of the bot
- Channel: Fill this in if you want to change the channel where the messages will be posted
- Mark it as active
- Paste in the webhook URL you got from Slack
1. Save your settings
Have fun :)

View File

@ -163,7 +163,7 @@ Consult the [Emoji Cheat Sheet](http://emoji.codes) for a list of all supported
## Special GitLab References
GFM recognized special references.
GFM recognizes special references.
You can easily reference e.g. an issue, a commit, a team member or even the whole team within a project.
@ -171,19 +171,30 @@ GFM will turn that reference into a link so you can navigate between them easily
GFM will recognize the following:
- @foo : for specific team members or groups
- @all : for the whole team
- #123 : for issues
- !123 : for merge requests
- $123 : for snippets
- 1234567 : for commits
- \[file\](path/to/file) : for file references
| input | references |
|-----------------------:|:---------------------------|
| `@user_name` | specific user |
| `@group_name` | specific group |
| `@all` | entire team |
| `#123` | issue |
| `!123` | merge request |
| `$123` | snippet |
| `~123` | label by ID |
| `~bug` | one-word label by name |
| `~"feature request"` | multi-word label by name |
| `9ba12248` | specific commit |
| `9ba12248...b19a04f5` | commit range comparison |
| `[README](doc/README)` | repository file references |
GFM also recognizes references to commits, issues, and merge requests in other projects:
GFM also recognizes certain cross-project references:
- namespace/project#123 : for issues
- namespace/project!123 : for merge requests
- namespace/project@1234567 : for commits
| input | references |
|----------------------------------------:|:------------------------|
| `namespace/project#123` | issue |
| `namespace/project!123` | merge request |
| `namespace/project$123` | snippet |
| `namespace/project@9ba12248` | specific commit |
| `namespace/project@9ba12248...b19a04f5` | commit range comparison |
## Task Lists

View File

@ -162,6 +162,7 @@ Options:
```
BACKUP=timestamp_of_backup (required if more than one backup exists)
force=yes (do not ask if the authorized_keys file should get regenerated)
```
Example output:

View File

@ -126,7 +126,7 @@ sudo apt-get install nodejs
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch
sudo -u git -H git checkout v2.6.0
sudo -u git -H git checkout v2.6.2
```
## 7. Install libs, migrations, etc.

View File

@ -42,6 +42,8 @@ sudo -u git -H git checkout v2.6.0
### 4. Install libs, migrations, etc.
Please refer to the [Node.js setup documentation](https://github.com/joyent/node/wiki/installing-node.js-via-package-manager#debian-and-ubuntu-based-linux-distributions) if you aren't running default GitLab server setup.
```bash
sudo apt-get install nodejs

118
doc/update/7.9-to-7.10.md Normal file
View File

@ -0,0 +1,118 @@
# From 7.9 to 7.10
### 0. Stop server
sudo service gitlab stop
### 1. Backup
```bash
cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
```
### 2. Get latest code
```bash
sudo -u git -H git fetch --all
sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
```
For GitLab Community Edition:
```bash
sudo -u git -H git checkout 7-10-stable
```
OR
For GitLab Enterprise Edition:
```bash
sudo -u git -H git checkout 7-10-stable-ee
```
### 3. Update gitlab-shell
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch
sudo -u git -H git checkout v2.6.2
```
### 4. Install libs, migrations, etc.
```bash
cd /home/git/gitlab
# MySQL installations (note: the line below states '--without ... postgres')
sudo -u git -H bundle install --without development test postgres --deployment
# PostgreSQL installations (note: the line below states '--without ... mysql')
sudo -u git -H bundle install --without development test mysql --deployment
# Run database migrations
sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
# Clean up assets and cache
sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production
# Update init.d script
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
```
### 5. Update config files
#### New configuration options for `gitlab.yml`
There are new configuration options available for [`gitlab.yml`](config/gitlab.yml.example). View them with the command below and apply them to your current `gitlab.yml`.
```
git diff origin/7-9-stable:config/gitlab.yml.example origin/7-10-stable:config/gitlab.yml.example
```
#### Change Nginx settings
* HTTP setups: Make `/etc/nginx/sites-available/gitlab` the same as [`lib/support/nginx/gitlab`](/lib/support/nginx/gitlab) but with your settings.
* HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as [`lib/support/nginx/gitlab-ssl`](/lib/support/nginx/gitlab-ssl) but with your settings.
* A new `location /uploads/` section has been added that needs to have the same content as the existing `location @gitlab` section.
#### Setup time zone (optional)
Consider setting the time zone in `gitlab.yml` otherwise GitLab will default to UTC. If you set a time zone previously in [`application.rb`](config/application.rb) (unlikely), unset it.
### 6. Start application
sudo service gitlab start
sudo service nginx restart
### 7. Check application status
Check if GitLab and its environment are configured correctly:
sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
To make sure you didn't miss anything run a more thorough check with:
sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
If all items are green, then congratulations upgrade is complete!
### 8. GitHub settings (if applicable)
If you are using GitHub as an OAuth provider for authentication, you should change the callback URL so that it
only contains a root URL (ex. `https://gitlab.example.com/`)
## Things went south? Revert to previous version (7.9)
### 1. Revert the code to the previous version
Follow the [upgrade guide from 7.8 to 7.8](7.8-to-7.9.md), except for the database migration
(The backup is already migrated to the previous version)
### 2. Restore from the backup:
```bash
cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
```
If you have more than one backup *.tar file(s) please add `BACKUP=timestamp_of_backup` to the command above.

View File

@ -26,12 +26,11 @@ If you have local changes to your GitLab repository the script will stash them a
Note: GitLab 7.9 adds `nodejs` as a dependency. GitLab 7.6 adds `libkrb5-dev` as a dependency (installed by default on Ubuntu and OSX). GitLab 7.2 adds `pkg-config` and `cmake` as dependency. Please check the dependencies in the [installation guide.](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md#1-packages-dependencies)
# Starting with GitLab version 7.0 upgrader script has been moved to bin directory
cd /home/git/gitlab
if [ -f bin/upgrade.rb ]; then sudo -u git -H ruby bin/upgrade.rb; else sudo -u git -H ruby script/upgrade.rb; fi
sudo -u git -H ruby -Ilib -e 'require "gitlab/upgrader"' -e 'class Gitlab::Upgrader' -e 'def latest_version_raw' -e '"v7.10.0"' -e 'end' -e 'end' -e 'Gitlab::Upgrader.new.execute'
# to perform a non-interactive install (no user input required) you can add -y
# if [ -f bin/upgrade.rb ]; then sudo -u git -H ruby bin/upgrade.rb -y; else sudo -u git -H ruby script/upgrade.rb -y; fi
# sudo -u git -H ruby -Ilib -e 'require "gitlab/upgrader"' -e 'class Gitlab::Upgrader' -e 'def latest_version_raw' -e '"v7.10.0"' -e 'end' -e 'end' -e 'Gitlab::Upgrader.new.execute' -- -y
## 3. Start application
@ -66,11 +65,12 @@ Here is a one line command with step 1 to 5 for the next time you upgrade:
cd /home/git/gitlab; \
sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production; \
sudo service gitlab stop; \
if [ -f bin/upgrade.rb ]; then sudo -u git -H ruby bin/upgrade.rb -y; else sudo -u git -H ruby script/upgrade.rb -y; fi; \
sudo -u git -H ruby -Ilib -e 'require "gitlab/upgrader"' -e 'class Gitlab::Upgrader' -e 'def latest_version_raw' -e '"v7.10.0"' -e 'end' -e 'end' -e 'Gitlab::Upgrader.new.execute' -- -y; \
cd /home/git/gitlab-shell; \
sudo -u git -H git fetch; \
sudo -u git -H git checkout v`cat /home/git/gitlab/GITLAB_SHELL_VERSION`; \
cd /home/git/gitlab; \
sudo service gitlab start; \
sudo service nginx restart; sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
sudo service nginx restart; \
sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
```

View File

@ -30,7 +30,10 @@ module Gitlab
def user_map
@user_map ||= begin
user_map = Hash.new { |hash, user| Client.mask_email(user) }
user_map = Hash.new do |hash, user|
# Replace ... by \.\.\., so `johnsm...@gmail.com` isn't autolinked.
Client.mask_email(user).sub("...", "\\.\\.\\.")
end
import_data = project.import_data.try(:data)
stored_user_map = import_data["user_map"] if import_data
@ -203,25 +206,25 @@ module Gitlab
end
def linkify_issues(s)
s.gsub(/([Ii]ssue) ([0-9]+)/, '\1 #\2')
s = s.gsub(/([Ii]ssue) ([0-9]+)/, '\1 #\2')
s = s.gsub(/([Cc]omment) #([0-9]+)/, '\1 \2')
s
end
def escape_for_markdown(s)
s = s.gsub("*", "\\*")
s = s.gsub("#", "\\#")
# No headings and lists
s = s.gsub(/^#/, "\\#")
s = s.gsub(/^-/, "\\-")
# No inline code
s = s.gsub("`", "\\`")
s = s.gsub(":", "\\:")
s = s.gsub("-", "\\-")
s = s.gsub("+", "\\+")
s = s.gsub("_", "\\_")
s = s.gsub("(", "\\(")
s = s.gsub(")", "\\)")
s = s.gsub("[", "\\[")
s = s.gsub("]", "\\]")
s = s.gsub("<", "\\<")
s = s.gsub(">", "\\>")
# Carriage returns make me sad
s = s.gsub("\r", "")
# Markdown ignores single newlines, but we need them as <br />.
s = s.gsub("\n", " \n")
s
end
@ -276,11 +279,18 @@ module Gitlab
if raw_updates.has_key?("blockedOn")
blocked_ons = raw_updates["blockedOn"].map do |raw_blocked_on|
name, id = raw_blocked_on.split(":", 2)
if name == project.import_source
"##{id}"
else
"#{project.namespace.path}/#{name}##{id}"
end
deleted = name.start_with?("-")
name = name[1..-1] if deleted
text =
if name == project.import_source
"##{id}"
else
"#{project.namespace.path}/#{name}##{id}"
end
text = "~~#{text}~~" if deleted
text
end
updates << "*Blocked on: #{blocked_ons.join(", ")}*"
end
@ -288,11 +298,18 @@ module Gitlab
if raw_updates.has_key?("blocking")
blockings = raw_updates["blocking"].map do |raw_blocked_on|
name, id = raw_blocked_on.split(":", 2)
if name == project.import_source
"##{id}"
else
"#{project.namespace.path}/#{name}##{id}"
end
deleted = name.start_with?("-")
name = name[1..-1] if deleted
text =
if name == project.import_source
"##{id}"
else
"#{project.namespace.path}/#{name}##{id}"
end
text = "~~#{text}~~" if deleted
text
end
updates << "*Blocking: #{blockings.join(", ")}*"
end
@ -340,7 +357,7 @@ module Gitlab
def format_issue_body(author, date, content, attachments)
body = []
body << "*By #{author} on #{date}*"
body << "*By #{author} on #{date} (imported from Google Code)*"
body << "---"
if content.blank?

View File

@ -1,5 +1,4 @@
require 'html/pipeline'
require 'html/pipeline/gitlab'
module Gitlab
# Custom parser for GitLab-flavored Markdown
@ -10,11 +9,11 @@ module Gitlab
# Supported reference formats are:
# * @foo for team members
# * #123 for issues
# * #JIRA-123 for Jira issues
# * JIRA-123 for Jira issues
# * !123 for merge requests
# * $123 for snippets
# * 123456 for commits
# * 123456...7890123 for commit ranges (comparisons)
# * 1c002d for specific commit
# * 1c002d...35cfb2 for commit ranges (comparisons)
#
# It also parses Emoji codes to insert images. See
# http://www.emoji-cheat-sheet.com/ for a list of the supported icons.
@ -30,10 +29,6 @@ module Gitlab
# >> gfm(":trollface:")
# => "<img alt=\":trollface:\" class=\"emoji\" src=\"/images/trollface.png" title=\":trollface:\" />
module Markdown
include IssuesHelper
attr_reader :options, :html_options
# Public: Parse the provided text with GitLab-Flavored Markdown
#
# text - the source text
@ -65,47 +60,24 @@ module Gitlab
reference_only_path: true
)
@options = options
@html_options = html_options
pipeline = HTML::Pipeline.new(filters)
# TODO: add popups with additional information
context = {
# SanitizationFilter
whitelist: sanitization_whitelist,
# Used markdown pipelines in GitLab:
# GitlabEmojiFilter - performs emoji replacement.
# SanitizationFilter - remove unsafe HTML tags and attributes
#
# see https://gitlab.com/gitlab-org/html-pipeline-gitlab for more filters
filters = [
HTML::Pipeline::Gitlab::GitlabEmojiFilter,
HTML::Pipeline::SanitizationFilter
]
# EmojiFilter
asset_root: Gitlab.config.gitlab.url,
asset_host: Gitlab::Application.config.asset_host,
whitelist = HTML::Pipeline::SanitizationFilter::WHITELIST
whitelist[:attributes][:all].push('class', 'id')
whitelist[:elements].push('span')
# Remove the rel attribute that the sanitize gem adds, and remove the
# href attribute if it contains inline javascript
fix_anchors = lambda do |env|
name, node = env[:node_name], env[:node]
if name == 'a'
node.remove_attribute('rel')
if node['href'] && node['href'].match('javascript:')
node.remove_attribute('href')
end
end
end
whitelist[:transformers].push(fix_anchors)
markdown_context = {
asset_root: Gitlab.config.gitlab.url,
asset_host: Gitlab::Application.config.asset_host,
whitelist: whitelist
# ReferenceFilter
current_user: current_user,
only_path: options[:reference_only_path],
project: project,
reference_class: html_options[:class]
}
markdown_pipeline = HTML::Pipeline::Gitlab.new(filters).pipeline
result = markdown_pipeline.call(text, markdown_context)
result = pipeline.call(text, context)
save_options = 0
if options[:xhtml]
@ -114,21 +86,6 @@ module Gitlab
text = result[:output].to_html(save_with: save_options)
# Extract pre blocks so they are not altered
# from http://github.github.com/github-flavored-markdown/
text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}m) { |match| extract_piece(match) }
# Extract links with probably parsable hrefs
text.gsub!(%r{<a.*?>.*?</a>}m) { |match| extract_piece(match) }
# Extract images with probably parsable src
text.gsub!(%r{<img.*?>}m) { |match| extract_piece(match) }
text = parse(text, project)
# Insert pre block extractions
text.gsub!(/\{gfm-extraction-(\h{32})\}/) do
insert_piece($1)
end
if options[:parse_tasks]
text = parse_tasks(text)
end
@ -138,242 +95,53 @@ module Gitlab
private
def extract_piece(text)
@extractions ||= {}
md5 = Digest::MD5.hexdigest(text)
@extractions[md5] = text
"{gfm-extraction-#{md5}}"
end
def insert_piece(id)
@extractions[id]
end
# Private: Parses text for references
# Filters used in our pipeline
#
# text - Text to parse
# SanitizationFilter should come first so that all generated reference HTML
# goes through untouched.
#
# Returns parsed text
def parse(text, project = @project)
parse_references(text, project) if project
# See https://gitlab.com/gitlab-org/html-pipeline-gitlab for more filters
def filters
[
HTML::Pipeline::SanitizationFilter,
text
Gitlab::Markdown::EmojiFilter,
Gitlab::Markdown::UserReferenceFilter,
Gitlab::Markdown::IssueReferenceFilter,
Gitlab::Markdown::ExternalIssueReferenceFilter,
Gitlab::Markdown::MergeRequestReferenceFilter,
Gitlab::Markdown::SnippetReferenceFilter,
Gitlab::Markdown::CommitRangeReferenceFilter,
Gitlab::Markdown::CommitReferenceFilter,
Gitlab::Markdown::LabelReferenceFilter,
]
end
NAME_STR = Gitlab::Regex::NAMESPACE_REGEX_STR
PROJ_STR = "(?<project>#{NAME_STR}/#{NAME_STR})"
REFERENCE_PATTERN = %r{
(?<prefix>\W)? # Prefix
( # Reference
@(?<user>#{NAME_STR}) # User name
|~(?<label>\d+) # Label ID
|(?<issue>([A-Z\-]+-)\d+) # JIRA Issue ID
|#{PROJ_STR}?\#(?<issue>([a-zA-Z\-]+-)?\d+) # Issue ID
|#{PROJ_STR}?!(?<merge_request>\d+) # MR ID
|\$(?<snippet>\d+) # Snippet ID
|(#{PROJ_STR}@)?(?<commit_range>[\h]{6,40}\.{2,3}[\h]{6,40}) # Commit range
|(#{PROJ_STR}@)?(?<commit>[\h]{6,40}) # Commit ID
|(?<skip>gfm-extraction-[\h]{6,40}) # Skip gfm extractions. Otherwise will be parsed as commit
)
(?<suffix>\W)? # Suffix
}x.freeze
TYPES = [:user, :issue, :label, :merge_request, :snippet, :commit, :commit_range].freeze
def parse_references(text, project = @project)
# parse reference links
text.gsub!(REFERENCE_PATTERN) do |match|
type = TYPES.select{|t| !$~[t].nil?}.first
actual_project = project
project_prefix = nil
project_path = $LAST_MATCH_INFO[:project]
if project_path
actual_project = ::Project.find_with_namespace(project_path)
actual_project = nil unless can?(current_user, :read_project, actual_project)
project_prefix = project_path
end
parse_result($LAST_MATCH_INFO, type,
actual_project, project_prefix) || match
end
end
# Called from #parse_references. Attempts to build a gitlab reference
# link. Returns nil if +type+ is nil, if the match string is an HTML
# entity, if the reference is invalid, or if the matched text includes an
# invalid project path.
def parse_result(match_info, type, project, project_prefix)
prefix = match_info[:prefix]
suffix = match_info[:suffix]
return nil if html_entity?(prefix, suffix) || type.nil?
return nil if project.nil? && !project_prefix.nil?
identifier = match_info[type]
ref_link = reference_link(type, identifier, project, project_prefix)
if ref_link
"#{prefix}#{ref_link}#{suffix}"
else
nil
end
end
# Return true if the +prefix+ and +suffix+ indicate that the matched string
# is an HTML entity like &amp;
def html_entity?(prefix, suffix)
prefix && suffix && prefix[0] == '&' && suffix[-1] == ';'
end
# Private: Dispatches to a dedicated processing method based on reference
# Customize the SanitizationFilter whitelist
#
# reference - Object reference ("@1234", "!567", etc.)
# identifier - Object identifier (Issue ID, SHA hash, etc.)
#
# Returns string rendered by the processing method
def reference_link(type, identifier, project = @project, prefix_text = nil)
send("reference_#{type}", identifier, project, prefix_text)
end
# - Allow `class` and `id` attributes on all elements
# - Allow `span` elements
# - Remove `rel` attributes from `a` elements
# - Remove `a` nodes with `javascript:` in the `href` attribute
def sanitization_whitelist
whitelist = HTML::Pipeline::SanitizationFilter::WHITELIST
whitelist[:attributes][:all].push('class', 'id')
whitelist[:elements].push('span')
def reference_user(identifier, project = @project, _ = nil)
link_options = html_options.merge(
class: "gfm gfm-project_member #{html_options[:class]}"
)
if identifier == "all"
link_to(
"@all",
namespace_project_url(project.namespace, project, only_path: options[:reference_only_path]),
link_options
)
elsif namespace = Namespace.find_by(path: identifier)
url =
if namespace.is_a?(Group)
return nil unless can?(current_user, :read_group, namespace)
group_url(identifier, only_path: options[:reference_only_path])
else
user_url(identifier, only_path: options[:reference_only_path])
fix_anchors = lambda do |env|
name, node = env[:node_name], env[:node]
if name == 'a'
node.remove_attribute('rel')
if node['href'] && node['href'].match('javascript:')
node.remove_attribute('href')
end
link_to("@#{identifier}", url, link_options)
end
end
def reference_label(identifier, project = @project, _ = nil)
if label = project.labels.find_by(id: identifier)
link_options = html_options.merge(
class: "gfm gfm-label #{html_options[:class]}"
)
link_to(
render_colored_label(label),
namespace_project_issues_path(project.namespace, project, label_name: label.name),
link_options
)
end
end
def reference_issue(identifier, project = @project, prefix_text = nil)
if project.default_issues_tracker?
if project.issue_exists? identifier
url = url_for_issue(identifier, project, only_path: options[:reference_only_path])
title = title_for_issue(identifier, project)
link_options = html_options.merge(
title: "Issue: #{title}",
class: "gfm gfm-issue #{html_options[:class]}"
)
link_to("#{prefix_text}##{identifier}", url, link_options)
end
else
if project.external_issue_tracker.present?
reference_external_issue(identifier, project,
prefix_text)
end
end
end
def reference_merge_request(identifier, project = @project, prefix_text = nil)
if merge_request = project.merge_requests.find_by(iid: identifier)
link_options = html_options.merge(
title: "Merge Request: #{merge_request.title}",
class: "gfm gfm-merge_request #{html_options[:class]}"
)
url = namespace_project_merge_request_url(project.namespace, project,
merge_request,
only_path: options[:reference_only_path])
link_to("#{prefix_text}!#{identifier}", url, link_options)
end
end
whitelist[:transformers].push(fix_anchors)
def reference_snippet(identifier, project = @project, _ = nil)
if snippet = project.snippets.find_by(id: identifier)
link_options = html_options.merge(
title: "Snippet: #{snippet.title}",
class: "gfm gfm-snippet #{html_options[:class]}"
)
link_to(
"$#{identifier}",
namespace_project_snippet_url(project.namespace, project, snippet,
only_path: options[:reference_only_path]),
link_options
)
end
end
def reference_commit(identifier, project = @project, prefix_text = nil)
if project.valid_repo? && commit = project.repository.commit(identifier)
link_options = html_options.merge(
title: commit.link_title,
class: "gfm gfm-commit #{html_options[:class]}"
)
prefix_text = "#{prefix_text}@" if prefix_text
link_to(
"#{prefix_text}#{identifier}",
namespace_project_commit_url( project.namespace, project, commit,
only_path: options[:reference_only_path]),
link_options
)
end
end
def reference_commit_range(identifier, project = @project, prefix_text = nil)
from_id, to_id = identifier.split(/\.{2,3}/, 2)
inclusive = identifier !~ /\.{3}/
from_id << "^" if inclusive
if project.valid_repo? &&
from = project.repository.commit(from_id) &&
to = project.repository.commit(to_id)
link_options = html_options.merge(
title: "Commits #{from_id} through #{to_id}",
class: "gfm gfm-commit_range #{html_options[:class]}"
)
prefix_text = "#{prefix_text}@" if prefix_text
link_to(
"#{prefix_text}#{identifier}",
namespace_project_compare_url(project.namespace, project,
from: from_id, to: to_id,
only_path: options[:reference_only_path]),
link_options
)
end
end
def reference_external_issue(identifier, project = @project, prefix_text = nil)
url = url_for_issue(identifier, project, only_path: options[:reference_only_path])
title = project.external_issue_tracker.title
link_options = html_options.merge(
title: "Issue in #{title}",
class: "gfm gfm-issue #{html_options[:class]}"
)
link_to("#{prefix_text}##{identifier}", url, link_options)
whitelist
end
# Turn list items that start with "[ ]" into HTML checkbox inputs.

View File

@ -0,0 +1,105 @@
module Gitlab
module Markdown
# HTML filter that replaces commit range references with links.
#
# This filter supports cross-project references.
class CommitRangeReferenceFilter < ReferenceFilter
include CrossProjectReference
# Public: Find commit range references in text
#
# CommitRangeReferenceFilter.references_in(text) do |match, commit_range, project_ref|
# "<a href=...>#{commit_range}</a>"
# end
#
# text - String text to search.
#
# Yields the String match, the String commit range, and an optional String
# of the external project reference.
#
# Returns a String replaced with the return of the block.
def self.references_in(text)
text.gsub(COMMIT_RANGE_PATTERN) do |match|
yield match, $~[:commit_range], $~[:project]
end
end
def initialize(*args)
super
@commit_map = {}
end
# Pattern used to extract commit range references from text
#
# The beginning and ending SHA1 sums can be between 6 and 40 hex
# characters, and the range selection can be double- or triple-dot.
#
# This pattern supports cross-project references.
COMMIT_RANGE_PATTERN = /(#{PROJECT_PATTERN}@)?(?<commit_range>\h{6,40}\.{2,3}\h{6,40})/
def call
replace_text_nodes_matching(COMMIT_RANGE_PATTERN) do |content|
commit_range_link_filter(content)
end
end
# Replace commit range references in text with links to compare the commit
# ranges.
#
# text - String text to replace references in.
#
# Returns a String with commit range references replaced with links. All
# links have `gfm` and `gfm-commit_range` class names attached for
# styling.
def commit_range_link_filter(text)
self.class.references_in(text) do |match, commit_range, project_ref|
project = self.project_from_ref(project_ref)
from_id, to_id = split_commit_range(commit_range)
if valid_range?(project, from_id, to_id)
url = url_for_commit_range(project, from_id, to_id)
title = "Commits #{from_id} through #{to_id}"
klass = reference_class(:commit_range)
project_ref += '@' if project_ref
%(<a href="#{url}"
title="#{title}"
class="#{klass}">#{project_ref}#{commit_range}</a>)
else
match
end
end
end
def split_commit_range(range)
from_id, to_id = range.split(/\.{2,3}/, 2)
from_id << "^" if range !~ /\.{3}/
[from_id, to_id]
end
def commit(id)
unless @commit_map[id]
@commit_map[id] = project.repository.commit(id)
end
@commit_map[id]
end
def valid_range?(project, from_id, to_id)
project && project.valid_repo? && commit(from_id) && commit(to_id)
end
def url_for_commit_range(project, from_id, to_id)
h = Rails.application.routes.url_helpers
h.namespace_project_compare_url(project.namespace, project,
from: from_id, to: to_id,
only_path: context[:only_path])
end
end
end
end

Some files were not shown because too many files have changed in this diff Show More